parry3d/utils/center.rs
1use crate::math::{Point, Real};
2use na;
3
4/// Computes the geometric center (centroid) of a set of points.
5///
6/// The center is calculated by averaging all the point coordinates. This is also known as
7/// the centroid or barycenter of the point cloud. All points are weighted equally.
8///
9/// # Arguments
10///
11/// * `pts` - A slice of points. Must contain at least one point.
12///
13/// # Returns
14///
15/// The geometric center as a `Point<Real>`.
16///
17/// # Panics
18///
19/// Panics if the input slice is empty.
20///
21/// # Examples
22///
23/// ## 2D Example
24///
25/// ```
26/// # #[cfg(all(feature = "dim2", feature = "f32"))] {
27/// use parry2d::utils::center;
28/// use parry2d::math::Point;
29///
30/// let points = vec![
31/// Point::new(0.0, 0.0),
32/// Point::new(2.0, 0.0),
33/// Point::new(2.0, 2.0),
34/// Point::new(0.0, 2.0),
35/// ];
36///
37/// let c = center(&points);
38///
39/// // The center of a square is at its middle
40/// assert!((c.x - 1.0).abs() < 1e-6);
41/// assert!((c.y - 1.0).abs() < 1e-6);
42/// # }
43/// ```
44///
45/// ## 3D Example
46///
47/// ```
48/// # #[cfg(all(feature = "dim3", feature = "f32"))] {
49/// use parry3d::utils::center;
50/// use parry3d::math::Point;
51///
52/// let points = vec![
53/// Point::new(0.0, 0.0, 0.0),
54/// Point::new(4.0, 0.0, 0.0),
55/// Point::new(0.0, 4.0, 0.0),
56/// ];
57///
58/// let c = center(&points);
59///
60/// // The center of these three points
61/// assert!((c.x - 4.0 / 3.0).abs() < 1e-6);
62/// assert!((c.y - 4.0 / 3.0).abs() < 1e-6);
63/// assert!(c.z.abs() < 1e-6);
64/// # }
65/// ```
66///
67/// ## Single Point
68///
69/// ```
70/// # #[cfg(all(feature = "dim2", feature = "f32"))] {
71/// use parry2d::utils::center;
72/// use parry2d::math::Point;
73///
74/// let points = vec![Point::new(5.0, 10.0)];
75/// let c = center(&points);
76///
77/// // The center of a single point is the point itself
78/// assert_eq!(c, points[0]);
79/// # }
80/// ```
81#[inline]
82pub fn center(pts: &[Point<Real>]) -> Point<Real> {
83 assert!(
84 !pts.is_empty(),
85 "Cannot compute the center of less than 1 point."
86 );
87
88 let denom: Real = na::convert::<f64, Real>(1.0 / (pts.len() as f64));
89
90 let mut piter = pts.iter();
91 let mut res = *piter.next().unwrap() * denom;
92
93 for pt in piter {
94 res += pt.coords * denom;
95 }
96
97 res
98}