1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
use crate::mass_properties::MassProperties;
use crate::math::{PrincipalAngularInertia, Real, RealField, Vector};
impl MassProperties {
pub(crate) fn ball_volume_unit_angular_inertia(
radius: Real,
) -> (Real, PrincipalAngularInertia) {
#[cfg(feature = "dim2")]
{
let volume = Real::pi() * radius * radius;
let i = radius * radius / 2.0;
(volume, i)
}
#[cfg(feature = "dim3")]
{
let volume = Real::pi() * radius * radius * radius * 4.0 / 3.0;
let i = radius * radius * 2.0 / 5.0;
(volume, Vector::splat(i))
}
}
/// Computes the mass properties of a ball (sphere in 3D, circle in 2D).
///
/// A ball is a perfectly round geometric shape defined by its radius. This function
/// calculates the physical properties needed for physics simulation, including mass,
/// center of mass, and angular inertia (resistance to rotation).
///
/// # Arguments
///
/// * `density` - The material density (mass per unit volume/area). Higher values make heavier objects.
/// - In 3D: units are typically kg/m³ (e.g., water = 1000, steel = 7850)
/// - In 2D: units are typically kg/m² (mass per unit area)
/// * `radius` - The radius of the ball (distance from center to surface)
///
/// # Returns
///
/// A `MassProperties` struct containing:
/// - **mass**: Total mass calculated from volume and density
/// - **local_com**: Center of mass at the origin (balls are perfectly symmetric)
/// - **inv_principal_inertia**: Inverse angular inertia (resistance to spinning)
///
/// # Physics Background
///
/// Balls have uniform density and perfect symmetry, which means:
/// - The center of mass is at the geometric center (origin)
/// - All rotational axes have the same angular inertia (isotropic)
/// - In 3D: moment of inertia = (2/5) * mass * radius²
/// - In 2D: moment of inertia = (1/2) * mass * radius²
///
/// # Example (3D)
///
/// ```
/// # #[cfg(all(feature = "dim3", feature = "f32"))] {
/// use parry3d::mass_properties::MassProperties;
/// use parry3d::math::Vector;
///
/// // Create mass properties for a 0.5m radius ball with density 1000 kg/m³ (water density)
/// let radius = 0.5;
/// let density = 1000.0;
/// let ball_props = MassProperties::from_ball(density, radius);
///
/// // Volume of sphere: (4/3) * π * r³ = 0.524 m³
/// // Mass: volume * density = 524 kg
/// let mass = ball_props.mass();
/// assert!((mass - 523.6).abs() < 1.0); // Approximately 524 kg
///
/// // Center of mass is at the origin for symmetric shapes
/// assert_eq!(ball_props.local_com, Vector::ZERO);
///
/// // Check if object can be moved (finite mass)
/// assert!(ball_props.inv_mass > 0.0, "Ball has finite mass and can move");
/// # }
/// ```
///
/// # Example (2D)
///
/// ```
/// # #[cfg(all(feature = "dim2", feature = "f32"))] {
/// use parry2d::mass_properties::MassProperties;
/// use parry2d::math::Vector;
///
/// // Create a circular disc with 1.0m radius and density 100 kg/m²
/// let radius = 1.0;
/// let density = 100.0;
/// let circle_props = MassProperties::from_ball(density, radius);
///
/// // Area of circle: π * r² = 3.14 m²
/// // Mass: area * density = 314 kg
/// let mass = circle_props.mass();
/// assert!((mass - 314.159).abs() < 0.1); // Approximately 314 kg
///
/// println!("Circle mass: {:.2} kg", mass);
/// println!("Moment of inertia: {:.2}", circle_props.principal_inertia());
/// # }
/// ```
///
/// # Use Cases
///
/// - **Sports balls**: Soccer balls, basketballs, bowling balls
/// - **Planets and celestial bodies**: Spherical approximations
/// - **Particles**: Vector-like objects with rotational inertia
/// - **Wheels and gears**: Cylindrical objects in 2D simulations
///
/// # Performance Note
///
/// This is a very fast computation (constant time) as it only involves basic arithmetic
/// with the radius and density. Balls are the simplest shape for collision detection
/// and physics simulation.
pub fn from_ball(density: Real, radius: Real) -> Self {
let (vol, unit_i) = Self::ball_volume_unit_angular_inertia(radius);
let mass = vol * density;
Self::new(Vector::ZERO, mass, unit_i * mass)
}
}