Lec24 Convex Hull
Lec24 Convex Hull
1 Introduction
Computational geometry is the design and analysis of algorithms for geometric problems that arise
on low dimensions, typically two or three dimensions. Many elegant algorithmic design and analysis
techniques have been devised to attack geometric problems. This is why I’ve included this topic in
this course.
Some applications of CG:
Computer Graphics
images creation
hidden surface removal
illumination
Robotics
motion planning
Scientific Computation
Blood flow simulations
Molecular modeling and simulations
It is traditional to discuss geometric algorithms assuming that computing can be done on ideal
objects, such as real valued points in the plane. The following chart gives some typical examples
of representations.
Suppose P1 , P2 , . . . Pk ∈ Rd . Below are several ways to use these points to generatel more complex
objects.
Linear Combination
X
Subspace = αi Pi where αi ∈ R
Affine Combination
X X
Plane = αi Pi where αi = 1, αi ∈ R
Convex Combination
X X
Body = αi Pi where αi = 1, αi ≥ 0 αi ∈ R
2
2 Primitive Operations
I’ll be giving integer implementations of these primitives in ocaml. Let’s start with some basic
operations on vectors in 2D. The code below defines vector addition subtraction, cross product, dot
product and the sign of a number.
Given three points P1 , P2 , P3 , the output of the line side test is “LEFT” if the point P3 is to the
left of ray P1 → P2 , “RIGHT” if the point P3 is to the right of ray P1 → P2 , and “ON” if it is on
that ray.
The algorithm is to construct vectors V2 and V3 by subtracting P1 from P2 and P3 respectively.
Then take the cross product of V2 and V2 and look at its value compared to 0.
Line segment
OneNote Online
intersection testing https://onenote.officeapps.live.com/o/onenoteframe.aspx?Fi=SDACE4EBC921613DBE!...
Here we are given two line segments (a, b) and (c, d) (where a, b, c, d are points), and we have to
!
determine if they cross. We can do this using four line-side tests, as illustrated here.
"#$%&'(!)&*+,!-.(!/0-.! -0120!3)!
! 3
Fast Robust Predicates for Computational Geometry http://www.cs.cmu.edu/~quake/robust.html
By changing the <= into a <, this can be changed into a strict intersection test, which would require
Jonathan Richard Shewchuk
the segments to intersect
Computer Science Division at a point interior to both of them.
University of California at Berkeley
Berkeley, test
In-circle California 94720-1776
Three non-colinear
Created points project
as part of the Archimedes determine
(tools for a circle.
parallel The in-circle
finite element methods). test will tell us the relationship of a
Supported in part by NSF Grant CMS-9318163 and an NSERC 1967 Scholarship.
fourth point to the circle determined by the other three points. So the test takes points a, b, c, and
d as inputs, and returns 1, 0, or −1 as follows:
Many computational geometry applications use numerical tests known as the orientation and incircle tests. The orientation test determines
whether a point lies to the left of, to the right of, or on a line or plane defined by other points. The incircle test determines whether a point
This
lies inside,returns 0 aifcircle
outside, or on thedefined
fourbypoints are on the same circle (or straight line.) Suppose I
other points.
walk forward around the circle with my right hand on the circle from a → b → c. It
Each of these tests is performed by evaluating the sign of a determinant (see the figure below). The determinant is expressed in terms of the
returnsof1theifpoints.
coordinates d isIf on
thesethe sameareside
coordinates of as
expressed the circle
single as precision
or double my body, −1 otherwise.
and numbers,
floating-point roundoff error It’s a
may lead
to an incorrect result when the true determinant is near zero. In turn, this misinformation can lead an application to fail or produce incorrect
fourth
results.
degree function in the given coordinates.
let row ax dx ay dy =
let a = ax - dx in
let b = ay - dy in
(a, b, (a*a) + (b*b))
in
sign (det (row ax dx ay dy, row bx dx by dy, row cx dx cy dy))
The One way to solve this problem is to use exact arithmetic. Unfortunately, traditional libraries for arbitrary precision floating-point arithmetic
picture above illustrates a case when the incircle test would return 1. (This figure was taken
are quite slow, and can reduce the speed of an application by one or two orders of magnitude.
from http://www.cs.cmu.edu/~quake/robust.html)
To minimize this problem, I've produced algorithms and implementations for performing the 2D and 3D orientation and incircle tests
1 of 2 3/16/15 3:26 AM
4
3 Computing the Convex Hull
This is the “sorting problem” of computational geometry. There are many algorithms for the
problem, and there are often analogous to well-known sorting algorithms.
A point set A ⊆ Rd is convex if it is closed under convex combinations. That is, if we take any
convex combination of any two points in A, the result is a point in A. In other words if when we
walk along the straight line between any pair of points in A we find that the entire path is also
inside of A, then the set A is convex.
We saw convex sets before when we talked about linear programming. One observation we used at
that time is that the intersection of any two convex sets is convex.
Definition: ConvexClosure(A) = smallest convex set containing A
This is well-defined and unique for any point set A. (We won’t prove this.) Assuming that the set
A is a closed set of points we can define the convex hull of A as follows:
Definition: ConvexHull(A) = boundary of ConvexClosure(A). (A point p is on the boundary of
S if for any > 0 there exists a point within of p that is inside S and also another point with
of p that is outside of S.)
These definitions are general and apply to any closed set of points.
For our purposes we’re only interested in the ConvexClosure(A) and ConvexHull(A) when A is a
finite set of points. In this case the ConvexClosure will be a closed polyhedron.
A computer representation of a convex hull must include the combinatorial structure. In two
dimensions, this just means a simple polygon in, say counter-clockwise order. (In three dimensions
it’s a planar graph of vertices edges and faces) The vertices are a subset of the input points.
So in this context, a 2D convex hull algorithm takes as input a finite set of n points A ∈ R2 , and
produces a list L of points from A which are the vertices of the ConvexHull(A) in counter-clockwise
order.
All the other points must be to the left of segment (Ps , Pt ). We can continue this process to find
the point Pu which is the one with the smallest angle with respect to (Ps , Pt ). This process is
continued until all the points are exhausted. The running time is O(n) to find each segment. There
are O(n) segments, so the algorithm is O(n2 ).
Actually we don’t need to compute angles. The line-side-test can be used for this instead. For
example look at what happens after we’ve found Ps and Pt . We process possibilities for the next
point in any order. Say we start from a in the figure. Then we try b, and note that b is on the right
side of segment (Pt , a) so we jettison a and continue with (Pt , b). But then we then throw out b in
6
favor of c. It turns out that the remaining points are all to the left of segment (Pt , c). Thus c = Pu
is the next point on the convex hull.
At this point we’ve formed the chain P0 , P1 , P2 , P3 , P4 . But the last step (from P3 to P4 ) is a right
turn. So we delete P3 from the chain. Now we have:
After all the points are processed in this way, we can just add the last segment from Pn−1 to P0 ,
to close the polygon, which will be the convex hull.
Each point can be added at most once to the sequence of vertices, and each point can be removed
at most once. Thus the running time of the scan is O(n). But remember we already paid O(n log n)
for sorting the points at the beginning of the algorithm, which makes the overall running time of
the algorithm O(n log n).
The reason this algorithm works is because whenever we delete a point we have implicitely shown
that it is a convex combination of other points. For example when we deleted P3 we know that
it is inside of the triangle formed by P0 , P2 and P4 . Because of the presorting P3 is to the left of
(P0 , P2 ), and to the right of (P0 , P4 ). And because (P2 , P3 , P4 ) is a right turn, P3 is to the left of
(P2 , P4 ).
At the end the chain is all left turns, with nothing outside of it. Therefore it must be the convex
hull.
Complete ocaml code for the graham scan is at the end of these notes.
8
3.3 Lower bound for computing the convex hull
Suppose the input to a sorting problem is X1 , . . . , Xn . Consider computing the convex hull of the
following set of points:
All of these points are on the convex hull (they’re on a parabola). Thus they are returned in the
order they appear along the parabola. No matter which convex hull algorithm is used, the points
can be reflected and/or cyclically shifted so that their x coordinates are in sorted order. Thus, they
can be sorted by computing a convex hull followed by O(n) additional work. Thus any comparison
based convex hull algorithm must make https://onenote.officeapps.live.com/o/onenoteframe.aspx?Fi=SDACE4EBC921613DBE!...
OneNote Online Ω(n log n) comparisons. The figure below illustrates this
phenomenon.
!
"#$%&'(!"&)*+!,-(!./,0! ,1,.!2"!
1 of 1 3/16/15 5:22 AM
3.4 Ocaml code for the Graham Scan convex hull algorithm
(* now the list starts at p1, and base is at the end of the list *)
let rec scan chain points =
let (c1,c2,chainx) = match chain with
| c1::((c2::_) as chainx) -> (c1,c2,chainx)
| _ -> failwith "chain must have length at least 2"
in
match points with [] -> chain
| pt::tail ->
match line_side_test c2 c1 pt with
| 1 -> scan (pt::chain) tail
| -1 -> scan chainx points
| _ ->
if len (pt--c2) > len (c1--c2)
then scan (pt::chainx) tail
else scan chain tail
in
match points with
| (p1::((_::(_::_)) as rest)) -> List.tl(scan [p1;base] rest);
| _ -> points (* do nothing if < 3 points *)
let print_list l =
List.iter (fun (x,y) -> Printf.printf "(%d,%d) " x y) l;
print_newline()
let () = print_list (graham_convex_hull [(0,0);(0,2);(2,2);(2,0);(1,1)])
-------------------------
output:
(0,2) (2,2) (2,0) (0,0)
10