diff --git a/go.mod b/go.mod index 57bbf2b..2458990 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,4 @@ module github.com/zealsham/raytrace go 1.15 -require ( - github.com/stretchr/testify v1.7.0 - -) \ No newline at end of file +require github.com/stretchr/testify v1.7.0 diff --git a/go.sum b/go.sum index acaf484..7b4dc41 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,11 @@ +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/main.go b/main.go new file mode 100644 index 0000000..1262ea3 --- /dev/null +++ b/main.go @@ -0,0 +1,9 @@ +package main + +import "github.com/zealsham/raytrace/shows" + +func main() { + + shows.Run() + +} diff --git a/shows/projectile.go b/shows/projectile.go new file mode 100644 index 0000000..9208646 --- /dev/null +++ b/shows/projectile.go @@ -0,0 +1,34 @@ +package shows + +import ( + "fmt" + + "github.com/zealsham/raytrace/tuple" +) + +type projectile struct { + position tuple.Tuple + velocity tuple.Tuple +} + +type enviroment struct { + gravity tuple.Tuple + wind tuple.Tuple +} + +func tick(env enviroment, proj projectile) projectile { + pos := tuple.AddTuple(proj.position, proj.velocity) + velocity := tuple.AddTuple(proj.velocity, tuple.AddTuple(env.gravity, env.wind)) + return projectile{pos, velocity} +} + +func Run() { + p := projectile{tuple.Point(0, 1, 0), tuple.NormalizeTuple(tuple.Vector(1, 1, 0))} + e := enviroment{tuple.Vector(0, -0.1, 0), tuple.Vector(-0.01, 0, 0)} + for i := 0; p.position.Y >= 0; i++ { + fmt.Printf("Position after tick %d: is x=%4.2f , y=%4.2f, z=%4.2f \n", i, p.position.X, p.position.Y, p.position.Z) + + p = tick(e, p) + } + +} diff --git a/tuple/tuple.go b/tuple/tuple.go new file mode 100644 index 0000000..ee9a78a --- /dev/null +++ b/tuple/tuple.go @@ -0,0 +1,89 @@ +package tuple + +import "math" + +//addresses floating point number comparaison computers have + +const EPSILON = 10e-6 + +type Tuple struct { + X float64 + Y float64 + Z float64 + W float64 +} + +func Point(x, y, z float64) Tuple { + return Tuple{X: x, Y: y, Z: z, W: 1.0} +} + +func Vector(x, y, z float64) Tuple { + return Tuple{X: x, Y: y, Z: z, W: 0.0} +} + +func IsVector(tup Tuple) bool { + return Equal(tup.W, 0.0) +} + +func IsPoint(tup Tuple) bool { + return Equal(tup.W, 1.0) +} + +func EqualTuple(tup1 Tuple, tup2 Tuple) bool { + return (Equal(tup1.X, tup2.X) && Equal(tup1.Y, tup2.Y) && Equal(tup1.Z, tup2.Z) && Equal(tup1.W, tup2.W)) +} +func AddTuple(tup1 Tuple, tup2 Tuple) Tuple { + //shows the new location if you followd tup2 from tup1 + return Tuple{tup1.X + tup2.X, tup1.Y + tup2.Y, tup1.Z + tup2.Z, tup1.W + tup2.W} +} + +func SubTuple(tup1 Tuple, tup2 Tuple) Tuple { + //basically moving backward by the given vector + return Tuple{tup1.X - tup2.X, tup1.Y - tup2.Y, tup1.Z - tup2.Z, tup1.W - tup2.W} +} + +func Equal(a, b float64) bool { + return math.Abs(a-b) < EPSILON +} + +func NegTuple(tup Tuple) Tuple { + // the opposite vector + return Tuple{-tup.X, -tup.Y, -tup.Z, -tup.W} +} + +func MultTuple(scalar float64, tup Tuple) Tuple { + //determines the point scalar times ahead of the vector + return Tuple{scalar * tup.X, scalar * tup.Y, scalar * tup.Z, scalar * tup.W} +} + +func DivTuple(divider float64, tup Tuple) Tuple { + return Tuple{tup.X / divider, tup.Y / divider, tup.Z / divider, tup.W / divider} +} + +func MagnitudeTuple(tup Tuple) float64 { + // the total distance covered by a vector + x := math.Pow(tup.X, 2) + y := math.Pow(tup.Y, 2) + z := math.Pow(tup.Z, 2) + w := math.Pow(tup.W, 2) + magnitude := math.Sqrt(x + y + z + w) + return magnitude +} + +func NormalizeTuple(tup Tuple) Tuple { + // transforms a vector into a unit vector + return Tuple{tup.X / MagnitudeTuple(tup), tup.Y / MagnitudeTuple(tup), tup.Z / MagnitudeTuple(tup), tup.W / MagnitudeTuple(tup)} +} + +func DotProduct(tup1 Tuple, tup2 Tuple) float64 { + result := (tup1.X * tup2.X) + (tup1.Y * tup2.Y) + (tup1.Z * tup2.Z) + (tup1.W * tup2.W) + return result + +} +func CrossProduct(tup1, tup2 Tuple) Tuple { + x := tup1.Y*tup2.Z - tup1.Z*tup2.Y + y := tup1.Z*tup2.X - tup1.X*tup2.Z + z := tup1.X*tup2.Y - tup1.Y*tup2.X + + return Vector(x, y, z) +} diff --git a/tuple/tuple_test.go b/tuple/tuple_test.go new file mode 100644 index 0000000..af0abb2 --- /dev/null +++ b/tuple/tuple_test.go @@ -0,0 +1,150 @@ +package tuple + +import ( + "math" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestVectorCreation(t *testing.T) { + data := Vector(1, 2, 4) + expected := Tuple{1, 2, 4, 0} + + assert.Equal(t, data, expected, "should be equal") +} + +func TestPointCreation(t *testing.T) { + data := Point(1, 3, 6) + expected := Tuple{1, 3, 6, 1.0} + + assert.Equal(t, data, expected, "should be equal") +} +func TestPoint(t *testing.T) { + point := Tuple{4.3, -4.2, 3.1, 1.0} + + assert := assert.New(t) + + assert.Equal(point.X, 4.3, "they should be equal") + assert.Equal(point.Y, -4.2, "they should be equal") + assert.Equal(point.Z, 3.1, "they should be equal") + assert.Equal(point.W, 1.0, "they should be equal") + assert.Equal(IsPoint(point), true, "should return true if it's a point") + assert.Equal(IsVector(point), false, "a point isnt a vector") + +} + +func TestVector(t *testing.T) { + vector := Tuple{4.3, -4.2, 3.1, 0.0} + assert := assert.New(t) + assert.Equal(vector.X, 4.3, "should be equal") + assert.Equal(vector.Y, -4.2, "should be eqaul") + assert.Equal(vector.Z, 3.1, "should be equal") + assert.Equal(vector.W, 0.0, "should be equal") + assert.Equal(IsPoint(vector), false, "a vector isnt a point") + assert.Equal(IsVector(vector), true, "should be true if it's a vector") +} + +func TestEqualTuple(t *testing.T) { + tup1 := Tuple{1.2, 3.2, 2.1, 0.0} + tup2 := Tuple{1.2, 3.2, 2.1, 0.0} + tup3 := Tuple{1.2, 3.2, 2.1, 1.0} + assert := assert.New(t) + assert.Equal(EqualTuple(tup1, tup2), true, "the two should be equal") + assert.Equal(EqualTuple(tup2, tup3), false, "they shoudn't be equal in this case") + +} + +func TestAddTuple(t *testing.T) { + tup1 := Tuple{3, -2, 5, 1} + tup2 := Tuple{-2, 3, 1, 0} + expected := Tuple{1, 1, 6, 1} + + assert := assert.New(t) + assert.Equal(AddTuple(tup1, tup2), expected, "should be equal") +} + +func TestSubtractTuple(t *testing.T) { + tup1 := Tuple{3, 2, 1, 1} + tup2 := Tuple{5, 6, 7, 1} + expected := Tuple{-2, -4, -6, 0} + testCaseVector := Tuple{2, 4, 5, 0} + + assert := assert.New(t) + assert.Equal(SubTuple(tup1, tup2), expected, "should be equal") + assert.Equal(IsVector(SubTuple(tup1, tup2)), true, "subtracting point from point should return a vector") + assert.Equal(IsPoint(SubTuple(tup1, expected)), true, "subtracting a vector from point should return a point") + assert.Equal(IsVector(SubTuple(expected, testCaseVector)), true, "subtracting two vector should return a new vector") +} + +func TestNegateTuple(t *testing.T) { + tup := Tuple{1, -2, 3, -4} + expected := Tuple{-1, 2, -3, 4} + + assert.Equal(t, NegTuple(tup), expected, "should be equal to the expected") +} + +func TestMultTuple(t *testing.T) { + tup := Tuple{1, -2, 3, -4} + scalar := 3.5 + + //a * tuple should be + expected := Tuple{3.5, -7, 10.5, -14} + + assert.Equal(t, MultTuple(scalar, tup), expected, "should be equal") +} + +func TestDivTuple(t *testing.T) { + tup := Tuple{1, -2, 3, -4} + scalar := 2.0 + expected := Tuple{0.5, -1, 1.5, -2} + + assert.Equal(t, DivTuple(scalar, tup), expected, "should be equal") +} +func TestMagniVector(t *testing.T) { + testdata := []Tuple{{0, 1, 0, 0}, {0, 0, 1, 0}, {1, 2, 3, 0}, {-1, -2, -3, 0}} + expected := []float64{1, 1, math.Sqrt(14), math.Sqrt(14)} + + assert := assert.New(t) + + for i, v := range testdata { + assert.Equal(Equal(MagnitudeTuple(v), expected[i]), true, "should be equal to") + } +} + +func TestNormVector(t *testing.T) { + + //my insticts tells me this can be done in a better way, currently just have a one day experience using + //tesitfy library, maybe as i gain mor experience i'll figure a better way out + testdata := []Tuple{{4, 0, 0, 0}, {1, 2, 3, 0}} + expected := []Tuple{{1, 0, 0, 0}, {0.26726, 0.53452, 0.80178, 0}} + magcalls := []Tuple{NormalizeTuple(testdata[0]), NormalizeTuple(testdata[1])} + + assert := assert.New(t) + + for i, v := range expected { + assert.Equal(Equal(v.X, magcalls[i].X), true, "should be equal") + assert.Equal(Equal(v.Y, magcalls[i].Y), true, "should be equal") + assert.Equal(Equal(v.Z, magcalls[i].Z), true, "should be equal") + assert.Equal(Equal(v.W, magcalls[i].W), true, "should be equal") + assert.Equal(Equal(MagnitudeTuple(magcalls[i]), 1.0), true, "should be equal") + } + +} +func TestDot(t *testing.T) { + testdata1 := Tuple{1, 2, 3, 0} + testdata2 := Tuple{2, 3, 4, 0} + expected := 20.0 + + assert.Equal(t, DotProduct(testdata1, testdata2), expected, "should return the correct float") +} +func TestCross(t *testing.T) { + a := Tuple{1, 2, 3, 0} + b := Tuple{2, 3, 4, 0} + crossAB := Tuple{-1, 2, -1, 0} + crossBA := Tuple{1, -2, 1, 0} + assert := assert.New(t) + assert.Equal(CrossProduct(a, b), crossAB, "should be equal") + assert.Equal(CrossProduct(b, a), crossBA, "should be equal") + +}