Skip to content

Conversation

@souma4
Copy link
Contributor

@souma4 souma4 commented Jan 11, 2026

In line with feedback in #1318 here is an initial small PR that adds a shell for the broader algorithm and the first necessary step for this algorithm - which is to compute and insert intersections into polygons.

I'm also adding a utility that's used through the algorithm to take a 4 bit number marking whether a segment has a subject or clipping polygon above or below it.

These are small, simple internals that should be easy to review.

The next PR will be taking these modified polygons and performing a sweep line to fill in those segment region fills.

Edit: current failing test is pairwiseintersect, which hasn't been changed.

@github-actions
Copy link
Contributor

github-actions bot commented Jan 11, 2026

Benchmark Results (Julia v1)

Time benchmarks
master 9f05a2a... master / 9f05a2a...
clipping/SutherlandHodgman 2.6 ± 0.23 μs 2.6 ± 0.21 μs 1 ± 0.12
discretization/simplexify 0.381 ± 0.019 ms 0.387 ± 0.019 ms 0.984 ± 0.069
intersection/ray-triangle 0.05 ± 0.001 μs 0.05 ± 0.01 μs 1 ± 0.2
sideof/ring/large 6.84 ± 0.011 μs 6.85 ± 0.061 μs 0.999 ± 0.009
sideof/ring/small 0.06 ± 0 μs 0.06 ± 0 μs 1 ± 0
topology/half-edge 2.77 ± 0.23 ms 2.7 ± 0.12 ms 1.03 ± 0.096
winding/mesh 15.4 ± 0.29 ms 15.3 ± 0.26 ms 1 ± 0.026
time_to_load 1.45 ± 0.0091 s 1.46 ± 0.0058 s 0.992 ± 0.0074
Memory benchmarks
master 9f05a2a... master / 9f05a2a...
clipping/SutherlandHodgman 0.064 k allocs: 5.55 kB 0.064 k allocs: 5.55 kB 1
discretization/simplexify 0.0362 M allocs: 1.93 MB 0.0362 M allocs: 1.93 MB 1
intersection/ray-triangle 0 allocs: 0 B 0 allocs: 0 B
sideof/ring/large 0 allocs: 0 B 0 allocs: 0 B
sideof/ring/small 0 allocs: 0 B 0 allocs: 0 B
topology/half-edge 25.9 k allocs: 3.17 MB 25.9 k allocs: 3.17 MB 1
winding/mesh 0.0413 M allocs: 3.08 MB 0.0413 M allocs: 3.08 MB 1
time_to_load 0.145 k allocs: 11 kB 0.145 k allocs: 11 kB 1

@github-actions
Copy link
Contributor

github-actions bot commented Jan 11, 2026

Benchmark Results (Julia vlts)

Time benchmarks
master 9f05a2a... master / 9f05a2a...
clipping/SutherlandHodgman 3.72 ± 0.24 μs 3.7 ± 0.14 μs 1.01 ± 0.076
discretization/simplexify 0.659 ± 0.092 ms 0.652 ± 0.1 ms 1.01 ± 0.21
intersection/ray-triangle 0.05 ± 0.01 μs 0.05 ± 0.01 μs 1 ± 0.28
sideof/ring/large 6.53 ± 0.01 μs 6.53 ± 0.01 μs 1 ± 0.0022
sideof/ring/small 0.05 ± 0.001 μs 0.05 ± 0.001 μs 1 ± 0.028
topology/half-edge 2.7 ± 0.043 ms 2.77 ± 0.077 ms 0.973 ± 0.031
winding/mesh 16.1 ± 0.31 ms 16.2 ± 0.27 ms 0.996 ± 0.025
time_to_load 1.48 ± 0.01 s 1.48 ± 0.0038 s 0.997 ± 0.0074
Memory benchmarks
master 9f05a2a... master / 9f05a2a...
clipping/SutherlandHodgman 0.053 k allocs: 4.97 kB 0.053 k allocs: 4.97 kB 1
discretization/simplexify 18.1 k allocs: 1.92 MB 18.1 k allocs: 1.92 MB 1
intersection/ray-triangle 0 allocs: 0 B 0 allocs: 0 B
sideof/ring/large 0 allocs: 0 B 0 allocs: 0 B
sideof/ring/small 0 allocs: 0 B 0 allocs: 0 B
topology/half-edge 18.1 k allocs: 2.92 MB 18.1 k allocs: 2.92 MB 1
winding/mesh 23.2 k allocs: 3.08 MB 23.2 k allocs: 3.08 MB 1
time_to_load 0.153 k allocs: 14.5 kB 0.153 k allocs: 14.5 kB 1

Comment on lines +5 to +6
# insert intersection points into rings
function _insertintersections!(intersections, seginds, allrings)
Copy link
Member

Choose a reason for hiding this comment

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

So is this function reimplementing Base.splice!? If you take the vertices(ring) as a CircularVector, you should be able to splice multiple points efficiently.

Copy link
Contributor Author

@souma4 souma4 Jan 12, 2026

Choose a reason for hiding this comment

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

CircularVector does not have a splice! method (weirdly). insert! also doesn't update the size of CircularVector until after insertion, which means it places points at the beginning of the vector. If we add multiple points to the end (e.g., the final segment of a poly has multiple intersections), their order gets reversed. Append is much cleaner.
The other key part here is making sure the right points go into the right rings in the right orientation. This means the checking of ps and pe, the sorting, etc, are necessary to keep proper geometry.

Copy link
Member

Choose a reason for hiding this comment

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

Should we open a PR in CircularArrays.jl to add splice! support?

"""
polygonbooleanop(geometry, other, operation)

Performs boolean `operation` of `geometry` with `other`.
Copy link
Member

Choose a reason for hiding this comment

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

Can the algorithm be used with any kind of geometry or just polygons (and their rings)?

Copy link
Contributor Author

@souma4 souma4 Jan 12, 2026

Choose a reason for hiding this comment

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

as of right now, polygons and rings, but in the future polygon-segment and segment-polygon should be added. I'll knock these down to polygon/ring for the time being.

Comment on lines 64 to 67
Base.union(a::Geometry, b::Geometry) = polygonbooleanop(a, b, union)
Base.setdiff(a::Geometry, b::Geometry) = polygonbooleanop(a, b, setdiff)
Base.symdiff(a::Geometry, b::Geometry) = polygonbooleanop(a, b, symdiff)
Base.xor(a::Geometry, b::Geometry) = polygonbooleanop(a, b, symdiff)
Copy link
Member

Choose a reason for hiding this comment

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

I believe the dispatch should be done with Polygon instead of general Geometry given the name of the function used in the implementation.

Also, please move these definitions to the source file where the Polygon is defined.

Copy link
Member

Choose a reason for hiding this comment

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

And the docstrings should be attached to these specific methods. You are currently adding docstrings to the function name, not the method.

Copy link
Member

@juliohm juliohm left a comment

Choose a reason for hiding this comment

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

It is not very clear what this PR is trying to accomplish. I can review it again after you consider the first round of comments.

…Fixing method dispatch for polygonbooleanop! on polygons.
@souma4
Copy link
Contributor Author

souma4 commented Jan 12, 2026

It is not very clear what this PR is trying to accomplish. I can review it again after you consider the first round of comments.

The primary goal is build a rough shell of the polygonboolean operation and implement the first major feature, which is splitting segments at intersections and inserting those into the polygon.

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

Successfully merging this pull request may close these issues.

2 participants