Skip to content

eadf/intersect2d.rs

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

44 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

crates.io Documentation Workflow Workflow dependency status license

intersect2d

After watching Philipp Kindermann's excellent sweep-line videos I think I finally understand how this algorithm works.

This is my humble take on an implementation of the segment line intersection sweep-line algorithm.

The library crate also contains a line intersection function.

This crate is educational, not ready for any production purpose. It has been adopted as a glam and cgmath library here: Linestring.

Rusty voronoi

Interactive step-by-step example:

cargo run --example fltk_gui --features console_trace

Intersection function API example:

use intersect2d::{intersect, Intersection};

let line1 = geo::Line::<f64>::from([(100.0,150.),(150.0,100.)]);
let line2 = geo::Line::<f64>::from([(100.0,150.),(150.0,100.)]);

let rv = intersect(&line1, &line2);
match rv {
    Some(Intersection::Intersection(_a)) => panic!("expected an overlap"),
    Some(Intersection::OverLap(a)) => println!("{:?}", a),
    None =>  panic!("expected an overlap"),
}
// you can also get a single intersection point from the Intersection enum.
// Albeit geometrically incorrect, it makes things easy
println!("{:?}", rv.unwrap().single());

Sweep-line API example:

let lines = vec![
    geo::Line::<f64>::from([(200.0,200.),(350.0,300.)]),
    geo::Line::<f64>::from([(400.0,200.),(250.0,300.)]),
];
let results = intersect2d::algorithm::AlgorithmData::<f64>::default()
    .with_ignore_end_point_intersections(false)?
    .with_lines(lines.into_iter())?
    .compute()?;
for (point, line) in results {
    println!("Intersection @{:?} Involved lines:{:?}", point, line);
}

Detection of self-intersecting geo::LineString:

let coordinates = vec![(200., 200.), (300., 300.), (400., 200.), (200., 300.)];
let line_string = geo::LineString::<f32>::from(coordinates);

// Obviously this example only makes sense for LinesStrings with many points.
// A simple brute force O(n²) intersection test will be faster than this O(nlog(n)+k)
// sweep-line algorithm if n is small enough.
let result = intersect2d::algorithm::AlgorithmData::<f32>::default()
    .with_ignore_end_point_intersections(true)?
    .with_stop_at_first_intersection(true)?
    .with_lines(line_string.lines())?
    .compute()?;
for (p, l) in result {
    println!("Intersection detected @{:?} Involved lines:{:?}", p, l);
}

or using the SelfIntersectingExclusive trait:

// SelfIntersectingExclusive does not report endpoint intersections
use intersect2d::SelfIntersectingExclusive;

let coordinates = vec![(200., 200.), (300., 300.), (400., 200.), (200., 300.)];
let line_string = geo::LineString::from(coordinates);

if line_string.is_self_intersecting()? {
    println!("Intersection detected");
}

for intersections in line_string.self_intersections()? {
    println!("Intersection: {:?}", intersections);
}

You can also check a bunch of geo::Line for self intersections using the SelfIntersectingInclusive trait:

// SelfIntersectingInclusive reports endpoint intersections
use intersect2d::SelfIntersectingInclusive;
let lines = vec![
    geo::Line::<f64>::from([(200.0,200.),(350.0,300.)]),
    geo::Line::<f64>::from([(400.0,200.),(250.0,300.)]),
];
if lines.is_self_intersecting_inclusive()? {
    println!("Intersection detected");
}
for intersections in lines.self_intersections_inclusive()? {
    println!("Intersection: {:?}", intersections);
}

Todo

  • Benchmark and optimize
  • Stable overlapping co-linear line detection