Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.fmap.mapcontext / org.gvsig.fmap.mapcontext.api / src / main / java / org / gvsig / fmap / mapcontext / ViewPort.java @ 43552

History | View | Annotate | Download (55.7 KB)

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