version 1.1.3

This commit is contained in:
Sampo Niskanen 2010-10-06 05:18:11 +00:00
parent 9e6bea78ad
commit ea3433f704
22 changed files with 555 additions and 268 deletions

View File

@ -1,3 +1,13 @@
2010-10-06 Sampo Niskanen
* Released version 1.1.3
2010-10-05 Sampo Niskanen
* Display comment as tooltip in component tree
* Limited allowed component attachments to those of the component
add buttons
2010-10-03 Sampo Niskanen 2010-10-03 Sampo Niskanen
* Added VBOSE logging level * Added VBOSE logging level

View File

@ -1,3 +1,10 @@
OpenRocket 1.1.3 (2010-10-06):
-------------------------------
Support for drag-drop moving and copying of components. Fixes a
severe bug in the undo system.
OpenRocket 1.1.2 (2010-09-07): OpenRocket 1.1.2 (2010-09-07):
------------------------------- -------------------------------

View File

@ -1,7 +1,7 @@
# The OpenRocket build version # The OpenRocket build version
build.version=1.1.3pre build.version=1.1.3
# The source of the package. When building a package for a specific # The source of the package. When building a package for a specific

View File

@ -9,6 +9,7 @@ import javax.swing.event.ChangeListener;
import net.sf.openrocket.aerodynamics.AerodynamicCalculator; import net.sf.openrocket.aerodynamics.AerodynamicCalculator;
import net.sf.openrocket.aerodynamics.BarrowmanCalculator; import net.sf.openrocket.aerodynamics.BarrowmanCalculator;
import net.sf.openrocket.aerodynamics.WarningSet; import net.sf.openrocket.aerodynamics.WarningSet;
import net.sf.openrocket.logging.LogHelper;
import net.sf.openrocket.masscalc.BasicMassCalculator; import net.sf.openrocket.masscalc.BasicMassCalculator;
import net.sf.openrocket.masscalc.MassCalculator; import net.sf.openrocket.masscalc.MassCalculator;
import net.sf.openrocket.rocketcomponent.Configuration; import net.sf.openrocket.rocketcomponent.Configuration;
@ -23,11 +24,13 @@ import net.sf.openrocket.simulation.SimulationStepper;
import net.sf.openrocket.simulation.exception.SimulationException; import net.sf.openrocket.simulation.exception.SimulationException;
import net.sf.openrocket.simulation.exception.SimulationListenerException; import net.sf.openrocket.simulation.exception.SimulationListenerException;
import net.sf.openrocket.simulation.listeners.SimulationListener; import net.sf.openrocket.simulation.listeners.SimulationListener;
import net.sf.openrocket.startup.Application;
import net.sf.openrocket.util.BugException; import net.sf.openrocket.util.BugException;
import net.sf.openrocket.util.ChangeSource; import net.sf.openrocket.util.ChangeSource;
public class Simulation implements ChangeSource, Cloneable { public class Simulation implements ChangeSource, Cloneable {
private static final LogHelper log = Application.getLogger();
public static enum Status { public static enum Status {
/** Up-to-date */ /** Up-to-date */
@ -238,22 +241,16 @@ public class Simulation implements ChangeSource, Cloneable {
throw new SimulationException("Cannot simulate imported simulation."); throw new SimulationException("Cannot simulate imported simulation.");
} }
AerodynamicCalculator aerodynamicCalculator;
SimulationEngine simulator; SimulationEngine simulator;
SimulationStepper stepper;
MassCalculator massCalculator;
try { try {
aerodynamicCalculator = aerodynamicCalculatorClass.newInstance();
simulator = simulationEngineClass.newInstance(); simulator = simulationEngineClass.newInstance();
stepper = simulationStepperClass.newInstance();
massCalculator = massCalculatorClass.newInstance();
} catch (InstantiationException e) { } catch (InstantiationException e) {
throw new IllegalStateException("Cannot instantiate calculator/simulator.", e); throw new IllegalStateException("Cannot instantiate simulator.", e);
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
throw new IllegalStateException("Cannot access calc/sim instance?! BUG!", e); throw new IllegalStateException("Cannot access simulator instance?! BUG!", e);
} catch (NullPointerException e) { } catch (NullPointerException e) {
throw new IllegalStateException("Calculator or simulator null", e); throw new IllegalStateException("Simulator null", e);
} }
SimulationConditions simulationConditions = conditions.toSimulationConditions(); SimulationConditions simulationConditions = conditions.toSimulationConditions();
@ -274,12 +271,11 @@ public class Simulation implements ChangeSource, Cloneable {
} }
long t1, t2; long t1, t2;
System.out.println("Simulation: calling simulator"); log.debug("Simulation: calling simulator");
t1 = System.currentTimeMillis(); t1 = System.currentTimeMillis();
simulatedData = simulator.simulate(simulationConditions); simulatedData = simulator.simulate(simulationConditions);
t2 = System.currentTimeMillis(); t2 = System.currentTimeMillis();
System.out.println("Simulation: returning from simulator, " + log.debug("Simulation: returning from simulator, simulation took " + (t2 - t1) + "ms");
"simulation took " + (t2 - t1) + "ms");
// Set simulated info after simulation, will not be set in case of exception // Set simulated info after simulation, will not be set in case of exception
simulatedConditions = conditions.clone(); simulatedConditions = conditions.clone();

View File

@ -0,0 +1,86 @@
package net.sf.openrocket.gui.dialogs.optimization;
import java.awt.Window;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
import javax.swing.JDialog;
import net.sf.openrocket.document.OpenRocketDocument;
import net.sf.openrocket.optimization.rocketoptimization.RocketOptimizationParameter;
import net.sf.openrocket.optimization.rocketoptimization.RocketOptimizationParameterService;
import net.sf.openrocket.optimization.rocketoptimization.SimulationModifier;
import net.sf.openrocket.optimization.rocketoptimization.SimulationModifierService;
import net.sf.openrocket.util.BugException;
public class GeneralOptimizationDialog extends JDialog {
private final List<RocketOptimizationParameter> optimizationParameters = new ArrayList<RocketOptimizationParameter>();
private final Map<Object, List<SimulationModifier>> simulationModifiers =
new HashMap<Object, List<SimulationModifier>>();
private final OpenRocketDocument document;
public GeneralOptimizationDialog(OpenRocketDocument document, Window parent) {
this.document = document;
loadOptimizationParameters();
loadSimulationModifiers();
}
private void loadOptimizationParameters() {
ServiceLoader<RocketOptimizationParameterService> loader =
ServiceLoader.load(RocketOptimizationParameterService.class);
for (RocketOptimizationParameterService g : loader) {
optimizationParameters.addAll(g.getParameters(document));
}
if (optimizationParameters.isEmpty()) {
throw new BugException("No rocket optimization parameters found, distribution built wrong.");
}
Collections.sort(optimizationParameters, new Comparator<RocketOptimizationParameter>() {
@Override
public int compare(RocketOptimizationParameter o1, RocketOptimizationParameter o2) {
return o1.getName().compareTo(o2.getName());
}
});
}
private void loadSimulationModifiers() {
ServiceLoader<SimulationModifierService> loader = ServiceLoader.load(SimulationModifierService.class);
for (SimulationModifierService g : loader) {
for (SimulationModifier m : g.getModifiers(document)) {
Object key = m.getRelatedObject();
List<SimulationModifier> list = simulationModifiers.get(key);
if (list == null) {
list = new ArrayList<SimulationModifier>();
simulationModifiers.put(key, list);
}
list.add(m);
}
}
for (Object key : simulationModifiers.keySet()) {
List<SimulationModifier> list = simulationModifiers.get(key);
Collections.sort(list, new Comparator<SimulationModifier>() {
@Override
public int compare(SimulationModifier o1, SimulationModifier o2) {
return o1.getName().compareTo(o2.getName());
}
});
}
}
}

View File

@ -9,6 +9,7 @@ import java.awt.Graphics2D;
import javax.swing.DropMode; import javax.swing.DropMode;
import javax.swing.Icon; import javax.swing.Icon;
import javax.swing.JTree; import javax.swing.JTree;
import javax.swing.ToolTipManager;
import net.sf.openrocket.document.OpenRocketDocument; import net.sf.openrocket.document.OpenRocketDocument;
@ -41,8 +42,13 @@ public class ComponentTree extends JTree {
// Expand whole tree by default // Expand whole tree by default
expandTree(); expandTree();
// Enable tooltips for this component
ToolTipManager.sharedInstance().registerComponent(this);
} }
public void expandTree() { public void expandTree() {
for (int i = 0; i < getRowCount(); i++) for (int i = 0; i < getRowCount(); i++)
expandRow(i); expandRow(i);

View File

@ -8,24 +8,38 @@ import javax.swing.JTree;
import javax.swing.tree.DefaultTreeCellRenderer; import javax.swing.tree.DefaultTreeCellRenderer;
import net.sf.openrocket.gui.main.ComponentIcons; import net.sf.openrocket.gui.main.ComponentIcons;
import net.sf.openrocket.rocketcomponent.RocketComponent;
import net.sf.openrocket.util.TextUtil;
public class ComponentTreeRenderer extends DefaultTreeCellRenderer { public class ComponentTreeRenderer extends DefaultTreeCellRenderer {
@Override @Override
public Component getTreeCellRendererComponent( public Component getTreeCellRendererComponent(
JTree tree, JTree tree,
Object value, Object value,
boolean sel, boolean sel,
boolean expanded, boolean expanded,
boolean leaf, boolean leaf,
int row, int row,
boolean hasFocus) { boolean hasFocus) {
super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
setIcon(ComponentIcons.getSmallIcon(value.getClass())); // Set icon
setIcon(ComponentIcons.getSmallIcon(value.getClass()));
return this; // Set tooltip
} RocketComponent c = (RocketComponent) value;
String comment = c.getComment().trim();
if (comment.length() > 0) {
comment = TextUtil.htmlEncode(comment);
comment = "<html>" + comment.replace("\n", "<br>");
this.setToolTipText(comment);
} else {
this.setToolTipText(null);
}
return this;
}
} }

View File

@ -98,7 +98,7 @@ public class RocketOptimizationFunction implements Function {
return value; return value;
} }
// TODO: CRITICAL: is in domain? // TODO: : is in domain?
return 0; return 0;
} }

View File

@ -0,0 +1,23 @@
package net.sf.openrocket.optimization.rocketoptimization;
import java.util.Collection;
import net.sf.openrocket.document.OpenRocketDocument;
/**
* A service for generating rocket optimization parameters.
*
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
*/
public interface RocketOptimizationParameterService {
/**
* Return all available rocket optimization parameters for this document.
* These should be new instances unless the parameter implementation is stateless.
*
* @param document the design document
* @return a collection of the rocket optimization parameters.
*/
public Collection<RocketOptimizationParameter> getParameters(OpenRocketDocument document);
}

View File

@ -1,6 +1,8 @@
package net.sf.openrocket.optimization.rocketoptimization; package net.sf.openrocket.optimization.rocketoptimization;
import net.sf.openrocket.document.Simulation; import net.sf.openrocket.document.Simulation;
import net.sf.openrocket.unit.UnitGroup;
import net.sf.openrocket.util.ChangeSource;
/** /**
* An interface what modifies a single parameter in a rocket simulation * An interface what modifies a single parameter in a rocket simulation
@ -8,14 +10,80 @@ import net.sf.openrocket.document.Simulation;
* *
* @author Sampo Niskanen <sampo.niskanen@iki.fi> * @author Sampo Niskanen <sampo.niskanen@iki.fi>
*/ */
public interface SimulationModifier { public interface SimulationModifier extends ChangeSource {
/**
* Return a name describing this modifier.
* @return a name describing this modifier.
*/
public String getName();
/**
* Return the object this modifier is related to. This is for example the
* rocket component this modifier is modifying. This object can be used by a
* UI to group related modifiers.
*
* @return the object this modifier is related to, or <code>null</code>.
*/
public Object getRelatedObject();
/**
* Return the current value of the modifier in SI units.
* @return the current value of this parameter in SI units.
*/
public double getCurrentValue();
/**
* Return the minimum value (corresponding to scaled value 0) in SI units.
* @return the value corresponding to scaled value 0.
*/
public double getMinValue();
/**
* Set the minimum value (corresponding to scaled value 0) in SI units.
* @param value the value corresponding to scaled value 0.
*/
public void setMinValue(double value);
/**
* Return the maximum value (corresponding to scaled value 1) in SI units.
* @return the value corresponding to scaled value 1.
*/
public double getMaxValue();
/**
* Set the maximum value (corresponding to scaled value 1) in SI units.
* @param value the value corresponding to scaled value 1.
*/
public void setMaxValue(double value);
/**
* Return the unit group used for the values returned by {@link #getCurrentValue()} etc.
* @return the unit group
*/
public UnitGroup getUnitGroup();
/**
* Return the current scaled value. This is normally within the range [0...1], but
* can be outside the range if the current value is outside of the min and max values.
* @return
*/
public double getCurrentScaledValue();
/** /**
* Modify the specified simulation to the corresponding parameter value. * Modify the specified simulation to the corresponding parameter value.
* *
* @param simulation the simulation to modify * @param simulation the simulation to modify
* @param value a value in the range [0...1] * @param scaledValue the scaled value in the range [0...1]
*/ */
public void modify(Simulation simulation, double value); public void modify(Simulation simulation, double scaledValue);
} }

View File

@ -0,0 +1,23 @@
package net.sf.openrocket.optimization.rocketoptimization;
import java.util.Collection;
import net.sf.openrocket.document.OpenRocketDocument;
/**
* A service for generating simulation modifiers.
*
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
*/
public interface SimulationModifierService {
/**
* Return all available simulation modifiers for this document.
*
* @param document the design document
* @return a collection of the rocket optimization parameters.
*/
public Collection<SimulationModifier> getModifiers(OpenRocketDocument document);
}

View File

@ -64,20 +64,4 @@ public abstract class BodyComponent extends ExternalComponent {
return true; return true;
} }
/**
* Check whether the given type can be added to this component. BodyComponents allow any
* InternalComponents or ExternalComponents, excluding BodyComponents, to be added.
*
* @param type The RocketComponent class type to add.
* @return Whether such a component can be added.
*/
@Override
public boolean isCompatible(Class<? extends RocketComponent> type) {
if (InternalComponent.class.isAssignableFrom(type))
return true;
if (ExternalComponent.class.isAssignableFrom(type) &&
!BodyComponent.class.isAssignableFrom(type))
return true;
return false;
}
} }

View File

@ -281,6 +281,24 @@ public class BodyTube extends SymmetricComponent implements MotorMount {
} }
/**
* Check whether the given type can be added to this component. BodyTubes allow any
* InternalComponents or ExternalComponents, excluding BodyComponents, to be added.
*
* @param type The RocketComponent class type to add.
* @return Whether such a component can be added.
*/
@Override
public boolean isCompatible(Class<? extends RocketComponent> type) {
if (InternalComponent.class.isAssignableFrom(type))
return true;
if (ExternalComponent.class.isAssignableFrom(type) &&
!BodyComponent.class.isAssignableFrom(type))
return true;
return false;
}
//////////////// Motor mount ///////////////// //////////////// Motor mount /////////////////
@Override @Override

View File

@ -107,7 +107,6 @@ public abstract class RocketComponent implements ChangeSource, Cloneable,
private String comment = ""; private String comment = "";
// Unique ID of the component // Unique ID of the component
// TODO: CRITICAL: Sort out usage of ID and undo defect
private String id = null; private String id = null;
/** /**

View File

@ -16,10 +16,10 @@ public class Transition extends SymmetricComponent {
private Shape type; private Shape type;
private double shapeParameter; private double shapeParameter;
private boolean clipped; // Not to be read - use isClipped(), which may be overriden private boolean clipped; // Not to be read - use isClipped(), which may be overriden
private double radius1, radius2; private double radius1, radius2;
private boolean autoRadius1, autoRadius2; // Whether the start radius is automatic private boolean autoRadius1, autoRadius2; // Whether the start radius is automatic
private double foreShoulderRadius; private double foreShoulderRadius;
@ -33,7 +33,7 @@ public class Transition extends SymmetricComponent {
// Used to cache the clip length // Used to cache the clip length
private double clipLength=-1; private double clipLength = -1;
public Transition() { public Transition() {
super(); super();
@ -76,7 +76,7 @@ public class Transition extends SymmetricComponent {
return; return;
this.autoRadius1 = false; this.autoRadius1 = false;
this.radius1 = Math.max(radius,0); this.radius1 = Math.max(radius, 0);
if (this.thickness > this.radius1 && this.thickness > this.radius2) if (this.thickness > this.radius1 && this.thickness > this.radius2)
this.thickness = Math.max(this.radius1, this.radius2); this.thickness = Math.max(this.radius1, this.radius2);
@ -122,7 +122,7 @@ public class Transition extends SymmetricComponent {
return; return;
this.autoRadius2 = false; this.autoRadius2 = false;
this.radius2 = Math.max(radius,0); this.radius2 = Math.max(radius, 0);
if (this.thickness > this.radius1 && this.thickness > this.radius2) if (this.thickness > this.radius1 && this.thickness > this.radius2)
this.thickness = Math.max(this.radius1, this.radius2); this.thickness = Math.max(this.radius1, this.radius2);
@ -324,17 +324,17 @@ public class Transition extends SymmetricComponent {
*/ */
@Override @Override
public double getRadius(double x) { public double getRadius(double x) {
if (x<0 || x>length) if (x < 0 || x > length)
return 0; return 0;
double r1=getForeRadius(); double r1 = getForeRadius();
double r2=getAftRadius(); double r2 = getAftRadius();
if (r1 == r2) if (r1 == r2)
return r1; return r1;
if (r1 > r2) { if (r1 > r2) {
x = length-x; x = length - x;
double tmp = r1; double tmp = r1;
r1 = r2; r1 = r2;
r2 = tmp; r2 = tmp;
@ -343,11 +343,11 @@ public class Transition extends SymmetricComponent {
if (isClipped()) { if (isClipped()) {
// Check clip calculation // Check clip calculation
if (clipLength < 0) if (clipLength < 0)
calculateClip(r1,r2); calculateClip(r1, r2);
return type.getRadius(clipLength+x, r2, clipLength+length, shapeParameter); return type.getRadius(clipLength + x, r2, clipLength + length, shapeParameter);
} else { } else {
// Not clipped // Not clipped
return r1 + type.getRadius(x, r2-r1, length, shapeParameter); return r1 + type.getRadius(x, r2 - r1, length, shapeParameter);
} }
} }
@ -357,15 +357,15 @@ public class Transition extends SymmetricComponent {
* using a binary search. It assumes getRadius() to be monotonically increasing. * using a binary search. It assumes getRadius() to be monotonically increasing.
*/ */
private void calculateClip(double r1, double r2) { private void calculateClip(double r1, double r2) {
double min=0, max=length; double min = 0, max = length;
if (r1 >= r2) { if (r1 >= r2) {
double tmp=r1; double tmp = r1;
r1 = r2; r1 = r2;
r2 = tmp; r2 = tmp;
} }
if (r1==0) { if (r1 == 0) {
clipLength = 0; clipLength = 0;
return; return;
} }
@ -379,21 +379,21 @@ public class Transition extends SymmetricComponent {
// getR(min,min+length,r2) - r1 < 0 // getR(min,min+length,r2) - r1 < 0
// getR(max,max+length,r2) - r1 > 0 // getR(max,max+length,r2) - r1 > 0
int n=0; int n = 0;
while (type.getRadius(max, r2, max+length, shapeParameter) - r1 < 0) { while (type.getRadius(max, r2, max + length, shapeParameter) - r1 < 0) {
min = max; min = max;
max *= 2; max *= 2;
n++; n++;
if (n>10) if (n > 10)
break; break;
} }
while (true) { while (true) {
clipLength = (min+max)/2; clipLength = (min + max) / 2;
if ((max-min)<CLIP_PRECISION) if ((max - min) < CLIP_PRECISION)
return; return;
double val = type.getRadius(clipLength, r2, clipLength+length, shapeParameter); double val = type.getRadius(clipLength, r2, clipLength + length, shapeParameter);
if (val-r1 > 0) { if (val - r1 > 0) {
max = clipLength; max = clipLength;
} else { } else {
min = clipLength; min = clipLength;
@ -404,7 +404,7 @@ public class Transition extends SymmetricComponent {
@Override @Override
public double getInnerRadius(double x) { public double getInnerRadius(double x) {
return Math.max(getRadius(x)-thickness,0); return Math.max(getRadius(x) - thickness, 0);
} }
@ -456,20 +456,20 @@ public class Transition extends SymmetricComponent {
if (isForeShoulderCapped()) { if (isForeShoulderCapped()) {
final double ir = Math.max(getForeShoulderRadius() - getForeShoulderThickness(), 0); final double ir = Math.max(getForeShoulderRadius() - getForeShoulderThickness(), 0);
cg = cg.average(ringCG(ir, 0, -getForeShoulderLength(), cg = cg.average(ringCG(ir, 0, -getForeShoulderLength(),
getForeShoulderThickness()-getForeShoulderLength(), getForeShoulderThickness() - getForeShoulderLength(),
getMaterial().getDensity())); getMaterial().getDensity()));
} }
if (getAftShoulderLength() > 0.001) { if (getAftShoulderLength() > 0.001) {
final double ir = Math.max(getAftShoulderRadius() - getAftShoulderThickness(), 0); final double ir = Math.max(getAftShoulderRadius() - getAftShoulderThickness(), 0);
cg = cg.average(ringCG(getAftShoulderRadius(), ir, getLength(), cg = cg.average(ringCG(getAftShoulderRadius(), ir, getLength(),
getLength()+getAftShoulderLength(), getMaterial().getDensity())); getLength() + getAftShoulderLength(), getMaterial().getDensity()));
} }
if (isAftShoulderCapped()) { if (isAftShoulderCapped()) {
final double ir = Math.max(getAftShoulderRadius() - getAftShoulderThickness(), 0); final double ir = Math.max(getAftShoulderRadius() - getAftShoulderThickness(), 0);
cg = cg.average(ringCG(ir, 0, cg = cg.average(ringCG(ir, 0,
getLength()+getAftShoulderLength()-getAftShoulderThickness(), getLength() + getAftShoulderLength() - getAftShoulderThickness(),
getLength()+getAftShoulderLength(), getMaterial().getDensity())); getLength() + getAftShoulderLength(), getMaterial().getDensity()));
} }
return cg; return cg;
} }
@ -498,6 +498,21 @@ public class Transition extends SymmetricComponent {
} }
/**
* Check whether the given type can be added to this component. Transitions allow any
* InternalComponents to be added.
*
* @param type The RocketComponent class type to add.
* @return Whether such a component can be added.
*/
@Override
public boolean isCompatible(Class<? extends RocketComponent> type) {
if (InternalComponent.class.isAssignableFrom(type))
return true;
return false;
}
/** /**
* An enumeration listing the possible shapes of transitions. * An enumeration listing the possible shapes of transitions.
@ -517,7 +532,7 @@ public class Transition extends SymmetricComponent {
assert x >= 0; assert x >= 0;
assert x <= length; assert x <= length;
assert radius >= 0; assert radius >= 0;
return radius*x/length; return radius * x / length;
} }
}, },
@ -528,21 +543,23 @@ public class Transition extends SymmetricComponent {
*/ */
OGIVE("Ogive", OGIVE("Ogive",
"An ogive nose cone has a profile that is a segment of a circle. " + "An ogive nose cone has a profile that is a segment of a circle. " +
"The shape parameter value 1 produces a <b>tangent ogive</b>, which has " + "The shape parameter value 1 produces a <b>tangent ogive</b>, which has " +
"a smooth transition to the body tube, values less than 1 produce "+ "a smooth transition to the body tube, values less than 1 produce " +
"<b>secant ogives</b>.", "<b>secant ogives</b>.",
"An ogive transition has a profile that is a segment of a circle. " + "An ogive transition has a profile that is a segment of a circle. " +
"The shape parameter value 1 produces a <b>tangent ogive</b>, which has " + "The shape parameter value 1 produces a <b>tangent ogive</b>, which has " +
"a smooth transition to the body tube at the aft end, values less than 1 " + "a smooth transition to the body tube at the aft end, values less than 1 " +
"produce <b>secant ogives</b>.") { "produce <b>secant ogives</b>.") {
@Override @Override
public boolean usesParameter() { public boolean usesParameter() {
return true; // Range 0...1 is default return true; // Range 0...1 is default
} }
@Override @Override
public double defaultParameter() { public double defaultParameter() {
return 1.0; // Tangent ogive by default return 1.0; // Tangent ogive by default
} }
@Override @Override
public double getRadius(double x, double radius, double length, double param) { public double getRadius(double x, double radius, double length, double param) {
assert x >= 0; assert x >= 0;
@ -562,12 +579,12 @@ public class Transition extends SymmetricComponent {
return CONICAL.getRadius(x, radius, length, param); return CONICAL.getRadius(x, radius, length, param);
// Radius of circle is: // Radius of circle is:
double R = sqrt((pow2(length)+pow2(radius)) * double R = sqrt((pow2(length) + pow2(radius)) *
(pow2((2-param)*length) + pow2(param*radius))/(4*pow2(param*radius))); (pow2((2 - param) * length) + pow2(param * radius)) / (4 * pow2(param * radius)));
double L = length/param; double L = length / param;
// double R = (radius + length*length/(radius*param*param))/2; // double R = (radius + length*length/(radius*param*param))/2;
double y0 = sqrt(R*R - L*L); double y0 = sqrt(R * R - L * L);
return sqrt(R*R - (L-x)*(L-x)) - y0; return sqrt(R * R - (L - x) * (L - x)) - y0;
} }
}, },
@ -575,43 +592,45 @@ public class Transition extends SymmetricComponent {
* Ellipsoidal shape. * Ellipsoidal shape.
*/ */
ELLIPSOID("Ellipsoid", ELLIPSOID("Ellipsoid",
"An ellipsoidal nose cone has a profile of a half-ellipse "+ "An ellipsoidal nose cone has a profile of a half-ellipse " +
"with major axes of lengths 2&times;<i>Length</i> and <i>Diameter</i>.", "with major axes of lengths 2&times;<i>Length</i> and <i>Diameter</i>.",
"An ellipsoidal transition has a profile of a half-ellipse "+ "An ellipsoidal transition has a profile of a half-ellipse " +
"with major axes of lengths 2&times;<i>Length</i> and <i>Diameter</i>. If the "+ "with major axes of lengths 2&times;<i>Length</i> and <i>Diameter</i>. If the " +
"transition is not clipped, then the profile is extended at the center by the "+ "transition is not clipped, then the profile is extended at the center by the " +
"corresponding radius.",true) { "corresponding radius.", true) {
@Override @Override
public double getRadius(double x, double radius, double length, double param) { public double getRadius(double x, double radius, double length, double param) {
assert x >= 0; assert x >= 0;
assert x <= length; assert x <= length;
assert radius >= 0; assert radius >= 0;
x = x*radius/length; x = x * radius / length;
return sqrt(2*radius*x-x*x); // radius/length * sphere return sqrt(2 * radius * x - x * x); // radius/length * sphere
} }
}, },
POWER("Power series", POWER("Power series",
"A power series nose cone has a profile of "+ "A power series nose cone has a profile of " +
"<i>Radius</i>&nbsp;&times;&nbsp;(<i>x</i>&nbsp;/&nbsp;<i>Length</i>)" + "<i>Radius</i>&nbsp;&times;&nbsp;(<i>x</i>&nbsp;/&nbsp;<i>Length</i>)" +
"<sup><i>k</i></sup> "+ "<sup><i>k</i></sup> " +
"where <i>k</i> is the shape parameter. For <i>k</i>=0.5 this is a "+ "where <i>k</i> is the shape parameter. For <i>k</i>=0.5 this is a " +
"<b>" + FRAC12 +"-power</b> or <b>parabolic</b> nose cone, for <i>k</i>=0.75 a "+ "<b>" + FRAC12 + "-power</b> or <b>parabolic</b> nose cone, for <i>k</i>=0.75 a " +
"<b>" + FRAC34 +"-power</b>, and for <i>k</i>=1 a <b>conical</b> nose cone.", "<b>" + FRAC34 + "-power</b>, and for <i>k</i>=1 a <b>conical</b> nose cone.",
"A power series transition has a profile of "+ "A power series transition has a profile of " +
"<i>Radius</i>&nbsp;&times;&nbsp;(<i>x</i>&nbsp;/&nbsp;<i>Length</i>)" + "<i>Radius</i>&nbsp;&times;&nbsp;(<i>x</i>&nbsp;/&nbsp;<i>Length</i>)" +
"<sup><i>k</i></sup> "+ "<sup><i>k</i></sup> " +
"where <i>k</i> is the shape parameter. For <i>k</i>=0.5 the transition is "+ "where <i>k</i> is the shape parameter. For <i>k</i>=0.5 the transition is " +
"<b>" + FRAC12 + "-power</b> or <b>parabolic</b>, for <i>k</i>=0.75 a " + "<b>" + FRAC12 + "-power</b> or <b>parabolic</b>, for <i>k</i>=0.75 a " +
"<b>" + FRAC34 + "-power</b>, and for <i>k</i>=1 <b>conical</b>.",true) { "<b>" + FRAC34 + "-power</b>, and for <i>k</i>=1 <b>conical</b>.", true) {
@Override @Override
public boolean usesParameter() { // Range 0...1 public boolean usesParameter() { // Range 0...1
return true; return true;
} }
@Override @Override
public double defaultParameter() { public double defaultParameter() {
return 0.5; return 0.5;
} }
@Override @Override
public double getRadius(double x, double radius, double length, double param) { public double getRadius(double x, double radius, double length, double param) {
assert x >= 0; assert x >= 0;
@ -619,40 +638,42 @@ public class Transition extends SymmetricComponent {
assert radius >= 0; assert radius >= 0;
assert param >= 0; assert param >= 0;
assert param <= 1; assert param <= 1;
if (param<=0.00001) { if (param <= 0.00001) {
if (x<=0.00001) if (x <= 0.00001)
return 0; return 0;
else else
return radius; return radius;
} }
return radius*Math.pow(x/length, param); return radius * Math.pow(x / length, param);
} }
}, },
PARABOLIC("Parabolic series", PARABOLIC("Parabolic series",
"A parabolic series nose cone has a profile of a parabola. The shape "+ "A parabolic series nose cone has a profile of a parabola. The shape " +
"parameter defines the segment of the parabola to utilize. The shape " + "parameter defines the segment of the parabola to utilize. The shape " +
"parameter 1.0 produces a <b>full parabola</b> which is tangent to the body " + "parameter 1.0 produces a <b>full parabola</b> which is tangent to the body " +
"tube, 0.75 produces a <b>3/4 parabola</b>, 0.5 procudes a " + "tube, 0.75 produces a <b>3/4 parabola</b>, 0.5 procudes a " +
"<b>1/2 parabola</b> and 0 produces a <b>conical</b> nose cone.", "<b>1/2 parabola</b> and 0 produces a <b>conical</b> nose cone.",
"A parabolic series transition has a profile of a parabola. The shape "+ "A parabolic series transition has a profile of a parabola. The shape " +
"parameter defines the segment of the parabola to utilize. The shape " + "parameter defines the segment of the parabola to utilize. The shape " +
"parameter 1.0 produces a <b>full parabola</b> which is tangent to the body " + "parameter 1.0 produces a <b>full parabola</b> which is tangent to the body " +
"tube at the aft end, 0.75 produces a <b>3/4 parabola</b>, 0.5 procudes a " + "tube at the aft end, 0.75 produces a <b>3/4 parabola</b>, 0.5 procudes a " +
"<b>1/2 parabola</b> and 0 produces a <b>conical</b> transition.") { "<b>1/2 parabola</b> and 0 produces a <b>conical</b> transition.") {
// In principle a parabolic transition is clippable, but the difference is // In principle a parabolic transition is clippable, but the difference is
// negligible. // negligible.
@Override @Override
public boolean usesParameter() { // Range 0...1 public boolean usesParameter() { // Range 0...1
return true; return true;
} }
@Override @Override
public double defaultParameter() { public double defaultParameter() {
return 1.0; return 1.0;
} }
@Override @Override
public double getRadius(double x, double radius, double length, double param) { public double getRadius(double x, double radius, double length, double param) {
assert x >= 0; assert x >= 0;
@ -661,7 +682,7 @@ public class Transition extends SymmetricComponent {
assert param >= 0; assert param >= 0;
assert param <= 1; assert param <= 1;
return radius * ((2*x/length - param*pow2(x/length))/(2-param)); return radius * ((2 * x / length - param * pow2(x / length)) / (2 - param));
} }
}, },
@ -669,22 +690,24 @@ public class Transition extends SymmetricComponent {
HAACK("Haack series", HAACK("Haack series",
"The Haack series nose cones are designed to minimize drag. The shape parameter " + "The Haack series nose cones are designed to minimize drag. The shape parameter " +
"0 produces an <b>LD-Haack</b> or <b>Von Karman</b> nose cone, which minimizes " + "0 produces an <b>LD-Haack</b> or <b>Von Karman</b> nose cone, which minimizes " +
"drag for fixed length and diameter, while a value of 0.333 produces an " + "drag for fixed length and diameter, while a value of 0.333 produces an " +
"<b>LV-Haack</b> nose cone, which minimizes drag for fixed length and volume.", "<b>LV-Haack</b> nose cone, which minimizes drag for fixed length and volume.",
"The Haack series <i>nose cones</i> are designed to minimize drag. " + "The Haack series <i>nose cones</i> are designed to minimize drag. " +
"These transition shapes are their equivalents, but do not necessarily produce " + "These transition shapes are their equivalents, but do not necessarily produce " +
"optimal drag for transitions. " + "optimal drag for transitions. " +
"The shape parameter 0 produces an <b>LD-Haack</b> or <b>Von Karman</b> shape, " + "The shape parameter 0 produces an <b>LD-Haack</b> or <b>Von Karman</b> shape, " +
"while a value of 0.333 produces an <b>LV-Haack</b> shape.",true) { "while a value of 0.333 produces an <b>LV-Haack</b> shape.", true) {
@Override @Override
public boolean usesParameter() { public boolean usesParameter() {
return true; return true;
} }
@Override @Override
public double maxParameter() { public double maxParameter() {
return 1.0/3.0; // Range 0...1/3 return 1.0 / 3.0; // Range 0...1/3
} }
@Override @Override
public double getRadius(double x, double radius, double length, double param) { public double getRadius(double x, double radius, double length, double param) {
assert x >= 0; assert x >= 0;
@ -693,44 +716,44 @@ public class Transition extends SymmetricComponent {
assert param >= 0; assert param >= 0;
assert param <= 2; assert param <= 2;
double theta = Math.acos(1-2*x/length); double theta = Math.acos(1 - 2 * x / length);
if (param==0) { if (param == 0) {
return radius*sqrt((theta-sin(2*theta)/2)/Math.PI); return radius * sqrt((theta - sin(2 * theta) / 2) / Math.PI);
} }
return radius*sqrt((theta-sin(2*theta)/2+param*pow3(sin(theta)))/Math.PI); return radius * sqrt((theta - sin(2 * theta) / 2 + param * pow3(sin(theta))) / Math.PI);
} }
}, },
// POLYNOMIAL("Smooth polynomial", // POLYNOMIAL("Smooth polynomial",
// "A polynomial is fitted such that the nose cone profile is horizontal "+ // "A polynomial is fitted such that the nose cone profile is horizontal "+
// "at the aft end of the transition. The angle at the tip is defined by "+ // "at the aft end of the transition. The angle at the tip is defined by "+
// "the shape parameter.", // "the shape parameter.",
// "A polynomial is fitted such that the transition profile is horizontal "+ // "A polynomial is fitted such that the transition profile is horizontal "+
// "at the aft end of the transition. The angle at the fore end is defined "+ // "at the aft end of the transition. The angle at the fore end is defined "+
// "by the shape parameter.") { // "by the shape parameter.") {
// @Override // @Override
// public boolean usesParameter() { // public boolean usesParameter() {
// return true; // return true;
// } // }
// @Override // @Override
// public double maxParameter() { // public double maxParameter() {
// return 3.0; // Range 0...3 // return 3.0; // Range 0...3
// } // }
// @Override // @Override
// public double defaultParameter() { // public double defaultParameter() {
// return 0.0; // return 0.0;
// } // }
// public double getRadius(double x, double radius, double length, double param) { // public double getRadius(double x, double radius, double length, double param) {
// assert x >= 0; // assert x >= 0;
// assert x <= length; // assert x <= length;
// assert radius >= 0; // assert radius >= 0;
// assert param >= 0; // assert param >= 0;
// assert param <= 3; // assert param <= 3;
// // p(x) = (k-2)x^3 + (3-2k)x^2 + k*x // // p(x) = (k-2)x^3 + (3-2k)x^2 + k*x
// x = x/length; // x = x/length;
// return radius*((((param-2)*x + (3-2*param))*x + param)*x); // return radius*((((param-2)*x + (3-2*param))*x + param)*x);
// } // }
// } // }
; ;
// Privete fields of the shapes // Privete fields of the shapes
@ -741,7 +764,7 @@ public class Transition extends SymmetricComponent {
// Non-clippable constructor // Non-clippable constructor
Shape(String name, String noseconeDesc, String transitionDesc) { Shape(String name, String noseconeDesc, String transitionDesc) {
this(name,noseconeDesc,transitionDesc,false); this(name, noseconeDesc, transitionDesc, false);
} }
// Clippable constructor // Clippable constructor

View File

@ -3,8 +3,8 @@ package net.sf.openrocket.util;
public class TextUtil { public class TextUtil {
private static final char[] HEX = { private static final char[] HEX = {
'0','1','2','3','4','5','6','7', '0', '1', '2', '3', '4', '5', '6', '7',
'8','9','a','b','c','d','e','f' '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
}; };
@ -18,7 +18,7 @@ public class TextUtil {
*/ */
public static final String hexString(byte[] bytes) { public static final String hexString(byte[] bytes) {
StringBuilder sb = new StringBuilder(bytes.length * 2); StringBuilder sb = new StringBuilder(bytes.length * 2);
for (byte b: bytes) { for (byte b : bytes) {
sb.append(HEX[(b >>> 4) & 0xF]); sb.append(HEX[(b >>> 4) & 0xF]);
sb.append(HEX[b & 0xF]); sb.append(HEX[b & 0xF]);
} }
@ -95,7 +95,7 @@ public class TextUtil {
*/ */
private static String decimalFormat(double value) { private static String decimalFormat(double value) {
if (value >= 10000) if (value >= 10000)
return "" + (int)(value + 0.5); return "" + (int) (value + 0.5);
int decimals = 1; int decimals = 1;
double v = value; double v = value;
@ -118,16 +118,16 @@ public class TextUtil {
// Calculate rounding and limit values (rounding slightly smaller) // Calculate rounding and limit values (rounding slightly smaller)
int rounding = 1; int rounding = 1;
double limit = 0.5; double limit = 0.5;
for (int i=0; i<decimals; i++) { for (int i = 0; i < decimals; i++) {
rounding *= 10; rounding *= 10;
limit /= 10; limit /= 10;
} }
// Round value // Round value
value = (Math.rint(value * rounding)+0.1) / rounding; value = (Math.rint(value * rounding) + 0.1) / rounding;
int whole = (int)value; int whole = (int) value;
value -= whole; value -= whole;
@ -140,12 +140,12 @@ public class TextUtil {
sb.append('.'); sb.append('.');
for (int i = 0; i<decimals; i++) { for (int i = 0; i < decimals; i++) {
value *= 10; value *= 10;
whole = (int)value; whole = (int) value;
value -= whole; value -= whole;
sb.append((char)('0' + whole)); sb.append((char) ('0' + whole));
if (value < limit) if (value < limit)
return sb.toString(); return sb.toString();
@ -156,4 +156,12 @@ public class TextUtil {
return sb.toString(); return sb.toString();
} }
public static String htmlEncode(String s) {
s = s.replace("&", "&amp;");
s = s.replace("\"", "&quot;");
s = s.replace("<", "&lt;");
s = s.replace(">", "&gt;");
return s;
}
} }

View File

@ -80,16 +80,18 @@ header("Content-type: text/plain");
$version = $_GET["version"]; $version = $_GET["version"];
$updates = ""; $updates = "";
$unstable = "1.1.2"; $unstable = "1.1.3";
$stable = "1.0.0"; $stable = "1.0.0";
if (preg_match("/^1\.1\.1/", $version)) { if (preg_match("/^1\.1\.[12]/", $version)) {
$updates = "Version: " . $unstable . "\n" . $updates = "Version: " . $unstable . "\n" .
"4: Fixed bug preventing addition of stages\n"; "5: Initial drag-and-drop support\n" .
"4: Bug fixes\n";
} else if (preg_match("/^1\.1\.0/", $version)) { } else if (preg_match("/^1\.1\.0/", $version)) {
$updates = "Version: " . $unstable . "\n" . $updates = "Version: " . $unstable . "\n" .
"6: Enhanced motor selection\n" . "6: Enhanced motor selection\n" .
"5: Rewritten simulation code\n" . "5: Rewritten simulation code\n" .
"5: Drag-and-drop support\n" .
"4: Bug fixes"; "4: Bug fixes";
} else if (preg_match("/^0\.9\.6/", $version)) { } else if (preg_match("/^0\.9\.6/", $version)) {
$updates = "Version: " . $stable . "\n" . $updates = "Version: " . $stable . "\n" .

View File

@ -45,6 +45,12 @@
<div class="content"> <div class="content">
<div class="news"> <div class="news">
<h2>Recent news:</h2> <h2>Recent news:</h2>
<p><span class="date">6.10.2010:</span> Version 1.1.3 is
<a href="download.html">released</a>!</p>
<p>This release includes support for moving and copying components
in the component tree using drag-and-drop. Use normal DnD for
moving, and control-drag for copy. This release also fixes a
severe bug in the undo system.</p>
<p><span class="date">7.9.2010:</span> A bug-fix version 1.1.2 is <p><span class="date">7.9.2010:</span> A bug-fix version 1.1.2 is
<a href="download.html">released</a>!</p> <a href="download.html">released</a>!</p>
<p>This release fixes a severe bug in 1.1.1 that prevented adding stages <p>This release fixes a severe bug in 1.1.1 that prevented adding stages
@ -82,13 +88,13 @@
<a href="http://sourceforge.net/donate/index.php?group_id=260357"><img src="project-support.jpg" width="88" height="32" alt="Support This Project" /></a> <a href="http://sourceforge.net/donate/index.php?group_id=260357"><img src="project-support.jpg" width="88" height="32" alt="Support This Project" /></a>
</div> </div>
<div class="downloadbox"> <div class="downloadbox">
<a class="main" href="https://sourceforge.net/projects/openrocket/files/openrocket/1.1.2/OpenRocket-1.1.2.jar/download"> <a class="main" href="https://sourceforge.net/projects/openrocket/files/openrocket/1.1.3/OpenRocket-1.1.3.jar/download">
<strong>Download now!</strong> <strong>Download now!</strong>
<span>OpenRocket-1.1.2.jar</span> <span>OpenRocket-1.1.3.jar</span>
</a> </a>
<span class="alternative"> <span class="alternative">
<a href="https://sourceforge.net/projects/openrocket/files/openrocket/1.1.2/ReleaseNotes/view">Release notes</a> | <a href="https://sourceforge.net/projects/openrocket/files/openrocket/1.1.3/ReleaseNotes/view">Release notes</a> |
<a href="https://sourceforge.net/projects/openrocket/files/openrocket/1.1.2/OpenRocket-1.1.2-src.zip/download">Source code</a> <a href="https://sourceforge.net/projects/openrocket/files/openrocket/1.1.3/OpenRocket-1.1.3-src.zip/download">Source code</a>
</span> </span>
</div> </div>
<h3>Stable release</h3> <h3>Stable release</h3>
@ -105,7 +111,7 @@
Windows) by double-clicking the package icon. No installation is Windows) by double-clicking the package icon. No installation is
required.</p> required.</p>
<p>From the command line OpenRocket can be started by <p>From the command line OpenRocket can be started by
<span class="command">java -jar OpenRocket-1.1.2.jar</span></p> <span class="command">java -jar OpenRocket-1.1.3.jar</span></p>
</div> </div>
<div class="clear"></div> <div class="clear"></div>

View File

@ -46,12 +46,12 @@
<h2>Introduction</h2> <h2>Introduction</h2>
<div class="rightpane"> <div class="rightpane">
<div class="downloadbox"> <div class="downloadbox">
<a class="main" href="https://sourceforge.net/projects/openrocket/files/openrocket/1.1.2/OpenRocket-1.1.2.jar/download"> <a class="main" href="https://sourceforge.net/projects/openrocket/files/openrocket/1.1.3/OpenRocket-1.1.3.jar/download">
<strong>Download now!</strong> <strong>Download now!</strong>
<span>OpenRocket-1.1.2.jar</span> <span>OpenRocket-1.1.3.jar</span>
</a> </a>
<span class="alternative"> <span class="alternative">
<a href="https://sourceforge.net/projects/openrocket/files/openrocket/1.1.2/ReleaseNotes/view">Release notes</a> | <a href="https://sourceforge.net/projects/openrocket/files/openrocket/1.1.3/ReleaseNotes/view">Release notes</a> |
<a href="download.html">Other versions</a> <a href="download.html">Other versions</a>
</span> </span>
</div> </div>
@ -88,6 +88,12 @@
<div class="clear"></div> <div class="clear"></div>
<div class="news"> <div class="news">
<h2>News</h2> <h2>News</h2>
<p><span class="date">6.10.2010:</span> Version 1.1.3 is
<a href="download.html">released</a>!</p>
<p>This release includes support for moving and copying components
in the component tree using drag-and-drop. Use normal DnD for
moving, and control-drag for copy. This release also fixes a
severe bug in the undo system.</p>
<p><span class="date">7.9.2010:</span> A bug-fix version 1.1.2 is <p><span class="date">7.9.2010:</span> A bug-fix version 1.1.2 is
<a href="download.html">released</a>!</p> <a href="download.html">released</a>!</p>
<p>This release fixes a severe bug in 1.1.1 that prevented adding stages <p>This release fixes a severe bug in 1.1.1 that prevented adding stages

View File

@ -1,5 +1,5 @@
<set stableversion="1.0.0"> <set stableversion="1.0.0">
<set developmentversion="1.1.2"> <set developmentversion="1.1.3">
<set version="${developmentversion}"> <set version="${developmentversion}">
<def name="downloadbox"> <def name="downloadbox">

View File

@ -9,6 +9,14 @@
<!--- Remember to move the position of "onlyrecent" below! ---> <!--- Remember to move the position of "onlyrecent" below! --->
<p><span class="date">6.10.2010:</span> Version 1.1.3 is
<a href="download.html">released</a>!</p>
<p>This release includes support for moving and copying components
in the component tree using drag-and-drop. Use normal DnD for
moving, and control-drag for copy. This release also fixes a
severe bug in the undo system.</p>
<p><span class="date">7.9.2010:</span> A bug-fix version 1.1.2 is <p><span class="date">7.9.2010:</span> A bug-fix version 1.1.2 is
<a href="download.html">released</a>!</p> <a href="download.html">released</a>!</p>