Les requêtes d’élévation dans Giro3D

By vendredi 4 octobre 2024NewsFR, Open Source

Cet article concerne des fonctionnalités publiées avec la version 0.36 de Giro3D.

Giro3D 0.36 introduit un système de requêtes d’élévation sur les Maps. Nous allons explorer cette API ainsi que quelques cas d’usages typiques.

Pré-requis: les couches d’élévation

Pour bénéficier de l’API de requêtes d’élévation, une Map doit être dotée d’une couche d’élévation. Les couches d’élévation peuvent lire des données de sources diverses, comme des GeoTIFF ou des couches tuilées (comme celles fournies par l’IGN ou Mapbox).

Requêter une élévation sur une coordonnée

Une fois notre Map et notre couche d’élévation prêtes, nous pouvons commencer à requêter les élévations. Cela passe par la méthode getElevation().

// Mont-Blanc
const coordinates = new Coordinates('EPSG:4326', 6.864594, 45.833641);

const elevationResult = map.getElevation({ coordinates });

getElevation() ne renvoie pas directement une valeur unique, mais un objet contenant une série d’échantillons (samples). Nous pouvons ordonner ces échantillons par résolution, puis récupérer celui ayant la meilleure résolution.

if (result.samples.length > 0) {
    result.samples.sort((a, b) => a.resolution - b.resolution);

    const best = result.samples[0];
    const elevation = best.elevation;

    console.log(`Elevation for coordinate: ${elevation} m`);
}

Il est ainsi possible de requêter plusieurs Maps simultanément, d’agréger leurs échantillons, puis de récupérer le meilleur.

Requêter plusieurs maps ?

Dans un contexte typique, une scène ne contient qu’une seule map. Mais il existe des scénarios ou plusieurs map dotées de données d’élévation sont présentes simultanément dans une scène, voire se chevauchent.

C’est le cas par exemple d’une scène contenant une mosaïque hétérogène de rasters d’élévation (chacun étant réprésenté par une Map). Dans ce cas nous devrons créer un objet pour stocker les résultats plutôt que de laisser getElevation() le faire pour nous, puis requêter toutes les map en leur passant cet objet:

const coordinates = new Coordinates('EPSG:4326', 6.864594, 45.833641);

const result = { samples: [], coordinates: options.coordinates };

for (const map of allMaps) {
    map.getElevation({ coordinates }, result);
}

if (result.samples.length > 0) {
    result.samples.sort((a, b) => a.resolution - b.resolution);

    const best = result.samples[0];
    const elevation = best.elevation;

    console.log(`Best sample for coordinate: ${elevation} m`);
}

Positionner des labels sur un terrain

Pour en savoir plus, voir l’exemple complet sur le site de Giro3D.

Un cas d’usage typique des requêtes d’élévation est le positionnement de labels sur le terrain. Supposons que nous voulions mettre une label au sommet du Mont-Blanc, mais que nous ne disposions que de sa latitude et longitude et pas son élévation:

const labelObject = new CSS2DObject(/** options */);

// Mont-Blanc
const coordinates = new Coordinates('EPSG:4326', 6.864594, 45.833641).as('EPSG:3857');

labelObject.position.setX(coordinates.x);
labelObject.position.setY(coordinates.y);

// ... After elevation query on the coordinates

labelObject.position.setZ(elevation);

Il est ainsi possible de positionner rapidement un grand nombre d’objets à la surface du terrain.

Positionnement de labels sur le terrain

Positionnement de labels sur le terrain

Limites

La requête d’élévation ne lit que les données actuellement présentes en mémoire, et ne fait aucune requête HTTP. Les données chargées dépendent du point de vue actuel : si la caméra est très éloignée du terrain, des données de faible résolution seront chargées. Cela peut avoir un impact sur la qualité du positionnement, notamment lorsque l’on se rapproche.

Pour pallier à ce problème, il suffit de procéder à une nouvelle requête d’élévation lorsque les données actuellement chargées changent. Nous pouvons pour cela ajouter un listener sur l’événement de changement d’élévation de la map, et mettre à jour les labels situées dans la zone de mise à jour (extent).

function updateLabels(extent) {
    // Code
}

map.addEventListener('elevation-changed', ({ extent }) => updateLabels(extent));

Créer un profil d’élévation

Pour en savoir plus, voir l’exemple complet sur le site de Giro3D.

Un autre scénario typique faisant usage des requêtes d’élévation est bien sûr le profil d’élévation. Il est relativement simple de créer un profil d’élévation en utilisant 3 composants:

  • les requêtes d’élévation
  • les outils de dessins Giro3D que nous avons présentés dans un article précédent.
  • la librairie chart.js
Dessin d'un profil d'élévation

Dessin d’un profil d’élévation

Le profil est créé en requếtant des dizaines, voire centaines d’élévations en un temps très court (moins d’une seconde généralement).

Bien sûr, les mêmes limites s’appliquent: il s’agit de requêter uniquement les données chargées, et aucune requête HTTP supplémentaire n’est effectuée par Giro3D. Il s’agit donc d’un cas idéal pour fournir aux utilisateurs un aperçu très rapide sans surcharger les serveurs.

Les performances

Les requêtes d’élévation sont généralement très rapides: de l’ordre de la dizaine de millisecondes.

Dans l’exemple Giro3D des profils d’élévation, les 200 échantillons sont obtenus en moins de 200 millisecondes. Un profil de 10 000 échantillons est réalisé en moins de 400 millisecondes.

Conclusion

Les requêtes d’élévation sont un moyen souple et performant de combler le fossé entre la géomatique 2D et 3D, sans nécessiter de service additionnel de type OGC WPS.