package cracking_the_coding_interview.ch_16;
public class Intersection {
private record Point(double x, double y) {
public boolean isBetween(Point start, Point end) {
return start.x <= this.x && this.x <= end.x &&
start.y <= this.y && this.y <= end.y;
}
public boolean isBetween(Line line) {
return isBetween(line.start, line.end);
}
}
private record Line(Point start, Point end) {
private double deltaOfX() {
return end.x - start.x;
}
private double deltaOfY() {
return end.y - start.y;
}
// y = mx + b
public double m() {
assert deltaOfX() != 0;
return deltaOfY() / deltaOfX();
}
public double b() {
return end.y - m() * end.x;
}
public boolean isBetween(Point point) {
return point.isBetween(start, end);
}
}
private static Point intersection(Point startA, Point endA, Point startB, Point endB) {
assert startA.x >= endA.x && startB.x >= endB.x && startA.x >= startB.x;
Line lineA = new Line(startA, endB), lineB = new Line(startB, endB);
// if lines are parallel to each other, they can only intersect when they have the same offset and a common segment
if (lineA.m() == lineB.m())
return lineA.b() == lineB.b() && lineA.isBetween(lineB.start) ? lineB.start : null;
// m1 * x + b1 = m2 * x + b2
// m1 * x - m2 * x + b1 = b2
// x(m1 - m2) = b2 - b1
// x = (b2 - b1) / (m1 - m2)
double intersectionX = (lineB.b() - lineA.b()) / (lineA.m() - lineB.m());
// y = m ((b2 - b1) / (m1 - m2)) + b
double intersectionY = intersectionX * lineA.m() + lineA.b();
Point intersectionPoint = new Point(intersectionX, intersectionY);
return intersectionPoint.isBetween(lineA) && intersectionPoint.isBetween(lineB) ? intersectionPoint : null;
}
}