MapContext

Introducción

MapContext es una clase utilizada por MapControl para almacenar, gestionar y dibujar capas con información gráfica, así como los manejadores de eventos que se producen en ellas.

Contiene un ViewPort con la información necesaria para visualizar un área seleccionada de las capas en el área disponible para ello. Y contiene la conversión de las unidades definidas en el ViewPort, a metros o a centímetros. Véase el apartado Conversión de Unidades de Medida .

Descripción

La librería libFMap permite trabajar con capas gráficas.

Estas capas gráficas se visualizarán de manera que un usuario pueda trabajar con ellas gracias a MapControl, que, siguiendo el patrón Modelo-Vista-Controlador, se desentiende de su almacenamiento (modelo), la gestión de eventos sobre ellas (parte del control), ni la transformación entre la parte que se quiere visualizar y la parte disponible para ello (otra parte del control, esta se encarga ViewPort), para encargarse solo de su visualización y la interacción con herramientas gráficas (vista, y parte del control).

Así pues, será MapContext quien se encargue de proporcionar a MapControl la lógica necesaria para almacenamiento de capas, la gestión de eventos en ellas y su dibujado, utilizando para ello un puerto de vista (ViewPort) y una proyección. Tal es así, que MapContext no puede existir fuera del contexto de MapControl .

MapContext soporta dibujado de las capas que almacena, estableciendo la calidad mediante antialiasing de texto e imágenes, y de renderizado, pero la lógica de dibujado está contenida en cada capa.

El diagrama 1 nos muestra una visión en conjunto de las principales clases e interfaces relacionadas con MapContext. Se puede así observar como MapContext, que implementa la funcionalidad definida en el interfaz Projected, es parte intrínseca de MapControl. También las relaciones con las capas que almacena (FLayers, y GraphicLayer), la información para dibujar el área seleccionada de las capas en el espacio disponible para ello (ViewPort), el buffer (EventBuffer) para tratar conjuntos de eventos recibidos de manera atómica, así como una clase interna para la manipulación genérica de los eventos en cualquier tipo de capa de éste (LayerEventListener).

Tenemos pues, una capa, GraphicLayer, propia de MapContext para los símbolos y geometrías editables, y un árbol con distinto tipo de capas gráficas. Ambas son opcionales, de manera que no es necesario que haya ambos tipos de capas a la vez.

Por último el diagrama se completa con los tipos de excepciones que puede lanzar trabajando con los eventos de las capas que contiene.

../images/mapcontext/dcmapcontext.png

Diagrama 1: diagrama de clases de MapContext. El paquete "Groups of Registered Listeners" representa un conjunto de listeners que MapContext puede registrar, y lanzar cuando recibe algún evento de los soportados por alguna de ellas.

Se puede ver en el diagrama 2 como EventBuffer implementa interfaces para soportar eventos en una capa (LayerListener), en un conjunto de capas (LayerCollectionListener), del puerto de vista (ViewPortListener), de leyendas en capas (LegendListener), y producidos por la selección en una capa vectorial (SelectionListener).

Los eventos que recibe, los irá almacenando hasta que se le indique que los lance, lo cual aparentará externamente que se ha ejecutado un solo evento atómico.

EventBuffer lanzará un tipo de evento denominado AtomicEvent que contendrá una lista con todos los eventos almacenados entre las operaciones: beginAtomicEvent() y endAtomicEvent(). Además, se pueden registrar *listeners de tipo AtomicEventListener que permitirán realizar el tratamiento que se desee con este tipo de eventos. También, es posible cancelar en tiempo de ejecución el tratamiento de un evento de tipo AtomicEvent, en caso de producirse un error, se lanzaría una excepción de tipo CancelableException.

AtomicEvent

AtomicEvent es muy útil para invocar listeners una vez realizadas una serie de operaciones, evitando que se pudiesen invocar más veces, y que en el ejecución de alguna de estas, se llegase a algún estado inestable. Con ello evitamos también que puedan interferir o ralentizar el proceso de dibujado de capas, y a su vez, mejorar la interactividad.

Antes de empezar a recibir los eventos se debe activar el modo buffer en la instancia de EventBuffer invocando el método beginAtomicEvent(), y una vez se considere que ya no se van a recibir más eventos atómicos, se le debe de indicar que acabe el modo, invocando endAtomicEvent().

AtomicEvent es un tipo de evento propio de la librería libFMap, este tipo de eventos se define genéricamente en la clase FMapEvent.

images/mapcontext/smalldceventbuffer.png

Diagrama 2: diagrama donde se muestra la clase EventBuffer, que usa MapContext para trabajar con conjuntos de eventos como atómicos, y donde se muestran los interfaces que implementa.

Pulse aquí si desea ver el diagrama 2 ampliado.

MapContext, por otro lado, permite registrar listeners de eventos de recepción de cambios en las leyendas de las capas (LegendListener), notificación que se ha pintado o se va a pintar una capa (LayerDrawingListener), o de eventos de errores producidos en cualquier operación de los componentes de MapContext (ErrorListener).

images/mapcontext/dcgroupsreglists.png

Diagrama 3: conjunto de listeners que puede registrar MapContext y lanzar cuando recibe algún evento de los soportados por alguna de ellas.

Atributos de MapContext

Conversión de Unidades de Medida

MapContext define dos vectores públicos (uno para metros y otro para centímetros) con los valores con que habría de dividirse un valor dado en una de las medidas soportadas (véase ViewPort) para obtener el equivalente en metros, o en centímetros.

Medidas soportadas

Entre corchetes, el número indica la posición en el vector:

  • [0]: kilómetro
  • [1]: metro
  • [2]: centímetro
  • [3]: milímetro
  • [4]: milla internacional estatutaria
  • [5]: yarda
  • [6]: pie
  • [7]: pulgada
  • [8]: grado - Esta unidad es calculada así: sabiendo que el radio aproximado de la Tierra es de R=6.37846082678100774672e6, queremos medir la distancia en línea recta entre dos puntos en su superfície. Si partimos de tener 2 puntos en la superfície de la Tierra que están a un grado entre ellos, la unión entre estos tres puntos (radio y los 2 puntos en la superfície) nos da un triángulo isósceles, que si lo dividimos por la mitad, nos dará 2 triángulos rectángulos, donde el ángulo menor es de 0.5 grados, y un cateto es el radio terrestre, y el otro la mitad de la distancia (D) que queremos calcular. Aplicando trigonometría y despejando D, tenemos que: D = 2 * (sin (1)) * R. Luego si invertimos este valor, sabremos cuántos grados equivalen a un metro, y éste es el valor que está almacenado en el vector. Idem para la conversión centímetros. Posteriormente, cuando se utilice este valor, se debe tener en cuenta la proyección que se está usando en el mapa, para obtener los grados según dicha proyección.
Ejemplos de uso
  • 1 milla estatutaria internacional / MapContext.CHANGEM[4] = M1 metros
  • 1 kilómetro / MapContext.CHANGEM[0] = M2 metros
  • 1 grado / MapContext.CHANGEM[8] = M3 metros
  • 1 milla estatutaria internacional / MapContext.CHANGE[4] = C1 centímetros
  • 1 kilómetro / MapContext.CHANGE[0] = C2 centímetros
  • 1 grado / MapContext.CHANGE[8] = C3 centímetros

Funcionalidad

LayerEventListener

Clase definida en MapContext para tratar eventos producidos en cualquier tipo de las capas de éste.

En concreto trata eventos de:

  • Se ha añadido, movido o eliminado capa.
  • Se está a punto de a añadir, mover o eliminar capa.
  • Ha cambiado la visibilidad de alguna capa.

ViewPort

Introducción

ViewPort es la clase utilizada por todas aquellas que deseen realizar una transformación afín 2D entre 2 áreas rectangulares, obteniendo coordenadas de píxel a partir de las de la capa visual (llamémosle mapa).

ViewPort en el contexto de MapContext

Así, pues, y aunque se utiliza en otras partes de gvSIG, nos centraremos en el uso que hace la clase MapContext, que se encarga del almacenar la información necesaria para visualizar capas en vistas de gvSIG.

Un objeto de tipo MapContext contendrá una instancia de ViewPort, que servirá para que se pueda visualizar el área rectangular de trabajo seleccionada sobre las capas gráficas, en el área disponible (llamémosle imageSize) que hay para visualizarla en el objeto MapControl que los contiene.

Así pues, tenemos 2 planos: el del mapa, y el de la pantalla; y cada uno puede estar en distinta unidad de medidad. MapContext permitirá realizar la conversión de medidas, entre ambos planos vía su objeto tipo ViewPort, y teniendo en cuenta su proyección. ViewPort define varias unidades de medida: metro, kilómetro, yarda, milla estatutaria internacional, etc.

En ViewPort, al área seleccionada para visualizar del mapa, la llamaremos extent, a la disponible para visualizarla, de la pantalla, dimensionSize, y a la seleccionada ajustada para que sea proporcional en ancho y alto a la disponible, adjustedExtent.

Al realizar el ajuste, el área "extra" se rellenará con el mapa, o, en última instancia, con el color de fondo del objeto ViewPort.

ViewPort almacena en un objeto de tipo ExtentHistory los últimos extents, dando la opción de recargar el previo cada vez.

Para acelerar el dibujado, se busca pintar la menor información necesaria, de manera que si al realizar la transformación mapa a ventana hay puntos muy cercanos que representan el mismo píxel o tres píxels juxtapuestos, se pintará uno. Por ello, cada vez que ViewPort recalcula la tranformación afín, además de recalcular adjustedExtent y la escala entre este e imageSize, se calcula la distancia en el mundo real a que equivalen 1 o 3 píxels juxtapuestos.

Visión Global

images/mapcontext/dcviewport.png

Diagrama 1: diagrama de clases simplificado de ViewPort en MapContext. Se muestran las clases e interfaces de sus atributos.

Atributos del ViewPort

Unidades de Medida

Las unidades de medida soportadas, tanto para distancias como para del mapa original son:

Funcionalidad

ViewPortListener

Interfaz para la captura y tratamiento de los eventos asociados a un ViewPort, que son:

  • ColorEvent: cambio de color de fondo.
  • ExtentEvent: cambio de área seleccionada.
  • ProjectionEvent: cambio de proyección.
ExtentHistory

Diseñada para tener un historial de Rectangle2D que representan áreas rectangulares seleccionadas de capa/s gráfica/s.

Se gestionan de manera que se puede agregar nuevas, pero sólo almacena una cantidad máxima (por defecto 10), elimando las más antiguas, y obteniendo siempre la última agregada.

Ejemplo

images/dirimejviewport/ejviewportim1.png

Imagen 1: Una vista de gvSIG, donde se indica la dimensión del área disponible para visualizar las capas.

images/dirimejviewport/ejviewportim2.png

Imagen 2: La vista de la Imagen 1, sobre la que se ha cargado dos capas. El/la usuario/a selecciona un área de interés, esta será el extent. Así, cuando deje de seleccionar, se recalculará el nuevo adjustedExtent.

images/dirimejviewport/ejviewportim3.png

Imagen 3: La vista de la Imagen 2, donde se visualiza el área de interés seleccionada, adaptada a las dimensiones disponibles. Se puede observar como se ha ampliado el ancho seleccionado, por mantener una proporción al aspecto del área disponible de visualización.