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
.geom
;
9 import gov
.nasa
.worldwind
.*;
10 import gov
.nasa
.worldwind
.layers
.*;
12 import javax
.media
.opengl
.*;
14 import java
.awt
.image
.*;
16 import java
.util
.List
;
18 import com
.sun
.opengl
.util
.texture
.*;
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
;
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
);
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
)));
74 Sector
[] sectors
= this.computeSplitSectors(this.positions
);
75 this.tiles
.add(new TextureTile(sectors
[0]));
76 this.tiles
.add(new TextureTile(sectors
[1]));
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();
105 double lon
= pos
.getLongitude().getDegrees();
106 if (lon
<= 0 && lon
> maxWest
)
108 if (lon
>= 0 && lon
< minEast
)
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
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
134 public void dispose()
136 if (this.tiles
.size() > 0)
137 for (TextureTile tile
: this.tiles
)
144 public ArrayList
<Sector
> getSectors()
146 ArrayList
<Sector
> sectors
= new ArrayList
<Sector
>();
147 for (TextureTile tile
: this.tiles
)
149 sectors
.add(tile
.getSector());
154 public List
<LatLon
> getPositions()
159 public Paint
getPaint()
164 public void setPaint(Paint paint
)
167 this.clearTextureData();
170 public Color
getBorderColor()
175 public void setBorderColor(Color borderColor
)
177 this.borderColor
= borderColor
;
178 this.clearTextureData();
181 public Dimension
getTextureSize()
186 public void setTextureSize(Dimension textureSize
)
188 this.textureSize
= textureSize
;
189 this.clearTextureData();
192 public Stroke
getStroke()
197 public void setStroke(Stroke stroke
)
199 this.stroke
= stroke
;
200 this.clearTextureData();
203 public boolean isDrawBorder()
208 public void setDrawBorder(boolean drawBorder
)
210 this.drawBorder
= drawBorder
;
211 this.clearTextureData();
214 public boolean isDrawInterior()
219 public void setDrawInterior(boolean drawInterior
)
221 this.drawInterior
= drawInterior
;
222 this.clearTextureData();
225 public boolean isAntiAlias()
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
))
257 public void render(DrawContext dc
)
259 if (!this.intersects(dc
.getVisibleSector()))
262 if (!this.tiles
.get(0).holdsTexture())
263 makeTextureData(this.textureSize
);
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
);
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());
351 // Dispose of any current textures
352 for (TextureTile tile
: oldTiles
)
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());