diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2e7699b --- /dev/null +++ b/.gitignore @@ -0,0 +1,30 @@ +# Allowlisting gitignore template for GO projects prevents us +# from adding various unwanted local files, such as generated +# files, developer configurations or IDE-specific files etc. +# +# Recommended: Go.AllowList.gitignore + +# Ignore everything +* + +# But not these files... +!/.gitignore + +!*.go +!go.sum +!go.mod + +!README.md +!LICENSE + +# Configuration files +!*.yaml +!*.json +!*.toml +!*.sh + +# ...even if they are in subdirectories +!*/ + +# Allow everything in assets folder +!/assets/** \ No newline at end of file diff --git a/README.md b/README.md index d819b46..6d11c34 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,97 @@ -# govec -Go library providing 2D and 3D vector operations +# GoVec +A library providing vector operations for Go. + +The library supports both 2D and 3D vectors in two formats: +- Floating Point Vectors: `V2F[T]` and `V3F[T]` +- Integer Vectors: `V2I[T]` and `V3I[T]` + +## Installation + +```bash +go get github.com/xkonti/govec +``` + +## Available Operations + +| Operation | Float | Integer | Description | +|-----------------|-------|------|--------------------------------------------------------------------------------------------| +| **Creation** | | | | +| `...FromArray` | ✔️ | ✔️ | Initializes a vector from an array of components. | +| `...FromSlice` | ✔️ | ✔️ | Initializes a vector from a slice of components. | +| `Fill` | ✔️ | ✔️ | Creates a vector where all components are set to a specified value. | +| `New` | ✔️ | ✔️ | Creates a new vector using the provided components. | +| `One` | ✔️ | ✔️ | Generates a vector with all components set to 1. | +| `Zero` | ✔️ | ✔️ | Generates a vector with all components set to 0. | +| **Conversions** | | | | +| `Apply` | ✔️ | ✔️ | Applies a given function to each component in the vector. | +| `ApplyToArray` | ✔️ | ✔️ | Modifies an array by assigning values from the vector's corresponding components. | +| `ApplyToSlice` | ✔️ | ✔️ | Modifies a slice by assigning values from the vector's corresponding components. | +| `Discard` | ✔️ | ✔️ | Removes a component from the vector at a specified index. | +| `Extend` | ✔️ | ✔️ | Extends the dimensionality of a vector by adding additional components. | +| `Insert` | ✔️ | ✔️ | Inserts a value into the vector at a specified index. | +| `Split` | ✔️ | ✔️ | Splits a vector into its individual components. | +| `ToArray` | ✔️ | ✔️ | Converts the vector to a new array. | +| `ToSlice` | ✔️ | ✔️ | Converts the vector to a new slice. | +| `To...` | ✔️ | ✔️ | Transforms the vector into another type. | +| **Mathematics** | | | | +| `Abs` | ✔️ | ✔️ | Computes the absolute value of each component in the vector. | +| `Add` | ✔️ | ✔️ | Performs vector addition. | +| `AddScalar` | ✔️ | ✔️ | Adds a scalar value to each component of the vector. | +| `Ceil` | ✔️ | ✔️ | Rounds each component of the vector up to the nearest integer. | +| `Cross` | ✔️ | ✔️ | Computes the cross product of two vectors. (Not applicable for 2D vectors.) | +| `Div` | ✔️ | ✔️ | Performs vector division. | +| `DivScalar` | ✔️ | ✔️ | Divides each component of the vector by a scalar. | +| `Dot` | ✔️ | ✔️ | Computes the dot product of two vectors. | +| `Floor` | ✔️ | ✔️ | Rounds each component of the vector down to the nearest integer. | +| `Inv` | ✔️ | ✔️ | Computes the multiplicative inverse of each component in the vector. | +| `Len` | ✔️ | ✔️ | Calculates the length of the vector. Returns `float64` for integer vectors. | +| `LenSqr` | ✔️ | ✔️ | Calculates the squared length of the vector. Returns `float64` for integer vectors. | +| `Mod` | ✔️ | ✔️ | Computes the modulus of each component in the vector. | +| `Mul` | ✔️ | ✔️ | Performs vector multiplication. | +| `MulScalar` | ✔️ | ✔️ | Multiplies each component of the vector by a scalar. | +| `Neg` | ✔️ | ✔️ | Negates each component of the vector. | +| `Norm` | ✔️ | ✔️ | Normalizes the vector. Returns a `float64` vector for integer vectors. | +| `Pow` | ✔️ | ✔️ | Raises each component of the vector to the power of the corresponding component in another vector.| +| `Pow2` | ✔️ | ✔️ | Squares each component of the vector. | +| `Pow3` | ✔️ | ✔️ | Cubes each component of the vector. | +| `PowN` | ✔️ | ✔️ | Raises each component of the vector to a specified integer power. | +| `PowNFloat` | ✔️ | ✔️ | Raises each component of the vector to a specified floating-point power. | +| `Round` | ✔️ | ✔️ | Rounds each component of the vector to the nearest integer. | +| `Sqrt` | ✔️ | ✔️ | Computes the square root of each component in the vector. | +| `Sub` | ✔️ | ✔️ | Performs vector subtraction. | +| `SubScalar` | ✔️ | ✔️ | Subtracts a scalar from each component of the vector. | + +## Not implemented yet + +The following list of operations are not implemented yet. Feel free to open an issue if you would like to see +any of these implemented or if you'd like to propose a different operation. + +| Operation | Planned | Description | +|-------------------|------------|-------------------------------------------------------------| +| `AngleBetweenDeg` | Yes (v1.0) | Calculates the angle between two vectors in degrees. | +| `AngleBetweenRad` | Yes (v1.0) | Calculates the angle between two vectors in radians. | +| `AngleDeg` | Yes (v1.0) | Creates a normalized vector from an angle in degrees. | +| `AngleRad` | Yes (v1.0) | Creates a normalized vector from an angle in radians. | +| `Average` | Yes (v1.0) | Calculates the average of the vector's components. | +| `ClampComponents` | Yes (v1.0) | Clamps the components of this vector to the given range. | +| `ClampMagnitude` | Yes (v1.0) | Clamps the magnitude of this vector to the given value. | +| `Cos` | | Applies the cosine function to all components. | +| `Distance` | Yes (v1.0) | Calculates the distance between two vectors. | +| `FromQuaternion` | | Initializes the vector from a quaternion. | +| `Hash` | | Produces a hash code for the vector for use in data structures. | +| `IsOrthogonalTo` | | Checks if the vector is orthogonal to another vector. | +| `IsUnit` | | Checks if the vector is a unit vector. | +| `IsZero` | Yes (v1.0) | Checks if the vector is a zero vector. | +| `Lerp` | Yes (v1.0) | Linearly interpolates between two vectors. | +| `Max` | Yes (v1.0) | Returns the maximum component values from two vectors. | +| `Min` | Yes (v1.0) | Returns the minimum component values from two vectors. | +| `Orthogonalize` | | Generates an orthogonal (or orthonormal) vector set. | +| `Project` | | Projects a 3D vector onto a plane. | +| `Random` | Yes (v1.0) | Generates a normal vector with random components. | +| `Reflect` | | Reflects a vector off the plane defined by a normal. | +| `RotateDeg` | Yes (v1.0) | Rotates a vector by an angle in degrees. | +| `RotateRad` | Yes (v1.0) | Rotates a vector by an angle in radians. | +| `Sin` | | Applies the sine function to all components. | +| `Slerp` | | Spherically interpolates between two vectors. | +| `Tan` | | Applies the tangent function to all components. | +| `ToQuaternion` | | Converts the vector to a quaternion. | \ No newline at end of file diff --git a/abs.go b/abs.go new file mode 100644 index 0000000..d02033f --- /dev/null +++ b/abs.go @@ -0,0 +1,107 @@ +package govec + +// V2F + +func (v V2F[T]) Abs() V2F[T] { + absX := v.X + absY := v.Y + if absX < 0 { + absX = -absX + } + if absY < 0 { + absY = -absY + } + return V2F[T]{X: absX, Y: absY} +} + +func (v *V2F[T]) AbsInPlace() { + if v.X < 0 { + v.X = -v.X + } + if v.Y < 0 { + v.Y = -v.Y + } +} + +// V3F + +func (v V3F[T]) Abs() V3F[T] { + absX := v.X + absY := v.Y + absZ := v.Z + if absX < 0 { + absX = -absX + } + if absY < 0 { + absY = -absY + } + if absZ < 0 { + absZ = -absZ + } + return V3F[T]{X: absX, Y: absY, Z: absZ} +} + +func (v *V3F[T]) AbsInPlace() { + if v.X < 0 { + v.X = -v.X + } + if v.Y < 0 { + v.Y = -v.Y + } + if v.Z < 0 { + v.Z = -v.Z + } +} + +// V2I + +func (v V2I[T]) Abs() V2I[T] { + absX := v.X + absY := v.Y + if absX < 0 { + absX = -absX + } + if absY < 0 { + absY = -absY + } + return V2I[T]{X: absX, Y: absY} +} + +func (v *V2I[T]) AbsInPlace() { + if v.X < 0 { + v.X = -v.X + } + if v.Y < 0 { + v.Y = -v.Y + } +} + +// V3I + +func (v V3I[T]) Abs() V3I[T] { + absX := v.X + absY := v.Y + absZ := v.Z + if absX < 0 { + absX = -absX + } + if absY < 0 { + absY = -absY + } + if absZ < 0 { + absZ = -absZ + } + return V3I[T]{X: absX, Y: absY, Z: absZ} +} + +func (v *V3I[T]) AbsInPlace() { + if v.X < 0 { + v.X = -v.X + } + if v.Y < 0 { + v.Y = -v.Y + } + if v.Z < 0 { + v.Z = -v.Z + } +} diff --git a/add.go b/add.go new file mode 100644 index 0000000..f7d2cac --- /dev/null +++ b/add.go @@ -0,0 +1,85 @@ +package govec + +// V2F + +func (v V2F[T]) Add(v2 V2F[T]) V2F[T] { + return V2F[T]{X: v.X + v2.X, Y: v.Y + v2.Y} +} + +func (v *V2F[T]) AddInPlace(v2 V2F[T]) { + v.X += v2.X + v.Y += v2.Y +} + +func (v V2F[T]) AddComp(x T, y T) V2F[T] { + return V2F[T]{X: v.X + x, Y: v.Y + y} +} + +func (v *V2F[T]) AddCompInPlace(x T, y T) { + v.X += x + v.Y += y +} + +// V3F + +func (v V3F[T]) Add(v2 V3F[T]) V3F[T] { + return V3F[T]{X: v.X + v2.X, Y: v.Y + v2.Y, Z: v.Z + v2.Z} +} + +func (v *V3F[T]) AddInPlace(v2 V3F[T]) { + v.X += v2.X + v.Y += v2.Y + v.Z += v2.Z +} + +func (v V3F[T]) AddComp(x T, y T, z T) V3F[T] { + return V3F[T]{X: v.X + x, Y: v.Y + y, Z: v.Z + z} +} + +func (v *V3F[T]) AddCompInPlace(x T, y T, z T) { + v.X += x + v.Y += y + v.Z += z +} + +// V2I + +func (v V2I[T]) Add(v2 V2I[T]) V2I[T] { + return V2I[T]{X: v.X + v2.X, Y: v.Y + v2.Y} +} + +func (v *V2I[T]) AddInPlace(v2 V2I[T]) { + v.X += v2.X + v.Y += v2.Y +} + +func (v V2I[T]) AddComp(x T, y T) V2I[T] { + return V2I[T]{X: v.X + x, Y: v.Y + y} +} + +func (v *V2I[T]) AddCompInPlace(x T, y T) { + v.X += x + v.Y += y +} + +// V3I + +func (v V3I[T]) Add(v2 V3I[T]) V3I[T] { + return V3I[T]{X: v.X + v2.X, Y: v.Y + v2.Y, Z: v.Z + v2.Z} +} + +func (v *V3I[T]) AddInPlace(v2 V3I[T]) { + v.X += v2.X + v.Y += v2.Y + v.Z += v2.Z +} + +func (v V3I[T]) AddComp(x T, y T, z T) V3I[T] { + return V3I[T]{X: v.X + x, Y: v.Y + y, Z: v.Z + z} +} + +func (v *V3I[T]) AddCompInPlace(x T, y T, z T) { + v.X += x + v.Y += y + v.Z += z +} diff --git a/addScalar.go b/addScalar.go new file mode 100644 index 0000000..fa8f870 --- /dev/null +++ b/addScalar.go @@ -0,0 +1,47 @@ +package govec + +// V2F + +func (v V2F[T]) AddScalar(scalar T) V2F[T] { + return V2F[T]{X: v.X + scalar, Y: v.Y + scalar} +} + +func (v *V2F[T]) AddScalarInPlace(scalar T) { + v.X += scalar + v.Y += scalar +} + +// V3F + +func (v V3F[T]) AddScalar(scalar T) V3F[T] { + return V3F[T]{X: v.X + scalar, Y: v.Y + scalar, Z: v.Z + scalar} +} + +func (v *V3F[T]) AddScalarInPlace(scalar T) { + v.X += scalar + v.Y += scalar + v.Z += scalar +} + +// V2I + +func (v V2I[T]) AddScalar(scalar T) V2I[T] { + return V2I[T]{X: v.X + scalar, Y: v.Y + scalar} +} + +func (v *V2I[T]) AddScalarInPlace(scalar T) { + v.X += scalar + v.Y += scalar +} + +// V3I + +func (v V3I[T]) AddScalar(scalar T) V3I[T] { + return V3I[T]{X: v.X + scalar, Y: v.Y + scalar, Z: v.Z + scalar} +} + +func (v *V3I[T]) AddScalarInPlace(scalar T) { + v.X += scalar + v.Y += scalar + v.Z += scalar +} diff --git a/add_test.go b/add_test.go new file mode 100644 index 0000000..2206275 --- /dev/null +++ b/add_test.go @@ -0,0 +1,73 @@ +package govec + +import "testing" + +// Test V2F Add +func TestV2F_Add(t *testing.T) { + v1 := V2F[float64]{X: 1.3, Y: 2.4} + v2 := V2F[float64]{X: 3.5, Y: 4.6} + v3 := v1.Add(v2) + if v3.X != 4.8 || v3.Y != 7.0 { + t.Errorf("V2F Add failed") + } +} + +func TestV2F_AddComp(t *testing.T) { + v1 := V2F[float64]{X: 1.3, Y: 2.4} + v3 := v1.AddComp(3.5, 4.6) + if v3.X != 4.8 || v3.Y != 7.0 { + t.Errorf("V2F AddComp failed") + } +} + +func TestV2F_AddInPlace(t *testing.T) { + v1 := V2F[float64]{X: 1.3, Y: 2.4} + v2 := V2F[float64]{X: 3.5, Y: 4.6} + v1.AddInPlace(v2) + if v1.X != 4.8 || v1.Y != 7.0 { + t.Errorf("V2F AddInPlace failed") + } +} + +func TestV2F_AddCompInPlace(t *testing.T) { + v1 := V2F[float64]{X: 1.3, Y: 2.4} + v1.AddCompInPlace(3.5, 4.6) + if v1.X != 4.8 || v1.Y != 7.0 { + t.Errorf("V2F AddCompInPlace failed") + } +} + +// Test V2I Add +func TestV2I_Add(t *testing.T) { + v1 := V2I[int16]{X: 3, Y: 24} + v2 := V2I[int16]{X: 67, Y: 100} + v3 := v1.Add(v2) + if v3.X != 70 || v3.Y != 124 { + t.Errorf("V2I Add failed") + } +} + +func TestV2I_AddComp(t *testing.T) { + v1 := V2I[int16]{X: 3, Y: 24} + v3 := v1.AddComp(67, 100) + if v3.X != 70 || v3.Y != 124 { + t.Errorf("V2I AddComp failed") + } +} + +func TestV2I_AddInPlace(t *testing.T) { + v1 := V2I[int16]{X: 3, Y: 24} + v2 := V2I[int16]{X: 67, Y: 100} + v1.AddInPlace(v2) + if v1.X != 70 || v1.Y != 124 { + t.Errorf("V2I AddInPlace failed") + } +} + +func TestV2I_AddCompInPlace(t *testing.T) { + v1 := V2I[int16]{X: 3, Y: 24} + v1.AddCompInPlace(67, 100) + if v1.X != 70 || v1.Y != 124 { + t.Errorf("V2I AddCompInPlace failed") + } +} diff --git a/apply.go b/apply.go new file mode 100644 index 0000000..7a04d81 --- /dev/null +++ b/apply.go @@ -0,0 +1,17 @@ +package govec + +func (v V2F[T]) apply(f func(T) T) V2F[T] { + return V2F[T]{X: f(v.X), Y: f(v.Y)} +} + +func (v V3F[T]) apply(f func(T) T) V3F[T] { + return V3F[T]{X: f(v.X), Y: f(v.Y), Z: f(v.Z)} +} + +func (v V2I[T]) apply(f func(T) T) V2I[T] { + return V2I[T]{X: f(v.X), Y: f(v.Y)} +} + +func (v V3I[T]) apply(f func(T) T) V3I[T] { + return V3I[T]{X: f(v.X), Y: f(v.Y), Z: f(v.Z)} +} diff --git a/array.go b/array.go new file mode 100644 index 0000000..17820c7 --- /dev/null +++ b/array.go @@ -0,0 +1,57 @@ +package govec + +import "golang.org/x/exp/constraints" + +func V2FFromArray[T constraints.Float](a [2]T) V2F[T] { + return V2F[T]{X: a[0], Y: a[1]} +} + +func V3FFromArray[T constraints.Float](a [3]T) V3F[T] { + return V3F[T]{X: a[0], Y: a[1], Z: a[2]} +} + +func V2IFromArray[T constraints.Integer](a [2]T) V2I[T] { + return V2I[T]{X: a[0], Y: a[1]} +} + +func V3IFromArray[T constraints.Integer](a [3]T) V3I[T] { + return V3I[T]{X: a[0], Y: a[1], Z: a[2]} +} + +func (v V2F[T]) ToArray() [2]T { + return [2]T{v.X, v.Y} +} + +func (v V3F[T]) ToArray() [3]T { + return [3]T{v.X, v.Y, v.Z} +} + +func (v V2I[T]) ToArray() [2]T { + return [2]T{v.X, v.Y} +} + +func (v V3I[T]) ToArray() [3]T { + return [3]T{v.X, v.Y, v.Z} +} + +func (v V2F[T]) ApplyToArray(a *[2]T) { + a[0] = v.X + a[1] = v.Y +} + +func (v V3F[T]) ApplyToArray(a *[3]T) { + a[0] = v.X + a[1] = v.Y + a[2] = v.Z +} + +func (v V2I[T]) ApplyToArray(a *[2]T) { + a[0] = v.X + a[1] = v.Y +} + +func (v V3I[T]) ApplyToArray(a *[3]T) { + a[0] = v.X + a[1] = v.Y + a[2] = v.Z +} diff --git a/ceil.go b/ceil.go new file mode 100644 index 0000000..95a6bbb --- /dev/null +++ b/ceil.go @@ -0,0 +1,26 @@ +package govec + +import "math" + +// V2F + +func (v V2F[T]) Ceil() V2F[T] { + return V2F[T]{X: T(math.Ceil(float64(v.X))), Y: T(math.Ceil(float64(v.Y)))} +} + +func (v *V2F[T]) CeilInPlace() { + v.X = T(math.Ceil(float64(v.X))) + v.Y = T(math.Ceil(float64(v.Y))) +} + +// V3F + +func (v V3F[T]) Ceil() V3F[T] { + return V3F[T]{X: T(math.Ceil(float64(v.X))), Y: T(math.Ceil(float64(v.Y))), Z: T(math.Ceil(float64(v.Z)))} +} + +func (v *V3F[T]) CeilInPlace() { + v.X = T(math.Ceil(float64(v.X))) + v.Y = T(math.Ceil(float64(v.Y))) + v.Z = T(math.Ceil(float64(v.Z))) +} diff --git a/constants.go b/constants.go new file mode 100644 index 0000000..701c14c --- /dev/null +++ b/constants.go @@ -0,0 +1 @@ +package govec diff --git a/cross.go b/cross.go new file mode 100644 index 0000000..db49191 --- /dev/null +++ b/cross.go @@ -0,0 +1,65 @@ +package govec + +// V3F + +func (v V3F[T]) Cross(v2 V3F[T]) V3F[T] { + return V3F[T]{ + X: v.Y*v2.Z - v.Z*v2.Y, + Y: v.Z*v2.X - v.X*v2.Z, + Z: v.X*v2.Y - v.Y*v2.X, + } +} + +func (v *V3F[T]) CrossInPlace(v2 V3F[T]) { + x := v.Y*v2.Z - v.Z*v2.Y + y := v.Z*v2.X - v.X*v2.Z + z := v.X*v2.Y - v.Y*v2.X + v.X, v.Y, v.Z = x, y, z +} + +func (v V3F[T]) CrossComp(x T, y T, z T) V3F[T] { + return V3F[T]{ + X: v.Y*z - v.Z*y, + Y: v.Z*x - v.X*z, + Z: v.X*y - v.Y*x, + } +} + +func (v *V3F[T]) CrossCompInPlace(x T, y T, z T) { + nx := v.Y*z - v.Z*y + ny := v.Z*x - v.X*z + nz := v.X*y - v.Y*x + v.X, v.Y, v.Z = nx, ny, nz +} + +// V3I + +func (v V3I[T]) Cross(v2 V3I[T]) V3I[T] { + return V3I[T]{ + X: v.Y*v2.Z - v.Z*v2.Y, + Y: v.Z*v2.X - v.X*v2.Z, + Z: v.X*v2.Y - v.Y*v2.X, + } +} + +func (v *V3I[T]) CrossInPlace(v2 V3I[T]) { + x := v.Y*v2.Z - v.Z*v2.Y + y := v.Z*v2.X - v.X*v2.Z + z := v.X*v2.Y - v.Y*v2.X + v.X, v.Y, v.Z = x, y, z +} + +func (v V3I[T]) CrossComp(x T, y T, z T) V3I[T] { + return V3I[T]{ + X: v.Y*z - v.Z*y, + Y: v.Z*x - v.X*z, + Z: v.X*y - v.Y*x, + } +} + +func (v *V3I[T]) CrossCompInPlace(x T, y T, z T) { + nx := v.Y*z - v.Z*y + ny := v.Z*x - v.X*z + nz := v.X*y - v.Y*x + v.X, v.Y, v.Z = nx, ny, nz +} diff --git a/discard.go b/discard.go new file mode 100644 index 0000000..bfd4391 --- /dev/null +++ b/discard.go @@ -0,0 +1,25 @@ +package govec + +func (v V3F[T]) discardX() V2F[T] { + return V2F[T]{X: v.Y, Y: v.Z} +} + +func (v V3F[T]) discardY() V2F[T] { + return V2F[T]{X: v.X, Y: v.Z} +} + +func (v V3F[T]) discardZ() V2F[T] { + return V2F[T]{X: v.X, Y: v.Y} +} + +func (v V3I[T]) discardX() V2I[T] { + return V2I[T]{X: v.Y, Y: v.Z} +} + +func (v V3I[T]) discardY() V2I[T] { + return V2I[T]{X: v.X, Y: v.Z} +} + +func (v V3I[T]) discardZ() V2I[T] { + return V2I[T]{X: v.X, Y: v.Y} +} diff --git a/div.go b/div.go new file mode 100644 index 0000000..37d847b --- /dev/null +++ b/div.go @@ -0,0 +1,85 @@ +package govec + +// V2F + +func (v V2F[T]) Div(v2 V2F[T]) V2F[T] { + return V2F[T]{X: v.X / v2.X, Y: v.Y / v2.Y} +} + +func (v *V2F[T]) DivInPlace(v2 V2F[T]) { + v.X /= v2.X + v.Y /= v2.Y +} + +func (v V2F[T]) DivComp(x T, y T) V2F[T] { + return V2F[T]{X: v.X / x, Y: v.Y / y} +} + +func (v *V2F[T]) DivCompInPlace(x T, y T) { + v.X /= x + v.Y /= y +} + +// V3F + +func (v V3F[T]) Div(v2 V3F[T]) V3F[T] { + return V3F[T]{X: v.X / v2.X, Y: v.Y / v2.Y, Z: v.Z / v2.Z} +} + +func (v *V3F[T]) DivInPlace(v2 V3F[T]) { + v.X /= v2.X + v.Y /= v2.Y + v.Z /= v2.Z +} + +func (v V3F[T]) DivComp(x T, y T, z T) V3F[T] { + return V3F[T]{X: v.X / x, Y: v.Y / y, Z: v.Z / z} +} + +func (v *V3F[T]) DivCompInPlace(x T, y T, z T) { + v.X /= x + v.Y /= y + v.Z /= z +} + +// V2I + +func (v V2I[T]) Div(v2 V2I[T]) V2I[T] { + return V2I[T]{X: v.X / v2.X, Y: v.Y / v2.Y} +} + +func (v *V2I[T]) DivInPlace(v2 V2I[T]) { + v.X /= v2.X + v.Y /= v2.Y +} + +func (v V2I[T]) DivComp(x T, y T) V2I[T] { + return V2I[T]{X: v.X / x, Y: v.Y / y} +} + +func (v *V2I[T]) DivCompInPlace(x T, y T) { + v.X /= x + v.Y /= y +} + +// V3I + +func (v V3I[T]) Div(v2 V3I[T]) V3I[T] { + return V3I[T]{X: v.X / v2.X, Y: v.Y / v2.Y, Z: v.Z / v2.Z} +} + +func (v *V3I[T]) DivInPlace(v2 V3I[T]) { + v.X /= v2.X + v.Y /= v2.Y + v.Z /= v2.Z +} + +func (v V3I[T]) DivComp(x T, y T, z T) V3I[T] { + return V3I[T]{X: v.X / x, Y: v.Y / y, Z: v.Z / z} +} + +func (v *V3I[T]) DivCompInPlace(x T, y T, z T) { + v.X /= x + v.Y /= y + v.Z /= z +} diff --git a/divScalar.go b/divScalar.go new file mode 100644 index 0000000..41c2f3d --- /dev/null +++ b/divScalar.go @@ -0,0 +1,47 @@ +package govec + +// V2F + +func (v V2F[T]) DivScalar(scalar T) V2F[T] { + return V2F[T]{X: v.X / scalar, Y: v.Y / scalar} +} + +func (v *V2F[T]) DivScalarInPlace(scalar T) { + v.X /= scalar + v.Y /= scalar +} + +// V3F + +func (v V3F[T]) DivScalar(scalar T) V3F[T] { + return V3F[T]{X: v.X / scalar, Y: v.Y / scalar, Z: v.Z / scalar} +} + +func (v *V3F[T]) DivScalarInPlace(scalar T) { + v.X /= scalar + v.Y /= scalar + v.Z /= scalar +} + +// V2I + +func (v V2I[T]) DivScalar(scalar T) V2I[T] { + return V2I[T]{X: v.X / scalar, Y: v.Y / scalar} +} + +func (v *V2I[T]) DivScalarInPlace(scalar T) { + v.X /= scalar + v.Y /= scalar +} + +// V3I + +func (v V3I[T]) DivScalar(scalar T) V3I[T] { + return V3I[T]{X: v.X / scalar, Y: v.Y / scalar, Z: v.Z / scalar} +} + +func (v *V3I[T]) DivScalarInPlace(scalar T) { + v.X /= scalar + v.Y /= scalar + v.Z /= scalar +} diff --git a/dot.go b/dot.go new file mode 100644 index 0000000..84810f3 --- /dev/null +++ b/dot.go @@ -0,0 +1,41 @@ +package govec + +// V2F + +func (v V2F[T]) Dot(v2 V2F[T]) T { + return v.X*v2.X + v.Y*v2.Y +} + +func (v V2F[T]) DotComp(x T, y T) T { + return v.X*x + v.Y*y +} + +// V3F + +func (v V3F[T]) Dot(v2 V3F[T]) T { + return v.X*v2.X + v.Y*v2.Y + v.Z*v2.Z +} + +func (v V3F[T]) DotComp(x T, y T, z T) T { + return v.X*x + v.Y*y + v.Z*z +} + +// V2I + +func (v V2I[T]) Dot(v2 V2I[T]) T { + return v.X*v2.X + v.Y*v2.Y +} + +func (v V2I[T]) DotComp(x T, y T) T { + return v.X*x + v.Y*y +} + +// V3I + +func (v V3I[T]) Dot(v2 V3I[T]) T { + return v.X*v2.X + v.Y*v2.Y + v.Z*v2.Z +} + +func (v V3I[T]) DotComp(x T, y T, z T) T { + return v.X*x + v.Y*y + v.Z*z +} diff --git a/extend.go b/extend.go new file mode 100644 index 0000000..1bfcddd --- /dev/null +++ b/extend.go @@ -0,0 +1,9 @@ +package govec + +func (v V2F[T]) extend(z T) V3F[T] { + return V3F[T]{X: v.X, Y: v.Y, Z: z} +} + +func (v V2I[T]) extend(z T) V3I[T] { + return V3I[T]{X: v.X, Y: v.Y, Z: z} +} diff --git a/floor.go b/floor.go new file mode 100644 index 0000000..542a78c --- /dev/null +++ b/floor.go @@ -0,0 +1,26 @@ +package govec + +import "math" + +// V2F + +func (v V2F[T]) Floor() V2F[T] { + return V2F[T]{X: T(math.Floor(float64(v.X))), Y: T(math.Floor(float64(v.Y)))} +} + +func (v *V2F[T]) FloorInPlace() { + v.X = T(math.Floor(float64(v.X))) + v.Y = T(math.Floor(float64(v.Y))) +} + +// V3F + +func (v V3F[T]) Floor() V3F[T] { + return V3F[T]{X: T(math.Floor(float64(v.X))), Y: T(math.Floor(float64(v.Y))), Z: T(math.Floor(float64(v.Z)))} +} + +func (v *V3F[T]) FloorInPlace() { + v.X = T(math.Floor(float64(v.X))) + v.Y = T(math.Floor(float64(v.Y))) + v.Z = T(math.Floor(float64(v.Z))) +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..0f8aecc --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module github.com/xkonti/govec + +go 1.21 + +require golang.org/x/exp v0.0.0-20230905200255-921286631fa9 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..1e02a32 --- /dev/null +++ b/go.sum @@ -0,0 +1 @@ +golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= diff --git a/insert.go b/insert.go new file mode 100644 index 0000000..000d8d7 --- /dev/null +++ b/insert.go @@ -0,0 +1,25 @@ +package govec + +func (v V2F[T]) insertX(a T) V3F[T] { + return V3F[T]{X: a, Y: v.X, Z: v.Y} +} + +func (v V2F[T]) insertY(a T) V3F[T] { + return V3F[T]{X: v.X, Y: a, Z: v.Y} +} + +func (v V2F[T]) insertZ(a T) V3F[T] { + return V3F[T]{X: v.X, Y: v.Y, Z: a} +} + +func (v V2I[T]) insertX(a T) V3I[T] { + return V3I[T]{X: a, Y: v.X, Z: v.Y} +} + +func (v V2I[T]) insertY(a T) V3I[T] { + return V3I[T]{X: v.X, Y: a, Z: v.Y} +} + +func (v V2I[T]) insertZ(a T) V3I[T] { + return V3I[T]{X: v.X, Y: v.Y, Z: a} +} diff --git a/inv.go b/inv.go new file mode 100644 index 0000000..9ebacea --- /dev/null +++ b/inv.go @@ -0,0 +1,47 @@ +package govec + +// V2F + +func (v V2F[T]) Inv() V2F[T] { + return V2F[T]{X: 1 / v.X, Y: 1 / v.Y} +} + +func (v *V2F[T]) InvInPlace() { + v.X = 1 / v.X + v.Y = 1 / v.Y +} + +// V3F + +func (v V3F[T]) Inv() V3F[T] { + return V3F[T]{X: 1 / v.X, Y: 1 / v.Y, Z: 1 / v.Z} +} + +func (v *V3F[T]) InvInPlace() { + v.X = 1 / v.X + v.Y = 1 / v.Y + v.Z = 1 / v.Z +} + +// V2I + +func (v V2I[T]) Inv() V2I[T] { + return V2I[T]{X: 1 / v.X, Y: 1 / v.Y} +} + +func (v *V2I[T]) InvInPlace() { + v.X = 1 / v.X + v.Y = 1 / v.Y +} + +// V3I + +func (v V3I[T]) Inv() V3I[T] { + return V3I[T]{X: 1 / v.X, Y: 1 / v.Y, Z: 1 / v.Z} +} + +func (v *V3I[T]) InvInPlace() { + v.X = 1 / v.X + v.Y = 1 / v.Y + v.Z = 1 / v.Z +} diff --git a/len.go b/len.go new file mode 100644 index 0000000..3e64771 --- /dev/null +++ b/len.go @@ -0,0 +1,27 @@ +package govec + +import "math" + +// V2F + +func (v V2F[T]) Len() float64 { + return math.Sqrt(float64(v.X*v.X + v.Y*v.Y)) +} + +// V3F + +func (v V3F[T]) Len() float64 { + return math.Sqrt(float64(v.X*v.X + v.Y*v.Y + v.Z*v.Z)) +} + +// V2I + +func (v V2I[T]) Len() float64 { + return math.Sqrt(float64(v.X*v.X + v.Y*v.Y)) +} + +// V3I + +func (v V3I[T]) Len() float64 { + return math.Sqrt(float64(v.X*v.X + v.Y*v.Y + v.Z*v.Z)) +} diff --git a/lenSqrt.go b/lenSqrt.go new file mode 100644 index 0000000..44b2ec8 --- /dev/null +++ b/lenSqrt.go @@ -0,0 +1,17 @@ +package govec + +func (v V2F[T]) LenSqrt() T { + return v.X*v.X + v.Y*v.Y +} + +func (v V3F[T]) LenSqrt() T { + return v.X*v.X + v.Y*v.Y + v.Z*v.Z +} + +func (v V2I[T]) LenSqrt() T { + return v.X*v.X + v.Y*v.Y +} + +func (v V3I[T]) LenSqrt() T { + return v.X*v.X + v.Y*v.Y + v.Z*v.Z +} diff --git a/math.go b/math.go new file mode 100644 index 0000000..ba3e7d2 --- /dev/null +++ b/math.go @@ -0,0 +1,24 @@ +package govec + +import "golang.org/x/exp/constraints" + +func pow[T constraints.Float | constraints.Integer](x T, n int16) T { + if n == 0 { + return 1 + } + if n < 0 { + x = 1 / x + n = -n + } + + result := T(1.0) + for n > 0 { + if n%2 == 1 { + result *= x + } + x *= x + n /= 2 + } + + return result +} diff --git a/mod.go b/mod.go new file mode 100644 index 0000000..747286b --- /dev/null +++ b/mod.go @@ -0,0 +1,87 @@ +package govec + +// Modulo for floating point types is using int64, so it might be a bit slower than necessary. + +// V2F + +func (v V2F[T]) Mod(v2 V2F[T]) V2F[T] { + return V2F[T]{X: v.X - v2.X*T(int64(v.X/v2.X)), Y: v.Y - v2.Y*T(int64(v.Y/v2.Y))} +} + +func (v *V2F[T]) ModInPlace(v2 V2F[T]) { + v.X = v.X - v2.X*T(int64(v.X/v2.X)) + v.Y = v.Y - v2.Y*T(int64(v.Y/v2.Y)) +} + +func (v V2F[T]) ModComp(x T, y T) V2F[T] { + return V2F[T]{X: v.X - x*T(int64(v.X/x)), Y: v.Y - y*T(int64(v.Y/y))} +} + +func (v *V2F[T]) ModCompInPlace(x T, y T) { + v.X = v.X - x*T(int64(v.X/x)) + v.Y = v.Y - y*T(int64(v.Y/y)) +} + +// V3F + +func (v V3F[T]) Mod(v2 V3F[T]) V3F[T] { + return V3F[T]{X: v.X - v2.X*T(int64(v.X/v2.X)), Y: v.Y - v2.Y*T(int64(v.Y/v2.Y)), Z: v.Z - v2.Z*T(int64(v.Z/v2.Z))} +} + +func (v *V3F[T]) ModInPlace(v2 V3F[T]) { + v.X = v.X - v2.X*T(int64(v.X/v2.X)) + v.Y = v.Y - v2.Y*T(int64(v.Y/v2.Y)) + v.Z = v.Z - v2.Z*T(int64(v.Z/v2.Z)) +} + +func (v V3F[T]) ModComp(x T, y T, z T) V3F[T] { + return V3F[T]{X: v.X - x*T(int64(v.X/x)), Y: v.Y - y*T(int64(v.Y/y)), Z: v.Z - z*T(int64(v.Z/z))} +} + +func (v *V3F[T]) ModCompInPlace(x T, y T, z T) { + v.X = v.X - x*T(int64(v.X/x)) + v.Y = v.Y - y*T(int64(v.Y/y)) + v.Z = v.Z - z*T(int64(v.Z/z)) +} + +// V2I + +func (v V2I[T]) Mod(v2 V2I[T]) V2I[T] { + return V2I[T]{X: v.X % v2.X, Y: v.Y % v2.Y} +} + +func (v *V2I[T]) ModInPlace(v2 V2I[T]) { + v.X %= v2.X + v.Y %= v2.Y +} + +func (v V2I[T]) ModComp(x T, y T) V2I[T] { + return V2I[T]{X: v.X % x, Y: v.Y % y} +} + +func (v *V2I[T]) ModCompInPlace(x T, y T) { + v.X %= x + v.Y %= y +} + +// V3I + +func (v V3I[T]) Mod(v2 V3I[T]) V3I[T] { + return V3I[T]{X: v.X % v2.X, Y: v.Y % v2.Y, Z: v.Z % v2.Z} +} + +func (v *V3I[T]) ModInPlace(v2 V3I[T]) { + v.X %= v2.X + v.Y %= v2.Y + v.Z %= v2.Z +} + +func (v V3I[T]) ModComp(x T, y T, z T) V3I[T] { + return V3I[T]{X: v.X % x, Y: v.Y % y, Z: v.Z % z} +} + +func (v *V3I[T]) ModCompInPlace(x T, y T, z T) { + v.X %= x + v.Y %= y + v.Z %= z +} diff --git a/mul.go b/mul.go new file mode 100644 index 0000000..48fcdbc --- /dev/null +++ b/mul.go @@ -0,0 +1,85 @@ +package govec + +// V2F + +func (v V2F[T]) Mul(v2 V2F[T]) V2F[T] { + return V2F[T]{X: v.X * v2.X, Y: v.Y * v2.Y} +} + +func (v *V2F[T]) MulInPlace(v2 V2F[T]) { + v.X *= v2.X + v.Y *= v2.Y +} + +func (v V2F[T]) MulComp(x T, y T) V2F[T] { + return V2F[T]{X: v.X * x, Y: v.Y * y} +} + +func (v *V2F[T]) MulCompInPlace(x T, y T) { + v.X *= x + v.Y *= y +} + +// V3F + +func (v V3F[T]) Mul(v2 V3F[T]) V3F[T] { + return V3F[T]{X: v.X * v2.X, Y: v.Y * v2.Y, Z: v.Z * v2.Z} +} + +func (v *V3F[T]) MulInPlace(v2 V3F[T]) { + v.X *= v2.X + v.Y *= v2.Y + v.Z *= v2.Z +} + +func (v V3F[T]) MulComp(x T, y T, z T) V3F[T] { + return V3F[T]{X: v.X * x, Y: v.Y * y, Z: v.Z * z} +} + +func (v *V3F[T]) MulCompInPlace(x T, y T, z T) { + v.X *= x + v.Y *= y + v.Z *= z +} + +// V2I + +func (v V2I[T]) Mul(v2 V2I[T]) V2I[T] { + return V2I[T]{X: v.X * v2.X, Y: v.Y * v2.Y} +} + +func (v *V2I[T]) MulInPlace(v2 V2I[T]) { + v.X *= v2.X + v.Y *= v2.Y +} + +func (v V2I[T]) MulComp(x T, y T) V2I[T] { + return V2I[T]{X: v.X * x, Y: v.Y * y} +} + +func (v *V2I[T]) MulCompInPlace(x T, y T) { + v.X *= x + v.Y *= y +} + +// V3I + +func (v V3I[T]) Mul(v2 V3I[T]) V3I[T] { + return V3I[T]{X: v.X * v2.X, Y: v.Y * v2.Y, Z: v.Z * v2.Z} +} + +func (v *V3I[T]) MulInPlace(v2 V3I[T]) { + v.X *= v2.X + v.Y *= v2.Y + v.Z *= v2.Z +} + +func (v V3I[T]) MulComp(x T, y T, z T) V3I[T] { + return V3I[T]{X: v.X * x, Y: v.Y * y, Z: v.Z * z} +} + +func (v *V3I[T]) MulCompInPlace(x T, y T, z T) { + v.X *= x + v.Y *= y + v.Z *= z +} diff --git a/mulScalar.go b/mulScalar.go new file mode 100644 index 0000000..206895c --- /dev/null +++ b/mulScalar.go @@ -0,0 +1,47 @@ +package govec + +// V2F + +func (v V2F[T]) MulScalar(scalar T) V2F[T] { + return V2F[T]{X: v.X * scalar, Y: v.Y * scalar} +} + +func (v *V2F[T]) MulScalarInPlace(scalar T) { + v.X *= scalar + v.Y *= scalar +} + +// V3F + +func (v V3F[T]) MulScalar(scalar T) V3F[T] { + return V3F[T]{X: v.X * scalar, Y: v.Y * scalar, Z: v.Z * scalar} +} + +func (v *V3F[T]) MulScalarInPlace(scalar T) { + v.X *= scalar + v.Y *= scalar + v.Z *= scalar +} + +// V2I + +func (v V2I[T]) MulScalar(scalar T) V2I[T] { + return V2I[T]{X: v.X * scalar, Y: v.Y * scalar} +} + +func (v *V2I[T]) MulScalarInPlace(scalar T) { + v.X *= scalar + v.Y *= scalar +} + +// V3I + +func (v V3I[T]) MulScalar(scalar T) V3I[T] { + return V3I[T]{X: v.X * scalar, Y: v.Y * scalar, Z: v.Z * scalar} +} + +func (v *V3I[T]) MulScalarInPlace(scalar T) { + v.X *= scalar + v.Y *= scalar + v.Z *= scalar +} diff --git a/neg.go b/neg.go new file mode 100644 index 0000000..b4abf65 --- /dev/null +++ b/neg.go @@ -0,0 +1,43 @@ +package govec + +// Neg for V2F +func (v V2F[T]) Neg(v2 V2F[T]) V2F[T] { + return V2F[T]{X: v.X - v2.X, Y: v.Y - v2.Y} +} + +func (v *V2F[T]) NegInPlace(v2 V2F[T]) { + v.X -= v2.X + v.Y -= v2.Y +} + +// Neg for V3F +func (v V3F[T]) Neg(v2 V3F[T]) V3F[T] { + return V3F[T]{X: v.X - v2.X, Y: v.Y - v2.Y, Z: v.Z - v2.Z} +} + +func (v *V3F[T]) NegInPlace(v2 V3F[T]) { + v.X -= v2.X + v.Y -= v2.Y + v.Z -= v2.Z +} + +// Neg for V2I +func (v V2I[T]) Neg(v2 V2I[T]) V2I[T] { + return V2I[T]{X: v.X - v2.X, Y: v.Y - v2.Y} +} + +func (v *V2I[T]) NegInPlace(v2 V2I[T]) { + v.X -= v2.X + v.Y -= v2.Y +} + +// Neg for V3I +func (v V3I[T]) Neg(v2 V3I[T]) V3I[T] { + return V3I[T]{X: v.X - v2.X, Y: v.Y - v2.Y, Z: v.Z - v2.Z} +} + +func (v *V3I[T]) NegInPlace(v2 V3I[T]) { + v.X -= v2.X + v.Y -= v2.Y + v.Z -= v2.Z +} diff --git a/new.go b/new.go new file mode 100644 index 0000000..7511471 --- /dev/null +++ b/new.go @@ -0,0 +1,75 @@ +package govec + +import "golang.org/x/exp/constraints" + +// NEW + +func NewV2F[T constraints.Float](x, y T) V2F[T] { + return V2F[T]{X: x, Y: y} +} + +func NewV3F[T constraints.Float](x, y, z T) V3F[T] { + return V3F[T]{X: x, Y: y, Z: z} +} + +func NewV2I[T constraints.Integer](x, y T) V2I[T] { + return V2I[T]{X: x, Y: y} +} + +func NewV3I[T constraints.Integer](x, y, z T) V3I[T] { + return V3I[T]{X: x, Y: y, Z: z} +} + +// Fill + +func FillV2F[T constraints.Float](value T) V2F[T] { + return V2F[T]{X: value, Y: value} +} + +func FillV3F[T constraints.Float](value T) V3F[T] { + return V3F[T]{X: value, Y: value, Z: value} +} + +func FillV2I[T constraints.Integer](value T) V2I[T] { + return V2I[T]{X: value, Y: value} +} + +func FillV3I[T constraints.Integer](value T) V3I[T] { + return V3I[T]{X: value, Y: value, Z: value} +} + +// ZERO + +func ZeroV2F[T constraints.Float]() V2F[T] { + return V2F[T]{X: 0.0, Y: 0.0} +} + +func ZeroV3F[T constraints.Float]() V3F[T] { + return V3F[T]{X: 0.0, Y: 0.0, Z: 0.0} +} + +func ZeroV2I[T constraints.Integer]() V2I[T] { + return V2I[T]{X: 0, Y: 0} +} + +func ZeroV3I[T constraints.Integer]() V3I[T] { + return V3I[T]{X: 0, Y: 0, Z: 0} +} + +// ONE + +func OneV2F[T constraints.Float]() V2F[T] { + return V2F[T]{X: 1.0, Y: 1.0} +} + +func OneV3F[T constraints.Float]() V3F[T] { + return V3F[T]{X: 1.0, Y: 1.0, Z: 1.0} +} + +func OneV2I[T constraints.Integer]() V2I[T] { + return V2I[T]{X: 1, Y: 1} +} + +func OneV3I[T constraints.Integer]() V3I[T] { + return V3I[T]{X: 1, Y: 1, Z: 1} +} diff --git a/norm.go b/norm.go new file mode 100644 index 0000000..477f2b4 --- /dev/null +++ b/norm.go @@ -0,0 +1,46 @@ +package govec + +import ( + "math" +) + +// V2F + +func (v V2F[T]) Norm() V2F[T] { + magnitude := math.Sqrt(float64(v.X*v.X + v.Y*v.Y)) + return V2F[T]{X: v.X / T(magnitude), Y: v.Y / T(magnitude)} +} + +func (v *V2F[T]) NormInPlace() { + magnitude := math.Sqrt(float64(v.X*v.X + v.Y*v.Y)) + v.X /= T(magnitude) + v.Y /= T(magnitude) +} + +// V3F + +func (v V3F[T]) Norm() V3F[T] { + magnitude := math.Sqrt(float64(v.X*v.X + v.Y*v.Y + v.Z*v.Z)) + return V3F[T]{X: v.X / T(magnitude), Y: v.Y / T(magnitude), Z: v.Z / T(magnitude)} +} + +func (v *V3F[T]) NormInPlace() { + magnitude := math.Sqrt(float64(v.X*v.X + v.Y*v.Y + v.Z*v.Z)) + v.X /= T(magnitude) + v.Y /= T(magnitude) + v.Z /= T(magnitude) +} + +// V2I + +func (v V2I[T]) Norm() V2F[float64] { + magnitude := math.Sqrt(float64(v.X*v.X + v.Y*v.Y)) + return V2F[float64]{X: float64(v.X) / magnitude, Y: float64(v.Y) / magnitude} +} + +// V3I + +func (v V3I[T]) Norm() V3F[float64] { + magnitude := math.Sqrt(float64(v.X*v.X + v.Y*v.Y + v.Z*v.Z)) + return V3F[float64]{X: float64(v.X) / magnitude, Y: float64(v.Y) / magnitude, Z: float64(v.Z) / magnitude} +} diff --git a/pow.go b/pow.go new file mode 100644 index 0000000..50c08ec --- /dev/null +++ b/pow.go @@ -0,0 +1,87 @@ +package govec + +import "math" + +// V2F + +func (v V2F[T]) Pow(v2 V2F[T]) V2F[T] { + return V2F[T]{X: T(math.Pow(float64(v.X), float64(v2.X))), Y: T(math.Pow(float64(v.Y), float64(v2.Y)))} +} + +func (v *V2F[T]) PowInPlace(v2 V2F[T]) { + v.X = T(math.Pow(float64(v.X), float64(v2.X))) + v.Y = T(math.Pow(float64(v.Y), float64(v2.Y))) +} + +func (v V2F[T]) PowComp(x T, y T) V2F[T] { + return V2F[T]{X: T(math.Pow(float64(v.X), float64(x))), Y: T(math.Pow(float64(v.Y), float64(y)))} +} + +func (v *V2F[T]) PowCompInPlace(x T, y T) { + v.X = T(math.Pow(float64(v.X), float64(x))) + v.Y = T(math.Pow(float64(v.Y), float64(y))) +} + +// V3F + +func (v V3F[T]) Pow(v2 V3F[T]) V3F[T] { + return V3F[T]{X: T(math.Pow(float64(v.X), float64(v2.X))), Y: T(math.Pow(float64(v.Y), float64(v2.Y))), Z: T(math.Pow(float64(v.Z), float64(v2.Z)))} +} + +func (v *V3F[T]) PowInPlace(v2 V3F[T]) { + v.X = T(math.Pow(float64(v.X), float64(v2.X))) + v.Y = T(math.Pow(float64(v.Y), float64(v2.Y))) + v.Z = T(math.Pow(float64(v.Z), float64(v2.Z))) +} + +func (v V3F[T]) PowComp(x T, y T, z T) V3F[T] { + return V3F[T]{X: T(math.Pow(float64(v.X), float64(x))), Y: T(math.Pow(float64(v.Y), float64(y))), Z: T(math.Pow(float64(v.Z), float64(z)))} +} + +func (v *V3F[T]) PowCompInPlace(x T, y T, z T) { + v.X = T(math.Pow(float64(v.X), float64(x))) + v.Y = T(math.Pow(float64(v.Y), float64(y))) + v.Z = T(math.Pow(float64(v.Z), float64(z))) +} + +// V2I + +func (v V2I[T]) Pow(v2 V2I[T]) V2I[T] { + return V2I[T]{X: pow(v.X, int16(v2.X)), Y: pow(v.Y, int16(v2.Y))} +} + +func (v *V2I[T]) PowInPlace(v2 V2I[T]) { + v.X = pow(v.X, int16(v2.X)) + v.Y = pow(v.Y, int16(v2.Y)) +} + +func (v V2I[T]) PowComp(x T, y T) V2I[T] { + return V2I[T]{X: pow(v.X, int16(x)), Y: pow(v.Y, int16(y))} +} + +func (v *V2I[T]) PowCompInPlace(x T, y T) { + v.X = pow(v.X, int16(x)) + v.Y = pow(v.Y, int16(y)) +} + +// V3I + +func (v V3I[T]) Pow(v2 V3I[T]) V3I[T] { + return V3I[T]{X: pow(v.X, int16(v2.X)), Y: pow(v.Y, int16(v2.Y)), Z: pow(v.Z, int16(v2.Z))} +} + +func (v *V3I[T]) PowInPlace(v2 V3I[T]) { + v.X = pow(v.X, int16(v2.X)) + v.Y = pow(v.Y, int16(v2.Y)) + v.Z = pow(v.Z, int16(v2.Z)) +} + +func (v V3I[T]) PowComp(x T, y T, z T) V3I[T] { + return V3I[T]{X: pow(v.X, int16(x)), Y: pow(v.Y, int16(y)), Z: pow(v.Z, int16(z))} +} + +func (v *V3I[T]) PowCompInPlace(x T, y T, z T) { + v.X = pow(v.X, int16(x)) + v.Y = pow(v.Y, int16(y)) + v.Z = pow(v.Z, int16(z)) +} diff --git a/pow2.go b/pow2.go new file mode 100644 index 0000000..2faef86 --- /dev/null +++ b/pow2.go @@ -0,0 +1,43 @@ +package govec + +// Pow2 for V2F +func (v V2F[T]) Pow2() V2F[T] { + return V2F[T]{X: v.X * v.X, Y: v.Y * v.Y} +} + +func (v *V2F[T]) Pow2InPlace() { + v.X = v.X * v.X + v.Y = v.Y * v.Y +} + +// Pow2 for V3F +func (v V3F[T]) Pow2() V3F[T] { + return V3F[T]{X: v.X * v.X, Y: v.Y * v.Y, Z: v.Z * v.Z} +} + +func (v *V3F[T]) Pow2InPlace() { + v.X = v.X * v.X + v.Y = v.Y * v.Y + v.Z = v.Z * v.Z +} + +// Pow2 for V2I +func (v V2I[T]) Pow2() V2I[T] { + return V2I[T]{X: v.X * v.X, Y: v.Y * v.Y} +} + +func (v *V2I[T]) Pow2InPlace() { + v.X = v.X * v.X + v.Y = v.Y * v.Y +} + +// Pow2 for V3I +func (v V3I[T]) Pow2() V3I[T] { + return V3I[T]{X: v.X * v.X, Y: v.Y * v.Y, Z: v.Z * v.Z} +} + +func (v *V3I[T]) Pow2InPlace() { + v.X = v.X * v.X + v.Y = v.Y * v.Y + v.Z = v.Z * v.Z +} diff --git a/pow3.go b/pow3.go new file mode 100644 index 0000000..2cc13b1 --- /dev/null +++ b/pow3.go @@ -0,0 +1,43 @@ +package govec + +// Pow3 for V2F +func (v V2F[T]) Pow3() V2F[T] { + return V2F[T]{X: v.X * v.X * v.X, Y: v.Y * v.Y * v.Y} +} + +func (v *V2F[T]) Pow3InPlace() { + v.X = v.X * v.X * v.X + v.Y = v.Y * v.Y * v.Y +} + +// Pow3 for V3F +func (v V3F[T]) Pow3() V3F[T] { + return V3F[T]{X: v.X * v.X * v.X, Y: v.Y * v.Y * v.Y, Z: v.Z * v.Z * v.Z} +} + +func (v *V3F[T]) Pow3InPlace() { + v.X = v.X * v.X * v.X + v.Y = v.Y * v.Y * v.Y + v.Z = v.Z * v.Z * v.Z +} + +// Pow3 for V2I +func (v V2I[T]) Pow3() V2I[T] { + return V2I[T]{X: v.X * v.X * v.X, Y: v.Y * v.Y * v.Y} +} + +func (v *V2I[T]) Pow3InPlace() { + v.X = v.X * v.X * v.X + v.Y = v.Y * v.Y * v.Y +} + +// Pow3 for V3I +func (v V3I[T]) Pow3() V3I[T] { + return V3I[T]{X: v.X * v.X * v.X, Y: v.Y * v.Y * v.Y, Z: v.Z * v.Z * v.Z} +} + +func (v *V3I[T]) Pow3InPlace() { + v.X = v.X * v.X * v.X + v.Y = v.Y * v.Y * v.Y + v.Z = v.Z * v.Z * v.Z +} diff --git a/powN.go b/powN.go new file mode 100644 index 0000000..5ef09a0 --- /dev/null +++ b/powN.go @@ -0,0 +1,47 @@ +package govec + +// V2F + +func (v V2F[T]) PowN(n int16) V2F[T] { + return V2F[T]{X: pow(v.X, n), Y: pow(v.Y, n)} +} + +func (v *V2F[T]) PowNInPlace(n int16) { + v.X = pow(v.X, n) + v.Y = pow(v.Y, n) +} + +// V3F + +func (v V3F[T]) PowN(n int16) V3F[T] { + return V3F[T]{X: pow(v.X, n), Y: pow(v.Y, n), Z: pow(v.Z, n)} +} + +func (v *V3F[T]) PowNInPlace(n int16) { + v.X = pow(v.X, n) + v.Y = pow(v.Y, n) + v.Z = pow(v.Z, n) +} + +// V2I + +func (v V2I[T]) PowN(n int16) V2I[T] { + return V2I[T]{X: pow(v.X, n), Y: pow(v.Y, n)} +} + +func (v *V2I[T]) PowNInPlace(n int16) { + v.X = pow(v.X, n) + v.Y = pow(v.Y, n) +} + +// V3I + +func (v V3I[T]) PowN(n int16) V3I[T] { + return V3I[T]{X: pow(v.X, n), Y: pow(v.Y, n), Z: pow(v.Z, n)} +} + +func (v *V3I[T]) PowNInPlace(n int16) { + v.X = pow(v.X, n) + v.Y = pow(v.Y, n) + v.Z = pow(v.Z, n) +} diff --git a/powNFloat.go b/powNFloat.go new file mode 100644 index 0000000..220ebca --- /dev/null +++ b/powNFloat.go @@ -0,0 +1,45 @@ +package govec + +import "math" + +// PowNFloat for V2F +func (v V2F[T]) PowNFloat(n float64) V2F[T] { + return V2F[T]{X: T(math.Pow(float64(v.X), n)), Y: T(math.Pow(float64(v.Y), n))} +} + +func (v *V2F[T]) PowNFloatInPlace(n float64) { + v.X = T(math.Pow(float64(v.X), n)) + v.Y = T(math.Pow(float64(v.Y), n)) +} + +// PowNFloat for V3F +func (v V3F[T]) PowNFloat(n float64) V3F[T] { + return V3F[T]{X: T(math.Pow(float64(v.X), n)), Y: T(math.Pow(float64(v.Y), n)), Z: T(math.Pow(float64(v.Z), n))} +} + +func (v *V3F[T]) PowNFloatInPlace(n float64) { + v.X = T(math.Pow(float64(v.X), n)) + v.Y = T(math.Pow(float64(v.Y), n)) + v.Z = T(math.Pow(float64(v.Z), n)) +} + +// PowNFloat for V2I +func (v V2I[T]) PowNFloat(n float64) V2I[T] { + return V2I[T]{X: T(math.Pow(float64(v.X), n)), Y: T(math.Pow(float64(v.Y), n))} +} + +func (v *V2I[T]) PowNFloatInPlace(n float64) { + v.X = T(math.Pow(float64(v.X), n)) + v.Y = T(math.Pow(float64(v.Y), n)) +} + +// PowNFloat for V3I +func (v V3I[T]) PowNFloat(n float64) V3I[T] { + return V3I[T]{X: T(math.Pow(float64(v.X), n)), Y: T(math.Pow(float64(v.Y), n)), Z: T(math.Pow(float64(v.Z), n))} +} + +func (v *V3I[T]) PowNFloatInPlace(n float64) { + v.X = T(math.Pow(float64(v.X), n)) + v.Y = T(math.Pow(float64(v.Y), n)) + v.Z = T(math.Pow(float64(v.Z), n)) +} diff --git a/round.go b/round.go new file mode 100644 index 0000000..6d7842f --- /dev/null +++ b/round.go @@ -0,0 +1,26 @@ +package govec + +import "math" + +// V2F + +func (v V2F[T]) Round() V2F[T] { + return V2F[T]{X: T(math.Round(float64(v.X))), Y: T(math.Round(float64(v.Y)))} +} + +func (v *V2F[T]) RoundInPlace() { + v.X = T(math.Round(float64(v.X))) + v.Y = T(math.Round(float64(v.Y))) +} + +// V3F + +func (v V3F[T]) Round() V3F[T] { + return V3F[T]{X: T(math.Round(float64(v.X))), Y: T(math.Round(float64(v.Y))), Z: T(math.Round(float64(v.Z)))} +} + +func (v *V3F[T]) RoundInPlace() { + v.X = T(math.Round(float64(v.X))) + v.Y = T(math.Round(float64(v.Y))) + v.Z = T(math.Round(float64(v.Z))) +} diff --git a/slice.go b/slice.go new file mode 100644 index 0000000..45b67ca --- /dev/null +++ b/slice.go @@ -0,0 +1,81 @@ +package govec + +import "golang.org/x/exp/constraints" + +func V2FFromSlice[T constraints.Float](a []T) V2F[T] { + if len(a) < 2 { + panic("vector.V2FFromSlice: slice length < 2") + } + return V2F[T]{X: a[0], Y: a[1]} +} + +func V3FFromSlice[T constraints.Float](a []T) V3F[T] { + if len(a) < 3 { + panic("vector.V3FFromSlice: slice length < 3") + } + return V3F[T]{X: a[0], Y: a[1], Z: a[2]} +} + +func V2IFromSlice[T constraints.Integer](a []T) V2I[T] { + if len(a) < 2 { + panic("vector.V2IFromSlice: slice length < 2") + } + return V2I[T]{X: a[0], Y: a[1]} +} + +func V3IFromSlice[T constraints.Integer](a []T) V3I[T] { + if len(a) < 3 { + panic("vector.V3IFromSlice: slice length < 3") + } + return V3I[T]{X: a[0], Y: a[1], Z: a[2]} +} + +func (v V2F[T]) ToSlice() []T { + return []T{v.X, v.Y} +} + +func (v V3F[T]) ToSlice() []T { + return []T{v.X, v.Y, v.Z} +} + +func (v V2I[T]) ToSlice() []T { + return []T{v.X, v.Y} +} + +func (v V3I[T]) ToSlice() []T { + return []T{v.X, v.Y, v.Z} +} + +func (v V2F[T]) ApplyToSlice(a []T) { + if len(a) < 2 { + panic("vector.V2F.ApplyToSlice: slice length < 2") + } + a[0] = v.X + a[1] = v.Y +} + +func (v V3F[T]) ApplyToSlice(a []T) { + if len(a) < 3 { + panic("vector.V3F.ApplyToSlice: slice length < 3") + } + a[0] = v.X + a[1] = v.Y + a[2] = v.Z +} + +func (v V2I[T]) ApplyToSlice(a []T) { + if len(a) < 2 { + panic("vector.V2I.ApplyToSlice: slice length < 2") + } + a[0] = v.X + a[1] = v.Y +} + +func (v V3I[T]) ApplyToSlice(a []T) { + if len(a) < 3 { + panic("vector.V3I.ApplyToSlice: slice length < 3") + } + a[0] = v.X + a[1] = v.Y + a[2] = v.Z +} diff --git a/splt.go b/splt.go new file mode 100644 index 0000000..d30bb3b --- /dev/null +++ b/splt.go @@ -0,0 +1,17 @@ +package govec + +func (v V2F[T]) split() (T, T) { + return v.X, v.Y +} + +func (v V3F[T]) split() (T, T, T) { + return v.X, v.Y, v.Z +} + +func (v V2I[T]) split() (T, T) { + return v.X, v.Y +} + +func (v V3I[T]) split() (T, T, T) { + return v.X, v.Y, v.Z +} diff --git a/sqrt.go b/sqrt.go new file mode 100644 index 0000000..e7f15ca --- /dev/null +++ b/sqrt.go @@ -0,0 +1,38 @@ +package govec + +import "math" + +// V2F + +func (v V2F[T]) Sqrt() V2F[T] { + return V2F[T]{X: T(math.Sqrt(float64(v.X))), Y: T(math.Sqrt(float64(v.Y)))} +} + +func (v *V2F[T]) SqrtInPlace() { + v.X = T(math.Sqrt(float64(v.X))) + v.Y = T(math.Sqrt(float64(v.Y))) +} + +// V3F + +func (v V3F[T]) Sqrt() V3F[T] { + return V3F[T]{X: T(math.Sqrt(float64(v.X))), Y: T(math.Sqrt(float64(v.Y))), Z: T(math.Sqrt(float64(v.Z)))} +} + +func (v *V3F[T]) SqrtInPlace() { + v.X = T(math.Sqrt(float64(v.X))) + v.Y = T(math.Sqrt(float64(v.Y))) + v.Z = T(math.Sqrt(float64(v.Z))) +} + +// V2I + +func (v V2I[T]) Sqrt() V2F[float64] { + return V2F[float64]{X: math.Sqrt(float64(v.X)), Y: math.Sqrt(float64(v.Y))} +} + +// V3I + +func (v V3I[T]) Sqrt() V3F[float64] { + return V3F[float64]{X: math.Sqrt(float64(v.X)), Y: math.Sqrt(float64(v.Y)), Z: math.Sqrt(float64(v.Z))} +} diff --git a/sub.go b/sub.go new file mode 100644 index 0000000..30f6518 --- /dev/null +++ b/sub.go @@ -0,0 +1,85 @@ +package govec + +// V2F + +func (v V2F[T]) Sub(v2 V2F[T]) V2F[T] { + return V2F[T]{X: v.X - v2.X, Y: v.Y - v2.Y} +} + +func (v *V2F[T]) SubInPlace(v2 V2F[T]) { + v.X -= v2.X + v.Y -= v2.Y +} + +func (v V2F[T]) SubComp(x T, y T) V2F[T] { + return V2F[T]{X: v.X - x, Y: v.Y - y} +} + +func (v *V2F[T]) SubCompInPlace(x T, y T) { + v.X -= x + v.Y -= y +} + +// V3F + +func (v V3F[T]) Sub(v2 V3F[T]) V3F[T] { + return V3F[T]{X: v.X - v2.X, Y: v.Y - v2.Y, Z: v.Z - v2.Z} +} + +func (v *V3F[T]) SubInPlace(v2 V3F[T]) { + v.X -= v2.X + v.Y -= v2.Y + v.Z -= v2.Z +} + +func (v V3F[T]) SubComp(x T, y T, z T) V3F[T] { + return V3F[T]{X: v.X - x, Y: v.Y - y, Z: v.Z - z} +} + +func (v *V3F[T]) SubCompInPlace(x T, y T, z T) { + v.X -= x + v.Y -= y + v.Z -= z +} + +// V2I + +func (v V2I[T]) Sub(v2 V2I[T]) V2I[T] { + return V2I[T]{X: v.X - v2.X, Y: v.Y - v2.Y} +} + +func (v *V2I[T]) SubInPlace(v2 V2I[T]) { + v.X -= v2.X + v.Y -= v2.Y +} + +func (v V2I[T]) SubComp(x T, y T) V2I[T] { + return V2I[T]{X: v.X - x, Y: v.Y - y} +} + +func (v *V2I[T]) SubCompInPlace(x T, y T) { + v.X -= x + v.Y -= y +} + +// V3I + +func (v V3I[T]) Sub(v2 V3I[T]) V3I[T] { + return V3I[T]{X: v.X - v2.X, Y: v.Y - v2.Y, Z: v.Z - v2.Z} +} + +func (v *V3I[T]) SubInPlace(v2 V3I[T]) { + v.X -= v2.X + v.Y -= v2.Y + v.Z -= v2.Z +} + +func (v V3I[T]) SubComp(x T, y T, z T) V3I[T] { + return V3I[T]{X: v.X - x, Y: v.Y - y, Z: v.Z - z} +} + +func (v *V3I[T]) SubCompInPlace(x T, y T, z T) { + v.X -= x + v.Y -= y + v.Z -= z +} diff --git a/subScalar.go b/subScalar.go new file mode 100644 index 0000000..101828b --- /dev/null +++ b/subScalar.go @@ -0,0 +1,47 @@ +package govec + +// V2F + +func (v V2F[T]) SubScalar(scalar T) V2F[T] { + return V2F[T]{X: v.X - scalar, Y: v.Y - scalar} +} + +func (v *V2F[T]) SubScalarInPlace(scalar T) { + v.X -= scalar + v.Y -= scalar +} + +// V3F + +func (v V3F[T]) SubScalar(scalar T) V3F[T] { + return V3F[T]{X: v.X - scalar, Y: v.Y - scalar, Z: v.Z - scalar} +} + +func (v *V3F[T]) SubScalarInPlace(scalar T) { + v.X -= scalar + v.Y -= scalar + v.Z -= scalar +} + +// V2I + +func (v V2I[T]) SubScalar(scalar T) V2I[T] { + return V2I[T]{X: v.X - scalar, Y: v.Y - scalar} +} + +func (v *V2I[T]) SubScalarInPlace(scalar T) { + v.X -= scalar + v.Y -= scalar +} + +// V3I + +func (v V3I[T]) SubScalar(scalar T) V3I[T] { + return V3I[T]{X: v.X - scalar, Y: v.Y - scalar, Z: v.Z - scalar} +} + +func (v *V3I[T]) SubScalarInPlace(scalar T) { + v.X -= scalar + v.Y -= scalar + v.Z -= scalar +} diff --git a/vec2f.go b/vec2f.go new file mode 100644 index 0000000..dc9b76d --- /dev/null +++ b/vec2f.go @@ -0,0 +1,32 @@ +package govec + +import "golang.org/x/exp/constraints" + +type V2F[T constraints.Float] struct { + X T + Y T +} + +func (v V2F[T]) ToV2F64() V2F[float64] { + return V2F[float64]{X: float64(v.X), Y: float64(v.Y)} +} + +func (v V2F[T]) ToV2F32() V2F[float32] { + return V2F[float32]{X: float32(v.X), Y: float32(v.Y)} +} + +func (v V2F[T]) ToV2I64() V2I[int64] { + return V2I[int64]{X: int64(v.X), Y: int64(v.Y)} +} + +func (v V2F[T]) ToV2I32() V2I[int32] { + return V2I[int32]{X: int32(v.X), Y: int32(v.Y)} +} + +func (v V2F[T]) ToV2I16() V2I[int16] { + return V2I[int16]{X: int16(v.X), Y: int16(v.Y)} +} + +func (v V2F[T]) ToV2I8() V2I[int8] { + return V2I[int8]{X: int8(v.X), Y: int8(v.Y)} +} diff --git a/vec2i.go b/vec2i.go new file mode 100644 index 0000000..2bf049c --- /dev/null +++ b/vec2i.go @@ -0,0 +1,32 @@ +package govec + +import "golang.org/x/exp/constraints" + +type V2I[T constraints.Integer] struct { + X T + Y T +} + +func (v V2I[T]) ToV2F64() V2F[float64] { + return V2F[float64]{X: float64(v.X), Y: float64(v.Y)} +} + +func (v V2I[T]) ToV2F32() V2F[float32] { + return V2F[float32]{X: float32(v.X), Y: float32(v.Y)} +} + +func (v V2I[T]) ToV2I64() V2I[int64] { + return V2I[int64]{X: int64(v.X), Y: int64(v.Y)} +} + +func (v V2I[T]) ToV2I32() V2I[int32] { + return V2I[int32]{X: int32(v.X), Y: int32(v.Y)} +} + +func (v V2I[T]) ToV2I16() V2I[int16] { + return V2I[int16]{X: int16(v.X), Y: int16(v.Y)} +} + +func (v V2I[T]) ToV2I8() V2I[int8] { + return V2I[int8]{X: int8(v.X), Y: int8(v.Y)} +} diff --git a/vec3f.go b/vec3f.go new file mode 100644 index 0000000..b175ae8 --- /dev/null +++ b/vec3f.go @@ -0,0 +1,33 @@ +package govec + +import "golang.org/x/exp/constraints" + +type V3F[T constraints.Float] struct { + X T + Y T + Z T +} + +func (v V3F[T]) ToV3F64() V3F[float64] { + return V3F[float64]{X: float64(v.X), Y: float64(v.Y), Z: float64(v.Z)} +} + +func (v V3F[T]) ToV3F32() V3F[float32] { + return V3F[float32]{X: float32(v.X), Y: float32(v.Y), Z: float32(v.Z)} +} + +func (v V3F[T]) ToV3I64() V3I[int64] { + return V3I[int64]{X: int64(v.X), Y: int64(v.Y), Z: int64(v.Z)} +} + +func (v V3F[T]) ToV3I32() V3I[int32] { + return V3I[int32]{X: int32(v.X), Y: int32(v.Y), Z: int32(v.Z)} +} + +func (v V3F[T]) ToV3I16() V3I[int16] { + return V3I[int16]{X: int16(v.X), Y: int16(v.Y), Z: int16(v.Z)} +} + +func (v V3F[T]) ToV3I8() V3I[int8] { + return V3I[int8]{X: int8(v.X), Y: int8(v.Y), Z: int8(v.Z)} +} diff --git a/vec3i.go b/vec3i.go new file mode 100644 index 0000000..2a4c1e2 --- /dev/null +++ b/vec3i.go @@ -0,0 +1,33 @@ +package govec + +import "golang.org/x/exp/constraints" + +type V3I[T constraints.Integer] struct { + X T + Y T + Z T +} + +func (v V3I[T]) ToV3F64() V3F[float64] { + return V3F[float64]{X: float64(v.X), Y: float64(v.Y), Z: float64(v.Z)} +} + +func (v V3I[T]) ToV3F32() V3F[float32] { + return V3F[float32]{X: float32(v.X), Y: float32(v.Y), Z: float32(v.Z)} +} + +func (v V3I[T]) ToV3I64() V3I[int64] { + return V3I[int64]{X: int64(v.X), Y: int64(v.Y), Z: int64(v.Z)} +} + +func (v V3I[T]) ToV3I32() V3I[int32] { + return V3I[int32]{X: int32(v.X), Y: int32(v.Y), Z: int32(v.Z)} +} + +func (v V3I[T]) ToV3I16() V3I[int16] { + return V3I[int16]{X: int16(v.X), Y: int16(v.Y), Z: int16(v.Z)} +} + +func (v V3I[T]) ToV3I8() V3I[int8] { + return V3I[int8]{X: int8(v.X), Y: int8(v.Y), Z: int8(v.Z)} +}