2 Copyright (C) 2001, 2006 United States Government
3 as represented by the Administrator of the
4 National Aeronautics and Space Administration.
7 package gov
.nasa
.worldwind
;
9 import gov
.nasa
.worldwind
.geom
.*;
11 import javax
.media
.opengl
.*;
12 import javax
.media
.opengl
.glu
.*;
18 public class TrackRenderer
implements Disposable
20 private int lowerLimit
= 0;
21 private int upperLimit
= Integer
.MAX_VALUE
;
22 private double markerPixels
= 10d
; // TODO: these should all be configurable
23 private double minMarkerSize
= 5d
;
24 private double markerElevation
= 10d
;
25 private boolean overrideMarkerElevation
= false;
26 private Material material
= Material
.WHITE
;
27 private String iconFilePath
;
28 private final TrackRenderer
.Shape SPHERE
= new TrackRenderer
.Sphere();
29 private final TrackRenderer
.Shape CONE
= new TrackRenderer
.Cone();
30 private final TrackRenderer
.Shape CYLINDER
= new TrackRenderer
.Cylinder();
31 private TrackRenderer
.Shape shape
= SPHERE
;
33 public TrackRenderer()
40 this.CYLINDER
.dispose();
41 this.SPHERE
.dispose();
44 public double getMarkerPixels()
49 public void setMarkerPixels(double markerPixels
)
51 this.markerPixels
= markerPixels
;
54 public double getMinMarkerSize()
59 public void setMinMarkerSize(double minMarkerSize
)
61 this.minMarkerSize
= minMarkerSize
;
64 public double getMarkerElevation()
66 return markerElevation
;
69 public void setMarkerElevation(double markerElevation
)
71 this.markerElevation
= markerElevation
;
74 public boolean isOverrideMarkerElevation()
76 return overrideMarkerElevation
;
79 public void setOverrideMarkerElevation(boolean overrideMarkerElevation
)
81 this.overrideMarkerElevation
= overrideMarkerElevation
;
84 public Material
getMaterial()
89 public void setMaterial(Material material
)
93 String msg
= WorldWind
.retrieveErrMsg("nullValue.MaterialIsNull");
94 WorldWind
.logger().log(java
.util
.logging
.Level
.FINE
, msg
);
95 throw new IllegalArgumentException(msg
);
98 // don't validate material's colors - material does that.
100 this.material
= material
;
103 public String
getIconFilePath()
108 public void setIconFilePath(String iconFilePath
)
110 //don't validate - a null iconFilePath cancels icon drawing
111 this.iconFilePath
= iconFilePath
;
114 public int getLowerLimit()
116 return this.lowerLimit
;
119 public void setLowerLimit(int lowerLimit
)
121 this.lowerLimit
= lowerLimit
;
124 public int getUpperLimit()
126 return this.upperLimit
;
129 public void setUpperLimit(int upperLimit
)
131 this.upperLimit
= upperLimit
;
134 public void setShapeType(String shapeName
)
136 if (shapeName
.equalsIgnoreCase("Cone"))
138 else if (shapeName
.equalsIgnoreCase("Cylinder"))
139 this.shape
= CYLINDER
;
144 public void pick(DrawContext dc
, java
.util
.Iterator
<TrackPoint
> trackPositions
, java
.awt
.Point pickPoint
,
150 public Vec4
render(DrawContext dc
, java
.util
.Iterator
<TrackPoint
> trackPositions
)
152 return this.draw(dc
, trackPositions
);
155 private Vec4
draw(DrawContext dc
, java
.util
.Iterator
<TrackPoint
> trackPositions
)
157 if (dc
.getVisibleSector() == null)
160 SectorGeometryList geos
= dc
.getSurfaceGeometry();
164 if (!this.shape
.isInitialized
)
165 this.shape
.initialize(dc
);
168 java
.util
.List
<Vec4
> points
= new java
.util
.ArrayList
<Vec4
>();
169 while (trackPositions
.hasNext())
171 TrackPoint tp
= trackPositions
.next();
172 if (index
>= this.lowerLimit
&& index
<= this.upperLimit
)
174 Vec4 point
= this.computeSurfacePoint(dc
, tp
);
180 if (++index
>= this.upperLimit
)
184 if (points
.size() < 1)
187 Vec4 firstPoint
= points
.get(0);
188 Vec4 lastPointDrawn
= firstPoint
;
191 Vec4 previousDrawnPoint
= null;
193 double radius
= this.computeMarkerRadius(dc
, firstPoint
);
194 this.shape
.render(dc
, firstPoint
, radius
);
195 for (Vec4 point
: points
)
197 if (previousDrawnPoint
== null)
199 previousDrawnPoint
= firstPoint
;
200 continue; // skip over first point
203 // TODO: More sophisticated separation algorithm to gain frame-to-frame consistency
204 radius
= this.computeMarkerRadius(dc
, point
);
205 double separation
= point
.distanceTo3(previousDrawnPoint
);
206 double minSeparation
= 4d
* radius
;
207 if (separation
> minSeparation
)
209 if (!dc
.isPickingMode())
210 this.shape
.render(dc
, point
, radius
);
212 previousDrawnPoint
= point
;
213 lastPointDrawn
= point
;
219 Vec4 iconPoint
= points
.get(points
.size() - 1);
220 return iconPoint
!= null ? iconPoint
: lastPointDrawn
;
223 private Vec4
computeSurfacePoint(DrawContext dc
, TrackPoint pos
)
225 return dc
.getSurfaceGeometry().getSurfacePoint(Angle
.fromDegrees(pos
.getLatitude()),
226 Angle
.fromDegrees(pos
.getLongitude()),
227 this.overrideMarkerElevation ?
this.markerElevation
: pos
.getElevation());
230 private double computeMarkerRadius(DrawContext dc
, Vec4 point
)
232 double d
= point
.distanceTo3(dc
.getView().getEyePoint());
233 double radius
= this.markerPixels
* dc
.getView().computePixelSizeAtDistance(d
);
234 if (radius
< this.minMarkerSize
)
235 radius
= this.minMarkerSize
;
240 private void begin(DrawContext dc
)
243 Vec4 cameraPosition
= dc
.getView().getEyePoint();
246 GL
.GL_TEXTURE_BIT
| GL
.GL_ENABLE_BIT
| GL
.GL_CURRENT_BIT
| GL
.GL_LIGHTING_BIT
| GL
.GL_TRANSFORM_BIT
);
247 gl
.glDisable(GL
.GL_TEXTURE_2D
);
249 float[] lightPosition
=
250 {(float) (cameraPosition
.x
* 2), (float) (cameraPosition
.y
/ 2), (float) (cameraPosition
.z
), 0.0f
};
251 float[] lightDiffuse
= {1.0f
, 1.0f
, 1.0f
, 1.0f
};
252 float[] lightAmbient
= {1.0f
, 1.0f
, 1.0f
, 1.0f
};
253 float[] lightSpecular
= {1.0f
, 1.0f
, 1.0f
, 1.0f
};
255 this.material
.apply(gl
, GL
.GL_FRONT
);
257 gl
.glLightfv(GL
.GL_LIGHT1
, GL
.GL_POSITION
, lightPosition
, 0);
258 gl
.glLightfv(GL
.GL_LIGHT1
, GL
.GL_DIFFUSE
, lightDiffuse
, 0);
259 gl
.glLightfv(GL
.GL_LIGHT1
, GL
.GL_AMBIENT
, lightAmbient
, 0);
260 gl
.glLightfv(GL
.GL_LIGHT1
, GL
.GL_SPECULAR
, lightSpecular
, 0);
262 gl
.glDisable(GL
.GL_LIGHT0
);
263 gl
.glEnable(GL
.GL_LIGHT1
);
264 gl
.glEnable(GL
.GL_LIGHTING
);
265 gl
.glEnable(GL
.GL_NORMALIZE
);
267 gl
.glMatrixMode(javax
.media
.opengl
.GL
.GL_MODELVIEW
);
271 private void end(DrawContext dc
)
275 gl
.glMatrixMode(javax
.media
.opengl
.GL
.GL_MODELVIEW
);
278 gl
.glDisable(GL
.GL_LIGHT1
);
279 gl
.glEnable(GL
.GL_LIGHT0
);
280 gl
.glDisable(GL
.GL_LIGHTING
);
281 gl
.glDisable(GL
.GL_NORMALIZE
);
285 private static abstract class Shape
287 protected int objectId
;
288 protected GLUquadric quadric
;
289 protected boolean isInitialized
= false;
291 abstract protected void doRender(DrawContext dc
, Vec4 point
, double radius
);
293 protected void initialize(DrawContext dc
)
295 this.objectId
= dc
.getGL().glGenLists(1);
296 this.quadric
= dc
.getGLU().gluNewQuadric();
297 dc
.getGLU().gluQuadricDrawStyle(quadric
, GLU
.GLU_FILL
);
298 dc
.getGLU().gluQuadricNormals(quadric
, GLU
.GLU_SMOOTH
);
299 dc
.getGLU().gluQuadricOrientation(quadric
, GLU
.GLU_OUTSIDE
);
300 dc
.getGLU().gluQuadricTexture(quadric
, false);
303 private void dispose()
305 if (this.isInitialized
)
308 glu
.gluDeleteQuadric(this.quadric
);
309 // TODO: Determine how to release the opengl object ID.
313 private void render(DrawContext dc
, Vec4 point
, double radius
)
315 dc
.getView().pushReferenceCenter(dc
, point
);
316 this.doRender(dc
, point
, radius
);
317 dc
.getView().popReferenceCenter(dc
);
321 private static class Sphere
extends Shape
323 protected void initialize(DrawContext dc
)
325 super.initialize(dc
);
331 dc
.getGL().glNewList(this.objectId
, GL
.GL_COMPILE
);
332 dc
.getGLU().gluSphere(quadric
, radius
, slices
, stacks
);
333 dc
.getGL().glEndList();
335 this.isInitialized
= true;
338 protected void doRender(DrawContext dc
, Vec4 point
, double radius
)
340 dc
.getGL().glScaled(radius
, radius
, radius
);
341 dc
.getGL().glCallList(this.objectId
);
345 private static class Cone
extends Shape
347 protected void initialize(DrawContext dc
)
349 super.initialize(dc
);
355 dc
.getGL().glNewList(this.objectId
, GL
.GL_COMPILE
);
356 dc
.getGLU().gluCylinder(quadric
, 1d
, 0d
, 2d
, slices
, (int) (2 * (Math
.sqrt(stacks
)) + 1));
357 dc
.getGLU().gluDisk(quadric
, 0d
, 1d
, slices
, loops
);
358 dc
.getGL().glEndList();
360 this.isInitialized
= true;
363 protected void doRender(DrawContext dc
, Vec4 point
, double size
)
365 PolarPoint p
= PolarPoint
.fromCartesian(point
);
367 dc
.getGL().glLoadIdentity();
368 dc
.getGL().glScaled(size
, size
, size
);
369 dc
.getGL().glRotated(p
.getLongitude().getDegrees(), 0, 1, 0);
370 dc
.getGL().glRotated(Math
.abs(p
.getLatitude().getDegrees()), Math
.signum(p
.getLatitude().getDegrees()) * -1,
372 dc
.getGL().glCallList(this.objectId
);
376 private static class Cylinder
extends Shape
378 protected void initialize(DrawContext dc
)
380 super.initialize(dc
);
386 dc
.getGL().glNewList(this.objectId
, GL
.GL_COMPILE
);
387 dc
.getGLU().gluCylinder(quadric
, 1d
, 1d
, 2d
, slices
, (int) (2 * (Math
.sqrt(stacks
)) + 1));
388 dc
.getGLU().gluDisk(quadric
, 0d
, 1d
, slices
, loops
);
389 dc
.getGL().glTranslated(0, 0, 2);
390 dc
.getGLU().gluDisk(quadric
, 0d
, 1d
, slices
, loops
);
391 dc
.getGL().glTranslated(0, 0, -2);
392 dc
.getGL().glEndList();
394 this.isInitialized
= true;
397 protected void doRender(DrawContext dc
, Vec4 point
, double size
)
399 PolarPoint p
= PolarPoint
.fromCartesian(point
);
401 dc
.getGL().glLoadIdentity();
402 dc
.getGL().glScaled(size
, size
, size
);
403 dc
.getGL().glRotated(p
.getLongitude().getDegrees(), 0, 1, 0);
404 dc
.getGL().glRotated(Math
.abs(p
.getLatitude().getDegrees()), Math
.signum(p
.getLatitude().getDegrees()) * -1,
406 dc
.getGL().glCallList(this.objectId
);