Added new feature : user configurable custom expression evaluation for the simulation, driven by exp4j.
This commit is contained in:
parent
d103ac1d05
commit
16eed9a30b
@ -89,7 +89,6 @@ dlg.but.ok = OK
|
||||
dlg.but.cancel = Cancel
|
||||
dlg.but.close = Close
|
||||
|
||||
|
||||
! General file type names
|
||||
filetypes.pdf = PDF files (*.pdf)
|
||||
BasicFrame.SimpleFileFilter1 = All rocket designs (*.ork; *.rkt)
|
||||
@ -286,6 +285,7 @@ simedtdlg.lbl.Simname = Simulation name:
|
||||
simedtdlg.tab.Launchcond = Launch conditions
|
||||
simedtdlg.tab.Simopt = Simulation options
|
||||
simedtdlg.tab.Plotdata = Plot data
|
||||
simedtdlg.tab.CustomExpressions = Custom expressions
|
||||
simedtdlg.tab.Exportdata = Export data
|
||||
simedtdlg.lbl.Motorcfg = Motor configuration:
|
||||
simedtdlg.lbl.ttip.Motorcfg = Select the motor configuration to use.
|
||||
@ -444,6 +444,37 @@ CsvOptionPanel.separator.space = SPACE
|
||||
CsvOptionPanel.separator.tab = TAB
|
||||
|
||||
|
||||
! Custom expression general stuff
|
||||
customExpression.Name = Name
|
||||
customExpression.Symbol = Symbol
|
||||
customExpression.Expression = Expression
|
||||
customExpression.Units = Units
|
||||
customExpression.Operator = Operator
|
||||
customExpression.Description = Description
|
||||
|
||||
! Custom expression panel
|
||||
customExpressionPanel.but.NewExpression = New expression
|
||||
customExpressionPanel.lbl.UpdateNote = You must run the simulation before data will be available for plotting.
|
||||
customExpressionPanel.lbl.CalcNote = Expressions will be calculated in the order shown.
|
||||
customExpressionPanel.lbl.CustomExpressions = Custom Expressions :
|
||||
customExpression.Units.but.ttip.Remove = Remove this expression
|
||||
customExpression.Units.but.ttip.Edit = Edit this expression
|
||||
customExpression.Units.but.ttip.MoveUp = Move expression up in calculation order
|
||||
customExpression.Units.but.ttip.MoveDown = Move expression down in calculation order
|
||||
|
||||
! Custom expression builder window
|
||||
ExpressionBuilderDialog.title = Expression Builder
|
||||
ExpressionBuilderDialog.InsertVariable = Insert Variable
|
||||
ExpressionBuilderDialog.InsertOperator = Insert Operator
|
||||
ExpressionBuilderDialog.led.ttip.Name = Name must not have already been used
|
||||
ExpressionBuilderDialog.led.ttip.Symbol = Symbol must not have already been used
|
||||
ExpressionBuilderDialog.led.ttip.Expression = Expression must use only known symbols and operators
|
||||
|
||||
! Custom expression variable selector
|
||||
CustomVariableSelector.title = Variable Selector
|
||||
|
||||
! Custom operator selector
|
||||
CustomOperatorSelector.title = Operator Selector
|
||||
|
||||
! MotorPlot
|
||||
MotorPlot.title.Motorplot = Motor plot
|
||||
@ -457,8 +488,6 @@ MotorPlot.txt.Type = Type:
|
||||
MotorPlot.txt.Delays = Delays:
|
||||
MotorPlot.txt.Comment = Comment:\n
|
||||
|
||||
|
||||
|
||||
! Simulation plot panel
|
||||
simplotpanel.lbl.Presetplotconf = Preset plot configurations:
|
||||
simplotpanel.lbl.Xaxistype = X axis type:
|
||||
@ -481,7 +510,6 @@ simplotpanel.CUSTOM = Custom
|
||||
SimulationPlotPanel.error.noPlotSelected = Please add one or more variables to plot on the Y-axis.
|
||||
SimulationPlotPanel.error.noPlotSelected.title = Nothing to plot
|
||||
|
||||
|
||||
! Component add buttons
|
||||
compaddbuttons.Bodycompandfinsets = Body components and fin sets
|
||||
compaddbuttons.Nosecone = Nose cone
|
||||
|
||||
@ -20,6 +20,9 @@ edit-delete.png
|
||||
edit-paste.png
|
||||
edit-redo.png
|
||||
edit-undo.png
|
||||
down.png
|
||||
pencil.png
|
||||
up.png
|
||||
edit-scale.png (modified from edit-copy.png)
|
||||
|
||||
|
||||
|
||||
BIN
core/resources/pix/icons/down.png
Normal file
BIN
core/resources/pix/icons/down.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 912 B |
BIN
core/resources/pix/icons/pencil.png
Normal file
BIN
core/resources/pix/icons/pencil.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 713 B |
BIN
core/resources/pix/icons/up.png
Normal file
BIN
core/resources/pix/icons/up.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 906 B |
@ -13,6 +13,7 @@ import net.sf.openrocket.masscalc.MassCalculator;
|
||||
import net.sf.openrocket.rocketcomponent.Configuration;
|
||||
import net.sf.openrocket.rocketcomponent.Rocket;
|
||||
import net.sf.openrocket.simulation.BasicEventSimulationEngine;
|
||||
import net.sf.openrocket.simulation.CustomExpression;
|
||||
import net.sf.openrocket.simulation.FlightData;
|
||||
import net.sf.openrocket.simulation.RK4SimulationStepper;
|
||||
import net.sf.openrocket.simulation.SimulationConditions;
|
||||
@ -70,13 +71,12 @@ public class Simulation implements ChangeSource, Cloneable {
|
||||
private SimulationOptions options;
|
||||
|
||||
private ArrayList<String> simulationListeners = new ArrayList<String>();
|
||||
private ArrayList<CustomExpression> customExpressions = new ArrayList<CustomExpression>();
|
||||
|
||||
private final Class<? extends SimulationEngine> simulationEngineClass = BasicEventSimulationEngine.class;
|
||||
private Class<? extends SimulationStepper> simulationStepperClass = RK4SimulationStepper.class;
|
||||
private Class<? extends AerodynamicCalculator> aerodynamicCalculatorClass = BarrowmanCalculator.class;
|
||||
private Class<? extends MassCalculator> massCalculatorClass = BasicMassCalculator.class;
|
||||
|
||||
|
||||
|
||||
/** Listeners for this object */
|
||||
private List<EventListener> listeners = new ArrayList<EventListener>();
|
||||
@ -148,6 +148,20 @@ public class Simulation implements ChangeSource, Cloneable {
|
||||
|
||||
}
|
||||
|
||||
public void addCustomExpression(CustomExpression expression){
|
||||
this.status = Simulation.Status.OUTDATED;
|
||||
log.debug("Simulation must be run again to update custom expression.");
|
||||
customExpressions.add(expression);
|
||||
}
|
||||
|
||||
public void removeCustomExpression(CustomExpression expression){
|
||||
customExpressions.remove(expression);
|
||||
}
|
||||
|
||||
public ArrayList<CustomExpression> getCustomExpressions(){
|
||||
return customExpressions;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the rocket associated with this simulation.
|
||||
@ -280,6 +294,7 @@ public class Simulation implements ChangeSource, Cloneable {
|
||||
}
|
||||
|
||||
SimulationConditions simulationConditions = options.toSimulationConditions();
|
||||
simulationConditions.setSimulation(this);
|
||||
for (SimulationListener l : additionalListeners) {
|
||||
simulationConditions.getSimulationListenerList().add(l);
|
||||
}
|
||||
|
||||
@ -24,6 +24,7 @@ import net.sf.openrocket.rocketcomponent.RecoveryDevice.DeployEvent;
|
||||
import net.sf.openrocket.rocketcomponent.Rocket;
|
||||
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
||||
import net.sf.openrocket.rocketcomponent.TubeCoupler;
|
||||
import net.sf.openrocket.simulation.CustomExpression;
|
||||
import net.sf.openrocket.simulation.FlightData;
|
||||
import net.sf.openrocket.simulation.FlightDataBranch;
|
||||
import net.sf.openrocket.simulation.FlightDataType;
|
||||
@ -322,10 +323,25 @@ public class OpenRocketSaver extends RocketSaver {
|
||||
|
||||
writeln("<name>" + escapeXML(simulation.getName()) + "</name>");
|
||||
// TODO: MEDIUM: Other simulators/calculators
|
||||
|
||||
writeln("<simulator>RK4Simulator</simulator>");
|
||||
writeln("<calculator>BarrowmanCalculator</calculator>");
|
||||
writeln("<conditions>");
|
||||
indent++;
|
||||
|
||||
// Write out custom expressions
|
||||
if (!simulation.getCustomExpressions().isEmpty()){
|
||||
writeln("<customexpressions>"); indent++;
|
||||
for (CustomExpression expression : simulation.getCustomExpressions()){
|
||||
writeln("<expression>"); indent++;
|
||||
writeElement("name", expression.getName());
|
||||
writeElement("symbol", expression.getSymbol());
|
||||
writeElement("unit", expression.getUnit());
|
||||
writeElement("expressionstring", expression.getExpressionString());
|
||||
indent--; writeln("</expression>");
|
||||
}
|
||||
indent--; writeln("</customexpressions>");
|
||||
}
|
||||
|
||||
writeln("<conditions>"); indent++;
|
||||
|
||||
writeElement("configid", cond.getMotorConfigurationID());
|
||||
writeElement("launchrodlength", cond.getLaunchRodLength());
|
||||
@ -359,7 +375,6 @@ public class OpenRocketSaver extends RocketSaver {
|
||||
writeElement("listener", escapeXML(s));
|
||||
}
|
||||
|
||||
|
||||
// Write basic simulation data
|
||||
|
||||
FlightData data = simulation.getSimulatedData();
|
||||
|
||||
@ -67,6 +67,7 @@ import net.sf.openrocket.rocketcomponent.ThicknessRingComponent;
|
||||
import net.sf.openrocket.rocketcomponent.Transition;
|
||||
import net.sf.openrocket.rocketcomponent.TrapezoidFinSet;
|
||||
import net.sf.openrocket.rocketcomponent.TubeCoupler;
|
||||
import net.sf.openrocket.simulation.CustomExpression;
|
||||
import net.sf.openrocket.simulation.FlightData;
|
||||
import net.sf.openrocket.simulation.FlightDataBranch;
|
||||
import net.sf.openrocket.simulation.FlightDataType;
|
||||
@ -1201,6 +1202,8 @@ class SimulationsHandler extends AbstractElementHandler {
|
||||
}
|
||||
|
||||
class SingleSimulationHandler extends AbstractElementHandler {
|
||||
private static final LogHelper log = Application.getLogger();
|
||||
|
||||
private final DocumentLoadingContext context;
|
||||
|
||||
private final OpenRocketDocument doc;
|
||||
@ -1209,7 +1212,9 @@ class SingleSimulationHandler extends AbstractElementHandler {
|
||||
|
||||
private SimulationConditionsHandler conditionHandler;
|
||||
private FlightDataHandler dataHandler;
|
||||
|
||||
private CustomExpressionsHandler customExpressionsHandler;
|
||||
|
||||
private ArrayList<CustomExpression> customExpressions = new ArrayList<CustomExpression>();
|
||||
private final List<String> listeners = new ArrayList<String>();
|
||||
|
||||
public SingleSimulationHandler(OpenRocketDocument doc, DocumentLoadingContext context) {
|
||||
@ -1217,7 +1222,9 @@ class SingleSimulationHandler extends AbstractElementHandler {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
|
||||
public void setCustomExpressions(ArrayList<CustomExpression> expressions){
|
||||
this.customExpressions = expressions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElementHandler openElement(String element, HashMap<String, String> attributes,
|
||||
@ -1226,6 +1233,9 @@ class SingleSimulationHandler extends AbstractElementHandler {
|
||||
if (element.equals("name") || element.equals("simulator") ||
|
||||
element.equals("calculator") || element.equals("listener")) {
|
||||
return PlainTextHandler.INSTANCE;
|
||||
} else if (element.equals("customexpressions")) {
|
||||
customExpressionsHandler = new CustomExpressionsHandler(this, context);
|
||||
return customExpressionsHandler;
|
||||
} else if (element.equals("conditions")) {
|
||||
conditionHandler = new SimulationConditionsHandler(doc.getRocket(), context);
|
||||
return conditionHandler;
|
||||
@ -1288,13 +1298,70 @@ class SingleSimulationHandler extends AbstractElementHandler {
|
||||
|
||||
Simulation simulation = new Simulation(doc.getRocket(), status, name,
|
||||
conditions, listeners, data);
|
||||
|
||||
|
||||
// Note : arraylist implementation in simulation different from standard one
|
||||
for (CustomExpression exp : customExpressions){
|
||||
exp.setSimulation(simulation);
|
||||
if (exp.checkAll())
|
||||
simulation.addCustomExpression(exp);
|
||||
}
|
||||
|
||||
doc.addSimulation(simulation);
|
||||
}
|
||||
}
|
||||
|
||||
class CustomExpressionsHandler extends AbstractElementHandler {
|
||||
private final DocumentLoadingContext context;
|
||||
private final SingleSimulationHandler simHandler;
|
||||
public CustomExpression currentExpression = new CustomExpression();
|
||||
private final ArrayList<CustomExpression> customExpressions = new ArrayList<CustomExpression>();
|
||||
|
||||
|
||||
public CustomExpressionsHandler(SingleSimulationHandler simHandler, DocumentLoadingContext context) {
|
||||
this.context = context;
|
||||
this.simHandler = simHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElementHandler openElement(String element,
|
||||
HashMap<String, String> attributes, WarningSet warnings)
|
||||
throws SAXException {
|
||||
|
||||
if (element.equals("expression")){
|
||||
currentExpression = new CustomExpression();
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeElement(String element, HashMap<String, String> attributes,
|
||||
String content, WarningSet warnings) {
|
||||
|
||||
if (element.equals("expression"))
|
||||
customExpressions.add(currentExpression);
|
||||
|
||||
if (element.equals("name"))
|
||||
currentExpression.setName(content);
|
||||
|
||||
else if (element.equals("symbol"))
|
||||
currentExpression.setSymbol(content);
|
||||
|
||||
else if (element.equals("unit"))
|
||||
currentExpression.setUnit(content);
|
||||
|
||||
else if (element.equals("expressionstring"))
|
||||
currentExpression.setExpression(content);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endHandler(String element, HashMap<String, String> attributes,
|
||||
String content, WarningSet warnings) {
|
||||
simHandler.setCustomExpressions(customExpressions);
|
||||
}
|
||||
}
|
||||
|
||||
class SimulationConditionsHandler extends AbstractElementHandler {
|
||||
private final DocumentLoadingContext context;
|
||||
private SimulationOptions conditions;
|
||||
@ -1605,7 +1672,8 @@ class FlightDataBranchHandler extends AbstractElementHandler {
|
||||
String[] split = typeList.split(",");
|
||||
types = new FlightDataType[split.length];
|
||||
for (int i = 0; i < split.length; i++) {
|
||||
types[i] = FlightDataType.getType(split[i], UnitGroup.UNITS_NONE);
|
||||
types[i] = FlightDataType.getType(split[i], "None ("+split[i]+")", UnitGroup.UNITS_NONE);
|
||||
// TODO: HIGH: Deal with symbols
|
||||
}
|
||||
|
||||
// TODO: LOW: May throw an IllegalArgumentException
|
||||
|
||||
@ -0,0 +1,195 @@
|
||||
package net.sf.openrocket.gui.customexpression;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Window;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import net.sf.openrocket.document.Simulation;
|
||||
import net.sf.openrocket.gui.components.DescriptionArea;
|
||||
import net.sf.openrocket.gui.components.UnitSelector;
|
||||
import net.sf.openrocket.gui.customexpression.ExpressionBuilderDialog;
|
||||
import net.sf.openrocket.gui.util.Icons;
|
||||
import net.sf.openrocket.l10n.Translator;
|
||||
import net.sf.openrocket.logging.LogHelper;
|
||||
import net.sf.openrocket.simulation.CustomExpression;
|
||||
import net.sf.openrocket.startup.Application;
|
||||
|
||||
public class CustomExpressionPanel extends JPanel {
|
||||
|
||||
private static final LogHelper log = Application.getLogger();
|
||||
private static final Translator trans = Application.getTranslator();
|
||||
|
||||
private JPanel expressionSelectorPanel;
|
||||
private Simulation simulation;
|
||||
|
||||
public CustomExpressionPanel(final Simulation simulation) {
|
||||
super(new MigLayout("fill"));
|
||||
this.simulation = simulation;
|
||||
|
||||
expressionSelectorPanel = new JPanel(new MigLayout("gapy rel"));
|
||||
JScrollPane scroll = new JScrollPane(expressionSelectorPanel);
|
||||
this.add(scroll, "spany 2, height 10px, wmin 400lp, grow 100, gapright para");
|
||||
|
||||
DescriptionArea desc = new DescriptionArea(trans.get("customExpressionPanel.lbl.UpdateNote")+"\n\n"+trans.get("customExpressionPanel.lbl.CalcNote"), 8, -2f);
|
||||
desc.setViewportBorder(BorderFactory.createEmptyBorder());
|
||||
this.add(desc, "width 1px, growx 1, wrap unrel");
|
||||
|
||||
//// New expression
|
||||
JButton button = new JButton(trans.get("customExpressionPanel.but.NewExpression"));
|
||||
button.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
// Open window to configure expression
|
||||
log.debug("Opening window to configure new expression");
|
||||
Window parent = SwingUtilities.getWindowAncestor(CustomExpressionPanel.this);
|
||||
new ExpressionBuilderDialog(parent, simulation).setVisible(true);
|
||||
updateExpressions();
|
||||
}
|
||||
});
|
||||
|
||||
this.add(button, "left");
|
||||
|
||||
updateExpressions();
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the expressionSelectorPanel
|
||||
*/
|
||||
private void updateExpressions(){
|
||||
|
||||
expressionSelectorPanel.removeAll();
|
||||
for (CustomExpression expression : simulation.getCustomExpressions()){
|
||||
SingleExpression se = new SingleExpression(expression);
|
||||
expressionSelectorPanel.add(se, "wrap");
|
||||
}
|
||||
|
||||
//TODO: High : Find out why repaint method not working properly here.
|
||||
//expressionSelectorPanel.repaint();
|
||||
expressionSelectorPanel.updateUI(); // Not the correct method to use but works
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void deleteExpression(CustomExpression expression){
|
||||
simulation.getCustomExpressions().remove(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves an expression up or down in the expression list
|
||||
* @param expression
|
||||
* @param move integer - +1 to move down, -1 to move up
|
||||
*/
|
||||
private void moveExpression(CustomExpression expression, int move){
|
||||
ArrayList<CustomExpression> expressions = simulation.getCustomExpressions();
|
||||
int i = expressions.indexOf(expression);
|
||||
if (i+move == expressions.size() || i+move < 0)
|
||||
return;
|
||||
else
|
||||
Collections.swap(expressions, i, i+move);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* A JPanel which configures a single expression
|
||||
*/
|
||||
private class SingleExpression extends JPanel {
|
||||
|
||||
// Convenience method to make the labels consistent
|
||||
private JLabel setLabelStyle(JLabel l){
|
||||
l.setBackground(Color.WHITE);
|
||||
l.setOpaque(true);
|
||||
l.setBorder(BorderFactory.createRaisedBevelBorder() );
|
||||
l.setText(" " + l.getText() + " ");
|
||||
return l;
|
||||
}
|
||||
|
||||
private SingleExpression(final CustomExpression expression) {
|
||||
super(new MigLayout("ins 0"));
|
||||
// name: aName symbol: a Unit: m/s
|
||||
//super(new MigLayout("","[::100][:200:400][::100][:100:200][::100][:100:200]",""));
|
||||
|
||||
JLabel nameLabel = new JLabel( trans.get("customExpression.Name")+ " :");
|
||||
JLabel name = new JLabel ( expression.getName() );
|
||||
name = setLabelStyle(name);
|
||||
JLabel symbolLabel = new JLabel( trans.get("customExpression.Symbol")+ " :" );
|
||||
JLabel symbol = new JLabel ( expression.getSymbol());
|
||||
symbol = setLabelStyle(symbol);
|
||||
symbol.setBackground(Color.WHITE);
|
||||
|
||||
JLabel unitLabel = new JLabel( trans.get("customExpression.Units")+ " :");
|
||||
UnitSelector unitSelector = new UnitSelector(expression.getType().getUnitGroup());
|
||||
|
||||
JButton editButton = new JButton(Icons.EDIT);
|
||||
editButton.setToolTipText(trans.get("customExpression.Units.but.ttip.Edit"));
|
||||
editButton.setBorderPainted(false);
|
||||
editButton.addActionListener( new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e){
|
||||
Window parent = SwingUtilities.getWindowAncestor(CustomExpressionPanel.this);
|
||||
expression.editExpression(parent);
|
||||
updateExpressions();
|
||||
}
|
||||
});
|
||||
|
||||
JButton upButton = new JButton(Icons.UP);
|
||||
upButton.setToolTipText(trans.get("customExpression.Units.but.ttip.MoveUp"));
|
||||
upButton.setBorderPainted(false);
|
||||
upButton.addActionListener( new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
moveExpression(expression, -1);
|
||||
updateExpressions();
|
||||
}
|
||||
});
|
||||
|
||||
JButton downButton = new JButton(Icons.DOWN);
|
||||
downButton.setToolTipText(trans.get("customExpression.Units.but.ttip.MoveDown"));
|
||||
downButton.setBorderPainted(false);
|
||||
downButton.addActionListener( new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
moveExpression(expression, 1);
|
||||
updateExpressions();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
JButton deleteButton = new JButton(Icons.DELETE);
|
||||
//// Remove this expression
|
||||
deleteButton.setToolTipText(trans.get("customExpression.Units.but.ttip.Remove"));
|
||||
deleteButton.setBorderPainted(false);
|
||||
deleteButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
deleteExpression(expression);
|
||||
updateExpressions();
|
||||
}
|
||||
});
|
||||
|
||||
this.add(nameLabel);
|
||||
this.add(name, "width 200:200:400, growx");
|
||||
this.add(new JPanel());
|
||||
this.add(symbolLabel);
|
||||
this.add(symbol, "width :50:200");
|
||||
this.add(new JPanel());
|
||||
this.add(unitLabel);
|
||||
this.add(unitSelector, "width :50:100");
|
||||
this.add(new JPanel(), "growx");
|
||||
this.add(upButton, "right");
|
||||
this.add(downButton, "right");
|
||||
this.add(editButton, "right");
|
||||
this.add(deleteButton, "right");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,266 @@
|
||||
package net.sf.openrocket.gui.customexpression;
|
||||
|
||||
import java.awt.Window;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.FocusListener;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.KeyListener;
|
||||
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import net.sf.openrocket.document.Simulation;
|
||||
import net.sf.openrocket.gui.util.Icons;
|
||||
import net.sf.openrocket.l10n.Translator;
|
||||
import net.sf.openrocket.logging.LogHelper;
|
||||
import net.sf.openrocket.simulation.CustomExpression;
|
||||
import net.sf.openrocket.startup.Application;
|
||||
|
||||
/**
|
||||
* Dialog box for making a custom expression
|
||||
* @author Richard Graham
|
||||
*
|
||||
*/
|
||||
|
||||
public class ExpressionBuilderDialog extends JDialog {
|
||||
|
||||
private static final Translator trans = Application.getTranslator();
|
||||
private static final LogHelper log = Application.getLogger();
|
||||
|
||||
private static final ImageIcon GreenIcon = Icons.loadImageIcon("pix/spheres/green-16x16.png", "OK");
|
||||
private static final ImageIcon RedIcon = Icons.loadImageIcon("pix/spheres/red-16x16.png", "Bad");
|
||||
|
||||
private CustomExpression expression;
|
||||
private CustomExpression previousExpressionCopy;
|
||||
|
||||
private final Window parentWindow;
|
||||
private final Simulation simulation;
|
||||
|
||||
// Define these check indicators to show if fields are OK
|
||||
private final JLabel nameCheck = new JLabel(RedIcon);
|
||||
private final JLabel expressionCheck = new JLabel(RedIcon);
|
||||
private final JLabel unitCheck = new JLabel(RedIcon);
|
||||
private final JButton okButton = new JButton(trans.get("dlg.but.ok"));
|
||||
private final JTextField expressionField = new JTextField(20);
|
||||
|
||||
public ExpressionBuilderDialog(Window parent, Simulation simulation){
|
||||
this(parent, simulation, new CustomExpression(simulation));
|
||||
}
|
||||
|
||||
public ExpressionBuilderDialog(Window parent, final Simulation simulation, final CustomExpression previousExpression){
|
||||
|
||||
super(parent, trans.get("ExpressionBuilderDialog.title"), JDialog.ModalityType.DOCUMENT_MODAL);
|
||||
|
||||
this.parentWindow = parent;
|
||||
this.simulation = simulation;
|
||||
this.previousExpressionCopy = (CustomExpression) previousExpression.clone();
|
||||
this.expression = previousExpression;
|
||||
|
||||
//// Name box -- Check input when focus changes and transfer focus to next box on enter key
|
||||
JLabel nameLabel = new JLabel(trans.get("customExpression.Name"));
|
||||
final JTextField nameField = new JTextField(20);
|
||||
nameField.setText(expression.getName());
|
||||
nameField.setFocusTraversalKeysEnabled(true);
|
||||
nameField.addFocusListener(new FocusListener() {
|
||||
@Override
|
||||
public void focusGained(FocusEvent e) { }
|
||||
|
||||
@Override
|
||||
public void focusLost(FocusEvent e) {
|
||||
expression.setName(nameField.getText());
|
||||
ExpressionBuilderDialog.this.updateOK();
|
||||
}
|
||||
});
|
||||
nameField.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent arg0) {
|
||||
nameField.transferFocus();
|
||||
}
|
||||
});
|
||||
|
||||
//// Expression box -- for this one we check after each keypress using a keyListener. Enter transfers to next field
|
||||
JLabel expressionLabel = new JLabel(trans.get("customExpression.Expression"));
|
||||
expressionField.setText(expression.getExpressionString());
|
||||
expressionField.addKeyListener(new KeyListener() {
|
||||
@Override
|
||||
public void keyReleased(KeyEvent arg0) {
|
||||
expression.setExpression( expressionField.getText() );
|
||||
ExpressionBuilderDialog.this.updateOK();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {}
|
||||
|
||||
@Override
|
||||
public void keyTyped(KeyEvent e) {}
|
||||
});
|
||||
expressionField.addActionListener(new ActionListener(){
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
expressionField.transferFocus();
|
||||
}
|
||||
});
|
||||
|
||||
//// Units box -- with action listeners checking input after change in focus or enter press
|
||||
JLabel unitLabel = new JLabel(trans.get("customExpression.Units"));
|
||||
final JTextField unitField = new JTextField(5);
|
||||
unitField.setText(expression.getUnit());
|
||||
unitField.addFocusListener(new FocusListener(){
|
||||
@Override
|
||||
public void focusLost(FocusEvent arg0) {
|
||||
expression.setUnit(unitField.getText()) ;
|
||||
ExpressionBuilderDialog.this.updateOK();
|
||||
}
|
||||
@Override
|
||||
public void focusGained(FocusEvent arg0) {}
|
||||
});
|
||||
unitField.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
unitField.transferFocus();
|
||||
}
|
||||
});
|
||||
|
||||
//// Symbol box
|
||||
JLabel symbolLabel = new JLabel(trans.get("customExpression.Symbol"));
|
||||
final JTextField symbolField = new JTextField(5);
|
||||
symbolField.setText(expression.getSymbol());
|
||||
symbolField.addFocusListener(new FocusListener(){
|
||||
@Override
|
||||
public void focusLost(FocusEvent arg0) {
|
||||
expression.setSymbol(symbolField.getText()) ;
|
||||
ExpressionBuilderDialog.this.updateOK();
|
||||
}
|
||||
@Override
|
||||
public void focusGained(FocusEvent arg0) {}
|
||||
});
|
||||
symbolField.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
symbolField.transferFocus();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
//// Insert variable button
|
||||
final JButton insertVariableButton = new JButton(trans.get("ExpressionBuilderDialog.InsertVariable"));
|
||||
insertVariableButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
log.debug("Opening insert variable window");
|
||||
Window parentWindow = SwingUtilities.getWindowAncestor(ExpressionBuilderDialog.this);
|
||||
new VariableSelector(parentWindow, ExpressionBuilderDialog.this, simulation).setVisible(true);
|
||||
}
|
||||
});
|
||||
|
||||
//// Insert operator button
|
||||
final JButton insertOperatorButton = new JButton(trans.get("ExpressionBuilderDialog.InsertOperator"));
|
||||
insertOperatorButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
log.debug("Opening insert operator window");
|
||||
Window parentWindow = SwingUtilities.getWindowAncestor(ExpressionBuilderDialog.this);
|
||||
new OperatorSelector(parentWindow, ExpressionBuilderDialog.this).setVisible(true);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
//// OK Button
|
||||
okButton.setEnabled(false);
|
||||
okButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
expression.addToSimulation();
|
||||
ExpressionBuilderDialog.this.dispose();
|
||||
}
|
||||
});
|
||||
|
||||
//// Cancel button
|
||||
final JButton cancelButton = new JButton(trans.get("dlg.but.cancel"));
|
||||
cancelButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
expression.overwrite(previousExpressionCopy);
|
||||
ExpressionBuilderDialog.this.dispose();
|
||||
}
|
||||
});
|
||||
|
||||
//// Set to tips
|
||||
nameCheck.setToolTipText(trans.get("ExpressionBuilderDialog.led.ttip.Name"));
|
||||
unitCheck.setToolTipText(trans.get("ExpressionBuilderDialog.led.ttip.Symbol"));
|
||||
expressionCheck.setToolTipText(trans.get("ExpressionBuilderDialog.led.ttip.Expression"));
|
||||
|
||||
//// Do the layout
|
||||
JPanel mainPanel = new JPanel(new MigLayout());
|
||||
mainPanel.add(nameLabel);
|
||||
mainPanel.add(nameField);
|
||||
mainPanel.add(nameCheck, "wrap, center");
|
||||
mainPanel.add(symbolLabel);
|
||||
mainPanel.add(symbolField, "split 4, growx");
|
||||
mainPanel.add(new JPanel());
|
||||
mainPanel.add(unitLabel, "right");
|
||||
mainPanel.add(unitField, "right, growx");
|
||||
mainPanel.add(unitCheck, "wrap, center");
|
||||
mainPanel.add(expressionLabel);
|
||||
mainPanel.add(expressionField);
|
||||
mainPanel.add(expressionCheck, "wrap, center");
|
||||
mainPanel.add(insertOperatorButton, "span 2, right, split 2");
|
||||
mainPanel.add(insertVariableButton, "right, wrap");
|
||||
mainPanel.add(cancelButton, "span 2, right, width :50:100");
|
||||
mainPanel.add(okButton, "right, width :50:100, wrap");
|
||||
|
||||
this.add(mainPanel);
|
||||
this.validate();
|
||||
this.pack();
|
||||
this.setLocationByPlatform(true);
|
||||
this.updateOK();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable OK button only if all the fields are ok
|
||||
* @param okButton
|
||||
*/
|
||||
protected void updateOK() {
|
||||
|
||||
boolean nameOK = expression.checkName();
|
||||
boolean unitOK = expression.checkUnit();
|
||||
boolean symbolOK = expression.checkSymbol();
|
||||
boolean expressionOK = expression.checkExpression();
|
||||
|
||||
if (nameOK) { nameCheck.setIcon(GreenIcon); } else { nameCheck.setIcon(RedIcon); }
|
||||
if (unitOK && symbolOK) { unitCheck.setIcon(GreenIcon); } else { unitCheck.setIcon(RedIcon); }
|
||||
if (expressionOK) { expressionCheck.setIcon(GreenIcon); } else { expressionCheck.setIcon(RedIcon); }
|
||||
|
||||
okButton.setEnabled( nameOK && unitOK && symbolOK && expressionOK );
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a string into the expression box at the position of the cursor.
|
||||
* String will be padded with spaces either side
|
||||
* Expression box will be focused after this is called.
|
||||
* For strings containing an ( , cursor will be moved to the point after that, otherwise, cursor will move to the end of the inserted string.
|
||||
* @param str
|
||||
*/
|
||||
public void pasteIntoExpression(String str) {
|
||||
int pos = expressionField.getCaretPosition();
|
||||
String current = expressionField.getText();
|
||||
expressionField.setText(current.subSequence(0, pos) + " " + str + " " + current.subSequence(pos, current.length()));
|
||||
expressionField.requestFocus();
|
||||
int bracketPos = str.indexOf("(");
|
||||
if (bracketPos != -1){
|
||||
expressionField.setCaretPosition(pos+2+bracketPos);
|
||||
}
|
||||
else {
|
||||
expressionField.setCaretPosition(pos+2+str.length());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,90 @@
|
||||
package net.sf.openrocket.gui.customexpression;
|
||||
|
||||
import java.awt.Window;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTable;
|
||||
import javax.swing.event.ListSelectionEvent;
|
||||
import javax.swing.event.ListSelectionListener;
|
||||
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import net.sf.openrocket.l10n.Translator;
|
||||
import net.sf.openrocket.logging.LogHelper;
|
||||
import net.sf.openrocket.startup.Application;
|
||||
|
||||
public class OperatorSelector extends JDialog {
|
||||
|
||||
private static final Translator trans = Application.getTranslator();
|
||||
private static final LogHelper log = Application.getLogger();
|
||||
|
||||
private final Window parentWindow;
|
||||
|
||||
public OperatorSelector(Window parent, final ExpressionBuilderDialog parentBuilder){
|
||||
|
||||
super(parent, trans.get("CustomOperatorSelector.title"), JDialog.ModalityType.DOCUMENT_MODAL);
|
||||
|
||||
this.parentWindow = parent;
|
||||
|
||||
final JButton insertButton = new JButton(trans.get("ExpressionBuilderDialog.InsertOperator"));
|
||||
|
||||
JPanel mainPanel = new JPanel(new MigLayout());
|
||||
|
||||
//// Table of variables and model
|
||||
final OperatorTableModel tableModel = new OperatorTableModel();
|
||||
final JTable table = new JTable(tableModel);
|
||||
|
||||
table.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
|
||||
int width = table.getColumnModel().getTotalColumnWidth();
|
||||
table.getColumnModel().getColumn(0).setPreferredWidth( (int) (.2 * width));
|
||||
table.getColumnModel().getColumn(1).setPreferredWidth( (int) (.8 * width));
|
||||
|
||||
JScrollPane scrollPane = new JScrollPane(table);
|
||||
table.setFillsViewportHeight(true);
|
||||
table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
|
||||
@Override
|
||||
public void valueChanged(ListSelectionEvent e){
|
||||
if (table.getSelectedRowCount() == 1){
|
||||
insertButton.setEnabled(true);
|
||||
}
|
||||
else {
|
||||
insertButton.setEnabled(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
mainPanel.add(scrollPane, "wrap");
|
||||
|
||||
//// Cancel button
|
||||
final JButton cancelButton = new JButton(trans.get("dlg.but.cancel"));
|
||||
cancelButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
OperatorSelector.this.dispose();
|
||||
}
|
||||
});
|
||||
mainPanel.add(cancelButton, "right, width :100:200, split 2");
|
||||
|
||||
//// Insert button
|
||||
insertButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
int row = table.getSelectedRow();
|
||||
String str = tableModel.getOperatorAt(row);
|
||||
parentBuilder.pasteIntoExpression(str);
|
||||
OperatorSelector.this.dispose();
|
||||
}
|
||||
});
|
||||
insertButton.setEnabled(false); // disabled by default, only enable when a variable selected
|
||||
mainPanel.add(insertButton, "right, width :100:200, wrap");
|
||||
|
||||
this.add(mainPanel);
|
||||
this.validate();
|
||||
this.pack();
|
||||
this.setLocationByPlatform(true);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
package net.sf.openrocket.gui.customexpression;
|
||||
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
|
||||
import net.sf.openrocket.l10n.Translator;
|
||||
import net.sf.openrocket.simulation.CustomExpression;
|
||||
import net.sf.openrocket.startup.Application;
|
||||
|
||||
public class OperatorTableModel extends AbstractTableModel {
|
||||
|
||||
private static final Translator trans = Application.getTranslator();
|
||||
|
||||
private static final String[] columnNames = {trans.get("customExpression.Operator"), trans.get("customExpression.Description")};
|
||||
|
||||
private final Object[] operators = CustomExpression.AVAILABLE_OPERATORS.keySet().toArray();
|
||||
private final Object[] descriptions = CustomExpression.AVAILABLE_OPERATORS.values().toArray();
|
||||
|
||||
public OperatorTableModel(){
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnCount() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRowCount() {
|
||||
return CustomExpression.AVAILABLE_OPERATORS.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValueAt(int row, int col) {
|
||||
if (col == 0){
|
||||
return operators[row].toString();
|
||||
}
|
||||
else if (col == 1){
|
||||
return descriptions[row].toString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getColumnName(int col) {
|
||||
return columnNames[col];
|
||||
}
|
||||
|
||||
public String getOperatorAt(int row) {
|
||||
return operators[row].toString();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,100 @@
|
||||
package net.sf.openrocket.gui.customexpression;
|
||||
|
||||
import java.awt.Window;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTable;
|
||||
import javax.swing.event.ListSelectionEvent;
|
||||
import javax.swing.event.ListSelectionListener;
|
||||
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import net.sf.openrocket.document.Simulation;
|
||||
import net.sf.openrocket.l10n.Translator;
|
||||
import net.sf.openrocket.logging.LogHelper;
|
||||
import net.sf.openrocket.startup.Application;
|
||||
|
||||
/**
|
||||
* Dialog to select from available custom variables
|
||||
* @author Richard Graham
|
||||
*
|
||||
*/
|
||||
|
||||
public class VariableSelector extends JDialog {
|
||||
|
||||
private static final Translator trans = Application.getTranslator();
|
||||
private static final LogHelper log = Application.getLogger();
|
||||
|
||||
private final Window parentWindow;
|
||||
private final Simulation simulation;
|
||||
|
||||
public VariableSelector(Window parent, final ExpressionBuilderDialog parentBuilder, final Simulation simulation){
|
||||
|
||||
super(parent, trans.get("CustomVariableSelector.title"), JDialog.ModalityType.DOCUMENT_MODAL);
|
||||
|
||||
this.parentWindow = parent;
|
||||
this.simulation = simulation;
|
||||
|
||||
final JButton insertButton = new JButton(trans.get("ExpressionBuilderDialog.InsertVariable"));
|
||||
|
||||
JPanel mainPanel = new JPanel(new MigLayout());
|
||||
|
||||
//// Table of variables and model
|
||||
final VariableTableModel tableModel = new VariableTableModel(simulation);
|
||||
final JTable table = new JTable(tableModel);
|
||||
|
||||
table.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
|
||||
int width = table.getColumnModel().getTotalColumnWidth();
|
||||
table.getColumnModel().getColumn(0).setPreferredWidth( (int) (.7 * width));
|
||||
table.getColumnModel().getColumn(1).setPreferredWidth( (int) (.15 * width));
|
||||
table.getColumnModel().getColumn(2).setPreferredWidth( (int) (.15 * width));
|
||||
|
||||
JScrollPane scrollPane = new JScrollPane(table);
|
||||
table.setFillsViewportHeight(true);
|
||||
table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
|
||||
@Override
|
||||
public void valueChanged(ListSelectionEvent e){
|
||||
if (table.getSelectedRowCount() == 1){
|
||||
insertButton.setEnabled(true);
|
||||
}
|
||||
else {
|
||||
insertButton.setEnabled(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
mainPanel.add(scrollPane, "wrap");
|
||||
|
||||
//// Cancel button
|
||||
final JButton cancelButton = new JButton(trans.get("dlg.but.cancel"));
|
||||
cancelButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
VariableSelector.this.dispose();
|
||||
}
|
||||
});
|
||||
mainPanel.add(cancelButton, "right, width :100:200, split 2");
|
||||
|
||||
//// Insert button
|
||||
insertButton.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
int row = table.getSelectedRow();
|
||||
String str = tableModel.getSymbolAt(row);
|
||||
parentBuilder.pasteIntoExpression(str);
|
||||
VariableSelector.this.dispose();
|
||||
}
|
||||
});
|
||||
insertButton.setEnabled(false); // disabled by default, only enable when a variable selected
|
||||
mainPanel.add(insertButton, "right, width :100:200, wrap");
|
||||
|
||||
this.add(mainPanel);
|
||||
this.validate();
|
||||
this.pack();
|
||||
this.setLocationByPlatform(true);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,77 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package net.sf.openrocket.gui.customexpression;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
|
||||
import net.sf.openrocket.document.Simulation;
|
||||
import net.sf.openrocket.l10n.Translator;
|
||||
import net.sf.openrocket.simulation.CustomExpression;
|
||||
import net.sf.openrocket.simulation.FlightDataType;
|
||||
import net.sf.openrocket.startup.Application;
|
||||
|
||||
/**
|
||||
* @author Richard Graham
|
||||
*
|
||||
*/
|
||||
public class VariableTableModel extends AbstractTableModel {
|
||||
|
||||
private static final Translator trans = Application.getTranslator();
|
||||
|
||||
private ArrayList<FlightDataType> types = new ArrayList<FlightDataType>();
|
||||
private static final String[] columnNames = {trans.get("customExpression.Name"), trans.get("customExpression.Symbol"), trans.get("customExpression.Units")};
|
||||
|
||||
/*
|
||||
* Table model will be constructed with all the built in variables and any custom variables defined
|
||||
*/
|
||||
public VariableTableModel(Simulation sim){
|
||||
|
||||
Collections.addAll(types, FlightDataType.ALL_TYPES);
|
||||
|
||||
for (CustomExpression expression : sim.getCustomExpressions()){
|
||||
types.add(expression.getType());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnCount() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRowCount() {
|
||||
return types.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValueAt(int row, int col) {
|
||||
if (col == 0)
|
||||
return types.get(row).getName();
|
||||
else if (col == 1)
|
||||
return types.get(row).getSymbol();
|
||||
else if (col == 2)
|
||||
return types.get(row).getUnitGroup().getDefaultUnit().toString();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getColumnName(int col) {
|
||||
return columnNames[col];
|
||||
}
|
||||
|
||||
public String getSymbolAt(int row) {
|
||||
if (row < 0 || row > types.size()){
|
||||
return "";
|
||||
}
|
||||
else {
|
||||
return types.get(row).getSymbol();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -41,6 +41,7 @@ import net.sf.openrocket.gui.components.DescriptionArea;
|
||||
import net.sf.openrocket.gui.components.SimulationExportPanel;
|
||||
import net.sf.openrocket.gui.components.UnitSelector;
|
||||
import net.sf.openrocket.gui.plot.Axis;
|
||||
import net.sf.openrocket.gui.customexpression.CustomExpressionPanel;
|
||||
import net.sf.openrocket.gui.plot.PlotConfiguration;
|
||||
import net.sf.openrocket.gui.plot.SimulationPlotPanel;
|
||||
import net.sf.openrocket.gui.util.GUIUtil;
|
||||
@ -77,7 +78,7 @@ public class SimulationEditDialog extends JDialog {
|
||||
|
||||
public static final int DEFAULT = -1;
|
||||
public static final int EDIT = 1;
|
||||
public static final int PLOT = 2;
|
||||
public static final int PLOT = 3;
|
||||
|
||||
|
||||
private final Window parentWindow;
|
||||
@ -138,6 +139,8 @@ public class SimulationEditDialog extends JDialog {
|
||||
tabbedPane.addTab(trans.get("simedtdlg.tab.Launchcond"), flightConditionsTab());
|
||||
//// Simulation options
|
||||
tabbedPane.addTab(trans.get("simedtdlg.tab.Simopt"), simulationOptionsTab());
|
||||
//// Custom expressions tab
|
||||
tabbedPane.addTab(trans.get("simedtdlg.tab.CustomExpressions"), customExpressionsTab());
|
||||
//// Plot data
|
||||
tabbedPane.addTab(trans.get("simedtdlg.tab.Plotdata"), plotTab());
|
||||
//// Export data
|
||||
@ -147,7 +150,7 @@ public class SimulationEditDialog extends JDialog {
|
||||
if (tab == EDIT) {
|
||||
tabbedPane.setSelectedIndex(0);
|
||||
} else if (tab == PLOT) {
|
||||
tabbedPane.setSelectedIndex(2);
|
||||
tabbedPane.setSelectedIndex(3);
|
||||
} else {
|
||||
FlightData data = s.getSimulatedData();
|
||||
if (data == null || data.getBranchCount() == 0)
|
||||
@ -835,7 +838,9 @@ public class SimulationEditDialog extends JDialog {
|
||||
}
|
||||
|
||||
|
||||
|
||||
private JPanel customExpressionsTab() {
|
||||
return new CustomExpressionPanel(simulation);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@ -73,6 +73,10 @@ public class Icons {
|
||||
public static final Icon PREFERENCES = loadImageIcon("pix/icons/preferences.png", "Preferences");
|
||||
|
||||
public static final Icon DELETE = loadImageIcon("pix/icons/delete.png", "Delete");
|
||||
public static final Icon EDIT = loadImageIcon("pix/icons/pencil.png", "Edit");
|
||||
public static final Icon UP = loadImageIcon("pix/icons/up.png", "Up");
|
||||
public static final Icon DOWN = loadImageIcon("pix/icons/down.png", "Down");
|
||||
|
||||
|
||||
static {
|
||||
log.debug("Icons loaded");
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package net.sf.openrocket.simulation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
@ -88,6 +89,12 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
||||
}
|
||||
SimulationListenerHelper.firePostStep(status);
|
||||
|
||||
// Calculate values for custom expressions
|
||||
FlightDataBranch data = status.getFlightData();
|
||||
ArrayList<CustomExpression> allExpressions = status.getSimulationConditions().getSimulation().getCustomExpressions();
|
||||
for (CustomExpression expression : allExpressions ) {
|
||||
data.setValue(expression.getType(), expression.evaluate(status));
|
||||
}
|
||||
|
||||
// Check for NaN values in the simulation status
|
||||
checkNaN();
|
||||
|
||||
317
core/src/net/sf/openrocket/simulation/CustomExpression.java
Normal file
317
core/src/net/sf/openrocket/simulation/CustomExpression.java
Normal file
@ -0,0 +1,317 @@
|
||||
package net.sf.openrocket.simulation;
|
||||
|
||||
import java.awt.Window;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import net.sf.openrocket.document.Simulation;
|
||||
import net.sf.openrocket.gui.customexpression.ExpressionBuilderDialog;
|
||||
import net.sf.openrocket.logging.LogHelper;
|
||||
import net.sf.openrocket.startup.Application;
|
||||
import net.sf.openrocket.unit.FixedUnitGroup;
|
||||
import net.sf.openrocket.unit.UnitGroup;
|
||||
import net.sf.openrocket.util.ArrayList;
|
||||
import de.congrace.exp4j.Calculable;
|
||||
import de.congrace.exp4j.ExpressionBuilder;
|
||||
|
||||
|
||||
/**
|
||||
* Represents a single custom expression
|
||||
* @author Richard Graham
|
||||
*
|
||||
*/
|
||||
public class CustomExpression implements Cloneable{
|
||||
|
||||
private static final LogHelper log = Application.getLogger();
|
||||
|
||||
private String name, symbol, unit, expression;
|
||||
private ExpressionBuilder builder;
|
||||
private static Simulation sim = null;
|
||||
|
||||
// A map of available operator strings (keys) and description of function (value)
|
||||
public static final SortedMap<String, String> AVAILABLE_OPERATORS = new TreeMap<String, String>() {{
|
||||
put("+" , "Addition");
|
||||
put("-" , "Subtraction");
|
||||
put("*" , "Multiplication");
|
||||
put("/" , "Divison");
|
||||
put("%" , "Modulo");
|
||||
put("^" , "Exponentiation");
|
||||
put("abs()" , "Absolute value");
|
||||
put("ceil()" , "Ceiling (next integer value");
|
||||
put("floor()" , "Floor (previous integer value");
|
||||
put("sqrt()" , "Square root");
|
||||
put("cbrt()" , "Cubic root");
|
||||
put("exp()" , "Euler\'s number raised to the value (e^x)");
|
||||
put("log()" , "Natural logarithm");
|
||||
put("sin()" , "Sine");
|
||||
put("cos()" , "Cosine");
|
||||
put("tan()" , "Tangent");
|
||||
put("asin()" , "Arc sine");
|
||||
put("acos()" , "Arc cosine");
|
||||
put("atan()" , "Arc tangent");
|
||||
put("sinh()" , "Hyerbolic sine");
|
||||
put("cosh()" , "Hyperbolic cosine");
|
||||
put("tanh()" , "Hyperbolic tangent");
|
||||
}};
|
||||
|
||||
|
||||
public CustomExpression(){
|
||||
setName("");
|
||||
setSymbol("");
|
||||
setUnit("");
|
||||
setExpression("");
|
||||
}
|
||||
|
||||
public CustomExpression(Simulation sim){
|
||||
this();
|
||||
setSimulation(sim);
|
||||
}
|
||||
|
||||
public CustomExpression(Simulation sim, String name, String symbol, String unit, String expression) {
|
||||
|
||||
setName(name);
|
||||
setSymbol(symbol);
|
||||
setUnit(unit);
|
||||
setExpression(expression);
|
||||
setSimulation(sim);
|
||||
}
|
||||
|
||||
/*
|
||||
* Opens an ExpressionBuilderDialog for this expression
|
||||
*/
|
||||
public void editExpression(Window parent){
|
||||
log.debug("Opening window to edit an existing custom expression");
|
||||
new ExpressionBuilderDialog(parent, sim, this).setVisible(true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Use this to update the simulation this is associated with
|
||||
*/
|
||||
public void setSimulation(Simulation sim){
|
||||
CustomExpression.sim = sim;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the flight data branch 0 for this simulation, or an empty branch
|
||||
* if no simulated data exists
|
||||
*/
|
||||
private FlightDataBranch getBranch() {
|
||||
if ( sim == null || sim.getSimulatedData().getBranch(0) == null) {
|
||||
return new FlightDataBranch();
|
||||
}
|
||||
else {
|
||||
return sim.getSimulatedData().getBranch(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void setName(String name){
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setUnit(String unit){
|
||||
this.unit = unit;
|
||||
}
|
||||
|
||||
public void setSymbol(String symbol){
|
||||
this.symbol = symbol;
|
||||
}
|
||||
|
||||
public void setExpression(String expression){
|
||||
this.expression = expression;
|
||||
builder = new ExpressionBuilder(expression);
|
||||
}
|
||||
|
||||
// get a list of all the names of all the available variables
|
||||
private ArrayList<String> getAllNames(){
|
||||
ArrayList<String> names = new ArrayList<String>();
|
||||
for (FlightDataType type : FlightDataType.ALL_TYPES)
|
||||
names.add(type.getName());
|
||||
for (CustomExpression exp : sim.getCustomExpressions() ){
|
||||
if (exp != this)
|
||||
names.add(exp.getName());
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
// get a list of all the symbols of the available variables ignoring this one
|
||||
private ArrayList<String> getAllSymbols(){
|
||||
ArrayList<String> symbols = new ArrayList<String>();
|
||||
for (FlightDataType type : FlightDataType.ALL_TYPES)
|
||||
symbols.add(type.getSymbol());
|
||||
for (CustomExpression exp : sim.getCustomExpressions() ){
|
||||
if (exp != this)
|
||||
symbols.add(exp.getSymbol());
|
||||
}
|
||||
return symbols;
|
||||
}
|
||||
|
||||
public boolean checkSymbol(){
|
||||
if (symbol.trim().isEmpty())
|
||||
return false;
|
||||
|
||||
// No bad characters
|
||||
for (char c : "0123456789.()[]{}".toCharArray())
|
||||
if (symbol.indexOf(c) != -1 )
|
||||
return false;
|
||||
|
||||
// No operators (ignoring brackets)
|
||||
for (String s : CustomExpression.AVAILABLE_OPERATORS.keySet()){
|
||||
if (symbol.contains(s.replaceAll("\\(|\\)", "")))
|
||||
return false;
|
||||
}
|
||||
|
||||
// No already defined symbols
|
||||
ArrayList<String> symbols = getAllSymbols().clone();
|
||||
if (symbols.contains(symbol.trim())){
|
||||
int index = symbols.indexOf(symbol.trim());
|
||||
log.user("Symbol "+symbol+" already exists, found "+symbols.get(index));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean checkName(){
|
||||
if (name.trim().isEmpty())
|
||||
return false;
|
||||
|
||||
ArrayList<String> names = getAllNames().clone();
|
||||
if (names.contains(name.trim())){
|
||||
int index = names.indexOf(name.trim());
|
||||
log.user("Symbol "+symbol+" already exists, found "+names.get(index));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Currently no restrictions on unit
|
||||
public boolean checkUnit(){
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean checkAll(){
|
||||
return checkUnit() && checkSymbol() && checkName();
|
||||
}
|
||||
|
||||
public String getName(){
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getSymbol(){
|
||||
return symbol;
|
||||
}
|
||||
|
||||
public String getUnit(){
|
||||
return unit;
|
||||
}
|
||||
|
||||
public String getExpressionString(){
|
||||
return expression;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Check if the current expression is valid
|
||||
*/
|
||||
public boolean checkExpression(){
|
||||
|
||||
if (expression.trim().isEmpty()){
|
||||
return false;
|
||||
}
|
||||
|
||||
// Define the available variables as 0
|
||||
for (FlightDataType type : getBranch().getTypes()){
|
||||
builder.withVariable(type.getSymbol(), 0.0);
|
||||
}
|
||||
|
||||
for (String symb : getAllSymbols()){
|
||||
builder.withVariable(symb, 0.0);
|
||||
}
|
||||
|
||||
// Try to build
|
||||
try {
|
||||
builder.build();
|
||||
} catch (Exception e) {
|
||||
log.user("Custom expression invalid : " + e.toString());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Otherwise, all OK
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Evaluate the expression using the last variable values from the simulation status.
|
||||
* Returns NaN on any error.
|
||||
*/
|
||||
public Double evaluate(SimulationStatus status){
|
||||
|
||||
for (FlightDataType type : status.getFlightData().getTypes()){
|
||||
builder.withVariable(type.getSymbol(), status.getFlightData().getLast(type) );
|
||||
}
|
||||
|
||||
Calculable calc;
|
||||
try {
|
||||
calc = builder.build();
|
||||
return new Double(calc.calculate());
|
||||
} catch (Exception e) {
|
||||
log.user("Could not calculate custom expression "+name);
|
||||
return Double.NaN;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the new flight data type corresponding to this calculated data
|
||||
*/
|
||||
public FlightDataType getType(){
|
||||
UnitGroup ug = new FixedUnitGroup(unit);
|
||||
return FlightDataType.getType(name, symbol, ug);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add this expression to the simulation if not already added
|
||||
*/
|
||||
public void addToSimulation(){
|
||||
if (! sim.getCustomExpressions().contains(this))
|
||||
sim.addCustomExpression( this );
|
||||
}
|
||||
|
||||
/*
|
||||
* Removes this expression from the simulation, replacing it with a given new expression
|
||||
*/
|
||||
public void overwrite(CustomExpression newExpression){
|
||||
if (!sim.getCustomExpressions().contains(this))
|
||||
return;
|
||||
else {
|
||||
int index = sim.getCustomExpressions().indexOf(this);
|
||||
sim.getCustomExpressions().set(index, newExpression);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(){
|
||||
return "Custom expression : "+this.name.toString()+ " " + this.expression.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
/*
|
||||
* Clone method makes a deep copy of everything except the simulation
|
||||
* @see java.lang.Object#clone()
|
||||
*/
|
||||
public Object clone() {
|
||||
try {
|
||||
return super.clone();
|
||||
}
|
||||
catch( CloneNotSupportedException e )
|
||||
{
|
||||
return new CustomExpression( sim ,
|
||||
new String(this.getName()),
|
||||
new String(this.getSymbol()),
|
||||
new String(this.getUnit()),
|
||||
new String(this.getExpressionString()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -68,7 +68,16 @@ public class FlightDataBranch implements Monitorable {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Makes an 'empty' flight data branch which has no data but all built in data types are defined.
|
||||
*/
|
||||
public FlightDataBranch() {
|
||||
branchName = "Empty branch";
|
||||
for (FlightDataType type : FlightDataType.ALL_TYPES){
|
||||
this.setValue(type, Double.NaN);
|
||||
}
|
||||
this.immute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new point into the data branch. The value for all types is set to NaN by default.
|
||||
|
||||
@ -33,152 +33,206 @@ public class FlightDataType implements Comparable<FlightDataType> {
|
||||
|
||||
|
||||
//// Time
|
||||
public static final FlightDataType TYPE_TIME = newType(trans.get("FlightDataType.TYPE_TIME"), UnitGroup.UNITS_FLIGHT_TIME, 1);
|
||||
|
||||
public static final FlightDataType TYPE_TIME = newType(trans.get("FlightDataType.TYPE_TIME"), "t", UnitGroup.UNITS_FLIGHT_TIME, 1);
|
||||
|
||||
//// Vertical position and motion
|
||||
//// Altitude
|
||||
public static final FlightDataType TYPE_ALTITUDE = newType(trans.get("FlightDataType.TYPE_ALTITUDE"), UnitGroup.UNITS_DISTANCE, 10);
|
||||
public static final FlightDataType TYPE_ALTITUDE = newType(trans.get("FlightDataType.TYPE_ALTITUDE"), "a", UnitGroup.UNITS_DISTANCE, 10);
|
||||
//// Vertical velocity
|
||||
public static final FlightDataType TYPE_VELOCITY_Z = newType(trans.get("FlightDataType.TYPE_VELOCITY_Z"), UnitGroup.UNITS_VELOCITY, 11);
|
||||
public static final FlightDataType TYPE_VELOCITY_Z = newType(trans.get("FlightDataType.TYPE_VELOCITY_Z"), "Vz", UnitGroup.UNITS_VELOCITY, 11);
|
||||
//// Vertical acceleration
|
||||
public static final FlightDataType TYPE_ACCELERATION_Z = newType(trans.get("FlightDataType.TYPE_ACCELERATION_Z"), UnitGroup.UNITS_ACCELERATION, 12);
|
||||
public static final FlightDataType TYPE_ACCELERATION_Z = newType(trans.get("FlightDataType.TYPE_ACCELERATION_Z"), "Az", UnitGroup.UNITS_ACCELERATION, 12);
|
||||
|
||||
|
||||
//// Total motion
|
||||
//// Total velocity
|
||||
public static final FlightDataType TYPE_VELOCITY_TOTAL = newType(trans.get("FlightDataType.TYPE_VELOCITY_TOTAL"), UnitGroup.UNITS_VELOCITY, 20);
|
||||
public static final FlightDataType TYPE_VELOCITY_TOTAL = newType(trans.get("FlightDataType.TYPE_VELOCITY_TOTAL"), "Vt", UnitGroup.UNITS_VELOCITY, 20);
|
||||
//// Total acceleration
|
||||
public static final FlightDataType TYPE_ACCELERATION_TOTAL = newType(trans.get("FlightDataType.TYPE_ACCELERATION_TOTAL"), UnitGroup.UNITS_ACCELERATION, 21);
|
||||
public static final FlightDataType TYPE_ACCELERATION_TOTAL = newType(trans.get("FlightDataType.TYPE_ACCELERATION_TOTAL"), "At", UnitGroup.UNITS_ACCELERATION, 21);
|
||||
|
||||
|
||||
//// Lateral position and motion
|
||||
//// Position upwind
|
||||
public static final FlightDataType TYPE_POSITION_X = newType(trans.get("FlightDataType.TYPE_POSITION_X"), UnitGroup.UNITS_DISTANCE, 30);
|
||||
public static final FlightDataType TYPE_POSITION_X = newType(trans.get("FlightDataType.TYPE_POSITION_X"), "Px", UnitGroup.UNITS_DISTANCE, 30);
|
||||
//// Position parallel to wind
|
||||
public static final FlightDataType TYPE_POSITION_Y = newType(trans.get("FlightDataType.TYPE_POSITION_Y"), UnitGroup.UNITS_DISTANCE, 31);
|
||||
public static final FlightDataType TYPE_POSITION_Y = newType(trans.get("FlightDataType.TYPE_POSITION_Y"), "Py", UnitGroup.UNITS_DISTANCE, 31);
|
||||
//// Lateral distance
|
||||
public static final FlightDataType TYPE_POSITION_XY = newType(trans.get("FlightDataType.TYPE_POSITION_XY"), UnitGroup.UNITS_DISTANCE, 32);
|
||||
public static final FlightDataType TYPE_POSITION_XY = newType(trans.get("FlightDataType.TYPE_POSITION_XY"), "Pl", UnitGroup.UNITS_DISTANCE, 32);
|
||||
//// Lateral direction
|
||||
public static final FlightDataType TYPE_POSITION_DIRECTION = newType(trans.get("FlightDataType.TYPE_POSITION_DIRECTION"), UnitGroup.UNITS_ANGLE, 33);
|
||||
public static final FlightDataType TYPE_POSITION_DIRECTION = newType(trans.get("FlightDataType.TYPE_POSITION_DIRECTION"), "θl", UnitGroup.UNITS_ANGLE, 33);
|
||||
//// Lateral velocity
|
||||
public static final FlightDataType TYPE_VELOCITY_XY = newType(trans.get("FlightDataType.TYPE_VELOCITY_XY"), UnitGroup.UNITS_VELOCITY, 34);
|
||||
public static final FlightDataType TYPE_VELOCITY_XY = newType(trans.get("FlightDataType.TYPE_VELOCITY_XY"), "Vl", UnitGroup.UNITS_VELOCITY, 34);
|
||||
//// Lateral acceleration
|
||||
public static final FlightDataType TYPE_ACCELERATION_XY = newType(trans.get("FlightDataType.TYPE_ACCELERATION_XY"), UnitGroup.UNITS_ACCELERATION, 35);
|
||||
public static final FlightDataType TYPE_ACCELERATION_XY = newType(trans.get("FlightDataType.TYPE_ACCELERATION_XY"), "Al", UnitGroup.UNITS_ACCELERATION, 35);
|
||||
//// Latitude
|
||||
public static final FlightDataType TYPE_LATITUDE = newType(trans.get("FlightDataType.TYPE_LATITUDE"), UnitGroup.UNITS_ANGLE, 36);
|
||||
public static final FlightDataType TYPE_LATITUDE = newType(trans.get("FlightDataType.TYPE_LATITUDE"), "φ", UnitGroup.UNITS_ANGLE, 36);
|
||||
//// Longitude
|
||||
public static final FlightDataType TYPE_LONGITUDE = newType(trans.get("FlightDataType.TYPE_LONGITUDE"), UnitGroup.UNITS_ANGLE, 37);
|
||||
public static final FlightDataType TYPE_LONGITUDE = newType(trans.get("FlightDataType.TYPE_LONGITUDE"), "λ", UnitGroup.UNITS_ANGLE, 37);
|
||||
|
||||
//// Angular motion
|
||||
//// Angle of attack
|
||||
public static final FlightDataType TYPE_AOA = newType(trans.get("FlightDataType.TYPE_AOA"), UnitGroup.UNITS_ANGLE, 40);
|
||||
public static final FlightDataType TYPE_AOA = newType(trans.get("FlightDataType.TYPE_AOA"), "α", UnitGroup.UNITS_ANGLE, 40);
|
||||
//// Roll rate
|
||||
public static final FlightDataType TYPE_ROLL_RATE = newType(trans.get("FlightDataType.TYPE_ROLL_RATE"), UnitGroup.UNITS_ROLL, 41);
|
||||
public static final FlightDataType TYPE_ROLL_RATE = newType(trans.get("FlightDataType.TYPE_ROLL_RATE"), "dΦ", UnitGroup.UNITS_ROLL, 41);
|
||||
//// Pitch rate
|
||||
public static final FlightDataType TYPE_PITCH_RATE = newType(trans.get("FlightDataType.TYPE_PITCH_RATE"), UnitGroup.UNITS_ROLL, 42);
|
||||
public static final FlightDataType TYPE_PITCH_RATE = newType(trans.get("FlightDataType.TYPE_PITCH_RATE"), "dθ", UnitGroup.UNITS_ROLL, 42);
|
||||
//// Yaw rate
|
||||
public static final FlightDataType TYPE_YAW_RATE = newType(trans.get("FlightDataType.TYPE_YAW_RATE"), UnitGroup.UNITS_ROLL, 43);
|
||||
public static final FlightDataType TYPE_YAW_RATE = newType(trans.get("FlightDataType.TYPE_YAW_RATE"), "dΨ", UnitGroup.UNITS_ROLL, 43);
|
||||
|
||||
|
||||
//// Stability information
|
||||
//// Mass
|
||||
public static final FlightDataType TYPE_MASS = newType(trans.get("FlightDataType.TYPE_MASS"), UnitGroup.UNITS_MASS, 50);
|
||||
public static final FlightDataType TYPE_MASS = newType(trans.get("FlightDataType.TYPE_MASS"), "m", UnitGroup.UNITS_MASS, 50);
|
||||
//// Longitudinal moment of inertia
|
||||
public static final FlightDataType TYPE_LONGITUDINAL_INERTIA = newType(trans.get("FlightDataType.TYPE_LONGITUDINAL_INERTIA"), UnitGroup.UNITS_INERTIA, 51);
|
||||
public static final FlightDataType TYPE_LONGITUDINAL_INERTIA = newType(trans.get("FlightDataType.TYPE_LONGITUDINAL_INERTIA"), "Il", UnitGroup.UNITS_INERTIA, 51);
|
||||
//// Rotational moment of inertia
|
||||
public static final FlightDataType TYPE_ROTATIONAL_INERTIA = newType(trans.get("FlightDataType.TYPE_ROTATIONAL_INERTIA"), UnitGroup.UNITS_INERTIA, 52);
|
||||
public static final FlightDataType TYPE_ROTATIONAL_INERTIA = newType(trans.get("FlightDataType.TYPE_ROTATIONAL_INERTIA"), "Ir", UnitGroup.UNITS_INERTIA, 52);
|
||||
//// CP location
|
||||
public static final FlightDataType TYPE_CP_LOCATION = newType(trans.get("FlightDataType.TYPE_CP_LOCATION"), UnitGroup.UNITS_LENGTH, 53);
|
||||
public static final FlightDataType TYPE_CP_LOCATION = newType(trans.get("FlightDataType.TYPE_CP_LOCATION"), "Cp", UnitGroup.UNITS_LENGTH, 53);
|
||||
//// CG location
|
||||
public static final FlightDataType TYPE_CG_LOCATION = newType(trans.get("FlightDataType.TYPE_CG_LOCATION"), UnitGroup.UNITS_LENGTH, 54);
|
||||
public static final FlightDataType TYPE_CG_LOCATION = newType(trans.get("FlightDataType.TYPE_CG_LOCATION"), "Cg", UnitGroup.UNITS_LENGTH, 54);
|
||||
//// Stability margin calibers
|
||||
public static final FlightDataType TYPE_STABILITY = newType(trans.get("FlightDataType.TYPE_STABILITY"), UnitGroup.UNITS_COEFFICIENT, 55);
|
||||
public static final FlightDataType TYPE_STABILITY = newType(trans.get("FlightDataType.TYPE_STABILITY"), "S", UnitGroup.UNITS_COEFFICIENT, 55);
|
||||
|
||||
|
||||
//// Characteristic numbers
|
||||
//// Mach number
|
||||
public static final FlightDataType TYPE_MACH_NUMBER = newType(trans.get("FlightDataType.TYPE_MACH_NUMBER"), UnitGroup.UNITS_COEFFICIENT, 60);
|
||||
public static final FlightDataType TYPE_MACH_NUMBER = newType(trans.get("FlightDataType.TYPE_MACH_NUMBER"), "M", UnitGroup.UNITS_COEFFICIENT, 60);
|
||||
//// Reynolds number
|
||||
public static final FlightDataType TYPE_REYNOLDS_NUMBER = newType(trans.get("FlightDataType.TYPE_REYNOLDS_NUMBER"), UnitGroup.UNITS_COEFFICIENT, 61);
|
||||
public static final FlightDataType TYPE_REYNOLDS_NUMBER = newType(trans.get("FlightDataType.TYPE_REYNOLDS_NUMBER"), "R", UnitGroup.UNITS_COEFFICIENT, 61);
|
||||
|
||||
|
||||
//// Thrust and drag
|
||||
//// Thrust
|
||||
public static final FlightDataType TYPE_THRUST_FORCE = newType(trans.get("FlightDataType.TYPE_THRUST_FORCE"), UnitGroup.UNITS_FORCE, 70);
|
||||
public static final FlightDataType TYPE_THRUST_FORCE = newType(trans.get("FlightDataType.TYPE_THRUST_FORCE"), "Ft", UnitGroup.UNITS_FORCE, 70);
|
||||
//// Drag force
|
||||
public static final FlightDataType TYPE_DRAG_FORCE = newType(trans.get("FlightDataType.TYPE_DRAG_FORCE"), UnitGroup.UNITS_FORCE, 71);
|
||||
public static final FlightDataType TYPE_DRAG_FORCE = newType(trans.get("FlightDataType.TYPE_DRAG_FORCE"), "Fd", UnitGroup.UNITS_FORCE, 71);
|
||||
//// Drag coefficient
|
||||
public static final FlightDataType TYPE_DRAG_COEFF = newType(trans.get("FlightDataType.TYPE_DRAG_COEFF"), UnitGroup.UNITS_COEFFICIENT, 72);
|
||||
public static final FlightDataType TYPE_DRAG_COEFF = newType(trans.get("FlightDataType.TYPE_DRAG_COEFF"), "Cd", UnitGroup.UNITS_COEFFICIENT, 72);
|
||||
//// Axial drag coefficient
|
||||
public static final FlightDataType TYPE_AXIAL_DRAG_COEFF = newType(trans.get("FlightDataType.TYPE_AXIAL_DRAG_COEFF"), UnitGroup.UNITS_COEFFICIENT, 73);
|
||||
public static final FlightDataType TYPE_AXIAL_DRAG_COEFF = newType(trans.get("FlightDataType.TYPE_AXIAL_DRAG_COEFF"), "Cda", UnitGroup.UNITS_COEFFICIENT, 73);
|
||||
|
||||
|
||||
//// Component drag coefficients
|
||||
//// Friction drag coefficient
|
||||
public static final FlightDataType TYPE_FRICTION_DRAG_COEFF = newType(trans.get("FlightDataType.TYPE_FRICTION_DRAG_COEFF"), UnitGroup.UNITS_COEFFICIENT, 80);
|
||||
public static final FlightDataType TYPE_FRICTION_DRAG_COEFF = newType(trans.get("FlightDataType.TYPE_FRICTION_DRAG_COEFF"), "Cdf", UnitGroup.UNITS_COEFFICIENT, 80);
|
||||
//// Pressure drag coefficient
|
||||
public static final FlightDataType TYPE_PRESSURE_DRAG_COEFF = newType(trans.get("FlightDataType.TYPE_PRESSURE_DRAG_COEFF"), UnitGroup.UNITS_COEFFICIENT, 81);
|
||||
public static final FlightDataType TYPE_PRESSURE_DRAG_COEFF = newType(trans.get("FlightDataType.TYPE_PRESSURE_DRAG_COEFF"), "Cdp", UnitGroup.UNITS_COEFFICIENT, 81);
|
||||
//// Base drag coefficient
|
||||
public static final FlightDataType TYPE_BASE_DRAG_COEFF = newType(trans.get("FlightDataType.TYPE_BASE_DRAG_COEFF"), UnitGroup.UNITS_COEFFICIENT, 82);
|
||||
public static final FlightDataType TYPE_BASE_DRAG_COEFF = newType(trans.get("FlightDataType.TYPE_BASE_DRAG_COEFF"), "Cdb", UnitGroup.UNITS_COEFFICIENT, 82);
|
||||
|
||||
|
||||
//// Other coefficients
|
||||
//// Normal force coefficient
|
||||
public static final FlightDataType TYPE_NORMAL_FORCE_COEFF = newType(trans.get("FlightDataType.TYPE_NORMAL_FORCE_COEFF"), UnitGroup.UNITS_COEFFICIENT, 90);
|
||||
public static final FlightDataType TYPE_NORMAL_FORCE_COEFF = newType(trans.get("FlightDataType.TYPE_NORMAL_FORCE_COEFF"), "Cn", UnitGroup.UNITS_COEFFICIENT, 90);
|
||||
//// Pitch moment coefficient
|
||||
public static final FlightDataType TYPE_PITCH_MOMENT_COEFF = newType(trans.get("FlightDataType.TYPE_PITCH_MOMENT_COEFF"), UnitGroup.UNITS_COEFFICIENT, 91);
|
||||
public static final FlightDataType TYPE_PITCH_MOMENT_COEFF = newType(trans.get("FlightDataType.TYPE_PITCH_MOMENT_COEFF"), "Cθ", UnitGroup.UNITS_COEFFICIENT, 91);
|
||||
//// Yaw moment coefficient
|
||||
public static final FlightDataType TYPE_YAW_MOMENT_COEFF = newType(trans.get("FlightDataType.TYPE_YAW_MOMENT_COEFF"), UnitGroup.UNITS_COEFFICIENT, 92);
|
||||
public static final FlightDataType TYPE_YAW_MOMENT_COEFF = newType(trans.get("FlightDataType.TYPE_YAW_MOMENT_COEFF"), "CτΨ", UnitGroup.UNITS_COEFFICIENT, 92);
|
||||
//// Side force coefficient
|
||||
public static final FlightDataType TYPE_SIDE_FORCE_COEFF = newType(trans.get("FlightDataType.TYPE_SIDE_FORCE_COEFF"), UnitGroup.UNITS_COEFFICIENT, 93);
|
||||
public static final FlightDataType TYPE_SIDE_FORCE_COEFF = newType(trans.get("FlightDataType.TYPE_SIDE_FORCE_COEFF"), "Cτs", UnitGroup.UNITS_COEFFICIENT, 93);
|
||||
//// Roll moment coefficient
|
||||
public static final FlightDataType TYPE_ROLL_MOMENT_COEFF = newType(trans.get("FlightDataType.TYPE_ROLL_MOMENT_COEFF"), UnitGroup.UNITS_COEFFICIENT, 94);
|
||||
public static final FlightDataType TYPE_ROLL_MOMENT_COEFF = newType(trans.get("FlightDataType.TYPE_ROLL_MOMENT_COEFF"), "CτΦ", UnitGroup.UNITS_COEFFICIENT, 94);
|
||||
//// Roll forcing coefficient
|
||||
public static final FlightDataType TYPE_ROLL_FORCING_COEFF = newType(trans.get("FlightDataType.TYPE_ROLL_FORCING_COEFF"), UnitGroup.UNITS_COEFFICIENT, 95);
|
||||
public static final FlightDataType TYPE_ROLL_FORCING_COEFF = newType(trans.get("FlightDataType.TYPE_ROLL_FORCING_COEFF"), "CfΦ", UnitGroup.UNITS_COEFFICIENT, 95);
|
||||
//// Roll damping coefficient
|
||||
public static final FlightDataType TYPE_ROLL_DAMPING_COEFF = newType(trans.get("FlightDataType.TYPE_ROLL_DAMPING_COEFF"), UnitGroup.UNITS_COEFFICIENT, 96);
|
||||
public static final FlightDataType TYPE_ROLL_DAMPING_COEFF = newType(trans.get("FlightDataType.TYPE_ROLL_DAMPING_COEFF"), "CζΦ", UnitGroup.UNITS_COEFFICIENT, 96);
|
||||
|
||||
//// Pitch damping coefficient
|
||||
public static final FlightDataType TYPE_PITCH_DAMPING_MOMENT_COEFF = newType(trans.get("FlightDataType.TYPE_PITCH_DAMPING_MOMENT_COEFF"), UnitGroup.UNITS_COEFFICIENT, 97);
|
||||
public static final FlightDataType TYPE_PITCH_DAMPING_MOMENT_COEFF = newType(trans.get("FlightDataType.TYPE_PITCH_DAMPING_MOMENT_COEFF"), "Cζθ", UnitGroup.UNITS_COEFFICIENT, 97);
|
||||
//// Yaw damping coefficient
|
||||
public static final FlightDataType TYPE_YAW_DAMPING_MOMENT_COEFF = newType(trans.get("FlightDataType.TYPE_YAW_DAMPING_MOMENT_COEFF"), UnitGroup.UNITS_COEFFICIENT, 98);
|
||||
public static final FlightDataType TYPE_YAW_DAMPING_MOMENT_COEFF = newType(trans.get("FlightDataType.TYPE_YAW_DAMPING_MOMENT_COEFF"), "CζΨ", UnitGroup.UNITS_COEFFICIENT, 98);
|
||||
|
||||
//// Coriolis acceleration
|
||||
public static final FlightDataType TYPE_CORIOLIS_ACCELERATION = newType(trans.get("FlightDataType.TYPE_CORIOLIS_ACCELERATION"), UnitGroup.UNITS_ACCELERATION, 99);
|
||||
public static final FlightDataType TYPE_CORIOLIS_ACCELERATION = newType(trans.get("FlightDataType.TYPE_CORIOLIS_ACCELERATION"), "Ac", UnitGroup.UNITS_ACCELERATION, 99);
|
||||
|
||||
|
||||
//// Reference length + area
|
||||
//// Reference length
|
||||
public static final FlightDataType TYPE_REFERENCE_LENGTH = newType(trans.get("FlightDataType.TYPE_REFERENCE_LENGTH"), UnitGroup.UNITS_LENGTH, 100);
|
||||
public static final FlightDataType TYPE_REFERENCE_LENGTH = newType(trans.get("FlightDataType.TYPE_REFERENCE_LENGTH"), "Lr", UnitGroup.UNITS_LENGTH, 100);
|
||||
//// Reference area
|
||||
public static final FlightDataType TYPE_REFERENCE_AREA = newType(trans.get("FlightDataType.TYPE_REFERENCE_AREA"), UnitGroup.UNITS_AREA, 101);
|
||||
public static final FlightDataType TYPE_REFERENCE_AREA = newType(trans.get("FlightDataType.TYPE_REFERENCE_AREA"), "Ar", UnitGroup.UNITS_AREA, 101);
|
||||
|
||||
|
||||
//// Orientation
|
||||
//// Vertical orientation (zenith)
|
||||
public static final FlightDataType TYPE_ORIENTATION_THETA = newType(trans.get("FlightDataType.TYPE_ORIENTATION_THETA"), UnitGroup.UNITS_ANGLE, 106);
|
||||
public static final FlightDataType TYPE_ORIENTATION_THETA = newType(trans.get("FlightDataType.TYPE_ORIENTATION_THETA"), "Θ", UnitGroup.UNITS_ANGLE, 106);
|
||||
//// Lateral orientation (azimuth)
|
||||
public static final FlightDataType TYPE_ORIENTATION_PHI = newType(trans.get("FlightDataType.TYPE_ORIENTATION_PHI"), UnitGroup.UNITS_ANGLE, 107);
|
||||
public static final FlightDataType TYPE_ORIENTATION_PHI = newType(trans.get("FlightDataType.TYPE_ORIENTATION_PHI"), "Φ", UnitGroup.UNITS_ANGLE, 107);
|
||||
|
||||
|
||||
//// Atmospheric conditions
|
||||
//// Wind velocity
|
||||
public static final FlightDataType TYPE_WIND_VELOCITY = newType(trans.get("FlightDataType.TYPE_WIND_VELOCITY"), UnitGroup.UNITS_VELOCITY, 110);
|
||||
public static final FlightDataType TYPE_WIND_VELOCITY = newType(trans.get("FlightDataType.TYPE_WIND_VELOCITY"), "Vw", UnitGroup.UNITS_VELOCITY, 110);
|
||||
//// Air temperature
|
||||
public static final FlightDataType TYPE_AIR_TEMPERATURE = newType(trans.get("FlightDataType.TYPE_AIR_TEMPERATURE"), UnitGroup.UNITS_TEMPERATURE, 111);
|
||||
public static final FlightDataType TYPE_AIR_TEMPERATURE = newType(trans.get("FlightDataType.TYPE_AIR_TEMPERATURE"), "T", UnitGroup.UNITS_TEMPERATURE, 111);
|
||||
//// Air pressure
|
||||
public static final FlightDataType TYPE_AIR_PRESSURE = newType(trans.get("FlightDataType.TYPE_AIR_PRESSURE"), UnitGroup.UNITS_PRESSURE, 112);
|
||||
public static final FlightDataType TYPE_AIR_PRESSURE = newType(trans.get("FlightDataType.TYPE_AIR_PRESSURE"), "p", UnitGroup.UNITS_PRESSURE, 112);
|
||||
//// Speed of sound
|
||||
public static final FlightDataType TYPE_SPEED_OF_SOUND = newType(trans.get("FlightDataType.TYPE_SPEED_OF_SOUND"), UnitGroup.UNITS_VELOCITY, 113);
|
||||
public static final FlightDataType TYPE_SPEED_OF_SOUND = newType(trans.get("FlightDataType.TYPE_SPEED_OF_SOUND"), "Vs", UnitGroup.UNITS_VELOCITY, 113);
|
||||
|
||||
//// Simulation information
|
||||
//// Simulation time step
|
||||
public static final FlightDataType TYPE_TIME_STEP = newType(trans.get("FlightDataType.TYPE_TIME_STEP"), UnitGroup.UNITS_TIME_STEP, 200);
|
||||
public static final FlightDataType TYPE_TIME_STEP = newType(trans.get("FlightDataType.TYPE_TIME_STEP"), "dt", UnitGroup.UNITS_TIME_STEP, 200);
|
||||
//// Computation time
|
||||
public static final FlightDataType TYPE_COMPUTATION_TIME = newType(trans.get("FlightDataType.TYPE_COMPUTATION_TIME"), UnitGroup.UNITS_SHORT_TIME, 201);
|
||||
public static final FlightDataType TYPE_COMPUTATION_TIME = newType(trans.get("FlightDataType.TYPE_COMPUTATION_TIME"), "tc", UnitGroup.UNITS_SHORT_TIME, 201);
|
||||
|
||||
|
||||
// An array of all the built in types
|
||||
public static final FlightDataType[] ALL_TYPES = {
|
||||
TYPE_ALTITUDE ,
|
||||
TYPE_VELOCITY_Z ,
|
||||
TYPE_ACCELERATION_Z,
|
||||
TYPE_VELOCITY_TOTAL,
|
||||
TYPE_ACCELERATION_TOTAL,
|
||||
TYPE_POSITION_X,
|
||||
TYPE_POSITION_Y,
|
||||
TYPE_POSITION_XY,
|
||||
TYPE_POSITION_DIRECTION,
|
||||
TYPE_VELOCITY_XY,
|
||||
TYPE_ACCELERATION_XY,
|
||||
TYPE_LATITUDE,
|
||||
TYPE_LONGITUDE,
|
||||
TYPE_AOA,
|
||||
TYPE_ROLL_RATE,
|
||||
TYPE_PITCH_RATE,
|
||||
TYPE_YAW_RATE,
|
||||
TYPE_MASS,
|
||||
TYPE_LONGITUDINAL_INERTIA,
|
||||
TYPE_ROTATIONAL_INERTIA,
|
||||
TYPE_CP_LOCATION,
|
||||
TYPE_CG_LOCATION,
|
||||
TYPE_STABILITY,
|
||||
TYPE_MACH_NUMBER,
|
||||
TYPE_REYNOLDS_NUMBER,
|
||||
TYPE_THRUST_FORCE,
|
||||
TYPE_DRAG_FORCE,
|
||||
TYPE_DRAG_COEFF,
|
||||
TYPE_AXIAL_DRAG_COEFF,
|
||||
TYPE_FRICTION_DRAG_COEFF,
|
||||
TYPE_PRESSURE_DRAG_COEFF,
|
||||
TYPE_BASE_DRAG_COEFF,
|
||||
TYPE_NORMAL_FORCE_COEFF,
|
||||
TYPE_PITCH_MOMENT_COEFF,
|
||||
TYPE_YAW_MOMENT_COEFF,
|
||||
TYPE_SIDE_FORCE_COEFF,
|
||||
TYPE_ROLL_MOMENT_COEFF,
|
||||
TYPE_ROLL_FORCING_COEFF,
|
||||
TYPE_ROLL_DAMPING_COEFF,
|
||||
TYPE_PITCH_DAMPING_MOMENT_COEFF,
|
||||
TYPE_YAW_DAMPING_MOMENT_COEFF,
|
||||
TYPE_CORIOLIS_ACCELERATION,
|
||||
TYPE_REFERENCE_LENGTH,
|
||||
TYPE_REFERENCE_AREA,
|
||||
TYPE_ORIENTATION_THETA,
|
||||
TYPE_ORIENTATION_PHI,
|
||||
TYPE_WIND_VELOCITY,
|
||||
TYPE_AIR_TEMPERATURE,
|
||||
TYPE_AIR_PRESSURE,
|
||||
TYPE_SPEED_OF_SOUND,
|
||||
TYPE_TIME_STEP,
|
||||
TYPE_COMPUTATION_TIME
|
||||
};
|
||||
|
||||
/**
|
||||
* Return a {@link FlightDataType} based on a string description. This returns known data types
|
||||
@ -188,37 +242,39 @@ public class FlightDataType implements Comparable<FlightDataType> {
|
||||
* @param u the unit group the new type should belong to if a new group is created.
|
||||
* @return a data type.
|
||||
*/
|
||||
public static synchronized FlightDataType getType(String s, UnitGroup u) {
|
||||
public static synchronized FlightDataType getType(String s, String symbol, UnitGroup u) {
|
||||
FlightDataType type = EXISTING_TYPES.get(s.toLowerCase(Locale.ENGLISH));
|
||||
if (type != null) {
|
||||
return type;
|
||||
}
|
||||
type = newType(s, u, DEFAULT_PRIORITY);
|
||||
type = newType(s, symbol, u, DEFAULT_PRIORITY);
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used while initializing the class.
|
||||
*/
|
||||
private static synchronized FlightDataType newType(String s, UnitGroup u, int priority) {
|
||||
FlightDataType type = new FlightDataType(s, u, priority);
|
||||
private static synchronized FlightDataType newType(String s, String symbol, UnitGroup u, int priority) {
|
||||
FlightDataType type = new FlightDataType(s, symbol, u, priority);
|
||||
EXISTING_TYPES.put(s.toLowerCase(Locale.ENGLISH), type);
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
private final String name;
|
||||
private final String symbol;
|
||||
private final UnitGroup units;
|
||||
private final int priority;
|
||||
private final int hashCode;
|
||||
|
||||
|
||||
private FlightDataType(String typeName, UnitGroup units, int priority) {
|
||||
private FlightDataType(String typeName, String symbol, UnitGroup units, int priority) {
|
||||
if (typeName == null)
|
||||
throw new IllegalArgumentException("typeName is null");
|
||||
if (units == null)
|
||||
throw new IllegalArgumentException("units is null");
|
||||
this.name = typeName;
|
||||
this.symbol = symbol;
|
||||
this.units = units;
|
||||
this.priority = priority;
|
||||
this.hashCode = this.name.toLowerCase(Locale.ENGLISH).hashCode();
|
||||
@ -231,6 +287,10 @@ public class FlightDataType implements Comparable<FlightDataType> {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getSymbol(){
|
||||
return symbol;
|
||||
}
|
||||
|
||||
public UnitGroup getUnitGroup() {
|
||||
return units;
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.sf.openrocket.aerodynamics.AerodynamicCalculator;
|
||||
import net.sf.openrocket.document.Simulation;
|
||||
import net.sf.openrocket.masscalc.MassCalculator;
|
||||
import net.sf.openrocket.models.atmosphere.AtmosphericModel;
|
||||
import net.sf.openrocket.models.gravity.GravityModel;
|
||||
@ -27,6 +28,7 @@ public class SimulationConditions implements Monitorable, Cloneable {
|
||||
private Rocket rocket;
|
||||
private String motorID = null;
|
||||
|
||||
private Simulation simulation; // The parent simulation
|
||||
|
||||
private double launchRodLength = 1;
|
||||
|
||||
@ -262,9 +264,14 @@ public class SimulationConditions implements Monitorable, Cloneable {
|
||||
this.modID++;
|
||||
}
|
||||
|
||||
public void setSimulation(Simulation sim) {
|
||||
this.simulation = sim;
|
||||
}
|
||||
|
||||
public Simulation getSimulation(){
|
||||
return this.simulation;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// TODO: HIGH: Make cleaner
|
||||
public List<SimulationListener> getSimulationListenerList() {
|
||||
return simulationListeners;
|
||||
|
||||
@ -5,8 +5,10 @@ import java.util.EventListener;
|
||||
import java.util.EventObject;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
|
||||
import net.sf.openrocket.aerodynamics.BarrowmanCalculator;
|
||||
import net.sf.openrocket.logging.LogHelper;
|
||||
import net.sf.openrocket.masscalc.BasicMassCalculator;
|
||||
import net.sf.openrocket.models.atmosphere.AtmosphericModel;
|
||||
import net.sf.openrocket.models.atmosphere.ExtendedISAModel;
|
||||
@ -14,6 +16,7 @@ import net.sf.openrocket.models.gravity.GravityModel;
|
||||
import net.sf.openrocket.models.gravity.WGSGravityModel;
|
||||
import net.sf.openrocket.models.wind.PinkNoiseWindModel;
|
||||
import net.sf.openrocket.rocketcomponent.Rocket;
|
||||
import net.sf.openrocket.startup.Application;
|
||||
import net.sf.openrocket.util.BugException;
|
||||
import net.sf.openrocket.util.ChangeSource;
|
||||
import net.sf.openrocket.util.GeodeticComputationStrategy;
|
||||
@ -31,6 +34,8 @@ import net.sf.openrocket.util.WorldCoordinate;
|
||||
*/
|
||||
public class SimulationOptions implements ChangeSource, Cloneable {
|
||||
|
||||
private static final LogHelper log = Application.getLogger();
|
||||
|
||||
public static final double MAX_LAUNCH_ROD_ANGLE = Math.PI / 3;
|
||||
|
||||
/**
|
||||
@ -93,7 +98,6 @@ public class SimulationOptions implements ChangeSource, Cloneable {
|
||||
this.rocket = rocket;
|
||||
}
|
||||
|
||||
|
||||
public Rocket getRocket() {
|
||||
return rocket;
|
||||
}
|
||||
|
||||
@ -22,8 +22,7 @@ public class RollControlListener extends AbstractSimulationListener {
|
||||
private static final String CONTROL_FIN_NAME = "CONTROL";
|
||||
|
||||
// Define custom flight data type
|
||||
private static final FlightDataType FIN_CANT_TYPE = FlightDataType.getType("Control fin cant",
|
||||
UnitGroup.UNITS_ANGLE);
|
||||
private static final FlightDataType FIN_CANT_TYPE = FlightDataType.getType("Control fin cant", "αfc", UnitGroup.UNITS_ANGLE);
|
||||
|
||||
// Simulation time at which PID controller is activated
|
||||
private static final double START_TIME = 0.5;
|
||||
|
||||
31
core/src/net/sf/openrocket/unit/FixedUnitGroup.java
Normal file
31
core/src/net/sf/openrocket/unit/FixedUnitGroup.java
Normal file
@ -0,0 +1,31 @@
|
||||
package net.sf.openrocket.unit;
|
||||
|
||||
/*
|
||||
* This class provides a 'dumb' version of UnitGroup
|
||||
* It allows any arbitrary unit to be created. It doesn't store any value and can't be converted into anything else.
|
||||
* This is useful for custom expression units.
|
||||
*
|
||||
* @author Richard Graham
|
||||
*/
|
||||
|
||||
public class FixedUnitGroup extends UnitGroup {
|
||||
|
||||
String unitString;
|
||||
|
||||
public FixedUnitGroup( String unitString ){
|
||||
this.unitString = unitString;
|
||||
}
|
||||
|
||||
public int getUnitCount(){
|
||||
return 1;
|
||||
}
|
||||
|
||||
public Unit getDefaultUnit(){
|
||||
return new GeneralUnit(1, unitString);
|
||||
}
|
||||
|
||||
public boolean contains(Unit u){
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user