1 package net.sf.openrocket.rocketcomponent;
3 import java.util.ArrayList;
5 import net.sf.openrocket.util.Coordinate;
8 public class FreeformFinSet extends FinSet {
10 private ArrayList<Coordinate> points = new ArrayList<Coordinate>();
12 public FreeformFinSet() {
13 points.add(Coordinate.NUL);
14 points.add(new Coordinate(0.025,0.05));
15 points.add(new Coordinate(0.075,0.05));
16 points.add(new Coordinate(0.05,0));
22 public FreeformFinSet(Coordinate[] finpoints) {
24 for (Coordinate c: finpoints) {
27 this.length = points.get(points.size()-1).x - points.get(0).x;
31 public FreeformFinSet(FinSet finset) {
32 Coordinate[] finpoints = finset.getFinPoints();
33 this.copyFrom(finset);
36 for (Coordinate c: finpoints) {
39 this.length = points.get(points.size()-1).x - points.get(0).x;
45 * Convert an existing fin set into a freeform fin set. The specified
46 * fin set is taken out of the rocket tree (if any) and the new component
47 * inserted in its stead.
49 * The specified fin set should not be used after the call!
51 * @param finset the fin set to convert.
52 * @return the new freeform fin set.
54 public static FreeformFinSet convertFinSet(FinSet finset) {
55 final RocketComponent root = finset.getRoot();
56 FreeformFinSet freeform;
59 if (root instanceof Rocket) {
60 ((Rocket)root).freeze();
63 // Get fin set position and remove fin set
64 final RocketComponent parent = finset.getParent();
67 position = parent.getChildPosition(finset);
68 parent.removeChild(position);
74 // Create the freeform fin set
75 Coordinate[] finpoints = finset.getFinPoints();
76 freeform = new FreeformFinSet(finpoints);
78 // Copy component attributes
79 freeform.copyFrom(finset);
82 final String componentTypeName = finset.getComponentName();
83 final String name = freeform.getName();
85 if (name.startsWith(componentTypeName)) {
86 freeform.setName(freeform.getComponentName() +
87 name.substring(componentTypeName.length()));
90 // Add freeform fin set to parent
92 parent.addChild(freeform, position);
96 if (root instanceof Rocket) {
97 ((Rocket)root).thaw();
106 * Add a fin point between indices <code>index-1</code> and <code>index</code>.
107 * The point is placed at the midpoint of the current segment.
109 * @param index the fin point before which to add the new point.
111 public void addPoint(int index) {
112 double x0, y0, x1, y1;
114 x0 = points.get(index-1).x;
115 y0 = points.get(index-1).y;
116 x1 = points.get(index).x;
117 y1 = points.get(index).y;
119 points.add(index, new Coordinate((x0+x1)/2, (y0+y1)/2));
120 // adding a point within the segment affects neither mass nor aerodynamics
121 fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE);
126 * Remove the fin point with the given index. The first and last fin points
127 * cannot be removed, and will cause an <code>IllegalFinPointException</code>
130 * @param index the fin point index to remove
131 * @throws IllegalFinPointException if removing the first or last fin point was attempted.
133 public void removePoint(int index) throws IllegalFinPointException {
134 if (index == 0 || index == points.size()-1) {
135 throw new IllegalFinPointException("cannot remove first or last point");
137 points.remove(index);
138 fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
142 public int getPointCount() {
143 return points.size();
146 public void setPoints(Coordinate[] p) throws IllegalFinPointException {
147 if (p[0].x != 0 || p[0].y != 0 || p[p.length-1].y != 0) {
148 throw new IllegalFinPointException("Start or end point illegal.");
150 for (int i=0; i < p.length-1; i++) {
151 for (int j=i+2; j < p.length-1; j++) {
152 if (intersects(p[i].x, p[i].y, p[i+1].x, p[i+1].y,
153 p[j].x, p[j].y, p[j+1].x, p[j+1].y)) {
154 throw new IllegalFinPointException("segments intersect");
158 throw new IllegalFinPointException("z-coordinate not zero");
163 for (Coordinate c: p) {
166 this.length = p[p.length-1].x;
167 fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
172 * Set the point at position <code>i</code> to coordinates (x,y).
174 * Note that this method enforces basic fin shape restrictions (non-negative y,
175 * first and last point locations) silently, but throws an
176 * <code>IllegalFinPointException</code> if the point causes fin segments to
179 * Moving of the first point in the X-axis is allowed, but this actually moves
180 * all of the other points the corresponding distance back.
182 * @param index the point index to modify.
183 * @param x the x-coordinate.
184 * @param y the y-coordinate.
185 * @throws IllegalFinPointException if the specified fin point would cause intersecting
188 public void setPoint(int index, double x, double y) throws IllegalFinPointException {
197 x = Math.min(x, points.get(points.size()-1).x);
201 x1 = points.get(1).x;
202 y1 = points.get(1).y;
204 } else if (index == points.size()-1) {
209 x0 = points.get(index-1).x;
210 y0 = points.get(index-1).y;
216 x0 = points.get(index-1).x;
217 y0 = points.get(index-1).y;
218 x1 = points.get(index+1).x;
219 y1 = points.get(index+1).y;
225 // Check for intersecting
226 double px0, py0, px1, py1;
229 for (int i=1; i < points.size(); i++) {
230 px1 = points.get(i).x;
231 py1 = points.get(i).y;
233 if (i != index-1 && i != index && i != index+1) {
234 if (intersects(x0,y0,x,y,px0,py0,px1,py1)) {
235 throw new IllegalFinPointException("segments intersect");
238 if (i != index && i != index+1 && i != index+2) {
239 if (intersects(x,y,x1,y1,px0,py0,px1,py1)) {
240 throw new IllegalFinPointException("segments intersect");
250 System.out.println("Set point zero to x:"+x);
251 for (int i=1; i < points.size(); i++) {
252 Coordinate c = points.get(i);
253 points.set(i, c.setX(c.x - x));
258 points.set(index,new Coordinate(x,y));
261 if (index == 0 || index == points.size()-1) {
262 this.length = points.get(points.size()-1).x;
264 fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
269 private boolean intersects(double ax0, double ay0, double ax1, double ay1,
270 double bx0, double by0, double bx1, double by1) {
272 double d = ((by1-by0)*(ax1-ax0) - (bx1-bx0)*(ay1-ay0));
274 double ua = ((bx1-bx0)*(ay0-by0) - (by1-by0)*(ax0-bx0)) / d;
275 double ub = ((ax1-ax0)*(ay0-by0) - (ay1-ay0)*(ax0-bx0)) / d;
277 return (ua >= 0) && (ua <= 1) && (ub >= 0) && (ub <= 1);
282 public Coordinate[] getFinPoints() {
283 return points.toArray(new Coordinate[0]);
287 public double getSpan() {
289 for (Coordinate c: points) {
297 public String getComponentName() {
298 return "Freeform fin set";
302 @SuppressWarnings("unchecked")
304 public RocketComponent copy() {
305 RocketComponent c = super.copy();
306 ((FreeformFinSet)c).points = (ArrayList<Coordinate>) this.points.clone();