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

History | View | Annotate | Download (35.8 KB)

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

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

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

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

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

    
128
        /**
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
        private RasterRenderReprojection
148
                                 reprojectionOnTheFly     = null;
149
        
150
        /**
151
         * Constructor
152
         * @param grid
153
         */
154
        public DefaultRender() {
155
        }
156
        
157
        /**
158
         * Constructor
159
         * @param grid
160
         */
161
        public DefaultRender(RasterDataStore ds) {
162
                this.dataStore = ds;
163
                init();
164
        }
165
        
166
        public void createReprojectionOnTheFly(
167
                        RasterDataStore store, 
168
                        ICoordTrans coordTrans,
169
                        TaskStatus status) {
170
                reprojectionOnTheFly = new RasterRenderReprojection(
171
                                store, coordTrans, status); 
172
        }
173
        
174
        public boolean isReprojectingOnTheFly() {
175
                return reprojectionOnTheFly != null;
176
        }
177
        
178
        /*
179
         * (non-Javadoc)
180
         * @see org.gvsig.fmap.dal.coverage.grid.render.Render#getDataStore()
181
         */
182
        public RasterDataStore getDataStore() {
183
                return this.dataStore;
184
        }
185
        
186
        /*
187
         * (non-Javadoc)
188
         * @see org.gvsig.fmap.dal.coverage.grid.render.Render#setDataStore(org.gvsig.fmap.dal.coverage.store.RasterDataStore)
189
         */
190
        public void setDataStore(RasterDataStore dataStore) {
191
                this.dataStore = dataStore;
192
                init();
193
        }
194

    
195
        private void init() {
196
                if(dataStore.getDataType() == null)
197
                        return;
198

    
199
                drawer = new ImageDrawerImpl();
200

    
201
                if (dataStore == null) {
202
                        setRenderBands(new int[] { 0, 1, 2 });
203
                        return;
204
                }
205

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

    
219
                //---------------------------------------------------
220
                //INICIALIZACI?N DE LA INTERPRETACI?N DE COLOR
221

    
222
                //Inicializaci?n de la asignaci?n de bandas en el renderizado
223
                //Leemos el objeto metadata para obtener la interpretaci?n de color asociada al raster
224

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

    
249
        /**
250
         * Asigna un listener a la lista que ser? informado cuando cambie una
251
         * propiedad visual en la renderizaci?n.
252
         * @param listener VisualPropertyListener
253
         */
254
        public void addVisualPropertyListener(VisualPropertyListener listener) {
255
                visualPropertyListener.add(listener);
256
        }
257

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

    
291
        /*
292
         * (non-Javadoc)
293
         * @see org.gvsig.fmap.dal.coverage.grid.render.Render#drawThread(java.awt.Graphics2D, org.gvsig.fmap.dal.coverage.datastruct.ViewPortData)
294
         */
295
        public void drawThread(Graphics2D g, ViewPortData vp) {
296
                //Se dibuja si cae dentro de la vista
297
                if(util.isOutside(vp.getExtent(), dataStore.getExtent())) 
298
                        return;
299
                
300
                setReading(true);
301
                setGraphicInfo(g, vp);
302
                new Thread(this).start();
303

    
304
                while(isReading()) {
305
                        try {
306
                                Thread.sleep(50);
307
                        } catch (InterruptedException e) {
308
                                break;
309
                        }
310
                }
311
        }
312
        
313
        /*
314
         * (non-Javadoc)
315
         * @see org.gvsig.fmap.dal.coverage.grid.render.Render#draw(java.awt.Graphics2D, org.cresques.geo.ViewPortData)
316
         */
317
        public synchronized void drawTiledService(Graphics2D g, 
318
                        ViewPortData vp, 
319
                        Dimension2D viewDimension, 
320
                        TaskStatus taskStatus)
321
                throws RasterDriverException, InvalidSetViewException, ProcessInterruptedException {
322
                lastGraphics = g;
323
                lastViewPortData = vp;
324
                this.viewDimension = viewDimension;
325

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

    
364
                if(util.isOutside(vp.getExtent(), dataStore.getExtent())) {
365
                        endReading();
366
                        return null;
367
                }
368

    
369
                Extent adjustedRotedRequest = request(vp, dataStore);
370

    
371
                if ((widthImage <= 0) || (heightImage <= 0)) {
372
                        endReading();
373
                        return null;
374
                }
375

    
376
                if (dataStore == null) 
377
                        return null;
378
                
379
                Buffer buf = null; 
380
                double[] step = null;
381
                
382
                if(reprojectionOnTheFly != null) {
383
                        buf = reprojectionOnTheFly.warp(adjustedRotedRequest, 
384
                                        (int)Math.round(widthImage), 
385
                                        (int)Math.round(heightImage), 
386
                                        vp.getTime(), 
387
                                        renderBands, 
388
                                        getLastTransparency());
389
                } else {
390
                        // Asignamos la banda de transparencia si existe esta
391
                        RasterQuery query = DefaultRasterManager.getInstance().createQuery();
392
                        //query.setReadOnly(true);
393
                        query.setTaskStatus(taskStatus);
394
                        query.setTime(vp.getTime());
395
                        query.setSupersamplingLoadingBuffer(false); // Desactivamos el supersampleo en la carga del buffer.
396
                        query.setAreaOfInterest(adjustedRotedRequest, (int)Math.round(widthImage), (int)Math.round(heightImage));
397

    
398
                        if (getLastTransparency().getAlphaBandNumber() != -1) {
399
                                query.setDrawableBands(new int[] { getLastTransparency().getAlphaBandNumber()});
400
                                getLastTransparency().setAlphaBand(dataStore.query(query));
401
                        }
402
                        lastAlphaBand = getLastTransparency().getAlphaBandNumber();
403

    
404
                        query.setAreaOfInterest(adjustedRotedRequest, (int)Math.round(widthImage), (int)Math.round(heightImage));
405
                        query.setDrawableBands(getRenderBands());
406
                        buf = dataStore.query(query);
407
                        ((DefaultRasterQuery)query).setBuffer(null);
408
                        query.setSupersamplingLoadingBuffer(true);
409
                        step = dataStore.getStep();
410
                }
411

    
412
                if(drawer == null) {
413
                        init();
414
                }
415
                
416
                return drawBufferOnImage(lastGraphics, 
417
                                        lastViewPortData, 
418
                                        buf, 
419
                                        step, 
420
                                        dataStore.getAffineTransform(), 
421
                                        adjustedRotedRequest);
422
        }
423
        
424
        /*
425
         * (non-Javadoc)
426
         * @see org.gvsig.fmap.dal.coverage.grid.render.Render#draw(java.awt.Graphics2D, org.cresques.geo.ViewPortData)
427
         */
428
        private synchronized Buffer drawBufferOnImage(Graphics2D g, ViewPortData vp, Buffer buf, double[] step, AffineTransform transf, Extent adjustedRotedRequest)
429
                throws RasterDriverException, InvalidSetViewException, ProcessInterruptedException {
430
                
431
                grid = bufferPreprocessing(buf, lastTransparency);
432
                
433
                //Buffer filtrado para renderizar
434
                buf = grid.getRasterBuf();
435
                if(g == null)
436
                        return buf;
437
                drawer.setBuffer(buf); // Buffer de datos a renderizar
438
                drawer.setSupersamplingOn(step); // Desplazamiento para supersampleo
439
                drawer.setOutputSize((int)Math.round(widthImage), (int)Math.round(heightImage)); // Ancho y alto del buffer
440
                drawer.setLastTransparency(getLastTransparency());
441
                Image geoImage = drawer.drawBufferOverImageObject(); // Acci?n de renderizado
442
                drawer.dispose();
443

    
444
                // Borramos el buffer de transparencia para que siempre se tenga que regenerar.
445
                getLastTransparency().setAlphaBand(null);
446

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

    
458
                /*
459
                 * Tenemos una matriz con la transformaci?n de la coordenadas de la vista a coordenadas reales vp.mat, adem?s tenemos
460
                 * la transformaci?n de coordenadas reales a coordenadas pixel (transf). Con ambas podemos obtener una matriz de trasformacion
461
                 * entre coordenadas de la vista a coordenadas pixel (transf X vp.mat). As? obtenemos la transformaci?n entre coordenadas
462
                 * de la vista y coordenadas pixel del raster. El problema es que a cada zoom la escala de la petici?n del raster varia
463
                 * por lo que habr? que calcular una matriz con la escala (escale). escale X transf X vp.mat
464
                 */
465
                double sX = Math.abs(ulPxRequest.getX() - lrPxRequest.getX()) / widthImage;
466
                double sY = Math.abs(ulPxRequest.getY() - lrPxRequest.getY()) / heightImage;
467
                AffineTransform scale = new AffineTransform(sX, 0, 0, sY, 0, 0);
468

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

    
560
                        ImageDrawerImpl d = new ImageDrawerImpl();
561
                        d.setBuffer(buf);
562
                        d.setSupersamplingOn(null);
563
                        d.setOutputSize(buf.getWidth(), buf.getHeight());
564
                        d.setLastTransparency(getLastTransparency());
565
                        Image geoImage;
566
                        try {
567
                                geoImage = d.drawBufferOverImageObject();
568
                        } catch (ProcessInterruptedException e2) {
569
                                return;
570
                        }
571
                        d.dispose();
572
                        
573
                        lastTransparency.setAlphaBand(null);
574
                        
575
                        AffineTransform at = new AffineTransform();
576
                        at.scale(1/scaleW, 1/scaleH);
577
                        
578
                        try {
579
                                Point2D pt = new Point2D.Double(e.getULX(), e.getULY());
580
                                ((DefaultViewPortData)lastViewPortData).mat.transform(pt, pt);
581
                                at.inverseTransform(pt, pt);
582

    
583
                                lastGraphics.transform(at);
584
                                lastGraphics.drawImage(geoImage, (int) Math.round(pt.getX()), (int) Math.round(pt.getY()), null);
585
                                lastGraphics.transform(at.createInverse());
586
                                
587
                        } catch (NoninvertibleTransformException e1) {
588
                                e1.printStackTrace();
589
                        }
590
                } else {
591
                        try {
592
                                drawBufferOnImage(lastGraphics, lastViewPortData, buf, step, transf, e);
593
                        } catch (RasterDriverException e1) {
594
                                LoggerFactory.getLogger(getClass()).debug("Error loading data", e1);
595
                        } catch (InvalidSetViewException e1) {
596
                                LoggerFactory.getLogger(getClass()).debug("Invalid view", e1);
597
                        } catch (ProcessInterruptedException e1) {
598
                        }
599
                }
600
                
601
                if(!crash) { //Las im?genes de crash no se liberan ya que est?n en un hashmap global
602
                        if(buf != null)
603
                                buf.dispose();
604
                        if(transparencyBuffer != null)
605
                                transparencyBuffer.dispose();
606
                }
607
        }
608

    
609
        /**
610
         * Applies filters and transparency on the buffer and returns the grid with the modified buffer.
611
         * @param buf
612
         * @param transparency
613
         * @throws ProcessInterruptedException
614
         */
615
        private Grid bufferPreprocessing(Buffer buf, Transparency transparency) throws ProcessInterruptedException {
616
                if (dataStore != null) {
617
                        //Asignamos los datos al objeto transparencia antes de aplicar la pila de filtros para que el valor NoData sea efectivo
618
                        if (dataStore.getTransparency().getNoData().isNoDataTransparent() || transparency.existAlphaBand())
619
                                transparency.setDataBuffer(buf);
620
                        else {
621
                                transparency.setDataBuffer(null);
622
                        }
623
                        transparency.activeTransparency();
624
                } else
625
                        return null;
626

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

    
729
                        //Las pasamos a coordenadas pixel del raster
730
                        ul = ldatastore.worldToRaster(ul);
731
                        ur = ldatastore.worldToRaster(ur);
732
                        ll = ldatastore.worldToRaster(ll);
733
                        lr = ldatastore.worldToRaster(lr);
734

    
735
                        //Obtenemos los valores pixel m?ximos y m?nimos para X e Y
736
                        double pxMaxX = Math.max(Math.max(ul.getX(), ur.getX()), Math.max(ll.getX(), lr.getX()));
737
                        double pxMaxY = Math.max(Math.max(ul.getY(), ur.getY()), Math.max(ll.getY(), lr.getY()));
738
                        double pxMinX = Math.min(Math.min(ul.getX(), ur.getX()), Math.min(ll.getX(), lr.getX()));
739
                        double pxMinY = Math.min(Math.min(ul.getY(), ur.getY()), Math.min(ll.getY(), lr.getY()));
740

    
741
                        //Ajustamos las coordenadas pixel al ?rea m?xima del raster
742
                        pxMinX = Math.max(pxMinX, 0);
743
                        pxMinY = Math.max(pxMinY, 0);
744
                        pxMaxX = Math.min(pxMaxX, ldatastore.getWidth());
745
                        pxMaxY = Math.min(pxMaxY, ldatastore.getHeight());
746

    
747
                        //Petici?n en coordenadas pixel
748
                        ulPxRequest = new Point2D.Double(pxMinX, pxMinY);
749
                        lrPxRequest = new Point2D.Double(pxMaxX, pxMaxY);
750

    
751
                        //Calculamos el ancho y alto del buffer sobre el que se escribe la petici?n
752
                        widthImage = ((Math.abs(lrPxRequest.getX() - ulPxRequest.getX()) * vp
753
                                        .getWidth()) / Math.abs(pxMaxX - pxMinX));
754
                        heightImage = ((Math.abs(lrPxRequest.getY() - ulPxRequest.getY()) * vp
755
                                        .getHeight()) / Math.abs(pxMaxY - pxMinY));
756

    
757
                        //Convertimos la petici?n en coordenadas pixel a petici?n en coordenadas reales.
758
                        Point2D ulWC = ldatastore.rasterToWorld(ulPxRequest);
759
                        Point2D lrWC = ldatastore.rasterToWorld(lrPxRequest);
760

    
761
                        //Ajustamos la petici?n a los limites del raster, teniendo en cuenta la rotaci?n de este.
762
                        return new ExtentImpl(ulWC, lrWC);
763
                }
764
                Extent adjustedRotedExtent = util.calculateAdjustedView(vp.getExtent(), ldatastore.getAffineTransform(), ldatastore.getWidth(), ldatastore.getHeight());
765
                widthImage = (int)Math.round(Math.abs(adjustedRotedExtent.width() * vp.getMat().getScaleX()));
766
                heightImage = (int)Math.round(Math.abs(adjustedRotedExtent.height() * vp.getMat().getScaleY()));
767
                Point2D ul = new Point2D.Double(adjustedRotedExtent.getULX(), adjustedRotedExtent.getULY());
768
                Point2D lr = new Point2D.Double(adjustedRotedExtent.getLRX(), adjustedRotedExtent.getLRY());
769
                ul = ldatastore.worldToRaster(ul);
770
                lr = ldatastore.worldToRaster(lr);
771
                ulPxRequest = new Point2D.Double(ul.getX(), ul.getY());
772
                lrPxRequest = new Point2D.Double(lr.getX(), lr.getY());
773
                return adjustedRotedExtent;
774
        }
775

    
776
        /*
777
         * (non-Javadoc)
778
         * @see org.gvsig.fmap.dal.coverage.grid.render.Render#getRenderBands()
779
         */
780
        public int[] getRenderBands() {
781
                return renderBands;
782
        }
783
        
784
        /*
785
         * (non-Javadoc)
786
         * @see org.gvsig.fmap.dal.coverage.grid.render.Render#isRenderingAsGray()
787
         */
788
        public boolean isRenderingAsGray() {
789
                int[] renderBands = getRenderBands();
790
                if ((renderBands != null) && (renderBands.length == 3) && (renderBands[0] >= 0) &&
791
                                (renderBands[0] == renderBands[1]) && (renderBands[1] == renderBands[2]))
792
                        return true;
793
                return false;
794
        }
795

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

    
826
        /**
827
         * Dado que la notaci?n de bandas para renderizado admite posiciones con -1 y la notaci?n del
828
         * buffer no ya que no tendria sentido. Esta funci?n adapta la primera notaci?n a la segunda
829
         * para realizar la petici?n setAreaOfInterest y cargar el buffer.
830
         * @param b Array que indica la posici?n de bandas para el renderizado
831
         * @return Array que indica la posici?n de bandas para la petici?n
832
         */
833
        public int[] formatArrayRenderBand(int[] b) {
834
                int cont = 0;
835
                for(int i = 0; i < b.length; i++)
836
                        if(b[i] >= 0)
837
                                cont ++;
838
                if(cont <= 0)
839
                        return null;
840
                int[] out = new int[cont];
841
                int pos = 0;
842
                for(int i = 0; i < cont; i++) {
843
                        while(b[pos] == -1)
844
                                pos ++;
845
                        out[i] = b[pos];
846
                        pos ++;
847
                }
848
                return out;
849
        }
850

    
851
        public Transparency getLastTransparency() {
852
                //If the transparency hasn't been defined yet then we'll take that from the store
853
                if (lastTransparency == null) {
854
                        lastTransparency = dataStore.getTransparency().cloneTransparency();
855
                        lastTransparency.addPropertyListener(this);
856
                }
857
                return lastTransparency;
858
        }
859
        
860
        /*
861
         * (non-Javadoc)
862
         * @see org.gvsig.fmap.dal.coverage.grid.render.Render#getLastAlphaBandNumber()
863
         */
864
        public int getLastAlphaBandNumber() {
865
                return lastAlphaBand;
866
        }
867

    
868
        /*
869
         * (non-Javadoc)
870
         * @see org.gvsig.fmap.dal.coverage.grid.render.Render#setLastTransparency(org.gvsig.fmap.dal.coverage.store.props.Transparency)
871
         */
872
        public void setLastTransparency(Transparency lastTransparency) {
873
                this.lastTransparency = lastTransparency;
874
                if(this.lastTransparency != null)
875
                        this.lastTransparency.addPropertyListener(this);
876
        }
877

    
878
        /*
879
         * (non-Javadoc)
880
         * @see org.gvsig.fmap.dal.coverage.grid.Render#getFilterList()
881
         */
882
        public RasterFilterList getFilterList() {
883
                return filterList;
884
        }
885

    
886
        /*
887
         * (non-Javadoc)
888
         * @see org.gvsig.fmap.dal.coverage.grid.render.Render#setFilterList(org.gvsig.fmap.dal.coverage.grid.RasterFilterList)
889
         */
890
        public void setFilterList(RasterFilterList filterList) {
891
                this.filterList = filterList;
892
                this.filterList.addFilterListListener(this);
893
        }
894

    
895
        /*
896
         * (non-Javadoc)
897
         * @see org.gvsig.fmap.dal.coverage.grid.render.Render#existColorTable()
898
         */
899
        public boolean existColorTable() {
900
                        return (filterList.getFilterByBaseClass(ColorTableFilter.class) != null);
901
        }
902
        
903
        /*
904
         * (non-Javadoc)
905
         * @see org.gvsig.fmap.dal.coverage.grid.render.Render#getColorTable()
906
         */
907
        public ColorTable getColorTable() {
908
                if(existColorTable()) {
909
                        RasterFilter f = filterList.getFilterByBaseClass(ColorTableFilter.class);
910
                        return ((ColorTableFilter)f).getColorTable();
911
                }
912
                return null;
913
        }
914

    
915
        /**
916
         * Obtiene el grid asociado al render
917
         * @return
918
         */
919
        public Grid getGrid() {
920
                return grid;
921
        }
922

    
923
        /**
924
         * Asigna la factoria de buffer del renderizador
925
         * @param bf
926
         */
927
        public void setDataSource(RasterDataStore ds) {
928
                this.dataStore = ds;
929
        }
930

    
931
        /**
932
         * Evento activado cuando cambia una propiedad de transparencia.
933
         */
934
        public void actionValueChanged(PropertyEvent e) {
935
                callVisualPropertyChanged(new VisualPropertyEvent(e.getSource()));
936
        }
937

    
938
        /**
939
         * Evento activado cuando cambia la lista de filtros.
940
         */
941
        public void filterListChanged(FilterListChangeEvent e) {
942
                callVisualPropertyChanged(new VisualPropertyEvent(e.getSource()));
943
        }
944

    
945
        /*
946
         * (non-Javadoc)
947
         * @see org.gvsig.tools.persistence.Persistent#loadFromState(org.gvsig.tools.persistence.PersistentState)
948
         */
949
        public void loadFromState(PersistentState state)
950
                        throws PersistenceException {
951
                lastTransparency = (Transparency)state.get("lastTransparency");        
952
                renderBands = (int[])state.getIntArray("renderBands");
953
                //setFilterList((RasterFilterList)state.get("filterList"));
954
        }
955

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

    
1020
}