Revert "Revert "[#1021] Add extra root point(s) if fin is outside parent's bounds""

This commit is contained in:
Sibo Van Gool 2022-12-13 19:16:22 +01:00 committed by GitHub
parent b9b49907fc
commit 2b80e43e32
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 214 additions and 80 deletions

View File

@ -1036,14 +1036,101 @@ public abstract class FinSet extends ExternalComponent implements AxialPositiona
* @return points representing the fin-root points, relative to ( x: fin-front, y: centerline ) i.e. relto: fin Component reference point
*/
public Coordinate[] getRootPoints(){
return getRootPoints(MAX_ROOT_DIVISIONS);
}
/**
* 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 getMountPoints(0., parent.getLength(), 0,0);
}
/**
* 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,
final int maximumBodyDivisionCount) {
if (parent == null) {
return new Coordinate[]{Coordinate.ZERO};
}
final Coordinate finLead = getFinFront();
final double xFinEnd = finLead.x + getLength();
// for a simple body, one increment is perfectly accurate.
int divisionCount = 1;
final SymmetricComponent body = (SymmetricComponent) getParent();
final double intervalLength = xEnd - xStart;
return getMountPoints( finLead.x, xFinEnd, -finLead.x, -finLead.y);
// for anything more complicated, increase the count:
if ((body instanceof Transition) && (((Transition)body).getType() != Shape.CONICAL)) {
// the maximum precision to enforce when calculating the areas of fins (especially on curved parent bodies)
final double xWidth = 0.0025; // width (in meters) of each individual iteration
divisionCount = (int) Math.ceil(intervalLength / xWidth);
// When creating body curves, don't create more than this many divisions. -- only relevant on very large components
// a too high division count will cause the 3D render to have invisible faces because it can't deal with the geometry.
divisionCount = Math.min(maximumBodyDivisionCount, divisionCount);
}
// Recalculate the x step increment, now with the (rounded) division count.
double xIncrement = intervalLength / divisionCount;
// Create the points: step through the radius of the parent
double xCur = xStart;
List<Coordinate> points = new ArrayList<>();
for (int index = 0; index < divisionCount+1; index++) {
double yCur = body.getRadius(xCur);
points.add(new Coordinate(xCur, yCur));
xCur += xIncrement;
}
/*
If the front fin point is outside the parent's bounds, and the last point is still within the parent's bounds,
then we need to add an extra root point at the front of the parent. Same goes for the last point, but vice versa.
This ensures that fins are drawn correctly on transitions and nose cones (see GitHub issue #1021 for more info).
*/
// Front fin point is outside the parent's bounds and last point is still within the parent's bounds
if (xStart < 0 && xEnd > 0) {
points.add(1, new Coordinate(0, points.get(0).y));
}
// End fin point is outside the parent's bounds and first point is still within the parent's bounds
if (xEnd > parent.length && xStart < parent.length) {
final double x = parent.length;
final double y = points.get(points.size() - 1).y;
points.add(points.size() - 1, new Coordinate(x, y));
}
Coordinate[] rootPoints = points.toArray(new Coordinate[0]);
// correct last point, if beyond a rounding error from body's end.
final int lastIndex = rootPoints.length - 1;
if (Math.abs(rootPoints[lastIndex].x - body.getLength()) < MathUtil.EPSILON) {
rootPoints[lastIndex] = rootPoints[lastIndex].setX(body.getLength()).setY(body.getAftRadius());
}
// translate the points if needed
if ((Math.abs(xOffset) + Math.abs(yOffset)) > MathUtil.EPSILON) {
rootPoints = translatePoints(rootPoints, xOffset, yOffset);
}
return rootPoints;
}
private Coordinate[] getMountPoints(final double xStart, final double xEnd, final double xOffset, final double yOffset) {
return getMountPoints(xStart, xEnd, xOffset, yOffset, MAX_ROOT_DIVISIONS);
}
/**
@ -1155,82 +1242,6 @@ public abstract class FinSet extends ExternalComponent implements AxialPositiona
return combineCurves(tabPoints, rootPoints.toArray(new Coordinate[0]));
}
/**
* 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 getMountPoints(0., parent.getLength(), 0,0);
}
/**
* 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,
final int maximumBodyDivisionCount) {
if (parent == null) {
return new Coordinate[]{Coordinate.ZERO};
}
// for a simple body, one increment is perfectly accurate.
int divisionCount = 1;
final SymmetricComponent body = (SymmetricComponent) getParent();
final double intervalLength = xEnd - xStart;
// for anything more complicated, increase the count:
if ((body instanceof Transition) && (((Transition)body).getType() != Shape.CONICAL)) {
// the maximum precision to enforce when calculating the areas of fins (especially on curved parent bodies)
final double xWidth = 0.0025; // width (in meters) of each individual iteration
divisionCount = (int) Math.ceil(intervalLength / xWidth);
// When creating body curves, don't create more than this many divisions. -- only relevant on very large components
// a too high division count will cause the 3D render to have invisible faces because it can't deal with the geometry.
divisionCount = Math.min(maximumBodyDivisionCount, divisionCount);
}
// Recalculate the x step increment, now with the (rounded) division count.
double xIncrement = intervalLength / divisionCount;
// Create the points: step through the radius of the parent
double xCur = xStart;
Coordinate[] points = new Coordinate[divisionCount+1];
for (int index = 0; index < points.length; index++) {
double yCur = body.getRadius(xCur);
points[index] = new Coordinate(xCur, yCur);
xCur += xIncrement;
}
// correct last point, if beyond a rounding error from body's end.
final int lastIndex = points.length - 1;
if (Math.abs(points[lastIndex].x - body.getLength()) < MathUtil.EPSILON) {
points[lastIndex] = points[lastIndex].setX(body.getLength()).setY(body.getAftRadius());
}
// translate the points if needed
if ((Math.abs(xOffset) + Math.abs(yOffset)) > MathUtil.EPSILON) {
points = translatePoints(points, xOffset, yOffset);
}
return points;
}
private Coordinate[] getMountPoints(final double xStart, final double xEnd, final double xOffset, final double yOffset) {
return getMountPoints(xStart, xEnd, xOffset, yOffset, MAX_ROOT_DIVISIONS);
}
@Override
public double getAngleOffset() {

View File

@ -1315,6 +1315,129 @@ public class FreeformFinSetTest extends BaseTestCase {
}
}
@Test
public void testGenerateBodyPointsWhenFinOutsideParentBounds() {
final Rocket rkt = createTemplateRocket();
final Transition tailCone = (Transition) rkt.getChild(0).getChild(2);
final FreeformFinSet fins = this.createFinOnConicalTransition(tailCone);
final Coordinate[] initialPoints = fins.getFinPoints();
assertEquals(1.0, tailCone.getLength(), EPSILON);
{ // move first point out of bounds, keep last point in bounds
fins.setAxialOffset(AxialMethod.TOP, 0);
fins.setPoints(initialPoints);
assertEquals(0f, fins.getFinFront().x, EPSILON);
assertEquals(1f, fins.getFinFront().y, EPSILON);
// Move first point
fins.setPoint(0, -0.1, 0.1f);
final Coordinate[] rootPoints = fins.getRootPoints();
assertEquals(3, rootPoints.length);
assertEquals("incorrect body points! ", 0f, rootPoints[0].x, EPSILON);
assertEquals("incorrect body points! ", 0f, rootPoints[0].y, EPSILON);
assertEquals("incorrect body points! ", 0.1f, rootPoints[1].x, EPSILON);
assertEquals("incorrect body points! ", 0f, rootPoints[1].y, EPSILON);
assertEquals("incorrect body points! ", 0.5f, rootPoints[2].x, EPSILON);
assertEquals("incorrect body points! ", -0.2f, rootPoints[2].y, EPSILON);
assertEquals("incorrect fin mass! ", 0.306, fins.getMass(), EPSILON);
} { // move both first and last point out of bounds to the left
fins.setAxialOffset(AxialMethod.TOP, 0);
fins.setPoints(initialPoints);
assertEquals(0f, fins.getFinFront().x, EPSILON);
assertEquals(1f, fins.getFinFront().y, EPSILON);
// Move first and last point
fins.setPoint(0, -0.2, 0.1f);
fins.setPoint(fins.getPointCount()-1, 0.1, 0.1f);
final Coordinate[] rootPoints = fins.getRootPoints();
assertEquals(2, rootPoints.length);
assertEquals("incorrect body points! ", 0f, rootPoints[0].x, EPSILON);
assertEquals("incorrect body points! ", 0f, rootPoints[0].y, EPSILON);
assertEquals("incorrect body points! ", 0.1f, rootPoints[1].x, EPSILON);
assertEquals("incorrect body points! ", 0f, rootPoints[1].y, EPSILON);
assertEquals("incorrect fin mass! ", 0.034, fins.getMass(), EPSILON);
} { // move last point out of bounds, keep first point in bounds
fins.setPoints(initialPoints);
fins.setAxialOffset(AxialMethod.BOTTOM, fins.getLength());
assertEquals(1f, fins.getFinFront().x, EPSILON);
assertEquals(0.5f, fins.getFinFront().y, EPSILON);
// Move first point
fins.setPoint(0, -0.1f, 0.1f);
fins.setPoint(fins.getPointCount()-1, 0.2f, 0f);
final Coordinate[] rootPoints = fins.getRootPoints();
assertEquals(3, rootPoints.length);
assertEquals("incorrect body points! ", 0f, rootPoints[0].x, EPSILON);
assertEquals("incorrect body points! ", 0f, rootPoints[0].y, EPSILON);
assertEquals("incorrect body points! ", 0.1f, rootPoints[1].x, EPSILON);
assertEquals("incorrect body points! ", -0.05f, rootPoints[1].y, EPSILON);
assertEquals("incorrect body points! ", 0.2f, rootPoints[2].x, EPSILON);
assertEquals("incorrect body points! ", -0.05f, rootPoints[2].y, EPSILON);
assertEquals("incorrect fin mass! ", 0.102, fins.getMass(), EPSILON);
} { // move both first and last point out of bounds to the right
fins.setPoints(initialPoints);
fins.setAxialOffset(AxialMethod.BOTTOM, fins.getLength());
assertEquals(1f, fins.getFinFront().x, EPSILON);
assertEquals(0.5f, fins.getFinFront().y, EPSILON);
// Move first and last point
fins.setPoint(0, 0.1, 0.1f);
fins.setPoint(fins.getPointCount()-1, 0.2, 0.1f);
final Coordinate[] rootPoints = fins.getRootPoints();
assertEquals(2, rootPoints.length);
assertEquals("incorrect body points! ", 0f, rootPoints[0].x, EPSILON);
assertEquals("incorrect body points! ", 0f, rootPoints[0].y, EPSILON);
assertEquals("incorrect body points! ", 0.2f, rootPoints[1].x, EPSILON);
assertEquals("incorrect body points! ", 0f, rootPoints[1].y, EPSILON);
assertEquals("incorrect fin mass! ", 0.068, fins.getMass(), EPSILON);
} { // move first point out of bounds to the left, and last point out of bounds to the right
fins.setAxialOffset(AxialMethod.TOP, 0);
fins.setPoints(initialPoints);
assertEquals(0, fins.getFinFront().x, EPSILON);
assertEquals(1, fins.getFinFront().y, EPSILON);
// Move first and last point
fins.setPoint(0, -0.1, 0.1f);
fins.setPoint(fins.getPointCount()-1, 1.2, -0.1f);
final Coordinate[] rootPoints = fins.getRootPoints();
assertEquals(4, rootPoints.length);
assertEquals("incorrect body points! ", 0f, rootPoints[0].x, EPSILON);
assertEquals("incorrect body points! ", 0f, rootPoints[0].y, EPSILON);
assertEquals("incorrect body points! ", 0.1f, rootPoints[1].x, EPSILON);
assertEquals("incorrect body points! ", 0f, rootPoints[1].y, EPSILON);
assertEquals("incorrect body points! ", 1.1f, rootPoints[2].x, EPSILON);
assertEquals("incorrect body points! ", -0.5f, rootPoints[2].y, EPSILON);
assertEquals("incorrect body points! ", 1.2f, rootPoints[3].x, EPSILON);
assertEquals("incorrect body points! ", -0.5f, rootPoints[3].y, EPSILON);
assertEquals("incorrect fin mass! ", 0.833, fins.getMass(), EPSILON);
}
}
@Test
public void testFreeFormCMWithNegativeY() throws Exception {
final Rocket rkt = createTemplateRocket();

View File

@ -226,7 +226,7 @@ public class FinPointFigure extends AbstractScaleFigure {
private void paintFinShape(final Graphics2D g2){
// excludes fin tab points
final Coordinate[] drawPoints = finset.getFinPoints();
final Coordinate[] drawPoints = finset.getFinPointsWithRoot();
Path2D.Double shape = new Path2D.Double();
Coordinate startPoint= drawPoints[0];