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 / GvSIGLayerDataRaster.java @ 497

History | View | Annotate | Download (18 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.WWObjectImpl;
28
import gov.nasa.worldwind.avlist.AVKey;
29
import gov.nasa.worldwind.avlist.AVList;
30
import gov.nasa.worldwind.data.BufferWrapperRaster;
31
import gov.nasa.worldwind.data.BufferedImageRaster;
32
import gov.nasa.worldwind.data.DataRaster;
33
import gov.nasa.worldwind.geom.Sector;
34
import gov.nasa.worldwind.util.BufferWrapper;
35

    
36
import java.awt.Dimension;
37
import java.awt.Graphics2D;
38
import java.awt.Rectangle;
39
import java.awt.geom.AffineTransform;
40
import java.awt.geom.Point2D;
41
import java.awt.image.BufferedImage;
42
import java.nio.ByteBuffer;
43

    
44
import org.cresques.cts.ICoordTrans;
45
import org.cresques.cts.IProjection;
46
import org.gvsig.fmap.crs.CRSFactory;
47
import org.gvsig.fmap.dal.coverage.RasterLocator;
48
import org.gvsig.fmap.dal.coverage.dataset.Buffer;
49
import org.gvsig.fmap.dal.coverage.exception.ProcessInterruptedException;
50
import org.gvsig.fmap.dal.coverage.exception.QueryException;
51
import org.gvsig.fmap.dal.coverage.store.RasterQuery;
52
import org.gvsig.fmap.dal.exception.ReadException;
53
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
54
import org.gvsig.fmap.geom.GeometryLocator;
55
import org.gvsig.fmap.geom.GeometryManager;
56
import org.gvsig.fmap.geom.exception.CreateEnvelopeException;
57
import org.gvsig.fmap.geom.primitive.Envelope;
58
import org.gvsig.fmap.mapcontext.MapContext;
59
import org.gvsig.fmap.mapcontext.ViewPort;
60
import org.gvsig.fmap.mapcontext.layers.FLayer;
61
import org.gvsig.fmap.mapcontext.layers.vectorial.FLyrVect;
62
import org.gvsig.fmap.mapcontext.rendering.legend.styling.ILabelable;
63
import org.gvsig.raster.fmap.layers.FLyrRaster;
64
import org.gvsig.view3d.lib.api.View3DLocator;
65
import org.gvsig.view3d.lib.api.View3DManager;
66
import org.gvsig.view3d.lib.api.properties.LayerProperties3D;
67
import org.gvsig.view3d.swing.api.MapControl3D;
68
import org.slf4j.Logger;
69
import org.slf4j.LoggerFactory;
70

    
71
/**
72
 * Default implementation of {@link DataRaster}.
73
 * 
74
 * @author <a href="mailto:lmarques@disid.com">Lluis Marques</a>
75
 *
76
 */
77
@SuppressWarnings("deprecation")
78
public class GvSIGLayerDataRaster extends WWObjectImpl implements DataRaster {
79

    
80
    private static final Logger LOG = LoggerFactory
81
        .getLogger(GvSIGLayerDataRaster.class);
82

    
83
    private MapControl3D mapControl3D;
84
    private FLayer layer;
85

    
86
    /**
87
     * Default constructor of <code>GvSIGLayerDataRaster</code>
88
     * 
89
     * @param mapControl3D
90
     *            context where {@link FLayer} is loaded.
91
     * @param theLayer
92
     *            source to get raster information
93
     * @param params
94
     *            parameters of <code>GvSIGLayerDataRaster</code>
95
     */
96
    public GvSIGLayerDataRaster(MapControl3D mapControl3D, FLayer theLayer,
97
        AVList params) {
98

    
99
        if (params == null || mapControl3D == null || theLayer == null) {
100
            throw new IllegalArgumentException();
101
        }
102

    
103
        this.layer = theLayer;
104
        this.mapControl3D = mapControl3D;
105
        this.setValues(params.copy());
106
    }
107

    
108
    public void dispose() {
109
    }
110

    
111
    public int getWidth() {
112
        return (Integer) this.getValue(AVKey.WIDTH);
113
    }
114

    
115
    public int getHeight() {
116
        return (Integer) this.getValue(AVKey.HEIGHT);
117
    }
118

    
119
    public Sector getSector() {
120

    
121
        return (Sector) this.getValue(AVKey.SECTOR);
122

    
123
    }
124

    
125
    public void drawOnTo(DataRaster canvas) {
126
        View3DManager manager = View3DLocator.getManager();
127
        LayerProperties3D properties = manager.getLayerProperties(layer);
128

    
129
        if (properties.getElevation() == true) {
130
            if (this.layer instanceof FLyrRaster) {
131
                this.drawRasterElevationOnTo(canvas);
132
            } else if (this.layer instanceof FLyrVect) {
133
                this.drawVectElevationOnTo(canvas);
134
            }
135
        } else {
136
            this.drawImageOnTo(canvas);
137
        }
138
    }
139

    
140
    private void drawRasterElevationOnTo(DataRaster canvas) {
141

    
142
        if (canvas == null) {
143
            throw new IllegalArgumentException();
144
        }
145

    
146
        if (!(this.layer instanceof FLyrRaster)
147
            || !canvas.getSector().intersects(getSector())) {
148
            return;
149
        }
150

    
151
        FLyrRaster rasterLayer = (FLyrRaster) this.layer;
152

    
153
        Sector overlap = this.getSector().intersection(canvas.getSector());
154

    
155
        java.awt.Rectangle clipRect = this.computeClipRect(overlap, this);
156
        if (null == clipRect || clipRect.width == 0 || clipRect.height == 0) {
157
            return;
158
        }
159

    
160
        LOG.debug("Request zone: x = {} y= {} width = {} height = {}",
161
            new Object[] { clipRect.x, clipRect.y, clipRect.width,
162
                clipRect.height });
163

    
164
        RasterQuery query = RasterLocator.getManager().createQuery();
165
        query.setSupersamplingOption(false);
166
        query.setDrawableBands(new int[] { 0 });
167
        query.setReadOnly(true);
168
        query.setAreaOfInterest(clipRect);
169

    
170
        Buffer buffer = null;
171
        try {
172
            buffer = rasterLayer.getDataStore().query(query);
173
        } catch (ProcessInterruptedException e) {
174
            LOG.error("Process interrupted while {} was executing a query",
175
                rasterLayer.getDataStore().getName(), e);
176
            return;
177
        } catch (QueryException e) {
178
            LOG.error("Query exception, can apply {} to {}", new Object[] {
179
                query.toString(), rasterLayer.getDataStore().getName() }, e);
180
            return;
181
        }
182

    
183
        // Create buffer depending on data type
184
        String dataType = (String) this.getValue(AVKey.DATA_TYPE);
185
        int bytesNumber = getBytesNumber(dataType);
186
        ByteBuffer byteBuffer =
187
            ByteBuffer.allocate(buffer.getWidth() * buffer.getHeight()
188
                * bytesNumber);
189

    
190
        LOG.debug("Start iterator buffer");
191
        long startTime = System.currentTimeMillis();
192
        for (int i = 0; i < buffer.getHeight(); i++) {
193
            for (int j = 0; j < buffer.getWidth(); j++) {
194
                if (AVKey.INT8.equals(dataType)) {
195
                    byte elemByte = buffer.getElemByte(i, j, 0);
196
                    byteBuffer.put(elemByte);
197
                } else if (AVKey.INT16.equals(dataType)) {
198
                    short elemShort = buffer.getElemShort(i, j, 0);
199
                    byteBuffer.putShort(elemShort);
200
                } else if (AVKey.INT32.equals(dataType)) {
201
                    int elemInteger = buffer.getElemInt(i, j, 0);
202
                    byteBuffer.putInt(elemInteger);
203
                } else if (AVKey.FLOAT32.equals(dataType)) {
204
                    float elemFloat = buffer.getElemFloat(i, j, 0);
205
                    byteBuffer.putFloat(elemFloat);
206
                } else if (AVKey.FLOAT64.equals(dataType)) {
207
                    double elemDouble = buffer.getElemDouble(i, j, 0);
208
                    byteBuffer.putDouble(elemDouble);
209
                }
210
            }
211
        }
212
        LOG.debug("Finish iterator buffer. Time {}", System.currentTimeMillis()
213
            - startTime);
214

    
215
        byteBuffer.position(0);
216

    
217
        BufferWrapper wrap = BufferWrapper.wrap(byteBuffer, this.copy());
218

    
219
        BufferWrapperRaster bufferWrapper =
220
            new BufferWrapperRaster(buffer.getWidth(), buffer.getHeight(),
221
                overlap, wrap, this.copy());
222
        bufferWrapper.drawOnTo(canvas);
223
    }
224

    
225
    private void drawVectElevationOnTo(DataRaster canvas) {
226
        // TODO Auto-generated method stub
227

    
228
    }
229

    
230
    private int getBytesNumber(String dataType) {
231

    
232
        if (AVKey.INT8.equals(dataType)) {
233
            return 1;
234
        } else if (AVKey.INT16.equals(dataType)) {
235
            return 2;
236
        } else if (AVKey.INT32.equals(dataType)
237
            || AVKey.FLOAT32.equals(dataType)) {
238
            return 4;
239
        } else if (AVKey.FLOAT64.equals(dataType)) {
240
            return 8;
241
        }
242

    
243
        return 1;
244
    }
245

    
246
    private void drawImageOnTo(DataRaster canvas) {
247
        if (canvas == null) {
248
            throw new IllegalArgumentException();
249
        }
250

    
251
        if (!canvas.getSector().intersects(getSector())) {
252
            return;
253
        }
254

    
255
        Sector overlap = this.getSector().intersection(canvas.getSector());
256

    
257
        ViewPort viewPort =
258
            new ViewPort(mapControl3D.getMapContext().getProjection());
259

    
260
        // Set adjustable to false to avoid problems with adjusted envelope
261
        viewPort.setAdjustable(false);
262

    
263
        GeometryManager geoManager = GeometryLocator.getGeometryManager();
264

    
265
        Envelope envelope = null;
266
        double[] degrees = overlap.asDegreesArray();
267

    
268
        try {
269

    
270
            IProjection projection =
271
                mapControl3D.getMapContext().getProjection();
272

    
273
            ICoordTrans ct = CRSFactory.getCRS("EPSG:4326").getCT(projection);
274
            Point2D p1 =
275
                convert(ct, new Point2D.Double(degrees[2], degrees[0]));
276
            Point2D p2 =
277
                convert(ct, new Point2D.Double(degrees[3], degrees[1]));
278

    
279
            envelope =
280
                geoManager.createEnvelope(Math.min(p1.getX(), p2.getX()),
281
                    Math.min(p1.getY(), p2.getY()),
282
                    Math.max(p1.getX(), p2.getX()),
283
                    Math.max(p1.getY(), p2.getY()), SUBTYPES.GEOM2D);
284

    
285
            /**
286
             * Check if request tile intersect with layer envelope to avoid
287
             * the creation of useless tiles.
288
             */
289
            if (!envelope.intersects(layer.getFullEnvelope())) {
290
                return;
291
            }
292

    
293
            viewPort.setEnvelope(envelope);
294

    
295
        } catch (CreateEnvelopeException e) {
296
            LOG.error(
297
                "Can't create envelope from sector tile:  minLat {} maxLat {} minLon {} maxLon {}",
298
                new Object[] { degrees[0], degrees[1], degrees[2], degrees[3] });
299
            return;
300
        } catch (ReadException e) {
301
            LOG.warn("Can't get full envelope of {}", layer.getName());
302
        }
303

    
304
        int canvasWidth = canvas.getWidth();
305
        int canvasHeight = canvas.getHeight();
306

    
307
        java.awt.Rectangle clipRect = this.computeClipRect(overlap, this);
308
        if (null == clipRect || clipRect.width == 0 || clipRect.height == 0) {
309
            return;
310
        }
311

    
312
        // Apply the transform that correctly maps the image onto the canvas.
313
        java.awt.geom.AffineTransform affineTransform =
314
            this.computeSourceToDestTransform(clipRect.width, clipRect.height,
315
                overlap, canvasWidth, canvasHeight, canvas.getSector());
316

    
317
        // Trick to apply transform to size value
318
        Point2D srcSizePoint =
319
            new Point2D.Double(clipRect.width, clipRect.height);
320
        Point2D dstSizePoint = new Point2D.Double();
321

    
322
        affineTransform.transform(srcSizePoint, dstSizePoint);
323

    
324
        int clipWidth =
325
            (int) Math.ceil((dstSizePoint.getX() >= canvasWidth) ? canvasWidth
326
                : dstSizePoint.getX());
327
        int clipHeight =
328
            (int) Math.ceil((dstSizePoint.getY() >= canvasHeight)
329
                ? canvasHeight : dstSizePoint.getY());
330

    
331
        if (clipWidth <= 0 || clipHeight <= 0) {
332
            return;
333
        }
334

    
335
        BufferedImage image =
336
            new BufferedImage(clipWidth, clipHeight,
337
                BufferedImage.TYPE_INT_ARGB);
338

    
339
        viewPort.setImageSize(new Dimension(clipWidth, clipHeight));
340
        viewPort.refreshExtent();
341

    
342
        try {
343
            layer.draw(image, (Graphics2D) image.getGraphics(), viewPort,
344
                mapControl3D.getCancellable(), getScale(viewPort));
345

    
346
            if (layer instanceof FLyrVect && layer instanceof ILabelable) {
347

    
348
                ILabelable labelable = (ILabelable) layer;
349

    
350
                if (labelable.isLabeled()
351
                    && labelable.getLabelingStrategy() != null
352
                    && labelable.getLabelingStrategy().shouldDrawLabels(
353
                        getScale(viewPort))) {
354

    
355
                    labelable.drawLabels(image,
356
                        (Graphics2D) image.getGraphics(), viewPort,
357
                        mapControl3D.getCancellable(), getScale(viewPort),
358
                        mapControl3D.getMapContext().getViewPort().getDPI());
359
                }
360
            }
361

    
362
        } catch (ReadException e) {
363
            LOG.warn("Can't draw required zone of layer {}, can't read legend",
364
                layer.getName());
365
            return;
366
        } finally {
367
            if (mapControl3D.getCancellable().isCanceled()) {
368
                return;
369
            }
370
        }
371
        BufferedImageRaster bufferedImageRaster =
372
            new BufferedImageRaster(overlap, image);
373
        bufferedImageRaster.drawOnTo(canvas);
374

    
375
    }
376

    
377
    private Point2D convert(ICoordTrans ct, Point2D srcPoint) {
378
        if (ct == null) {
379
            return srcPoint;
380
        }
381
        return ct.convert(srcPoint, null);
382
    }
383

    
384
    private java.awt.geom.AffineTransform computeSourceToDestTransform(
385
        int sourceWidth, int sourceHeight, Sector sourceSector, int destWidth,
386
        int destHeight, Sector destSector) {
387
        // Compute the the transform from source to destination coordinates. In
388
        // this computation a pixel is assumed
389
        // to cover a finite area.
390

    
391
        double ty =
392
            destHeight
393
                * -(sourceSector.getMaxLatitude().degrees - destSector
394
                    .getMaxLatitude().degrees)
395
                / destSector.getDeltaLatDegrees();
396
        double tx =
397
            destWidth
398
                * (sourceSector.getMinLongitude().degrees - destSector
399
                    .getMinLongitude().degrees)
400
                / destSector.getDeltaLonDegrees();
401

    
402
        double sy =
403
            ((double) destHeight / (double) sourceHeight)
404
                * (sourceSector.getDeltaLatDegrees() / destSector
405
                    .getDeltaLatDegrees());
406
        double sx =
407
            ((double) destWidth / (double) sourceWidth)
408
                * (sourceSector.getDeltaLonDegrees() / destSector
409
                    .getDeltaLonDegrees());
410

    
411
        java.awt.geom.AffineTransform transform =
412
            new java.awt.geom.AffineTransform();
413
        transform.translate(tx, ty);
414
        transform.scale(sx, sy);
415
        return transform;
416
    }
417

    
418
    private double getScale(ViewPort viewPort) {
419

    
420
        double dpi = viewPort.getDPI();
421
        IProjection proj = viewPort.getProjection();
422

    
423
        if (viewPort.getImageSize() == null) {
424
            return -1;
425
        }
426

    
427
        if (viewPort.getAdjustedEnvelope() == null) {
428
            return 0;
429
        }
430
        double[] trans2Meter = MapContext.getDistanceTrans2Meter();
431
        int mUnits = viewPort.getMapUnits();
432

    
433
        if (proj == null) {
434
            double w = ((viewPort.getImageSize().width / dpi) * 0.0254);
435
            return (long) (viewPort.getAdjustedEnvelope().getLength(0) / w * trans2Meter[mUnits]);
436
        }
437

    
438
        return Math.round(proj.getScale(viewPort.getAdjustedEnvelope()
439
            .getMinimum(0) * trans2Meter[mUnits], viewPort
440
            .getAdjustedEnvelope().getMaximum(0) * trans2Meter[mUnits],
441
            viewPort.getImageSize().width, dpi));
442
    }
443

    
444
    private Rectangle computeClipRect(Sector clipSector,
445
        DataRaster clippedRaster) {
446

    
447
        AffineTransform geographicToRaster =
448
            this.computeGeographicToRasterTransform(clippedRaster.getWidth(),
449
                clippedRaster.getHeight(), clippedRaster.getSector());
450

    
451
        java.awt.geom.Point2D geoPoint = new java.awt.geom.Point2D.Double();
452
        java.awt.geom.Point2D ul = new java.awt.geom.Point2D.Double();
453
        java.awt.geom.Point2D lr = new java.awt.geom.Point2D.Double();
454

    
455
        geoPoint.setLocation(clipSector.getMinLongitude().degrees,
456
            clipSector.getMaxLatitude().degrees);
457
        geographicToRaster.transform(geoPoint, ul);
458

    
459
        geoPoint.setLocation(clipSector.getMaxLongitude().degrees,
460
            clipSector.getMinLatitude().degrees);
461
        geographicToRaster.transform(geoPoint, lr);
462

    
463
        int x = (int) Math.floor(ul.getX());
464
        int y = (int) Math.floor(ul.getY());
465
        int width = (int) Math.ceil(lr.getX() - ul.getX());
466
        int height = (int) Math.ceil(lr.getY() - ul.getY());
467

    
468
        return new Rectangle(x, y, width, height);
469
    }
470

    
471
    private java.awt.geom.AffineTransform computeGeographicToRasterTransform(
472
        int width, int height, Sector sector) {
473
        // Compute the the transform from geographic to raster coordinates. In
474
        // this computation a pixel is assumed
475
        // to cover a finite area.
476

    
477
        double ty = -sector.getMaxLatitude().degrees;
478
        double tx = -sector.getMinLongitude().degrees;
479

    
480
        double sy = -(height / sector.getDeltaLatDegrees());
481
        double sx = (width / sector.getDeltaLonDegrees());
482

    
483
        java.awt.geom.AffineTransform transform =
484
            new java.awt.geom.AffineTransform();
485
        transform.scale(sx, sy);
486
        transform.translate(tx, ty);
487
        return transform;
488
    }
489

    
490
    public DataRaster getSubRaster(AVList params) {
491
        int width = (Integer) params.getValue(AVKey.WIDTH);
492
        int height = (Integer) params.getValue(AVKey.HEIGHT);
493
        Sector sector = (Sector) params.getValue(AVKey.SECTOR);
494

    
495
        return this.getSubRaster(width, height, sector, params);
496
    }
497

    
498
    public DataRaster getSubRaster(int width, int height, Sector sector,
499
        AVList params) {
500

    
501
        params.setValue(AVKey.WIDTH, width);
502
        params.setValue(AVKey.HEIGHT, height);
503
        params.setValue(AVKey.SECTOR, sector);
504

    
505
        GvSIGLayerDataRaster subRaster =
506
            new GvSIGLayerDataRaster(mapControl3D, layer, params);
507
        return subRaster;
508
    }
509
}