Statistics
| Revision:

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

History | View | Annotate | Download (58.6 KB)

1 32880 jjdelcerro
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
2 21200 vcaballero
 *
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 29506 jtorres
 *   Av. Blasco Ib??ez, 50
24 21200 vcaballero
 *   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 26225 jmvivo
import java.awt.Toolkit;
46 21200 vcaballero
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 27514 cmartinez
import org.cresques.cts.UTM;
55 33652 jjdelcerro
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
56 27414 jpiera
import org.gvsig.fmap.geom.GeometryLocator;
57
import org.gvsig.fmap.geom.GeometryManager;
58
import org.gvsig.fmap.geom.exception.CreateEnvelopeException;
59 21426 vcaballero
import org.gvsig.fmap.geom.primitive.Envelope;
60 21200 vcaballero
import org.gvsig.fmap.mapcontext.events.ColorEvent;
61
import org.gvsig.fmap.mapcontext.events.ExtentEvent;
62
import org.gvsig.fmap.mapcontext.events.ProjectionEvent;
63
import org.gvsig.fmap.mapcontext.events.listeners.ViewPortListener;
64 30173 jldominguez
import org.gvsig.tools.ToolsLocator;
65 32880 jjdelcerro
import org.gvsig.tools.dynobject.DynStruct;
66 33652 jjdelcerro
import org.gvsig.tools.lang.Cloneable;
67 32711 cmartinez
import org.gvsig.tools.persistence.PersistenceManager;
68 30173 jldominguez
import org.gvsig.tools.persistence.Persistent;
69
import org.gvsig.tools.persistence.PersistentState;
70 32880 jjdelcerro
import org.gvsig.tools.persistence.exception.PersistenceException;
71 33652 jjdelcerro
import org.gvsig.tools.util.Callable;
72 27414 jpiera
import org.slf4j.Logger;
73
import org.slf4j.LoggerFactory;
74 21200 vcaballero
75
/**
76 29519 jtorres
 * <p>
77
 * <code>ViewPort</code> class represents the logic needed to transform a
78
 * rectangular area of a map to the available area in screen to display it.
79
 * </p>
80
 *
81
 * <p>
82
 * Includes an affine transformation, between the rectangular area selected of
83
 * the external map, in its own <i>map coordinates</i>, to the rectangular area
84
 * available of a view in <i>screen coordinates</i>.
85
 * </p>
86
 *
87
 * <p>
88
 * Elements:
89 21200 vcaballero
 * <ul>
90
 * <li><i>extent</i>: the area selected of the map, in <i>map coordinates</i>.
91 29519 jtorres
 * <li><i>imageSize</i>: width and height in pixels (<i>screen coordinates</i>)
92
 * of the area available in screen to display the area selected of the map.
93
 * <li><i>adjustedExtent</i>: the area selected must be an scale of
94
 * <i>imageSize</i>.<br>
95
 * This implies adapt the extent, preserving and centering it, and adding around
96
 * the needed area to fill all the image size. That added area will be extracted
97
 * from the original map, wherever exists, and filled with the background color
98
 * wherever not.
99 21200 vcaballero
 * <li><i>scale</i>: the scale between the adjusted extent and the image size.
100 29519 jtorres
 * <li><i>backColor</i>: the default background color in the view, if there is
101
 * no map.
102 21200 vcaballero
 * <li><i>trans</i>: the affine transformation.
103
 * <li><i>proj</i>: map projection used in this view.
104
 * <li><i>distanceUnits</i>: distance measurement units, of data in screen.
105
 * <li><i>mapUnits</i>: measurement units, of data in map.
106 29519 jtorres
 * <li><i>extents</i>: an {@link ExtentHistory ExtentHistory} with the last
107
 * previous extents.
108
 * <li><i>offset</i>: position in pixels of the available rectangular area,
109
 * where start drawing the map.
110
 * <li><i>dist1pixel</i>: the distance in <i>world coordinates</i> equivalent to
111
 * 1 pixel in the view with the current extent.
112
 * <li><i>dist3pixel</i>: the distance in <i>world coordinates</i> equivalent to
113
 * 3 pixels in the view with the current extent.
114
 * <li><i>listeners</i>: list with the {@link ViewPortListener ViewPortListener}
115
 * registered.
116 21200 vcaballero
 * </ul>
117
 * </p>
118 29519 jtorres
 *
119 21200 vcaballero
 * @author Vicente Caballero Navarro
120
 */
121 33613 fdiaz
public class ViewPort implements Persistent, Cloneable {
122 33352 cordinyana
123 33613 fdiaz
    private static final String FIELD_DISTANCE_AREA = "distanceArea";
124
    private static final String FIELD_IMAGE_SIZE = "imageSize";
125
    private static final String FIELD_PROJ = "proj";
126
    private static final String FIELD_OFFSET = "offset";
127
    private static final String FIELD_MAP_UNITS = "mapUnits";
128
    private static final String FIELD_EXTENT = "extent";
129
    private static final String FIELD_EXTENTS = "extents";
130
    private static final String FIELD_DISTANCE_UNITS = "distanceUnits";
131
    private static final String FIELD_DIST3PIXEL = "dist3pixel";
132
    private static final String FIELD_DIST1PIXEL = "dist1pixel";
133
    private static final String FIELD_CLIP = "clip";
134
    private static final String FIELD_BACK_COLOR = "backColor";
135
    private static final String FIELD_ADJUSTED_EXTENT = "adjustedExtent";
136 29519 jtorres
137 33613 fdiaz
    private static final GeometryManager geomManager =
138
        GeometryLocator.getGeometryManager();
139
    private static final Logger logger =
140
        LoggerFactory.getLogger(ViewPort.class);
141 21200 vcaballero
142 33613 fdiaz
    /**
143
     * <p>
144
     * Screen resolution in <i>dots-per-inch</i>. Useful to calculate the
145
     * geographic scale of the view.
146
     * </p>
147
     *
148
     * @see Toolkit#getScreenResolution()
149
     * @see #getScale()
150
     */
151
    private static int dpi = java.awt.Toolkit.getDefaultToolkit()
152
        .getScreenResolution();
153 21200 vcaballero
154 33613 fdiaz
    /**
155
     * <p>
156
     * Area selected by user using some tool.
157
     * </p>
158
     *
159
     * <p>
160
     * When the zoom changes (for instance when using the zoom in or zoom out
161
     * tools, but also zooming to a selected feature or shape) the extent that
162
     * covers that area is the value returned by this method. It is not the
163
     * actual area shown in the view because it does not care about the aspect
164
     * ratio of the available area. However, any part of the real world
165
     * contained in this extent is shown in the view.
166
     * </p>
167
     * <p>
168
     * Probably this is not what you are looking for. If you are looking for the
169
     * complete extent currently shown, you must use
170
     * {@linkplain #getAdjustedExtent()} method which returns the extent that
171
     * contains this one but regarding the current view's aspect ratio.
172
     * </p>
173
     *
174
     * @see #getExtent()
175
     * @see #setEnvelope(Envelope)
176
     */
177
    protected Rectangle2D extent;
178 21200 vcaballero
179 33613 fdiaz
    /**
180
     * <p>
181
     * Location and dimensions of the extent adjusted to the image size.
182
     * </p>
183
     *
184
     * @see #getAdjustedExtent()
185
     */
186
    protected Rectangle2D adjustedExtent;
187 29519 jtorres
188 33613 fdiaz
    /**
189
     * Draw version of the context. It's used for know when de componend has
190
     * changed any visualization property
191
     *
192
     * @see getDrawVersion
193
     * @see updateDrawVersion
194
     */
195
    private long drawVersion = 0L;
196 21200 vcaballero
197 33613 fdiaz
    /**
198
     * <p>
199
     * History with the last extents of the view.
200
     * </p>
201
     *
202
     * @see #setPreviousExtent()
203
     * @see #getExtents()
204
     */
205
    protected ExtentHistory extents = new ExtentHistory();
206 21200 vcaballero
207 33613 fdiaz
    /**
208
     * <p>
209
     * Size in <i>screen coordinates</i> of the rectangle where the image is
210
     * displayed.
211
     * </p>
212
     * <p>
213
     * Used by {@linkplain #calculateAffineTransform()} to calculate:<br>
214
     *
215
     * <ul>
216
     * <li>The new {@link #scale scale} .
217
     * <li>The new {@link #adjustedExtent adjustableExtent} .
218
     * <li>The new {@link #trans trans} .
219
     * <li>The new real world coordinates equivalent to 1 pixel (
220
     * {@link #dist1pixel dist1pixel}) .
221
     * <li>The new real world coordinates equivalent to 3 pixels (
222
     * {@link #dist3pixel dist3pixel}) .
223
     * </ul>
224
     * </p>
225
     *
226
     * @see #getImageSize()
227
     * @see #getImageHeight()
228
     * @see #getImageWidth()
229
     * @see #setImageSize(Dimension)
230
     */
231
    private Dimension imageSize;
232 21200 vcaballero
233 33613 fdiaz
    /**
234
     * <p>
235
     * the affine transformation between the {@link #extent extent} in <i>map 2D
236
     * coordinates</i> to the image area in the screen, in <i>screen 2D
237
     * coordinates</i> (pixels).
238
     * </p>
239
     *
240
     * @see AffineTransform
241
     *
242
     * @see #getAffineTransform()
243
     * @see #setAffineTransform(AffineTransform)
244
     * @see #calculateAffineTransform()
245
     */
246
    private AffineTransform trans = new AffineTransform();
247 21200 vcaballero
248 33613 fdiaz
    /**
249
     * <p>
250
     * Measurement unit used for measuring distances and displaying information.
251
     * </p>
252
     *
253
     * @see #getDistanceUnits()
254
     * @see #setDistanceUnits(int)
255
     */
256
    private int distanceUnits = 1;
257
    /**
258
     * <p>
259
     * Measurement unit used for measuring areas and displaying information.
260
     * </p>
261
     *
262
     * @see #getDistanceArea()
263
     * @see #setDistanceArea(int)
264
     */
265
    private int distanceArea = 1;
266
    /**
267
     * <p>
268
     * Measurement unit used by this view port for the map.
269
     * </p>
270
     *
271
     * @see #getMapUnits()
272
     * @see #setMapUnits(int)
273
     */
274
    private int mapUnits = 1;
275 21200 vcaballero
276 33613 fdiaz
    /**
277
     * <p>
278
     * Array with the {@link ViewPortListener ViewPortListener}s registered to
279
     * this view port.
280
     * </p>
281
     *
282
     * @see #addViewPortListener(ViewPortListener)
283
     * @see #removeViewPortListener(ViewPortListener)
284
     */
285
    private ArrayList listeners = new ArrayList();
286 21200 vcaballero
287 33613 fdiaz
    /**
288
     * <p>
289
     * The offset is the position where start drawing the map.
290
     * </p>
291
     * <p>
292
     * The offset of a <a href="http://www.gvsig.gva.es/">gvSIG</a>'s
293
     * <i>View</i> is always (0, 0) because the drawing area fits with the full
294
     * window area. But in a <a href="http://www.gvsig.gva.es/">gvSIG</a>'s
295
     * <i>Layout</i> it's up to the place where the <code>FFrameView</code> is
296
     * located.
297
     * </p>
298
     *
299
     * @see #getOffset()
300
     * @see #setOffset(Point2D)
301
     */
302
    private Point2D offset = new Point2D.Double(0, 0);
303 21200 vcaballero
304 33613 fdiaz
    /**
305
     * <p>
306
     * Clipping area.
307
     * </p>
308
     */
309
    // private Rectangle2D clip;
310 21200 vcaballero
311 33613 fdiaz
    /**
312
     * <p>
313
     * Background color of this view.
314
     * </p>
315
     *
316
     * @see #getBackColor()
317
     * @see #setBackColor(Color)
318
     */
319
    private Color backColor = null; // Color.WHITE;
320 21200 vcaballero
321 33613 fdiaz
    /**
322
     * <p>
323
     * Information about the map projection used in this view.
324
     * </p>
325
     *
326
     * @see #getProjection()
327
     * @see #setProjection(IProjection)
328
     */
329
    private IProjection proj;
330 21200 vcaballero
331 33613 fdiaz
    /**
332
     * <p>
333
     * Represents the distance in <i>world coordinates</i> equivalent to 1 pixel
334
     * in the view with the current extent.
335
     * </p>
336
     *
337
     * @see #getDist1pixel()
338
     * @see #setDist1pixel(double)
339
     */
340
    private double dist1pixel;
341 21200 vcaballero
342 33613 fdiaz
    /**
343
     * <p>
344
     * Represents the distance in <i>world coordinates</i> equivalent to 3
345
     * pixels in the view with the current extent.
346
     * </p>
347
     *
348
     * @see #getDist3pixel()
349
     * @see #setDist3pixel(double)
350
     */
351
    private double dist3pixel;
352 21200 vcaballero
353 33613 fdiaz
    /**
354
     * <p>
355
     * Ratio between the size of <code>imageSize</code> and <code>extent</code>:
356
     * <br>
357
     * <i>
358
     *
359
     * <pre>
360
     * min{(imageSize.getHeight()/extent.getHeight(), imageSize.getWidth()/extent.getWidth())}
361
     * </pre>
362
     *
363
     * </i>
364
     * </p>
365
     */
366
    private double scale;
367 21200 vcaballero
368 33613 fdiaz
    /**
369
     * <p>
370
     * Clipping area.
371
     * </p>
372
     *
373
     * @see #setClipRect(Rectangle2D)
374
     */
375
    private Rectangle2D cliprect;
376 21200 vcaballero
377 33613 fdiaz
    /**
378
     * <p>
379
     * Enables or disables the <i>"adjustable extent"</i> mode.
380
     * </p>
381
     *
382
     * <p>
383
     * When calculates the affine transform, if
384
     * <ul>
385
     * <li><i>enabled</i>: the new <code>adjustedExtent</code> will have the (X,
386
     * Y) coordinates of the <code>extent</code> and an area that will be an
387
     * scale of the image size. That area will have different height or width
388
     * (not both) of the extent according the least ratio (height or width) in
389
     *
390
     * <pre>
391
     * image.size/extent.size&quot;
392
     * </pre>.
393
     * <li><i>disabled</i>: the new <code>adjustedExtent</code> will be like
394
     * <code>extent</code>.
395
     * </ul>
396
     * </p>
397
     *
398
     * @see #setAdjustable(boolean)
399
     */
400
    private boolean adjustableExtent = true;
401 21200 vcaballero
402 33613 fdiaz
    public ViewPort() {
403 21200 vcaballero
404 33613 fdiaz
    }
405 21200 vcaballero
406 33613 fdiaz
    /**
407
     * <p>
408
     * Creates a new view port with the information of the projection in
409
     * <code>proj</code> argument, and default configuration:
410
     * </p>
411
     * <p>
412
     * <ul>
413
     * <li><i><code>distanceUnits</code></i> = meters
414
     * <li><i><code>mapUnits</code></i> = meters
415
     * <li><i><code>backColor</code></i> = <i>undefined</i>
416
     * <li><i><code>offset</code></i> = <code>new Point2D.Double(0, 0);</code>
417
     * </ul>
418
     * </p>
419
     *
420
     * @param proj
421
     *            information of the projection for this view port
422
     */
423
    public ViewPort(IProjection proj) {
424
        // Por defecto
425
        this.proj = proj;
426
    }
427 21200 vcaballero
428 33613 fdiaz
    /**
429
     * <p>
430
     * Changes the status of the <i>"adjustable extent"</i> option to enabled or
431
     * disabled.
432
     * </p>
433
     *
434
     * <p>
435
     * If view port isn't adjustable, won't bear in mind the aspect ratio of the
436
     * available rectangular area to calculate the affine transform from the
437
     * original map in real coordinates. (Won't scale the image to adapt it to
438
     * the available rectangular area).
439
     * </p>
440
     *
441
     * @param boolean the boolean to be set
442
     */
443
    public void setAdjustable(boolean adjustable) {
444
        if (adjustable == adjustableExtent) {
445
            return;
446
        }
447
        adjustableExtent = adjustable;
448
        this.updateDrawVersion();
449
    }
450 21200 vcaballero
451 33613 fdiaz
    /**
452
     * <p>
453
     * Appends the specified {@link ViewPortListener ViewPortListener} listener
454
     * if weren't.
455
     * </p>
456
     *
457
     * @param arg0
458
     *            the listener to add
459
     *
460
     * @return <code>true</code> if has been added successfully
461
     *
462
     * @see #removeViewPortListener(ViewPortListener)
463
     */
464
    public boolean addViewPortListener(ViewPortListener arg0) {
465
        if (!listeners.contains(arg0)) {
466
            return listeners.add(arg0);
467
        }
468
        return false;
469
    }
470 21200 vcaballero
471 33613 fdiaz
    /**
472
     * <p>
473
     * Removes the specified {@link ViewPortListener ViewPortListener} listener,
474
     * if existed.
475
     * </p>
476
     *
477
     * @param arg0
478
     *            the listener to remove
479
     *
480
     * @return <code>true</code> if the contained the specified listener.
481
     *
482
     * @see #addViewPortListener(ViewPortListener)
483
     */
484
    public boolean removeViewPortListener(ViewPortListener arg0) {
485
        return listeners.remove(arg0);
486
    }
487 21200 vcaballero
488 33613 fdiaz
    /**
489
     * <p>
490
     * Converts and returns the distance <code>d</code>, that is in <i>map
491
     * coordinates</i> to <i>screen coordinates</i> using a <i>delta
492
     * transform</i> with the transformation affine information in the
493
     * {@link #trans #trans} attribute.
494
     * </p>
495
     *
496
     * @param d
497
     *            distance in <i>map coordinates</i>
498
     *
499
     * @return distance equivalent in <i>screen coordinates</i>
500
     *
501
     * @see #toMapDistance(int)
502
     * @see AffineTransform#deltaTransform(Point2D, Point2D)S
503
     */
504
    public int fromMapDistance(double d) {
505
        Point2D.Double pWorld = new Point2D.Double(1, 1);
506
        Point2D.Double pScreen = new Point2D.Double();
507 21200 vcaballero
508 33613 fdiaz
        try {
509
            trans.deltaTransform(pWorld, pScreen);
510
        } catch (Exception e) {
511
            System.err.print(e.getMessage());
512
        }
513 21200 vcaballero
514 33613 fdiaz
        return (int) (d * pScreen.x);
515
    }
516 21200 vcaballero
517 33613 fdiaz
    /**
518
     * <p>
519
     * Converts and returns the 2D point <code>(x,y)</code>, that is in <i>map
520
     * coordinates</i> to <i>screen coordinates</i> (pixels) using the affine
521
     * transformation in the {@link #trans #trans} attribute.
522
     * </p>
523
     *
524
     * @param x
525
     *            the <code>x</code> <i>map coordinate</i> of a 2D point
526
     * @param y
527
     *            the <code>y</code> <i>map coordinate</i> of a 2D point
528
     *
529
     * @return 2D point equivalent in <i>screen coordinates</i> (pixels)
530
     *
531
     * @see #fromMapPoint(Point2D)
532
     * @see AffineTransform#transform(Point2D, Point2D)
533
     */
534
    public Point2D fromMapPoint(double x, double y) {
535
        Point2D.Double pWorld = new Point2D.Double(x, y);
536
        Point2D.Double pScreen = new Point2D.Double();
537 21200 vcaballero
538 33613 fdiaz
        try {
539
            trans.transform(pWorld, pScreen);
540
        } catch (Exception e) {
541
            System.err.print(e.getMessage());
542
        }
543 21200 vcaballero
544 33613 fdiaz
        return pScreen;
545
    }
546 21200 vcaballero
547 33613 fdiaz
    /**
548
     * <p>
549
     * Converts and returns the 2D point argument, that is in <i>map
550
     * coordinates</i> to <i>screen coordinates</i> (pixels) using the affine
551
     * transformation in the {@link #trans #trans} attribute.
552
     * </p>
553
     *
554
     * @param point
555
     *            the 2D point in <i>map coordinates</i>
556
     *
557
     * @return 2D point equivalent in <i>screen coordinates</i> (pixels)
558
     *
559
     * @see #toMapPoint(Point2D)
560
     * @see #fromMapPoint(double, double)
561
     */
562
    public Point2D fromMapPoint(Point2D point) {
563
        return fromMapPoint(point.getX(), point.getY());
564
    }
565 21200 vcaballero
566 33613 fdiaz
    /**
567
     * <p>
568
     * Converts and returns the 2D point <code>(x,y)</code>, that is in
569
     * <i>screen coordinates</i> (pixels) to <i>map coordinates</i> using the
570
     * affine transformation in the {@link #trans #trans} attribute.
571
     * </p>
572
     *
573
     * @param x
574
     *            the <code>x</code> <i>screen coordinate</i> of a 2D point
575
     * @param y
576
     *            the <code>y</code> <i>screen coordinate</i> of a 2D point
577
     *
578
     * @return 2D point equivalent in <i>map coordinates</i>
579
     *
580
     * @see #toMapPoint(Point2D)
581
     * @see #fromMapPoint(double, double)
582
     */
583
    public Point2D toMapPoint(int x, int y) {
584
        Point2D pScreen = new Point2D.Double(x, y);
585 21200 vcaballero
586 33613 fdiaz
        return toMapPoint(pScreen);
587
    }
588 21200 vcaballero
589 33613 fdiaz
    /**
590
     * <p>
591
     * Converts and returns the {@link Rectangle2D Rectangle2D}, that is in
592
     * <i>screen coordinates</i> (pixels) to <i>map coordinates</i> using
593
     * {@linkplain #toMapDistance(int)}, and {@linkplain #toMapPoint(int, int)}.
594
     * </p>
595
     *
596
     * @param r
597
     *            the 2D rectangle in <i>screen coordinates</i> (pixels)
598
     * @return 2D rectangle equivalent in <i>map coordinates</i>
599
     *
600
     * @see #fromMapRectangle(Rectangle2D)
601
     * @see #toMapDistance(int)
602
     * @see #toMapPoint(int, int)
603
     */
604
    public Rectangle2D toMapRectangle(Rectangle2D r) {
605
        Rectangle2D rect = new Rectangle2D.Double();
606
        Point2D p1 = toMapPoint((int) r.getX(), (int) r.getY());
607
        Point2D p2 = toMapPoint((int) r.getMaxX(), (int) r.getMaxY());
608
        rect.setFrameFromDiagonal(p1, p2);
609
        return rect;
610
    }
611 21200 vcaballero
612 33613 fdiaz
    /**
613
     * <p>
614
     * Converts and returns the distance <code>d</code>, that is in <i>screen
615
     * coordinates</i> to <i>map coordinates</i> using the transformation affine
616
     * information in the {@link #trans #trans} attribute.
617
     * </p>
618
     *
619
     * @param d
620
     *            distance in pixels
621
     *
622
     * @return distance equivalent in <i>map coordinates</i>
623
     *
624
     * @see #fromMapDistance(double)
625
     * @see AffineTransform
626
     */
627
    public double toMapDistance(int d) {
628
        double dist = d / trans.getScaleX();
629 21200 vcaballero
630 33613 fdiaz
        return dist;
631
    }
632 21200 vcaballero
633 33613 fdiaz
    /**
634
     * <p>
635
     * Converts and returns the 2D point argument, that is in <i>screen
636
     * coordinates</i> (pixels) to <i>map coordinates</i> using the inverse
637
     * affine transformation of the {@link #trans #trans} attribute.
638
     * </p>
639
     *
640
     * @param pScreen
641
     *            the 2D point in <i>screen coordinates</i> (pixels)
642
     *
643
     * @return 2D point equivalent in <i>map coordinates</i>
644
     *
645
     * @see #toMapPoint(int, int)
646
     * @see AffineTransform#createInverse()
647
     * @see AffineTransform#transform(Point2D, Point2D)
648
     */
649
    public Point2D toMapPoint(Point2D pScreen) {
650
        Point2D.Double pWorld = new Point2D.Double();
651
        AffineTransform at;
652 21200 vcaballero
653 33613 fdiaz
        try {
654
            at = trans.createInverse();
655
            at.transform(pScreen, pWorld);
656
        } catch (NoninvertibleTransformException e) {
657
            throw new RuntimeException("Non invertible transform Exception", e);
658
        }
659 21200 vcaballero
660 33613 fdiaz
        return pWorld;
661
    }
662 29519 jtorres
663 33613 fdiaz
    /**
664
     * <p>
665
     * Returns the real distance (in <i>world coordinates</i>) at the graphic
666
     * layers of two 2D points (in <i>map coordinates</i>) of the plane where is
667
     * selected the <i>extent</i>.
668
     * </p>
669
     * <p>
670
     * If the projection of this view is UTM, considers the Earth curvature.
671
     * </p>
672
     *
673
     * @param pt1
674
     *            a 2D point in <i>map coordinates</i>
675
     * @param pt2
676
     *            another 2D point in <i>map coordinates</i>
677
     *
678
     * @return the distance in meters between the two points 2D
679
     *
680
     * @see GeoCalcImpl#distanceVincenty(Point2D, Point2D)
681
     */
682
    public double distanceWorld(Point2D pt1, Point2D pt2) {
683
        double dist = -1;
684
        dist = pt1.distance(pt2);
685 21200 vcaballero
686 33613 fdiaz
        if ((proj != null) && !(proj instanceof UTM)) {
687
            dist =
688
                new GeoCalc(proj).distanceVincenty(proj.toGeo(pt1),
689
                    proj.toGeo(pt2));
690
            return dist;
691
        }
692
        return (dist * MapContext.getDistanceTrans2Meter()[getMapUnits()]);
693
    }
694 21200 vcaballero
695 33613 fdiaz
    /**
696
     * <p>
697
     * Sets as extent and adjusted extent of this view port, the previous.
698
     * Recalculating its parameters.
699
     * </p>
700
     *
701
     * @see #getExtents()
702
     * @see #calculateAffineTransform()
703
     * @deprecated use {@link ViewPort#setPreviousEnvelope()}
704
     */
705
    public void setPreviousExtent() {
706
        setPreviousEnvelope();
707
    }
708 21200 vcaballero
709 33613 fdiaz
    /**
710
     * <p>
711
     * Sets as envelope and adjusted envelope of this view port, the previous.
712
     * Recalculating its parameters.
713
     * </p>
714
     *
715
     * @see #getExtents()
716
     * @see #calculateAffineTransform()
717
     */
718
    public void setPreviousEnvelope() {
719
        this.updateDrawVersion();
720
        extent = extents.removePrev();
721 29519 jtorres
722 33613 fdiaz
        // Calcula la transformaci?n af?n
723
        calculateAffineTransform();
724 21200 vcaballero
725 33613 fdiaz
        // Lanzamos los eventos de extent cambiado
726
        callExtentChanged(getAdjustedExtent());
727
    }
728 21200 vcaballero
729 33613 fdiaz
    /**
730
     * <p>
731
     * Gets the area selected by user using some tool.
732
     * </p>
733
     *
734
     * <p>
735
     * When the zoom changes (for instance using the <i>zoom in</i> or <i>zoom
736
     * out</i> tools, but also zooming to a selected feature or shape) the
737
     * extent that covers that area is the value returned by this method. It is
738
     * not the actual area shown because it doesn't care about the aspect ratio
739
     * of the image size of the view. However, any part of the real world
740
     * contained in this extent is shown in the view.
741
     * </p>
742
     *
743
     * <p>
744
     * If you are looking for the complete extent currently shown, you must use
745
     * the {@linkplain #getAdjustedExtent()} method.
746
     * </p>
747
     *
748
     * @return the current extent
749
     *
750
     * @see #setEnvelope(Envelope)
751
     * @see #getAdjustedExtent()
752
     * @see #setPreviousExtent()
753
     * @see #getExtents()
754
     *
755
     * @deprecated use {@link ViewPort#getEnvelope()}
756
     */
757
    public Rectangle2D getExtent() {
758
        return extent;
759
    }
760 26905 jmvivo
761 33613 fdiaz
    /**
762
     * <p>
763
     * Gets the envelope selected by user using some tool.
764
     * </p>
765
     *
766
     * <p>
767
     * When the zoom changes (for instance using the <i>zoom in</i> or <i>zoom
768
     * out</i> tools, but also zooming to a selected feature or shape) the
769
     * envelope that covers that area is the value returned by this method. It
770
     * is not the actual envelope shown because it doesn't care about the aspect
771
     * ratio of the image size of the view. However, any part of the real world
772
     * contained in this envelope is shown in the view.
773
     * </p>
774
     *
775
     * <p>
776
     * If you are looking for the complete extent currently shown, you must use
777
     * the {@linkplain #getAdjustedEnvelope()} method.
778
     * </p>
779
     *
780
     * @return the current envelope
781
     *
782
     * @see #setEnvelope(Envelope)
783
     * @see #getAdjustedEnvelope()
784
     * @see #setPreviousEnvelope()
785
     * @see #getEnvelopes()
786
     */
787
    public Envelope getEnvelope() {
788
        if (this.extent == null) {
789
            return null;
790
        }
791
        try {
792
            return geomManager.createEnvelope(extent.getMinX(),
793
                extent.getMinY(),
794
                extent.getMaxX(),
795
                extent.getMaxY(),
796
                SUBTYPES.GEOM2D);
797
            // This class has to use Envelope instead of Rectangle2D. This catch
798
            // will disappear
799
        } catch (CreateEnvelopeException e) {
800
            logger.error("Error creating the envelope");
801
        }
802
        return null;
803
    }
804 21200 vcaballero
805 33613 fdiaz
    /**
806
     * <p>
807
     * Changes the <i>extent</i> and <i>adjusted extent</i> of this view port:<br>
808
     * <ul>
809
     * <li>Stores the previous extent.
810
     * <li>Calculates the new extent using <code>r</code>:
811
     *
812
     * <pre>
813
     * extent =
814
     *     new Rectangle2D.Double(r.getMinX() - 0.1,
815
     *         r.getMinY() - 0.1,
816
     *         r.getWidth() + 0.2,
817
     *         r.getHeight() + 0.2);
818
     * </pre>
819
     *
820
     * <li>Executes {@linkplain #calculateAffineTransform()}: getting the new
821
     * scale, adjusted extent, affine transformation between map and screen
822
     * coordinates, the real world coordinates equivalent to 1 pixel, and the
823
     * real world coordinates equivalent to 3 pixels.
824
     * <li>Notifies all {@link ViewPortListener ViewPortListener} registered
825
     * that the extent has changed.
826
     * </ul>
827
     * </p>
828
     *
829
     * @param r
830
     *            the new extent
831
     *
832
     * @see #getExtent()
833
     * @see #getExtents()
834
     * @see #calculateAffineTransform()
835
     * @see #setPreviousExtent()
836
     */
837
    public void setEnvelope(Envelope r) {
838
        Rectangle2D newExtent = null;
839
        // Esto comprueba que el extent no es de anchura o altura = "0"
840
        // y si es as? lo redimensiona.
841
        if (r != null) {
842
            if ((r.getMaximum(0) - r.getMinimum(0) == 0)
843
                || (r.getMaximum(1) - r.getMinimum(1) == 0)) {
844
                newExtent =
845
                    new Rectangle2D.Double(r.getMinimum(0) - 0.1,
846
                        r.getMinimum(1) - 0.1,
847
                        r.getMaximum(0) - r.getMinimum(0) + 0.2,
848
                        r.getMaximum(1) - r.getMinimum(1) + 0.2);
849
            } else {
850
                newExtent =
851
                    new Rectangle2D.Double(r.getMinimum(0),
852
                        r.getMinimum(1),
853
                        Math.abs(r.getMaximum(0) - r.getMinimum(0)),
854
                        Math.abs(r.getMaximum(1) - r.getMinimum(1)));
855
            }
856
        }
857 21200 vcaballero
858 33613 fdiaz
        if (this.extent != null && this.extent.equals(newExtent)) {
859
            return;
860
        }
861
        if (extent != null) {
862
            extents.put(extent);
863
        }
864
        this.updateDrawVersion();
865
        this.extent = newExtent;
866 21200 vcaballero
867 33613 fdiaz
        // Calcula la transformaci?n af?n
868
        calculateAffineTransform();
869 21200 vcaballero
870 33613 fdiaz
        // Lanzamos los eventos de extent cambiado
871
        callExtentChanged(getAdjustedExtent());
872
    }
873 21200 vcaballero
874 33613 fdiaz
    /**
875
     * <p>
876
     * Changes the <i>extent</i> and <i>adjusted extent</i> of this view port:<br>
877
     * <ul>
878
     * <li>Executes {@linkplain #calculateAffineTransform()}: getting the new
879
     * scale, adjusted extent, affine transformation between map and screen
880
     * coordinates, the real world coordinates equivalent to 1 pixel, and the
881
     * real world coordinates equivalent to 3 pixels.
882
     * <li>Notifies to all {@link ViewPortListener ViewPortListener} registered
883
     * that the extent has changed.
884
     * </ul>
885
     * </p>
886
     *
887
     * @see #setEnvelope(Envelope)
888
     * @see #calculateAffineTransform()
889
     */
890
    public void refreshExtent() {
891
        // this.scale = scale;
892 21200 vcaballero
893 33613 fdiaz
        // Calcula la transformaci?n af?n
894
        calculateAffineTransform();
895 21200 vcaballero
896 33613 fdiaz
        // Lanzamos los eventos de extent cambiado
897
        callExtentChanged(getAdjustedExtent());
898
    }
899 21200 vcaballero
900 33613 fdiaz
    /**
901
     * <p>
902
     * Calculates and returns using the current projection of this view port,
903
     * the scale that is the extent in <i>screen coordinates</i> from the image
904
     * in <i>map coordinates</i>.
905
     * </p>
906
     *
907
     * @return the scale <i>extent / image size</i> projected by this view port
908
     *
909
     * @deprecated since 07/09/07, use {@linkplain MapContext#getScaleView()}
910
     */
911
    public double getScale() {
912
        return proj.getScale(extent.getMinX(),
913
            extent.getMaxX(),
914
            imageSize.width,
915
            dpi);
916
    }
917 26225 jmvivo
918 33613 fdiaz
    /**
919
     * <p>
920
     * Affine transformation between <i>map 2D coordinates</i> to <i>screen 2D
921
     * coordinates</i> (pixels), preserving the "straightness" and "parallelism"
922
     * of the lines.
923
     * </p>
924
     *
925
     * @return the affine transformation
926
     *
927
     * @see #setAffineTransform(AffineTransform)
928
     * @see #calculateAffineTransform()
929
     */
930
    public AffineTransform getAffineTransform() {
931
        return trans;
932
    }
933 21200 vcaballero
934 33613 fdiaz
    /**
935
     * <p>
936
     * Returns the size of the image projected.
937
     * </p>
938
     *
939
     * @return the image size
940
     *
941
     * @see #setImageSize(Dimension)
942
     * @see #getImageHeight()
943
     * @see #getImageWidth()
944
     */
945
    public Dimension getImageSize() {
946
        return imageSize;
947
    }
948 21200 vcaballero
949 33613 fdiaz
    /**
950
     * <p>
951
     * Sets the size of the image projected, recalculating the parameters of
952
     * this view port.
953
     * </p>
954
     *
955
     * @param imageSize
956
     *            the image size
957
     *
958
     * @see #getImageSize()
959
     * @see #calculateAffineTransform()
960
     */
961
    public void setImageSize(Dimension imageSize) {
962 21200 vcaballero
963 33613 fdiaz
        if (this.imageSize == null || (!this.imageSize.equals(imageSize))) {
964
            this.updateDrawVersion();
965
            this.imageSize = imageSize;
966
            calculateAffineTransform();
967
        }
968
    }
969 21200 vcaballero
970 33613 fdiaz
    /**
971
     * <p>
972
     * Notifies to all view port listeners registered, that the adjusted extent
973
     * of this view port has changed.
974
     * </p>
975
     *
976
     * @param newRect
977
     *            the new adjusted extend
978
     *
979
     * @see #refreshExtent()
980
     * @see #setEnvelope(Envelope)
981
     * @see #setPreviousExtent()
982
     * @see ExtentEvent
983
     * @see ViewPortListener
984
     */
985
    protected void callExtentChanged(Envelope newRect) {
986
        ExtentEvent ev = ExtentEvent.createExtentEvent(newRect);
987 21200 vcaballero
988 33613 fdiaz
        for (int i = 0; i < listeners.size(); i++) {
989
            ViewPortListener listener = (ViewPortListener) listeners.get(i);
990
            listener.extentChanged(ev);
991
        }
992
    }
993 21200 vcaballero
994 33613 fdiaz
    /**
995
     * <p>
996
     * Notifies to all view port listeners registered, that the background color
997
     * of this view port has changed.
998
     * </p>
999
     *
1000
     * @param c
1001
     *            the new background color
1002
     *
1003
     * @see #setBackColor(Color)
1004
     * @see ColorEvent
1005
     * @see ViewPortListener
1006
     */
1007
    private void callColorChanged(Color c) {
1008
        ColorEvent ce = ColorEvent.createColorEvent(c);
1009 21200 vcaballero
1010 33613 fdiaz
        for (int i = 0; i < listeners.size(); i++) {
1011
            ViewPortListener listener = (ViewPortListener) listeners.get(i);
1012
            listener.backColorChanged(ce);
1013
        }
1014
    }
1015 21200 vcaballero
1016 33613 fdiaz
    /**
1017
     * <p>
1018
     * Notifies to all view port listeners registered, that the projection of
1019
     * this view port has changed.
1020
     * </p>
1021
     *
1022
     * @param projection
1023
     *            the new projection
1024
     *
1025
     * @see #setProjection(IProjection)
1026
     * @see ProjectionEvent
1027
     * @see ViewPortListener
1028
     */
1029
    private void callProjectionChanged(IProjection projection) {
1030
        ProjectionEvent ev = ProjectionEvent.createProjectionEvent(projection);
1031 21200 vcaballero
1032 33613 fdiaz
        for (int i = 0; i < listeners.size(); i++) {
1033
            ViewPortListener listener = (ViewPortListener) listeners.get(i);
1034
            listener.projectionChanged(ev);
1035
        }
1036
    }
1037 21200 vcaballero
1038 33613 fdiaz
    /**
1039
     * <p>
1040
     * Calculates the affine transformation between the {@link #extent extent}
1041
     * in <i>map 2D coordinates</i> to the image area in the screen, in
1042
     * <i>screen 2D coordinates</i> (pixels).
1043
     * </p>
1044
     *
1045
     * <p>
1046
     * This process recalculates some parameters of this view port:<br>
1047
     *
1048
     * <ul>
1049
     * <li>The new {@link #scale scale} .
1050
     * <li>The new {@link #adjustedExtent adjustedExtent} .
1051
     * <li>The new {@link #trans trans} .
1052
     * <li>The new real world coordinates equivalent to 1 pixel (
1053
     * {@link #dist1pixel dist1pixel}) .
1054
     * <li>The new real world coordinates equivalent to 3 pixels (
1055
     * {@link #dist3pixel dist3pixel}) .
1056
     * </ul>
1057
     * </p>
1058
     *
1059
     * @see #getAffineTransform()
1060
     * @see #setAffineTransform(AffineTransform)
1061
     * @see #refreshExtent()
1062
     * @see #setEnvelope(Envelope)
1063
     * @see #setImageSize(Dimension)
1064
     * @see #setPreviousExtent()
1065
     * @see #createFromXML(XMLEntity)
1066
     * @see AffineTransform
1067
     */
1068
    private void calculateAffineTransform() {
1069
        if ((imageSize == null) || (extent == null) || (imageSize.width <= 0)
1070
            || (imageSize.height <= 0)) {
1071
            return;
1072
        }
1073 21200 vcaballero
1074 33613 fdiaz
        AffineTransform escalado = new AffineTransform();
1075
        AffineTransform translacion = new AffineTransform();
1076 21200 vcaballero
1077 33613 fdiaz
        double escalaX;
1078
        double escalaY;
1079 21200 vcaballero
1080 33613 fdiaz
        escalaX = imageSize.width / extent.getWidth();
1081
        escalaY = imageSize.height / extent.getHeight();
1082 21200 vcaballero
1083 33613 fdiaz
        double xCenter = extent.getCenterX();
1084
        double yCenter = extent.getCenterY();
1085
        double newHeight;
1086
        double newWidth;
1087 21200 vcaballero
1088 33613 fdiaz
        adjustedExtent = new Rectangle2D.Double();
1089 21200 vcaballero
1090 33613 fdiaz
        if (adjustableExtent) {
1091
            if (escalaX < escalaY) {
1092
                scale = escalaX;
1093
                newHeight = imageSize.height / scale;
1094
                adjustedExtent.setRect(xCenter - (extent.getWidth() / 2.0),
1095
                    yCenter - (newHeight / 2.0),
1096
                    extent.getWidth(),
1097
                    newHeight);
1098
            } else {
1099
                scale = escalaY;
1100
                newWidth = imageSize.width / scale;
1101
                adjustedExtent.setRect(xCenter - (newWidth / 2.0), yCenter
1102
                    - (extent.getHeight() / 2.0), newWidth, extent.getHeight());
1103
            }
1104
            escalado.setToScale(scale, -scale);
1105
        } else { // adjusted is same as extent
1106
            scale = escalaX;
1107
            adjustedExtent.setFrame(extent);
1108
            escalado.setToScale(escalaX, -escalaY);
1109
        }
1110
        Envelope env = getAdjustedExtent();
1111
        if (env == null) {
1112
            return;
1113
        }
1114
        translacion.setToTranslation(-env.getMinimum(0), -env.getMinimum(1)
1115
            - getAdjustedExtent().getLength(1));
1116 21200 vcaballero
1117 33613 fdiaz
        AffineTransform offsetTrans = new AffineTransform();
1118
        offsetTrans.setToTranslation(offset.getX(), offset.getY());
1119 21200 vcaballero
1120 33613 fdiaz
        trans.setToIdentity();
1121
        trans.concatenate(offsetTrans);
1122
        trans.concatenate(escalado);
1123 21200 vcaballero
1124 33613 fdiaz
        trans.concatenate(translacion);
1125 21200 vcaballero
1126 33613 fdiaz
        // Calculamos las distancias de 1 pixel y 3 pixel con esa
1127
        // transformaci?n
1128
        // de coordenadas, de forma que est?n precalculadas para cuando las
1129
        // necesitemos
1130
        AffineTransform at;
1131 21200 vcaballero
1132 33613 fdiaz
        try {
1133
            at = trans.createInverse();
1134 21200 vcaballero
1135 33613 fdiaz
            Point2D pPixel = new Point2D.Float(1, 1);
1136 21200 vcaballero
1137 33613 fdiaz
            Point2D.Float pProv = new Point2D.Float();
1138
            at.deltaTransform(pPixel, pProv);
1139 21200 vcaballero
1140 33613 fdiaz
            dist1pixel = pProv.x;
1141
            dist3pixel = 3 * pProv.x;
1142
        } catch (NoninvertibleTransformException e) {
1143
            System.err.println("transformada afin = " + trans.toString());
1144
            System.err.println("extent = " + extent.toString() + " imageSize= "
1145
                + imageSize.toString());
1146
            throw new RuntimeException("Non invertible transform Exception", e);
1147
        }
1148
    }
1149 21200 vcaballero
1150 33613 fdiaz
    /**
1151
     * <p>
1152
     * Sets the offset.
1153
     * </p>
1154
     * <p>
1155
     * The offset is the position where start drawing the map.
1156
     * </p>
1157
     *
1158
     * @param p
1159
     *            2D point that represents the offset in pixels
1160
     *
1161
     * @see #getOffset()
1162
     */
1163
    public void setOffset(Point2D p) {
1164
        if (!offset.equals(p)) {
1165
            this.updateDrawVersion();
1166
            offset = p;
1167
        }
1168
    }
1169 29519 jtorres
1170 33613 fdiaz
    /**
1171
     * <p>
1172
     * Gets the offset.
1173
     * </p>
1174
     * <p>
1175
     * The offset is the position where start drawing the map.
1176
     * </p>
1177
     *
1178
     * @return 2D point that represents the offset in pixels
1179
     *
1180
     * @see #setOffset(Point2D)
1181
     */
1182
    public Point2D getOffset() {
1183
        return offset;
1184
    }
1185 21200 vcaballero
1186 33613 fdiaz
    /**
1187
     * <p>
1188
     * Sets the background color.
1189
     * </p>
1190
     *
1191
     * @param c
1192
     *            the new background color
1193
     *
1194
     * @see #getBackColor()
1195
     */
1196
    public void setBackColor(Color c) {
1197
        if (!c.equals(this.backColor)) {
1198
            this.updateDrawVersion();
1199
            backColor = c;
1200
            callColorChanged(backColor);
1201
        }
1202
    }
1203 29519 jtorres
1204 33613 fdiaz
    /**
1205
     * <p>
1206
     * Gets the background color.
1207
     * </p>
1208
     *
1209
     * @return the background color of the view
1210
     *
1211
     * @see #setBackColor(Color)
1212
     */
1213
    public Color getBackColor() {
1214
        return backColor;
1215
    }
1216 29519 jtorres
1217 33613 fdiaz
    /**
1218
     * <p>
1219
     * Returns the extent currently covered by the view adjusted (scaled) to the
1220
     * image size aspect.
1221
     * </p>
1222
     *
1223
     * @return extent of the view adjusted to the image size aspect
1224
     *
1225
     * @see #setAdjustable(boolean)
1226
     * @deprecated use {@link ViewPort#getAdjustedEnvelope()} instead
1227
     */
1228
    public Envelope getAdjustedExtent() {
1229
        return getAdjustedEnvelope();
1230
    }
1231 29519 jtorres
1232 33613 fdiaz
    /**
1233
     * <p>
1234
     * Returns the envelope currently covered by the view adjusted (scaled) to
1235
     * the image size aspect.
1236
     * </p>
1237
     *
1238
     * @return envelope of the view adjusted to the image size aspect
1239
     *
1240
     * @see #setAdjustable(boolean)
1241
     */
1242
    public Envelope getAdjustedEnvelope() {
1243
        if (cliprect != null) {
1244
            Rectangle2D r = adjustedExtent.createIntersection(cliprect);
1245
            try {
1246
                return geomManager.createEnvelope(r.getX(),
1247
                    r.getY(),
1248
                    r.getMaxX(),
1249
                    r.getMaxY(),
1250
                    SUBTYPES.GEOM2D);
1251
            } catch (CreateEnvelopeException e) {
1252
                e.printStackTrace();
1253
                logger.error("Error adjusting the extent", e);
1254
            }
1255
        }
1256
        if (adjustedExtent != null) {
1257
            try {
1258
                return geomManager.createEnvelope(adjustedExtent.getX(),
1259
                    adjustedExtent.getY(),
1260
                    adjustedExtent.getMaxX(),
1261
                    adjustedExtent.getMaxY(),
1262
                    SUBTYPES.GEOM2D);
1263
            } catch (CreateEnvelopeException e) {
1264
                e.printStackTrace();
1265
                logger.error("Error adjusting the extent", e);
1266
            }
1267
        }
1268
        return null;
1269
    }
1270 29519 jtorres
1271 33613 fdiaz
    /**
1272
     * <p>
1273
     * Returns the measurement unit of this view port used for measuring
1274
     * distances and displaying information.
1275
     * </p>
1276
     *
1277
     * @return the measurement unit of this view used for measuring distances
1278
     *         and displaying information
1279
     *
1280
     * @see #setDistanceUnits(int)
1281
     */
1282
    public int getDistanceUnits() {
1283
        return distanceUnits;
1284
    }
1285 21200 vcaballero
1286 33613 fdiaz
    /**
1287
     * <p>
1288
     * Returns the measurement unit of this view port used for measuring areas
1289
     * and displaying information.
1290
     * </p>
1291
     *
1292
     * @return the measurement unit of this view used for measuring areas and
1293
     *         displaying information
1294
     *
1295
     * @see #setDistanceUnits(int)
1296
     */
1297
    public int getDistanceArea() {
1298
        return distanceArea;
1299
    }
1300 21200 vcaballero
1301 33613 fdiaz
    /**
1302
     * <p>
1303
     * Sets the measurement unit of this view port used for measuring distances
1304
     * and displaying information.
1305
     * </p>
1306
     *
1307
     * @param distanceUnits
1308
     *            the measurement unit of this view used for measuring distances
1309
     *            and displaying information
1310
     *
1311
     * @see #getDistanceUnits()
1312
     */
1313
    public void setDistanceUnits(int distanceUnits) {
1314
        this.distanceUnits = distanceUnits;
1315
    }
1316 21200 vcaballero
1317 33613 fdiaz
    /**
1318
     * <p>
1319
     * Sets the measurement unit of this view port used for measuring areas and
1320
     * displaying information.
1321
     * </p>
1322
     *
1323
     * @param distanceUnits
1324
     *            the measurement unit of this view used for measuring areas and
1325
     *            displaying information
1326
     *
1327
     * @see #getDistanceUnits()
1328
     */
1329
    public void setDistanceArea(int distanceArea) {
1330
        this.distanceArea = distanceArea;
1331
    }
1332 21200 vcaballero
1333 33613 fdiaz
    /**
1334
     * <p>
1335
     * Gets the measurement unit used by this view port for the map.
1336
     * </p>
1337
     *
1338
     * @return Returns the current map measure unit
1339
     *
1340
     * @see #setMapUnits(int)
1341
     */
1342
    public int getMapUnits() {
1343
        return mapUnits;
1344
    }
1345 21200 vcaballero
1346 33613 fdiaz
    /**
1347
     * <p>
1348
     * Sets the measurement unit used by this view port for the map.
1349
     * </p>
1350
     *
1351
     * @param mapUnits
1352
     *            the new map measure unit
1353
     *
1354
     * @see #getMapUnits()
1355
     */
1356
    public void setMapUnits(int mapUnits) {
1357
        this.mapUnits = mapUnits;
1358
    }
1359 21200 vcaballero
1360 33613 fdiaz
    /**
1361
     * <p>
1362
     * Gets the width in <i>screen coordinates</i> of the rectangle where the
1363
     * image is displayed.
1364
     * </p>
1365
     * <p>
1366
     * Used by {@linkplain #calculateAffineTransform()} to calculate:<br>
1367
     *
1368
     * <ul>
1369
     * <li>The new {@link #scale scale} .
1370
     * <li>The new {@link #adjustedExtent adjustableExtent} .
1371
     * <li>The new {@link #trans trans} .
1372
     * <li>The new real world coordinates equivalent to 1 pixel (
1373
     * {@link #dist1pixel dist1pixel}) .
1374
     * <li>The new real world coordinates equivalent to 3 pixels (
1375
     * {@link #dist3pixel dist3pixel}) .
1376
     * </ul>
1377
     * </p>
1378
     *
1379
     * @see #getImageHeight()
1380
     * @see #getImageSize()
1381
     * @see #setImageSize(Dimension)
1382
     */
1383
    public int getImageWidth() {
1384
        return imageSize.width;
1385
    }
1386 21200 vcaballero
1387 33613 fdiaz
    /**
1388
     * <p>
1389
     * Gets the height in <i>screen coordinates</i> of the rectangle where the
1390
     * image is displayed.
1391
     * </p>
1392
     * <p>
1393
     * Used by {@linkplain #calculateAffineTransform()} to calculate:<br>
1394
     *
1395
     * <ul>
1396
     * <li>The new {@link #scale scale} .
1397
     * <li>The new {@link #adjustedExtent adjustableExtent} .
1398
     * <li>The new {@link #trans trans} .
1399
     * <li>The new real world coordinates equivalent to 1 pixel (
1400
     * {@link #dist1pixel dist1pixel}) .
1401
     * <li>The new real world coordinates equivalent to 3 pixels (
1402
     * {@link #dist3pixel dist3pixel}) .
1403
     * </ul>
1404
     * </p>
1405
     *
1406
     * @see #getImageWidth()
1407
     * @see #getImageSize()
1408
     * @see #setImageSize(Dimension)
1409
     */
1410
    public int getImageHeight() {
1411
        return imageSize.height;
1412
    }
1413 21200 vcaballero
1414 33613 fdiaz
    /**
1415
     * <p>
1416
     * Gets the distance in <i>world coordinates</i> equivalent to 1 pixel in
1417
     * the view with the current extent.
1418
     * </p>
1419
     *
1420
     * @return the distance
1421
     *
1422
     * @see #setDist1pixel(double)
1423
     */
1424
    public double getDist1pixel() {
1425
        return dist1pixel;
1426
    }
1427 29519 jtorres
1428 33613 fdiaz
    /**
1429
     * <p>
1430
     * Sets the distance in <i>world coordinates</i> equivalent to 1 pixel in
1431
     * the view with the current extent.
1432
     * </p>
1433
     *
1434
     * @param dist1pixel
1435
     *            the distance
1436
     *
1437
     * @see #getDist1pixel()
1438
     */
1439
    public void setDist1pixel(double dist1pixel) {
1440
        if (dist1pixel == this.dist1pixel) {
1441
            return;
1442
        }
1443
        this.updateDrawVersion();
1444
        this.dist1pixel = dist1pixel;
1445
    }
1446 21200 vcaballero
1447 33613 fdiaz
    /**
1448
     * <p>
1449
     * Gets the distance in <i>world coordinates</i> equivalent to 3 pixels in
1450
     * the view with the current extent.
1451
     * </p>
1452
     *
1453
     * @return the distance
1454
     *
1455
     * @see #setDist3pixel(double)
1456
     */
1457
    public double getDist3pixel() {
1458
        return dist3pixel;
1459
    }
1460 21200 vcaballero
1461 33613 fdiaz
    /**
1462
     * <p>
1463
     * Sets the distance in <i>world coordinates</i> equivalent to 3 pixels in
1464
     * the view with the current extent.
1465
     * </p>
1466
     *
1467
     * @param dist3pixel
1468
     *            the distance
1469
     *
1470
     * @see #getDist3pixel()
1471
     */
1472
    public void setDist3pixel(double dist3pixel) {
1473
        if (this.dist3pixel == dist3pixel) {
1474
            return;
1475
        }
1476
        this.updateDrawVersion();
1477
        this.dist3pixel = dist3pixel;
1478
    }
1479 21200 vcaballero
1480 33613 fdiaz
    /**
1481
     * <p>
1482
     * Returns the last previous extents of this view port.
1483
     * </p>
1484
     *
1485
     * @return the last previous extents of this view port
1486
     *
1487
     * @see #setPreviousExtent()
1488
     * @deprecated use {@link ViewPort#getEnvelopes()}
1489
     */
1490
    public ExtentHistory getExtents() {
1491
        return getEnvelopes();
1492
    }
1493 21200 vcaballero
1494 33613 fdiaz
    /**
1495
     * <p>
1496
     * Returns the last previous extents of this view port.
1497
     * </p>
1498
     *
1499
     * @return the last previous extents of this view port
1500
     *
1501
     * @see #setPreviousExtent()
1502
     */
1503
    public ExtentHistory getEnvelopes() {
1504
        return extents;
1505
    }
1506 21200 vcaballero
1507 33613 fdiaz
    /**
1508
     * <p>
1509
     * Gets the projection used in this view port.
1510
     * </p>
1511
     *
1512
     * @return projection used in this view port
1513
     *
1514
     * @see #setProjection(IProjection)
1515
     */
1516
    public IProjection getProjection() {
1517
        return proj;
1518
    }
1519 21200 vcaballero
1520 33613 fdiaz
    /**
1521
     * <p>
1522
     * Sets the projection to this view port.
1523
     * </p>
1524
     *
1525
     * @param proj
1526
     *            the new projection
1527
     *
1528
     * @see #getProjection()
1529
     */
1530
    public void setProjection(IProjection proj) {
1531
        if (this.proj == null || !this.proj.getAbrev().equals(proj.getAbrev())) {
1532
            this.updateDrawVersion();
1533
            this.proj = proj;
1534
            callProjectionChanged(proj);
1535
        }
1536
    }
1537 21200 vcaballero
1538 33613 fdiaz
    // -----------------------------------------------------------------------------------------------------------
1539
    // NOTA PARA DESARROLLADORES SOBRE EL M?TODO
1540
    // "public void setAffineTransform(AffineTransform at)"
1541
    // ==============================================================================================
1542
    // Only used for print, should be removed, redefining the {@link
1543
    // RasterAdapter RasterAdapter} interface,
1544
    // allowing it to receive a {@link ViewPortData ViewPortData} .
1545
    // -----------------------------------------------------------------------------------------------------------
1546 21200 vcaballero
1547 33613 fdiaz
    /**
1548
     * <p>
1549
     * Sets only the affine transform to this view port, without updating
1550
     * dependent attributes.
1551
     * </p>
1552
     * <p>
1553
     * <b><i>This method could be problematic!</i></b>
1554
     * </p>
1555
     *
1556
     * @param at
1557
     *            the affine transform to set
1558
     *
1559
     * @see #getAffineTransform()
1560
     * @see #calculateAffineTransform()
1561
     */
1562
    public void setAffineTransform(AffineTransform at) {
1563
        this.trans = at;
1564
    }
1565 31681 jldominguez
1566 33613 fdiaz
    /**
1567
     * <p>
1568
     * Returns an XML entity that represents this view port instance:<br>
1569
     * <ul>
1570
     * <li>Properties:
1571
     * <ul>
1572
     * <li><i>className</i>: name of this class.
1573
     * <li>If defined, the adjusted extent:
1574
     * <ul>
1575
     * <li><i>adjustedExtentX</i>: X coordinate of the adjusted extent.
1576
     * <li><i>adjustedExtentY</i>: Y coordinate of the adjusted extent.
1577
     * <li><i>adjustedExtentW</i>: width of the adjusted extent.
1578
     * <li><i>adjustedExtentH</i>: height of the adjusted extent.
1579
     * </ul>
1580
     * <li>If defined, the background color:
1581
     * <ul>
1582
     * <li><i>backColor</i>: background color.
1583
     * </ul>
1584
     * <li>If defined, the clip:
1585
     * <ul>
1586
     * <li><i>clipX</i>: X coordinate of the clip.
1587
     * <li><i>clipY</i>: Y coordinate of clip.
1588
     * <li><i>clipW</i>: width of the clip.
1589
     * <li><i>clipH</i>: height of the clip.
1590
     * </ul>
1591
     * <li><i>dist1pixel</i>: the distance in world coordinates equivalent to 1
1592
     * pixel in the view.
1593
     * <li><i>dist3pixel</i>: the distance in world coordinates equivalent to 3
1594
     * pixels in the view.
1595
     * <li><i>distanceUnits</i>: the distance measurement unit.
1596
     * <li>If defined, the extent:
1597
     * <ul>
1598
     * <li><i>extentX</i>: X coordinate of the extent.
1599
     * <li><i>extentY</i>: Y coordinate of the extent.
1600
     * <li><i>extentW</i>: width of the extent.
1601
     * <li><i>extentH</i>: height of the extent.
1602
     * </ul>
1603
     * <li><i>mapUnits</i>: the map measurement unit.
1604
     * <li><i>offsetX</i>: X coordinate of the offset.
1605
     * <li><i>offsetY</i>: Y coordinate of the offset.
1606
     * <li>If defined, the projection:
1607
     * <ul>
1608
     * <li>If its defined, the projection:
1609
     * <ul>
1610
     * <li><i>proj</i>: the projection.</li>
1611
     * </ul>
1612
     * </ul>
1613
     * <li><i>scale</i>: ratio between the size of <code>imageSize</code> and
1614
     * <code>extent</code>.
1615
     * </ul>
1616
     * <li>Child branches:
1617
     * <ul>
1618
     * <li>XML entity of the internal {@link ExtentHistory ExtentHistory} .
1619
     * </ul>
1620
     * </ul>
1621
     *
1622
     * @return the XML entity
1623
     *
1624
     * @see #createFromXML(XMLEntity)
1625
     */
1626
    public void saveToState(PersistentState state) throws PersistenceException {
1627 31681 jldominguez
1628 33613 fdiaz
        state.set(FIELD_ADJUSTED_EXTENT, adjustedExtent);
1629
        state.set(FIELD_BACK_COLOR, backColor);
1630
        state.set(FIELD_CLIP, cliprect);
1631
        state.set(FIELD_DIST1PIXEL, dist1pixel);
1632
        state.set(FIELD_DIST3PIXEL, dist3pixel);
1633
        state.set(FIELD_DISTANCE_UNITS, distanceUnits);
1634
        state.set(FIELD_DISTANCE_AREA, distanceArea);
1635
1636
        state.set(FIELD_EXTENT, extent);
1637
        state.set(FIELD_EXTENTS, extents);
1638
1639
        state.set(FIELD_MAP_UNITS, mapUnits);
1640
        state.set(FIELD_OFFSET, offset);
1641
1642
        state.set(FIELD_PROJ, proj);
1643
1644
        state.set(FIELD_IMAGE_SIZE, imageSize);
1645
    }
1646
1647
    public void loadFromState(PersistentState state) throws PersistenceException {
1648
1649
        adjustedExtent = (Rectangle2D) state.get(FIELD_ADJUSTED_EXTENT);
1650
        backColor = (Color) state.get(FIELD_BACK_COLOR);
1651
        cliprect = (Rectangle2D) state.get(FIELD_CLIP);
1652
        dist1pixel = state.getDouble(FIELD_DIST1PIXEL);
1653
        dist3pixel = state.getDouble(FIELD_DIST3PIXEL);
1654
        distanceUnits = state.getInt(FIELD_DISTANCE_UNITS);
1655
        extents = (ExtentHistory) state.get(FIELD_EXTENTS);
1656
        extent = (Rectangle2D) state.get(FIELD_EXTENT);
1657
        mapUnits = state.getInt(FIELD_MAP_UNITS);
1658
        offset = (Point2D) state.get(FIELD_OFFSET);
1659
        proj = (IProjection) state.get(FIELD_PROJ);
1660
        imageSize = (Dimension) state.get(FIELD_IMAGE_SIZE);
1661
        distanceArea = state.getInt(FIELD_DISTANCE_AREA);
1662
1663
        refreshExtent();
1664
    }
1665
1666 33652 jjdelcerro
        public static class RegisterPersistence implements Callable {
1667
1668
                public Object call() throws Exception {
1669
                        PersistenceManager manager = ToolsLocator.getPersistenceManager();
1670
                        if( manager.getDefinition("ViewPort")==null ) {
1671
                        DynStruct definition =
1672
                            manager.addDefinition(ViewPort.class,
1673
                                "ViewPort",
1674
                                "ViewPort Persistence definition",
1675
                                null,
1676
                                null);
1677
1678
                        definition.addDynFieldObject(FIELD_ADJUSTED_EXTENT)
1679
                            .setClassOfValue(Rectangle2D.class)
1680
                            .setMandatory(false);
1681
1682
                        definition.addDynFieldObject(FIELD_BACK_COLOR)
1683
                            .setClassOfValue(Color.class)
1684
                            .setMandatory(false);
1685
1686
                        definition.addDynFieldObject(FIELD_CLIP)
1687
                            .setClassOfValue(Rectangle2D.class)
1688
                            .setMandatory(false);
1689
1690
                        definition.addDynFieldDouble(FIELD_DIST1PIXEL).setMandatory(true);
1691
1692
                        definition.addDynFieldDouble(FIELD_DIST3PIXEL).setMandatory(true);
1693
1694
                        definition.addDynFieldInt(FIELD_DISTANCE_UNITS).setMandatory(true);
1695
1696
                        definition.addDynFieldInt(FIELD_DISTANCE_AREA).setMandatory(false);
1697
1698
                        definition.addDynFieldObject(FIELD_EXTENT)
1699
                            .setClassOfValue(Rectangle2D.class)
1700
                            .setMandatory(false);
1701
1702
                        definition.addDynFieldObject(FIELD_EXTENTS)
1703
                            .setClassOfValue(ExtentHistory.class)
1704
                            .setMandatory(true);
1705
1706
                        definition.addDynFieldInt(FIELD_MAP_UNITS).setMandatory(true);
1707
1708
                        definition.addDynFieldObject(FIELD_OFFSET)
1709
                            .setClassOfValue(Point2D.class)
1710
                            .setMandatory(false);
1711
1712
                        definition.addDynFieldObject(FIELD_PROJ)
1713
                            .setClassOfValue(IProjection.class)
1714
                            .setMandatory(true);
1715
1716
                        definition.addDynFieldObject(FIELD_IMAGE_SIZE)
1717
                            .setClassOfValue(Dimension.class)
1718
                            .setMandatory(false);
1719
                        }
1720
                        return Boolean.TRUE;
1721
                }
1722
1723
        }
1724
1725
        /**
1726 33613 fdiaz
     * Clone the view port without clone the listeners nor the extent history.
1727
     *
1728
     * @return the cloned view port
1729
     */
1730
    public Object clone() throws CloneNotSupportedException {
1731
1732
        ViewPort clonedViewPort = (ViewPort) super.clone();
1733
        clonedViewPort.listeners = new ArrayList();
1734
        clonedViewPort.extents = new ExtentHistory();
1735
1736
        if (this.adjustedExtent!=null){
1737
            clonedViewPort.adjustedExtent =
1738
                (Rectangle2D) this.adjustedExtent.clone();
1739
        }
1740
1741
        if (this.cliprect!=null){
1742
            clonedViewPort.cliprect = (Rectangle2D) this.cliprect.clone();
1743
        }
1744 31681 jldominguez
1745 33613 fdiaz
        if (this.extent!=null) {
1746
            clonedViewPort.extent = (Rectangle2D) this.extent.clone();
1747
        }
1748
        if (this.imageSize!=null){
1749
            clonedViewPort.imageSize = (Dimension) this.imageSize.clone();
1750
        }
1751 31681 jldominguez
1752 33613 fdiaz
        if (this.offset!=null){
1753
            clonedViewPort.offset = (Point2D) this.offset.clone();
1754
        }
1755
        if (proj!=null){
1756
            clonedViewPort.proj = (IProjection) this.proj.clone();
1757
        }
1758 31681 jldominguez
1759 33613 fdiaz
        clonedViewPort.trans = (AffineTransform) this.trans.clone();
1760 31681 jldominguez
1761 33613 fdiaz
        return clonedViewPort;
1762
    }
1763 30173 jldominguez
1764 33613 fdiaz
    /**
1765
     * <p>
1766
     * Returns a <code>String</code> representation of the main values of this
1767
     * view port: <code>{@linkplain #extent}</code>,
1768
     * <code>{@linkplain #adjustedExtent}</code>,
1769
     * <code>{@linkplain #imageSize}</code>, <code>{@linkplain #scale}</code>,
1770
     * and <code>{@linkplain #trans}</code>.
1771
     * </p>
1772
     *
1773
     * @return a <code>string</code> representation of the main values of this
1774
     *         view port
1775
     */
1776
    public String toString() {
1777 21200 vcaballero
1778 33613 fdiaz
        String str;
1779
        str =
1780
            "Datos del viewPort:\nExtent=" + extent + "\nadjustedExtent="
1781
                + adjustedExtent + "\nimageSize=" + imageSize + "\nescale="
1782
                + scale + "\ntrans=" + trans;
1783 21200 vcaballero
1784 33613 fdiaz
        return str;
1785
    }
1786 21200 vcaballero
1787 33613 fdiaz
    /**
1788
     * <p>
1789
     * Sets the position and size of the clipping rectangle.
1790
     * </p>
1791
     *
1792
     * @param rectView
1793
     *            the clipping rectangle to set
1794
     */
1795
    public void setClipRect(Rectangle2D rectView) {
1796
        this.updateDrawVersion();
1797
        cliprect = rectView;
1798
    }
1799 21200 vcaballero
1800 33613 fdiaz
    /**
1801
     * <p>
1802
     * Converts and returns the {@link Rectangle2D Rectangle2D}, that is in
1803
     * <i>map coordinates</i> to <i>screen coordinates</i> (pixels) using an
1804
     * <i>inverse transform</i> with the transformation affine information in
1805
     * the {@link #trans #trans} attribute.
1806
     * </p>
1807
     *
1808
     * @param r
1809
     *            the 2D rectangle in <i>map coordinates</i>
1810
     * @return 2D rectangle equivalent in <i>screen coordinates</i> (pixels)
1811
     *
1812
     * @see #toMapRectangle(Rectangle2D)
1813
     * @see #fromMapDistance(double)
1814
     * @see #fromMapPoint(Point2D)
1815
     */
1816
    public Rectangle2D fromMapRectangle(Rectangle2D r) {
1817
        Rectangle2D rect = new Rectangle2D.Double();
1818
        Point2D p1 = fromMapPoint((int) r.getX(), (int) r.getY());
1819
        Point2D p2 = fromMapPoint((int) r.getMaxX(), (int) r.getMaxY());
1820
        rect.setFrameFromDiagonal(p1, p2);
1821
        return rect;
1822
    }
1823 21200 vcaballero
1824 33613 fdiaz
    /**
1825
     * <p>
1826
     * Recalculates the current <code>{@linkplain #extent}</code> using an
1827
     * scale. It's necessary execute {@linkplain #refreshExtent()} after.
1828
     * </p>
1829
     *
1830
     * @param s
1831
     *            the scale to set
1832
     *
1833
     * @deprecated since 07/09/07, use
1834
     *             {@linkplain MapContext#setScaleView(long)}
1835
     */
1836
    public void setScale(long s) {
1837
        double x = extent.getX();
1838
        double y = extent.getY();
1839
        double escalaX = imageSize.width / extent.getWidth();
1840
        // double w = imageSize.width / s;
1841
        // double h = imageSize.height / s;
1842
        double difw = escalaX / s;
1843 26905 jmvivo
1844 33613 fdiaz
        double x1 = (-x * difw) - x + extent.getWidth() / 2;
1845
        double y1 = (-y * difw) - y + extent.getHeight() / 2;
1846
        double w1 = extent.getWidth() * difw;
1847
        double h1 = extent.getHeight() * difw;
1848
        extent.setRect(-x1, -y1, w1, h1);
1849
    }
1850 21200 vcaballero
1851 33613 fdiaz
    public long getDrawVersion() {
1852
        return this.drawVersion;
1853
    }
1854 21200 vcaballero
1855 33613 fdiaz
    protected void updateDrawVersion() {
1856
        this.drawVersion++;
1857
    }
1858 29519 jtorres
1859 33652 jjdelcerro
//    /**
1860
//     * Obtiene la representaci?n de un color como String
1861
//     *
1862
//     * @param c
1863
//     *            Color
1864
//     *
1865
//     * @return String
1866
//     */
1867
//    public static String color2String(Color c) {
1868
//        if (c == null)
1869
//            return null;
1870
//        return c.getRed() + "," + c.getGreen() + "," + c.getBlue() + ","
1871
//            + c.getAlpha();
1872
//    }
1873
//
1874
//    /**
1875
//     * Obtiene el color de un string generado con color2String
1876
//     *
1877
//     * @param stringColor
1878
//     *            string
1879
//     *
1880
//     * @return Color
1881
//     */
1882
//    public static Color string2Color(String stringColor) {
1883
//        if (stringColor == null || stringColor.equals("null"))
1884
//            return null;
1885
//        String[] ints = new String[4];
1886
//
1887
//        ints = CompatLocator.getStringUtils().split(stringColor, ",");
1888
//
1889
//        int[] ret = new int[4];
1890
//
1891
//        for (int i = 0; i < ret.length; i++) {
1892
//            ret[i] = new Integer(ints[i]).intValue();
1893
//        }
1894
//
1895
//        return new Color(ret[0], ret[1], ret[2], ret[3]);
1896
//    }
1897 29519 jtorres
1898 21200 vcaballero
}