svn-gvsig-desktop / trunk / docs / Cresques / Cresques.html @ 18386
History | View | Annotate | Download (48.4 KB)
1 |
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
---|---|
2 |
<HTML>
|
3 |
<HEAD>
|
4 |
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=iso-8859-15"> |
5 |
<TITLE>Cresques</TITLE> |
6 |
<META NAME="GENERATOR" CONTENT="OpenOffice.org 1.1.0 (Linux)"> |
7 |
<META NAME="CREATED" CONTENT="20050622;16400400"> |
8 |
<META NAME="CHANGED" CONTENT="20050901;10340300"> |
9 |
<STYLE>
|
10 |
<!--
|
11 |
@page { size: 21cm 29.7cm; margin-left: 2cm; margin-right: 1.06cm; margin-top: 1.06cm; margin-bottom: 1.06cm }
|
12 |
TD P { color: #676767; font-family: "Verdana", "Arial", "Helvetica", sans-serif; font-size: 9pt; font-style: normal; text-align: justify }
|
13 |
P { font-family: "Verdana", "Arial", "Helvetica", sans-serif; font-size: 9pt; text-align: justify }
|
14 |
PRE { margin-left: 5cm }
|
15 |
A:link { color: #e86d26; font-family: "Verdana", "Arial", "Helvetica", sans-serif; font-size: 9pt; font-style: normal }
|
16 |
-->
|
17 |
</STYLE>
|
18 |
</HEAD>
|
19 |
<BODY LANG="es-ES" LINK="#e86d26" DIR="LTR"> |
20 |
<TABLE WIDTH=600 BORDER=0 CELLPADDING=2 CELLSPACING=0 STYLE="page-break-before: always"> |
21 |
<COL WIDTH=30> |
22 |
<COL WIDTH=562> |
23 |
<TR>
|
24 |
<TD WIDTH=30> |
25 |
<P> </P> |
26 |
</TD>
|
27 |
<TD WIDTH=562 BGCOLOR="#e86d26"> |
28 |
<P><A HREF="#Intro"><SPAN STYLE="background: #e86d26"><B><FONT COLOR="#ffffff">1. |
29 |
Introducción</FONT></B></SPAN></A></P> |
30 |
</TD>
|
31 |
</TR>
|
32 |
<TR>
|
33 |
<TD WIDTH=30> |
34 |
<P><BR> |
35 |
</P>
|
36 |
</TD>
|
37 |
<TD WIDTH=562 BGCOLOR="#e86d26"> |
38 |
<P><A HREF="#Filtros"><SPAN STYLE="background: #e86d26"><B><FONT COLOR="#ffffff">2.Drivers</FONT></B></SPAN></A></P> |
39 |
</TD>
|
40 |
</TR>
|
41 |
<TR>
|
42 |
<TD WIDTH=30> |
43 |
<P><BR> |
44 |
</P>
|
45 |
</TD>
|
46 |
<TD WIDTH=562> |
47 |
<P> <A HREF="#DLectura">2.1 Drivers de lectura</A></P> |
48 |
</TD>
|
49 |
</TR>
|
50 |
<TR>
|
51 |
<TD WIDTH=30> |
52 |
<P><BR> |
53 |
</P>
|
54 |
</TD>
|
55 |
<TD WIDTH=562> |
56 |
<P> <A HREF="#DEscritura">2.2 Drivers de |
57 |
escritura</A></P> |
58 |
</TD>
|
59 |
</TR>
|
60 |
<TR>
|
61 |
<TD WIDTH=30> |
62 |
<P> </P> |
63 |
</TD>
|
64 |
<TD WIDTH=562 BGCOLOR="#e86d26"> |
65 |
<P><A HREF="#Filtros"><SPAN STYLE="background: #e86d26"><B><FONT COLOR="#ffffff">3.Filtros</FONT></B></SPAN></A></P> |
66 |
</TD>
|
67 |
</TR>
|
68 |
<TR>
|
69 |
<TD WIDTH=30> |
70 |
<P> </P> |
71 |
</TD>
|
72 |
<TD WIDTH=562> |
73 |
<P> <A HREF="#NewFiter">3.1 Creación de |
74 |
un nuevo filtro</A></P> |
75 |
</TD>
|
76 |
</TR>
|
77 |
<TR>
|
78 |
<TD WIDTH=30> |
79 |
<P><BR> |
80 |
</P>
|
81 |
</TD>
|
82 |
<TD WIDTH=562> |
83 |
<P> <A HREF="#ManageFilter">3.2 Gestión |
84 |
de un nuevo filtro</A></P> |
85 |
</TD>
|
86 |
</TR>
|
87 |
<TR>
|
88 |
<TD WIDTH=30> |
89 |
<P><BR> |
90 |
</P>
|
91 |
</TD>
|
92 |
<TD WIDTH=562 BGCOLOR="#eb613d"> |
93 |
<P><A HREF="#Interfaces"><SPAN STYLE="background: #e86d26"><B><FONT COLOR="#ffffff">4.Interfaces |
94 |
Gráficas</FONT></B></SPAN></A></P> |
95 |
</TD>
|
96 |
</TR>
|
97 |
<TR>
|
98 |
<TD WIDTH=30> |
99 |
<P><BR> |
100 |
</P>
|
101 |
</TD>
|
102 |
<TD WIDTH=562> |
103 |
<P> <A HREF="#InterfazPropiedades">4.1 Interfaz |
104 |
de Propiedades</A></P> |
105 |
</TD>
|
106 |
</TR>
|
107 |
<TR>
|
108 |
<TD WIDTH=30> |
109 |
<P><BR> |
110 |
</P>
|
111 |
</TD>
|
112 |
<TD WIDTH=562> |
113 |
<P> <A HREF="#InterfazSalvar">4.1 Interfaz de |
114 |
salvar a raster </A>
|
115 |
</P>
|
116 |
</TD>
|
117 |
</TR>
|
118 |
</TABLE>
|
119 |
<P><STRONG><FONT SIZE=5>1.Introducción</FONT></STRONG></P> |
120 |
<P STYLE="margin-bottom: 0cm"> La librería |
121 |
de Cresques consta de los siguientes elementos:</P>
|
122 |
<UL>
|
123 |
<LI><P STYLE="margin-bottom: 0cm">Un interfaz homogeneo de acceso a |
124 |
los datos de todos los formatos soportados . |
125 |
</P>
|
126 |
<LI><P STYLE="margin-bottom: 0cm">Drivers de acceso de lectura a |
127 |
formatos raster georeferenciados como ecw, mrsid, tif, jpg, png a |
128 |
través de sus respectivas librerias.
|
129 |
</P>
|
130 |
<LI><P STYLE="margin-bottom: 0cm">Drivers de acceso a formatos Dxf y |
131 |
gml. |
132 |
</P>
|
133 |
<LI><P STYLE="margin-bottom: 0cm">Drivers de escritura para GeoTiff |
134 |
y Ecw(solo linux kernel 2.4) |
135 |
</P>
|
136 |
<LI><P STYLE="margin-bottom: 0cm">Una arquitectura para filtros |
137 |
sobre los formatos raster soportados. |
138 |
</P>
|
139 |
<LI><P STYLE="margin-bottom: 0cm">Una interfaz gráfica en |
140 |
java para la gestión de filtros.
|
141 |
</P>
|
142 |
<LI><P STYLE="margin-bottom: 0cm">Una interfaz gráfica en |
143 |
java para el manejo del salvado a raster. |
144 |
</P>
|
145 |
</UL>
|
146 |
<P STYLE="margin-left: 0.02cm"><A NAME="Drivers"></A><STRONG><FONT SIZE=5>2. |
147 |
Drivers</FONT></STRONG></P> |
148 |
<P STYLE="margin-left: 0.02cm"> Los drivers de |
149 |
Cresques son clases que contiene un interfaz de acceso a un tipo de |
150 |
fichero a través de una librería o implementando sus |
151 |
propias funcionalidades. Para el acceso a Ecw, MrSID y Gdal utiliza |
152 |
librerias externas en C por lo que deberán estar instaladas
|
153 |
correctamente para hacer uso de estos drivers. Las librerias externas |
154 |
al estar en C necestan un interfaz para el uso desde java. Este |
155 |
interfaz puede constar de otra librería en C que debe estar
|
156 |
también instalada y un fichero .jar con las funciones en java
|
157 |
de acceso a la librería que debe estar en el classpath. El
|
158 |
directorio depend del proyecto de Cresques contiene las librerias C |
159 |
necesarias y el directorio lib las de java. |
160 |
</P>
|
161 |
<P STYLE="margin-left: 0.02cm"> Los drivers de |
162 |
lectura y escritura para un mismo tipo de fichero están
|
163 |
separadas en clases disintas. |
164 |
</P>
|
165 |
<P STYLE="margin-left: 0.02cm"><A NAME="DLectura"></A><STRONG><FONT SIZE=4>2.1 |
166 |
Drivers de lectura</FONT></STRONG></P> |
167 |
<P STYLE="margin-left: 0.02cm"> El nombre de la |
168 |
clase de un driver de lectura está compuesto por el tipo de
|
169 |
fichero al que accede seguido de la palabra File, así tenemos
|
170 |
los siguientes drivers de lectura:</P>
|
171 |
<UL>
|
172 |
<LI><P STYLE="margin-bottom: 0cm">EcwFile para el driver de acceso a |
173 |
ficheros con formato ecw.</P>
|
174 |
<LI><P STYLE="margin-bottom: 0cm">MrSIDFile para el driver de acceso |
175 |
a ficheros con formato MrSID.</P>
|
176 |
<LI><P STYLE="margin-bottom: 0cm">GdalFile para el acceso a ficheros |
177 |
raster a través de la librería gdal.</P> |
178 |
<LI><P STYLE="margin-bottom: 0cm">DxfFile para acceso a ficheros |
179 |
dxf.</P>
|
180 |
<LI><P STYLE="margin-bottom: 0cm">GmlFile para acceso a ficheros |
181 |
gml.</P>
|
182 |
</UL>
|
183 |
<P STYLE="margin-left: 0.02cm; margin-bottom: 0cm"> |
184 |
Los drivers de lectura de acceso a raster hereda todos de una misma |
185 |
clase abstracta GeoRasterFile para darles a todos ellos una interfaz |
186 |
homogenea de acceso a los datos. Los drivers que dependen de |
187 |
GeoRasterFile deben usar un mecanismo de registro para ser accesible. |
188 |
Este mecanismo permite que si creamos un driver fuera de cresques |
189 |
pero que herede de GeoRasterFile sea reconocido por este y pueda |
190 |
accederse a su funcionalidad. Para el registro, el driver en cuestión
|
191 |
deberá incluir un bloque static en su código y añadir |
192 |
una entrada en la variable TreeMap supportedExtensions de |
193 |
GeoRasterFile con el nombre del driver y la clase que lo implementa. |
194 |
Esto se hará con la función registerExtension. Por |
195 |
ejemplo, si quisieramos hacer un driver para acceso a Jpg que use |
196 |
nuestra propia librería le incluiriamos un código como |
197 |
este:</P>
|
198 |
<P STYLE="margin-left: 0.02cm; margin-bottom: 0cm"><BR> |
199 |
</P>
|
200 |
<PRE> static {
|
201 |
registerExtension("jpg", JpgGeoRefFile.class); |
202 |
}</PRE><P STYLE="margin-left: 0.02cm; margin-bottom: 0cm"> |
203 |
<BR>
|
204 |
</P>
|
205 |
<P STYLE="margin-left: 0.02cm; margin-bottom: 0cm"> |
206 |
Sin necesidad de instanciar la nueva clase se ejecutará el
|
207 |
bloque static asignando a la gestión de la extensión |
208 |
jpg la nueva clase creada. Como esta nuevo driver heredará de
|
209 |
GeoRasterFile tendrá el interfaz necesario para acceso a los
|
210 |
datos por lo que no habrá ningún problema. Por lo |
211 |
tanto, los métodos abstractos de GeoRasterFile son de
|
212 |
obligatoria implementación en nuestro driver. Los drivers de
|
213 |
GeoRasterFile están registrados en esta misma clase ya que son
|
214 |
drivers que no varian dentro de Cresques.</P>
|
215 |
<P STYLE="margin-left: 0.02cm; margin-bottom: 0cm"><BR> |
216 |
</P>
|
217 |
<P STYLE="margin-left: 0.02cm"><A NAME="DEscritura"></A><STRONG><FONT SIZE=4>2.2 |
218 |
Drivers de escritura</FONT></STRONG></P> |
219 |
<P STYLE="margin-left: 0.02cm"> El nombre de la |
220 |
clase de un driver de escritura está compuesto por el tipo de
|
221 |
fichero al que accede seguido de la palabra Writer, así
|
222 |
tenemos los siguientes drivers de lectura:</P>
|
223 |
<UL>
|
224 |
<LI><P STYLE="margin-bottom: 0cm">EcwWriter para el driver de |
225 |
escritura sobre ficheros con formato ecw (solo Linux kernel 2.4). |
226 |
</P>
|
227 |
<LI><P STYLE="margin-bottom: 0cm">GdalWriter para la escritura sobre |
228 |
ficheros georeferenciados a través de Gdal.</P> |
229 |
</UL>
|
230 |
<P STYLE="margin-left: 0.02cm; margin-bottom: 0cm"><BR> |
231 |
</P>
|
232 |
<P STYLE="margin-left: 0.02cm; margin-bottom: 0cm"> |
233 |
Estos drivers son para la escritura de ficheros raster |
234 |
georeferenciados. |
235 |
</P>
|
236 |
<P STYLE="margin-left: 0.02cm; margin-bottom: 0cm"><BR> |
237 |
</P>
|
238 |
<P STYLE="margin-left: 0.02cm; margin-bottom: 0cm"> |
239 |
Los drivers de escritura en raster georeferenciados deben heredar de |
240 |
la misma clase abstracta GeoRasterWriter para darles a todos ellos |
241 |
una interfaz homogenea de escritura de datos. Los drivers que |
242 |
dependen de GeoRasterFile deben usar un mecanismo de registro para |
243 |
ser accesible. Este mecanismo permite que si creamos un driver fuera |
244 |
de cresques pero que herede de GeoRasterWriter sea reconocido por |
245 |
este y pueda accederse a su funcionalidad. Para el registro, el |
246 |
driver en cuestión deberá incluir un bloque static en |
247 |
su código y añadir una entrada en la variable TreeMap |
248 |
supportedExtensions de GeoRasterFile con el nombre del driver y la |
249 |
clase que lo implementa. Esto se hará con la función |
250 |
registerWriterExtension. Por ejemplo, si quisieramos hacer un driver |
251 |
de escritura en Jpg que use nuestra propia librería le
|
252 |
incluiriamos un código como este:</P> |
253 |
<P STYLE="margin-left: 0.02cm; margin-bottom: 0cm"><BR> |
254 |
</P>
|
255 |
<PRE> static {
|
256 |
registerWriterExtension("jpg", JpgGeoRefWriter.class); |
257 |
}</PRE><P STYLE="margin-left: 0.02cm; margin-bottom: 0cm"> |
258 |
<BR>
|
259 |
</P>
|
260 |
<P ALIGN=LEFT STYLE="margin-bottom: 0cm"> Dentro |
261 |
del driver tendremos que escribir una clase que deberá
|
262 |
llamarse <NombreFormato>SupportOptions y que deberá |
263 |
heredar de WriterSupportOptions. Esta clase contendrá las
|
264 |
opciones de escritura concretas para este formato. Esta opciones son |
265 |
las que el usuario visualizará en la ventana de propiedades de
|
266 |
escritura. Es conveniente que las opciones que corresponderan a una |
267 |
lista de selección (combo) se guarden aquí como un |
268 |
vector de Strings o cualquier otro tipo de lista de esta forma:</P>
|
269 |
<PRE STYLE="margin-bottom: 0.5cm"> <FONT FACE="Nimbus Mono L">private String[] formatList = {"NONE","UINT8","YUV","MULTI","RGB"};</FONT></PRE><P ALIGN=LEFT STYLE="margin-bottom: 0cm"> |
270 |
<FONT FACE="Verdana, Arial, Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">y |
271 |
además se definan variables para los valores seleccionados por
|
272 |
defecto </FONT></FONT> |
273 |
</P>
|
274 |
<P ALIGN=LEFT STYLE="margin-bottom: 0cm"><BR> |
275 |
</P>
|
276 |
<P ALIGN=LEFT STYLE="margin-bottom: 0cm"> Deben |
277 |
crearse métodos para la lectura y escritura de todas las
|
278 |
propiedades</P>
|
279 |
<P ALIGN=LEFT STYLE="margin-bottom: 0cm"><BR> |
280 |
</P>
|
281 |
<P ALIGN=LEFT STYLE="margin-bottom: 0cm"><FONT FACE="Verdana, Arial, Helvetica, sans-serif"><FONT SIZE=2 STYLE="font-size: 9pt">El |
282 |
constructor estará vacio en funcionalidades pero llamará |
283 |
al constructor del padre pasando como parámetro un string que
|
284 |
identifica al driver.</FONT></FONT></P> |
285 |
<PRE> <FONT FACE="Nimbus Mono L">EcwSupportOptions(){</FONT> |
286 |
super("Ecw"); |
287 |
}</PRE><P ALIGN=LEFT STYLE="margin-bottom: 0cm; text-decoration: none"> |
288 |
Constructor sin parámetros:</P> |
289 |
<P ALIGN=LEFT STYLE="margin-bottom: 0cm"><BR> |
290 |
</P>
|
291 |
<P ALIGN=LEFT STYLE="margin-bottom: 0cm; text-decoration: none"> |
292 |
Este constructor inicializa el xxxSupportOptions que contiene las |
293 |
opciones de escritura y asigna valores a estas opciones especificas |
294 |
del driver que estamos implementando</P>
|
295 |
<PRE> public EcwWriter(){
|
296 |
this.support = new EcwSupportOptions(); |
297 |
this.driver = "ecw"; |
298 |
this.support.setBlockSize(64); |
299 |
this.support.setCompressionDefault(10); |
300 |
this.support.setFormatDefault(4); |
301 |
this.support.setWriteGeoref(true); |
302 |
this.ident = "Ecw"; |
303 |
this.consulta = true; |
304 |
|
305 |
}</PRE><P ALIGN=LEFT STYLE="margin-bottom: 0cm; text-decoration: none"> |
306 |
Constructor para salvar una sola imagen completa</P> |
307 |
<PRE> <FONT FACE="Nimbus Mono L">public EcwWriter( PxRaster raster, </FONT> |
308 |
String outfilename, |
309 |
String infilename, |
310 |
int compresion)throws EcwException, IOException </PRE><P ALIGN=LEFT STYLE="margin-bottom: 0cm; text-decoration: none"> |
311 |
Para este constructor se ha de pasar como |
312 |
parámetro el PxRaster de la imagen que se desea salvar a
|
313 |
disco. Se inicializará la clase xxxSupportOptions de la misma
|
314 |
forma que en el constructor anterior y se asignarán valores a
|
315 |
variables de instancia con datos para salvar a raster tales como |
316 |
georeferenciación, número de bandas, ancho, alto, |
317 |
tamaño de pixel, ...</P> |
318 |
<P STYLE="margin-left: 0.02cm; margin-bottom: 0cm"><BR> |
319 |
</P>
|
320 |
<P ALIGN=LEFT STYLE="margin-left: 0.02cm; margin-bottom: 0cm; text-decoration: none"> |
321 |
Los drivers de escritura diseñan su propia |
322 |
ventana de propiedades en java. Para ello tiene un método
|
323 |
getXMLPropertiesDialog que dice como será esta ventana. Para
|
324 |
ello debe devolver una cadena de texto con un XML que contiene esta |
325 |
configuración. El Xml deberá comenzar definiendo el |
326 |
tamaño de la ventana de esta forma:</P> |
327 |
<PRE><window sizex="340" sizey="180"> |
328 |
... Cuerpo de la ventana ... |
329 |
</window></PRE><P STYLE="margin-left: 0.02cm"> |
330 |
<SPAN STYLE="text-decoration: none"> </SPAN>Dentro |
331 |
del cuerpo de la ventana deberán definirse los panels con los
|
332 |
componentes. Solo está permitido un nivel de anidamiento y el
|
333 |
uso de Checkbox, labels, combos, sliders. |
334 |
</P>
|
335 |
<PRE><panel sizex="330" sizey="170" layout="FlowLayout" border="yes" > |
336 |
</panel> |
337 |
|
338 |
<label>Tamaño bloque: |
339 |
</label> |
340 |
|
341 |
<combo ident="BLOCKSIZE" selected="64"> |
342 |
<elem>32</elem> |
343 |
<elem>64</elem> |
344 |
<elem>128</elem> |
345 |
</combo> |
346 |
|
347 |
<check ident="GEOREF" selected="10”> |
348 |
</check></PRE><P> |
349 |
<SPAN STYLE="text-decoration: none"> </SPAN>Las |
350 |
opciones del driver que se incorporan pueden ser almacenadas y |
351 |
consultadas en una clase que herede de WriteSupportOptions. |
352 |
WriterSupportOptions contiene todas las opciones de salvado comunes a |
353 |
todos los drivers. Por ejemplo, el driver de escritura de ecw tendrá
|
354 |
una clase EcwSupportOptions con las opciones especificas de salvado. |
355 |
</P>
|
356 |
<P STYLE="margin-left: 0.02cm; text-decoration: none"> |
357 |
El salvado a raster puede realizarse en dos modos:</P>
|
358 |
<UL>
|
359 |
<LI><P STYLE="text-decoration: none">El primero se hace a partir de |
360 |
un GeoRasterFile leyendo datos de una imagen raster soportada de |
361 |
entrada y salvandolos en la imagen de la salida. Este método
|
362 |
es rapido y directo para la conversión de unos formatos
|
363 |
raster a otros. Para esta forma se usa el método fileWrite.</P> |
364 |
<LI><P STYLE="text-decoration: none">El segundo se realiza salvando |
365 |
la imagen a partir de los datos pasados por un cliente utilizando el |
366 |
método dataWrite. En la construcción del filtro se |
367 |
especificará el tamaño de la imagen de salida, nombre |
368 |
de la misma, coordenadas de georeferenciación, compresión |
369 |
si la hubiere, ... Cuando se invoca el método dataWrite
|
370 |
solicitará datos al cliente cuando vacie su buffer hasta que
|
371 |
haya terminado con toda la imagen. De esta forma es el escritor el |
372 |
que controla el flujo de bytes y el cliente puede salvar a raster |
373 |
cualquier dato que quiera y que venga de otras fuentes. De esta |
374 |
forma podriamos tener una aplicación con una vista que
|
375 |
deseemos salvar a raster, si somos capaces de leer los bytes de ella |
376 |
podemos crear un flujo de datos para salvarlos. |
377 |
</P>
|
378 |
<P STYLE="text-decoration: none">El cliente debe crear una clase |
379 |
servidora de datos. Un ejemplo de esto es la clase Rasterizer que |
380 |
debe implementar el interfaz IDataWriter que obliga al método
|
381 |
readData. Este servidor de datos se pasará en el constructor
|
382 |
del driver de escritura y lo utilizará para solicitar los
|
383 |
datos. Por esto, es el cliente el encargado de controlar los datos |
384 |
que ha pasado y los que le quedan por pasar. El driver irá
|
385 |
cogiendo hasta que complete la ventana que necesita.</P>
|
386 |
<P STYLE="text-decoration: none">En la clase Rasterizer a partir de |
387 |
una capa de PxRaster (PxLayerList) se crea calcula el recuadro del |
388 |
trozo de la vista que se necesita en cada petición, se leen
|
389 |
los datos desde un image y se devuelven en forma de array de |
390 |
enteros. Será el driver el que escriba a disco ese array. En
|
391 |
general, si se necesita hacer uso de salvar a raster se deberá
|
392 |
escribir una clase como Rasterizer para el caso concreto que estamos |
393 |
tratando. GvSIG hace uso de esta funcionalidad a través de la
|
394 |
clase RasterizerLayer en el paquete com.iver.cit.gvsig, la cual |
395 |
sirve los datos para salvar a raster una vista.</P>
|
396 |
<P STYLE="text-decoration: none">Normalmente la escritura de las |
397 |
imagenes debe ser por franjas. Cada franja tiene la anchura total de |
398 |
la imagen y una altura que viene definida por el tamaño de
|
399 |
bloque que el usuario podría variar en la ventana de
|
400 |
propiedades del driver.</P>
|
401 |
</UL>
|
402 |
<P ALIGN=LEFT><A NAME="Filtros"></A><A NAME="NewFiter"></A><STRONG><FONT SIZE=5>3. |
403 |
Filtros</FONT></STRONG><BR><BR><STRONG><FONT SIZE=4>3.1 Creación |
404 |
de un nuevo filtro</FONT></STRONG></P> |
405 |
<P STYLE="margin-left: 0.02cm"> Crear una nueva |
406 |
clase abstracta que heredará de RasterFilter y que tendrá |
407 |
como nombre el nombre del filtro (en inglés a poder ser)
|
408 |
seguido de Filter. Usaremos como ejemplo la generación del
|
409 |
filtro de transparencia. En este caso, esta clase abstracta debe |
410 |
llamarse TransparencyFilter. |
411 |
</P>
|
412 |
<P> Crear una clase que hereda de esta clase que |
413 |
hemos creado para cada tipo de dato básico que se da soporte.
|
414 |
En nuestro caso dos clases heredan de TransparencyFilter y son |
415 |
TransparencyImageFilter y TransparencyShortFilter. Notese que la |
416 |
nomenclatura hace referencia al tipo de dato que maneja. La primera |
417 |
funciona para objetos Image de java y la segunda para imágenes
|
418 |
de 16 bits.Estas últimas están representadas por una |
419 |
clase llamada RasterBuf. Si fuera necesario debería hacerse
|
420 |
para Float, Double, ... |
421 |
</P>
|
422 |
<P> El constructor de los filtros es recomendable |
423 |
que esté vacio.</P> |
424 |
<P> En la clase base del filtro que estamos creando |
425 |
(TransparencyFilter) deben ponerse las variables de instancia que |
426 |
contengan los parámetros necesarios para el filtro. En este
|
427 |
caso tendriamos 3 vectores bidimensionales que contendran los |
428 |
intervalos de valores a poner como transparentes y cuatro enteros que |
429 |
representan el alpha y el color de transparencia en caso de querer |
430 |
proporcionar alguno. Por defecto será blanco, es decir
|
431 |
totalmente transparente y sin ninguna tonalidad.</P>
|
432 |
<P> Aquí deben ponerse también todas |
433 |
las funcionalidades comunes a todos los tipos de filtro de |
434 |
transparencia. Como TransparencyFilter hereda de RasterFilter que es |
435 |
abstracta y tiene métodos abstractos obligará a |
436 |
implementar estos. Si es necesario que estos métodos
|
437 |
abstractos tengan código podemos implementarlos aquí |
438 |
sino podrá hacerse en las clases hijas que contienen la
|
439 |
especificación para el filtro de transparencia sobre cada tipo
|
440 |
de dato concreto. Los métodos abstractos que es preciso
|
441 |
implementar son:</P>
|
442 |
<UL>
|
443 |
<LI><P><B>abstract public void pre();</B> .</P> |
444 |
</UL>
|
445 |
<P> Aquí pondremos las operaciones que hay |
446 |
que realizar antes de ejecutar el filtro que estamos creando. En |
447 |
nuestro caso está implementado en la clase base del filtro y
|
448 |
en las hijas . En la clase base tiene código común para |
449 |
los filtros de transparencia de cualquier tipo de datos.</P>
|
450 |
<PRE> public void pre(){
|
451 |
this.rangesR = (int[][])params.get("red"); |
452 |
this.rangesG = (int[][])params.get("green"); |
453 |
this.rangesB = (int[][])params.get("blue"); |
454 |
this.alpha = ((Integer)params.get("alpha")).intValue(); |
455 |
this.transparencyColorRed = ((Integer)params.get("transparencyRed")).intValue(); |
456 |
this.transparencyColorGreen = ((Integer)params.get("transparencyGreen")).intValue(); |
457 |
this.transparencyColorBlue = ((Integer)params.get("transparencyBlue")).intValue(); |
458 |
}</PRE><P> |
459 |
En las clases hijas se pone la implementación |
460 |
concreta para ese tipo de dato. En el caso de la transparencia sobre |
461 |
un Image obtenemos el parámetro que contiene la Image y
|
462 |
asignamos los valore de altura y anchura de raster a partir de este |
463 |
Image. Antes de finalizar llama al pre() de TransparencyFilter.</P>
|
464 |
<PRE> public void pre(){
|
465 |
this.image = (Image)params.get("raster"); |
466 |
height = image.getHeight(null); |
467 |
width = image.getWidth(null); |
468 |
super.pre(); |
469 |
}</PRE>
|
470 |
<UL>
|
471 |
<LI><P><B>abstract public void post();</B></P> |
472 |
</UL>
|
473 |
<P> Aquí se ponen las operaciones a realizar |
474 |
después de ejecutar el filtro. En el caso que estamos viendo
|
475 |
no es necesario hacer nada por lo que estará vacio. Podria ser
|
476 |
necesario alguna operación como por ejemplo cargar el
|
477 |
resultado de la operación en alguna variable de salida o algo
|
478 |
así.</P> |
479 |
<UL>
|
480 |
<LI><P><B>abstract public void process(int x, int y);</B></P> |
481 |
</UL>
|
482 |
<P> Este método es el encargado de procesar |
483 |
el filtro para un pixel de la imagen. La clase abstracta RasterFilter |
484 |
de la cual heredan todos los filtros tiene el metodo execute() que |
485 |
hará lo siguiente:</P> |
486 |
<PRE> pre();
|
487 |
for (int y=0; y<height; y=y+incY)
|
488 |
for (int x=0; x<width; x=x+incX) {
|
489 |
process(x, y); |
490 |
} |
491 |
post();</PRE><P> |
492 |
Por esto debemos tener en process el código |
493 |
que ejecuta el filtro. Esto siempre suele rellenarse en las clases |
494 |
que representan a un filtro de un tipo de dato concreto. Para nuestro |
495 |
ejemplo en TransparencyImageFilter el process tendrá el
|
496 |
siguiente código:</P> |
497 |
<PRE> public void process(int x, int y) {
|
498 |
int pt = ((BufferedImage) image).getRGB(x,y); |
499 |
int []px4 = {(pt & 0xff000000) >> 24,(pt & 0xff0000) >> 16, (pt & 0x00ff00) >> 8, (pt & 0x0000ff)}; |
500 |
if(rangesR!=null) |
501 |
processRange(rangesR, 1, px4); |
502 |
if(rangesG!=null) |
503 |
processRange(rangesG, 2, px4); |
504 |
if(rangesB!=null) |
505 |
processRange(rangesB, 3, px4); |
506 |
((BufferedImage) image).setRGB(x,y, ( |
507 |
(px4[0] << 24) & 0xff000000 | (px4[1] << 16) & 0x00ff0000 | |
508 |
(px4[2] << 8) & 0x0000ff00 | (px4[3] & 0x0000ff) )); |
509 |
}</PRE><P> |
510 |
<BR><BR> |
511 |
</P>
|
512 |
<P> Esta función obtendrá el pixel |
513 |
del buffer lo procesará y salvará el resultado sobre el |
514 |
mismo buffer.</P>
|
515 |
<UL>
|
516 |
<LI><P><B>abstract public void processLine(int y);</B></P> |
517 |
</UL>
|
518 |
<P> Esta función realizará el mismo |
519 |
proceso que process(int x, int y) pero aplicada directamente a una |
520 |
línea del buffer.</P> |
521 |
<UL>
|
522 |
<LI><P><B>abstract public int getInRasterDataType();</B></P> |
523 |
</UL>
|
524 |
<P> Devuelve el tipo de dato del buffer de entrada. |
525 |
La clase RasterBuf tiene constantes que tiene todos los tipos de |
526 |
datos posibles por lo que puede realizarse algo así:</P> |
527 |
<PRE> public int getInRasterDataType(){
|
528 |
return RasterBuf.TYPE_IMAGE; |
529 |
<I>} </I> </PRE> |
530 |
<UL>
|
531 |
<LI><P><B>abstract public int getOutRasterDataType();</B></P> |
532 |
</UL>
|
533 |
<P> Devuelve el tipo de dato del buffer de salida. |
534 |
La clase RasterBuf tiene constantes que tiene todos los tipos de |
535 |
datos posibles por lo que puede realizarse algo así:
|
536 |
</P>
|
537 |
<PRE> public int getOutRasterDataType(){
|
538 |
return RasterBuf.TYPE_IMAGE; |
539 |
}</PRE>
|
540 |
<UL>
|
541 |
<LI><P><B>abstract public Object getResult(String name);</B></P> |
542 |
</UL>
|
543 |
<P> Obtiene el resultado del filtro en un Object. |
544 |
Para esto se la pasa un parámetro con la clave del resultado y
|
545 |
nos devolverá el Object correspondiente. Esto es necesario
|
546 |
porque un mismo filtro puede tener varias salidas, por ejemplo puede |
547 |
tener un raster con el resultado de aplicar el filtro y una clase con |
548 |
algunas estadisticas calculadas en el proceso. En este caso el filtro |
549 |
de transparencia solo devuelve un raster de salida por lo que se hará
|
550 |
una función por tipo de dato tal que:</P> |
551 |
<PRE> public Object getResult(String name){
|
552 |
if(name.equals("raster")) |
553 |
return (Object)this.image; |
554 |
else |
555 |
return null; |
556 |
<FONT SIZE=2 STYLE="font-size: 9pt">}</FONT></PRE><P> |
557 |
Esta es la que se hará para |
558 |
TransparencyImageFilter ya que devuelve un tipo Image.</P>
|
559 |
<P><A NAME="ManageFilter"></A><BR> <BR><STRONG><FONT SIZE=4>3.2 |
560 |
Gestión de un nuevo filtro</FONT></STRONG></P> |
561 |
<P> Para el almacenaje de filtros seleccionados hay |
562 |
una clase llamada RasterFilterStack que contiene la pila de filtros y |
563 |
que es generica para cualquier tipo de filtro realizado, es decir, en |
564 |
condiciones normales, en la creación de un nuevo filtro esta
|
565 |
clase no debe tocarse. Sin embargo si debe añadirse la gestión |
566 |
del nuevo filtro con filterStackManager . Para añadir este
|
567 |
nuevo filtro deberá crearse una nueva clase que heredará |
568 |
de RasterFilterStackManager. RasterFilter esla encargada de añadir
|
569 |
filtros a la pila ya que ella es la que sabrá el orden en el
|
570 |
que deben ir estos . Un orden de la pila incorrecto da un resultado |
571 |
de aplicaciones de filtros indeseado. Con esto deducimos que la pila |
572 |
es tratada como tal para la ejecución de filtros pero que
|
573 |
estos deben estar de antemano ordenados correctamente por lo que no |
574 |
es una pila en el sentido estricto.</P>
|
575 |
<P> Este nuevo gestor de filtros deberá |
576 |
implementar la interfaz StackManager de forma que la definición
|
577 |
de nuestra nueva clase sería más o menos asi:</P> |
578 |
<PRE>public class PruebaStackManager extends RasterFilterStackManager implements StackManager{
|
579 |
... |
580 |
}</PRE><P> |
581 |
Para el nuevo filtro debe añadirse en esta |
582 |
nueva clase una constante que represente el tipo del nuevo filtro. Lo |
583 |
más lógico es darle un número de orden |
584 |
consecutivo a las que hay pero podría asignarse otro en caso
|
585 |
de haber una causa justificada. Las actualmente asignadas en la |
586 |
RasterFilterStackManager son |
587 |
</P>
|
588 |
<PRE> <I>transparency = 0;</I> |
589 |
enhanced=1; |
590 |
computeminmax=2; |
591 |
tail=3;</PRE><P> |
592 |
El vector order de RasterFilterStackManager |
593 |
contiene la forma de ordenación de los filtros de la pila.
|
594 |
Este orden es importante, por ejemplo la transparencia debe aplicarse |
595 |
despues del realce de la imagen ya que esta se aplica a rangos de |
596 |
colores y antes o después del realce los rangos de colores
|
597 |
difieren por lo que la transparencia debe aplicarse sobre la imagen |
598 |
realzada y no al revés. Para asignar este nuevo order
|
599 |
deberemos indicarlo en el constructor de esta clase que hemos creado.</P>
|
600 |
<PRE> public PruebaStackManager(RasterFilterStack filterStack){
|
601 |
super(filterStack); |
602 |
addTypeFilter("prueba", PruebaStackManager.prueba, 2); |
603 |
}</PRE><P> |
604 |
<BR><BR> |
605 |
</P>
|
606 |
<P> Habrá que elegir una posición |
607 |
para el nuevo filtro creado para que produzca el resultado deseado. |
608 |
La función addTypeFilter tendrá como parámetros |
609 |
en nombre del filtro, constante asignada y posición para la
|
610 |
ordenación. Si introducimos el nuevo filtro en la posición |
611 |
3 la ordenación inicial:</P> |
612 |
<PRE STYLE="margin-bottom: 0.5cm">computeminmax, tail, enhanced, transparency </PRE><P> |
613 |
<BR><BR> |
614 |
</P>
|
615 |
<P>quedará |
616 |
</P>
|
617 |
<PRE STYLE="margin-bottom: 0.5cm">computeminmax, tail, prueba, enhanced, transparency </PRE><P> |
618 |
<BR><BR> |
619 |
</P>
|
620 |
<P>ya que la posición en el vector de ordenación tiene |
621 |
en cuenta la posición 0.</P> |
622 |
<P> En RasterFilterStackManager también |
623 |
existe una función llamada getType que devuelve el tipo de
|
624 |
filtro que contiene un RasterFilter. Deberemos añadir el
|
625 |
nuestro para una correcta gestión. Para ello sobrescribiremos
|
626 |
el método getType de esta forma:</P> |
627 |
<PRE> public int getType(RasterFilter rasterFilter){
|
628 |
if(rasterFilter instanceof <<NuestoFiltro>>) |
629 |
return PruebaStackManager.<<Nuestra constante>>; |
630 |
|
631 |
return super.getType(rasterFilter); |
632 |
}</PRE><P> |
633 |
<BR><BR> |
634 |
</P>
|
635 |
<P>sustituyendo <<NuestroFiltro>> por el nombre de la |
636 |
clase abstracta base del filtro que hemos construido y <<Nuestra |
637 |
constante>> por la constante que representa nuestro filtro.</P> |
638 |
<P> Dentro de nuestra clase habrá que |
639 |
definir una función para añadir el nuevo filtro. Esta |
640 |
función debe tener como argumentos los parámetros |
641 |
necesarios para el nuevo filtro. En el caso de un filtro de |
642 |
transparencia podrian ser los intervalos para RGB y el color de |
643 |
transparencia.</P>
|
644 |
<P> En esta función hay que hacer algunas |
645 |
acciones obligatorias y otras opcionales. Podemos verlas sobre un |
646 |
ejemplo:</P>
|
647 |
<P> Cabecera de la función ya comentada:</P> |
648 |
<P><BR><BR> |
649 |
</P>
|
650 |
<PRE> public void addTransparencyFilter( int[][] red,
|
651 |
int[][] green, |
652 |
int[][] blue, |
653 |
int alpha, |
654 |
int transparencyRed, |
655 |
int transparencyGreen, |
656 |
int transparencyBlue){ |
657 |
</PRE><P> |
658 |
Es necesario crear un RasterFilter de un tipo u |
659 |
otro dependiendo del tipo de dato que nos diga la pila que necesita. |
660 |
El método
|
661 |
filterStack.getDataTypeInFilter(RasterFilterStackManager.transparency) |
662 |
devuelve el tipo de dato que necesitamos si el filtro que vamos a |
663 |
meter es de transparencia. Esta función de la pila calculará |
664 |
en que posición debe ir el filtro y que tipo de dato devuelve
|
665 |
el que tendrá por encima, por lo tanto sabremos de que tipo es
|
666 |
el filtro que debemos crear. Podemos hacer la selección con un
|
667 |
switch de esta forma:</P>
|
668 |
<PRE> RasterFilter filtro = null;
|
669 |
switch(filterStack.getDataTypeInFilter(((Integer)typeFilters.get("transparency")).intValue())){ |
670 |
case RasterBuf.TYPE_IMAGE:filtro = new TransparencyImageFilter();break; |
671 |
case RasterBuf.TYPE_SHORT: |
672 |
case RasterBuf.TYPE_USHORT: |
673 |
case RasterBuf.TYPE_INT:filtro = new TransparencyShortFilter();break; |
674 |
}</PRE><P> |
675 |
<BR><BR> |
676 |
</P>
|
677 |
<P> Si tiene parámetros deberemos añadirlos |
678 |
al filtro creado con addParam. Cada parámetro debe ser añadido |
679 |
con una clave. Esta debe coincidir con la que definimos para su |
680 |
recuperación en el método pre() del filtro.</P> |
681 |
<PRE> if(red != null)filtro.addParam("red", red); |
682 |
if(green != null)filtro.addParam("green", green); |
683 |
if(blue != null)filtro.addParam("blue", blue); |
684 |
filtro.addParam("alpha", new Integer(alpha)); |
685 |
filtro.addParam("transparencyRed", new Integer(transparencyRed)); |
686 |
filtro.addParam("transparencyGreen", new Integer(transparencyGreen)); |
687 |
filtro.addParam("transparencyBlue", new Integer(transparencyBlue));</PRE><P> |
688 |
En este momento podriamos añadir el filtro |
689 |
a la pila con addFilter si no necesitara ninguna restricción.
|
690 |
En este caso tenemos que añadir código para comprobar |
691 |
que si hay filtros equivalentes no será necesario añadir |
692 |
el nuevo o si hay varios filtros de transparencia que están
|
693 |
contenidos en el nuevo tendremos que eliminar estos y añadir
|
694 |
el nuevo.</P>
|
695 |
<PRE> //Elimina los filtros que son equivalentes a este
|
696 |
|
697 |
for(int i=0;i<filterStack.lenght();i++){
|
698 |
if( filterStack.get(i) instanceof TransparencyImageFilter || |
699 |
filterStack.get(i) instanceof TransparencyShortFilter){ |
700 |
|
701 |
//Si este filtro es equivalente a uno de la pila se elimina este |
702 |
if(((TransparencyFilter)filtro).isEquivalent((TransparencyFilter)filterStack.get(i))) |
703 |
filterStack.removeFilter(filterStack.get(i)); |
704 |
|
705 |
} |
706 |
} |
707 |
//Añade el filtro si no hay uno equivalente
|
708 |
|
709 |
boolean equivalentFilter = false; |
710 |
for(int i=0;i<filterStack.lenght();i++){
|
711 |
if( filterStack.get(i) instanceof TransparencyImageFilter || |
712 |
filterStack.get(i) instanceof TransparencyShortFilter){ |
713 |
|
714 |
//Si no existe en la pila un filtro equivalente se añade
|
715 |
if(((TransparencyFilter)filterStack.get(i)).isEquivalent((TransparencyFilter)filtro)){ |
716 |
equivalentFilter = true; |
717 |
break; |
718 |
} |
719 |
} |
720 |
} |
721 |
if(!equivalentFilter) |
722 |
filterStack.addFilter(RasterFilterStackManager.transparency, filtro); |
723 |
}</PRE><P> |
724 |
Teniendo la nueva función para añadir |
725 |
filtro ya podremos añadirlo desde un dialogo creando un
|
726 |
RasterFilterStackManager o usando uno ya creado y leyendo los |
727 |
parámetros del filtro desde el cuadro (también podemos |
728 |
ponerlos fijos si nos interesa). En nuestro caso:</P>
|
729 |
<PRE>stackManager.addTransparencyFilter( contentPane.getRangeRed(), //Parámetros leidos desde el dialogo contentPane.getRangeGreen(), |
730 |
contentPane.getRangeBlue(), |
731 |
0x10, //Parámetros a valor fijo
|
732 |
0xff, |
733 |
0xff, |
734 |
0xff);</PRE><P> |
735 |
Para que sea posible salvar el estado de un raster |
736 |
cuando se salva un proyecto y se le hayan aplicado filtros es |
737 |
necesario codificar esta posibilidad para ello deberemos crear dos |
738 |
métodos obligados por el interfaz en nuestro Manager. Estos
|
739 |
son:</P>
|
740 |
<PRE> public ArrayList getStringsFromStack(RasterFilter rf); y
|
741 |
public void createStackFromStrings(ArrayList f, Integer pos);</PRE><P> |
742 |
En el primero es para añadir las cadenas al |
743 |
XML que salva el proyecto y habrá que comprobar si primero si
|
744 |
el RasterFilter pasado es instancia de este filtro que estamos |
745 |
implementando y si lo es añadir las cadenas adecuadas de esta
|
746 |
forma:</P>
|
747 |
<PRE> public ArrayList getStringsFromStack(RasterFilter rf){
|
748 |
if(rf instanceof PruebaFilter){ |
749 |
filterList.add("filter.prueba.active=true"); |
750 |
} |
751 |
}</PRE><P> |
752 |
El segundo es para recuperar el estado de un |
753 |
proyecto. Para ello lo primero que deberemos hacer es recuperar del |
754 |
array el elemento analizado, comprobar que contiene la cadena que |
755 |
representa nuestro filtro y si es así eliminar esa entrada del
|
756 |
vector ya que ya ha sido analizada y añadir las acciones que
|
757 |
conllevan la adición de nuestro filtro. En este caso un simple
|
758 |
addPruebaFilter añadirá el filtro creado cuando se |
759 |
habra un proyecto con la cadena filter.prueba.active=true.</P>
|
760 |
<PRE> public void createStackFromStrings(ArrayList f, Integer pos){
|
761 |
String fil = (String)f.get(pos); |
762 |
if(fil.startsWith("filter.prueba.active") && getValue(fil).equals("true")){ |
763 |
filters.remove(pos.intValue()); |
764 |
this.addPruebaFilter(); |
765 |
pos = -1; |
766 |
} |
767 |
}</PRE><P ALIGN=LEFT> |
768 |
<A NAME="Interfaces"></A><STRONG><FONT SIZE=5>4.Interfaces Gráficas</FONT></STRONG></P> |
769 |
<P ALIGN=LEFT><BR> Cresques tiene incluidas |
770 |
interfaces gráficas para la gestión de propiedades y |
771 |
filtros y el salvado a raster. Estas interfaces no tienen |
772 |
funcionalidad completa sino que son paneles con los controles para |
773 |
una recogida de datos desde la aplicación cliente. El cliente
|
774 |
debe insertar estos paneles dentro de sus propios frames y gestionar |
775 |
la recogida y escritura de datos. |
776 |
</P>
|
777 |
<P ALIGN=LEFT><A NAME="InterfazPropiedades"></A><BR><STRONG><FONT SIZE=4>4.1 |
778 |
Interfaz de propiedades</FONT></STRONG></P> |
779 |
<P ALIGN=LEFT> Para la gestión de los |
780 |
controles de propiedades, el cliente deberá crear una clase
|
781 |
que herede de org.cresques.ui.raster.FilterRasterDialogPanel para |
782 |
tener el acceso a los controles protected que tiene. Por ejemplo, |
783 |
podemos querer incluir los paneles dentro de un frame con un botón
|
784 |
de Aceptar, otro de Cancelar y otro de Aplicar. Un ejemplo de lo que |
785 |
aquí se explica puede encontrarse en gvSIG dentro de la clase
|
786 |
com.iver.cit.gvsig.gui.panels.PropertiesRasterDialog. |
787 |
</P>
|
788 |
<P ALIGN=LEFT> Si se desea gestionar la |
789 |
restauración de valores cuando se pulsa cancelar deberá |
790 |
hacerlo en esta clase. Una posibilidad es crear una clase, por |
791 |
ejemplo Status que guarde los valores al entrar y los restaure al |
792 |
salir en caso que las acciones sean canceladas.</P>
|
793 |
<P ALIGN=LEFT> Para la traducción del panel |
794 |
habrá que crear una función normalmente llamada por el |
795 |
constructor que sustituya las siguientes cadenas por el idioma que se |
796 |
desee:</P>
|
797 |
<PRE>this.getBandSetup().getFileList().getJButtonAdd().setText("Anadir"); |
798 |
this.getBandSetup().getFileList().getJButtonRemove().setText(“Eliminar"); |
799 |
this.getBandSetup().getFileList().lbandasVisibles.setText("bandas"); |
800 |
|
801 |
RasterTransparencyPanel tpan = this.getTransparencyPanel(); |
802 |
tpan.lGreenValue.setText("Valor verde:"); |
803 |
tpan.lRedValue.setText("Valor rojo:"); |
804 |
tpan.lBlueValue.setText("Valor azul:"); |
805 |
tpan.getTransparencyCheck().setText("transparencia"); |
806 |
tpan.getOpacityCheck().setText("opacidad"); |
807 |
tpan.lRange.setText("usar_rango: 1,3,5:8"); |
808 |
tpan.lPixelValue.setText("valor pixel: 0 a 255"); |
809 |
|
810 |
EnhancedPanel ep = this.getEnhancedPanel(); |
811 |
ep.lLineal.setText("lineal directo"); |
812 |
ep.lQueue.setText("recorte colas"); |
813 |
ep.lWithoutEnhanced.setText("sin realce"); |
814 |
ep.lCut.setText("% "recorte"); |
815 |
ep.lRemove.setText("eliminar extremos"); |
816 |
|
817 |
for(int i=0;i<this.getTab().getTabCount();i++){
|
818 |
if(this.getTab().getTitleAt(i).equals("Info")) |
819 |
this.getTab().setTitleAt(i,"info"); |
820 |
if(this.getTab().getTitleAt(i).equals("Transparencia")) |
821 |
this.getTab().setTitleAt(i,"Transparencia"); |
822 |
if(this.getTab().getTitleAt(i).equals("Bandas")) |
823 |
this.getTab().setTitleAt(i,"bandas"); |
824 |
if(this.getTab().getTitleAt(i).equals("Realce")) |
825 |
this.getTab().setTitleAt(i,"realce"); |
826 |
} |
827 |
|
828 |
this.getAcceptButton().setText("Aceptar"); |
829 |
this.getApplyButton().setText("Aplicar"); |
830 |
this.getCancelButton().setText("Cancelar");</PRE><P ALIGN=LEFT> |
831 |
En la gestión de eventos del botón |
832 |
Aceptar hay que controlar el estado de cada panel a acceder a los |
833 |
métodos de estos para recuperar la información y poder |
834 |
procesarla. Cada panel tiene los suyos:</P>
|
835 |
<UL>
|
836 |
<LI><P ALIGN=LEFT STYLE="margin-bottom: 0cm; font-weight: medium"><FONT SIZE=2 STYLE="font-size: 9pt">Panel |
837 |
de realce:</FONT></P> |
838 |
<P ALIGN=LEFT STYLE="margin-bottom: 0cm; font-weight: medium"><FONT SIZE=2 STYLE="font-size: 9pt">this.getEnhancedPanel(): |
839 |
Recupera el panel de tipo EnhancedPanel.</FONT></P> |
840 |
<P ALIGN=LEFT STYLE="margin-bottom: 0cm; font-weight: medium"><FONT SIZE=2 STYLE="font-size: 9pt">panel.getLinealDirectoRadioButton(): |
841 |
Obtiene el control de selección de filtro de realce.</FONT></P> |
842 |
<P ALIGN=LEFT STYLE="margin-bottom: 0cm; font-weight: medium"><FONT SIZE=2 STYLE="font-size: 9pt">panel.getTailCheck(): |
843 |
Obtiene el control de selección de recorte de colas.</FONT></P> |
844 |
<P ALIGN=LEFT STYLE="margin-bottom: 0cm; font-weight: medium"><FONT SIZE=2 STYLE="font-size: 9pt">panel.getRemoveCheck(): |
845 |
Obtiene el control de eliminar extremos.</FONT></P> |
846 |
<P ALIGN=LEFT STYLE="margin-bottom: 0cm; font-weight: medium"><FONT SIZE=2 STYLE="font-size: 9pt">Panel.getTailText(): |
847 |
Obtiene el porcentaje de recorte del cuadro de texto.</FONT></P> |
848 |
<LI><P ALIGN=LEFT STYLE="margin-bottom: 0cm; font-weight: medium"><FONT SIZE=2 STYLE="font-size: 9pt">Panel |
849 |
de transparencia:</FONT></P> |
850 |
<P ALIGN=LEFT STYLE="margin-bottom: 0cm">this.getTransparencyPanel(): |
851 |
Recupera el panel de tipo TransparencyPanel.</P>
|
852 |
<P ALIGN=LEFT STYLE="margin-bottom: 0cm">panel.getOpacityCheck(): |
853 |
Obtiene el control de opacidad activada (nivel de traslucidez de la |
854 |
imagen).</P>
|
855 |
<P ALIGN=LEFT STYLE="margin-bottom: 0cm">panel..getTransparencyCheck(): |
856 |
Obtiene el control de transparencia activada (transparencia por |
857 |
rangos de pixeles).</P>
|
858 |
<P ALIGN=LEFT STYLE="margin-bottom: 0cm">this.getRangeRed(): Obtiene |
859 |
los rangos de colores de pixeles de transparencia para la banda del |
860 |
rojo como vector de enteros.</P>
|
861 |
<P ALIGN=LEFT STYLE="margin-bottom: 0cm">this.getRangeGreen(): |
862 |
Obtiene los rangos de colores de pixeles de transparencia para la |
863 |
banda del verde como vector de enteros.</P>
|
864 |
<P ALIGN=LEFT STYLE="margin-bottom: 0cm">this.getRangeBlue(): |
865 |
Obtiene los rangos de colores de pixeles de transparencia para la |
866 |
banda del azul como vector de enteros.</P>
|
867 |
<LI><P ALIGN=LEFT STYLE="margin-bottom: 0cm; font-weight: medium"><FONT SIZE=2 STYLE="font-size: 9pt">Panel |
868 |
de bandas:</FONT></P> |
869 |
<P ALIGN=LEFT STYLE="margin-bottom: 0cm; font-weight: medium"><FONT SIZE=2 STYLE="font-size: 9pt">this.getBandSetup(): |
870 |
Recupera el panel de tipo BandSetup</FONT></P> |
871 |
<P ALIGN=LEFT STYLE="margin-bottom: 0cm">this.getAssignedBand(GeoRasterFile.RED_BAND): |
872 |
Obtiene la banda asignada al rojo.</P>
|
873 |
<P ALIGN=LEFT STYLE="margin-bottom: 0cm">this.getAssignedBand(GeoRasterFile.GREEN_BAND): |
874 |
Obtiene la banda asignada al verde.</P>
|
875 |
<P ALIGN=LEFT STYLE="margin-bottom: 0cm">this.getAssignedBand(GeoRasterFile.BLUE_BAND): |
876 |
Obtiene la banda asignada al azul.</P>
|
877 |
</UL>
|
878 |
<P ALIGN=LEFT><A NAME="InterfazSalvar"></A><STRONG><FONT SIZE=4>4.2 |
879 |
Interfaz de salvar a raster</FONT></STRONG></P> |
880 |
<P ALIGN=LEFT> Para la gestión de los |
881 |
controles de raster, el cliente deberá crear una clase que
|
882 |
herede de org.cresques.ui.raster.SaveRasterDialogPanel para tener el |
883 |
acceso a los controles protected que tiene. Por ejemplo, podemos |
884 |
querer incluir los paneles dentro de un frame con un botón de
|
885 |
Aceptar y otro de Cancelar. Un ejemplo de lo que aquí se
|
886 |
explica puede encontrarse en gvSIG dentro de la clase |
887 |
com.iver.cit.gvsig.gui.panels.SaveRasterDialog. |
888 |
</P>
|
889 |
<P ALIGN=LEFT> Para la traducción del panel |
890 |
habrá que crear una función normalmente llamada por el |
891 |
constructor que sustituya las siguientes cadenas por el idioma que se |
892 |
desee:</P>
|
893 |
<PRE>DataInputSaveRaster dInput = ((SaveSetupPanel)super.getContentPanel()).getSaveParameters();
|
894 |
dInput.lSupIzq.setText("lsup izq :"); |
895 |
dInput.lInfDer.setText("linf der :"); |
896 |
dInput.lFile.setText("Fichero :"); |
897 |
dInput.lResolucion.setText("resolucion"); |
898 |
dInput.lEscala.setText("escala 1:"); |
899 |
dInput.lPpp.setText("ppp"); |
900 |
dInput.bSeleccion.setText("Seleccionar"); |
901 |
dInput.lAncho.setText("ancho."); |
902 |
dInput.lAlto.setText("alto.");</PRE><P ALIGN=LEFT> |
903 |
En la gestión de eventos del botón |
904 |
Aceptar hay que controlar el estado de cada panel a acceder a los |
905 |
métodos de estos para recuperar la información y poder |
906 |
procesarla.</P>
|
907 |
<P ALIGN=LEFT STYLE="margin-bottom: 0cm">(DataInputSaveRaster)((SaveSetupPanel)((SaveRasterDialogPanel)this.getContentPane()).getContentPanel()).getSaveParameters(): |
908 |
Obtiene el dialogo de tipo DataInputSaveRaster</P>
|
909 |
<P ALIGN=LEFT STYLE="margin-bottom: 0cm">dialog.getTinf_derX().getText(): |
910 |
Obtiene la coordenada X inferior derecha.</P>
|
911 |
<P ALIGN=LEFT STYLE="margin-bottom: 0cm">dialog.getTinf_derY().getText(): |
912 |
Obtiene la coordenada Y inferior derecha.</P>
|
913 |
<P ALIGN=LEFT STYLE="margin-bottom: 0cm">dialog.getTsup_izqX().getText(): |
914 |
Obtiene la coordenada X superior izquierda.</P>
|
915 |
<P ALIGN=LEFT STYLE="margin-bottom: 0cm">dialog.getTsup_izqY().getText(): |
916 |
Obtiene la coordenada Y superior izquierda.</P>
|
917 |
<P ALIGN=LEFT STYLE="margin-bottom: 0cm">((SaveSetupPanel)((SaveRasterDialogPanel)this.getContentPane()).getContentPanel()).getFileName(); |
918 |
Obtiene el nombre del fichero sobre el que se salvará.</P> |
919 |
<P ALIGN=LEFT STYLE="margin-bottom: 0cm">dialog.getBPropiedades(): |
920 |
Obtiene el botón de propiedades.</P> |
921 |
<P ALIGN=LEFT STYLE="margin-bottom: 0cm"><BR> |
922 |
</P>
|
923 |
<P ALIGN=LEFT STYLE="margin-bottom: 0cm"> El botón |
924 |
de propiedades de raster debe de capturarse el evento de pulsado para |
925 |
ser procesado. Dependiendo del tipo de driver cargado hará una
|
926 |
acción u otra. El tipo de driver puede determinarse a través |
927 |
del texto del control, ya que este cambia cuando hemos seleccionado |
928 |
una extensión de raster con “Seleccionar”. Este |
929 |
botón de propiedades mostrará el dialogo de propiedades |
930 |
del driver. La configuración de esta ventana es leida
|
931 |
directamente desde el mismo driver a través de un texto en
|
932 |
formato XML. Para esto crearemos la ventana en una clase, por ejemplo |
933 |
SaveRasterPropsDialog que puede heredar de Jdialog en cuyo |
934 |
constructor crearemos el parser del XML y asignaremos el tamaño
|
935 |
a nuestra ventana de esta forma:</P>
|
936 |
<PRE> String xml = writer.getXMLPropertiesDialog();
|
937 |
if(xml!=null){ |
938 |
CXMLParser parser = new CXMLParser(xml); |
939 |
widthWindow = Integer.parseInt(parser.getAttr("window","sizex")); |
940 |
heightWindow = Integer.parseInt(parser.getAttr("window","sizey")); |
941 |
} |
942 |
setContentPane(getContentPane());</PRE><P> |
943 |
donde el writer es el driver de tipo GeoRasterWriter y contentPane es |
944 |
un SaveRasterPropsDialogPanel. El panel de propiedades puede añadirse
|
945 |
de forma facil con una función como esta:</P> |
946 |
<PRE> public Container getContentPane() {
|
947 |
if (contentPane == null) { |
948 |
contentPane = new SaveRasterPropsDialogPanel(writer); |
949 |
} |
950 |
return contentPane; |
951 |
}</PRE><P> |
952 |
Este dialogo puede tener botones de aceptar y cancelar cuyos eventos |
953 |
de pulsado deben ser capturados. |
954 |
</P>
|
955 |
</BODY>
|
956 |
</HTML>
|