Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

turf.polygonize not creating polygons from grid of multilinestring lines #819

Open
maphew opened this issue Jun 27, 2017 · 11 comments
Open

Comments

@maphew
Copy link

maphew commented Jun 27, 2017

turf.polygonize isn't creating polygons from this input:

Code snippet:

var grid = {"coordinates":[[[-135.025,6 ...snip.... 4092,60.6726],"type":"MultiLineString","properties"};
var polygon = turf.polygonize(grid);

Full test case - https://jsfiddle.net/87cq6edb/

@DenisCarriere
Copy link
Member

@NickCis Can you have a look at this? You are the one most "qualified" to answer/fix this.

@NickCis
Copy link
Contributor

NickCis commented Jun 27, 2017

Current implementation of polygonize makes the following assumption (copying from docs):

Edges must be correctly noded, i.e., they must only meet at their endpoints.

As far as i understand, in this test case the lineStrings are not correctly noded, ie: they intersect between them, that's why polygonize isn't generating any polygons.

I must highlight that (according to the docs) this is the library's expected behavior.

At the moment, the user has to look for all the intersections and make the lineStrings divitions. It was the problem described at the end of the PR.

@maphew
Copy link
Author

maphew commented Jun 27, 2017

Oh sorry. I read "I ended up porting this to javascript because I wanted the same functionality as Shapely's polygonize function" in the PR intro and assumed there was feature parity with Shapely (because that's what I wanted to believe ;-).

@NickCis
Copy link
Contributor

NickCis commented Jun 27, 2017

As far as i know Shapely is calling the GEOS's polygonizer class. This is a javascript port of that c++ class. I think that with Shapely you'll get the same problem.

If that's not the case, please tell me so (if possible, inform the Shapely version used and a working example). i could try to port that functionality.

@DenisCarriere
Copy link
Member

We can always attempt to port over Shapely's polygonize function to NodeJS and include it in the test cases.

We've done this so far with some of the @turf/boolean modules.

This test process is a bit unconventional, but if you want to check boolean-shapely (should only be used for testing purposes).

@maphew
Copy link
Author

maphew commented Jun 28, 2017

According to https://gis.stackexchange.com/a/95374/108 Qgis' polygonize uses shapely, and that's how I produced the "expected output" above.

@NickCis
Copy link
Contributor

NickCis commented Jun 29, 2017

@maphew I really don't know what QGis is exactly doing, but if i run Shapely's polygonize i get the same blank result.

Using the following script (i'm using shapely 1.5.17):

#! /usr/bin/env python
import sys
import json

from shapely.ops import polygonize
from shapely.geometry import asShape
from shapely.geometry import mapping

def main(in_path, out_path):
    with open(in_path, encoding='utf-8') as f:
        geo_json = json.load(f)

    output = {
        'type': 'FeatureCollection',
        'features': []
    }

    for poly in polygonize(asShape(geo_json)):
        output['features'].append({
            'type': 'Feature',
            'properties': {},
            'geometry': mapping(poly)
        })

    with open(out_path, 'w') as f:
        json.dump(output, f)

if __name__ == '__main__':
    main(sys.argv[1], sys.argv[2])

It's first argument is the input geojson, and the second one the output feature collection:

$ ./polygonizer.py input.geojson outpu.geojson

When running with your example, i get a blank result, as with turf's Polygonizer.

If it is run with an example that has the lines correctly nodded, eg:

{
  "coordinates": [
    [
        [0, 0],
        [1, 1]
    ],
    [
        [0, 0],
        [0, 1]
    ],
    [
        [0, 1],
        [1, 1]
    ],
    [
        [1, 1],
        [1, 0]
    ],
    [
        [1, 0],
        [0, 0]
    ]
  ],
  "type": "MultiLineString",
  "properties": {}
}
Loading

The polygons are formed.

If you read the performace section of Shapely's ops documentation, it says that it is using geos c library. Turf's polygonize is a port of the Polygonizer class of that library, so you get similar results.

@NickCis
Copy link
Contributor

NickCis commented Jun 30, 2017

I've been reading the QGis source code in order to understand what QGis is doing.

Apparently, when you are running "QGis >> Vector geometry Tools >> Polygonize", it runs this QGis Polygonize algorithm.

If you look at the processAlgorithm method, you'll notice that before calling QgsGeometry.polygonize it calls QgsGeometry.unaryUnion.

The QgsGeometry.polygonize (header file) function is basically a wrapper of the geos polygonize function. But, if you read Doxygen comments of the header file, you'll notice the following clarification:

The input geometries must be fully noded (i.e. nodes exist at every common intersection of the geometries). The easiest way to ensure this is to first call unaryUnion() on the set of input geometries and then pass the result to polygonize()

The QgsGeometry.unaryUnion (header file) function is basically a wrapper of geos combine function. Reading the docs this function does the following:

Compute the unary union on a list of \a geometries. May be faster than an iterative union on a set of geometries. The returned geometry will be fully noded, i.e. a node will be created at every common intersection of the input geometries. An empty geometry will be returned in the case of errors.

So, in terms of a library, turf's polygonize works correctly. Its output is coherent with what other libraries (such as geos or shapely) create. All of them have the precondition that the input has to be correctly nodded.

I really don't know (please help me @DenisCarriere ) if there is a function in turf that does something similar to QgsGeometry.unaryUnion or geos combine, if not, i could try to port that function into turf.

@maphew
Copy link
Author

maphew commented Jun 30, 2017 via email

@DenisCarriere
Copy link
Member

DenisCarriere commented Jun 30, 2017

⭐️ 👍 @NickCis Great research. Unfortunately we Turf does not have any methods that performs unaryUnion, however it would be REALLY useful since I do recall needing this type of behavior in the past.

I have no issues if you call this new module exactly the same name as QGIS @turf/unary-union.

The only library that would do a similar effort would be @turf/line-intersect and if you only pass it 2-vertex segments it will perform really fast (skips any indexing).

@NickCis
Copy link
Contributor

NickCis commented Jul 3, 2017

Ok!, I'll be starting to work on that new module. I'll update with further news.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants