Statistics
| Revision:

gvsig-3d / 2.1 / trunk / org.gvsig.view3d / org.gvsig.view3d.lib / org.gvsig.view3d.lib.impl / src / main / java / org / gvsig / view3d / lib / impl / loader / raster / DefaultRasterLoader.java @ 773

History | View | Annotate | Download (15.4 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright ? 2007-2017 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.lib.impl.loader.raster;
25

    
26
import gov.nasa.worldwind.avlist.AVKey;
27
import gov.nasa.worldwind.avlist.AVList;
28
import gov.nasa.worldwind.avlist.AVListImpl;
29
import gov.nasa.worldwind.geom.Angle;
30
import gov.nasa.worldwind.geom.LatLon;
31
import gov.nasa.worldwind.geom.Sector;
32
import gov.nasa.worldwind.layers.TiledImageLayer;
33
import gov.nasa.worldwind.util.WWMath;
34

    
35
import java.awt.geom.Point2D;
36
import java.security.MessageDigest;
37
import java.security.NoSuchAlgorithmException;
38

    
39
import org.cresques.cts.IProjection;
40
import org.gvsig.fmap.crs.CRSFactory;
41
import org.gvsig.fmap.dal.DataStoreParameters;
42
import org.gvsig.fmap.dal.coverage.grid.render.VisualPropertyListener;
43
import org.gvsig.fmap.dal.exception.DataException;
44
import org.gvsig.fmap.geom.primitive.Envelope;
45
import org.gvsig.fmap.mapcontext.MapContextLocator;
46
import org.gvsig.fmap.mapcontext.exceptions.LoadLayerException;
47
import org.gvsig.fmap.mapcontext.layers.FLayer;
48
import org.gvsig.fmap.mapcontext.layers.operations.SingleLayer;
49
import org.gvsig.fmap.mapcontext.layers.vectorial.FLyrVect;
50
import org.gvsig.fmap.mapcontext.rendering.legend.IVectorLegend;
51
import org.gvsig.raster.fmap.layers.FLyrRaster;
52
import org.gvsig.raster.fmap.layers.ILayerState;
53
import org.gvsig.raster.fmap.layers.NotAvailableStateException;
54
import org.gvsig.view3d.lib.api.View3DLocator;
55
import org.gvsig.view3d.lib.api.View3DManager;
56
import org.gvsig.view3d.lib.api.exception.LoadException;
57
import org.gvsig.view3d.lib.api.loader.Loader;
58
import org.gvsig.view3d.lib.api.loader.LoaderParameters;
59
import org.gvsig.view3d.lib.impl.DefaultTiledImageLayer;
60
import org.slf4j.Logger;
61
import org.slf4j.LoggerFactory;
62
import org.w3c.dom.Document;
63

    
64
/**
65
 * @author <a href="mailto:lmarques@disid.com">Lluis Marques</a>
66
 *
67
 */
68
public class DefaultRasterLoader implements Loader {
69

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

    
72
    private final int DEFAULT_RASTERIZED_LEVEL_ZERO = 20;
73

    
74
    @Override
75
    public Object load(LoaderParameters parameters) throws LoadException {
76

    
77
        if (!(parameters instanceof DefaultRasterLoaderParameters)) {
78
            throw new IllegalArgumentException(
79
                "Illegal parameters, it must be an instance of RasterLoaderParameters");
80
        }
81

    
82
        DefaultRasterLoaderParameters rasterParameters = (DefaultRasterLoaderParameters) parameters;
83
        FLayer layer = (FLayer) rasterParameters.getLayer();
84

    
85
        IProjection projectionLayer = layer.getProjection();
86
        if (!projectionLayer.equals(CRSFactory.getCRS("ESPG:4326"))) {
87

    
88
            // Create new layer and configure it to be drawn projected on the
89
            // fly
90
            try {
91
                layer = createNewProjectedOnTheFlyLayer(layer, projectionLayer);
92
            } catch (LoadLayerException e) {
93
                // throw new
94
                // ConversionLayerException("Can not create layer and set"
95
                // + " project on the fly configuration", e);
96
            }
97
        }
98

    
99
        AVList params = new AVListImpl();
100

    
101
        // Add Layer to parameters.
102
        params.setValue(View3DManager.GVSIG_LAYER, layer);
103

    
104
        params.setValue(AVKey.DATASET_NAME, layer.getName());
105
        params.setValue(AVKey.DATA_CACHE_NAME, getUniqueCacheId(layer));
106
        params.setValue(AVKey.DISPLAY_NAME, layer.getName());
107
        params.setValue(AVKey.SERVICE_NAME, "Offline");
108

    
109
        Sector sector = null;
110
        try {
111
            sector = getSector(layer);
112
        } catch (DataException e) {
113
            LOG.error("Can't create sector from {} layer", new Object[] { layer }, e);
114
            throw new LoadException(layer.getName(), e);
115
        }
116

    
117
        params.setValue(AVKey.SECTOR, sector);
118

    
119
        // Set resolution of layer
120
        params.setValue(AVKey.WIDTH, Integer.MAX_VALUE);
121
        params.setValue(AVKey.HEIGHT, Integer.MAX_VALUE);
122
        params.setValue(AVKey.IMAGE_FORMAT, "image/png");
123
        params.setValue(AVKey.PIXEL_FORMAT, AVKey.IMAGE);
124
        params.setValue(AVKey.TEXTURE_FORMAT, "image/dds");
125
        params.setValue(AVKey.FORMAT_SUFFIX, ".png");
126
        params.setValue(AVKey.AVAILABLE_IMAGE_FORMATS,
127
            new String[] { params.getValue(AVKey.IMAGE_FORMAT).toString() });
128
        params.setValue(AVKey.NETWORK_RETRIEVAL_ENABLED, false);
129
        params.setValue(AVKey.USE_MIP_MAPS, true);
130
        params.setValue(AVKey.USE_TRANSPARENT_TEXTURES, true);
131
        params.setValue(AVKey.TILE_ORIGIN,
132
            new LatLon(sector.getMinLatitude(), sector.getMinLongitude()));
133
        params.setValue(AVKey.TILE_WIDTH, rasterParameters.getTileSize());
134
        params.setValue(AVKey.TILE_HEIGHT, rasterParameters.getTileSize());
135

    
136
        int numLevels;
137
        // If detail levels are 0, compute best level of detail number
138
        if (rasterParameters.getMinLevel() == 0 && rasterParameters.getMaxLevel() == 0) {
139

    
140
            LatLon rasterTileDelta = this.computeRasterTileDelta(params);
141
            LatLon desiredLevelZeroDelta = this.computeDesiredTileDelta(sector);
142
            numLevels = computeNumLevels(desiredLevelZeroDelta, rasterTileDelta);
143

    
144
        } else {
145
            numLevels = rasterParameters.getMaxLevel() - rasterParameters.getMinLevel();
146
            params.setValue(AVKey.NUM_EMPTY_LEVELS, rasterParameters.getMinLevel());
147

    
148
        }
149
        params.setValue(AVKey.NUM_LEVELS, numLevels);
150

    
151
        if (layer instanceof FLyrVect) {
152
            // Only rasterized vector layers
153
            double degrees =
154
                DEFAULT_RASTERIZED_LEVEL_ZERO * rasterParameters.getLevelZeroResolution();
155
            params.setValue(AVKey.LEVEL_ZERO_TILE_DELTA, new LatLon(Angle.fromDegrees(degrees),
156
                Angle.fromDegrees(degrees)));
157
        } else {
158
            LatLon rasterTileDelta = this.computeRasterTileDelta(params);
159
            double scale = Math.pow(2d, numLevels - 1);
160
            LatLon levelZeroTileDelta =
161
                LatLon.fromDegrees(
162
                    scale * rasterParameters.getLevelZeroResolution()
163
                        * rasterTileDelta.getLatitude().degrees,
164
                    scale * rasterParameters.getLevelZeroResolution()
165
                        * rasterTileDelta.getLongitude().degrees);
166
            params.setValue(AVKey.LEVEL_ZERO_TILE_DELTA, levelZeroTileDelta);
167
        }
168

    
169
        // Create configuration document from parameters.
170
        Document doc = TiledImageLayer.createTiledImageLayerConfigDocument(params);
171

    
172
        // Copy parameters to avoid problems
173
        AVList paramsLayer = params.copy();
174

    
175
        DefaultTiledImageLayer rasterLayer =
176
            new DefaultTiledImageLayer(doc.getDocumentElement(), paramsLayer);
177
        return rasterLayer;
178
    }
179

    
180
    private FLayer createNewProjectedOnTheFlyLayer(FLayer layer, IProjection projectionLayer)
181
        throws LoadLayerException {
182

    
183
        FLayer newLayer = null;
184
        DataStoreParameters parameters = null;
185
        if (layer instanceof FLyrVect) {
186
            FLyrVect layerVect = (FLyrVect) layer;
187
            parameters = layerVect.getFeatureStore().getParameters();
188
        } else if (layer instanceof FLyrRaster) {
189
            FLyrRaster layerRaster = (FLyrRaster) layer;
190
            parameters = layerRaster.getDataStore().getParameters();
191
        }
192

    
193
        newLayer =
194
            MapContextLocator.getMapContextManager().createLayer(layer.getName(), parameters);
195
        newLayer.setCoordTrans(projectionLayer.getCT(CRSFactory.getCRS("EPSG:4326")));
196

    
197
        // Set the same legend/render to new layer
198
        if (newLayer instanceof FLyrVect) {
199
            ((FLyrVect) newLayer).setLegend((IVectorLegend) ((FLyrVect) layer).getLegend());
200
        } else if (newLayer instanceof FLyrRaster) {
201

    
202
            // Set layer initialized and opened to avoid render configurations
203
            // changes
204
            FLyrRaster rasterLayer = (FLyrRaster) newLayer;
205
            rasterLayer.setLayerInitialized(true);
206
            if (rasterLayer instanceof ILayerState) {
207
                try {
208
                    ((ILayerState) rasterLayer).enableOpen();
209
                } catch (NotAvailableStateException e) {
210
                    throw new LoadLayerException(rasterLayer.getName(), e);
211
                }
212
            }
213

    
214
            rasterLayer.getDataStore().setRender(((FLyrRaster) layer).getRender());
215

    
216
            // Add layer to listen visual property changes. This is necessary
217
            // because we are initializing layer manually to avoid render
218
            // filters changes.
219
            if (rasterLayer instanceof VisualPropertyListener) {
220
                rasterLayer.getRender().addVisualPropertyListener(
221
                    (VisualPropertyListener) rasterLayer);
222
            }
223
        }
224
        
225
        View3DManager manager = View3DLocator.getManager();
226
        LoaderParameters loaderParameters = manager.getLoaderParameters(layer);
227
        manager.setLoaderParameters(newLayer, loaderParameters);
228
        return newLayer;
229
    }
230

    
231
    private Sector getSector(FLayer layer) throws DataException {
232

    
233
        Point2D p1 = null;
234
        Point2D p2 = null;
235
        Envelope envelope = layer.getFullEnvelope();
236

    
237
        p1 = new Point2D.Double(envelope.getMinimum(0), envelope.getMinimum(1));
238
        p2 = new Point2D.Double(envelope.getMaximum(0), envelope.getMaximum(1));
239

    
240
        double minLatitude =
241
            Double.isInfinite(p1.getY()) || p1.getY() < Angle.NEG90.degrees ? Angle.NEG90.degrees
242
                : p1.getY();
243
        double maxLatitude =
244
            Double.isInfinite(p2.getY()) || p2.getY() > Angle.POS90.degrees ? Angle.POS90.degrees
245
                : p2.getY();
246
        double minLongitude =
247
            Double.isInfinite(p1.getX()) || p1.getX() < Angle.NEG180.degrees ? Angle.NEG180.degrees
248
                : p1.getX();
249
        double maxLongitude =
250
            Double.isInfinite(p2.getX()) || p2.getX() > Angle.POS180.degrees ? Angle.POS180.degrees
251
                : p2.getX();
252

    
253
        Sector sector =
254
            new Sector(Sector.fromDegrees(minLatitude, maxLatitude, minLongitude, maxLongitude));
255

    
256
        return sector;
257
    }
258

    
259
    private String getUniqueCacheId(FLayer layer) {
260
        // TODO This is not valid. We have to take in account more properties
261
        // to get unique cache id
262
        try {
263
            // Create MD5 Hash
264
            MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
265

    
266
            String name = layer.getName();
267
            long drawVersion = layer.getDrawVersion();
268
            String dataStoreFullName = null;
269
            if (layer instanceof SingleLayer) {
270
                dataStoreFullName = ((SingleLayer) layer).getDataStore().getFullName();
271
            }
272
            int hashCode = layer.hashCode();
273

    
274
            StringBuilder stb = new StringBuilder();
275
            stb.append(name);
276
            stb.append("$");
277
            stb.append(drawVersion);
278
            stb.append("$");
279
            stb.append(hashCode);
280
            stb.append("$");
281
            if (dataStoreFullName != null) {
282
                stb.append(dataStoreFullName);
283
                stb.append("$");
284
            }
285

    
286
            String id = stb.toString();
287
            digest.update(id.getBytes());
288
            byte messageDigest[] = digest.digest();
289

    
290
            // Create Hex String
291
            StringBuilder hexString = new StringBuilder();
292
            hexString.append(layer.getName());
293
            hexString.append("-");
294
            for (int i = 0; i < messageDigest.length; i++)
295
                hexString.append(Integer.toHexString(0xFF & messageDigest[i]));
296
            return hexString.toString();
297

    
298
        } catch (NoSuchAlgorithmException e) {
299
            LOG.warn("MD5 algorith is not available", e);
300

    
301
            String name = layer.getName();
302
            long drawVersion = layer.getDrawVersion();
303
            String dataStoreFullName = null;
304
            if (layer instanceof SingleLayer) {
305
                dataStoreFullName = ((SingleLayer) layer).getDataStore().getFullName();
306
            }
307
            int hashCode = layer.hashCode();
308

    
309
            StringBuilder stb = new StringBuilder();
310
            stb.append(name);
311
            stb.append("$");
312
            stb.append(drawVersion);
313
            stb.append("$");
314
            stb.append(hashCode);
315
            stb.append("$");
316
            if (dataStoreFullName != null) {
317
                stb.append(dataStoreFullName);
318
                stb.append("$");
319
            }
320

    
321
            return stb.toString();
322
        }
323
    }
324

    
325
    private int computeNumLevels(LatLon levelZeroDelta, LatLon lastLevelDelta) {
326
        // Compute the number of levels needed to achieve the given last level
327
        // tile delta, starting from the given
328
        // level zero tile delta.
329
        double numLatLevels =
330
            WWMath.logBase2(levelZeroDelta.getLatitude().getDegrees())
331
                - WWMath.logBase2(lastLevelDelta.getLatitude().getDegrees());
332
        double numLonLevels =
333
            WWMath.logBase2(levelZeroDelta.getLongitude().getDegrees())
334
                - WWMath.logBase2(lastLevelDelta.getLongitude().getDegrees());
335

    
336
        // Compute the maximum number of levels needed, but limit the number of
337
        // levels to positive integers greater
338
        // than or equal to one.
339
        int numLevels = (int) Math.ceil(Math.max(numLatLevels, numLonLevels));
340
        if (numLevels < 1)
341
            numLevels = 1;
342

    
343
        return numLevels;
344
    }
345

    
346
    private LatLon computeRasterTileDelta(AVList parameters) {
347

    
348
        Sector sector = (Sector) parameters.getValue(AVKey.SECTOR);
349
        int width = (Integer) parameters.getValue(AVKey.WIDTH);
350
        int height = (Integer) parameters.getValue(AVKey.HEIGHT);
351
        int tileWidth = (Integer) parameters.getValue(AVKey.TILE_WIDTH);
352
        int tileHeight = (Integer) parameters.getValue(AVKey.TILE_HEIGHT);
353

    
354
        LatLon pixelSize = this.computeRasterPixelSize(sector, width, height);
355
        // Compute the tile size in latitude and longitude, given a raster's
356
        // sector and dimension, and the tile
357
        // dimensions. In this computation a pixel is assumed to cover a finite
358
        // area.
359
        double latDelta = tileHeight * pixelSize.getLatitude().degrees;
360
        double lonDelta = tileWidth * pixelSize.getLongitude().degrees;
361
        return LatLon.fromDegrees(latDelta, lonDelta);
362
    }
363

    
364
    private LatLon computeRasterPixelSize(Sector sector, int width, int height) {
365
        // Compute the raster's pixel dimension in latitude and longitude. In
366
        // this computation a pixel is assumed to
367
        // cover a finite area.
368
        return LatLon.fromDegrees(sector.getDeltaLatDegrees() / height, sector.getDeltaLonDegrees()
369
            / width);
370
    }
371

    
372
    private LatLon computeDesiredTileDelta(Sector sector) {
373
        return LatLon.fromDegrees(sector.getDeltaLatDegrees(), sector.getDeltaLonDegrees());
374
    }
375
}