Triangle.js 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. import { Vector3 } from './Vector3.js';
  2. /**
  3. * @author bhouston / http://clara.io
  4. * @author mrdoob / http://mrdoob.com/
  5. */
  6. function Triangle( a, b, c ) {
  7. this.a = ( a !== undefined ) ? a : new Vector3();
  8. this.b = ( b !== undefined ) ? b : new Vector3();
  9. this.c = ( c !== undefined ) ? c : new Vector3();
  10. }
  11. Object.assign( Triangle, {
  12. getNormal: function () {
  13. var v0 = new Vector3();
  14. return function getNormal( a, b, c, target ) {
  15. if ( target === undefined ) {
  16. console.warn( 'THREE.Triangle: .getNormal() target is now required' );
  17. target = new Vector3();
  18. }
  19. target.subVectors( c, b );
  20. v0.subVectors( a, b );
  21. target.cross( v0 );
  22. var targetLengthSq = target.lengthSq();
  23. if ( targetLengthSq > 0 ) {
  24. return target.multiplyScalar( 1 / Math.sqrt( targetLengthSq ) );
  25. }
  26. return target.set( 0, 0, 0 );
  27. };
  28. }(),
  29. // static/instance method to calculate barycentric coordinates
  30. // based on: http://www.blackpawn.com/texts/pointinpoly/default.html
  31. getBarycoord: function () {
  32. var v0 = new Vector3();
  33. var v1 = new Vector3();
  34. var v2 = new Vector3();
  35. return function getBarycoord( point, a, b, c, target ) {
  36. v0.subVectors( c, a );
  37. v1.subVectors( b, a );
  38. v2.subVectors( point, a );
  39. var dot00 = v0.dot( v0 );
  40. var dot01 = v0.dot( v1 );
  41. var dot02 = v0.dot( v2 );
  42. var dot11 = v1.dot( v1 );
  43. var dot12 = v1.dot( v2 );
  44. var denom = ( dot00 * dot11 - dot01 * dot01 );
  45. if ( target === undefined ) {
  46. console.warn( 'THREE.Triangle: .getBarycoord() target is now required' );
  47. target = new Vector3();
  48. }
  49. // collinear or singular triangle
  50. if ( denom === 0 ) {
  51. // arbitrary location outside of triangle?
  52. // not sure if this is the best idea, maybe should be returning undefined
  53. return target.set( - 2, - 1, - 1 );
  54. }
  55. var invDenom = 1 / denom;
  56. var u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
  57. var v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
  58. // barycentric coordinates must always sum to 1
  59. return target.set( 1 - u - v, v, u );
  60. };
  61. }(),
  62. containsPoint: function () {
  63. var v1 = new Vector3();
  64. return function containsPoint( point, a, b, c ) {
  65. Triangle.getBarycoord( point, a, b, c, v1 );
  66. return ( v1.x >= 0 ) && ( v1.y >= 0 ) && ( ( v1.x + v1.y ) <= 1 );
  67. };
  68. }(),
  69. getUV: function () {
  70. var barycoord = new Vector3();
  71. return function getUV( point, p1, p2, p3, uv1, uv2, uv3, target ) {
  72. this.getBarycoord( point, p1, p2, p3, barycoord );
  73. target.set( 0, 0 );
  74. target.addScaledVector( uv1, barycoord.x );
  75. target.addScaledVector( uv2, barycoord.y );
  76. target.addScaledVector( uv3, barycoord.z );
  77. return target;
  78. };
  79. }(),
  80. isFrontFacing: function () {
  81. var v0 = new Vector3();
  82. var v1 = new Vector3();
  83. return function isFrontFacing( a, b, c, direction ) {
  84. v0.subVectors( c, b );
  85. v1.subVectors( a, b );
  86. // strictly front facing
  87. return ( v0.cross( v1 ).dot( direction ) < 0 ) ? true : false;
  88. };
  89. }()
  90. } );
  91. Object.assign( Triangle.prototype, {
  92. set: function ( a, b, c ) {
  93. this.a.copy( a );
  94. this.b.copy( b );
  95. this.c.copy( c );
  96. return this;
  97. },
  98. setFromPointsAndIndices: function ( points, i0, i1, i2 ) {
  99. this.a.copy( points[ i0 ] );
  100. this.b.copy( points[ i1 ] );
  101. this.c.copy( points[ i2 ] );
  102. return this;
  103. },
  104. clone: function () {
  105. return new this.constructor().copy( this );
  106. },
  107. copy: function ( triangle ) {
  108. this.a.copy( triangle.a );
  109. this.b.copy( triangle.b );
  110. this.c.copy( triangle.c );
  111. return this;
  112. },
  113. getArea: function () {
  114. var v0 = new Vector3();
  115. var v1 = new Vector3();
  116. return function getArea() {
  117. v0.subVectors( this.c, this.b );
  118. v1.subVectors( this.a, this.b );
  119. return v0.cross( v1 ).length() * 0.5;
  120. };
  121. }(),
  122. getMidpoint: function ( target ) {
  123. if ( target === undefined ) {
  124. console.warn( 'THREE.Triangle: .getMidpoint() target is now required' );
  125. target = new Vector3();
  126. }
  127. return target.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 );
  128. },
  129. getNormal: function ( target ) {
  130. return Triangle.getNormal( this.a, this.b, this.c, target );
  131. },
  132. getPlane: function ( target ) {
  133. if ( target === undefined ) {
  134. console.warn( 'THREE.Triangle: .getPlane() target is now required' );
  135. target = new Vector3();
  136. }
  137. return target.setFromCoplanarPoints( this.a, this.b, this.c );
  138. },
  139. getBarycoord: function ( point, target ) {
  140. return Triangle.getBarycoord( point, this.a, this.b, this.c, target );
  141. },
  142. getUV: function ( point, uv1, uv2, uv3, target ) {
  143. return Triangle.getUV( point, this.a, this.b, this.c, uv1, uv2, uv3, target );
  144. },
  145. containsPoint: function ( point ) {
  146. return Triangle.containsPoint( point, this.a, this.b, this.c );
  147. },
  148. isFrontFacing: function ( direction ) {
  149. return Triangle.isFrontFacing( this.a, this.b, this.c, direction );
  150. },
  151. intersectsBox: function ( box ) {
  152. return box.intersectsTriangle( this );
  153. },
  154. closestPointToPoint: function () {
  155. var vab = new Vector3();
  156. var vac = new Vector3();
  157. var vbc = new Vector3();
  158. var vap = new Vector3();
  159. var vbp = new Vector3();
  160. var vcp = new Vector3();
  161. return function closestPointToPoint( p, target ) {
  162. if ( target === undefined ) {
  163. console.warn( 'THREE.Triangle: .closestPointToPoint() target is now required' );
  164. target = new Vector3();
  165. }
  166. var a = this.a, b = this.b, c = this.c;
  167. var v, w;
  168. // algorithm thanks to Real-Time Collision Detection by Christer Ericson,
  169. // published by Morgan Kaufmann Publishers, (c) 2005 Elsevier Inc.,
  170. // under the accompanying license; see chapter 5.1.5 for detailed explanation.
  171. // basically, we're distinguishing which of the voronoi regions of the triangle
  172. // the point lies in with the minimum amount of redundant computation.
  173. vab.subVectors( b, a );
  174. vac.subVectors( c, a );
  175. vap.subVectors( p, a );
  176. var d1 = vab.dot( vap );
  177. var d2 = vac.dot( vap );
  178. if ( d1 <= 0 && d2 <= 0 ) {
  179. // vertex region of A; barycentric coords (1, 0, 0)
  180. return target.copy( a );
  181. }
  182. vbp.subVectors( p, b );
  183. var d3 = vab.dot( vbp );
  184. var d4 = vac.dot( vbp );
  185. if ( d3 >= 0 && d4 <= d3 ) {
  186. // vertex region of B; barycentric coords (0, 1, 0)
  187. return target.copy( b );
  188. }
  189. var vc = d1 * d4 - d3 * d2;
  190. if ( vc <= 0 && d1 >= 0 && d3 <= 0 ) {
  191. v = d1 / ( d1 - d3 );
  192. // edge region of AB; barycentric coords (1-v, v, 0)
  193. return target.copy( a ).addScaledVector( vab, v );
  194. }
  195. vcp.subVectors( p, c );
  196. var d5 = vab.dot( vcp );
  197. var d6 = vac.dot( vcp );
  198. if ( d6 >= 0 && d5 <= d6 ) {
  199. // vertex region of C; barycentric coords (0, 0, 1)
  200. return target.copy( c );
  201. }
  202. var vb = d5 * d2 - d1 * d6;
  203. if ( vb <= 0 && d2 >= 0 && d6 <= 0 ) {
  204. w = d2 / ( d2 - d6 );
  205. // edge region of AC; barycentric coords (1-w, 0, w)
  206. return target.copy( a ).addScaledVector( vac, w );
  207. }
  208. var va = d3 * d6 - d5 * d4;
  209. if ( va <= 0 && ( d4 - d3 ) >= 0 && ( d5 - d6 ) >= 0 ) {
  210. vbc.subVectors( c, b );
  211. w = ( d4 - d3 ) / ( ( d4 - d3 ) + ( d5 - d6 ) );
  212. // edge region of BC; barycentric coords (0, 1-w, w)
  213. return target.copy( b ).addScaledVector( vbc, w ); // edge region of BC
  214. }
  215. // face region
  216. var denom = 1 / ( va + vb + vc );
  217. // u = va * denom
  218. v = vb * denom;
  219. w = vc * denom;
  220. return target.copy( a ).addScaledVector( vab, v ).addScaledVector( vac, w );
  221. };
  222. }(),
  223. equals: function ( triangle ) {
  224. return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c );
  225. }
  226. } );
  227. export { Triangle };