Categorygithub.com/EliCDavis/vector
modulepackage
1.8.0
Repository: https://github.com/elicdavis/vector.git
Documentation: pkg.go.dev

# README

Vector

Coverage Go Report Card GoDoc

Collection of generic, immutable vector math functions I've written overtime for different hobby projects.

API

FunctionVector2Vector3Vector4Description
AbsReturns a vector with each component's absolute value
AddComponent Wise Addition
AngleReturns the angle between two vectors
ToArrReturns a slice containing the vector component data
ToFixedArrReturns a array containing the vector component data
CeilCeils each vectors component to the nearest integer
ClampClamps each component between two values
ContainsNaNReturns true if any component of the vector is NaN
CrossReturns the cross product between two vectors
DotReturns the dot product between two vectors
FlipScales the vector by -1
FlipXReturns a vector with the X component multiplied by -1
FlipYReturns a vector with the Y component multiplied by -1
FlipZReturns a vector with the Z component multiplied by -1
FlipWReturns a vector with the W component multiplied by -1
FloorFloors each vectors component
FormatBuild a string with vector data
LengthReturns the length of the vector
LengthSquaredReturns the squared length of the vector
MaxReturns a new vector where each component is the largest value between the two vectors
MaxXReturns the largest X component between the two vectors
MaxYReturns the largest Y component between the two vectors
MaxZReturns the largest Z component between the two vectors
MaxWReturns the largest W component between the two vectors
MaxComponentReturns the vectors largest component
MidpointFinds the mid point between two vectors
MinReturns a new vector where each component is the smallest value between the two vectors
MinXReturns the smallest X component between the two vectors
MinYReturns the smallest Y component between the two vectors
MinZReturns the smallest Z component between the two vectors
MinWReturns the smallest W component between the two vectors
MinComponentReturns the vectors smallest component
NormalizedReturns the normalized vector
NearZeroReturns true if all of the components are near 0
RoundRounds each vectors component to the nearest integer
ScaleScales the vector by some constant
SqrtReturns a vector with each component's square root
SubComponent Wise Subtraction
ValuesReturns all components of the vector
XReturns the x component of the vector
YReturns the y component of the vector
ZReturns the z component of the vector
WReturns the w component of the vector
XYEquivalent to vector2.New[T](v.x, v.y)
YZEquivalent to vector2.New[T](v.y, v.z)
XZEquivalent to vector2.New[T](v.x, v.z)
YXEquivalent to vector2.New[T](v.y, v.x)
ZXEquivalent to vector2.New[T](v.z, v.x)
ZYEquivalent to vector2.New[T](v.z, v.y)
LerpInterpolates between two vectors by t.
LerpClampedInterpolates between two vectors by t. T is clamped 0 to 1
LogReturns the natural logarithm for each component
Log2Returns the binary logarithm for each component
Log10Returns the decimal logarithm for each component
ExpReturns e**x, the base-e exponential for each component
Exp2Returns 2**x, the base-2 exponential for each component
Expm1Returns e**x - 1, the base-e exponential for each component minus 1. It is more accurate than Exp(x) - 1 when the component is near zero
WriteWrite vector component data as binary to io.Writer

Example

Below is an example on how to implement the different sign distance field functions in a generic fashion to work for both int8, int16, int32 int, int64, float32, and float64.

The code below produces this output:

out.gif

package main

import (
	"fmt"
	"image"
	"image/color"
	"image/png"
	"math"
	"os"

	"github.com/EliCDavis/vector"
	"github.com/EliCDavis/vector/vector2"
	"github.com/EliCDavis/vector/vector3"
)

type Field[T vector.Number] func(v vector3.Vector[T]) float64

func Sphere[T vector.Number](pos vector3.Vector[T], radius float64) Field[T] {
	return func(v vector3.Vector[T]) float64 {
		return v.Distance(pos) - radius
	}
}

func Box[T vector.Number](pos vector3.Vector[T], bounds vector3.Vector[T]) Field[T] {
	halfBounds := bounds.Scale(0.5)
	// It's best to watch the video to understand
	// https://www.youtube.com/watch?v=62-pRVZuS5c
	return func(v vector3.Vector[T]) float64 {
		q := v.Sub(pos).Abs().Sub(halfBounds)
		inside := math.Min(float64(q.MaxComponent()), 0)
		return vector3.Max(q, vector3.Zero[T]()).Length() + inside
	}
}

func Union[T vector.Number](fields ...Field[T]) Field[T] {
	return func(v vector3.Vector[T]) float64 {
		min := math.MaxFloat64

		for _, f := range fields {
			fv := f(v)
			if fv < min {
				min = fv
			}
		}

		return min
	}
}

func Intersect[T vector.Number](fields ...Field[T]) Field[T] {
	return func(v vector3.Vector[T]) float64 {
		max := -math.MaxFloat64

		for _, f := range fields {
			fv := f(v)
			if fv > max {
				max = fv
			}
		}

		return max
	}
}

func Subtract[T vector.Number](minuend, subtrahend Field[T]) Field[T] {
	return func(f vector3.Vector[T]) float64 {
		return math.Max(minuend(f), -subtrahend(f))
	}
}

func Translate[T vector.Number](field Field[T], translation vector3.Vector[T]) Field[T] {
	return func(v vector3.Vector[T]) float64 {
		return field(v.Sub(translation))
	}
}

func evaluateAtDepth[T vector.Number](dimension int, field Field[T], depth T, i int) {
	img := image.NewRGBA(image.Rectangle{
		image.Point{0, 0},
		image.Point{dimension, dimension},
	})

	for x := 0; x < dimension; x++ {
		for y := 0; y < dimension; y++ {
			v := field(vector3.New[T](T(x), T(y), depth))
			byteVal := (v / float64(dimension/20)) * 255
			var c color.Color
			if v > 0 {
				c = color.RGBA{R: 0, G: 0, B: byte(byteVal), A: 255}
			} else {
				c = color.RGBA{R: 0, G: byte(-byteVal), B: 0, A: 255}
			}
			img.Set(x, y, c)
		}
	}

	f, err := os.Create(fmt.Sprintf("field_%04d.png", i))
	if err != nil {
		panic(err)
	}
	defer f.Close()

	err = png.Encode(f, img)
	if err != nil {
		panic(err)
	}
}

func main() {
	dimension := 512
	quarterDim := float64(dimension) / 4.

	middleCoord := vector2.
		Fill(dimension).
		Scale(0.5).
		ToFloat64()

	middleCord3D := vector3.New(middleCoord.X(), middleCoord.Y(), 0)

	smallRing := Subtract(
		Sphere(middleCord3D, 100),
		Sphere(middleCord3D, 50),
	)

	field := Intersect(
		Subtract(
			Sphere(middleCord3D, 200),
			Sphere(middleCord3D, 100),
		),
		Union(
			Translate(smallRing, vector3.New(1., 1., 0.).Scale(quarterDim)),
			Translate(smallRing, vector3.New(1., -1., 0.).Scale(quarterDim)),
			Translate(smallRing, vector3.New(-1., 1., 0.).Scale(quarterDim)),
			Translate(smallRing, vector3.New(-1., -1., 0.).Scale(quarterDim)),
			Box(middleCord3D, middleCord3D),
		),
	)

	for i := 0; i < 100; i++ {
		evaluateAtDepth(dimension, field, float64(-dimension/2)+(float64(i*dimension)*0.01), i)
	}
}

# Packages

No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author

# Functions

No description provided by the author

# Interfaces

No description provided by the author