Слави обнови решението на 21.11.2018 06:47 (преди 9 месеца)
+package main
+
+import (
+ "github.com/fmi/go-homework/geom"
+ "math"
+)
+
+type vector geom.Vector
+
+func newVector(x, y, z float64) vector {
+ return vector(geom.NewVector(x, y, z))
+}
+
+func vectorFromTo(
+ origin point,
+ destination point,
+) vector {
+ return newVector(
+ destination.X-origin.X,
+ destination.Y-origin.Y,
+ destination.Z-origin.Z,
+ )
+}
+
+func (self vector) dot(other vector) float64 {
+ return self.X*other.X + self.Y*other.Y + self.Z*other.Z
+}
+
+func (self vector) cross(other vector) vector {
+ return newVector(
+ self.Y*other.Z-self.Z*other.Y,
+ self.Z*other.X-self.X*other.Z,
+ self.X*other.Y-self.Y*other.X,
+ )
+}
+
+func (self vector) scale(scalar float64) vector {
+ return newVector(
+ self.X*scalar,
+ self.Y*scalar,
+ self.Z*scalar,
+ )
+}
+
+func (self vector) length() float64 {
+ return math.Sqrt(self.dot(self))
+}
+
+func (self vector) project(on vector) vector {
+ return on.scale(self.dot(on) / on.dot(on))
+}
+
+func (self vector) sameDirection(as vector) bool {
+ return self.dot(as) > 0
+}
+
+func (self vector) subtract(other vector) vector {
+ return newVector(
+ self.X-other.X,
+ self.Y-other.Y,
+ self.Z-other.Z,
+ )
+}
+
+type point geom.Vector
+
+func newPoint(x, y, z float64) point {
+ return point(geom.NewVector(x, y, z))
+}
+
+func (self point) translate(with vector) point {
+ return newPoint(
+ self.X+with.X,
+ self.Y+with.Y,
+ self.Z+with.Z,
+ )
+}
+
+func (self point) squareDistance(to point) float64 {
+ vec := vectorFromTo(self, to)
+ return vec.dot(vec)
+}
+
+func deconstruct(ray geom.Ray) (point, vector) {
+ return point(ray.Origin), vector(ray.Direction)
+}
+
+type plane struct {
+ normal vector
+ member point
+}
+
+func newPlane(x, y, z point) plane {
+ coVector1 := vectorFromTo(x, y)
+ coVector2 := vectorFromTo(x, z)
+ return plane{
+ normal: coVector1.cross(coVector2),
+ member: x,
+ }
+}
+
+func (self plane) intersectWith(ray geom.Ray) (
+ intersects bool,
+ intersection point,
+) {
+ origin, direction := deconstruct(ray)
+ originToPlane := vectorFromTo(
+ origin,
+ self.member,
+ )
+ scalar := direction.dot(self.normal) /
+ originToPlane.dot(self.normal)
+ intersects = (scalar > 0)
+ if intersects {
+ intersection = origin.translate(
+ direction.scale(scalar),
+ )
+ }
+ return
+}
+
+type triangle struct {
+ a, b, c point
+ p plane
+}
+
+func newTriangle(a, b, c point) triangle {
+ return triangle{
+ a: a,
+ b: b,
+ c: c,
+ p: newPlane(a, b, c),
+ }
+}
+
+func NewTriangle(a, b, c geom.Vector) triangle {
+ return newTriangle(
+ point(a),
+ point(b),
+ point(c),
+ )
+}
+
+func (self triangle) area() float64 {
+ return self.p.normal.length() / 2
+}
+
+func (self triangle) contains(p point) bool {
+
+ pab, pbc, pac := newTriangle(p, self.a, self.b),
+ newTriangle(p, self.c, self.b),
+ newTriangle(p, self.a, self.c)
+ return (pab.area() + pbc.area() + pac.area() - self.area()) < 1e-7
+}
+
+func (self triangle) Intersect(ray geom.Ray) bool {
+ intersects, intersection := self.p.intersectWith(ray)
+ if !intersects {
+ return false
+ }
+
+ return self.contains(intersection)
+}
+
+type quad struct {
+ firstTri, secondTri triangle
+}
+
+func NewQuad(a, b, c, d geom.Vector) (result quad) {
+ result = quad{
+ firstTri: NewTriangle(a, b, c),
+ secondTri: NewTriangle(a, c, d),
+ }
+ if result.firstTri.contains(point(d)) ||
+ result.secondTri.contains(point(b)) {
+
+ result = quad{
+ firstTri: NewTriangle(a, b, d),
+ secondTri: NewTriangle(b, c, d),
+ }
+ }
+ return
+}
+
+func (self quad) Intersect(ray geom.Ray) bool {
+ return self.firstTri.Intersect(ray) ||
+ self.secondTri.Intersect(ray)
+}
+
+type sphere struct {
+ center point
+ radiusSquare float64
+}
+
+func NewSphere(center geom.Vector, radius float64) sphere {
+ return sphere{
+ center: point(center),
+ radiusSquare: radius * radius,
+ }
+}
+
+func (self sphere) Intersect(ray geom.Ray) bool {
+ origin, direction := deconstruct(ray)
+ if self.center.squareDistance(origin) <= self.radiusSquare {
+ return true
+ }
+
+ originToCenterPoint := vectorFromTo(
+ origin,
+ self.center,
+ )
+
+ projection := originToCenterPoint.project(direction)
+
+ if !projection.sameDirection(direction) {
+ return false
+ }
+
+ closestPoint := origin.translate(projection)
+
+ return self.center.squareDistance(closestPoint) <= self.radiusSquare
+}
+
+func main() {
+ a, b, c := geom.NewVector(-1, -1, 0), geom.NewVector(1, -1, 0), geom.NewVector(1, 1, 0)
+ prim := NewTriangle(a, b, c)
+ ray := geom.NewRay(geom.NewVector(0, 0, 1), geom.NewVector(0, 0, -1))
+ _ = prim.Intersect(ray)
+}