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
|
||||
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)
|
||||
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.util.Coordinate;
|
||||
import net.sf.openrocket.util.MathUtil;
|
||||
import net.sf.openrocket.util.BoundingBox;
|
||||
|
||||
/*
|
||||
* @author Bill Kuker <bkuker@billkuker.com>
|
||||
@ -285,9 +286,7 @@ public class RocketFigure3d extends JPanel implements GLEventListener {
|
||||
public void display(final GLAutoDrawable drawable) {
|
||||
GL2 gl = drawable.getGL().getGL2();
|
||||
GLU glu = new GLU();
|
||||
|
||||
gl.glEnable(GL.GL_MULTISAMPLE);
|
||||
|
||||
|
||||
gl.glClearColor(1, 1, 1, 1);
|
||||
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();
|
||||
if (pickPoint != null) {
|
||||
gl.glDisable(GL.GL_MULTISAMPLE);
|
||||
gl.glDisable(GLLightingFunc.GL_LIGHTING);
|
||||
|
||||
final RocketComponent picked = rr.pick(drawable, configuration,
|
||||
@ -305,7 +305,6 @@ public class RocketFigure3d extends JPanel implements GLEventListener {
|
||||
@Override
|
||||
public void run() {
|
||||
if (picked == null) {
|
||||
log.debug("unselecting");
|
||||
csl.componentClicked(new RocketComponent[] {}, e);
|
||||
} else {
|
||||
csl.componentClicked(new RocketComponent[] { picked }, e);
|
||||
@ -318,7 +317,8 @@ public class RocketFigure3d extends JPanel implements GLEventListener {
|
||||
|
||||
gl.glClearColor(1, 1, 1, 1);
|
||||
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
|
||||
gl.glEnable(GL.GL_MULTISAMPLE);
|
||||
gl.glEnable(GLLightingFunc.GL_LIGHTING);
|
||||
}
|
||||
rr.render(drawable, configuration, selection);
|
||||
@ -326,7 +326,7 @@ public class RocketFigure3d extends JPanel implements GLEventListener {
|
||||
drawExtras(gl, glu);
|
||||
drawCarets(gl, glu);
|
||||
|
||||
//GLJPanel with GLSL Flipper relies on this:
|
||||
// GLJPanel with GLSL Flipper relies on this:
|
||||
gl.glFrontFace(GL.GL_CCW);
|
||||
|
||||
}
|
||||
@ -468,47 +468,19 @@ public class RocketFigure3d extends JPanel implements GLEventListener {
|
||||
redrawExtras = true;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static class Bounds {
|
||||
double xMin, xMax, xSize;
|
||||
double yMin, yMax, ySize;
|
||||
double zMin, zMax, zSize;
|
||||
double rMax;
|
||||
}
|
||||
|
||||
private Bounds cachedBounds = null;
|
||||
private BoundingBox cachedBounds = null;
|
||||
|
||||
/**
|
||||
* Calculates the bounds for the current configuration
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private Bounds calculateBounds() {
|
||||
if (cachedBounds != null) {
|
||||
return cachedBounds;
|
||||
} else {
|
||||
final Bounds b = new Bounds();
|
||||
private BoundingBox calculateBounds() {
|
||||
if (cachedBounds == null) {
|
||||
final FlightConfiguration configuration = rkt.getSelectedConfiguration();
|
||||
final Collection<Coordinate> bounds = configuration.getBounds();
|
||||
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;
|
||||
cachedBounds = configuration.getBoundingBox();
|
||||
}
|
||||
return cachedBounds;
|
||||
}
|
||||
|
||||
private void setupView(final GL2 gl, final GLU glu) {
|
||||
@ -516,16 +488,16 @@ public class RocketFigure3d extends JPanel implements GLEventListener {
|
||||
|
||||
gl.glLightfv(GLLightingFunc.GL_LIGHT1, GLLightingFunc.GL_POSITION,
|
||||
lightPosition, 0);
|
||||
|
||||
|
||||
// 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
|
||||
// direction
|
||||
// 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));
|
||||
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));
|
||||
|
||||
// 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);
|
||||
|
||||
// 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
|
||||
gl.glScaled(1, 1, -1);
|
||||
@ -593,14 +565,14 @@ public class RocketFigure3d extends JPanel implements GLEventListener {
|
||||
private void setRoll(final double rot) {
|
||||
if (MathUtil.equals(roll, rot))
|
||||
return;
|
||||
this.roll = MathUtil.reduce360(rot);
|
||||
this.roll = MathUtil.reduce2PI(rot);
|
||||
internalRepaint();
|
||||
}
|
||||
|
||||
private void setYaw(final double rot) {
|
||||
if (MathUtil.equals(yaw, rot))
|
||||
return;
|
||||
this.yaw = MathUtil.reduce360(rot);
|
||||
this.yaw = MathUtil.reduce2PI(rot);
|
||||
internalRepaint();
|
||||
}
|
||||
|
||||
|
@ -4,9 +4,9 @@ import java.awt.Point;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Vector;
|
||||
|
||||
import com.jogamp.opengl.GL;
|
||||
import com.jogamp.opengl.GL2;
|
||||
@ -59,50 +59,62 @@ public abstract class RocketRenderer {
|
||||
public abstract boolean isDrawnTransparent(RocketComponent c);
|
||||
|
||||
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();
|
||||
gl.glEnable(GL.GL_DEPTH_TEST);
|
||||
|
||||
|
||||
// Store a vector of pickable parts.
|
||||
final Vector<RocketComponent> pickParts = new Vector<RocketComponent>();
|
||||
|
||||
for (RocketComponent c : configuration.getActiveComponents()) {
|
||||
if (ignore != null && ignore.contains(c))
|
||||
final Map<Integer, RocketComponent> selectionMap = new HashMap<>();
|
||||
|
||||
Collection<Geometry> geometryList = getTreeGeometry( configuration);
|
||||
for(Geometry geom: geometryList ) {
|
||||
final RocketComponent comp = geom.getComponent();
|
||||
if (ignore != null && ignore.contains(comp))
|
||||
continue;
|
||||
|
||||
// Encode the index of the part as a color
|
||||
// if index is 0x0ABC the color ends up as
|
||||
// 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)) {
|
||||
cr.getComponentGeometry(c).render(gl, Surface.INSIDE);
|
||||
} else {
|
||||
cr.getComponentGeometry(c).render(gl, Surface.ALL);
|
||||
|
||||
if( geom.active ) {
|
||||
final int hashCode = comp.hashCode();
|
||||
|
||||
selectionMap.put(hashCode, comp);
|
||||
|
||||
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 {
|
||||
geom.render(gl, Surface.ALL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ByteBuffer bb = ByteBuffer.allocateDirect(4);
|
||||
|
||||
if (p == null)
|
||||
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 int pickColor = bb.getInt();
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
return selected;
|
||||
}
|
||||
|
||||
public void render(GLAutoDrawable drawable, FlightConfiguration configuration, Set<RocketComponent> selection) {
|
||||
|
@ -312,8 +312,11 @@ public class GUIUtil {
|
||||
window.addComponentListener(new ComponentAdapter() {
|
||||
@Override
|
||||
public void componentResized(ComponentEvent e) {
|
||||
log.debug("Storing size of " + window.getClass().getName() + ": " + window.getSize());
|
||||
((SwingPreferences) Application.getPreferences()).setWindowSize(window.getClass(), window.getSize());
|
||||
final Dimension previousWindowSize = ((SwingPreferences)Application.getPreferences()).getWindowSize(window.getClass());
|
||||
if( ! window.getSize().equals(previousWindowSize)) {
|
||||
log.debug("Storing size of " + window.getClass().getName() + ": " + window.getSize());
|
||||
((SwingPreferences) Application.getPreferences()).setWindowSize(window.getClass(), window.getSize());
|
||||
}
|
||||
if (window instanceof JFrame) {
|
||||
if ((((JFrame) window).getExtendedState() & JFrame.MAXIMIZED_BOTH) == JFrame.MAXIMIZED_BOTH) {
|
||||
log.debug("Storing maximized state of " + window.getClass().getName());
|
||||
|
Loading…
x
Reference in New Issue
Block a user