我试图弄清楚如何在数学上得出给定中心Lat / Lon和每个点的半径的情况下地球表面上两个相交圆的共同点。
例如,给定:
- 纬度/经度(37.673442,-90.234036)半径107.5海里
- 纬度/经度(36.109997,-90.953669)半径145海里
我应该找到两个相交点,其中之一是(36.948,-088.158)。
在平坦的平面上解决这个问题很容易,但是我没有在诸如地球表面之类的不完美球体上求解方程的经验。
我试图弄清楚如何在数学上得出给定中心Lat / Lon和每个点的半径的情况下地球表面上两个相交圆的共同点。
例如,给定:
我应该找到两个相交点,其中之一是(36.948,-088.158)。
在平坦的平面上解决这个问题很容易,但是我没有在诸如地球表面之类的不完美球体上求解方程的经验。
Answers:
一旦认识到这一点,在球面上就比在飞机上难得多
所讨论的点是三个球体的相互交点:一个在给定半径的x1位置(在地球表面上)下方居中的球体,一个在给定半径的x2位置(在地球表面上)下方居中的球体和地球本身,这是一个以给定半径的O =(0,0,0)为中心的球体。
前两个球体与地球表面的交点是一个圆,它定义了两个平面。因此,所有三个球体的相互交点位于这两个平面的交点上:直线。
因此,问题被简化为使线与球相交,这很容易。
这是详细信息。输入是地球表面上的点P1 =(lat1,lon1)和P2 =(lat2,lon2),以及两个对应的半径r1和r2。
将(lat,lon)转换为(x,y,z)地心坐标。像往常一样,因为我们可以选择地球具有单位半径的度量单位,
x = cos(lon) cos(lat)
y = sin(lon) cos(lat)
z = sin(lat).
在此示例中,P1 =(-90.234036度,37.673442度)具有地心坐标x1 =(-0.00323306,-0.7915,0.61116)和P2 =(-90.953669度,36.109997度)具有地心坐标x2 =(-0.0134464,-0.807775 ,0.589337)。
将半径r1和r2(沿球体测量)转换为沿球体的角度。根据定义,一海里(NM)是1/60弧度(即pi / 180 * 1/60 = 0.0002908888弧度)。因此,作为角度,
r1 = 107.5 / 60 Degree = 0.0312705 radian
r2 = 145 / 60 Degree = 0.0421788 radian
围绕x1的半径r1 的测地线圆是地球表面与以cos(r1)* x1为中心的半径sin(r1)的欧几里得球的交点。
由围绕cos(r1)* x1的半径sin(r1)的球面与地球表面的交点确定的平面垂直于x1并穿过点cos(r1)x1,因此其等式为x.x1 = cos (r1)(“。”代表通常的点积);对于另一架飞机也是如此。在这两个平面的交点上将存在一个唯一点x0,这是x1和x2的线性组合。写x0 = a x1 + b * x2这两个平面方程是
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
利用x2.x1 = x1.x2的事实(我将其写为q),解(如果存在)由下式给出
a = (cos(r1) - cos(r2)*q) / (1 - q^2),
b = (cos(r2) - cos(r1)*q) / (1 - q^2).
在运行的示例中,我计算出a = 0.973503和b = 0.0260194。
显然,我们需要q ^ 2!=1。这意味着x1和x2既不能是同一点,也不能是对映点。
现在,两个平面相交线上的所有其他点与x0相差一个矢量n的几倍,矢量n相互垂直于两个平面。叉积
n = x1~Cross~x2
如果n不为零,该作业是否执行:再次,这意味着x1和x2既不是重合的也不是完全相反的。(我们需要小心地计算叉积,因为当x1和x2彼此接近时,它涉及很多相减的减法。)在示例中,n =(0.0272194,-0.00631254,-0.00803124) 。
因此,我们寻找位于地球表面的x0 + t * n形式的两个点:即它们的长度等于1。等效地,它们的平方长度为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.n的项消失了,因为x0(x1和x2的线性组合)垂直于n。两种解决方案很容易
t = sqrt((1 - x0.x0)/n.n)
及其负面影响。再次需要高精度,因为当x1和x2接近时,x0.x0 非常接近1,从而导致浮点精度下降。在示例中,t = 1.07509或t = -1.07509。因此,交点的两个点相等
x0 + t*n = (0.0257661, -0.798332, 0.601666)
x0 - t*n = (-0.0327606, -0.784759, 0.618935)
最后,我们可以通过将地心线(x,y,z)转换为地理坐标,将这些解转换回(lat,lon):
lon = ArcTan(x,y)
lat = ArcTan(Sqrt[x^2+y^2], z)
为经度,使用广义反正切范围为返回值-180到180度(在计算应用,这一函数的两个 x和y作为参数,而不仅仅是比Y / X;它有时被称为“ATAN2”)。
我获得了两个解决方案(-88.151426、36.989311)和(-92.390485、38.238380),在图中以黄色圆点显示。
轴显示地心(x,y,z)坐标。灰色斑块是地球表面经度-95至-87度,纬度33至40度(以1度刻度标出)的部分。地球表面已经部分透明,可以显示所有三个球体。计算出的解决方案的正确性通过黄点位于球体的交点处显而易见。
该椭球的情况下:
这个问题是寻找被定义为“中线”的海上边界之一的概括,关于这一主题有大量文献。我对此问题的解决方案是利用等距的方位角投影:
该算法二次收敛,并在椭球上产生精确的解。(对于海洋边界,要求准确性,因为它决定了捕鱼,石油和矿产的权利。)
测地线第14节给出了关于旋转椭球的公式。椭球等距方位角投影由GeographicLib提供。在椭球的大地测量投影中可以使用MATLAB版本 。
这是一些R代码可以做到这一点:
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)
在@whuber的答案之后,这是一些Java代码,由于两个原因,它们很有用:
它不是经过优化或完整的(我已经省略了明显的类,例如Point
),但应该可以解决问题。
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;
}
另外,重要的是,请注意-的用法与atan2
@whuber答案的预期相反(我不知道为什么,但是有效):
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)));
}
@wuhber答案的有效“ R”代码。
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=",")
如果一个圆是Nortstar,则存在单位球最简单的方法。
您可以使用Nortstar来衡量自己的纬度。然后,您在此球体上具有相对位置。v1(0,sin(la),cos(la))您可以从almanach知道另一颗恒星(star2)的位置(角度)。v2(sin(lo2)* cos(la2),sin(la2),cos(lo2)* cos(la2))其向量。从球面方程。
lo2是相对经度。它的未知。
您与star2之间的夹角也可以测量,(m)而且您知道,两个单位向量的内积为cos(夹角)。cos(m)= dot(v1,v2)现在您可以计算相对经度(lo2)。lo2 = acos((cos(m)-sin(la)* sin(la2))/(cos(la)* cos(la2))))
毕竟,您将star2的真实经度添加到lo2中。(或子,取决于它在您的西边还是东边。)现在,lo2是您的经度。
对不起,我的英语,我从没学过这种语言。
2件事:北极星是极星。
另一个。因为相对于水平线测得的角度,总是需要90角校正。它对m角也有效。
ps:实际角度均值:星号位置-时间校正。