Skip to content
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

Add Bentley-Ottmann algorithm #1126

Open
juliohm opened this issue Nov 9, 2024 · 0 comments
Open

Add Bentley-Ottmann algorithm #1126

juliohm opened this issue Nov 9, 2024 · 0 comments
Labels
feature help wanted Extra attention is needed performance

Comments

@juliohm
Copy link
Member

juliohm commented Nov 9, 2024

The Bentley-Ottmann algorithm is a sweep-line algorithm for efficient pairwise segment-segment intersection in 2D space: https://youtu.be/nNtiZM-j3Pk?si=bwPt-btl2S0Ps8oO

I've started implementing this algorithm, but got stuck due to limitations in the AVLTree of the DataStructures.jl package. Below is the draft for future reference, in case someone finds the time to finish it up:

using Meshes
using DataStructures

"""
    bentleyottmann(segments)

Compute pairwise intersections between n `segments`
in O(n⋅log(n)) time using Bentley-Ottmann sweep line
algorithm.
"""
function bentleyottmann(segments)
  # adjust vertices of segments
  segs = map(segments) do s
    a, b = extrema(s)
    a > b ? reverse(s) : s
  end

  # retrieve relevant info
  s = first(segs)
  p = minimum(s)
  P = typeof(p)
  S = Tuple{P,P}

  # initialization
  𝒬 = AVLTree{P}()
  𝒯 = AVLTree{S}()
  ℒ = Dict{P,Vector{S}}()
  𝒰 = Dict{P,Vector{S}}()
  𝒞 = Dict{P,Vector{S}}()
  for s in segs
    a, b = extrema(s)
    push!(𝒬, a)
    push!(𝒬, b)
    haskey(ℒ, a) ? push!(ℒ[a], (a, b)) : (ℒ[a] = [(a, b)])
    haskey(𝒰, b) ? push!(𝒰[b], (a, b)) : (𝒰[b] = [(a, b)])
    haskey(ℒ, b) || (ℒ[b] = S[])
    haskey(𝒰, a) || (𝒰[a] = S[])
    haskey(𝒞, a) || (𝒞[a] = S[])
    haskey(𝒞, b) || (𝒞[b] = S[])
  end
  m = Point(-Inf, -Inf)
  M = Point(Inf, Inf)
  push!(𝒯, (m, m))
  push!(𝒯, (M, M))

  # sweep line
  I = Dict{P,Vector{S}}()
  while length(𝒬) > 0
    p = 𝒬[1]
    delete!(𝒬, p)
    handle!(I, p, 𝒬, 𝒯, ℒ, 𝒰, 𝒞)
  end
  I
end

function handle!(I, p, 𝒬, 𝒯, ℒ, 𝒰, 𝒞)
  ss = ℒ[p]  𝒰[p]  𝒞[p]
  if length(ss) > 1
    I[p] = ss
  end
  for s in ℒ[p]  𝒞[p]
    delete!(𝒯, s)
  end
  for s in 𝒰[p]  𝒞[p]
    push!(𝒯, s)
  end
  if length(𝒰[p]  𝒞[p]) == 0
    # n = search_node(𝒯, p)
  else
  end
end

We finished writing a better AVLTree in BinaryTrees.jl that is already registered: https://github.com/JuliaCollections/BinaryTrees.jl

Ideally, we can finish up the algorithm above with this new dependency instead.

The result of this function could be used in clipping algorithms such as the one in #1125.

cc: @souma4

@juliohm juliohm added help wanted Extra attention is needed performance feature labels Nov 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature help wanted Extra attention is needed performance
Projects
None yet
Development

No branches or pull requests

1 participant