Updated to worldwind release 20070817
[worldwind-tracker.git] / gov / nasa / worldwind / tracks / TrackRenderer.java
blob6a475e2d68a3fadc6c9441b25899f47969332142
1 /*
2 Copyright (C) 2001, 2006 United States Government
3 as represented by the Administrator of the
4 National Aeronautics and Space Administration.
5 All Rights Reserved.
6 */
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.*;
19 /**
20 * @author tag
21 * @version $Id$
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()
42 public void dispose()
44 this.CONE.dispose();
45 this.CYLINDER.dispose();
46 this.SPHERE.dispose();
49 public double getMarkerPixels()
51 return markerPixels;
54 public void setMarkerPixels(double markerPixels)
56 this.markerPixels = markerPixels;
59 public double getMinMarkerSize()
61 return minMarkerSize;
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()
91 return material;
94 public void setMaterial(Material material)
96 if (material == null)
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()
110 return iconFilePath;
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"))
142 this.shape = CONE;
143 else if (shapeName.equalsIgnoreCase("Cylinder"))
144 this.shape = CYLINDER;
145 else
146 this.shape = SPHERE;
149 public void pick(DrawContext dc, java.util.Iterator<TrackPoint> trackPositions, java.awt.Point pickPoint,
150 Layer layer)
152 // TODO: picking
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)
163 return null;
165 SectorGeometryList geos = dc.getSurfaceGeometry();
166 if (geos == null)
167 return null;
169 if (!this.shape.isInitialized)
170 this.shape.initialize(dc);
172 int index = 0;
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);
180 if (point != null)
182 points.add(point);
185 if (++index >= this.upperLimit)
186 break;
189 if (points.size() < 1)
190 return null;
192 Vec4 firstPoint = points.get(0);
193 Vec4 lastPointDrawn = firstPoint;
194 this.begin(dc);
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;
222 this.end(dc);
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;
242 return radius;
245 private void begin(DrawContext dc)
247 GL gl = dc.getGL();
248 Vec4 cameraPosition = dc.getView().getEyePoint();
250 gl.glPushAttrib(
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);
273 gl.glPushMatrix();
276 private void end(DrawContext dc)
278 GL gl = dc.getGL();
280 gl.glMatrixMode(javax.media.opengl.GL.GL_MODELVIEW);
281 gl.glPopMatrix();
283 gl.glDisable(GL.GL_LIGHT1);
284 gl.glEnable(GL.GL_LIGHT0);
285 gl.glDisable(GL.GL_LIGHTING);
286 gl.glDisable(GL.GL_NORMALIZE);
287 gl.glPopAttrib();
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)
312 GLU glu = new GLU();
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);
332 double radius = 1;
333 int slices = 36;
334 int stacks = 18;
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);
356 int slices = 30;
357 int stacks = 30;
358 int loops = 2;
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,
376 0, 0);
377 dc.getGL().glCallList(this.objectId);
381 private static class Cylinder extends Shape
383 protected void initialize(DrawContext dc)
385 super.initialize(dc);
387 int slices = 30;
388 int stacks = 30;
389 int loops = 2;
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,
410 0, 0);
411 dc.getGL().glCallList(this.objectId);