@@ -83,53 +83,60 @@ public static Vector2 ProjectiveTransform2D(float x, float y, Matrix4x4 matrix)
83
83
/// </summary>
84
84
/// <param name="degrees">The amount of rotation, in degrees.</param>
85
85
/// <param name="size">The source image size.</param>
86
+ /// <param name="transformSpace">The <see cref="TransformSpace"/> to use when creating the centered matrix.</param>
86
87
/// <returns>The <see cref="Matrix3x2"/>.</returns>
87
88
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
88
- public static Matrix3x2 CreateRotationTransformMatrixDegrees ( float degrees , Size size )
89
- => CreateCenteredTransformMatrix ( Matrix3x2Extensions . CreateRotationDegrees ( degrees , PointF . Empty ) , size ) ;
89
+ public static Matrix3x2 CreateRotationTransformMatrixDegrees ( float degrees , Size size , TransformSpace transformSpace )
90
+ => CreateRotationTransformMatrixRadians ( GeometryUtilities . DegreeToRadian ( degrees ) , size , transformSpace ) ;
90
91
91
92
/// <summary>
92
93
/// Creates a centered rotation transform matrix using the given rotation in radians and the source size.
93
94
/// </summary>
94
95
/// <param name="radians">The amount of rotation, in radians.</param>
95
96
/// <param name="size">The source image size.</param>
97
+ /// <param name="transformSpace">The <see cref="TransformSpace"/> to use when creating the centered matrix.</param>
96
98
/// <returns>The <see cref="Matrix3x2"/>.</returns>
97
99
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
98
- public static Matrix3x2 CreateRotationTransformMatrixRadians ( float radians , Size size )
99
- => CreateCenteredTransformMatrix ( Matrix3x2Extensions . CreateRotation ( radians , PointF . Empty ) , size ) ;
100
+ public static Matrix3x2 CreateRotationTransformMatrixRadians ( float radians , Size size , TransformSpace transformSpace )
101
+ => CreateCenteredTransformMatrix ( Matrix3x2Extensions . CreateRotation ( radians , PointF . Empty ) , size , transformSpace ) ;
100
102
101
103
/// <summary>
102
104
/// Creates a centered skew transform matrix from the give angles in degrees and the source size.
103
105
/// </summary>
104
106
/// <param name="degreesX">The X angle, in degrees.</param>
105
107
/// <param name="degreesY">The Y angle, in degrees.</param>
106
108
/// <param name="size">The source image size.</param>
109
+ /// <param name="transformSpace">The <see cref="TransformSpace"/> to use when creating the centered matrix.</param>
107
110
/// <returns>The <see cref="Matrix3x2"/>.</returns>
108
111
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
109
- public static Matrix3x2 CreateSkewTransformMatrixDegrees ( float degreesX , float degreesY , Size size )
110
- => CreateCenteredTransformMatrix ( Matrix3x2Extensions . CreateSkewDegrees ( degreesX , degreesY , PointF . Empty ) , size ) ;
112
+ public static Matrix3x2 CreateSkewTransformMatrixDegrees ( float degreesX , float degreesY , Size size , TransformSpace transformSpace )
113
+ => CreateSkewTransformMatrixRadians ( GeometryUtilities . DegreeToRadian ( degreesX ) , GeometryUtilities . DegreeToRadian ( degreesY ) , size , transformSpace ) ;
111
114
112
115
/// <summary>
113
116
/// Creates a centered skew transform matrix from the give angles in radians and the source size.
114
117
/// </summary>
115
118
/// <param name="radiansX">The X angle, in radians.</param>
116
119
/// <param name="radiansY">The Y angle, in radians.</param>
117
120
/// <param name="size">The source image size.</param>
121
+ /// <param name="transformSpace">The <see cref="TransformSpace"/> to use when creating the centered matrix.</param>
118
122
/// <returns>The <see cref="Matrix3x2"/>.</returns>
119
123
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
120
- public static Matrix3x2 CreateSkewTransformMatrixRadians ( float radiansX , float radiansY , Size size )
121
- => CreateCenteredTransformMatrix ( Matrix3x2Extensions . CreateSkew ( radiansX , radiansY , PointF . Empty ) , size ) ;
124
+ public static Matrix3x2 CreateSkewTransformMatrixRadians ( float radiansX , float radiansY , Size size , TransformSpace transformSpace )
125
+ => CreateCenteredTransformMatrix ( Matrix3x2Extensions . CreateSkew ( radiansX , radiansY , PointF . Empty ) , size , transformSpace ) ;
122
126
123
127
/// <summary>
124
128
/// Gets the centered transform matrix based upon the source rectangle.
125
129
/// </summary>
126
130
/// <param name="matrix">The transformation matrix.</param>
127
131
/// <param name="size">The source image size.</param>
132
+ /// <param name="transformSpace">
133
+ /// The <see cref="TransformSpace"/> to use when creating the centered matrix.
134
+ /// </param>
128
135
/// <returns>The <see cref="Matrix3x2"/></returns>
129
136
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
130
- public static Matrix3x2 CreateCenteredTransformMatrix ( Matrix3x2 matrix , Size size )
137
+ public static Matrix3x2 CreateCenteredTransformMatrix ( Matrix3x2 matrix , Size size , TransformSpace transformSpace )
131
138
{
132
- Size destinationSize = GetUnboundedTransformedSize ( matrix , size ) ;
139
+ Size transformSize = GetUnboundedTransformedSize ( matrix , size , transformSpace ) ;
133
140
134
141
// We invert the matrix to handle the transformation from screen to world space.
135
142
// This ensures scaling matrices are correct.
@@ -138,8 +145,10 @@ public static Matrix3x2 CreateCenteredTransformMatrix(Matrix3x2 matrix, Size siz
138
145
// The source size is provided using the coordinate space of the source image.
139
146
// however the transform should always be applied in the pixel space.
140
147
// To account for this we offset by the size - 1 to translate to the pixel space.
141
- Matrix3x2 translationToTargetCenter = Matrix3x2 . CreateTranslation ( new Vector2 ( - ( destinationSize . Width - 1 ) , - ( destinationSize . Height - 1 ) ) * .5F ) ;
142
- Matrix3x2 translateToSourceCenter = Matrix3x2 . CreateTranslation ( new Vector2 ( size . Width - 1 , size . Height - 1 ) * .5F ) ;
148
+ float offset = transformSpace == TransformSpace . Pixel ? 1F : 0F ;
149
+
150
+ Matrix3x2 translationToTargetCenter = Matrix3x2 . CreateTranslation ( new Vector2 ( - ( transformSize . Width - offset ) , - ( transformSize . Height - offset ) ) * .5F ) ;
151
+ Matrix3x2 translateToSourceCenter = Matrix3x2 . CreateTranslation ( new Vector2 ( size . Width - offset , size . Height - offset ) * .5F ) ;
143
152
144
153
// Translate back to world space.
145
154
Matrix3x2 . Invert ( translationToTargetCenter * inverted * translateToSourceCenter , out Matrix3x2 centered ) ;
@@ -161,12 +170,6 @@ public static Matrix4x4 CreateTaperMatrix(Size size, TaperSide side, TaperCorner
161
170
{
162
171
Matrix4x4 matrix = Matrix4x4 . Identity ;
163
172
164
- // The source size is provided using the Coordinate/Geometric space of the source image.
165
- // However, the transform should always be applied in the Discrete/Pixel space to ensure
166
- // that the transformation fully encompasses all pixels without clipping at the edges.
167
- // To account for this, we subtract [1,1] from the size to translate to the Discrete/Pixel space.
168
- // size -= new Size(1, 1);
169
-
170
173
/*
171
174
* SkMatrix is laid out in the following manner:
172
175
*
@@ -280,11 +283,10 @@ public static Matrix4x4 CreateTaperMatrix(Size size, TaperSide side, TaperCorner
280
283
/// </summary>
281
284
/// <param name="matrix">The transformation matrix.</param>
282
285
/// <param name="size">The source size.</param>
283
- /// <returns>
284
- /// The <see cref="Size"/>.
285
- /// </returns>
286
- public static Size GetTransformedSize ( Matrix3x2 matrix , Size size )
287
- => GetTransformedSize ( matrix , size , true ) ;
286
+ /// <param name="transformSpace">The <see cref="TransformSpace"/> to use when calculating the size.</param>
287
+ /// <returns>The <see cref="Size"/>.</returns>
288
+ public static Size GetTransformedSize ( Matrix3x2 matrix , Size size , TransformSpace transformSpace )
289
+ => GetTransformedSize ( matrix , size , transformSpace , true ) ;
288
290
289
291
/// <summary>
290
292
/// Returns the size relative to the source for the given transformation matrix.
@@ -355,22 +357,22 @@ public static Size GetTransformedSize(Matrix4x4 matrix, Size size)
355
357
/// </summary>
356
358
/// <param name="matrix">The transformation matrix.</param>
357
359
/// <param name="size">The source size.</param>
358
- /// <returns>
359
- /// The <see cref="Size"/>.
360
- /// </returns>
361
- private static Size GetUnboundedTransformedSize ( Matrix3x2 matrix , Size size )
362
- => GetTransformedSize ( matrix , size , false ) ;
360
+ /// <param name="transformSpace">The <see cref="TransformSpace"/> to use when calculating the size.</param>
361
+ /// <returns>The <see cref="Size"/>.</returns>
362
+ private static Size GetUnboundedTransformedSize ( Matrix3x2 matrix , Size size , TransformSpace transformSpace )
363
+ => GetTransformedSize ( matrix , size , transformSpace , false ) ;
363
364
364
365
/// <summary>
365
366
/// Returns the size relative to the source for the given transformation matrix.
366
367
/// </summary>
367
368
/// <param name="matrix">The transformation matrix.</param>
368
369
/// <param name="size">The source size.</param>
370
+ /// <param name="transformSpace">The <see cref="TransformSpace"/> to use when calculating the size.</param>
369
371
/// <param name="constrain">Whether to constrain the size to ensure that the dimensions are positive.</param>
370
372
/// <returns>
371
373
/// The <see cref="Size"/>.
372
374
/// </returns>
373
- private static Size GetTransformedSize ( Matrix3x2 matrix , Size size , bool constrain )
375
+ private static Size GetTransformedSize ( Matrix3x2 matrix , Size size , TransformSpace transformSpace , bool constrain )
374
376
{
375
377
Guard . IsTrue ( size . Width > 0 && size . Height > 0 , nameof ( size ) , "Source size dimensions cannot be 0!" ) ;
376
378
@@ -381,9 +383,13 @@ private static Size GetTransformedSize(Matrix3x2 matrix, Size size, bool constra
381
383
382
384
// Define an offset size to translate between coordinate space and pixel space.
383
385
// Compute scaling factors from the matrix
384
- float scaleX = 1F / new Vector2 ( matrix . M11 , matrix . M21 ) . Length ( ) ; // sqrt(M11^2 + M21^2)
385
- float scaleY = 1F / new Vector2 ( matrix . M12 , matrix . M22 ) . Length ( ) ; // sqrt(M12^2 + M22^2)
386
- SizeF offsetSize = new ( scaleX , scaleY ) ;
386
+ SizeF offsetSize = SizeF . Empty ;
387
+ if ( transformSpace == TransformSpace . Pixel )
388
+ {
389
+ float scaleX = 1F / new Vector2 ( matrix . M11 , matrix . M21 ) . Length ( ) ; // sqrt(M11^2 + M21^2)
390
+ float scaleY = 1F / new Vector2 ( matrix . M12 , matrix . M22 ) . Length ( ) ; // sqrt(M12^2 + M22^2)
391
+ offsetSize = new ( scaleX , scaleY ) ;
392
+ }
387
393
388
394
// Subtract the offset size to translate to the pixel space.
389
395
if ( TryGetTransformedRectangle ( new RectangleF ( Point . Empty , size - offsetSize ) , matrix , out Rectangle bounds ) )
0 commit comments