Statistics
| Revision:

svn-gvsig-desktop / branches / v2_0_0_prep / libraries / libFMap_mapcontext / src / org / gvsig / fmap / mapcontext / ViewPort.java @ 28954

History | View | Annotate | Download (46.9 KB)

1 21200 vcaballero
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
2
 *
3
 * Copyright (C) 2004 IVER T.I. and Generalitat Valenciana.
4
 *
5
 * This program is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU General Public License
7
 * as published by the Free Software Foundation; either version 2
8
 * of the License, or (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
18
 *
19
 * For more information, contact:
20
 *
21
 *  Generalitat Valenciana
22
 *   Conselleria d'Infraestructures i Transport
23
 *   Av. Blasco Ib??ez, 50
24
 *   46010 VALENCIA
25
 *   SPAIN
26
 *
27
 *      +34 963862235
28
 *   gvsig@gva.es
29
 *      www.gvsig.gva.es
30
 *
31
 *    or
32
 *
33
 *   IVER T.I. S.A
34
 *   Salamanca 50
35
 *   46005 Valencia
36
 *   Spain
37
 *
38
 *   +34 963163400
39
 *   dac@iver.es
40
 */
41
package org.gvsig.fmap.mapcontext;
42
43
import java.awt.Color;
44
import java.awt.Dimension;
45
import java.awt.Point;
46 26225 jmvivo
import java.awt.Toolkit;
47 21200 vcaballero
import java.awt.geom.AffineTransform;
48
import java.awt.geom.NoninvertibleTransformException;
49
import java.awt.geom.Point2D;
50
import java.awt.geom.Rectangle2D;
51
import java.util.ArrayList;
52
53
import org.cresques.cts.GeoCalc;
54
import org.cresques.cts.IProjection;
55 27514 cmartinez
import org.cresques.cts.UTM;
56 21200 vcaballero
import org.gvsig.fmap.crs.CRSFactory;
57 27414 jpiera
import org.gvsig.fmap.geom.GeometryLocator;
58
import org.gvsig.fmap.geom.GeometryManager;
59
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
60
import org.gvsig.fmap.geom.exception.CreateEnvelopeException;
61 21426 vcaballero
import org.gvsig.fmap.geom.primitive.Envelope;
62 27019 jpiera
import org.gvsig.fmap.geom.util.UtilFunctions;
63 21200 vcaballero
import org.gvsig.fmap.mapcontext.events.ColorEvent;
64
import org.gvsig.fmap.mapcontext.events.ExtentEvent;
65
import org.gvsig.fmap.mapcontext.events.ProjectionEvent;
66
import org.gvsig.fmap.mapcontext.events.listeners.ViewPortListener;
67 27414 jpiera
import org.slf4j.Logger;
68
import org.slf4j.LoggerFactory;
69 21200 vcaballero
70
import com.iver.utiles.StringUtilities;
71
import com.iver.utiles.XMLEntity;
72
73
74
/**
75
 * <p><code>ViewPort</code> class represents the logic needed to transform a rectangular area of a map
76
 *  to the available area in screen to display it.</p>
77
 *
78
 * <p>Includes an affine transformation, between the rectangular area selected of the external map, in its own
79
 *  <i>map coordinates</i>, to the rectangular area available of a view in <i>screen coordinates</i>.</p>
80
 *
81
 * <p>Elements:
82
 * <ul>
83
 * <li><i>extent</i>: the area selected of the map, in <i>map coordinates</i>.
84
 * <li><i>imageSize</i>: width and height in pixels (<i>screen coordinates</i>) of the area available
85
 *  in screen to display the area selected of the map.
86
 * <li><i>adjustedExtent</i>: the area selected must be an scale of <i>imageSize</i>.<br>This implies adapt the
87
 *  extent, preserving and centering it, and adding around the needed area to fill all the image size. That
88
 *  added area will be extracted from the original map, wherever exists, and filled with the background color
89
 *  wherever not.
90
 * <li><i>scale</i>: the scale between the adjusted extent and the image size.
91
 * <li><i>backColor</i>: the default background color in the view, if there is no map.
92
 * <li><i>trans</i>: the affine transformation.
93
 * <li><i>proj</i>: map projection used in this view.
94
 * <li><i>distanceUnits</i>: distance measurement units, of data in screen.
95
 * <li><i>mapUnits</i>: measurement units, of data in map.
96
 * <li><i>extents</i>: an {@link ExtentHistory ExtentHistory} with the last previous extents.
97
 * <li><i>offset</i>: position in pixels of the available rectangular area, where start drawing the map.
98
 * <li><i>dist1pixel</i>: the distance in <i>world coordinates</i> equivalent to 1 pixel in the view with the
99
 *  current extent.
100
 * <li><i>dist3pixel</i>: the distance in <i>world coordinates</i> equivalent to 3 pixels in the view with the
101
 *  current extent.
102
 * <li><i>listeners</i>: list with the {@link ViewPortListener ViewPortListener} registered.
103
 * </ul>
104
 * </p>
105
 *
106
 * @author Vicente Caballero Navarro
107
 */
108
public class ViewPort {
109
//        /**
110
//         * <p>Metric unit or length equal to 1000 meters.</p>
111
//         */
112
//        public static int KILOMETROS = 0;
113
//
114
//        /**
115
//         * <p>The base unit of length in the International System of Units that is equal to the distance
116
//         *  traveled by light in a vacuum in {frac;1;299,792,458} second or to about 39.37 inches.</p>
117
//         */
118
//        public static int METROS = 1;
119
//
120
//        /**
121
//         * <p>Metric unit or length equal to 0'01 meters.</p>
122
//         */
123
//        public static int CENTIMETRO = 2;
124
//
125
//        /**
126
//         * <p>Metric unit or length equal to 0'001 meters.</p>
127
//         */
128
//        public static int MILIMETRO = 3;
129
//
130
//        /**
131
//         * <p>The international statute mile by international agreement. It is defined to be precisely
132
//         *  1,760 international yards (by definition, 0.9144 m each) and is therefore exactly 1,609.344
133
//         *  metres (1.609344 km).</p>
134
//         */
135
//        public static int MILLAS = 4;
136
//
137
//        /**
138
//         * <p>Unit of length equal in the United States to 0.9144 meter.</p>
139
//         */
140
//        public static int YARDAS = 5;
141
//
142
//        /**
143
//         * <p>Any of various units of length based on the length of the human foot; especially :
144
//         *  a unit equal to 1/3 yard and comprising 12 inches.</p>
145
//         */
146
//        public static int PIES = 6;
147
//
148
//        /**
149
//         * <p>Unit of length equal to 1/36 yard.</p>
150
//         */
151
//        public static int PULGADAS = 7;
152
//
153
//        /**
154
//         * <p>Grades according the current projection.</p>
155
//         */
156
//        public static int GRADOS = 8;
157 27414 jpiera
        private static final GeometryManager geomManager = GeometryLocator.getGeometryManager();
158
        private static final Logger logger = LoggerFactory.getLogger(GeometryManager.class);
159
160 21200 vcaballero
        /**
161
         * <p>Screen resolution in <i>dots-per-inch</i>. Useful to calculate the geographic scale of the view.</p>
162
         *
163
         * @see Toolkit#getScreenResolution()
164
         * @see #getScale()
165
         */
166
        private static int dpi = java.awt.Toolkit.getDefaultToolkit()
167
                                                                                         .getScreenResolution();
168
169
        /**
170
         * <p>Area selected by user using some tool.</p>
171
         *
172
         * <p>When the zoom changes (for instance when using the zoom in or zoom out tools,
173
         *  but also zooming to a selected feature or shape) the extent that covers that
174
         *  area is the value returned by this method. It is not the actual area shown
175
         *  in the view because it does not care about the aspect ratio of the available
176
         *  area. However, any part of the real world contained in this extent is shown
177
         *  in the view.
178
         * </p>
179
         * <p>
180
         * Probably this is not what you are looking for. If you are looking for
181
         * the complete extent currently shown, you must use {@linkplain #getAdjustedExtent()} method
182
         * which returns the extent that contains this one but regarding the current
183
         * view's aspect ratio.
184
         * </p>
185
         *
186
         * @see #getExtent()
187 21426 vcaballero
         * @see #setEnvelope(Envelope)
188 21200 vcaballero
         */
189
        protected Rectangle2D extent;
190
191
        /**
192
         * <p>Location and dimensions of the extent adjusted to the image size.</p>
193
         *
194
         * @see #getAdjustedExtent()
195
         */
196
        protected Rectangle2D adjustedExtent;
197
198
        /**
199 26225 jmvivo
         * Draw version of the context. It's used for know when de componend has
200
         * changed any visualization property
201
         *
202
         *  @see getDrawVersion
203
         *  @see updateDrawVersion
204
         */
205
        private long drawVersion= 0L;
206
207
        /**
208 21200 vcaballero
         * <p>History with the last extents of the view.</p>
209
         *
210
         * @see #setPreviousExtent()
211
         * @see #getExtents()
212
         */
213
        protected ExtentHistory extents = new ExtentHistory();
214
215
        /**
216
         * <p>Size in <i>screen coordinates</i> of the rectangle where the image is displayed.</p>
217
         * <p>Used by {@linkplain #calculateAffineTransform()} to calculate:<br>
218
           *
219
         * <ul>
220
         * <li>The new {@link #scale scale} .
221
         * <li>The new {@link #adjustedExtent adjustableExtent} .
222
         * <li>The new {@link #trans trans} .
223
         * <li>The new real world coordinates equivalent to 1 pixel ({@link #dist1pixel dist1pixel}) .
224
         * <li>The new real world coordinates equivalent to 3 pixels ({@link #dist3pixel dist3pixel}) .
225
         * </ul>
226
         * </p>
227
         *
228
         * @see #getImageSize()
229
         * @see #getImageHeight()
230
         * @see #getImageWidth()
231
         * @see #setImageSize(Dimension)
232
         */
233
        private Dimension imageSize;
234
235
        /**
236
         * <p>the affine transformation between the {@link #extent extent} in <i>map 2D coordinates</i> to
237
         *  the image area in the screen, in <i>screen 2D coordinates</i> (pixels).</p>
238
         *
239
         * @see AffineTransform
240
         *
241
         * @see #getAffineTransform()
242
         * @see #setAffineTransform(AffineTransform)
243
         * @see #calculateAffineTransform()
244
         */
245
        private AffineTransform trans = new AffineTransform();
246
247
        /**
248
         * <p>Measurement unit used for measuring distances and displaying information.</p>
249
         *
250
         * @see #getDistanceUnits()
251
         * @see #setDistanceUnits(int)
252
         */
253
        private int distanceUnits = 1;
254
        /**
255
         * <p>Measurement unit used for measuring areas and displaying information.</p>
256
         *
257
         * @see #getDistanceArea()
258
         * @see #setDistanceArea(int)
259
         */
260
        private int distanceArea = 1;
261
        /**
262
         * <p>Measurement unit used by this view port for the map.</p>
263
         *
264
         * @see #getMapUnits()
265
         * @see #setMapUnits(int)
266
         */
267
        private int mapUnits = 1;
268
269
        /**
270
         * <p>Array with the {@link ViewPortListener ViewPortListener}s registered to this view port.</p>
271
         *
272
         * @see #addViewPortListener(ViewPortListener)
273
         * @see #removeViewPortListener(ViewPortListener)
274
         */
275
        private ArrayList listeners = new ArrayList();
276
277
        /**
278
         * <p>The offset is the position where start drawing the map.</p>
279
         * <p>The offset of a <a href="http://www.gvsig.gva.es/">gvSIG</a>'s <i>View</i> is
280
         * always (0, 0) because the drawing area fits with the full window area. But in
281
         * a <a href="http://www.gvsig.gva.es/">gvSIG</a>'s <i>Layout</i> it's up to the place where
282
         * the <code>FFrameView</code> is located.</p>
283
         *
284
         * @see #getOffset()
285
         * @see #setOffset(Point2D)
286
         */
287
        private Point2D offset = new Point2D.Double(0, 0);
288
289
        /**
290
         * <p>Clipping area.</p>
291
         */
292
        private Rectangle2D clip;
293
294
        /**
295
         * <p>Background color of this view.</p>
296
         *
297
         * @see #getBackColor()
298
         * @see #setBackColor(Color)
299
         */
300
        private Color backColor = null; //Color.WHITE;
301
302
        /**
303
         * <p>Information about the map projection used in this view.</p>
304
         *
305
         * @see #getProjection()
306
         * @see #setProjection(IProjection)
307
         */
308
        private IProjection proj;
309
310
        /**
311
         * <p>Represents the distance in <i>world coordinates</i> equivalent to 1 pixel in the view with the current extent.</p>
312
         *
313
         * @see #getDist1pixel()
314
         * @see #setDist1pixel(double)
315
         */
316
        private double dist1pixel;
317
318
        /**
319
         * <p>Represents the distance in <i>world coordinates</i> equivalent to 3 pixels in the view with the current extent.</p>
320
         *
321
         * @see #getDist3pixel()
322
         * @see #setDist3pixel(double)
323
         */
324
        private double dist3pixel;
325
326
        /**
327
         * <p>Ratio between the size of <code>imageSize</code> and <code>extent</code>:<br> <i><pre>min{(imageSize.getHeight()/extent.getHeight(), imageSize.getWidth()/extent.getWidth())}</pre></i></p>
328
         */
329
        private double scale;
330
331
        /**
332
         * <p>Clipping area.</p>
333
         *
334
         * @see #setClipRect(Rectangle2D)
335
         */
336
        private Rectangle2D cliprect;
337
338
        /**
339
         * <p>Enables or disables the <i>"adjustable extent"</i> mode.</p>
340
         *
341
         * <p>
342
         * When calculates the affine transform, if
343
         * <ul>
344
         * <li><i>enabled</i>: the new <code>adjustedExtent</code> will have the (X, Y) coordinates of the <code>extent</code> and
345
         *  an area that will be an scale of the image size. That area will have different
346
         *  height or width (not both) of the extent according the least ratio (height or width) in <pre>image.size/extent.size"</pre>.
347
         * <li><i>disabled</i>: the new <code>adjustedExtent</code> will be like <code>extent</code>.
348
         * </ul>
349
         * </p>
350
         *
351
         * @see #setAdjustable(boolean)
352
         */
353
        private boolean adjustableExtent=true;
354
355
        /**
356
         * <p>Creates a new view port with the information of the projection in <code>proj</code> argument, and
357
         *  default configuration:</p>
358
         * <p>
359
         * <ul>
360
         *  <li><i><code>distanceUnits</code></i> = meters
361
         *  <li><i><code>mapUnits</code></i> = meters
362
         *  <li><i><code>backColor</code></i> = <i>undefined</i>
363
         *  <li><i><code>offset</code></i> = <code>new Point2D.Double(0, 0);</code>
364
         * </ul>
365
         * </p>
366
         *
367
         * @param proj information of the projection for this view port
368
         */
369
        public ViewPort(IProjection proj) {
370
                // Por defecto
371
                this.proj = proj;
372
        }
373
374
        /**
375
         * <p>Changes the status of the <i>"adjustable extent"</i> option to enabled or disabled.</p>
376
         *
377
         * <p>If view port isn't adjustable, won't bear in mind the aspect ratio of the available rectangular area to
378
         *  calculate the affine transform from the original map in real coordinates. (Won't scale the image to adapt
379
         *  it to the available rectangular area).</p>
380
         *
381
         * @param boolean the boolean to be set
382
         */
383
        public void setAdjustable(boolean adjustable) {
384 26225 jmvivo
                if (adjustable == adjustableExtent){
385
                        return;
386
                }
387 21200 vcaballero
                adjustableExtent = adjustable;
388 26225 jmvivo
                this.updateDrawVersion();
389 21200 vcaballero
        }
390
391
        /**
392
         * <p>Appends the specified {@link ViewPortListener ViewPortListener} listener if weren't.</p>
393
         *
394
         * @param arg0 the listener to add
395
         *
396
         * @return <code>true</code> if has been added successfully
397
         *
398
         * @see #removeViewPortListener(ViewPortListener)
399
         */
400
        public boolean addViewPortListener(ViewPortListener arg0) {
401 26905 jmvivo
                if (!listeners.contains(arg0)) {
402 21200 vcaballero
                        return listeners.add(arg0);
403 26905 jmvivo
                }
404 21200 vcaballero
                return false;
405
        }
406
407
        /**
408
          * <p>Removes the specified {@link ViewPortListener ViewPortListener} listener, if existed.</p>
409
         *
410
         * @param arg0 the listener to remove
411
         *
412
         * @return <code>true</code> if the contained the specified listener.
413
         *
414
         * @see #addViewPortListener(ViewPortListener)
415
         */
416
        public boolean removeViewPortListener(ViewPortListener arg0) {
417
                return listeners.remove(arg0);
418
        }
419
420
        /**
421
         * <p>Converts and returns the distance <code>d</code>, that is in <i>map
422
         *  coordinates</i> to <i>screen coordinates</i> using a <i>delta transform</i> with
423
         *  the transformation affine information in the {@link #trans #trans} attribute.</p>
424
         *
425
         * @param d distance in <i>map coordinates</i>
426
         *
427
         * @return distance equivalent in <i>screen coordinates</i>
428
         *
429
         * @see #toMapDistance(int)
430
         * @see AffineTransform#deltaTransform(Point2D, Point2D)S
431
         */
432
        public int fromMapDistance(double d) {
433
                Point2D.Double pWorld = new Point2D.Double(1, 1);
434
                Point2D.Double pScreen = new Point2D.Double();
435
436
                try {
437
                        trans.deltaTransform(pWorld, pScreen);
438
                } catch (Exception e) {
439
                        System.err.print(e.getMessage());
440
                }
441
442
                return (int) (d * pScreen.x);
443
        }
444
445
        /**
446
         * <p>Converts and returns the 2D point <code>(x,y)</code>, that is in <i>map
447
         *  coordinates</i> to <i>screen coordinates</i> (pixels) using
448
         *  the affine transformation in the {@link #trans #trans} attribute.</p>
449
         *
450
         * @param x the <code>x</code> <i>map coordinate</i> of a 2D point
451
         * @param y the <code>y</code> <i>map coordinate</i> of a 2D point
452
         *
453
         * @return 2D point equivalent in <i>screen coordinates</i> (pixels)
454
         *
455
         * @see #fromMapPoint(Point2D)
456
         * @see AffineTransform#transform(Point2D, Point2D)
457
         */
458
        public Point2D fromMapPoint(double x, double y) {
459
                Point2D.Double pWorld = new Point2D.Double(x, y);
460
                Point2D.Double pScreen = new Point2D.Double();
461
462
                try {
463
                        trans.transform(pWorld, pScreen);
464
                } catch (Exception e) {
465
                        System.err.print(e.getMessage());
466
                }
467
468
                return pScreen;
469
        }
470
471
        /**
472
         * <p>Converts and returns the 2D point argument, that is in <i>map
473
         *  coordinates</i> to <i>screen coordinates</i> (pixels) using
474
         *  the affine transformation in the {@link #trans #trans} attribute.</p>
475
         *
476
         * @param point the 2D point in <i>map coordinates</i>
477
         *
478
         * @return 2D point equivalent in <i>screen coordinates</i> (pixels)
479
         *
480
         * @see #toMapPoint(Point2D)
481
         * @see #fromMapPoint(double, double)
482
         */
483
        public Point2D fromMapPoint(Point2D point) {
484
                return fromMapPoint(point.getX(), point.getY());
485
        }
486
487
        /**
488
         * <p>Converts and returns the 2D point <code>(x,y)</code>, that is in <i>screen coordinates</i>
489
         *  (pixels) to <i>map coordinates</i> using
490
         *  the affine transformation in the {@link #trans #trans} attribute.</p>
491
         *
492
         * @param x the <code>x</code> <i>screen coordinate</i> of a 2D point
493
         * @param y the <code>y</code> <i>screen coordinate</i> of a 2D point
494
         *
495
         * @return 2D point equivalent in <i>map coordinates</i>
496
         *
497
         * @see #toMapPoint(Point2D)
498
         * @see #fromMapPoint(double, double)
499
         */
500
        public Point2D toMapPoint(int x, int y) {
501
                Point pScreen = new Point(x, y);
502
503
                return toMapPoint(pScreen);
504
        }
505
506
        /**
507
         * <p>Converts and returns the {@link Rectangle2D Rectangle2D}, that is in <i>screen
508
         *  coordinates</i> (pixels) to <i>map coordinates</i> using {@linkplain #toMapDistance(int)},
509
         *  and {@linkplain #toMapPoint(int, int)}.</p>
510
         *
511
         * @param r the 2D rectangle in <i>screen coordinates</i> (pixels)
512
         * @return 2D rectangle equivalent in <i>map coordinates</i>
513
         *
514
         * @see #fromMapRectangle(Rectangle2D)
515
         * @see #toMapDistance(int)
516
         * @see #toMapPoint(int, int)
517
         */
518
        public Rectangle2D toMapRectangle(Rectangle2D r){
519
                Rectangle2D rect=new Rectangle2D.Double();
520
                Point2D p1=toMapPoint((int)r.getX(),(int)r.getY());
521
                Point2D p2=toMapPoint((int)r.getMaxX(),(int)r.getMaxY());
522
                rect.setFrameFromDiagonal(p1,p2);
523
                return rect;
524
        }
525
526
        /**
527
         * <p>Converts and returns the distance <code>d</code>, that is in <i>screen
528
         *  coordinates</i> to <i>map coordinates</i> using the transformation affine information
529
         *  in the {@link #trans #trans} attribute.</p>
530
         *
531
         * @param d distance in pixels
532
         *
533
         * @return distance equivalent in <i>map coordinates</i>
534
         *
535
         * @see #fromMapDistance(double)
536
         * @see AffineTransform
537
         */
538
        public double toMapDistance(int d) {
539
                double dist = d / trans.getScaleX();
540
541
                return dist;
542
        }
543
544
        /**
545
         * <p>Converts and returns the 2D point argument, that is in <i>screen coordinates</i>
546
         *  (pixels) to <i>map coordinates</i> using the
547
         *  inverse affine transformation of the {@link #trans #trans} attribute.</p>
548
         *
549
         * @param pScreen the 2D point in <i>screen coordinates</i> (pixels)
550
         *
551
         * @return 2D point equivalent in <i>map coordinates</i>
552
         *
553
         * @see #toMapPoint(int, int)
554
         * @see AffineTransform#createInverse()
555
         * @see AffineTransform#transform(Point2D, Point2D)
556
         */
557
        public Point2D toMapPoint(Point2D pScreen) {
558
                Point2D.Double pWorld = new Point2D.Double();
559
                AffineTransform at;
560
561
                try {
562
                        at = trans.createInverse();
563
                        at.transform(pScreen, pWorld);
564
                } catch (NoninvertibleTransformException e) {
565
                        throw new RuntimeException("Non invertible transform Exception",e);
566
                }
567
568
                return pWorld;
569
        }
570
571
        /**
572
         * <p>Returns the real distance (in <i>world coordinates</i>) at the graphic layers of two 2D points
573
         *  (in <i>map coordinates</i>) of the plane where is selected the <i>extent</i>.</p>
574
         * <p>If the projection of this view is UTM, considers the Earth curvature.</p>
575
         *
576
         * @param pt1 a 2D point in <i>map coordinates</i>
577
         * @param pt2 another 2D point in <i>map coordinates</i>
578
         *
579
         * @return the distance in meters between the two points 2D
580
         *
581 27514 cmartinez
         * @see GeoCalcImpl#distanceVincenty(Point2D, Point2D)
582 21200 vcaballero
         */
583
        public double distanceWorld(Point2D pt1, Point2D pt2) {
584
                double dist = -1;
585
                dist = pt1.distance(pt2);
586
587 27514 cmartinez
                if ((proj != null) && !(proj instanceof UTM)) {
588 21200 vcaballero
                        dist = new GeoCalc(proj).distanceVincenty(proj.toGeo(pt1),
589
                                        proj.toGeo(pt2));
590
                        return dist;
591
                }
592
                return (dist*MapContext.getDistanceTrans2Meter()[getMapUnits()]);
593
        }
594
595
        /**
596
         * <p>Sets as extent and adjusted extent of this view port, the previous. Recalculating
597
         *  its parameters.</p>
598
         *
599
         * @see #getExtents()
600
         * @see #calculateAffineTransform()
601
         */
602
        public void setPreviousExtent() {
603 26225 jmvivo
                this.updateDrawVersion();
604 21200 vcaballero
                extent = extents.removePrev();
605
606
                //Calcula la transformaci?n af?n
607
                calculateAffineTransform();
608
609
                // Lanzamos los eventos de extent cambiado
610
                callExtentChanged(getAdjustedExtent());
611
        }
612
613
        /**
614
         * <p>Gets the area selected by user using some tool.</p>
615
         *
616
         * <p>When the zoom changes (for instance using the <i>zoom in</i> or <i>zoom out</i> tools,
617
         *  but also zooming to a selected feature or shape) the extent that covers that
618
         *  area is the value returned by this method. It is not the actual area shown
619
         *  because it doesn't care about the aspect ratio of the image size of the view. However, any
620
         *  part of the real world contained in this extent is shown in the view.</p>
621
         *
622
         * <p>If you are looking for the complete extent currently shown, you must use the
623
         *  {@linkplain #getAdjustedExtent()} method.</p>
624
         *
625
         * @return the current extent
626
         *
627 21426 vcaballero
         * @see #setEnvelope(Envelope)
628 21200 vcaballero
         * @see #getAdjustedExtent()
629
         * @see #setPreviousExtent()
630
         * @see #getExtents()
631
         */
632
        public Rectangle2D getExtent() {
633
                return extent;
634
        }
635
636
        /**
637
         * <p>Changes the <i>extent</i> and <i>adjusted extent</i> of this view port:<br>
638
         * <ul>
639
         * <li>Stores the previous extent.
640
         * <li>Calculates the new extent using <code>r</code>:
641
         * <pre>extent = new Rectangle2D.Double(r.getMinX() - 0.1, r.getMinY() - 0.1, r.getWidth() + 0.2, r.getHeight() + 0.2);</pre>
642
         * <li>Executes {@linkplain #calculateAffineTransform()}: getting the new scale, adjusted extent, affine transformation between
643
         *  map and screen coordinates, the real world coordinates equivalent to 1 pixel, and the real world coordinates equivalent to 3 pixels.
644
         * <li>Notifies all {@link ViewPortListener ViewPortListener} registered that the extent has changed.
645
         * </ul>
646
         * </p>
647
         *
648
         * @param r the new extent
649
         *
650
         * @see #getExtent()
651
         * @see #getExtents()
652
         * @see #calculateAffineTransform()
653
         * @see #setPreviousExtent()
654
         */
655 21426 vcaballero
        public void setEnvelope(Envelope r) {
656 26225 jmvivo
                Rectangle2D newExtent=null;
657 21200 vcaballero
                //Esto comprueba que el extent no es de anchura o altura = "0"
658
                //y si es as? lo redimensiona.
659 26905 jmvivo
                if (r!=null) {
660
                        if ((r.getMaximum(0) - r.getMinimum(0) == 0)
661
                                        || (r.getMaximum(1) - r.getMinimum(1) == 0)) {
662
                                newExtent = new Rectangle2D.Double(r.getMinimum(0) - 0.1,
663 21426 vcaballero
                                        r.getMinimum(1) - 0.1, r.getMaximum(0)-r.getMinimum(0) + 0.2, r.getMaximum(1)-r.getMinimum(1) + 0.2);
664 26905 jmvivo
                        } else {
665
                                newExtent = new Rectangle2D.Double(r.getMinimum(0),r.getMinimum(1),Math.abs(r.getMaximum(0)-r.getMinimum(0)),Math.abs(r.getMaximum(1)-r.getMinimum(1)));
666
                        }
667 21200 vcaballero
                }
668
669 26225 jmvivo
                if (this.extent != null && this.extent.equals(newExtent)){
670
                        return;
671
                }
672
                if (extent != null) {
673
                        extents.put(extent);
674
                }
675
                this.updateDrawVersion();
676
                this.extent = newExtent;
677 26905 jmvivo
678 21200 vcaballero
                //Calcula la transformaci?n af?n
679
                calculateAffineTransform();
680
681
                // Lanzamos los eventos de extent cambiado
682
                callExtentChanged(getAdjustedExtent());
683
        }
684
685
        /**
686
         * <p>Changes the <i>extent</i> and <i>adjusted extent</i> of this view port:<br>
687
         * <ul>
688
         * <li>Executes {@linkplain #calculateAffineTransform()}: getting the new scale, adjusted extent, affine transformation between
689
         *  map and screen coordinates, the real world coordinates equivalent to 1 pixel, and the real world coordinates equivalent to 3 pixels.
690
         * <li>Notifies to all {@link ViewPortListener ViewPortListener} registered that the extent has changed.
691
         * </ul>
692
         * </p>
693
         *
694 21426 vcaballero
         * @see #setEnvelope(Envelope)
695 21200 vcaballero
         * @see #calculateAffineTransform()
696
         */
697
        public void refreshExtent() {
698
                //this.scale = scale;
699
700
                //Calcula la transformaci?n af?n
701
                calculateAffineTransform();
702
703
                // Lanzamos los eventos de extent cambiado
704
                callExtentChanged(getAdjustedExtent());
705
        }
706
707
        /**
708
         * <p>Calculates and returns using the current projection of this view port, the scale that
709
         *  is the extent in <i>screen coordinates</i> from the image in <i>map coordinates</i>.</p>
710
         *
711
         * @return the scale <i>extent / image size</i> projected by this view port
712
         *
713
         * @deprecated since 07/09/07, use {@linkplain MapContext#getScaleView()}
714
         */
715
        public double getScale() {
716
                return proj.getScale(extent.getMinX(), extent.getMaxX(),
717
                        imageSize.getWidth(), dpi);
718
        }
719
720
        /**
721
         * <p>Affine transformation between <i>map 2D coordinates</i> to <i>screen 2D coordinates</i> (pixels),
722
         * preserving the "straightness" and "parallelism" of the lines.</p>
723
         *
724
         * @return the affine transformation
725
         *
726
         * @see #setAffineTransform(AffineTransform)
727
         * @see #calculateAffineTransform()
728
         */
729
        public AffineTransform getAffineTransform() {
730
                return trans;
731
        }
732
733
        /**
734
         * <p>Returns the size of the image projected.</p>
735
         *
736
         * @return the image size
737
         *
738
         * @see #setImageSize(Dimension)
739
         * @see #getImageHeight()
740
         * @see #getImageWidth()
741
         */
742
        public Dimension getImageSize() {
743
                return imageSize;
744
        }
745
746
        /**
747
         * <p>Sets the size of the image projected, recalculating the parameters of this view port.</p>
748
         *
749
         * @param imageSize the image size
750
         *
751
         * @see #getImageSize()
752
         * @see #calculateAffineTransform()
753
         */
754
        public void setImageSize(Dimension imageSize) {
755 26225 jmvivo
756
                if (this.imageSize == null  || (!this.imageSize.equals(imageSize))){
757
                                this.updateDrawVersion();
758
                                this.imageSize = imageSize;
759
                                calculateAffineTransform();
760
                }
761 21200 vcaballero
        }
762
763
        /**
764
         * <p>Notifies to all view port listeners registered, that the adjusted extent of this view port
765
         *  has changed.</p>
766
         *
767
         * @param newRect the new adjusted extend
768
         *
769
         * @see #refreshExtent()
770 21426 vcaballero
         * @see #setEnvelope(Envelope)
771 21200 vcaballero
         * @see #setPreviousExtent()
772
         * @see ExtentEvent
773
         * @see ViewPortListener
774
         */
775 21531 vcaballero
        protected void callExtentChanged(Envelope newRect) {
776 21200 vcaballero
                ExtentEvent ev = ExtentEvent.createExtentEvent(newRect);
777
778
                for (int i = 0; i < listeners.size(); i++) {
779
                        ViewPortListener listener = (ViewPortListener) listeners.get(i);
780
                        listener.extentChanged(ev);
781
                }
782
        }
783
784
        /**
785
         * <p>Notifies to all view port listeners registered, that the background color of this view port
786
         *  has changed.</p>
787
         *
788
         * @param c the new background color
789
         *
790
         * @see #setBackColor(Color)
791
         * @see ColorEvent
792
         * @see ViewPortListener
793
         */
794
        private void callColorChanged(Color c) {
795
                ColorEvent ce = ColorEvent.createColorEvent(c);
796
797
                for (int i = 0; i < listeners.size(); i++) {
798
                        ViewPortListener listener = (ViewPortListener) listeners.get(i);
799
                        listener.backColorChanged(ce);
800
                }
801
        }
802
803
        /**
804
         * <p>Notifies to all view port listeners registered, that the projection of this view port
805
         *  has changed.</p>
806
         *
807
         * @param projection the new projection
808
         *
809
         * @see #setProjection(IProjection)
810
         * @see ProjectionEvent
811
         * @see ViewPortListener
812
         */
813
        private void callProjectionChanged(IProjection projection) {
814
                ProjectionEvent ev = ProjectionEvent.createProjectionEvent(projection);
815
816
                for (int i = 0; i < listeners.size(); i++) {
817
                        ViewPortListener listener = (ViewPortListener) listeners.get(i);
818
                        listener.projectionChanged(ev);
819
                }
820
        }
821
822
        /**
823
         * <p>Calculates the affine transformation between the {@link #extent extent} in <i>map 2D coordinates</i> to
824
         *  the image area in the screen, in <i>screen 2D coordinates</i> (pixels).</p>
825
         *
826
         * <p>This process recalculates some parameters of this view port:<br>
827
         *
828
         * <ul>
829
         * <li>The new {@link #scale scale} .
830
         * <li>The new {@link #adjustedExtent adjustedExtent} .
831
         * <li>The new {@link #trans trans} .
832
         * <li>The new real world coordinates equivalent to 1 pixel ({@link #dist1pixel dist1pixel}) .
833
         * <li>The new real world coordinates equivalent to 3 pixels ({@link #dist3pixel dist3pixel}) .
834
         * </ul>
835
         * </p>
836
         *
837
         * @see #getAffineTransform()
838
         * @see #setAffineTransform(AffineTransform)
839
         * @see #refreshExtent()
840 21426 vcaballero
         * @see #setEnvelope(Envelope)
841 21200 vcaballero
         * @see #setImageSize(Dimension)
842
         * @see #setPreviousExtent()
843
         * @see #createFromXML(XMLEntity)
844
         * @see AffineTransform
845
         */
846
        private void calculateAffineTransform() {
847
                if ((imageSize == null) || (extent == null) ||
848
                                (imageSize.getWidth() <= 0) || (imageSize.getHeight() <= 0)) {
849
                        return;
850
                }
851
852
                AffineTransform escalado = new AffineTransform();
853
                AffineTransform translacion = new AffineTransform();
854
855
                double escalaX;
856
                double escalaY;
857
858
                escalaX = imageSize.getWidth() / extent.getWidth();
859
                escalaY = imageSize.getHeight() / extent.getHeight();
860
861
                double xCenter = extent.getCenterX();
862
                double yCenter = extent.getCenterY();
863
                double newHeight;
864
                double newWidth;
865
866
                adjustedExtent = new Rectangle2D.Double();
867
868
                if (adjustableExtent) {
869
                        if (escalaX < escalaY) {
870
                                scale = escalaX;
871
                                newHeight = imageSize.getHeight() / scale;
872
                                adjustedExtent.setRect(xCenter - (extent.getWidth() / 2.0),
873
                                        yCenter - (newHeight / 2.0), extent.getWidth(), newHeight);
874
                        } else {
875
                                scale = escalaY;
876
                                newWidth = imageSize.getWidth() / scale;
877
                                adjustedExtent.setRect(xCenter - (newWidth / 2.0),
878
                                        yCenter - (extent.getHeight() / 2.0), newWidth,
879
                                        extent.getHeight());
880
                        }
881
                        escalado.setToScale(scale, -scale);
882
                }
883
                else { // adjusted is same as extent
884
                        scale = escalaX;
885
                        adjustedExtent.setFrame(extent);
886
                        escalado.setToScale(escalaX, -escalaY);
887
                }
888 21531 vcaballero
                Envelope env=getAdjustedExtent();
889 26905 jmvivo
                if (env == null) {
890 21886 vcaballero
                        return;
891 26905 jmvivo
                }
892 21531 vcaballero
                translacion.setToTranslation(-env.getMinimum(0),
893 21886 vcaballero
                        -env.getMinimum(1) - getAdjustedExtent().getLength(1));
894 21200 vcaballero
895
                AffineTransform offsetTrans = new AffineTransform();
896
                offsetTrans.setToTranslation(offset.getX(), offset.getY());
897
898
                trans.setToIdentity();
899
                trans.concatenate(offsetTrans);
900
                trans.concatenate(escalado);
901
902
                trans.concatenate(translacion);
903
904
                // Calculamos las distancias de 1 pixel y 3 pixel con esa transformaci?n
905
                // de coordenadas, de forma que est?n precalculadas para cuando las necesitemos
906
                AffineTransform at;
907
908
                try {
909
                        at = trans.createInverse();
910
911
                        java.awt.Point pPixel = new java.awt.Point(1, 1);
912
                        Point2D.Float pProv = new Point2D.Float();
913
                        at.deltaTransform(pPixel, pProv);
914
915
                        dist1pixel = pProv.x;
916
                        dist3pixel = 3 * pProv.x;
917
                } catch (NoninvertibleTransformException e) {
918
                        System.err.println("transformada afin = " + trans.toString());
919
                        System.err.println("extent = " + extent.toString() +
920
                                " imageSize= " + imageSize.toString());
921
                        throw new RuntimeException("Non invertible transform Exception",e);
922
                }
923
        }
924
925
        /**
926
         * <p>Sets the offset.</p>
927
         * <p>The offset is the position where start drawing the map.</p>
928
         *
929
         * @param p 2D point that represents the offset in pixels
930
         *
931
         * @see #getOffset()
932
         */
933
        public void setOffset(Point2D p) {
934 26225 jmvivo
                if (!offset.equals(p)){
935
                        this.updateDrawVersion();
936 26905 jmvivo
                        offset = p;
937 26225 jmvivo
                }
938 21200 vcaballero
        }
939
940
        /**
941
         * <p>Gets the offset.</p>
942
         * <p>The offset is the position where start drawing the map.</p>
943
         *
944
         * @return 2D point that represents the offset in pixels
945
         *
946
         * @see #setOffset(Point2D)
947
         */
948
        public Point2D getOffset() {
949
                return offset;
950
        }
951
952
        /**
953
         * <p>Sets the background color.</p>
954
         *
955
         * @param c the new background color
956
         *
957
         * @see #getBackColor()
958
         */
959
        public void setBackColor(Color c) {
960 26225 jmvivo
                if (!c.equals(this.backColor)){
961
                        this.updateDrawVersion();
962
                        backColor = c;
963
                        callColorChanged(backColor);
964
                }
965 21200 vcaballero
        }
966
967
        /**
968
         * <p>Gets the background color.</p>
969
         *
970
         * @return the background color of the view
971
         *
972
         * @see #setBackColor(Color)
973
         */
974
        public Color getBackColor() {
975
                return backColor;
976
        }
977
978
        /**
979
         * <p>Returns the extent currently covered by the view adjusted (scaled) to the image size aspect.</p>
980
         *
981
         * @return extent of the view adjusted to the image size aspect
982
         *
983
         * @see #setAdjustable(boolean)
984
         */
985 21531 vcaballero
        public Envelope getAdjustedExtent() {
986 21200 vcaballero
                if (cliprect!=null){
987 21531 vcaballero
                        Rectangle2D r= adjustedExtent.createIntersection(cliprect);
988 27414 jpiera
                        try {
989
                                return geomManager.createEnvelope(r.getX(),r.getY(),r.getMaxX(),r.getMaxY(), SUBTYPES.GEOM2D);
990
                        } catch (CreateEnvelopeException e) {
991
                                e.printStackTrace();
992
                                logger.error("Error adjusting the extent", e);
993
                        }
994 21200 vcaballero
                }
995 26905 jmvivo
                if (adjustedExtent!=null) {
996 27414 jpiera
                        try {
997
                                return geomManager.createEnvelope(adjustedExtent.getX(),adjustedExtent.getY(),adjustedExtent.getMaxX(),adjustedExtent.getMaxY(), SUBTYPES.GEOM2D);
998
                        } catch (CreateEnvelopeException e) {
999
                                e.printStackTrace();
1000
                                logger.error("Error adjusting the extent", e);
1001
                        }
1002 26905 jmvivo
                }
1003 21742 vcaballero
                return null;
1004 21200 vcaballero
        }
1005
1006
        /**
1007
         * <p>Returns the measurement unit of this view port used for measuring distances and displaying information.</p>
1008
         *
1009
         * @return the measurement unit of this view used for measuring distances and displaying information
1010
         *
1011
         * @see #setDistanceUnits(int)
1012
         */
1013
        public int getDistanceUnits() {
1014
                return distanceUnits;
1015
        }
1016
        /**
1017
         * <p>Returns the measurement unit of this view port used for measuring areas and displaying information.</p>
1018
         *
1019
         * @return the measurement unit of this view used for measuring areas and displaying information
1020
         *
1021
         * @see #setDistanceUnits(int)
1022
         */
1023
        public int getDistanceArea() {
1024
                return distanceArea;
1025
        }
1026
        /**
1027
         * <p>Sets the measurement unit of this view port used for measuring distances and displaying information.</p>
1028
         *
1029
         * @param distanceUnits the measurement unit of this view used for measuring distances and displaying information
1030
         *
1031
         * @see #getDistanceUnits()
1032
         */
1033
        public void setDistanceUnits(int distanceUnits) {
1034
                this.distanceUnits = distanceUnits;
1035
        }
1036
        /**
1037
         * <p>Sets the measurement unit of this view port used for measuring areas and displaying information.</p>
1038
         *
1039
         * @param distanceUnits the measurement unit of this view used for measuring areas and displaying information
1040
         *
1041
         * @see #getDistanceUnits()
1042
         */
1043
        public void setDistanceArea(int distanceArea) {
1044
                this.distanceArea = distanceArea;
1045
        }
1046
        /**
1047
         * <p>Gets the measurement unit used by this view port for the map.</p>
1048
         *
1049
         * @return Returns the current map measure unit
1050
         *
1051
         * @see #setMapUnits(int)
1052
         */
1053
        public int getMapUnits() {
1054
                return mapUnits;
1055
        }
1056
1057
        /**
1058
         * <p>Sets the measurement unit used by this view port for the map.</p>
1059
         *
1060
         * @param mapUnits the new map measure unit
1061
         *
1062
         * @see #getMapUnits()
1063
         */
1064
        public void setMapUnits(int mapUnits) {
1065
                this.mapUnits = mapUnits;
1066
        }
1067
1068
        /**
1069
         * <p>Gets the width in <i>screen coordinates</i> of the rectangle where the image is displayed.</p>
1070
         * <p>Used by {@linkplain #calculateAffineTransform()} to calculate:<br>
1071
           *
1072
         * <ul>
1073
         * <li>The new {@link #scale scale} .
1074
         * <li>The new {@link #adjustedExtent adjustableExtent} .
1075
         * <li>The new {@link #trans trans} .
1076
         * <li>The new real world coordinates equivalent to 1 pixel ({@link #dist1pixel dist1pixel}) .
1077
         * <li>The new real world coordinates equivalent to 3 pixels ({@link #dist3pixel dist3pixel}) .
1078
         * </ul>
1079
         * </p>
1080
         *
1081
         * @see #getImageHeight()
1082
         * @see #getImageSize()
1083
         * @see #setImageSize(Dimension)
1084
         */
1085
        public int getImageWidth() {
1086
                return imageSize.width;
1087
        }
1088
1089
        /**
1090
         * <p>Gets the height in <i>screen coordinates</i> of the rectangle where the image is displayed.</p>
1091
         * <p>Used by {@linkplain #calculateAffineTransform()} to calculate:<br>
1092
           *
1093
         * <ul>
1094
         * <li>The new {@link #scale scale} .
1095
         * <li>The new {@link #adjustedExtent adjustableExtent} .
1096
         * <li>The new {@link #trans trans} .
1097
         * <li>The new real world coordinates equivalent to 1 pixel ({@link #dist1pixel dist1pixel}) .
1098
         * <li>The new real world coordinates equivalent to 3 pixels ({@link #dist3pixel dist3pixel}) .
1099
         * </ul>
1100
         * </p>
1101
         *
1102
         * @see #getImageWidth()
1103
         * @see #getImageSize()
1104
         * @see #setImageSize(Dimension)
1105
         */
1106
        public int getImageHeight() {
1107
                return imageSize.height;
1108
        }
1109
1110
        /**
1111
         * <p>Gets the distance in <i>world coordinates</i> equivalent to 1 pixel in the view with the current extent.</p>
1112
         *
1113
         * @return the distance
1114
         *
1115
         * @see #setDist1pixel(double)
1116
         */
1117
        public double getDist1pixel() {
1118
                return dist1pixel;
1119
        }
1120
1121
        /**
1122
         * <p>Sets the distance in <i>world coordinates</i> equivalent to 1 pixel in the view with the current extent.</p>
1123
         *
1124
         * @param dist1pixel the distance
1125
         *
1126
         * @see #getDist1pixel()
1127
         */
1128
        public void setDist1pixel(double dist1pixel) {
1129 26225 jmvivo
                if (dist1pixel == this.dist1pixel){
1130
                        return;
1131
                }
1132
                        this.updateDrawVersion();
1133 21200 vcaballero
                this.dist1pixel = dist1pixel;
1134
        }
1135
1136
        /**
1137
         * <p>Gets the distance in <i>world coordinates</i> equivalent to 3 pixels in the view with the current extent.</p>
1138
         *
1139
         * @return the distance
1140
         *
1141
         * @see #setDist3pixel(double)
1142
         */
1143
        public double getDist3pixel() {
1144
                return dist3pixel;
1145
        }
1146
1147
        /**
1148
         * <p>Sets the distance in <i>world coordinates</i> equivalent to 3 pixels in the view with the current extent.</p>
1149
         *
1150
         * @param dist3pixel the distance
1151
         *
1152
         * @see #getDist3pixel()
1153
         */
1154
        public void setDist3pixel(double dist3pixel) {
1155 26225 jmvivo
                if (this.dist3pixel == dist3pixel){
1156
                        return;
1157
                }
1158
                this.updateDrawVersion();
1159 21200 vcaballero
                this.dist3pixel = dist3pixel;
1160
        }
1161
1162
        /**
1163
         * <p>Returns the last previous extents of this view port.</p>
1164
         *
1165
         * @return the last previous extents of this view port
1166
         *
1167
         * @see #setPreviousExtent()
1168
         */
1169
        public ExtentHistory getExtents() {
1170
                return extents;
1171
        }
1172
1173
        /**
1174
         * <p>Gets the projection used in this view port.</p>
1175
         *
1176
         * @return projection used in this view port
1177
         *
1178
         * @see #setProjection(IProjection)
1179
         */
1180
        public IProjection getProjection() {
1181
                return proj;
1182
        }
1183
1184
        /**
1185
         * <p>Sets the projection to this view port.</p>
1186
         *
1187
         * @param proj the new projection
1188
         *
1189
         * @see #getProjection()
1190
         */
1191
        public void setProjection(IProjection proj) {
1192
                if(this.proj == null || !this.proj.getAbrev().equals(proj.getAbrev())) {
1193 26225 jmvivo
                        this.updateDrawVersion();
1194 21200 vcaballero
                        this.proj = proj;
1195
                        callProjectionChanged(proj);
1196
                }
1197
        }
1198
1199
//  -----------------------------------------------------------------------------------------------------------
1200
//  NOTA PARA DESARROLLADORES SOBRE EL M?TODO "public void setAffineTransform(AffineTransform at)"
1201
//  ==============================================================================================
1202
//          Only used for print, should be removed, redefining the {@link RasterAdapter RasterAdapter} interface,
1203
//           allowing it to receive a {@link ViewPortData ViewPortData} .
1204
//  -----------------------------------------------------------------------------------------------------------
1205
1206
        /**
1207
         * <p>Sets only the affine transform to this view port, without updating dependent attributes.</p>
1208
         * <p><b><i>This method could be problematic!</i></b></p>
1209
         *
1210
         * @param at the affine transform to set
1211
         *
1212
         * @see #getAffineTransform()
1213
         * @see #calculateAffineTransform()
1214
         */
1215
        public void setAffineTransform(AffineTransform at)
1216
        {
1217
            this.trans = at;
1218
        }
1219
1220
        /**
1221
         * <p>Returns an XML entity that represents this view port instance:<br>
1222
         * <ul>
1223
         * <li>Properties:
1224
         *  <ul>
1225
         *  <li><i>className</i>: name of this class.
1226
         *  <li>If defined, the adjusted extent:
1227
         *   <ul>
1228
         *   <li><i>adjustedExtentX</i>: X coordinate of the adjusted extent.
1229
         *   <li><i>adjustedExtentY</i>: Y coordinate of the adjusted extent.
1230
         *   <li><i>adjustedExtentW</i>: width of the adjusted extent.
1231
         *   <li><i>adjustedExtentH</i>: height of the adjusted extent.
1232
         *   </ul>
1233
         *  <li>If defined, the background color:
1234
         *   <ul>
1235
         *   <li><i>backColor</i>: background color.
1236
         *   </ul>
1237
         *  <li>If defined, the clip:
1238
         *   <ul>
1239
         *   <li><i>clipX</i>: X coordinate of the clip.
1240
         *   <li><i>clipY</i>: Y coordinate of clip.
1241
         *   <li><i>clipW</i>: width of the clip.
1242
         *   <li><i>clipH</i>: height of the clip.
1243
         *   </ul>
1244
         *  <li><i>dist1pixel</i>: the distance in world coordinates equivalent to 1 pixel in the view.
1245
         *  <li><i>dist3pixel</i>: the distance in world coordinates equivalent to 3 pixels in the view.
1246
         *  <li><i>distanceUnits</i>: the distance measurement unit.
1247
         *  <li>If defined, the extent:
1248
         *   <ul>
1249
         *   <li><i>extentX</i>: X coordinate of the extent.
1250
         *   <li><i>extentY</i>: Y coordinate of the extent.
1251
         *   <li><i>extentW</i>: width of the extent.
1252
         *   <li><i>extentH</i>: height of the extent.
1253
         *   </ul>
1254
         *  <li><i>mapUnits</i>: the map measurement unit.
1255
         *  <li><i>offsetX</i>: X coordinate of the offset.
1256
         *  <li><i>offsetY</i>: Y coordinate of the offset.
1257
         *  <li>If defined, the projection:
1258
         *   <ul>
1259
         *   <li>If its defined, the projection:
1260
         *    <ul>
1261
         *     <li><i>proj</i>: the projection.</li>
1262
         *    </ul>
1263
         *   </ul>
1264
         *  <li><i>scale</i>: ratio between the size of <code>imageSize</code> and <code>extent</code>.
1265
         *  </ul>
1266
         * <li>Child branches:
1267
         *  <ul>
1268
         *  <li>XML entity of the internal {@link ExtentHistory ExtentHistory} .
1269
         *  </ul>
1270
         * </ul>
1271
         *
1272
         * @return the XML entity
1273
         *
1274
         * @see #createFromXML(XMLEntity)
1275
         */
1276
        public XMLEntity getXMLEntity() {
1277
                XMLEntity xml = new XMLEntity();
1278
                xml.putProperty("className",this.getClass().getName());
1279
1280
                if (adjustedExtent != null) {
1281
                        xml.putProperty("adjustedExtentX", adjustedExtent.getX());
1282
                        xml.putProperty("adjustedExtentY", adjustedExtent.getY());
1283
                        xml.putProperty("adjustedExtentW", adjustedExtent.getWidth());
1284
                        xml.putProperty("adjustedExtentH", adjustedExtent.getHeight());
1285
                }
1286
1287 26905 jmvivo
                if (backColor != null) {
1288
                        xml.putProperty("backColor", StringUtilities.color2String(backColor));
1289
                }
1290 21200 vcaballero
1291
                if (clip != null) {
1292
                        xml.putProperty("clipX", clip.getX());
1293
                        xml.putProperty("clipY", clip.getY());
1294
                        xml.putProperty("clipW", clip.getWidth());
1295
                        xml.putProperty("clipH", clip.getHeight());
1296
                }
1297
1298
                xml.putProperty("dist1pixel", dist1pixel);
1299
                xml.putProperty("dist3pixel", dist3pixel);
1300
                xml.putProperty("distanceUnits", distanceUnits);
1301
1302
                if (extent != null) {
1303
                        xml.putProperty("extentX", extent.getX());
1304
                        xml.putProperty("extentY", extent.getY());
1305
                        xml.putProperty("extentW", extent.getWidth());
1306
                        xml.putProperty("extentH", extent.getHeight());
1307
                }
1308
1309
                xml.addChild(extents.getXMLEntity());
1310
                xml.putProperty("mapUnits", mapUnits);
1311
                xml.putProperty("offsetX", offset.getX());
1312
                xml.putProperty("offsetY", offset.getY());
1313
1314
                if (proj != null) {
1315
                        xml.putProperty("proj", proj.getAbrev());
1316
                }
1317
1318
                xml.putProperty("scale", scale);
1319
1320
                return xml;
1321
        }
1322
1323
1324
        /**
1325
         * <p>Creates a new <code>ViewPort</code> from an XML entity.</p>
1326
         *
1327
         * @param xml an XML entity
1328
         *
1329
         * @return the new <code>ViewPort</code>
1330
         *
1331
         * @see #getXMLEntity()
1332
         */
1333
        public static ViewPort createFromXML(XMLEntity xml) {
1334
                ViewPort vp = new ViewPort(null);
1335
1336
                if (xml.contains("adjustedExtentX")) {
1337
                        vp.adjustedExtent = new Rectangle2D.Double(xml.getDoubleProperty(
1338
                                                "adjustedExtentX"),
1339
                                        xml.getDoubleProperty("adjustedExtentY"),
1340
                                        xml.getDoubleProperty("adjustedExtentW"),
1341
                                        xml.getDoubleProperty("adjustedExtentH"));
1342
                }
1343
1344
                if (xml.contains("backColor")) {
1345
                        vp.setBackColor(StringUtilities.string2Color(xml.getStringProperty(
1346
                                                "backColor")));
1347
                }else {
1348
                        vp.setBackColor(Color.white);
1349
                }
1350
1351
                if (xml.contains("clipX")) {
1352
                        vp.clip = new Rectangle2D.Double(xml.getDoubleProperty("clipX"),
1353
                                        xml.getDoubleProperty("clipY"),
1354
                                        xml.getDoubleProperty("clipW"),
1355
                                        xml.getDoubleProperty("clipH"));
1356
                }
1357
1358
                vp.setDist1pixel(xml.getDoubleProperty("dist1pixel"));
1359
                vp.setDist3pixel(xml.getDoubleProperty("dist3pixel"));
1360
                vp.setDistanceUnits(xml.getIntProperty("distanceUnits"));
1361
                if (xml.contains("distanceArea")){
1362
                        vp.setDistanceArea(xml.getIntProperty("distanceArea"));
1363
                }else{
1364
                        vp.setDistanceArea(xml.getIntProperty("distanceUnits"));
1365
                }
1366
                vp.extents = ExtentHistory.createFromXML(xml.getChild(0));
1367
1368
                if (xml.contains("extentX")) {
1369 21426 vcaballero
                        double x=xml.getDoubleProperty("extentX");
1370
                        double y=xml.getDoubleProperty("extentY");
1371 27414 jpiera
                        try {
1372
                                vp.setEnvelope(geomManager.createEnvelope(x,y,
1373
                                                x+xml.getDoubleProperty("extentW"),y+xml.getDoubleProperty("extentH"), SUBTYPES.GEOM2D));
1374
                        } catch (CreateEnvelopeException e) {
1375
                                e.printStackTrace();
1376
                                logger.error("Error setting the extent", e);
1377
                        }
1378 21200 vcaballero
1379
                        //Calcula la transformaci?n af?n
1380
                        vp.calculateAffineTransform();
1381
1382
                        // Lanzamos los eventos de extent cambiado
1383
                        // vp.callExtentListeners(vp.adjustedExtent);
1384
                }
1385
1386
                vp.setMapUnits(xml.getIntProperty("mapUnits"));
1387
                vp.setOffset(new Point2D.Double(xml.getDoubleProperty("offsetX"),
1388
                                xml.getDoubleProperty("offsetY")));
1389
1390
                if (xml.contains("proj")) {
1391
                        vp.proj = CRSFactory.getCRS(xml.getStringProperty("proj"));
1392
                }
1393
1394
                //vp.setScale(xml.getDoubleProperty("scale"));
1395
                vp.refreshExtent();
1396
                return vp;
1397
        }
1398
1399
        /**
1400
         * <p>Fast clone implementation: creates and returns a clone of this view port using XML entities.</p>
1401
         * <p>Isn't a <i>deepclone</i> to avoid unnecessary memory consumption.</p>
1402
         *
1403
         * @return the new view port
1404
         *
1405
         * @see #createFromXML(XMLEntity)
1406
         */
1407
        public ViewPort cloneViewPort() {
1408
                return createFromXML(getXMLEntity());
1409
        }
1410
1411
        /**
1412
         * <p>Returns a <code>String</code> representation of the main values of this view port: <code>{@linkplain #extent}</code>,
1413
         *  <code>{@linkplain #adjustedExtent}</code>, <code>{@linkplain #imageSize}</code>, <code>{@linkplain #scale}</code>, and <code>{@linkplain #trans}</code>.</p>
1414
         *
1415
         * @return a <code>string</code> representation of the main values of this view port
1416
         */
1417
        public String toString() {
1418
1419
                String str;
1420
                str = "Datos del viewPort:\nExtent=" + extent + "\nadjustedExtent=" +
1421
                        adjustedExtent + "\nimageSize=" + imageSize + "\nescale=" + scale +
1422
                        "\ntrans=" + trans;
1423
1424
                return str;
1425
        }
1426
1427
        /**
1428
         * <p>Sets the position and size of the clipping rectangle.</p>
1429
         *
1430
         * @param rectView the clipping rectangle to set
1431
         */
1432
        public void setClipRect(Rectangle2D rectView) {
1433 26225 jmvivo
                this.updateDrawVersion();
1434 21200 vcaballero
                cliprect=rectView;
1435
        }
1436 26905 jmvivo
1437 21200 vcaballero
        /**
1438
         * <p>Converts and returns the {@link Rectangle2D Rectangle2D}, that is in <i>map
1439
         *  coordinates</i> to <i>screen coordinates</i> (pixels) using an <i>inverse transform</i> with
1440
         *  the transformation affine information in the {@link #trans #trans} attribute.</p>
1441
         *
1442
         * @param r the 2D rectangle in <i>map coordinates</i>
1443
         * @return 2D rectangle equivalent in <i>screen coordinates</i> (pixels)
1444
         *
1445
         * @see #toMapRectangle(Rectangle2D)
1446
         * @see #fromMapDistance(double)
1447
         * @see #fromMapPoint(Point2D)
1448
         */
1449
        public Rectangle2D fromMapRectangle(Rectangle2D r) {
1450
                Rectangle2D rect=new Rectangle2D.Double();
1451
                Point2D p1=fromMapPoint((int)r.getX(),(int)r.getY());
1452
                Point2D p2=fromMapPoint((int)r.getMaxX(),(int)r.getMaxY());
1453
                rect.setFrameFromDiagonal(p1,p2);
1454
                return rect;
1455
        }
1456
1457
        /**
1458
         * <p>Recalculates the current <code>{@linkplain #extent}</code> using an scale. It's necessary execute {@linkplain #refreshExtent()} after.</p>
1459
         *
1460
         * @param s the scale to set
1461
         *
1462
         * @deprecated since 07/09/07, use {@linkplain MapContext#setScaleView(long)}
1463
         */
1464
        public void setScale(long s){
1465
                double x=extent.getX();
1466
                double y=extent.getY();
1467
                double escalaX = imageSize.getWidth() / extent.getWidth();
1468
                double w=imageSize.getWidth() / s;
1469
                double h=imageSize.getHeight() / s;
1470
                double difw = escalaX/s;
1471
1472
                double x1 = (-x * difw) -
1473
            x+
1474
            extent.getWidth()/2;
1475
        double y1 = (-y * difw) -
1476
            y +
1477
            extent.getHeight()/2;
1478
        double w1=extent.getWidth()*difw;
1479
        double h1=extent.getHeight()*difw;
1480
                extent.setRect(-x1,-y1,w1,h1);
1481
        }
1482 26225 jmvivo
1483
1484
        public long getDrawVersion() {
1485
                return this.drawVersion;
1486
        }
1487
1488
        protected void updateDrawVersion(){
1489
                this.drawVersion++;
1490
        }
1491
1492 21200 vcaballero
}