Merge pull request #1874 from SiboVG/issue-1021
[#1021] Add extra root point(s) if fin is outside parent's bounds
This commit is contained in:
		
						commit
						19eb969b6c
					
				@ -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);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
@ -1156,82 +1243,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() {
 | 
			
		||||
		return firstFinOffsetRadians;
 | 
			
		||||
 | 
			
		||||
@ -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();
 | 
			
		||||
 | 
			
		||||
@ -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];
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user