Mauvaise boîte englobante lors de filtre selon l'emprise de la carte
jgrosmaire opened this issue · 13 comments
Environnement
- Version de QGIS : 3.22.7
- Version du plugin isogeo : 3.4.0
- Installation de QGIS : Installation avec apt-get/executable
- Système d'exploitation : Ubuntu 20.04/Windows 10
- Architecture processeur : 64 bits
Reproduire
- Lancer QGIS
- Ouvrir le plugin
- Ouvrir un projet en Pseudo Mercartor (EPSG:3857)
- Dézoomer de telle sorte que l'intégralité du monde soit visible dans l'emprise.
- Faire une recherche selon un filtre géographique
Comportement observé
L'intégralité du monde est dans l'emprise de la carte pourtant l'URL suivant est requêté https://v1.api.isogeo.com/resources/search?&box=-85.54414890356387,-89.96426690001276,12.970226622131646,89.99338238430887&rel=intersects&_limit=0&_offset=0&_lang=fr'
où la boîte englobante ne contient pas tout le monde.
Note : Ce comportement n'est pas reproductible à chaque fois mais a lieu de manière assez régulière (30% des requêtes environ). Je ne peux pas donner de meilleures précisions pour le reproduire mais zoomer dézoomer plusieurs fois et faire une requête à chaque fois semble bien marcher, surtout quand l'intégralité de la planète est comprise dans l'emprise de la carte
Comportement attendu
La bbox est bien récupérée/reprojetée
Apparemment, les coordonnées récupérées via iface.mapCanvas().extent()
sont correctes, elles correspondent bien à un rectangle qui dépasse "les bornes" du système de coordonnées courant. C'est pendant la conversion de ces coordonnées en WGS84 que ça se corse.
Pour faire ça on utilise la méthode transform
d'un QgsCoordinateTransform
est les coordonnées obtenues en WGS84 sont correctes pour ce qui est des y mais les x sont trop petits.
J'ai posé la question sur GIS StackExchange : https://gis.stackexchange.com/questions/469039/qgscoordinatetransform-doesnt-work-correctly-for-outbound-coordinates-using-pyq
Un commentaire riche en condescendance sur mon post GIS StackExchange me laisse penser que ce comportement n'est pas résoluble. Étant donné le fait que ce genre de filtre géographique est probablement rarement utilisé et que les données dont la géométrie dépasse les bornes du CRS sont rares, je pense que je peux gérer ce sujet de 2 manières :
détecter que l'extent dépasse les bornes et alerter l'utilisateur (bandeau d'avertissement) que le résultat de la recherche risque d'être aléatoire- détecter que l'extent dépasse les bornes et arrondir les coordonnées aux bornes (de toutes façons quand ça dépasse, l'API Isogeo fait des trucs bizarres), dans ce cas on pourrait préciser ce comportement dans la doc en ligne du plugin
Recette
Il faut surtout tester avec plusieurs systèmes de coordonnées différents du WGS84, et notamment avec des systèmes fait pour une zone plus petite que la planète entière.
Tests avec Pseudo Mercator
Quand je zoom et dézoom, j'ai :
- Les résultats sur la zone quand je contient toutes une zone ✅
- Emprise plus large que la carte mais proche, il y 0 résultat ❌
box=-180.0,-85.4990878392578,180.00000000000009,86.02427210564555
- Emprise beaucoup plus grande que la carte, tous les résultats ✅
box=-180.0,-89.89231302609743,180.00000000000003,89.77313855098201
Je te laisse regarder avant de tester avec d'autres projections.
Reproduction du deuxième cas : requête de recherche à l'URL suivant avec l'opérateur "contient" :
https://v1.api.isogeo.com/resources/search?&box=-180.0,-85.76980764462886,180.00000000000009,85.76980764462884&rel=contains&_limit=0&_offset=0&_lang=fr
Requête testée dans postman : comme prévu ça renvoie 0 résultats et ça me semble normal qu'aucune fiche ait une emprise qui contient l'emprise du monde entier.
J'ai généré le polygone correspondant dans QGIS et il correspond bien à ce qui est attendu (l'emprise est rognée par le plugin)
@jgrosmaire est-ce que tu sais quel opérateur était sélectionné dans l'onglet "paramètres" ? (pour info, quand tu cliques sur le bouton de rénitialisation de la recherche, l'opérateur est remis à la valeur "intersecte")
pour la suite de la recette, quand tu as des anomalies, je veut bien que tu m'indiques l'URL de requête en entier et pas seulement la bbox
, comme ça j'aurais aussi l'opérateur qui est utilisé.
A priori le soucis c'est que selon le nivau de dézoom, même si on englobe les limites du WGS84 à chaque fois, le plugin génère une bbox différentes (les valeurs des Y varient)
Bon ya un soucis qui est dû au fait que les bornes en Y du Pseudo Mercator sont inférieures à celles du WGS84 et donc quand a l'impression d'englober tout et bah en fait c'est pas vraiment le cas du point de vu du WGS84. C'est pour ça que plus on dézoom, plus on se rapproche des bornes du WGS84 alors qu'à chaque fois on à l'impression d'englober tout.
Quoiqu'il en soit, avant l'algo fonctionnait de la manière suivante :
- récupérer l'emprise courante en Pseudo Mercator (ou autre selon CRS courant)
- récupérer les bornes du WGS84 en WGS84
- convertir les bornes du WGS84 en Pseudo Mercator
- comparer l'emprise courante en Pseudo Mercator aux bornes du WGS84 en pseudo mercator
- rogner l'emprise courante en Pseudo Mercator si elle dépasse les bornes du WGS84 en pseudo mercator
- convertir l'emprise courante rognée en WGS84
Je vais mettre une modif en QA pour qu'il fasse ça :
- récupérer l'emprise courante en Pseudo Mercator (ou autre selon CRS courant)
- récupérer les bornes en WGS84 du WGS84
- convertir l'emprise courante en WGS84
- comparer l'emprise courante en WGS84 aux bornes du WGS84 en WGS84
- rogner l'emprise courante en WGS84 si elle dépasse les bornes du WGS84 en WGS84
Parce que ça à l'air de mieux fonctionner avec le deuxième algo
@jgrosmaire c'est en QA, tu peux rechecker et poursuivre la recette si ça fonctionne
Test avec EPSG:7659
J'essaye d'expliquer au mieux ce que j'ai fait
- En faisant la commande "Zoom sur la couche" --> ok, on récupère bien tous les résultats
- Par contre, si je descentre la terre pour par exemple récupérer les données entre les latitude 60° est et 180° (en me déplaçant), j'ai des comportement bizarre et jamais les bons résultat
- Quand je ne suis pas trop proche du bord, je récupère tous les résultats et pas seulement les résultats dans mon emprise mais la bbox n'est pas toute la terre :
https://v1.api.isogeo.com/resources/search?&box=76.64249233912153,-90.0,180.0,90.0&rel=intersects&_limit=0&_offset=0&_lang=fr
- Quand je descend plus vers le bas (plus petit écart), j'ai 22 résultats (sur 40) mais pas non plus les données de l'ensemble. Par exemple, on retrouve la donnée communes de France.
https://v1.api.isogeo.com/resources/search?&box=76.2563840653728,-89.7701736465782,180.0,90.0&rel=intersects&_limit=0&_offset=0&_lang=fr
Le résultat est en fait le même en gardant la carte centrée (22 résultats sur 40 avec cette affichage) :
@jgrosmaire cette fois-ci, j'ai l'impression que le soucis provient de l'API et pas des coordonnées que le plugin lui envoie.
J'ai mis une nouvelle version du plugin dans le OneDrive qui ajoute au canevas une couche contenant la BBOX qui vient d'être envoyée à l'API à chaque fois que tu utilises le filtre géographique. Sachant que cette BBOX est rognée selon les bornes du WGS84.
Pour la suite de la recette, en gros il faut vérifier que cette couche correspond bien à l'emprise de la carte. Sachant que pour certains systèmes de coordonnées (genre le Lambert93) ça sera déformé (rapport au fait que c'est une projection conforme ou conique ou un truc du genre alors que c'est pas le cas du WGS84). Et d'autant plus si l'emprise s'éloigne des bornes du système en question (même si ça reste dans celles du WGS84). Et alors si tu t'éloignes des bornes du WGS84 là ça peut vraiment faire des dingueries mais on y peut rien.
Du coup tu risques de te retrouver avec un paquet de couches dans ton projet et comme je suis trop gentil, voici un script Python qui te permettra de toutes les supprimer quand tu l'exécutes :
from qgis.core import QgsProject, QgsRasterLayer
from qgis.utils import iface
qgs_prj = QgsProject.instance()
for layer in qgs_prj.mapLayers().values():
if layer.name().startswith("BoundingBox"):
qgs_prj.removeMapLayer(layer)
iface.mapCanvas().refresh()
Pour l'exécuter : Ctrl+Alt+P > dans le menu de la fenêtre qui s'affiche, cliquer sur > coller le script > cliquer sur
C'est bon pour moi, les bbox affichées correspondent à l'emprise de la carte