
L'utilisation de données géospatiales et de cartes cartographiques fait partie intégrante de nombreuses applications commerciales. Il peut s'agir de systèmes d'information urbains et régionaux, d'applications pour l'industrie pétrolière et gazière, de systèmes de gestion des infrastructures de transport, ainsi que de services de livraison et bien d'autres. Dans notre plate-forme CUBA, pour créer de telles applications, en plus des fonctionnalités de base fournies, il existe un ensemble assez étendu de modules complémentaires et de composants . L'un d'eux est Charts and Maps , qui, en plus d'afficher des graphiques, vous permet d'intégrer Google maps dans la partie visuelle de l'application. L'année dernière, Google a mis à jour les conditions d'utilisation de ses services de cartographie, ce qui a entraîné une augmentation des coûts, et a également introduit la condition de la présence obligatoire d'un profil de paiement pour l'utilisation de l'API. Ces circonstances ont amené la plupart de nos clients à penser à d'autres fournisseurs de cartes et nous avons été invités à développer un nouveau composant de carte.
Nous sommes maintenant heureux de vous présenter un tout nouveau composant - CUBA Maps . CUBA Maps complète la fonctionnalité de l'application avec une représentation visuelle et des outils intuitifs pour l'édition des données géospatiales. Le composant fonctionne avec les données raster et vectorielles. Vous pouvez utiliser n'importe quel fournisseur de carte compatible avec le protocole Web Map Service ou fournir des vignettes au format XYZ en tant que données raster. Pour travailler avec des données vectorielles, le composant utilise des types de données géométriques (point, polyligne, polygone) de la bibliothèque JTS Topology Suite (JTS) - la bibliothèque Java la plus populaire pour travailler avec des données géospatiales. Le composant fournit tous les outils nécessaires pour créer un système d'information géographique complet basé sur CUBA.
Dans cet article, nous parlerons des nouvelles fonctionnalités offertes par le composant Maps, et le comparerons également avec notre composant de carte précédent.
Structure basée sur les couches
Le composant prend en charge la structure multicouche traditionnelle qui est largement utilisée dans les systèmes d'information géographique professionnels. Les couches sont principalement divisées en raster et vecteur. Les couches raster sont constituées d'images raster, tandis que les couches vectorielles contiennent des géométries vectorielles.
Le composant prend en charge les types de calques suivants:
- La couche de tuiles affiche les tuiles fournies par les services de tuiles au format XYZ.
- La couche Web Map Service (WMS) affiche les images fournies par les services WMS.
- La couche vectorielle contient des géo-objets (entités avec des attributs géométriques).
Ces couches sont des éléments structurels des cartes. Par exemple, la couche inférieure peut être une carte de base composée de tuiles, la deuxième couche peut contenir des polygones décrivant des unités territoriales, par exemple des régions, et la couche supérieure peut contenir des points géographiques (localisation des clients, des magasins, etc.). En superposant ces couches les unes sur les autres, nous obtenons la carte finale:

Grâce à cette approche, vous pouvez créer des cartes clairement structurées avec n'importe quel contenu.
CUBA Maps fournit un nouveau composant visuel - GeoMap
. Dans le descripteur XML du composant, vous pouvez définir les paramètres de base de la carte, ainsi qu'un ensemble de couches affichées. Un exemple d'une telle configuration:
<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>
Cette approche vous permet d'obtenir plus de flexibilité qui faisait défaut dans les graphiques et les cartes :
- Superposition. Cette structure vous permet de créer des cartes avec n'importe quel contenu, par exemple, de combiner des tuiles fournies par divers services.
- Les couches fournissent une abstraction qui rassemble des objets homogènes. Dans le composant Graphiques et cartes , tout le contenu de la carte (par exemple, des points, des polygones, etc.) a été vidé dans un tas commun dans le composant d'interface utilisateur. Afin de structurer ces objets, les équipes de projet ont dû écrire une logique supplémentaire.
- Une méthode déclarative pour décrire les couches. Comme le montre l'exemple ci-dessus, vous pouvez spécifier complètement la structure de la carte (ensemble de couches) dans le descripteur XML. Dans de nombreux cas, cela suffit pour ne pas implémenter de logique supplémentaire dans le contrôleur d'écran. À l'aide de graphiques et de cartes, il était presque impossible de faire sans écrire de logique supplémentaire.
L'utilisation de couches de tuiles ou de WMS vous permet de travailler avec n'importe quel fournisseur de cartes préféré. Vous n'êtes pas lié à un fournisseur spécifique, comme c'était le cas dans les graphiques et les cartes .
Les couches vectorielles simplifient considérablement l'affichage, l'édition interactive et le dessin des géo-objets sur la carte.
Il convient également de noter que le composant visuel de GeoMap
par défaut une couche auxiliaire spéciale - Canvas . Canvas fournit une API pratique pour afficher et dessiner des géométries (points, polylignes, polygones) sur une carte. Nous couvrirons des exemples d'utilisation de Canvas plus loin dans l'article.
Objets géographiques
Supposons que nous ayons une entité qui contient un attribut associé à la géométrie (point, polyligne, polygone). Nous appellerons cette entité un géo-objet . Ainsi, le composant simplifie considérablement le travail avec les géo-objets.
Par exemple, considérez l' adresse de l' objet géographique:
@Entity public class Address extends StandardEntity { ... @Column(name = "LOCATION") @Geometry @MetaProperty(datatype = "GeoPoint") @Convert(converter = CubaPointWKTConverter.class) protected Point location; ... }
Il a un attribut d' location
de type org.locationtech.jts.geom.Point
de la bibliothèque JTS Topology Suite (JTS). Le composant prend en charge les types géométriques suivants de JTS:
org.locationtech.jts.geom.Point
- point.org.locationtech.jts.geom.LineString
- polyligne.org.locationtech.jts.geom.Polygon
- polygone.
L'attribut d' location
est balisé avec l'annotation @Geometry
. Cette annotation annonce que la valeur de cet attribut doit être utilisée lors de l'affichage d'un géo-objet sur la carte. L'attribut est également marqué des annotations suivantes:
@MetaProperty
- dans ce cas, utilisé pour indiquer l'attribut de type de données . L'interface de Datatype
utilisée par le framework CUBA pour convertir des valeurs vers et depuis une chaîne.@Convert
- Définit un convertisseur JPA pour un attribut persistant. Le convertisseur JPA convertit les valeurs d'attribut entre ses représentations dans la base de données et le code Java. Le composant fournit un ensemble de types de données spatiales et de convertisseurs JPA. Plus d'informations sont disponibles dans la documentation des composants. Vous pouvez également utiliser votre propre implémentation du convertisseur JPA, qui permet de travailler avec différentes sources de données spatiales (par exemple, PostGIS ).
Ainsi, pour transformer une entité en géo-objet, vous devez définir un attribut du type de géométrie JTS et l'annoter avec @Geometry
. Il existe une autre option - créer un attribut non persistant en fournissant des méthodes getter / setter. Cela peut être utile si vous ne souhaitez pas modifier le modèle de données et régénérer les scripts DDL.
Par exemple, considérez l' adresse de l'entité avec des attributs distincts pour la latitude et la longitude:
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 vous décidez d'utiliser cette approche, assurez-vous que la méthode propertyChanged
est appelée dans le setter, car le composant répond à cet événement en mettant à jour la géométrie sur la carte.
Maintenant que nous avons préparé la classe de notre géo-objet, nous pouvons ajouter des instances de cette classe à la couche vectorielle. Une couche vectorielle est essentiellement un élément de connexion entre des données (géo-objets) et une carte. Pour connecter des géo-objets à une couche, vous devez transférer le conteneur de données ou, dans le cas d'écrans obsolètes (jusqu'à la version 7 de CUBA), la source de données vers la couche vectorielle. Cela peut être fait dans un descripteur XML:
<maps:geoMap id="map"> <maps:layers> ... <maps:vector id="addressesLayer" dataContainer="addressesDc"/> </maps:layers> </maps:geoMap>
Par conséquent, les instances de classe Address
contenues dans le conteneur addressDc seront affichées sur la carte.
Considérons une tâche élémentaire: créer un écran pour éditer un géo-objet avec une carte, où vous pouvez éditer la géométrie de l'objet. Pour résoudre le problème, vous devez déclarer le composant visuel de GeoMap
dans le descripteur XML de l'écran d'édition et ajouter une couche vectorielle associée au conteneur contenant le géo-objet édité:
<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 vous marquez la couche vectorielle comme modifiable, l'édition interactive du géo-objet sur la carte est activée. Si la géométrie de l'objet est vide, la carte passe automatiquement en mode dessin. Comme vous pouvez le voir, pour résoudre le problème, il suffit de déclarer une couche vectorielle sur la carte et de lui passer le conteneur de données / source de données.
C’est tout. Si nous utilisions des graphiques et des cartes pour résoudre le même problème, nous aurions à écrire beaucoup de code dans le contrôleur d'écran pour fournir des fonctionnalités similaires. Avec le nouveau composant de Maps, la résolution de tels problèmes est beaucoup plus simple.
Toile
Il y a des moments où vous ne devez pas travailler avec des entités. Au lieu de cela, vous voulez une API simple pour ajouter et dessiner des géométries sur une carte, comme c'était le cas dans les graphiques et les cartes . Pour cela, le composant visuel GeoMap
a une couche spéciale - Canvas . Il s'agit d'une couche auxiliaire, qui est sur la carte par défaut et qui fournit une API simple pour ajouter et dessiner des géométries sur la carte. Vous pouvez map.getCanvas()
carte de map.getCanvas()
en appelant la méthode map.getCanvas()
.
Ensuite, nous examinerons quelques tâches simples, comment elles ont été résolues dans les graphiques et les cartes et comment faire de même à l'aide de Canvas.
Afficher les géométries sur une carte
Dans les graphiques et les cartes, les objets géométriques ont été créés à l'aide du composant visuel de la carte, utilisé comme usine, puis ajoutés à la carte:
Marker marker = map.createMarker(); GeoPoint position = map.createGeoPoint(lat, lon); marker.setPosition(position); map.addMarker(marker);
Le nouveau composant Maps fonctionne directement avec les classes de la bibliothèque JTS:
CanvasLayer canvasLayer = map.getCanvas(); Point point = address.getLocation(); canvasLayer.addPoint(point);
Modification de la géométrie
Dans les graphiques et les cartes, vous pouvez désigner la géométrie comme modifiable. Lorsque de telles géométries ont été modifiées via l'interface utilisateur, les événements correspondants ont été appelés:
Marker marker = map.createMarker(); GeoPoint position = map.createGeoPoint(lat, lon); marker.setPosition(position); marker.setDraggable(true); map.addMarker(marker); map.addMarkerDragListener(event -> {
Dans le composant Maps , lors de l'ajout d'une géométrie JTS à Canvas, la méthode correspondante renvoie un objet spécial qui est une représentation de cette géométrie sur la carte: CanvasLayer.Point
, CanvasLayer.Polyline
ou CanvasLayer.Polygon
. Cet objet possède une interface fluide pour définir divers paramètres de géométrie, il peut également être utilisé pour s'abonner à des événements liés à la géométrie ou pour supprimer la géométrie d'un canevas.
CanvasLayer canvasLayer = map.getCanvas(); CanvasLayer.Point location = canvasLayer.addPoint(address.getLocation()); location.setEditable(true) .setPopupContent(address.getName()) .addModifiedListener(modifiedEvent -> address.setLocation(modifiedEvent.getGeometry()));
Dessin géométrique
Dans les anciens tableaux et cartes complémentaires, il y avait un composant auxiliaire - DrawingOptions
. Il a été utilisé pour activer la possibilité de dessiner sur la carte. Une fois la géométrie dessinée, l'événement correspondant a été déclenché:
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 -> {
Le composant Maps rend la même chose beaucoup plus facile. Le nouveau canevas de cartes contient un ensemble de méthodes pour dessiner des géométries. Par exemple, pour dessiner un polygone, utilisez la méthode canvas.drawPolygon()
. Après avoir appelé cette méthode, la carte passe en mode de dessin de polygone. La méthode accepte la fonction Consumer<CanvasLayer.Polygon>
, dans laquelle vous pouvez effectuer des actions supplémentaires avec le polygone dessiné.
canvasLayer.drawPolygon(polygon -> { territory.setPolygon(polygon.getGeometry()); });
Outils de géo-analyse
Regroupement
Un autre outil utile présent dans le nouveau composant Maps est le regroupement de points. Si la couche se compose d'un grand nombre de points, vous pouvez activer le clustering pour regrouper les points voisins en clusters afin que la carte soit plus nette et mieux perçue:

Le clustering est activé en ajoutant la balise de cluster
à l'intérieur de la balise vector
dans le descripteur XML:
<maps:vector id="locations" dataContainer="locationsDc" > <maps:cluster/> </maps:vector>
Vous pouvez également activer le clustering en fonction des poids ponctuels. Le poids du point est la valeur de l'attribut spécifié dans le paramètre weightProperty
.
<maps:vector id="orders" dataContainer="ordersDc" > <maps:cluster weightProperty="amount"/> </maps:vector>
Cartes thermiques
Les cartes thermiques sont une représentation visuelle de la densité des données sur plusieurs emplacements géographiques. Le composant visuel de GeoMap contient une méthode pour ajouter une carte thermique: addHeatMap(Map<Point, Double> intensityMap)
.

Conclusion
Le traitement, l'analyse et la visualisation des données géospatiales sont un élément essentiel de nombreuses applications commerciales. Le composant CUBA Maps fournira à votre application CUBA tous les outils nécessaires pour implémenter cette fonctionnalité.
Une structure basée sur les couches aide à créer des cartes avec n'importe quel contenu. Avec les couches de tuiles / WMS, vous pouvez utiliser n'importe quel fournisseur dont vous avez besoin comme carte de base. Les couches vectorielles vous permettent de travailler efficacement avec des ensembles de géo-objets homogènes. Canvas fournit une API simple pour afficher et dessiner des géométries sur une carte.
Le composant fonctionne avec des types spatiaux de la bibliothèque JTS, ce qui le rend compatible avec de nombreux autres cadres (par exemple, GeoTools ) pour résoudre un large éventail de tâches liées au traitement et à l'analyse des données géographiques.
Nous espérons que vous apprécierez le composant. En attente de vos commentaires!