PHP / Mongo geoJSON 循环无效

Posted

技术标签:

【中文标题】PHP / Mongo geoJSON 循环无效【英文标题】:PHP / Mongo geoJSON Loop is not valid 【发布时间】:2016-12-17 06:45:36 【问题描述】:

我将一些坐标传递给 mongo 进行地理搜索。如果坐标不相交(例如八字形),它可以正常工作。但是当两条线相交时,它会给出loop is not valid。有什么方法可以找到交叉点并将所有这些循环分开?

注意可能有很多。

编辑:我添加了示例查询和错误。请注意,我理解它为什么会发生,我只是想知道是否有一些已知的方法可以将这些循环分成单独的多边形(一些算法或在 Mongo 中)。

查询:

db.items.find(
    "address.location": 
        "$geoWithin": 
            "$geometry": 
                "type": "Polygon",
                "coordinates": [[
                    [-97.209091, 49.905691],
                    [-97.206345, 49.918072],
                    [-97.178879, 49.919399],
                    [-97.165146, 49.907903],
                    [-97.164459, 49.892865],
                    [-97.180939, 49.889326],
                    [-97.197418, 49.895077],
                    [-97.200165, 49.902596],
                    [-97.203598, 49.919399],
                    [-97.216644, 49.928682],
                    [-97.244797, 49.927356],
                    [-97.255096, 49.913209],
                    [-97.209091, 49.905691]
                ]]
            
        
    
);

错误:

Error: error: 
    "waitedMS" : NumberLong(0),
    "ok" : 0,
    "errmsg" : "Loop is not valid: [
            [ -97.209091, 49.905691 ]
            [ -97.206345, 49.918072 ],
            [ -97.17887899999999, 49.919399 ],
            [ -97.16514599999999, 49.907903 ],
            [ -97.16445899999999, 49.892865 ],
            [ -97.180939, 49.889326 ],
            [ -97.197418, 49.895077 ],
            [ -97.200165, 49.902596 ],
            [ -97.203598, 49.919399 ],
            [ -97.216644, 49.928682 ],
            [ -97.24479700000001, 49.927356 ],
            [ -97.25509599999999, 49.913209 ],
            [ -97.209091, 49.905691 ]
        ]
        Edges 1 and 7 cross.
        Edge locations in degrees: [-97.2063450, 49.9180720]-[-97.1788790, 49.9193990]
        and [-97.2001650, 49.9025960]-[-97.2035980, 49.9193990]
    ",
    "code" : 2

更新

我添加了一个蛮力方法的图像。

Polygon Slicing

基本上它是在交叉点上进行预测。 如果它找到一个,它会交换这些点,以便它保持在一个循环内。 它会在某些队列中添加截止点作为“起点”。 当向前看并找到它自己的起点时,我们就有了一个循环。 然后继续遍历“起点”队列,直到它为空。 新的多边形集应该包含所有单独的循环(理论上)。

这有一些问题,通过所有这些循环可能会变得非常昂贵。假设最多 50 个点将是大约 1275 次操作。

同时处理 0/180 度坐标上的环绕可能是一个挑战。

无论如何,我不想花一整天的时间在这上面,我什至可以处理一个不处理环绕条件的解决方案。

希望我已经可以在某个地方找到一个很好的算法(可能有一些花哨的技术术语)。

如果有一种比蛮力前瞻更有效的方法,那就太好了。

【问题讨论】:

一些代码示例将有助于解决此问题。 你说你明白为什么会发生。 (是不是因为不是有效的多边形?)您能否将此信息添加到问题中。 @PawelDubiel 是的,它是一个无效的多边形,因为它的形状是 8 字形。所以有两条线相交。问题是如何处理。 我不知道 mongodb 是否真的是您尝试存档的好工具。我会考虑 postgis,因为它具有诸如 postgis.refractions.net/docs/ST_Polygonize.html 之类的有用功能 你想用不同孔共享的边缘做什么? see closed jira 【参考方案1】:

这是因为您的坐标相同,才会在多边形形状中产生异常:[-97.1788790, 49.9193990] 和 [-97.2035980, 49.9193990]。在您的代码中删除或更改任何重复的坐标,

"coordinates": [[
    [-97.209091, 49.905691],
    [-97.206345, 49.918072],
    [-97.178879, 49.919399], // this line
    [-97.165146, 49.907903],
    [-97.164459, 49.892865],
    [-97.180939, 49.889326],
    [-97.197418, 49.895077],
    [-97.200165, 49.902596],
    [-97.203598, 49.919399], // and this one
    [-97.216644, 49.928682],
    [-97.244797, 49.927356],
    [-97.255096, 49.913209],
    [-97.209091, 49.905691]
]]

【讨论】:

好吧,为了试一试,我修改了坐标,还是报错。但问题不在于重复坐标,而是两条线相交(如图 8 循环),mongo 似乎不支持。【参考方案2】:

正如我在 cmets 中提到的,查询空间数据的更好工具是使用 PostGIS。

例如 PostGIS 有 ST_validReason() 来查找多边形的问题和 st_makevalid 来修复,但如果这不是一个选项,那么我将创建一个可用于您的 php 脚本的服务shapely python 库https://github.com/Toblerity/Shapely

http://toblerity.org/shapely/manual.html

Shapely 的第一个前提是 Python 程序员应该能够 在 RDBMS 之外执行 PostGIS 类型的几何操作

当然,shapely 是一种流行的工具,您应该在 *** 或 gis.stackexchange.com 上向更有经验的用户寻求帮助

我认为您要解决的问题并不像听起来那么简单。

所以我会执行以下步骤:

1 了解如何使用 shapely 进行操作

类似的问题: Splitting self-intersecting polygon only returned one polygon in shapely in Python

2 创建一个简单的 php 服务,它将查询详细信息传递给 python 脚本

3 Shapely 不会阻止无效多边形的创建,但操作时会引发异常。所以基本上在这种例外情况下,我会从第 1 步调用脚本。

如果这只是用于查询之一,我会使用 QGIS 软件(将点导入为 CSV,创建一个新的 shapefile 图层(多边形类型),并使用数值顶点编辑插件)

更新

我认为多边形应该由创建它的工具修复,所以在这种情况下,它应该是用户。也许你通过从不同的角度看来解决这个问题,如果形状来自用户并且在你的应用程序的 GoogleMap 中绘制,则可能在绘制过程中强制没有交叉。

也发现了这个Drawing a Polygon(排序点并创建没有交集的多边形)

【讨论】:

这似乎有点矫枉过正。虽然我不确定如果有多条相交线会发生什么,但我可以想象做一个蛮力向前看,只是在路径上添加点以删除相交。还有 180/0 度包裹的问题。试图为它找到一些算法。 @Rob 我觉得那个面积很小,你真的需要这么复杂的形状吗?把这个形状变成一个矩形旋转区域很容易 这些形状来自用户在谷歌地图中绘制的,所以我无法真正控制它们是否形成了几条相交的线。它不是真正的矩形,它可以是任何形状。所以我不知道要在哪些角落采取行动。 @Rob 更新答案(评论框内字符不足) 这不是一个糟糕的解决方法。但我敢肯定,如果多边形突然改变形状,用户会抱怨这是一个错误(功能!)@pawel-dubiel

以上是关于PHP / Mongo geoJSON 循环无效的主要内容,如果未能解决你的问题,请参考以下文章

用 php 和 mongo 处理巨大的数组

尝试将变量保存到 GeoJSON 点时出现 Mongoose CastError

用php检查是不是指向内部或不在多多边形geojson中

使用 PHP 数组输出 MySQL 查询 - foreach 循环错误“非法偏移”和“无效参数”

从 MySql 在 php 中创建 GeoJson 以与 MapBox javascript API 一起使用

php请求返回GeoJSON格式的数据