Ангел обнови решението на 20.11.2018 22:59 (преди 9 месеца)
+package main
+
+import (
+ "math"
+ "sync"
+
+ "github.com/fmi/go-homework/geom"
+)
+
+type Triangle struct {
+ A, B, C geom.Vector
+}
+
+type Quad struct {
+ A, B, C, D geom.Vector
+}
+
+type Sphere struct {
+ Origin geom.Vector
+ R float64
+}
+
+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,
+ R: r,
+ }
+}
+
+func (tr Triangle) Intersect(ray geom.Ray) bool {
+ // a.k.a Möller–Trumbore intersection algorithm
+ const EPSILON float64 = 0.0000001
+ e1 := Subtract(tr.B, tr.A)
+ e2 := Subtract(tr.C, tr.A)
+ p := CrossProduct(ray.Direction, e2)
+ det := DotProduct(e1, p)
+
+ if det > -EPSILON && det < EPSILON {
+ return false
+ }
+
+ f := 1.0 / det
+ s := Subtract(ray.Origin, tr.A)
+ u := f * DotProduct(s, p)
+
+ if u < 0.0 || u > 1.0 {
+ return false
+ }
+
+ q := CrossProduct(s, e1)
+ v := f * DotProduct(ray.Direction, q)
+
+ if v < 0.0 || u+v > 1.0 {
+ return false
+ }
+ t := f * DotProduct(e2, q)
+
+ return t > EPSILON
+
+}
+
+func (quad Quad) Intersect(ray geom.Ray) bool {
+ // Disclaimer: doesn't work for complex quads :( (had no time to implement "Triangulating")
+ var wg sync.WaitGroup
+ const CNT int = 2
+ ch := make(chan bool, CNT)
+ defer close(ch)
+ for i := 0; i < CNT; i++ {
+ wg.Add(1)
+ go func(i int) {
+ defer wg.Done()
+ var tr Triangle
+ if i == 0 {
+ tr = Triangle{quad.A, quad.B, quad.C}
+ } else {
+ tr = Triangle{quad.A, quad.C, quad.D}
+ }
+ ch <- tr.Intersect(ray)
+ }(i)
+ }
+ wg.Wait()
+
+ return <-ch || <-ch
+}
+
+func (sph Sphere) Intersect(ray geom.Ray) bool {
+ L := Subtract(ray.Origin, sph.Origin)
+ a := DotProduct(ray.Direction, ray.Direction)
+ b := 2 * DotProduct(ray.Direction, L)
+ c := DotProduct(L, L) - math.Pow(sph.R, 2)
+ const SCALE_NUM float64 = 0.01
Най - добре кръсти константата scaleNum
- camelCase и без главна буква. Виж тук. Също така, когато правиш константа типа може да се вземе от стойността ѝ:
const scaleNum = 0.01
+ closeDirectionPoint := Add(ray.Origin, Multiply(ray.Direction, SCALE_NUM))
+ return b*b-4*a*c >= 0 && Distance(sph.Origin, ray.Origin) > Distance(sph.Origin, closeDirectionPoint)
+}
+
+func Distance(a, b geom.Vector) float64 {
+ return math.Sqrt(math.Pow(a.X-b.X, 2) + math.Pow(a.Y-b.Y, 2) + math.Pow(a.Z-b.Z, 2))
+}
+
+func DotProduct(a, b geom.Vector) float64 {
+ return (a.X * b.X) + (a.Y * b.Y) + (a.Z * b.Z)
+}
+
+func CrossProduct(a, b geom.Vector) geom.Vector {
+ return geom.Vector{
+ X: a.Y*b.Z - a.Z*b.Y,
+ Y: a.Z*b.X - a.X*b.Z,
+ Z: a.X*b.Y - a.Y*b.X,
+ }
+}
+
+func Add(a, b geom.Vector) geom.Vector {
+ return geom.Vector{
+ X: a.X + b.X,
+ Y: a.Y + b.Y,
+ Z: a.Z + b.Z,
+ }
+}
+
+func Subtract(a, b geom.Vector) geom.Vector {
+ return geom.Vector{
+ X: a.X - b.X,
+ Y: a.Y - b.Y,
+ Z: a.Z - b.Z,
+ }
+}
+
+func Multiply(a geom.Vector, f float64) geom.Vector {
+ return geom.Vector{
+ X: a.X * f,
+ Y: a.Y * f,
+ Z: a.Z * f,
+ }
+}