refactor: RcVecUtils.SafeNormalize

This commit is contained in:
ikpil 2023-10-24 23:46:45 +09:00
parent ef8ef94826
commit 04fa38bb96
15 changed files with 60 additions and 63 deletions

View File

@ -23,7 +23,6 @@ namespace DotRecast.Core.Numerics
{ {
public struct RcVec3f public struct RcVec3f
{ {
public const float EPSILON = 1e-6f;
public float X; public float X;
public float Y; public float Y;
@ -144,29 +143,10 @@ namespace DotRecast.Core.Numerics
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode() public override int GetHashCode()
{ {
int hash = X.GetHashCode(); return HashCode.Combine(X, Y, Z);
hash = RcHashCodes.CombineHashCodes(hash, Y.GetHashCode());
hash = RcHashCodes.CombineHashCodes(hash, Z.GetHashCode());
return hash;
} }
/// Normalizes the vector if the length is greater than zero.
/// If the magnitude is zero, the vector is unchanged.
/// @param[in,out] v The vector to normalize. [(x, y, z)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SafeNormalize()
{
float sqMag = RcMath.Sqr(X) + RcMath.Sqr(Y) + RcMath.Sqr(Z);
if (sqMag > EPSILON)
{
float inverseMag = 1.0f / (float)Math.Sqrt(sqMag);
X *= inverseMag;
Y *= inverseMag;
Z *= inverseMag;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Min(float[] @in, int i) public void Min(float[] @in, int i)
{ {
@ -368,7 +348,7 @@ namespace DotRecast.Core.Numerics
{ {
float dx = v2.X - v1.X; float dx = v2.X - v1.X;
float dz = v2.Z - v1.Z; float dz = v2.Z - v1.Z;
return (float)Math.Sqrt(dx * dx + dz * dz); return (float)MathF.Sqrt(dx * dx + dz * dz);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -457,18 +437,13 @@ namespace DotRecast.Core.Numerics
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RcVec3f Normalize(RcVec3f v) public static RcVec3f Normalize(RcVec3f v)
{ {
float d = (float)(1.0f / Math.Sqrt(RcMath.Sqr(v.X) + RcMath.Sqr(v.Y) + RcMath.Sqr(v.Z))); float d = 1.0f / MathF.Sqrt(RcMath.Sqr(v.X) + RcMath.Sqr(v.Y) + RcMath.Sqr(v.Z));
if (d != 0) return new RcVec3f(
{ v.X *= d,
return new RcVec3f( v.Y *= d,
v.X *= d, v.Z *= d
v.Y *= d, );
v.Z *= d
);
}
return v;
} }
} }
} }

View File

@ -5,6 +5,8 @@ namespace DotRecast.Core.Numerics
{ {
public static class RcVecUtils public static class RcVecUtils
{ {
public const float EPSILON = 1e-6f;
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Get(this RcVec2f v, int i) public static float Get(this RcVec2f v, int i)
{ {
@ -120,5 +122,25 @@ namespace DotRecast.Core.Numerics
v1[1] * vector2.Y + v1[1] * vector2.Y +
v1[2] * vector2.Z; v1[2] * vector2.Z;
} }
/// Normalizes the vector if the length is greater than zero.
/// If the magnitude is zero, the vector is unchanged.
/// @param[in,out] v The vector to normalize. [(x, y, z)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RcVec3f SafeNormalize(RcVec3f v)
{
float sqMag = RcMath.Sqr(v.X) + RcMath.Sqr(v.Y) + RcMath.Sqr(v.Z);
if (sqMag > EPSILON)
{
float inverseMag = 1.0f / MathF.Sqrt(sqMag);
return new RcVec3f(
v.X *= inverseMag,
v.Y *= inverseMag,
v.Z *= inverseMag
);
}
return v;
}
} }
} }

View File

@ -1091,7 +1091,7 @@ namespace DotRecast.Detour.Crowd
continue; continue;
} }
float dist = (float)Math.Sqrt(distSqr); float dist = MathF.Sqrt(distSqr);
float weight = separationWeight * (1.0f - RcMath.Sqr(dist * invSeparationDist)); float weight = separationWeight * (1.0f - RcMath.Sqr(dist * invSeparationDist));
disp = RcVec3f.Mad(disp, diff, weight / dist); disp = RcVec3f.Mad(disp, diff, weight / dist);
@ -1233,7 +1233,7 @@ namespace DotRecast.Detour.Crowd
continue; continue;
} }
dist = (float)Math.Sqrt(dist); dist = MathF.Sqrt(dist);
float pen = (ag.option.radius + nei.option.radius) - dist; float pen = (ag.option.radius + nei.option.radius) - dist;
if (dist < 0.0001f) if (dist < 0.0001f)
{ {

View File

@ -175,7 +175,7 @@ namespace DotRecast.Detour.Crowd
return false; // no intersection. return false; // no intersection.
a = 1.0f / a; a = 1.0f / a;
float rd = (float)Math.Sqrt(d); float rd = MathF.Sqrt(d);
tmin = (b - rd) * a; tmin = (b - rd) * a;
tmax = (b + rd) * a; tmax = (b + rd) * a;
@ -364,7 +364,7 @@ namespace DotRecast.Detour.Crowd
// vector normalization that ignores the y-component. // vector normalization that ignores the y-component.
void DtNormalize2D(float[] v) void DtNormalize2D(float[] v)
{ {
float d = (float)Math.Sqrt(v[0] * v[0] + v[2] * v[2]); float d = MathF.Sqrt(v[0] * v[0] + v[2] * v[2]);
if (d == 0) if (d == 0)
return; return;
d = 1.0f / d; d = 1.0f / d;

View File

@ -11,7 +11,7 @@ namespace DotRecast.Detour.Extras.Jumplink
protected void SampleGround(JumpLinkBuilderConfig acfg, EdgeSampler es, ComputeNavMeshHeight heightFunc) protected void SampleGround(JumpLinkBuilderConfig acfg, EdgeSampler es, ComputeNavMeshHeight heightFunc)
{ {
float cs = acfg.cellSize; float cs = acfg.cellSize;
float dist = (float)Math.Sqrt(RcVec3f.Dist2DSqr(es.start.p, es.start.q)); float dist = MathF.Sqrt(RcVec3f.Dist2DSqr(es.start.p, es.start.q));
int ngsamples = Math.Max(2, (int)Math.Ceiling(dist / cs)); int ngsamples = Math.Max(2, (int)Math.Ceiling(dist / cs));
SampleGroundSegment(heightFunc, es.start, ngsamples); SampleGroundSegment(heightFunc, es.start, ngsamples);

View File

@ -3302,7 +3302,7 @@ namespace DotRecast.Detour
hitNormal = RcVec3f.Normalize(new RcVec3f(tangent.Z, 0, -tangent.X)); hitNormal = RcVec3f.Normalize(new RcVec3f(tangent.Z, 0, -tangent.X));
} }
hitDist = (float)Math.Sqrt(radiusSqr); hitDist = MathF.Sqrt(radiusSqr);
return status; return status;
} }

View File

@ -193,7 +193,7 @@ namespace DotRecast.Detour
acc += dacc; acc += dacc;
} }
float v = (float)Math.Sqrt(t); float v = MathF.Sqrt(t);
float a = 1 - v; float a = 1 - v;
float b = (1 - u) * v; float b = (1 - u) * v;

View File

@ -335,7 +335,7 @@ public class DebugDraw
float dx = x1 - x0; float dx = x1 - x0;
float dy = y1 - y0; float dy = y1 - y0;
float dz = z1 - z0; float dz = z1 - z0;
float len = (float)Math.Sqrt(dx * dx + dy * dy + dz * dz); float len = MathF.Sqrt(dx * dx + dy * dy + dz * dz);
RcVec3f prev = new RcVec3f(); RcVec3f prev = new RcVec3f();
EvalArc(x0, y0, z0, dx, dy, dz, len * h, PAD, ref prev); EvalArc(x0, y0, z0, dx, dy, dz, len * h, PAD, ref prev);
for (int i = 1; i <= NUM_ARC_PTS; ++i) for (int i = 1; i <= NUM_ARC_PTS; ++i)
@ -677,7 +677,7 @@ public class DebugDraw
private void NormalizePlane(float px, float py, float pz, float pw, ref float[] plane) private void NormalizePlane(float px, float py, float pz, float pw, ref float[] plane)
{ {
float length = (float)Math.Sqrt(px * px + py * py + pz * pz); float length = MathF.Sqrt(px * px + py * py + pz * pz);
if (length != 0) if (length != 0)
{ {
length = 1f / length; length = 1f / length;

View File

@ -424,7 +424,7 @@ public class TestNavmeshSampleTool : ISampleTool
dd.DepthMask(false); dd.DepthMask(false);
float dx = m_epos.X - m_spos.X; float dx = m_epos.X - m_spos.X;
float dz = m_epos.Z - m_spos.Z; float dz = m_epos.Z - m_spos.Z;
float dist = (float)Math.Sqrt(dx * dx + dz * dz); float dist = MathF.Sqrt(dx * dx + dz * dz);
dd.DebugDrawCircle(m_spos.X, m_spos.Y + agentHeight / 2, m_spos.Z, dist, DuRGBA(64, 16, 0, 220), 2.0f); dd.DebugDrawCircle(m_spos.X, m_spos.Y + agentHeight / 2, m_spos.Z, dist, DuRGBA(64, 16, 0, 220), 2.0f);
dd.DepthMask(true); dd.DepthMask(true);
} }
@ -566,7 +566,7 @@ public class TestNavmeshSampleTool : ISampleTool
dd.DepthMask(false); dd.DepthMask(false);
float dx = m_epos.X - m_spos.X; float dx = m_epos.X - m_spos.X;
float dz = m_epos.Z - m_spos.Z; float dz = m_epos.Z - m_spos.Z;
float dist = (float)Math.Sqrt(dx * dx + dz * dz); float dist = MathF.Sqrt(dx * dx + dz * dz);
dd.DebugDrawCircle(m_spos.X, m_spos.Y + agentHeight / 2, m_spos.Z, dist, DuRGBA(64, 16, 0, 220), 2.0f); dd.DebugDrawCircle(m_spos.X, m_spos.Y + agentHeight / 2, m_spos.Z, dist, DuRGBA(64, 16, 0, 220), 2.0f);
dd.DepthMask(true); dd.DepthMask(true);
} }

View File

@ -101,7 +101,7 @@ namespace DotRecast.Recast.Toolset.Geom
normals[i] = e0.Y * e1.Z - e0.Z * e1.Y; normals[i] = e0.Y * e1.Z - e0.Z * e1.Y;
normals[i + 1] = e0.Z * e1.X - e0.X * e1.Z; normals[i + 1] = e0.Z * e1.X - e0.X * e1.Z;
normals[i + 2] = e0.X * e1.Y - e0.Y * e1.X; normals[i + 2] = e0.X * e1.Y - e0.Y * e1.X;
float d = (float)Math.Sqrt(normals[i] * normals[i] + normals[i + 1] * normals[i + 1] + normals[i + 2] * normals[i + 2]); float d = MathF.Sqrt(normals[i] * normals[i] + normals[i + 1] * normals[i + 1] + normals[i + 2] * normals[i + 2]);
if (d > 0) if (d > 0)
{ {
d = 1.0f / d; d = 1.0f / d;

View File

@ -74,7 +74,7 @@ namespace DotRecast.Recast.Toolset.Tools
// Find movement delta. // Find movement delta.
RcVec3f delta = RcVec3f.Subtract(steerPos, iterPos); RcVec3f delta = RcVec3f.Subtract(steerPos, iterPos);
float len = (float)Math.Sqrt(RcVec3f.Dot(delta, delta)); float len = MathF.Sqrt(RcVec3f.Dot(delta, delta));
// If the steer target is end of path or off-mesh link, do not move past the location. // If the steer target is end of path or off-mesh link, do not move past the location.
if ((endOfPath || offMeshConnection) && len < STEP_SIZE) if ((endOfPath || offMeshConnection) && len < STEP_SIZE)
{ {
@ -329,7 +329,7 @@ namespace DotRecast.Recast.Toolset.Tools
float dx = epos.X - spos.X; float dx = epos.X - spos.X;
float dz = epos.Z - spos.Z; float dz = epos.Z - spos.Z;
float dist = (float)Math.Sqrt(dx * dx + dz * dz); float dist = MathF.Sqrt(dx * dx + dz * dz);
List<long> tempResultRefs = new List<long>(); List<long> tempResultRefs = new List<long>();
List<long> tempParentRefs = new List<long>(); List<long> tempParentRefs = new List<long>();
@ -417,7 +417,7 @@ namespace DotRecast.Recast.Toolset.Tools
float dx = epos.X - spos.X; float dx = epos.X - spos.X;
float dz = epos.Z - spos.Z; float dz = epos.Z - spos.Z;
float dist = (float)Math.Sqrt(dx * dx + dz * dz); float dist = MathF.Sqrt(dx * dx + dz * dz);
IDtPolygonByCircleConstraint constraint = constrainByCircle IDtPolygonByCircleConstraint constraint = constrainByCircle
? DtStrictDtPolygonByCircleConstraint.Shared ? DtStrictDtPolygonByCircleConstraint.Shared

View File

@ -163,7 +163,7 @@ namespace DotRecast.Recast.Geom
normals[i] = e0.Y * e1.Z - e0.Z * e1.Y; normals[i] = e0.Y * e1.Z - e0.Z * e1.Y;
normals[i + 1] = e0.Z * e1.X - e0.X * e1.Z; normals[i + 1] = e0.Z * e1.X - e0.X * e1.Z;
normals[i + 2] = e0.X * e1.Y - e0.Y * e1.X; normals[i + 2] = e0.X * e1.Y - e0.Y * e1.X;
float d = (float)Math.Sqrt(normals[i] * normals[i] + normals[i + 1] * normals[i + 1] + normals[i + 2] * normals[i + 2]); float d = MathF.Sqrt(normals[i] * normals[i] + normals[i + 1] * normals[i + 1] + normals[i + 2] * normals[i + 2]);
if (d > 0) if (d > 0)
{ {
d = 1.0f / d; d = 1.0f / d;

View File

@ -760,12 +760,12 @@ namespace DotRecast.Recast
// From A to B on the x/z plane // From A to B on the x/z plane
RcVec3f prevSegmentDir = RcVec3f.Subtract(vertB, vertA); RcVec3f prevSegmentDir = RcVec3f.Subtract(vertB, vertA);
prevSegmentDir.Y = 0; // Squash onto x/z plane prevSegmentDir.Y = 0; // Squash onto x/z plane
prevSegmentDir.SafeNormalize(); prevSegmentDir = RcVecUtils.SafeNormalize(prevSegmentDir);
// From B to C on the x/z plane // From B to C on the x/z plane
RcVec3f currSegmentDir = RcVec3f.Subtract(vertC, vertB); RcVec3f currSegmentDir = RcVec3f.Subtract(vertC, vertB);
currSegmentDir.Y = 0; // Squash onto x/z plane currSegmentDir.Y = 0; // Squash onto x/z plane
currSegmentDir.SafeNormalize(); currSegmentDir = RcVecUtils.SafeNormalize(currSegmentDir);
// The y component of the cross product of the two normalized segment directions. // The y component of the cross product of the two normalized segment directions.
// The X and Z components of the cross product are both zero because the two // The X and Z components of the cross product are both zero because the two
@ -792,7 +792,7 @@ namespace DotRecast.Recast
bool bevel = cornerMiterSqMag * MITER_LIMIT * MITER_LIMIT < 1.0f; bool bevel = cornerMiterSqMag * MITER_LIMIT * MITER_LIMIT < 1.0f;
// Scale the corner miter so it's proportional to how much the corner should be offset compared to the edges. // Scale the corner miter so it's proportional to how much the corner should be offset compared to the edges.
if (cornerMiterSqMag > RcVec3f.EPSILON) if (cornerMiterSqMag > RcVecUtils.EPSILON)
{ {
float scale = 1.0f / cornerMiterSqMag; float scale = 1.0f / cornerMiterSqMag;
cornerMiterX *= scale; cornerMiterX *= scale;

View File

@ -253,7 +253,7 @@ namespace DotRecast.Recast
return null; return null;
} }
float discrSqrt = (float)Math.Sqrt(discr); float discrSqrt = MathF.Sqrt(discr);
float tmin = -b - discrSqrt; float tmin = -b - discrSqrt;
float tmax = -b + discrSqrt; float tmax = -b + discrSqrt;
@ -346,7 +346,7 @@ namespace DotRecast.Recast
float discr = b * b - c; float discr = b * b - c;
if (discr > EPSILON) if (discr > EPSILON)
{ {
float discrSqrt = (float)Math.Sqrt(discr); float discrSqrt = MathF.Sqrt(discr);
float t1 = -b - discrSqrt; float t1 = -b - discrSqrt;
float t2 = -b + discrSqrt; float t2 = -b + discrSqrt;
if (t1 <= 1 && t2 >= 0) if (t1 <= 1 && t2 >= 0)
@ -454,7 +454,7 @@ namespace DotRecast.Recast
return null; // No real roots; no intersection return null; // No real roots; no intersection
} }
float discSqrt = (float)Math.Sqrt(discr); float discSqrt = MathF.Sqrt(discr);
float t1 = (-b - discSqrt) / a; float t1 = (-b - discSqrt) / a;
float t2 = (-b + discSqrt) / a; float t2 = (-b + discSqrt) / a;

View File

@ -60,7 +60,7 @@ namespace DotRecast.Recast
private static float Vdist2(float[] verts, int p, int q) private static float Vdist2(float[] verts, int p, int q)
{ {
return (float)Math.Sqrt(VdistSq2(verts, p, q)); return MathF.Sqrt(VdistSq2(verts, p, q));
} }
private static float VdistSq2(float[] p, float[] q) private static float VdistSq2(float[] p, float[] q)
@ -88,17 +88,17 @@ namespace DotRecast.Recast
private static float Vdist2(float[] p, float[] q) private static float Vdist2(float[] p, float[] q)
{ {
return (float)Math.Sqrt(VdistSq2(p, q)); return MathF.Sqrt(VdistSq2(p, q));
} }
private static float Vdist2(RcVec3f p, RcVec3f q) private static float Vdist2(RcVec3f p, RcVec3f q)
{ {
return (float)Math.Sqrt(VdistSq2(p, q)); return MathF.Sqrt(VdistSq2(p, q));
} }
private static float Vdist2(float[] p, RcVec3f q) private static float Vdist2(float[] p, RcVec3f q)
{ {
return (float)Math.Sqrt(VdistSq2(p, q)); return MathF.Sqrt(VdistSq2(p, q));
} }
@ -119,12 +119,12 @@ namespace DotRecast.Recast
private static float Vdist2(float[] p, float[] verts, int q) private static float Vdist2(float[] p, float[] verts, int q)
{ {
return (float)Math.Sqrt(VdistSq2(p, verts, q)); return MathF.Sqrt(VdistSq2(p, verts, q));
} }
private static float Vdist2(RcVec3f p, float[] verts, int q) private static float Vdist2(RcVec3f p, float[] verts, int q)
{ {
return (float)Math.Sqrt(VdistSq2(p, verts, q)); return MathF.Sqrt(VdistSq2(p, verts, q));
} }
@ -743,7 +743,7 @@ namespace DotRecast.Recast
minDist = Math.Min(minDist, maxEdgeDist); minDist = Math.Min(minDist, maxEdgeDist);
} }
return (float)Math.Sqrt(minDist); return MathF.Sqrt(minDist);
} }
private static void TriangulateHull(int nverts, float[] verts, int nhull, int[] hull, int nin, List<int> tris) private static void TriangulateHull(int nverts, float[] verts, int nhull, int[] hull, int nin, List<int> tris)
@ -890,7 +890,7 @@ namespace DotRecast.Recast
float dx = @in[vi + 0] - @in[vj + 0]; float dx = @in[vi + 0] - @in[vj + 0];
float dy = @in[vi + 1] - @in[vj + 1]; float dy = @in[vi + 1] - @in[vj + 1];
float dz = @in[vi + 2] - @in[vj + 2]; float dz = @in[vi + 2] - @in[vj + 2];
float d = (float)Math.Sqrt(dx * dx + dz * dz); float d = MathF.Sqrt(dx * dx + dz * dz);
int nn = 1 + (int)Math.Floor(d / sampleDist); int nn = 1 + (int)Math.Floor(d / sampleDist);
if (nn >= MAX_VERTS_PER_EDGE) if (nn >= MAX_VERTS_PER_EDGE)
{ {