Statistics
| Revision:

svn-gvsig-desktop / trunk / libraries / libFMap / src / com / iver / cit / gvsig / fmap / ViewPort.java @ 1094

History | View | Annotate | Download (16.8 KB)

1
package com.iver.cit.gvsig.fmap;
2

    
3
import com.iver.utiles.StringUtilities;
4
import com.iver.utiles.XMLEntity;
5

    
6
import org.cresques.cts.GeoCalc;
7
import org.cresques.cts.IProjection;
8
import org.cresques.cts.ProjectionPool;
9
import org.cresques.cts.gt2.CSUTM;
10

    
11
import java.awt.Color;
12
import java.awt.Dimension;
13
import java.awt.Point;
14
import java.awt.geom.AffineTransform;
15
import java.awt.geom.NoninvertibleTransformException;
16
import java.awt.geom.Point2D;
17
import java.awt.geom.Rectangle2D;
18

    
19
import java.util.ArrayList;
20

    
21

    
22
/**
23
 * Clase con atributos de la vista.
24
 *
25
 * @author Vicente Caballero Navarro
26
 */
27
public class ViewPort {
28
        public static int KILOMETROS = 0;
29
        public static int METROS = 1;
30
        public static int CENTIMETRO = 2;
31
        public static int MILIMETRO = 3;
32
        public static int MILLAS = 4;
33
        public static int YARDAS = 5;
34
        public static int PIES = 6;
35
        public static int PULGADAS = 7;
36

    
37
        /**
38
         * Resoluci?n (Puntos por pulgada) de la vista actual. Se necesita para los
39
         * c?lculos de escala geogr?fica.
40
         */
41
        private static int dpi = java.awt.Toolkit.getDefaultToolkit()
42
                                                                                         .getScreenResolution();
43
        private Rectangle2D extent;
44
        private Rectangle2D adjustedExtent;
45
        private ExtentHistory extents = new ExtentHistory();
46
        private Dimension imageSize;
47
        private AffineTransform trans = new AffineTransform();
48
        private int distanceUnits = METROS;
49
        private int mapUnits = METROS;
50
        private ArrayList extentListeners = new ArrayList();
51
        private ArrayList colorListeners = new ArrayList();
52
        private Point2D offset = new Point2D.Double(0, 0);
53
        private Rectangle2D clip;
54
        private Color backColor = Color.WHITE;
55
        private IProjection proj;
56
        private double dist1pixel;
57
        private double dist3pixel;
58
        private double scale;
59

    
60
        /**
61
         * Crea un nuevo ViewPort.
62
         *
63
         * @param proj Proyecci?n.
64
         */
65
        public ViewPort(IProjection proj) {
66
                // Por defecto
67
                this.proj = proj;
68
        }
69

    
70
        /**
71
         * A?ade un ViewPortListener al extentListener.
72
         *
73
         * @param arg0 ViewPortListener.
74
         *
75
         * @return True si ha sido a?adida correctamente.
76
         */
77
        public boolean addExtentListener(ViewPortListener arg0) {
78
                return extentListeners.add(arg0);
79
        }
80

    
81
        /**
82
         * A?ade un ViewPortListener al colorListener.
83
         *
84
         * @param arg0 ViewPortListener,
85
         *
86
         * @return True si ha sido a?adida correctamente.
87
         */
88
        public boolean addColorListener(ViewPortListener arg0) {
89
                return colorListeners.add(arg0);
90
        }
91

    
92
        /**
93
         * Borra el ViewPortListener que se pasa como par?metro delos
94
         * extentListener.
95
         *
96
         * @param arg0 ViewPortListener.
97
         *
98
         * @return True si ha sido borrado correctamente.
99
         */
100
        public boolean removeExtentListener(ViewPortListener arg0) {
101
                return extentListeners.remove(arg0);
102
        }
103

    
104
        /**
105
         * Borra el ViewPortListener que se pasa como par?metro delos
106
         * colorListener.
107
         *
108
         * @param arg0 ViewPortListener.
109
         *
110
         * @return True si ha sido borrado correctamente.
111
         */
112
        public boolean removeColorListener(ViewPortListener arg0) {
113
                return colorListeners.remove(arg0);
114
        }
115

    
116
        /**
117
         * Devuelve la distancia en pixels a partir de una distancia real.
118
         *
119
         * @param d Distancia real.
120
         *
121
         * @return Distancia en pixels.
122
         */
123
        public int fromMapDistance(double d) {
124
                Point2D.Double pWorld = new Point2D.Double(1, 1);
125
                Point2D.Double pScreen = new Point2D.Double();
126

    
127
                double nuevoX;
128
                double nuevoY;
129
                double cX;
130
                double cY;
131

    
132
                try {
133
                        trans.deltaTransform(pWorld, pScreen);
134
                } catch (Exception e) {
135
                        System.err.print(e.getMessage());
136
                }
137

    
138
                return (int) (d * pScreen.x);
139
        }
140

    
141
        /**
142
         * Devuelve un punto en pixels a partir de una coordenada X e Y real.
143
         *
144
         * @param x Coordenada X real.
145
         * @param y Coordenada Y real.
146
         *
147
         * @return Punto en pixels.
148
         */
149
        public Point2D fromMapPoint(double x, double y) {
150
                Point2D.Double pWorld = new Point2D.Double(x, y);
151
                Point2D.Double pScreen = new Point2D.Double();
152

    
153
                double nuevoX;
154
                double nuevoY;
155
                double cX;
156
                double cY;
157

    
158
                try {
159
                        trans.transform(pWorld, pScreen);
160
                } catch (Exception e) {
161
                        System.err.print(e.getMessage());
162
                }
163

    
164
                return pScreen;
165
        }
166

    
167
        /**
168
         * Devuelve el punto en pixels a partir de un punto real.
169
         *
170
         * @param point Punto real.
171
         *
172
         * @return Punto en pixels.
173
         */
174
        public Point2D fromMapPoint(Point2D point) {
175
                return fromMapPoint(point.getX(), point.getY());
176
        }
177

    
178
        /**
179
         * Devuelve un punto real a partir de una coordenada X e Y en pixels.
180
         *
181
         * @param x Coordenada X en pixels.
182
         * @param y Coordenada Y en pixels.
183
         *
184
         * @return Punto real.
185
         */
186
        public Point2D toMapPoint(int x, int y) {
187
                Point pScreen = new Point(x, y);
188

    
189
                return toMapPoint(pScreen);
190
        }
191

    
192
        /**
193
         * Devuelve la distancia real a partir de la distancia en pixels.
194
         *
195
         * @param d Distancia en pixels.
196
         *
197
         * @return Distancia real.
198
         */
199
        public double toMapDistance(int d) {
200
                double dist = d / trans.getScaleX();
201

    
202
                return dist;
203
        }
204

    
205
        /**
206
         * Devuelve un punto real a partir de un punto en pixels.
207
         *
208
         * @param pScreen Punto en pixels.
209
         *
210
         * @return Punto real.
211
         *
212
         * @throws RuntimeException
213
         */
214
        public Point2D toMapPoint(Point2D pScreen) {
215
                Point2D.Double pWorld = new Point2D.Double();
216
                AffineTransform at;
217

    
218
                try {
219
                        at = trans.createInverse();
220
                        at.transform(pScreen, pWorld);
221
                } catch (NoninvertibleTransformException e) {
222
                        throw new RuntimeException(e);
223
                }
224

    
225
                return pWorld;
226
        }
227

    
228
        /**
229
         * Calcula la distancia entre dos puntos en unidades de usuario. Los puntos
230
         * est?n en unidades de usuario. Se tiene en cuenta la proyecci?n, con lo
231
         * que es INDISPENSABLE que la variable proj contenga el valor correcto de
232
         * la proyecci?n.
233
         *
234
         * @param pt1
235
         * @param pt2
236
         *
237
         * @return distancia real.
238
         */
239
        public double distanceWorld(Point2D pt1, Point2D pt2) {
240
                double dist = -1;
241
                dist = pt1.distance(pt2);
242

    
243
                if ((proj != null) && !(proj instanceof CSUTM)) {
244
                        dist = new GeoCalc(proj).distanceVincenty(proj.toGeo(pt1),
245
                                        proj.toGeo(pt2));
246
                }
247

    
248
                return dist;
249
        }
250

    
251
        /**
252
         * Rellena el extent anterior como actual.
253
         */
254
        public void setPreviousExtent() {
255
                extent = extents.removePrev();
256

    
257
                //Calcula la transformaci?n af?n
258
                calculateAffineTransform();
259

    
260
                // Lanzamos los eventos de extent cambiado
261
                callExtentListeners(adjustedExtent);
262
        }
263

    
264
        /**
265
         * Devuelve el extent.
266
         *
267
         * @return Extent.
268
         */
269
        public Rectangle2D getExtent() {
270
                return extent;
271
        }
272

    
273
        /**
274
         * Inserta el extent.
275
         *
276
         * @param r Extent.
277
         */
278
        public void setExtent(Rectangle2D r) {
279
                if (extent != null) {
280
                        extents.put(extent);
281
                }
282

    
283
                //Esto comprueba que el extent no es de anchura o altura = "0" 
284
                //y si es as? lo redimensiona.
285
                if ((r.getWidth() == 0) || (r.getHeight() == 0)) {
286
                        extent = new Rectangle2D.Double(r.getMinX() - 0.1,
287
                                        r.getMinY() - 0.1, r.getWidth() + 0.2, r.getHeight() + 0.2);
288
                } else {
289
                        extent = r;
290
                }
291

    
292
                //Calcula la transformaci?n af?n
293
                calculateAffineTransform();
294

    
295
                // Lanzamos los eventos de extent cambiado
296
                callExtentListeners(adjustedExtent);
297
        }
298

    
299
        /**
300
         * Inserta la escala.
301
         *
302
         * @param scale escala.
303
         */
304
        public void setScale(double scale) {
305
                this.scale = scale;
306

    
307
                //Calcula la transformaci?n af?n
308
                calculateAffineTransform();
309

    
310
                // Lanzamos los eventos de extent cambiado
311
                callExtentListeners(adjustedExtent);
312
        }
313

    
314
        /**
315
         * Devuelve la escala. Debe estar siempre actualizada y no calcularse nunca
316
         * aqu? pues se utiliza en el dibujado para cada geometr?a
317
         *
318
         * @return Escala.
319
         */
320
        public double getScale() {
321
                return proj.getScale(extent.getMinX(), extent.getMaxX(),
322
                        imageSize.getWidth(), dpi);
323
        }
324

    
325
        /**
326
         * Devuelve la matriz de transformaci?n.
327
         *
328
         * @return Matriz de transformaci?n.
329
         */
330
        public AffineTransform getAffineTransform() {
331
                return trans;
332
        }
333

    
334
        /**
335
         * Devuelve las dimensiones de la imagen.
336
         *
337
         * @return Returns the imageSize.
338
         */
339
        public Dimension getImageSize() {
340
                return imageSize;
341
        }
342

    
343
        /**
344
         * Inserta las dimensiones de la imagen.
345
         *
346
         * @param imageSize The imageSize to set.
347
         */
348
        public void setImageSize(Dimension imageSize) {
349
                this.imageSize = imageSize;
350
                calculateAffineTransform();
351
        }
352

    
353
        /**
354
         * Llamada a los listeners tras el cambio de extent.
355
         *
356
         * @param newRect Extent.
357
         */
358
        private void callExtentListeners(Rectangle2D newRect) {
359
                ExtentEvent ev = ExtentEvent.createExtentEvent(newRect);
360

    
361
                for (int i = 0; i < extentListeners.size(); i++) {
362
                        ViewPortListener listener = (ViewPortListener) extentListeners.get(i);
363
                        listener.extentChanged(ev);
364
                }
365
        }
366

    
367
        /**
368
         * Llamada a los listeners tras el cambio de color.
369
         *
370
         * @param c Color.
371
         */
372
        private void callColorListeners(Color c) {
373
                ColorEvent ce = ColorEvent.createColorEvent(c);
374

    
375
                for (int i = 0; i < colorListeners.size(); i++) {
376
                        ViewPortListener listener = (ViewPortListener) colorListeners.get(i);
377
                        listener.backColorChanged(ce);
378
                }
379
        }
380

    
381
        /**
382
         * C?lculo de la matriz de transformaci?n.
383
         *
384
         * @throws RuntimeException 
385
         */
386
        private void calculateAffineTransform() {
387
                if ((imageSize == null) || (extent == null) ||
388
                                (imageSize.getWidth() <= 0) || (imageSize.getHeight() <= 0)) {
389
                        return;
390
                }
391

    
392
                AffineTransform escalado = new AffineTransform();
393
                AffineTransform translacion = new AffineTransform();
394

    
395
                double escalaX;
396
                double escalaY;
397

    
398
                escalaX = imageSize.getWidth() / extent.getWidth();
399
                escalaY = imageSize.getHeight() / extent.getHeight();
400

    
401
                double xCenter = extent.getCenterX();
402
                double yCenter = extent.getCenterY();
403
                double newHeight;
404
                double newWidth;
405

    
406
                adjustedExtent = new Rectangle2D.Double();
407

    
408
                if (escalaX < escalaY) {
409
                        scale = escalaX;
410
                        newHeight = imageSize.getHeight() / scale;
411
                        adjustedExtent.setRect(xCenter - (extent.getWidth() / 2.0),
412
                                yCenter - (newHeight / 2.0), extent.getWidth(), newHeight);
413
                } else {
414
                        scale = escalaY;
415
                        newWidth = imageSize.getWidth() / scale;
416
                        adjustedExtent.setRect(xCenter - (newWidth / 2.0),
417
                                yCenter - (extent.getHeight() / 2.0), newWidth,
418
                                extent.getHeight());
419
                }
420

    
421
                translacion.setToTranslation(-adjustedExtent.getX(),
422
                        -adjustedExtent.getY() - adjustedExtent.getHeight());
423
                escalado.setToScale(scale, -scale);
424

    
425
                AffineTransform offsetTrans = new AffineTransform();
426
                offsetTrans.setToTranslation(offset.getX(), offset.getY());
427

    
428
                trans.setToIdentity();
429
                trans.concatenate(offsetTrans);
430
                trans.concatenate(escalado);
431

    
432
                trans.concatenate(translacion);
433

    
434
                // Calculamos las distancias de 1 pixel y 3 pixel con esa transformaci?n 
435
                // de coordenadas, de forma que est?n precalculadas para cuando las necesitemos
436
                AffineTransform at;
437

    
438
                try {
439
                        at = trans.createInverse();
440

    
441
                        java.awt.Point pPixel = new java.awt.Point(1, 1);
442
                        Point2D.Float pProv = new Point2D.Float();
443
                        at.deltaTransform(pPixel, pProv);
444

    
445
                        dist1pixel = pProv.x;
446
                        dist3pixel = 3 * pProv.x;
447
                } catch (NoninvertibleTransformException e) {
448
                        System.err.println("transformada afin = " + trans.toString());
449
                        System.err.println("extent = " + extent.toString() +
450
                                " imageSize= " + imageSize.toString());
451
                        throw new RuntimeException(e);
452
                }
453
        }
454

    
455
        /**
456
         * Inserta la desviaci?n.
457
         *
458
         * @param p Punto.
459
         */
460
        public void setOffset(Point2D p) {
461
                offset = p;
462
        }
463

    
464
        /**
465
         * Inserta el color de fondo.
466
         *
467
         * @param c Color de fondo.
468
         */
469
        public void setBackColor(Color c) {
470
                backColor = c;
471
                callColorListeners(backColor);
472
        }
473

    
474
        /**
475
         * Devuelve el color de fondo.
476
         *
477
         * @return Color de fondo.
478
         */
479
        public Color getBackColor() {
480
                return backColor;
481
        }
482

    
483
        /**
484
         * Devuelve el extent ajustado.
485
         *
486
         * @return Returns the adjustedExtent.
487
         */
488
        public Rectangle2D getAdjustedExtent() {
489
                return adjustedExtent;
490
        }
491

    
492
        /**
493
         * Devuelve la unidad de medida.
494
         *
495
         * @return Returns the distanceUnits.
496
         */
497
        public int getDistanceUnits() {
498
                return distanceUnits;
499
        }
500

    
501
        /**
502
         * Inserta la unidad de medida.
503
         *
504
         * @param distanceUnits The distanceUnits to set.
505
         */
506
        public void setDistanceUnits(int distanceUnits) {
507
                this.distanceUnits = distanceUnits;
508
        }
509

    
510
        /**
511
         * Devuelve la unidad de medida del mapa.
512
         *
513
         * @return Returns the mapUnits.
514
         */
515
        public int getMapUnits() {
516
                return mapUnits;
517
        }
518

    
519
        /**
520
         * Inserta la unidad de medida del mapa.
521
         *
522
         * @param mapUnits The mapUnits to set.
523
         */
524
        public void setMapUnits(int mapUnits) {
525
                this.mapUnits = mapUnits;
526
        }
527

    
528
        /**
529
         * Devuelve la anchura de la imagen.
530
         *
531
         * @return anchura en pixels de la imagen.
532
         */
533
        public int getImageWidth() {
534
                return imageSize.width;
535
        }
536

    
537
        /**
538
         * Devuelve la altura de la imagen.
539
         *
540
         * @return altura de la imagen.
541
         */
542
        public int getImageHeight() {
543
                return imageSize.height;
544
        }
545

    
546
        /**
547
         * Devuelve la distancia real de un pixel.
548
         *
549
         * @return Distancia real de un pixel.
550
         */
551
        public double getDist1pixel() {
552
                return dist1pixel;
553
        }
554

    
555
        /**
556
         * Inserta la distancia real de un pixel.
557
         *
558
         * @param dist1pixel Distancia real de un pixel.
559
         */
560
        public void setDist1pixel(double dist1pixel) {
561
                this.dist1pixel = dist1pixel;
562
        }
563

    
564
        /**
565
         * Devuelve la distancia real de tres pixel.
566
         *
567
         * @return Distancia real de tres pixel.
568
         */
569
        public double getDist3pixel() {
570
                return dist3pixel;
571
        }
572

    
573
        /**
574
         * Inserta la distancia real de tres pixels.
575
         *
576
         * @param dist3pixel Distancia real de tres pixels.
577
         */
578
        public void setDist3pixel(double dist3pixel) {
579
                this.dist3pixel = dist3pixel;
580
        }
581

    
582
        /**
583
         * Devuelve los Extents anteriores almacenados.
584
         *
585
         * @return Returns the extents.
586
         */
587
        public ExtentHistory getExtents() {
588
                return extents;
589
        }
590

    
591
        /**
592
         * Devuelve la proyecci?n.
593
         *
594
         * @return Returns the proj.
595
         */
596
        public IProjection getProjection() {
597
                return proj;
598
        }
599

    
600
        /**
601
         * Inserta la proyecci?n.
602
         *
603
         * @param proj The proj to set.
604
         */
605
        public void setProjection(IProjection proj) {
606
                this.proj = proj;
607
        }
608

    
609
        /**
610
         * Devuelve el XMLEntity.
611
         *
612
         * @return XMLEntity.
613
         */
614
        public XMLEntity getXMLEntity() {
615
                XMLEntity xml = new XMLEntity();
616
                xml.putProperty("className",this.getClass().getName());
617

    
618
                if (adjustedExtent != null) {
619
                        xml.putProperty("adjustedExtentX", adjustedExtent.getX());
620
                        xml.putProperty("adjustedExtentY", adjustedExtent.getY());
621
                        xml.putProperty("adjustedExtentW", adjustedExtent.getWidth());
622
                        xml.putProperty("adjustedExtentH", adjustedExtent.getHeight());
623
                }
624

    
625
                xml.putProperty("backColor", StringUtilities.color2String(backColor));
626

    
627
                if (clip != null) {
628
                        xml.putProperty("clipX", clip.getX());
629
                        xml.putProperty("clipY", clip.getY());
630
                        xml.putProperty("clipW", clip.getWidth());
631
                        xml.putProperty("clipH", clip.getHeight());
632
                }
633

    
634
                xml.putProperty("dist1pixel", dist1pixel);
635
                xml.putProperty("dist3pixel", dist3pixel);
636
                xml.putProperty("distanceUnits", distanceUnits);
637

    
638
                if (extent != null) {
639
                        xml.putProperty("extentX", extent.getX());
640
                        xml.putProperty("extentY", extent.getY());
641
                        xml.putProperty("extentW", extent.getWidth());
642
                        xml.putProperty("extentH", extent.getHeight());
643
                }
644

    
645
                xml.addChild(extents.getXMLEntity());
646
                xml.putProperty("mapUnits", mapUnits);
647
                xml.putProperty("offsetX", offset.getX());
648
                xml.putProperty("offsetY", offset.getY());
649

    
650
                if (proj != null) {
651
                        xml.putProperty("proj", proj.getAbrev());
652
                }
653

    
654
                xml.putProperty("scale", scale);
655

    
656
                return xml;
657
        }
658

    
659
        /**
660
         * Crea un nuevo ViewPort a partir del XMLEntity.
661
         *
662
         * @param xml XMLEntity.
663
         *
664
         * @return Nuevo ViewPort.
665
         */
666
        public static ViewPort createFromXML(XMLEntity xml) {
667
                ViewPort vp = new ViewPort(null);
668

    
669
                if (xml.contains("adjustedExtentX")) {
670
                        vp.adjustedExtent = new Rectangle2D.Double(xml.getDoubleProperty(
671
                                                "adjustedExtentX"),
672
                                        xml.getDoubleProperty("adjustedExtentY"),
673
                                        xml.getDoubleProperty("adjustedExtentW"),
674
                                        xml.getDoubleProperty("adjustedExtentH"));
675
                }
676

    
677
                if (xml.contains("backColor")) {
678
                        vp.setBackColor(StringUtilities.string2Color(xml.getStringProperty(
679
                                                "backColor")));
680
                }
681

    
682
                if (xml.contains("clipX")) {
683
                        vp.clip = new Rectangle2D.Double(xml.getDoubleProperty("clipX"),
684
                                        xml.getDoubleProperty("clipY"),
685
                                        xml.getDoubleProperty("clipW"),
686
                                        xml.getDoubleProperty("clipH"));
687
                }
688

    
689
                vp.setDist1pixel(xml.getDoubleProperty("dist1pixel"));
690
                vp.setDist3pixel(xml.getDoubleProperty("dist3pixel"));
691
                vp.setDistanceUnits(xml.getIntProperty("distanceUnits"));
692
                vp.extents = ExtentHistory.createFromXML(xml.getChild(0));
693

    
694
                if (xml.contains("extentX")) {
695
                        vp.setExtent(new Rectangle2D.Double(xml.getDoubleProperty("extentX"),
696
                                        xml.getDoubleProperty("extentY"),
697
                                        xml.getDoubleProperty("extentW"),
698
                                        xml.getDoubleProperty("extentH")));
699

    
700
                        //Calcula la transformaci?n af?n
701
                        vp.calculateAffineTransform();
702

    
703
                        // Lanzamos los eventos de extent cambiado
704
                        // vp.callExtentListeners(vp.adjustedExtent);
705
                }
706

    
707
                vp.setMapUnits(xml.getIntProperty("mapUnits"));
708
                vp.setOffset(new Point2D.Double(xml.getDoubleProperty("offsetX"),
709
                                xml.getDoubleProperty("offsetY")));
710

    
711
                if (xml.contains("proj")) {
712
                        vp.proj = ProjectionPool.get(xml.getStringProperty("proj"));
713
                }
714

    
715
                vp.setScale(xml.getDoubleProperty("scale"));
716

    
717
                return vp;
718
        }
719

    
720
        /**
721
         * Clona el ViewPort.
722
         *
723
         * @return ViewPort clonado.
724
         */
725
        public ViewPort cloneViewPort() {
726
                return createFromXML(getXMLEntity());
727
        }
728

    
729
        /**
730
         * Devuelve el String con datos del ViewPort.
731
         *
732
         * @return Cadena con datos del ViewPort.
733
         */
734
        public String toString() {
735
                String str;
736
                str = "Datos del viewPort:\nExtent=" + extent + "\nadjustedExtent=" +
737
                        adjustedExtent + "\nimageSize=" + imageSize + "\nescale=" + scale +
738
                        "\ntrans=" + trans;
739

    
740
                return str;
741
        }
742
}