Decompose extracts the translation, rotation, scaling and rotation components (applied in the reverse order) as (tx, ty, theta, sx, sy, phi) with rotation counter clockwise. This corresponds to Identity.Translate(tx, ty).Rotate(phi).Scale(sx, sy).Rotate(theta).
()
| 776 | |
| 777 | // Decompose extracts the translation, rotation, scaling and rotation components (applied in the reverse order) as (tx, ty, theta, sx, sy, phi) with rotation counter clockwise. This corresponds to Identity.Translate(tx, ty).Rotate(phi).Scale(sx, sy).Rotate(theta). |
| 778 | func (m Matrix) Decompose() (float64, float64, float64, float64, float64, float64) { |
| 779 | // see https://math.stackexchange.com/questions/861674/decompose-a-2d-arbitrary-transform-into-only-scaling-and-rotation |
| 780 | E := (m[0][0] + m[1][1]) / 2.0 |
| 781 | F := (m[0][0] - m[1][1]) / 2.0 |
| 782 | G := (m[1][0] + m[0][1]) / 2.0 |
| 783 | H := (m[1][0] - m[0][1]) / 2.0 |
| 784 | |
| 785 | Q, R := math.Sqrt(E*E+H*H), math.Sqrt(F*F+G*G) |
| 786 | sx, sy := Q+R, Q-R |
| 787 | |
| 788 | a1, a2 := math.Atan2(G, F), math.Atan2(H, E) |
| 789 | theta := (a2 - a1) / 2.0 * 180.0 / math.Pi |
| 790 | phi := (a2 + a1) / 2.0 * 180.0 / math.Pi |
| 791 | if Equal(sx, 1.0) && Equal(sy, 1.0) { |
| 792 | theta += phi |
| 793 | phi = 0.0 |
| 794 | } |
| 795 | return m[0][2], m[1][2], phi, sx, sy, theta |
| 796 | } |
| 797 | |
| 798 | func (m Matrix) IsIdentity() bool { |
| 799 | return m == Identity |