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 @ 2303

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

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

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

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

    
132
        private Point2D          ulPxRequest, lrPxRequest;
133

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

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

    
204
                drawer = new ImageDrawerImpl();
205

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

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

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

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

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

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

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

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

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

    
319
                if(util.isOutside(vp.getExtent(), dataStore.getExtent())) {
320
                        endReading();
321
                        return;
322
                }
323
                
324
                if (dataStore != null) {
325
                        //TODO:Eliminado pq parece que machaca lo que ha puesto BandSelectorPropertiesListener y no hace caso al selector de bandas. 
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(lastAlphaBand);
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
                        //if(lastTransparency.getAlphaBandNumber() != -1) {
522
                                lastTransparency.setAlphaBand(transparencyBuffer);
523
                                Grid grid = null;
524
                                try {
525
                                        grid = bufferPreprocessing(buf, lastTransparency);
526
                                } catch (ProcessInterruptedException e3) {
527
                                        return;
528
                                }
529
                                buf = grid.getRasterBuf();
530
                        //}
531
                }
532
                
533
                if(tiling == null || tiling.booleanValue()) {
534
                        //Reescalado de los tiles. El tama?o en pixels de un tile no tiene pq coincidir con el de la vista.
535
                        double w = lastViewPortData.getWidth();
536
                        double h = lastViewPortData.getHeight();
537
                        if(viewDimension != null) {
538
                                w = viewDimension.getWidth();
539
                                h = viewDimension.getHeight();
540
                        }
541
                        double viewScaleW = lastViewPortData.getExtent().width() / w;
542
                        double tileScaleW = e.width() / (double)buf.getWidth();
543
                        double scaleW = viewScaleW / tileScaleW;
544
                        double viewScaleH = lastViewPortData.getExtent().height() / h;
545
                        double tileScaleH = e.height() / (double)buf.getHeight();
546
                        double scaleH = viewScaleH / tileScaleH;
547

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1006
}