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
.tracks
;
9 import gov
.nasa
.worldwind
.Disposable
;
10 import gov
.nasa
.worldwind
.geom
.*;
11 import gov
.nasa
.worldwind
.globes
.SectorGeometryList
;
12 import gov
.nasa
.worldwind
.layers
.Layer
;
13 import gov
.nasa
.worldwind
.render
.*;
14 import gov
.nasa
.worldwind
.util
.Logging
;
16 import javax
.media
.opengl
.GL
;
17 import javax
.media
.opengl
.glu
.*;
23 public class TrackRenderer
implements Disposable
25 private int lowerLimit
= 0;
26 private int upperLimit
= Integer
.MAX_VALUE
;
27 private double markerPixels
= 10d
; // TODO: these should all be configurable
28 private double minMarkerSize
= 5d
;
29 private double markerElevation
= 10d
;
30 private boolean overrideMarkerElevation
= false;
31 private Material material
= Material
.WHITE
;
32 private String iconFilePath
;
33 private final TrackRenderer
.Shape SPHERE
= new TrackRenderer
.Sphere();
34 private final TrackRenderer
.Shape CONE
= new TrackRenderer
.Cone();
35 private final TrackRenderer
.Shape CYLINDER
= new TrackRenderer
.Cylinder();
36 private TrackRenderer
.Shape shape
= SPHERE
;
38 public TrackRenderer()
45 this.CYLINDER
.dispose();
46 this.SPHERE
.dispose();
49 public double getMarkerPixels()
54 public void setMarkerPixels(double markerPixels
)
56 this.markerPixels
= markerPixels
;
59 public double getMinMarkerSize()
64 public void setMinMarkerSize(double minMarkerSize
)
66 this.minMarkerSize
= minMarkerSize
;
69 public double getMarkerElevation()
71 return markerElevation
;
74 public void setMarkerElevation(double markerElevation
)
76 this.markerElevation
= markerElevation
;
79 public boolean isOverrideMarkerElevation()
81 return overrideMarkerElevation
;
84 public void setOverrideMarkerElevation(boolean overrideMarkerElevation
)
86 this.overrideMarkerElevation
= overrideMarkerElevation
;
89 public Material
getMaterial()
94 public void setMaterial(Material material
)
98 String msg
= Logging
.getMessage("nullValue.MaterialIsNull");
99 Logging
.logger().severe(msg
);
100 throw new IllegalArgumentException(msg
);
103 // don't validate material's colors - material does that.
105 this.material
= material
;
108 public String
getIconFilePath()
113 public void setIconFilePath(String iconFilePath
)
115 //don't validate - a null iconFilePath cancels icon drawing
116 this.iconFilePath
= iconFilePath
;
119 public int getLowerLimit()
121 return this.lowerLimit
;
124 public void setLowerLimit(int lowerLimit
)
126 this.lowerLimit
= lowerLimit
;
129 public int getUpperLimit()
131 return this.upperLimit
;
134 public void setUpperLimit(int upperLimit
)
136 this.upperLimit
= upperLimit
;
139 public void setShapeType(String shapeName
)
141 if (shapeName
.equalsIgnoreCase("Cone"))
143 else if (shapeName
.equalsIgnoreCase("Cylinder"))
144 this.shape
= CYLINDER
;
149 public void pick(DrawContext dc
, java
.util
.Iterator
<TrackPoint
> trackPositions
, java
.awt
.Point pickPoint
,
155 public Vec4
render(DrawContext dc
, java
.util
.Iterator
<TrackPoint
> trackPositions
)
157 return this.draw(dc
, trackPositions
);
160 private Vec4
draw(DrawContext dc
, java
.util
.Iterator
<TrackPoint
> trackPositions
)
162 if (dc
.getVisibleSector() == null)
165 SectorGeometryList geos
= dc
.getSurfaceGeometry();
169 if (!this.shape
.isInitialized
)
170 this.shape
.initialize(dc
);
173 java
.util
.List
<Vec4
> points
= new java
.util
.ArrayList
<Vec4
>();
174 while (trackPositions
.hasNext())
176 TrackPoint tp
= trackPositions
.next();
177 if (index
>= this.lowerLimit
&& index
<= this.upperLimit
)
179 Vec4 point
= this.computeSurfacePoint(dc
, tp
);
185 if (++index
>= this.upperLimit
)
189 if (points
.size() < 1)
192 Vec4 firstPoint
= points
.get(0);
193 Vec4 lastPointDrawn
= firstPoint
;
196 Vec4 previousDrawnPoint
= null;
198 double radius
= this.computeMarkerRadius(dc
, firstPoint
);
199 this.shape
.render(dc
, firstPoint
, radius
);
200 for (Vec4 point
: points
)
202 if (previousDrawnPoint
== null)
204 previousDrawnPoint
= firstPoint
;
205 continue; // skip over first point
208 // TODO: More sophisticated separation algorithm to gain frame-to-frame consistency
209 radius
= this.computeMarkerRadius(dc
, point
);
210 double separation
= point
.distanceTo3(previousDrawnPoint
);
211 double minSeparation
= 4d
* radius
;
212 if (separation
> minSeparation
)
214 if (!dc
.isPickingMode())
215 this.shape
.render(dc
, point
, radius
);
217 previousDrawnPoint
= point
;
218 lastPointDrawn
= point
;
224 Vec4 iconPoint
= points
.get(points
.size() - 1);
225 return iconPoint
!= null ? iconPoint
: lastPointDrawn
;
228 private Vec4
computeSurfacePoint(DrawContext dc
, TrackPoint pos
)
230 return dc
.getSurfaceGeometry().getSurfacePoint(Angle
.fromDegrees(pos
.getLatitude()),
231 Angle
.fromDegrees(pos
.getLongitude()),
232 this.overrideMarkerElevation ?
this.markerElevation
: pos
.getElevation());
235 private double computeMarkerRadius(DrawContext dc
, Vec4 point
)
237 double d
= point
.distanceTo3(dc
.getView().getEyePoint());
238 double radius
= this.markerPixels
* dc
.getView().computePixelSizeAtDistance(d
);
239 if (radius
< this.minMarkerSize
)
240 radius
= this.minMarkerSize
;
245 private void begin(DrawContext dc
)
248 Vec4 cameraPosition
= dc
.getView().getEyePoint();
251 GL
.GL_TEXTURE_BIT
| GL
.GL_ENABLE_BIT
| GL
.GL_CURRENT_BIT
| GL
.GL_LIGHTING_BIT
| GL
.GL_TRANSFORM_BIT
);
252 gl
.glDisable(GL
.GL_TEXTURE_2D
);
254 float[] lightPosition
=
255 {(float) (cameraPosition
.x
* 2), (float) (cameraPosition
.y
/ 2), (float) (cameraPosition
.z
), 0.0f
};
256 float[] lightDiffuse
= {1.0f
, 1.0f
, 1.0f
, 1.0f
};
257 float[] lightAmbient
= {1.0f
, 1.0f
, 1.0f
, 1.0f
};
258 float[] lightSpecular
= {1.0f
, 1.0f
, 1.0f
, 1.0f
};
260 this.material
.apply(gl
, GL
.GL_FRONT
);
262 gl
.glLightfv(GL
.GL_LIGHT1
, GL
.GL_POSITION
, lightPosition
, 0);
263 gl
.glLightfv(GL
.GL_LIGHT1
, GL
.GL_DIFFUSE
, lightDiffuse
, 0);
264 gl
.glLightfv(GL
.GL_LIGHT1
, GL
.GL_AMBIENT
, lightAmbient
, 0);
265 gl
.glLightfv(GL
.GL_LIGHT1
, GL
.GL_SPECULAR
, lightSpecular
, 0);
267 gl
.glDisable(GL
.GL_LIGHT0
);
268 gl
.glEnable(GL
.GL_LIGHT1
);
269 gl
.glEnable(GL
.GL_LIGHTING
);
270 gl
.glEnable(GL
.GL_NORMALIZE
);
272 gl
.glMatrixMode(javax
.media
.opengl
.GL
.GL_MODELVIEW
);
276 private void end(DrawContext dc
)
280 gl
.glMatrixMode(javax
.media
.opengl
.GL
.GL_MODELVIEW
);
283 gl
.glDisable(GL
.GL_LIGHT1
);
284 gl
.glEnable(GL
.GL_LIGHT0
);
285 gl
.glDisable(GL
.GL_LIGHTING
);
286 gl
.glDisable(GL
.GL_NORMALIZE
);
290 private static abstract class Shape
292 protected int objectId
;
293 protected GLUquadric quadric
;
294 protected boolean isInitialized
= false;
296 abstract protected void doRender(DrawContext dc
, Vec4 point
, double radius
);
298 protected void initialize(DrawContext dc
)
300 this.objectId
= dc
.getGL().glGenLists(1);
301 this.quadric
= dc
.getGLU().gluNewQuadric();
302 dc
.getGLU().gluQuadricDrawStyle(quadric
, GLU
.GLU_FILL
);
303 dc
.getGLU().gluQuadricNormals(quadric
, GLU
.GLU_SMOOTH
);
304 dc
.getGLU().gluQuadricOrientation(quadric
, GLU
.GLU_OUTSIDE
);
305 dc
.getGLU().gluQuadricTexture(quadric
, false);
308 private void dispose()
310 if (this.isInitialized
)
313 glu
.gluDeleteQuadric(this.quadric
);
314 // TODO: Determine how to release the opengl object ID.
318 private void render(DrawContext dc
, Vec4 point
, double radius
)
320 dc
.getView().pushReferenceCenter(dc
, point
);
321 this.doRender(dc
, point
, radius
);
322 dc
.getView().popReferenceCenter(dc
);
326 private static class Sphere
extends Shape
328 protected void initialize(DrawContext dc
)
330 super.initialize(dc
);
336 dc
.getGL().glNewList(this.objectId
, GL
.GL_COMPILE
);
337 dc
.getGLU().gluSphere(quadric
, radius
, slices
, stacks
);
338 dc
.getGL().glEndList();
340 this.isInitialized
= true;
343 protected void doRender(DrawContext dc
, Vec4 point
, double radius
)
345 dc
.getGL().glScaled(radius
, radius
, radius
);
346 dc
.getGL().glCallList(this.objectId
);
350 private static class Cone
extends Shape
352 protected void initialize(DrawContext dc
)
354 super.initialize(dc
);
360 dc
.getGL().glNewList(this.objectId
, GL
.GL_COMPILE
);
361 dc
.getGLU().gluCylinder(quadric
, 1d
, 0d
, 2d
, slices
, (int) (2 * (Math
.sqrt(stacks
)) + 1));
362 dc
.getGLU().gluDisk(quadric
, 0d
, 1d
, slices
, loops
);
363 dc
.getGL().glEndList();
365 this.isInitialized
= true;
368 protected void doRender(DrawContext dc
, Vec4 point
, double size
)
370 PolarPoint p
= PolarPoint
.fromCartesian(point
);
372 dc
.getGL().glLoadIdentity();
373 dc
.getGL().glScaled(size
, size
, size
);
374 dc
.getGL().glRotated(p
.getLongitude().getDegrees(), 0, 1, 0);
375 dc
.getGL().glRotated(Math
.abs(p
.getLatitude().getDegrees()), Math
.signum(p
.getLatitude().getDegrees()) * -1,
377 dc
.getGL().glCallList(this.objectId
);
381 private static class Cylinder
extends Shape
383 protected void initialize(DrawContext dc
)
385 super.initialize(dc
);
391 dc
.getGL().glNewList(this.objectId
, GL
.GL_COMPILE
);
392 dc
.getGLU().gluCylinder(quadric
, 1d
, 1d
, 2d
, slices
, (int) (2 * (Math
.sqrt(stacks
)) + 1));
393 dc
.getGLU().gluDisk(quadric
, 0d
, 1d
, slices
, loops
);
394 dc
.getGL().glTranslated(0, 0, 2);
395 dc
.getGLU().gluDisk(quadric
, 0d
, 1d
, slices
, loops
);
396 dc
.getGL().glTranslated(0, 0, -2);
397 dc
.getGL().glEndList();
399 this.isInitialized
= true;
402 protected void doRender(DrawContext dc
, Vec4 point
, double size
)
404 PolarPoint p
= PolarPoint
.fromCartesian(point
);
406 dc
.getGL().glLoadIdentity();
407 dc
.getGL().glScaled(size
, size
, size
);
408 dc
.getGL().glRotated(p
.getLongitude().getDegrees(), 0, 1, 0);
409 dc
.getGL().glRotated(Math
.abs(p
.getLatitude().getDegrees()), Math
.signum(p
.getLatitude().getDegrees()) * -1,
411 dc
.getGL().glCallList(this.objectId
);