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

History | View | Annotate | Download (12.4 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.geom.Angle;
31
import gov.nasa.worldwind.geom.LatLon;
32
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
import gov.nasa.worldwind.util.WWMath;
37

    
38
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.gvsig.fmap.crs.CRSFactory;
45
import org.gvsig.fmap.dal.exception.DataException;
46
import org.gvsig.fmap.geom.primitive.Envelope;
47
import org.gvsig.fmap.mapcontext.MapContext;
48
import org.gvsig.fmap.mapcontext.layers.FLayer;
49
import org.gvsig.fmap.mapcontext.layers.operations.SingleLayer;
50
import org.gvsig.fmap.mapcontext.layers.vectorial.FLyrVect;
51
import org.gvsig.view3d.swing.api.MapControl3D;
52
import org.gvsig.view3d.swing.impl.DefaultMapControl3D;
53
import org.slf4j.Logger;
54
import org.slf4j.LoggerFactory;
55
import org.w3c.dom.Document;
56

    
57
/**
58
 * @author <a href="mailto:lmarques@disid.com">Lluis Marques</a>
59
 *
60
 */
61
public class DefaultLayerConverter implements LayerConverter {
62

    
63
    private static final Logger LOG = LoggerFactory
64
        .getLogger(DefaultLayerConverter.class);
65

    
66
    public Layer convertToLayer(MapControl3D mapControl, FLayer layer)
67
        throws DataException {
68

    
69
        AVList params = new AVListImpl();
70

    
71
        // Add Layer and MapContext to parameters.
72
        params.setValue(DefaultMapControl3D.GVSIG_MAPCONTROL3D, mapControl);
73
        params.setValue(DefaultMapControl3D.GVSIG_LAYER, layer);
74

    
75
        createRasterTiledImageLayerParams(layer, params);
76

    
77
        // Create configuration document from parameters.
78
        Document doc =
79
            TiledImageLayer.createTiledImageLayerConfigDocument(params);
80

    
81
        // Copy parameters to avoid problems
82
        AVList paramsLayer = params.copy();
83

    
84
        DefaultTiledImageLayer rasterLayer =
85
            new DefaultTiledImageLayer(doc.getDocumentElement(), paramsLayer);
86
        return rasterLayer;
87
    }
88

    
89
    public ElevationModel convertToElevationModel(MapControl3D mapControl,
90
        FLayer layer) {
91
        // TODO Auto-generated method stub
92
        return null;
93
    }
94

    
95
    private String getUniqueCacheId(FLayer layer) {
96
        // TODO This is not valid. We have to take in account more properties
97
        // to get unique cache id
98
        try {
99
            // Create MD5 Hash
100
            MessageDigest digest =
101
                java.security.MessageDigest.getInstance("MD5");
102

    
103
            String name = layer.getName();
104
            long drawVersion = layer.getDrawVersion();
105
            String dataStoreFullName = null;
106
            if (layer instanceof SingleLayer) {
107
                dataStoreFullName =
108
                    ((SingleLayer) layer).getDataStore().getFullName();
109
            }
110
            int hashCode = layer.hashCode();
111

    
112
            StringBuilder stb = new StringBuilder();
113
            stb.append(name);
114
            stb.append("$");
115
            stb.append(drawVersion);
116
            stb.append("$");
117
            stb.append(hashCode);
118
            stb.append("$");
119
            if (dataStoreFullName != null) {
120
                stb.append(dataStoreFullName);
121
                stb.append("$");
122
            }
123

    
124
            String id = stb.toString();
125
            digest.update(id.getBytes());
126
            byte messageDigest[] = digest.digest();
127

    
128
            // Create Hex String
129
            StringBuilder hexString = new StringBuilder();
130
            hexString.append(layer.getName());
131
            hexString.append("-");
132
            for (int i = 0; i < messageDigest.length; i++)
133
                hexString.append(Integer.toHexString(0xFF & messageDigest[i]));
134
            return hexString.toString();
135

    
136
        } catch (NoSuchAlgorithmException e) {
137
            LOG.warn("MD5 algorith is not available", e);
138

    
139
            String name = layer.getName();
140
            long drawVersion = layer.getDrawVersion();
141
            String dataStoreFullName = null;
142
            if (layer instanceof SingleLayer) {
143
                dataStoreFullName =
144
                    ((SingleLayer) layer).getDataStore().getFullName();
145
            }
146
            int hashCode = layer.hashCode();
147

    
148
            StringBuilder stb = new StringBuilder();
149
            stb.append(name);
150
            stb.append("$");
151
            stb.append(drawVersion);
152
            stb.append("$");
153
            stb.append(hashCode);
154
            stb.append("$");
155
            if (dataStoreFullName != null) {
156
                stb.append(dataStoreFullName);
157
                stb.append("$");
158
            }
159

    
160
            return stb.toString();
161
        }
162
    }
163

    
164
    private void createRasterTiledImageLayerParams(FLayer layer, AVList params) {
165

    
166
        // TODO Get 3D propeties of layer with View3DManager.getProperties3D(layer)
167
        // and fill parameters with properties
168
        
169
        if (params == null) {
170
            params = new AVListImpl();
171
        }
172

    
173
        params.setValue(AVKey.DATASET_NAME, layer.getName());
174
        params.setValue(AVKey.DATA_CACHE_NAME,
175
            getUniqueCacheId(layer));
176
        params.setValue(AVKey.DISPLAY_NAME, layer.getName());
177
        params.setValue(AVKey.SERVICE_NAME, "Offline");
178

    
179
        MapControl3D mapControl3D =
180
            (MapControl3D) params.getValue(DefaultMapControl3D.GVSIG_MAPCONTROL3D);
181

    
182
        Sector sector = null;
183
        try {
184
            sector = getSector(layer, mapControl3D.getMapContext().getProjection());
185
        } catch (DataException e) {
186
            LOG.info("Can't create sector from layer and projection", e);
187
            return;
188
        }
189

    
190
        params.setValue(AVKey.SECTOR, sector);
191
        
192
        // Set resolution of layer
193
        // TODO Make configurable by user
194
        params.setValue(AVKey.WIDTH, Integer.MAX_VALUE);
195
        params.setValue(AVKey.HEIGHT,Integer.MAX_VALUE);
196

    
197
        params.setValue(AVKey.IMAGE_FORMAT, "image/png");
198
        params.setValue(AVKey.PIXEL_FORMAT, AVKey.IMAGE);
199
        params.setValue(AVKey.TEXTURE_FORMAT, "image/dds");
200
        params.setValue(AVKey.FORMAT_SUFFIX, ".png");
201
        params.setValue(AVKey.AVAILABLE_IMAGE_FORMATS, new String[] { params
202
            .getValue(AVKey.IMAGE_FORMAT).toString() });
203
        params.setValue(AVKey.TILE_ORIGIN, new LatLon(sector.getMinLatitude(),
204
            sector.getMinLongitude()));
205
        params.setValue(AVKey.TILE_WIDTH, 512);
206
        params.setValue(AVKey.TILE_HEIGHT, 512);
207

    
208
        LatLon rasterTileDelta = this.computeRasterTileDelta(params);
209
        LatLon desiredLevelZeroDelta = this.computeDesiredTileDelta(sector);
210
        int numLevels = computeNumLevels(desiredLevelZeroDelta, rasterTileDelta);
211

    
212
        params.setValue(AVKey.NUM_LEVELS, numLevels);
213
        
214
        if(layer instanceof FLyrVect){
215
            
216
            // Only rasterized vectorial layers TODO Make configurable
217
            params.setValue(AVKey.LEVEL_ZERO_TILE_DELTA, new
218
                 LatLon(Angle.fromDegrees(20), Angle.fromDegrees(20)));
219
            
220
        } else {
221
            
222
            double scale = Math.pow(2d, numLevels - 1);
223
            LatLon levelZeroTileDelta = LatLon.fromDegrees(
224
                scale * rasterTileDelta.getLatitude().degrees,
225
                scale * rasterTileDelta.getLongitude().degrees);
226
            params.setValue(AVKey.LEVEL_ZERO_TILE_DELTA, levelZeroTileDelta);
227
        }
228

    
229
        params.setValue(AVKey.NETWORK_RETRIEVAL_ENABLED, false);
230
        params.setValue(AVKey.USE_MIP_MAPS, true);
231
        params.setValue(AVKey.USE_TRANSPARENT_TEXTURES, true);
232
        
233
    }
234

    
235
    private Sector getSector(FLayer layer, IProjection projection)
236
        throws DataException {
237

    
238
        ICoordTrans ct = projection.getCT(CRSFactory.getCRS("EPSG:4326"));
239
        Point2D p1 = null;
240
        Point2D p2 = null;
241
        Envelope envelope = layer.getFullEnvelope();
242

    
243
        p1 =
244
            convert(
245
                ct,
246
                new Point2D.Double(envelope.getMinimum(0), envelope
247
                    .getMinimum(1)));
248
        p2 =
249
            convert(
250
                ct,
251
                new Point2D.Double(envelope.getMaximum(0), envelope
252
                    .getMaximum(1)));
253
        
254
        double minLatitude =
255
            Double.isInfinite(p1.getY()) || p1.getY() < Angle.NEG90.degrees
256
                ? Angle.NEG90.degrees : p1.getY();
257
        double maxLatitude =
258
            Double.isInfinite(p2.getY()) || p2.getY() > Angle.POS90.degrees
259
                ? Angle.POS90.degrees : p2.getY();
260
        double minLongitude =
261
            Double.isInfinite(p1.getX()) || p1.getX() < Angle.NEG180.degrees
262
                ? Angle.NEG180.degrees : p1.getX();
263
        double maxLongitude =
264
            Double.isInfinite(p2.getX()) || p2.getX() > Angle.POS180.degrees
265
                ? Angle.POS180.degrees : p2.getX();
266

    
267
        Sector sector =
268
            new Sector(Sector.fromDegrees(minLatitude,maxLatitude,
269
                minLongitude, maxLongitude));
270

    
271
        return sector;
272
    }
273
    
274
    private int computeNumLevels(LatLon levelZeroDelta, LatLon lastLevelDelta) {
275
        // Compute the number of levels needed to achieve the given last level
276
        // tile delta, starting from the given
277
        // level zero tile delta.
278
        double numLatLevels =
279
            WWMath.logBase2(levelZeroDelta.getLatitude().getDegrees())
280
                - WWMath.logBase2(lastLevelDelta.getLatitude().getDegrees());
281
        double numLonLevels =
282
            WWMath.logBase2(levelZeroDelta.getLongitude().getDegrees())
283
                - WWMath.logBase2(lastLevelDelta.getLongitude().getDegrees());
284

    
285
        // Compute the maximum number of levels needed, but limit the number of
286
        // levels to positive integers greater
287
        // than or equal to one.
288
        int numLevels = (int) Math.ceil(Math.max(numLatLevels, numLonLevels));
289
        if (numLevels < 1)
290
            numLevels = 1;
291

    
292
        return numLevels;
293
    }
294

    
295
    private LatLon computeRasterTileDelta(AVList parameters) {
296

    
297
        Sector sector = (Sector) parameters.getValue(AVKey.SECTOR);
298
        int width = (Integer) parameters.getValue(AVKey.WIDTH);
299
        int height = (Integer) parameters.getValue(AVKey.HEIGHT);
300
        int tileWidth = (Integer) parameters.getValue(AVKey.TILE_WIDTH);
301
        int tileHeight = (Integer) parameters.getValue(AVKey.TILE_HEIGHT);
302

    
303
        LatLon pixelSize = this.computeRasterPixelSize(sector, width, height);
304
        // Compute the tile size in latitude and longitude, given a raster's
305
        // sector and dimension, and the tile
306
        // dimensions. In this computation a pixel is assumed to cover a finite
307
        // area.
308
        double latDelta = tileHeight * pixelSize.getLatitude().degrees;
309
        double lonDelta = tileWidth * pixelSize.getLongitude().degrees;
310
        return LatLon.fromDegrees(latDelta, lonDelta);
311
    }
312

    
313
    private LatLon computeRasterPixelSize(Sector sector, int width, int height) {
314
        // Compute the raster's pixel dimension in latitude and longitude. In
315
        // this computation a pixel is assumed to
316
        // cover a finite area.
317
        return LatLon.fromDegrees(sector.getDeltaLatDegrees() / height,
318
            sector.getDeltaLonDegrees() / width);
319
    }
320
    
321
    private LatLon computeDesiredTileDelta(Sector sector) {
322
        return LatLon.fromDegrees(sector.getDeltaLatDegrees(), sector.getDeltaLonDegrees());
323
    }
324
    
325
    private Point2D convert(ICoordTrans ct, Point2D point){
326
        if(ct == null){
327
            return point;
328
        }
329
        
330
        return ct.convert(point, null);
331
    }
332

    
333
}