Statistics
| Revision:

svn-gvsig-desktop / branches / v10 / libraries / libFMap / src / com / iver / cit / gvsig / fmap / ViewPort.java @ 20100

History | View | Annotate | Download (43.9 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
        /**
325
         * <p>Creates a new view port with the information of the projection in <code>proj</code> argument, and
326
         *  default configuration:</p>
327
         * <p>
328
         * <ul>
329
         *  <li><i><code>distanceUnits</code></i> = meters
330
         *  <li><i><code>mapUnits</code></i> = meters
331
         *  <li><i><code>backColor</code></i> = <i>undefined</i>
332
         *  <li><i><code>offset</code></i> = <code>new Point2D.Double(0, 0);</code>
333
         * </ul>
334
         * </p>
335
         *
336
         * @param proj information of the projection for this view port
337
         */
338
        public ViewPort(IProjection proj) {
339
                // Por defecto
340
                this.proj = proj;
341
        }
342

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

    
356
        /**
357
         * <p>Appends the specified {@link ViewPortListener ViewPortListener} listener if weren't.</p>
358
         * 
359
         * @param arg0 the listener to add
360
         *
361
         * @return <code>true</code> if has been added successfully
362
         * 
363
         * @see #removeViewPortListener(ViewPortListener)
364
         */
365
        public boolean addViewPortListener(ViewPortListener arg0) {
366
                if (!listeners.contains(arg0))
367
                        return listeners.add(arg0);
368
                return false;
369
        }
370

    
371
        /**
372
          * <p>Removes the specified {@link ViewPortListener ViewPortListener} listener, if existed.</p>
373
         * 
374
         * @param arg0 the listener to remove
375
         * 
376
         * @return <code>true</code> if the contained the specified listener.
377
         * 
378
         * @see #addViewPortListener(ViewPortListener)
379
         */
380
        public boolean removeViewPortListener(ViewPortListener arg0) {
381
                return listeners.remove(arg0);
382
        }
383

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

    
400
                try {
401
                        trans.deltaTransform(pWorld, pScreen);
402
                } catch (Exception e) {
403
                        System.err.print(e.getMessage());
404
                }
405

    
406
                return (int) (d * pScreen.x);
407
        }
408

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

    
424
                return dist;
425
        }
426

    
427
        /**
428
         * <p>Converts and returns the {@link Rectangle2D Rectangle2D}, that is in <i>map
429
         *  coordinates</i> to <i>screen coordinates</i> (pixels) using an <i>inverse transform</i> with
430
         *  the transformation affine information in the {@link #trans #trans} attribute.</p>
431
         * 
432
         * @param r the 2D rectangle in <i>map coordinates</i>
433
         * @return 2D rectangle equivalent in <i>screen coordinates</i> (pixels)
434
         * 
435
         * @see #toMapRectangle(Rectangle2D)
436
         * @see #fromMapDistance(double)
437
         * @see #fromMapPoint(Point2D)
438
         */
439
        public Rectangle2D fromMapRectangle(Rectangle2D r) {
440
                double w=fromMapDistance((int)r.getWidth());
441
                double h=fromMapDistance((int)r.getHeight());
442
                Point2D p1=fromMapPoint((int)r.getX(),(int)r.getY());
443
                return new Rectangle2D.Double(p1.getX(),p1.getY(),w,h);
444
        }
445
        
446
        /**
447
         * <p>Converts and returns the {@link Rectangle2D Rectangle2D}, that is in <i>screen
448
         *  coordinates</i> (pixels) to <i>map coordinates</i> using {@linkplain #toMapDistance(int)},
449
         *  and {@linkplain #toMapPoint(int, int)}.</p>
450
         * 
451
         * @param r the 2D rectangle in <i>screen coordinates</i> (pixels)
452
         * @return 2D rectangle equivalent in <i>map coordinates</i>
453
         * 
454
         * @see #fromMapRectangle(Rectangle2D)
455
         * @see #toMapDistance(int)
456
         * @see #toMapPoint(int, int)
457
         */
458
        public Rectangle2D toMapRectangle(Rectangle2D r){
459
                double w=toMapDistance((int)r.getWidth());
460
                double h=toMapDistance((int)r.getHeight());
461
                Point2D p1=toMapPoint((int)r.getX(),(int)r.getY());
462
                return new Rectangle2D.Double(p1.getX(),p1.getY(),w,h);
463
        }
464
        
465
        /**
466
         * <p>Converts and returns the 2D point <code>(x,y)</code>, that is in <i>map
467
         *  coordinates</i> to <i>screen coordinates</i> (pixels) using 
468
         *  the affine transformation in the {@link #trans #trans} attribute.</p>
469
         *
470
         * @param x the <code>x</code> <i>map coordinate</i> of a 2D point
471
         * @param y the <code>y</code> <i>map coordinate</i> of a 2D point
472
         *
473
         * @return 2D point equivalent in <i>screen coordinates</i> (pixels)
474
         * 
475
         * @see #fromMapPoint(Point2D)
476
         * @see AffineTransform#transform(Point2D, Point2D)
477
         */
478
        public Point2D fromMapPoint(double x, double y) {
479
                Point2D.Double pWorld = new Point2D.Double(x, y);
480
                Point2D.Double pScreen = new Point2D.Double();
481

    
482
                try {
483
                        trans.transform(pWorld, pScreen);
484
                } catch (Exception e) {
485
                        System.err.print(e.getMessage());
486
                }
487

    
488
                return pScreen;
489
        }
490

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

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

    
523
                return toMapPoint(pScreen);
524
        }
525

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

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

    
569
                if ((proj != null) && !(proj instanceof CSUTM)) {
570
                        dist = new GeoCalc(proj).distanceVincenty(proj.toGeo(pt1),
571
                                        proj.toGeo(pt2));
572
                }
573

    
574
                return dist*MapContext.CHANGEM[getMapUnits()];
575
        }
576

    
577
        /**
578
         * <p>Sets as extent and adjusted extent of this view port, the previous. Recalculating
579
         *  its parameters.</p>
580
         * 
581
         * @see #getExtents()
582
         * @see #calculateAffineTransform()
583
         */
584
        public void setPreviousExtent() {
585
                extent = extents.removePrev();
586

    
587
                //Calcula la transformaci?n af?n
588
                calculateAffineTransform();
589

    
590
                // Lanzamos los eventos de extent cambiado
591
                callExtentChanged(getAdjustedExtent());
592
        }
593

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

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

    
641
                //Esto comprueba que el extent no es de anchura o altura = "0"
642
                //y si es as? lo redimensiona.
643
                if (r!=null &&((r.getWidth() == 0) || (r.getHeight() == 0))) {
644
                        extent = new Rectangle2D.Double(r.getMinX() - 0.1,
645
                                        r.getMinY() - 0.1, r.getWidth() + 0.2, r.getHeight() + 0.2);
646
                } else {
647
                        extent = r;
648
                }
649

    
650
                //Calcula la transformaci?n af?n
651
                calculateAffineTransform();
652

    
653
                // Lanzamos los eventos de extent cambiado
654
                callExtentChanged(getAdjustedExtent());
655
        }
656

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

    
672
                //Calcula la transformaci?n af?n
673
                calculateAffineTransform();
674

    
675
                // Lanzamos los eventos de extent cambiado
676
                callExtentChanged(getAdjustedExtent());
677
        }
678

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

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

    
707
                double x1 = (-x * difw) -
708
            x+
709
            extent.getWidth()/2;
710
        double y1 = (-y * difw) -
711
            y +
712
            extent.getHeight()/2;
713
        double w1=extent.getWidth()*difw;
714
        double h1=extent.getHeight()*difw;
715
                extent.setRect(-x1,-y1,w1,h1);
716
        }        
717

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

    
731
        /**
732
         * <p>Returns the size of the image projected.</p>
733
         *
734
         * @return the image size
735
         * 
736
         * @see #setImageSize(Dimension)
737
         * @see #getImageHeight()
738
         * @see #getImageWidth()
739
         */
740
        public Dimension getImageSize() {
741
                return imageSize;
742
        }
743

    
744
        /**
745
         * <p>Sets the size of the image projected, recalculating the parameters of this view port.</p>
746
         *
747
         * @param imageSize the image size
748
         * 
749
         * @see #getImageSize()
750
         * @see #calculateAffineTransform()
751
         */
752
        public void setImageSize(Dimension imageSize) {
753
                this.imageSize = imageSize;
754
                calculateAffineTransform();
755
        }
756

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

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

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

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

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

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

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

    
846
                AffineTransform escalado = new AffineTransform();
847
                AffineTransform translacion = new AffineTransform();
848

    
849
                double escalaX;
850
                double escalaY;
851

    
852
                escalaX = imageSize.getWidth() / extent.getWidth();
853
                escalaY = imageSize.getHeight() / extent.getHeight();
854

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

    
860
                adjustedExtent = new Rectangle2D.Double();
861

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

    
889
                translacion.setToTranslation(-getAdjustedExtent().getX(),
890
                        -getAdjustedExtent().getY() - getAdjustedExtent().getHeight());
891

    
892
                AffineTransform offsetTrans = new AffineTransform();
893
                offsetTrans.setToTranslation(offset.getX(), offset.getY());
894

    
895
                trans.setToIdentity();
896
                trans.concatenate(offsetTrans);
897
                trans.concatenate(escalado);
898

    
899
                trans.concatenate(translacion);
900

    
901
                // Calculamos las distancias de 1 pixel y 3 pixel con esa transformaci?n
902
                // de coordenadas, de forma que est?n precalculadas para cuando las necesitemos
903
                AffineTransform at;
904

    
905
                try {
906
                        at = trans.createInverse();
907

    
908
                        java.awt.Point pPixel = new java.awt.Point(1, 1);
909
                        Point2D.Float pProv = new Point2D.Float();
910
                        at.deltaTransform(pPixel, pProv);
911

    
912
                        dist1pixel = pProv.x;
913
                        dist3pixel = 3 * pProv.x;
914
                } catch (NoninvertibleTransformException e) {
915
                        System.err.println("transformada afin = " + trans.toString());
916
                        System.err.println("extent = " + extent.toString() +
917
                                " imageSize= " + imageSize.toString());
918
                        throw new RuntimeException(e);
919
                }
920
        }
921

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

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

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

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

    
969
        /**
970
         * <p>Returns the extent currently covered by the view adjusted (scaled) to the image size aspect.</p>
971
         * 
972
         * @return extent of the view adjusted to the image size aspect
973
         * 
974
         * @see #setAdjustable(boolean)
975
         */
976
        public Rectangle2D getAdjustedExtent() {
977
                if (cliprect!=null){
978
                        return adjustedExtent.createIntersection(cliprect);
979
                }
980
                return adjustedExtent;
981
        }
982

    
983
        /**
984
         * <p>Returns the measurement unit of this view port used for measuring distances and displaying information.</p>
985
         *
986
         * @return the measurement unit of this view used for measuring distances and displaying information
987
         * 
988
         * @see #setDistanceUnits(int)
989
         */
990
        public int getDistanceUnits() {
991
                return distanceUnits;
992
        }
993

    
994
        /**
995
         * <p>Sets the measurement unit of this view port used for measuring distances and displaying information.</p>
996
         *
997
         * @param distanceUnits the measurement unit of this view used for measuring distances and displaying information
998
         * 
999
         * @see #getDistanceUnits()
1000
         */
1001
        public void setDistanceUnits(int distanceUnits) {
1002
                this.distanceUnits = distanceUnits;
1003
        }
1004

    
1005
        /**
1006
         * <p>Gets the measurement unit used by this view port for the map.</p>
1007
         *
1008
         * @return Returns the current map measure unit
1009
         * 
1010
         * @see #setMapUnits(int)
1011
         */
1012
        public int getMapUnits() {
1013
                return mapUnits;
1014
        }
1015

    
1016
        /**
1017
         * <p>Sets the measurement unit used by this view port for the map.</p>
1018
         *
1019
         * @param mapUnits the new map measure unit
1020
         * 
1021
         * @see #getMapUnits()
1022
         */
1023
        public void setMapUnits(int mapUnits) {
1024
                this.mapUnits = mapUnits;
1025
        }
1026

    
1027
        /**
1028
         * <p>Gets the width in <i>screen coordinates</i> of the rectangle where the image is displayed.</p>
1029
         * <p>Used by {@linkplain #calculateAffineTransform()} to calculate:<br>
1030
           * 
1031
         * <ul>
1032
         * <li>The new {@link #scale scale} .
1033
         * <li>The new {@link #adjustedExtent adjustableExtent} .
1034
         * <li>The new {@link #trans trans} .
1035
         * <li>The new real world coordinates equivalent to 1 pixel ({@link #dist1pixel dist1pixel}) .
1036
         * <li>The new real world coordinates equivalent to 3 pixels ({@link #dist3pixel dist3pixel}) .
1037
         * </ul>
1038
         * </p>
1039
         * 
1040
         * @see #getImageHeight()
1041
         * @see #getImageSize()
1042
         * @see #setImageSize(Dimension)
1043
         */
1044
        public int getImageWidth() {
1045
                return imageSize.width;
1046
        }
1047

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

    
1069
        /**
1070
         * <p>Gets the distance in <i>world coordinates</i> equivalent to 1 pixel in the view with the current extent.</p> 
1071
         *
1072
         * @return the distance
1073
         * 
1074
         * @see #setDist1pixel(double)
1075
         */
1076
        public double getDist1pixel() {
1077
                return dist1pixel;
1078
        }
1079

    
1080
        /**
1081
         * <p>Sets the distance in <i>world coordinates</i> equivalent to 1 pixel in the view with the current extent.</p> 
1082
         *
1083
         * @param dist1pixel the distance
1084
         * 
1085
         * @see #getDist1pixel()
1086
         */
1087
        public void setDist1pixel(double dist1pixel) {
1088
                this.dist1pixel = dist1pixel;
1089
        }
1090

    
1091
        /**
1092
         * <p>Gets the distance in <i>world coordinates</i> equivalent to 3 pixels in the view with the current extent.</p> 
1093
         *
1094
         * @return the distance
1095
         * 
1096
         * @see #setDist3pixel(double)
1097
         */
1098
        public double getDist3pixel() {
1099
                return dist3pixel;
1100
        }
1101

    
1102
        /**
1103
         * <p>Sets the distance in <i>world coordinates</i> equivalent to 3 pixels in the view with the current extent.</p> 
1104
         *
1105
         * @param dist3pixel the distance
1106
         * 
1107
         * @see #getDist3pixel()
1108
         */
1109
        public void setDist3pixel(double dist3pixel) {
1110
                this.dist3pixel = dist3pixel;
1111
        }
1112

    
1113
        /**
1114
         * <p>Returns the last previous extents of this view port.</p>
1115
         *
1116
         * @return the last previous extents of this view port
1117
         * 
1118
         * @see #setPreviousExtent()
1119
         */
1120
        public ExtentHistory getExtents() {
1121
                return extents;
1122
        }
1123

    
1124
        /**
1125
         * <p>Gets the projection used in this view port.</p>
1126
         *
1127
         * @return projection used in this view port
1128
         * 
1129
         * @see #setProjection(IProjection)
1130
         */
1131
        public IProjection getProjection() {
1132
                return proj;
1133
        }
1134

    
1135
        /**
1136
         * <p>Sets the projection to this view port.</p>
1137
         *
1138
         * @param proj the new projection
1139
         * 
1140
         * @see #getProjection()
1141
         */
1142
        public void setProjection(IProjection proj) {
1143
                if(this.proj == null || !this.proj.getAbrev().equals(proj.getAbrev())) {
1144
                        this.proj = proj;
1145
                        callProjectionChanged(proj);
1146
                }
1147
        }
1148

    
1149
//    -----------------------------------------------------------------------------------------------------------
1150
//    NOTA PARA DESARROLLADORES SOBRE EL M?TODO "public void setAffineTransform(AffineTransform at)"
1151
//    ==============================================================================================
1152
//          Only used for print, should be removed, redefining the {@link RasterAdapter RasterAdapter} interface,
1153
//           allowing it to receive a {@link ViewPortData ViewPortData} .
1154
//    -----------------------------------------------------------------------------------------------------------
1155

    
1156
        /**
1157
         * <p>Sets only the affine transform to this view port, without updating dependent attributes.</p>
1158
         * <p><b><i>This method could be problematic!</i></b></p>
1159
         *
1160
         * @param at the affine transform to set
1161
         * 
1162
         * @see #getAffineTransform()
1163
         * @see #calculateAffineTransform()
1164
         */
1165
        public void setAffineTransform(AffineTransform at)
1166
        {
1167
            this.trans = at;
1168
        }
1169

    
1170
        /**
1171
         * <p>Returns an XML entity that represents this view port instance:<br>
1172
         * <ul>
1173
         * <li>Properties:
1174
         *  <ul>
1175
         *  <li><i>className</i>: name of this class.
1176
         *  <li>If defined, the adjusted extent:
1177
         *   <ul>
1178
         *   <li><i>adjustedExtentX</i>: X coordinate of the adjusted extent. 
1179
         *   <li><i>adjustedExtentY</i>: Y coordinate of the adjusted extent.
1180
         *   <li><i>adjustedExtentW</i>: width of the adjusted extent.
1181
         *   <li><i>adjustedExtentH</i>: height of the adjusted extent.
1182
         *   </ul> 
1183
         *  <li>If defined, the background color:
1184
         *   <ul>
1185
         *   <li><i>backColor</i>: background color.
1186
         *   </ul> 
1187
         *  <li>If defined, the clip:
1188
         *   <ul>
1189
         *   <li><i>clipX</i>: X coordinate of the clip. 
1190
         *   <li><i>clipY</i>: Y coordinate of clip.
1191
         *   <li><i>clipW</i>: width of the clip.
1192
         *   <li><i>clipH</i>: height of the clip.
1193
         *   </ul> 
1194
         *  <li><i>dist1pixel</i>: the distance in world coordinates equivalent to 1 pixel in the view.
1195
         *  <li><i>dist3pixel</i>: the distance in world coordinates equivalent to 3 pixels in the view.
1196
         *  <li><i>distanceUnits</i>: the distance measurement unit.
1197
         *  <li>If defined, the extent:
1198
         *   <ul>
1199
         *   <li><i>extentX</i>: X coordinate of the extent. 
1200
         *   <li><i>extentY</i>: Y coordinate of the extent.
1201
         *   <li><i>extentW</i>: width of the extent.
1202
         *   <li><i>extentH</i>: height of the extent.
1203
         *   </ul> 
1204
         *  <li><i>mapUnits</i>: the map measurement unit. 
1205
         *  <li><i>offsetX</i>: X coordinate of the offset.
1206
         *  <li><i>offsetY</i>: Y coordinate of the offset. 
1207
         *  <li>If defined, the projection:
1208
         *   <ul>
1209
         *   <li><i>proj</i>: the projection.
1210
         *   </ul> 
1211
         *  <li><i>scale</i>: ratio between the size of <code>imageSize</code> and <code>extent</code>.
1212
         *  </ul>
1213
         * <li>Child branches:
1214
         *  <ul>
1215
         *  <li>XML entity of the internal {@link ExtentHistory ExtentHistory} .
1216
         *  </ul>
1217
         * </ul>
1218
         * 
1219
         * @return the XML entity
1220
         * 
1221
         * @see #createFromXML(XMLEntity)
1222
         */
1223
        public XMLEntity getXMLEntity() {
1224
                XMLEntity xml = new XMLEntity();
1225
                xml.putProperty("className",this.getClass().getName());
1226

    
1227
                if (adjustedExtent != null) {
1228
                        xml.putProperty("adjustedExtentX", adjustedExtent.getX());
1229
                        xml.putProperty("adjustedExtentY", adjustedExtent.getY());
1230
                        xml.putProperty("adjustedExtentW", adjustedExtent.getWidth());
1231
                        xml.putProperty("adjustedExtentH", adjustedExtent.getHeight());
1232
                }
1233

    
1234
                if (backColor != null)
1235
                    xml.putProperty("backColor", StringUtilities.color2String(backColor));
1236

    
1237
                if (clip != null) {
1238
                        xml.putProperty("clipX", clip.getX());
1239
                        xml.putProperty("clipY", clip.getY());
1240
                        xml.putProperty("clipW", clip.getWidth());
1241
                        xml.putProperty("clipH", clip.getHeight());
1242
                }
1243

    
1244
                xml.putProperty("dist1pixel", dist1pixel);
1245
                xml.putProperty("dist3pixel", dist3pixel);
1246
                xml.putProperty("distanceUnits", distanceUnits);
1247

    
1248
                if (extent != null) {
1249
                        xml.putProperty("extentX", extent.getX());
1250
                        xml.putProperty("extentY", extent.getY());
1251
                        xml.putProperty("extentW", extent.getWidth());
1252
                        xml.putProperty("extentH", extent.getHeight());
1253
                }
1254

    
1255
                xml.addChild(extents.getXMLEntity());
1256
                xml.putProperty("mapUnits", mapUnits);
1257
                xml.putProperty("offsetX", offset.getX());
1258
                xml.putProperty("offsetY", offset.getY());
1259

    
1260
                if (proj != null) {
1261
                        xml.putProperty("proj", proj.getAbrev());
1262
                }
1263

    
1264
                xml.putProperty("scale", scale);
1265

    
1266
                return xml;
1267
        }
1268

    
1269
        /**
1270
         * <p>Creates a new <code>ViewPort</code> from an XML entity.</p>
1271
         *
1272
         * @param xml an XML entity
1273
         *
1274
         * @return the new <code>ViewPort</code>
1275
         * 
1276
         * @see #getXMLEntity()
1277
         * @see #createFromXML(XMLEntity)
1278
         */
1279
        public static ViewPort createFromXML03(XMLEntity xml) {
1280
                ViewPort vp = new ViewPort(null);
1281

    
1282
                if (xml.contains("adjustedExtentX")) {
1283
                        vp.adjustedExtent = new Rectangle2D.Double(xml.getDoubleProperty(
1284
                                                "adjustedExtentX"),
1285
                                        xml.getDoubleProperty("adjustedExtentY"),
1286
                                        xml.getDoubleProperty("adjustedExtentW"),
1287
                                        xml.getDoubleProperty("adjustedExtentH"));
1288
                }
1289

    
1290
                if (xml.contains("backColor")) {
1291
                        vp.setBackColor(StringUtilities.string2Color(xml.getStringProperty(
1292
                                                "backColor")));
1293
                }
1294

    
1295
                if (xml.contains("clipX")) {
1296
                        vp.clip = new Rectangle2D.Double(xml.getDoubleProperty("clipX"),
1297
                                        xml.getDoubleProperty("clipY"),
1298
                                        xml.getDoubleProperty("clipW"),
1299
                                        xml.getDoubleProperty("clipH"));
1300
                }
1301

    
1302
                vp.setDist1pixel(xml.getDoubleProperty("dist1pixel"));
1303
                vp.setDist3pixel(xml.getDoubleProperty("dist3pixel"));
1304
                vp.setDistanceUnits(xml.getIntProperty("distanceUnits"));
1305
                vp.extents = ExtentHistory.createFromXML03(xml.getChild(0));
1306

    
1307
                if (xml.contains("extentX")) {
1308
                        vp.setExtent(new Rectangle2D.Double(xml.getDoubleProperty("extentX"),
1309
                                        xml.getDoubleProperty("extentY"),
1310
                                        xml.getDoubleProperty("extentW"),
1311
                                        xml.getDoubleProperty("extentH")));
1312

    
1313
                        //Calcula la transformaci?n af?n
1314
                        vp.calculateAffineTransform();
1315

    
1316
                        // Lanzamos los eventos de extent cambiado
1317
                        // vp.callExtentListeners(vp.adjustedExtent);
1318
                }
1319

    
1320
                vp.setMapUnits(xml.getIntProperty("mapUnits"));
1321
                vp.setOffset(new Point2D.Double(xml.getDoubleProperty("offsetX"),
1322
                                xml.getDoubleProperty("offsetY")));
1323

    
1324
                if (xml.contains("proj")) {
1325
                        vp.proj = CRSFactory.getCRS(xml.getStringProperty("proj"));
1326
                }
1327

    
1328
                //vp.setScale(xml.getDoubleProperty("scale"));
1329
                vp.refreshExtent();
1330
                return vp;
1331
        }
1332

    
1333
        /**
1334
         * <p>Creates a new <code>ViewPort</code> from an XML entity.</p>
1335
         *
1336
         * @param xml an XML entity
1337
         *
1338
         * @return the new <code>ViewPort</code>
1339
         * 
1340
         * @see #getXMLEntity()
1341
         * @see #createFromXML03(XMLEntity)
1342
         */
1343
        public static ViewPort createFromXML(XMLEntity xml) {
1344
                ViewPort vp = new ViewPort(null);
1345

    
1346
                if (xml.contains("adjustedExtentX")) {
1347
                        vp.adjustedExtent = new Rectangle2D.Double(xml.getDoubleProperty(
1348
                                                "adjustedExtentX"),
1349
                                        xml.getDoubleProperty("adjustedExtentY"),
1350
                                        xml.getDoubleProperty("adjustedExtentW"),
1351
                                        xml.getDoubleProperty("adjustedExtentH"));
1352
                }
1353

    
1354
                if (xml.contains("backColor")) {
1355
                        vp.setBackColor(StringUtilities.string2Color(xml.getStringProperty(
1356
                                                "backColor")));
1357
                }else {
1358
                        vp.setBackColor(Color.white);
1359
                }
1360

    
1361
                if (xml.contains("clipX")) {
1362
                        vp.clip = new Rectangle2D.Double(xml.getDoubleProperty("clipX"),
1363
                                        xml.getDoubleProperty("clipY"),
1364
                                        xml.getDoubleProperty("clipW"),
1365
                                        xml.getDoubleProperty("clipH"));
1366
                }
1367

    
1368
                vp.setDist1pixel(xml.getDoubleProperty("dist1pixel"));
1369
                vp.setDist3pixel(xml.getDoubleProperty("dist3pixel"));
1370
                vp.setDistanceUnits(xml.getIntProperty("distanceUnits"));
1371
                vp.extents = ExtentHistory.createFromXML(xml.getChild(0));
1372

    
1373
                if (xml.contains("extentX")) {
1374
                        vp.setExtent(new Rectangle2D.Double(xml.getDoubleProperty("extentX"),
1375
                                        xml.getDoubleProperty("extentY"),
1376
                                        xml.getDoubleProperty("extentW"),
1377
                                        xml.getDoubleProperty("extentH")));
1378

    
1379
                        //Calcula la transformaci?n af?n
1380
                        vp.calculateAffineTransform();
1381

    
1382
                        // Lanzamos los eventos de extent cambiado
1383
                        // vp.callExtentListeners(vp.adjustedExtent);
1384
                }
1385

    
1386
                vp.setMapUnits(xml.getIntProperty("mapUnits"));
1387
                vp.setOffset(new Point2D.Double(xml.getDoubleProperty("offsetX"),
1388
                                xml.getDoubleProperty("offsetY")));
1389

    
1390
                if (xml.contains("proj")) {
1391
                        vp.proj = CRSFactory.getCRS(xml.getStringProperty("proj"));
1392
                }
1393

    
1394
                //vp.setScale(xml.getDoubleProperty("scale"));
1395
                vp.refreshExtent();
1396
                return vp;
1397
        }
1398

    
1399
        /**
1400
         * <p>Fast clone implementation: creates and returns a clone of this view port using XML entities.</p>
1401
         * <p>Isn't a <i>deepclone</i> to avoid unnecessary memory consumption.</p>
1402
         *
1403
         * @return the new view port
1404
         * 
1405
         * @see #createFromXML(XMLEntity)
1406
         */
1407
        public ViewPort cloneViewPort() {
1408
                return createFromXML(getXMLEntity());
1409
        }
1410

    
1411
        /**
1412
         * <p>Returns a <code>String</code> representation of the main values of this view port: <code>{@linkplain #extent}</code>,
1413
         *  <code>{@linkplain #adjustedExtent}</code>, <code>{@linkplain #imageSize}</code>, <code>{@linkplain #scale}</code>, and <code>{@linkplain #trans}</code>.</p>
1414
         * 
1415
         * @return a <code>string</code> representation of the main values of this view port
1416
         */
1417
        public String toString() {
1418
                
1419
                String str;
1420
                str = "Datos del viewPort:\nExtent=" + extent + "\nadjustedExtent=" +
1421
                        adjustedExtent + "\nimageSize=" + imageSize + "\nescale=" + scale +
1422
                        "\ntrans=" + trans;
1423

    
1424
                return str;
1425
        }
1426

    
1427
        /**
1428
         * <p>Sets the position and size of the clipping rectangle.</p>
1429
         * 
1430
         * @param rectView the clipping rectangle to set
1431
         */
1432
        public void setClipRect(Rectangle2D rectView) {
1433
                cliprect=rectView;
1434
        }
1435
}