Closed TODO to shift grain based on ends inhibited
[sw/motorsim] / src / com / billkuker / rocketry / motorsim / grain / util / ExtrudedShapeGrain.java
1 package com.billkuker.rocketry.motorsim.grain.util;\r
2 \r
3 import java.awt.Rectangle;\r
4 import java.awt.Shape;\r
5 import java.awt.geom.AffineTransform;\r
6 import java.awt.geom.Ellipse2D;\r
7 import java.awt.geom.Rectangle2D;\r
8 \r
9 import javax.measure.quantity.Area;\r
10 import javax.measure.quantity.Length;\r
11 import javax.measure.quantity.Volume;\r
12 import javax.measure.unit.SI;\r
13 \r
14 import org.jscience.physics.amount.Amount;\r
15 \r
16 import com.billkuker.rocketry.motorsim.grain.ExtrudedGrain;\r
17 import com.billkuker.rocketry.motorsim.visual.Editor;\r
18 import com.billkuker.rocketry.motorsim.visual.GrainPanel;\r
19 \r
20 public abstract class ExtrudedShapeGrain extends ExtrudedGrain {\r
21         \r
22         public static ExtrudedShapeGrain DEFAULT_GRAIN = new ExtrudedShapeGrain(){\r
23                 {\r
24                         try{\r
25                                 Shape outside = new Ellipse2D.Double(0, 0, 30, 30);\r
26                                 xsection.add(outside);\r
27                                 xsection.inhibit(outside);\r
28                                 xsection.subtract(new Ellipse2D.Double(10,10, 10, 10));\r
29                                 setLength(Amount.valueOf(70, SI.MILLIMETER));\r
30                                 setForeEndInhibited(false);\r
31                                 setAftEndInhibited(false);\r
32                         } catch ( Exception e ){\r
33                                 throw new Error(e);\r
34                         }\r
35                 }\r
36         };\r
37 \r
38         protected BurningShape xsection = new BurningShape();\r
39 \r
40         protected Amount<Length> webThickness;\r
41 \r
42         public Amount<Area> surfaceArea(Amount<Length> regression) {\r
43                 Amount<Area> zero = Amount.valueOf(0, Area.UNIT);\r
44                 \r
45                 if (regression.isGreaterThan(webThickness()))\r
46                         return zero;\r
47                 \r
48                 Amount<Length> rLen = regressedLength(regression);\r
49                 \r
50                 if (rLen.isLessThan(Amount.valueOf(0, SI.MILLIMETER)))\r
51                         return zero;\r
52 \r
53                 java.awt.geom.Area burn = getCrossSection(regression);\r
54                 \r
55                 if (burn.isEmpty())\r
56                         return zero;\r
57                 \r
58                 burn.subtract(getCrossSection(regression.plus(Amount.valueOf(.001,\r
59                                 SI.MILLIMETER))));\r
60         \r
61                 Amount<Area> xSection = ShapeUtil.area(xsection.getShape(regression));\r
62                 \r
63                 Amount<Area> sides = ShapeUtil.perimeter(burn).divide(2).times(rLen).to(Area.UNIT);\r
64                 Amount<Area> ends = xSection.times(numberOfBurningEnds(regression));\r
65                 \r
66                 return sides.plus(ends);\r
67 \r
68         }\r
69 \r
70         public Amount<Volume> volume(Amount<Length> regression) {\r
71                 Amount<Volume> zero = Amount.valueOf(0, Volume.UNIT);\r
72                 \r
73                 Amount<Length> rLen = regressedLength(regression);\r
74                 \r
75                 if (rLen.isLessThan(Amount.valueOf(0, SI.MILLIMETER)))\r
76                         return zero;\r
77                 \r
78                 Amount<Area> xSection = ShapeUtil.area(xsection.getShape(regression));\r
79 \r
80                 return xSection.times(rLen).to(Volume.UNIT);\r
81 \r
82         }\r
83 \r
84 \r
85         public Amount<Length> webThickness() {\r
86                 if ( webThickness != null )\r
87                         return webThickness;\r
88                 java.awt.geom.Area a = getCrossSection(Amount.valueOf(0, SI.MILLIMETER));\r
89                 Rectangle r = a.getBounds();\r
90                 double max = r.getWidth() < r.getHeight() ? r.getHeight() : r\r
91                                 .getWidth(); // The max size\r
92                 double min = 0;\r
93                 double guess;\r
94                 while (true) {\r
95                         guess = min + (max - min) / 2; // Guess halfway through\r
96 \r
97                         a = getCrossSection(Amount.valueOf(guess, SI.MILLIMETER));\r
98                         if (a.isEmpty()) {\r
99                                 // guess is too big\r
100                                 max = guess;\r
101                         } else {\r
102                                 // min is too big\r
103                                 min = guess;\r
104                         }\r
105                         if ((max - min) < .01)\r
106                                 break;\r
107                 }\r
108                 webThickness = Amount.valueOf(guess, SI.MILLIMETER);\r
109                 \r
110                 //TODO Need to check # of burning ends!\r
111                 if (webThickness.isGreaterThan(getLength().divide(2)))\r
112                         webThickness = getLength().divide(2);\r
113                 \r
114                 return webThickness;\r
115         }\r
116 \r
117         public java.awt.geom.Area getCrossSection(Amount<Length> regression) {\r
118                 return xsection.getShape(regression);\r
119         }\r
120         \r
121         public java.awt.geom.Area getSideView(Amount<Length> regression) {\r
122                 java.awt.geom.Area res = new java.awt.geom.Area();\r
123                 \r
124                 Amount<Length> rLen = regressedLength(regression);\r
125                 \r
126                 double rLenmm = rLen.doubleValue(SI.MILLIMETER);\r
127                 \r
128                 for( java.awt.geom.Area a : ShapeUtil.separate(getCrossSection(regression))){\r
129                         Rectangle2D bounds = a.getBounds2D();\r
130                         Rectangle2D side = new Rectangle2D.Double(bounds.getMinX(), -rLenmm/2.0, bounds.getWidth(), rLenmm);\r
131                         res.add(new java.awt.geom.Area(side));\r
132                 }\r
133                 \r
134                 //Shift up or down based on burning ends\r
135                 if ( isForeEndInhibited() ){\r
136                         res.transform(AffineTransform.getTranslateInstance(0, +rLenmm/2.0));\r
137                 }\r
138                 if ( isAftEndInhibited() ){\r
139                         res.transform(AffineTransform.getTranslateInstance(0, -rLenmm/2.0));\r
140                 }\r
141                 return res;\r
142         }\r
143         \r
144         public static void main(String args[]) throws Exception {\r
145                 ExtrudedShapeGrain e = DEFAULT_GRAIN;\r
146                 new Editor(e).showAsWindow();\r
147                 new GrainPanel(e).showAsWindow();\r
148         }\r
149 \r
150 }\r