Update to Worldwind release 0.4.1
[worldwind-tracker.git] / gov / nasa / worldwind / globes / GlobeRectangularTessellator.java
blob567cb04ef9393c968663ad3d8ae7699d92c83c28
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.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;
15 /**
16 * @author tag
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;
26 private Globe globe;
27 private int density = DEFAULT_DENSITY;
29 protected String getCacheId()
31 return GlobeRectangularTessellator.class.getName();
34 protected String getCacheName()
36 return "Terrain";
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)
61 lat = Angle.POS90;
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)
69 lon = Angle.POS180;
71 Sector tileSector = new Sector(lastLat, lat, lastLon, lon);
72 tops.add(this.createTile(dc, tileSector, 0));
73 lastLon = lon;
75 lastLat = lat;
78 return tops;
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;
99 @Override
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);
116 int iv = 0;
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++)
126 Angle lon = lonMin;
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);
138 if (i > density)
139 lon = lonMax;
140 else if (i != 0)
141 lon = lon.add(dLon);
143 if (j > density)
144 lat = latMax;
145 else if (j != 0)
146 lat = lat.add(dLat);
149 return new RenderInfo(density, verts, getTextureCoordinates(density), refCenter, elevations.getResolution());
152 // public RenderInfo buildVerts(DrawContext dc, RectTile tile, int resolution, boolean makeSkirts)
153 // {
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;
169 // int iv = 0;
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++)
180 // {
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++)
186 // {
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;
191 // }
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);
199 // if (i > density)
200 // lon = lonMax;
201 // else if (i != 0)
202 // lon += dLon;
203 // }
204 // if (j > density)
205 // lat = latMax;
206 // else if (j != 0)
207 // lat += dLat;
208 // }
210 // return new RenderInfo(density, verts, getTextureCoordinates(density), refCenter,
211 // elevations.getResolution());
212 // }
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);
228 this.globe = globe;
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;
244 return true;
247 public int hashCode()
249 int result = super.hashCode();
250 long temp;
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));
254 return result;
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);
264 return result;
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);
279 return point;