Skip to content

Commit c079c4c

Browse files
committed
Matrix updates
- Fix incorrect implementation of the Translate, Scale, Skew, and Rotate methods - Removed helper methods that took geom.Point - Assume degrees, not radians, and remove the ByDegrees variants in favor of the shorter name
1 parent 8b69968 commit c079c4c

File tree

3 files changed

+33
-111
lines changed

3 files changed

+33
-111
lines changed

collection/bitset/bitset.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,7 @@ func (b *BitSet) Load(data []uint64) {
392392
b.Trim()
393393
b.set = 0
394394
for i := len(b.data) - 1; i >= 0; i-- {
395-
word := data[i]
395+
word := data[i] //nolint:gosec // This is not a security issue.
396396
if word != 0 {
397397
for j := range dataBitsPerWord {
398398
mask := wordMask(j)

geom/matrix.go

Lines changed: 21 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,6 @@ func NewTranslationMatrix(tx, ty float32) Matrix {
4343
}
4444
}
4545

46-
// NewTranslationMatrixPt creates a new Matrix that translates by translation.X and translation.Y.
47-
func NewTranslationMatrixPt(translation Point) Matrix {
48-
return NewTranslationMatrix(translation.X, translation.Y)
49-
}
50-
5146
// NewScaleMatrix creates a new Matrix that scales by 'sx' and 'sy'.
5247
func NewScaleMatrix(sx, sy float32) Matrix {
5348
return Matrix{
@@ -56,16 +51,9 @@ func NewScaleMatrix(sx, sy float32) Matrix {
5651
}
5752
}
5853

59-
// NewScaleMatrixPt creates a new Matrix that scales by scale.X and scale.Y.
60-
func NewScaleMatrixPt(scale Point) Matrix {
61-
return Matrix{
62-
ScaleX: scale.X,
63-
ScaleY: scale.Y,
64-
}
65-
}
66-
67-
// NewRotationMatrix creates a new Matrix that rotates by 'radians'. Positive values are clockwise.
68-
func NewRotationMatrix(radians float32) Matrix {
54+
// NewRotationMatrix creates a new Matrix that rotates by 'degrees'. Positive values are clockwise.
55+
func NewRotationMatrix(degrees float32) Matrix {
56+
radians := degrees * xmath.DegreesToRadians
6957
s := xmath.Sin(radians)
7058
c := xmath.Cos(radians)
7159
return Matrix{
@@ -76,9 +64,14 @@ func NewRotationMatrix(radians float32) Matrix {
7664
}
7765
}
7866

79-
// NewRotationByDegreesMatrix creates a new Matrix that rotates by 'degrees'. Positive values are clockwise.
80-
func NewRotationByDegreesMatrix(degrees float32) Matrix {
81-
return NewRotationMatrix(degrees * xmath.DegreesToRadians)
67+
// NewSkewMatrix creates a new Matrix that skews by 'sx' and 'sy' degrees.
68+
func NewSkewMatrix(sx, sy float32) Matrix {
69+
return Matrix{
70+
ScaleX: 1,
71+
SkewX: xmath.Tan(sx * xmath.DegreesToRadians),
72+
SkewY: xmath.Tan(sy * xmath.DegreesToRadians),
73+
ScaleY: 1,
74+
}
8275
}
8376

8477
// IsIdentity returns true if this is an identity matrix.
@@ -88,68 +81,27 @@ func (m Matrix) IsIdentity() bool {
8881

8982
// Translate returns a new Matrix which is a copy of this Matrix translated by 'tx' and 'ty'.
9083
func (m Matrix) Translate(tx, ty float32) Matrix {
91-
return Matrix{
92-
ScaleX: m.ScaleX,
93-
SkewX: m.SkewX,
94-
TransX: m.TransX + tx,
95-
SkewY: m.SkewY,
96-
ScaleY: m.ScaleY,
97-
TransY: m.TransY + ty,
98-
}
99-
}
100-
101-
// TranslatePt returns a new Matrix which is a copy of this Matrix translated by translate.X and translate.Y.
102-
func (m Matrix) TranslatePt(translate Point) Matrix {
103-
return m.Translate(translate.X, translate.Y)
84+
return NewTranslationMatrix(tx, ty).Multiply(m)
10485
}
10586

10687
// Scale returns a new Matrix which is a copy of this Matrix scaled by 'sx' and 'sy'.
10788
func (m Matrix) Scale(sx, sy float32) Matrix {
108-
return Matrix{
109-
ScaleX: m.ScaleX * sx,
110-
SkewX: m.SkewX * sx,
111-
TransX: m.TransX * sx,
112-
SkewY: m.SkewY * sy,
113-
ScaleY: m.ScaleY * sy,
114-
TransY: m.TransY * sy,
115-
}
116-
}
117-
118-
// ScalePt returns a new Matrix which is a copy of this Matrix scaled by scale.X and scale.Y.
119-
func (m Matrix) ScalePt(scale Point) Matrix {
120-
return m.Scale(scale.X, scale.Y)
89+
return NewScaleMatrix(sx, sy).Multiply(m)
12190
}
12291

123-
// Skew returns a new Matrix which is a copy of this Matrix skewed by 'sx' and 'sy' radians.
92+
// Skew returns a new Matrix which is a copy of this Matrix skewed by 'sx' and 'sy' degrees.
12493
func (m Matrix) Skew(sx, sy float32) Matrix {
125-
return m.Multiply(Matrix{
126-
ScaleX: 1,
127-
SkewX: xmath.Tan(sx),
128-
SkewY: xmath.Tan(sy),
129-
ScaleY: 1,
130-
})
131-
}
132-
133-
// SkewByDegrees returns a new Matrix which is a copy of this Matrix skewed by 'sx' and 'sy' degrees.
134-
func (m Matrix) SkewByDegrees(sx, sy float32) Matrix {
135-
return m.Skew(xmath.DegreesToRadians*sx, xmath.DegreesToRadians*sy)
94+
return NewSkewMatrix(sx, sy).Multiply(m)
13695
}
13796

138-
// Rotate returns a new Matrix which is a copy of this Matrix rotated by 'radians'. Positive values are clockwise.
139-
func (m Matrix) Rotate(radians float32) Matrix {
140-
s := xmath.Sin(radians)
141-
c := xmath.Cos(radians)
142-
return m.Multiply(Matrix{
143-
ScaleX: c,
144-
SkewX: -s,
145-
SkewY: s,
146-
ScaleY: c,
147-
})
97+
// Rotate returns a new Matrix which is a copy of this Matrix rotated by 'degrees'. Positive values are clockwise.
98+
func (m Matrix) Rotate(degrees float32) Matrix {
99+
return NewRotationMatrix(degrees).Multiply(m)
148100
}
149101

150-
// RotateByDegrees returns a new Matrix which is a copy of this Matrix rotated by 'degrees'. Positive values are clockwise.
151-
func (m Matrix) RotateByDegrees(degrees float32) Matrix {
152-
return m.Rotate(degrees * xmath.DegreesToRadians)
102+
// RotateAround returns a new Matrix which is a copy of this Matrix rotated by 'degrees' around the point (cx, cy).
103+
func (m Matrix) RotateAround(degrees, cx, cy float32) Matrix {
104+
return m.Translate(-cx, -cy).Rotate(degrees).Translate(cx, cy)
153105
}
154106

155107
// Multiply returns this Matrix multiplied by the other Matrix.

geom/matrix_test.go

Lines changed: 11 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
package geom_test
1111

1212
import (
13-
"math"
1413
"testing"
1514

1615
"github.com/richardwilkes/toolbox/v2/check"
@@ -58,25 +57,11 @@ func TestNewScaleMatrix(t *testing.T) {
5857
func TestNewRotationMatrix(t *testing.T) {
5958
c := check.New(t)
6059

61-
// Test 90 degree rotation (π/2 radians)
62-
m := geom.NewRotationMatrix(math.Pi / 2)
63-
64-
// cos(π/2) = 0, sin(π/2) = 1
65-
// For clockwise rotation: ScaleX = cos, SkewX = -sin, SkewY = sin, ScaleY = cos
66-
c.True(xmath.Abs(m.ScaleX) < 0.0001) // Should be ~0
67-
c.True(xmath.Abs(m.SkewX+1) < 0.0001) // Should be ~-1
68-
c.Equal(float32(0), m.TransX)
69-
c.True(xmath.Abs(m.SkewY-1) < 0.0001) // Should be ~1
70-
c.True(xmath.Abs(m.ScaleY) < 0.0001) // Should be ~0
71-
c.Equal(float32(0), m.TransY)
72-
}
73-
74-
func TestNewRotationByDegreesMatrix(t *testing.T) {
75-
c := check.New(t)
76-
7760
// Test 90 degree rotation
78-
m := geom.NewRotationByDegreesMatrix(90)
61+
m := geom.NewRotationMatrix(90)
7962

63+
// cos(90) = 0, sin(90) = 1
64+
// For clockwise rotation: ScaleX = cos, SkewX = -sin, SkewY = sin, ScaleY = cos
8065
c.True(xmath.Abs(m.ScaleX) < 0.0001) // Should be ~0
8166
c.True(xmath.Abs(m.SkewX+1) < 0.0001) // Should be ~-1
8267
c.Equal(float32(0), m.TransX)
@@ -116,10 +101,10 @@ func TestMatrixScale(t *testing.T) {
116101

117102
c.Equal(float32(2), scaled.ScaleX)
118103
c.Equal(float32(0), scaled.SkewX)
119-
c.Equal(float32(20), scaled.TransX) // Translation is also scaled
104+
c.Equal(float32(20), scaled.TransX)
120105
c.Equal(float32(0), scaled.SkewY)
121106
c.Equal(float32(3), scaled.ScaleY)
122-
c.Equal(float32(60), scaled.TransY) // Translation is also scaled
107+
c.Equal(float32(60), scaled.TransY)
123108

124109
// Original matrix should be unchanged
125110
c.Equal(float32(1), m.ScaleX)
@@ -132,7 +117,7 @@ func TestMatrixRotate(t *testing.T) {
132117
c := check.New(t)
133118

134119
m := geom.NewIdentityMatrix()
135-
rotated := m.Rotate(math.Pi / 2) // 90 degrees
120+
rotated := m.Rotate(90)
136121

137122
c.True(xmath.Abs(rotated.ScaleX) < 0.0001) // Should be ~0
138123
c.True(xmath.Abs(rotated.SkewX+1) < 0.0001) // Should be ~-1
@@ -146,20 +131,6 @@ func TestMatrixRotate(t *testing.T) {
146131
c.Equal(float32(1), m.ScaleY)
147132
}
148133

149-
func TestMatrixRotateByDegrees(t *testing.T) {
150-
c := check.New(t)
151-
152-
m := geom.NewIdentityMatrix()
153-
rotated := m.RotateByDegrees(90)
154-
155-
c.True(xmath.Abs(rotated.ScaleX) < 0.0001) // Should be ~0
156-
c.True(xmath.Abs(rotated.SkewX+1) < 0.0001) // Should be ~-1
157-
c.Equal(float32(0), rotated.TransX)
158-
c.True(xmath.Abs(rotated.SkewY-1) < 0.0001) // Should be ~1
159-
c.True(xmath.Abs(rotated.ScaleY) < 0.0001) // Should be ~0
160-
c.Equal(float32(0), rotated.TransY)
161-
}
162-
163134
func TestMatrixMultiply(t *testing.T) {
164135
c := check.New(t)
165136

@@ -181,13 +152,12 @@ func TestMatrixMultiply(t *testing.T) {
181152

182153
c.Equal(float32(2), combined.ScaleX)
183154
c.Equal(float32(0), combined.SkewX)
184-
c.Equal(float32(20), combined.TransX) // Translation after scale
155+
c.Equal(float32(20), combined.TransX)
185156
c.Equal(float32(0), combined.SkewY)
186157
c.Equal(float32(3), combined.ScaleY)
187-
c.Equal(float32(60), combined.TransY) // Translation after scale
158+
c.Equal(float32(60), combined.TransY)
188159
}
189160

190-
//nolint:gocritic // The "commented out code" is actually explanation
191161
func TestMatrixTransformPoint(t *testing.T) {
192162
c := check.New(t)
193163

@@ -214,7 +184,7 @@ func TestMatrixTransformPoint(t *testing.T) {
214184
c.Equal(float32(21), result3.Y) // 7 * 3
215185

216186
// Test 90-degree rotation (point (1,0) should become (0,1))
217-
rotation := geom.NewRotationByDegreesMatrix(90)
187+
rotation := geom.NewRotationMatrix(90)
218188
p2 := geom.NewPoint(1.0, 0.0)
219189
result4 := rotation.TransformPoint(p2)
220190

@@ -226,8 +196,8 @@ func TestMatrixTransformPoint(t *testing.T) {
226196
p3 := geom.NewPoint(3.0, 4.0)
227197
result5 := combined.TransformPoint(p3)
228198

229-
c.Equal(float32(16), result5.X) // (3 + 5) * 2 = 16
230-
c.Equal(float32(18), result5.Y) // (4 + 5) * 2 = 18
199+
c.Equal(float32(16), result5.X)
200+
c.Equal(float32(18), result5.Y)
231201
}
232202

233203
func TestMatrixString(t *testing.T) {

0 commit comments

Comments
 (0)