From d728a27ee954a64eaafe34d2dd6b835a2e2c8fce Mon Sep 17 00:00:00 2001 From: SiboVG Date: Sat, 1 Jul 2023 20:32:00 +0200 Subject: [PATCH] [#2231] Account for fin cant in root points --- .../rocketcomponent/EllipticalFinSet.java | 13 +++- .../sf/openrocket/rocketcomponent/FinSet.java | 74 ++++++++++++++++--- .../rocketcomponent/FreeformFinSet.java | 11 ++- .../rocketcomponent/TrapezoidFinSet.java | 23 ++++-- 4 files changed, 98 insertions(+), 23 deletions(-) diff --git a/core/src/net/sf/openrocket/rocketcomponent/EllipticalFinSet.java b/core/src/net/sf/openrocket/rocketcomponent/EllipticalFinSet.java index cc4d54455..400f68a57 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/EllipticalFinSet.java +++ b/core/src/net/sf/openrocket/rocketcomponent/EllipticalFinSet.java @@ -36,11 +36,18 @@ public class EllipticalFinSet extends FinSet { @Override public Coordinate[] getFinPoints() { double len = MathUtil.max(length, 0.0001); - Coordinate[] points = new Coordinate[POINTS]; + Coordinate[] finPoints = new Coordinate[POINTS]; for (int i = 0; i < POINTS; i++) { - points[i] = new Coordinate(POINT_X[i] * len, POINT_Y[i] * height); + finPoints[i] = new Coordinate(POINT_X[i] * len, POINT_Y[i] * height); } - return points; + + // Set the start and end fin points the same as the root points (necessary for canted fins) + final Coordinate[] rootPoints = getRootPoints(); + if (rootPoints.length > 1) { + finPoints[0] = finPoints[0].setX(rootPoints[0].x).setY(rootPoints[0].y); + finPoints[finPoints.length - 1] = finPoints[finPoints.length - 1].setX(rootPoints[rootPoints.length - 1].x).setY(rootPoints[rootPoints.length - 1].y); + } + return finPoints; } @Override diff --git a/core/src/net/sf/openrocket/rocketcomponent/FinSet.java b/core/src/net/sf/openrocket/rocketcomponent/FinSet.java index ed675b502..227f9036a 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/FinSet.java +++ b/core/src/net/sf/openrocket/rocketcomponent/FinSet.java @@ -1025,14 +1025,14 @@ 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(final int maximumBodyDivisionCount) { - if( null == parent){ + if (parent == null) { return new Coordinate[]{Coordinate.ZERO}; } final Coordinate finLead = getFinFront(); final double xFinEnd = finLead.x + getLength(); - return getMountPoints( finLead.x, xFinEnd, -finLead.x, -finLead.y, maximumBodyDivisionCount); + return getMountPoints(finLead.x, xFinEnd, -finLead.x, -finLead.y, maximumBodyDivisionCount); } /** @@ -1075,11 +1075,11 @@ public abstract class FinSet extends ExternalComponent implements AxialPositiona // for a simple body, one increment is perfectly accurate. int divisionCount = 1; - final SymmetricComponent body = (SymmetricComponent) getParent(); + final SymmetricComponent parent = (SymmetricComponent) getParent(); final double intervalLength = xEnd - xStart; // for anything more complicated, increase the count: - if ((body instanceof Transition) && (((Transition)body).getShapeType() != Shape.CONICAL)) { + if ((!MathUtil.equals(getCantAngle(), 0)) || (parent instanceof Transition) && (((Transition)parent).getShapeType() != 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); @@ -1093,13 +1093,18 @@ public abstract class FinSet extends ExternalComponent implements AxialPositiona double xIncrement = intervalLength / divisionCount; // Create the points: step through the radius of the parent - double xCur = xStart; + double xCurr = xStart; List points = new ArrayList<>(); for (int index = 0; index < divisionCount+1; index++) { - double yCur = body.getRadius(xCur); - points.add(new Coordinate(xCur, yCur)); + double yCurr = parent.getRadius(xCurr); - xCur += xIncrement; + // Account for the fin cant angle + final double dy = getFinCantYOffset(xStart, xEnd, xCurr); + yCurr += dy; + + points.add(new Coordinate(xCurr, yCurr)); + + xCurr += xIncrement; } /* @@ -1107,11 +1112,11 @@ public abstract class FinSet extends ExternalComponent implements AxialPositiona 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 + // Front fin point is outside the parent's bounds and last point is beyond the parent's fore end 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 + // End fin point is beyond the parent's aft and first point is still before the parent's aft end if (xEnd > parent.length && xStart < parent.length) { final double x = parent.length; final double y = points.get(points.size() - 1).y; @@ -1122,8 +1127,8 @@ public abstract class FinSet extends ExternalComponent implements AxialPositiona // 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()); + if (Math.abs(rootPoints[lastIndex].x - parent.getLength()) < MathUtil.EPSILON) { + rootPoints[lastIndex] = rootPoints[lastIndex].setX(parent.getLength()); } // translate the points if needed @@ -1138,6 +1143,51 @@ public abstract class FinSet extends ExternalComponent implements AxialPositiona return getMountPoints(xStart, xEnd, xOffset, yOffset, MAX_ROOT_DIVISIONS); } + /** + * Returns a y offset that should be applied to the fin root point at the given x position to account for the fin cant. + * @param xStart The x position of the fin root point at the front of the fin. + * @param xEnd The x position of the fin root point at the back of the fin. + * @param xCurr The x position of the fin root point to calculate the y offset for. + * @return The y offset to apply to the fin root point at the given x position. + */ + private double getFinCantYOffset(final double xStart, final double xEnd, double xCurr) { + final SymmetricComponent parent = (SymmetricComponent) getParent(); + final double cantAngle = getCantAngle(); + + if (MathUtil.equals(cantAngle, 0) || (xStart > parent.length && xEnd > parent.length) || (xStart < 0 && xEnd < 0)) { + return 0; + } + + // Limit the x position to the parent's bounds + double x = Math.max(xCurr, 0); + x = Math.min(x, parent.getLength()); + + // Determine the center of rotation + final double xCenter = (xStart + xEnd) / 2; + + // Calculate the new x position after rotation + final double dx = x - xCenter; // Distance to the center of rotation + final double xCurr_rot = xCenter + dx * Math.abs(Math.cos(cantAngle)); // X coordinate after rotation + + // Extend the root of the fin to touch the surface of the parent + final double radius_rot = parent.getRadius(xCurr_rot); + final double dz = Math.abs(Math.sin(cantAngle)) * dx; + + final double dy; + if (dz >= radius_rot) { + dy = 0; + } else { + /* + Simplification of r^2 = (r-dy)^2 + dz^2, given that dz < r. (to derive this, draw + the cross-section of the body, which is just a circle, with a tangent line starting on the top of the circle + and reaching a distance dz. Use some Pythagorean theorem and bam, you got this equation.) + */ + dy = radius_rot - Math.sqrt(Math.pow(radius_rot, 2) - Math.pow(dz, 2)); + } + + return -dy; + } + /** * Return a list of coordinates defining the geometry of a single fin, including the parent's body points . */ diff --git a/core/src/net/sf/openrocket/rocketcomponent/FreeformFinSet.java b/core/src/net/sf/openrocket/rocketcomponent/FreeformFinSet.java index 99d901e93..169377c17 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/FreeformFinSet.java +++ b/core/src/net/sf/openrocket/rocketcomponent/FreeformFinSet.java @@ -392,7 +392,16 @@ public class FreeformFinSet extends FinSet { @Override public Coordinate[] getFinPoints() { - return points.toArray(new Coordinate[0]); + Coordinate[] finPoints = points.toArray(new Coordinate[0]); + + // Set the start and end fin points the same as the root points (necessary for canted fins) + final Coordinate[] rootPoints = getRootPoints(); + if (rootPoints.length > 1) { + finPoints[0] = finPoints[0].setX(rootPoints[0].x).setY(rootPoints[0].y); + finPoints[finPoints.length - 1] = finPoints[finPoints.length - 1].setX(rootPoints[rootPoints.length - 1].x).setY(rootPoints[rootPoints.length - 1].y); + } + + return finPoints; } @Override diff --git a/core/src/net/sf/openrocket/rocketcomponent/TrapezoidFinSet.java b/core/src/net/sf/openrocket/rocketcomponent/TrapezoidFinSet.java index afb7ee2d4..d7f63f434 100644 --- a/core/src/net/sf/openrocket/rocketcomponent/TrapezoidFinSet.java +++ b/core/src/net/sf/openrocket/rocketcomponent/TrapezoidFinSet.java @@ -193,16 +193,25 @@ public class TrapezoidFinSet extends FinSet { */ @Override public Coordinate[] getFinPoints() { - List list = new ArrayList(4); - - list.add(Coordinate.NUL); - list.add(new Coordinate(sweep, height)); + List points = new ArrayList<>(4); + + points.add(Coordinate.NUL); + points.add(new Coordinate(sweep, height)); if (tipChord > 0.0001) { - list.add(new Coordinate(sweep + tipChord, height)); + points.add(new Coordinate(sweep + tipChord, height)); + } + points.add(new Coordinate(MathUtil.max(length, 0.0001), 0)); + + Coordinate[] finPoints = points.toArray(new Coordinate[0]); + + // Set the start and end fin points the same as the root points (necessary for canted fins) + final Coordinate[] rootPoints = getRootPoints(); + if (rootPoints.length > 1) { + finPoints[0] = finPoints[0].setX(rootPoints[0].x).setY(rootPoints[0].y); + finPoints[finPoints.length - 1] = finPoints[finPoints.length - 1].setX(rootPoints[rootPoints.length - 1].x).setY(rootPoints[rootPoints.length - 1].y); } - list.add(new Coordinate(MathUtil.max(length, 0.0001), 0)); - return list.toArray(new Coordinate[list.size()]); + return finPoints; } /**