Николай обнови решението на 18.11.2018 19:15 (преди 9 месеца)
+package main
+
+import "github.com/fmi/go-homework/geom"
+
+const EPSILON = 0.00001
+
+type Triangle struct {
+ a, b, c geom.Vector
+}
+
+type Quad struct {
+ a, b, c, d geom.Vector
+}
+
+type Sphere struct {
+ origin geom.Vector
+ radius float64
+}
+
+func abs(f float64) float64 {
+ if f < 0 {
+ return -f
+ }
+ return f
+}
+
+func normal(a *geom.Vector, b *geom.Vector) geom.Vector {
+ return geom.NewVector(
+ a.Y*b.Z-a.Z*b.Y,
+ a.Z*b.X-a.X*b.Z,
+ a.X*b.Y-a.Y*b.X,
+ )
+}
+
+func diff(a *geom.Vector, b *geom.Vector) geom.Vector {
+ return geom.NewVector(
+ a.X-b.X,
+ a.Y-b.Y,
+ a.Z-b.Z,
+ )
+}
+
+func scalar(a *geom.Vector, b *geom.Vector) float64 {
+ return a.X*b.X + a.Y*b.Y + a.Z*b.Z
+}
+
+func orthogonal(a *geom.Vector, b *geom.Vector) bool {
+ return abs(scalar(a, b)) < EPSILON
+}
+
+func add(a *geom.Vector, b *geom.Vector) geom.Vector {
+ return geom.NewVector(
+ a.X+b.X,
+ a.Y+b.Y,
+ a.Z+b.Z,
+ )
+}
+
+func mult(t float64, a *geom.Vector) geom.Vector {
+ return geom.NewVector(
+ t*a.X,
+ t*a.Y,
+ t*a.Z,
+ )
+}
+
+func (t Triangle) Intersect(ray geom.Ray) bool {
+ v1 := diff(&t.b, &t.a)
+ v2 := diff(&t.c, &t.a)
+ n := normal(&v1, &v2)
+ d := scalar(&n, &t.a)
+
+ if orthogonal(&ray.Direction, &n) {
+ // check if ray is outside the plane
+ if abs(scalar(&n, &ray.Origin)-d) >= EPSILON {
+ return false
+ }
+
+ // TODO: check if ray crosses triangle
+ return false
+ } else {
+ // compute intersection point
+ param := (d - scalar(&n, &ray.Origin)) / scalar(&n, &ray.Direction)
+
+ if param < 0 {
+ // ray is pointing away
+ return false
+ }
+
+ tmp := mult(param, &ray.Direction) // thank you golang
+ intersection := add(&ray.Origin, &tmp)
+ v3 := diff(&intersection, &t.a)
+
+ // compute dot products
+ dot11 := scalar(&v1, &v1)
+ dot12 := scalar(&v1, &v2)
+ dot13 := scalar(&v1, &v3)
+ dot22 := scalar(&v2, &v2)
+ dot23 := scalar(&v2, &v3)
+
+ // compute barycentric coordinates
+ inv_denom := 1 / (dot11*dot22 - dot12*dot12)
+ u := (dot22*dot13 - dot12*dot23) * inv_denom
+ v := (dot11*dot23 - dot12*dot13) * inv_denom
+
+ // check if point is in triangle
+ return u >= 0 && v >= 0 && (u+v) <= 1
+ }
+}
+
+func (q Quad) Intersect(ray geom.Ray) bool {
+ t1 := NewTriangle(q.a, q.b, q.c)
+ t2 := NewTriangle(q.a, q.c, q.d)
+ t3 := NewTriangle(q.a, q.b, q.d)
+ return t1.Intersect(ray) || t2.Intersect(ray) || t3.Intersect(ray)
+}
+
+func (s Sphere) Intersect(ray geom.Ray) bool {
+ v := diff(&s.origin, &ray.Origin)
+
+ // check if the ray starts from the sphere
+ if scalar(&v, &v) <= s.radius*s.radius {
+ return true
+ }
+
+ t := scalar(&v, &ray.Direction) / scalar(&ray.Direction, &ray.Direction)
+
+ if t < 0 {
+ // ray is pointing away
+ return false
+ }
+
+ tmp := mult(t, &ray.Direction) // thank you golang
+ projection := add(&ray.Origin, &tmp)
+
+ d := diff(&projection, &s.origin)
+ distance_squared := scalar(&d, &d)
+
+ return distance_squared <= s.radius*s.radius
+}
+
+func NewTriangle(a, b, c geom.Vector) Triangle {
+ return Triangle{
+ a: a,
+ b: b,
+ c: c,
+ }
+}
+
+func NewQuad(a, b, c, d geom.Vector) Quad {
+ return Quad{
+ a: a,
+ b: b,
+ c: c,
+ d: d,
+ }
+}
+
+func NewSphere(origin geom.Vector, r float64) Sphere {
+ return Sphere{
+ origin: origin,
+ radius: r,
+ }
+}