好像你可以使用 project_point 战略:
project_point
的 住在Coliru 强>
#include <string> #include <iostream> #include <boost/geometry.hpp> namespace bg = boost::geometry; int main(){ double const earth_radius = 6371.0; // Km typedef bg::model::point<double, 2, bg::cs::spherical_equatorial<bg::degree>> geo_point; typedef bg::model::segment<geo_point> geo_segment; geo_point p(88.41253929999999, 22.560206299999997); geo_point q(88.36928063300775, 22.620867969497795); geo_point t(88.29580956367181, 22.71558662052875); double dist_qt = bg::distance(q, t); std::cout << dist_qt*earth_radius << std::endl; geo_segment line(p, q); double perp_dist = distance(t, line, bg::strategy::distance::projected_point<>{}); std::cout << perp_dist*earth_radius << std::endl; }
打印
12.9521 763.713
我没有检查结果(在那张照片中,似乎有点令人惊讶的是perp_dist要大得多),但也许我错过了一些东西。
如果你必须做一些特殊的事情(除了坐标系统)来获得那个“hasrsine”(对不起,我还没有达到这个速度),你可能需要将第二个模板参数传递给 projected_point 策略:“ 基础点 - 点距离策略 ”。
projected_point
这个答案做了所有的计算, 的 没有提升 强> 。
考虑半径为R = 1的球体。
A,B点在a上 大圈子 。这个伟大的圈子 gcAB 也是通过中心点 的 Ø 强> 球体(大圆圈所需)。点 的 一个 强> , 的 乙 强> , 的 Ø 强> 定义一个平面 PL1 。
gcAB
PL1
点 的 P 强> 也是一个很大的圈子。
来自的最小距离(沿大圆弧测量,而不是沿3D直线测量) 的 P 强> 到了大圈 gcAB 是弧的长度 的 个人计算机 强> 。 平面 的 PL2 强> 伟大的圈子 gcPC 垂直于平面 的 PL1 强> 。
gcPC
我们想要点 的 C 强> ,这就行了 的 OC 强> ,这是两个提到的飞机的交叉点。
。 平面 的 PL1 强> 由垂直向量定义 pp1 。这个向量是由 交叉产品 向量 OA 和 OB 。
pp1
OA
OB
因为飞机 的 PL2 强> 垂直于平面 的 PL1 强> ,它必须包含矢量 pp1 。所以垂直向量 pp2 顶级车道 的 PL2 强> 可以通过产品的交叉产品获得 OP 和 pp1 。
pp2
OP
矢量 ppi 在线 OC 两个平面的交叉点是通过的交叉积得到的 pp1 和 pp2 。
ppi
OC
要是我们 正常化 向量 ppi 并将其组件乘以半径 R 地球,我们得到点的坐标 的 C 强> 。 交叉产品不是可交换的。这意味着如果我们交换点A,B,我们得到相反的点 的 C' 强> 在球体中。我们可以测试距离 PC 和 PC' 并得到他们的最低限度
R
PC
PC'
计算 的 大圆距离 强> 维基百科链接 两点 的 一个 强> , 的 乙 强> ,它依赖于角度 a 线之间 OA 和 OB 。 为了我们使用的所有角度的最佳精度 a = atan2(y, x) 其中,使用半径1, y= sin(a) 和 x= cos(a) 。 sin(a) 和 cos(a) 可以通过交叉积(OA,OB)和 点积 (OA,OB)。
a
a = atan2(y, x)
y= sin(a)
x= cos(a)
sin(a)
cos(a)
总而言之,我们有这个C ++代码:
#include <iostream> #include <cmath> const double degToRad = std::acos(-1) / 180; struct vec3 { double x, y, z; vec3(double xd, double yd, double zd) : x(xd), y(yd), z(zd) {} double length() { return std::sqrt(x*x + y*y + z*z); } void normalize() { double len = length(); x = x / len; y = y / len; z = z / len; } }; vec3 cross(const vec3& v1, const vec3& v2) { return vec3( v1.y * v2.z - v2.y * v1.z, v1.z * v2.x - v2.z * v1.x, v1.x * v2.y - v2.x * v1.y ); } double dot(const vec3& v1, const vec3& v2) { return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z; } double GCDistance(const vec3& v1, const vec3& v2, double R) { //normalize, so we can pass any vectors vec3 v1n = v1; v1n.normalize(); vec3 v2n = v2; v2n.normalize(); vec3 tmp = cross(v1n, v2n); //minimum distance may be in one direction or the other double d1 = std::abs(R * std::atan2(tmp.length() , dot(v1n, v2n))); double d2 = std::abs(R * std::atan2(tmp.length() , -dot(v1n, v2n))); return std::min(std::abs(d1), std::abs(d2)); } int main() { //Points A, B, and P double lon1 = 88.41253929999999 * degToRad; double lat1 = 22.560206299999997 * degToRad; double lon2 = 88.36928063300775 * degToRad; double lat2 = 22.620867969497795 * degToRad; double lon3 = 88.29580956367181 * degToRad; double lat3 = 22.71558662052875 * degToRad; //Let's work with a sphere of R = 1 vec3 OA(std::cos(lat1) * std::cos(lon1), std::cos(lat1) * std::sin(lon1), std::sin(lat1)); vec3 OB(std::cos(lat2) * std::cos(lon2), std::cos(lat2) * std::sin(lon2), std::sin(lat2)); vec3 OP(std::cos(lat3) * std::cos(lon3), std::cos(lat3) * std::sin(lon3), std::sin(lat3)); //plane OAB, defined by its perpendicular vector pp1 vec3 pp1 = cross(OA, OB); //plane OPC vec3 pp2 = cross(pp1, OP); //planes intersection, defined by a line whose vector is ppi vec3 ppi = cross(pp1, pp2); ppi.normalize(); //unitary vector //Radious or Earth double R = 6371000; //mean value. For more precision, data from a reference ellipsoid is required std::cout << "Distance AP = " << GCDistance(OA, OP, R) << std::endl; std::cout << "Distance BP = " << GCDistance(OB, OP, R) << std::endl; std::cout << "Perpendicular distance (on arc) = " << GCDistance(OP, ppi, R) << std::endl; }
给出了距离 对于给定的三个点,AP = 21024.4 BP = 12952.1并且PC = 499.493。
运行代码 这里