| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197 |
- // Copyright 2016 The G3N Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- package math32
- import ()
- type Plane struct {
- normal Vector3
- constant float32
- }
- func NewPlane(normal *Vector3, constant float32) *Plane {
- this := new(Plane)
- if normal != nil {
- this.normal = *normal
- }
- this.constant = constant
- return this
- }
- func (this *Plane) Set(normal *Vector3, constant float32) *Plane {
- this.normal = *normal
- this.constant = constant
- return this
- }
- func (this *Plane) SetComponents(x, y, z, w float32) *Plane {
- this.normal.Set(x, y, z)
- this.constant = w
- return this
- }
- func (this *Plane) SetFromNormalAndCoplanarPoint(normal *Vector3, point *Vector3) *Plane {
- this.normal.Copy(normal)
- this.constant = -point.Dot(&this.normal)
- return this
- }
- func (this *Plane) SetFromCoplanarPoints(a, b, c *Vector3) *Plane {
- var v1 Vector3
- var v2 Vector3
- normal := v1.SubVectors(c, b).Cross(v2.SubVectors(a, b)).Normalize()
- // Q: should an error be thrown if normal is zero (e.g. degenerate plane)?
- this.SetFromNormalAndCoplanarPoint(normal, a)
- return this
- }
- func (this *Plane) Copy(plane *Plane) *Plane {
- this.normal.Copy(&plane.normal)
- this.constant = plane.constant
- return this
- }
- func (this *Plane) Normalize() *Plane {
- // Note: will lead to a divide by zero if the plane is invalid.
- inverseNormalLength := 1.0 / this.normal.Length()
- this.normal.MultiplyScalar(inverseNormalLength)
- this.constant *= inverseNormalLength
- return this
- }
- func (this *Plane) Negate() *Plane {
- this.constant *= -1
- this.normal.Negate()
- return this
- }
- func (this *Plane) DistanceToPoint(point *Vector3) float32 {
- return this.normal.Dot(point) + this.constant
- }
- func (this *Plane) DistanceToSphere(sphere *Sphere) float32 {
- return this.DistanceToPoint(&sphere.Center) - sphere.Radius
- }
- func (this *Plane) ProjectPoint(point *Vector3, optionalTarget *Vector3) *Vector3 {
- return this.OrthoPoint(point, optionalTarget).Sub(point).Negate()
- }
- func (this *Plane) OrthoPoint(point *Vector3, optionalTarget *Vector3) *Vector3 {
- var result *Vector3
- if optionalTarget == nil {
- result = NewVector3(0, 0, 0)
- } else {
- result = optionalTarget
- }
- perpendicularMagnitude := this.DistanceToPoint(point)
- return result.Copy(&this.normal).MultiplyScalar(perpendicularMagnitude)
- }
- func (this *Plane) IsIntersectionLine(line *Line3) bool {
- // Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it.
- startSign := this.DistanceToPoint(&line.start)
- endSign := this.DistanceToPoint(&line.end)
- return (startSign < 0 && endSign > 0) || (endSign < 0 && startSign > 0)
- }
- func (this *Plane) IntersectLine(line *Line3, optionalTarget *Vector3) *Vector3 {
- var v1 Vector3
- var result *Vector3
- if optionalTarget == nil {
- result = NewVector3(0, 0, 0)
- } else {
- result = optionalTarget
- }
- direction := line.Delta(&v1)
- denominator := this.normal.Dot(direction)
- if denominator == 0 {
- // line is coplanar, return origin
- if this.DistanceToPoint(&line.start) == 0 {
- return result.Copy(&line.start)
- }
- // Unsure if this is the correct method to handle this case.
- return nil
- }
- var t = -(line.start.Dot(&this.normal) + this.constant) / denominator
- if t < 0 || t > 1 {
- return nil
- }
- return result.Copy(direction).MultiplyScalar(t).Add(&line.start)
- }
- func (this *Plane) CoplanarPoint(optionalTarget *Vector3) *Vector3 {
- var result *Vector3
- if optionalTarget == nil {
- result = NewVector3(0, 0, 0)
- } else {
- result = optionalTarget
- }
- return result.Copy(&this.normal).MultiplyScalar(-this.constant)
- }
- func (this *Plane) ApplyMatrix4(matrix *Matrix4, optionalNormalMatrix *Matrix3) (*Plane, error) {
- // compute new normal based on theory here:
- // http://www.songho.ca/opengl/gl_normaltransform.html
- var v1 Vector3
- var v2 Vector3
- m1 := NewMatrix3()
- var normalMatrix *Matrix3
- var err error
- if optionalNormalMatrix != nil {
- normalMatrix = optionalNormalMatrix
- } else {
- normalMatrix, err = m1.GetNormalMatrix(matrix)
- if err != nil {
- return nil, err
- }
- }
- newNormal := v1.Copy(&this.normal).ApplyMatrix3(normalMatrix)
- newCoplanarPoint := this.CoplanarPoint(&v2)
- newCoplanarPoint.ApplyMatrix4(matrix)
- this.SetFromNormalAndCoplanarPoint(newNormal, newCoplanarPoint)
- return this, nil
- }
- func (this *Plane) Translate(offset *Vector3) *Plane {
- this.constant = this.constant - offset.Dot(&this.normal)
- return this
- }
- func (this *Plane) Equals(plane *Plane) bool {
- return plane.normal.Equals(&this.normal) && (plane.constant == this.constant)
- }
- func (this *Plane) Clone(plane *Plane) *Plane {
- return NewPlane(&plane.normal, plane.constant)
- }
|