@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
132 lines (120 loc) • 3.81 kB
text/typescript
import {Vector3, BufferGeometry} from 'three';
import {setToArray, setDifference} from '../../../../../SetUtils';
import {TriangleGraph} from './TriangleGraph';
import {randFloat} from '../../../../../math/_Module';
import {sample} from '../../../../../ArrayUtils';
import {Number3} from '../../../../../../types/GlobalTypes';
const _v3 = new Vector3();
const _triangleIds: Set<number> = new Set();
const _edgeIds0 = new Set<string>();
const _edgeIds1 = new Set<string>();
const _edgeIds2 = new Set<string>();
const _notVisited = new Set<string>();
const _edgeIdsArray: string[] = [];
const _triangleIndices: Number3 = [0, 0, 0];
export function triangleGraphFromGeometry(geometry: BufferGeometry): TriangleGraph | undefined {
const index = geometry.getIndex();
if (!index) {
return;
}
const trianglesCount = index.array.length / 3;
const graph = new TriangleGraph();
for (let i = 0; i < trianglesCount; i++) {
_v3.fromArray(index.array, i * 3);
_v3.toArray(_triangleIndices);
graph.addTriangle(_triangleIndices);
}
return graph;
}
export function triangleGraphExpandEdges(
graph: TriangleGraph,
startEdgeIds: Readonly<Set<string>>,
target: Set<string>,
excluded?: Readonly<Set<string>>
) {
_triangleIds.clear();
target.clear();
startEdgeIds.forEach((edgeId) => {
const edge = graph.edge(edgeId);
if (edge) {
const edgeTriangleIds = edge.triangleIds;
for (const triangleId of edgeTriangleIds) {
_triangleIds.add(triangleId);
}
}
});
_triangleIds.forEach((triangleId) => {
const triangleEdges = graph.edgesByTriangleId(triangleId);
if (triangleEdges) {
for (const edge of triangleEdges) {
if (!startEdgeIds.has(edge.id) && (excluded == null || !excluded.has(edge.id))) {
target.add(edge.id);
}
}
}
});
}
export function getFirstEdgeIdBetweenTriangles(graph: TriangleGraph, edgeIds: string[]) {
for (const edgeId of edgeIds) {
const edge = graph.edge(edgeId);
if (edge && edge.triangleIds.length == 2) {
return edgeId;
}
}
}
export function sortEdgesFromLargestToSmallest(edgeIds: string[], edgeLengthById: Map<string, number>) {
edgeIds.sort((a, b) => {
const lengthA = edgeLengthById.get(a)!;
const lengthB = edgeLengthById.get(b)!;
return lengthB - lengthA;
});
}
export function triangleGraphFindNextLargest(
edgeLengthById: Map<string, number>,
graph: TriangleGraph,
startEdgeId: string,
visited: Readonly<Set<string>>
): string | undefined {
_edgeIds0.clear();
_edgeIds0.add(startEdgeId);
triangleGraphExpandEdges(graph, _edgeIds0, _edgeIds1);
triangleGraphExpandEdges(graph, _edgeIds1, _edgeIds2, _edgeIds0);
setToArray(_edgeIds2, _edgeIdsArray);
sortEdgesFromLargestToSmallest(_edgeIdsArray, edgeLengthById);
for (const edgeId of _edgeIdsArray) {
if (!visited.has(edgeId)) {
return edgeId;
}
}
}
const SEED_OFFSET = 17.336;
export function triangleGraphFindExpandedEdge(
edgeLengthById: Map<string, number>,
graph: TriangleGraph,
startEdgeId: string,
seed: number,
step: number,
irregularAmount: number,
visited: Readonly<Set<string>>,
randomSample3: (step: number) => string | undefined
): string | undefined {
const seed0 = randFloat(seed + step);
const _sampleFromEdges2 = () => {
const seed1 = randFloat(seed + step + SEED_OFFSET);
//
_edgeIds0.clear();
_edgeIds0.add(startEdgeId);
triangleGraphExpandEdges(graph, _edgeIds0, _edgeIds1);
triangleGraphExpandEdges(graph, _edgeIds1, _edgeIds2, _edgeIds0);
//
setDifference(_edgeIds2, visited, _notVisited);
setToArray(_notVisited, _edgeIdsArray);
if (seed1 > irregularAmount) {
sortEdgesFromLargestToSmallest(_edgeIdsArray, edgeLengthById);
return _edgeIdsArray[0];
} else {
return sample(_edgeIdsArray, seed);
}
};
return seed0 > irregularAmount ? _sampleFromEdges2() : randomSample3(step);
}