Worldwind public release 0.2.1
[worldwind-tracker.git] / gov / nasa / worldwind / geom / SurfaceShape.java
blob851cfd4f2895ededbe00e03d8547ce6e69a39ede
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.geom;
9 import gov.nasa.worldwind.*;
10 import gov.nasa.worldwind.layers.*;
12 import javax.media.opengl.*;
13 import java.awt.*;
14 import java.awt.image.*;
15 import java.util.*;
16 import java.util.List;
18 import com.sun.opengl.util.texture.*;
20 /**
21 * @author tag
22 * @version $Id: SurfaceShape.java 2234 2007-07-07 00:10:08Z tgaskins $
24 public abstract class SurfaceShape implements Renderable, Disposable, Movable
26 private static final Color DEFAULT_COLOR = new Color(1f, 1f, 0f, 0.4f);
27 private static final Color DEFAULT_BORDER_COLOR = new Color(1f, 1f, 0f, 0.7f);
28 private static final Dimension DEFAULT_TEXTURE_SIZE = new Dimension(512, 512);
29 private static final double DEFAULT_NUM_EDGE_INTERVALS_PER_DEGREE = 1;
31 private ArrayList<TextureTile> tiles = new ArrayList<TextureTile>();
32 private Dimension textureSize = DEFAULT_TEXTURE_SIZE;
33 private Paint paint;
34 private Color borderColor;
35 private Stroke stroke = new BasicStroke();
36 private boolean drawBorder = true;
37 private boolean drawInterior = true;
38 private boolean antiAlias = true;
39 private double numEdgeIntervalsPerDegree = DEFAULT_NUM_EDGE_INTERVALS_PER_DEGREE;
40 private ArrayList<LatLon> positions = new ArrayList<LatLon>();
42 protected abstract BufferedImage drawShape(BufferedImage image, Sector sector);
44 public SurfaceShape(Iterable<LatLon> positions, Color color, Color borderColor)
46 if (positions == null)
48 String message = WorldWind.retrieveErrMsg("nullValue.PositionsListIsNull");
49 WorldWind.logger().log(java.util.logging.Level.FINE, message);
50 throw new IllegalArgumentException(message);
53 // Copy positions list.
54 for (LatLon posNext : positions)
56 this.positions.add(posNext);
59 // Make tile(s)
60 createTextureTiles();
61 // Set draw attributes
62 this.paint = color != null ? color : DEFAULT_COLOR;
63 this.borderColor = borderColor != null ? borderColor : DEFAULT_BORDER_COLOR;
66 private void createTextureTiles()
68 if (!LatLon.positionsCrossLongitudeBoundary(this.positions))
70 this.tiles.add(new TextureTile(Sector.boundingSector(this.positions)));
72 else
74 Sector[] sectors = this.computeSplitSectors(this.positions);
75 this.tiles.add(new TextureTile(sectors[0]));
76 this.tiles.add(new TextureTile(sectors[1]));
80 /**
81 * Returns two 'mirror' sectors each on one side of the longitude boundary - for boundary crossing shapes
83 * @param positions the shape positions
84 * @return an array of two sectors representing the shape
86 private Sector[] computeSplitSectors(ArrayList<LatLon> positions)
88 Sector[] sectors = new Sector[2];
89 // Find out longitude extremes for each sides
90 double maxWest = Angle.NEG180.getDegrees();
91 double minEast = Angle.POS180.getDegrees();
92 // Find out absolute latitude extremes
93 double minSouth = Angle.POS90.getDegrees();
94 double maxNorth = Angle.NEG90.getDegrees();
96 LatLon lastPos = null;
97 for (LatLon pos : positions)
99 double lat = pos.getLatitude().getDegrees();
100 if (lat > maxNorth)
101 maxNorth = lat;
102 if (lat < minSouth)
103 minSouth = lat;
105 double lon = pos.getLongitude().getDegrees();
106 if (lon <= 0 && lon > maxWest)
107 maxWest = lon;
108 if (lon >= 0 && lon < minEast)
109 minEast = lon;
111 if (lastPos != null)
113 double lastLon = lastPos.getLongitude().getDegrees();
114 if (Math.signum(lon) != Math.signum(lastLon))
115 if (Math.abs(lon - lastLon) < 180)
117 // Crossing the zero longitude line too
118 maxWest = 0;
119 minEast = 0;
122 lastPos = pos;
124 // Mirror the two sectors - same longitude span
125 maxWest = minEast < -maxWest ? -minEast : maxWest;
126 minEast = minEast > -maxWest ? -maxWest : minEast;
128 sectors[0] = Sector.fromDegrees(minSouth, maxNorth, minEast, 180d); // East side
129 sectors[1] = Sector.fromDegrees(minSouth, maxNorth, -180d, maxWest); // West side
131 return sectors;
134 public void dispose()
136 if (this.tiles.size() > 0)
137 for (TextureTile tile : this.tiles)
139 tile.dispose();
141 tiles.clear();
144 public ArrayList<Sector> getSectors()
146 ArrayList<Sector> sectors = new ArrayList<Sector>();
147 for (TextureTile tile : this.tiles)
149 sectors.add(tile.getSector());
151 return sectors;
154 public List<LatLon> getPositions()
156 return positions;
159 public Paint getPaint()
161 return paint;
164 public void setPaint(Paint paint)
166 this.paint = paint;
167 this.clearTextureData();
170 public Color getBorderColor()
172 return borderColor;
175 public void setBorderColor(Color borderColor)
177 this.borderColor = borderColor;
178 this.clearTextureData();
181 public Dimension getTextureSize()
183 return textureSize;
186 public void setTextureSize(Dimension textureSize)
188 this.textureSize = textureSize;
189 this.clearTextureData();
192 public Stroke getStroke()
194 return stroke;
197 public void setStroke(Stroke stroke)
199 this.stroke = stroke;
200 this.clearTextureData();
203 public boolean isDrawBorder()
205 return drawBorder;
208 public void setDrawBorder(boolean drawBorder)
210 this.drawBorder = drawBorder;
211 this.clearTextureData();
214 public boolean isDrawInterior()
216 return drawInterior;
219 public void setDrawInterior(boolean drawInterior)
221 this.drawInterior = drawInterior;
222 this.clearTextureData();
225 public boolean isAntiAlias()
227 return antiAlias;
230 public void setAntiAlias(boolean antiAlias)
232 this.antiAlias = antiAlias;
233 this.clearTextureData();
236 public double getNumEdgeIntervalsPerDegree()
238 return numEdgeIntervalsPerDegree;
241 public void setNumEdgeIntervalsPerDegree(double numEdgeIntervals)
243 this.numEdgeIntervalsPerDegree = numEdgeIntervals;
244 this.clearTextureData();
247 private boolean intersects(Sector sector)
249 for (TextureTile tile : this.tiles)
251 if (tile.getSector().intersects(sector))
252 return true;
254 return false;
257 public void render(DrawContext dc)
259 if (!this.intersects(dc.getVisibleSector()))
260 return;
262 if (!this.tiles.get(0).holdsTexture())
263 makeTextureData(this.textureSize);
265 GL gl = dc.getGL();
267 gl.glPushAttrib(GL.GL_COLOR_BUFFER_BIT | GL.GL_POLYGON_BIT);
271 if (!dc.isPickingMode())
273 gl.glEnable(GL.GL_BLEND);
274 gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
277 gl.glPolygonMode(GL.GL_FRONT, GL.GL_FILL);
278 gl.glEnable(GL.GL_CULL_FACE);
279 gl.glCullFace(GL.GL_BACK);
281 dc.getSurfaceTileRenderer().renderTiles(dc, this.tiles);
283 finally
285 gl.glPopAttrib();
289 private void makeTextureData(Dimension size)
291 for (TextureTile tile : this.tiles)
293 BufferedImage image = new BufferedImage((int) size.getWidth(), (int) size.getHeight(),
294 BufferedImage.TYPE_4BYTE_ABGR);
296 TextureData td = new TextureData(GL.GL_RGBA, GL.GL_RGBA, false,
297 this.drawShape(image, tile.getSector()));
298 td.setMustFlipVertically(false);
299 tile.setTextureData(td);
303 private void clearTextureData()
305 for (TextureTile tile : this.tiles)
307 if (tile.getTextureData() != null)
308 tile.setTextureData(null);
310 if (tile.holdsTexture())
311 tile.setTexture(null);
315 public Position getReferencePosition()
317 LatLon centroid = this.tiles.get(0).getSector().getCentroid();
318 return new Position(centroid, 0);
321 public void move(Position position)
323 if (position == null)
325 String msg = WorldWind.retrieveErrMsg("nullValue.PositionIsNull");
326 WorldWind.logger().log(java.util.logging.Level.FINE, msg);
327 throw new IllegalArgumentException(msg);
330 for (int i = 0; i < this.positions.size(); i++)
332 this.positions.set(i, this.positions.get(i).add(position));
335 ArrayList<TextureTile> oldTiles = this.tiles;
336 this.tiles = new ArrayList<TextureTile>(oldTiles.size());
337 this.createTextureTiles();
339 // Re-use the existing texture if possible.
340 if (oldTiles.size() == 1 && this.tiles.size() == 1)
342 TextureTile oldTile = oldTiles.get(0);
343 TextureTile newTile = this.tiles.get(0);
344 if (oldTile.getTextureData() != null)
345 newTile.setTextureData(oldTile.getTextureData());
346 if (oldTile.holdsTexture())
347 newTile.setTexture(oldTile.getTexture());
349 else
351 // Dispose of any current textures
352 for (TextureTile tile : oldTiles)
354 tile.dispose();
359 public void moveTo(Position position)
361 if (position == null)
363 String msg = WorldWind.retrieveErrMsg("nullValue.PositionIsNull");
364 WorldWind.logger().log(java.util.logging.Level.FINE, msg);
365 throw new IllegalArgumentException(msg);
368 Position delta = position.subtract(this.getReferencePosition());
369 this.move(delta);