diff --git a/core/src/main/resources/l10n/messages.properties b/core/src/main/resources/l10n/messages.properties index 58c287ad2..68c17d295 100644 --- a/core/src/main/resources/l10n/messages.properties +++ b/core/src/main/resources/l10n/messages.properties @@ -1260,9 +1260,11 @@ FreeformFinSetCfg.lbl.ttip.Fincant = The angle that the fins are canted with res FreeformFinSetCfg.lbl.FincrossSection = Fin cross section: FreeformFinSetCfg.lbl.Thickness = Thickness: FreeformFinSetConfig.lbl.doubleClick1 = Double-click -FreeformFinSetConfig.lbl.doubleClick2 = to edit -FreeformFinSetConfig.lbl.clickDrag = Click+drag: Add and move points +FreeformFinSetConfig.lbl.doubleClick2 = to edit table entry FreeformFinSetConfig.lbl.ctrlClick = Ctrl+click: Delete point +FreeformFinSetConfig.lbl.clickDrag = Click+drag: Add and move points +FreeformFinSetConfig.lbl.shiftClickDrag = Shift+click+drag: Lock angle to previous point +FreeformFinSetConfig.lbl.ctrlShiftClickDrag = Ctrl+shift+click+drag: Lock angle to following point FreeformFinSetConfig.lbl.scaleFin = Scale Fin FreeformFinSetConfig.lbl.exportCSV = Export CSV FreeformFinSetConfig.lbl.deletePoint = Delete point diff --git a/swing/src/main/java/info/openrocket/swing/gui/configdialog/FreeformFinSetConfig.java b/swing/src/main/java/info/openrocket/swing/gui/configdialog/FreeformFinSetConfig.java index b43cc420b..0e3c4f778 100644 --- a/swing/src/main/java/info/openrocket/swing/gui/configdialog/FreeformFinSetConfig.java +++ b/swing/src/main/java/info/openrocket/swing/gui/configdialog/FreeformFinSetConfig.java @@ -337,9 +337,11 @@ public class FreeformFinSetConfig extends FinSetConfig { order.add(table); // row of text directly below figure - panel.add(new StyledLabel(trans.get("lbl.doubleClick1")+" "+trans.get("FreeformFinSetConfig.lbl.doubleClick2"), -2), "spanx 3"); - panel.add(new StyledLabel(trans.get("FreeformFinSetConfig.lbl.clickDrag"), -2), "spanx 3"); - panel.add(new StyledLabel(trans.get("FreeformFinSetConfig.lbl.ctrlClick"), -2), "spanx 3, wrap"); + panel.add(new StyledLabel(trans.get("lbl.doubleClick1")+" "+trans.get("FreeformFinSetConfig.lbl.doubleClick2"), -2), "spanx 2"); + panel.add(new StyledLabel(trans.get("FreeformFinSetConfig.lbl.ctrlClick"), -2), "spanx 2, wrap"); + panel.add(new StyledLabel(trans.get("FreeformFinSetConfig.lbl.clickDrag"), -2), "spanx 2"); + panel.add(new StyledLabel(trans.get("FreeformFinSetConfig.lbl.shiftClickDrag"), -2), "spanx 2"); + panel.add(new StyledLabel(trans.get("FreeformFinSetConfig.lbl.ctrlShiftClickDrag"), -2), "spanx 2, wrap"); // row of controls at the bottom of the tab: panel.add(selector.getAsPanel(), "aligny bottom, gap unrel"); @@ -534,13 +536,58 @@ public class FreeformFinSetConfig extends FinSetConfig { @Override public void mouseDragged(MouseEvent event) { int mods = event.getModifiersEx(); + /*XXX if (dragIndex < 0 || (mods & (ANY_MASK | MouseEvent.BUTTON1_DOWN_MASK)) != MouseEvent.BUTTON1_DOWN_MASK) { super.mouseDragged(event); return; } + */ Point2D.Double point = getCoordinates(event); final FreeformFinSet finset = (FreeformFinSet) component; + + // If shift is held down and a point is being dragged, constrain angle relative to previous or following point + int lockIndex = -1; + int highlightIndex = -1; + if (dragIndex >= 0 && (mods & MouseEvent.SHIFT_DOWN_MASK) != 0) { + if ((mods & MouseEvent.CTRL_DOWN_MASK) != 0) { + if (dragIndex < finset.getFinPoints().length-1) { + lockIndex = dragIndex + 1; + highlightIndex = dragIndex; + } + } + else if (dragIndex > 0) { + lockIndex = dragIndex - 1; + highlightIndex = dragIndex - 1; + } + + if (lockIndex >= 0) { + // Fetch point to lock to + final Coordinate lockPoint = finset.getFinPoints()[lockIndex]; + // Distances to vertical and horizontal lines + final double diffX = point.x - lockPoint.x; + final double diffY = point.y - lockPoint.y; + final double distanceX = Math.abs(diffX); + final double distanceY = Math.abs(diffY); + // Calculate distance to 45 or 135 degree line, as appropriate + final double a = 1; // always + final double b = (Math.signum(diffX) == Math.signum(diffY)) ? -1 : 1; + final double c = -(a*lockPoint.x + b*lockPoint.y); + final double distanceDiag = Math.abs(a*point.x + b*point.y + c) / Math.sqrt(2); + + // Snap in the appropriate direction + if (distanceX <= distanceY && distanceX <= distanceDiag) // snap horizontal + point.x = lockPoint.x; + else if (distanceY <= distanceX && distanceY <= distanceDiag) // snap vertical + point.y = lockPoint.y; + else { // snap diagonal + point.x = (b*( b*point.x - a*point.y) - a*c) / 2; + point.y = (a*(-b*point.x + a*point.y) - b*c) / 2; + } + } + } + figure.setHighlightIndex(highlightIndex); + try { finset.setPoint(dragIndex, point.x, point.y); } catch (IllegalFinPointException e) { @@ -627,6 +674,9 @@ public class FreeformFinSetConfig extends FinSetConfig { public void mouseReleased(MouseEvent event) { dragIndex = -1; dragPoint = null; + figure.setHighlightIndex(-1); + figure.updateFigure(); + super.mouseReleased(event); } diff --git a/swing/src/main/java/info/openrocket/swing/gui/scalefigure/FinPointFigure.java b/swing/src/main/java/info/openrocket/swing/gui/scalefigure/FinPointFigure.java index 11b7a214f..4f3911ab7 100644 --- a/swing/src/main/java/info/openrocket/swing/gui/scalefigure/FinPointFigure.java +++ b/swing/src/main/java/info/openrocket/swing/gui/scalefigure/FinPointFigure.java @@ -39,6 +39,7 @@ public class FinPointFigure extends AbstractScaleFigure { private static final int LINE_WIDTH_FIN_PIXELS = 1; private static final int LINE_WIDTH_BODY_PIXELS = 2; + private static final int LINE_WIDTH_HIGHLIGHT_PIXELS = 3; // the size of the boxes around each fin point vertex private static final int LINE_WIDTH_BOX_PIXELS = 1; @@ -59,6 +60,7 @@ public class FinPointFigure extends AbstractScaleFigure { private Rectangle2D.Double[] finPointHandles = null; private int selectedIndex = -1; + private int highlightIndex = -1; private static Color backgroundColor; private static Color finPointBodyLineColor; @@ -124,6 +126,7 @@ public class FinPointFigure extends AbstractScaleFigure { paintRocketBody(g2); paintFinShape(g2); + paintHighlight(g2); paintFinHandles(g2); } @@ -261,6 +264,22 @@ public class FinPointFigure extends AbstractScaleFigure { g2.setColor(finPointBodyLineColor); g2.draw(shape); } + + private void paintHighlight(final Graphics2D g2) { + final Coordinate[] points = finset.getFinPointsWithRoot(); + + if (highlightIndex < 0 || highlightIndex > points.length - 1) { + return; + } + + Coordinate start = points[highlightIndex]; + Coordinate end = points[highlightIndex+1]; + + final float highlightWidth_m = (float) (LINE_WIDTH_HIGHLIGHT_PIXELS / scale ); + g2.setStroke(new BasicStroke(highlightWidth_m)); + g2.setColor(Color.RED); + g2.draw(new Line2D.Double(start.x, start.y, end.x, end.y)); + } private void paintFinHandles(final Graphics2D g2) { // Excludes fin tab points @@ -438,4 +457,8 @@ public class FinPointFigure extends AbstractScaleFigure { this.selectedIndex = newIndex; } + public void setHighlightIndex(final int newIndex) { + this.highlightIndex = newIndex; + } + }