starry / backend /libs /three /geometries /EdgesGeometry.js
k-l-lambda's picture
feat: add Python ML services (CPU mode) with model download
2b7aae2
import { BufferGeometry } from '../core/BufferGeometry.js';
import { Float32BufferAttribute } from '../core/BufferAttribute.js';
import * as MathUtils from '../math/MathUtils.js';
import { Triangle } from '../math/Triangle.js';
import { Vector3 } from '../math/Vector3.js';
const _v0 = new Vector3();
const _v1 = new Vector3();
const _normal = new Vector3();
const _triangle = new Triangle();
class EdgesGeometry extends BufferGeometry {
constructor(geometry = null, thresholdAngle = 1) {
super();
this.type = 'EdgesGeometry';
this.parameters = {
geometry: geometry,
thresholdAngle: thresholdAngle,
};
if (geometry !== null) {
const precisionPoints = 4;
const precision = Math.pow(10, precisionPoints);
const thresholdDot = Math.cos(MathUtils.DEG2RAD * thresholdAngle);
const indexAttr = geometry.getIndex();
const positionAttr = geometry.getAttribute('position');
const indexCount = indexAttr ? indexAttr.count : positionAttr.count;
const indexArr = [0, 0, 0];
const vertKeys = ['a', 'b', 'c'];
const hashes = new Array(3);
const edgeData = {};
const vertices = [];
for (let i = 0; i < indexCount; i += 3) {
if (indexAttr) {
indexArr[0] = indexAttr.getX(i);
indexArr[1] = indexAttr.getX(i + 1);
indexArr[2] = indexAttr.getX(i + 2);
} else {
indexArr[0] = i;
indexArr[1] = i + 1;
indexArr[2] = i + 2;
}
const { a, b, c } = _triangle;
a.fromBufferAttribute(positionAttr, indexArr[0]);
b.fromBufferAttribute(positionAttr, indexArr[1]);
c.fromBufferAttribute(positionAttr, indexArr[2]);
_triangle.getNormal(_normal);
// create hashes for the edge from the vertices
hashes[0] = `${Math.round(a.x * precision)},${Math.round(a.y * precision)},${Math.round(a.z * precision)}`;
hashes[1] = `${Math.round(b.x * precision)},${Math.round(b.y * precision)},${Math.round(b.z * precision)}`;
hashes[2] = `${Math.round(c.x * precision)},${Math.round(c.y * precision)},${Math.round(c.z * precision)}`;
// skip degenerate triangles
if (hashes[0] === hashes[1] || hashes[1] === hashes[2] || hashes[2] === hashes[0]) {
continue;
}
// iterate over every edge
for (let j = 0; j < 3; j++) {
// get the first and next vertex making up the edge
const jNext = (j + 1) % 3;
const vecHash0 = hashes[j];
const vecHash1 = hashes[jNext];
const v0 = _triangle[vertKeys[j]];
const v1 = _triangle[vertKeys[jNext]];
const hash = `${vecHash0}_${vecHash1}`;
const reverseHash = `${vecHash1}_${vecHash0}`;
if (reverseHash in edgeData && edgeData[reverseHash]) {
// if we found a sibling edge add it into the vertex array if
// it meets the angle threshold and delete the edge from the map.
if (_normal.dot(edgeData[reverseHash].normal) <= thresholdDot) {
vertices.push(v0.x, v0.y, v0.z);
vertices.push(v1.x, v1.y, v1.z);
}
edgeData[reverseHash] = null;
} else if (!(hash in edgeData)) {
// if we've already got an edge here then skip adding a new one
edgeData[hash] = {
index0: indexArr[j],
index1: indexArr[jNext],
normal: _normal.clone(),
};
}
}
}
// iterate over all remaining, unmatched edges and add them to the vertex array
for (const key in edgeData) {
if (edgeData[key]) {
const { index0, index1 } = edgeData[key];
_v0.fromBufferAttribute(positionAttr, index0);
_v1.fromBufferAttribute(positionAttr, index1);
vertices.push(_v0.x, _v0.y, _v0.z);
vertices.push(_v1.x, _v1.y, _v1.z);
}
}
this.setAttribute('position', new Float32BufferAttribute(vertices, 3));
}
}
}
export { EdgesGeometry };