@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
149 lines (148 loc) • 4.75 kB
JavaScript
;
import { Vector3, BufferGeometry, Float32BufferAttribute } from "three";
import { TypedSopNode } from "./_Base";
import { NodeParamsConfig, ParamConfig } from "../utils/params/ParamsConfig";
import { InputCloneMode } from "../../poly/InputCloneMode";
import { CoreMask } from "../../../core/geometry/Mask";
import { SopType } from "../../poly/registers/nodes/types/Sop";
import { Node, Edge, Graph, AStar } from "../../../core/thirdParty/yuka/yuka";
import { Attribute } from "../../../core/geometry/Attribute";
import { ObjectType } from "../../../core/geometry/Constant";
const _v0 = new Vector3();
const _v1 = new Vector3();
const EDGES = [
[0, 1],
[1, 2],
[2, 0]
];
function getDist(graph, source, target) {
const sourceNode = graph.getNode(source);
const targetNode = graph.getNode(target);
if (!(sourceNode && targetNode)) {
return 0;
}
sourceNode.position(_v0);
targetNode.position(_v1);
return _v0.distanceToSquared(_v1);
}
const heuristicPolicy = {
calculate: getDist
};
class PositionNode extends Node {
constructor(index, positionArray) {
super(index);
this.index = index;
this.positionArray = positionArray;
}
position(target) {
return target.fromArray(this.positionArray, this.index * 3);
}
}
class ShortestPathSopParamsConfig extends NodeParamsConfig {
constructor() {
super(...arguments);
/** @param objects to find paths in */
this.group = ParamConfig.STRING("", {
objectMask: true
});
/** @param index of start point */
this.pt0 = ParamConfig.INTEGER(0, {
range: [0, 100],
rangeLocked: [true, false]
});
/** @param index of end point */
this.pt1 = ParamConfig.INTEGER(1, {
range: [0, 100],
rangeLocked: [true, false]
});
}
}
const ParamsConfig = new ShortestPathSopParamsConfig();
export class ShortestPathSopNode extends TypedSopNode {
constructor() {
super(...arguments);
this.paramsConfig = ParamsConfig;
}
static type() {
return SopType.SHORTEST_PATH;
}
initializeNode() {
this.io.inputs.setCount(1);
this.io.inputs.initInputsClonedState(InputCloneMode.NEVER);
}
cook(inputCoreGroups) {
const inputCoreGroup = inputCoreGroups[0];
const selectedObjects = CoreMask.filterThreejsObjects(inputCoreGroup, this.pv);
const newObjects = [];
for (const object of selectedObjects) {
this._createShortestPath(object, newObjects);
}
this.setObjects(newObjects);
}
_createShortestPath(object, newObjects) {
const geometry = object.geometry;
if (!geometry) {
return;
}
const positionAttribute = geometry.getAttribute(Attribute.POSITION);
const index = geometry.getIndex();
if (!(positionAttribute && index)) {
return;
}
const pointsCount = positionAttribute.count;
const facesCount = index.count / 3;
const positions = positionAttribute.array;
const indices = index.array;
const endPtBySrcPt = /* @__PURE__ */ new Map();
const graph = new Graph();
for (let i = 0; i < pointsCount; i++) {
const node = new PositionNode(i, positions);
graph.addNode(node);
}
for (let i = 0; i < facesCount; i++) {
for (const edgeIndices of EDGES) {
const i0 = indices[i * 3 + edgeIndices[0]];
const i1 = indices[i * 3 + edgeIndices[1]];
let endPts0 = endPtBySrcPt.get(i0);
let endPts1 = endPtBySrcPt.get(i1);
if (!endPts0) {
endPts0 = /* @__PURE__ */ new Set();
endPtBySrcPt.set(i0, endPts0);
}
if (!endPts1) {
endPts1 = /* @__PURE__ */ new Set();
endPtBySrcPt.set(i1, endPts1);
}
if (!endPts0.has(i1)) {
const edge = new Edge(i0, i1, 0);
graph.addEdge(edge);
endPts0.add(i1);
endPts1.add(i0);
}
}
}
const solver = new AStar(graph, this.pv.pt0, this.pv.pt1);
solver.heuristic = heuristicPolicy;
solver.search();
const path = solver.getPath();
this._buildLine(path, graph, newObjects);
}
_buildLine(path, graph, newObjects) {
const pointsCount = path.length;
const positions = new Array(pointsCount * 3);
const indices = new Array(pointsCount);
for (let i = 0; i < pointsCount; i++) {
const node = graph.getNode(path[i]);
node.position(_v0).toArray(positions, i * 3);
if (i > 0) {
indices[(i - 1) * 2] = i - 1;
indices[(i - 1) * 2 + 1] = i;
}
}
const geometry = new BufferGeometry();
geometry.setAttribute("position", new Float32BufferAttribute(positions, 3));
geometry.setIndex(indices);
const object = this.createObject(geometry, ObjectType.LINE_SEGMENTS);
newObjects.push(object);
}
}