Merge pull request #703 from teyrana/385/3d-select
[fixes #385] Restores ability to select components in the 3d views
This commit is contained in:
commit
0f2edc0024
@ -673,9 +673,6 @@ public abstract class FinSet extends ExternalComponent implements AxialPositiona
|
|||||||
// (Iyy / M + Izz / M) / 2 = (h^2 + 2 * w^2)/24
|
// (Iyy / M + Izz / M) / 2 = (h^2 + 2 * w^2)/24
|
||||||
final double inertia = (h2 + 2 * w2) / 24;
|
final double inertia = (h2 + 2 * w2) / 24;
|
||||||
|
|
||||||
System.out.println("component " + this);
|
|
||||||
System.out.println("finCount " + finCount);
|
|
||||||
System.out.println("inertia " + inertia);
|
|
||||||
|
|
||||||
if (finCount == 1)
|
if (finCount == 1)
|
||||||
return inertia;
|
return inertia;
|
||||||
|
Binary file not shown.
@ -51,6 +51,7 @@ import net.sf.openrocket.startup.Application;
|
|||||||
import net.sf.openrocket.startup.Preferences;
|
import net.sf.openrocket.startup.Preferences;
|
||||||
import net.sf.openrocket.util.Coordinate;
|
import net.sf.openrocket.util.Coordinate;
|
||||||
import net.sf.openrocket.util.MathUtil;
|
import net.sf.openrocket.util.MathUtil;
|
||||||
|
import net.sf.openrocket.util.BoundingBox;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @author Bill Kuker <bkuker@billkuker.com>
|
* @author Bill Kuker <bkuker@billkuker.com>
|
||||||
@ -286,8 +287,6 @@ public class RocketFigure3d extends JPanel implements GLEventListener {
|
|||||||
GL2 gl = drawable.getGL().getGL2();
|
GL2 gl = drawable.getGL().getGL2();
|
||||||
GLU glu = new GLU();
|
GLU glu = new GLU();
|
||||||
|
|
||||||
gl.glEnable(GL.GL_MULTISAMPLE);
|
|
||||||
|
|
||||||
gl.glClearColor(1, 1, 1, 1);
|
gl.glClearColor(1, 1, 1, 1);
|
||||||
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
|
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
@ -295,6 +294,7 @@ public class RocketFigure3d extends JPanel implements GLEventListener {
|
|||||||
|
|
||||||
final FlightConfiguration configuration = rkt.getSelectedConfiguration();
|
final FlightConfiguration configuration = rkt.getSelectedConfiguration();
|
||||||
if (pickPoint != null) {
|
if (pickPoint != null) {
|
||||||
|
gl.glDisable(GL.GL_MULTISAMPLE);
|
||||||
gl.glDisable(GLLightingFunc.GL_LIGHTING);
|
gl.glDisable(GLLightingFunc.GL_LIGHTING);
|
||||||
|
|
||||||
final RocketComponent picked = rr.pick(drawable, configuration,
|
final RocketComponent picked = rr.pick(drawable, configuration,
|
||||||
@ -305,7 +305,6 @@ public class RocketFigure3d extends JPanel implements GLEventListener {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (picked == null) {
|
if (picked == null) {
|
||||||
log.debug("unselecting");
|
|
||||||
csl.componentClicked(new RocketComponent[] {}, e);
|
csl.componentClicked(new RocketComponent[] {}, e);
|
||||||
} else {
|
} else {
|
||||||
csl.componentClicked(new RocketComponent[] { picked }, e);
|
csl.componentClicked(new RocketComponent[] { picked }, e);
|
||||||
@ -319,6 +318,7 @@ public class RocketFigure3d extends JPanel implements GLEventListener {
|
|||||||
gl.glClearColor(1, 1, 1, 1);
|
gl.glClearColor(1, 1, 1, 1);
|
||||||
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
|
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
|
gl.glEnable(GL.GL_MULTISAMPLE);
|
||||||
gl.glEnable(GLLightingFunc.GL_LIGHTING);
|
gl.glEnable(GLLightingFunc.GL_LIGHTING);
|
||||||
}
|
}
|
||||||
rr.render(drawable, configuration, selection);
|
rr.render(drawable, configuration, selection);
|
||||||
@ -326,7 +326,7 @@ public class RocketFigure3d extends JPanel implements GLEventListener {
|
|||||||
drawExtras(gl, glu);
|
drawExtras(gl, glu);
|
||||||
drawCarets(gl, glu);
|
drawCarets(gl, glu);
|
||||||
|
|
||||||
//GLJPanel with GLSL Flipper relies on this:
|
// GLJPanel with GLSL Flipper relies on this:
|
||||||
gl.glFrontFace(GL.GL_CCW);
|
gl.glFrontFace(GL.GL_CCW);
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -468,47 +468,19 @@ public class RocketFigure3d extends JPanel implements GLEventListener {
|
|||||||
redrawExtras = true;
|
redrawExtras = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
private BoundingBox cachedBounds = null;
|
||||||
private static class Bounds {
|
|
||||||
double xMin, xMax, xSize;
|
|
||||||
double yMin, yMax, ySize;
|
|
||||||
double zMin, zMax, zSize;
|
|
||||||
double rMax;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Bounds cachedBounds = null;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates the bounds for the current configuration
|
* Calculates the bounds for the current configuration
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private Bounds calculateBounds() {
|
private BoundingBox calculateBounds() {
|
||||||
if (cachedBounds != null) {
|
if (cachedBounds == null) {
|
||||||
return cachedBounds;
|
|
||||||
} else {
|
|
||||||
final Bounds b = new Bounds();
|
|
||||||
final FlightConfiguration configuration = rkt.getSelectedConfiguration();
|
final FlightConfiguration configuration = rkt.getSelectedConfiguration();
|
||||||
final Collection<Coordinate> bounds = configuration.getBounds();
|
cachedBounds = configuration.getBoundingBox();
|
||||||
for (Coordinate c : bounds) {
|
|
||||||
b.xMax = Math.max(b.xMax, c.x);
|
|
||||||
b.xMin = Math.min(b.xMin, c.x);
|
|
||||||
|
|
||||||
b.yMax = Math.max(b.yMax, c.y);
|
|
||||||
b.yMin = Math.min(b.yMin, c.y);
|
|
||||||
|
|
||||||
b.zMax = Math.max(b.zMax, c.z);
|
|
||||||
b.zMin = Math.min(b.zMin, c.z);
|
|
||||||
|
|
||||||
double r = MathUtil.hypot(c.y, c.z);
|
|
||||||
b.rMax = Math.max(b.rMax, r);
|
|
||||||
}
|
|
||||||
b.xSize = b.xMax - b.xMin;
|
|
||||||
b.ySize = b.yMax - b.yMin;
|
|
||||||
b.zSize = b.zMax - b.zMin;
|
|
||||||
cachedBounds = b;
|
|
||||||
return b;
|
|
||||||
}
|
}
|
||||||
|
return cachedBounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupView(final GL2 gl, final GLU glu) {
|
private void setupView(final GL2 gl, final GLU glu) {
|
||||||
@ -518,14 +490,14 @@ public class RocketFigure3d extends JPanel implements GLEventListener {
|
|||||||
lightPosition, 0);
|
lightPosition, 0);
|
||||||
|
|
||||||
// Get the bounds
|
// Get the bounds
|
||||||
final Bounds b = calculateBounds();
|
final BoundingBox b = calculateBounds();
|
||||||
|
|
||||||
// Calculate the distance needed to fit the bounds in both the X and Y
|
// Calculate the distance needed to fit the bounds in both the X and Y
|
||||||
// direction
|
// direction
|
||||||
// Add 10% for space around it.
|
// Add 10% for space around it.
|
||||||
final double dX = (b.xSize * 1.2 / 2.0)
|
final double dX = (b.span().x * 1.2 / 2.0)
|
||||||
/ Math.tan(Math.toRadians(fovX / 2.0));
|
/ Math.tan(Math.toRadians(fovX / 2.0));
|
||||||
final double dY = (b.rMax * 2.0 * 1.2 / 2.0)
|
final double dY = (b.span().y * 2.0 * 1.2 / 2.0)
|
||||||
/ Math.tan(Math.toRadians(fovY / 2.0));
|
/ Math.tan(Math.toRadians(fovY / 2.0));
|
||||||
|
|
||||||
// Move back the greater of the 2 distances
|
// Move back the greater of the 2 distances
|
||||||
@ -535,7 +507,7 @@ public class RocketFigure3d extends JPanel implements GLEventListener {
|
|||||||
gl.glRotated(roll * (180.0 / Math.PI), 1, 0, 0);
|
gl.glRotated(roll * (180.0 / Math.PI), 1, 0, 0);
|
||||||
|
|
||||||
// Center the rocket in the view.
|
// Center the rocket in the view.
|
||||||
gl.glTranslated(-b.xMin - b.xSize / 2.0, 0, 0);
|
gl.glTranslated(-b.min.x - b.span().x / 2.0, 0, 0);
|
||||||
|
|
||||||
//Change to LEFT Handed coordinates
|
//Change to LEFT Handed coordinates
|
||||||
gl.glScaled(1, 1, -1);
|
gl.glScaled(1, 1, -1);
|
||||||
@ -593,14 +565,14 @@ public class RocketFigure3d extends JPanel implements GLEventListener {
|
|||||||
private void setRoll(final double rot) {
|
private void setRoll(final double rot) {
|
||||||
if (MathUtil.equals(roll, rot))
|
if (MathUtil.equals(roll, rot))
|
||||||
return;
|
return;
|
||||||
this.roll = MathUtil.reduce360(rot);
|
this.roll = MathUtil.reduce2PI(rot);
|
||||||
internalRepaint();
|
internalRepaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setYaw(final double rot) {
|
private void setYaw(final double rot) {
|
||||||
if (MathUtil.equals(yaw, rot))
|
if (MathUtil.equals(yaw, rot))
|
||||||
return;
|
return;
|
||||||
this.yaw = MathUtil.reduce360(rot);
|
this.yaw = MathUtil.reduce2PI(rot);
|
||||||
internalRepaint();
|
internalRepaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,9 +4,9 @@ import java.awt.Point;
|
|||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.Vector;
|
|
||||||
|
|
||||||
import com.jogamp.opengl.GL;
|
import com.jogamp.opengl.GL;
|
||||||
import com.jogamp.opengl.GL2;
|
import com.jogamp.opengl.GL2;
|
||||||
@ -60,49 +60,61 @@ public abstract class RocketRenderer {
|
|||||||
|
|
||||||
public abstract void flushTextureCache(GLAutoDrawable drawable);
|
public abstract void flushTextureCache(GLAutoDrawable drawable);
|
||||||
|
|
||||||
public RocketComponent pick(GLAutoDrawable drawable, FlightConfiguration configuration, Point p,
|
/**
|
||||||
Set<RocketComponent> ignore) {
|
* This function is a bit.... unusual. Instead of computing an inverse transform from the UI window into design-space,
|
||||||
|
* this renders each component with a unique identifiable color ... to a dummy, throwaway canvas:
|
||||||
|
*
|
||||||
|
* Then, we read the pixel (RGB) color value at a point on the canvas, and use that color to identify the component
|
||||||
|
*
|
||||||
|
* @param drawable canvas to draw to
|
||||||
|
* @param configuration active configuration
|
||||||
|
* @param p point to select at
|
||||||
|
* @param ignore list of ignore components
|
||||||
|
* @return optional (nullable) component selection result
|
||||||
|
*/
|
||||||
|
public RocketComponent pick(GLAutoDrawable drawable, FlightConfiguration configuration, Point p, Set<RocketComponent> ignore) {
|
||||||
final GL2 gl = drawable.getGL().getGL2();
|
final GL2 gl = drawable.getGL().getGL2();
|
||||||
gl.glEnable(GL.GL_DEPTH_TEST);
|
gl.glEnable(GL.GL_DEPTH_TEST);
|
||||||
|
|
||||||
// Store a vector of pickable parts.
|
// Store a vector of pickable parts.
|
||||||
final Vector<RocketComponent> pickParts = new Vector<RocketComponent>();
|
final Map<Integer, RocketComponent> selectionMap = new HashMap<>();
|
||||||
|
|
||||||
for (RocketComponent c : configuration.getActiveComponents()) {
|
Collection<Geometry> geometryList = getTreeGeometry( configuration);
|
||||||
if (ignore != null && ignore.contains(c))
|
for(Geometry geom: geometryList ) {
|
||||||
|
final RocketComponent comp = geom.getComponent();
|
||||||
|
if (ignore != null && ignore.contains(comp))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Encode the index of the part as a color
|
if( geom.active ) {
|
||||||
// if index is 0x0ABC the color ends up as
|
final int hashCode = comp.hashCode();
|
||||||
// 0xA0B0C000 with each nibble in the coresponding
|
|
||||||
// high bits of the RG and B channels.
|
|
||||||
gl.glColor4ub((byte) ((pickParts.size() >> 4) & 0xF0), (byte) ((pickParts.size() << 0) & 0xF0),
|
|
||||||
(byte) ((pickParts.size() << 4) & 0xF0), (byte) 1);
|
|
||||||
pickParts.add(c);
|
|
||||||
|
|
||||||
if (isDrawnTransparent(c)) {
|
selectionMap.put(hashCode, comp);
|
||||||
cr.getComponentGeometry(c).render(gl, Surface.INSIDE);
|
|
||||||
|
gl.glColor4ub((byte) ((hashCode >> 24) & 0xFF), // red channel (LSB)
|
||||||
|
(byte) ((hashCode >> 16) & 0xFF), // green channel
|
||||||
|
(byte) ((hashCode >> 8) & 0xFF), // blue channel
|
||||||
|
(byte) ((hashCode) & 0xFF)); // alpha channel (MSB)
|
||||||
|
|
||||||
|
if (isDrawnTransparent(comp)) {
|
||||||
|
geom.render(gl, Surface.INSIDE);
|
||||||
} else {
|
} else {
|
||||||
cr.getComponentGeometry(c).render(gl, Surface.ALL);
|
geom.render(gl, Surface.ALL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteBuffer bb = ByteBuffer.allocateDirect(4);
|
|
||||||
|
|
||||||
if (p == null)
|
if (p == null)
|
||||||
return null; //Allow pick to be called without a point for debugging
|
return null; //Allow pick to be called without a point for debugging
|
||||||
|
|
||||||
gl.glReadPixels(p.x, p.y, 1, 1, GL.GL_RGB, GL.GL_UNSIGNED_BYTE, bb);
|
final ByteBuffer buffer = ByteBuffer.allocateDirect(4);
|
||||||
|
gl.glReadPixels(p.x, p.y, // coordinates of "first" pixel to read
|
||||||
|
1, 1, // width, height of rectangle to read
|
||||||
|
GL.GL_RGBA, GL.GL_UNSIGNED_BYTE,
|
||||||
|
buffer); // output buffer
|
||||||
|
final int pixelValue = buffer.getInt();
|
||||||
|
final RocketComponent selected = selectionMap.get(pixelValue);
|
||||||
|
|
||||||
final int pickColor = bb.getInt();
|
return selected;
|
||||||
final int pickIndex = ((pickColor >> 20) & 0xF00) | ((pickColor >> 16) & 0x0F0) | ((pickColor >> 12) & 0x00F);
|
|
||||||
|
|
||||||
log.trace("Picked pixel color is {} index is {}", pickColor, pickIndex);
|
|
||||||
|
|
||||||
if (pickIndex < 0 || pickIndex > pickParts.size() - 1)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
return pickParts.get(pickIndex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void render(GLAutoDrawable drawable, FlightConfiguration configuration, Set<RocketComponent> selection) {
|
public void render(GLAutoDrawable drawable, FlightConfiguration configuration, Set<RocketComponent> selection) {
|
||||||
|
@ -312,8 +312,11 @@ public class GUIUtil {
|
|||||||
window.addComponentListener(new ComponentAdapter() {
|
window.addComponentListener(new ComponentAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public void componentResized(ComponentEvent e) {
|
public void componentResized(ComponentEvent e) {
|
||||||
|
final Dimension previousWindowSize = ((SwingPreferences)Application.getPreferences()).getWindowSize(window.getClass());
|
||||||
|
if( ! window.getSize().equals(previousWindowSize)) {
|
||||||
log.debug("Storing size of " + window.getClass().getName() + ": " + window.getSize());
|
log.debug("Storing size of " + window.getClass().getName() + ": " + window.getSize());
|
||||||
((SwingPreferences) Application.getPreferences()).setWindowSize(window.getClass(), window.getSize());
|
((SwingPreferences) Application.getPreferences()).setWindowSize(window.getClass(), window.getSize());
|
||||||
|
}
|
||||||
if (window instanceof JFrame) {
|
if (window instanceof JFrame) {
|
||||||
if ((((JFrame) window).getExtendedState() & JFrame.MAXIMIZED_BOTH) == JFrame.MAXIMIZED_BOTH) {
|
if ((((JFrame) window).getExtendedState() & JFrame.MAXIMIZED_BOTH) == JFrame.MAXIMIZED_BOTH) {
|
||||||
log.debug("Storing maximized state of " + window.getClass().getName());
|
log.debug("Storing maximized state of " + window.getClass().getName());
|
||||||
|
Loading…
x
Reference in New Issue
Block a user