Skip to content

fix(polygonize): Migrate edge storage from Array to Map for performance - #3081

Merged
mfedderly merged 3 commits into
masterfrom
mf/polygonize-edges-map
Jun 26, 2026
Merged

fix(polygonize): Migrate edge storage from Array to Map for performance#3081
mfedderly merged 3 commits into
masterfrom
mf/polygonize-edges-map

Conversation

@mfedderly

@mfedderly mfedderly commented Jun 26, 2026

Copy link
Copy Markdown
Collaborator

A follow on update to #3074, working towards #3045

This migrates edge storage to Map<Node, Map<Node, Edge>> which lets us look up an edge directly by its nodes.

Maps are slightly slower to iterate than arrays, so this is a bit of a regression from the performance achieved in #3074, but is faster than the original version before that PR. Our test data only has one complex input geometry, and that performance is about doubled by this PR vs the #3074 version. We're trading slight slowness on the simple cases that are already quite fast for much better performance in the cases that are actually slow.

Using a Map here instead of a Set sets us up nicely for the last PR which will prevent inserting duplicate edges. We need the map to look up any existing edges directly. I also noticed that the duplicate accounting for Nodes isn't really needed, we can get away with just iterating the index version. This is a slight speedup in all cases by avoiding the double storage.

The test outputs are visually identical, but changed the ordering slightly because the iteration order changes (they were previously ordered entirely by insertion order, but now they are ordered by to insertion order and then from)

before
complex x 2,425 ops/sec ±0.63% (98 runs sampled)
cutedge x 186,505 ops/sec ±0.30% (95 runs sampled)
dangle x 335,310 ops/sec ±0.27% (100 runs sampled)
kinked-linestring x 258,189 ops/sec ±0.41% (98 runs sampled)
linestrings x 184,092 ops/sec ±0.49% (96 runs sampled)
multi-linestring x 315,983 ops/sec ±0.20% (97 runs sampled)
two-polygons x 193,986 ops/sec ±0.29% (93 runs sampled)

after #3074
complex x 4,323 ops/sec ±0.54% (97 runs sampled)
cutedge x 258,635 ops/sec ±0.25% (100 runs sampled)
dangle x 500,764 ops/sec ±0.24% (100 runs sampled)
kinked-linestring x 367,662 ops/sec ±0.22% (100 runs sampled)
linestrings x 274,570 ops/sec ±0.21% (100 runs sampled)
multi-linestring x 445,724 ops/sec ±0.38% (97 runs sampled)
two-polygons x 250,375 ops/sec ±0.31% (100 runs sampled)

after #3081
complex x 9,545 ops/sec ±0.36% (96 runs sampled)
cutedge x 227,484 ops/sec ±0.45% (98 runs sampled)
dangle x 437,344 ops/sec ±0.21% (101 runs sampled)
kinked-linestring x 305,488 ops/sec ±0.17% (99 runs sampled)
linestrings x 245,169 ops/sec ±0.24% (99 runs sampled)
multi-linestring x 379,647 ops/sec ±0.19% (99 runs sampled)
two-polygons x 214,679 ops/sec ±0.19% (99 runs sampled)

@mfedderly mfedderly added this to the v7.4 milestone Jun 26, 2026
Comment on lines +118 to +132
// add the forward edge
let toMap = this.edges.get(from);
if (toMap == null) {
toMap = new Map();
this.edges.set(from, toMap);
}
toMap.set(to, edge);

// add the symmetric edge
let symToMap = this.edges.get(to);
if (symToMap == null) {
symToMap = new Map();
this.edges.set(to, symToMap);
}
symToMap.set(from, symetricEdge);

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This block actually implicitly deduplicates edges as they're inserted. We'll create a new edge and clobber the previous edge with the same (to, from) Nodes.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After a bit more research, the Edge constructor modifies the passed-in Node objects. That means that merely creating an Edge will still cause the bug that #3045 set out to address.

@mfedderly
mfedderly merged commit 9622dbd into master Jun 26, 2026
5 checks passed
@mfedderly
mfedderly deleted the mf/polygonize-edges-map branch June 26, 2026 18:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant