jagua_rs/geometry/
convex_hull.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
use crate::fsize;
use crate::geometry::primitives::point::Point;
use crate::geometry::primitives::simple_polygon::SimplePolygon;
use ordered_float::OrderedFloat;

/// Returns the indices of the points in the [SimplePolygon] that form the [convex hull](https://en.wikipedia.org/wiki/Convex_hull)
pub fn convex_hull_indices(shape: &SimplePolygon) -> Vec<usize> {
    let c_hull = convex_hull_from_points(shape.points.clone());
    let mut indices = vec![];
    for p in c_hull.iter() {
        indices.push(shape.points.iter().position(|x| x == p).unwrap());
    }
    indices
}

pub fn convex_hull_from_shapes<'a>(
    shapes: impl IntoIterator<Item = &'a SimplePolygon>,
) -> Vec<Point> {
    let mut ch_points = vec![];
    for shape in shapes {
        if let Some(surr) = shape.surrogate.as_ref() {
            ch_points.extend(surr.convex_hull_indices.iter().map(|&i| shape.points[i]));
        } else {
            ch_points.extend(convex_hull_indices(shape).iter().map(|&i| shape.points[i]));
        }
    }

    convex_hull_from_points(ch_points)
}

/// Filters a set of points to only include the points that form the [convex hull](https://en.wikipedia.org/wiki/Convex_hull)
pub fn convex_hull_from_points(mut points: Vec<Point>) -> Vec<Point> {
    //https://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chain

    //sort the points by x coordinate
    points.sort_by_key(|p| OrderedFloat(p.0));

    let mut lower_hull = points
        .iter()
        .fold(vec![], |hull, p| grow_convex_hull(hull, *p));
    let mut upper_hull = points
        .iter()
        .rev()
        .fold(vec![], |hull, p| grow_convex_hull(hull, *p));

    //First and last element of both hull parts are the same point
    upper_hull.pop();
    lower_hull.pop();

    lower_hull.append(&mut upper_hull);
    lower_hull
}

fn grow_convex_hull(mut h: Vec<Point>, next: Point) -> Vec<Point> {
    //pop all points from the hull which will be made irrelevant due to the new point
    while h.len() >= 2 && cross(h[h.len() - 2], h[h.len() - 1], next) <= 0.0 {
        h.pop();
    }
    h.push(next);
    h
}

fn cross(a: Point, b: Point, c: Point) -> fsize {
    (b.0 - a.0) * (c.1 - a.1) - (b.1 - a.1) * (c.0 - a.0)
}