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
use N;
use line_path::LinePath;
use closed_line_path::ClosedLinePath;
use areas::Area;
#[derive(Clone)]
#[cfg_attr(feature = "compact_containers", derive(Compact))]
#[cfg_attr(feature = "serde-serialization", derive(Serialize, Deserialize))]
pub struct Band {
pub path: LinePath,
pub width_left: N,
pub width_right: N,
}
impl Band {
pub fn new(path: LinePath, width: N) -> Band {
Band {
path,
width_left: width / 2.0,
width_right: width / 2.0,
}
}
pub fn new_asymmetric(path: LinePath, width_left: N, width_right: N) -> Band {
Band {
path,
width_left,
width_right,
}
}
pub fn outline(&self) -> ClosedLinePath {
let left_path = self
.path
.shift_orthogonally(-self.width_left)
.unwrap_or_else(|| self.path.clone());
let right_path = self
.path
.shift_orthogonally(self.width_right)
.unwrap_or_else(|| self.path.clone())
.reverse();
ClosedLinePath::new(
LinePath::new(
left_path
.points
.iter()
.chain(right_path.points.iter())
.chain(left_path.points.first())
.cloned()
.collect(),
).expect("Band path should always be valid"),
).expect("Band path should always be closed")
}
pub fn outline_distance_to_path_distance(&self, distance: N) -> N {
let full_width = self.width_left + self.width_right;
if let (Some(left_path_length), Some(right_path_length)) = (
self.path
.shift_orthogonally(-self.width_left)
.map(|p| p.length()),
self.path
.shift_orthogonally(self.width_right)
.map(|p| p.length()),
) {
if distance > left_path_length + full_width + right_path_length {
0.0
} else if distance > left_path_length + full_width {
(1.0 - (distance - left_path_length - full_width) / right_path_length)
* self.path.length()
} else if distance > left_path_length {
self.path.length()
} else {
(distance / left_path_length) * self.path.length()
}
} else {
distance
}
}
pub fn as_area(&self) -> Area {
Area::new_simple(self.outline())
}
}