通过大型纬度/长度坐标优化搜索以找到匹配

时间:2013-08-09 03:22:50

标签: javascript performance search google-maps-api-3 geolocation

我需要创建一个页面

  1. 需要2个地址(往返),
  2. 绘制该路线1英里范围内的路线和区域,
  3. 然后确定是否有数千个纬度/长度坐标的预定义列表属于此区域(沿着路线1英里)
  4. 我正在使用google-maps v3 api和routeboxer类。
    这是一个很好的例子:http://google-maps-utility-library-v3.googlecode.com/svn/trunk/routeboxer/examples/routeboxer-v3.html
    如您所见,#1和#2基本上由此路由器示例处理。

    我的问题是如何有效地处理#3。 Routeboxer提供一系列箱形电缆(东北纬/长至西南纬/长角)。我可以逐框循环,然后在每个预定义的纬度/长度坐标系内循环,看看列表中是否有任何坐标位于路径盒的范围内,但这是一个冗长,低效的过程。

    我正在寻找一种优化此(#3)搜索部分的方法。 一些想法:

    1. 二元搜索;需要按纬度对coord列表进行排序,然后需要很长时间 - 但可能会加快速度
    2. mySQL查询:这将处理userPC并将其放到我们的服务器上; 我会查询每个routeBox:
      select * from myListOfLatLongs where lat box_latwest&& lng box)lngsouth
    3. 哪个更适合速度和速度稳定性?有没有更好的想法/优化? 最重要的是,如果没有优化,这理论上可以返回多个盒子,然后需要将每个盒子与成千上万的线圈进行比较 - 这可能会成为一个漫长的过程。任何帮助表示赞赏

2 个答案:

答案 0 :(得分:1)

将您的纬度/经度空间细分为适当大小的单元格,并将位置分类到这些单元格中。

然后,对于沿着路线的每个点,在单元格中向外进行螺旋搜索以找到最近的邻居。

P.S。螺旋搜索。你可以像这样在正方形,砖块或六边形上做。如果瓷砖大到足以包含一些点但不会太多,如果快速找到邻居。

enter image description here

将纬度和经度转换为上述坐标系,将它们四舍五入到最近的中心,并为每个单元格制作一个桶。 然后拿你的搜索点找到它的桶。 如果在其桶中找不到任何有用的东西,则在半径1处搜索六个桶,依此类推,直到找到合适的邻居集合,并选择最佳的一个。 单元格序列如下所示,假设0,0是起始单元格:

look in 0,0
++x

++y
--x
--x,--y
--y
++x
++y,x+=2

++y twice
--x twice
--x,--y twice
--y twice
++x twice
++x,++y
++y,x+=2

etc. etc.

编辑:要做的一些C ++代码

// for each point x,y, do this (d is diameter of a cell)
double x1 = (x + y/2)/d;  // transform x coordinate
double y1 = (y / 0.866)/d;  // transform y coordinate (it's shortened a bit)
int ix = (int)floor(x1 + 0.5);  // find corresponding bucket
int iy = (int)floor(y1 + 0.5);
// then put point into bucket at ix,iy

// to search, enumerate over the cells
// first at distance 0, then 1, then 2, etc.
bool bPointsFound = false;
// collect points in bucket at 0,0
if (/* there are any points in the collection */){
  bPointsFound = true;
}
for (n = 1; n < upper_limit && !bPointsFound; n++){
  iy = 0; ix = n;
  // upper right edge
  for (i = 0; i < n; i++){
    // collect points in bucket at ix, iy
    iy++;
  }
  // top edge
  for (i = 0; i < n; i++){
    // collect points in bucket at ix, iy
    ix--;
  }
  // upper left edge
  for (i = 0; i < n; i++){
    // collect points in bucket at ix, iy
    ix--; iy--;
  }
  // lower left edge
  for (i = 0; i < n; i++){
    // collect points in bucket at ix, iy
    iy--;
  }
  // bottom edge
  for (i = 0; i < n; i++){
    // collect points in bucket at ix, iy
    ix++;
  }
  // lower right edge
  for (i = 0; i < n; i++){
    // collect points in bucket at ix, iy
    ix++; iy++;
  }
  if (/* there are any points in the collection */){
    bPointsFound = true;
  }
}
// pick the closest point in the collection

补充:获得一个不是最接近的点的可能性很小,因为六边形边缘外的点可能比角落内的点更近。如果这是一个问题,请转到额外的层。

答案 1 :(得分:0)

您可以使用空间索引并搜索2d范围,即。边界框。例如,使用MySQL空间扩展。您也可以尝试我的希尔伯特曲线类(phpclasses.org),它使用带有范围搜索的四核,它是纯粹的PHP解决方案。您还可以尝试使用四叉树,它在r树上具有更好的性能。