ncollide3d/utils/
triangle.rs
1use crate::math::Point;
2use crate::utils;
3use na;
4use simba::scalar::RealField;
5
6#[inline]
8pub fn triangle_area<N: RealField + Copy>(pa: &Point<N>, pb: &Point<N>, pc: &Point<N>) -> N {
9 let mut a = na::distance(pa, pb);
11 let mut b = na::distance(pb, pc);
12 let mut c = na::distance(pc, pa);
13
14 let (c, b, a) = utils::sort3(&mut a, &mut b, &mut c);
15 let a = *a;
16 let b = *b;
17 let c = *c;
18
19 let sqr = (a + (b + c)) * (c - (a - b)) * (c + (a - b)) * (a + (b - c));
20
21 sqr.sqrt() * na::convert(0.25)
22}
23
24#[inline]
26pub fn triangle_center<N: RealField + Copy>(
27 pa: &Point<N>,
28 pb: &Point<N>,
29 pc: &Point<N>,
30) -> Point<N> {
31 utils::center(&[*pa, *pb, *pc])
32}
33
34#[inline]
36pub fn triangle_perimeter<N: RealField + Copy>(pa: &Point<N>, pb: &Point<N>, pc: &Point<N>) -> N {
37 na::distance(pa, pb) + na::distance(pb, pc) + na::distance(pc, pa)
38}
39
40pub fn circumcircle<N: RealField + Copy>(
42 pa: &Point<N>,
43 pb: &Point<N>,
44 pc: &Point<N>,
45) -> (Point<N>, N) {
46 let a = *pa - *pc;
47 let b = *pb - *pc;
48
49 let na = a.norm_squared();
50 let nb = b.norm_squared();
51
52 let dab = a.dot(&b);
53
54 let _2: N = na::convert(2.0);
55 let denom = _2 * (na * nb - dab * dab);
56
57 if denom.is_zero() {
58 let c = *pa - *pb;
61 let nc = c.norm_squared();
62
63 if nc >= na && nc >= nb {
64 (na::center(pa, pb), nc.sqrt() / na::convert(2.0f64))
66 } else if na >= nb && na >= nc {
67 (na::center(pa, pc), na.sqrt() / na::convert(2.0f64))
69 } else {
70 (na::center(pb, pc), nb.sqrt() / na::convert(2.0f64))
72 }
73 } else {
74 let k = b * na - a * nb;
75
76 let center = *pc + (a * k.dot(&b) - b * k.dot(&a)) / denom;
77 let radius = na::distance(pa, ¢er);
78
79 (center, radius)
80 }
81}
82
83#[cfg(feature = "dim3")]
85pub fn is_affinely_dependent_triangle<N: RealField + Copy>(
86 p1: &Point<N>,
87 p2: &Point<N>,
88 p3: &Point<N>,
89) -> bool {
90 let p1p2 = *p2 - *p1;
91 let p1p3 = *p3 - *p1;
92
93 let _eps = N::default_epsilon(); let _eps_tol = _eps * na::convert(100.0f64);
96
97 relative_eq!(
98 p1p2.cross(&p1p3).norm_squared(),
99 na::zero(),
100 epsilon = _eps_tol * _eps_tol
101 )
102}
103
104pub fn is_point_in_triangle<N: RealField + Copy>(
106 p: &Point<N>,
107 p1: &Point<N>,
108 p2: &Point<N>,
109 p3: &Point<N>,
110) -> bool {
111 let p1p2 = *p2 - *p1;
112 let p2p3 = *p3 - *p2;
113 let p3p1 = *p1 - *p3;
114
115 let p1p = *p - *p1;
116 let p2p = *p - *p2;
117 let p3p = *p - *p3;
118
119 let d11 = p1p.dot(&p1p2);
120 let d12 = p2p.dot(&p2p3);
121 let d13 = p3p.dot(&p3p1);
122
123 d11 >= na::zero()
124 && d11 <= p1p2.norm_squared()
125 && d12 >= na::zero()
126 && d12 <= p2p3.norm_squared()
127 && d13 >= na::zero()
128 && d13 <= p3p1.norm_squared()
129}
130
131#[cfg(feature = "dim3")]
132#[cfg(test)]
133mod test {
134 use na::Point3;
135
136 #[test]
137 fn test_triangle_area() {
138 let pa = Point3::new(0.0f64, 5.0, 0.0);
139 let pb = Point3::new(0.0f64, 0.0, 0.0);
140 let pc = Point3::new(0.0f64, 0.0, 4.0);
141
142 assert!(relative_eq!(super::triangle_area(&pa, &pb, &pc), 10.0));
143 }
144}