SweptSolidBuilder.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. /*
  2. * SweptSolidBuilder.js
  3. *
  4. * @author realor
  5. */
  6. import { ObjectBuilder } from './ObjectBuilder.js'
  7. import { SolidBuilder } from './SolidBuilder.js'
  8. import { Profile } from '../core/Profile.js'
  9. import { ProfileGeometry } from '../core/ProfileGeometry.js'
  10. import * as THREE from '../lib/three.module.js'
  11. class SweptSolidBuilder extends SolidBuilder {
  12. minPointDistance = 0.0001
  13. constructor() {
  14. super()
  15. }
  16. findClosedProfile(solid) {
  17. for (let child of solid.children) {
  18. if (child instanceof Profile) {
  19. if (child.geometry && child.geometry.isClosed()) return child
  20. }
  21. }
  22. return undefined
  23. }
  24. prepareRings(profile) {
  25. profile.visible = false
  26. const shape = profile.geometry.path
  27. const points = shape.extractPoints(profile.geometry.divisions)
  28. let outerRing = points.shape
  29. let innerRings = points.holes
  30. // prepare shape, orient rings and remove duplicated vertices
  31. const removeDuplicatedVertices = ring => {
  32. let i = 0
  33. for (let j = 1; j < ring.length; j++) {
  34. let point1 = ring[i]
  35. let point2 = ring[j]
  36. if (point1.distanceTo(point2) >= this.minPointDistance) {
  37. i++
  38. ring[i] = point2
  39. }
  40. }
  41. while (i < ring.length - 1) {
  42. ring.pop()
  43. }
  44. if (ring.length >= 2 && ring[0].distanceTo(ring[ring.length - 1]) < this.minPointDistance) {
  45. ring.pop()
  46. }
  47. }
  48. removeDuplicatedVertices(outerRing)
  49. if (outerRing.length < 3) {
  50. throw "Can't extrude an invalid profile"
  51. }
  52. innerRings.forEach(removeDuplicatedVertices)
  53. innerRings = innerRings.filter(innerRing => innerRing.length >= 3)
  54. let stepVertexCount = outerRing.length
  55. if (THREE.ShapeUtils.isClockWise(outerRing)) {
  56. outerRing = outerRing.reverse()
  57. }
  58. for (let h = 0; h < innerRings.length; h++) {
  59. let innerRing = innerRings[h]
  60. stepVertexCount += innerRing.length
  61. if (THREE.ShapeUtils.isClockWise(innerRing)) {
  62. innerRings[h] = innerRing.reverse()
  63. }
  64. }
  65. return [outerRing, innerRings, stepVertexCount]
  66. }
  67. addStepVertices(outerRing, innerRings, matrix, geometry) {
  68. const addVertices = ring => {
  69. for (let i = 0; i < ring.length; i++) {
  70. let vertex2 = ring[i]
  71. let vertex3 = new THREE.Vector3(vertex2.x, vertex2.y, 0)
  72. vertex3.applyMatrix4(matrix)
  73. geometry.vertices.push(vertex3)
  74. }
  75. }
  76. addVertices(outerRing)
  77. for (let h = 0; h < innerRings.length; h++) {
  78. let innerRing = innerRings[h]
  79. addVertices(innerRing)
  80. }
  81. }
  82. addProfileFace(offset, outerRing, innerRings, reverse, geometry) {
  83. let indices = []
  84. for (let i = 0; i < outerRing.length; i++) {
  85. indices.push(offset++)
  86. }
  87. if (reverse) indices.reverse()
  88. let face = geometry.addFace(...indices)
  89. for (let innerRing of innerRings) {
  90. indices = []
  91. for (let i = 0; i < innerRing.length; i++) {
  92. indices.push(offset++)
  93. }
  94. if (reverse) indices.reverse()
  95. face.addHole(...indices)
  96. }
  97. return face
  98. }
  99. addLateralFaces(offset1, offset2, outerRing, innerRings, reverse, geometry) {
  100. // add outer ring side faces
  101. for (let i = 0; i < outerRing.length; i++) {
  102. let va1 = offset1 + i
  103. let vb1 = offset1 + ((i + 1) % outerRing.length)
  104. let va2 = offset2 + i
  105. let vb2 = offset2 + ((i + 1) % outerRing.length)
  106. if (reverse) {
  107. this.addFace(va2, vb2, vb1, va1, geometry)
  108. } else {
  109. this.addFace(va1, vb1, vb2, va2, geometry)
  110. }
  111. }
  112. // add inner rings side faces
  113. let innerRingOffset = outerRing.length
  114. for (let r = 0; r < innerRings.length; r++) {
  115. let innerRing = innerRings[r]
  116. for (let i = 0; i < innerRing.length; i++) {
  117. let va1 = offset1 + innerRingOffset + i
  118. let vb1 = offset1 + innerRingOffset + ((i + 1) % innerRing.length)
  119. let va2 = offset2 + innerRingOffset + i
  120. let vb2 = offset2 + innerRingOffset + ((i + 1) % innerRing.length)
  121. if (reverse) {
  122. this.addFace(va1, vb1, vb2, va2, geometry)
  123. } else {
  124. this.addFace(va2, vb2, vb1, va1, geometry)
  125. }
  126. }
  127. innerRingOffset += innerRing.length
  128. }
  129. }
  130. addFace(va1, vb1, vb2, va2, geometry) {
  131. const vertices = geometry.vertices
  132. const pa1 = vertices[va1]
  133. const pb1 = vertices[vb1]
  134. const pa2 = vertices[va2]
  135. const pb2 = vertices[vb2]
  136. let equalsA = pa1.distanceTo(pa2) < this.minPointDistance
  137. let equalsB = pb1.distanceTo(pb2) < this.minPointDistance
  138. if (!equalsA && !equalsB) {
  139. geometry.addFace(va1, vb1, vb2, va2)
  140. } else if (!equalsA && equalsB) {
  141. geometry.addFace(va1, vb1, va2)
  142. } else if (equalsA && !equalsB) {
  143. geometry.addFace(va1, vb1, vb2)
  144. }
  145. }
  146. }
  147. export { SweptSolidBuilder }