Search code examples
algorithmmathluapolygons

Bentley-Ottmann Algorithm in Lua


I'm implementing the Bentley-Ottmann Algorithm in Lua for finding intersecting points in a polygon using the pseudo code located here.

I'm relatively new to implementing algorithms so I couldn't understand all parts of it. Here's my code so far:

local function getPolygonIntersectingVertices( poly )
  -- initializing and sorting X
  local X = {}
  for i = 1, table.getn( poly ) do
    if i == 1 then
      table.insert( X, { x = poly[i].x, y = poly[i].y, endpoint = 'left' } )
    elseif i == table.getn( poly ) then
      table.insert( X, { x = poly[i].x, y = poly[i].y, endpoint = 'right' } )
    else
      table.insert( X, { x = poly[i].x, y = poly[i].y, endpoint = 'right' })
      table.insert( X, { x = poly[i].x, y = poly[i].y, endpoint = 'left' })
    end
  end

  local sortxy = function( a, b )
    if a.x < b.x then return true
    elseif a.x > b.x then return false
    elseif a.y <= b.y then return true
    else return false end
  end
  table.sort( X, sortxy )

  -- Main loop
  local SL = {}
  local L = {}
  local E
  local i = 1
  while next(X) ~= nil do
    E = { x = X[i].x, y = X[i].y, endpoint = X[i].endpoint }
    if E.endpoint == 'left' then
      -- left endpoint code here
    elseif E.endpoint == 'right' then
      -- right endpoint code here
    else
    end
    table.remove( X, i )
  end

  return L
end

My polygon is a table using this structure: { { x = 1, y = 3 }, { x = 5, y = 6 }, ... }

How do I determine "the segment above segE in SL;" and "the segment below segE in SL;" and what to do if the sweep line (SL) is empty? Also when inserting I into X, should I mark it with endpoint = 'intersect' and append it to the end so when the loop comes to this part goes into the "else" statement of the main loop or I've got the whole algorithm wrong?

It would be perfect in someone can show me a link with a simple implementation in Python, Ruby, etc. as I find it hard to follow the pseudo code and match it with the C++ example.


Solution

  • Your reference link fails from my location. I will reference the Wikipedia article, which is reasonably good.

    How do I determine "the segment above segE in SL;" and "the segment below segE in SL;"

    The algorithm requires a BST for current scan line intersections sorted on a key of y, i.e. in order vertically. So the segment above is the BST successor and the one below is the BST predecessor. Finding the predecessor and successor of a given node in a BST is standard stuff. The predecessor of key K is the rightmost node left of K. The successor is the leftmost node right of K. There are several ways of computing these. The simplest is to use parent pointers to walk back up and then down the tree from K. A stack-based iterator is another.

    what to do if the sweep line (SL) is empty?

    Keep processing the event queue. An empty sweep line just means no segments are crossing at its current x location.

    Also when inserting I into X, should I mark it with endpoint = 'intersect' and append it to the end ...?

    The event queue must remain sorted on the x-coordinate of points. When you insert an intersection it must be in x-coordinate order, too. It must be marked as an intersection because intersections are processed differently from endpoints. It will be processed in due course when it's the first remaining item in x order.

    Note that Bentley Ottman - just as nearly all geometric algorithms - is notoriously subject to horrendous failures due to floating point inaccuracy. Also, the algorithm is normally given with a "general position" assumption, which lets out all the nasty cases of vertical edges, point-edge coincidence, edge-edge overlaps, etc. My strongest recommendation is to use rational arithmetic. Even then, getting a fully robust, correct implementation is a significant achievement. You can tell this by the very small number of free implementations!