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

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

Към профила на Траян Троев

Резултати

  • 10 точки от тестове
  • 0 бонус точки
  • 10 точки общо
  • 20 успешни тест(а)
  • 0 неуспешни тест(а)

Код

package main
import (
"github.com/fmi/go-homework/geom"
"math"
)
const epsilon = 1e-7
// type plane with some useful methods
type plane struct {
A float64
B float64
C float64
D float64
}
func newPlane(a, b, c geom.Vector) plane {
vectAB := vectorFromAtoB(a, b)
vectAC := vectorFromAtoB(a, c)
normalizedVector := geom.NewVector(
vectAB.Y*vectAC.Z-vectAB.Z*vectAC.Y,
vectAB.Z*vectAC.X-vectAB.X*vectAC.Z,
vectAB.X*vectAC.Y-vectAB.Y*vectAC.X)
dValue := -(normalizedVector.X*a.X +
normalizedVector.Y*a.Y +
normalizedVector.Z*a.Z)
plane := plane{
A: normalizedVector.X,
B: normalizedVector.Y,
C: normalizedVector.Z,
D: dValue,
}
return plane
}
func (plane *plane) rayParallelToPlane(ray geom.Ray) bool {
parallelCheckSum := plane.A*ray.Direction.X +
plane.B*ray.Direction.Y +
plane.C*ray.Direction.Z
return (parallelCheckSum) >= -epsilon &&
(parallelCheckSum) <= epsilon
}
func (plane *plane) intersetionPoint(ray geom.Ray) (intersectionPoint geom.Vector, isIntersected bool) {
if !plane.rayParallelToPlane(ray) {
numerator := -(plane.A*ray.Origin.X +
plane.B*ray.Origin.Y +
plane.C*ray.Origin.Z +
plane.D)
denominator := plane.A*ray.Direction.X +
plane.B*ray.Direction.Y +
plane.C*ray.Direction.Z
t := numerator / denominator
if t < -epsilon {
return
}
isIntersected = true
intersectionPoint = geom.NewVector(ray.Origin.X+t*ray.Direction.X,
ray.Origin.Y+t*ray.Direction.Y,
ray.Origin.Z+t*ray.Direction.Z)
return
}
return
}
func (plane *plane) normalizedVector() geom.Vector {
return geom.Vector{plane.A, plane.B, plane.C}
}
type Triangle struct {
A geom.Vector
B geom.Vector
C geom.Vector
}
func NewTriangle(a, b, c geom.Vector) Triangle {
return Triangle{
a,
b,
c,
}
}
func (triangle Triangle) Intersect(ray geom.Ray) bool {
trianglePlane := newPlane(triangle.A, triangle.B, triangle.C)
intersectionPoint, isPlaneIntersected := trianglePlane.intersetionPoint(ray)
if !isPlaneIntersected {
return false
}
triangleNormV := trianglePlane.normalizedVector()
vectAP := vectorFromAtoB(triangle.A, intersectionPoint)
vectAB := vectorFromAtoB(triangle.A, triangle.B)
vectBP := vectorFromAtoB(triangle.B, intersectionPoint)
vectBC := vectorFromAtoB(triangle.B, triangle.C)
vectCP := vectorFromAtoB(triangle.C, intersectionPoint)
vectCA := vectorFromAtoB(triangle.C, triangle.A)
ABxAP := vectorsCrossProd(vectAB, vectAP)
ABxAPNV := scalarMultiplication(ABxAP, triangleNormV)
BCxBP := vectorsCrossProd(vectBC, vectBP)
BCxBPNV := scalarMultiplication(BCxBP, triangleNormV)
CAxCP := vectorsCrossProd(vectCA, vectCP)
CAxCPNV := scalarMultiplication(CAxCP, triangleNormV)
if (ABxAPNV <= epsilon && BCxBPNV <= epsilon && CAxCPNV <= epsilon) ||
(ABxAPNV >= -epsilon && BCxBPNV >= -epsilon && CAxCPNV >= -epsilon) {
return true
}
return false
}
func (triangle *Triangle) area() float64 {
vectAB := vectorFromAtoB(triangle.A, triangle.B)
vectBC := vectorFromAtoB(triangle.A, triangle.C)
normalizedVector := geom.NewVector(vectAB.Y*vectBC.Z-vectAB.Z*vectBC.Y,
vectAB.Z*vectBC.X-vectAB.X*vectBC.Z,
vectAB.X*vectBC.Y-vectAB.Y*vectBC.X)
return math.Sqrt(normalizedVector.X*normalizedVector.X+
normalizedVector.Y*normalizedVector.Y+
normalizedVector.Z*normalizedVector.Z) / 2
}
type Quadrangle struct {
Triangle
D geom.Vector
}
func NewQuad(a, b, c, d geom.Vector) Quadrangle {
return Quadrangle{
NewTriangle(a, b, c),
d,
}
}
func (quadrangle Quadrangle) Intersect(ray geom.Ray) bool {
quadPlane := newPlane(quadrangle.A, quadrangle.B, quadrangle.C)
_, isPlaneIntersected := quadPlane.intersetionPoint(ray)
if !isPlaneIntersected {
return false
}
normalVectorABD := vectorsCrossProd(
vectorFromAtoB(quadrangle.A, quadrangle.B),
vectorFromAtoB(quadrangle.A, quadrangle.D))
normalVectorCBD := vectorsCrossProd(
vectorFromAtoB(quadrangle.C, quadrangle.B),
vectorFromAtoB(quadrangle.C, quadrangle.D))
if scalarMultiplication(normalVectorABD, normalVectorCBD) < -epsilon {
// choose diagonal AC for division of the quadrangle
return NewTriangle(quadrangle.A, quadrangle.B, quadrangle.C).Intersect(ray) ||
NewTriangle(quadrangle.A, quadrangle.C, quadrangle.D).Intersect(ray)
} else {
// choose diagonal BD for division of the quadrangle
return NewTriangle(quadrangle.A, quadrangle.B, quadrangle.D).Intersect(ray) ||
NewTriangle(quadrangle.B, quadrangle.C, quadrangle.D).Intersect(ray)
}
}
// type quadratic equation with some useful methods
type quadrEquation struct {
a float64
b float64
c float64
}
func newQuadrEqation(a, b, c float64) quadrEquation {
return quadrEquation{
a,
b,
c,
}
}
func (qdeq *quadrEquation) discriminant() float64 {
return qdeq.b*qdeq.b - 4*qdeq.a*qdeq.c
}
func (qdeq *quadrEquation) roots() (float64, float64, int8) {
discriminant := qdeq.discriminant()
var x1 float64
var x2 float64
var cntDiffRoots int8 = 0
if discriminant >= -epsilon && discriminant <= epsilon {
x1 = -(qdeq.b) / 2 * qdeq.a
x2 = x1
cntDiffRoots = 1
} else if discriminant > epsilon {
x1 = -qdeq.b + math.Sqrt(discriminant)
x2 = -qdeq.b - math.Sqrt(discriminant)
cntDiffRoots = 2
}
return x1, x2, cntDiffRoots
}
type Sphere struct {
center geom.Vector
radius float64
}
func NewSphere(origin geom.Vector, r float64) Sphere {
return Sphere{
origin,
r,
}
}
func (sphere Sphere) Intersect(ray geom.Ray) bool {
sphereQuadrEq := newQuadrEqation(
scalarMultiplication(ray.Direction, ray.Direction),
2*scalarMultiplication(
ray.Direction,
subtractVectors(ray.Origin, sphere.center)),
scalarMultiplication(
subtractVectors(ray.Origin, sphere.center),
subtractVectors(ray.Origin, sphere.center))-
sphere.radius*sphere.radius)
t1, t2, cntRoots := sphereQuadrEq.roots()
if cntRoots == 1 && t1 >= -epsilon {
return true
} else if cntRoots == 2 && (t1 >= -epsilon || t2 >= -epsilon) {
return true
}
return false
}
// helper functions for vector operations
func vectorFromAtoB(point1 geom.Vector, point2 geom.Vector) geom.Vector {
return geom.NewVector(point2.X-point1.X, point2.Y-point1.Y, point2.Z-point1.Z)
}
func subtractVectors(v1 geom.Vector, v2 geom.Vector) geom.Vector {
return geom.NewVector(v1.X-v2.X, v1.Y-v2.Y, v1.Z-v2.Z)
}
func scalarMultiplication(v1 geom.Vector, v2 geom.Vector) float64 {
return v1.X*v2.X + v1.Y*v2.Y + v1.Z*v2.Z
}
func vectorsCrossProd(v1 geom.Vector, v2 geom.Vector) geom.Vector {
return geom.Vector{
v1.Y*v2.Z - v1.Z*v2.Y,
v1.Z*v2.X - v1.X*v2.Z,
v1.X*v2.Y - v1.Y*v2.X,
}
}

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

PASS
ok  	_/tmp/d20181122-57-1m9tzo3	0.002s
PASS
ok  	_/tmp/d20181122-57-1m9tzo3	0.002s
PASS
ok  	_/tmp/d20181122-57-1m9tzo3	0.002s
PASS
ok  	_/tmp/d20181122-57-1m9tzo3	0.002s
PASS
ok  	_/tmp/d20181122-57-1m9tzo3	0.002s
PASS
ok  	_/tmp/d20181122-57-1m9tzo3	0.002s
PASS
ok  	_/tmp/d20181122-57-1m9tzo3	0.002s
PASS
ok  	_/tmp/d20181122-57-1m9tzo3	0.002s
PASS
ok  	_/tmp/d20181122-57-1m9tzo3	0.002s
PASS
ok  	_/tmp/d20181122-57-1m9tzo3	0.002s
PASS
ok  	_/tmp/d20181122-57-1m9tzo3	0.002s
PASS
ok  	_/tmp/d20181122-57-1m9tzo3	0.002s
PASS
ok  	_/tmp/d20181122-57-1m9tzo3	0.002s
PASS
ok  	_/tmp/d20181122-57-1m9tzo3	0.002s
PASS
ok  	_/tmp/d20181122-57-1m9tzo3	0.002s
PASS
ok  	_/tmp/d20181122-57-1m9tzo3	0.003s
PASS
ok  	_/tmp/d20181122-57-1m9tzo3	0.002s
PASS
ok  	_/tmp/d20181122-57-1m9tzo3	0.002s
PASS
ok  	_/tmp/d20181122-57-1m9tzo3	0.002s
PASS
ok  	_/tmp/d20181122-57-1m9tzo3	0.002s

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

Траян обнови решението на 19.11.2018 10:24 (преди 9 месеца)

+package main
+
+import (
+ "github.com/fmi/go-homework/geom"
+ "math"
+)
+
+// type plane with some useful methods
+type plane struct {
+ A float64
+ B float64
+ C float64
+ D float64
+}
+
+func newPlane(triangle Triangle) plane {
+ vectAB := vectorByTwoPoints(triangle.A, triangle.B)
+ vectBC := vectorByTwoPoints(triangle.A, triangle.C)
+
+ normalizedVector := geom.NewVector(vectAB.Y*vectBC.Z-vectAB.Z*vectBC.Y,
+ vectAB.Z*vectBC.X-vectAB.X*vectBC.Z,
+ vectAB.X*vectBC.Y-vectAB.Y*vectBC.X)
+
+ dValue := -(normalizedVector.X*triangle.A.X +
+ normalizedVector.Y*triangle.A.Y +
+ normalizedVector.Z*triangle.A.Z)
+
+ plane := plane{
+ A: normalizedVector.X,
+ B: normalizedVector.Y,
+ C: normalizedVector.Z,
+ D: dValue,
+ }
+ return plane
+}
+
+func (plane *plane) rayParallelToPlane(ray geom.Ray) bool {
+ return (plane.A*ray.Direction.X +
+ plane.B*ray.Direction.Y +
+ plane.C*ray.Direction.Z) == 0.0
+}
+
+type Triangle struct {
+ A geom.Vector
+ B geom.Vector
+ C geom.Vector
+}
+
+func NewTriangle(a, b, c geom.Vector) Triangle {
+ return Triangle{
+ a,
+ b,
+ c,
+ }
+}
+
+func (triangle Triangle) Intersect(ray geom.Ray) bool {
+ trianglePlane := newPlane(triangle)
+ if trianglePlane.rayParallelToPlane(ray) {
+ return false
+ } else {
+ numerator := -(trianglePlane.A*ray.Origin.X +
+ trianglePlane.B*ray.Origin.Y +
+ trianglePlane.C*ray.Origin.Z) +
+ trianglePlane.D
+ denominator := trianglePlane.A*ray.Direction.X +
+ trianglePlane.B*ray.Direction.Y +
+ trianglePlane.C*ray.Direction.Z
+
+ t := numerator / denominator
+
+ if t < 0 {
+ return false
+ }
+ intersectionPoint := geom.NewVector(ray.Origin.X+t*ray.Direction.X,
+ ray.Origin.Y+t*ray.Direction.Y,
+ ray.Origin.Z+t*ray.Direction.Z)
+
+ triangleAPC := NewTriangle(triangle.A, intersectionPoint, triangle.C)
+ triangleABP := NewTriangle(triangle.A, triangle.B, intersectionPoint)
+ trianglePBC := NewTriangle(intersectionPoint, triangle.B, triangle.C)
+
+ baricentPBCtoABC := trianglePBC.area() / triangle.area()
+ baricentAPCtoABC := triangleAPC.area() / triangle.area()
+ baricentABPtoABC := triangleABP.area() / triangle.area()
+
+ if baricentPBCtoABC >= 0.0 && baricentPBCtoABC <= 1.0 {
+ if baricentAPCtoABC >= 0.0 && baricentAPCtoABC <= 1.0 {
+ if baricentABPtoABC >= 0.0 && baricentABPtoABC <= 1.0 {
+ return true
+ }
+ }
+ }
+
+ return false
+ }
+}
+
+func (triangle *Triangle) area() float64 {
+ vectAB := vectorByTwoPoints(triangle.A, triangle.B)
+ vectBC := vectorByTwoPoints(triangle.A, triangle.C)
+
+ normalizedVector := geom.NewVector(vectAB.Y*vectBC.Z-vectAB.Z*vectBC.Y,
+ vectAB.Z*vectBC.X-vectAB.X*vectBC.Z,
+ vectAB.X*vectBC.Y-vectAB.Y*vectBC.X)
+
+ return math.Sqrt(normalizedVector.X*normalizedVector.X+
+ normalizedVector.Y*normalizedVector.Y+
+ normalizedVector.Z*normalizedVector.Z) / 2
+}
+
+type Quadrangle struct {
+ triangle Triangle
+ D geom.Vector
+}
+
+func NewQuad(a, b, c, d geom.Vector) Quadrangle {
+ return Quadrangle{
+ NewTriangle(a, b, c),
+ d,
+ }
+}
+
+func (quadrangle Quadrangle) Intersect(ray geom.Ray) bool {
+ secondTriangle := NewTriangle(quadrangle.triangle.A, quadrangle.triangle.C, quadrangle.D)
+ return quadrangle.triangle.Intersect(ray) ||
+ secondTriangle.Intersect(ray)
+}
+
+// type quadratic equation with some useful methods
+type quadrEquation struct {
+ a float64
+ b float64
+ c float64
+}
+
+func newQuadrEqation(a, b, c float64) quadrEquation {
+ return quadrEquation{
+ a,
+ b,
+ c,
+ }
+}
+
+func (qdeq *quadrEquation) discriminant() float64 {
+ return qdeq.b*qdeq.b - 4*qdeq.a*qdeq.c
+}
+
+type Sphere struct {
+ center geom.Vector
+ radius float64
+}
+
+func NewSphere(origin geom.Vector, r float64) Sphere {
+ return Sphere{
+ origin,
+ r,
+ }
+}
+func (sphere Sphere) Intersect(ray geom.Ray) bool {
+ sphereQuadrEq := newQuadrEqation(
+ scalarMultiplication(ray.Direction, ray.Direction),
+ 2*scalarMultiplication(
+ ray.Direction,
+ subtractVectors(ray.Origin, sphere.center)),
+ scalarMultiplication(
+ subtractVectors(ray.Origin, sphere.center),
+ subtractVectors(ray.Origin, sphere.center))-
+ sphere.radius*sphere.radius)
+
+ det := sphereQuadrEq.discriminant()
+ if det < 0 {
+ return false
+ }
+ if det == 0 {
+ t := -sphereQuadrEq.b / 2
+ if t >= 0 {
+ return true
+ }
+ return false
+ }
+
+ t1 := (-sphereQuadrEq.b + math.Sqrt(det)) / 2
+ t2 := (-sphereQuadrEq.b - math.Sqrt(det)) / 2
+ if t1 >= 0 || t2 >= 0 {
+ return true
+ }
+
+ return false
+}
+
+// helper functions for vector operations
+func vectorByTwoPoints(point1 geom.Vector, point2 geom.Vector) geom.Vector {
+ return geom.NewVector(point2.X-point1.X, point2.Y-point1.Y, point2.Z-point1.Z)
+}
+
+func subtractVectors(v1 geom.Vector, v2 geom.Vector) geom.Vector {
+ return geom.NewVector(v1.X-v2.X, v1.Y-v2.Y, v1.Z-v2.Z)
+}
+
+func scalarMultiplication(v1 geom.Vector, v2 geom.Vector) float64 {
+ return v1.X*v2.X + v1.Y*v2.Y + v1.Z*v2.Z
+}

Траян обнови решението на 19.11.2018 11:29 (преди 9 месеца)

package main
import (
"github.com/fmi/go-homework/geom"
"math"
)
// type plane with some useful methods
type plane struct {
A float64
B float64
C float64
D float64
}
func newPlane(triangle Triangle) plane {
vectAB := vectorByTwoPoints(triangle.A, triangle.B)
vectBC := vectorByTwoPoints(triangle.A, triangle.C)
normalizedVector := geom.NewVector(vectAB.Y*vectBC.Z-vectAB.Z*vectBC.Y,
vectAB.Z*vectBC.X-vectAB.X*vectBC.Z,
vectAB.X*vectBC.Y-vectAB.Y*vectBC.X)
dValue := -(normalizedVector.X*triangle.A.X +
normalizedVector.Y*triangle.A.Y +
normalizedVector.Z*triangle.A.Z)
plane := plane{
A: normalizedVector.X,
B: normalizedVector.Y,
C: normalizedVector.Z,
D: dValue,
}
return plane
}
func (plane *plane) rayParallelToPlane(ray geom.Ray) bool {
- return (plane.A*ray.Direction.X +
+ parallelCheckSum := plane.A*ray.Direction.X +
plane.B*ray.Direction.Y +
- plane.C*ray.Direction.Z) == 0.0
+ plane.C*ray.Direction.Z
+ return (parallelCheckSum) >= -(1e-7) &&
+ (parallelCheckSum) <= 1e-7
+
}
type Triangle struct {
A geom.Vector
B geom.Vector
C geom.Vector
}
func NewTriangle(a, b, c geom.Vector) Triangle {
return Triangle{
a,
b,
c,
}
}
func (triangle Triangle) Intersect(ray geom.Ray) bool {
trianglePlane := newPlane(triangle)
if trianglePlane.rayParallelToPlane(ray) {
return false
} else {
numerator := -(trianglePlane.A*ray.Origin.X +
trianglePlane.B*ray.Origin.Y +
trianglePlane.C*ray.Origin.Z) +
trianglePlane.D
denominator := trianglePlane.A*ray.Direction.X +
trianglePlane.B*ray.Direction.Y +
trianglePlane.C*ray.Direction.Z
t := numerator / denominator
- if t < 0 {
+ if t < -(1e-7) {
return false
}
intersectionPoint := geom.NewVector(ray.Origin.X+t*ray.Direction.X,
ray.Origin.Y+t*ray.Direction.Y,
ray.Origin.Z+t*ray.Direction.Z)
triangleAPC := NewTriangle(triangle.A, intersectionPoint, triangle.C)
triangleABP := NewTriangle(triangle.A, triangle.B, intersectionPoint)
trianglePBC := NewTriangle(intersectionPoint, triangle.B, triangle.C)
baricentPBCtoABC := trianglePBC.area() / triangle.area()
baricentAPCtoABC := triangleAPC.area() / triangle.area()
baricentABPtoABC := triangleABP.area() / triangle.area()
- if baricentPBCtoABC >= 0.0 && baricentPBCtoABC <= 1.0 {
- if baricentAPCtoABC >= 0.0 && baricentAPCtoABC <= 1.0 {
- if baricentABPtoABC >= 0.0 && baricentABPtoABC <= 1.0 {
+ if baricentPBCtoABC >= 1e-7 && baricentPBCtoABC <= 1.0 {
+ if baricentAPCtoABC >= 1e-7 && baricentAPCtoABC <= 1.0 {
+ if baricentABPtoABC >= 1e-7 && baricentABPtoABC <= 1.0 {
return true
}
}
}
return false
}
}
func (triangle *Triangle) area() float64 {
vectAB := vectorByTwoPoints(triangle.A, triangle.B)
vectBC := vectorByTwoPoints(triangle.A, triangle.C)
normalizedVector := geom.NewVector(vectAB.Y*vectBC.Z-vectAB.Z*vectBC.Y,
vectAB.Z*vectBC.X-vectAB.X*vectBC.Z,
vectAB.X*vectBC.Y-vectAB.Y*vectBC.X)
return math.Sqrt(normalizedVector.X*normalizedVector.X+
normalizedVector.Y*normalizedVector.Y+
normalizedVector.Z*normalizedVector.Z) / 2
}
type Quadrangle struct {
triangle Triangle
D geom.Vector
}
func NewQuad(a, b, c, d geom.Vector) Quadrangle {
return Quadrangle{
NewTriangle(a, b, c),
d,
}
}
func (quadrangle Quadrangle) Intersect(ray geom.Ray) bool {
secondTriangle := NewTriangle(quadrangle.triangle.A, quadrangle.triangle.C, quadrangle.D)
return quadrangle.triangle.Intersect(ray) ||
secondTriangle.Intersect(ray)
}
// type quadratic equation with some useful methods
type quadrEquation struct {
a float64
b float64
c float64
}
func newQuadrEqation(a, b, c float64) quadrEquation {
return quadrEquation{
a,
b,
c,
}
}
func (qdeq *quadrEquation) discriminant() float64 {
return qdeq.b*qdeq.b - 4*qdeq.a*qdeq.c
}
type Sphere struct {
center geom.Vector
radius float64
}
func NewSphere(origin geom.Vector, r float64) Sphere {
return Sphere{
origin,
r,
}
}
func (sphere Sphere) Intersect(ray geom.Ray) bool {
sphereQuadrEq := newQuadrEqation(
scalarMultiplication(ray.Direction, ray.Direction),
2*scalarMultiplication(
ray.Direction,
subtractVectors(ray.Origin, sphere.center)),
scalarMultiplication(
subtractVectors(ray.Origin, sphere.center),
subtractVectors(ray.Origin, sphere.center))-
sphere.radius*sphere.radius)
det := sphereQuadrEq.discriminant()
- if det < 0 {
+ if det < -(1e-7) {
return false
}
- if det == 0 {
+ if det >= -(1e-7) && det <= 1e-7 {
t := -sphereQuadrEq.b / 2
- if t >= 0 {
+ if t >= 1e-7 {
return true
}
return false
}
t1 := (-sphereQuadrEq.b + math.Sqrt(det)) / 2
t2 := (-sphereQuadrEq.b - math.Sqrt(det)) / 2
- if t1 >= 0 || t2 >= 0 {
+ if t1 >= 1e-7 || t2 >= 1e-7 {
return true
}
return false
}
// helper functions for vector operations
func vectorByTwoPoints(point1 geom.Vector, point2 geom.Vector) geom.Vector {
return geom.NewVector(point2.X-point1.X, point2.Y-point1.Y, point2.Z-point1.Z)
}
func subtractVectors(v1 geom.Vector, v2 geom.Vector) geom.Vector {
return geom.NewVector(v1.X-v2.X, v1.Y-v2.Y, v1.Z-v2.Z)
}
func scalarMultiplication(v1 geom.Vector, v2 geom.Vector) float64 {
return v1.X*v2.X + v1.Y*v2.Y + v1.Z*v2.Z
}

Траян обнови решението на 20.11.2018 12:58 (преди 9 месеца)

package main
import (
"github.com/fmi/go-homework/geom"
"math"
)
// type plane with some useful methods
type plane struct {
A float64
B float64
C float64
D float64
}
func newPlane(triangle Triangle) plane {
vectAB := vectorByTwoPoints(triangle.A, triangle.B)
vectBC := vectorByTwoPoints(triangle.A, triangle.C)
normalizedVector := geom.NewVector(vectAB.Y*vectBC.Z-vectAB.Z*vectBC.Y,
vectAB.Z*vectBC.X-vectAB.X*vectBC.Z,
vectAB.X*vectBC.Y-vectAB.Y*vectBC.X)
dValue := -(normalizedVector.X*triangle.A.X +
normalizedVector.Y*triangle.A.Y +
normalizedVector.Z*triangle.A.Z)
plane := plane{
A: normalizedVector.X,
B: normalizedVector.Y,
C: normalizedVector.Z,
D: dValue,
}
return plane
}
func (plane *plane) rayParallelToPlane(ray geom.Ray) bool {
parallelCheckSum := plane.A*ray.Direction.X +
plane.B*ray.Direction.Y +
plane.C*ray.Direction.Z
return (parallelCheckSum) >= -(1e-7) &&
(parallelCheckSum) <= 1e-7
}
type Triangle struct {
A geom.Vector
B geom.Vector
C geom.Vector
}
func NewTriangle(a, b, c geom.Vector) Triangle {
return Triangle{
a,
b,
c,
}
}
func (triangle Triangle) Intersect(ray geom.Ray) bool {
trianglePlane := newPlane(triangle)
if trianglePlane.rayParallelToPlane(ray) {
return false
} else {
numerator := -(trianglePlane.A*ray.Origin.X +
trianglePlane.B*ray.Origin.Y +
trianglePlane.C*ray.Origin.Z) +
trianglePlane.D
denominator := trianglePlane.A*ray.Direction.X +
trianglePlane.B*ray.Direction.Y +
trianglePlane.C*ray.Direction.Z
t := numerator / denominator
if t < -(1e-7) {
return false
}
intersectionPoint := geom.NewVector(ray.Origin.X+t*ray.Direction.X,
ray.Origin.Y+t*ray.Direction.Y,
ray.Origin.Z+t*ray.Direction.Z)
triangleAPC := NewTriangle(triangle.A, intersectionPoint, triangle.C)
triangleABP := NewTriangle(triangle.A, triangle.B, intersectionPoint)
trianglePBC := NewTriangle(intersectionPoint, triangle.B, triangle.C)
baricentPBCtoABC := trianglePBC.area() / triangle.area()
baricentAPCtoABC := triangleAPC.area() / triangle.area()
baricentABPtoABC := triangleABP.area() / triangle.area()
- if baricentPBCtoABC >= 1e-7 && baricentPBCtoABC <= 1.0 {
- if baricentAPCtoABC >= 1e-7 && baricentAPCtoABC <= 1.0 {
- if baricentABPtoABC >= 1e-7 && baricentABPtoABC <= 1.0 {
+ if baricentPBCtoABC >= -(1e-7) && baricentPBCtoABC <= 1.0 {
+ if baricentAPCtoABC >= -(1e-7) && baricentAPCtoABC <= 1.0 {
+ if baricentABPtoABC >= -(1e-7) && baricentABPtoABC <= 1.0 {
return true
}
}
}
return false
}
}
func (triangle *Triangle) area() float64 {
vectAB := vectorByTwoPoints(triangle.A, triangle.B)
vectBC := vectorByTwoPoints(triangle.A, triangle.C)
normalizedVector := geom.NewVector(vectAB.Y*vectBC.Z-vectAB.Z*vectBC.Y,
vectAB.Z*vectBC.X-vectAB.X*vectBC.Z,
vectAB.X*vectBC.Y-vectAB.Y*vectBC.X)
return math.Sqrt(normalizedVector.X*normalizedVector.X+
normalizedVector.Y*normalizedVector.Y+
normalizedVector.Z*normalizedVector.Z) / 2
}
type Quadrangle struct {
triangle Triangle
D geom.Vector
}
func NewQuad(a, b, c, d geom.Vector) Quadrangle {
return Quadrangle{
NewTriangle(a, b, c),
d,
}
}
func (quadrangle Quadrangle) Intersect(ray geom.Ray) bool {
secondTriangle := NewTriangle(quadrangle.triangle.A, quadrangle.triangle.C, quadrangle.D)
return quadrangle.triangle.Intersect(ray) ||
secondTriangle.Intersect(ray)

Този метод ми се вижда твърде сложен. Почти съм сигурен, че няма как да работи. Добро правило което можеш да следваш е, че ако нещо е станало малко по - завъртяно, то най - вероятно е грешно и има по - добър начин.

Добре, ще има ли самопресичащи се, или вдлъбнати(неизпъкнали) 4-ъгълници? Защото аз съм разделил 4-ъгълника на 2 триъгълника по единия диагонал и съм проверил, дали някой от тях се пресича с лъча, тоест свел съм задачата към вече решена :) Даже и за вдлъбнати(неизпъкнали) би трябвало да работи като се замисля. Tака че по-скоро, ще има ли самопресичащи се?

Благодаря.

}
// type quadratic equation with some useful methods
type quadrEquation struct {
a float64
b float64
c float64
}
func newQuadrEqation(a, b, c float64) quadrEquation {
return quadrEquation{
a,
b,
c,
}
}
func (qdeq *quadrEquation) discriminant() float64 {
return qdeq.b*qdeq.b - 4*qdeq.a*qdeq.c
}
+func (qdeq *quadrEquation) roots() (float64, float64, int8) {
+ discriminant := qdeq.discriminant()
+ var x1 float64
+ var x2 float64
+ var cntDiffRoots int8 = 0
+ if discriminant >= -(1e-7) && discriminant <= 1e-7 {
+ x1 = -(qdeq.b) / 2 * qdeq.a
+ x2 = x1
+ cntDiffRoots = 1
+ } else if discriminant > 1e-7 {
+ x1 = -qdeq.b + math.Sqrt(discriminant)
+ x2 = -qdeq.b - math.Sqrt(discriminant)
+ cntDiffRoots = 2
+ }
+ return x1, x2, cntDiffRoots
+}
+
type Sphere struct {
center geom.Vector
radius float64
}
func NewSphere(origin geom.Vector, r float64) Sphere {
return Sphere{
origin,
r,
}
}
func (sphere Sphere) Intersect(ray geom.Ray) bool {
sphereQuadrEq := newQuadrEqation(
scalarMultiplication(ray.Direction, ray.Direction),
2*scalarMultiplication(
ray.Direction,
subtractVectors(ray.Origin, sphere.center)),
scalarMultiplication(
subtractVectors(ray.Origin, sphere.center),
subtractVectors(ray.Origin, sphere.center))-
sphere.radius*sphere.radius)
- det := sphereQuadrEq.discriminant()
- if det < -(1e-7) {
- return false
- }
- if det >= -(1e-7) && det <= 1e-7 {
- t := -sphereQuadrEq.b / 2
- if t >= 1e-7 {
- return true
- }
- return false
- }
+ t1, t2, cntRoots := sphereQuadrEq.roots()
- t1 := (-sphereQuadrEq.b + math.Sqrt(det)) / 2
- t2 := (-sphereQuadrEq.b - math.Sqrt(det)) / 2
- if t1 >= 1e-7 || t2 >= 1e-7 {
+ if cntRoots == 1 && t1 >= -(1e-7) {
return true
+ } else if cntRoots == 2 && (t1 >= -(1e-7) || t2 >= -(1e-7)) {
+ return true
}
return false
}
// helper functions for vector operations
func vectorByTwoPoints(point1 geom.Vector, point2 geom.Vector) geom.Vector {
return geom.NewVector(point2.X-point1.X, point2.Y-point1.Y, point2.Z-point1.Z)
}
func subtractVectors(v1 geom.Vector, v2 geom.Vector) geom.Vector {
return geom.NewVector(v1.X-v2.X, v1.Y-v2.Y, v1.Z-v2.Z)
}
func scalarMultiplication(v1 geom.Vector, v2 geom.Vector) float64 {
return v1.X*v2.X + v1.Y*v2.Y + v1.Z*v2.Z
-}
+}

Траян обнови решението на 20.11.2018 22:43 (преди 9 месеца)

package main
import (
"github.com/fmi/go-homework/geom"
"math"
)
+const epsilon = 1e-7
+
// type plane with some useful methods
type plane struct {
A float64
B float64
C float64
D float64
}
-func newPlane(triangle Triangle) plane {
- vectAB := vectorByTwoPoints(triangle.A, triangle.B)
- vectBC := vectorByTwoPoints(triangle.A, triangle.C)
+func newPlane(a, b, c geom.Vector) plane {
+ vectAB := vectorFromAtoB(a, b)
+ vectBC := vectorFromAtoB(a, c)
- normalizedVector := geom.NewVector(vectAB.Y*vectBC.Z-vectAB.Z*vectBC.Y,
+ normalizedVector := geom.NewVector(
+ vectAB.Y*vectBC.Z-vectAB.Z*vectBC.Y,
vectAB.Z*vectBC.X-vectAB.X*vectBC.Z,
vectAB.X*vectBC.Y-vectAB.Y*vectBC.X)
- dValue := -(normalizedVector.X*triangle.A.X +
- normalizedVector.Y*triangle.A.Y +
- normalizedVector.Z*triangle.A.Z)
+ dValue := -(normalizedVector.X*a.X +
+ normalizedVector.Y*a.Y +
+ normalizedVector.Z*a.Z)
plane := plane{
A: normalizedVector.X,
B: normalizedVector.Y,
C: normalizedVector.Z,
D: dValue,
}
return plane
}
func (plane *plane) rayParallelToPlane(ray geom.Ray) bool {
parallelCheckSum := plane.A*ray.Direction.X +
plane.B*ray.Direction.Y +
plane.C*ray.Direction.Z
- return (parallelCheckSum) >= -(1e-7) &&
- (parallelCheckSum) <= 1e-7
+ return (parallelCheckSum) >= -epsilon &&
+ (parallelCheckSum) <= epsilon
+}
+func (plane *plane) intersetionPoint(ray geom.Ray) (intersectionPoint geom.Vector, isIntersected bool) {
+ if !plane.rayParallelToPlane(ray) {
+ numerator := -(plane.A*ray.Origin.X +
+ plane.B*ray.Origin.Y +
+ plane.C*ray.Origin.Z +
+ plane.D)
+ denominator := plane.A*ray.Direction.X +
+ plane.B*ray.Direction.Y +
+ plane.C*ray.Direction.Z
+
+ t := numerator / denominator
+ if t < -epsilon {
+ return
+ }
+
+ isIntersected = true
+ intersectionPoint = geom.NewVector(ray.Origin.X+t*ray.Direction.X,
+ ray.Origin.Y+t*ray.Direction.Y,
+ ray.Origin.Z+t*ray.Direction.Z)
+ return
+ }
+ return
}
+func (plane *plane) normalizedVector() geom.Vector {
+ return geom.Vector{plane.A, plane.B, plane.C}
+}
+
type Triangle struct {
A geom.Vector
B geom.Vector
C geom.Vector
}
func NewTriangle(a, b, c geom.Vector) Triangle {
return Triangle{
a,
b,
c,
}
}
func (triangle Triangle) Intersect(ray geom.Ray) bool {
- trianglePlane := newPlane(triangle)
- if trianglePlane.rayParallelToPlane(ray) {
+ trianglePlane := newPlane(triangle.A, triangle.B, triangle.C)
+ intersectionPoint, isPlaneIntersected := trianglePlane.intersetionPoint(ray)
+ if !isPlaneIntersected {
return false
- } else {
- numerator := -(trianglePlane.A*ray.Origin.X +
- trianglePlane.B*ray.Origin.Y +
- trianglePlane.C*ray.Origin.Z) +
- trianglePlane.D
- denominator := trianglePlane.A*ray.Direction.X +
- trianglePlane.B*ray.Direction.Y +
- trianglePlane.C*ray.Direction.Z
+ }
- t := numerator / denominator
+ triangleNormV := trianglePlane.normalizedVector()
+ vectAP := vectorFromAtoB(triangle.A, intersectionPoint)
+ vectAB := vectorFromAtoB(triangle.A, triangle.B)
+ vectBP := vectorFromAtoB(triangle.B, intersectionPoint)
+ vectBC := vectorFromAtoB(triangle.B, triangle.C)
+ vectCP := vectorFromAtoB(triangle.C, intersectionPoint)
+ vectCA := vectorFromAtoB(triangle.C, triangle.A)
- if t < -(1e-7) {
- return false
- }
- intersectionPoint := geom.NewVector(ray.Origin.X+t*ray.Direction.X,
- ray.Origin.Y+t*ray.Direction.Y,
- ray.Origin.Z+t*ray.Direction.Z)
+ ABxAP := vectorsCrossProd(vectAB, vectAP)
+ ABxAPNV := scalarMultiplication(ABxAP, triangleNormV)
+ BCxBP := vectorsCrossProd(vectBC, vectBP)
+ BCxBPNV := scalarMultiplication(BCxBP, triangleNormV)
+ CAxCP := vectorsCrossProd(vectCA, vectCP)
+ CAxCPNV := scalarMultiplication(CAxCP, triangleNormV)
- triangleAPC := NewTriangle(triangle.A, intersectionPoint, triangle.C)
- triangleABP := NewTriangle(triangle.A, triangle.B, intersectionPoint)
- trianglePBC := NewTriangle(intersectionPoint, triangle.B, triangle.C)
-
- baricentPBCtoABC := trianglePBC.area() / triangle.area()
- baricentAPCtoABC := triangleAPC.area() / triangle.area()
- baricentABPtoABC := triangleABP.area() / triangle.area()
-
- if baricentPBCtoABC >= -(1e-7) && baricentPBCtoABC <= 1.0 {
- if baricentAPCtoABC >= -(1e-7) && baricentAPCtoABC <= 1.0 {
- if baricentABPtoABC >= -(1e-7) && baricentABPtoABC <= 1.0 {
- return true
- }
- }
- }
-
- return false
+ if (ABxAPNV <= epsilon && BCxBPNV <= epsilon && CAxCPNV <= epsilon) ||
+ (ABxAPNV >= -epsilon && BCxBPNV >= -epsilon && CAxCPNV >= -epsilon) {
+ return true
}
+
+ return false
}
func (triangle *Triangle) area() float64 {
- vectAB := vectorByTwoPoints(triangle.A, triangle.B)
- vectBC := vectorByTwoPoints(triangle.A, triangle.C)
+ vectAB := vectorFromAtoB(triangle.A, triangle.B)
+ vectBC := vectorFromAtoB(triangle.A, triangle.C)
normalizedVector := geom.NewVector(vectAB.Y*vectBC.Z-vectAB.Z*vectBC.Y,
vectAB.Z*vectBC.X-vectAB.X*vectBC.Z,
vectAB.X*vectBC.Y-vectAB.Y*vectBC.X)
return math.Sqrt(normalizedVector.X*normalizedVector.X+
normalizedVector.Y*normalizedVector.Y+
normalizedVector.Z*normalizedVector.Z) / 2
}
type Quadrangle struct {
- triangle Triangle
- D geom.Vector
+ Triangle
+ D geom.Vector
}
func NewQuad(a, b, c, d geom.Vector) Quadrangle {
return Quadrangle{
NewTriangle(a, b, c),
d,
}
}
func (quadrangle Quadrangle) Intersect(ray geom.Ray) bool {
- secondTriangle := NewTriangle(quadrangle.triangle.A, quadrangle.triangle.C, quadrangle.D)
- return quadrangle.triangle.Intersect(ray) ||
- secondTriangle.Intersect(ray)
+ quadPlane := newPlane(quadrangle.A, quadrangle.B, quadrangle.C)
+ _, isPlaneIntersected := quadPlane.intersetionPoint(ray)
+ if !isPlaneIntersected {
+ return false
+ }
+ normalVectorABD := vectorsCrossProd(
+ vectorFromAtoB(quadrangle.A, quadrangle.B),
+ vectorFromAtoB(quadrangle.A, quadrangle.D))
+
+ normalVectorCBD := vectorsCrossProd(
+ vectorFromAtoB(quadrangle.C, quadrangle.B),
+ vectorFromAtoB(quadrangle.C, quadrangle.D))
+
+ if scalarMultiplication(normalVectorABD, normalVectorCBD) < -epsilon {
+ // choose diagonal AC for division of the quadrangle
+ return NewTriangle(quadrangle.A, quadrangle.B, quadrangle.C).Intersect(ray) ||
+ NewTriangle(quadrangle.A, quadrangle.C, quadrangle.D).Intersect(ray)
+ } else {
+ // choose diagonal BD for division of the quadrangle
+ return NewTriangle(quadrangle.A, quadrangle.B, quadrangle.D).Intersect(ray) ||
+ NewTriangle(quadrangle.B, quadrangle.C, quadrangle.D).Intersect(ray)
+ }
}
// type quadratic equation with some useful methods
type quadrEquation struct {
a float64
b float64
c float64
}
func newQuadrEqation(a, b, c float64) quadrEquation {
return quadrEquation{
a,
b,
c,
}
}
func (qdeq *quadrEquation) discriminant() float64 {
return qdeq.b*qdeq.b - 4*qdeq.a*qdeq.c
}
func (qdeq *quadrEquation) roots() (float64, float64, int8) {
discriminant := qdeq.discriminant()
var x1 float64
var x2 float64
var cntDiffRoots int8 = 0
- if discriminant >= -(1e-7) && discriminant <= 1e-7 {
+ if discriminant >= -epsilon && discriminant <= epsilon {
x1 = -(qdeq.b) / 2 * qdeq.a
x2 = x1
cntDiffRoots = 1
- } else if discriminant > 1e-7 {
+ } else if discriminant > epsilon {
x1 = -qdeq.b + math.Sqrt(discriminant)
x2 = -qdeq.b - math.Sqrt(discriminant)
cntDiffRoots = 2
}
return x1, x2, cntDiffRoots
}
type Sphere struct {
center geom.Vector
radius float64
}
func NewSphere(origin geom.Vector, r float64) Sphere {
return Sphere{
origin,
r,
}
}
func (sphere Sphere) Intersect(ray geom.Ray) bool {
sphereQuadrEq := newQuadrEqation(
scalarMultiplication(ray.Direction, ray.Direction),
2*scalarMultiplication(
ray.Direction,
subtractVectors(ray.Origin, sphere.center)),
scalarMultiplication(
subtractVectors(ray.Origin, sphere.center),
subtractVectors(ray.Origin, sphere.center))-
sphere.radius*sphere.radius)
t1, t2, cntRoots := sphereQuadrEq.roots()
- if cntRoots == 1 && t1 >= -(1e-7) {
+ if cntRoots == 1 && t1 >= -epsilon {
return true
- } else if cntRoots == 2 && (t1 >= -(1e-7) || t2 >= -(1e-7)) {
+ } else if cntRoots == 2 && (t1 >= -epsilon || t2 >= -epsilon) {
return true
}
return false
}
// helper functions for vector operations
-func vectorByTwoPoints(point1 geom.Vector, point2 geom.Vector) geom.Vector {
+func vectorFromAtoB(point1 geom.Vector, point2 geom.Vector) geom.Vector {
return geom.NewVector(point2.X-point1.X, point2.Y-point1.Y, point2.Z-point1.Z)
}
func subtractVectors(v1 geom.Vector, v2 geom.Vector) geom.Vector {
return geom.NewVector(v1.X-v2.X, v1.Y-v2.Y, v1.Z-v2.Z)
}
func scalarMultiplication(v1 geom.Vector, v2 geom.Vector) float64 {
return v1.X*v2.X + v1.Y*v2.Y + v1.Z*v2.Z
}
+
+func vectorsCrossProd(v1 geom.Vector, v2 geom.Vector) geom.Vector {
+ return geom.Vector{
+ v1.Y*v2.Z - v1.Z*v2.Y,
+ v1.Z*v2.X - v1.X*v2.Z,
+ v1.X*v2.Y - v1.Y*v2.X,
+ }
+}

Траян обнови решението на 20.11.2018 23:19 (преди 9 месеца)

package main
import (
"github.com/fmi/go-homework/geom"
"math"
)
const epsilon = 1e-7
// type plane with some useful methods
type plane struct {
A float64
B float64
C float64
D float64
}
func newPlane(a, b, c geom.Vector) plane {
vectAB := vectorFromAtoB(a, b)
- vectBC := vectorFromAtoB(a, c)
+ vectAC := vectorFromAtoB(a, c)
normalizedVector := geom.NewVector(
- vectAB.Y*vectBC.Z-vectAB.Z*vectBC.Y,
- vectAB.Z*vectBC.X-vectAB.X*vectBC.Z,
- vectAB.X*vectBC.Y-vectAB.Y*vectBC.X)
+ vectAB.Y*vectAC.Z-vectAB.Z*vectAC.Y,
+ vectAB.Z*vectAC.X-vectAB.X*vectAC.Z,
+ vectAB.X*vectAC.Y-vectAB.Y*vectAC.X)
dValue := -(normalizedVector.X*a.X +
normalizedVector.Y*a.Y +
normalizedVector.Z*a.Z)
plane := plane{
A: normalizedVector.X,
B: normalizedVector.Y,
C: normalizedVector.Z,
D: dValue,
}
return plane
}
func (plane *plane) rayParallelToPlane(ray geom.Ray) bool {
parallelCheckSum := plane.A*ray.Direction.X +
plane.B*ray.Direction.Y +
plane.C*ray.Direction.Z
return (parallelCheckSum) >= -epsilon &&
(parallelCheckSum) <= epsilon
}
func (plane *plane) intersetionPoint(ray geom.Ray) (intersectionPoint geom.Vector, isIntersected bool) {
if !plane.rayParallelToPlane(ray) {
numerator := -(plane.A*ray.Origin.X +
plane.B*ray.Origin.Y +
plane.C*ray.Origin.Z +
plane.D)
denominator := plane.A*ray.Direction.X +
plane.B*ray.Direction.Y +
plane.C*ray.Direction.Z
t := numerator / denominator
if t < -epsilon {
return
}
isIntersected = true
intersectionPoint = geom.NewVector(ray.Origin.X+t*ray.Direction.X,
ray.Origin.Y+t*ray.Direction.Y,
ray.Origin.Z+t*ray.Direction.Z)
return
}
return
}
func (plane *plane) normalizedVector() geom.Vector {
return geom.Vector{plane.A, plane.B, plane.C}
}
type Triangle struct {
A geom.Vector
B geom.Vector
C geom.Vector
}
func NewTriangle(a, b, c geom.Vector) Triangle {
return Triangle{
a,
b,
c,
}
}
func (triangle Triangle) Intersect(ray geom.Ray) bool {
trianglePlane := newPlane(triangle.A, triangle.B, triangle.C)
intersectionPoint, isPlaneIntersected := trianglePlane.intersetionPoint(ray)
if !isPlaneIntersected {
return false
}
triangleNormV := trianglePlane.normalizedVector()
vectAP := vectorFromAtoB(triangle.A, intersectionPoint)
vectAB := vectorFromAtoB(triangle.A, triangle.B)
vectBP := vectorFromAtoB(triangle.B, intersectionPoint)
vectBC := vectorFromAtoB(triangle.B, triangle.C)
vectCP := vectorFromAtoB(triangle.C, intersectionPoint)
vectCA := vectorFromAtoB(triangle.C, triangle.A)
ABxAP := vectorsCrossProd(vectAB, vectAP)
ABxAPNV := scalarMultiplication(ABxAP, triangleNormV)
BCxBP := vectorsCrossProd(vectBC, vectBP)
BCxBPNV := scalarMultiplication(BCxBP, triangleNormV)
CAxCP := vectorsCrossProd(vectCA, vectCP)
CAxCPNV := scalarMultiplication(CAxCP, triangleNormV)
if (ABxAPNV <= epsilon && BCxBPNV <= epsilon && CAxCPNV <= epsilon) ||
(ABxAPNV >= -epsilon && BCxBPNV >= -epsilon && CAxCPNV >= -epsilon) {
return true
}
return false
}
func (triangle *Triangle) area() float64 {
vectAB := vectorFromAtoB(triangle.A, triangle.B)
vectBC := vectorFromAtoB(triangle.A, triangle.C)
normalizedVector := geom.NewVector(vectAB.Y*vectBC.Z-vectAB.Z*vectBC.Y,
vectAB.Z*vectBC.X-vectAB.X*vectBC.Z,
vectAB.X*vectBC.Y-vectAB.Y*vectBC.X)
return math.Sqrt(normalizedVector.X*normalizedVector.X+
normalizedVector.Y*normalizedVector.Y+
normalizedVector.Z*normalizedVector.Z) / 2
}
type Quadrangle struct {
Triangle
D geom.Vector
}
func NewQuad(a, b, c, d geom.Vector) Quadrangle {
return Quadrangle{
NewTriangle(a, b, c),
d,
}
}
func (quadrangle Quadrangle) Intersect(ray geom.Ray) bool {
quadPlane := newPlane(quadrangle.A, quadrangle.B, quadrangle.C)
_, isPlaneIntersected := quadPlane.intersetionPoint(ray)
if !isPlaneIntersected {
return false
}
normalVectorABD := vectorsCrossProd(
vectorFromAtoB(quadrangle.A, quadrangle.B),
vectorFromAtoB(quadrangle.A, quadrangle.D))
normalVectorCBD := vectorsCrossProd(
vectorFromAtoB(quadrangle.C, quadrangle.B),
vectorFromAtoB(quadrangle.C, quadrangle.D))
if scalarMultiplication(normalVectorABD, normalVectorCBD) < -epsilon {
// choose diagonal AC for division of the quadrangle
return NewTriangle(quadrangle.A, quadrangle.B, quadrangle.C).Intersect(ray) ||
NewTriangle(quadrangle.A, quadrangle.C, quadrangle.D).Intersect(ray)
} else {
// choose diagonal BD for division of the quadrangle
return NewTriangle(quadrangle.A, quadrangle.B, quadrangle.D).Intersect(ray) ||
NewTriangle(quadrangle.B, quadrangle.C, quadrangle.D).Intersect(ray)
}
}
// type quadratic equation with some useful methods
type quadrEquation struct {
a float64
b float64
c float64
}
func newQuadrEqation(a, b, c float64) quadrEquation {
return quadrEquation{
a,
b,
c,
}
}
func (qdeq *quadrEquation) discriminant() float64 {
return qdeq.b*qdeq.b - 4*qdeq.a*qdeq.c
}
func (qdeq *quadrEquation) roots() (float64, float64, int8) {
discriminant := qdeq.discriminant()
var x1 float64
var x2 float64
var cntDiffRoots int8 = 0
if discriminant >= -epsilon && discriminant <= epsilon {
x1 = -(qdeq.b) / 2 * qdeq.a
x2 = x1
cntDiffRoots = 1
} else if discriminant > epsilon {
x1 = -qdeq.b + math.Sqrt(discriminant)
x2 = -qdeq.b - math.Sqrt(discriminant)
cntDiffRoots = 2
}
return x1, x2, cntDiffRoots
}
type Sphere struct {
center geom.Vector
radius float64
}
func NewSphere(origin geom.Vector, r float64) Sphere {
return Sphere{
origin,
r,
}
}
func (sphere Sphere) Intersect(ray geom.Ray) bool {
sphereQuadrEq := newQuadrEqation(
scalarMultiplication(ray.Direction, ray.Direction),
2*scalarMultiplication(
ray.Direction,
subtractVectors(ray.Origin, sphere.center)),
scalarMultiplication(
subtractVectors(ray.Origin, sphere.center),
subtractVectors(ray.Origin, sphere.center))-
sphere.radius*sphere.radius)
t1, t2, cntRoots := sphereQuadrEq.roots()
if cntRoots == 1 && t1 >= -epsilon {
return true
} else if cntRoots == 2 && (t1 >= -epsilon || t2 >= -epsilon) {
return true
}
return false
}
// helper functions for vector operations
func vectorFromAtoB(point1 geom.Vector, point2 geom.Vector) geom.Vector {
return geom.NewVector(point2.X-point1.X, point2.Y-point1.Y, point2.Z-point1.Z)
}
func subtractVectors(v1 geom.Vector, v2 geom.Vector) geom.Vector {
return geom.NewVector(v1.X-v2.X, v1.Y-v2.Y, v1.Z-v2.Z)
}
func scalarMultiplication(v1 geom.Vector, v2 geom.Vector) float64 {
return v1.X*v2.X + v1.Y*v2.Y + v1.Z*v2.Z
}
func vectorsCrossProd(v1 geom.Vector, v2 geom.Vector) geom.Vector {
return geom.Vector{
v1.Y*v2.Z - v1.Z*v2.Y,
v1.Z*v2.X - v1.X*v2.Z,
v1.X*v2.Y - v1.Y*v2.X,
}
}