Statistics
| Revision:

root / trunk / extensions / extGeoreferencing / src / org / gvsig / georeferencing / ui / zoom / CanvasZone.java @ 18530

History | View | Annotate | Download (18.2 KB)

1
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
2
 *
3
 * Copyright (C) 2007 IVER T.I. and Generalitat Valenciana.
4
 *
5
 * This program is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU General Public License
7
 * as published by the Free Software Foundation; either version 2
8
 * of the License, or (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
18
 */
19
package org.gvsig.georeferencing.ui.zoom;
20

    
21
import java.awt.Color;
22
import java.awt.Graphics;
23
import java.awt.Graphics2D;
24
import java.awt.event.MouseEvent;
25
import java.awt.event.MouseListener;
26
import java.awt.event.MouseMotionListener;
27
import java.awt.geom.Point2D;
28
import java.awt.geom.Rectangle2D;
29
import java.awt.image.BufferedImage;
30
import java.util.ArrayList;
31

    
32
import javax.swing.JPanel;
33

    
34
import org.gvsig.georeferencing.ui.zoom.tools.BaseViewTool;
35
import org.gvsig.raster.util.MathUtils;
36

    
37
/**
38
 * Zona de dibujado del raster
39
 * 21/12/2007
40
 * @author Nacho Brodin nachobrodin@gmail.com
41
 */
42
public class CanvasZone extends JPanel implements MouseListener, MouseMotionListener {
43
        private static final long      serialVersionUID     = 1308683333757367640L;
44
        
45
        private BufferedImage          image                = null;
46
        private double                 scale                = 1;
47
        private Rectangle2D            extent               = null;
48
        private double                 pixelSize            = 1;
49
        private Point2D                center               = null;
50
        private ArrayList              graphicLayers        = new ArrayList();
51
        /**
52
         * ?ltimo extent aplicado. Si no ha variado el siguiente a aplicar no hace falta que releamos de nuevo
53
         */
54
        private Rectangle2D            lastExtent           = null;
55
        //Ultimo Image con la capa dibujada y con la transformaci?n que tiene en cuenta los desplazamientos dentro de un pixel
56
        //Este buffer no varia hasta que se hace la siguiente petici?n de setDrawParams
57
        private BufferedImage          lastImage            = null;
58
        //lastImage sobre el que se pintan las capas gr?ficas. Este buffer varia en cada repaint. El orden en el que se carga
59
        //es: se vuelva el lastImage, se pintan las capas gr?ficas, se pintan las tools.
60
        private BufferedImage          lastImageWithLayers  = null;
61
    
62
    private boolean                clear                = false;
63
    private BaseViewTool           selectedTool         = null;
64
    
65
    private Point2D                realCoord            = new Point2D.Double(0, 0);
66
    //private Point2D                viewCoord = new Point2D.Double(0, 0);
67
    private boolean                showInfo             = false;
68
    /**
69
     * Informa de que la esquina superior izquierda corresponde con el valor de m?nimo X y
70
     * m?ximo Y. En caso de ser false esta esquina ser?a de m?nimo X y m?nimo Y.
71
     */
72
    private boolean                minxMaxyUL           = true;
73
                    
74
    private Color                  backgroundColor      = Color.BLACK;
75
    private Color                  textColor            = Color.RED;
76
    
77
    /**
78
     * Normalmente no se hace una petici?n al dibujado del raster si el extent no ha variado. Si esta variable
79
     * est? a true fuerza que haya una petici?n de redibujado aunque el extent del raster no haya cambiado.
80
     * Esto solo se hace para una petici?n. La siguiente vuelve a estar a false.
81
     */
82
    private boolean                forceRequest         = false;
83
    
84
    private ViewListener           viewListener         = null;
85
    private ViewEvent              viewEvent            = null;
86
    
87
    /**
88
         * Asigna los par?metros de dibujado
89
         * @param img Buffer con un ?rea de datos
90
         * @param ext Rectangle2D del ?rea de datos dada 
91
         * @param pixelSize Tama?o de pixel
92
         * @param center Punto del ?rea de datos donde se quiere centrar el dibujado del buffer
93
         */
94
        public void setDrawParams(BufferedImage img, Rectangle2D ext, double pixelSize, Point2D center) {
95
                this.image = img;
96
                this.extent = ext;
97
                this.pixelSize = pixelSize;
98
                this.center = center;
99
                this.addMouseListener(this);
100
                this.addMouseMotionListener(this);
101
                repaint();
102
        }
103
        
104
        /**
105
         * Asigna el listener de eventos de la vista
106
         * @param listener
107
         */
108
        public void setViewListener(ViewListener listener) {
109
                this.viewListener = listener;
110
                viewEvent = new ViewEvent(this);
111
        }
112
        
113
        /**
114
         * Asigna un nuevo centro de visualizaci?n
115
         * @param center
116
         */
117
        public void setCenter(Point2D center) {
118
                this.center = center;
119
                repaint();
120
        }
121
        
122
        /**
123
         * Conversi?n de un punto en coordenadas del canvas a reales
124
         * @param p
125
         * @return
126
         */
127
        public Point2D viewCoordsToWorld(Point2D p) {
128
                int w = getVisibleRect().width;
129
                int h = getVisibleRect().height;
130
                double cx = extent.getMinX() + ((p.getX() * extent.getWidth()) / w);
131
                double cy = 0;
132
                if(minxMaxyUL) //Cuando las Y decrecen de arriba a abajo
133
                        cy = extent.getMaxY() - (p.getY() * extent.getHeight()) / h;
134
                else //Cuando las Y crecen de arriba a abajo
135
                        cy = extent.getMinY() + (p.getY() * extent.getHeight()) / h;
136
                return new Point2D.Double(cx, cy);
137
        }
138
        
139
        /**
140
         * Conversi?n de un punto en coordenadas del canvas a reales
141
         * @param p
142
         * @return
143
         */
144
        public Point2D viewCoordsFromWorld(Point2D p) {
145
                int w = getVisibleRect().width;
146
                int h = getVisibleRect().height;
147
                double cx = ((p.getX() - extent.getMinX()) * w) / extent.getWidth();
148
                double cy = 0;
149
                if(minxMaxyUL) //Cuando las Y decrecen de arriba a abajo
150
                        cy = ((extent.getMaxY() - p.getY()) * h) / extent.getHeight();
151
                else //Cuando las Y crecen de arriba a abajo
152
                        cy = ((p.getY() - extent.getMinY()) * h) / extent.getHeight();
153
                return new Point2D.Double(cx, cy);
154
        }
155
        
156
        /**
157
         * Obtiene el extent del canvas en coordenadas del mundo real
158
         * @return Rectangle2D
159
         */
160
        public Rectangle2D getExtent() {
161
                if(lastExtent == null)
162
                        return extent;
163
                return lastExtent;
164
        }
165
        
166
        /**
167
         * Asigna un nuevo centro de visualizaci?n en coordenadas del
168
         * componente.
169
         * @param center
170
         */
171
        public void setViewCenter(Point2D c) {
172
                int w = getVisibleRect().width;
173
                int h = getVisibleRect().height;
174
                
175
                double cx = (c.getX() * lastExtent.getWidth()) / w;
176
                double cy = (c.getY() * lastExtent.getHeight()) / h;
177
                setPixelCenter(new Point2D.Double(cx, cy));
178
        }
179
        
180
        /**
181
         * Asigna un nuevo centro de visualizaci?n en coordenadas pixel
182
         * del ?rea de dibujado (canvas). El nuevo centro ser? calculado en coordenadas
183
         * del mapa.
184
         * @param center
185
         */
186
        public void setPixelCenter(Point2D c) {
187
                int w = getVisibleRect().width;
188
                int h = getVisibleRect().height;
189
                
190
                //Calculamos el extent del canvas 
191
                Rectangle2D ext = getCanvasExtent(w, h, scale);
192
                
193
                //Calculamos el nuevo centro en coordenadas reales
194
                double wWC = (c.getX() / scale) * pixelSize;
195
                double hWC = (c.getY() / scale) * pixelSize;
196
                this.center = new Point2D.Double(ext.getMinX() + wWC,
197
                                                                                 ext.getMinY() - hWC);
198
                repaint();
199
        }
200
        
201
        /**
202
         * Asigna un nuevo centro de visualizaci?n en coordenadas pixel. Esta llamada tiene
203
         * en cuenta solo p?xeles completos. No centra sobre porciones de pixel cuando el zoom es
204
         * mayor de 1:1. El nuevo centro es en coordenadas del mapa pero siempre centrar?
205
         * en la esquina inferior izquierda del pixel.
206
         * @param center
207
         */
208
        public void setPixelCenter(int x, int y) {
209
                int w = getVisibleRect().width;
210
                int h = getVisibleRect().height;
211
                
212
                //Calculamos el extent del canvas 
213
                Rectangle2D ext = getCanvasExtent(w, h, scale);
214
                
215
                //Calculamos el nuevo centro en coordenadas reales
216
                double wWC = (x / scale) * pixelSize;
217
                double hWC = (y / scale) * pixelSize;
218
                Point2D center = new Point2D.Double(ext.getMinX() + wWC,
219
                                                                                          ext.getMinY() - hWC);
220
                
221
                //Calculamos la coordena pixel a la que pertenece esa coordenada real
222
                int pxX = (int)((center.getX() * (w / scale)) / ext.getWidth());
223
                int pxY = (int)((center.getY() * (h / scale)) / ext.getHeight());
224
                
225
                //Despu?s de haber convertido a pixel y redondeado la coordenada a entero volvemos a convertirla en real
226
                double wcX = (pxX * ext.getWidth()) / (w / scale);
227
                double wcY = (pxY * ext.getHeight()) / (h / scale);
228

    
229
                this.center = new Point2D.Double(wcX, wcY);
230
                repaint();
231
        }
232
        
233
        /**
234
         * Asigna una capa gr?fica
235
         * @param layer IGraphicLayer
236
         */
237
        public void setGraphicLayer(IGraphicLayer layer) {
238
                graphicLayers.add(layer);
239
        }
240
        
241
        /**
242
         * Asigna la escala para el nuevo zoom
243
         * @param scale
244
         */
245
        public void setZoom(double scale) {
246
                this.scale = scale;
247
                repaint();
248
        }
249
        
250
        /**
251
         * Obtiene la escala aplicada en el dibujado
252
         * @return double
253
         */
254
        public double getZoom() {
255
                return scale;
256
        }
257
        
258
        /**
259
         * Obtiene el extent actual asignado al canvas
260
         * @return Rectangle2D
261
         */
262
        public Rectangle2D getCanvasExtent() {
263
                return lastExtent;
264
        }
265
        
266
        /**
267
         * Asigna el extent del canvas
268
         * @param r
269
         */
270
        public void setCanvasExtent(Rectangle2D r) {
271
                this.lastExtent = r;
272
        }
273
        
274
        /**
275
         * Obtiene el tama?o de pixel
276
         * @return double
277
         */
278
        public double getPixelSize() {
279
                return pixelSize;
280
        }
281
        
282
        /**
283
         * Obtiene el centro del canvas
284
         * @return Point2D
285
         */
286
        public Point2D getCenter() {
287
                return center;
288
        }
289
        
290
        /**
291
         * Obtiene el buffer de la vista activa y lo dibuja sobre el panel
292
         * con los datos de escala y desplazamiento seleccionados.
293
         */
294
        protected void paintComponent(Graphics g) {
295
                if(image == null)
296
                        return;
297
                
298
                if(viewListener != null)
299
                        viewListener.startDraw(viewEvent);
300
                
301
                int w = getVisibleRect().width;
302
                int h = getVisibleRect().height;
303
                Rectangle2D ext = getCanvasExtent(w, h, scale);
304
                
305
                if(lastImage == null || !equal(lastExtent, ext)) { 
306
                        lastImage = new BufferedImage((int)w, (int)h, BufferedImage.TYPE_INT_RGB);
307
                        lastImageWithLayers = new BufferedImage((int)w, (int)h, BufferedImage.TYPE_INT_RGB);
308
                }
309
                                
310
                if(clear) {
311
                        g.setColor(backgroundColor);
312
                        g.fillRect(0, 0, w, h);
313
                        return;
314
                }
315
                
316
                //Dibujamos el buffer sobre el grafics
317
                Graphics graphicsDB = draw(ext, w, h);        
318
                                
319
                //Dibujamos todas las capas registradas
320
                for (int i = 0; i < graphicLayers.size(); i++) 
321
                        ((IGraphicLayer)graphicLayers.get(i)).draw((Graphics2D)graphicsDB, ext, w, h);
322
                
323
                lastExtent = ext;
324
                
325
                if(selectedTool != null)
326
                        selectedTool.draw(graphicsDB);
327
                        
328
                if(showInfo)
329
                        showInfo(graphicsDB);
330
                                
331
                g.drawImage(lastImageWithLayers, 0, 0, this);
332
                graphicsDB.dispose();
333
                
334
                if(viewListener != null)
335
                        viewListener.endDraw(viewEvent);
336
        }
337
        
338
        /**
339
         * Muestra informaci?n sobre la vista
340
         * @param g
341
         */
342
        private void showInfo(Graphics g) {
343
                g.setColor(textColor);
344
                g.drawString("X: " + MathUtils.tailDecimals(realCoord.getX(), 3), 12, 18);
345
                g.drawString("Y: " + MathUtils.tailDecimals(realCoord.getY(), 3), 12, 32);
346
                //g.drawString("X': " + MathUtils.tailDecimals(viewCoord.getX(), 3), 12, 46);
347
                //g.drawString("Y': " + MathUtils.tailDecimals(viewCoord.getY(), 3), 12, 60);
348
        }
349
        
350
        /**
351
         * Compara dos extents y devuelve true si son iguales y false si son distintos
352
         * @param e1 Extent 1
353
         * @param e2 Extent 2
354
         * @return true si son iguales y false si son diferentes
355
         */
356
        private boolean equal(Rectangle2D e1, Rectangle2D e2) {
357
                return (e1 != null && e2 != null && e1.getMinX() == e2.getMinX() && e1.getMinY() == e2.getMinY() 
358
                                && e1.getMaxX() == e2.getMaxX() && e1.getMaxY() == e2.getMaxY());
359
        }
360
        
361
        /**
362
         * Obtiene el Extent del canvas. Este canvas tiene un ancho en pixeles
363
         * de w y un alto de h. Tiene en cuenta la escala a la que se quiere dibujar
364
         * para devolver el extent cuando el zoom ya est? aplicado.
365
         * @param w Ancho del canvas en p?xeles
366
         * @param h Alto del canvas en p?xeles
367
         * @return Rectangle2D
368
         */
369
        private Rectangle2D getCanvasExtent(double w, double h, double scale) {
370
                double tW = ((w / scale) / 2) * pixelSize;
371
                double tH = ((h / scale) / 2) * pixelSize;
372
                double minX = center.getX() - tW;
373
                double minY = center.getY() - tH;
374
                double width = Math.abs((center.getX() + tW) - minX);
375
                double height = Math.abs((center.getY() + tH) - minY);
376
                return new Rectangle2D.Double(minX, minY, width, height);
377
        }
378
        
379
        /**
380
         * <P>
381
         * Dibujado del buffer de datos sobre el Graphics. 
382
         * </P><P>
383
         * No podemos aplicar un escalado al
384
         * Graphics y dibujar porque cuando el zoom es mayor a 1 los pixeles no empiezan a dibujarse
385
         * siempre en la esquina superior izquierda y al Graphics solo podemos ordenarle el dibujado
386
         * en coordenadas enteras. Para solucionarlo debemos copiar el trozo de buffer a dibujar teniendo
387
         * en cuenta el desplazamiento de la esquina superior izquierda de un pixel.
388
         * </P> 
389
         * @param g
390
         * @param ext
391
         * @param w
392
         * @param h
393
         */
394
        private Graphics draw(Rectangle2D ext, double w, double h) {
395
                if(!equal(lastExtent, ext)  || forceRequest) {                        
396
                        //Hallamos la coordenada pixel del buffer de la esquina superior izquierda del extent
397
                        double pxX = ((ext.getMinX() - extent.getMinX()) * (w / scale)) / ext.getWidth();
398
                        double pxY = ((extent.getMinY() - ext.getMinY()) * (h / scale)) / ext.getHeight();
399

    
400
                        //Creamos el buffer y lo cargamos teniendo en cuenta el desplazamiento inicial
401
                        double step = 1 / scale;
402

    
403
                        double xValue = pxX;
404
                        double yValue = pxY;
405

    
406
                        for (int i = 0; i < w; i++) {
407
                                yValue = pxY;
408
                                for (int j = 0; j < h; j++) {
409
                                        if((int)xValue >= 0 && (int)yValue >= 0 && (int)xValue < image.getWidth() && (int)yValue < image.getHeight()) {
410
                                                lastImage.setRGB(i, j, image.getRGB((int)xValue, (int)yValue));
411
                                                lastImageWithLayers.setRGB(i, j, image.getRGB((int)xValue, (int)yValue));
412
                                        } else {
413
                                                lastImage.setRGB(i, j, 0xffffffff);
414
                                                lastImageWithLayers.setRGB(i, j, 0xffffffff);
415
                                        }
416
                                        yValue += step;
417
                                }
418
                                xValue += step;
419
                        }
420
                        if(viewListener != null)
421
                                viewListener.zoomViewChanged(viewEvent);
422
                        forceRequest = false;
423
                } else 
424
                        ((Graphics2D)lastImageWithLayers.getGraphics()).drawImage(lastImage, 0, 0, null);
425
                
426
                return lastImageWithLayers.getGraphics();
427
        }
428

    
429
        /*
430
         * (non-Javadoc)
431
         * @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent)
432
         */
433
        public void mouseClicked(MouseEvent e) {
434
                for (int i = 0; i < graphicLayers.size(); i++) 
435
                        ((IGraphicLayer)graphicLayers.get(i)).mouseClicked(e);
436
                repaint();
437
        }
438

    
439
        /*
440
         * (non-Javadoc)
441
         * @see java.awt.event.MouseListener#mouseEntered(java.awt.event.MouseEvent)
442
         */
443
        public void mouseEntered(MouseEvent e) {
444
                for (int i = 0; i < graphicLayers.size(); i++) 
445
                        ((IGraphicLayer)graphicLayers.get(i)).mouseEntered(e);
446
                repaint();
447
        }
448

    
449
        /*
450
         * (non-Javadoc)
451
         * @see java.awt.event.MouseListener#mouseExited(java.awt.event.MouseEvent)
452
         */
453
        public void mouseExited(MouseEvent e) {
454
                for (int i = 0; i < graphicLayers.size(); i++) 
455
                        ((IGraphicLayer)graphicLayers.get(i)).mouseExited(e);
456
                repaint();
457
        }
458

    
459
        /*
460
         * (non-Javadoc)
461
         * @see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent)
462
         */
463
        public void mousePressed(MouseEvent e) {
464
                for (int i = 0; i < graphicLayers.size(); i++) 
465
                        ((IGraphicLayer)graphicLayers.get(i)).mousePressed(e);
466
                repaint();
467
        }
468

    
469
        /*
470
         * (non-Javadoc)
471
         * @see java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent)
472
         */
473
        public void mouseReleased(MouseEvent e) {
474
                for (int i = 0; i < graphicLayers.size(); i++) 
475
                        ((IGraphicLayer)graphicLayers.get(i)).mouseReleased(e);
476
                repaint();
477
        }
478

    
479
        /*
480
         * (non-Javadoc)
481
         * @see java.awt.event.MouseMotionListener#mouseDragged(java.awt.event.MouseEvent)
482
         */
483
        public void mouseDragged(MouseEvent e) {
484
                for (int i = 0; i < graphicLayers.size(); i++) 
485
                        ((IGraphicLayer)graphicLayers.get(i)).mouseDragged(e);
486
                repaint();
487
        }
488

    
489
        /*
490
         * (non-Javadoc)
491
         * @see java.awt.event.MouseMotionListener#mouseMoved(java.awt.event.MouseEvent)
492
         */
493
        public void mouseMoved(MouseEvent e) {
494
                realCoord = viewCoordsToWorld((Point2D)e.getPoint());
495
                //viewCoord = e.getPoint();
496
                for (int i = 0; i < graphicLayers.size(); i++) 
497
                        ((IGraphicLayer)graphicLayers.get(i)).mouseMoved(e);
498
                repaint();
499
        }
500

    
501
        /**
502
         * Asigna la tool seleccionada
503
         * @param selectedTool
504
         */
505
        public void setSelectedTool(BaseViewTool selectedTool) {
506
                this.selectedTool = selectedTool;
507
        }
508
        
509
        /**
510
         * Obtiene la herramienta seleccionada
511
         * @return BaseViewTool
512
         */
513
        public BaseViewTool getSelectedTool() {
514
                return selectedTool;
515
        }
516

    
517
        /**
518
         * Activa o desactiva el mostrado de informaci?n
519
         * @param showInfo
520
         */
521
        public void setShowInfo(boolean showInfo) {
522
                this.showInfo = showInfo;
523
        }
524
        
525
        /**
526
         * Asigna el valor para el flag minxMaxyUL. Este flag informa de que la esquina 
527
         * superior izquierda corresponde con el valor de m?nimo X y m?ximo Y. En caso 
528
         * de ser false esta esquina ser?a de m?nimo X y m?nimo Y.
529
         * @param v
530
         */
531
        public void setMinxMaxyUL(boolean v) {
532
                this.minxMaxyUL = v;
533
        }
534
        
535
        /**
536
         * Obtiene el valor para el flag minxMaxyUL. Este flag informa de que la esquina 
537
         * superior izquierda corresponde con el valor de m?nimo X y m?ximo Y. En caso 
538
         * de ser false esta esquina ser?a de m?nimo X y m?nimo Y.
539
         * @param v
540
         */
541
        public boolean getMinxMaxyUL() {
542
                return minxMaxyUL;
543
        }
544

    
545
        /**
546
         * Asigna el color del texto
547
         * @param textColor
548
         */
549
        public void setTextColor(Color textColor) {
550
                this.textColor = textColor;
551
                repaint();
552
        }
553

    
554
        /**
555
         * Obtiene el color del texto
556
         * @return
557
         */
558
        public Color getTextColor() {
559
                return textColor;
560
        }
561

    
562
        /**
563
         * Obtiene el color de fondo
564
         * @return
565
         */
566
        public Color getBackgroundColor() {
567
                return backgroundColor;
568
        }
569

    
570
        /**
571
         * Asigna el color de fondo
572
         * @param backgroundColor
573
         */
574
        public void setBackgroundColor(Color backgroundColor) {
575
                this.backgroundColor = backgroundColor;
576
        }
577

    
578
        /**
579
         * Normalmente no se hace una petici?n al dibujado del raster si el extent no ha variado. Si esta variable
580
     * est? a true fuerza que haya una petici?n de redibujado aunque el extent del raster no haya cambiado.
581
     * Esto solo se hace para una petici?n. La siguiente vuelve a estar a false.
582
         * @return
583
         */
584
        public boolean isForceRequest() {
585
                return forceRequest;
586
        }
587

    
588
        /**
589
         * Normalmente no se hace una petici?n al dibujado del raster si el extent no ha variado. Si esta variable
590
     * est? a true fuerza que haya una petici?n de redibujado aunque el extent del raster no haya cambiado.
591
     * Esto solo se hace para una petici?n. La siguiente vuelve a estar a false.
592
         * @param forceRequest
593
         */
594
        public void setForceRequest(boolean forceRequest) {
595
                this.forceRequest = forceRequest;
596
        }
597
}