Statistics
| Revision:

root / tags / v1_1_Build_1014 / libraries / libFMap / src / com / iver / cit / gvsig / fmap / ViewPort.java @ 13593

History | View | Annotate | Download (43.7 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
import org.cresques.geo.ViewPortData;
57

    
58
import com.iver.cit.gvsig.fmap.crs.CRSFactory;
59
import com.iver.cit.gvsig.fmap.layers.RasterAdapter;
60
import com.iver.utiles.StringUtilities;
61
import com.iver.utiles.XMLEntity;
62

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

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

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

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

    
119
        /**
120
         * <p>The statute miles is a unit of length originated from a Statute of the English parliament in 1592 during
121
         *  the reign of Elizabeth I.as 5,280 feet or 1,760 yards; or 63,360 inches.</p> 
122
         */
123
        public static int MILLAS = 4;
124

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

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

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

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

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

    
154
        /**
155
         * <p>Area selected by user using some tool.</p>
156
         * 
157
         * <p>When the zoom changes (for instance when using the zoom in or zoom out tools,
158
         * but also zooming to a selected feature or shape) the extent that covers that
159
         * area is the value returned by this method. It is not the actual area shown
160
         * in the view because it does not care about the aspect ratio. However, any
161
         * part of the real world contained in this extent is shown 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()
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>Affine transformation between <i>map 2D coordinates</i> to <i>screen 2D coordinates</i> (pixels).</p>
212
         *  
213
         * @see AffineTransform
214
         * 
215
         * @see #getAffineTransform()
216
         * @see #setAffineTransform(AffineTransform)
217
         * @see #calculateAffineTransform()
218
         */
219
        private AffineTransform trans = new AffineTransform();
220

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

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

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

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

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

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

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

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

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

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

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

    
306
        /**
307
         * <p>Enables or disables the <i>"adjustable extent"</i> mode.</p>
308
         * 
309
         * <p>
310
         * When calculates the affine transform, if
311
         * <ul>
312
         * <li><i>enabled</i>: the new <code>adjustedExtent</code> will have the (X, Y) coordinates of the <code>extent</code> and
313
         *  an area that will be an scale of the image size. That area will have different.
314
         *  height or width (not both) of the extent according the least ratio (height or width) in <i>"image.size/extent.size"</i>.
315
         * <li><i>disabled</i>: the new <code>adjustedExtent</code> will be like <code>extent</code>.
316
         * </ul>
317
         * </p>
318
         * 
319
         * @see #setAdjustable(boolean)
320
         */
321
        private boolean adjustableExtent=true;
322

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

    
342
        /**
343
         * <p>Changes the status of the <i>"adjustable extent"</i> option to enabled or disabled.</p>
344
         *
345
         * @param boolean the boolean to be set
346
         */
347
        public void setAdjustable(boolean adjustable) {
348
                adjustableExtent = adjustable;
349
        }
350

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

    
366
        /**
367
         * @see ArrayList#remove(Object)
368
         * 
369
         * @see #addViewPortListener(ViewPortListener)
370
         */
371
        public boolean removeViewPortListener(ViewPortListener arg0) {
372
                return listeners.remove(arg0);
373
        }
374

    
375
        /**
376
         * <p>Converts and returns the distance <code>d</code> argument, that is in <i>map
377
         *  coordinates</i> to <i>screen coordinates<i/> using a <i>delta transform</i> with
378
         *  the transformation affine information in the {@link #trans #trans} attribute.</p>
379
         *
380
         * @param d distance in <i>map coordinates</i>
381
         *
382
         * @return distance equivalent in <i>screen coordinates<i>
383
         * 
384
         * @see #toMapDistance(int)
385
         * @see AffineTransform#deltaTransform(Point2D, Point2D)S
386
         */
387
        public int fromMapDistance(double d) {
388
                Point2D.Double pWorld = new Point2D.Double(1, 1);
389
                Point2D.Double pScreen = new Point2D.Double();
390

    
391
                try {
392
                        trans.deltaTransform(pWorld, pScreen);
393
                } catch (Exception e) {
394
                        System.err.print(e.getMessage());
395
                }
396

    
397
                return (int) (d * pScreen.x);
398
        }
399

    
400
        /**
401
         * <p>Converts and returns the distance <code>d</code> argument, that is in <i>screen
402
         *  coordinates</i> to <i>map coordinates<i/> using the transformation affine information
403
         *  in the {@link #trans #trans} attribute.</p>
404
         *
405
         * @param d distance in pixels
406
         *
407
         * @return distance equivalent in <i>map coordinates<i>
408
         * 
409
         * @see #fromMapDistance(double)
410
         * @see AffineTransform
411
         */
412
        public double toMapDistance(int d) {
413
                double dist = d / trans.getScaleX();
414

    
415
                return dist;
416
        }
417

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

    
473
                try {
474
                        trans.transform(pWorld, pScreen);
475
                } catch (Exception e) {
476
                        System.err.print(e.getMessage());
477
                }
478

    
479
                return pScreen;
480
        }
481

    
482
        /**
483
         * <p>Converts and returns the 2D point argument, that is in <i>map
484
         *  coordinates</i> to <i>screen coordinates<i/> (pixels) using a <i>transform</i> with
485
         *  the transformation affine information in the {@link #trans #trans} attribute.</p>
486
         *
487
         * @param point the 2D point in <i>map coordinates</i>
488
         *
489
         * @return 2D point equivalent in <i>screen coordinates<i> (pixels)
490
         * 
491
         * @see #toMapPoint(Point2D)
492
         * @see #fromMapPoint(double, double)
493
         */
494
        public Point2D fromMapPoint(Point2D point) {
495
                return fromMapPoint(point.getX(), point.getY());
496
        }
497

    
498
        /**
499
         * <p>Converts and returns the 2D point <code>(x,y)</code>, that is in <i>screen coordinates<i/>
500
         *  (pixels) to <i>map coordinates</i> using a <i>transform</i> with
501
         *  the transformation affine information in the {@link #trans #trans} attribute.</p>
502
         *
503
         * @param x the <code>x</code> <i>screen coordinate</i> of a 2D point
504
         * @param y the <code>y</code> <i>screen coordinate</i> of a 2D point
505
         *
506
         * @return 2D point equivalent in <i>map coordinates<i>
507
         * 
508
         * @see #toMapPoint(Point2D)
509
         * @see #fromMapPoint(double, double)
510
         */
511
        public Point2D toMapPoint(int x, int y) {
512
                Point pScreen = new Point(x, y);
513

    
514
                return toMapPoint(pScreen);
515
        }
516

    
517
        /**
518
         * <p>Converts and returns the 2D point argument, that is in <i>screen coordinates<i/>
519
         *  (pixels) to <i>map coordinates</i> using an <i>inverse transform</i> with
520
         *  the transformation affine information in the {@link #trans #trans} attribute.</p>
521
         * 
522
         * @param pScreen the 2D point in <i>screen coordinates</i> (pixels)
523
         *
524
         * @return 2D point equivalent in <i>map coordinates<i>
525
         * 
526
         * @see #toMapPoint(int, int)
527
         * @see AffineTransform#createInverse()
528
         * @see AffineTransform#transform(Point2D, Point2D)
529
         */
530
        public Point2D toMapPoint(Point2D pScreen) {
531
                Point2D.Double pWorld = new Point2D.Double();
532
                AffineTransform at;
533
        
534
                try {
535
                        at = trans.createInverse();
536
                        at.transform(pScreen, pWorld);
537
                } catch (NoninvertibleTransformException e) {
538
                        throw new RuntimeException(e);
539
                }
540
        
541
                return pWorld;
542
        }
543

    
544
        /**
545
         * <p>Returns the distance in meters between two points 2D that are in <i>map coordinates</i>. If
546
         *  the projection of this view is UTM, considers the Earth curvature.</p>
547
         *
548
         * @param pt1 a 2D point in <i>map coordinates</i>
549
         * @param pt2 another 2D point in <i>map coordinates</i>
550
         *
551
         * @return the distance in meters between the two points 2D
552
         * 
553
         * @see GeoCalc#distanceVincenty(Point2D, Point2D)
554
         */
555
        public double distanceWorld(Point2D pt1, Point2D pt2) {
556
                double dist = -1;
557
                dist = pt1.distance(pt2);
558

    
559
                if ((proj != null) && !(proj instanceof CSUTM)) {
560
                        dist = new GeoCalc(proj).distanceVincenty(proj.toGeo(pt1),
561
                                        proj.toGeo(pt2));
562
                }
563

    
564
                return dist*MapContext.CHANGEM[getMapUnits()];
565
        }
566

    
567
        /**
568
         * <p>Sets as current view's extent and adjusted extent, the previous.</p>
569
         * 
570
         * @see #getExtents()
571
         * @see #calculateAffineTransform()
572
         */
573
        public void setPreviousExtent() {
574
                extent = extents.removePrev();
575

    
576
                //Calcula la transformaci?n af?n
577
                calculateAffineTransform();
578

    
579
                // Lanzamos los eventos de extent cambiado
580
                callExtentChanged(getAdjustedExtent());
581
        }
582

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

    
605
        /**
606
         * <p>Changes the extent and adjusted extent of this view port:<br>
607
         * <ul>
608
         * <li>Stores the previous extent.
609
         * <li>Calculates the new extent using <code>r</code>:
610
         * <pre>extent = new Rectangle2D.Double(r.getMinX() - 0.1, r.getMinY() - 0.1, r.getWidth() + 0.2, r.getHeight() + 0.2);</pre>
611
         * <li>Executes {@linkplain #calculateAffineTransform()}: getting the new scale, adjusted extent, affine transformation between
612
         *  map and screen coordinates, the real world coordinates equivalent to 1 pixel, and the real world coordinates equivalent to 3 pixels.
613
         * <li>Notifies to all {@link ViewPortListener ViewPortListener}s registered that the extent has changed.
614
         * </ul>
615
         * </p>
616
         *
617
         * @param r the new extent
618
         * 
619
         * @see #getExtent()
620
         * @see #getExtents()
621
         * @see #calculateAffineTransform()
622
         * @see #setPreviousExtent()
623
         */
624
        public void setExtent(Rectangle2D r) {
625
                if (extent != null) {
626
                        extents.put(extent);
627
                }
628

    
629
                //Esto comprueba que el extent no es de anchura o altura = "0"
630
                //y si es as? lo redimensiona.
631
                if (r!=null &&((r.getWidth() == 0) || (r.getHeight() == 0))) {
632
                        extent = new Rectangle2D.Double(r.getMinX() - 0.1,
633
                                        r.getMinY() - 0.1, r.getWidth() + 0.2, r.getHeight() + 0.2);
634
                } else {
635
                        extent = r;
636
                }
637

    
638
                //Calcula la transformaci?n af?n
639
                calculateAffineTransform();
640

    
641
                // Lanzamos los eventos de extent cambiado
642
                callExtentChanged(getAdjustedExtent());
643
        }
644

    
645
        /**
646
         * <p>Changes the extent and adjusted extent of this view port:<br>
647
         * <ul>
648
         * <li>Stores the previous extent.
649
         * <li>Calculates the new extent using <code>r</code>:
650
         * <pre>extent = new Rectangle2D.Double(r.getMinX() - 0.1, r.getMinY() - 0.1, r.getWidth() + 0.2, r.getHeight() + 0.2);</pre>
651
         * <li>Executes {@linkplain #calculateAffineTransform()}: getting the new scale, adjusted extent, affine transformation between
652
         *  map and screen coordinates, the real world coordinates equivalent to 1 pixel, and the real world coordinates equivalent to 3 pixels.
653
         * <li>Notifies to all {@link ViewPortListener ViewPortListener}s registered that the extent has changed.
654
         * </ul>
655
         * </p>
656
         * 
657
         * @see #setExtent(Rectangle2D)
658
         * @see #calculateAffineTransform()
659
         */
660
        public void refreshExtent() {
661
                //this.scale = scale;
662

    
663
                //Calcula la transformaci?n af?n
664
                calculateAffineTransform();
665

    
666
                // Lanzamos los eventos de extent cambiado
667
                callExtentChanged(getAdjustedExtent());
668
        }
669

    
670
        /**
671
         * <p>Calculates and returns using the current projection of this view port, the scale that
672
         *  is the extent in <i>screen coordinates</i> from the image in <i>map coordinates</i>.</p>
673
         *
674
         * @return the scale <i>extent / image size</i> projected by this view port
675
         * 
676
         * @deprecated since 07/09/07, use {@linkplain MapContext#getScaleView()}
677
         */
678
        public double getScale() {
679
                return proj.getScale(extent.getMinX(), extent.getMaxX(),
680
                        imageSize.getWidth(), dpi);
681
        }
682

    
683
        /**
684
         * <p>Recalculates the current {@linkplain #extent} using an scale. It's necessary execute {@linkplain #refreshExtent()} after.</p>
685
         * 
686
         * @param s the scale to set
687
         * 
688
         * @deprecated since 07/09/07, use {@linkplain MapContext#setScaleView(long)} 
689
         */
690
        public void setScale(long s){
691
                double x=extent.getX();
692
                double y=extent.getY();
693
                double escalaX = imageSize.getWidth() / extent.getWidth();
694
                double w=imageSize.getWidth() / s;
695
                double h=imageSize.getHeight() / s;
696
                double difw = escalaX/s;
697

    
698
                double x1 = (-x * difw) -
699
            x+
700
            extent.getWidth()/2;
701
        double y1 = (-y * difw) -
702
            y +
703
            extent.getHeight()/2;
704
        double w1=extent.getWidth()*difw;
705
        double h1=extent.getHeight()*difw;
706
                extent.setRect(-x1,-y1,w1,h1);
707
        }        
708

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

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

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

    
748
        /**
749
         * <p>Notifies to all view port listeners registered, that the adjusted extent of this view port
750
         *  has changed.</p>
751
         *
752
         * @param newRect the new adjusted extend
753
         * 
754
         * @see #refreshExtent()
755
         * @see #setExtent(Rectangle2D)
756
         * @see #setPreviousExtent()
757
         * @see ExtentEvent
758
         * @see ViewPortListener
759
         */
760
        private void callExtentChanged(Rectangle2D newRect) {
761
                ExtentEvent ev = ExtentEvent.createExtentEvent(newRect);
762

    
763
                for (int i = 0; i < listeners.size(); i++) {
764
                        ViewPortListener listener = (ViewPortListener) listeners.get(i);
765
                        listener.extentChanged(ev);
766
                }
767
        }
768

    
769
        /**
770
         * <p>Notifies to all view port listeners registered, that the background color of this view port
771
         *  has changed.</p>
772
         *
773
         * @param c the new background color
774
         * 
775
         * @see #setBackColor(Color)
776
         * @see ColorEvent
777
         * @see ViewPortListener
778
         */
779
        private void callColorChanged(Color c) {
780
                ColorEvent ce = ColorEvent.createColorEvent(c);
781

    
782
                for (int i = 0; i < listeners.size(); i++) {
783
                        ViewPortListener listener = (ViewPortListener) listeners.get(i);
784
                        listener.backColorChanged(ce);
785
                }
786
        }
787

    
788
        /**
789
         * <p>Notifies to all view port listeners registered, that the projection of this view port
790
         *  has changed.</p>
791
         *
792
         * @param projection the new projection
793
         * 
794
         * @see #setProjection(IProjection)
795
         * @see ProjectionEvent
796
         * @see ViewPortListener
797
         */
798
        private void callProjectionChanged(IProjection projection) {
799
                ProjectionEvent ev = ProjectionEvent.createProjectionEvent(projection);
800

    
801
                for (int i = 0; i < listeners.size(); i++) {
802
                        ViewPortListener listener = (ViewPortListener) listeners.get(i);
803
                        listener.projectionChanged(ev);
804
                }
805
        }
806

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

    
837
                AffineTransform escalado = new AffineTransform();
838
                AffineTransform translacion = new AffineTransform();
839

    
840
                double escalaX;
841
                double escalaY;
842

    
843
                escalaX = imageSize.getWidth() / extent.getWidth();
844
                escalaY = imageSize.getHeight() / extent.getHeight();
845

    
846
                double xCenter = extent.getCenterX();
847
                double yCenter = extent.getCenterY();
848
                double newHeight;
849
                double newWidth;
850

    
851
                adjustedExtent = new Rectangle2D.Double();
852

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

    
880
                translacion.setToTranslation(-getAdjustedExtent().getX(),
881
                        -getAdjustedExtent().getY() - getAdjustedExtent().getHeight());
882

    
883
                AffineTransform offsetTrans = new AffineTransform();
884
                offsetTrans.setToTranslation(offset.getX(), offset.getY());
885

    
886
                trans.setToIdentity();
887
                trans.concatenate(offsetTrans);
888
                trans.concatenate(escalado);
889

    
890
                trans.concatenate(translacion);
891

    
892
                // Calculamos las distancias de 1 pixel y 3 pixel con esa transformaci?n
893
                // de coordenadas, de forma que est?n precalculadas para cuando las necesitemos
894
                AffineTransform at;
895

    
896
                try {
897
                        at = trans.createInverse();
898

    
899
                        java.awt.Point pPixel = new java.awt.Point(1, 1);
900
                        Point2D.Float pProv = new Point2D.Float();
901
                        at.deltaTransform(pPixel, pProv);
902

    
903
                        dist1pixel = pProv.x;
904
                        dist3pixel = 3 * pProv.x;
905
                } catch (NoninvertibleTransformException e) {
906
                        System.err.println("transformada afin = " + trans.toString());
907
                        System.err.println("extent = " + extent.toString() +
908
                                " imageSize= " + imageSize.toString());
909
                        throw new RuntimeException(e);
910
                }
911
        }
912

    
913
        /**
914
         * <p>Sets the offset.</p>
915
         * <p>The offset is the position where start drawing the map.</p>
916
         * <p>The offset of a <a href="http://www.gvsig.gva.es/">gvSIG</a>'s <i>View</i> is
917
         * always (0, 0) because the drawing area fits with the full window area. But in
918
         * a <a href="http://www.gvsig.gva.es/">gvSIG</a>'s <i>Layout</i> it's up to the place where
919
         * the <code>FFrameView</code> is located.</p>
920
         *
921
         * @param p 2D point that represents the offset in pixels
922
         * 
923
         * @see #getOffset()
924
         */
925
        public void setOffset(Point2D p) {
926
                offset = p;
927
        }
928

    
929
        /**
930
         * <p>Gets the offset.</p>
931
         * <p>The offset is the position where start drawing the map.</p>
932
         * <p>The offset of a <a href="http://www.gvsig.gva.es/">gvSIG</a>'s <i>View</i> is
933
         * always (0, 0) because the drawing area fits with the full window area. But in
934
         * a <a href="http://www.gvsig.gva.es/">gvSIG</a>'s <i>Layout</i> it's up to the place where
935
         * the <code>FFrameView</code> is located.</p>
936
         *
937
         * @return 2D point that represents the offset in pixels
938
         * 
939
         * @see #setOffset(Point2D)
940
         */
941
        public Point2D getOffset() {
942
                return offset;
943
        }
944

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1148
        /**
1149
         * <p>Sets only the affine transform to this view port, without updating dependent attributes.</p>
1150
         * <p><b><i>This method can be problematic!.</i></b></p>
1151
         * <p>Only used for print, should be removed, redefining the {@link RasterAdapter RasterAdapter} interface,
1152
         *  allowing it to receive a {@link ViewPortData ViewPortData} .</p>
1153
         *
1154
         * @param at the affine transform to set
1155
         * 
1156
         * @see #getAffineTransform()
1157
         * @see #calculateAffineTransform()
1158
         */
1159
        public void setAffineTransform(AffineTransform at)
1160
        {
1161
            this.trans = at;
1162
        }
1163

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

    
1221
                if (adjustedExtent != null) {
1222
                        xml.putProperty("adjustedExtentX", adjustedExtent.getX());
1223
                        xml.putProperty("adjustedExtentY", adjustedExtent.getY());
1224
                        xml.putProperty("adjustedExtentW", adjustedExtent.getWidth());
1225
                        xml.putProperty("adjustedExtentH", adjustedExtent.getHeight());
1226
                }
1227

    
1228
                if (backColor != null)
1229
                    xml.putProperty("backColor", StringUtilities.color2String(backColor));
1230

    
1231
                if (clip != null) {
1232
                        xml.putProperty("clipX", clip.getX());
1233
                        xml.putProperty("clipY", clip.getY());
1234
                        xml.putProperty("clipW", clip.getWidth());
1235
                        xml.putProperty("clipH", clip.getHeight());
1236
                }
1237

    
1238
                xml.putProperty("dist1pixel", dist1pixel);
1239
                xml.putProperty("dist3pixel", dist3pixel);
1240
                xml.putProperty("distanceUnits", distanceUnits);
1241

    
1242
                if (extent != null) {
1243
                        xml.putProperty("extentX", extent.getX());
1244
                        xml.putProperty("extentY", extent.getY());
1245
                        xml.putProperty("extentW", extent.getWidth());
1246
                        xml.putProperty("extentH", extent.getHeight());
1247
                }
1248

    
1249
                xml.addChild(extents.getXMLEntity());
1250
                xml.putProperty("mapUnits", mapUnits);
1251
                xml.putProperty("offsetX", offset.getX());
1252
                xml.putProperty("offsetY", offset.getY());
1253

    
1254
                if (proj != null) {
1255
                        xml.putProperty("proj", proj.getAbrev());
1256
                }
1257

    
1258
                xml.putProperty("scale", scale);
1259

    
1260
                return xml;
1261
        }
1262

    
1263
        /**
1264
         * <p>Creates a new <code>ViewPort</code> from an XML entity.</p>
1265
         *
1266
         * @param xml an XML entity
1267
         *
1268
         * @return the new <code>ViewPort</code>
1269
         * 
1270
         * @see #getXMLEntity()
1271
         * @see #createFromXML(XMLEntity)
1272
         */
1273
        public static ViewPort createFromXML03(XMLEntity xml) {
1274
                ViewPort vp = new ViewPort(null);
1275

    
1276
                if (xml.contains("adjustedExtentX")) {
1277
                        vp.adjustedExtent = new Rectangle2D.Double(xml.getDoubleProperty(
1278
                                                "adjustedExtentX"),
1279
                                        xml.getDoubleProperty("adjustedExtentY"),
1280
                                        xml.getDoubleProperty("adjustedExtentW"),
1281
                                        xml.getDoubleProperty("adjustedExtentH"));
1282
                }
1283

    
1284
                if (xml.contains("backColor")) {
1285
                        vp.setBackColor(StringUtilities.string2Color(xml.getStringProperty(
1286
                                                "backColor")));
1287
                }
1288

    
1289
                if (xml.contains("clipX")) {
1290
                        vp.clip = new Rectangle2D.Double(xml.getDoubleProperty("clipX"),
1291
                                        xml.getDoubleProperty("clipY"),
1292
                                        xml.getDoubleProperty("clipW"),
1293
                                        xml.getDoubleProperty("clipH"));
1294
                }
1295

    
1296
                vp.setDist1pixel(xml.getDoubleProperty("dist1pixel"));
1297
                vp.setDist3pixel(xml.getDoubleProperty("dist3pixel"));
1298
                vp.setDistanceUnits(xml.getIntProperty("distanceUnits"));
1299
                vp.extents = ExtentHistory.createFromXML03(xml.getChild(0));
1300

    
1301
                if (xml.contains("extentX")) {
1302
                        vp.setExtent(new Rectangle2D.Double(xml.getDoubleProperty("extentX"),
1303
                                        xml.getDoubleProperty("extentY"),
1304
                                        xml.getDoubleProperty("extentW"),
1305
                                        xml.getDoubleProperty("extentH")));
1306

    
1307
                        //Calcula la transformaci?n af?n
1308
                        vp.calculateAffineTransform();
1309

    
1310
                        // Lanzamos los eventos de extent cambiado
1311
                        // vp.callExtentListeners(vp.adjustedExtent);
1312
                }
1313

    
1314
                vp.setMapUnits(xml.getIntProperty("mapUnits"));
1315
                vp.setOffset(new Point2D.Double(xml.getDoubleProperty("offsetX"),
1316
                                xml.getDoubleProperty("offsetY")));
1317

    
1318
                if (xml.contains("proj")) {
1319
                        vp.proj = CRSFactory.getCRS(xml.getStringProperty("proj"));
1320
                }
1321

    
1322
                //vp.setScale(xml.getDoubleProperty("scale"));
1323
                vp.refreshExtent();
1324
                return vp;
1325
        }
1326

    
1327
        /**
1328
         * <p>Creates a new <code>ViewPort</code> from an XML entity.</p>
1329
         *
1330
         * @param xml an XML entity
1331
         *
1332
         * @return the new <code>ViewPort</code>
1333
         * 
1334
         * @see #getXMLEntity()
1335
         * @see #createFromXML03(XMLEntity)
1336
         */
1337
        public static ViewPort createFromXML(XMLEntity xml) {
1338
                ViewPort vp = new ViewPort(null);
1339

    
1340
                if (xml.contains("adjustedExtentX")) {
1341
                        vp.adjustedExtent = new Rectangle2D.Double(xml.getDoubleProperty(
1342
                                                "adjustedExtentX"),
1343
                                        xml.getDoubleProperty("adjustedExtentY"),
1344
                                        xml.getDoubleProperty("adjustedExtentW"),
1345
                                        xml.getDoubleProperty("adjustedExtentH"));
1346
                }
1347

    
1348
                if (xml.contains("backColor")) {
1349
                        vp.setBackColor(StringUtilities.string2Color(xml.getStringProperty(
1350
                                                "backColor")));
1351
                }else {
1352
                        vp.setBackColor(Color.white);
1353
                }
1354

    
1355
                if (xml.contains("clipX")) {
1356
                        vp.clip = new Rectangle2D.Double(xml.getDoubleProperty("clipX"),
1357
                                        xml.getDoubleProperty("clipY"),
1358
                                        xml.getDoubleProperty("clipW"),
1359
                                        xml.getDoubleProperty("clipH"));
1360
                }
1361

    
1362
                vp.setDist1pixel(xml.getDoubleProperty("dist1pixel"));
1363
                vp.setDist3pixel(xml.getDoubleProperty("dist3pixel"));
1364
                vp.setDistanceUnits(xml.getIntProperty("distanceUnits"));
1365
                vp.extents = ExtentHistory.createFromXML(xml.getChild(0));
1366

    
1367
                if (xml.contains("extentX")) {
1368
                        vp.setExtent(new Rectangle2D.Double(xml.getDoubleProperty("extentX"),
1369
                                        xml.getDoubleProperty("extentY"),
1370
                                        xml.getDoubleProperty("extentW"),
1371
                                        xml.getDoubleProperty("extentH")));
1372

    
1373
                        //Calcula la transformaci?n af?n
1374
                        vp.calculateAffineTransform();
1375

    
1376
                        // Lanzamos los eventos de extent cambiado
1377
                        // vp.callExtentListeners(vp.adjustedExtent);
1378
                }
1379

    
1380
                vp.setMapUnits(xml.getIntProperty("mapUnits"));
1381
                vp.setOffset(new Point2D.Double(xml.getDoubleProperty("offsetX"),
1382
                                xml.getDoubleProperty("offsetY")));
1383

    
1384
                if (xml.contains("proj")) {
1385
                        vp.proj = CRSFactory.getCRS(xml.getStringProperty("proj"));
1386
                }
1387

    
1388
                //vp.setScale(xml.getDoubleProperty("scale"));
1389
                vp.refreshExtent();
1390
                return vp;
1391
        }
1392

    
1393
        /**
1394
         * <p>Fast clone implementation: creates and returns a clone of this view port using XML entities.</p>
1395
         * <p>Doesn't <i>deepclone</i> to avoid unnecessary memory consumption.</p>
1396
         *
1397
         * @return the new view port
1398
         * 
1399
         * @see #createFromXML(XMLEntity)
1400
         */
1401
        public ViewPort cloneViewPort() {
1402
                return createFromXML(getXMLEntity());
1403
        }
1404

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

    
1418
                return str;
1419
        }
1420

    
1421
        /**
1422
         * <p>Sets the position and size of the clipping rectangle.</p>
1423
         * 
1424
         * @param rectView the clipping rectangle to set
1425
         */
1426
        public void setClipRect(Rectangle2D rectView) {
1427
                cliprect=rectView;
1428
        }
1429
}