Statistics
| Revision:

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

History | View | Annotate | Download (33.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.gvsig.fmap.dal.coverage.RasterLocator;
33
import org.gvsig.fmap.dal.coverage.dataset.Buffer;
34
import org.gvsig.fmap.dal.coverage.datastruct.Extent;
35
import org.gvsig.fmap.dal.coverage.datastruct.Params;
36
import org.gvsig.fmap.dal.coverage.datastruct.ViewPortData;
37
import org.gvsig.fmap.dal.coverage.exception.FilterManagerException;
38
import org.gvsig.fmap.dal.coverage.exception.FilterTypeException;
39
import org.gvsig.fmap.dal.coverage.exception.InvalidSetViewException;
40
import org.gvsig.fmap.dal.coverage.exception.ProcessInterruptedException;
41
import org.gvsig.fmap.dal.coverage.exception.RasterDriverException;
42
import org.gvsig.fmap.dal.coverage.grid.FilterListChangeEvent;
43
import org.gvsig.fmap.dal.coverage.grid.FilterListChangeListener;
44
import org.gvsig.fmap.dal.coverage.grid.Grid;
45
import org.gvsig.fmap.dal.coverage.grid.RasterFilter;
46
import org.gvsig.fmap.dal.coverage.grid.RasterFilterList;
47
import org.gvsig.fmap.dal.coverage.grid.RasterFilterListManager;
48
import org.gvsig.fmap.dal.coverage.grid.render.Render;
49
import org.gvsig.fmap.dal.coverage.grid.render.VisualPropertyEvent;
50
import org.gvsig.fmap.dal.coverage.grid.render.VisualPropertyListener;
51
import org.gvsig.fmap.dal.coverage.store.RasterDataStore;
52
import org.gvsig.fmap.dal.coverage.store.RasterQuery;
53
import org.gvsig.fmap.dal.coverage.store.props.ColorInterpretation;
54
import org.gvsig.fmap.dal.coverage.store.props.ColorTable;
55
import org.gvsig.fmap.dal.coverage.store.props.Transparency;
56
import org.gvsig.fmap.dal.coverage.util.PropertyEvent;
57
import org.gvsig.fmap.dal.coverage.util.PropertyListener;
58
import org.gvsig.fmap.dal.coverage.util.RasterUtils;
59
import org.gvsig.raster.cache.tile.Tile;
60
import org.gvsig.raster.cache.tile.exception.TileGettingException;
61
import org.gvsig.raster.cache.tile.provider.TileListener;
62
import org.gvsig.raster.impl.DefaultRasterManager;
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.DefaultRasterFilterList;
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.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 ImageDrawer      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
        private Buffer           lastRenderBuffer         = null;
127

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

    
134
        private Point2D          ulPxRequest, lrPxRequest;
135

    
136
        /**
137
         * Array de listeners que ser?n informados cuando cambia una propiedad en la visualizaci?n
138
         */
139
        private ArrayList<VisualPropertyListener>        
140
                                 visualPropertyListener   = new ArrayList<VisualPropertyListener>();
141
        private RasterUtils      util                     = RasterLocator.getManager().getRasterUtils();
142
        private boolean          isDrawing                = false;
143
        
144
        private Graphics2D       lastGraphics             = null;
145
        private ViewPortData     lastViewPortData         = null;
146
        private Dimension2D      viewDimension            = null;
147

    
148
        /**
149
         * Constructor
150
         * @param grid
151
         */
152
        public DefaultRender() {
153
        }
154
        
155
        /**
156
         * Constructor
157
         * @param grid
158
         */
159
        public DefaultRender(RasterDataStore ds) {
160
                this.dataStore = ds;
161
                init();
162
        }
163
        
164
        /*
165
         * (non-Javadoc)
166
         * @see org.gvsig.fmap.dal.coverage.grid.render.Render#getDataStore()
167
         */
168
        public RasterDataStore getDataStore() {
169
                return this.dataStore;
170
        }
171
        
172
        /*
173
         * (non-Javadoc)
174
         * @see org.gvsig.fmap.dal.coverage.grid.render.Render#setDataStore(org.gvsig.fmap.dal.coverage.store.RasterDataStore)
175
         */
176
        public void setDataStore(RasterDataStore dataStore) {
177
                this.dataStore = dataStore;
178
                init();
179
        }
180

    
181
        private void init() {
182
                if(dataStore.getDataType() == null)
183
                        return;
184
                
185
                drawer = new ImageDrawer(this);
186

    
187
                if (dataStore == null) {
188
                        setRenderBands(new int[] { 0, 1, 2 });
189
                        return;
190
                }
191

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

    
205
                //---------------------------------------------------
206
                //INICIALIZACI?N DE LA INTERPRETACI?N DE COLOR
207

    
208
                //Inicializaci?n de la asignaci?n de bandas en el renderizado
209
                //Leemos el objeto metadata para obtener la interpretaci?n de color asociada al raster
210

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

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

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

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

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

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

    
348
                if(util.isOutside(vp.getExtent(), dataStore.getExtent())) {
349
                        endReading();
350
                        return;
351
                }
352

    
353
                Extent adjustedRotedRequest = request(vp, dataStore);
354

    
355
                if ((widthImage <= 0) || (heightImage <= 0)) {
356
                        endReading();
357
                        return;
358
                }
359

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

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

    
414
                // Borramos el buffer de transparencia para que siempre se tenga que regenerar.
415
                lastTransparency.setAlphaBand(null);
416

    
417
                //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
418
                //transformaci?n. Esto no es necesario hacerlo, sin ello se visualiza igual. Unicamente se hace porque de esta
419
                //forma el raster resultante mejora un poco en calidad en ciertos niveles de zoom ya que al aplicar transformaciones
420
                //sobre el Graphics parece que pierde algo de calidad.
421
                if(transf.getScaleX() > 0 && transf.getScaleY() < 0 && transf.getShearX() == 0 && transf.getShearY() == 0) {
422
                        Point2D lastGraphicOffset = new Point2D.Double(adjustedRotedRequest.getULX(), adjustedRotedRequest.getULY());
423
                        ((DefaultViewPortData)vp).mat.transform(lastGraphicOffset, lastGraphicOffset);
424
                        g.drawImage(geoImage, (int) Math.round(lastGraphicOffset.getX()), (int) Math.round(lastGraphicOffset.getY()), null);
425
                        return;
426
                }
427

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
906
        /*
907
         * (non-Javadoc)
908
         * @see org.gvsig.tools.persistence.Persistent#loadFromState(org.gvsig.tools.persistence.PersistentState)
909
         */
910
        public void loadFromState(PersistentState state)
911
                        throws PersistenceException {
912
                lastTransparency = (Transparency)state.get("lastTransparency");        
913
                renderBands = (int[])state.getIntArray("renderBands");
914
                //setFilterList((RasterFilterList)state.get("filterList"));
915
        }
916

    
917
        /*
918
         * (non-Javadoc)
919
         * @see org.gvsig.tools.persistence.Persistent#saveToState(org.gvsig.tools.persistence.PersistentState)
920
         */
921
        public void saveToState(PersistentState state) throws PersistenceException {
922
                state.set("lastTransparency", lastTransparency);
923
                state.set("renderBands", renderBands);
924
                //state.set("filterList", filterList);
925
        }
926
        
927
        public static void registerPersistence() {
928
                PersistenceManager manager = ToolsLocator.getPersistenceManager();
929
                DynStruct definition = manager.addDefinition(
930
                                DefaultRender.class,
931
                                "RasterRendering",
932
                                "RasterRendering Persistent definition",
933
                                null, 
934
                                null
935
                );
936
                definition.addDynFieldObject("lastTransparency").setClassOfValue(Transparency.class).setMandatory(false);
937
                definition.addDynFieldList("renderBands").setClassOfItems(int.class).setMandatory(false);
938
                //definition.addDynFieldObject("filterList").setClassOfValue(RasterFilterList.class).setMandatory(false);
939
        }
940

    
941
}