-
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
Merged
Merged
Changes from 5 commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
da20a78
new PR for line segment intersections. Simpler, not quite as efficien…
souma4 8aa5cfc
add tests
souma4 7f19f82
update utils.jl to include intersect
souma4 35a062b
update names to intervalsweep since this is no longer 'true' bentley-…
souma4 746382a
add test for coverage when segments stop overlapping
souma4 174ff95
incorporated review feedback. sweep1D is a descriptive name and leave…
souma4 63a26f9
sweep1D doesn't update the initial queue.
souma4 03e407a
simplified implementation, no new structs, moved from sets of indices…
souma4 e8b8585
consolidated code, cleaned up names, removed maps, improved type stab…
souma4 744189e
disolve _checkintersection function and change P definition
souma4 a07ddbc
basic cleanup
juliohm 5a290df
minor cleanup
souma4 d381b5d
fixed addintersection. it gets I
souma4 efc65c4
split out the for loops because continue for inline double for loops …
souma4 a79e599
no need for continue
souma4 d401576
Basic cleanup
juliohm 28a7f8a
Basic cleanup
juliohm 1939484
Improve docstring
juliohm 9a746e2
Refactor tests
juliohm ad49ebc
improved docstring and edited @inferred test
souma4 4dab40a
Adjust type of key in dictionary of intersections
juliohm File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,111 @@ | ||
| # ------------------------------------------------------------------ | ||
| # Licensed under the MIT License. See LICENSE in the project root. | ||
| # ------------------------------------------------------------------ | ||
|
|
||
| """ | ||
| intervalsweep(segments; [digits]) | ||
| Compute pairwise intersections between n `segments` | ||
| with `digits` precision in O(n⋅log(n+k)) time using | ||
|
||
| an x-interval sweep line algorithm. Similar to an optimal | ||
souma4 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| Bentley-Ottmann algorithm in sparse systems, and closer to O(n²) in dense systems. | ||
souma4 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| 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 intervalsweep(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 | ||
| 𝒮 = SweepLineQueue(segs) | ||
|
|
||
| points, seginds = handle!(𝒮; digits=digits) | ||
souma4 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| end | ||
|
|
||
| # # compute the number of significant digits based on the segment type | ||
| # # this is used to determine the precision of the points | ||
souma4 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| 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 | ||
|
|
||
| # ---------------- | ||
| # DATA STRUCTURES | ||
| # ---------------- | ||
|
|
||
| struct SweepLineInterval{T<:Number} | ||
| start::T | ||
| stop::T | ||
| segment::Any | ||
| index::Int | ||
| end | ||
|
|
||
| struct SweepLineQueue | ||
| intervals::Vector{SweepLineInterval} | ||
| end | ||
| Base.length(𝒮::SweepLineQueue) = length(𝒮.intervals) | ||
| Base.getindex(𝒮::SweepLineQueue, i::Int) = 𝒮.intervals[i] | ||
|
|
||
| function SweepLineQueue(segs::Vector{<:Tuple{Point,Point}}) | ||
| intervals = Vector{SweepLineInterval}() | ||
| for (i, seg) in enumerate(segs) | ||
| x₁, _ = CoordRefSystems.values(coords(seg[1])) | ||
| x₂, _ = CoordRefSystems.values(coords(seg[2])) | ||
| push!(intervals, SweepLineInterval(min(x₁, x₂), max(x₁, x₂), seg, i)) | ||
| end | ||
| SweepLineQueue(sort!(intervals, by=s -> s.start)) | ||
| end | ||
souma4 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| function overlaps(i₁::SweepLineInterval, i₂::SweepLineInterval) | ||
| i₁.start ≤ i₂.start && i₂.stop ≥ i₁.start | ||
| end | ||
souma4 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| # ---------------- | ||
| # SWEEP LINE HANDLER | ||
| # ---------------- | ||
|
|
||
| """ | ||
| handle!(𝒮::SweepLineQueue) | ||
| Iterate through the sweep line queue and compute all intersection points | ||
| between overlapping intervals. Returns a tuple of intersection points and | ||
| the sets of segment indices that intersect at each point. | ||
| """ | ||
| function handle!(𝒮::SweepLineQueue; digits=10) | ||
souma4 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| 𝐺 = Dict{Point,Set{Int}}() | ||
| n = length(𝒮) | ||
| for i in 1:n | ||
| current = 𝒮[i] | ||
| for k in (i + 1):n | ||
| candidate = 𝒮[k] | ||
| # If the intervals no longer overlap, break out of the inner loop | ||
| if !overlaps(current, candidate) | ||
| break | ||
| end | ||
| # Check if the segments actually intersect | ||
| I = intersection(Segment(current.segment), Segment(candidate.segment)) do 𝑖 | ||
| t = type(𝑖) | ||
| (t === Crossing || t === EdgeTouching) ? get(𝑖) : nothing | ||
| end | ||
| isnothing(I) || _addintersection!(𝐺, I, current.index, candidate.index; digits=digits) | ||
| end | ||
| end | ||
| (collect(keys(𝐺)), collect(values(𝐺))) | ||
| end | ||
| function _addintersection!(𝐺::Dict{Point,Set{Int}}, I::Point, index₁::Int, index₂::Int; digits=10) | ||
| p = coordround(I, digits=digits) | ||
| if haskey(𝐺, p) | ||
| union!(𝐺[p], index₁) | ||
| union!(𝐺[p], index₂) | ||
| else | ||
| 𝐺[p] = Set([index₁, index₂]) | ||
| end | ||
| end | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.