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
8 import java.beans.PropertyChangeEvent;
\r
9 import java.beans.PropertyChangeListener;
\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
16 import org.jscience.physics.amount.Amount;
\r
18 import com.billkuker.rocketry.motorsim.grain.ExtrudedGrain;
\r
20 public abstract class ExtrudedShapeGrain extends ExtrudedGrain {
\r
22 public static ExtrudedShapeGrain DEFAULT_GRAIN = new ExtrudedShapeGrain(){
\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
38 public ExtrudedShapeGrain(){
\r
39 addPropertyChangeListener(new PropertyChangeListener() {
\r
41 public void propertyChange(PropertyChangeEvent evt) {
\r
42 webThickness = null;
\r
47 protected BurningShape xsection = new BurningShape();
\r
49 protected Amount<Length> webThickness;
\r
51 public Amount<Area> surfaceArea(Amount<Length> regression) {
\r
52 Amount<Area> zero = Amount.valueOf(0, Area.UNIT);
\r
54 if (regression.isGreaterThan(webThickness()))
\r
57 Amount<Length> rLen = regressedLength(regression);
\r
59 if (rLen.isLessThan(Amount.valueOf(0, SI.MILLIMETER)))
\r
62 java.awt.geom.Area burn = getCrossSection(regression);
\r
67 burn.subtract(getCrossSection(regression.plus(Amount.valueOf(.001,
\r
70 Amount<Area> xSection = ShapeUtil.area(xsection.getShape(regression));
\r
72 Amount<Area> sides = ShapeUtil.perimeter(burn).divide(2).times(rLen).to(Area.UNIT);
\r
73 Amount<Area> ends = xSection.times(numberOfBurningEnds(regression));
\r
75 return sides.plus(ends);
\r
79 public Amount<Volume> volume(Amount<Length> regression) {
\r
80 Amount<Volume> zero = Amount.valueOf(0, Volume.UNIT);
\r
82 Amount<Length> rLen = regressedLength(regression);
\r
84 if (rLen.isLessThan(Amount.valueOf(0, SI.MILLIMETER)))
\r
87 Amount<Area> xSection = ShapeUtil.area(xsection.getShape(regression));
\r
89 return xSection.times(rLen).to(Volume.UNIT);
\r
94 public Amount<Length> webThickness() {
\r
95 if ( webThickness != null )
\r
96 return webThickness;
\r
97 java.awt.geom.Area a = getCrossSection(Amount.valueOf(0, SI.MILLIMETER));
\r
98 Rectangle r = a.getBounds();
\r
99 double max = r.getWidth() < r.getHeight() ? r.getHeight() : r
\r
100 .getWidth(); // The max size
\r
104 guess = min + (max - min) / 2; // Guess halfway through
\r
106 a = getCrossSection(Amount.valueOf(guess, SI.MILLIMETER));
\r
108 // guess is too big
\r
114 if ((max - min) < .01)
\r
117 webThickness = Amount.valueOf(guess, SI.MILLIMETER);
\r
119 int ends = numberOfBurningEnds(Amount.valueOf(0, SI.MILLIMETER));
\r
120 if (ends != 0 && webThickness.isGreaterThan(getLength().divide(ends)))
\r
121 webThickness = getLength().divide(ends);
\r
123 return webThickness;
\r
126 public java.awt.geom.Area getCrossSection(Amount<Length> regression) {
\r
127 return xsection.getShape(regression);
\r
130 public java.awt.geom.Area getSideView(Amount<Length> regression) {
\r
131 java.awt.geom.Area res = new java.awt.geom.Area();
\r
133 Amount<Length> rLen = regressedLength(regression);
\r
135 double rLenmm = rLen.doubleValue(SI.MILLIMETER);
\r
137 for( java.awt.geom.Area a : ShapeUtil.separate(getCrossSection(regression))){
\r
138 Rectangle2D bounds = a.getBounds2D();
\r
139 Rectangle2D side = new Rectangle2D.Double(bounds.getMinX(), -rLenmm/2.0, bounds.getWidth(), rLenmm);
\r
140 res.add(new java.awt.geom.Area(side));
\r
143 //Shift up or down based on burning ends
\r
144 if ( isForeEndInhibited() ){
\r
145 res.transform(AffineTransform.getTranslateInstance(0, +rLenmm/2.0));
\r
147 if ( isAftEndInhibited() ){
\r
148 res.transform(AffineTransform.getTranslateInstance(0, -rLenmm/2.0));
\r