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