BooleanOperator.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. /*
  2. * BooleanOperator.js
  3. *
  4. * @author realor
  5. */
  6. import { ObjectBuilder } from './ObjectBuilder.js'
  7. import { SolidBuilder } from './SolidBuilder.js'
  8. import { SolidGeometry } from '../core/SolidGeometry.js'
  9. import { Solid } from '../core/Solid.js'
  10. import { BSP } from '../core/BSP.js'
  11. import * as THREE from '../lib/three.module.js'
  12. class BooleanOperator extends SolidBuilder {
  13. static UNION = 'union'
  14. static INTERSECT = 'intersect'
  15. static SUBTRACT = 'subtract'
  16. constructor(operation) {
  17. super()
  18. this.operation = operation || BooleanOperator.SUBTRACT
  19. }
  20. performBuild(solid) {
  21. const solids = []
  22. this.findSolids(solid, solids)
  23. if (solids.length === 0) return true
  24. const matrix = new THREE.Matrix4()
  25. const createBSP = child => {
  26. matrix.copy(child.matrix)
  27. let parent = child.parent
  28. while (parent && parent !== solid) {
  29. matrix.premultiply(parent.matrix)
  30. parent = parent.parent
  31. }
  32. const bsp = new BSP()
  33. bsp.fromSolidGeometry(child.geometry, matrix)
  34. return bsp
  35. }
  36. let resultBSP = createBSP(solids[0])
  37. for (let i = 1; i < solids.length; i++) {
  38. let solid = solids[i]
  39. if (solid.isValid()) {
  40. let otherBSP = createBSP(solid)
  41. switch (this.operation) {
  42. case BooleanOperator.UNION:
  43. resultBSP = resultBSP.union(otherBSP)
  44. break
  45. case BooleanOperator.INTERSECT:
  46. resultBSP = resultBSP.intersect(otherBSP)
  47. break
  48. case BooleanOperator.SUBTRACT:
  49. resultBSP = resultBSP.subtract(otherBSP)
  50. break
  51. }
  52. }
  53. }
  54. let geometry = resultBSP.toSolidGeometry()
  55. geometry.smoothAngle = this.calculateSmoothAngle(solids)
  56. solid.updateGeometry(geometry, true)
  57. return true
  58. }
  59. copy(source) {
  60. this.operation = source.operation
  61. return this
  62. }
  63. calculateSmoothAngle(solids) {
  64. let smoothAngle = 0
  65. for (let solid of solids) {
  66. if (solid.geometry.smoothAngle > smoothAngle) {
  67. smoothAngle = solid.geometry.smoothAngle
  68. }
  69. }
  70. return smoothAngle
  71. }
  72. findSolids(object, solids) {
  73. const children = object.children
  74. const start = object instanceof Solid ? 2 : 0
  75. for (let i = start; i < children.length; i++) {
  76. let child = children[i]
  77. if (child instanceof Solid) {
  78. child.visible = false
  79. child.edgesVisible = false
  80. child.facesVisible = false
  81. solids.push(child)
  82. } else {
  83. this.findSolids(child, solids)
  84. }
  85. }
  86. }
  87. }
  88. ObjectBuilder.addClass(BooleanOperator)
  89. export { BooleanOperator }