1 package com.billkuker.rocketry.motorsim.grain.util;
\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
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
14 import org.jscience.physics.amount.Amount;
\r
16 import com.billkuker.rocketry.motorsim.grain.ExtrudedGrain;
\r
18 public abstract class ExtrudedShapeGrain extends ExtrudedGrain {
\r
20 public static ExtrudedShapeGrain DEFAULT_GRAIN = new ExtrudedShapeGrain(){
\r
23 Shape outside = new Ellipse2D.Double(0, 0, 30, 30);
\r
24 xsection.add(outside);
\r
25 xsection.inhibit(outside);
\r
26 xsection.subtract(new Ellipse2D.Double(10,10, 10, 10));
\r
27 setLength(Amount.valueOf(70, SI.MILLIMETER));
\r
28 setForeEndInhibited(false);
\r
29 setAftEndInhibited(false);
\r
30 } catch ( Exception e ){
\r
36 protected BurningShape xsection = new BurningShape();
\r
38 protected Amount<Length> webThickness;
\r
40 public Amount<Area> surfaceArea(Amount<Length> regression) {
\r
41 Amount<Area> zero = Amount.valueOf(0, Area.UNIT);
\r
43 if (regression.isGreaterThan(webThickness()))
\r
46 Amount<Length> rLen = regressedLength(regression);
\r
48 if (rLen.isLessThan(Amount.valueOf(0, SI.MILLIMETER)))
\r
51 java.awt.geom.Area burn = getCrossSection(regression);
\r
56 burn.subtract(getCrossSection(regression.plus(Amount.valueOf(.001,
\r
59 Amount<Area> xSection = ShapeUtil.area(xsection.getShape(regression));
\r
61 Amount<Area> sides = ShapeUtil.perimeter(burn).divide(2).times(rLen).to(Area.UNIT);
\r
62 Amount<Area> ends = xSection.times(numberOfBurningEnds(regression));
\r
64 return sides.plus(ends);
\r
68 public Amount<Volume> volume(Amount<Length> regression) {
\r
69 Amount<Volume> zero = Amount.valueOf(0, Volume.UNIT);
\r
71 Amount<Length> rLen = regressedLength(regression);
\r
73 if (rLen.isLessThan(Amount.valueOf(0, SI.MILLIMETER)))
\r
76 Amount<Area> xSection = ShapeUtil.area(xsection.getShape(regression));
\r
78 return xSection.times(rLen).to(Volume.UNIT);
\r
83 public Amount<Length> webThickness() {
\r
84 if ( webThickness != null )
\r
85 return webThickness;
\r
86 java.awt.geom.Area a = getCrossSection(Amount.valueOf(0, SI.MILLIMETER));
\r
87 Rectangle r = a.getBounds();
\r
88 double max = r.getWidth() < r.getHeight() ? r.getHeight() : r
\r
89 .getWidth(); // The max size
\r
93 guess = min + (max - min) / 2; // Guess halfway through
\r
95 a = getCrossSection(Amount.valueOf(guess, SI.MILLIMETER));
\r
103 if ((max - min) < .01)
\r
106 webThickness = Amount.valueOf(guess, SI.MILLIMETER);
\r
108 //TODO Need to check # of burning ends!
\r
109 if (webThickness.isGreaterThan(getLength().divide(2)))
\r
110 webThickness = getLength().divide(2);
\r
112 return webThickness;
\r
115 public java.awt.geom.Area getCrossSection(Amount<Length> regression) {
\r
116 return xsection.getShape(regression);
\r
119 public java.awt.geom.Area getSideView(Amount<Length> regression) {
\r
120 java.awt.geom.Area res = new java.awt.geom.Area();
\r
122 Amount<Length> rLen = regressedLength(regression);
\r
124 double rLenmm = rLen.doubleValue(SI.MILLIMETER);
\r
126 for( java.awt.geom.Area a : ShapeUtil.separate(getCrossSection(regression))){
\r
127 Rectangle2D bounds = a.getBounds2D();
\r
128 Rectangle2D side = new Rectangle2D.Double(bounds.getMinX(), -rLenmm/2.0, bounds.getWidth(), rLenmm);
\r
129 res.add(new java.awt.geom.Area(side));
\r
132 //Shift up or down based on burning ends
\r
133 if ( isForeEndInhibited() ){
\r
134 res.transform(AffineTransform.getTranslateInstance(0, +rLenmm/2.0));
\r
136 if ( isAftEndInhibited() ){
\r
137 res.transform(AffineTransform.getTranslateInstance(0, -rLenmm/2.0));
\r