github.com/richardwilkes/toolbox@v1.121.0/xmath/geom/matrix.go (about) 1 // Copyright (c) 2016-2024 by Richard A. Wilkes. All rights reserved. 2 // 3 // This Source Code Form is subject to the terms of the Mozilla Public 4 // License, version 2.0. If a copy of the MPL was not distributed with 5 // this file, You can obtain one at http://mozilla.org/MPL/2.0/. 6 // 7 // This Source Code Form is "Incompatible With Secondary Licenses", as 8 // defined by the Mozilla Public License, version 2.0. 9 10 package geom 11 12 import ( 13 "fmt" 14 15 "github.com/richardwilkes/toolbox/xmath" 16 "golang.org/x/exp/constraints" 17 ) 18 19 // Matrix provides a 2D matrix. 20 type Matrix[T constraints.Float] struct { 21 ScaleX T `json:"scale_x"` 22 SkewX T `json:"skew_x"` 23 TransX T `json:"trans_x"` 24 SkewY T `json:"skew_y"` 25 ScaleY T `json:"scale_y"` 26 TransY T `json:"trans_y"` 27 } 28 29 // NewIdentityMatrix creates a new identity transformation Matrix. 30 func NewIdentityMatrix[T constraints.Float]() Matrix[T] { 31 return Matrix[T]{ScaleX: 1, ScaleY: 1} 32 } 33 34 // NewTranslationMatrix creates a new Matrix that translates by 'tx' and 'ty'. 35 func NewTranslationMatrix[T constraints.Float](tx, ty T) Matrix[T] { 36 return Matrix[T]{ScaleX: 1, ScaleY: 1, TransX: tx, TransY: ty} 37 } 38 39 // NewScaleMatrix creates a new Matrix that scales by 'sx' and 'sy'. 40 func NewScaleMatrix[T constraints.Float](sx, sy T) Matrix[T] { 41 return Matrix[T]{ScaleX: sx, ScaleY: sy} 42 } 43 44 // NewRotationMatrix creates a new Matrix that rotates by 'radians'. Positive values are clockwise. 45 func NewRotationMatrix[T constraints.Float](radians T) Matrix[T] { 46 s := xmath.Sin(radians) 47 c := xmath.Cos(radians) 48 return Matrix[T]{ScaleX: c, SkewX: -s, SkewY: s, ScaleY: c} 49 } 50 51 // NewRotationByDegreesMatrix creates a new Matrix that rotates by 'degrees'. Positive values are clockwise. 52 func NewRotationByDegreesMatrix[T constraints.Float](degrees T) Matrix[T] { 53 return NewRotationMatrix(degrees * xmath.DegreesToRadians) 54 } 55 56 // Translate returns a new Matrix which is a copy of this Matrix translated by 'tx' and 'ty'. 57 func (m Matrix[T]) Translate(tx, ty T) Matrix[T] { 58 return Matrix[T]{ 59 ScaleX: m.ScaleX, 60 SkewX: m.SkewX, 61 TransX: m.TransX + tx, 62 SkewY: m.SkewY, 63 ScaleY: m.ScaleY, 64 TransY: m.TransY + ty, 65 } 66 } 67 68 // Scale returns a new Matrix which is a copy of this Matrix scaled by 'sx' and 'sy'. 69 func (m Matrix[T]) Scale(sx, sy T) Matrix[T] { 70 return Matrix[T]{ 71 ScaleX: m.ScaleX * sx, 72 SkewX: m.SkewX * sx, 73 TransX: m.TransX * sx, 74 SkewY: m.SkewY * sy, 75 ScaleY: m.ScaleY * sy, 76 TransY: m.TransY * sy, 77 } 78 } 79 80 // Rotate returns a new Matrix which is a copy of this Matrix rotated by 'radians'. Positive values are clockwise. 81 func (m Matrix[T]) Rotate(radians T) Matrix[T] { 82 s := xmath.Sin(radians) 83 c := xmath.Cos(radians) 84 return Matrix[T]{ 85 ScaleX: m.ScaleX*c - s*m.SkewY, 86 SkewX: m.SkewX*c - s*m.ScaleY, 87 TransX: m.TransX*c - s*m.TransY, 88 SkewY: m.ScaleX*s + m.SkewY*c, 89 ScaleY: m.SkewX*s + m.ScaleY*c, 90 TransY: m.TransX*s + m.TransY*c, 91 } 92 } 93 94 // RotateByDegrees returns a new Matrix which is a copy of this Matrix rotated by 'degrees'. Positive values are clockwise. 95 func (m Matrix[T]) RotateByDegrees(degrees T) Matrix[T] { 96 return m.Rotate(degrees * xmath.DegreesToRadians) 97 } 98 99 // Multiply returns this Matrix multiplied by the other Matrix. 100 func (m Matrix[T]) Multiply(other Matrix[T]) Matrix[T] { 101 return Matrix[T]{ 102 ScaleX: m.ScaleX*other.ScaleX + m.SkewY*other.SkewX, 103 SkewX: m.SkewX*other.ScaleX + m.ScaleY*other.SkewX, 104 TransX: m.TransX*other.ScaleX + m.TransY*other.SkewX + other.TransX, 105 SkewY: m.ScaleX*other.SkewY + m.SkewY*other.ScaleY, 106 ScaleY: m.SkewX*other.SkewY + m.ScaleY*other.ScaleY, 107 TransY: m.TransX*other.ScaleX + m.TransY*other.SkewX + other.TransX, 108 } 109 } 110 111 // TransformPoint returns the result of transforming the given Point by this Matrix. 112 func (m Matrix[T]) TransformPoint(p Point[T]) Point[T] { 113 return Point[T]{X: m.ScaleX*p.X + m.SkewX*p.Y + m.TransX, Y: m.SkewY*p.X + m.ScaleY*p.Y + m.TransY} 114 } 115 116 // String implements fmt.Stringer. 117 func (m Matrix[T]) String() string { 118 return fmt.Sprintf("%#v,%#v,%#v,%#v,%#v,%#v", m.ScaleX, m.SkewX, m.TransX, m.SkewY, m.ScaleY, m.TransY) 119 }