"use strict"; var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => { __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); const THREE = require("three"); const BufferGeometryUtils = require("../utils/BufferGeometryUtils.cjs"); const cb = /* @__PURE__ */ new THREE.Vector3(); const ab = /* @__PURE__ */ new THREE.Vector3(); function pushIfUnique(array, object) { if (array.indexOf(object) === -1) array.push(object); } function removeFromArray(array, object) { const k = array.indexOf(object); if (k > -1) array.splice(k, 1); } class Vertex { constructor(v, id) { __publicField(this, "position"); __publicField(this, "id"); __publicField(this, "faces"); __publicField(this, "neighbors"); __publicField(this, "collapseCost"); __publicField(this, "collapseNeighbor"); __publicField(this, "minCost", 0); __publicField(this, "totalCost", 0); __publicField(this, "costCount", 0); this.position = v; this.id = id; this.faces = []; this.neighbors = []; this.collapseCost = 0; this.collapseNeighbor = null; } addUniqueNeighbor(vertex) { pushIfUnique(this.neighbors, vertex); } removeIfNonNeighbor(n) { const neighbors = this.neighbors; const faces = this.faces; const offset = neighbors.indexOf(n); if (offset === -1) return; for (let i = 0; i < faces.length; i++) { if (faces[i].hasVertex(n)) return; } neighbors.splice(offset, 1); } } class Triangle { constructor(v1, v2, v3, a, b, c) { __publicField(this, "a"); __publicField(this, "b"); __publicField(this, "c"); __publicField(this, "v1"); __publicField(this, "v2"); __publicField(this, "v3"); __publicField(this, "normal", new THREE.Vector3()); this.a = a; this.b = b; this.c = c; this.v1 = v1; this.v2 = v2; this.v3 = v3; this.computeNormal(); v1.faces.push(this); v1.addUniqueNeighbor(v2); v1.addUniqueNeighbor(v3); v2.faces.push(this); v2.addUniqueNeighbor(v1); v2.addUniqueNeighbor(v3); v3.faces.push(this); v3.addUniqueNeighbor(v1); v3.addUniqueNeighbor(v2); } computeNormal() { const vA = this.v1.position; const vB = this.v2.position; const vC = this.v3.position; cb.subVectors(vC, vB); ab.subVectors(vA, vB); cb.cross(ab).normalize(); this.normal.copy(cb); } hasVertex(v) { return v === this.v1 || v === this.v2 || v === this.v3; } replaceVertex(oldv, newv) { if (oldv === this.v1) this.v1 = newv; else if (oldv === this.v2) this.v2 = newv; else if (oldv === this.v3) this.v3 = newv; removeFromArray(oldv.faces, this); newv.faces.push(this); oldv.removeIfNonNeighbor(this.v1); this.v1.removeIfNonNeighbor(oldv); oldv.removeIfNonNeighbor(this.v2); this.v2.removeIfNonNeighbor(oldv); oldv.removeIfNonNeighbor(this.v3); this.v3.removeIfNonNeighbor(oldv); this.v1.addUniqueNeighbor(this.v2); this.v1.addUniqueNeighbor(this.v3); this.v2.addUniqueNeighbor(this.v1); this.v2.addUniqueNeighbor(this.v3); this.v3.addUniqueNeighbor(this.v1); this.v3.addUniqueNeighbor(this.v2); this.computeNormal(); } } class SimplifyModifier { constructor() { __publicField(this, "computeEdgeCollapseCost", (u, v) => { const edgelength = v.position.distanceTo(u.position); let curvature = 0; const sideFaces = []; let i, il = u.faces.length, face, sideFace; for (i = 0; i < il; i++) { face = u.faces[i]; if (face.hasVertex(v)) { sideFaces.push(face); } } for (i = 0; i < il; i++) { let minCurvature = 1; face = u.faces[i]; for (let j = 0; j < sideFaces.length; j++) { sideFace = sideFaces[j]; const dotProd = face.normal.dot(sideFace.normal); minCurvature = Math.min(minCurvature, (1.001 - dotProd) / 2); } curvature = Math.max(curvature, minCurvature); } const borders = 0; if (sideFaces.length < 2) { curvature = 1; } const amt = edgelength * curvature + borders; return amt; }); __publicField(this, "computeEdgeCostAtVertex", (v) => { if (v.neighbors.length === 0) { v.collapseNeighbor = null; v.collapseCost = -0.01; return; } v.collapseCost = 1e5; v.collapseNeighbor = null; for (let i = 0; i < v.neighbors.length; i++) { const collapseCost = this.computeEdgeCollapseCost(v, v.neighbors[i]); if (!v.collapseNeighbor) { v.collapseNeighbor = v.neighbors[i]; v.collapseCost = collapseCost; v.minCost = collapseCost; v.totalCost = 0; v.costCount = 0; } v.costCount++; v.totalCost += collapseCost; if (collapseCost < v.minCost) { v.collapseNeighbor = v.neighbors[i]; v.minCost = collapseCost; } } v.collapseCost = v.totalCost / v.costCount; }); __publicField(this, "removeFace", (f, faces) => { removeFromArray(faces, f); if (f.v1) removeFromArray(f.v1.faces, f); if (f.v2) removeFromArray(f.v2.faces, f); if (f.v3) removeFromArray(f.v3.faces, f); const vs = [f.v1, f.v2, f.v3]; let v1, v2; for (let i = 0; i < 3; i++) { v1 = vs[i]; v2 = vs[(i + 1) % 3]; if (!v1 || !v2) continue; v1.removeIfNonNeighbor(v2); v2.removeIfNonNeighbor(v1); } }); __publicField(this, "collapse", (vertices, faces, u, v) => { if (!v) { this.removeVertex(u, vertices); return; } let i; const tmpVertices = []; for (i = 0; i < u.neighbors.length; i++) { tmpVertices.push(u.neighbors[i]); } for (i = u.faces.length - 1; i >= 0; i--) { if (u.faces[i].hasVertex(v)) { this.removeFace(u.faces[i], faces); } } for (i = u.faces.length - 1; i >= 0; i--) { u.faces[i].replaceVertex(u, v); } this.removeVertex(u, vertices); for (i = 0; i < tmpVertices.length; i++) { this.computeEdgeCostAtVertex(tmpVertices[i]); } }); __publicField(this, "minimumCostEdge", (vertices) => { let least = vertices[0]; for (let i = 0; i < vertices.length; i++) { if (vertices[i].collapseCost < least.collapseCost) { least = vertices[i]; } } return least; }); __publicField(this, "modify", (geometry, count) => { geometry = geometry.clone(); const attributes = geometry.attributes; for (let name in attributes) { if (name !== "position") geometry.deleteAttribute(name); } geometry = BufferGeometryUtils.mergeVertices(geometry); const vertices = []; const faces = []; const positionAttribute = geometry.getAttribute("position"); for (let i = 0; i < positionAttribute.count; i++) { const v = new THREE.Vector3().fromBufferAttribute(positionAttribute, i); const vertex = new Vertex(v, i); vertices.push(vertex); } const geomIndex = geometry.getIndex(); if (geomIndex !== null) { for (let i = 0; i < geomIndex.count; i += 3) { const a = geomIndex.getX(i); const b = geomIndex.getX(i + 1); const c = geomIndex.getX(i + 2); const triangle = new Triangle(vertices[a], vertices[b], vertices[c], a, b, c); faces.push(triangle); } } else { for (let i = 0; i < positionAttribute.count; i += 3) { const a = i; const b = i + 1; const c = i + 2; const triangle = new Triangle(vertices[a], vertices[b], vertices[c], a, b, c); faces.push(triangle); } } for (let i = 0, il = vertices.length; i < il; i++) { this.computeEdgeCostAtVertex(vertices[i]); } let nextVertex; let z = count; while (z--) { nextVertex = this.minimumCostEdge(vertices); if (!nextVertex) { console.log("THREE.SimplifyModifier: No next vertex"); break; } else { this.collapse(vertices, faces, nextVertex, nextVertex.collapseNeighbor); } } const simplifiedGeometry = new THREE.BufferGeometry(); const position = []; let index = []; for (let i = 0; i < vertices.length; i++) { const vertex = vertices[i].position; position.push(vertex.x, vertex.y, vertex.z); } for (let i = 0; i < faces.length; i++) { const face = faces[i]; const a = vertices.indexOf(face.v1); const b = vertices.indexOf(face.v2); const c = vertices.indexOf(face.v3); index.push(a, b, c); } simplifiedGeometry.setAttribute("position", new THREE.Float32BufferAttribute(position, 3)); simplifiedGeometry.setIndex(index); return simplifiedGeometry; }); } removeVertex(v, vertices) { console.assert(v.faces.length === 0); while (v.neighbors.length) { const n = v.neighbors.pop(); removeFromArray(n.neighbors, v); } removeFromArray(vertices, v); } } exports.SimplifyModifier = SimplifyModifier; //# sourceMappingURL=SimplifyModifier.cjs.map