finite_element_method/fem/
convex_hull_on_plane.rs

1use std::fmt::Debug;
2use std::cmp::Ordering;
3
4use extended_matrix::FloatTrait;
5
6
7pub fn quick_sort<T>(arr: &mut [T])
8    where T: PartialOrd
9{
10    let len = arr.len();
11    _quick_sort(arr, 0, (len - 1) as isize);
12}
13
14
15fn _quick_sort<T>(arr: &mut [T], low: isize, high: isize)
16    where T: PartialOrd
17{
18    if low < high
19    {
20        let p = partition(arr, low, high);
21        _quick_sort(arr, low, p - 1);
22        _quick_sort(arr, p + 1, high);
23    }
24}
25
26
27fn partition<T>(arr: &mut [T], low: isize, high: isize) -> isize
28    where T: PartialOrd
29{
30    let pivot = high as usize;
31    let mut store_index = low - 1;
32    let mut last_index = high;
33
34    loop
35    {
36        store_index += 1;
37        while arr[store_index as usize] < arr[pivot]
38        {
39            store_index += 1;
40        }
41        last_index -= 1;
42        while last_index >= 0 && arr[last_index as usize] > arr[pivot]
43        {
44            last_index -= 1;
45        }
46        if store_index >= last_index
47        {
48            break;
49        }
50        else
51        {
52            arr.swap(store_index as usize, last_index as usize);
53        }
54    }
55    arr.swap(store_index as usize, pivot as usize);
56    store_index
57}
58
59
60#[derive(Debug, Clone)]
61pub struct Point<V>
62{
63    n: u32,
64    x: V,
65    y: V,
66}
67
68
69impl<V> Point<V>
70    where V: FloatTrait<Output = V>,
71{
72    pub fn create(n: u32, x: V, y: V) -> Self
73    {
74        Point { n, x, y }
75    }
76
77
78    fn vector_from_origin_to_point(&self) -> Vector<V>
79    {
80        Vector::create(0, V::from(0.0), V::from(0.0), self.n, self.x, self.y)
81    }
82
83
84    pub fn copy_number(&self) -> u32
85    {
86        self.n
87    }
88}
89
90
91impl<V> PartialOrd for Point<V>
92    where V: FloatTrait<Output = V>
93{
94    fn partial_cmp(&self, other: &Point<V>) -> Option<Ordering>
95    {
96        let directional_vector = Vector::create_directional_vector();
97        let lhs_vector_from_origin = self.vector_from_origin_to_point();
98        let rhs_vector_from_origin = other.vector_from_origin_to_point();
99        directional_vector
100            .cosine_of_angle_between_vectors(&lhs_vector_from_origin)
101            .my_acos()
102            .my_to_degrees()
103            .partial_cmp(
104                &(directional_vector
105                    .cosine_of_angle_between_vectors(&rhs_vector_from_origin)
106                    .my_acos()
107                )
108                .my_to_degrees()
109            )
110    }
111}
112
113
114impl<V> PartialEq for Point<V>
115    where V: FloatTrait<Output = V>
116{
117    fn eq(&self, other: &Point<V>) -> bool
118    {
119        let directional_vector = Vector::create_directional_vector();
120        let lhs_vector_from_origin = self.vector_from_origin_to_point();
121        let rhs_vector_from_origin = other.vector_from_origin_to_point();
122        directional_vector
123            .cosine_of_angle_between_vectors(&lhs_vector_from_origin)
124            .my_acos()
125            .my_to_degrees() ==
126        directional_vector
127            .cosine_of_angle_between_vectors(&rhs_vector_from_origin)
128            .my_acos()
129            .my_to_degrees()
130
131    }
132}
133
134
135#[derive(Debug)]
136struct Vector<V>
137{
138    point_1: Point<V>,
139    point_2: Point<V>,
140}
141
142
143fn double_signed_area<V>(p_1: &Point<V>, p_2: &Point<V>, p_3: &Point<V>) -> V
144    where V: FloatTrait<Output = V>
145{
146    (p_2.x - p_1.x) * (p_3.y - p_1.y) - (p_2.y - p_1.y) * (p_3.x - p_1.x)
147}
148
149
150impl<V> Vector<V>
151    where V: FloatTrait<Output = V>
152{
153    fn create_directional_vector() -> Self
154    {
155        Vector::create(0, V::from(0.0), V::from(0.0), 0, V::from(1.0), V::from(0.0))
156    }
157
158
159    fn create(n_1: u32, x_1: V, y_1: V, n_2: u32, x_2: V, y_2: V) -> Self
160    {
161        let point_1 = Point { n: n_1, x: x_1, y: y_1 };
162        let point_2 = Point { n: n_2, x: x_2, y: y_2 };
163        Vector { point_1, point_2 }
164    }
165
166    fn vector_length(&self) -> V
167    {
168        (
169            (self.point_1.x - self.point_2.x) * (self.point_1.x - self.point_2.x) +
170            (self.point_1.y - self.point_2.y) * (self.point_1.y - self.point_2.y)
171        ).my_sqrt()
172    }
173
174
175    fn scalar_product(&self, other: &Vector<V>) -> V
176    {
177        (self.point_1.x - self.point_2.x) * (other.point_1.x - other.point_2.x) +
178        (self.point_1.y - self.point_2.y) * (other.point_1.y - other.point_2.y)
179    }
180
181
182    fn cosine_of_angle_between_vectors(&self, other: &Vector<V>) -> V
183    {
184        let lhs_length = self.vector_length();
185        let rhs_length = other.vector_length();
186        let scalar_product = self.scalar_product(other);
187        scalar_product / (lhs_length * rhs_length)
188    }
189}
190
191
192pub fn convex_hull_on_plane<V>(data: &[Point<V>]) -> Vec<Point<V>>
193    where V: FloatTrait<Output = V>,
194{
195    let mut updated_data = data.to_vec();
196    let mut shift_x = updated_data[0].x;
197    let mut min_y = updated_data[0].y;
198    let mut min_y_position = 0;
199    for i in 0..updated_data.len()
200    {
201        if updated_data[i].y < min_y
202        {
203            shift_x = updated_data[i].x;
204            min_y = updated_data[i].y;
205            min_y_position = i;
206        }
207    }
208    updated_data.swap(0, min_y_position);
209    for i in 0..updated_data.len()
210    {
211        updated_data[i].x -= shift_x;
212        updated_data[i].y -= min_y;
213    }
214    quick_sort(&mut updated_data[1..]);
215    let mut i = 0;
216    while i + 2 < updated_data.len()
217    {
218        let doubled_area = double_signed_area(
219            &updated_data[i], &updated_data[i + 1], &updated_data[i + 2]);
220        if doubled_area <= V::from(0.0)
221        {
222            updated_data.remove(i + 1);
223        }
224        else
225        {
226            i += 1;
227        }
228    }
229    for i in 0..updated_data.len()
230    {
231        updated_data[i].x += shift_x;
232        updated_data[i].y += min_y;
233    }
234    updated_data
235}