Added new feature : user configurable custom expression evaluation for the simulation, driven by exp4j.

This commit is contained in:
Richard Graham 2012-06-02 17:58:47 +00:00
parent d103ac1d05
commit 16eed9a30b
24 changed files with 1433 additions and 81 deletions

View File

@ -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

View File

@ -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)

Binary file not shown.

After

Width:  |  Height:  |  Size: 912 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 713 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 906 B

View File

@ -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);
}

View File

@ -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();

View File

@ -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

View File

@ -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");
}
}
}

View File

@ -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());
}
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}
}

View File

@ -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);
}
/**

View File

@ -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");

View File

@ -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();

View 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()));
}
}
}

View File

@ -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.

View File

@ -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"), "", 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"), "", 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"), "", 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"), "", 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;
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View 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;
}
}