gvSIG
gvSIG es una herramienta orientada al manejo de información geográfica. Permite
acceder a información vectorial y rasterizada georreferenciada, así como
a servidores de mapas que cumplan las especificaciones que impone el OGC
(Open Geospatial Consortium —Consorcio Abierto Geoespacial—).
Las razones para usar gvSIG son variadas:
• Está programado en Java, lo que significa que puede ejecutarse virtualmente
en casi cualquier máquina.
• Es software libre*, lo que nos da la libertad de modificarlo y distribuirlo a
nuestro antojo. El coste de este software es cero.
• Su funcionalidad se puede ampliar fácilmente mediante complementos
que se pueden programar en Java o en Jython**.
• Está probado por una base amplia de usuarios, lo que asegura una buena
estabilidad del código
1.1. Arquitectura de gvSIG
gvSIG se estructura alrededor de un núcleo de funcionalidad relativamente pequeño.
A este núcleo, que contiene las partes esenciales del sistema, se le pueden
añadir complementos para dotarlo de nuevas funcionalidades.
Esta
arquitectura permite descomponer el sistema en partes pequeñas, más fáciles
de implementar y mantener. Actualmente, gran parte de la distribución de gvSIG
son complementos.
Aunque los complementos pueden ser de naturaleza muy variopinta, siempre
se muestran al usuario de forma homogénea.
Es decir, el aspecto gráfico y la
forma de trabajar con un complemento u otro serán más o menos parecidos.
Los complementos se integran en el marco de gvSIG mediante las llamadas
“extensiones”, que no son más que un conjunto de clases Java que añaden
nuevas funcionalidades a la aplicación.
El núcleo de gvSIG está formado por tres subsistemas:
FMap. Agrupa la lógica SIG. Contiene las clases que se encargan de generar
los mapas, gestionar las capas, transformar coordenadas y realizar búsquedas,
consultas, análisis, etc.
gvSIG. Agrupa las clases encargadas de gestionar la interfaz gráfica de la
aplicación y representar en pantalla los mapas generados por el subsistema
FMap. En otras palabras, este subsistema se encarga de proporcionar una interfaz
de usuario que proporciona acceso a las funcionalidades de gvSIG
Subdriver. Contiene las clases que se encargan de dar acceso a los datos,
tanto locales como remotos (por ejemplo, servicios OGC). Además, permite
escribir datos geográficos en los formatos más comunes.
Para llevar a cabo su cometido, un complemento puede acceder a uno o más
subsistemas de gvSIG
1.2. Anatomía de un complemento
Como mínimo, un complemento está constituido por:
• un fichero XML que describe el complemento, y
• el código del complemento.
El fichero XML, que debe llamarse config.xml, proporciona a gvSIG la información
necesaria sobre el complemento para que pueda cargarlo e integrarlo en
la interfaz gráfica.
Entre otras cosas, especifica el directorio que contiene el có-
digo del complemento, las dependencias que tiene con otros complementos y
los elementos de interfaz de usuario (menús, barras de herramientas, etc.) que
añade a la interfaz de gvSIG.
El código del complemento es un conjunto de clases Java que implementan la
funcionalidad aportada por el complemento.
Probablemente, el código irá
acompañado de ficheros de configuración, imágenes, datos geográficos o cualquier
otro dato que sea necesario para la ejecución de éste.
A lo largo de este módulo, vamos a implementar, a modo de ejemplo, un complemento
llamado “Construcciones” que mostrará elementos constructivos
(edificios y caminos) sobre una base topográfica.
En los apartados siguientes,
aprenderemos a crear un complemento y, por medio de él, a:
• agregar una capa de información geográfica a una vista,
• dibujar líneas y polígonos georeferenciados sobre un mapa, y
• crear una herramienta que muestre información sobre los elementos dibujados.
1.3. El fichero config.xml
El fichero config.xml contiene los datos de configuración del complemento.
Este fichero, que obligatoriamente debe acompañar al código, define básica-
CC BY • PID_00174756 9 Adaptación y extensión de un SIG
mente los elementos de interfaz de usuario que se van a añadir a la aplicación
(herramientas, menús y controles de la barra de estado), a la vez que los asocia
con clases del código. Cada una de estas asociaciones es una “extensión”.
El fichero config.xml debe escribirse en lenguaje XML (de eXtensible Markup
Language —‘lenguaje de marcas extensible’—) y ha de seguir unas pautas determinadas.
Un documento XML está constituido por elementos que forman una jerarquía.
Estos elementos se denotan mediante el uso de etiquetas de inicio y fin.
Las etiquetas tienen la forma , o , en donde
nombre es el nombre del elemento. La primera es una etiqueta de inicio, la segunda
de fin, y la última una combinación de ambas. Las dos primeras se utilizan
cuando un elemento puede contener otros elementos, y sirven para
marcar el inicio y el fin de dicho elemento.
La última está reservada a elementos
que no contienen otros. Además, los elementos pueden tener atributos cuyos
valores se establecen de forma muy parecida a las asignaciones de los
lenguajes de programación.
Veamos el fichero de configuración que usará nuestro complemento:
<?xml version="1.0" encoding="ISO-8859-1"?>
<plugin-config>
<depends plugin-name="com.iver.cit.gvsig" />
<libraries library-dir="."/>
<extensions>
<extension class-name=
"edu.uoc.postgradosig. construcciones.Construcciones"
description="Complemento que dibuja construcciones"
active="true"
priority="50">
<menu text="Postgrado SIG/Construcciones"
<action-command="MENU_CONSTRUCCIONES" />
</extension>
</extensions>
</plugin-config>
La primera línea, llamada prólogo, describe la versión del lenguaje XML
utilizada para escribir el documento y su codificación. Como el prólogo no
forma parte de la configuración del complemento, no debemos preocuparnos
demasiado por su contenido. Simplemente, siempre utilizaremos la misma
fórmula.
El significado del resto de elementos es el siguiente:
plugin-config. Es una etiqueta que engloba todas las opciones de configuración.
Es la raíz de la jerarquía de elementos.
depends. Enumera los complementos de los que depende nuestro complemento
para funcionar correctamente. El nombre del complemento se especifica
mediante el atributo “plugin-name”. Debe haber un elemento
“depends” por cada complemento. Un complemento depende de otro
cuando el código del primero utiliza alguna de las clases del código del segundo.
Normalmente, todos los complementos dependerán del complemento
gvSIG (“com.iver.cit.gvsig”), que es la aplicación en sí. libraries. Especifica el directorio en el que reside el código de nuestro complemento.
El nombre del directorio se especifica mediante el atributo “library-dir”.
El punto como nombre de directorio significa que el código se
encuentra en el mismo directorio que el fichero de configuración. extensions. Marca el inicio de la lista de extensiones del complemento.
extension. Declara una extensión de gvSIG. La declaración incluye el nombre
de la clase Java que implementa la extensión y una lista de elementos
de interfaz de usuario que deben añadirse a la aplicación y que están asociados
con la extensión. El elemento “extension” tiene los atributos siguientes:
class-name: especifica el nombre de la clase que implementa la extensión.
description: describe la funcionalidad que aporta la extensión. Esta etiqueta
es meramente informativa.
active: especifica si la extensión está activa o inactiva. Si el valor de este
atributo es “false”, gvSIG no cargará la extensión.
priority: establece la prioridad de carga de la extensión respecto al
resto de extensiones declaradas en el fichero de configuración. Cuanto
menor sea el número, antes se cargará la extensión. En nuestro caso,
sólo hay una extensión, por lo que el valor de la prioridad no es
fundamental.
menu. Define una nueva entrada del menú de gvSIG y la asocia a la extensión.
El elemento “menu” tiene dos atributos:
text: establece el nombre y la ubicación del menú. Puede usarse la barra
(“/”) para establecer diversos niveles de menú.
action-command: especifica el identificador de la acción. Cada vez
que se active el menú, se llamará a la clase asociada pasándole el valor
de este atributo. Esto nos permite asociar varios menús a una sola
clase.
CC BY • PID_00174756 11 Adaptación y extensión de un SIG
En el ejemplo, se declara la opción de menú Postgrado SIG /Construcciones
con el identificador asociado “MENU_CONSTRUCCIONES”. El resultado será
el siguiente:
1.4. La clase “Extensión”
Una vez creado el fichero XML de configuración de la extensión, en cuyo contenido
hemos definido la clase que la implementa y los elementos de interfaz de
usuario que nos permitirán acceder a su funcionalidad, llega el momento de implementarla.
Para ser consideradas como tales, las extensiones deben extender (valga la redundancia)
la clase “Extension”* y sobrecargar sus funciones. Al reconocer la
clase como una extensión, gvSIG se comunicará con ella por medio de estas
funciones, que actuarán a modo de interfaz entre gvSIG y la extensión.
A continuación, se muestra una posible implementación de la extensión
“Construcciones”:
package edu.uoc.postgradosig.construcciones;
import com.iver.andami.plugins.Extension;
import javax.swing.JOptionPane;
public class Construcciones extends Extension {
public void initialize() {
// aquí se realizan las tareas de inicialización
}
public boolean isEnabled() {
return true; // está habilitada
}
import com.iver.andami.plugins.Extension;
import javax.swing.JOptionPane;
public class Construcciones extends Extension {
public void initialize() {
// aquí se realizan las tareas de inicialización
}
public boolean isEnabled() {
return true; // está habilitada
}
public boolean isVisible() {
return true; // es visible
}
public void execute(String actionCommand) {
// muestra un mensaje por pantalla
JOptionPane.showMessageDialog(null,
"Esta extensión muestra elementos constructivos.");
}
}
return true; // es visible
}
public void execute(String actionCommand) {
// muestra un mensaje por pantalla
JOptionPane.showMessageDialog(null,
"Esta extensión muestra elementos constructivos.");
}
}
Como se puede observar, la clase “Construcciones” extiende la clase “Extension”
e implementa (sobrecarga) cuatro funciones: initialize, isEnabled, isVisible
y execute. El cometido de cada una de ellas es el siguiente:
void initialize(). Se utiliza para inicializar la extensión. En esta función emplazaremos
llamadas a funciones que se encarguen de reservar recursos,
leer configuraciones, etc. Debemos fijarnos en que esta función desempeña
un papel muy parecido al del constructor de la clase. Sin embargo, por coherencia
con gvSIG, reservaremos las tareas más arduas para esta función,
limitando el cometido del constructor —si lo hay— a la inicialización de
variables.
boolean isEnabled(). Indica si la extensión debe considerarse habilitada o
no. Cuando una extensión no está habilitada, los elementos de interfaz de
usuario (botones, menús o controles de la barra de estado) que tiene asociados
no son accesibles. En la mayoría de sistemas, estos elementos se
mostrarán en tonos grisáceos. gvSIG llama periódicamente a esta función
respondiendo a los eventos de la interfaz gráfica.
boolean isVisible(). Indica si los elementos de interfaz de usuario que tiene
asociados la extensión deben estar visibles o no. Si esta función devuelve
false, no se mostrará ninguno de sus elementos. gvSIG llama periódicamente
a esta función respondiendo a los eventos de la interfaz gráfica.
void execute(String actionCommand). gvSIG llama a esta función cada vez
que se activa la extensión, es decir, cada vez que el usuario accede a alguno de
los elementos de interfaz de usuario que la extensión ha definido. El parámetro
“actionCommand” contiene el valor del atributo “action-command” (definido
en el fichero de configuración) del elemento al que se ha accedido.
Todas las extensiones están obligadas a implementar estas cuatro funciones.
Al tratarse de funciones sobrecargadas, debemos prestar especial atención a
respetar tanto los modificadores de visibilidad como el tipo de la función y de
los parámetros. Opcionalmente, si se desea un mayor control sobre los procesos de inicialización y descarga de la extensión, también se pueden implementar
las funciones siguientes:
void postInitialize(). Se llama a esta función después de haberse llamado a
la función initialize de todas las extensiones. Se utilizará para realizar tareas
de inicialización que requieran una interacción con otras extensiones.
void terminate(). Se llama a esta función al terminar la ejecución de gvSIG.
Típicamente, en esta función almacenaremos las preferencias del usuario,
liberaremos recursos, etc.
Volvamos al ejemplo: la extensión mostrará una ventana con un mensaje descriptivo
cada vez que se active. Este código, combinado con el fichero de configuración
que ya habíamos definido, dará lugar a que se muestre el mensaje
cada vez que se seleccione la opción de menú Postgrado SIG / Construcciones.
Cabe destacar que, en este caso, el contenido del parámetro “actionCommand”
será “MENU_CONSTRUCCIONES”, tal y como habíamos definido en
el fichero de configuración. También es importante observar que las funciones
isEnabled e isVisible devuelven true, lo que indica en todo momento que la extensión
está habilitada y es visible.
Debemos observar también que el mensaje informativo se muestra mediante
la función showMessageDialog de la clase “JOptionPane”*.
El resultado será el siguiente:
1.5 Crear una capa vectorial en memoria
Para crear un mapa vectorial en memoria, usaremos la clase “ConcreteMemoryDriver”.
Las líneas siguientes:
ConcreteMemoryDriver mapa;
mapa = new ConcreteMemoryDriver();
mapa.setShapeType(FShape.LINE + FShape.POLYGON);
mapa.getTableModel().setColumnIdentifiers(new String[] {
"ID", "Descripcion"});
mapa = new ConcreteMemoryDriver();
mapa.setShapeType(FShape.LINE + FShape.POLYGON);
mapa.getTableModel().setColumnIdentifiers(new String[] {
"ID", "Descripcion"});
crean un mapa vectorial llamado “mapa”. Además, se establecen, mediante la
función setShapeType, los tipos de figuras que contendrá, “FShape.LINE” (por lí-
neas) y “FShape.POLYGON” (por polígonos), y mediante la función setColumnIdentifiers,
los atributos asociados a cada una de ellas, “ID” y “Descripcion”. Los
atributos se pueden definir arbitrariamente según nuestras necesidades
1.6.Dibujar líneas y polígonos
Una vez creado el mapa, podemos empezar a añadirle figuras. Supongamos
que, en una fase previa de captación de datos, hemos localizado una vivienda
y un camino.
La vivienda la dibujaremos mediante el objeto “FPolygon2D”. El código siguiente:
La vivienda la dibujaremos mediante el objeto “FPolygon2D”. El código siguiente:
GeneralPathX ruta;
FPolygon2D edificio;
// definimos la geometría del edificio
ruta = new GeneralPathX();
ruta.moveTo(356270.7, 4727507.1); // mueve el cursor al inicio
ruta.lineTo(356273.0, 4727503.3); // dibuja el primer segmento
ruta.lineTo(356278.5, 4727505.8); // dibuja el segundo segmento
ruta.lineTo(356275.5, 4727509.8); // dibuja el tercer segmento
ruta.lineTo(356270.7, 4727507.1); // dibuja el cuarto segmento
// creamos el objeto edificio a partir de la geometría definida
// previamente
edificio = new FPolygon2D(ruta);
// agregamos el edificio al mapa
mapa.addShape(edificio, new Object[] {
// valor del atributo "ID"
ValueFactory.createValue(1),
// valor del atributo "Descripcion"
ValueFactory.createValue("Casa unifamiliar.") });
FPolygon2D edificio;
// definimos la geometría del edificio
ruta = new GeneralPathX();
ruta.moveTo(356270.7, 4727507.1); // mueve el cursor al inicio
ruta.lineTo(356273.0, 4727503.3); // dibuja el primer segmento
ruta.lineTo(356278.5, 4727505.8); // dibuja el segundo segmento
ruta.lineTo(356275.5, 4727509.8); // dibuja el tercer segmento
ruta.lineTo(356270.7, 4727507.1); // dibuja el cuarto segmento
// creamos el objeto edificio a partir de la geometría definida
// previamente
edificio = new FPolygon2D(ruta);
// agregamos el edificio al mapa
mapa.addShape(edificio, new Object[] {
// valor del atributo "ID"
ValueFactory.createValue(1),
// valor del atributo "Descripcion"
ValueFactory.createValue("Casa unifamiliar.") });
dibuja la vivienda y la agrega al mapa. Como se puede observar, primero usamos
un objeto de la clase “GeneralPathX” para definir la geometría de la figura,
y después creamos el polígono mediante la clase “FPolygon2D”. En un
último paso, lo agregamos al mapa y especificamos el valor de sus atributos.
Observad que la función createValue está sobrecargada, lo que permite pasarle
por parámetro tanto enteros como texto. También debemos notar que trabajamos
directamente con coordenadas geográficas.
El camino lo dibujaremos de forma muy parecida. La única diferencia es que
utilizaremos la clase “FPolyline2D” en lugar de “FPolygon2D”:
GeneralPathX ruta;
FShape camino;
// definimos la geometría del edificio
ruta = new GeneralPathX();
ruta.moveTo(356242.7, 4727498.8);
ruta.lineTo(356268.0, 4727509.8);
ruta.lineTo(356281.0, 4727519.1);
// creamos el objeto camino a partir de la geometría
// definida previamente
camino = new FPolyline2D(ruta);
// agregamos el camino al mapa
mapa.addShape(camino, new Object[] {
ValueFactory.createValue(2),
ValueFactory.createValue("Camino de herradura.") });
FShape camino;
// definimos la geometría del edificio
ruta = new GeneralPathX();
ruta.moveTo(356242.7, 4727498.8);
ruta.lineTo(356268.0, 4727509.8);
ruta.lineTo(356281.0, 4727519.1);
// creamos el objeto camino a partir de la geometría
// definida previamente
camino = new FPolyline2D(ruta);
// agregamos el camino al mapa
mapa.addShape(camino, new Object[] {
ValueFactory.createValue(2),
ValueFactory.createValue("Camino de herradura.") });
1.7 Crear una capa
Una vez dibujado el mapa, ya sólo nos queda agregarlo a la vista actual como
una capa. Esta tarea se reparte entre las clases “LayerFactory”, que crea la capa,
y “MapControl”, que la agrega a la vista actual:
FLayer capa;
MapControl controlMapa;
View vistaActual;
// obtiene la ventana de vista activa
vistaActual = (View)PluginServices.getMDIManager().
getActiveWindow();
// obtiene el objeto que controla el mapa
controlMapa = vistaActual.getMapControl();
// crea una capa a partir de un mapa
capa = LayerFactory.createLayer("Construcciones", mapa,
controlMapa.getProjection());
// hace visible la capa
capa.setVisible(true);
// agrega la capa a la vista actual
controlMapa.getMapContext().getLayers().addLayer(capa);
MapControl controlMapa;
View vistaActual;
// obtiene la ventana de vista activa
vistaActual = (View)PluginServices.getMDIManager().
getActiveWindow();
// obtiene el objeto que controla el mapa
controlMapa = vistaActual.getMapControl();
// crea una capa a partir de un mapa
capa = LayerFactory.createLayer("Construcciones", mapa,
controlMapa.getProjection());
// hace visible la capa
capa.setVisible(true);
// agrega la capa a la vista actual
controlMapa.getMapContext().getLayers().addLayer(capa);
Como se puede observar, la capa se crea mediante la función createLayer de la clase “LayerFactory”. Esta función espera tres argumentos: el nombre de la capa (“Construcciones”), el mapa que contendrá y la proyección con la que se representará (la misma que se utiliza en la vista). En un segundo paso, se agrega la capa a la vista mediante la función addLayer. Como podemos ver, para poder llamar a la función necesitamos obtener, en primer lugar, el contexto del mapa (“getMapContext”), y en segundo lugar, la colección de las capas que contiene (“getLayers”)
Recapitulando, el código de la extensión nos queda así:
package edu.uoc.postgradosig.construcciones;
import com.hardcode.gdbms.engine.values.ValueFactory;
import com.iver.andami.PluginServices;
import com.iver.andami.plugins.Extension;
import com.iver.andami.ui.mdiManager.IWindow;
import com.iver.cit.gvsig.fmap.MapControl;
import com.iver.cit.gvsig.fmap.core.FPolygon2D;
import com.iver.cit.gvsig.fmap.core.FPolyline2D;
import com.iver.cit.gvsig.fmap.core.FShape;
import com.iver.cit.gvsig.fmap.core.GeneralPathX;
import com.iver.cit.gvsig.fmap.drivers.
ConcreteMemoryDriver;
import com.iver.cit.gvsig.fmap.layers.FLayer;
import com.iver.cit.gvsig.fmap.layers.LayerFactory;
import com.iver.cit.gvsig.project.documents.view.gui.View;
public class Construcciones extends Extension {
public void execute(String actionCommand) {
ConcreteMemoryDriver mapa;
GeneralPathX ruta;
FShape edificio, camino;
FLayer capa;
MapControl controlMapa;
View vistaActual;
// crea un mapa vectorial en memoria
mapa = new ConcreteMemoryDriver();
mapa.setShapeType(FShape.LINE + Fshape.POLYGON);
mapa.getTableModel().setColumnIdentifiers(
new String[] { "ID", "Descripcion"});
// definimos la geometría del edificio
ruta = new GeneralPathX();
ruta.moveTo(356270.7, 4727507.1);
ruta.lineTo(356273.0, 4727503.3);
ruta.lineTo(356278.5, 4727505.8);
ruta.lineTo(356275.5, 4727509.8);
ruta.lineTo(356270.7, 4727507.1);
// creamos el objeto edificio a partir de la geometría
// definida previamente
edificio = new Fpolygon2D(ruta);
// agregamos el edificio al mapa
mapa.addShape(edificio, new Object[] {
ValueFactory.createValue(1),
ValueFactory.createValue("Casa unifamiliar.") });
// definimos la geometría del camino
ruta = new GeneralPathX();
ruta.moveTo(356242.7, 4727498.8);
ruta.lineTo(356268.0, 4727509.8);
ruta.lineTo(356281.0, 4727519.1);
// creamos el objeto camino a partir de la geometría
// definida previamente
camino = new Fpolyline2D(ruta);
// agregamos el camino al mapa
mapa.addShape(camino, new Object[] {
ValueFactory.createValue(2),
ValueFactory.createValue("Camino de herradura.") });
// crea la capa
vistaActual = (View)PluginServices.getMDIManager().
getActiveWindow();
controlMapa = vistaActual.getMapControl();
capa = LayerFactory.createLayer("Construcciones", mapa,
controlMapa.getProjection());
capa.setVisible(true);
// agrega la capa a la vista actual
controlMapa.getMapContext().getLayers().addLayer(capa);
}
public boolean isEnabled() {
IWindow ventanaActiva;
// obtiene la ventana activa
ventanaActiva = PluginServices.getMDIManager().
getActiveWindow();
// estará habilitada sólo si la ventana actual es una
// ventana de vista
return ventanaActiva instanceof View;
}
public boolean isVisible() {
// siempre estará visible
return true;
}
public void initialize() {
}
}
import com.hardcode.gdbms.engine.values.ValueFactory;
import com.iver.andami.PluginServices;
import com.iver.andami.plugins.Extension;
import com.iver.andami.ui.mdiManager.IWindow;
import com.iver.cit.gvsig.fmap.MapControl;
import com.iver.cit.gvsig.fmap.core.FPolygon2D;
import com.iver.cit.gvsig.fmap.core.FPolyline2D;
import com.iver.cit.gvsig.fmap.core.FShape;
import com.iver.cit.gvsig.fmap.core.GeneralPathX;
import com.iver.cit.gvsig.fmap.drivers.
ConcreteMemoryDriver;
import com.iver.cit.gvsig.fmap.layers.FLayer;
import com.iver.cit.gvsig.fmap.layers.LayerFactory;
import com.iver.cit.gvsig.project.documents.view.gui.View;
public class Construcciones extends Extension {
public void execute(String actionCommand) {
ConcreteMemoryDriver mapa;
GeneralPathX ruta;
FShape edificio, camino;
FLayer capa;
MapControl controlMapa;
View vistaActual;
// crea un mapa vectorial en memoria
mapa = new ConcreteMemoryDriver();
mapa.setShapeType(FShape.LINE + Fshape.POLYGON);
mapa.getTableModel().setColumnIdentifiers(
new String[] { "ID", "Descripcion"});
// definimos la geometría del edificio
ruta = new GeneralPathX();
ruta.moveTo(356270.7, 4727507.1);
ruta.lineTo(356273.0, 4727503.3);
ruta.lineTo(356278.5, 4727505.8);
ruta.lineTo(356275.5, 4727509.8);
ruta.lineTo(356270.7, 4727507.1);
// creamos el objeto edificio a partir de la geometría
// definida previamente
edificio = new Fpolygon2D(ruta);
// agregamos el edificio al mapa
mapa.addShape(edificio, new Object[] {
ValueFactory.createValue(1),
ValueFactory.createValue("Casa unifamiliar.") });
// definimos la geometría del camino
ruta = new GeneralPathX();
ruta.moveTo(356242.7, 4727498.8);
ruta.lineTo(356268.0, 4727509.8);
ruta.lineTo(356281.0, 4727519.1);
// creamos el objeto camino a partir de la geometría
// definida previamente
camino = new Fpolyline2D(ruta);
// agregamos el camino al mapa
mapa.addShape(camino, new Object[] {
ValueFactory.createValue(2),
ValueFactory.createValue("Camino de herradura.") });
// crea la capa
vistaActual = (View)PluginServices.getMDIManager().
getActiveWindow();
controlMapa = vistaActual.getMapControl();
capa = LayerFactory.createLayer("Construcciones", mapa,
controlMapa.getProjection());
capa.setVisible(true);
// agrega la capa a la vista actual
controlMapa.getMapContext().getLayers().addLayer(capa);
}
public boolean isEnabled() {
IWindow ventanaActiva;
// obtiene la ventana activa
ventanaActiva = PluginServices.getMDIManager().
getActiveWindow();
// estará habilitada sólo si la ventana actual es una
// ventana de vista
return ventanaActiva instanceof View;
}
public boolean isVisible() {
// siempre estará visible
return true;
}
public void initialize() {
}
}
Como podemos apreciar, la vista contiene dos capas: la base topográfica
(“TGSPNIRS.jpg”) y la capa “Construcciones” que acabamos de crear. Mediante
las clases “GPolygon2D” y “GPolyline2D” hemos conseguido dibujar un
edificio y un camino al este del pueblo de Noarre.
1.8. El viewport
Cuando se muestra un mapa por pantalla, no siempre se muestra en toda
su extensión. Que veamos una parte mayor o menor del mismo depende
del nivel de zoom. De hecho, el área visible y el nivel de zoom se rigen por
una regla de proporcionalidad inversa: a mayor zoom, menor área, y a menor
zoom, mayor área.
El recuadro que delimita el área visible de un mapa se llama viewport. Normalmente,
se define por las coordenadas geográficas de sus esquinas inferior izquierda
(suroeste) y superior derecha (noreste). Latitud y longitud crecen
desde la coordenada suroeste hasta la coordenada noreste.
View vistaActiva;
MapControl controlMapa;
ViewPort viewport;
Point2D geoPoint;
// obtiene el viewport
vistaActiva = (View)PluginServices.getMDIManager().
getActiveWindow();
controlMapa = vistaActiva.getMapControl();
viewport = controlMapa.getViewPort();
// transforma las coordenadas del viewport en coordenadas
// geográficas
geoPoint = viewport.toMapPoint(x, y);
JOptionPane.showMessageDialog(null, “Latitud: “ +
geoPoint().getX() + “ Longitud: “ +
geoPoint.getY());
muestra por pantalla las coordenadas geográficas que se corresponden con este punto. Como se puede observar, la función que hace la transformación es toMapPoint. Esta función devuelve un objeto “Point2D” que contiene las coordenadas geográficas resultantes, cuyas componentes se pueden consultar mediante las funciones getY (latitud) y getX (longitud). Otras funciones interesantes que nos ofrece la clase viewport son las siguientes:
fromMapPoint. Hace la transformación inversa: de coordenadas geográficas a coordenadas del viewport.
fromMapDistance. Transforma una distancia geográfica en una distancia del viewport. • toMapDistance. Transforma una distancia del viewport en una distancia geográfica. • getAdjustedExtend. Devuelve los límites geográficos del viewport, es decir, las coordenadas de las esquinas.
1.9. Agregar un botón a la barra de herramientas
El primer paso será agregar un botón a la barra de herramientas de la aplicación. Los botones, como todo elemento gráfico, pueden añadirse mediante el fichero de configuración config.xml. Las líneas siguientes
El primer paso será agregar un botón a la barra de herramientas de la aplicación. Los botones, como todo elemento gráfico, pueden añadirse mediante el fichero de configuración config.xml. Las líneas siguientes
<tool-bar name="Postgrado SIG" position="2">
<action-tool icon="seleccion.png"
tooltip="Localizador" position="1"
action-command="BOTON_LOCALIZADOR"/>
</tool-bar>
<action-tool icon="seleccion.png"
tooltip="Localizador" position="1"
action-command="BOTON_LOCALIZADOR"/>
</tool-bar>
añaden un botón a la barra de herramientas de gvSIG. El significado de cada
uno de los elementos se detalla a continuación:
tool-bar. Define una barra de herramientas. Este elemento tiene dos atributos:
– name: especifica el nombre de la barra de herramientas.
– position: especifica la posición que ocupará la barra de herramientas entre
las demás.
action-tool. Define un botón de la barra de herramientas. Este elemento, que
debe ir siempre dentro de un elemento “tool-bar”, tiene cuatro atributos:
– icon: especifica el nombre del fichero que contiene la imagen que aparecerá
en el botón.
– tooltip: especifica el texto que se mostrará para describir la herramienta.
– position: especifica la posición del botón dentro de la barra de herramientas.
action-command: al igual que el atributo “action-command” de los
menús, define un identificador para la acción (este identificador se utilizará
en las llamadas a la función exec de la extensión).
El elemento “tool-bar” debe ir siempre dentro de un elemento “extension”. Si
incorporamos estas líneas al fichero de configuración de la extensión “Construcciones”,
el resultado será el siguiente:
<?xml version="1.0" encoding="ISO-8859-1"?>
<plugin-config>
<depends plugin-name="com.iver.cit.gvsig" />
<libraries library-dir="."/>
<extensions>
<extensionclass-name=
"edu.uoc.postgradosig.construcciones.Construcciones"
description="Complemento que dibuja construcciones"
active="true"
priority="50">
<menu text="Postgrado SIG/Construcciones"
action-command="MENU_CONSTRUCCIONES" />
<tool-bar name="Postgrado SIG" position="2">
<action-tool icon="consulta.png"
tooltip="Consultar construcciones"
position="1"
action-command="BOTON_CONSTRUCCIONES"/>
</tool-bar>
</extension>
</extensions>
</plugin-config>
<plugin-config>
<depends plugin-name="com.iver.cit.gvsig" />
<libraries library-dir="."/>
<extensions>
<extensionclass-name=
"edu.uoc.postgradosig.construcciones.Construcciones"
description="Complemento que dibuja construcciones"
active="true"
priority="50">
<menu text="Postgrado SIG/Construcciones"
action-command="MENU_CONSTRUCCIONES" />
<tool-bar name="Postgrado SIG" position="2">
<action-tool icon="consulta.png"
tooltip="Consultar construcciones"
position="1"
action-command="BOTON_CONSTRUCCIONES"/>
</tool-bar>
</extension>
</extensions>
</plugin-config>
Es importante observar que el atributo “action-command” del menú y del botón
son diferentes: en el primer caso es MENU_CONSTRUCCIONES, mientras
que en el segundo caso es BOTON_CONSTRUCCIONES. Esto permite a la extensión
(mediante el parámetro que recibe en la función execute) averiguar por
medio de qué elemento de la interfaz de usuario ha sido llamada: si por medio
del menú o por medio del botón de la herramienta.
El efecto sobre la interfaz de usuario de gvSIG será el siguiente:
Como se puede observar, se añade un botón “C” a la barra de herramientas.
Bibliografía
Oracle, "The Java(tm) Tutorials", http://download.oracle.com/javase/tutorial/.
Oracle,
"Java(tm) 2
Platform Standard Edition 5.0 API Specification", http:// download.oracle.com/javase/1.5.0/docs/api/.
Personalización SIG, Albert Gavarró Rodríguez
, Universidad Oberta de Catalunya, España 2011




No hay comentarios:
Publicar un comentario