Repository navigation
Conversation
…any direction A SPATIAL_FILTER carries two matrices that place the clip boundary. Four faults between the four ends that read and write them. The DXF reader threw one away: the flag telling the inverse from the forward transform was set inside the branch that already required it to be true, so it never became true. Both twelve-double blocks went into InverseInsertTransform, the second overwriting the first, and InsertTransform was never assigned at all. The formats disagreed about the layout. Both record these as three rows of four with the translation in the fourth column - the transpose of how Matrix4 holds one, since CreateTranslation writes M30/M31/M32 and operator* reads the translation from there. The DXF path already landed in the library's convention (Matrix4(double[]) maps elements 0..3 to M00, M10, M20, M30); the DWG reader and writer kept the file's. The same matrix read from a DWG therefore dropped its own translation when applied to a point, and read from a DXF did not. The DWG reader and writer now transpose, and the DXF writer emits each file row from a matrix COLUMN, which is what Matrix4(double[]) undoes on the way in. Why nothing caught it: the single-object fixture built its filter with IDENTITY matrices, and an identity survives being transposed, dropped or doubled. It now carries a scale together with a translation. That alone is still not enough - the comparison does not reach these properties - so SpatialFilterRoundTripTests asserts them directly, including the case a per-format round trip structurally cannot see: that DWG and DXF agree with each other. Measured: sample_AC1032.dwg holds a clip whose inverse transform is a 25.4 scale with a translation. Through this library's own DXF it came back as the identity. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A
SPATIAL_FILTER(an XCLIP boundary) carries two matrices that place the boundary. Four faults between the four ends that read and write them.1. The DXF reader threw one away
The flag starts
falseand is only assigned inside the branch that already requires it to betrue. So both twelve-double blocks take theelse:InverseInsertTransformis written twice, the second overwriting the first, andInsertTransformis never assigned at all.2. The two formats disagreed about the layout
Both DWG and DXF record these as three rows of four with the translation in the fourth column. That is the transpose of how
Matrix4holds one:CreateTranslationwritesM30/M31/M32, andoperator *(Matrix4, XYZ)reads the translation from there.The DXF path already landed in the library's convention —
Matrix4(double[])mapselements[0..3]toM00, M10, M20, M30, so the file's rows become the matrix's columns. The DWG reader and writer kept the file's layout instead.The consequence is quiet and total: the same matrix read from a DWG dropped its own translation when applied to a point, while read from a DXF it did not. For a clip boundary, translation is most of what these matrices carry.
The fix
read4x3Matrixandwrite4x3Matrixtranspose, so the DWG path lands where the DXF path already was; and the DXF writer emits each file row from a matrix column, which is exactly whatMatrix4(double[])undoes on the way back in. All four ends now agree, andSpatialFilter.InverseInsertTransformcan be used withMatrix4's own operators without the caller knowing any of this.Why nothing caught it
SingleCaseGenerator.InsertWithSpatialFilterbuilds its filter with identity matrices — and an identity survives being transposed, dropped, or applied twice. The fixture now carries a scale together with a translation.That alone is still not enough: the single-object comparison does not reach these properties (I checked — with the fixture strengthened and the writer fix reverted, it still passed). So
SpatialFilterRoundTripTestsasserts them directly, including the one case a per-format round trip structurally cannot see: that DWG and DXF agree with each other. A format can be perfectly self-consistent and still disagree with the other.All three new tests fail against the current code.
Evidence
samples/sample_AC1032.dwgholds a clip whose inverse transform is a 25.4 scale with a translation of(-1087.9487, 942.61675, 0). Through this library's own DXF it came back as the identity — so a clipped insert reported the whole block instead of the clipped part.dotnet teston this branch: 2316 passed / 17 failed, againstmasterat 592d70a on this machine at 2313 / 17 — the same pre-existing failures, plus the three tests added here.Related
Found while checking a fidelity gate that flagged a lost entity after #1226 made something finally consume these matrices. #1226 transposes at the point of use and explicitly leaves this normalisation as a separate question; this PR is that answer, and #1226 should drop its
.Transpose()if both land.Same family: #1223, #1224, #1225, #1226, #1227, #1228, #1229, DomCR/CSUtilities#23.