|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- /****************************************************************************
- * Copyright (C) 2020 by Simulation Team, NavInfo Ltd. *
- * *
- * This file is part of Simulation Core Software Stack. *
- * *
- * Simulation Core is a commercial autonomous driving simulation solution.*
- * *
- * You should have received a copy of the NavInfo EULA License along with *
- * the software. If not, please contact us, <simulation@navinfo.com>. *
- ****************************************************************************/
-
- #include "geo/private/base/constant.h"
- #include "geo/private/math/angle.h"
- #include "geo/private/math/distance.h"
- #include "geo/private/math/trigonometric.h"
-
- namespace ns
- {
- namespace geo
- {
-
- double flat_distance(const PointD& p1, const PointD& p2)
- {
- const double dx = p1.x - p2.x;
- const double dy = p1.y - p2.y;
- return std::sqrt(dx * dx + dy * dy);
- }
-
- /*
- * 计算pos点到由p1、p2组成的直线的距离,以及直线上距离pos最近的点foot
- */
- double pointSegmentDistance(const PointD& p, const PointD& p1,
- const PointD& p2, PointD& foot, CalDistanceFunc func)
- {
- double deltaX = p2.x - p1.x;
- double deltaY = p2.y - p1.y;
- double d1 = deltaX * (p.x - p1.x) + deltaY * (p.y - p1.y);
- if (d1 <= 0)
- {
- foot = p1;
- return func(p, p1);
- }
- double d2 = deltaX * deltaX + deltaY * deltaY;
- if (d1 >= d2)
- {
- foot = p2;
- return func(p, p2);
- }
- double r = d1 / d2;
- foot.x = p1.x + deltaX * r;
- foot.y = p1.y + deltaY * r;
- foot.z = p1.z + (p2.z - p1.z) * r;
- return func(p, foot);
- }
-
- double calcPt2SegmentLonlat(const PointD& pos, const PointD& p1,
- const PointD& p2, CalDistanceFunc func)
- {
- double a = func(p1, p2); //经纬坐标系中求两点的距离公式
- double b = func(p2, pos); //经纬坐标系中求两点的距离公式
- double c = func(p1, pos); //经纬坐标系中求两点的距离公式
- if (b * b >= c * c + a * a)
- return c;
- if (c * c >= b * b + a * a)
- return b;
- double l = (a + b + c) / 2; //周长的一半
- double s = sqrt(std::abs(l * (l - a) * (l - b) * (l - c))); //海伦公式求面积
- return 2 * s / a;
- }
-
- // 美团采用的计算方法,在一个小范围内,例如北京市里面,把地球的经线和纬线当成是垂直的,直接采用勾股定理计算出距离
- const double calDistanceSimple(const PointD& p1, const PointD& p2)
- {
- double dx = Degree2Radian(p1.x - p2.x); // 经度差值
- double dy = Degree2Radian(p1.y - p2.y); // 纬度差值
- double cosb1 = ns_cos_round((p1.y + p2.y) * 0.5);
- double lx = dx * EARTH_EQUATOR_RADIUS * cosb1; // 东西距离
- // double b = Degree2Radian((p1.y + p2.y) * 0.5); // 平均纬度
- // double lx = dx * EARTH_EQUATOR_RADIUS * cos(b); // 东西距离
- double ly = dy * EARTH_EQUATOR_RADIUS; // 南北距离
- return sqrt(lx * lx + ly * ly);
- }
-
- // 已知两个经纬度坐标点,求两个经纬度之间的距离
- const double calDistanceHaversine(const PointD& p1, const PointD& p2)
- {
- // 所有的角度转化为弧度进行计算
- double dLat = Degree2Radian(p2.y - p1.y);
- double dLon = Degree2Radian(p2.x - p1.x);
- double tmpLat1 = Degree2Radian(p1.y);
- double tmpLat2 = Degree2Radian(p2.y);
- // 代入计算地球距离的Haversine公式中
- double a = pow(sin(dLat * 0.5), 2) + pow(sin(dLon * 0.5), 2) * cos(tmpLat1) * cos(tmpLat2);
- double c = 2 * asin(sqrt(a)); // 和2 * atan2(sqrt(a), sqrt(1-a));一样
- // double c = 2 * atan2(sqrt(a), sqrt(1-a));
- return EARTH_EQUATOR_RADIUS * c;
- }
-
- // 根据Vincenty的公式计算地球上两点间的距离,把地球当成椭圆形进行计算
- const double calDistanceVincenty(const PointD& p1, const PointD& p2)
- {
- static double a = EARTH_EQUATOR_RADIUS; // 椭球长轴半径
- static double f = 1 / 298.257223563; // 椭球体变平
- static double b = (1 - f) * a; // 椭球短轴半径
-
- double U1 = atan((1 - f) * tan(Degree2Radian(p1.y))); //降低纬度处理
- double U2 = atan((1 - f) * tan(Degree2Radian(p2.y))); //同时把经纬度转化为弧度
- double sinU1 = sin(U1), cosU1 = cos(U1);
- double sinU2 = sin(U2), cosU2 = cos(U2);
- double L = Degree2Radian(p2.x - p1.x); // 两点经度差
-
- double sinLambda;
- double cosLambda;
- double sinSigma;
- double cosSigma;
- double sigma;
- double cosSqAlpha;
- double cos2SigmaM;
-
- double lambda = L;
- double prevLambda;
- int iterationLimit = 100; // 迭代公式次数限制
- do
- {
- sinLambda = sin(lambda);
- cosLambda = cos(lambda);
- sinSigma =
- sqrt(pow(cosU2 * sinLambda, 2) + pow(cosU1 * sinU2 - sinU1 * cosU2 * cosLambda, 2));
- if (sinSigma == 0) // 判断是否为重合点
- return 0;
-
- cosSigma = sinU1 * sinU2 + cosU1 * cosU2 * cosLambda;
- sigma = atan(sinSigma / cosSigma);
- double sinAlpha = cosU1 * cosU2 * sinLambda / sinSigma;
- cosSqAlpha = 1 - pow(sinAlpha, 2);
-
- if (cosSqAlpha == 0)
- {
- cos2SigmaM = 0;
- }
- else
- {
- cos2SigmaM = cosSigma - 2 * sinU1 * sinU2 / cosSqAlpha;
- }
-
- double C = f / 16 * cosSqAlpha * (4 + f * (4 - 3 * cosSqAlpha));
- prevLambda = lambda;
- lambda = L + (1 - C) * f * sinAlpha *
- (sigma + C * sinSigma *
- (cos2SigmaM + C * cosSigma * (-1 + 2 * pow(cos2SigmaM, 2))));
- } while (std::abs(lambda - prevLambda) > 1e-12 && --iterationLimit > 0);
-
- if (iterationLimit == 0)
- return 0;
-
- double uSq = cosSqAlpha * (pow(a, 2) - pow(b, 2)) / pow(b, 2);
- double A = 1 + uSq / 16384 * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)));
- double B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)));
- double deltaSigma = B * sinSigma *
- (cos2SigmaM + B / 4 *
- (cosSigma * (-1 + 2 * pow(cos2SigmaM, 2)) -
- B / 6 * cos2SigmaM * (-3 + 4 * pow(sinSigma, 2)) *
- (-3 + 4 * pow(cos2SigmaM, 2))));
- double s = b * A * (sigma - deltaSigma);
-
- return s;
- }
-
- } // namespace geo
- } // namespace ns
|