UNPKG

@polygonjs/polygonjs

Version:

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

214 lines (213 loc) 6.92 kB
"use strict"; import { mapFirstKey } from "../../../MapUtils"; import { TET_FACE_POINT_INDICES } from "./TetCommon"; import { updateTetNeighboursFromNewTet } from "./utils/tetNeighboursHelper"; import { Vector3, Triangle } from "three"; import { circumSphere } from "./utils/tetSphere"; import { tetFaceTriangle } from "./utils/tetTriangle"; import { logRedBg } from "../../../logger/Console"; import { objectCloneDeep } from "../../../ObjectUtils"; const _triangle = new Triangle(); const _triangleNormal = new Vector3(); const _newPointDelta = new Vector3(); export class TetGeometry { constructor() { this.tetrahedrons = /* @__PURE__ */ new Map(); this.points = /* @__PURE__ */ new Map(); this.tetrahedronsByPointId = /* @__PURE__ */ new Map(); this._nextPointId = -1; this._nextTetId = -1; this._pointsCount = 0; this._tetsCount = 0; this._lastAddedTetId = null; this.userData = {}; } addPoint(x, y, z) { this._nextPointId++; const id = this._nextPointId; const point = { id, position: new Vector3(x, y, z) }; this._pointsCount++; this.points.set(point.id, point); return id; } removePoint(pointId) { this.points.delete(pointId); this.tetrahedronsByPointId.delete(pointId); this._pointsCount--; } pointsCount() { return this._pointsCount; } tetsCount() { return this._tetsCount; } firstTetId() { return mapFirstKey(this.tetrahedrons); } lastAddedTetId() { return this._lastAddedTetId; } addTetrahedron(p0, p1, p2, p3) { if (p0 == p1 || p0 == p2 || p0 == p3 || p1 == p2 || p1 == p3 || p2 == p3) { console.warn("tetrahedron has duplicate points", p0, p1, p2, p3); return; } this._nextTetId++; const id = this._nextTetId; const _circumSphere = { center: new Vector3(), radius: 0 }; circumSphere(this, p0, p1, p2, p3, _circumSphere); const tetrahedron = { id, pointIds: [p0, p1, p2, p3], neighbours: [null, null, null, null], sphere: _circumSphere, disposed: false }; this.tetrahedrons.set(tetrahedron.id, tetrahedron); this._tetsCount++; this._lastAddedTetId = tetrahedron.id; for (const p of tetrahedron.pointIds) { let tetrahedrons = this.tetrahedronsByPointId.get(p); if (!tetrahedrons) { tetrahedrons = /* @__PURE__ */ new Set(); this.tetrahedronsByPointId.set(p, tetrahedrons); } tetrahedrons.add(tetrahedron.id); } updateTetNeighboursFromNewTet(this, tetrahedron); return id; } removeTets(tetIds, sharedFacesNeighbourData, newPointPosition) { if (sharedFacesNeighbourData && newPointPosition) { sharedFacesNeighbourData.clear(); for (const tetId of tetIds) { const tetrahedron = this.tetrahedrons.get(tetId); if (!tetrahedron) { continue; } let faceIndex = 0; for (const neighbourData of tetrahedron.neighbours) { if (neighbourData == null || !tetIds.includes(neighbourData.id)) { let faceAvailableOnSideOfNewPoint = true; if (neighbourData && neighbourData.id != null) { tetFaceTriangle(this, neighbourData.id, neighbourData.faceIndex, _triangle); _triangle.getNormal(_triangleNormal); _newPointDelta.copy(_triangle.a).sub(newPointPosition); if (_triangleNormal.dot(_newPointDelta) > 0) { faceAvailableOnSideOfNewPoint = false; } } if (faceAvailableOnSideOfNewPoint) { const pointIndices = TET_FACE_POINT_INDICES[faceIndex]; sharedFacesNeighbourData.add({ // faceIndex, pointIds: [ tetrahedron.pointIds[pointIndices[0]], tetrahedron.pointIds[pointIndices[1]], tetrahedron.pointIds[pointIndices[2]] ] }); } } faceIndex++; } } } for (const tetId of tetIds) { const tetrahedron = this.tetrahedrons.get(tetId); if (!tetrahedron) { logRedBg(`tet not found:${tetId} (${tetIds})`); throw `removeTets: tet not found ${tetId}`; continue; } for (const pointId of tetrahedron.pointIds) { const tetrahedrons = this.tetrahedronsByPointId.get(pointId); if (tetrahedrons) { tetrahedrons.delete(tetrahedron.id); } } for (const neighbourData of tetrahedron.neighbours) { if (neighbourData != null) { const neighbourTet = this.tetrahedrons.get(neighbourData.id); if (neighbourTet) { const neighbourFaceIndex = neighbourData.faceIndex; neighbourTet.neighbours[neighbourFaceIndex] = null; } } } tetrahedron.disposed = true; this.tetrahedrons.delete(tetId); this._tetsCount--; } } clone() { const clonedGeometry = new TetGeometry(); this.points.forEach((point, id) => { clonedGeometry.points.set(id, { id: point.id, position: point.position.clone() }); }); this.tetrahedrons.forEach((tetrahedron, id) => { clonedGeometry.tetrahedrons.set(id, { id: tetrahedron.id, pointIds: tetrahedron.pointIds.map((id2) => id2), neighbours: tetrahedron.neighbours.map((d) => { if (!d) { return null; } const tetNeighbourData = { id: d.id, faceIndex: d.faceIndex }; return tetNeighbourData; }), sphere: { center: tetrahedron.sphere.center.clone(), radius: tetrahedron.sphere.radius }, disposed: tetrahedron.disposed }); }); this.tetrahedronsByPointId.forEach((tetrahedrons, id) => { clonedGeometry.tetrahedronsByPointId.set(id, new Set(tetrahedrons)); }); clonedGeometry._nextPointId = this._nextPointId; clonedGeometry._nextTetId = this._nextTetId; clonedGeometry._pointsCount = this._pointsCount; clonedGeometry._tetsCount = this._tetsCount; clonedGeometry._lastAddedTetId = this._lastAddedTetId; clonedGeometry.userData = objectCloneDeep(this.userData); return clonedGeometry; } applyMatrix4(matrix) { this.points.forEach((point) => { point.position.applyMatrix4(matrix); }); this.tetrahedrons.forEach((tetrahedron) => { circumSphere( this, tetrahedron.pointIds[0], tetrahedron.pointIds[1], tetrahedron.pointIds[2], tetrahedron.pointIds[3], tetrahedron.sphere ); }); } boundingBox(target) { this.points.forEach((point) => { target.expandByPoint(point.position); }); } boundingSphere(target) { this.points.forEach((point) => { target.expandByPoint(point.position); }); } }