【Apollo Common代码解析-计算点到线段的距离】

计算点到线段的最短距离,在路径规划领域使用较多,是为基础函数,降低其耗时,对整个规划的效率有益。
先以apollo中使用DistanceTo函数实现为例。

 double LineSegment2d::DistanceTo(const Vec2d &point) const
      {
        if (length_ <= kMathEpsilon)
        {
          return point.DistanceTo(start_);
        }
        const double x0 = point.x() - start_.x();
        const double y0 = point.y() - start_.y();
        const double proj = x0 * unit_direction_.x() + y0 * unit_direction_.y();
        if (proj <= 0.0)
        {
          return hypot(x0, y0);
        }
        if (proj >= length_)
        {
          return point.DistanceTo(end_);
        }
        return std::abs(x0 * unit_direction_.y() - y0 * unit_direction_.x());
      }

如果长度很小那么该线段只是一个点,计算两点之间的距离即可。
x0,y0组成的向量即为向量SP,unit_direction_为向量SE的单位向量图中红色的箭头,
那么proj的结果是向量SP和向量unit_direction_的内积,内积的大小是指向量SP在单位向量unit_direction_的投影,如果这个投影距离大于了线段的长度,那么说明该点point距离end_点是最近的,只需要返回这两个点之间的距离即可。
std::abs(x0 * unit_direction_.y() - y0 * unit_direction_.x());
上面这一句明显是叉乘的结果,叉乘的含义是两个向量组成的平行四边形的面积,由于unit_direction_是单位向量,那么该面积实际上就是垂线。
在这里插入图片描述
下面是另外求线段到点的最短距离的算法
假设线段是ab,求点c到线段的距离,其原理是算出三个点的相互距离,找出线段ac.bc中最大的一个max_cab,求出c点到直线ab的距离c_ab,然后用max_cab的平方-c_ab的平方得到的实际上就是ad的距离,如果ad长度小于线段长度,那么垂足就在线段上,如果大于ab那么垂足就在线段之外,只需要取ac,bc的最小值即可。
在这里插入图片描述

  double Point2LineSegment(const Point3d &c, const Point3d &a, const Point3d &b)
    {
        auto dis_between2points = [](const Point3d &Point1, const Point3d &Point2) -> double
        {
            return sqrt((Point1.x - Point2.x) * (Point1.x - Point2.x) + (Point1.y - Point2.y) * (Point1.y - Point2.y));
        };
        double min_dis = 0;
        // 先求出三个点之间的距离
        double ac = dis_between2points(a, c);
        double ab = dis_between2points(a, b);
        double bc = dis_between2points(c, b);
        double max_cab = max(ac, bc);
        // 计算点c到直线AB的距离
        // 根据两个点的坐标求直线方程
        double A = b.y - a.y;
        double B = a.x - b.x;
        double C = b.x * a.y - a.x * b.y;
        auto distance2Line = [](const double x, const double y, const double A, const double B, const double C) -> double
        {
            return std::abs(A * x + B * y + C) / std::sqrt(A * A + B * B);
        };
        double c_ab = distance2Line(c.x, c.y, A, B, C);
        double delt = pow(max_cab, 2) - pow(c_ab, 2);
        if (delt > ab * ab)
        {
            // 说明垂足在线段之外
            min_dis = min(ac, bc);
        }
        else
        { // 说明垂足在线段之内
            min_dis = c_ab;
        }
        return min_dis;
    }

以下是测试用例:

 planner::common::math::Vec2d p0(2, 3);
    planner::common::math::Vec2d p1(5, 4);
    planner::common::math::Vec2d p2(3, 7);

    planner::common::math::LineSegment2d line_segment2d_(p0, p1);
    double dis1 = line_segment2d_.DistanceTo(p2);

    //
    planner::common::math::Vec2d unit_direction_;
    const double dx = p1.x() - p0.x();
    const double dy = p1.y() - p0.y();
    double length_ = hypot(dx, dy);
    unit_direction_ =
        (planner::common::math::Vec2d(dx / length_, dy / length_));
    const double x0 = p2.x() - p0.x();
    const double y0 = p2.y() - p0.y();
    const double proj = x0 * unit_direction_.x() + y0 * unit_direction_.y();
    if (proj <= 0.0)
    {
        // return hypot(x0, y0);
    }
    if (proj >= length_)
    {
        // return p2.DistanceTo(p1);
    }
    double dis4 = std::abs(x0 * unit_direction_.y() - y0 * unit_direction_.x());
    //
    planner::Point3d O;
    planner::Point3d q0(p0.x(), p0.y(), 0);
    planner::Point3d q1(p1.x(), p1.y(), 0);
    planner::Point3d q2(p2.x(), p2.y(), 0);
    planner::Point3d unit_direction(unit_direction_.x(), unit_direction_.y(), 0);
    planner::Point3d p02(x0, y0, 0);
    planner::Point3d p01(p1.x() - p0.x(), p1.y() - p0.y(), 0);
    double dis2 = planner::Point2LineSegment(q2, q0, q1);
    MatplotVisualization_.PlotLineSegmentArrow(O, q0, planner::plot_black_arrow);
    MatplotVisualization_.PlotLineSegmentArrow(O, q1, planner::plot_black_arrow);
    MatplotVisualization_.PlotLineSegmentArrow(O, q2, planner::plot_black_arrow);
    MatplotVisualization_.PlotLineSegmentArrow(O, unit_direction, planner::plot_red_arrow);
    MatplotVisualization_.PlotLineSegmentArrow(O, p02, planner::plot_blue_arrow);
    MatplotVisualization_.PlotLineSegmentArrow(O, p01, planner::plot_green_arrow);
    MatplotVisualization_.PlotLineSegmentArrow(q0, q1, planner::plot_magenta_arrow);
    // MatplotVisualization_.PlotLineSegmentArrow(q1, q2, planner::plot_magenta_arrow);
    MatplotVisualization_.PlotLineSegmentArrow(q0, q2, planner::plot_magenta_arrow);
    MatplotVisualization_.PlotOnePoint(q0, planner::plot_red_point);
    MatplotVisualization_.PlotOnePoint(q1, planner::plot_red_point);
    MatplotVisualization_.PlotOnePoint(q2, planner::plot_red_point);
    MatplotVisualization_.PlotOnePoint(unit_direction, planner::plot_black_point);
    MatplotVisualization_.PlotOnePoint(p02, planner::plot_green_point);
    MatplotVisualization_.PlotOnePoint(p02, planner::plot_blue_point);

    MatplotVisualization_.PlotPltPause(0.1);
    MatplotVisualization_.PlotShow();
    int break_point = 0;

下面是耗时比较:

 planner::common::math::Vec2d p0(2, 3);
    planner::common::math::Vec2d p1(5, 4);
    planner::common::math::Vec2d p2(3, 7);
    auto start_time1 = system_clock::now();
    for (size_t i = 0; i < 10000; i++)
    {
        planner::common::math::LineSegment2d line_segment2d_(p0, p1);
        double dis1 = line_segment2d_.DistanceTo(p2);
    }
    duration<double> cost_time1 = system_clock::now() - start_time1;
    cout << "LineSegment2d time: " << cost_time1.count() << std::endl;
    auto start_time3 = system_clock::now();
    for (size_t i = 0; i < 10000; i++)
    {
        double dis1 =  planner::common::math::LineSegment2d::DistanceToLineSegment(p2,p0,p1) ;
    }
    duration<double> cost_time3 = system_clock::now() - start_time3;
    cout << "DistanceToLineSegment time: " << cost_time3.count() << std::endl;
    planner::Point3d q0(p0.x(), p0.y(), 0);
    planner::Point3d q1(p1.x(), p1.y(), 0);
    planner::Point3d q2(p2.x(), p2.y(), 0);
    auto start_time2 = system_clock::now();
    for (size_t i = 0; i < 10000; i++)
    {
        double dis2 = planner::Point2LineSegment(q2, q0, q1);
    }
    duration<double> cost_time2 = system_clock::now() - start_time2;
    cout << "Point2LineSegment time: " << cost_time2.count() << std::endl;

耗时的结果(单位:s)如下所示,类的构建是很耗时的,采用静态函数,可以提高计算速度。
LineSegment2d time: 0.00124451
DistanceToLineSegment time: 0.0002523
Point2LineSegment time: 0.00047673

以上为个人学习使用,请批评指正,如有侵权,请联系删除。

参考文献
【1】百度apollo源码

  • 14
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Apollo Docker Quick Start Files是用于在Docker容器中快速启动Apollo配置中心的文件集合。Apollo配置中心是携程框架部门开发的分布式配置管理平台,用于实现配置集中管理和动态配置更新的需求。 使用Docker容器来快速启动Apollo配置中心可以提高开发和部署的效率,方便跨平台和环境的使用。Apollo Docker Quick Start Files包含了配置中心的相关配置文件、Dockerfile和启动脚本等,使用这些文件可以快速构建和启动配置中心的Docker容器。 在启动Docker容器之前,我们需要先配置好Apollo配置中心的相关信息,在配置文件中指定数据库、端口等参数。然后,使用Docker命令构建Docker镜像并生成Docker容器,通过运行启动脚本,让Docker容器启动并运行Apollo配置中心。 通过使用Apollo Docker Quick Start Files,可以方便地在各种环境中部署和启动Apollo配置中心,提高系统的可维护性和可扩展性。同时,通过Docker的特性,我们可以更好地管理和监控配置中心的运行状态,更灵活地进行配置的更新和维护。 总之,Apollo Docker Quick Start Files提供了一种便捷的方式来快速部署和启动Apollo配置中心,使得我们能够更加高效地管理和使用分布式配置,提高系统的稳定性和可靠性。 ### 回答2: Apollo是一个分布式配置中心,用于管理和配置分布式系统中的应用程序的配置信息。Docker是一种容器化平台,可以将应用程序打包成容器,并在不同的环境中快速部署和运行。 Apollo-Docker-Quick-Start-Files是一个用于快速开始使用Apollo和Docker的文件集合。它包含了一系列的配置文件和脚本,可以帮助用户快速搭建Apollo配置中心和使用Docker部署应用程序。 在这个文件集合中,用户可以找到一些配置文件示例,如application.properties和meta-server.properties,这些文件定义了Apollo的配置中心和元数据服务器的相关配置信息。用户可以根据自己的需要进行修改和定制。 此外,还有一些脚本文件,如docker-compose.yaml和Dockerfile。这些文件用于定义Docker容器的构建和部署规则。用户可以使用docker-compose命令,根据docker-compose.yaml文件一键启动Apollo配置中心和应用程序的Docker容器。 使用Apollo-Docker-Quick-Start-Files,用户可以轻松地搭建Apollo配置中心和部署应用程序。它提供了一种快捷的方式,帮助用户快速入门并使用Apollo和Docker进行分布式系统的配置和部署管理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值