Statistics
| Revision:

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

History | View | Annotate | Download (44.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 org.gvsig.fmap.mapcontext;
42

    
43
import java.awt.Color;
44
import java.awt.Dimension;
45
import java.awt.Point;
46
import java.awt.geom.AffineTransform;
47
import java.awt.geom.NoninvertibleTransformException;
48
import java.awt.geom.Point2D;
49
import java.awt.geom.Rectangle2D;
50
import java.util.ArrayList;
51

    
52
import org.cresques.cts.GeoCalc;
53
import org.cresques.cts.IProjection;
54
import org.cresques.cts.gt2.CSUTM;
55
import org.gvsig.fmap.crs.CRSFactory;
56
import org.gvsig.fmap.geom.primitive.DefaultEnvelope;
57
import org.gvsig.fmap.geom.primitive.Envelope;
58
import org.gvsig.fmap.mapcontext.events.ColorEvent;
59
import org.gvsig.fmap.mapcontext.events.ExtentEvent;
60
import org.gvsig.fmap.mapcontext.events.ProjectionEvent;
61
import org.gvsig.fmap.mapcontext.events.listeners.ViewPortListener;
62

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

    
66

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

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

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

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

    
189
        /**
190
         * <p>History with the last extents of the view.</p>
191
         *
192
         * @see #setPreviousExtent()
193
         * @see #getExtents()
194
         */
195
        protected ExtentHistory extents = new ExtentHistory();
196

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

    
217
        /**
218
         * <p>the affine transformation between the {@link #extent extent} in <i>map 2D coordinates</i> to
219
         *  the image area in the screen, in <i>screen 2D coordinates</i> (pixels).</p>
220
         *
221
         * @see AffineTransform
222
         *
223
         * @see #getAffineTransform()
224
         * @see #setAffineTransform(AffineTransform)
225
         * @see #calculateAffineTransform()
226
         */
227
        private AffineTransform trans = new AffineTransform();
228

    
229
        /**
230
         * <p>Measurement unit used for measuring distances and displaying information.</p>
231
         *
232
         * @see #getDistanceUnits()
233
         * @see #setDistanceUnits(int)
234
         */
235
        private int distanceUnits = 1;
236
        /**
237
         * <p>Measurement unit used for measuring areas and displaying information.</p>
238
         *
239
         * @see #getDistanceArea()
240
         * @see #setDistanceArea(int)
241
         */
242
        private int distanceArea = 1;
243
        /**
244
         * <p>Measurement unit used by this view port for the map.</p>
245
         *
246
         * @see #getMapUnits()
247
         * @see #setMapUnits(int)
248
         */
249
        private int mapUnits = 1;
250

    
251
        /**
252
         * <p>Array with the {@link ViewPortListener ViewPortListener}s registered to this view port.</p>
253
         *
254
         * @see #addViewPortListener(ViewPortListener)
255
         * @see #removeViewPortListener(ViewPortListener)
256
         */
257
        private ArrayList listeners = new ArrayList();
258

    
259
        /**
260
         * <p>The offset is the position where start drawing the map.</p>
261
         * <p>The offset of a <a href="http://www.gvsig.gva.es/">gvSIG</a>'s <i>View</i> is
262
         * always (0, 0) because the drawing area fits with the full window area. But in
263
         * a <a href="http://www.gvsig.gva.es/">gvSIG</a>'s <i>Layout</i> it's up to the place where
264
         * the <code>FFrameView</code> is located.</p>
265
         *
266
         * @see #getOffset()
267
         * @see #setOffset(Point2D)
268
         */
269
        private Point2D offset = new Point2D.Double(0, 0);
270

    
271
        /**
272
         * <p>Clipping area.</p>
273
         */
274
        private Rectangle2D clip;
275

    
276
        /**
277
         * <p>Background color of this view.</p>
278
         *
279
         * @see #getBackColor()
280
         * @see #setBackColor(Color)
281
         */
282
        private Color backColor = null; //Color.WHITE;
283

    
284
        /**
285
         * <p>Information about the map projection used in this view.</p>
286
         *
287
         * @see #getProjection()
288
         * @see #setProjection(IProjection)
289
         */
290
        private IProjection proj;
291

    
292
        /**
293
         * <p>Represents the distance in <i>world coordinates</i> equivalent to 1 pixel in the view with the current extent.</p>
294
         *
295
         * @see #getDist1pixel()
296
         * @see #setDist1pixel(double)
297
         */
298
        private double dist1pixel;
299

    
300
        /**
301
         * <p>Represents the distance in <i>world coordinates</i> equivalent to 3 pixels in the view with the current extent.</p>
302
         *
303
         * @see #getDist3pixel()
304
         * @see #setDist3pixel(double)
305
         */
306
        private double dist3pixel;
307

    
308
        /**
309
         * <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>
310
         */
311
        private double scale;
312

    
313
        /**
314
         * <p>Clipping area.</p>
315
         *
316
         * @see #setClipRect(Rectangle2D)
317
         */
318
        private Rectangle2D cliprect;
319

    
320
        /**
321
         * <p>Enables or disables the <i>"adjustable extent"</i> mode.</p>
322
         *
323
         * <p>
324
         * When calculates the affine transform, if
325
         * <ul>
326
         * <li><i>enabled</i>: the new <code>adjustedExtent</code> will have the (X, Y) coordinates of the <code>extent</code> and
327
         *  an area that will be an scale of the image size. That area will have different
328
         *  height or width (not both) of the extent according the least ratio (height or width) in <pre>image.size/extent.size"</pre>.
329
         * <li><i>disabled</i>: the new <code>adjustedExtent</code> will be like <code>extent</code>.
330
         * </ul>
331
         * </p>
332
         *
333
         * @see #setAdjustable(boolean)
334
         */
335
        private boolean adjustableExtent=true;
336

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

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

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

    
384
        /**
385
          * <p>Removes the specified {@link ViewPortListener ViewPortListener} listener, if existed.</p>
386
         *
387
         * @param arg0 the listener to remove
388
         *
389
         * @return <code>true</code> if the contained the specified listener.
390
         *
391
         * @see #addViewPortListener(ViewPortListener)
392
         */
393
        public boolean removeViewPortListener(ViewPortListener arg0) {
394
                return listeners.remove(arg0);
395
        }
396

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

    
413
                try {
414
                        trans.deltaTransform(pWorld, pScreen);
415
                } catch (Exception e) {
416
                        System.err.print(e.getMessage());
417
                }
418

    
419
                return (int) (d * pScreen.x);
420
        }
421

    
422
        /**
423
         * <p>Converts and returns the 2D point <code>(x,y)</code>, that is in <i>map
424
         *  coordinates</i> to <i>screen coordinates</i> (pixels) using
425
         *  the affine transformation in the {@link #trans #trans} attribute.</p>
426
         *
427
         * @param x the <code>x</code> <i>map coordinate</i> of a 2D point
428
         * @param y the <code>y</code> <i>map coordinate</i> of a 2D point
429
         *
430
         * @return 2D point equivalent in <i>screen coordinates</i> (pixels)
431
         *
432
         * @see #fromMapPoint(Point2D)
433
         * @see AffineTransform#transform(Point2D, Point2D)
434
         */
435
        public Point2D fromMapPoint(double x, double y) {
436
                Point2D.Double pWorld = new Point2D.Double(x, y);
437
                Point2D.Double pScreen = new Point2D.Double();
438

    
439
                try {
440
                        trans.transform(pWorld, pScreen);
441
                } catch (Exception e) {
442
                        System.err.print(e.getMessage());
443
                }
444

    
445
                return pScreen;
446
        }
447

    
448
        /**
449
         * <p>Converts and returns the 2D point argument, that is in <i>map
450
         *  coordinates</i> to <i>screen coordinates</i> (pixels) using
451
         *  the affine transformation in the {@link #trans #trans} attribute.</p>
452
         *
453
         * @param point the 2D point in <i>map coordinates</i>
454
         *
455
         * @return 2D point equivalent in <i>screen coordinates</i> (pixels)
456
         *
457
         * @see #toMapPoint(Point2D)
458
         * @see #fromMapPoint(double, double)
459
         */
460
        public Point2D fromMapPoint(Point2D point) {
461
                return fromMapPoint(point.getX(), point.getY());
462
        }
463

    
464
        /**
465
         * <p>Converts and returns the 2D point <code>(x,y)</code>, that is in <i>screen coordinates</i>
466
         *  (pixels) to <i>map coordinates</i> using
467
         *  the affine transformation in the {@link #trans #trans} attribute.</p>
468
         *
469
         * @param x the <code>x</code> <i>screen coordinate</i> of a 2D point
470
         * @param y the <code>y</code> <i>screen coordinate</i> of a 2D point
471
         *
472
         * @return 2D point equivalent in <i>map coordinates</i>
473
         *
474
         * @see #toMapPoint(Point2D)
475
         * @see #fromMapPoint(double, double)
476
         */
477
        public Point2D toMapPoint(int x, int y) {
478
                Point pScreen = new Point(x, y);
479

    
480
                return toMapPoint(pScreen);
481
        }
482

    
483
        /**
484
         * <p>Converts and returns the {@link Rectangle2D Rectangle2D}, that is in <i>screen
485
         *  coordinates</i> (pixels) to <i>map coordinates</i> using {@linkplain #toMapDistance(int)},
486
         *  and {@linkplain #toMapPoint(int, int)}.</p>
487
         *
488
         * @param r the 2D rectangle in <i>screen coordinates</i> (pixels)
489
         * @return 2D rectangle equivalent in <i>map coordinates</i>
490
         *
491
         * @see #fromMapRectangle(Rectangle2D)
492
         * @see #toMapDistance(int)
493
         * @see #toMapPoint(int, int)
494
         */
495
        public Rectangle2D toMapRectangle(Rectangle2D r){
496
                Rectangle2D rect=new Rectangle2D.Double();
497
                Point2D p1=toMapPoint((int)r.getX(),(int)r.getY());
498
                Point2D p2=toMapPoint((int)r.getMaxX(),(int)r.getMaxY());
499
                rect.setFrameFromDiagonal(p1,p2);
500
                return rect;
501
        }
502

    
503
        /**
504
         * <p>Converts and returns the distance <code>d</code>, that is in <i>screen
505
         *  coordinates</i> to <i>map coordinates</i> using the transformation affine information
506
         *  in the {@link #trans #trans} attribute.</p>
507
         *
508
         * @param d distance in pixels
509
         *
510
         * @return distance equivalent in <i>map coordinates</i>
511
         *
512
         * @see #fromMapDistance(double)
513
         * @see AffineTransform
514
         */
515
        public double toMapDistance(int d) {
516
                double dist = d / trans.getScaleX();
517

    
518
                return dist;
519
        }
520

    
521
        /**
522
         * <p>Converts and returns the 2D point argument, that is in <i>screen coordinates</i>
523
         *  (pixels) to <i>map coordinates</i> using the
524
         *  inverse affine transformation of the {@link #trans #trans} attribute.</p>
525
         *
526
         * @param pScreen the 2D point in <i>screen coordinates</i> (pixels)
527
         *
528
         * @return 2D point equivalent in <i>map coordinates</i>
529
         *
530
         * @see #toMapPoint(int, int)
531
         * @see AffineTransform#createInverse()
532
         * @see AffineTransform#transform(Point2D, Point2D)
533
         */
534
        public Point2D toMapPoint(Point2D pScreen) {
535
                Point2D.Double pWorld = new Point2D.Double();
536
                AffineTransform at;
537

    
538
                try {
539
                        at = trans.createInverse();
540
                        at.transform(pScreen, pWorld);
541
                } catch (NoninvertibleTransformException e) {
542
                        throw new RuntimeException("Non invertible transform Exception",e);
543
                }
544

    
545
                return pWorld;
546
        }
547

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

    
564
                if ((proj != null) && !(proj instanceof CSUTM)) {
565
                        dist = new GeoCalc(proj).distanceVincenty(proj.toGeo(pt1),
566
                                        proj.toGeo(pt2));
567
                        return dist;
568
                }
569
                return (dist*MapContext.getDistanceTrans2Meter()[getMapUnits()]);
570
        }
571

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

    
582
                //Calcula la transformaci?n af?n
583
                calculateAffineTransform();
584

    
585
                // Lanzamos los eventos de extent cambiado
586
                callExtentChanged(getAdjustedExtent());
587
        }
588

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

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

    
636
                //Esto comprueba que el extent no es de anchura o altura = "0"
637
                //y si es as? lo redimensiona.
638
                if (r!=null &&((r.getMaximum(0)-r.getMinimum(0) == 0) || (r.getMaximum(1)-r.getMinimum(1) == 0))) {
639
                        extent = new Rectangle2D.Double(r.getMinimum(0) - 0.1,
640
                                        r.getMinimum(1) - 0.1, r.getMaximum(0)-r.getMinimum(0) + 0.2, r.getMaximum(1)-r.getMinimum(1) + 0.2);
641
                } else {
642
                        extent = new Rectangle2D.Double(r.getMinimum(0),r.getMinimum(1),r.getMaximum(0)-r.getMinimum(0),r.getMaximum(1)-r.getMinimum(1));
643
                }
644

    
645
                //Calcula la transformaci?n af?n
646
                calculateAffineTransform();
647

    
648
                // Lanzamos los eventos de extent cambiado
649
                callExtentChanged(getAdjustedExtent());
650
        }
651

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

    
667
                //Calcula la transformaci?n af?n
668
                calculateAffineTransform();
669

    
670
                // Lanzamos los eventos de extent cambiado
671
                callExtentChanged(getAdjustedExtent());
672
        }
673

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

    
687
        /**
688
         * <p>Affine transformation between <i>map 2D coordinates</i> to <i>screen 2D coordinates</i> (pixels),
689
         * preserving the "straightness" and "parallelism" of the lines.</p>
690
         *
691
         * @return the affine transformation
692
         *
693
         * @see #setAffineTransform(AffineTransform)
694
         * @see #calculateAffineTransform()
695
         */
696
        public AffineTransform getAffineTransform() {
697
                return trans;
698
        }
699

    
700
        /**
701
         * <p>Returns the size of the image projected.</p>
702
         *
703
         * @return the image size
704
         *
705
         * @see #setImageSize(Dimension)
706
         * @see #getImageHeight()
707
         * @see #getImageWidth()
708
         */
709
        public Dimension getImageSize() {
710
                return imageSize;
711
        }
712

    
713
        /**
714
         * <p>Sets the size of the image projected, recalculating the parameters of this view port.</p>
715
         *
716
         * @param imageSize the image size
717
         *
718
         * @see #getImageSize()
719
         * @see #calculateAffineTransform()
720
         */
721
        public void setImageSize(Dimension imageSize) {
722
                this.imageSize = imageSize;
723
                calculateAffineTransform();
724
        }
725

    
726
        /**
727
         * <p>Notifies to all view port listeners registered, that the adjusted extent of this view port
728
         *  has changed.</p>
729
         *
730
         * @param newRect the new adjusted extend
731
         *
732
         * @see #refreshExtent()
733
         * @see #setEnvelope(Envelope)
734
         * @see #setPreviousExtent()
735
         * @see ExtentEvent
736
         * @see ViewPortListener
737
         */
738
        protected void callExtentChanged(Envelope newRect) {
739
                ExtentEvent ev = ExtentEvent.createExtentEvent(newRect);
740

    
741
                for (int i = 0; i < listeners.size(); i++) {
742
                        ViewPortListener listener = (ViewPortListener) listeners.get(i);
743
                        listener.extentChanged(ev);
744
                }
745
        }
746

    
747
        /**
748
         * <p>Notifies to all view port listeners registered, that the background color of this view port
749
         *  has changed.</p>
750
         *
751
         * @param c the new background color
752
         *
753
         * @see #setBackColor(Color)
754
         * @see ColorEvent
755
         * @see ViewPortListener
756
         */
757
        private void callColorChanged(Color c) {
758
                ColorEvent ce = ColorEvent.createColorEvent(c);
759

    
760
                for (int i = 0; i < listeners.size(); i++) {
761
                        ViewPortListener listener = (ViewPortListener) listeners.get(i);
762
                        listener.backColorChanged(ce);
763
                }
764
        }
765

    
766
        /**
767
         * <p>Notifies to all view port listeners registered, that the projection of this view port
768
         *  has changed.</p>
769
         *
770
         * @param projection the new projection
771
         *
772
         * @see #setProjection(IProjection)
773
         * @see ProjectionEvent
774
         * @see ViewPortListener
775
         */
776
        private void callProjectionChanged(IProjection projection) {
777
                ProjectionEvent ev = ProjectionEvent.createProjectionEvent(projection);
778

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

    
785
        /**
786
         * <p>Calculates the affine transformation between the {@link #extent extent} in <i>map 2D coordinates</i> to
787
         *  the image area in the screen, in <i>screen 2D coordinates</i> (pixels).</p>
788
         *
789
         * <p>This process recalculates some parameters of this view port:<br>
790
         *
791
         * <ul>
792
         * <li>The new {@link #scale scale} .
793
         * <li>The new {@link #adjustedExtent adjustedExtent} .
794
         * <li>The new {@link #trans trans} .
795
         * <li>The new real world coordinates equivalent to 1 pixel ({@link #dist1pixel dist1pixel}) .
796
         * <li>The new real world coordinates equivalent to 3 pixels ({@link #dist3pixel dist3pixel}) .
797
         * </ul>
798
         * </p>
799
         *
800
         * @see #getAffineTransform()
801
         * @see #setAffineTransform(AffineTransform)
802
         * @see #refreshExtent()
803
         * @see #setEnvelope(Envelope)
804
         * @see #setImageSize(Dimension)
805
         * @see #setPreviousExtent()
806
         * @see #createFromXML(XMLEntity)
807
         * @see AffineTransform
808
         */
809
        private void calculateAffineTransform() {
810
                if ((imageSize == null) || (extent == null) ||
811
                                (imageSize.getWidth() <= 0) || (imageSize.getHeight() <= 0)) {
812
                        return;
813
                }
814

    
815
                AffineTransform escalado = new AffineTransform();
816
                AffineTransform translacion = new AffineTransform();
817

    
818
                double escalaX;
819
                double escalaY;
820

    
821
                escalaX = imageSize.getWidth() / extent.getWidth();
822
                escalaY = imageSize.getHeight() / extent.getHeight();
823

    
824
                double xCenter = extent.getCenterX();
825
                double yCenter = extent.getCenterY();
826
                double newHeight;
827
                double newWidth;
828

    
829
                adjustedExtent = new Rectangle2D.Double();
830

    
831
                if (adjustableExtent) {
832
                        if (escalaX < escalaY) {
833
                                scale = escalaX;
834
                                newHeight = imageSize.getHeight() / scale;
835
                                adjustedExtent.setRect(xCenter - (extent.getWidth() / 2.0),
836
                                        yCenter - (newHeight / 2.0), extent.getWidth(), newHeight);
837
                        } else {
838
                                scale = escalaY;
839
                                newWidth = imageSize.getWidth() / scale;
840
                                adjustedExtent.setRect(xCenter - (newWidth / 2.0),
841
                                        yCenter - (extent.getHeight() / 2.0), newWidth,
842
                                        extent.getHeight());
843
                        }
844
                        escalado.setToScale(scale, -scale);
845
                }
846
                else { // adjusted is same as extent
847
                        scale = escalaX;
848
                        adjustedExtent.setFrame(extent);
849
                        escalado.setToScale(escalaX, -escalaY);
850
                }
851
                Envelope env=getAdjustedExtent();
852
                if (env == null)
853
                        return;
854
                translacion.setToTranslation(-env.getMinimum(0),
855
                        -env.getMinimum(1) - getAdjustedExtent().getLength(1));
856

    
857
                AffineTransform offsetTrans = new AffineTransform();
858
                offsetTrans.setToTranslation(offset.getX(), offset.getY());
859

    
860
                trans.setToIdentity();
861
                trans.concatenate(offsetTrans);
862
                trans.concatenate(escalado);
863

    
864
                trans.concatenate(translacion);
865

    
866
                // Calculamos las distancias de 1 pixel y 3 pixel con esa transformaci?n
867
                // de coordenadas, de forma que est?n precalculadas para cuando las necesitemos
868
                AffineTransform at;
869

    
870
                try {
871
                        at = trans.createInverse();
872

    
873
                        java.awt.Point pPixel = new java.awt.Point(1, 1);
874
                        Point2D.Float pProv = new Point2D.Float();
875
                        at.deltaTransform(pPixel, pProv);
876

    
877
                        dist1pixel = pProv.x;
878
                        dist3pixel = 3 * pProv.x;
879
                } catch (NoninvertibleTransformException e) {
880
                        System.err.println("transformada afin = " + trans.toString());
881
                        System.err.println("extent = " + extent.toString() +
882
                                " imageSize= " + imageSize.toString());
883
                        throw new RuntimeException("Non invertible transform Exception",e);
884
                }
885
        }
886

    
887
        /**
888
         * <p>Sets the offset.</p>
889
         * <p>The offset is the position where start drawing the map.</p>
890
         *
891
         * @param p 2D point that represents the offset in pixels
892
         *
893
         * @see #getOffset()
894
         */
895
        public void setOffset(Point2D p) {
896
                offset = p;
897
        }
898

    
899
        /**
900
         * <p>Gets the offset.</p>
901
         * <p>The offset is the position where start drawing the map.</p>
902
         *
903
         * @return 2D point that represents the offset in pixels
904
         *
905
         * @see #setOffset(Point2D)
906
         */
907
        public Point2D getOffset() {
908
                return offset;
909
        }
910

    
911
        /**
912
         * <p>Sets the background color.</p>
913
         *
914
         * @param c the new background color
915
         *
916
         * @see #getBackColor()
917
         */
918
        public void setBackColor(Color c) {
919
                backColor = c;
920
                callColorChanged(backColor);
921
        }
922

    
923
        /**
924
         * <p>Gets the background color.</p>
925
         *
926
         * @return the background color of the view
927
         *
928
         * @see #setBackColor(Color)
929
         */
930
        public Color getBackColor() {
931
                return backColor;
932
        }
933

    
934
        /**
935
         * <p>Returns the extent currently covered by the view adjusted (scaled) to the image size aspect.</p>
936
         *
937
         * @return extent of the view adjusted to the image size aspect
938
         *
939
         * @see #setAdjustable(boolean)
940
         */
941
        public Envelope getAdjustedExtent() {
942
                if (cliprect!=null){
943
                        Rectangle2D r= adjustedExtent.createIntersection(cliprect);
944
                        return new DefaultEnvelope(2,new double[]{r.getX(),r.getY()},new double[]{r.getMaxX(),r.getMaxY()});
945
                }
946
                if (adjustedExtent!=null)
947
                        return new DefaultEnvelope(2,new double[]{adjustedExtent.getX(),adjustedExtent.getY()},new double[]{adjustedExtent.getMaxX(),adjustedExtent.getMaxY()});
948
                return null;
949
        }
950

    
951
        /**
952
         * <p>Returns the measurement unit of this view port used for measuring distances and displaying information.</p>
953
         *
954
         * @return the measurement unit of this view used for measuring distances and displaying information
955
         *
956
         * @see #setDistanceUnits(int)
957
         */
958
        public int getDistanceUnits() {
959
                return distanceUnits;
960
        }
961
        /**
962
         * <p>Returns the measurement unit of this view port used for measuring areas and displaying information.</p>
963
         *
964
         * @return the measurement unit of this view used for measuring areas and displaying information
965
         *
966
         * @see #setDistanceUnits(int)
967
         */
968
        public int getDistanceArea() {
969
                return distanceArea;
970
        }
971
        /**
972
         * <p>Sets the measurement unit of this view port used for measuring distances and displaying information.</p>
973
         *
974
         * @param distanceUnits the measurement unit of this view used for measuring distances and displaying information
975
         *
976
         * @see #getDistanceUnits()
977
         */
978
        public void setDistanceUnits(int distanceUnits) {
979
                this.distanceUnits = distanceUnits;
980
        }
981
        /**
982
         * <p>Sets the measurement unit of this view port used for measuring areas and displaying information.</p>
983
         *
984
         * @param distanceUnits the measurement unit of this view used for measuring areas and displaying information
985
         *
986
         * @see #getDistanceUnits()
987
         */
988
        public void setDistanceArea(int distanceArea) {
989
                this.distanceArea = distanceArea;
990
        }
991
        /**
992
         * <p>Gets the measurement unit used by this view port for the map.</p>
993
         *
994
         * @return Returns the current map measure unit
995
         *
996
         * @see #setMapUnits(int)
997
         */
998
        public int getMapUnits() {
999
                return mapUnits;
1000
        }
1001

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

    
1013
        /**
1014
         * <p>Gets the width in <i>screen coordinates</i> of the rectangle where the image is displayed.</p>
1015
         * <p>Used by {@linkplain #calculateAffineTransform()} to calculate:<br>
1016
           *
1017
         * <ul>
1018
         * <li>The new {@link #scale scale} .
1019
         * <li>The new {@link #adjustedExtent adjustableExtent} .
1020
         * <li>The new {@link #trans trans} .
1021
         * <li>The new real world coordinates equivalent to 1 pixel ({@link #dist1pixel dist1pixel}) .
1022
         * <li>The new real world coordinates equivalent to 3 pixels ({@link #dist3pixel dist3pixel}) .
1023
         * </ul>
1024
         * </p>
1025
         *
1026
         * @see #getImageHeight()
1027
         * @see #getImageSize()
1028
         * @see #setImageSize(Dimension)
1029
         */
1030
        public int getImageWidth() {
1031
                return imageSize.width;
1032
        }
1033

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

    
1055
        /**
1056
         * <p>Gets the distance in <i>world coordinates</i> equivalent to 1 pixel in the view with the current extent.</p>
1057
         *
1058
         * @return the distance
1059
         *
1060
         * @see #setDist1pixel(double)
1061
         */
1062
        public double getDist1pixel() {
1063
                return dist1pixel;
1064
        }
1065

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

    
1077
        /**
1078
         * <p>Gets the distance in <i>world coordinates</i> equivalent to 3 pixels in the view with the current extent.</p>
1079
         *
1080
         * @return the distance
1081
         *
1082
         * @see #setDist3pixel(double)
1083
         */
1084
        public double getDist3pixel() {
1085
                return dist3pixel;
1086
        }
1087

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

    
1099
        /**
1100
         * <p>Returns the last previous extents of this view port.</p>
1101
         *
1102
         * @return the last previous extents of this view port
1103
         *
1104
         * @see #setPreviousExtent()
1105
         */
1106
        public ExtentHistory getExtents() {
1107
                return extents;
1108
        }
1109

    
1110
        /**
1111
         * <p>Gets the projection used in this view port.</p>
1112
         *
1113
         * @return projection used in this view port
1114
         *
1115
         * @see #setProjection(IProjection)
1116
         */
1117
        public IProjection getProjection() {
1118
                return proj;
1119
        }
1120

    
1121
        /**
1122
         * <p>Sets the projection to this view port.</p>
1123
         *
1124
         * @param proj the new projection
1125
         *
1126
         * @see #getProjection()
1127
         */
1128
        public void setProjection(IProjection proj) {
1129
                if(this.proj == null || !this.proj.getAbrev().equals(proj.getAbrev())) {
1130
                        this.proj = proj;
1131
                        callProjectionChanged(proj);
1132
                }
1133
        }
1134

    
1135
//  -----------------------------------------------------------------------------------------------------------
1136
//  NOTA PARA DESARROLLADORES SOBRE EL M?TODO "public void setAffineTransform(AffineTransform at)"
1137
//  ==============================================================================================
1138
//          Only used for print, should be removed, redefining the {@link RasterAdapter RasterAdapter} interface,
1139
//           allowing it to receive a {@link ViewPortData ViewPortData} .
1140
//  -----------------------------------------------------------------------------------------------------------
1141

    
1142
        /**
1143
         * <p>Sets only the affine transform to this view port, without updating dependent attributes.</p>
1144
         * <p><b><i>This method could be problematic!</i></b></p>
1145
         *
1146
         * @param at the affine transform to set
1147
         *
1148
         * @see #getAffineTransform()
1149
         * @see #calculateAffineTransform()
1150
         */
1151
        public void setAffineTransform(AffineTransform at)
1152
        {
1153
            this.trans = at;
1154
        }
1155

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

    
1216
                if (adjustedExtent != null) {
1217
                        xml.putProperty("adjustedExtentX", adjustedExtent.getX());
1218
                        xml.putProperty("adjustedExtentY", adjustedExtent.getY());
1219
                        xml.putProperty("adjustedExtentW", adjustedExtent.getWidth());
1220
                        xml.putProperty("adjustedExtentH", adjustedExtent.getHeight());
1221
                }
1222

    
1223
                if (backColor != null)
1224
                    xml.putProperty("backColor", StringUtilities.color2String(backColor));
1225

    
1226
                if (clip != null) {
1227
                        xml.putProperty("clipX", clip.getX());
1228
                        xml.putProperty("clipY", clip.getY());
1229
                        xml.putProperty("clipW", clip.getWidth());
1230
                        xml.putProperty("clipH", clip.getHeight());
1231
                }
1232

    
1233
                xml.putProperty("dist1pixel", dist1pixel);
1234
                xml.putProperty("dist3pixel", dist3pixel);
1235
                xml.putProperty("distanceUnits", distanceUnits);
1236

    
1237
                if (extent != null) {
1238
                        xml.putProperty("extentX", extent.getX());
1239
                        xml.putProperty("extentY", extent.getY());
1240
                        xml.putProperty("extentW", extent.getWidth());
1241
                        xml.putProperty("extentH", extent.getHeight());
1242
                }
1243

    
1244
                xml.addChild(extents.getXMLEntity());
1245
                xml.putProperty("mapUnits", mapUnits);
1246
                xml.putProperty("offsetX", offset.getX());
1247
                xml.putProperty("offsetY", offset.getY());
1248

    
1249
                if (proj != null) {
1250
                        xml.putProperty("proj", proj.getAbrev());
1251
                }
1252

    
1253
                xml.putProperty("scale", scale);
1254

    
1255
                return xml;
1256
        }
1257

    
1258

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

    
1272
                if (xml.contains("adjustedExtentX")) {
1273
                        vp.adjustedExtent = new Rectangle2D.Double(xml.getDoubleProperty(
1274
                                                "adjustedExtentX"),
1275
                                        xml.getDoubleProperty("adjustedExtentY"),
1276
                                        xml.getDoubleProperty("adjustedExtentW"),
1277
                                        xml.getDoubleProperty("adjustedExtentH"));
1278
                }
1279

    
1280
                if (xml.contains("backColor")) {
1281
                        vp.setBackColor(StringUtilities.string2Color(xml.getStringProperty(
1282
                                                "backColor")));
1283
                }else {
1284
                        vp.setBackColor(Color.white);
1285
                }
1286

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

    
1294
                vp.setDist1pixel(xml.getDoubleProperty("dist1pixel"));
1295
                vp.setDist3pixel(xml.getDoubleProperty("dist3pixel"));
1296
                vp.setDistanceUnits(xml.getIntProperty("distanceUnits"));
1297
                if (xml.contains("distanceArea")){
1298
                        vp.setDistanceArea(xml.getIntProperty("distanceArea"));
1299
                }else{
1300
                        vp.setDistanceArea(xml.getIntProperty("distanceUnits"));
1301
                }
1302
                vp.extents = ExtentHistory.createFromXML(xml.getChild(0));
1303

    
1304
                if (xml.contains("extentX")) {
1305
                        double x=xml.getDoubleProperty("extentX");
1306
                        double y=xml.getDoubleProperty("extentY");
1307
                        vp.setEnvelope(new DefaultEnvelope(2,new double[]{x,y},
1308
                                        new double[]{x+xml.getDoubleProperty("extentW"),y+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>Fast clone implementation: creates and returns a clone of this view port using XML entities.</p>
1332
         * <p>Isn't a <i>deepclone</i> to avoid unnecessary memory consumption.</p>
1333
         *
1334
         * @return the new view port
1335
         *
1336
         * @see #createFromXML(XMLEntity)
1337
         */
1338
        public ViewPort cloneViewPort() {
1339
                return createFromXML(getXMLEntity());
1340
        }
1341

    
1342
        /**
1343
         * <p>Returns a <code>String</code> representation of the main values of this view port: <code>{@linkplain #extent}</code>,
1344
         *  <code>{@linkplain #adjustedExtent}</code>, <code>{@linkplain #imageSize}</code>, <code>{@linkplain #scale}</code>, and <code>{@linkplain #trans}</code>.</p>
1345
         *
1346
         * @return a <code>string</code> representation of the main values of this view port
1347
         */
1348
        public String toString() {
1349

    
1350
                String str;
1351
                str = "Datos del viewPort:\nExtent=" + extent + "\nadjustedExtent=" +
1352
                        adjustedExtent + "\nimageSize=" + imageSize + "\nescale=" + scale +
1353
                        "\ntrans=" + trans;
1354

    
1355
                return str;
1356
        }
1357

    
1358
        /**
1359
         * <p>Sets the position and size of the clipping rectangle.</p>
1360
         *
1361
         * @param rectView the clipping rectangle to set
1362
         */
1363
        public void setClipRect(Rectangle2D rectView) {
1364
                cliprect=rectView;
1365
        }
1366

    
1367
        /**
1368
         * <p>Converts and returns the {@link Rectangle2D Rectangle2D}, that is in <i>map
1369
         *  coordinates</i> to <i>screen coordinates</i> (pixels) using an <i>inverse transform</i> with
1370
         *  the transformation affine information in the {@link #trans #trans} attribute.</p>
1371
         *
1372
         * @param r the 2D rectangle in <i>map coordinates</i>
1373
         * @return 2D rectangle equivalent in <i>screen coordinates</i> (pixels)
1374
         *
1375
         * @see #toMapRectangle(Rectangle2D)
1376
         * @see #fromMapDistance(double)
1377
         * @see #fromMapPoint(Point2D)
1378
         */
1379
        public Rectangle2D fromMapRectangle(Rectangle2D r) {
1380
                Rectangle2D rect=new Rectangle2D.Double();
1381
                Point2D p1=fromMapPoint((int)r.getX(),(int)r.getY());
1382
                Point2D p2=fromMapPoint((int)r.getMaxX(),(int)r.getMaxY());
1383
                rect.setFrameFromDiagonal(p1,p2);
1384
                return rect;
1385
        }
1386

    
1387
        /**
1388
         * <p>Recalculates the current <code>{@linkplain #extent}</code> using an scale. It's necessary execute {@linkplain #refreshExtent()} after.</p>
1389
         *
1390
         * @param s the scale to set
1391
         *
1392
         * @deprecated since 07/09/07, use {@linkplain MapContext#setScaleView(long)}
1393
         */
1394
        public void setScale(long s){
1395
                double x=extent.getX();
1396
                double y=extent.getY();
1397
                double escalaX = imageSize.getWidth() / extent.getWidth();
1398
                double w=imageSize.getWidth() / s;
1399
                double h=imageSize.getHeight() / s;
1400
                double difw = escalaX/s;
1401

    
1402
                double x1 = (-x * difw) -
1403
            x+
1404
            extent.getWidth()/2;
1405
        double y1 = (-y * difw) -
1406
            y +
1407
            extent.getHeight()/2;
1408
        double w1=extent.getWidth()*difw;
1409
        double h1=extent.getHeight()*difw;
1410
                extent.setRect(-x1,-y1,w1,h1);
1411
        }
1412
}