Computational Geometry Part 1: Intro, Primitives, Area, Circles Lucca Siaudzionis and Jack Spalding-Jamieson 2020/02/25 University of British Columbia
Announcements • A3 is due Sunday! • Project topics are due next Tuesday! 1
What is Computational Geometry? Computational Geometry is a huge field, with its own conferences and labs dedicated to it. It includes all sorts of problems. It can include problems involving: • Point sets • Line segments • Polygons • Convexity Some classic problem classes you may have heard of are: • Art gallery problems • Voronoi diagrams and Delauney triangulations • Ray tracing • Graph drawing (which is a field in its own right) 2
Primitives: Vectors What is a vector? Not dynamic arrays! A d -dimensional vector is a list of exactly d numbers. Normally we work with 2-dimensional and 3-dimensional vectors. Vectors are used for everything in geometry! They can be used to represent: • Points • Displacement • Velocity • Direction 3
Primitives: Vectors - Notation and Implementation A 2D vector � v can be denoted as a tuple, i.e. � v = ( x , y ), and likewise a 3D vector can appear as ( x , y , z ). In code, this can be represented many ways, such as: typedef long double ld; 1 struct vec2 { 2 ld x, y; 3 vec2() : x(0), y(0) {} 4 }; 5 struct vec3 { 6 ld x, y, z; 7 vec3() : x(0), y(0), z(0) {} 8 }; 9 template <size_t N> 10 struct vec { 11 array<ld,N> a; }; 4 12
Primitives: Vectors - Operations (1) There are many operations we can do on a vector, such as: • Addition/subtraction: � v 1 ± � v 2 = ( x 1 ± x 2 , y 1 ± y 2 ) • Scalar multiplication: a � v = ( ax , ay ) These are the simplest operations, and in general can be implemented as follows: template <size_t N> struct vec { 1 array<ld,N> a; 2 vec operator+(const vec& o) const { 3 vec ret; 4 for (size_t i = 0; i < N; ++i) ret.a[i] = a[i] + o.a[i]; 5 return ret; } 6 vec operator*(const int c) const { 7 vec ret; 8 for (size_t i = 0; i < N; ++i) ret.a[i] = c*a[i]; 9 return ret; } 10 5
Primitives: Vectors - Operations (2) We can also measure the ”length” of a vector in many different ways: • L 1 norm: � � v � 1 = | x | + | y | (“Manhattan distance”) x 2 + y 2 (Euclidean distance, often written as | � � • L 2 norm: � � v � 2 = v | ) • L ∞ norm: � � v � ∞ = max( | x | , | y | ) v � k = ( | x | k + | y | k ) 1 / k • L k norm (general): � � Generally, this can be implemented as: ld norm(ld k) const { 11 ld ret = 0; 12 for (size_t i = 0; i < N; ++i) ret += powl(abs(a[i]),k); 13 return powl(ret, 1/k); } 14 6
Primitives: Vectors - Operations (3) Dot product • � v 1 · � v 2 = x 1 x 2 + y 1 y 2 = | � v 1 || � v 2 | cos θ , where θ is the angle between � v 1 and � v 2 v | 2 • � v · � v = | � • Interpretation: signed length of projection from � v 1 to � v 2 , scaled by length | � v 2 | • � v 1 · � v 2 = 0 ⇔ � v 1 ⊥ � v 2 Generally, this can be implemented as: friend vec dot(const vec& u, const vec& v) { 15 vec ret; 16 for (size_t i = 0; i < N; ++i) ret[i] = u.a[i] + v.a[i]; 17 return ret; } 18 }; 19 7
Primitives: Vectors - Operations (4) 2D cross-product: • � v 1 × � v 2 = x 1 y 2 − x 2 y 1 = | � v 1 || � v 2 | sin θ • Interpretation: signed distance from � v 1 to its projection on � v 2 , scaled by length | � v 2 | • � v 1 × � v 2 = 0 ⇔ � v 1 � � v 2 • Returns a scalar . This can be implemented as: struct vec2 { 1 ld x, y; 2 vec2() : x(0), y(0) {} 3 friend ld cross(const vec2& u, const vec2& v) { 4 return u.x*v.y-v.x*u.y; } 5 }; 6 8
Primitives: Vectors - Operations (5) 3D cross-product: � � x 1 x 2 i j k y 1 z 2 − z 1 y 2 � � � � v 1 × � � v 2 = × = = z 1 x 2 − x 1 z 2 y 1 y 2 x 1 y 1 z 1 � � � � � � x 1 y 2 − y 1 x 2 z 1 z 2 x 2 y 2 z 2 � � • Still true: | � v 1 × � v 2 | = | � v 1 || � v 2 | sin θ • Interpretation: vector that is perpendicular to both � v 1 and � v 2 • Direction determined by left-hand rule • NOT associative, NOT commutative • Returns a vector . 9
Primitives: Vectors - Operations (6) The 3D cross-product can be implemented succinctly as: struct vec3 { 7 array<ld,3> a; 8 friend vec3 cross(const vec3& u, const vec3& v) { 9 vec3 ret; 10 for (size_t i = 0; i < 3; ++i) 11 ret[i] = u.a[(i+1)%3]*v.a[(i+2)%3]-u.a[(i+2)%3]*v.a[(i+1)%3]; 12 return ret; } 13 }; 14 10
Primitives: Turning Left or Right How can we tell if the 2D points � x 0 , � x 1 , � x 2 in that order are oriented clockwise or counterclockwise? x 2 � x 1 � x 2 � x 1 � x 0 � x 0 � Figure 1: Left: 3 points that are CCW; Right: 3 points that are CW i.e. how do we differentiate left and right turns? 11
Primitives: Turning Left or Right (Solution) > 0 Counterclockwise ( � x 1 − � x 0 ) × ( � x 2 − � x 1 ) = 0 Collinear < 0 Clockwise If you remember your first year physics courses, you can use the right-hand rule to derive this. Otherwise, take this as a primitive operation. 12
Complex numbers Implementing all these linear algebra routines seems tedious. Luckily, in 2D we have a representation using complex numbers! Recall that complex numbers are defined as √ C = { a + bi | a , b ∈ R , i = − 1 } Then, we can represent a 2D point ( x , y ) by x + yi . We can add/subtract/multiply/divide complex numbers by multiplying the real and imaginary parts, then remembering that i 2 = − 1. Addition and subtraction is the same as with vectors (translation). What about multiplication/division? 13
Complex numbers Recall that we can represent points in 2D using polar coordinates ( r , θ ). Euler’s formula: e i θ = cos θ + i sin θ Then ( r , θ ) = r cos θ + ir sin θ = re i θ , so we get ( r 1 e i θ 1 )( r 2 e i θ 2 ) = ( r 1 r 2 ) e i ( θ 1 + θ 2 ) Multiplication = multiply absolute values, add angles! In particular, if r 2 = 1 then this is a rotation of a point about the origin! 14
Complex numbers Complex numbers make geometry much easier! • Vector addition: add complex numbers • Multiply vector by scalar: multiply complex by real • Dot/cross product: zw = ( � z · � w ) + ( � z × � w ) i • if z = a + bi then z = a − bi . This is called the conjugate of z . • Rotation by θ : multiply by e i θ • Length: | z | 15
Primitives: Representations of 2D Vectors There are many different ways we can implement our 2D vectors: ld x, y struct vec2 vec<2> complex<T> Speed Fast Fast Fast Slow Bug frequency High Low Very low Negligible Code length Very short Short Short Very short! Vector Arithmetic Hard-code Operator Operator Operator Multiply by e i θ Rotation Hard-code Matrix Matrix (difficult) Dot Product Hard-code Function Function Re ( zw ) Cross Product Hard-code Function Function Im ( zw ) Length/Distance Hard-code Function Function | z | In C++, complex numbers are implemented by complex<T> . In Python, complex numbers are builtin (e.g. 1 + 2j ). In Java, Point2D.Double is fairly useless for lots of typing; just write your own 16 vector/complex class.
Primitives: Representing Lines / Line Segments (1) Representing lines • Bad: y = mx + b (what can possibly go wrong with this?) • Okay: ax + by + c = 0 • Good: � L ( t ) = � x 0 + � v 0 t Representing line segments • � S ( t ) = � x 0 + ( � x 1 − � x 0 ) t where t ∈ [0 , 1] Both lines and line segments can (and should) be represented by a pair of vectors! 17
Primitives: Representing Lines / Line Segments (2) x 1 � v 0 � � x 0 Figure 2: Parametric representation of a line 18
Primitives: Line Segment Intersection (Seg X Seg) (1) Given two line segments L 1 and L 2 , how do we tell if they intersect? Intersects Does not Intersect Endpoint intersection Overlap (Colinear) Figure 3: Types of intersections 19
Primitives: Line Segment Intersection (Seg X Seg) (2) After choosing one of the segments as a ”primary” segment (with vector � A ), create some vectors: � C � B � A Notice how we have two kinds of turns: � A → � B is a left turn, and � A → � C is a right turn. 20
Primitives: Line Segment Intersection (Seg X Seg) (3) What can we say about intersections, given the turns? • If both turns are left turns, then the segments do not intersect. • If both turns are right turns, then the segments do not intersect. • We can try this with either segment as the “primary” segment. • If we never satisfy the first two points with either primary, then the two segments do intersect (except for some edge cases). 21
Primitives: Line Segment Intersection (Seg X Seg) (4) What are the edge cases? • Colinearity! • Endpoint intersection (easy to handle). The two segments are colinear if all the cross-products computed for the direction are zero. There are several different ways for the segments to be colinear. 22
Primitives: Line Segment Intersection (Seg X Seg) (5) b ′ b ′ a ′ b b a ′ a a No overlap Interior overlap b ′ b b ′ a ′ b a ′ a a Shared endpoint Containment 23
Recommend
More recommend