Added compound grain
[sw/motorsim] / src / com / billkuker / rocketry / motorsim / grain / CoredCylindricalGrain.java
1 package com.billkuker.rocketry.motorsim.grain;\r
2 \r
3 import java.awt.BasicStroke;\r
4 import java.awt.Color;\r
5 import java.awt.Graphics2D;\r
6 import java.awt.Rectangle;\r
7 import java.awt.Shape;\r
8 import java.awt.geom.Ellipse2D;\r
9 import java.awt.geom.Rectangle2D;\r
10 \r
11 import javax.measure.quantity.Area;\r
12 import javax.measure.quantity.Length;\r
13 import javax.measure.quantity.Volume;\r
14 import javax.measure.unit.SI;\r
15 \r
16 import org.jscience.physics.amount.Amount;\r
17 \r
18 import com.billkuker.rocketry.motorsim.Grain;\r
19 import com.billkuker.rocketry.motorsim.validation.Validating;\r
20 import com.billkuker.rocketry.motorsim.validation.ValidationException;\r
21 \r
22 public class CoredCylindricalGrain implements Grain, Validating {\r
23 \r
24         private Amount<Length> length, oD, iD;\r
25         private boolean oInh = true, iInh = false, eInh = false;\r
26 \r
27         public CoredCylindricalGrain() {\r
28 \r
29         }\r
30         \r
31         public void inhibit(boolean in, boolean out, boolean end){\r
32                 oInh = out;\r
33                 iInh = in;\r
34                 eInh = end;\r
35         }\r
36 \r
37         @Override\r
38         public Amount<Area> surfaceArea(Amount<Length> regression) {\r
39                 Amount<Length> zero = Amount.valueOf(0, SI.MILLIMETER);\r
40                 \r
41                 //Calculated regressed length\r
42                 Amount<Length> cLength = length;\r
43                 if ( !eInh ){\r
44                         cLength = cLength.minus(regression.times(2));\r
45                 }\r
46                 \r
47                 //Calculate regressed iD\r
48                 Amount<Length> cID = iD;\r
49                 if ( !iInh ){\r
50                         cID = iD.plus(regression.times(2));\r
51                 }\r
52                 \r
53                 //Calculate regressed oD\r
54                 Amount<Length> cOD = oD;\r
55                 if ( !oInh ){\r
56                         cOD = oD.minus(regression.times(2));\r
57                 }\r
58                 \r
59                 if ( cID.isGreaterThan(cOD) )\r
60                         return Amount.valueOf(0, SI.SQUARE_METRE);\r
61                 if ( cOD.isLessThan(cID) )\r
62                         return Amount.valueOf(0, SI.SQUARE_METRE);\r
63                 if ( cLength.isLessThan(zero) )\r
64                         return Amount.valueOf(0, SI.SQUARE_METRE);\r
65                 \r
66                 Amount<Area> inner = cID.times(Math.PI).times(cLength).to(SI.SQUARE_METRE);\r
67                 \r
68                 Amount<Area> outer = cOD.times(Math.PI).times(cLength).to(SI.SQUARE_METRE);\r
69                 \r
70                 Amount<Area> ends = (cOD.divide(2).pow(2).times(Math.PI)).minus(cID.divide(2).pow(2).times(Math.PI)).times(2).to(SI.SQUARE_METRE);\r
71                 \r
72                 Amount<Area> total = inner.times(iInh?0:1).plus(outer.times(oInh?0:1)).plus(ends.times(eInh?0:1));\r
73                 \r
74                 return total;\r
75         }\r
76 \r
77         @Override\r
78         public Amount<Volume> volume(Amount<Length> regression) {\r
79                 Amount<Length> zero = Amount.valueOf(0, SI.MILLIMETER);\r
80                 \r
81                 //Calculated regressed length\r
82                 Amount<Length> cLength = length;\r
83                 if ( !eInh ){\r
84                         cLength = cLength.minus(regression.times(2));\r
85                 }\r
86                 \r
87                 //Calculate regressed iD\r
88                 Amount<Length> cID = iD;\r
89                 if ( !iInh ){\r
90                         cID = iD.plus(regression.times(2));\r
91                 }\r
92                 \r
93                 //Calculate regressed oD\r
94                 Amount<Length> cOD = oD;\r
95                 if ( !oInh ){\r
96                         cOD = oD.minus(regression.times(2));\r
97                 }\r
98                 \r
99                 if ( cID.isGreaterThan(cOD) )\r
100                         return Amount.valueOf(0, SI.CUBIC_METRE);\r
101                 if ( cOD.isLessThan(cID) )\r
102                         return Amount.valueOf(0, SI.CUBIC_METRE);\r
103                 if ( cLength.isLessThan(zero) )\r
104                         return Amount.valueOf(0, SI.CUBIC_METRE);\r
105         \r
106                 \r
107                 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
108 \r
109                 return end.times(cLength).to(SI.CUBIC_METRE);\r
110         }\r
111 \r
112         public void setLength(Amount<Length> length) {\r
113                 this.length = length;\r
114         }\r
115 \r
116         public void setOD(Amount<Length> od) {\r
117                 oD = od;\r
118         }\r
119 \r
120         public void setID(Amount<Length> id) {\r
121                 iD = id;\r
122         }\r
123         \r
124         public void checkValidity() throws ValidationException{\r
125                 if ( iD.equals(Amount.ZERO) )\r
126                         throw new ValidationException(this, "Invalid iD");\r
127                 if ( oD.equals(Amount.ZERO) )\r
128                         throw new ValidationException(this, "Invalid oD");\r
129                 if ( length.equals(Amount.ZERO) )\r
130                         throw new ValidationException(this, "Invalid Length");\r
131                 if ( iD.isGreaterThan(oD) )\r
132                         throw new ValidationException(this, "iD > oD");\r
133                 \r
134                 if ( iInh && oInh && eInh )\r
135                         throw new ValidationException(this, "No exposed grain surface");\r
136                 \r
137         }\r
138 \r
139         @Override\r
140         public Amount<Length> webThickness() {\r
141                 Amount<Length> radial = null;\r
142                 if ( !iInh && !oInh )\r
143                         radial = oD.minus(iD).divide(4); //Outer and inner exposed\r
144                 else if ( !iInh || !oInh )\r
145                         radial = oD.minus(iD).divide(2); //Outer or inner exposed\r
146                 \r
147                 Amount<Length> axial = null;\r
148                 \r
149                 if ( !eInh )\r
150                         axial = length.divide(2);\r
151                 \r
152                 if ( axial == null )\r
153                         return radial;\r
154                 if ( radial == null )\r
155                         return axial;\r
156                 if ( radial.isLessThan(axial) )\r
157                         return radial;\r
158                 return axial;\r
159         }\r
160 \r
161         public Amount<Length> getLength() {\r
162                 return length;\r
163         }\r
164 \r
165         public Amount<Length> getOD() {\r
166                 return oD;\r
167         }\r
168 \r
169         public Amount<Length> getID() {\r
170                 return iD;\r
171         }\r
172         \r
173         @Override\r
174         public java.awt.geom.Area getCrossSection(Amount<Length> regression){\r
175                 double rmm = regression.doubleValue(SI.MILLIMETER);\r
176                 double oDmm = oD.doubleValue(SI.MILLIMETER);\r
177                 double iDmm = iD.doubleValue(SI.MILLIMETER);\r
178 \r
179                 if ( !oInh )\r
180                         oDmm -= 2.0 * rmm;\r
181                 if ( !iInh )\r
182                         iDmm += 2.0 * rmm;\r
183                 \r
184                 Shape oDs = new Ellipse2D.Double(-oDmm/2.0, -oDmm/2.0, oDmm, oDmm);\r
185                 Shape iDs = new Ellipse2D.Double(-iDmm/2.0, -iDmm/2.0, iDmm, iDmm);\r
186                 \r
187                 java.awt.geom.Area a = new java.awt.geom.Area(oDs);\r
188                 a.subtract(new java.awt.geom.Area(iDs));\r
189                 return a;\r
190         }\r
191         \r
192         public java.awt.geom.Area getSideView(Amount<Length> regression){\r
193                 double rmm = regression.doubleValue(SI.MILLIMETER);\r
194                 double oDmm = oD.doubleValue(SI.MILLIMETER);\r
195                 double iDmm = iD.doubleValue(SI.MILLIMETER);\r
196                 double lmm = length.doubleValue(SI.MILLIMETER);\r
197 \r
198                 if ( !oInh )\r
199                         oDmm -= 2.0 * rmm;\r
200                 if ( !iInh )\r
201                         iDmm += 2.0 * rmm;\r
202                 if ( !eInh )\r
203                         lmm -= 2.0 * rmm;\r
204                 \r
205                 java.awt.geom.Area a = new java.awt.geom.Area();\r
206                 a.add( new java.awt.geom.Area(new Rectangle2D.Double(-oDmm/2,-lmm/2,oDmm, lmm)));\r
207                 a.subtract( new java.awt.geom.Area(new Rectangle2D.Double(-iDmm/2,-lmm/2,iDmm, lmm)));\r
208                 \r
209                 return a;\r
210         }\r
211         \r
212 \r
213 }\r