Statistics
| Revision:

svn-gvsig-desktop / trunk / extensions / extRasterTools-SE / src / org / gvsig / rastertools / georeferencing / ui / zoom / CanvasZone.java @ 18326

History | View | Annotate | Download (15.8 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.rastertools.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.raster.util.MathUtils;
35
import org.gvsig.rastertools.georeferencing.ui.zoom.tools.BaseViewTool;
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 Color                  background = Color.WHITE;
64
    private BaseViewTool           selectedTool = null;
65
    
66
    private Point2D                realCoord = new Point2D.Double(0, 0);
67
    private Point2D                viewCoord = new Point2D.Double(0, 0);
68
    private boolean                showInfo = false;
69
    /**
70
     * Informa de que la esquina superior izquierda corresponde con el valor de m?nimo X y
71
     * m?ximo Y. En caso de ser false esta esquina ser?a de m?nimo X y m?nimo Y.
72
     */
73
    private boolean                minxMaxyUL = true;
74
                    
75
    /**
76
         * Asigna los par?metros de dibujado
77
         * @param img Buffer con un ?rea de datos
78
         * @param ext Rectangle2D del ?rea de datos dada 
79
         * @param pixelSize Tama?o de pixel
80
         * @param center Punto del ?rea de datos donde se quiere centrar el dibujado del buffer
81
         */
82
        public void setDrawParams(BufferedImage img, Rectangle2D ext, double pixelSize, Point2D center) {
83
                this.image = img;
84
                this.extent = ext;
85
                this.pixelSize = pixelSize;
86
                this.center = center;
87
                this.addMouseListener(this);
88
                this.addMouseMotionListener(this);
89
                repaint();
90
        }
91
        
92
        /**
93
         * Asigna un nuevo centro de visualizaci?n
94
         * @param center
95
         */
96
        public void setCenter(Point2D center) {
97
                this.center = center;
98
                repaint();
99
        }
100
        
101
        /**
102
         * Conversi?n de un punto en coordenadas del canvas a reales
103
         * @param p
104
         * @return
105
         */
106
        public Point2D viewCoordsToWorld(Point2D p) {
107
                int w = getVisibleRect().width;
108
                int h = getVisibleRect().height;
109
                double cx = extent.getMinX() + ((p.getX() * extent.getWidth()) / w);
110
                double cy = 0;
111
                if(minxMaxyUL) //Cuando las Y decrecen de arriba a abajo
112
                        cy = extent.getMaxY() - (p.getY() * extent.getHeight()) / h;
113
                else //Cuando las Y crecen de arriba a abajo
114
                        cy = extent.getMinY() + (p.getY() * extent.getHeight()) / h;
115
                return new Point2D.Double(cx, cy);
116
        }
117
        
118
        /**
119
         * Conversi?n de un punto en coordenadas del canvas a reales
120
         * @param p
121
         * @return
122
         */
123
        public Point2D viewCoordsFromWorld(Point2D p) {
124
                int w = getVisibleRect().width;
125
                int h = getVisibleRect().height;
126
                double cx = ((p.getX() - extent.getMinX()) * w) / extent.getWidth();
127
                double cy = 0;
128
                if(minxMaxyUL) //Cuando las Y decrecen de arriba a abajo
129
                        cy = ((extent.getMaxY() - p.getY()) * h) / extent.getHeight();
130
                else //Cuando las Y crecen de arriba a abajo
131
                        cy = ((p.getY() - extent.getMinY()) * h) / extent.getHeight();
132
                return new Point2D.Double(cx, cy);
133
        }
134
        
135
        /**
136
         * Obtiene el extent del canvas en coordenadas del mundo real
137
         * @return Rectangle2D
138
         */
139
        public Rectangle2D getExtent() {
140
                if(lastExtent == null)
141
                        return extent;
142
                return lastExtent;
143
        }
144
        
145
        /**
146
         * Asigna un nuevo centro de visualizaci?n en coordenadas del
147
         * componente.
148
         * @param center
149
         */
150
        public void setViewCenter(Point2D c) {
151
                int w = getVisibleRect().width;
152
                int h = getVisibleRect().height;
153
                
154
                double cx = (c.getX() * lastExtent.getWidth()) / w;
155
                double cy = (c.getY() * lastExtent.getHeight()) / h;
156
                setPixelCenter(new Point2D.Double(cx, cy));
157
        }
158
        
159
        /**
160
         * Asigna un nuevo centro de visualizaci?n en coordenadas pixel
161
         * del ?rea de dibujado (canvas). El nuevo centro ser? calculado en coordenadas
162
         * del mapa.
163
         * @param center
164
         */
165
        public void setPixelCenter(Point2D c) {
166
                int w = getVisibleRect().width;
167
                int h = getVisibleRect().height;
168
                
169
                //Calculamos el extent del canvas 
170
                Rectangle2D ext = getCanvasExtent(w, h, scale);
171
                
172
                //Calculamos el nuevo centro en coordenadas reales
173
                double wWC = (c.getX() / scale) * pixelSize;
174
                double hWC = (c.getY() / scale) * pixelSize;
175
                this.center = new Point2D.Double(ext.getMinX() + wWC,
176
                                                                                 ext.getMinY() - hWC);
177
                repaint();
178
        }
179
        
180
        /**
181
         * Asigna un nuevo centro de visualizaci?n en coordenadas pixel. Esta llamada tiene
182
         * en cuenta solo p?xeles completos. No centra sobre porciones de pixel cuando el zoom es
183
         * mayor de 1:1. El nuevo centro es en coordenadas del mapa pero siempre centrar?
184
         * en la esquina inferior izquierda del pixel.
185
         * @param center
186
         */
187
        public void setPixelCenter(int x, int y) {
188
                int w = getVisibleRect().width;
189
                int h = getVisibleRect().height;
190
                
191
                //Calculamos el extent del canvas 
192
                Rectangle2D ext = getCanvasExtent(w, h, scale);
193
                
194
                //Calculamos el nuevo centro en coordenadas reales
195
                double wWC = (x / scale) * pixelSize;
196
                double hWC = (y / scale) * pixelSize;
197
                Point2D center = new Point2D.Double(ext.getMinX() + wWC,
198
                                                                                          ext.getMinY() - hWC);
199
                
200
                //Calculamos la coordena pixel a la que pertenece esa coordenada real
201
                int pxX = (int)((center.getX() * (w / scale)) / ext.getWidth());
202
                int pxY = (int)((center.getY() * (h / scale)) / ext.getHeight());
203
                
204
                //Despu?s de haber convertido a pixel y redondeado la coordenada a entero volvemos a convertirla en real
205
                double wcX = (pxX * ext.getWidth()) / (w / scale);
206
                double wcY = (pxY * ext.getHeight()) / (h / scale);
207

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

    
375
                        //Creamos el buffer y lo cargamos teniendo en cuenta el desplazamiento inicial
376
                        double step = 1 / scale;
377

    
378
                        double xValue = pxX;
379
                        double yValue = pxY;
380

    
381
                        for (int i = 0; i < w; i++) {
382
                                yValue = pxY;
383
                                for (int j = 0; j < h; j++) {
384
                                        if((int)xValue >= 0 && (int)yValue >= 0 && (int)xValue < image.getWidth() && (int)yValue < image.getHeight()) {
385
                                                lastImage.setRGB(i, j, image.getRGB((int)xValue, (int)yValue));
386
                                                lastImageWithLayers.setRGB(i, j, image.getRGB((int)xValue, (int)yValue));
387
                                        } else {
388
                                                lastImage.setRGB(i, j, 0xffffffff);
389
                                                lastImageWithLayers.setRGB(i, j, 0xffffffff);
390
                                        }
391
                                        yValue += step;
392
                                }
393
                                xValue += step;
394
                        }
395
                } else 
396
                        ((Graphics2D)lastImageWithLayers.getGraphics()).drawImage(lastImage, 0, 0, null);
397
                
398
                return lastImageWithLayers.getGraphics();
399
        }
400

    
401
        /*
402
         * (non-Javadoc)
403
         * @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent)
404
         */
405
        public void mouseClicked(MouseEvent e) {
406
                for (int i = 0; i < graphicLayers.size(); i++) 
407
                        ((IGraphicLayer)graphicLayers.get(i)).mouseClicked(e);
408
                repaint();
409
        }
410

    
411
        /*
412
         * (non-Javadoc)
413
         * @see java.awt.event.MouseListener#mouseEntered(java.awt.event.MouseEvent)
414
         */
415
        public void mouseEntered(MouseEvent e) {
416
                for (int i = 0; i < graphicLayers.size(); i++) 
417
                        ((IGraphicLayer)graphicLayers.get(i)).mouseEntered(e);
418
                repaint();
419
        }
420

    
421
        /*
422
         * (non-Javadoc)
423
         * @see java.awt.event.MouseListener#mouseExited(java.awt.event.MouseEvent)
424
         */
425
        public void mouseExited(MouseEvent e) {
426
                for (int i = 0; i < graphicLayers.size(); i++) 
427
                        ((IGraphicLayer)graphicLayers.get(i)).mouseExited(e);
428
                repaint();
429
        }
430

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

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

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

    
461
        /*
462
         * (non-Javadoc)
463
         * @see java.awt.event.MouseMotionListener#mouseMoved(java.awt.event.MouseEvent)
464
         */
465
        public void mouseMoved(MouseEvent e) {
466
                realCoord = viewCoordsToWorld((Point2D)e.getPoint());
467
                viewCoord = e.getPoint();
468
                for (int i = 0; i < graphicLayers.size(); i++) 
469
                        ((IGraphicLayer)graphicLayers.get(i)).mouseMoved(e);
470
                repaint();
471
        }
472

    
473
        /**
474
         * Asigna la tool seleccionada
475
         * @param selectedTool
476
         */
477
        public void setSelectedTool(BaseViewTool selectedTool) {
478
                this.selectedTool = selectedTool;
479
        }
480
        
481
        /**
482
         * Obtiene la herramienta seleccionada
483
         * @return BaseViewTool
484
         */
485
        public BaseViewTool getSelectedTool() {
486
                return selectedTool;
487
        }
488

    
489
        /**
490
         * Activa o desactiva el mostrado de informaci?n
491
         * @param showInfo
492
         */
493
        public void setShowInfo(boolean showInfo) {
494
                this.showInfo = showInfo;
495
        }
496
        
497
        /**
498
         * Asigna el valor para el flag minxMaxyUL. Este flag informa de que la esquina 
499
         * superior izquierda corresponde con el valor de m?nimo X y m?ximo Y. En caso 
500
         * de ser false esta esquina ser?a de m?nimo X y m?nimo Y.
501
         * @param v
502
         */
503
        public void setMinxMaxyUL(boolean v) {
504
                this.minxMaxyUL = v;
505
        }
506
        
507
        /**
508
         * Obtiene el valor para el flag minxMaxyUL. Este flag informa de que la esquina 
509
         * superior izquierda corresponde con el valor de m?nimo X y m?ximo Y. En caso 
510
         * de ser false esta esquina ser?a de m?nimo X y m?nimo Y.
511
         * @param v
512
         */
513
        public boolean getMinxMaxyUL() {
514
                return minxMaxyUL;
515
        }
516
}