Решение на Пресичания от Йоан Петров

Обратно към всички решения

Към профила на Йоан Петров

Резултати

  • 8 точки от тестове
  • 0 бонус точки
  • 8 точки общо
  • 15 успешни тест(а)
  • 5 неуспешни тест(а)

Код

package main
import (
"github.com/fmi/go-homework/geom"
"math"
)
type Triangle struct {
A, B, C geom.Vector
}
func NewTriangle(a, b, c geom.Vector) Triangle {
return Triangle{A: a, B: b, C: c}
}
func (tr Triangle) Intersect(ray geom.Ray) bool {
BminusA := Subtract(tr.B, tr.A)
CminusA := Subtract(tr.C, tr.A)
n := Cross(BminusA, CminusA)
n = Multiply(n, 1/(math.Sqrt(Dot(n, n))))
d := Dot(n, tr.A)
nP := Dot(n, ray.Origin)
nd := Dot(n, ray.Direction)
t := (d - nP) / nd
Q := Add(ray.Origin, Multiply(ray.Direction, t))
QminusA := Subtract(Q, tr.A)
CminusB := Subtract(tr.C, tr.B)
QminusB := Subtract(Q, tr.B)
AminusC := Subtract(tr.A, tr.C)
QminusC := Subtract(Q, tr.C)
epsilon := 1e-7
if Dot(Cross(BminusA, QminusA), n) >= 0-epsilon && Dot(Cross(CminusB, QminusB), n) >= 0-epsilon && Dot(Cross(AminusC, QminusC), n) >= 0-epsilon ||
Dot(Cross(BminusA, QminusA), n) <= 0+epsilon && Dot(Cross(CminusB, QminusB), n) <= 0+epsilon && Dot(Cross(AminusC, QminusC), n) <= 0+epsilon {
return true
}
return false
}
func Multiply(v geom.Vector, n float64) geom.Vector {
return geom.NewVector(v.X*n, v.Y*n, v.Z*n)
}
func Subtract(a, b geom.Vector) geom.Vector {
return geom.NewVector(a.X-b.X, a.Y-b.Y, a.Z-b.Z)
}
func Add(a, b geom.Vector) geom.Vector {
return geom.NewVector(a.X+b.X, a.Y+b.Y, a.Z+b.Z)
}
func Dot(a, b geom.Vector) float64 {
return a.X*b.X + a.Y*b.Y + a.Z*b.Z
}
func Cross(a, 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)
}
type Quad struct {
A, B, C, D geom.Vector
}
func NewQuad(a, b, c, d geom.Vector) Quad {
return Quad{A: a, B: b, C: c, D: d}
}
func Area(tr Triangle) float64 {
A, B, C := tr.A, tr.B, tr.C
S := math.Sqrt(Dot(Cross(Subtract(B, A), Subtract(C, A)), Cross(Subtract(B, A), Subtract(C, A)))) / 2
return S
}
func (qa Quad) Intersect(ray geom.Ray) bool {
A, B, C, D := qa.A, qa.B, qa.C, qa.D
tr1 := NewTriangle(A, B, C)
tr2 := NewTriangle(C, D, A)
tr3 := NewTriangle(B, C, D)
tr4 := NewTriangle(D, A, B)
if Area(tr1)+Area(tr2) <= Area(tr3)+Area(tr4) {
if tr1.Intersect(ray) || tr2.Intersect(ray) {
return true
}
} else {
if tr3.Intersect(ray) || tr4.Intersect(ray) {
return true
}
}
return false
}
type Sphere struct {
O geom.Vector
R float64
}
func NewSphere(origin geom.Vector, r float64) Sphere {
return Sphere{O: origin, R: r}
}
func (sp Sphere) Intersect(ray geom.Ray) bool {
Q := Subtract(ray.Origin, sp.O)
a := Dot(ray.Direction, ray.Direction)
b := 2 * Dot(ray.Direction, Q)
c := Dot(Q, Q) - sp.R*sp.R
d := b*b - 4*a*c
epsilon := 1e-7
if d >= 0-epsilon {
return true
}
return false
}

Лог от изпълнението

PASS
ok  	_/tmp/d20181122-57-1jghsx0	0.002s
PASS
ok  	_/tmp/d20181122-57-1jghsx0	0.002s
--- FAIL: TestTriangleRayOppositeDirection (0.00s)
    solution_test.go:206: Expected intersection to be false but it was not
FAIL
exit status 1
FAIL	_/tmp/d20181122-57-1jghsx0	0.002s
PASS
ok  	_/tmp/d20181122-57-1jghsx0	0.002s
PASS
ok  	_/tmp/d20181122-57-1jghsx0	0.002s
--- FAIL: TestTriangleRayOriginReallyCloseToObject (0.00s)
    solution_test.go:206: Expected intersection to be false but it was not
FAIL
exit status 1
FAIL	_/tmp/d20181122-57-1jghsx0	0.002s
PASS
ok  	_/tmp/d20181122-57-1jghsx0	0.002s
PASS
ok  	_/tmp/d20181122-57-1jghsx0	0.002s
--- FAIL: TestQuadRayOppositeDirection (0.00s)
    solution_test.go:206: Expected intersection to be false but it was not
FAIL
exit status 1
FAIL	_/tmp/d20181122-57-1jghsx0	0.003s
PASS
ok  	_/tmp/d20181122-57-1jghsx0	0.002s
PASS
ok  	_/tmp/d20181122-57-1jghsx0	0.002s
--- FAIL: TestQuadOriginReallyClosedToObject (0.00s)
    solution_test.go:206: Expected intersection to be false but it was not
FAIL
exit status 1
FAIL	_/tmp/d20181122-57-1jghsx0	0.003s
PASS
ok  	_/tmp/d20181122-57-1jghsx0	0.002s
PASS
ok  	_/tmp/d20181122-57-1jghsx0	0.002s
PASS
ok  	_/tmp/d20181122-57-1jghsx0	0.002s
PASS
ok  	_/tmp/d20181122-57-1jghsx0	0.002s
PASS
ok  	_/tmp/d20181122-57-1jghsx0	0.002s
PASS
ok  	_/tmp/d20181122-57-1jghsx0	0.002s
--- FAIL: TestSphereRayOppositeDirection (0.00s)
    solution_test.go:206: Expected intersection to be false but it was not
FAIL
exit status 1
FAIL	_/tmp/d20181122-57-1jghsx0	0.002s
PASS
ok  	_/tmp/d20181122-57-1jghsx0	0.002s

История (4 версии и 1 коментар)

Йоан обнови решението на 18.11.2018 12:26 (преди 9 месеца)

+package main
+
+import (
+ "github.com/fmi/go-homework/geom"
+ "math"
+)
+
+type Triangle struct {
+ A, B, C geom.Vector
+}
+
+func NewTriangle(a, b, c geom.Vector) Triangle {
+ return Triangle{A: a, B: b, C: c}
+}
+
+func (tr Triangle) Intersect(ray geom.Ray) bool {
+ if (ray.Origin.X <= math.Min(tr.A.X, math.Min(tr.B.X, tr.C.X)) && ray.Direction.X >= math.Max(tr.A.X, math.Max(tr.B.X, tr.C.X)) ||
+ ray.Origin.X >= math.Min(tr.A.X, math.Min(tr.B.X, tr.C.X)) && ray.Direction.X <= math.Max(tr.A.X, math.Max(tr.B.X, tr.C.X))) &&
+ (ray.Origin.X <= math.Min(tr.A.Y, math.Min(tr.B.Y, tr.C.Y)) && ray.Direction.X >= math.Max(tr.A.Y, math.Max(tr.B.Y, tr.C.Y)) ||
+ ray.Origin.X >= math.Min(tr.A.Y, math.Min(tr.B.Y, tr.C.Y)) && ray.Direction.X <= math.Max(tr.A.Y, math.Max(tr.B.Y, tr.C.Y))) &&
+ (ray.Origin.X <= math.Min(tr.A.Z, math.Min(tr.B.Z, tr.C.Z)) && ray.Direction.X >= math.Max(tr.A.Z, math.Max(tr.B.Z, tr.C.Z)) ||
+ ray.Origin.X >= math.Min(tr.A.Z, math.Min(tr.B.Z, tr.C.Z)) && ray.Direction.X <= math.Max(tr.A.Z, math.Max(tr.B.Z, tr.C.Z))) {
+ return true
+ }
+ return false
+}
+
+type Quad struct {
+ A, B, C, D geom.Vector
+}
+
+func NewQuad(a, b, c, d geom.Vector) Quad {
+ return Quad{A: a, B: b, C: c, D: d}
+}
+
+func (qa Quad) Intersect(ray geom.Ray) bool {
+ if (ray.Origin.X <= math.Min(qa.A.X, math.Min(qa.B.X, math.Min(qa.C.X, qa.D.X))) && ray.Direction.X >= math.Max(qa.A.X, math.Max(qa.B.X, math.Max(qa.C.X, qa.D.X))) ||
+ ray.Origin.X >= math.Min(qa.A.X, math.Min(qa.B.X, math.Min(qa.C.X, qa.D.X))) && ray.Direction.X <= math.Max(qa.A.X, math.Max(qa.B.X, math.Max(qa.C.X, qa.D.X)))) &&
+ (ray.Origin.X <= math.Min(qa.A.Y, math.Min(qa.B.Y, math.Min(qa.C.Y, qa.D.Y))) && ray.Direction.X >= math.Max(qa.A.Y, math.Max(qa.B.Y, math.Max(qa.C.Y, qa.D.Y))) ||
+ ray.Origin.X >= math.Min(qa.A.Y, math.Min(qa.B.Y, math.Min(qa.C.Y, qa.D.Y))) && ray.Direction.X <= math.Max(qa.A.Y, math.Max(qa.B.Y, math.Max(qa.C.Y, qa.D.Y)))) &&
+ (ray.Origin.X <= math.Min(qa.A.Z, math.Min(qa.B.Z, math.Min(qa.C.Z, qa.D.Z))) && ray.Direction.X >= math.Max(qa.A.Z, math.Max(qa.B.Z, math.Max(qa.C.Z, qa.D.Z))) ||
+ ray.Origin.X >= math.Min(qa.A.Z, math.Min(qa.B.Z, math.Min(qa.C.Z, qa.D.Z))) && ray.Direction.X <= math.Max(qa.A.Z, math.Max(qa.B.Z, math.Max(qa.C.Z, qa.D.Z)))) {
+ return true
+ }
+ return false
+}
+
+type Sphere struct {
+ O geom.Vector
+ R float64
+}
+
+func NewSphere(origin geom.Vector, r float64) Sphere {
+ return Sphere{O: origin, R: r}
+}
+
+func (sp Sphere) Intersect(ray geom.Ray) bool {
+ if (ray.Origin.X <= sp.O.X-sp.R && ray.Direction.X >= sp.O.X-sp.R || ray.Origin.X >= sp.O.X-sp.R && ray.Direction.X <= sp.O.X-sp.R) &&
+ (ray.Origin.Y <= sp.O.Y-sp.R && ray.Direction.Y >= sp.O.Y-sp.R || ray.Origin.Y >= sp.O.Y-sp.R && ray.Direction.Y <= sp.O.Y-sp.R) &&
+ (ray.Origin.Z <= sp.O.Z-sp.R && ray.Direction.Z >= sp.O.Z-sp.R || ray.Origin.Z >= sp.O.Z-sp.R && ray.Direction.Z <= sp.O.Z-sp.R) {
+ return true
+ }
+ return false
+}

Йоан обнови решението на 19.11.2018 23:06 (преди 9 месеца)

package main
-import (
- "github.com/fmi/go-homework/geom"
- "math"
-)
+import "github.com/fmi/go-homework/geom"
type Triangle struct {
A, B, C geom.Vector
}
func NewTriangle(a, b, c geom.Vector) Triangle {
return Triangle{A: a, B: b, C: c}
}
func (tr Triangle) Intersect(ray geom.Ray) bool {
- if (ray.Origin.X <= math.Min(tr.A.X, math.Min(tr.B.X, tr.C.X)) && ray.Direction.X >= math.Max(tr.A.X, math.Max(tr.B.X, tr.C.X)) ||
- ray.Origin.X >= math.Min(tr.A.X, math.Min(tr.B.X, tr.C.X)) && ray.Direction.X <= math.Max(tr.A.X, math.Max(tr.B.X, tr.C.X))) &&
- (ray.Origin.X <= math.Min(tr.A.Y, math.Min(tr.B.Y, tr.C.Y)) && ray.Direction.X >= math.Max(tr.A.Y, math.Max(tr.B.Y, tr.C.Y)) ||
- ray.Origin.X >= math.Min(tr.A.Y, math.Min(tr.B.Y, tr.C.Y)) && ray.Direction.X <= math.Max(tr.A.Y, math.Max(tr.B.Y, tr.C.Y))) &&
- (ray.Origin.X <= math.Min(tr.A.Z, math.Min(tr.B.Z, tr.C.Z)) && ray.Direction.X >= math.Max(tr.A.Z, math.Max(tr.B.Z, tr.C.Z)) ||
- ray.Origin.X >= math.Min(tr.A.Z, math.Min(tr.B.Z, tr.C.Z)) && ray.Direction.X <= math.Max(tr.A.Z, math.Max(tr.B.Z, tr.C.Z))) {
+ BminusA := Subtract(tr.B, tr.A)
+ CminusA := Subtract(tr.C, tr.A)
+ n := Cross(BminusA, CminusA)
+ d := Dot(n, tr.A)
+ nP := Dot(n, ray.Origin)
+ nd := Dot(n, ray.Direction)
+ t := (d - nP) / nd
+ Q := geom.NewVector(t*ray.Direction.X, t*ray.Direction.Y, t*ray.Direction.Z)
+ QminusA := Subtract(Q, tr.A)
+ CminusB := Subtract(tr.C, tr.B)
+ QminusB := Subtract(Q, tr.B)
+ AminusC := Subtract(tr.A, tr.C)
+ QminusC := Subtract(Q, tr.C)
+ if Dot(Cross(BminusA, QminusA), n) >= 0 && Dot(Cross(CminusB, QminusB), n) >= 0 && Dot(Cross(AminusC, QminusC), n) >= 0 ||
+ Dot(Cross(BminusA, QminusA), n) <= 0 && Dot(Cross(CminusB, QminusB), n) <= 0 && Dot(Cross(AminusC, QminusC), n) <= 0 {
return true
}
return false
}
+func Subtract(a, b geom.Vector) geom.Vector {
+ return geom.NewVector(a.X-b.X, a.Y-b.Y, a.Z-b.Z)
+}
+
+func Dot(a, b geom.Vector) float64 {
+ return a.X*b.X + a.Y*b.Y + a.Z*b.Z
+}
+
+func Cross(a, 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)
+}
+
type Quad struct {
A, B, C, D geom.Vector
}
func NewQuad(a, b, c, d geom.Vector) Quad {
return Quad{A: a, B: b, C: c, D: d}
}
func (qa Quad) Intersect(ray geom.Ray) bool {
- if (ray.Origin.X <= math.Min(qa.A.X, math.Min(qa.B.X, math.Min(qa.C.X, qa.D.X))) && ray.Direction.X >= math.Max(qa.A.X, math.Max(qa.B.X, math.Max(qa.C.X, qa.D.X))) ||
- ray.Origin.X >= math.Min(qa.A.X, math.Min(qa.B.X, math.Min(qa.C.X, qa.D.X))) && ray.Direction.X <= math.Max(qa.A.X, math.Max(qa.B.X, math.Max(qa.C.X, qa.D.X)))) &&
- (ray.Origin.X <= math.Min(qa.A.Y, math.Min(qa.B.Y, math.Min(qa.C.Y, qa.D.Y))) && ray.Direction.X >= math.Max(qa.A.Y, math.Max(qa.B.Y, math.Max(qa.C.Y, qa.D.Y))) ||
- ray.Origin.X >= math.Min(qa.A.Y, math.Min(qa.B.Y, math.Min(qa.C.Y, qa.D.Y))) && ray.Direction.X <= math.Max(qa.A.Y, math.Max(qa.B.Y, math.Max(qa.C.Y, qa.D.Y)))) &&
- (ray.Origin.X <= math.Min(qa.A.Z, math.Min(qa.B.Z, math.Min(qa.C.Z, qa.D.Z))) && ray.Direction.X >= math.Max(qa.A.Z, math.Max(qa.B.Z, math.Max(qa.C.Z, qa.D.Z))) ||
- ray.Origin.X >= math.Min(qa.A.Z, math.Min(qa.B.Z, math.Min(qa.C.Z, qa.D.Z))) && ray.Direction.X <= math.Max(qa.A.Z, math.Max(qa.B.Z, math.Max(qa.C.Z, qa.D.Z)))) {
+ tr1 := NewTriangle(qa.A, qa.B, qa.C)
+ tr2 := NewTriangle(qa.C, qa.D, qa.A)
+ if tr1.Intersect(ray) || tr2.Intersect(ray) {
return true
}
return false
}
type Sphere struct {
O geom.Vector
R float64
}
func NewSphere(origin geom.Vector, r float64) Sphere {
return Sphere{O: origin, R: r}
}
func (sp Sphere) Intersect(ray geom.Ray) bool {
if (ray.Origin.X <= sp.O.X-sp.R && ray.Direction.X >= sp.O.X-sp.R || ray.Origin.X >= sp.O.X-sp.R && ray.Direction.X <= sp.O.X-sp.R) &&
(ray.Origin.Y <= sp.O.Y-sp.R && ray.Direction.Y >= sp.O.Y-sp.R || ray.Origin.Y >= sp.O.Y-sp.R && ray.Direction.Y <= sp.O.Y-sp.R) &&
(ray.Origin.Z <= sp.O.Z-sp.R && ray.Direction.Z >= sp.O.Z-sp.R || ray.Origin.Z >= sp.O.Z-sp.R && ray.Direction.Z <= sp.O.Z-sp.R) {
return true
}
return false
-}
+}

Йоан обнови решението на 20.11.2018 00:11 (преди 9 месеца)

package main
import "github.com/fmi/go-homework/geom"
type Triangle struct {
A, B, C geom.Vector
}
func NewTriangle(a, b, c geom.Vector) Triangle {
return Triangle{A: a, B: b, C: c}
}
func (tr Triangle) Intersect(ray geom.Ray) bool {
BminusA := Subtract(tr.B, tr.A)
CminusA := Subtract(tr.C, tr.A)
n := Cross(BminusA, CminusA)
d := Dot(n, tr.A)
nP := Dot(n, ray.Origin)
nd := Dot(n, ray.Direction)
t := (d - nP) / nd
Q := geom.NewVector(t*ray.Direction.X, t*ray.Direction.Y, t*ray.Direction.Z)
QminusA := Subtract(Q, tr.A)
CminusB := Subtract(tr.C, tr.B)
QminusB := Subtract(Q, tr.B)
AminusC := Subtract(tr.A, tr.C)
QminusC := Subtract(Q, tr.C)
if Dot(Cross(BminusA, QminusA), n) >= 0 && Dot(Cross(CminusB, QminusB), n) >= 0 && Dot(Cross(AminusC, QminusC), n) >= 0 ||
Dot(Cross(BminusA, QminusA), n) <= 0 && Dot(Cross(CminusB, QminusB), n) <= 0 && Dot(Cross(AminusC, QminusC), n) <= 0 {
return true
}
return false
}
func Subtract(a, b geom.Vector) geom.Vector {
return geom.NewVector(a.X-b.X, a.Y-b.Y, a.Z-b.Z)
}
func Dot(a, b geom.Vector) float64 {
return a.X*b.X + a.Y*b.Y + a.Z*b.Z
}
func Cross(a, 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)
}
type Quad struct {
A, B, C, D geom.Vector
}
func NewQuad(a, b, c, d geom.Vector) Quad {
return Quad{A: a, B: b, C: c, D: d}
}
func (qa Quad) Intersect(ray geom.Ray) bool {
tr1 := NewTriangle(qa.A, qa.B, qa.C)
tr2 := NewTriangle(qa.C, qa.D, qa.A)
if tr1.Intersect(ray) || tr2.Intersect(ray) {
return true
}
return false
}
type Sphere struct {
O geom.Vector
R float64
}
func NewSphere(origin geom.Vector, r float64) Sphere {
return Sphere{O: origin, R: r}
}
func (sp Sphere) Intersect(ray geom.Ray) bool {
- if (ray.Origin.X <= sp.O.X-sp.R && ray.Direction.X >= sp.O.X-sp.R || ray.Origin.X >= sp.O.X-sp.R && ray.Direction.X <= sp.O.X-sp.R) &&
- (ray.Origin.Y <= sp.O.Y-sp.R && ray.Direction.Y >= sp.O.Y-sp.R || ray.Origin.Y >= sp.O.Y-sp.R && ray.Direction.Y <= sp.O.Y-sp.R) &&
- (ray.Origin.Z <= sp.O.Z-sp.R && ray.Direction.Z >= sp.O.Z-sp.R || ray.Origin.Z >= sp.O.Z-sp.R && ray.Direction.Z <= sp.O.Z-sp.R) {
+ Q := Subtract(ray.Origin, sp.O)
+ a := Dot(ray.Direction, ray.Direction)
+ b := 2 * Dot(ray.Direction, Q)
+ c := Dot(Q, Q) - sp.R*sp.R
+ d := b*b - 4*a*c
+ if d >= 0 {
return true
}
return false
-}
+}

Прочети условието отново и виж какво сме казали за culling. Иначе решението ти изглежда доста хубаво.

Също така, знай че операциите с float числа не са съвсем стабилни. Провери дали нямаш грешки когато лъчите минават много близо до твоите фигури.

Йоан обнови решението на 21.11.2018 14:12 (преди 9 месеца)

package main
-import "github.com/fmi/go-homework/geom"
+import (
+ "github.com/fmi/go-homework/geom"
+ "math"
+)
type Triangle struct {
A, B, C geom.Vector
}
func NewTriangle(a, b, c geom.Vector) Triangle {
return Triangle{A: a, B: b, C: c}
}
func (tr Triangle) Intersect(ray geom.Ray) bool {
BminusA := Subtract(tr.B, tr.A)
CminusA := Subtract(tr.C, tr.A)
n := Cross(BminusA, CminusA)
+ n = Multiply(n, 1/(math.Sqrt(Dot(n, n))))
d := Dot(n, tr.A)
nP := Dot(n, ray.Origin)
nd := Dot(n, ray.Direction)
t := (d - nP) / nd
- Q := geom.NewVector(t*ray.Direction.X, t*ray.Direction.Y, t*ray.Direction.Z)
+ Q := Add(ray.Origin, Multiply(ray.Direction, t))
QminusA := Subtract(Q, tr.A)
CminusB := Subtract(tr.C, tr.B)
QminusB := Subtract(Q, tr.B)
AminusC := Subtract(tr.A, tr.C)
QminusC := Subtract(Q, tr.C)
- if Dot(Cross(BminusA, QminusA), n) >= 0 && Dot(Cross(CminusB, QminusB), n) >= 0 && Dot(Cross(AminusC, QminusC), n) >= 0 ||
- Dot(Cross(BminusA, QminusA), n) <= 0 && Dot(Cross(CminusB, QminusB), n) <= 0 && Dot(Cross(AminusC, QminusC), n) <= 0 {
+ epsilon := 1e-7
+ if Dot(Cross(BminusA, QminusA), n) >= 0-epsilon && Dot(Cross(CminusB, QminusB), n) >= 0-epsilon && Dot(Cross(AminusC, QminusC), n) >= 0-epsilon ||
+ Dot(Cross(BminusA, QminusA), n) <= 0+epsilon && Dot(Cross(CminusB, QminusB), n) <= 0+epsilon && Dot(Cross(AminusC, QminusC), n) <= 0+epsilon {
return true
}
return false
}
+func Multiply(v geom.Vector, n float64) geom.Vector {
+ return geom.NewVector(v.X*n, v.Y*n, v.Z*n)
+}
+
func Subtract(a, b geom.Vector) geom.Vector {
return geom.NewVector(a.X-b.X, a.Y-b.Y, a.Z-b.Z)
}
+func Add(a, b geom.Vector) geom.Vector {
+ return geom.NewVector(a.X+b.X, a.Y+b.Y, a.Z+b.Z)
+}
+
func Dot(a, b geom.Vector) float64 {
return a.X*b.X + a.Y*b.Y + a.Z*b.Z
}
func Cross(a, 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)
}
type Quad struct {
A, B, C, D geom.Vector
}
func NewQuad(a, b, c, d geom.Vector) Quad {
return Quad{A: a, B: b, C: c, D: d}
}
+func Area(tr Triangle) float64 {
+ A, B, C := tr.A, tr.B, tr.C
+ S := math.Sqrt(Dot(Cross(Subtract(B, A), Subtract(C, A)), Cross(Subtract(B, A), Subtract(C, A)))) / 2
+ return S
+}
+
func (qa Quad) Intersect(ray geom.Ray) bool {
- tr1 := NewTriangle(qa.A, qa.B, qa.C)
- tr2 := NewTriangle(qa.C, qa.D, qa.A)
- if tr1.Intersect(ray) || tr2.Intersect(ray) {
- return true
+ A, B, C, D := qa.A, qa.B, qa.C, qa.D
+ tr1 := NewTriangle(A, B, C)
+ tr2 := NewTriangle(C, D, A)
+ tr3 := NewTriangle(B, C, D)
+ tr4 := NewTriangle(D, A, B)
+ if Area(tr1)+Area(tr2) <= Area(tr3)+Area(tr4) {
+ if tr1.Intersect(ray) || tr2.Intersect(ray) {
+ return true
+ }
+ } else {
+ if tr3.Intersect(ray) || tr4.Intersect(ray) {
+ return true
+ }
}
+
return false
}
type Sphere struct {
O geom.Vector
R float64
}
func NewSphere(origin geom.Vector, r float64) Sphere {
return Sphere{O: origin, R: r}
}
func (sp Sphere) Intersect(ray geom.Ray) bool {
Q := Subtract(ray.Origin, sp.O)
a := Dot(ray.Direction, ray.Direction)
b := 2 * Dot(ray.Direction, Q)
c := Dot(Q, Q) - sp.R*sp.R
d := b*b - 4*a*c
- if d >= 0 {
+ epsilon := 1e-7
+ if d >= 0-epsilon {
return true
}
return false
-}
+}