Sim/Metrics.cs
using System;
using System.Collections.Generic;
namespace SquishyTerry.Sim;
/// <summary>Mesh measurements that drive the audio (computeVolume / computeArea / ...).</summary>
public static class Metrics
{
public static float Volume( IReadOnlyList<Vec3> p, IReadOnlyList<int> idx )
{
float v = 0;
for ( int t = 0; t + 2 < idx.Count; t += 3 )
v += Vec3.Dot( p[idx[t]], Vec3.Cross( p[idx[t + 1]], p[idx[t + 2]] ) ) / 6.0f;
return MathF.Abs( v );
}
/// <summary>Array fast path of <see cref="Volume(IReadOnlyList{Vec3}, IReadOnlyList{int})"/> (same arithmetic order).</summary>
public static float Volume( Vec3[] p, int[] idx )
{
float v = 0;
int count = idx.Length - 2;
for ( int t = 0; t < count; t += 3 )
{
ref Vec3 a = ref p[idx[t]];
ref Vec3 b = ref p[idx[t + 1]];
ref Vec3 c = ref p[idx[t + 2]];
float cx = b.Y * c.Z - b.Z * c.Y, cy = b.Z * c.X - b.X * c.Z, cz = b.X * c.Y - b.Y * c.X;
v += (a.X * cx + a.Y * cy + a.Z * cz) / 6.0f;
}
return MathF.Abs( v );
}
public static float Area( IReadOnlyList<Vec3> p, IReadOnlyList<int> idx )
{
float a = 0;
for ( int t = 0; t + 2 < idx.Count; t += 3 )
a += Vec3.Cross( p[idx[t + 1]] - p[idx[t]], p[idx[t + 2]] - p[idx[t]] ).Length * 0.5f;
return a;
}
/// <summary>Array fast path of <see cref="Area(IReadOnlyList{Vec3}, IReadOnlyList{int})"/> (same arithmetic order).</summary>
public static float Area( Vec3[] p, int[] idx )
{
float a = 0;
int count = idx.Length - 2;
for ( int t = 0; t < count; t += 3 )
{
ref Vec3 p0 = ref p[idx[t]];
ref Vec3 p1 = ref p[idx[t + 1]];
ref Vec3 p2 = ref p[idx[t + 2]];
float ux = p1.X - p0.X, uy = p1.Y - p0.Y, uz = p1.Z - p0.Z;
float vx = p2.X - p0.X, vy = p2.Y - p0.Y, vz = p2.Z - p0.Z;
float nx = uy * vz - uz * vy, ny = uz * vx - ux * vz, nz = ux * vy - uy * vx;
a += MathF.Sqrt( nx * nx + ny * ny + nz * nz ) * 0.5f;
}
return a;
}
public static float AverageSpeed( IReadOnlyList<Vec3> vel )
{
if ( vel.Count == 0 ) return 0;
float s = 0;
for ( int i = 0; i < vel.Count; i++ ) s += vel[i].Length;
return s / vel.Count;
}
/// <summary>Array fast path of <see cref="AverageSpeed(IReadOnlyList{Vec3})"/> (same arithmetic order).</summary>
public static float AverageSpeed( Vec3[] vel )
{
if ( vel.Length == 0 ) return 0;
float s = 0;
for ( int i = 0; i < vel.Length; i++ )
{
ref Vec3 v = ref vel[i];
s += MathF.Sqrt( v.X * v.X + v.Y * v.Y + v.Z * v.Z );
}
return s / vel.Length;
}
}