【问题标题】:Find Overlapping Trajectories查找重叠轨迹
【发布时间】:2016-06-09 22:51:00
【问题描述】:

考虑以下情况:

我在 mongodb 中将行程/轨迹存储为LineString,索引为2dsphere

根据提供的图片,Trip 1 是用户想要搜索的轨迹,Trip2-6 是已经存储在 mongodb 上的行程。

给定 $near 上的 maxDistance,Trip1 应该与所示的 Trip 3 和 4 “匹配”。

但是 $geointersects 似乎接受 Polygon or Multipolygon 作为 $geometry 类型,$near 似乎只接受 Point

是否有任何省时方法来使用 mongo 查询实现以下场景?

谢谢!


编辑:正如 Alex Blex 所说,我将几何图形更改为 Polygon

数据可视化(Trip 1 是搜索 Trip,Trip2-3 存储在 db 中)

所以我们在 mongo 上存储了以下文档:

Trip2

  tripData: Object
 {
   type: Polygon
   coordinates: [ 
      [ [8,2] , [7,3] , [7,4], [8,2] ] 
   ]
 }

Trip3

  tripData: Object
 {
   type: Polygon
   coordinates: [ 
      [ [3,1], [4,1], [4,1.9999], [3,1] ] 
   ]
 }

Trip 1 是我们搜索的行程

  tripData: Object
 {
   type: Polygon
   coordinates: [ 
      [ [2,2] , [1,4] , [3,5] , [4,2] , [2,2] ] 
   ]
 }

我运行的查询如下:

 db.trips.find({ tripData: { $geoIntersects : { $geometry : trip1 } } } )

此查询未按预期返回任何内容,因为行程不相交,正如您在可视化中看到的那样。如何修改查询以使用 $near 运算符将 Trip1 与 Trip3 匹配?

【问题讨论】:

  • 如何存储行程?如果它只是一条线,你可以做一个简单的数学来计算交点。
  • 我将行程存储为 LineString(这意味着坐标数组),但我想利用 2dsphere 索引并拥有 mongo 在处理地理空间数据方面提供的效率。此外,我认为做数学运算会很耗时,因为在最坏的情况下,我必须将行程 1 的每个点与其他行程的每个其他点进行比较。
  • “数学”是指通过将near 值添加到坐标,将目标Trip 1 转换为多边形。基本上是地理相交您绘制的石灰形状。如果你提供一些数据,用代码回答会更简单。
  • @AlexBlex 感谢您抽出宝贵时间,我已经编辑了问题。
  • 您不喜欢测试驱动的方法,对吗 =) 我希望看到 2 个文档和 1 个查询,其坐标您知道应该只返回 1 个文档,例如Trip 4Trip 6 文档,以及 Trip 1 带有 near 值的查询。

标签: mongodb gis geospatial


【解决方案1】:

geoIntersects 需要多边形或多边形在查询中,即问题中的 Trip1。 Trip2-6 是LineString 存储在文档中,非常好。所以唯一要做的额外事情是使用偏移量将 Trip1 转换为多边形,在问题中显示为石灰near

让我们首先考虑直线。将线[[x1,y1][x2,y2]] 转换为具有偏移d 的多边形的函数可以很简单:

function LineToPolyWithFalsePositive(line, d) {
    var teta = Math.atan2(line[1][0] - line[0][0], line[1][1] - line[0][1]);
    var s = Math.sin(teta);
    var c = Math.cos(teta);
    return [
        [line[0][0] - d*s - d*c, line[0][1] - d*c + d*s], 
        [line[1][0] + d*s - d*c, line[1][1] + d*c + d*s], 
        [line[1][0] + d*s + d*c, line[1][1] + d*c - d*s], 
        [line[0][0] - d*s + d*c, line[0][1] - d*c - d*s]
    ];
}

function LineToPolyWithFalseNegative(line, d) {
    var teta = Math.atan2(line[1][0] - line[0][0], line[1][1] - line[0][1]);
    var s = Math.sin(teta);
    var c = Math.cos(teta);
    return [
        [line[0][0] - d*s, line[0][1] - d*c], 
        [line[0][0] - d*c, line[0][1] + d*s], 
        [line[1][0] - d*c, line[1][1] + d*s], 
        [line[1][0] + d*s, line[1][1] + d*c], 
        [line[1][0] + d*c, line[1][1] - d*s], 
        [line[0][0] + d*c, line[0][1] - d*s]
    ];
}

这会产生如下图所示的石灰多边形:

返回值可用于geoIntersects 查询具有LineString 位置的文档。

用红色突出显示的问题区域。在边缘情况下,第一个多边形覆盖的距离大于d,而在相同的边缘情况下,第二个多边形覆盖的距离小于d

如果这是唯一的问题,我会采用假阴性方法并针对点 [x1,y1][x2,y2] 再运行 2 个 near 查询,以检查突出显示的区域中是否有任何遗漏的文档。

如果 Trip1 是复杂的 LineString,则需要进行更多计算才能将其转换为多边形。看图:

除了第一个点和最后一个点的边缘情况外,每个段的开始和结束都有类似的问题。基本上,您需要计算每个段之间的角度以锻炼多边形的对应顶点。你还是可行的。在多边形的假阴性版本中,应切割用红色圈出的顶点,再次考虑线段之间的角度。

如果查询中的 Trip1 行有很多段,则可能会非常昂贵,因为您需要为每个顶点运行 near 查询 + 2 用于端点。

作为一种务实的方法,如果它可以接受的,则误报版本可能会工作得很快,因为它是单个查询。

【讨论】:

  • 感谢您的回答亚历克斯。但是这种方法看起来不错,我实现了 Routeboxer。
猜你喜欢
  • 2018-03-05
  • 1970-01-01
  • 2021-11-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-28
  • 1970-01-01
相关资源
最近更新 更多