New panels.
authorBill Kuker <bkuker@billkuker.com>
Fri, 10 Apr 2009 19:43:20 +0000 (19:43 +0000)
committerBill Kuker <bkuker@billkuker.com>
Fri, 10 Apr 2009 19:43:20 +0000 (19:43 +0000)
Better graphical representation of grains

.settings/org.eclipse.jdt.core.prefs [new file with mode: 0644]
.settings/org.eclipse.jdt.ui.prefs [new file with mode: 0644]
src/com/billkuker/rocketry/motorsim/Burn.java
src/com/billkuker/rocketry/motorsim/Grain.java
src/com/billkuker/rocketry/motorsim/grain/BurnPanel.java [new file with mode: 0644]
src/com/billkuker/rocketry/motorsim/grain/CoredCylindricalGrain.java
src/com/billkuker/rocketry/motorsim/grain/ExtrudedGrain.java
src/com/billkuker/rocketry/motorsim/grain/GrainPanel.java

diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs
new file mode 100644 (file)
index 0000000..667d97f
--- /dev/null
@@ -0,0 +1,12 @@
+#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
diff --git a/.settings/org.eclipse.jdt.ui.prefs b/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644 (file)
index 0000000..23755fd
--- /dev/null
@@ -0,0 +1,3 @@
+#Thu Apr 09 17:28:08 EDT 2009\r
+eclipse.preferences.version=1\r
+internal.default.compliance=default\r
index b0958e9476c55146d019c95c0bbff80a150c5039..f02d8ac00a636683bb8c174b2340baa32079b735 100644 (file)
@@ -24,8 +24,10 @@ import org.jscience.physics.amount.Amount;
 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
@@ -40,10 +42,10 @@ public class Burn {
        \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
@@ -54,6 +56,18 @@ public class Burn {
        \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
@@ -216,7 +230,7 @@ public class Burn {
                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
@@ -228,6 +242,8 @@ public class Burn {
                \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
@@ -244,19 +260,7 @@ public class Burn {
                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
index 8d36df30fa438d1bb36919df3c2de2743956317b..b5e9914288448837dc92ece3579559984cc2a0cb 100644 (file)
@@ -10,8 +10,9 @@ import org.jscience.physics.amount.Amount;
 \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
diff --git a/src/com/billkuker/rocketry/motorsim/grain/BurnPanel.java b/src/com/billkuker/rocketry/motorsim/grain/BurnPanel.java
new file mode 100644 (file)
index 0000000..c0a2673
--- /dev/null
@@ -0,0 +1,140 @@
+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
index 8727657ee5074b488906bd8c1356c4ece249185c..960cdaa9ba0ed62242b8cb5f9a7fb0eac3acfa44 100644 (file)
@@ -1,5 +1,13 @@
 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
@@ -11,7 +19,7 @@ import com.billkuker.rocketry.motorsim.Grain;
 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
@@ -156,7 +164,44 @@ public class CoredCylindricalGrain implements Grain, Validating {
                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
index 092430048186b41fff1e72b7356775ff3f75a4b7..a60c85dbf1daa21b83604adf2d9bbb1fabe62dc9 100644 (file)
@@ -56,8 +56,6 @@ public class ExtrudedGrain implements Grain, Grain.Graphical {
                Amount<Volume> volume;\r
        }\r
 \r
-       SortedMap<Amount<Length>, RegEntry> data = new TreeMap<Amount<Length>, RegEntry>();\r
-\r
        Amount<Length> webThickness;\r
 \r
        {\r
@@ -71,8 +69,8 @@ public class ExtrudedGrain implements Grain, Grain.Graphical {
                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
@@ -85,89 +83,48 @@ public class ExtrudedGrain implements Grain, Grain.Graphical {
 \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
@@ -189,7 +146,7 @@ public class ExtrudedGrain implements Grain, Grain.Graphical {
                \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
@@ -227,7 +184,7 @@ public class ExtrudedGrain implements Grain, Grain.Graphical {
        }\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
@@ -237,7 +194,7 @@ public class ExtrudedGrain implements Grain, Grain.Graphical {
                        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
@@ -253,12 +210,26 @@ public class ExtrudedGrain implements Grain, Grain.Graphical {
                        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
@@ -292,15 +263,42 @@ public class ExtrudedGrain implements Grain, Grain.Graphical {
                        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
@@ -310,30 +308,6 @@ public class ExtrudedGrain implements Grain, Grain.Graphical {
                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
@@ -429,7 +403,7 @@ public class ExtrudedGrain implements Grain, Grain.Graphical {
                                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
@@ -439,7 +413,6 @@ public class ExtrudedGrain implements Grain, Grain.Graphical {
                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
index 6f2b7d627b21a8e0bcb2070397082d867543fa50..e684236ee76455c2320531e09dc4325d05f3097d 100644 (file)
@@ -1,9 +1,12 @@
 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
@@ -71,30 +74,98 @@ public class GrainPanel extends JPanel {
                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
@@ -111,14 +182,8 @@ public class GrainPanel extends JPanel {
                @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