MapContext
Documentos relacionados con el dibujado, gestión y almacenamiento de capas de MapControl.
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.
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.
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).
Atributos de MapContext
- Nodo raíz opcional de tipo FLayers para el árbol con las capas.
- Capa (GraphicLayer) opcional para geometrías y símbolos editables.
- ViewPort con información para que pueda dibujar MapControl la información seleccionada de las capas.
- Lista de listeners de tipo LegendListener, que se utilizan con los cambios en las leyendas de las capas.
- Lista de listeners de tipo LayerDrawingListener, que se utilizan para notificar que se ha pintado o se va a pintar una capa.
- Un buffer (EventBuffer) para almacenar una serie de eventos, y luego lanzarlos todos de una vez. Estos eventos pueden ser:
- Producidos en una capa (FLayer): LayerEvent.
- Producidos en un colección de capas (FLayers): LayerCollectionEvent, LayerPositionEvent.
- Producidos en leyendas de una capa de tipo clasificable: LegendChangedEvent, LegendEvent.
- Producidos en el puerto de vista (ViewPort): ExtentEvent, ColorEvent, ProjectionEvent.
- Producidos por la selección en una capa alfanumérica: SelectionEvent.
- Eventos atómicos: AtomicEvent.
- Un listener de tipo LayerEventListener, para la notificación de eventos en cualquier tipo de capa de las que contiene MapContext. El tipo de eventos es:
- Se ha añadido, movido o eliminado una capa del árbol de capas.
- Una capa está a punto de añadirse, moverse o eliminarse del árbol de capas.
- Ha cambiado la visibilidad de una capa.
- Ha cambiado la selección de capas en el árbol.
- Una lista con los errores producidos en cualquier capa.
- Una lista con los errores producidos en el mapa.
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.
- Vector para conversión a metros: MapContext.CHANGEM .
- Vector para conversión a centímetros: MapContext.CHANGE .
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
- Atomicidad: iniciar o terminar un evento atómico usando EventBuffer, y agregar o eliminar listeners de tipo AtomicEventListener para manejar este tipo de eventos.
- Clonación: soporta dos modos, una clonación total, o una copia parcial con lo necesario para el pintado.
- Dibujado de capas: en principio, el dibujado que soporta es solo de las capas que almacena MapContext, con la lógica de dibujado de cada una. Para acelerar el proceso de dibujado, solo se dibujan o redibujan aquellas capas "sucias", por eso, MapContext soporta tres tipos de dibujado:
- Solo la capa con símbolos y geometrías.
- Dibujado de todas las capas que lo requieran (estén sucias).
- Dibujado de todas las capas. En este caso y en el anterior puede establecer la calidad de dibujado mediante antialiasing de texto y símbolos, y mediante la calidad del renderizado.
- Escala de la vista: obtener o establecer la escala del puerto de vista teniendo en cuenta la resolución en puntos por pulgada en la pantalla.
- Gestión de errores: agregar, obtener o borrar los mensajes de errores producidos.
- Gestión de las capas:
- Obtener, establecer o dibujar la capa de tipo GraphicLayer.
- Obtener las capas, asociar listeners o el buffer de eventos, o dibujarlas.
- Listeners: permite trabajar con distintos tipos de listeners:
- ErrorListener: agregar este tipo de listener, o notificar a todos estos listeners registrados de un conjunto de eventos de error producidos durante una transacción atómica.
- LayerDrawingListener y LegendListener: agregar, eliminar o invocar un listener de alguno de estos tipos.
- Persistencia: crear una nueva instancia de MapContext a partir de una entidad XML, o devolver una entidad XML que represente el objeto MapContext actual (con la menor información necesaria), esta entidad tendrá:
- className: el nombre completo de la clase.
- 1 rama que será la entidad XML del ViewPort interno.
- 1 rama que será la entidad XML a partir del nodo raíz del FLayers interno.
- Comparar con otro objeto MapContext: considerará igual al objeto actual si:
- Ambos objetos son igual según el método equals de la clase Object.
- Si tienen las mismas capas.
- O, si tienen el mismo número de capas, y con el mismo nombre.
- Proyección: establecer u obtener la proyección que se utilizará con todas la capas que almacena MapContext.
- Puerto de vista: establecer u obtener el puerto de vista (ViewPort) actual de MapContext.
- Otra funcionalidad:
- Crear un objeto MapContext a partir de un puerto de vista, y el árbol de capas actual.
- Obtener el extent (dimensión y posición del área) unión del de todas las capas.
- Obtener el extent seleccionado.
- Registar el LayerEventListener del MapContext a un nodo de tipo FLayers .
- Redibujado de todas las capas.
- Define el factor de zoom por defecto para alejar o acercar el encuadre del área visible:
- Factor de Zoom In (acercar): 2
- Factor de Zoom Out (alejar): 0.5
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.
Atributos del ViewPort
- Área seleccionada a visualizar, en coordendas del mapa: extent.
- Dimensiones en pixels del área disponible para visualizarla: imageSize.
- Área que se utilizará para visualizar. Esta área es la seleccionada, ajustada al aspecto de la disponible, de forma que ampliará la seleccionada, y en caso que no hubiese suficiente, con el color de fondo: adjustedExtent.
- Escala entre el área ajustada y la disponible. Esta escala es igual para ancho y alto.
- Color de fondo por defecto.
- Transformación afín entre el área a visualizar ajustada (en coordenadas de mapa), y la disponible para visualizarla (en coordenadas de píxel).
- Proyección que se utiliza para obtener el área a visualizar.
- Unidad de medida de distancias en el área visualizada: distanceUnits.
- Unidad de medida en el mapa original: mapUnits.
- Lista de las últimas áreas visualizadas: extents. Permite ir a vistas previas.
- Posición del área visible, de la esquina donde empieza a visualizar el mapa: offset.
- Distancia en coordenadas del mundo equivalente a 1 pixel en la vista con el área a visualizar actual: dist1pixel.
- Distancia en coordenadas del mundo equivalente a 3 pixels en la vista con el área a visualizar actual: dist3pixel.
- Lista de listeners de tipo ViewPortListener asociados a este puerto de vista.
Unidades de Medida
Las unidades de medida soportadas, tanto para distancias como para del mapa original son:
- Kilómetro: unidad métrica o de longitud equivalente a 1000 metros.
- Metro: unidad de longitud del Sistema Internacional, que originalmente se estableció como la diezmillonésima parte del cuadrante del meridiano terrestre, y hoy, con más precisión, se define como la longitud del trayecto recorrido en el vacío por la luz durante un tiempo de 1/299 792 458 de segundo.
- Centímetro: centésima parte de un metro.
- Milímetro: milésima parte de un metro.
- Millas estatutarias internacionales: the international statute mile is by international agreement. It is defined to be precisely 1,760 international yards (by definition, 0.9144 m each) and is therefore exactly 1,609.344 metres (1.609344 km).
- Yarda: medida de longitud equivalente a 0,914 m.
- Pie: antigua unidad de medida que aún se utiliza en algunos países anglosajones, equivalente a 1/3 yardas y a 12 pulgadas.
- Pulgada: medida inglesa equivalente a 1/12 pies, y a 25,4 mm.
- Grados: grados según la proyección actual.
Funcionalidad
- Áreas:
- Área disponible: indicar y obtener las dimensiones (en pixels) del área disponible de visualización. Está en coordenadas de imagen.
- Área seleccionada: indicar y obtener sus dimensiones y posición. Está en coordenadas del mundo, con su sistema de medida.
- Área seleccionada ajustada a una escala de la disponible: permite obtener sus dimensiones y posición. Está en coordenadas del mundo, con su sistema de medida.
- Configuración:
- Ajuste de Extent: adaptar o no el área a visualizar a una escala de la disponible antes de calcular la transformación afín.
- Listeners: lógica a ejecutar cuando se producen ciertos eventos sobre la vista. Permite agregar o eliminar listeners a la capa.
- Clonación: obtener otra capa idéntica e independiente de la actual.
- Cálculo de la Transformación: se realiza automáticamente al refrescar el puerto de vista, cambiar de extent, o cambiar de área disponible. Este proceso además recalcula la nueva área ajustada, la escala entre área ajustada y visible, y las distancias equivalentes en coordenadas del mundo a 1 y 3 pixels.
- Conversiones: ViewPort permite realizar conversiones entre datos (puntos, distancias o Rectangle2D (dimensión + posición de un área rectangular)) en coordenadas del mapa, y coordenadas de la imagen, o viceversa.
- Offset: indicar y obtener la posición donde empieza a situar el área seleccionada transformada en el área disponible.
- Persistencia: crear una nueva instancia de ViewPort a partir de una entidad XML.
- Proyección: indicar y obtener la proyección que se ha usado para obtener el plano a partir de la información gráfica original, del que se visualiza un área.
- Unidades de medida: explicadas en el apartado Unidades de Medida.
- Otra funcionalidad:
- Color de fondo: se puede cambiar y obtener el color de fondo por defecto.
- Distancias equivalentes a 1 o 3 pixels: obtener la distancia equivalente en unidades de medida del mundo a 1 o 3 pixels en el área de visualización.
- Obtener los extents previos almacenados.
- Cambiar al extent previo, recalculando transformación afín, etc.
- Refrescar, recalculando transformación afín, ...
- Cálculo de la distancia (en coordenadas del mundo) entre dos puntos de las capas gráficas originales. Para ello se tiene en cuenta la proyección con que se ha obtenido el plano a partir de dichas capas.
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.