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 / rasterelevation / DefaultRasterElevationLoader.java @ 773

History | View | Annotate | Download (16.5 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.rasterelevation;
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.dataset.Buffer;
43
import org.gvsig.fmap.dal.coverage.grid.render.VisualPropertyListener;
44
import org.gvsig.fmap.dal.coverage.store.props.Statistics;
45
import org.gvsig.fmap.dal.exception.DataException;
46
import org.gvsig.fmap.geom.primitive.Envelope;
47
import org.gvsig.fmap.mapcontext.MapContextLocator;
48
import org.gvsig.fmap.mapcontext.exceptions.LoadLayerException;
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.fmap.mapcontext.rendering.legend.IVectorLegend;
53
import org.gvsig.raster.fmap.layers.FLyrRaster;
54
import org.gvsig.raster.fmap.layers.ILayerState;
55
import org.gvsig.raster.fmap.layers.NotAvailableStateException;
56
import org.gvsig.view3d.lib.api.View3DLocator;
57
import org.gvsig.view3d.lib.api.View3DManager;
58
import org.gvsig.view3d.lib.api.exception.LoadException;
59
import org.gvsig.view3d.lib.api.loader.Loader;
60
import org.gvsig.view3d.lib.api.loader.LoaderParameters;
61
import org.gvsig.view3d.lib.impl.DefaultElevationModel;
62
import org.slf4j.Logger;
63
import org.slf4j.LoggerFactory;
64
import org.w3c.dom.Document;
65

    
66
/**
67
 * 
68
 * @author <a href="mailto:lmarques@disid.com">Lluis Marques</a>
69
 *
70
 */
71
public class DefaultRasterElevationLoader implements Loader {
72

    
73
    private static final Logger LOG = LoggerFactory.getLogger(DefaultRasterElevationLoader.class);
74

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

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

    
83
        DefaultRasterElevationLoaderParameters rasterElevationParameters =
84
            (DefaultRasterElevationLoaderParameters) parameters;
85

    
86
        FLayer layer = (FLayer) rasterElevationParameters.getLayer();
87

    
88
        IProjection projectionLayer = layer.getProjection();
89
        if (!projectionLayer.equals(CRSFactory.getCRS("ESPG:4326"))) {
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 and MapContext 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
        if (layer instanceof FLyrRaster) {
120

    
121
            FLyrRaster rasterLayer = (FLyrRaster) layer;
122
            int[] dataType = rasterLayer.getDataStore().getDataType();
123

    
124
            switch (dataType[0]) {
125
            case Buffer.TYPE_BYTE:
126
                params.setValue(AVKey.DATA_TYPE, AVKey.INT8);
127
                break;
128
            case Buffer.TYPE_SHORT:
129
            case Buffer.TYPE_USHORT:
130
                params.setValue(AVKey.DATA_TYPE, AVKey.INT16);
131
                break;
132
            case Buffer.TYPE_INT:
133
                params.setValue(AVKey.DATA_TYPE, AVKey.INT32);
134
                break;
135
            case Buffer.TYPE_FLOAT:
136
                params.setValue(AVKey.DATA_TYPE, AVKey.FLOAT32);
137
                break;
138
            case Buffer.TYPE_DOUBLE:
139
                params.setValue(AVKey.DATA_TYPE, AVKey.FLOAT64);
140
                break;
141
            case Buffer.TYPE_UNDEFINED:
142
            default:
143
                // throw new UnsupportedDataTypeException(String.format(
144
                // "Unsupported buffer data type %1s", dataType[0]));
145
            }
146

    
147
            params.setValue(AVKey.WIDTH, (int) rasterLayer.getDataStore().getWidth());
148
            params.setValue(AVKey.HEIGHT, (int) rasterLayer.getDataStore().getHeight());
149

    
150
            Statistics statistics = rasterLayer.getDataStore().getStatistics();
151
            params.setValue(AVKey.ELEVATION_MIN, statistics.getMin()[0]);
152
            params.setValue(AVKey.ELEVATION_MAX, statistics.getMax()[0]);
153

    
154
        }
155

    
156
        params.setValue(AVKey.PIXEL_FORMAT, AVKey.ELEVATION);
157
        params.setValue(AVKey.IMAGE_FORMAT, "application/bil32");
158
        params.setValue(AVKey.MISSING_DATA_SIGNAL, rasterElevationParameters.getNoData());
159
        params.setValue(AVKey.ELEVATION_UNIT, rasterElevationParameters.getElevationUnits());
160
        params.setValue(AVKey.BYTE_ORDER, AVKey.LITTLE_ENDIAN);
161
        params.setValue(AVKey.AVAILABLE_IMAGE_FORMATS,
162
            new String[] { params.getValue(AVKey.IMAGE_FORMAT).toString() });
163

    
164
        params.setValue(AVKey.TILE_ORIGIN,
165
            new LatLon(sector.getMinLatitude(), sector.getMinLongitude()));
166
        // If tile sizes are 0, set default values
167
        params.setValue(AVKey.TILE_WIDTH, rasterElevationParameters.getTileSize());
168
        params.setValue(AVKey.TILE_HEIGHT, rasterElevationParameters.getTileSize());
169

    
170
        int numLevels;
171
        // If detail levels are 0, compute best level of detail number
172
        if (rasterElevationParameters.getMinLevel() == 0
173
            && rasterElevationParameters.getMaxLevel() == 0) {
174

    
175
            LatLon rasterTileDelta = this.computeRasterTileDelta(params);
176
            LatLon desiredLevelZeroDelta = this.computeDesiredTileDelta(sector);
177
            numLevels = computeNumLevels(desiredLevelZeroDelta, rasterTileDelta);
178

    
179
        } else {
180
            numLevels =
181
                rasterElevationParameters.getMaxLevel() - rasterElevationParameters.getMinLevel();
182
            params.setValue(AVKey.NUM_EMPTY_LEVELS, rasterElevationParameters.getMinLevel());
183

    
184
        }
185

    
186
        params.setValue(AVKey.NUM_LEVELS, numLevels);
187
        LatLon rasterTileDelta = this.computeRasterTileDelta(params);
188
        double scale = Math.pow(2d, numLevels - 1);
189
        LatLon levelZeroTileDelta =
190
            LatLon.fromDegrees(
191
                scale * rasterElevationParameters.getLevelZeroResolution()
192
                    * rasterTileDelta.getLatitude().degrees,
193
                scale * rasterElevationParameters.getLevelZeroResolution()
194
                    * rasterTileDelta.getLongitude().degrees);
195
        params.setValue(AVKey.LEVEL_ZERO_TILE_DELTA, levelZeroTileDelta);
196

    
197
        // Create configuration document from parameters.
198
        Document doc = TiledImageLayer.createTiledImageLayerConfigDocument(params);
199

    
200
        // Copy parameters to avoid problems
201
        AVList paramsLayer = params.copy();
202

    
203
        DefaultElevationModel elevationModel =
204
            new DefaultElevationModel(doc.getDocumentElement(), paramsLayer);
205
        return elevationModel;
206
    }
207

    
208
    private FLayer createNewProjectedOnTheFlyLayer(FLayer layer, IProjection projectionLayer)
209
        throws LoadLayerException {
210

    
211
        FLayer newLayer = null;
212
        DataStoreParameters parameters = null;
213
        if (layer instanceof FLyrVect) {
214
            FLyrVect layerVect = (FLyrVect) layer;
215
            parameters = layerVect.getFeatureStore().getParameters();
216
        } else if (layer instanceof FLyrRaster) {
217
            FLyrRaster layerRaster = (FLyrRaster) layer;
218
            parameters = layerRaster.getDataStore().getParameters();
219
        }
220

    
221
        newLayer =
222
            MapContextLocator.getMapContextManager().createLayer(layer.getName(), parameters);
223
        newLayer.setCoordTrans(projectionLayer.getCT(CRSFactory.getCRS("EPSG:4326")));
224

    
225
        // Set the same legend/render to new layer
226
        if (newLayer instanceof FLyrVect) {
227
            ((FLyrVect) newLayer).setLegend((IVectorLegend) ((FLyrVect) layer).getLegend());
228
        } else if (newLayer instanceof FLyrRaster) {
229

    
230
            // Set layer initialized and opened to avoid render configurations
231
            // changes
232
            FLyrRaster rasterLayer = (FLyrRaster) newLayer;
233
            rasterLayer.setLayerInitialized(true);
234
            if (rasterLayer instanceof ILayerState) {
235
                try {
236
                    ((ILayerState) rasterLayer).enableOpen();
237
                } catch (NotAvailableStateException e) {
238
                    throw new LoadLayerException(rasterLayer.getName(), e);
239
                }
240
            }
241

    
242
            rasterLayer.getDataStore().setRender(((FLyrRaster) layer).getRender());
243

    
244
            // Add layer to listen visual property changes. This is necessary
245
            // because we are initializing layer manually to avoid render
246
            // filters changes.
247
            if (rasterLayer instanceof VisualPropertyListener) {
248
                rasterLayer.getRender().addVisualPropertyListener(
249
                    (VisualPropertyListener) rasterLayer);
250
            }
251
        }
252

    
253
        View3DManager manager = View3DLocator.getManager();
254
        LoaderParameters loaderParameters = manager.getLoaderParameters(layer);
255
        manager.setLoaderParameters(newLayer, loaderParameters);
256
        return newLayer;
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 Sector getSector(FLayer layer) throws DataException {
326

    
327
        Point2D p1 = null;
328
        Point2D p2 = null;
329
        Envelope envelope = layer.getFullEnvelope();
330

    
331
        p1 = new Point2D.Double(envelope.getMinimum(0), envelope.getMinimum(1));
332
        p2 = new Point2D.Double(envelope.getMaximum(0), envelope.getMaximum(1));
333

    
334
        double minLatitude =
335
            Double.isInfinite(p1.getY()) || p1.getY() < Angle.NEG90.degrees ? Angle.NEG90.degrees
336
                : p1.getY();
337
        double maxLatitude =
338
            Double.isInfinite(p2.getY()) || p2.getY() > Angle.POS90.degrees ? Angle.POS90.degrees
339
                : p2.getY();
340
        double minLongitude =
341
            Double.isInfinite(p1.getX()) || p1.getX() < Angle.NEG180.degrees ? Angle.NEG180.degrees
342
                : p1.getX();
343
        double maxLongitude =
344
            Double.isInfinite(p2.getX()) || p2.getX() > Angle.POS180.degrees ? Angle.POS180.degrees
345
                : p2.getX();
346

    
347
        Sector sector =
348
            new Sector(Sector.fromDegrees(minLatitude, maxLatitude, minLongitude, maxLongitude));
349

    
350
        return sector;
351
    }
352

    
353
    private int computeNumLevels(LatLon levelZeroDelta, LatLon lastLevelDelta) {
354
        // Compute the number of levels needed to achieve the given last level
355
        // tile delta, starting from the given
356
        // level zero tile delta.
357
        double numLatLevels =
358
            WWMath.logBase2(levelZeroDelta.getLatitude().getDegrees())
359
                - WWMath.logBase2(lastLevelDelta.getLatitude().getDegrees());
360
        double numLonLevels =
361
            WWMath.logBase2(levelZeroDelta.getLongitude().getDegrees())
362
                - WWMath.logBase2(lastLevelDelta.getLongitude().getDegrees());
363

    
364
        // Compute the maximum number of levels needed, but limit the number of
365
        // levels to positive integers greater
366
        // than or equal to one.
367
        int numLevels = (int) Math.ceil(Math.max(numLatLevels, numLonLevels));
368
        if (numLevels < 1)
369
            numLevels = 1;
370

    
371
        return numLevels;
372
    }
373

    
374
    private LatLon computeRasterTileDelta(AVList parameters) {
375

    
376
        Sector sector = (Sector) parameters.getValue(AVKey.SECTOR);
377
        int width = (Integer) parameters.getValue(AVKey.WIDTH);
378
        int height = (Integer) parameters.getValue(AVKey.HEIGHT);
379
        int tileWidth = (Integer) parameters.getValue(AVKey.TILE_WIDTH);
380
        int tileHeight = (Integer) parameters.getValue(AVKey.TILE_HEIGHT);
381

    
382
        LatLon pixelSize = this.computeRasterPixelSize(sector, width, height);
383
        // Compute the tile size in latitude and longitude, given a raster's
384
        // sector and dimension, and the tile
385
        // dimensions. In this computation a pixel is assumed to cover a finite
386
        // area.
387
        double latDelta = tileHeight * pixelSize.getLatitude().degrees;
388
        double lonDelta = tileWidth * pixelSize.getLongitude().degrees;
389
        return LatLon.fromDegrees(latDelta, lonDelta);
390
    }
391

    
392
    private LatLon computeRasterPixelSize(Sector sector, int width, int height) {
393
        // Compute the raster's pixel dimension in latitude and longitude. In
394
        // this computation a pixel is assumed to
395
        // cover a finite area.
396
        return LatLon.fromDegrees(sector.getDeltaLatDegrees() / height, sector.getDeltaLonDegrees()
397
            / width);
398
    }
399

    
400
    private LatLon computeDesiredTileDelta(Sector sector) {
401
        return LatLon.fromDegrees(sector.getDeltaLatDegrees(), sector.getDeltaLonDegrees());
402
    }
403
}