Projection de Mercator

a marqué ce sujet comme résolu.

Bonjour,

J’essaye d’obtenir une carte avec la latitude et la longitude depuis une carte de la terre issue de la projection de Mercator.

Pour la longitude, bon c’est pas tout à fait exacte mais grosso modo c’est pas l’idée. Pour la latitude par-contre, on est loin du compte, c’est pas bon du tout.

Vous auriez une idée de comment je peux m’y prendre ?

<!doctype html>
<html lang="fr">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Canva earth</title>
  </head>
  <body>
    <h1>Test sphere</h1>
    <canvas id="canvasIn" width="800" height="500"></canvas>
    <br>

    <label for="x"> <input type="number" value="0" id="x" readonly>
      Absice
    </label>
    <label for="y">
      <input type="number" value="0" id="y" readonly>
      Ordonnée
    </label>
    <br>

    <label for="lon">
      <input type="number" value="0" id="lon" readonly>
      Longitude
    </label>
    <label for="lat">
      <input type="number" value="0" id="lat" readonly>
      Latitude
    </label>
    <br>

    x
    <input type="number" value="0" id="bX" readonly>
    y
    <input type="number" value="0" id="bY" readonly>
    z
    <input type="number" value="0" id="bZ" readonly>
  </body>
  <script>
    var img = new Image();
    img.src = 'http://localhost:8080/merca.png';
    img.onload = function() {
      draw(this);
    };

    var sphere = [];

    function getLongitude(x) {
      x %= 800;
      return (x-400)/400*180;
    }
    function getLatitude(y) {
      const tmp = ((2*Math.atan(Math.exp((y+20)/500)/1.))-Math.PI/2)*3;
      return (180 - tmp * 180 / Math.PI) - 90;
    }
    function getColatitude(y) {
      return 90 - getLatitude(y);
    }

    function getXYZ(x, y) {
      const long = (90 - getLongitude(x))/180*Math.PI;
      const lat = getLatitude(y)/180*Math.PI;
      const r = 120;

      const X = r * Math.cos(lat) * Math.cos(long);
      const Y = r * Math.cos(lat) * Math.sin(long);
      const Z = r * Math.sin(lat);
      return {'x': X, 'y': Y, 'z': Z};
    }

    function draw(img) {
      var canvasIn = document.getElementById('canvasIn');
      var ctx = canvasIn.getContext('2d');
      ctx.drawImage(img, 0, 0);
      img.style.display = 'none';
      img.src = '';
      img.crossOrigin = 'anonymous';

      var coord = function(event) {
        const x = event.offsetX;
        const y = event.offsetY;

        const X= document.getElementById('x');
        const Y = document.getElementById('y');

        const lon = document.getElementById('lon');
        const lat = document.getElementById('lat');

        X.value = x;
        Y.value = y;

        lon.value = getLongitude(x);
        lat.value = getLatitude(y);

        const bX = document.getElementById('bX');
        const bY = document.getElementById('bY');
        const bZ = document.getElementById('bZ');
        const pt = getXYZ(x, y);
        bX.value = pt.x;
        bY.value = pt.y;
        bZ.value = pt.z;
      };

      canvasIn.addEventListener('mousemove', coord);
    }
  </script>
</html>

L’essentiel du calcul est ici:

function getLongitude(x) {
  x %= 800;
  return (x-400)/400*180;
}
function getLatitude(y) {
  const tmp = ((2*Math.atan(Math.exp((y+20)/500)))-Math.PI/2)*3;
  return (180 - tmp * 180 / Math.PI) - 90;
}
function getColatitude(y) {
  return 90 - getLatitude(y);
}

Les constantes sont des tentatives de coller au plus juste aux coordonnées de la carte mais j’ai conscience qu’elles ne devraient pas être là.

On devrait plutôt avoir:

function getLatitude(y) {
  const tmp = ((Math.atan(Math.exp(y/400)))-Math.PI/2);
  return (180 - tmp * 180 / Math.PI) - 90;
}

Mais ça ne colle pas du tout aux coordonnées, il y a quelque chose que je loupe ?!

Edit: J’utilise une image de Wikipédia.

merca.png
merca.png
+0 -0

Salut,

Plutôt que bricoler un truc sur une carte dont tu n’es pas sûr de la position de l’origine, pourquoi ne pas produire la carte souhaitée directement? Un outil comme GMT ou bien cartopy devrait être capable de te sortir la carte voulue.

+0 -0

J’essaye d’utiliser GMT du coup.

Sauf que la dernière modification de libc rend la compilation impossible. Dès que j’ai un truc je reviens.

  • The deprecated arrays sys_siglist, _sys_siglist, and sys_sigabbrev are no longer available to newly linked binaries, and their declarations have been removed from <string.h>. They are exported solely as compatibility symbols to support old binaries. All programs should use strsignal instead.

Humm, j’ai hotfixé à l’arrache. Il me reste ce bug qui devrait être résolu en prenant une version plus récente de GMT.

Bien donc ça compile. Pas besoin de faire de bug report, c’est déjà corriger sur master, la correction est prévu pour 6.2.0.


Bref !

D’après la doc, je teste comme ça gmt coast -Rd -Gblack -png merca ou précisément je préfère : gmt coast -R-169/191/-60/85 -Gblack -png merca mais bon, la première est plus simple donc on va resté dessus.

J’ai lu un peu la doc en diagonale et j’ai certainement loupé des trucs sur la projection de Mercator.

J’obtiens ça:

merca.png
merca.png

Toujours ok niveau longitude. Niveau latitude, c’est pas mal mais peu largement mieux faire.
Il y a quelque chose que je ne comprend pas dans mon inverse de Mercator:

    function getLatitude(y) {
      const tmp = ((Math.atan(Math.exp(y/100)))-Math.PI/4)*2;
      return (180 - tmp * 180 / Math.PI) - 90; // Ici on recentre sur 0
    }

Comment je détermine n ? Ici c’est la constante que je fixe à 100 ? Ensuite, ma valeur de latitude se situe toujours entre 0 et 90, c’est problématique. :/

Je dois multiplier par 4 au lieu de 2 à la fin pour obtenir un nombre dans les proportions souhaitée mais je suis sûr que ce n’est pas la bonne méthode !

Des idées @adri1 ?

+0 -0

Salut,

J’essaye d’obtenir une carte avec la latitude et la longitude depuis une carte de la terre issue de la projection de Mercator.

C’est une mauvaise idée sachant que :

  1. En théorie, avec Mercator, les pôles s’étendent à l’infini, avec une carte prise quelque part et qui a été découpée arbitrairement tu ne peux pas être sûr de ce que tu fais
  2. Le système de coordonnées Web Mercator (EPSG:3857), utilisé par Google Maps, OpenStreetMap et consorts, s’utilise en convertissant des tuples spécifiant niveau de zoom (exponentiel), x, y, désignant des tuiles, vers des tuples niveau de zoom, latitude, longitude lorsqu’il s’agit d’obtenir des coordonnées GPS (aka WGS84, aka EPSG:4326). Si tu n’es pas certain d’une part de la position d’origine, d’autre part du niveau de zoom tu ne peux pas faire de conversation fiable.

J’ai lu un peu la doc en diagonale et j’ai certainement loupé des trucs sur la projection de Mercator.

J’obtiens ça:

Déjà la carte que tu as généré ne ressemble pas à une Mercator, on dirait une équirectangulaire (Plate carrée). Mercator préserve les angles mais pas les distances, équirectangulaire préserve les distances mais pas les angles (aucune projection ne conserve les deux à la fois, "sauf" une vue 3D qui représente un vrai globe). Le Groenland, le Canada ou l’Islande ont une taille hypertrophiée sur une Mercator alors qu’ils sont aplatis sur une Plate carrée (voir https://thetruesize.com/ pour comprendre les déformations de Mercator).

Je pense que tu ferais bien de nous expliquer ce que tu veux faire. Est-ce que tu veux afficher une carte sur un site web et afficher les coordonnées GPS lorsque l’utilisateur bouge la souris ? Ou est-ce que tu veux "simplement" envoyer des coordonnées au serveur au clic ?

Est-ce que tu as pensé à utiliser une bibliothèque de conversion des coordonnées standard, qui par exemple comme je l’ai dit plus haut, peut convertir des coordonnées de type (zoom, x, y) vers des coordonnées de type (zoom, lat, lng), à partir d’un numéro EPSG (un numéro EPSG identifie de manière standard une projection, un système de coordonnées ou autre) ? Alternativement, et selon ce que tu veux faire, est-ce que tu as pensé à utiliser une vraie bibliothèque de cartographie comme Leaflet ?

Si tu veux simplement une carte du monde colorée avec les pays en étant sûr de ce que tu as fait pour la générer, tu peux aussi utiliser QGis (éventuellement en important les contours de pays d’OpenStreetMap en utilisant le plug-in idoine) et exporter un SVG avec. Il me semble que les coordonnées de la carte sont restituées en utilisant le système de coordonnées d’origine dans les métadonnées du fichier, dans certains cas de figure.

Si tu veux savoir si l’utilisateur a cliqué sur un pays, tu peux utiliser une bibliothèque type Raphaël.js ou D3, dessiner des polygones représentant les pays et regarder les données associées au polygone sur lequel l’utilisateur a cliqué…

Bonne journée

+0 -0

Salut @r0anne, je veux une image bitmap de la terre avec des coordonnées au mieux précise, c’est pour jouer avec. Ce n’est pas pour un site web, ce n’est pas pour jouer avec les pays, il n’y a pas de serveur (enfin si pour servir l’image m’enfin bref…), il n’y a pas d’application derrière, pas de connexion internet, pas de couleur (enfin pourquoi pas mais pas pour l’instant), rien. Juste un bitmap de 800*YYY avec des pixels de préférence noir et blanc qui représentent la terre dans une projection quelconque et je veux les coordonnées GPS d’un point.

Je m’amuse à faire des choses comme ça :

Résultat pas final du tout
Résultat pas final du tout

Bon là, c’est rond pour des raisons évidentes. Mais au final je vais juste m’amuser avec le bitmap et faire autre chose avec si j’ai d’autres idées.

Tu as tout à fait raison pour la projection. J’ai pensé là même chose, mais je me suis dis que Mercator était forcément la projection par défaut et que c’était mes connaissances qui devaient être mauvaises. Bref, cette fois-ci avec la projection mercator j’obtiens ça:

merca.png
merca.png

gmt coast -Gblack -R-169/191/-60/85 -Jm1.2e-2i -png merca

Mais coordonnées sont toujours loin d’être bonne. 😭 Je regarde ça se soir après le taf.

Vu ce que je veux faire, je ne pense pas que Leaflet soit adapté. Pas contre une bibliothèque de conversion de coordonnées standard peut-être, je ne connais pas bien le domaine.Je me renseignerais sur les EPSG, WGS84 et je reviens.

En vrai, je suis déjà assez content d’avoir découvert GMT. Je vais prendre un peu de temps à découvrir le truc. D’ailleurs, s’il y a un tout autre moyen de faire ce que je veux alors je prend également. Partir d’une carte créer moi même semble pas mauvaise comme idée. Après, certainement qu’il devrait avoir des ajustements à faire, une autre projection peut-être. Peut-être autre chose (cf. EPSG, WGS84)

Pour ce qui est des pays, j’ai déjà fait ça. À partir d’une carte wikipédia et du SVG, ça se fait très simplement. C’est assez drôle. Mais c’est pas le but ici.

+0 -0

Ok,

Je pense ce qu’il peut t’intéresser de faire, c’est d’obtenir des tableaux contenant des formes de pays constituées de coordonnées GPS brutes.

Ensuite, tu fais les projections toi-même :

  • Si tu veux faire du Mercator, tu peux te contenter de faire les calculs, de dessiner ça dans un canvas avec l’API 2D, et de voir à quel moment le résultat correspond à ce que tu escomptes (tu peux décalquer une carte par-dessus pour t’en apercevoir aussi).
  • Si tu veux faire un globe qui tourne, tu peux être intéressé par l’utilisation de Three.JS. Si tu veux faire un globe qui tourne sans bibliothèque 3D, tu peux faire sans aussi, mais dans les deux cas tu n’as pas besoin de projection 2D. Une projection 2D est un algorithme d’aplatissement, un contournement pour le fait qu’une sphère s’aplatit mal en temps normal.

Three.JS peut t’afficher une image 2D sur une sphère néanmoins, les coordonnées x,y deviendront des coordonnées u,v (on emploie la notion de coordonnées u,v lorsqu’on dessine une texture (image) sur un patron (e.g une sphère) pour produire un objet rendu (mesh)). Si tu fais de l'UV mapping tu vas vouloir utiliser une projection équirectangulaire.

Bonne journée

+0 -0

Salut,

Mais coordonnées sont toujours loin d’être bonne.

Je comprends pas ce que tu veux dire, GMT gère les coordonnées tout seul. Qu’est-ce que tu veux faire avec cette carte ? Dessiner les méridiens et parallèles ? GMT peut le faire. Mettre un point à un endroit particulier ? GMT peut le faire. C’est un outil développé par la communauté géophysique, donc la plupart des calculs et opérations sur des cartes que tu peux imaginer sont déjà implémentés.

Je réponds rapidement pour l’instant, mais ta fonction d’inversion de Mercator, tu veux en faire quoi ? C’est un peu absurde comme façon de procéder (créer une carte puis bricoler dans l’autre sens après), il vaut mieux créer la carte dont tu as besoin directement avec GMT.

Dans tous les cas, @r0anne, le fait que Mercator diverge ne pose pas de problème particulier tant que les pôles sont exclus, ce qui est le cas.

+0 -0

Je veux pouvoir retrouver les coordonnées (lat et longitude) d’un point arbitraire de la carte. Et inversement à partir des coordonnées positionner un point sur la carte. Dynamiquement, je ne connais pas le point à l’avance.

Je veux bien croire que la méthode est pas la bonne (absurde ?). Vous en avez une autre ?

+0 -0

Tu peux le faire si tu connais le système de projection ET les coordonnées de référence. Là tu n’as déjà pas l’air de connaître les coordonnées de références (tu essayes d’appliquer des formules génériques sur des cartes recadrées aux continents sauf l’Antarctique), c’est normal que les résultats ne soient pas les bons.

Tu veux dire que si je veux un truc précis, j’ai besoin de plus qu’une carte ?

Avec GMT je devrais pouvoir réussir à extraire les informations dont j’ai besoin ? J’ai pas encore eu le temps d’étudier les informations que tu m’as donné.

+0 -0

Idéalement, tu as au moins besoin de connaître les limites de ta carte (savoir que le pixel 0,0 correspond à la latitude lat,lng, et cela pour les quatre extrémités). Ou bien savoir comment l’image d’origine a été projetée si elle a été projetée sans recadrement supplémentaire (les référentiels EPSG sont faits exactement pour ça : avoir une manière unique de convertir des coordonnées projetées d’une certaine manière en des coordonnées (dé)projetées d’une certaine manière).

Je ne connais pas GMT mais on dirait que tu lui as passé des coordonnées :

-R-169/191/-60/85
+0 -0

Je veux pouvoir retrouver les coordonnées (lat et longitude) d’un point arbitraire de la carte.

D’accord, mais pourquoi ? De fait, une bibliothèque comme celle conseillée par @r0anne plus haut serait sûrement plus adaptée, parce que là, contrôler avec précision la position des pixels dans l’image de sortie, c’est pas forcément facile (GMT est un outil vectoriel plutôt que matriciel).

Avec GMT je devrais pouvoir réussir à extraire les informations dont j’ai besoin ?

Il peut te sortir la grille, oui.

+0 -0

Je veux pouvoir retrouver les coordonnées (lat et longitude) d’un point arbitraire de la carte.

D’accord, mais pourquoi ? De fait, une bibliothèque comme celle conseillée par @r0anne plus haut serait sûrement plus adaptée, parce que là, contrôler avec précision la position des pixels dans l’image de sortie, c’est pas forcément facile (GMT est un outil vectoriel plutôt que matriciel).

Pour jouer avec pardi ! ^^

Hummm, je me fiche de la grille non ? Je peux m’en servir pour retrouver les données informatiquement ?

+0 -0

Hummm, je me fiche de la grille non ?

Ben pas du tout, la grille est exactement l’info que tu cherches puisque c’est la correspondance entre position sur l’image et position GPS…

Après comme dit plus haut, ce qu’il te faut est repérer deux points sur la carte pour savoir comment elle est projetée et t’en servir pour recaler la formule que tu as montrée plus haut. Est-ce que tu comprends cette formule ? Sans ça, tu vas juste bricoler et ce serait un gros coup de bol de tomber juste, mais si tu la comprends ça devient juste un problème de l’écrire dans le bon repère et ça n’a du coup pas un intérêt prodigieux…

+0 -0

Je comprend bien que c’est l’info que je cherche mais je ne vois pas comment m’en servir.

Euh non je ne la comprend pas. J’ai pris la fonction de Wikipédia et j’ai essayé de retrouver l’inverse. Le pourquoi m’échappe. Tu dis que deux points suffisent ? J’étudie ça et je reviens.

Merci pour vos aides. ^^

+0 -0

Tu dis que deux points suffisent ?

Oui (enfin, si il ne sont pas sur le même méridien ou parallèle), par exemple deux coins opposés que tu connais puisque tu as donné les limites de la carte avec l’option -R.

Dans tes formules pour getLongitude et getLatitude, il ne te reste plus qu’ensuite à comprendre ce que sont les différents nombres et par rapport à quoi x et y sont définis (ce qui n’est pas très compliqué en prenant des valeurs remarquables et en voyant à quelles longitudes et latitudes elles correspondent).

+0 -0

Je crois que j’ai saisi l’idée !
Le recalage se fait comme pour la longitude ! Et c’est normal car on a pas les pôles. ^^

Je testes dès que j’ai le temps. :)

+0 -0

Pour être plus clair, la fonction Mercator te sort des coordonnées arbitraires appelées easting et northing (x et y, sur un plan) à partir de longitudes et latitudes (méridiens et parallèles, sur une sphère).

La fonction Mercator inverse te sort longitudes et latitudes à partir d’easting et northing.

Tu as des pixels x et y, tu veux les reconvertir en easting et nothing puis longitude et latitude, il te faudra au moins passer par trois étapes :

  • Faire une remise à l’échelle des pixels vers les coordonnées arbitraires de Mercator (aller par exemple de 800x504 pixels sur ta carte d’origine à l’échelle d’origine)
  • Faire une remise à l’échelle de l’easting et northing affichés sur ta carte matricielle vers easting et northing calculés par la fonction (si ta Mercator d’origine travaillait sur des longitudes de -180° à 180° et des latitudes de -90° à 90°, et que tu as tronqué ta carte produite pour afficher des longitudes de -169° à 191° et des latitudes de -60° à 85° comme le suggère ta commande, il faudra au moins faire une remise à l’échelle, voir même remettre l’extrémité de la Sibérie sur la bonne moitié du plan)
  • Appliquer la fonction Mercator inverse en prenant soin de vérifier que ce soit la bonne et que tu ne te plantes pas sur les degrés/radians/…

Juste pour dire.

Ça m’a pris un temps fou. Bien plus que raisonnable. Mais en étudiant bien WGS84 et en utilisant la projection plate carré plutôt que Mercator. J’arrive à ce que je veux.

Je n’ai finalement pas réussi à obtenir un truc convenable avec Mercator.

Désormais ma “sphère” est en fait une ellipsoïde et la précision de l’oddre du pixel. Je suis très content du résultat.

Je poste mon code ici dès que je suis satisfait du résultat @ http://git.ache.one/sphere
Pour l’instant c’est là : https://ache.one/labs/sphere/ Merci à vous deux. :)

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte