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.cancel = Cancel
|
||||||
dlg.but.close = Close
|
dlg.but.close = Close
|
||||||
|
|
||||||
|
|
||||||
! General file type names
|
! General file type names
|
||||||
filetypes.pdf = PDF files (*.pdf)
|
filetypes.pdf = PDF files (*.pdf)
|
||||||
BasicFrame.SimpleFileFilter1 = All rocket designs (*.ork; *.rkt)
|
BasicFrame.SimpleFileFilter1 = All rocket designs (*.ork; *.rkt)
|
||||||
@ -286,6 +285,7 @@ simedtdlg.lbl.Simname = Simulation name:
|
|||||||
simedtdlg.tab.Launchcond = Launch conditions
|
simedtdlg.tab.Launchcond = Launch conditions
|
||||||
simedtdlg.tab.Simopt = Simulation options
|
simedtdlg.tab.Simopt = Simulation options
|
||||||
simedtdlg.tab.Plotdata = Plot data
|
simedtdlg.tab.Plotdata = Plot data
|
||||||
|
simedtdlg.tab.CustomExpressions = Custom expressions
|
||||||
simedtdlg.tab.Exportdata = Export data
|
simedtdlg.tab.Exportdata = Export data
|
||||||
simedtdlg.lbl.Motorcfg = Motor configuration:
|
simedtdlg.lbl.Motorcfg = Motor configuration:
|
||||||
simedtdlg.lbl.ttip.Motorcfg = Select the motor configuration to use.
|
simedtdlg.lbl.ttip.Motorcfg = Select the motor configuration to use.
|
||||||
@ -444,6 +444,37 @@ CsvOptionPanel.separator.space = SPACE
|
|||||||
CsvOptionPanel.separator.tab = TAB
|
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
|
||||||
MotorPlot.title.Motorplot = Motor plot
|
MotorPlot.title.Motorplot = Motor plot
|
||||||
@ -457,8 +488,6 @@ MotorPlot.txt.Type = Type:
|
|||||||
MotorPlot.txt.Delays = Delays:
|
MotorPlot.txt.Delays = Delays:
|
||||||
MotorPlot.txt.Comment = Comment:\n
|
MotorPlot.txt.Comment = Comment:\n
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
! Simulation plot panel
|
! Simulation plot panel
|
||||||
simplotpanel.lbl.Presetplotconf = Preset plot configurations:
|
simplotpanel.lbl.Presetplotconf = Preset plot configurations:
|
||||||
simplotpanel.lbl.Xaxistype = X axis type:
|
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 = Please add one or more variables to plot on the Y-axis.
|
||||||
SimulationPlotPanel.error.noPlotSelected.title = Nothing to plot
|
SimulationPlotPanel.error.noPlotSelected.title = Nothing to plot
|
||||||
|
|
||||||
|
|
||||||
! Component add buttons
|
! Component add buttons
|
||||||
compaddbuttons.Bodycompandfinsets = Body components and fin sets
|
compaddbuttons.Bodycompandfinsets = Body components and fin sets
|
||||||
compaddbuttons.Nosecone = Nose cone
|
compaddbuttons.Nosecone = Nose cone
|
||||||
|
|||||||
@ -20,6 +20,9 @@ edit-delete.png
|
|||||||
edit-paste.png
|
edit-paste.png
|
||||||
edit-redo.png
|
edit-redo.png
|
||||||
edit-undo.png
|
edit-undo.png
|
||||||
|
down.png
|
||||||
|
pencil.png
|
||||||
|
up.png
|
||||||
edit-scale.png (modified from edit-copy.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.Configuration;
|
||||||
import net.sf.openrocket.rocketcomponent.Rocket;
|
import net.sf.openrocket.rocketcomponent.Rocket;
|
||||||
import net.sf.openrocket.simulation.BasicEventSimulationEngine;
|
import net.sf.openrocket.simulation.BasicEventSimulationEngine;
|
||||||
|
import net.sf.openrocket.simulation.CustomExpression;
|
||||||
import net.sf.openrocket.simulation.FlightData;
|
import net.sf.openrocket.simulation.FlightData;
|
||||||
import net.sf.openrocket.simulation.RK4SimulationStepper;
|
import net.sf.openrocket.simulation.RK4SimulationStepper;
|
||||||
import net.sf.openrocket.simulation.SimulationConditions;
|
import net.sf.openrocket.simulation.SimulationConditions;
|
||||||
@ -70,13 +71,12 @@ public class Simulation implements ChangeSource, Cloneable {
|
|||||||
private SimulationOptions options;
|
private SimulationOptions options;
|
||||||
|
|
||||||
private ArrayList<String> simulationListeners = new ArrayList<String>();
|
private ArrayList<String> simulationListeners = new ArrayList<String>();
|
||||||
|
private ArrayList<CustomExpression> customExpressions = new ArrayList<CustomExpression>();
|
||||||
|
|
||||||
private final Class<? extends SimulationEngine> simulationEngineClass = BasicEventSimulationEngine.class;
|
private final Class<? extends SimulationEngine> simulationEngineClass = BasicEventSimulationEngine.class;
|
||||||
private Class<? extends SimulationStepper> simulationStepperClass = RK4SimulationStepper.class;
|
private Class<? extends SimulationStepper> simulationStepperClass = RK4SimulationStepper.class;
|
||||||
private Class<? extends AerodynamicCalculator> aerodynamicCalculatorClass = BarrowmanCalculator.class;
|
private Class<? extends AerodynamicCalculator> aerodynamicCalculatorClass = BarrowmanCalculator.class;
|
||||||
private Class<? extends MassCalculator> massCalculatorClass = BasicMassCalculator.class;
|
private Class<? extends MassCalculator> massCalculatorClass = BasicMassCalculator.class;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Listeners for this object */
|
/** Listeners for this object */
|
||||||
private List<EventListener> listeners = new ArrayList<EventListener>();
|
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.
|
* Return the rocket associated with this simulation.
|
||||||
@ -280,6 +294,7 @@ public class Simulation implements ChangeSource, Cloneable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SimulationConditions simulationConditions = options.toSimulationConditions();
|
SimulationConditions simulationConditions = options.toSimulationConditions();
|
||||||
|
simulationConditions.setSimulation(this);
|
||||||
for (SimulationListener l : additionalListeners) {
|
for (SimulationListener l : additionalListeners) {
|
||||||
simulationConditions.getSimulationListenerList().add(l);
|
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.Rocket;
|
||||||
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
||||||
import net.sf.openrocket.rocketcomponent.TubeCoupler;
|
import net.sf.openrocket.rocketcomponent.TubeCoupler;
|
||||||
|
import net.sf.openrocket.simulation.CustomExpression;
|
||||||
import net.sf.openrocket.simulation.FlightData;
|
import net.sf.openrocket.simulation.FlightData;
|
||||||
import net.sf.openrocket.simulation.FlightDataBranch;
|
import net.sf.openrocket.simulation.FlightDataBranch;
|
||||||
import net.sf.openrocket.simulation.FlightDataType;
|
import net.sf.openrocket.simulation.FlightDataType;
|
||||||
@ -322,10 +323,25 @@ public class OpenRocketSaver extends RocketSaver {
|
|||||||
|
|
||||||
writeln("<name>" + escapeXML(simulation.getName()) + "</name>");
|
writeln("<name>" + escapeXML(simulation.getName()) + "</name>");
|
||||||
// TODO: MEDIUM: Other simulators/calculators
|
// TODO: MEDIUM: Other simulators/calculators
|
||||||
|
|
||||||
writeln("<simulator>RK4Simulator</simulator>");
|
writeln("<simulator>RK4Simulator</simulator>");
|
||||||
writeln("<calculator>BarrowmanCalculator</calculator>");
|
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("configid", cond.getMotorConfigurationID());
|
||||||
writeElement("launchrodlength", cond.getLaunchRodLength());
|
writeElement("launchrodlength", cond.getLaunchRodLength());
|
||||||
@ -359,7 +375,6 @@ public class OpenRocketSaver extends RocketSaver {
|
|||||||
writeElement("listener", escapeXML(s));
|
writeElement("listener", escapeXML(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Write basic simulation data
|
// Write basic simulation data
|
||||||
|
|
||||||
FlightData data = simulation.getSimulatedData();
|
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.Transition;
|
||||||
import net.sf.openrocket.rocketcomponent.TrapezoidFinSet;
|
import net.sf.openrocket.rocketcomponent.TrapezoidFinSet;
|
||||||
import net.sf.openrocket.rocketcomponent.TubeCoupler;
|
import net.sf.openrocket.rocketcomponent.TubeCoupler;
|
||||||
|
import net.sf.openrocket.simulation.CustomExpression;
|
||||||
import net.sf.openrocket.simulation.FlightData;
|
import net.sf.openrocket.simulation.FlightData;
|
||||||
import net.sf.openrocket.simulation.FlightDataBranch;
|
import net.sf.openrocket.simulation.FlightDataBranch;
|
||||||
import net.sf.openrocket.simulation.FlightDataType;
|
import net.sf.openrocket.simulation.FlightDataType;
|
||||||
@ -1201,6 +1202,8 @@ class SimulationsHandler extends AbstractElementHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class SingleSimulationHandler extends AbstractElementHandler {
|
class SingleSimulationHandler extends AbstractElementHandler {
|
||||||
|
private static final LogHelper log = Application.getLogger();
|
||||||
|
|
||||||
private final DocumentLoadingContext context;
|
private final DocumentLoadingContext context;
|
||||||
|
|
||||||
private final OpenRocketDocument doc;
|
private final OpenRocketDocument doc;
|
||||||
@ -1209,7 +1212,9 @@ class SingleSimulationHandler extends AbstractElementHandler {
|
|||||||
|
|
||||||
private SimulationConditionsHandler conditionHandler;
|
private SimulationConditionsHandler conditionHandler;
|
||||||
private FlightDataHandler dataHandler;
|
private FlightDataHandler dataHandler;
|
||||||
|
private CustomExpressionsHandler customExpressionsHandler;
|
||||||
|
|
||||||
|
private ArrayList<CustomExpression> customExpressions = new ArrayList<CustomExpression>();
|
||||||
private final List<String> listeners = new ArrayList<String>();
|
private final List<String> listeners = new ArrayList<String>();
|
||||||
|
|
||||||
public SingleSimulationHandler(OpenRocketDocument doc, DocumentLoadingContext context) {
|
public SingleSimulationHandler(OpenRocketDocument doc, DocumentLoadingContext context) {
|
||||||
@ -1217,7 +1222,9 @@ class SingleSimulationHandler extends AbstractElementHandler {
|
|||||||
this.context = context;
|
this.context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setCustomExpressions(ArrayList<CustomExpression> expressions){
|
||||||
|
this.customExpressions = expressions;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ElementHandler openElement(String element, HashMap<String, String> attributes,
|
public ElementHandler openElement(String element, HashMap<String, String> attributes,
|
||||||
@ -1226,6 +1233,9 @@ class SingleSimulationHandler extends AbstractElementHandler {
|
|||||||
if (element.equals("name") || element.equals("simulator") ||
|
if (element.equals("name") || element.equals("simulator") ||
|
||||||
element.equals("calculator") || element.equals("listener")) {
|
element.equals("calculator") || element.equals("listener")) {
|
||||||
return PlainTextHandler.INSTANCE;
|
return PlainTextHandler.INSTANCE;
|
||||||
|
} else if (element.equals("customexpressions")) {
|
||||||
|
customExpressionsHandler = new CustomExpressionsHandler(this, context);
|
||||||
|
return customExpressionsHandler;
|
||||||
} else if (element.equals("conditions")) {
|
} else if (element.equals("conditions")) {
|
||||||
conditionHandler = new SimulationConditionsHandler(doc.getRocket(), context);
|
conditionHandler = new SimulationConditionsHandler(doc.getRocket(), context);
|
||||||
return conditionHandler;
|
return conditionHandler;
|
||||||
@ -1288,13 +1298,70 @@ class SingleSimulationHandler extends AbstractElementHandler {
|
|||||||
|
|
||||||
Simulation simulation = new Simulation(doc.getRocket(), status, name,
|
Simulation simulation = new Simulation(doc.getRocket(), status, name,
|
||||||
conditions, listeners, data);
|
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);
|
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 {
|
class SimulationConditionsHandler extends AbstractElementHandler {
|
||||||
private final DocumentLoadingContext context;
|
private final DocumentLoadingContext context;
|
||||||
private SimulationOptions conditions;
|
private SimulationOptions conditions;
|
||||||
@ -1605,7 +1672,8 @@ class FlightDataBranchHandler extends AbstractElementHandler {
|
|||||||
String[] split = typeList.split(",");
|
String[] split = typeList.split(",");
|
||||||
types = new FlightDataType[split.length];
|
types = new FlightDataType[split.length];
|
||||||
for (int i = 0; i < split.length; i++) {
|
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
|
// 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.SimulationExportPanel;
|
||||||
import net.sf.openrocket.gui.components.UnitSelector;
|
import net.sf.openrocket.gui.components.UnitSelector;
|
||||||
import net.sf.openrocket.gui.plot.Axis;
|
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.PlotConfiguration;
|
||||||
import net.sf.openrocket.gui.plot.SimulationPlotPanel;
|
import net.sf.openrocket.gui.plot.SimulationPlotPanel;
|
||||||
import net.sf.openrocket.gui.util.GUIUtil;
|
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 DEFAULT = -1;
|
||||||
public static final int EDIT = 1;
|
public static final int EDIT = 1;
|
||||||
public static final int PLOT = 2;
|
public static final int PLOT = 3;
|
||||||
|
|
||||||
|
|
||||||
private final Window parentWindow;
|
private final Window parentWindow;
|
||||||
@ -138,6 +139,8 @@ public class SimulationEditDialog extends JDialog {
|
|||||||
tabbedPane.addTab(trans.get("simedtdlg.tab.Launchcond"), flightConditionsTab());
|
tabbedPane.addTab(trans.get("simedtdlg.tab.Launchcond"), flightConditionsTab());
|
||||||
//// Simulation options
|
//// Simulation options
|
||||||
tabbedPane.addTab(trans.get("simedtdlg.tab.Simopt"), simulationOptionsTab());
|
tabbedPane.addTab(trans.get("simedtdlg.tab.Simopt"), simulationOptionsTab());
|
||||||
|
//// Custom expressions tab
|
||||||
|
tabbedPane.addTab(trans.get("simedtdlg.tab.CustomExpressions"), customExpressionsTab());
|
||||||
//// Plot data
|
//// Plot data
|
||||||
tabbedPane.addTab(trans.get("simedtdlg.tab.Plotdata"), plotTab());
|
tabbedPane.addTab(trans.get("simedtdlg.tab.Plotdata"), plotTab());
|
||||||
//// Export data
|
//// Export data
|
||||||
@ -147,7 +150,7 @@ public class SimulationEditDialog extends JDialog {
|
|||||||
if (tab == EDIT) {
|
if (tab == EDIT) {
|
||||||
tabbedPane.setSelectedIndex(0);
|
tabbedPane.setSelectedIndex(0);
|
||||||
} else if (tab == PLOT) {
|
} else if (tab == PLOT) {
|
||||||
tabbedPane.setSelectedIndex(2);
|
tabbedPane.setSelectedIndex(3);
|
||||||
} else {
|
} else {
|
||||||
FlightData data = s.getSimulatedData();
|
FlightData data = s.getSimulatedData();
|
||||||
if (data == null || data.getBranchCount() == 0)
|
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 PREFERENCES = loadImageIcon("pix/icons/preferences.png", "Preferences");
|
||||||
|
|
||||||
public static final Icon DELETE = loadImageIcon("pix/icons/delete.png", "Delete");
|
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 {
|
static {
|
||||||
log.debug("Icons loaded");
|
log.debug("Icons loaded");
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
package net.sf.openrocket.simulation;
|
package net.sf.openrocket.simulation;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -88,6 +89,12 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
|||||||
}
|
}
|
||||||
SimulationListenerHelper.firePostStep(status);
|
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
|
// Check for NaN values in the simulation status
|
||||||
checkNaN();
|
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.
|
* 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
|
//// 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
|
//// Vertical position and motion
|
||||||
//// Altitude
|
//// 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
|
//// 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
|
//// 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 motion
|
||||||
//// Total velocity
|
//// 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
|
//// 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
|
//// Lateral position and motion
|
||||||
//// Position upwind
|
//// 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
|
//// 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
|
//// 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
|
//// 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
|
//// 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
|
//// 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
|
//// 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
|
//// 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
|
//// Angular motion
|
||||||
//// Angle of attack
|
//// 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
|
//// 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
|
//// 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
|
//// 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
|
//// Stability information
|
||||||
//// Mass
|
//// 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
|
//// 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
|
//// 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
|
//// 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
|
//// 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
|
//// 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
|
//// Characteristic numbers
|
||||||
//// Mach number
|
//// 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
|
//// 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 and drag
|
||||||
//// Thrust
|
//// 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
|
//// 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
|
//// 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
|
//// 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
|
//// Component drag coefficients
|
||||||
//// Friction drag coefficient
|
//// 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
|
//// 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
|
//// 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
|
//// Other coefficients
|
||||||
//// Normal force coefficient
|
//// 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
|
//// 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
|
//// 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
|
//// 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
|
//// 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
|
//// 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
|
//// 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
|
//// 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
|
//// 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
|
//// 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 + area
|
||||||
//// Reference length
|
//// 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
|
//// 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
|
//// Orientation
|
||||||
//// Vertical orientation (zenith)
|
//// 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)
|
//// 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
|
//// Atmospheric conditions
|
||||||
//// Wind velocity
|
//// 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
|
//// 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
|
//// 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
|
//// 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 information
|
||||||
//// Simulation time step
|
//// 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
|
//// 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
|
* 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.
|
* @param u the unit group the new type should belong to if a new group is created.
|
||||||
* @return a data type.
|
* @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));
|
FlightDataType type = EXISTING_TYPES.get(s.toLowerCase(Locale.ENGLISH));
|
||||||
if (type != null) {
|
if (type != null) {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
type = newType(s, u, DEFAULT_PRIORITY);
|
type = newType(s, symbol, u, DEFAULT_PRIORITY);
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used while initializing the class.
|
* Used while initializing the class.
|
||||||
*/
|
*/
|
||||||
private static synchronized FlightDataType newType(String s, UnitGroup u, int priority) {
|
private static synchronized FlightDataType newType(String s, String symbol, UnitGroup u, int priority) {
|
||||||
FlightDataType type = new FlightDataType(s, u, priority);
|
FlightDataType type = new FlightDataType(s, symbol, u, priority);
|
||||||
EXISTING_TYPES.put(s.toLowerCase(Locale.ENGLISH), type);
|
EXISTING_TYPES.put(s.toLowerCase(Locale.ENGLISH), type);
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
|
private final String symbol;
|
||||||
private final UnitGroup units;
|
private final UnitGroup units;
|
||||||
private final int priority;
|
private final int priority;
|
||||||
private final int hashCode;
|
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)
|
if (typeName == null)
|
||||||
throw new IllegalArgumentException("typeName is null");
|
throw new IllegalArgumentException("typeName is null");
|
||||||
if (units == null)
|
if (units == null)
|
||||||
throw new IllegalArgumentException("units is null");
|
throw new IllegalArgumentException("units is null");
|
||||||
this.name = typeName;
|
this.name = typeName;
|
||||||
|
this.symbol = symbol;
|
||||||
this.units = units;
|
this.units = units;
|
||||||
this.priority = priority;
|
this.priority = priority;
|
||||||
this.hashCode = this.name.toLowerCase(Locale.ENGLISH).hashCode();
|
this.hashCode = this.name.toLowerCase(Locale.ENGLISH).hashCode();
|
||||||
@ -231,6 +287,10 @@ public class FlightDataType implements Comparable<FlightDataType> {
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getSymbol(){
|
||||||
|
return symbol;
|
||||||
|
}
|
||||||
|
|
||||||
public UnitGroup getUnitGroup() {
|
public UnitGroup getUnitGroup() {
|
||||||
return units;
|
return units;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import net.sf.openrocket.aerodynamics.AerodynamicCalculator;
|
import net.sf.openrocket.aerodynamics.AerodynamicCalculator;
|
||||||
|
import net.sf.openrocket.document.Simulation;
|
||||||
import net.sf.openrocket.masscalc.MassCalculator;
|
import net.sf.openrocket.masscalc.MassCalculator;
|
||||||
import net.sf.openrocket.models.atmosphere.AtmosphericModel;
|
import net.sf.openrocket.models.atmosphere.AtmosphericModel;
|
||||||
import net.sf.openrocket.models.gravity.GravityModel;
|
import net.sf.openrocket.models.gravity.GravityModel;
|
||||||
@ -27,6 +28,7 @@ public class SimulationConditions implements Monitorable, Cloneable {
|
|||||||
private Rocket rocket;
|
private Rocket rocket;
|
||||||
private String motorID = null;
|
private String motorID = null;
|
||||||
|
|
||||||
|
private Simulation simulation; // The parent simulation
|
||||||
|
|
||||||
private double launchRodLength = 1;
|
private double launchRodLength = 1;
|
||||||
|
|
||||||
@ -262,9 +264,14 @@ public class SimulationConditions implements Monitorable, Cloneable {
|
|||||||
this.modID++;
|
this.modID++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setSimulation(Simulation sim) {
|
||||||
|
this.simulation = sim;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Simulation getSimulation(){
|
||||||
|
return this.simulation;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// TODO: HIGH: Make cleaner
|
// TODO: HIGH: Make cleaner
|
||||||
public List<SimulationListener> getSimulationListenerList() {
|
public List<SimulationListener> getSimulationListenerList() {
|
||||||
return simulationListeners;
|
return simulationListeners;
|
||||||
|
|||||||
@ -5,8 +5,10 @@ import java.util.EventListener;
|
|||||||
import java.util.EventObject;
|
import java.util.EventObject;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import net.sf.openrocket.aerodynamics.BarrowmanCalculator;
|
import net.sf.openrocket.aerodynamics.BarrowmanCalculator;
|
||||||
|
import net.sf.openrocket.logging.LogHelper;
|
||||||
import net.sf.openrocket.masscalc.BasicMassCalculator;
|
import net.sf.openrocket.masscalc.BasicMassCalculator;
|
||||||
import net.sf.openrocket.models.atmosphere.AtmosphericModel;
|
import net.sf.openrocket.models.atmosphere.AtmosphericModel;
|
||||||
import net.sf.openrocket.models.atmosphere.ExtendedISAModel;
|
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.gravity.WGSGravityModel;
|
||||||
import net.sf.openrocket.models.wind.PinkNoiseWindModel;
|
import net.sf.openrocket.models.wind.PinkNoiseWindModel;
|
||||||
import net.sf.openrocket.rocketcomponent.Rocket;
|
import net.sf.openrocket.rocketcomponent.Rocket;
|
||||||
|
import net.sf.openrocket.startup.Application;
|
||||||
import net.sf.openrocket.util.BugException;
|
import net.sf.openrocket.util.BugException;
|
||||||
import net.sf.openrocket.util.ChangeSource;
|
import net.sf.openrocket.util.ChangeSource;
|
||||||
import net.sf.openrocket.util.GeodeticComputationStrategy;
|
import net.sf.openrocket.util.GeodeticComputationStrategy;
|
||||||
@ -31,6 +34,8 @@ import net.sf.openrocket.util.WorldCoordinate;
|
|||||||
*/
|
*/
|
||||||
public class SimulationOptions implements ChangeSource, Cloneable {
|
public class SimulationOptions implements ChangeSource, Cloneable {
|
||||||
|
|
||||||
|
private static final LogHelper log = Application.getLogger();
|
||||||
|
|
||||||
public static final double MAX_LAUNCH_ROD_ANGLE = Math.PI / 3;
|
public static final double MAX_LAUNCH_ROD_ANGLE = Math.PI / 3;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -93,7 +98,6 @@ public class SimulationOptions implements ChangeSource, Cloneable {
|
|||||||
this.rocket = rocket;
|
this.rocket = rocket;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Rocket getRocket() {
|
public Rocket getRocket() {
|
||||||
return rocket;
|
return rocket;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,8 +22,7 @@ public class RollControlListener extends AbstractSimulationListener {
|
|||||||
private static final String CONTROL_FIN_NAME = "CONTROL";
|
private static final String CONTROL_FIN_NAME = "CONTROL";
|
||||||
|
|
||||||
// Define custom flight data type
|
// Define custom flight data type
|
||||||
private static final FlightDataType FIN_CANT_TYPE = FlightDataType.getType("Control fin cant",
|
private static final FlightDataType FIN_CANT_TYPE = FlightDataType.getType("Control fin cant", "αfc", UnitGroup.UNITS_ANGLE);
|
||||||
UnitGroup.UNITS_ANGLE);
|
|
||||||
|
|
||||||
// Simulation time at which PID controller is activated
|
// Simulation time at which PID controller is activated
|
||||||
private static final double START_TIME = 0.5;
|
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