Skip to content

Commit 0845680

Browse files
committed
refactor: quat and vector normalization strategy
1 parent 0cf1c8b commit 0845680

File tree

3 files changed

+114
-42
lines changed

3 files changed

+114
-42
lines changed

src/FixedMathSharp/Numerics/FixedQuaternion.cs

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -182,19 +182,48 @@ public FixedQuaternion Rotated(Fixed64 sin, Fixed64 cos, Vector3d? axis = null)
182182

183183
#region Quaternion Operations
184184

185+
/// <summary>
186+
/// Checks if this vector has been normalized by checking if the magnitude is close to 1.
187+
/// </summary>
188+
public bool IsNormalized()
189+
{
190+
Fixed64 mag = GetMagnitude(this);
191+
return FixedMath.Abs(mag - Fixed64.One) <= Fixed64.Epsilon;
192+
}
193+
194+
public static Fixed64 GetMagnitude(FixedQuaternion q)
195+
{
196+
Fixed64 mag = (q.x * q.x) + (q.y * q.y) + (q.z * q.z) + (q.w * q.w);
197+
// If rounding error caused the final magnitude to be slightly above 1, clamp it
198+
if (mag > Fixed64.One && mag <= Fixed64.One + Fixed64.Epsilon)
199+
return Fixed64.One;
200+
201+
return mag != Fixed64.Zero ? FixedMath.Sqrt(mag) : Fixed64.Zero;
202+
}
203+
185204
/// <summary>
186205
/// Normalizes the quaternion to a unit quaternion.
187206
/// </summary>
188207
[MethodImpl(MethodImplOptions.AggressiveInlining)]
189208
public static FixedQuaternion GetNormalized(FixedQuaternion q)
190209
{
191-
Fixed64 mag = q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w;
192-
if (mag > Fixed64.Zero && mag != Fixed64.One)
193-
{
194-
Fixed64 invMagnitude = Fixed64.One / FixedMath.Sqrt(mag);
195-
return new FixedQuaternion(q.x * invMagnitude, q.y * invMagnitude, q.z * invMagnitude, q.w * invMagnitude);
196-
}
197-
return q;
210+
Fixed64 mag = GetMagnitude(q);
211+
212+
// If magnitude is zero, return identity quaternion (to avoid divide by zero)
213+
if (mag == Fixed64.Zero)
214+
return new FixedQuaternion(Fixed64.Zero, Fixed64.Zero, Fixed64.Zero, Fixed64.One);
215+
216+
// If already normalized, return as-is
217+
if (mag == Fixed64.One)
218+
return q;
219+
220+
// Normalize it exactly
221+
return new FixedQuaternion(
222+
q.x / mag,
223+
q.y / mag,
224+
q.z / mag,
225+
q.w / mag
226+
);
198227
}
199228

200229
/// <summary>
@@ -343,7 +372,7 @@ public static FixedQuaternion FromAxisAngle(Vector3d axis, Fixed64 angle)
343372
public static FixedQuaternion FromEulerAnglesInDegrees(Fixed64 pitch, Fixed64 yaw, Fixed64 roll)
344373
{
345374
// Convert input angles from degrees to radians
346-
pitch = FixedMath.DegToRad(pitch);
375+
pitch = FixedMath.DegToRad(pitch);
347376
yaw = FixedMath.DegToRad(yaw);
348377
roll = FixedMath.DegToRad(roll);
349378

@@ -432,8 +461,8 @@ public static Vector3d QuaternionLog(FixedQuaternion q)
432461
/// - Finally, it divides by `deltaTime` to compute the angular velocity.
433462
/// </remarks>
434463
public static Vector3d ToAngularVelocity(
435-
FixedQuaternion currentRotation,
436-
FixedQuaternion previousRotation,
464+
FixedQuaternion currentRotation,
465+
FixedQuaternion previousRotation,
437466
Fixed64 deltaTime)
438467
{
439468
FixedQuaternion rotationDelta = currentRotation * previousRotation.Inverse();

src/FixedMathSharp/Numerics/Vector2d.cs

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -335,12 +335,23 @@ public Vector2d Normalize()
335335
[MethodImpl(MethodImplOptions.AggressiveInlining)]
336336
public Vector2d Normalize(out Fixed64 mag)
337337
{
338-
mag = Magnitude;
339-
if (mag > Fixed64.Zero && mag != Fixed64.One)
338+
mag = GetMagnitude(this);
339+
340+
// If magnitude is zero, return a zero vector to avoid divide-by-zero errors
341+
if (mag == Fixed64.Zero)
340342
{
341-
x /= mag;
342-
y /= mag;
343+
x = Fixed64.Zero;
344+
y = Fixed64.Zero;
345+
return this;
343346
}
347+
348+
// If already normalized, return as-is
349+
if (mag == Fixed64.One)
350+
return this;
351+
352+
x /= mag;
353+
y /= mag;
354+
344355
return this;
345356
}
346357

@@ -604,13 +615,19 @@ public Fixed64 SqrDistance(Vector2d other)
604615
public static Vector2d GetNormalized(Vector2d value)
605616
{
606617
Fixed64 mag = GetMagnitude(value);
607-
if (mag > Fixed64.Zero && mag != Fixed64.One)
608-
{
609-
Fixed64 xM = value.x / mag;
610-
Fixed64 yM = value.y / mag;
611-
return new Vector2d(xM, yM);
612-
}
613-
return value;
618+
619+
if (mag == Fixed64.Zero)
620+
return new Vector2d(Fixed64.Zero, Fixed64.Zero);
621+
622+
// If already normalized, return as-is
623+
if (mag == Fixed64.One)
624+
return value;
625+
626+
// Normalize it exactly
627+
return new Vector2d(
628+
value.x / mag,
629+
value.y / mag
630+
);
614631
}
615632

616633
/// <summary>
@@ -621,8 +638,13 @@ public static Vector2d GetNormalized(Vector2d value)
621638
[MethodImpl(MethodImplOptions.AggressiveInlining)]
622639
public static Fixed64 GetMagnitude(Vector2d vector)
623640
{
624-
Fixed64 temp1 = (vector.x * vector.x) + (vector.y * vector.y);
625-
return temp1.Abs() > Fixed64.Zero ? FixedMath.Sqrt(temp1) : Fixed64.Zero;
641+
Fixed64 mag = (vector.x * vector.x) + (vector.y * vector.y);
642+
643+
// If rounding error pushed magnitude slightly above 1, clamp it
644+
if (mag > Fixed64.One && mag <= Fixed64.One + Fixed64.Epsilon)
645+
return Fixed64.One;
646+
647+
return mag.Abs() > Fixed64.Zero ? FixedMath.Sqrt(mag) : Fixed64.Zero;
626648
}
627649

628650
/// <summary>

src/FixedMathSharp/Numerics/Vector3d.cs

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -374,17 +374,26 @@ public Vector3d Normalize()
374374
/// If the vector is zero-length or already normalized, no operation is performed, but the original magnitude will still be output.
375375
/// </remarks>
376376
[MethodImpl(MethodImplOptions.AggressiveInlining)]
377-
public Vector3d Normalize(out Fixed64 m)
377+
public Vector3d Normalize(out Fixed64 mag)
378378
{
379-
Fixed64 mag = Magnitude;
380-
if (mag > Fixed64.Zero && mag != Fixed64.One)
379+
mag = GetMagnitude(this);
380+
381+
// If magnitude is zero, return a zero vector to avoid divide-by-zero errors
382+
if (mag == Fixed64.Zero)
381383
{
382-
x /= mag;
383-
y /= mag;
384-
z /= mag;
384+
x = Fixed64.Zero;
385+
y = Fixed64.Zero;
386+
z = Fixed64.Zero;
387+
return this;
385388
}
386389

387-
m = mag;
390+
// If already normalized, return as-is
391+
if (mag == Fixed64.One)
392+
return this;
393+
394+
x /= mag;
395+
y /= mag;
396+
z /= mag;
388397

389398
return this;
390399
}
@@ -394,7 +403,7 @@ public Vector3d Normalize(out Fixed64 m)
394403
/// </summary>
395404
public bool IsNormalized()
396405
{
397-
return Magnitude.Round() - Fixed64.One == Fixed64.Zero;
406+
return FixedMath.Abs(Magnitude - Fixed64.One) <= Fixed64.Epsilon;
398407
}
399408

400409
/// <summary>
@@ -561,14 +570,21 @@ public static Vector3d Slerp(Vector3d start, Vector3d end, Fixed64 percent)
561570
public static Vector3d GetNormalized(Vector3d value)
562571
{
563572
Fixed64 mag = GetMagnitude(value);
564-
if (mag > Fixed64.Zero && mag != Fixed64.One)
565-
{
566-
Fixed64 xM = value.x / mag;
567-
Fixed64 yM = value.y / mag;
568-
Fixed64 zM = value.z / mag;
569-
return new Vector3d(xM, yM, zM);
570-
}
571-
return value;
573+
574+
// If magnitude is zero, return a zero vector to avoid divide-by-zero errors
575+
if (mag == Fixed64.Zero)
576+
return new Vector3d(Fixed64.Zero, Fixed64.Zero, Fixed64.Zero);
577+
578+
// If already normalized, return as-is
579+
if (mag == Fixed64.One)
580+
return value;
581+
582+
// Normalize it exactly
583+
return new Vector3d(
584+
value.x / mag,
585+
value.y / mag,
586+
value.z / mag
587+
);
572588
}
573589

574590
/// <summary>
@@ -579,8 +595,13 @@ public static Vector3d GetNormalized(Vector3d value)
579595
[MethodImpl(MethodImplOptions.AggressiveInlining)]
580596
public static Fixed64 GetMagnitude(Vector3d vector)
581597
{
582-
Fixed64 temp1 = (vector.x * vector.x) + (vector.y * vector.y) + (vector.z * vector.z);
583-
return temp1 != Fixed64.Zero ? FixedMath.Sqrt(temp1) : Fixed64.Zero;
598+
Fixed64 mag = (vector.x * vector.x) + (vector.y * vector.y) + (vector.z * vector.z);
599+
600+
// If rounding error pushed magnitude slightly above 1, clamp it
601+
if (mag > Fixed64.One && mag <= Fixed64.One + Fixed64.Epsilon)
602+
return Fixed64.One;
603+
604+
return mag != Fixed64.Zero ? FixedMath.Sqrt(mag) : Fixed64.Zero;
584605
}
585606

586607
/// <summary>
@@ -1010,7 +1031,7 @@ public static Vector3d InverseRotate(Vector3d source, Vector3d position, FixedQu
10101031
[MethodImpl(MethodImplOptions.AggressiveInlining)]
10111032
public static Vector3d operator *(Fixed4x4 matrix, Vector3d point)
10121033
{
1013-
if(matrix.IsAffine)
1034+
if (matrix.IsAffine)
10141035
{
10151036
return new Vector3d(
10161037
matrix.m00 * point.x + matrix.m01 * point.y + matrix.m02 * point.z + matrix.m03 + matrix.m30,

0 commit comments

Comments
 (0)