From 021e1d729b042ef6486ba153ebe8e64d926901c5 Mon Sep 17 00:00:00 2001 From: Bill Kuker Date: Fri, 10 Apr 2009 19:43:20 +0000 Subject: [PATCH] New panels. Better graphical representation of grains --- .settings/org.eclipse.jdt.core.prefs | 12 ++ .settings/org.eclipse.jdt.ui.prefs | 3 + src/com/billkuker/rocketry/motorsim/Burn.java | 38 ++-- .../billkuker/rocketry/motorsim/Grain.java | 5 +- .../rocketry/motorsim/grain/BurnPanel.java | 140 +++++++++++++ .../motorsim/grain/CoredCylindricalGrain.java | 47 ++++- .../motorsim/grain/ExtrudedGrain.java | 191 ++++++++---------- .../rocketry/motorsim/grain/GrainPanel.java | 93 +++++++-- 8 files changed, 386 insertions(+), 143 deletions(-) create mode 100644 .settings/org.eclipse.jdt.core.prefs create mode 100644 .settings/org.eclipse.jdt.ui.prefs create mode 100644 src/com/billkuker/rocketry/motorsim/grain/BurnPanel.java diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..667d97f --- /dev/null +++ b/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,12 @@ +#Thu Apr 09 17:28:08 EDT 2009 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/.settings/org.eclipse.jdt.ui.prefs b/.settings/org.eclipse.jdt.ui.prefs new file mode 100644 index 0000000..23755fd --- /dev/null +++ b/.settings/org.eclipse.jdt.ui.prefs @@ -0,0 +1,3 @@ +#Thu Apr 09 17:28:08 EDT 2009 +eclipse.preferences.version=1 +internal.default.compliance=default diff --git a/src/com/billkuker/rocketry/motorsim/Burn.java b/src/com/billkuker/rocketry/motorsim/Burn.java index b0958e9..f02d8ac 100644 --- a/src/com/billkuker/rocketry/motorsim/Burn.java +++ b/src/com/billkuker/rocketry/motorsim/Burn.java @@ -24,8 +24,10 @@ import org.jscience.physics.amount.Amount; import org.jscience.physics.amount.Constants; import com.billkuker.rocketry.motorsim.fuel.KNSU; +import com.billkuker.rocketry.motorsim.grain.BurnPanel; import com.billkuker.rocketry.motorsim.grain.CoredCylindricalGrain; import com.billkuker.rocketry.motorsim.grain.ExtrudedGrain; +import com.billkuker.rocketry.motorsim.grain.GrainPanel; import com.billkuker.rocketry.motorsim.visual.Chart; public class Burn { @@ -40,10 +42,10 @@ public class Burn { private static double densityRatio = 0.96; - protected class Interval{ + public class Interval{ Amount time; - Amount regression; - Amount chamberPressure; + public Amount regression; + public Amount chamberPressure; Amount chamberProduct; Amount thrust; @@ -54,6 +56,18 @@ public class Burn { protected SortedMap,Interval> data = new TreeMap, Interval>(); + public SortedMap,Interval> getData(){ + return data; + } + + public Motor getMotor(){ + return motor; + } + + public Amount burnTime(){ + return data.lastKey(); + } + public Burn(Motor m){ motor = m; } @@ -216,7 +230,7 @@ public class Burn { g.setID(Amount.valueOf(10, SI.MILLIMETER)); m.setGrain(g); - m.setGrain(new ExtrudedGrain()); + //m.setGrain(new ExtrudedGrain()); ConvergentDivergentNozzle n = new ConvergentDivergentNozzle(); n.setThroatDiameter(Amount.valueOf(6.600, SI.MILLIMETER)); @@ -228,6 +242,8 @@ public class Burn { b.burn(); + new BurnPanel(b).show(); + /* Chart r = new Chart( SI.SECOND, SI.MEGA(SI.PASCAL), @@ -244,19 +260,7 @@ public class Burn { t.setDomain(b.data.keySet()); t.show(); - /* - Chart s = new Chart(SI.MILLIMETER, - SI.MILLIMETER.pow(2).asType(Area.class), g, "surfaceArea"); - s.setDomain(s.new IntervalDomain(Amount.valueOf(0, SI.CENTIMETER), g - .webThickness())); - s.show(); - */ - - Chart kn = new Chart(SI.MILLIMETER, - Dimensionless.UNIT, b, "kn"); - kn.setDomain(kn.new IntervalDomain(Amount.valueOf(0, SI.CENTIMETER), m.getGrain() - .webThickness())); - kn.show(); + new GrainPanel( m.getGrain() ).show();*/ } } diff --git a/src/com/billkuker/rocketry/motorsim/Grain.java b/src/com/billkuker/rocketry/motorsim/Grain.java index 8d36df3..b5e9914 100644 --- a/src/com/billkuker/rocketry/motorsim/Grain.java +++ b/src/com/billkuker/rocketry/motorsim/Grain.java @@ -10,8 +10,9 @@ import org.jscience.physics.amount.Amount; public interface Grain { - public interface Graphical{ - public void draw( Graphics2D g, Amount regression ); + public interface Graphical extends Grain{ + public java.awt.geom.Area getCrossSection(Amount regression); + public java.awt.geom.Area getSideView(Amount regression); } public interface DiscreteRegression{ diff --git a/src/com/billkuker/rocketry/motorsim/grain/BurnPanel.java b/src/com/billkuker/rocketry/motorsim/grain/BurnPanel.java new file mode 100644 index 0000000..c0a2673 --- /dev/null +++ b/src/com/billkuker/rocketry/motorsim/grain/BurnPanel.java @@ -0,0 +1,140 @@ +package com.billkuker.rocketry.motorsim.grain; + +import java.awt.BorderLayout; +import java.text.NumberFormat; + +import javax.measure.quantity.Duration; +import javax.measure.quantity.Force; +import javax.measure.quantity.Pressure; +import javax.measure.quantity.Velocity; +import javax.measure.unit.SI; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JSlider; +import javax.swing.JSplitPane; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +import org.jscience.physics.amount.Amount; + +import com.billkuker.rocketry.motorsim.Burn; +import com.billkuker.rocketry.motorsim.visual.Chart; + +public class BurnPanel extends JPanel { + private Burn burn; + Chart pressure; + Chart thrust; + Chart burnRate; + GrainPanel grain; + Amount displayedTime = Amount.valueOf(0, SI.SECOND); + + public BurnPanel(Burn b){ + super( new BorderLayout() ); + burn = b; + + try { + pressure = new Chart( + SI.SECOND, + SI.MEGA(SI.PASCAL), + b, + "pressure"); + pressure.setDomain(burn.getData().keySet()); + + thrust = new Chart( + SI.SECOND, + SI.NEWTON, + b, + "thrust"); + thrust.setDomain(burn.getData().keySet()); + + burnRate = new Chart( + SI.MEGA(SI.PASCAL), + SI.METERS_PER_SECOND, + burn.getMotor().getFuel(), + "burnRate"); + burnRate.setDomain( + burnRate.new IntervalDomain( + Amount.valueOf(0, SI.MEGA(SI.PASCAL)), + Amount.valueOf(3, SI.MEGA(SI.PASCAL)), + 20 + )); + + + JSplitPane tp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, thrust, pressure); + tp.setDividerLocation(.5); + tp.setResizeWeight(.5); + + grain = new GrainPanel(burn.getMotor().getGrain()); + + JSplitPane grains = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, grain, burnRate); + grains.setDividerLocation(.5); + grains.setResizeWeight(.5); + + JSplitPane main = new JSplitPane(JSplitPane.VERTICAL_SPLIT, grains, tp); + main.setDividerLocation(.5); + main.setResizeWeight(.5); + + add( main, BorderLayout.CENTER ); + + add( new SL(), BorderLayout.SOUTH); + + } catch (NoSuchMethodException e){ + throw new Error(e); + } + + + } + + private class SL extends JSlider implements ChangeListener{ + private static final long serialVersionUID = 1L; + private static final int STEPS = 150; + public SL(){ + addChangeListener(this); + setMinimum(0); + setMaximum(STEPS); + setValue(0); + } + + @Override + public void stateChanged(ChangeEvent e) { + double t = ((SL)e.getSource()).getValue(); + displayedTime = burn.burnTime().divide(STEPS).times(t); + + //Find the nearest key in the data set + displayedTime =burn.getData().tailMap(displayedTime).firstKey(); + + NumberFormat nf = NumberFormat.getInstance(); + nf.setMaximumFractionDigits(2); + //System.out.println("Time: " + nf.format(displayedTime.doubleValue(SI.SECOND)) + "s"); + + pressure.mark(displayedTime); + thrust.mark(displayedTime); + + grain.setDisplayedRegression(burn.getData().get(displayedTime).regression); + + burnRate.mark(burn.getData().get(displayedTime).chamberPressure); + + + /* + double r = ((SL)e.getSource()).getValue(); + displayedRegression = grain.webThickness().divide(STEPS).times(r); + NumberFormat nf = NumberFormat.getInstance(); + nf.setMaximumFractionDigits(2); + l.setText("Regression: " + nf.format(displayedRegression.doubleValue(SI.MILLIMETER)) + "mm"); + area.mark(displayedRegression); + volume.mark(displayedRegression); + if ( xc != null ) + xc.repaint(); + */ + } + } + + public void show(){ + JFrame f = new JFrame(); + f.setSize(1280,720); + f.setLocation(0, 0); + f.setContentPane(this); + f.setDefaultCloseOperation(f.DISPOSE_ON_CLOSE); + f.setVisible(true); + } +} diff --git a/src/com/billkuker/rocketry/motorsim/grain/CoredCylindricalGrain.java b/src/com/billkuker/rocketry/motorsim/grain/CoredCylindricalGrain.java index 8727657..960cdaa 100644 --- a/src/com/billkuker/rocketry/motorsim/grain/CoredCylindricalGrain.java +++ b/src/com/billkuker/rocketry/motorsim/grain/CoredCylindricalGrain.java @@ -1,5 +1,13 @@ package com.billkuker.rocketry.motorsim.grain; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Rectangle2D; + import javax.measure.quantity.Area; import javax.measure.quantity.Length; import javax.measure.quantity.Volume; @@ -11,7 +19,7 @@ import com.billkuker.rocketry.motorsim.Grain; import com.billkuker.rocketry.motorsim.validation.Validating; import com.billkuker.rocketry.motorsim.validation.ValidationException; -public class CoredCylindricalGrain implements Grain, Validating { +public class CoredCylindricalGrain implements Grain, Validating, Grain.Graphical { private Amount length, oD, iD; private boolean oInh = true, iInh = false, eInh = false; @@ -156,7 +164,44 @@ public class CoredCylindricalGrain implements Grain, Validating { return iD; } + @Override + public java.awt.geom.Area getCrossSection(Amount regression){ + double rmm = regression.doubleValue(SI.MILLIMETER); + double oDmm = oD.doubleValue(SI.MILLIMETER); + double iDmm = iD.doubleValue(SI.MILLIMETER); + + if ( !oInh ) + oDmm -= 2.0 * rmm; + if ( !iInh ) + iDmm += 2.0 * rmm; + + Shape oDs = new Ellipse2D.Double(-oDmm/2.0, -oDmm/2.0, oDmm, oDmm); + Shape iDs = new Ellipse2D.Double(-iDmm/2.0, -iDmm/2.0, iDmm, iDmm); + + java.awt.geom.Area a = new java.awt.geom.Area(oDs); + a.subtract(new java.awt.geom.Area(iDs)); + return a; + } + public java.awt.geom.Area getSideView(Amount regression){ + double rmm = regression.doubleValue(SI.MILLIMETER); + double oDmm = oD.doubleValue(SI.MILLIMETER); + double iDmm = iD.doubleValue(SI.MILLIMETER); + double lmm = length.doubleValue(SI.MILLIMETER); + + if ( !oInh ) + oDmm -= 2.0 * rmm; + if ( !iInh ) + iDmm += 2.0 * rmm; + if ( !eInh ) + lmm -= 2.0 * rmm; + + java.awt.geom.Area a = new java.awt.geom.Area(); + a.add( new java.awt.geom.Area(new Rectangle2D.Double(-oDmm/2,-lmm/2,oDmm, lmm))); + a.subtract( new java.awt.geom.Area(new Rectangle2D.Double(-iDmm/2,-lmm/2,iDmm, lmm))); + + return a; + } } diff --git a/src/com/billkuker/rocketry/motorsim/grain/ExtrudedGrain.java b/src/com/billkuker/rocketry/motorsim/grain/ExtrudedGrain.java index 0924300..a60c85d 100644 --- a/src/com/billkuker/rocketry/motorsim/grain/ExtrudedGrain.java +++ b/src/com/billkuker/rocketry/motorsim/grain/ExtrudedGrain.java @@ -56,8 +56,6 @@ public class ExtrudedGrain implements Grain, Grain.Graphical { Amount volume; } - SortedMap, RegEntry> data = new TreeMap, RegEntry>(); - Amount webThickness; { @@ -71,8 +69,8 @@ public class ExtrudedGrain implements Grain, Grain.Graphical { Shape outside = new Ellipse2D.Double(0, 0, 30, 30); plus.add(outside); inhibited.add(outside); - minus.add(new Rectangle2D.Double(12, 25, 5, 10)); - minus.add(new Ellipse2D.Double(10, 4, 5, 5)); + minus.add(new Rectangle2D.Double(13, 13, 4, 30)); + //minus.add(new Ellipse2D.Double(12, 12, 6, 6)); length = Amount.valueOf(70, SI.MILLIMETER); /**/ @@ -85,89 +83,48 @@ public class ExtrudedGrain implements Grain, Grain.Graphical { findWebThickness(); - fillInData(); } @Override public Amount surfaceArea(Amount regression) { + Amount zero = Amount.valueOf(0, Area.UNIT); + if (regression.isGreaterThan(webThickness)) - return Amount.valueOf(0, Area.UNIT); - Amount highKey = data.tailMap(regression).firstKey(); - Amount lowKey; - try { - lowKey = data.headMap(regression).lastKey(); - } catch (NoSuchElementException e) { - return data.get(highKey).surfaceArea; - } - - double lp = regression.minus(lowKey).divide(highKey.minus(lowKey)).to( - Dimensionless.UNIT).doubleValue(Dimensionless.UNIT); + return zero; + + Amount rLen = length.minus(regression.times(2)); + if (rLen.isLessThan(Amount.valueOf(0, SI.MILLIMETER))) + return zero; - Amount lowVal = data.get(lowKey).surfaceArea; - Amount highVal = data.get(highKey).surfaceArea; + java.awt.geom.Area burn = getCrossSection(regression); + + if (burn.isEmpty()) + return zero; + + burn.subtract(getCrossSection(regression.plus(Amount.valueOf(.001, + SI.MILLIMETER)))); + + Amount xSection = crossSectionArea(regression); - return lowVal.times(1 - lp).plus(highVal.times(lp)); + return perimeter(burn).divide(2).times(rLen).plus( + xSection.times(2)).to(Area.UNIT); } @Override public Amount volume(Amount regression) { - if (regression.isGreaterThan(webThickness)) - return Amount.valueOf(0, Volume.UNIT); - Amount highKey = data.tailMap(regression).firstKey(); - Amount lowKey; - try { - lowKey = data.headMap(regression).lastKey(); - } catch (NoSuchElementException e) { - return data.get(highKey).volume; - } - - double lp = regression.minus(lowKey).divide(highKey.minus(lowKey)).to( - Dimensionless.UNIT).doubleValue(Dimensionless.UNIT); + Amount zero = Amount.valueOf(0, Volume.UNIT); + + Amount rLen = length.minus(regression.times(2)); + if (rLen.isLessThan(Amount.valueOf(0, SI.MILLIMETER))) + return zero; + + Amount xSection = crossSectionArea(regression); - Amount lowVal = data.get(lowKey).volume; - Amount highVal = data.get(highKey).volume; + return xSection.times(rLen).to(Volume.UNIT); - return lowVal.times(1 - lp).plus(highVal.times(lp)); } - private void fillInData() { - double max = webThickness().doubleValue(SI.MILLIMETER); - double delta = max / 100; - rStep = Amount.valueOf(delta, SI.MILLIMETER).divide(10); - for (double r = 0; r <= max + 1; r += delta) { - RegEntry e = new RegEntry(); - Amount regression = Amount.valueOf(r, SI.MILLIMETER); - Amount rLen = length.minus(regression.times(2)); - if (rLen.isLessThan(Amount.valueOf(0, SI.MILLIMETER))) - break; - - System.out.println("Calculating area for regression " + regression); - - java.awt.geom.Area burn = getArea(regression); - if (burn.isEmpty()) - break; - burn.subtract(getArea(regression.plus(Amount.valueOf(.001, - SI.MILLIMETER)))); - - //Amount xSection = crossSectionArea(getArea(regression)); - - Amount xSection = crossSectionArea(regression); - - e.volume = xSection.times(rLen).to(Volume.UNIT); - - e.surfaceArea = perimeter(burn).divide(2).times(rLen).plus( - xSection.times(2)).to(Area.UNIT); - - data.put(regression, e); - - } - - RegEntry e = new RegEntry(); - e.surfaceArea = Amount.valueOf(0, Area.UNIT); - e.volume = Amount.valueOf(0, Volume.UNIT); - data.put(webThickness(), e); - } private Amount crossSectionArea(Amount regression) { @@ -189,7 +146,7 @@ public class ExtrudedGrain implements Grain, Grain.Graphical { //Subtract PLUS from MINUS and return Amount area = plusArea.minus(minusArea); - System.out.println(area.to(SI.MILLIMETER.pow(2))); + return area; } @@ -227,7 +184,7 @@ public class ExtrudedGrain implements Grain, Grain.Graphical { } private void findWebThickness() { - java.awt.geom.Area a = getArea(Amount.valueOf(0, SI.MILLIMETER)); + java.awt.geom.Area a = getCrossSection(Amount.valueOf(0, SI.MILLIMETER)); Rectangle r = a.getBounds(); double max = r.getWidth() < r.getHeight() ? r.getHeight() : r .getWidth(); // The max size @@ -237,7 +194,7 @@ public class ExtrudedGrain implements Grain, Grain.Graphical { guess = min + (max - min) / 2; // Guess halfway through System.out.println("Min: " + min + " Guess: " + guess + " Max: " + max); - a = getArea(Amount.valueOf(guess, SI.MILLIMETER)); + a = getCrossSection(Amount.valueOf(guess, SI.MILLIMETER)); if (a.isEmpty()) { // guess is too big max = guess; @@ -253,12 +210,26 @@ public class ExtrudedGrain implements Grain, Grain.Graphical { webThickness = length.divide(2); } - private java.awt.geom.Area getArea(Amount regression) { + @Override + public java.awt.geom.Area getCrossSection(Amount regression) { java.awt.geom.Area res = getPlus(regression); res.subtract(getMinus(regression)); return res; } + @Override + public java.awt.geom.Area getSideView(Amount regression) { + java.awt.geom.Area res = new java.awt.geom.Area(); + double rLenmm = length.minus(regression.times(2)).doubleValue(SI.MILLIMETER); + + for( java.awt.geom.Area a : separate(getCrossSection(regression))){ + Rectangle2D bounds = a.getBounds2D(); + Rectangle2D side = new Rectangle2D.Double(bounds.getMinX(), -rLenmm/2.0, bounds.getWidth(), rLenmm); + res.add(new java.awt.geom.Area(side)); + } + return res; + } + private java.awt.geom.Area getPlus(Amount regression) { java.awt.geom.Area a = new java.awt.geom.Area(); for (Shape s : plus) @@ -292,15 +263,42 @@ public class ExtrudedGrain implements Grain, Grain.Graphical { return new Ellipse2D.Double(x, y, w, h); } else if (s instanceof Rectangle2D) { Rectangle2D r = (Rectangle2D) s; + + if ( plus ){ + double d = -2 * mm; + double w = r.getWidth() + d; + double h = r.getHeight() + d; + double x = r.getX() - d / 2; + double y = r.getY() - d / 2; + return new Rectangle2D.Double(x, y, w, h); + } else { + //A rectangular hole gets rounded corners as it grows + java.awt.geom.Area a = new java.awt.geom.Area(); + double d = 2 * mm; + + //Make it wider + double w = r.getWidth() + d; + double h = r.getHeight(); + double x = r.getX() - d / 2; + double y = r.getY(); + a.add( new java.awt.geom.Area(new Rectangle2D.Double(x, y, w, h))); + + //Make it taller + w = r.getWidth(); + h = r.getHeight() + d; + x = r.getX(); + y = r.getY() - d / 2; + a.add( new java.awt.geom.Area(new Rectangle2D.Double(x, y, w, h))); + + //Add rounded corners + a.add( new java.awt.geom.Area(new Ellipse2D.Double(r.getX()-mm, r.getY()-mm, mm*2, mm*2))); + a.add( new java.awt.geom.Area(new Ellipse2D.Double(r.getX()+r.getWidth()-mm, r.getY()-mm, mm*2, mm*2))); + a.add( new java.awt.geom.Area(new Ellipse2D.Double(r.getX()+r.getWidth()-mm, r.getY()+r.getHeight()-mm, mm*2, mm*2))); + a.add( new java.awt.geom.Area(new Ellipse2D.Double(r.getX()-mm, r.getY()+r.getHeight()-mm, mm*2, mm*2))); + + return a; + } - double d = plus ? -2 * mm : 2 * mm; - - double w = r.getWidth() + d; - double h = r.getHeight() + d; - double x = r.getX() - d / 2; - double y = r.getY() - d / 2; - - return new Rectangle2D.Double(x, y, w, h); } return null; } @@ -310,30 +308,6 @@ public class ExtrudedGrain implements Grain, Grain.Graphical { new GrainPanel(e).show(); } - @Override - public void draw(Graphics2D g2d, Amount regression) { - - java.awt.geom.Area reg = getArea(regression); - java.awt.geom.Area burn = getArea(regression); - burn.subtract(getArea(regression.plus(Amount.valueOf(.001, - SI.MILLIMETER)))); - java.awt.geom.Area noreg = getArea(Amount.valueOf(0, SI.MILLIMETER)); - - Rectangle bounds = noreg.getBounds(); - g2d.scale(200 / bounds.getWidth(), 200 / bounds.getHeight()); - g2d.translate(-bounds.getX(), -bounds.getY()); - - g2d.setStroke(new BasicStroke(0.5f)); - - g2d.setColor(Color.GRAY); - g2d.fill(reg); - g2d.setColor(Color.RED); - g2d.draw(burn); - g2d.setColor(Color.BLACK); - g2d.draw(noreg); - - - } /* * Separate an area into multiple distinct area. @@ -429,7 +403,7 @@ public class ExtrudedGrain implements Grain, Grain.Graphical { y = sy = coords[1]; break; default: - System.err.println("Got " + type); + throw new Error("Bad segment type from Flattening Path Iterator"); } i.next(); } @@ -439,7 +413,6 @@ public class ExtrudedGrain implements Grain, Grain.Graphical { if ( area < 0 ) //Depending on winding it could be negative area = area * -1.0; - System.out.println(area); return Amount.valueOf(area, SI.MILLIMETER.pow(2)).to(Area.UNIT); } diff --git a/src/com/billkuker/rocketry/motorsim/grain/GrainPanel.java b/src/com/billkuker/rocketry/motorsim/grain/GrainPanel.java index 6f2b7d6..e684236 100644 --- a/src/com/billkuker/rocketry/motorsim/grain/GrainPanel.java +++ b/src/com/billkuker/rocketry/motorsim/grain/GrainPanel.java @@ -1,9 +1,12 @@ package com.billkuker.rocketry.motorsim.grain; import java.awt.BorderLayout; +import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.geom.AffineTransform; import java.text.NumberFormat; import javax.measure.quantity.Area; @@ -71,30 +74,98 @@ public class GrainPanel extends JPanel { charts.setDividerLocation(.5); charts.setResizeWeight(.5); - if ( grain instanceof Grain.Graphical) - add(xc = new XC((Grain.Graphical)grain), BorderLayout.CENTER); - JPanel left = new JPanel(new BorderLayout()); - left.add(xc); + + if ( grain instanceof Grain.Graphical){ + add(xc = new XC((Grain.Graphical)grain), BorderLayout.CENTER); + left.add(xc); + } left.add(l, BorderLayout.NORTH); - left.add( new SL(), BorderLayout.SOUTH); + left.add( sl = new SL(), BorderLayout.SOUTH); add(new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, left, charts)); } + public void setDisplayedRegression( Amount r ){ + displayedRegression = r; + + NumberFormat nf = NumberFormat.getInstance(); + nf.setMaximumFractionDigits(2); + l.setText("Regression: " + nf.format(displayedRegression.doubleValue(SI.MILLIMETER)) + "mm"); + + area.mark(displayedRegression); + volume.mark(displayedRegression); + if ( xc != null ) + xc.repaint(); + } + private class XC extends JPanel{ private static final long serialVersionUID = 1L; Grain.Graphical grain; public XC(Grain.Graphical g){ - setMinimumSize(new Dimension(220,220)); + setMinimumSize(new Dimension(440,250)); grain = g; } public void paint(Graphics g){ super.paint(g); Graphics2D g2d = (Graphics2D)g; g2d.translate(10, 30); + /* grain.draw(g2d, displayedRegression ); + */ + + { + AffineTransform t = g2d.getTransform(); + java.awt.geom.Area unburnt = grain.getCrossSection(Amount.valueOf(0, SI.MILLIMETER)); + + Rectangle bounds = unburnt.getBounds(); + g2d.scale(200 / bounds.getWidth(), 200 / bounds.getHeight()); + g2d.translate(-bounds.getX(), -bounds.getY()); + + //Draw the fuel that is left + java.awt.geom.Area burning = grain.getCrossSection(displayedRegression); + g2d.setColor(Color.RED); + g2d.fill(burning); + //Draw the fuel that is left + java.awt.geom.Area left = grain.getCrossSection(displayedRegression.plus(grain.webThickness().divide(30))); + g2d.setColor(Color.GRAY); + g2d.fill(left); + //Draw the outline of the unburnt grain + g2d.setColor(Color.BLACK); + g2d.draw(unburnt); + //untranslate + g2d.setTransform(t); + } + { + AffineTransform t = g2d.getTransform(); + java.awt.geom.Area unburnt = grain.getSideView(Amount.valueOf(0, SI.MILLIMETER)); + + Rectangle bounds = unburnt.getBounds(); + g2d.translate(220, 0); + + double max = bounds.getWidth(); + if ( bounds.getHeight() > max ) + max = bounds.getHeight(); + + g2d.scale(200 / max, 200 / max); + g2d.translate(-bounds.getX(), -bounds.getY()); + + //Draw the fuel that is left + java.awt.geom.Area burning = grain.getSideView(displayedRegression); + g2d.setColor(Color.RED); + g2d.fill(burning); + //Draw the fuel that is left + java.awt.geom.Area left = grain.getSideView(displayedRegression.plus(grain.webThickness().divide(30))); + g2d.setColor(Color.GRAY); + g2d.fill(left); + //Draw the outline of the unburnt grain + g2d.setColor(Color.BLACK); + g2d.draw(unburnt); + //untranslate + g2d.setTransform(t); + } + } } @@ -111,14 +182,8 @@ public class GrainPanel extends JPanel { @Override public void stateChanged(ChangeEvent e) { double r = ((SL)e.getSource()).getValue(); - displayedRegression = grain.webThickness().divide(STEPS).times(r); - NumberFormat nf = NumberFormat.getInstance(); - nf.setMaximumFractionDigits(2); - l.setText("Regression: " + nf.format(displayedRegression.doubleValue(SI.MILLIMETER)) + "mm"); - area.mark(displayedRegression); - volume.mark(displayedRegression); - if ( xc != null ) - xc.repaint(); + + setDisplayedRegression(grain.webThickness().divide(STEPS).times(r)); } } -- 2.30.2