Nuevas tarjetas CUBA

mapas


Trabajar con datos geoespaciales y mapas cartográficos son partes integrales de muchas aplicaciones comerciales. Pueden ser sistemas de información municipales y regionales, aplicaciones para la industria del petróleo y el gas, sistemas de gestión de infraestructura de transporte, así como servicios de entrega y muchos otros. En nuestra Plataforma CUBA, para construir tales aplicaciones, además de las características básicas provistas de fábrica, hay un conjunto bastante extenso de complementos y componentes . Uno de ellos es Gráficos y mapas , que, además de mostrar gráficos, le permite integrar mapas de Google en la parte visual de la aplicación. El año pasado, Google actualizó los términos de uso de sus servicios de mapas, lo que llevó a un aumento en el costo, y también introdujo la condición para la presencia obligatoria de un perfil de pago para usar la API. Estas circunstancias llevaron a la mayoría de nuestros clientes a pensar en proveedores de tarjetas alternativos, y se nos solicitó desarrollar un nuevo componente de tarjeta.


Ahora nos complace presentar un componente completamente nuevo: CUBA Maps . CUBA Maps complementa la funcionalidad de la aplicación con una representación visual y herramientas intuitivas para editar datos geoespaciales. El componente funciona con datos ráster y vectoriales. Puede usar cualquier proveedor de mapas compatible con el protocolo del Servicio de mapas web o proporcionar mosaicos en formato XYZ como datos ráster. Para trabajar con datos vectoriales, el componente utiliza tipos de datos geométricos (punto, polilínea, polígono) de la biblioteca JTS Topology Suite (JTS) , la biblioteca Java más popular para trabajar con datos geoespaciales. El componente proporciona todas las herramientas necesarias para crear un sistema integral de información geográfica basado en CUBA.


En este artículo, hablaremos sobre las nuevas características que ofrece el componente Mapas y también lo compararemos con nuestro componente de mapa anterior.


Estructura basada en capas


El componente admite la estructura multicapa tradicional que se usa ampliamente en los sistemas profesionales de información geográfica. Las capas se dividen principalmente en ráster y vector. Las capas ráster consisten en imágenes ráster, mientras que las capas vectoriales contienen geometrías vectoriales.


El componente admite los siguientes tipos de capas:


  • La capa de mosaico muestra los mosaicos proporcionados por los servicios de mosaico en formato XYZ.
  • La capa del Servicio de mapas web (WMS) muestra las imágenes proporcionadas por los servicios WMS.
  • La capa vectorial contiene geoobjetos (entidades con atributos geométricos).

Estas capas son elementos estructurales de los mapas. Por ejemplo, la capa inferior puede ser un mapa base que consta de mosaicos, la segunda capa puede contener polígonos que describen unidades territoriales, por ejemplo, regiones, y la capa superior puede contener puntos geográficos (ubicación de clientes, tiendas, etc.). Superponiendo estas capas una encima de la otra, obtenemos el mapa final:


capas


Gracias a este enfoque, puede crear mapas claramente estructurados con cualquier contenido.


CUBA Maps proporciona un nuevo componente visual: GeoMap . En el descriptor XML del componente, puede establecer los parámetros básicos del mapa, así como un conjunto de capas mostradas. Un ejemplo de tal configuración:


 <maps:geoMap id="map" height="600px" width="100%" center="37.615, 55.752" zoom="10"> <maps:layers selectedLayer="addressLayer"> <maps:tile id="tiles" tileProvider="maps_OpenStreetMap"/> <maps:vector id="territoryLayer" dataContainer="territoryDc"/> <maps:vector id="addressLayer" dataContainer="addressDc" editable="true"/> </maps:layers> </maps:geoMap> 

Este enfoque le permite lograr una mayor flexibilidad que faltaba en Gráficos y Mapas :


  • Capas. Esta estructura le permite crear tarjetas con cualquier contenido, por ejemplo, combinar mosaicos proporcionados por varios servicios.
  • Las capas proporcionan una abstracción que reúne objetos homogéneos. En el componente Gráficos y mapas , todos los contenidos del mapa (por ejemplo, puntos, polígonos, etc.) se volcaron en un montón común en el componente UI. Para estructurar de alguna manera estos objetos, los equipos del proyecto tuvieron que escribir lógica adicional.
  • Un método declarativo para describir capas. Como se muestra en el ejemplo anterior, puede especificar completamente la estructura del mapa (conjunto de capas) en el descriptor XML. En muchos casos, esto es suficiente para no implementar ninguna lógica adicional en el controlador de pantalla. Usando Gráficos y Mapas era casi imposible hacerlo sin escribir lógica adicional.

El uso de capas de mosaico o WMS le permite trabajar con cualquier proveedor de mapas preferido. No está vinculado a un proveedor específico, como estaba en Gráficos y Mapas .


Las capas vectoriales simplifican enormemente la visualización, la edición interactiva y el dibujo de geoobjetos en el mapa.


También vale la pena señalar que el componente visual de GeoMap por defecto tiene una capa auxiliar especial: Canvas . Canvas proporciona una API conveniente para mostrar y dibujar geometrías (puntos, polilíneas, polígonos) en un mapa. Cubriremos ejemplos de uso de Canvas más adelante en el artículo.


Geo objetos


Supongamos que tenemos una entidad que contiene un atributo asociado con la geometría (punto, polilínea, polígono). Llamaremos a esta entidad un geoobjeto . Entonces, el componente simplifica enormemente el trabajo con geoobjetos.


Por ejemplo, considere la dirección del objeto geográfico:


 @Entity public class Address extends StandardEntity { ... @Column(name = "LOCATION") @Geometry @MetaProperty(datatype = "GeoPoint") @Convert(converter = CubaPointWKTConverter.class) protected Point location; ... } 

Tiene un atributo de location de tipo org.locationtech.jts.geom.Point de la biblioteca JTS Topology Suite (JTS). El componente admite los siguientes tipos geométricos de JTS:


  • org.locationtech.jts.geom.Point : punto.
  • org.locationtech.jts.geom.LineString - polilínea.
  • org.locationtech.jts.geom.Polygon - polígono.

El atributo de location está etiquetado con la anotación @Geometry . Esta anotación anuncia que el valor de este atributo debe usarse al mostrar un geoobjeto en el mapa. El atributo también está marcado con las siguientes anotaciones:


  • @MetaProperty : en este caso, se utiliza para indicar el atributo de tipo de datos . El marco CUBA utiliza la interfaz Datatype para convertir valores hacia y desde una cadena.
  • @Convert : define un convertidor JPA para un atributo persistente. El convertidor JPA convierte los valores de atributo entre sus representaciones en la base de datos y el código Java. El componente proporciona un conjunto de tipos de datos espaciales y convertidores JPA. Hay más información disponible en la documentación del componente. También puede usar su propia implementación del convertidor JPA, que le permite trabajar con varias fuentes de datos espaciales (por ejemplo, PostGIS ).

Por lo tanto, para convertir una entidad en un geoobjeto, debe definir un atributo del tipo de geometría JTS y anotarlo con @Geometry . Hay otra opción: crear un atributo no persistente proporcionando métodos getter / setter. Esto puede ser útil si no desea realizar cambios en el modelo de datos y regenerar los scripts DDL.


Por ejemplo, considere la dirección de la entidad con atributos separados para latitud y longitud:


 import com.haulmont.addon.maps.gis.utils.GeometryUtils; ... @Entity public class Address extends StandardEntity { ... @Column(name = "LATITUDE") protected Double latitude; @Column(name = "LONGITUDE") protected Double longitude; ... @Geometry @MetaProperty(datatype = "GeoPoint", related = {"latitude", "longitude"}) public Point getLocation() { if (getLatitude() == null || getLongitude() == null) { return null; } return GeometryUtils.createPoint(getLongitude(), getLatitude()); } @Geometry @MetaProperty(datatype = "GeoPoint") public void setLocation(Point point) { Point prevValue = getLocation(); if (point == null) { setLatitude(null); setLongitude(null); } else { setLatitude(point.getY()); setLongitude(point.getX()); } propertyChanged("location", prevValue, point); } ... } 

Si decide utilizar este enfoque, asegúrese de que se llame al método propertyChanged en el setter, ya que el componente responde a este evento actualizando la geometría en el mapa.


Ahora que hemos preparado la clase de nuestro geoobjeto, podemos agregar instancias de esta clase a la capa vectorial. Una capa vectorial es esencialmente un elemento de conexión entre datos (geoobjetos) y un mapa. Para conectar objetos geográficos con una capa, debe transferir el contenedor de datos o, en el caso de pantallas obsoletas (hasta la versión 7 de CUBA), fuente de datos a la capa vectorial. Esto se puede hacer en un descriptor XML:


 <maps:geoMap id="map"> <maps:layers> ... <maps:vector id="addressesLayer" dataContainer="addressesDc"/> </maps:layers> </maps:geoMap> 

Como resultado, las instancias de la clase Address contenidas en el contenedor AddressDc se mostrarán en el mapa.


Consideremos una tarea elemental: crear una pantalla para editar un geoobjeto con un mapa, donde puede editar la geometría del objeto. Para resolver el problema, debe declarar el componente visual de GeoMap en el descriptor XML de la pantalla de edición y agregar una capa vectorial asociada con el contenedor que contiene el geoobjeto editado:


 <maps:geoMap id="map" height="600px" width="100%" center="37.615, 55.752" zoom="10"> <maps:layers selectedLayer="addressLayer"> <maps:tile ..."/> <maps:vector id="addressLayer" dataContainer="addressDc" editable="true"/> </maps:layers> </maps:geoMap> 

Si marca la capa vectorial como editable, se activa la edición interactiva del geoobjeto en el mapa. Si la geometría del objeto está vacía, el mapa cambiará automáticamente al modo de dibujo. Como puede ver, para resolver el problema, es suficiente declarar una capa vectorial en el mapa y pasarle el contenedor de datos / fuente de datos.


Eso es todo Si utilizáramos Gráficos y Mapas para resolver el mismo problema, tendríamos que escribir bastante código en el controlador de pantalla para proporcionar una funcionalidad similar. Con el nuevo componente de Maps, resolver estos problemas es mucho más simple.


Lienzo


Hay momentos en los que necesita trabajar no con entidades. En cambio, desea una API simple para agregar y dibujar geometrías en un mapa, como lo fue en Gráficos y Mapas . Para esto, el componente visual GeoMap tiene una capa especial: Canvas . Esta es una capa auxiliar, que está en el mapa de manera predeterminada y que proporciona una API simple para agregar y dibujar geometrías en el mapa. Puede map.getCanvas() mapa de map.getCanvas() llamando al método map.getCanvas() .


A continuación, veremos algunas tareas simples, cómo se resolvieron en Gráficos y Mapas y cómo hacer lo mismo con Canvas.


Mostrar geometrías en un mapa


En Gráficos y mapas, los objetos de geometría se crearon usando el componente visual del mapa, se usaron como una fábrica y luego se agregaron al mapa:


 Marker marker = map.createMarker(); GeoPoint position = map.createGeoPoint(lat, lon); marker.setPosition(position); map.addMarker(marker); 

El nuevo componente de Maps funciona directamente con las clases de la biblioteca JTS:


 CanvasLayer canvasLayer = map.getCanvas(); Point point = address.getLocation(); canvasLayer.addPoint(point); 

Edición de geometría


En Gráficos y mapas, puede designar la geometría como editable. Cuando tales geometrías se cambiaron a través de la interfaz de usuario, los eventos correspondientes se llamaron:


 Marker marker = map.createMarker(); GeoPoint position = map.createGeoPoint(lat, lon); marker.setPosition(position); marker.setDraggable(true); map.addMarker(marker); map.addMarkerDragListener(event -> { // do something }); 

En el componente Mapas , al agregar geometría JTS a Canvas, el método correspondiente devuelve un objeto especial que es una representación de esta geometría en el mapa: CanvasLayer.Point , CanvasLayer.Polyline o CanvasLayer.Polygon . Este objeto tiene una interfaz fluida para configurar varios parámetros de geometría, también se puede utilizar para suscribirse a eventos relacionados con la geometría o para eliminar geometría de un lienzo.


 CanvasLayer canvasLayer = map.getCanvas(); CanvasLayer.Point location = canvasLayer.addPoint(address.getLocation()); location.setEditable(true) .setPopupContent(address.getName()) .addModifiedListener(modifiedEvent -> address.setLocation(modifiedEvent.getGeometry())); 

Dibujo de geometría


En los mapas y mapas complementarios anteriores había un componente auxiliar: DrawingOptions . Se utilizó para activar la capacidad de dibujar en el mapa. Después de dibujar la geometría, se generó el evento correspondiente:


 DrawingOptions options = new DrawingOptions(); PolygonOptions polygonOptions = new PolygonOptions(true, true, "#993366", 0.6); ControlOptions controlOptions = new ControlOptions( Position.TOP_CENTER, Arrays.asList(OverlayType.POLYGON)); options.setEnableDrawingControl(true); options.setPolygonOptions(polygonOptions); options.setDrawingControlOptions(controlOptions); options.setInitialDrawingMode(OverlayType.POLYGON); map.setDrawingOptions(options); map.addPolygonCompleteListener(event -> { //do something }); 

El componente Mapas hace que lo mismo sea mucho más fácil. El nuevo Canvas de mapas contiene un conjunto de métodos para dibujar geometrías. Por ejemplo, para dibujar un polígono, use el método canvas.drawPolygon() . Después de llamar a este método, el mapa cambiará al modo de dibujo de polígono. El método acepta la función Consumer<CanvasLayer.Polygon> , en la que puede realizar acciones adicionales con el polígono dibujado.


 canvasLayer.drawPolygon(polygon -> { territory.setPolygon(polygon.getGeometry()); }); 

Herramientas de geoanálisis


Agrupación


Otra herramienta útil presente en el nuevo componente de Mapas es la agrupación de puntos. Si la capa consta de una gran cantidad de puntos, puede habilitar la agrupación para agrupar los puntos cercanos en grupos para que el mapa se vea más ordenado y mejor percibido:


grupo


La agrupación en clústeres se habilita agregando la etiqueta del cluster dentro de la etiqueta del vector en el descriptor XML:


 <maps:vector id="locations" dataContainer="locationsDc" > <maps:cluster/> </maps:vector> 

También puede habilitar la agrupación en función de los pesos de los puntos. El peso del punto es el valor del atributo especificado en el parámetro weightProperty .


 <maps:vector id="orders" dataContainer="ordersDc" > <maps:cluster weightProperty="amount"/> </maps:vector> 

Mapas de calor


Los mapas de calor son una representación visual de la densidad de datos en múltiples ubicaciones geográficas. El componente visual de GeoMap contiene un método para agregar un mapa de calor: addHeatMap(Map<Point, Double> intensityMap) .


mapa de calor


Conclusión


El procesamiento, análisis y visualización de datos geoespaciales es un elemento esencial de muchas aplicaciones comerciales. El componente CUBA Maps le proporcionará a su aplicación CUBA todas las herramientas necesarias para implementar esta funcionalidad.


Una estructura basada en capas ayuda a construir mapas con cualquier contenido. Con las capas de mosaico / WMS, puede usar cualquier proveedor que necesite como tarjeta base. Las capas vectoriales le permiten trabajar eficazmente con conjuntos de geoobjetos homogéneos. Canvas proporciona una API simple para mostrar y dibujar geometrías en un mapa.


El componente funciona con tipos espaciales de la biblioteca JTS, lo que lo hace compatible con muchos otros marcos (por ejemplo, GeoTools ) para resolver una amplia gama de tareas relacionadas con el procesamiento y análisis de datos geográficos.


Esperamos que disfrute el componente. Esperando sus comentarios!

Source: https://habr.com/ru/post/464517/


All Articles