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 |
} |