Add rail button presets options

Allow rail buttons to define presets. This change doesn't actually add
any default presets to the library, but enables the ability to add some
preset options for rail buttons.

Partially Closes #554

Signed-off-by: Billy Olsen <billy.olsen@gmail.com>
This commit is contained in:
Billy Olsen 2020-03-01 18:24:54 -07:00
parent 232b363712
commit f8993e89db
7 changed files with 397 additions and 0 deletions

View File

@ -200,6 +200,8 @@ public class ComponentPreset implements Comparable<ComponentPreset>, Serializabl
public final static TypedKey<Double> LINE_LENGTH = new TypedKey<Double>("LineLength", Double.class, UnitGroup.UNITS_LENGTH);
public final static TypedKey<Material> LINE_MATERIAL = new TypedKey<Material>("LineMaterial", Material.class);
public final static TypedKey<byte[]> IMAGE = new TypedKey<byte[]>("Image", byte[].class);
public final static TypedKey<Double> STANDOFF_HEIGHT = new TypedKey<Double>("StandoffHeight", Double.class, UnitGroup.UNITS_LENGTH);
public final static TypedKey<Double> FLANGE_HEIGHT = new TypedKey<Double>("FlangeHeight", Double.class, UnitGroup.UNITS_LENGTH);
public final static List<TypedKey<?>> ORDERED_KEY_LIST = Collections.unmodifiableList(Arrays.<TypedKey<?>> asList(
MANUFACTURER,
@ -215,6 +217,8 @@ public class ComponentPreset implements Comparable<ComponentPreset>, Serializabl
AFT_SHOULDER_LENGTH,
FORE_SHOULDER_DIAMETER,
FORE_SHOULDER_LENGTH,
STANDOFF_HEIGHT,
FLANGE_HEIGHT,
SHAPE,
THICKNESS,
FILLED,

View File

@ -5,6 +5,7 @@ import net.sf.openrocket.database.Databases;
import net.sf.openrocket.material.Material;
import net.sf.openrocket.preset.ComponentPreset.Type;
import net.sf.openrocket.rocketcomponent.NoseCone;
import net.sf.openrocket.rocketcomponent.RailButton;
import net.sf.openrocket.rocketcomponent.Transition;
public abstract class ComponentPresetFactory {
@ -67,6 +68,10 @@ public abstract class ComponentPresetFactory {
makeBodyTube(exceptions, preset);
break;
}
case RAIL_BUTTON: {
makeRailButton(exceptions, preset);
break;
}
case STREAMER: {
makeStreamer(exceptions, preset);
break;
@ -108,6 +113,30 @@ public abstract class ComponentPresetFactory {
}
private static void makeRailButton(InvalidComponentPresetException exceptions, ComponentPreset preset) throws InvalidComponentPresetException {
checkRequiredFields(exceptions, preset, HEIGHT);
checkRequiredFields(exceptions, preset, OUTER_DIAMETER);
checkRequiredFields(exceptions, preset, INNER_DIAMETER);
checkRequiredFields(exceptions, preset, FLANGE_HEIGHT);
checkRequiredFields(exceptions, preset, STANDOFF_HEIGHT);
if (preset.has(MASS)) {
double mass = preset.get(MASS);
RailButton rb = new RailButton();
rb.loadPreset(preset);
double density = mass / rb.getComponentVolume();
String materialName = "RailButtonCustom";
if (preset.has(MATERIAL)) {
materialName = preset.get(MATERIAL).getName();
}
Material m = Databases.findMaterial(Material.Type.BULK, materialName, density);
preset.put(MATERIAL, m);
}
}
private static void makeNoseCone(InvalidComponentPresetException exceptions, ComponentPreset preset) {
checkRequiredFields(exceptions, preset, LENGTH, SHAPE, AFT_OUTER_DIAMETER);

View File

@ -0,0 +1,32 @@
package net.sf.openrocket.preset.loader;
import net.sf.openrocket.preset.ComponentPreset;
import net.sf.openrocket.preset.ComponentPreset.Type;
import java.io.File;
public class RailButtonLoader extends BaseComponentLoader {
public RailButtonLoader(MaterialHolder materials, File theBasePath) {
super(materials, theBasePath);
fileColumns.add(new DoubleUnitColumnParser("ID","Units",ComponentPreset.INNER_DIAMETER));
fileColumns.add(new DoubleUnitColumnParser("OD","Units",ComponentPreset.OUTER_DIAMETER));
fileColumns.add(new DoubleUnitColumnParser("Height","Units",ComponentPreset.HEIGHT));
fileColumns.add(new DoubleUnitColumnParser("Flange Height", "Units", ComponentPreset.FLANGE_HEIGHT));
fileColumns.add(new DoubleUnitColumnParser("Standoff Height", "Units", ComponentPreset.STANDOFF_HEIGHT));
}
@Override
protected Type getComponentPresetType() {
return ComponentPreset.Type.RAIL_BUTTON;
}
@Override
protected RocksimComponentFileType getFileType() {
return RocksimComponentFileType.LAUNCH_LUG;
}
}

View File

@ -39,6 +39,7 @@ public class OpenRocketComponentDTO {
@XmlElementRef(name = "CenteringRings", type = CenteringRingDTO.class),
@XmlElementRef(name = "EngineBlocks", type = EngineBlockDTO.class),
@XmlElementRef(name = "LaunchLugs", type = LaunchLugDTO.class),
@XmlElementRef(name = "RailButtons", type = RailButtonDTO.class),
@XmlElementRef(name = "Streamers", type = StreamerDTO.class),
@XmlElementRef(name = "Parachutes", type = ParachuteDTO.class)})
private List<BaseComponentDTO> components = new ArrayList<BaseComponentDTO>();

View File

@ -198,6 +198,8 @@ public class OpenRocketComponentSaver {
return new EngineBlockDTO(thePreset);
case LAUNCH_LUG:
return new LaunchLugDTO(thePreset);
case RAIL_BUTTON:
return new RailButtonDTO(thePreset);
case STREAMER:
return new StreamerDTO(thePreset);
case PARACHUTE:

View File

@ -0,0 +1,132 @@
package net.sf.openrocket.preset.xml;
import net.sf.openrocket.preset.ComponentPreset;
import net.sf.openrocket.preset.ComponentPresetFactory;
import net.sf.openrocket.preset.InvalidComponentPresetException;
import net.sf.openrocket.preset.TypedPropertyMap;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.List;
/**
* Body tube preset XML handler.
*/
@XmlRootElement(name = "RailButton")
@XmlAccessorType(XmlAccessType.FIELD)
public class RailButtonDTO extends BaseComponentDTO {
@XmlElement(name = "InsideDiameter")
private AnnotatedLengthDTO insideDiameter;
@XmlElement(name = "OutsideDiameter")
private AnnotatedLengthDTO outsideDiameter;
@XmlElement(name = "Height")
private AnnotatedLengthDTO height;
@XmlElement(name = "StandoffHeight")
private AnnotatedLengthDTO standoffHeight;
@XmlElement(name = "FlangeHeight")
private AnnotatedLengthDTO flangeHeight;
/**
* Default constructor.
*/
public RailButtonDTO() {
}
/**
* Most-useful constructor that maps a RailButton preset to a RailButtonDTO.
*
* @param preset the preset
*
* @throws net.sf.openrocket.util.BugException thrown if the expected body tube keys are not in the preset
*/
public RailButtonDTO(final ComponentPreset preset) {
super(preset);
setInsideDiameter(preset.get(ComponentPreset.INNER_DIAMETER));
setOutsideDiameter(preset.get(ComponentPreset.OUTER_DIAMETER));
setHeight(preset.get(ComponentPreset.HEIGHT));
setStandoffHeight(preset.get(ComponentPreset.STANDOFF_HEIGHT));
setFlangeHeight(preset.get(ComponentPreset.FLANGE_HEIGHT));
}
public double getInsideDiameter() {
return insideDiameter.getValue();
}
public void setInsideDiameter( final AnnotatedLengthDTO theLength ) {
insideDiameter = theLength;
}
public void setInsideDiameter(final double theId) {
insideDiameter = new AnnotatedLengthDTO(theId);
}
public double getOutsideDiameter() {
return outsideDiameter.getValue();
}
public void setOutsideDiameter(final AnnotatedLengthDTO theOd) {
outsideDiameter = theOd;
}
public void setOutsideDiameter(final double theOd) {
outsideDiameter = new AnnotatedLengthDTO(theOd);
}
public double getHeight() {
return height.getValue();
}
public void setHeight(final AnnotatedLengthDTO theHeight) {
height = theHeight;
}
public void setHeight(final double theHeight) {
height = new AnnotatedLengthDTO(theHeight);
}
public double getStandoffHeight() {
return standoffHeight.getValue();
}
public void setStandoffHeight(final AnnotatedLengthDTO theStandoffHeight) {
standoffHeight = theStandoffHeight;
}
public void setStandoffHeight(final double theStandoffHeight) {
standoffHeight = new AnnotatedLengthDTO(theStandoffHeight);
}
public double getFlangeHeight() {
return flangeHeight.getValue();
}
public void setFlangeHeight(final AnnotatedLengthDTO theFlangeHeight) {
flangeHeight = theFlangeHeight;
}
public void setFlangeHeight(final double theFlangeHeight) {
flangeHeight = new AnnotatedLengthDTO(theFlangeHeight);
}
@Override
public ComponentPreset asComponentPreset(java.util.List<MaterialDTO> materials) throws InvalidComponentPresetException {
return asComponentPreset(ComponentPreset.Type.RAIL_BUTTON, materials);
}
public ComponentPreset asComponentPreset(ComponentPreset.Type type, List<MaterialDTO> materials) throws InvalidComponentPresetException {
TypedPropertyMap props = new TypedPropertyMap();
addProps(props, materials);
props.put(ComponentPreset.INNER_DIAMETER, this.getInsideDiameter());
props.put(ComponentPreset.OUTER_DIAMETER, this.getOutsideDiameter());
props.put(ComponentPreset.HEIGHT, this.getHeight());
props.put(ComponentPreset.STANDOFF_HEIGHT, this.getStandoffHeight());
props.put(ComponentPreset.FLANGE_HEIGHT, this.getFlangeHeight());
props.put(ComponentPreset.TYPE, type);
return ComponentPresetFactory.create(props);
}
}

View File

@ -168,6 +168,17 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
private ImageIcon llImage;
private JButton llImageBtn;
private JTextField rbPartNoTextField;
private JTextField rbDescTextField;
private DoubleModel rbOuterDia;
private DoubleModel rbInnerDia;
private DoubleModel rbHeight;
private DoubleModel rbStandoffHeight;
private DoubleModel rbFlangeHeight;
private DoubleModel rbMass;
private ImageIcon rbImage;
private JButton rbImageBtn;
private JTextField stPartNoTextField;
private JTextField stDescTextField;
private DoubleModel stThickness;
@ -204,6 +215,7 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
private static final String BULKHEAD_KEY = "Bulkhead.Bulkhead";
private static final String EB_KEY = "ComponentIcons.Engineblock";
private static final String LAUNCH_LUG_KEY = "ComponentIcons.Launchlug";
private static final String RAIL_BUTTON_KEY = "ComponentIcons.RailButton";
private static final String STREAMER_KEY = "ComponentIcons.Streamer";
private static final String PARACHUTE_KEY = "ComponentIcons.Parachute";
@ -217,6 +229,7 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
componentMap.put(trans.get(BULKHEAD_KEY), "BULKHEAD");
componentMap.put(trans.get(EB_KEY), "ENGINEBLOCK");
componentMap.put(trans.get(LAUNCH_LUG_KEY), "LAUNCHLUG");
componentMap.put(trans.get(RAIL_BUTTON_KEY), "RAILBUTTON");
componentMap.put(trans.get(PARACHUTE_KEY), "PARACHUTE");
componentMap.put(trans.get(STREAMER_KEY), "STREAMER");
}
@ -961,6 +974,103 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
});
}
// Railbutton
{
JPanel rbPanel = new JPanel();
componentOverlayPanel.add(rbPanel, "RAILBUTTON");
rbPanel.setLayout(new MigLayout("", "[][grow][][grow]", "[][][][]"));
JLabel rbPartNoLabel = new JLabel("Part No:");
rbPanel.add(rbPartNoLabel, "cell 0 0,alignx left");
rbPartNoTextField = new JTextField();
rbPanel.add(rbPartNoTextField, "cell 1 0,growx");
rbPartNoTextField.setColumns(10);
JLabel rbDescLabel = new JLabel("Description:");
rbPanel.add(rbDescLabel, "cell 3 0,alignx left");
rbDescTextField = new JTextField();
rbPanel.add(rbDescTextField, "cell 4 0,growx");
rbDescTextField.setColumns(10);
JLabel rbOuterDiaLabel = new JLabel("Outer Dia.:");
rbPanel.add(rbOuterDiaLabel, "cell 0 1,alignx left");
rbOuterDia = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
JSpinner spin = new JSpinner(rbOuterDia.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
rbPanel.add(spin, "cell 1 1, growx");
rbPanel.add(new UnitSelector(rbOuterDia), "growx");
JLabel rbMassLabel = new JLabel("Mass:");
rbPanel.add(rbMassLabel, "cell 3 1,alignx left");
rbMass = new DoubleModel(0, UnitGroup.UNITS_MASS, 0);
spin = new JSpinner(rbMass.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
rbPanel.add(spin, "cell 4 1, growx");
rbPanel.add(new UnitSelector(llMass), "w 34lp!");
JLabel rbInnerDiaLabel = new JLabel("Inner Dia.:");
rbPanel.add(rbInnerDiaLabel, "cell 0 2,alignx left");
rbInnerDia = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
spin = new JSpinner(rbInnerDia.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
rbPanel.add(spin, "cell 1 2, growx");
rbPanel.add(new UnitSelector(rbInnerDia), "growx");
JLabel rbHeightLabel = new JLabel("Height:");
rbPanel.add(rbHeightLabel, "cell 3 2,alignx left");
rbHeight = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
spin = new JSpinner(rbHeight.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
rbPanel.add(spin, "cell 4 2, growx");
rbPanel.add(new UnitSelector(rbHeight), "w 34lp!");
JLabel rbStandoffLabel = new JLabel("Standoff:");
rbPanel.add(rbStandoffLabel, "cell 0 3,alignx left");
rbStandoffHeight = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
spin = new JSpinner(rbStandoffHeight.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
rbPanel.add(spin, "cell 1 3, growx");
rbPanel.add(new UnitSelector(rbStandoffHeight), "growx");
JLabel rbFlangeLabel = new JLabel("Flange:");
rbPanel.add(rbFlangeLabel, "cell 3 3,alignx left");
rbFlangeHeight = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
spin = new JSpinner(rbFlangeHeight.getSpinnerModel());
spin.setEditor(new SpinnerEditor(spin));
rbPanel.add(spin, "cell 4 3, growx");
rbPanel.add(new UnitSelector(rbFlangeHeight), "w 34lp!");
JPanel panel = new JPanel();
panel.setMinimumSize(new Dimension(200, 200));
rbPanel.add(panel, "cell 4 4");
panel.setLayout(null);
rbImageBtn = new JButton("No Image");
rbImageBtn.setMaximumSize(new Dimension(75, 75));
rbImageBtn.setMinimumSize(new Dimension(75, 75));
panel.add(rbImageBtn);
rbImageBtn.setBounds(new Rectangle(6, 6, 132, 145));
rbImageBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent e) {
int returnVal = imageChooser.showOpenDialog(PresetEditorDialog.this);
if (returnVal == JFileChooser.APPROVE_OPTION) {
File file = imageChooser.getSelectedFile();
rbImage = scaleImage(new ImageIcon(file.getAbsolutePath()).getImage(), 155);
rbImageBtn.setIcon(rbImage);
}
}
});
}
{
JPanel stPanel = new JPanel();
componentOverlayPanel.add(stPanel, "STREAMER");
@ -1188,6 +1298,7 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
cb.addItem(trans.get(TRANSITION_KEY), preset != null && !preset.get(ComponentPreset.TYPE).equals(ComponentPreset.Type.TRANSITION));
cb.addItem(trans.get(TUBE_COUPLER_KEY), preset != null && !preset.get(ComponentPreset.TYPE).equals(ComponentPreset.Type.TUBE_COUPLER));
cb.addItem(trans.get(LAUNCH_LUG_KEY), preset != null && !preset.get(ComponentPreset.TYPE).equals(ComponentPreset.Type.LAUNCH_LUG));
cb.addItem(trans.get(RAIL_BUTTON_KEY), preset != null && !preset.get(ComponentPreset.TYPE).equals(ComponentPreset.Type.RAIL_BUTTON));
cb.addItem(trans.get(PARACHUTE_KEY), preset != null && !preset.get(ComponentPreset.TYPE).equals(ComponentPreset.Type.PARACHUTE));
cb.addItem(trans.get(STREAMER_KEY), preset != null && !preset.get(ComponentPreset.TYPE).equals(ComponentPreset.Type.STREAMER));
}
@ -1447,6 +1558,40 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
llImageBtn.setIcon(llImage);
}
break;
case RAIL_BUTTON:
typeCombo.setSelectedItem(trans.get(RAIL_BUTTON_KEY));
rbDescTextField.setText(preset.get(ComponentPreset.DESCRIPTION));
if (preset.has(ComponentPreset.INNER_DIAMETER)) {
rbInnerDia.setValue(preset.get(ComponentPreset.INNER_DIAMETER));
rbInnerDia.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
}
if (preset.has(ComponentPreset.OUTER_DIAMETER)) {
rbOuterDia.setValue(preset.get(ComponentPreset.OUTER_DIAMETER));
rbOuterDia.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
}
if (preset.has(ComponentPreset.HEIGHT)) {
rbHeight.setValue(preset.get(ComponentPreset.HEIGHT));
rbHeight.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
}
if (preset.has(ComponentPreset.STANDOFF_HEIGHT)) {
rbStandoffHeight.setValue(preset.get(ComponentPreset.STANDOFF_HEIGHT));
rbStandoffHeight.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
}
if (preset.has(ComponentPreset.FLANGE_HEIGHT)) {
rbFlangeHeight.setValue(preset.get(ComponentPreset.FLANGE_HEIGHT));
rbFlangeHeight.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
}
if (preset.has(ComponentPreset.MASS)) {
rbMass.setValue(preset.get(ComponentPreset.MASS));
rbMass.setCurrentUnit(UnitGroup.UNITS_MASS.getDefaultUnit());
}
rbPartNoTextField.setText(preset.get(ComponentPreset.PARTNO));
if (preset.has(ComponentPreset.IMAGE)) {
rbImage = new ImageIcon(byteArrayToImage(preset.get(ComponentPreset.IMAGE)));
rbImageBtn.setIcon(llImage);
}
break;
case PARACHUTE:
setMaterial(materialChooser, preset, matHolder, Material.Type.SURFACE, ComponentPreset.MATERIAL);
typeCombo.setSelectedItem(trans.get(PARACHUTE_KEY));
@ -1579,6 +1724,12 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
clearLaunchLug();
}
}
else if (type.equals(trans.get(RAIL_BUTTON_KEY))) {
result = extractRailButton();
if (result != null) {
clearRailButton();
}
}
else if (type.equals(trans.get(PARACHUTE_KEY))) {
result = extractParachute();
if (result != null) {
@ -1954,6 +2105,52 @@ public class PresetEditorDialog extends JDialog implements ItemListener {
llImageBtn.setIcon(null);
}
public ComponentPreset extractRailButton() {
TypedPropertyMap props = new TypedPropertyMap();
try {
props.put(ComponentPreset.TYPE, ComponentPreset.Type.RAIL_BUTTON);
props.put(ComponentPreset.OUTER_DIAMETER, rbOuterDia.getValue());
props.put(ComponentPreset.INNER_DIAMETER, rbInnerDia.getValue());
props.put(ComponentPreset.STANDOFF_HEIGHT, rbStandoffHeight.getValue());
props.put(ComponentPreset.FLANGE_HEIGHT, rbFlangeHeight.getValue());
props.put(ComponentPreset.DESCRIPTION, rbDescTextField.getText());
props.put(ComponentPreset.PARTNO, rbPartNoTextField.getText());
props.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer(mfgTextField.getText()));
props.put(ComponentPreset.HEIGHT, rbHeight.getValue());
final Material material = (Material) materialChooser.getSelectedItem();
if (material != null) {
props.put(ComponentPreset.MATERIAL, material);
}
else {
JOptionPane.showMessageDialog(null, "A material must be selected.", "Error", JOptionPane.ERROR_MESSAGE);
return null;
}
props.put(ComponentPreset.MASS, rbMass.getValue());
if (llImage != null) {
props.put(ComponentPreset.IMAGE, imageToByteArray(rbImage.getImage()));
}
return ComponentPresetFactory.create(props);
} catch (NumberFormatException nfe) {
JOptionPane.showMessageDialog(null, "Could not convert rail button attribute.", "Error", JOptionPane.ERROR_MESSAGE);
} catch (InvalidComponentPresetException e) {
JOptionPane.showMessageDialog(null, craftErrorMessage(e, "Mandatory rail button attribute not set."), "Error", JOptionPane.ERROR_MESSAGE);
}
return null;
}
private void clearRailButton() {
rbOuterDia.setValue(0);
rbInnerDia.setValue(0);
rbDescTextField.setText("");
rbPartNoTextField.setText("");
rbFlangeHeight.setValue(0);
rbHeight.setValue(0);
rbStandoffHeight.setValue(0);
rbMass.setValue(0);
rbImage = null;
rbImageBtn.setIcon(null);
}
public ComponentPreset extractParachute() {
TypedPropertyMap props = new TypedPropertyMap();
try {