Statistics
| Revision:

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

History | View | Annotate | Download (46 KB)

1
/* 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
import java.awt.Toolkit;
47
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
import org.cresques.cts.gt2.CSUTM;
56
import org.gvsig.fmap.crs.CRSFactory;
57
import org.gvsig.fmap.geom.primitive.Envelope;
58
import org.gvsig.fmap.geom.util.UtilFunctions;
59
import org.gvsig.fmap.mapcontext.events.ColorEvent;
60
import org.gvsig.fmap.mapcontext.events.ExtentEvent;
61
import org.gvsig.fmap.mapcontext.events.ProjectionEvent;
62
import org.gvsig.fmap.mapcontext.events.listeners.ViewPortListener;
63

    
64
import com.iver.utiles.StringUtilities;
65
import com.iver.utiles.XMLEntity;
66

    
67

    
68
/**
69
 * <p><code>ViewPort</code> class represents the logic needed to transform a rectangular area of a map
70
 *  to the available area in screen to display it.</p>
71
 *
72
 * <p>Includes an affine transformation, between the rectangular area selected of the external map, in its own
73
 *  <i>map coordinates</i>, to the rectangular area available of a view in <i>screen coordinates</i>.</p>
74
 *
75
 * <p>Elements:
76
 * <ul>
77
 * <li><i>extent</i>: the area selected of the map, in <i>map coordinates</i>.
78
 * <li><i>imageSize</i>: width and height in pixels (<i>screen coordinates</i>) of the area available
79
 *  in screen to display the area selected of the map.
80
 * <li><i>adjustedExtent</i>: the area selected must be an scale of <i>imageSize</i>.<br>This implies adapt the
81
 *  extent, preserving and centering it, and adding around the needed area to fill all the image size. That
82
 *  added area will be extracted from the original map, wherever exists, and filled with the background color
83
 *  wherever not.
84
 * <li><i>scale</i>: the scale between the adjusted extent and the image size.
85
 * <li><i>backColor</i>: the default background color in the view, if there is no map.
86
 * <li><i>trans</i>: the affine transformation.
87
 * <li><i>proj</i>: map projection used in this view.
88
 * <li><i>distanceUnits</i>: distance measurement units, of data in screen.
89
 * <li><i>mapUnits</i>: measurement units, of data in map.
90
 * <li><i>extents</i>: an {@link ExtentHistory ExtentHistory} with the last previous extents.
91
 * <li><i>offset</i>: position in pixels of the available rectangular area, where start drawing the map.
92
 * <li><i>dist1pixel</i>: the distance in <i>world coordinates</i> equivalent to 1 pixel in the view with the
93
 *  current extent.
94
 * <li><i>dist3pixel</i>: the distance in <i>world coordinates</i> equivalent to 3 pixels in the view with the
95
 *  current extent.
96
 * <li><i>listeners</i>: list with the {@link ViewPortListener ViewPortListener} registered.
97
 * </ul>
98
 * </p>
99
 *
100
 * @author Vicente Caballero Navarro
101
 */
102
public class ViewPort {
103
//        /**
104
//         * <p>Metric unit or length equal to 1000 meters.</p>
105
//         */
106
//        public static int KILOMETROS = 0;
107
//
108
//        /**
109
//         * <p>The base unit of length in the International System of Units that is equal to the distance
110
//         *  traveled by light in a vacuum in {frac;1;299,792,458} second or to about 39.37 inches.</p>
111
//         */
112
//        public static int METROS = 1;
113
//
114
//        /**
115
//         * <p>Metric unit or length equal to 0'01 meters.</p>
116
//         */
117
//        public static int CENTIMETRO = 2;
118
//
119
//        /**
120
//         * <p>Metric unit or length equal to 0'001 meters.</p>
121
//         */
122
//        public static int MILIMETRO = 3;
123
//
124
//        /**
125
//         * <p>The international statute mile by international agreement. It is defined to be precisely
126
//         *  1,760 international yards (by definition, 0.9144 m each) and is therefore exactly 1,609.344
127
//         *  metres (1.609344 km).</p>
128
//         */
129
//        public static int MILLAS = 4;
130
//
131
//        /**
132
//         * <p>Unit of length equal in the United States to 0.9144 meter.</p>
133
//         */
134
//        public static int YARDAS = 5;
135
//
136
//        /**
137
//         * <p>Any of various units of length based on the length of the human foot; especially :
138
//         *  a unit equal to 1/3 yard and comprising 12 inches.</p>
139
//         */
140
//        public static int PIES = 6;
141
//
142
//        /**
143
//         * <p>Unit of length equal to 1/36 yard.</p>
144
//         */
145
//        public static int PULGADAS = 7;
146
//
147
//        /**
148
//         * <p>Grades according the current projection.</p>
149
//         */
150
//        public static int GRADOS = 8;
151

    
152
        /**
153
         * <p>Screen resolution in <i>dots-per-inch</i>. Useful to calculate the geographic scale of the view.</p>
154
         *
155
         * @see Toolkit#getScreenResolution()
156
         * @see #getScale()
157
         */
158
        private static int dpi = java.awt.Toolkit.getDefaultToolkit()
159
                                                                                         .getScreenResolution();
160

    
161
        /**
162
         * <p>Area selected by user using some tool.</p>
163
         *
164
         * <p>When the zoom changes (for instance when using the zoom in or zoom out tools,
165
         *  but also zooming to a selected feature or shape) the extent that covers that
166
         *  area is the value returned by this method. It is not the actual area shown
167
         *  in the view because it does not care about the aspect ratio of the available
168
         *  area. However, any part of the real world contained in this extent is shown
169
         *  in the view.
170
         * </p>
171
         * <p>
172
         * Probably this is not what you are looking for. If you are looking for
173
         * the complete extent currently shown, you must use {@linkplain #getAdjustedExtent()} method
174
         * which returns the extent that contains this one but regarding the current
175
         * view's aspect ratio.
176
         * </p>
177
         *
178
         * @see #getExtent()
179
         * @see #setEnvelope(Envelope)
180
         */
181
        protected Rectangle2D extent;
182

    
183
        /**
184
         * <p>Location and dimensions of the extent adjusted to the image size.</p>
185
         *
186
         * @see #getAdjustedExtent()
187
         */
188
        protected Rectangle2D adjustedExtent;
189

    
190
        /**
191
         * Draw version of the context. It's used for know when de componend has
192
         * changed any visualization property
193
         *
194
         *  @see getDrawVersion
195
         *  @see updateDrawVersion
196
         */
197
        private long drawVersion= 0L;
198

    
199
        /**
200
         * <p>History with the last extents of the view.</p>
201
         *
202
         * @see #setPreviousExtent()
203
         * @see #getExtents()
204
         */
205
        protected ExtentHistory extents = new ExtentHistory();
206

    
207
        /**
208
         * <p>Size in <i>screen coordinates</i> of the rectangle where the image is displayed.</p>
209
         * <p>Used by {@linkplain #calculateAffineTransform()} to calculate:<br>
210
           *
211
         * <ul>
212
         * <li>The new {@link #scale scale} .
213
         * <li>The new {@link #adjustedExtent adjustableExtent} .
214
         * <li>The new {@link #trans trans} .
215
         * <li>The new real world coordinates equivalent to 1 pixel ({@link #dist1pixel dist1pixel}) .
216
         * <li>The new real world coordinates equivalent to 3 pixels ({@link #dist3pixel dist3pixel}) .
217
         * </ul>
218
         * </p>
219
         *
220
         * @see #getImageSize()
221
         * @see #getImageHeight()
222
         * @see #getImageWidth()
223
         * @see #setImageSize(Dimension)
224
         */
225
        private Dimension imageSize;
226

    
227
        /**
228
         * <p>the affine transformation between the {@link #extent extent} in <i>map 2D coordinates</i> to
229
         *  the image area in the screen, in <i>screen 2D coordinates</i> (pixels).</p>
230
         *
231
         * @see AffineTransform
232
         *
233
         * @see #getAffineTransform()
234
         * @see #setAffineTransform(AffineTransform)
235
         * @see #calculateAffineTransform()
236
         */
237
        private AffineTransform trans = new AffineTransform();
238

    
239
        /**
240
         * <p>Measurement unit used for measuring distances and displaying information.</p>
241
         *
242
         * @see #getDistanceUnits()
243
         * @see #setDistanceUnits(int)
244
         */
245
        private int distanceUnits = 1;
246
        /**
247
         * <p>Measurement unit used for measuring areas and displaying information.</p>
248
         *
249
         * @see #getDistanceArea()
250
         * @see #setDistanceArea(int)
251
         */
252
        private int distanceArea = 1;
253
        /**
254
         * <p>Measurement unit used by this view port for the map.</p>
255
         *
256
         * @see #getMapUnits()
257
         * @see #setMapUnits(int)
258
         */
259
        private int mapUnits = 1;
260

    
261
        /**
262
         * <p>Array with the {@link ViewPortListener ViewPortListener}s registered to this view port.</p>
263
         *
264
         * @see #addViewPortListener(ViewPortListener)
265
         * @see #removeViewPortListener(ViewPortListener)
266
         */
267
        private ArrayList listeners = new ArrayList();
268

    
269
        /**
270
         * <p>The offset is the position where start drawing the map.</p>
271
         * <p>The offset of a <a href="http://www.gvsig.gva.es/">gvSIG</a>'s <i>View</i> is
272
         * always (0, 0) because the drawing area fits with the full window area. But in
273
         * a <a href="http://www.gvsig.gva.es/">gvSIG</a>'s <i>Layout</i> it's up to the place where
274
         * the <code>FFrameView</code> is located.</p>
275
         *
276
         * @see #getOffset()
277
         * @see #setOffset(Point2D)
278
         */
279
        private Point2D offset = new Point2D.Double(0, 0);
280

    
281
        /**
282
         * <p>Clipping area.</p>
283
         */
284
        private Rectangle2D clip;
285

    
286
        /**
287
         * <p>Background color of this view.</p>
288
         *
289
         * @see #getBackColor()
290
         * @see #setBackColor(Color)
291
         */
292
        private Color backColor = null; //Color.WHITE;
293

    
294
        /**
295
         * <p>Information about the map projection used in this view.</p>
296
         *
297
         * @see #getProjection()
298
         * @see #setProjection(IProjection)
299
         */
300
        private IProjection proj;
301

    
302
        /**
303
         * <p>Represents the distance in <i>world coordinates</i> equivalent to 1 pixel in the view with the current extent.</p>
304
         *
305
         * @see #getDist1pixel()
306
         * @see #setDist1pixel(double)
307
         */
308
        private double dist1pixel;
309

    
310
        /**
311
         * <p>Represents the distance in <i>world coordinates</i> equivalent to 3 pixels in the view with the current extent.</p>
312
         *
313
         * @see #getDist3pixel()
314
         * @see #setDist3pixel(double)
315
         */
316
        private double dist3pixel;
317

    
318
        /**
319
         * <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>
320
         */
321
        private double scale;
322

    
323
        /**
324
         * <p>Clipping area.</p>
325
         *
326
         * @see #setClipRect(Rectangle2D)
327
         */
328
        private Rectangle2D cliprect;
329

    
330
        /**
331
         * <p>Enables or disables the <i>"adjustable extent"</i> mode.</p>
332
         *
333
         * <p>
334
         * When calculates the affine transform, if
335
         * <ul>
336
         * <li><i>enabled</i>: the new <code>adjustedExtent</code> will have the (X, Y) coordinates of the <code>extent</code> and
337
         *  an area that will be an scale of the image size. That area will have different
338
         *  height or width (not both) of the extent according the least ratio (height or width) in <pre>image.size/extent.size"</pre>.
339
         * <li><i>disabled</i>: the new <code>adjustedExtent</code> will be like <code>extent</code>.
340
         * </ul>
341
         * </p>
342
         *
343
         * @see #setAdjustable(boolean)
344
         */
345
        private boolean adjustableExtent=true;
346

    
347
        /**
348
         * <p>Creates a new view port with the information of the projection in <code>proj</code> argument, and
349
         *  default configuration:</p>
350
         * <p>
351
         * <ul>
352
         *  <li><i><code>distanceUnits</code></i> = meters
353
         *  <li><i><code>mapUnits</code></i> = meters
354
         *  <li><i><code>backColor</code></i> = <i>undefined</i>
355
         *  <li><i><code>offset</code></i> = <code>new Point2D.Double(0, 0);</code>
356
         * </ul>
357
         * </p>
358
         *
359
         * @param proj information of the projection for this view port
360
         */
361
        public ViewPort(IProjection proj) {
362
                // Por defecto
363
                this.proj = proj;
364
        }
365

    
366
        /**
367
         * <p>Changes the status of the <i>"adjustable extent"</i> option to enabled or disabled.</p>
368
         *
369
         * <p>If view port isn't adjustable, won't bear in mind the aspect ratio of the available rectangular area to
370
         *  calculate the affine transform from the original map in real coordinates. (Won't scale the image to adapt
371
         *  it to the available rectangular area).</p>
372
         *
373
         * @param boolean the boolean to be set
374
         */
375
        public void setAdjustable(boolean adjustable) {
376
                if (adjustable == adjustableExtent){
377
                        return;
378
                }
379
                adjustableExtent = adjustable;
380
                this.updateDrawVersion();
381
        }
382

    
383
        /**
384
         * <p>Appends the specified {@link ViewPortListener ViewPortListener} listener if weren't.</p>
385
         *
386
         * @param arg0 the listener to add
387
         *
388
         * @return <code>true</code> if has been added successfully
389
         *
390
         * @see #removeViewPortListener(ViewPortListener)
391
         */
392
        public boolean addViewPortListener(ViewPortListener arg0) {
393
                if (!listeners.contains(arg0)) {
394
                        return listeners.add(arg0);
395
                }
396
                return false;
397
        }
398

    
399
        /**
400
          * <p>Removes the specified {@link ViewPortListener ViewPortListener} listener, if existed.</p>
401
         *
402
         * @param arg0 the listener to remove
403
         *
404
         * @return <code>true</code> if the contained the specified listener.
405
         *
406
         * @see #addViewPortListener(ViewPortListener)
407
         */
408
        public boolean removeViewPortListener(ViewPortListener arg0) {
409
                return listeners.remove(arg0);
410
        }
411

    
412
        /**
413
         * <p>Converts and returns the distance <code>d</code>, that is in <i>map
414
         *  coordinates</i> to <i>screen coordinates</i> using a <i>delta transform</i> with
415
         *  the transformation affine information in the {@link #trans #trans} attribute.</p>
416
         *
417
         * @param d distance in <i>map coordinates</i>
418
         *
419
         * @return distance equivalent in <i>screen coordinates</i>
420
         *
421
         * @see #toMapDistance(int)
422
         * @see AffineTransform#deltaTransform(Point2D, Point2D)S
423
         */
424
        public int fromMapDistance(double d) {
425
                Point2D.Double pWorld = new Point2D.Double(1, 1);
426
                Point2D.Double pScreen = new Point2D.Double();
427

    
428
                try {
429
                        trans.deltaTransform(pWorld, pScreen);
430
                } catch (Exception e) {
431
                        System.err.print(e.getMessage());
432
                }
433

    
434
                return (int) (d * pScreen.x);
435
        }
436

    
437
        /**
438
         * <p>Converts and returns the 2D point <code>(x,y)</code>, that is in <i>map
439
         *  coordinates</i> to <i>screen coordinates</i> (pixels) using
440
         *  the affine transformation in the {@link #trans #trans} attribute.</p>
441
         *
442
         * @param x the <code>x</code> <i>map coordinate</i> of a 2D point
443
         * @param y the <code>y</code> <i>map coordinate</i> of a 2D point
444
         *
445
         * @return 2D point equivalent in <i>screen coordinates</i> (pixels)
446
         *
447
         * @see #fromMapPoint(Point2D)
448
         * @see AffineTransform#transform(Point2D, Point2D)
449
         */
450
        public Point2D fromMapPoint(double x, double y) {
451
                Point2D.Double pWorld = new Point2D.Double(x, y);
452
                Point2D.Double pScreen = new Point2D.Double();
453

    
454
                try {
455
                        trans.transform(pWorld, pScreen);
456
                } catch (Exception e) {
457
                        System.err.print(e.getMessage());
458
                }
459

    
460
                return pScreen;
461
        }
462

    
463
        /**
464
         * <p>Converts and returns the 2D point argument, that is in <i>map
465
         *  coordinates</i> to <i>screen coordinates</i> (pixels) using
466
         *  the affine transformation in the {@link #trans #trans} attribute.</p>
467
         *
468
         * @param point the 2D point in <i>map coordinates</i>
469
         *
470
         * @return 2D point equivalent in <i>screen coordinates</i> (pixels)
471
         *
472
         * @see #toMapPoint(Point2D)
473
         * @see #fromMapPoint(double, double)
474
         */
475
        public Point2D fromMapPoint(Point2D point) {
476
                return fromMapPoint(point.getX(), point.getY());
477
        }
478

    
479
        /**
480
         * <p>Converts and returns the 2D point <code>(x,y)</code>, that is in <i>screen coordinates</i>
481
         *  (pixels) to <i>map coordinates</i> using
482
         *  the affine transformation in the {@link #trans #trans} attribute.</p>
483
         *
484
         * @param x the <code>x</code> <i>screen coordinate</i> of a 2D point
485
         * @param y the <code>y</code> <i>screen coordinate</i> of a 2D point
486
         *
487
         * @return 2D point equivalent in <i>map coordinates</i>
488
         *
489
         * @see #toMapPoint(Point2D)
490
         * @see #fromMapPoint(double, double)
491
         */
492
        public Point2D toMapPoint(int x, int y) {
493
                Point pScreen = new Point(x, y);
494

    
495
                return toMapPoint(pScreen);
496
        }
497

    
498
        /**
499
         * <p>Converts and returns the {@link Rectangle2D Rectangle2D}, that is in <i>screen
500
         *  coordinates</i> (pixels) to <i>map coordinates</i> using {@linkplain #toMapDistance(int)},
501
         *  and {@linkplain #toMapPoint(int, int)}.</p>
502
         *
503
         * @param r the 2D rectangle in <i>screen coordinates</i> (pixels)
504
         * @return 2D rectangle equivalent in <i>map coordinates</i>
505
         *
506
         * @see #fromMapRectangle(Rectangle2D)
507
         * @see #toMapDistance(int)
508
         * @see #toMapPoint(int, int)
509
         */
510
        public Rectangle2D toMapRectangle(Rectangle2D r){
511
                Rectangle2D rect=new Rectangle2D.Double();
512
                Point2D p1=toMapPoint((int)r.getX(),(int)r.getY());
513
                Point2D p2=toMapPoint((int)r.getMaxX(),(int)r.getMaxY());
514
                rect.setFrameFromDiagonal(p1,p2);
515
                return rect;
516
        }
517

    
518
        /**
519
         * <p>Converts and returns the distance <code>d</code>, that is in <i>screen
520
         *  coordinates</i> to <i>map coordinates</i> using the transformation affine information
521
         *  in the {@link #trans #trans} attribute.</p>
522
         *
523
         * @param d distance in pixels
524
         *
525
         * @return distance equivalent in <i>map coordinates</i>
526
         *
527
         * @see #fromMapDistance(double)
528
         * @see AffineTransform
529
         */
530
        public double toMapDistance(int d) {
531
                double dist = d / trans.getScaleX();
532

    
533
                return dist;
534
        }
535

    
536
        /**
537
         * <p>Converts and returns the 2D point argument, that is in <i>screen coordinates</i>
538
         *  (pixels) to <i>map coordinates</i> using the
539
         *  inverse affine transformation of the {@link #trans #trans} attribute.</p>
540
         *
541
         * @param pScreen the 2D point in <i>screen coordinates</i> (pixels)
542
         *
543
         * @return 2D point equivalent in <i>map coordinates</i>
544
         *
545
         * @see #toMapPoint(int, int)
546
         * @see AffineTransform#createInverse()
547
         * @see AffineTransform#transform(Point2D, Point2D)
548
         */
549
        public Point2D toMapPoint(Point2D pScreen) {
550
                Point2D.Double pWorld = new Point2D.Double();
551
                AffineTransform at;
552

    
553
                try {
554
                        at = trans.createInverse();
555
                        at.transform(pScreen, pWorld);
556
                } catch (NoninvertibleTransformException e) {
557
                        throw new RuntimeException("Non invertible transform Exception",e);
558
                }
559

    
560
                return pWorld;
561
        }
562

    
563
        /**
564
         * <p>Returns the real distance (in <i>world coordinates</i>) at the graphic layers of two 2D points
565
         *  (in <i>map coordinates</i>) of the plane where is selected the <i>extent</i>.</p>
566
         * <p>If the projection of this view is UTM, considers the Earth curvature.</p>
567
         *
568
         * @param pt1 a 2D point in <i>map coordinates</i>
569
         * @param pt2 another 2D point in <i>map coordinates</i>
570
         *
571
         * @return the distance in meters between the two points 2D
572
         *
573
         * @see GeoCalc#distanceVincenty(Point2D, Point2D)
574
         */
575
        public double distanceWorld(Point2D pt1, Point2D pt2) {
576
                double dist = -1;
577
                dist = pt1.distance(pt2);
578

    
579
                if ((proj != null) && !(proj instanceof CSUTM)) {
580
                        dist = new GeoCalc(proj).distanceVincenty(proj.toGeo(pt1),
581
                                        proj.toGeo(pt2));
582
                        return dist;
583
                }
584
                return (dist*MapContext.getDistanceTrans2Meter()[getMapUnits()]);
585
        }
586

    
587
        /**
588
         * <p>Sets as extent and adjusted extent of this view port, the previous. Recalculating
589
         *  its parameters.</p>
590
         *
591
         * @see #getExtents()
592
         * @see #calculateAffineTransform()
593
         */
594
        public void setPreviousExtent() {
595
                this.updateDrawVersion();
596
                extent = extents.removePrev();
597

    
598
                //Calcula la transformaci?n af?n
599
                calculateAffineTransform();
600

    
601
                // Lanzamos los eventos de extent cambiado
602
                callExtentChanged(getAdjustedExtent());
603
        }
604

    
605
        /**
606
         * <p>Gets the area selected by user using some tool.</p>
607
         *
608
         * <p>When the zoom changes (for instance using the <i>zoom in</i> or <i>zoom out</i> tools,
609
         *  but also zooming to a selected feature or shape) the extent that covers that
610
         *  area is the value returned by this method. It is not the actual area shown
611
         *  because it doesn't care about the aspect ratio of the image size of the view. However, any
612
         *  part of the real world contained in this extent is shown in the view.</p>
613
         *
614
         * <p>If you are looking for the complete extent currently shown, you must use the
615
         *  {@linkplain #getAdjustedExtent()} method.</p>
616
         *
617
         * @return the current extent
618
         *
619
         * @see #setEnvelope(Envelope)
620
         * @see #getAdjustedExtent()
621
         * @see #setPreviousExtent()
622
         * @see #getExtents()
623
         */
624
        public Rectangle2D getExtent() {
625
                return extent;
626
        }
627

    
628
        /**
629
         * <p>Changes the <i>extent</i> and <i>adjusted extent</i> of this view port:<br>
630
         * <ul>
631
         * <li>Stores the previous extent.
632
         * <li>Calculates the new extent using <code>r</code>:
633
         * <pre>extent = new Rectangle2D.Double(r.getMinX() - 0.1, r.getMinY() - 0.1, r.getWidth() + 0.2, r.getHeight() + 0.2);</pre>
634
         * <li>Executes {@linkplain #calculateAffineTransform()}: getting the new scale, adjusted extent, affine transformation between
635
         *  map and screen coordinates, the real world coordinates equivalent to 1 pixel, and the real world coordinates equivalent to 3 pixels.
636
         * <li>Notifies all {@link ViewPortListener ViewPortListener} registered that the extent has changed.
637
         * </ul>
638
         * </p>
639
         *
640
         * @param r the new extent
641
         *
642
         * @see #getExtent()
643
         * @see #getExtents()
644
         * @see #calculateAffineTransform()
645
         * @see #setPreviousExtent()
646
         */
647
        public void setEnvelope(Envelope r) {
648
                Rectangle2D newExtent=null;
649
                //Esto comprueba que el extent no es de anchura o altura = "0"
650
                //y si es as? lo redimensiona.
651
                if (r!=null) {
652
                        if ((r.getMaximum(0) - r.getMinimum(0) == 0)
653
                                        || (r.getMaximum(1) - r.getMinimum(1) == 0)) {
654
                                newExtent = new Rectangle2D.Double(r.getMinimum(0) - 0.1,
655
                                        r.getMinimum(1) - 0.1, r.getMaximum(0)-r.getMinimum(0) + 0.2, r.getMaximum(1)-r.getMinimum(1) + 0.2);
656
                        } else {
657
                                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)));
658
                        }
659
                }
660

    
661
                if (this.extent != null && this.extent.equals(newExtent)){
662
                        return;
663
                }
664
                if (extent != null) {
665
                        extents.put(extent);
666
                }
667
                this.updateDrawVersion();
668
                this.extent = newExtent;
669

    
670
                //Calcula la transformaci?n af?n
671
                calculateAffineTransform();
672

    
673
                // Lanzamos los eventos de extent cambiado
674
                callExtentChanged(getAdjustedExtent());
675
        }
676

    
677
        /**
678
         * <p>Changes the <i>extent</i> and <i>adjusted extent</i> of this view port:<br>
679
         * <ul>
680
         * <li>Executes {@linkplain #calculateAffineTransform()}: getting the new scale, adjusted extent, affine transformation between
681
         *  map and screen coordinates, the real world coordinates equivalent to 1 pixel, and the real world coordinates equivalent to 3 pixels.
682
         * <li>Notifies to all {@link ViewPortListener ViewPortListener} registered that the extent has changed.
683
         * </ul>
684
         * </p>
685
         *
686
         * @see #setEnvelope(Envelope)
687
         * @see #calculateAffineTransform()
688
         */
689
        public void refreshExtent() {
690
                //this.scale = scale;
691

    
692
                //Calcula la transformaci?n af?n
693
                calculateAffineTransform();
694

    
695
                // Lanzamos los eventos de extent cambiado
696
                callExtentChanged(getAdjustedExtent());
697
        }
698

    
699
        /**
700
         * <p>Calculates and returns using the current projection of this view port, the scale that
701
         *  is the extent in <i>screen coordinates</i> from the image in <i>map coordinates</i>.</p>
702
         *
703
         * @return the scale <i>extent / image size</i> projected by this view port
704
         *
705
         * @deprecated since 07/09/07, use {@linkplain MapContext#getScaleView()}
706
         */
707
        public double getScale() {
708
                return proj.getScale(extent.getMinX(), extent.getMaxX(),
709
                        imageSize.getWidth(), dpi);
710
        }
711

    
712
        /**
713
         * <p>Affine transformation between <i>map 2D coordinates</i> to <i>screen 2D coordinates</i> (pixels),
714
         * preserving the "straightness" and "parallelism" of the lines.</p>
715
         *
716
         * @return the affine transformation
717
         *
718
         * @see #setAffineTransform(AffineTransform)
719
         * @see #calculateAffineTransform()
720
         */
721
        public AffineTransform getAffineTransform() {
722
                return trans;
723
        }
724

    
725
        /**
726
         * <p>Returns the size of the image projected.</p>
727
         *
728
         * @return the image size
729
         *
730
         * @see #setImageSize(Dimension)
731
         * @see #getImageHeight()
732
         * @see #getImageWidth()
733
         */
734
        public Dimension getImageSize() {
735
                return imageSize;
736
        }
737

    
738
        /**
739
         * <p>Sets the size of the image projected, recalculating the parameters of this view port.</p>
740
         *
741
         * @param imageSize the image size
742
         *
743
         * @see #getImageSize()
744
         * @see #calculateAffineTransform()
745
         */
746
        public void setImageSize(Dimension imageSize) {
747

    
748
                if (this.imageSize == null  || (!this.imageSize.equals(imageSize))){
749
                                this.updateDrawVersion();
750
                                this.imageSize = imageSize;
751
                                calculateAffineTransform();
752
                }
753
        }
754

    
755
        /**
756
         * <p>Notifies to all view port listeners registered, that the adjusted extent of this view port
757
         *  has changed.</p>
758
         *
759
         * @param newRect the new adjusted extend
760
         *
761
         * @see #refreshExtent()
762
         * @see #setEnvelope(Envelope)
763
         * @see #setPreviousExtent()
764
         * @see ExtentEvent
765
         * @see ViewPortListener
766
         */
767
        protected void callExtentChanged(Envelope newRect) {
768
                ExtentEvent ev = ExtentEvent.createExtentEvent(newRect);
769

    
770
                for (int i = 0; i < listeners.size(); i++) {
771
                        ViewPortListener listener = (ViewPortListener) listeners.get(i);
772
                        listener.extentChanged(ev);
773
                }
774
        }
775

    
776
        /**
777
         * <p>Notifies to all view port listeners registered, that the background color of this view port
778
         *  has changed.</p>
779
         *
780
         * @param c the new background color
781
         *
782
         * @see #setBackColor(Color)
783
         * @see ColorEvent
784
         * @see ViewPortListener
785
         */
786
        private void callColorChanged(Color c) {
787
                ColorEvent ce = ColorEvent.createColorEvent(c);
788

    
789
                for (int i = 0; i < listeners.size(); i++) {
790
                        ViewPortListener listener = (ViewPortListener) listeners.get(i);
791
                        listener.backColorChanged(ce);
792
                }
793
        }
794

    
795
        /**
796
         * <p>Notifies to all view port listeners registered, that the projection of this view port
797
         *  has changed.</p>
798
         *
799
         * @param projection the new projection
800
         *
801
         * @see #setProjection(IProjection)
802
         * @see ProjectionEvent
803
         * @see ViewPortListener
804
         */
805
        private void callProjectionChanged(IProjection projection) {
806
                ProjectionEvent ev = ProjectionEvent.createProjectionEvent(projection);
807

    
808
                for (int i = 0; i < listeners.size(); i++) {
809
                        ViewPortListener listener = (ViewPortListener) listeners.get(i);
810
                        listener.projectionChanged(ev);
811
                }
812
        }
813

    
814
        /**
815
         * <p>Calculates the affine transformation between the {@link #extent extent} in <i>map 2D coordinates</i> to
816
         *  the image area in the screen, in <i>screen 2D coordinates</i> (pixels).</p>
817
         *
818
         * <p>This process recalculates some parameters of this view port:<br>
819
         *
820
         * <ul>
821
         * <li>The new {@link #scale scale} .
822
         * <li>The new {@link #adjustedExtent adjustedExtent} .
823
         * <li>The new {@link #trans trans} .
824
         * <li>The new real world coordinates equivalent to 1 pixel ({@link #dist1pixel dist1pixel}) .
825
         * <li>The new real world coordinates equivalent to 3 pixels ({@link #dist3pixel dist3pixel}) .
826
         * </ul>
827
         * </p>
828
         *
829
         * @see #getAffineTransform()
830
         * @see #setAffineTransform(AffineTransform)
831
         * @see #refreshExtent()
832
         * @see #setEnvelope(Envelope)
833
         * @see #setImageSize(Dimension)
834
         * @see #setPreviousExtent()
835
         * @see #createFromXML(XMLEntity)
836
         * @see AffineTransform
837
         */
838
        private void calculateAffineTransform() {
839
                if ((imageSize == null) || (extent == null) ||
840
                                (imageSize.getWidth() <= 0) || (imageSize.getHeight() <= 0)) {
841
                        return;
842
                }
843

    
844
                AffineTransform escalado = new AffineTransform();
845
                AffineTransform translacion = new AffineTransform();
846

    
847
                double escalaX;
848
                double escalaY;
849

    
850
                escalaX = imageSize.getWidth() / extent.getWidth();
851
                escalaY = imageSize.getHeight() / extent.getHeight();
852

    
853
                double xCenter = extent.getCenterX();
854
                double yCenter = extent.getCenterY();
855
                double newHeight;
856
                double newWidth;
857

    
858
                adjustedExtent = new Rectangle2D.Double();
859

    
860
                if (adjustableExtent) {
861
                        if (escalaX < escalaY) {
862
                                scale = escalaX;
863
                                newHeight = imageSize.getHeight() / scale;
864
                                adjustedExtent.setRect(xCenter - (extent.getWidth() / 2.0),
865
                                        yCenter - (newHeight / 2.0), extent.getWidth(), newHeight);
866
                        } else {
867
                                scale = escalaY;
868
                                newWidth = imageSize.getWidth() / scale;
869
                                adjustedExtent.setRect(xCenter - (newWidth / 2.0),
870
                                        yCenter - (extent.getHeight() / 2.0), newWidth,
871
                                        extent.getHeight());
872
                        }
873
                        escalado.setToScale(scale, -scale);
874
                }
875
                else { // adjusted is same as extent
876
                        scale = escalaX;
877
                        adjustedExtent.setFrame(extent);
878
                        escalado.setToScale(escalaX, -escalaY);
879
                }
880
                Envelope env=getAdjustedExtent();
881
                if (env == null) {
882
                        return;
883
                }
884
                translacion.setToTranslation(-env.getMinimum(0),
885
                        -env.getMinimum(1) - getAdjustedExtent().getLength(1));
886

    
887
                AffineTransform offsetTrans = new AffineTransform();
888
                offsetTrans.setToTranslation(offset.getX(), offset.getY());
889

    
890
                trans.setToIdentity();
891
                trans.concatenate(offsetTrans);
892
                trans.concatenate(escalado);
893

    
894
                trans.concatenate(translacion);
895

    
896
                // Calculamos las distancias de 1 pixel y 3 pixel con esa transformaci?n
897
                // de coordenadas, de forma que est?n precalculadas para cuando las necesitemos
898
                AffineTransform at;
899

    
900
                try {
901
                        at = trans.createInverse();
902

    
903
                        java.awt.Point pPixel = new java.awt.Point(1, 1);
904
                        Point2D.Float pProv = new Point2D.Float();
905
                        at.deltaTransform(pPixel, pProv);
906

    
907
                        dist1pixel = pProv.x;
908
                        dist3pixel = 3 * pProv.x;
909
                } catch (NoninvertibleTransformException e) {
910
                        System.err.println("transformada afin = " + trans.toString());
911
                        System.err.println("extent = " + extent.toString() +
912
                                " imageSize= " + imageSize.toString());
913
                        throw new RuntimeException("Non invertible transform Exception",e);
914
                }
915
        }
916

    
917
        /**
918
         * <p>Sets the offset.</p>
919
         * <p>The offset is the position where start drawing the map.</p>
920
         *
921
         * @param p 2D point that represents the offset in pixels
922
         *
923
         * @see #getOffset()
924
         */
925
        public void setOffset(Point2D p) {
926
                if (!offset.equals(p)){
927
                        this.updateDrawVersion();
928
                        offset = p;
929
                }
930
        }
931

    
932
        /**
933
         * <p>Gets the offset.</p>
934
         * <p>The offset is the position where start drawing the map.</p>
935
         *
936
         * @return 2D point that represents the offset in pixels
937
         *
938
         * @see #setOffset(Point2D)
939
         */
940
        public Point2D getOffset() {
941
                return offset;
942
        }
943

    
944
        /**
945
         * <p>Sets the background color.</p>
946
         *
947
         * @param c the new background color
948
         *
949
         * @see #getBackColor()
950
         */
951
        public void setBackColor(Color c) {
952
                if (!c.equals(this.backColor)){
953
                        this.updateDrawVersion();
954
                        backColor = c;
955
                        callColorChanged(backColor);
956
                }
957
        }
958

    
959
        /**
960
         * <p>Gets the background color.</p>
961
         *
962
         * @return the background color of the view
963
         *
964
         * @see #setBackColor(Color)
965
         */
966
        public Color getBackColor() {
967
                return backColor;
968
        }
969

    
970
        /**
971
         * <p>Returns the extent currently covered by the view adjusted (scaled) to the image size aspect.</p>
972
         *
973
         * @return extent of the view adjusted to the image size aspect
974
         *
975
         * @see #setAdjustable(boolean)
976
         */
977
        public Envelope getAdjustedExtent() {
978
                if (cliprect!=null){
979
                        Rectangle2D r= adjustedExtent.createIntersection(cliprect);
980
                        return UtilFunctions.createEnvelope(r.getX(),r.getY(),r.getMaxX(),r.getMaxY());
981
                }
982
                if (adjustedExtent!=null) {
983
                        return UtilFunctions.createEnvelope(adjustedExtent.getX(),adjustedExtent.getY(),adjustedExtent.getMaxX(),adjustedExtent.getMaxY());
984
                }
985
                return null;
986
        }
987

    
988
        /**
989
         * <p>Returns the measurement unit of this view port used for measuring distances and displaying information.</p>
990
         *
991
         * @return the measurement unit of this view used for measuring distances and displaying information
992
         *
993
         * @see #setDistanceUnits(int)
994
         */
995
        public int getDistanceUnits() {
996
                return distanceUnits;
997
        }
998
        /**
999
         * <p>Returns the measurement unit of this view port used for measuring areas and displaying information.</p>
1000
         *
1001
         * @return the measurement unit of this view used for measuring areas and displaying information
1002
         *
1003
         * @see #setDistanceUnits(int)
1004
         */
1005
        public int getDistanceArea() {
1006
                return distanceArea;
1007
        }
1008
        /**
1009
         * <p>Sets the measurement unit of this view port used for measuring distances and displaying information.</p>
1010
         *
1011
         * @param distanceUnits the measurement unit of this view used for measuring distances and displaying information
1012
         *
1013
         * @see #getDistanceUnits()
1014
         */
1015
        public void setDistanceUnits(int distanceUnits) {
1016
                this.distanceUnits = distanceUnits;
1017
        }
1018
        /**
1019
         * <p>Sets the measurement unit of this view port used for measuring areas and displaying information.</p>
1020
         *
1021
         * @param distanceUnits the measurement unit of this view used for measuring areas and displaying information
1022
         *
1023
         * @see #getDistanceUnits()
1024
         */
1025
        public void setDistanceArea(int distanceArea) {
1026
                this.distanceArea = distanceArea;
1027
        }
1028
        /**
1029
         * <p>Gets the measurement unit used by this view port for the map.</p>
1030
         *
1031
         * @return Returns the current map measure unit
1032
         *
1033
         * @see #setMapUnits(int)
1034
         */
1035
        public int getMapUnits() {
1036
                return mapUnits;
1037
        }
1038

    
1039
        /**
1040
         * <p>Sets the measurement unit used by this view port for the map.</p>
1041
         *
1042
         * @param mapUnits the new map measure unit
1043
         *
1044
         * @see #getMapUnits()
1045
         */
1046
        public void setMapUnits(int mapUnits) {
1047
                this.mapUnits = mapUnits;
1048
        }
1049

    
1050
        /**
1051
         * <p>Gets the width in <i>screen coordinates</i> of the rectangle where the image is displayed.</p>
1052
         * <p>Used by {@linkplain #calculateAffineTransform()} to calculate:<br>
1053
           *
1054
         * <ul>
1055
         * <li>The new {@link #scale scale} .
1056
         * <li>The new {@link #adjustedExtent adjustableExtent} .
1057
         * <li>The new {@link #trans trans} .
1058
         * <li>The new real world coordinates equivalent to 1 pixel ({@link #dist1pixel dist1pixel}) .
1059
         * <li>The new real world coordinates equivalent to 3 pixels ({@link #dist3pixel dist3pixel}) .
1060
         * </ul>
1061
         * </p>
1062
         *
1063
         * @see #getImageHeight()
1064
         * @see #getImageSize()
1065
         * @see #setImageSize(Dimension)
1066
         */
1067
        public int getImageWidth() {
1068
                return imageSize.width;
1069
        }
1070

    
1071
        /**
1072
         * <p>Gets the height in <i>screen coordinates</i> of the rectangle where the image is displayed.</p>
1073
         * <p>Used by {@linkplain #calculateAffineTransform()} to calculate:<br>
1074
           *
1075
         * <ul>
1076
         * <li>The new {@link #scale scale} .
1077
         * <li>The new {@link #adjustedExtent adjustableExtent} .
1078
         * <li>The new {@link #trans trans} .
1079
         * <li>The new real world coordinates equivalent to 1 pixel ({@link #dist1pixel dist1pixel}) .
1080
         * <li>The new real world coordinates equivalent to 3 pixels ({@link #dist3pixel dist3pixel}) .
1081
         * </ul>
1082
         * </p>
1083
         *
1084
         * @see #getImageWidth()
1085
         * @see #getImageSize()
1086
         * @see #setImageSize(Dimension)
1087
         */
1088
        public int getImageHeight() {
1089
                return imageSize.height;
1090
        }
1091

    
1092
        /**
1093
         * <p>Gets the distance in <i>world coordinates</i> equivalent to 1 pixel in the view with the current extent.</p>
1094
         *
1095
         * @return the distance
1096
         *
1097
         * @see #setDist1pixel(double)
1098
         */
1099
        public double getDist1pixel() {
1100
                return dist1pixel;
1101
        }
1102

    
1103
        /**
1104
         * <p>Sets the distance in <i>world coordinates</i> equivalent to 1 pixel in the view with the current extent.</p>
1105
         *
1106
         * @param dist1pixel the distance
1107
         *
1108
         * @see #getDist1pixel()
1109
         */
1110
        public void setDist1pixel(double dist1pixel) {
1111
                if (dist1pixel == this.dist1pixel){
1112
                        return;
1113
                }
1114
                        this.updateDrawVersion();
1115
                this.dist1pixel = dist1pixel;
1116
        }
1117

    
1118
        /**
1119
         * <p>Gets the distance in <i>world coordinates</i> equivalent to 3 pixels in the view with the current extent.</p>
1120
         *
1121
         * @return the distance
1122
         *
1123
         * @see #setDist3pixel(double)
1124
         */
1125
        public double getDist3pixel() {
1126
                return dist3pixel;
1127
        }
1128

    
1129
        /**
1130
         * <p>Sets the distance in <i>world coordinates</i> equivalent to 3 pixels in the view with the current extent.</p>
1131
         *
1132
         * @param dist3pixel the distance
1133
         *
1134
         * @see #getDist3pixel()
1135
         */
1136
        public void setDist3pixel(double dist3pixel) {
1137
                if (this.dist3pixel == dist3pixel){
1138
                        return;
1139
                }
1140
                this.updateDrawVersion();
1141
                this.dist3pixel = dist3pixel;
1142
        }
1143

    
1144
        /**
1145
         * <p>Returns the last previous extents of this view port.</p>
1146
         *
1147
         * @return the last previous extents of this view port
1148
         *
1149
         * @see #setPreviousExtent()
1150
         */
1151
        public ExtentHistory getExtents() {
1152
                return extents;
1153
        }
1154

    
1155
        /**
1156
         * <p>Gets the projection used in this view port.</p>
1157
         *
1158
         * @return projection used in this view port
1159
         *
1160
         * @see #setProjection(IProjection)
1161
         */
1162
        public IProjection getProjection() {
1163
                return proj;
1164
        }
1165

    
1166
        /**
1167
         * <p>Sets the projection to this view port.</p>
1168
         *
1169
         * @param proj the new projection
1170
         *
1171
         * @see #getProjection()
1172
         */
1173
        public void setProjection(IProjection proj) {
1174
                if(this.proj == null || !this.proj.getAbrev().equals(proj.getAbrev())) {
1175
                        this.updateDrawVersion();
1176
                        this.proj = proj;
1177
                        callProjectionChanged(proj);
1178
                }
1179
        }
1180

    
1181
//  -----------------------------------------------------------------------------------------------------------
1182
//  NOTA PARA DESARROLLADORES SOBRE EL M?TODO "public void setAffineTransform(AffineTransform at)"
1183
//  ==============================================================================================
1184
//          Only used for print, should be removed, redefining the {@link RasterAdapter RasterAdapter} interface,
1185
//           allowing it to receive a {@link ViewPortData ViewPortData} .
1186
//  -----------------------------------------------------------------------------------------------------------
1187

    
1188
        /**
1189
         * <p>Sets only the affine transform to this view port, without updating dependent attributes.</p>
1190
         * <p><b><i>This method could be problematic!</i></b></p>
1191
         *
1192
         * @param at the affine transform to set
1193
         *
1194
         * @see #getAffineTransform()
1195
         * @see #calculateAffineTransform()
1196
         */
1197
        public void setAffineTransform(AffineTransform at)
1198
        {
1199
            this.trans = at;
1200
        }
1201

    
1202
        /**
1203
         * <p>Returns an XML entity that represents this view port instance:<br>
1204
         * <ul>
1205
         * <li>Properties:
1206
         *  <ul>
1207
         *  <li><i>className</i>: name of this class.
1208
         *  <li>If defined, the adjusted extent:
1209
         *   <ul>
1210
         *   <li><i>adjustedExtentX</i>: X coordinate of the adjusted extent.
1211
         *   <li><i>adjustedExtentY</i>: Y coordinate of the adjusted extent.
1212
         *   <li><i>adjustedExtentW</i>: width of the adjusted extent.
1213
         *   <li><i>adjustedExtentH</i>: height of the adjusted extent.
1214
         *   </ul>
1215
         *  <li>If defined, the background color:
1216
         *   <ul>
1217
         *   <li><i>backColor</i>: background color.
1218
         *   </ul>
1219
         *  <li>If defined, the clip:
1220
         *   <ul>
1221
         *   <li><i>clipX</i>: X coordinate of the clip.
1222
         *   <li><i>clipY</i>: Y coordinate of clip.
1223
         *   <li><i>clipW</i>: width of the clip.
1224
         *   <li><i>clipH</i>: height of the clip.
1225
         *   </ul>
1226
         *  <li><i>dist1pixel</i>: the distance in world coordinates equivalent to 1 pixel in the view.
1227
         *  <li><i>dist3pixel</i>: the distance in world coordinates equivalent to 3 pixels in the view.
1228
         *  <li><i>distanceUnits</i>: the distance measurement unit.
1229
         *  <li>If defined, the extent:
1230
         *   <ul>
1231
         *   <li><i>extentX</i>: X coordinate of the extent.
1232
         *   <li><i>extentY</i>: Y coordinate of the extent.
1233
         *   <li><i>extentW</i>: width of the extent.
1234
         *   <li><i>extentH</i>: height of the extent.
1235
         *   </ul>
1236
         *  <li><i>mapUnits</i>: the map measurement unit.
1237
         *  <li><i>offsetX</i>: X coordinate of the offset.
1238
         *  <li><i>offsetY</i>: Y coordinate of the offset.
1239
         *  <li>If defined, the projection:
1240
         *   <ul>
1241
         *   <li>If its defined, the projection:
1242
         *    <ul>
1243
         *     <li><i>proj</i>: the projection.</li>
1244
         *    </ul>
1245
         *   </ul>
1246
         *  <li><i>scale</i>: ratio between the size of <code>imageSize</code> and <code>extent</code>.
1247
         *  </ul>
1248
         * <li>Child branches:
1249
         *  <ul>
1250
         *  <li>XML entity of the internal {@link ExtentHistory ExtentHistory} .
1251
         *  </ul>
1252
         * </ul>
1253
         *
1254
         * @return the XML entity
1255
         *
1256
         * @see #createFromXML(XMLEntity)
1257
         */
1258
        public XMLEntity getXMLEntity() {
1259
                XMLEntity xml = new XMLEntity();
1260
                xml.putProperty("className",this.getClass().getName());
1261

    
1262
                if (adjustedExtent != null) {
1263
                        xml.putProperty("adjustedExtentX", adjustedExtent.getX());
1264
                        xml.putProperty("adjustedExtentY", adjustedExtent.getY());
1265
                        xml.putProperty("adjustedExtentW", adjustedExtent.getWidth());
1266
                        xml.putProperty("adjustedExtentH", adjustedExtent.getHeight());
1267
                }
1268

    
1269
                if (backColor != null) {
1270
                        xml.putProperty("backColor", StringUtilities.color2String(backColor));
1271
                }
1272

    
1273
                if (clip != null) {
1274
                        xml.putProperty("clipX", clip.getX());
1275
                        xml.putProperty("clipY", clip.getY());
1276
                        xml.putProperty("clipW", clip.getWidth());
1277
                        xml.putProperty("clipH", clip.getHeight());
1278
                }
1279

    
1280
                xml.putProperty("dist1pixel", dist1pixel);
1281
                xml.putProperty("dist3pixel", dist3pixel);
1282
                xml.putProperty("distanceUnits", distanceUnits);
1283

    
1284
                if (extent != null) {
1285
                        xml.putProperty("extentX", extent.getX());
1286
                        xml.putProperty("extentY", extent.getY());
1287
                        xml.putProperty("extentW", extent.getWidth());
1288
                        xml.putProperty("extentH", extent.getHeight());
1289
                }
1290

    
1291
                xml.addChild(extents.getXMLEntity());
1292
                xml.putProperty("mapUnits", mapUnits);
1293
                xml.putProperty("offsetX", offset.getX());
1294
                xml.putProperty("offsetY", offset.getY());
1295

    
1296
                if (proj != null) {
1297
                        xml.putProperty("proj", proj.getAbrev());
1298
                }
1299

    
1300
                xml.putProperty("scale", scale);
1301

    
1302
                return xml;
1303
        }
1304

    
1305

    
1306
        /**
1307
         * <p>Creates a new <code>ViewPort</code> from an XML entity.</p>
1308
         *
1309
         * @param xml an XML entity
1310
         *
1311
         * @return the new <code>ViewPort</code>
1312
         *
1313
         * @see #getXMLEntity()
1314
         */
1315
        public static ViewPort createFromXML(XMLEntity xml) {
1316
                ViewPort vp = new ViewPort(null);
1317

    
1318
                if (xml.contains("adjustedExtentX")) {
1319
                        vp.adjustedExtent = new Rectangle2D.Double(xml.getDoubleProperty(
1320
                                                "adjustedExtentX"),
1321
                                        xml.getDoubleProperty("adjustedExtentY"),
1322
                                        xml.getDoubleProperty("adjustedExtentW"),
1323
                                        xml.getDoubleProperty("adjustedExtentH"));
1324
                }
1325

    
1326
                if (xml.contains("backColor")) {
1327
                        vp.setBackColor(StringUtilities.string2Color(xml.getStringProperty(
1328
                                                "backColor")));
1329
                }else {
1330
                        vp.setBackColor(Color.white);
1331
                }
1332

    
1333
                if (xml.contains("clipX")) {
1334
                        vp.clip = new Rectangle2D.Double(xml.getDoubleProperty("clipX"),
1335
                                        xml.getDoubleProperty("clipY"),
1336
                                        xml.getDoubleProperty("clipW"),
1337
                                        xml.getDoubleProperty("clipH"));
1338
                }
1339

    
1340
                vp.setDist1pixel(xml.getDoubleProperty("dist1pixel"));
1341
                vp.setDist3pixel(xml.getDoubleProperty("dist3pixel"));
1342
                vp.setDistanceUnits(xml.getIntProperty("distanceUnits"));
1343
                if (xml.contains("distanceArea")){
1344
                        vp.setDistanceArea(xml.getIntProperty("distanceArea"));
1345
                }else{
1346
                        vp.setDistanceArea(xml.getIntProperty("distanceUnits"));
1347
                }
1348
                vp.extents = ExtentHistory.createFromXML(xml.getChild(0));
1349

    
1350
                if (xml.contains("extentX")) {
1351
                        double x=xml.getDoubleProperty("extentX");
1352
                        double y=xml.getDoubleProperty("extentY");
1353
                        vp.setEnvelope(UtilFunctions.createEnvelope(x,y,
1354
                                        x+xml.getDoubleProperty("extentW"),y+xml.getDoubleProperty("extentH")));
1355

    
1356
                        //Calcula la transformaci?n af?n
1357
                        vp.calculateAffineTransform();
1358

    
1359
                        // Lanzamos los eventos de extent cambiado
1360
                        // vp.callExtentListeners(vp.adjustedExtent);
1361
                }
1362

    
1363
                vp.setMapUnits(xml.getIntProperty("mapUnits"));
1364
                vp.setOffset(new Point2D.Double(xml.getDoubleProperty("offsetX"),
1365
                                xml.getDoubleProperty("offsetY")));
1366

    
1367
                if (xml.contains("proj")) {
1368
                        vp.proj = CRSFactory.getCRS(xml.getStringProperty("proj"));
1369
                }
1370

    
1371
                //vp.setScale(xml.getDoubleProperty("scale"));
1372
                vp.refreshExtent();
1373
                return vp;
1374
        }
1375

    
1376
        /**
1377
         * <p>Fast clone implementation: creates and returns a clone of this view port using XML entities.</p>
1378
         * <p>Isn't a <i>deepclone</i> to avoid unnecessary memory consumption.</p>
1379
         *
1380
         * @return the new view port
1381
         *
1382
         * @see #createFromXML(XMLEntity)
1383
         */
1384
        public ViewPort cloneViewPort() {
1385
                return createFromXML(getXMLEntity());
1386
        }
1387

    
1388
        /**
1389
         * <p>Returns a <code>String</code> representation of the main values of this view port: <code>{@linkplain #extent}</code>,
1390
         *  <code>{@linkplain #adjustedExtent}</code>, <code>{@linkplain #imageSize}</code>, <code>{@linkplain #scale}</code>, and <code>{@linkplain #trans}</code>.</p>
1391
         *
1392
         * @return a <code>string</code> representation of the main values of this view port
1393
         */
1394
        public String toString() {
1395

    
1396
                String str;
1397
                str = "Datos del viewPort:\nExtent=" + extent + "\nadjustedExtent=" +
1398
                        adjustedExtent + "\nimageSize=" + imageSize + "\nescale=" + scale +
1399
                        "\ntrans=" + trans;
1400

    
1401
                return str;
1402
        }
1403

    
1404
        /**
1405
         * <p>Sets the position and size of the clipping rectangle.</p>
1406
         *
1407
         * @param rectView the clipping rectangle to set
1408
         */
1409
        public void setClipRect(Rectangle2D rectView) {
1410
                this.updateDrawVersion();
1411
                cliprect=rectView;
1412
        }
1413

    
1414
        /**
1415
         * <p>Converts and returns the {@link Rectangle2D Rectangle2D}, that is in <i>map
1416
         *  coordinates</i> to <i>screen coordinates</i> (pixels) using an <i>inverse transform</i> with
1417
         *  the transformation affine information in the {@link #trans #trans} attribute.</p>
1418
         *
1419
         * @param r the 2D rectangle in <i>map coordinates</i>
1420
         * @return 2D rectangle equivalent in <i>screen coordinates</i> (pixels)
1421
         *
1422
         * @see #toMapRectangle(Rectangle2D)
1423
         * @see #fromMapDistance(double)
1424
         * @see #fromMapPoint(Point2D)
1425
         */
1426
        public Rectangle2D fromMapRectangle(Rectangle2D r) {
1427
                Rectangle2D rect=new Rectangle2D.Double();
1428
                Point2D p1=fromMapPoint((int)r.getX(),(int)r.getY());
1429
                Point2D p2=fromMapPoint((int)r.getMaxX(),(int)r.getMaxY());
1430
                rect.setFrameFromDiagonal(p1,p2);
1431
                return rect;
1432
        }
1433

    
1434
        /**
1435
         * <p>Recalculates the current <code>{@linkplain #extent}</code> using an scale. It's necessary execute {@linkplain #refreshExtent()} after.</p>
1436
         *
1437
         * @param s the scale to set
1438
         *
1439
         * @deprecated since 07/09/07, use {@linkplain MapContext#setScaleView(long)}
1440
         */
1441
        public void setScale(long s){
1442
                double x=extent.getX();
1443
                double y=extent.getY();
1444
                double escalaX = imageSize.getWidth() / extent.getWidth();
1445
                double w=imageSize.getWidth() / s;
1446
                double h=imageSize.getHeight() / s;
1447
                double difw = escalaX/s;
1448

    
1449
                double x1 = (-x * difw) -
1450
            x+
1451
            extent.getWidth()/2;
1452
        double y1 = (-y * difw) -
1453
            y +
1454
            extent.getHeight()/2;
1455
        double w1=extent.getWidth()*difw;
1456
        double h1=extent.getHeight()*difw;
1457
                extent.setRect(-x1,-y1,w1,h1);
1458
        }
1459

    
1460

    
1461
        public long getDrawVersion() {
1462
                return this.drawVersion;
1463
        }
1464

    
1465
        protected void updateDrawVersion(){
1466
                this.drawVersion++;
1467
        }
1468

    
1469
}