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

History | View | Annotate | Download (10.7 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.slf4j.Logger;
45
import org.slf4j.LoggerFactory;
46
import org.w3c.dom.Document;
47
import org.gvsig.fmap.crs.CRSFactory;
48
import org.gvsig.fmap.dal.exception.DataException;
49
import org.gvsig.fmap.geom.primitive.Envelope;
50
import org.gvsig.fmap.mapcontext.MapContext;
51
import org.gvsig.fmap.mapcontext.layers.FLayer;
52
import org.gvsig.fmap.mapcontext.layers.vectorial.FLyrVect;
53
import org.gvsig.view3d.swing.impl.DefaultMapControl3D;
54

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

    
61
    private static final Logger LOG = LoggerFactory
62
        .getLogger(DefaultLayerConverter.class);
63

    
64
    public Layer convertToLayer(MapContext mapContext, FLayer layer)
65
        throws DataException {
66

    
67
        AVList params = new AVListImpl();
68

    
69
        // Add Layer and MapContext to parameters.
70
        params.setValue(DefaultMapControl3D.GVSIG_MAPCONTEXT, mapContext);
71
        params.setValue(DefaultMapControl3D.GVSIG_LAYER, layer);
72

    
73
        createRasterTiledImageLayerParams(layer, params);
74

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

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

    
82
        RasterTiledImageLayer rasterLayer =
83
            new RasterTiledImageLayer(doc.getDocumentElement(), paramsLayer);
84
        return rasterLayer;
85
    }
86

    
87
    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
        // TODO This is not valid. We have to take in account more properties
95
        // to get unique cache id
96
        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
            LOG.warn("MD5 algorith is not available", e);
113
            return name;
114
        }
115
    }
116

    
117
    private void createRasterTiledImageLayerParams(FLayer layer, AVList params) {
118

    
119
        // TODO Get 3D propeties of layer with View3DManager.getProperties3D(layer)
120
        // and fill parameters with properties
121
        
122
        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
        params.setValue(AVKey.DISPLAY_NAME, layer.getName());
130
        params.setValue(AVKey.SERVICE_NAME, "Offline");
131

    
132
        MapContext mapContext =
133
            (MapContext) params.getValue(DefaultMapControl3D.GVSIG_MAPCONTEXT);
134

    
135
        Sector sector = null;
136
        try {
137
            sector = getSector(layer, mapContext.getProjection());
138
        } catch (DataException e) {
139
            LOG.info("Can't create sector from layer and projection", e);
140
            return;
141
        }
142

    
143
        params.setValue(AVKey.SECTOR, sector);
144
        
145
        // Set resolution of layer
146
        // TODO Make configurable by user
147
        params.setValue(AVKey.WIDTH, Integer.MAX_VALUE);
148
        params.setValue(AVKey.HEIGHT,Integer.MAX_VALUE);
149

    
150
        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

    
161
        LatLon rasterTileDelta = this.computeRasterTileDelta(params);
162
        LatLon desiredLevelZeroDelta = this.computeDesiredTileDelta(sector);
163
        int numLevels = computeNumLevels(desiredLevelZeroDelta, rasterTileDelta);
164

    
165
        params.setValue(AVKey.NUM_LEVELS, numLevels);
166
        
167
        if(layer instanceof FLyrVect){
168
            
169
            // Only rasterized vectorial layers TODO Make configurable
170
            params.setValue(AVKey.LEVEL_ZERO_TILE_DELTA, new
171
                 LatLon(Angle.fromDegrees(20), Angle.fromDegrees(20)));
172
            
173
        } else {
174
            
175
            double scale = Math.pow(2d, numLevels - 1);
176
            LatLon levelZeroTileDelta = LatLon.fromDegrees(
177
                scale * rasterTileDelta.getLatitude().degrees,
178
                scale * rasterTileDelta.getLongitude().degrees);
179
            params.setValue(AVKey.LEVEL_ZERO_TILE_DELTA, levelZeroTileDelta);
180
        }
181

    
182
        params.setValue(AVKey.NETWORK_RETRIEVAL_ENABLED, false);
183
        params.setValue(AVKey.USE_MIP_MAPS, true);
184
        params.setValue(AVKey.USE_TRANSPARENT_TEXTURES, true);
185

    
186
    }
187

    
188
    private Sector getSector(FLayer layer, IProjection projection)
189
        throws DataException {
190

    
191
        ICoordTrans ct = projection.getCT(CRSFactory.getCRS("EPSG:4326"));
192
        Point2D p1 = null;
193
        Point2D p2 = null;
194
        Envelope envelope = layer.getFullEnvelope();
195

    
196
        p1 =
197
            convert(
198
                ct,
199
                new Point2D.Double(envelope.getMinimum(0), envelope
200
                    .getMinimum(1)));
201
        p2 =
202
            convert(
203
                ct,
204
                new Point2D.Double(envelope.getMaximum(0), envelope
205
                    .getMaximum(1)));
206
        
207
        double minLatitude =
208
            Double.isInfinite(p1.getY()) || p1.getY() < Angle.NEG90.degrees
209
                ? Angle.NEG90.degrees : p1.getY();
210
        double maxLatitude =
211
            Double.isInfinite(p2.getY()) || p2.getY() > Angle.POS90.degrees
212
                ? Angle.POS90.degrees : p2.getY();
213
        double minLongitude =
214
            Double.isInfinite(p1.getX()) || p1.getX() < Angle.NEG180.degrees
215
                ? Angle.NEG180.degrees : p1.getX();
216
        double maxLongitude =
217
            Double.isInfinite(p2.getX()) || p2.getX() > Angle.POS180.degrees
218
                ? Angle.POS180.degrees : p2.getX();
219

    
220
        Sector sector =
221
            new Sector(Sector.fromDegrees(minLatitude,maxLatitude,
222
                minLongitude, maxLongitude));
223

    
224
        return sector;
225
    }
226
    
227
    private int computeNumLevels(LatLon levelZeroDelta, LatLon lastLevelDelta) {
228
        // Compute the number of levels needed to achieve the given last level
229
        // tile delta, starting from the given
230
        // level zero tile delta.
231
        double numLatLevels =
232
            WWMath.logBase2(levelZeroDelta.getLatitude().getDegrees())
233
                - WWMath.logBase2(lastLevelDelta.getLatitude().getDegrees());
234
        double numLonLevels =
235
            WWMath.logBase2(levelZeroDelta.getLongitude().getDegrees())
236
                - WWMath.logBase2(lastLevelDelta.getLongitude().getDegrees());
237

    
238
        // Compute the maximum number of levels needed, but limit the number of
239
        // levels to positive integers greater
240
        // than or equal to one.
241
        int numLevels = (int) Math.ceil(Math.max(numLatLevels, numLonLevels));
242
        if (numLevels < 1)
243
            numLevels = 1;
244

    
245
        return numLevels;
246
    }
247

    
248
    private LatLon computeRasterTileDelta(AVList parameters) {
249

    
250
        Sector sector = (Sector) parameters.getValue(AVKey.SECTOR);
251
        int width = (Integer) parameters.getValue(AVKey.WIDTH);
252
        int height = (Integer) parameters.getValue(AVKey.HEIGHT);
253
        int tileWidth = (Integer) parameters.getValue(AVKey.TILE_WIDTH);
254
        int tileHeight = (Integer) parameters.getValue(AVKey.TILE_HEIGHT);
255

    
256
        LatLon pixelSize = this.computeRasterPixelSize(sector, width, height);
257
        // Compute the tile size in latitude and longitude, given a raster's
258
        // sector and dimension, and the tile
259
        // dimensions. In this computation a pixel is assumed to cover a finite
260
        // area.
261
        double latDelta = tileHeight * pixelSize.getLatitude().degrees;
262
        double lonDelta = tileWidth * pixelSize.getLongitude().degrees;
263
        return LatLon.fromDegrees(latDelta, lonDelta);
264
    }
265

    
266
    private LatLon computeRasterPixelSize(Sector sector, int width, int height) {
267
        // Compute the raster's pixel dimension in latitude and longitude. In
268
        // this computation a pixel is assumed to
269
        // cover a finite area.
270
        return LatLon.fromDegrees(sector.getDeltaLatDegrees() / height,
271
            sector.getDeltaLonDegrees() / width);
272
    }
273
    
274
    private LatLon computeDesiredTileDelta(Sector sector) {
275
        return LatLon.fromDegrees(sector.getDeltaLatDegrees(), sector.getDeltaLonDegrees());
276
    }
277
    
278
    private Point2D convert(ICoordTrans ct, Point2D point){
279
        if(ct == null){
280
            return point;
281
        }
282
        
283
        return ct.convert(point, null);
284
    }
285

    
286
}