Statistics
| Revision:

gvsig-raster / org.gvsig.raster.georeferencing / trunk / org.gvsig.raster.georeferencing / org.gvsig.raster.georeferencing.swing / org.gvsig.raster.georeferencing.swing.impl / src / main / java / org / gvsig / raster / georeferencing / swing / impl / view / CanvasZone.java @ 1725

History | View | Annotate | Download (18.8 KB)

1
/* gvSIG. Geographic Information System of the Valencian Government
2
 *
3
 * Copyright (C) 2007-2008 Infrastructures and Transports Department
4
 * of the Valencian Government (CIT)
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 2
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 */
22
package org.gvsig.raster.georeferencing.swing.impl.view;
23

    
24
import java.awt.Color;
25
import java.awt.Graphics;
26
import java.awt.Graphics2D;
27
import java.awt.event.MouseEvent;
28
import java.awt.event.MouseListener;
29
import java.awt.event.MouseMotionListener;
30
import java.awt.geom.Point2D;
31
import java.awt.geom.Rectangle2D;
32
import java.awt.image.BufferedImage;
33
import java.util.ArrayList;
34
import java.util.List;
35

    
36
import javax.swing.JPanel;
37

    
38
import org.gvsig.raster.georeferencing.swing.impl.tool.BaseViewTool;
39
import org.gvsig.raster.georeferencing.swing.view.GeorefCanvas;
40
import org.gvsig.raster.georeferencing.swing.view.IGraphicLayer;
41
import org.gvsig.raster.georeferencing.swing.view.ViewEvent;
42
import org.gvsig.raster.georeferencing.swing.view.ViewListener;
43

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

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

    
423
                        //Creamos el buffer y lo cargamos teniendo en cuenta el desplazamiento inicial
424
                        double step = 1 / scale;
425

    
426
                        double xValue = pxX;
427
                        double yValue = pxY;
428

    
429
                        for (int i = 0; i < w; i++) {
430
                                yValue = pxY;
431
                                for (int j = 0; j < h; j++) {
432
                                        if((int)xValue >= 0 && (int)yValue >= 0 && (int)xValue < image.getWidth() && (int)yValue < image.getHeight()) {
433
                                                lastImage.setRGB(i, j, image.getRGB((int)xValue, (int)yValue));
434
                                                lastImageWithLayers.setRGB(i, j, image.getRGB((int)xValue, (int)yValue));
435
                                        } else {
436
                                                lastImage.setRGB(i, j, 0xffffffff);
437
                                                lastImageWithLayers.setRGB(i, j, 0xffffffff);
438
                                        }
439
                                        yValue += step;
440
                                }
441
                                xValue += step;
442
                        }
443
                        if(viewListener != null)
444
                                viewListener.zoomViewChanged(viewEvent);
445
                        forceRequest = false;
446
                } else 
447
                        ((Graphics2D)lastImageWithLayers.getGraphics()).drawImage(lastImage, 0, 0, null);
448
                
449
                return lastImageWithLayers.getGraphics();
450
        }
451

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

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

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

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

    
492
        /*
493
         * (non-Javadoc)
494
         * @see java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent)
495
         */
496
        public void mouseReleased(MouseEvent e) {
497
                for (int i = 0; i < graphicLayers.size(); i++) 
498
                        ((IGraphicLayer)graphicLayers.get(i)).mouseReleased(e);
499
                repaint();
500
        }
501

    
502
        /*
503
         * (non-Javadoc)
504
         * @see java.awt.event.MouseMotionListener#mouseDragged(java.awt.event.MouseEvent)
505
         */
506
        public void mouseDragged(MouseEvent e) {
507
                for (int i = 0; i < graphicLayers.size(); i++) 
508
                        ((IGraphicLayer)graphicLayers.get(i)).mouseDragged(e);
509
                repaint();
510
        }
511

    
512
        /*
513
         * (non-Javadoc)
514
         * @see java.awt.event.MouseMotionListener#mouseMoved(java.awt.event.MouseEvent)
515
         */
516
        public void mouseMoved(MouseEvent e) {
517
                realCoord = viewCoordsToWorld((Point2D)e.getPoint());
518
                //viewCoord = e.getPoint();
519
                for (int i = 0; i < graphicLayers.size(); i++) 
520
                        ((IGraphicLayer)graphicLayers.get(i)).mouseMoved(e);
521
                repaint();
522
        }
523

    
524
        /**
525
         * Asigna la tool seleccionada
526
         * @param selectedTool
527
         */
528
        public void setSelectedTool(BaseViewTool selectedTool) {
529
                this.selectedTool = selectedTool;
530
        }
531
        
532
        /**
533
         * Obtiene la herramienta seleccionada
534
         * @return BaseViewTool
535
         */
536
        public BaseViewTool getSelectedTool() {
537
                return selectedTool;
538
        }
539

    
540
        /**
541
         * Activa o desactiva el mostrado de informaci?n
542
         * @param showInfo
543
         */
544
        public void setShowInfo(boolean showInfo) {
545
                this.showInfo = showInfo;
546
        }
547
        
548
        /**
549
         * Asigna el valor para el flag minxMaxyUL. Este flag informa de que la esquina 
550
         * superior izquierda corresponde con el valor de m?nimo X y m?ximo Y. En caso 
551
         * de ser false esta esquina ser?a de m?nimo X y m?nimo Y.
552
         * @param v
553
         */
554
        public void setMinxMaxyUL(boolean v) {
555
                this.minxMaxyUL = v;
556
        }
557
        
558
        /**
559
         * Obtiene el valor para el flag minxMaxyUL. Este flag informa de que la esquina 
560
         * superior izquierda corresponde con el valor de m?nimo X y m?ximo Y. En caso 
561
         * de ser false esta esquina ser?a de m?nimo X y m?nimo Y.
562
         * @param v
563
         */
564
        public boolean getMinxMaxyUL() {
565
                return minxMaxyUL;
566
        }
567

    
568
        /**
569
         * Asigna el color del texto
570
         * @param textColor
571
         */
572
        public void setTextColor(Color textColor) {
573
                this.textColor = textColor;
574
                repaint();
575
        }
576

    
577
        /**
578
         * Obtiene el color del texto
579
         * @return
580
         */
581
        public Color getTextColor() {
582
                return textColor;
583
        }
584

    
585
        /**
586
         * Obtiene el color de fondo
587
         * @return
588
         */
589
        public Color getBackgroundColor() {
590
                return backgroundColor;
591
        }
592

    
593
        /**
594
         * Asigna el color de fondo
595
         * @param backgroundColor
596
         */
597
        public void setBackgroundColor(Color backgroundColor) {
598
                this.backgroundColor = backgroundColor;
599
        }
600

    
601
        /**
602
         * Normalmente no se hace una petici?n al dibujado del raster si el extent no ha variado. Si esta variable
603
     * est? a true fuerza que haya una petici?n de redibujado aunque el extent del raster no haya cambiado.
604
     * Esto solo se hace para una petici?n. La siguiente vuelve a estar a false.
605
         * @return
606
         */
607
        public boolean isForceRequest() {
608
                return forceRequest;
609
        }
610

    
611
        /**
612
         * Normalmente no se hace una petici?n al dibujado del raster si el extent no ha variado. Si esta variable
613
     * est? a true fuerza que haya una petici?n de redibujado aunque el extent del raster no haya cambiado.
614
     * Esto solo se hace para una petici?n. La siguiente vuelve a estar a false.
615
         * @param forceRequest
616
         */
617
        public void setForceRequest(boolean forceRequest) {
618
                this.forceRequest = forceRequest;
619
        }
620
}