查找地球上两个圆的交点坐标?

时间:2018-11-15 17:11:48

标签: javascript math coordinates earthdistance

我试图找到两个圆的第二个交点。我已经知道的一点之一用于计算距离,然后用作圆半径(here)。问题在于,即使您是相似的,我也无法获得知识点,无法获得两个新坐标。问题可能与地球曲率有关,但我一直在寻找解决方案,却一无所获。

圆半径是根据地球曲率计算的。这是我的代码:

  PageView(
        children: [
          //Page1

          GestureDetector(
            onTap: () {
              print("Click page1");

              Navigator.of(context).push(MaterialPageRoute(
                builder: (context) => NewPage()
              ));

            },
            child: Container(
              color: Colors.red,
              child: Center(
                child: Text("text 1"),
              ),
            ),
          ),

          //Page2
          GestureDetector(
              onTap: () {
                print("Click page2");
              },
              child: Container(
                color: Colors.blue,
                child: Center(
                  child: Text("text 1"),
                ),
              )),

          //Page3
          GestureDetector(
              onTap: () {
                print("Click page3");
              },
              child: Container(
                color: Colors.green,
                child: Center(
                  child: Text("text 1"),
                ),
              )),
        ],
      );

假定deg2rad变量随地球曲率调整其他计算。

谢谢您的帮助。

2 个答案:

答案 0 :(得分:1)

您对R的计算等等是错误的,因为平面毕达哥拉斯公式不适用于球面三角法(例如-我们可以在球面上拥有三个直角的三角形!)。相反,我们应该使用特殊公式。其中一些摘自this page

首先使用R = Earth radius = 6,371km

查找两个半径的弧度大圆弧
a1 = r1 / R
a2 = r2 / R

使用Haversine公式计算圆心之间的距离(再次以弧度为单位)

var R = 6371e3; // metres
var φ1 = lat1.toRadians();
var φ2 = lat2.toRadians();
var Δφ = (lat2-lat1).toRadians();
var Δλ = (lon2-lon1).toRadians();

var a = Math.sin(Δφ/2) * Math.sin(Δφ/2) +
        Math.cos(φ1) * Math.cos(φ2) *
        Math.sin(Δλ/2) * Math.sin(Δλ/2);
var ad = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));

从位置1到位置2:

 //where    φ1,λ1 is the start point, φ2,λ2 the end point 
 //(Δλ is the difference in longitude)
var y = Math.sin(λ2-λ1) * Math.cos(φ2);
var x = Math.cos(φ1)*Math.sin(φ2) -
        Math.sin(φ1)*Math.cos(φ2)*Math.cos(λ2-λ1);
var brng = Math.atan2(y, x);

现在看看我的answer considering equal radii case中的照片。 (这里的圆半径可能不同,我们应该使用另一种方法来找到所需的圆弧)

enter image description here

我们有球面直角三角形ACB和FCB(类似于平面情况BD在C点处垂直于AF且BCA角度为右)。
球形勾股定理(来自关于trig的书)说

 cos(AB) = cos(BC) * cos(AC)
 cos(FB) = cos(BC) * cos(FC)

或(对于AC使用x,对于BC使用y,对于FC使用(ad-x))

 cos(a1) = cos(y) * cos(x)
 cos(a2) = cos(y) * cos(ad-x)

除以等式以消除cos(y)

 cos(a1)*cos(ad-x) = cos(a2) * cos(x)
 cos(a1)*(cos(ad)*cos(x) + sin(ad)*sin(x)) = cos(a2) * cos(x)
 cos(ad)*cos(x) + sin(ad)*sin(x) = cos(a2) * cos(x) / cos(a1)
 sin(ad)*sin(x) = cos(a2) * cos(x) / cos(a1) - cos(ad)*cos(x)
 sin(ad)*sin(x) = cos(x) * (cos(a2) / cos(a1) - cos(ad))
 TAC = tg(x) = (cos(a2) / cos(a1) - cos(ad)) / sin(ad)

具有ACB三角形的斜边和导管,我们可以找到AC和AB方向之间的角度(直角三角形的纳皮尔法则)-注意我们已经知道TAC = tg(AC)a1 = AB

cos(CAB)= tg(AC) * ctg(AB)
CAB = Math.acos(TAC * ctg(a1))

现在我们可以计算出交点-它们沿着轴承brng-CABbrng+CAB位于距position1的弧距a1处

B_bearing = brng - CAB
D_bearing = brng + CAB

交叉点的坐标:

var latB = Math.asin( Math.sin(lat1)*Math.cos(a1) + 
              Math.cos(lat1)*Math.sin(a1)*Math.cos(B_bearing) );
var lonB = lon1.toRad() + Math.atan2(Math.sin(B_bearing)*Math.sin(a1)*Math.cos(lat1), 
                     Math.cos(a1)-Math.sin(lat1)*Math.sin(lat2));

与D_bearing相同

latB,lonB以弧度为单位

答案 1 :(得分:0)

我有类似的需求(Intersection coordinates (lat/lon) of two circles (given the coordinates of the center and the radius) on earth),因此我在python中共享了该解决方案,以防它可能对某人有所帮助:

'''
FINDING THE INTERSECTION COORDINATES (LAT/LON) OF TWO CIRCLES (GIVEN THE COORDINATES OF THE CENTER AND THE RADII)

Many thanks to Ture Pålsson who directed me to the right source, the code below is based on whuber's brilliant work here:
https://gis.stackexchange.com/questions/48937/calculating-intersection-of-two-circles 

The idea is that;
  1. The points in question are the mutual intersections of three spheres: a sphere centered beneath location x1 (on the 
  earth's surface) of a given radius, a sphere centered beneath location x2 (on the earth's surface) of a given radius, and
  the earth itself, which is a sphere centered at O = (0,0,0) of a given radius.
  2. The intersection of each of the first two spheres with the earth's surface is a circle, which defines two planes.
  The mutual intersections of all three spheres therefore lies on the intersection of those two planes: a line.
  Consequently, the problem is reduced to intersecting a line with a sphere.

Note that "Decimal" is used to have higher precision which is important if the distance between two points are a few
meters.
'''
from decimal import Decimal
from math import cos, sin, sqrt
import math
import numpy as np

def intersection(p1, r1_meter, p2, r2_meter):
    # p1 = Coordinates of Point 1: latitude, longitude. This serves as the center of circle 1. Ex: (36.110174,  -90.953524)
    # r1_meter = Radius of circle 1 in meters
    # p2 = Coordinates of Point 2: latitude, longitude. This serves as the center of circle 1. Ex: (36.110174,  -90.953524)
    # r2_meter = Radius of circle 2 in meters
    '''
    1. Convert (lat, lon) to (x,y,z) geocentric coordinates.
    As usual, because we may choose units of measurement in which the earth has a unit radius
    '''
    x_p1 = Decimal(cos(math.radians(p1[1]))*cos(math.radians(p1[0])))  # x = cos(lon)*cos(lat)
    y_p1 = Decimal(sin(math.radians(p1[1]))*cos(math.radians(p1[0])))  # y = sin(lon)*cos(lat)
    z_p1 = Decimal(sin(math.radians(p1[0])))                           # z = sin(lat)
    x1 = (x_p1, y_p1, z_p1)

    x_p2 = Decimal(cos(math.radians(p2[1]))*cos(math.radians(p2[0])))  # x = cos(lon)*cos(lat)
    y_p2 = Decimal(sin(math.radians(p2[1]))*cos(math.radians(p2[0])))  # y = sin(lon)*cos(lat)
    z_p2 = Decimal(sin(math.radians(p2[0])))                           # z = sin(lat)
    x2 = (x_p2, y_p2, z_p2)
    '''
    2. Convert the radii r1 and r2 (which are measured along the sphere) to angles along the sphere.
    By definition, one nautical mile (NM) is 1/60 degree of arc (which is pi/180 * 1/60 = 0.0002908888 radians).
    '''
    r1 = Decimal(math.radians((r1_meter/1852) / 60)) # r1_meter/1852 converts meter to Nautical mile.
    r2 = Decimal(math.radians((r2_meter/1852) / 60))
    '''
    3. The geodesic circle of radius r1 around x1 is the intersection of the earth's surface with an Euclidean sphere
    of radius sin(r1) centered at cos(r1)*x1.

    4. The plane determined by the intersection of the sphere of radius sin(r1) around cos(r1)*x1 and the earth's surface
    is perpendicular to x1 and passes through the point cos(r1)x1, whence its equation is x.x1 = cos(r1)
    (the "." represents the usual dot product); likewise for the other plane. There will be a unique point x0 on the
    intersection of those two planes that is a linear combination of x1 and x2. Writing x0 = ax1 + b*x2 the two planar
    equations are;
       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
    Using the fact that x2.x1 = x1.x2, which I shall write as q, the solution (if it exists) is given by
       a = (cos(r1) - cos(r2)*q) / (1 - q^2),
       b = (cos(r2) - cos(r1)*q) / (1 - q^2).
    '''
    q = Decimal(np.dot(x1, x2))

    if q**2 != 1 :
        a = (Decimal(cos(r1)) - Decimal(cos(r2))*q) / (1 - q**2)
        b = (Decimal(cos(r2)) - Decimal(cos(r1))*q) / (1 - q**2)
        '''
        5. Now all other points on the line of intersection of the two planes differ from x0 by some multiple of a vector
        n which is mutually perpendicular to both planes. The cross product  n = x1~Cross~x2  does the job provided n is 
        nonzero: once again, this means that x1 and x2 are neither coincident nor diametrically opposite. (We need to 
        take care to compute the cross product with high precision, because it involves subtractions with a lot of
        cancellation when x1 and x2 are close to each other.)
        '''
        n = np.cross(x1, x2)
        '''
        6. Therefore, we seek up to two points of the form x0 + t*n which lie on the earth's surface: that is, their length
        equals 1. Equivalently, their squared length is 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
        '''
        x0_1 = [a*f for f in x1]
        x0_2 = [b*f for f in x2]
        x0 = [sum(f) for f in zip(x0_1, x0_2)]
        '''
          The term with x0.n disappears because x0 (being a linear combination of x1 and x2) is perpendicular to n.
          The two solutions easily are   t = sqrt((1 - x0.x0)/n.n)    and its negative. Once again high precision
          is called for, because when x1 and x2 are close, x0.x0 is very close to 1, leading to some loss of
          floating point precision.
        '''
        if (np.dot(x0, x0) <= 1) & (np.dot(n,n) != 0): # This is to secure that (1 - np.dot(x0, x0)) / np.dot(n,n) > 0
            t = Decimal(sqrt((1 - np.dot(x0, x0)) / np.dot(n,n)))
            t1 = t
            t2 = -t

            i1 = x0 + t1*n
            i2 = x0 + t2*n
            '''
            7. Finally, we may convert these solutions back to (lat, lon) by converting geocentric (x,y,z) to geographic
            coordinates. For the longitude, use the generalized arctangent returning values in the range -180 to 180
            degrees (in computing applications, this function takes both x and y as arguments rather than just the
            ratio y/x; it is sometimes called "ATan2").
            '''

            i1_lat = math.degrees( math.asin(i1[2]))
            i1_lon = math.degrees( math.atan2(i1[1], i1[0] ) )
            ip1 = (i1_lat, i1_lon)

            i2_lat = math.degrees( math.asin(i2[2]))
            i2_lon = math.degrees( math.atan2(i2[1], i2[0] ) )
            ip2 = (i2_lat, i2_lon)
            return [ip1, ip2]
        elif (np.dot(n,n) == 0):
            return("The centers of the circles can be neither the same point nor antipodal points.")
        else:
            return("The circles do not intersect")
    else:
        return("The centers of the circles can be neither the same point nor antipodal points.")

'''
Example: The output of below is  [(36.989311051533505, -88.15142628069133), (38.2383796094578, -92.39048549120287)]

         intersection_points = intersection((37.673442, -90.234036), 107.5*1852, (36.109997, -90.953669), 145*1852)
         print(intersection_points)
'''

感谢任何反馈。