[refactor] separated FinSet Tests into files corresponding to FinSet, TrapezoidalFinSet, and FreeformFinSet
This commit is contained in:
parent
104b0ce74f
commit
f3dbceba37
@ -35,361 +35,4 @@ public class FinSetTest extends BaseTestCase {
|
|||||||
assertEquals(1, efins.getFinCount());
|
assertEquals(1, efins.getFinCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testTrapezoidCGComputation() {
|
|
||||||
|
|
||||||
{
|
|
||||||
// This is a simple square fin with sides of 1.0.
|
|
||||||
TrapezoidFinSet fins = new TrapezoidFinSet();
|
|
||||||
fins.setFinCount(1);
|
|
||||||
fins.setFinShape(1.0, 1.0, 0.0, 1.0, .005);
|
|
||||||
|
|
||||||
Coordinate coords = fins.getCG();
|
|
||||||
assertEquals(1.0, fins.getFinArea(), 0.001);
|
|
||||||
assertEquals(0.5, coords.x, 0.001);
|
|
||||||
assertEquals(0.5, coords.y, 0.001);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
// This is a trapezoid. Height 1, root 1, tip 1/2 no sweep.
|
|
||||||
// It can be decomposed into a rectangle followed by a triangle
|
|
||||||
// +---+
|
|
||||||
// | \
|
|
||||||
// | \
|
|
||||||
// +------+
|
|
||||||
TrapezoidFinSet fins = new TrapezoidFinSet();
|
|
||||||
fins.setFinCount(1);
|
|
||||||
fins.setFinShape(1.0, 0.5, 0.0, 1.0, .005);
|
|
||||||
|
|
||||||
Coordinate coords = fins.getCG();
|
|
||||||
assertEquals(0.75, fins.getFinArea(), 0.001);
|
|
||||||
assertEquals(0.3889, coords.x, 0.001);
|
|
||||||
assertEquals(0.4444, coords.y, 0.001);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testInstancePoints_PI_2_BaseRotation() {
|
|
||||||
// This is a simple square fin with sides of 1.0.
|
|
||||||
TrapezoidFinSet fins = new TrapezoidFinSet();
|
|
||||||
fins.setFinCount(4);
|
|
||||||
fins.setFinShape(1.0, 1.0, 0.0, 1.0, .005);
|
|
||||||
fins.setBaseRotation( Math.PI/2 );
|
|
||||||
|
|
||||||
BodyTube body = new BodyTube(1.0, 0.05 );
|
|
||||||
body.addChild( fins );
|
|
||||||
|
|
||||||
Coordinate[] points = fins.getInstanceOffsets();
|
|
||||||
|
|
||||||
assertEquals( 0, points[0].x, 0.00001);
|
|
||||||
assertEquals( 0, points[0].y, 0.00001);
|
|
||||||
assertEquals( 0.05, points[0].z, 0.00001);
|
|
||||||
|
|
||||||
assertEquals( 0, points[1].x, 0.00001);
|
|
||||||
assertEquals( -0.05, points[1].y, 0.00001);
|
|
||||||
assertEquals( 0, points[1].z, 0.00001);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testInstancePoints_PI_4_BaseRotation() {
|
|
||||||
// This is a simple square fin with sides of 1.0.
|
|
||||||
TrapezoidFinSet fins = new TrapezoidFinSet();
|
|
||||||
fins.setFinCount(4);
|
|
||||||
fins.setFinShape(1.0, 1.0, 0.0, 1.0, .005);
|
|
||||||
fins.setBaseRotation( Math.PI/4 );
|
|
||||||
|
|
||||||
BodyTube body = new BodyTube(1.0, 0.05 );
|
|
||||||
body.addChild( fins );
|
|
||||||
|
|
||||||
Coordinate[] points = fins.getInstanceOffsets();
|
|
||||||
|
|
||||||
assertEquals( 0, points[0].x, 0.0001);
|
|
||||||
assertEquals( 0.03535, points[0].y, 0.0001);
|
|
||||||
assertEquals( 0.03535, points[0].z, 0.0001);
|
|
||||||
|
|
||||||
assertEquals( 0, points[1].x, 0.0001);
|
|
||||||
assertEquals( -0.03535, points[1].y, 0.0001);
|
|
||||||
assertEquals( 0.03535, points[1].z, 0.0001);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testInstanceAngles_zeroBaseRotation() {
|
|
||||||
// This is a simple square fin with sides of 1.0.
|
|
||||||
TrapezoidFinSet fins = new TrapezoidFinSet();
|
|
||||||
fins.setFinCount(4);
|
|
||||||
fins.setFinShape(1.0, 1.0, 0.0, 1.0, .005);
|
|
||||||
fins.setBaseRotation( 0.0 );
|
|
||||||
|
|
||||||
double[] angles = fins.getInstanceAngles();
|
|
||||||
|
|
||||||
assertEquals( angles[0], 0, 0.000001 );
|
|
||||||
assertEquals( angles[1], Math.PI/2, 0.000001 );
|
|
||||||
assertEquals( angles[2], Math.PI, 0.000001 );
|
|
||||||
assertEquals( angles[3], 1.5*Math.PI, 0.000001 );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testInstanceAngles_90_BaseRotation() {
|
|
||||||
// This is a simple square fin with sides of 1.0.
|
|
||||||
TrapezoidFinSet fins = new TrapezoidFinSet();
|
|
||||||
fins.setFinCount(4);
|
|
||||||
fins.setFinShape(1.0, 1.0, 0.0, 1.0, .005);
|
|
||||||
fins.setBaseRotation( Math.PI/2 );
|
|
||||||
|
|
||||||
double[] angles = fins.getInstanceAngles();
|
|
||||||
|
|
||||||
assertEquals( angles[0], Math.PI/2, 0.000001 );
|
|
||||||
assertEquals( angles[1], Math.PI, 0.000001 );
|
|
||||||
assertEquals( angles[2], 1.5*Math.PI, 0.000001 );
|
|
||||||
assertEquals( angles[3], 0, 0.000001 );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testFreeformCGComputation() throws Exception {
|
|
||||||
|
|
||||||
{
|
|
||||||
// This is a trapezoid. Height 1, root 1, tip 1/2 no sweep.
|
|
||||||
// It can be decomposed into a rectangle followed by a triangle
|
|
||||||
// +---+
|
|
||||||
// | \
|
|
||||||
// | \
|
|
||||||
// +------+
|
|
||||||
FreeformFinSet fins = new FreeformFinSet();
|
|
||||||
fins.setFinCount(1);
|
|
||||||
Coordinate[] points = new Coordinate[] {
|
|
||||||
new Coordinate(0, 0),
|
|
||||||
new Coordinate(0, 1),
|
|
||||||
new Coordinate(.5, 1),
|
|
||||||
new Coordinate(1, 0)
|
|
||||||
};
|
|
||||||
fins.setPoints(points);
|
|
||||||
Coordinate coords = fins.getCG();
|
|
||||||
assertEquals(0.75, fins.getFinArea(), 0.001);
|
|
||||||
assertEquals(0.3889, coords.x, 0.001);
|
|
||||||
assertEquals(0.4444, coords.y, 0.001);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
// This is the same trapezoid as previous free form, but it has
|
|
||||||
// some extra points along the lines.
|
|
||||||
FreeformFinSet fins = new FreeformFinSet();
|
|
||||||
fins.setFinCount(1);
|
|
||||||
Coordinate[] points = new Coordinate[] {
|
|
||||||
new Coordinate(0, 0),
|
|
||||||
new Coordinate(0, .5),
|
|
||||||
new Coordinate(0, 1),
|
|
||||||
new Coordinate(.25, 1),
|
|
||||||
new Coordinate(.5, 1),
|
|
||||||
new Coordinate(.75, .5),
|
|
||||||
new Coordinate(1, 0)
|
|
||||||
};
|
|
||||||
fins.setPoints(points);
|
|
||||||
Coordinate coords = fins.getCG();
|
|
||||||
assertEquals(0.75, fins.getFinArea(), 0.001);
|
|
||||||
assertEquals(0.3889, coords.x, 0.001);
|
|
||||||
assertEquals(0.4444, coords.y, 0.001);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
// This is the same trapezoid as previous free form, but it has
|
|
||||||
// some extra points which are very close to previous points.
|
|
||||||
// in particular for points 0 & 1,
|
|
||||||
// y0 + y1 is very small.
|
|
||||||
FreeformFinSet fins = new FreeformFinSet();
|
|
||||||
fins.setFinCount(1);
|
|
||||||
Coordinate[] points = new Coordinate[] {
|
|
||||||
new Coordinate(0, 0),
|
|
||||||
new Coordinate(0, 1E-15),
|
|
||||||
new Coordinate(0, 1),
|
|
||||||
new Coordinate(1E-15, 1),
|
|
||||||
new Coordinate(.5, 1),
|
|
||||||
new Coordinate(.5, 1 - 1E-15),
|
|
||||||
new Coordinate(1, 1E-15),
|
|
||||||
new Coordinate(1, 0)
|
|
||||||
};
|
|
||||||
fins.setPoints(points);
|
|
||||||
Coordinate coords = fins.getCG();
|
|
||||||
assertEquals(0.75, fins.getFinArea(), 0.001);
|
|
||||||
assertEquals(0.3889, coords.x, 0.001);
|
|
||||||
assertEquals(0.4444, coords.y, 0.001);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testWildmanVindicatorShape() throws Exception {
|
|
||||||
// This fin shape is similar to the aft fins on the Wildman Vindicator.
|
|
||||||
// A user noticed that if the y values are similar but not equal,
|
|
||||||
// the compuation of CP was incorrect because of numerical instability.
|
|
||||||
//
|
|
||||||
// +-----------------+
|
|
||||||
// \ \
|
|
||||||
// \ \
|
|
||||||
// + \
|
|
||||||
// / \
|
|
||||||
// +---------------------+
|
|
||||||
//
|
|
||||||
FreeformFinSet fins = new FreeformFinSet();
|
|
||||||
fins.setFinCount(1);
|
|
||||||
Coordinate[] points = new Coordinate[] {
|
|
||||||
new Coordinate(0, 0),
|
|
||||||
new Coordinate(0.02143125, 0.01143),
|
|
||||||
new Coordinate(0.009524999999999999, 0.032543749999999996),
|
|
||||||
new Coordinate(0.041275, 0.032537399999999994),
|
|
||||||
new Coordinate(0.066675, 0)
|
|
||||||
};
|
|
||||||
fins.setPoints(points);
|
|
||||||
Coordinate coords = fins.getCG();
|
|
||||||
assertEquals(0.00130, fins.getFinArea(), 0.00001);
|
|
||||||
assertEquals(0.03423, coords.x, 0.00001);
|
|
||||||
assertEquals(0.01427, coords.y, 0.00001);
|
|
||||||
|
|
||||||
BodyTube bt = new BodyTube();
|
|
||||||
bt.addChild(fins);
|
|
||||||
FinSetCalc calc = new FinSetCalc(fins);
|
|
||||||
FlightConditions conditions = new FlightConditions(null);
|
|
||||||
AerodynamicForces forces = new AerodynamicForces();
|
|
||||||
WarningSet warnings = new WarningSet();
|
|
||||||
calc.calculateNonaxialForces(conditions, forces, warnings);
|
|
||||||
//System.out.println(forces);
|
|
||||||
assertEquals(0.023409, forces.getCP().x, 0.0001);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testFreeFormCGWithNegativeY() throws Exception {
|
|
||||||
// This particular fin shape is currently not allowed in OR since the y values are negative
|
|
||||||
// however, it is possible to convert RockSim files and end up with fins which
|
|
||||||
// have negative y values.
|
|
||||||
|
|
||||||
// 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.
|
|
||||||
|
|
||||||
// This Fin set is constructed to have the same problem. It is a square and rectagle
|
|
||||||
// where the two trailing edge corners of the rectangle satisfy y_0 = -y_1
|
|
||||||
//
|
|
||||||
// +---------+
|
|
||||||
// | |
|
|
||||||
// | |
|
|
||||||
// +----+ |
|
|
||||||
// | |
|
|
||||||
// | |
|
|
||||||
// +----+
|
|
||||||
|
|
||||||
FreeformFinSet fins = new FreeformFinSet();
|
|
||||||
fins.setFinCount(1);
|
|
||||||
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)
|
|
||||||
};
|
|
||||||
fins.setPoints(points);
|
|
||||||
Coordinate coords = fins.getCG();
|
|
||||||
assertEquals(3.0, fins.getFinArea(), 0.001);
|
|
||||||
assertEquals(3.5 / 3.0, coords.x, 0.001);
|
|
||||||
assertEquals(0.5 / 3.0, coords.y, 0.001);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testFreeformConvert() {
|
|
||||||
testFreeformConvert(new TrapezoidFinSet());
|
|
||||||
testFreeformConvert(new EllipticalFinSet());
|
|
||||||
testFreeformConvert(new FreeformFinSet());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void testFreeformConvert(FinSet fin) {
|
|
||||||
FreeformFinSet converted;
|
|
||||||
Material mat = Material.newMaterial(Type.BULK, "foo", 0.1, true);
|
|
||||||
|
|
||||||
fin.setBaseRotation(1.1);
|
|
||||||
fin.setCantAngle(0.001);
|
|
||||||
fin.setCGOverridden(true);
|
|
||||||
fin.setColor(Color.BLACK);
|
|
||||||
fin.setComment("cmt");
|
|
||||||
fin.setCrossSection(CrossSection.ROUNDED);
|
|
||||||
fin.setFinCount(5);
|
|
||||||
fin.setFinish(Finish.ROUGH);
|
|
||||||
fin.setLineStyle(LineStyle.DASHDOT);
|
|
||||||
fin.setMassOverridden(true);
|
|
||||||
fin.setMaterial(mat);
|
|
||||||
fin.setOverrideCGX(0.012);
|
|
||||||
fin.setOverrideMass(0.0123);
|
|
||||||
fin.setOverrideSubcomponents(true);
|
|
||||||
fin.setAxialOffset(0.1);
|
|
||||||
fin.setAxialMethod(AxialMethod.ABSOLUTE);
|
|
||||||
fin.setTabHeight(0.01);
|
|
||||||
fin.setTabLength(0.02);
|
|
||||||
fin.setTabRelativePosition(TabRelativePosition.END);
|
|
||||||
fin.setTabShift(0.015);
|
|
||||||
fin.setThickness(0.005);
|
|
||||||
|
|
||||||
|
|
||||||
converted = FreeformFinSet.convertFinSet((FinSet) fin.copy());
|
|
||||||
|
|
||||||
/// what do we want to ACTUALLY compare?
|
|
||||||
// ComponentCompare.assertSimilarity(fin, converted, true); // deprecated; removed
|
|
||||||
|
|
||||||
|
|
||||||
assertEquals(converted.getComponentName(), converted.getName());
|
|
||||||
|
|
||||||
|
|
||||||
// Create test rocket
|
|
||||||
Rocket rocket = new Rocket();
|
|
||||||
AxialStage stage = new AxialStage();
|
|
||||||
BodyTube body = new BodyTube();
|
|
||||||
|
|
||||||
rocket.addChild(stage);
|
|
||||||
stage.addChild(body);
|
|
||||||
body.addChild(fin);
|
|
||||||
rocket.enableEvents();
|
|
||||||
|
|
||||||
Listener l1 = new Listener("l1");
|
|
||||||
rocket.addComponentChangeListener(l1);
|
|
||||||
|
|
||||||
fin.setName("Custom name");
|
|
||||||
assertEquals("FinSet listener has not been notified: ", l1.changed, true);
|
|
||||||
assertEquals(ComponentChangeEvent.NONFUNCTIONAL_CHANGE, l1.changetype);
|
|
||||||
|
|
||||||
|
|
||||||
// Create copy
|
|
||||||
RocketComponent rocketcopy = rocket.copy();
|
|
||||||
|
|
||||||
Listener l2 = new Listener("l2");
|
|
||||||
rocketcopy.addComponentChangeListener(l2);
|
|
||||||
|
|
||||||
FinSet fincopy = (FinSet) rocketcopy.getChild(0).getChild(0).getChild(0);
|
|
||||||
FreeformFinSet.convertFinSet(fincopy);
|
|
||||||
|
|
||||||
assertTrue("FinSet listener is changed", l2.changed);
|
|
||||||
assertEquals(ComponentChangeEvent.TREE_CHANGE,
|
|
||||||
l2.changetype & ComponentChangeEvent.TREE_CHANGE);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static class Listener implements ComponentChangeListener {
|
|
||||||
private boolean changed = false;
|
|
||||||
private int changetype = 0;
|
|
||||||
private final String name;
|
|
||||||
|
|
||||||
public Listener(String name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void componentChanged(ComponentChangeEvent e) {
|
|
||||||
assertFalse("Ensuring listener " + name + " has not been called.", changed);
|
|
||||||
changed = true;
|
|
||||||
changetype = e.getType();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,272 @@
|
|||||||
|
package net.sf.openrocket.rocketcomponent;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import java.awt.geom.Point2D;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import net.sf.openrocket.aerodynamics.AerodynamicForces;
|
||||||
|
import net.sf.openrocket.aerodynamics.FlightConditions;
|
||||||
|
import net.sf.openrocket.aerodynamics.WarningSet;
|
||||||
|
import net.sf.openrocket.aerodynamics.barrowman.FinSetCalc;
|
||||||
|
import net.sf.openrocket.material.Material;
|
||||||
|
import net.sf.openrocket.material.Material.Type;
|
||||||
|
import net.sf.openrocket.rocketcomponent.ExternalComponent.Finish;
|
||||||
|
import net.sf.openrocket.rocketcomponent.FinSet.CrossSection;
|
||||||
|
import net.sf.openrocket.rocketcomponent.FinSet.TabRelativePosition;
|
||||||
|
import net.sf.openrocket.rocketcomponent.position.*;
|
||||||
|
import net.sf.openrocket.util.Color;
|
||||||
|
import net.sf.openrocket.util.Coordinate;
|
||||||
|
import net.sf.openrocket.util.LineStyle;
|
||||||
|
import net.sf.openrocket.util.BaseTestCase.BaseTestCase;
|
||||||
|
|
||||||
|
public class FreeformFinSetTest extends BaseTestCase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFreeformCGComputationSimpleTrapezoid() throws Exception {
|
||||||
|
// This is a trapezoid. Height 1, root 1, tip 1/2 no sweep.
|
||||||
|
// It can be decomposed into a rectangle followed by a triangle
|
||||||
|
// +---+
|
||||||
|
// | \
|
||||||
|
// | \
|
||||||
|
// +------+
|
||||||
|
FreeformFinSet fins = new FreeformFinSet();
|
||||||
|
fins.setFinCount(1);
|
||||||
|
Coordinate[] points = new Coordinate[] {
|
||||||
|
new Coordinate(0, 0),
|
||||||
|
new Coordinate(0, 1),
|
||||||
|
new Coordinate(.5, 1),
|
||||||
|
new Coordinate(1, 0)
|
||||||
|
};
|
||||||
|
fins.setPoints(points);
|
||||||
|
Coordinate coords = fins.getCG();
|
||||||
|
assertEquals(0.75, fins.getFinArea(), 0.001);
|
||||||
|
assertEquals(0.3889, coords.x, 0.001);
|
||||||
|
assertEquals(0.4444, coords.y, 0.001);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFreeformCGComputationTrapezoidExtraPoints() throws Exception {
|
||||||
|
// This is the same trapezoid as previous free form, but it has
|
||||||
|
// some extra points along the lines.
|
||||||
|
FreeformFinSet fins = new FreeformFinSet();
|
||||||
|
fins.setFinCount(1);
|
||||||
|
Coordinate[] points = new Coordinate[] {
|
||||||
|
new Coordinate(0, 0),
|
||||||
|
new Coordinate(0, .5),
|
||||||
|
new Coordinate(0, 1),
|
||||||
|
new Coordinate(.25, 1),
|
||||||
|
new Coordinate(.5, 1),
|
||||||
|
new Coordinate(.75, .5),
|
||||||
|
new Coordinate(1, 0)
|
||||||
|
};
|
||||||
|
fins.setPoints(points);
|
||||||
|
Coordinate coords = fins.getCG();
|
||||||
|
assertEquals(0.75, fins.getFinArea(), 0.001);
|
||||||
|
assertEquals(0.3889, coords.x, 0.001);
|
||||||
|
assertEquals(0.4444, coords.y, 0.001);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFreeformCGComputationAdjacentPoinst() throws Exception {
|
||||||
|
// This is the same trapezoid as previous free form, but it has
|
||||||
|
// some extra points which are very close to previous points.
|
||||||
|
// in particular for points 0 & 1,
|
||||||
|
// y0 + y1 is very small.
|
||||||
|
FreeformFinSet fins = new FreeformFinSet();
|
||||||
|
fins.setFinCount(1);
|
||||||
|
Coordinate[] points = new Coordinate[] {
|
||||||
|
new Coordinate(0, 0),
|
||||||
|
new Coordinate(0, 1E-15),
|
||||||
|
new Coordinate(0, 1),
|
||||||
|
new Coordinate(1E-15, 1),
|
||||||
|
new Coordinate(.5, 1),
|
||||||
|
new Coordinate(.5, 1 - 1E-15),
|
||||||
|
new Coordinate(1, 1E-15),
|
||||||
|
new Coordinate(1, 0)
|
||||||
|
};
|
||||||
|
fins.setPoints(points);
|
||||||
|
Coordinate coords = fins.getCG();
|
||||||
|
assertEquals(0.75, fins.getFinArea(), 0.001);
|
||||||
|
assertEquals(0.3889, coords.x, 0.001);
|
||||||
|
assertEquals(0.4444, coords.y, 0.001);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWildmanVindicatorShape() throws Exception {
|
||||||
|
// This fin shape is similar to the aft fins on the Wildman Vindicator.
|
||||||
|
// A user noticed that if the y values are similar but not equal,
|
||||||
|
// the compuation of CP was incorrect because of numerical instability.
|
||||||
|
//
|
||||||
|
// +-----------------+
|
||||||
|
// \ \
|
||||||
|
// \ \
|
||||||
|
// + \
|
||||||
|
// / \
|
||||||
|
// +---------------------+
|
||||||
|
//
|
||||||
|
FreeformFinSet fins = new FreeformFinSet();
|
||||||
|
fins.setFinCount(1);
|
||||||
|
Coordinate[] points = new Coordinate[] {
|
||||||
|
new Coordinate(0, 0),
|
||||||
|
new Coordinate(0.02143125, 0.01143),
|
||||||
|
new Coordinate(0.009524999999999999, 0.032543749999999996),
|
||||||
|
new Coordinate(0.041275, 0.032537399999999994),
|
||||||
|
new Coordinate(0.066675, 0)
|
||||||
|
};
|
||||||
|
fins.setPoints(points);
|
||||||
|
Coordinate coords = fins.getCG();
|
||||||
|
assertEquals(0.00130, fins.getFinArea(), 0.00001);
|
||||||
|
assertEquals(0.03423, coords.x, 0.00001);
|
||||||
|
assertEquals(0.01427, coords.y, 0.00001);
|
||||||
|
|
||||||
|
BodyTube bt = new BodyTube();
|
||||||
|
bt.addChild(fins);
|
||||||
|
FinSetCalc calc = new FinSetCalc(fins);
|
||||||
|
FlightConditions conditions = new FlightConditions(null);
|
||||||
|
AerodynamicForces forces = new AerodynamicForces();
|
||||||
|
WarningSet warnings = new WarningSet();
|
||||||
|
calc.calculateNonaxialForces(conditions, forces, warnings);
|
||||||
|
//System.out.println(forces);
|
||||||
|
assertEquals(0.023409, forces.getCP().x, 0.0001);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFreeFormCGWithNegativeY() throws Exception {
|
||||||
|
// This particular fin shape is currently not allowed in OR since the y values are negative
|
||||||
|
// however, it is possible to convert RockSim files and end up with fins which
|
||||||
|
// have negative y values.
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// This Fin set is constructed to have the same problem. It is a square and rectagle
|
||||||
|
// where the two trailing edge corners of the rectangle satisfy y_0 = -y_1
|
||||||
|
//
|
||||||
|
// +---------+
|
||||||
|
// | |
|
||||||
|
// | |
|
||||||
|
// +----+ |
|
||||||
|
// | |
|
||||||
|
// | |
|
||||||
|
// +----+
|
||||||
|
|
||||||
|
FreeformFinSet fins = new FreeformFinSet();
|
||||||
|
fins.setFinCount(1);
|
||||||
|
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)
|
||||||
|
};
|
||||||
|
fins.setPoints(points);
|
||||||
|
Coordinate coords = fins.getCG();
|
||||||
|
assertEquals(3.0, fins.getFinArea(), 0.001);
|
||||||
|
assertEquals(3.5 / 3.0, coords.x, 0.001);
|
||||||
|
assertEquals(0.5 / 3.0, coords.y, 0.001);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFreeformConvert() {
|
||||||
|
testFreeformConvert(new TrapezoidFinSet());
|
||||||
|
testFreeformConvert(new EllipticalFinSet());
|
||||||
|
testFreeformConvert(new FreeformFinSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void testFreeformConvert(FinSet fin) {
|
||||||
|
FreeformFinSet converted;
|
||||||
|
Material mat = Material.newMaterial(Type.BULK, "foo", 0.1, true);
|
||||||
|
|
||||||
|
fin.setBaseRotation(1.1);
|
||||||
|
fin.setCantAngle(0.001);
|
||||||
|
fin.setCGOverridden(true);
|
||||||
|
fin.setColor(Color.BLACK);
|
||||||
|
fin.setComment("cmt");
|
||||||
|
fin.setCrossSection(CrossSection.ROUNDED);
|
||||||
|
fin.setFinCount(5);
|
||||||
|
fin.setFinish(Finish.ROUGH);
|
||||||
|
fin.setLineStyle(LineStyle.DASHDOT);
|
||||||
|
fin.setMassOverridden(true);
|
||||||
|
fin.setMaterial(mat);
|
||||||
|
fin.setOverrideCGX(0.012);
|
||||||
|
fin.setOverrideMass(0.0123);
|
||||||
|
fin.setOverrideSubcomponents(true);
|
||||||
|
fin.setAxialOffset(0.1);
|
||||||
|
fin.setAxialMethod(AxialMethod.ABSOLUTE);
|
||||||
|
fin.setTabHeight(0.01);
|
||||||
|
fin.setTabLength(0.02);
|
||||||
|
fin.setTabRelativePosition(TabRelativePosition.END);
|
||||||
|
fin.setTabShift(0.015);
|
||||||
|
fin.setThickness(0.005);
|
||||||
|
|
||||||
|
|
||||||
|
converted = FreeformFinSet.convertFinSet((FinSet) fin.copy());
|
||||||
|
|
||||||
|
/// what do we want to ACTUALLY compare?
|
||||||
|
// ComponentCompare.assertSimilarity(fin, converted, true); // deprecated; removed
|
||||||
|
|
||||||
|
|
||||||
|
assertEquals(converted.getComponentName(), converted.getName());
|
||||||
|
|
||||||
|
|
||||||
|
// Create test rocket
|
||||||
|
Rocket rocket = new Rocket();
|
||||||
|
AxialStage stage = new AxialStage();
|
||||||
|
BodyTube body = new BodyTube();
|
||||||
|
|
||||||
|
rocket.addChild(stage);
|
||||||
|
stage.addChild(body);
|
||||||
|
body.addChild(fin);
|
||||||
|
rocket.enableEvents();
|
||||||
|
|
||||||
|
Listener l1 = new Listener("l1");
|
||||||
|
rocket.addComponentChangeListener(l1);
|
||||||
|
|
||||||
|
fin.setName("Custom name");
|
||||||
|
assertEquals("FinSet listener has not been notified: ", l1.changed, true);
|
||||||
|
assertEquals(ComponentChangeEvent.NONFUNCTIONAL_CHANGE, l1.changetype);
|
||||||
|
|
||||||
|
|
||||||
|
// Create copy
|
||||||
|
RocketComponent rocketcopy = rocket.copy();
|
||||||
|
|
||||||
|
Listener l2 = new Listener("l2");
|
||||||
|
rocketcopy.addComponentChangeListener(l2);
|
||||||
|
|
||||||
|
FinSet fincopy = (FinSet) rocketcopy.getChild(0).getChild(0).getChild(0);
|
||||||
|
FreeformFinSet.convertFinSet(fincopy);
|
||||||
|
|
||||||
|
assertTrue("FinSet listener is changed", l2.changed);
|
||||||
|
assertEquals(ComponentChangeEvent.TREE_CHANGE,
|
||||||
|
l2.changetype & ComponentChangeEvent.TREE_CHANGE);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static class Listener implements ComponentChangeListener {
|
||||||
|
private boolean changed = false;
|
||||||
|
private int changetype = 0;
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
public Listener(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void componentChanged(ComponentChangeEvent e) {
|
||||||
|
assertFalse("Ensuring listener " + name + " has not been called.", changed);
|
||||||
|
changed = true;
|
||||||
|
changetype = e.getType();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,137 @@
|
|||||||
|
package net.sf.openrocket.rocketcomponent;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import net.sf.openrocket.aerodynamics.AerodynamicForces;
|
||||||
|
import net.sf.openrocket.aerodynamics.FlightConditions;
|
||||||
|
import net.sf.openrocket.aerodynamics.WarningSet;
|
||||||
|
import net.sf.openrocket.aerodynamics.barrowman.FinSetCalc;
|
||||||
|
import net.sf.openrocket.material.Material;
|
||||||
|
import net.sf.openrocket.material.Material.Type;
|
||||||
|
import net.sf.openrocket.rocketcomponent.ExternalComponent.Finish;
|
||||||
|
import net.sf.openrocket.rocketcomponent.FinSet.CrossSection;
|
||||||
|
import net.sf.openrocket.rocketcomponent.FinSet.TabRelativePosition;
|
||||||
|
import net.sf.openrocket.rocketcomponent.position.*;
|
||||||
|
import net.sf.openrocket.util.Color;
|
||||||
|
import net.sf.openrocket.util.Coordinate;
|
||||||
|
import net.sf.openrocket.util.LineStyle;
|
||||||
|
import net.sf.openrocket.util.BaseTestCase.BaseTestCase;
|
||||||
|
|
||||||
|
public class TrapezoidFinSetTest extends BaseTestCase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTrapezoidCGComputation() {
|
||||||
|
|
||||||
|
{
|
||||||
|
// This is a simple square fin with sides of 1.0.
|
||||||
|
TrapezoidFinSet fins = new TrapezoidFinSet();
|
||||||
|
fins.setFinCount(1);
|
||||||
|
fins.setFinShape(1.0, 1.0, 0.0, 1.0, .005);
|
||||||
|
|
||||||
|
Coordinate coords = fins.getCG();
|
||||||
|
assertEquals(1.0, fins.getFinArea(), 0.001);
|
||||||
|
assertEquals(0.5, coords.x, 0.001);
|
||||||
|
assertEquals(0.5, coords.y, 0.001);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// This is a trapezoid. Height 1, root 1, tip 1/2 no sweep.
|
||||||
|
// It can be decomposed into a rectangle followed by a triangle
|
||||||
|
// +---+
|
||||||
|
// | \
|
||||||
|
// | \
|
||||||
|
// +------+
|
||||||
|
TrapezoidFinSet fins = new TrapezoidFinSet();
|
||||||
|
fins.setFinCount(1);
|
||||||
|
fins.setFinShape(1.0, 0.5, 0.0, 1.0, .005);
|
||||||
|
|
||||||
|
Coordinate coords = fins.getCG();
|
||||||
|
assertEquals(0.75, fins.getFinArea(), 0.001);
|
||||||
|
assertEquals(0.3889, coords.x, 0.001);
|
||||||
|
assertEquals(0.4444, coords.y, 0.001);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInstancePoints_PI_2_BaseRotation() {
|
||||||
|
// This is a simple square fin with sides of 1.0.
|
||||||
|
TrapezoidFinSet fins = new TrapezoidFinSet();
|
||||||
|
fins.setFinCount(4);
|
||||||
|
fins.setFinShape(1.0, 1.0, 0.0, 1.0, .005);
|
||||||
|
fins.setBaseRotation( Math.PI/2 );
|
||||||
|
|
||||||
|
BodyTube body = new BodyTube(1.0, 0.05 );
|
||||||
|
body.addChild( fins );
|
||||||
|
|
||||||
|
Coordinate[] points = fins.getInstanceOffsets();
|
||||||
|
|
||||||
|
assertEquals( 0, points[0].x, 0.00001);
|
||||||
|
assertEquals( 0, points[0].y, 0.00001);
|
||||||
|
assertEquals( 0.05, points[0].z, 0.00001);
|
||||||
|
|
||||||
|
assertEquals( 0, points[1].x, 0.00001);
|
||||||
|
assertEquals( -0.05, points[1].y, 0.00001);
|
||||||
|
assertEquals( 0, points[1].z, 0.00001);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInstancePoints_PI_4_BaseRotation() {
|
||||||
|
// This is a simple square fin with sides of 1.0.
|
||||||
|
TrapezoidFinSet fins = new TrapezoidFinSet();
|
||||||
|
fins.setFinCount(4);
|
||||||
|
fins.setFinShape(1.0, 1.0, 0.0, 1.0, .005);
|
||||||
|
fins.setBaseRotation( Math.PI/4 );
|
||||||
|
|
||||||
|
BodyTube body = new BodyTube(1.0, 0.05 );
|
||||||
|
body.addChild( fins );
|
||||||
|
|
||||||
|
Coordinate[] points = fins.getInstanceOffsets();
|
||||||
|
|
||||||
|
assertEquals( 0, points[0].x, 0.0001);
|
||||||
|
assertEquals( 0.03535, points[0].y, 0.0001);
|
||||||
|
assertEquals( 0.03535, points[0].z, 0.0001);
|
||||||
|
|
||||||
|
assertEquals( 0, points[1].x, 0.0001);
|
||||||
|
assertEquals( -0.03535, points[1].y, 0.0001);
|
||||||
|
assertEquals( 0.03535, points[1].z, 0.0001);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInstanceAngles_zeroBaseRotation() {
|
||||||
|
// This is a simple square fin with sides of 1.0.
|
||||||
|
TrapezoidFinSet fins = new TrapezoidFinSet();
|
||||||
|
fins.setFinCount(4);
|
||||||
|
fins.setFinShape(1.0, 1.0, 0.0, 1.0, .005);
|
||||||
|
fins.setBaseRotation( 0.0 );
|
||||||
|
|
||||||
|
double[] angles = fins.getInstanceAngles();
|
||||||
|
|
||||||
|
assertEquals( angles[0], 0, 0.000001 );
|
||||||
|
assertEquals( angles[1], Math.PI/2, 0.000001 );
|
||||||
|
assertEquals( angles[2], Math.PI, 0.000001 );
|
||||||
|
assertEquals( angles[3], 1.5*Math.PI, 0.000001 );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInstanceAngles_90_BaseRotation() {
|
||||||
|
// This is a simple square fin with sides of 1.0.
|
||||||
|
TrapezoidFinSet fins = new TrapezoidFinSet();
|
||||||
|
fins.setFinCount(4);
|
||||||
|
fins.setFinShape(1.0, 1.0, 0.0, 1.0, .005);
|
||||||
|
fins.setBaseRotation( Math.PI/2 );
|
||||||
|
|
||||||
|
double[] angles = fins.getInstanceAngles();
|
||||||
|
|
||||||
|
assertEquals( angles[0], Math.PI/2, 0.000001 );
|
||||||
|
assertEquals( angles[1], Math.PI, 0.000001 );
|
||||||
|
assertEquals( angles[2], 1.5*Math.PI, 0.000001 );
|
||||||
|
assertEquals( angles[3], 0, 0.000001 );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user