Merge remote-tracking branch 'origin/Change-side-view-to-top-view' into Change-side-view-to-top-view
This commit is contained in:
commit
3306ed0f50
Binary file not shown.
@ -1149,6 +1149,8 @@ NoseConeCfg.tab.General = General
|
|||||||
NoseConeCfg.tab.ttip.General = General properties
|
NoseConeCfg.tab.ttip.General = General properties
|
||||||
NoseConeCfg.tab.Shoulder = Shoulder
|
NoseConeCfg.tab.Shoulder = Shoulder
|
||||||
NoseConeCfg.tab.ttip.Shoulder = Shoulder properties
|
NoseConeCfg.tab.ttip.Shoulder = Shoulder properties
|
||||||
|
NoseConeCfg.checkbox.Flip = Flip to tail cone
|
||||||
|
NoseConeCfg.checkbox.Flip.ttip = Flips the nose cone direction to a tail cone.
|
||||||
|
|
||||||
! ParachuteConfig
|
! ParachuteConfig
|
||||||
Parachute.Parachute = Parachute
|
Parachute.Parachute = Parachute
|
||||||
@ -1363,7 +1365,7 @@ TCMotorSelPan.lbl.Datapoints = Data points:
|
|||||||
TCMotorSelPan.lbl.Digest = Digest:
|
TCMotorSelPan.lbl.Digest = Digest:
|
||||||
TCMotorSelPan.title.Thrustcurve = Thrust curve:
|
TCMotorSelPan.title.Thrustcurve = Thrust curve:
|
||||||
TCMotorSelPan.title.Thrust = Thrust
|
TCMotorSelPan.title.Thrust = Thrust
|
||||||
TCMotorSelPan.delayBox.None = None
|
TCMotorSelPan.delayBox.None = Plugged (none)
|
||||||
TCMotorSelPan.noDescription = No description available.
|
TCMotorSelPan.noDescription = No description available.
|
||||||
TCMotorSelPan.btn.checkAll = Select All
|
TCMotorSelPan.btn.checkAll = Select All
|
||||||
TCMotorSelPan.btn.checkNone = Clear All
|
TCMotorSelPan.btn.checkNone = Clear All
|
||||||
|
@ -1046,7 +1046,7 @@ TCMotorSelPan.lbl.Datapoints = \u30C7\u30FC\u30BF\u70B9\uFF1A
|
|||||||
TCMotorSelPan.lbl.Digest = \u30C0\u30A4\u30B8\u30A7\u30B9\u30C8\uFF1A
|
TCMotorSelPan.lbl.Digest = \u30C0\u30A4\u30B8\u30A7\u30B9\u30C8\uFF1A
|
||||||
TCMotorSelPan.title.Thrustcurve = \u63A8\u529B\u5C65\u6B74\uFF1A
|
TCMotorSelPan.title.Thrustcurve = \u63A8\u529B\u5C65\u6B74\uFF1A
|
||||||
TCMotorSelPan.title.Thrust = \u63A8\u529B
|
TCMotorSelPan.title.Thrust = \u63A8\u529B
|
||||||
TCMotorSelPan.delayBox.None = None
|
TCMotorSelPan.delayBox.None = Plugged (none)
|
||||||
TCMotorSelPan.noDescription = No description available.
|
TCMotorSelPan.noDescription = No description available.
|
||||||
|
|
||||||
|
|
||||||
|
@ -1119,7 +1119,7 @@ TCMotorSelPan.lbl.Datapoints = Data points:
|
|||||||
TCMotorSelPan.lbl.Digest = Digest:
|
TCMotorSelPan.lbl.Digest = Digest:
|
||||||
TCMotorSelPan.title.Thrustcurve = Thrust curve:
|
TCMotorSelPan.title.Thrustcurve = Thrust curve:
|
||||||
TCMotorSelPan.title.Thrust = Thrust
|
TCMotorSelPan.title.Thrust = Thrust
|
||||||
TCMotorSelPan.delayBox.None = None
|
TCMotorSelPan.delayBox.None = Plugged (none)
|
||||||
TCMotorSelPan.noDescription = No description available.
|
TCMotorSelPan.noDescription = No description available.
|
||||||
TCMotorSelPan.btn.checkAll = Select All
|
TCMotorSelPan.btn.checkAll = Select All
|
||||||
TCMotorSelPan.btn.checkNone = Clear All
|
TCMotorSelPan.btn.checkNone = Clear All
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 12 KiB |
@ -0,0 +1,102 @@
|
|||||||
|
package net.sf.openrocket.aerodynamics.barrowman;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.lang.Math;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import net.sf.openrocket.aerodynamics.AerodynamicForces;
|
||||||
|
import net.sf.openrocket.aerodynamics.FlightConditions;
|
||||||
|
import net.sf.openrocket.aerodynamics.WarningSet;
|
||||||
|
import net.sf.openrocket.rocketcomponent.RailButton;
|
||||||
|
import net.sf.openrocket.rocketcomponent.RocketComponent;
|
||||||
|
import net.sf.openrocket.util.Coordinate;
|
||||||
|
import net.sf.openrocket.util.MathUtil;
|
||||||
|
import net.sf.openrocket.util.Transformation;
|
||||||
|
|
||||||
|
public class RailButtonCalc extends RocketComponentCalc {
|
||||||
|
private final static Logger log = LoggerFactory.getLogger(RailButtonCalc.class);
|
||||||
|
|
||||||
|
// values transcribed from Gowen and Perkins, "Drag of Circular Cylinders for a Wide Range
|
||||||
|
// of Reynolds Numbers and Mach Numbers", NACA Technical Note 2960, Figure 7
|
||||||
|
private static final List<Double> cdDomain = List.of(0.0, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 1.0, 1.6, 2.0, 2.8, 100.0);
|
||||||
|
private static final List<Double> cdRange = List.of(1.2, 1.22, 1.25, 1.3, 1.4, 1.5, 1.6, 2.1, 1.5, 1.45, 1.33, 1.33);
|
||||||
|
|
||||||
|
private final RailButton button;
|
||||||
|
|
||||||
|
public RailButtonCalc(RocketComponent component) {
|
||||||
|
super(component);
|
||||||
|
|
||||||
|
// need to stash the button
|
||||||
|
button = (RailButton) component;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double calculateFrictionCD(FlightConditions conditions, double componentCf, WarningSet warnings) {
|
||||||
|
// very small relative surface area, and slick
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void calculateNonaxialForces(FlightConditions conditions, Transformation transform,
|
||||||
|
AerodynamicForces forces, WarningSet warnings) {
|
||||||
|
// Nothing to be done
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double calculatePressureCD(FlightConditions conditions,
|
||||||
|
double stagnationCD, double baseCD, WarningSet warnings) {
|
||||||
|
|
||||||
|
// grab relevant button params
|
||||||
|
final int instanceCount = button.getInstanceCount();
|
||||||
|
final Coordinate[] instanceOffsets = button.getInstanceOffsets();
|
||||||
|
|
||||||
|
// compute button reference area
|
||||||
|
final double buttonHt = button.getTotalHeight();
|
||||||
|
final double outerArea = buttonHt * button.getOuterDiameter();
|
||||||
|
final double notchArea = (button.getOuterDiameter() - button.getInnerDiameter()) * button.getInnerHeight();
|
||||||
|
final double refArea = outerArea - notchArea;
|
||||||
|
|
||||||
|
// accumulate Cd contribution from each rail button
|
||||||
|
double CDmul = 0.0;
|
||||||
|
for (int i = 0; i < button.getInstanceCount(); i++) {
|
||||||
|
|
||||||
|
// compute boundary layer height at button location. I can't find a good reference for the
|
||||||
|
// formula, e.g. https://aerospaceengineeringblog.com/boundary-layers/ simply says it's the
|
||||||
|
// "scientific consensus".
|
||||||
|
double x = (button.toAbsolute(instanceOffsets[i]))[0].x; // location of button
|
||||||
|
double rex = calculateReynoldsNumber(x, conditions); // Reynolds number of button location
|
||||||
|
double del = 0.37 * x / Math.pow(rex, 0.2); // Boundary layer thickness
|
||||||
|
|
||||||
|
// compute mean airspeed over button
|
||||||
|
// this assumes airspeed changes linearly through boundary layer
|
||||||
|
// and that all parts of the railbutton contribute equally to Cd,
|
||||||
|
// neither of which is true but both are plenty close enough for our purposes
|
||||||
|
|
||||||
|
double mach;
|
||||||
|
if (buttonHt > del) {
|
||||||
|
// Case 1: button extends beyond boundary layer
|
||||||
|
// Mean velocity is 1/2 rocket velocity up to limit of boundary layer,
|
||||||
|
// full velocity after that
|
||||||
|
mach = (buttonHt - 0.5*del) * conditions.getMach()/buttonHt;
|
||||||
|
} else {
|
||||||
|
// Case 2: button is entirely within boundary layer
|
||||||
|
mach = MathUtil.map(buttonHt/2.0, 0, del, 0, conditions.getMach());
|
||||||
|
}
|
||||||
|
|
||||||
|
// look up Cd as function of speed. It's pretty constant as a function of Reynolds
|
||||||
|
// number when slow, so we can just use a function of Mach number
|
||||||
|
double cd = MathUtil.interpolate(cdDomain, cdRange, mach);
|
||||||
|
|
||||||
|
// Since later drag force calculations don't consider boundary layer, compute "effective Cd"
|
||||||
|
// based on rocket velocity
|
||||||
|
cd = cd * MathUtil.pow2(mach)/MathUtil.pow2(conditions.getMach());
|
||||||
|
|
||||||
|
// add to CDmul
|
||||||
|
CDmul += cd;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CDmul * stagnationCD * refArea / conditions.getRefArea();
|
||||||
|
}
|
||||||
|
}
|
@ -221,6 +221,9 @@ public class ThrustCurveMotorSet implements Comparable<ThrustCurveMotorSet> {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!designation.equalsIgnoreCase(m.getDesignation()))
|
||||||
|
return false;
|
||||||
|
|
||||||
if (!commonName.equalsIgnoreCase(m.getCommonName()))
|
if (!commonName.equalsIgnoreCase(m.getCommonName()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -385,14 +385,18 @@ public class Simulation implements ChangeSource, Cloneable {
|
|||||||
t2 = System.currentTimeMillis();
|
t2 = System.currentTimeMillis();
|
||||||
log.debug("Simulation: returning from simulator, simulation took " + (t2 - t1) + "ms");
|
log.debug("Simulation: returning from simulator, simulation took " + (t2 - t1) + "ms");
|
||||||
|
|
||||||
// Set simulated info after simulation, will not be set in case of exception
|
} catch (SimulationException e) {
|
||||||
|
simulatedData = e.getFlightData();
|
||||||
|
throw e;
|
||||||
|
} finally {
|
||||||
|
// Set simulated info after simulation
|
||||||
simulatedConditions = options.clone();
|
simulatedConditions = options.clone();
|
||||||
simulatedConfigurationDescription = descriptor.format( this.rocket, getId());
|
simulatedConfigurationDescription = descriptor.format( this.rocket, getId());
|
||||||
simulatedRocketID = rocket.getFunctionalModID();
|
simulatedRocketID = rocket.getFunctionalModID();
|
||||||
|
|
||||||
status = Status.UPTODATE;
|
status = Status.UPTODATE;
|
||||||
fireChangeEvent();
|
fireChangeEvent();
|
||||||
} finally {
|
|
||||||
mutex.unlock("simulate");
|
mutex.unlock("simulate");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ public class ZipFileMotorLoader implements MotorLoader {
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ThrustCurveMotor.Builder> load(InputStream stream, String filename) throws IOException {
|
public List<ThrustCurveMotor.Builder> load(InputStream stream, String filename) throws IOException, IllegalArgumentException {
|
||||||
List<ThrustCurveMotor.Builder> motors = new ArrayList<>();
|
List<ThrustCurveMotor.Builder> motors = new ArrayList<>();
|
||||||
|
|
||||||
ZipInputStream is = new ZipInputStream(stream);
|
ZipInputStream is = new ZipInputStream(stream);
|
||||||
|
@ -10,9 +10,11 @@ import net.sf.openrocket.util.Reflection;
|
|||||||
//// BooleanSetter - set a boolean value
|
//// BooleanSetter - set a boolean value
|
||||||
class BooleanSetter implements Setter {
|
class BooleanSetter implements Setter {
|
||||||
private final Reflection.Method setMethod;
|
private final Reflection.Method setMethod;
|
||||||
|
private Object[] extraParameters = null;
|
||||||
|
|
||||||
public BooleanSetter(Reflection.Method set) {
|
public BooleanSetter(Reflection.Method set, Object... parameters) {
|
||||||
setMethod = set;
|
setMethod = set;
|
||||||
|
this.extraParameters = parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -20,12 +22,23 @@ class BooleanSetter implements Setter {
|
|||||||
WarningSet warnings) {
|
WarningSet warnings) {
|
||||||
|
|
||||||
s = s.trim();
|
s = s.trim();
|
||||||
|
final boolean setValue;
|
||||||
if (s.equalsIgnoreCase("true")) {
|
if (s.equalsIgnoreCase("true")) {
|
||||||
setMethod.invoke(c, true);
|
setValue = true;
|
||||||
} else if (s.equalsIgnoreCase("false")) {
|
} else if (s.equalsIgnoreCase("false")) {
|
||||||
setMethod.invoke(c, false);
|
setValue = false;
|
||||||
} else {
|
} else {
|
||||||
warnings.add(Warning.FILE_INVALID_PARAMETER);
|
warnings.add(Warning.FILE_INVALID_PARAMETER);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extraParameters != null) {
|
||||||
|
Object[] parameters = new Object[extraParameters.length + 1];
|
||||||
|
parameters[0] = setValue;
|
||||||
|
System.arraycopy(extraParameters, 0, parameters, 1, extraParameters.length);
|
||||||
|
setMethod.invoke(c, parameters);
|
||||||
|
} else {
|
||||||
|
setMethod.invoke(c, setValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -249,6 +249,8 @@ class DocumentConfig {
|
|||||||
setters.put("Transition:aftshouldercapped", new BooleanSetter(
|
setters.put("Transition:aftshouldercapped", new BooleanSetter(
|
||||||
Reflection.findMethod(Transition.class, "setAftShoulderCapped", boolean.class)));
|
Reflection.findMethod(Transition.class, "setAftShoulderCapped", boolean.class)));
|
||||||
|
|
||||||
|
setters.put("NoseCone:isflipped", new BooleanSetter(
|
||||||
|
Reflection.findMethod(NoseCone.class, "setFlipped", boolean.class, boolean.class), false));
|
||||||
// NoseCone - disable disallowed elements
|
// NoseCone - disable disallowed elements
|
||||||
setters.put("NoseCone:foreradius", null);
|
setters.put("NoseCone:foreradius", null);
|
||||||
setters.put("NoseCone:foreshoulderradius", null);
|
setters.put("NoseCone:foreshoulderradius", null);
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
package net.sf.openrocket.file.openrocket.savers;
|
package net.sf.openrocket.file.openrocket.savers;
|
||||||
|
|
||||||
|
import net.sf.openrocket.rocketcomponent.NoseCone;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
public class NoseConeSaver extends TransitionSaver {
|
public class NoseConeSaver extends TransitionSaver {
|
||||||
|
|
||||||
@ -20,8 +23,23 @@ public class NoseConeSaver extends TransitionSaver {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void addParams(net.sf.openrocket.rocketcomponent.RocketComponent c, List<String> elements) {
|
protected void addParams(net.sf.openrocket.rocketcomponent.RocketComponent c, List<String> elements) {
|
||||||
|
NoseCone noseCone = (NoseCone) c;
|
||||||
super.addParams(c, elements);
|
super.addParams(c, elements);
|
||||||
|
|
||||||
// Transition handles nose cone saving as well
|
if (noseCone.isBaseRadiusAutomatic())
|
||||||
|
elements.add("<aftradius>auto " + noseCone.getBaseRadiusNoAutomatic() + "</aftradius>");
|
||||||
|
else
|
||||||
|
elements.add("<aftradius>" + noseCone.getBaseRadius() + "</aftradius>");
|
||||||
|
|
||||||
|
elements.add("<aftshoulderradius>" + noseCone.getShoulderRadius()
|
||||||
|
+ "</aftshoulderradius>");
|
||||||
|
elements.add("<aftshoulderlength>" + noseCone.getShoulderLength()
|
||||||
|
+ "</aftshoulderlength>");
|
||||||
|
elements.add("<aftshoulderthickness>" + noseCone.getShoulderThickness()
|
||||||
|
+ "</aftshoulderthickness>");
|
||||||
|
elements.add("<aftshouldercapped>" + noseCone.isShoulderCapped()
|
||||||
|
+ "</aftshouldercapped>");
|
||||||
|
|
||||||
|
elements.add("<isflipped>" + noseCone.isFlipped() + "</isflipped>");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,8 +30,6 @@ public class TransitionSaver extends SymmetricComponentSaver {
|
|||||||
protected void addParams(net.sf.openrocket.rocketcomponent.RocketComponent c, List<String> elements) {
|
protected void addParams(net.sf.openrocket.rocketcomponent.RocketComponent c, List<String> elements) {
|
||||||
super.addParams(c, elements);
|
super.addParams(c, elements);
|
||||||
net.sf.openrocket.rocketcomponent.Transition trans = (net.sf.openrocket.rocketcomponent.Transition) c;
|
net.sf.openrocket.rocketcomponent.Transition trans = (net.sf.openrocket.rocketcomponent.Transition) c;
|
||||||
boolean nosecone = (trans instanceof NoseCone);
|
|
||||||
|
|
||||||
|
|
||||||
Transition.Shape shape = trans.getType();
|
Transition.Shape shape = trans.getType();
|
||||||
elements.add("<shape>" + shape.name().toLowerCase(Locale.ENGLISH) + "</shape>");
|
elements.add("<shape>" + shape.name().toLowerCase(Locale.ENGLISH) + "</shape>");
|
||||||
@ -42,13 +40,15 @@ public class TransitionSaver extends SymmetricComponentSaver {
|
|||||||
elements.add("<shapeparameter>" + trans.getShapeParameter() + "</shapeparameter>");
|
elements.add("<shapeparameter>" + trans.getShapeParameter() + "</shapeparameter>");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Nose cones need other parameter saving, due to the isFlipped() parameter
|
||||||
|
if (trans instanceof NoseCone) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!nosecone) {
|
|
||||||
if (trans.isForeRadiusAutomatic())
|
if (trans.isForeRadiusAutomatic())
|
||||||
elements.add("<foreradius>auto " + trans.getForeRadiusNoAutomatic() + "</foreradius>");
|
elements.add("<foreradius>auto " + trans.getForeRadiusNoAutomatic() + "</foreradius>");
|
||||||
else
|
else
|
||||||
elements.add("<foreradius>" + trans.getForeRadius() + "</foreradius>");
|
elements.add("<foreradius>" + trans.getForeRadius() + "</foreradius>");
|
||||||
}
|
|
||||||
|
|
||||||
if (trans.isAftRadiusAutomatic())
|
if (trans.isAftRadiusAutomatic())
|
||||||
elements.add("<aftradius>auto " + trans.getAftRadiusNoAutomatic() + "</aftradius>");
|
elements.add("<aftradius>auto " + trans.getAftRadiusNoAutomatic() + "</aftradius>");
|
||||||
@ -56,7 +56,6 @@ public class TransitionSaver extends SymmetricComponentSaver {
|
|||||||
elements.add("<aftradius>" + trans.getAftRadius() + "</aftradius>");
|
elements.add("<aftradius>" + trans.getAftRadius() + "</aftradius>");
|
||||||
|
|
||||||
|
|
||||||
if (!nosecone) {
|
|
||||||
elements.add("<foreshoulderradius>" + trans.getForeShoulderRadius()
|
elements.add("<foreshoulderradius>" + trans.getForeShoulderRadius()
|
||||||
+ "</foreshoulderradius>");
|
+ "</foreshoulderradius>");
|
||||||
elements.add("<foreshoulderlength>" + trans.getForeShoulderLength()
|
elements.add("<foreshoulderlength>" + trans.getForeShoulderLength()
|
||||||
@ -65,7 +64,6 @@ public class TransitionSaver extends SymmetricComponentSaver {
|
|||||||
+ "</foreshoulderthickness>");
|
+ "</foreshoulderthickness>");
|
||||||
elements.add("<foreshouldercapped>" + trans.isForeShoulderCapped()
|
elements.add("<foreshouldercapped>" + trans.isForeShoulderCapped()
|
||||||
+ "</foreshouldercapped>");
|
+ "</foreshouldercapped>");
|
||||||
}
|
|
||||||
|
|
||||||
elements.add("<aftshoulderradius>" + trans.getAftShoulderRadius()
|
elements.add("<aftshoulderradius>" + trans.getAftShoulderRadius()
|
||||||
+ "</aftshoulderradius>");
|
+ "</aftshoulderradius>");
|
||||||
|
@ -65,7 +65,11 @@ public class PodSetDTO extends BasePartDTO implements AttachableParts {
|
|||||||
} else if (child instanceof BodyTube) {
|
} else if (child instanceof BodyTube) {
|
||||||
addAttachedPart(new BodyTubeDTO((BodyTube) child));
|
addAttachedPart(new BodyTubeDTO((BodyTube) child));
|
||||||
} else if (child instanceof NoseCone) {
|
} else if (child instanceof NoseCone) {
|
||||||
|
if (((NoseCone) child).isFlipped()) {
|
||||||
|
addAttachedPart(new TransitionDTO((NoseCone) child));
|
||||||
|
} else {
|
||||||
addAttachedPart(new NoseConeDTO((NoseCone) child));
|
addAttachedPart(new NoseConeDTO((NoseCone) child));
|
||||||
|
}
|
||||||
} else if (child instanceof Transition) {
|
} else if (child instanceof Transition) {
|
||||||
addAttachedPart(new TransitionDTO((Transition) child));
|
addAttachedPart(new TransitionDTO((Transition) child));
|
||||||
}
|
}
|
||||||
|
@ -93,9 +93,13 @@ public class StageDTO {
|
|||||||
externalPart.add(theExternalPartDTO);
|
externalPart.add(theExternalPartDTO);
|
||||||
}
|
}
|
||||||
|
|
||||||
private NoseConeDTO toNoseConeDTO(NoseCone nc) {
|
private AbstractTransitionDTO toNoseConeDTO(NoseCone nc) {
|
||||||
|
if (nc.isFlipped()) {
|
||||||
|
return new TransitionDTO(nc);
|
||||||
|
} else {
|
||||||
return new NoseConeDTO(nc);
|
return new NoseConeDTO(nc);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private BodyTubeDTO toBodyTubeDTO(BodyTube bt) {
|
private BodyTubeDTO toBodyTubeDTO(BodyTube bt) {
|
||||||
return new BodyTubeDTO(bt);
|
return new BodyTubeDTO(bt);
|
||||||
|
@ -56,7 +56,7 @@ public class DefaultSimulationModifierService implements SimulationModifierServi
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
addModifier("optimization.modifier.nosecone.length", UnitGroup.UNITS_LENGTH, 1.0, NoseCone.class, "Length");
|
addModifier("optimization.modifier.nosecone.length", UnitGroup.UNITS_LENGTH, 1.0, NoseCone.class, "Length");
|
||||||
addModifier("optimization.modifier.nosecone.diameter", UnitGroup.UNITS_LENGTH, 2.0, NoseCone.class, "AftRadius", "isAftRadiusAutomatic");
|
addModifier("optimization.modifier.nosecone.diameter", UnitGroup.UNITS_LENGTH, 2.0, NoseCone.class, "BaseRadius", "isBaseRadiusAutomatic");
|
||||||
addModifier("optimization.modifier.nosecone.thickness", UnitGroup.UNITS_LENGTH, 1.0, NoseCone.class, "Thickness", "isFilled");
|
addModifier("optimization.modifier.nosecone.thickness", UnitGroup.UNITS_LENGTH, 1.0, NoseCone.class, "Thickness", "isFilled");
|
||||||
|
|
||||||
addModifier("optimization.modifier.transition.length", UnitGroup.UNITS_LENGTH, 1.0, Transition.class, "Length");
|
addModifier("optimization.modifier.transition.length", UnitGroup.UNITS_LENGTH, 1.0, Transition.class, "Length");
|
||||||
|
@ -13,6 +13,9 @@ import java.util.EventObject;
|
|||||||
/**
|
/**
|
||||||
* Rocket nose cones of various types. Implemented as a transition with the
|
* Rocket nose cones of various types. Implemented as a transition with the
|
||||||
* fore radius == 0.
|
* fore radius == 0.
|
||||||
|
* <p>
|
||||||
|
* The normal nose cone can be converted to a tail cone by setting the {@link #isFlipped} parameter.
|
||||||
|
* This will flip all the aft side dimensions with the fore side dimensions.
|
||||||
*
|
*
|
||||||
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
|
* @author Sampo Niskanen <sampo.niskanen@iki.fi>
|
||||||
*/
|
*/
|
||||||
@ -21,6 +24,7 @@ public class NoseCone extends Transition implements InsideColorComponent {
|
|||||||
private static final Translator trans = Application.getTranslator();
|
private static final Translator trans = Application.getTranslator();
|
||||||
|
|
||||||
private InsideColorComponentHandler insideColorComponentHandler = new InsideColorComponentHandler(this);
|
private InsideColorComponentHandler insideColorComponentHandler = new InsideColorComponentHandler(this);
|
||||||
|
private boolean isFlipped; // If true, the nose cone is converted to a tail cone
|
||||||
|
|
||||||
/********* Constructors **********/
|
/********* Constructors **********/
|
||||||
public NoseCone() {
|
public NoseCone() {
|
||||||
@ -29,16 +33,12 @@ public class NoseCone extends Transition implements InsideColorComponent {
|
|||||||
|
|
||||||
public NoseCone(Transition.Shape type, double length, double radius) {
|
public NoseCone(Transition.Shape type, double length, double radius) {
|
||||||
super();
|
super();
|
||||||
|
this.isFlipped = false;
|
||||||
super.setType(type);
|
super.setType(type);
|
||||||
super.setForeRadiusAutomatic(false);
|
|
||||||
super.setForeRadius(0);
|
|
||||||
super.setForeShoulderLength(0);
|
|
||||||
super.setForeShoulderRadius(0.9 * radius);
|
|
||||||
super.setForeShoulderThickness(0);
|
|
||||||
super.setForeShoulderCapped(filled);
|
|
||||||
super.setThickness(0.002);
|
super.setThickness(0.002);
|
||||||
super.setLength(length);
|
super.setLength(length);
|
||||||
super.setClipped(false);
|
super.setClipped(false);
|
||||||
|
resetForeRadius();
|
||||||
|
|
||||||
super.setAftRadiusAutomatic(false);
|
super.setAftRadiusAutomatic(false);
|
||||||
super.setAftRadius(radius);
|
super.setAftRadius(radius);
|
||||||
@ -47,72 +47,208 @@ public class NoseCone extends Transition implements InsideColorComponent {
|
|||||||
super.displayOrder_back = 0; // Order for displaying the component in the 2D back view
|
super.displayOrder_back = 0; // Order for displaying the component in the 2D back view
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/********** Nose cone dimensions **********/
|
||||||
|
|
||||||
/********** Get/set methods for component parameters **********/
|
/**
|
||||||
|
* Returns the base radius of the nose cone (independent of whether the nose cone is flipped or not).
|
||||||
@Override
|
* This method should be used over {@link #getAftRadius()} because it works for both normal and flipped nose cones.
|
||||||
public double getForeRadius() {
|
*/
|
||||||
return 0;
|
public double getBaseRadius() {
|
||||||
|
return isFlipped ? getForeRadius() : getAftRadius();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public void setForeRadius(double r) {
|
* Returns the raw base radius of the nose cone (independent of whether the nose cone is flipped or not).
|
||||||
// No-op
|
* This method should be used over {@link #getAftRadiusNoAutomatic()} because it works for both normal and flipped nose cones.
|
||||||
|
*/
|
||||||
|
public double getBaseRadiusNoAutomatic() {
|
||||||
|
return isFlipped ? getForeRadiusNoAutomatic() : getAftRadiusNoAutomatic();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public boolean isForeRadiusAutomatic() {
|
* Sets the base radius of the nose cone (independent of whether the nose cone is flipped or not).
|
||||||
return false;
|
* This method should be used over {@link #setAftRadius(double)} because it works for both normal and flipped nose cones.
|
||||||
|
*/
|
||||||
|
public void setBaseRadius(double radius) {
|
||||||
|
if (isFlipped) {
|
||||||
|
setForeRadius(radius);
|
||||||
|
} else {
|
||||||
|
setAftRadius(radius);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public void setForeRadiusAutomatic(boolean b) {
|
* Returns whether the base radius of the nose cone takes it settings from the previous/next component
|
||||||
// No-op
|
* (independent of whether the nose cone is flipped or not).
|
||||||
|
* This method should be used over {@link #isAftRadiusAutomatic()} because it works for both normal and flipped nose cones.
|
||||||
|
*/
|
||||||
|
public boolean isBaseRadiusAutomatic() {
|
||||||
|
return isFlipped ? isForeRadiusAutomatic() : isAftRadiusAutomatic();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public boolean usesPreviousCompAutomatic() {
|
* Sets whether the base radius of the nose cone takes it settings from the previous/next component
|
||||||
return false;
|
* (independent of whether the nose cone is flipped or not).
|
||||||
|
* This method should be used over {@link #setAftRadiusAutomatic(boolean)} because it works for both normal and flipped nose cones.
|
||||||
|
*/
|
||||||
|
public void setBaseRadiusAutomatic(boolean auto) {
|
||||||
|
if (isFlipped) {
|
||||||
|
setForeRadiusAutomatic(auto);
|
||||||
|
} else {
|
||||||
|
setAftRadiusAutomatic(auto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public double getForeShoulderLength() {
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public double getForeShoulderRadius() {
|
* Returns the shoulder length, regardless of how the nose cone is flipped (independent of whether the nose cone is flipped or not).
|
||||||
return 0;
|
* This method should be used over {@link #getAftShoulderLength()} because it works for both normal and flipped nose cones.
|
||||||
|
*/
|
||||||
|
public double getShoulderLength() {
|
||||||
|
return isFlipped ? getForeShoulderLength() : getAftShoulderLength();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public double getForeShoulderThickness() {
|
* Sets the shoulder length (independent of whether the nose cone is flipped or not).
|
||||||
return 0;
|
* This method should be used over {@link #setAftShoulderLength(double)} because it works for both normal and flipped nose cones.
|
||||||
|
*/
|
||||||
|
public void setShoulderLength(double length) {
|
||||||
|
if (isFlipped) {
|
||||||
|
setForeShoulderLength(length);
|
||||||
|
} else {
|
||||||
|
setAftShoulderLength(length);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public boolean isForeShoulderCapped() {
|
* Returns the shoulder radius (independent of whether the nose cone is flipped or not).
|
||||||
return false;
|
* This method should be used over {@link #getAftShoulderRadius()} because it works for both normal and flipped nose cones.
|
||||||
|
*/
|
||||||
|
public double getShoulderRadius() {
|
||||||
|
return isFlipped ? getForeShoulderRadius() : getAftShoulderRadius();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public void setForeShoulderCapped(boolean capped) {
|
* Sets the shoulder radius (independent of whether the nose cone is flipped or not).
|
||||||
// No-op
|
* This method should be used over {@link #setAftShoulderRadius(double)} because it works for both normal and flipped nose cones.
|
||||||
|
*/
|
||||||
|
public void setShoulderRadius(double radius) {
|
||||||
|
if (isFlipped) {
|
||||||
|
setForeShoulderRadius(radius);
|
||||||
|
} else {
|
||||||
|
setAftShoulderRadius(radius);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public void setForeShoulderLength(double foreShoulderLength) {
|
* Returns the shoulder thickness (independent of whether the nose cone is flipped or not).
|
||||||
// No-op
|
* This method should be used over {@link #getAftShoulderThickness()} because it works for both normal and flipped nose cones.
|
||||||
|
*/
|
||||||
|
public double getShoulderThickness() {
|
||||||
|
return isFlipped ? getForeShoulderThickness() : getAftShoulderThickness();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public void setForeShoulderRadius(double foreShoulderRadius) {
|
* Sets the shoulder thickness (independent of whether the nose cone is flipped or not).
|
||||||
// No-op
|
* This method should be used over {@link #setAftShoulderRadius(double)} because it works for both normal and flipped nose cones.
|
||||||
|
*/
|
||||||
|
public void setShoulderThickness(double thickness) {
|
||||||
|
if (isFlipped) {
|
||||||
|
setForeShoulderThickness(thickness);
|
||||||
|
} else {
|
||||||
|
setAftShoulderThickness(thickness);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public void setForeShoulderThickness(double foreShoulderThickness) {
|
* Returns the shoulder cap (independent of whether the nose cone is flipped or not).
|
||||||
// No-op
|
* This method should be used over {@link #isAftShoulderCapped()} because it works for both normal and flipped nose cones.
|
||||||
|
*/
|
||||||
|
public boolean isShoulderCapped() {
|
||||||
|
return isFlipped ? isForeShoulderCapped() : isAftShoulderCapped();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the shoulder cap (independent of whether the nose cone is flipped or not).
|
||||||
|
* This method should be used over {@link #setAftShoulderCapped(boolean)} because it works for both normal and flipped nose cones.
|
||||||
|
*/
|
||||||
|
public void setShoulderCapped(boolean capped) {
|
||||||
|
if (isFlipped) {
|
||||||
|
setForeShoulderCapped(capped);
|
||||||
|
} else {
|
||||||
|
setAftShoulderCapped(capped);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/********** Other **********/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if the nose cone is flipped, i.e. converted to a tail cone, false if it is a regular nose cone.
|
||||||
|
*/
|
||||||
|
public boolean isFlipped() {
|
||||||
|
return isFlipped;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the nose cone to be flipped, i.e. converted to a tail cone, or set it to be a regular nose cone.
|
||||||
|
* @param flipped if true, the nose cone is converted to a tail cone, if false it is a regular nose cone.
|
||||||
|
* @param sanityCheck whether to check if the auto radius parameter can be used for the new nose cone orientation
|
||||||
|
*/
|
||||||
|
public void setFlipped(boolean flipped, boolean sanityCheck) {
|
||||||
|
if (isFlipped == flipped) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setBypassChangeEvent(true);
|
||||||
|
if (flipped) {
|
||||||
|
setForeRadius(getAftRadiusNoAutomatic());
|
||||||
|
setForeRadiusAutomatic(isAftRadiusAutomatic(), sanityCheck);
|
||||||
|
setForeShoulderLength(getAftShoulderLength());
|
||||||
|
setForeShoulderRadius(getAftShoulderRadius());
|
||||||
|
setForeShoulderThickness(getAftShoulderThickness());
|
||||||
|
setForeShoulderCapped(isAftShoulderCapped());
|
||||||
|
|
||||||
|
resetAftRadius();
|
||||||
|
} else {
|
||||||
|
setAftRadius(getForeRadiusNoAutomatic());
|
||||||
|
setAftRadiusAutomatic(isForeRadiusAutomatic(), sanityCheck);
|
||||||
|
setAftShoulderLength(getForeShoulderLength());
|
||||||
|
setAftShoulderRadius(getForeShoulderRadius());
|
||||||
|
setAftShoulderThickness(getForeShoulderThickness());
|
||||||
|
setAftShoulderCapped(isForeShoulderCapped());
|
||||||
|
|
||||||
|
resetForeRadius();
|
||||||
|
}
|
||||||
|
setBypassChangeEvent(false);
|
||||||
|
|
||||||
|
isFlipped = flipped;
|
||||||
|
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the nose cone to be flipped, i.e. converted to a tail cone, or set it to be a regular nose cone.
|
||||||
|
* @param flipped if true, the nose cone is converted to a tail cone, if false it is a regular nose cone.
|
||||||
|
*/
|
||||||
|
public void setFlipped(boolean flipped) {
|
||||||
|
setFlipped(flipped, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resetForeRadius() {
|
||||||
|
setForeRadius(0);
|
||||||
|
setForeRadiusAutomatic(false);
|
||||||
|
setForeShoulderLength(0);
|
||||||
|
setForeShoulderRadius(0);
|
||||||
|
setForeShoulderThickness(0);
|
||||||
|
setForeShoulderCapped(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resetAftRadius() {
|
||||||
|
setAftRadius(0);
|
||||||
|
setAftRadiusAutomatic(false);
|
||||||
|
setAftShoulderLength(0);
|
||||||
|
setAftShoulderRadius(0);
|
||||||
|
setAftShoulderThickness(0);
|
||||||
|
setAftShoulderCapped(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -125,8 +261,6 @@ public class NoseCone extends Transition implements InsideColorComponent {
|
|||||||
// No-op
|
// No-op
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/********** RocketComponent methods **********/
|
/********** RocketComponent methods **********/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -136,7 +270,7 @@ public class NoseCone extends Transition implements InsideColorComponent {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void loadFromPreset(ComponentPreset preset) {
|
protected void loadFromPreset(ComponentPreset preset) {
|
||||||
|
setFlipped(false);
|
||||||
//Many parameters are handled by the super class Transition.loadFromPreset
|
//Many parameters are handled by the super class Transition.loadFromPreset
|
||||||
super.loadFromPreset(preset);
|
super.loadFromPreset(preset);
|
||||||
}
|
}
|
||||||
|
@ -208,12 +208,6 @@ public class RailButton extends ExternalComponent implements AnglePositionable,
|
|||||||
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
|
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isAerodynamic(){
|
|
||||||
// TODO: implement aerodynamics
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double getAngleOffset(){
|
public double getAngleOffset(){
|
||||||
return angle_rad;
|
return angle_rad;
|
||||||
|
@ -5,17 +5,13 @@ import static net.sf.openrocket.util.MathUtil.pow2;
|
|||||||
import static net.sf.openrocket.util.MathUtil.pow3;
|
import static net.sf.openrocket.util.MathUtil.pow3;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.EventObject;
|
|
||||||
|
|
||||||
import net.sf.openrocket.appearance.Appearance;
|
|
||||||
import net.sf.openrocket.appearance.Decal;
|
|
||||||
import net.sf.openrocket.l10n.Translator;
|
import net.sf.openrocket.l10n.Translator;
|
||||||
import net.sf.openrocket.preset.ComponentPreset;
|
import net.sf.openrocket.preset.ComponentPreset;
|
||||||
import net.sf.openrocket.preset.ComponentPreset.Type;
|
import net.sf.openrocket.preset.ComponentPreset.Type;
|
||||||
import net.sf.openrocket.startup.Application;
|
import net.sf.openrocket.startup.Application;
|
||||||
import net.sf.openrocket.util.Coordinate;
|
import net.sf.openrocket.util.Coordinate;
|
||||||
import net.sf.openrocket.util.MathUtil;
|
import net.sf.openrocket.util.MathUtil;
|
||||||
import net.sf.openrocket.util.StateChangeListener;
|
|
||||||
|
|
||||||
|
|
||||||
public class Transition extends SymmetricComponent implements InsideColorComponent {
|
public class Transition extends SymmetricComponent implements InsideColorComponent {
|
||||||
@ -27,8 +23,8 @@ public class Transition extends SymmetricComponent implements InsideColorCompone
|
|||||||
private double shapeParameter;
|
private double shapeParameter;
|
||||||
private boolean clipped; // Not to be read - use isClipped(), which may be overridden
|
private boolean clipped; // Not to be read - use isClipped(), which may be overridden
|
||||||
|
|
||||||
private double foreRadius, aftRadius;
|
protected double foreRadius, aftRadius; // Warning: avoid using these directly, use getForeRadius() and getAftRadius() instead (because the definition of the two can change for flipped nose cones)
|
||||||
private boolean autoForeRadius, autoAftRadius2; // Whether the start radius is automatic
|
protected boolean autoForeRadius, autoAftRadius; // Whether the start radius is automatic
|
||||||
|
|
||||||
|
|
||||||
private double foreShoulderRadius;
|
private double foreShoulderRadius;
|
||||||
@ -53,7 +49,7 @@ public class Transition extends SymmetricComponent implements InsideColorCompone
|
|||||||
this.aftRadius = DEFAULT_RADIUS;
|
this.aftRadius = DEFAULT_RADIUS;
|
||||||
this.length = DEFAULT_RADIUS * 3;
|
this.length = DEFAULT_RADIUS * 3;
|
||||||
this.autoForeRadius = true;
|
this.autoForeRadius = true;
|
||||||
this.autoAftRadius2 = true;
|
this.autoAftRadius = true;
|
||||||
|
|
||||||
this.type = Shape.CONICAL;
|
this.type = Shape.CONICAL;
|
||||||
this.shapeParameter = 0;
|
this.shapeParameter = 0;
|
||||||
@ -81,19 +77,24 @@ public class Transition extends SymmetricComponent implements InsideColorCompone
|
|||||||
@Override
|
@Override
|
||||||
public double getForeRadius() {
|
public double getForeRadius() {
|
||||||
if (isForeRadiusAutomatic()) {
|
if (isForeRadiusAutomatic()) {
|
||||||
// Get the automatic radius from the front
|
return getAutoForeRadius();
|
||||||
double r = -1;
|
|
||||||
SymmetricComponent c = this.getPreviousSymmetricComponent();
|
|
||||||
if (c != null) {
|
|
||||||
r = c.getFrontAutoRadius();
|
|
||||||
}
|
|
||||||
if (r < 0)
|
|
||||||
r = DEFAULT_RADIUS;
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
return foreRadius;
|
return foreRadius;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the automatic radius from the front, taken from the previous component. Returns the default radius if there
|
||||||
|
* is no previous component.
|
||||||
|
*/
|
||||||
|
protected double getAutoForeRadius() {
|
||||||
|
SymmetricComponent c = this.getPreviousSymmetricComponent();
|
||||||
|
if (c != null) {
|
||||||
|
return c.getFrontAutoRadius();
|
||||||
|
} else {
|
||||||
|
return DEFAULT_RADIUS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the fore radius that was manually entered, so not the value that the component received from automatic
|
* Return the fore radius that was manually entered, so not the value that the component received from automatic
|
||||||
* fore radius.
|
* fore radius.
|
||||||
@ -136,13 +137,24 @@ public class Transition extends SymmetricComponent implements InsideColorCompone
|
|||||||
return autoForeRadius;
|
return autoForeRadius;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setForeRadiusAutomatic(boolean auto) {
|
/**
|
||||||
|
* Set the fore radius to automatic mode (takes its value from the previous symmetric component's radius).
|
||||||
|
*
|
||||||
|
* @param auto whether to set the fore radius to automatic mode
|
||||||
|
* @param sanityCheck whether to sanity check auto mode for whether there is a previous component of which you can take the radius
|
||||||
|
*/
|
||||||
|
public void setForeRadiusAutomatic(boolean auto, boolean sanityCheck) {
|
||||||
for (RocketComponent listener : configListeners) {
|
for (RocketComponent listener : configListeners) {
|
||||||
if (listener instanceof Transition) {
|
if (listener instanceof Transition) {
|
||||||
((Transition) listener).setForeRadiusAutomatic(auto);
|
((Transition) listener).setForeRadiusAutomatic(auto);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// You can only set the auto fore radius if it is possible
|
||||||
|
if (sanityCheck) {
|
||||||
|
auto = auto && canUsePreviousCompAutomatic();
|
||||||
|
}
|
||||||
|
|
||||||
if (autoForeRadius == auto)
|
if (autoForeRadius == auto)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -152,25 +164,34 @@ public class Transition extends SymmetricComponent implements InsideColorCompone
|
|||||||
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
|
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setForeRadiusAutomatic(boolean auto) {
|
||||||
|
setForeRadiusAutomatic(auto, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//////// Aft radius /////////
|
//////// Aft radius /////////
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public double getAftRadius() {
|
public double getAftRadius() {
|
||||||
if (isAftRadiusAutomatic()) {
|
if (isAftRadiusAutomatic()) {
|
||||||
// Return the auto radius from the rear
|
return getAutoAftRadius();
|
||||||
double r = -1;
|
|
||||||
SymmetricComponent c = this.getNextSymmetricComponent();
|
|
||||||
if (c != null) {
|
|
||||||
r = c.getRearAutoRadius();
|
|
||||||
}
|
|
||||||
if (r < 0)
|
|
||||||
r = DEFAULT_RADIUS;
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
return aftRadius;
|
return aftRadius;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the automatic radius from the rear, taken from the next component. Returns the default radius if there
|
||||||
|
* is no next component.
|
||||||
|
*/
|
||||||
|
protected double getAutoAftRadius() {
|
||||||
|
SymmetricComponent c = this.getNextSymmetricComponent();
|
||||||
|
if (c != null) {
|
||||||
|
return c.getRearAutoRadius();
|
||||||
|
} else {
|
||||||
|
return DEFAULT_RADIUS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the aft radius that was manually entered, so not the value that the component received from automatic
|
* Return the aft radius that was manually entered, so not the value that the component received from automatic
|
||||||
* zft radius.
|
* zft radius.
|
||||||
@ -191,10 +212,10 @@ public class Transition extends SymmetricComponent implements InsideColorCompone
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((this.aftRadius == radius) && (autoAftRadius2 == false))
|
if ((this.aftRadius == radius) && (autoAftRadius == false))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this.autoAftRadius2 = false;
|
this.autoAftRadius = false;
|
||||||
this.aftRadius = Math.max(radius, 0);
|
this.aftRadius = Math.max(radius, 0);
|
||||||
|
|
||||||
if (doClamping && this.thickness > this.foreRadius && this.thickness > this.aftRadius)
|
if (doClamping && this.thickness > this.foreRadius && this.thickness > this.aftRadius)
|
||||||
@ -210,25 +231,40 @@ public class Transition extends SymmetricComponent implements InsideColorCompone
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isAftRadiusAutomatic() {
|
public boolean isAftRadiusAutomatic() {
|
||||||
return autoAftRadius2;
|
return autoAftRadius;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAftRadiusAutomatic(boolean auto) {
|
/**
|
||||||
|
* Set the aft radius to automatic mode (takes its value from the next symmetric component's radius).
|
||||||
|
*
|
||||||
|
* @param auto whether to set the aft radius to automatic mode
|
||||||
|
* @param sanityCheck whether to sanity check auto mode for whether there is a next component of which you can take the radius
|
||||||
|
*/
|
||||||
|
public void setAftRadiusAutomatic(boolean auto, boolean sanityCheck) {
|
||||||
for (RocketComponent listener : configListeners) {
|
for (RocketComponent listener : configListeners) {
|
||||||
if (listener instanceof Transition) {
|
if (listener instanceof Transition) {
|
||||||
((Transition) listener).setAftRadiusAutomatic(auto);
|
((Transition) listener).setAftRadiusAutomatic(auto);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (autoAftRadius2 == auto)
|
// You can only set the auto aft radius if it is possible
|
||||||
|
if (sanityCheck) {
|
||||||
|
auto = auto && canUseNextCompAutomatic();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (autoAftRadius == auto)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
autoAftRadius2 = auto;
|
autoAftRadius = auto;
|
||||||
|
|
||||||
clearPreset();
|
clearPreset();
|
||||||
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
|
fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setAftRadiusAutomatic(boolean auto) {
|
||||||
|
setAftRadiusAutomatic(auto, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//// Radius automatics
|
//// Radius automatics
|
||||||
|
|
||||||
@ -257,6 +293,32 @@ public class Transition extends SymmetricComponent implements InsideColorCompone
|
|||||||
return isAftRadiusAutomatic();
|
return isAftRadiusAutomatic();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether this component can use the automatic radius of the previous symmetric component.
|
||||||
|
* @return false if there is no previous symmetric component, or if the previous component already has this component
|
||||||
|
* as its auto dimension reference
|
||||||
|
*/
|
||||||
|
public boolean canUsePreviousCompAutomatic() {
|
||||||
|
SymmetricComponent referenceComp = getPreviousSymmetricComponent();
|
||||||
|
if (referenceComp == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return !referenceComp.usesNextCompAutomatic();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether this component can use the automatic radius of the next symmetric component.
|
||||||
|
* @return false if there is no next symmetric component, or if the next component already has this component
|
||||||
|
* as its auto dimension reference
|
||||||
|
*/
|
||||||
|
public boolean canUseNextCompAutomatic() {
|
||||||
|
SymmetricComponent referenceComp = getNextSymmetricComponent();
|
||||||
|
if (referenceComp == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return !referenceComp.usesPreviousCompAutomatic();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//////// Type & shape /////////
|
//////// Type & shape /////////
|
||||||
|
|
||||||
|
@ -59,11 +59,13 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
|||||||
// this is just a list of simulation branches to
|
// this is just a list of simulation branches to
|
||||||
Deque<SimulationStatus> toSimulate = new ArrayDeque<SimulationStatus>();
|
Deque<SimulationStatus> toSimulate = new ArrayDeque<SimulationStatus>();
|
||||||
|
|
||||||
|
FlightData flightData;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FlightData simulate(SimulationConditions simulationConditions) throws SimulationException {
|
public FlightData simulate(SimulationConditions simulationConditions) throws SimulationException {
|
||||||
|
|
||||||
// Set up flight data
|
// Set up flight data
|
||||||
FlightData flightData = new FlightData();
|
flightData = new FlightData();
|
||||||
|
|
||||||
// Set up rocket configuration
|
// Set up rocket configuration
|
||||||
this.fcid = simulationConditions.getFlightConfigurationID();
|
this.fcid = simulationConditions.getFlightConfigurationID();
|
||||||
@ -269,6 +271,11 @@ public class BasicEventSimulationEngine implements SimulationEngine {
|
|||||||
// Add FlightEvent for Abort.
|
// Add FlightEvent for Abort.
|
||||||
currentStatus.getFlightData().addEvent(new FlightEvent(FlightEvent.Type.EXCEPTION, currentStatus.getSimulationTime(), currentStatus.getConfiguration().getRocket(), e.getLocalizedMessage()));
|
currentStatus.getFlightData().addEvent(new FlightEvent(FlightEvent.Type.EXCEPTION, currentStatus.getSimulationTime(), currentStatus.getConfiguration().getRocket(), e.getLocalizedMessage()));
|
||||||
|
|
||||||
|
flightData.addBranch(currentStatus.getFlightData());
|
||||||
|
flightData.getWarningSet().addAll(currentStatus.getWarnings());
|
||||||
|
|
||||||
|
e.setFlightData(flightData);
|
||||||
|
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
package net.sf.openrocket.simulation.exception;
|
package net.sf.openrocket.simulation.exception;
|
||||||
|
|
||||||
|
import net.sf.openrocket.simulation.FlightData;
|
||||||
|
|
||||||
public class SimulationException extends Exception {
|
public class SimulationException extends Exception {
|
||||||
|
|
||||||
|
private FlightData flightData = null;
|
||||||
|
|
||||||
public SimulationException() {
|
public SimulationException() {
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -18,4 +22,11 @@ public class SimulationException extends Exception {
|
|||||||
super(message, cause);
|
super(message, cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setFlightData(FlightData f) {
|
||||||
|
flightData = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FlightData getFlightData() {
|
||||||
|
return flightData;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
101
core/test/net/sf/openrocket/aerodynamics/RailButtonCalcTest.java
Normal file
101
core/test/net/sf/openrocket/aerodynamics/RailButtonCalcTest.java
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
package net.sf.openrocket.aerodynamics;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import com.google.inject.Guice;
|
||||||
|
import com.google.inject.Injector;
|
||||||
|
import com.google.inject.Module;
|
||||||
|
|
||||||
|
import net.sf.openrocket.ServicesForTesting;
|
||||||
|
import net.sf.openrocket.aerodynamics.BarrowmanCalculator;
|
||||||
|
import net.sf.openrocket.aerodynamics.barrowman.RailButtonCalc;
|
||||||
|
import net.sf.openrocket.plugin.PluginModule;
|
||||||
|
import net.sf.openrocket.rocketcomponent.FlightConfiguration;
|
||||||
|
import net.sf.openrocket.rocketcomponent.BodyTube;
|
||||||
|
import net.sf.openrocket.rocketcomponent.RailButton;
|
||||||
|
import net.sf.openrocket.rocketcomponent.LaunchLug;
|
||||||
|
import net.sf.openrocket.rocketcomponent.Rocket;
|
||||||
|
import net.sf.openrocket.rocketcomponent.position.AxialMethod;
|
||||||
|
import net.sf.openrocket.startup.Application;
|
||||||
|
import net.sf.openrocket.util.MathUtil;
|
||||||
|
import net.sf.openrocket.util.TestRockets;
|
||||||
|
import net.sf.openrocket.util.Transformation;
|
||||||
|
|
||||||
|
public class RailButtonCalcTest {
|
||||||
|
protected final double EPSILON = 0.0001;
|
||||||
|
|
||||||
|
private static Injector injector;
|
||||||
|
@BeforeClass
|
||||||
|
public static void setup() {
|
||||||
|
Module applicationModule = new ServicesForTesting();
|
||||||
|
Module pluginModule = new PluginModule();
|
||||||
|
|
||||||
|
injector = Guice.createInjector( applicationModule, pluginModule);
|
||||||
|
Application.setInjector(injector);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRailButtons() {
|
||||||
|
|
||||||
|
Rocket rocket = TestRockets.makeEstesAlphaIII();
|
||||||
|
FlightConfiguration config = rocket.getSelectedConfiguration();
|
||||||
|
|
||||||
|
// Get the body tube...
|
||||||
|
BodyTube tube = (BodyTube)rocket.getChild(0).getChild(1);
|
||||||
|
|
||||||
|
// Replace the launch lug with a (single) railbutton
|
||||||
|
LaunchLug lug = (LaunchLug)tube.getChild(1);
|
||||||
|
rocket.removeChild(lug);
|
||||||
|
|
||||||
|
RailButton button = new RailButton();
|
||||||
|
tube.addChild(button);
|
||||||
|
|
||||||
|
// Button parameters from Binder Design standard 1010
|
||||||
|
button.setOuterDiameter(0.011);
|
||||||
|
button.setInnerDiameter(0.006);
|
||||||
|
|
||||||
|
button.setBaseHeight(0.002);
|
||||||
|
button.setFlangeHeight(0.002);
|
||||||
|
button.setTotalHeight(0.008);
|
||||||
|
|
||||||
|
button.setAxialMethod(AxialMethod.ABSOLUTE);
|
||||||
|
button.setAxialOffset(1.0);
|
||||||
|
|
||||||
|
// Set up flight conditions
|
||||||
|
FlightConditions conditions = new FlightConditions(config);
|
||||||
|
conditions.setMach(1.0);
|
||||||
|
|
||||||
|
BarrowmanCalculator barrowmanObj = new BarrowmanCalculator();
|
||||||
|
RailButtonCalc calcObj = new RailButtonCalc(button);
|
||||||
|
|
||||||
|
// Calculate effective CD for rail button
|
||||||
|
// Boundary layer height
|
||||||
|
double rex = calcObj.calculateReynoldsNumber(1.0, conditions); // Reynolds number of button location
|
||||||
|
double del = 0.37 * 1.0 / Math.pow(rex, 0.2); // Boundary layer height
|
||||||
|
|
||||||
|
// Interpolate velocity at midpoint of railbutton
|
||||||
|
double mach = MathUtil.map(0.008/2.0, 0, del, 0, 1.0);
|
||||||
|
|
||||||
|
// Interpolate to get CD
|
||||||
|
double cd = MathUtil.map(mach, 0.2, 0.3, 1.22, 1.25);
|
||||||
|
|
||||||
|
// Reference area of rail button
|
||||||
|
final double outerArea = button.getTotalHeight() * button.getOuterDiameter();
|
||||||
|
final double notchArea = (button.getOuterDiameter() - button.getInnerDiameter()) * button.getInnerHeight();
|
||||||
|
final double refArea = outerArea - notchArea;
|
||||||
|
|
||||||
|
// Get "effective" CD
|
||||||
|
double calccd = cd * MathUtil.pow2(mach) * barrowmanObj.calculateStagnationCD(conditions.getMach()) * refArea / conditions.getRefArea() ;
|
||||||
|
|
||||||
|
// Now compare with value from RailButtonCalc
|
||||||
|
WarningSet warnings = new WarningSet();
|
||||||
|
AerodynamicForces assemblyForces = new AerodynamicForces().zero();
|
||||||
|
AerodynamicForces componentForces = new AerodynamicForces();
|
||||||
|
|
||||||
|
double testcd = calcObj.calculatePressureCD(conditions, barrowmanObj.calculateStagnationCD(conditions.getMach()), 0, warnings);
|
||||||
|
|
||||||
|
assertEquals("Calculated rail button CD incorrect", calccd, testcd, EPSILON);
|
||||||
|
}
|
||||||
|
}
|
@ -23,7 +23,7 @@ public class ThrustCurveMotorSetTest {
|
|||||||
private static final ThrustCurveMotor motor1 = new ThrustCurveMotor.Builder()
|
private static final ThrustCurveMotor motor1 = new ThrustCurveMotor.Builder()
|
||||||
.setManufacturer(Manufacturer.getManufacturer("A"))
|
.setManufacturer(Manufacturer.getManufacturer("A"))
|
||||||
.setCommonName("F12")
|
.setCommonName("F12")
|
||||||
.setDesignation("F12X")
|
.setDesignation("F12")
|
||||||
.setDescription("Desc")
|
.setDescription("Desc")
|
||||||
.setMotorType(Motor.Type.UNKNOWN)
|
.setMotorType(Motor.Type.UNKNOWN)
|
||||||
.setStandardDelays(new double[] {})
|
.setStandardDelays(new double[] {})
|
||||||
@ -38,7 +38,7 @@ public class ThrustCurveMotorSetTest {
|
|||||||
private static final ThrustCurveMotor motor2 = new ThrustCurveMotor.Builder()
|
private static final ThrustCurveMotor motor2 = new ThrustCurveMotor.Builder()
|
||||||
.setManufacturer(Manufacturer.getManufacturer("A"))
|
.setManufacturer(Manufacturer.getManufacturer("A"))
|
||||||
.setCommonName("F12")
|
.setCommonName("F12")
|
||||||
.setDesignation("F12H")
|
.setDesignation("F12")
|
||||||
.setDescription("Desc")
|
.setDescription("Desc")
|
||||||
.setMotorType(Motor.Type.SINGLE)
|
.setMotorType(Motor.Type.SINGLE)
|
||||||
.setStandardDelays(new double[] { 5 })
|
.setStandardDelays(new double[] { 5 })
|
||||||
@ -51,20 +51,6 @@ public class ThrustCurveMotorSetTest {
|
|||||||
.build();
|
.build();
|
||||||
|
|
||||||
private static final ThrustCurveMotor motor3 = new ThrustCurveMotor.Builder()
|
private static final ThrustCurveMotor motor3 = new ThrustCurveMotor.Builder()
|
||||||
.setManufacturer(Manufacturer.getManufacturer("A"))
|
|
||||||
.setCode("F12")
|
|
||||||
.setDescription("Desc")
|
|
||||||
.setMotorType(Motor.Type.UNKNOWN)
|
|
||||||
.setStandardDelays(new double[] { 0, Motor.PLUGGED_DELAY })
|
|
||||||
.setDiameter(0.024)
|
|
||||||
.setLength(0.07)
|
|
||||||
.setTimePoints(new double[] { 0, 1, 2 })
|
|
||||||
.setThrustPoints(new double[] { 0, 2, 0 })
|
|
||||||
.setCGPoints(new Coordinate[] { Coordinate.NUL, Coordinate.NUL, Coordinate.NUL })
|
|
||||||
.setDigest("digestC")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
private static final ThrustCurveMotor motor4 = new ThrustCurveMotor.Builder()
|
|
||||||
.setManufacturer(Manufacturer.getManufacturer("A"))
|
.setManufacturer(Manufacturer.getManufacturer("A"))
|
||||||
.setDesignation("F12")
|
.setDesignation("F12")
|
||||||
.setDescription("Desc")
|
.setDescription("Desc")
|
||||||
@ -113,39 +99,20 @@ public class ThrustCurveMotorSetTest {
|
|||||||
// Add motor2
|
// Add motor2
|
||||||
assertTrue(set.matches(motor2));
|
assertTrue(set.matches(motor2));
|
||||||
set.addMotor(motor2);
|
set.addMotor(motor2);
|
||||||
assertEquals(motor1.getManufacturer(), set.getManufacturer());
|
assertEquals(motor2.getManufacturer(), set.getManufacturer());
|
||||||
assertEquals(motor3.getCommonName(), set.getCommonName());
|
assertEquals(motor2.getCommonName(), set.getCommonName());
|
||||||
assertEquals(Motor.Type.SINGLE, set.getType());
|
assertEquals(Motor.Type.SINGLE, set.getType());
|
||||||
assertEquals(motor1.getDiameter(), set.getDiameter(), 0.00001);
|
assertEquals(motor2.getDiameter(), set.getDiameter(), 0.00001);
|
||||||
assertEquals(motor1.getLength(), set.getLength(), 0.00001);
|
assertEquals(motor2.getLength(), set.getLength(), 0.00001);
|
||||||
assertEquals(2, set.getMotors().size());
|
assertEquals(2, set.getMotors().size());
|
||||||
assertEquals(motor2, set.getMotors().get(0));
|
assertEquals(motor1, set.getMotors().get(0));
|
||||||
assertEquals(motor1, set.getMotors().get(1));
|
assertEquals(motor2, set.getMotors().get(1));
|
||||||
assertEquals(Arrays.asList(5.0), set.getDelays());
|
assertEquals(Arrays.asList(5.0), set.getDelays());
|
||||||
|
|
||||||
// Add motor3
|
// Test that adding motor3 fails
|
||||||
assertTrue(set.matches(motor3));
|
assertFalse(set.matches(motor3));
|
||||||
set.addMotor(motor3);
|
|
||||||
assertEquals(motor1.getManufacturer(), set.getManufacturer());
|
|
||||||
assertEquals(motor3.getCommonName(), set.getCommonName());
|
|
||||||
assertEquals(Motor.Type.SINGLE, set.getType());
|
|
||||||
assertEquals(motor1.getDiameter(), set.getDiameter(), 0.00001);
|
|
||||||
assertEquals(motor1.getLength(), set.getLength(), 0.00001);
|
|
||||||
assertEquals(3, set.getMotors().size());
|
|
||||||
System.out.println("motor set");
|
|
||||||
System.out.println(set.getMotors());
|
|
||||||
System.out.println(motor3);
|
|
||||||
System.out.println(motor2);
|
|
||||||
System.out.println(motor1);
|
|
||||||
assertEquals(motor3, set.getMotors().get(0));
|
|
||||||
assertEquals(motor2, set.getMotors().get(1));
|
|
||||||
assertEquals(motor1, set.getMotors().get(2));
|
|
||||||
assertEquals(Arrays.asList(0.0, 5.0, Motor.PLUGGED_DELAY), set.getDelays());
|
|
||||||
|
|
||||||
// Test that adding motor4 fails
|
|
||||||
assertFalse(set.matches(motor4));
|
|
||||||
try {
|
try {
|
||||||
set.addMotor(motor4);
|
set.addMotor(motor3);
|
||||||
fail("Did not throw exception");
|
fail("Did not throw exception");
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
}
|
}
|
||||||
|
398
core/test/net/sf/openrocket/rocketcomponent/NoseConeTest.java
Normal file
398
core/test/net/sf/openrocket/rocketcomponent/NoseConeTest.java
Normal file
@ -0,0 +1,398 @@
|
|||||||
|
package net.sf.openrocket.rocketcomponent;
|
||||||
|
|
||||||
|
import net.sf.openrocket.document.OpenRocketDocumentFactory;
|
||||||
|
import net.sf.openrocket.util.BaseTestCase.BaseTestCase;
|
||||||
|
import net.sf.openrocket.util.MathUtil;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertSame;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
public class NoseConeTest extends BaseTestCase {
|
||||||
|
private final double EPSILON = MathUtil.EPSILON * 1000;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNormalNoseCone() {
|
||||||
|
NoseCone noseCone = new NoseCone();
|
||||||
|
|
||||||
|
// First set the parameters using the normal transition setters (i.e. using AftRadius and AftShoulder instead of Base and Shoulder)
|
||||||
|
noseCone.setType(Transition.Shape.OGIVE);
|
||||||
|
noseCone.setLength(0.06);
|
||||||
|
noseCone.setAftRadius(0.1);
|
||||||
|
noseCone.setAftShoulderLength(0.01);
|
||||||
|
noseCone.setAftShoulderRadius(0.05);
|
||||||
|
noseCone.setAftShoulderCapped(false);
|
||||||
|
noseCone.setAftShoulderThickness(0.001);
|
||||||
|
|
||||||
|
assertEquals(Transition.Shape.OGIVE, noseCone.getType());
|
||||||
|
assertEquals(0.06, noseCone.getLength(), EPSILON);
|
||||||
|
assertEquals(0.1, noseCone.getAftRadius(), EPSILON);
|
||||||
|
assertEquals(0.1, noseCone.getBaseRadius(), EPSILON);
|
||||||
|
assertEquals(0.1, noseCone.getAftRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(0.1, noseCone.getBaseRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(0.01, noseCone.getAftShoulderLength(), EPSILON);
|
||||||
|
assertEquals(0.01, noseCone.getShoulderLength(), EPSILON);
|
||||||
|
assertEquals(0.05, noseCone.getAftShoulderRadius(), EPSILON);
|
||||||
|
assertEquals(0.05, noseCone.getShoulderRadius(), EPSILON);
|
||||||
|
assertFalse(noseCone.isAftShoulderCapped());
|
||||||
|
assertFalse(noseCone.isShoulderCapped());
|
||||||
|
assertEquals(0.001, noseCone.getAftShoulderThickness(), EPSILON);
|
||||||
|
assertEquals(0.001, noseCone.getShoulderThickness(), EPSILON);
|
||||||
|
assertFalse(noseCone.isAftRadiusAutomatic());
|
||||||
|
|
||||||
|
assertEquals(0, noseCone.getForeRadius(), EPSILON);
|
||||||
|
assertEquals(0, noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(0, noseCone.getForeShoulderLength(), EPSILON);
|
||||||
|
assertEquals(0, noseCone.getForeShoulderRadius(), EPSILON);
|
||||||
|
assertEquals(0, noseCone.getForeShoulderThickness(), EPSILON);
|
||||||
|
assertFalse(noseCone.isForeShoulderCapped());
|
||||||
|
assertFalse(noseCone.isForeRadiusAutomatic());
|
||||||
|
|
||||||
|
// Test setting the specific nose cone setters
|
||||||
|
noseCone.setBaseRadius(0.2);
|
||||||
|
noseCone.setShoulderLength(0.03);
|
||||||
|
noseCone.setShoulderRadius(0.04);
|
||||||
|
noseCone.setShoulderCapped(true);
|
||||||
|
noseCone.setShoulderThickness(0.005);
|
||||||
|
|
||||||
|
assertEquals(0.2, noseCone.getAftRadius(), EPSILON);
|
||||||
|
assertEquals(0.2, noseCone.getBaseRadius(), EPSILON);
|
||||||
|
assertEquals(0.2, noseCone.getAftRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(0.2, noseCone.getBaseRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(0.03, noseCone.getAftShoulderLength(), EPSILON);
|
||||||
|
assertEquals(0.03, noseCone.getShoulderLength(), EPSILON);
|
||||||
|
assertEquals(0.04, noseCone.getAftShoulderRadius(), EPSILON);
|
||||||
|
assertEquals(0.04, noseCone.getShoulderRadius(), EPSILON);
|
||||||
|
assertTrue(noseCone.isAftShoulderCapped());
|
||||||
|
assertTrue(noseCone.isShoulderCapped());
|
||||||
|
assertEquals(0.005, noseCone.getAftShoulderThickness(), EPSILON);
|
||||||
|
assertEquals(0.005, noseCone.getShoulderThickness(), EPSILON);
|
||||||
|
assertFalse(noseCone.isAftRadiusAutomatic());
|
||||||
|
|
||||||
|
assertEquals(0, noseCone.getForeRadius(), EPSILON);
|
||||||
|
assertEquals(0, noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(0, noseCone.getForeShoulderLength(), EPSILON);
|
||||||
|
assertEquals(0, noseCone.getForeShoulderRadius(), EPSILON);
|
||||||
|
assertEquals(0, noseCone.getForeShoulderThickness(), EPSILON);
|
||||||
|
assertFalse(noseCone.isForeShoulderCapped());
|
||||||
|
assertFalse(noseCone.isForeRadiusAutomatic());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFlippedNoseCone() {
|
||||||
|
NoseCone noseCone = new NoseCone();
|
||||||
|
|
||||||
|
// First set the parameters using the normal transition setters (i.e. using AftRadius and AftShoulder instead of Base and Shoulder)
|
||||||
|
noseCone.setType(Transition.Shape.OGIVE);
|
||||||
|
noseCone.setLength(0.06);
|
||||||
|
noseCone.setAftRadius(0.1);
|
||||||
|
noseCone.setAftShoulderLength(0.01);
|
||||||
|
noseCone.setAftShoulderRadius(0.05);
|
||||||
|
noseCone.setAftShoulderCapped(false);
|
||||||
|
noseCone.setAftShoulderThickness(0.001);
|
||||||
|
noseCone.setFlipped(true);
|
||||||
|
|
||||||
|
assertEquals(Transition.Shape.OGIVE, noseCone.getType());
|
||||||
|
assertEquals(0.06, noseCone.getLength(), EPSILON);
|
||||||
|
assertEquals(0.1, noseCone.getForeRadius(), EPSILON);
|
||||||
|
assertEquals(0.1, noseCone.getBaseRadius(), EPSILON);
|
||||||
|
assertEquals(0.1, noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(0.1, noseCone.getBaseRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(0.01, noseCone.getForeShoulderLength(), EPSILON);
|
||||||
|
assertEquals(0.01, noseCone.getShoulderLength(), EPSILON);
|
||||||
|
assertEquals(0.05, noseCone.getForeShoulderRadius(), EPSILON);
|
||||||
|
assertEquals(0.05, noseCone.getShoulderRadius(), EPSILON);
|
||||||
|
assertFalse(noseCone.isForeShoulderCapped());
|
||||||
|
assertFalse(noseCone.isShoulderCapped());
|
||||||
|
assertEquals(0.001, noseCone.getForeShoulderThickness(), EPSILON);
|
||||||
|
assertEquals(0.001, noseCone.getShoulderThickness(), EPSILON);
|
||||||
|
assertFalse(noseCone.isForeRadiusAutomatic());
|
||||||
|
|
||||||
|
assertEquals(0, noseCone.getAftRadius(), EPSILON);
|
||||||
|
assertEquals(0, noseCone.getAftRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(0, noseCone.getAftShoulderLength(), EPSILON);
|
||||||
|
assertEquals(0, noseCone.getAftShoulderRadius(), EPSILON);
|
||||||
|
assertEquals(0, noseCone.getAftShoulderThickness(), EPSILON);
|
||||||
|
assertFalse(noseCone.isAftShoulderCapped());
|
||||||
|
assertFalse(noseCone.isAftRadiusAutomatic());
|
||||||
|
|
||||||
|
// Test setting the specific nose cone setters
|
||||||
|
noseCone.setBaseRadius(0.2);
|
||||||
|
noseCone.setShoulderLength(0.03);
|
||||||
|
noseCone.setShoulderRadius(0.04);
|
||||||
|
noseCone.setShoulderCapped(true);
|
||||||
|
noseCone.setShoulderThickness(0.005);
|
||||||
|
|
||||||
|
assertEquals(0.2, noseCone.getForeRadius(), EPSILON);
|
||||||
|
assertEquals(0.2, noseCone.getBaseRadius(), EPSILON);
|
||||||
|
assertEquals(0.2, noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(0.2, noseCone.getBaseRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(0.03, noseCone.getForeShoulderLength(), EPSILON);
|
||||||
|
assertEquals(0.03, noseCone.getShoulderLength(), EPSILON);
|
||||||
|
assertEquals(0.04, noseCone.getForeShoulderRadius(), EPSILON);
|
||||||
|
assertEquals(0.04, noseCone.getShoulderRadius(), EPSILON);
|
||||||
|
assertTrue(noseCone.isForeShoulderCapped());
|
||||||
|
assertTrue(noseCone.isShoulderCapped());
|
||||||
|
assertEquals(0.005, noseCone.getForeShoulderThickness(), EPSILON);
|
||||||
|
assertEquals(0.005, noseCone.getShoulderThickness(), EPSILON);
|
||||||
|
assertFalse(noseCone.isForeRadiusAutomatic());
|
||||||
|
|
||||||
|
assertEquals(0, noseCone.getAftRadius(), EPSILON);
|
||||||
|
assertEquals(0, noseCone.getAftRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(0, noseCone.getAftShoulderLength(), EPSILON);
|
||||||
|
assertEquals(0, noseCone.getAftShoulderRadius(), EPSILON);
|
||||||
|
assertEquals(0, noseCone.getAftShoulderThickness(), EPSILON);
|
||||||
|
assertFalse(noseCone.isAftShoulderCapped());
|
||||||
|
assertFalse(noseCone.isAftRadiusAutomatic());
|
||||||
|
|
||||||
|
// Flip back to normal
|
||||||
|
noseCone.setFlipped(false);
|
||||||
|
|
||||||
|
assertEquals(0.2, noseCone.getAftRadius(), EPSILON);
|
||||||
|
assertEquals(0.2, noseCone.getBaseRadius(), EPSILON);
|
||||||
|
assertEquals(0.2, noseCone.getAftRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(0.2, noseCone.getBaseRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(0.03, noseCone.getAftShoulderLength(), EPSILON);
|
||||||
|
assertEquals(0.03, noseCone.getShoulderLength(), EPSILON);
|
||||||
|
assertEquals(0.04, noseCone.getAftShoulderRadius(), EPSILON);
|
||||||
|
assertEquals(0.04, noseCone.getShoulderRadius(), EPSILON);
|
||||||
|
assertTrue(noseCone.isAftShoulderCapped());
|
||||||
|
assertTrue(noseCone.isShoulderCapped());
|
||||||
|
assertEquals(0.005, noseCone.getAftShoulderThickness(), EPSILON);
|
||||||
|
assertEquals(0.005, noseCone.getShoulderThickness(), EPSILON);
|
||||||
|
assertFalse(noseCone.isAftRadiusAutomatic());
|
||||||
|
|
||||||
|
assertEquals(0, noseCone.getForeRadius(), EPSILON);
|
||||||
|
assertEquals(0, noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(0, noseCone.getForeShoulderLength(), EPSILON);
|
||||||
|
assertEquals(0, noseCone.getForeShoulderRadius(), EPSILON);
|
||||||
|
assertEquals(0, noseCone.getForeShoulderThickness(), EPSILON);
|
||||||
|
assertFalse(noseCone.isForeShoulderCapped());
|
||||||
|
assertFalse(noseCone.isForeRadiusAutomatic());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNormalNoseConeRadiusAutomatic() {
|
||||||
|
Rocket rocket = OpenRocketDocumentFactory.createNewRocket().getRocket();
|
||||||
|
AxialStage stage = rocket.getStage(0);
|
||||||
|
|
||||||
|
NoseCone noseCone = new NoseCone(Transition.Shape.CONICAL, 0.06, 0.01);
|
||||||
|
BodyTube tube1 = new BodyTube(0.06, 0.02);
|
||||||
|
tube1.setOuterRadiusAutomatic(false);
|
||||||
|
BodyTube tube2 = new BodyTube(0.06, 0.03);
|
||||||
|
tube2.setOuterRadiusAutomatic(false);
|
||||||
|
|
||||||
|
// Test no previous or next component
|
||||||
|
stage.addChild(noseCone);
|
||||||
|
|
||||||
|
assertFalse(noseCone.usesPreviousCompAutomatic());
|
||||||
|
assertFalse(noseCone.usesNextCompAutomatic());
|
||||||
|
assertSame(stage, noseCone.getPreviousComponent());
|
||||||
|
assertNull(noseCone.getPreviousSymmetricComponent());
|
||||||
|
assertNull(noseCone.getNextComponent());
|
||||||
|
assertNull(noseCone.getNextSymmetricComponent());
|
||||||
|
assertFalse(noseCone.isAftRadiusAutomatic());
|
||||||
|
assertFalse(noseCone.isBaseRadiusAutomatic());
|
||||||
|
assertFalse(noseCone.isForeRadiusAutomatic());
|
||||||
|
assertEquals(noseCone.getAftRadius(), noseCone.getAftRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(noseCone.getBaseRadius(), noseCone.getBaseRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(noseCone.getForeRadius(), noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(0.01, noseCone.getAftRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(0, noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||||
|
|
||||||
|
noseCone.setAftRadiusAutomatic(true, true);
|
||||||
|
assertFalse(noseCone.isAftRadiusAutomatic());
|
||||||
|
assertFalse(noseCone.isBaseRadiusAutomatic());
|
||||||
|
noseCone.setForeRadiusAutomatic(true, true);
|
||||||
|
assertFalse(noseCone.isForeRadiusAutomatic());
|
||||||
|
assertFalse(noseCone.isBaseRadiusAutomatic());
|
||||||
|
|
||||||
|
// Test with next component
|
||||||
|
stage.addChild(tube1);
|
||||||
|
|
||||||
|
assertFalse(noseCone.usesPreviousCompAutomatic());
|
||||||
|
assertFalse(noseCone.usesNextCompAutomatic());
|
||||||
|
assertSame(stage, noseCone.getPreviousComponent());
|
||||||
|
assertNull(noseCone.getPreviousSymmetricComponent());
|
||||||
|
assertSame(tube1, noseCone.getNextComponent());
|
||||||
|
assertSame(tube1, noseCone.getNextSymmetricComponent());
|
||||||
|
assertFalse(noseCone.isAftRadiusAutomatic());
|
||||||
|
assertFalse(noseCone.isBaseRadiusAutomatic());
|
||||||
|
assertFalse(noseCone.isForeRadiusAutomatic());
|
||||||
|
assertEquals(noseCone.getAftRadius(), noseCone.getAftRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(noseCone.getBaseRadius(), noseCone.getBaseRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(noseCone.getForeRadius(), noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(0, noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||||
|
|
||||||
|
noseCone.setAftRadiusAutomatic(true, true);
|
||||||
|
assertFalse(noseCone.usesPreviousCompAutomatic());
|
||||||
|
assertTrue(noseCone.usesNextCompAutomatic());
|
||||||
|
assertSame(stage, noseCone.getPreviousComponent());
|
||||||
|
assertNull(noseCone.getPreviousSymmetricComponent());
|
||||||
|
assertSame(tube1, noseCone.getNextComponent());
|
||||||
|
assertSame(tube1, noseCone.getNextSymmetricComponent());
|
||||||
|
assertTrue(noseCone.isAftRadiusAutomatic());
|
||||||
|
assertTrue(noseCone.isBaseRadiusAutomatic());
|
||||||
|
assertFalse(noseCone.isForeRadiusAutomatic());
|
||||||
|
assertEquals(tube1.getForeRadius(), noseCone.getAftRadius(), EPSILON);
|
||||||
|
assertEquals(0.01, noseCone.getAftRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(tube1.getForeRadius(), noseCone.getBaseRadius(), EPSILON);
|
||||||
|
assertEquals(0.01, noseCone.getBaseRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(noseCone.getForeRadius(), noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(0, noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||||
|
|
||||||
|
noseCone.setAftRadiusAutomatic(false, true);
|
||||||
|
assertEquals(noseCone.getAftRadius(), noseCone.getAftRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(noseCone.getBaseRadius(), noseCone.getBaseRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(noseCone.getForeRadius(), noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(0, noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||||
|
|
||||||
|
noseCone.setBaseRadiusAutomatic(true);
|
||||||
|
assertEquals(0.01, noseCone.getAftRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(tube1.getForeRadius(), noseCone.getBaseRadius(), EPSILON);
|
||||||
|
assertEquals(0.01, noseCone.getBaseRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(noseCone.getForeRadius(), noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(0, noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||||
|
|
||||||
|
noseCone.setForeRadiusAutomatic(true, true);
|
||||||
|
assertFalse(noseCone.isForeRadiusAutomatic());
|
||||||
|
assertTrue(noseCone.isBaseRadiusAutomatic());
|
||||||
|
|
||||||
|
// Test with previous component
|
||||||
|
stage.addChild(tube2, 0);
|
||||||
|
|
||||||
|
assertFalse(noseCone.usesPreviousCompAutomatic());
|
||||||
|
assertTrue(noseCone.usesNextCompAutomatic());
|
||||||
|
assertSame(tube2, noseCone.getPreviousComponent());
|
||||||
|
assertSame(tube2, noseCone.getPreviousSymmetricComponent());
|
||||||
|
assertSame(tube1, noseCone.getNextComponent());
|
||||||
|
assertSame(tube1, noseCone.getNextSymmetricComponent());
|
||||||
|
assertTrue(noseCone.isAftRadiusAutomatic());
|
||||||
|
assertTrue(noseCone.isBaseRadiusAutomatic());
|
||||||
|
assertFalse(noseCone.isForeRadiusAutomatic());
|
||||||
|
assertEquals(tube1.getForeRadius(), noseCone.getAftRadius(), EPSILON);
|
||||||
|
assertEquals(0.01, noseCone.getAftRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(tube1.getForeRadius(), noseCone.getBaseRadius(), EPSILON);
|
||||||
|
assertEquals(0.01, noseCone.getBaseRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(noseCone.getForeRadius(), noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(0, noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||||
|
|
||||||
|
// Do a flip
|
||||||
|
noseCone.setFlipped(true);
|
||||||
|
assertTrue(noseCone.isForeRadiusAutomatic());
|
||||||
|
assertTrue(noseCone.isBaseRadiusAutomatic());
|
||||||
|
assertFalse(noseCone.isAftRadiusAutomatic());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFlippedNoseConeRadiusAutomatic() {
|
||||||
|
Rocket rocket = OpenRocketDocumentFactory.createNewRocket().getRocket();
|
||||||
|
AxialStage stage = rocket.getStage(0);
|
||||||
|
|
||||||
|
NoseCone noseCone = new NoseCone(Transition.Shape.CONICAL, 0.06, 0.01);
|
||||||
|
noseCone.setFlipped(true);
|
||||||
|
BodyTube tube1 = new BodyTube(0.06, 0.02);
|
||||||
|
tube1.setOuterRadiusAutomatic(false);
|
||||||
|
BodyTube tube2 = new BodyTube(0.06, 0.03);
|
||||||
|
tube2.setOuterRadiusAutomatic(false);
|
||||||
|
|
||||||
|
// Test no previous or next component
|
||||||
|
stage.addChild(noseCone);
|
||||||
|
|
||||||
|
assertFalse(noseCone.usesPreviousCompAutomatic());
|
||||||
|
assertFalse(noseCone.usesNextCompAutomatic());
|
||||||
|
assertSame(stage, noseCone.getPreviousComponent());
|
||||||
|
assertNull(noseCone.getPreviousSymmetricComponent());
|
||||||
|
assertNull(noseCone.getNextComponent());
|
||||||
|
assertNull(noseCone.getNextSymmetricComponent());
|
||||||
|
assertFalse(noseCone.isAftRadiusAutomatic());
|
||||||
|
assertFalse(noseCone.isBaseRadiusAutomatic());
|
||||||
|
assertFalse(noseCone.isForeRadiusAutomatic());
|
||||||
|
assertEquals(noseCone.getAftRadius(), noseCone.getAftRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(noseCone.getBaseRadius(), noseCone.getBaseRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(noseCone.getForeRadius(), noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(0, noseCone.getAftRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(0.01, noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||||
|
|
||||||
|
noseCone.setAftRadiusAutomatic(true, true);
|
||||||
|
assertFalse(noseCone.isAftRadiusAutomatic());
|
||||||
|
assertFalse(noseCone.isBaseRadiusAutomatic());
|
||||||
|
noseCone.setForeRadiusAutomatic(true, true);
|
||||||
|
assertFalse(noseCone.isForeRadiusAutomatic());
|
||||||
|
assertFalse(noseCone.isBaseRadiusAutomatic());
|
||||||
|
|
||||||
|
// Test with previous component
|
||||||
|
stage.addChild(tube1, 0);
|
||||||
|
|
||||||
|
assertFalse(noseCone.usesPreviousCompAutomatic());
|
||||||
|
assertFalse(noseCone.usesNextCompAutomatic());
|
||||||
|
assertSame(tube1, noseCone.getPreviousComponent());
|
||||||
|
assertSame(tube1, noseCone.getPreviousSymmetricComponent());
|
||||||
|
assertNull(noseCone.getNextComponent());
|
||||||
|
assertNull(noseCone.getNextSymmetricComponent());
|
||||||
|
assertFalse(noseCone.isAftRadiusAutomatic());
|
||||||
|
assertFalse(noseCone.isBaseRadiusAutomatic());
|
||||||
|
assertFalse(noseCone.isForeRadiusAutomatic());
|
||||||
|
assertEquals(noseCone.getAftRadius(), noseCone.getAftRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(noseCone.getBaseRadius(), noseCone.getBaseRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(noseCone.getForeRadius(), noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(0, noseCone.getAftRadiusNoAutomatic(), EPSILON);
|
||||||
|
|
||||||
|
noseCone.setBaseRadiusAutomatic(true);
|
||||||
|
assertTrue(noseCone.usesPreviousCompAutomatic());
|
||||||
|
assertFalse(noseCone.usesNextCompAutomatic());
|
||||||
|
assertSame(tube1, noseCone.getPreviousComponent());
|
||||||
|
assertSame(tube1, noseCone.getPreviousSymmetricComponent());
|
||||||
|
assertNull(noseCone.getNextComponent());
|
||||||
|
assertNull(noseCone.getNextSymmetricComponent());
|
||||||
|
assertFalse(noseCone.isAftRadiusAutomatic());
|
||||||
|
assertTrue(noseCone.isBaseRadiusAutomatic());
|
||||||
|
assertTrue(noseCone.isForeRadiusAutomatic());
|
||||||
|
assertEquals(tube1.getAftRadius(), noseCone.getForeRadius(), EPSILON);
|
||||||
|
assertEquals(0.01, noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(tube1.getAftRadius(), noseCone.getBaseRadius(), EPSILON);
|
||||||
|
assertEquals(0.01, noseCone.getBaseRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(noseCone.getAftRadius(), noseCone.getAftRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(0, noseCone.getAftRadiusNoAutomatic(), EPSILON);
|
||||||
|
|
||||||
|
noseCone.setForeRadiusAutomatic(false, true);
|
||||||
|
assertEquals(noseCone.getAftRadius(), noseCone.getAftRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(noseCone.getBaseRadius(), noseCone.getBaseRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(noseCone.getForeRadius(), noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(0.01, noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||||
|
|
||||||
|
noseCone.setBaseRadiusAutomatic(true);
|
||||||
|
assertEquals(tube1.getAftRadius(), noseCone.getForeRadius(), EPSILON);
|
||||||
|
assertEquals(0.01, noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(tube1.getAftRadius(), noseCone.getBaseRadius(), EPSILON);
|
||||||
|
assertEquals(0.01, noseCone.getBaseRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(noseCone.getAftRadius(), noseCone.getAftRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(0, noseCone.getAftRadiusNoAutomatic(), EPSILON);
|
||||||
|
|
||||||
|
assertTrue(noseCone.isForeRadiusAutomatic());
|
||||||
|
assertTrue(noseCone.isBaseRadiusAutomatic());
|
||||||
|
assertFalse(noseCone.isAftRadiusAutomatic());
|
||||||
|
|
||||||
|
// Test with next component
|
||||||
|
stage.addChild(tube2);
|
||||||
|
|
||||||
|
assertTrue(noseCone.usesPreviousCompAutomatic());
|
||||||
|
assertFalse(noseCone.usesNextCompAutomatic());
|
||||||
|
assertSame(tube1, noseCone.getPreviousComponent());
|
||||||
|
assertSame(tube1, noseCone.getPreviousSymmetricComponent());
|
||||||
|
assertSame(tube2, noseCone.getNextComponent());
|
||||||
|
assertSame(tube2, noseCone.getNextSymmetricComponent());
|
||||||
|
assertFalse(noseCone.isAftRadiusAutomatic());
|
||||||
|
assertTrue(noseCone.isBaseRadiusAutomatic());
|
||||||
|
assertTrue(noseCone.isForeRadiusAutomatic());
|
||||||
|
assertEquals(tube1.getAftRadius(), noseCone.getForeRadius(), EPSILON);
|
||||||
|
assertEquals(0.01, noseCone.getForeRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(tube1.getForeRadius(), noseCone.getBaseRadius(), EPSILON);
|
||||||
|
assertEquals(0.01, noseCone.getBaseRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(noseCone.getAftRadius(), noseCone.getAftRadiusNoAutomatic(), EPSILON);
|
||||||
|
assertEquals(0, noseCone.getAftRadius(), EPSILON);
|
||||||
|
}
|
||||||
|
}
|
@ -58,6 +58,7 @@ The following file format versions exist:
|
|||||||
Added PhotoStudio settings saving (<photostudio>)
|
Added PhotoStudio settings saving (<photostudio>)
|
||||||
Added override CD parameter (<overridecd>)
|
Added override CD parameter (<overridecd>)
|
||||||
Added stage activeness remembrance (<stage> under <motorconfiguration>)
|
Added stage activeness remembrance (<stage> under <motorconfiguration>)
|
||||||
|
Added <isflipped> parameter for Nose Cones
|
||||||
Separated <overridesubcomponents> into individual parameters for mass, CG, and CD.
|
Separated <overridesubcomponents> into individual parameters for mass, CG, and CD.
|
||||||
Rename <fincount> to <instancecount> (<fincount> remains for backward compatibility)
|
Rename <fincount> to <instancecount> (<fincount> remains for backward compatibility)
|
||||||
Rename <position> to <axialoffset> (<position> remains for backward compatibility)
|
Rename <position> to <axialoffset> (<position> remains for backward compatibility)
|
||||||
|
Binary file not shown.
Binary file not shown.
@ -127,8 +127,8 @@ public class MotorDatabaseLoader extends AsynchronousDatabaseLoader {
|
|||||||
new Pair<String,InputStream>(
|
new Pair<String,InputStream>(
|
||||||
file.getName(),
|
file.getName(),
|
||||||
new BufferedInputStream(new FileInputStream(file))));
|
new BufferedInputStream(new FileInputStream(file))));
|
||||||
} catch (IOException e) {
|
} catch (Exception e) {
|
||||||
log.warn("IOException while reading " + file + ": " + e, e);
|
log.warn("Exception while reading " + file + ": " + e, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,8 +158,8 @@ public class MotorDatabaseLoader extends AsynchronousDatabaseLoader {
|
|||||||
dialog.setVisible(true);
|
dialog.setVisible(true);
|
||||||
}
|
}
|
||||||
f.getV().close();
|
f.getV().close();
|
||||||
} catch (IOException e) {
|
} catch (Exception e) {
|
||||||
log.warn("IOException while loading file " + f.getU() + ": " + e, e);
|
log.warn("Exception while loading file " + f.getU() + ": " + e, e);
|
||||||
try {
|
try {
|
||||||
f.getV().close();
|
f.getV().close();
|
||||||
} catch (IOException e1) {
|
} catch (IOException e1) {
|
||||||
@ -178,7 +178,7 @@ public class MotorDatabaseLoader extends AsynchronousDatabaseLoader {
|
|||||||
FileIterator iterator;
|
FileIterator iterator;
|
||||||
try {
|
try {
|
||||||
iterator = new DirectoryIterator(file, fileFilter, true);
|
iterator = new DirectoryIterator(file, fileFilter, true);
|
||||||
} catch (IOException e) {
|
} catch (Exception e) {
|
||||||
log.warn("Unable to read directory " + file + ": " + e, e);
|
log.warn("Unable to read directory " + file + ": " + e, e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,8 @@ package net.sf.openrocket.gui.configdialog;
|
|||||||
|
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
|
import java.awt.event.ItemEvent;
|
||||||
|
import java.awt.event.ItemListener;
|
||||||
|
|
||||||
import javax.swing.JCheckBox;
|
import javax.swing.JCheckBox;
|
||||||
import javax.swing.JComboBox;
|
import javax.swing.JComboBox;
|
||||||
@ -40,7 +42,7 @@ public class NoseConeConfig extends RocketComponentConfig {
|
|||||||
private JLabel shapeLabel;
|
private JLabel shapeLabel;
|
||||||
private JSpinner shapeSpinner;
|
private JSpinner shapeSpinner;
|
||||||
private JSlider shapeSlider;
|
private JSlider shapeSlider;
|
||||||
private final JCheckBox checkAutoAftRadius;
|
private final JCheckBox checkAutoBaseRadius;
|
||||||
private static final Translator trans = Application.getTranslator();
|
private static final Translator trans = Application.getTranslator();
|
||||||
|
|
||||||
// Prepended to the description from NoseCone.DESCRIPTIONS
|
// Prepended to the description from NoseCone.DESCRIPTIONS
|
||||||
@ -106,21 +108,21 @@ public class NoseConeConfig extends RocketComponentConfig {
|
|||||||
|
|
||||||
panel.add(new JLabel(trans.get("NoseConeCfg.lbl.Basediam")));
|
panel.add(new JLabel(trans.get("NoseConeCfg.lbl.Basediam")));
|
||||||
|
|
||||||
final DoubleModel aftRadiusModel = new DoubleModel(component, "AftRadius", 2.0, UnitGroup.UNITS_LENGTH, 0); // Diameter = 2*Radius
|
final DoubleModel baseRadius = new DoubleModel(component, "BaseRadius", 2.0, UnitGroup.UNITS_LENGTH, 0); // Diameter = 2*Radius
|
||||||
final JSpinner radiusSpinner = new JSpinner(aftRadiusModel.getSpinnerModel());
|
final JSpinner radiusSpinner = new JSpinner(baseRadius.getSpinnerModel());
|
||||||
radiusSpinner.setEditor(new SpinnerEditor(radiusSpinner));
|
radiusSpinner.setEditor(new SpinnerEditor(radiusSpinner));
|
||||||
panel.add(radiusSpinner, "growx");
|
panel.add(radiusSpinner, "growx");
|
||||||
order.add(((SpinnerEditor) radiusSpinner.getEditor()).getTextField());
|
order.add(((SpinnerEditor) radiusSpinner.getEditor()).getTextField());
|
||||||
|
|
||||||
panel.add(new UnitSelector(aftRadiusModel), "growx");
|
panel.add(new UnitSelector(baseRadius), "growx");
|
||||||
panel.add(new BasicSlider(aftRadiusModel.getSliderModel(0, 0.04, 0.2)), "w 100lp, wrap 0px");
|
panel.add(new BasicSlider(baseRadius.getSliderModel(0, 0.04, 0.2)), "w 100lp, wrap 0px");
|
||||||
|
|
||||||
checkAutoAftRadius = new JCheckBox(aftRadiusModel.getAutomaticAction());
|
checkAutoBaseRadius = new JCheckBox(baseRadius.getAutomaticAction());
|
||||||
//// Automatic
|
//// Automatic
|
||||||
checkAutoAftRadius.setText(trans.get("NoseConeCfg.checkbox.Automatic"));
|
checkAutoBaseRadius.setText(trans.get("NoseConeCfg.checkbox.Automatic"));
|
||||||
panel.add(checkAutoAftRadius, "skip, span 2, wrap");
|
panel.add(checkAutoBaseRadius, "skip, span 2, wrap");
|
||||||
order.add(checkAutoAftRadius);
|
order.add(checkAutoBaseRadius);
|
||||||
updateCheckboxAutoAftRadius();
|
updateCheckboxAutoBaseRadius(((NoseCone) component).isFlipped());
|
||||||
}
|
}
|
||||||
|
|
||||||
{//// Wall thickness:
|
{//// Wall thickness:
|
||||||
@ -142,10 +144,24 @@ public class NoseConeConfig extends RocketComponentConfig {
|
|||||||
//// Filled
|
//// Filled
|
||||||
filledCheckbox.setText(trans.get("NoseConeCfg.checkbox.Filled"));
|
filledCheckbox.setText(trans.get("NoseConeCfg.checkbox.Filled"));
|
||||||
filledCheckbox.setToolTipText(trans.get("NoseConeCfg.checkbox.Filled.ttip"));
|
filledCheckbox.setToolTipText(trans.get("NoseConeCfg.checkbox.Filled.ttip"));
|
||||||
panel.add(filledCheckbox, "skip, span 2, wrap");
|
panel.add(filledCheckbox, "skip, span 2, wrap para");
|
||||||
order.add(filledCheckbox);
|
order.add(filledCheckbox);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{//// Flip to tail cone:
|
||||||
|
final JCheckBox flipCheckbox = new JCheckBox(new BooleanModel(component, "Flipped"));
|
||||||
|
flipCheckbox.setText(trans.get("NoseConeCfg.checkbox.Flip"));
|
||||||
|
flipCheckbox.setToolTipText(trans.get("NoseConeCfg.checkbox.Flip.ttip"));
|
||||||
|
panel.add(flipCheckbox, "spanx, wrap");
|
||||||
|
order.add(flipCheckbox);
|
||||||
|
flipCheckbox.addItemListener(new ItemListener() {
|
||||||
|
@Override
|
||||||
|
public void itemStateChanged(ItemEvent e) {
|
||||||
|
updateCheckboxAutoBaseRadius(e.getStateChange() == ItemEvent.SELECTED);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
panel.add(new JLabel(""), "growy");
|
panel.add(new JLabel(""), "growy");
|
||||||
|
|
||||||
//// Description
|
//// Description
|
||||||
@ -189,25 +205,29 @@ public class NoseConeConfig extends RocketComponentConfig {
|
|||||||
* Sets the checkAutoAftRadius checkbox's enabled state and tooltip text, based on the state of its next component.
|
* Sets the checkAutoAftRadius checkbox's enabled state and tooltip text, based on the state of its next component.
|
||||||
* If there is no next symmetric component or if that component already has its auto checkbox checked, the
|
* If there is no next symmetric component or if that component already has its auto checkbox checked, the
|
||||||
* checkAutoAftRadius checkbox is disabled.
|
* checkAutoAftRadius checkbox is disabled.
|
||||||
|
*
|
||||||
|
* @param isFlipped whether the nose cone is flipped
|
||||||
*/
|
*/
|
||||||
private void updateCheckboxAutoAftRadius() {
|
private void updateCheckboxAutoBaseRadius(boolean isFlipped) {
|
||||||
if (component == null || checkAutoAftRadius == null) return;
|
if (component == null || checkAutoBaseRadius == null) return;
|
||||||
|
|
||||||
// Disable check button if there is no component to get the diameter from
|
// Disable check button if there is no component to get the diameter from
|
||||||
SymmetricComponent nextComp = ((NoseCone) component).getNextSymmetricComponent();
|
NoseCone noseCone = ((NoseCone) component);
|
||||||
if (nextComp == null) {
|
SymmetricComponent referenceComp = isFlipped ? noseCone.getPreviousSymmetricComponent() : noseCone.getNextSymmetricComponent();
|
||||||
checkAutoAftRadius.setEnabled(false);
|
if (referenceComp == null) {
|
||||||
((NoseCone) component).setAftRadiusAutomatic(false);
|
checkAutoBaseRadius.setEnabled(false);
|
||||||
checkAutoAftRadius.setToolTipText(trans.get("NoseConeCfg.checkbox.ttip.Automatic_noReferenceComponent"));
|
((NoseCone) component).setBaseRadiusAutomatic(false);
|
||||||
|
checkAutoBaseRadius.setToolTipText(trans.get("NoseConeCfg.checkbox.ttip.Automatic_noReferenceComponent"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!nextComp.usesPreviousCompAutomatic()) {
|
if ((!isFlipped&& !referenceComp.usesPreviousCompAutomatic()) ||
|
||||||
checkAutoAftRadius.setEnabled(true);
|
isFlipped && !referenceComp.usesNextCompAutomatic()) {
|
||||||
checkAutoAftRadius.setToolTipText(trans.get("NoseConeCfg.checkbox.ttip.Automatic"));
|
checkAutoBaseRadius.setEnabled(true);
|
||||||
|
checkAutoBaseRadius.setToolTipText(trans.get("NoseConeCfg.checkbox.ttip.Automatic"));
|
||||||
} else {
|
} else {
|
||||||
checkAutoAftRadius.setEnabled(false);
|
checkAutoBaseRadius.setEnabled(false);
|
||||||
((NoseCone) component).setAftRadiusAutomatic(false);
|
((NoseCone) component).setBaseRadiusAutomatic(false);
|
||||||
checkAutoAftRadius.setToolTipText(trans.get("NoseConeCfg.checkbox.ttip.Automatic_alreadyAuto"));
|
checkAutoBaseRadius.setToolTipText(trans.get("NoseConeCfg.checkbox.ttip.Automatic_alreadyAuto"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -613,17 +613,26 @@ public class RocketComponentConfig extends JPanel {
|
|||||||
|
|
||||||
protected JPanel shoulderTab() {
|
protected JPanel shoulderTab() {
|
||||||
JPanel panel = new JPanel(new MigLayout("fill"));
|
JPanel panel = new JPanel(new MigLayout("fill"));
|
||||||
JPanel sub;
|
|
||||||
DoubleModel m, m2;
|
|
||||||
DoubleModel m0 = new DoubleModel(0);
|
DoubleModel m0 = new DoubleModel(0);
|
||||||
BooleanModel bm;
|
|
||||||
JCheckBox check;
|
|
||||||
JSpinner spin;
|
|
||||||
|
|
||||||
|
|
||||||
//// Fore shoulder, not for NoseCone
|
//// Fore shoulder, not for NoseCone
|
||||||
|
|
||||||
if (!(component instanceof NoseCone)) {
|
if (!(component instanceof NoseCone)) {
|
||||||
|
addForeShoulderSection(panel, m0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//// Aft shoulder
|
||||||
|
addAftShoulderSection(panel, m0);
|
||||||
|
|
||||||
|
return panel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addForeShoulderSection(JPanel panel, DoubleModel m0) {
|
||||||
|
DoubleModel m;
|
||||||
|
JCheckBox check;
|
||||||
|
JPanel sub;
|
||||||
|
DoubleModel m2;
|
||||||
|
JSpinner spin;
|
||||||
|
BooleanModel bm;
|
||||||
sub = new JPanel(new MigLayout("gap rel unrel", "[][65lp::][30lp::]", ""));
|
sub = new JPanel(new MigLayout("gap rel unrel", "[][65lp::][30lp::]", ""));
|
||||||
|
|
||||||
//// Fore shoulder
|
//// Fore shoulder
|
||||||
@ -684,28 +693,39 @@ public class RocketComponentConfig extends JPanel {
|
|||||||
sub.add(check, "spanx");
|
sub.add(check, "spanx");
|
||||||
order.add(check);
|
order.add(check);
|
||||||
|
|
||||||
|
|
||||||
panel.add(sub);
|
panel.add(sub);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addAftShoulderSection(JPanel panel, DoubleModel m0) {
|
||||||
//// Aft shoulder
|
JSpinner spin;
|
||||||
|
JCheckBox check;
|
||||||
|
DoubleModel m;
|
||||||
|
DoubleModel m2;
|
||||||
|
JPanel sub;
|
||||||
|
BooleanModel bm;
|
||||||
sub = new JPanel(new MigLayout("gap rel unrel", "[][65lp::][30lp::]", ""));
|
sub = new JPanel(new MigLayout("gap rel unrel", "[][65lp::][30lp::]", ""));
|
||||||
|
|
||||||
if (component instanceof NoseCone)
|
String valueNameShoulder = "AftShoulder";
|
||||||
|
String valueNameRadius = "AftRadius";
|
||||||
|
|
||||||
|
if (component instanceof NoseCone) {
|
||||||
|
// Nose cones have a special shoulder method to cope with flipped nose cones
|
||||||
|
valueNameShoulder = "Shoulder";
|
||||||
|
valueNameRadius = "BaseRadius";
|
||||||
//// Nose cone shoulder
|
//// Nose cone shoulder
|
||||||
sub.setBorder(BorderFactory.createTitledBorder(trans.get("RocketCompCfg.title.Noseconeshoulder")));
|
sub.setBorder(BorderFactory.createTitledBorder(trans.get("RocketCompCfg.title.Noseconeshoulder")));
|
||||||
else
|
} else {
|
||||||
//// Aft shoulder
|
//// Aft shoulder
|
||||||
sub.setBorder(BorderFactory.createTitledBorder(trans.get("RocketCompCfg.title.Aftshoulder")));
|
sub.setBorder(BorderFactory.createTitledBorder(trans.get("RocketCompCfg.title.Aftshoulder")));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//// Radius
|
//// Radius
|
||||||
//// Diameter:
|
//// Diameter:
|
||||||
sub.add(new JLabel(trans.get("RocketCompCfg.lbl.Diameter")));
|
sub.add(new JLabel(trans.get("RocketCompCfg.lbl.Diameter")));
|
||||||
|
|
||||||
m = new DoubleModel(component, "AftShoulderRadius", 2, UnitGroup.UNITS_LENGTH, 0);
|
m = new DoubleModel(component, valueNameShoulder+"Radius", 2, UnitGroup.UNITS_LENGTH, 0);
|
||||||
m2 = new DoubleModel(component, "AftRadius", 2, UnitGroup.UNITS_LENGTH);
|
m2 = new DoubleModel(component, valueNameRadius, 2, UnitGroup.UNITS_LENGTH);
|
||||||
|
|
||||||
spin = new JSpinner(m.getSpinnerModel());
|
spin = new JSpinner(m.getSpinnerModel());
|
||||||
spin.setEditor(new SpinnerEditor(spin));
|
spin.setEditor(new SpinnerEditor(spin));
|
||||||
@ -719,7 +739,7 @@ public class RocketComponentConfig extends JPanel {
|
|||||||
//// Length:
|
//// Length:
|
||||||
sub.add(new JLabel(trans.get("RocketCompCfg.lbl.Length")));
|
sub.add(new JLabel(trans.get("RocketCompCfg.lbl.Length")));
|
||||||
|
|
||||||
m = new DoubleModel(component, "AftShoulderLength", UnitGroup.UNITS_LENGTH, 0);
|
m = new DoubleModel(component, valueNameShoulder+"Length", UnitGroup.UNITS_LENGTH, 0);
|
||||||
|
|
||||||
spin = new JSpinner(m.getSpinnerModel());
|
spin = new JSpinner(m.getSpinnerModel());
|
||||||
spin.setEditor(new SpinnerEditor(spin));
|
spin.setEditor(new SpinnerEditor(spin));
|
||||||
@ -733,8 +753,8 @@ public class RocketComponentConfig extends JPanel {
|
|||||||
//// Thickness:
|
//// Thickness:
|
||||||
sub.add(new JLabel(trans.get("RocketCompCfg.lbl.Thickness")));
|
sub.add(new JLabel(trans.get("RocketCompCfg.lbl.Thickness")));
|
||||||
|
|
||||||
m = new DoubleModel(component, "AftShoulderThickness", UnitGroup.UNITS_LENGTH, 0);
|
m = new DoubleModel(component, valueNameShoulder+"Thickness", UnitGroup.UNITS_LENGTH, 0);
|
||||||
m2 = new DoubleModel(component, "AftShoulderRadius", UnitGroup.UNITS_LENGTH);
|
m2 = new DoubleModel(component, valueNameShoulder+"Radius", UnitGroup.UNITS_LENGTH);
|
||||||
|
|
||||||
spin = new JSpinner(m.getSpinnerModel());
|
spin = new JSpinner(m.getSpinnerModel());
|
||||||
spin.setEditor(new SpinnerEditor(spin));
|
spin.setEditor(new SpinnerEditor(spin));
|
||||||
@ -746,7 +766,7 @@ public class RocketComponentConfig extends JPanel {
|
|||||||
|
|
||||||
|
|
||||||
//// Capped
|
//// Capped
|
||||||
bm = new BooleanModel(component, "AftShoulderCapped");
|
bm = new BooleanModel(component, valueNameShoulder+"Capped");
|
||||||
check = new JCheckBox(bm);
|
check = new JCheckBox(bm);
|
||||||
//// End capped
|
//// End capped
|
||||||
check.setText(trans.get("RocketCompCfg.checkbox.Endcapped"));
|
check.setText(trans.get("RocketCompCfg.checkbox.Endcapped"));
|
||||||
@ -754,16 +774,9 @@ public class RocketComponentConfig extends JPanel {
|
|||||||
sub.add(check, "spanx");
|
sub.add(check, "spanx");
|
||||||
order.add(check);
|
order.add(check);
|
||||||
|
|
||||||
|
|
||||||
panel.add(sub);
|
panel.add(sub);
|
||||||
|
|
||||||
|
|
||||||
return panel;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Private inner class to handle events in componentNameField.
|
* Private inner class to handle events in componentNameField.
|
||||||
*/
|
*/
|
||||||
|
@ -228,18 +228,16 @@ public class TransitionConfig extends RocketComponentConfig {
|
|||||||
private void updateCheckboxAutoAftRadius() {
|
private void updateCheckboxAutoAftRadius() {
|
||||||
if (component == null || checkAutoAftRadius == null) return;
|
if (component == null || checkAutoAftRadius == null) return;
|
||||||
|
|
||||||
// Disable check button if there is no component to get the diameter from
|
Transition transition = (Transition) component;
|
||||||
SymmetricComponent nextComp = ((Transition) component).getNextSymmetricComponent();
|
boolean enabled = transition.canUseNextCompAutomatic();
|
||||||
if (nextComp == null) {
|
if (enabled) { // Can use auto radius
|
||||||
|
checkAutoAftRadius.setEnabled(true);
|
||||||
|
checkAutoAftRadius.setToolTipText(trans.get("TransitionCfg.checkbox.ttip.Automatic"));
|
||||||
|
} else if (transition.getNextSymmetricComponent() == null) { // No next component to take the auto radius from
|
||||||
checkAutoAftRadius.setEnabled(false);
|
checkAutoAftRadius.setEnabled(false);
|
||||||
((Transition) component).setAftRadiusAutomatic(false);
|
((Transition) component).setAftRadiusAutomatic(false);
|
||||||
checkAutoAftRadius.setToolTipText(trans.get("TransitionCfg.checkbox.ttip.Automatic_noReferenceComponent"));
|
checkAutoAftRadius.setToolTipText(trans.get("TransitionCfg.checkbox.ttip.Automatic_noReferenceComponent"));
|
||||||
return;
|
} else { // Next component already has its auto radius checked
|
||||||
}
|
|
||||||
if (!nextComp.usesPreviousCompAutomatic()) {
|
|
||||||
checkAutoAftRadius.setEnabled(true);
|
|
||||||
checkAutoAftRadius.setToolTipText(trans.get("TransitionCfg.checkbox.ttip.Automatic"));
|
|
||||||
} else {
|
|
||||||
checkAutoAftRadius.setEnabled(false);
|
checkAutoAftRadius.setEnabled(false);
|
||||||
((Transition) component).setAftRadiusAutomatic(false);
|
((Transition) component).setAftRadiusAutomatic(false);
|
||||||
checkAutoAftRadius.setToolTipText(trans.get("TransitionCfg.checkbox.ttip.Automatic_alreadyAuto"));
|
checkAutoAftRadius.setToolTipText(trans.get("TransitionCfg.checkbox.ttip.Automatic_alreadyAuto"));
|
||||||
@ -254,18 +252,16 @@ public class TransitionConfig extends RocketComponentConfig {
|
|||||||
private void updateCheckboxAutoForeRadius() {
|
private void updateCheckboxAutoForeRadius() {
|
||||||
if (component == null || checkAutoForeRadius == null) return;
|
if (component == null || checkAutoForeRadius == null) return;
|
||||||
|
|
||||||
// Disable check button if there is no component to get the diameter from
|
Transition transition = (Transition) component;
|
||||||
SymmetricComponent prevComp = ((Transition) component).getPreviousSymmetricComponent();
|
boolean enabled = transition.canUsePreviousCompAutomatic();
|
||||||
if (prevComp == null) {
|
if (enabled) { // Can use auto radius
|
||||||
|
checkAutoForeRadius.setEnabled(true);
|
||||||
|
checkAutoForeRadius.setToolTipText(trans.get("TransitionCfg.checkbox.ttip.Automatic"));
|
||||||
|
} else if (transition.getPreviousSymmetricComponent() == null) { // No next component to take the auto radius from
|
||||||
checkAutoForeRadius.setEnabled(false);
|
checkAutoForeRadius.setEnabled(false);
|
||||||
((Transition) component).setForeRadiusAutomatic(false);
|
((Transition) component).setForeRadiusAutomatic(false);
|
||||||
checkAutoForeRadius.setToolTipText(trans.get("TransitionCfg.checkbox.ttip.Automatic_noReferenceComponent"));
|
checkAutoForeRadius.setToolTipText(trans.get("TransitionCfg.checkbox.ttip.Automatic_noReferenceComponent"));
|
||||||
return;
|
} else { // Next component already has its auto radius checked
|
||||||
}
|
|
||||||
if (!prevComp.usesNextCompAutomatic()) {
|
|
||||||
checkAutoForeRadius.setEnabled(true);
|
|
||||||
checkAutoForeRadius.setToolTipText(trans.get("TransitionCfg.checkbox.ttip.Automatic"));
|
|
||||||
} else {
|
|
||||||
checkAutoForeRadius.setEnabled(false);
|
checkAutoForeRadius.setEnabled(false);
|
||||||
((Transition) component).setForeRadiusAutomatic(false);
|
((Transition) component).setForeRadiusAutomatic(false);
|
||||||
checkAutoForeRadius.setToolTipText(trans.get("TransitionCfg.checkbox.ttip.Automatic_alreadyAuto"));
|
checkAutoForeRadius.setToolTipText(trans.get("TransitionCfg.checkbox.ttip.Automatic_alreadyAuto"));
|
||||||
|
@ -27,6 +27,7 @@ import net.miginfocom.swing.MigLayout;
|
|||||||
import net.sf.openrocket.gui.components.StyledLabel;
|
import net.sf.openrocket.gui.components.StyledLabel;
|
||||||
import net.sf.openrocket.gui.components.URLLabel;
|
import net.sf.openrocket.gui.components.URLLabel;
|
||||||
import net.sf.openrocket.gui.util.GUIUtil;
|
import net.sf.openrocket.gui.util.GUIUtil;
|
||||||
|
import net.sf.openrocket.gui.util.SwingPreferences;
|
||||||
import net.sf.openrocket.l10n.Translator;
|
import net.sf.openrocket.l10n.Translator;
|
||||||
import net.sf.openrocket.logging.LogLevelBufferLogger;
|
import net.sf.openrocket.logging.LogLevelBufferLogger;
|
||||||
import net.sf.openrocket.logging.LogLine;
|
import net.sf.openrocket.logging.LogLine;
|
||||||
@ -44,6 +45,7 @@ public class BugReportDialog extends JDialog {
|
|||||||
private static final String REPORT_EMAIL_URL = "mailto:" + REPORT_EMAIL;
|
private static final String REPORT_EMAIL_URL = "mailto:" + REPORT_EMAIL;
|
||||||
|
|
||||||
private static final Translator trans = Application.getTranslator();
|
private static final Translator trans = Application.getTranslator();
|
||||||
|
private static final SwingPreferences preferences = (SwingPreferences) Application.getPreferences();
|
||||||
|
|
||||||
|
|
||||||
public BugReportDialog(Window parent, String labelText, final String message, final boolean sendIfUnchanged) {
|
public BugReportDialog(Window parent, String labelText, final String message, final boolean sendIfUnchanged) {
|
||||||
@ -108,31 +110,10 @@ public class BugReportDialog extends JDialog {
|
|||||||
* @param parent the parent window (may be null).
|
* @param parent the parent window (may be null).
|
||||||
*/
|
*/
|
||||||
public static void showBugReportDialog(Window parent) {
|
public static void showBugReportDialog(Window parent) {
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
sb.append("<html>---------- Bug report ----------\n");
|
// ---------- Bug report ----------
|
||||||
sb.append('\n');
|
addBugReportInformation(sb);
|
||||||
sb.append("<b>Include detailed steps on how to trigger the bug:</b>\n");
|
|
||||||
sb.append("<i>(You can edit text directly in this window)</i>\n");
|
|
||||||
sb.append('\n');
|
|
||||||
sb.append("1. \n");
|
|
||||||
sb.append("2. \n");
|
|
||||||
sb.append("3. \n");
|
|
||||||
sb.append('\n');
|
|
||||||
|
|
||||||
sb.append("<b>What does the software do and what in your opinion should it do in the " +
|
|
||||||
"case described above:</b>\n");
|
|
||||||
sb.append('\n');
|
|
||||||
sb.append('\n');
|
|
||||||
sb.append('\n');
|
|
||||||
|
|
||||||
sb.append("Include your email address (optional; it helps if we can " +
|
|
||||||
"contact you in case we need additional information):\n");
|
|
||||||
sb.append('\n');
|
|
||||||
sb.append('\n');
|
|
||||||
sb.append('\n');
|
|
||||||
|
|
||||||
|
|
||||||
sb.append("(Do not modify anything below this line.)\n");
|
sb.append("(Do not modify anything below this line.)\n");
|
||||||
sb.append("---------- System information ----------\n");
|
sb.append("---------- System information ----------\n");
|
||||||
@ -158,27 +139,8 @@ public class BugReportDialog extends JDialog {
|
|||||||
public static void showExceptionDialog(Window parent, Thread t, Throwable e) {
|
public static void showExceptionDialog(Window parent, Thread t, Throwable e) {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
sb.append("<html>---------- Bug report ----------\n");
|
// ---------- Bug report ----------
|
||||||
sb.append('\n');
|
addBugReportInformation(sb);
|
||||||
sb.append("<b style='color:rgb(210, 20, 5)'>Please include a description about what actions you were " +
|
|
||||||
"performing when the exception occurred:</b>\n");
|
|
||||||
sb.append("<i>(You can edit text directly in this window)</i>\n");
|
|
||||||
sb.append('\n');
|
|
||||||
sb.append("1. \n");
|
|
||||||
sb.append("2. \n");
|
|
||||||
sb.append("3. \n");
|
|
||||||
|
|
||||||
sb.append("\n");
|
|
||||||
sb.append("<b>If possible, please send us the .ork file that caused the bug.</b>\n");
|
|
||||||
sb.append('\n');
|
|
||||||
|
|
||||||
|
|
||||||
sb.append("Include your email address (optional; it helps if we can " +
|
|
||||||
"contact you in case we need additional information):\n");
|
|
||||||
sb.append('\n');
|
|
||||||
sb.append('\n');
|
|
||||||
sb.append('\n');
|
|
||||||
sb.append('\n');
|
|
||||||
|
|
||||||
sb.append("(Do not modify anything below this line.)\n");
|
sb.append("(Do not modify anything below this line.)\n");
|
||||||
sb.append("---------- Exception stack trace ----------\n");
|
sb.append("---------- Exception stack trace ----------\n");
|
||||||
@ -212,11 +174,36 @@ public class BugReportDialog extends JDialog {
|
|||||||
reportDialog.setVisible(true);
|
reportDialog.setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void addBugReportInformation(StringBuilder sb) {
|
||||||
|
sb.append("<html>---------- Bug report ----------\n");
|
||||||
|
sb.append('\n');
|
||||||
|
sb.append("<b style='color:rgb(210, 20, 5)'>Please include a description about what actions you were " +
|
||||||
|
"performing when the exception occurred:</b>\n");
|
||||||
|
sb.append("<i>(You can edit text directly in this window)</i>\n");
|
||||||
|
sb.append('\n');
|
||||||
|
sb.append("1. \n");
|
||||||
|
sb.append("2. \n");
|
||||||
|
sb.append("3. \n");
|
||||||
|
|
||||||
|
sb.append("\n");
|
||||||
|
sb.append("<b>If possible, please send us the .ork file that caused the bug.</b>\n");
|
||||||
|
sb.append('\n');
|
||||||
|
|
||||||
|
|
||||||
|
sb.append("Include your email address (optional; it helps if we can " +
|
||||||
|
"contact you in case we need additional information):\n");
|
||||||
|
sb.append('\n');
|
||||||
|
sb.append('\n');
|
||||||
|
sb.append('\n');
|
||||||
|
sb.append('\n');
|
||||||
|
}
|
||||||
|
|
||||||
private static void addSystemInformation(StringBuilder sb) {
|
private static void addSystemInformation(StringBuilder sb) {
|
||||||
StringBuilder sbTemp = new StringBuilder();
|
StringBuilder sbTemp = new StringBuilder();
|
||||||
sbTemp.append("OpenRocket version: " + BuildProperties.getVersion() + "\n");
|
sbTemp.append("OpenRocket version: " + BuildProperties.getVersion() + "\n");
|
||||||
sbTemp.append("OpenRocket source: " + BuildProperties.getBuildSource() + "\n");
|
sbTemp.append("OpenRocket source: " + BuildProperties.getBuildSource() + "\n");
|
||||||
sbTemp.append("OpenRocket location: " + JarUtil.getCurrentJarFile() + "\n");
|
sbTemp.append("OpenRocket location: " + JarUtil.getCurrentJarFile() + "\n");
|
||||||
|
sbTemp.append("User-defined thrust curves location: " + preferences.getUserThrustCurveFilesAsString() + "\n");
|
||||||
sbTemp.append("JOGL version: " + JoglVersion.getInstance().getImplementationVersion() + "\n");
|
sbTemp.append("JOGL version: " + JoglVersion.getInstance().getImplementationVersion() + "\n");
|
||||||
sbTemp.append("Current default locale: " + Locale.getDefault() + "\n");
|
sbTemp.append("Current default locale: " + Locale.getDefault() + "\n");
|
||||||
sbTemp.append("System properties:\n");
|
sbTemp.append("System properties:\n");
|
||||||
|
@ -83,7 +83,7 @@ public class ScaleDialog extends JDialog {
|
|||||||
// SymmetricComponent
|
// SymmetricComponent
|
||||||
addScaler(SymmetricComponent.class, "Thickness", "isFilled", SCALERS_NO_OFFSET);
|
addScaler(SymmetricComponent.class, "Thickness", "isFilled", SCALERS_NO_OFFSET);
|
||||||
|
|
||||||
// Transition + Nose cone
|
// Transition
|
||||||
addScaler(Transition.class, "ForeRadius", "isForeRadiusAutomatic", SCALERS_NO_OFFSET);
|
addScaler(Transition.class, "ForeRadius", "isForeRadiusAutomatic", SCALERS_NO_OFFSET);
|
||||||
addScaler(Transition.class, "AftRadius", "isAftRadiusAutomatic", SCALERS_NO_OFFSET);
|
addScaler(Transition.class, "AftRadius", "isAftRadiusAutomatic", SCALERS_NO_OFFSET);
|
||||||
addScaler(Transition.class, "ForeShoulderRadius", SCALERS_NO_OFFSET);
|
addScaler(Transition.class, "ForeShoulderRadius", SCALERS_NO_OFFSET);
|
||||||
@ -93,6 +93,12 @@ public class ScaleDialog extends JDialog {
|
|||||||
addScaler(Transition.class, "AftShoulderThickness", SCALERS_NO_OFFSET);
|
addScaler(Transition.class, "AftShoulderThickness", SCALERS_NO_OFFSET);
|
||||||
addScaler(Transition.class, "AftShoulderLength", SCALERS_NO_OFFSET);
|
addScaler(Transition.class, "AftShoulderLength", SCALERS_NO_OFFSET);
|
||||||
|
|
||||||
|
// Nose cone
|
||||||
|
addScaler(NoseCone.class, "BaseRadius", "isBaseRadiusAutomatic", SCALERS_NO_OFFSET);
|
||||||
|
addScaler(NoseCone.class, "ShoulderRadius", SCALERS_NO_OFFSET);
|
||||||
|
addScaler(NoseCone.class, "ShoulderThickness", SCALERS_NO_OFFSET);
|
||||||
|
addScaler(NoseCone.class, "ShoulderLength", SCALERS_NO_OFFSET);
|
||||||
|
|
||||||
// Body tube
|
// Body tube
|
||||||
addScaler(BodyTube.class, "OuterRadius", "isOuterRadiusAutomatic", SCALERS_NO_OFFSET);
|
addScaler(BodyTube.class, "OuterRadius", "isOuterRadiusAutomatic", SCALERS_NO_OFFSET);
|
||||||
addScaler(BodyTube.class, "MotorOverhang", SCALERS_NO_OFFSET);
|
addScaler(BodyTube.class, "MotorOverhang", SCALERS_NO_OFFSET);
|
||||||
@ -559,6 +565,10 @@ public class ScaleDialog extends JDialog {
|
|||||||
}
|
}
|
||||||
Collections.reverse(classes); // Always do the super component scales first (can cause problems otherwise in the scale order)
|
Collections.reverse(classes); // Always do the super component scales first (can cause problems otherwise in the scale order)
|
||||||
for (Class<?> cl : classes) {
|
for (Class<?> cl : classes) {
|
||||||
|
// Don't use the super-class methods of transitions for nose cones
|
||||||
|
if (cl == Transition.class && component instanceof NoseCone) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
List<Scaler> list = SCALERS_NO_OFFSET.get(cl);
|
List<Scaler> list = SCALERS_NO_OFFSET.get(cl);
|
||||||
if (list != null && list.size() > 0) {
|
if (list != null && list.size() > 0) {
|
||||||
for (Scaler s : list) {
|
for (Scaler s : list) {
|
||||||
|
@ -86,14 +86,7 @@ public class GeneralPreferencesPanel extends PreferencesPanel {
|
|||||||
//// User-defined thrust curves:
|
//// User-defined thrust curves:
|
||||||
this.add(new JLabel(trans.get("pref.dlg.lbl.User-definedthrust")), "spanx, wrap");
|
this.add(new JLabel(trans.get("pref.dlg.lbl.User-definedthrust")), "spanx, wrap");
|
||||||
final JTextField field = new JTextField();
|
final JTextField field = new JTextField();
|
||||||
List<File> files = preferences.getUserThrustCurveFiles();
|
String str = preferences.getUserThrustCurveFilesAsString();
|
||||||
String str = "";
|
|
||||||
for (File file : files) {
|
|
||||||
if (str.length() > 0) {
|
|
||||||
str += ";";
|
|
||||||
}
|
|
||||||
str += file.getAbsolutePath();
|
|
||||||
}
|
|
||||||
field.setText(str);
|
field.setText(str);
|
||||||
field.getDocument().addDocumentListener(new DocumentListener() {
|
field.getDocument().addDocumentListener(new DocumentListener() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package net.sf.openrocket.gui.main.componenttree;
|
package net.sf.openrocket.gui.main.componenttree;
|
||||||
|
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
|
import java.awt.Dimension;
|
||||||
import java.awt.FlowLayout;
|
import java.awt.FlowLayout;
|
||||||
|
import java.awt.Font;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
@ -80,6 +82,8 @@ public class ComponentTreeRenderer extends DefaultTreeCellRenderer {
|
|||||||
p.setToolTipText(getToolTipSingleComponent(c));
|
p.setToolTipText(getToolTipSingleComponent(c));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Font originalFont = tree.getFont();
|
||||||
|
p.setFont(originalFont);
|
||||||
comp = p;
|
comp = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,6 +305,24 @@ public class SwingPreferences extends net.sf.openrocket.startup.Preferences {
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the files/directories to be loaded as custom thrust curves, formatting as a string. If there are multiple
|
||||||
|
* locations, they are separated by a semicolon.
|
||||||
|
*
|
||||||
|
* @return a list of files to load as thrust curves, formatted as a semicolon separated string.
|
||||||
|
*/
|
||||||
|
public String getUserThrustCurveFilesAsString() {
|
||||||
|
List<File> files = getUserThrustCurveFiles();
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (File file : files) {
|
||||||
|
if (sb.length() > 0) {
|
||||||
|
sb.append(";");
|
||||||
|
}
|
||||||
|
sb.append(file.getAbsolutePath());
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
public File getDefaultUserThrustCurveFile() {
|
public File getDefaultUserThrustCurveFile() {
|
||||||
File appdir = SystemInfo.getUserApplicationDirectory();
|
File appdir = SystemInfo.getUserApplicationDirectory();
|
||||||
File tcdir = new File(appdir, "ThrustCurves");
|
File tcdir = new File(appdir, "ThrustCurves");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user