Statistics
| Revision:

gvsig-raster / org.gvsig.raster / trunk / org.gvsig.raster / org.gvsig.raster.lib / org.gvsig.raster.lib.impl / src / main / java / org / gvsig / raster / impl / grid / render / DefaultRender.java @ 723

History | View | Annotate | Download (33.2 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.impl.grid.render;
23

    
24
import java.awt.Graphics2D;
25
import java.awt.Image;
26
import java.awt.geom.AffineTransform;
27
import java.awt.geom.Dimension2D;
28
import java.awt.geom.NoninvertibleTransformException;
29
import java.awt.geom.Point2D;
30
import java.util.ArrayList;
31

    
32
import org.gvsig.fmap.dal.coverage.RasterLocator;
33
import org.gvsig.fmap.dal.coverage.dataset.Buffer;
34
import org.gvsig.fmap.dal.coverage.datastruct.Extent;
35
import org.gvsig.fmap.dal.coverage.datastruct.Params;
36
import org.gvsig.fmap.dal.coverage.datastruct.ViewPortData;
37
import org.gvsig.fmap.dal.coverage.exception.FilterManagerException;
38
import org.gvsig.fmap.dal.coverage.exception.FilterTypeException;
39
import org.gvsig.fmap.dal.coverage.exception.InvalidSetViewException;
40
import org.gvsig.fmap.dal.coverage.exception.ProcessInterruptedException;
41
import org.gvsig.fmap.dal.coverage.exception.RasterDriverException;
42
import org.gvsig.fmap.dal.coverage.grid.FilterListChangeEvent;
43
import org.gvsig.fmap.dal.coverage.grid.FilterListChangeListener;
44
import org.gvsig.fmap.dal.coverage.grid.Grid;
45
import org.gvsig.fmap.dal.coverage.grid.GridTransparency;
46
import org.gvsig.fmap.dal.coverage.grid.RasterFilter;
47
import org.gvsig.fmap.dal.coverage.grid.RasterFilterList;
48
import org.gvsig.fmap.dal.coverage.grid.RasterFilterListManager;
49
import org.gvsig.fmap.dal.coverage.grid.render.Render;
50
import org.gvsig.fmap.dal.coverage.grid.render.VisualPropertyEvent;
51
import org.gvsig.fmap.dal.coverage.grid.render.VisualPropertyListener;
52
import org.gvsig.fmap.dal.coverage.store.RasterDataStore;
53
import org.gvsig.fmap.dal.coverage.store.RasterQuery;
54
import org.gvsig.fmap.dal.coverage.store.props.ColorInterpretation;
55
import org.gvsig.fmap.dal.coverage.store.props.ColorTable;
56
import org.gvsig.fmap.dal.coverage.store.props.Transparency;
57
import org.gvsig.fmap.dal.coverage.util.PropertyEvent;
58
import org.gvsig.fmap.dal.coverage.util.PropertyListener;
59
import org.gvsig.fmap.dal.coverage.util.RasterUtils;
60
import org.gvsig.raster.cache.tile.Tile;
61
import org.gvsig.raster.cache.tile.exception.TileGettingException;
62
import org.gvsig.raster.cache.tile.provider.TileListener;
63
import org.gvsig.raster.impl.DefaultRasterManager;
64
import org.gvsig.raster.impl.datastruct.DefaultViewPortData;
65
import org.gvsig.raster.impl.datastruct.ExtentImpl;
66
import org.gvsig.raster.impl.grid.GridImpl;
67
import org.gvsig.raster.impl.grid.GridTransparencyImpl;
68
import org.gvsig.raster.impl.grid.filter.DefaultRasterFilterList;
69
import org.gvsig.raster.impl.grid.filter.band.ColorTableFilter;
70
import org.gvsig.raster.impl.store.properties.DataStoreColorInterpretation;
71
import org.gvsig.tools.ToolsLocator;
72
import org.gvsig.tools.dynobject.DynStruct;
73
import org.gvsig.tools.persistence.PersistenceManager;
74
import org.gvsig.tools.persistence.Persistent;
75
import org.gvsig.tools.persistence.PersistentState;
76
import org.gvsig.tools.persistence.exception.PersistenceException;
77
import org.slf4j.LoggerFactory;
78
/**
79
 * Esta clase se encarga de la gesti?n del dibujado de datos le?dos desde la capa
80
 * "dataaccess" sobre objetos java. Para ello necesita una fuente de datos que tipicamente
81
 * es un buffer (RasterBuffer) y un objeto que realice la funci?n de escritura de datos a
82
 * partir de un estado inicial.
83
 * Esta capa del renderizado gestiona Extents, rotaciones, tama?os de vista pero la escritura
84
 * de datos desde el buffer al objeto image es llevada a cabo por ImageDrawer.
85
 *
86
 * Par?metros de control de la visualizaci?n:
87
 * <UL>
88
 * <LI>renderBands: Orden de visualizado de las bands.</LI>
89
 * <LI>replicateBands: Para visualizaci?n de raster de una banda. Dice si se replica sobre las otras dos bandas
90
 * de visualizaci?n o se ponen a 0.</LI>
91
 * <LI>enhanced: aplicaci?n de filtro de realce</LI>
92
 * <LI>removeEnds: Eliminar extremos en el filtro de realce. Uso del segundo m?ximo y m?nimo</LI>
93
 * <LI>tailTrim: Aplicacion de recorte de colas en el realce. Es un valor decimal que representa el porcentaje del recorte entre 100.
94
 * Es decir, 0.1 significa que el recorte es de un 10%</LI>
95
 * </UL>
96
 *
97
 * @author Nacho Brodin (nachobrodin@gmail.com)
98
 */
99
public class DefaultRender implements Render, PropertyListener, FilterListChangeListener, Persistent, TileListener {
100

    
101
        /**
102
         * Grid para la gesti?n del buffer
103
         */
104
        private Grid             grid                     = null;
105
        /**
106
         * Fuente de datos para el renderizado
107
         */
108
        private RasterDataStore dataStore                 = null;
109
        /**
110
         * N?mero de bandas a renderizar y en el orden que se har?. Esto es asignado
111
         * por el usuario de la renderizaci?n.
112
         */
113
        private int[]            renderBands              = { 0, 1, 2 };
114

    
115
        private ImageDrawer      drawer                   = null;
116
        /**
117
         * Ultima transparencia aplicada en la visualizaci?n que es obtenida desde el
118
         * grid
119
         */
120
        private Transparency     lastTransparency         = null;
121
        private int              lastAlphaBand            = -1;
122
        
123
        /**
124
         * Lista de filtros aplicada en la renderizaci?n
125
         */
126
        private RasterFilterList filterList               = null;
127

    
128
        private Buffer           lastRenderBuffer         = null;
129

    
130
        /**
131
         * Ancho y alto del objeto Image en una petici?n de dibujado a un raster
132
         * raster
133
         */
134
        private double           widthImage, heightImage;
135

    
136
        private Point2D          ulPxRequest, lrPxRequest;
137

    
138
        /**
139
         * Array de listeners que ser?n informados cuando cambia una propiedad en la visualizaci?n
140
         */
141
        private ArrayList<VisualPropertyListener>        
142
                                 visualPropertyListener   = new ArrayList<VisualPropertyListener>();
143
        private RasterUtils      util                     = RasterLocator.getManager().getRasterUtils();
144
        private boolean          isDrawing                = false;
145
        
146
        private Graphics2D       lastGraphics             = null;
147
        private ViewPortData     lastViewPortData         = null;
148
        private Dimension2D      viewDimension            = null;
149
        
150
        /**
151
         * Constructor
152
         * @param grid
153
         */
154
        public DefaultRender(Grid grid) {
155
                this.grid = grid;
156
                init();
157
        }
158

    
159
        /**
160
         * Constructor
161
         * @param grid
162
         */
163
        public DefaultRender(RasterDataStore ds) {
164
                this.dataStore = ds;
165
                init();
166
        }
167
        
168
        /*
169
         * (non-Javadoc)
170
         * @see org.gvsig.fmap.dal.coverage.grid.render.Render#getDataStore()
171
         */
172
        public RasterDataStore getDataStore() {
173
                return this.dataStore;
174
        }
175
        
176
        /*
177
         * (non-Javadoc)
178
         * @see org.gvsig.fmap.dal.coverage.grid.render.Render#setDataStore(org.gvsig.fmap.dal.coverage.store.RasterDataStore)
179
         */
180
        public void setDataStore(RasterDataStore dataStore) {
181
                this.dataStore = dataStore;
182
                init();
183
        }
184

    
185
        private void init() {
186
                if(dataStore.getDataType() == null)
187
                        return;
188
                
189
                drawer = new ImageDrawer(this);
190

    
191
                if (dataStore == null) {
192
                        setRenderBands(new int[] { 0, 1, 2 });
193
                        return;
194
                }
195

    
196
                //Bandas que se dibujan por defecto si la interpretaci?n de color no tiene valores
197
                switch (dataStore.getBandCount()) {
198
                        case 1:
199
                                setRenderBands(new int[] { 0, 0, 0 });
200
                                break;
201
                        case 2:
202
                                setRenderBands(new int[] { 0, 1, 1 });
203
                                break;
204
                        default:
205
                                setRenderBands(new int[] { 0, 1, 2 });
206
                                break;
207
                }
208

    
209
                //---------------------------------------------------
210
                //INICIALIZACI?N DE LA INTERPRETACI?N DE COLOR
211

    
212
                //Inicializaci?n de la asignaci?n de bandas en el renderizado
213
                //Leemos el objeto metadata para obtener la interpretaci?n de color asociada al raster
214

    
215
                ColorInterpretation colorInterpr = dataStore.getColorInterpretation();
216
                if (colorInterpr != null)
217
                        if (colorInterpr.getBand(DataStoreColorInterpretation.PAL_BAND) == -1) {
218
                                if (colorInterpr.isUndefined())
219
                                        return;
220
                                int[] result = new int[] { -1, -1, -1 };
221
                                int gray = colorInterpr.getBand(DataStoreColorInterpretation.GRAY_BAND);
222
                                if (gray != -1)
223
                                        result[0] = result[1] = result[2] = gray;
224
                                else {
225
                                        int r = colorInterpr.getBand(DataStoreColorInterpretation.RED_BAND);
226
                                        if (r != -1)
227
                                                result[0] = r;
228
                                        int g = colorInterpr.getBand(DataStoreColorInterpretation.GREEN_BAND);
229
                                        if (g != -1)
230
                                                result[1] = g;
231
                                        int b = colorInterpr.getBand(DataStoreColorInterpretation.BLUE_BAND);
232
                                        if (b != -1)
233
                                                result[2] = b;
234
                                }
235
                                setRenderBands(result);
236
                        }
237
        }
238

    
239
        /**
240
         * Asigna un listener a la lista que ser? informado cuando cambie una
241
         * propiedad visual en la renderizaci?n.
242
         * @param listener VisualPropertyListener
243
         */
244
        public void addVisualPropertyListener(VisualPropertyListener listener) {
245
                visualPropertyListener.add(listener);
246
        }
247

    
248
        /**
249
         * M?todo llamado cuando hay un cambio en una propiedad de visualizaci?n
250
         */
251
        private void callVisualPropertyChanged(Object obj) {
252
                for (int i = 0; i < visualPropertyListener.size(); i++) {
253
                        VisualPropertyEvent ev = new VisualPropertyEvent(obj);
254
                        ((VisualPropertyListener)visualPropertyListener.get(i)).visualPropertyValueChanged(ev);
255
                }
256
        }
257
        
258
        /**
259
         * Thread de dibujado
260
         */
261
        public void run() {
262
                try {
263
                        draw(lastGraphics, lastViewPortData);
264
                } catch (RasterDriverException e) {
265
                        LoggerFactory.getLogger(getClass()).debug("Error reading data", e);
266
                } catch (InvalidSetViewException e) {
267
                        LoggerFactory.getLogger(getClass()).debug("Invalid view", e);
268
                } catch (ProcessInterruptedException e) {
269
                }
270
        }
271
        
272
        /*
273
         * (non-Javadoc)
274
         * @see org.gvsig.fmap.dal.coverage.grid.render.Render#setGraphicInfo(java.awt.Graphics2D, org.gvsig.fmap.dal.coverage.datastruct.ViewPortData)
275
         */
276
        public void setGraphicInfo(Graphics2D g, ViewPortData vp) {
277
                this.lastGraphics = g;
278
                this.lastViewPortData = vp;
279
        }
280

    
281
        /*
282
         * (non-Javadoc)
283
         * @see org.gvsig.fmap.dal.coverage.grid.render.Render#drawThread(java.awt.Graphics2D, org.gvsig.fmap.dal.coverage.datastruct.ViewPortData)
284
         */
285
        public void drawThread(Graphics2D g, ViewPortData vp) {
286
                //Se dibuja si cae dentro de la vista
287
                if(util.isOutside(vp.getExtent(), dataStore.getExtent())) 
288
                        return;
289
                
290
                setReading(true);
291
                setGraphicInfo(g, vp);
292
                new Thread(this).start();
293

    
294
                while(isReading()) {
295
                        try {
296
                                Thread.sleep(50);
297
                        } catch (InterruptedException e) {
298
                                break;
299
                        }
300
                }
301
        }
302
        
303
        /*
304
         * (non-Javadoc)
305
         * @see org.gvsig.fmap.dal.coverage.grid.render.Render#draw(java.awt.Graphics2D, org.cresques.geo.ViewPortData)
306
         */
307
        public synchronized void drawTiledService(Graphics2D g, ViewPortData vp, Dimension2D viewDimension)
308
                throws RasterDriverException, InvalidSetViewException, ProcessInterruptedException {
309
                lastGraphics = g;
310
                lastViewPortData = vp;
311
                this.     viewDimension             = viewDimension;
312

    
313
                if(util.isOutside(vp.getExtent(), dataStore.getExtent())) {
314
                        endReading();
315
                        return;
316
                }
317
                
318
                if (dataStore != null) {
319
                        if (lastTransparency == null) {
320
                                lastTransparency = new GridTransparencyImpl(dataStore.getTransparency());
321
                                lastTransparency.addPropertyListener(this);
322
                        }
323
                        lastTransparency.setTransparencyBand(dataStore.getTransparency().getAlphaBandNumber());
324
                        lastAlphaBand = lastTransparency.getAlphaBandNumber();
325
                        
326
                        // Asignamos la banda de transparencia si existe esta
327
                        RasterQuery query = DefaultRasterManager.getInstance().createQuery();
328
                        query.setTime(vp.getTime());
329
                        query.setSupersamplingLoadingBuffer(false); // Desactivamos el supersampleo en la carga del buffer.
330
                        query.setDrawableBands(getRenderBands());
331
                        query.setFrameWidth(0);
332
                        query.setAlphaBand(dataStore.getTransparency().getAlphaBandNumber());
333
                        query.setAreaOfInterest(vp.getExtent(), 
334
                                        (int)Math.round(vp.getWidth()), 
335
                                        (int)Math.round(vp.getHeight()), this);
336
                        dataStore.query(query);
337
                        query.setSupersamplingLoadingBuffer(true);
338
                } else
339
                        return;
340
        }
341
        
342
        /*
343
         * (non-Javadoc)
344
         * @see org.gvsig.fmap.dal.coverage.grid.render.Render#draw(java.awt.Graphics2D, org.cresques.geo.ViewPortData)
345
         */
346
        public synchronized void draw(Graphics2D g, ViewPortData vp)
347
                throws RasterDriverException, InvalidSetViewException, ProcessInterruptedException {
348
                lastGraphics = g;
349
                lastViewPortData = vp;
350

    
351
                if(util.isOutside(vp.getExtent(), dataStore.getExtent())) {
352
                        endReading();
353
                        return;
354
                }
355

    
356
                Extent adjustedRotedRequest = request(vp, dataStore);
357

    
358
                if ((widthImage <= 0) || (heightImage <= 0)) {
359
                        endReading();
360
                        return;
361
                }
362

    
363
                if (dataStore == null) 
364
                        return;
365
                
366
                //If the transparency hasn't been defined yet then we'll take that from the store
367
                if (lastTransparency == null) {
368
                        lastTransparency = dataStore.getTransparency().cloneTransparency();
369
                        lastTransparency.addPropertyListener(this);
370
                }
371
                // Asignamos la banda de transparencia si existe esta
372
                RasterQuery query = DefaultRasterManager.getInstance().createQuery();
373
                query.setTime(vp.getTime());
374
                query.setSupersamplingLoadingBuffer(false); // Desactivamos el supersampleo en la carga del buffer.
375
                query.setAreaOfInterest(adjustedRotedRequest, (int)Math.round(widthImage), (int)Math.round(heightImage));
376
                
377
                if (lastTransparency.getAlphaBandNumber() != -1) {
378
                        query.setDrawableBands(new int[] { lastTransparency.getAlphaBandNumber()});
379
                        lastTransparency.setAlphaBand(dataStore.query(query));
380
                }
381
                lastAlphaBand = lastTransparency.getAlphaBandNumber();
382
                
383
                //query.setAreaOfInterest(adjustedRotedRequest.getULX(), adjustedRotedRequest.getULY(), adjustedRotedRequest.getLRX(), adjustedRotedRequest.getLRY(), (int)Math.round(widthImage), (int)Math.round(heightImage), this, 0);
384
                query.setDrawableBands(getRenderBands());
385
                Buffer buf = dataStore.query(query);
386
                query.setSupersamplingLoadingBuffer(true);
387
                double[] step = dataStore.getStep();
388
                
389
                if(drawer == null) {
390
                        init();
391
                }
392
                
393
                drawBufferOnImage(lastGraphics, 
394
                                lastViewPortData, 
395
                                buf, 
396
                                step, 
397
                                dataStore.getAffineTransform(), 
398
                                adjustedRotedRequest);
399
        }
400
        
401
        /*
402
         * (non-Javadoc)
403
         * @see org.gvsig.fmap.dal.coverage.grid.render.Render#draw(java.awt.Graphics2D, org.cresques.geo.ViewPortData)
404
         */
405
        private synchronized void drawBufferOnImage(Graphics2D g, ViewPortData vp, Buffer buf, double[] step, AffineTransform transf, Extent adjustedRotedRequest)
406
                throws RasterDriverException, InvalidSetViewException, ProcessInterruptedException {
407
                
408
                lastTransparency = new GridTransparencyImpl(lastTransparency);
409
                grid = bufferPreprocessing(buf, (GridTransparency)lastTransparency);
410

    
411
                //Buffer filtrado para renderizar
412
                lastRenderBuffer = grid.getRasterBuf();
413
                drawer.setBuffer(lastRenderBuffer); // Buffer de datos a renderizar
414
                drawer.setStep(step); // Desplazamiento para supersampleo
415
                drawer.setBufferSize((int)Math.round(widthImage), (int)Math.round(heightImage)); // Ancho y alto del buffer
416
                Image geoImage = drawer.drawBufferOverImageObject(); // Acci?n de renderizado
417

    
418
                // Borramos el buffer de transparencia para que siempre se tenga que regenerar.
419
                lastTransparency.setAlphaBand(null);
420

    
421
                //En el caso de no tenga rotaci?n y el tama?o de pixel sea positivo en X y negativo en Y no aplicamos ninguna
422
                //transformaci?n. Esto no es necesario hacerlo, sin ello se visualiza igual. Unicamente se hace porque de esta
423
                //forma el raster resultante mejora un poco en calidad en ciertos niveles de zoom ya que al aplicar transformaciones
424
                //sobre el Graphics parece que pierde algo de calidad.
425
                if(transf.getScaleX() > 0 && transf.getScaleY() < 0 && transf.getShearX() == 0 && transf.getShearY() == 0) {
426
                        Point2D lastGraphicOffset = new Point2D.Double(adjustedRotedRequest.getULX(), adjustedRotedRequest.getULY());
427
                        ((DefaultViewPortData)vp).mat.transform(lastGraphicOffset, lastGraphicOffset);
428
                        g.drawImage(geoImage, (int) Math.round(lastGraphicOffset.getX()), (int) Math.round(lastGraphicOffset.getY()), null);
429
                        return;
430
                }
431

    
432
                /*
433
                 * Tenemos una matriz con la transformaci?n de la coordenadas de la vista a coordenadas reales vp.mat, adem?s tenemos
434
                 * la transformaci?n de coordenadas reales a coordenadas pixel (transf). Con ambas podemos obtener una matriz de trasformacion
435
                 * entre coordenadas de la vista a coordenadas pixel (transf X vp.mat). As? obtenemos la transformaci?n entre coordenadas
436
                 * de la vista y coordenadas pixel del raster. El problema es que a cada zoom la escala de la petici?n del raster varia
437
                 * por lo que habr? que calcular una matriz con la escala (escale). escale X transf X vp.mat
438
                 */
439
                double sX = Math.abs(ulPxRequest.getX() - lrPxRequest.getX()) / widthImage;
440
                double sY = Math.abs(ulPxRequest.getY() - lrPxRequest.getY()) / heightImage;
441
                AffineTransform scale = new AffineTransform(sX, 0, 0, sY, 0, 0);
442

    
443
                try {
444
                        AffineTransform at = (AffineTransform)scale.clone();
445
                        at.preConcatenate(transf);
446
                        at.preConcatenate(vp.getMat());
447
                        g.transform(at);
448
                        Point2D.Double pt = null;
449
                        //El punto sobre el que rota la imagen depende del signo de los tama?os del pixel
450
                        if(transf.getScaleX() < 0 && transf.getScaleY() < 0)
451
                                pt = new Point2D.Double(adjustedRotedRequest.maxX(), adjustedRotedRequest.maxY());
452
                        else if(transf.getScaleX() > 0 && transf.getScaleY() > 0)
453
                                pt = new Point2D.Double(adjustedRotedRequest.minX(), adjustedRotedRequest.minY());
454
                        else if(transf.getScaleX() < 0 && transf.getScaleY() > 0)
455
                                pt = new Point2D.Double(adjustedRotedRequest.maxX(), adjustedRotedRequest.minY());
456
                        else
457
                                pt = new Point2D.Double(adjustedRotedRequest.getULX(), adjustedRotedRequest.getULY());
458
                        vp.getMat().transform(pt, pt);
459
                        at.inverseTransform(pt, pt);
460
                        g.drawImage(geoImage, (int) Math.round(pt.getX()), (int) Math.round(pt.getY()), null);
461
                        g.transform(at.createInverse());
462
                } catch (NoninvertibleTransformException e) {
463
                        LoggerFactory.getLogger(getClass()).debug("Transformation error", e);
464
                }
465
                return;
466
                // long t2 = new Date().getTime();
467
                // System.out.println("Renderizando Raster: " + ((t2 - t1) / 1000D) + ", secs.");
468
        }
469
        
470
        /*
471
         * (non-Javadoc)
472
         * @see org.gvsig.raster.cache.tile.provider.TileListener#tileReady(org.gvsig.raster.cache.tile.Tile)
473
         */
474
        public void tileReady(Tile loadedTile) throws TileGettingException {
475
                //Getting parameters
476
                Boolean tiling = (Boolean)loadedTile.getDownloaderParams("Tiling");
477
                AffineTransform transf = (AffineTransform)loadedTile.getDownloaderParams("AffineTransform");
478
                Buffer buf = (loadedTile.getData() != null && loadedTile.getData().length > 0) ? (Buffer)loadedTile.getData()[0] : null;
479
                if(buf == null)
480
                        return;
481
                Buffer transparencyBuffer = (loadedTile.getData() != null && loadedTile.getData().length > 1) ? (Buffer)loadedTile.getData()[1] : null;
482
                ColorTable colorTable = (loadedTile.getData() != null && loadedTile.getData().length > 2) ? (ColorTable)loadedTile.getData()[2] : null;
483
                double[] step = (double[])loadedTile.getDownloaderParams("Step");
484
                Extent e = RasterLocator.getManager().getDataStructFactory().
485
                createExtent(loadedTile.getUl().getX(), 
486
                                        loadedTile.getUl().getY(), 
487
                                        loadedTile.getLr().getX(), 
488
                                        loadedTile.getLr().getY());
489
                
490
                if(tiling == null || tiling.booleanValue()) {
491
                        lastTransparency.setAlphaBand(transparencyBuffer);
492
                        if(filterList != null) 
493
                                replaceColorTable(colorTable);
494
                        Grid grid = null;
495
                        try {
496
                                grid = bufferPreprocessing(buf, new GridTransparencyImpl(lastTransparency));
497
                        } catch (ProcessInterruptedException e3) {
498
                                return;
499
                        }
500
                        buf = grid.getRasterBuf();
501

    
502
                        //Reescalado de los tiles. El tama?o en pixels de un tile no tiene pq coincidir con el de la vista.
503
                        double w = lastViewPortData.getWidth();
504
                        double h = lastViewPortData.getHeight();
505
                        if(viewDimension != null) {
506
                                w = viewDimension.getWidth();
507
                                h = viewDimension.getHeight();
508
                        }
509
                        double viewScaleW = lastViewPortData.getExtent().width() / w;
510
                        double tileScaleW = e.width() / (double)buf.getWidth();
511
                        double scaleW = viewScaleW / tileScaleW;
512
                        double viewScaleH = lastViewPortData.getExtent().height() / h;
513
                        double tileScaleH = e.height() / (double)buf.getHeight();
514
                        double scaleH = viewScaleH / tileScaleH;
515

    
516
                        ImageDrawer d = new ImageDrawer(this);
517
                        d.setBuffer(buf);
518
                        d.setStep(null);
519
                        d.setBufferSize(buf.getWidth(), buf.getHeight());
520
                        Image geoImage;
521
                        try {
522
                                geoImage = d.drawBufferOverImageObject();
523
                        } catch (ProcessInterruptedException e2) {
524
                                return;
525
                        }
526

    
527
                        lastTransparency.setAlphaBand(null);
528
                        
529
                        AffineTransform at = new AffineTransform();
530
                        at.scale(1/scaleW, 1/scaleH);
531
                        
532
                        try {
533
                                Point2D pt = new Point2D.Double(e.getULX(), e.getULY());
534
                                ((DefaultViewPortData)lastViewPortData).mat.transform(pt, pt);
535
                                at.inverseTransform(pt, pt);
536

    
537
                                lastGraphics.transform(at);
538
                                lastGraphics.drawImage(geoImage, (int) Math.round(pt.getX()), (int) Math.round(pt.getY()), null);
539
                                lastGraphics.transform(at.createInverse());
540
                                
541
                        } catch (NoninvertibleTransformException e1) {
542
                                e1.printStackTrace();
543
                        }
544
                } else {
545
                        try {
546
                                drawBufferOnImage(lastGraphics, lastViewPortData, buf, step, transf, e);
547
                        } catch (RasterDriverException e1) {
548
                                LoggerFactory.getLogger(getClass()).debug("Error loading data", e1);
549
                        } catch (InvalidSetViewException e1) {
550
                                LoggerFactory.getLogger(getClass()).debug("Invalid view", e1);
551
                        } catch (ProcessInterruptedException e1) {
552
                        }
553
                }
554
        }
555
        
556
        /**
557
         * Applies filters and transparency on the buffer and returns the grid with the modified buffer.
558
         * @param buf
559
         * @param transparency
560
         * @throws ProcessInterruptedException
561
         */
562
        private Grid bufferPreprocessing(Buffer buf, GridTransparency transparency) throws ProcessInterruptedException {
563
                if (dataStore != null) {
564
                        //Asignamos los datos al objeto transparencia antes de aplicar la pila de filtros para que el valor NoData sea efectivo
565
                        if (dataStore.getTransparency().isNoDataActive() || transparency.existAlphaBand())
566
                                transparency.setDataBuffer(buf);
567
                        else {
568
                                transparency.setDataBuffer(null);
569
                        }
570
                        transparency.activeTransparency();
571
                } else
572
                        return null;
573

    
574
                //Aplicamos los filtros
575
                grid = new GridImpl(buf, dataStore, true);
576
                if(filterList != null) {
577
                        filterList.addEnvParam("Transparency", transparency);
578
                        grid.setFilterList(filterList);
579
                        grid.applyFilters();
580
                }
581
                
582
                //Si la lista de filtros genera bandas de transparencia se mezclan con la actual
583
                if(grid.getFilterList().getAlphaBand() != null) {
584
                        Buffer t = grid.getFilterList().getAlphaBand();
585
                        if(transparency.getAlphaBand() != null)
586
                                t = RasterLocator.getManager().getColorConversion().mergeTransparencyBuffers(t, transparency.getAlphaBand());
587
                        transparency.setAlphaBand(t);
588
                        transparency.activeTransparency();
589
                }
590
                
591
                return grid;
592
        }
593
        
594
        /**
595
         * When tiles are renderized the color table in each tile could be diferent.
596
         * In this case the color table must be replaced
597
         */
598
        private void replaceColorTable(ColorTable ct) {
599
                ColorTable colorTable = null;
600
                if(ct == null)
601
                        colorTable = dataStore.getColorTable();
602
                else
603
                        colorTable = ct;
604
                if(colorTable != null) {
605
                        RasterFilterListManager colorTableManager;
606
                        try {
607
                                filterList.remove("enhanced_stretch");
608
                                colorTableManager = filterList.getManagerByID("ColorTable");
609
                                Params params = filterList.createEmptyFilterParams();
610
                                params.setParam("colorTable", colorTable);
611
                                colorTableManager.addFilter(params);
612
                        } catch (FilterManagerException e) {
613
                                e.printStackTrace();
614
                        } catch (FilterTypeException e) {
615
                                e.printStackTrace();
616
                        }
617
                }
618
        }
619
        
620
        /*
621
         * (non-Javadoc)
622
         * @see org.gvsig.raster.impl.grid.render.TileListener#endReading()
623
         */
624
        public void endReading() {
625
                isDrawing = false;
626
        }
627
        
628
        /*
629
         * (non-Javadoc)
630
         * @see org.gvsig.raster.impl.grid.render.TileListener#isReading()
631
         */
632
        public boolean isReading() {
633
                return isDrawing;
634
        }
635
        
636
        /*
637
         * (non-Javadoc)
638
         * @see org.gvsig.fmap.dal.coverage.grid.render.Render#setReading(boolean)
639
         */
640
        public void setReading(boolean reading) {
641
                isDrawing = reading;
642
        }
643
        
644
        /**
645
         * Calculamos la petici?n en coordenadas del mundo real con la transformaci?n del raster. Esto
646
         * permite obtener las coordenadas de la petici?n con la rotaci?n, si la tiene.
647
         * @param vp
648
         * @param ldatastore
649
         * @return
650
         */
651
        private Extent request(ViewPortData vp, RasterDataStore ldatastore) {
652
                if (ldatastore.isRotated()) {
653
                        //Obtenemos las cuatro esquinas de la selecci?n que hemos hecho en la vista
654
                        Point2D ul = new Point2D.Double(vp.getExtent().minX(), vp.getExtent().maxY());
655
                        Point2D ur = new Point2D.Double(vp.getExtent().maxX(), vp.getExtent().maxY());
656
                        Point2D ll = new Point2D.Double(vp.getExtent().minX(), vp.getExtent().minY());
657
                        Point2D lr = new Point2D.Double(vp.getExtent().maxX(), vp.getExtent().minY());
658

    
659
                        //Las pasamos a coordenadas pixel del raster
660
                        ul = ldatastore.worldToRaster(ul);
661
                        ur = ldatastore.worldToRaster(ur);
662
                        ll = ldatastore.worldToRaster(ll);
663
                        lr = ldatastore.worldToRaster(lr);
664

    
665
                        //Obtenemos los valores pixel m?ximos y m?nimos para X e Y
666
                        double pxMaxX = Math.max(Math.max(ul.getX(), ur.getX()), Math.max(ll.getX(), lr.getX()));
667
                        double pxMaxY = Math.max(Math.max(ul.getY(), ur.getY()), Math.max(ll.getY(), lr.getY()));
668
                        double pxMinX = Math.min(Math.min(ul.getX(), ur.getX()), Math.min(ll.getX(), lr.getX()));
669
                        double pxMinY = Math.min(Math.min(ul.getY(), ur.getY()), Math.min(ll.getY(), lr.getY()));
670

    
671
                        //Ajustamos las coordenadas pixel al ?rea m?xima del raster
672
                        pxMinX = Math.max(pxMinX, 0);
673
                        pxMinY = Math.max(pxMinY, 0);
674
                        pxMaxX = Math.min(pxMaxX, ldatastore.getWidth());
675
                        pxMaxY = Math.min(pxMaxY, ldatastore.getHeight());
676

    
677
                        //Petici?n en coordenadas pixel
678
                        ulPxRequest = new Point2D.Double(pxMinX, pxMinY);
679
                        lrPxRequest = new Point2D.Double(pxMaxX, pxMaxY);
680

    
681
                        //Calculamos el ancho y alto del buffer sobre el que se escribe la petici?n
682
                        widthImage = ((Math.abs(lrPxRequest.getX() - ulPxRequest.getX()) * vp
683
                                        .getWidth()) / Math.abs(pxMaxX - pxMinX));
684
                        heightImage = ((Math.abs(lrPxRequest.getY() - ulPxRequest.getY()) * vp
685
                                        .getHeight()) / Math.abs(pxMaxY - pxMinY));
686

    
687
                        //Convertimos la petici?n en coordenadas pixel a petici?n en coordenadas reales.
688
                        Point2D ulWC = ldatastore.rasterToWorld(ulPxRequest);
689
                        Point2D lrWC = ldatastore.rasterToWorld(lrPxRequest);
690

    
691
                        //Ajustamos la petici?n a los limites del raster, teniendo en cuenta la rotaci?n de este.
692
                        return new ExtentImpl(ulWC, lrWC);
693
                }
694
                Extent adjustedRotedExtent = util.calculateAdjustedView(vp.getExtent(), ldatastore.getAffineTransform(), ldatastore.getWidth(), ldatastore.getHeight());
695
                widthImage = (int)Math.round(Math.abs(adjustedRotedExtent.width() * vp.getMat().getScaleX()));
696
                heightImage = (int)Math.round(Math.abs(adjustedRotedExtent.height() * vp.getMat().getScaleY()));
697
                Point2D ul = new Point2D.Double(adjustedRotedExtent.getULX(), adjustedRotedExtent.getULY());
698
                Point2D lr = new Point2D.Double(adjustedRotedExtent.getLRX(), adjustedRotedExtent.getLRY());
699
                ul = ldatastore.worldToRaster(ul);
700
                lr = ldatastore.worldToRaster(lr);
701
                ulPxRequest = new Point2D.Double(ul.getX(), ul.getY());
702
                lrPxRequest = new Point2D.Double(lr.getX(), lr.getY());
703
                return adjustedRotedExtent;
704
        }
705

    
706
        /*
707
         * (non-Javadoc)
708
         * @see org.gvsig.fmap.dal.coverage.grid.render.Render#getRenderBands()
709
         */
710
        public int[] getRenderBands() {
711
                return renderBands;
712
        }
713
        
714
        /*
715
         * (non-Javadoc)
716
         * @see org.gvsig.fmap.dal.coverage.grid.render.Render#isRenderingAsGray()
717
         */
718
        public boolean isRenderingAsGray() {
719
                int[] renderBands = getRenderBands();
720
                if ((renderBands != null) && (renderBands.length == 3) && (renderBands[0] >= 0) &&
721
                                (renderBands[0] == renderBands[1]) && (renderBands[1] == renderBands[2]))
722
                        return true;
723
                return false;
724
        }
725

    
726
        /**
727
                 * Asigna el n?mero de bandas y el orden de renderizado. Cada posici?n del vector es una banda
728
         * del buffer y el contenido de esa posici?n es la banda de la imagen que se dibujar?
729
         * sobre ese buffer. A la hora de renderizar hay que tener en cuenta que solo se renderizan las
730
         * tres primeras bandas del buffer por lo que solo se tienen en cuenta los tres primeros
731
         * elementos. Por ejemplo, el array {1, 0, 3} dibujar? sobre el Graphics las bandas 1,0 y 3 de un
732
         * raster que tiene al menos 4 bandas. La notaci?n con -1 en alguna posici?n del vector solo tiene sentido
733
         * en la visualizaci?n pero no se puede as?gnar una banda del buffer a null.
734
         * Algunos ejemplos:
735
         * <P>
736
         * {-1, 0, -1} Dibuja la banda 0 del raster en la G de la visualizaci?n.
737
         * Si replicateBand es true R = G = B sino R = B = 0
738
         * {1, 0, 3} La R = banda 1 del raster, G = 0 y B = 3
739
         * {0} La R = banda 0 del raster. Si replicateBand es true R = G = B sino G = B = 0
740
         * </P>
741
         *
742
         *
743
                 * @param renderBands: bandas y su posici?n
744
                 */
745
        public void setRenderBands(int[] renderBands) {
746
                if(        renderBands[0] != this.renderBands[0] ||
747
                        renderBands[1] != this.renderBands[1] ||
748
                        renderBands[2] != this.renderBands[2])
749
                        callVisualPropertyChanged(renderBands);
750
                this.renderBands = renderBands;
751
                if (filterList != null)
752
                        for (int i = 0; i < filterList.lenght(); i++)
753
                                (filterList.get(i)).addParam("renderBands", renderBands);
754
        }
755

    
756
        /**
757
         * Dado que la notaci?n de bandas para renderizado admite posiciones con -1 y la notaci?n del
758
         * buffer no ya que no tendria sentido. Esta funci?n adapta la primera notaci?n a la segunda
759
         * para realizar la petici?n setAreaOfInterest y cargar el buffer.
760
         * @param b Array que indica la posici?n de bandas para el renderizado
761
         * @return Array que indica la posici?n de bandas para la petici?n
762
         */
763
        public int[] formatArrayRenderBand(int[] b) {
764
                int cont = 0;
765
                for(int i = 0; i < b.length; i++)
766
                        if(b[i] >= 0)
767
                                cont ++;
768
                if(cont <= 0)
769
                        return null;
770
                int[] out = new int[cont];
771
                int pos = 0;
772
                for(int i = 0; i < cont; i++) {
773
                        while(b[pos] == -1)
774
                                pos ++;
775
                        out[i] = b[pos];
776
                        pos ++;
777
                }
778
                return out;
779
        }
780

    
781
        /*
782
         * (non-Javadoc)
783
         * @see org.gvsig.fmap.dal.coverage.grid.Render#getLastTransparency()
784
         */
785
        public Transparency getLastTransparency() {
786
                return lastTransparency;
787
        }
788
        
789
        /*
790
         * (non-Javadoc)
791
         * @see org.gvsig.fmap.dal.coverage.grid.render.Render#getLastAlphaBandNumber()
792
         */
793
        public int getLastAlphaBandNumber() {
794
                return lastAlphaBand;
795
        }
796

    
797
        /*
798
         * (non-Javadoc)
799
         * @see org.gvsig.fmap.dal.coverage.grid.render.Render#setLastTransparency(org.gvsig.fmap.dal.coverage.store.props.Transparency)
800
         */
801
        public void setLastTransparency(Transparency lastTransparency) {
802
                this.lastTransparency = lastTransparency;
803
                if(this.lastTransparency != null)
804
                        this.lastTransparency.addPropertyListener(this);
805
        }
806

    
807
        /*
808
         * (non-Javadoc)
809
         * @see org.gvsig.fmap.dal.coverage.grid.Render#getFilterList()
810
         */
811
        public RasterFilterList getFilterList() {
812
                return filterList;
813
        }
814

    
815
        /*
816
         * (non-Javadoc)
817
         * @see org.gvsig.fmap.dal.coverage.grid.render.Render#getLastRenderBuffer()
818
         */
819
        public Buffer getLastRenderBuffer() {
820
                return this.lastRenderBuffer;
821
        }
822

    
823
        /*
824
         * (non-Javadoc)
825
         * @see org.gvsig.fmap.dal.coverage.grid.render.Render#setLastRenderBuffer(org.gvsig.fmap.dal.coverage.dataset.Buffer)
826
         */
827
        public void setLastRenderBuffer(Buffer buf) {
828
                this.lastRenderBuffer = buf;
829
        }
830

    
831
        /*
832
         * (non-Javadoc)
833
         * @see org.gvsig.fmap.dal.coverage.grid.render.Render#setFilterList(org.gvsig.fmap.dal.coverage.grid.RasterFilterList)
834
         */
835
        public void setFilterList(RasterFilterList filterList) {
836
                this.filterList = filterList;
837
                this.filterList.addFilterListListener(this);
838
        }
839

    
840
        /*
841
         * (non-Javadoc)
842
         * @see org.gvsig.fmap.dal.coverage.grid.render.Render#existColorTable()
843
         */
844
        public boolean existColorTable() {
845
                        return (filterList.getFilterByBaseClass(ColorTableFilter.class) != null);
846
        }
847
        
848
        /*
849
         * (non-Javadoc)
850
         * @see org.gvsig.fmap.dal.coverage.grid.render.Render#getColorTable()
851
         */
852
        public ColorTable getColorTable() {
853
                if(existColorTable()) {
854
                        RasterFilter f = filterList.getFilterByBaseClass(ColorTableFilter.class);
855
                        return ((ColorTableFilter)f).getColorTable();
856
                }
857
                return null;
858
        }
859

    
860
        /**
861
         * Obtiene el grid asociado al render
862
         * @return
863
         */
864
        public Grid getGrid() {
865
                return grid;
866
        }
867

    
868
        /**
869
         * Asigna la factoria de buffer del renderizador
870
         * @param bf
871
         */
872
        public void setDataSource(RasterDataStore ds) {
873
                this.dataStore = ds;
874
        }
875

    
876
        /**
877
         * Evento activado cuando cambia una propiedad de transparencia.
878
         */
879
        public void actionValueChanged(PropertyEvent e) {
880
                callVisualPropertyChanged(new VisualPropertyEvent(e.getSource()));
881
        }
882

    
883
        /**
884
         * Evento activado cuando cambia la lista de filtros.
885
         */
886
        public void filterListChanged(FilterListChangeEvent e) {
887
                callVisualPropertyChanged(new VisualPropertyEvent(e.getSource()));
888
        }
889

    
890
        /**
891
         * Sets buffers to null
892
         */
893
        public void free() {
894
                if (lastTransparency != null)
895
                        lastTransparency.free();
896
                if (grid != null && grid instanceof GridImpl)
897
                        ((GridImpl)grid).free();
898
                if (getFilterList() != null && getFilterList() instanceof DefaultRasterFilterList)
899
                        ((DefaultRasterFilterList)getFilterList()).free();
900
                grid = null;
901
                dataStore = null;
902
                if (lastRenderBuffer != null)
903
                        lastRenderBuffer.free();
904
                lastRenderBuffer = null;
905
        }
906

    
907
        public void loadFromState(PersistentState state)
908
                        throws PersistenceException {
909
                lastTransparency = (GridTransparencyImpl)state.get("lastTransparency");                
910
        }
911

    
912
        public void saveToState(PersistentState state) throws PersistenceException {
913
                state.set("lastTransparency", lastTransparency);        
914
        }
915
        
916
        public static void registerPersistent() {
917
                PersistenceManager manager = ToolsLocator.getPersistenceManager();
918
                DynStruct definition = manager.addDefinition(
919
                                DefaultRender.class,
920
                                "RasterRendering",
921
                                "RasterRendering Persistent definition",
922
                                null, 
923
                                null
924
                );
925
                definition.addDynField("lastTransparency");
926
        }
927

    
928
}