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
.globes
;
9 import com
.sun
.opengl
.util
.BufferUtil
;
10 import gov
.nasa
.worldwind
.geom
.*;
11 import gov
.nasa
.worldwind
.render
.DrawContext
;
13 import java
.util
.ArrayList
;
17 * @version $Id: GlobeRectangularTessellator.java 3632 2007-11-28 03:28:17Z tgaskins $
19 public class GlobeRectangularTessellator
extends RectangularTessellator
21 private static final int DEFAULT_NUM_LAT_SUBDIVISIONS
= 5; // TODO: make configurable
22 private static final int DEFAULT_NUM_LON_SUBDIVISIONS
= 10; // TODO: make configurable
23 private static final int DEFAULT_DENSITY
= 20; // TODO: make configurable
25 private ArrayList
<RectTile
> topLevels
;
27 private int density
= DEFAULT_DENSITY
;
29 protected String
getCacheId()
31 return GlobeRectangularTessellator
.class.getName();
34 protected String
getCacheName()
39 protected Iterable
<RectTile
> getTopLevelTiles(DrawContext dc
)
41 if (this.topLevels
!= null)
42 return this.topLevels
;
44 return this.topLevels
= this.createTopLevelTiles(dc
);
47 protected ArrayList
<RectTile
> createTopLevelTiles(DrawContext dc
)
49 ArrayList
<RectTile
> tops
=
50 new ArrayList
<RectTile
>(DEFAULT_NUM_LAT_SUBDIVISIONS
* DEFAULT_NUM_LON_SUBDIVISIONS
);
52 this.globe
= dc
.getGlobe();
53 double deltaLat
= 180d
/ DEFAULT_NUM_LAT_SUBDIVISIONS
;
54 double deltaLon
= 360d
/ DEFAULT_NUM_LON_SUBDIVISIONS
;
55 Angle lastLat
= Angle
.NEG90
;
57 for (int row
= 0; row
< DEFAULT_NUM_LAT_SUBDIVISIONS
; row
++)
59 Angle lat
= lastLat
.addDegrees(deltaLat
);
60 if (lat
.getDegrees() + 1d
> 90d
)
63 Angle lastLon
= Angle
.NEG180
;
65 for (int col
= 0; col
< DEFAULT_NUM_LON_SUBDIVISIONS
; col
++)
67 Angle lon
= lastLon
.addDegrees(deltaLon
);
68 if (lon
.getDegrees() + 1d
> 180d
)
71 Sector tileSector
= new Sector(lastLat
, lat
, lastLon
, lon
);
72 tops
.add(this.createTile(dc
, tileSector
, 0));
81 protected RectTile
createTile(DrawContext dc
, Sector tileSector
, int level
)
83 Cylinder cylinder
= dc
.getGlobe().computeBoundingCylinder(1d
, tileSector
);
84 double cellSize
= tileSector
.getDeltaLatRadians() * dc
.getGlobe().getRadius() / this.density
;
86 return new RectTile(this, cylinder
, level
, this.density
, tileSector
, cellSize
);
89 public int getTargetResolution(DrawContext dc
, RectTile tile
)
91 return dc
.getGlobe().getElevationModel().getTargetResolution(dc
, tile
.sector
, tile
.density
);
94 public boolean acceptResolution(DrawContext dc
, RectTile tile
, int resolution
)
96 return tile
.ri
.resolution
>= resolution
;
100 public RenderInfo
buildVerts(DrawContext dc
, RectTile tile
, int resolution
, boolean makeSkirts
)
102 int density
= tile
.density
;
103 int numVertices
= (density
+ 3) * (density
+ 3);
104 java
.nio
.DoubleBuffer verts
= BufferUtil
.newDoubleBuffer(numVertices
* 3);
106 Globe globe
= dc
.getGlobe();
107 ElevationModel
.Elevations elevations
= globe
.getElevationModel().getElevations(tile
.sector
, resolution
);
109 Angle latMax
= tile
.sector
.getMaxLatitude();
110 Angle dLat
= tile
.sector
.getDeltaLat().divide(density
);
112 Angle lonMin
= tile
.sector
.getMinLongitude();
113 Angle lonMax
= tile
.sector
.getMaxLongitude();
114 Angle dLon
= tile
.sector
.getDeltaLon().divide(density
);
117 Angle lat
= tile
.sector
.getMinLatitude();
118 double verticalExaggeration
= dc
.getVerticalExaggeration();
119 double exaggeratedMinElevation
= makeSkirts ? globe
.getMinElevation() * verticalExaggeration
: 0;
121 LatLon centroid
= tile
.sector
.getCentroid();
122 Vec4 refCenter
= globe
.computePointFromPosition(centroid
.getLatitude(), centroid
.getLongitude(), 0d
);
124 for (int j
= 0; j
<= density
+ 2; j
++)
127 for (int i
= 0; i
<= density
+ 2; i
++)
129 double elevation
= verticalExaggeration
* elevations
.getElevation(lat
.radians
, lon
.radians
);
130 if (j
== 0 || j
>= tile
.density
+ 2 || i
== 0 || i
>= tile
.density
+ 2)
131 { // use abs to account for negative elevation.
132 elevation
-= exaggeratedMinElevation
>= 0 ? exaggeratedMinElevation
: -exaggeratedMinElevation
;
135 Vec4 p
= globe
.computePointFromPosition(lat
, lon
, elevation
);
136 verts
.put(iv
++, p
.x
- refCenter
.x
).put(iv
++, p
.y
- refCenter
.y
).put(iv
++, p
.z
- refCenter
.z
);
149 return new RenderInfo(density
, verts
, getTextureCoordinates(density
), refCenter
, elevations
.getResolution());
152 // public RenderInfo buildVerts(DrawContext dc, RectTile tile, int resolution, boolean makeSkirts)
154 // int density = tile.density;
155 // int numVertices = (density + 3) * (density + 3);
156 // java.nio.DoubleBuffer verts = BufferUtil.newDoubleBuffer(numVertices * 3);
158 // Globe globe = dc.getGlobe();
159 // ElevationModel.Elevations elevations = globe.getElevationModel().getElevations(tile.sector, resolution);
161 // double latMin = tile.sector.getMinLatitude().radians;
162 // double latMax = tile.sector.getMaxLatitude().radians;
163 // double dLat = (latMax - latMin) / density;
165 // double lonMin = tile.sector.getMinLongitude().radians;
166 // double lonMax = tile.sector.getMaxLongitude().radians;
167 // double dLon = (lonMax - lonMin) / density;
170 // double lat = latMin;
171 // double verticalExaggeration = dc.getVerticalExaggeration();
172 // double exaggeratedMinElevation = makeSkirts ? globe.getMinElevation() * verticalExaggeration : 0;
173 // double equatorialRadius = globe.getEquatorialRadius();
174 // double eccentricity = globe.getEccentricitySquared();
176 // LatLon centroid = tile.sector.getCentroid();
177 // Vec4 refCenter = globe.computePointFromPosition(centroid.getLatitude(), centroid.getLongitude(), 0d);
179 // for (int j = 0; j <= density + 2; j++)
181 // double cosLat = Math.cos(lat);
182 // double sinLat = Math.sin(lat);
183 // double rpm = equatorialRadius / Math.sqrt(1.0 - eccentricity * sinLat * sinLat);
184 // double lon = lonMin;
185 // for (int i = 0; i <= density + 2; i++)
187 // double elevation = verticalExaggeration * elevations.getElevation(lat, lon);
188 // if (j == 0 || j >= tile.density + 2 || i == 0 || i >= tile.density + 2)
189 // { // use abs to account for negative elevation.
190 // elevation -= exaggeratedMinElevation >= 0 ? exaggeratedMinElevation : -exaggeratedMinElevation;
193 // double x = ((rpm + elevation) * cosLat * Math.sin(lon)) - refCenter.x;
194 // double y = ((rpm * (1.0 - eccentricity) + elevation) * sinLat) - refCenter.y;
195 // double z = ((rpm + elevation) * cosLat * Math.cos(lon)) - refCenter.z;
197 // verts.put(iv++, x).put(iv++, y).put(iv++, z);
210 // return new RenderInfo(density, verts, getTextureCoordinates(density), refCenter,
211 // elevations.getResolution());
214 public GlobeRectangularTessellator
.CacheKey
createCacheKey(DrawContext dc
, RectTile tile
, int resolution
)
216 return new CacheKey(dc
.getGlobe(), tile
.sector
, resolution
, dc
.getVerticalExaggeration(), tile
.density
);
219 protected static class CacheKey
extends RectangularTessellator
.CacheKey
221 private final Globe globe
;
222 private final double verticalExaggeration
;
224 protected CacheKey(Globe globe
, Sector sector
, int resolution
, double verticalExaggeration
, int density
)
226 super(sector
, resolution
, density
);
229 this.verticalExaggeration
= verticalExaggeration
;
232 public boolean equals(Object o
)
234 if (this == o
) return true;
235 if (o
== null || getClass() != o
.getClass()) return false;
236 if (!super.equals(o
)) return false;
238 CacheKey cacheKey
= (CacheKey
) o
;
240 if (Double
.compare(cacheKey
.verticalExaggeration
, verticalExaggeration
) != 0) return false;
241 //noinspection RedundantIfStatement
242 if (globe
!= null ?
!globe
.equals(cacheKey
.globe
) : cacheKey
.globe
!= null) return false;
247 public int hashCode()
249 int result
= super.hashCode();
251 result
= 31 * result
+ (globe
!= null ? globe
.hashCode() : 0);
252 temp
= verticalExaggeration
!= +0.0d ? Double
.doubleToLongBits(verticalExaggeration
) : 0L;
253 result
= 31 * result
+ (int) (temp ^
(temp
>>> 32));
258 protected Vec4
getSurfacePoint(RectTile tile
, Angle latitude
, Angle longitude
, double metersOffset
)
260 Vec4 result
= super.getSurfacePoint(tile
, latitude
, longitude
);
261 if (metersOffset
!= 0 && result
!= null)
262 result
= applyOffset(this.globe
, result
, metersOffset
);
268 * Offsets <code>point</code> by <code>metersOffset</code> meters.
270 * @param globe the <code>Globe</code> from which to offset
271 * @param point the <code>Vec4</code> to offset
272 * @param metersOffset the magnitude of the offset
273 * @return <code>point</code> offset along its surface normal as if it were on <code>globe</code>
275 private static Vec4
applyOffset(Globe globe
, Vec4 point
, double metersOffset
)
277 Vec4 normal
= globe
.computeSurfaceNormalAtPoint(point
);
278 point
= Vec4
.fromLine3(point
, metersOffset
, normal
);