如何找到中心圆半径的所有重叠圆?

时间:2012-10-15 08:55:20

标签: ruby mongodb mongodb-query mongoid3

如何在mongo shell中进行交叉或重叠查询 - 哪些圆圈与我的搜索区域重叠? Within仅与中心位置相关,但不包括搜索范围内其他圆的半径。

蒙戈:

# My bad conception:
var search = [[30, 30], 10]
db.places.find({circle : {"$within" : {"$center" : [search]}}})

现在我只能获得中心点内的这些圆圈位于搜索范围的圆圈中:

红宝石:

# field :circle, type: Circle # eg. [ [ 30, 30 ], 10 ]
field :radius, type: Integer
field :location, :type => Array, :spatial => true
spatial_index :location

Places.within_circle(location: [ [ 30, 30 ], 10 ])

# {"$query"=>{"location"=>{"$within"=>{"$center"=>[[30, 30], 10]}}}

我创建了带有附加位置(特殊索引)和半径而不是圆的示例数据,因为mongodb geo index不支持circle:

{ "_id" : 1, "name" : "a", "circle" : [ [ 5, 5 ], 40 ], "latlng" : [ 5, 5 ], "radius" : 40 }
{ "_id" : 2, "name" : "b", "circle" : [ [ 10, 10 ], 5 ], "latlng" : [ 10, 10 ], "radius" : 5 }
{ "_id" : 3, "name" : "c", "circle" : [ [ 20, 20 ], 5 ], "latlng" : [ 20, 20 ], "radius" : 5 }
{ "_id" : 4, "name" : "d", "circle" : [ [ 30, 30 ], 50 ], "latlng" : [ 30, 30 ], "radius" : 50}
{ "_id" : 5, "name" : "e", "circle" : [ [ 80, 80 ], 30 ], "latlng" : [ 80, 80 ], "radius" : 30}
{ "_id" : 6, "name" : "f", "circle" : [ [ 80, 80 ], 20 ], "latlng" : [ 80, 80 ], "radius" : 20}

所需的查询结果:

{ "_id" : 1, "name" : "a", "circle" : [ [ 5, 5 ], 40 ], "latlng" : [ 5, 5 ], "radius" : 40 }
{ "_id" : 3, "name" : "c", "circle" : [ [ 20, 20 ], 5 ], "latlng" : [ 20, 20 ], "radius" : 5 }
{ "_id" : 4, "name" : "d", "circle" : [ [ 30, 30 ], 50 ], "latlng" : [ 30, 30 ], "radius" : 50}
{ "_id" : 5, "name" : "e", "circle" : [ [ 80, 80 ], 30 ], "latlng" : [ 80, 80 ], "radius" : 30}

下面的解决方案假设我得到了所有行,然后在ruby一侧过滤我的半径,但它只返回:

{ "_id" : 4, "name" : "d", "circle" : [ [ 30, 30 ], 50 ], "latlng" : [ 30, 30 ], "radius" : 50}

2 个答案:

答案 0 :(得分:5)

我不熟悉mongodb,但我认为在[[x,y],r]值中意味着

  

x:轴x上的中心值。   y:轴y上的中心值。   r:圆半径。

假设您有一个圆圈S,这是您的搜索和一个随机圆圈A.然后您可以计算两个圆圈中心(S.center和A.center)之间的距离,看看它是否低于两个圆圈的半径(Sr + Ar)。

def distance_between(a, b)
  ((b.first - a.first)**2 + (b.last - a.last)**2)**0.5
end

elements = [{ _id: 1, name: "a", circle: [ [ 5, 5 ], 40 ] },
            { _id: 2, name: "b", circle: [ [ 10, 10 ], 5 ] },
            { _id: 3, name: "c", circle: [ [ 20, 20 ], 5 ] },
            { _id: 4, name: "d", circle: [ [ 30, 30 ], 50 ] },
            { _id: 5, name: "e", circle: [ [ 80, 80 ], 30 ] },
            { _id: 6, name: "f", circle: [ [ 80, 80 ], 20 ] }]
search = [[30, 30], 10]

elements.select do |elem| circle = elem[:circle]
  distance_between(circle.first, search.first) <= circle.last + search.last
end

#{:_id=>1, :name=>"a", :circle=>[[5, 5], 40]}
#{:_id=>3, :name=>"c", :circle=>[[20, 20], 5]}
#{:_id=>4, :name=>"d", :circle=>[[30, 30], 50]}

答案 1 :(得分:3)

不幸的是,mongo目前没有能力直接查询重叠对象,只查询对象内的点。

@oldgod的答案描述了计算两个圆是否重叠的算法。

以下是基于该计算的shell中的解决方法:

function distance(a, b) {
    return Math.pow(Math.pow(a[0] - b[0], 2) + Math.pow(a[1] - b[1], 2), 0.5);
}

将您的样本数据插入集合'circle':

> db.circle.find().forEach(
    function(c) {  
        if ( (distance(c.latlng, search.latlng) < c.radius + search.radius) ) 
          {   
               print(c.name); 
          } 
    } )
a
c
d
>