1 //! Various methods for computing with vectors.
2 
3 pub use vecmath::row_mat2x3_mul as multiply;
4 pub use vecmath::vec2_dot as dot;
5 pub use vecmath::vec2_cross as cross;
6 pub use vecmath::vec2_add as add;
7 pub use vecmath::vec2_sub as sub;
8 pub use vecmath::vec2_cast as cast;
9 pub use vecmath::vec2_mul as mul;
10 pub use vecmath::vec2_scale as mul_scalar;
11 pub use vecmath::vec2_square_len as square_len;
12 pub use vecmath::row_mat2x3_transform_pos2 as transform_pos;
13 pub use vecmath::row_mat2x3_transform_vec2 as transform_vec;
14 
15 use std::ops::{Add, Rem};
16 use vecmath;
17 use vecmath::traits::Float;
18 use types::{Area, Color, Line, Polygon, Ray, Rectangle, SourceRectangle, Triangle};
19 use modular_index::previous;
20 
21 /// The type used for scalars.
22 pub type Scalar = f64;
23 
24 /// The type used for matrices.
25 pub type Matrix2d<T = Scalar> = vecmath::Matrix2x3<T>;
26 
27 /// The type used for 2D vectors.
28 pub type Vec2d<T = Scalar> = vecmath::Vector2<T>;
29 
30 /// The type used for 3D vectors.
31 pub type Vec3d<T = Scalar> = vecmath::Vector3<T>;
32 
33 /// Creates a perpendicular vector.
34 #[inline(always)]
perp<T>(v: [T; 2]) -> [T; 2] where T: Float35 pub fn perp<T>(v: [T; 2]) -> [T; 2]
36     where T: Float
37 {
38     [-v[1], v[0]]
39 }
40 
41 /// Transforms from normalized to absolute coordinates.
42 ///
43 /// Computes absolute transform from width and height of viewport.
44 /// In absolute coordinates, the x axis points to the right,
45 /// and the y axis points down on the screen.
46 #[inline(always)]
abs_transform<T>(w: T, h: T) -> Matrix2d<T> where T: Float47 pub fn abs_transform<T>(w: T, h: T) -> Matrix2d<T>
48     where T: Float
49 {
50     use vecmath::traits::{One, FromPrimitive, Zero};
51 
52     let _0: T = Zero::zero();
53     let _1: T = One::one();
54     let _2: T = FromPrimitive::from_f64(2.0);
55     let sx = _2 / w;
56     let sy = -_2 / h;
57     [[sx, _0, -_1], [_0, sy, _1]]
58 }
59 
60 /// Creates a translation matrix.
61 #[inline(always)]
translate<T>(v: Vec2d<T>) -> Matrix2d<T> where T: Float62 pub fn translate<T>(v: Vec2d<T>) -> Matrix2d<T>
63     where T: Float
64 {
65     use vecmath::traits::{One, Zero};
66 
67     let _0: T = Zero::zero();
68     let _1: T = One::one();
69     [[_1, _0, v[0]], [_0, _1, v[1]]]
70 }
71 
72 /// Creates a rotation matrix.
73 #[inline(always)]
rotate_radians<T>(angle: T) -> Matrix2d<T> where T: Float74 pub fn rotate_radians<T>(angle: T) -> Matrix2d<T>
75     where T: Float
76 {
77     use vecmath::traits::Zero;
78 
79     let _0 = Zero::zero();
80     let c = angle.cos();
81     let s = angle.sin();
82     [[c, -s, _0], [s, c, _0]]
83 }
84 
85 /// Orients x axis to look at point.
86 ///
87 /// Leaves x axis unchanged if the
88 /// point to look at is the origin.
89 #[inline(always)]
orient<T>(x: T, y: T) -> Matrix2d<T> where T: Float90 pub fn orient<T>(x: T, y: T) -> Matrix2d<T>
91     where T: Float
92 {
93     use vecmath::traits::Zero;
94 
95     let _0: T = Zero::zero();
96     let len = x * x + y * y;
97     if len == _0 {
98         return identity();
99     }
100 
101     let len = len.sqrt();
102     let c = x / len;
103     let s = y / len;
104     [[c, -s, _0], [s, c, _0]]
105 }
106 
107 /// Create a scale matrix.
108 #[inline(always)]
scale<T>(sx: T, sy: T) -> Matrix2d<T> where T: Float109 pub fn scale<T>(sx: T, sy: T) -> Matrix2d<T>
110     where T: Float
111 {
112     use vecmath::traits::Zero;
113 
114     let _0: T = Zero::zero();
115     [[sx, _0, _0], [_0, sy, _0]]
116 }
117 
118 /// Create a shear matrix.
119 #[inline(always)]
shear<T>(v: Vec2d<T>) -> Matrix2d<T> where T: Float120 pub fn shear<T>(v: Vec2d<T>) -> Matrix2d<T>
121     where T: Float
122 {
123     use vecmath::traits::{Zero, One};
124 
125     let _0 = Zero::zero();
126     let _1 = One::one();
127     [[_1, v[0], _0], [v[1], _1, _0]]
128 }
129 
130 /// Create an identity matrix.
131 #[inline(always)]
identity<T>() -> Matrix2d<T> where T: Float132 pub fn identity<T>() -> Matrix2d<T>
133     where T: Float
134 {
135     use vecmath::traits::{Zero, One};
136 
137     let _0: T = Zero::zero();
138     let _1: T = One::one();
139     [[_1, _0, _0], [_0, _1, _0]]
140 }
141 
142 /// Extract scale information from matrix.
143 #[inline(always)]
get_scale<T>(m: Matrix2d<T>) -> Vec2d<T> where T: Float144 pub fn get_scale<T>(m: Matrix2d<T>) -> Vec2d<T>
145     where T: Float
146 {
147     [(m[0][0] * m[0][0] + m[1][0] * m[1][0]).sqrt(), (m[0][1] * m[0][1] + m[1][1] * m[1][1]).sqrt()]
148 }
149 
150 /// Compute the shortest vector from point to ray.
151 /// A ray stores starting point and directional vector.
152 #[inline(always)]
separation<T>(ray: Ray<T>, v: Vec2d<T>) -> Vec2d<T> where T: Float153 pub fn separation<T>(ray: Ray<T>, v: Vec2d<T>) -> Vec2d<T>
154     where T: Float
155 {
156     // Get the directional vector.
157     let (dir_x, dir_y) = (ray[2], ray[3]);
158     // Get displacement vector from point.
159     let (dx, dy) = (ray[0] - v[0], ray[1] - v[1]);
160     // Compute the component of position in ray direction.
161     let dot = dir_x * v[0] + dir_y * v[1];
162     // The directional vector multiplied with
163     // the dot gives us a parallel vector.
164     // When we subtract this from the displacement
165     // we get a vector normal to the ray.
166     // This is the shortest vector from the point to the ray.
167     [dx - dot * dir_x, dy - dot * dir_y]
168 }
169 
170 /// Returns the least separation out of four.
171 /// Each seperation can be computed using `separation` function.
172 /// The separation returned can be used
173 /// to solve collision of rectangles.
174 #[inline(always)]
least_separation_4<T>(sep1: Vec2d<T>, sep2: Vec2d<T>, sep3: Vec2d<T>, sep4: Vec2d<T>) -> Vec2d<T> where T: Float175 pub fn least_separation_4<T>(sep1: Vec2d<T>,
176                              sep2: Vec2d<T>,
177                              sep3: Vec2d<T>,
178                              sep4: Vec2d<T>)
179                              -> Vec2d<T>
180     where T: Float
181 {
182     let dot1 = sep1[0] * sep1[0] + sep1[1] * sep1[1];
183     let dot2 = sep2[0] * sep2[0] + sep2[1] * sep2[1];
184     let dot3 = sep3[0] * sep3[0] + sep3[1] * sep3[1];
185     let dot4 = sep4[0] * sep4[0] + sep4[1] * sep4[1];
186     // Search for the smallest dot product.
187     if dot1 < dot2 {
188         if dot3 < dot4 {
189             if dot1 < dot3 { sep1 } else { sep3 }
190         } else {
191             if dot1 < dot4 { sep1 } else { sep4 }
192         }
193     } else {
194         if dot3 < dot4 {
195             if dot2 < dot3 { sep2 } else { sep3 }
196         } else {
197             if dot2 < dot4 { sep2 } else { sep4 }
198         }
199     }
200 }
201 
202 /// Shrinks a rectangle by a factor on all sides.
203 #[inline(always)]
margin_rectangle<T>(rect: Rectangle<T>, m: T) -> Rectangle<T> where T: Float204 pub fn margin_rectangle<T>(rect: Rectangle<T>, m: T) -> Rectangle<T>
205     where T: Float
206 {
207     use vecmath::traits::{Zero, FromPrimitive};
208 
209     let _0: T = Zero::zero();
210     let _05: T = FromPrimitive::from_f64(0.5);
211     let _2: T = FromPrimitive::from_f64(2.0);
212     let w = rect[2] - _2 * m;
213     let h = rect[3] - _2 * m;
214     let (x, w) = if w < _0 {
215         (rect[0] + _05 * rect[2], _0)
216     } else {
217         (rect[0] + m, w)
218     };
219     let (y, h) = if h < _0 {
220         (rect[1] + _05 * rect[3], _0)
221     } else {
222         (rect[1] + m, h)
223     };
224     [x, y, w, h]
225 }
226 
227 /// Computes a relative rectangle using the rectangle as a tile.
228 #[inline(always)]
relative_rectangle<T>(rect: Rectangle<T>, v: Vec2d<T>) -> Rectangle<T> where T: Float229 pub fn relative_rectangle<T>(rect: Rectangle<T>, v: Vec2d<T>) -> Rectangle<T>
230     where T: Float
231 {
232     [rect[0] + v[0] * rect[2], rect[1] + v[1] * rect[3], rect[2], rect[3]]
233 }
234 
235 /// Computes overlap between two rectangles.
236 /// The area of the overlapping rectangle is positive.
237 /// A shared edge or corner is not considered overlap.
238 #[inline(always)]
overlap_rectangle<T>(a: Rectangle<T>, b: Rectangle<T>) -> Option<Rectangle<T>> where T: Float239 pub fn overlap_rectangle<T>(a: Rectangle<T>, b: Rectangle<T>) -> Option<Rectangle<T>>
240     where T: Float
241 {
242     #[inline(always)]
243     fn min<T: Float>(a: T, b: T) -> T {
244         if a < b { a } else { b }
245     }
246 
247     #[inline(always)]
248     fn max<T: Float>(a: T, b: T) -> T {
249         if a > b { a } else { b }
250     }
251 
252     if a[0] < b[0] + b[2] && a[1] < b[1] + b[3] && b[0] < a[0] + a[2] && b[1] < a[1] + a[3] {
253         let x = max(a[0], b[0]);
254         let y = max(a[1], b[1]);
255         let w = min(a[0] + a[2], b[0] + b[2]) - x;
256         let h = min(a[1] + a[3], b[1] + b[3]) - y;
257         Some([x, y, w, h])
258     } else {
259         None
260     }
261 }
262 
263 #[cfg(test)]
264 mod test_overlap {
265     use super::overlap_rectangle;
266 
267     #[test]
overlap()268     fn overlap() {
269         let a = [0.0, 1.0, 100.0, 101.0];
270         let b = [51.0, 52.0, 102.0, 103.0];
271         let c = overlap_rectangle(a, b).unwrap();
272         assert_eq!(c, [51.0, 52.0, 49.0, 50.0]);
273         let d = overlap_rectangle(a, c).unwrap();
274         assert_eq!(d, c);
275         let e = overlap_rectangle(b, c).unwrap();
276         assert_eq!(e, c);
277     }
278 
279     #[test]
edge()280     fn edge() {
281         let a = [0.0, 0.0, 100.0, 100.0];
282         let b = [100.0, 0.0, 100.0, 100.0];
283         let c = overlap_rectangle(a, b);
284         assert_eq!(c, None);
285     }
286 }
287 
288 /// Computes a relative source rectangle using
289 /// the source rectangle as a tile.
290 #[inline(always)]
relative_source_rectangle<T>(rect: SourceRectangle<T>, x: T, y: T) -> SourceRectangle<T> where T: Float291 pub fn relative_source_rectangle<T>(rect: SourceRectangle<T>, x: T, y: T) -> SourceRectangle<T>
292     where T: Float
293 {
294     let (rx, ry, rw, rh) = (rect[0], rect[1], rect[2], rect[3]);
295     let (x, y) = (rx + x * rw, ry + y * rh);
296     [x, y, rw, rh]
297 }
298 
299 /// Computes modular offset safely for numbers.
300 #[inline(always)]
modular_offset<T: Add<Output = T> + Rem<Output = T> + Copy>(n: &T, i: &T, off: &T) -> T301 pub fn modular_offset<T: Add<Output = T> + Rem<Output = T> + Copy>(n: &T, i: &T, off: &T) -> T {
302     (*i + (*off % *n + *n)) % *n
303 }
304 
305 #[cfg(test)]
306 mod test_modular_offset {
307     use super::*;
308 
309     #[test]
test_modular_offset()310     fn test_modular_offset() {
311         assert_eq!(modular_offset(&3.0_f64, &0.0_f64, &-1.0_f64), 2.0_f64);
312         assert_eq!(modular_offset(&3.0_f64, &1.0_f64, &-1.0_f64), 0.0_f64);
313         assert_eq!(modular_offset(&3.0_f64, &2.0_f64, &-1.0_f64), 1.0_f64);
314         assert_eq!(modular_offset(&3.0_f64, &3.0_f64, &-1.0_f64), 2.0_f64);
315 
316         assert_eq!(modular_offset(&3.0_f64, &0.0_f64, &1.0_f64), 1.0_f64);
317         assert_eq!(modular_offset(&3.0_f64, &1.0_f64, &1.0_f64), 2.0_f64);
318         assert_eq!(modular_offset(&3.0_f64, &2.0_f64, &1.0_f64), 0.0_f64);
319         assert_eq!(modular_offset(&3.0_f64, &3.0_f64, &1.0_f64), 1.0_f64);
320     }
321 }
322 
323 /// Computes the area and centroid of a simple polygon.
324 ///
325 /// A simple polygon is one that does not intersect itself.
326 /// Source: http://en.wikipedia.org/wiki/Polygon_area#Simple_polygons
area_centroid<T>(polygon: Polygon<T>) -> (Area<T>, Vec2d<T>) where T: Float327 pub fn area_centroid<T>(polygon: Polygon<T>) -> (Area<T>, Vec2d<T>)
328     where T: Float
329 {
330     use vecmath::traits::{Zero, FromPrimitive};
331 
332     let _0: T = Zero::zero();
333     let _05: T = FromPrimitive::from_f64(0.5);
334     let _3: T = FromPrimitive::from_f64(3.0);
335     let n = polygon.len();
336     let mut sum = _0;
337     let (mut cx, mut cy) = (_0, _0);
338     for i in 0..n {
339         let qx = polygon[i][0];
340         let qy = polygon[i][1];
341         let p_i = previous(n, i);
342         let px = polygon[p_i][0];
343         let py = polygon[p_i][1];
344         let cross = px * qy - qx * py;
345         cx = cx + (px + qx) * cross;
346         cy = cy + (py + qy) * cross;
347         sum = sum + cross;
348     }
349 
350     let area = _05 * sum;
351     // 'cx / (6.0 * area)' = 'cx / (3.0 * sum)'
352     let centroid = [cx / (_3 * sum), cy / (_3 * sum)];
353     (area, centroid)
354 }
355 
356 /// Computes area of a simple polygon.
357 ///
358 /// A simple polygon is one that does not intersect itself.
359 #[inline(always)]
area<T>(polygon: Polygon<T>) -> T where T: Float360 pub fn area<T>(polygon: Polygon<T>) -> T
361     where T: Float
362 {
363     let (res, _) = area_centroid(polygon);
364     res
365 }
366 
367 /// Computes centroid of a simple polygon.
368 ///
369 /// A simple polygon is one that does not intersect itself.
370 #[inline(always)]
centroid<T>(polygon: Polygon<T>) -> Vec2d<T> where T: Float371 pub fn centroid<T>(polygon: Polygon<T>) -> Vec2d<T>
372     where T: Float
373 {
374     let (_, res) = area_centroid(polygon);
375     res
376 }
377 
378 /// Returns a number that tells which side it is relative to a line.
379 ///
380 /// Computes the cross product of the vector that gives the line
381 /// with the vector between point and starting point of line.
382 /// One side of the line has opposite sign of the other.
383 #[inline(always)]
line_side<T>(line: Line<T>, v: Vec2d<T>) -> T where T: Float384 pub fn line_side<T>(line: Line<T>, v: Vec2d<T>) -> T
385     where T: Float
386 {
387     let (ax, ay) = (line[0], line[1]);
388     let (bx, by) = (line[2], line[3]);
389     (bx - ax) * (v[1] - ay) - (by - ay) * (v[0] - ax)
390 }
391 
392 /// Returns true if point is inside triangle.
393 ///
394 /// This is done by computing a `side` number for each edge.
395 /// If the number is inside if it is on the same side for all edges.
396 /// Might break for very small triangles.
inside_triangle<T>(triangle: Triangle<T>, v: Vec2d<T>) -> bool where T: Float397 pub fn inside_triangle<T>(triangle: Triangle<T>, v: Vec2d<T>) -> bool
398     where T: Float
399 {
400     use vecmath::traits::Zero;
401 
402     let _0: T = Zero::zero();
403 
404     let ax = triangle[0][0];
405     let ay = triangle[0][1];
406     let bx = triangle[1][0];
407     let by = triangle[1][1];
408     let cx = triangle[2][0];
409     let cy = triangle[2][1];
410 
411     let ab_side = line_side([ax, ay, bx, by], v);
412     let bc_side = line_side([bx, by, cx, cy], v);
413     let ca_side = line_side([cx, cy, ax, ay], v);
414 
415     let ab_positive = ab_side >= _0;
416     let bc_positive = bc_side >= _0;
417     let ca_positive = ca_side >= _0;
418 
419     ab_positive == bc_positive && bc_positive == ca_positive
420 }
421 
422 /// Returns true if triangle is clockwise.
423 ///
424 /// This is done by computing which side the third vertex is relative to
425 /// the line starting from the first vertex to second vertex.
426 ///
427 /// The triangle is considered clockwise if the third vertex is on the line
428 /// between the two first vertices.
429 #[inline(always)]
triangle_face<T>(triangle: Triangle<T>) -> bool where T: Float430 pub fn triangle_face<T>(triangle: Triangle<T>) -> bool
431     where T: Float
432 {
433     use vecmath::traits::Zero;
434 
435     let _0 = Zero::zero();
436 
437     let ax = triangle[0][0];
438     let ay = triangle[0][1];
439     let bx = triangle[1][0];
440     let by = triangle[1][1];
441     let cx = triangle[2][0];
442     let cy = triangle[2][1];
443 
444     let ab_side = line_side([ax, ay, bx, by], [cx, cy]);
445 
446     ab_side <= _0
447 }
448 
449 #[cfg(test)]
450 mod test_triangle {
451     use super::*;
452 
453     #[test]
test_triangle()454     fn test_triangle() {
455         // Triangle counter clock-wise.
456         let tri_1 = [[0.0, 0.0], [1.0, 0.0], [1.0, 1.0]];
457         // Triangle clock-wise.
458         let tri_2 = [[0.0, 0.0], [1.0, 1.0], [1.0, 0.0]];
459         let (x, y) = (0.5, 0.25);
460         assert_eq!(inside_triangle(tri_1, [x, y]), true);
461         assert_eq!(inside_triangle(tri_2, [x, y]), true);
462         assert_eq!(triangle_face(tri_1), false);
463         assert_eq!(triangle_face(tri_2), true);
464     }
465 }
466 
467 /// Transforms from cartesian coordinates to barycentric.
468 #[inline(always)]
to_barycentric<T>(triangle: Triangle<T>, pos: Vec2d<T>) -> Vec3d<T> where T: Float469 pub fn to_barycentric<T>(triangle: Triangle<T>, pos: Vec2d<T>) -> Vec3d<T>
470     where T: Float
471 {
472     use vecmath::traits::One;
473 
474     let _1: T = One::one();
475     let x = pos[0];
476     let y = pos[1];
477     let x1 = triangle[0][0];
478     let y1 = triangle[0][1];
479     let x2 = triangle[1][0];
480     let y2 = triangle[1][1];
481     let x3 = triangle[2][0];
482     let y3 = triangle[2][1];
483     let lambda1 = ((y2 - y3) * (x - x3) + (x3 - x2) * (y - y3)) /
484                   ((y2 - y3) * (x1 - x3) + (x3 - x2) * (y1 - y3));
485     let lambda2 = ((y3 - y1) * (x - x3) + (x1 - x3) * (y - y3)) /
486                   ((y2 - y3) * (x1 - x3) + (x3 - x2) * (y1 - y3));
487     let lambda3 = _1 - lambda1 - lambda2;
488     [lambda1, lambda2, lambda3]
489 }
490 
491 /// Transforms from barycentric coordinates to cartesian.
492 #[inline(always)]
from_barycentric<T>(triangle: Triangle<T>, lambda: Vec3d<T>) -> Vec2d<T> where T: Float493 pub fn from_barycentric<T>(triangle: Triangle<T>, lambda: Vec3d<T>) -> Vec2d<T>
494     where T: Float
495 {
496     let x1 = triangle[0][0];
497     let y1 = triangle[0][1];
498     let x2 = triangle[1][0];
499     let y2 = triangle[1][1];
500     let x3 = triangle[2][0];
501     let y3 = triangle[2][1];
502     [lambda[0] * x1 + lambda[1] * x2 + lambda[2] * x3,
503      lambda[0] * y1 + lambda[1] * y2 + lambda[2] * y3]
504 }
505 
506 #[cfg(test)]
507 mod test_barycentric {
508     use super::*;
509 
510     #[test]
test_barycentric()511     fn test_barycentric() {
512         let triangle = [[0.0, 0.0], [100.0, 0.0], [0.0, 50.0]];
513         let old_pos = [10.0, 20.0];
514         let b = to_barycentric(triangle, old_pos);
515         let new_pos: Vec2d = from_barycentric(triangle, b);
516         let eps = 0.00001;
517         assert!((new_pos[0] - old_pos[0]).abs() < eps);
518         assert!((new_pos[1] - old_pos[1]).abs() < eps);
519     }
520 }
521 
522 /// Transform color with hue, saturation and value.
523 ///
524 /// Source: http://beesbuzz.biz/code/hsv_color_transforms.php
525 #[inline(always)]
hsv(color: Color, h_rad: f32, s: f32, v: f32) -> Color526 pub fn hsv(color: Color, h_rad: f32, s: f32, v: f32) -> Color {
527     let vsu = v * s * h_rad.cos();
528     let vsw = v * s * h_rad.sin();
529     [(0.299 * v + 0.701 * vsu + 0.168 * vsw) * color[0] +
530      (0.587 * v - 0.587 * vsu + 0.330 * vsw) * color[1] +
531      (0.114 * v - 0.114 * vsu - 0.497 * vsw) * color[2],
532      (0.299 * v - 0.299 * vsu - 0.328 * vsw) * color[0] +
533      (0.587 * v + 0.413 * vsu + 0.035 * vsw) * color[1] +
534      (0.114 * v - 0.114 * vsu + 0.292 * vsw) * color[2],
535      (0.299 * v - 0.3 * vsu + 1.25 * vsw) * color[0] +
536      (0.587 * v - 0.588 * vsu - 1.05 * vsw) * color[1] +
537      (0.114 * v + 0.886 * vsu - 0.203 * vsw) * color[2],
538      color[3]]
539 }
540