I recently had to track down a source of NaNs that were being detected long after the invalid values had snuck into the system. I found it was helpful to create an extension class to check for NaN values on common types, and pepper the Bepu code with these checks. The methods are conditional, so they incur zero overhead unless disabled (not even a function call). I'd be pretty happy to see Bepu use this class and start putting in calls to CheckNaN() at strategic spots to help users narrow down NaN problems in the future. Tracking down NaNs can sometimes be pretty time consuming, and being able to just turn on validation code would be pretty handy when this kind of bug pops up.
You basically just put code like this wherever you think might be useful, which is generally places where Bepu accepts values from the application.
Code: Select all
void function(ref Vector3 v)
{
v.CheckNaN();
}
Code: Select all
// use project level symbol definition CHECK_NAN or #define CHECK_NAN here to enable NaN checks.
public static class CheckNaNs
{
[Conditional("CHECK_NAN")]
public static void CheckNaN(this Vector3 v)
{
if (float.IsNaN(v.X)
|| float.IsNaN(v.Y)
|| float.IsNaN(v.Z))
{
throw new Exception("Invalid Vector3");
}
}
[Conditional("CHECK_NAN")]
public static void CheckNaN(this RigidTransform t)
{
if (float.IsNaN(t.Position.X)
|| float.IsNaN(t.Position.Y)
|| float.IsNaN(t.Position.Z)
|| float.IsNaN(t.Orientation.X)
|| float.IsNaN(t.Orientation.Y)
|| float.IsNaN(t.Orientation.Z)
|| float.IsNaN(t.Orientation.W))
{
throw new Exception("Invalid transform");
}
}
[Conditional("CHECK_NAN")]
public static void CheckNaN(this Matrix t)
{
if (float.IsNaN(t.M11)
|| float.IsNaN(t.M12)
|| float.IsNaN(t.M13)
|| float.IsNaN(t.M14)
|| float.IsNaN(t.M21)
|| float.IsNaN(t.M22)
|| float.IsNaN(t.M23)
|| float.IsNaN(t.M24)
|| float.IsNaN(t.M31)
|| float.IsNaN(t.M32)
|| float.IsNaN(t.M33)
|| float.IsNaN(t.M34)
|| float.IsNaN(t.M41)
|| float.IsNaN(t.M42)
|| float.IsNaN(t.M43)
|| float.IsNaN(t.M44))
{
throw new Exception("Invalid transform");
}
}
}