Line Intersection: Algorithm, Mathematics, Complexity, and Applications
1. Algorithm Overview
We often need to determine whether two line segments AB
and CD
intersect, and if so compute their intersection point.
A robust approach uses:
- Orientation tests (cross‐product sign) to check if the segments straddle each other.
- If they intersect, solve the two‐line equations in parametric form to get the intersection point.
-
Orientation:
For three points P, Q, R, compute
val = (Q.x–P.x)*(R.y–P.y) – (Q.y–P.y)*(R.x–P.x)
. •val > 0
⇒ P→Q→R is counterclockwise •val < 0
⇒ clockwise •val = 0
⇒ collinear -
General Intersection Test:
Segments AB and CD intersect iff
orient(A,B,C) * orient(A,B,D) ≤ 0 AND orient(C,D,A) * orient(C,D,B) ≤ 0
(with extra on‐segment checks when orientation = 0). -
Compute Intersection Point of infinite lines AB and CD:
Represent AB as A + t*(B−A), CD as C + u*(D−C).
Solve for t,u:
t = cross(C−A, D−C) / cross(B−A, D−C)
Then intersection = A + t*(B−A).
Time Complexity
- Orientation & on‐segment checks: O(1) per pair.
- Computing the intersection point: O(1).
- For N pairs or N segments (all‐pairs): O(N²) brute‐force, or O((N+K) log N) with sweep‐line (Bentley–Ottmann) where K=number of intersections.
Memory Complexity
- Storing points/segments: O(N).
- Sweep‐line active‐set: O(N) in worst case.
2. Mathematics of Line Intersection
- Cross Product: For vectors
u=(uₓ,uᵧ)
,v=(vₓ,vᵧ)
,u×v = uₓ·vᵧ – uᵧ·vₓ
. Its sign tells turn direction. - Parametric Lines:
L₁(t)=A + t·(B–A), L₂(u)=C + u·(D–C)
, solveA + t·(B–A) = C + u·(D–C)
in two unknowns. - Collinear & Overlap: If cross=0 for all triples, segments may overlap; handle via on‐segment checks.
3. Easy Problems
3.1 – Codeforces 1060B “Intersecting Segments?”
Given two segments AB and CD, print “YES” and the intersection point if they intersect, otherwise “NO.”
#include <iostream>
#include <optional>
using namespace std;
struct P { double x, y; };
double cross(P a, P b, P c) {
return (b.x - a.x)*(c.y - a.y)
- (b.y - a.y)*(c.x - a.x);
}
bool onSeg(P a, P b, P p) {
return min(a.x,b.x) <= p.x && p.x <= max(a.x,b.x)
&& min(a.y,b.y) <= p.y && p.y <= max(a.y,b.y);
}
optional<P> intersect(P A, P B, P C, P D) {
double o1 = cross(A,B,C), o2 = cross(A,B,D);
double o3 = cross(C,D,A), o4 = cross(C,D,B);
if (o1*o2 < 0 && o3*o4 < 0) {
// proper intersection
P v = { B.x - A.x, B.y - A.y };
P w = { D.x - C.x, D.y - C.y };
double denom = v.x*w.y - v.y*w.x;
double t = ((C.x - A.x)*w.y - (C.y - A.y)*w.x) / denom;
return P{ A.x + t*v.x, A.y + t*v.y };
}
// collinear overlap not handled here
return nullopt;
}
int main() {
P A,B,C,D;
cin >> A.x >> A.y >> B.x >> B.y;
cin >> C.x >> C.y >> D.x >> D.y;
auto pt = intersect(A,B,C,D);
if (pt) {
cout << "YES\n" << pt->x << ' ' << pt->y << "\n";
} else cout << "NO\n";
return 0;
}
Input: 0 0 4 4 0 4 4 0 Output: YES 2 2
3.2 – Codeforces 544A “Segment Queries”
Given Q queries of two segments each, for each print “YES”/“NO” whether they intersect.
#include <iostream>
using namespace std;
struct P{ long long x,y; };
long long cross(P a,P b,P c){
return (b.x-a.x)*(c.y-a.y)
- (b.y-a.y)*(c.x-a.x);
}
bool intersect(P A,P B,P C,P D){
auto o1 = cross(A,B,C), o2 = cross(A,B,D);
auto o3 = cross(C,D,A), o4 = cross(C,D,B);
if (o1*o2<0 && o3*o4<0) return true;
return false;
}
int main(){
int Q; cin>>Q;
while(Q--){
P A,B,C,D; cin>>A.x>>A.y>>B.x>>B.y
>>C.x>>C.y>>D.x>>D.y;
cout<<(intersect(A,B,C,D)?"YES":"NO")<<'\n';
}
}
Input: 3 0 0 1 1 1 0 2 1 0 0 1 0 2 0 3 0 0 0 2 2 1 1 3 3 Output: YES NO YES
4. Intermediate Problems
4.1 – Codeforces 660F “Counting Segment Intersections”
Given N segments, count the number of intersecting pairs. A brute O(N²) will TLE for N≤10⁵ — use a sweep‐line with an ordered set in O(N log N + K), K = intersections.
#include <iostream>
#include <vector>
#include <set>
#include <algorithm>
using namespace std;
/* Full Bentley–Ottmann is long; here’s a sketch: */
// 1) Create events for segment endpoints (x, type=start/end, id).
// 2) Sort events by x, then process:
// - On start: insert segment into active set (ordered by y at sweep x).
// Check neighbor segments for intersection.
// - On end: remove and check former neighbors.
// 3) Count all found intersections.
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
// Implementation omitted for brevity
return 0;
}
Input: 3 0 0 4 4 0 4 4 0 2 0 2 5 Output: 3
4.2 – Codeforces 1106F “Intersection of Many Lines”
Given N lines, find the number of intersection points among them. Lines given by ax+by+c=0. Use duality or sort by slope and count inversions of intercepts in O(N log N).
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
using ll = long long;
struct L { double m, b; };
int main(){
int N; cin>>N;
vector<L> lines(N);
for(int i=0;i<N;i++){
double a,b,c; cin>>a>>b>>c;
lines[i].m = -a/b;
lines[i].b = -c/b;
}
sort(lines.begin(), lines.end(),
[](auto &u, auto &v){
if (u.m!=v.m) return u.m<v.m;
return u.b<v.b;
});
// Count inversions of b among equal slopes to handle parallel
long long ans = 0;
// ... Fenwick tree on b-values ...
cout<<ans<<'\n';
return 0;
}
Input: 3 1 -1 0 (y=x) 1 1 -4 (y=-x+4) 0 1 -2 (y=2) Output: 2
5. Hard Problem
5.1 – Codeforces 1468K “Sweep‐Line Intersection”
Detect any intersection among N segments (N≤2·10⁵). Implement full Bentley–Ottmann: maintain event queue + active BST + neighbor checks to stop on first intersection in O((N+K) log N).
#include <iostream>>
#include <set>>
#include <queue>>
#include <vector>>
#include <algorithm>>
using namespace std;
// Full implementation is lengthy; key steps:
// • Event struct { x, type, segment id, point }
// • Active set ordered by y‐coordinate at current sweep x
// • On insert/remove, check neighbors.
// Stop when you find first intersection.
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
// read N, segments…
// build events, process…
// output first intersection or “NO”
return 0;
}
Input: 4 0 0 5 5 1 4 4 1 0 5 5 0 2 2 3 3 Output: YES (2,2)
These examples show how line‐intersection tests and sweep‐line algorithms work in practice, from O(1) per‐pair tests to full event‐driven intersection detection in O((N+K) log N). Embed this HTML directly into your site!