Statistics
| Revision:

root / branches / v10 / libraries / libFMap / src / com / iver / cit / gvsig / fmap / ViewPort.java @ 20332

History | View | Annotate | Download (44.8 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 com.iver.cit.gvsig.fmap;
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

    
57
import com.iver.cit.gvsig.fmap.crs.CRSFactory;
58
import com.iver.utiles.StringUtilities;
59
import com.iver.utiles.XMLEntity;
60

    
61
/**
62
 * <p><code>ViewPort</code> class represents the logic needed to transform a rectangular area of a map
63
 *  to the available area in screen to display it.</p>
64
 *
65
 * <p>Includes an affine transformation, between the rectangular area selected of the external map, in its own
66
 *  <i>map coordinates</i>, to the rectangular area available of a view in <i>screen coordinates</i>.</p>
67
 *
68
 * <p>Elements:
69
 * <ul>
70
 * <li><i>extent</i>: the area selected of the map, in <i>map coordinates</i>.
71
 * <li><i>imageSize</i>: width and height in pixels (<i>screen coordinates</i>) of the area available
72
 *  in screen to display the area selected of the map.
73
 * <li><i>adjustedExtent</i>: the area selected must be an scale of <i>imageSize</i>.<br>This implies adapt the
74
 *  extent, preserving and centering it, and adding around the needed area to fill all the image size. That
75
 *  added area will be extracted from the original map, wherever exists, and filled with the background color
76
 *  wherever not.
77
 * <li><i>scale</i>: the scale between the adjusted extent and the image size.
78
 * <li><i>backColor</i>: the default background color in the view, if there is no map.
79
 * <li><i>trans</i>: the affine transformation.
80
 * <li><i>proj</i>: map projection used in this view.
81
 * <li><i>distanceUnits</i>: distance measurement units, of data in screen.
82
 * <li><i>mapUnits</i>: measurement units, of data in map.
83
 * <li><i>extents</i>: an {@link ExtentHistory ExtentHistory} with the last previous extents.
84
 * <li><i>offset</i>: position in pixels of the available rectangular area, where start drawing the map.
85
 * <li><i>dist1pixel</i>: the distance in <i>world coordinates</i> equivalent to 1 pixel in the view with the
86
 *  current extent.
87
 * <li><i>dist3pixel</i>: the distance in <i>world coordinates</i> equivalent to 3 pixels in the view with the
88
 *  current extent.
89
 * <li><i>listeners</i>: list with the {@link ViewPortListener ViewPortListener} registered.
90
 * </ul>
91
 * </p>
92
 *
93
 * @author Vicente Caballero Navarro
94
 */
95
public class ViewPort {
96
        /**
97
         * <p>Metric unit or length equal to 1000 meters.</p>
98
         */
99
        public static int KILOMETROS = 0;
100

    
101
        /**
102
         * <p>The base unit of length in the International System of Units that is equal to the distance
103
         *  traveled by light in a vacuum in {frac;1;299,792,458} second or to about 39.37 inches.</p>
104
         */
105
        public static int METROS = 1;
106

    
107
        /**
108
         * <p>Metric unit or length equal to 0'01 meters.</p>
109
         */
110
        public static int CENTIMETRO = 2;
111

    
112
        /**
113
         * <p>Metric unit or length equal to 0'001 meters.</p>
114
         */
115
        public static int MILIMETRO = 3;
116

    
117
        /**
118
         * <p>The international statute mile by international agreement. It is defined to be precisely
119
         *  1,760 international yards (by definition, 0.9144 m each) and is therefore exactly 1,609.344
120
         *  metres (1.609344 km).</p>
121
         */
122
        public static int MILLAS = 4;
123

    
124
        /**
125
         * <p>Unit of length equal in the United States to 0.9144 meter.</p>
126
         */
127
        public static int YARDAS = 5;
128

    
129
        /**
130
         * <p>Any of various units of length based on the length of the human foot; especially :
131
         *  a unit equal to 1/3 yard and comprising 12 inches.</p>
132
         */
133
        public static int PIES = 6;
134

    
135
        /**
136
         * <p>Unit of length equal to 1/36 yard.</p>
137
         */
138
        public static int PULGADAS = 7;
139

    
140
        /**
141
         * <p>Grades according the current projection.</p>
142
         */
143
        public static int GRADOS = 8;
144

    
145
        /**
146
         * <p>Screen resolution in <i>dots-per-inch</i>. Useful to calculate the geographic scale of the view.</p>
147
         *
148
         * @see Toolkit#getScreenResolution()
149
         * @see #getScale()
150
         */
151
        private static int dpi = java.awt.Toolkit.getDefaultToolkit().getScreenResolution();
152

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

    
175
        /**
176
         * <p>Location and dimensions of the extent adjusted to the image size.</p>
177
         *
178
         * @see #getAdjustedExtent()
179
         */
180
        private Rectangle2D adjustedExtent;
181

    
182
        /**
183
         * <p>History with the last extents of the view.</p>
184
         *
185
         * @see #setPreviousExtent()
186
         * @see #getExtents()
187
         */
188
        private ExtentHistory extents = new ExtentHistory();
189

    
190
        /**
191
         * <p>Size in <i>screen coordinates</i> of the rectangle where the image is displayed.</p>
192
         * <p>Used by {@linkplain #calculateAffineTransform()} to calculate:<br>
193
           *
194
         * <ul>
195
         * <li>The new {@link #scale scale} .
196
         * <li>The new {@link #adjustedExtent adjustableExtent} .
197
         * <li>The new {@link #trans trans} .
198
         * <li>The new real world coordinates equivalent to 1 pixel ({@link #dist1pixel dist1pixel}) .
199
         * <li>The new real world coordinates equivalent to 3 pixels ({@link #dist3pixel dist3pixel}) .
200
         * </ul>
201
         * </p>
202
         *
203
         * @see #getImageSize()
204
         * @see #getImageHeight()
205
         * @see #getImageWidth()
206
         * @see #setImageSize(Dimension)
207
         */
208
        private Dimension imageSize;
209

    
210
        /**
211
         * <p>the affine transformation between the {@link #extent extent} in <i>map 2D coordinates</i> to
212
         *  the image area in the screen, in <i>screen 2D coordinates</i> (pixels).</p>
213
         *
214
         * @see AffineTransform
215
         *
216
         * @see #getAffineTransform()
217
         * @see #setAffineTransform(AffineTransform)
218
         * @see #calculateAffineTransform()
219
         */
220
        private AffineTransform trans = new AffineTransform();
221

    
222
        /**
223
         * <p>Measurement unit used for measuring distances and displaying information.</p>
224
         *
225
         * @see #getDistanceUnits()
226
         * @see #setDistanceUnits(int)
227
         */
228
        private int distanceUnits = METROS;
229

    
230
        /**
231
         * <p>Measurement unit used by this view port for the map.</p>
232
         *
233
         * @see #getMapUnits()
234
         * @see #setMapUnits(int)
235
         */
236
        private int mapUnits = METROS;
237

    
238
        /**
239
         * <p>Array with the {@link ViewPortListener ViewPortListener}s registered to this view port.</p>
240
         *
241
         * @see #addViewPortListener(ViewPortListener)
242
         * @see #removeViewPortListener(ViewPortListener)
243
         */
244
        private ArrayList listeners = new ArrayList();
245

    
246
        /**
247
         * <p>The offset is the position where start drawing the map.</p>
248
         * <p>The offset of a <a href="http://www.gvsig.gva.es/">gvSIG</a>'s <i>View</i> is
249
         * always (0, 0) because the drawing area fits with the full window area. But in
250
         * a <a href="http://www.gvsig.gva.es/">gvSIG</a>'s <i>Layout</i> it's up to the place where
251
         * the <code>FFrameView</code> is located.</p>
252
         *
253
         * @see #getOffset()
254
         * @see #setOffset(Point2D)
255
         */
256
        private Point2D offset = new Point2D.Double(0, 0);
257

    
258
        /**
259
         * <p>Clipping area.</p>
260
         */
261
        private Rectangle2D clip;
262

    
263
        /**
264
         * <p>Background color of this view.</p>
265
         *
266
         * @see #getBackColor()
267
         * @see #setBackColor(Color)
268
         */
269
        private Color backColor = null; //Color.WHITE;
270

    
271
        /**
272
         * <p>Information about the map projection used in this view.</p>
273
         *
274
         * @see #getProjection()
275
         * @see #setProjection(IProjection)
276
         */
277
        private IProjection proj;
278

    
279
        /**
280
         * <p>Represents the distance in <i>world coordinates</i> equivalent to 1 pixel in the view with the current extent.</p>
281
         *
282
         * @see #getDist1pixel()
283
         * @see #setDist1pixel(double)
284
         */
285
        private double dist1pixel;
286

    
287
        /**
288
         * <p>Represents the distance in <i>world coordinates</i> equivalent to 3 pixels in the view with the current extent.</p>
289
         *
290
         * @see #getDist3pixel()
291
         * @see #setDist3pixel(double)
292
         */
293
        private double dist3pixel;
294

    
295
        /**
296
         * <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>
297
         */
298
        private double scale;
299

    
300
        /**
301
         * <p>Clipping area.</p>
302
         *
303
         * @see #setClipRect(Rectangle2D)
304
         */
305
        private Rectangle2D cliprect;
306

    
307
        /**
308
         * <p>Enables or disables the <i>"adjustable extent"</i> mode.</p>
309
         *
310
         * <p>
311
         * When calculates the affine transform, if
312
         * <ul>
313
         * <li><i>enabled</i>: the new <code>adjustedExtent</code> will have the (X, Y) coordinates of the <code>extent</code> and
314
         *  an area that will be an scale of the image size. That area will have different
315
         *  height or width (not both) of the extent according the least ratio (height or width) in <pre>image.size/extent.size"</pre>.
316
         * <li><i>disabled</i>: the new <code>adjustedExtent</code> will be like <code>extent</code>.
317
         * </ul>
318
         * </p>
319
         *
320
         * @see #setAdjustable(boolean)
321
         */
322
        private boolean adjustableExtent=true;
323
        /**
324
         * <p>Measurement unit used for measuring areas and displaying information.</p>
325
         *
326
         * @see #getDistanceArea()
327
         * @see #setDistanceArea(int)
328
         */
329
        private int distanceArea = 0;
330

    
331
        /**
332
         * <p>Creates a new view port with the information of the projection in <code>proj</code> argument, and
333
         *  default configuration:</p>
334
         * <p>
335
         * <ul>
336
         *  <li><i><code>distanceUnits</code></i> = meters
337
         *  <li><i><code>mapUnits</code></i> = meters
338
         *  <li><i><code>backColor</code></i> = <i>undefined</i>
339
         *  <li><i><code>offset</code></i> = <code>new Point2D.Double(0, 0);</code>
340
         * </ul>
341
         * </p>
342
         *
343
         * @param proj information of the projection for this view port
344
         */
345
        public ViewPort(IProjection proj) {
346
                // Por defecto
347
                this.proj = proj;
348
        }
349

    
350
        /**
351
         * <p>Changes the status of the <i>"adjustable extent"</i> option to enabled or disabled.</p>
352
         *
353
         * <p>If view port isn't adjustable, won't bear in mind the aspect ratio of the available rectangular area to
354
         *  calculate the affine transform from the original map in real coordinates. (Won't scale the image to adapt
355
         *  it to the available rectangular area).</p>
356
         *
357
         * @param boolean the boolean to be set
358
         */
359
        public void setAdjustable(boolean adjustable) {
360
                adjustableExtent = adjustable;
361
        }
362

    
363
        /**
364
         * <p>Appends the specified {@link ViewPortListener ViewPortListener} listener if weren't.</p>
365
         *
366
         * @param arg0 the listener to add
367
         *
368
         * @return <code>true</code> if has been added successfully
369
         *
370
         * @see #removeViewPortListener(ViewPortListener)
371
         */
372
        public boolean addViewPortListener(ViewPortListener arg0) {
373
                if (!listeners.contains(arg0))
374
                        return listeners.add(arg0);
375
                return false;
376
        }
377

    
378
        /**
379
          * <p>Removes the specified {@link ViewPortListener ViewPortListener} listener, if existed.</p>
380
         *
381
         * @param arg0 the listener to remove
382
         *
383
         * @return <code>true</code> if the contained the specified listener.
384
         *
385
         * @see #addViewPortListener(ViewPortListener)
386
         */
387
        public boolean removeViewPortListener(ViewPortListener arg0) {
388
                return listeners.remove(arg0);
389
        }
390

    
391
        /**
392
         * <p>Converts and returns the distance <code>d</code>, that is in <i>map
393
         *  coordinates</i> to <i>screen coordinates</i> using a <i>delta transform</i> with
394
         *  the transformation affine information in the {@link #trans #trans} attribute.</p>
395
         *
396
         * @param d distance in <i>map coordinates</i>
397
         *
398
         * @return distance equivalent in <i>screen coordinates</i>
399
         *
400
         * @see #toMapDistance(int)
401
         * @see AffineTransform#deltaTransform(Point2D, Point2D)S
402
         */
403
        public int fromMapDistance(double d) {
404
                Point2D.Double pWorld = new Point2D.Double(1, 1);
405
                Point2D.Double pScreen = new Point2D.Double();
406

    
407
                try {
408
                        trans.deltaTransform(pWorld, pScreen);
409
                } catch (Exception e) {
410
                        System.err.print(e.getMessage());
411
                }
412

    
413
                return (int) (d * pScreen.x);
414
        }
415

    
416
        /**
417
         * <p>Converts and returns the distance <code>d</code>, that is in <i>screen
418
         *  coordinates</i> to <i>map coordinates</i> using the transformation affine information
419
         *  in the {@link #trans #trans} attribute.</p>
420
         *
421
         * @param d distance in pixels
422
         *
423
         * @return distance equivalent in <i>map coordinates</i>
424
         *
425
         * @see #fromMapDistance(double)
426
         * @see AffineTransform
427
         */
428
        public double toMapDistance(int d) {
429
                double dist = d / trans.getScaleX();
430

    
431
                return dist;
432
        }
433

    
434
        /**
435
         * <p>Converts and returns the {@link Rectangle2D Rectangle2D}, that is in <i>map
436
         *  coordinates</i> to <i>screen coordinates</i> (pixels) using an <i>inverse transform</i> with
437
         *  the transformation affine information in the {@link #trans #trans} attribute.</p>
438
         *
439
         * @param r the 2D rectangle in <i>map coordinates</i>
440
         * @return 2D rectangle equivalent in <i>screen coordinates</i> (pixels)
441
         *
442
         * @see #toMapRectangle(Rectangle2D)
443
         * @see #fromMapDistance(double)
444
         * @see #fromMapPoint(Point2D)
445
         */
446
        public Rectangle2D fromMapRectangle(Rectangle2D r) {
447
                double w=fromMapDistance((int)r.getWidth());
448
                double h=fromMapDistance((int)r.getHeight());
449
                Point2D p1=fromMapPoint((int)r.getX(),(int)r.getY());
450
                return new Rectangle2D.Double(p1.getX(),p1.getY(),w,h);
451
        }
452

    
453
        /**
454
         * <p>Converts and returns the {@link Rectangle2D Rectangle2D}, that is in <i>screen
455
         *  coordinates</i> (pixels) to <i>map coordinates</i> using {@linkplain #toMapDistance(int)},
456
         *  and {@linkplain #toMapPoint(int, int)}.</p>
457
         *
458
         * @param r the 2D rectangle in <i>screen coordinates</i> (pixels)
459
         * @return 2D rectangle equivalent in <i>map coordinates</i>
460
         *
461
         * @see #fromMapRectangle(Rectangle2D)
462
         * @see #toMapDistance(int)
463
         * @see #toMapPoint(int, int)
464
         */
465
        public Rectangle2D toMapRectangle(Rectangle2D r){
466
                double w=toMapDistance((int)r.getWidth());
467
                double h=toMapDistance((int)r.getHeight());
468
                Point2D p1=toMapPoint((int)r.getX(),(int)r.getY());
469
                return new Rectangle2D.Double(p1.getX(),p1.getY(),w,h);
470
        }
471

    
472
        /**
473
         * <p>Converts and returns the 2D point <code>(x,y)</code>, that is in <i>map
474
         *  coordinates</i> to <i>screen coordinates</i> (pixels) using
475
         *  the affine transformation in the {@link #trans #trans} attribute.</p>
476
         *
477
         * @param x the <code>x</code> <i>map coordinate</i> of a 2D point
478
         * @param y the <code>y</code> <i>map coordinate</i> of a 2D point
479
         *
480
         * @return 2D point equivalent in <i>screen coordinates</i> (pixels)
481
         *
482
         * @see #fromMapPoint(Point2D)
483
         * @see AffineTransform#transform(Point2D, Point2D)
484
         */
485
        public Point2D fromMapPoint(double x, double y) {
486
                Point2D.Double pWorld = new Point2D.Double(x, y);
487
                Point2D.Double pScreen = new Point2D.Double();
488

    
489
                try {
490
                        trans.transform(pWorld, pScreen);
491
                } catch (Exception e) {
492
                        System.err.print(e.getMessage());
493
                }
494

    
495
                return pScreen;
496
        }
497

    
498
        /**
499
         * <p>Converts and returns the 2D point argument, that is in <i>map
500
         *  coordinates</i> to <i>screen coordinates</i> (pixels) using
501
         *  the affine transformation in the {@link #trans #trans} attribute.</p>
502
         *
503
         * @param point the 2D point in <i>map coordinates</i>
504
         *
505
         * @return 2D point equivalent in <i>screen coordinates</i> (pixels)
506
         *
507
         * @see #toMapPoint(Point2D)
508
         * @see #fromMapPoint(double, double)
509
         */
510
        public Point2D fromMapPoint(Point2D point) {
511
                return fromMapPoint(point.getX(), point.getY());
512
        }
513

    
514
        /**
515
         * <p>Converts and returns the 2D point <code>(x,y)</code>, that is in <i>screen coordinates</i>
516
         *  (pixels) to <i>map coordinates</i> using
517
         *  the affine transformation in the {@link #trans #trans} attribute.</p>
518
         *
519
         * @param x the <code>x</code> <i>screen coordinate</i> of a 2D point
520
         * @param y the <code>y</code> <i>screen coordinate</i> of a 2D point
521
         *
522
         * @return 2D point equivalent in <i>map coordinates</i>
523
         *
524
         * @see #toMapPoint(Point2D)
525
         * @see #fromMapPoint(double, double)
526
         */
527
        public Point2D toMapPoint(int x, int y) {
528
                Point pScreen = new Point(x, y);
529

    
530
                return toMapPoint(pScreen);
531
        }
532

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

    
550
                try {
551
                        at = trans.createInverse();
552
                        at.transform(pScreen, pWorld);
553
                } catch (NoninvertibleTransformException e) {
554
                        throw new RuntimeException(e);
555
                }
556

    
557
                return pWorld;
558
        }
559

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

    
576
                if ((proj != null) && !(proj instanceof CSUTM)) {
577
                        dist = new GeoCalc(proj).distanceVincenty(proj.toGeo(pt1),
578
                                        proj.toGeo(pt2));
579
                }
580

    
581
                return dist*MapContext.CHANGEM[getMapUnits()];
582
        }
583

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

    
594
                //Calcula la transformaci?n af?n
595
                calculateAffineTransform();
596

    
597
                // Lanzamos los eventos de extent cambiado
598
                callExtentChanged(getAdjustedExtent());
599
        }
600

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

    
624
        /**
625
         * <p>Changes the <i>extent</i> and <i>adjusted extent</i> of this view port:<br>
626
         * <ul>
627
         * <li>Stores the previous extent.
628
         * <li>Calculates the new extent using <code>r</code>:
629
         * <pre>extent = new Rectangle2D.Double(r.getMinX() - 0.1, r.getMinY() - 0.1, r.getWidth() + 0.2, r.getHeight() + 0.2);</pre>
630
         * <li>Executes {@linkplain #calculateAffineTransform()}: getting the new scale, adjusted extent, affine transformation between
631
         *  map and screen coordinates, the real world coordinates equivalent to 1 pixel, and the real world coordinates equivalent to 3 pixels.
632
         * <li>Notifies all {@link ViewPortListener ViewPortListener} registered that the extent has changed.
633
         * </ul>
634
         * </p>
635
         *
636
         * @param r the new extent
637
         *
638
         * @see #getExtent()
639
         * @see #getExtents()
640
         * @see #calculateAffineTransform()
641
         * @see #setPreviousExtent()
642
         */
643
        public void setExtent(Rectangle2D r) {
644
                if (extent != null) {
645
                        extents.put(extent);
646
                }
647

    
648
                //Esto comprueba que el extent no es de anchura o altura = "0"
649
                //y si es as? lo redimensiona.
650
                if (r!=null &&((r.getWidth() == 0) || (r.getHeight() == 0))) {
651
                        extent = new Rectangle2D.Double(r.getMinX() - 0.1,
652
                                        r.getMinY() - 0.1, r.getWidth() + 0.2, r.getHeight() + 0.2);
653
                } else {
654
                        extent = r;
655
                }
656

    
657
                //Calcula la transformaci?n af?n
658
                calculateAffineTransform();
659

    
660
                // Lanzamos los eventos de extent cambiado
661
                callExtentChanged(getAdjustedExtent());
662
        }
663

    
664
        /**
665
         * <p>Changes the <i>extent</i> and <i>adjusted extent</i> of this view port:<br>
666
         * <ul>
667
         * <li>Executes {@linkplain #calculateAffineTransform()}: getting the new scale, adjusted extent, affine transformation between
668
         *  map and screen coordinates, the real world coordinates equivalent to 1 pixel, and the real world coordinates equivalent to 3 pixels.
669
         * <li>Notifies to all {@link ViewPortListener ViewPortListener} registered that the extent has changed.
670
         * </ul>
671
         * </p>
672
         *
673
         * @see #setExtent(Rectangle2D)
674
         * @see #calculateAffineTransform()
675
         */
676
        public void refreshExtent() {
677
                //this.scale = scale;
678

    
679
                //Calcula la transformaci?n af?n
680
                calculateAffineTransform();
681

    
682
                // Lanzamos los eventos de extent cambiado
683
                callExtentChanged(getAdjustedExtent());
684
        }
685

    
686
        /**
687
         * <p>Calculates and returns using the current projection of this view port, the scale that
688
         *  is the extent in <i>screen coordinates</i> from the image in <i>map coordinates</i>.</p>
689
         *
690
         * @return the scale <i>extent / image size</i> projected by this view port
691
         *
692
         * @deprecated since 07/09/07, use {@linkplain MapContext#getScaleView()}
693
         */
694
        public double getScale() {
695
                return proj.getScale(extent.getMinX(), extent.getMaxX(),
696
                        imageSize.getWidth(), dpi);
697
        }
698

    
699
        /**
700
         * <p>Recalculates the current <code>{@linkplain #extent}</code> using an scale. It's necessary execute {@linkplain #refreshExtent()} after.</p>
701
         *
702
         * @param s the scale to set
703
         *
704
         * @deprecated since 07/09/07, use {@linkplain MapContext#setScaleView(long)}
705
         */
706
        public void setScale(long s){
707
                double x=extent.getX();
708
                double y=extent.getY();
709
                double escalaX = imageSize.getWidth() / extent.getWidth();
710
                double w=imageSize.getWidth() / s;
711
                double h=imageSize.getHeight() / s;
712
                double difw = escalaX/s;
713

    
714
                double x1 = (-x * difw) -
715
            x+
716
            extent.getWidth()/2;
717
        double y1 = (-y * difw) -
718
            y +
719
            extent.getHeight()/2;
720
        double w1=extent.getWidth()*difw;
721
        double h1=extent.getHeight()*difw;
722
                extent.setRect(-x1,-y1,w1,h1);
723
        }
724

    
725
        /**
726
         * <p>Affine transformation between <i>map 2D coordinates</i> to <i>screen 2D coordinates</i> (pixels),
727
         * preserving the "straightness" and "parallelism" of the lines.</p>
728
         *
729
         * @return the affine transformation
730
         *
731
         * @see #setAffineTransform(AffineTransform)
732
         * @see #calculateAffineTransform()
733
         */
734
        public AffineTransform getAffineTransform() {
735
                return trans;
736
        }
737

    
738
        /**
739
         * <p>Returns the size of the image projected.</p>
740
         *
741
         * @return the image size
742
         *
743
         * @see #setImageSize(Dimension)
744
         * @see #getImageHeight()
745
         * @see #getImageWidth()
746
         */
747
        public Dimension getImageSize() {
748
                return imageSize;
749
        }
750

    
751
        /**
752
         * <p>Sets the size of the image projected, recalculating the parameters of this view port.</p>
753
         *
754
         * @param imageSize the image size
755
         *
756
         * @see #getImageSize()
757
         * @see #calculateAffineTransform()
758
         */
759
        public void setImageSize(Dimension imageSize) {
760
                this.imageSize = imageSize;
761
                calculateAffineTransform();
762
        }
763

    
764
        /**
765
         * <p>Notifies to all view port listeners registered, that the adjusted extent of this view port
766
         *  has changed.</p>
767
         *
768
         * @param newRect the new adjusted extend
769
         *
770
         * @see #refreshExtent()
771
         * @see #setExtent(Rectangle2D)
772
         * @see #setPreviousExtent()
773
         * @see ExtentEvent
774
         * @see ViewPortListener
775
         */
776
        private void callExtentChanged(Rectangle2D newRect) {
777
                ExtentEvent ev = ExtentEvent.createExtentEvent(newRect);
778

    
779
                for (int i = 0; i < listeners.size(); i++) {
780
                        ViewPortListener listener = (ViewPortListener) listeners.get(i);
781
                        listener.extentChanged(ev);
782
                }
783
        }
784

    
785
        /**
786
         * <p>Notifies to all view port listeners registered, that the background color of this view port
787
         *  has changed.</p>
788
         *
789
         * @param c the new background color
790
         *
791
         * @see #setBackColor(Color)
792
         * @see ColorEvent
793
         * @see ViewPortListener
794
         */
795
        private void callColorChanged(Color c) {
796
                ColorEvent ce = ColorEvent.createColorEvent(c);
797

    
798
                for (int i = 0; i < listeners.size(); i++) {
799
                        ViewPortListener listener = (ViewPortListener) listeners.get(i);
800
                        listener.backColorChanged(ce);
801
                }
802
        }
803

    
804
        /**
805
         * <p>Notifies to all view port listeners registered, that the projection of this view port
806
         *  has changed.</p>
807
         *
808
         * @param projection the new projection
809
         *
810
         * @see #setProjection(IProjection)
811
         * @see ProjectionEvent
812
         * @see ViewPortListener
813
         */
814
        private void callProjectionChanged(IProjection projection) {
815
                ProjectionEvent ev = ProjectionEvent.createProjectionEvent(projection);
816

    
817
                for (int i = 0; i < listeners.size(); i++) {
818
                        ViewPortListener listener = (ViewPortListener) listeners.get(i);
819
                        listener.projectionChanged(ev);
820
                }
821
        }
822

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

    
853
                AffineTransform escalado = new AffineTransform();
854
                AffineTransform translacion = new AffineTransform();
855

    
856
                double escalaX;
857
                double escalaY;
858

    
859
                escalaX = imageSize.getWidth() / extent.getWidth();
860
                escalaY = imageSize.getHeight() / extent.getHeight();
861

    
862
                double xCenter = extent.getCenterX();
863
                double yCenter = extent.getCenterY();
864
                double newHeight;
865
                double newWidth;
866

    
867
                adjustedExtent = new Rectangle2D.Double();
868

    
869
                if (adjustableExtent) {
870
                        // If is enabled the adjustable extent mode:
871
                        // the new 'adjustedExtent' will have the (X, Y) coordinates of the 'extent' and
872
                        // an area that will be an scale of the image size according the projection. That area will have different
873
                        // height or width (not both) of the extent according the least ratio image.size/extent.size
874
                        // The least ratio (height or width) will be used to calculate the other size value of the
875
                        // new 'adjustedExtent'
876
                        if (escalaX < escalaY) {
877
                                scale = escalaX;
878
                                newHeight = imageSize.getHeight() / scale;
879
                                adjustedExtent.setRect(xCenter - (extent.getWidth() / 2.0),
880
                                        yCenter - (newHeight / 2.0), extent.getWidth(), newHeight);
881
                        } else {
882
                                scale = escalaY;
883
                                newWidth = imageSize.getWidth() / scale;
884
                                adjustedExtent.setRect(xCenter - (newWidth / 2.0),
885
                                        yCenter - (extent.getHeight() / 2.0), newWidth,
886
                                        extent.getHeight());
887
                        }
888
                        escalado.setToScale(scale, -scale);
889
                }
890
                else { // adjusted is same as extent
891
                        scale = escalaX;
892
                        adjustedExtent.setFrame(extent);
893
                        escalado.setToScale(escalaX, -escalaY);
894
                }
895

    
896
                translacion.setToTranslation(-getAdjustedExtent().getX(),
897
                        -getAdjustedExtent().getY() - getAdjustedExtent().getHeight());
898

    
899
                AffineTransform offsetTrans = new AffineTransform();
900
                offsetTrans.setToTranslation(offset.getX(), offset.getY());
901

    
902
                trans.setToIdentity();
903
                trans.concatenate(offsetTrans);
904
                trans.concatenate(escalado);
905

    
906
                trans.concatenate(translacion);
907

    
908
                // Calculamos las distancias de 1 pixel y 3 pixel con esa transformaci?n
909
                // de coordenadas, de forma que est?n precalculadas para cuando las necesitemos
910
                AffineTransform at;
911

    
912
                try {
913
                        at = trans.createInverse();
914

    
915
                        java.awt.Point pPixel = new java.awt.Point(1, 1);
916
                        Point2D.Float pProv = new Point2D.Float();
917
                        at.deltaTransform(pPixel, pProv);
918

    
919
                        dist1pixel = pProv.x;
920
                        dist3pixel = 3 * pProv.x;
921
                } catch (NoninvertibleTransformException e) {
922
                        System.err.println("transformada afin = " + trans.toString());
923
                        System.err.println("extent = " + extent.toString() +
924
                                " imageSize= " + imageSize.toString());
925
                        throw new RuntimeException(e);
926
                }
927
        }
928

    
929
        /**
930
         * <p>Sets the offset.</p>
931
         * <p>The offset is the position where start drawing the map.</p>
932
         *
933
         * @param p 2D point that represents the offset in pixels
934
         *
935
         * @see #getOffset()
936
         */
937
        public void setOffset(Point2D p) {
938
                offset = p;
939
        }
940

    
941
        /**
942
         * <p>Gets the offset.</p>
943
         * <p>The offset is the position where start drawing the map.</p>
944
         *
945
         * @return 2D point that represents the offset in pixels
946
         *
947
         * @see #setOffset(Point2D)
948
         */
949
        public Point2D getOffset() {
950
                return offset;
951
        }
952

    
953
        /**
954
         * <p>Sets the background color.</p>
955
         *
956
         * @param c the new background color
957
         *
958
         * @see #getBackColor()
959
         */
960
        public void setBackColor(Color c) {
961
                backColor = c;
962
                callColorChanged(backColor);
963
        }
964

    
965
        /**
966
         * <p>Gets the background color.</p>
967
         *
968
         * @return the background color of the view
969
         *
970
         * @see #setBackColor(Color)
971
         */
972
        public Color getBackColor() {
973
                return backColor;
974
        }
975

    
976
        /**
977
         * <p>Returns the extent currently covered by the view adjusted (scaled) to the image size aspect.</p>
978
         *
979
         * @return extent of the view adjusted to the image size aspect
980
         *
981
         * @see #setAdjustable(boolean)
982
         */
983
        public Rectangle2D getAdjustedExtent() {
984
                if (cliprect!=null){
985
                        return adjustedExtent.createIntersection(cliprect);
986
                }
987
                return adjustedExtent;
988
        }
989

    
990
        /**
991
         * <p>Returns the measurement unit of this view port used for measuring distances and displaying information.</p>
992
         *
993
         * @return the measurement unit of this view used for measuring distances and displaying information
994
         *
995
         * @see #setDistanceUnits(int)
996
         */
997
        public int getDistanceUnits() {
998
                return distanceUnits;
999
        }
1000
        /**
1001
         * <p>Returns the measurement unit of this view port used for measuring areas and displaying information.</p>
1002
         *
1003
         * @return the measurement unit of this view used for measuring areas and displaying information
1004
         *
1005
         * @see #setDistanceUnits(int)
1006
         */
1007
        public int getDistanceArea() {
1008
                return distanceArea;
1009
        }
1010

    
1011

    
1012
        /**
1013
         * <p>Sets the measurement unit of this view port used for measuring distances and displaying information.</p>
1014
         *
1015
         * @param distanceUnits the measurement unit of this view used for measuring distances and displaying information
1016
         *
1017
         * @see #getDistanceUnits()
1018
         */
1019
        public void setDistanceUnits(int distanceUnits) {
1020
                this.distanceUnits = distanceUnits;
1021
        }
1022
        /**
1023
         * <p>Sets the measurement unit of this view port used for measuring areas and displaying information.</p>
1024
         *
1025
         * @param distanceUnits the measurement unit of this view used for measuring areas and displaying information
1026
         *
1027
         * @see #getDistanceUnits()
1028
         */
1029
        public void setDistanceArea(int distanceArea) {
1030
                this.distanceArea = distanceArea;
1031
        }
1032

    
1033
        /**
1034
         * <p>Gets the measurement unit used by this view port for the map.</p>
1035
         *
1036
         * @return Returns the current map measure unit
1037
         *
1038
         * @see #setMapUnits(int)
1039
         */
1040
        public int getMapUnits() {
1041
                return mapUnits;
1042
        }
1043

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1255
                if (adjustedExtent != null) {
1256
                        xml.putProperty("adjustedExtentX", adjustedExtent.getX());
1257
                        xml.putProperty("adjustedExtentY", adjustedExtent.getY());
1258
                        xml.putProperty("adjustedExtentW", adjustedExtent.getWidth());
1259
                        xml.putProperty("adjustedExtentH", adjustedExtent.getHeight());
1260
                }
1261

    
1262
                if (backColor != null)
1263
                    xml.putProperty("backColor", StringUtilities.color2String(backColor));
1264

    
1265
                if (clip != null) {
1266
                        xml.putProperty("clipX", clip.getX());
1267
                        xml.putProperty("clipY", clip.getY());
1268
                        xml.putProperty("clipW", clip.getWidth());
1269
                        xml.putProperty("clipH", clip.getHeight());
1270
                }
1271

    
1272
                xml.putProperty("dist1pixel", dist1pixel);
1273
                xml.putProperty("dist3pixel", dist3pixel);
1274
                xml.putProperty("distanceUnits", distanceUnits);
1275

    
1276
                if (extent != null) {
1277
                        xml.putProperty("extentX", extent.getX());
1278
                        xml.putProperty("extentY", extent.getY());
1279
                        xml.putProperty("extentW", extent.getWidth());
1280
                        xml.putProperty("extentH", extent.getHeight());
1281
                }
1282

    
1283
                xml.addChild(extents.getXMLEntity());
1284
                xml.putProperty("mapUnits", mapUnits);
1285
                xml.putProperty("offsetX", offset.getX());
1286
                xml.putProperty("offsetY", offset.getY());
1287

    
1288
                if (proj != null) {
1289
                        xml.putProperty("proj", proj.getAbrev());
1290
                }
1291

    
1292
                xml.putProperty("scale", scale);
1293

    
1294
                return xml;
1295
        }
1296

    
1297
        /**
1298
         * <p>Creates a new <code>ViewPort</code> from an XML entity.</p>
1299
         *
1300
         * @param xml an XML entity
1301
         *
1302
         * @return the new <code>ViewPort</code>
1303
         *
1304
         * @see #getXMLEntity()
1305
         * @see #createFromXML(XMLEntity)
1306
         */
1307
        public static ViewPort createFromXML03(XMLEntity xml) {
1308
                ViewPort vp = new ViewPort(null);
1309

    
1310
                if (xml.contains("adjustedExtentX")) {
1311
                        vp.adjustedExtent = new Rectangle2D.Double(xml.getDoubleProperty(
1312
                                                "adjustedExtentX"),
1313
                                        xml.getDoubleProperty("adjustedExtentY"),
1314
                                        xml.getDoubleProperty("adjustedExtentW"),
1315
                                        xml.getDoubleProperty("adjustedExtentH"));
1316
                }
1317

    
1318
                if (xml.contains("backColor")) {
1319
                        vp.setBackColor(StringUtilities.string2Color(xml.getStringProperty(
1320
                                                "backColor")));
1321
                }
1322

    
1323
                if (xml.contains("clipX")) {
1324
                        vp.clip = new Rectangle2D.Double(xml.getDoubleProperty("clipX"),
1325
                                        xml.getDoubleProperty("clipY"),
1326
                                        xml.getDoubleProperty("clipW"),
1327
                                        xml.getDoubleProperty("clipH"));
1328
                }
1329

    
1330
                vp.setDist1pixel(xml.getDoubleProperty("dist1pixel"));
1331
                vp.setDist3pixel(xml.getDoubleProperty("dist3pixel"));
1332
                vp.setDistanceUnits(xml.getIntProperty("distanceUnits"));
1333
                vp.extents = ExtentHistory.createFromXML03(xml.getChild(0));
1334

    
1335
                if (xml.contains("extentX")) {
1336
                        vp.setExtent(new Rectangle2D.Double(xml.getDoubleProperty("extentX"),
1337
                                        xml.getDoubleProperty("extentY"),
1338
                                        xml.getDoubleProperty("extentW"),
1339
                                        xml.getDoubleProperty("extentH")));
1340

    
1341
                        //Calcula la transformaci?n af?n
1342
                        vp.calculateAffineTransform();
1343

    
1344
                        // Lanzamos los eventos de extent cambiado
1345
                        // vp.callExtentListeners(vp.adjustedExtent);
1346
                }
1347

    
1348
                vp.setMapUnits(xml.getIntProperty("mapUnits"));
1349
                vp.setOffset(new Point2D.Double(xml.getDoubleProperty("offsetX"),
1350
                                xml.getDoubleProperty("offsetY")));
1351

    
1352
                if (xml.contains("proj")) {
1353
                        vp.proj = CRSFactory.getCRS(xml.getStringProperty("proj"));
1354
                }
1355

    
1356
                //vp.setScale(xml.getDoubleProperty("scale"));
1357
                vp.refreshExtent();
1358
                return vp;
1359
        }
1360

    
1361
        /**
1362
         * <p>Creates a new <code>ViewPort</code> from an XML entity.</p>
1363
         *
1364
         * @param xml an XML entity
1365
         *
1366
         * @return the new <code>ViewPort</code>
1367
         *
1368
         * @see #getXMLEntity()
1369
         * @see #createFromXML03(XMLEntity)
1370
         */
1371
        public static ViewPort createFromXML(XMLEntity xml) {
1372
                ViewPort vp = new ViewPort(null);
1373

    
1374
                if (xml.contains("adjustedExtentX")) {
1375
                        vp.adjustedExtent = new Rectangle2D.Double(xml.getDoubleProperty(
1376
                                                "adjustedExtentX"),
1377
                                        xml.getDoubleProperty("adjustedExtentY"),
1378
                                        xml.getDoubleProperty("adjustedExtentW"),
1379
                                        xml.getDoubleProperty("adjustedExtentH"));
1380
                }
1381

    
1382
                if (xml.contains("backColor")) {
1383
                        vp.setBackColor(StringUtilities.string2Color(xml.getStringProperty(
1384
                                                "backColor")));
1385
                }else {
1386
                        vp.setBackColor(Color.white);
1387
                }
1388

    
1389
                if (xml.contains("clipX")) {
1390
                        vp.clip = new Rectangle2D.Double(xml.getDoubleProperty("clipX"),
1391
                                        xml.getDoubleProperty("clipY"),
1392
                                        xml.getDoubleProperty("clipW"),
1393
                                        xml.getDoubleProperty("clipH"));
1394
                }
1395

    
1396
                vp.setDist1pixel(xml.getDoubleProperty("dist1pixel"));
1397
                vp.setDist3pixel(xml.getDoubleProperty("dist3pixel"));
1398
                vp.setDistanceUnits(xml.getIntProperty("distanceUnits"));
1399
                if (xml.contains("distanceArea")){
1400
                        vp.setDistanceArea(xml.getIntProperty("distanceArea"));
1401
                }else{
1402
                        vp.setDistanceArea(xml.getIntProperty("distanceUnits"));
1403
                }
1404
                vp.extents = ExtentHistory.createFromXML(xml.getChild(0));
1405

    
1406
                if (xml.contains("extentX")) {
1407
                        vp.setExtent(new Rectangle2D.Double(xml.getDoubleProperty("extentX"),
1408
                                        xml.getDoubleProperty("extentY"),
1409
                                        xml.getDoubleProperty("extentW"),
1410
                                        xml.getDoubleProperty("extentH")));
1411

    
1412
                        //Calcula la transformaci?n af?n
1413
                        vp.calculateAffineTransform();
1414

    
1415
                        // Lanzamos los eventos de extent cambiado
1416
                        // vp.callExtentListeners(vp.adjustedExtent);
1417
                }
1418

    
1419
                vp.setMapUnits(xml.getIntProperty("mapUnits"));
1420
                vp.setOffset(new Point2D.Double(xml.getDoubleProperty("offsetX"),
1421
                                xml.getDoubleProperty("offsetY")));
1422

    
1423
                if (xml.contains("proj")) {
1424
                        vp.proj = CRSFactory.getCRS(xml.getStringProperty("proj"));
1425
                }
1426

    
1427
                //vp.setScale(xml.getDoubleProperty("scale"));
1428
                vp.refreshExtent();
1429
                return vp;
1430
        }
1431

    
1432
        /**
1433
         * <p>Fast clone implementation: creates and returns a clone of this view port using XML entities.</p>
1434
         * <p>Isn't a <i>deepclone</i> to avoid unnecessary memory consumption.</p>
1435
         *
1436
         * @return the new view port
1437
         *
1438
         * @see #createFromXML(XMLEntity)
1439
         */
1440
        public ViewPort cloneViewPort() {
1441
                return createFromXML(getXMLEntity());
1442
        }
1443

    
1444
        /**
1445
         * <p>Returns a <code>String</code> representation of the main values of this view port: <code>{@linkplain #extent}</code>,
1446
         *  <code>{@linkplain #adjustedExtent}</code>, <code>{@linkplain #imageSize}</code>, <code>{@linkplain #scale}</code>, and <code>{@linkplain #trans}</code>.</p>
1447
         *
1448
         * @return a <code>string</code> representation of the main values of this view port
1449
         */
1450
        public String toString() {
1451

    
1452
                String str;
1453
                str = "Datos del viewPort:\nExtent=" + extent + "\nadjustedExtent=" +
1454
                        adjustedExtent + "\nimageSize=" + imageSize + "\nescale=" + scale +
1455
                        "\ntrans=" + trans;
1456

    
1457
                return str;
1458
        }
1459

    
1460
        /**
1461
         * <p>Sets the position and size of the clipping rectangle.</p>
1462
         *
1463
         * @param rectView the clipping rectangle to set
1464
         */
1465
        public void setClipRect(Rectangle2D rectView) {
1466
                cliprect=rectView;
1467
        }
1468
}