From 3d3cfa7886e8fad75284a9b9c7ada241e758e841 Mon Sep 17 00:00:00 2001 From: Martin Dias Date: Sat, 30 Nov 2024 20:37:24 -0300 Subject: [PATCH 1/2] AeCairoMatrix: Add API to scale and rotate about a center Fixes #75 --- .../AeCairoExamplesRenderTest.class.st | 35 ++++++++++++++ .../AeCairoMatrixTest.class.st | 32 +++++++++++++ src/Alexandrie-Cairo/AeCairoMatrix.class.st | 47 +++++++++++++++++++ 3 files changed, 114 insertions(+) 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 [ From ddca120cacd6a472987f06de01b8bef952ae11d5 Mon Sep 17 00:00:00 2001 From: Martin Dias Date: Sat, 30 Nov 2024 20:38:49 -0300 Subject: [PATCH 2/2] Add PNG for test added in parent commit --- tests/cairo/surfaceWithRotationAboutCenter.png | Bin 0 -> 1162 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/cairo/surfaceWithRotationAboutCenter.png diff --git a/tests/cairo/surfaceWithRotationAboutCenter.png b/tests/cairo/surfaceWithRotationAboutCenter.png new file mode 100644 index 0000000000000000000000000000000000000000..7d76786d19003ef9ba7ce0aa14f9f96c9852e343 GIT binary patch literal 1162 zcmV;51aX000D0Nklso zV2QO<448+@MiC??TrY)Pz=TcFM^X_W>^WH0JX|&q86T;gYRHa7vfHKLGGR=)P(^0& z!#dGKk)fiCJ#ust;+iih6mNYyo!^W>$Zv}O{cgV zB<#I^fb47VK7#R!G=#X(XfOOsqibq4!;wRnB}v3ddo%&dLAH$a2XlZ&E@EsX2u)I8 zN@AD;OZ%0R8v%sfS?P;nu)jk*&#=-q zU4W&KN6gV5ha97~0O>fk{ie@px!P~<|Jl?Py<8IJCL+U$FEl(u9@V@DAq2uic!GmG zVGap`ZBS?)O9~AW-|>w2)iKlgX#ft{#^wf`qklfRWq7`I%jp|Mmy;!vbh%$LJ$qq= zE_bn#xD!k@#ijBh*mQ;8{N9Y<;BOt@5SaB^KV2AXjouz?iQe(7i!8QvPF%}}NeO_} zbj7Q5Ef$nzm8zO~f+h=*M?bcH`))^IZeMd`VK?AfqiKk@TPE(jX$dd1_nw?>+x5|} zPwn=`_Kn$}6XG@P!?6{0x&yNT9}Zvg&L>awb?)_q*6liR)7f`&_6=+J4?tysfCcoy z_EYnR1CHeAC$^ z|3Qc61VQ`#1f3Ej6w+mh8+WE2rdLuoO$p~pr3;fgc6mp~tH1c1wyQS(wi}+!ff)co z>QO7zGyx%bLJ}>VU?KU+-eI%#eMrjDRVzQQqe*&ouVAJ19+eWE(sSs z!zRoLhB3o+20$6(m+3t`4%ZzZ_t=Bi)Jiptz?iwd$%@tw>!P917f+*PqBP+x@f;%MLWky*RJ@7u~MxYtU#x!&M9k z4O*!`2Xt?=m&$*o73F%>N;QGDwtghKDl&r^paq(EXy(=GNj2QE0Lv|U{fLCraQ_+b ce*Td93;aXOZ1>w#zyJUM07*qoM6N<$f+;6BEdT%j literal 0 HcmV?d00001