GeometryUtils.js 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. /**
  2. * @author mrdoob / http://mrdoob.com/
  3. * @author alteredq / http://alteredqualia.com/
  4. */
  5. import {
  6. Mesh,
  7. Vector3
  8. } from "../../../build/three.module.js";
  9. var GeometryUtils = {
  10. // Merge two geometries or geometry and geometry from object (using object's transform)
  11. merge: function ( geometry1, geometry2, materialIndexOffset ) {
  12. console.warn( 'THREE.GeometryUtils: .merge() has been moved to Geometry. Use geometry.merge( geometry2, matrix, materialIndexOffset ) instead.' );
  13. var matrix;
  14. if ( geometry2 instanceof Mesh ) {
  15. geometry2.matrixAutoUpdate && geometry2.updateMatrix();
  16. matrix = geometry2.matrix;
  17. geometry2 = geometry2.geometry;
  18. }
  19. geometry1.merge( geometry2, matrix, materialIndexOffset );
  20. },
  21. // Get random point in triangle (via barycentric coordinates)
  22. // (uniform distribution)
  23. // http://www.cgafaq.info/wiki/Random_Point_In_Triangle
  24. randomPointInTriangle: function () {
  25. var vector = new Vector3();
  26. return function ( vectorA, vectorB, vectorC ) {
  27. var point = new Vector3();
  28. var a = Math.random();
  29. var b = Math.random();
  30. if ( ( a + b ) > 1 ) {
  31. a = 1 - a;
  32. b = 1 - b;
  33. }
  34. var c = 1 - a - b;
  35. point.copy( vectorA );
  36. point.multiplyScalar( a );
  37. vector.copy( vectorB );
  38. vector.multiplyScalar( b );
  39. point.add( vector );
  40. vector.copy( vectorC );
  41. vector.multiplyScalar( c );
  42. point.add( vector );
  43. return point;
  44. };
  45. }(),
  46. // Get random point in face (triangle)
  47. // (uniform distribution)
  48. randomPointInFace: function ( face, geometry ) {
  49. var vA, vB, vC;
  50. vA = geometry.vertices[ face.a ];
  51. vB = geometry.vertices[ face.b ];
  52. vC = geometry.vertices[ face.c ];
  53. return GeometryUtils.randomPointInTriangle( vA, vB, vC );
  54. },
  55. // Get uniformly distributed random points in mesh
  56. // - create array with cumulative sums of face areas
  57. // - pick random number from 0 to total area
  58. // - find corresponding place in area array by binary search
  59. // - get random point in face
  60. randomPointsInGeometry: function ( geometry, n ) {
  61. var face, i,
  62. faces = geometry.faces,
  63. vertices = geometry.vertices,
  64. il = faces.length,
  65. totalArea = 0,
  66. cumulativeAreas = [],
  67. vA, vB, vC;
  68. // precompute face areas
  69. for ( i = 0; i < il; i ++ ) {
  70. face = faces[ i ];
  71. vA = vertices[ face.a ];
  72. vB = vertices[ face.b ];
  73. vC = vertices[ face.c ];
  74. face._area = GeometryUtils.triangleArea( vA, vB, vC );
  75. totalArea += face._area;
  76. cumulativeAreas[ i ] = totalArea;
  77. }
  78. // binary search cumulative areas array
  79. function binarySearchIndices( value ) {
  80. function binarySearch( start, end ) {
  81. // return closest larger index
  82. // if exact number is not found
  83. if ( end < start )
  84. return start;
  85. var mid = start + Math.floor( ( end - start ) / 2 );
  86. if ( cumulativeAreas[ mid ] > value ) {
  87. return binarySearch( start, mid - 1 );
  88. } else if ( cumulativeAreas[ mid ] < value ) {
  89. return binarySearch( mid + 1, end );
  90. } else {
  91. return mid;
  92. }
  93. }
  94. var result = binarySearch( 0, cumulativeAreas.length - 1 );
  95. return result;
  96. }
  97. // pick random face weighted by face area
  98. var r, index,
  99. result = [];
  100. var stats = {};
  101. for ( i = 0; i < n; i ++ ) {
  102. r = Math.random() * totalArea;
  103. index = binarySearchIndices( r );
  104. result[ i ] = GeometryUtils.randomPointInFace( faces[ index ], geometry );
  105. if ( ! stats[ index ] ) {
  106. stats[ index ] = 1;
  107. } else {
  108. stats[ index ] += 1;
  109. }
  110. }
  111. return result;
  112. },
  113. randomPointsInBufferGeometry: function ( geometry, n ) {
  114. var i,
  115. vertices = geometry.attributes.position.array,
  116. totalArea = 0,
  117. cumulativeAreas = [],
  118. vA, vB, vC;
  119. // precompute face areas
  120. vA = new Vector3();
  121. vB = new Vector3();
  122. vC = new Vector3();
  123. // geometry._areas = [];
  124. var il = vertices.length / 9;
  125. for ( i = 0; i < il; i ++ ) {
  126. vA.set( vertices[ i * 9 + 0 ], vertices[ i * 9 + 1 ], vertices[ i * 9 + 2 ] );
  127. vB.set( vertices[ i * 9 + 3 ], vertices[ i * 9 + 4 ], vertices[ i * 9 + 5 ] );
  128. vC.set( vertices[ i * 9 + 6 ], vertices[ i * 9 + 7 ], vertices[ i * 9 + 8 ] );
  129. totalArea += GeometryUtils.triangleArea( vA, vB, vC );
  130. cumulativeAreas.push( totalArea );
  131. }
  132. // binary search cumulative areas array
  133. function binarySearchIndices( value ) {
  134. function binarySearch( start, end ) {
  135. // return closest larger index
  136. // if exact number is not found
  137. if ( end < start )
  138. return start;
  139. var mid = start + Math.floor( ( end - start ) / 2 );
  140. if ( cumulativeAreas[ mid ] > value ) {
  141. return binarySearch( start, mid - 1 );
  142. } else if ( cumulativeAreas[ mid ] < value ) {
  143. return binarySearch( mid + 1, end );
  144. } else {
  145. return mid;
  146. }
  147. }
  148. var result = binarySearch( 0, cumulativeAreas.length - 1 );
  149. return result;
  150. }
  151. // pick random face weighted by face area
  152. var r, index,
  153. result = [];
  154. for ( i = 0; i < n; i ++ ) {
  155. r = Math.random() * totalArea;
  156. index = binarySearchIndices( r );
  157. // result[ i ] = GeometryUtils.randomPointInFace( faces[ index ], geometry, true );
  158. vA.set( vertices[ index * 9 + 0 ], vertices[ index * 9 + 1 ], vertices[ index * 9 + 2 ] );
  159. vB.set( vertices[ index * 9 + 3 ], vertices[ index * 9 + 4 ], vertices[ index * 9 + 5 ] );
  160. vC.set( vertices[ index * 9 + 6 ], vertices[ index * 9 + 7 ], vertices[ index * 9 + 8 ] );
  161. result[ i ] = GeometryUtils.randomPointInTriangle( vA, vB, vC );
  162. }
  163. return result;
  164. },
  165. // Get triangle area (half of parallelogram)
  166. // http://mathworld.wolfram.com/TriangleArea.html
  167. triangleArea: function () {
  168. var vector1 = new Vector3();
  169. var vector2 = new Vector3();
  170. return function ( vectorA, vectorB, vectorC ) {
  171. vector1.subVectors( vectorB, vectorA );
  172. vector2.subVectors( vectorC, vectorA );
  173. vector1.cross( vector2 );
  174. return 0.5 * vector1.length();
  175. };
  176. }(),
  177. center: function ( geometry ) {
  178. console.warn( 'THREE.GeometryUtils: .center() has been moved to Geometry. Use geometry.center() instead.' );
  179. return geometry.center();
  180. }
  181. };
  182. export { GeometryUtils };