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

Having trouble with polygonize #178

Open
nk9 opened this issue Jan 20, 2025 · 0 comments
Open

Having trouble with polygonize #178

nk9 opened this issue Jan 20, 2025 · 0 comments

Comments

@nk9
Copy link

nk9 commented Jan 20, 2025

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"}"#;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant