Statistics
| Revision:

gvsig-raster / org.gvsig.raster / branches / org.gvsig.raster_dataaccess_refactoring / org.gvsig.raster.lib / org.gvsig.raster.lib.impl / src / main / java / org / gvsig / raster / impl / grid / render / DefaultRender.java @ 2236

History | View | Annotate | Download (34.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.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.cresques.cts.ICoordTrans;
33
import org.gvsig.fmap.dal.coverage.RasterLocator;
34
import org.gvsig.fmap.dal.coverage.RasterManager;
35
import org.gvsig.fmap.dal.coverage.dataset.Buffer;
36
import org.gvsig.fmap.dal.coverage.datastruct.Extent;
37
import org.gvsig.fmap.dal.coverage.datastruct.Params;
38
import org.gvsig.fmap.dal.coverage.datastruct.ViewPortData;
39
import org.gvsig.fmap.dal.coverage.exception.FilterManagerException;
40
import org.gvsig.fmap.dal.coverage.exception.FilterTypeException;
41
import org.gvsig.fmap.dal.coverage.exception.ProcessInterruptedException;
42
import org.gvsig.fmap.dal.coverage.exception.QueryException;
43
import org.gvsig.fmap.dal.coverage.grid.FilterListChangeEvent;
44
import org.gvsig.fmap.dal.coverage.grid.FilterListChangeListener;
45
import org.gvsig.fmap.dal.coverage.grid.Grid;
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.buffer.DefaultRasterQuery;
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.filter.band.ColorTableFilter;
68
import org.gvsig.raster.impl.store.properties.DataStoreColorInterpretation;
69
import org.gvsig.tools.ToolsLocator;
70
import org.gvsig.tools.dynobject.DynStruct;
71
import org.gvsig.tools.persistence.PersistenceManager;
72
import org.gvsig.tools.persistence.Persistent;
73
import org.gvsig.tools.persistence.PersistentState;
74
import org.gvsig.tools.persistence.exception.PersistenceException;
75
import org.gvsig.tools.task.TaskStatus;
76
import org.slf4j.LoggerFactory;
77
/**
78
 * Esta clase se encarga de la gesti?n del dibujado de datos le?dos desde la capa
79
 * "dataaccess" sobre objetos java. Para ello necesita una fuente de datos que tipicamente
80
 * es un buffer (RasterBuffer) y un objeto que realice la funci?n de escritura de datos a
81
 * partir de un estado inicial.
82
 * Esta capa del renderizado gestiona Extents, rotaciones, tama?os de vista pero la escritura
83
 * de datos desde el buffer al objeto image es llevada a cabo por ImageDrawer.
84
 *
85
 * Par?metros de control de la visualizaci?n:
86
 * <UL>
87
 * <LI>renderBands: Orden de visualizado de las bands.</LI>
88
 * <LI>replicateBands: Para visualizaci?n de raster de una banda. Dice si se replica sobre las otras dos bandas
89
 * de visualizaci?n o se ponen a 0.</LI>
90
 * <LI>enhanced: aplicaci?n de filtro de realce</LI>
91
 * <LI>removeEnds: Eliminar extremos en el filtro de realce. Uso del segundo m?ximo y m?nimo</LI>
92
 * <LI>tailTrim: Aplicacion de recorte de colas en el realce. Es un valor decimal que representa el porcentaje del recorte entre 100.
93
 * Es decir, 0.1 significa que el recorte es de un 10%</LI>
94
 * </UL>
95
 *
96
 * @author Nacho Brodin (nachobrodin@gmail.com)
97
 */
98
public class DefaultRender implements Render, PropertyListener, FilterListChangeListener, Persistent, TileListener {
99

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

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

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

    
133
        private Point2D          ulPxRequest, lrPxRequest;
134

    
135
        /**
136
         * Array de listeners que ser?n informados cuando cambia una propiedad en la visualizaci?n
137
         */
138
        private ArrayList<VisualPropertyListener>        
139
                                 visualPropertyListener   = new ArrayList<VisualPropertyListener>();
140
        private RasterUtils      util                     = RasterLocator.getManager().getRasterUtils();
141
        private boolean          isDrawing                = false;
142
        
143
        private Graphics2D       lastGraphics             = null;
144
        private ViewPortData     lastViewPortData         = null;
145
        private Dimension2D      viewDimension            = null;
146
        private RasterRenderReprojection
147
                                 reprojectionOnTheFly     = null;
148
        private RasterManager    rManager                 = null;
149
        
150
        /**
151
         * Constructor
152
         * @param grid
153
         */
154
        public DefaultRender() {
155
        }
156
        
157
        /**
158
         * Constructor
159
         * @param grid
160
         */
161
        public DefaultRender(RasterDataStore ds) {
162
                this.dataStore = ds;
163
                init();
164
        }
165
        
166
        private RasterManager getRasterManager() {
167
                if(rManager == null)
168
                        rManager = RasterLocator.getManager();
169
                return rManager;
170
        }
171
        
172
        public void createReprojectionOnTheFly(
173
                        RasterDataStore store, 
174
                        ICoordTrans coordTrans,
175
                        TaskStatus status) {
176
                reprojectionOnTheFly = new RasterRenderReprojection(
177
                                store, coordTrans, status); 
178
        }
179
        
180
        public boolean isReprojectingOnTheFly() {
181
                return reprojectionOnTheFly != null;
182
        }
183
        
184
        /*
185
         * (non-Javadoc)
186
         * @see org.gvsig.fmap.dal.coverage.grid.render.Render#getDataStore()
187
         */
188
        public RasterDataStore getDataStore() {
189
                return this.dataStore;
190
        }
191
        
192
        /*
193
         * (non-Javadoc)
194
         * @see org.gvsig.fmap.dal.coverage.grid.render.Render#setDataStore(org.gvsig.fmap.dal.coverage.store.RasterDataStore)
195
         */
196
        public void setDataStore(RasterDataStore dataStore) {
197
                this.dataStore = dataStore;
198
                init();
199
        }
200

    
201
        private void init() {
202
                if(dataStore == null || dataStore.getDataType() == null)
203
                        return;
204

    
205
                drawer = new ImageDrawerImpl();
206

    
207
                if (dataStore == null) {
208
                        setRenderBands(new int[] { 0, 1, 2 });
209
                        return;
210
                }
211

    
212
                //Bandas que se dibujan por defecto si la interpretaci?n de color no tiene valores
213
                switch (dataStore.getBandCount()) {
214
                case 1:
215
                        setRenderBands(new int[] { 0, 0, 0 });
216
                        break;
217
                case 2:
218
                        setRenderBands(new int[] { 0, 1, 1 });
219
                        break;
220
                default:
221
                        setRenderBands(new int[] { 0, 1, 2 });
222
                        break;
223
                }
224

    
225
                //---------------------------------------------------
226
                //INICIALIZACI?N DE LA INTERPRETACI?N DE COLOR
227

    
228
                //Inicializaci?n de la asignaci?n de bandas en el renderizado
229
                //Leemos el objeto metadata para obtener la interpretaci?n de color asociada al raster
230

    
231
                ColorInterpretation colorInterpr = dataStore.getColorInterpretation();
232
                if (colorInterpr != null)
233
                        if (colorInterpr.getBand(DataStoreColorInterpretation.PAL_BAND) == -1) {
234
                                if (colorInterpr.isUndefined())
235
                                        return;
236
                                int[] result = new int[] { -1, -1, -1 };
237
                                int gray = colorInterpr.getBand(DataStoreColorInterpretation.GRAY_BAND);
238
                                if (gray != -1)
239
                                        result[0] = result[1] = result[2] = gray;
240
                                else {
241
                                        int r = colorInterpr.getBand(DataStoreColorInterpretation.RED_BAND);
242
                                        if (r != -1)
243
                                                result[0] = r;
244
                                        int g = colorInterpr.getBand(DataStoreColorInterpretation.GREEN_BAND);
245
                                        if (g != -1)
246
                                                result[1] = g;
247
                                        int b = colorInterpr.getBand(DataStoreColorInterpretation.BLUE_BAND);
248
                                        if (b != -1)
249
                                                result[2] = b;
250
                                }
251
                                setRenderBands(result);
252
                        }
253
        }
254

    
255
        /**
256
         * Asigna un listener a la lista que ser? informado cuando cambie una
257
         * propiedad visual en la renderizaci?n.
258
         * @param listener VisualPropertyListener
259
         */
260
        public void addVisualPropertyListener(VisualPropertyListener listener) {
261
                visualPropertyListener.add(listener);
262
        }
263

    
264
        /**
265
         * M?todo llamado cuando hay un cambio en una propiedad de visualizaci?n
266
         */
267
        private void callVisualPropertyChanged(Object obj) {
268
                if(visualPropertyListener != null) {
269
                        for (int i = 0; i < visualPropertyListener.size(); i++) {
270
                                VisualPropertyEvent ev = new VisualPropertyEvent(obj);
271
                                ((VisualPropertyListener)visualPropertyListener.get(i)).visualPropertyValueChanged(ev);
272
                        }
273
                }
274
        }
275
        
276
        /**
277
         * Thread de dibujado
278
         */
279
        public void run() {
280
                try {
281
                        draw(lastGraphics, lastViewPortData, null);
282
                } catch (QueryException e) {
283
                        LoggerFactory.getLogger(getClass()).debug("Error in a query", e);
284
                } catch (ProcessInterruptedException e) {
285
                }
286
        }
287
        
288
        public void setGraphicInfo(Graphics2D g, ViewPortData vp) {
289
                this.lastGraphics = g;
290
                this.lastViewPortData = vp;
291
        }
292

    
293
        public void drawThread(Graphics2D g, ViewPortData vp) {
294
                //Se dibuja si cae dentro de la vista
295
                if(util.isOutside(vp.getExtent(), dataStore.getExtent())) 
296
                        return;
297
                
298
                setReading(true);
299
                setGraphicInfo(g, vp);
300
                new Thread(this).start();
301

    
302
                while(isReading()) {
303
                        try {
304
                                Thread.sleep(50);
305
                        } catch (InterruptedException e) {
306
                                break;
307
                        }
308
                }
309
        }
310
        
311
        public synchronized void drawTiledService(Graphics2D g, 
312
                        ViewPortData vp, 
313
                        Dimension2D viewDimension, 
314
                        TaskStatus taskStatus)
315
                throws QueryException, ProcessInterruptedException {
316
                lastGraphics = g;
317
                lastViewPortData = vp;
318
                this.viewDimension = viewDimension;
319

    
320
                if(util.isOutside(vp.getExtent(), dataStore.getExtent())) {
321
                        endReading();
322
                        return;
323
                }
324
                
325
                if (dataStore != null) {
326
                        if(getLastTransparency().getAlphaBandNumber() == -1)
327
                                getLastTransparency().setTransparencyBand(dataStore.getTransparency().getAlphaBandNumber());
328
                        
329
                        lastAlphaBand = getLastTransparency().getAlphaBandNumber();
330
                        
331
                        // Asignamos la banda de transparencia si existe esta
332
                        RasterQuery query = getRasterManager().createQuery();
333
                        query.setTaskStatus(taskStatus);
334
                        query.setTime(vp.getTime());
335
                        query.setSupersamplingOption(false); // Desactivamos el supersampleo en la carga del buffer.
336
                        query.setDrawableBands(getRenderBands());
337
                        query.setAlphaBand(getLastTransparency().getAlphaBandNumber());
338
                        query.setAreaOfInterest(vp.getExtent(), 
339
                                        (int)Math.round(vp.getWidth()), 
340
                                        (int)Math.round(vp.getHeight()), this);
341
                        dataStore.query(query);
342
                        query.setSupersamplingOption(true);
343
                } else
344
                        return;
345
        }
346
        
347
        public synchronized Buffer getLastRenderBuffer() 
348
                throws QueryException, ProcessInterruptedException {
349
                return draw(null, lastViewPortData, null);
350
        }
351
        
352
        public synchronized Buffer draw(Graphics2D g, ViewPortData vp, TaskStatus taskStatus)
353
                throws QueryException, ProcessInterruptedException {
354
                lastGraphics = g;
355
                lastViewPortData = vp;
356

    
357
                if(util.isOutside(vp.getExtent(), dataStore.getExtent())) {
358
                        endReading();
359
                        return null;
360
                }
361

    
362
                Extent adjustedRotedRequest = request(vp, dataStore);
363

    
364
                if ((widthImage <= 0) || (heightImage <= 0)) {
365
                        endReading();
366
                        return null;
367
                }
368

    
369
                if (dataStore == null) 
370
                        return null;
371
                
372
                Buffer buf = null; 
373
                double[] step = null;
374
                
375
                if(reprojectionOnTheFly != null) {
376
                        buf = reprojectionOnTheFly.warp(adjustedRotedRequest, 
377
                                        (int)Math.round(widthImage), 
378
                                        (int)Math.round(heightImage), 
379
                                        vp.getTime(), 
380
                                        renderBands, 
381
                                        getLastTransparency());
382
                } else {
383
                        if (getLastTransparency().getAlphaBandNumber() != -1) {
384
                                RasterQuery query = getRasterManager().createQuery();
385
                                //query.setReadOnly(true);
386
                                //query.setMemoryBuffer(true); //Ojo! con buffers remotos
387
                                query.setTaskStatus(taskStatus);
388
                                query.setTime(vp.getTime());
389
                                query.setAreaOfInterest(adjustedRotedRequest, (int)Math.round(widthImage), (int)Math.round(heightImage));
390
                                query.setDrawableBands(new int[] { getLastTransparency().getAlphaBandNumber()});
391
                                getLastTransparency().setAlphaBand(dataStore.query(query));
392
                        }
393
                        lastAlphaBand = getLastTransparency().getAlphaBandNumber();
394

    
395
                        RasterQuery query = getRasterManager().createQuery();
396
                        //query.setReadOnly(true);
397
                        //query.setMemoryBuffer(true); //Ojo! con buffers remotos
398
                        query.setTaskStatus(taskStatus);
399
                        query.setTime(vp.getTime());
400
                        query.setAreaOfInterest(adjustedRotedRequest, (int)Math.round(widthImage), (int)Math.round(heightImage));
401
                        query.setDrawableBands(getRenderBands());
402
                        buf = dataStore.query(query);
403
                        step = query.getStep();
404
                }
405

    
406
                if(drawer == null) {
407
                        init();
408
                }
409
                
410
                return drawBufferOnImage(lastGraphics, 
411
                                        lastViewPortData, 
412
                                        buf, 
413
                                        step, 
414
                                        dataStore.getAffineTransform(), 
415
                                        adjustedRotedRequest);
416
        }
417
        
418
        private synchronized Buffer drawBufferOnImage(Graphics2D g, ViewPortData vp, Buffer buf, double[] step, AffineTransform transf, Extent adjustedRotedRequest)
419
                throws QueryException, ProcessInterruptedException {
420
                
421
                grid = bufferPreprocessing(buf, lastTransparency);
422
                
423
                //Buffer filtrado para renderizar
424
                buf = grid.getRasterBuf();
425
                if(g == null)
426
                        return buf;
427
                drawer.setBuffer(buf); // Buffer de datos a renderizar
428
                drawer.setSupersamplingOn(step); // Desplazamiento para supersampleo
429
                drawer.setOutputSize((int)Math.round(widthImage), (int)Math.round(heightImage)); // Ancho y alto del buffer
430
                drawer.setLastTransparency(getLastTransparency());
431
                Image geoImage = drawer.drawBufferOverImageObject(); // Acci?n de renderizado
432
                drawer.dispose();
433

    
434
                // Borramos el buffer de transparencia para que siempre se tenga que regenerar.
435
                getLastTransparency().setAlphaBand(null);
436

    
437
                //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
438
                //transformaci?n. Esto no es necesario hacerlo, sin ello se visualiza igual. Unicamente se hace porque de esta
439
                //forma el raster resultante mejora un poco en calidad en ciertos niveles de zoom ya que al aplicar transformaciones
440
                //sobre el Graphics parece que pierde algo de calidad.
441
                if(transf.getScaleX() > 0 && transf.getScaleY() < 0 && transf.getShearX() == 0 && transf.getShearY() == 0) {
442
                        Point2D lastGraphicOffset = new Point2D.Double(adjustedRotedRequest.getULX(), adjustedRotedRequest.getULY());
443
                        ((DefaultViewPortData)vp).mat.transform(lastGraphicOffset, lastGraphicOffset);
444
                        g.drawImage(geoImage, (int) Math.round(lastGraphicOffset.getX()), (int) Math.round(lastGraphicOffset.getY()), null);
445
                        return buf;
446
                }
447

    
448
                /*
449
                 * Tenemos una matriz con la transformaci?n de la coordenadas de la vista a coordenadas reales vp.mat, adem?s tenemos
450
                 * la transformaci?n de coordenadas reales a coordenadas pixel (transf). Con ambas podemos obtener una matriz de trasformacion
451
                 * entre coordenadas de la vista a coordenadas pixel (transf X vp.mat). As? obtenemos la transformaci?n entre coordenadas
452
                 * de la vista y coordenadas pixel del raster. El problema es que a cada zoom la escala de la petici?n del raster varia
453
                 * por lo que habr? que calcular una matriz con la escala (escale). escale X transf X vp.mat
454
                 */
455
                double sX = Math.abs(ulPxRequest.getX() - lrPxRequest.getX()) / widthImage;
456
                double sY = Math.abs(ulPxRequest.getY() - lrPxRequest.getY()) / heightImage;
457
                AffineTransform scale = new AffineTransform(sX, 0, 0, sY, 0, 0);
458

    
459
                try {
460
                        AffineTransform at = (AffineTransform)scale.clone();
461
                        at.preConcatenate(transf);
462
                        at.preConcatenate(vp.getMat());
463
                        g.transform(at);
464
                        Point2D.Double pt = null;
465
                        //El punto sobre el que rota la imagen depende del signo de los tama?os del pixel
466
                        if(transf.getScaleX() < 0 && transf.getScaleY() < 0)
467
                                pt = new Point2D.Double(adjustedRotedRequest.maxX(), adjustedRotedRequest.maxY());
468
                        else if(transf.getScaleX() > 0 && transf.getScaleY() > 0)
469
                                pt = new Point2D.Double(adjustedRotedRequest.minX(), adjustedRotedRequest.minY());
470
                        else if(transf.getScaleX() < 0 && transf.getScaleY() > 0)
471
                                pt = new Point2D.Double(adjustedRotedRequest.maxX(), adjustedRotedRequest.minY());
472
                        else
473
                                pt = new Point2D.Double(adjustedRotedRequest.getULX(), adjustedRotedRequest.getULY());
474
                        vp.getMat().transform(pt, pt);
475
                        at.inverseTransform(pt, pt);
476
                        g.drawImage(geoImage, (int) Math.round(pt.getX()), (int) Math.round(pt.getY()), null);
477
                        g.transform(at.createInverse());
478
                } catch (NoninvertibleTransformException e) {
479
                        LoggerFactory.getLogger(getClass()).debug("Transformation error", e);
480
                }
481
                
482
                return buf;
483
                // long t2 = new Date().getTime();
484
                // System.out.println("Renderizando Raster: " + ((t2 - t1) / 1000D) + ", secs.");
485
        }
486
        
487
        public synchronized void tileReady(Tile loadedTile) throws TileGettingException {
488
                boolean crash = false;
489
                Boolean tiling = (Boolean)loadedTile.getDownloaderParams("Tiling");
490
                double[] step = (double[])loadedTile.getDownloaderParams("Step");
491
                AffineTransform transf = (AffineTransform)loadedTile.getDownloaderParams("AffineTransform");
492
                
493
                Extent e = getRasterManager().getDataStructFactory().
494
                createExtent(loadedTile.getUl().getX(), 
495
                                loadedTile.getUl().getY(), 
496
                                loadedTile.getLr().getX(), 
497
                                loadedTile.getLr().getY());
498
                
499
                Buffer buf = (loadedTile.getData() != null && loadedTile.getData().length > 0) ? (Buffer)loadedTile.getData()[0] : null;
500
                Buffer transparencyBuffer = (loadedTile.getData() != null && loadedTile.getData().length > 1) 
501
                                                                                ? (Buffer)loadedTile.getData()[1] : null;
502
                
503
                if(!loadedTile.dataIsLoaded()) {
504
                        if(loadedTile.getCrashImage() == null)
505
                                return;
506
                        crash = true;
507
                        buf = (Buffer)loadedTile.getCrashImage()[0];
508
                        transparencyBuffer = (Buffer)loadedTile.getCrashImage()[1];
509
                        transparencyBuffer.setDataExtent(e.toRectangle2D());
510
                } else {
511
                        if(buf == null)
512
                                return;
513
                        ColorTable tileColorTable = (loadedTile.getData() != null && loadedTile.getData().length > 2) ? (ColorTable)loadedTile.getData()[2] : null;
514
                        if(tiling == null || tiling.booleanValue()) {
515
                                if(filterList != null) 
516
                                        addTileColorTable(tileColorTable);
517
                        }
518
                }
519
                
520
                if(tiling == null || tiling.booleanValue()) {
521
                        lastTransparency.setAlphaBand(transparencyBuffer);
522
                        Grid grid = null;
523
                        try {
524
                                grid = bufferPreprocessing(buf, lastTransparency);
525
                        } catch (ProcessInterruptedException e3) {
526
                                return;
527
                        }
528
                        buf = grid.getRasterBuf();
529
                }
530
                
531
                if(tiling == null || tiling.booleanValue()) {
532
                        //Reescalado de los tiles. El tama?o en pixels de un tile no tiene pq coincidir con el de la vista.
533
                        double w = lastViewPortData.getWidth();
534
                        double h = lastViewPortData.getHeight();
535
                        if(viewDimension != null) {
536
                                w = viewDimension.getWidth();
537
                                h = viewDimension.getHeight();
538
                        }
539
                        double viewScaleW = lastViewPortData.getExtent().width() / w;
540
                        double tileScaleW = e.width() / (double)buf.getWidth();
541
                        double scaleW = viewScaleW / tileScaleW;
542
                        double viewScaleH = lastViewPortData.getExtent().height() / h;
543
                        double tileScaleH = e.height() / (double)buf.getHeight();
544
                        double scaleH = viewScaleH / tileScaleH;
545

    
546
                        ImageDrawerImpl d = new ImageDrawerImpl();
547
                        d.setBuffer(buf);
548
                        d.setSupersamplingOn(null);
549
                        d.setOutputSize(buf.getWidth(), buf.getHeight());
550
                        d.setLastTransparency(getLastTransparency());
551
                        Image geoImage;
552
                        try {
553
                                geoImage = d.drawBufferOverImageObject();
554
                        } catch (ProcessInterruptedException e2) {
555
                                return;
556
                        }
557
                        d.dispose();
558
                        
559
                        lastTransparency.setAlphaBand(null);
560
                        
561
                        AffineTransform at = new AffineTransform();
562
                        at.scale(1/scaleW, 1/scaleH);
563
                        
564
                        try {
565
                                Point2D pt = new Point2D.Double(e.getULX(), e.getULY());
566
                                ((DefaultViewPortData)lastViewPortData).mat.transform(pt, pt);
567
                                at.inverseTransform(pt, pt);
568

    
569
                                lastGraphics.transform(at);
570
                                lastGraphics.drawImage(geoImage, (int) Math.round(pt.getX()), (int) Math.round(pt.getY()), null);
571
                                lastGraphics.transform(at.createInverse());
572
                                
573
                        } catch (NoninvertibleTransformException e1) {
574
                                e1.printStackTrace();
575
                        }
576
                } else {
577
                        try {
578
                                drawBufferOnImage(lastGraphics, lastViewPortData, buf, step, transf, e);
579
                        } catch (QueryException e1) {
580
                                LoggerFactory.getLogger(getClass()).debug("Error loading data", e1);
581
                        } catch (ProcessInterruptedException e1) {
582
                        }
583
                }
584
                
585
                if(!crash) { //Las im?genes de crash no se liberan ya que est?n en un hashmap global
586
                        if(buf != null)
587
                                buf.dispose();
588
                        if(transparencyBuffer != null)
589
                                transparencyBuffer.dispose();
590
                }
591
        }
592

    
593
        /**
594
         * Applies filters and transparency on the buffer and returns the grid with the modified buffer.
595
         * @param buf
596
         * @param transparency
597
         * @throws ProcessInterruptedException
598
         */
599
        private Grid bufferPreprocessing(Buffer buf, Transparency transparency) throws ProcessInterruptedException {
600
                if (dataStore != null) {
601
                        //Asignamos los datos al objeto transparencia antes de aplicar la pila de filtros para que el valor NoData sea efectivo
602
                        if (dataStore.getTransparency().getNoData().isNoDataTransparent() || transparency.existAlphaBand())
603
                                transparency.setDataBuffer(buf);
604
                        else {
605
                                transparency.setDataBuffer(null);
606
                        }
607
                        transparency.activeTransparency();
608
                } else
609
                        return null;
610

    
611
                //Aplicamos los filtros
612
                grid = new GridImpl(buf, dataStore, true);
613
                if(filterList != null) {
614
                        filterList.addEnvParam("Transparency", transparency);
615
                        grid.setFilterList(filterList);
616
                        grid.applyFilters();
617
                }
618
                
619
                //Si la lista de filtros genera bandas de transparencia se mezclan con la actual
620
                if(grid.getFilterList().getAlphaBand() != null) {
621
                        Buffer t = grid.getFilterList().getAlphaBand();
622
                        if(transparency.getAlphaBand() != null)
623
                                t = getRasterManager().getColorConversion().mergeTransparencyBuffers(t, transparency.getAlphaBand());
624
                        transparency.setAlphaBand(t);
625
                        transparency.activeTransparency();
626
                }
627
                
628
                return grid;
629
        }
630
        
631
        /**
632
         * When tiles are renderized the color table in each tile could be diferent.
633
         * In this case the color table must be replaced
634
         */
635
        //@deprecated one color table by tiled layer
636
        private void addTileColorTable(ColorTable tileColorTable) {
637
                if(tileColorTable == null)
638
                        return;
639
                else {
640
                        if(filterList.getFilterClassByID("ColorTable") == null) {
641
                                try {
642
                                        RasterFilterListManager colorTableManager = filterList.getManagerByID("ColorTable");
643
                                        Params params = filterList.createEmptyFilterParams();
644
                                        params.setParam("colorTable", tileColorTable);
645
                                        colorTableManager.addFilter(params);
646
                                } catch (FilterManagerException e) {
647
                                        e.printStackTrace();
648
                                } catch (FilterTypeException e) {
649
                                        e.printStackTrace();
650
                                }
651
                        }
652
                }
653
                /*ColorTable colorTable = null;
654
                if(tileColorTable == null)
655
                        colorTable = dataStore.getColorTable();
656
                else
657
                        colorTable = tileColorTable;
658
                if(colorTable != null) {
659
                        RasterFilterListManager colorTableManager;
660
                        try {
661
                                filterList.remove("enhanced_stretch");
662
                                colorTableManager = filterList.getManagerByID("ColorTable");
663
                                Params params = filterList.createEmptyFilterParams();
664
                                params.setParam("colorTable", colorTable);
665
                                colorTableManager.addFilter(params);
666
                        } catch (FilterManagerException e) {
667
                                e.printStackTrace();
668
                        } catch (FilterTypeException e) {
669
                                e.printStackTrace();
670
                        }
671
                }*/
672
        }
673
        
674
        /*
675
         * (non-Javadoc)
676
         * @see org.gvsig.raster.impl.grid.render.TileListener#endReading()
677
         */
678
        public void endReading() {
679
                isDrawing = false;
680
        }
681
        
682
        /*
683
         * (non-Javadoc)
684
         * @see org.gvsig.raster.impl.grid.render.TileListener#isReading()
685
         */
686
        public boolean isReading() {
687
                return isDrawing;
688
        }
689
        
690
        /*
691
         * (non-Javadoc)
692
         * @see org.gvsig.fmap.dal.coverage.grid.render.Render#setReading(boolean)
693
         */
694
        public void setReading(boolean reading) {
695
                isDrawing = reading;
696
        }
697
        
698
        /**
699
         * Calculamos la petici?n en coordenadas del mundo real con la transformaci?n del raster. Esto
700
         * permite obtener las coordenadas de la petici?n con la rotaci?n, si la tiene.
701
         * @param vp
702
         * @param ldatastore
703
         * @return
704
         */
705
        private Extent request(ViewPortData vp, RasterDataStore ldatastore) {
706
                if (ldatastore.isRotated()) {
707
                        //Obtenemos las cuatro esquinas de la selecci?n que hemos hecho en la vista
708
                        Point2D ul = new Point2D.Double(vp.getExtent().minX(), vp.getExtent().maxY());
709
                        Point2D ur = new Point2D.Double(vp.getExtent().maxX(), vp.getExtent().maxY());
710
                        Point2D ll = new Point2D.Double(vp.getExtent().minX(), vp.getExtent().minY());
711
                        Point2D lr = new Point2D.Double(vp.getExtent().maxX(), vp.getExtent().minY());
712

    
713
                        //Las pasamos a coordenadas pixel del raster
714
                        ul = ldatastore.worldToRaster(ul);
715
                        ur = ldatastore.worldToRaster(ur);
716
                        ll = ldatastore.worldToRaster(ll);
717
                        lr = ldatastore.worldToRaster(lr);
718

    
719
                        //Obtenemos los valores pixel m?ximos y m?nimos para X e Y
720
                        double pxMaxX = Math.max(Math.max(ul.getX(), ur.getX()), Math.max(ll.getX(), lr.getX()));
721
                        double pxMaxY = Math.max(Math.max(ul.getY(), ur.getY()), Math.max(ll.getY(), lr.getY()));
722
                        double pxMinX = Math.min(Math.min(ul.getX(), ur.getX()), Math.min(ll.getX(), lr.getX()));
723
                        double pxMinY = Math.min(Math.min(ul.getY(), ur.getY()), Math.min(ll.getY(), lr.getY()));
724

    
725
                        //Ajustamos las coordenadas pixel al ?rea m?xima del raster
726
                        pxMinX = Math.max(pxMinX, 0);
727
                        pxMinY = Math.max(pxMinY, 0);
728
                        pxMaxX = Math.min(pxMaxX, ldatastore.getWidth());
729
                        pxMaxY = Math.min(pxMaxY, ldatastore.getHeight());
730

    
731
                        //Petici?n en coordenadas pixel
732
                        ulPxRequest = new Point2D.Double(pxMinX, pxMinY);
733
                        lrPxRequest = new Point2D.Double(pxMaxX, pxMaxY);
734

    
735
                        //Calculamos el ancho y alto del buffer sobre el que se escribe la petici?n
736
                        widthImage = ((Math.abs(lrPxRequest.getX() - ulPxRequest.getX()) * vp
737
                                        .getWidth()) / Math.abs(pxMaxX - pxMinX));
738
                        heightImage = ((Math.abs(lrPxRequest.getY() - ulPxRequest.getY()) * vp
739
                                        .getHeight()) / Math.abs(pxMaxY - pxMinY));
740

    
741
                        //Convertimos la petici?n en coordenadas pixel a petici?n en coordenadas reales.
742
                        Point2D ulWC = ldatastore.rasterToWorld(ulPxRequest);
743
                        Point2D lrWC = ldatastore.rasterToWorld(lrPxRequest);
744

    
745
                        //Ajustamos la petici?n a los limites del raster, teniendo en cuenta la rotaci?n de este.
746
                        return new ExtentImpl(ulWC, lrWC);
747
                }
748
                Extent adjustedRotedExtent = util.calculateAdjustedView(vp.getExtent(), ldatastore.getAffineTransform(), ldatastore.getWidth(), ldatastore.getHeight());
749
                widthImage = (int)Math.round(Math.abs(adjustedRotedExtent.width() * vp.getMat().getScaleX()));
750
                heightImage = (int)Math.round(Math.abs(adjustedRotedExtent.height() * vp.getMat().getScaleY()));
751
                Point2D ul = new Point2D.Double(adjustedRotedExtent.getULX(), adjustedRotedExtent.getULY());
752
                Point2D lr = new Point2D.Double(adjustedRotedExtent.getLRX(), adjustedRotedExtent.getLRY());
753
                ul = ldatastore.worldToRaster(ul);
754
                lr = ldatastore.worldToRaster(lr);
755
                ulPxRequest = new Point2D.Double(ul.getX(), ul.getY());
756
                lrPxRequest = new Point2D.Double(lr.getX(), lr.getY());
757
                return adjustedRotedExtent;
758
        }
759

    
760
        /*
761
         * (non-Javadoc)
762
         * @see org.gvsig.fmap.dal.coverage.grid.render.Render#getRenderBands()
763
         */
764
        public int[] getRenderBands() {
765
                return renderBands;
766
        }
767
        
768
        /*
769
         * (non-Javadoc)
770
         * @see org.gvsig.fmap.dal.coverage.grid.render.Render#isRenderingAsGray()
771
         */
772
        public boolean isRenderingAsGray() {
773
                int[] renderBands = getRenderBands();
774
                if ((renderBands != null) && (renderBands.length == 3) && (renderBands[0] >= 0) &&
775
                                (renderBands[0] == renderBands[1]) && (renderBands[1] == renderBands[2]))
776
                        return true;
777
                return false;
778
        }
779

    
780
        /**
781
                 * Asigna el n?mero de bandas y el orden de renderizado. Cada posici?n del vector es una banda
782
         * del buffer y el contenido de esa posici?n es la banda de la imagen que se dibujar?
783
         * sobre ese buffer. A la hora de renderizar hay que tener en cuenta que solo se renderizan las
784
         * tres primeras bandas del buffer por lo que solo se tienen en cuenta los tres primeros
785
         * elementos. Por ejemplo, el array {1, 0, 3} dibujar? sobre el Graphics las bandas 1,0 y 3 de un
786
         * raster que tiene al menos 4 bandas. La notaci?n con -1 en alguna posici?n del vector solo tiene sentido
787
         * en la visualizaci?n pero no se puede as?gnar una banda del buffer a null.
788
         * Algunos ejemplos:
789
         * <P>
790
         * {-1, 0, -1} Dibuja la banda 0 del raster en la G de la visualizaci?n.
791
         * Si replicateBand es true R = G = B sino R = B = 0
792
         * {1, 0, 3} La R = banda 1 del raster, G = 0 y B = 3
793
         * {0} La R = banda 0 del raster. Si replicateBand es true R = G = B sino G = B = 0
794
         * </P>
795
         *
796
         *
797
                 * @param renderBands: bandas y su posici?n
798
                 */
799
        public void setRenderBands(int[] renderBands) {
800
                if(        renderBands[0] != this.renderBands[0] ||
801
                        renderBands[1] != this.renderBands[1] ||
802
                        renderBands[2] != this.renderBands[2])
803
                        callVisualPropertyChanged(renderBands);
804
                this.renderBands = renderBands;
805
                if (filterList != null)
806
                        for (int i = 0; i < filterList.lenght(); i++)
807
                                (filterList.get(i)).addParam("renderBands", renderBands);
808
        }
809

    
810
        /**
811
         * Dado que la notaci?n de bandas para renderizado admite posiciones con -1 y la notaci?n del
812
         * buffer no ya que no tendria sentido. Esta funci?n adapta la primera notaci?n a la segunda
813
         * para realizar la petici?n setAreaOfInterest y cargar el buffer.
814
         * @param b Array que indica la posici?n de bandas para el renderizado
815
         * @return Array que indica la posici?n de bandas para la petici?n
816
         */
817
        public int[] formatArrayRenderBand(int[] b) {
818
                int cont = 0;
819
                for(int i = 0; i < b.length; i++)
820
                        if(b[i] >= 0)
821
                                cont ++;
822
                if(cont <= 0)
823
                        return null;
824
                int[] out = new int[cont];
825
                int pos = 0;
826
                for(int i = 0; i < cont; i++) {
827
                        while(b[pos] == -1)
828
                                pos ++;
829
                        out[i] = b[pos];
830
                        pos ++;
831
                }
832
                return out;
833
        }
834

    
835
        public Transparency getLastTransparency() {
836
                //If the transparency hasn't been defined yet then we'll take that from the store
837
                if (lastTransparency == null) {
838
                        lastTransparency = dataStore.getTransparency().cloneTransparency();
839
                        lastTransparency.addPropertyListener(this);
840
                }
841
                return lastTransparency;
842
        }
843
        
844
        /*
845
         * (non-Javadoc)
846
         * @see org.gvsig.fmap.dal.coverage.grid.render.Render#getLastAlphaBandNumber()
847
         */
848
        public int getLastAlphaBandNumber() {
849
                return lastAlphaBand;
850
        }
851

    
852
        /*
853
         * (non-Javadoc)
854
         * @see org.gvsig.fmap.dal.coverage.grid.render.Render#setLastTransparency(org.gvsig.fmap.dal.coverage.store.props.Transparency)
855
         */
856
        public void setLastTransparency(Transparency lastTransparency) {
857
                this.lastTransparency = lastTransparency;
858
                if(this.lastTransparency != null)
859
                        this.lastTransparency.addPropertyListener(this);
860
        }
861

    
862
        /*
863
         * (non-Javadoc)
864
         * @see org.gvsig.fmap.dal.coverage.grid.Render#getFilterList()
865
         */
866
        public RasterFilterList getFilterList() {
867
                return filterList;
868
        }
869

    
870
        /*
871
         * (non-Javadoc)
872
         * @see org.gvsig.fmap.dal.coverage.grid.render.Render#setFilterList(org.gvsig.fmap.dal.coverage.grid.RasterFilterList)
873
         */
874
        public void setFilterList(RasterFilterList filterList) {
875
                this.filterList = filterList;
876
                this.filterList.addFilterListListener(this);
877
        }
878

    
879
        /*
880
         * (non-Javadoc)
881
         * @see org.gvsig.fmap.dal.coverage.grid.render.Render#existColorTable()
882
         */
883
        public boolean existColorTable() {
884
                        return (filterList.getFilterByBaseClass(ColorTableFilter.class) != null);
885
        }
886
        
887
        /*
888
         * (non-Javadoc)
889
         * @see org.gvsig.fmap.dal.coverage.grid.render.Render#getColorTable()
890
         */
891
        public ColorTable getColorTable() {
892
                if(existColorTable()) {
893
                        RasterFilter f = filterList.getFilterByBaseClass(ColorTableFilter.class);
894
                        return ((ColorTableFilter)f).getColorTable();
895
                }
896
                return null;
897
        }
898

    
899
        /**
900
         * Obtiene el grid asociado al render
901
         * @return
902
         */
903
        public Grid getGrid() {
904
                return grid;
905
        }
906

    
907
        /**
908
         * Asigna la factoria de buffer del renderizador
909
         * @param bf
910
         */
911
        public void setDataSource(RasterDataStore ds) {
912
                this.dataStore = ds;
913
        }
914

    
915
        /**
916
         * Evento activado cuando cambia una propiedad de transparencia.
917
         */
918
        public void actionValueChanged(PropertyEvent e) {
919
                callVisualPropertyChanged(new VisualPropertyEvent(e.getSource()));
920
        }
921

    
922
        /**
923
         * Evento activado cuando cambia la lista de filtros.
924
         */
925
        public void filterListChanged(FilterListChangeEvent e) {
926
                callVisualPropertyChanged(new VisualPropertyEvent(e.getSource()));
927
        }
928

    
929
        /*
930
         * (non-Javadoc)
931
         * @see org.gvsig.tools.persistence.Persistent#loadFromState(org.gvsig.tools.persistence.PersistentState)
932
         */
933
        public void loadFromState(PersistentState state)
934
                        throws PersistenceException {
935
                lastTransparency = (Transparency)state.get("lastTransparency");        
936
                renderBands = (int[])state.getIntArray("renderBands");
937
                //setFilterList((RasterFilterList)state.get("filterList"));
938
        }
939

    
940
        /*
941
         * (non-Javadoc)
942
         * @see org.gvsig.tools.persistence.Persistent#saveToState(org.gvsig.tools.persistence.PersistentState)
943
         */
944
        public void saveToState(PersistentState state) throws PersistenceException {
945
                state.set("lastTransparency", lastTransparency);
946
                state.set("renderBands", renderBands);
947
                //state.set("filterList", filterList);
948
        }
949
        
950
        public static void registerPersistence() {
951
                PersistenceManager manager = ToolsLocator.getPersistenceManager();
952
                DynStruct definition = manager.addDefinition(
953
                                DefaultRender.class,
954
                                "RasterRendering",
955
                                "RasterRendering Persistent definition",
956
                                null, 
957
                                null
958
                );
959
                definition.addDynFieldObject("lastTransparency").setClassOfValue(Transparency.class).setMandatory(false);
960
                definition.addDynFieldList("renderBands").setClassOfItems(int.class).setMandatory(false);
961
                //definition.addDynFieldObject("filterList").setClassOfValue(RasterFilterList.class).setMandatory(false);
962
        }
963
        
964
        /**
965
         * Sets buffers to null
966
         */
967
        public void dispose() {
968
                if (lastTransparency != null)
969
                        lastTransparency.dispose();
970
                if (grid != null)
971
                        grid.dispose();
972
                if (getFilterList() != null)
973
                        getFilterList().dispose();
974
                try {
975
                        finalize();
976
                } catch (Throwable e) {
977
                }
978
        }
979
        
980
        /*
981
         * (non-Javadoc)
982
         * @see java.lang.Object#finalize()
983
         */
984
        protected void finalize() throws Throwable {
985
                grid                     = null;
986
                dataStore                = null;
987
                renderBands              = null;
988
        drawer                   = null;
989
                lastTransparency         = null;
990
                filterList               = null;
991
        ulPxRequest              = null;
992
        lrPxRequest              = null;
993
                lastGraphics             = null;
994
                lastViewPortData         = null;
995
                viewDimension            = null;
996
                
997
                if(visualPropertyListener != null) {
998
                        visualPropertyListener.clear();
999
                        visualPropertyListener = null;
1000
                }
1001
                super.finalize();
1002
        }
1003

    
1004
}