Mongodb 寻找重叠的轨迹
考虑以下情况: 我在mongodb中将行程/轨迹存储为Mongodb 寻找重叠的轨迹,mongodb,gis,geospatial,Mongodb,Gis,Geospatial,考虑以下情况: 我在mongodb中将行程/轨迹存储为LineString,索引为2dsphere 根据提供的图像,Trip 1是用户想要搜索的轨迹,Trip2-6是已经存储在mongodb上的行程 给定$near上的maxDistance,Trip1应与Trip3和Trip4“匹配”,如图所示 但是,似乎接受多边形或多边形作为$geometry类型,并且似乎只接受点 是否有任何省时的方法来使用mongo查询实现以下场景 谢谢 编辑:正如Alex Blex所说,我将几何体更改为多边形 数据可视
LineString
,索引为2dsphere
根据提供的图像,Trip 1
是用户想要搜索的轨迹,Trip2-6
是已经存储在mongodb上的行程
给定$near上的maxDistance,Trip1应与Trip3和Trip4“匹配”,如图所示
但是,似乎接受多边形或多边形作为$geometry类型,并且似乎只接受点
是否有任何省时的方法来使用mongo查询实现以下场景
谢谢
编辑:正如Alex Blex所说,我将几何体更改为多边形 数据可视化(行程1为搜索行程,行程2-3存储在数据库中) 因此,我们在mongo上存储了以下文档: Trip2 Trip3 旅程1是我们寻找的旅程 我运行的查询如下所示:
db.trips.find({ tripData: { $geoIntersects : { $geometry : trip1 } } } )
此查询不会像预期的那样返回任何内容,因为旅行不会像您在可视化中看到的那样相交。如何使用$near运算符修改查询以匹配Trip1和Trip3?
地理相交
需要查询中的多边形或多边形,即问题中的Trip1。Trip2-6将LineString
存储在文档中,这非常好。因此,唯一需要做的额外工作是使用偏移量将Trip1转换为多边形,如问题中的limenear
所示
我们先来考虑直线。将线[[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]
];
}
或
生成石灰多边形,如下图所示:
返回值可用于geoIntersects
查询具有LineString
位置的文档
问题区域以红色突出显示。在边缘情况下,第一个多边形覆盖的距离大于d
,在相同边缘情况下,第二个多边形覆盖的距离小于d
如果这是唯一的问题,我会采用假阴性方法,在点[x1,y1]
和[x2,y2]
附近再运行两次查询,以检查突出显示区域中是否有遗漏的文档
如果Trip1是一个复杂的线字符串
,则需要进行更多的计算才能将其转换为多边形。如图所示:
除了第一个和最后一个点的边缘情况外,每个线段的起点和终点都存在类似的问题。基本上,您需要计算每个线段之间的角度,以计算多边形对应的顶点。你仍然可行。在多边形的假负片版本中,应切割用红色圈起的顶点,再次考虑线段之间的角度
如果查询中的Trip1线有许多线段,可能会非常昂贵,因为您需要为每个顶点运行near
query+2个端点
作为一种实用的方法,如果是可以接受的,那么假阳性版本可能工作得相当快,因为它是一个单一的查询 你是如何储存旅行的?如果它只是一条直线,您可以做一个简单的数学来计算交点。我将行程存储为LineString(这意味着坐标数组),但我希望利用2dsphere索引,并具有mongo提供的处理地理空间数据的效率。此外,我认为做数学计算会很耗时,因为我必须在最坏的情况下将行程1的每个点与其他行程的每个点进行比较。所谓“数学”,我的意思是通过将附近的值添加到坐标,将目标行程1
转换为多边形。基本上与您绘制的石灰形状相交。如果你提供一些数据,用代码回答会更简单。@AlexBlex谢谢你的时间,我已经编辑了这个问题。你不喜欢测试驱动的方法,是吗=)我希望看到2个文档和1个查询,坐标是你知道只应返回1个文档,例如trip4
,和trip6
文档,和Trip 1
查询near
值。感谢您的回答。不管这种方法看起来多么好,我还是实现了RouteBox。
tripData: Object
{
type: Polygon
coordinates: [
[ [2,2] , [1,4] , [3,5] , [4,2] , [2,2] ]
]
}
db.trips.find({ tripData: { $geoIntersects : { $geometry : trip1 } } } )
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]
];
}