bug fixes

This commit is contained in:
Sampo Niskanen 2011-08-25 19:29:50 +00:00
parent 50e8b972a3
commit ceac736133
16 changed files with 407 additions and 206 deletions

View File

@ -1,3 +1,14 @@
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.

View File

@ -606,8 +606,11 @@ public class GeneralOptimizationDialog extends JDialog {
@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);
@ -803,6 +806,7 @@ public class GeneralOptimizationDialog extends JDialog {
});
timer.setRepeats(false);
timer.start();
updateComponents();
}
@Override
@ -1125,16 +1129,21 @@ public class GeneralOptimizationDialog extends JDialog {
* 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);
}
@ -1143,46 +1152,56 @@ public class GeneralOptimizationDialog extends JDialog {
// "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);
}
@ -1445,6 +1464,12 @@ public class GeneralOptimizationDialog extends JDialog {
@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;

View File

@ -162,7 +162,12 @@ public class OptimizationPlotDialog extends JDialog {
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);
@ -296,8 +301,19 @@ public class OptimizationPlotDialog extends JDialog {
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);
@ -308,6 +324,15 @@ public class OptimizationPlotDialog extends JDialog {
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();

View File

@ -301,6 +301,29 @@ public class ExceptionHandler implements Thread.UncaughtExceptionHandler {
// 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.
*/

View File

@ -1,6 +1,35 @@
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;
@ -40,34 +69,6 @@ import net.sf.openrocket.util.Coordinate;
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.
*
@ -241,12 +242,13 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change
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 &nbsp;&nbsp; Shift+click to select other &nbsp;&nbsp; Double-click to edit &nbsp;&nbsp; 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();
}
@ -263,35 +265,35 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change
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);
}

View File

@ -95,31 +95,33 @@ public class TraceException extends Exception {
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;

View File

@ -15,7 +15,7 @@ import net.sf.openrocket.util.MathUtil;
*/
public abstract class Material implements Comparable<Material> {
public enum Type {
LINE("Line", UnitGroup.UNITS_DENSITY_LINE),
SURFACE("Surface", UnitGroup.UNITS_DENSITY_SURFACE),
@ -23,13 +23,16 @@ public abstract class Material implements Comparable<Material> {
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;
@ -43,7 +46,7 @@ public abstract class Material implements Comparable<Material> {
public Line(String name, double density, boolean userDefined) {
super(name, density, userDefined);
}
@Override
public Type getType() {
return Type.LINE;
@ -71,7 +74,7 @@ public abstract class Material implements Comparable<Material> {
public Bulk(String name, double density, boolean userDefined) {
super(name, density, userDefined);
}
@Override
public Type getType() {
return Type.BULK;
@ -79,7 +82,7 @@ public abstract class Material implements Comparable<Material> {
}
private final String name;
private final double density;
private final boolean userDefined;
@ -92,7 +95,7 @@ public abstract class Material implements Comparable<Material> {
}
public double getDensity() {
return density;
}
@ -116,7 +119,7 @@ public abstract class Material implements Comparable<Material> {
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.
@ -127,30 +130,30 @@ public abstract class Material implements Comparable<Material> {
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);
}
}
@ -158,7 +161,7 @@ public abstract class Material implements Comparable<Material> {
/**
* 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:
@ -171,7 +174,7 @@ public abstract class Material implements Comparable<Material> {
return new Material.Bulk(name, density, userDefined);
default:
throw new IllegalArgumentException("Unknown material type: "+type);
throw new IllegalArgumentException("Unknown material type: " + type);
}
}
@ -193,10 +196,10 @@ public abstract class Material implements Comparable<Material> {
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;
@ -204,15 +207,15 @@ public abstract class Material implements Comparable<Material> {
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) {
@ -226,8 +229,8 @@ public abstract class Material implements Comparable<Material> {
return new Material.Line(name, density, userDefined);
default:
throw new IllegalArgumentException("Illegal material string: "+str);
throw new IllegalArgumentException("Illegal material string: " + str);
}
}
}

View File

@ -7,26 +7,31 @@ 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.
* part information, and a method that returns a prototype of the preset component.
*
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
*/
public abstract class RocketComponentPreset {
public abstract class ComponentPreset {
private final Class<? extends RocketComponent> componentClass;
private final Manufacturer manufacturer;
private final String partName;
private final String partNo;
private final String partDescription;
private final RocketComponent prototype;
public RocketComponentPreset(Class<? extends RocketComponent> componentClass, Manufacturer manufacturer,
String partName, String partNo, String partDescription) {
this.componentClass = componentClass;
public ComponentPreset(Manufacturer manufacturer, String partNo, String partDescription,
RocketComponent prototype) {
this.manufacturer = manufacturer;
this.partName = partName;
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");
}
}
@ -34,7 +39,7 @@ public abstract class RocketComponentPreset {
* Return the component class that this preset defines.
*/
public Class<? extends RocketComponent> getComponentClass() {
return componentClass;
return prototype.getClass();
}
/**
@ -44,13 +49,6 @@ public abstract class RocketComponentPreset {
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").
*/
@ -65,4 +63,11 @@ public abstract class RocketComponentPreset {
return partDescription;
}
/**
* Return a prototype component. This component may be modified freely.
*/
public RocketComponent getPrototype() {
return prototype.copy();
}
}

View File

@ -1,29 +0,0 @@
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;
}
}

View File

@ -1,6 +1,7 @@
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
@ -13,7 +14,7 @@ package net.sf.openrocket.rocketcomponent;
*/
public abstract class BodyComponent extends ExternalComponent {
/**
* Default constructor. Sets the relative position to POSITION_RELATIVE_AFTER,
* i.e. body components come after one another.
@ -21,8 +22,8 @@ public abstract class BodyComponent extends ExternalComponent {
public BodyComponent() {
super(RocketComponent.Position.AFTER);
}
/**
* Get the outer radius of the component at cylindrical coordinate (x,theta).
*
@ -33,8 +34,8 @@ public abstract class BodyComponent extends ExternalComponent {
* @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).
*
@ -45,11 +46,23 @@ public abstract class BodyComponent extends ExternalComponent {
* @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)
@ -57,10 +70,10 @@ public abstract class BodyComponent extends ExternalComponent {
this.length = Math.max(length, 0);
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
}
@Override
public boolean allowsChildren() {
return true;
}
}

View File

@ -108,6 +108,7 @@ public class BodyTube extends SymmetricComponent implements MotorMount, Coaxial
if (this.thickness > this.outerRadius)
this.thickness = this.outerRadius;
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
clearPreset();
}
@ -128,6 +129,16 @@ public class BodyTube extends SymmetricComponent implements MotorMount, Coaxial
autoRadius = auto;
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
clearPreset();
}
@Override
protected void loadFromPreset(RocketComponent preset) {
BodyTube c = (BodyTube) preset;
this.setOuterRadius(c.getOuterRadius());
super.loadFromPreset(preset);
}

View File

@ -5,8 +5,6 @@ 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;
@ -116,6 +114,7 @@ public abstract class ExternalComponent extends RocketComponent {
material = mat;
clearPreset();
fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
clearPreset();
}
public Finish getFinish() {
@ -131,22 +130,26 @@ public abstract class ExternalComponent extends RocketComponent {
@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
double volume = getComponentVolume();
double density;
if (volume > 0.00001) {
density = mass / volume;
} else {
density = 1000;
ExternalComponent c = (ExternalComponent) preset;
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);
}

View File

@ -12,7 +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.preset.ComponentPreset;
import net.sf.openrocket.startup.Application;
import net.sf.openrocket.util.ArrayList;
import net.sf.openrocket.util.BugException;
@ -125,7 +125,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
private String id = null;
// Preset component this component is based upon
private RocketComponentPreset presetComponent = null;
private ComponentPreset presetComponent = null;
/**
@ -669,7 +669,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
*
* @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;
}
@ -679,7 +679,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
*
* @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;
}
@ -707,7 +707,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
rocket.freeze();
}
loadFromPreset(preset);
loadFromPreset(preset.getPrototype());
this.presetComponent = preset;
fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE);
@ -726,10 +726,13 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
* <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
}

View File

@ -103,6 +103,7 @@ public abstract class SymmetricComponent extends BodyComponent implements Radial
this.thickness = MathUtil.clamp(thickness, 0, Math.max(getForeRadius(), getAftRadius()));
filled = false;
fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
clearPreset();
}
@ -124,6 +125,7 @@ public abstract class SymmetricComponent extends BodyComponent implements Radial
return;
this.filled = filled;
fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
clearPreset();
}
@ -143,6 +145,18 @@ public abstract class SymmetricComponent extends BodyComponent implements Radial
@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
@ -368,7 +382,7 @@ public abstract class SymmetricComponent extends BodyComponent implements Radial
longitudinalInertia = 0;
rotationalInertia = 0;
double volume = 0;
double vol = 0;
for (int n = 1; n <= DIVISIONS; n++) {
/*
@ -399,20 +413,20 @@ public abstract class SymmetricComponent extends BodyComponent implements Radial
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);

View File

@ -17,6 +17,7 @@ import net.sf.openrocket.rocketcomponent.Rocket;
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
@ -415,7 +416,7 @@ public class SimulationOptions implements ChangeSource, Cloneable {
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) &&

View File

@ -0,0 +1,89 @@
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);
}
}
}