【问题标题】:Is there know algorithm for the vehicle route coverage?是否有已知的车辆路线覆盖算法?
【发布时间】:2021-07-18 07:03:30
【问题描述】:

我有车辆路线作为输入:Lon1,Lat1;经度2,纬度2;经度3,纬度3;等等,我有白天的车辆运动坐标。

而且我需要找出车辆经过的路线的哪一部分。在我开始实现自己的算法之前,是否有一些现成的算法?

这是任务的插图:

【问题讨论】:

  • 有趣的问题!但是,作为这里的经验丰富的用户,您可能知道这个问题并不是特别适合 SO。这个网站不是关于“这是我的问题,请为我彻底解决”,而是“我试过 A,结果是 B,但我期望 C”。请编辑问题,显示您尝试过的代码并解释您的问题,从而显着增加获得有意义答案的可能性。理想情况下,提供MCVE 其他人可以检查并与您一起帮助改进。
  • 车辆坐标多久记录一次?距离路线多远算作“在途”?测量的准确性如何?
  • 是鸟儿飞翔的路线还是实际的导航数据?
  • @Dave 车辆坐标在移动过程中记录,~ 在移动过程中每 5 秒记录一次。我认为我们可以添加一些半径,例如围绕路线点多边形的 10 米将是“在途”。我会说测量精确到〜1m。
  • @Surt 这是实际的导航数据,不是鸟儿飞翔的。

标签: algorithm geolocation coordinates geospatial


【解决方案1】:

我不知道有什么明确的算法可以直接应用于这个问题。如果我必须自己编程:

很明显,问题在于计算预期路线的交集和实际车辆轨迹段的并集(我引入了并集以去除可能的重复段)。这可以通过以下方式完成:

  1. 先计算车辆轨迹的并集,然后从预期路线中减去

  2. 每次有新的车辆位置到达时,只需从剩余的预期路线中减去每个车辆轨迹段并计算减去的距离。

我想我会选择第二个选项,乍一看似乎更有效。假设,挑战主要减少计算当前剩余路线和每个到达轨迹段之间的差异。这种差异的计算方法将根据采样时间、所需精度等而有所不同。

一个非常幼稚的代码来说明这个想法(在 C# 中)

       class RouteChecker
        {
            List<RouteSegment> MissingRoute = null;
            double TotalCoveredDistance = 0.0;
            Point LastVehiclePoint = default(Point);


            public RouteChecker(List<Point> expectedRoute)
            {
                MissingRoute = new List<RouteSegment>(expectedRoute.Count - 1);
                Point previousPoint = expectedRoute[0];
                for (int i = 1; i < expectedRoute.Count; i++)
                {
                    MissingRoute.Add(new RouteSegment(previousPoint, expectedRoute[i]));
                    previousPoint = expectedRoute[i];
                }
            }

            public void SetStartPoint(Point startPoint)
            {
                TotalCoveredDistance = 0.0;
                LastVehiclePoint = startPoint;
            }


            public double CheckRouteCovered(Point realRouteNextPoint)
            {

                RouteSegment vehSegment = new RouteSegment(LastVehiclePoint, realRouteNextPoint);
                LastVehiclePoint = realRouteNextPoint;

                for (int i = 0; i < MissingRoute.Count; i++)
                {
                    if (!MissingRoute[i].isActive)
                        continue;

                    RouteSegment[] remainingSegments;
                    double removedDistance;
                    bool otherSegmentisFullyContained;
                    if (MissingRoute[i].Difference(vehSegment, out remainingSegments, out removedDistance, out otherSegmentisFullyContained))
                    {
                        if (remainingSegments != null)
                        {
                            MissingRoute[i] = remainingSegments[0];
                            if (remainingSegments.Length > 1)
                                MissingRoute.Add(remainingSegments[1]);
                        }
                        else
                            MissingRoute[i].isActive = false;
                       
                        TotalCoveredDistance += removedDistance;
                        if(otherSegmentisFullyContained)
                            break;
                    }                   
                }

                return TotalCoveredDistance;

            }  
   }     


所以相应的对象将被创建为

    List<Point> expectedRoute = new List<Point>() {  new Point(Lon1, Lat1),
                                                    new Point(Lon2, Lat2),
                                                    new Point(Lon3, Lat3),
                                                    new Point(Lon4, Lat4),
                                                    new Point(Lon5, Lat5)
                                                    //[...]
                                                  };

     RouteChecker myChecker = new RouteChecker(expectedRoute);

     myChecker.SetStartPoint(new Point(vehicleStartLon, vehicleStartLat));

然后,每 5 秒


   double CoveredDistance = myChecker.CheckRouteCovered(new Point(vehicleNextLon, vehicleNextLat));

RouteSegment 类只是一个管理所有带有点和线段的几何操作的类。

 private class RouteSegment
{
    const double ParallelMinAngleRadians = Math.PI / 180;
    const double MaxOnRouteDist = 10;

    Point P1, P2;
    public bool isActive = true;
    public RouteSegment(Point p1, Point p2)
    {
        P1 = p1;
        P2 = p2;
    }             

    public bool Difference(RouteSegment otherSegment, out RouteSegment[] RemainingRouteSegments, out double removedDistance,out bool otherSegmentisFullyContained)
    {
        otherSegmentisFullyContained = false;

        if(!IsParallelTo(otherSegment))
        {
            removedDistance = 0.0;
            RemainingRouteSegments = null;
            return false;
        }

        if (Contains(otherSegment.P1))
        {
            if (Contains(otherSegment.P2))
            {
                removedDistance = Distance(otherSegment.P1, otherSegment.P2);
                if (Distance(otherSegment.P2, P1) < Distance(otherSegment.P2, P2))
                    RemainingRouteSegments = new RouteSegment[] { new RouteSegment(P1, otherSegment.P2), new RouteSegment(otherSegment.P1, P2) };
                else
                    RemainingRouteSegments = new RouteSegment[] { new RouteSegment(P1, otherSegment.P1), new RouteSegment(otherSegment.P2, P2) };

                otherSegmentisFullyContained = true;

                return true;                        
            }
            else
            {
                if(Distance(otherSegment.P2,P1)< Distance(otherSegment.P2, P2))
                {
                    RemainingRouteSegments = new RouteSegment[] { new RouteSegment(otherSegment.P1, P2) };
                    removedDistance = Distance(otherSegment.P1, P1);
                    return true;
                }
                else
                {
                    RemainingRouteSegments = new RouteSegment[] { new RouteSegment(P1,otherSegment.P1) };
                    removedDistance = Distance(otherSegment.P1, P2);
                    return true;
                }
            }
        }
        else if (Contains(otherSegment.P2))
        {
            if (Distance(otherSegment.P1, P1) < Distance(otherSegment.P1, P2))
            {
                RemainingRouteSegments = new RouteSegment[] { new RouteSegment(otherSegment.P2, P2) };
                removedDistance = Distance(otherSegment.P2, P1);
                return true;
            }
            else
            {
                RemainingRouteSegments = new RouteSegment[] { new RouteSegment(P1, otherSegment.P2) };
                removedDistance = Distance(otherSegment.P2, P2);
                return true;
            }
        }
        else if (otherSegment.Contains(P1))
        {
            RemainingRouteSegments = null;
            removedDistance = Distance(P1, P2);
            return true;
        }
        else
        {
            removedDistance = 0.0;
            RemainingRouteSegments = null;
            return false;
        }
                       
    }

    bool Contains(Point p)
    {
        double A = P1.Y - P2.Y;
        double B = P2.X - P1.X;
        double dist = Math.Abs(A * (p.X - P1.X) + B * (p.Y - P1.Y)) / Distance(P1, P2);
        return dist < MaxOnRouteDist;
    }

               
    bool IsParallelTo(RouteSegment otherSegment)
    {
        double v1X = P2.X - P1.X;
        double v1Y = P2.Y - P1.Y;
        double v2X = otherSegment.P2.X - otherSegment.P1.X;
        double v2Y = otherSegment.P2.Y - otherSegment.P1.Y;
        return Math.Abs(v1X * v2X + v1Y * v2Y) / Distance(P1, P2) / Distance(otherSegment.P1, otherSegment.P2) < Math.Cos(ParallelMinAngleRadians);
    }

    static double  Distance(Point p, Point q)
    {
        double dX = p.X - q.X;
        double dY = p.Y - q.Y;
        return Math.Sqrt(dX * dX + dY * dY);
    }
}

抱歉,有这么多代码。我发现编写它比解释所有情况更容易。

【讨论】:

    【解决方案2】:

    跟踪:

    • 途中累积距离(初始化为零)
    • 沿路线的最大优先位置
    • 优先位置
    • 先前位置状态(开/关路线)

    每 5 秒我们获得一个新位置:

    如果:

    • 新位置在路线上
    • 新位置在路线上比最大先前位置更远
    • 前一个位置在路线上

    然后添加|(新位置)-(先前位置)|沿路线累积距离。

    最后,返回(沿路线的累积距离)/(路线长度)。

    我们关心沿路线的最大位置的原因是为了避免在驱动器由于某种原因回溯时重复计算某些路线长度。

    我只计算当前和先前位置都在路线上的路线段。您可以在这里更加宽容,并仅根据当前位置做出决定。应该不会对所描述的问题产生太大影响。

    【讨论】:

      猜你喜欢
      • 2012-11-26
      • 2018-10-27
      • 1970-01-01
      • 2014-04-12
      • 2020-08-04
      • 2021-05-15
      • 2019-01-20
      • 2016-05-31
      • 1970-01-01
      相关资源
      最近更新 更多