Update to Worldwind release 20070920
[worldwind-tracker.git] / gov / nasa / worldwind / render / Polyline.java
blobc2e4889288efde977507da6cccab77f8fa1dd6d6
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.render;
9 import com.sun.opengl.util.BufferUtil;
10 import gov.nasa.worldwind.Movable;
11 import gov.nasa.worldwind.geom.*;
12 import gov.nasa.worldwind.util.Logging;
14 import javax.media.opengl.GL;
15 import java.awt.*;
16 import java.nio.DoubleBuffer;
17 import java.util.*;
18 import java.util.List;
20 /**
21 * @author tag
22 * @version $Id: Polyline.java 2932 2007-09-19 19:41:34Z patrickmurris $
24 public class Polyline implements Renderable, Movable
26 private ArrayList<Position> positions;
27 private Vec4 referenceCenter;
28 private DoubleBuffer vertices;
29 private int antiAliasHint = GL.GL_FASTEST;
30 private Color color = Color.WHITE;
31 private boolean filled = false; // makes it a polygon
32 private boolean followGreatCircles = true;
33 private int numEdgeIntervals = 10;
34 private Position center;
36 public Polyline(Iterable<Position> positions)
38 if (positions == null)
40 String msg = Logging.getMessage("nullValue.PositionsListIsNull");
41 Logging.logger().severe(msg);
42 throw new IllegalArgumentException(msg);
45 this.setPositions(positions);
48 public Polyline(Iterable<LatLon> positions, double elevation)
50 if (positions == null)
52 String msg = Logging.getMessage("nullValue.PositionsListIsNull");
53 Logging.logger().severe(msg);
54 throw new IllegalArgumentException(msg);
57 this.setPositions(positions, elevation);
60 public Color getColor()
62 return color;
65 public void setColor(Color color)
67 if (color == null)
69 String msg = Logging.getMessage("nullValue.ColorIsNull");
70 Logging.logger().severe(msg);
71 throw new IllegalArgumentException(msg);
74 this.color = color;
77 public int getAntiAliasHint()
79 return antiAliasHint;
82 public void setAntiAliasHint(int hint)
84 if (!(hint == GL.GL_DONT_CARE || hint == GL.GL_FASTEST || hint == GL.GL_NICEST))
86 String msg = Logging.getMessage("generic.InvalidHint");
87 Logging.logger().severe(msg);
88 throw new IllegalArgumentException(msg);
91 this.antiAliasHint = hint;
94 public boolean isFilled()
96 return filled;
99 public void setFilled(boolean filled)
101 this.filled = filled;
104 public boolean isFollowGreatCircles()
106 return followGreatCircles;
109 public void setFollowGreatCircles(boolean followGreatCircles)
111 this.followGreatCircles = followGreatCircles;
114 public int getNumEdgeIntervals()
116 return numEdgeIntervals;
119 public void setNumEdgeIntervals(int numEdgeIntervals)
121 this.numEdgeIntervals = numEdgeIntervals;
124 public void setPositions(Iterable<Position> inPositions)
126 if (inPositions == null)
128 String msg = Logging.getMessage("nullValue.PositionsListIsNull");
129 Logging.logger().severe(msg);
130 throw new IllegalArgumentException(msg);
133 this.positions = new ArrayList<Position>();
134 for (Position position : inPositions)
136 this.positions.add(position);
139 if ((this.filled && this.positions.size() < 3) || (!this.filled && this.positions.size() < 2))
141 String msg = Logging.getMessage("generic.InsufficientPositions");
142 Logging.logger().severe(msg);
143 throw new IllegalArgumentException(msg);
146 this.vertices = null;
149 public void setPositions(Iterable<LatLon> inPositions, double elevation)
151 if (inPositions == null)
153 String msg = Logging.getMessage("nullValue.PositionsListIsNull");
154 Logging.logger().severe(msg);
155 throw new IllegalArgumentException(msg);
158 this.positions = new ArrayList<Position>();
159 for (LatLon position : inPositions)
161 this.positions.add(new Position(position, elevation));
164 if (this.positions.size() < 2 || (this.filled && this.positions.size() < 3))
166 String msg = Logging.getMessage("generic.InsufficientPositions");
167 Logging.logger().severe(msg);
168 throw new IllegalArgumentException(msg);
171 this.vertices = null;
174 public Iterable<Position> getPositions()
176 return this.positions;
179 private void intializeGeometry(DrawContext dc)
181 if (this.positions.size() < 2)
182 return;
184 double[] refCenter = new double[3];
185 if (this.followGreatCircles)
186 this.vertices = this.makeGreatCircleVertices(dc, this.positions, refCenter);
187 else
188 this.vertices = makeVertices(dc, this.positions, refCenter);
189 this.referenceCenter = new Vec4(refCenter[0], refCenter[1], refCenter[2]);
191 double avgX = this.referenceCenter.x;
192 double avgY = this.referenceCenter.y;
193 double avgZ = this.referenceCenter.z;
195 this.vertices.rewind();
196 for (int i = 0; i < this.vertices.limit(); i += 3)
198 this.vertices.put(i, this.vertices.get(i) - avgX);
199 this.vertices.put(i + 1, this.vertices.get(i + 1) - avgY);
200 this.vertices.put(i + 2, this.vertices.get(i + 2) - avgZ);
203 this.center = dc.getGlobe().computePositionFromPoint(this.referenceCenter);
206 protected DoubleBuffer makeVertices(DrawContext dc, List<Position> posList, double[] refCenter)
208 DoubleBuffer verts = BufferUtil.newDoubleBuffer(posList.size() * 3);
210 double avgX = 0;
211 double avgY = 0;
212 double avgZ = 0;
214 int n = 0;
215 for (Position p : posList)
217 Vec4 pt = dc.getGlobe().computePointFromPosition(p.getLatitude(), p.getLongitude(), p.getElevation());
218 verts.put(pt.x).put(pt.y).put(pt.z);
219 avgX += pt.x;
220 avgY += pt.y;
221 avgZ += pt.z;
222 ++n;
225 refCenter[0] = avgX / (double) n;
226 refCenter[1] = avgY / (double) n;
227 refCenter[2] = avgZ / (double) n;
229 return verts;
232 protected DoubleBuffer makeGreatCircleVertices(DrawContext dc, List<Position> posList, double[] refCenter)
234 if (posList.size() < 1)
235 return null;
237 int size = posList.size() + (this.numEdgeIntervals - 1) * (posList.size() - 1);
238 DoubleBuffer verts = BufferUtil.newDoubleBuffer(size * 3);
240 double avgX = 0;
241 double avgY = 0;
242 double avgZ = 0;
243 int n = 0;
245 Iterator<Position> iter = posList.iterator();
246 Position pos = iter.next();
247 Vec4 pt = dc.getGlobe().computePointFromPosition(pos.getLatitude(), pos.getLongitude(), pos.getElevation());
248 verts.put(pt.x);
249 verts.put(pt.y);
250 verts.put(pt.z);
251 avgX += pt.x;
252 avgY += pt.y;
253 avgZ += pt.z;
254 ++n;
256 double delta = 1d / this.numEdgeIntervals;
257 while (iter.hasNext())
259 Position posNext = iter.next();
260 for (int i = 1; i < numEdgeIntervals; i++)
262 LatLon ll = LatLon.interpolate(i * delta, new LatLon(pos.getLatitude(), pos.getLongitude()),
263 new LatLon(posNext.getLatitude(), posNext.getLongitude()));
264 double elevation = (1d - i * delta) * pos.getElevation() + (i * delta) * posNext.getElevation();
265 pt = dc.getGlobe().computePointFromPosition(ll.getLatitude(), ll.getLongitude(), elevation);
266 verts.put(pt.x).put(pt.y).put(pt.z);
267 avgX += pt.x;
268 avgY += pt.y;
269 avgZ += pt.z;
270 ++n;
273 pt = dc.getGlobe().computePointFromPosition(posNext.getLatitude(), posNext.getLongitude(),
274 posNext.getElevation());
275 verts.put(pt.x).put(pt.y).put(pt.z);
276 avgX += pt.x;
277 avgY += pt.y;
278 avgZ += pt.z;
279 ++n;
281 pos = posNext;
284 refCenter[0] = avgX / (double) n;
285 refCenter[1] = avgY / (double) n;
286 refCenter[2] = avgZ / (double) n;
288 return verts;
291 public void render(DrawContext dc)
293 if (dc == null)
295 String message = Logging.getMessage("nullValue.DrawContextIsNull");
296 Logging.logger().severe(message);
297 throw new IllegalStateException(message);
300 if (this.vertices == null)
302 this.intializeGeometry(dc);
304 if (this.vertices == null)
305 return; // TODO: logger a warning
308 GL gl = dc.getGL();
310 int attrBits = GL.GL_HINT_BIT | GL.GL_CURRENT_BIT;
311 if (!dc.isPickingMode())
313 if (this.color.getAlpha() != 255)
314 attrBits |= GL.GL_COLOR_BUFFER_BIT;
317 gl.glPushAttrib(attrBits);
318 gl.glPushClientAttrib(GL.GL_CLIENT_VERTEX_ARRAY_BIT);
319 dc.getView().pushReferenceCenter(dc, this.referenceCenter);
323 if (!dc.isPickingMode())
325 if (this.color.getAlpha() != 255)
327 gl.glEnable(GL.GL_BLEND);
328 gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
330 dc.getGL().glColor4ub((byte) this.color.getRed(), (byte) this.color.getGreen(),
331 (byte) this.color.getBlue(), (byte) this.color.getAlpha());
334 int hintAttr = GL.GL_LINE_SMOOTH_HINT;
335 if (this.filled)
336 hintAttr = GL.GL_POLYGON_SMOOTH_HINT;
337 gl.glHint(hintAttr, this.antiAliasHint);
339 gl.glEnableClientState(GL.GL_VERTEX_ARRAY);
340 gl.glVertexPointer(3, GL.GL_DOUBLE, 0, this.vertices.rewind());
342 int primType = GL.GL_LINE_STRIP;
343 if (this.filled)
344 primType = GL.GL_POLYGON;
345 gl.glDrawArrays(primType, 0, this.vertices.capacity() / 3);
347 finally
349 gl.glPopClientAttrib();
350 gl.glPopAttrib();
351 dc.getView().popReferenceCenter(dc);
355 public Position getReferencePosition()
357 return this.center;
360 public void move(Position position)
362 if (position == null)
364 String msg = Logging.getMessage("nullValue.PositionIsNull");
365 Logging.logger().severe(msg);
366 throw new IllegalArgumentException(msg);
369 for (int i = 0; i < this.positions.size(); i++)
371 this.positions.set(i, this.positions.get(i).add(position));
374 this.vertices = null;
377 public void moveTo(Position position)
379 if (position == null)
381 String msg = Logging.getMessage("nullValue.PositionIsNull");
382 Logging.logger().severe(msg);
383 throw new IllegalArgumentException(msg);
386 Position delta = position.subtract(this.getReferencePosition());
387 this.move(delta);