forked from williamfiset/Algorithms
-
Notifications
You must be signed in to change notification settings - Fork 0
/
CollinearPoints.java
85 lines (67 loc) · 3.11 KB
/
CollinearPoints.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
/**
* In this file I show you how to determine if three points are collinear to each other (on the same
* line).
*
* <p>Time Complexity: O(1)
*
* @author William Fiset, [email protected]
*/
package com.williamfiset.algorithms.geometry;
import static java.lang.Math.*;
import java.awt.geom.Point2D;
public class CollinearPoints {
// Epsilon is a small double value used for double comparisons
private static final double EPS = 1e-9;
// Suppose a != b and the points a & b form an infinite line and we want
// to determine if c is a point on that line. This method returns 0 if
// it is on the line, -1 if c is to the right of the line and +1 if it's
// to the left from the frame of reference of standing at point a
// and facing point b.
public static int collinear(Point2D a, Point2D b, Point2D c) {
if (a.distance(b) < EPS) throw new IllegalArgumentException("a cannot equal b");
// To determine if c is on the line we will use the determinant of
// the two vectors formed by 'ab' and 'ac' (could also have done 'ba' and 'bc').
// The determinant is a particularly useful property in linear algebra because
// it can tell us the signed area of a parallelogram between two vectors.
// Furthermore, we know that two vectors are parallel if the area of the
// parallelogram between them is zero and we will use this fact to determine
// if the point c is on the line formed by a & b
// If a = (a_x, a_y), b = (b_x, b_y), c = (c_x, c_y) then our two vectors
// 'ab' and 'ac' are v1 = <b_x-a_x, b_y-a_y> and v2 = <c_x-a_x, c_y-a_y>
double v1_x = b.getX() - a.getX();
double v1_y = b.getY() - a.getY();
double v2_x = c.getX() - a.getX();
double v2_y = c.getY() - a.getY();
// | v1_x v2_x |
// When we place our two vectors inside a 2x2 matrix we get: | v1_y v2_y |, and
// hence we get that the determinant is (v1_x*v2_y)-(v2_x*v1_y)
double determinant = (v1_x * v2_y) - (v2_x * v1_y);
// The points a, b, c are collinear
if (abs(determinant) < EPS) return 0;
// Return -1 for right and +1 for left
return (determinant < 0 ? -1 : +1);
}
// Compressed version of collinear code above
public static int collinear2(Point2D a, Point2D b, Point2D c) {
double area =
(b.getX() - a.getX()) * (c.getY() - a.getY())
- (b.getY() - a.getY()) * (c.getX() - a.getX());
if (abs(area) < EPS) return 0;
return (int) signum(area);
}
// Example of collinear points
public static void main(String[] args) {
Point2D a = new Point2D.Double(1, 1);
Point2D b = new Point2D.Double(3, 3);
Point2D c = new Point2D.Double(7, 7);
// Returns 0 means that yes these points are collinear
System.out.println(collinear(a, b, c));
// Returns +1 meaning that c is to the left of the line
c = new Point2D.Double(2, 7);
System.out.println(collinear(a, b, c));
// Returns -1 meaning that c is to the right of the line
c = new Point2D.Double(2, -7);
System.out.println(collinear(a, b, c));
System.out.println(collinear2(a, b, c));
}
}