create changelog entry
[debian/openrocket] / core / src / net / sf / openrocket / optimization / rocketoptimization / modifiers / AbstractSimulationModifier.java
1 package net.sf.openrocket.optimization.rocketoptimization.modifiers;
2
3 import java.util.ArrayList;
4 import java.util.EventListener;
5 import java.util.EventObject;
6 import java.util.List;
7
8 import net.sf.openrocket.document.Simulation;
9 import net.sf.openrocket.optimization.general.OptimizationException;
10 import net.sf.openrocket.optimization.rocketoptimization.SimulationModifier;
11 import net.sf.openrocket.unit.UnitGroup;
12 import net.sf.openrocket.util.MathUtil;
13 import net.sf.openrocket.util.StateChangeListener;
14
15 /**
16  * An abstract implementation of the SimulationModifier interface.  An implementation
17  * needs only to implement the {@link #getCurrentSIValue(Simulation)} and
18  * {@link #modify(net.sf.openrocket.document.Simulation, double)} methods.
19  * 
20  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
21  */
22 public abstract class AbstractSimulationModifier implements SimulationModifier {
23         
24         private final String name;
25         private final String description;
26         private final Object relatedObject;
27         private final UnitGroup unitGroup;
28         
29         private double minValue = 0.0;
30         private double maxValue = 1.0;
31         
32         private final List<EventListener> listeners = new ArrayList<EventListener>();
33         
34         
35         /**
36          * Sole constructor.
37          * 
38          * @param modifierName                  the name of this modifier (returned by {@link #getName()})
39          * @param modifierDescription   the description of this modifier (returned by {@link #getDescription()})
40          * @param relatedObject                 the related object (returned by {@link #getRelatedObject()})
41          * @param unitGroup                             the unit group (returned by {@link #getUnitGroup()})
42          */
43         public AbstractSimulationModifier(String modifierName, String modifierDescription, Object relatedObject,
44                         UnitGroup unitGroup) {
45                 this.name = modifierName;
46                 this.description = modifierDescription;
47                 this.relatedObject = relatedObject;
48                 this.unitGroup = unitGroup;
49                 
50                 if (this.name == null || this.description == null || this.relatedObject == null || this.unitGroup == null) {
51                         throw new IllegalArgumentException("null value provided:" +
52                                         " name=" + this.name + " description=" + description + " relatedObject=" + relatedObject +
53                                         " unitGroup=" + unitGroup);
54                 }
55         }
56         
57         
58         @Override
59         public String getName() {
60                 return name;
61         }
62         
63         @Override
64         public String getDescription() {
65                 return description;
66         }
67         
68         @Override
69         public Object getRelatedObject() {
70                 return relatedObject;
71         }
72         
73         @Override
74         public double getCurrentScaledValue(Simulation simulation) throws OptimizationException {
75                 double value = getCurrentSIValue(simulation);
76                 return toScaledValue(value);
77         }
78         
79         
80
81         /**
82          * Returns the scaled value (normally within [0...1]).  If the min...max range is singular,
83          * this method returns 0.0, 1.0 or 0.5 depending on whether the value is less than,
84          * greater than or equal to the limit.
85          * 
86          * @param value         the value in SI units
87          * @return                      the value in scaled range (normally within [0...1])
88          */
89         protected double toScaledValue(double value) {
90                 if (MathUtil.equals(minValue, maxValue)) {
91                         if (value > maxValue)
92                                 return 1.0;
93                         if (value < minValue)
94                                 return 0.0;
95                         return 0.5;
96                 }
97                 
98                 return MathUtil.map(value, minValue, maxValue, 0.0, 1.0);
99         }
100         
101         
102         /**
103          * Returns the base value (in SI units).
104          * 
105          * @param value         the value in scaled range (normally within [0...1])
106          * @return                      the value in SI units
107          */
108         protected double toBaseValue(double value) {
109                 return MathUtil.map(value, 0.0, 1.0, minValue, maxValue);
110         }
111         
112         
113
114         @Override
115         public double getMinValue() {
116                 return minValue;
117         }
118         
119         @Override
120         public void setMinValue(double value) {
121                 if (MathUtil.equals(minValue, value))
122                         return;
123                 this.minValue = value;
124                 if (maxValue < minValue)
125                         maxValue = minValue;
126                 fireChangeEvent();
127         }
128         
129         @Override
130         public double getMaxValue() {
131                 return maxValue;
132         }
133         
134         @Override
135         public void setMaxValue(double value) {
136                 if (MathUtil.equals(maxValue, value))
137                         return;
138                 this.maxValue = value;
139                 if (minValue > maxValue)
140                         minValue = maxValue;
141                 fireChangeEvent();
142         }
143         
144         @Override
145         public UnitGroup getUnitGroup() {
146                 return unitGroup;
147         }
148         
149         
150         @Override
151         public void addChangeListener(EventListener listener) {
152                 listeners.add(listener);
153         }
154         
155         @Override
156         public void removeChangeListener(EventListener listener) {
157                 listeners.remove(listener);
158         }
159         
160         
161         /**
162          * Fire a change event to the listeners.
163          */
164         protected void fireChangeEvent() {
165                 EventObject event = new EventObject(this);
166                 // Copy the list before iterating to prevent concurrent modification exceptions.
167                 EventListener[] list = listeners.toArray(new EventListener[0]);
168                 for (EventListener l : list) {
169                         if ( l instanceof StateChangeListener ) {
170                                 ((StateChangeListener)l).stateChanged(event);
171                         }
172                 }
173         }
174         
175         @Override
176         public boolean equals(Object obj) {
177                 if (this == obj)
178                         return true;
179                 if (obj == null)
180                         return false;
181                 if (getClass() != obj.getClass())
182                         return false;
183                 
184                 AbstractSimulationModifier other = (AbstractSimulationModifier) obj;
185                 if (!this.description.equals(other.description))
186                         return false;
187                 if (!this.name.equals(other.name))
188                         return false;
189                 if (!this.relatedObject.equals(other.relatedObject))
190                         return false;
191                 if (!this.unitGroup.equals(other.unitGroup))
192                         return false;
193                 
194                 return true;
195         }
196         
197         
198
199         @Override
200         public int hashCode() {
201                 final int prime = 31;
202                 int result = 1;
203                 result = prime * result + (description.hashCode());
204                 result = prime * result + (name.hashCode());
205                 result = prime * result + (relatedObject.hashCode());
206                 result = prime * result + (unitGroup.hashCode());
207                 return result;
208         }
209         
210
211 }