gvsig-3d / 2.1 / trunk / org.gvsig.view3d / org.gvsig.view3d.swing / org.gvsig.view3d.swing.impl / src / main / java / org / gvsig / view3d / swing / impl / data / DefaultLayerConverter.java @ 461
History | View | Annotate | Download (10.5 KB)
1 | 446 | llmarques | /**
|
---|---|---|---|
2 | * gvSIG. Desktop Geographic Information System.
|
||
3 | *
|
||
4 | * Copyright ? 2007-2015 gvSIG Association
|
||
5 | *
|
||
6 | * This program is free software; you can redistribute it and/or
|
||
7 | * modify it under the terms of the GNU General Public License
|
||
8 | * as published by the Free Software Foundation; either version 2
|
||
9 | * of the License, or (at your option) any later version.
|
||
10 | *
|
||
11 | * This program is distributed in the hope that it will be useful,
|
||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
14 | * GNU General Public License for more details.
|
||
15 | *
|
||
16 | * You should have received a copy of the GNU General Public License
|
||
17 | * along with this program; if not, write to the Free Software
|
||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||
19 | * MA 02110-1301, USA.
|
||
20 | *
|
||
21 | * For any additional information, do not hesitate to contact us
|
||
22 | * at info AT gvsig.com, or visit our website www.gvsig.com.
|
||
23 | */
|
||
24 | |||
25 | package org.gvsig.view3d.swing.impl.data; |
||
26 | |||
27 | 450 | llmarques | import gov.nasa.worldwind.avlist.AVKey; |
28 | import gov.nasa.worldwind.avlist.AVList; |
||
29 | import gov.nasa.worldwind.avlist.AVListImpl; |
||
30 | 457 | llmarques | import gov.nasa.worldwind.geom.Angle; |
31 | import gov.nasa.worldwind.geom.LatLon; |
||
32 | 450 | llmarques | import gov.nasa.worldwind.geom.Sector; |
33 | import gov.nasa.worldwind.globes.ElevationModel; |
||
34 | import gov.nasa.worldwind.layers.Layer; |
||
35 | import gov.nasa.worldwind.layers.TiledImageLayer; |
||
36 | 457 | llmarques | import gov.nasa.worldwind.util.WWMath; |
37 | 450 | llmarques | |
38 | 446 | llmarques | import java.awt.geom.Point2D; |
39 | import java.security.MessageDigest; |
||
40 | import java.security.NoSuchAlgorithmException; |
||
41 | |||
42 | import org.cresques.cts.ICoordTrans; |
||
43 | import org.cresques.cts.IProjection; |
||
44 | import org.slf4j.Logger; |
||
45 | import org.slf4j.LoggerFactory; |
||
46 | import org.w3c.dom.Document; |
||
47 | |||
48 | import org.gvsig.fmap.crs.CRSFactory; |
||
49 | import org.gvsig.fmap.dal.exception.DataException; |
||
50 | import org.gvsig.fmap.geom.primitive.Envelope; |
||
51 | import org.gvsig.fmap.mapcontext.MapContext; |
||
52 | import org.gvsig.fmap.mapcontext.layers.FLayer; |
||
53 | 452 | llmarques | import org.gvsig.view3d.swing.impl.DefaultMapControl3D; |
54 | 446 | llmarques | |
55 | /**
|
||
56 | * @author <a href="mailto:lmarques@disid.com">Lluis Marques</a>
|
||
57 | *
|
||
58 | */
|
||
59 | public class DefaultLayerConverter implements LayerConverter { |
||
60 | |||
61 | 457 | llmarques | private static final Logger LOG = LoggerFactory |
62 | 446 | llmarques | .getLogger(DefaultLayerConverter.class); |
63 | |||
64 | 450 | llmarques | public Layer convertToLayer(MapContext mapContext, FLayer layer)
|
65 | throws DataException {
|
||
66 | 446 | llmarques | |
67 | AVList params = new AVListImpl();
|
||
68 | 457 | llmarques | |
69 | // Add Layer and MapContext to parameters.
|
||
70 | 452 | llmarques | params.setValue(DefaultMapControl3D.GVSIG_MAPCONTEXT, mapContext); |
71 | 457 | llmarques | params.setValue(DefaultMapControl3D.GVSIG_LAYER, layer); |
72 | |||
73 | 450 | llmarques | createRasterTiledImageLayerParams(layer, params); |
74 | 457 | llmarques | |
75 | 450 | llmarques | // Create configuration document from parameters.
|
76 | Document doc =
|
||
77 | TiledImageLayer.createTiledImageLayerConfigDocument(params); |
||
78 | 457 | llmarques | |
79 | 450 | llmarques | // Copy parameters to avoid problems
|
80 | AVList paramsLayer = params.copy(); |
||
81 | 446 | llmarques | |
82 | 450 | llmarques | RasterTiledImageLayer rasterLayer = |
83 | new RasterTiledImageLayer(doc.getDocumentElement(), paramsLayer);
|
||
84 | return rasterLayer;
|
||
85 | } |
||
86 | 446 | llmarques | |
87 | 450 | llmarques | public ElevationModel convertToElevationModel(MapContext mapContext,
|
88 | FLayer layer) { |
||
89 | // TODO Auto-generated method stub
|
||
90 | return null; |
||
91 | } |
||
92 | |||
93 | private String getUniqueCacheId(String name) { |
||
94 | 457 | llmarques | // TODO This is not valid. We have to take in account more properties
|
95 | // to get unique cache id
|
||
96 | 450 | llmarques | try {
|
97 | // Create MD5 Hash
|
||
98 | MessageDigest digest =
|
||
99 | java.security.MessageDigest.getInstance("MD5");
|
||
100 | digest.update(name.getBytes()); |
||
101 | byte messageDigest[] = digest.digest(); |
||
102 | |||
103 | // Create Hex String
|
||
104 | StringBuilder hexString = new StringBuilder(); |
||
105 | hexString.append(name); |
||
106 | hexString.append("-");
|
||
107 | for (int i = 0; i < messageDigest.length; i++) |
||
108 | hexString.append(Integer.toHexString(0xFF & messageDigest[i])); |
||
109 | return hexString.toString();
|
||
110 | |||
111 | } catch (NoSuchAlgorithmException e) { |
||
112 | 457 | llmarques | LOG.warn("MD5 algorith is not available", e);
|
113 | 450 | llmarques | return name;
|
114 | } |
||
115 | } |
||
116 | |||
117 | private void createRasterTiledImageLayerParams(FLayer layer, AVList params) { |
||
118 | |||
119 | 457 | llmarques | // TODO Get 3D propeties of layer with View3DManager.getProperties3D(layer)
|
120 | // and fill parameters with properties
|
||
121 | |||
122 | 450 | llmarques | if (params == null) { |
123 | params = new AVListImpl();
|
||
124 | } |
||
125 | |||
126 | params.setValue(AVKey.DATASET_NAME, layer.getName()); |
||
127 | params.setValue(AVKey.DATA_CACHE_NAME, |
||
128 | getUniqueCacheId(layer.getName())); |
||
129 | 457 | llmarques | params.setValue(AVKey.DISPLAY_NAME, layer.getName()); |
130 | params.setValue(AVKey.SERVICE_NAME, "Offline");
|
||
131 | 450 | llmarques | |
132 | MapContext mapContext = |
||
133 | 452 | llmarques | (MapContext) params.getValue(DefaultMapControl3D.GVSIG_MAPCONTEXT); |
134 | 446 | llmarques | |
135 | 450 | llmarques | Sector sector = null;
|
136 | try {
|
||
137 | sector = getSector(layer, mapContext.getProjection()); |
||
138 | } catch (DataException e) {
|
||
139 | 457 | llmarques | LOG.info("Can't create sector from layer and projection", e);
|
140 | 450 | llmarques | return;
|
141 | } |
||
142 | |||
143 | params.setValue(AVKey.SECTOR, sector); |
||
144 | 457 | llmarques | |
145 | // Set resolution of layer
|
||
146 | // TODO Make configurable by user
|
||
147 | 458 | llmarques | params.setValue(AVKey.WIDTH, Integer.MAX_VALUE);
|
148 | params.setValue(AVKey.HEIGHT,Integer.MAX_VALUE);
|
||
149 | 450 | llmarques | |
150 | 457 | llmarques | params.setValue(AVKey.IMAGE_FORMAT, "image/png");
|
151 | params.setValue(AVKey.PIXEL_FORMAT, AVKey.IMAGE); |
||
152 | params.setValue(AVKey.TEXTURE_FORMAT, "image/dds");
|
||
153 | params.setValue(AVKey.FORMAT_SUFFIX, ".png");
|
||
154 | params.setValue(AVKey.AVAILABLE_IMAGE_FORMATS, new String[] { params |
||
155 | .getValue(AVKey.IMAGE_FORMAT).toString() }); |
||
156 | params.setValue(AVKey.TILE_ORIGIN, new LatLon(sector.getMinLatitude(),
|
||
157 | sector.getMinLongitude())); |
||
158 | params.setValue(AVKey.TILE_WIDTH, 512);
|
||
159 | params.setValue(AVKey.TILE_HEIGHT, 512);
|
||
160 | 450 | llmarques | |
161 | 457 | llmarques | LatLon rasterTileDelta = this.computeRasterTileDelta(params);
|
162 | LatLon desiredLevelZeroDelta = this.computeDesiredTileDelta(sector);
|
||
163 | int numLevels = computeNumLevels(desiredLevelZeroDelta, rasterTileDelta);
|
||
164 | 450 | llmarques | |
165 | 457 | llmarques | params.setValue(AVKey.NUM_LEVELS, numLevels); |
166 | |||
167 | double scale = Math.pow(2d, numLevels - 1); |
||
168 | LatLon levelZeroTileDelta = LatLon.fromDegrees( |
||
169 | scale * rasterTileDelta.getLatitude().degrees, |
||
170 | scale * rasterTileDelta.getLongitude().degrees); |
||
171 | params.setValue(AVKey.LEVEL_ZERO_TILE_DELTA, levelZeroTileDelta); |
||
172 | 458 | llmarques | |
173 | 461 | llmarques | // Only rasterized vectorial layers
|
174 | 458 | llmarques | // params.setValue(AVKey.LEVEL_ZERO_TILE_DELTA, new
|
175 | // LatLon(Angle.fromDegrees(1), Angle.fromDegrees(1)));
|
||
176 | 450 | llmarques | |
177 | 457 | llmarques | params.setValue(AVKey.NETWORK_RETRIEVAL_ENABLED, false);
|
178 | params.setValue(AVKey.USE_MIP_MAPS, true);
|
||
179 | params.setValue(AVKey.USE_TRANSPARENT_TEXTURES, true);
|
||
180 | 450 | llmarques | |
181 | } |
||
182 | |||
183 | private Sector getSector(FLayer layer, IProjection projection)
|
||
184 | throws DataException {
|
||
185 | |||
186 | 446 | llmarques | ICoordTrans ct = projection.getCT(CRSFactory.getCRS("EPSG:4326"));
|
187 | Point2D p1 = null; |
||
188 | Point2D p2 = null; |
||
189 | 457 | llmarques | Envelope envelope = layer.getFullEnvelope(); |
190 | 446 | llmarques | |
191 | 457 | llmarques | p1 = |
192 | convert( |
||
193 | ct, |
||
194 | new Point2D.Double(envelope.getMinimum(0), envelope |
||
195 | .getMinimum(1)));
|
||
196 | p2 = |
||
197 | convert( |
||
198 | ct, |
||
199 | new Point2D.Double(envelope.getMaximum(0), envelope |
||
200 | .getMaximum(1)));
|
||
201 | |||
202 | 461 | llmarques | double minLatitude =
|
203 | Double.isInfinite(p1.getY()) || p1.getY() < Angle.NEG90.degrees
|
||
204 | ? Angle.NEG90.degrees : p1.getY(); |
||
205 | double maxLatitude =
|
||
206 | Double.isInfinite(p2.getY()) || p2.getY() > Angle.POS90.degrees
|
||
207 | ? Angle.POS90.degrees : p2.getY(); |
||
208 | double minLongitude =
|
||
209 | Double.isInfinite(p1.getX()) || p1.getX() < Angle.NEG180.degrees
|
||
210 | ? Angle.NEG180.degrees : p1.getX(); |
||
211 | double maxLongitude =
|
||
212 | Double.isInfinite(p2.getX()) || p2.getX() > Angle.POS180.degrees
|
||
213 | ? Angle.POS180.degrees : p2.getX(); |
||
214 | 446 | llmarques | |
215 | Sector sector = |
||
216 | 461 | llmarques | new Sector(Sector.fromDegrees(minLatitude,maxLatitude,
|
217 | 446 | llmarques | minLongitude, maxLongitude)); |
218 | |||
219 | 450 | llmarques | return sector;
|
220 | 446 | llmarques | } |
221 | 457 | llmarques | |
222 | private int computeNumLevels(LatLon levelZeroDelta, LatLon lastLevelDelta) { |
||
223 | // Compute the number of levels needed to achieve the given last level
|
||
224 | // tile delta, starting from the given
|
||
225 | // level zero tile delta.
|
||
226 | double numLatLevels =
|
||
227 | WWMath.logBase2(levelZeroDelta.getLatitude().getDegrees()) |
||
228 | - WWMath.logBase2(lastLevelDelta.getLatitude().getDegrees()); |
||
229 | double numLonLevels =
|
||
230 | WWMath.logBase2(levelZeroDelta.getLongitude().getDegrees()) |
||
231 | - WWMath.logBase2(lastLevelDelta.getLongitude().getDegrees()); |
||
232 | |||
233 | // Compute the maximum number of levels needed, but limit the number of
|
||
234 | // levels to positive integers greater
|
||
235 | // than or equal to one.
|
||
236 | int numLevels = (int) Math.ceil(Math.max(numLatLevels, numLonLevels)); |
||
237 | if (numLevels < 1) |
||
238 | numLevels = 1;
|
||
239 | |||
240 | return numLevels;
|
||
241 | } |
||
242 | |||
243 | private LatLon computeRasterTileDelta(AVList parameters) {
|
||
244 | |||
245 | Sector sector = (Sector) parameters.getValue(AVKey.SECTOR); |
||
246 | int width = (Integer) parameters.getValue(AVKey.WIDTH); |
||
247 | int height = (Integer) parameters.getValue(AVKey.HEIGHT); |
||
248 | int tileWidth = (Integer) parameters.getValue(AVKey.TILE_WIDTH); |
||
249 | int tileHeight = (Integer) parameters.getValue(AVKey.TILE_HEIGHT); |
||
250 | |||
251 | LatLon pixelSize = this.computeRasterPixelSize(sector, width, height);
|
||
252 | // Compute the tile size in latitude and longitude, given a raster's
|
||
253 | // sector and dimension, and the tile
|
||
254 | // dimensions. In this computation a pixel is assumed to cover a finite
|
||
255 | // area.
|
||
256 | double latDelta = tileHeight * pixelSize.getLatitude().degrees;
|
||
257 | double lonDelta = tileWidth * pixelSize.getLongitude().degrees;
|
||
258 | return LatLon.fromDegrees(latDelta, lonDelta);
|
||
259 | } |
||
260 | |||
261 | private LatLon computeRasterPixelSize(Sector sector, int width, int height) { |
||
262 | // Compute the raster's pixel dimension in latitude and longitude. In
|
||
263 | // this computation a pixel is assumed to
|
||
264 | // cover a finite area.
|
||
265 | return LatLon.fromDegrees(sector.getDeltaLatDegrees() / height,
|
||
266 | sector.getDeltaLonDegrees() / width); |
||
267 | } |
||
268 | |||
269 | private LatLon computeDesiredTileDelta(Sector sector) {
|
||
270 | return LatLon.fromDegrees(sector.getDeltaLatDegrees(), sector.getDeltaLonDegrees());
|
||
271 | } |
||
272 | |||
273 | private Point2D convert(ICoordTrans ct, Point2D point){ |
||
274 | if(ct == null){ |
||
275 | return point;
|
||
276 | } |
||
277 | |||
278 | return ct.convert(point, null); |
||
279 | } |
||
280 | |||
281 | 446 | llmarques | } |