Skip to main content

haply/
physics.rs

1//! Physics computation module for haptic interactions.
2//! Provides utilities for calculating forces and interactions with virtual objects.
3
4use serde::{Deserialize, Serialize};
5
6/// A trait representing a physical object that can compute a force given a position.
7pub trait PhysicalObject {
8    /// Compute the force vector (as [x, y, z]) for a given position.
9    fn compute_force(&self, position: [f32; 3]) -> [f32; 3];
10}
11
12/// A sphere model with physical properties.
13#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct Sphere {
15    pub center: [f32; 3],
16    pub radius: f32,
17    pub stiffness: f32, // restoring force constant (if inside)
18    pub magnetism: f32, // attractive force magnitude (if outside)
19    pub damping: f32,   // damping factor (not used in this simple example)
20}
21
22impl PhysicalObject for Sphere {
23    fn compute_force(&self, position: [f32; 3]) -> [f32; 3] {
24        let dx = position[0] - self.center[0];
25        let dy = position[1] - self.center[1];
26        let dz = position[2] - self.center[2];
27        let distance = (dx * dx + dy * dy + dz * dz).sqrt();
28        if distance < self.radius {
29            // Inside the sphere: spring restoring force based on the penetration depth.
30            let norm_dx = dx / distance;
31            let norm_dy = dy / distance;
32            let norm_dz = dz / distance;
33            let penetration = self.radius - distance;
34            [
35                self.stiffness * penetration * norm_dx,
36                self.stiffness * penetration * norm_dy,
37                self.stiffness * penetration * norm_dz,
38            ]
39        } else if distance > 0.0 {
40            // Outside the sphere: attractive force toward the center.
41            let norm_dx = (self.center[0] - position[0]) / distance;
42            let norm_dy = (self.center[1] - position[1]) / distance;
43            let norm_dz = (self.center[2] - position[2]) / distance;
44            [
45                self.magnetism * norm_dx,
46                self.magnetism * norm_dy,
47                self.magnetism * norm_dz,
48            ]
49        } else {
50            [0.0, 0.0, 0.0]
51        }
52    }
53}
54
55/// A cube model with physical properties.
56#[derive(Debug, Clone, Serialize, Deserialize)]
57pub struct Cube {
58    pub center: [f32; 3],
59    pub size: f32,      // edge length of the cube
60    pub stiffness: f32, // restoring force constant
61    pub magnetism: f32, // attraction force magnitude
62    pub damping: f32,   // damping factor (not used in this example)
63}
64
65impl PhysicalObject for Cube {
66    fn compute_force(&self, position: [f32; 3]) -> [f32; 3] {
67        // For simplicity, assume that if a coordinate is within half the size,
68        // apply a restoring force for that axis; otherwise, apply an attractive force.
69        let half = self.size / 2.0;
70        let mut force = [0.0_f32, 0.0, 0.0];
71        for i in 0..3 {
72            let diff = position[i] - self.center[i];
73            if diff.abs() < half {
74                force[i] = -self.stiffness * diff;
75            } else {
76                // Apply a constant attractive force toward the center on that axis.
77                force[i] = if diff > 0.0 {
78                    self.magnetism
79                } else {
80                    -self.magnetism
81                };
82            }
83        }
84        force
85    }
86}
87
88
89/// Computes the total force vector acting on a point in 3D space.
90/// 
91/// Takes a position and a list of physical objects, then calculates and combines
92/// the forces from each object to determine the total force at that position.
93/// 
94/// # Arguments
95/// * `position` - The 3D position at which to compute forces
96/// * `objects` - A slice of physical objects that can exert forces
97/// 
98/// # Returns
99/// A 3D force vector as [f32; 3]
100pub fn compute_total_force(position: [f32; 3], objects: &[Box<dyn PhysicalObject>]) -> [f32; 3] {
101    let mut total = [0.0_f32, 0.0, 0.0];
102    for obj in objects {
103        let f = obj.compute_force(position);
104        total[0] += f[0];
105        total[1] += f[1];
106        total[2] += f[2];
107    }
108    total
109}