parry3d/query/clip/
clip_halfspace_polygon.rs

1use crate::math::{Point, Real, Vector};
2use crate::query::{self, Ray};
3use alloc::vec::Vec;
4
5/// Cuts a polygon with the given half-space.
6///
7/// Given the half-space `center` and outward `normal`,
8/// this computes the intersecting between the half-space and
9/// the polygon. (Note that a point `pt` is considered as inside of
10/// the half-space if `normal.dot(&(pt - center)) <= 0.0`.
11pub fn clip_halfspace_polygon(
12    center: &Point<Real>,
13    normal: &Vector<Real>,
14    polygon: &[Point<Real>],
15    result: &mut Vec<Point<Real>>,
16) {
17    result.clear();
18
19    if polygon.is_empty() {
20        return;
21    }
22
23    let keep_point = |pt: &Point<Real>| (pt - center).dot(normal) <= 0.0;
24    let last_pt = polygon.last().unwrap();
25    let mut last_keep = keep_point(last_pt);
26
27    if last_keep {
28        result.push(*last_pt);
29    }
30
31    for i in 0..polygon.len() {
32        let pt = &polygon[i];
33        let keep = keep_point(pt);
34
35        if keep != last_keep {
36            // We crossed the plane, so we need
37            // to cut the edge.
38            let prev_i = if i == 0 { polygon.len() - 1 } else { i - 1 };
39            let prev_pt = &polygon[prev_i];
40            let ray = Ray::new(*prev_pt, pt - prev_pt);
41
42            if let Some(time_of_impact) =
43                query::details::ray_toi_with_halfspace(center, normal, &ray)
44            {
45                if time_of_impact > 0.0 && time_of_impact < 1.0 {
46                    result.push(ray.origin + ray.dir * time_of_impact)
47                }
48            }
49
50            last_keep = keep;
51        }
52
53        if keep && i != polygon.len() - 1 {
54            result.push(*pt);
55        }
56    }
57}