-
Notifications
You must be signed in to change notification settings - Fork 95
Add pairwise intersection between segments with sweep-line algorithm #1251
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
Changes from 11 commits
da20a78
8aa5cfc
7f19f82
35a062b
746382a
174ff95
63a26f9
03e407a
e8b8585
744189e
a07ddbc
5a290df
d381b5d
efc65c4
a79e599
d401576
28a7f8a
1939484
9a746e2
ad49ebc
4dab40a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| # ------------------------------------------------------------------ | ||
| # Licensed under the MIT License. See LICENSE in the project root. | ||
| # ------------------------------------------------------------------ | ||
|
|
||
| """ | ||
| pairwiseintersect(segments; [digits]) | ||
| Compute pairwise intersections between n `segments` | ||
| with `digits` precision in O(n⋅log(n+k)) time using | ||
| a sweep line algorithm. Similar to an optimal | ||
| Bentley-Ottmann algorithm in sparse systems, | ||
| and closer to O(n²) in dense systems. | ||
| By default, set `digits` based on the absolute | ||
| tolerance of the length type of the segments. | ||
| ## References | ||
| * Bentley & Ottmann 1979. [Algorithms for reporting and counting | ||
| geometric intersections](https://ieeexplore.ieee.org/document/1675432) | ||
| """ | ||
| function pairwiseintersect(segments; digits=_digits(segments)) | ||
| # orient segments and round coordinates | ||
| segs = map(segments) do seg | ||
| a, b = coordround.(extrema(seg), digits=digits) | ||
| a > b ? (b, a) : (a, b) | ||
| end | ||
|
|
||
| starts = [CoordRefSystems.values(coords(seg[1]))[1] for seg in segs] | ||
| stops = [CoordRefSystems.values(coords(seg[2]))[1] for seg in segs] | ||
|
|
||
| # sort segments based on start coordinates | ||
| inds = sortperm(starts) | ||
| starts = starts[inds] | ||
| stops = stops[inds] | ||
| segs = segs[inds] | ||
|
|
||
| # keep track of original indices | ||
| n = length(segs) | ||
| oldindices = (1:n)[inds] | ||
|
||
|
|
||
| # sweepline algorithm | ||
| P = eltype(first(segs)) | ||
juliohm marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| 𝐺 = Dict{P,Vector{Int}}() | ||
| for i in eachindex(segs) | ||
| for j in (i + 1):length(segs) | ||
| _overlaps(starts[i], stops[i], starts[j]) || break | ||
|
|
||
| I = intersection(Segment(segs[i]), Segment(segs[j])) do 𝑖 | ||
| t = type(𝑖) | ||
| (t === Crossing || t === EdgeTouching) ? get(𝑖) : nothing | ||
| end | ||
|
|
||
| # continue if no intersection, add intersection otherwise | ||
| if isnothing(I) | ||
| continue | ||
| else | ||
| _addintersection!(𝐺, I, oldindices[i], oldindices[j]; digits=digits) | ||
| end | ||
juliohm marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| end | ||
| end | ||
| (collect(keys(𝐺)), collect(values(𝐺))) | ||
| end | ||
|
|
||
| _overlaps(startᵢ, stopᵢ, startₖ) = (startᵢ ≤ startₖ ≤ stopᵢ) | ||
|
|
||
| # compute the number of significant digits based on the segment type | ||
| # this is used to determine the precision of the points | ||
| function _digits(segments) | ||
| seg = first(segments) | ||
| ℒ = lentype(seg) | ||
| τ = ustrip(eps(ℒ)) | ||
| round(Int, 0.8 * (-log10(τ))) # 0.8 is a heuristic to avoid numerical issues | ||
| end | ||
|
|
||
| # add an intersection point to the dictionary with segment indices | ||
| function _addintersection!(𝐺, I::Point, index₁::Int, index₂::Int; digits=10) | ||
| p = coordround(I, digits=digits) | ||
| if haskey(𝐺, p) | ||
| append!(𝐺[p], (index₁, index₂)) | ||
| unique!(𝐺[p]) | ||
| else | ||
| 𝐺[p] = Vector{Int}([index₁, index₂]) | ||
| end | ||
| end | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to define
kin the docstring