import org.jscience.physics.amount.Amount;\r
import org.jscience.physics.amount.Constants;\r
\r
+import com.billkuker.rocketry.motorsim.Validating.ValidationException;\r
+\r
public class Burn {\r
//Some constants to tune adaptive regression step\r
private static final double regStepIncreaseFactor = 1.01;\r
}\r
\r
public Burn(Motor m){\r
+ try {\r
+ m.validate();\r
+ } catch (ValidationException e) {\r
+ throw new IllegalArgumentException("Invalid Motor: " + e.getMessage());\r
+ }\r
motor = m;\r
burn();\r
}\r
\r
public Burn(Motor m, BurnProgressListener bpl){\r
+ try {\r
+ m.validate();\r
+ } catch (ValidationException e) {\r
+ throw new IllegalArgumentException("Invalid Motor: " + e.getMessage());\r
+ }\r
motor = m;\r
this.bpl = bpl;\r
burn();\r
\r
import org.jscience.physics.amount.Amount;\r
\r
-public class ConvergentDivergentNozzle implements Nozzle {\r
+public class ConvergentDivergentNozzle implements Nozzle, Validating {\r
\r
private Amount<Length> throatDiameter;\r
\r
\r
\r
public void setThroatDiameter(Amount<Length> throatDiameter) {\r
- if ( exitDiameter != null && throatDiameter.isGreaterThan(exitDiameter))\r
- throw new IllegalArgumentException("Throat > Exit");\r
this.throatDiameter = throatDiameter;\r
}\r
\r
\r
\r
public void setExitDiameter(Amount<Length> exitDiameter) {\r
- if ( throatDiameter != null && exitDiameter.isLessThan(throatDiameter))\r
- throw new IllegalArgumentException("Throat > Exit");\r
this.exitDiameter = exitDiameter;\r
}\r
\r
\r
return s;\r
}\r
+\r
+ @Override\r
+ public void validate() throws ValidationException {\r
+ if ( exitDiameter != null && throatDiameter.isGreaterThan(exitDiameter))\r
+ throw new IllegalArgumentException("Throat > Exit");\r
+ }\r
}\r
package com.billkuker.rocketry.motorsim;\r
\r
-public class Motor {\r
+import javax.measure.unit.SI;\r
+\r
+import org.jscience.physics.amount.Amount;\r
+import com.billkuker.rocketry.motorsim.Validating.ValidationException;\r
+\r
+public class Motor implements Validating{\r
private Chamber chamber;\r
private Grain grain;\r
private Nozzle nozzle;\r
private Fuel fuel;\r
private String name;\r
\r
+ public void validate() throws ValidationException {\r
+ if ( chamber.chamberVolume().isLessThan(grain.volume(Amount.valueOf(0, SI.MILLIMETER)))){\r
+ throw new ValidationException(this, "Fuel does not fit in chamber");\r
+ }\r
+ if ( chamber instanceof Validating )\r
+ ((Validating)chamber).validate();\r
+ if ( grain instanceof Validating )\r
+ ((Validating)grain).validate();\r
+ if ( nozzle instanceof Validating )\r
+ ((Validating)nozzle).validate();\r
+ if ( fuel instanceof Validating )\r
+ ((Validating)fuel).validate();\r
+ }\r
\r
public Chamber getChamber() {\r
return chamber;\r
--- /dev/null
+package com.billkuker.rocketry.motorsim;
+
+public interface Validating {
+
+ public class ValidationException extends Exception{
+ public ValidationException(Validating part, String error){
+ super(error);
+ }
+ }
+
+ public void validate() throws ValidationException;
+}
\r
import org.jscience.physics.amount.Amount;\r
\r
+import com.billkuker.rocketry.motorsim.Validating;\r
import com.billkuker.rocketry.motorsim.visual.Editor;\r
import com.billkuker.rocketry.motorsim.visual.GrainPanel;\r
\r
\r
-public class CoredCylindricalGrain extends ExtrudedGrain {\r
+public class CoredCylindricalGrain extends ExtrudedGrain implements Validating {\r
\r
private Amount<Length> oD, iD;\r
private boolean outerSurfaceInhibited = true, innerSurfaceInhibited = false;\r
iD = id;\r
}\r
\r
- /*\r
- public void checkValidity() throws ValidationException{\r
+ @Override\r
+ public void validate() throws ValidationException{\r
if ( iD.equals(Amount.ZERO) )\r
throw new ValidationException(this, "Invalid iD");\r
if ( oD.equals(Amount.ZERO) )\r
throw new ValidationException(this, "No exposed grain surface");\r
\r
}\r
- */\r
\r
public Amount<Length> webThickness() {\r
if ( innerSurfaceInhibited && outerSurfaceInhibited ){\r
\r
import org.jscience.physics.amount.Amount;\r
\r
+import com.billkuker.rocketry.motorsim.Validating;\r
+import com.billkuker.rocketry.motorsim.Validating.ValidationException;\r
import com.billkuker.rocketry.motorsim.grain.util.BurningShape;\r
import com.billkuker.rocketry.motorsim.grain.util.ExtrudedShapeGrain;\r
import com.billkuker.rocketry.motorsim.visual.Editor;\r
import com.billkuker.rocketry.motorsim.visual.GrainPanel;\r
\r
-public class Finocyl extends ExtrudedShapeGrain {\r
+public class Finocyl extends ExtrudedShapeGrain implements Validating {\r
private Amount<Length> oD = Amount.valueOf(30, SI.MILLIMETER);\r
private Amount<Length> iD = Amount.valueOf(10, SI.MILLIMETER);\r
private Amount<Length> finWidth = Amount.valueOf(2, SI.MILLIMETER);\r
new Editor(e).showAsWindow();\r
new GrainPanel(e).showAsWindow();\r
}\r
+ \r
+ @Override\r
+ public void validate() throws ValidationException{\r
+ if ( iD.equals(Amount.ZERO) )\r
+ throw new ValidationException(this, "Invalid iD");\r
+ if ( oD.equals(Amount.ZERO) )\r
+ throw new ValidationException(this, "Invalid oD");\r
+ if ( getLength().equals(Amount.ZERO) )\r
+ throw new ValidationException(this, "Invalid Length");\r
+ if ( iD.isGreaterThan(oD) )\r
+ throw new ValidationException(this, "iD > oD"); \r
+ }\r
}\r
\r
import org.jscience.physics.amount.Amount;\r
\r
+import com.billkuker.rocketry.motorsim.Validating;\r
+import com.billkuker.rocketry.motorsim.Validating.ValidationException;\r
import com.billkuker.rocketry.motorsim.grain.util.BurningShape;\r
import com.billkuker.rocketry.motorsim.grain.util.ExtrudedShapeGrain;\r
import com.billkuker.rocketry.motorsim.visual.Editor;\r
import com.billkuker.rocketry.motorsim.visual.GrainPanel;\r
\r
-public class Moonburner extends ExtrudedShapeGrain {\r
+public class Moonburner extends ExtrudedShapeGrain implements Validating {\r
\r
private Amount<Length> oD = Amount.valueOf(30, SI.MILLIMETER);\r
private Amount<Length> iD = Amount.valueOf(10, SI.MILLIMETER);\r
xsection.add(outside);\r
xsection.inhibit(outside);\r
\r
- xsection.subtract(new Ellipse2D.Double(odmm/2 - idmm/2 + offmm, odmm/2 - idmm/2 + offmm, idmm, idmm));\r
+ xsection.subtract(new Ellipse2D.Double(odmm/2 - idmm/2 + offmm, odmm/2 - idmm/2, idmm, idmm));\r
webThickness = null;\r
}\r
\r
new Editor(e).showAsWindow();\r
new GrainPanel(e).showAsWindow();\r
}\r
+ \r
+ public void validate() throws ValidationException{\r
+ if ( iD.equals(Amount.ZERO) )\r
+ throw new ValidationException(this, "Invalid iD");\r
+ if ( oD.equals(Amount.ZERO) )\r
+ throw new ValidationException(this, "Invalid oD");\r
+ if ( getLength().equals(Amount.ZERO) )\r
+ throw new ValidationException(this, "Invalid Length");\r
+ if ( iD.isGreaterThan(oD) )\r
+ throw new ValidationException(this, "iD > oD");\r
+ if ( coreOffset.isGreaterThan(iD.plus(oD).divide(2.0)))\r
+ throw new ValidationException(this, "Core offset too large");\r
+ }\r
\r
}\r
\r
import com.billkuker.rocketry.motorsim.ChangeListening;\r
import com.billkuker.rocketry.motorsim.Grain;\r
+import com.billkuker.rocketry.motorsim.Validating;\r
\r
-public class MultiGrain implements Grain, Grain.Composite, PropertyChangeListener {\r
+public class MultiGrain implements Grain, Grain.Composite, PropertyChangeListener, Validating {\r
\r
private Grain grain = null;\r
private int count = 1;\r
}\r
\r
public void setCount(int count) {\r
+ if ( count <= 0 )\r
+ throw new IllegalArgumentException("Must have at least 1 grain");\r
this.count = count;\r
}\r
\r
firePropertyChange(evt);\r
}\r
\r
+ @Override\r
+ public void validate() throws ValidationException {\r
+ if ( grain instanceof Validating )\r
+ ((Validating)grain).validate();\r
+ }\r
+\r
}\r
import org.jscience.physics.amount.Amount;\r
\r
import com.billkuker.rocketry.motorsim.Grain;\r
+import com.billkuker.rocketry.motorsim.Validating;\r
import com.billkuker.rocketry.motorsim.visual.Editor;\r
import com.billkuker.rocketry.motorsim.visual.GrainPanel;\r
\r
-public class RodAndTubeGrain extends CompoundGrain {\r
+public class RodAndTubeGrain extends CompoundGrain implements Validating {\r
CoredCylindricalGrain rod, tube;\r
\r
public static RodAndTubeGrain DEFAULT_GRAIN = new RodAndTubeGrain(){\r
new Editor(g).showAsWindow();\r
new GrainPanel(g).showAsWindow();\r
}\r
+\r
+ @Override\r
+ public void validate() throws ValidationException {\r
+ rod.validate();\r
+ tube.validate();\r
+ if ( rod.getOD().isGreaterThan(tube.getID()))\r
+ throw new ValidationException(this, "Rod does not fit inside tube");\r
+ \r
+ }\r
}\r
import javax.swing.JProgressBar;\r
import javax.swing.JSplitPane;\r
import javax.swing.JTabbedPane;\r
+import javax.swing.JTextArea;\r
import javax.swing.JTextField;\r
import javax.swing.SwingUtilities;\r
import javax.swing.UIManager;\r
public void run() {\r
final JProgressBar bar = new JProgressBar(0,100);\r
add(bar);\r
+ try{\r
final Burn b = new Burn(motor, new Burn.BurnProgressListener(){\r
@Override\r
public void setProgress(float f){\r
bar.setValue((int)(f*100));\r
}\r
});\r
+ \r
final BurnPanel bp = new BurnPanel(b);\r
SwingUtilities.invokeLater(new Thread() {\r
public void run() {\r
revalidate();\r
}\r
});\r
+ } catch ( Exception e ){\r
+ remove(bar);\r
+ JTextArea t = new JTextArea(e.getMessage());\r
+ t.setEditable(false);\r
+ add(t);\r
+ }\r
}\r
}.start();\r
}\r
package com.billkuker.rocketry.motorsim.visual.workbench;
+import java.awt.Color;
import java.awt.Component;
import javax.swing.JTree;
import javax.swing.tree.DefaultTreeCellRenderer;
import com.billkuker.rocketry.motorsim.Motor;
+import com.billkuker.rocketry.motorsim.Validating;
+import com.billkuker.rocketry.motorsim.Validating.ValidationException;
public class WorkbenchTreeCellRenderer extends DefaultTreeCellRenderer {
private static final long serialVersionUID = 1L;
@Override
- public Component getTreeCellRendererComponent(JTree tree, Object value,
+ public Component getTreeCellRendererComponent(JTree tree, final Object value,
boolean sel, boolean expanded, boolean leaf, int row,
boolean hasFocus) {
- super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf,
- row, hasFocus);
+
+ String tip = null;
+ setTextNonSelectionColor(Color.black);
+ setTextSelectionColor(Color.black);
+
+ Object part = null;
if (value instanceof DefaultMutableTreeNode) {
- value = ((DefaultMutableTreeNode) value).getUserObject();
+ part = ((DefaultMutableTreeNode) value).getUserObject();
+ }
+
+ if ( part instanceof Validating ){
+ try {
+ ((Validating)part).validate();
+ } catch (ValidationException e) {
+ setTextSelectionColor(Color.RED);
+ setTextNonSelectionColor(Color.RED);
+ setToolTipText(e.getMessage());
+ tip = e.getMessage();
+ }
}
- if (value instanceof Motor) {
- setText(((Motor) value).getName());
- } else if ( value == null ) {
+
+ super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf,
+ row, hasFocus);
+
+ if (part instanceof Motor) {
+ setText(((Motor) part).getName());
+ } else if ( part == null ) {
setText("");
} else {
- setText(value.getClass().getSimpleName());
+ setText(part.getClass().getSimpleName());
}
+ setToolTipText(tip);
+
+
return this;
}
}
- public class MotorNode extends DefaultMutableTreeNode implements PropertyChangeListener {
+ public class MotorNode extends PartNode implements PropertyChangeListener {
private static final long serialVersionUID = 1L;
Motor motor;
PartNode cn, nn, gn, fn;
public MotorNode(Motor m) {
super(m);
+ setAllowsChildren(true);
motor = m;
add( cn = new PartNode(m.getChamber()));
add( nn = new PartNode(m.getNozzle()));
} else {
nodeChanged(this);
}
+ super.propertyChange(e);
}
}