Revolver.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. /*
  2. * Revolver.js
  3. *
  4. * @author realor
  5. */
  6. import { ObjectBuilder } from './ObjectBuilder.js'
  7. import { SweptSolidBuilder } from './SweptSolidBuilder.js'
  8. import { Solid } from '../core/Solid.js'
  9. import { Profile } from '../core/Profile.js'
  10. import { Cord } from '../core/Cord.js'
  11. import { SolidGeometry } from '../core/SolidGeometry.js'
  12. import { ProfileGeometry } from '../core/ProfileGeometry.js'
  13. import * as THREE from '../lib/three.module.js'
  14. class Revolver extends SweptSolidBuilder {
  15. angle = 90 // degrees
  16. location = new THREE.Vector3()
  17. axis = new THREE.Vector3(0, 1, 0)
  18. segments = 32 // segments per turn (360 degress)
  19. smoothAngle = 5 // degrees
  20. optimize = true // optimize geometry
  21. constructor(angle, location, axis, segments) {
  22. super()
  23. if (typeof angle === 'number') {
  24. this.angle = angle
  25. }
  26. if (location instanceof THREE.Vector3) {
  27. this.location.copy(location)
  28. }
  29. if (axis instanceof THREE.Vector3) {
  30. this.axis.copy(axis)
  31. }
  32. if (typeof segments === 'number') {
  33. if (segments > 2) {
  34. this.segments = segments
  35. }
  36. }
  37. }
  38. performBuild(solid) {
  39. let profile = this.findClosedProfile(solid)
  40. if (profile === undefined) return true
  41. let [outerRing, innerRings, stepVertexCount] = this.prepareRings(profile)
  42. const yAxis = new THREE.Vector3()
  43. yAxis.copy(this.axis).normalize()
  44. const xAxis = new THREE.Vector3(yAxis.y, -yAxis.x, 0)
  45. const zAxis = new THREE.Vector3()
  46. zAxis.crossVectors(xAxis, yAxis)
  47. const baseMatrix = new THREE.Matrix4()
  48. baseMatrix.makeBasis(xAxis, yAxis, zAxis)
  49. baseMatrix.setPosition(this.location)
  50. const baseMatrixInverse = new THREE.Matrix4()
  51. baseMatrixInverse.copy(baseMatrix).invert()
  52. const geometry = new SolidGeometry()
  53. let angle = Math.abs(this.angle)
  54. if (angle > 360) angle = 360
  55. let reverse = Math.sign(this.angle) === -1
  56. let steps = Math.ceil((this.segments * angle) / 360)
  57. const angleRad = THREE.MathUtils.degToRad(angle)
  58. let stepAngleRad = steps > 0 ? angleRad / steps : 0
  59. if (reverse) {
  60. stepAngleRad *= -1
  61. }
  62. let offset1 = -1
  63. let offset2 = 0
  64. const matrix = new THREE.Matrix4()
  65. const rotationMatrix = new THREE.Matrix4()
  66. for (let i = 0; i <= steps; i++) {
  67. rotationMatrix.makeRotationY(stepAngleRad * i)
  68. matrix.copy(baseMatrix)
  69. matrix.multiply(rotationMatrix)
  70. matrix.multiply(baseMatrixInverse)
  71. matrix.multiply(profile.matrix)
  72. if (i === steps && angle === 360) {
  73. offset2 = 0
  74. } else {
  75. this.addStepVertices(outerRing, innerRings, matrix, geometry)
  76. }
  77. // add faces
  78. if (i === 0 && angle < 360 && steps > 0) {
  79. // first face
  80. this.addProfileFace(0, outerRing, innerRings, !reverse, geometry)
  81. } else if (i === steps && angle < 360) {
  82. // last face
  83. this.addProfileFace(offset2, outerRing, innerRings, reverse, geometry)
  84. }
  85. if (offset1 >= 0 && steps > 0) {
  86. this.addLateralFaces(offset1, offset2, outerRing, innerRings, reverse, geometry)
  87. }
  88. offset1 = offset2
  89. offset2 += stepVertexCount
  90. }
  91. geometry.isManifold = steps > 0
  92. geometry.smoothAngle = this.smoothAngle
  93. solid.updateGeometry(geometry, this.optimize)
  94. return true
  95. }
  96. copy(source) {
  97. this.angle = source.angle
  98. this.location.copy(source.location)
  99. this.axis.copy(source.axis)
  100. this.segments = source.segments
  101. this.smoothAngle = source.smothAngle // degrees
  102. this.optimize = source.optimize
  103. this.minPointDistance = source.minPointDistance
  104. return this
  105. }
  106. }
  107. ObjectBuilder.addClass(Revolver)
  108. export { Revolver }