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 / store / properties / DataStoreTransparency.java @ 162

History | View | Annotate | Download (15.4 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.store.properties;
23

    
24
import java.util.ArrayList;
25

    
26
import org.gvsig.fmap.dal.coverage.RasterLibrary;
27
import org.gvsig.fmap.dal.coverage.dataset.Buffer;
28
import org.gvsig.fmap.dal.coverage.datastruct.TransparencyRange;
29
import org.gvsig.fmap.dal.coverage.grid.GridTransparency;
30
import org.gvsig.fmap.dal.coverage.store.props.Transparency;
31
import org.gvsig.fmap.dal.coverage.util.PropertyEvent;
32
import org.gvsig.fmap.dal.coverage.util.PropertyListener;
33
import org.gvsig.raster.impl.DefaultRasterManager;
34
import org.gvsig.raster.impl.grid.GridTransparencyImpl;
35
import org.gvsig.tools.ToolsLocator;
36
import org.gvsig.tools.dynobject.DynStruct;
37
import org.gvsig.tools.persistence.PersistenceManager;
38
import org.gvsig.tools.persistence.Persistent;
39
import org.gvsig.tools.persistence.PersistentState;
40
import org.gvsig.tools.persistence.exception.PersistenceException;
41
/**
42
 * <p>
43
 * Esta clase contiene informaci?n de transparencia de un objeto. Los objetos
44
 * pueden ser dataset, grid u otros. Cuando un usuario quiere a?adir nueva
45
 * informaci?n de transparencia crea un objeto de este tipo que debe ser
46
 * mezclado (merge) con otros objetos de este tipo que existan para la misma
47
 * fuente de datos.
48
 * </p>
49
 * <p>
50
 * Un multirasterdatset obtiene los distintos objetos transparency de todos los
51
 * ficheros que los componen. Para realizar un solo objeto transparency se har?
52
 * un merge de todos ellos.
53
 * </p>
54
 * <p>
55
 * Finalmente y antes de renderizar se necesita un objeto GridTransparency. Este
56
 * estar? compuesto con toda la informaci?n de transparencia aplicar, es decir,
57
 * todos los objetos Transparency mezclados. GridTransparency con tiene el
58
 * m?todo de procesado de un pixel. Se le proporciona un pixel y devuelve este
59
 * mismo pixel con la transparencia aplicada.
60
 * </p>
61
 * <p>
62
 * Una transparencia que se aplica a un buffer puede tener cuatro procedencias distintas:
63
 * <UL>
64
 * <LI>Mascara: Un buffer de NxN aplicado sobre la zona a renderizar como una m?scara de
65
 * transparencia. Las bandas alpha de las imagenes se comportan de esta forma.</LI>
66
 * <LI>Opacidad global: Un valor de opacidad se aplicado a cada pixel a renderizar. Este es
67
 * igual para todos los p?xeles.</LI>
68
 * <LI>Rangos: Una lista de rangos de valores RGB. Cada pixel cuyo valor est? dentro de alguno
69
 * de los rangos se aplica como transparente.</LI>
70
 * <LI>Dato: Todos los valores del buffer que coincidan con ese dato son puestos como transparente.
71
 * Para que esto sea posible tenemos que disponer del buffer de datos originales sin ning?n proceso.</LI>
72
 * </UL>
73
 * </p>
74
 *
75
 * @version 07/06/2007
76
 * @author Nacho Brodin (nachobrodin@gmail.com)
77
 */
78
public class DataStoreTransparency implements Transparency, Persistent {
79
        public static final String PERSISTENCE_NAME = "Transparency_Persistent";
80

    
81
        public static int     MAX_OPACITY        = 255;
82
        protected int         alphaBandNumber    = -1;
83
        /**
84
         * Buffer con la banda alpha correspondiente a la zona a renderizar
85
         */
86
        private Buffer       mask               = null;
87
        /**
88
         * Buffer con los datos originales (sin filtrar) correspondiente a la zona a renderizar.
89
         * Esto es util para aplicar el valor NoData ya que hay que consultar el valor original del
90
         * dato. Despu?s de hacer un process es recomendable hacer free para poner a null los buffers.
91
         */
92
        protected Buffer     originalData       = null;
93
        /**
94
         * Valor de dato transparente. Todos los p?xeles de originalData que correspondan con este
95
         * valor se pondr?n 100% transparentes.
96
         */
97
        protected double      noData             = RasterLibrary.defaultNoDataValue;
98
        /**
99
         * Flag que indica que el uso de noData para transparencia est? activo
100
         */
101
        protected boolean     noDataActive       = false;
102
        /**
103
         * Rangos de transparencia aplicados. Lista de TransparencyRange
104
         */
105
        protected ArrayList<TransparencyRange>   
106
                              transparencyRanges = new ArrayList<TransparencyRange>();
107
        /**
108
         * Grado de opacidad de todo el raster
109
         */
110
        protected int         opacity            = 0xff;
111

    
112
        /**
113
         * Array de listeners que ser?n informados cuando cambia la propiedad de transparencia
114
         */
115
        private ArrayList<PropertyListener>     
116
                              transparencyPropertyListener = new ArrayList<PropertyListener>();
117

    
118
        /**
119
         * Constructor
120
         */
121
        public DataStoreTransparency() {
122
        }
123

    
124
        /**
125
         * Constructor de copia
126
         */
127
        @SuppressWarnings("unchecked")
128
        public DataStoreTransparency(Transparency tParam) {
129
                DataStoreTransparency t = null;
130
                if(tParam instanceof DataStoreTransparency)
131
                        t = (DataStoreTransparency)tParam;
132
                else 
133
                        return;
134
                
135
                //TODO: FUNCIONALIDAD: Falta asignar lo necesario para la transparencia por selecci?n
136
                this.transparencyRanges = (ArrayList<TransparencyRange>) t.getTransparencyRange().clone();
137
                this.mask = t.getAlphaBand();
138
                this.opacity = t.getOpacity();
139
                this.alphaBandNumber = t.alphaBandNumber;
140
                this.noData = t.getNoData();
141
                this.noDataActive = t.isNoDataActive();
142
                this.originalData = t.originalData;
143
        }
144

    
145
        /*
146
         * (non-Javadoc)
147
         * @see org.gvsig.fmap.dal.coverage.store.props.Transparency#addPropertyListener(PropertyListener)
148
         */
149
        public void addPropertyListener(PropertyListener listener) {
150
                transparencyPropertyListener.add(listener);
151
        }
152

    
153
        /**
154
         * M?todo llamado cuando hay un cambio en una propiedad de transparencia
155
         */
156
        private void callPropertyChanged(Object obj) {
157
                for (int i = 0; i < transparencyPropertyListener.size(); i++) {
158
                        PropertyEvent ev = new PropertyEvent(this, "transparency", null, null);
159
                        ((PropertyListener)transparencyPropertyListener.get(i)).actionValueChanged(ev);
160
                }
161
        }
162

    
163
        /**
164
         * Obtiene la m?scara asociada
165
         * @return M?scara de transparencia
166
         */
167
        public Buffer getAlphaBand() {
168
                return mask;
169
        }
170

    
171
        /*
172
         * (non-Javadoc)
173
         * @see org.gvsig.fmap.dal.coverage.store.props.Transparency#setAlphaBand(org.gvsig.fmap.dal.coverage.dataset.Buffer)
174
         */
175
        public void setAlphaBand(Buffer b) {
176
                if(b == null && mask != null) {
177
                        mask = b;
178
                        callPropertyChanged(this);
179
                        return;
180
                } else {
181
                        mask = b;
182
                        if(b != null)
183
                                callPropertyChanged(this);
184
                }
185
        }
186

    
187
        /*
188
         * (non-Javadoc)
189
         * @see org.gvsig.fmap.dal.coverage.store.props.Transparency#existAlphaBand()
190
         */
191
        public boolean existAlphaBand() {
192
                return (mask != null);
193
        }
194

    
195

    
196
        /**
197
         * Obtiene el ?rea de datos
198
         * @return M?scara de transparencia
199
         */
200
        public Buffer getDataBuffer() {
201
                return originalData;
202
        }
203

    
204
        /*
205
         * (non-Javadoc)
206
         * @see org.gvsig.fmap.dal.coverage.store.props.Transparency#setDataBuffer(org.gvsig.fmap.dal.coverage.dataset.Buffer)
207
         */
208
        public void setDataBuffer(Buffer b) {
209
                originalData = b;
210
        }
211

    
212
        /**
213
         * Obtiene la informaci?n de si existe o no la posibilidad de aplicar valore no data
214
         * como transparentes. Para ello tiene que estar activo su uso y el buffer debe contener datos
215
         * @return true si puede aplicarse noData y false si no se puede
216
         */
217
        public boolean isNoDataActive() {
218
                return noDataActive;
219
        }
220

    
221
        /**
222
         * Obtiene el valor noData
223
         * @return
224
         */
225
        public double getNoData() {
226
                return noData;
227
        }
228

    
229
        /*
230
         * (non-Javadoc)
231
         * @see org.gvsig.fmap.dal.coverage.store.props.Transparency#setNoData(double)
232
         */
233
        public void setNoData(double noData) {
234
                this.noDataActive = true;
235
                if(this.noData != noData)
236
                        callPropertyChanged(this);
237
                this.noData = noData;
238
        }
239

    
240
        /*
241
         * (non-Javadoc)
242
         * @see org.gvsig.fmap.dal.coverage.store.props.Transparency#activeNoData(boolean)
243
         */
244
        public void activeNoData(boolean active) {
245
                this.noDataActive = active;
246
        }
247

    
248
        /**
249
         * Obtiene los rangos de pixels que son transparentes en el raster.
250
         * @return Rangos de transparencias a aplicar
251
         */
252
        public ArrayList<TransparencyRange> getTransparencyRange() {
253
                return transparencyRanges;
254
        }
255

    
256
        /*
257
         * (non-Javadoc)
258
         * @see org.gvsig.fmap.dal.coverage.store.props.Transparency#setTransparencyRange(org.gvsig.fmap.dal.coverage.datastruct.TransparencyRange)
259
         */
260
        public void setTransparencyRange(TransparencyRange range) {
261
                this.transparencyRanges.add(range);
262
                callPropertyChanged(this);
263
        }
264

    
265
        /**
266
         * Asigna la lista de rangos de transparencia
267
         * @param ranges
268
         */
269
        public void setTransparencyRangeList(ArrayList<TransparencyRange> ranges) {
270
                this.transparencyRanges = ranges;
271
                callPropertyChanged(this);
272
        }
273

    
274
        /*
275
         * (non-Javadoc)
276
         * @see org.gvsig.fmap.dal.coverage.store.props.Transparency#clearListOfTransparencyRange()
277
         */
278
        public void clearListOfTransparencyRange() {
279
                transparencyRanges.clear();
280
                callPropertyChanged(this);
281
        }
282

    
283
        /**
284
         * Obtiene el grado de opacidad de todo el raster
285
         * @return valor del grado de opacidad.
286
         */
287
        public int getOpacity() {
288
                return opacity;
289
        }
290

    
291
        /*
292
         * (non-Javadoc)
293
         * @see org.gvsig.fmap.dal.coverage.store.props.Transparency#setOpacity(int)
294
         */
295
        public void setOpacity(int opacity) {
296
                if(opacity != this.opacity)
297
                        callPropertyChanged(this);
298
                this.opacity = opacity;
299
        }
300

    
301
        /**
302
         * Asigna la transparencia a partir de un objeto con los metadatos del raster.
303
         * @param metadata
304
         */
305
        public void setTransparencyByPixelFromMetadata(DataStoreMetadata metadata){
306
                if (metadata != null) {
307
                        TransparencyRange[] noData = metadata.parserNodataInMetadata();
308
                        if (noData != null)
309
                                for (int i = 0; i < noData.length; i++)
310
                                        getTransparencyRange().add(noData[i]);
311
                        TransparencyRange noDataValue = metadata.parserNodataByBand();
312
                        if (noData == null && noDataValue != null)
313
                                getTransparencyRange().add(noDataValue);
314
                }
315
        }
316

    
317
        /**
318
         * Mezcla el alpha actual con el que nos pasan por parametro y se asigna
319
         * directamente a destino
320
         * @param buffer
321
         * @param dst
322
         */
323
        public void mergeBuffer(Buffer buffer, Buffer dst) {
324
                for (int y = 0; y < mask.getHeight(); y++)
325
                        for (int x = 0; x < mask.getWidth(); x++)
326
                                // ((a / 255) * (b / 255)) * 255
327
                                // Es lo mismo que:
328
                                // (a * b) / 255
329
                                dst.setElem(y, x, 0,
330
                                                (byte) (((mask.getElemByte(y, x, 0) & 0xff) * (buffer.getElemByte(y, x, 0) & 0xff)) / 255D));
331
        }
332

    
333
        /**
334
         * Mezcla un objeto Transparency con el actual
335
         * @param ts objeto TransparencyStatus
336
         */
337
        public Transparency merge(Transparency tParam) {
338
                DataStoreTransparency transp = null;
339
                if(tParam instanceof DataStoreTransparency)
340
                        transp = (DataStoreTransparency)tParam;
341
                else 
342
                        return null;
343
                
344
                DataStoreTransparency t = new DataStoreTransparency();
345
                // Mezclamos la opacidad
346
                double op1 = (double) opacity / (double) MAX_OPACITY;
347
                double op2 = (double) transp.getOpacity() / (double) MAX_OPACITY;
348
                t.setOpacity((int) (op1 * op2 * MAX_OPACITY));
349

    
350
                // Mezclamos los rangos de transparencia
351
                ArrayList<TransparencyRange> tr = transp.getTransparencyRange();
352
                for (int i = 0; i < tr.size(); i++)
353
                        transparencyRanges.add(tr.get(i));
354

    
355
                // TODO: FUNCIONALIDAD Mezclamos la m?scara
356
                if (mask != null && transp.getAlphaBand() != null) {
357
                        Buffer newMask = DefaultRasterManager.getInstance().createBuffer(Buffer.TYPE_BYTE, mask.getWidth(), mask.getHeight(), 1, true);
358
                        // Mezclamos alphaBand con el que nos pasan en transp y lo asignamos al nuevo buffer
359
                        mergeBuffer(transp.getAlphaBand(), newMask);
360

    
361
                        t.setAlphaBand(newMask);
362
                } else if (mask != null) {
363
                        t.setAlphaBand(mask);
364
                        t.alphaBandNumber = alphaBandNumber;
365
                } else {
366
                        t.setAlphaBand(transp.getAlphaBand());
367
                        t.alphaBandNumber = transp.alphaBandNumber;
368
                }
369

    
370
                // TODO: FUNCIONALIDAD Mezclamos las ?reas
371

    
372
                // TODO: FUNCIONALIDAD Mezclamos las mascaras
373
                return t;
374
        }
375

    
376
        /**
377
         * Obtiene la banda de transpareci si existe o -1 si no existe.
378
         * @return n?mero de banda de transparencia o -1 si no existe.
379
         */
380
        public int getAlphaBandNumber() {
381
                return alphaBandNumber;
382
        }
383

    
384
        /**
385
         * Asigna la informaci?n de si existe o no banda de transparencia cuando este
386
         * objeto va asociado a un dataset. Si tiene este tipo de banda en cada
387
         * dibujado se cargar? la informaci?n de m?scara de transparencia en el la
388
         * variable mask.
389
         * @param true si existe banda de transparencia y false si no lo es.
390
         */
391
        public void setTransparencyBand(int alphaBandNumber) {
392
                this.alphaBandNumber = alphaBandNumber;
393
        }
394

    
395
        /**
396
         * Consulta si el valor de la posici?n (line, col) del buffer es considerado
397
         * NoData o no.
398
         * @param line Linea del buffer
399
         * @param col Columna del buffer
400
         * @return
401
         */
402
        protected boolean isNoData(int line, int col) {
403
                switch (originalData.getDataType()) {
404
                case Buffer.TYPE_BYTE:
405
                        if((originalData.getElemByte(line, col, 0)) == noData)
406
                                return true;
407
                        break;
408
                case Buffer.TYPE_SHORT:
409
                        if((originalData.getElemShort(line, col, 0)) == noData)
410
                                return true;
411
                        break;
412
                case Buffer.TYPE_INT:
413
                        if((originalData.getElemInt(line, col, 0)) == noData)
414
                                return true;
415
                        break;
416
                case Buffer.TYPE_FLOAT:
417
                        if((originalData.getElemFloat(line, col, 0)) == noData)
418
                                return true;
419
                        break;
420
                case Buffer.TYPE_DOUBLE:
421
                        if((originalData.getElemDouble(line, col, 0)) == noData)
422
                                return true;
423
                        break;
424
                }
425
                return false;
426
        }
427

    
428
        /*
429
         * (non-Javadoc)
430
         * @see org.gvsig.fmap.dal.coverage.store.props.Transparency#free()
431
         */
432
        public void free() {
433
                if (mask != null)
434
                        mask.free();
435
                if (originalData != null)
436
                        originalData.free();
437
                mask = null;
438
                originalData = null;
439
        }
440

    
441
        /*
442
         * (non-Javadoc)
443
         * @see org.gvsig.tools.persistence.Persistent#loadFromState(org.gvsig.tools.persistence.PersistentState)
444
         */
445
        @SuppressWarnings("unchecked")
446
        public void loadFromState(PersistentState state)
447
        throws PersistenceException {                
448
                if (state.hasValue("opacity")){
449
                        opacity = state.getInt("opacity");
450
                }
451
                transparencyRanges = new ArrayList<TransparencyRange>(state.getList("transparencyRange"));        
452
                if (state.hasValue("bandnumber")){
453
                        alphaBandNumber = state.getInt("bandnumber");
454
                }
455
        }
456

    
457
        /*
458
         * (non-Javadoc)
459
         * @see org.gvsig.tools.persistence.Persistent#saveToState(org.gvsig.tools.persistence.PersistentState)
460
         */
461
        public void saveToState(PersistentState state) throws PersistenceException {
462
                if(getOpacity() != 255){
463
                        state.set("opacity", getOpacity());
464
                }        
465

    
466
                //Rangos de transparencia                
467
                state.set("transparencyRange", transparencyRanges);
468

    
469
                if(getAlphaBandNumber() != -1) {
470
                        state.set("bandnumber", getAlphaBandNumber());
471
                }
472
        }
473
        
474
        /*
475
         * (non-Javadoc)
476
         * @see org.gvsig.fmap.dal.coverage.store.props.Transparency#activeTransparency()
477
         */
478
        public void activeTransparency() {
479
                
480
        }
481
        
482
        /*
483
         * (non-Javadoc)
484
         * @see org.gvsig.fmap.dal.coverage.store.props.Transparency#getGridTransparency()
485
         */
486
        public GridTransparency getGridTransparency() {
487
                return new GridTransparencyImpl(this);
488
        }        
489

    
490
        public static void registerPersistent() {
491
                PersistenceManager manager = ToolsLocator.getPersistenceManager();
492
                DynStruct definition = manager.addDefinition(
493
                                Transparency.class,
494
                                PERSISTENCE_NAME,
495
                                "Transparency Persistent definition (FIXME)",
496
                                null, 
497
                                null
498
                );
499
                definition.addDynFieldInt("opacity");
500
                definition.addDynFieldInt("bandnumber");
501
                definition.addDynFieldList("transparencyRange")
502
                        .setClassOfItems(TransparencyRange.class);
503
        }
504
}