Statistics
| Revision:

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

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

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

    
366
                        //Creamos el buffer y lo cargamos teniendo en cuenta el desplazamiento inicial
367
                        double step = 1 / scale;
368

    
369
                        double xValue = pxX;
370
                        double yValue = pxY;
371

    
372
                        for (int i = 0; i < w; i++) {
373
                                yValue = pxY;
374
                                for (int j = 0; j < h; j++) {
375
                                        if((int)xValue >= 0 && (int)yValue >= 0 && (int)xValue < image.getWidth() && (int)yValue < image.getHeight()) {
376
                                                lastImage.setRGB(i, j, image.getRGB((int)xValue, (int)yValue));
377
                                                lastImageWithLayers.setRGB(i, j, image.getRGB((int)xValue, (int)yValue));
378
                                        } else {
379
                                                lastImage.setRGB(i, j, 0xffffffff);
380
                                                lastImageWithLayers.setRGB(i, j, 0xffffffff);
381
                                        }
382
                                        yValue += step;
383
                                }
384
                                xValue += step;
385
                        }
386
                } else 
387
                        ((Graphics2D)lastImageWithLayers.getGraphics()).drawImage(lastImage, 0, 0, null);
388
                
389
                return lastImageWithLayers.getGraphics();
390
        }
391

    
392
        /*
393
         * (non-Javadoc)
394
         * @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent)
395
         */
396
        public void mouseClicked(MouseEvent e) {
397
                for (int i = 0; i < graphicLayers.size(); i++) 
398
                        ((IGraphicLayer)graphicLayers.get(i)).mouseClicked(e);
399
                repaint();
400
        }
401

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

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

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

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

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

    
452
        /*
453
         * (non-Javadoc)
454
         * @see java.awt.event.MouseMotionListener#mouseMoved(java.awt.event.MouseEvent)
455
         */
456
        public void mouseMoved(MouseEvent e) {
457
                realCoord = viewCoordsToWorld((Point2D)e.getPoint());
458
                viewCoord = e.getPoint();
459
                for (int i = 0; i < graphicLayers.size(); i++) 
460
                        ((IGraphicLayer)graphicLayers.get(i)).mouseMoved(e);
461
                repaint();
462
        }
463

    
464
        /**
465
         * Asigna la tool seleccionada
466
         * @param selectedTool
467
         */
468
        public void setSelectedTool(BaseViewTool selectedTool) {
469
                this.selectedTool = selectedTool;
470
        }
471
        
472
        /**
473
         * Obtiene la herramienta seleccionada
474
         * @return BaseViewTool
475
         */
476
        public BaseViewTool getSelectedTool() {
477
                return selectedTool;
478
        }
479

    
480
        /**
481
         * Activa o desactiva el mostrado de informaci?n
482
         * @param showInfo
483
         */
484
        public void setShowInfo(boolean showInfo) {
485
                this.showInfo = showInfo;
486
        }
487
}