UNPKG

@polygonjs/polygonjs

Version:

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

130 lines (129 loc) 4.55 kB
"use strict"; import { BaseSopOperation } from "./_Base"; import { InputCloneMode } from "../../../engine/poly/InputCloneMode"; import { CoreMask } from "../../../core/geometry/Mask"; import { SopType } from "../../poly/registers/nodes/types/Sop"; import { triangleGraphFromGeometry } from "../../../core/geometry/modules/three/graph/triangle/TriangleGraphUtils"; import { ThreejsPrimitiveTriangle } from "../../../core/geometry/modules/three/ThreejsPrimitiveTriangle"; import { threeMeshFromPrimitives } from "../../../core/geometry/modules/three/builders/Mesh"; import { setToArray } from "../../../core/SetUtils"; import { arrayDifference } from "../../../core/ArrayUtils"; export class DeleteNonManifoldSopOperation extends BaseSopOperation { static type() { return SopType.DELETE_NON_MANIFOLD; } cook(inputCoreGroups, params) { const coreGroup = inputCoreGroups[0]; const selectedObjects = CoreMask.filterObjects(coreGroup, params); for (const inputObject of selectedObjects) { const mesh = inputObject; if (mesh.geometry != null && mesh.geometry.index != null) { this._deleteNonManifold(mesh, params.invert); } } coreGroup.resetBoundingBox(); return coreGroup; } _deleteNonManifold(mesh, invert) { const graph = triangleGraphFromGeometry(mesh.geometry); if (!graph) { return; } const edgeIds = []; const triangleIds = []; graph.edgeIds(edgeIds); graph.triangleIds(triangleIds); const sortedTriangleIds = sortTriangleIdsByScore(graph, triangleIds); const selectedTriangleIds = /* @__PURE__ */ new Set(); let status = manifoldStatus(graph, triangleIds, selectedTriangleIds); if (status.nonManifoldEdges > 0) { for (const triangleId of sortedTriangleIds) { selectedTriangleIds.add(triangleId); status = manifoldStatus(graph, triangleIds, selectedTriangleIds); if (status.nonManifoldEdges == 0) { break; } } } if (invert) { const triangleIdsToRemove = []; setToArray(selectedTriangleIds, triangleIdsToRemove); this._cleanMesh(mesh, triangleIdsToRemove); } else { const selectedTriangleIdsArray = []; setToArray(selectedTriangleIds, selectedTriangleIdsArray); const triangleIdsToRemove = []; arrayDifference(triangleIds, selectedTriangleIdsArray, triangleIdsToRemove); this._cleanMesh(mesh, triangleIdsToRemove); } } _cleanMesh(mesh, triangleIdsToKeep) { const triangles = triangleIdsToKeep.map((triangleId) => new ThreejsPrimitiveTriangle(mesh, triangleId)); if (triangles.length > 0) { const newObject = threeMeshFromPrimitives(mesh, triangles); if (newObject) { mesh.geometry = newObject.geometry; } } else { const newObject = threeMeshFromPrimitives(mesh, []); if (newObject) { mesh.geometry = newObject.geometry; } } } } DeleteNonManifoldSopOperation.DEFAULT_PARAMS = { group: "", invert: false }; DeleteNonManifoldSopOperation.INPUT_CLONED_STATE = InputCloneMode.FROM_NODE; function sortTriangleIdsByScore(graph, triangleIds) { const scoreByTriangleId = []; for (const triangleId of triangleIds) { scoreByTriangleId.push(triangleScore(graph, triangleId)); } const sortedTriangleIds = triangleIds.slice(); sortedTriangleIds.sort((a, b) => scoreByTriangleId[b] - scoreByTriangleId[a]); return sortedTriangleIds; } function triangleScore(graph, triangleId) { const edges = graph.edgesByTriangleId(triangleId); let potentialNonManifoldEdges = 0; let totalEdges = 0; if (edges) { for (const edge of edges) { if (edge.triangleIds.length != 2) { potentialNonManifoldEdges++; } totalEdges += edge.triangleIds.length; } } totalEdges /= 3; return potentialNonManifoldEdges * 10 + (totalEdges - 2); } function manifoldStatus(graph, triangleIds, triangleIdsToRemove) { let nonManifoldEdges = 0; const activeEdges = /* @__PURE__ */ new Map(); triangleIds.forEach((triangleId) => { if (triangleIdsToRemove.has(triangleId)) return; const edges = graph.edgesByTriangleId(triangleId); if (edges) { edges.forEach((edge) => { if (!activeEdges.has(edge.id)) { activeEdges.set(edge.id, 0); } activeEdges.set(edge.id, activeEdges.get(edge.id) + 1); }); } }); activeEdges.forEach((count, edge) => { if (count !== 2) { nonManifoldEdges++; } }); return { nonManifoldEdges, activeEdges }; }