Cette réponse est divisée en plusieurs sections:
Analyse et réduction du problème , montrant comment trouver le point souhaité avec des routines "en conserve".
Illustration: un prototype fonctionnel , donnant un code de travail.
Exemple , montrant des exemples de solutions.
Pièges , discuter des problèmes potentiels et comment y faire face.
Implémentation d'ArcGIS , commentaires sur la création d'un outil ArcGIS personnalisé et où obtenir les routines nécessaires.
Analyse et réduction du problème
Commençons par observer que dans le modèle sphérique (parfaitement rond), il y aura toujours une solution - en fait, exactement deux solutions. Étant donné les points de base A, B et C, chaque paire détermine sa "bissectrice perpendiculaire", qui est l'ensemble des points équidistants des deux points donnés. Cette bissectrice est une géodésique (grand cercle). La géométrie sphérique est elliptique : deux géodésiques quelconques se croisent (en deux points uniques). Ainsi, les points d'intersection de la bissectrice AB et de la bissectrice BC sont - par définition - équidistants de A, B et C, résolvant ainsi le problème. (Voir la première figure ci-dessous.)
Les choses semblent plus compliquées sur un ellipsoïde, mais comme il s'agit d'une petite perturbation de la sphère, on peut s'attendre à un comportement similaire. (L'analyse de cela nous mènerait trop loin.) Les formules compliquées utilisées (en interne dans un SIG) pour calculer des distances précises sur un ellipsoïde ne sont cependant pas une complication conceptuelle: le problème est fondamentalement le même. Pour voir à quel point le problème est simple, énonçons-le de manière un peu abstraite. Dans cette déclaration, "d (U, V)" fait référence à la distance vraie et entièrement précise entre les points U et V.
Étant donné trois points A, B, C (en tant que paires lat-lon) sur un ellipsoïde, trouvez un point X pour lequel (1) d (X, A) = d (X, B) = d (X, C) et ( 2) cette distance commune est la plus petite possible.
Ces trois distances dépendent toutes du X inconnu . Ainsi, les différences de distances u (X) = d (X, A) - d (X, B) et v (X) = d (X, B) - d (X, C) sont des fonctions à valeur réelle de X. Encore une fois, de façon quelque peu abstraite, nous pouvons assembler ces différences en une paire ordonnée. Nous utiliserons également (lat, lon) comme coordonnées pour X, ce qui nous permettra de le considérer également comme une paire ordonnée, disons X = (phi, lambda). Dans cette configuration, la fonction
F (phi, lambda) = (u (X), v (X))
est une fonction d'une partie d'un espace à deux dimensions prenant des valeurs dans un espace à deux dimensions et notre problème se réduit à
Trouver tous les possibles (phi, lambda) pour lesquels F (phi, lambda) = (0,0).
C'est là que l'abstraction est payante: il existe de nombreux excellents logiciels pour résoudre ce problème (de recherche de racine multidimensionnelle purement numérique). La façon dont cela fonctionne est que vous écrivez une routine pour calculer F , puis vous la transmettez au logiciel avec toute information sur les restrictions de son entrée ( phi doit se situer entre -90 et 90 degrés et lambda doit se situer entre -180 et 180 degrés). Il démarre pendant une fraction de seconde et retourne (généralement) une seule valeur de ( phi , lambda ), s'il en trouve une.
Il y a des détails à gérer, car il y a un art à cela: il existe différentes méthodes de solution à choisir, selon la façon dont F "se comporte"; il permet de "piloter" le logiciel en lui donnant un point de départ raisonnable pour sa recherche (c'est une façon d'obtenir la solution la plus proche , plutôt que toute autre); et vous devez généralement spécifier à quel point vous souhaitez que la solution soit précise (afin qu'elle sache quand arrêter la recherche). (Pour en savoir plus sur ce que les analystes SIG doivent savoir à propos de ces détails, qui surviennent souvent dans les problèmes SIG, veuillez consulter la rubrique Recommandations à inclure dans un cours d'informatique pour les technologies géospatiales et consultez la section "Divers" vers la fin. )
Illustration: un prototype fonctionnel
L'analyse montre que nous devons programmer deux choses: une estimation initiale brute de la solution et le calcul de F lui-même.
L'estimation initiale peut être faite par une "moyenne sphérique" des trois points de base. Ceci est obtenu en les représentant en coordonnées géocentriques cartésiennes (x, y, z), en faisant la moyenne de ces coordonnées et en projetant cette moyenne dans la sphère et en la ré-exprimant en latitude et longitude. La taille de la sphère est sans importance et les calculs sont donc simples: parce que ce n'est qu'un point de départ, nous n'avons pas besoin de calculs ellipsoïdaux.
Pour ce prototype fonctionnel, j'ai utilisé Mathematica 8.
sphericalMean[points_] := Module[{sToC, cToS, cMean},
sToC[{f_, l_}] := {Cos[f] Cos[l], Cos[f] Sin[l], Sin[f]};
cToS[{x_, y_, z_}] := {ArcTan[x, y], ArcTan[Norm[{x, y}], z]};
cMean = Mean[sToC /@ (points Degree)];
If[Norm[Most@cMean] < 10^(-8), Mean[points], cToS[cMean]] / Degree
]
(La If
condition finale teste si la moyenne peut ne pas indiquer clairement une longitude; dans l'affirmative, elle revient à une moyenne arithmétique droite des latitudes et longitudes de son entrée - peut-être pas un excellent choix, mais au moins une valeur valide. Pour ceux qui utilisent ce code comme guide d'implémentation, notez que les arguments de Mathematica ArcTan
sont inversés par rapport à la plupart des autres implémentations: son premier argument est la coordonnée x, son second est la coordonnée y et il renvoie l'angle fait par le vecteur ( x, y).)
En ce qui concerne la deuxième partie, car Mathematica - comme ArcGIS et presque tous les autres SIG - contient du code pour calculer des distances précises sur l'ellipsoïde, il n'y a presque rien à écrire. Nous appelons simplement la routine de recherche de racine:
tri[a_, b_, c_] := Block[{d = sphericalMean[{a, b, c}], sol, f, q},
sol = FindRoot[{GeoDistance[{Mod[f, 180, -90], Mod[q, 360, -180]}, a] ==
GeoDistance[{Mod[f, 180, -90], Mod[q, 360, -180]}, b] ==
GeoDistance[{Mod[f, 180, -90], Mod[q, 360, -180]}, c]},
{{f, d[[1]]}, {q, d[[2]]}},
MaxIterations -> 1000, AccuracyGoal -> Infinity, PrecisionGoal -> 8];
{Mod[f, 180, -90], Mod[q, 360, -180]} /. sol
];
L'aspect le plus remarquable de cette implémentation est la façon dont elle évite la nécessité de contraindre la latitude ( f
) et la longitude ( q
) en les calculant toujours modulo à 180 et 360 degrés, respectivement. Cela évite d'avoir à contraindre le problème (ce qui crée souvent des complications). Les paramètres de contrôle, MaxIterations
etc. sont modifiés pour que ce code offre la plus grande précision possible.
Pour le voir en action, appliquons-le aux trois points de base donnés dans une question connexe :
sol = tri @@ (bases = {{-6.28530175, 106.9004975375}, {-6.28955287, 106.89573839}, {-6.28388865789474, 106.908087643421}})
{-6.29692, 106.907}
Les distances calculées entre cette solution et les trois points sont
{1450.23206979, 1450.23206979, 1450.23206978}
(ce sont des mètres). Ils s'accordent au onzième chiffre significatif (ce qui est trop précis, en fait, car les distances sont rarement précises à mieux qu'un millimètre environ). Voici une image de ces trois points (noir), de leurs trois bissectrices mutuelles et de la solution (rouge):
Exemple
Pour tester cette implémentation et mieux comprendre le comportement du problème, voici un tracé de contour de l'écart quadratique moyen des distances pour trois points de base largement espacés. (L'écart RMS est obtenu en calculant les trois différences d (X, A) -d (X, B), d (X, B) -d (X, C) et d (X, C) -d (X , A), en faisant la moyenne de leurs carrés et en prenant la racine carrée. Il est égal à zéro lorsque X résout le problème et augmente à mesure que X s'éloigne d'une solution, et mesure ainsi à quel point nous sommes «proches» d'être une solution à n'importe quel endroit. )
Les points de base (60, -120), (10, -40) et (45,10) sont représentés en rouge dans cette projection Plate Carree; la solution (49.2644488, -49.9052992) - qui a nécessité 0,03 seconde pour calculer - est en jaune. Son écart RMS est inférieur à trois nanomètres , bien que toutes les distances pertinentes soient des milliers de kilomètres. Les zones sombres montrent de petites valeurs de RMS et les zones claires montrent des valeurs élevées.
Cette carte montre clairement qu'une autre solution se trouve à proximité (-49.2018206, 130.0297177) (calculée à un RMS de deux nanomètres en définissant la valeur de recherche initiale diamétralement opposée à la première solution.)
Pièges
Instabilité numérique
Lorsque les points de base sont presque colinéaires et rapprochés, toutes les solutions seront à près d'un demi-monde et extrêmement difficiles à cerner avec précision. La raison en est que de petits changements dans un emplacement à travers le globe - le déplacer vers ou loin des points de base - n'induiront que des changements incroyablement minuscules dans les différences de distances. Il n'y a tout simplement pas assez d'exactitude et de précision intégrées dans le calcul habituel des distances géodésiques pour déterminer le résultat.
Par exemple, en commençant par les points de base à (45.001, 0), (45, 0) et (44.999,0), qui sont séparés le long du méridien principal de seulement 111 mètres entre chaque paire, tri
obtient la solution (11.8213, 77.745 ). Les distances de celui-ci aux points de base sont de 8 127 964,998 77; 8 127 964,998 41; et 8 127 964,998 65 mètres, respectivement. Ils s'entendent au millimètre près! Je ne suis pas sûr de la précision de ce résultat, mais je ne serais pas du tout surpris si d'autres implémentations renvoyaient des emplacements loin de celui-ci, montrant une égalité presque aussi bonne des trois distances.
Temps de calcul
Ces calculs, car ils impliquent une recherche considérable à l'aide de calculs de distance compliqués, ne sont pas rapides, nécessitant généralement une fraction notable de seconde. Les applications en temps réel doivent en être conscientes.
Implémentation d'ArcGIS
Python est l'environnement de script préféré pour ArcGIS (à partir de la version 9). Le paquet scipy.optimize a un rootfinder multivarié root
qui devrait faire ce qui FindRoot
fait dans le code Mathematica . Bien sûr, ArcGIS lui-même propose des calculs précis de distance ellipsoïdale. Le reste, alors, ce sont tous les détails d'implémentation: décidez comment les coordonnées du point de base seront obtenues (à partir d'un calque? Tapé par l'utilisateur? À partir d'un fichier texte? De la souris?) Et comment la sortie sera présentée (sous forme de coordonnées affiché à l'écran? comme un point graphique? comme un nouvel objet ponctuel dans un calque?), écrivez cette interface, portez le code Mathematica montré ici (simple), et vous serez prêt.