Красена обнови решението на 21.11.2018 12:55 (преди 9 месеца)
+package main
+
+import (
+ "github.com/fmi/go-homework/geom"
+ "math"
+)
+
+type Triangle struct {
+ a, b, c geom.Vector
+}
+
+type Sphere struct {
+ centre geom.Vector
+ radius float64
+}
+
+type Quad struct {
+ a, b, c, d geom.Vector
+}
+
+func NewTriangle(x, y, z geom.Vector) Triangle {
+ return Triangle{a: x, b: y, c: z}
+}
+
+func NewSphere(origin geom.Vector, r float64) Sphere {
+ return Sphere{centre: origin, radius: r}
+}
+
+func NewQuad(x, y, z, t geom.Vector) Quad {
+ return Quad{a: x, b: y, c: z, d: t}
+}
+
+func vectorsTri(t Triangle, c chan<- geom.Vector) {
+ defer close(c)
+ ab := vectorOp(t.a, t.b, func(x, y float64) float64 { return y - x })
+ ac := vectorOp(t.a, t.c, func(x, y float64) float64 { return y - x })
+ bc := vectorOp(t.b, t.c, func(x, y float64) float64 { return y - x })
+ ca := vectorOp(t.c, t.a, func(x, y float64) float64 { return y - x })
+ c <- ab
+ c <- ac
+ c <- bc
+ c <- ca
+}
+
+func (t Triangle) Intersect(ray geom.Ray) bool {
+ channel := make(chan geom.Vector, 4)
+ go vectorsTri(t, channel)
+ ab, ac, bc, ca := <-channel, <-channel, <-channel, <-channel
+ norm := crossProd(ab, ac)
+ sqrtNorm := math.Sqrt(vectorSum(vectorOp(norm, norm, func(x, y float64) float64 { return x * y })))
+ norm = geom.NewVector(norm.X/sqrtNorm, norm.Y/sqrtNorm, norm.Z/sqrtNorm)
+ d := vectorSum(vectorOp(norm, t.a, func(x, y float64) float64 { return x * y }))
+ normDir := vectorSum(vectorOp(norm, ray.Direction, func(x, y float64) float64 { return x * y }))
+ normOr := vectorSum(vectorOp(norm, ray.Origin, func(x, y float64) float64 { return x * y }))
+ if normDir == 0 { // ray is parallel to the plane
+ return false
+ }
+ solv := (d - normOr) / normDir
+ inPnt := vectorOp(ray.Origin, ray.Direction, func(x, y float64) float64 {
+ return func(p float64) float64 {
+ return x + y*p
+ }(solv)
+ })
+ ainPnt := vectorOp(t.a, inPnt, func(x, y float64) float64 { return y - x })
+ binPnt := vectorOp(t.b, inPnt, func(x, y float64) float64 { return y - x })
+ cinPnt := vectorOp(t.c, inPnt, func(x, y float64) float64 { return y - x })
+ condAB := vectorSum(vectorOp(crossProd(ab, ainPnt), norm, func(x, y float64) float64 { return x * y }))
+ condBC := vectorSum(vectorOp(crossProd(bc, binPnt), norm, func(x, y float64) float64 { return x * y }))
+ condCA := vectorSum(vectorOp(crossProd(ca, cinPnt), norm, func(x, y float64) float64 { return x * y }))
+ if condAB >= 0 && condBC >= 0 && condCA >= 0 {
+ return true
+ } else {
+ return false
+ }
+}
+
+func (s Sphere) Intersect(ray geom.Ray) bool {
+ oc := vectorOp(ray.Origin, s.centre, func(x, y float64) float64 { return y - x })
+ c := vectorSum(vectorOp(oc, oc, func(x, y float64) float64 { return x * y })) - s.radius*s.radius
+ b := vectorSum(vectorOp(ray.Direction, oc, func(x, y float64) float64 { return x * y })) * 2
+ a := vectorSum(vectorOp(ray.Direction, ray.Direction, func(x, y float64) float64 { return x * y }))
+ d := b*b - 4*a*c
+ if d >= 0 {
+ return true
+ } else {
+ return false
+ }
+}
+
+func degree(x, y geom.Vector) float64 {
+ xy := vectorSum(vectorOp(x, y, func(x, y float64) float64 { return x * y }))
+ xd := math.Sqrt(vectorSum(vectorOp(x, x, func(x, y float64) float64 { return x * y })))
+ yd := math.Sqrt(vectorSum(vectorOp(y, y, func(x, y float64) float64 { return x * y })))
+ return math.Acos(xy/(xd*yd)) * 180 / math.Pi
+}
+
+func vectorsQuad(q Quad, c chan<- geom.Vector) {
+ defer close(c)
+ ba := vectorOp(q.b, q.a, func(x, y float64) float64 { return y - x })
+ bc := vectorOp(q.b, q.c, func(x, y float64) float64 { return y - x })
+ cb := vectorOp(q.c, q.b, func(x, y float64) float64 { return y - x })
+ cd := vectorOp(q.c, q.d, func(x, y float64) float64 { return y - x })
+ dc := vectorOp(q.d, q.c, func(x, y float64) float64 { return y - x })
+ da := vectorOp(q.d, q.a, func(x, y float64) float64 { return y - x })
+ ad := vectorOp(q.a, q.d, func(x, y float64) float64 { return y - x })
+ ab := vectorOp(q.a, q.b, func(x, y float64) float64 { return y - x })
+ c <- ba
+ c <- bc
+ c <- cb
+ c <- cd
+ c <- dc
+ c <- da
+ c <- ad
+ c <- ab
+
+}
+
+func (q Quad) Intersect(ray geom.Ray) bool {
+ channel := make(chan geom.Vector, 8)
+ go vectorsQuad(q, channel)
+ ba, bc, cb, cd, dc, da, ad, ab := <-channel, <-channel, <-channel, <-channel, <-channel, <-channel, <-channel, <-channel
+ a := degree(ad, ab)
+ b := degree(ba, bc)
+ c := degree(cb, cd)
+ d := degree(dc, da)
+ var fst, snd Triangle
+ if c >= 90 || a >= 90 {
+ fst = NewTriangle(q.a, q.b, q.c)
+ snd = NewTriangle(q.a, q.d, q.c)
+ } else if b >= 90 || d >= 90 {
+ fst = NewTriangle(q.a, q.b, q.d)
+ snd = NewTriangle(q.b, q.c, q.d)
+ }
+ if fst.Intersect(ray) || snd.Intersect(ray) {
+ return true
+ } else {
+ return false
+ }
+}
+
+func crossProd(fst, snd geom.Vector) geom.Vector {
+ return geom.NewVector(fst.Y*snd.Z-fst.Z*snd.Y, fst.Z*snd.X-fst.X*snd.Z, fst.X*snd.Y-fst.Y*snd.X)
+}
+
+func vectorOp(fst, snd geom.Vector, op func(x, y float64) float64) geom.Vector {
+ return geom.NewVector(op(fst.X, snd.X), op(fst.Y, snd.Y), op(fst.Z, snd.Z))
+}
+
+func vectorSum(fst geom.Vector) float64 {
+ return fst.X + fst.Y + fst.Z
+}