bug fixes
This commit is contained in:
parent
50e8b972a3
commit
ceac736133
11
ChangeLog
11
ChangeLog
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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 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();
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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) &&
|
||||
|
89
test/net/sf/openrocket/logging/TraceExceptionTest.java
Normal file
89
test/net/sf/openrocket/logging/TraceExceptionTest.java
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user