Skip to content

Fix GetArbitraryAxis threshold for normals near +Z - #28

Open
jarrett-meyer wants to merge 1 commit into
DomCR:masterfrom
jarrett-meyer:fix/arbitrary-axis-threshold
Open

jarrett-meyer wants to merge 1 commit into
DomCR:masterfrom
jarrett-meyer:fix/arbitrary-axis-threshold

Conversation

@jarrett-meyer

Copy link
Copy Markdown

Bug

Matrix4.GetArbitraryAxis(XYZ zaxis) decides which world axis to cross with the normal using:

if (Math.Abs(zaxis.X) < (1 / 64) && Math.Abs(zaxis.Y) < (1 / 64))

1 / 64 is integer division, so the threshold is always 0 and the condition can never be true. For any normal whose X and Y components are both below 1/64 (but which is not exactly +Z or -Z), the method computes the X axis from Wz x N instead of Wy x N. This does not follow the DXF arbitrary axis algorithm, so entities with a normal close to +Z get an OCS rotated by about 90 degrees.

Matrix3.ArbitraryAxis already uses 1 / 64.0 and is not affected.

How to reproduce

XYZ n = new XYZ(0.01, 0, 1).Normalize();
Matrix4 m = Matrix4.GetArbitraryAxis(n);
// Expected X axis: Cross(AxisY, n) ~ (1, 0, -0.01)
// Actual X axis:   Cross(AxisZ, n) = (0, 1, 0)

Fix

Use 1.0 / 64 so the comparison is done in floating point.

Tests

Added CSMath.Tests/Matrix4Tests.cs with two cases: a normal near +Z (uses Wy x N; fails before this change) and a general normal (uses Wz x N). The full CSMath.Tests suite passes (292 tests).

🤖 Generated with Claude Code

`1 / 64` is integer division and evaluates to 0, so the near-Z branch
of the arbitrary axis algorithm was never taken and normals close to
+Z got an X axis from Wz x N instead of Wy x N. Use `1.0 / 64`, as
Matrix3.ArbitraryAxis already does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant