Statistics
| Revision:

gvsig-3d / 2.1 / branches / org.gvsig.view3d_vector_and_extrusion_2.3 / org.gvsig.view3d / org.gvsig.view3d / org.gvsig.view3d.swing / org.gvsig.view3d.swing.impl / src / main / java / org / gvsig / view3d / swing / impl / layers / loaders / AbstractRasterizedLayerLoaderFactory.java @ 735

History | View | Annotate | Download (14.1 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright © 2007-2016 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
package org.gvsig.view3d.swing.impl.layers.loaders;
25

    
26
import java.awt.geom.Point2D;
27
import java.security.MessageDigest;
28
import java.security.NoSuchAlgorithmException;
29

    
30
import org.cresques.cts.ICoordTrans;
31
import org.cresques.cts.IProjection;
32
import org.slf4j.Logger;
33
import org.slf4j.LoggerFactory;
34
import org.w3c.dom.Document;
35

    
36
import org.gvsig.fmap.crs.CRSFactory;
37
import org.gvsig.fmap.dal.exception.DataException;
38
import org.gvsig.fmap.geom.primitive.Envelope;
39
import org.gvsig.fmap.mapcontext.layers.FLayer;
40
import org.gvsig.fmap.mapcontext.layers.operations.SingleLayer;
41
import org.gvsig.fmap.mapcontext.layers.vectorial.FLyrVect;
42
import org.gvsig.view3d.lib.api.properties.E3DLayerLoadingModes;
43
import org.gvsig.view3d.lib.api.properties.LayerProperties3D;
44
import org.gvsig.view3d.lib.api.properties.RasterLayerProperties3D;
45
import org.gvsig.view3d.swing.api.MapControl3D;
46
import org.gvsig.view3d.swing.impl.DefaultMapControl3D;
47
import org.gvsig.view3d.swing.impl.layers.raster.DefaultTiledImageLayer;
48

    
49
import gov.nasa.worldwind.avlist.AVKey;
50
import gov.nasa.worldwind.avlist.AVList;
51
import gov.nasa.worldwind.avlist.AVListImpl;
52
import gov.nasa.worldwind.geom.Angle;
53
import gov.nasa.worldwind.geom.LatLon;
54
import gov.nasa.worldwind.geom.Sector;
55
import gov.nasa.worldwind.layers.Layer;
56
import gov.nasa.worldwind.layers.TiledImageLayer;
57
import gov.nasa.worldwind.util.WWMath;
58

    
59
/**
60
 * Abstract Loader factory for vector layers.
61
 *
62
 * @author Andrea Antonello (www.hydrologis.com)
63
 *
64
 */
65
public abstract class AbstractRasterizedLayerLoaderFactory {
66

    
67
    private static final Logger LOG = LoggerFactory.getLogger(AbstractRasterizedLayerLoaderFactory.class);
68

    
69
    private final int DEFAULT_RASTERIZED_LEVEL_ZERO = 20;
70
    private final int DEFAULT_TILE_WIDTH = 512;
71
    private final int DEFAULT_TILE_HEIGHT = 512;
72

    
73
    protected MapControl3D mapControl3D;
74

    
75
    public void setMapControl(MapControl3D mapControl3D) {
76
        this.mapControl3D = mapControl3D;
77
    }
78

    
79
    public Layer loadLayer(LayerProperties3D properties) {
80
        FLayer layer = properties.getLayer();
81
        AVList params = new AVListImpl();
82
        params.setValue(DefaultMapControl3D.GVSIG_MAPCONTROL3D, mapControl3D);
83
        params.setValue(E3DLayerLoadingModes.GVSIG_LAYER, layer);
84
        createRasterTiledImageLayerParams(layer, params, (RasterLayerProperties3D) properties);
85
        // Create configuration document from parameters.
86
        Document doc = TiledImageLayer.createTiledImageLayerConfigDocument(params);
87
        // Copy parameters to avoid problems
88
        AVList paramsLayer = params.copy();
89
        DefaultTiledImageLayer rasterLayer = new DefaultTiledImageLayer(doc.getDocumentElement(), paramsLayer);
90
        return rasterLayer;
91
    }
92

    
93
    private void createRasterTiledImageLayerParams(FLayer layer, AVList params,
94
        RasterLayerProperties3D layerProperties) {
95

    
96
        if (params == null) {
97
            params = new AVListImpl();
98
        }
99

    
100
        setBasicParameters(layer, params);
101

    
102
        setSectorParameters(layer, params);
103

    
104
        // Set resolution of layer
105
        params.setValue(AVKey.WIDTH, Integer.MAX_VALUE);
106
        params.setValue(AVKey.HEIGHT, Integer.MAX_VALUE);
107
        params.setValue(AVKey.IMAGE_FORMAT, "image/png");
108
        params.setValue(AVKey.PIXEL_FORMAT, AVKey.IMAGE);
109
        params.setValue(AVKey.TEXTURE_FORMAT, "image/dds");
110
        params.setValue(AVKey.FORMAT_SUFFIX, ".png");
111
        params.setValue(AVKey.AVAILABLE_IMAGE_FORMATS, new String[] { params.getValue(AVKey.IMAGE_FORMAT).toString() });
112
        params.setValue(AVKey.NETWORK_RETRIEVAL_ENABLED, false);
113
        params.setValue(AVKey.USE_MIP_MAPS, true);
114
        params.setValue(AVKey.USE_TRANSPARENT_TEXTURES, true);
115

    
116
        Sector sector = (Sector) params.getValue(AVKey.SECTOR);
117

    
118
        setTileParameters(layer, sector, params, layerProperties);
119

    
120
        setDetailLevelParameters(layer, sector, params, layerProperties);
121
    }
122

    
123
    protected void setDetailLevelParameters(FLayer layer, Sector sector, AVList params,
124
        RasterLayerProperties3D layerProperties) {
125

    
126
        int numLevels;
127
        // If deatail levels are 0, compute best level of detail number
128
        if (layerProperties.getMinLevel() == 0 && layerProperties.getMaxLevel() == 0) {
129

    
130
            LatLon rasterTileDelta = this.computeRasterTileDelta(params);
131
            LatLon desiredLevelZeroDelta = this.computeDesiredTileDelta(sector);
132
            numLevels = computeNumLevels(desiredLevelZeroDelta, rasterTileDelta);
133

    
134
        } else {
135
            numLevels = layerProperties.getMaxLevel() - layerProperties.getMinLevel();
136
            params.setValue(AVKey.NUM_EMPTY_LEVELS, layerProperties.getMinLevel());
137

    
138
        }
139
        params.setValue(AVKey.NUM_LEVELS, numLevels);
140

    
141
        if (layer instanceof FLyrVect) {
142

    
143
            // Only rasterized vectorial layers
144
            double degrees = DEFAULT_RASTERIZED_LEVEL_ZERO * layerProperties.getLevelZeroResolutionMultiplier();
145
            params.setValue(AVKey.LEVEL_ZERO_TILE_DELTA,
146
                new LatLon(Angle.fromDegrees(degrees), Angle.fromDegrees(degrees)));
147

    
148
        } else {
149

    
150
            LatLon rasterTileDelta = this.computeRasterTileDelta(params);
151
            double scale = Math.pow(2d, numLevels - 1);
152
            LatLon levelZeroTileDelta = LatLon.fromDegrees(
153
                scale * layerProperties.getLevelZeroResolutionMultiplier() * rasterTileDelta.getLatitude().degrees,
154
                scale * layerProperties.getLevelZeroResolutionMultiplier() * rasterTileDelta.getLongitude().degrees);
155
            params.setValue(AVKey.LEVEL_ZERO_TILE_DELTA, levelZeroTileDelta);
156
        }
157

    
158
    }
159

    
160
    protected void setSectorParameters(FLayer layer, AVList params) {
161
        MapControl3D mapControl3D = (MapControl3D) params.getValue(DefaultMapControl3D.GVSIG_MAPCONTROL3D);
162
        Sector sector = null;
163
        IProjection projection = mapControl3D.getMapContext().getProjection();
164
        try {
165
            sector = getSector(layer, projection);
166
        } catch (DataException e) {
167
            LOG.info("Can't create sector from layer {} with projection {}", new Object[] { layer, projection }, e);
168
            return;
169
        }
170

    
171
        params.setValue(AVKey.SECTOR, sector);
172
    }
173

    
174
    protected void setTileParameters(FLayer layer, Sector sector, AVList params,
175
        RasterLayerProperties3D layerProperties) {
176

    
177
        params.setValue(AVKey.TILE_ORIGIN, new LatLon(sector.getMinLatitude(), sector.getMinLongitude()));
178
        // If tile sizes are 0, set defautlt values
179
        params.setValue(AVKey.TILE_WIDTH,
180
            layerProperties.getTileWidth() == 0 ? DEFAULT_TILE_WIDTH : layerProperties.getTileWidth());
181
        params.setValue(AVKey.TILE_HEIGHT,
182
            layerProperties.getTileHeight() == 0 ? DEFAULT_TILE_HEIGHT : layerProperties.getTileHeight());
183

    
184
    }
185

    
186
    protected void setBasicParameters(FLayer layer, AVList params) {
187
        params.setValue(AVKey.DATASET_NAME, layer.getName());
188
        params.setValue(AVKey.DATA_CACHE_NAME, getUniqueCacheId(layer));
189
        params.setValue(AVKey.DISPLAY_NAME, layer.getName());
190
        params.setValue(AVKey.SERVICE_NAME, "Offline");
191
    }
192

    
193
    private Sector getSector(FLayer layer, IProjection projection) throws DataException {
194

    
195
        ICoordTrans ct = null;
196
        IProjection epsg4326 = CRSFactory.getCRS("EPSG:4326");
197
        if(!layer.getProjection().equals(epsg4326)) {
198
            if (layer.getCoordTrans() != null) {
199
                ct = layer.getCoordTrans().getPDest().getCT(epsg4326);
200
            } else {
201
                ct = projection.getCT(epsg4326);
202
            }
203
        }
204
        Point2D p1 = null;
205
        Point2D p2 = null;
206
        Envelope envelope = layer.getFullEnvelope();
207

    
208
        p1 = convert(ct, new Point2D.Double(envelope.getMinimum(0), envelope.getMinimum(1)));
209
        p2 = convert(ct, new Point2D.Double(envelope.getMaximum(0), envelope.getMaximum(1)));
210

    
211
        double minLatitude =
212
            Double.isInfinite(p1.getY()) || p1.getY() < Angle.NEG90.degrees ? Angle.NEG90.degrees : p1.getY();
213
        double maxLatitude =
214
            Double.isInfinite(p2.getY()) || p2.getY() > Angle.POS90.degrees ? Angle.POS90.degrees : p2.getY();
215
        double minLongitude =
216
            Double.isInfinite(p1.getX()) || p1.getX() < Angle.NEG180.degrees ? Angle.NEG180.degrees : p1.getX();
217
        double maxLongitude =
218
            Double.isInfinite(p2.getX()) || p2.getX() > Angle.POS180.degrees ? Angle.POS180.degrees : p2.getX();
219

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

    
222
        return sector;
223
    }
224

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

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

    
241
        return numLevels;
242
    }
243

    
244
    private LatLon computeRasterTileDelta(AVList parameters) {
245

    
246
        Sector sector = (Sector) parameters.getValue(AVKey.SECTOR);
247
        int width = (Integer) parameters.getValue(AVKey.WIDTH);
248
        int height = (Integer) parameters.getValue(AVKey.HEIGHT);
249
        int tileWidth = (Integer) parameters.getValue(AVKey.TILE_WIDTH);
250
        int tileHeight = (Integer) parameters.getValue(AVKey.TILE_HEIGHT);
251

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

    
262
    private LatLon computeRasterPixelSize(Sector sector, int width, int height) {
263
        // Compute the raster's pixel dimension in latitude and longitude. In
264
        // this computation a pixel is assumed to
265
        // cover a finite area.
266
        return LatLon.fromDegrees(sector.getDeltaLatDegrees() / height, 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
    private String getUniqueCacheId(FLayer layer) {
282
        // TODO This is not valid. We have to take in account more properties
283
        // to get unique cache id
284
        try {
285
            // Create MD5 Hash
286
            MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
287

    
288
            String name = layer.getName();
289
            long drawVersion = layer.getDrawVersion();
290
            String dataStoreFullName = null;
291
            if (layer instanceof SingleLayer) {
292
                dataStoreFullName = ((SingleLayer) layer).getDataStore().getFullName();
293
            }
294
            int hashCode = layer.hashCode();
295

    
296
            StringBuilder stb = new StringBuilder();
297
            stb.append(name);
298
            stb.append("$");
299
            stb.append(drawVersion);
300
            stb.append("$");
301
            stb.append(hashCode);
302
            stb.append("$");
303
            if (dataStoreFullName != null) {
304
                stb.append(dataStoreFullName);
305
                stb.append("$");
306
            }
307

    
308
            String id = stb.toString();
309
            digest.update(id.getBytes());
310
            byte messageDigest[] = digest.digest();
311

    
312
            // Create Hex String
313
            StringBuilder hexString = new StringBuilder();
314
            hexString.append(layer.getName());
315
            hexString.append("-");
316
            for (int i = 0; i < messageDigest.length; i++)
317
                hexString.append(Integer.toHexString(0xFF & messageDigest[i]));
318
            return hexString.toString();
319

    
320
        } catch (NoSuchAlgorithmException e) {
321
            LOG.warn("MD5 algorith is not available", e);
322

    
323
            String name = layer.getName();
324
            long drawVersion = layer.getDrawVersion();
325
            String dataStoreFullName = null;
326
            if (layer instanceof SingleLayer) {
327
                dataStoreFullName = ((SingleLayer) layer).getDataStore().getFullName();
328
            }
329
            int hashCode = layer.hashCode();
330

    
331
            StringBuilder stb = new StringBuilder();
332
            stb.append(name);
333
            stb.append("$");
334
            stb.append(drawVersion);
335
            stb.append("$");
336
            stb.append(hashCode);
337
            stb.append("$");
338
            if (dataStoreFullName != null) {
339
                stb.append(dataStoreFullName);
340
                stb.append("$");
341
            }
342

    
343
            return stb.toString();
344
        }
345
    }
346
}