Esta resposta está dividida em várias seções:
Análise e Redução do Problema , mostrando como encontrar o ponto desejado com rotinas "enlatadas".
Ilustração: um Protótipo de Trabalho , fornecendo código de trabalho.
Exemplo , mostrando exemplos das soluções.
Armadilhas , discutindo problemas em potencial e como lidar com eles.
Implementação do ArcGIS , comentários sobre a criação de uma ferramenta personalizada do ArcGIS e onde obter as rotinas necessárias.
Análise e Redução do Problema
Vamos começar por observar que, no (perfeitamente redonda) modelo esférico haverá sempre ser uma solução --em verdade, exatamente duas soluções. Dados os pontos base A, B e C, cada par determina sua "bissetor perpendicular", que é o conjunto de pontos equidistantes dos dois pontos dados. Essa bissetriz é uma geodésica (grande círculo). A geometria esférica é elíptica : quaisquer duas geodésicas se cruzam (em dois pontos únicos). Assim, os pontos de interseção da bissetriz de AB e da bissetriz de BC são - por definição - equidistantes de A, B e C, resolvendo assim o problema. (Veja a primeira figura abaixo.)
As coisas parecem mais complicadas em um elipsóide, mas , como é uma pequena perturbação da esfera, podemos esperar um comportamento semelhante. (A análise disso nos levaria muito longe.) As fórmulas complicadas usadas (internamente em um SIG) para calcular distâncias precisas em um elipsóide não são uma complicação conceitual: o problema é basicamente o mesmo. Para ver como o problema é realmente simples, vamos declarar algo abstrato. Nesta declaração, "d (U, V)" refere-se à distância verdadeira e totalmente precisa entre os pontos U e V.
Dados três pontos A, B, C (como pares lat-lon) em um elipsóide, encontre um ponto X para o qual (1) d (X, A) = d (X, B) = d (X, C) e ( 2) essa distância comum é a menor possível.
Todas essas três distâncias dependem do X desconhecido . Assim, as diferenças nas distâncias u (X) = d (X, A) - d (X, B) e v (X) = d (X, B) - d (X, C) são funções com valor real de X. Novamente, de maneira um pouco abstrata, podemos reunir essas diferenças em um par ordenado. Também usaremos (lat, lon) como coordenadas para X, permitindo-nos considerá-lo também como um par ordenado, digamos X = (phi, lambda). Nesta configuração, a função
F (phi, lambda) = (u (X), v (X))
é uma função de uma parte de um espaço bidimensional que recebe valores no espaço bidimensional e nosso problema se reduz a
Encontre todo o possível (phi, lambda) para o qual F (phi, lambda) = (0,0).
Aqui é onde a abstração compensa: existe um grande número de ótimos softwares para resolver esse problema (busca de raiz multidimensional puramente numérica). O modo como funciona é que você escreve uma rotina para calcular F e depois a repassa para o software, juntamente com qualquer informação sobre restrições em sua entrada ( phi deve estar entre -90 e 90 graus e lambda deve estar entre -180 e 180 graus). Ele dispara por uma fração de segundo e retorna (normalmente) apenas um valor de ( phi , lambda ), se puder encontrar um.
Há detalhes para lidar, porque há uma arte nisso: existem vários métodos de solução para escolher, dependendo de como F "se comporta"; ajuda a "orientar" o software, fornecendo a ele um ponto de partida razoável para sua pesquisa (essa é uma maneira de obtermos a solução mais próxima , em vez de qualquer outra); e você geralmente precisa especificar o quão preciso você gostaria que a solução fosse (para que ele saiba quando interromper a pesquisa). (Para saber mais sobre o que os analistas de GIS precisam saber sobre esses detalhes, que surgem muito nos problemas de SIG, visite os tópicos de recomendação a serem incluídos em um curso de Ciência da computação para tecnologias geoespaciais e consulte a seção "Miscelânea" no final. )
Ilustração: um protótipo funcional
A análise mostra que precisamos programar duas coisas: uma estimativa inicial bruta da solução e o cálculo do próprio F.
A estimativa inicial pode ser feita por uma "média esférica" dos três pontos base. Isso é obtido representando-as em coordenadas cartesianas geocêntricas (x, y, z), calculando a média dessas coordenadas e projetando essa média de volta para a esfera e reexpressando-a em latitude e longitude. O tamanho da esfera é imaterial e, portanto, os cálculos são feitos de maneira direta: como esse é apenas um ponto de partida, não precisamos de cálculos elipsoidais.
Para este protótipo de trabalho, usei o 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
]
(A If
condição final testa se a média pode falhar claramente ao indicar uma longitude; nesse caso, ela volta a uma média aritmética reta das latitudes e longitudes de sua entrada - talvez não seja uma ótima opção, mas pelo menos válida. Para aqueles que usam este código para orientação de implementação, observe que os argumentos do Mathematica ArcTan
são revertidos em comparação com a maioria das outras implementações: seu primeiro argumento é a coordenada x, seu segundo é a coordenada y e retorna o ângulo feito pelo vetor ( x, y).)
Quanto à segunda parte, porque o Mathematica - como o ArcGIS e quase todos os outros GIS - contém código para calcular distâncias precisas no elipsóide, não há quase nada para escrever. Apenas chamamos a rotina de busca de raiz:
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
];
O aspecto mais notável dessa implementação é como ela evita a necessidade de restringir a latitude ( f
) e a longitude ( q
), sempre computando-as nos módulos 180 e 360 graus, respectivamente. Isso evita ter que restringir o problema (que geralmente cria complicações). Os parâmetros de controle MaxIterations
etc. são ajustados para tornar esse código a maior precisão possível.
Para vê-lo em ação, vamos aplicá-lo aos três pontos base fornecidos em uma pergunta relacionada :
sol = tri @@ (bases = {{-6.28530175, 106.9004975375}, {-6.28955287, 106.89573839}, {-6.28388865789474, 106.908087643421}})
{-6,29692, 106,907}
As distâncias calculadas entre esta solução e os três pontos são
{1450.23206979, 1450.23206979, 1450.23206978}
(estes são metros). Eles concordam com o décimo primeiro dígito significativo (que é muito preciso, na verdade, uma vez que as distâncias raramente são precisas ou melhores que um milímetro). Aqui está uma figura desses três pontos (preto), seus três bissetores mútuos e a solução (vermelho):
Exemplo
Para testar esta implementação e entender melhor como o problema se comporta, aqui está um gráfico de contorno da discrepância quadrática média da raiz nas distâncias para três pontos base amplamente espaçados. (A discrepância do RMS é obtida calculando as três diferenças d (X, A) -d (X, B), d (X, B) -d (X, C) ed (X, C) -d (X , A) calculando a média de seus quadrados e obtendo a raiz quadrada.É igual a zero quando X resolve o problema e aumenta à medida que X se afasta de uma solução, e mede o quão "próximos" estamos de ser uma solução em qualquer local. )
Os pontos base (60, -120), (10, -40) e (45,10) são mostrados em vermelho nesta projeção do Plate Carree; a solução (49.2644488, -49.9052992) - que levou 0,03 segundos para calcular - está em amarelo. Sua discrepância RMS é inferior a três nanômetros , apesar de todas as distâncias relevantes serem milhares de quilômetros. As áreas escuras mostram valores pequenos do RMS e as áreas claras mostram valores altos.
Este mapa mostra claramente que outra solução está próxima (-49.2018206, 130.0297177) (calculada em um RMS de dois nanômetros, definindo o valor da pesquisa inicial diametralmente oposto à primeira solução).
Armadilhas
Instabilidade numérica
Quando os pontos de base são quase colineares e próximos, todas as soluções estarão a quase meio mundo de distância e extremamente difíceis de definir com precisão. A razão é que pequenas mudanças em um local em todo o mundo - movendo-o para ou longe dos pontos de base - induzirão apenas mudanças incrivelmente pequenas nas diferenças de distâncias. Apenas não há precisão e precisão suficientes incorporadas no cálculo usual das distâncias geodésicas para determinar o resultado.
Por exemplo, começando com os pontos base em (45.001, 0), (45, 0) e (44.999,0), que são separados ao longo do Meridiano Prime por apenas 111 metros entre cada par, tri
obtém a solução (11.8213, 77.745 ) As distâncias dele até os pontos de base são 8.127.964,998 77; 8.127.964,998 41; e 8.127.964,998 65 metros, respectivamente. Eles concordam com o milímetro mais próximo! Não tenho certeza de quão preciso seja esse resultado, mas não ficaria nem um pouco surpreso se outras implementações retornassem locais distantes deste, mostrando quase a mesma igualdade das três distâncias.
Tempo de computação
Esses cálculos, porque envolvem uma pesquisa considerável usando cálculos de distância complicados, não são rápidos, geralmente exigindo uma fração perceptível de segundo. Os aplicativos em tempo real precisam estar cientes disso.
Implementação do ArcGIS
Python é o ambiente de script preferido para o ArcGIS (começando com a versão 9). O pacote scipy.optimize possui um rootfinder multivariado root
que deve fazer o que FindRoot
faz no código do Mathematica . É claro que o próprio ArcGIS oferece cálculos precisos de distância elipsoidal. O resto, então, são todos os detalhes da implementação: decida como as coordenadas do ponto base serão obtidas (de uma camada digitada pelo usuário? De um arquivo de texto? Do mouse?) E como a saída será apresentada (como coordenadas exibido na tela - como um ponto gráfico - como um novo objeto de ponto em uma camada?), escreva essa interface, transporta o código do Mathematica mostrado aqui (direto) e você estará pronto.