-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathaffine.go
103 lines (91 loc) · 2.63 KB
/
affine.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// SPDX-License-Identifier: Unlicense OR MIT
// The following code has been extracted from Gioui.org
package stroke
import "math"
// affine2D represents an affine 2D transformation. The zero value of affine2D
// represents the identity transform.
type affine2D struct {
// in order to make the zero value of affine2D represent the identity
// transform we store it with the identity matrix subtracted, that is
// if the actual transformation matrix is:
// [sx, hx, ox]
// [hy, sy, oy]
// [ 0, 0, 1]
// we store a = sx-1 and e = sy-1
a, b, c float32
d, e, f float32
}
// Offset the transformation.
func (a affine2D) Offset(offset Point) affine2D {
return affine2D{
a.a, a.b, a.c + offset.X,
a.d, a.e, a.f + offset.Y,
}
}
// Scale the transformation around the given origin.
func (a affine2D) Scale(origin, factor Point) affine2D {
if origin == (Point{}) {
return a.scale(factor)
}
a = a.Offset(origin.Mul(-1))
a = a.scale(factor)
return a.Offset(origin)
}
// Rotate the transformation by the given angle (in radians) counter clockwise around the given origin.
func (a affine2D) Rotate(origin Point, radians float32) affine2D {
if origin == (Point{}) {
return a.rotate(radians)
}
a = a.Offset(origin.Mul(-1))
a = a.rotate(radians)
return a.Offset(origin)
}
// Mul returns A*B.
func (A affine2D) Mul(B affine2D) (r affine2D) {
r.a = (A.a+1)*(B.a+1) + A.b*B.d - 1
r.b = (A.a+1)*B.b + A.b*(B.e+1)
r.c = (A.a+1)*B.c + A.b*B.f + A.c
r.d = A.d*(B.a+1) + (A.e+1)*B.d
r.e = A.d*B.b + (A.e+1)*(B.e+1) - 1
r.f = A.d*B.c + (A.e+1)*B.f + A.f
return r
}
// Invert the transformation. Note that if the matrix is close to singular
// numerical errors may become large or infinity.
func (a affine2D) Invert() affine2D {
if a.a == 0 && a.b == 0 && a.d == 0 && a.e == 0 {
return affine2D{a: 0, b: 0, c: -a.c, d: 0, e: 0, f: -a.f}
}
a.a += 1
a.e += 1
det := a.a*a.e - a.b*a.d
a.a, a.e = a.e/det, a.a/det
a.b, a.d = -a.b/det, -a.d/det
temp := a.c
a.c = -a.a*a.c - a.b*a.f
a.f = -a.d*temp - a.e*a.f
a.a -= 1
a.e -= 1
return a
}
// Transform p by returning a*p.
func (a affine2D) Transform(p Point) Point {
return Point{
X: p.X*(a.a+1) + p.Y*a.b + a.c,
Y: p.X*a.d + p.Y*(a.e+1) + a.f,
}
}
func (a affine2D) scale(factor Point) affine2D {
return affine2D{
(a.a+1)*factor.X - 1, a.b * factor.X, a.c * factor.X,
a.d * factor.Y, (a.e+1)*factor.Y - 1, a.f * factor.Y,
}
}
func (a affine2D) rotate(radians float32) affine2D {
sin, cos := math.Sincos(float64(radians))
s, c := float32(sin), float32(cos)
return affine2D{
(a.a+1)*c - a.d*s - 1, a.b*c - (a.e+1)*s, a.c*c - a.f*s,
(a.a+1)*s + a.d*c, a.b*s + (a.e+1)*c - 1, a.c*s + a.f*c,
}
}