UNPKG

@polygonjs/polygonjs

Version:

node-based WebGL 3D engine https://polygonjs.com

186 lines (185 loc) 6.64 kB
"use strict"; import { traverseEdges, traverseFaces } from "../CadTraverse"; import { faceData } from "./CadTriangulationFaceUtils"; import { BufferGeometry, BufferAttribute } from "three"; import { BaseSopOperation } from "../../../../../engine/operations/sop/_Base"; import { ObjectType } from "../../../Constant"; import { cadMaterialLineGroup, cadMaterialMesh, cadMaterialMeshGroup } from "../CadConstant"; import { cadEdgeToObject3D } from "./CadEdge"; import { CadLoaderSync } from "../CadLoaderSync"; import { objectContentCopyProperties } from "../../../ObjectContent"; import { SopType } from "../../../../../engine/poly/registers/nodes/types/Sop"; import { CadEntityGroupCollection } from "../CadEntityGroupCollection"; import { EntityGroupType } from "../../../EntityGroupCollection"; import { withCadException } from "../CadExceptionHandler"; import { arrayPushItems } from "../../../../ArrayUtils"; function cachedTesselationParamsEqual(params1, params2) { return params1.linearTolerance == params2.linearTolerance && params1.angularTolerance == params2.angularTolerance && params1.curveAbscissa == params2.curveAbscissa && params1.curveTolerance == params2.curveTolerance; } const tesselationParamsByShape = /* @__PURE__ */ new WeakMap(); export function cadShapeToObject3D(cadObject, tesselationParams, displayNode) { const oc = CadLoaderSync.oc(); const shape = cadObject.cadGeometry(); let cachedParams = tesselationParamsByShape.get(shape); if (cachedParams && !cachedTesselationParamsEqual(cachedParams, tesselationParams)) { oc.BRepTools.Clean(shape, true); } tesselationParamsByShape.set(shape, { ...tesselationParams }); const objects = []; function _processMesh(mesh) { if (mesh) { objectContentCopyProperties(cadObject, mesh); objects.push(mesh); } return mesh; } function _processEdgeObject(edge) { const edgeObject = cadEdgeToObject3D(edge, tesselationParams); if (edgeObject) { edgeObject.castShadow = false; edgeObject.receiveShadow = false; objects.push(edgeObject); } return edgeObject; } function _displayNodeIsEdgeGroup() { if (displayNode.type() == SopType.CAD_GROUP) { const groupNode = displayNode; return groupNode.groupType() == EntityGroupType.EDGE; } return false; } function _displayNodeIsFaceGroup() { if (displayNode.type() == SopType.CAD_GROUP) { const groupNode = displayNode; return groupNode.groupType() == EntityGroupType.FACE; } return false; } if (_displayNodeIsFaceGroup()) { const groupNode = displayNode; const groupName = groupNode.groupName(); const facesInGroup = []; const facesNotInGroup = []; CadEntityGroupCollection.traverseEntitiesInGroup({ groupName, groupType: EntityGroupType.FACE, object: cadObject, shape, traverseFunction: traverseFaces, onEntityTraversed: (face, i) => { facesInGroup.push(face); }, onEntityNotInGroupTraversed: (face, i) => { facesNotInGroup.push(face); } }); const objectInGroup = _createMeshFromFaces(oc, shape, facesInGroup, tesselationParams); const objectNotInGroup = _createMeshFromFaces(oc, shape, facesNotInGroup, tesselationParams); if (objectInGroup) { objectInGroup.material = cadMaterialMeshGroup(); } _processMesh(objectInGroup); _processMesh(objectNotInGroup); } else { if (tesselationParams.displayMeshes) { const mesh = _createMesh(oc, shape, tesselationParams); _processMesh(mesh); } } if (_displayNodeIsEdgeGroup()) { const groupNode = displayNode; const groupName = groupNode.groupName(); CadEntityGroupCollection.traverseEntitiesInGroup({ groupName, groupType: EntityGroupType.EDGE, object: cadObject, shape, traverseFunction: traverseEdges, onEntityTraversed: (edge, i) => { const edgeObject = _processEdgeObject(edge); if (edgeObject) { edgeObject.material = cadMaterialLineGroup(); } }, onEntityNotInGroupTraversed: _processEdgeObject }); } else { if (tesselationParams.displayEdges) { traverseEdges(oc, shape, _processEdgeObject); } } return objects; } function _createMesh(oc, object, tesselationParams) { const mesher = withCadException(oc, () => { const _mesher = new oc.BRepMesh_IncrementalMesh_2( object, tesselationParams.linearTolerance, true, tesselationParams.angularTolerance, true ); return _mesher; }); if (!mesher) { const updatedTesselationParams = { ...tesselationParams }; updatedTesselationParams.linearTolerance *= 2; updatedTesselationParams.angularTolerance *= 2; updatedTesselationParams.curveAbscissa *= 2; updatedTesselationParams.curveTolerance *= 2; return _createMesh(oc, object, updatedTesselationParams); } if (mesher.IsDone()) { const positions = []; const normals = []; const indices = []; const buffers = { positions, normals, indices }; traverseFaces(oc, object, (face) => { _updateBufferFromFace(oc, face, buffers); }); mesher.delete(); return _createMeshFromBuffers(buffers, tesselationParams); } } function _createMeshFromFaces(oc, object, faces, tesselationParams) { const mesher = new oc.BRepMesh_IncrementalMesh_2( object, tesselationParams.linearTolerance, true, tesselationParams.angularTolerance, true ); if (mesher.IsDone()) { const positions = []; const normals = []; const indices = []; const buffers = { positions, normals, indices }; for (const face of faces) { _updateBufferFromFace(oc, face, buffers); } mesher.delete(); return _createMeshFromBuffers(buffers, tesselationParams); } } function _updateBufferFromFace(oc, face, buffers) { const { positions, normals, indices } = buffers; const data = faceData(oc, face, positions.length / 3); if (data) { arrayPushItems(data.positions, positions); arrayPushItems(data.normals, normals); arrayPushItems(data.indices, indices); } } function _createMeshFromBuffers(buffers, tesselationParams) { const { positions, normals, indices } = buffers; const geo = new BufferGeometry(); geo.setAttribute("position", new BufferAttribute(new Float32Array(positions), 3)); geo.setAttribute("normal", new BufferAttribute(new Float32Array(normals), 3)); geo.setIndex(indices); return BaseSopOperation.createObject( geo, ObjectType.MESH, cadMaterialMesh(tesselationParams.meshesColor, tesselationParams.wireframe) ); }