1 | // pathfinder/geometry/src/basic/line_segment.rs |
2 | // |
3 | // Copyright © 2019 The Pathfinder Project Developers. |
4 | // |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your |
8 | // option. This file may not be copied, modified, or distributed |
9 | // except according to those terms. |
10 | |
11 | //! Line segment types, optimized with SIMD. |
12 | |
13 | use crate::transform2d::Matrix2x2F; |
14 | use crate::vector::{Vector2F, vec2f}; |
15 | use crate::util; |
16 | use pathfinder_simd::default::F32x4; |
17 | use std::ops::{Add, Mul, MulAssign, Sub}; |
18 | |
19 | #[derive (Clone, Copy, Debug, PartialEq, Default)] |
20 | pub struct LineSegment2F(pub F32x4); |
21 | |
22 | impl LineSegment2F { |
23 | #[inline ] |
24 | pub fn new(from: Vector2F, to: Vector2F) -> LineSegment2F { |
25 | LineSegment2F(from.0.concat_xy_xy(to.0)) |
26 | } |
27 | |
28 | #[inline ] |
29 | pub fn from(self) -> Vector2F { |
30 | Vector2F(self.0.xy()) |
31 | } |
32 | |
33 | #[inline ] |
34 | pub fn to(self) -> Vector2F { |
35 | Vector2F(self.0.zw()) |
36 | } |
37 | |
38 | #[inline ] |
39 | pub fn set_from(&mut self, point: Vector2F) { |
40 | self.0 = point.0.to_f32x4().concat_xy_zw(self.0) |
41 | } |
42 | |
43 | #[inline ] |
44 | pub fn set_to(&mut self, point: Vector2F) { |
45 | self.0 = self.0.concat_xy_xy(point.0.to_f32x4()) |
46 | } |
47 | |
48 | #[allow (clippy::wrong_self_convention)] |
49 | #[inline ] |
50 | pub fn from_x(self) -> f32 { |
51 | self.0[0] |
52 | } |
53 | |
54 | #[allow (clippy::wrong_self_convention)] |
55 | #[inline ] |
56 | pub fn from_y(self) -> f32 { |
57 | self.0[1] |
58 | } |
59 | |
60 | #[inline ] |
61 | pub fn to_x(self) -> f32 { |
62 | self.0[2] |
63 | } |
64 | |
65 | #[inline ] |
66 | pub fn to_y(self) -> f32 { |
67 | self.0[3] |
68 | } |
69 | |
70 | #[inline ] |
71 | pub fn set_from_x(&mut self, x: f32) { |
72 | self.0[0] = x |
73 | } |
74 | |
75 | #[inline ] |
76 | pub fn set_from_y(&mut self, y: f32) { |
77 | self.0[1] = y |
78 | } |
79 | |
80 | #[inline ] |
81 | pub fn set_to_x(&mut self, x: f32) { |
82 | self.0[2] = x |
83 | } |
84 | |
85 | #[inline ] |
86 | pub fn set_to_y(&mut self, y: f32) { |
87 | self.0[3] = y |
88 | } |
89 | |
90 | #[inline ] |
91 | pub fn split(self, t: f32) -> (LineSegment2F, LineSegment2F) { |
92 | debug_assert!(t >= 0.0 && t <= 1.0); |
93 | let (from_from, to_to) = (self.0.xyxy(), self.0.zwzw()); |
94 | let d_d = to_to - from_from; |
95 | let mid_mid = from_from + d_d * F32x4::splat(t); |
96 | ( |
97 | LineSegment2F(from_from.concat_xy_xy(mid_mid)), |
98 | LineSegment2F(mid_mid.concat_xy_xy(to_to)), |
99 | ) |
100 | } |
101 | |
102 | // Returns the left segment first, followed by the right segment. |
103 | #[inline ] |
104 | pub fn split_at_x(self, x: f32) -> (LineSegment2F, LineSegment2F) { |
105 | let (min_part, max_part) = self.split(self.solve_t_for_x(x)); |
106 | if min_part.from_x() < max_part.from_x() { |
107 | (min_part, max_part) |
108 | } else { |
109 | (max_part, min_part) |
110 | } |
111 | } |
112 | |
113 | // Returns the upper segment first, followed by the lower segment. |
114 | #[inline ] |
115 | pub fn split_at_y(self, y: f32) -> (LineSegment2F, LineSegment2F) { |
116 | let (min_part, max_part) = self.split(self.solve_t_for_y(y)); |
117 | |
118 | // Make sure we compare `from_y` and `to_y` to properly handle the case in which one of the |
119 | // two segments is zero-length. |
120 | if min_part.from_y() < max_part.to_y() { |
121 | (min_part, max_part) |
122 | } else { |
123 | (max_part, min_part) |
124 | } |
125 | } |
126 | |
127 | #[inline ] |
128 | pub fn solve_t_for_x(self, x: f32) -> f32 { |
129 | (x - self.from_x()) / (self.to_x() - self.from_x()) |
130 | } |
131 | |
132 | #[inline ] |
133 | pub fn solve_t_for_y(self, y: f32) -> f32 { |
134 | (y - self.from_y()) / (self.to_y() - self.from_y()) |
135 | } |
136 | |
137 | #[inline ] |
138 | pub fn solve_x_for_y(self, y: f32) -> f32 { |
139 | util::lerp(self.from_x(), self.to_x(), self.solve_t_for_y(y)) |
140 | } |
141 | |
142 | #[inline ] |
143 | pub fn solve_y_for_x(self, x: f32) -> f32 { |
144 | util::lerp(self.from_y(), self.to_y(), self.solve_t_for_x(x)) |
145 | } |
146 | |
147 | #[inline ] |
148 | pub fn reversed(self) -> LineSegment2F { |
149 | LineSegment2F(self.0.zwxy()) |
150 | } |
151 | |
152 | #[inline ] |
153 | pub fn upper_point(self) -> Vector2F { |
154 | if self.from_y() < self.to_y() { |
155 | self.from() |
156 | } else { |
157 | self.to() |
158 | } |
159 | } |
160 | |
161 | #[inline ] |
162 | pub fn min_x(self) -> f32 { |
163 | f32::min(self.from_x(), self.to_x()) |
164 | } |
165 | |
166 | #[inline ] |
167 | pub fn max_x(self) -> f32 { |
168 | f32::max(self.from_x(), self.to_x()) |
169 | } |
170 | |
171 | #[inline ] |
172 | pub fn min_y(self) -> f32 { |
173 | f32::min(self.from_y(), self.to_y()) |
174 | } |
175 | |
176 | #[inline ] |
177 | pub fn max_y(self) -> f32 { |
178 | f32::max(self.from_y(), self.to_y()) |
179 | } |
180 | |
181 | #[inline ] |
182 | pub fn y_winding(self) -> i32 { |
183 | if self.from_y() < self.to_y() { |
184 | 1 |
185 | } else { |
186 | -1 |
187 | } |
188 | } |
189 | |
190 | // Reverses if necessary so that the from point is above the to point. Calling this method |
191 | // again will undo the transformation. |
192 | #[inline ] |
193 | pub fn orient(self, y_winding: i32) -> LineSegment2F { |
194 | if y_winding >= 0 { |
195 | self |
196 | } else { |
197 | self.reversed() |
198 | } |
199 | } |
200 | |
201 | // TODO(pcwalton): Optimize with SIMD. |
202 | #[inline ] |
203 | pub fn square_length(self) -> f32 { |
204 | let (dx, dy) = (self.to_x() - self.from_x(), self.to_y() - self.from_y()); |
205 | dx * dx + dy * dy |
206 | } |
207 | |
208 | #[inline ] |
209 | pub fn vector(self) -> Vector2F { |
210 | self.to() - self.from() |
211 | } |
212 | |
213 | // http://www.cs.swan.ac.uk/~cssimon/line_intersection.html |
214 | pub fn intersection_t(self, other: LineSegment2F) -> Option<f32> { |
215 | let p0p1 = self.vector(); |
216 | let matrix = Matrix2x2F(other.vector().0.concat_xy_xy((-p0p1).0)); |
217 | if f32::abs(matrix.det()) < EPSILON { |
218 | return None; |
219 | } |
220 | return Some((matrix.inverse() * (self.from() - other.from())).y()); |
221 | |
222 | const EPSILON: f32 = 0.0001; |
223 | } |
224 | |
225 | #[inline ] |
226 | pub fn sample(self, t: f32) -> Vector2F { |
227 | self.from() + self.vector() * t |
228 | } |
229 | |
230 | #[inline ] |
231 | pub fn midpoint(self) -> Vector2F { |
232 | self.sample(0.5) |
233 | } |
234 | |
235 | #[inline ] |
236 | pub fn offset(self, distance: f32) -> LineSegment2F { |
237 | if self.is_zero_length() { |
238 | self |
239 | } else { |
240 | self + self.vector().yx().normalize() * vec2f(-distance, distance) |
241 | } |
242 | } |
243 | |
244 | #[inline ] |
245 | pub fn is_zero_length(self) -> bool { |
246 | self.vector().is_zero() |
247 | } |
248 | } |
249 | |
250 | impl Add<Vector2F> for LineSegment2F { |
251 | type Output = LineSegment2F; |
252 | #[inline ] |
253 | fn add(self, point: Vector2F) -> LineSegment2F { |
254 | LineSegment2F(self.0 + point.0.to_f32x4().xyxy()) |
255 | } |
256 | } |
257 | |
258 | impl Sub<Vector2F> for LineSegment2F { |
259 | type Output = LineSegment2F; |
260 | #[inline ] |
261 | fn sub(self, point: Vector2F) -> LineSegment2F { |
262 | LineSegment2F(self.0 - point.0.to_f32x4().xyxy()) |
263 | } |
264 | } |
265 | |
266 | impl Mul<Vector2F> for LineSegment2F { |
267 | type Output = LineSegment2F; |
268 | #[inline ] |
269 | fn mul(self, factors: Vector2F) -> LineSegment2F { |
270 | LineSegment2F(self.0 * factors.0.to_f32x4().xyxy()) |
271 | } |
272 | } |
273 | |
274 | impl Mul<f32> for LineSegment2F { |
275 | type Output = LineSegment2F; |
276 | #[inline ] |
277 | fn mul(self, factor: f32) -> LineSegment2F { |
278 | LineSegment2F(self.0 * F32x4::splat(factor)) |
279 | } |
280 | } |
281 | |
282 | impl MulAssign<Vector2F> for LineSegment2F { |
283 | #[inline ] |
284 | fn mul_assign(&mut self, factors: Vector2F) { |
285 | *self = *self * factors |
286 | } |
287 | } |
288 | |
289 | #[derive (Clone, Copy, Debug, Default)] |
290 | #[repr (C)] |
291 | pub struct LineSegmentU4 { |
292 | pub from: u8, |
293 | pub to: u8, |
294 | } |
295 | |
296 | #[derive (Clone, Copy, Debug, Default)] |
297 | #[repr (C)] |
298 | pub struct LineSegmentU8 { |
299 | pub from_x: u8, |
300 | pub from_y: u8, |
301 | pub to_x: u8, |
302 | pub to_y: u8, |
303 | } |
304 | |