
Dans un
article précédent, j'ai expliqué comment créer une application mobile avec une carte. Dans la suite de la série "à genoux" je partagerai avec vous les outils de mise en œuvre des plans d'étage.
L'énoncé initial du problème sous une forme simplifiée: je veux pouvoir visualiser le diagramme d'étage dans votre application mobile et pouvoir y montrer l'emplacement d'une organisation particulière. J'aimerais aussi voir l'emplacement de l'utilisateur, mais ici le problème est dans le plan technique - vous avez besoin d'un équipement qui vous permettra d'obtenir les coordonnées de l'appareil à l'intérieur. Nous laissons donc cet aspect hors du champ de l'article et nous concentrons sur la partie logicielle.
Ci-dessous, je vais vous montrer plusieurs options avec lesquelles vous pouvez implémenter les exigences décrites ci-dessus. Tout dépend des données dont vous disposez et de ce que l'application devrait être en mesure de faire. Et nous allons commencer par le plus simple.
La première option. API prête avec données
La première option que nous considérerons est l'utilisation d'un widget prêt à l'emploi de 2GIS. La description de l'API peut être consultée sur
api.2gis.ru. Cela vous conviendra si le bâtiment qui vous intéresse est déjà présenté dans 2GIS et que les étages ont déjà été dessinés dans le bâtiment. Autrement dit, en termes de données, tout a déjà été fait. Et surtout, vous êtes prêt pour la connexion en ligne, car cette option fonctionnera exclusivement avec Internet.
Pour afficher les sols dans ce cas, pratiquement rien n'est exigé de vous. Implémentation de l'exécution en tant que widget Web, que vous n'avez qu'à insérer dans WebView.
<WebView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/am_webview" android:layout_marginTop="160dp" />
Ceci est le conteneur dans lequel nous placerons notre widget. Nous l'initialisons comme suit:
webView = findViewById(R.id.am_webview) webView.settings.javaScriptEnabled = true webView.settings.useWideViewPort = true webView.settings.loadWithOverviewMode = true
Nous configurons le webView lui-même, assurez-vous d'activer JavaScript, javaScriptEnabled = true, car nous interagirons avec le widget à travers lui. Si nécessaire, vous pouvez activer les barres de défilement et les boutons de zoom (voir le code commenté), mais cela ne fonctionne pas très bien, donc je ne le recommande pas.
La chose la plus importante est de charger le HTML avec notre widget
webView.loadUrl ("fichier: ///android_asset/map_api.html") et de vous abonner aux événements, si nécessaire. Dans l'exemple ci-dessus, après avoir chargé la carte, nous appelons la méthode
initMap définie dans map_api.html, en passant l'identifiant du bâtiment pour lequel nous voulons afficher les étages.
HTML est un code assez simple. La méthode
DG.FloorsWidget.init est
appelée , dans laquelle l'objet json contenant les données à initialiser est passé. En tant que conteneur, spécifiez l'id avec lequel nous avons déclaré un div dans le balisage HTML ci-dessus. Ajustez la largeur, la hauteur. Et dans
initData, nous transmettons le bâtiment dans la balise
complexId et des paramètres d'affichage de widget supplémentaires, qui peuvent être trouvés dans la documentation de l'API. Soit dit en passant, l'identifiant peut être vu en réponse à la requête de recherche, que 2GIS envoie lorsque vous cliquez sur le bâtiment qui vous intéresse sur
2gis.ru. Dans mon exemple, j'ai utilisé le Dubai Mall. Mais personne ne se soucie d'indiquer un autre bâtiment avec des planchers.
La touche finale. Pour passer à une entreprise spécifique, appelez la méthode showFirm, en passant l'identifiant de l'entreprise
webView.loadUrl("javascript:showFirm('$firmId')")
C'est assez simple. Un exemple d'implémentation prêt à l'emploi peut être consulté sur
Github .

Avantages de l'option envisagée:
- des données toutes faites avec des plans d'étage et des données d'entreprise;
- mise en œuvre légère prête à l'emploi sur la visualisation Web;
- recherche prête selon 2GIS.
Inconvénients:
- Internet requis;
- une connaissance de base de HTML et JavaScript est requise;
- seules les données 2GIS et uniquement les bâtiments qui ont déjà des étages.
La deuxième option. Plan d'étage en image
Si l'option avec des données prêtes et l'API ne vous convient pas, vous pouvez utiliser ce qui suit.
Dans ce cas, vous aurez besoin d'un plan d'étage sous la forme d'une image, disons jpeg ou png. Si une interactivité du type "enfoncé dans l'image - a ouvert la carte d'objet" est requise, alors le géocodage sera également nécessaire, qui devra être mis en œuvre indépendamment. Si vous accrochez aux coordonnées globales, l'image doit être correctement mise à l'échelle et l'un des coins doit être tiré aux coordonnées réelles afin que vous puissiez calculer les déplacements à partir de celle-ci. Nous ne nous attarderons pas sur cette question en détail, j'espère que tout est clair ici.
La chose la plus importante est de montrer cette image dans l'application. Et pour cela, la bibliothèque
TileView est idéale pour nous. En fait, cette bibliothèque permet, en principe, d'afficher des tuiles de carte. Mais cela nous convient aussi, car il offre la possibilité de se déplacer et de zoomer, de se centrer dans une position spécifiée, d'afficher des marqueurs, de transformer les coordonnées et de s'abonner à divers événements.
Pour que la bibliothèque fonctionne le plus efficacement possible, l'image originale doit être préparée en la découpant en tuiles. Il existe une
instruction assez simple
pour cela . Je recommande un script à la fin de la page spécifiée qui créera 4 ensembles de tuiles. Nous ajoutons le résultat obtenu aux actifs et affichons notre image dans l'activité avec un code simple:
tileView.setSize(floorWidth, floorHeight) tileView.setShouldRenderWhilePanning(true) tileView.addDetailLevel(1f, "tiles/floors1/1000/%d_%d.jpg") tileView.addDetailLevel(0.500f, "tiles/floors1/500/%d_%d.jpg") tileView.addDetailLevel(0.250f, "tiles/floors1/250/%d_%d.jpg") tileView.addDetailLevel(0.125f, "tiles/floors1/125/%d_%d.jpg") tileView.defineBounds(0.0, 0.0, floorWidth.toDouble(), floorHeight.toDouble()) tileView.setScaleLimits(0f, 5f) tileView.setMinimumScaleMode(ZoomPanLayout.MinimumScaleMode.FIT)
Tout, l'écran est prêt. Vous pouvez vous abonner aux événements et ajouter la logique nécessaire. Par exemple, un marqueur peut être affiché comme ceci:
tileView.setMarkerAnchorPoints(-0.5f, -0.5f) tileView.addMarker(imageView, x, floorHeight - y, null, null)
Un exemple complet est disponible sur
Github .

Avantages:
- la possibilité de faire complètement hors ligne;
- préparation des données relativement simple, plan d'étage sous forme d'image.
Inconvénients:
- manque de style dynamique.
La troisième option. Données vectorielles
Cette option est la plus avancée et la plus difficile. Il suppose que vous avez préparé des données vectorielles, c'est-à-dire des sols complètement dessinés dans le vecteur. Vous aurez besoin de plusieurs types d'objets. Zones d'organisations, parkings, aires de restauration, scènes, patinoires, etc. Objets linéaires - principalement murs, directions d'écoulement. Objets ponctuels: entrées / sorties, ascenseurs, distributeurs automatiques de billets et similaires.
Voici à quoi ressemble un plan d'étage aux Fidji, système interne 2GIS:

Eh bien, pour leur visualisation, le moteur vectoriel, dont j'ai parlé dans l'
article précédent , mapsforge-vtm nous convient.
Pour démontrer l'approche, j'ai préparé des données de test: un ensemble de carrés et de lignes pour plusieurs étages en utilisant l'exemple d'un bâtiment sur l'île ensoleillée de Chypre. Pour la préparation, j'ai pris la géométrie d'origine du bâtiment et je l'ai découpée en morceaux correspondant aux composants de la géométrie, uniquement pour des raisons de simplicité. Comme vous le savez, la partie la plus difficile est la préparation de données de qualité. Le reste est une question de technologie. Vous aurez besoin de boutons pour changer d'étage, de styles préparés pour le rendu de différents carrés et lignes et d'une superposition pour les rendre.
Voir le code complet
ici .
La classe
FloorData contient le code de géodonnées de test pour nos sols, et la classe
FloorsManager est conçue pour les rendre.
Dans le constructeur, nous définissons des styles pour les carrés et les murs:
styles.put(ObjectType.Floor, org.oscim.layers.vector.geometries.Style.builder() .fillColor(Color.GRAY) .build());
Et dans la méthode
drawFloor ,
nous déterminons la logique de l'ajout d'objets aux couches sur la carte:
public void drawFloor(int floorId) { hideFloors(); indoorLayer = new CustomVectorLayer(this.map); List<GeoData> geoObjects = this.floorData.getFloorData(floorId); for (GeoData geo: geoObjects) { indoorLayer.add(geo.getGeometry(), styles.get(geo.getObjectType())); } this.map.layers().add(indoorLayer); indoorLayer.update(); }
Ici, tout est élémentaire. Créez une nouvelle couche
indoorLayer , ajoutez-y des données d'étage pré-préparées avec les styles nécessaires et ajoutez la couche à la carte
this.map.layers (). Ajoutez (indoorLayer) .
Reste à ajouter des boutons pour changer d'étage. Pour ce faire, il existe un
FloorPickerControl basé sur
RecyclerView , qui fait exactement ce dont vous avez besoin. Ne perdons pas de temps dessus, voir la source.
Et voici le Dubai Mall dans notre application. Il a également implémenté la modification des objets géographiques.

Avantages:
- encore une fois, la possibilité de faire complètement hors ligne;
- image de haute qualité;
- la possibilité d'une variété de stylisation dynamique;
- la possibilité d'implémenter un éditeur de données.
Inconvénients:
- préparation de données complexes.
À la fin de l'article, je tiens à dire que la tâche d'afficher les plans d'étage dans l'application n'est pas aussi terrible que cela puisse paraître à première vue. Vous avez plusieurs options avec vos avantages et vos inconvénients, parmi lesquels vous pouvez choisir la plus appropriée pour résoudre votre problème.
Toutes les références en un seul endroit:
Article sur la carte dans le mobileAPI 2GISExemple d'API 2GISBibliothèque TileViewExemple TileViewUn exemple sur mapsforge-vtm