Triangle.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. import { Vector3 } from './Vector3';
  2. import { Line3 } from './Line3';
  3. import { Plane } from './Plane';
  4. /**
  5. * @author bhouston / http://clara.io
  6. * @author mrdoob / http://mrdoob.com/
  7. */
  8. function Triangle( a, b, c ) {
  9. this.a = ( a !== undefined ) ? a : new Vector3();
  10. this.b = ( b !== undefined ) ? b : new Vector3();
  11. this.c = ( c !== undefined ) ? c : new Vector3();
  12. }
  13. Triangle.normal = function () {
  14. var v0 = new Vector3();
  15. return function normal( a, b, c, optionalTarget ) {
  16. var result = optionalTarget || new Vector3();
  17. result.subVectors( c, b );
  18. v0.subVectors( a, b );
  19. result.cross( v0 );
  20. var resultLengthSq = result.lengthSq();
  21. if ( resultLengthSq > 0 ) {
  22. return result.multiplyScalar( 1 / Math.sqrt( resultLengthSq ) );
  23. }
  24. return result.set( 0, 0, 0 );
  25. };
  26. }();
  27. // static/instance method to calculate barycentric coordinates
  28. // based on: http://www.blackpawn.com/texts/pointinpoly/default.html
  29. Triangle.barycoordFromPoint = function () {
  30. var v0 = new Vector3();
  31. var v1 = new Vector3();
  32. var v2 = new Vector3();
  33. return function barycoordFromPoint( point, a, b, c, optionalTarget ) {
  34. v0.subVectors( c, a );
  35. v1.subVectors( b, a );
  36. v2.subVectors( point, a );
  37. var dot00 = v0.dot( v0 );
  38. var dot01 = v0.dot( v1 );
  39. var dot02 = v0.dot( v2 );
  40. var dot11 = v1.dot( v1 );
  41. var dot12 = v1.dot( v2 );
  42. var denom = ( dot00 * dot11 - dot01 * dot01 );
  43. var result = optionalTarget || new Vector3();
  44. // collinear or singular triangle
  45. if ( denom === 0 ) {
  46. // arbitrary location outside of triangle?
  47. // not sure if this is the best idea, maybe should be returning undefined
  48. return result.set( - 2, - 1, - 1 );
  49. }
  50. var invDenom = 1 / denom;
  51. var u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
  52. var v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
  53. // barycentric coordinates must always sum to 1
  54. return result.set( 1 - u - v, v, u );
  55. };
  56. }();
  57. Triangle.containsPoint = function () {
  58. var v1 = new Vector3();
  59. return function containsPoint( point, a, b, c ) {
  60. var result = Triangle.barycoordFromPoint( point, a, b, c, v1 );
  61. return ( result.x >= 0 ) && ( result.y >= 0 ) && ( ( result.x + result.y ) <= 1 );
  62. };
  63. }();
  64. Triangle.prototype = {
  65. constructor: Triangle,
  66. set: function ( a, b, c ) {
  67. this.a.copy( a );
  68. this.b.copy( b );
  69. this.c.copy( c );
  70. return this;
  71. },
  72. setFromPointsAndIndices: function ( points, i0, i1, i2 ) {
  73. this.a.copy( points[ i0 ] );
  74. this.b.copy( points[ i1 ] );
  75. this.c.copy( points[ i2 ] );
  76. return this;
  77. },
  78. clone: function () {
  79. return new this.constructor().copy( this );
  80. },
  81. copy: function ( triangle ) {
  82. this.a.copy( triangle.a );
  83. this.b.copy( triangle.b );
  84. this.c.copy( triangle.c );
  85. return this;
  86. },
  87. area: function () {
  88. var v0 = new Vector3();
  89. var v1 = new Vector3();
  90. return function area() {
  91. v0.subVectors( this.c, this.b );
  92. v1.subVectors( this.a, this.b );
  93. return v0.cross( v1 ).length() * 0.5;
  94. };
  95. }(),
  96. midpoint: function ( optionalTarget ) {
  97. var result = optionalTarget || new Vector3();
  98. return result.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 );
  99. },
  100. normal: function ( optionalTarget ) {
  101. return Triangle.normal( this.a, this.b, this.c, optionalTarget );
  102. },
  103. plane: function ( optionalTarget ) {
  104. var result = optionalTarget || new Plane();
  105. return result.setFromCoplanarPoints( this.a, this.b, this.c );
  106. },
  107. barycoordFromPoint: function ( point, optionalTarget ) {
  108. return Triangle.barycoordFromPoint( point, this.a, this.b, this.c, optionalTarget );
  109. },
  110. containsPoint: function ( point ) {
  111. return Triangle.containsPoint( point, this.a, this.b, this.c );
  112. },
  113. closestPointToPoint: function () {
  114. var plane, edgeList, projectedPoint, closestPoint;
  115. return function closestPointToPoint( point, optionalTarget ) {
  116. if ( plane === undefined ) {
  117. plane = new Plane();
  118. edgeList = [ new Line3(), new Line3(), new Line3() ];
  119. projectedPoint = new Vector3();
  120. closestPoint = new Vector3();
  121. }
  122. var result = optionalTarget || new Vector3();
  123. var minDistance = Infinity;
  124. // project the point onto the plane of the triangle
  125. plane.setFromCoplanarPoints( this.a, this.b, this.c );
  126. plane.projectPoint( point, projectedPoint );
  127. // check if the projection lies within the triangle
  128. if( this.containsPoint( projectedPoint ) === true ) {
  129. // if so, this is the closest point
  130. result.copy( projectedPoint );
  131. } else {
  132. // if not, the point falls outside the triangle. the result is the closest point to the triangle's edges or vertices
  133. edgeList[ 0 ].set( this.a, this.b );
  134. edgeList[ 1 ].set( this.b, this.c );
  135. edgeList[ 2 ].set( this.c, this.a );
  136. for( var i = 0; i < edgeList.length; i ++ ) {
  137. edgeList[ i ].closestPointToPoint( projectedPoint, true, closestPoint );
  138. var distance = projectedPoint.distanceToSquared( closestPoint );
  139. if( distance < minDistance ) {
  140. minDistance = distance;
  141. result.copy( closestPoint );
  142. }
  143. }
  144. }
  145. return result;
  146. };
  147. }(),
  148. equals: function ( triangle ) {
  149. return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c );
  150. }
  151. };
  152. export { Triangle };
粤ICP备19079148号