major optimization updates
[debian/openrocket] / src / net / sf / openrocket / gui / rocketfigure / SymmetricComponentShapes.java
1 package net.sf.openrocket.gui.rocketfigure;
2
3 import java.awt.Shape;
4 import java.awt.geom.Path2D;
5 import java.util.ArrayList;
6
7 import net.sf.openrocket.util.Coordinate;
8 import net.sf.openrocket.util.MathUtil;
9 import net.sf.openrocket.util.Transformation;
10
11
12 public class SymmetricComponentShapes extends RocketComponentShapes {
13         private static final int MINPOINTS = 91;
14         private static final double ACCEPTABLE_ANGLE = Math.cos(7.0 * Math.PI / 180.0);
15         
16         // TODO: HIGH: adaptiveness sucks, remove it.
17         
18         // TODO: LOW: Uses only first component of cluster (not currently clusterable)
19         
20         public static Shape[] getShapesSide(net.sf.openrocket.rocketcomponent.RocketComponent component,
21                         Transformation transformation) {
22                 net.sf.openrocket.rocketcomponent.SymmetricComponent c = (net.sf.openrocket.rocketcomponent.SymmetricComponent) component;
23                 int i;
24                 
25                 final double delta = 0.0000001;
26                 double x;
27                 
28                 ArrayList<Coordinate> points = new ArrayList<Coordinate>();
29                 x = delta;
30                 points.add(new Coordinate(x, c.getRadius(x), 0));
31                 for (i = 1; i < MINPOINTS - 1; i++) {
32                         x = c.getLength() * i / (MINPOINTS - 1);
33                         points.add(new Coordinate(x, c.getRadius(x), 0));
34                         //System.out.println("Starting with x="+x);
35                 }
36                 x = c.getLength() - delta;
37                 points.add(new Coordinate(x, c.getRadius(x), 0));
38                 
39
40                 i = 0;
41                 while (i < points.size() - 2) {
42                         if (angleAcceptable(points.get(i), points.get(i + 1), points.get(i + 2)) ||
43                                         points.get(i + 1).x - points.get(i).x < 0.001) { // 1mm
44                                 i++;
45                                 continue;
46                         }
47                         
48                         // Split the longer of the areas
49                         int n;
50                         if (points.get(i + 2).x - points.get(i + 1).x > points.get(i + 1).x - points.get(i).x)
51                                 n = i + 1;
52                         else
53                                 n = i;
54                         
55                         x = (points.get(n).x + points.get(n + 1).x) / 2;
56                         points.add(n + 1, new Coordinate(x, c.getRadius(x), 0));
57                 }
58                 
59
60                 //System.out.println("Final points: "+points.size());
61                 
62                 final int len = points.size();
63                 
64                 for (i = 0; i < len; i++) {
65                         points.set(i, c.toAbsolute(points.get(i))[0]);
66                 }
67                 
68                 /*   Show points:
69                 Shape[] s = new Shape[len+1];
70                 final double d=0.001;
71                 for (i=0; i<len; i++) {
72                         s[i] = new Ellipse2D.Double(points.get(i).x()-d/2,points.get(i).y()-d/2,d,d);
73                 }
74                 */
75
76                 //System.out.println("here");
77                 
78                 // TODO: LOW: curved path instead of linear
79                 Path2D.Double path = new Path2D.Double();
80                 path.moveTo(points.get(len - 1).x * S, points.get(len - 1).y * S);
81                 for (i = len - 2; i >= 0; i--) {
82                         path.lineTo(points.get(i).x * S, points.get(i).y * S);
83                 }
84                 for (i = 0; i < len; i++) {
85                         path.lineTo(points.get(i).x * S, -points.get(i).y * S);
86                 }
87                 path.lineTo(points.get(len - 1).x * S, points.get(len - 1).y * S);
88                 path.closePath();
89                 
90                 //s[len] = path;
91                 //return s;
92                 return new Shape[] { path };
93         }
94         
95         private static boolean angleAcceptable(Coordinate v1, Coordinate v2, Coordinate v3) {
96                 return (cosAngle(v1, v2, v3) > ACCEPTABLE_ANGLE);
97         }
98         
99         /*
100          * cosAngle = v1.v2 / |v1|*|v2| = v1.v2 / sqrt(v1.v1*v2.v2)
101          */
102         private static double cosAngle(Coordinate v1, Coordinate v2, Coordinate v3) {
103                 double cos;
104                 double len;
105                 cos = Coordinate.dot(v1.sub(v2), v2.sub(v3));
106                 len = MathUtil.safeSqrt(v1.sub(v2).length2() * v2.sub(v3).length2());
107                 return cos / len;
108         }
109 }