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

History | View | Annotate | Download (14.1 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.exception.DataException;
48
import org.gvsig.fmap.geom.primitive.Envelope;
49
import org.gvsig.fmap.mapcontext.layers.FLayer;
50
import org.gvsig.fmap.mapcontext.layers.operations.SingleLayer;
51
import org.gvsig.fmap.mapcontext.layers.vectorial.FLyrVect;
52
import org.gvsig.view3d.lib.api.View3DLocator;
53
import org.gvsig.view3d.lib.api.View3DManager;
54
import org.gvsig.view3d.lib.api.properties.LayerProperties3D;
55
import org.gvsig.view3d.swing.api.MapControl3D;
56
import org.gvsig.view3d.swing.impl.DefaultMapControl3D;
57
import org.slf4j.Logger;
58
import org.slf4j.LoggerFactory;
59
import org.w3c.dom.Document;
60

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

    
68
    private static final Logger LOG = LoggerFactory
69
        .getLogger(DefaultLayerConverter.class);
70
    
71
    private final int DEFAULT_RASTERIZED_LEVEL_ZERO = 20;
72
    private final int DEFAULT_TILE_WIDTH = 512;
73
    private final int DEFAULT_TILE_HEIGHT = 512;
74

    
75
    public Layer convertToLayer(MapControl3D mapControl, FLayer layer)
76
        throws DataException {
77

    
78
        AVList params = new AVListImpl();
79

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

    
84
        createRasterTiledImageLayerParams(layer, params);
85

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

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

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

    
98
    public ElevationModel convertToElevationModel(MapControl3D mapControl,
99
        FLayer layer) {
100
        // TODO Auto-generated method stub
101
        return null;
102
    }
103

    
104
    private String getUniqueCacheId(FLayer layer) {
105
        // TODO This is not valid. We have to take in account more properties
106
        // to get unique cache id
107
        try {
108
            // Create MD5 Hash
109
            MessageDigest digest =
110
                java.security.MessageDigest.getInstance("MD5");
111

    
112
            String name = layer.getName();
113
            long drawVersion = layer.getDrawVersion();
114
            String dataStoreFullName = null;
115
            if (layer instanceof SingleLayer) {
116
                dataStoreFullName =
117
                    ((SingleLayer) layer).getDataStore().getFullName();
118
            }
119
            int hashCode = layer.hashCode();
120

    
121
            StringBuilder stb = new StringBuilder();
122
            stb.append(name);
123
            stb.append("$");
124
            stb.append(drawVersion);
125
            stb.append("$");
126
            stb.append(hashCode);
127
            stb.append("$");
128
            if (dataStoreFullName != null) {
129
                stb.append(dataStoreFullName);
130
                stb.append("$");
131
            }
132

    
133
            String id = stb.toString();
134
            digest.update(id.getBytes());
135
            byte messageDigest[] = digest.digest();
136

    
137
            // Create Hex String
138
            StringBuilder hexString = new StringBuilder();
139
            hexString.append(layer.getName());
140
            hexString.append("-");
141
            for (int i = 0; i < messageDigest.length; i++)
142
                hexString.append(Integer.toHexString(0xFF & messageDigest[i]));
143
            return hexString.toString();
144

    
145
        } catch (NoSuchAlgorithmException e) {
146
            LOG.warn("MD5 algorith is not available", e);
147

    
148
            String name = layer.getName();
149
            long drawVersion = layer.getDrawVersion();
150
            String dataStoreFullName = null;
151
            if (layer instanceof SingleLayer) {
152
                dataStoreFullName =
153
                    ((SingleLayer) layer).getDataStore().getFullName();
154
            }
155
            int hashCode = layer.hashCode();
156

    
157
            StringBuilder stb = new StringBuilder();
158
            stb.append(name);
159
            stb.append("$");
160
            stb.append(drawVersion);
161
            stb.append("$");
162
            stb.append(hashCode);
163
            stb.append("$");
164
            if (dataStoreFullName != null) {
165
                stb.append(dataStoreFullName);
166
                stb.append("$");
167
            }
168

    
169
            return stb.toString();
170
        }
171
    }
172

    
173
    private void createRasterTiledImageLayerParams(FLayer layer, AVList params) {
174

    
175
        if (params == null) {
176
            params = new AVListImpl();
177
        }
178

    
179
        params.setValue(AVKey.DATASET_NAME, layer.getName());
180
        params.setValue(AVKey.DATA_CACHE_NAME,
181
            getUniqueCacheId(layer));
182
        params.setValue(AVKey.DISPLAY_NAME, layer.getName());
183
        params.setValue(AVKey.SERVICE_NAME, "Offline");
184
        
185
        String cachePath =
186
            View3DLocator.getManager().getGeneral3DProperties().getCachePath();
187
        params.setValue(AVKey.FILE_STORE, new BasicDataFileStore(new File(
188
            cachePath)));
189

    
190
        MapControl3D mapControl3D =
191
            (MapControl3D) params.getValue(DefaultMapControl3D.GVSIG_MAPCONTROL3D);
192

    
193
        Sector sector = null;
194
        try {
195
            sector = getSector(layer, mapControl3D.getMapContext().getProjection());
196
        } catch (DataException e) {
197
            LOG.info("Can't create sector from layer and projection", e);
198
            return;
199
        }
200

    
201
        params.setValue(AVKey.SECTOR, sector);
202
        
203
        // Set resolution of layer
204
        params.setValue(AVKey.WIDTH, Integer.MAX_VALUE);
205
        params.setValue(AVKey.HEIGHT,Integer.MAX_VALUE);
206

    
207
        params.setValue(AVKey.IMAGE_FORMAT, "image/png");
208
        params.setValue(AVKey.PIXEL_FORMAT, AVKey.IMAGE);
209
        params.setValue(AVKey.TEXTURE_FORMAT, "image/dds");
210
        params.setValue(AVKey.FORMAT_SUFFIX, ".png");
211
        params.setValue(AVKey.AVAILABLE_IMAGE_FORMATS, new String[] { params
212
            .getValue(AVKey.IMAGE_FORMAT).toString() });
213
        params.setValue(AVKey.TILE_ORIGIN, new LatLon(sector.getMinLatitude(),
214
            sector.getMinLongitude()));
215
        
216
        View3DManager manager = View3DLocator.getManager();
217
        LayerProperties3D layerProperties = manager.getLayerProperties(layer);
218
        
219
        // If tile sizes are 0, set defautlt values
220
        params.setValue(AVKey.TILE_WIDTH, layerProperties.getTileWidth() == 0
221
            ? DEFAULT_TILE_WIDTH : layerProperties.getTileWidth());
222
        params.setValue(AVKey.TILE_HEIGHT, layerProperties.getTileHeight() == 0
223
            ? DEFAULT_TILE_HEIGHT : layerProperties.getTileHeight());
224
        
225
        int numLevels;
226
        // If deatail levels are 0, compute best level of detail number
227
        if(layerProperties.getMinLevel() == 0 && layerProperties.getMaxLevel() == 0){
228
            
229
            LatLon rasterTileDelta = this.computeRasterTileDelta(params);
230
            LatLon desiredLevelZeroDelta = this.computeDesiredTileDelta(sector);
231
            numLevels = computeNumLevels(desiredLevelZeroDelta, rasterTileDelta);
232
            
233
        } else {
234
            numLevels =
235
                layerProperties.getMaxLevel() - layerProperties.getMinLevel();
236
            params.setValue(AVKey.NUM_EMPTY_LEVELS,
237
                layerProperties.getMinLevel());
238
            
239
        }
240
        params.setValue(AVKey.NUM_LEVELS, numLevels);
241
        
242
        if(layer instanceof FLyrVect){
243
            
244
            // Only rasterized vectorial layers
245
            double degrees =
246
                DEFAULT_RASTERIZED_LEVEL_ZERO
247
                    * layerProperties.getLevelZeroResolutionMultiplier();
248
            params.setValue(
249
                AVKey.LEVEL_ZERO_TILE_DELTA,
250
                new LatLon(Angle.fromDegrees(degrees), Angle
251
                    .fromDegrees(degrees)));
252
            
253
        } else {
254
            
255
            LatLon rasterTileDelta = this.computeRasterTileDelta(params);
256
            double scale = Math.pow(2d, numLevels - 1);
257
            LatLon levelZeroTileDelta =
258
                LatLon.fromDegrees(
259
                    scale * layerProperties.getLevelZeroResolutionMultiplier()
260
                        * rasterTileDelta.getLatitude().degrees, scale
261
                        * layerProperties.getLevelZeroResolutionMultiplier()
262
                        * rasterTileDelta.getLongitude().degrees);
263
            params.setValue(AVKey.LEVEL_ZERO_TILE_DELTA, levelZeroTileDelta);
264
        }
265
        
266
        params.setValue(AVKey.NUM_LEVELS, numLevels);
267
        params.setValue(AVKey.NETWORK_RETRIEVAL_ENABLED, false);
268
        params.setValue(AVKey.USE_MIP_MAPS, true);
269
        params.setValue(AVKey.USE_TRANSPARENT_TEXTURES, true);
270
    }
271

    
272
    private Sector getSector(FLayer layer, IProjection projection)
273
        throws DataException {
274

    
275
        ICoordTrans ct = projection.getCT(CRSFactory.getCRS("EPSG:4326"));
276
        Point2D p1 = null;
277
        Point2D p2 = null;
278
        Envelope envelope = layer.getFullEnvelope();
279

    
280
        p1 =
281
            convert(
282
                ct,
283
                new Point2D.Double(envelope.getMinimum(0), envelope
284
                    .getMinimum(1)));
285
        p2 =
286
            convert(
287
                ct,
288
                new Point2D.Double(envelope.getMaximum(0), envelope
289
                    .getMaximum(1)));
290
        
291
        double minLatitude =
292
            Double.isInfinite(p1.getY()) || p1.getY() < Angle.NEG90.degrees
293
                ? Angle.NEG90.degrees : p1.getY();
294
        double maxLatitude =
295
            Double.isInfinite(p2.getY()) || p2.getY() > Angle.POS90.degrees
296
                ? Angle.POS90.degrees : p2.getY();
297
        double minLongitude =
298
            Double.isInfinite(p1.getX()) || p1.getX() < Angle.NEG180.degrees
299
                ? Angle.NEG180.degrees : p1.getX();
300
        double maxLongitude =
301
            Double.isInfinite(p2.getX()) || p2.getX() > Angle.POS180.degrees
302
                ? Angle.POS180.degrees : p2.getX();
303

    
304
        Sector sector =
305
            new Sector(Sector.fromDegrees(minLatitude,maxLatitude,
306
                minLongitude, maxLongitude));
307

    
308
        return sector;
309
    }
310
    
311
    private int computeNumLevels(LatLon levelZeroDelta, LatLon lastLevelDelta) {
312
        // Compute the number of levels needed to achieve the given last level
313
        // tile delta, starting from the given
314
        // level zero tile delta.
315
        double numLatLevels =
316
            WWMath.logBase2(levelZeroDelta.getLatitude().getDegrees())
317
                - WWMath.logBase2(lastLevelDelta.getLatitude().getDegrees());
318
        double numLonLevels =
319
            WWMath.logBase2(levelZeroDelta.getLongitude().getDegrees())
320
                - WWMath.logBase2(lastLevelDelta.getLongitude().getDegrees());
321

    
322
        // Compute the maximum number of levels needed, but limit the number of
323
        // levels to positive integers greater
324
        // than or equal to one.
325
        int numLevels = (int) Math.ceil(Math.max(numLatLevels, numLonLevels));
326
        if (numLevels < 1)
327
            numLevels = 1;
328

    
329
        return numLevels;
330
    }
331

    
332
    private LatLon computeRasterTileDelta(AVList parameters) {
333

    
334
        Sector sector = (Sector) parameters.getValue(AVKey.SECTOR);
335
        int width = (Integer) parameters.getValue(AVKey.WIDTH);
336
        int height = (Integer) parameters.getValue(AVKey.HEIGHT);
337
        int tileWidth = (Integer) parameters.getValue(AVKey.TILE_WIDTH);
338
        int tileHeight = (Integer) parameters.getValue(AVKey.TILE_HEIGHT);
339

    
340
        LatLon pixelSize = this.computeRasterPixelSize(sector, width, height);
341
        // Compute the tile size in latitude and longitude, given a raster's
342
        // sector and dimension, and the tile
343
        // dimensions. In this computation a pixel is assumed to cover a finite
344
        // area.
345
        double latDelta = tileHeight * pixelSize.getLatitude().degrees;
346
        double lonDelta = tileWidth * pixelSize.getLongitude().degrees;
347
        return LatLon.fromDegrees(latDelta, lonDelta);
348
    }
349

    
350
    private LatLon computeRasterPixelSize(Sector sector, int width, int height) {
351
        // Compute the raster's pixel dimension in latitude and longitude. In
352
        // this computation a pixel is assumed to
353
        // cover a finite area.
354
        return LatLon.fromDegrees(sector.getDeltaLatDegrees() / height,
355
            sector.getDeltaLonDegrees() / width);
356
    }
357
    
358
    private LatLon computeDesiredTileDelta(Sector sector) {
359
        return LatLon.fromDegrees(sector.getDeltaLatDegrees(), sector.getDeltaLonDegrees());
360
    }
361
    
362
    private Point2D convert(ICoordTrans ct, Point2D point){
363
        if(ct == null){
364
            return point;
365
        }
366
        
367
        return ct.convert(point, null);
368
    }
369

    
370
}