measures
triwarp.measures
What the whole mesh adds up to: the volume it encloses, its moments and its Euler characteristic.
Every function here reduces the entire surface to a single host-side number (or a small tuple of
them), which is why they are gathered rather than left beside the per-element fields they sum over.
Each therefore costs at least one host readback and forces a device synchronisation -- call them
once and keep the answer, and reach for triwarp.reduce when a reduction should
stay on the device.
Three of the four are mass properties of the enclosed solid, and all three are only meaningful
on a closed, consistently wound surface -- is_volume is the check
for that, and make_volume the repair.
volume is the signed volume,
moments adds the centre of mass and the inertia tensor, and
surface_centroid is the one member that is a normalized
total rather than a sum: the area-weighted mean of the per-face centroids. It is a property of the
shell, so it differs from moments' centre of mass on any solid whose mass is not distributed
like its surface -- and it needs no watertightness, since a surface has a centroid whether or not it
bounds anything.
euler_characteristic is the odd one out: a topological
invariant rather than a measurement, counted off the index buffer with no geometry involved. It sits
here because it is a whole-mesh integer, and it is what
homology_generators derives the genus from.
volume
volume(
vertices: array[vec3] | array[vec3d],
faces: array[int32],
) -> float
Signed volume enclosed by the mesh.
Sum of per-face signed tetrahedron volumes measured from the origin
(dot(v0, cross(v1, v2)) / 6); for a closed, consistently wound surface this is
independent of the reference point, and its sign follows the orientation of the face
normals (positive for outward-facing normals). For an open or inconsistently wound mesh
the result is not a meaningful volume.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
vertices
|
array[vec3] | array[vec3d]
|
|
required |
faces
|
array[int32]
|
Length- |
required |
Returns:
| Type | Description |
|---|---|
float
|
Signed volume, accumulated in |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If |
See Also
face_signed_volumes
The per-face primitive this sums.
is_volume
Whether the sum means anything on this mesh.
make_volume
Make it mean something.
moments
The same volume in float64, plus the centre of mass and inertia.
filter_laplacian
The float64 consumer: its volume constraint rescales the mesh to hold this fixed.
trimesh.Trimesh.volume
Source code in triwarp/measures.py
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 | |
surface_centroid
surface_centroid(
vertices: array[vec3], faces: array[int32]
) -> wp.vec3
Area-weighted centroid of the mesh surface: the mean of the per-face centroids by area.
A normalized total rather than a sum, and a property of the shell alone -- unlike
moments' centre of mass it needs no watertightness and no
consistent winding, because a surface has a centroid whether or not it bounds a solid. The two
differ on any solid whose mass is not distributed like its surface.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
vertices
|
array[vec3]
|
|
required |
faces
|
array[int32]
|
Length- |
required |
Returns:
| Type | Description |
|---|---|
vec3
|
Area-weighted mean of per-face centroids. All- |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If |
See Also
moments
The centre of mass of the enclosed solid, which this is not.
face_centroids
The per-face barycentres this averages.
centroid
The unweighted mean of a point cloud, and the only other centroid in the package.
trimesh.Trimesh.centroid
Source code in triwarp/measures.py
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 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | |
moments
moments(
vertices: array[vec3], faces: array[int32]
) -> tuple[float, wp.vec3, wp.mat33d]
Mass properties of the solid bounded by the mesh: volume, centre of mass and inertia tensor.
Integrates over the enclosed solid at unit density by summing the contribution of every
(origin, face) tetrahedron, so the result is only meaningful for a closed, consistently
wound surface -- the same precondition volume carries, and
is_volume is the check for it.
The integrals accumulate in float64 even though the positions are float32: the second
moments scale as length ** 5, so a float32 sum loses their low digits on any sizeable
mesh.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
vertices
|
array[vec3]
|
|
required |
faces
|
array[int32]
|
Length- |
required |
Returns:
| Name | Type | Description |
|---|---|---|
volume |
float
|
Signed volume, identical to |
center_of_mass |
vec3
|
Volume centroid, i.e. the first moment divided by the volume. This is not
|
inertia |
mat33d
|
|
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If |
Notes
igl.moments returns (m0, m1, m2) where m1 is the first moment -- the centre of mass
times the mass -- rather than the centre of mass itself, and m2 is already referred to the
centre of mass (verified against a translated mesh, not assumed). This function returns the
decoded forms, so the transform between the two is m1 / m0.
Three host readbacks are unavoidable here: all three returns are host-side values, so the ten accumulated sums have to cross the device boundary to be combined.
See Also
volume
surface_centroid
is_volume
trimesh.Trimesh.moment_inertia
igl.moments
Source code in triwarp/measures.py
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 | |
euler_characteristic
euler_characteristic(faces: array[int32]) -> int
Euler characteristic V - E + F of the mesh (topological invariant).
Counts distinct referenced vertices, unique undirected edges, and faces, matching
trimesh.Trimesh.euler_number (which uses referenced vertices, edges_unique, and
faces). For a closed genus-g surface this equals 2 - 2 * g.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
faces
|
array[int32]
|
Length- |
required |
Returns:
| Type | Description |
|---|---|
int
|
|
See Also
Source code in triwarp/measures.py
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 | |