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

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

    
118
        private ImageDrawerImpl  drawer                    = null;
119
        
120
        /**
121
         * 
122
         */
123
        private Transparency     renderingTransparency     = null;
124
        private int              lastAlphaBand             = -1;
125
        
126
        /**
127
         * Lista de filtros aplicada en la renderizaci?n
128
         */
129
        private RasterFilterList filterList               = null;
130

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

    
137
        private Point2D          ulPxRequest, lrPxRequest;
138

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

    
186
        private void init() {
187
                if(dataStore == null || dataStore.getDataType() == null)
188
                        return;
189

    
190
                drawer = new ImageDrawerImpl();
191
                getRenderColorInterpretation();
192
        }
193

    
194
        /**
195
         * Asigna un listener a la lista que ser? informado cuando cambie una
196
         * propiedad visual en la renderizaci?n.
197
         * @param listener VisualPropertyListener
198
         */
199
        public void addVisualPropertyListener(VisualPropertyListener listener) {
200
                visualPropertyListener.add(listener);
201
        }
202

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

    
232
        public void drawThread(Graphics2D g, ViewPortData vp) {
233
                //Se dibuja si cae dentro de la vista
234
                if(util.isOutside(vp.getExtent(), dataStore.getExtent())) 
235
                        return;
236
                
237
                setReading(true);
238
                setGraphicInfo(g, vp);
239
                new Thread(this).start();
240

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

    
368
                if(tiling == null || tiling.booleanValue()) {
369
                        //Reescalado de los tiles. El tama?o en pixels de un tile no tiene pq coincidir con el de la vista.
370
                        double w = lastViewPortData.getWidth();
371
                        double h = lastViewPortData.getHeight();
372
                        if(viewDimension != null) {
373
                                w = viewDimension.getWidth();
374
                                h = viewDimension.getHeight();
375
                        }
376
                        double viewScaleW = lastViewPortData.getExtent().width() / w;
377
                        double tileScaleW = tileExtent.width() / (double)buf.getWidth();
378
                        double scaleW = viewScaleW / tileScaleW;
379
                        double viewScaleH = lastViewPortData.getExtent().height() / h;
380
                        double tileScaleH = tileExtent.height() / (double)buf.getHeight();
381
                        double scaleH = viewScaleH / tileScaleH;
382

    
383
                        ImageDrawerImpl d = new ImageDrawerImpl();
384
                        d.setBuffer(buf);
385
                        d.setSupersamplingOn(null);
386
                        d.setOutputSize(buf.getWidth(), buf.getHeight());
387
                        d.setLastTransparency(transparencyProcessed);
388
                        Image geoImage;
389
                        try {
390
                                geoImage = d.drawBufferOverImageObject();
391
                        } catch (ProcessInterruptedException e2) {
392
                                return;
393
                        }
394
                        d.dispose();
395
                        
396
                        AffineTransform at = new AffineTransform();
397
                        at.scale(1 / scaleW, 1 / scaleH);
398
                        
399
                        try {
400
                                Point2D pt = new Point2D.Double(tileExtent.getULX(), tileExtent.getULY());
401
                                ((DefaultViewPortData)lastViewPortData).mat.transform(pt, pt);
402
                                at.inverseTransform(pt, pt);
403

    
404
                                lastGraphics.transform(at);
405
                                lastGraphics.drawImage(geoImage, (int) Math.round(pt.getX()), (int) Math.round(pt.getY()), null);
406
                                lastGraphics.transform(at.createInverse());
407
                                geoImage.flush();
408
                        } catch (NoninvertibleTransformException e1) {
409
                                e1.printStackTrace();
410
                        }
411
                } else {
412
                        try {
413
                                drawBufferOnImage(lastGraphics, lastViewPortData, buf, step, transf, tileExtent);
414
                        } catch (QueryException e1) {
415
                                LoggerFactory.getLogger(getClass()).debug("Error loading data", e1);
416
                        } catch (ProcessInterruptedException e1) {
417
                        }
418
                }
419
                
420
                if(!crash) { //Las im?genes de crash no se liberan ya que est?n en un hashmap global
421
                        if(buf != null)
422
                                buf.dispose();
423
                }
424
        }
425
        
426
        public synchronized Buffer draw(Graphics2D g, ViewPortData vp, ICoordTrans coordTrans, TaskStatus taskStatus)
427
                throws QueryException, ProcessInterruptedException {
428
                lastGraphics = g;
429
                lastViewPortData = vp;
430
                lastCoordTrans = coordTrans;
431

    
432
                Extent extent = dataStore.getExtent();
433
                if(coordTrans != null){
434
                    extent = extent.convert(coordTrans);
435
                }
436
                
437
                if(util.isOutside(vp.getExtent(), extent)) {
438
                        endReading();
439
                        return null;
440
                }
441

    
442
                Extent adjustedRotedRequest = null;
443
        try {
444
            adjustedRotedRequest = request(vp, coordTrans, dataStore);
445
        } catch (NoninvertibleTransformException e) {
446
            throw new ProcessInterruptedException("Problems adjusting extent to render");
447
        }
448

    
449
                if ((widthImage <= 0) || (heightImage <= 0)) {
450
                        endReading();
451
                        return null;
452
                }
453

    
454
                if (dataStore == null) 
455
                        return null;
456
                
457
                Buffer buf = null; 
458
                double[] step = null;
459
                int[] renderBands = getRenderColorInterpretation().buildRenderBands();
460
                
461
        if (coordTrans != null) {
462
            RasterRenderReprojection renderReprojection = new RasterRenderReprojection();
463
            try {
464
                buf =
465
                    renderReprojection.warp(dataStore, coordTrans, adjustedRotedRequest,
466
                        (int) Math.round(widthImage), (int) Math.round(heightImage), vp.getTime(),
467
                        renderBands, taskStatus);
468
            } catch (WarpException e) {
469
                throw new ProcessInterruptedException(e);
470
            }
471
                } else {
472
                        lastAlphaBand = getRenderingTransparency().getAlphaBandNumber();
473

    
474
                        RasterQuery query = getRasterManager().createQuery();
475
                        query.setTaskStatus(taskStatus);
476
                        query.setTime(vp.getTime());
477
                        query.setAreaOfInterest(adjustedRotedRequest, (int)Math.round(widthImage), (int)Math.round(heightImage));
478
                        query.setDrawableBands(renderBands);
479
                        if(dataStore.getDataType()[0] == Buffer.TYPE_BYTE) {
480
                                if(lastAlphaBand != -1)
481
                                        query.forceARGBRequest();
482
                                else if(renderBands.length == 3 || (renderBands.length == 4 && renderBands[3] == -1))
483
                                        query.forceRGBRequest();
484
                        } else {
485
                                if(renderBands.length == 4 && renderBands[3] != -1)
486
                                        query.forceARGBRequest();
487
                                else
488
                                        query.forceRGBRequest();
489
                        }
490
                        buf = dataStore.query(query);
491
                        step = query.getStep();
492
                }
493

    
494
                if(drawer == null) {
495
                        init();
496
                }
497
                
498
                return drawBufferOnImage(lastGraphics, 
499
                                        lastViewPortData, 
500
                                        buf, 
501
                                        step, 
502
                                        dataStore.getAffineTransform(), 
503
                                        adjustedRotedRequest);
504
        }
505
        
506
        private synchronized Buffer drawBufferOnImage(Graphics2D g, ViewPortData vp, Buffer buf, double[] step, AffineTransform transf, Extent adjustedRotedRequest)
507
                throws QueryException, ProcessInterruptedException {
508
                FilterLoader filterLoader = bufferPreprocessing(buf);
509
                Transparency transparencyProcessed = filterLoader.getTransparency(); 
510
                buf = filterLoader.getBufferResult();
511
                
512
                if(g == null)
513
                        return buf;
514
                
515
                drawer.setBuffer(buf); // Buffer de datos a renderizar
516
                drawer.setSupersamplingOn(step); // Desplazamiento para supersampleo
517
                drawer.setOutputSize((int)Math.round(widthImage), (int)Math.round(heightImage)); // Ancho y alto del buffer
518
                drawer.setLastTransparency(transparencyProcessed);
519
                Image geoImage = drawer.drawBufferOverImageObject(); // Acci?n de renderizado
520
                drawer.dispose();
521
                
522
                //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
523
                //transformaci?n. Esto no es necesario hacerlo, sin ello se visualiza igual. Unicamente se hace porque de esta
524
                //forma el raster resultante mejora un poco en calidad en ciertos niveles de zoom ya que al aplicar transformaciones
525
                //sobre el Graphics parece que pierde algo de calidad.
526
                if(transf.getScaleX() > 0 && transf.getScaleY() < 0 && transf.getShearX() == 0 && transf.getShearY() == 0) {
527
                        Point2D lastGraphicOffset = new Point2D.Double(adjustedRotedRequest.getULX(), adjustedRotedRequest.getULY());
528
                        ((DefaultViewPortData)vp).mat.transform(lastGraphicOffset, lastGraphicOffset);
529
                        g.drawImage(geoImage, (int) Math.round(lastGraphicOffset.getX()), (int) Math.round(lastGraphicOffset.getY()), null);
530
                        return buf;
531
                }
532

    
533
                /*
534
                 * Tenemos una matriz con la transformaci?n de la coordenadas de la vista a coordenadas reales vp.mat, adem?s tenemos
535
                 * la transformaci?n de coordenadas reales a coordenadas pixel (transf). Con ambas podemos obtener una matriz de trasformacion
536
                 * entre coordenadas de la vista a coordenadas pixel (transf X vp.mat). As? obtenemos la transformaci?n entre coordenadas
537
                 * de la vista y coordenadas pixel del raster. El problema es que a cada zoom la escala de la petici?n del raster varia
538
                 * por lo que habr? que calcular una matriz con la escala (escale). escale X transf X vp.mat
539
                 */
540
                double sX = Math.abs(ulPxRequest.getX() - lrPxRequest.getX()) / widthImage;
541
                double sY = Math.abs(ulPxRequest.getY() - lrPxRequest.getY()) / heightImage;
542
                AffineTransform scale = new AffineTransform(sX, 0, 0, sY, 0, 0);
543

    
544
                try {
545
                        AffineTransform at = (AffineTransform)scale.clone();
546
                        at.preConcatenate(transf);
547
                        at.preConcatenate(vp.getMat());
548
                        g.transform(at);
549
                        Point2D.Double pt = null;
550
                        //El punto sobre el que rota la imagen depende del signo de los tama?os del pixel
551
                        if(transf.getScaleX() < 0 && transf.getScaleY() < 0)
552
                                pt = new Point2D.Double(adjustedRotedRequest.maxX(), adjustedRotedRequest.maxY());
553
                        else if(transf.getScaleX() > 0 && transf.getScaleY() > 0)
554
                                pt = new Point2D.Double(adjustedRotedRequest.minX(), adjustedRotedRequest.minY());
555
                        else if(transf.getScaleX() < 0 && transf.getScaleY() > 0)
556
                                pt = new Point2D.Double(adjustedRotedRequest.maxX(), adjustedRotedRequest.minY());
557
                        else
558
                                pt = new Point2D.Double(adjustedRotedRequest.getULX(), adjustedRotedRequest.getULY());
559
                        vp.getMat().transform(pt, pt);
560
                        at.inverseTransform(pt, pt);
561
                        g.drawImage(geoImage, (int) Math.round(pt.getX()), (int) Math.round(pt.getY()), null);
562
                        g.transform(at.createInverse());
563
                        geoImage.flush();
564
                } catch (NoninvertibleTransformException e) {
565
                        LoggerFactory.getLogger(getClass()).debug("Transformation error", e);
566
                }
567
                
568
                return buf;
569
                // long t2 = new Date().getTime();
570
                // System.out.println("Renderizando Raster: " + ((t2 - t1) / 1000D) + ", secs.");
571
        }
572
        
573
        /**
574
         * Applies filters and transparency on the buffer and returns the grid with the modified buffer.
575
         * @param buf
576
         * @param transparency
577
         * @throws ProcessInterruptedException
578
         */
579
        private FilterLoader bufferPreprocessing(Buffer buf) throws ProcessInterruptedException {
580
                //Asignamos los datos al objeto transparencia antes de aplicar la pila de filtros para que el valor NoData sea efectivo
581
                if (getRenderingTransparency().getNoData().isNoDataTransparent() || 
582
                                getRenderingTransparency().existAlphaBand())
583
                        getRenderingTransparency().setDataBuffer(buf);
584
                else {
585
                        getRenderingTransparency().setDataBuffer(null);
586
                }
587
                getRenderingTransparency().activeTransparency();
588
                List<ROI> roi = null;
589
                try {
590
                        roi = (List<ROI>)dataStore.getRois(lastViewPortData != null ? lastViewPortData.getProjection() : null);
591
                } catch (ROIException e) {
592
                }
593
                
594
                FilterLoader filterLoader = RasterLocator.getManager().createFilterLoader(filterList);
595
                filterLoader.addSrcBandCount(dataStore.getBandCount());
596
                filterLoader.addSrcDataType(dataStore.getDataType()[0]);
597
                filterLoader.addSrcStatistics(dataStore.getStatistics());
598
                filterLoader.addSrcROI(roi);
599
                filterLoader.addSrcHistogram(dataStore.getHistogramComputer());
600
                filterLoader.addTransparency(getRenderingTransparency());
601
                filterLoader.applyFilters(buf);
602

    
603
                return filterLoader;
604
        }
605

    
606
        /**
607
         * When tiles are renderized the color table in each tile could be diferent.
608
         * In this case the color table must be replaced
609
         */
610
        //@deprecated one color table by tiled layer
611
        private void addTileColorTable(ColorTable tileColorTable) {
612
                if(tileColorTable == null)
613
                        return;
614
                else {
615
                        if(filterList.getFilterClassByID("ColorTable") == null) {
616
                                try {
617
                                        RasterFilterListManager colorTableManager = filterList.getManagerByID("ColorTable");
618
                                        Params params = filterList.createEmptyFilterParams();
619
                                        params.setParam("colorTable", tileColorTable);
620
                                        colorTableManager.addFilter(params);
621
                                } catch (FilterManagerException e) {
622
                                        e.printStackTrace();
623
                                } catch (FilterTypeException e) {
624
                                        e.printStackTrace();
625
                                }
626
                        }
627
                }
628
        }
629
        
630
        public void endReading() {
631
                isDrawing = false;
632
        }
633
        
634
        public boolean isReading() {
635
                return isDrawing;
636
        }
637
        
638
        public void setReading(boolean reading) {
639
                isDrawing = reading;
640
        }
641
        
642
        /**
643
         * Calculamos la petici?n en coordenadas del mundo real con la transformaci?n del raster. Esto
644
         * permite obtener las coordenadas de la petici?n con la rotaci?n, si la tiene.
645
         * @param vp
646
         * @param ldatastore
647
         * @return
648
         * @throws NoninvertibleTransformException 
649
         */
650
        private Extent request(ViewPortData vp, ICoordTrans coordTrans, RasterDataStore ldatastore) throws NoninvertibleTransformException {
651
            if (ldatastore.isRotated()) {
652
                        //Obtenemos las cuatro esquinas de la selecci?n que hemos hecho en la vista
653
                        Point2D ul = new Point2D.Double(vp.getExtent().minX(), vp.getExtent().maxY());
654
                        Point2D ur = new Point2D.Double(vp.getExtent().maxX(), vp.getExtent().maxY());
655
                        Point2D ll = new Point2D.Double(vp.getExtent().minX(), vp.getExtent().minY());
656
                        Point2D lr = new Point2D.Double(vp.getExtent().maxX(), vp.getExtent().minY());
657

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

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

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

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

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

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

    
690
                        //Ajustamos la petici?n a los limites del raster, teniendo en cuenta la rotaci?n de este.
691
                        return new ExtentImpl(ulWC, lrWC);
692
                }
693
                
694
                AffineTransform at = ldatastore.getAffineTransform();
695
        Extent adjustedRotedExtent = null; 
696
        if (coordTrans != null) {
697
            Extent reprojectedExtent = ldatastore.getExtent().convert(coordTrans);
698
            double cellSizeX =
699
                (reprojectedExtent.getMax().getX() - reprojectedExtent.getMin().getX())
700
                    / ldatastore.getWidth();
701
            double cellSizeY =
702
                (reprojectedExtent.getMax().getY() - reprojectedExtent.getMin().getY())
703
                    / ldatastore.getHeight();
704
            
705
            Extent intersection = vp.getExtent().intersection(reprojectedExtent);
706
            at =
707
                new AffineTransform(cellSizeX, at.getShearY(), at.getShearX(), -cellSizeY,
708
                    intersection.getMin().getX(), intersection.getMax().getY());
709
            double width = intersection.width() / cellSizeX;
710
            double height = intersection.height() / cellSizeY;
711
            adjustedRotedExtent = util.calculateAdjustedView(intersection, at, width, height);
712
        } else {
713
                    adjustedRotedExtent = util.calculateAdjustedView(vp.getExtent(), at, ldatastore.getWidth(),
714
                ldatastore.getHeight());
715
                }
716
                
717
                widthImage = (int)Math.round(Math.abs(adjustedRotedExtent.width() * vp.getMat().getScaleX()));
718
                heightImage = (int)Math.round(Math.abs(adjustedRotedExtent.height() * vp.getMat().getScaleY()));
719
                Point2D ul = new Point2D.Double(adjustedRotedExtent.getMin().getX(), adjustedRotedExtent.getMax().getY());
720
                Point2D lr = new Point2D.Double(adjustedRotedExtent.getMax().getX(), adjustedRotedExtent.getMin().getY());
721
                
722
                Point2D worldUL = new Point2D.Double();
723
                Point2D worldLR = new Point2D.Double();
724
                
725
        if (coordTrans != null) {
726
            ul = at.inverseTransform(ul, worldUL);
727
            lr = at.inverseTransform(lr, worldLR);
728
        } else {
729
                    worldUL = ldatastore.worldToRaster(ul);
730
                    worldLR = ldatastore.worldToRaster(lr);
731
                }
732
                
733
                ulPxRequest = new Point2D.Double(worldUL.getX(), worldUL.getY());
734
                lrPxRequest = new Point2D.Double(worldLR.getX(), worldLR.getY());
735
                return adjustedRotedExtent;
736
        }
737

    
738
        public boolean isRenderingAsGray() {
739
                int[] renderBands = getRenderColorInterpretation().buildRenderBands();
740
                if ((renderBands != null) && (renderBands.length == 3 || renderBands.length == 4) && (renderBands[0] >= 0) &&
741
                                (renderBands[0] == renderBands[1]) && (renderBands[1] == renderBands[2]))
742
                        return true;
743
                return false;
744
        }
745
        
746
        public void setRenderColorInterpretation(ColorInterpretation ci) {
747
                this.renderColorInterpretation = ci;
748
        }
749
        
750
        public ColorInterpretation getRenderColorInterpretation() {
751
                if(renderColorInterpretation == null) {
752
                        //Initializes the color interpretation using the source but if the source does not have
753
                        //it will be figure out depending on the number of bands
754
                        renderColorInterpretation = dataStore.getColorInterpretation();
755
                        if(renderColorInterpretation == null || !renderColorInterpretation.hasInterpretation()) {
756
                                switch (dataStore.getBandCount()) {
757
                                case 1:
758
                                case 2:
759
                                        renderColorInterpretation = DataStoreColorInterpretation.createGrayInterpretation();
760
                                        break;
761
                                case 3:
762
                                        renderColorInterpretation = DataStoreColorInterpretation.createRGBInterpretation();
763
                                        break;
764
                                case 4:
765
                                        renderColorInterpretation = DataStoreColorInterpretation.createRGBAInterpretation();
766
                                default:
767
                                        renderColorInterpretation = DataStoreColorInterpretation.createRGBInterpretation();
768
                                        break;
769
                                }        
770
                        } else
771
                                renderColorInterpretation = dataStore.getColorInterpretation().cloneColorInterpretation();
772
                }
773
                return renderColorInterpretation;
774
        }
775
        
776
        /**
777
                 * Asigna el n?mero de bandas y el orden de renderizado. Cada posici?n del vector es una banda
778
         * del buffer y el contenido de esa posici?n es la banda de la imagen que se dibujar?
779
         * sobre ese buffer. A la hora de renderizar hay que tener en cuenta que solo se renderizan las
780
         * tres primeras bandas del buffer por lo que solo se tienen en cuenta los tres primeros
781
         * elementos. Por ejemplo, el array {1, 0, 3} dibujar? sobre el Graphics las bandas 1,0 y 3 de un
782
         * raster que tiene al menos 4 bandas. La notaci?n con -1 en alguna posici?n del vector solo tiene sentido
783
         * en la visualizaci?n pero no se puede as?gnar una banda del buffer a null.
784
         * Algunos ejemplos:
785
         * <P>
786
         * {-1, 0, -1} Dibuja la banda 0 del raster en la G de la visualizaci?n.
787
         * Si replicateBand es true R = G = B sino R = B = 0
788
         * {1, 0, 3} La R = banda 1 del raster, G = 0 y B = 3
789
         * {0} La R = banda 0 del raster. Si replicateBand es true R = G = B sino G = B = 0
790
         * </P>
791
         *
792
         *
793
                 * @param renderBands: bandas y su posici?n
794
                 */
795
        /*public void setRenderBands(int[] renderBands) {
796
                if(        renderBands[0] != this.renderBands[0] ||
797
                        renderBands[1] != this.renderBands[1] ||
798
                        renderBands[2] != this.renderBands[2] ||
799
                        renderBands[3] != this.renderBands[3])
800
                        callVisualPropertyChanged(renderBands);
801
                
802
                this.renderBands = renderBands;
803
                if (filterList != null)
804
                        for (int i = 0; i < filterList.lenght(); i++)
805
                                (filterList.get(i)).addParam("renderBands", renderBands);
806
        }
807
        
808
        public int[] getRenderBands() {
809
                return renderBands;
810
        }*/
811

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

    
837
        public Transparency getRenderingTransparency() {
838
                //If the transparency hasn't been defined yet then we'll take that from the store
839
                if (renderingTransparency == null) {
840
                        renderingTransparency = dataStore.getTransparency().cloneTransparency();
841
                        renderingTransparency.addPropertyListener(this);
842
                }
843
                renderingTransparency.setColorInterpretation(getRenderColorInterpretation());
844
                return renderingTransparency;
845
        }
846
        
847
        public int getLastAlphaBandNumber() {
848
                return lastAlphaBand;
849
        }
850

    
851
        public void setLastTransparency(Transparency lastTransparency) {
852
                this.renderingTransparency = lastTransparency;
853
                if(this.renderingTransparency != null)
854
                        this.renderingTransparency.addPropertyListener(this);
855
        }
856

    
857
        public RasterFilterList getFilterList() {
858
                return filterList;
859
        }
860

    
861
        public void setFilterList(RasterFilterList filterList) {
862
                this.filterList = filterList;
863
                this.filterList.addFilterListListener(this);
864
        }
865

    
866
        public boolean existColorTable() {
867
                if(filterList != null)
868
                        return (filterList.getFilterByBaseClass(ColorTableFilter.class) != null);
869
                else
870
                        return false;
871
        }
872
        
873
        public ColorTable getColorTable() {
874
                if(existColorTable()) {
875
                        RasterFilter f = filterList.getFilterByBaseClass(ColorTableFilter.class);
876
                        return ((ColorTableFilter)f).getColorTable();
877
                }
878
                return null;
879
        }
880

    
881
        /**
882
         * Asigna la factoria de buffer del renderizador
883
         * @param ds
884
         */
885
        public void setDataSource(RasterDataStore ds) {
886
                this.dataStore = ds;
887
        }
888

    
889
        /**
890
         * Evento activado cuando cambia una propiedad de transparencia.
891
         */
892
        public void actionValueChanged(PropertyEvent e) {
893
                callVisualPropertyChanged(new VisualPropertyEvent(e.getSource()));
894
        }
895

    
896
        /**
897
         * Evento activado cuando cambia la lista de filtros.
898
         */
899
        public void filterListChanged(FilterListChangeEvent e) {
900
                callVisualPropertyChanged(new VisualPropertyEvent(e.getSource()));
901
        }
902
        
903
        /**
904
         * Sets buffers to null
905
         */
906
        public void dispose() {
907
                if (renderingTransparency != null)
908
                        renderingTransparency.dispose();
909
                if (getFilterList() != null)
910
                        getFilterList().dispose();
911
                try {
912
                        finalize();
913
                } catch (Throwable e) {
914
                }
915
        }
916
        
917
        protected void finalize() throws Throwable {
918
                dataStore                = null;
919
        drawer                   = null;
920
                renderingTransparency    = null;
921
                filterList               = null;
922
        ulPxRequest              = null;
923
        lrPxRequest              = null;
924
                lastGraphics             = null;
925
                lastViewPortData         = null;
926
                viewDimension            = null;
927
                
928
                if(visualPropertyListener != null) {
929
                        visualPropertyListener.clear();
930
                        visualPropertyListener = null;
931
                }
932
                super.finalize();
933
        }
934

    
935
        //******************************
936
        //Persistence
937
        //******************************
938

    
939
        public static void registerPersistence() {
940
                PersistenceManager manager = ToolsLocator.getPersistenceManager();
941
                DynStruct definition = manager.getDefinition("DefaultRender_Persistent");
942
                if( definition == null ) {
943
                        definition = manager.addDefinition(
944
                                        DefaultRender.class,
945
                                        "DefaultRender_Persistent",
946
                                        "RasterRendering Persistent definition",
947
                                        null, 
948
                                        null
949
                                        );
950

    
951
                        definition.addDynFieldObject("lastTransparency")
952
                        .setClassOfValue(Transparency.class)
953
                        .setMandatory(false);
954

    
955
                        definition.addDynFieldObject("filterList")
956
                        .setClassOfValue(RasterFilterList.class)
957
                        .setMandatory(false);
958

    
959
                        definition.addDynFieldList("paramlist")
960
                        .setClassOfItems(PersistencyFilterParams.class)
961
                        .setMandatory(false);
962
                }
963
        }
964

    
965
        private List<PersistencyFilterParams> listFilterParameters = null;
966
                        
967
        @SuppressWarnings("unchecked")
968
        public void loadFromState(PersistentState state)
969
                        throws PersistenceException {
970
                renderingTransparency = (Transparency)state.get("lastTransparency");        
971
                renderColorInterpretation = renderingTransparency.getColorInterpretation();
972
                filterList = (RasterFilterList)state.get("filterList");
973
                listFilterParameters = state.getList("paramlist");
974
        }
975

    
976
        public void saveToState(PersistentState state) throws PersistenceException {
977
                state.set("lastTransparency", getRenderingTransparency());
978
                state.set("filterList", getFilterList());
979
                state.set("paramlist", buildPersistencyFilterParamFromFilters());
980
        }
981
        
982
        /**
983
         * Builds the list of filter parameters to persist 
984
         * @return
985
         */
986
        private List<PersistencyFilterParams> buildPersistencyFilterParamFromFilters() throws PersistenceException {
987
                List<PersistencyFilterParams> filters = new ArrayList<PersistencyFilterParams>();
988
                
989
                for (int i = 0; i < getFilterList().lenght(); i++) {
990
                        RasterFilter f = getFilterList().get(i);
991
                        Params uipar = f.getUIParams(f.getName());
992
                        PersistencyFilterParams param = new PersistencyFilterParams();
993
                        param.setFilterParam(uipar);
994
                        param.setFilterName(f.getName());
995
                        try {
996
                                RasterFilterListManager manager = getFilterList().getManagerByFilterClass(f.getClass());
997
                                param.setManagerExtensionName(manager.getManagerID());
998
                        } catch (FilterManagerException e) {
999
                                throw new PersistenceException("Error getting filter manager ID", e);
1000
                        }
1001
                        filters.add(param);
1002
                }
1003
                return filters;
1004
        }
1005
        
1006
        /**
1007
         * Builds the filters from the list of classes <code>PersistencyFilterParam</code> recovered from a project
1008
         * @param stats
1009
         * @throws PersistenceException
1010
         */
1011
        public void buildFiltersFromPersistencyFilterParam(Statistics stats) throws PersistenceException {
1012
                filterList.addEnvParam("SrcStatistics", stats);
1013
                setFilterList(filterList);
1014
                
1015
                ArrayList<Exception> exc = new ArrayList<Exception>();
1016
                for (int i = 0; i < listFilterParameters.size(); i++) {
1017
                        try {
1018
                                PersistencyFilterParams pfp = (PersistencyFilterParams) listFilterParameters.get(i);
1019
                                if(pfp != null && pfp.getFilterClass() != null && pfp.getFilterParams() != null) {
1020
                                        RasterFilterListManager filterManager = filterList.getManagerByFilterClass(pfp.getFilterClass());
1021
                                        filterManager.setFilterList(filterList);
1022
                                        if(filterManager != null)
1023
                                                filterManager.addFilter(pfp.getFilterClass(), pfp.getFilterParams());
1024
                                }
1025
                        } catch (FilterTypeException e) {
1026
                                exc.add(e);
1027
                        } catch (FilterManagerException e) {
1028
                                exc.add(e);
1029
                        }
1030
                }
1031
                
1032
                if(exc.size() != 0) {
1033
                        throw new PersistenceException("error_adding_filters", exc.get(0));
1034
                }
1035
        }
1036

    
1037
    @Override
1038
    public Buffer draw(Graphics2D g, ViewPortData vp, TaskStatus taskStatus) throws QueryException,
1039
        ProcessInterruptedException {
1040
        return draw(g, vp, null, taskStatus);
1041
    }
1042

    
1043
    @Override
1044
    public void drawTiledService(Graphics2D g, ViewPortData vp, Dimension2D viewDimension,
1045
        TaskStatus status) throws QueryException, ProcessInterruptedException {
1046
        drawTiledService(g, vp, viewDimension, null, status);
1047
    }
1048
}