Added offset
[sw/motorsim] / src / com / billkuker / rocketry / motorsim / grain / CoredCylindricalGrain.java
1 package com.billkuker.rocketry.motorsim.grain;\r
2 \r
3 import java.awt.Shape;\r
4 import java.awt.geom.Ellipse2D;\r
5 import java.awt.geom.Rectangle2D;\r
6 import java.beans.PropertyVetoException;\r
7 \r
8 import javax.measure.quantity.Area;\r
9 import javax.measure.quantity.Length;\r
10 import javax.measure.quantity.Volume;\r
11 import javax.measure.unit.SI;\r
12 \r
13 import org.jscience.physics.amount.Amount;\r
14 \r
15 import com.billkuker.rocketry.motorsim.Validating;\r
16 import com.billkuker.rocketry.motorsim.visual.Editor;\r
17 import com.billkuker.rocketry.motorsim.visual.GrainPanel;\r
18 \r
19 \r
20 public class CoredCylindricalGrain extends ExtrudedGrain implements Validating {\r
21 \r
22         private Amount<Length> oD, iD;\r
23         private boolean outerSurfaceInhibited = true, innerSurfaceInhibited = false;\r
24         \r
25         public static CoredCylindricalGrain DEFAULT_GRAIN = new CoredCylindricalGrain(){\r
26                 {\r
27                         try{\r
28                                 setOD(Amount.valueOf(30, SI.MILLIMETER));\r
29                                 setID(Amount.valueOf(10, SI.MILLIMETER));\r
30                                 setLength(Amount.valueOf(70, SI.MILLIMETER));\r
31                                 setInnerSurfaceInhibited(false);\r
32                                 setOuterSurfaceInhibited(true);\r
33                                 setForeEndInhibited(false);\r
34                                 setAftEndInhibited(false);\r
35                         } catch ( Exception e ){\r
36                                 throw new Error(e);\r
37                         }\r
38                 }\r
39         };\r
40 \r
41         public CoredCylindricalGrain() {\r
42                 oD = Amount.valueOf(30, SI.MILLIMETER);\r
43                 iD = Amount.valueOf(10, SI.MILLIMETER);\r
44         }\r
45         \r
46         @Deprecated\r
47         public void inhibit(boolean in, boolean out, boolean end){\r
48                 outerSurfaceInhibited = out;\r
49                 innerSurfaceInhibited = in;\r
50         }\r
51 \r
52         public Amount<Area> surfaceArea(Amount<Length> regression) {\r
53                 Amount<Length> zero = Amount.valueOf(0, SI.MILLIMETER);\r
54                 if ( regression.isLessThan(zero) )\r
55                         return Amount.valueOf(0, SI.SQUARE_METRE);\r
56                 \r
57                 //Calculated regressed length\r
58                 Amount<Length> cLength = regressedLength(regression);\r
59                 \r
60                 //Calculate regressed iD\r
61                 Amount<Length> cID = iD;\r
62                 if ( !innerSurfaceInhibited ){\r
63                         cID = iD.plus(regression.times(2));\r
64                 }\r
65                 \r
66                 //Calculate regressed oD\r
67                 Amount<Length> cOD = oD;\r
68                 if ( !outerSurfaceInhibited ){\r
69                         cOD = oD.minus(regression.times(2));\r
70                 }\r
71                 \r
72                 if ( cID.isGreaterThan(cOD) )\r
73                         return Amount.valueOf(0, SI.SQUARE_METRE);\r
74                 if ( cOD.isLessThan(cID) )\r
75                         return Amount.valueOf(0, SI.SQUARE_METRE);\r
76                 if ( cLength.isLessThan(zero) )\r
77                         return Amount.valueOf(0, SI.SQUARE_METRE);\r
78                 \r
79                 Amount<Area> inner = cID.times(Math.PI).times(cLength).to(SI.SQUARE_METRE);\r
80                 \r
81                 Amount<Area> outer = cOD.times(Math.PI).times(cLength).to(SI.SQUARE_METRE);\r
82                 \r
83                 Amount<Area> end = (cOD.divide(2).pow(2).times(Math.PI)).minus(cID.divide(2).pow(2).times(Math.PI)).to(SI.SQUARE_METRE);\r
84                 \r
85                 Amount<Area> total = inner.times(innerSurfaceInhibited?0:1).plus(outer.times(outerSurfaceInhibited?0:1)).plus(end.times(numberOfBurningEnds(regression)));\r
86                 \r
87                 return total;\r
88         }\r
89 \r
90         public Amount<Volume> volume(Amount<Length> regression) {\r
91                 Amount<Length> zero = Amount.valueOf(0, SI.MILLIMETER);\r
92                 \r
93                 if ( regression.isLessThan(zero) )\r
94                         regression = zero;\r
95                 \r
96                 //Calculated regressed length\r
97                 Amount<Length> cLength = regressedLength(regression);\r
98                 \r
99                 //Calculate regressed iD\r
100                 Amount<Length> cID = iD;\r
101                 if ( !innerSurfaceInhibited ){\r
102                         cID = iD.plus(regression.times(2));\r
103                 }\r
104                 \r
105                 //Calculate regressed oD\r
106                 Amount<Length> cOD = oD;\r
107                 if ( !outerSurfaceInhibited ){\r
108                         cOD = oD.minus(regression.times(2));\r
109                 }\r
110                 \r
111                 if ( cID.isGreaterThan(cOD) )\r
112                         return Amount.valueOf(0, SI.CUBIC_METRE);\r
113                 if ( cOD.isLessThan(cID) )\r
114                         return Amount.valueOf(0, SI.CUBIC_METRE);\r
115                 if ( cLength.isLessThan(zero) )\r
116                         return Amount.valueOf(0, SI.CUBIC_METRE);\r
117         \r
118                 \r
119                 Amount<Area> end = (cOD.divide(2).pow(2).times(Math.PI)).minus(cID.divide(2).pow(2).times(Math.PI)).to(SI.SQUARE_METRE);\r
120 \r
121                 return end.times(cLength).to(SI.CUBIC_METRE);\r
122         }\r
123 \r
124         public void setOD(Amount<Length> od) throws PropertyVetoException {\r
125                 this.oD = od;\r
126         }\r
127 \r
128         public void setID(Amount<Length> id) throws PropertyVetoException {\r
129                 iD = id;\r
130         }\r
131         \r
132         @Override\r
133         public void validate() throws ValidationException{\r
134                 if ( iD.equals(Amount.ZERO) )\r
135                         throw new ValidationException(this, "Invalid iD");\r
136                 if ( oD.equals(Amount.ZERO) )\r
137                         throw new ValidationException(this, "Invalid oD");\r
138                 if ( getLength().equals(Amount.ZERO) )\r
139                         throw new ValidationException(this, "Invalid Length");\r
140                 if ( iD.isGreaterThan(oD) )\r
141                         throw new ValidationException(this, "iD > oD");\r
142                 \r
143                 if ( innerSurfaceInhibited && outerSurfaceInhibited )\r
144                         throw new ValidationException(this, "No exposed grain surface");\r
145                 \r
146         }\r
147 \r
148         public Amount<Length> webThickness() {\r
149                 if ( innerSurfaceInhibited && outerSurfaceInhibited ){\r
150                         return oD; //TODO gotta move this to the end\r
151                 }\r
152                 \r
153                 Amount<Length> radial = null;\r
154                 if ( !innerSurfaceInhibited && !outerSurfaceInhibited )\r
155                         radial = oD.minus(iD).divide(4); //Outer and inner exposed\r
156                 else if ( !innerSurfaceInhibited || !outerSurfaceInhibited )\r
157                         radial = oD.minus(iD).divide(2); //Outer or inner exposed\r
158                 \r
159                 Amount<Length> axial = null;\r
160                 \r
161                 if ( numberOfBurningEnds(Amount.valueOf(0, SI.MILLIMETER)) != 0 )\r
162                         axial = getLength().divide(numberOfBurningEnds(Amount.valueOf(0, SI.MILLIMETER)));\r
163                 \r
164                 if ( axial == null )\r
165                         return radial;\r
166                 if ( radial == null )\r
167                         return axial;\r
168                 if ( radial.isLessThan(axial) )\r
169                         return radial;\r
170                 return axial;\r
171         }\r
172 \r
173         public Amount<Length> getOD() {\r
174                 return oD;\r
175         }\r
176 \r
177         public Amount<Length> getID() {\r
178                 return iD;\r
179         }\r
180         \r
181         public java.awt.geom.Area getCrossSection(Amount<Length> regression){\r
182                 Amount<Length> zero = Amount.valueOf(0, SI.MILLIMETER);\r
183                 if ( regression.isLessThan(zero) )\r
184                         regression = zero;\r
185                 double rmm = regression.doubleValue(SI.MILLIMETER);\r
186                 double oDmm = oD.doubleValue(SI.MILLIMETER);\r
187                 double iDmm = iD.doubleValue(SI.MILLIMETER);\r
188 \r
189                 if ( !outerSurfaceInhibited )\r
190                         oDmm -= 2.0 * rmm;\r
191                 if ( !innerSurfaceInhibited )\r
192                         iDmm += 2.0 * rmm;\r
193                 \r
194                 Shape oDs = new Ellipse2D.Double(-oDmm/2.0, -oDmm/2.0, oDmm, oDmm);\r
195                 Shape iDs = new Ellipse2D.Double(-iDmm/2.0, -iDmm/2.0, iDmm, iDmm);\r
196                 \r
197                 java.awt.geom.Area a = new java.awt.geom.Area(oDs);\r
198                 a.subtract(new java.awt.geom.Area(iDs));\r
199                 return a;\r
200         }\r
201         \r
202         public java.awt.geom.Area getSideView(Amount<Length> regression){\r
203                 Amount<Length> zero = Amount.valueOf(0, SI.MILLIMETER);\r
204                 if ( regression.isLessThan(zero) )\r
205                         regression = zero;\r
206                 double rmm = regression.doubleValue(SI.MILLIMETER);\r
207                 double oDmm = oD.doubleValue(SI.MILLIMETER);\r
208                 double iDmm = iD.doubleValue(SI.MILLIMETER);\r
209                 double lmm = regressedLength(regression).doubleValue(SI.MILLIMETER);\r
210                 double length = getLength().doubleValue(SI.MILLIMETER);\r
211 \r
212                 if ( !outerSurfaceInhibited )\r
213                         oDmm -= 2.0 * rmm;\r
214                 if ( !innerSurfaceInhibited )\r
215                         iDmm += 2.0 * rmm;\r
216                 \r
217                 java.awt.geom.Area a = new java.awt.geom.Area();\r
218                 \r
219                 double top = -lmm/2;\r
220                 if ( isForeEndInhibited() && !isAftEndInhibited() )\r
221                         top = -length/2;\r
222                 else if ( isAftEndInhibited() && !isForeEndInhibited() )\r
223                         top = length/2-lmm;\r
224                 \r
225                 a.add( new java.awt.geom.Area(new Rectangle2D.Double(-oDmm/2,top,oDmm, lmm)));\r
226                 a.subtract( new java.awt.geom.Area(new Rectangle2D.Double(-iDmm/2,-length/2,iDmm, length)));\r
227                 \r
228                 return a;\r
229         }\r
230 \r
231 \r
232         public boolean isOuterSurfaceInhibited() {\r
233                 return outerSurfaceInhibited;\r
234         }\r
235 \r
236 \r
237         public void setOuterSurfaceInhibited(boolean outerSurfaceInhibited) throws PropertyVetoException {\r
238                 this.outerSurfaceInhibited = outerSurfaceInhibited;\r
239         }\r
240 \r
241 \r
242         public boolean isInnerSurfaceInhibited() {\r
243                 return innerSurfaceInhibited;\r
244         }\r
245 \r
246 \r
247         public void setInnerSurfaceInhibited(boolean innerSurfaceInhibited)  throws PropertyVetoException {\r
248                 this.innerSurfaceInhibited = innerSurfaceInhibited;\r
249         }\r
250 \r
251         public static void main(String args[]) throws Exception {\r
252                 CoredCylindricalGrain e = DEFAULT_GRAIN;\r
253                 new Editor(e).showAsWindow();\r
254                 new GrainPanel(e).showAsWindow();\r
255         }\r
256 \r
257 }\r