UNPKG

@polygonjs/polygonjs

Version:

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

149 lines (148 loc) 4.75 kB
"use strict"; 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); } }