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