+
+OpenRocket 23.xx
+------------------------
+
+Here, the release notes for the next release will be documented.
+
+
+
OpenRocket 22.02 (2023-02-08)
diff --git a/core/build.xml b/core/build.xml
index ffa0250b8..0b2306bed 100644
--- a/core/build.xml
+++ b/core/build.xml
@@ -59,7 +59,7 @@
Java/JVM detail version: ${java.version}
Compiling main classes
-
+
diff --git a/core/resources-src/pix/splashscreen.txt b/core/resources-src/pix/splashscreen.txt
index cb22901ce..7c9fa3cdd 100644
--- a/core/resources-src/pix/splashscreen.txt
+++ b/core/resources-src/pix/splashscreen.txt
@@ -4,6 +4,7 @@ OpenRocket text:
Create logo using Gimp's "Blended" logo script.
Apply suitable gradient to text layer
(softened "Horizon 1" -> "Horizon 1 soft").
+Font: Kanit (Italic): https://fonts.google.com/specimen/Kanit?query=kanit
Background starfield:
diff --git a/core/resources/build.properties b/core/resources/build.properties
index d2cc23036..121feabaa 100644
--- a/core/resources/build.properties
+++ b/core/resources/build.properties
@@ -1,6 +1,6 @@
# The OpenRocket build version
-build.version=22.02
+build.version=23.xx
# The copyright year for the build. Displayed in the about dialog.
# Will show as Copyright 2013-${build.copyright}
diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties
index 2e3bbdc1c..d2ea4caed 100644
--- a/core/resources/l10n/messages.properties
+++ b/core/resources/l10n/messages.properties
@@ -297,6 +297,7 @@ pref.dlg.tab.Launch = Launch
pref.dlg.tab.Miscellaneousoptions = Miscellaneous options
pref.dlg.lbl.RASAeroWarning = Show warning when saving in RASAero format
pref.dlg.lbl.RockSimWarning = Show warning when saving in RockSim format
+pref.dlg.checkbox.ShowDiscardPreferencesConfirmation = Show confirmation dialog when discarding preferences
pref.dlg.but.resetAllPreferences = Reset all preferences
pref.dlg.but.resetAllPreferences.ttip = Reset all the preferences, including cached preferences (UI settings, recent files, etc.)
pref.dlg.but.exportPreferences = Export preferences
@@ -366,6 +367,10 @@ pref.dlg.lbl.Temperature = Temperature:
pref.dlg.lbl.Momentofinertia = Moment of inertia:
pref.dlg.lbl.Pressure = Pressure:
pref.dlg.lbl.Stability = Stability:
+pref.dlg.lbl.SecondaryStability = Secondary Stability:
+pref.dlg.lbl.SecondaryStability.ttip = Select the stability unit that will be displayed alongside the main stability unit in the design view.
+pref.dlg.checkbox.DisplaySecondaryStability = Display secondary stability unit
+pref.dlg.checkbox.DisplaySecondaryStability.ttip = If checked, a secondary stability unit will be displayed in the rocket design view.
pref.dlg.lbl.FlightTime = Flight time:
pref.dlg.lbl.effect1 = The effects will take place the next time you open a window.
pref.dlg.lbl.Checkingupdates = Checking for updates\u2026
@@ -380,6 +385,8 @@ pref.dlg.DescriptionArea.Adddirectories = Add directories, RASP motor files (*.e
PreferencesDialog.lbl.language = Interface language:
PreferencesDialog.languages.default = System default
PreferencesDialog.lbl.languageEffect = The language will change the next time you start OpenRocket.
+PreferencesDialog.CancelOperation.title = Discard Preference Changes
+PreferencesDialog.CancelOperation.msg.discardChanges = Are you sure you want to
discard the preference changes?
generalprefs.lbl.language = Interface language
generalprefs.languages.default = System default
@@ -619,7 +626,7 @@ SimuRunDlg.msg.branchErrorOccurred = An error occurred during simulation branch
BasicEventSimulationEngine.error.noMotorsDefined = No motors defined in the simulation.
BasicEventSimulationEngine.error.activeLengthZero = Active airframe has length 0
BasicEventSimulationEngine.error.cantCalculateStability = Can't calculate stability
-BasicEventSimulationEngine.error.earlyMotorBurnout = Motor burnout without liftoff.
+BasicEventSimulationEngine.error.earlyMotorBurnout = Motor burnout without liftoff.
Use more (powerful) motors, or decrease the rocket mass.
BasicEventSimulationEngine.error.noConfiguredIgnition = No motors configured to ignite at liftoff
BasicEventSimulationEngine.error.noIgnition = No motors ignited.
BasicEventSimulationEngine.error.NaNResult = Simulation resulted in not-a-number (NaN) value, please report a bug.
@@ -1504,6 +1511,7 @@ TCMotorSelPan.btn.close = Close
! PlotDialog
PlotDialog.CheckBox.Showdatapoints = Show data points
PlotDialog.lbl.Chart = left click drag to zoom area. mouse wheel to zoom. ctrl-mouse wheel to zoom x axis only. ctrl-left click drag to pan. right click drag to zoom dynamically.
+PlotDialog.lbl.timeSeriesWarning = The data is plotted in time order even though the X axis type is not time.
PlotDialog.btn.exportImage = Export Image
ComponentTree.ttip.massoverride = mass overriden
diff --git a/core/resources/pix/icons/cd-override-subcomponent.png b/core/resources/pix/icons/cd-override-subcomponent.png
index 228cb95f3..6791e6b6f 100644
Binary files a/core/resources/pix/icons/cd-override-subcomponent.png and b/core/resources/pix/icons/cd-override-subcomponent.png differ
diff --git a/core/resources/pix/icons/cg-override-subcomponent.png b/core/resources/pix/icons/cg-override-subcomponent.png
index 1107ec954..a289b1486 100644
Binary files a/core/resources/pix/icons/cg-override-subcomponent.png and b/core/resources/pix/icons/cg-override-subcomponent.png differ
diff --git a/core/resources/pix/icons/mass-override-subcomponent.png b/core/resources/pix/icons/mass-override-subcomponent.png
index 5b09443d7..4fc9df88d 100755
Binary files a/core/resources/pix/icons/mass-override-subcomponent.png and b/core/resources/pix/icons/mass-override-subcomponent.png differ
diff --git a/core/src/net/sf/openrocket/rocketcomponent/BodyTube.java b/core/src/net/sf/openrocket/rocketcomponent/BodyTube.java
index 5b42fdcda..5b737dae6 100644
--- a/core/src/net/sf/openrocket/rocketcomponent/BodyTube.java
+++ b/core/src/net/sf/openrocket/rocketcomponent/BodyTube.java
@@ -172,8 +172,8 @@ public class BodyTube extends SymmetricComponent implements BoxBounded, MotorMou
@Override
protected void loadFromPreset(ComponentPreset preset) {
- this.autoRadius = false;
if (preset.has(ComponentPreset.OUTER_DIAMETER)) {
+ this.autoRadius = false;
double outerDiameter = preset.get(ComponentPreset.OUTER_DIAMETER);
this.outerRadius = outerDiameter / 2.0;
if (preset.has(ComponentPreset.INNER_DIAMETER)) {
diff --git a/core/src/net/sf/openrocket/rocketcomponent/ExternalComponent.java b/core/src/net/sf/openrocket/rocketcomponent/ExternalComponent.java
index acac70c8c..b81ee55b3 100644
--- a/core/src/net/sf/openrocket/rocketcomponent/ExternalComponent.java
+++ b/core/src/net/sf/openrocket/rocketcomponent/ExternalComponent.java
@@ -102,7 +102,7 @@ public abstract class ExternalComponent extends RocketComponent {
*/
@Override
public double getComponentMass() {
- return material.getDensity() * getComponentVolume() * getInstanceCount();
+ return material.getDensity() * getComponentVolume();
}
/**
diff --git a/core/src/net/sf/openrocket/rocketcomponent/FinSet.java b/core/src/net/sf/openrocket/rocketcomponent/FinSet.java
index dd033566c..ed675b502 100644
--- a/core/src/net/sf/openrocket/rocketcomponent/FinSet.java
+++ b/core/src/net/sf/openrocket/rocketcomponent/FinSet.java
@@ -544,7 +544,7 @@ public abstract class FinSet extends ExternalComponent implements AxialPositiona
return centerOfMass;
}
- private static Coordinate calculateFilletCrossSection(final double filletRadius, final double bodyRadius){
+ private static Coordinate calculateFilletCrossSection(final double filletRadius, final double bodyRadius) {
final double hypotenuse = filletRadius + bodyRadius;
final double innerArcAngle = Math.asin(filletRadius / hypotenuse);
final double outerArcAngle = Math.acos(filletRadius / hypotenuse);
@@ -554,17 +554,17 @@ public abstract class FinSet extends ExternalComponent implements AxialPositiona
- outerArcAngle * filletRadius * filletRadius / 2
- innerArcAngle * bodyRadius * bodyRadius / 2);
- if(Double.isNaN(crossSectionArea)) {
+ if (Double.isNaN(crossSectionArea)) {
crossSectionArea = 0.;
- }else {
+ } else {
// each fin has a fillet on each side
crossSectionArea *= 2;
}
// heuristic, relTo the body center
- double yCentroid = bodyRadius + filletRadius /5;
+ double yCentroid = bodyRadius + filletRadius / 5;
- return new Coordinate(0,yCentroid,0,crossSectionArea);
+ return new Coordinate(0, yCentroid, 0, crossSectionArea);
}
/*
@@ -581,7 +581,8 @@ public abstract class FinSet extends ExternalComponent implements AxialPositiona
* 5. Return twice that since there is a fillet on each side of the fin.
*/
protected Coordinate calculateFilletVolumeCentroid() {
- if((null == this.parent) || (!SymmetricComponent.class.isAssignableFrom(this.parent.getClass()))){
+ if ((this.filletRadius == 0) || (this.parent == null) ||
+ (!SymmetricComponent.class.isAssignableFrom(this.parent.getClass()))) {
return Coordinate.ZERO;
}
Coordinate[] mountPoints = this.getRootPoints();
@@ -594,7 +595,7 @@ public abstract class FinSet extends ExternalComponent implements AxialPositiona
final Coordinate finLead = getFinFront();
final double xFinEnd = finLead.x + getLength();
final Coordinate[] rootPoints = getMountPoints( finLead.x, xFinEnd, -finLead.x, -finLead.y);
- if (0 == rootPoints.length) {
+ if (rootPoints.length == 0) {
return Coordinate.ZERO;
}
@@ -616,7 +617,7 @@ public abstract class FinSet extends ExternalComponent implements AxialPositiona
final Coordinate segmentCentroid = segmentCrossSection.setWeight(segmentVolume);
- filletVolumeCentroid = filletVolumeCentroid.add(segmentCentroid);
+ filletVolumeCentroid = filletVolumeCentroid.average(segmentCentroid);
prev = cur;
}
@@ -624,7 +625,7 @@ public abstract class FinSet extends ExternalComponent implements AxialPositiona
if (finCount == 1) {
Transformation rotation = Transformation.rotate_x( getAngleOffset());
return rotation.transform(filletVolumeCentroid);
- }else{
+ } else{
return filletVolumeCentroid.setY(0.);
}
}
diff --git a/core/src/net/sf/openrocket/rocketcomponent/LaunchLug.java b/core/src/net/sf/openrocket/rocketcomponent/LaunchLug.java
index 4b0c18912..06aebbb2a 100644
--- a/core/src/net/sf/openrocket/rocketcomponent/LaunchLug.java
+++ b/core/src/net/sf/openrocket/rocketcomponent/LaunchLug.java
@@ -215,7 +215,7 @@ public class LaunchLug extends Tube implements AnglePositionable, BoxBounded, Li
@Override
public double getComponentVolume() {
- return length * Math.PI * (MathUtil.pow2(radius) - MathUtil.pow2(radius - thickness));
+ return length * Math.PI * (MathUtil.pow2(radius) - MathUtil.pow2(radius - thickness)) * getInstanceCount();
}
@Override
@@ -228,9 +228,12 @@ public class LaunchLug extends Tube implements AnglePositionable, BoxBounded, Li
@Override
public Coordinate getComponentCG() {
+ final double parentRadius = parent instanceof SymmetricComponent ?
+ ((SymmetricComponent) parent).getRadius(getAxialOffset()) : 0;
+
final double CMx = length / 2 + (instanceSeparation * (instanceCount-1)) / 2;
- final double CMy = Math.cos(this.angleOffsetRad)*getOuterRadius();
- final double CMz = Math.sin(this.angleOffsetRad)*getOuterRadius();
+ final double CMy = Math.cos(this.angleOffsetRad) * (parentRadius + getOuterRadius());
+ final double CMz = Math.sin(this.angleOffsetRad) * (parentRadius + getOuterRadius());
return new Coordinate(CMx, CMy, CMz, getComponentMass());
}
diff --git a/core/src/net/sf/openrocket/rocketcomponent/RailButton.java b/core/src/net/sf/openrocket/rocketcomponent/RailButton.java
index 734966339..17e270109 100644
--- a/core/src/net/sf/openrocket/rocketcomponent/RailButton.java
+++ b/core/src/net/sf/openrocket/rocketcomponent/RailButton.java
@@ -304,7 +304,8 @@ public class RailButton extends ExternalComponent implements AnglePositionable,
final double volInner = Math.PI*Math.pow( innerDiameter_m/2, 2)*getInnerHeight();
final double volStandoff = Math.PI*Math.pow( outerDiameter_m/2, 2)* baseHeight_m;
final double volScrew = 2f/3 * Math.PI * MathUtil.pow2(outerDiameter_m/2) * screwHeight_m;
- return volOuter + volInner + volStandoff + volScrew;
+ final double volInstance = volOuter + volInner + volStandoff + volScrew;
+ return volInstance * getInstanceCount();
}
@Override
@@ -380,14 +381,16 @@ public class RailButton extends ExternalComponent implements AnglePositionable,
final double flangeCM = this.totalHeight_m - getFlangeHeight()/2;
final double screwCM = this.totalHeight_m + 4 * this.screwHeight_m / (3 * Math.PI);
final double heightCM = (massBase*baseCM + massInner*innerCM + massFlange*flangeCM + massScrew*screwCM)/totalMass;
+ final double parentRadius = parent instanceof SymmetricComponent ?
+ ((SymmetricComponent) parent).getRadius(getAxialOffset()) : 0;
if (heightCM > this.totalHeight_m + this.screwHeight_m) {
throw new BugException(" bug found while computing the CG of a RailButton: "+this.getName()+"\n height of CG: "+heightCM);
}
final double CMx = (instanceSeparation * (instanceCount-1)) / 2;
- final double CMy = Math.cos(this.angleOffsetRad)*heightCM;
- final double CMz = Math.sin(this.angleOffsetRad)*heightCM;
+ final double CMy = Math.cos(this.angleOffsetRad) * (parentRadius + heightCM);
+ final double CMz = Math.sin(this.angleOffsetRad) * (parentRadius + heightCM);
return new Coordinate( CMx, CMy, CMz, getComponentMass());
}
diff --git a/core/src/net/sf/openrocket/rocketcomponent/StageSeparationConfiguration.java b/core/src/net/sf/openrocket/rocketcomponent/StageSeparationConfiguration.java
index 0c582cd0d..d7ef82824 100644
--- a/core/src/net/sf/openrocket/rocketcomponent/StageSeparationConfiguration.java
+++ b/core/src/net/sf/openrocket/rocketcomponent/StageSeparationConfiguration.java
@@ -60,6 +60,14 @@ public class StageSeparationConfiguration implements FlightConfigurableParameter
return (mount == ignition);
}
},
+ //// Launch
+ LAUNCH(trans.get("Stage.SeparationEvent.LAUNCH")) {
+ @Override
+ public boolean isSeparationEvent(FlightEvent e, AxialStage stage) {
+ return e.getType() == FlightEvent.Type.LAUNCH;
+ }
+ },
+ //// Never
NEVER(trans.get("Stage.SeparationEvent.NEVER")) {
@Override
public boolean isSeparationEvent(FlightEvent e, AxialStage stage) {
diff --git a/core/src/net/sf/openrocket/rocketcomponent/TubeFinSet.java b/core/src/net/sf/openrocket/rocketcomponent/TubeFinSet.java
index 992a8935a..b5823989c 100644
--- a/core/src/net/sf/openrocket/rocketcomponent/TubeFinSet.java
+++ b/core/src/net/sf/openrocket/rocketcomponent/TubeFinSet.java
@@ -518,6 +518,19 @@ public class TubeFinSet extends Tube implements AxialPositionable, BoxBounded, R
}
+ @Override
+ protected void loadFromPreset(ComponentPreset preset) {
+ super.loadFromPreset(preset);
+ if (preset.has(ComponentPreset.OUTER_DIAMETER)) {
+ this.autoRadius = false;
+ double outerDiameter = preset.get(ComponentPreset.OUTER_DIAMETER);
+ this.outerRadius = outerDiameter / 2.0;
+ if (preset.has(ComponentPreset.INNER_DIAMETER)) {
+ double innerDiameter = preset.get(ComponentPreset.INNER_DIAMETER);
+ this.thickness = (outerDiameter - innerDiameter) / 2.0;
+ }
+ }
+ }
@Override
public InsideColorComponentHandler getInsideColorComponentHandler() {
diff --git a/core/src/net/sf/openrocket/simulation/AbstractEulerStepper.java b/core/src/net/sf/openrocket/simulation/AbstractEulerStepper.java
new file mode 100644
index 000000000..a004b1069
--- /dev/null
+++ b/core/src/net/sf/openrocket/simulation/AbstractEulerStepper.java
@@ -0,0 +1,184 @@
+package net.sf.openrocket.simulation;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import net.sf.openrocket.models.atmosphere.AtmosphericConditions;
+import net.sf.openrocket.rocketcomponent.InstanceMap;
+import net.sf.openrocket.rocketcomponent.RecoveryDevice;
+import net.sf.openrocket.simulation.exception.SimulationException;
+import net.sf.openrocket.util.Coordinate;
+import net.sf.openrocket.util.GeodeticComputationStrategy;
+import net.sf.openrocket.util.MathUtil;
+import net.sf.openrocket.util.WorldCoordinate;
+
+public abstract class AbstractEulerStepper extends AbstractSimulationStepper {
+ private static final Logger log = LoggerFactory.getLogger(AbstractEulerStepper.class);
+
+ private static final double RECOVERY_TIME_STEP = 0.5;
+
+ protected double cd;
+
+ @Override
+ public SimulationStatus initialize(SimulationStatus status) {
+ this.cd = computeCD(status);
+ return status;
+ }
+
+ private double getCD() {
+ return cd;
+ }
+
+ protected abstract double computeCD(SimulationStatus status);
+
+ @Override
+ public void step(SimulationStatus status, double maxTimeStep) throws SimulationException {
+
+ // Get the atmospheric conditions
+ AtmosphericConditions atmosphere = modelAtmosphericConditions(status);
+
+ //// Local wind speed and direction
+ Coordinate windSpeed = modelWindVelocity(status);
+ Coordinate airSpeed = status.getRocketVelocity().add(windSpeed);
+
+ // Compute drag force
+ double mach = airSpeed.length() / atmosphere.getMachSpeed();
+ double dynP = (0.5 * atmosphere.getDensity() * airSpeed.length2());
+ double dragForce = getCD() * dynP * status.getConfiguration().getReferenceArea();
+
+ // n.b. this is constant, and could be calculated once at the beginning of this simulation branch...
+ double rocketMass = calculateStructureMass(status).getMass();
+ double motorMass = calculateMotorMass(status).getMass();
+
+ double mass = rocketMass + motorMass;
+
+ // Compute drag acceleration
+ Coordinate linearAcceleration;
+ if (airSpeed.length() > 0.001) {
+ linearAcceleration = airSpeed.normalize().multiply(-dragForce / mass);
+ } else {
+ linearAcceleration = Coordinate.NUL;
+ }
+
+ // Add effect of gravity
+ double gravity = modelGravity(status);
+ linearAcceleration = linearAcceleration.sub(0, 0, gravity);
+
+
+ // Add coriolis acceleration
+ Coordinate coriolisAcceleration = status.getSimulationConditions().getGeodeticComputation().getCoriolisAcceleration(
+ status.getRocketWorldPosition(), status.getRocketVelocity());
+ linearAcceleration = linearAcceleration.add(coriolisAcceleration);
+
+ // Select tentative time step
+ double timeStep = RECOVERY_TIME_STEP;
+
+ // adjust based on change in acceleration (ie jerk)
+ final double jerk = Math.abs(linearAcceleration.sub(status.getRocketAcceleration()).multiply(1.0/status.getPreviousTimeStep()).length());
+ if (jerk > MathUtil.EPSILON) {
+ timeStep = Math.min(timeStep, 1.0/jerk);
+ }
+
+ // but don't let it get *too* small
+ timeStep = Math.max(timeStep, MIN_TIME_STEP);
+ log.trace("timeStep is " + timeStep);
+
+ // Perform Euler integration
+ Coordinate newPosition = status.getRocketPosition().add(status.getRocketVelocity().multiply(timeStep)).
+ add(linearAcceleration.multiply(MathUtil.pow2(timeStep) / 2));
+
+ // If I've hit the ground, recalculate time step and position
+ if (newPosition.z < 0) {
+
+ final double a = linearAcceleration.z;
+ final double v = status.getRocketVelocity().z;
+ final double z0 = status.getRocketPosition().z;
+
+ // The new timestep is the solution of
+ // 1/2 at^2 + vt + z0 = 0
+ timeStep = (-v - Math.sqrt(v*v - 2*a*z0))/a;
+ log.trace("ground hit changes timeStep to " + timeStep);
+
+ newPosition = status.getRocketPosition().add(status.getRocketVelocity().multiply(timeStep)).
+ add(linearAcceleration.multiply(MathUtil.pow2(timeStep) / 2));
+
+ // avoid rounding error in new altitude
+ newPosition = newPosition.setZ(0);
+ }
+
+ status.setSimulationTime(status.getSimulationTime() + timeStep);
+ status.setPreviousTimeStep(timeStep);
+
+ status.setRocketPosition(newPosition);
+ status.setRocketVelocity(status.getRocketVelocity().add(linearAcceleration.multiply(timeStep)));
+ status.setRocketAcceleration(linearAcceleration);
+
+ // Update the world coordinate
+ WorldCoordinate w = status.getSimulationConditions().getLaunchSite();
+ w = status.getSimulationConditions().getGeodeticComputation().addCoordinate(w, status.getRocketPosition());
+ status.setRocketWorldPosition(w);
+
+ // Store data
+ FlightDataBranch data = status.getFlightData();
+ boolean extra = status.getSimulationConditions().isCalculateExtras();
+ data.addPoint();
+
+ data.setValue(FlightDataType.TYPE_TIME, status.getSimulationTime());
+ data.setValue(FlightDataType.TYPE_ALTITUDE, status.getRocketPosition().z);
+ data.setValue(FlightDataType.TYPE_POSITION_X, status.getRocketPosition().x);
+ data.setValue(FlightDataType.TYPE_POSITION_Y, status.getRocketPosition().y);
+
+ airSpeed = status.getRocketVelocity().add(windSpeed);
+ if (extra) {
+ data.setValue(FlightDataType.TYPE_POSITION_XY,
+ MathUtil.hypot(status.getRocketPosition().x, status.getRocketPosition().y));
+ data.setValue(FlightDataType.TYPE_POSITION_DIRECTION,
+ Math.atan2(status.getRocketPosition().y, status.getRocketPosition().x));
+
+ data.setValue(FlightDataType.TYPE_VELOCITY_XY,
+ MathUtil.hypot(status.getRocketVelocity().x, status.getRocketVelocity().y));
+ data.setValue(FlightDataType.TYPE_ACCELERATION_XY,
+ MathUtil.hypot(linearAcceleration.x, linearAcceleration.y));
+
+ data.setValue(FlightDataType.TYPE_ACCELERATION_TOTAL, linearAcceleration.length());
+
+ double Re = airSpeed.length() *
+ status.getConfiguration().getLengthAerodynamic() /
+ atmosphere.getKinematicViscosity();
+ data.setValue(FlightDataType.TYPE_REYNOLDS_NUMBER, Re);
+ }
+
+
+ data.setValue(FlightDataType.TYPE_LATITUDE, status.getRocketWorldPosition().getLatitudeRad());
+ data.setValue(FlightDataType.TYPE_LONGITUDE, status.getRocketWorldPosition().getLongitudeRad());
+ data.setValue(FlightDataType.TYPE_GRAVITY, gravity);
+
+ if (status.getSimulationConditions().getGeodeticComputation() != GeodeticComputationStrategy.FLAT) {
+ data.setValue(FlightDataType.TYPE_CORIOLIS_ACCELERATION, coriolisAcceleration.length());
+ }
+
+
+ data.setValue(FlightDataType.TYPE_VELOCITY_Z, status.getRocketVelocity().z);
+ data.setValue(FlightDataType.TYPE_ACCELERATION_Z, linearAcceleration.z);
+
+ data.setValue(FlightDataType.TYPE_VELOCITY_TOTAL, airSpeed.length());
+ data.setValue(FlightDataType.TYPE_MACH_NUMBER, mach);
+
+ data.setValue(FlightDataType.TYPE_MASS, mass);
+ data.setValue(FlightDataType.TYPE_MOTOR_MASS, motorMass);
+
+ data.setValue(FlightDataType.TYPE_THRUST_FORCE, 0);
+ data.setValue(FlightDataType.TYPE_DRAG_FORCE, dragForce);
+
+ data.setValue(FlightDataType.TYPE_WIND_VELOCITY, windSpeed.length());
+ data.setValue(FlightDataType.TYPE_AIR_TEMPERATURE, atmosphere.getTemperature());
+ data.setValue(FlightDataType.TYPE_AIR_PRESSURE, atmosphere.getPressure());
+ data.setValue(FlightDataType.TYPE_SPEED_OF_SOUND, atmosphere.getMachSpeed());
+
+ data.setValue(FlightDataType.TYPE_TIME_STEP, timeStep);
+ data.setValue(FlightDataType.TYPE_COMPUTATION_TIME,
+ (System.nanoTime() - status.getSimulationStartWallTime()) / 1000000000.0);
+ log.trace("time " + data.getLast(FlightDataType.TYPE_TIME) + ", altitude " + data.getLast(FlightDataType.TYPE_ALTITUDE) + ", velocity " + data.getLast(FlightDataType.TYPE_VELOCITY_Z));
+ }
+
+}
diff --git a/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java b/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java
index 827771438..ffdb3c2fa 100644
--- a/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java
+++ b/core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java
@@ -100,8 +100,8 @@ public class BasicEventSimulationEngine implements SimulationEngine {
toSimulate.push(currentStatus);
SimulationListenerHelper.fireStartSimulation(currentStatus);
- do{
- if( null == toSimulate.peek()){
+ do {
+ if (toSimulate.peek() == null) {
break;
}
currentStatus = toSimulate.pop();
@@ -121,7 +121,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
if (dataBranch.getLength() == 0) {
flightData.getWarningSet().add(Warning.EMPTY_BRANCH, dataBranch.getBranchName());
}
- }while( ! toSimulate.isEmpty());
+ } while (!toSimulate.isEmpty());
SimulationListenerHelper.fireEndSimulation(currentStatus, null);
@@ -707,7 +707,7 @@ public class BasicEventSimulationEngine implements SimulationEngine {
}
}
- private FlightData computeCoastTime() {
+ private FlightData computeCoastTime() throws SimulationException {
try {
SimulationConditions conds = currentStatus.getSimulationConditions().clone();
conds.getSimulationListenerList().add(OptimumCoastListener.INSTANCE);
@@ -715,6 +715,8 @@ public class BasicEventSimulationEngine implements SimulationEngine {
FlightData d = e.simulate(conds);
return d;
+ } catch (SimulationException e) {
+ throw e;
} catch (Exception e) {
log.warn("Exception computing coast time: ", e);
return null;
diff --git a/core/src/net/sf/openrocket/simulation/BasicLandingStepper.java b/core/src/net/sf/openrocket/simulation/BasicLandingStepper.java
index de7db0bab..cf0f56804 100644
--- a/core/src/net/sf/openrocket/simulation/BasicLandingStepper.java
+++ b/core/src/net/sf/openrocket/simulation/BasicLandingStepper.java
@@ -1,185 +1,18 @@
package net.sf.openrocket.simulation;
-import net.sf.openrocket.models.atmosphere.AtmosphericConditions;
import net.sf.openrocket.rocketcomponent.InstanceMap;
import net.sf.openrocket.rocketcomponent.RecoveryDevice;
-import net.sf.openrocket.simulation.exception.SimulationException;
-import net.sf.openrocket.util.Coordinate;
-import net.sf.openrocket.util.GeodeticComputationStrategy;
-import net.sf.openrocket.util.MathUtil;
-import net.sf.openrocket.util.WorldCoordinate;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+public class BasicLandingStepper extends AbstractEulerStepper {
-public class BasicLandingStepper extends AbstractSimulationStepper {
- private static final Logger log = LoggerFactory.getLogger(BasicLandingStepper.class);
-
- private static final double RECOVERY_TIME_STEP = 0.5;
-
@Override
- public SimulationStatus initialize(SimulationStatus status) {
- return status;
- }
-
- @Override
- public void step(SimulationStatus status, double maxTimeStep) throws SimulationException {
- double totalCD = 0;
- double refArea = status.getConfiguration().getReferenceArea();
-
- // Get the atmospheric conditions
- AtmosphericConditions atmosphere = modelAtmosphericConditions(status);
-
- //// Local wind speed and direction
- Coordinate windSpeed = modelWindVelocity(status);
- Coordinate airSpeed = status.getRocketVelocity().add(windSpeed);
-
- // Get total CD
- double mach = airSpeed.length() / atmosphere.getMachSpeed();
-
+ protected double computeCD(SimulationStatus status) {
+ // Accumulate CD for all recovery devices
+ cd = 0;
final InstanceMap imap = status.getConfiguration().getActiveInstances();
for (RecoveryDevice c : status.getDeployedRecoveryDevices()) {
- totalCD += imap.count(c) * c.getCD(mach) * c.getArea() / refArea;
+ cd += imap.count(c) * c.getCD() * c.getArea() / status.getConfiguration().getReferenceArea();
}
-
- // Compute drag force
- double dynP = (0.5 * atmosphere.getDensity() * airSpeed.length2());
- double dragForce = totalCD * dynP * refArea;
-
- // Calculate mass data
- double rocketMass = calculateStructureMass(status).getMass();
- double motorMass = calculateMotorMass(status).getMass();
-
- double mass = rocketMass + motorMass;
-
- // Compute drag acceleration
- Coordinate linearAcceleration;
- if (airSpeed.length() > 0.001) {
- linearAcceleration = airSpeed.normalize().multiply(-dragForce / mass);
- } else {
- linearAcceleration = Coordinate.NUL;
- }
-
- // Add effect of gravity
- double gravity = modelGravity(status);
- linearAcceleration = linearAcceleration.sub(0, 0, gravity);
-
-
- // Add coriolis acceleration
- Coordinate coriolisAcceleration = status.getSimulationConditions().getGeodeticComputation().getCoriolisAcceleration(
- status.getRocketWorldPosition(), status.getRocketVelocity());
- linearAcceleration = linearAcceleration.add(coriolisAcceleration);
-
-
-
- // Select tentative time step
- double timeStep = RECOVERY_TIME_STEP;
-
- // adjust based on change in acceleration (ie jerk)
- final double jerk = Math.abs(linearAcceleration.sub(status.getRocketAcceleration()).multiply(1.0/status.getPreviousTimeStep()).length());
- if (jerk > MathUtil.EPSILON) {
- timeStep = Math.min(timeStep, 1.0/jerk);
- }
- // but don't let it get *too* small
- timeStep = Math.max(timeStep, MIN_TIME_STEP);
- log.trace("timeStep is " + timeStep);
-
- // Perform Euler integration
- Coordinate newPosition = status.getRocketPosition().add(status.getRocketVelocity().multiply(timeStep)).
- add(linearAcceleration.multiply(MathUtil.pow2(timeStep) / 2));
-
- // If I've hit the ground, recalculate time step and position
- if (newPosition.z < 0) {
-
- final double a = linearAcceleration.z;
- final double v = status.getRocketVelocity().z;
- final double z0 = status.getRocketPosition().z;
-
- // The new timestep is the solution of
- // 1/2 at^2 + vt + z0 = 0
- timeStep = (-v - Math.sqrt(v*v - 2*a*z0))/a;
- log.trace("ground hit changes timeStep to " + timeStep);
-
- newPosition = status.getRocketPosition().add(status.getRocketVelocity().multiply(timeStep)).
- add(linearAcceleration.multiply(MathUtil.pow2(timeStep) / 2));
-
- // avoid rounding error in new altitude
- newPosition = newPosition.setZ(0);
- }
-
- status.setSimulationTime(status.getSimulationTime() + timeStep);
- status.setPreviousTimeStep(timeStep);
-
- status.setRocketPosition(newPosition);
- status.setRocketVelocity(status.getRocketVelocity().add(linearAcceleration.multiply(timeStep)));
- status.setRocketAcceleration(linearAcceleration);
-
- // Update the world coordinate
- WorldCoordinate w = status.getSimulationConditions().getLaunchSite();
- w = status.getSimulationConditions().getGeodeticComputation().addCoordinate(w, status.getRocketPosition());
- status.setRocketWorldPosition(w);
-
- // Store data
- FlightDataBranch data = status.getFlightData();
- boolean extra = status.getSimulationConditions().isCalculateExtras();
- data.addPoint();
-
- data.setValue(FlightDataType.TYPE_TIME, status.getSimulationTime());
- data.setValue(FlightDataType.TYPE_ALTITUDE, status.getRocketPosition().z);
- data.setValue(FlightDataType.TYPE_POSITION_X, status.getRocketPosition().x);
- data.setValue(FlightDataType.TYPE_POSITION_Y, status.getRocketPosition().y);
-
- airSpeed = status.getRocketVelocity().add(windSpeed);
- if (extra) {
- data.setValue(FlightDataType.TYPE_POSITION_XY,
- MathUtil.hypot(status.getRocketPosition().x, status.getRocketPosition().y));
- data.setValue(FlightDataType.TYPE_POSITION_DIRECTION,
- Math.atan2(status.getRocketPosition().y, status.getRocketPosition().x));
-
- data.setValue(FlightDataType.TYPE_VELOCITY_XY,
- MathUtil.hypot(status.getRocketVelocity().x, status.getRocketVelocity().y));
- data.setValue(FlightDataType.TYPE_ACCELERATION_XY,
- MathUtil.hypot(linearAcceleration.x, linearAcceleration.y));
-
- data.setValue(FlightDataType.TYPE_ACCELERATION_TOTAL, linearAcceleration.length());
-
- double Re = airSpeed.length() *
- status.getConfiguration().getLengthAerodynamic() /
- atmosphere.getKinematicViscosity();
- data.setValue(FlightDataType.TYPE_REYNOLDS_NUMBER, Re);
- }
-
-
- data.setValue(FlightDataType.TYPE_LATITUDE, status.getRocketWorldPosition().getLatitudeRad());
- data.setValue(FlightDataType.TYPE_LONGITUDE, status.getRocketWorldPosition().getLongitudeRad());
- data.setValue(FlightDataType.TYPE_GRAVITY, gravity);
-
- if (status.getSimulationConditions().getGeodeticComputation() != GeodeticComputationStrategy.FLAT) {
- data.setValue(FlightDataType.TYPE_CORIOLIS_ACCELERATION, coriolisAcceleration.length());
- }
-
-
- data.setValue(FlightDataType.TYPE_VELOCITY_Z, status.getRocketVelocity().z);
- data.setValue(FlightDataType.TYPE_ACCELERATION_Z, linearAcceleration.z);
-
- data.setValue(FlightDataType.TYPE_VELOCITY_TOTAL, airSpeed.length());
- data.setValue(FlightDataType.TYPE_MACH_NUMBER, mach);
-
- data.setValue(FlightDataType.TYPE_MASS, mass);
- data.setValue(FlightDataType.TYPE_MOTOR_MASS, motorMass);
-
- data.setValue(FlightDataType.TYPE_THRUST_FORCE, 0);
- data.setValue(FlightDataType.TYPE_DRAG_FORCE, dragForce);
-
- data.setValue(FlightDataType.TYPE_WIND_VELOCITY, windSpeed.length());
- data.setValue(FlightDataType.TYPE_AIR_TEMPERATURE, atmosphere.getTemperature());
- data.setValue(FlightDataType.TYPE_AIR_PRESSURE, atmosphere.getPressure());
- data.setValue(FlightDataType.TYPE_SPEED_OF_SOUND, atmosphere.getMachSpeed());
-
- data.setValue(FlightDataType.TYPE_TIME_STEP, timeStep);
- data.setValue(FlightDataType.TYPE_COMPUTATION_TIME,
- (System.nanoTime() - status.getSimulationStartWallTime()) / 1000000000.0);
- log.trace("time " + data.getLast(FlightDataType.TYPE_TIME) + ", altitude " + data.getLast(FlightDataType.TYPE_ALTITUDE) + ", velocity " + data.getLast(FlightDataType.TYPE_VELOCITY_Z));
+ return cd;
}
-
}
diff --git a/core/src/net/sf/openrocket/simulation/BasicTumbleStatus.java b/core/src/net/sf/openrocket/simulation/BasicTumbleStatus.java
deleted file mode 100644
index 324789b61..000000000
--- a/core/src/net/sf/openrocket/simulation/BasicTumbleStatus.java
+++ /dev/null
@@ -1,85 +0,0 @@
-package net.sf.openrocket.simulation;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.Map;
-
-import net.sf.openrocket.rocketcomponent.FinSet;
-import net.sf.openrocket.rocketcomponent.FlightConfiguration;
-import net.sf.openrocket.rocketcomponent.InstanceContext;
-import net.sf.openrocket.rocketcomponent.InstanceMap;
-import net.sf.openrocket.rocketcomponent.Rocket;
-import net.sf.openrocket.rocketcomponent.RocketComponent;
-import net.sf.openrocket.rocketcomponent.SymmetricComponent;
-
-public class BasicTumbleStatus extends SimulationStatus {
-
- // Magic constants from techdoc.pdf
- private final static double cDFin = 1.42;
- private final static double cDBt = 0.56;
- // Fin efficiency. Index is number of fins. The 0th entry is arbitrary and used to
- // offset the indexes so finEff[1] is the coefficient for one fin from the table in techdoc.pdf
- private final static double[] finEff = { 0.0, 0.5, 1.0, 1.41, 1.81, 1.73, 1.90, 1.85 };
-
- private final double drag;
-
- public BasicTumbleStatus(FlightConfiguration configuration,
- SimulationConditions simulationConditions) {
- super(configuration, simulationConditions);
- this.drag = computeTumbleDrag();
- }
-
- public BasicTumbleStatus(SimulationStatus orig) {
- super(orig);
- if (orig instanceof BasicTumbleStatus) {
- this.drag = ((BasicTumbleStatus) orig).drag;
- } else {
- this.drag = computeTumbleDrag();
- }
- }
-
- public double getTumbleDrag() {
- return drag;
- }
-
-
- private double computeTumbleDrag() {
-
- // Computed based on Sampo's experimentation as documented in the pdf.
-
- // compute the fin and body tube projected areas
- double aFins = 0.0;
- double aBt = 0.0;
- final InstanceMap imap = this.getConfiguration().getActiveInstances();
- for(Map.Entry
> entry: imap.entrySet() ) {
- final RocketComponent component = entry.getKey();
-
- if (!component.isAerodynamic()) {
- continue;
- }
-
- // iterate across component instances
- final ArrayList contextList = entry.getValue();
- for(InstanceContext context: contextList ) {
-
- if (component instanceof FinSet) {
- final FinSet finComponent = ((FinSet) component);
- final double finArea = finComponent.getPlanformArea();
- int finCount = finComponent.getFinCount();
-
- // check bounds on finCount.
- if (finCount >= finEff.length) {
- finCount = finEff.length - 1;
- }
-
- aFins += finArea * finEff[finCount] / finComponent.getFinCount();
-
- } else if (component instanceof SymmetricComponent) {
- aBt += ((SymmetricComponent) component).getComponentPlanformArea();
- }
- }
- }
-
- return (cDFin * aFins + cDBt * aBt);
- }
-}
diff --git a/core/src/net/sf/openrocket/simulation/BasicTumbleStepper.java b/core/src/net/sf/openrocket/simulation/BasicTumbleStepper.java
index cd8750e23..6eeaa47f3 100644
--- a/core/src/net/sf/openrocket/simulation/BasicTumbleStepper.java
+++ b/core/src/net/sf/openrocket/simulation/BasicTumbleStepper.java
@@ -1,165 +1,62 @@
package net.sf.openrocket.simulation;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Map;
-import net.sf.openrocket.models.atmosphere.AtmosphericConditions;
-import net.sf.openrocket.simulation.exception.SimulationException;
-import net.sf.openrocket.util.Coordinate;
-import net.sf.openrocket.util.GeodeticComputationStrategy;
-import net.sf.openrocket.util.MathUtil;
-import net.sf.openrocket.util.WorldCoordinate;
+import net.sf.openrocket.rocketcomponent.FinSet;
+import net.sf.openrocket.rocketcomponent.InstanceContext;
+import net.sf.openrocket.rocketcomponent.InstanceMap;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+import net.sf.openrocket.rocketcomponent.SymmetricComponent;
-public class BasicTumbleStepper extends AbstractSimulationStepper {
+public class BasicTumbleStepper extends AbstractEulerStepper {
- private static final double RECOVERY_TIME_STEP = 0.5;
+ public double computeCD(SimulationStatus status) {
+
+ // Computed based on Sampo's experimentation as documented in techdoc.pdf.
- @Override
- public SimulationStatus initialize(SimulationStatus original) {
- BasicTumbleStatus status = new BasicTumbleStatus(original);
- status.setWarnings(original.getWarnings());
-
- return status;
- }
-
- @Override
- public void step(SimulationStatus status, double maxTimeStep) throws SimulationException {
+ // Magic constants from techdoc.pdf
+ final double cDFin = 1.42;
+ final double cDBt = 0.56;
+ // Fin efficiency. Index is number of fins. The 0th entry is arbitrary and used to
+ // offset the indexes so finEff[1] is the coefficient for one fin from the table in techdoc.pdf
+ final double[] finEff = { 0.0, 0.5, 1.0, 1.41, 1.81, 1.73, 1.90, 1.85 };
- // Get the atmospheric conditions
- AtmosphericConditions atmosphere = modelAtmosphericConditions(status);
-
- //// Local wind speed and direction
- Coordinate windSpeed = modelWindVelocity(status);
- Coordinate airSpeed = status.getRocketVelocity().add(windSpeed);
-
- // Get total CD
- double mach = airSpeed.length() / atmosphere.getMachSpeed();
-
- double tumbleDrag = ((BasicTumbleStatus)status).getTumbleDrag();
+ // compute the fin and body tube projected areas
+ double aFins = 0.0;
+ double aBt = 0.0;
+ final InstanceMap imap = status.getConfiguration().getActiveInstances();
+ for(Map.Entry> entry: imap.entrySet() ) {
+ final RocketComponent component = entry.getKey();
+
+ if (!component.isAerodynamic()) {
+ continue;
+ }
+
+ // iterate across component instances
+ final ArrayList contextList = entry.getValue();
+ for(InstanceContext context: contextList ) {
- // Compute drag force
- double dynP = (0.5 * atmosphere.getDensity() * airSpeed.length2());
- double dragForce = tumbleDrag * dynP;
-
- // n.b. this is constant, and could be calculated once at the beginning of this simulation branch...
- double rocketMass = calculateStructureMass(status).getMass();
- double motorMass = calculateMotorMass(status).getMass();
-
- double mass = rocketMass + motorMass;
-
- // Compute drag acceleration
- Coordinate linearAcceleration;
- if (airSpeed.length() > 0.001) {
- linearAcceleration = airSpeed.normalize().multiply(-dragForce / mass);
- } else {
- linearAcceleration = Coordinate.NUL;
+ if (component instanceof FinSet) {
+ final FinSet finComponent = ((FinSet) component);
+ final double finArea = finComponent.getPlanformArea();
+ int finCount = finComponent.getFinCount();
+
+ // check bounds on finCount.
+ if (finCount >= finEff.length) {
+ finCount = finEff.length - 1;
+ }
+
+ aFins += finArea * finEff[finCount] / finComponent.getFinCount();
+
+ } else if (component instanceof SymmetricComponent) {
+ aBt += ((SymmetricComponent) component).getComponentPlanformArea();
+ }
+ }
}
- // Add effect of gravity
- double gravity = modelGravity(status);
- linearAcceleration = linearAcceleration.sub(0, 0, gravity);
-
-
- // Add coriolis acceleration
- Coordinate coriolisAcceleration = status.getSimulationConditions().getGeodeticComputation().getCoriolisAcceleration(
- status.getRocketWorldPosition(), status.getRocketVelocity());
- linearAcceleration = linearAcceleration.add(coriolisAcceleration);
-
-
-
- // Select time step
- double timeStep = MathUtil.min(0.5 / linearAcceleration.length(), RECOVERY_TIME_STEP);
-
- // Perform Euler integration
- Coordinate newPosition = status.getRocketPosition().add(status.getRocketVelocity().multiply(timeStep)).
- add(linearAcceleration.multiply(MathUtil.pow2(timeStep) / 2));
-
- // If I've hit the ground, recalculate time step and position
- if (newPosition.z < 0) {
-
- final double a = linearAcceleration.z;
- final double v = status.getRocketVelocity().z;
- final double z0 = status.getRocketPosition().z;
-
- // The new timestep is the solution of
- // 1/2 at^2 + vt + z0 = 0
- timeStep = (-v - Math.sqrt(v*v - 2*a*z0))/a;
-
- newPosition = status.getRocketPosition().add(status.getRocketVelocity().multiply(timeStep)).
- add(linearAcceleration.multiply(MathUtil.pow2(timeStep) / 2));
-
- // avoid rounding error in new altitude
- newPosition = newPosition.setZ(0);
- }
-
- status.setRocketPosition(status.getRocketPosition().add(status.getRocketVelocity().multiply(timeStep)).
- add(linearAcceleration.multiply(MathUtil.pow2(timeStep) / 2)));
- status.setRocketVelocity(status.getRocketVelocity().add(linearAcceleration.multiply(timeStep)));
- status.setSimulationTime(status.getSimulationTime() + timeStep);
-
-
- // Update the world coordinate
- WorldCoordinate w = status.getSimulationConditions().getLaunchSite();
- w = status.getSimulationConditions().getGeodeticComputation().addCoordinate(w, status.getRocketPosition());
- status.setRocketWorldPosition(w);
-
-
- // Store data
- FlightDataBranch data = status.getFlightData();
- boolean extra = status.getSimulationConditions().isCalculateExtras();
- data.addPoint();
-
- data.setValue(FlightDataType.TYPE_TIME, status.getSimulationTime());
- data.setValue(FlightDataType.TYPE_ALTITUDE, status.getRocketPosition().z);
- data.setValue(FlightDataType.TYPE_POSITION_X, status.getRocketPosition().x);
- data.setValue(FlightDataType.TYPE_POSITION_Y, status.getRocketPosition().y);
- if (extra) {
- data.setValue(FlightDataType.TYPE_POSITION_XY,
- MathUtil.hypot(status.getRocketPosition().x, status.getRocketPosition().y));
- data.setValue(FlightDataType.TYPE_POSITION_DIRECTION,
- Math.atan2(status.getRocketPosition().y, status.getRocketPosition().x));
-
- data.setValue(FlightDataType.TYPE_VELOCITY_XY,
- MathUtil.hypot(status.getRocketVelocity().x, status.getRocketVelocity().y));
- data.setValue(FlightDataType.TYPE_ACCELERATION_XY,
- MathUtil.hypot(linearAcceleration.x, linearAcceleration.y));
-
- data.setValue(FlightDataType.TYPE_ACCELERATION_TOTAL, linearAcceleration.length());
-
- double Re = airSpeed.length() *
- status.getConfiguration().getLengthAerodynamic() /
- atmosphere.getKinematicViscosity();
- data.setValue(FlightDataType.TYPE_REYNOLDS_NUMBER, Re);
- }
-
-
- data.setValue(FlightDataType.TYPE_LATITUDE, status.getRocketWorldPosition().getLatitudeRad());
- data.setValue(FlightDataType.TYPE_LONGITUDE, status.getRocketWorldPosition().getLongitudeRad());
- data.setValue(FlightDataType.TYPE_GRAVITY, gravity);
-
- if (status.getSimulationConditions().getGeodeticComputation() != GeodeticComputationStrategy.FLAT) {
- data.setValue(FlightDataType.TYPE_CORIOLIS_ACCELERATION, coriolisAcceleration.length());
- }
-
-
- data.setValue(FlightDataType.TYPE_VELOCITY_Z, status.getRocketVelocity().z);
- data.setValue(FlightDataType.TYPE_ACCELERATION_Z, linearAcceleration.z);
-
- data.setValue(FlightDataType.TYPE_VELOCITY_TOTAL, airSpeed.length());
- data.setValue(FlightDataType.TYPE_MACH_NUMBER, mach);
-
- data.setValue(FlightDataType.TYPE_MASS, mass);
- data.setValue(FlightDataType.TYPE_MOTOR_MASS, motorMass);
-
- data.setValue(FlightDataType.TYPE_THRUST_FORCE, 0);
- data.setValue(FlightDataType.TYPE_DRAG_FORCE, dragForce);
-
- data.setValue(FlightDataType.TYPE_WIND_VELOCITY, windSpeed.length());
- data.setValue(FlightDataType.TYPE_AIR_TEMPERATURE, atmosphere.getTemperature());
- data.setValue(FlightDataType.TYPE_AIR_PRESSURE, atmosphere.getPressure());
- data.setValue(FlightDataType.TYPE_SPEED_OF_SOUND, atmosphere.getMachSpeed());
-
- data.setValue(FlightDataType.TYPE_TIME_STEP, timeStep);
- data.setValue(FlightDataType.TYPE_COMPUTATION_TIME,
- (System.nanoTime() - status.getSimulationStartWallTime()) / 1000000000.0);
+ return (cDFin * aFins + cDBt * aBt)/status.getConfiguration().getReferenceArea();
}
}
diff --git a/core/src/net/sf/openrocket/startup/Preferences.java b/core/src/net/sf/openrocket/startup/Preferences.java
index 0830222ae..382bfc438 100644
--- a/core/src/net/sf/openrocket/startup/Preferences.java
+++ b/core/src/net/sf/openrocket/startup/Preferences.java
@@ -44,6 +44,10 @@ public abstract class Preferences implements ChangeSource {
public static final String USER_THRUST_CURVES_KEY = "UserThrustCurves";
public static final String DEFAULT_MACH_NUMBER = "DefaultMachNumber";
+
+ // Preferences related to units
+ public static final String DISPLAY_SECONDARY_STABILITY = "DisplaySecondaryStability";
+
// Preferences related to data export
public static final String EXPORT_FIELD_SEPARATOR = "ExportFieldSeparator";
public static final String EXPORT_DECIMAL_PLACES = "ExportDecimalPlaces";
@@ -79,10 +83,11 @@ public abstract class Preferences implements ChangeSource {
private static final String OPEN_LEFTMOST_DESIGN_TAB = "OpenLeftmostDesignTab";
private static final String SHOW_DISCARD_CONFIRMATION = "IgnoreDiscardEditingWarning";
private static final String SHOW_DISCARD_SIMULATION_CONFIRMATION = "IgnoreDiscardSimulationEditingWarning";
- public static final String MARKER_STYLE_ICON = "MARKER_STYLE_ICON";
- private static final String SHOW_MARKERS = "SHOW_MARKERS";
- private static final String SHOW_RASAERO_FORMAT_WARNING = "SHOW_RASAERO_FORMAT_WARNING";
- private static final String SHOW_ROCKSIM_FORMAT_WARNING = "SHOW_ROCKSIM_FORMAT_WARNING";
+ private static final String SHOW_DISCARD_PREFERENCES_CONFIRMATION = "IgnoreDiscardPreferencesWarning";
+ public static final String MARKER_STYLE_ICON = "MarkerStyleIcon";
+ private static final String SHOW_MARKERS = "ShowMarkers";
+ private static final String SHOW_RASAERO_FORMAT_WARNING = "ShowRASAeroFormatWarning";
+ private static final String SHOW_ROCKSIM_FORMAT_WARNING = "ShowRockSimFormatWarning";
private static final String EXPORT_USER_DIRECTORIES = "ExportUserDirectories";
private static final String EXPORT_WINDOW_INFORMATION = "ExportWindowInformation";
@@ -201,6 +206,27 @@ public abstract class Preferences implements ChangeSource {
}
+ /*
+ * *********************** Unit Preferences *******************************************
+ */
+
+ /**
+ * Return whether to display a secondary stability unit in the rocket design view.
+ * @return true if the secondary unit should be displayed, false if not.
+ */
+ public final boolean isDisplaySecondaryStability() {
+ return this.getBoolean(DISPLAY_SECONDARY_STABILITY, true);
+ }
+
+ /**
+ * Set whether to display a secondary stability unit in the rocket design view.
+ * @param check if true, display the secondary unit, if false not.
+ */
+ public final void setDisplaySecondaryStability(boolean check) {
+ this.putBoolean(DISPLAY_SECONDARY_STABILITY, check);
+ }
+
+
/*
* ******************************************************************************************
*/
@@ -582,6 +608,22 @@ public abstract class Preferences implements ChangeSource {
this.putBoolean(SHOW_DISCARD_SIMULATION_CONFIRMATION, enabled);
}
+ /**
+ * Answer if a confirmation dialog should be shown when canceling preferences changes.
+ *
+ * @return true if the confirmation dialog should be shown.
+ */
+ public final boolean isShowDiscardPreferencesConfirmation() {
+ return this.getBoolean(SHOW_DISCARD_PREFERENCES_CONFIRMATION, true);
+ }
+
+ /**
+ * Enable/Disable showing a confirmation warning when canceling preferences changes.
+ */
+ public final void setShowDiscardPreferencesConfirmation(boolean enabled) {
+ this.putBoolean(SHOW_DISCARD_PREFERENCES_CONFIRMATION, enabled);
+ }
+
/**
* Answer if the always open leftmost tab is enabled.
*
diff --git a/core/src/net/sf/openrocket/unit/UnitGroup.java b/core/src/net/sf/openrocket/unit/UnitGroup.java
index 654410d70..eb5621687 100644
--- a/core/src/net/sf/openrocket/unit/UnitGroup.java
+++ b/core/src/net/sf/openrocket/unit/UnitGroup.java
@@ -39,6 +39,8 @@ public class UnitGroup {
public static final UnitGroup UNITS_AREA;
public static final UnitGroup UNITS_STABILITY;
+ public static final UnitGroup UNITS_SECONDARY_STABILITY;
+
/**
* This unit group contains only the caliber unit that never scales the originating "SI" value.
* It can be used in cases where the originating value is already in calibers to obtains the correct unit.
@@ -162,12 +164,10 @@ public class UnitGroup {
UNITS_STABILITY = new UnitGroup();
- UNITS_STABILITY.addUnit(new GeneralUnit(0.001, "mm"));
- UNITS_STABILITY.addUnit(new GeneralUnit(0.01, "cm"));
- UNITS_STABILITY.addUnit(new GeneralUnit(1, "m"));
- UNITS_STABILITY.addUnit(new GeneralUnit(0.0254, "in"));
- UNITS_STABILITY.addUnit(new CaliberUnit((Rocket) null));
- UNITS_STABILITY.addUnit(new PercentageOfLengthUnit((Rocket) null));
+ UNITS_SECONDARY_STABILITY = new UnitGroup();
+ addStabilityUnits(UNITS_STABILITY);
+ addStabilityUnits(UNITS_SECONDARY_STABILITY);
+
UNITS_STABILITY_CALIBERS = new UnitGroup();
UNITS_STABILITY_CALIBERS.addUnit(new GeneralUnit(1, "cal"));
@@ -310,6 +310,7 @@ public class UnitGroup {
map.put("ACCELERATION", UNITS_ACCELERATION);
map.put("AREA", UNITS_AREA);
map.put("STABILITY", UNITS_STABILITY);
+ map.put("SECONDARY_STABILITY", UNITS_SECONDARY_STABILITY);
map.put("MASS", UNITS_MASS);
map.put("INERTIA", UNITS_INERTIA);
map.put("ANGLE", UNITS_ANGLE);
@@ -366,6 +367,7 @@ public class UnitGroup {
UNITS_DISTANCE.setDefaultUnit("m");
UNITS_AREA.setDefaultUnit("cm" + SQUARED);
UNITS_STABILITY.setDefaultUnit("cal");
+ UNITS_SECONDARY_STABILITY.setDefaultUnit("%");
UNITS_VELOCITY.setDefaultUnit("m/s");
UNITS_ACCELERATION.setDefaultUnit("m/s" + SQUARED);
UNITS_MASS.setDefaultUnit("g");
@@ -392,6 +394,7 @@ public class UnitGroup {
UNITS_DISTANCE.setDefaultUnit("ft");
UNITS_AREA.setDefaultUnit("in" + SQUARED);
UNITS_STABILITY.setDefaultUnit("cal");
+ UNITS_SECONDARY_STABILITY.setDefaultUnit("%");
UNITS_VELOCITY.setDefaultUnit("ft/s");
UNITS_ACCELERATION.setDefaultUnit("ft/s" + SQUARED);
UNITS_MASS.setDefaultUnit("oz");
@@ -425,6 +428,7 @@ public class UnitGroup {
UNITS_ALL_LENGTHS.setDefaultUnit(2);
UNITS_AREA.setDefaultUnit(1);
UNITS_STABILITY.setDefaultUnit(4);
+ UNITS_SECONDARY_STABILITY.setDefaultUnit(5);
UNITS_STABILITY_CALIBERS.setDefaultUnit(0);
UNITS_VELOCITY.setDefaultUnit(0);
UNITS_WINDSPEED.setDefaultUnit(0);
@@ -448,6 +452,15 @@ public class UnitGroup {
UNITS_COEFFICIENT.setDefaultUnit(0);
UNITS_FREQUENCY.setDefaultUnit(1);
}
+
+ private static void addStabilityUnits(UnitGroup stabilityUnit) {
+ stabilityUnit.addUnit(new GeneralUnit(0.001, "mm"));
+ stabilityUnit.addUnit(new GeneralUnit(0.01, "cm"));
+ stabilityUnit.addUnit(new GeneralUnit(1, "m"));
+ stabilityUnit.addUnit(new GeneralUnit(0.0254, "in"));
+ stabilityUnit.addUnit(new CaliberUnit((Rocket) null));
+ stabilityUnit.addUnit(new PercentageOfLengthUnit((Rocket) null));
+ }
/**
@@ -456,8 +469,18 @@ public class UnitGroup {
* @param rocket the rocket from which to calculate the caliber
* @return the unit group
*/
- public static UnitGroup stabilityUnits(Rocket rocket) {
- return new StabilityUnitGroup(rocket);
+ public static StabilityUnitGroup stabilityUnits(Rocket rocket) {
+ return new StabilityUnitGroup(UnitGroup.UNITS_STABILITY, rocket);
+ }
+
+ /**
+ * Return a UnitGroup for secondary stability units based on the rocket.
+ *
+ * @param rocket the rocket from which to calculate the caliber
+ * @return the unit group
+ */
+ public static StabilityUnitGroup secondaryStabilityUnits(Rocket rocket) {
+ return new StabilityUnitGroup(UnitGroup.UNITS_SECONDARY_STABILITY, rocket);
}
@@ -467,8 +490,18 @@ public class UnitGroup {
* @param config the rocket configuration from which to calculate the caliber
* @return the unit group
*/
- public static UnitGroup stabilityUnits(FlightConfiguration config) {
- return new StabilityUnitGroup(config);
+ public static StabilityUnitGroup stabilityUnits(FlightConfiguration config) {
+ return new StabilityUnitGroup(UnitGroup.UNITS_STABILITY, config);
+ }
+
+ /**
+ * Return a UnitGroup for stability units based on the rocket configuration.
+ *
+ * @param config the rocket configuration from which to calculate the caliber
+ * @return the unit group
+ */
+ public static StabilityUnitGroup secondaryStabilityUnits(FlightConfiguration config) {
+ return new StabilityUnitGroup(UnitGroup.UNITS_SECONDARY_STABILITY, config);
}
@@ -479,7 +512,17 @@ public class UnitGroup {
* @return the unit group
*/
public static UnitGroup stabilityUnits(double reference) {
- return new StabilityUnitGroup(reference);
+ return new StabilityUnitGroup(UnitGroup.UNITS_STABILITY, reference);
+ }
+
+ /**
+ * Return a UnitGroup for secondary stability units based on a constant caliber.
+ *
+ * @param reference the constant reference length
+ * @return the unit group
+ */
+ public static UnitGroup secondaryStabilityUnits(double reference) {
+ return new StabilityUnitGroup(UnitGroup.UNITS_SECONDARY_STABILITY, reference);
}
@@ -717,19 +760,27 @@ public class UnitGroup {
* A private class that switches the CaliberUnit to a rocket-specific CaliberUnit.
* All other methods are passed through to UNITS_STABILITY.
*/
- private static class StabilityUnitGroup extends UnitGroup {
+ public static class StabilityUnitGroup extends UnitGroup {
+ private final PercentageOfLengthUnit percentageOfLengthUnit;
+ private final UnitGroup stabilityUnit;
- public StabilityUnitGroup(double ref) { this(new CaliberUnit(ref), new PercentageOfLengthUnit(ref)); }
-
- public StabilityUnitGroup(Rocket rocket) {
- this(new CaliberUnit(rocket), new PercentageOfLengthUnit(rocket));
+ public StabilityUnitGroup(UnitGroup stabilityUnit, double ref) {
+ this(stabilityUnit, new CaliberUnit(ref), new PercentageOfLengthUnit(ref));
}
- public StabilityUnitGroup(FlightConfiguration config) { this(new CaliberUnit(config), new PercentageOfLengthUnit(config)); }
+ public StabilityUnitGroup(UnitGroup stabilityUnit, Rocket rocket) {
+ this(stabilityUnit, new CaliberUnit(rocket), new PercentageOfLengthUnit(rocket));
+ }
- private StabilityUnitGroup(CaliberUnit caliberUnit, PercentageOfLengthUnit percentageOfLengthUnit) {
- this.units.addAll(UnitGroup.UNITS_STABILITY.units);
- this.defaultUnit = UnitGroup.UNITS_STABILITY.defaultUnit;
+ public StabilityUnitGroup(UnitGroup stabilityUnit, FlightConfiguration config) {
+ this(stabilityUnit, new CaliberUnit(config), new PercentageOfLengthUnit(config));
+ }
+
+ private StabilityUnitGroup(UnitGroup stabilityUnit, CaliberUnit caliberUnit, PercentageOfLengthUnit percentageOfLengthUnit) {
+ this.percentageOfLengthUnit = percentageOfLengthUnit;
+ this.stabilityUnit = stabilityUnit;
+ this.units.addAll(stabilityUnit.units);
+ this.defaultUnit = stabilityUnit.defaultUnit;
for (int i = 0; i < units.size(); i++) {
if (units.get(i) instanceof CaliberUnit) {
units.set(i, caliberUnit);
@@ -744,7 +795,15 @@ public class UnitGroup {
@Override
public void setDefaultUnit(int n) {
super.setDefaultUnit(n);
- UNITS_STABILITY.setDefaultUnit(n);
+ this.stabilityUnit.setDefaultUnit(n);
+ }
+
+ /**
+ * Returns the percentage of length unit. (Stability in %)
+ * @return the percentage of length unit.
+ */
+ public Unit getPercentageOfLengthUnit() {
+ return this.percentageOfLengthUnit;
}
}
}
diff --git a/core/test/net/sf/openrocket/masscalc/MassCalculatorTest.java b/core/test/net/sf/openrocket/masscalc/MassCalculatorTest.java
index c7a01a770..245948e04 100644
--- a/core/test/net/sf/openrocket/masscalc/MassCalculatorTest.java
+++ b/core/test/net/sf/openrocket/masscalc/MassCalculatorTest.java
@@ -65,7 +65,7 @@ public class MassCalculatorTest extends BaseTestCase {
assertEquals(" Alpha III Empty Mass is incorrect: ", expRocketDryMass, actualRocketDryMass, EPSILON);
double expCMx = 0.1917685523;
- double expCMy = -0.00006340812673; // Slight offset due to launch lug
+ double expCMy = -0.000317040634; // Slight offset due to launch lug
Coordinate expCM = new Coordinate(expCMx, expCMy, 0, expRocketDryMass);
assertEquals("Simple Rocket CM.x is incorrect: ", expCM.x, actualRocketDryCM.x, EPSILON);
assertEquals("Simple Rocket CM.y is incorrect: ", expCM.y, actualRocketDryCM.y, EPSILON);
@@ -73,7 +73,7 @@ public class MassCalculatorTest extends BaseTestCase {
assertEquals("Simple Rocket CM is incorrect: ", expCM, actualRocketDryCM);
- double expMOIrot = 1.8763734635622462E-5;
+ double expMOIrot = 1.888136072268211E-5;
double expMOIlong = 1.7808603404853048E-4;
double actualMOIrot = actualStructure.getRotationalInertia();
@@ -118,7 +118,7 @@ public class MassCalculatorTest extends BaseTestCase {
assertEquals(" Alpha III Total Mass (with motor: " + desig + ") is incorrect: ", expRocketLaunchMass, actualRocketLaunchMass, EPSILON);
double expCMx = 0.20996455968266833;
- double expCMy = -0.00003845163503; // Slight offset due to launch lug
+ double expCMy = -0.00019225817513303; // Slight offset due to launch lug
Coordinate expCM = new Coordinate(expCMx, expCMy, 0, expRocketLaunchMass);
assertEquals("Simple Rocket CM.x is incorrect: ", expCM.x, actualRocketLaunchCM.x, EPSILON);
assertEquals("Simple Rocket CM.y is incorrect: ", expCM.y, actualRocketLaunchCM.y, EPSILON);
@@ -1269,5 +1269,37 @@ public class MassCalculatorTest extends BaseTestCase {
assertEquals(0.02, bodyTube.getMass(), EPSILON);
assertEquals(0.02, bodyTube.getSectionMass(), EPSILON);
}
+
+
+ @Test
+ public void testTubeFinMass() {
+ Rocket rocket = OpenRocketDocumentFactory.createNewRocket().getRocket();
+ AxialStage stage = rocket.getStage(0);
+ BodyTube bodyTube = new BodyTube();
+ stage.addChild(bodyTube);
+ TubeFinSet tubeFinSet = new TubeFinSet();
+ tubeFinSet.setOuterRadius(0.04);
+ tubeFinSet.setThickness(0.002);
+ tubeFinSet.setLength(0.1);
+ tubeFinSet.setInstanceCount(3);
+ bodyTube.addChild(tubeFinSet);
+
+ assertEquals(0.0001470265, tubeFinSet.getComponentVolume(), EPSILON);
+ assertEquals(0.0999780446, tubeFinSet.getComponentMass(), EPSILON);
+ assertEquals(0.0999780446, tubeFinSet.getMass(), EPSILON);
+
+ tubeFinSet.setInstanceCount(4);
+
+ assertEquals(0.000196035, tubeFinSet.getComponentVolume(), EPSILON);
+ assertEquals(0.133304059, tubeFinSet.getComponentMass(), EPSILON);
+ assertEquals(0.133304059, tubeFinSet.getMass(), EPSILON);
+
+ tubeFinSet.setMassOverridden(true);
+ tubeFinSet.setOverrideMass(0.02);
+
+ assertEquals(0.133304059, tubeFinSet.getComponentMass(), EPSILON);
+ assertEquals(0.02, tubeFinSet.getMass(), EPSILON);
+ }
+
}
diff --git a/core/test/net/sf/openrocket/rocketcomponent/LaunchLugTest.java b/core/test/net/sf/openrocket/rocketcomponent/LaunchLugTest.java
index 4d2e7f594..a9351f41a 100644
--- a/core/test/net/sf/openrocket/rocketcomponent/LaunchLugTest.java
+++ b/core/test/net/sf/openrocket/rocketcomponent/LaunchLugTest.java
@@ -39,7 +39,7 @@ public class LaunchLugTest extends BaseTestCase {
public void testLaunchLugLocationAtAngles() {
Rocket rocket = TestRockets.makeEstesAlphaIII();
- BodyTube body= (BodyTube)rocket.getChild(0).getChild(1);
+ BodyTube body = (BodyTube)rocket.getChild(0).getChild(1);
LaunchLug lug = (LaunchLug)rocket.getChild(0).getChild(1).getChild(1);
double startAngle = Math.PI/2;
lug.setAngleOffset( startAngle );
@@ -67,6 +67,7 @@ public class LaunchLugTest extends BaseTestCase {
@Test
public void testCMSingleInstance() {
BodyTube bodyTube = new BodyTube();
+ bodyTube.setOuterRadius(0.025);
LaunchLug lug = new LaunchLug();
lug.setLength(0.1);
lug.setOuterRadius(0.02);
@@ -75,7 +76,7 @@ public class LaunchLugTest extends BaseTestCase {
// Test normal CG
Coordinate CG = lug.getCG();
assertEquals(" LaunchLug CG has the wrong x value: ", 0.05, CG.x, EPSILON);
- assertEquals(" LaunchLug CG has the wrong y value: ", -0.02, CG.y, EPSILON);
+ assertEquals(" LaunchLug CG has the wrong y value: ", -0.045, CG.y, EPSILON);
assertEquals(" LaunchLug CG has the wrong z value: ", 0, CG.z, EPSILON);
assertEquals(" LaunchLug CM has the wrong value: ", 0.008331504, CG.weight, EPSILON);
@@ -84,14 +85,14 @@ public class LaunchLugTest extends BaseTestCase {
CG = lug.getCG();
assertEquals(" LaunchLug CG has the wrong x value: ", 0.05, CG.x, EPSILON);
assertEquals(" LaunchLug CG has the wrong y value: ", 0, CG.y, EPSILON);
- assertEquals(" LaunchLug CG has the wrong z value: ", 0.02, CG.z, EPSILON);
+ assertEquals(" LaunchLug CG has the wrong z value: ", 0.045, CG.z, EPSILON);
assertEquals(" LaunchLug CM has the wrong value: ", 0.008331504, CG.weight, EPSILON);
lug.setAngleOffset(-Math.PI / 3);
CG = lug.getCG();
assertEquals(" LaunchLug CG has the wrong x value: ", 0.05, CG.x, EPSILON);
- assertEquals(" LaunchLug CG has the wrong y value: ", 0.01, CG.y, EPSILON);
- assertEquals(" LaunchLug CG has the wrong z value: ", -0.0173205, CG.z, EPSILON);
+ assertEquals(" LaunchLug CG has the wrong y value: ", 0.0225, CG.y, EPSILON);
+ assertEquals(" LaunchLug CG has the wrong z value: ", -0.03897114, CG.z, EPSILON);
assertEquals(" LaunchLug CM has the wrong value: ", 0.008331504, CG.weight, EPSILON);
@@ -102,7 +103,7 @@ public class LaunchLugTest extends BaseTestCase {
CG = lug.getCG();
assertEquals(" LaunchLug CG has the wrong x value: ", 0.025, CG.x, EPSILON);
- assertEquals(" LaunchLug CG has the wrong y value: ", 0.015, CG.y, EPSILON);
+ assertEquals(" LaunchLug CG has the wrong y value: ", 0.04, CG.y, EPSILON);
assertEquals(" LaunchLug CG has the wrong z value: ", 0, CG.z, EPSILON);
assertEquals(" LaunchLug CM has the wrong value: ", 0.00309761, CG.weight, EPSILON);
@@ -111,20 +112,21 @@ public class LaunchLugTest extends BaseTestCase {
CG = lug.getCG();
assertEquals(" LaunchLug CG has the wrong x value: ", 0.025, CG.x, EPSILON);
assertEquals(" LaunchLug CG has the wrong y value: ", 0, CG.y, EPSILON);
- assertEquals(" LaunchLug CG has the wrong z value: ", 0.015, CG.z, EPSILON);
+ assertEquals(" LaunchLug CG has the wrong z value: ", 0.04, CG.z, EPSILON);
assertEquals(" LaunchLug CM has the wrong value: ", 0.00309761, CG.weight, EPSILON);
lug.setAngleOffset(-Math.PI / 3);
CG = lug.getCG();
assertEquals(" LaunchLug CG has the wrong x value: ", 0.025, CG.x, EPSILON);
- assertEquals(" LaunchLug CG has the wrong y value: ", 0.0075, CG.y, EPSILON);
- assertEquals(" LaunchLug CG has the wrong z value: ", -0.01299038, CG.z, EPSILON);
+ assertEquals(" LaunchLug CG has the wrong y value: ", 0.02, CG.y, EPSILON);
+ assertEquals(" LaunchLug CG has the wrong z value: ", -0.034641016, CG.z, EPSILON);
assertEquals(" LaunchLug CM has the wrong value: ", 0.00309761, CG.weight, EPSILON);
}
@Test
public void testCMSingleInstanceOverride() {
BodyTube bodyTube = new BodyTube();
+ bodyTube.setOuterRadius(0.025);
LaunchLug lug = new LaunchLug();
lug.setLength(0.1);
lug.setOuterRadius(0.02);
@@ -135,7 +137,7 @@ public class LaunchLugTest extends BaseTestCase {
// Test normal CG
Coordinate CG = lug.getCG();
assertEquals(" LaunchLug CG has the wrong x value: ", 0.0123, CG.x, EPSILON);
- assertEquals(" LaunchLug CG has the wrong y value: ", -0.02, CG.y, EPSILON);
+ assertEquals(" LaunchLug CG has the wrong y value: ", -0.045, CG.y, EPSILON);
assertEquals(" LaunchLug CG has the wrong z value: ", 0, CG.z, EPSILON);
assertEquals(" LaunchLug CM has the wrong value: ", 0.008331504, CG.weight, EPSILON);
@@ -144,14 +146,14 @@ public class LaunchLugTest extends BaseTestCase {
CG = lug.getCG();
assertEquals(" LaunchLug CG has the wrong x value: ", 0.0123, CG.x, EPSILON);
assertEquals(" LaunchLug CG has the wrong y value: ", 0, CG.y, EPSILON);
- assertEquals(" LaunchLug CG has the wrong z value: ", 0.02, CG.z, EPSILON);
+ assertEquals(" LaunchLug CG has the wrong z value: ", 0.045, CG.z, EPSILON);
assertEquals(" LaunchLug CM has the wrong value: ", 0.008331504, CG.weight, EPSILON);
lug.setAngleOffset(-Math.PI / 3);
CG = lug.getCG();
assertEquals(" LaunchLug CG has the wrong x value: ", 0.0123, CG.x, EPSILON);
- assertEquals(" LaunchLug CG has the wrong y value: ", 0.01, CG.y, EPSILON);
- assertEquals(" LaunchLug CG has the wrong z value: ", -0.0173205, CG.z, EPSILON);
+ assertEquals(" LaunchLug CG has the wrong y value: ", 0.0225, CG.y, EPSILON);
+ assertEquals(" LaunchLug CG has the wrong z value: ", -0.03897114, CG.z, EPSILON);
assertEquals(" LaunchLug CM has the wrong value: ", 0.008331504, CG.weight, EPSILON);
@@ -165,7 +167,7 @@ public class LaunchLugTest extends BaseTestCase {
CG = lug.getCG();
assertEquals(" LaunchLug CG has the wrong x value: ", 0.0321, CG.x, EPSILON);
- assertEquals(" LaunchLug CG has the wrong y value: ", 0.015, CG.y, EPSILON);
+ assertEquals(" LaunchLug CG has the wrong y value: ", 0.04, CG.y, EPSILON);
assertEquals(" LaunchLug CG has the wrong z value: ", 0, CG.z, EPSILON);
assertEquals(" LaunchLug CM has the wrong value: ", 0.1, CG.weight, EPSILON);
@@ -174,20 +176,21 @@ public class LaunchLugTest extends BaseTestCase {
CG = lug.getCG();
assertEquals(" LaunchLug CG has the wrong x value: ", 0.0321, CG.x, EPSILON);
assertEquals(" LaunchLug CG has the wrong y value: ", 0, CG.y, EPSILON);
- assertEquals(" LaunchLug CG has the wrong z value: ", 0.015, CG.z, EPSILON);
+ assertEquals(" LaunchLug CG has the wrong z value: ", 0.04, CG.z, EPSILON);
assertEquals(" LaunchLug CM has the wrong value: ", 0.1, CG.weight, EPSILON);
lug.setAngleOffset(-Math.PI / 3);
CG = lug.getCG();
assertEquals(" LaunchLug CG has the wrong x value: ", 0.0321, CG.x, EPSILON);
- assertEquals(" LaunchLug CG has the wrong y value: ", 0.0075, CG.y, EPSILON);
- assertEquals(" LaunchLug CG has the wrong z value: ", -0.01299038, CG.z, EPSILON);
+ assertEquals(" LaunchLug CG has the wrong y value: ", 0.02, CG.y, EPSILON);
+ assertEquals(" LaunchLug CG has the wrong z value: ", -0.034641016, CG.z, EPSILON);
assertEquals(" LaunchLug CM has the wrong value: ", 0.1, CG.weight, EPSILON);
}
@Test
public void testCMMultipleInstances() {
BodyTube bodyTube = new BodyTube();
+ bodyTube.setOuterRadius(0.025);
LaunchLug lug = new LaunchLug();
lug.setLength(0.1);
lug.setOuterRadius(0.02);
@@ -198,7 +201,7 @@ public class LaunchLugTest extends BaseTestCase {
// Test normal CG
Coordinate CG = lug.getCG();
assertEquals(" LaunchLug CG has the wrong x value: ", 0.25, CG.x, EPSILON);
- assertEquals(" LaunchLug CG has the wrong y value: ", -0.02, CG.y, EPSILON);
+ assertEquals(" LaunchLug CG has the wrong y value: ", -0.045, CG.y, EPSILON);
assertEquals(" LaunchLug CG has the wrong z value: ", 0, CG.z, EPSILON);
assertEquals(" LaunchLug CM has the wrong value: ", 0.024994512, CG.weight, EPSILON);
@@ -207,14 +210,14 @@ public class LaunchLugTest extends BaseTestCase {
CG = lug.getCG();
assertEquals(" LaunchLug CG has the wrong x value: ", 0.25, CG.x, EPSILON);
assertEquals(" LaunchLug CG has the wrong y value: ", 0, CG.y, EPSILON);
- assertEquals(" LaunchLug CG has the wrong z value: ", 0.02, CG.z, EPSILON);
+ assertEquals(" LaunchLug CG has the wrong z value: ", 0.045, CG.z, EPSILON);
assertEquals(" LaunchLug CM has the wrong value: ", 0.024994512, CG.weight, EPSILON);
lug.setAngleOffset(-Math.PI / 3);
CG = lug.getCG();
assertEquals(" LaunchLug CG has the wrong x value: ", 0.25, CG.x, EPSILON);
- assertEquals(" LaunchLug CG has the wrong y value: ", 0.01, CG.y, EPSILON);
- assertEquals(" LaunchLug CG has the wrong z value: ", -0.0173205, CG.z, EPSILON);
+ assertEquals(" LaunchLug CG has the wrong y value: ", 0.0225, CG.y, EPSILON);
+ assertEquals(" LaunchLug CG has the wrong z value: ", -0.03897114, CG.z, EPSILON);
assertEquals(" LaunchLug CM has the wrong value: ", 0.024994512, CG.weight, EPSILON);
@@ -227,7 +230,7 @@ public class LaunchLugTest extends BaseTestCase {
CG = lug.getCG();
assertEquals(" LaunchLug CG has the wrong x value: ", 0.1, CG.x, EPSILON);
- assertEquals(" LaunchLug CG has the wrong y value: ", 0.015, CG.y, EPSILON);
+ assertEquals(" LaunchLug CG has the wrong y value: ", 0.04, CG.y, EPSILON);
assertEquals(" LaunchLug CG has the wrong z value: ", 0, CG.z, EPSILON);
assertEquals(" LaunchLug CM has the wrong value: ", 0.00619522, CG.weight, EPSILON);
@@ -236,20 +239,21 @@ public class LaunchLugTest extends BaseTestCase {
CG = lug.getCG();
assertEquals(" LaunchLug CG has the wrong x value: ", 0.1, CG.x, EPSILON);
assertEquals(" LaunchLug CG has the wrong y value: ", 0, CG.y, EPSILON);
- assertEquals(" LaunchLug CG has the wrong z value: ", 0.015, CG.z, EPSILON);
+ assertEquals(" LaunchLug CG has the wrong z value: ", 0.04, CG.z, EPSILON);
assertEquals(" LaunchLug CM has the wrong value: ", 0.00619522, CG.weight, EPSILON);
lug.setAngleOffset(-Math.PI / 3);
CG = lug.getCG();
assertEquals(" LaunchLug CG has the wrong x value: ", 0.1, CG.x, EPSILON);
- assertEquals(" LaunchLug CG has the wrong y value: ", 0.0075, CG.y, EPSILON);
- assertEquals(" LaunchLug CG has the wrong z value: ", -0.01299038, CG.z, EPSILON);
+ assertEquals(" LaunchLug CG has the wrong y value: ", 0.02, CG.y, EPSILON);
+ assertEquals(" LaunchLug CG has the wrong z value: ", -0.034641016, CG.z, EPSILON);
assertEquals(" LaunchLug CM has the wrong value: ", 0.00619522, CG.weight, EPSILON);
}
@Test
public void testCMMultipleInstancesOverride() {
BodyTube bodyTube = new BodyTube();
+ bodyTube.setOuterRadius(0.025);
LaunchLug lug = new LaunchLug();
lug.setLength(0.1);
lug.setOuterRadius(0.02);
@@ -262,7 +266,7 @@ public class LaunchLugTest extends BaseTestCase {
// Test normal CG
Coordinate CG = lug.getCG();
assertEquals(" LaunchLug CG has the wrong x value: ", 0.0123, CG.x, EPSILON);
- assertEquals(" LaunchLug CG has the wrong y value: ", -0.02, CG.y, EPSILON);
+ assertEquals(" LaunchLug CG has the wrong y value: ", -0.045, CG.y, EPSILON);
assertEquals(" LaunchLug CG has the wrong z value: ", 0, CG.z, EPSILON);
assertEquals(" LaunchLug CM has the wrong value: ", 0.024994512, CG.weight, EPSILON);
@@ -271,14 +275,14 @@ public class LaunchLugTest extends BaseTestCase {
CG = lug.getCG();
assertEquals(" LaunchLug CG has the wrong x value: ", 0.0123, CG.x, EPSILON);
assertEquals(" LaunchLug CG has the wrong y value: ", 0, CG.y, EPSILON);
- assertEquals(" LaunchLug CG has the wrong z value: ", 0.02, CG.z, EPSILON);
+ assertEquals(" LaunchLug CG has the wrong z value: ", 0.045, CG.z, EPSILON);
assertEquals(" LaunchLug CM has the wrong value: ", 0.024994512, CG.weight, EPSILON);
lug.setAngleOffset(-Math.PI / 3);
CG = lug.getCG();
assertEquals(" LaunchLug CG has the wrong x value: ", 0.0123, CG.x, EPSILON);
- assertEquals(" LaunchLug CG has the wrong y value: ", 0.01, CG.y, EPSILON);
- assertEquals(" LaunchLug CG has the wrong z value: ", -0.0173205, CG.z, EPSILON);
+ assertEquals(" LaunchLug CG has the wrong y value: ", 0.0225, CG.y, EPSILON);
+ assertEquals(" LaunchLug CG has the wrong z value: ", -0.03897114, CG.z, EPSILON);
assertEquals(" LaunchLug CM has the wrong value: ", 0.024994512, CG.weight, EPSILON);
@@ -294,7 +298,7 @@ public class LaunchLugTest extends BaseTestCase {
CG = lug.getCG();
assertEquals(" LaunchLug CG has the wrong x value: ", 0.0321, CG.x, EPSILON);
- assertEquals(" LaunchLug CG has the wrong y value: ", 0.015, CG.y, EPSILON);
+ assertEquals(" LaunchLug CG has the wrong y value: ", 0.04, CG.y, EPSILON);
assertEquals(" LaunchLug CG has the wrong z value: ", 0, CG.z, EPSILON);
assertEquals(" LaunchLug CM has the wrong value: ", 0.2, CG.weight, EPSILON);
@@ -303,14 +307,14 @@ public class LaunchLugTest extends BaseTestCase {
CG = lug.getCG();
assertEquals(" LaunchLug CG has the wrong x value: ", 0.0321, CG.x, EPSILON);
assertEquals(" LaunchLug CG has the wrong y value: ", 0, CG.y, EPSILON);
- assertEquals(" LaunchLug CG has the wrong z value: ", 0.015, CG.z, EPSILON);
+ assertEquals(" LaunchLug CG has the wrong z value: ", 0.04, CG.z, EPSILON);
assertEquals(" LaunchLug CM has the wrong value: ", 0.2, CG.weight, EPSILON);
lug.setAngleOffset(-Math.PI / 3);
CG = lug.getCG();
assertEquals(" LaunchLug CG has the wrong x value: ", 0.0321, CG.x, EPSILON);
- assertEquals(" LaunchLug CG has the wrong y value: ", 0.0075, CG.y, EPSILON);
- assertEquals(" LaunchLug CG has the wrong z value: ", -0.01299038, CG.z, EPSILON);
+ assertEquals(" LaunchLug CG has the wrong y value: ", 0.02, CG.y, EPSILON);
+ assertEquals(" LaunchLug CG has the wrong z value: ", -0.034641016, CG.z, EPSILON);
assertEquals(" LaunchLug CM has the wrong value: ", 0.2, CG.weight, EPSILON);
}
diff --git a/core/test/net/sf/openrocket/rocketcomponent/RailButtonTest.java b/core/test/net/sf/openrocket/rocketcomponent/RailButtonTest.java
index 985299e38..6790b6497 100644
--- a/core/test/net/sf/openrocket/rocketcomponent/RailButtonTest.java
+++ b/core/test/net/sf/openrocket/rocketcomponent/RailButtonTest.java
@@ -13,6 +13,7 @@ public class RailButtonTest extends BaseTestCase {
@Test
public void testCMSingleInstance() {
BodyTube bodyTube = new BodyTube();
+ bodyTube.setOuterRadius(0.025);
RailButton button = new RailButton();
button.setOuterDiameter(0.05);
button.setTotalHeight(0.05);
@@ -21,7 +22,7 @@ public class RailButtonTest extends BaseTestCase {
// Test normal CG
Coordinate CG = button.getCG();
assertEquals(" RailButton CG has the wrong x value: ", 0, CG.x, EPSILON);
- assertEquals(" RailButton CG has the wrong y value: ", -0.025, CG.y, EPSILON);
+ assertEquals(" RailButton CG has the wrong y value: ", -0.05, CG.y, EPSILON);
assertEquals(" RailButton CG has the wrong z value: ", 0, CG.z, EPSILON);
assertEquals(" RailButton CM has the wrong value: ", 0.014435995, CG.weight, EPSILON);
@@ -30,14 +31,14 @@ public class RailButtonTest extends BaseTestCase {
CG = button.getCG();
assertEquals(" RailButton CG has the wrong x value: ", 0, CG.x, EPSILON);
assertEquals(" RailButton CG has the wrong y value: ", 0, CG.y, EPSILON);
- assertEquals(" RailButton CG has the wrong z value: ", 0.025, CG.z, EPSILON);
+ assertEquals(" RailButton CG has the wrong z value: ", 0.05, CG.z, EPSILON);
assertEquals(" RailButton CM has the wrong value: ", 0.014435995, CG.weight, EPSILON);
button.setAngleOffset(-Math.PI / 3);
CG = button.getCG();
assertEquals(" RailButton CG has the wrong x value: ", 0, CG.x, EPSILON);
- assertEquals(" RailButton CG has the wrong y value: ", 0.0125, CG.y, EPSILON);
- assertEquals(" RailButton CG has the wrong z value: ", -0.02165064, CG.z, EPSILON);
+ assertEquals(" RailButton CG has the wrong y value: ", 0.025, CG.y, EPSILON);
+ assertEquals(" RailButton CG has the wrong z value: ", -0.04330127, CG.z, EPSILON);
assertEquals(" RailButton CM has the wrong value: ", 0.014435995, CG.weight, EPSILON);
@@ -48,7 +49,7 @@ public class RailButtonTest extends BaseTestCase {
CG = button.getCG();
assertEquals(" RailButton CG has the wrong x value: ", 0, CG.x, EPSILON);
- assertEquals(" RailButton CG has the wrong y value: ", 0.01, CG.y, EPSILON);
+ assertEquals(" RailButton CG has the wrong y value: ", 0.035, CG.y, EPSILON);
assertEquals(" RailButton CG has the wrong z value: ", 0, CG.z, EPSILON);
assertEquals(" RailButton CM has the wrong value: ", 0.003930195, CG.weight, EPSILON);
@@ -57,20 +58,21 @@ public class RailButtonTest extends BaseTestCase {
CG = button.getCG();
assertEquals(" RailButton CG has the wrong x value: ", 0, CG.x, EPSILON);
assertEquals(" RailButton CG has the wrong y value: ", 0, CG.y, EPSILON);
- assertEquals(" RailButton CG has the wrong z value: ", 0.01, CG.z, EPSILON);
+ assertEquals(" RailButton CG has the wrong z value: ", 0.035, CG.z, EPSILON);
assertEquals(" RailButton CM has the wrong value: ", 0.003930195, CG.weight, EPSILON);
button.setAngleOffset(-Math.PI / 3);
CG = button.getCG();
assertEquals(" RailButton CG has the wrong x value: ", 0, CG.x, EPSILON);
- assertEquals(" RailButton CG has the wrong y value: ", 0.005, CG.y, EPSILON);
- assertEquals(" RailButton CG has the wrong z value: ", -0.00866025, CG.z, EPSILON);
+ assertEquals(" RailButton CG has the wrong y value: ", 0.0175, CG.y, EPSILON);
+ assertEquals(" RailButton CG has the wrong z value: ", -0.03031089, CG.z, EPSILON);
assertEquals(" RailButton CM has the wrong value: ", 0.003930195, CG.weight, EPSILON);
}
@Test
public void testCMSingleInstanceOverride() {
BodyTube bodyTube = new BodyTube();
+ bodyTube.setOuterRadius(0.025);
RailButton button = new RailButton();
button.setOuterDiameter(0.05);
button.setTotalHeight(0.05);
@@ -81,7 +83,7 @@ public class RailButtonTest extends BaseTestCase {
// Test normal CG
Coordinate CG = button.getCG();
assertEquals(" RailButton CG has the wrong x value: ", 0.0123, CG.x, EPSILON);
- assertEquals(" RailButton CG has the wrong y value: ", -0.025, CG.y, EPSILON);
+ assertEquals(" RailButton CG has the wrong y value: ", -0.05, CG.y, EPSILON);
assertEquals(" RailButton CG has the wrong z value: ", 0, CG.z, EPSILON);
assertEquals(" RailButton CM has the wrong value: ", 0.014435995, CG.weight, EPSILON);
@@ -90,14 +92,14 @@ public class RailButtonTest extends BaseTestCase {
CG = button.getCG();
assertEquals(" RailButton CG has the wrong x value: ", 0.0123, CG.x, EPSILON);
assertEquals(" RailButton CG has the wrong y value: ", 0, CG.y, EPSILON);
- assertEquals(" RailButton CG has the wrong z value: ", 0.025, CG.z, EPSILON);
+ assertEquals(" RailButton CG has the wrong z value: ", 0.05, CG.z, EPSILON);
assertEquals(" RailButton CM has the wrong value: ", 0.014435995, CG.weight, EPSILON);
button.setAngleOffset(-Math.PI / 3);
CG = button.getCG();
assertEquals(" RailButton CG has the wrong x value: ", 0.0123, CG.x, EPSILON);
- assertEquals(" RailButton CG has the wrong y value: ", 0.0125, CG.y, EPSILON);
- assertEquals(" RailButton CG has the wrong z value: ", -0.02165064, CG.z, EPSILON);
+ assertEquals(" RailButton CG has the wrong y value: ", 0.025, CG.y, EPSILON);
+ assertEquals(" RailButton CG has the wrong z value: ", -0.04330127, CG.z, EPSILON);
assertEquals(" RailButton CM has the wrong value: ", 0.014435995, CG.weight, EPSILON);
@@ -111,7 +113,7 @@ public class RailButtonTest extends BaseTestCase {
CG = button.getCG();
assertEquals(" RailButton CG has the wrong x value: ", 0.0321, CG.x, EPSILON);
- assertEquals(" RailButton CG has the wrong y value: ", 0.01, CG.y, EPSILON);
+ assertEquals(" RailButton CG has the wrong y value: ", 0.035, CG.y, EPSILON);
assertEquals(" RailButton CG has the wrong z value: ", 0, CG.z, EPSILON);
assertEquals(" RailButton CM has the wrong value: ", 0.1, CG.weight, EPSILON);
@@ -120,20 +122,21 @@ public class RailButtonTest extends BaseTestCase {
CG = button.getCG();
assertEquals(" RailButton CG has the wrong x value: ", 0.0321, CG.x, EPSILON);
assertEquals(" RailButton CG has the wrong y value: ", 0, CG.y, EPSILON);
- assertEquals(" RailButton CG has the wrong z value: ", 0.01, CG.z, EPSILON);
+ assertEquals(" RailButton CG has the wrong z value: ", 0.035, CG.z, EPSILON);
assertEquals(" RailButton CM has the wrong value: ", 0.1, CG.weight, EPSILON);
button.setAngleOffset(-Math.PI / 3);
CG = button.getCG();
assertEquals(" RailButton CG has the wrong x value: ", 0.0321, CG.x, EPSILON);
- assertEquals(" RailButton CG has the wrong y value: ", 0.005, CG.y, EPSILON);
- assertEquals(" RailButton CG has the wrong z value: ", -0.00866025, CG.z, EPSILON);
+ assertEquals(" RailButton CG has the wrong y value: ", 0.0175, CG.y, EPSILON);
+ assertEquals(" RailButton CG has the wrong z value: ", -0.03031089, CG.z, EPSILON);
assertEquals(" RailButton CM has the wrong value: ", 0.1, CG.weight, EPSILON);
}
@Test
public void testCMMultipleInstances() {
BodyTube bodyTube = new BodyTube();
+ bodyTube.setOuterRadius(0.025);
RailButton button = new RailButton();
button.setOuterDiameter(0.05);
button.setTotalHeight(0.05);
@@ -144,7 +147,7 @@ public class RailButtonTest extends BaseTestCase {
// Test normal CG
Coordinate CG = button.getCG();
assertEquals(" RailButton CG has the wrong x value: ", 0.2, CG.x, EPSILON);
- assertEquals(" RailButton CG has the wrong y value: ", -0.025, CG.y, EPSILON);
+ assertEquals(" RailButton CG has the wrong y value: ", -0.05, CG.y, EPSILON);
assertEquals(" RailButton CG has the wrong z value: ", 0, CG.z, EPSILON);
assertEquals(" RailButton CM has the wrong value: ", 0.043307985, CG.weight, EPSILON);
@@ -153,14 +156,14 @@ public class RailButtonTest extends BaseTestCase {
CG = button.getCG();
assertEquals(" RailButton CG has the wrong x value: ", 0.2, CG.x, EPSILON);
assertEquals(" RailButton CG has the wrong y value: ", 0, CG.y, EPSILON);
- assertEquals(" RailButton CG has the wrong z value: ", 0.025, CG.z, EPSILON);
+ assertEquals(" RailButton CG has the wrong z value: ", 0.05, CG.z, EPSILON);
assertEquals(" RailButton CM has the wrong value: ", 0.043307985, CG.weight, EPSILON);
button.setAngleOffset(-Math.PI / 3);
CG = button.getCG();
assertEquals(" RailButton CG has the wrong x value: ", 0.2, CG.x, EPSILON);
- assertEquals(" RailButton CG has the wrong y value: ", 0.0125, CG.y, EPSILON);
- assertEquals(" RailButton CG has the wrong z value: ", -0.02165064, CG.z, EPSILON);
+ assertEquals(" RailButton CG has the wrong y value: ", 0.025, CG.y, EPSILON);
+ assertEquals(" RailButton CG has the wrong z value: ", -0.04330127, CG.z, EPSILON);
assertEquals(" RailButton CM has the wrong value: ", 0.043307985, CG.weight, EPSILON);
@@ -173,7 +176,7 @@ public class RailButtonTest extends BaseTestCase {
CG = button.getCG();
assertEquals(" RailButton CG has the wrong x value: ", 0.075, CG.x, EPSILON);
- assertEquals(" RailButton CG has the wrong y value: ", 0.01, CG.y, EPSILON);
+ assertEquals(" RailButton CG has the wrong y value: ", 0.035, CG.y, EPSILON);
assertEquals(" RailButton CG has the wrong z value: ", 0, CG.z, EPSILON);
assertEquals(" RailButton CM has the wrong value: ", 0.00786039, CG.weight, EPSILON);
@@ -182,20 +185,21 @@ public class RailButtonTest extends BaseTestCase {
CG = button.getCG();
assertEquals(" RailButton CG has the wrong x value: ", 0.075, CG.x, EPSILON);
assertEquals(" RailButton CG has the wrong y value: ", 0, CG.y, EPSILON);
- assertEquals(" RailButton CG has the wrong z value: ", 0.01, CG.z, EPSILON);
+ assertEquals(" RailButton CG has the wrong z value: ", 0.035, CG.z, EPSILON);
assertEquals(" RailButton CM has the wrong value: ", 0.00786039, CG.weight, EPSILON);
button.setAngleOffset(-Math.PI / 3);
CG = button.getCG();
assertEquals(" RailButton CG has the wrong x value: ", 0.075, CG.x, EPSILON);
- assertEquals(" RailButton CG has the wrong y value: ", 0.005, CG.y, EPSILON);
- assertEquals(" RailButton CG has the wrong z value: ", -0.00866025, CG.z, EPSILON);
+ assertEquals(" RailButton CG has the wrong y value: ", 0.0175, CG.y, EPSILON);
+ assertEquals(" RailButton CG has the wrong z value: ", -0.03031089, CG.z, EPSILON);
assertEquals(" RailButton CM has the wrong value: ", 0.00786039, CG.weight, EPSILON);
}
@Test
public void testCMMultipleInstancesOverride() {
BodyTube bodyTube = new BodyTube();
+ bodyTube.setOuterRadius(0.025);
RailButton button = new RailButton();
button.setOuterDiameter(0.05);
button.setTotalHeight(0.05);
@@ -208,7 +212,7 @@ public class RailButtonTest extends BaseTestCase {
// Test normal CG
Coordinate CG = button.getCG();
assertEquals(" RailButton CG has the wrong x value: ", 0.0123, CG.x, EPSILON);
- assertEquals(" RailButton CG has the wrong y value: ", -0.025, CG.y, EPSILON);
+ assertEquals(" RailButton CG has the wrong y value: ", -0.05, CG.y, EPSILON);
assertEquals(" RailButton CG has the wrong z value: ", 0, CG.z, EPSILON);
assertEquals(" RailButton CM has the wrong value: ", 0.043307985, CG.weight, EPSILON);
@@ -217,14 +221,14 @@ public class RailButtonTest extends BaseTestCase {
CG = button.getCG();
assertEquals(" RailButton CG has the wrong x value: ", 0.0123, CG.x, EPSILON);
assertEquals(" RailButton CG has the wrong y value: ", 0, CG.y, EPSILON);
- assertEquals(" RailButton CG has the wrong z value: ", 0.025, CG.z, EPSILON);
+ assertEquals(" RailButton CG has the wrong z value: ", 0.05, CG.z, EPSILON);
assertEquals(" RailButton CM has the wrong value: ", 0.043307985, CG.weight, EPSILON);
button.setAngleOffset(-Math.PI / 3);
CG = button.getCG();
assertEquals(" RailButton CG has the wrong x value: ", 0.0123, CG.x, EPSILON);
- assertEquals(" RailButton CG has the wrong y value: ", 0.0125, CG.y, EPSILON);
- assertEquals(" RailButton CG has the wrong z value: ", -0.02165064, CG.z, EPSILON);
+ assertEquals(" RailButton CG has the wrong y value: ", 0.025, CG.y, EPSILON);
+ assertEquals(" RailButton CG has the wrong z value: ", -0.04330127, CG.z, EPSILON);
assertEquals(" RailButton CM has the wrong value: ", 0.043307985, CG.weight, EPSILON);
@@ -240,7 +244,7 @@ public class RailButtonTest extends BaseTestCase {
CG = button.getCG();
assertEquals(" RailButton CG has the wrong x value: ", 0.0321, CG.x, EPSILON);
- assertEquals(" RailButton CG has the wrong y value: ", 0.01, CG.y, EPSILON);
+ assertEquals(" RailButton CG has the wrong y value: ", 0.035, CG.y, EPSILON);
assertEquals(" RailButton CG has the wrong z value: ", 0, CG.z, EPSILON);
assertEquals(" RailButton CM has the wrong value: ", 0.2, CG.weight, EPSILON);
@@ -249,14 +253,14 @@ public class RailButtonTest extends BaseTestCase {
CG = button.getCG();
assertEquals(" RailButton CG has the wrong x value: ", 0.0321, CG.x, EPSILON);
assertEquals(" RailButton CG has the wrong y value: ", 0, CG.y, EPSILON);
- assertEquals(" RailButton CG has the wrong z value: ", 0.01, CG.z, EPSILON);
+ assertEquals(" RailButton CG has the wrong z value: ", 0.035, CG.z, EPSILON);
assertEquals(" RailButton CM has the wrong value: ", 0.2, CG.weight, EPSILON);
button.setAngleOffset(-Math.PI / 3);
CG = button.getCG();
assertEquals(" RailButton CG has the wrong x value: ", 0.0321, CG.x, EPSILON);
- assertEquals(" RailButton CG has the wrong y value: ", 0.005, CG.y, EPSILON);
- assertEquals(" RailButton CG has the wrong z value: ", -0.00866025, CG.z, EPSILON);
+ assertEquals(" RailButton CG has the wrong y value: ", 0.0175, CG.y, EPSILON);
+ assertEquals(" RailButton CG has the wrong z value: ", -0.03031089, CG.z, EPSILON);
assertEquals(" RailButton CM has the wrong value: ", 0.2, CG.weight, EPSILON);
}
diff --git a/core/test/net/sf/openrocket/rocketcomponent/TrapezoidFinSetTest.java b/core/test/net/sf/openrocket/rocketcomponent/TrapezoidFinSetTest.java
index cab506755..d047b2eff 100644
--- a/core/test/net/sf/openrocket/rocketcomponent/TrapezoidFinSetTest.java
+++ b/core/test/net/sf/openrocket/rocketcomponent/TrapezoidFinSetTest.java
@@ -52,6 +52,32 @@ public class TrapezoidFinSetTest extends BaseTestCase {
return rkt;
}
+ private Rocket createFreeformFinOnTransition() {
+ final Rocket rkt = new Rocket();
+ final AxialStage stg = new AxialStage();
+ rkt.addChild(stg);
+ Transition transition = new Transition();
+ transition.setLength(0.2);
+ transition.setForeRadius(0.1);
+ transition.setAftRadius(0.3);
+ transition.setShapeType(Transition.Shape.OGIVE);
+ stg.addChild(transition);
+ FreeformFinSet fins = new FreeformFinSet();
+ fins.setFinCount(1);
+ fins.setAxialOffset(AxialMethod.MIDDLE, 0.0);
+ fins.setMaterial(Material.newMaterial(Material.Type.BULK, "Fin-Test-Material", 1.0, true));
+ fins.setThickness(0.005); // == 5 mm
+
+ transition.addChild(fins);
+
+ fins.setTabLength(0.00);
+
+ fins.setFilletRadius(0.0);
+
+ rkt.enableEvents();
+ return rkt;
+ }
+
@Test
public void testMultiplicity() {
final TrapezoidFinSet trapFins = new TrapezoidFinSet();
@@ -187,6 +213,33 @@ public class TrapezoidFinSetTest extends BaseTestCase {
}
}
+ @Test
+ public void testFilletCalculationsOnTransition() {
+ final Rocket rkt = createFreeformFinOnTransition();
+ Transition transition = (Transition) rkt.getChild(0).getChild(0);
+ FinSet fins = (FinSet) rkt.getChild(0).getChild(0).getChild(0);
+
+ fins.setFilletRadius(0.005);
+ fins.setFilletMaterial(Material.newMaterial(Material.Type.BULK, "Fillet-Test-Material", 1.0, true));
+
+ // used for fillet and edge calculations:
+ //
+ // [1] +--+ [2]
+ // / \
+ // / \
+ // [0] +--------+ [3]
+ //
+ assertEquals(0.05, fins.getLength(), EPSILON);
+ assertEquals("Transition fore radius doesn't match: ", 0.1, transition.getForeRadius(), EPSILON);
+ assertEquals("Transition aft radius doesn't match: ", 0.3, transition.getAftRadius(), EPSILON);
+
+ final Coordinate actVolume = fins.calculateFilletVolumeCentroid();
+
+ assertEquals("Fin volume doesn't match: ", 5.973e-07, actVolume.weight, EPSILON);
+ assertEquals("Fin mass center.x doesn't match: ", 0.024393025, actVolume.x, EPSILON);
+ assertEquals("Fin mass center.y doesn't match: ", 0.190479957, actVolume.y, EPSILON);
+ }
+
@Test
public void testTrapezoidCGComputation() {
{
diff --git a/install4j/22.02/.gitignore b/install4j/23.xx/.gitignore
similarity index 86%
rename from install4j/22.02/.gitignore
rename to install4j/23.xx/.gitignore
index e5a57839b..60eadae4b 100644
--- a/install4j/22.02/.gitignore
+++ b/install4j/23.xx/.gitignore
@@ -20,4 +20,3 @@ media/
.DS_Store
code_signing/
-openrocket-22.xx.install4j~
diff --git a/install4j/22.02/macOS_resources/DS_Store b/install4j/23.xx/macOS_resources/DS_Store
similarity index 100%
rename from install4j/22.02/macOS_resources/DS_Store
rename to install4j/23.xx/macOS_resources/DS_Store
diff --git a/install4j/22.02/macOS_resources/macOS_installer_background.png b/install4j/23.xx/macOS_resources/macOS_installer_background.png
similarity index 100%
rename from install4j/22.02/macOS_resources/macOS_installer_background.png
rename to install4j/23.xx/macOS_resources/macOS_installer_background.png
diff --git a/install4j/22.02/macOS_resources/macOS_installer_background.psd b/install4j/23.xx/macOS_resources/macOS_installer_background.psd
similarity index 100%
rename from install4j/22.02/macOS_resources/macOS_installer_background.psd
rename to install4j/23.xx/macOS_resources/macOS_installer_background.psd
diff --git a/install4j/22.02/openrocket-22.02.install4j b/install4j/23.xx/openrocket-23.xx.install4j
similarity index 99%
rename from install4j/22.02/openrocket-22.02.install4j
rename to install4j/23.xx/openrocket-23.xx.install4j
index f3b51e829..10a55f19a 100644
--- a/install4j/22.02/openrocket-22.02.install4j
+++ b/install4j/23.xx/openrocket-23.xx.install4j
@@ -1,9 +1,9 @@
-
+
-
+
@@ -19,7 +19,7 @@
-
+
diff --git a/swing/lib/jogl/gluegen-rt-natives-linux-aarch64.jar b/swing/lib/jogl/gluegen-rt-natives-linux-aarch64.jar
index 82671c461..7ae0b699d 100644
Binary files a/swing/lib/jogl/gluegen-rt-natives-linux-aarch64.jar and b/swing/lib/jogl/gluegen-rt-natives-linux-aarch64.jar differ
diff --git a/swing/lib/jogl/gluegen-rt-natives-linux-amd64.jar b/swing/lib/jogl/gluegen-rt-natives-linux-amd64.jar
index 4a44e284c..599866fee 100644
Binary files a/swing/lib/jogl/gluegen-rt-natives-linux-amd64.jar and b/swing/lib/jogl/gluegen-rt-natives-linux-amd64.jar differ
diff --git a/swing/lib/jogl/gluegen-rt-natives-linux-armv6hf.jar b/swing/lib/jogl/gluegen-rt-natives-linux-armv6hf.jar
index debf9f887..fefb8515e 100644
Binary files a/swing/lib/jogl/gluegen-rt-natives-linux-armv6hf.jar and b/swing/lib/jogl/gluegen-rt-natives-linux-armv6hf.jar differ
diff --git a/swing/lib/jogl/gluegen-rt-natives-linux-i586.jar b/swing/lib/jogl/gluegen-rt-natives-linux-i586.jar
deleted file mode 100644
index 0e71f1359..000000000
Binary files a/swing/lib/jogl/gluegen-rt-natives-linux-i586.jar and /dev/null differ
diff --git a/swing/lib/jogl/gluegen-rt-natives-macosx-universal.jar b/swing/lib/jogl/gluegen-rt-natives-macosx-universal.jar
index 33e73ee5b..ca3fcae95 100644
Binary files a/swing/lib/jogl/gluegen-rt-natives-macosx-universal.jar and b/swing/lib/jogl/gluegen-rt-natives-macosx-universal.jar differ
diff --git a/swing/lib/jogl/gluegen-rt-natives-windows-amd64.jar b/swing/lib/jogl/gluegen-rt-natives-windows-amd64.jar
index ce89c6f00..0101c6ca9 100644
Binary files a/swing/lib/jogl/gluegen-rt-natives-windows-amd64.jar and b/swing/lib/jogl/gluegen-rt-natives-windows-amd64.jar differ
diff --git a/swing/lib/jogl/gluegen-rt-natives-windows-i586.jar b/swing/lib/jogl/gluegen-rt-natives-windows-i586.jar
deleted file mode 100644
index 287412be1..000000000
Binary files a/swing/lib/jogl/gluegen-rt-natives-windows-i586.jar and /dev/null differ
diff --git a/swing/lib/jogl/gluegen-rt.jar b/swing/lib/jogl/gluegen-rt.jar
index d92fbcc59..49c0099c6 100644
Binary files a/swing/lib/jogl/gluegen-rt.jar and b/swing/lib/jogl/gluegen-rt.jar differ
diff --git a/swing/lib/jogl/gluegen.jar b/swing/lib/jogl/gluegen.jar
index b4b743045..54baa8538 100644
Binary files a/swing/lib/jogl/gluegen.jar and b/swing/lib/jogl/gluegen.jar differ
diff --git a/swing/lib/jogl/jogl-all-natives-linux-aarch64.jar b/swing/lib/jogl/jogl-all-natives-linux-aarch64.jar
index a0deef3ad..d5f3adf96 100644
Binary files a/swing/lib/jogl/jogl-all-natives-linux-aarch64.jar and b/swing/lib/jogl/jogl-all-natives-linux-aarch64.jar differ
diff --git a/swing/lib/jogl/jogl-all-natives-linux-amd64.jar b/swing/lib/jogl/jogl-all-natives-linux-amd64.jar
index 388bcb0a4..e79f8eb07 100644
Binary files a/swing/lib/jogl/jogl-all-natives-linux-amd64.jar and b/swing/lib/jogl/jogl-all-natives-linux-amd64.jar differ
diff --git a/swing/lib/jogl/jogl-all-natives-linux-armv6hf.jar b/swing/lib/jogl/jogl-all-natives-linux-armv6hf.jar
index db9c07c8d..8333debef 100644
Binary files a/swing/lib/jogl/jogl-all-natives-linux-armv6hf.jar and b/swing/lib/jogl/jogl-all-natives-linux-armv6hf.jar differ
diff --git a/swing/lib/jogl/jogl-all-natives-linux-i586.jar b/swing/lib/jogl/jogl-all-natives-linux-i586.jar
deleted file mode 100644
index cde6472d9..000000000
Binary files a/swing/lib/jogl/jogl-all-natives-linux-i586.jar and /dev/null differ
diff --git a/swing/lib/jogl/jogl-all-natives-macosx-universal.jar b/swing/lib/jogl/jogl-all-natives-macosx-universal.jar
index 1798a558e..b111e2df7 100644
Binary files a/swing/lib/jogl/jogl-all-natives-macosx-universal.jar and b/swing/lib/jogl/jogl-all-natives-macosx-universal.jar differ
diff --git a/swing/lib/jogl/jogl-all-natives-windows-amd64.jar b/swing/lib/jogl/jogl-all-natives-windows-amd64.jar
index 82c8f3ed0..e05aecfd0 100644
Binary files a/swing/lib/jogl/jogl-all-natives-windows-amd64.jar and b/swing/lib/jogl/jogl-all-natives-windows-amd64.jar differ
diff --git a/swing/lib/jogl/jogl-all-natives-windows-i586.jar b/swing/lib/jogl/jogl-all-natives-windows-i586.jar
deleted file mode 100644
index e500fe9c8..000000000
Binary files a/swing/lib/jogl/jogl-all-natives-windows-i586.jar and /dev/null differ
diff --git a/swing/lib/jogl/jogl-all.jar b/swing/lib/jogl/jogl-all.jar
index 0aba718c0..8011e7f08 100644
Binary files a/swing/lib/jogl/jogl-all.jar and b/swing/lib/jogl/jogl-all.jar differ
diff --git a/swing/src/net/sf/openrocket/gui/components/DescriptionArea.java b/swing/src/net/sf/openrocket/gui/components/DescriptionArea.java
index b60d4f6ad..2c666eff2 100644
--- a/swing/src/net/sf/openrocket/gui/components/DescriptionArea.java
+++ b/swing/src/net/sf/openrocket/gui/components/DescriptionArea.java
@@ -18,6 +18,9 @@ import java.io.FileOutputStream;
import javax.swing.JTextPane;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
+import javax.swing.text.SimpleAttributeSet;
+import javax.swing.text.StyleConstants;
+import javax.swing.text.StyledDocument;
import javax.swing.JEditorPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
@@ -188,6 +191,7 @@ public class DescriptionArea extends JScrollPane {
}
});
+ setForeground(editorPane.getForeground());
editorPane.scrollRectToVisible(new Rectangle(0, 0, 1, 1));
}
@@ -202,5 +206,23 @@ public class DescriptionArea extends JScrollPane {
editorPane.setFont(font);
}
}
+
+ public void setBackground(Color color) {
+ if (editorPane == null) return;
+ editorPane.setBackground(color);
+ StyledDocument styledDocument = (StyledDocument) editorPane.getDocument();
+ SimpleAttributeSet attributeSet = new SimpleAttributeSet();
+ StyleConstants.setForeground(attributeSet, color);
+ styledDocument.setCharacterAttributes(0, styledDocument.getLength(), attributeSet, false);
+ }
+
+ public void setForeground(Color color) {
+ if (editorPane == null) return;
+ editorPane.setForeground(color);
+ StyledDocument styledDocument = (StyledDocument) editorPane.getDocument();
+ SimpleAttributeSet attributeSet = new SimpleAttributeSet();
+ StyleConstants.setForeground(attributeSet, color);
+ styledDocument.setCharacterAttributes(0, styledDocument.getLength(), attributeSet, false);
+ }
}
diff --git a/swing/src/net/sf/openrocket/gui/dialogs/preferences/GeneralPreferencesPanel.java b/swing/src/net/sf/openrocket/gui/dialogs/preferences/GeneralPreferencesPanel.java
index 7cfba5735..4457b9786 100644
--- a/swing/src/net/sf/openrocket/gui/dialogs/preferences/GeneralPreferencesPanel.java
+++ b/swing/src/net/sf/openrocket/gui/dialogs/preferences/GeneralPreferencesPanel.java
@@ -3,6 +3,8 @@ package net.sf.openrocket.gui.dialogs.preferences;
import java.awt.Dialog.ModalityType;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
@@ -40,7 +42,6 @@ import net.sf.openrocket.gui.util.PreferencesExporter;
import net.sf.openrocket.gui.util.PreferencesImporter;
import net.sf.openrocket.l10n.L10N;
import net.sf.openrocket.logging.Markers;
-import net.sf.openrocket.startup.Application;
import net.sf.openrocket.startup.Preferences;
import net.sf.openrocket.util.BuildProperties;
import net.sf.openrocket.util.Named;
@@ -255,6 +256,17 @@ public class GeneralPreferencesPanel extends PreferencesPanel {
});
this.add(rocksimWarningDialogBox,"spanx, wrap");
+ //// Show confirmation dialog when discarding preferences
+ final JCheckBox prefsDiscardBox = new JCheckBox(trans.get("pref.dlg.checkbox.ShowDiscardPreferencesConfirmation"));
+ prefsDiscardBox.setSelected(preferences.isShowDiscardPreferencesConfirmation());
+ prefsDiscardBox.addItemListener(new ItemListener() {
+ @Override
+ public void itemStateChanged(ItemEvent e) {
+ preferences.setShowDiscardPreferencesConfirmation(e.getStateChange() == ItemEvent.SELECTED);
+ }
+ });
+ this.add(prefsDiscardBox,"spanx, wrap");
+
// Preference buttons
JPanel buttonPanel = new JPanel(new MigLayout("fillx, ins 0"));
@@ -315,7 +327,7 @@ public class GeneralPreferencesPanel extends PreferencesPanel {
}
}
});
- buttonPanel.add(resetAllPreferences, "pushx, right, wrap");
+ buttonPanel.add(resetAllPreferences, "pushx, right, gaptop 20lp, wrap");
this.add(buttonPanel, "spanx, growx, pushy, bottom, wrap");
}
diff --git a/swing/src/net/sf/openrocket/gui/dialogs/preferences/PreferencesDialog.java b/swing/src/net/sf/openrocket/gui/dialogs/preferences/PreferencesDialog.java
index 4dadc0f14..4f689507d 100644
--- a/swing/src/net/sf/openrocket/gui/dialogs/preferences/PreferencesDialog.java
+++ b/swing/src/net/sf/openrocket/gui/dialogs/preferences/PreferencesDialog.java
@@ -1,21 +1,31 @@
package net.sf.openrocket.gui.dialogs.preferences;
import java.awt.Dialog;
-import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.prefs.BackingStoreException;
import javax.swing.JButton;
+import javax.swing.JCheckBox;
import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import net.miginfocom.swing.MigLayout;
import net.sf.openrocket.gui.main.BasicFrame;
import net.sf.openrocket.gui.util.GUIUtil;
+import net.sf.openrocket.gui.util.PreferencesExporter;
+import net.sf.openrocket.gui.util.PreferencesImporter;
import net.sf.openrocket.gui.util.SwingPreferences;
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.startup.Application;
@@ -35,6 +45,9 @@ public class PreferencesDialog extends JDialog {
private BasicFrame parentFrame;
+ private boolean storePreferences = true;
+ private File initPrefsFile = null;
+
private PreferencesDialog(BasicFrame parent) {
// // Preferences
super(parent, trans.get("pref.dlg.title.Preferences"),
@@ -42,6 +55,9 @@ public class PreferencesDialog extends JDialog {
this.parentFrame = parent;
+ // First store the initial preferences
+ initPrefsFile = storeInitPreferences();
+
JPanel panel = new JPanel(new MigLayout("fill, gap unrel", "[grow]",
"[grow][]"));
@@ -78,16 +94,42 @@ public class PreferencesDialog extends JDialog {
// tabbedPane.addTab(trans.get("pref.dlg.tab.Colors"),
// new DisplayPreferencesPanel());
- // Close button
- JButton close = new SelectColorButton(trans.get("dlg.but.close"));
- close.addActionListener(new ActionListener() {
+
+ //// Cancel button
+ JButton cancelButton = new SelectColorButton(trans.get("dlg.but.cancel"));
+ cancelButton.setToolTipText(trans.get("SimulationEditDialog.btn.Cancel.ttip"));
+ cancelButton.addActionListener(new ActionListener() {
@Override
- public void actionPerformed(ActionEvent arg0) {
- PreferencesDialog.this.setVisible(false);
- PreferencesDialog.this.dispose();
+ public void actionPerformed(ActionEvent e) {
+ // Apply the cancel operation if set to auto discard in preferences
+ if (!preferences.isShowDiscardPreferencesConfirmation()) {
+ closeDialog(false);
+ return;
+ }
+
+ // Yes/No dialog: Are you sure you want to discard your changes?
+ JPanel msg = createCancelOperationContent();
+ int resultYesNo = JOptionPane.showConfirmDialog(PreferencesDialog.this, msg,
+ trans.get("PreferencesDialog.CancelOperation.title"), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
+ if (resultYesNo == JOptionPane.YES_OPTION) {
+ closeDialog(false);
+ }
}
});
- panel.add(close, "span, right, tag close");
+ panel.add(cancelButton, "span, split 2, right, tag cancel");
+
+ //// Ok button
+ JButton okButton = new SelectColorButton(trans.get("dlg.but.ok"));
+ okButton.setToolTipText(trans.get("SimulationEditDialog.btn.OK.ttip"));
+ okButton.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ closeDialog(true);
+ }
+ });
+ panel.add(okButton, "tag ok");
+
+
this.setContentPane(panel);
pack();
@@ -96,7 +138,22 @@ public class PreferencesDialog extends JDialog {
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosed(WindowEvent e) {
- preferences.storeDefaultUnits();
+ // We don't want to lose the preference for the confirmation dialog
+ boolean isShowDiscardConfirmation = preferences.isShowDiscardPreferencesConfirmation();
+
+ // Reload initial preferences
+ if (!storePreferences) {
+ loadInitPreferences();
+ }
+
+ // Store the preference for showing the confirmation dialog
+ preferences.setShowDiscardPreferencesConfirmation(isShowDiscardConfirmation);
+
+ // Delete the init prefs
+ if (initPrefsFile != null) {
+ initPrefsFile.delete();
+ }
+
// Make sure unit change applies to the rocket figure
if (parent != null) {
parent.getRocketPanel().updateExtras();
@@ -106,13 +163,72 @@ public class PreferencesDialog extends JDialog {
}
});
- GUIUtil.setDisposableDialogOptions(this, close);
+ GUIUtil.setDisposableDialogOptions(this, okButton);
}
public BasicFrame getParentFrame() {
return parentFrame;
}
+ private void closeDialog(boolean storeChanges) {
+ storePreferences = storeChanges;
+ PreferencesDialog.this.setVisible(false);
+ PreferencesDialog.this.dispose();
+ }
+
+ /**
+ * Store the intial preferences in a temporary file, and return that file.
+ * @return the file containing the initial preferences, or null if something went wrong
+ */
+ private File storeInitPreferences() {
+ try {
+ File outputFile = Files.createTempFile("ORInitPrefs_" + System.currentTimeMillis(), ".xml").toFile();
+ try (FileOutputStream outputFos = new FileOutputStream(outputFile)) {
+ PreferencesExporter.exportPreferencesToFile(preferences.getPreferences(), outputFos, false);
+ log.debug("Initial preferences stored in temporary file: " + outputFile.getAbsolutePath());
+ } catch (BackingStoreException e) {
+ log.error("Could not store initial preferences", e);
+ return null;
+ }
+ return outputFile;
+ } catch (IOException e) {
+ log.error("Could not create temporary preferences file", e);
+ return null;
+ }
+ }
+
+ /**
+ * Loads the initial stored preferences back (restores preferences).
+ */
+ private void loadInitPreferences() {
+ if (initPrefsFile == null) {
+ return;
+ }
+ PreferencesImporter.importPreferences(initPrefsFile);
+ }
+
+ private JPanel createCancelOperationContent() {
+ JPanel panel = new JPanel(new MigLayout());
+ String msg = trans.get("PreferencesDialog.CancelOperation.msg.discardChanges");
+ JLabel msgLabel = new JLabel(msg);
+ JCheckBox dontAskAgain = new JCheckBox(trans.get("SimulationEditDialog.CancelOperation.checkbox.dontAskAgain"));
+ dontAskAgain.setSelected(false);
+ dontAskAgain.addItemListener(new ItemListener() {
+ @Override
+ public void itemStateChanged(ItemEvent e) {
+ if (e.getStateChange() == ItemEvent.SELECTED) {
+ preferences.setShowDiscardPreferencesConfirmation(false);
+ }
+ // Unselected state should be not be possible and thus not be handled
+ }
+ });
+
+ panel.add(msgLabel, "left, wrap");
+ panel.add(dontAskAgain, "left, gaptop para");
+
+ return panel;
+ }
+
// ////// Singleton implementation ////////
private static PreferencesDialog dialog = null;
diff --git a/swing/src/net/sf/openrocket/gui/dialogs/preferences/UnitsPreferencesPanel.java b/swing/src/net/sf/openrocket/gui/dialogs/preferences/UnitsPreferencesPanel.java
index 3b561e04f..bb32755b0 100644
--- a/swing/src/net/sf/openrocket/gui/dialogs/preferences/UnitsPreferencesPanel.java
+++ b/swing/src/net/sf/openrocket/gui/dialogs/preferences/UnitsPreferencesPanel.java
@@ -3,11 +3,15 @@ package net.sf.openrocket.gui.dialogs.preferences;
import java.awt.LayoutManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
import javax.swing.JButton;
+import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
+import javax.swing.JPanel;
import net.miginfocom.swing.MigLayout;
import net.sf.openrocket.gui.components.StyledLabel;
@@ -18,122 +22,146 @@ import net.sf.openrocket.gui.widgets.SelectColorButton;
public class UnitsPreferencesPanel extends PreferencesPanel {
public UnitsPreferencesPanel(JDialog parent) {
- super(parent, new MigLayout("", "[][]40lp[][]"));
+ super(parent, new MigLayout("", "[]40lp[]"));
JComboBox> combo;
+ JPanel leftPanel = new JPanel(new MigLayout("ins 0"));
+ JPanel rightPanel = new JPanel(new MigLayout("ins 0"));
//// Select your preferred units:
this.add(new JLabel(trans.get("pref.dlg.lbl.Selectprefunits")), "span, wrap paragraph");
-
+
+
+ // -------------- LEFT PANEL
//// Rocket dimensions:
- this.add(new JLabel(trans.get("pref.dlg.lbl.Rocketdimensions")));
+ leftPanel.add(new JLabel(trans.get("pref.dlg.lbl.Rocketdimensions")));
combo = new JComboBox