Contest Algorithms January 2016 Overview of the CG library code. Look at dot product, cross product,...
-
Upload
luke-holland -
Category
Documents
-
view
228 -
download
0
Transcript of Contest Algorithms January 2016 Overview of the CG library code. Look at dot product, cross product,...
1
Contest AlgorithmsJanuary 2016
Overview of the CG library code.Look at dot product, cross product, ccw(), intersection, closest point, basic polygon
methods.
14. Computational Geometry Basics
Contest Algorithms: 14. CG Basics
Points (x, y) Cartesian coordinates (r, Θ) Polar coordinates
Lines 2-tuple (m, c) using y = mx + c 3-tuple (a, b, c) using ax + by = c Two points P0, P1 on the line using P(t) = (1-t)P0 + t P1
Line Segments Positioned using their end points
Polygons Ordered list of points that form a closed shape
1. Simple Geometry
see Pt.java
see Line.java
see Polygon.java
see Segment.java
Contest Algorithms:14. CG Basics 3
y = mx + c m = gradient; c = intercept on y-axis
Ax + By + C = 0 // not the same 'c' gradient = -A/B; intercept = -C/B
A line with gradient m that passes through the point (a,b) as the equation:
(y – b) = m(x – a)
Line Equationsgradient (slope) = m
c
Contest Algorithms:14. CG Basics 4
A line can be defined by two points: (a,b) and (s,t)
The gradient m = (t-b)/(s-a) Using y = mx + c, and one of the points,
the intercept c = b – (m*a)
(a, b)
(s, t)
Other Helpful Formulas
Length of line segment between P1 and P2:
L = sqrt[ (x2-x1)2 + (y2-y1)2 ]
Midpoint of a line segment between P1 and P3:
P2 = ( (x1+x3)/2 , (y1+y3)/2 )
Two lines are perpendicular iff
1) m1 = -1/m2
or2) Cosine of the angle between them is 0.
Parametric Form Of a LineGiven points P1 = (x1, y1) and P2 = (x2, y2)
x = x1 + t(x2-x1)
y = y1 + t(y2-y1)
t is called the parameter. When
t = 0 we get (x1,y1)
t = 1 we get (x2,y2)
As 0 < t < 1 we get all the other points on the line segment between (x1,y1) and (x2,y2).
Line Segments & Vectors
p = (x , y )
p = (x , y )
1
2
O = (0, 0) x
y
1 1
2 2
Points (vectors): p , p , p p = p p 1 2 1 2 2 1
p p = (x x , y y ) 1 2
1 2 1 2
Line segment: p p = p p 2 1 1 2
see Vec.java
see Segment.java
Contest Algorithms 8
public class Pt implements Comparable<Pt>{ private static final double EPS = 1e-9;
public double x, y; // 2D (x,y)
public Pt() { x = y = 0.0; }
public Pt(double x, double y) { this.x = x; this.y = y; }
public String toString() { return String.format("(%.3f, %.3f)", x, y); }
public boolean equals(Pt p2) { return ((Math.abs(x - p2.x) < EPS) && (Math.abs(y - p2.y) < EPS)); } : : // many more methods} // end of Pt class
The Pt ClassPt()Pt(double x, double y)
String toString()boolean equals(Pt p2)int compareTo(Pt p)Pt rotate(double theta)Pt translate(Vec v)double dist(Pt p2)double distSqr(Pt p2)double angle()double angle(Pt b)void setSegment(Segment s)Segment getSegment()boolean isLeft()boolean isRight()
// static methodsstatic double angle(Pt a, Pt orig, Pt b)static int ccw(Pt p, Pt q, Pt r)static boolean collinear(Pt p, Pt q, Pt r)static Pt linesIntersect(Pt p1, Pt p2, Pt p3, Pt p4)static double distToLine(Pt p, Pt a, Pt b, Pt c)
Contest Algorithms:14. CG Basics 9
public class Line{ private static final double EPS = 1e-9; public double a, b, c; // 2D // using the line definition: ax + by + c = 0
public Line(double a, double b, double c) { this.a = a; this.b = b; this.c = c; }
public Line(Pt p1, Pt p2) { if (Math.abs(p1.x - p2.x) < EPS) { a = 1; b = 0; c = -p1.x; } else { a = -(p1.y - p2.y) / (p1.x - p2.x); b = 1; c = -(a * p1.x) - p1.y; } } // end of Line() ; // many more methods} // end of Line class
The Line ClassLine(double a, double b, double c)Line(Pt p1, Pt p2)Line(Pt p, double m)
String toString()double angle()double gradient()double value(Pt p)double value(double x, double y)Pt ptForX(double x)Pt ptForY(double y)boolean contains(Pt p)boolean isPointOnLeft(Pt p)boolean isPointOnRight(Pt p)boolean areParallel(Line l2)boolean areSame(Line l2)Pt getIntersect(Line l2)Pt closestPoint(Pt p)Pt reflectionPoint(Pt p)Line perpendicular(Pt p)
Contest Algorithms:14. CG Basics 10
public class Segment{ private static final double EPS = 1e-9; public Pt p1, p2; private double length; private Line line;
public Segment(Pt p1, Pt p2) { this.p1 = p1; this.p2 = p2; length = p1.dist(p2); line = new Line(p1, p2); }
public double length() { return length; }
public Line line() { return line; } : // many more methods}
The Segment Class Segment(Pt p1, Pt p2)
double length()Line line()String toString()Pt middle()double angle()double minX()double minY()double maxX()double maxY()Pt ptForX(double x)Pt ptForY(double y)boolean areParallel(Segment seg)boolean areSame(Segment seg)boolean onSegment(Pt p)double dist(Pt p)Pt closestPoint(Pt p)double dist(Segment seg)Pt getIntersect(Segment seg)boolean intersects(Segment seg)Pt getIntersect(Line l2)boolean contains(Pt p)
// static methodsstatic boolean segmentsIntersect( Pt p1, Pt p2, Pt p3, Pt p4)static boolean onSegment(Pt p, Pt q, Pt mid)
Contest Algorithms:14. CG Basics 11
public class Vec{ private static final double EPS = 1e-9;
public double x, y; // 2D; not Java's Vector public Vec(double x, double y) { this.x = x; this.y = y; }
public Vec(Pt a, Pt b) { x = (b.x - a.x); y = (b.y - a.y); }
public Vec scale(double s) { return new Vec(x*s, y*s); }
public double angle() { return Math.atan2(y, x); }
: // more methods} // end of Vec class
The Vec ClassVec(double x, double y)Vec(Pt a, Pt b)
String toString()Vec scale(double s)double angle()double norm()double normSq()double dot(Vec b)double cross(Vec b)double getAngle(Vec v2)
Contest Algorithms:14. CG Basics 12
public class Polygon{ private static final double EPS = 1e-9; private ArrayList<Pt> pts; // 2D
public Polygon(Pt[] ptsArr) { pts = new ArrayList<Pt>(); for (int i=0; i < ptsArr.length; i++) pts.add(ptsArr[i]); pts.add(ptsArr[0]); // loop back so polygon is closed } // pts[0] = pts[n-1]
public int getSize() { return pts.size(); }
public Pt getPoint(int i) { if ((i < 0) || (i > pts.size()-1)) { System.out.println("Index "+i+" is out of range"); return null; } else return pts.get(i); } // end of getPoint()
: // more methods} // end of Polygon class
The Polygon ClassPolygon(Pt[] ptsArr)
int getSize()Pt getPoint(int i)String toString()double perimeter()double area()Pt center()boolean isConvex()boolean inPolygon(Pt pt)Polygon convexHull()
// static methods for trianglesstatic double perimeter(double ab, double bc, double ca)static double perimeter(Pt a, Pt b, Pt c)static double area(double ab, double bc, double ca)static double area(Pt a, Pt b, Pt c)static boolean canFormTriangle(double a, double b, double c)
Contest Algorithms:14. CG Basics 13
Prefer test (predicates) over 'exact' numerical answers
Avoid floating point ops (e.g. division, square root) that can produce numerical inaccuracies
Try to design functionsto use integers mine use double which is bad style it means the code must test for floating point equality
using |a ‐ b| < EPS instead of a == b
Avoid Float Answers
Contest Algorithms:14. CG Basics 14
public boolean equals(Pt p2) // in Pt class { return ((Math.abs(x - p2.x) < EPS) && (Math.abs(y - p2.y) < EPS)); }
Usage:Pt pt1 = new Pt(2,3);Pt pt2 = new Pt(); // (0,0)if (pt1.equals(pts)) ...
Compare Two Points
Distance between two Points
public double dist(Pt p2) // implements Euclidean distance { return Math.hypot(x - p2.x, y - p2.y); }
Square root is slow and imprecise If we only need to check whether the distance is less
than some certain length, say R, then use: double dx = x - p2.x; double dy = y - p2.y; if ((dx*dx + dy*dy) < R*R) ...
double d = pt1.dist(pt2);
Angle
Given a point (x, y), find its angle about the origin (conventionally counterclockwise)
Answer should be in the range (-π, π]
16
(x, y)
θ
tan θ = y/x
Do not use Math.atan() it cannot distinguish between angles in the first and third
quadrants and in the second or fourth quadrants. it also fails when y == 0
Use Math.atan2(y, x) it returns a radian value between π and –π, and will not
crash if y == 0 note the argument order
17
Math.atan2(), not atan()
public double angle() // in Pt class { return Math.atan2(y, x); }
Angle between Two Points
Find the minor angle (i.e. <= π) between two points a and b.
Solution #1: use atan2() for each point, then subtract Solution #2: use the dot product (see next)
18
a
b
Contest Algorithms:14. CG Basics 19
There are three test programs: PointsLinesTest.java PolygonTests.java TriangleTests.java
You should look at them to see how the Pt, Line, Segment, Vec, and Polygon classes can be used.
Test Programs
Given the two vectors a = <a1, a2, a3> and b = <b1, b2, b3> then the dot product is
a· b = a1*b1 + a2*b2 + a3*b3
Example a = <0, -3, 7>, b = <2, 3, 1> a· b = 0*2 + -3*3 + 7*1 = 9 – 7 = 2
2. Dot (Scalar) Product
Dot Product as Geometry
a b = |a| |b| cos θ
The dot product is the product of the magnitudes of the two vectors a and b and the cosine of the angle between them.
The angle between a and b is:Θ = cos-1((a b) / |a||b|)
Determine the angle between a = <3, -4, -1> and b = <0, 5, 2>
Dot product a· b = -22, |a| = , |b| = The angle is: = = -0.8011927 θ = cos-1(-0.8011927) = 2.5 radians
= 143.24 degrees
Angle Example
Contest Algorithms:14. CG Basics 23
public double angle(Pt b) // in Pt class { Vec oa = new Vec(new Pt(), this); Vec ob = new Vec(new Pt(), b); return Math.acos( oa.dot(ob)/(oa.norm()*ob.norm())); } // end of angle()
Code
public double dot(Vec b) // in Vec class { return ((x * b.x) + (y * b.y)); }
public double norm() { return Math.sqrt(normSq()); }
public double normSq() { return (x * x) + (y * y); }
Pt pt = new Pt(2,2);Pt pt2 = new Pt(0,6);System.out.println("Angle: " + Math.toDegrees( pt.angle(pt2))); // 45 degrees
Contest Algorithms:14. CG Basics 24
double theta = 120.0; System.out.println(theta + " degrees is " + Math.toRadians(theta) + " radians"); theta = 1.312; System.out.println(theta + " radians is " +
Math.toDegrees(theta) + " degrees");
The output: 120.0 degrees is 2.0943951023931953 radians
1.312 radians is 75.17206272116401 degrees
Degrees ↔ Radians
Or use printf() and "%.3f"e.g. see Pt.toString()
It can be used to get the projection (length) of vector a onto vector b.
Uses of Dot Product
Given two vectors a = <a1, a2, a3> and b = <b1, b2, b3> then the cross product is
a x b = <a2*b3 – a3*b2, a3*b1 – a1*b3, a1*b2 – a2*b1>This can be written as a determinant: This expands to i - + k
3. Cross (Vector) Product
a = <2, 1, -1> and b = <-3, 4, 1>
Calculate a x b i - + kso i - + k
= 5 i + j + 11 k = <5, 1, 11>
Cross Product Example
The cross product a × b is defined as a vector c that is perpendicular to both a and b, with a direction given by the right-hand rule (the unit vector n) and a magnitude equal to the area of the parallelogram that the vectors span.
Cross Product as Geometry
the area of the parallelogram.
a b = |a| |b | sin θ n
counter-clockwise
Why is |a x b| an area?
a
b
θ
|b| sin θ
|a|
|a x b| = |a||b| sin(θ)so θ = sin-1((a x b) / |a||b|)
What is the angle between a = <2, 1, -1> and b = <-3, 4, 1> (from the last example)?
a x b = 5 i + j + 11 k |a x b| = = 12.124 |a| = (4 + 1 + 1)1/2 = 2.450 |b| = (9 + 16 + 1)1/2 = 5.099
so θ = sin-1(12.124/(2.450*5.099)) = 76.05 degreesor perhaps 180 - 76.05 = 103.95
Angle Example
Contest Algorithms:14. CG Basics 31
public double cross(Vec b) // in the Vec class { return ((x * b.y) - (y * b.x)); }
public double getAngle(Vec v2) { double cross = cross(v2); double sine = cross/(norm()*v2.norm()); // correct any numerical inaccuracies double angle = (sine >= 1) ? Math.PI/2 : Math.asin(sine); double dot = dot(v2); if (dot < 0) angle = Math.PI - angle; if (cross < 0) angle = - angle; return angle; } // end of getAngle()
Code
Contest Algorithms:14. CG Basics 32
Vec v1 = new Vec( new Pt(2,2), new Pt(4,4)); Vec v2 = new Vec( new Pt(2,2), new Pt(2,6)); System.out.println("Angle between vectors v1 and v2: " + Math.toDegrees( v1.getAngle(v2))); // prints 44.9999999999 (really 45)
Usage
(2,2)
(4,4)
(2,6)
45º
You can use the cross product of the vectors a and b to generate a perpendicular vector, which is the normal to the plane defined by a and b.
Normals are very useful when calculating things like lighting in 3D computer games, and up/down in FPSs.
Uses of Cross Product
Suppose we have three vectors a, b, c which form a 3D figure like so:
Geometric Properties
ba
c
Area of the parallelogram of the front face of the object is: area = | a x b |
Volume of the parallelepiped (the entire object) is: volume = |a · (b x c) |
If the volume == 0 then it must mean that all three vectors lie in the same plane
in terms of the box diagram, it means that |a| is 0 units above the b x c face
Area and Volume
Why is |a · (b x c) | a volume? Geometric view:
Scalar Triple Product: a · (b x c)
h = |a| cos α
b x c
α
Determine if the vectors a = <1, 4, -7>, b = <2, -1, 4>, and c = <0, -9, 18> lie on the same plane.
i - + k = 18i - 36j - 18k = <18, -36, -18> a · (b x c) = <1, 4, -7> · <18, -36, -18> = 1*18 + 4*-36 + 7*18 = 18 – 144 + 126 = 0 volume = |a · (b x c) | = 0, which means that all 3
vectors do lie on the same plane.
Example
A basic geometric function: Returns 1 if the points are in
counter-clockwise order (ccw) Returns -1 if the points are in
clockwise order (cw) Returns 0 if the points are
collinear
ccw() utilises cross product.
4. The ccw() Function
2
01
ccw(p0, p1, p2) returns 1
Turning of Consecutive Segments
Counterclockwise Clockwise No turn (collinear)
p
p
p
0
1
2
p
p
p0
1
2p p
p0
1 2
p p p p > 00 1 0 2 p p p p < 00 1 0 2p p p p = 00 1 0 2
Segments p p and p p . Move from p to p then to p . 0 1 1 2 0 1 2
Contest Algorithms:14. CG Basics 40
public static int ccw(Pt p, Pt q, Pt r) /* returns 0, 1, or -1 in Pt class 0 if p-->r and p-->q are collinear 1 if p--> r is left (counter-clockwise) of p-->q -1 if p--> r is right (clockwise) of p-->q */ { Vec v1 = new Vec(p,q); Vec v2 = new Vec(p,r); double cross = v1.cross(v2); if (Math.abs(cross) < EPS) return 0; else if (cross > 0) return 1; else return -1; } // end of ccw()
Codep
q
r
?
System.out.println("ccw value (2,2),(4,4),(2,6): " + Pt.ccw( new Pt(2,2), new Pt(4,4), new Pt(2,6)));
(2,2)
(4,4)
(2,6)
45º
Contest Algorithms:14. CG Basics 41
Intersection of 2 lines in y=ax+b form
Intersection of 2 lines in ax+by +c = 0 form
Intersection of 2 lines defined by four points, two for each line
4. Intersection of Two Lines (in 2D)
Contest Algorithms:14. CG Basics 42
Lines are: y = a1x + b1
y = a2x + b2
and neither is vertical
The lines intersect if the slopes are different (a1 ≠ a2), and the intersection is:
xi = (b2-b1)/(a1-a2) yi = a1xi + b1
Intersection of Lines in y=ax+b form
Contest Algorithms:14. CG Basics 43
Lines are: a1x+b1y+c1 = 0 a2x+b2y+c2 = 0
The lines intersect only if a1b2≠a2b1. The intersection point is:
y = (c1a2- c2a1)/(a1b2-a2b1) x = -1/a1 - b1y/a1
Intersection of Lines in ax+by +c = 0 form
Used by Line.java
Contest Algorithms:14. CG Basics 44
(x1,y1) and (x2,y2) belonging to the first line (x3,y3) and (x4,y4) belonging to the second line
The intersection is given by solving the following equations:
Intersection of Lines defined by 4 Points
xi,yi is the intersection point
Contest Algorithms:14. CG Basics 45
The lines intersect if D ≡ (x1-x2)(y3-y4) - (y1-y2)(x3-x4) ≠ 0
The intersection point is: xi = [ (x3 - x4)(x1y2 – y1x2) - (x1 – x2)(x3y4 – y3x4) ] / D yi = [ (y3 - y4)(x1y2 – y1x2) - (y1 – y2)(x3y4 – y3x4) ] / D
Contest Algorithms:14. CG Basics 46
// in Pt class public static Pt linesIntersect(Pt p1, Pt p2, Pt p3, Pt p4) // p1 and p2 are on the first line; p3 and p4 are on the second line { double d = (p1.x-p2.x)*(p3.y-p4.y) - (p1.y-p2.y)*(p3.x-p4.x); if (d == 0) return null; double xi = ((p3.x - p4.x)*(p1.x*p2.y - p1.y*p2.x) - (p1.x - p2.x)*(p3.x*p4.y - p3.y*p4.x) )/d; double yi = ((p3.y - p4.y)*(p1.x*p2.y - p1.y*p2.x) - (p1.y - p2.y)*(p3.x*p4.y - p3.y*p4.x) )/d; return new Pt(xi,yi); } // end of linesIntersect()
Code
Contest Algorithms:14. CG Basics
System.out.println("Intersection of lines (2,2)--(4,4) and (2,4)--(4,2): " + Pt.linesIntersect( new Pt(2,2), new Pt(4,4), new Pt(2,4), new Pt(4,2))); // prints (3.000, 3.000)
Usage
47
(4,4)(4,2)
(2,4)(2,2)
Contest Algorithms:14. CG Basics 48
Line ln1 = new Line( new Pt(2,2), new Pt(4,4));Line ln2 = new Line( new Pt(2,4), new Pt(4,2));System.out.println("2. Intersection of lines: " + ln1.getIntersect(ln2)); // (3.000,3.000)
Usage 2
Contest Algorithms:14. CG Basics 49
// in the Line class public Pt getIntersect(Line l2) // returns intersection Pt if two lines intersect { if (areParallel(l2)) return null;
// solve system of 2 linear algebraic equations // with 2 unknowns double x = ((l2.b * c) - (b * l2.c)) / ((l2.a * b) - (a * l2.b));
// special case: test for vertical Line to // avoid division by zero double y; if (Math.abs(b) > EPS) y = -((a * x) + c); else y = -((l2.a * x) + l2.c); return new Pt(x,y); } // end of getIntersect()
Code
I cannot use Pt.linesIntersect() since my Line class does not store point information
5. Intersection of two Line Segments Method 1:
1. Assume the segments are lines (i.e. no endpoints)2. Find the intersection of the two lines3. Check whether the intersection point lies between the
endpoints Method 2:
First check whether the two segments intersect A lot easier than step 3 in method 1. See next slide
If so, find the intersection as in step 2 of method 1
50
Do two line segments and intersect ?
Do Two Line Segment Intersects?
p4
p3p1
p2
• Boundary cases must be considered.
A segment straddles a line if point p1 lies on one side of the line and point p2 lies on the other side.
a man straddlinga motorbike
p1
p2
A boundary case arises if p1 or p2 lies directly on the line.
p1
p2
Contest Algorithms 54
public static boolean segmentsIntersect(Pt p1, Pt p2, Pt p3, Pt p4) // do the line segments p1--p2 and p3--p4 intersect? in Segment class { int d1 = Pt.ccw(p3, p4, p1); int d2 = Pt.ccw(p3, p4, p2); int d3 = Pt.ccw(p1, p2, p3); int d4 = Pt.ccw(p1, p2, p4);
if (((d1 > 0 && d2 < 0) || (d1 < 0 && d2 > 0)) && ((d3 > 0 && d4 < 0) || (d3 < 0 && d4 > 0))) return true;
if (d1 == 0 && Pt.onSegment(p3, p4, p1)) return true; if (d2 == 0 && Pt.onSegment(p3, p4, p2)) return true; if (d3 == 0 && Pt.onSegment(p1, p2, p3)) return true; if (d4 == 0 && Pt.onSegment(p1, p2, p4)) return true; return false; } // end of segmentsIntersect()
Code
linesstraddle
checkboundarycases
p
p
1
2
p
p
3
4
p 1
p2
p3
p4
public static boolean onSegment(Pt p, Pt q, Pt mid) // is mid on the line between p and q? { if ( (mid.x <= Math.max(p.x, q.x)) && (mid.x >= Math.min(p.x, q.x)) && (mid.y <= Math.max(p.y, q.y)) && (mid.y >= Math.min(p.y, q.y)) ) return true; return false; } // end of onSegment()
public boolean intersects(Segment seg) { return Segment.segmentsIntersect(p1, p2, seg.p1, seg.p2); }
General Cased1 = ccw(p3, p4, p1)d2 = ccw(p3, p4, p2)
d3 = ccw(p1, p2, p3)d4 = ccw(p1, p2, p4)
p
p
1
2
p
p
3
4
d1
d2
p
p
1
2
p
p
3
4d3
d4
if ((d1 > 0 && d2 < 0) || (d1 < 0 && d2 > 0)) &&
((d3 > 0 && d4 < 0) || (d3 < 0 && d4 > 0)) return true
d1 and d2 must go opposite ways
d3 and d4 must go opposite ways
Non-intersection Example
p2
p1p4
p3
d1 = ccw(p3, p4, p1)d2 = ccw(p3, p4, p2)
d3 = ccw(p1, p2, p3)d4 = ccw(p1, p2, p4)
d3 and d4 do not go opposite ways
d3
d4
Contest Algorithms:14. CG Basics 58
Segment seg = new Segment( new Pt(2,2), new Pt(4,4));System.out.println("Segment: " + seg);System.out.println("Intersection of segs (2,2)--(4,4) and (2,4)--(4,2): " + seg.intersects( new Segment(new Pt(2,4), new Pt(4,2))) ); // true
System.out.println("Intersection of segs (2,2)--(4,4) and (2,3)--(4,5): " + seg.intersects( new Segment(new Pt(2,3), new Pt(4,5))) ); // false
Usage
(4,4)(4,2)
(2,4)(2,2)
(4,4)
(4,5)
(2,3)(2,2)
Contest Algorithms:14. CG Basics 59
System.out.println("Intersection of segs (2,2)--(4,4) and (2,4)--(4,2): " + seg.getIntersect( new Segment(new Pt(2,4), new Pt(4,2))) ); // (3.000,3.000)
// in Segment class public Pt getIntersect(Segment seg) { if (intersects(seg)) { // check if segments intersect Line l2 = new Line(seg.p1, seg.p2); return line.getIntersect(l2); // use line intersection to get pt } else return null; } // end of getIntersect()
Finding the Intersection
Given a point and a line, determine the shortest distance between them.
6. Shortest Distance Between a Point and a Line
P3
P1P2
h
One way is to find the intersection between the line and the line perpendicular to the P1—P2 line which goes through P3.
using the dot product
P
Contest Algorithms:14. CG Basics 61
P3
P1P2
P
gradient == m
gradient == 1/m
One way is to find the intersection between the line and the line perpendicular to the P1—P2 line which goes through P3.
Contest Algorithms:14. CG Basics 62
// in the Line class public Pt closestPoint(Pt p3) // find the closest pt on the line to p3 { if (Math.abs(b) < EPS) // special case 1: vertical Line return new Pt(-c, p3.y); if (Math.abs(a) < EPS) // special case 2: horizontal Line return new Pt(p3.x, -c);
Line perp = new Line(p3, -1/gradient()); // perpendicular (normal line) // intersect Line with this perpendicular; // the intersection is the closest Pt, P return getIntersect(perp); } // end of closestPoint()
Code
Contest Algorithms:14. CG Basics 63
Shortest Distance for a Line Segment
Given a point and a line segment, determine the shortest distance between them.
P1P2
h
The equation of a line defined through two points P1 (x1,y1) and P2 (x2,y2) is P = P1 + u (P2 - P1)with 0 ≤ u ≤ 1 (for line segments)
P3
P
The point P3 (x3, y3) is closest to the line at the tangent to the line which passes through P3, that is, the dot product of the tangent and line is 0, thus
(P3 - P) (P2 - P1) = 0
Substituting the equation of the line gives: [P3 - P1 - u(P2 - P1)] (P2 - P1) = 0
Solving this gives the value of u:
Uses a (b+c) = (a b) + (a c)
cos 90 == 0
Substituting this into the equation of the line gives the point of intersection (x, y) of the tangent as:
x = x1 + u (x2 - x1)y = y1 + u (y2 - y1)
The distance between the point P3 and the line is the distance between (x, y) and P3.
// in the Segment class public Pt closestPoint(Pt p3) /* returns the point on the line segment which is closest to the point p3 */ { Vec vp = new Vec(p1, p3); Vec v = new Vec(p1, p2); // change line segment into vector double u = vp.dot(v) / v.normSq(); // projection
if (u < 0.0) return p1; // closer to p1 else if (u > 1.0) { return p2; // closer to p2 } else // some pt along p1--p2 from p1 return new Pt(p1.x + u*v.x, p1.y + u*v.y); } // end of closestPoint()
Code
Contest Algorithms:14. CG Basics 67
Segment segLine = new Segment( new Pt(2,2), new Pt(4,4));Pt p3 = new Pt(2,4);Pt p = segLine.closestPoint(p3);double d = p3.dist(p);System.out.println("Closest Pt to (2,4) on seg (2,2)--(4,4)): " + p + ", dist = " + d); // (3,3) , √2
Usage
(4,4)
(2,4)(2,2)
(3,3)
√2
7. Area of a Triangle
Area = Base * Height / 2
Area = a * b * sin(C) / 2
Heron’s formula: Area = sqrt( s(s-a)(s-b)(s-c) ) where s = (a+b+c)/2, the semi-perimeter
68
A
B
C
a
b
c
static methods in Polygon.java
public static double area(double ab, double bc, double ca) { double s = 0.5 * Polygon.perimeter(ab, bc, ca); return Math.sqrt(s) * Math.sqrt(s-ab) * Math.sqrt(s-bc) * Math.sqrt(s-ca); }
Area of a Triangle Given as Points
What if only the vertices of the triangle are given? e.g. (x1, y1), (x2, y2), (x3, y3)
Area = abs( x1*y2 + x2*y3 + x3*y1 - x2*y1 - x3*y2 - x1*y3 ) / 2
abs can be omitted if the vertices are in counter-clockwise order.
If the vertices are in clockwise order, the area evaluates to a negative.
69
That hard-to-memorize expression can be drawn as:
Area = ½ * x1 y1
x2 y2
x3 y3
x1 y1
-
+
Contest Algorithms:14. CG Basics 71
Basic Polydon functions: perimeter, area, center point is it convex or concave? does a point lie inside the polygon or not?
More complex functions: convex hull (see next part) triangulation Voronoi diagrams
8. Polygon Functions
Area of a Convex (and Concave) Polygon It turns out the previous formula still works
Area = ½ *
72
(x1, y1)
(x2, y2)
(x3, y3)(x4, y4)
(x5, y5)
x1 y1
x2 y2
x3 y3
x4 y4
x5 y5
x1 y1+
-
Contest Algorithms:14. CG Basics 73
public double area() // in Polygon class // returns the area, which is half the determinant; // works for both convex and concave polygons { double result = 0.0; double x1, y1, x2, y2; for (int i = 0; i < pts.size()-1; i++) { x1 = pts.get(i).x; x2 = pts.get(i+1).x; y1 = pts.get(i).y; y2 = pts.get(i+1).y; result += (x1 * y2 - x2 * y1); } return Math.abs(result)/2.0; } // end of area()
Code
Contest Algorithms:14. CG Basics 74
Pt[] ptsArr = { new Pt(1,1), new Pt(3,3), new Pt(6,1), new Pt(6,6), new Pt(1,6) }; // points, in counter clockwise order
Polygon poly = new Polygon(ptsArr); // last point added to polygon is always copy of first, so that // the shape is closed System.out.println("Perimeter: " + poly.perimeter()); // 21.434System.out.println("Area: " + poly.area()); // 20System.out.println("Is convex: " + poly.isConvex()); // false (P1 is the culprit)
Usage in PolygonTests.java
75
Polygon Coordinates
Contest Algorithms:14. CG Basics
1 2 3 4 5 6 7 8 9
1
23
4
5
678
9
Pt[] ptsArr = { new Pt(1,1), new Pt(3,3), new Pt(6,1), new Pt(6,6), new Pt(1,6) }
Is a Point inside a Convex Polygon?
Given a convex polygon and a point, is the point inside the polygon?
Assume the vertices are given in counterclockwise order for convenience
76
inside
outside
inside (definition may change)
Is a Polygon Convex?
A polygon is convex if and only if every turn (at every vertex) is a left turn
Whether a “straight” turn is allowed depends on the problem definition
ccw() is useful
77
Contest Algorithms:14. CG Basics 78
public boolean isConvex() // in Polygon class /* returns true if we always make a left turn while examining all the edges of the polygon one by one. I assume the points are listed in counter-clockwise order. */ { int sz = pts.size(); if (sz <= 3) // not convex return false; Pt lastPt; for (int i = 0; i < sz - 1; i++) { // compare with the others if ((i+2) == sz) lastPt = pts.get(1); else lastPt = pts.get(i+2); if (Pt.ccw(pts.get(i), pts.get(i+1), lastPt) < 1) // not ccw return false; // this polygon is concave } return true; } // end of isConvex()
Code
Is a Point inside a Polygon?
Compute the angle between pt and consecutive vertices in the polygon, pi and pi+1.
The sum for all the vertices should be (close to) 2π if pt is inside the polygon.
79
pt
pi
pi+1
θ
Contest Algorithms:14. CG Basics 80
public boolean inPolygon(Pt pt) // in Polygon class // returns true if Pt p is inside either convex/concave polygon pts { if (pts.size() == 0) return false;
double sum = 0; // assume first vertex = last vertex for (int i = 0; i < pts.size()-1; i++) { if ( Pt.ccw(pt, pts.get(i), pts.get(i+1)) == 1) sum += Pt.angle(pts.get(i), pt, pts.get(i+1)); // left turn/ccw else sum -= Pt.angle(pts.get(i), pt, pts.get(i+1)); // right turn/cw } return (Math.abs(Math.abs(sum) - 2*Math.PI) < EPS); } // end of inPolygon()
Code
Contest Algorithms:14. CG Basics 81
Pt P6 = new Pt(3, 2); System.out.println("Point P6 is inside: " + poly.inPolygon(P6)); // false
Pt P7 = new Pt(3, 4);System.out.println("Point P7 is inside: " + poly.inPolygon(P7)); // true
Usage in PolygonTests.java
Contest Algorithms:14. CG Basics 82
https://github.com/mikhaildubov/ Computational-geometry
segments intersection, convex hull, closest points, triangulation, Halfplanes, Voronoi diagrams
https://github.com/bkiers/CompGeom Graham scan (convex hulls), rotating calipers, closest pair of
points, Shamos-Hoey algorithm, Bentley-Ottmann (sweep line)
9. Some Other CG Code Sources
Contest Algorithms:14. CG Basics 83
http://www.sanfoundry.com/java-programming-examples-computational-geometry-problems-algorithms/
a lot of examples still to be uploaded
https://tutorial92.wordpress.com/2012/08/17/ geometry-library-java/