plane.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  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. // Plane represents a plane in 3D space by its normal vector and a constant.
  7. // When the the normal vector is the unit vector the constant is the distance from the origin.
  8. type Plane struct {
  9. normal Vector3
  10. constant float32
  11. }
  12. // NewPlane creates and returns a new plane from a normal vector and a constant.
  13. func NewPlane(normal *Vector3, constant float32) *Plane {
  14. p := new(Plane)
  15. if normal != nil {
  16. p.normal = *normal
  17. }
  18. p.constant = constant
  19. return p
  20. }
  21. // Set sets this plane normal vector and constant.
  22. // Returns pointer to this updated plane.
  23. func (p *Plane) Set(normal *Vector3, constant float32) *Plane {
  24. p.normal = *normal
  25. p.constant = constant
  26. return p
  27. }
  28. // SetComponents sets this plane normal vector components and constant.
  29. // Returns pointer to this updated plane.
  30. func (p *Plane) SetComponents(x, y, z, w float32) *Plane {
  31. p.normal.Set(x, y, z)
  32. p.constant = w
  33. return p
  34. }
  35. // SetFromNormalAndCoplanarPoint sets this plane from a normal vector and a point on the plane.
  36. // Returns pointer to this updated plane.
  37. func (p *Plane) SetFromNormalAndCoplanarPoint(normal *Vector3, point *Vector3) *Plane {
  38. p.normal = *normal
  39. p.constant = -point.Dot(&p.normal)
  40. return p
  41. }
  42. // SetFromCoplanarPoints sets this plane from three coplanar points.
  43. // Returns pointer to this updated plane.
  44. func (p *Plane) SetFromCoplanarPoints(a, b, c *Vector3) *Plane {
  45. var v1 Vector3
  46. var v2 Vector3
  47. normal := v1.SubVectors(c, b).Cross(v2.SubVectors(a, b)).Normalize()
  48. // Q: should an error be thrown if normal is zero (e.g. degenerate plane)?
  49. p.SetFromNormalAndCoplanarPoint(normal, a)
  50. return p
  51. }
  52. // Copy sets this plane to a copy of other.
  53. // Returns pointer to this updated plane.
  54. func (p *Plane) Copy(other *Plane) *Plane {
  55. p.normal.Copy(&other.normal)
  56. p.constant = other.constant
  57. return p
  58. }
  59. // Normalize normalizes this plane normal vector and adjusts the constant.
  60. // Note: will lead to a divide by zero if the plane is invalid.
  61. // Returns pointer to this updated plane.
  62. func (p *Plane) Normalize() *Plane {
  63. inverseNormalLength := 1.0 / p.normal.Length()
  64. p.normal.MultiplyScalar(inverseNormalLength)
  65. p.constant *= inverseNormalLength
  66. return p
  67. }
  68. // Negate negates this plane normal.
  69. // Returns pointer to this updated plane.
  70. func (p *Plane) Negate() *Plane {
  71. p.constant *= -1
  72. p.normal.Negate()
  73. return p
  74. }
  75. // DistanceToPoint returns the distance of this plane from point.
  76. func (p *Plane) DistanceToPoint(point *Vector3) float32 {
  77. return p.normal.Dot(point) + p.constant
  78. }
  79. // DistanceToSphere returns the distance of this place from the sphere.
  80. func (p *Plane) DistanceToSphere(sphere *Sphere) float32 {
  81. return p.DistanceToPoint(&sphere.Center) - sphere.Radius
  82. }
  83. // IsIntersectionLine returns the line intersects this plane.
  84. func (p *Plane) IsIntersectionLine(line *Line3) bool {
  85. startSign := p.DistanceToPoint(&line.start)
  86. endSign := p.DistanceToPoint(&line.end)
  87. return (startSign < 0 && endSign > 0) || (endSign < 0 && startSign > 0)
  88. }
  89. // IntersectLine calculates the point in the plane which intersets the specified line.
  90. // Sets the optionalTarget, if not nil to this point, and also returns it.
  91. // Returns nil if the line does not intersects the plane.
  92. func (p *Plane) IntersectLine(line *Line3, optionalTarget *Vector3) *Vector3 {
  93. var v1 Vector3
  94. var result *Vector3
  95. if optionalTarget == nil {
  96. result = NewVector3(0, 0, 0)
  97. } else {
  98. result = optionalTarget
  99. }
  100. direction := line.Delta(&v1)
  101. denominator := p.normal.Dot(direction)
  102. if denominator == 0 {
  103. // line is coplanar, return origin
  104. if p.DistanceToPoint(&line.start) == 0 {
  105. return result.Copy(&line.start)
  106. }
  107. // Unsure if this is the correct method to handle this case.
  108. return nil
  109. }
  110. var t = -(line.start.Dot(&p.normal) + p.constant) / denominator
  111. if t < 0 || t > 1 {
  112. return nil
  113. }
  114. return result.Copy(direction).MultiplyScalar(t).Add(&line.start)
  115. }
  116. // CoplanarPoint sets the optionalTarget to a point in the plane and also returns it.
  117. // The point set and returned is the closest point from the origin.
  118. func (p *Plane) CoplanarPoint(optionalTarget *Vector3) *Vector3 {
  119. var result *Vector3
  120. if optionalTarget == nil {
  121. result = NewVector3(0, 0, 0)
  122. } else {
  123. result = optionalTarget
  124. }
  125. return result.Copy(&p.normal).MultiplyScalar(-p.constant)
  126. }
  127. // Translate translates this plane in the direction of its normal by offset.
  128. // Returns pointer to this updated plane.
  129. func (p *Plane) Translate(offset *Vector3) *Plane {
  130. p.constant = p.constant - offset.Dot(&p.normal)
  131. return p
  132. }
  133. // Equals returns if this plane is equal to other
  134. func (p *Plane) Equals(other *Plane) bool {
  135. return other.normal.Equals(&p.normal) && (other.constant == p.constant)
  136. }
  137. // Clone creates and returns a pointer to a copy of this plane.
  138. func (p *Plane) Clone(plane *Plane) *Plane {
  139. return NewPlane(&plane.normal, plane.constant)
  140. }