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

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

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

    
43
import org.cresques.cts.IProjection;
44
import org.gvsig.fmap.dal.coverage.RasterLocator;
45
import org.gvsig.fmap.dal.coverage.RasterManager;
46
import org.gvsig.fmap.dal.coverage.dataset.Buffer;
47
import org.gvsig.fmap.dal.coverage.datastruct.DataStructFactory;
48
import org.gvsig.fmap.dal.coverage.datastruct.Extent;
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.exception.WarpException;
52
import org.gvsig.fmap.dal.coverage.store.RasterDataStore;
53
import org.gvsig.fmap.dal.coverage.store.RasterQuery;
54
import org.gvsig.fmap.dal.exception.ReadException;
55
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
56
import org.gvsig.fmap.geom.GeometryLocator;
57
import org.gvsig.fmap.geom.GeometryManager;
58
import org.gvsig.fmap.geom.exception.CreateEnvelopeException;
59
import org.gvsig.fmap.geom.primitive.Envelope;
60
import org.gvsig.fmap.mapcontext.MapContext;
61
import org.gvsig.fmap.mapcontext.ViewPort;
62
import org.gvsig.fmap.mapcontext.exceptions.ReloadLayerException;
63
import org.gvsig.fmap.mapcontext.layers.FLayer;
64
import org.gvsig.fmap.mapcontext.layers.vectorial.FLyrVect;
65
import org.gvsig.fmap.mapcontext.rendering.legend.styling.ILabelable;
66
import org.gvsig.raster.fmap.layers.FLyrRaster;
67
import org.gvsig.tools.task.Cancellable;
68
import org.gvsig.view3d.lib.api.View3DLocator;
69
import org.gvsig.view3d.lib.api.View3DManager;
70
import org.gvsig.view3d.lib.api.properties.LayerProperties3D;
71
import org.gvsig.view3d.swing.api.MapControl3D;
72
import org.slf4j.Logger;
73
import org.slf4j.LoggerFactory;
74

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

    
84
    private static final Logger LOG = LoggerFactory
85
        .getLogger(GvSIGLayerDataRaster.class);
86

    
87
    private MapControl3D mapControl3D;
88
    private FLayer layer;
89
    
90
    private Extent canvasExtent;
91

    
92
    /**
93
     * Default constructor of <code>GvSIGLayerDataRaster</code>
94
     * 
95
     * @param mapControl3D
96
     *            context where {@link FLayer} is loaded.
97
     * @param theLayer
98
     *            source to get raster information
99
     * @param params
100
     *            parameters of <code>GvSIGLayerDataRaster</code>
101
     */
102
    public GvSIGLayerDataRaster(MapControl3D mapControl3D, FLayer theLayer,
103
        AVList params) {
104

    
105
        if (params == null || mapControl3D == null || theLayer == null) {
106
            throw new IllegalArgumentException();
107
        }
108

    
109
        this.layer = theLayer;
110
        this.mapControl3D = mapControl3D;
111
        this.setValues(params.copy());
112
    }
113

    
114
    public void dispose() {
115
    }
116

    
117
    public int getWidth() {
118
        return (Integer) this.getValue(AVKey.WIDTH);
119
    }
120

    
121
    public int getHeight() {
122
        return (Integer) this.getValue(AVKey.HEIGHT);
123
    }
124

    
125
    public Sector getSector() {
126

    
127
        return (Sector) this.getValue(AVKey.SECTOR);
128

    
129
    }
130

    
131
    public void drawOnTo(DataRaster canvas) {
132
        View3DManager manager = View3DLocator.getManager();
133
        LayerProperties3D properties = manager.getLayerProperties(layer);
134

    
135
        if (properties.getElevation() == true) {
136
            if (this.layer instanceof FLyrRaster) {
137
                this.drawRasterElevationOnTo(canvas);
138
            } else if (this.layer instanceof FLyrVect) {
139
                this.drawVectElevationOnTo(canvas);
140
            }
141
        } else {
142
            this.drawImageOnTo(canvas);
143
        }
144
    }
145

    
146
    private void drawRasterElevationOnTo(DataRaster canvas) {
147

    
148
        if (canvas == null) {
149
            throw new IllegalArgumentException();
150
        }
151

    
152
        if (!(this.layer instanceof FLyrRaster)
153
            || !canvas.getSector().intersects(getSector())) {
154
            return;
155
        }
156
        
157
        Extent canvasExtent = getExtent(canvas.getSector());
158
        
159
        FLyrRaster rasterLayer = (FLyrRaster) this.layer;
160
        RasterDataStore dataStore = rasterLayer.getDataStore();
161
        
162
        // Create query. Configure to get the zone request by canvas scaled to
163
        // tile size. 
164
        RasterQuery query = RasterLocator.getManager().createQuery();
165
        query.setSupersamplingOption(false);
166
        query.setDrawableBands(new int[] { 0 });
167
        query.setReadOnly(true);
168
        query.storeLastBuffer(true);
169
        
170
        Buffer adjustedBuffer = null;
171
        if(rasterLayer.getCoordTrans() != null){
172
            query.setAreaOfInterest(
173
                canvasExtent.convert(rasterLayer.getCoordTrans().getInverted()),
174
                canvas.getWidth(), canvas.getHeight());
175
        } else {
176
            query.setAreaOfInterest(canvasExtent, canvas.getWidth(),
177
                canvas.getHeight());
178
        }
179
        
180
        try {
181
            // For best performance, checks if canvas extent is the same than
182
            // last request. If it is the same, it will get last buffer
183
            // stored. Otherwise, it will do created query. 
184
            if (canvasExtent.equals(this.canvasExtent)
185
                && dataStore.getLastBuffer() != null) {
186
                adjustedBuffer = dataStore.getLastBuffer();
187
            } else {
188
                adjustedBuffer = dataStore.query(query);
189
            }
190
        } catch (ProcessInterruptedException e) {
191
            LOG.error("Process interrupted while {} was executing a query",
192
                dataStore.getName(), e);
193
            return;
194
        } catch (QueryException e) {
195
            LOG.error("Query exception, can apply {} to {}", new Object[] {
196
                query.toString(), dataStore.getName() }, e);
197
            return;
198
        }
199
        
200

    
201
        // For performance reasons, stores canvas extent to avoid calculate it
202
        // in each iteration
203
        setCanvasEnxent(canvas.getSector());
204
        
205
        if (this.layer.getProjection() == null){
206
            
207
            try {
208
                adjustedBuffer = adjustedBuffer.project(null, canvasExtent,
209
                    canvas.getWidth(), canvas.getHeight());
210
            } catch (WarpException e) {
211
                LOG.error(String
212
                    .format(
213
                        "Error projecting buffer. [source CRS: %1s target CRS: %2s canvas extent: %3s width: %4s height: %5s]",
214
                        rasterLayer.getCoordTrans().getPOrig().getAbrev(), rasterLayer.getCoordTrans()
215
                            .getPDest().getAbrev(), canvasExtent, canvas.getWidth(),
216
                        canvas.getHeight()));
217
                return;
218
            }
219
            
220
        } else if (rasterLayer.getCoordTrans() != null) {
221
            
222
            try {
223
                adjustedBuffer = adjustedBuffer.project(rasterLayer.getCoordTrans().getInverted(), canvasExtent,
224
                    canvas.getWidth(), canvas.getHeight());
225
            } catch (WarpException e) {
226
                LOG.error(String
227
                    .format(
228
                        "Error projecting buffer. [source CRS: %1s target CRS: %2s canvas extent: %3s width: %4s height: %5s]",
229
                        rasterLayer.getCoordTrans().getPOrig().getAbrev(), rasterLayer.getCoordTrans()
230
                            .getPDest().getAbrev(), canvasExtent, canvas.getWidth(),
231
                        canvas.getHeight()));
232
                return;
233
            }
234
        }
235
        
236
        String dataType = this.getStringValue(AVKey.DATA_TYPE);
237

    
238
        for (int y = 0; y < canvas.getHeight(); y++) {
239
            for (int x = 0; x < canvas.getWidth(); x++) {
240
                
241
                if (AVKey.INT8.equals(dataType)) {
242

    
243
                    byte byteValue = adjustedBuffer.getElemByte( y, x, 0);
244
                    setNumberToDataRaster((ByteBufferRaster) canvas, y, x, byteValue);
245

    
246
                } else if (AVKey.INT16.equals(dataType)) {
247

    
248
                    short shortValue =  adjustedBuffer.getElemShort(y, x, 0);
249
                    setNumberToDataRaster((ByteBufferRaster) canvas, y, x, shortValue);
250

    
251
                } else if (AVKey.INT32.equals(dataType)) {
252

    
253
                    int intValue = adjustedBuffer.getElemInt(y, x, 0);
254
                    setNumberToDataRaster((ByteBufferRaster) canvas, y, x, intValue);
255

    
256
                } else if (AVKey.FLOAT32.equals(dataType)) {
257

    
258
                    float floatValue = adjustedBuffer.getElemFloat(y, x, 0);
259
                    setNumberToDataRaster((ByteBufferRaster) canvas, y, x, floatValue);
260

    
261
                } else if (AVKey.FLOAT64.equals(dataType)) {
262

    
263
                    double doubleValue = adjustedBuffer.getElemDouble(y, x, 0);
264
                    setNumberToDataRaster((ByteBufferRaster) canvas, y, x, doubleValue);
265
                }
266
            }
267
        }
268
    }
269

    
270
    private void setCanvasEnxent(Sector canvasSector) {
271
        this.canvasExtent = getExtent(canvasSector);
272
    }
273
    
274
    private Extent getExtent(Sector sector){
275
        Rectangle2D rectangleDegrees = sector.toRectangleDegrees();
276
        RasterManager rasterManager = RasterLocator.getManager();
277
        DataStructFactory dataStructFactory =
278
            rasterManager.getDataStructFactory();
279
        return dataStructFactory.createExtent(rectangleDegrees);
280
    }
281

    
282
    private void setNumberToDataRaster(ByteBufferRaster byteBuferRaster,
283
        int line, int col, Number value) {
284
        byteBuferRaster.setDoubleAtPosition(line, col, value.doubleValue());
285
    }
286
    
287
    private void drawVectElevationOnTo(DataRaster canvas) {
288
        // TODO Auto-generated method stub
289

    
290
    }
291

    
292
    private void drawImageOnTo(DataRaster canvas) {
293
        if (canvas == null) {
294
            throw new IllegalArgumentException();
295
        }
296

    
297
        if (!canvas.getSector().intersects(getSector())) {
298
            return;
299
        }
300
        
301
        if (!layer.isAvailable()){
302
            try {
303
                layer.reload();
304
                if(!layer.isAvailable()){
305
                    throw new ReloadLayerException(layer.getName(), null);
306
                }
307
            } catch (ReloadLayerException e) {
308
                LOG.error(
309
                    String.format("%1s layer is no available... canceling drawing process",
310
                        layer.getName()), e);
311
                return;
312
            }
313
        }
314
        
315
        Sector overlap = this.getSector().intersection(canvas.getSector());
316
        
317
        ViewPort viewPort =
318
            new ViewPort(mapControl3D.getMapContext().getProjection());
319

    
320
        // Set adjustable to false to avoid problems with adjusted envelope
321
        viewPort.setAdjustable(false);
322

    
323
        GeometryManager geoManager = GeometryLocator.getGeometryManager();
324

    
325
        Envelope envelope = null;
326
        double[] degrees = overlap.asDegreesArray();
327

    
328
        try {
329

    
330
            Point2D p1 = new Point2D.Double(degrees[2], degrees[0]);
331
            Point2D p2 = new Point2D.Double(degrees[3], degrees[1]);
332

    
333
            envelope =
334
                geoManager.createEnvelope(Math.min(p1.getX(), p2.getX()),
335
                    Math.min(p1.getY(), p2.getY()),
336
                    Math.max(p1.getX(), p2.getX()),
337
                    Math.max(p1.getY(), p2.getY()), SUBTYPES.GEOM2D);
338

    
339
            /**
340
             * Check if request tile intersect with layer envelope to avoid
341
             * the creation of useless tiles.
342
             */
343
            if (!envelope.intersects(layer.getFullEnvelope())) {
344
                return;
345
            }
346

    
347
            viewPort.setEnvelope(envelope);
348

    
349
        } catch (CreateEnvelopeException e) {
350
            LOG.error(
351
                "Can't create envelope from sector tile:  minLat {} maxLat {} minLon {} maxLon {}",
352
                new Object[] { degrees[0], degrees[1], degrees[2], degrees[3] });
353
            return;
354
        } catch (ReadException e) {
355
            LOG.warn("Can't get full envelope of {}", layer.getName());
356
        }
357

    
358
        int canvasWidth = canvas.getWidth();
359
        int canvasHeight = canvas.getHeight();
360

    
361
        java.awt.Rectangle clipRect = this.computeClipRect(overlap, this);
362
        if (null == clipRect || clipRect.width == 0 || clipRect.height == 0) {
363
            return;
364
        }
365

    
366
        // Apply the transform that correctly maps the image onto the canvas.
367
        java.awt.geom.AffineTransform affineTransform =
368
            this.computeSourceToDestTransform(clipRect.width, clipRect.height,
369
                overlap, canvasWidth, canvasHeight, canvas.getSector());
370

    
371
        // Trick to apply transform to size value
372
        Point2D srcSizePoint =
373
            new Point2D.Double(clipRect.width, clipRect.height);
374
        Point2D dstSizePoint = new Point2D.Double();
375

    
376
        affineTransform.transform(srcSizePoint, dstSizePoint);
377

    
378
        int clipWidth =
379
            (int) Math.ceil((dstSizePoint.getX() >= canvasWidth) ? canvasWidth
380
                : dstSizePoint.getX());
381
        int clipHeight =
382
            (int) Math.ceil((dstSizePoint.getY() >= canvasHeight)
383
                ? canvasHeight : dstSizePoint.getY());
384

    
385
        if (clipWidth <= 0 || clipHeight <= 0) {
386
            return;
387
        }
388

    
389
        BufferedImage image =
390
            new BufferedImage(clipWidth, clipHeight,
391
                BufferedImage.TYPE_INT_ARGB);
392

    
393
        viewPort.setImageSize(new Dimension(clipWidth, clipHeight));
394
        viewPort.refreshExtent();
395

    
396
        try {
397
            layer.draw(image, (Graphics2D) image.getGraphics(), viewPort,
398
                new Cancellable() {
399
                
400
                    boolean canceled = false;
401
                    
402
                    @Override
403
                    public void setCanceled(boolean canceled) {
404
                        this.canceled = canceled;
405
                        
406
                    }
407
                    
408
                    @Override
409
                    public boolean isCanceled() {
410
                        return canceled;
411
                    }
412
                }, getScale(viewPort));
413

    
414
            if (layer instanceof FLyrVect && layer instanceof ILabelable) {
415

    
416
                ILabelable labelable = (ILabelable) layer;
417

    
418
                if (labelable.isLabeled()
419
                    && labelable.getLabelingStrategy() != null
420
                    && labelable.getLabelingStrategy().shouldDrawLabels(
421
                        getScale(viewPort))) {
422

    
423
                    labelable.drawLabels(image,
424
                        (Graphics2D) image.getGraphics(), viewPort,
425
                        mapControl3D.getCancellable(), getScale(viewPort),
426
                        mapControl3D.getMapContext().getViewPort().getDPI());
427
                }
428
            }
429

    
430
        } catch (ReadException e) {
431
            LOG.warn("Can't draw required zone of layer {}, can't read legend",
432
                layer.getName());
433
            return;
434
        } 
435
        
436
        BufferedImageRaster bufferedImageRaster =
437
            new BufferedImageRaster(overlap, image);
438
        bufferedImageRaster.drawOnTo(canvas);
439

    
440
    }
441

    
442
    private java.awt.geom.AffineTransform computeSourceToDestTransform(
443
        int sourceWidth, int sourceHeight, Sector sourceSector, int destWidth,
444
        int destHeight, Sector destSector) {
445
        // Compute the the transform from source to destination coordinates. In
446
        // this computation a pixel is assumed
447
        // to cover a finite area.
448

    
449
        double ty =
450
            destHeight
451
                * -(sourceSector.getMaxLatitude().degrees - destSector
452
                    .getMaxLatitude().degrees)
453
                / destSector.getDeltaLatDegrees();
454
        double tx =
455
            destWidth
456
                * (sourceSector.getMinLongitude().degrees - destSector
457
                    .getMinLongitude().degrees)
458
                / destSector.getDeltaLonDegrees();
459

    
460
        double sy =
461
            ((double) destHeight / (double) sourceHeight)
462
                * (sourceSector.getDeltaLatDegrees() / destSector
463
                    .getDeltaLatDegrees());
464
        double sx =
465
            ((double) destWidth / (double) sourceWidth)
466
                * (sourceSector.getDeltaLonDegrees() / destSector
467
                    .getDeltaLonDegrees());
468

    
469
        java.awt.geom.AffineTransform transform =
470
            new java.awt.geom.AffineTransform();
471
        transform.translate(tx, ty);
472
        transform.scale(sx, sy);
473
        return transform;
474
    }
475

    
476
    private double getScale(ViewPort viewPort) {
477

    
478
        double dpi = viewPort.getDPI();
479
        IProjection proj = viewPort.getProjection();
480

    
481
        if (viewPort.getImageSize() == null) {
482
            return -1;
483
        }
484

    
485
        if (viewPort.getAdjustedEnvelope() == null) {
486
            return 0;
487
        }
488
        double[] trans2Meter = MapContext.getDistanceTrans2Meter();
489
        int mUnits = viewPort.getMapUnits();
490

    
491
        if (proj == null) {
492
            double w = ((viewPort.getImageSize().width / dpi) * 0.0254);
493
            return (long) (viewPort.getAdjustedEnvelope().getLength(0) / w * trans2Meter[mUnits]);
494
        }
495

    
496
        return Math.round(proj.getScale(viewPort.getAdjustedEnvelope()
497
            .getMinimum(0) * trans2Meter[mUnits], viewPort
498
            .getAdjustedEnvelope().getMaximum(0) * trans2Meter[mUnits],
499
            viewPort.getImageSize().width, dpi));
500
    }
501

    
502
    private Rectangle computeClipRect(Sector clipSector,
503
        DataRaster clippedRaster) {
504

    
505
        AffineTransform geographicToRaster =
506
            this.computeGeographicToRasterTransform(clippedRaster.getWidth(),
507
                clippedRaster.getHeight(), clippedRaster.getSector());
508

    
509
        java.awt.geom.Point2D geoPoint = new java.awt.geom.Point2D.Double();
510
        java.awt.geom.Point2D ul = new java.awt.geom.Point2D.Double();
511
        java.awt.geom.Point2D lr = new java.awt.geom.Point2D.Double();
512

    
513
        geoPoint.setLocation(clipSector.getMinLongitude().degrees,
514
            clipSector.getMaxLatitude().degrees);
515
        geographicToRaster.transform(geoPoint, ul);
516

    
517
        geoPoint.setLocation(clipSector.getMaxLongitude().degrees,
518
            clipSector.getMinLatitude().degrees);
519
        geographicToRaster.transform(geoPoint, lr);
520

    
521
        int x = (int) Math.floor(ul.getX());
522
        int y = (int) Math.floor(ul.getY());
523
        int width = (int) Math.ceil(lr.getX() - ul.getX());
524
        int height = (int) Math.ceil(lr.getY() - ul.getY());
525

    
526
        return new Rectangle(x, y, width, height);
527
    }
528

    
529
    private java.awt.geom.AffineTransform computeGeographicToRasterTransform(
530
        int width, int height, Sector sector) {
531
        // Compute the the transform from geographic to raster coordinates. In
532
        // this computation a pixel is assumed
533
        // to cover a finite area.
534

    
535
        double ty = -sector.getMaxLatitude().degrees;
536
        double tx = -sector.getMinLongitude().degrees;
537

    
538
        double sy = -(height / sector.getDeltaLatDegrees());
539
        double sx = (width / sector.getDeltaLonDegrees());
540

    
541
        java.awt.geom.AffineTransform transform =
542
            new java.awt.geom.AffineTransform();
543
        transform.scale(sx, sy);
544
        transform.translate(tx, ty);
545
        return transform;
546
    }
547

    
548
    public DataRaster getSubRaster(AVList params) {
549
        int width = (Integer) params.getValue(AVKey.WIDTH);
550
        int height = (Integer) params.getValue(AVKey.HEIGHT);
551
        Sector sector = (Sector) params.getValue(AVKey.SECTOR);
552

    
553
        return this.getSubRaster(width, height, sector, params);
554
    }
555

    
556
    public DataRaster getSubRaster(int width, int height, Sector sector,
557
        AVList params) {
558

    
559
        params.setValue(AVKey.WIDTH, width);
560
        params.setValue(AVKey.HEIGHT, height);
561
        params.setValue(AVKey.SECTOR, sector);
562

    
563
        GvSIGLayerDataRaster subRaster =
564
            new GvSIGLayerDataRaster(mapControl3D, layer, params);
565
        return subRaster;
566
    }
567
}