Skip to content

Having trouble with polygonize #178

@nk9

Description

@nk9

I'm trying to use polygonize to take a set of LineStrings and turn them into a Polygon. However, this is frequently failing, with the output being just an empty geometry collection. This is likely not a bug in the Rust GEOS bindings, and may not even be a bug in GEOS. However, I'm looking for some help to understand why it's working for some sets of lines and not others. None of the lines overlap, however I'm not certain that every one of the endpoints line up exactly to the 14th decimal place with the starting points of the next line. Is this required for polygonize? The lines may also not be wound appropriately. Is that important?

I have tried doing a unary union on the MultiLineString as suggested here, but that doesn't change the fact that polygonize is giving me an empty result in the failure case below.

MRE code
use anyhow::{anyhow, Result};
use geo::{Geometry, LineString, MultiLineString};
use geojson::GeoJson;
use geos::{Geometry as GeosGeometry, WKTWriter};

fn main() -> Result<()> {
    for geoj in [GEOJSON_STRING_WORKS, GEOJSON_STRING_FAILS] {
        let geojson = geoj.parse::<GeoJson>()?;
        let geos_multi_linestring = process_geojson(geojson)?;

        print_geom("before", &geos_multi_linestring);

        let mut unioned = geos_multi_linestring
            .unary_union()
            .expect("ERROR: failed union");
        unioned.normalize().expect("ERROR: failed normalization");
        let geos_poly = GeosGeometry::polygonize(&[unioned]).expect("ERROR: Polygonize failed");

        print_geom("after", &geos_poly);
    }

    Ok(())
}

fn print_geom(tag: &str, geom: &GeosGeometry) {
    let mut writer = WKTWriter::new().expect("Failed to create WKTWriter");
    match writer.write(geom) {
        Ok(wkt) => println!("\n\n\n==WKT string {}==\n\n{}", tag, wkt),
        _ => println!("••• WKT conversion failed"),
    }
}

// Processes a GeoJSON object and returns the processed GeoJSON as a String
fn process_geojson(geojson: GeoJson) -> Result<GeosGeometry> {
    match geojson {
        GeoJson::FeatureCollection(collection) => {
            let lines: Vec<LineString> = collection
                .features
                .into_iter()
                .flat_map(|f| TryInto::<Geometry>::try_into(f))
                .flat_map(|g| TryInto::<LineString>::try_into(g))
                .collect();

            let multi_line = MultiLineString(lines.clone());
            let g_geom = GeosGeometry::try_from(&multi_line).expect("Failed conversion to GEOS");
            Ok(g_geom)
        }
        _ => Err(anyhow!("Input GeoJSON must be a FeatureCollection")),
    }
}

const GEOJSON_STRING_FAILS: &str = r#"{"features":[{"geometry":{"coordinates":[[-73.1678200000696,41.19344600032452],[-73.16775299977584,41.19344300022071],[-73.16765799986257,41.19343900008236],[-73.1675530002779,41.193450999822936],[-73.1674870000187,41.19346000013419]],"type":"LineString"},"properties":{"index":0},"type":"Feature"},{"geometry":{"coordinates":[[-73.16842600011974,41.19342899973656],[-73.1683039999472,41.19342699966739],[-73.16812299975751,41.19342500027269],[-73.16794100020769,41.19343700001327],[-73.1678200000696,41.19344600032452]],"type":"LineString"},"properties":{"index":1},"type":"Feature"},{"geometry":{"coordinates":[[-73.16878799982472,41.193411999823084],[-73.16871499999782,41.19341299985772],[-73.16860600027496,41.19341499992681],[-73.168497999912,41.193423000203516],[-73.16842600011974,41.19342899973656]],"type":"LineString"},"properties":{"index":2},"type":"Feature"},{"geometry":{"coordinates":[[-73.16933799996153,41.19339099977125],[-73.16922800020396,41.19339499990961],[-73.16889700022222,41.193407000324584],[-73.16878799982472,41.193411999823084]],"type":"LineString"},"properties":{"index":3},"type":"Feature"},{"geometry":{"coordinates":[[-73.16972299978741,41.19335599990967],[-73.16964599982225,41.19336500022101],[-73.16952899982252,41.19338000006531],[-73.16941499992669,41.19338600027284],[-73.16933799996153,41.19339099977125]],"type":"LineString"},"properties":{"index":4},"type":"Feature"},{"geometry":{"coordinates":[[-73.17021900007998,41.1933470002729],[-73.17011899999382,41.193354999875126],[-73.1699749997348,41.19336899968479],[-73.16982199983903,41.19336100008265],[-73.16972299978741,41.19335599990967]],"type":"LineString"},"properties":{"index":5},"type":"Feature"},{"geometry":{"coordinates":[[-73.1718577789133,41.193395526882114],[-73.17176109549814,41.19339059859732],[-73.17136199975647,41.19338500031756],[-73.17133999964125,41.193381000133115],[-73.17113299998795,41.193369999625816],[-73.1708709995969,41.19335699992564],[-73.17044699982915,41.193349999602844],[-73.17021900010673,41.193347000363815]],"type":"LineString"},"properties":{"index":6},"type":"Feature"},{"geometry":{"coordinates":[[-73.17185326335287,41.18892700605986],[-73.17193445157719,41.18909258832794],[-73.17199155855562,41.18938764149979],[-73.17199155855562,41.189749319254915],[-73.17196300506644,41.19009196180036],[-73.17193445157719,41.19050122892908],[-73.17188686287817,41.19079628210093],[-73.17188686287817,41.19119603162481],[-73.17190589808793,41.19161481703294],[-73.17187734459876,41.19198601306756],[-73.1718487911095,41.19217636988729],[-73.17185830871433,41.19249997654832],[-73.17183927350456,41.19313767226553],[-73.17185777893332,41.19339552683957]],"type":"LineString"},"properties":{"index":7},"type":"Feature"},{"geometry":{"coordinates":[[-73.17185326341735,41.18892700607654],[-73.1716280003319,41.18894999994262],[-73.17158400010146,41.18895400012707],[-73.1714809998482,41.18896499973499],[-73.17122199959556,41.18899600026526],[-73.17104300033418,41.18902199966561],[-73.17089799994272,41.18904499982693],[-73.17077599971259,41.18906399980381],[-73.17074800021999,41.189061999711555],[-73.17029500001422,41.189040999642486],[-73.17014500029148,41.18903500026511]],"type":"LineString"},"properties":{"index":8},"type":"Feature"},{"geometry":{"coordinates":[[-73.17014500021854,41.18903500019883],[-73.17002200001146,41.18902699992221],[-73.16965400009896,41.18900599987038],[-73.16953199992632,41.1889990003027]],"type":"LineString"},"properties":{"index":9},"type":"Feature"},{"geometry":{"coordinates":[[-73.16953199990184,41.18899900040361],[-73.16944200024807,41.18899100003466],[-73.16930999955679,41.188980999573516],[-73.16917399958038,41.188983999711866],[-73.16908499997271,41.18898599980412],[-73.1687639995589,41.18896499973499],[-73.16828399990663,41.1889340001041],[-73.16780000006992,41.18891700021942],[-73.16747899965605,41.188906999758274]],"type":"LineString"},"properties":{"index":10},"type":"Feature"},{"geometry":{"coordinates":[[-73.16747899965605,41.188906999758274],[-73.1674809997483,41.18913200024167],[-73.16748599997885,41.18945199971006],[-73.16747500037093,41.18980799993932],[-73.16747000014038,41.18999999980019],[-73.16746900009423,41.19003399956949]],"type":"LineString"},"properties":{"index":11},"type":"Feature"},{"geometry":{"coordinates":[[-73.16746900007058,41.19003399967717],[-73.16747000010521,41.19026300017804],[-73.16747200017439,41.19062599991756],[-73.16747899974207,41.19095299976102],[-73.16748499994951,41.19118300029644]],"type":"LineString"},"properties":{"index":12},"type":"Feature"},{"geometry":{"coordinates":[[-73.16748499994951,41.19118300029644],[-73.1674950002954,41.191637999845504],[-73.16750099982845,41.191882000190674],[-73.1674870000187,41.19257499987738],[-73.16748996411894,41.192786918879456],[-73.16749300022622,41.193003999876105],[-73.1674870000187,41.19346000013419]],"type":"LineString"},"properties":{"index":13},"type":"Feature"}],"type":"FeatureCollection"}"#;

const GEOJSON_STRING_WORKS: &str = r#"{"features":[{"geometry":{"coordinates":[[-73.17734200024968,41.19073100017662],[-73.17731800009412,41.19086500008983],[-73.17724799969656,41.191269999933006],[-73.17722600028458,41.191405999915304]],"type":"LineString"},"properties":{"index":0},"type":"Feature"},{"geometry":{"coordinates":[[-73.17744799986889,41.19006800017852],[-73.17742000024947,41.190198999988006],[-73.17741400004202,41.190230999745786],[-73.17736100023232,41.19059800029813],[-73.17734200024968,41.19073100017662]],"type":"LineString"},"properties":{"index":1},"type":"Feature"},{"geometry":{"coordinates":[[-73.17759800033542,41.18911899973167],[-73.17756599990325,41.18930800019806],[-73.17751900030109,41.189592999937865],[-73.17747600016288,41.18987700031752],[-73.17744799986889,41.19006800017852]],"type":"LineString"},"properties":{"index":2},"type":"Feature"},{"geometry":{"coordinates":[[-73.1795329998111,41.18919100019841],[-73.17914599991595,41.189175999679634],[-73.17798500023058,41.18913300021582],[-73.17759800033542,41.18911899973167]],"type":"LineString"},"properties":{"index":3},"type":"Feature"},{"geometry":{"coordinates":[[-73.18063900029208,41.18924299997339],[-73.18041700003327,41.18923200026753],[-73.17975400003517,41.189200999869726],[-73.1795329998111,41.18919100019841]],"type":"LineString"},"properties":{"index":4},"type":"Feature"},{"geometry":{"coordinates":[[-73.18063900029208,41.18924299997339],[-73.18062899994628,41.18943399983456],[-73.18060000029223,41.19000800012684],[-73.18059099998098,41.19020000002255]],"type":"LineString"},"properties":{"index":5},"type":"Feature"},{"geometry":{"coordinates":[[-73.18059099998098,41.19020000002255],[-73.18058499977344,41.190334999970304],[-73.18057800020586,41.190548999952306],[-73.18056299968698,41.19073999981348],[-73.18055300001566,41.19087599979578]],"type":"LineString"},"properties":{"index":6},"type":"Feature"},{"geometry":{"coordinates":[[-73.18055300001566,41.19087599979578],[-73.18054799984267,41.191012999812706],[-73.18053299999838,41.19142399986341],[-73.18052799982549,41.19156099988025]],"type":"LineString"},"properties":{"index":7},"type":"Feature"},{"geometry":{"coordinates":[[-73.18052799982549,41.19156099988025],[-73.18030600024116,41.19154800010513],[-73.1796440002776,41.19151100017446],[-73.17942300005353,41.191498999759396]],"type":"LineString"},"properties":{"index":8},"type":"Feature"},{"geometry":{"coordinates":[[-73.17942300005353,41.191498999759396],[-73.17920299986382,41.19148900008799],[-73.17854500003871,41.19146199982872],[-73.17832599988371,41.19145300019186]],"type":"LineString"},"properties":{"index":9},"type":"Feature"},{"geometry":{"coordinates":[[-73.17832599988371,41.19145300019186],[-73.1781059996941,41.19144299984607],[-73.17744599979972,41.191415000226556],[-73.17722600028458,41.191405999915304]],"type":"LineString"},"properties":{"index":10},"type":"Feature"}],"type":"FeatureCollection"}"#;

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions