2 Copyright (C) 2001, 2006 United States Government as represented by
3 the Administrator of the National Aeronautics and Space Administration.
6 package gov
.nasa
.worldwind
.awt
;
8 import gov
.nasa
.worldwind
.*;
9 import gov
.nasa
.worldwind
.geom
.*;
13 * @version $Id: InterpolatorTimer.java 1818 2007-05-10 15:59:46Z dcollins $
15 class InterpolatorTimer
17 static class ViewProperties
25 private java
.util
.TimerTask timerTask
;
26 private volatile boolean isRunning
;
27 private java
.beans
.PropertyChangeListener listener
;
28 private double stepCoefficient
;
29 private double errorThreshold
;
33 public InterpolatorTimer(final int period
)
37 String message
= WorldWind
.retrieveErrMsg("awt.InterpolatorTimer.PeriodLessThanZero");
38 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
39 throw new IllegalArgumentException(message
);
41 java
.util
.Timer timer
= new java
.util
.Timer();
42 this.timerTask
= new java
.util
.TimerTask()
46 long time
= System
.currentTimeMillis();
47 if (time
- this.scheduledExecutionTime() >= 2 * period
)
49 if (InterpolatorTimer
.this.listener
== null)
51 InterpolatorTimer
.this.updateAndNotify(InterpolatorTimer
.this.listener
);
54 timer
.schedule(timerTask
, 0, period
);
57 public synchronized boolean isRunning()
59 return this.isRunning
;
62 private static double error(Object x
, Object end
)
64 if (x
instanceof Angle
)
65 return error((Angle
) x
, (Angle
) end
);
66 else if (x
instanceof Double
)
67 return error((Double
) x
, (Double
) end
);
68 else if (x
instanceof LatLon
)
69 return error((LatLon
) x
, (LatLon
) end
);
70 else if (x
instanceof Point
)
71 return error((Point
) x
, (Point
) end
);
72 else if (x
instanceof ViewProperties
)
73 return error((ViewProperties
) x
, (ViewProperties
) end
);
78 private static double error(Double x
, Double end
)
80 return Math
.abs(end
- x
);
83 private static double error(Angle x
, Angle end
)
85 return Math
.abs(end
.getDegrees() - x
.getDegrees()) % 360d
;
88 private static double error(LatLon x
, LatLon end
)
90 double latError
= Math
.abs(end
.getLatitude().getRadians() - x
.getLatitude().getRadians()) % (Math
.PI
/ 2);
91 double lonError
= Math
.abs(end
.getLongitude().getRadians() - x
.getLongitude().getRadians()) % Math
.PI
;
92 return latError
> lonError ? latError
: lonError
;
95 private static double error(Point x
, Point end
)
98 maxError
= Math
.max(maxError
, error(x
.x(), end
.x()));
99 maxError
= Math
.max(maxError
, error(x
.y(), end
.y()));
100 maxError
= Math
.max(maxError
, error(x
.z(), end
.z()));
101 maxError
= Math
.max(maxError
, error(x
.w(), end
.w()));
105 private static double error(ViewProperties x
, ViewProperties end
)
108 if (x
.latLon
!= null && end
.latLon
!= null)
109 maxError
= Math
.max(maxError
, error(x
.latLon
, end
.latLon
));
110 if (x
.heading
!= null && end
.heading
!= null)
111 maxError
= Math
.max(maxError
, error(x
.heading
, end
.heading
));
112 if (x
.pitch
!= null && end
.pitch
!= null)
113 maxError
= Math
.max(maxError
, error(x
.pitch
, end
.pitch
));
114 if (x
.zoom
!= null && end
.zoom
!= null)
115 maxError
= Math
.max(maxError
, error(x
.zoom
, end
.zoom
));
119 private static Object
mix(double t
, Object begin
, Object end
)
121 if (begin
instanceof Angle
)
122 return mix(t
, (Angle
) begin
, (Angle
) end
);
123 else if (begin
instanceof Double
)
124 return mix(t
, (Double
) begin
, (Double
) end
);
125 else if (begin
instanceof LatLon
)
126 return mix(t
, (LatLon
) begin
, (LatLon
) end
);
127 else if (begin
instanceof Point
)
128 return mix(t
, (Point
) begin
, (Point
) end
);
129 else if (begin
instanceof ViewProperties
)
130 return mix(t
, (ViewProperties
) begin
, (ViewProperties
) end
);
135 private static Angle
mix(double t
, Angle begin
, Angle end
)
141 Quaternion beginQuat
= Quaternion
.EulerToQuaternion(begin
.getRadians(), 0, 0);
142 Quaternion endQuat
= Quaternion
.EulerToQuaternion(end
.getRadians(), 0, 0);
143 Quaternion q
= Quaternion
.Slerp(beginQuat
, endQuat
, t
);
144 Point v
= Quaternion
.QuaternionToEuler(q
);
146 if (Double
.isNaN(v
.x()))
149 return Angle
.fromRadians(v
.x());
152 private static Double
mix(double t
, Double begin
, Double end
)
158 return (1 - t
) * begin
+ t
* end
;
161 private static LatLon
mix(double t
, LatLon begin
, LatLon end
)
167 Quaternion beginQuat
= Quaternion
.EulerToQuaternion(begin
.getLongitude().getRadians(),
168 begin
.getLatitude().getRadians(), 0);
169 Quaternion endQuat
= Quaternion
.EulerToQuaternion(end
.getLongitude().getRadians(),
170 end
.getLatitude().getRadians(), 0);
171 Quaternion q
= Quaternion
.Slerp(beginQuat
, endQuat
, t
);
172 Point v
= Quaternion
.QuaternionToEuler(q
);
173 if (Double
.isNaN(v
.x()) || Double
.isNaN(v
.y()))
175 return LatLon
.fromRadians(v
.y(), v
.x());
178 private static Point
mix(double t
, Point begin
, Point end
)
180 return new Point(mix(t
, begin
.x(), end
.x()), mix(t
, begin
.y(), end
.y()),
181 mix(t
, begin
.z(), end
.z()), mix(t
, begin
.w(), end
.w()));
184 private static ViewProperties
mix(double t
, ViewProperties begin
, ViewProperties end
)
186 ViewProperties x
= new ViewProperties();
187 if (begin
.latLon
!= null && end
.latLon
!= null)
188 x
.latLon
= mix(t
, begin
.latLon
, end
.latLon
);
189 if (begin
.heading
!= null && end
.heading
!= null)
191 if (begin
.pitch
!= null && end
.pitch
!= null)
193 // TODO: this doesn't pan heading & pitch equally
194 Quaternion beginQuat
= Quaternion
.EulerToQuaternion(begin
.heading
.getRadians(),
195 begin
.pitch
.getRadians(), 0);
196 Quaternion endQuat
= Quaternion
.EulerToQuaternion(end
.heading
.getRadians(),
197 end
.pitch
.getRadians(), 0);
198 Quaternion q
= Quaternion
.Slerp(beginQuat
, endQuat
, t
);
199 Point v
= Quaternion
.QuaternionToEuler(q
);
200 if (!Double
.isNaN(v
.x()) && !Double
.isNaN(v
.y()))
202 x
.heading
= Angle
.fromRadians(v
.x());
203 x
.pitch
= Angle
.fromRadians(v
.y());
213 x
.heading
= mix(t
, begin
.heading
, end
.heading
);
216 else if (begin
.pitch
!= null && end
.pitch
!= null)
217 x
.pitch
= mix(t
, begin
.pitch
, end
.pitch
);
218 if (begin
.zoom
!= null && end
.zoom
!= null)
219 x
.zoom
= mix(t
, begin
.zoom
, end
.zoom
);
223 public synchronized void start(double stepCoefficient
, double errorThreshold
, Object begin
, Object end
,
224 java
.beans
.PropertyChangeListener listener
)
226 if (stepCoefficient
< 0)
228 String message
= WorldWind
.retrieveErrMsg("awt.InterpolatorTimer.StepCoefficientLessThanZero");
229 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
230 throw new IllegalArgumentException(message
);
232 if (errorThreshold
< 0)
234 String message
= WorldWind
.retrieveErrMsg("awt.InterpolatorTimer.ErrorThresholdLessThanZero");
235 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
236 throw new IllegalArgumentException(message
);
238 if (begin
== null || end
== null)
240 String message
= WorldWind
.retrieveErrMsg("nullValue.ObjectIsNull");
241 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
242 throw new IllegalArgumentException(message
);
244 if (!end
.getClass().isInstance(begin
))
246 String message
= WorldWind
.retrieveErrMsg("awt.InterpolatorTimer.DifferentMixTypes");
247 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
248 throw new IllegalArgumentException(message
);
250 if (listener
== null)
252 String message
= WorldWind
.retrieveErrMsg("nullValue.ListenerIsNull");
253 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, message
);
254 throw new IllegalArgumentException(message
);
257 if (this.isRunning
&& this.listener
!= null && !this.listener
.equals(listener
))
258 this.listener
.propertyChange(new java
.beans
.PropertyChangeEvent(this, null, null, null));
260 this.listener
= listener
;
261 this.stepCoefficient
= stepCoefficient
;
262 this.errorThreshold
= errorThreshold
;
265 this.isRunning
= true;
268 public synchronized void stop()
272 if (this.listener
!= null)
273 listener
.propertyChange(new java
.beans
.PropertyChangeEvent(this, null, null, null));
274 this.listener
= null;
275 this.stepCoefficient
= errorThreshold
= -1;
276 this.begin
= end
= null;
277 this.isRunning
= false;
281 private synchronized void updateAndNotify(java
.beans
.PropertyChangeListener listener
)
283 if (!this.isRunning
|| this.begin
== null || listener
== null)
286 Object newValue
= mix(this.stepCoefficient
, this.begin
, this.end
);
287 if (newValue
== null)
293 double error
= error(newValue
, this.end
);
294 if (error
< this.errorThreshold
)
300 listener
.propertyChange(new java
.beans
.PropertyChangeEvent(this, null, this.begin
, newValue
));
301 this.begin
= newValue
;