diff --git a/src/Alexandrie-Cairo-Tests/AeCairoExamplesRenderTest.class.st b/src/Alexandrie-Cairo-Tests/AeCairoExamplesRenderTest.class.st index ee3002c..6fe3887 100644 --- a/src/Alexandrie-Cairo-Tests/AeCairoExamplesRenderTest.class.st +++ b/src/Alexandrie-Cairo-Tests/AeCairoExamplesRenderTest.class.st @@ -455,6 +455,41 @@ AeCairoExamplesRenderTest >> surfaceWithPixelatedIcon [ ^ aSurface ] +{ #category : #tests } +AeCairoExamplesRenderTest >> surfaceWithRotationAboutCenter [ + "Draw an asterisk with multiple lines rotated and scaled about the surface center." + + | extent pivot mainSurface mainContext aMatrix numberOfLines | + extent := 40 @ 30. + pivot := extent / 2. + numberOfLines := 5. + + mainSurface := + AeCairoImageSurface + extent: extent + format: AeCairoSurfaceFormat argb32. + mainContext := mainSurface newContext. + + aMatrix := AeCairoMatrix newIdentity. + (Color wheel: numberOfLines) do: [ :eachColor | + "Each iteration, rotate and scale a bit more" + aMatrix + rotateByRadians: Float twoPi / numberOfLines + center: pivot. + aMatrix + scaleBy: 1.2 @ 1.2 + center: pivot. + + mainContext + matrix: aMatrix; + sourceColor: (eachColor alpha: 0.75); + moveTo: pivot - 5; + lineTo: pivot + 5; + stroke ]. + + ^ mainSurface +] + { #category : #tests } AeCairoExamplesRenderTest >> surfaceWithRotationByQuadrantsOnContext [ diff --git a/src/Alexandrie-Cairo-Tests/AeCairoMatrixTest.class.st b/src/Alexandrie-Cairo-Tests/AeCairoMatrixTest.class.st index 8220bcf..80a8c71 100644 --- a/src/Alexandrie-Cairo-Tests/AeCairoMatrixTest.class.st +++ b/src/Alexandrie-Cairo-Tests/AeCairoMatrixTest.class.st @@ -303,6 +303,22 @@ AeCairoMatrixTest >> testRotateByRadians [ self assert: matrix shy equals: radians sin ] +{ #category : #tests } +AeCairoMatrixTest >> testRotateByRadiansCenter [ + + | radians | + matrix := AeCairoMatrix newIdentity. + radians := 180 degreesToRadians. + matrix rotateByRadians: radians center: 20@10. + + self assert: matrix x equals: 40.0. + self assert: matrix y equals: 20.0. + self assert: matrix sx equals: radians cos. + self assert: matrix sy equals: radians cos. + self assert: matrix shx equals: radians sin negated. + self assert: matrix shy equals: radians sin +] + { #category : #tests } AeCairoMatrixTest >> testRotateTwice [ @@ -335,6 +351,22 @@ AeCairoMatrixTest >> testScaleBy [ self assert: matrix scaleFactors equals: 2 @ 3 ] +{ #category : #tests } +AeCairoMatrixTest >> testScaleByCenter [ + + matrix := AeCairoMatrix newIdentity. + matrix scaleBy: 2 @ 3 center: 20 @ 10. + + self assert: matrix x equals: -20.0. + self assert: matrix y equals: -20.0. + self assert: matrix sx equals: 2.0. + self assert: matrix sy equals: 3.0. + self assert: matrix shx equals: 0.0. + self assert: matrix shy equals: 0.0. + + self assert: matrix scaleFactors equals: 2 @ 3 +] + { #category : #tests } AeCairoMatrixTest >> testScaleTwice [ diff --git a/src/Alexandrie-Cairo/AeCairoMatrix.class.st b/src/Alexandrie-Cairo/AeCairoMatrix.class.st index 5e452cf..2da9726 100644 --- a/src/Alexandrie-Cairo/AeCairoMatrix.class.st +++ b/src/Alexandrie-Cairo/AeCairoMatrix.class.st @@ -486,12 +486,47 @@ AeCairoMatrix >> rotateByRadians: angle [ double angle ) ) ] +{ #category : #'API - transformations' } +AeCairoMatrix >> rotateByRadians: angle center: aPoint [ + "Rotate about a center. + + See: https://www.cairographics.org/cookbook/transform_about_point/" + + self rotateByRadians: angle centerX: aPoint x y: aPoint y +] + +{ #category : #'API - transformations' } +AeCairoMatrix >> rotateByRadians: angle centerX: cx y: cy [ + "Rotate about a center. + + See: https://www.cairographics.org/cookbook/transform_about_point/" + + self + translateByX: cx y: cy; + rotateByRadians: angle; + translateByX: cx negated y: cy negated +] + { #category : #'API - transformations' } AeCairoMatrix >> scaleBy: aPoint [ + "Scale about origin (0@0)." self scaleByX: aPoint x y: aPoint y ] +{ #category : #'API - transformations' } +AeCairoMatrix >> scaleBy: aPoint center: anotherPoint [ + "Scale about a center. + + See: https://www.cairographics.org/cookbook/transform_about_point/" + + self + scaleByX: aPoint x + y: aPoint y + centerX: anotherPoint x + y: anotherPoint y +] + { #category : #'API - transformations' } AeCairoMatrix >> scaleByX: sx y: sy [ "Applies scaling by (sx @ sy) to the transformation in this matrix. The effect of the new transformation is to first scale the coordinates by sx and sy, then apply the original transformation to the coordinates. @@ -506,6 +541,18 @@ AeCairoMatrix >> scaleByX: sx y: sy [ double sy ) ) ] +{ #category : #'API - transformations' } +AeCairoMatrix >> scaleByX: sx y: sy centerX: cx y: cy [ + "Scale about a center. + + See: https://www.cairographics.org/cookbook/transform_about_point/" + + self + translateByX: cx y: cy; + scaleByX: sx y: sy; + translateByX: cx negated y: cy negated +] + { #category : #'accessing - structure variables' } AeCairoMatrix >> scaleFactors [ diff --git a/tests/cairo/surfaceWithRotationAboutCenter.png b/tests/cairo/surfaceWithRotationAboutCenter.png new file mode 100644 index 0000000..7d76786 Binary files /dev/null and b/tests/cairo/surfaceWithRotationAboutCenter.png differ