@@ -83,53 +83,60 @@ public static Vector2 ProjectiveTransform2D(float x, float y, Matrix4x4 matrix)
8383 /// </summary>
8484 /// <param name="degrees">The amount of rotation, in degrees.</param>
8585 /// <param name="size">The source image size.</param>
86+ /// <param name="transformSpace">The <see cref="TransformSpace"/> to use when creating the centered matrix.</param>
8687 /// <returns>The <see cref="Matrix3x2"/>.</returns>
8788 [ 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 ) ;
9091
9192 /// <summary>
9293 /// Creates a centered rotation transform matrix using the given rotation in radians and the source size.
9394 /// </summary>
9495 /// <param name="radians">The amount of rotation, in radians.</param>
9596 /// <param name="size">The source image size.</param>
97+ /// <param name="transformSpace">The <see cref="TransformSpace"/> to use when creating the centered matrix.</param>
9698 /// <returns>The <see cref="Matrix3x2"/>.</returns>
9799 [ 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 ) ;
100102
101103 /// <summary>
102104 /// Creates a centered skew transform matrix from the give angles in degrees and the source size.
103105 /// </summary>
104106 /// <param name="degreesX">The X angle, in degrees.</param>
105107 /// <param name="degreesY">The Y angle, in degrees.</param>
106108 /// <param name="size">The source image size.</param>
109+ /// <param name="transformSpace">The <see cref="TransformSpace"/> to use when creating the centered matrix.</param>
107110 /// <returns>The <see cref="Matrix3x2"/>.</returns>
108111 [ 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 ) ;
111114
112115 /// <summary>
113116 /// Creates a centered skew transform matrix from the give angles in radians and the source size.
114117 /// </summary>
115118 /// <param name="radiansX">The X angle, in radians.</param>
116119 /// <param name="radiansY">The Y angle, in radians.</param>
117120 /// <param name="size">The source image size.</param>
121+ /// <param name="transformSpace">The <see cref="TransformSpace"/> to use when creating the centered matrix.</param>
118122 /// <returns>The <see cref="Matrix3x2"/>.</returns>
119123 [ 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 ) ;
122126
123127 /// <summary>
124128 /// Gets the centered transform matrix based upon the source rectangle.
125129 /// </summary>
126130 /// <param name="matrix">The transformation matrix.</param>
127131 /// <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>
128135 /// <returns>The <see cref="Matrix3x2"/></returns>
129136 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
130- public static Matrix3x2 CreateCenteredTransformMatrix ( Matrix3x2 matrix , Size size )
137+ public static Matrix3x2 CreateCenteredTransformMatrix ( Matrix3x2 matrix , Size size , TransformSpace transformSpace )
131138 {
132- Size destinationSize = GetUnboundedTransformedSize ( matrix , size ) ;
139+ Size transformSize = GetUnboundedTransformedSize ( matrix , size , transformSpace ) ;
133140
134141 // We invert the matrix to handle the transformation from screen to world space.
135142 // This ensures scaling matrices are correct.
@@ -138,8 +145,10 @@ public static Matrix3x2 CreateCenteredTransformMatrix(Matrix3x2 matrix, Size siz
138145 // The source size is provided using the coordinate space of the source image.
139146 // however the transform should always be applied in the pixel space.
140147 // 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 ) ;
143152
144153 // Translate back to world space.
145154 Matrix3x2 . Invert ( translationToTargetCenter * inverted * translateToSourceCenter , out Matrix3x2 centered ) ;
@@ -161,12 +170,6 @@ public static Matrix4x4 CreateTaperMatrix(Size size, TaperSide side, TaperCorner
161170 {
162171 Matrix4x4 matrix = Matrix4x4 . Identity ;
163172
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-
170173 /*
171174 * SkMatrix is laid out in the following manner:
172175 *
@@ -280,11 +283,10 @@ public static Matrix4x4 CreateTaperMatrix(Size size, TaperSide side, TaperCorner
280283 /// </summary>
281284 /// <param name="matrix">The transformation matrix.</param>
282285 /// <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 ) ;
288290
289291 /// <summary>
290292 /// Returns the size relative to the source for the given transformation matrix.
@@ -355,22 +357,22 @@ public static Size GetTransformedSize(Matrix4x4 matrix, Size size)
355357 /// </summary>
356358 /// <param name="matrix">The transformation matrix.</param>
357359 /// <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 ) ;
363364
364365 /// <summary>
365366 /// Returns the size relative to the source for the given transformation matrix.
366367 /// </summary>
367368 /// <param name="matrix">The transformation matrix.</param>
368369 /// <param name="size">The source size.</param>
370+ /// <param name="transformSpace">The <see cref="TransformSpace"/> to use when calculating the size.</param>
369371 /// <param name="constrain">Whether to constrain the size to ensure that the dimensions are positive.</param>
370372 /// <returns>
371373 /// The <see cref="Size"/>.
372374 /// </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 )
374376 {
375377 Guard . IsTrue ( size . Width > 0 && size . Height > 0 , nameof ( size ) , "Source size dimensions cannot be 0!" ) ;
376378
@@ -381,9 +383,13 @@ private static Size GetTransformedSize(Matrix3x2 matrix, Size size, bool constra
381383
382384 // Define an offset size to translate between coordinate space and pixel space.
383385 // 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+ }
387393
388394 // Subtract the offset size to translate to the pixel space.
389395 if ( TryGetTransformedRectangle ( new RectangleF ( Point . Empty , size - offsetSize ) , matrix , out Rectangle bounds ) )
0 commit comments