geodetic computations
[debian/openrocket] / src / net / sf / openrocket / simulation / SimulationConditions.java
index 8b79bfbc9ef303e4db2618dcafb1e58b2e9d8501..f2412717a34a55bcfe6200c1a924eecd09829267 100644 (file)
@@ -3,424 +3,290 @@ package net.sf.openrocket.simulation;
 import java.util.ArrayList;
 import java.util.List;
 
-import javax.swing.event.ChangeEvent;
-import javax.swing.event.ChangeListener;
-
-import net.sf.openrocket.aerodynamics.AtmosphericModel;
-import net.sf.openrocket.aerodynamics.ExtendedISAModel;
+import net.sf.openrocket.aerodynamics.AerodynamicCalculator;
+import net.sf.openrocket.masscalc.MassCalculator;
+import net.sf.openrocket.models.atmosphere.AtmosphericModel;
+import net.sf.openrocket.models.gravity.GravityModel;
+import net.sf.openrocket.models.wind.WindModel;
 import net.sf.openrocket.rocketcomponent.Rocket;
-import net.sf.openrocket.util.ChangeSource;
-import net.sf.openrocket.util.MathUtil;
-
-
-public class SimulationConditions implements ChangeSource, Cloneable {
-
-       public static final double MAX_LAUNCH_ROD_ANGLE = Math.PI/3;
-       
-       /**
-        * The ISA standard atmosphere.
-        */
-       private static final AtmosphericModel ISA_ATMOSPHERIC_MODEL = new ExtendedISAModel();
-       
-       
-       private final Rocket rocket;
+import net.sf.openrocket.simulation.listeners.SimulationListener;
+import net.sf.openrocket.util.BugException;
+import net.sf.openrocket.util.GeodeticComputationStrategy;
+import net.sf.openrocket.util.Monitorable;
+import net.sf.openrocket.util.WorldCoordinate;
+
+/**
+ * A holder class for the simulation conditions.  These include conditions that do not change
+ * during the flight of a rocket, for example launch rod parameters, atmospheric models,
+ * aerodynamic calculators etc.
+ * 
+ * @author Sampo Niskanen <sampo.niskanen@iki.fi>
+ */
+public class SimulationConditions implements Monitorable, Cloneable {
+       
+       private Rocket rocket;
        private String motorID = null;
-
        
-       /*
-        * NOTE:  When adding/modifying parameters, they must also be added to the
-        * equals and copyFrom methods!!
-        */
 
-       // TODO: HIGH: Fetch default values from Prefs!
-       
        private double launchRodLength = 1;
        
-       /** Launch rod angle > 0, radians from vertical */ 
+       /** Launch rod angle >= 0, radians from vertical */
        private double launchRodAngle = 0;
        
        /** Launch rod direction, 0 = upwind, PI = downwind. */
        private double launchRodDirection = 0;
        
+       // TODO: Depreciate these and use worldCoordinate only.
+       //private double launchAltitude = 0;
+       //private double launchLatitude = 45;
+       //private double launchLongitude = 0;
+       private WorldCoordinate launchSite = new WorldCoordinate(0, 0, 0);
+       private GeodeticComputationStrategy geodeticComputation = GeodeticComputationStrategy.SPHERICAL;
+       
 
-       private double windAverage = 2.0;
-       private double windTurbulence = 0.1;
+       private WindModel windModel;
+       private AtmosphericModel atmosphericModel;
+       private GravityModel gravityModel;
        
-       private double launchAltitude = 0;
-       private double launchLatitude = 45;
+       private AerodynamicCalculator aerodynamicCalculator;
+       private MassCalculator massCalculator;
        
-       private boolean useISA = true;
-       private double launchTemperature = ExtendedISAModel.STANDARD_TEMPERATURE;
-       private double launchPressure = ExtendedISAModel.STANDARD_PRESSURE;
-       private AtmosphericModel atmosphericModel = null;
+
+       private double timeStep = RK4SimulationStepper.RECOMMENDED_TIME_STEP;
+       private double maximumAngleStep = RK4SimulationStepper.RECOMMENDED_ANGLE_STEP;
        
+       /* Whether to calculate additional data or only primary simulation figures */
+       private boolean calculateExtras = true;
        
-       private double timeStep = RK4Simulator.RECOMMENDED_TIME_STEP;
-       private double maximumAngle = RK4Simulator.RECOMMENDED_ANGLE_STEP;
+
+       private List<SimulationListener> simulationListeners = new ArrayList<SimulationListener>();
        
-       private boolean calculateExtras = true;
+
+       private int randomSeed = 0;
+       
+       private int modID = 0;
+       private int modIDadd = 0;
        
+       
+
 
-       private List<ChangeListener> listeners = new ArrayList<ChangeListener>();
+       public AerodynamicCalculator getAerodynamicCalculator() {
+               return aerodynamicCalculator;
+       }
        
        
+       public void setAerodynamicCalculator(AerodynamicCalculator aerodynamicCalculator) {
+               if (this.aerodynamicCalculator != null)
+                       this.modIDadd += this.aerodynamicCalculator.getModID();
+               this.modID++;
+               this.aerodynamicCalculator = aerodynamicCalculator;
+       }
        
-       public SimulationConditions(Rocket rocket) {
-               this.rocket = rocket;
+       public MassCalculator getMassCalculator() {
+               return massCalculator;
        }
        
        
+       public void setMassCalculator(MassCalculator massCalculator) {
+               if (this.massCalculator != null)
+                       this.modIDadd += this.massCalculator.getModID();
+               this.modID++;
+               this.massCalculator = massCalculator;
+       }
+       
        
        public Rocket getRocket() {
                return rocket;
        }
-               
+       
+       
+       public void setRocket(Rocket rocket) {
+               if (this.rocket != null)
+                       this.modIDadd += this.rocket.getModID();
+               this.modID++;
+               this.rocket = rocket;
+       }
+       
        
        public String getMotorConfigurationID() {
                return motorID;
        }
        
-       /**
-        * Set the motor configuration ID.  This must be a valid motor configuration ID of
-        * the rocket, otherwise the configuration is set to <code>null</code>.
-        * 
-        * @param id    the configuration to set.
-        */
-       public void setMotorConfigurationID(String id) {
-               if (id != null)
-                       id = id.intern();
-               if (!rocket.isMotorConfigurationID(id))
-                       id = null;
-               if (id == motorID)
-                       return;
-               motorID = id;
-               fireChangeEvent();
+       
+       public void setMotorConfigurationID(String motorID) {
+               this.motorID = motorID;
+               this.modID++;
        }
        
-
+       
        public double getLaunchRodLength() {
                return launchRodLength;
        }
-
+       
+       
        public void setLaunchRodLength(double launchRodLength) {
-               if (MathUtil.equals(this.launchRodLength, launchRodLength))
-                       return;
                this.launchRodLength = launchRodLength;
-               fireChangeEvent();
+               this.modID++;
        }
-
+       
        
        public double getLaunchRodAngle() {
                return launchRodAngle;
        }
-
+       
+       
        public void setLaunchRodAngle(double launchRodAngle) {
-               launchRodAngle = MathUtil.clamp(launchRodAngle, 0, MAX_LAUNCH_ROD_ANGLE);
-               if (MathUtil.equals(this.launchRodAngle, launchRodAngle))
-                       return;
                this.launchRodAngle = launchRodAngle;
-               fireChangeEvent();
+               this.modID++;
        }
-
+       
        
        public double getLaunchRodDirection() {
                return launchRodDirection;
        }
-
+       
+       
        public void setLaunchRodDirection(double launchRodDirection) {
-               launchRodDirection = MathUtil.reduce180(launchRodDirection);
-               if (MathUtil.equals(this.launchRodDirection, launchRodDirection))
-                       return;
                this.launchRodDirection = launchRodDirection;
-               fireChangeEvent();
+               this.modID++;
        }
-
        
        
-       public double getWindSpeedAverage() {
-               return windAverage;
+       public WorldCoordinate getLaunchSite() {
+               return this.launchSite;
        }
-
-       public void setWindSpeedAverage(double windAverage) {
-               if (MathUtil.equals(this.windAverage, windAverage))
+       
+       public void setLaunchSite(WorldCoordinate site) {
+               if (this.launchSite.equals(site))
                        return;
-               this.windAverage = MathUtil.max(windAverage, 0);
-               fireChangeEvent();
+               this.launchSite = site;
+               this.modID++;
        }
-
        
-       public double getWindSpeedDeviation() {
-               return windAverage * windTurbulence;
+       
+       public GeodeticComputationStrategy getGeodeticComputation() {
+               return geodeticComputation;
        }
-
-       public void setWindSpeedDeviation(double windDeviation) {
-               if (windAverage < 0.1) {
-                       windAverage = 0.1;
+       
+       public void setGeodeticComputation(GeodeticComputationStrategy geodeticComputation) {
+               if (this.geodeticComputation == geodeticComputation)
+                       return;
+               if (geodeticComputation == null) {
+                       throw new IllegalArgumentException("strategy cannot be null");
                }
-               setWindTurbulenceIntensity(windDeviation / windAverage);
+               this.geodeticComputation = geodeticComputation;
+               this.modID++;
        }
-
        
-       /**
-     * Return the wind turbulence intensity (standard deviation / average).
-     * 
-     * @return  the turbulence intensity
-     */
-    public double getWindTurbulenceIntensity() {
-        return windTurbulence;
-    }
-
-    /**
-     * Set the wind standard deviation to match the given turbulence intensity.
-     * 
-     * @param intensity   the turbulence intensity
-     */
-    public void setWindTurbulenceIntensity(double intensity) {
-       // Does not check equality so that setWindSpeedDeviation can be sure of event firing
-       this.windTurbulence = intensity;
-       fireChangeEvent();
-    }
-    
-
        
+       public WindModel getWindModel() {
+               return windModel;
+       }
        
        
-       public double getLaunchAltitude() {
-               return launchAltitude;
-       }
-
-       public void setLaunchAltitude(double altitude) {
-               if (MathUtil.equals(this.launchAltitude, altitude))
-                       return;
-               this.launchAltitude = altitude;
-               fireChangeEvent();
+       public void setWindModel(WindModel windModel) {
+               if (this.windModel != null)
+                       this.modIDadd += this.windModel.getModID();
+               this.modID++;
+               this.windModel = windModel;
        }
        
        
-       public double getLaunchLatitude() {
-               return launchLatitude;
-       }
-
-       public void setLaunchLatitude(double launchLatitude) {
-               launchLatitude = MathUtil.clamp(launchLatitude, -90, 90);
-               if (MathUtil.equals(this.launchLatitude, launchLatitude))
-                       return;
-               this.launchLatitude = launchLatitude;
-               fireChangeEvent();
+       public AtmosphericModel getAtmosphericModel() {
+               return atmosphericModel;
        }
-
-
        
        
-       
-       public boolean isISAAtmosphere() {
-               return useISA;
+       public void setAtmosphericModel(AtmosphericModel atmosphericModel) {
+               if (this.atmosphericModel != null)
+                       this.modIDadd += this.atmosphericModel.getModID();
+               this.modID++;
+               this.atmosphericModel = atmosphericModel;
        }
        
-       public void setISAAtmosphere(boolean isa) {
-               if (isa == useISA)
-                       return;
-               useISA = isa;
-               fireChangeEvent();
-       }
        
-
-       public double getLaunchTemperature() {
-               return launchTemperature;
-       }
-
-
-
-       public void setLaunchTemperature(double launchTemperature) {
-               if (MathUtil.equals(this.launchTemperature, launchTemperature))
-                       return;
-               this.launchTemperature = launchTemperature;
-               this.atmosphericModel = null;
-               fireChangeEvent();
-       }
-
-
-
-       public double getLaunchPressure() {
-               return launchPressure;
-       }
-
-
-
-       public void setLaunchPressure(double launchPressure) {
-               if (MathUtil.equals(this.launchPressure, launchPressure))
-                       return;
-               this.launchPressure = launchPressure;
-               this.atmosphericModel = null;
-               fireChangeEvent();
+       public GravityModel getGravityModel() {
+               return gravityModel;
        }
-
        
-       /**
-        * Returns an atmospheric model corresponding to the launch conditions.  The
-        * atmospheric models may be shared between different calls.
-        * 
-        * @return      an AtmosphericModel object.
-        */
-       public AtmosphericModel getAtmosphericModel() {
-               if (useISA) {
-                       return ISA_ATMOSPHERIC_MODEL;
-               }
-               if (atmosphericModel == null) {
-                       atmosphericModel = new ExtendedISAModel(launchAltitude, 
-                                       launchTemperature, launchPressure);
-               }
-               return atmosphericModel;
+       
+       public void setGravityModel(GravityModel gravityModel) {
+               //if (this.gravityModel != null)
+               //      this.modIDadd += this.gravityModel.getModID();
+               this.modID++;
+               this.gravityModel = gravityModel;
        }
        
        
        public double getTimeStep() {
                return timeStep;
        }
-
+       
+       
        public void setTimeStep(double timeStep) {
-               if (MathUtil.equals(this.timeStep, timeStep))
-                       return;
                this.timeStep = timeStep;
-               fireChangeEvent();
+               this.modID++;
        }
-
-       public double getMaximumStepAngle() {
-               return maximumAngle;
+       
+       
+       public double getMaximumAngleStep() {
+               return maximumAngleStep;
        }
-
-       public void setMaximumStepAngle(double maximumAngle) {
-               maximumAngle = MathUtil.clamp(maximumAngle, 1*Math.PI/180, 20*Math.PI/180);
-               if (MathUtil.equals(this.maximumAngle, maximumAngle))
-                       return;
-               this.maximumAngle = maximumAngle;
-               fireChangeEvent();
+       
+       
+       public void setMaximumAngleStep(double maximumAngle) {
+               this.maximumAngleStep = maximumAngle;
+               this.modID++;
        }
-
-
-
-       public boolean getCalculateExtras() {
+       
+       
+       public boolean isCalculateExtras() {
                return calculateExtras;
        }
-
-
-
+       
+       
        public void setCalculateExtras(boolean calculateExtras) {
-               if (this.calculateExtras == calculateExtras)
-                       return;
                this.calculateExtras = calculateExtras;
-               fireChangeEvent();
+               this.modID++;
        }
-
-
        
-       @Override
-       public SimulationConditions clone() {
-               try {
-                       SimulationConditions copy = (SimulationConditions)super.clone();
-                       copy.listeners = new ArrayList<ChangeListener>();
-                       return copy;
-               } catch (CloneNotSupportedException e) {
-                       throw new RuntimeException(e);
-               }
+       
+
+       public int getRandomSeed() {
+               return randomSeed;
        }
        
        
-       public void copyFrom(SimulationConditions src) {
-               
-               if (this.rocket == src.rocket) {
-                       
-                       this.motorID = src.motorID;
-                       
-               } else {
-               
-                       if (src.rocket.hasMotors(src.motorID)) {
-                               // Try to find a matching motor ID
-                               String motorDesc = src.rocket.getMotorConfigurationDescription(src.motorID);
-                               String matchID = null;
-                               
-                               for (String id: this.rocket.getMotorConfigurationIDs()) {
-                                       if (motorDesc.equals(this.rocket.getMotorConfigurationDescription(id))) {
-                                               matchID = id;
-                                               break;
-                                       }
-                               }
-                               
-                               this.motorID = matchID;
-                       } else {
-                               this.motorID = null;
-                       }
-               }
-               
-               this.launchAltitude = src.launchAltitude;
-               this.launchLatitude = src.launchLatitude;
-               this.launchPressure = src.launchPressure;
-               this.launchRodAngle = src.launchRodAngle;
-               this.launchRodDirection = src.launchRodDirection;
-               this.launchRodLength = src.launchRodLength;
-               this.launchTemperature = src.launchTemperature;
-               this.maximumAngle = src.maximumAngle;
-               this.timeStep = src.timeStep;
-               this.windAverage = src.windAverage;
-               this.windTurbulence = src.windTurbulence;
-               this.calculateExtras = src.calculateExtras;
-               
-               fireChangeEvent();
-       }
-       
-       
-       
-       /**
-        * Compares whether the two simulation conditions are equal.  The two are considered
-        * equal if the rocket, motor id and all variables are equal.
-        */
-       @Override
-       public boolean equals(Object other) {
-               if (!(other instanceof SimulationConditions))
-                       return false;
-               SimulationConditions o = (SimulationConditions)other;
-               return ((this.rocket == o.rocket) &&
-                               this.motorID == o.motorID &&
-                               MathUtil.equals(this.launchAltitude, o.launchAltitude) &&
-                               MathUtil.equals(this.launchLatitude, o.launchLatitude) &&
-                               MathUtil.equals(this.launchPressure, o.launchPressure) &&
-                               MathUtil.equals(this.launchRodAngle, o.launchRodAngle) &&
-                               MathUtil.equals(this.launchRodDirection, o.launchRodDirection) &&
-                               MathUtil.equals(this.launchRodLength, o.launchRodLength) &&
-                               MathUtil.equals(this.launchTemperature, o.launchTemperature) &&
-                               MathUtil.equals(this.maximumAngle, o.maximumAngle) &&
-                               MathUtil.equals(this.timeStep, o.timeStep) &&
-                               MathUtil.equals(this.windAverage, o.windAverage) &&
-                               MathUtil.equals(this.windTurbulence, o.windTurbulence) &&
-                               this.calculateExtras == o.calculateExtras);
-       }
-       
-       /**
-        * Hashcode method compatible with {@link #equals(Object)}.
-        */
-       @Override
-       public int hashCode() {
-               if (motorID == null)
-                       return rocket.hashCode();
-               return rocket.hashCode() + motorID.hashCode();
+       public void setRandomSeed(int randomSeed) {
+               this.randomSeed = randomSeed;
+               this.modID++;
        }
+       
+       
 
-       @Override
-       public void addChangeListener(ChangeListener listener) {
-               listeners.add(listener);
-       }
 
+       // TODO: HIGH: Make cleaner
+       public List<SimulationListener> getSimulationListenerList() {
+               return simulationListeners;
+       }
+       
+       
        @Override
-       public void removeChangeListener(ChangeListener listener) {
-               listeners.remove(listener);
+       public int getModID() {
+               //return (modID + modIDadd + rocket.getModID() + windModel.getModID() + atmosphericModel.getModID() +
+               //              gravityModel.getModID() + aerodynamicCalculator.getModID() + massCalculator.getModID());
+               return (modID + modIDadd + rocket.getModID() + windModel.getModID() + atmosphericModel.getModID() +
+                               aerodynamicCalculator.getModID() + massCalculator.getModID());
        }
        
-       private final ChangeEvent event = new ChangeEvent(this);
-       private void fireChangeEvent() {
-               ChangeListener[] array = listeners.toArray(new ChangeListener[0]);
-               
-               for (int i=array.length-1; i >=0; i--) {
-                       array[i].stateChanged(event);
+       
+       @Override
+       public SimulationConditions clone() {
+               try {
+                       // TODO: HIGH: Deep clone models
+                       return (SimulationConditions) super.clone();
+               } catch (CloneNotSupportedException e) {
+                       throw new BugException(e);
                }
        }