LineSegmentsGeometry.js 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. import {
  2. Box3,
  3. Float32BufferAttribute,
  4. InstancedBufferGeometry,
  5. InstancedInterleavedBuffer,
  6. InterleavedBufferAttribute,
  7. Sphere,
  8. Vector3,
  9. WireframeGeometry
  10. } from 'three';
  11. const _box = new Box3();
  12. const _vector = new Vector3();
  13. /**
  14. * A series of vertex pairs, forming line segments.
  15. *
  16. * This is used in {@link LineSegments2} to describe the shape.
  17. *
  18. * @augments InstancedBufferGeometry
  19. * @three_import import { LineSegmentsGeometry } from 'three/addons/lines/LineSegmentsGeometry.js';
  20. */
  21. class LineSegmentsGeometry extends InstancedBufferGeometry {
  22. /**
  23. * Constructs a new line segments geometry.
  24. */
  25. constructor() {
  26. super();
  27. /**
  28. * This flag can be used for type testing.
  29. *
  30. * @type {boolean}
  31. * @readonly
  32. * @default true
  33. */
  34. this.isLineSegmentsGeometry = true;
  35. this.type = 'LineSegmentsGeometry';
  36. const positions = [ - 1, 2, 0, 1, 2, 0, - 1, 1, 0, 1, 1, 0, - 1, 0, 0, 1, 0, 0, - 1, - 1, 0, 1, - 1, 0 ];
  37. const uvs = [ - 1, 2, 1, 2, - 1, 1, 1, 1, - 1, - 1, 1, - 1, - 1, - 2, 1, - 2 ];
  38. const index = [ 0, 2, 1, 2, 3, 1, 2, 4, 3, 4, 5, 3, 4, 6, 5, 6, 7, 5 ];
  39. this.setIndex( index );
  40. this.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );
  41. this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
  42. }
  43. /**
  44. * Applies the given 4x4 transformation matrix to the geometry.
  45. *
  46. * @param {Matrix4} matrix - The matrix to apply.
  47. * @return {LineSegmentsGeometry} A reference to this instance.
  48. */
  49. applyMatrix4( matrix ) {
  50. const start = this.attributes.instanceStart;
  51. const end = this.attributes.instanceEnd;
  52. if ( start !== undefined ) {
  53. start.applyMatrix4( matrix );
  54. end.applyMatrix4( matrix );
  55. start.needsUpdate = true;
  56. }
  57. if ( this.boundingBox !== null ) {
  58. this.computeBoundingBox();
  59. }
  60. if ( this.boundingSphere !== null ) {
  61. this.computeBoundingSphere();
  62. }
  63. return this;
  64. }
  65. /**
  66. * Sets the given line positions for this geometry. The length must be a multiple of six since
  67. * each line segment is defined by a start end vertex in the pattern `(xyz xyz)`.
  68. *
  69. * @param {Float32Array|Array<number>} array - The position data to set.
  70. * @return {LineSegmentsGeometry} A reference to this geometry.
  71. */
  72. setPositions( array ) {
  73. let lineSegments;
  74. if ( array instanceof Float32Array ) {
  75. lineSegments = array;
  76. } else if ( Array.isArray( array ) ) {
  77. lineSegments = new Float32Array( array );
  78. }
  79. const instanceBuffer = new InstancedInterleavedBuffer( lineSegments, 6, 1 ); // xyz, xyz
  80. this.setAttribute( 'instanceStart', new InterleavedBufferAttribute( instanceBuffer, 3, 0 ) ); // xyz
  81. this.setAttribute( 'instanceEnd', new InterleavedBufferAttribute( instanceBuffer, 3, 3 ) ); // xyz
  82. this.instanceCount = this.attributes.instanceStart.count;
  83. //
  84. this.computeBoundingBox();
  85. this.computeBoundingSphere();
  86. return this;
  87. }
  88. /**
  89. * Sets the given line colors for this geometry. The length must be a multiple of six since
  90. * each line segment is defined by a start end color in the pattern `(rgb rgb)`.
  91. *
  92. * @param {Float32Array|Array<number>} array - The position data to set.
  93. * @return {LineSegmentsGeometry} A reference to this geometry.
  94. */
  95. setColors( array ) {
  96. let colors;
  97. if ( array instanceof Float32Array ) {
  98. colors = array;
  99. } else if ( Array.isArray( array ) ) {
  100. colors = new Float32Array( array );
  101. }
  102. const instanceColorBuffer = new InstancedInterleavedBuffer( colors, 6, 1 ); // rgb, rgb
  103. this.setAttribute( 'instanceColorStart', new InterleavedBufferAttribute( instanceColorBuffer, 3, 0 ) ); // rgb
  104. this.setAttribute( 'instanceColorEnd', new InterleavedBufferAttribute( instanceColorBuffer, 3, 3 ) ); // rgb
  105. return this;
  106. }
  107. /**
  108. * Setups this line segments geometry from the given wireframe geometry.
  109. *
  110. * @param {WireframeGeometry} geometry - The geometry that should be used as a data source for this geometry.
  111. * @return {LineSegmentsGeometry} A reference to this geometry.
  112. */
  113. fromWireframeGeometry( geometry ) {
  114. this.setPositions( geometry.attributes.position.array );
  115. return this;
  116. }
  117. /**
  118. * Setups this line segments geometry from the given edges geometry.
  119. *
  120. * @param {EdgesGeometry} geometry - The geometry that should be used as a data source for this geometry.
  121. * @return {LineSegmentsGeometry} A reference to this geometry.
  122. */
  123. fromEdgesGeometry( geometry ) {
  124. this.setPositions( geometry.attributes.position.array );
  125. return this;
  126. }
  127. /**
  128. * Setups this line segments geometry from the given mesh.
  129. *
  130. * @param {Mesh} mesh - The mesh geometry that should be used as a data source for this geometry.
  131. * @return {LineSegmentsGeometry} A reference to this geometry.
  132. */
  133. fromMesh( mesh ) {
  134. this.fromWireframeGeometry( new WireframeGeometry( mesh.geometry ) );
  135. // set colors, maybe
  136. return this;
  137. }
  138. /**
  139. * Setups this line segments geometry from the given line segments.
  140. *
  141. * @param {LineSegments} lineSegments - The line segments that should be used as a data source for this geometry.
  142. * Assumes the source geometry is not using indices.
  143. * @return {LineSegmentsGeometry} A reference to this geometry.
  144. */
  145. fromLineSegments( lineSegments ) {
  146. const geometry = lineSegments.geometry;
  147. this.setPositions( geometry.attributes.position.array ); // assumes non-indexed
  148. // set colors, maybe
  149. return this;
  150. }
  151. computeBoundingBox() {
  152. if ( this.boundingBox === null ) {
  153. this.boundingBox = new Box3();
  154. }
  155. const start = this.attributes.instanceStart;
  156. const end = this.attributes.instanceEnd;
  157. if ( start !== undefined && end !== undefined ) {
  158. this.boundingBox.setFromBufferAttribute( start );
  159. _box.setFromBufferAttribute( end );
  160. this.boundingBox.union( _box );
  161. }
  162. }
  163. computeBoundingSphere() {
  164. if ( this.boundingSphere === null ) {
  165. this.boundingSphere = new Sphere();
  166. }
  167. if ( this.boundingBox === null ) {
  168. this.computeBoundingBox();
  169. }
  170. const start = this.attributes.instanceStart;
  171. const end = this.attributes.instanceEnd;
  172. if ( start !== undefined && end !== undefined ) {
  173. const center = this.boundingSphere.center;
  174. this.boundingBox.getCenter( center );
  175. let maxRadiusSq = 0;
  176. for ( let i = 0, il = start.count; i < il; i ++ ) {
  177. _vector.fromBufferAttribute( start, i );
  178. maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector ) );
  179. _vector.fromBufferAttribute( end, i );
  180. maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector ) );
  181. }
  182. this.boundingSphere.radius = Math.sqrt( maxRadiusSq );
  183. if ( isNaN( this.boundingSphere.radius ) ) {
  184. console.error( 'THREE.LineSegmentsGeometry.computeBoundingSphere(): Computed radius is NaN. The instanced position data is likely to have NaN values.', this );
  185. }
  186. }
  187. }
  188. toJSON() {
  189. // todo
  190. }
  191. }
  192. export { LineSegmentsGeometry };