--- /dev/null
+#Thu Apr 09 17:28:08 EDT 2009\r
+eclipse.preferences.version=1\r
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled\r
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6\r
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve\r
+org.eclipse.jdt.core.compiler.compliance=1.6\r
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate\r
+org.eclipse.jdt.core.compiler.debug.localVariable=generate\r
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate\r
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error\r
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error\r
+org.eclipse.jdt.core.compiler.source=1.6\r
--- /dev/null
+#Thu Apr 09 17:28:08 EDT 2009\r
+eclipse.preferences.version=1\r
+internal.default.compliance=default\r
import org.jscience.physics.amount.Constants;\r
\r
import com.billkuker.rocketry.motorsim.fuel.KNSU;\r
+import com.billkuker.rocketry.motorsim.grain.BurnPanel;\r
import com.billkuker.rocketry.motorsim.grain.CoredCylindricalGrain;\r
import com.billkuker.rocketry.motorsim.grain.ExtrudedGrain;\r
+import com.billkuker.rocketry.motorsim.grain.GrainPanel;\r
import com.billkuker.rocketry.motorsim.visual.Chart;\r
\r
public class Burn {\r
\r
private static double densityRatio = 0.96;\r
\r
- protected class Interval{\r
+ public class Interval{\r
Amount<Duration> time;\r
- Amount<Length> regression;\r
- Amount<Pressure> chamberPressure;\r
+ public Amount<Length> regression;\r
+ public Amount<Pressure> chamberPressure;\r
Amount<Mass> chamberProduct;\r
Amount<Force> thrust;\r
\r
\r
protected SortedMap<Amount<Duration>,Interval> data = new TreeMap<Amount<Duration>, Interval>();\r
\r
+ public SortedMap<Amount<Duration>,Interval> getData(){\r
+ return data;\r
+ }\r
+ \r
+ public Motor getMotor(){\r
+ return motor;\r
+ }\r
+\r
+ public Amount<Duration> burnTime(){\r
+ return data.lastKey();\r
+ }\r
+ \r
public Burn(Motor m){\r
motor = m;\r
}\r
g.setID(Amount.valueOf(10, SI.MILLIMETER));\r
m.setGrain(g);\r
\r
- m.setGrain(new ExtrudedGrain());\r
+ //m.setGrain(new ExtrudedGrain());\r
\r
ConvergentDivergentNozzle n = new ConvergentDivergentNozzle();\r
n.setThroatDiameter(Amount.valueOf(6.600, SI.MILLIMETER));\r
\r
b.burn();\r
\r
+ new BurnPanel(b).show();\r
+ /*\r
Chart<Duration, Pressure> r = new Chart<Duration, Pressure>(\r
SI.SECOND,\r
SI.MEGA(SI.PASCAL),\r
t.setDomain(b.data.keySet());\r
t.show();\r
\r
- /*\r
- Chart<Length, Area> s = new Chart<Length, Area>(SI.MILLIMETER,\r
- SI.MILLIMETER.pow(2).asType(Area.class), g, "surfaceArea");\r
- s.setDomain(s.new IntervalDomain(Amount.valueOf(0, SI.CENTIMETER), g\r
- .webThickness()));\r
- s.show();\r
- */\r
- \r
- Chart<Length, Dimensionless> kn = new Chart<Length, Dimensionless>(SI.MILLIMETER,\r
- Dimensionless.UNIT, b, "kn");\r
- kn.setDomain(kn.new IntervalDomain(Amount.valueOf(0, SI.CENTIMETER), m.getGrain()\r
- .webThickness()));\r
- kn.show();\r
+ new GrainPanel( m.getGrain() ).show();*/\r
\r
}\r
}\r
\r
public interface Grain {\r
\r
- public interface Graphical{\r
- public void draw( Graphics2D g, Amount<Length> regression );\r
+ public interface Graphical extends Grain{\r
+ public java.awt.geom.Area getCrossSection(Amount<Length> regression);\r
+ public java.awt.geom.Area getSideView(Amount<Length> regression);\r
}\r
\r
public interface DiscreteRegression{\r
--- /dev/null
+package com.billkuker.rocketry.motorsim.grain;\r
+\r
+import java.awt.BorderLayout;\r
+import java.text.NumberFormat;\r
+\r
+import javax.measure.quantity.Duration;\r
+import javax.measure.quantity.Force;\r
+import javax.measure.quantity.Pressure;\r
+import javax.measure.quantity.Velocity;\r
+import javax.measure.unit.SI;\r
+import javax.swing.JFrame;\r
+import javax.swing.JPanel;\r
+import javax.swing.JSlider;\r
+import javax.swing.JSplitPane;\r
+import javax.swing.event.ChangeEvent;\r
+import javax.swing.event.ChangeListener;\r
+\r
+import org.jscience.physics.amount.Amount;\r
+\r
+import com.billkuker.rocketry.motorsim.Burn;\r
+import com.billkuker.rocketry.motorsim.visual.Chart;\r
+\r
+public class BurnPanel extends JPanel {\r
+ private Burn burn;\r
+ Chart<Duration, Pressure> pressure;\r
+ Chart<Duration, Force> thrust;\r
+ Chart<Pressure, Velocity> burnRate;\r
+ GrainPanel grain;\r
+ Amount<Duration> displayedTime = Amount.valueOf(0, SI.SECOND);\r
+ \r
+ public BurnPanel(Burn b){\r
+ super( new BorderLayout() );\r
+ burn = b;\r
+ \r
+ try {\r
+ pressure = new Chart<Duration, Pressure>(\r
+ SI.SECOND,\r
+ SI.MEGA(SI.PASCAL),\r
+ b,\r
+ "pressure");\r
+ pressure.setDomain(burn.getData().keySet());\r
+ \r
+ thrust = new Chart<Duration, Force>(\r
+ SI.SECOND,\r
+ SI.NEWTON,\r
+ b,\r
+ "thrust");\r
+ thrust.setDomain(burn.getData().keySet());\r
+ \r
+ burnRate = new Chart<Pressure, Velocity>(\r
+ SI.MEGA(SI.PASCAL),\r
+ SI.METERS_PER_SECOND,\r
+ burn.getMotor().getFuel(),\r
+ "burnRate");\r
+ burnRate.setDomain(\r
+ burnRate.new IntervalDomain(\r
+ Amount.valueOf(0, SI.MEGA(SI.PASCAL)),\r
+ Amount.valueOf(3, SI.MEGA(SI.PASCAL)),\r
+ 20\r
+ ));\r
+ \r
+ \r
+ JSplitPane tp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, thrust, pressure);\r
+ tp.setDividerLocation(.5);\r
+ tp.setResizeWeight(.5);\r
+ \r
+ grain = new GrainPanel(burn.getMotor().getGrain());\r
+ \r
+ JSplitPane grains = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, grain, burnRate);\r
+ grains.setDividerLocation(.5);\r
+ grains.setResizeWeight(.5);\r
+ \r
+ JSplitPane main = new JSplitPane(JSplitPane.VERTICAL_SPLIT, grains, tp);\r
+ main.setDividerLocation(.5);\r
+ main.setResizeWeight(.5);\r
+ \r
+ add( main, BorderLayout.CENTER );\r
+ \r
+ add( new SL(), BorderLayout.SOUTH);\r
+ \r
+ } catch (NoSuchMethodException e){\r
+ throw new Error(e);\r
+ }\r
+ \r
+\r
+ }\r
+ \r
+ private class SL extends JSlider implements ChangeListener{\r
+ private static final long serialVersionUID = 1L;\r
+ private static final int STEPS = 150;\r
+ public SL(){\r
+ addChangeListener(this);\r
+ setMinimum(0);\r
+ setMaximum(STEPS);\r
+ setValue(0);\r
+ }\r
+ \r
+ @Override\r
+ public void stateChanged(ChangeEvent e) {\r
+ double t = ((SL)e.getSource()).getValue();\r
+ displayedTime = burn.burnTime().divide(STEPS).times(t);\r
+ \r
+ //Find the nearest key in the data set\r
+ displayedTime =burn.getData().tailMap(displayedTime).firstKey();\r
+ \r
+ NumberFormat nf = NumberFormat.getInstance();\r
+ nf.setMaximumFractionDigits(2);\r
+ //System.out.println("Time: " + nf.format(displayedTime.doubleValue(SI.SECOND)) + "s");\r
+ \r
+ pressure.mark(displayedTime);\r
+ thrust.mark(displayedTime);\r
+ \r
+ grain.setDisplayedRegression(burn.getData().get(displayedTime).regression);\r
+ \r
+ burnRate.mark(burn.getData().get(displayedTime).chamberPressure);\r
+ \r
+ \r
+ /*\r
+ double r = ((SL)e.getSource()).getValue();\r
+ displayedRegression = grain.webThickness().divide(STEPS).times(r);\r
+ NumberFormat nf = NumberFormat.getInstance();\r
+ nf.setMaximumFractionDigits(2);\r
+ l.setText("Regression: " + nf.format(displayedRegression.doubleValue(SI.MILLIMETER)) + "mm");\r
+ area.mark(displayedRegression);\r
+ volume.mark(displayedRegression);\r
+ if ( xc != null )\r
+ xc.repaint();\r
+ */\r
+ }\r
+ }\r
+ \r
+ public void show(){\r
+ JFrame f = new JFrame();\r
+ f.setSize(1280,720);\r
+ f.setLocation(0, 0);\r
+ f.setContentPane(this);\r
+ f.setDefaultCloseOperation(f.DISPOSE_ON_CLOSE);\r
+ f.setVisible(true);\r
+ }\r
+}\r
package com.billkuker.rocketry.motorsim.grain;\r
\r
+import java.awt.BasicStroke;\r
+import java.awt.Color;\r
+import java.awt.Graphics2D;\r
+import java.awt.Rectangle;\r
+import java.awt.Shape;\r
+import java.awt.geom.Ellipse2D;\r
+import java.awt.geom.Rectangle2D;\r
+\r
import javax.measure.quantity.Area;\r
import javax.measure.quantity.Length;\r
import javax.measure.quantity.Volume;\r
import com.billkuker.rocketry.motorsim.validation.Validating;\r
import com.billkuker.rocketry.motorsim.validation.ValidationException;\r
\r
-public class CoredCylindricalGrain implements Grain, Validating {\r
+public class CoredCylindricalGrain implements Grain, Validating, Grain.Graphical {\r
\r
private Amount<Length> length, oD, iD;\r
private boolean oInh = true, iInh = false, eInh = false;\r
return iD;\r
}\r
\r
+ @Override\r
+ public java.awt.geom.Area getCrossSection(Amount<Length> regression){\r
+ double rmm = regression.doubleValue(SI.MILLIMETER);\r
+ double oDmm = oD.doubleValue(SI.MILLIMETER);\r
+ double iDmm = iD.doubleValue(SI.MILLIMETER);\r
+\r
+ if ( !oInh )\r
+ oDmm -= 2.0 * rmm;\r
+ if ( !iInh )\r
+ iDmm += 2.0 * rmm;\r
+ \r
+ Shape oDs = new Ellipse2D.Double(-oDmm/2.0, -oDmm/2.0, oDmm, oDmm);\r
+ Shape iDs = new Ellipse2D.Double(-iDmm/2.0, -iDmm/2.0, iDmm, iDmm);\r
+ \r
+ java.awt.geom.Area a = new java.awt.geom.Area(oDs);\r
+ a.subtract(new java.awt.geom.Area(iDs));\r
+ return a;\r
+ }\r
\r
+ public java.awt.geom.Area getSideView(Amount<Length> regression){\r
+ double rmm = regression.doubleValue(SI.MILLIMETER);\r
+ double oDmm = oD.doubleValue(SI.MILLIMETER);\r
+ double iDmm = iD.doubleValue(SI.MILLIMETER);\r
+ double lmm = length.doubleValue(SI.MILLIMETER);\r
+\r
+ if ( !oInh )\r
+ oDmm -= 2.0 * rmm;\r
+ if ( !iInh )\r
+ iDmm += 2.0 * rmm;\r
+ if ( !eInh )\r
+ lmm -= 2.0 * rmm;\r
+ \r
+ java.awt.geom.Area a = new java.awt.geom.Area();\r
+ a.add( new java.awt.geom.Area(new Rectangle2D.Double(-oDmm/2,-lmm/2,oDmm, lmm)));\r
+ a.subtract( new java.awt.geom.Area(new Rectangle2D.Double(-iDmm/2,-lmm/2,iDmm, lmm)));\r
+ \r
+ return a;\r
+ }\r
\r
\r
}\r
Amount<Volume> volume;\r
}\r
\r
- SortedMap<Amount<Length>, RegEntry> data = new TreeMap<Amount<Length>, RegEntry>();\r
-\r
Amount<Length> webThickness;\r
\r
{\r
Shape outside = new Ellipse2D.Double(0, 0, 30, 30);\r
plus.add(outside);\r
inhibited.add(outside);\r
- minus.add(new Rectangle2D.Double(12, 25, 5, 10));\r
- minus.add(new Ellipse2D.Double(10, 4, 5, 5));\r
+ minus.add(new Rectangle2D.Double(13, 13, 4, 30));\r
+ //minus.add(new Ellipse2D.Double(12, 12, 6, 6));\r
length = Amount.valueOf(70, SI.MILLIMETER);\r
/**/\r
\r
\r
findWebThickness();\r
\r
- fillInData();\r
}\r
\r
@Override\r
public Amount<Area> surfaceArea(Amount<Length> regression) {\r
+ Amount<Area> zero = Amount.valueOf(0, Area.UNIT);\r
+ \r
if (regression.isGreaterThan(webThickness))\r
- return Amount.valueOf(0, Area.UNIT);\r
- Amount<Length> highKey = data.tailMap(regression).firstKey();\r
- Amount<Length> lowKey;\r
- try {\r
- lowKey = data.headMap(regression).lastKey();\r
- } catch (NoSuchElementException e) {\r
- return data.get(highKey).surfaceArea;\r
- }\r
-\r
- double lp = regression.minus(lowKey).divide(highKey.minus(lowKey)).to(\r
- Dimensionless.UNIT).doubleValue(Dimensionless.UNIT);\r
+ return zero;\r
+ \r
+ Amount<Length> rLen = length.minus(regression.times(2));\r
+ if (rLen.isLessThan(Amount.valueOf(0, SI.MILLIMETER)))\r
+ return zero;\r
\r
- Amount<Area> lowVal = data.get(lowKey).surfaceArea;\r
- Amount<Area> highVal = data.get(highKey).surfaceArea;\r
+ java.awt.geom.Area burn = getCrossSection(regression);\r
+ \r
+ if (burn.isEmpty())\r
+ return zero;\r
+ \r
+ burn.subtract(getCrossSection(regression.plus(Amount.valueOf(.001,\r
+ SI.MILLIMETER))));\r
+ \r
+ Amount<Area> xSection = crossSectionArea(regression);\r
\r
- return lowVal.times(1 - lp).plus(highVal.times(lp));\r
+ return perimeter(burn).divide(2).times(rLen).plus(\r
+ xSection.times(2)).to(Area.UNIT);\r
}\r
\r
@Override\r
public Amount<Volume> volume(Amount<Length> regression) {\r
- if (regression.isGreaterThan(webThickness))\r
- return Amount.valueOf(0, Volume.UNIT);\r
- Amount<Length> highKey = data.tailMap(regression).firstKey();\r
- Amount<Length> lowKey;\r
- try {\r
- lowKey = data.headMap(regression).lastKey();\r
- } catch (NoSuchElementException e) {\r
- return data.get(highKey).volume;\r
- }\r
-\r
- double lp = regression.minus(lowKey).divide(highKey.minus(lowKey)).to(\r
- Dimensionless.UNIT).doubleValue(Dimensionless.UNIT);\r
+ Amount<Volume> zero = Amount.valueOf(0, Volume.UNIT);\r
+ \r
+ Amount<Length> rLen = length.minus(regression.times(2));\r
+ if (rLen.isLessThan(Amount.valueOf(0, SI.MILLIMETER)))\r
+ return zero;\r
+ \r
+ Amount<Area> xSection = crossSectionArea(regression);\r
\r
- Amount<Volume> lowVal = data.get(lowKey).volume;\r
- Amount<Volume> highVal = data.get(highKey).volume;\r
+ return xSection.times(rLen).to(Volume.UNIT);\r
\r
- return lowVal.times(1 - lp).plus(highVal.times(lp));\r
}\r
\r
- private void fillInData() {\r
- double max = webThickness().doubleValue(SI.MILLIMETER);\r
- double delta = max / 100;\r
- rStep = Amount.valueOf(delta, SI.MILLIMETER).divide(10);\r
- for (double r = 0; r <= max + 1; r += delta) {\r
- RegEntry e = new RegEntry();\r
- Amount<Length> regression = Amount.valueOf(r, SI.MILLIMETER);\r
\r
- Amount<Length> rLen = length.minus(regression.times(2));\r
- if (rLen.isLessThan(Amount.valueOf(0, SI.MILLIMETER)))\r
- break;\r
-\r
- System.out.println("Calculating area for regression " + regression);\r
-\r
- java.awt.geom.Area burn = getArea(regression);\r
- if (burn.isEmpty())\r
- break;\r
- burn.subtract(getArea(regression.plus(Amount.valueOf(.001,\r
- SI.MILLIMETER))));\r
-\r
- //Amount<Area> xSection = crossSectionArea(getArea(regression));\r
- \r
- Amount<Area> xSection = crossSectionArea(regression);\r
-\r
- e.volume = xSection.times(rLen).to(Volume.UNIT);\r
-\r
- e.surfaceArea = perimeter(burn).divide(2).times(rLen).plus(\r
- xSection.times(2)).to(Area.UNIT);\r
-\r
- data.put(regression, e);\r
-\r
- }\r
-\r
- RegEntry e = new RegEntry();\r
- e.surfaceArea = Amount.valueOf(0, Area.UNIT);\r
- e.volume = Amount.valueOf(0, Volume.UNIT);\r
- data.put(webThickness(), e);\r
- }\r
\r
\r
private Amount<Area> crossSectionArea(Amount<Length> regression) {\r
\r
//Subtract PLUS from MINUS and return\r
Amount<Area> area = plusArea.minus(minusArea);\r
- System.out.println(area.to(SI.MILLIMETER.pow(2)));\r
+\r
return area;\r
}\r
\r
}\r
\r
private void findWebThickness() {\r
- java.awt.geom.Area a = getArea(Amount.valueOf(0, SI.MILLIMETER));\r
+ java.awt.geom.Area a = getCrossSection(Amount.valueOf(0, SI.MILLIMETER));\r
Rectangle r = a.getBounds();\r
double max = r.getWidth() < r.getHeight() ? r.getHeight() : r\r
.getWidth(); // The max size\r
guess = min + (max - min) / 2; // Guess halfway through\r
System.out.println("Min: " + min + " Guess: " + guess + " Max: "\r
+ max);\r
- a = getArea(Amount.valueOf(guess, SI.MILLIMETER));\r
+ a = getCrossSection(Amount.valueOf(guess, SI.MILLIMETER));\r
if (a.isEmpty()) {\r
// guess is too big\r
max = guess;\r
webThickness = length.divide(2);\r
}\r
\r
- private java.awt.geom.Area getArea(Amount<Length> regression) {\r
+ @Override\r
+ public java.awt.geom.Area getCrossSection(Amount<Length> regression) {\r
java.awt.geom.Area res = getPlus(regression);\r
res.subtract(getMinus(regression));\r
return res;\r
}\r
\r
+ @Override\r
+ public java.awt.geom.Area getSideView(Amount<Length> regression) {\r
+ java.awt.geom.Area res = new java.awt.geom.Area();\r
+ double rLenmm = length.minus(regression.times(2)).doubleValue(SI.MILLIMETER);\r
+ \r
+ for( java.awt.geom.Area a : separate(getCrossSection(regression))){\r
+ Rectangle2D bounds = a.getBounds2D();\r
+ Rectangle2D side = new Rectangle2D.Double(bounds.getMinX(), -rLenmm/2.0, bounds.getWidth(), rLenmm);\r
+ res.add(new java.awt.geom.Area(side));\r
+ }\r
+ return res;\r
+ }\r
+ \r
private java.awt.geom.Area getPlus(Amount<Length> regression) {\r
java.awt.geom.Area a = new java.awt.geom.Area();\r
for (Shape s : plus)\r
return new Ellipse2D.Double(x, y, w, h);\r
} else if (s instanceof Rectangle2D) {\r
Rectangle2D r = (Rectangle2D) s;\r
+ \r
+ if ( plus ){\r
+ double d = -2 * mm;\r
+ double w = r.getWidth() + d;\r
+ double h = r.getHeight() + d;\r
+ double x = r.getX() - d / 2;\r
+ double y = r.getY() - d / 2;\r
+ return new Rectangle2D.Double(x, y, w, h);\r
+ } else {\r
+ //A rectangular hole gets rounded corners as it grows\r
+ java.awt.geom.Area a = new java.awt.geom.Area();\r
+ double d = 2 * mm;\r
+ \r
+ //Make it wider\r
+ double w = r.getWidth() + d;\r
+ double h = r.getHeight();\r
+ double x = r.getX() - d / 2;\r
+ double y = r.getY();\r
+ a.add( new java.awt.geom.Area(new Rectangle2D.Double(x, y, w, h)));\r
+ \r
+ //Make it taller\r
+ w = r.getWidth();\r
+ h = r.getHeight() + d;\r
+ x = r.getX();\r
+ y = r.getY() - d / 2;\r
+ a.add( new java.awt.geom.Area(new Rectangle2D.Double(x, y, w, h)));\r
+ \r
+ //Add rounded corners\r
+ a.add( new java.awt.geom.Area(new Ellipse2D.Double(r.getX()-mm, r.getY()-mm, mm*2, mm*2)));\r
+ a.add( new java.awt.geom.Area(new Ellipse2D.Double(r.getX()+r.getWidth()-mm, r.getY()-mm, mm*2, mm*2)));\r
+ a.add( new java.awt.geom.Area(new Ellipse2D.Double(r.getX()+r.getWidth()-mm, r.getY()+r.getHeight()-mm, mm*2, mm*2)));\r
+ a.add( new java.awt.geom.Area(new Ellipse2D.Double(r.getX()-mm, r.getY()+r.getHeight()-mm, mm*2, mm*2)));\r
+ \r
+ return a;\r
+ }\r
\r
- double d = plus ? -2 * mm : 2 * mm;\r
-\r
- double w = r.getWidth() + d;\r
- double h = r.getHeight() + d;\r
- double x = r.getX() - d / 2;\r
- double y = r.getY() - d / 2;\r
-\r
- return new Rectangle2D.Double(x, y, w, h);\r
}\r
return null;\r
}\r
new GrainPanel(e).show();\r
}\r
\r
- @Override\r
- public void draw(Graphics2D g2d, Amount<Length> regression) {\r
-\r
- java.awt.geom.Area reg = getArea(regression);\r
- java.awt.geom.Area burn = getArea(regression);\r
- burn.subtract(getArea(regression.plus(Amount.valueOf(.001,\r
- SI.MILLIMETER))));\r
- java.awt.geom.Area noreg = getArea(Amount.valueOf(0, SI.MILLIMETER));\r
-\r
- Rectangle bounds = noreg.getBounds();\r
- g2d.scale(200 / bounds.getWidth(), 200 / bounds.getHeight());\r
- g2d.translate(-bounds.getX(), -bounds.getY());\r
-\r
- g2d.setStroke(new BasicStroke(0.5f));\r
-\r
- g2d.setColor(Color.GRAY);\r
- g2d.fill(reg);\r
- g2d.setColor(Color.RED);\r
- g2d.draw(burn);\r
- g2d.setColor(Color.BLACK);\r
- g2d.draw(noreg);\r
- \r
-\r
- }\r
\r
/*\r
* Separate an area into multiple distinct area.\r
y = sy = coords[1];\r
break;\r
default:\r
- System.err.println("Got " + type);\r
+ throw new Error("Bad segment type from Flattening Path Iterator");\r
}\r
i.next();\r
}\r
if ( area < 0 ) //Depending on winding it could be negative\r
area = area * -1.0;\r
\r
- System.out.println(area);\r
\r
return Amount.valueOf(area, SI.MILLIMETER.pow(2)).to(Area.UNIT);\r
}\r
package com.billkuker.rocketry.motorsim.grain;\r
\r
import java.awt.BorderLayout;\r
+import java.awt.Color;\r
import java.awt.Dimension;\r
import java.awt.Graphics;\r
import java.awt.Graphics2D;\r
+import java.awt.Rectangle;\r
+import java.awt.geom.AffineTransform;\r
import java.text.NumberFormat;\r
\r
import javax.measure.quantity.Area;\r
charts.setDividerLocation(.5);\r
charts.setResizeWeight(.5);\r
\r
- if ( grain instanceof Grain.Graphical)\r
- add(xc = new XC((Grain.Graphical)grain), BorderLayout.CENTER);\r
- \r
JPanel left = new JPanel(new BorderLayout());\r
- left.add(xc);\r
+ \r
+ if ( grain instanceof Grain.Graphical){\r
+ add(xc = new XC((Grain.Graphical)grain), BorderLayout.CENTER);\r
+ left.add(xc);\r
+ }\r
left.add(l, BorderLayout.NORTH);\r
- left.add( new SL(), BorderLayout.SOUTH);\r
+ left.add( sl = new SL(), BorderLayout.SOUTH);\r
\r
add(new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, left, charts));\r
\r
}\r
\r
+ public void setDisplayedRegression( Amount<Length> r ){\r
+ displayedRegression = r;\r
+ \r
+ NumberFormat nf = NumberFormat.getInstance();\r
+ nf.setMaximumFractionDigits(2);\r
+ l.setText("Regression: " + nf.format(displayedRegression.doubleValue(SI.MILLIMETER)) + "mm");\r
+ \r
+ area.mark(displayedRegression);\r
+ volume.mark(displayedRegression);\r
+ if ( xc != null )\r
+ xc.repaint();\r
+ }\r
+ \r
private class XC extends JPanel{\r
private static final long serialVersionUID = 1L;\r
Grain.Graphical grain;\r
public XC(Grain.Graphical g){\r
- setMinimumSize(new Dimension(220,220));\r
+ setMinimumSize(new Dimension(440,250));\r
grain = g;\r
}\r
public void paint(Graphics g){\r
super.paint(g);\r
Graphics2D g2d = (Graphics2D)g;\r
g2d.translate(10, 30);\r
+ /*\r
grain.draw(g2d, displayedRegression );\r
+ */\r
+ \r
+ {\r
+ AffineTransform t = g2d.getTransform();\r
+ java.awt.geom.Area unburnt = grain.getCrossSection(Amount.valueOf(0, SI.MILLIMETER));\r
+ \r
+ Rectangle bounds = unburnt.getBounds();\r
+ g2d.scale(200 / bounds.getWidth(), 200 / bounds.getHeight());\r
+ g2d.translate(-bounds.getX(), -bounds.getY());\r
+ \r
+ //Draw the fuel that is left\r
+ java.awt.geom.Area burning = grain.getCrossSection(displayedRegression);\r
+ g2d.setColor(Color.RED);\r
+ g2d.fill(burning);\r
+ //Draw the fuel that is left\r
+ java.awt.geom.Area left = grain.getCrossSection(displayedRegression.plus(grain.webThickness().divide(30)));\r
+ g2d.setColor(Color.GRAY);\r
+ g2d.fill(left);\r
+ //Draw the outline of the unburnt grain\r
+ g2d.setColor(Color.BLACK);\r
+ g2d.draw(unburnt);\r
+ //untranslate\r
+ g2d.setTransform(t);\r
+ }\r
+ {\r
+ AffineTransform t = g2d.getTransform();\r
+ java.awt.geom.Area unburnt = grain.getSideView(Amount.valueOf(0, SI.MILLIMETER));\r
+ \r
+ Rectangle bounds = unburnt.getBounds();\r
+ g2d.translate(220, 0);\r
+ \r
+ double max = bounds.getWidth();\r
+ if ( bounds.getHeight() > max )\r
+ max = bounds.getHeight();\r
+ \r
+ g2d.scale(200 / max, 200 / max);\r
+ g2d.translate(-bounds.getX(), -bounds.getY());\r
+ \r
+ //Draw the fuel that is left\r
+ java.awt.geom.Area burning = grain.getSideView(displayedRegression);\r
+ g2d.setColor(Color.RED);\r
+ g2d.fill(burning);\r
+ //Draw the fuel that is left\r
+ java.awt.geom.Area left = grain.getSideView(displayedRegression.plus(grain.webThickness().divide(30)));\r
+ g2d.setColor(Color.GRAY);\r
+ g2d.fill(left);\r
+ //Draw the outline of the unburnt grain\r
+ g2d.setColor(Color.BLACK);\r
+ g2d.draw(unburnt);\r
+ //untranslate\r
+ g2d.setTransform(t);\r
+ }\r
+ \r
}\r
}\r
\r
@Override\r
public void stateChanged(ChangeEvent e) {\r
double r = ((SL)e.getSource()).getValue();\r
- displayedRegression = grain.webThickness().divide(STEPS).times(r);\r
- NumberFormat nf = NumberFormat.getInstance();\r
- nf.setMaximumFractionDigits(2);\r
- l.setText("Regression: " + nf.format(displayedRegression.doubleValue(SI.MILLIMETER)) + "mm");\r
- area.mark(displayedRegression);\r
- volume.mark(displayedRegression);\r
- if ( xc != null )\r
- xc.repaint();\r
+\r
+ setDisplayedRegression(grain.webThickness().divide(STEPS).times(r));\r
}\r
}\r
\r