+2011-08-25 Sampo Niskanen
+
+ * [BUG] Ignore synthetic methods in logging traces
+ * [BUG] Ignore JRE bug #6826104
+
+2011-08-24 Sampo Niskanen
+
+ * [BUG] NPE in SimulationOptions.equals
+ * [BUG] Exception in plotting optimization path
+ * [BUG] Exception in saving optimization path
+
2011-08-17 Justin Seitz
* Added Blue tube to materials database.
@Override
public void actionPerformed(ActionEvent e) {
log.user("Plotting optimization path, dimensionality=" + selectedModifiers.size());
- OptimizationPlotDialog dialog = new OptimizationPlotDialog(optimizationPath, evaluationHistory,
- selectedModifiers, getSelectedParameter(),
+ OptimizationPlotDialog dialog = new OptimizationPlotDialog(
+ Collections.unmodifiableList(optimizationPath),
+ Collections.unmodifiableMap(evaluationHistory),
+ Collections.unmodifiableList(selectedModifiers),
+ getSelectedParameter(),
UnitGroup.stabilityUnits(getSelectedSimulation().getRocket()),
GeneralOptimizationDialog.this);
dialog.setVisible(true);
});
timer.setRepeats(false);
timer.start();
+ updateComponents();
}
@Override
* Update the enabled status of all components in the dialog.
*/
private void updateComponents() {
+ boolean state;
if (updating) {
+ log.debug("Ignoring updateComponents");
return;
}
+ log.debug("Running updateComponents()");
+
updating = true;
// First enable all components if optimization not running
if (!running) {
+ log.debug("Initially enabling all components");
for (JComponent c : disableComponents) {
c.setEnabled(true);
}
// "Add" button
SimulationModifier mod = getSelectedAvailableModifier();
- if (mod != null && !selectedModifiers.contains(mod)) {
- addButton.setEnabled(true);
- } else {
- addButton.setEnabled(false);
- }
+ state = (mod != null && !selectedModifiers.contains(mod));
+ log.debug("addButton enabled: " + state);
+ addButton.setEnabled(state);
// "Remove" button
- removeButton.setEnabled(selectedModifierTable.getSelectedRow() >= 0);
+ state = (selectedModifierTable.getSelectedRow() >= 0);
+ log.debug("removeButton enabled: " + state);
+ removeButton.setEnabled(state);
// "Remove all" button
- removeAllButton.setEnabled(!selectedModifiers.isEmpty());
+ state = (!selectedModifiers.isEmpty());
+ log.debug("removeAllButton enabled: " + state);
+ removeAllButton.setEnabled(state);
// Optimization goal
String selected = (String) optimizationGoalCombo.getSelectedItem();
- if (GOAL_SEEK.equals(selected)) {
- optimizationGoalSpinner.setVisible(true);
- optimizationGoalUnitSelector.setVisible(true);
- } else {
- optimizationGoalSpinner.setVisible(false);
- optimizationGoalUnitSelector.setVisible(false);
- }
+ state = GOAL_SEEK.equals(selected);
+ log.debug("optimizationGoalSpinner & UnitSelector enabled: " + state);
+ optimizationGoalSpinner.setVisible(state);
+ optimizationGoalUnitSelector.setVisible(state);
// Minimum/maximum stability options
- minimumStabilitySpinner.setEnabled(minimumStabilitySelected.isSelected());
- minimumStabilityUnitSelector.setEnabled(minimumStabilitySelected.isSelected());
- maximumStabilitySpinner.setEnabled(maximumStabilitySelected.isSelected());
- maximumStabilityUnitSelector.setEnabled(maximumStabilitySelected.isSelected());
+ state = minimumStabilitySelected.isSelected();
+ log.debug("minimumStabilitySpinner & UnitSelector enabled: " + state);
+ minimumStabilitySpinner.setEnabled(state);
+ minimumStabilityUnitSelector.setEnabled(state);
+
+ state = maximumStabilitySelected.isSelected();
+ log.debug("maximumStabilitySpimmer & UnitSelector enabled: " + state);
+ maximumStabilitySpinner.setEnabled(state);
+ maximumStabilityUnitSelector.setEnabled(state);
// Plot button (enabled if path exists and dimensionality is 1 or 2)
- plotButton.setEnabled(!optimizationPath.isEmpty() && (selectedModifiers.size() == 1 || selectedModifiers.size() == 2));
+ state = (!optimizationPath.isEmpty() && (selectedModifiers.size() == 1 || selectedModifiers.size() == 2));
+ log.debug("plotButton enabled: " + state + " optimizationPath.isEmpty=" + optimizationPath.isEmpty() +
+ " selectedModifiers.size=" + selectedModifiers.size());
+ plotButton.setEnabled(state);
// Save button (enabled if path exists)
- saveButton.setEnabled(!optimizationPath.isEmpty());
+ state = (!evaluationHistory.isEmpty());
+ log.debug("saveButton enabled: " + state);
+ saveButton.setEnabled(state);
// Last disable all components if optimization is running
if (running) {
+ log.debug("Disabling all components because optimization is running");
for (JComponent c : disableComponents) {
c.setEnabled(false);
}
@Override
public void setValueAt(Object value, int row, int column) {
+ if (row >= selectedModifiers.size()) {
+ throw new BugException("setValueAt with invalid row: value=" + value + " row=" + row + " column=" + column +
+ " selectedModifiers.size=" + selectedModifiers.size() + " selectedModifiers=" + selectedModifiers +
+ " selectedModifierTable.getRowCount=" + selectedModifierTable.getRowCount());
+ }
+
switch (column) {
case PARAMETER:
break;
double x1 = xUnit.toUnit(modX.getMinValue());
double x2 = xUnit.toUnit(modX.getMaxValue());
- chart.getXYPlot().getDomainAxis().setRange(x1, x2);
+ if (x1 < x2 - 0.0001) {
+ log.debug("Setting 1D plot domain axis x1=" + x1 + " x2=" + x2);
+ chart.getXYPlot().getDomainAxis().setRange(x1, x2);
+ } else {
+ log.warn("1D plot domain singular x1=" + x1 + " x2=" + x2 + ", not setting");
+ }
// Add lines to show optimization limits
XYLineAnnotation line = new XYLineAnnotation(x1, -1e19, x1, 1e19);
double y1 = yUnit.toUnit(modY.getMinValue());
double y2 = yUnit.toUnit(modY.getMaxValue());
- chart.getXYPlot().getDomainAxis().setRange(x1, x2);
- chart.getXYPlot().getRangeAxis().setRange(y1, y2);
+ if (x1 < x2 - 0.0001) {
+ log.debug("Setting 2D plot domain axis to x1=" + x1 + " x2=" + x2);
+ chart.getXYPlot().getDomainAxis().setRange(x1, x2);
+ } else {
+ log.warn("2D plot has singular domain axis: x1=" + x1 + " x2=" + x2);
+ }
+
+ if (y1 < y2 - 0.0001) {
+ log.debug("Setting 2D plot range axis to y1=" + y1 + " y2=" + y2);
+ chart.getXYPlot().getRangeAxis().setRange(y1, y2);
+ } else {
+ log.warn("2D plot has singular range axis: y1=" + y1 + " y2=" + y2);
+ }
XYBoxAnnotation box = new XYBoxAnnotation(x1, y1, x2, y2);
chart.getXYPlot().addAnnotation(box);
text.setTextAnchor(TextAnchor.BASELINE_LEFT);
chart.getXYPlot().addAnnotation(text);
+
+ if (min < max - 0.0001) {
+ log.debug("Setting gradient scale range to min=" + min + " max=" + max);
+ } else {
+ log.warn("2D plot has singular gradient scale, resetting to (0,1): min=" + min + " max=" + max);
+ min = 0;
+ max = 1;
+ }
+
PaintScale paintScale = new GradientScale(min, max);
XYShapeRenderer shapeRenderer = new XYShapeRenderer();
// NOTE: Calling method logs the entire throwable, so log only message here
+
+ /*
+ * Detect and ignore bug 6826104 in Sun JRE.
+ */
+ if (t instanceof NullPointerException) {
+ StackTraceElement[] trace = t.getStackTrace();
+
+ if (trace.length > 3 &&
+ trace[0].getClassName().equals("sun.awt.X11.XWindowPeer") &&
+ trace[0].getMethodName().equals("restoreTransientFor") &&
+
+ trace[1].getClassName().equals("sun.awt.X11.XWindowPeer") &&
+ trace[1].getMethodName().equals("removeFromTransientFors") &&
+
+ trace[2].getClassName().equals("sun.awt.X11.XWindowPeer") &&
+ trace[2].getMethodName().equals("setModalBlocked")) {
+ log.warn("Ignoring Sun JRE bug (6826104): http://bugs.sun.com/view_bug.do?bug_id=6826104" + t);
+ return true;
+ }
+
+ }
+
+
/*
* Detect and ignore bug 6828938 in Sun JRE 1.6.0_14 - 1.6.0_16.
*/
package net.sf.openrocket.gui.scalefigure;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Point;
+import java.awt.event.ActionEvent;
+import java.awt.event.InputEvent;
+import java.awt.event.MouseEvent;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JSlider;
+import javax.swing.JToggleButton;
+import javax.swing.JViewport;
+import javax.swing.SwingUtilities;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.event.TreeSelectionEvent;
+import javax.swing.event.TreeSelectionListener;
+import javax.swing.tree.TreePath;
+import javax.swing.tree.TreeSelectionModel;
+
import net.miginfocom.swing.MigLayout;
import net.sf.openrocket.aerodynamics.AerodynamicCalculator;
import net.sf.openrocket.aerodynamics.BarrowmanCalculator;
import net.sf.openrocket.util.MathUtil;
import net.sf.openrocket.util.Prefs;
-import javax.swing.AbstractAction;
-import javax.swing.Action;
-import javax.swing.JComboBox;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.JSlider;
-import javax.swing.JToggleButton;
-import javax.swing.JViewport;
-import javax.swing.SwingUtilities;
-import javax.swing.event.ChangeEvent;
-import javax.swing.event.ChangeListener;
-import javax.swing.event.TreeSelectionEvent;
-import javax.swing.event.TreeSelectionListener;
-import javax.swing.tree.TreePath;
-import javax.swing.tree.TreeSelectionModel;
-import java.awt.Dimension;
-import java.awt.Font;
-import java.awt.Point;
-import java.awt.event.ActionEvent;
-import java.awt.event.InputEvent;
-import java.awt.event.MouseEvent;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.concurrent.Executor;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ThreadFactory;
-
/**
* A JPanel that contains a RocketFigure and buttons to manipulate the figure.
*
add(new BasicSlider(theta.getSliderModel(0, 2 * Math.PI), JSlider.VERTICAL, true),
"ax 50%, wrap, width " + (d.width + 6) + "px:null:null, growy");
-
+
//// <html>Click to select Shift+click to select other Double-click to edit Click+drag to move
infoMessage = new JLabel(trans.get("RocketPanel.lbl.infoMessage"));
infoMessage.setFont(new Font("Sans Serif", Font.PLAIN, 9));
add(infoMessage, "skip, span, gapleft 25, wrap");
+
addExtras();
}
public Configuration getConfiguration() {
return configuration;
}
-
- /**
- * Get the center of pressure figure element.
- *
- * @return center of pressure info
- */
- public Caret getExtraCP () {
- return extraCP;
- }
-
- /**
- * Get the center of gravity figure element.
- *
- * @return center of gravity info
- */
- public Caret getExtraCG () {
- return extraCG;
- }
-
- /**
- * Get the extra text figure element.
- *
- * @return extra text that contains info about the rocket design
- */
- public RocketInfo getExtraText () {
- return extraText;
- }
-
- public void setSelectionModel(TreeSelectionModel m) {
+
+ /**
+ * Get the center of pressure figure element.
+ *
+ * @return center of pressure info
+ */
+ public Caret getExtraCP() {
+ return extraCP;
+ }
+
+ /**
+ * Get the center of gravity figure element.
+ *
+ * @return center of gravity info
+ */
+ public Caret getExtraCG() {
+ return extraCG;
+ }
+
+ /**
+ * Get the extra text figure element.
+ *
+ * @return extra text that contains info about the rocket design
+ */
+ public RocketInfo getExtraText() {
+ return extraText;
+ }
+
+ public void setSelectionModel(TreeSelectionModel m) {
if (selectionModel != null) {
selectionModel.removeTreeSelectionListener(this);
}
StackTraceElement[] elements = this.getStackTrace();
StringBuilder sb = new StringBuilder();
- if (minLevel < elements.length) {
-
- sb.append("(");
- sb.append(toString(elements[minLevel]));
- for (int i = minLevel + 1; i <= maxLevel; i++) {
- if (i < elements.length) {
- sb.append(' ').append(toString(elements[i]));
- }
- }
- sb.append(')');
-
- } else if (elements.length == 0) {
-
- sb.append("(no stack trace)");
-
+ sb.append('(');
+
+ if (elements == null || elements.length == 0) {
+ sb.append("no stack trace");
} else {
- sb.append('(');
- sb.append(toString(elements[0]));
- for (int i = 1; i < elements.length; i++) {
- sb.append(' ').append(toString(elements[i]));
+ int levelCount = 0;
+ int position = minLevel;
+ while (levelCount <= (maxLevel - minLevel) && position < elements.length) {
+
+ // Ignore synthetic "access$0" methods generated by the JRE
+ if (elements[position].getMethodName().contains("$")) {
+ position++;
+ continue;
+ }
+
+ if (levelCount > 0) {
+ sb.append(' ');
+ }
+ sb.append(toString(elements[position]));
+ levelCount++;
+ position++;
}
- sb.append(" level=").append(minLevel).append(')');
}
+ sb.append(')');
+
message = sb.toString();
}
return message;
*/
public abstract class Material implements Comparable<Material> {
-
+
public enum Type {
LINE("Line", UnitGroup.UNITS_DENSITY_LINE),
SURFACE("Surface", UnitGroup.UNITS_DENSITY_SURFACE),
private final String name;
private final UnitGroup units;
+
private Type(String name, UnitGroup units) {
this.name = name;
this.units = units;
}
+
public UnitGroup getUnitGroup() {
return units;
}
+
@Override
public String toString() {
return name;
public Line(String name, double density, boolean userDefined) {
super(name, density, userDefined);
}
-
+
@Override
public Type getType() {
return Type.LINE;
public Bulk(String name, double density, boolean userDefined) {
super(name, density, userDefined);
}
-
+
@Override
public Type getType() {
return Type.BULK;
}
-
+
private final String name;
private final double density;
private final boolean userDefined;
}
-
+
public double getDensity() {
return density;
}
return this.getName(this.getType().getUnitGroup().getDefaultUnit());
}
-
+
/**
* Compares this object to another object. Material objects are equal if and only if
* their types, names and densities are identical.
return false;
if (this.getClass() != o.getClass())
return false;
- Material m = (Material)o;
- return ((m.name.equals(this.name)) &&
- MathUtil.equals(m.density, this.density));
+ Material m = (Material) o;
+ return ((m.name.equals(this.name)) && MathUtil.equals(m.density, this.density));
}
-
-
+
+
/**
* A hashCode() method giving a hash code compatible with the equals() method.
*/
@Override
public int hashCode() {
- return name.hashCode() + (int)(density*1000);
+ return name.hashCode() + (int) (density * 1000);
}
-
+
/**
* Order the materials according to their name, secondarily according to density.
*/
+ @Override
public int compareTo(Material o) {
int c = this.name.compareTo(o.name);
if (c != 0) {
return c;
} else {
- return (int)((this.density - o.density)*1000);
+ return (int) ((this.density - o.density) * 1000);
}
}
/**
* Return a new material of the specified type.
*/
- public static Material newMaterial(Type type, String name, double density,
+ public static Material newMaterial(Type type, String name, double density,
boolean userDefined) {
switch (type) {
case LINE:
return new Material.Bulk(name, density, userDefined);
default:
- throw new IllegalArgumentException("Unknown material type: "+type);
+ throw new IllegalArgumentException("Unknown material type: " + type);
}
}
if (str == null)
throw new IllegalArgumentException("Material string is null");
- String[] split = str.split("\\|",3);
+ String[] split = str.split("\\|", 3);
if (split.length < 3)
- throw new IllegalArgumentException("Illegal material string: "+str);
-
+ throw new IllegalArgumentException("Illegal material string: " + str);
+
Type type = null;
String name;
double density;
try {
type = Type.valueOf(split[0]);
} catch (Exception e) {
- throw new IllegalArgumentException("Illegal material string: "+str, e);
+ throw new IllegalArgumentException("Illegal material string: " + str, e);
}
-
+
name = split[1];
try {
density = Double.parseDouble(split[2]);
} catch (NumberFormatException e) {
- throw new IllegalArgumentException("Illegal material string: "+str, e);
+ throw new IllegalArgumentException("Illegal material string: " + str, e);
}
switch (type) {
return new Material.Line(name, density, userDefined);
default:
- throw new IllegalArgumentException("Illegal material string: "+str);
+ throw new IllegalArgumentException("Illegal material string: " + str);
}
}
-
+
}
--- /dev/null
+package net.sf.openrocket.preset;
+
+import net.sf.openrocket.motor.Manufacturer;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+
+/**
+ * A model for a preset component.
+ * <p>
+ * A preset component contains a component class type, manufacturer information,
+ * part information, and a method that returns a prototype of the preset component.
+ *
+ * @author Sampo Niskanen <sampo.niskanen@iki.fi>
+ */
+public abstract class ComponentPreset {
+
+ private final Manufacturer manufacturer;
+ private final String partNo;
+ private final String partDescription;
+ private final RocketComponent prototype;
+
+
+ public ComponentPreset(Manufacturer manufacturer, String partNo, String partDescription,
+ RocketComponent prototype) {
+ this.manufacturer = manufacturer;
+ this.partNo = partNo;
+ this.partDescription = partDescription;
+ this.prototype = prototype.copy();
+
+ if (prototype.getParent() != null) {
+ throw new IllegalArgumentException("Prototype component cannot have a parent");
+ }
+ if (prototype.getChildCount() > 0) {
+ throw new IllegalArgumentException("Prototype component cannot have children");
+ }
+ }
+
+
+ /**
+ * Return the component class that this preset defines.
+ */
+ public Class<? extends RocketComponent> getComponentClass() {
+ return prototype.getClass();
+ }
+
+ /**
+ * Return the manufacturer of this preset component.
+ */
+ public Manufacturer getManufacturer() {
+ return manufacturer;
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * Return a prototype component. This component may be modified freely.
+ */
+ public RocketComponent getPrototype() {
+ return prototype.copy();
+ }
+
+}
+++ /dev/null
-package net.sf.openrocket.preset;
-
-import net.sf.openrocket.motor.Manufacturer;
-import net.sf.openrocket.rocketcomponent.RocketComponent;
-
-public class ExternalComponentPreset extends RocketComponentPreset {
-
- private final double mass;
- private final String materialName;
-
- public ExternalComponentPreset(Class<? extends RocketComponent> 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;
- }
-
-}
+++ /dev/null
-package net.sf.openrocket.preset;
-
-import net.sf.openrocket.motor.Manufacturer;
-import net.sf.openrocket.rocketcomponent.RocketComponent;
-
-/**
- * A model for a preset component.
- * <p>
- * A preset component contains a component class type, manufacturer information,
- * part information, and getter methods for various properties of the component.
- *
- * @author Sampo Niskanen <sampo.niskanen@iki.fi>
- */
-public abstract class RocketComponentPreset {
-
- private final Class<? extends RocketComponent> componentClass;
- private final Manufacturer manufacturer;
- private final String partName;
- private final String partNo;
- private final String partDescription;
-
-
- public RocketComponentPreset(Class<? extends RocketComponent> 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<? extends RocketComponent> 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;
- }
-
-}
package net.sf.openrocket.rocketcomponent;
+
/**
* Class to represent a body object. The object can be described as a function of
* the cylindrical coordinates x and angle theta as r = f(x,theta). The component
*/
public abstract class BodyComponent extends ExternalComponent {
-
+
/**
* Default constructor. Sets the relative position to POSITION_RELATIVE_AFTER,
* i.e. body components come after one another.
public BodyComponent() {
super(RocketComponent.Position.AFTER);
}
-
-
+
+
/**
* Get the outer radius of the component at cylindrical coordinate (x,theta).
*
* @return Distance to the outer edge of the object
*/
public abstract double getRadius(double x, double theta);
-
-
+
+
/**
* Get the inner radius of the component at cylindrical coordinate (x,theta).
*
* @return Distance to the inner edge of the object
*/
public abstract double getInnerRadius(double x, double theta);
-
-
+
+
+ @Override
+ protected void loadFromPreset(RocketComponent preset) {
+ BodyComponent c = (BodyComponent) preset;
+ this.setLength(c.getLength());
+
+ super.loadFromPreset(preset);
+ }
+
+
/**
* Sets the length of the body component.
+ * <p>
+ * Note: This should be overridden by the subcomponents which need to call
+ * clearPreset(). (BodyTube allows changing length without resetting the preset.)
*/
public void setLength(double length) {
if (this.length == length)
this.length = Math.max(length, 0);
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
}
-
+
@Override
public boolean allowsChildren() {
return true;
}
-
+
}
if (this.thickness > this.outerRadius)
this.thickness = this.outerRadius;
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
+ clearPreset();
}
autoRadius = auto;
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
+ clearPreset();
+ }
+
+
+ @Override
+ protected void loadFromPreset(RocketComponent preset) {
+ BodyTube c = (BodyTube) preset;
+ this.setOuterRadius(c.getOuterRadius());
+
+ super.loadFromPreset(preset);
}
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;
material = mat;
clearPreset();
fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
+ clearPreset();
}
public Finish getFinish() {
@Override
- protected void loadFromPreset(RocketComponentPreset preset) {
+ protected void loadFromPreset(RocketComponent preset) {
super.loadFromPreset(preset);
- ExternalComponentPreset p = (ExternalComponentPreset) preset;
- String materialName = p.getMaterialName();
- double mass = p.getMass();
+ // Surface finish is left unchanged
+
+ ExternalComponent c = (ExternalComponent) preset;
- double volume = getComponentVolume();
- double density;
- if (volume > 0.00001) {
- density = mass / volume;
- } else {
- density = 1000;
+ Material mat = c.getMaterial();
+ if (c.isMassOverridden()) {
+ double mass = c.getOverrideMass();
+ double volume = getComponentVolume();
+ double density;
+ if (volume > 0.00001) {
+ density = mass / volume;
+ } else {
+ density = 1000;
+ }
+ mat = Material.newMaterial(Type.BULK, mat.getName(), density, true);
}
- Material mat = Material.newMaterial(Type.BULK, materialName, density, true);
setMaterial(mat);
}
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.logging.LogHelper;
-import net.sf.openrocket.preset.RocketComponentPreset;
+import net.sf.openrocket.preset.ComponentPreset;
import net.sf.openrocket.startup.Application;
import net.sf.openrocket.util.ArrayList;
import net.sf.openrocket.util.BugException;
private String id = null;
// Preset component this component is based upon
- private RocketComponentPreset presetComponent = null;
+ private ComponentPreset presetComponent = null;
/**
*
* @return the preset component, or <code>null</code> if this is not based on a preset.
*/
- public final RocketComponentPreset getPresetComponent() {
+ public final ComponentPreset getPresetComponent() {
return presetComponent;
}
*
* @param preset the preset component to load, or <code>null</code> to clear the preset.
*/
- public final void loadPreset(RocketComponentPreset preset) {
+ public final void loadPreset(ComponentPreset preset) {
if (presetComponent == preset) {
return;
}
rocket.freeze();
}
- loadFromPreset(preset);
+ loadFromPreset(preset.getPrototype());
this.presetComponent = preset;
fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE);
* <p>
* 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.
+ * <p>
+ * This method must FIRST perform the preset loading and THEN call super.loadFromPreset().
+ * This is because mass setting requires the dimensions to be set beforehand.
*
* @param preset the preset to load from
*/
- protected void loadFromPreset(RocketComponentPreset preset) {
+ protected void loadFromPreset(RocketComponent preset) {
// No-op
}
this.thickness = MathUtil.clamp(thickness, 0, Math.max(getForeRadius(), getAftRadius()));
filled = false;
fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
+ clearPreset();
}
return;
this.filled = filled;
fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
+ clearPreset();
}
+ @Override
+ protected void loadFromPreset(RocketComponent preset) {
+ SymmetricComponent c = (SymmetricComponent) preset;
+ this.setThickness(c.getThickness());
+ this.setFilled(c.isFilled());
+
+ super.loadFromPreset(preset);
+ }
+
+
+
+
/**
* Calculate volume of the component by integrating over the length of the component.
* The method caches the result, so subsequent calls are instant. Subclasses may
longitudinalInertia = 0;
rotationalInertia = 0;
- double volume = 0;
+ double vol = 0;
for (int n = 1; n <= DIVISIONS; n++) {
/*
longitudinalInertia += dV * ((3 * (pow2(outer) + pow2(inner)) + pow2(l)) / 12
+ pow2(x + l / 2));
- volume += dV;
+ vol += dV;
// Update for next iteration
r1 = r2;
x += l;
}
- if (MathUtil.equals(volume, 0)) {
+ if (MathUtil.equals(vol, 0)) {
integrateInertiaSurface();
return;
}
- rotationalInertia /= volume;
- longitudinalInertia /= volume;
+ rotationalInertia /= vol;
+ longitudinalInertia /= vol;
// Shift longitudinal inertia to CG
longitudinalInertia = Math.max(longitudinalInertia - pow2(getComponentCG().x), 0);
import net.sf.openrocket.util.BugException;
import net.sf.openrocket.util.ChangeSource;
import net.sf.openrocket.util.MathUtil;
+import net.sf.openrocket.util.Utils;
/**
* A class holding simulation options in basic parameter form and which functions
return false;
SimulationOptions o = (SimulationOptions) other;
return ((this.rocket == o.rocket) &&
- this.motorID.equals(o.motorID) &&
+ Utils.equals(this.motorID, o.motorID) &&
MathUtil.equals(this.launchAltitude, o.launchAltitude) &&
MathUtil.equals(this.launchLatitude, o.launchLatitude) &&
MathUtil.equals(this.launchPressure, o.launchPressure) &&
--- /dev/null
+package net.sf.openrocket.logging;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+public class TraceExceptionTest {
+
+ private TraceException getViaAccess() {
+
+ /*
+ * The SubClass test bases on the fact that getViaAccess method is defined on a row number < 20
+ * and the return statement is on a row number > 20.
+ *
+ * The JRE sometimes adds an additional "access$NNN" method call between the calls with the
+ * row number equal to the method definition line.
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+
+ return new TraceException(0, 1);
+ }
+
+
+ @Test
+ public void testBasic() {
+ TraceException trace = new TraceException();
+ assertMatch("\\(TraceExceptionTest.java:[2-9][0-9]\\)", trace);
+ }
+
+
+ @Test
+ public void testOneLevelUp() {
+ // @formatter:off - these need to be on the same line number
+ TraceException trace = getOneLevelUp(); TraceException ref = new TraceException();
+ // @formatter:on
+ assertEquals(ref.getMessage(), trace.getMessage());
+ }
+
+ private TraceException getOneLevelUp() {
+ return new TraceException(1);
+ }
+
+
+ @Test
+ public void testTwoLevels() {
+ TraceException trace = getTwoLevels();
+ assertMatch("\\(TraceExceptionTest.java:[2-9][0-9] TraceExceptionTest.java:[2-9][0-9]\\)", trace);
+ }
+
+ private TraceException getTwoLevels() {
+ return new TraceException(0, 1);
+ }
+
+
+ @Test
+ public void testViaSubclass() {
+ /*
+ * This tests that TraceException.getMessage ignores the synthetic "access$0" method calls.
+ */
+
+ TraceException trace = new SubClass().getTrace();
+ assertMatch("\\(TraceExceptionTest.java:[2-9][0-9] TraceExceptionTest.java:[2-9][0-9]\\)", trace);
+ }
+
+ private class SubClass {
+ private TraceException getTrace() {
+ return getViaAccess();
+ }
+ }
+
+
+
+
+
+ private void assertMatch(String regex, TraceException trace) {
+ boolean match = trace.getMessage().matches(regex);
+ if (!match) {
+ trace.printStackTrace();
+ assertTrue("Was: " + trace.getMessage(), match);
+ }
+ }
+
+}