package net.sf.openrocket.rocketcomponent;
-import java.util.ArrayList;
-import java.util.Arrays;
-
+import net.sf.openrocket.logging.LogHelper;
+import net.sf.openrocket.startup.Application;
import net.sf.openrocket.util.BugException;
import net.sf.openrocket.util.Coordinate;
+import java.util.ArrayList;
+import java.util.Arrays;
+
public class FreeformFinSet extends FinSet {
-
+ private static final LogHelper log = Application.getLogger();
+
private ArrayList<Coordinate> points = new ArrayList<Coordinate>();
public FreeformFinSet() {
points.add(Coordinate.NUL);
- points.add(new Coordinate(0.025,0.05));
- points.add(new Coordinate(0.075,0.05));
- points.add(new Coordinate(0.05,0));
+ points.add(new Coordinate(0.025, 0.05));
+ points.add(new Coordinate(0.075, 0.05));
+ points.add(new Coordinate(0.05, 0));
this.length = 0.05;
}
-
+
public FreeformFinSet(Coordinate[] finpoints) throws IllegalFinPointException {
setPoints(finpoints);
}
-
+
/*
public FreeformFinSet(FinSet finset) {
Coordinate[] finpoints = finset.getFinPoints();
this.length = points.get(points.size()-1).x - points.get(0).x;
}
*/
-
-
+
+
/**
* Convert an existing fin set into a freeform fin set. The specified
* fin set is taken out of the rocket tree (if any) and the new component
* @return the new freeform fin set.
*/
public static FreeformFinSet convertFinSet(FinSet finset) {
+ log.info("Converting " + finset.getComponentName() + " into freeform fin set");
final RocketComponent root = finset.getRoot();
FreeformFinSet freeform;
try {
if (root instanceof Rocket) {
- ((Rocket)root).freeze();
+ ((Rocket) root).freeze();
}
-
+
// Get fin set position and remove fin set
final RocketComponent parent = finset.getParent();
final int position;
} else {
position = -1;
}
-
+
// Create the freeform fin set
Coordinate[] finpoints = finset.getFinPoints();
try {
freeform = new FreeformFinSet(finpoints);
} catch (IllegalFinPointException e) {
throw new BugException("Illegal fin points when converting existing fin to " +
- "freeform fin, fin=" + finset + " points="+Arrays.toString(finpoints),
+ "freeform fin, fin=" + finset + " points=" + Arrays.toString(finpoints),
e);
}
-
+
// Copy component attributes
freeform.copyFrom(finset);
// Set name
final String componentTypeName = finset.getComponentName();
final String name = freeform.getName();
-
+
if (name.startsWith(componentTypeName)) {
- freeform.setName(freeform.getComponentName() +
+ freeform.setName(freeform.getComponentName() +
name.substring(componentTypeName.length()));
}
-
+
// Add freeform fin set to parent
if (parent != null) {
parent.addChild(freeform, position);
}
-
+
} finally {
if (root instanceof Rocket) {
- ((Rocket)root).thaw();
+ ((Rocket) root).thaw();
}
}
return freeform;
}
-
+
/**
* Add a fin point between indices <code>index-1</code> and <code>index</code>.
* The point is placed at the midpoint of the current segment.
public void addPoint(int index) {
double x0, y0, x1, y1;
- x0 = points.get(index-1).x;
- y0 = points.get(index-1).y;
+ x0 = points.get(index - 1).x;
+ y0 = points.get(index - 1).y;
x1 = points.get(index).x;
y1 = points.get(index).y;
- points.add(index, new Coordinate((x0+x1)/2, (y0+y1)/2));
+ points.add(index, new Coordinate((x0 + x1) / 2, (y0 + y1) / 2));
// adding a point within the segment affects neither mass nor aerodynamics
fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE);
}
* if attempted.
*
* @param index the fin point index to remove
- * @throws IllegalFinPointException if removing the first or last fin point was attempted.
+ * @throws IllegalFinPointException if removing would result in invalid fin planform
*/
+ @SuppressWarnings("unchecked")
public void removePoint(int index) throws IllegalFinPointException {
- if (index == 0 || index == points.size()-1) {
+ if (index == 0 || index == points.size() - 1) {
throw new IllegalFinPointException("cannot remove first or last point");
}
- // TODO: CRITICAL: Can result in invalid fin points
- points.remove(index);
+
+ ArrayList<Coordinate> copy = (ArrayList<Coordinate>) this.points.clone();
+ copy.remove(index);
+ validate(copy);
+ this.points = copy;
+
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
}
return points.size();
}
- public void setPoints(Coordinate[] p) throws IllegalFinPointException {
- if (p[0].x != 0 || p[0].y != 0 || p[p.length-1].x < 0 || p[p.length-1].y != 0) {
- throw new IllegalFinPointException("Start or end point illegal.");
- }
- for (int i=0; i < p.length-1; i++) {
- for (int j=i+2; j < p.length-1; j++) {
- if (intersects(p[i].x, p[i].y, p[i+1].x, p[i+1].y,
- p[j].x, p[j].y, p[j+1].x, p[j+1].y)) {
- throw new IllegalFinPointException("segments intersect");
- }
- }
- if (p[i].z != 0) {
- throw new IllegalFinPointException("z-coordinate not zero");
- }
+ public void setPoints(Coordinate[] points) throws IllegalFinPointException {
+ ArrayList<Coordinate> list = new ArrayList<Coordinate>(points.length);
+ for (Coordinate p : points) {
+ list.add(p);
}
+ validate(list);
+ this.points = list;
- points.clear();
- for (Coordinate c: p) {
- points.add(c);
- }
- this.length = p[p.length-1].x;
+ this.length = points[points.length - 1].x;
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
}
-
+
/**
* Set the point at position <code>i</code> to coordinates (x,y).
* <p>
if (y < 0)
y = 0;
- double x0,y0,x1,y1;
+ double x0, y0, x1, y1;
if (index == 0) {
// Restrict point
- x = Math.min(x, points.get(points.size()-1).x);
+ x = Math.min(x, points.get(points.size() - 1).x);
y = 0;
x0 = Double.NaN;
y0 = Double.NaN;
x1 = points.get(1).x;
y1 = points.get(1).y;
- } else if (index == points.size()-1) {
+ } else if (index == points.size() - 1) {
// Restrict point
x = Math.max(x, 0);
y = 0;
- x0 = points.get(index-1).x;
- y0 = points.get(index-1).y;
+ x0 = points.get(index - 1).x;
+ y0 = points.get(index - 1).y;
x1 = Double.NaN;
y1 = Double.NaN;
} else {
- x0 = points.get(index-1).x;
- y0 = points.get(index-1).y;
- x1 = points.get(index+1).x;
- y1 = points.get(index+1).y;
+ x0 = points.get(index - 1).x;
+ y0 = points.get(index - 1).y;
+ x1 = points.get(index + 1).x;
+ y1 = points.get(index + 1).y;
}
-
-
+
+
// Check for intersecting
double px0, py0, px1, py1;
px0 = 0;
py0 = 0;
- for (int i=1; i < points.size(); i++) {
+ for (int i = 1; i < points.size(); i++) {
px1 = points.get(i).x;
py1 = points.get(i).y;
- if (i != index-1 && i != index && i != index+1) {
- if (intersects(x0,y0,x,y,px0,py0,px1,py1)) {
+ if (i != index - 1 && i != index && i != index + 1) {
+ if (intersects(x0, y0, x, y, px0, py0, px1, py1)) {
throw new IllegalFinPointException("segments intersect");
}
}
- if (i != index && i != index+1 && i != index+2) {
- if (intersects(x,y,x1,y1,px0,py0,px1,py1)) {
+ if (i != index && i != index + 1 && i != index + 2) {
+ if (intersects(x, y, x1, y1, px0, py0, px1, py1)) {
throw new IllegalFinPointException("segments intersect");
}
}
if (index == 0) {
- System.out.println("Set point zero to x:"+x);
- for (int i=1; i < points.size(); i++) {
+ System.out.println("Set point zero to x:" + x);
+ for (int i = 1; i < points.size(); i++) {
Coordinate c = points.get(i);
points.set(i, c.setX(c.x - x));
}
} else {
- points.set(index,new Coordinate(x,y));
+ points.set(index, new Coordinate(x, y));
}
- if (index == 0 || index == points.size()-1) {
- this.length = points.get(points.size()-1).x;
+ if (index == 0 || index == points.size() - 1) {
+ this.length = points.get(points.size() - 1).x;
}
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
}
-
+
private boolean intersects(double ax0, double ay0, double ax1, double ay1,
double bx0, double by0, double bx1, double by1) {
- double d = ((by1-by0)*(ax1-ax0) - (bx1-bx0)*(ay1-ay0));
+ double d = ((by1 - by0) * (ax1 - ax0) - (bx1 - bx0) * (ay1 - ay0));
- double ua = ((bx1-bx0)*(ay0-by0) - (by1-by0)*(ax0-bx0)) / d;
- double ub = ((ax1-ax0)*(ay0-by0) - (ay1-ay0)*(ax0-bx0)) / d;
+ double ua = ((bx1 - bx0) * (ay0 - by0) - (by1 - by0) * (ax0 - bx0)) / d;
+ double ub = ((ax1 - ax0) * (ay0 - by0) - (ay1 - ay0) * (ax0 - bx0)) / d;
return (ua >= 0) && (ua <= 1) && (ub >= 0) && (ub <= 1);
}
-
+
@Override
public Coordinate[] getFinPoints() {
return points.toArray(new Coordinate[0]);
}
-
+
@Override
public double getSpan() {
double max = 0;
- for (Coordinate c: points) {
+ for (Coordinate c : points) {
if (c.y > max)
max = c.y;
}
return max;
}
-
+
@Override
public String getComponentName() {
return "Freeform fin set";
}
-
-
+
+
@SuppressWarnings("unchecked")
@Override
- public RocketComponent copy() {
- RocketComponent c = super.copy();
- ((FreeformFinSet)c).points = (ArrayList<Coordinate>) this.points.clone();
+ protected RocketComponent copyWithOriginalID() {
+ RocketComponent c = super.copyWithOriginalID();
+ ((FreeformFinSet) c).points = (ArrayList<Coordinate>) this.points.clone();
return c;
}
-
+
+ /**
+ * Accept a visitor to this FreeformFinSet in the component hierarchy.
+ *
+ * @param theVisitor the visitor that will be called back with a reference to this FreeformFinSet
+ */
+ @Override
+ public void accept(ComponentVisitor theVisitor) {
+ theVisitor.visit(this);
+ }
+
+ private void validate(ArrayList<Coordinate> points) throws IllegalFinPointException {
+ final int n = points.size();
+ if (points.get(0).x != 0 || points.get(0).y != 0 ||
+ points.get(n - 1).x < 0 || points.get(n - 1).y != 0) {
+ throw new IllegalFinPointException("Start or end point illegal.");
+ }
+ for (int i = 0; i < n - 1; i++) {
+ for (int j = i + 2; j < n - 1; j++) {
+ if (intersects(points.get(i).x, points.get(i).y, points.get(i + 1).x, points.get(i + 1).y,
+ points.get(j).x, points.get(j).y, points.get(j + 1).x, points.get(j + 1).y)) {
+ throw new IllegalFinPointException("segments intersect");
+ }
+ }
+ if (points.get(i).z != 0) {
+ throw new IllegalFinPointException("z-coordinate not zero");
+ }
+ }
+ }
+
}