From cf4a93530240e49060ad6b98ccc3a523af2cfff7 Mon Sep 17 00:00:00 2001 From: Daniel M Williams Date: Thu, 27 Dec 2018 13:31:04 -0500 Subject: [PATCH 1/3] [test] Refactored FreeformFinSetTest to de-dup code execution. --- .../rocketcomponent/FreeformFinSetTest.java | 347 +++++++++--------- 1 file changed, 168 insertions(+), 179 deletions(-) diff --git a/core/test/net/sf/openrocket/rocketcomponent/FreeformFinSetTest.java b/core/test/net/sf/openrocket/rocketcomponent/FreeformFinSetTest.java index 84b0a668b..2bfb25f8c 100644 --- a/core/test/net/sf/openrocket/rocketcomponent/FreeformFinSetTest.java +++ b/core/test/net/sf/openrocket/rocketcomponent/FreeformFinSetTest.java @@ -4,13 +4,9 @@ import java.awt.geom.Point2D; import org.junit.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.assertThat; - import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.not; +import static org.junit.Assert.*; import net.sf.openrocket.aerodynamics.AerodynamicForces; import net.sf.openrocket.aerodynamics.FlightConditions; @@ -32,12 +28,6 @@ public class FreeformFinSetTest extends BaseTestCase { private static final double EPSILON = 1E-6; - @Test - public void testMultiplicity() { - final FreeformFinSet fins = new FreeformFinSet(); - assertEquals(1, fins.getFinCount()); - } - private FreeformFinSet testFreeformConvert(FinSet sourceSet) { sourceSet.setName("test-convert-finset"); sourceSet.setBaseRotation(1.1); @@ -86,7 +76,7 @@ public class FreeformFinSetTest extends BaseTestCase { nose.setName("Nose Fairing"); stage.addChild(nose); - BodyTube body = new BodyTube(1.0,1.0,0.01); + BodyTube body = new BodyTube(2.0,1.0,0.01); body.setName("Body Tube"); stage.addChild(body); @@ -99,16 +89,17 @@ public class FreeformFinSetTest extends BaseTestCase { tail.setName("Tail Cone"); stage.addChild(tail); - createFinOnEllipsoidNose(nose); - createFinOnTube(body); - createFinOnConicalTransition(tail); + // zero-length body tube -- triggers a whole other class of errors + final BodyTube phantom = new BodyTube(0., 0.5, 0.01); + phantom.setName("Phantom Body Tube"); + body.setOuterRadiusAutomatic(true); + stage.addChild(phantom); rocket.enableEvents(); return rocket; } - - private void createFinOnEllipsoidNose(NoseCone nose){ + private FreeformFinSet createFinOnEllipsoidNose(NoseCone nose){ FreeformFinSet fins = new FreeformFinSet(); fins.setName("test-freeform-finset"); fins.setFinCount(1); @@ -120,11 +111,12 @@ public class FreeformFinSetTest extends BaseTestCase { new Coordinate( 0.8, 0.9) // y-value should be automaticaly adjusted to snap to body }; fins.setPoints(points); - nose.addChild(fins); + + return fins; } - private void createFinOnTube(final BodyTube body){ + private FreeformFinSet createFinOnTube(final BodyTube body){ // This is a trapezoid: // - Height: 1 // - Root Chord: 1 @@ -132,10 +124,11 @@ public class FreeformFinSetTest extends BaseTestCase { // - Sweep: 1/2 // It can be decomposed into a triangle followed by a rectangle // +--+ - // /. |x + // /. | // / . | // +=====+ FreeformFinSet fins = new FreeformFinSet(); + fins.setName("TubeBodyFins"); fins.setFinCount(1); Coordinate[] points = new Coordinate[]{ new Coordinate(0, 0), @@ -147,9 +140,11 @@ public class FreeformFinSetTest extends BaseTestCase { fins.setAxialOffset( AxialMethod.BOTTOM, 0.0); body.addChild(fins); + + return fins; } - private void createFinOnConicalTransition(final Transition body) { + private FreeformFinSet createFinOnConicalTransition(final Transition body) { // ----+ (1) // (0) ----- | // ---+ | @@ -168,6 +163,8 @@ public class FreeformFinSetTest extends BaseTestCase { fins.setPoints(initPoints); body.addChild(fins); + + return fins; } // ==================== Test Methods ==================== @@ -247,8 +244,8 @@ public class FreeformFinSetTest extends BaseTestCase { @Test public void testFreeformCMComputation_trapezoidOnTube() { final Rocket rkt = createTemplateRocket(); - final BodyTube finMount= (BodyTube)rkt.getChild(0).getChild(1); - final FreeformFinSet fins = (FreeformFinSet)rkt.getChild(0).getChild(1).getChild(0); + final BodyTube body = (BodyTube)rkt.getChild(0).getChild(1); + final FreeformFinSet fins = createFinOnTube(body); // assert pre-condition: final Coordinate[] finPoints = fins.getFinPoints(); @@ -259,8 +256,8 @@ public class FreeformFinSetTest extends BaseTestCase { assertEquals(finPoints[3], new Coordinate(1.0, 0.0)); final double x0 = fins.getAxialFront(); - assertEquals(0., x0, EPSILON); - assertEquals(1.0, finMount.getRadius(x0), EPSILON); + assertEquals(1.0, x0, EPSILON); + assertEquals(1.0, body.getRadius(x0), EPSILON); // NOTE: this will be relative to the center of the finset -- which is at the center of it's mounted body final Coordinate coords = fins.getCG(); @@ -273,7 +270,7 @@ public class FreeformFinSetTest extends BaseTestCase { public void testFreeformCMComputation_triangleOnTransition(){ Rocket rkt = createTemplateRocket(); final Transition finMount = (Transition)rkt.getChild(0).getChild(2); - FinSet fins = (FinSet)rkt.getChild(0).getChild(2).getChild(0); + final FreeformFinSet fins = createFinOnConicalTransition(finMount); // assert pre-condition: final Coordinate[] finPoints = fins.getFinPoints(); @@ -318,12 +315,12 @@ public class FreeformFinSetTest extends BaseTestCase { @Test public void testFreeformCMComputation_triangleOnEllipsoid(){ final Rocket rkt = createTemplateRocket(); - final Transition body = (Transition) rkt.getChild(0).getChild(0); - final FinSet fins = (FreeformFinSet) rkt.getChild(0).getChild(0).getChild(0); + final NoseCone nose = (NoseCone) rkt.getChild(0).getChild(0); + final FinSet fins = createFinOnEllipsoidNose(nose); // assert preconditions - assertEquals(Shape.ELLIPSOID, body.getType()); - assertEquals(1.0, body.getLength(), EPSILON); + assertEquals(Shape.ELLIPSOID, nose.getType()); + assertEquals(1.0, nose.getLength(), EPSILON); assertEquals(AxialMethod.TOP, fins.getAxialMethod()); assertEquals(0.02, fins.getAxialOffset(), EPSILON); @@ -359,8 +356,9 @@ public class FreeformFinSetTest extends BaseTestCase { @Test public void testFreeformCMComputationTrapezoidExtraPoints() { final Rocket rkt = createTemplateRocket(); - final FreeformFinSet fins = (FreeformFinSet)rkt.getChild(0).getChild(1).getChild(0); - + final BodyTube body = (BodyTube) rkt.getChild(0).getChild(1); + final FreeformFinSet fins = createFinOnTube(body); + // This is the same trapezoid as previous free form, but it has // some extra points along the lines. Coordinate[] points = new Coordinate[]{ @@ -383,7 +381,8 @@ public class FreeformFinSetTest extends BaseTestCase { @Test public void testFreeformCMComputationAdjacentPoints() { Rocket rkt = createTemplateRocket(); - FreeformFinSet fins = (FreeformFinSet)rkt.getChild(0).getChild(1).getChild(0); + final BodyTube body = (BodyTube) rkt.getChild(0).getChild(1); + final FreeformFinSet fins = createFinOnTube(body); // This is the same trapezoid as previous free form, but it has // some extra points which are very close to previous points. @@ -410,7 +409,8 @@ public class FreeformFinSetTest extends BaseTestCase { @Test public void testFreeformFinAddPoint() { Rocket rkt = createTemplateRocket(); - FreeformFinSet fin = (FreeformFinSet)rkt.getChild(0).getChild(1).getChild(0); + final BodyTube body = (BodyTube) rkt.getChild(0).getChild(1); + final FreeformFinSet fin = createFinOnTube(body); assertEquals(4, fin.getPointCount()); @@ -431,8 +431,8 @@ public class FreeformFinSetTest extends BaseTestCase { public void testSetFirstPoint() throws IllegalFinPointException { // more transitions trigger more complicated positioning math: final Rocket rkt = createTemplateRocket(); - final Transition finMount = (Transition) rkt.getChild(0).getChild(2); - final FreeformFinSet fins = (FreeformFinSet) rkt.getChild(0).getChild(2).getChild(0); + final Transition tailCone = (Transition) rkt.getChild(0).getChild(2); + final FreeformFinSet fins = createFinOnConicalTransition(tailCone); final Coordinate[] initialPoints = fins.getFinPoints(); // assert pre-conditions: @@ -440,8 +440,8 @@ public class FreeformFinSetTest extends BaseTestCase { assertEquals(initialPoints[0], Coordinate.ZERO); assertEquals(initialPoints[1], new Coordinate(0.4, 0.2)); assertEquals(initialPoints[2], new Coordinate(0.4, -0.2)); - assertEquals(1.0, finMount.getLength(), EPSILON); - assertEquals(0.8, finMount.getRadius(fins.getAxialFront()), EPSILON); + assertEquals(1.0, tailCone.getLength(), EPSILON); + assertEquals(0.8, tailCone.getRadius(fins.getAxialFront()), EPSILON); { // case 1: fins.setAxialOffset( AxialMethod.TOP, 0.1); @@ -588,8 +588,8 @@ public class FreeformFinSetTest extends BaseTestCase { @Test public void testSetLastPoint() { final Rocket rkt = createTemplateRocket(); - Transition finMount = (Transition) rkt.getChild(0).getChild(2); - FreeformFinSet fins = (FreeformFinSet) rkt.getChild(0).getChild(2).getChild(0); + final Transition tailCone = (Transition) rkt.getChild(0).getChild(2); + final FreeformFinSet fins = createFinOnConicalTransition(tailCone); final Coordinate[] initialPoints = fins.getFinPoints(); final int lastIndex = initialPoints.length - 1; final double xf = initialPoints[lastIndex].x; @@ -599,8 +599,8 @@ public class FreeformFinSetTest extends BaseTestCase { assertEquals(initialPoints[0], Coordinate.ZERO); assertEquals(initialPoints[1], new Coordinate(0.4, 0.2)); assertEquals(initialPoints[2], new Coordinate(0.4, -0.2)); - assertEquals(1.0, finMount.getLength(), EPSILON); - assertEquals(0.8, finMount.getRadius(fins.getAxialFront()), EPSILON); + assertEquals(1.0, tailCone.getLength(), EPSILON); + assertEquals(0.8, tailCone.getRadius(fins.getAxialFront()), EPSILON); { // case 1: fins.setAxialOffset( AxialMethod.TOP, 0.1); @@ -753,7 +753,8 @@ public class FreeformFinSetTest extends BaseTestCase { @Test public void testSetInteriorPoint() { final Rocket rkt = createTemplateRocket(); - FreeformFinSet fins = (FreeformFinSet) rkt.getChild(0).getChild(2).getChild(0); + final Transition tailCone = (Transition) rkt.getChild(0).getChild(2); + final FreeformFinSet fins = this.createFinOnConicalTransition(tailCone); { // preconditions // initial points final Coordinate[] initialPoints = fins.getFinPoints(); @@ -796,19 +797,15 @@ public class FreeformFinSetTest extends BaseTestCase { } @Test - public void testSetAllPoints() { + public void testSetAllPointsOnPhantomBody() { final Rocket rkt = createTemplateRocket(); - final AxialStage stage = (AxialStage) rkt.getChild(0); - + final BodyTube phantomBody = (BodyTube) rkt.getChild(0).getChild(3); + { // setup // mount - BodyTube body = new BodyTube(0.0, 1.0, 0.002); - body.setName("Phantom Body Tube"); - body.setOuterRadiusAutomatic(true); - stage.addChild(body, 2); - assertEquals(1.0, body.getOuterRadius(), EPSILON); - assertEquals(0.0, body.getLength(), EPSILON); - - FreeformFinSet fins = new FreeformFinSet(); + assertEquals(0.5, phantomBody.getOuterRadius(), EPSILON); + assertEquals(0.0, phantomBody.getLength(), EPSILON); + }{ + final FreeformFinSet fins = new FreeformFinSet(); fins.setFinCount(4); Coordinate[] points = new Coordinate[]{ new Coordinate(0.0, 0.0), @@ -818,16 +815,17 @@ public class FreeformFinSetTest extends BaseTestCase { new Coordinate(1.1e-4, 0.0) // final point is within the testing thresholds :/ }; fins.setPoints(points); - - body.addChild(fins); - - }{ // postconditions - FreeformFinSet fins = (FreeformFinSet) rkt.getChild(0).getChild(2).getChild(0); - + + phantomBody.addChild(fins); + assertEquals(1, phantomBody.getChildCount()); + + }{ // postconditions + final FreeformFinSet fins = (FreeformFinSet) phantomBody.getChild(0); + final Coordinate[] postPoints = fins.getFinPoints(); assertEquals(6, postPoints.length); - // p1 + // p1 assertEquals(-0.0508, postPoints[1].x, EPSILON); assertEquals(0.007721, postPoints[1].y, EPSILON); @@ -835,7 +833,7 @@ public class FreeformFinSetTest extends BaseTestCase { assertEquals(0.0, postPoints[2].x, EPSILON); assertEquals(0.01544, postPoints[2].y, EPSILON); - // p3 + // p3 assertEquals(0.0254, postPoints[3].x, EPSILON); assertEquals(0.007721, postPoints[3].y, EPSILON); @@ -846,24 +844,24 @@ public class FreeformFinSetTest extends BaseTestCase { // p/last: generated by loading code: assertEquals(0.0, postPoints[5].x, EPSILON); assertEquals(0.0, postPoints[5].y, EPSILON); - + assertEquals(0.0, fins.getLength(), EPSILON); assertEquals(0.0, fins.getFinFront().x, EPSILON); - assertEquals(1.0, fins.getFinFront().y, EPSILON); + assertEquals(0.5, fins.getFinFront().y, EPSILON); } } @Test public void testSetFirstPoint_testNonIntersection() { final Rocket rkt = createTemplateRocket(); - final FreeformFinSet fins = (FreeformFinSet) rkt.getChild(0).getChild(2).getChild(0); - final Transition mount = (Transition) rkt.getChild(0).getChild(2); + final Transition tailCone = (Transition) rkt.getChild(0).getChild(2); + final FreeformFinSet fins = this.createFinOnConicalTransition(tailCone); assertEquals( 1, fins.getFinCount()); assertEquals( 3, fins.getPointCount()); assertEquals( AxialMethod.TOP, fins.getAxialMethod()); assertEquals( 0.4, fins.getAxialOffset(), EPSILON); // pre-condition - assertEquals( 1.0, mount.getLength(), EPSILON); + assertEquals( 1.0, tailCone.getLength(), EPSILON); // fin offset: 0.4 -> 0.59 (just short of prev fin end) // fin end: 0.4 ~> min root chord @@ -888,9 +886,10 @@ public class FreeformFinSetTest extends BaseTestCase { 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: - Rocket rkt = createTemplateRocket(); - FreeformFinSet fins = (FreeformFinSet) rkt.getChild(0).getChild(2).getChild(0); - + final Rocket rkt = createTemplateRocket(); + final Transition tailCone = (Transition) rkt.getChild(0).getChild(2); + final FreeformFinSet fins = createFinOnConicalTransition(tailCone); + // all points are restricted to be outside the parent body: Coordinate exp_pt = fins.getFinPoints()[0]; fins.setPoint(0, -0.6, 0); @@ -900,10 +899,10 @@ public class FreeformFinSetTest extends BaseTestCase { assertEquals( 0.0, act_pt.y, EPSILON); } { // more transitions trigger more complicated positioning math: - Rocket rkt = createTemplateRocket(); - FreeformFinSet fins = (FreeformFinSet) rkt.getChild(0).getChild(2).getChild(0); - assertEquals( 1, fins.getFinCount()); - + final Rocket rkt = createTemplateRocket(); + final Transition tailCone = (Transition) rkt.getChild(0).getChild(2); + final FreeformFinSet fins = this.createFinOnConicalTransition(tailCone); + Coordinate act_p_l; Coordinate exp_p_l; @@ -921,17 +920,17 @@ public class FreeformFinSetTest extends BaseTestCase { @Test public void testSetOffset_triggerClampCorrection() { // test correction of last point due to moving entire fin: - Rocket rkt = createTemplateRocket(); - Transition body = (Transition) rkt.getChild(0).getChild(2); - FreeformFinSet fins = (FreeformFinSet) rkt.getChild(0).getChild(2).getChild(0); - + final Rocket rkt = createTemplateRocket(); + final Transition tailCone = (Transition) rkt.getChild(0).getChild(2); + final FreeformFinSet fins = this.createFinOnConicalTransition(tailCone); + final int lastIndex = fins.getPointCount()-1; final double initXOffset = fins.getAxialOffset(); assertEquals( 0.4, initXOffset, EPSILON); // pre-condition final double newXTop = 0.85; final double expFinOffset = 0.6; - final double expLength = body.getLength() - expFinOffset; + final double expLength = tailCone.getLength() - expFinOffset; fins.setAxialOffset( AxialMethod.TOP, newXTop); // fin start: 0.4 => 0.8 [body] // fin end: 0.8 => 0.99 [body] @@ -945,7 +944,7 @@ public class FreeformFinSetTest extends BaseTestCase { } @Test - public void testComputeCM_mountlesFin(){ + public void testComputeCM_mountlessFin(){ // This is a trapezoid. Height 1, root 1, tip 1/2 no sweep. // It can be decomposed into a rectangle followed by a triangle // +---+ @@ -970,47 +969,58 @@ public class FreeformFinSetTest extends BaseTestCase { @Test public void testTranslatePoints(){ - final Rocket rkt = new Rocket(); - final AxialStage stg = new AxialStage(); - rkt.addChild(stg); - BodyTube body = new BodyTube(2.0, 0.01); - stg.addChild(body); - + final Rocket rkt = createTemplateRocket(); + final BodyTube body = (BodyTube) rkt.getChild(0).getChild(1); + final FreeformFinSet fin = this.createFinOnTube(body); + + assertNotNull(fin.getParent()); + // Fin length = 1 // Body Length = 2 // +--+ // / | // / | // +---+-----+---+ - // - FreeformFinSet fins = new FreeformFinSet(); - fins.setFinCount(1); - Coordinate[] initPoints = new Coordinate[] { - new Coordinate(0, 0), - new Coordinate(0.5, 1), - new Coordinate(1, 1), - new Coordinate(1, 0) - }; - fins.setPoints(initPoints); - body.addChild(fins); - - final AxialMethod[] pos={AxialMethod.TOP, AxialMethod.MIDDLE, AxialMethod.MIDDLE, AxialMethod.BOTTOM}; + final Coordinate[] expectPoints = new Coordinate[]{ + Coordinate.ZERO, + new Coordinate(0.5, 1), + new Coordinate(1, 1), + new Coordinate(1, 0) + }; + + final Coordinate[] finPoints = fin.getFinPoints(); + assertEquals(4, finPoints.length); + assertEquals(expectPoints[1], finPoints[1]); + assertEquals(expectPoints[2], finPoints[2]); + assertEquals(expectPoints[3], finPoints[3]); + + // mounting body: + assertEquals(body.getLength(), 2.0, EPSILON); + + assertEquals(fin.getAxialMethod(), AxialMethod.BOTTOM); + assertEquals(fin.getAxialOffset(), 0.0, EPSILON); + + final AxialMethod[] pos={AxialMethod.TOP, AxialMethod.MIDDLE, AxialMethod.MIDDLE, AxialMethod.BOTTOM}; final double[] offs = {1.0, 0.0, 0.4, -0.2}; final double[] expOffs = {1.0, 0.5, 0.9, 0.8}; for( int caseIndex=0; caseIndex < pos.length; ++caseIndex ){ - fins.setAxialOffset( pos[caseIndex], offs[caseIndex]); - final double x_delta = fins.getAxialOffset(AxialMethod.TOP); + fin.setAxialOffset( pos[caseIndex], offs[caseIndex]); + + assertEquals(fin.getAxialMethod(), pos[caseIndex]); + assertEquals(fin.getAxialOffset(), offs[caseIndex], EPSILON); + + final double x_delta = fin.getAxialOffset(AxialMethod.TOP); - Coordinate actualPoints[] = fins.getFinPoints(); + final Coordinate[] actualPoints = fin.getFinPoints(); - final String rawPointDescr = "\n"+fins.toDebugDetail().toString()+"\n>> axial offset: "+x_delta; + final String rawPointDescr = "\n"+fin.toDebugDetail().toString()+"\n>> axial offset: "+x_delta; Coordinate[] displayPoints = FinSet.translatePoints( actualPoints, x_delta, 0); for( int index=0; index < displayPoints.length; ++index){ - assertEquals(String.format("Bad Fin Position.x (%6.2g via:%s at point: %d) %s\n",offs[caseIndex], pos[caseIndex].name(), index, rawPointDescr), - (initPoints[index].x + expOffs[caseIndex]), displayPoints[index].x, EPSILON); + assertEquals(String.format("Bad Fin Position.x (%6.2g via:%s at point: %d) %s\n",offs[caseIndex], pos[caseIndex].name(), index, rawPointDescr), + (expectPoints[index].x + expOffs[caseIndex]), displayPoints[index].x, EPSILON); assertEquals(String.format("Bad Fin Position.y (%6.2g via:%s at point: %d) %s\n",offs[caseIndex], pos[caseIndex].name(), index, rawPointDescr), - initPoints[index].y, displayPoints[index].y, EPSILON); + expectPoints[index].y, displayPoints[index].y, EPSILON); } } @@ -1018,41 +1028,32 @@ public class FreeformFinSetTest extends BaseTestCase { @Test public void testForIntersection_false() { - final Rocket rkt = new Rocket(); - final AxialStage stg = new AxialStage(); - rkt.addChild(stg); - BodyTube body = new BodyTube(2.0, 0.01); - stg.addChild(body); - - // Fin length = 1 - // Body Length = 2 - // +--+ - // / | - // / | - // +---+-----+---+ - // - FreeformFinSet fins = new FreeformFinSet(); - fins.setFinCount(1); - Coordinate[] initPoints = new Coordinate[] { - new Coordinate(0, 0), - new Coordinate(0.5, 1), - new Coordinate(1, 1), - new Coordinate(1, 0) - }; - fins.setPoints(initPoints); - body.addChild(fins); - - assertFalse( " Fin detects false positive intersection in fin points: ", fins.intersects()); + final Rocket rkt = createTemplateRocket(); + final BodyTube body = (BodyTube) rkt.getChild(0).getChild(1); + final FreeformFinSet fins = createFinOnTube(body); + + // Fin length = 1 + // Body Length = 2 + // +--+ + // / | + // / | + // +---+-----+---+ + final Coordinate[] finPoints = fins.getFinPoints(); + assertEquals(4, finPoints.length); + assertEquals(finPoints[0], Coordinate.ZERO); + assertEquals(finPoints[1], new Coordinate(0.5, 1.0)); + assertEquals(finPoints[2], new Coordinate(1.0, 1.0)); + assertEquals(finPoints[3], new Coordinate(1.0, 0.0)); + + assertFalse( " Fin detects false positive intersection in fin points: ", fins.intersects()); } @Test public void testForIntersection_true() { - final Rocket rkt = new Rocket(); - final AxialStage stg = new AxialStage(); - rkt.addChild(stg); - BodyTube body = new BodyTube(2.0, 0.01); - stg.addChild(body); - // + final Rocket rkt = createTemplateRocket(); + final Transition tailCone = (Transition) rkt.getChild(0).getChild(2); + final FreeformFinSet fins = this.createFinOnConicalTransition(tailCone); + // An obviously intersecting fin: // [2] +-----+ [1] // \ / @@ -1062,8 +1063,6 @@ public class FreeformFinSetTest extends BaseTestCase { // [0] / \ [3] // +---+-----+---+ // = +x => - FreeformFinSet fins = new FreeformFinSet(); - fins.setFinCount(1); Coordinate[] initPoints = new Coordinate[] { new Coordinate(0, 0), new Coordinate(1, 1), @@ -1072,7 +1071,6 @@ public class FreeformFinSetTest extends BaseTestCase { }; // this line throws an exception? fins.setPoints(initPoints); - body.addChild(fins); // this *already* has detected the intersection, and aborted... Coordinate p1 = fins.getFinPoints()[1]; @@ -1083,21 +1081,17 @@ public class FreeformFinSetTest extends BaseTestCase { @Test public void testForIntersectionAtFirstLast() { - final Rocket rkt = new Rocket(); - final AxialStage stg = new AxialStage(); - rkt.addChild(stg); - BodyTube body = new BodyTube(2.0, 0.01); - stg.addChild(body); - // - // An obviously intersecting fin: + final Rocket rkt = createTemplateRocket(); + final Transition tailCone = (Transition) rkt.getChild(0).getChild(2); + final FreeformFinSet fins = this.createFinOnConicalTransition(tailCone); + + // An obviously intersecting fin: // [2] +---+ [1] // | / // | / // [0]|/ [3] // +---+-----+---+ // = +x => - FreeformFinSet fins = new FreeformFinSet(); - fins.setFinCount(1); Coordinate[] initPoints = new Coordinate[] { new Coordinate(0, 0), new Coordinate(0, 1), @@ -1106,7 +1100,6 @@ public class FreeformFinSetTest extends BaseTestCase { }; // this line throws an exception? fins.setPoints(initPoints); - body.addChild(fins); final Coordinate[] finPoints = fins.getFinPoints(); @@ -1173,10 +1166,12 @@ public class FreeformFinSetTest extends BaseTestCase { @Test public void testGenerateBodyPointsOnBodyTube(){ final Rocket rkt = createTemplateRocket(); - final FreeformFinSet fins = (FreeformFinSet) rkt.getChild(0).getChild(1).getChild(0); + final BodyTube body = (BodyTube) rkt.getChild(0).getChild(1); + final FreeformFinSet fins = this.createFinOnTube(body); + final Coordinate finFront = fins.getFinFront(); final Coordinate[] finPoints = fins.getFinPoints(); - final Coordinate[] finPointsFromBody = FinSet.translatePoints( finPoints, 0.0, fins.getFinFront().y); + final Coordinate[] finPointsFromBody = FinSet.translatePoints( finPoints, finFront.x, finFront.y); { // body points (relative to body) final Coordinate[] mountPoints = fins.getMountPoints(); @@ -1201,8 +1196,9 @@ public class FreeformFinSetTest extends BaseTestCase { @Test public void testGenerateBodyPointsOnConicalTransition(){ final Rocket rkt = createTemplateRocket(); - final FreeformFinSet fins = (FreeformFinSet) rkt.getChild(0).getChild(2).getChild(0); - + final Transition tailCone = (Transition) rkt.getChild(0).getChild(2); + final FreeformFinSet fins = this.createFinOnConicalTransition(tailCone); + final Coordinate[] finPoints = fins.getFinPoints(); { // body points (relative to body) @@ -1228,8 +1224,8 @@ public class FreeformFinSetTest extends BaseTestCase { @Test public void testGenerateBodyPointsOnEllipsoidNose(){ final Rocket rocket = createTemplateRocket(); - final Transition body = (Transition)rocket.getChild(0).getChild(0); - final FinSet fins = (FreeformFinSet) body.getChild(0); + final NoseCone nose = (NoseCone) rocket.getChild(0).getChild(0); + final FreeformFinSet fins = this.createFinOnEllipsoidNose(nose); final Coordinate finFront = fins.getFinFront(); final Coordinate[] finPoints = fins.getFinPoints(); @@ -1245,7 +1241,7 @@ public class FreeformFinSetTest extends BaseTestCase { // ?? SMOKING GUN: // ?? is this y-value of the fin not getting snapped to the body? - assertEquals(body.getRadius(0.8+finFront.x) - finFront.y, finPoints[3].y, EPSILON); + assertEquals(nose.getRadius(0.8+finFront.x) - finFront.y, finPoints[3].y, EPSILON); assertEquals("incorrect body points! ", 0.78466912, finPoints[3].y, EPSILON); @@ -1274,7 +1270,7 @@ public class FreeformFinSetTest extends BaseTestCase { assertEquals(String.format("Root points @ %d :: x coordinate mismatch!", testIndex), expectedX[testCase], rootPoints[testIndex].x, EPSILON); assertEquals(String.format("Root points @ %d :: y coordinate mismatch!", testIndex), - body.getRadius(rootPoints[testIndex].x + finFront.x) - finFront.y, rootPoints[testIndex].y, EPSILON); + nose.getRadius(rootPoints[testIndex].x + finFront.x) - finFront.y, rootPoints[testIndex].y, EPSILON); } } }{ // body points (relative to body) @@ -1301,7 +1297,7 @@ public class FreeformFinSetTest extends BaseTestCase { assertEquals(String.format("Body points @ %d :: x coordinate mismatch!", testIndex), expectedX[testCase], mountPoints[testIndex].x, EPSILON); assertEquals(String.format("Body points @ %d :: y coordinate mismatch!", testIndex), - body.getRadius(mountPoints[testIndex].x), mountPoints[testIndex].y, EPSILON); + nose.getRadius(mountPoints[testIndex].x), mountPoints[testIndex].y, EPSILON); } } } @@ -1309,10 +1305,7 @@ public class FreeformFinSetTest extends BaseTestCase { @Test public void testFreeFormCMWithNegativeY() throws Exception { - // A user submitted an ork file which could not be simulated because the fin - // was constructed on a tail cone. It so happened that for one pair of points - // y_n = - y_(n+1) which caused a divide by zero and resulted in CGx = NaN. - // + // A user submitted an ork file which could not be simulated. // This Fin set is constructed to have the same problem. It is a square and rectangle // where the two trailing edge corners of the rectangle satisfy y_0 = -y_1 // @@ -1330,9 +1323,7 @@ public class FreeformFinSetTest extends BaseTestCase { // | // | FreeformFinSet fins = new FreeformFinSet(); - fins.setCrossSection( CrossSection.SQUARE ); // to ensure uniform density - fins.setFinCount(1); - // fins.setAxialOffset( Position.BOTTOM, 1.0); // ERROR: no parent! + fins.setAxialOffset( AxialMethod.BOTTOM, -1.0); Coordinate[] points = new Coordinate[] { new Coordinate(0, 0), new Coordinate(0, 1), @@ -1341,26 +1332,24 @@ public class FreeformFinSetTest extends BaseTestCase { new Coordinate(1, -1), new Coordinate(1, 0) }; - fins.setPoints(points); - Coordinate coords = fins.getCG(); - assertEquals(3.0, fins.getPlanformArea(), EPSILON); - assertEquals(3.5 / 3.0, coords.x, EPSILON); - assertEquals(0.5 / 3.0, coords.y, EPSILON); - + + System.err.println(fins.toDebugDetail()); + fins.setPoints( points); fins.setFilletRadius( 0.0); fins.setTabHeight( 0.0); + fins.setCrossSection( CrossSection.SQUARE ); // to ensure uniform density fins.setMaterial( Material.newMaterial(Type.BULK, "dummy", 1.0, true)); -// assertEquals( 3.0, fins.getFinWettedArea(), EPSILON); -// -// Coordinate cg = fins.getCG(); -// assertEquals( 1.1666, cg.x, EPSILON); -// assertEquals( 0.1666, cg.y, EPSILON); -// assertEquals( 0.0, cg.z, EPSILON); -// assertEquals( 0.009, cg.weight, EPSILON); + assertEquals( 3.0, fins.getPlanformArea(), EPSILON); + final Coordinate cg = fins.getCG(); + assertEquals(3.0, fins.getPlanformArea(), EPSILON); + assertEquals(3.5 / 3.0, cg.x, EPSILON); + assertEquals(0.5 / 3.0, cg.y, EPSILON); + assertEquals( 0.0, cg.z, EPSILON); + assertEquals( 0.009, cg.weight, EPSILON); } } From 01fd20ebcc7696f2f65c9f7195298b2329f935f9 Mon Sep 17 00:00:00 2001 From: Daniel M Williams Date: Sun, 16 Dec 2018 13:11:33 -0500 Subject: [PATCH 2/3] [refactor] added code to tests for negative inertia / intersection case --- .../sf/openrocket/rocketcomponent/FinSet.java | 149 +++-- .../rocketcomponent/FreeformFinSet.java | 336 +++-------- .../rocketcomponent/Transition.java | 6 +- .../masscalc/MassCalculatorTest.java | 41 +- .../rocketcomponent/FreeformFinSetTest.java | 550 ++++++++++-------- .../configdialog/FreeformFinSetConfig.java | 3 + 6 files changed, 520 insertions(+), 565 deletions(-) diff --git a/core/src/net/sf/openrocket/rocketcomponent/FinSet.java b/core/src/net/sf/openrocket/rocketcomponent/FinSet.java index 2f99e1091..57bb50b27 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/FinSet.java +++ b/core/src/net/sf/openrocket/rocketcomponent/FinSet.java @@ -439,17 +439,25 @@ public abstract class FinSet extends ExternalComponent implements RingInstanceab * 5. Return twice that since there is a fillet on each side of the fin. */ protected Coordinate calculateFilletVolumeCentroid() { + if((null == this.parent) || (!SymmetricComponent.class.isAssignableFrom(this.parent.getClass()))){ + return Coordinate.ZERO; + } Coordinate[] mountPoints = this.getRootPoints(); - if( null == mountPoints ){ +// if( null == mountPoints ){ +// return Coordinate.ZERO; +// } + + final SymmetricComponent sym = (SymmetricComponent) this.parent; + + final Coordinate finLead = getFinFront(); + final double xFinEnd = finLead.x + getLength(); + final Coordinate[] rootPoints = getMountPoints( finLead.x, xFinEnd, -finLead.x, -finLead.y); + if (0 == rootPoints.length) { return Coordinate.ZERO; } - final SymmetricComponent sym = (SymmetricComponent) this.parent; - if (!SymmetricComponent.class.isInstance(this.parent)) { - return Coordinate.ZERO; - } - Coordinate filletVolumeCentroid = Coordinate.ZERO; + Coordinate prev = mountPoints[0]; for (int index = 1; index < mountPoints.length; index++) { final Coordinate cur = mountPoints[index]; @@ -470,7 +478,7 @@ public abstract class FinSet extends ExternalComponent implements RingInstanceab prev = cur; } - + if (finCount == 1) { Transformation rotation = Transformation.rotate_x( getAngleOffset()); return rotation.transform(filletVolumeCentroid); @@ -496,10 +504,9 @@ public abstract class FinSet extends ExternalComponent implements RingInstanceab for( int index = 1; index < points.length; index++){ Coordinate cur = points[index]; + // calculate marginal area final double delta_x = (cur.x - prev.x); final double y_avg = (cur.y + prev.y)*0.5; - - // calculate marginal area double area_increment = delta_x*y_avg; if( MathUtil.equals( 0, area_increment)){ prev = cur; @@ -534,20 +541,17 @@ public abstract class FinSet extends ExternalComponent implements RingInstanceab // relto: fin final double xTabFront_fin = getTabFrontEdge(); final double xTabTrail_fin = getTabTrailingEdge(); - - final double xFinFront_body = this.getAxialFront(); + + final Coordinate finFront = getFinFront(); + final double xFinFront_body = finFront.x; final double xTabFront_body = xFinFront_body + xTabFront_fin; final double xTabTrail_body = xFinFront_body + xTabTrail_fin; - // always returns x coordinates relTo fin front: - Coordinate[] upperCurve = getMountInterval( xTabFront_body, xTabTrail_body ); - // locate relative to fin/body centerline - upperCurve = translatePoints( upperCurve, -xFinFront_body, 0.0); - - Coordinate[] lowerCurve = translateToCenterline( getTabPoints()); - + // get body points, relTo fin front / centerline); + final Coordinate[] upperCurve = getMountPoints( xTabFront_body, xTabTrail_body, -xFinFront_body, 0); + final Coordinate[] lowerCurve = translateToCenterline( getTabPoints()); final Coordinate[] tabPoints = combineCurves( upperCurve, lowerCurve); - + return calculateCurveIntegral( tabPoints ); } @@ -559,27 +563,23 @@ public abstract class FinSet extends ExternalComponent implements RingInstanceab } /** - * calculates the 2-dimensional area-centroid of a single fin. - * - * Located from the leading end of the fin root. + * The coordinate contains an x,y coordinate of the centroid, relative to the parent-body-centerline + * The weight contains the area of the fin. * * @return area centroid coordinates (weight is the area) */ - - /* - * The coordinate contains an x,y coordinate of the centroid, relative to the parent-body-centerline - */ private Coordinate calculateSinglePlanformCentroid(){ - final Coordinate finFront = getFinFront(); - - final Coordinate[] upperCurve = getFinPoints(); - final Coordinate[] lowerCurve = getRootPoints(); + final Coordinate finLead = getFinFront(); + final double xFinTrail = finLead.x+getLength(); + + final Coordinate[] upperCurve = translatePoints(getFinPoints(), 0, finLead.y); + final Coordinate[] lowerCurve = getMountPoints( finLead.x, xFinTrail, -finLead.x, 0); final Coordinate[] totalCurve = combineCurves( upperCurve, lowerCurve); - - Coordinate planformCentroid = calculateCurveIntegral( totalCurve ); + + final Coordinate planformCentroid = calculateCurveIntegral( totalCurve ); // return as a position relative to fin-root - return planformCentroid.add(0., finFront.y, 0); + return planformCentroid; } /** @@ -592,15 +592,15 @@ public abstract class FinSet extends ExternalComponent implements RingInstanceab * @return combined curve */ private Coordinate[] combineCurves( final Coordinate[] c1, final Coordinate[] c2){ - Coordinate[] combined = new Coordinate[ c1.length + c2.length - 1]; + Coordinate[] combined = new Coordinate[ c1.length + c2.length]; // copy the first array to the start of the return array... System.arraycopy(c1, 0, combined, 0, c1.length); Coordinate[] revCurve = reverse( c2); int writeIndex = c1.length; // start directly after previous array - int writeCount = revCurve.length - 1; // write all-but-first - System.arraycopy(revCurve, 1, combined, writeIndex, writeCount); + int writeCount = revCurve.length; + System.arraycopy(revCurve, 0, combined, writeIndex, writeCount); return combined; } @@ -813,7 +813,12 @@ public abstract class FinSet extends ExternalComponent implements RingInstanceab // by default, assume a flat base return true; } - + + /** + * Return a copied list of the given input, translated by the delta + * + * @return List of XY-coordinates. + */ protected static Coordinate[] translatePoints( final Coordinate[] inp, final double x_delta , final double y_delta){ Coordinate[] returnPoints = new Coordinate[inp.length]; for( int index=0; index < inp.length; ++index){ @@ -823,8 +828,23 @@ public abstract class FinSet extends ExternalComponent implements RingInstanceab } return returnPoints; } - - + + /** + * Return a copied list of the given input, translated by the delta + * + * @return List of XY-coordinates. + */ + protected static ArrayList translatePoints( final ArrayList inp, final Coordinate delta){ + final ArrayList returnPoints = new ArrayList<>(); + returnPoints.ensureCapacity(inp.size()); + + for( Coordinate c: inp ){ + returnPoints.add(c.add(delta)); + } + + return returnPoints; + } + /** * Return a list of X,Y coordinates defining the geometry of a single fin tab. * The origin is the leading root edge, and the tab height (or 'depth') is @@ -1037,22 +1057,23 @@ public abstract class FinSet extends ExternalComponent implements RingInstanceab } /** +<<<<<<< HEAD * use this for calculating physical properties, and routine drawing - * + * * @return points representing the fin-root points, relative to ( x: fin-front, y: centerline ) i.e. relto: fin Component reference point */ public Coordinate[] getMountPoints() { if( null == parent){ return null; } - - return getMountInterval(0., parent.getLength()); + + return getMountPoints(0., parent.getLength(), 0,0); } /** * used to get body points for the profile design view * - * @return points representing the fin-root points, relative to ( x: fin-front, y: fin-root-radius ) + * @return points representing the fin-root points, relative to ( x: fin-front, y: centerline ) i.e. relto: fin Component reference point */ public Coordinate[] getRootPoints(){ if( null == parent){ @@ -1060,16 +1081,25 @@ public abstract class FinSet extends ExternalComponent implements RingInstanceab } final Coordinate finLead = getFinFront(); - final double finTailX = finLead.x + getLength(); + final double xFinEnd = finLead.x + getLength(); - final Coordinate[] bodyPoints = getMountInterval( finLead.x, finTailX); - - return translatePoints(bodyPoints, -finLead.x, -finLead.y); + return getMountPoints( finLead.x, xFinEnd, -finLead.x, -finLead.y); } - - private Coordinate[] getMountInterval( final double xStart, final double xEnd ) { -// System.err.println(String.format(" .... >> mount interval/x: ( %g, %g)]", xStart, xEnd)); + /** + * used to get calculate body profile points: + * + * @param xStart - xStart, in Mount-frame + * @param xEnd - xEnd, in Mount-frame + * @param xOffset - x-Offset to apply to returned points + * @param yOffset - y-Offset to apply to returned points + * + * @return points representing the mount's points + */ + private Coordinate[] getMountPoints(final double xStart, final double xEnd, final double xOffset, final double yOffset) { + if( null == parent){ + return new Coordinate[]{Coordinate.ZERO}; + } // for a simple bodies, one increment is perfectly accurate. int divisionCount = 1; @@ -1104,15 +1134,24 @@ public abstract class FinSet extends ExternalComponent implements RingInstanceab if( body.getLength()-0.000001 < points[lastIndex].x) { points[lastIndex] = points[lastIndex].setX(body.getLength()).setY(body.getAftRadius()); } - + + if( 0.0000001 < (Math.abs(xOffset) + Math.abs(yOffset))){ + points = translatePoints(points, xOffset, yOffset); + } + return points; } // for debugging. You can safely delete this method public static String getPointDescr( final Coordinate[] points, final String name, final String indent){ - StringBuilder buf = new StringBuilder(); - - buf.append(String.format("%s >> %s: %d points\n", indent, name, points.length)); + return getPointDescr(Arrays.asList(points), name, indent); + } + + // for debugging. You can safely delete this method + public static String getPointDescr( final List points, final String name, final String indent){ + StringBuilder buf = new StringBuilder(); + + buf.append(String.format("%s >> %s: %d points\n", indent, name, points.size())); int index =0; for( Coordinate c : points ){ buf.append( String.format( indent+" ....[%2d] (%6.4g, %6.4g)\n", index, c.x, c.y)); @@ -1128,8 +1167,8 @@ public abstract class FinSet extends ExternalComponent implements RingInstanceab buf.append( getPointDescr( this.getFinPoints(), "Fin Points", "")); if (null != parent) { + buf.append( getPointDescr( this.getMountPoints(0, parent.getLength(), 0, 0), "Body Points", "")); buf.append( getPointDescr( this.getRootPoints(), "Root Points", "")); - buf.append( getPointDescr( this.getMountPoints(), "Mount Points", "")); } if( ! this.isTabTrivial() ) { diff --git a/core/src/net/sf/openrocket/rocketcomponent/FreeformFinSet.java b/core/src/net/sf/openrocket/rocketcomponent/FreeformFinSet.java index 99bc17bdf..47d01afd0 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/FreeformFinSet.java +++ b/core/src/net/sf/openrocket/rocketcomponent/FreeformFinSet.java @@ -22,7 +22,7 @@ public class FreeformFinSet extends FinSet { // this class uses certain features of 'ArrayList' which are not implemented in other 'List' implementations. private ArrayList points = new ArrayList<>(); - private static final double SNAP_SMALLER_THAN = 1e-6; + private static final double SNAP_SMALLER_THAN = 5e-3; private static final double IGNORE_SMALLER_THAN = 1e-12; public FreeformFinSet() { @@ -133,7 +133,7 @@ public class FreeformFinSet extends FinSet { ArrayList copy = new ArrayList<>(this.points); this.points.remove(index); - if (!validate()) { + if (intersects()) { // if error, rollback. this.points = copy; } @@ -149,12 +149,6 @@ public class FreeformFinSet extends FinSet { /** maintained just for backwards compatibility: */ public void setPoints(Coordinate[] newPoints) { - // move to zero, if applicable - if( ! Coordinate.ZERO.equals(newPoints[0])) { - final Coordinate p0 = newPoints[0]; - newPoints = translatePoints( newPoints, -p0.x, -p0.y); - } - setPoints(new ArrayList<>(Arrays.asList(newPoints))); } @@ -164,43 +158,29 @@ public class FreeformFinSet extends FinSet { * @param newPoints New points to set as the exposed edges of the fin */ public void setPoints( ArrayList newPoints) { + + final Coordinate delta = newPoints.get(0).multiply(-1); + if( IGNORE_SMALLER_THAN < delta.length2()){ + newPoints = translatePoints( newPoints, delta); + } + // copy the old points, in case validation fails - ArrayList copy = new ArrayList<>(this.points); + final ArrayList pointsCopy = new ArrayList<>(this.points); + final double lengthCopy = this.length; + this.points = newPoints; - this.length = newPoints.get(newPoints.size() -1).x; - + update(); - - //StackTraceElement[] stacktrack = Thread.currentThread().getStackTrace(); - if("Canard fins, mounted to transition".equals(this.getName())) { - log.error(String.format("starting to set %d points @ %s", newPoints.size(), this.getName()), new NullPointerException()); - System.err.println( toDebugDetail()); - } - - if( ! validate()){ + + if( intersects()){ // on error, reset to the old points - this.points = copy; + this.points = pointsCopy; + this.length = lengthCopy; } - + fireComponentChangeEvent(ComponentChangeEvent.AEROMASS_CHANGE); } - - private double y_body(final double x) { - return y_body(x, 0.0); - } - - private double y_body(final double x_target, final double x_ref) { - final SymmetricComponent sym = (SymmetricComponent) getParent(); - return (sym.getRadius(x_target) - sym.getRadius(x_ref)); - } - - public void setPointRelToFin(final int index, final double x_request_fin, final double y_request_fin) throws IllegalFinPointException { - final double x_finStart_body = getAxialFront(); // x @ fin start, body frame - final double y_finStart_body = y_body(x_finStart_body); - - setPoint(index, x_request_fin + x_finStart_body, y_request_fin + y_finStart_body); - } - + /** * Set the point at position i to coordinates (x,y). *

@@ -225,19 +205,16 @@ public class FreeformFinSet extends FinSet { public void setPoint(final int index, final double xRequest, final double yRequest) { if(null != this.getParent()) { - if (0 == index) { - clampFirstPoint(new Coordinate(xRequest, yRequest)); - } else if ((this.points.size() - 1) == index) { - Coordinate priorPoint = points.get(index); - points.set(index, new Coordinate(xRequest, yRequest)); - clampLastPoint(priorPoint); - } else { - // interior points can never change the - points.set(index, new Coordinate(xRequest, yRequest)); - clampInteriorPoint(index); + final Coordinate prior = points.get(index); + points.set(index, new Coordinate(xRequest, yRequest)); + + if((points.size() - 1) == index){ + clampLastPoint(xRequest-prior.x); } } - + + update(); + // this maps the last index and the next-to-last-index to the same 'testIndex' int testIndex = Math.min(index, (points.size() - 2)); if (intersects(testIndex)) { @@ -245,24 +222,24 @@ public class FreeformFinSet extends FinSet { log.error(String.format("ERROR: found an intersection while setting fin point #%d to [%6.4g, %6.4g] : ABORTING setPoint(..) !! ", index, xRequest, yRequest)); return; } - - fireComponentChangeEvent(ComponentChangeEvent.AEROMASS_CHANGE); } private void movePoints(final double delta_x, final double delta_y) { - // skip 0th index -- it's the local origin and is always (0,0) + // zero-out 0th index -- it's the local origin and is always (0,0) + points.set(0, Coordinate.ZERO); + for (int index = 1; index < points.size(); ++index) { final Coordinate oldPoint = this.points.get(index); final Coordinate newPoint = oldPoint.add(delta_x, delta_y, 0.0f); points.set(index, newPoint); } } - + @Override public Coordinate[] getFinPoints() { return points.toArray(new Coordinate[0]); } - + @Override public double getSpan() { double max = 0; @@ -287,237 +264,114 @@ public class FreeformFinSet extends FinSet { return c; } - - @Override - public void setAxialOffset(final AxialMethod newAxialMethod, final double newOffsetRequest) { - super.setAxialOffset(newAxialMethod, newOffsetRequest); - - if (null != parent) { - // if the new position would cause fin overhang, only allow movement up to the end of the parent component. - // N.B. if you want a fin to overhang, add & adjust interior points. - final double backOverhang = getAxialOffset(AxialMethod.BOTTOM); - if (0 < backOverhang) { - final double newOffset = newOffsetRequest - backOverhang; - super.setAxialOffset(newAxialMethod, newOffset); - } - final double frontOverhang = getAxialFront(); - if (0 > frontOverhang) { - final double newOffset = newOffsetRequest - frontOverhang; - super.setAxialOffset(newAxialMethod, newOffset); - } - } - } - + @Override public void update() { + this.length = points.get(points.size() -1).x - points.get(0).x; this.setAxialOffset(this.axialMethod, this.axialOffset); - + if(null != this.getParent()) { - clampFirstPoint(points.get(0)); + clampFirstPoint(); + for(int i=1; i < points.size()-1; i++) { clampInteriorPoint(i); } - clampLastPoint(null); + clampLastPoint(); validateFinTab(); } } - - private void clampFirstPoint(final Coordinate newPoint) { + + private void clampFirstPoint() { final SymmetricComponent body = (SymmetricComponent) getParent(); - + final Coordinate finFront = getFinFront(); final double xFinFront = finFront.x; // x of fin start, body-frame final double yFinFront = finFront.y; // y of fin start, body-frame - final double xBodyStart = -getAxialFront(); // x-offset from start-to-start; fin-frame + + final Coordinate p0 = points.get(0); - double xDelta; - double yDelta; + if( ! Coordinate.ZERO.equals(p0)){ + double xDelta = p0.x; + double xTrail = points.get(points.size() - 1).x; + if(xDelta > xTrail){ + xDelta = xTrail; + } + double yDelta = body.getRadius(xFinFront + xDelta) - yFinFront; - if(IGNORE_SMALLER_THAN > Math.abs(newPoint.x)){ - return; - }else if (xBodyStart > newPoint.x) { - // attempt to place point in front of the start of the body - - // delta for new zeroth point - xDelta = xBodyStart; - yDelta = body.getForeRadius() - yFinFront; - points.set(0, newPoint); - points.add(0, Coordinate.ZERO); - movePoints(-xDelta, -yDelta); - - //System.err.println(String.format(".... @[0]//A: delta= %f, %f", xDelta, yDelta)); - - }else if (xFinFront > body.getLength()) { - final double xNew = body.getLength(); - final double yNew = yFinFront - body.getAftRadius(); - points.set(0, points.set(0, new Coordinate(xNew, yNew))); - - xDelta = xNew - xFinFront; - yDelta = yNew - yFinFront; - movePoints(-xDelta, -yDelta); - //System.err.println(String.format(".... @[0]//B: delta= %f, %f", xDelta, yDelta)); - - }else { - // distance to move the entire fin by: - xDelta = newPoint.x; - yDelta = body.getRadius(xFinFront + xDelta) - yFinFront; movePoints(-xDelta, -yDelta); - //System.err.println(String.format(".... @[0]//C: delta= %f, %f", xDelta, yDelta)); + if(AxialMethod.TOP == getAxialMethod()) { + this.axialOffset = axialOffset + xDelta; + this.position = this.position.add(xDelta, 0, 0); + } else if (AxialMethod.MIDDLE == getAxialMethod()) { + this.axialOffset = axialOffset + xDelta / 2; + } } - + final int lastIndex = points.size()-1; this.length = points.get(lastIndex).x; - - if (AxialMethod.TOP == getAxialMethod()) { - setAxialOffset(AxialMethod.TOP, getAxialOffset() + xDelta); - } else if (AxialMethod.MIDDLE == getAxialMethod()) { - setAxialOffset(AxialMethod.MIDDLE, getAxialOffset() + xDelta / 2); - } + } - + private void clampInteriorPoint(final int index) { final SymmetricComponent sym = (SymmetricComponent) this.getParent(); - final double xPrior = points.get(index).x; - final double yPrior = points.get(index).y; - final Coordinate finFront = getFinFront(); final double xFinFront = finFront.x; // x of fin start, body-frame final double yFinFront = finFront.y; // y of fin start, body-frame - - final double yBody = sym.getRadius(xPrior + xFinFront) - yFinFront; - - // ensure that an interior point is outside of its mounting body: - if (yBody > yPrior) { - points.set(index, points.get(index).setY(yBody)); + + final double xBodyFront = -xFinFront; + final double xBodyBack = xBodyFront + sym.getLength(); + + final double xPrior = points.get(index).x; + final double yPrior = points.get(index).y; + + if((xBodyFront <= xPrior ) && ( xPrior <= xBodyBack )) { + final double yBody = sym.getRadius(xPrior + xFinFront) - yFinFront; + + // ensure that an interior point is outside of its mounting body: + if (yBody > yPrior) { + points.set(index, points.get(index).setY(yBody)); + } } + } - private void clampLastPoint(final Coordinate prior) { + private void clampLastPoint() { + clampLastPoint(0); + } + + private void clampLastPoint(final double xDelta) { final SymmetricComponent body = (SymmetricComponent) getParent(); - - final double xFinStart = getAxialFront(); // x of fin start, body-frame - final double yFinStart = body.getRadius(xFinStart); // y of fin start, body-frame - - final double xBodyStart = -getAxialFront(); // x-offset from start-to-start; fin-frame - final double xBodyEnd = xBodyStart + body.getLength(); /// x-offset from start-to-body; fin-frame - + + final Coordinate finFront = getFinFront(); + final double xFinStart = finFront.x; // x of fin start, body-frame + final double yFinStart = finFront.y; // y of fin start, body-frame + int lastIndex = points.size() - 1; - final Coordinate cur = points.get(lastIndex); + final Coordinate last = points.get(lastIndex); - double xDelta=0; + double yBody = body.getRadius(xFinStart + last.x) - yFinStart; + double yDelta = yBody - last.y; + if( IGNORE_SMALLER_THAN < Math.abs(yDelta)){ + // i.e. if it delta is close enough above OR is inside the body. In either case, snap it to the body. - if (xBodyEnd < cur.x) { - if(SNAP_SMALLER_THAN > Math.abs(xBodyEnd - cur.x)){ - points.set( lastIndex, new Coordinate(xBodyEnd, body.getAftRadius() - yFinStart)); - }else { - // the last point is placed after the end of the mount-body - points.add(new Coordinate(xBodyEnd, body.getAftRadius() - yFinStart)); - } - - if(null != prior) { - xDelta = xBodyEnd - prior.x; - }else{ - xDelta = xBodyEnd - cur.x; - } - //System.err.println(String.format(".... @[-1]//A: delta= %f", xDelta)); - - }else if (cur.x < 0) { - // the last point is positioned ahead of the first point. - points.set(lastIndex, Coordinate.ZERO); - - xDelta = cur.x; - - //System.err.println(String.format(".... @[-1]//B: delta= %f", xDelta)); - - } else { - if(null != prior) { - xDelta = cur.x - prior.x; - } - double yBody = body.getRadius(xFinStart + cur.x) - yFinStart; - if(IGNORE_SMALLER_THAN < Math.abs(yBody - cur.y)) { - // for the first and last points: set y-value to *exactly* match parent body: - points.set(lastIndex, new Coordinate(cur.x, yBody)); - - } - - - //System.err.println(String.format(".... @[-1]//C: delta = %f", xDelta)); + // => set y-value to *exactly* match parent body: + points.set(lastIndex, new Coordinate(last.x, yBody)); } - - if(IGNORE_SMALLER_THAN < Math.abs(xDelta)) { - lastIndex = points.size()-1; + + if( IGNORE_SMALLER_THAN < Math.abs(xDelta)) { this.length = points.get(lastIndex).x; - if (AxialMethod.MIDDLE == getAxialMethod()) { - setAxialOffset(AxialMethod.MIDDLE, getAxialOffset() + xDelta / 2); + this.axialOffset = axialOffset + xDelta/2; } else if (AxialMethod.BOTTOM == getAxialMethod()) { - setAxialOffset(AxialMethod.BOTTOM, getAxialOffset() + xDelta); + this.axialOffset = axialOffset + xDelta; } } } - private boolean validate() { - final Coordinate firstPoint = this.points.get(0); - if (firstPoint.x != 0 || firstPoint.y != 0) { - log.error("Start point illegal -- not located at (0,0): " + firstPoint + " (" + getName() + ")"); - return false; - } - - final Coordinate lastPoint = this.points.get(points.size() - 1); - if (lastPoint.x < 0) { - log.error("End point illegal: end point starts in front of start point: " + lastPoint.x); - return false; - } - - // the last point *is* restricted to be on the surface of its owning component: - SymmetricComponent symBody = (SymmetricComponent) this.getParent(); - if (null != symBody) { - final double startOffset = this.getAxialFront(); - final Coordinate finStart = new Coordinate(startOffset, symBody.getRadius(startOffset)); - - // campare x-values - final Coordinate finAtLast = lastPoint.add(finStart); - if (symBody.getLength() < finAtLast.x) { - log.error("End point falls after parent body ends: [" + symBody.getName() + "]. Exception: ", - new IllegalFinPointException("Fin ends after its parent body \"" + symBody.getName() + "\". Ignoring.")); - log.error(String.format(" ..fin position: (x: %12.10f via: %s)", this.axialOffset, this.axialMethod.name())); - log.error(String.format(" ..Body Length: %12.10f finLength: %12.10f", symBody.getLength(), this.getLength())); - log.error(String.format(" ..fin endpoint: (x: %12.10f, y: %12.10f)", finAtLast.x, finAtLast.y)); - return false; - } - - // compare the y-values - final Coordinate bodyAtLast = finAtLast.setY(symBody.getRadius(finAtLast.x)); - if (0.0001 < Math.abs(finAtLast.y - bodyAtLast.y)) { - String numbers = String.format("finStart=(%6.2g,%6.2g) // fin_end=(%6.2g,%6.2g) // body=(%6.2g,%6.2g)", finStart.x, finStart.y, finAtLast.x, finAtLast.y, bodyAtLast.x, bodyAtLast.y); - log.error("End point does not touch its parent body [" + symBody.getName() + "]. exception: ", - new IllegalFinPointException("End point does not touch its parent body! Expected: " + numbers)); - log.error(" .." + numbers); - return false; - } - } - - if (intersects()) { - log.error("found intersection in finset points!"); - return false; - } - - final int lastIndex = points.size() - 1; - final List pts = this.points; - for (int i = 0; i < lastIndex; i++) { - if (pts.get(i).z != 0) { - log.error("z-coordinate not zero"); - return false; - } - } - - return true; - } - /** * Check if *any* of the fin-point line segments intersects with another. * @@ -541,7 +395,7 @@ public class FreeformFinSet extends FinSet { if ((points.size() - 2) < targetIndex) { throw new IndexOutOfBoundsException("request validate of non-existent fin edge segment: " + targetIndex + "/" + points.size()); } - + // (pre-check the indices above.) final Point2D.Double pt1 = new Point2D.Double(points.get(targetIndex).x, points.get(targetIndex).y); final Point2D.Double pt2 = new Point2D.Double(points.get(targetIndex + 1).x, points.get(targetIndex + 1).y); diff --git a/core/src/net/sf/openrocket/rocketcomponent/Transition.java b/core/src/net/sf/openrocket/rocketcomponent/Transition.java index 587b2b509..d89f6de69 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/Transition.java +++ b/core/src/net/sf/openrocket/rocketcomponent/Transition.java @@ -348,8 +348,10 @@ public class Transition extends SymmetricComponent { */ @Override public double getRadius(double x) { - if (x < 0 || x > length) - return 0; + if ( x < 0 ) + return getForeRadius(); + if ( x > length) + return getAftRadius(); double r1 = getForeRadius(); double r2 = getAftRadius(); diff --git a/core/test/net/sf/openrocket/masscalc/MassCalculatorTest.java b/core/test/net/sf/openrocket/masscalc/MassCalculatorTest.java index 9c123c11d..ab56fcc62 100644 --- a/core/test/net/sf/openrocket/masscalc/MassCalculatorTest.java +++ b/core/test/net/sf/openrocket/masscalc/MassCalculatorTest.java @@ -318,7 +318,6 @@ public class MassCalculatorTest extends BaseTestCase { FlightConfiguration emptyConfig = rocket.getEmptyConfiguration(); rocket.setSelectedConfiguration( emptyConfig.getFlightConfigurationID() ); - double expInertia; RocketComponent cc; double compInertia; @@ -326,30 +325,24 @@ public class MassCalculatorTest extends BaseTestCase { // ====== Payload Stage ====== // ====== ====== ====== ====== { - expInertia = 3.1698055283e-5; - cc= rocket.getChild(0).getChild(0); - compInertia = cc.getRotationalInertia(); - assertEquals(cc.getName()+" Rotational MOI calculated incorrectly: ", expInertia, compInertia, EPSILON); - expInertia = 1.79275e-5; - compInertia = cc.getLongitudinalInertia(); - assertEquals(cc.getName()+" Longitudinal MOI calculated incorrectly: ", expInertia, compInertia, EPSILON); - - cc= rocket.getChild(0).getChild(1); - expInertia = 7.70416e-5; - compInertia = cc.getRotationalInertia(); - assertEquals(cc.getName()+" Rotational MOI calculated incorrectly: ", expInertia, compInertia, EPSILON); - expInertia = 8.06940e-5; - compInertia = cc.getLongitudinalInertia(); - assertEquals(cc.getName()+" Longitudinal MOI calculated incorrectly: ", expInertia, compInertia, EPSILON); - - cc= rocket.getChild(0).getChild(2); - expInertia = 1.43691e-5; - compInertia = cc.getRotationalInertia(); - assertEquals(cc.getName()+" Rotational MOI calculated incorrectly: ", expInertia, compInertia, EPSILON); - expInertia = 7.30265e-6; - compInertia = cc.getLongitudinalInertia(); - assertEquals(cc.getName()+" Longitudinal MOI calculated incorrectly: ", expInertia, compInertia, EPSILON); + final AxialStage payloadStage = (AxialStage) rocket.getChild(0); + + // Component: Nose Cone + final NoseCone payloadNose = (NoseCone) payloadStage.getChild(0); + assertEquals(payloadNose.getName()+" Rotational MOI calculated incorrectly: ", 3.508155e-5, payloadNose.getRotationalInertia(), EPSILON); + assertEquals(payloadNose.getName()+" Longitudinal MOI calculated incorrectly: ", 2.0400578477e-6, payloadNose.getLongitudinalInertia(), EPSILON); + + // Component: Payload BodyTube + final BodyTube payloadBody = (BodyTube)payloadStage.getChild(1); + assertEquals(payloadBody.getName()+" Rotational MOI calculated incorrectly: ", 7.70416e-5, payloadBody.getRotationalInertia(), EPSILON); + assertEquals(payloadBody.getName()+" Longitudinal MOI calculated incorrectly: ", 8.06940e-5, payloadBody.getLongitudinalInertia(), EPSILON); + + // Component: Payload Trailing Transition + final Transition payloadTail = (Transition) payloadStage.getChild(2); + assertEquals(payloadTail.getName()+" Rotational MOI calculated incorrectly: ", 1.43691e-5, payloadTail.getRotationalInertia(), EPSILON); + assertEquals(payloadTail.getName()+" Longitudinal MOI calculated incorrectly: ", 7.30265e-6, payloadTail.getLongitudinalInertia(), EPSILON); + // Component: Interstage cc= rocket.getChild(0).getChild(3); expInertia = 4.22073e-5; compInertia = cc.getRotationalInertia(); diff --git a/core/test/net/sf/openrocket/rocketcomponent/FreeformFinSetTest.java b/core/test/net/sf/openrocket/rocketcomponent/FreeformFinSetTest.java index 2bfb25f8c..38499750c 100644 --- a/core/test/net/sf/openrocket/rocketcomponent/FreeformFinSetTest.java +++ b/core/test/net/sf/openrocket/rocketcomponent/FreeformFinSetTest.java @@ -108,7 +108,7 @@ public class FreeformFinSetTest extends BaseTestCase { new Coordinate( 0.0, 0.0), new Coordinate( 0.4, 1.0), new Coordinate( 0.6, 1.0), - new Coordinate( 0.8, 0.9) // y-value should be automaticaly adjusted to snap to body + new Coordinate( 0.8, 0.788) // y-value should be automatically adjusted to snap to body }; fins.setPoints(points); nose.addChild(fins); @@ -130,13 +130,12 @@ public class FreeformFinSetTest extends BaseTestCase { FreeformFinSet fins = new FreeformFinSet(); fins.setName("TubeBodyFins"); fins.setFinCount(1); - Coordinate[] points = new Coordinate[]{ + fins.setPoints(new Coordinate[]{ new Coordinate(0, 0), new Coordinate(0.5, 1), new Coordinate(1, 1), new Coordinate(1, 0) - }; - fins.setPoints(points); + }); fins.setAxialOffset( AxialMethod.BOTTOM, 0.0); body.addChild(fins); @@ -318,36 +317,42 @@ public class FreeformFinSetTest extends BaseTestCase { final NoseCone nose = (NoseCone) rkt.getChild(0).getChild(0); final FinSet fins = createFinOnEllipsoidNose(nose); - // assert preconditions - assertEquals(Shape.ELLIPSOID, nose.getType()); - assertEquals(1.0, nose.getLength(), EPSILON); - - assertEquals(AxialMethod.TOP, fins.getAxialMethod()); - assertEquals(0.02, fins.getAxialOffset(), EPSILON); - assertEquals(0.8, fins.getLength(), EPSILON); - final Coordinate[] finPoints = fins.getFinPoints(); - assertEquals(4, finPoints.length); - assertEquals(finPoints[0], Coordinate.ZERO); - assertEquals(finPoints[1], new Coordinate(0.4, 1.0)); - assertEquals(finPoints[2], new Coordinate(0.6, 1.0)); - assertEquals(finPoints[3], new Coordinate(0.8, 0.78466912)); - // [1] [2] - // +======+ - // / \ [3] - // / ---+---- - // / -------- - // [0] / -------- - // ---+---- - // - // [0] ( 0.0, 0.0) - // [1] ( 0.4, 1.0) - // [2] ( 0.6, 1.0) - // [3] ( 0.8, 0.7847) + { // assert preconditions::Mount + assertEquals(Shape.ELLIPSOID, nose.getType()); + assertEquals(1.0, nose.getLength(), EPSILON); - final double expectedWettedArea = 0.13397384; - final double actualWettedArea = fins.getPlanformArea(); - Coordinate wcg = fins.getCG(); // relative to parent - assertEquals("Calculated fin area is wrong: ", expectedWettedArea, actualWettedArea, EPSILON); + }{ // Assert fin shape + // [1] [2] + // +======+ + // / \ [3] + // / ---+---- + // / -------- + // [0] / -------- + // ---+---- + // + // [0] ( 0.0, 0.0) + // [1] ( 0.4, 1.0) + // [2] ( 0.6, 1.0) + // [3] ( 0.8, 0.7847) + + assertEquals(AxialMethod.TOP, fins.getAxialMethod()); + assertEquals(0.02, fins.getAxialOffset(), EPSILON); + assertEquals(0.8, fins.getLength(), EPSILON); + + final Coordinate[] finPoints = fins.getFinPoints(); + assertEquals(4, finPoints.length); + assertEquals(Coordinate.ZERO, finPoints[0]); + assertEquals(new Coordinate(0.4, 1.0), finPoints[1]); + assertEquals(new Coordinate(0.6, 1.0), finPoints[2]); + assertEquals(new Coordinate(0.8, 0.78466912), finPoints[3]); + } + + final double expectedPlanformArea = 0.13397384; + final double actualPlanformArea = fins.getPlanformArea(); + assertEquals("Calculated fin planform area is wrong: ", expectedPlanformArea, actualPlanformArea, EPSILON); + + Coordinate wcg = fins.getCG(); // relative to parent + assertEquals("Calculated fin weight is wrong! ", 0.2733066, wcg.weight, EPSILON); assertEquals("Calculated fin centroid is wrong! ", 0.4793588, wcg.x, EPSILON); assertEquals("Calculated fin centroid is wrong! ", 0.996741, wcg.y, EPSILON); } @@ -428,7 +433,7 @@ public class FreeformFinSetTest extends BaseTestCase { } @Test - public void testSetFirstPoint() throws IllegalFinPointException { + public void testSetFirstPoint() { // more transitions trigger more complicated positioning math: final Rocket rkt = createTemplateRocket(); final Transition tailCone = (Transition) rkt.getChild(0).getChild(2); @@ -446,23 +451,29 @@ public class FreeformFinSetTest extends BaseTestCase { { // case 1: fins.setAxialOffset( AxialMethod.TOP, 0.1); fins.setPoints(initialPoints); + assertEquals(0.1f, fins.getAxialOffset(), EPSILON); // vvvv function under test vvvv fins.setPoint( 0, 0.2, 0.1f); // ^^^^ function under test ^^^^ - + + assertEquals(0.3f, fins.getAxialOffset(), EPSILON); + assertEquals(0.2f, fins.getLength(), EPSILON); + assertEquals(0.3, fins.getFinFront().x, EPSILON); assertEquals(0.85, fins.getFinFront().y, EPSILON); final Coordinate[] postPoints = fins.getFinPoints(); assertEquals(postPoints.length, 3); - + // middle point: assertEquals(0.2, postPoints[1].x, EPSILON); assertEquals(0.3, postPoints[1].y, EPSILON); - - assertEquals(0.3f, fins.getAxialOffset(), EPSILON); - assertEquals(0.2f, fins.getLength(), EPSILON); + + // final point + assertEquals(0.2, postPoints[2].x, EPSILON); + assertEquals(-0.1, postPoints[2].y, EPSILON); + }{ // case 2: fins.setAxialOffset( AxialMethod.TOP, 0.1); fins.setPoints(initialPoints); @@ -471,32 +482,35 @@ public class FreeformFinSetTest extends BaseTestCase { fins.setPoint( 0, -0.2, 0.1f); // ^^^^ function under test ^^^^ - assertEquals(0.0, fins.getFinFront().x, EPSILON); + assertEquals(-0.1, fins.getFinFront().x, EPSILON); assertEquals(1.0, fins.getFinFront().y, EPSILON); + assertEquals(-0.1f, fins.getAxialOffset(), EPSILON); + assertEquals(0.6f, fins.getLength(), EPSILON); + final Coordinate[] postPoints = fins.getFinPoints(); - assertEquals(postPoints.length, 4); + assertEquals(postPoints.length, 3); - // pseudo-front point - assertEquals(-0.1, postPoints[1].x, EPSILON); - assertEquals(0.05, postPoints[1].y, EPSILON); + assertEquals(0.6, postPoints[1].x, EPSILON); + assertEquals(0.15, postPoints[1].y, EPSILON); - assertEquals(0.5, postPoints[2].x, EPSILON); - assertEquals(0.15, postPoints[2].y, EPSILON); + assertEquals(0.6, postPoints[2].x, EPSILON); + assertEquals(-0.25, postPoints[2].y, EPSILON); - assertEquals(0.0f, fins.getAxialOffset(), EPSILON); - assertEquals(0.5f, fins.getLength(), EPSILON); }{ // case 3: fins.setAxialOffset( AxialMethod.MIDDLE, 0.0); fins.setPoints(initialPoints); assertEquals(0.3, fins.getFinFront().x, EPSILON); - + // vvvv function under test vvvv fins.setPoint( 0, 0.1, 0.1f); // ^^^^ function under test ^^^^ - - assertEquals(0.4, fins.getFinFront().x, EPSILON); - assertEquals(0.8, fins.getFinFront().y, EPSILON); + + assertEquals(0.05, fins.getAxialOffset(), EPSILON); + assertEquals(0.3, fins.getLength(), EPSILON); + + assertEquals(0.35, fins.getFinFront().x, EPSILON); + assertEquals(0.825, fins.getFinFront().y, EPSILON); final Coordinate[] postPoints = fins.getFinPoints(); assertEquals(postPoints.length, 3); @@ -507,9 +521,6 @@ public class FreeformFinSetTest extends BaseTestCase { assertEquals(0.3, postPoints[2].x, EPSILON); assertEquals(-0.15, postPoints[2].y, EPSILON); - - assertEquals(0.05f, fins.getAxialOffset(), EPSILON); - assertEquals(0.3f, fins.getLength(), EPSILON); }{ // case 4: fins.setAxialOffset( AxialMethod.MIDDLE, 0.0); @@ -519,8 +530,8 @@ public class FreeformFinSetTest extends BaseTestCase { fins.setPoint( 0, -0.1, 0.1f); // ^^^^ function under test ^^^^ - assertEquals(0.2, fins.getFinFront().x, EPSILON); - assertEquals(0.9, fins.getFinFront().y, EPSILON); + assertEquals(0.25, fins.getFinFront().x, EPSILON); + assertEquals(0.875, fins.getFinFront().y, EPSILON); final Coordinate[] postPoints = fins.getFinPoints(); assertEquals(postPoints.length, 3); @@ -537,13 +548,16 @@ public class FreeformFinSetTest extends BaseTestCase { }{ // case 5: fins.setAxialOffset( AxialMethod.BOTTOM, 0.0); fins.setPoints(initialPoints); + assertEquals(0.6, fins.getFinFront().x, EPSILON); // vvvv function under test vvvv fins.setPoint( 0, 0.1, 0.1f); // ^^^^ function under test ^^^^ - + assertEquals(0.7, fins.getFinFront().x, EPSILON); assertEquals(0.65, fins.getFinFront().y, EPSILON); + assertEquals(0.0, fins.getAxialOffset(), EPSILON); + assertEquals(0.3, fins.getLength(), EPSILON); final Coordinate[] postPoints = fins.getFinPoints(); assertEquals(postPoints.length, 3); @@ -555,34 +569,28 @@ public class FreeformFinSetTest extends BaseTestCase { assertEquals(0.3, postPoints[2].x, EPSILON); //assertEquals(0.15, postPoints[2].y, EPSILON); - assertEquals(0.0f, fins.getAxialOffset(), EPSILON); - assertEquals(0.3f, fins.getLength(), EPSILON); }{ // case 6: fins.setAxialOffset( AxialMethod.BOTTOM, 0.0); fins.setPoints(initialPoints); - assertEquals(3, fins.getPointCount()); - + assertEquals(0.6, fins.getFinFront().x, EPSILON); + // vvvv function under test vvvv fins.setPoint( 0, -0.1, 0.1f); // ^^^^ function under test ^^^^ - + assertEquals(0.5, fins.getFinFront().x, EPSILON); assertEquals(0.75, fins.getFinFront().y, EPSILON); + assertEquals(0.5, fins.getLength(), EPSILON); final Coordinate[] postPoints = fins.getFinPoints(); assertEquals(3, postPoints.length); - // mid-point assertEquals(0.5, postPoints[1].x, EPSILON); assertEquals(0.15, postPoints[1].y, EPSILON); assertEquals(0.5, postPoints[2].x, EPSILON); assertEquals(-0.25, postPoints[2].y, EPSILON); - - assertEquals(0.0f, fins.getAxialOffset(), EPSILON); - assertEquals(0.5f, fins.getLength(), EPSILON); } - } @Test @@ -593,6 +601,7 @@ public class FreeformFinSetTest extends BaseTestCase { final Coordinate[] initialPoints = fins.getFinPoints(); final int lastIndex = initialPoints.length - 1; final double xf = initialPoints[lastIndex].x; + final double yf = initialPoints[lastIndex].y; // assert pre-conditions: assertEquals(0.4, fins.getLength(), EPSILON); @@ -607,8 +616,12 @@ public class FreeformFinSetTest extends BaseTestCase { fins.setPoints(initialPoints); // vvvv function under test vvvv - fins.setPoint( lastIndex, xf+0.2, -0.3f); + fins.setPoint( lastIndex, xf+0.2, yf - 0.3f); // ^^^^ function under test ^^^^ + + assertEquals(0.1, fins.getFinFront().x, EPSILON); + assertEquals(0.95, fins.getFinFront().y, EPSILON); + assertEquals(0.6, fins.getLength(), EPSILON); final Coordinate[] postPoints = fins.getFinPoints(); assertEquals(postPoints.length, 3); @@ -621,19 +634,20 @@ public class FreeformFinSetTest extends BaseTestCase { assertEquals(0.6, postPoints[2].x, EPSILON); assertEquals(-0.3, postPoints[2].y, EPSILON); - assertEquals(0.1, fins.getFinFront().x, EPSILON); - assertEquals(0.95, fins.getFinFront().y, EPSILON); - assertEquals(0.6, fins.getLength(), EPSILON); }{ // case 2: fins.setAxialOffset( AxialMethod.TOP, 0.1); fins.setPoints(initialPoints); // vvvv function under test vvvv - fins.setPoint( lastIndex, xf - 0.2, 0.1f); + fins.setPoint( lastIndex, xf - 0.2, yf + 0.1f); // ^^^^ function under test ^^^^ - - final Coordinate[] postPoints = fins.getFinPoints(); + + assertEquals(0.1, fins.getFinFront().x, EPSILON); + assertEquals(0.95, fins.getFinFront().y, EPSILON); + assertEquals(0.2, fins.getLength(), EPSILON); + + final Coordinate[] postPoints = fins.getFinPoints(); assertEquals(postPoints.length, 3); // middle point: @@ -643,19 +657,21 @@ public class FreeformFinSetTest extends BaseTestCase { // last point: assertEquals(0.2, postPoints[2].x, EPSILON); assertEquals(-0.1, postPoints[2].y, EPSILON); - - assertEquals(0.1, fins.getFinFront().x, EPSILON); - assertEquals(0.95, fins.getFinFront().y, EPSILON); - assertEquals(0.2f, fins.getLength(), EPSILON); }{ // case 3: fins.setAxialOffset( AxialMethod.MIDDLE, 0.0); fins.setPoints(initialPoints); + assertEquals(0.3, fins.getFinFront().x, EPSILON); // vvvv function under test vvvv - fins.setPoint( lastIndex, xf + 0.1, 0.1f); + fins.setPoint( lastIndex, xf + 0.1, yf + 0.1f); // ^^^^ function under test ^^^^ - + + assertEquals(0.3, fins.getFinFront().x, EPSILON); + assertEquals(0.85, fins.getFinFront().y, EPSILON); + assertEquals(0.5, fins.getLength(), EPSILON); + assertEquals(0.05, fins.getAxialOffset(), EPSILON); + final Coordinate[] postPoints = fins.getFinPoints(); assertEquals(postPoints.length, 3); @@ -667,19 +683,20 @@ public class FreeformFinSetTest extends BaseTestCase { assertEquals(0.5, postPoints[2].x, EPSILON); assertEquals(-0.25, postPoints[2].y, EPSILON); - assertEquals(0.3, fins.getFinFront().x, EPSILON); - assertEquals(0.85, fins.getFinFront().y, EPSILON); - assertEquals(0.05, fins.getAxialOffset(), EPSILON); - assertEquals(0.5, fins.getLength(), EPSILON); - }{ // case 4: fins.setAxialOffset( AxialMethod.MIDDLE, 0.0); fins.setPoints(initialPoints); + assertEquals(0.3, fins.getFinFront().x, EPSILON); // vvvv function under test vvvv - fins.setPoint( lastIndex, xf - 0.1, 0.1f); + fins.setPoint( lastIndex, xf - 0.1, yf + 0.1f); // ^^^^ function under test ^^^^ + assertEquals(0.3, fins.getFinFront().x, EPSILON); + assertEquals(0.85, fins.getFinFront().y, EPSILON); + assertEquals(0.3, fins.getLength(), EPSILON); + assertEquals(-0.05, fins.getAxialOffset(), EPSILON); + final Coordinate[] postPoints = fins.getFinPoints(); assertEquals(postPoints.length, 3); @@ -691,21 +708,21 @@ public class FreeformFinSetTest extends BaseTestCase { assertEquals(0.3, postPoints[2].x, EPSILON); assertEquals(-0.15, postPoints[2].y, EPSILON); - assertEquals(0.3, fins.getFinFront().x, EPSILON); - assertEquals(0.85, fins.getFinFront().y, EPSILON); - assertEquals(-0.05, fins.getAxialOffset(), EPSILON); - assertEquals(0.3, fins.getLength(), EPSILON); - }{ // case 5: fins.setAxialOffset( AxialMethod.BOTTOM, 0.0); fins.setPoints(initialPoints); // vvvv function under test vvvv - fins.setPoint( lastIndex, xf + 0.1, 0.1f); + fins.setPoint( lastIndex, xf + 0.1, yf + 0.1f); // ^^^^ function under test ^^^^ - + + assertEquals(0.6, fins.getFinFront().x, EPSILON); + assertEquals(0.7, fins.getFinFront().y, EPSILON); + assertEquals(0.1, fins.getAxialOffset(), EPSILON); + assertEquals(0.5f, fins.getLength(), EPSILON); + final Coordinate[] postPoints = fins.getFinPoints(); - assertEquals(postPoints.length, 4); + assertEquals(postPoints.length, 3); // mid-point assertEquals(0.4, postPoints[1].x, EPSILON); @@ -713,25 +730,21 @@ public class FreeformFinSetTest extends BaseTestCase { // pseudo last point assertEquals(0.5, postPoints[2].x, EPSILON); - assertEquals(0.1, postPoints[2].y, EPSILON); + assertEquals(-0.2, postPoints[2].y, EPSILON); - // last point - assertEquals(0.4, postPoints[3].x, EPSILON); - assertEquals(-0.2, postPoints[3].y, EPSILON); - - assertEquals(0.6, fins.getFinFront().x, EPSILON); - assertEquals(0.7, fins.getFinFront().y, EPSILON); - assertEquals(0.0, fins.getAxialOffset(), EPSILON); - assertEquals(0.4f, fins.getLength(), EPSILON); - }{ // case 6: fins.setAxialOffset( AxialMethod.BOTTOM, 0.0); fins.setPoints(initialPoints); // vvvv function under test vvvv - fins.setPoint( lastIndex, xf - 0.1, 0.1f); + fins.setPoint( lastIndex, xf - 0.1, yf + 0.1f); // ^^^^ function under test ^^^^ + assertEquals(0.6, fins.getFinFront().x, EPSILON); + assertEquals(0.7, fins.getFinFront().y, EPSILON); + assertEquals(-0.1, fins.getAxialOffset(), EPSILON); + assertEquals(0.3, fins.getLength(), EPSILON); + final Coordinate[] postPoints = fins.getFinPoints(); assertEquals(postPoints.length, 3); @@ -743,10 +756,6 @@ public class FreeformFinSetTest extends BaseTestCase { assertEquals(0.3, postPoints[2].x, EPSILON); assertEquals(-0.15, postPoints[2].y, EPSILON); - assertEquals(0.6, fins.getFinFront().x, EPSILON); - assertEquals(0.7, fins.getFinFront().y, EPSILON); - assertEquals(-0.1, fins.getAxialOffset(), EPSILON); - assertEquals(0.3, fins.getLength(), EPSILON); } } @@ -805,54 +814,57 @@ public class FreeformFinSetTest extends BaseTestCase { assertEquals(0.5, phantomBody.getOuterRadius(), EPSILON); assertEquals(0.0, phantomBody.getLength(), EPSILON); }{ + // (1)---------(2) + // | Fin | + // | | + // (0)----+----(3) + // | + // (body) final FreeformFinSet fins = new FreeformFinSet(); - fins.setFinCount(4); - Coordinate[] points = new Coordinate[]{ - new Coordinate(0.0, 0.0), - new Coordinate(-0.0508, 0.007721), - new Coordinate(0.0, 0.01544), - new Coordinate(0.0254, 0.007721), - new Coordinate(1.1e-4, 0.0) // final point is within the testing thresholds :/ - }; - fins.setPoints(points); - + fins.setName("SquareFin"); phantomBody.addChild(fins); - assertEquals(1, phantomBody.getChildCount()); + fins.setAxialOffset(AxialMethod.MIDDLE, 0.0); + fins.setPoints(new Coordinate[]{ + new Coordinate(-0.5, 0.0), + new Coordinate(-0.5, 1.0), + new Coordinate(0.5, 1.0), + new Coordinate(0.5, 0.0) + }); }{ // postconditions - final FreeformFinSet fins = (FreeformFinSet) phantomBody.getChild(0); + FreeformFinSet fins = (FreeformFinSet) rkt.getChild(0).getChild(3).getChild(0); + + assertEquals(AxialMethod.MIDDLE, fins.getAxialMethod()); + assertEquals(0.0, fins.getAxialOffset(), EPSILON); + + assertEquals(-0.5, fins.getFinFront().x, EPSILON); + assertEquals(0.5, fins.getFinFront().y, EPSILON); final Coordinate[] postPoints = fins.getFinPoints(); - assertEquals(6, postPoints.length); + assertEquals(4, postPoints.length); - // p1 - assertEquals(-0.0508, postPoints[1].x, EPSILON); - assertEquals(0.007721, postPoints[1].y, EPSILON); + // p0 + assertEquals("p0::x", 0.0, postPoints[0].x, EPSILON); + assertEquals("p0::y", 0.0, postPoints[0].y, EPSILON); - // p2 - assertEquals(0.0, postPoints[2].x, EPSILON); - assertEquals(0.01544, postPoints[2].y, EPSILON); + // p1 + assertEquals("p1::x", 0.0, postPoints[1].x, EPSILON); + assertEquals("p1::y", 1.0, postPoints[1].y, EPSILON); - // p3 - assertEquals(0.0254, postPoints[3].x, EPSILON); - assertEquals(0.007721, postPoints[3].y, EPSILON); + // p2 + assertEquals("p2::x", 1.0, postPoints[2].x, EPSILON); + assertEquals("p2::y", 1.0, postPoints[2].y, EPSILON); - // p4 - assertEquals(0.00011, postPoints[4].x, EPSILON); - assertEquals(0.0, postPoints[4].y, EPSILON); + // p3 / last + assertEquals("p3::x", 1.0, postPoints[3].x, EPSILON); + assertEquals("p3::y", 0.0, postPoints[3].y, EPSILON); - // p/last: generated by loading code: - assertEquals(0.0, postPoints[5].x, EPSILON); - assertEquals(0.0, postPoints[5].y, EPSILON); - - assertEquals(0.0, fins.getLength(), EPSILON); - assertEquals(0.0, fins.getFinFront().x, EPSILON); - assertEquals(0.5, fins.getFinFront().y, EPSILON); + assertEquals(1.0, fins.getLength(), EPSILON); } } @Test - public void testSetFirstPoint_testNonIntersection() { + public void testSetFirstPoint_clampToLast() { final Rocket rkt = createTemplateRocket(); final Transition tailCone = (Transition) rkt.getChild(0).getChild(2); final FreeformFinSet fins = this.createFinOnConicalTransition(tailCone); @@ -868,22 +880,22 @@ public class FreeformFinSetTest extends BaseTestCase { // vv Test Target vv fins.setPoint( 0, 0.6, 0); // ^^ Test Target ^^ - + assertEquals(fins.getFinPoints()[ 0], Coordinate.ZERO); // setting the first point actually offsets the whole fin by that amount: - final double expFinOffset = 1.0; + final double expFinOffset = 0.8; assertEquals("Resultant fin offset does not match!", expFinOffset, fins.getAxialOffset(), EPSILON); assertEquals( 3, fins.getPointCount()); Coordinate actualLastPoint = fins.getFinPoints()[2]; - assertEquals("last point did not adjust correctly: ", 0f, actualLastPoint.x, EPSILON); - assertEquals("last point did not adjust correctly: ", 0f, actualLastPoint.y, EPSILON); + assertEquals(0, actualLastPoint.x, EPSILON); + assertEquals(0, actualLastPoint.y, EPSILON); assertEquals("New fin length is wrong: ", 0.0, fins.getLength(), EPSILON); } @Test - public void testSetPoint_otherPoint() throws IllegalFinPointException { + public void testSetPoint_otherPoint(){ // 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(); @@ -917,31 +929,66 @@ public class FreeformFinSetTest extends BaseTestCase { } } - @Test - public void testSetOffset_triggerClampCorrection() { + + @Test + public void testSetOffset_triggerLeadingClampCorrection() { // test correction of last point due to moving entire fin: final Rocket rkt = createTemplateRocket(); final Transition tailCone = (Transition) rkt.getChild(0).getChild(2); final FreeformFinSet fins = this.createFinOnConicalTransition(tailCone); - + final int lastIndex = fins.getPointCount()-1; - final double initXOffset = fins.getAxialOffset(); - assertEquals( 0.4, initXOffset, EPSILON); // pre-condition - final double newXTop = 0.85; - final double expFinOffset = 0.6; - final double expLength = tailCone.getLength() - expFinOffset; - fins.setAxialOffset( AxialMethod.TOP, newXTop); + { // pre-condition + assertEquals(AxialMethod.TOP, fins.getAxialMethod()); + assertEquals(0.4, fins.getAxialOffset(), EPSILON); + assertEquals(0.4, fins.getLength(), EPSILON); + } + + // vv Test Target vv + fins.setAxialOffset( -0.2); + // ^^ Test Target ^^ + // fin start: 0.4 => 0.8 [body] - // fin end: 0.8 => 0.99 [body] - assertEquals( expFinOffset, fins.getAxialOffset(), EPSILON); - assertEquals( expLength, fins.getLength(), EPSILON); - - // SHOULD DEFINITELY CHANGE - Coordinate actualLastPoint = fins.getFinPoints()[ lastIndex]; + // fin end: 0.8 => 1.2 [body] + assertEquals( -0.2, fins.getAxialOffset(), EPSILON); + assertEquals( 0.4, fins.getLength(), EPSILON); + + // SHOULD DEFINITELY CHANGE + Coordinate actualLastPoint = fins.getFinPoints()[ lastIndex]; assertEquals( 0.4, actualLastPoint.x, EPSILON); - assertEquals( -0.2, actualLastPoint.y, EPSILON); - } + assertEquals( -0.1, actualLastPoint.y, EPSILON); + } + + @Test + public void testSetOffset_triggerTrailingClampCorrection() { + // test correction of last point due to moving entire fin: + final Rocket rkt = createTemplateRocket(); + final Transition tailCone = (Transition) rkt.getChild(0).getChild(2); + final FreeformFinSet fins = this.createFinOnConicalTransition(tailCone); + + final int lastIndex = fins.getPointCount()-1; + + { // pre-condition + assertEquals(AxialMethod.TOP, fins.getAxialMethod()); + assertEquals(0.4, fins.getAxialOffset(), EPSILON); + assertEquals(0.4, fins.getLength(), EPSILON); + } + + // vv Test Target vv + fins.setAxialOffset( 0.8); + // ^^ Test Target ^^ + + // fin start: 0.4 => 0.8 [body] + // fin end: 0.8 => 1.2 [body] + assertEquals( 0.8, fins.getAxialOffset(), EPSILON); + assertEquals( 0.4, fins.getLength(), EPSILON); + + // SHOULD DEFINITELY CHANGE + Coordinate actualLastPoint = fins.getFinPoints()[ lastIndex]; + assertEquals( 0.4, actualLastPoint.x, EPSILON); + assertEquals( -0.1, actualLastPoint.y, EPSILON); + } @Test public void testComputeCM_mountlessFin(){ @@ -1012,7 +1059,7 @@ public class FreeformFinSetTest extends BaseTestCase { final double x_delta = fin.getAxialOffset(AxialMethod.TOP); final Coordinate[] actualPoints = fin.getFinPoints(); - + final String rawPointDescr = "\n"+fin.toDebugDetail().toString()+"\n>> axial offset: "+x_delta; Coordinate[] displayPoints = FinSet.translatePoints( actualPoints, x_delta, 0); @@ -1164,32 +1211,20 @@ public class FreeformFinSetTest extends BaseTestCase { } @Test - public void testGenerateBodyPointsOnBodyTube(){ + public void testGenerateRootPointsOnBodyTube(){ final Rocket rkt = createTemplateRocket(); final BodyTube body = (BodyTube) rkt.getChild(0).getChild(1); final FreeformFinSet fins = this.createFinOnTube(body); - final Coordinate finFront = fins.getFinFront(); - final Coordinate[] finPoints = fins.getFinPoints(); - final Coordinate[] finPointsFromBody = FinSet.translatePoints( finPoints, finFront.x, finFront.y); - - { // body points (relative to body) - final Coordinate[] mountPoints = fins.getMountPoints(); - - assertEquals("Method should only generate minimal points for a conical transition fin body! ", 2, mountPoints.length ); - assertEquals("incorrect body points! ", finPointsFromBody[0].x, mountPoints[0].x, EPSILON); - assertEquals("incorrect body points! ", finPointsFromBody[0].y, mountPoints[0].y, EPSILON); - assertEquals("incorrect body points! ", finPointsFromBody[finPoints.length-1].x, mountPoints[1].x, EPSILON); - assertEquals("incorrect body points! ", finPointsFromBody[finPoints.length-1].y, mountPoints[1].y, EPSILON); - } { // root points (relative to fin-front) + final Coordinate[] finPoints = fins.getFinPoints(); final Coordinate[] rootPoints = fins.getRootPoints(); - + assertEquals("Method should only generate minimal points for a conical transition fin body! ", 2, rootPoints.length ); - assertEquals("incorrect body points! ", finPoints[0].x, rootPoints[0].x, EPSILON); - assertEquals("incorrect body points! ", finPoints[0].y, rootPoints[0].y, EPSILON); - assertEquals("incorrect body points! ", finPoints[finPoints.length-1].x, rootPoints[1].x, EPSILON); - assertEquals("incorrect body points! ", finPoints[finPoints.length-1].y, rootPoints[1].y, EPSILON); + assertEquals("incorrect body point: 0::x ! ", finPoints[0].x, rootPoints[0].x, EPSILON); + assertEquals("incorrect body point: 0::y ! ", finPoints[0].y, rootPoints[0].y, EPSILON); + assertEquals("incorrect body point: -1::x !", finPoints[finPoints.length-1].x, rootPoints[1].x, EPSILON); + assertEquals("incorrect body point: -1::y !", finPoints[finPoints.length-1].y, rootPoints[1].y, EPSILON); } } @@ -1199,18 +1234,8 @@ public class FreeformFinSetTest extends BaseTestCase { final Transition tailCone = (Transition) rkt.getChild(0).getChild(2); final FreeformFinSet fins = this.createFinOnConicalTransition(tailCone); - final Coordinate[] finPoints = fins.getFinPoints(); - - { // body points (relative to body) - final Coordinate[] bodyPoints = fins.getMountPoints(); - - assertEquals("Method should only generate minimal points for a conical transition fin body! ", 2, bodyPoints.length ); - assertEquals("incorrect body points! ", 0.0, bodyPoints[0].x, EPSILON); - assertEquals("incorrect body points! ", 1.0, bodyPoints[0].y, EPSILON); - assertEquals("incorrect body points! ", 1.0, bodyPoints[1].x, EPSILON); - assertEquals("incorrect body points! ", 0.5, bodyPoints[1].y, EPSILON); - } { // body points (relative to root) + final Coordinate[] finPoints = fins.getFinPoints(); final Coordinate[] rootPoints = fins.getRootPoints(); assertEquals("Method should only generate minimal points for a conical transition fin body! ", 2, rootPoints.length ); @@ -1233,17 +1258,14 @@ public class FreeformFinSetTest extends BaseTestCase { { // fin points (relative to fin) // preconditions assertEquals(4, finPoints.length); - assertEquals("incorrect body points! ", 0f, finPoints[0].x, EPSILON); - assertEquals("incorrect body points! ", 0f, finPoints[0].y, EPSILON); + assertEquals("incorrect fin points! ", 0f, finPoints[0].x, EPSILON); + assertEquals("incorrect fin points! ", 0f, finPoints[0].y, EPSILON); - assertEquals("incorrect body points! ", 0.8, finPoints[3].x, EPSILON); + assertEquals("incorrect fin points! ", 0.8, finPoints[3].x, EPSILON); -// ?? SMOKING GUN: -// ?? is this y-value of the fin not getting snapped to the body? - assertEquals(nose.getRadius(0.8+finFront.x) - finFront.y, finPoints[3].y, EPSILON); - assertEquals("incorrect body points! ", 0.78466912, finPoints[3].y, EPSILON); + assertEquals("incorrect fin points! ", 0.78466912, finPoints[3].y, EPSILON); }{ // body points (relative to fin) final Coordinate[] rootPoints = fins.getRootPoints(); @@ -1273,38 +1295,14 @@ public class FreeformFinSetTest extends BaseTestCase { nose.getRadius(rootPoints[testIndex].x + finFront.x) - finFront.y, rootPoints[testIndex].y, EPSILON); } } - }{ // body points (relative to body) - final Coordinate[] mountPoints = fins.getMountPoints(); - assertEquals(101, mountPoints.length); - - // trivial, and uninteresting: - assertEquals("incorrect body points! ", 0.0, mountPoints[0].x, EPSILON); - assertEquals("incorrect body points! ", 0.0, mountPoints[0].y, EPSILON); - - // n.b.: This should match EXACTLY the end point of the fin. (in fin coordinates) - assertEquals("incorrect body points! ", 1.0, mountPoints[mountPoints.length-1].x, EPSILON); - assertEquals("incorrect body points! ", 1.0, mountPoints[mountPoints.length-1].y, EPSILON); - - {// the tests within this scope is are rather fragile, and may break for reasons other than bugs :( - // the number of points is somewhat arbitrary, but if this test fails, the rest *definitely* will. - assertEquals("Method is generating how many points, in general? ", 101, mountPoints.length ); - - final int[] testIndices = { 3, 12, 61, 88}; - final double[] expectedX = { 0.03, 0.12, 0.61, 0.88}; - - for( int testCase = 0; testCase < testIndices.length; testCase++){ - final int testIndex = testIndices[testCase]; - assertEquals(String.format("Body points @ %d :: x coordinate mismatch!", testIndex), - expectedX[testCase], mountPoints[testIndex].x, EPSILON); - assertEquals(String.format("Body points @ %d :: y coordinate mismatch!", testIndex), - nose.getRadius(mountPoints[testIndex].x), mountPoints[testIndex].y, EPSILON); - } - } } } @Test public void testFreeFormCMWithNegativeY() throws Exception { + final Rocket rkt = createTemplateRocket(); + final BodyTube body = (BodyTube) rkt.getChild(0).getChild(1); + // A user submitted an ork file which could not be simulated. // This Fin set is constructed to have the same problem. It is a square and rectangle // where the two trailing edge corners of the rectangle satisfy y_0 = -y_1 @@ -1323,33 +1321,99 @@ public class FreeformFinSetTest extends BaseTestCase { // | // | FreeformFinSet fins = new FreeformFinSet(); - fins.setAxialOffset( AxialMethod.BOTTOM, -1.0); + body.addChild(fins); + fins.setAxialOffset( AxialMethod.TOP, 1.0); + Coordinate[] points = new Coordinate[] { - new Coordinate(0, 0), - new Coordinate(0, 1), - new Coordinate(2, 1), - new Coordinate(2, -1), - new Coordinate(1, -1), - new Coordinate(1, 0) + new Coordinate(0.0, 0), + new Coordinate(0.0, 1), + new Coordinate(2.0, 1), + new Coordinate(2.0, -1), + new Coordinate(1.0001, -1), + new Coordinate(1.0, 0) }; fins.setPoints(points); - System.err.println(fins.toDebugDetail()); - fins.setPoints( points); fins.setFilletRadius( 0.0); fins.setTabHeight( 0.0); fins.setCrossSection( CrossSection.SQUARE ); // to ensure uniform density fins.setMaterial( Material.newMaterial(Type.BULK, "dummy", 1.0, true)); - assertEquals( 3.0, fins.getPlanformArea(), EPSILON); + assertEquals( 3.0, fins.getPlanformArea(), 0.0001); final Coordinate cg = fins.getCG(); - assertEquals(3.0, fins.getPlanformArea(), EPSILON); - assertEquals(3.5 / 3.0, cg.x, EPSILON); - assertEquals(0.5 / 3.0, cg.y, EPSILON); + assertEquals(1.1666, cg.x, 0.0001); + assertEquals(1.1666, cg.y, 0.0001); assertEquals( 0.0, cg.z, EPSILON); assertEquals( 0.009, cg.weight, EPSILON); } + @Test + public void testFreeFormCMWithTooManyPoints() { + final Rocket rkt = createTemplateRocket(); + final BodyTube phantomBody = (BodyTube) rkt.getChild(0).getChild(3); + final FreeformFinSet fins = new FreeformFinSet(); + + // fins.setAxialOffset( Position.BOTTOM, 1.0); // ERROR: no parent! + final Coordinate[] setPoints = new Coordinate[] { + new Coordinate(0.006349996571001852, 0.0), + new Coordinate(0.00635, 0.022224999999999998), + new Coordinate(0.0067056, 0.02716387422039681), + new Coordinate(0.007619999999999999, 0.03174998285500926), + new Coordinate(0.0093472, 0.036159702695982766), + new Coordinate(0.0110998, 0.03951108977512263), + new Coordinate(0.028134012585410983, 0.06508746485276898), + new Coordinate(0.030427066902717206, 0.06843885193190885), + new Coordinate(0.03298470441048184, 0.07170204461422924), + new Coordinate(0.0351895643309686, 0.073906904534716), + new Coordinate(0.03801178502919164, 0.0756707924711054), + new Coordinate(0.04101039452105363, 0.07672912523293904), + new Coordinate(0.04409719840973508, 0.07743468040749481), + new Coordinate(0.04762497428251389, 0.07787565239159215), + new Coordinate(0.0511527501552927, 0.07797799999999999), + new Coordinate(0.08021280390730812, 0.07797799999999999), + new Coordinate(0.08127113666914176, 0.07796384678841163), + new Coordinate(0.08206488624051698, 0.07787565239159215), + new Coordinate(0.08281453861348248, 0.07747877760590453), + new Coordinate(0.08316731620076037, 0.07681731962975852), + new Coordinate(0.08325551059757984, 0.07584718126474434), + new Coordinate(0.083312, 0.07487704289973017), + new Coordinate(0.08329960779598958, 0.033293384799349984), + new Coordinate(0.08325551059757984, 0.03254373242638449), + new Coordinate(0.08307912180394089, 0.03174998285500926), + new Coordinate(0.08263814981984355, 0.031132622077272968), + new Coordinate(0.08180030305005857, 0.030691650093175617), + new Coordinate(0.0806978730898152, 0.030479999999999997), + new Coordinate(0.06178017497203885, 0.030479999999999997), + new Coordinate(0.05635621956764143, 0.030479999999999997), + new Coordinate(0.05344580447259892, 0.030225999999999996), + new Coordinate(0.051461430544160844, 0.0292862), + new Coordinate(0.050006222996639586, 0.027711399999999997), + new Coordinate(0.04921247342526435, 0.0261112), + new Coordinate(0.048683307044347535, 0.024002999999999997), + new Coordinate(0.048768, 0.022098), + new Coordinate(0.048768, 0.0) + }; + fins.setPoints( setPoints); + phantomBody.addChild(fins); + + { // fin points (relative to fin) // preconditions + final Coordinate[] finPoints = fins.getFinPoints(); + assertEquals(37, finPoints.length); + + // fin root length: + assertEquals(0.04241800, fins.length, EPSILON); + + // p_first + assertEquals(0f, finPoints[0].x, EPSILON); + assertEquals(0f, finPoints[0].y, EPSILON); + + // p_last + assertEquals(0.042418, finPoints[36].x, EPSILON); + assertEquals(0., finPoints[36].y, EPSILON); + + } + } + } diff --git a/swing/src/net/sf/openrocket/gui/configdialog/FreeformFinSetConfig.java b/swing/src/net/sf/openrocket/gui/configdialog/FreeformFinSetConfig.java index 8008d8355..26deb3540 100644 --- a/swing/src/net/sf/openrocket/gui/configdialog/FreeformFinSetConfig.java +++ b/swing/src/net/sf/openrocket/gui/configdialog/FreeformFinSetConfig.java @@ -426,6 +426,7 @@ public class FreeformFinSetConfig extends FinSetConfig { finset.setPoint(dragIndex, point.x, point.y); final double bodyFront = -finset.getAxialFront(); + if(0 == dragIndex && bodyFront > point.x){ dragIndex = 1; } @@ -447,6 +448,8 @@ public class FreeformFinSetConfig extends FinSetConfig { if ( 0 < clickIndex) { // if ctrl+click, delete point try { + Point2D.Double point = getCoordinates(event); + System.err.println(String.format("---- Removing Point %d @ %g, %g", clickIndex, point.x, point.y)); finset.removePoint(clickIndex); } catch (IllegalFinPointException ignore) { log.error("Ignoring IllegalFinPointException while dragging, dragIndex=" + dragIndex + ". This is likely an internal error."); From 3b342391b19144fd295c3a28be1de37156bd8872 Mon Sep 17 00:00:00 2001 From: Daniel M Williams Date: Tue, 1 Jan 2019 17:03:44 -0500 Subject: [PATCH 3/3] [fix] may now always edit a FreeformFinSet's p[0]. Again. --- .../openrocket/gui/configdialog/FreeformFinSetConfig.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/swing/src/net/sf/openrocket/gui/configdialog/FreeformFinSetConfig.java b/swing/src/net/sf/openrocket/gui/configdialog/FreeformFinSetConfig.java index 26deb3540..37ccc6118 100644 --- a/swing/src/net/sf/openrocket/gui/configdialog/FreeformFinSetConfig.java +++ b/swing/src/net/sf/openrocket/gui/configdialog/FreeformFinSetConfig.java @@ -424,13 +424,7 @@ public class FreeformFinSetConfig extends FinSetConfig { Point2D.Double point = getCoordinates(event); finset.setPoint(dragIndex, point.x, point.y); - - final double bodyFront = -finset.getAxialFront(); - if(0 == dragIndex && bodyFront > point.x){ - dragIndex = 1; - } - updateFields(); } @@ -449,7 +443,6 @@ public class FreeformFinSetConfig extends FinSetConfig { // if ctrl+click, delete point try { Point2D.Double point = getCoordinates(event); - System.err.println(String.format("---- Removing Point %d @ %g, %g", clickIndex, point.x, point.y)); finset.removePoint(clickIndex); } catch (IllegalFinPointException ignore) { log.error("Ignoring IllegalFinPointException while dragging, dragIndex=" + dragIndex + ". This is likely an internal error.");