swf2ass-go/types/Vector2.go

168 lines
3 KiB
Go
Raw Normal View History

2023-11-20 05:20:31 +00:00
package types
import (
"fmt"
"git.gammaspectra.live/WeebDataHoarder/swf2ass-go/swf/types"
"math"
"reflect"
)
type Vector2[T ~int64 | ~float64] struct {
X T
Y T
}
func NewVector2[T ~int64 | ~float64](x, y T) Vector2[T] {
return Vector2[T]{
X: x,
Y: y,
}
}
var epsilon = math.Abs(float64(7.)/3 - float64(4.)/3 - float64(1.))
func (v Vector2[T]) Equals(b Vector2[T]) bool {
switch any(v.X).(type) {
case int64, types.Twip:
return v.equalsInt(b)
case float64:
return v.equalsFloat(b)
default:
//slow path to find underlying type
switch reflect.TypeOf(v.X).Kind() {
case reflect.Int64:
return v.equalsInt(b)
case reflect.Float64:
return v.equalsFloat(b)
}
}
panic("unsupported type")
}
func (v Vector2[T]) equalsFloat(b Vector2[T]) bool {
return v == b || ((math.Abs(float64(b.Y-v.Y))) <= epsilon && (math.Abs(float64(b.X-v.Y))) <= epsilon)
}
func (v Vector2[T]) equalsInt(b Vector2[T]) bool {
return v == b
}
func (v Vector2[T]) Distance(b Vector2[T]) float64 {
return math.Sqrt(float64(v.SquaredDistance(b)))
}
func (v Vector2[T]) SquaredDistance(b Vector2[T]) T {
r := v.SubVector(b)
r = r.MultiplyVector(r)
return r.X + r.Y
}
func (v Vector2[T]) MultiplyVector(b Vector2[T]) Vector2[T] {
return Vector2[T]{
X: v.X * b.X,
Y: v.Y * b.Y,
}
}
func (v Vector2[T]) DivideVector(b Vector2[T]) Vector2[T] {
return Vector2[T]{
X: v.X / b.X,
Y: v.Y / b.Y,
}
}
func (v Vector2[T]) Multiply(size T) Vector2[T] {
return Vector2[T]{
X: v.X * size,
Y: v.Y * size,
}
}
func (v Vector2[T]) Divide(size T) Vector2[T] {
return Vector2[T]{
X: v.X / size,
Y: v.Y / size,
}
}
func (v Vector2[T]) Invert() Vector2[T] {
return Vector2[T]{
X: v.Y,
Y: v.X,
}
}
func (v Vector2[T]) AddVector(b Vector2[T]) Vector2[T] {
return Vector2[T]{
X: v.X + b.X,
Y: v.Y + b.Y,
}
}
func (v Vector2[T]) SubVector(b Vector2[T]) Vector2[T] {
return Vector2[T]{
X: v.X - b.X,
Y: v.Y - b.Y,
}
}
func (v Vector2[T]) Abs() Vector2[T] {
x := v.X
if x < 0 {
x = -x
}
y := v.Y
if y < 0 {
y = -y
}
return Vector2[T]{
X: x,
Y: y,
}
}
func (v Vector2[T]) Dot(b Vector2[T]) T {
return v.X*b.X + v.Y*b.Y
}
func (v Vector2[T]) SquaredLength() T {
return v.X*v.X + v.Y*v.Y
}
func (v Vector2[T]) Normalize() Vector2[float64] {
length := v.SquaredLength()
if length > 0 {
return v.Float64().Divide(math.Sqrt(float64(length)))
}
return Vector2[float64]{
X: 0,
Y: 0,
}
}
func (v Vector2[T]) Float64() Vector2[float64] {
return Vector2ToType[T, float64](v)
}
func (v Vector2[T]) Int64() Vector2[int64] {
return Vector2ToType[T, int64](v)
}
func Vector2ToType[T ~int64 | ~float64, T2 ~int64 | ~float64](v Vector2[T]) Vector2[T2] {
return Vector2[T2]{
X: T2(v.X),
Y: T2(v.Y),
}
}
func (v Vector2[T]) String() string {
typ := reflect.TypeOf(v.X)
switch typ.Kind() {
case reflect.Int64:
return fmt.Sprintf("Vector2[%s](%d, %d)", typ.Name(), v.X, v.Y)
case reflect.Float64:
return fmt.Sprintf("Vector2[%s](%f, %f)", typ.Name(), v.X, v.Y)
}
panic("unsupported type")
}