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

History | View | Annotate | Download (12.3 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.DataRaster;
32
import gov.nasa.worldwind.geom.Sector;
33

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

    
41
import org.cresques.cts.ICoordTrans;
42
import org.cresques.cts.IProjection;
43
import org.slf4j.Logger;
44
import org.slf4j.LoggerFactory;
45
import org.gvsig.fmap.crs.CRSFactory;
46
import org.gvsig.fmap.dal.exception.ReadException;
47
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
48
import org.gvsig.fmap.geom.GeometryLocator;
49
import org.gvsig.fmap.geom.GeometryManager;
50
import org.gvsig.fmap.geom.exception.CreateEnvelopeException;
51
import org.gvsig.fmap.geom.primitive.Envelope;
52
import org.gvsig.fmap.mapcontext.MapContext;
53
import org.gvsig.fmap.mapcontext.ViewPort;
54
import org.gvsig.fmap.mapcontext.layers.FLayer;
55
import org.gvsig.fmap.mapcontext.layers.vectorial.FLyrVect;
56
import org.gvsig.fmap.mapcontext.rendering.legend.styling.ILabelable;
57
import org.gvsig.tools.task.Cancellable;
58

    
59
/**
60
 * @author <a href="mailto:lmarques@disid.com">Lluis Marques</a>
61
 *
62
 */
63
@SuppressWarnings("deprecation")
64
public class GvSIGLayerDataRaster extends WWObjectImpl implements DataRaster {
65

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

    
69
    private MapContext mapContext;
70
    private FLayer layer;
71

    
72
    /**
73
     * 
74
     */
75
    public GvSIGLayerDataRaster(MapContext mapContext, FLayer theLayer,
76
        AVList params) {
77

    
78
        if (params == null || mapContext == null || theLayer == null) {
79
            throw new IllegalArgumentException();
80
        }
81

    
82
        this.layer = theLayer;
83
        this.mapContext = mapContext;
84
        this.setValues(params.copy());
85
    }
86

    
87
    public void dispose() {
88
        //TODO
89
    }
90

    
91
    public int getWidth() {
92
        return (Integer) this.getValue(AVKey.WIDTH);
93
    }
94

    
95
    public int getHeight() {
96
        return (Integer) this.getValue(AVKey.HEIGHT);
97
    }
98

    
99
    public Sector getSector() {
100

    
101
        return (Sector) this.getValue(AVKey.SECTOR);
102

    
103
    }
104

    
105
    public void drawOnTo(DataRaster canvas) {
106

    
107
        if (canvas == null) {
108
            throw new IllegalArgumentException();
109
        }
110

    
111
        if (!canvas.getSector().intersects(getSector())) {
112
            return;
113
        }
114

    
115
        Sector overlap = this.getSector().intersection(canvas.getSector());
116

    
117
        ViewPort viewPort = new ViewPort(mapContext.getProjection());
118

    
119
        // Set adjustable to false to avoid problems with adjusted envelope
120
        viewPort.setAdjustable(false);
121

    
122
        GeometryManager geoManager = GeometryLocator.getGeometryManager();
123

    
124
        Envelope envelope = null;
125
        double[] degrees = overlap.asDegreesArray();
126

    
127
        try {
128

    
129
            IProjection projection = mapContext.getProjection();
130

    
131
            ICoordTrans ct = CRSFactory.getCRS("EPSG:4326").getCT(projection);
132
            Point2D p1 = convert(ct, new Point2D.Double(degrees[2], degrees[0]));
133
            Point2D p2 = convert(ct, new Point2D.Double(degrees[3], degrees[1]));
134

    
135
            envelope =
136
                geoManager.createEnvelope(Math.min(p1.getX(), p2.getX()),
137
                    Math.min(p1.getY(), p2.getY()),
138
                    Math.max(p1.getX(), p2.getX()),
139
                    Math.max(p1.getY(), p2.getY()), SUBTYPES.GEOM2D);
140
            
141
            /**
142
             *  Check if request tile intersect with layer envelope to avoid
143
             *  the creation of useless tiles. 
144
             */
145
            if (!envelope.intersects(layer.getFullEnvelope())) {
146
                return;
147
            }
148

    
149
            viewPort.setEnvelope(envelope);
150

    
151
        } catch (CreateEnvelopeException e) {
152
            LOG.error(
153
                "Can't create envelope from sector tile:  minLat {} maxLat {} minLon {} maxLon {}",
154
                new Object[] { degrees[0], degrees[1], degrees[2], degrees[3] });
155
            return;
156
        } catch (ReadException e) {
157
            LOG.warn("Can't get full envelope of {}", layer.getInfoString());
158
        }
159

    
160
        int canvasWidth = canvas.getWidth();
161
        int canvasHeight = canvas.getHeight();
162

    
163
        java.awt.Rectangle clipRect = this.computeClipRect(overlap, this);
164
        if (null == clipRect || clipRect.width == 0 || clipRect.height == 0) {
165
            return;
166
        }
167

    
168
        // Apply the transform that correctly maps the image onto the canvas.
169
        java.awt.geom.AffineTransform affineTransform =
170
            this.computeSourceToDestTransform(clipRect.width, clipRect.height,
171
                overlap, canvasWidth, canvasHeight, canvas.getSector());
172

    
173
        // Trick to apply transform to size value
174
        Point2D srcSizePoint =
175
            new Point2D.Double(clipRect.width, clipRect.height);
176
        Point2D dstSizePoint = new Point2D.Double();
177

    
178
        affineTransform.transform(srcSizePoint, dstSizePoint);
179

    
180
        int clipWidth =
181
            (int) Math.ceil((dstSizePoint.getX() >= canvasWidth) ? canvasWidth
182
                : dstSizePoint.getX());
183
        int clipHeight =
184
            (int) Math.ceil((dstSizePoint.getY() >= canvasHeight)
185
                ? canvasHeight : dstSizePoint.getY());
186

    
187
        if (clipWidth <= 0 || clipHeight <= 0) {
188
            return;
189
        }
190

    
191
        BufferedImage image =
192
            new BufferedImage(clipWidth, clipHeight,
193
                BufferedImage.TYPE_INT_ARGB);
194

    
195
        viewPort.setImageSize(new Dimension(clipWidth, clipHeight));
196
        viewPort.refreshExtent();
197

    
198
        try {
199
            
200
            layer.draw(image, (Graphics2D) image.getGraphics(), viewPort,
201
                getCancel(), getScale(viewPort));
202
            
203
            if (layer instanceof FLyrVect && layer instanceof ILabelable) {
204
                
205
                ILabelable labelable = (ILabelable) layer;
206
                
207
                if (labelable.isLabeled() 
208
                    && labelable.getLabelingStrategy() != null
209
                    && labelable.getLabelingStrategy().shouldDrawLabels(
210
                        getScale(viewPort))) {
211
    
212
                    labelable.drawLabels(image, (Graphics2D) image
213
                        .getGraphics(), viewPort, getCancel(),
214
                        getScale(viewPort), mapContext.getViewPort().getDPI());
215
                }
216
            }
217

    
218
        } catch (ReadException e) {
219
            LOG.warn(
220
                "Can't draw required zone of layer {}, can't read legend",
221
                layer.getInfoString());
222
            return;
223
        }
224
        BufferedImageRaster bufferedImageRaster =
225
            new BufferedImageRaster(overlap, image);
226
        bufferedImageRaster.drawOnTo(canvas);
227

    
228
    }
229
    
230
    private Point2D convert(ICoordTrans ct, Point2D srcPoint){
231
        if(ct == null){
232
            return srcPoint;
233
        }
234
        return ct.convert(srcPoint, null);
235
    }
236

    
237
    private java.awt.geom.AffineTransform computeSourceToDestTransform(
238
        int sourceWidth, int sourceHeight, Sector sourceSector, int destWidth,
239
        int destHeight, Sector destSector) {
240
        // Compute the the transform from source to destination coordinates. In
241
        // this computation a pixel is assumed
242
        // to cover a finite area.
243

    
244
        double ty =
245
            destHeight
246
                * -(sourceSector.getMaxLatitude().degrees - destSector
247
                    .getMaxLatitude().degrees)
248
                / destSector.getDeltaLatDegrees();
249
        double tx =
250
            destWidth
251
                * (sourceSector.getMinLongitude().degrees - destSector
252
                    .getMinLongitude().degrees)
253
                / destSector.getDeltaLonDegrees();
254

    
255
        double sy =
256
            ((double) destHeight / (double) sourceHeight)
257
                * (sourceSector.getDeltaLatDegrees() / destSector
258
                    .getDeltaLatDegrees());
259
        double sx =
260
            ((double) destWidth / (double) sourceWidth)
261
                * (sourceSector.getDeltaLonDegrees() / destSector
262
                    .getDeltaLonDegrees());
263

    
264
        java.awt.geom.AffineTransform transform =
265
            new java.awt.geom.AffineTransform();
266
        transform.translate(tx, ty);
267
        transform.scale(sx, sy);
268
        return transform;
269
    }
270

    
271
    private double getScale(ViewPort viewPort) {
272

    
273
        MapContext mapContextCloned = mapContext.cloneFMap();
274
        mapContextCloned.setViewPort(viewPort);
275
        double scale = mapContextCloned.getScaleView();
276
        mapContextCloned.dispose();
277

    
278
        return scale;
279
    }
280

    
281
    private Rectangle computeClipRect(Sector clipSector,
282
        DataRaster clippedRaster) {
283

    
284
        AffineTransform geographicToRaster =
285
            this.computeGeographicToRasterTransform(clippedRaster.getWidth(),
286
                clippedRaster.getHeight(), clippedRaster.getSector());
287

    
288
        java.awt.geom.Point2D geoPoint = new java.awt.geom.Point2D.Double();
289
        java.awt.geom.Point2D ul = new java.awt.geom.Point2D.Double();
290
        java.awt.geom.Point2D lr = new java.awt.geom.Point2D.Double();
291

    
292
        geoPoint.setLocation(clipSector.getMinLongitude().degrees,
293
            clipSector.getMaxLatitude().degrees);
294
        geographicToRaster.transform(geoPoint, ul);
295

    
296
        geoPoint.setLocation(clipSector.getMaxLongitude().degrees,
297
            clipSector.getMinLatitude().degrees);
298
        geographicToRaster.transform(geoPoint, lr);
299

    
300
        int x = (int) Math.floor(ul.getX());
301
        int y = (int) Math.floor(ul.getY());
302
        int width = (int) Math.ceil(lr.getX() - ul.getX());
303
        int height = (int) Math.ceil(lr.getY() - ul.getY());
304

    
305
        return new Rectangle(x, y, width, height);
306
    }
307

    
308
    private java.awt.geom.AffineTransform computeGeographicToRasterTransform(
309
        int width, int height, Sector sector) {
310
        // Compute the the transform from geographic to raster coordinates. In
311
        // this computation a pixel is assumed
312
        // to cover a finite area.
313

    
314
        double ty = -sector.getMaxLatitude().degrees;
315
        double tx = -sector.getMinLongitude().degrees;
316

    
317
        double sy = -(height / sector.getDeltaLatDegrees());
318
        double sx = (width / sector.getDeltaLonDegrees());
319

    
320
        java.awt.geom.AffineTransform transform =
321
            new java.awt.geom.AffineTransform();
322
        transform.scale(sx, sy);
323
        transform.translate(tx, ty);
324
        return transform;
325
    }
326

    
327
    public DataRaster getSubRaster(AVList params) {
328
        int width = (Integer) params.getValue(AVKey.WIDTH);
329
        int height = (Integer) params.getValue(AVKey.HEIGHT);
330
        Sector sector = (Sector) params.getValue(AVKey.SECTOR);
331

    
332
        return this.getSubRaster(width, height, sector, params);
333
    }
334

    
335
    public DataRaster getSubRaster(int width, int height, Sector sector,
336
        AVList params) {
337

    
338
        params.setValue(AVKey.WIDTH, width);
339
        params.setValue(AVKey.HEIGHT, height);
340
        params.setValue(AVKey.SECTOR, sector);
341

    
342
        GvSIGLayerDataRaster subRaster =
343
            new GvSIGLayerDataRaster(mapContext, layer, params);
344
        return subRaster;
345
    }
346
    
347
    private Cancellable getCancel(){
348
        Cancellable cancel = new Cancellable() {
349

    
350
            private boolean canceled = false;
351

    
352
            public void setCanceled(boolean flag) {
353
                canceled = flag;
354
            }
355

    
356
            public boolean isCanceled() {
357
                return canceled;
358
            }
359
        };
360
        
361
        return cancel;
362
    }
363
}