1 package com.billkuker.rocketry.motorsim.grain;
\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
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
13 import org.jscience.physics.amount.Amount;
\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
20 public class CoredCylindricalGrain extends ExtrudedGrain implements Validating {
\r
22 private Amount<Length> oD, iD;
\r
23 private boolean outerSurfaceInhibited = true, innerSurfaceInhibited = false;
\r
25 public static CoredCylindricalGrain DEFAULT_GRAIN = new CoredCylindricalGrain(){
\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
41 public CoredCylindricalGrain() {
\r
42 oD = Amount.valueOf(30, SI.MILLIMETER);
\r
43 iD = Amount.valueOf(10, SI.MILLIMETER);
\r
47 public void inhibit(boolean in, boolean out, boolean end){
\r
48 outerSurfaceInhibited = out;
\r
49 innerSurfaceInhibited = in;
\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
57 //Calculated regressed length
\r
58 Amount<Length> cLength = regressedLength(regression);
\r
60 //Calculate regressed iD
\r
61 Amount<Length> cID = iD;
\r
62 if ( !innerSurfaceInhibited ){
\r
63 cID = iD.plus(regression.times(2));
\r
66 //Calculate regressed oD
\r
67 Amount<Length> cOD = oD;
\r
68 if ( !outerSurfaceInhibited ){
\r
69 cOD = oD.minus(regression.times(2));
\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
79 Amount<Area> inner = cID.times(Math.PI).times(cLength).to(SI.SQUARE_METRE);
\r
81 Amount<Area> outer = cOD.times(Math.PI).times(cLength).to(SI.SQUARE_METRE);
\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
85 Amount<Area> total = inner.times(innerSurfaceInhibited?0:1).plus(outer.times(outerSurfaceInhibited?0:1)).plus(end.times(numberOfBurningEnds(regression)));
\r
90 public Amount<Volume> volume(Amount<Length> regression) {
\r
91 Amount<Length> zero = Amount.valueOf(0, SI.MILLIMETER);
\r
93 if ( regression.isLessThan(zero) )
\r
96 //Calculated regressed length
\r
97 Amount<Length> cLength = regressedLength(regression);
\r
99 //Calculate regressed iD
\r
100 Amount<Length> cID = iD;
\r
101 if ( !innerSurfaceInhibited ){
\r
102 cID = iD.plus(regression.times(2));
\r
105 //Calculate regressed oD
\r
106 Amount<Length> cOD = oD;
\r
107 if ( !outerSurfaceInhibited ){
\r
108 cOD = oD.minus(regression.times(2));
\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
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
121 return end.times(cLength).to(SI.CUBIC_METRE);
\r
124 public void setOD(Amount<Length> od) throws PropertyVetoException {
\r
128 public void setID(Amount<Length> id) throws PropertyVetoException {
\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
143 if ( innerSurfaceInhibited && outerSurfaceInhibited )
\r
144 throw new ValidationException(this, "No exposed grain surface");
\r
148 public Amount<Length> webThickness() {
\r
149 if ( innerSurfaceInhibited && outerSurfaceInhibited ){
\r
150 return oD; //TODO gotta move this to the end
\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
159 Amount<Length> axial = null;
\r
161 if ( numberOfBurningEnds(Amount.valueOf(0, SI.MILLIMETER)) != 0 )
\r
162 axial = getLength().divide(numberOfBurningEnds(Amount.valueOf(0, SI.MILLIMETER)));
\r
164 if ( axial == null )
\r
166 if ( radial == null )
\r
168 if ( radial.isLessThan(axial) )
\r
173 public Amount<Length> getOD() {
\r
177 public Amount<Length> getID() {
\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
185 double rmm = regression.doubleValue(SI.MILLIMETER);
\r
186 double oDmm = oD.doubleValue(SI.MILLIMETER);
\r
187 double iDmm = iD.doubleValue(SI.MILLIMETER);
\r
189 if ( !outerSurfaceInhibited )
\r
191 if ( !innerSurfaceInhibited )
\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
197 java.awt.geom.Area a = new java.awt.geom.Area(oDs);
\r
198 a.subtract(new java.awt.geom.Area(iDs));
\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
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
212 if ( !outerSurfaceInhibited )
\r
214 if ( !innerSurfaceInhibited )
\r
217 java.awt.geom.Area a = new java.awt.geom.Area();
\r
219 double top = -lmm/2;
\r
220 if ( isForeEndInhibited() && !isAftEndInhibited() )
\r
222 else if ( isAftEndInhibited() && !isForeEndInhibited() )
\r
223 top = length/2-lmm;
\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
232 public boolean isOuterSurfaceInhibited() {
\r
233 return outerSurfaceInhibited;
\r
237 public void setOuterSurfaceInhibited(boolean outerSurfaceInhibited) throws PropertyVetoException {
\r
238 this.outerSurfaceInhibited = outerSurfaceInhibited;
\r
242 public boolean isInnerSurfaceInhibited() {
\r
243 return innerSurfaceInhibited;
\r
247 public void setInnerSurfaceInhibited(boolean innerSurfaceInhibited) throws PropertyVetoException {
\r
248 this.innerSurfaceInhibited = innerSurfaceInhibited;
\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