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 @ 457
History | View | Annotate | Download (11.5 KB)
1 | 446 | llmarques | /**
|
---|---|---|---|
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 | 457 | llmarques | import java.awt.Dimension; |
35 | 446 | llmarques | 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 | 457 | llmarques | import org.slf4j.Logger; |
44 | import org.slf4j.LoggerFactory; |
||
45 | 446 | llmarques | |
46 | import org.gvsig.fmap.crs.CRSFactory; |
||
47 | import org.gvsig.fmap.dal.exception.ReadException; |
||
48 | import org.gvsig.fmap.geom.Geometry.SUBTYPES; |
||
49 | import org.gvsig.fmap.geom.GeometryLocator; |
||
50 | import org.gvsig.fmap.geom.GeometryManager; |
||
51 | import org.gvsig.fmap.geom.exception.CreateEnvelopeException; |
||
52 | import org.gvsig.fmap.geom.primitive.Envelope; |
||
53 | import org.gvsig.fmap.mapcontext.MapContext; |
||
54 | import org.gvsig.fmap.mapcontext.ViewPort; |
||
55 | import org.gvsig.fmap.mapcontext.layers.FLayer; |
||
56 | import org.gvsig.tools.task.Cancellable; |
||
57 | |||
58 | /**
|
||
59 | * @author <a href="mailto:lmarques@disid.com">Lluis Marques</a>
|
||
60 | *
|
||
61 | */
|
||
62 | @SuppressWarnings("deprecation") |
||
63 | public class GvSIGLayerDataRaster extends WWObjectImpl implements DataRaster { |
||
64 | |||
65 | 457 | llmarques | private static final Logger LOG = LoggerFactory |
66 | .getLogger(GvSIGLayerDataRaster.class); |
||
67 | |||
68 | 446 | llmarques | private MapContext mapContext;
|
69 | private FLayer layer;
|
||
70 | |||
71 | /**
|
||
72 | *
|
||
73 | */
|
||
74 | public GvSIGLayerDataRaster(MapContext mapContext, FLayer theLayer,
|
||
75 | AVList params) { |
||
76 | |||
77 | if (params == null || mapContext == null || theLayer == null) { |
||
78 | throw new IllegalArgumentException(); |
||
79 | } |
||
80 | |||
81 | this.layer = theLayer;
|
||
82 | this.mapContext = mapContext;
|
||
83 | this.setValues(params.copy());
|
||
84 | } |
||
85 | |||
86 | public void dispose() { |
||
87 | 457 | llmarques | //TODO
|
88 | 446 | llmarques | } |
89 | |||
90 | public int getWidth() { |
||
91 | return (Integer) this.getValue(AVKey.WIDTH); |
||
92 | } |
||
93 | |||
94 | public int getHeight() { |
||
95 | return (Integer) this.getValue(AVKey.HEIGHT); |
||
96 | } |
||
97 | |||
98 | public Sector getSector() {
|
||
99 | |||
100 | return (Sector) this.getValue(AVKey.SECTOR); |
||
101 | |||
102 | } |
||
103 | |||
104 | public void drawOnTo(DataRaster canvas) { |
||
105 | |||
106 | if (canvas == null) { |
||
107 | throw new IllegalArgumentException(); |
||
108 | } |
||
109 | |||
110 | 457 | llmarques | if (!canvas.getSector().intersects(getSector())) {
|
111 | 446 | llmarques | return;
|
112 | } |
||
113 | |||
114 | 457 | llmarques | Sector overlap = this.getSector().intersection(canvas.getSector());
|
115 | |||
116 | 446 | llmarques | ViewPort viewPort = new ViewPort(mapContext.getProjection());
|
117 | 457 | llmarques | |
118 | // Set adjustable to false to avoid problems with adjusted envelope
|
||
119 | viewPort.setAdjustable(false);
|
||
120 | |||
121 | 446 | llmarques | GeometryManager geoManager = GeometryLocator.getGeometryManager(); |
122 | |||
123 | Envelope envelope = null;
|
||
124 | 457 | llmarques | double[] degrees = overlap.asDegreesArray(); |
125 | |||
126 | 446 | llmarques | try {
|
127 | |||
128 | IProjection projection = layer.getProjection(); |
||
129 | |||
130 | if (projection == null) { |
||
131 | projection = mapContext.getProjection(); |
||
132 | } |
||
133 | |||
134 | ICoordTrans ct = CRSFactory.getCRS("EPSG:4326").getCT(projection);
|
||
135 | 457 | llmarques | Point2D p1 = convert(ct, new Point2D.Double(degrees[2], degrees[0])); |
136 | Point2D p2 = convert(ct, new Point2D.Double(degrees[3], degrees[1])); |
||
137 | 446 | llmarques | |
138 | envelope = |
||
139 | geoManager.createEnvelope(Math.min(p1.getX(), p2.getX()),
|
||
140 | Math.min(p1.getY(), p2.getY()),
|
||
141 | Math.max(p1.getX(), p2.getX()),
|
||
142 | Math.max(p1.getY(), p2.getY()), SUBTYPES.GEOM2D);
|
||
143 | 457 | llmarques | |
144 | /**
|
||
145 | * Check if request tile intersect with layer envelope to avoid
|
||
146 | * the creation of useless tiles.
|
||
147 | */
|
||
148 | if (!envelope.intersects(layer.getFullEnvelope())) {
|
||
149 | return;
|
||
150 | } |
||
151 | 446 | llmarques | |
152 | 457 | llmarques | viewPort.setEnvelope(envelope); |
153 | |||
154 | 446 | llmarques | } catch (CreateEnvelopeException e) {
|
155 | 457 | llmarques | LOG.error( |
156 | "Can't create envelope from sector tile: minLat {} maxLat {} minLon {} maxLon {}",
|
||
157 | new Object[] { degrees[0], degrees[1], degrees[2], degrees[3] }); |
||
158 | return;
|
||
159 | } catch (ReadException e) {
|
||
160 | LOG.warn("Can't get full envelope of {}", layer.getInfoString());
|
||
161 | 446 | llmarques | } |
162 | |||
163 | 457 | llmarques | int canvasWidth = canvas.getWidth();
|
164 | int canvasHeight = canvas.getHeight();
|
||
165 | 446 | llmarques | |
166 | 457 | llmarques | java.awt.Rectangle clipRect = this.computeClipRect(overlap, this); |
167 | if (null == clipRect || clipRect.width == 0 || clipRect.height == 0) { |
||
168 | return;
|
||
169 | } |
||
170 | |||
171 | // Apply the transform that correctly maps the image onto the canvas.
|
||
172 | java.awt.geom.AffineTransform affineTransform = |
||
173 | this.computeSourceToDestTransform(clipRect.width, clipRect.height,
|
||
174 | overlap, canvasWidth, canvasHeight, canvas.getSector()); |
||
175 | |||
176 | // Trick to apply transform to size value
|
||
177 | Point2D srcSizePoint =
|
||
178 | new Point2D.Double(clipRect.width, clipRect.height); |
||
179 | Point2D dstSizePoint = new Point2D.Double(); |
||
180 | |||
181 | affineTransform.transform(srcSizePoint, dstSizePoint); |
||
182 | |||
183 | int clipWidth =
|
||
184 | (int) Math.ceil((dstSizePoint.getX() >= canvasWidth) ? canvasWidth |
||
185 | : dstSizePoint.getX()); |
||
186 | int clipHeight =
|
||
187 | (int) Math.ceil((dstSizePoint.getY() >= canvasHeight) |
||
188 | ? canvasHeight : dstSizePoint.getY()); |
||
189 | |||
190 | if (clipWidth <= 0 || clipHeight <= 0) { |
||
191 | return;
|
||
192 | } |
||
193 | |||
194 | 446 | llmarques | BufferedImage image =
|
195 | 457 | llmarques | new BufferedImage(clipWidth, clipHeight, |
196 | BufferedImage.TYPE_INT_ARGB);
|
||
197 | 446 | llmarques | |
198 | 457 | llmarques | viewPort.setImageSize(new Dimension(clipWidth, clipHeight)); |
199 | viewPort.refreshExtent(); |
||
200 | |||
201 | 446 | llmarques | try {
|
202 | layer.draw(image, (Graphics2D) image.getGraphics(), viewPort,
|
||
203 | new Cancellable() {
|
||
204 | |||
205 | 457 | llmarques | private boolean canceled = false; |
206 | |||
207 | public void setCanceled(boolean flag) { |
||
208 | canceled = flag; |
||
209 | 446 | llmarques | } |
210 | |||
211 | public boolean isCanceled() { |
||
212 | 457 | llmarques | return canceled;
|
213 | 446 | llmarques | } |
214 | }, getScale(viewPort)); |
||
215 | 457 | llmarques | |
216 | 446 | llmarques | } catch (ReadException e) {
|
217 | 457 | llmarques | LOG.warn( |
218 | "Can't draw required zone of layer {}, can't read legend",
|
||
219 | layer.getInfoString()); |
||
220 | return;
|
||
221 | 446 | llmarques | } |
222 | |||
223 | BufferedImageRaster bufferedImageRaster = |
||
224 | new BufferedImageRaster(overlap, image);
|
||
225 | bufferedImageRaster.drawOnTo(canvas); |
||
226 | 457 | llmarques | |
227 | 446 | llmarques | } |
228 | 457 | llmarques | |
229 | private Point2D convert(ICoordTrans ct, Point2D srcPoint){ |
||
230 | if(ct == null){ |
||
231 | return srcPoint;
|
||
232 | } |
||
233 | return ct.convert(srcPoint, null); |
||
234 | } |
||
235 | 446 | llmarques | |
236 | 457 | llmarques | private java.awt.geom.AffineTransform computeSourceToDestTransform(
|
237 | int sourceWidth, int sourceHeight, Sector sourceSector, int destWidth, |
||
238 | int destHeight, Sector destSector) {
|
||
239 | // Compute the the transform from source to destination coordinates. In
|
||
240 | // this computation a pixel is assumed
|
||
241 | // to cover a finite area.
|
||
242 | |||
243 | double ty =
|
||
244 | destHeight |
||
245 | * -(sourceSector.getMaxLatitude().degrees - destSector |
||
246 | .getMaxLatitude().degrees) |
||
247 | / destSector.getDeltaLatDegrees(); |
||
248 | double tx =
|
||
249 | destWidth |
||
250 | * (sourceSector.getMinLongitude().degrees - destSector |
||
251 | .getMinLongitude().degrees) |
||
252 | / destSector.getDeltaLonDegrees(); |
||
253 | |||
254 | double sy =
|
||
255 | ((double) destHeight / (double) sourceHeight) |
||
256 | * (sourceSector.getDeltaLatDegrees() / destSector |
||
257 | .getDeltaLatDegrees()); |
||
258 | double sx =
|
||
259 | ((double) destWidth / (double) sourceWidth) |
||
260 | * (sourceSector.getDeltaLonDegrees() / destSector |
||
261 | .getDeltaLonDegrees()); |
||
262 | |||
263 | java.awt.geom.AffineTransform transform = |
||
264 | new java.awt.geom.AffineTransform();
|
||
265 | transform.translate(tx, ty); |
||
266 | transform.scale(sx, sy); |
||
267 | return transform;
|
||
268 | } |
||
269 | |||
270 | 446 | llmarques | private double getScale(ViewPort viewPort) { |
271 | |||
272 | MapContext mapContextCloned = mapContext.cloneFMap(); |
||
273 | mapContextCloned.setViewPort(viewPort); |
||
274 | double scale = mapContextCloned.getScaleView();
|
||
275 | mapContextCloned.dispose(); |
||
276 | |||
277 | return scale;
|
||
278 | } |
||
279 | |||
280 | private Rectangle computeClipRect(Sector clipSector, |
||
281 | DataRaster clippedRaster) { |
||
282 | |||
283 | AffineTransform geographicToRaster =
|
||
284 | this.computeGeographicToRasterTransform(clippedRaster.getWidth(),
|
||
285 | clippedRaster.getHeight(), clippedRaster.getSector()); |
||
286 | |||
287 | java.awt.geom.Point2D geoPoint = new java.awt.geom.Point2D.Double();
|
||
288 | java.awt.geom.Point2D ul = new java.awt.geom.Point2D.Double();
|
||
289 | java.awt.geom.Point2D lr = new java.awt.geom.Point2D.Double();
|
||
290 | |||
291 | geoPoint.setLocation(clipSector.getMinLongitude().degrees, |
||
292 | clipSector.getMaxLatitude().degrees); |
||
293 | geographicToRaster.transform(geoPoint, ul); |
||
294 | |||
295 | geoPoint.setLocation(clipSector.getMaxLongitude().degrees, |
||
296 | clipSector.getMinLatitude().degrees); |
||
297 | geographicToRaster.transform(geoPoint, lr); |
||
298 | |||
299 | int x = (int) Math.floor(ul.getX()); |
||
300 | int y = (int) Math.floor(ul.getY()); |
||
301 | int width = (int) Math.ceil(lr.getX() - ul.getX()); |
||
302 | int height = (int) Math.ceil(lr.getY() - ul.getY()); |
||
303 | |||
304 | return new Rectangle(x, y, width, height); |
||
305 | } |
||
306 | |||
307 | private java.awt.geom.AffineTransform computeGeographicToRasterTransform(
|
||
308 | int width, int height, Sector sector) { |
||
309 | // Compute the the transform from geographic to raster coordinates. In
|
||
310 | // this computation a pixel is assumed
|
||
311 | // to cover a finite area.
|
||
312 | |||
313 | double ty = -sector.getMaxLatitude().degrees;
|
||
314 | double tx = -sector.getMinLongitude().degrees;
|
||
315 | |||
316 | double sy = -(height / sector.getDeltaLatDegrees());
|
||
317 | double sx = (width / sector.getDeltaLonDegrees());
|
||
318 | |||
319 | java.awt.geom.AffineTransform transform = |
||
320 | new java.awt.geom.AffineTransform();
|
||
321 | transform.scale(sx, sy); |
||
322 | transform.translate(tx, ty); |
||
323 | return transform;
|
||
324 | } |
||
325 | |||
326 | public DataRaster getSubRaster(AVList params) {
|
||
327 | int width = (Integer) params.getValue(AVKey.WIDTH); |
||
328 | int height = (Integer) params.getValue(AVKey.HEIGHT); |
||
329 | Sector sector = (Sector) params.getValue(AVKey.SECTOR); |
||
330 | |||
331 | return this.getSubRaster(width, height, sector, params); |
||
332 | } |
||
333 | |||
334 | public DataRaster getSubRaster(int width, int height, Sector sector, |
||
335 | AVList params) { |
||
336 | |||
337 | params.setValue(AVKey.WIDTH, width); |
||
338 | params.setValue(AVKey.HEIGHT, height); |
||
339 | params.setValue(AVKey.SECTOR, sector); |
||
340 | |||
341 | GvSIGLayerDataRaster subRaster = |
||
342 | new GvSIGLayerDataRaster(mapContext, layer, params);
|
||
343 | return subRaster;
|
||
344 | } |
||
345 | } |