| 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); |
| } |
| } |
| } |
| } |
|
|