Statistics
| Revision:

svn-gvsig-desktop / tags / v1_1_Build_1015 / libraries / libFMap / src / com / iver / cit / gvsig / fmap / ViewPort.java @ 13679

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>The <code>ViewPort</code> class represents the information needed to transform an area of a map that user
63
 *  will use to work to the available area of a gvSIG's view in screen.</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 of a view in <i>screen coordinates</i>.</p>
67
 * 
68
 * <p>Then we have:
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 unit, for data in screen.
82
 * <li><i>mapUnits</i>: measurement unit, for 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 view, 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 statute miles is a unit of length originated from a Statute of the English parliament in 1592 during
119
         *  the reign of Elizabeth I.as 5,280 feet or 1,760 yards; or 63,360 inches.</p> 
120
         */
121
        public static int MILLAS = 4;
122

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

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

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

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

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

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

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

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

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

    
209
        /**
210
         * <p>the affine transformation between the {@link #extent extent} in <i>map 2D coordinates</i> to
211
         *  the image area in the screen, in <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 <pre>image.size/extent.size"</pre>.
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:</p>
326
         * <p>
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 {@linkplain #toMapDistance(int)},
440
         *  and {@linkplain #toMapPoint(int, int)}.</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 
459
         *  the affine transformation 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
485
         *  the affine transformation 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
501
         *  the affine transformation 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 the
520
         *  inverse affine transformation of 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 extent and adjusted extent of this view port, the previous. Recalculating
569
         *  its parameters.</p>
570
         * 
571
         * @see #getExtents()
572
         * @see #calculateAffineTransform()
573
         */
574
        public void setPreviousExtent() {
575
                extent = extents.removePrev();
576

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

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

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

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

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

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

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

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

    
661
                //Calcula la transformaci?n af?n
662
                calculateAffineTransform();
663

    
664
                // Lanzamos los eventos de extent cambiado
665
                callExtentChanged(getAdjustedExtent());
666
        }
667

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

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

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

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

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

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

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

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

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

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

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

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

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

    
835
                AffineTransform escalado = new AffineTransform();
836
                AffineTransform translacion = new AffineTransform();
837

    
838
                double escalaX;
839
                double escalaY;
840

    
841
                escalaX = imageSize.getWidth() / extent.getWidth();
842
                escalaY = imageSize.getHeight() / extent.getHeight();
843

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

    
849
                adjustedExtent = new Rectangle2D.Double();
850

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

    
878
                translacion.setToTranslation(-getAdjustedExtent().getX(),
879
                        -getAdjustedExtent().getY() - getAdjustedExtent().getHeight());
880

    
881
                AffineTransform offsetTrans = new AffineTransform();
882
                offsetTrans.setToTranslation(offset.getX(), offset.getY());
883

    
884
                trans.setToIdentity();
885
                trans.concatenate(offsetTrans);
886
                trans.concatenate(escalado);
887

    
888
                trans.concatenate(translacion);
889

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

    
894
                try {
895
                        at = trans.createInverse();
896

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1231
                if (backColor != null)
1232
                    xml.putProperty("backColor", StringUtilities.color2String(backColor));
1233

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

    
1241
                xml.putProperty("dist1pixel", dist1pixel);
1242
                xml.putProperty("dist3pixel", dist3pixel);
1243
                xml.putProperty("distanceUnits", distanceUnits);
1244

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

    
1252
                xml.addChild(extents.getXMLEntity());
1253
                xml.putProperty("mapUnits", mapUnits);
1254
                xml.putProperty("offsetX", offset.getX());
1255
                xml.putProperty("offsetY", offset.getY());
1256

    
1257
                if (proj != null) {
1258
                        xml.putProperty("proj", proj.getAbrev());
1259
                }
1260

    
1261
                xml.putProperty("scale", scale);
1262

    
1263
                return xml;
1264
        }
1265

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

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

    
1287
                if (xml.contains("backColor")) {
1288
                        vp.setBackColor(StringUtilities.string2Color(xml.getStringProperty(
1289
                                                "backColor")));
1290
                }
1291

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

    
1299
                vp.setDist1pixel(xml.getDoubleProperty("dist1pixel"));
1300
                vp.setDist3pixel(xml.getDoubleProperty("dist3pixel"));
1301
                vp.setDistanceUnits(xml.getIntProperty("distanceUnits"));
1302
                vp.extents = ExtentHistory.createFromXML03(xml.getChild(0));
1303

    
1304
                if (xml.contains("extentX")) {
1305
                        vp.setExtent(new Rectangle2D.Double(xml.getDoubleProperty("extentX"),
1306
                                        xml.getDoubleProperty("extentY"),
1307
                                        xml.getDoubleProperty("extentW"),
1308
                                        xml.getDoubleProperty("extentH")));
1309

    
1310
                        //Calcula la transformaci?n af?n
1311
                        vp.calculateAffineTransform();
1312

    
1313
                        // Lanzamos los eventos de extent cambiado
1314
                        // vp.callExtentListeners(vp.adjustedExtent);
1315
                }
1316

    
1317
                vp.setMapUnits(xml.getIntProperty("mapUnits"));
1318
                vp.setOffset(new Point2D.Double(xml.getDoubleProperty("offsetX"),
1319
                                xml.getDoubleProperty("offsetY")));
1320

    
1321
                if (xml.contains("proj")) {
1322
                        vp.proj = CRSFactory.getCRS(xml.getStringProperty("proj"));
1323
                }
1324

    
1325
                //vp.setScale(xml.getDoubleProperty("scale"));
1326
                vp.refreshExtent();
1327
                return vp;
1328
        }
1329

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

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

    
1351
                if (xml.contains("backColor")) {
1352
                        vp.setBackColor(StringUtilities.string2Color(xml.getStringProperty(
1353
                                                "backColor")));
1354
                }else {
1355
                        vp.setBackColor(Color.white);
1356
                }
1357

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

    
1365
                vp.setDist1pixel(xml.getDoubleProperty("dist1pixel"));
1366
                vp.setDist3pixel(xml.getDoubleProperty("dist3pixel"));
1367
                vp.setDistanceUnits(xml.getIntProperty("distanceUnits"));
1368
                vp.extents = ExtentHistory.createFromXML(xml.getChild(0));
1369

    
1370
                if (xml.contains("extentX")) {
1371
                        vp.setExtent(new Rectangle2D.Double(xml.getDoubleProperty("extentX"),
1372
                                        xml.getDoubleProperty("extentY"),
1373
                                        xml.getDoubleProperty("extentW"),
1374
                                        xml.getDoubleProperty("extentH")));
1375

    
1376
                        //Calcula la transformaci?n af?n
1377
                        vp.calculateAffineTransform();
1378

    
1379
                        // Lanzamos los eventos de extent cambiado
1380
                        // vp.callExtentListeners(vp.adjustedExtent);
1381
                }
1382

    
1383
                vp.setMapUnits(xml.getIntProperty("mapUnits"));
1384
                vp.setOffset(new Point2D.Double(xml.getDoubleProperty("offsetX"),
1385
                                xml.getDoubleProperty("offsetY")));
1386

    
1387
                if (xml.contains("proj")) {
1388
                        vp.proj = CRSFactory.getCRS(xml.getStringProperty("proj"));
1389
                }
1390

    
1391
                //vp.setScale(xml.getDoubleProperty("scale"));
1392
                vp.refreshExtent();
1393
                return vp;
1394
        }
1395

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

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

    
1421
                return str;
1422
        }
1423

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