|
use crate::aabb::Aabb; |
|
use crate::line_segment::LineSegment; |
|
|
|
const INSIDE: u8 = 0; |
|
const LEFT: u8 = 1; |
|
const RIGHT: u8 = 1 << 1; |
|
const BOTTOM: u8 = 1 << 2; |
|
const TOP: u8 = 1 << 3; |
|
|
|
fn out_code(x: f64, y: f64, bounding_box: &Aabb) -> u8 { |
|
let mut code = INSIDE; |
|
|
|
if x < bounding_box.left { |
|
code |= LEFT; |
|
} else if x > bounding_box.right { |
|
code |= RIGHT; |
|
} |
|
|
|
if y < bounding_box.top { |
|
code |= BOTTOM; |
|
} else if y > bounding_box.bottom { |
|
code |= TOP; |
|
} |
|
|
|
code |
|
} |
|
|
|
pub(crate) fn line_segment_aabb_intersect(seg: LineSegment, bounding_box: &Aabb) -> bool { |
|
let [mut p0, mut p1] = seg; |
|
|
|
let mut outcode0 = out_code(p0.x, p0.y, bounding_box); |
|
let mut outcode1 = out_code(p1.x, p1.y, bounding_box); |
|
|
|
loop { |
|
if (outcode0 | outcode1) == 0 { |
|
|
|
return true; |
|
} else if (outcode0 & outcode1) != 0 { |
|
|
|
|
|
return false; |
|
} else { |
|
|
|
|
|
let mut x = 0.; |
|
let mut y = 0.; |
|
|
|
|
|
let outcode_out = if outcode1 > outcode0 { outcode1 } else { outcode0 }; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (outcode_out & TOP) != 0 { |
|
|
|
x = p0.x + (p1.x - p0.x) * (bounding_box.bottom - p0.y) / (p1.y - p0.y); |
|
y = bounding_box.bottom; |
|
} else if (outcode_out & BOTTOM) != 0 { |
|
|
|
x = p0.x + (p1.x - p0.x) * (bounding_box.top - p0.y) / (p1.y - p0.y); |
|
y = bounding_box.top; |
|
} else if (outcode_out & RIGHT) != 0 { |
|
|
|
y = p0.y + (p1.y - p0.y) * (bounding_box.right - p0.x) / (p1.x - p0.x); |
|
x = bounding_box.right; |
|
} else if (outcode_out & LEFT) != 0 { |
|
|
|
y = p0.y + (p1.y - p0.y) * (bounding_box.left - p0.x) / (p1.x - p0.x); |
|
x = bounding_box.left; |
|
} |
|
|
|
|
|
|
|
if outcode_out == outcode0 { |
|
p0.x = x; |
|
p0.y = y; |
|
outcode0 = out_code(p0.x, p0.y, bounding_box); |
|
} else { |
|
p1.x = x; |
|
p1.y = y; |
|
outcode1 = out_code(p1.x, p1.y, bounding_box); |
|
} |
|
} |
|
} |
|
} |
|
|