[x] I have written a descriptive pull-request title
[x] I have verified that there are no overlapping pull-requests open
[x] I have verified that I am following the existing coding patterns and practice as demonstrated in the repository. These follow strict Stylecop rules :cop:.
[x] I have provided test coverage for my change (where applicable)
Description
Fixes #2753
This is a rework of #2760 to correctly handle transforms that require working in the pixel transform space.
Previous attempts to fix these issues inadvertently introduced breaking changes for users who relied on the builder APIs to transform 2D paths. These changes affected how paths were handled, particularly in scenarios where the distinction between coordinate and pixel spaces wasn't explicitly managed. To mitigate this, the refactor introduces new configuration options within the builder APIs that allow users to specify which space (coordinate or pixel) they want to operate within. This ensures that developers can maintain control over how their transformations are applied, preserving existing workflows while also benefiting from the improved accuracy and flexibility of the new implementation. These options provide a smoother transition for users, allowing them to adapt to the changes without disrupting their existing codebases.
A little theory....
2D transforms take place in two different spaces:
Coordinate Space:
Coordinate space is a continuous, mathematical grid where objects and positions are defined with precise, often fractional values. This space allows for high-precision transformations like scaling, rotation, and translation. In coordinate space, each pixel is treated as a square unit that can be positioned and transformed with exactness, even down to fractions of a unit. However, the final rendering to a screen (which operates in pixel space) requires careful handling to ensure that these precise transformations map correctly to the discrete grid of pixels.
Pixel Space:
Pixel space is a discrete grid where each position corresponds to a specific pixel on the screen, defined by whole numbers. This space represents the actual grid of pixels that make up an image or rendering surface. Operations in pixel space are constrained to integer values, which means that any transformation needs to account for the fact that pixels are indivisible and cannot be positioned between grid points. This can introduce challenges when applying transformations like scaling or rotation, as the final positions must align with the pixel grid to avoid visual artifacts like clipping or misalignment.
Key Changes in This Refactor:
Accurate Space Handling:
The refactor ensures that transformations are applied correctly depending on the space in which they occur. For affine transformations, which typically include operations like scaling, rotation, and translation, the method now correctly distinguishes between when to use coordinate space (for precise, continuous transformations) and pixel space (for rendering and final output).
Inverted Scaled Offset:
One of the significant improvements is the correct application of an inverted scaled offset when transitioning from coordinate space to pixel space. This adjustment ensures that when scaling transformations are applied, the pixel boundaries align correctly with the intended coordinate boundaries, avoiding issues where pixels could be misaligned or clipped.
Conditional Offset Application:
The PR introduces logic to apply offsets only when appropriate. For example, when a transformation includes perspective or non-standard depth scaling, the offset is not applied, as the transformation is non-linear and requires a different handling approach. This ensures that the transformation's effects are correctly captured and rendered.
Improved Visual Accuracy:
These changes significantly enhance the visual accuracy of transformations, particularly when dealing with complex scenarios involving both rotation and scaling. By correctly handling the distinction between coordinate and pixel spaces, the refactor ensures that the final rendered output matches the intended design without unexpected distortions.
Prerequisites
Description
Fixes #2753
This is a rework of #2760 to correctly handle transforms that require working in the pixel transform space.
Previous attempts to fix these issues inadvertently introduced breaking changes for users who relied on the builder APIs to transform 2D paths. These changes affected how paths were handled, particularly in scenarios where the distinction between coordinate and pixel spaces wasn't explicitly managed. To mitigate this, the refactor introduces new configuration options within the builder APIs that allow users to specify which space (coordinate or pixel) they want to operate within. This ensures that developers can maintain control over how their transformations are applied, preserving existing workflows while also benefiting from the improved accuracy and flexibility of the new implementation. These options provide a smoother transition for users, allowing them to adapt to the changes without disrupting their existing codebases.
A little theory....
2D transforms take place in two different spaces:
Coordinate Space:
Pixel Space:
Key Changes in This Refactor:
Accurate Space Handling:
Inverted Scaled Offset:
Conditional Offset Application:
Improved Visual Accuracy: