plane.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. // Copyright 2016 The G3N Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package math32
  5. import ()
  6. type Plane struct {
  7. normal Vector3
  8. constant float32
  9. }
  10. func NewPlane(normal *Vector3, constant float32) *Plane {
  11. this := new(Plane)
  12. if normal != nil {
  13. this.normal = *normal
  14. }
  15. this.constant = constant
  16. return this
  17. }
  18. func (this *Plane) Set(normal *Vector3, constant float32) *Plane {
  19. this.normal = *normal
  20. this.constant = constant
  21. return this
  22. }
  23. func (this *Plane) SetComponents(x, y, z, w float32) *Plane {
  24. this.normal.Set(x, y, z)
  25. this.constant = w
  26. return this
  27. }
  28. func (this *Plane) SetFromNormalAndCoplanarPoint(normal *Vector3, point *Vector3) *Plane {
  29. this.normal.Copy(normal)
  30. this.constant = -point.Dot(&this.normal)
  31. return this
  32. }
  33. func (this *Plane) SetFromCoplanarPoints(a, b, c *Vector3) *Plane {
  34. var v1 Vector3
  35. var v2 Vector3
  36. normal := v1.SubVectors(c, b).Cross(v2.SubVectors(a, b)).Normalize()
  37. // Q: should an error be thrown if normal is zero (e.g. degenerate plane)?
  38. this.SetFromNormalAndCoplanarPoint(normal, a)
  39. return this
  40. }
  41. func (this *Plane) Copy(plane *Plane) *Plane {
  42. this.normal.Copy(&plane.normal)
  43. this.constant = plane.constant
  44. return this
  45. }
  46. func (this *Plane) Normalize() *Plane {
  47. // Note: will lead to a divide by zero if the plane is invalid.
  48. inverseNormalLength := 1.0 / this.normal.Length()
  49. this.normal.MultiplyScalar(inverseNormalLength)
  50. this.constant *= inverseNormalLength
  51. return this
  52. }
  53. func (this *Plane) Negate() *Plane {
  54. this.constant *= -1
  55. this.normal.Negate()
  56. return this
  57. }
  58. func (this *Plane) DistanceToPoint(point *Vector3) float32 {
  59. return this.normal.Dot(point) + this.constant
  60. }
  61. func (this *Plane) DistanceToSphere(sphere *Sphere) float32 {
  62. return this.DistanceToPoint(&sphere.Center) - sphere.Radius
  63. }
  64. func (this *Plane) ProjectPoint(point *Vector3, optionalTarget *Vector3) *Vector3 {
  65. return this.OrthoPoint(point, optionalTarget).Sub(point).Negate()
  66. }
  67. func (this *Plane) OrthoPoint(point *Vector3, optionalTarget *Vector3) *Vector3 {
  68. var result *Vector3
  69. if optionalTarget == nil {
  70. result = NewVector3(0, 0, 0)
  71. } else {
  72. result = optionalTarget
  73. }
  74. perpendicularMagnitude := this.DistanceToPoint(point)
  75. return result.Copy(&this.normal).MultiplyScalar(perpendicularMagnitude)
  76. }
  77. func (this *Plane) IsIntersectionLine(line *Line3) bool {
  78. // Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it.
  79. startSign := this.DistanceToPoint(&line.start)
  80. endSign := this.DistanceToPoint(&line.end)
  81. return (startSign < 0 && endSign > 0) || (endSign < 0 && startSign > 0)
  82. }
  83. func (this *Plane) IntersectLine(line *Line3, optionalTarget *Vector3) *Vector3 {
  84. var v1 Vector3
  85. var result *Vector3
  86. if optionalTarget == nil {
  87. result = NewVector3(0, 0, 0)
  88. } else {
  89. result = optionalTarget
  90. }
  91. direction := line.Delta(&v1)
  92. denominator := this.normal.Dot(direction)
  93. if denominator == 0 {
  94. // line is coplanar, return origin
  95. if this.DistanceToPoint(&line.start) == 0 {
  96. return result.Copy(&line.start)
  97. }
  98. // Unsure if this is the correct method to handle this case.
  99. return nil
  100. }
  101. var t = -(line.start.Dot(&this.normal) + this.constant) / denominator
  102. if t < 0 || t > 1 {
  103. return nil
  104. }
  105. return result.Copy(direction).MultiplyScalar(t).Add(&line.start)
  106. }
  107. func (this *Plane) CoplanarPoint(optionalTarget *Vector3) *Vector3 {
  108. var result *Vector3
  109. if optionalTarget == nil {
  110. result = NewVector3(0, 0, 0)
  111. } else {
  112. result = optionalTarget
  113. }
  114. return result.Copy(&this.normal).MultiplyScalar(-this.constant)
  115. }
  116. func (this *Plane) ApplyMatrix4(matrix *Matrix4, optionalNormalMatrix *Matrix3) (*Plane, error) {
  117. // compute new normal based on theory here:
  118. // http://www.songho.ca/opengl/gl_normaltransform.html
  119. var v1 Vector3
  120. var v2 Vector3
  121. m1 := NewMatrix3()
  122. var normalMatrix *Matrix3
  123. var err error
  124. if optionalNormalMatrix != nil {
  125. normalMatrix = optionalNormalMatrix
  126. } else {
  127. normalMatrix, err = m1.GetNormalMatrix(matrix)
  128. if err != nil {
  129. return nil, err
  130. }
  131. }
  132. newNormal := v1.Copy(&this.normal).ApplyMatrix3(normalMatrix)
  133. newCoplanarPoint := this.CoplanarPoint(&v2)
  134. newCoplanarPoint.ApplyMatrix4(matrix)
  135. this.SetFromNormalAndCoplanarPoint(newNormal, newCoplanarPoint)
  136. return this, nil
  137. }
  138. func (this *Plane) Translate(offset *Vector3) *Plane {
  139. this.constant = this.constant - offset.Dot(&this.normal)
  140. return this
  141. }
  142. func (this *Plane) Equals(plane *Plane) bool {
  143. return plane.normal.Equals(&this.normal) && (plane.constant == this.constant)
  144. }
  145. func (this *Plane) Clone(plane *Plane) *Plane {
  146. return NewPlane(&plane.normal, plane.constant)
  147. }