boundingSphere.ts 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. import { Tools } from "Tools";
  2. import { Matrix, Vector3, Plane } from "Math";
  3. /**
  4. * Class used to store bounding sphere information
  5. */
  6. export class BoundingSphere {
  7. /**
  8. * Gets the center of the bounding sphere in local space
  9. */
  10. public readonly center = Vector3.Zero();
  11. /**
  12. * Radius of the bounding sphere in local space
  13. */
  14. public radius: number;
  15. /**
  16. * Gets the center of the bounding sphere in world space
  17. */
  18. public readonly centerWorld = Vector3.Zero();
  19. /**
  20. * Radius of the bounding sphere in world space
  21. */
  22. public radiusWorld: number;
  23. /**
  24. * Gets the minimum vector in local space
  25. */
  26. public readonly minimum = Vector3.Zero();
  27. /**
  28. * Gets the maximum vector in local space
  29. */
  30. public readonly maximum = Vector3.Zero();
  31. private _worldMatrix: Readonly<Matrix>;
  32. private static readonly TmpVector3 = Tools.BuildArray(3, Vector3.Zero);
  33. /**
  34. * Creates a new bounding sphere
  35. * @param min defines the minimum vector (in local space)
  36. * @param max defines the maximum vector (in local space)
  37. * @param worldMatrix defines the new world matrix
  38. */
  39. constructor(min: Readonly<Vector3>, max: Readonly<Vector3>, worldMatrix?: Readonly<Matrix>) {
  40. this.reConstruct(min, max, worldMatrix);
  41. }
  42. /**
  43. * Recreates the entire bounding sphere from scratch as if we call the constructor in place
  44. * @param min defines the new minimum vector (in local space)
  45. * @param max defines the new maximum vector (in local space)
  46. * @param worldMatrix defines the new world matrix
  47. */
  48. public reConstruct(min: Readonly<Vector3>, max: Readonly<Vector3>, worldMatrix?: Readonly<Matrix>) {
  49. this.minimum.copyFrom(min);
  50. this.maximum.copyFrom(max);
  51. var distance = Vector3.Distance(min, max);
  52. max.addToRef(min, this.center).scaleInPlace(0.5);
  53. this.radius = distance * 0.5;
  54. this._update(worldMatrix || Matrix.IdentityReadOnly);
  55. }
  56. /**
  57. * Scale the current bounding sphere by applying a scale factor
  58. * @param factor defines the scale factor to apply
  59. * @returns the current bounding box
  60. */
  61. public scale(factor: number): BoundingSphere {
  62. const newRadius = this.radius * factor;
  63. const tmpVectors = BoundingSphere.TmpVector3;
  64. const tempRadiusVector = tmpVectors[0].setAll(newRadius);
  65. const min = this.center.subtractToRef(tempRadiusVector, tmpVectors[1]);
  66. const max = this.center.addToRef(tempRadiusVector, tmpVectors[2]);
  67. this.reConstruct(min, max, this._worldMatrix);
  68. return this;
  69. }
  70. /**
  71. * Gets the world matrix of the bounding box
  72. * @returns a matrix
  73. */
  74. public getWorldMatrix(): Readonly<Matrix> {
  75. return this._worldMatrix;
  76. }
  77. // Methods
  78. /** @hidden */
  79. public _update(worldMatrix: Readonly<Matrix>): void {
  80. if (!worldMatrix.isIdentity()) {
  81. Vector3.TransformCoordinatesToRef(this.center, worldMatrix, this.centerWorld);
  82. const tempVector = BoundingSphere.TmpVector3[0];
  83. Vector3.TransformNormalFromFloatsToRef(1.0, 1.0, 1.0, worldMatrix, tempVector);
  84. this.radiusWorld = Math.max(Math.abs(tempVector.x), Math.abs(tempVector.y), Math.abs(tempVector.z)) * this.radius;
  85. }
  86. else {
  87. this.centerWorld.copyFrom(this.center);
  88. this.radiusWorld = this.radius;
  89. }
  90. }
  91. /**
  92. * Tests if the bounding sphere is intersecting the frustum planes
  93. * @param frustumPlanes defines the frustum planes to test
  94. * @returns true if there is an intersection
  95. */
  96. public isInFrustum(frustumPlanes: Array<Readonly<Plane>>): boolean {
  97. for (var i = 0; i < 6; i++) {
  98. if (frustumPlanes[i].dotCoordinate(this.centerWorld) <= -this.radiusWorld) {
  99. return false;
  100. }
  101. }
  102. return true;
  103. }
  104. /**
  105. * Tests if a point is inside the bounding sphere
  106. * @param point defines the point to test
  107. * @returns true if the point is inside the bounding sphere
  108. */
  109. public intersectsPoint(point: Readonly<Vector3>): boolean {
  110. const squareDistance = Vector3.DistanceSquared(this.centerWorld, point);
  111. if (this.radiusWorld * this.radiusWorld < squareDistance) {
  112. return false;
  113. }
  114. return true;
  115. }
  116. // Statics
  117. /**
  118. * Checks if two sphere intersct
  119. * @param sphere0 sphere 0
  120. * @param sphere1 sphere 1
  121. * @returns true if the speres intersect
  122. */
  123. public static Intersects(sphere0: Readonly<BoundingSphere>, sphere1: Readonly<BoundingSphere>): boolean {
  124. const squareDistance = Vector3.DistanceSquared(sphere0.centerWorld, sphere1.centerWorld);
  125. const radiusSum = sphere0.radiusWorld + sphere1.radiusWorld;
  126. if (radiusSum * radiusSum < squareDistance) {
  127. return false;
  128. }
  129. return true;
  130. }
  131. }