@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
130 lines (129 loc) • 4.55 kB
JavaScript
;
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
};
}