[refactor] added code to tests for negative inertia / intersection case

This commit is contained in:
Daniel M Williams 2018-12-16 13:11:33 -05:00 committed by Daniel_M_Williams
parent cf4a935302
commit 01fd20ebcc
6 changed files with 520 additions and 565 deletions

View File

@ -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<Coordinate> translatePoints( final ArrayList<Coordinate> inp, final Coordinate delta){
final ArrayList<Coordinate> 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<Coordinate> 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() ) {

View File

@ -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<Coordinate> 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<Coordinate> 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<Coordinate> 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<Coordinate> copy = new ArrayList<>(this.points);
final ArrayList<Coordinate> 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 <code>i</code> to coordinates (x,y).
* <p>
@ -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] <body frame> : 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<Coordinate> 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);

View File

@ -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();

View File

@ -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();

View File

@ -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);
}
}
}

View File

@ -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.");