Calculando a interseção de dois círculos?

29

Estou tentando descobrir como derivar matematicamente os pontos comuns de dois círculos que se cruzam na superfície da Terra, dado um centro Lat / Lon e um raio para cada ponto.

Por exemplo, dado:

  • Lat / Lon (37.673442, -90.234036) Raio 107,5 NM
  • Lat / Lon (36.109997, -90.953669) Raio 145 NM

Eu deveria encontrar dois pontos de interseção com um deles sendo (36.948, -088.158).

Seria trivialmente fácil resolver isso em um plano plano, mas não tenho experiência em resolver equações em uma esfera imperfeita, como a superfície da Terra.

Vai
fonte
1
Se todos os seus raios forem tão pequenos (menos de vários quilômetros), a Terra é essencialmente plana nessa escala e você também pode escolher uma projeção precisa e simples e executar os cálculos euclidianos habituais. Calcule a interseção com mais de três casas decimais - a imprecisão na terceira casa decimal é tão grande quanto qualquer um dos seus raios!
whuber
1
Eu deveria ter acrescentado unidades, esses raios estão no NM, então ainda é uma pequena distância em relação à superfície da Terra, mas maior que alguns quilômetros. Como essa escala afeta a distorção? Estou tentando encontrar uma solução precisa com menos de <1nm, para que ela não precise ser super precisa. Obrigado!
Will
É bom saber tudo isso, porque mostra que você pode usar um modelo esférico da Terra - os modelos elipsoidais mais complicados são desnecessários.
whuber
@whuber Isso implica que o problema pode ser corrigido da seguinte maneira: encontre a interseção de 3 esferas em que uma delas é a terra e as outras duas estejam centradas nos pontos com seus respectivos raios?
22413 Kirk Kuykendall
@ Kirk Sim, é assim que se faz, assumindo um modelo esférico da superfície da Terra. Após alguns cálculos preliminares, isso reduz a um caso especial do problema de Trilateração em 3D. (Os cálculos são necessários para converter a distância ao longo de arcos esféricos em distâncias em acordes esféricos, que se tornam os raios das duas esferas menores.)
whuber

Respostas:

21

Não é muito mais difícil na esfera do que no avião, uma vez que você reconhece que

  1. Os pontos em questão são as interseções mútuas de três esferas: uma esfera centralizada abaixo do local x1 (na superfície da Terra) de um determinado raio, uma esfera centralizada abaixo do local x2 (na superfície da Terra) de um determinado raio e a própria Terra , que é uma esfera centralizada em O = (0,0,0) de um determinado raio.

  2. A interseção de cada uma das duas primeiras esferas com a superfície da Terra é um círculo, que define dois planos. As interseções mútuas de todas as três esferas estão, portanto, na interseção desses dois planos: uma linha .

Consequentemente, o problema é reduzido ao cruzamento de uma linha com uma esfera, o que é fácil.


Aqui estão os detalhes. As entradas são os pontos P1 = (lat1, lon1) e P2 = (lat2, lon2) na superfície da Terra, considerados como uma esfera, e dois raios correspondentes r1 e r2.

  1. Converter (lat, lon) em (x, y, z) coordenadas geocêntricas. Como sempre, porque podemos escolher unidades de medida nas quais a Terra possui um raio unitário,

    x = cos(lon) cos(lat)
    y = sin(lon) cos(lat)
    z = sin(lat).
    

    No exemplo, P1 = (-90.234036 Grau, 37.673442 Grau) possui coordenadas geocêntricas x1 = (-0.00323306, -0.7915, 0.61116) e P2 = (-90.953669 Grau, 36.109997 Grau) possui coordenadas geocêntricas x2 = (-0.0134464, -0.807775 0,589337).

  2. Converta os raios r1 e r2 (medidos ao longo da esfera) em ângulos ao longo da esfera. Por definição, uma milha náutica (NM) é 1/60 de grau de arco (que é pi / 180 * 1/60 = 0,0002908888 radianos). Portanto, como ângulos,

    r1 = 107.5 / 60 Degree = 0.0312705 radian
    r2 = 145 / 60 Degree = 0.0421788 radian
    
  3. O círculo geodésico do raio r1 em torno de x1 é a interseção da superfície da Terra com uma esfera euclidiana de raio sin (r1) centrada em cos (r1) * x1.

  4. O plano determinado pela interseção da esfera do raio sin (r1) em torno de cos (r1) * x1 e a superfície da Terra é perpendicular a x1 e passa pelo ponto cos (r1) x1, de onde sua equação é x.x1 = cos (r1) (o "." representa o produto escalar usual ); da mesma forma para o outro plano. Haverá um ponto único x0 na interseção desses dois planos que é uma combinação linear de x1 e x2. Escrevendo x0 = a x1 + b * x2, as duas equações planares são

    cos(r1) = x.x1 = (a*x1 + b*x2).x1 = a + b*(x2.x1)
    cos(r2) = x.x2 = (a*x1 + b*x2).x2 = a*(x1.x2) + b
    

    Usando o fato de que x2.x1 = x1.x2, que escreverei como q, a solução (se existir) é dada por

    a = (cos(r1) - cos(r2)*q) / (1 - q^2),
    b = (cos(r2) - cos(r1)*q) / (1 - q^2).
    

    No exemplo em execução, calculo a = 0,973503 eb = 0,0260194.

    Evidentemente, precisamos de q ^ 2! = 1. Isso significa que x1 e x2 não podem ser o mesmo ponto nem pontos antipodais.

  5. Agora todos os outros pontos na linha de interseção dos dois planos diferem de x0 por algum múltiplo de um vetor n que é mutuamente perpendicular a ambos os planos. O produto cruzado

    n = x1~Cross~x2
    

    faz o trabalho fornecido n é diferente de zero: mais uma vez, isso significa que x1 e x2 não são coincidentes nem diametralmente opostos. (Precisamos ter o cuidado de calcular o produto cruzado com alta precisão, pois envolve subtrações com muito cancelamento quando x1 e x2 estão próximos um do outro.) No exemplo, n = (0,0272194, -0,00631254, -0,00803124) .

  6. Portanto, buscamos até dois pontos da forma x0 + t * n que se encontram na superfície da Terra: ou seja, seu comprimento é igual a 1. Equivalentemente, seu comprimento ao quadrado é 1:

    1 = squared length = (x0 + t*n).(x0 + t*n) = x0.x0 + 2t*x0.n + t^2*n.n = x0.x0 + t^2*n.n
    

    O termo com x0.n desaparece porque x0 (sendo uma combinação linear de x1 e x2) é perpendicular a n. As duas soluções são facilmente

    t = sqrt((1 - x0.x0)/n.n)
    

    e é negativo. Mais uma vez, é necessária alta precisão, porque quando x1 e x2 estão próximos, x0.x0 está muito próximo de 1, levando a uma perda de precisão do ponto flutuante. No exemplo, t = 1,07509 ou t = -1,07509. Os dois pontos de interseção, portanto, são iguais

    x0 + t*n = (0.0257661, -0.798332, 0.601666)
    x0 - t*n = (-0.0327606, -0.784759, 0.618935)
    
  7. Por fim, podemos converter essas soluções de volta para (lat, lon) convertendo as coordenadas geocêntricas (x, y, z) em geográficas:

    lon = ArcTan(x,y)
    lat = ArcTan(Sqrt[x^2+y^2], z)
    

    Para a longitude, usar o arco tangente generalizada retornando valores na faixa de -180 a 180 graus (em aplicações de computação, esta função leva ambos x e y como argumentos ao invés de apenas a relação y / x, que é às vezes chamado de "ATAN2").

    Eu obtenho as duas soluções (-88.151426, 36.989311) e (-92.390485, 38.238380), mostradas na figura como pontos amarelos.

Figura 3D

Os eixos exibem as coordenadas geocêntricas (x, y, z). A mancha cinza é a parte da superfície da Terra de -95 a -87 graus de longitude e 33 a 40 graus de latitude (marcada com uma gratícula de um grau). A superfície da Terra foi parcialmente transparente para mostrar as três esferas. A correção das soluções computadas é evidente pela forma como os pontos amarelos ficam nas interseções das esferas.

whuber
fonte
Bill, isso é incrível. Um esclarecimento que você pode adicionar, com base em alguém que estava tentando implementá-lo. Na etapa 2, você não fornece explicitamente a conversão de graus para radianos.
Jersey Andy
@ Jersey Obrigado por sua edição sugerida. Mudei um pouco para evitar a redundância e manter as fórmulas o mais claras possível. Depois de ler o tópico ao qual você está se referindo, também inseri um link para explicar o produto escalar.
whuber
8

O caso elipsoidal :

Esse problema é uma generalização da localização de fronteiras marítimas definidas como "linhas medianas" e há uma extensa literatura sobre esse tópico. Minha solução para esse problema é alavancar a projeção azimutal equidistante:

  1. Adivinha no ponto de interseção
  2. Projete os dois pontos de base usando esse ponto de interseção adivinhado como o centro de uma projeção azimutal equidistante,
  3. Resolva o problema de interseção no 2º espaço projetado.
  4. Se o novo ponto de interseção estiver muito longe do anterior, volte para a etapa 2.

Esse algoritmo converge quadraticamente e produz uma solução precisa em um elipsóide. (É necessária precisão no caso de fronteiras marítimas, pois determina os direitos de pesca, petróleo e minerais.)

As fórmulas são dadas na Seção 14 da Geodésica em um elipsóide de revolução . A projeção azimutal equidistante elipsoidal é fornecida por GeographicLib . Uma versão do MATLAB está disponível em projeções geodésicas para um elipsóide .

cffk
fonte
+1 Esse é um artigo incrível: sua descrição modesta aqui não faz justiça.
whuber
Veja também meu artigo mais curto sobre geodésica "Algoritmos para geodésica" dx.doi.org/10.1007/s00190-012-0578-z (download gratuito!), Além de erratas e adendos para esses documentos geographiclib.sf.net/geod-addenda.html
Cffk 10/03
1

Aqui está um código R para fazer isso:

p1 <- cbind(-90.234036, 37.673442) 
p2 <- cbind(-90.953669, 36.109997 )

library(geosphere)
steps <- seq(0, 360, 0.1)
c1 <- destPoint(p1, steps, 107.5 * 1852)
c2 <- destPoint(p2, steps, 145 * 1852)

library(raster)
s1 <- spLines(c1)
s2 <- spLines(c2)

i <- intersect(s1, s2)
coordinates(i)

#        x        y
# -92.38241 38.24267
# -88.15830 36.98740

s <- bind(s1, s2)
crs(s) <- "+proj=longlat +datum=WGS84"
plot(s)
points(i, col='red', pch=20, cex=2)
Robert Hijmans
fonte
1

Seguindo a resposta do @ whuber , aqui está um código Java que é útil por dois motivos:

  • destaca uma dica sobre o ArcTan (para Java e talvez outras linguagens?)
  • ele lida com os possíveis casos extremos, incluindo um não mencionado na resposta do @ whuber.

Não é otimizado ou completo (deixei de lado as classes óbvias como Point), mas deve fazer o truque.

public static List<Point> intersection(EarthSurfaceCircle c1, EarthSurfaceCircle c2) {

    List<Point> intersections = new ArrayList<Point>();

    // project to (x,y,z) with unit radius
    UnitVector x1 = UnitVector.toPlanar(c1.lat, c1.lon);
    UnitVector x2 = UnitVector.toPlanar(c2.lat, c2.lon);

    // convert radii to radians:
    double r1 = c1.radius / RadiusEarth;
    double r2 = c2.radius / RadiusEarth;

    // compute the unique point x0
    double q = UnitVector.dot(x1, x2);
    double q2 = q * q;
    if (q2 == 1) {
        // no solution: circle centers are either the same or antipodal
        return intersections;
    }
    double a = (Math.cos(r1) - q * Math.cos(r2)) / (1 - q2);
    double b = (Math.cos(r2) - q * Math.cos(r1)) / (1 - q2);
    UnitVector x0 = UnitVector.add(UnitVector.scale(x1, a), UnitVector.scale(x2, b));

    // we only have a solution if x0 is within the sphere - if not,
    // the circles are not touching.
    double x02 = UnitVector.dot(x0, x0);
    if (x02 > 1) {
        // no solution: circles not touching
        return intersections;
    }

    // get the normal vector:
    UnitVector n = UnitVector.cross(x1, x2);
    double n2 = UnitVector.dot(n, n);
    if (n2 == 0) {
        // no solution: circle centers are either the same or antipodal
        return intersections;
    }

    // find intersections:
    double t = Math.sqrt((1 - UnitVector.dot(x0, x0)) / n2);
    intersections.add(UnitVector.toPolar(UnitVector.add(x0, UnitVector.scale(n, t))));
    if (t > 0) {
        // there's only multiple solutions if t > 0
        intersections.add(UnitVector.toPolar(UnitVector.add(x0, UnitVector.scale(n, -t))));
    }
    return intersections;
}

Além disso, observe o uso de atan2- é o inverso do que você esperaria da resposta do @ whuber (não sei por que, mas funciona):

    public static Point toPolar(UnitVector a) {
        return new Point(
                Math.toDegrees(Math.atan2(a.z, Math.sqrt(a.x * a.x + a.y * a.y))),
                Math.toDegrees(Math.atan2(a.y, a.x)));          
    }
ianhoolihan
fonte
0

Código 'R' em funcionamento para a resposta @wuhber.

P1 <- c(37.673442, -90.234036)
P2 <- c(36.109997, -90.953669) 

#1 NM nautical-mile is 1852 meters
R1 <- 107.5
R2 <- 145

x1 <- c(
  cos(deg2rad(P1[2])) * cos(deg2rad(P1[1])),  
  sin(deg2rad(P1[2])) * cos(deg2rad(P1[1])),
  sin(deg2rad(P1[1]))
);

x2 <- c(
  cos(deg2rad(P2[2])) * cos(deg2rad(P2[1])),
  sin(deg2rad(P2[2])) * cos(deg2rad(P2[1])),
  sin(deg2rad(P2[1]))
);

r1 = R1 * (pi/180) * (1/60)
r2 = R2 * (pi/180) * (1/60)

q = dot(x1,x2)
a = (cos(r1) - cos(r2) * q) / (1 - q^2)
b = (cos(r2) - cos(r1) * q)/ (1 - q^2)

n <- cross(x1,x2)

x0 = a*x1 + b*x2


t = sqrt((1 - dot(x0, x0))/dot(n,n))

point1 = x0 + (t * n)
point2 = x0 - (t * n)

lat1 = rad2deg(atan2(point1[2] ,point1[1]))
lon1= rad2deg(asin(point1[3]))
paste(lat1, lon1, sep=",")

lat2 = rad2deg(atan2(point2[2] ,point2[1]))
lon2 = rad2deg(asin(point2[3]))
paste(lat2, lon2, sep=",")
Sri
fonte
-1

Se um círculo é o Nortstar, existe uma maneira mais fácil com a esfera unitária.

Você pode medir sua latitude com a Nortstar. Então você tem uma posição relativa nesta esfera. v1 (0, sen (la), cos (la)) Você conhece a posição (ângulo) de outra estrela (estrela2), de almanach. v2 (sin (lo2) * cos (la2), sin (la2), cos (lo2) * cos (la2)) Seus vetores. Da equação da esfera.

lo2 é a longitude relativa. É desconhecido .

O ângulo entre você e a estrela2, você também pode medir, (m) E você sabe, o produto interno de um vetor de duas unidades é cos (ângulo) de entre. cos (m) = ponto (v1, v2) u pode calcular agora a longitude relativa (lo2). lo2 = acos ((cos (m) -sin (la) * sin (la2)) / (cos (la) * cos (la2)))

Afinal, você adiciona a longitude real de star2 a lo2. (ou sub, depende do lado oeste de você ou do leste.) lo2 agora é a sua longitude.

Desculpe pelo meu inglês, eu nunca aprendo esse idioma.


2 coisas: Northstar significa estrela polar.

Outro. Como o ângulo medido na horizontal relativamente, sempre precisa de correção de 90 ângulos. É válido para m ângulo também.

ps: média do ângulo real: posição da estrela - correção do tempo.

docwho
fonte
Não é aparente como isso responde à pergunta.
whuber