Statistics
| Revision:

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

History | View | Annotate | Download (34.5 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
import java.util.List;
32

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

    
113
        private ImageDrawerImpl  drawer                    = null;
114
        
115
        /**
116
         * 
117
         */
118
        private Transparency     renderingTransparency     = null;
119
        private int              lastAlphaBand             = -1;
120
        
121
        /**
122
         * Lista de filtros aplicada en la renderizaci?n
123
         */
124
        private RasterFilterList filterList               = null;
125

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

    
132
        private Point2D          ulPxRequest, lrPxRequest;
133

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

    
192
        private void init() {
193
                if(dataStore == null || dataStore.getDataType() == null)
194
                        return;
195

    
196
                drawer = new ImageDrawerImpl();
197
                getRenderColorInterpretation();
198
        }
199

    
200
        /**
201
         * Asigna un listener a la lista que ser? informado cuando cambie una
202
         * propiedad visual en la renderizaci?n.
203
         * @param listener VisualPropertyListener
204
         */
205
        public void addVisualPropertyListener(VisualPropertyListener listener) {
206
                visualPropertyListener.add(listener);
207
        }
208

    
209
        /**
210
         * M?todo llamado cuando hay un cambio en una propiedad de visualizaci?n
211
         */
212
        private void callVisualPropertyChanged(Object obj) {
213
                if(visualPropertyListener != null) {
214
                        for (int i = 0; i < visualPropertyListener.size(); i++) {
215
                                VisualPropertyEvent ev = new VisualPropertyEvent(obj);
216
                                ((VisualPropertyListener)visualPropertyListener.get(i)).visualPropertyValueChanged(ev);
217
                        }
218
                }
219
        }
220
        
221
        /**
222
         * Thread de dibujado
223
         */
224
        public void run() {
225
                try {
226
                        draw(lastGraphics, lastViewPortData, null);
227
                } catch (QueryException e) {
228
                        LoggerFactory.getLogger(getClass()).debug("Error in a query", e);
229
                } catch (ProcessInterruptedException e) {
230
                }
231
        }
232
        
233
        public void setGraphicInfo(Graphics2D g, ViewPortData vp) {
234
                this.lastGraphics = g;
235
                this.lastViewPortData = vp;
236
        }
237

    
238
        public void drawThread(Graphics2D g, ViewPortData vp) {
239
                //Se dibuja si cae dentro de la vista
240
                if(util.isOutside(vp.getExtent(), dataStore.getExtent())) 
241
                        return;
242
                
243
                setReading(true);
244
                setGraphicInfo(g, vp);
245
                new Thread(this).start();
246

    
247
                while(isReading()) {
248
                        try {
249
                                Thread.sleep(50);
250
                        } catch (InterruptedException e) {
251
                                break;
252
                        }
253
                }
254
        }
255
        
256
        public synchronized Buffer getLastRenderBuffer() 
257
                throws QueryException, ProcessInterruptedException {
258
                return draw(null, lastViewPortData, null);
259
        }
260
        
261
        public synchronized void drawTiledService(Graphics2D g, 
262
                        ViewPortData vp, 
263
                        Dimension2D viewDimension, 
264
                        TaskStatus taskStatus)
265
                throws QueryException, ProcessInterruptedException {
266
                lastGraphics = g;
267
                lastViewPortData = vp;
268
                this.viewDimension = viewDimension;
269
                int[] renderBands = getRenderColorInterpretation().buildRenderBands();
270
                
271
                if(util.isOutside(vp.getExtent(), dataStore.getExtent())) {
272
                        endReading();
273
                        return;
274
                }
275
                
276
                if (dataStore != null) {
277
                        lastAlphaBand = getRenderingTransparency().getAlphaBandNumber();
278
                        
279
                        // Asignamos la banda de transparencia si existe esta
280
                        RasterQuery query = getRasterManager().createQuery();
281
                        query.setTaskStatus(taskStatus);
282
                        query.setTime(vp.getTime());
283
                        query.setSupersamplingOption(false); // Desactivamos el supersampleo en la carga del buffer.
284
                        if(dataStore.getColorInterpretation().isRGB())
285
                                renderBands[3] = 3;
286
                        query.setDrawableBands(renderBands);
287
                        if(dataStore.getDataType()[0] == Buffer.TYPE_BYTE) {
288
                                if(lastAlphaBand != -1)
289
                                        query.forceARGBRequest();
290
                                else if(renderBands.length == 3 || (renderBands.length == 4 && renderBands[3] == -1))
291
                                        query.forceRGBRequest();
292
                                else
293
                                        query.forceARGBRequest();
294
                        } else
295
                                query.forceRGBRequest();
296
                        query.setAreaOfInterest(vp.getExtent(), 
297
                                        (int)Math.round(vp.getWidth()), 
298
                                        (int)Math.round(vp.getHeight()), this);
299
                        dataStore.query(query);
300
                        query.setSupersamplingOption(true);
301
                } else
302
                        return;
303
        }
304
        
305
        public synchronized void tileReady(Tile loadedTile) throws TileGettingException {
306
                boolean crash = false;
307
                Boolean tiling = (Boolean)loadedTile.getDownloaderParams("Tiling");
308
                double[] step = (double[])loadedTile.getDownloaderParams("Step");
309
                AffineTransform transf = (AffineTransform)loadedTile.getDownloaderParams("AffineTransform");
310
                
311
                Extent e = getRasterManager().getDataStructFactory().
312
                createExtent(loadedTile.getUl().getX(), 
313
                                loadedTile.getUl().getY(), 
314
                                loadedTile.getLr().getX(), 
315
                                loadedTile.getLr().getY());
316
                
317
                Buffer buf = (loadedTile.getData() != null && loadedTile.getData().length > 0) ? (Buffer)loadedTile.getData()[0] : null;
318
                
319
                if(!loadedTile.dataIsLoaded()) {
320
                        if(loadedTile.getCrashARGB() == null)
321
                                return;
322
                        crash = true;
323
                        buf = (Buffer)loadedTile.getCrashARGB();
324
                } else {
325
                        if(buf == null)
326
                                return;
327
                        ColorTable tileColorTable = (loadedTile.getData() != null && loadedTile.getData().length > 2) ? (ColorTable)loadedTile.getData()[2] : null;
328
                        if(tiling == null || tiling.booleanValue()) {
329
                                if(filterList != null) 
330
                                        addTileColorTable(tileColorTable);
331
                        }
332
                }
333
                buf.setDataExtent(e.toRectangle2D());
334
                
335
                Transparency transparencyProcessed = null;
336
                if(tiling == null || tiling.booleanValue()) {
337
                        try {
338
                                FilterLoader filterLoader = bufferPreprocessing(buf);
339
                                transparencyProcessed = filterLoader.getTransparency();
340
                                buf = filterLoader.getBufferResult();
341
                        } catch (ProcessInterruptedException e3) {
342
                                return;
343
                        }
344
                }
345

    
346
                if(tiling == null || tiling.booleanValue()) {
347
                        //Reescalado de los tiles. El tama?o en pixels de un tile no tiene pq coincidir con el de la vista.
348
                        double w = lastViewPortData.getWidth();
349
                        double h = lastViewPortData.getHeight();
350
                        if(viewDimension != null) {
351
                                w = viewDimension.getWidth();
352
                                h = viewDimension.getHeight();
353
                        }
354
                        double viewScaleW = lastViewPortData.getExtent().width() / w;
355
                        double tileScaleW = e.width() / (double)buf.getWidth();
356
                        double scaleW = viewScaleW / tileScaleW;
357
                        double viewScaleH = lastViewPortData.getExtent().height() / h;
358
                        double tileScaleH = e.height() / (double)buf.getHeight();
359
                        double scaleH = viewScaleH / tileScaleH;
360

    
361
                        ImageDrawerImpl d = new ImageDrawerImpl();
362
                        d.setBuffer(buf);
363
                        d.setSupersamplingOn(null);
364
                        d.setOutputSize(buf.getWidth(), buf.getHeight());
365
                        d.setLastTransparency(transparencyProcessed);
366
                        Image geoImage;
367
                        try {
368
                                geoImage = d.drawBufferOverImageObject();
369
                        } catch (ProcessInterruptedException e2) {
370
                                return;
371
                        }
372
                        d.dispose();
373
                        
374
                        AffineTransform at = new AffineTransform();
375
                        at.scale(1 / scaleW, 1 / scaleH);
376
                        
377
                        try {
378
                                Point2D pt = new Point2D.Double(e.getULX(), e.getULY());
379
                                ((DefaultViewPortData)lastViewPortData).mat.transform(pt, pt);
380
                                at.inverseTransform(pt, pt);
381

    
382
                                lastGraphics.transform(at);
383
                                lastGraphics.drawImage(geoImage, (int) Math.round(pt.getX()), (int) Math.round(pt.getY()), null);
384
                                lastGraphics.transform(at.createInverse());
385
                                geoImage.flush();
386
                        } catch (NoninvertibleTransformException e1) {
387
                                e1.printStackTrace();
388
                        }
389
                } else {
390
                        try {
391
                                drawBufferOnImage(lastGraphics, lastViewPortData, buf, step, transf, e);
392
                        } catch (QueryException e1) {
393
                                LoggerFactory.getLogger(getClass()).debug("Error loading data", e1);
394
                        } catch (ProcessInterruptedException e1) {
395
                        }
396
                }
397
                
398
                if(!crash) { //Las im?genes de crash no se liberan ya que est?n en un hashmap global
399
                        if(buf != null)
400
                                buf.dispose();
401
                }
402
        }
403
        
404
        public synchronized Buffer draw(Graphics2D g, ViewPortData vp, TaskStatus taskStatus)
405
                throws QueryException, ProcessInterruptedException {
406
                lastGraphics = g;
407
                lastViewPortData = vp;
408

    
409
                if(util.isOutside(vp.getExtent(), dataStore.getExtent())) {
410
                        endReading();
411
                        return null;
412
                }
413

    
414
                Extent adjustedRotedRequest = request(vp, dataStore);
415

    
416
                if ((widthImage <= 0) || (heightImage <= 0)) {
417
                        endReading();
418
                        return null;
419
                }
420

    
421
                if (dataStore == null) 
422
                        return null;
423
                
424
                Buffer buf = null; 
425
                double[] step = null;
426
                int[] renderBands = getRenderColorInterpretation().buildRenderBands();
427
                
428
                if(reprojectionOnTheFly != null) {
429
                        buf = reprojectionOnTheFly.warp(adjustedRotedRequest, 
430
                                        (int)Math.round(widthImage), 
431
                                        (int)Math.round(heightImage), 
432
                                        vp.getTime(), 
433
                                        renderBands, 
434
                                        getRenderingTransparency());
435
                } else {
436
                        lastAlphaBand = getRenderingTransparency().getAlphaBandNumber();
437

    
438
                        RasterQuery query = getRasterManager().createQuery();
439
                        query.setTaskStatus(taskStatus);
440
                        query.setTime(vp.getTime());
441
                        query.setAreaOfInterest(adjustedRotedRequest, (int)Math.round(widthImage), (int)Math.round(heightImage));
442
                        query.setDrawableBands(renderBands);
443
                        if(dataStore.getDataType()[0] == Buffer.TYPE_BYTE) {
444
                                if(lastAlphaBand != -1)
445
                                        query.forceARGBRequest();
446
                                else if(renderBands.length == 3 || (renderBands.length == 4 && renderBands[3] == -1))
447
                                        query.forceRGBRequest();
448
                        } else {
449
                                if(renderBands.length == 4 && renderBands[3] != -1)
450
                                        query.forceARGBRequest();
451
                                else
452
                                        query.forceRGBRequest();
453
                        }
454
                        buf = dataStore.query(query);
455
                        step = query.getStep();
456
                }
457

    
458
                if(drawer == null) {
459
                        init();
460
                }
461
                
462
                return drawBufferOnImage(lastGraphics, 
463
                                        lastViewPortData, 
464
                                        buf, 
465
                                        step, 
466
                                        dataStore.getAffineTransform(), 
467
                                        adjustedRotedRequest);
468
        }
469
        
470
        private synchronized Buffer drawBufferOnImage(Graphics2D g, ViewPortData vp, Buffer buf, double[] step, AffineTransform transf, Extent adjustedRotedRequest)
471
                throws QueryException, ProcessInterruptedException {
472
                FilterLoader filterLoader = bufferPreprocessing(buf);
473
                Transparency transparencyProcessed = filterLoader.getTransparency(); 
474
                buf = filterLoader.getBufferResult();
475
                
476
                if(g == null)
477
                        return buf;
478
                
479
                drawer.setBuffer(buf); // Buffer de datos a renderizar
480
                drawer.setSupersamplingOn(step); // Desplazamiento para supersampleo
481
                drawer.setOutputSize((int)Math.round(widthImage), (int)Math.round(heightImage)); // Ancho y alto del buffer
482
                drawer.setLastTransparency(transparencyProcessed);
483
                Image geoImage = drawer.drawBufferOverImageObject(); // Acci?n de renderizado
484
                drawer.dispose();
485
                
486
                //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
487
                //transformaci?n. Esto no es necesario hacerlo, sin ello se visualiza igual. Unicamente se hace porque de esta
488
                //forma el raster resultante mejora un poco en calidad en ciertos niveles de zoom ya que al aplicar transformaciones
489
                //sobre el Graphics parece que pierde algo de calidad.
490
                if(transf.getScaleX() > 0 && transf.getScaleY() < 0 && transf.getShearX() == 0 && transf.getShearY() == 0) {
491
                        Point2D lastGraphicOffset = new Point2D.Double(adjustedRotedRequest.getULX(), adjustedRotedRequest.getULY());
492
                        ((DefaultViewPortData)vp).mat.transform(lastGraphicOffset, lastGraphicOffset);
493
                        g.drawImage(geoImage, (int) Math.round(lastGraphicOffset.getX()), (int) Math.round(lastGraphicOffset.getY()), null);
494
                        return buf;
495
                }
496

    
497
                /*
498
                 * Tenemos una matriz con la transformaci?n de la coordenadas de la vista a coordenadas reales vp.mat, adem?s tenemos
499
                 * la transformaci?n de coordenadas reales a coordenadas pixel (transf). Con ambas podemos obtener una matriz de trasformacion
500
                 * entre coordenadas de la vista a coordenadas pixel (transf X vp.mat). As? obtenemos la transformaci?n entre coordenadas
501
                 * de la vista y coordenadas pixel del raster. El problema es que a cada zoom la escala de la petici?n del raster varia
502
                 * por lo que habr? que calcular una matriz con la escala (escale). escale X transf X vp.mat
503
                 */
504
                double sX = Math.abs(ulPxRequest.getX() - lrPxRequest.getX()) / widthImage;
505
                double sY = Math.abs(ulPxRequest.getY() - lrPxRequest.getY()) / heightImage;
506
                AffineTransform scale = new AffineTransform(sX, 0, 0, sY, 0, 0);
507

    
508
                try {
509
                        AffineTransform at = (AffineTransform)scale.clone();
510
                        at.preConcatenate(transf);
511
                        at.preConcatenate(vp.getMat());
512
                        g.transform(at);
513
                        Point2D.Double pt = null;
514
                        //El punto sobre el que rota la imagen depende del signo de los tama?os del pixel
515
                        if(transf.getScaleX() < 0 && transf.getScaleY() < 0)
516
                                pt = new Point2D.Double(adjustedRotedRequest.maxX(), adjustedRotedRequest.maxY());
517
                        else if(transf.getScaleX() > 0 && transf.getScaleY() > 0)
518
                                pt = new Point2D.Double(adjustedRotedRequest.minX(), adjustedRotedRequest.minY());
519
                        else if(transf.getScaleX() < 0 && transf.getScaleY() > 0)
520
                                pt = new Point2D.Double(adjustedRotedRequest.maxX(), adjustedRotedRequest.minY());
521
                        else
522
                                pt = new Point2D.Double(adjustedRotedRequest.getULX(), adjustedRotedRequest.getULY());
523
                        vp.getMat().transform(pt, pt);
524
                        at.inverseTransform(pt, pt);
525
                        g.drawImage(geoImage, (int) Math.round(pt.getX()), (int) Math.round(pt.getY()), null);
526
                        g.transform(at.createInverse());
527
                        geoImage.flush();
528
                } catch (NoninvertibleTransformException e) {
529
                        LoggerFactory.getLogger(getClass()).debug("Transformation error", e);
530
                }
531
                
532
                return buf;
533
                // long t2 = new Date().getTime();
534
                // System.out.println("Renderizando Raster: " + ((t2 - t1) / 1000D) + ", secs.");
535
        }
536
        
537
        /**
538
         * Applies filters and transparency on the buffer and returns the grid with the modified buffer.
539
         * @param buf
540
         * @param transparency
541
         * @throws ProcessInterruptedException
542
         */
543
        private FilterLoader bufferPreprocessing(Buffer buf) throws ProcessInterruptedException {
544
                //Asignamos los datos al objeto transparencia antes de aplicar la pila de filtros para que el valor NoData sea efectivo
545
                if (getRenderingTransparency().getNoData().isNoDataTransparent() || 
546
                                getRenderingTransparency().existAlphaBand())
547
                        getRenderingTransparency().setDataBuffer(buf);
548
                else {
549
                        getRenderingTransparency().setDataBuffer(null);
550
                }
551
                getRenderingTransparency().activeTransparency();
552
                List<ROI> roi = null;
553
                try {
554
                        roi = (List<ROI>)dataStore.getRois(lastViewPortData != null ? lastViewPortData.getProjection() : null);
555
                } catch (ROIException e) {
556
                }
557
                
558
                FilterLoader filterLoader = RasterLocator.getManager().createFilterLoader(filterList);
559
                filterLoader.addSrcBandCount(dataStore.getBandCount());
560
                filterLoader.addSrcDataType(dataStore.getDataType()[0]);
561
                filterLoader.addSrcStatistics(dataStore.getStatistics());
562
                filterLoader.addSrcROI(roi);
563
                filterLoader.addSrcHistogram(dataStore.getHistogramComputer());
564
                filterLoader.addTransparency(getRenderingTransparency());
565
                filterLoader.applyFilters(buf);
566

    
567
                return filterLoader;
568
        }
569

    
570
        /**
571
         * When tiles are renderized the color table in each tile could be diferent.
572
         * In this case the color table must be replaced
573
         */
574
        //@deprecated one color table by tiled layer
575
        private void addTileColorTable(ColorTable tileColorTable) {
576
                if(tileColorTable == null)
577
                        return;
578
                else {
579
                        if(filterList.getFilterClassByID("ColorTable") == null) {
580
                                try {
581
                                        RasterFilterListManager colorTableManager = filterList.getManagerByID("ColorTable");
582
                                        Params params = filterList.createEmptyFilterParams();
583
                                        params.setParam("colorTable", tileColorTable);
584
                                        colorTableManager.addFilter(params);
585
                                } catch (FilterManagerException e) {
586
                                        e.printStackTrace();
587
                                } catch (FilterTypeException e) {
588
                                        e.printStackTrace();
589
                                }
590
                        }
591
                }
592
        }
593
        
594
        public void endReading() {
595
                isDrawing = false;
596
        }
597
        
598
        public boolean isReading() {
599
                return isDrawing;
600
        }
601
        
602
        public void setReading(boolean reading) {
603
                isDrawing = reading;
604
        }
605
        
606
        /**
607
         * Calculamos la petici?n en coordenadas del mundo real con la transformaci?n del raster. Esto
608
         * permite obtener las coordenadas de la petici?n con la rotaci?n, si la tiene.
609
         * @param vp
610
         * @param ldatastore
611
         * @return
612
         */
613
        private Extent request(ViewPortData vp, RasterDataStore ldatastore) {
614
                if (ldatastore.isRotated()) {
615
                        //Obtenemos las cuatro esquinas de la selecci?n que hemos hecho en la vista
616
                        Point2D ul = new Point2D.Double(vp.getExtent().minX(), vp.getExtent().maxY());
617
                        Point2D ur = new Point2D.Double(vp.getExtent().maxX(), vp.getExtent().maxY());
618
                        Point2D ll = new Point2D.Double(vp.getExtent().minX(), vp.getExtent().minY());
619
                        Point2D lr = new Point2D.Double(vp.getExtent().maxX(), vp.getExtent().minY());
620

    
621
                        //Las pasamos a coordenadas pixel del raster
622
                        ul = ldatastore.worldToRaster(ul);
623
                        ur = ldatastore.worldToRaster(ur);
624
                        ll = ldatastore.worldToRaster(ll);
625
                        lr = ldatastore.worldToRaster(lr);
626

    
627
                        //Obtenemos los valores pixel m?ximos y m?nimos para X e Y
628
                        double pxMaxX = Math.max(Math.max(ul.getX(), ur.getX()), Math.max(ll.getX(), lr.getX()));
629
                        double pxMaxY = Math.max(Math.max(ul.getY(), ur.getY()), Math.max(ll.getY(), lr.getY()));
630
                        double pxMinX = Math.min(Math.min(ul.getX(), ur.getX()), Math.min(ll.getX(), lr.getX()));
631
                        double pxMinY = Math.min(Math.min(ul.getY(), ur.getY()), Math.min(ll.getY(), lr.getY()));
632

    
633
                        //Ajustamos las coordenadas pixel al ?rea m?xima del raster
634
                        pxMinX = Math.max(pxMinX, 0);
635
                        pxMinY = Math.max(pxMinY, 0);
636
                        pxMaxX = Math.min(pxMaxX, ldatastore.getWidth());
637
                        pxMaxY = Math.min(pxMaxY, ldatastore.getHeight());
638

    
639
                        //Petici?n en coordenadas pixel
640
                        ulPxRequest = new Point2D.Double(pxMinX, pxMinY);
641
                        lrPxRequest = new Point2D.Double(pxMaxX, pxMaxY);
642

    
643
                        //Calculamos el ancho y alto del buffer sobre el que se escribe la petici?n
644
                        widthImage = ((Math.abs(lrPxRequest.getX() - ulPxRequest.getX()) * vp
645
                                        .getWidth()) / Math.abs(pxMaxX - pxMinX));
646
                        heightImage = ((Math.abs(lrPxRequest.getY() - ulPxRequest.getY()) * vp
647
                                        .getHeight()) / Math.abs(pxMaxY - pxMinY));
648

    
649
                        //Convertimos la petici?n en coordenadas pixel a petici?n en coordenadas reales.
650
                        Point2D ulWC = ldatastore.rasterToWorld(ulPxRequest);
651
                        Point2D lrWC = ldatastore.rasterToWorld(lrPxRequest);
652

    
653
                        //Ajustamos la petici?n a los limites del raster, teniendo en cuenta la rotaci?n de este.
654
                        return new ExtentImpl(ulWC, lrWC);
655
                }
656
                Extent adjustedRotedExtent = util.calculateAdjustedView(vp.getExtent(), ldatastore.getAffineTransform(), ldatastore.getWidth(), ldatastore.getHeight());
657
                widthImage = (int)Math.round(Math.abs(adjustedRotedExtent.width() * vp.getMat().getScaleX()));
658
                heightImage = (int)Math.round(Math.abs(adjustedRotedExtent.height() * vp.getMat().getScaleY()));
659
                Point2D ul = new Point2D.Double(adjustedRotedExtent.getULX(), adjustedRotedExtent.getULY());
660
                Point2D lr = new Point2D.Double(adjustedRotedExtent.getLRX(), adjustedRotedExtent.getLRY());
661
                ul = ldatastore.worldToRaster(ul);
662
                lr = ldatastore.worldToRaster(lr);
663
                ulPxRequest = new Point2D.Double(ul.getX(), ul.getY());
664
                lrPxRequest = new Point2D.Double(lr.getX(), lr.getY());
665
                return adjustedRotedExtent;
666
        }
667

    
668
        public boolean isRenderingAsGray() {
669
                int[] renderBands = getRenderColorInterpretation().buildRenderBands();
670
                if ((renderBands != null) && (renderBands.length == 3 || renderBands.length == 4) && (renderBands[0] >= 0) &&
671
                                (renderBands[0] == renderBands[1]) && (renderBands[1] == renderBands[2]))
672
                        return true;
673
                return false;
674
        }
675
        
676
        public void setRenderColorInterpretation(ColorInterpretation ci) {
677
                this.renderColorInterpretation = ci;
678
        }
679
        
680
        public ColorInterpretation getRenderColorInterpretation() {
681
                if(renderColorInterpretation == null) {
682
                        //Initializes the color interpretation using the source but if the source does not have
683
                        //it will be figure out depending on the number of bands
684
                        renderColorInterpretation = dataStore.getColorInterpretation();
685
                        if(renderColorInterpretation == null || !renderColorInterpretation.hasInterpretation()) {
686
                                switch (dataStore.getBandCount()) {
687
                                case 1:
688
                                case 2:
689
                                        renderColorInterpretation = DataStoreColorInterpretation.createGrayInterpretation();
690
                                        break;
691
                                case 3:
692
                                        renderColorInterpretation = DataStoreColorInterpretation.createRGBInterpretation();
693
                                        break;
694
                                case 4:
695
                                        renderColorInterpretation = DataStoreColorInterpretation.createRGBAInterpretation();
696
                                default:
697
                                        renderColorInterpretation = DataStoreColorInterpretation.createRGBInterpretation();
698
                                        break;
699
                                }        
700
                        } else
701
                                renderColorInterpretation = dataStore.getColorInterpretation().cloneColorInterpretation();
702
                }
703
                return renderColorInterpretation;
704
        }
705
        
706
        /**
707
                 * Asigna el n?mero de bandas y el orden de renderizado. Cada posici?n del vector es una banda
708
         * del buffer y el contenido de esa posici?n es la banda de la imagen que se dibujar?
709
         * sobre ese buffer. A la hora de renderizar hay que tener en cuenta que solo se renderizan las
710
         * tres primeras bandas del buffer por lo que solo se tienen en cuenta los tres primeros
711
         * elementos. Por ejemplo, el array {1, 0, 3} dibujar? sobre el Graphics las bandas 1,0 y 3 de un
712
         * raster que tiene al menos 4 bandas. La notaci?n con -1 en alguna posici?n del vector solo tiene sentido
713
         * en la visualizaci?n pero no se puede as?gnar una banda del buffer a null.
714
         * Algunos ejemplos:
715
         * <P>
716
         * {-1, 0, -1} Dibuja la banda 0 del raster en la G de la visualizaci?n.
717
         * Si replicateBand es true R = G = B sino R = B = 0
718
         * {1, 0, 3} La R = banda 1 del raster, G = 0 y B = 3
719
         * {0} La R = banda 0 del raster. Si replicateBand es true R = G = B sino G = B = 0
720
         * </P>
721
         *
722
         *
723
                 * @param renderBands: bandas y su posici?n
724
                 */
725
        /*public void setRenderBands(int[] renderBands) {
726
                if(        renderBands[0] != this.renderBands[0] ||
727
                        renderBands[1] != this.renderBands[1] ||
728
                        renderBands[2] != this.renderBands[2] ||
729
                        renderBands[3] != this.renderBands[3])
730
                        callVisualPropertyChanged(renderBands);
731
                
732
                this.renderBands = renderBands;
733
                if (filterList != null)
734
                        for (int i = 0; i < filterList.lenght(); i++)
735
                                (filterList.get(i)).addParam("renderBands", renderBands);
736
        }
737
        
738
        public int[] getRenderBands() {
739
                return renderBands;
740
        }*/
741

    
742
        /**
743
         * Dado que la notaci?n de bandas para renderizado admite posiciones con -1 y la notaci?n del
744
         * buffer no ya que no tendria sentido. Esta funci?n adapta la primera notaci?n a la segunda
745
         * para realizar la petici?n setAreaOfInterest y cargar el buffer.
746
         * @param b Array que indica la posici?n de bandas para el renderizado
747
         * @return Array que indica la posici?n de bandas para la petici?n
748
         */
749
        public int[] formatArrayRenderBand(int[] b) {
750
                int cont = 0;
751
                for(int i = 0; i < b.length; i++)
752
                        if(b[i] >= 0)
753
                                cont ++;
754
                if(cont <= 0)
755
                        return null;
756
                int[] out = new int[cont];
757
                int pos = 0;
758
                for(int i = 0; i < cont; i++) {
759
                        while(b[pos] == -1)
760
                                pos ++;
761
                        out[i] = b[pos];
762
                        pos ++;
763
                }
764
                return out;
765
        }
766

    
767
        public Transparency getRenderingTransparency() {
768
                //If the transparency hasn't been defined yet then we'll take that from the store
769
                if (renderingTransparency == null) {
770
                        renderingTransparency = dataStore.getTransparency().cloneTransparency();
771
                        renderingTransparency.addPropertyListener(this);
772
                }
773
                renderingTransparency.setColorInterpretation(getRenderColorInterpretation());
774
                return renderingTransparency;
775
        }
776
        
777
        public int getLastAlphaBandNumber() {
778
                return lastAlphaBand;
779
        }
780

    
781
        public void setLastTransparency(Transparency lastTransparency) {
782
                this.renderingTransparency = lastTransparency;
783
                if(this.renderingTransparency != null)
784
                        this.renderingTransparency.addPropertyListener(this);
785
        }
786

    
787
        public RasterFilterList getFilterList() {
788
                return filterList;
789
        }
790

    
791
        public void setFilterList(RasterFilterList filterList) {
792
                this.filterList = filterList;
793
                this.filterList.addFilterListListener(this);
794
        }
795

    
796
        public boolean existColorTable() {
797
                        return (filterList.getFilterByBaseClass(ColorTableFilter.class) != null);
798
        }
799
        
800
        public ColorTable getColorTable() {
801
                if(existColorTable()) {
802
                        RasterFilter f = filterList.getFilterByBaseClass(ColorTableFilter.class);
803
                        return ((ColorTableFilter)f).getColorTable();
804
                }
805
                return null;
806
        }
807

    
808
        /**
809
         * Asigna la factoria de buffer del renderizador
810
         * @param bf
811
         */
812
        public void setDataSource(RasterDataStore ds) {
813
                this.dataStore = ds;
814
        }
815

    
816
        /**
817
         * Evento activado cuando cambia una propiedad de transparencia.
818
         */
819
        public void actionValueChanged(PropertyEvent e) {
820
                callVisualPropertyChanged(new VisualPropertyEvent(e.getSource()));
821
        }
822

    
823
        /**
824
         * Evento activado cuando cambia la lista de filtros.
825
         */
826
        public void filterListChanged(FilterListChangeEvent e) {
827
                callVisualPropertyChanged(new VisualPropertyEvent(e.getSource()));
828
        }
829
        
830
        /**
831
         * Sets buffers to null
832
         */
833
        public void dispose() {
834
                if (renderingTransparency != null)
835
                        renderingTransparency.dispose();
836
                if (getFilterList() != null)
837
                        getFilterList().dispose();
838
                try {
839
                        finalize();
840
                } catch (Throwable e) {
841
                }
842
        }
843
        
844
        protected void finalize() throws Throwable {
845
                dataStore                = null;
846
        drawer                   = null;
847
                renderingTransparency    = null;
848
                filterList               = null;
849
        ulPxRequest              = null;
850
        lrPxRequest              = null;
851
                lastGraphics             = null;
852
                lastViewPortData         = null;
853
                viewDimension            = null;
854
                
855
                if(visualPropertyListener != null) {
856
                        visualPropertyListener.clear();
857
                        visualPropertyListener = null;
858
                }
859
                super.finalize();
860
        }
861

    
862
        //******************************
863
        //Persistence
864
        //******************************
865

    
866
        public static void registerPersistence() {
867
                PersistenceManager manager = ToolsLocator.getPersistenceManager();
868
                DynStruct definition = manager.getDefinition("DefaultRender_Persistent");
869
                if( definition == null ) {
870
                        definition = manager.addDefinition(
871
                                        DefaultRender.class,
872
                                        "DefaultRender_Persistent",
873
                                        "RasterRendering Persistent definition",
874
                                        null, 
875
                                        null
876
                                        );
877

    
878
                        definition.addDynFieldObject("lastTransparency")
879
                        .setClassOfValue(Transparency.class)
880
                        .setMandatory(false);
881

    
882
                        definition.addDynFieldObject("filterList")
883
                        .setClassOfValue(RasterFilterList.class)
884
                        .setMandatory(false);
885

    
886
                        definition.addDynFieldList("paramlist")
887
                        .setClassOfItems(PersistencyFilterParams.class)
888
                        .setMandatory(false);
889
                }
890
        }
891

    
892
        private List<PersistencyFilterParams> listFilterParameters = null;
893
                        
894
        @SuppressWarnings("unchecked")
895
        public void loadFromState(PersistentState state)
896
                        throws PersistenceException {
897
                renderingTransparency = (Transparency)state.get("lastTransparency");        
898
                renderColorInterpretation = renderingTransparency.getColorInterpretation();
899
                filterList = (RasterFilterList)state.get("filterList");
900
                listFilterParameters = state.getList("paramlist");
901
        }
902

    
903
        public void saveToState(PersistentState state) throws PersistenceException {
904
                state.set("lastTransparency", getRenderingTransparency());
905
                state.set("filterList", getFilterList());
906
                state.set("paramlist", buildPersistencyFilterParamFromFilters());
907
        }
908
        
909
        /**
910
         * Builds the list of filter parameters to persist 
911
         * @return
912
         */
913
        private List<PersistencyFilterParams> buildPersistencyFilterParamFromFilters() throws PersistenceException {
914
                List<PersistencyFilterParams> filters = new ArrayList<PersistencyFilterParams>();
915
                
916
                for (int i = 0; i < getFilterList().lenght(); i++) {
917
                        RasterFilter f = getFilterList().get(i);
918
                        Params uipar = f.getUIParams(f.getName());
919
                        PersistencyFilterParams param = new PersistencyFilterParams();
920
                        param.setFilterParam(uipar);
921
                        param.setFilterName(f.getName());
922
                        try {
923
                                RasterFilterListManager manager = getFilterList().getManagerByFilterClass(f.getClass());
924
                                param.setManagerExtensionName(manager.getManagerID());
925
                        } catch (FilterManagerException e) {
926
                                throw new PersistenceException("Error getting filter manager ID", e);
927
                        }
928
                        filters.add(param);
929
                }
930
                return filters;
931
        }
932
        
933
        /**
934
         * Builds the filters from the list of classes <code>PersistencyFilterParam</code> recovered from a project
935
         * @param fList
936
         * @param listFilterUsed
937
         * @throws PersistenceException
938
         */
939
        public void buildFiltersFromPersistencyFilterParam(Statistics stats) throws PersistenceException {
940
                filterList.addEnvParam("SrcStatistics", stats);
941
                setFilterList(filterList);
942
                
943
                ArrayList<Exception> exc = new ArrayList<Exception>();
944
                for (int i = 0; i < listFilterParameters.size(); i++) {
945
                        try {
946
                                PersistencyFilterParams pfp = (PersistencyFilterParams) listFilterParameters.get(i);
947
                                if(pfp != null && pfp.getFilterClass() != null && pfp.getFilterParams() != null) {
948
                                        RasterFilterListManager filterManager = filterList.getManagerByFilterClass(pfp.getFilterClass());
949
                                        filterManager.setFilterList(filterList);
950
                                        if(filterManager != null)
951
                                                filterManager.addFilter(pfp.getFilterClass(), pfp.getFilterParams());
952
                                }
953
                        } catch (FilterTypeException e) {
954
                                exc.add(e);
955
                        } catch (FilterManagerException e) {
956
                                exc.add(e);
957
                        }
958
                }
959
                
960
                if(exc.size() != 0) {
961
                        throw new PersistenceException("error_adding_filters", exc.get(0));
962
                }
963
        }
964
        
965
}