Skip to content
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
/target
/.vscode
79 changes: 79 additions & 0 deletions examples/generate_single_fixture_output.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
use std::fs;
use std::path::PathBuf;

use geo::{Line, LinesIter};
use geo_polygonizer::polygonize;
use geojson::{Feature, FeatureCollection, Geometry, GeometryValue};

fn fixture_path(kind: &str, name: &str) -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("fixtures")
.join("polygonizer")
.join(kind)
.join(format!("{name}.geojson"))
}

fn load_input_lines(name: &str) -> Vec<Line<f64>> {
let path = fixture_path("input", name);
let text = fs::read_to_string(&path)
.unwrap_or_else(|err| panic!("failed to read fixture {}: {err}", path.display()));
let collection: FeatureCollection = serde_json::from_str(&text)
.unwrap_or_else(|err| panic!("failed to parse fixture {}: {err}", path.display()));

collection
.features
.into_iter()
.flat_map(|feature| {
let geometry = feature
.geometry
.unwrap_or_else(|| panic!("input fixture {name} has a feature with no geometry"));
match geometry.value {
GeometryValue::LineString { .. } => {
let linestring: geo::LineString<f64> = geometry.try_into().unwrap();
linestring.lines().collect::<Vec<_>>()
}
GeometryValue::MultiLineString { .. } => {
let multiline: geo::MultiLineString<f64> = geometry.try_into().unwrap();
multiline.lines_iter().collect::<Vec<_>>()
}
other => {
panic!("input fixture {name} uses unsupported geometry type: {other:?}")
}
}
})
.collect()
}

fn main() {
let name = std::env::args()
.nth(1)
.unwrap_or_else(|| "minimal_secondary_probe_split".to_string());
let input_lines = load_input_lines(&name);
let polygons = polygonize(input_lines);

let features = polygons
.0
.into_iter()
.map(|polygon| {
let geometry = Geometry::new(GeometryValue::from(&polygon));
Feature {
bbox: None,
geometry: Some(geometry),
id: None,
properties: None,
foreign_members: None,
}
})
.collect();

let collection = FeatureCollection {
bbox: None,
features,
foreign_members: None,
};

let output_path = fixture_path("output", &name);
let output_json = serde_json::to_string_pretty(&collection).expect("serialize output");
fs::write(&output_path, output_json)
.unwrap_or_else(|err| panic!("failed to write fixture {}: {err}", output_path.display()));
}
77 changes: 77 additions & 0 deletions examples/update_very_complex_fixture.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
use std::fs;
use std::path::PathBuf;

use geo::{Line, LinesIter};
use geo_polygonizer::polygonize;
use geojson::{Feature, FeatureCollection, Geometry, GeometryValue};

fn fixture_path(kind: &str, name: &str) -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("fixtures")
.join("polygonizer")
.join(kind)
.join(format!("{name}.geojson"))
}

fn load_input_lines(name: &str) -> Vec<Line<f64>> {
let path = fixture_path("input", name);
let text = fs::read_to_string(&path)
.unwrap_or_else(|err| panic!("failed to read fixture {}: {err}", path.display()));
let collection: FeatureCollection = serde_json::from_str(&text)
.unwrap_or_else(|err| panic!("failed to parse fixture {}: {err}", path.display()));

collection
.features
.into_iter()
.flat_map(|feature| {
let geometry = feature
.geometry
.unwrap_or_else(|| panic!("input fixture {name} has a feature with no geometry"));
match geometry.value {
GeometryValue::LineString { .. } => {
let linestring: geo::LineString<f64> = geometry.try_into().unwrap();
linestring.lines().collect::<Vec<_>>()
}
GeometryValue::MultiLineString { .. } => {
let multiline: geo::MultiLineString<f64> = geometry.try_into().unwrap();
multiline.lines_iter().collect::<Vec<_>>()
}
other => {
panic!("input fixture {name} uses unsupported geometry type: {other:?}")
}
}
})
.collect()
}

fn main() {
let name = "very_complex_linework";
let input_lines = load_input_lines(name);
let polygons = polygonize(input_lines);

let features = polygons
.0
.into_iter()
.map(|polygon| {
let geometry = Geometry::new(GeometryValue::from(&polygon));
Feature {
bbox: None,
geometry: Some(geometry),
id: None,
properties: None,
foreign_members: None,
}
})
.collect();

let collection = FeatureCollection {
bbox: None,
features,
foreign_members: None,
};

let output_path = fixture_path("output", name);
let output_json = serde_json::to_string_pretty(&collection).expect("serialize output");
fs::write(&output_path, output_json)
.unwrap_or_else(|err| panic!("failed to write fixture {}: {err}", output_path.display()));
}
7 changes: 7 additions & 0 deletions fixtures/nodify/input/collinear_contained.geojson
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "FeatureCollection",
"features": [
{ "type": "Feature", "properties": { "name": "long segment" }, "geometry": { "type": "LineString", "coordinates": [[0, 0], [6, 0]] } },
{ "type": "Feature", "properties": { "name": "inner segment" }, "geometry": { "type": "LineString", "coordinates": [[1, 0], [3, 0]] } }
]
}
7 changes: 7 additions & 0 deletions fixtures/nodify/input/collinear_overlap.geojson
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "FeatureCollection",
"features": [
{ "type": "Feature", "properties": { "name": "left-long" }, "geometry": { "type": "LineString", "coordinates": [[0, 0], [3, 0]] } },
{ "type": "Feature", "properties": { "name": "right-long" }, "geometry": { "type": "LineString", "coordinates": [[1, 0], [4, 0]] } }
]
}
7 changes: 7 additions & 0 deletions fixtures/nodify/input/duplicate_lines.geojson
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "FeatureCollection",
"features": [
{ "type": "Feature", "properties": { "name": "first copy" }, "geometry": { "type": "LineString", "coordinates": [[0, 0], [3, 0]] } },
{ "type": "Feature", "properties": { "name": "second copy" }, "geometry": { "type": "LineString", "coordinates": [[0, 0], [3, 0]] } }
]
}
7 changes: 7 additions & 0 deletions fixtures/nodify/input/multi_segment_linestring.geojson
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "FeatureCollection",
"features": [
{ "type": "Feature", "properties": { "name": "L-shape" }, "geometry": { "type": "LineString", "coordinates": [[0, 0], [3, 0], [3, 3]] } },
{ "type": "Feature", "properties": { "name": "crossing" }, "geometry": { "type": "LineString", "coordinates": [[1, -1], [1, 1]] } }
]
}
7 changes: 7 additions & 0 deletions fixtures/nodify/input/no_interaction.geojson
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "FeatureCollection",
"features": [
{ "type": "Feature", "properties": { "name": "lower" }, "geometry": { "type": "LineString", "coordinates": [[0, 0], [4, 0]] } },
{ "type": "Feature", "properties": { "name": "upper" }, "geometry": { "type": "LineString", "coordinates": [[0, 1], [4, 1]] } }
]
}
7 changes: 7 additions & 0 deletions fixtures/nodify/input/reversed_duplicate.geojson
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "FeatureCollection",
"features": [
{ "type": "Feature", "properties": { "name": "forward" }, "geometry": { "type": "LineString", "coordinates": [[0, 0], [3, 0]] } },
{ "type": "Feature", "properties": { "name": "backward" }, "geometry": { "type": "LineString", "coordinates": [[3, 0], [0, 0]] } }
]
}
7 changes: 7 additions & 0 deletions fixtures/nodify/input/shared_endpoint.geojson
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "FeatureCollection",
"features": [
{ "type": "Feature", "properties": { "name": "left segment" }, "geometry": { "type": "LineString", "coordinates": [[0, 0], [2, 0]] } },
{ "type": "Feature", "properties": { "name": "right segment" }, "geometry": { "type": "LineString", "coordinates": [[2, 0], [4, 0]] } }
]
}
7 changes: 7 additions & 0 deletions fixtures/nodify/input/simple_crossing.geojson
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "FeatureCollection",
"features": [
{ "type": "Feature", "properties": { "name": "horizontal" }, "geometry": { "type": "LineString", "coordinates": [[0, 0], [4, 0]] } },
{ "type": "Feature", "properties": { "name": "vertical" }, "geometry": { "type": "LineString", "coordinates": [[2, -2], [2, 2]] } }
]
}
8 changes: 8 additions & 0 deletions fixtures/nodify/input/star_crossings.geojson
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"type": "FeatureCollection",
"features": [
{ "type": "Feature", "properties": { "name": "horizontal" }, "geometry": { "type": "LineString", "coordinates": [[0, 2], [4, 2]] } },
{ "type": "Feature", "properties": { "name": "vertical" }, "geometry": { "type": "LineString", "coordinates": [[2, 0], [2, 4]] } },
{ "type": "Feature", "properties": { "name": "diagonal" }, "geometry": { "type": "LineString", "coordinates": [[0, 0], [4, 4]] } }
]
}
7 changes: 7 additions & 0 deletions fixtures/nodify/input/t_junction.geojson
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "FeatureCollection",
"features": [
{ "type": "Feature", "properties": { "name": "horizontal" }, "geometry": { "type": "LineString", "coordinates": [[0, 0], [4, 0]] } },
{ "type": "Feature", "properties": { "name": "vertical stem" }, "geometry": { "type": "LineString", "coordinates": [[2, 0], [2, 3]] } }
]
}
8 changes: 8 additions & 0 deletions fixtures/nodify/output/collinear_contained.geojson
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"type": "FeatureCollection",
"features": [
{ "type": "Feature", "properties": {}, "geometry": { "type": "LineString", "coordinates": [[0, 0], [1, 0]] } },
{ "type": "Feature", "properties": {}, "geometry": { "type": "LineString", "coordinates": [[1, 0], [3, 0]] } },
{ "type": "Feature", "properties": {}, "geometry": { "type": "LineString", "coordinates": [[3, 0], [6, 0]] } }
]
}
8 changes: 8 additions & 0 deletions fixtures/nodify/output/collinear_overlap.geojson
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"type": "FeatureCollection",
"features": [
{ "type": "Feature", "properties": {}, "geometry": { "type": "LineString", "coordinates": [[0, 0], [1, 0]] } },
{ "type": "Feature", "properties": {}, "geometry": { "type": "LineString", "coordinates": [[1, 0], [3, 0]] } },
{ "type": "Feature", "properties": {}, "geometry": { "type": "LineString", "coordinates": [[3, 0], [4, 0]] } }
]
}
6 changes: 6 additions & 0 deletions fixtures/nodify/output/duplicate_lines.geojson
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"type": "FeatureCollection",
"features": [
{ "type": "Feature", "properties": {}, "geometry": { "type": "LineString", "coordinates": [[0, 0], [3, 0]] } }
]
}
10 changes: 10 additions & 0 deletions fixtures/nodify/output/multi_segment_linestring.geojson
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"type": "FeatureCollection",
"features": [
{ "type": "Feature", "properties": {}, "geometry": { "type": "LineString", "coordinates": [[0, 0], [1, 0]] } },
{ "type": "Feature", "properties": {}, "geometry": { "type": "LineString", "coordinates": [[1, -1], [1, 0]] } },
{ "type": "Feature", "properties": {}, "geometry": { "type": "LineString", "coordinates": [[1, 0], [1, 1]] } },
{ "type": "Feature", "properties": {}, "geometry": { "type": "LineString", "coordinates": [[1, 0], [3, 0]] } },
{ "type": "Feature", "properties": {}, "geometry": { "type": "LineString", "coordinates": [[3, 0], [3, 3]] } }
]
}
7 changes: 7 additions & 0 deletions fixtures/nodify/output/no_interaction.geojson
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "FeatureCollection",
"features": [
{ "type": "Feature", "properties": {}, "geometry": { "type": "LineString", "coordinates": [[0, 0], [4, 0]] } },
{ "type": "Feature", "properties": {}, "geometry": { "type": "LineString", "coordinates": [[0, 1], [4, 1]] } }
]
}
6 changes: 6 additions & 0 deletions fixtures/nodify/output/reversed_duplicate.geojson
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"type": "FeatureCollection",
"features": [
{ "type": "Feature", "properties": {}, "geometry": { "type": "LineString", "coordinates": [[0, 0], [3, 0]] } }
]
}
7 changes: 7 additions & 0 deletions fixtures/nodify/output/shared_endpoint.geojson
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "FeatureCollection",
"features": [
{ "type": "Feature", "properties": {}, "geometry": { "type": "LineString", "coordinates": [[0, 0], [2, 0]] } },
{ "type": "Feature", "properties": {}, "geometry": { "type": "LineString", "coordinates": [[2, 0], [4, 0]] } }
]
}
9 changes: 9 additions & 0 deletions fixtures/nodify/output/simple_crossing.geojson
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"type": "FeatureCollection",
"features": [
{ "type": "Feature", "properties": {}, "geometry": { "type": "LineString", "coordinates": [[0, 0], [2, 0]] } },
{ "type": "Feature", "properties": {}, "geometry": { "type": "LineString", "coordinates": [[2, -2], [2, 0]] } },
{ "type": "Feature", "properties": {}, "geometry": { "type": "LineString", "coordinates": [[2, 0], [2, 2]] } },
{ "type": "Feature", "properties": {}, "geometry": { "type": "LineString", "coordinates": [[2, 0], [4, 0]] } }
]
}
11 changes: 11 additions & 0 deletions fixtures/nodify/output/star_crossings.geojson
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"type": "FeatureCollection",
"features": [
{ "type": "Feature", "properties": {}, "geometry": { "type": "LineString", "coordinates": [[0, 0], [2, 2]] } },
{ "type": "Feature", "properties": {}, "geometry": { "type": "LineString", "coordinates": [[0, 2], [2, 2]] } },
{ "type": "Feature", "properties": {}, "geometry": { "type": "LineString", "coordinates": [[2, 0], [2, 2]] } },
{ "type": "Feature", "properties": {}, "geometry": { "type": "LineString", "coordinates": [[2, 2], [2, 4]] } },
{ "type": "Feature", "properties": {}, "geometry": { "type": "LineString", "coordinates": [[2, 2], [4, 2]] } },
{ "type": "Feature", "properties": {}, "geometry": { "type": "LineString", "coordinates": [[2, 2], [4, 4]] } }
]
}
8 changes: 8 additions & 0 deletions fixtures/nodify/output/t_junction.geojson
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"type": "FeatureCollection",
"features": [
{ "type": "Feature", "properties": {}, "geometry": { "type": "LineString", "coordinates": [[0, 0], [2, 0]] } },
{ "type": "Feature", "properties": {}, "geometry": { "type": "LineString", "coordinates": [[2, 0], [2, 3]] } },
{ "type": "Feature", "properties": {}, "geometry": { "type": "LineString", "coordinates": [[2, 0], [4, 0]] } }
]
}
1 change: 1 addition & 0 deletions fixtures/polygonizer/input/buggy_outlines.geojson
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"LineString","coordinates":[[66.917152079,-49.483609955],[67.076757868,-49.04184243]]},"properties":null},{"type":"Feature","geometry":{"type":"LineString","coordinates":[[66.917152079,-49.483609955],[68.49003423,-50.548027294]]},"properties":null},{"type":"Feature","geometry":{"type":"LineString","coordinates":[[67.076757868,-49.04184243],[68.698823473,-48.144678001]]},"properties":null},{"type":"Feature","geometry":{"type":"LineString","coordinates":[[67.96072344674927,-49.21812840419421],[68.03560388863696,-49.526937060777]]},"properties":null},{"type":"Feature","geometry":{"type":"LineString","coordinates":[[67.96072344674927,-49.21812840419421],[68.03560388863696,-48.90931974761142]]},"properties":null},{"type":"Feature","geometry":{"type":"LineString","coordinates":[[68.03560388863696,-49.526937060777],[68.25291539492534,-49.80551737445704]]},"properties":null},{"type":"Feature","geometry":{"type":"LineString","coordinates":[[68.03560388863696,-48.90931974761142],[68.25291539492534,-48.63073943393138]]},"properties":null},{"type":"Feature","geometry":{"type":"LineString","coordinates":[[68.25291539492534,-49.80551737445704],[68.5913860012806,-50.02659996314815]]},"properties":null},{"type":"Feature","geometry":{"type":"LineString","coordinates":[[68.25291539492534,-48.63073943393138],[68.5913860012806,-48.40965684524027]]},"properties":null},{"type":"Feature","geometry":{"type":"LineString","coordinates":[[68.49003423,-50.548027294],[69.861979006,-50.549689302]]},"properties":null},{"type":"Feature","geometry":{"type":"LineString","coordinates":[[68.5913860012806,-50.02659996314815],[69.01788384648931,-50.16854372269627]]},"properties":null},{"type":"Feature","geometry":{"type":"LineString","coordinates":[[68.5913860012806,-48.40965684524027],[69.01788384648931,-48.26771308569215]]},"properties":null},{"type":"Feature","geometry":{"type":"LineString","coordinates":[[68.698823473,-48.144678001],[70.997703438,-47.154869247]]},"properties":null},{"type":"Feature","geometry":{"type":"LineString","coordinates":[[69.01788384648931,-50.16854372269627],[69.49066034987723,-50.21745420893651]]},"properties":null},{"type":"Feature","geometry":{"type":"LineString","coordinates":[[69.01788384648931,-48.26771308569215],[69.49066034987723,-48.21880259945191]]},"properties":null},{"type":"Feature","geometry":{"type":"LineString","coordinates":[[69.49066034987723,-50.21745420893651],[69.96343685326515,-50.16854372269627]]},"properties":null},{"type":"Feature","geometry":{"type":"LineString","coordinates":[[69.49066034987723,-48.21880259945191],[69.96343685326515,-48.26771308569215]]},"properties":null},{"type":"Feature","geometry":{"type":"LineString","coordinates":[[69.861979006,-50.549689302],[70.26289097957036,-50.06888168459346]]},"properties":null},{"type":"Feature","geometry":{"type":"LineString","coordinates":[[69.96343685326515,-50.16854372269627],[70.26289097957036,-50.06888168459346]]},"properties":null},{"type":"Feature","geometry":{"type":"LineString","coordinates":[[69.96343685326515,-48.26771308569215],[70.38993469847387,-48.40965684524027]]},"properties":null},{"type":"Feature","geometry":{"type":"LineString","coordinates":[[70.26289097957036,-50.06888168459346],[70.38993469847387,-50.02659996314815]]},"properties":null},{"type":"Feature","geometry":{"type":"LineString","coordinates":[[70.26289097957036,-50.06888168459346],[71.00971073191234,-49.17323214198215]]},"properties":null},{"type":"Feature","geometry":{"type":"LineString","coordinates":[[70.38993469847387,-50.02659996314815],[70.72840530482912,-49.80551737445704]]},"properties":null},{"type":"Feature","geometry":{"type":"LineString","coordinates":[[70.38993469847387,-48.40965684524027],[70.72840530482912,-48.63073943393138]]},"properties":null},{"type":"Feature","geometry":{"type":"LineString","coordinates":[[70.72840530482912,-49.80551737445704],[70.9457168111175,-49.526937060777]]},"properties":null},{"type":"Feature","geometry":{"type":"LineString","coordinates":[[70.72840530482912,-48.63073943393138],[70.9457168111175,-48.90931974761142]]},"properties":null},{"type":"Feature","geometry":{"type":"LineString","coordinates":[[70.9457168111175,-49.526937060777],[71.02059725300519,-49.21812840419421]]},"properties":null},{"type":"Feature","geometry":{"type":"LineString","coordinates":[[70.9457168111175,-48.90931974761142],[71.00971073191234,-49.17323214198215]]},"properties":null},{"type":"Feature","geometry":{"type":"LineString","coordinates":[[70.997703438,-47.154869247],[71.638389864,-47.695087312]]},"properties":null},{"type":"Feature","geometry":{"type":"LineString","coordinates":[[71.00971073191234,-49.17323214198215],[71.02059725300519,-49.21812840419421]]},"properties":null},{"type":"Feature","geometry":{"type":"LineString","coordinates":[[71.00971073191234,-49.17323214198215],[71.09668316,-49.068927435]]},"properties":null},{"type":"Feature","geometry":{"type":"LineString","coordinates":[[71.09668316,-49.068927435],[71.638389864,-47.695087312]]},"properties":null}]}
19 changes: 19 additions & 0 deletions fixtures/polygonizer/input/contained_island.geojson
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"type": "FeatureCollection",
"features": [
{ "type": "Feature", "properties": { "name": "outer bottom" }, "geometry": { "type": "LineString", "coordinates": [[0, 0], [20, 0]] } },
{ "type": "Feature", "properties": { "name": "outer right" }, "geometry": { "type": "LineString", "coordinates": [[20, 0], [20, 20]] } },
{ "type": "Feature", "properties": { "name": "outer top" }, "geometry": { "type": "LineString", "coordinates": [[20, 20], [0, 20]] } },
{ "type": "Feature", "properties": { "name": "outer left" }, "geometry": { "type": "LineString", "coordinates": [[0, 20], [0, 0]] } },

{ "type": "Feature", "properties": { "name": "hole bottom" }, "geometry": { "type": "LineString", "coordinates": [[3, 3], [10, 3]] } },
{ "type": "Feature", "properties": { "name": "hole right" }, "geometry": { "type": "LineString", "coordinates": [[10, 3], [10, 10]] } },
{ "type": "Feature", "properties": { "name": "hole top" }, "geometry": { "type": "LineString", "coordinates": [[10, 10], [3, 10]] } },
{ "type": "Feature", "properties": { "name": "hole left" }, "geometry": { "type": "LineString", "coordinates": [[3, 10], [3, 3]] } },

{ "type": "Feature", "properties": { "name": "island bottom" }, "geometry": { "type": "LineString", "coordinates": [[13, 13], [18, 13]] } },
{ "type": "Feature", "properties": { "name": "island right" }, "geometry": { "type": "LineString", "coordinates": [[18, 13], [18, 18]] } },
{ "type": "Feature", "properties": { "name": "island top" }, "geometry": { "type": "LineString", "coordinates": [[18, 18], [13, 18]] } },
{ "type": "Feature", "properties": { "name": "island left" }, "geometry": { "type": "LineString", "coordinates": [[13, 18], [13, 13]] } }
]
}
Loading
Loading