Worldwind public release 0.2.1
[worldwind-tracker.git] / gov / nasa / worldwind / TrackRenderer.java
blob31b4f77aa17fc3d905493112ad394e693f479e20
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;
9 import gov.nasa.worldwind.geom.*;
11 import javax.media.opengl.*;
12 import javax.media.opengl.glu.*;
14 /**
15 * @author tag
16 * @version $Id$
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()
37 public void dispose()
39 this.CONE.dispose();
40 this.CYLINDER.dispose();
41 this.SPHERE.dispose();
44 public double getMarkerPixels()
46 return markerPixels;
49 public void setMarkerPixels(double markerPixels)
51 this.markerPixels = markerPixels;
54 public double getMinMarkerSize()
56 return minMarkerSize;
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()
86 return material;
89 public void setMaterial(Material material)
91 if (material == null)
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()
105 return iconFilePath;
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"))
137 this.shape = CONE;
138 else if (shapeName.equalsIgnoreCase("Cylinder"))
139 this.shape = CYLINDER;
140 else
141 this.shape = SPHERE;
144 public void pick(DrawContext dc, java.util.Iterator<TrackPoint> trackPositions, java.awt.Point pickPoint,
145 Layer layer)
147 // TODO: picking
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)
158 return null;
160 SectorGeometryList geos = dc.getSurfaceGeometry();
161 if (geos == null)
162 return null;
164 if (!this.shape.isInitialized)
165 this.shape.initialize(dc);
167 int index = 0;
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);
175 if (point != null)
177 points.add(point);
180 if (++index >= this.upperLimit)
181 break;
184 if (points.size() < 1)
185 return null;
187 Vec4 firstPoint = points.get(0);
188 Vec4 lastPointDrawn = firstPoint;
189 this.begin(dc);
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;
217 this.end(dc);
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;
237 return radius;
240 private void begin(DrawContext dc)
242 GL gl = dc.getGL();
243 Vec4 cameraPosition = dc.getView().getEyePoint();
245 gl.glPushAttrib(
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);
268 gl.glPushMatrix();
271 private void end(DrawContext dc)
273 GL gl = dc.getGL();
275 gl.glMatrixMode(javax.media.opengl.GL.GL_MODELVIEW);
276 gl.glPopMatrix();
278 gl.glDisable(GL.GL_LIGHT1);
279 gl.glEnable(GL.GL_LIGHT0);
280 gl.glDisable(GL.GL_LIGHTING);
281 gl.glDisable(GL.GL_NORMALIZE);
282 gl.glPopAttrib();
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)
307 GLU glu = new GLU();
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);
327 double radius = 1;
328 int slices = 36;
329 int stacks = 18;
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);
351 int slices = 30;
352 int stacks = 30;
353 int loops = 2;
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,
371 0, 0);
372 dc.getGL().glCallList(this.objectId);
376 private static class Cylinder extends Shape
378 protected void initialize(DrawContext dc)
380 super.initialize(dc);
382 int slices = 30;
383 int stacks = 30;
384 int loops = 2;
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,
405 0, 0);
406 dc.getGL().glCallList(this.objectId);