Bentley-Ottmann Algorithm in Lua - algorithm

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.

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!

Related

Searching a 3D array for closest point satisfying a certain predicate

I'm looking for an enumeration algorithm to search through a 3D array "sphering" around a given starting point.
Given an array a of size NxNxN where each N is 2^k for some k, and a point p in that array. The algorithm I'm looking for should do the following: If a[p] satisfies a certain predicate, the algorithm stops and p is returned. Otherwise the next point q is checked, where q is another point in the array that is the closest to p and hasn't been visited yet. If that doesn't match either, the next q'is checked an so on until in the worst case the whole array has been searched.
By "closest" here the perfect solution would be the point q that has the smallest Euclidean distance to p. As only discrete points have to be considered, perhaps some clever enumeration algorithm woukd make that possible. However, if this gets too complicated, the smallest Manhattan distance would be fine too. If there are several nearest points, it doesn't matter which one should be considered next.
Is there already an algorithm that can be used for this task?
You can search for increasing squared distances, so you won't miss a point. This python code should make it clear:
import math
import itertools
# Calculates all points at a certain distance.
# Coordinate constraint: z <= y <= x
def get_points_at_squared_euclidean_distance(d):
result = []
x = int(math.floor(math.sqrt(d)))
while 0 <= x:
y = x
while 0 <= y:
target = d - x*x - y*y
lower = 0
upper = y + 1
while lower < upper:
middle = (lower + upper) / 2
current = middle * middle
if current == target:
result.append((x, y, middle))
break
if current < target:
lower = middle + 1
else:
upper = middle
y -= 1
x -= 1
return result
# Creates all possible reflections of a point
def get_point_reflections(point):
result = set()
for p in itertools.permutations(point):
for n in range(8):
result.add((
p[0] * (1 if n % 8 < 4 else -1),
p[1] * (1 if n % 4 < 2 else -1),
p[2] * (1 if n % 2 < 1 else -1),
))
return sorted(result)
# Enumerates all points around a center, in increasing distance
def get_next_point_near(center):
d = 0
points_at_d = []
while True:
while not points_at_d:
d += 1
points_at_d = get_points_at_squared_euclidean_distance(d)
point = points_at_d.pop()
for reflection in get_point_reflections(point):
yield (
center[0] + reflection[0],
center[1] + reflection[1],
center[2] + reflection[2],
)
# The function you asked for
def get_nearest_point(center, predicate):
for point in get_next_point_near(center):
if predicate(point):
return point
# Example usage
print get_nearest_point((1,2,3), lambda p: sum(p) == 10)
Basically you consume points from the generator until one of them fulfills your predicate.
This is pseudocode for a simple algorithm that will search in increasing-radius spherical husks until it either finds a point or it runs out of array. Let us assume that condition returns either true or false and has access to the x, y, z coordinates being tested and the array itself, returning false (instead of exploding) for out-of-bounds coordinates:
def find_from_center(center, max_radius, condition) returns a point
let radius = 0
while radius < max_radius,
let point = find_in_spherical_husk(center, radius, condition)
if (point != null) return point
radius ++
return null
the hard part is inside find_in_spherical_husk. We are interested in checking out points such that
dist(center, p) >= radius AND dist(center, p) < radius+1
which will be our operating definition of husk. We could iterate over the whole 3D array in O(n^3) looking for those, but that would be really expensive in terms of time. A better pseudocode is the following:
def find_in_spherical_husk(center, radius, condition)
let z = center.z - radius // current slice height
let r = 0 // current circle radius; maxes at equator, then decreases
while z <= center + radius,
let z_center = (z, center.x, point.y)
let point = find_in_z_circle(z_center, r)
if (point != null) return point
// prepare for next z-sliced cirle
z ++
r = sqrt(radius*radius - (z-center.z)*(z-center.z))
the idea here is to slice each husk into circles along the z-axis (any axis will do), and then look at each slice separately. If you were looking at the earth, and the poles were the z axis, you would be slicing from north to south. Finally, you would implement find_in_z_circle(z_center, r, condition) to look at the circumference of each of those circles. You can avoid some math there by using the Bresenham circle-drawing algorithm; but I assume that the savings are negligible compared with the cost of checking condition.

Merge collided bodies as one

I'm working on some Physics stuff in Javascript and basically want to handle collided bodies as one.
I've got an array of all the collisions that occur, a collision consists of two bodies, body A and body B.
Let's say six collision occur, collisions between bodies:
X and Y
Y and Z
C and D
E and F
F and H
G and H
Now I want to merge all the bodies that are in some way connected into a single body. I want those merged bodies in a list. For example in this case I'd want a list that looks like this:
X, Y and Z (Because X collided with Y and Y collided with Z)
C and D (Because C collided with D)
E, F, G and H (Because E collided with F, F with H, and G with H)
Now I'm pretty sure there's some algorithm out there that I need, I just don't know where to look and I'm out of ideas to solve this myself.
How would you do this in real life?
I suppose I would read each rule. For each rule, I'd connect the two pieces. What I'd end up with is a collection of blobs. I could then walk each of the graphs to get the list of nodes in each one. Each "connected component" would be a "blob". Formalizing this algorithm a bit might give this:
// make the graph of connected components
nodes = map<symbol, pair<symbol, list<symbol>>>
for each (a, b) in rules do
if nodes[a] is null then nodes[a] = node(a, [b])
else nodes[a].connections.append(b)
if nodes[b] is null then nodes[b] = node(b, [a])
else nodes[b].connections.append(a)
loop
blobs = map<symbol, list<symbol>>
for each (a, b) in rules do
firstNode = nodes[a]
// do a DFS/BFS search starting from firstNode to find
// all nodes in the connected component. whenever you
// follow a link from a node, remove it from the node's
// list of links. this prevents ever searching from that
// node again since we know what component it's in already
// add each node to the list of symbols in blobs[a]
loop
In the first loop, we read each rule once, then do a constant amount of work, so it is O(n) time in the number of rules. It will store two connections for each rule and so is O(n) storage in terms of the number of rules.
In the second loop, we look at each rule and do a DFS or BFS for each rule's LHS symbol. However, note that the searches will only traverse any edge once, and so this is O(n) time in the number of rules. We will end up with some set of blobs the union of whose lists will be the set of symbols which is no more than the number of rules, so it's O(n) storage as well.
So we have an O(n) time, O(n) space complexity algorithm for determining the blobs. Can we do better, asymptotically speaking? Clearly we need to look at all n rules, so the time complexity is optimal. Also note that any solution to this problem must say for each symbol which blob that symbol ends up belonging to, so simply writing the answer down on the output tape takes O(n) space. So this should be optimal as well.
If you have an ADT (in this case a map) that contains all objects and you keep parent id to track object collisions you can handle each collision+merge in constant time.
// setup
var X = {id: 1, name:'X'};
var Y = {id: 2, name:'Y'};
var Z = {id: 3, name:'Z'};
var C = {id: 4, name:'C'};
var D = {id: 5, name:'D'};
var E = {id: 6, name:'E'};
var F = {id: 7, name:'F'};
var G = {id: 8, name:'G'};
var H = {id: 9, name:'H'};
var all = { 1:X, 2:Y, 3:Z, 4:C, 5:D, 6:E, 7:F, 8:G, 9:H };
// method to merge collided objects together
function collision(obj1, obj2) {
var p1 = obj1.parent;
var p2 = obj2.parent;
if(p1 === undefined && p2 === undefined) {
obj1.parent = obj1.id;
obj2.parent = obj1.id;
obj1.name += obj2.name;
delete all[obj2.id];
} else if(p1 !== undefined && p2 === undefined) {
obj2.parent = obj1.parent;
all[obj1.parent].name += obj2.name;
delete all[obj2.id];
} else if(p1 === undefined && p2 !== undefined) {
obj1.parent = obj2.parent;
all[obj2.parent].name += obj1.name;
delete all[obj1.id];
} else if(p1 !== undefined && p2 !== undefined && obj1.parent !== obj2.parent) {
if(all[obj1.parent] !== undefined) {
all[obj1.parent].name += all[obj2.parent].name;
delete all[obj2.parent];
} else if(all[obj2.parent] !== undefined) {
all[obj2.parent].name += all[obj1.parent].name;
delete all[obj1.parent];
}
}
}
// test
console.log(JSON.stringify(all));
collision(X, Y);
collision(Y, Z);
collision(C, D);
collision(E, F);
collision(F, H);
collision(G, H);
console.log(JSON.stringify(all));
collision(X, E);
console.log(JSON.stringify(all));
{"1":{"id":1,"name":"X"},"2":{"id":2,"name":"Y"},"3":{"id":3,"name":"Z"},"4":{"id":4,"name":"C"},"5":{"id":5,"name":"D"},"6":{"id":6,"name":"E"},"7":{"id":7,"name":"F"},"8":{"id":8,"name":"G"},"9":{"id":9,"name":"H"}}
{"1":{"id":1,"name":"XYZ","parent":1},"4":{"id":4,"name":"CD","parent":4},"6":{"id":6,"name":"EFHG","parent":6}}
{"1":{"id":1,"name":"XYZEFHG","parent":1},"4":{"id":4,"name":"CD","parent":4}}

Algorithm: path finding with variable path width

given a grid of paths with different width, how can i find a path which leads to the end point?
The path is going to be represented by a two dimentional array where 0 means cannot be walk on, 1 means it is walkable, 2 represents starting point and 3 represents end point. Consider the following example:
21111111100000
00000011000000
00001111111111
00001111100111
00001110000101
00001111100113
in the above example the width of a path varies from 1 to 3, and there exists many solutions which would lead to the end point. I want to find one path which leads to it and the path does not have to be the shortest one (should not be the longest one either). The width of each path is unknown which means the grid could be all "1"s except the starting and end point.
Edited: The path should not contain uneccessary "wasted" walk meaning that if a vertical path has width 2 the result should not just walk down the path and then take one step right then walk all the way up
I agree with Calumn: DFS is the simplest approach here. Here is a simple solution in python-like pseudocode. It will print the solution as a sequence of 'L','R',U','D' to indicate left,right,up, or down.
def flood(x,y,story):
if (visited[x][y] or map[x][y]=='0'): return;
visited[x][y]=True;
if (map[x][y]=='3'):
print 'done. The path is: '+story
return
if (x<len(a[0])): flood(x+1,y,story+'R')
if (y<len(a)): flood(x,y+1,story+'D')
if (x>0): flood(x-1,y,story+'L')
if (y>0): flood(x,y-1,story+'U')
def solve(map):
visited = array_of_false_of_same_size_as(map)
x,y = find_the_two(map)
flood(x,y,'')
The optimization of making it stop as soon as it finds a solution is left as an exercise to the reader (you could make flood return a boolean to indicate if it found something, or use a global flag).
(p.s. I made this answer community wiki since I'm just clarifying Calumn's answer. I can't claim much credit)
Breadth-First Search version, also in Python
For what it's worth, and just to show that breadth-first search is not that complicated, an actual runnable program in Python:
def find(grid, xstart=0, ystart=0):
# Maps (xi,yi) to (x(i-1), y(i-1))
prev = {(xstart, ystart):None}
# Prepare for the breadth-first search
queue = [(xstart, ystart)]
qpos = 0
# Possibly enqueue a trial coordinate
def enqueue(prevxy, dx, dy):
x = prevxy[0] + dx
y = prevxy[1] + dy
xy = (x, y)
# Check that it hasn't been visited and the coordinates
# are valid and the grid position is not a 0
if (xy not in prev
and x >= 0 and x < len(grid)
and y >= 0 and y < len(grid[x])
and grid[x][y] != 0):
# Record the history (and the fact that we've been here)
prev[xy] = prevxy
# If we found the target, signal success
if grid[x][y] == 3:
return xy
# Otherwise, queue the new coordinates
else:
queue.append(xy)
return None
# The actual breadth-first search
while qpos < len(queue):
xy = queue[qpos]
qpos += 1
found = ( enqueue(xy, 1, 0)
or enqueue(xy, 0, 1)
or enqueue(xy, -1, 0)
or enqueue(xy, 0, -1))
if found: break
# Recover the path
path = []
while found:
path.append(found)
found = prev[found]
path.reverse()
return path
# Test run
grid = [ [2,1,1,1,1,1,1,1,1,0,0,0,0,0]
, [0,0,0,0,0,0,1,1,0,0,0,0,0,0]
, [0,0,0,0,1,1,1,1,1,1,1,1,1,1]
, [0,0,0,0,1,1,1,1,1,0,0,1,1,1]
, [0,0,0,0,1,1,1,0,0,0,0,1,0,1]
, [0,0,0,0,1,1,1,1,1,0,0,1,1,3]
]
for x, y in find(grid): grid[x][y]='*'
print '\n'.join(''.join(str(p) for p in line) for line in grid)
Output:
*******1100000
000000*1000000
000011******11
00001111100*11
00001110000*01
00001111100***

Algorithm to dins minimal number of rectangles

I have a rectangular area R in the coordinate system and a set of points P lying inside R. All sides are parallel to the axes and all points are integers. I want to divide R into smaller rectangles in such a way that
(a) the sides of the rectangles either stick to the sides of R or include at least one point from P and
(b) within each rectangle there is exactly one point from P
I have to find the smallest amount of rectangles which would cover all points from P. An example is drawn here: http://i5.minus.com/jC5LnVhjk6soT.png The purple line would indicate an incorrect division because the upper rectangle does not include a point from P. The blue line, however, is quite alright, because both rectangles have a point from P within, so the correct output would be: 2, because this is the minimum amount of rectangles.
Does anyone have an idea of an algorithm/method to find the smallest number?
According to your specifications, I end up with this recursive algorithm : (pseudocode~ruby implementation)
def resolve R, P
if P.empty?
return nil
elsif P.size == 1
return 1
end
results = []
P.each do |p|
rect1, rect2 = split_vertical(R, P, p)
s1 = split_resolve(rect1, rect2)
rect1, rect2 = split_horizontal(R, P, p)
s2 = split_resolve(rect1, rect2)
results.push [s1, s2].min
end
return results.min
end
def split_resolve rect1, rect2
sum1 = resolve(rect1.R, rect1.P)
sum2 = resolve(rect2.R, rect2.P)
if !sum1.nil? and !sum2.nil?
return sum1 + sum2
else
return nil
end
end
Functions split_vertical and split_horizontal split the area R with a vertical and an horizontal line passing through the point p.
You can also optimize this algorithm using dynamic programming. You can store the results of sub-rectangles without computing it an other time. This happend when severals points stands on the same line.
ps : Don't copy the raw source code, you may have some problems with the nil idiom. It's just a pseudocode example for the whole process.

How to easily know if a maze has a road from start to goal?

I implemented a maze using 0,1 array. The entry and goal is fixed in the maze. Entry always be 0,0 point of the maze. Goal always be m-1,n-1 point of the maze. I'm using breadth-first search algorithm for now, but the speed is not good enough. Especially for large maze (100*100 or so). Could someone help me on this algorithm?
Here is my solution:
queue = []
position = start_node
mark_tried(position)
queue << position
while(!queue.empty?)
p = queue.shift #pop the first element
return true if maze.goal?(p)
left = p.left
visit(queue,left) if can_visit?(maze,left)
right = p.right
visit(queue,right) if can_visit?(maze,right)
up = p.up
visit(queue,up) if can_visit?(maze,up)
down = p.down
visit(queue,down) if can_visit?(maze,down)
end
return false
the can_visit? method check whether the node is inside the maze, whether the node is visited, whether the node is blocked.
worst answer possible.
1) go front until you cant move
2) turn left
3) rinse and repeat.
if you make it out , there is an end.
A better solution.
Traverse through your maze keeping 2 lists for open and closed nodes. Use the famous A-Star algorithm
to choose evaluate the next node and discard nodes which are a dead end. If you run out of nodes on your open list, there is no exit.
Here is a simple algorithm which should be much faster:
From start/goal move to to the first junction. You can ignore anything between that junction and the start/goal.
Locate all places in the maze which are dead ends (they have three walls). Move back to the next junction and take this path out of the search tree.
After you have removed all dead ends this way, there should be a single path left (or several if there are several ways to reach the goal).
I would not use the AStar algorithm there yet, unless I really need to, because this can be done with some simple 'coloring'.
# maze is a m x n array
def canBeTraversed(maze):
m = len(maze)
n = len(maze[0])
colored = [ [ False for i in range(0,n) ] for j in range(0,m) ]
open = [(0,0),]
while len(open) != 0:
(x,y) = open.pop()
if x == m-1 and y == n-1:
return True
elif x < m and y < n and maze[x][y] != 0 not colored[x][y]:
colored[x][y] = True
open.extend([(x-1,y), (x,y-1), (x+1,y), (x,y+1)])
return False
Yes it's stupid, yes it's breadfirst and all that.
Here is the A* implementation
def dist(x,y):
return (abs(x[0]-y[0]) + abs(x[1]-y[1]))^2
def heuristic(x,y):
return (x[0]-y[0])^2 + (x[1]-y[1])^2
def find(open,f):
result = None
min = None
for x in open:
tmp = f[x[0]][x[1]]
if min == None or tmp < min:
min = tmp
result = x
return result
def neighbors(x,m,n):
def add(result,y,m,n):
if x < m and y < n: result.append(y)
result = []
add(result, (x[0]-1,x[1]), m, n)
add(result, (x[0],x[1]-1), m, n)
add(result, (x[0]+1,x[1]), m, n)
add(result, (x[0],x[1]+1), m, n)
return result
def canBeTraversedAStar(maze):
m = len(maze)
n = len(maze[0])
goal = (m-1,n-1)
closed = set([])
open = set([(0,0),])
g = [ [ 0 for y in range(0,n) ] for x in range(0,m) ]
h = [ [ heuristic((x,y),goal) for y in range(0,n) ] for x in range(0,m) ]
f = [ [ h[x][y] for y in range(0,n) ] for x in range(0,m) ]
while len(open) != 0:
x = find(open,f)
if x == (m-1,n-1):
return True
open.remove(x)
closed.add(x)
for y in neighbors(x,m,n):
if y in closed: continue
if y not in open:
open.add(y)
g[y[0]][y[1]] = g[x[0]][x[1]] + dist(x,y)
h[y[0]][y[1]] = heuristic(y,goal)
f[y[0]][y[1]] = g[y[0]][y[1]] + h[y[0]][y[1]]
return True
Here is my (simple) benchmark code:
def tryIt(func,size, runs):
maze = [ [ 1 for i in range(0,size) ] for j in range(0,size) ]
begin = datetime.datetime.now()
for i in range(0,runs): func(maze)
end = datetime.datetime.now()
print size, 'x', size, ':', (end - begin) / runs, 'average on', runs, 'runs'
tryIt(canBeTraversed,100,100)
tryIt(canBeTraversed,1000,100)
tryIt(canBeTraversedAStar,100,100)
tryIt(canBeTraversedAStar,1000,100)
Which outputs:
# For canBeTraversed
100 x 100 : 0:00:00.002650 average on 100 runs
1000 x 1000 : 0:00:00.198440 average on 100 runs
# For canBeTraversedAStar
100 x 100 : 0:00:00.016100 average on 100 runs
1000 x 1000 : 0:00:01.679220 average on 100 runs
The obvious here: going A* to run smoothly requires a lot of optimizations I did not bother to go after...
I would say:
Don't optimize
(Expert only) Don't optimize yet
How much time are you talking about when you say too much ? Really a 100x100 grid is so easily parsed in brute force it's a joke :/
I would have solved this with an AStar implementation. If you want even more speed, you can optimize to only generate the nodes from the junctions rather than every tile/square/step.
A method you can use that does not need to visit all nodes in the maze is as follows:
create an integer[][] with one value per maze "room"
create a queue, add [startpoint, count=1, delta=1] and [goal, count=-1, delta=-1]
start coloring the route by:
popping an object from the head of the queue, put the count at the maze point.
check all reachable rooms for a count with sign opposite to that of the rooms delta, if you find one the maze is solved: run both ways and connect the routes with the biggest steps up and down in room counts.
otherwise add all reachable rooms that have no count to the tail of the queue, with delta added to the room count.
if the queue is empty no path through the maze is possible.
This not only determines if there is a path, but also shows the shortest path possible through the maze.
You don't need to backtrack, so its O(number of maze rooms)

Resources