From: plaa Date: Thu, 18 Aug 2011 05:28:08 +0000 (+0000) Subject: preset component framework X-Git-Tag: upstream/1.1.8^2~3 X-Git-Url: https://git.gag.com/?a=commitdiff_plain;h=7783fc65bb6ae4d1f062f4db9e4b1f8dfb526f3d;p=debian%2Fopenrocket preset component framework git-svn-id: https://openrocket.svn.sourceforge.net/svnroot/openrocket/trunk@159 180e2498-e6e9-4542-8430-84ac67f01cd8 --- diff --git a/src/net/sf/openrocket/motor/MotorDigest.java b/src/net/sf/openrocket/motor/MotorDigest.java index e7fb9f5f..cec3cbdc 100644 --- a/src/net/sf/openrocket/motor/MotorDigest.java +++ b/src/net/sf/openrocket/motor/MotorDigest.java @@ -7,6 +7,17 @@ import java.security.NoSuchAlgorithmException; import net.sf.openrocket.util.Coordinate; import net.sf.openrocket.util.TextUtil; +/** + * A class that generated a "digest" of a motor. A digest is a string value that + * uniquely identifies a motor (like a hash code or checksum). Two motors that have + * the same digest behave similarly with a very high probability. The digest can + * therefore be used to identify motors that otherwise have the same specifications. + *

+ * The digest only uses a limited amount of precision, so that rounding errors won't + * cause differing digest results. + * + * @author Sampo Niskanen + */ public class MotorDigest { private static final double EPSILON = 0.00000000001; @@ -24,22 +35,25 @@ public class MotorDigest { CG_PER_TIME(4, 1000), /** Thrust force per time (in mN) */ FORCE_PER_TIME(5, 1000); - + private final int order; private final int multiplier; + DataType(int order, int multiplier) { this.order = order; this.multiplier = multiplier; } + public int getOrder() { return order; } + public int getMultiplier() { return multiplier; } } - + private final MessageDigest digest; private boolean used = false; private int lastOrder = -1; @@ -54,11 +68,11 @@ public class MotorDigest { } - public void update(DataType type, int ... values) { - + public void update(DataType type, int... values) { + // Check for correct order if (lastOrder >= type.getOrder()) { - throw new IllegalArgumentException("Called with type="+type+" order="+type.getOrder()+ + throw new IllegalArgumentException("Called with type=" + type + " order=" + type.getOrder() + " while lastOrder=" + lastOrder); } lastOrder = type.getOrder(); @@ -70,17 +84,17 @@ public class MotorDigest { digest.update(bytes(values.length)); // Digest the values - for (int v: values) { + for (int v : values) { digest.update(bytes(v)); } } - private void update(DataType type, int multiplier, double ... values) { - + private void update(DataType type, int multiplier, double... values) { + int[] intValues = new int[values.length]; - for (int i=0; i>>24) & 0xFF), (byte) ((value>>>16) & 0xFF), - (byte) ((value>>>8) & 0xFF), (byte) (value & 0xFF) - }; + (byte) ((value >>> 24) & 0xFF), (byte) ((value >>> 16) & 0xFF), + (byte) ((value >>> 8) & 0xFF), (byte) (value & 0xFF) }; } - + /** * Digest the contents of a thrust curve motor. The result is a string uniquely @@ -126,7 +139,7 @@ public class MotorDigest { * @return the digest */ public static String digestMotor(ThrustCurveMotor m) { - + // Create the motor digest from data available in RASP files MotorDigest motorDigest = new MotorDigest(); motorDigest.update(DataType.TIME_ARRAY, m.getTimePoints()); @@ -134,7 +147,7 @@ public class MotorDigest { Coordinate[] cg = m.getCGPoints(); double[] cgx = new double[cg.length]; double[] mass = new double[cg.length]; - for (int i=0; i componentClass, Manufacturer manufacturer, String partName, + String partNo, String partDescription, double mass, String materialName) { + super(componentClass, manufacturer, partName, partNo, partDescription); + + this.materialName = materialName; + this.mass = mass; + } + + + public String getMaterialName() { + return materialName; + } + + + public double getMass() { + return mass; + } + +} diff --git a/src/net/sf/openrocket/preset/RocketComponentPreset.java b/src/net/sf/openrocket/preset/RocketComponentPreset.java new file mode 100644 index 00000000..34940b00 --- /dev/null +++ b/src/net/sf/openrocket/preset/RocketComponentPreset.java @@ -0,0 +1,68 @@ +package net.sf.openrocket.preset; + +import net.sf.openrocket.motor.Manufacturer; +import net.sf.openrocket.rocketcomponent.RocketComponent; + +/** + * A model for a preset component. + *

+ * A preset component contains a component class type, manufacturer information, + * part information, and getter methods for various properties of the component. + * + * @author Sampo Niskanen + */ +public abstract class RocketComponentPreset { + + private final Class componentClass; + private final Manufacturer manufacturer; + private final String partName; + private final String partNo; + private final String partDescription; + + + public RocketComponentPreset(Class componentClass, Manufacturer manufacturer, + String partName, String partNo, String partDescription) { + this.componentClass = componentClass; + this.manufacturer = manufacturer; + this.partName = partName; + this.partNo = partNo; + this.partDescription = partDescription; + } + + + /** + * Return the component class that this preset defines. + */ + public Class getComponentClass() { + return componentClass; + } + + /** + * Return the manufacturer of this preset component. + */ + public Manufacturer getManufacturer() { + return manufacturer; + } + + /** + * Return the part name. This is a short, human-readable name of the part. + */ + public String getPartName() { + return partName; + } + + /** + * Return the part number. This is the part identifier (e.g. "BT-50"). + */ + public String getPartNo() { + return partNo; + } + + /** + * Return the part description. This is a longer description of the component. + */ + public String getPartDescription() { + return partDescription; + } + +} diff --git a/src/net/sf/openrocket/rocketcomponent/ComponentChangeEvent.java b/src/net/sf/openrocket/rocketcomponent/ComponentChangeEvent.java index 58d3297b..60123e87 100644 --- a/src/net/sf/openrocket/rocketcomponent/ComponentChangeEvent.java +++ b/src/net/sf/openrocket/rocketcomponent/ComponentChangeEvent.java @@ -4,8 +4,8 @@ import javax.swing.event.ChangeEvent; public class ComponentChangeEvent extends ChangeEvent { private static final long serialVersionUID = 1L; - + /** A change that does not affect simulation results in any way (name, color, etc.) */ public static final int NONFUNCTIONAL_CHANGE = 1; /** A change that affects the mass properties of the rocket */ @@ -13,15 +13,15 @@ public class ComponentChangeEvent extends ChangeEvent { /** A change that affects the aerodynamic properties of the rocket */ public static final int AERODYNAMIC_CHANGE = 4; /** A change that affects the mass and aerodynamic properties of the rocket */ - public static final int BOTH_CHANGE = MASS_CHANGE|AERODYNAMIC_CHANGE; // Mass & Aerodynamic - + public static final int BOTH_CHANGE = MASS_CHANGE | AERODYNAMIC_CHANGE; // Mass & Aerodynamic + /** A change that affects the rocket tree structure */ public static final int TREE_CHANGE = 8; /** A change caused by undo/redo. */ public static final int UNDO_CHANGE = 16; /** A change in the motor configurations or names */ public static final int MOTOR_CHANGE = 32; - /** A change in the events occurring during flight. */ + /** A change that affects the events occurring during flight. */ public static final int EVENT_CHANGE = 64; /** A bit-field that contains all possible change types. */ @@ -29,7 +29,7 @@ public class ComponentChangeEvent extends ChangeEvent { private final int type; - + public ComponentChangeEvent(RocketComponent component, int type) { super(component); if (type == 0) { @@ -46,8 +46,8 @@ public class ComponentChangeEvent extends ChangeEvent { public RocketComponent getSource() { return (RocketComponent) super.getSource(); } - - + + public boolean isAerodynamicChange() { return (type & AERODYNAMIC_CHANGE) != 0; } @@ -71,7 +71,7 @@ public class ComponentChangeEvent extends ChangeEvent { public boolean isMotorChange() { return (type & MOTOR_CHANGE) != 0; } - + public int getType() { return type; } diff --git a/src/net/sf/openrocket/rocketcomponent/ExternalComponent.java b/src/net/sf/openrocket/rocketcomponent/ExternalComponent.java index 64c1a50e..23cea240 100644 --- a/src/net/sf/openrocket/rocketcomponent/ExternalComponent.java +++ b/src/net/sf/openrocket/rocketcomponent/ExternalComponent.java @@ -4,6 +4,9 @@ import java.util.List; import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.material.Material; +import net.sf.openrocket.material.Material.Type; +import net.sf.openrocket.preset.ExternalComponentPreset; +import net.sf.openrocket.preset.RocketComponentPreset; import net.sf.openrocket.startup.Application; import net.sf.openrocket.unit.UnitGroup; import net.sf.openrocket.util.Prefs; @@ -111,6 +114,7 @@ public abstract class ExternalComponent extends RocketComponent { if (material.equals(mat)) return; material = mat; + clearPreset(); fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE); } @@ -126,6 +130,27 @@ public abstract class ExternalComponent extends RocketComponent { } + @Override + protected void loadFromPreset(RocketComponentPreset preset) { + super.loadFromPreset(preset); + + ExternalComponentPreset p = (ExternalComponentPreset) preset; + String materialName = p.getMaterialName(); + double mass = p.getMass(); + + double volume = getComponentVolume(); + double density; + if (volume > 0.00001) { + density = mass / volume; + } else { + density = 1000; + } + + Material mat = Material.newMaterial(Type.BULK, materialName, density, true); + setMaterial(mat); + } + + @Override protected List copyFrom(RocketComponent c) { ExternalComponent src = (ExternalComponent) c; diff --git a/src/net/sf/openrocket/rocketcomponent/RocketComponent.java b/src/net/sf/openrocket/rocketcomponent/RocketComponent.java index f9b28ea3..b0c7b47e 100644 --- a/src/net/sf/openrocket/rocketcomponent/RocketComponent.java +++ b/src/net/sf/openrocket/rocketcomponent/RocketComponent.java @@ -12,6 +12,7 @@ import javax.swing.event.ChangeListener; import net.sf.openrocket.l10n.Translator; import net.sf.openrocket.logging.LogHelper; +import net.sf.openrocket.preset.RocketComponentPreset; import net.sf.openrocket.startup.Application; import net.sf.openrocket.util.ArrayList; import net.sf.openrocket.util.BugException; @@ -123,6 +124,10 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab // Unique ID of the component private String id = null; + // Preset component this component is based upon + private RocketComponentPreset presetComponent = null; + + /** * Used to invalidate the component after calling {@link #copyFrom(RocketComponent)}. */ @@ -659,6 +664,89 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab + /** + * Return the preset component that this component is based upon. + * + * @return the preset component, or null if this is not based on a preset. + */ + public final RocketComponentPreset getPresetComponent() { + return presetComponent; + } + + /** + * Set the preset component this component is based upon and load all of the + * preset values. + * + * @param preset the preset component to load, or null to clear the preset. + */ + public final void loadPreset(RocketComponentPreset preset) { + if (presetComponent == preset) { + return; + } + + if (preset == null) { + clearPreset(); + return; + } + + if (preset.getComponentClass() != this.getClass()) { + throw new IllegalArgumentException("Attempting to load preset of type " + preset.getComponentClass() + + " into component of type " + this.getClass()); + } + + RocketComponent root = getRoot(); + final Rocket rocket; + if (root instanceof Rocket) { + rocket = (Rocket) root; + } else { + rocket = null; + } + + try { + if (rocket != null) { + rocket.freeze(); + } + + loadFromPreset(preset); + + this.presetComponent = preset; + fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE); + + } finally { + if (rocket != null) { + rocket.thaw(); + } + } + } + + + /** + * Load component properties from the specified preset. The preset is guaranteed + * to be of the correct type. + *

+ * This method should fire the appropriate events related to the changes. The rocket + * is frozen by the caller, so the events will be automatically combined. + * + * @param preset the preset to load from + */ + protected void loadFromPreset(RocketComponentPreset preset) { + // No-op + } + + + /** + * Clear the current component preset. This does not affect the component properties + * otherwise. + */ + public final void clearPreset() { + if (presetComponent == null) + return; + presetComponent = null; + fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE); + } + + + /** * Returns the unique ID of the component. *