diff --git a/core/src/net/sf/openrocket/rocketcomponent/FreeformFinSet.java b/core/src/net/sf/openrocket/rocketcomponent/FreeformFinSet.java
index e1c22a7f1..94a4f80b9 100644
--- a/core/src/net/sf/openrocket/rocketcomponent/FreeformFinSet.java
+++ b/core/src/net/sf/openrocket/rocketcomponent/FreeformFinSet.java
@@ -103,6 +103,43 @@ public class FreeformFinSet extends FinSet {
}
return freeform;
}
+
+ /**
+ * Converts a point of this fin set to edit into a point for a config listener to edit.
+ *
+ * The editing is as follows:
+ * 1) Editing the first point of this fin set will always edit the first point of the listener set
+ * 2) Editing the last point of this fin set will always edit the last point of the listener set
+ * 3) Editing any other point of this fin set will edit the corresponding point of the listener set, except
+ * for when the current point is not the last of this set, but it is the last of the listener set. In that
+ * case, no listener point will be edited.
+ *
+ * @param listener the listener which point needs to be edited
+ * @param index the point index of this fin set that is being edited
+ * @return the point index of the listener fin set that needs to be edited. Returns -1 if the listener's point should not be edited.
+ */
+ private int getConfigListenerPointIdx(FreeformFinSet listener, int index) {
+ /*
+ The editing is as follows:
+ 1) Editing the first point of this fin set will always edit the first point of the listener set
+ 2) Editing the last point of this fin set will always edit the last point of the listener set
+ 3) Editing any other point of this fin set will edit the corresponding point of the listener set, except
+ for when the current point is not the last of this set, but it is the last of the listener set. In that
+ case, no listener point will be edited.
+ */
+ if (index == this.points.size() - 1) {
+ // If editing the last point, also edit the last point of the listener
+ return listener.getPointCount() - 1;
+ } else {
+ if (index == listener.getPointCount() - 1) {
+ // If editing the last point of the listener, but not the last point of this fin set, don't edit the listener
+ return -1;
+ } else {
+ // Index-wise editing
+ return index;
+ }
+ }
+ }
/**
* Add a fin point between indices index-1
and index
.
@@ -111,7 +148,22 @@ public class FreeformFinSet extends FinSet {
* @param index the fin point before which to add the new point.
* @param location the target location to create the new point at
*/
- public void addPoint(int index, Point2D.Double location) {
+ public void addPoint(int index, Point2D.Double location) throws IllegalFinPointException {
+ if (index < 1 || index > points.size() - 1) {
+ throw new IllegalFinPointException("Cannot add new point before the first or after the last point");
+ }
+
+ for (RocketComponent listener : configListeners) {
+ if (listener instanceof FreeformFinSet) {
+ try {
+ int listenerIdx = getConfigListenerPointIdx((FreeformFinSet) listener, index);
+ ((FreeformFinSet) listener).addPoint(listenerIdx, location);
+ } catch (IllegalFinPointException ignored) {
+ // ignore
+ }
+ }
+ }
+
// new method: add new point at closest point
points.add(index, new Coordinate(location.x, location.y));
@@ -131,6 +183,20 @@ public class FreeformFinSet extends FinSet {
if (index == 0 || index == points.size() - 1) {
throw new IllegalFinPointException("cannot remove first or last point");
}
+ if (index < 0 || index >= points.size() - 1) {
+ throw new IllegalFinPointException("index out of range");
+ }
+
+ for (RocketComponent listener : configListeners) {
+ if (listener instanceof FreeformFinSet) {
+ try {
+ int listenerIdx = getConfigListenerPointIdx((FreeformFinSet) listener, index);
+ ((FreeformFinSet) listener).removePoint(listenerIdx);
+ } catch (IllegalFinPointException ignored) {
+ // ignore
+ }
+ }
+ }
// copy the old list in case the operation fails
ArrayList copy = new ArrayList<>(this.points);
@@ -226,11 +292,26 @@ public class FreeformFinSet extends FinSet {
* @param xRequest the x-coordinate.
* @param yRequest the y-coordinate.
*/
- public void setPoint(final int index, final double xRequest, final double yRequest) {
- if(null == this.getParent()) {
+ public void setPoint(final int index, final double xRequest, final double yRequest) throws IllegalFinPointException {
+ if (this.getParent() == null) {
return;
}
+ if (index < 0 || index > this.points.size() - 1) {
+ throw new IllegalFinPointException("index out of range");
+ }
+
+ for (RocketComponent listener : configListeners) {
+ if (listener instanceof FreeformFinSet) {
+ try {
+ int listenerIdx = getConfigListenerPointIdx((FreeformFinSet) listener, index);
+ ((FreeformFinSet) listener).setPoint(listenerIdx, xRequest, yRequest);
+ } catch (IllegalFinPointException ignored) {
+ // Ignore
+ }
+ }
+ }
+
// if the new x,y would cause a fin larger than our max-size, limit the new request:
double xAccept = xRequest;
double yAccept = yRequest;
diff --git a/core/test/net/sf/openrocket/rocketcomponent/FreeformFinSetTest.java b/core/test/net/sf/openrocket/rocketcomponent/FreeformFinSetTest.java
index 8e17dfa71..9e14b2050 100644
--- a/core/test/net/sf/openrocket/rocketcomponent/FreeformFinSetTest.java
+++ b/core/test/net/sf/openrocket/rocketcomponent/FreeformFinSetTest.java
@@ -7,6 +7,7 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import java.awt.geom.Point2D;
@@ -432,7 +433,11 @@ public class FreeformFinSetTest extends BaseTestCase {
// / |
// +=====+
Point2D.Double toAdd = new Point2D.Double(1.01, 0.8);
- fin.addPoint(3, toAdd);
+ try {
+ fin.addPoint(3, toAdd);
+ } catch (IllegalFinPointException e) {
+ fail("IllegalFinPointException thrown");
+ }
assertEquals(5, fin.getPointCount());
final Coordinate added = fin.getFinPoints()[3];
@@ -441,7 +446,7 @@ public class FreeformFinSetTest extends BaseTestCase {
}
@Test
- public void testSetFirstPoint() {
+ public void testSetFirstPoint() throws IllegalFinPointException {
// more transitions trigger more complicated positioning math:
final Rocket rkt = createTemplateRocket();
final Transition tailCone = (Transition) rkt.getChild(0).getChild(2);
@@ -605,7 +610,7 @@ public class FreeformFinSetTest extends BaseTestCase {
}
@Test
- public void testSetLastPoint() {
+ public void testSetLastPoint() throws IllegalFinPointException {
final Rocket rkt = createTemplateRocket();
final Transition tailCone = (Transition) rkt.getChild(0).getChild(2);
final FreeformFinSet fins = createFinOnConicalTransition(tailCone);
@@ -771,7 +776,7 @@ public class FreeformFinSetTest extends BaseTestCase {
}
@Test
- public void testSetInteriorPoint() {
+ public void testSetInteriorPoint() throws IllegalFinPointException {
final Rocket rkt = createTemplateRocket();
final Transition tailCone = (Transition) rkt.getChild(0).getChild(2);
final FreeformFinSet fins = this.createFinOnConicalTransition(tailCone);
@@ -875,7 +880,7 @@ public class FreeformFinSetTest extends BaseTestCase {
}
@Test
- public void testSetFirstPoint_clampToLast() {
+ public void testSetFirstPoint_clampToLast() throws IllegalFinPointException {
final Rocket rkt = createTemplateRocket();
final Transition tailCone = (Transition) rkt.getChild(0).getChild(2);
final FreeformFinSet fins = this.createFinOnConicalTransition(tailCone);
@@ -906,7 +911,7 @@ public class FreeformFinSetTest extends BaseTestCase {
}
@Test
- public void testSetPoint_otherPoint(){
+ public void testSetPoint_otherPoint() throws IllegalFinPointException {
// combine the simple case with the complicated to ensure that the simple case is flagged, tested, and debugged before running the more complicated case...
{ // setting points on a Tube Body is the simpler case. Test this first:
final Rocket rkt = createTemplateRocket();
diff --git a/swing/src/net/sf/openrocket/gui/configdialog/FreeformFinSetConfig.java b/swing/src/net/sf/openrocket/gui/configdialog/FreeformFinSetConfig.java
index 66ba5710c..47ade763f 100644
--- a/swing/src/net/sf/openrocket/gui/configdialog/FreeformFinSetConfig.java
+++ b/swing/src/net/sf/openrocket/gui/configdialog/FreeformFinSetConfig.java
@@ -466,7 +466,7 @@ public class FreeformFinSetConfig extends FinSetConfig {
* Insert a new fin point between the currently selected point and the next point.
* The coordinates of the new point will be the average of the two points.
*/
- private void insertPoint() {
+ private void insertPoint() throws IllegalFinPointException {
int currentPointIdx = table.getSelectedRow();
if (currentPointIdx == -1 || currentPointIdx >= table.getRowCount() - 1) {
return;
@@ -532,7 +532,11 @@ public class FreeformFinSetConfig extends FinSetConfig {
final int segmentIndex = getSegment(event);
if (segmentIndex >= 0) {
Point2D.Double point = getCoordinates(event);
- finset.addPoint(segmentIndex, point);
+ try {
+ finset.addPoint(segmentIndex, point);
+ } catch (IllegalFinPointException e) {
+ throw new RuntimeException(e);
+ }
dragIndex = segmentIndex;
dragPoint = event.getPoint();
@@ -554,7 +558,11 @@ public class FreeformFinSetConfig extends FinSetConfig {
Point2D.Double point = getCoordinates(event);
final FreeformFinSet finset = (FreeformFinSet) component;
- finset.setPoint(dragIndex, point.x, point.y);
+ try {
+ finset.setPoint(dragIndex, point.x, point.y);
+ } catch (IllegalFinPointException e) {
+ throw new RuntimeException(e);
+ }
dragPoint.x = event.getX();
dragPoint.y = event.getY();
@@ -782,6 +790,8 @@ public class FreeformFinSetConfig extends FinSetConfig {
updateFields();
} catch (NumberFormatException ignore) {
log.warn("ignoring NumberFormatException while editing a Freeform Fin");
+ } catch (IllegalFinPointException e) {
+ throw new RuntimeException(e);
}
}
}
@@ -800,7 +810,11 @@ public class FreeformFinSetConfig extends FinSetConfig {
@Override
public void actionPerformed(ActionEvent e) {
- insertPoint();
+ try {
+ insertPoint();
+ } catch (IllegalFinPointException ex) {
+ throw new RuntimeException(ex);
+ }
}
@Override