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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
use super::*;
/// A polygonal chain connecting a vector of points in space
#[derive(Debug, Clone)]
pub struct Chain<T> {
/// List of points
pub vertices: Vec<vec2<T>>,
}
impl<T: Float> Chain<T> {
/// Construct a new chain
pub fn new(vertices: Vec<vec2<T>>) -> Self {
Self { vertices }
}
/// Returns the total length of the chain
pub fn length(&self) -> T
where
T: std::iter::Sum<T>,
{
self.vertices
.iter()
.zip(self.vertices.iter().skip(1))
.map(|(&a, &b)| (a - b).len())
.sum()
}
/// Returns a part of the chain. The full chain's range is `0.0..=1.0`.
///
/// # Examples
/// ```
/// # use batbox_la::*;
/// # use batbox_lapp::*;
/// let chain = Chain::new(vec![vec2(0.0, 0.0), vec2(1.0, 0.0), vec2(1.0, 1.0), vec2(0.0, 1.0)]);
/// assert_eq!(chain.clone().take_range_ratio(0.0..=1.0).vertices, chain.vertices);
/// ```
pub fn take_range_ratio(self, range: RangeInclusive<T>) -> Self
where
T: std::iter::Sum<T>,
{
let len = self.length();
let (start, end) = range.into_inner();
self.take_range_length(start * len..=end * len)
}
/// Returns a part of the chain. The full chain's range is `0.0..=chain.length()`.
///
/// # Examples
/// ```
/// # use batbox_la::*;
/// # use batbox_lapp::*;
/// let chain = Chain::new(vec![vec2(0.0, 0.0), vec2(1.0, 0.0), vec2(1.0, 1.0), vec2(0.0, 1.0)]);
/// assert_eq!(chain.clone().take_range_ratio(0.0..=chain.length()).vertices, chain.vertices);
/// ```
pub fn take_range_length(self, range: RangeInclusive<T>) -> Self {
let &(mut start_len) = range.start();
let &(mut end_len) = range.end();
let segments = self.vertices.iter().zip(self.vertices.iter().skip(1));
let mut start = self.vertices[0];
let mut start_i = 1;
for (i, (&a, &b)) in segments.enumerate() {
let len = (a - b).len();
start_len -= len;
if start_len < T::ZERO {
start = if len.approx_eq(&T::ZERO) {
b
} else {
b + (a - b) * (-start_len / len)
};
start_i = i + 1;
break;
}
end_len -= len;
}
let mut vertices = vec![start];
for i in start_i..self.vertices.len() {
let a = self.vertices[i - 1];
let b = self.vertices[i];
let len = (a - b).len();
end_len -= len;
if end_len <= T::ZERO {
let end = if len.approx_eq(&T::ZERO) {
b
} else {
b + (a - b) * (-end_len / len)
};
vertices.push(end);
break;
}
vertices.push(b);
}
Self { vertices }
}
/// Converts a chain into a vector of segments.
pub fn segments(&self) -> Vec<Segment<T>> {
let length = self.vertices.len();
if length < 2 {
return vec![];
}
let mut segments = Vec::with_capacity(length - 1);
let mut prev = self.vertices[0];
for &vertex in self.vertices.iter().skip(1) {
segments.push(Segment(prev, vertex));
prev = vertex;
}
segments
}
}