Toast Engine
Loading...
Searching...
No Matches
mass_accumulator.hpp
Go to the documentation of this file.
1
6
7#pragma once
8#include "voxel_constants.hpp"
9
10#include <cassert>
11#include <cstdint>
12#include <glm/glm.hpp>
13
14namespace voxel {
15
16inline constexpr int64_t k_moment_safe_limit = int64_t {1} << 62;
17
20 int64_t mass = 0;
21
23 int64_t m_x = 0;
24 int64_t m_y = 0;
25 int64_t m_z = 0;
26
28 int64_t m_xx = 0;
29 int64_t m_yy = 0;
30 int64_t m_zz = 0;
31
33 int64_t m_xy = 0;
34 int64_t m_xz = 0;
35 int64_t m_yz = 0;
36
37 [[nodiscard]]
38 constexpr auto operator==(const MassMoments&) const noexcept -> bool = default;
39
40 [[nodiscard]]
41 constexpr auto isEmpty() const noexcept -> bool {
42 return mass == 0;
43 }
44
45 constexpr void add(int32_t x, int32_t y, int32_t z, uint32_t density) noexcept {
46 accumulate(x, y, z, static_cast<int64_t>(density));
47 }
48
49 constexpr void remove(int32_t x, int32_t y, int32_t z, uint32_t density) noexcept {
50 accumulate(x, y, z, -static_cast<int64_t>(density));
51 assert(mass >= 0);
52 }
53
54 constexpr auto operator-=(const MassMoments& other) noexcept -> MassMoments& {
55 mass -= other.mass;
56 m_x -= other.m_x;
57 m_y -= other.m_y;
58 m_z -= other.m_z;
59 m_xx -= other.m_xx;
60 m_yy -= other.m_yy;
61 m_zz -= other.m_zz;
62 m_xy -= other.m_xy;
63 m_xz -= other.m_xz;
64 m_yz -= other.m_yz;
65 assert(mass >= 0);
66 return *this;
67 }
68
69 [[nodiscard]]
70 constexpr auto scaled(int64_t factor) const noexcept -> MassMoments {
71 MassMoments out;
72 out.mass = mass * factor;
73 out.m_x = m_x * factor;
74 out.m_y = m_y * factor;
75 out.m_z = m_z * factor;
76 out.m_xx = m_xx * factor;
77 out.m_yy = m_yy * factor;
78 out.m_zz = m_zz * factor;
79 out.m_xy = m_xy * factor;
80 out.m_xz = m_xz * factor;
81 out.m_yz = m_yz * factor;
82 out.checkHeadroom();
83 return out;
84 }
85
86 constexpr auto operator+=(const MassMoments& other) noexcept -> MassMoments& {
87 mass += other.mass;
88 m_x += other.m_x;
89 m_y += other.m_y;
90 m_z += other.m_z;
91 m_xx += other.m_xx;
92 m_yy += other.m_yy;
93 m_zz += other.m_zz;
94 m_xy += other.m_xy;
95 m_xz += other.m_xz;
96 m_yz += other.m_yz;
97 checkHeadroom();
98 return *this;
99 }
100
101 [[nodiscard]]
102 constexpr auto operator+(const MassMoments& other) const noexcept -> MassMoments {
103 MassMoments out = *this;
104 out += other;
105 return out;
106 }
107
108 [[nodiscard]]
109 constexpr auto shifted(int32_t ox, int32_t oy, int32_t oz) const noexcept -> MassMoments {
110 const int64_t dx = ox;
111 const int64_t dy = oy;
112 const int64_t dz = oz;
113
114 MassMoments out;
115 out.mass = mass;
116 out.m_x = m_x + (dx * mass);
117 out.m_y = m_y + (dy * mass);
118 out.m_z = m_z + (dz * mass);
119 out.m_xx = m_xx + (2 * dx * m_x) + (dx * dx * mass);
120 out.m_yy = m_yy + (2 * dy * m_y) + (dy * dy * mass);
121 out.m_zz = m_zz + (2 * dz * m_z) + (dz * dz * mass);
122 out.m_xy = m_xy + (dx * m_y) + (dy * m_x) + (dx * dy * mass);
123 out.m_xz = m_xz + (dx * m_z) + (dz * m_x) + (dx * dz * mass);
124 out.m_yz = m_yz + (dy * m_z) + (dz * m_y) + (dy * dz * mass);
125 out.checkHeadroom();
126 return out;
127 }
128
129private:
130 constexpr void accumulate(int32_t x, int32_t y, int32_t z, int64_t signed_density) noexcept {
131 const int64_t lx = x;
132 const int64_t ly = y;
133 const int64_t lz = z;
134
135 mass += signed_density;
136 m_x += signed_density * lx;
137 m_y += signed_density * ly;
138 m_z += signed_density * lz;
139 m_xx += signed_density * lx * lx;
140 m_yy += signed_density * ly * ly;
141 m_zz += signed_density * lz * lz;
142 m_xy += signed_density * lx * ly;
143 m_xz += signed_density * lx * lz;
144 m_yz += signed_density * ly * lz;
145 checkHeadroom();
146 }
147
148 constexpr void checkHeadroom() const noexcept {
149 assert(m_xx < k_moment_safe_limit && m_yy < k_moment_safe_limit && m_zz < k_moment_safe_limit);
150 }
151};
152
155 float mass = 0.0f;
156
158 glm::vec3 center_of_mass {0.0f};
159
161 glm::mat3 inertia {0.0f};
162};
163
164[[nodiscard]]
165inline auto resolveMass(const MassMoments& moments, float voxel_size = k_voxel_size) -> float {
166 const double s = static_cast<double>(voxel_size);
167 return static_cast<float>(static_cast<double>(moments.mass) * s * s * s);
168}
169
170[[nodiscard]]
171inline auto resolve(const MassMoments& moments, float voxel_size = k_voxel_size) -> MassProperties {
172 MassProperties out;
173 if (moments.mass <= 0) {
174 return out;
175 }
176
177 const double s = voxel_size;
178 const double s3 = s * s * s;
179 const double s5 = s3 * s * s;
180
181 const double density_sum = static_cast<double>(moments.mass);
182 const double total_mass = density_sum * s3;
183
184 // sum(d * (l_a + 1/2) * (l_b + 1/2)) = m_ab + (m_a + m_b)/2 + density_sum/4
185 const auto product = [&](int64_t m_ab, int64_t m_a, int64_t m_b) {
186 return static_cast<double>(m_ab) + (0.5 * (static_cast<double>(m_a) + static_cast<double>(m_b))) + (0.25 * density_sum);
187 };
188
189 const double p_xx = product(moments.m_xx, moments.m_x, moments.m_x);
190 const double p_yy = product(moments.m_yy, moments.m_y, moments.m_y);
191 const double p_zz = product(moments.m_zz, moments.m_z, moments.m_z);
192 const double p_xy = product(moments.m_xy, moments.m_x, moments.m_y);
193 const double p_xz = product(moments.m_xz, moments.m_x, moments.m_z);
194 const double p_yz = product(moments.m_yz, moments.m_y, moments.m_z);
195
196 const double com_x = ((static_cast<double>(moments.m_x) / density_sum) + 0.5) * s;
197 const double com_y = ((static_cast<double>(moments.m_y) / density_sum) + 0.5) * s;
198 const double com_z = ((static_cast<double>(moments.m_z) / density_sum) + 0.5) * s;
199
200 // A cube of edge s adds m * s² / 6 to every diagonal
201 const double self_term = total_mass * s * s / 6.0;
202
203 double i_xx = (s5 * (p_yy + p_zz)) + self_term;
204 double i_yy = (s5 * (p_xx + p_zz)) + self_term;
205 double i_zz = (s5 * (p_xx + p_yy)) + self_term;
206 double i_xy = -s5 * p_xy;
207 double i_xz = -s5 * p_xz;
208 double i_yz = -s5 * p_yz;
209
210 i_xx -= total_mass * ((com_y * com_y) + (com_z * com_z));
211 i_yy -= total_mass * ((com_x * com_x) + (com_z * com_z));
212 i_zz -= total_mass * ((com_x * com_x) + (com_y * com_y));
213 i_xy += total_mass * com_x * com_y;
214 i_xz += total_mass * com_x * com_z;
215 i_yz += total_mass * com_y * com_z;
216
217 out.mass = static_cast<float>(total_mass);
218 out.center_of_mass = glm::vec3(static_cast<float>(com_x), static_cast<float>(com_y), static_cast<float>(com_z));
219 out.inertia = glm::mat3(
220 static_cast<float>(i_xx),
221 static_cast<float>(i_xy),
222 static_cast<float>(i_xz),
223 static_cast<float>(i_xy),
224 static_cast<float>(i_yy),
225 static_cast<float>(i_yz),
226 static_cast<float>(i_xz),
227 static_cast<float>(i_yz),
228 static_cast<float>(i_zz)
229 );
230 return out;
231}
232
233}
Definition mass_accumulator.hpp:18
int64_t mass
Sum of densities.
Definition mass_accumulator.hpp:20
int64_t m_xx
Sum of density * coordinate*coordinate.
Definition mass_accumulator.hpp:28
int64_t m_x
Sum of density * coordinate.
Definition mass_accumulator.hpp:23
int64_t m_xy
Sum of density * coordinate_a * coordinate_b.
Definition mass_accumulator.hpp:33
Definition mass_accumulator.hpp:153
float mass
kg
Definition mass_accumulator.hpp:155
glm::mat3 inertia
kg·m² about the centre of mass
Definition mass_accumulator.hpp:161
glm::vec3 center_of_mass
Volume local metres.
Definition mass_accumulator.hpp:158