From 77648071d9d21ee2518ed09f96227e77ad3a4c31 Mon Sep 17 00:00:00 2001 From: Martin Dias Date: Mon, 2 Dec 2024 23:47:58 -0300 Subject: [PATCH] Avoid using Array2D since it's deprecated in Pharo 12 * asMatrixCollection was only used from printOn:. I rewrote it to print directly. * The real use was as internal state of BlMatrixDecomposition2D, to store (sx, sy, shx, shy) values in some maths for interpolation. I rewrote the code to directly reference those 4 values instead of the Array2D. See #643 --- src/Bloc/BlMatrix.class.st | 10 +- src/Bloc/BlMatrix2D.class.st | 110 +++++++------ src/Bloc/BlMatrix3D.class.st | 32 ++-- src/Bloc/BlMatrixDecomposition.class.st | 12 +- src/Bloc/BlMatrixDecomposition2D.class.st | 183 ++++++++++++---------- 5 files changed, 178 insertions(+), 169 deletions(-) diff --git a/src/Bloc/BlMatrix.class.st b/src/Bloc/BlMatrix.class.st index a49015377..c16e9a76f 100644 --- a/src/Bloc/BlMatrix.class.st +++ b/src/Bloc/BlMatrix.class.st @@ -15,13 +15,6 @@ BlMatrix >> = anObject [ self subclassResponsibility ] -{ #category : #converting } -BlMatrix >> asMatrixCollection [ - - - ^ self subclassResponsibility -] - { #category : #'matrix - mathematical functions' } BlMatrix >> decomposition [ "Return a decomposition of the matrix" @@ -45,8 +38,7 @@ BlMatrix >> hash [ { #category : #'matrix - mathematical functions' } BlMatrix >> interpolate: aFactor to: anotherMatrix [ - "Perform a matrix interpolation with a given factor" - + "Answer a `BlMatrix` that interpolates self with another matrix, with a given factor." ^ (self decomposition interpolate: aFactor diff --git a/src/Bloc/BlMatrix2D.class.st b/src/Bloc/BlMatrix2D.class.st index b0676a943..6eea44403 100644 --- a/src/Bloc/BlMatrix2D.class.st +++ b/src/Bloc/BlMatrix2D.class.st @@ -84,79 +84,63 @@ BlMatrix2D >> = anObject [ and: [ self y = anObject y ] ] ] ] ] ] -{ #category : #converting } -BlMatrix2D >> asMatrixCollection [ - ^ Array2D rows: 3 columns: 3 contents: { - sx . shx . x. - shy . sy . y. - 0 . 0. 1 - } -] - { #category : #'matrix - mathematical functions' } BlMatrix2D >> decomposition [ - "Decompose this 2D Matrix into components and return a resulting decomposition. - Based on https://drafts.csswg.org/css-transforms/#decomposing-a-2d-matrix" - - - | row0x row0y row1x row1y scaleX scaleY translate determinant angle matrix | - - row0x := self sx. - row0y := self shy. - row1x := self shx. - row1y := self sy. + "Answer my decomposition, in a`BlMatrixDecomposition2D`. + + Based on: https://drafts.csswg.org/css-transforms/#decomposing-a-2d-matrix" - translate := BlVector x: self x y: self y. + | row0x row0y row1x row1y scaleX scaleY determinant angle | + row0x := sx. + row0y := shy. + row1x := shx. + row1y := sy. + scaleX := ((row0x * row0x) + (row0y * row0y)) sqrt. scaleY := ((row1x * row1x) + (row1y * row1y)) sqrt. - determinant := (row0x * row1y) - (row0y * row1x). "If determinant is negative, one axis was flipped." - determinant < 0 - ifTrue: [ - row0x < row1y - ifTrue: [ scaleX := scaleX negated ] - ifFalse: [ scaleY := scaleY negated ] ]. + determinant := (row0x * row1y) - (row0y * row1x). + determinant < 0 ifTrue: [ + row0x < row1y + ifTrue: [ scaleX := scaleX negated ] + ifFalse: [ scaleY := scaleY negated ] ]. "Renormalize matrix to remove scale." - scaleX isZero - ifFalse: [ - row0x := row0x * (1.0 / scaleX). - row0y := row0y * (1.0 / scaleX) ]. - scaleY isZero - ifFalse: [ - row1x := row1x * (1.0 / scaleY). - row1y := row1y * (1.0 / scaleY) ]. + scaleX isZero ifFalse: [ + row0x := row0x * (1.0 / scaleX). + row0y := row0y * (1.0 / scaleX) ]. + scaleY isZero ifFalse: [ + row1x := row1x * (1.0 / scaleY). + row1y := row1y * (1.0 / scaleY) ]. "Compute rotation and renormalize matrix." angle := row0y arcTan: row0x. - angle isZero - ifFalse: [ - | sn cs m11 m12 m21 m22 | - sn := row0y negated. - cs := row0x. - m11 := row0x. - m12 := row0y. - m21 := row1x. - m22 := row1y. - row0x := (cs * m11) + (sn * m21). - row0y := (cs * m12) + (sn * m22). - row1x := (sn negated * m11) + (cs * m21). - row1y := (sn negated * m12) + (cs * m22) ]. - - matrix := Array2D - rows: 2 - columns: 2 - contents: { row0x . row0y . row1x . row1y }. - + angle isZero ifFalse: [ + | sn cs m11 m12 m21 m22 | + sn := row0y negated. + cs := row0x. + m11 := row0x. + m12 := row0y. + m21 := row1x. + m22 := row1y. + row0x := (cs * m11) + (sn * m21). + row0y := (cs * m12) + (sn * m22). + row1x := (sn negated * m11) + (cs * m21). + row1y := (sn negated * m12) + (cs * m22) ]. + "Convert into degrees because our rotation functions expect it." angle := angle radiansToDegrees. ^ BlMatrixDecomposition2D new - translation: translate; + translation: (BlVector x: x y: y); scale: (BlVector x: scaleX y: scaleY); angle: angle; - matrix: matrix + sx: row0x; + sy: row1y; + shx: row1x; + shy: row0y; + yourself ] { #category : #'matrix - mathematical functions' } @@ -281,7 +265,21 @@ BlMatrix2D >> perspective: aDepth [ { #category : #printing } BlMatrix2D >> printOn: aStream [ - aStream print: self asMatrixCollection + + super printOn: aStream. + + aStream nextPut: $(. + + #(x y sx sy shx shy) + do: [ :each | + aStream + nextPutAll: each; + nextPut: $:; + space. + ((self perform: each) printOn: aStream) ] + separatedBy: [ aStream space ]. + + aStream nextPut: $) ] { #category : #'matrix - transformations' } diff --git a/src/Bloc/BlMatrix3D.class.st b/src/Bloc/BlMatrix3D.class.st index cd4ef7186..cccd424b9 100644 --- a/src/Bloc/BlMatrix3D.class.st +++ b/src/Bloc/BlMatrix3D.class.st @@ -85,19 +85,6 @@ BlMatrix3D >> = anObject [ ^true ] -{ #category : #converting } -BlMatrix3D >> asMatrixCollection [ - ^ Array2D - rows: 4 - columns: 4 - contents: { - sx . shx0 . shx1 . x . - shy0 . sy . shy1 . y . - shz0 . shz1 . sz . z . - wx . wy . wz . w - } -] - { #category : #initialization } BlMatrix3D >> initialize [ super initialize. @@ -296,6 +283,25 @@ BlMatrix3D >> preTranslateX: aX Y: aY Z: aZ [ w := w + (aX * wx) + (aY * wy) + (aZ * wz) ] +{ #category : #printing } +BlMatrix3D >> printOn: aStream [ + + super printOn: aStream. + + aStream nextPut: $(. + + #(#x #y #z #w #sx #sy #sz #shx0 #shy0 #shz0 #shx1 #shy1 #shz1 #wx #wy #wz) + do: [ :each | + aStream + nextPutAll: each; + nextPut: $:; + space. + ((self perform: each) printOn: aStream) ] + separatedBy: [ aStream space ]. + + aStream nextPut: $) +] + { #category : #initialization } BlMatrix3D >> quaternion: aQuaternion [ "Set me to be a rotation matrix defined by a given quaternion" diff --git a/src/Bloc/BlMatrixDecomposition.class.st b/src/Bloc/BlMatrixDecomposition.class.st index 2582cc94d..68602aa0c 100644 --- a/src/Bloc/BlMatrixDecomposition.class.st +++ b/src/Bloc/BlMatrixDecomposition.class.st @@ -21,24 +21,16 @@ Class { #category : #'Bloc-Basic-Math' } -{ #category : #converting } -BlMatrixDecomposition >> asDictionary [ - - - ^ self subclassResponsibility -] - { #category : #'matrix - mathematical functions' } BlMatrixDecomposition >> composition [ - "Compose and return a matrix for this decomposition" - + "Compose and return a `BlMatrix` for this decomposition" ^ self subclassResponsibility ] { #category : #'matrix - mathematical functions' } BlMatrixDecomposition >> interpolate: aFactor to: anotherDecomposition [ - + "Answer a `BlMatrixDecomposition` that interpolates self with anotherDecomposition." ^ self subclassResponsibility ] diff --git a/src/Bloc/BlMatrixDecomposition2D.class.st b/src/Bloc/BlMatrixDecomposition2D.class.st index ab7377eeb..e408d765d 100644 --- a/src/Bloc/BlMatrixDecomposition2D.class.st +++ b/src/Bloc/BlMatrixDecomposition2D.class.st @@ -11,7 +11,10 @@ Class { 'translation', 'scale', 'angle', - 'matrix' + 'sx', + 'sy', + 'shx', + 'shy' ], #category : #'Bloc-Basic-Math' } @@ -19,133 +22,151 @@ Class { { #category : #accessing } BlMatrixDecomposition2D >> angle [ "Return a decomposed rotation angle in degrees" - ^ angle ] { #category : #accessing } -BlMatrixDecomposition2D >> angle: aNumber [ - angle := aNumber -] +BlMatrixDecomposition2D >> angle: aNumberOfDegrees [ -{ #category : #converting } -BlMatrixDecomposition2D >> asDictionary [ - - ^ { - 'Translation' -> self translation. - 'Scale' -> self scale. - 'Rotation angle (degrees)' -> self angle. - 'Inner matrix' -> self matrix - } asOrderedDictionary + angle := aNumberOfDegrees ] { #category : #'matrix - mathematical functions' } BlMatrixDecomposition2D >> composition [ - - | composedMatrix | - - composedMatrix := BlMatrix2D new. - composedMatrix sx: (matrix at: 1 at: 1). - composedMatrix shy: (matrix at: 1 at: 2). - composedMatrix shx: (matrix at: 2 at: 1). - composedMatrix sy: (matrix at: 2 at: 2). + + | aMatrix | + aMatrix := BlMatrix2D new. + aMatrix sx: sx. + aMatrix sy: sy. + aMatrix shx: shx. + aMatrix shy: shy. "Translate matrix" - composedMatrix x: (translation x * composedMatrix sx) + (translation y * composedMatrix shx). - composedMatrix y: (translation x * composedMatrix shy) + (translation y * composedMatrix sy). + aMatrix x: (translation x * aMatrix sx) + (translation y * aMatrix shx). + aMatrix y: (translation x * aMatrix shy) + (translation y * aMatrix sy). - "rotate matrix" - composedMatrix := (BlMatrix2D rotation: angle degreesToRadians) multiplyBy: (composedMatrix). + "Rotate matrix" + aMatrix := (BlMatrix2D rotation: angle degreesToRadians) multiplyBy: aMatrix. "Scale matrix." - composedMatrix sx: composedMatrix sx * scale x. - composedMatrix shy: composedMatrix shy * scale x. - composedMatrix shx: composedMatrix shx * scale y. - composedMatrix sy: composedMatrix sy * scale y. + aMatrix sx: aMatrix sx * scale x. + aMatrix shy: aMatrix shy * scale x. + aMatrix shx: aMatrix shx * scale y. + aMatrix sy: aMatrix sy * scale y. - ^ composedMatrix + ^ aMatrix ] { #category : #'matrix - mathematical functions' } BlMatrixDecomposition2D >> interpolate: aFactor to: anotherDecomposition [ "Algorithm is based on https://drafts.csswg.org/css-transforms/#interpolation-of-decomposed-2d-matrix-values" - - | aScaleX aScaleY anAngle anOtherAngle aTranslation aScale aMatrix | - - aScaleX := self scale x. - aScaleY := self scale y. - anAngle := self angle. - anOtherAngle := anotherDecomposition angle. - - ((aScaleX < 0 and: [ anotherDecomposition scale y ]) - or: [ aScaleY < 0 and: [ anotherDecomposition scale x < 0 ] ]) - ifTrue: [ - aScaleX := aScaleX negated. - aScaleY := aScaleY negated. - anAngle < 0 - ifTrue: [ anAngle := anAngle + 180 ] - ifFalse: [ anAngle := anAngle - 180 ] ]. + + | aScaleX aScaleY anAngle anotherAngle | + aScaleX := scale x. + aScaleY := scale y. + anAngle := angle. + anotherAngle := anotherDecomposition angle. + + ((aScaleX < 0 and: [ anotherDecomposition scale y < 0 ]) or: + [ aScaleY < 0 and: [ anotherDecomposition scale x < 0 ] ]) + ifTrue: [ + aScaleX := aScaleX negated. + aScaleY := aScaleY negated. + anAngle := anAngle < 0 + ifTrue: [ anAngle + 180 ] + ifFalse: [ anAngle - 180 ] ]. "Don't rotate the long way around." - anAngle isZero - ifTrue: [ anAngle := 360 ]. - anOtherAngle isZero - ifTrue: [ anOtherAngle := 360 ]. - - (anAngle - anOtherAngle) abs > 180 - ifTrue: [ - anAngle > anOtherAngle - ifTrue: [ anAngle := anAngle - 360 ] - ifFalse: [ anOtherAngle := anOtherAngle - 360 ] ]. + anAngle isZero ifTrue: [ anAngle := 360 ]. + anotherAngle isZero ifTrue: [ anotherAngle := 360 ]. + + (anAngle - anotherAngle) abs > 180 ifTrue: [ + anAngle > anotherAngle + ifTrue: [ anAngle := anAngle - 360 ] + ifFalse: [ anotherAngle := anotherAngle - 360 ] ]. "Interpolate all values." - aTranslation := self translation + ((anotherDecomposition translation - self translation) * aFactor). - aScale := self scale + ((anotherDecomposition scale - (BlVector x: aScaleX y: aScaleY)) * aFactor). - anAngle := anAngle + ((anOtherAngle - anAngle) * aFactor). - aMatrix := self matrix - with: anotherDecomposition matrix - collect: [ :aComponent :anOtherComponent | aComponent + ((anOtherComponent - aComponent) * aFactor) ]. - ^ self class new - translation: aTranslation; - scale: aScale; - angle: anAngle; - matrix: aMatrix + translation: translation + ((anotherDecomposition translation - translation) * aFactor); + scale: scale + ((anotherDecomposition scale - (BlVector x: aScaleX y: aScaleY)) * aFactor); + angle: anAngle + ((anotherAngle - anAngle) * aFactor); + sx: sx + ((anotherDecomposition sx - sx) * aFactor); + sy: sy + ((anotherDecomposition sy - sy) * aFactor); + shx: shx + ((anotherDecomposition shx - shx) * aFactor); + shy: shy + ((anotherDecomposition shy - shy) * aFactor); + yourself ] { #category : #accessing } -BlMatrixDecomposition2D >> matrix [ - +BlMatrixDecomposition2D >> scale [ - ^ matrix + ^ scale ] { #category : #accessing } -BlMatrixDecomposition2D >> matrix: aMatrix [ - matrix := aMatrix +BlMatrixDecomposition2D >> scale: aBlVector [ + + scale := aBlVector ] { #category : #accessing } -BlMatrixDecomposition2D >> scale [ - +BlMatrixDecomposition2D >> shx [ - ^ scale + ^ shx +] + +{ #category : #accessing } +BlMatrixDecomposition2D >> shx: aNumber [ + + shx := aNumber +] + +{ #category : #accessing } +BlMatrixDecomposition2D >> shy [ + + ^ shy +] + +{ #category : #accessing } +BlMatrixDecomposition2D >> shy: aNumber [ + + shy := aNumber ] { #category : #accessing } -BlMatrixDecomposition2D >> scale: aVector [ - scale := aVector +BlMatrixDecomposition2D >> sx [ + + ^ sx +] + +{ #category : #accessing } +BlMatrixDecomposition2D >> sx: aNumber [ + + sx := aNumber +] + +{ #category : #accessing } +BlMatrixDecomposition2D >> sy [ + + ^ sy +] + +{ #category : #accessing } +BlMatrixDecomposition2D >> sy: aNumber [ + + sy := aNumber ] { #category : #accessing } BlMatrixDecomposition2D >> translation [ - "Return the vector (BlVector) corresponding to the translation." + "Return the vector (`BlVector`) corresponding to the translation." ^ translation ] { #category : #accessing } -BlMatrixDecomposition2D >> translation: aVector [ - translation := aVector +BlMatrixDecomposition2D >> translation: aBlVector [ + + translation := aBlVector ]