Statistics
| Revision:

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 @ 497

History | View | Annotate | Download (17.8 KB)

1
/**
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
import gov.nasa.worldwind.avlist.AVKey;
28
import gov.nasa.worldwind.avlist.AVList;
29
import gov.nasa.worldwind.avlist.AVListImpl;
30
import gov.nasa.worldwind.cache.BasicDataFileStore;
31
import gov.nasa.worldwind.geom.Angle;
32
import gov.nasa.worldwind.geom.LatLon;
33
import gov.nasa.worldwind.geom.Sector;
34
import gov.nasa.worldwind.globes.ElevationModel;
35
import gov.nasa.worldwind.layers.Layer;
36
import gov.nasa.worldwind.layers.TiledImageLayer;
37
import gov.nasa.worldwind.util.WWMath;
38

    
39
import java.awt.geom.Point2D;
40
import java.io.File;
41
import java.security.MessageDigest;
42
import java.security.NoSuchAlgorithmException;
43

    
44
import org.cresques.cts.ICoordTrans;
45
import org.cresques.cts.IProjection;
46
import org.gvsig.fmap.crs.CRSFactory;
47
import org.gvsig.fmap.dal.coverage.dataset.Buffer;
48
import org.gvsig.fmap.dal.exception.DataException;
49
import org.gvsig.fmap.geom.primitive.Envelope;
50
import org.gvsig.fmap.mapcontext.layers.FLayer;
51
import org.gvsig.fmap.mapcontext.layers.operations.SingleLayer;
52
import org.gvsig.fmap.mapcontext.layers.vectorial.FLyrVect;
53
import org.gvsig.raster.fmap.layers.FLyrRaster;
54
import org.gvsig.view3d.lib.api.View3DLocator;
55
import org.gvsig.view3d.lib.api.View3DManager;
56
import org.gvsig.view3d.lib.api.properties.LayerProperties3D;
57
import org.gvsig.view3d.swing.api.MapControl3D;
58
import org.gvsig.view3d.swing.impl.DefaultMapControl3D;
59
import org.slf4j.Logger;
60
import org.slf4j.LoggerFactory;
61
import org.w3c.dom.Document;
62

    
63
/**
64
 * Default implementation of {@link LayerConverter}.
65
 *
66
 * @author <a href="mailto:lmarques@disid.com">Lluis Marques</a>
67
 */
68
public class DefaultLayerConverter implements LayerConverter {
69

    
70
    private static final Logger LOG = LoggerFactory
71
        .getLogger(DefaultLayerConverter.class);
72

    
73
    private final int DEFAULT_RASTERIZED_LEVEL_ZERO = 20;
74
    private final int DEFAULT_TILE_WIDTH = 512;
75
    private final int DEFAULT_TILE_HEIGHT = 512;
76

    
77
    public Layer convertToLayer(MapControl3D mapControl, FLayer layer)
78
        throws DataException {
79

    
80
        AVList params = new AVListImpl();
81

    
82
        // Add Layer and MapContext to parameters.
83
        params.setValue(DefaultMapControl3D.GVSIG_MAPCONTROL3D, mapControl);
84
        params.setValue(DefaultMapControl3D.GVSIG_LAYER, layer);
85

    
86
        createRasterTiledImageLayerParams(layer, params);
87

    
88
        // Create configuration document from parameters.
89
        Document doc =
90
            TiledImageLayer.createTiledImageLayerConfigDocument(params);
91

    
92
        // Copy parameters to avoid problems
93
        AVList paramsLayer = params.copy();
94

    
95
        DefaultTiledImageLayer rasterLayer =
96
            new DefaultTiledImageLayer(doc.getDocumentElement(), paramsLayer);
97
        return rasterLayer;
98
    }
99

    
100
    public ElevationModel convertToElevationModel(MapControl3D mapControl,
101
        FLayer layer) {
102

    
103
        AVList params = new AVListImpl();
104

    
105
        // Add Layer and MapContext to parameters.
106
        params.setValue(DefaultMapControl3D.GVSIG_MAPCONTROL3D, mapControl);
107
        params.setValue(DefaultMapControl3D.GVSIG_LAYER, layer);
108

    
109
        createElevationModelParams(layer, params);
110

    
111
        // Create configuration document from parameters.
112
        Document doc =
113
            TiledImageLayer.createTiledImageLayerConfigDocument(params);
114

    
115
        // Copy parameters to avoid problems
116
        AVList paramsLayer = params.copy();
117

    
118
        DefaultElevationModel elevationModel =
119
            new DefaultElevationModel(doc.getDocumentElement(), paramsLayer);
120
        return elevationModel;
121
    }
122

    
123
    private String getUniqueCacheId(FLayer layer) {
124
        // TODO This is not valid. We have to take in account more properties
125
        // to get unique cache id
126
        try {
127
            // Create MD5 Hash
128
            MessageDigest digest =
129
                java.security.MessageDigest.getInstance("MD5");
130

    
131
            String name = layer.getName();
132
            long drawVersion = layer.getDrawVersion();
133
            String dataStoreFullName = null;
134
            if (layer instanceof SingleLayer) {
135
                dataStoreFullName =
136
                    ((SingleLayer) layer).getDataStore().getFullName();
137
            }
138
            int hashCode = layer.hashCode();
139

    
140
            StringBuilder stb = new StringBuilder();
141
            stb.append(name);
142
            stb.append("$");
143
            stb.append(drawVersion);
144
            stb.append("$");
145
            stb.append(hashCode);
146
            stb.append("$");
147
            if (dataStoreFullName != null) {
148
                stb.append(dataStoreFullName);
149
                stb.append("$");
150
            }
151

    
152
            String id = stb.toString();
153
            digest.update(id.getBytes());
154
            byte messageDigest[] = digest.digest();
155

    
156
            // Create Hex String
157
            StringBuilder hexString = new StringBuilder();
158
            hexString.append(layer.getName());
159
            hexString.append("-");
160
            for (int i = 0; i < messageDigest.length; i++)
161
                hexString.append(Integer.toHexString(0xFF & messageDigest[i]));
162
            return hexString.toString();
163

    
164
        } catch (NoSuchAlgorithmException e) {
165
            LOG.warn("MD5 algorith is not available", e);
166

    
167
            String name = layer.getName();
168
            long drawVersion = layer.getDrawVersion();
169
            String dataStoreFullName = null;
170
            if (layer instanceof SingleLayer) {
171
                dataStoreFullName =
172
                    ((SingleLayer) layer).getDataStore().getFullName();
173
            }
174
            int hashCode = layer.hashCode();
175

    
176
            StringBuilder stb = new StringBuilder();
177
            stb.append(name);
178
            stb.append("$");
179
            stb.append(drawVersion);
180
            stb.append("$");
181
            stb.append(hashCode);
182
            stb.append("$");
183
            if (dataStoreFullName != null) {
184
                stb.append(dataStoreFullName);
185
                stb.append("$");
186
            }
187

    
188
            return stb.toString();
189
        }
190
    }
191

    
192
    private void createRasterTiledImageLayerParams(FLayer layer, AVList params) {
193

    
194
        if (params == null) {
195
            params = new AVListImpl();
196
        }
197

    
198
        setBasicParameters(layer, params);
199

    
200
        setSectorParameters(layer, params);
201

    
202
        // Set resolution of layer
203
        params.setValue(AVKey.WIDTH, Integer.MAX_VALUE);
204
        params.setValue(AVKey.HEIGHT, Integer.MAX_VALUE);
205
        params.setValue(AVKey.IMAGE_FORMAT, "image/png");
206
        params.setValue(AVKey.PIXEL_FORMAT, AVKey.IMAGE);
207
        params.setValue(AVKey.TEXTURE_FORMAT, "image/dds");
208
        params.setValue(AVKey.FORMAT_SUFFIX, ".png");
209
        params.setValue(AVKey.AVAILABLE_IMAGE_FORMATS, new String[] { params
210
            .getValue(AVKey.IMAGE_FORMAT).toString() });
211
        params.setValue(AVKey.NETWORK_RETRIEVAL_ENABLED, false);
212
        params.setValue(AVKey.USE_MIP_MAPS, true);
213
        params.setValue(AVKey.USE_TRANSPARENT_TEXTURES, true);
214
        
215
        Sector sector = (Sector) params.getValue(AVKey.SECTOR);
216

    
217
        setTileParameters(layer, sector, params);
218
        
219
        setDetailLevelParameters(layer,sector, params);
220
    }
221

    
222
    private void createElevationModelParams(FLayer layer, AVList params) {
223

    
224
        if (params == null) {
225
            params = new AVListImpl();
226
        }
227
        
228
        setBasicParameters(layer,params);
229

    
230
        setSectorParameters(layer, params);
231

    
232
        if (layer instanceof FLyrRaster) {
233
            
234
            FLyrRaster rasterLayer = (FLyrRaster) layer;
235
            int[] dataType = rasterLayer.getDataStore().getDataType();
236
            
237
            switch (dataType[0]) {
238
            case Buffer.TYPE_BYTE:
239
                params.setValue(AVKey.DATA_TYPE, AVKey.INT8);
240
                break;
241
            case Buffer.TYPE_SHORT:
242
            case Buffer.TYPE_USHORT:
243
                params.setValue(AVKey.DATA_TYPE, AVKey.INT16);
244
                break;
245
            case Buffer.TYPE_INT:
246
                params.setValue(AVKey.DATA_TYPE, AVKey.INT32);
247
                break;
248
            case Buffer.TYPE_FLOAT:
249
                params.setValue(AVKey.DATA_TYPE, AVKey.FLOAT32);
250
                break;
251
            case Buffer.TYPE_DOUBLE:
252
                params.setValue(AVKey.DATA_TYPE, AVKey.FLOAT64);
253
                break;
254
            case Buffer.TYPE_UNDEFINED:
255
            default:
256
                return;
257
            }
258
            
259
            params.setValue(AVKey.WIDTH, (int) rasterLayer.getDataStore().getWidth());
260
            params.setValue(AVKey.HEIGHT, (int) rasterLayer.getDataStore().getHeight());
261
            
262
        } else {
263
            
264
            //TODO Vectorial elevation
265
        }
266
        
267
        LayerProperties3D layerProperties =
268
            View3DLocator.getManager().getLayerProperties(layer);
269
        
270
        params.setValue(AVKey.PIXEL_FORMAT, AVKey.ELEVATION);
271
        params.setValue(AVKey.IMAGE_FORMAT, "application/bil32");
272
        params.setValue(AVKey.MISSING_DATA_SIGNAL, layerProperties.getNoDataValue());
273
        params.setValue(AVKey.ELEVATION_UNIT, layerProperties.getElevationUnits());
274
        params.setValue(AVKey.BYTE_ORDER, AVKey.BIG_ENDIAN);
275
        params.setValue(AVKey.AVAILABLE_IMAGE_FORMATS, new String[] { params
276
            .getValue(AVKey.IMAGE_FORMAT).toString() });
277
            
278
        Sector sector = (Sector) params.getValue(AVKey.SECTOR);
279
        
280
        setTileParameters(layer, sector, params);
281
        
282
        setDetailLevelParameters(layer,sector, params);
283
    }
284
    
285
    private void setDetailLevelParameters(FLayer layer, Sector sector,
286
        AVList params) {
287

    
288
        View3DManager manager = View3DLocator.getManager();
289
        LayerProperties3D layerProperties = manager.getLayerProperties(layer);
290

    
291
        int numLevels;
292
        // If deatail levels are 0, compute best level of detail number
293
        if (layerProperties.getMinLevel() == 0
294
            && layerProperties.getMaxLevel() == 0) {
295

    
296
            LatLon rasterTileDelta = this.computeRasterTileDelta(params);
297
            LatLon desiredLevelZeroDelta = this.computeDesiredTileDelta(sector);
298
            numLevels =
299
                computeNumLevels(desiredLevelZeroDelta, rasterTileDelta);
300

    
301
        } else {
302
            numLevels =
303
                layerProperties.getMaxLevel() - layerProperties.getMinLevel();
304
            params.setValue(AVKey.NUM_EMPTY_LEVELS,
305
                layerProperties.getMinLevel());
306

    
307
        }
308
        params.setValue(AVKey.NUM_LEVELS, numLevels);
309

    
310
        if (layer instanceof FLyrVect) {
311

    
312
            // Only rasterized vectorial layers
313
            double degrees =
314
                DEFAULT_RASTERIZED_LEVEL_ZERO
315
                    * layerProperties.getLevelZeroResolutionMultiplier();
316
            params.setValue(
317
                AVKey.LEVEL_ZERO_TILE_DELTA,
318
                new LatLon(Angle.fromDegrees(degrees), Angle
319
                    .fromDegrees(degrees)));
320

    
321
        } else {
322

    
323
            LatLon rasterTileDelta = this.computeRasterTileDelta(params);
324
            double scale = Math.pow(2d, numLevels - 1);
325
            LatLon levelZeroTileDelta =
326
                LatLon.fromDegrees(
327
                    scale * layerProperties.getLevelZeroResolutionMultiplier()
328
                        * rasterTileDelta.getLatitude().degrees, scale
329
                        * layerProperties.getLevelZeroResolutionMultiplier()
330
                        * rasterTileDelta.getLongitude().degrees);
331
            params.setValue(AVKey.LEVEL_ZERO_TILE_DELTA, levelZeroTileDelta);
332
        }
333

    
334
    }
335
    
336
    private void setSectorParameters(FLayer layer, AVList params) {
337
        MapControl3D mapControl3D =
338
            (MapControl3D) params
339
                .getValue(DefaultMapControl3D.GVSIG_MAPCONTROL3D);
340
        Sector sector = null;
341
        IProjection projection = mapControl3D.getMapContext().getProjection();
342
        try {
343
            sector = getSector(layer, projection);
344
        } catch (DataException e) {
345
            LOG.info("Can't create sector from layer {} with projection {}",
346
                new Object[] { layer, projection }, e);
347
            return;
348
        }
349

    
350
        params.setValue(AVKey.SECTOR, sector);
351
    }
352

    
353
    private void setTileParameters(FLayer layer, Sector sector, AVList params) {
354
        
355
        View3DManager manager = View3DLocator.getManager();
356
        LayerProperties3D layerProperties = manager.getLayerProperties(layer);
357
        
358
        params.setValue(AVKey.TILE_ORIGIN, new LatLon(sector.getMinLatitude(),
359
            sector.getMinLongitude()));
360
        // If tile sizes are 0, set defautlt values
361
        params.setValue(AVKey.TILE_WIDTH, layerProperties.getTileWidth() == 0
362
            ? DEFAULT_TILE_WIDTH : layerProperties.getTileWidth());
363
        params.setValue(AVKey.TILE_HEIGHT, layerProperties.getTileHeight() == 0
364
            ? DEFAULT_TILE_HEIGHT : layerProperties.getTileHeight());
365
        
366
    }
367

    
368
    private void setBasicParameters(FLayer layer, AVList params){
369
        params.setValue(AVKey.DATASET_NAME, layer.getName());
370
        params.setValue(AVKey.DATA_CACHE_NAME, getUniqueCacheId(layer));
371
        params.setValue(AVKey.DISPLAY_NAME, layer.getName());
372
        params.setValue(AVKey.SERVICE_NAME, "Offline");
373
        
374
        String cachePath =
375
            View3DLocator.getManager().getGeneral3DProperties().getCachePath();
376
        params.setValue(AVKey.FILE_STORE, new BasicDataFileStore(new File(
377
            cachePath)));
378
    }
379

    
380
    private Sector getSector(FLayer layer, IProjection projection)
381
        throws DataException {
382

    
383
        ICoordTrans ct = projection.getCT(CRSFactory.getCRS("EPSG:4326"));
384
        Point2D p1 = null;
385
        Point2D p2 = null;
386
        Envelope envelope = layer.getFullEnvelope();
387

    
388
        p1 =
389
            convert(
390
                ct,
391
                new Point2D.Double(envelope.getMinimum(0), envelope
392
                    .getMinimum(1)));
393
        p2 =
394
            convert(
395
                ct,
396
                new Point2D.Double(envelope.getMaximum(0), envelope
397
                    .getMaximum(1)));
398

    
399
        double minLatitude =
400
            Double.isInfinite(p1.getY()) || p1.getY() < Angle.NEG90.degrees
401
                ? Angle.NEG90.degrees : p1.getY();
402
        double maxLatitude =
403
            Double.isInfinite(p2.getY()) || p2.getY() > Angle.POS90.degrees
404
                ? Angle.POS90.degrees : p2.getY();
405
        double minLongitude =
406
            Double.isInfinite(p1.getX()) || p1.getX() < Angle.NEG180.degrees
407
                ? Angle.NEG180.degrees : p1.getX();
408
        double maxLongitude =
409
            Double.isInfinite(p2.getX()) || p2.getX() > Angle.POS180.degrees
410
                ? Angle.POS180.degrees : p2.getX();
411

    
412
        Sector sector =
413
            new Sector(Sector.fromDegrees(minLatitude, maxLatitude,
414
                minLongitude, maxLongitude));
415

    
416
        return sector;
417
    }
418

    
419
    private int computeNumLevels(LatLon levelZeroDelta, LatLon lastLevelDelta) {
420
        // Compute the number of levels needed to achieve the given last level
421
        // tile delta, starting from the given
422
        // level zero tile delta.
423
        double numLatLevels =
424
            WWMath.logBase2(levelZeroDelta.getLatitude().getDegrees())
425
                - WWMath.logBase2(lastLevelDelta.getLatitude().getDegrees());
426
        double numLonLevels =
427
            WWMath.logBase2(levelZeroDelta.getLongitude().getDegrees())
428
                - WWMath.logBase2(lastLevelDelta.getLongitude().getDegrees());
429

    
430
        // Compute the maximum number of levels needed, but limit the number of
431
        // levels to positive integers greater
432
        // than or equal to one.
433
        int numLevels = (int) Math.ceil(Math.max(numLatLevels, numLonLevels));
434
        if (numLevels < 1)
435
            numLevels = 1;
436

    
437
        return numLevels;
438
    }
439

    
440
    private LatLon computeRasterTileDelta(AVList parameters) {
441

    
442
        Sector sector = (Sector) parameters.getValue(AVKey.SECTOR);
443
        int width = (Integer) parameters.getValue(AVKey.WIDTH);
444
        int height = (Integer) parameters.getValue(AVKey.HEIGHT);
445
        int tileWidth = (Integer) parameters.getValue(AVKey.TILE_WIDTH);
446
        int tileHeight = (Integer) parameters.getValue(AVKey.TILE_HEIGHT);
447

    
448
        LatLon pixelSize = this.computeRasterPixelSize(sector, width, height);
449
        // Compute the tile size in latitude and longitude, given a raster's
450
        // sector and dimension, and the tile
451
        // dimensions. In this computation a pixel is assumed to cover a finite
452
        // area.
453
        double latDelta = tileHeight * pixelSize.getLatitude().degrees;
454
        double lonDelta = tileWidth * pixelSize.getLongitude().degrees;
455
        return LatLon.fromDegrees(latDelta, lonDelta);
456
    }
457

    
458
    private LatLon computeRasterPixelSize(Sector sector, int width, int height) {
459
        // Compute the raster's pixel dimension in latitude and longitude. In
460
        // this computation a pixel is assumed to
461
        // cover a finite area.
462
        return LatLon.fromDegrees(sector.getDeltaLatDegrees() / height,
463
            sector.getDeltaLonDegrees() / width);
464
    }
465

    
466
    private LatLon computeDesiredTileDelta(Sector sector) {
467
        return LatLon.fromDegrees(sector.getDeltaLatDegrees(), sector.getDeltaLonDegrees());
468
    }
469

    
470
    private Point2D convert(ICoordTrans ct, Point2D point) {
471
        if (ct == null) {
472
            return point;
473
        }
474

    
475
        return ct.convert(point, null);
476
    }
477

    
478
}