UNPKG

@polygonjs/polygonjs

Version:

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

360 lines (359 loc) 11.2 kB
"use strict"; import { isArray } from "../Type"; import { addToSetAtEntry } from "../MapUtils"; const _idStack = []; const _idsSet = /* @__PURE__ */ new Set(); export class CoreGraph { constructor() { this._nextId = 0; this._successors = /* @__PURE__ */ new Map(); this._predecessors = /* @__PURE__ */ new Map(); this._nodesById = /* @__PURE__ */ new Map(); this._forbiddenTriggerNodeIds = /* @__PURE__ */ new Map(); this._selfDirtyForbidden = /* @__PURE__ */ new Set(); this._nodesCount = 0; this._debugging = false; this._addedNodesDuringDebugging = /* @__PURE__ */ new Map(); this._boundPredecessorIds = this.predecessorIds.bind(this); this._boundSuccessorIds = this.successorIds.bind(this); } startDebugging() { this._debugging = true; } stopDebugging() { this._debugging = false; } printDebug() { this._addedNodesDuringDebugging.forEach((node, nodeId) => { console.log(nodeId, node, node.graphPredecessors(), node.graphSuccessors()); }); } // print() { // this._nodesById.forEach((node, nodeId) => { // console.log(nodeId, node, node.graphPredecessors(), node.graphSuccessors()); // }); // } setScene(scene) { this._scene = scene; } scene() { return this._scene; } nextId() { this._nextId += 1; return this._nextId; } nodesFromIds(ids, target) { target.length = 0; for (const id of ids) { const node = this.nodeFromId(id); if (node) { target.push(node); } } } nodeFromId(id) { return this._nodesById.get(id); } hasNode(node) { return this._nodesById.get(node.graphNodeId()) != null; } addNode(node) { this._nodesById.set(node.graphNodeId(), node); this._nodesCount += 1; if (this._debugging) { this._addedNodesDuringDebugging.set(node.graphNodeId(), node); } } removeNode(node) { this.disconnectPredecessors(node); this.disconnectSuccessors(node); const nodeId = node.graphNodeId(); this._nodesById.delete(nodeId); this._successors.delete(nodeId); this._predecessors.delete(nodeId); this._nodesCount -= 1; this._forbiddenTriggerNodeIds.delete(nodeId); this._forbiddenTriggerNodeIds.forEach((set, nodeId2) => { if (set.has(nodeId2)) { set.delete(nodeId2); } }); this._selfDirtyForbidden.delete(nodeId); if (this._debugging) { this._addedNodesDuringDebugging.delete(nodeId); } } nodesCount() { return this._nodesCount; } connect(src, dest, checkCycle = true) { const srcId = src.graphNodeId(); const destId = dest.graphNodeId(); if (!(this.hasNode(src) && this.hasNode(dest))) { console.warn(`attempt to connect non existing node ${srcId} or ${destId}`); return false; } if (checkCycle) { const sceneLoading = this._scene ? this._scene.loadingController.isLoading() : true; checkCycle = !sceneLoading; } const graphWouldHaveCycle = checkCycle ? src.hasPredecessor(dest) : false; if (graphWouldHaveCycle) { return false; } else { this._createConnection(srcId, destId); src.clearCachesWithPredecessorsAndSuccessors(); return true; } } disconnect(src, dest) { this._removeConnection(src.graphNodeId(), dest.graphNodeId()); src.clearCachesWithPredecessorsAndSuccessors(); dest.clearCachesWithPredecessorsAndSuccessors(); } disconnectPredecessors(node) { const predecessors = this.predecessors(node); if (!predecessors) { return; } for (const predecessor of predecessors) { this.disconnect(predecessor, node); } } disconnectSuccessors(node) { const successors = this.successors(node); if (!successors) { return; } for (const successor of successors) { this.disconnect(node, successor); } } predecessorIds(id) { var _a; return (_a = this._predecessors.get(id)) == null ? void 0 : _a.idsArray; } predecessors(node) { var _a; return (_a = this._predecessors.get(node.graphNodeId())) == null ? void 0 : _a.nodes; } successorIds(id) { var _a; return (_a = this._successors.get(id)) == null ? void 0 : _a.idsArray; } successors(node) { var _a; return (_a = this._successors.get(node.graphNodeId())) == null ? void 0 : _a.nodes; } // private _allNodeIds(node: CoreGraphNode, method: TraverseCallback, target: CoreGraphNodeId[]): void { // target.length = 0; // _idsSet.clear(); // _idStack.length = 1; // _idStack[0] = node.graphNodeId(); // const forbiddenIds = this._forbiddenTriggerNodeIds.get(node.graphNodeId()) // while (_idStack.length > 0) { // const currentId = _idStack.pop()!; // const ids = method(currentId); // if (ids) { // for (const id of ids) { // if (!_idsSet.has(id)) { // _idsSet.add(id); // target.push(id); // _idStack.push(id); // } // } // } // } // } allPredecessorIds(node, target) { target.length = 0; _idsSet.clear(); _idStack.length = 1; _idStack[0] = node.graphNodeId(); while (_idStack.length > 0) { const currentId = _idStack.pop(); const ids = this._boundPredecessorIds(currentId); if (ids) { for (const id of ids) { if (!_idsSet.has(id)) { _idsSet.add(id); target.push(id); _idStack.push(id); } } } } } allSuccessorIds(node, target) { target.length = 0; _idsSet.clear(); _idStack.length = 1; _idStack[0] = node.graphNodeId(); const forbiddenIds = this._forbiddenTriggerNodeIds.get(node.graphNodeId()); while (_idStack.length > 0) { const currentId = _idStack.pop(); const ids = this._boundSuccessorIds(currentId); if (ids) { for (const id of ids) { if (!_idsSet.has(id)) { _idsSet.add(id); if (forbiddenIds == null || !forbiddenIds.has(id)) { target.push(id); _idStack.push(id); } } } } } } // private _allNodes(node: CoreGraphNode, method: TraverseCallback, target: CoreGraphNode[]): void { // target.length = 0; // _idsSet.clear(); // _idStack.length = 1; // _idStack[0] = node.graphNodeId(); // while (_idStack.length > 0) { // const currentId = _idStack.pop()!; // const ids = method(currentId); // if (ids) { // for (const id of ids) { // if (!_idsSet.has(id)) { // _idsSet.add(id); // const otherNode = this._nodesById.get(id); // if (otherNode) { // target.push(otherNode); // } // _idStack.push(id); // } // } // } // } // } allPredecessors(node, target) { target.length = 0; _idsSet.clear(); _idStack.length = 1; _idStack[0] = node.graphNodeId(); while (_idStack.length > 0) { const currentId = _idStack.pop(); const ids = this._boundPredecessorIds(currentId); if (ids) { for (const id of ids) { if (!_idsSet.has(id)) { _idsSet.add(id); const otherNode = this._nodesById.get(id); if (otherNode) { target.push(otherNode); } _idStack.push(id); } } } } } allSuccessors(node, target) { target.length = 0; _idsSet.clear(); _idStack.length = 1; _idStack[0] = node.graphNodeId(); const forbiddenIds = this._forbiddenTriggerNodeIds.get(node.graphNodeId()); while (_idStack.length > 0) { const currentId = _idStack.pop(); const ids = this._boundSuccessorIds(currentId); if (ids) { for (const id of ids) { if (!_idsSet.has(id)) { _idsSet.add(id); if (forbiddenIds == null || !forbiddenIds.has(id)) { const otherNode = this._nodesById.get(id); if (otherNode) { target.push(otherNode); } _idStack.push(id); } } } } } } _createConnection(srcId, destId) { let successorsData = this._successors.get(srcId); let predecessorsData = this._predecessors.get(destId); if (!successorsData) { successorsData = { idsSet: /* @__PURE__ */ new Set(), idsArray: [], nodes: [] }; this._successors.set(srcId, successorsData); } if (!predecessorsData) { predecessorsData = { idsSet: /* @__PURE__ */ new Set(), idsArray: [], nodes: [] }; this._predecessors.set(destId, predecessorsData); } if (!successorsData.idsSet.has(destId)) { successorsData.idsSet.add(destId); successorsData.idsArray.push(destId); const destNode = this._nodesById.get(destId); if (destNode) { successorsData.nodes.push(destNode); } else { throw new Error(`creating connection with node not in graph ${destId}`); } } if (!predecessorsData.idsSet.has(srcId)) { predecessorsData.idsSet.add(srcId); predecessorsData.idsArray.push(srcId); const srcNode = this._nodesById.get(srcId); if (srcNode) { predecessorsData.nodes.push(srcNode); } else { throw new Error(`creating connection with node not in graph ${srcId}`); } } } _removeConnection(srcId, destId) { const successorsData = this._successors.get(srcId); if (successorsData && successorsData.idsSet.has(destId)) { successorsData.idsSet.delete(destId); const idIndex = successorsData.idsArray.indexOf(destId); if (idIndex >= 0) { successorsData.idsArray.splice(idIndex, 1); successorsData.nodes.splice(idIndex, 1); } else { console.warn(`could not find id ${destId} in successorsData.idsArray`, successorsData.idsArray); } } const predecessorsData = this._predecessors.get(destId); if (predecessorsData && predecessorsData.idsSet.has(srcId)) { predecessorsData.idsSet.delete(srcId); const idIndex = predecessorsData.idsArray.indexOf(srcId); if (idIndex >= 0) { predecessorsData.idsArray.splice(idIndex, 1); predecessorsData.nodes.splice(idIndex, 1); } else { console.warn(`could not find id ${srcId} in predecessorsData.idsArray`, predecessorsData.idsArray); } } } setForbiddenTriggerNodes(src, dest) { var _a; (_a = this._forbiddenTriggerNodeIds.get(src.graphNodeId())) == null ? void 0 : _a.clear(); if (isArray(dest)) { for (const destNode of dest) { addToSetAtEntry(this._forbiddenTriggerNodeIds, src.graphNodeId(), destNode.graphNodeId()); } } else { addToSetAtEntry(this._forbiddenTriggerNodeIds, src.graphNodeId(), dest.graphNodeId()); } } clearForbiddenTriggerNodes(src) { this._forbiddenTriggerNodeIds.delete(src.graphNodeId()); } setSelfDirtyForbidden(node, state) { if (state) { this._selfDirtyForbidden.add(node.graphNodeId()); } else { this._selfDirtyForbidden.delete(node.graphNodeId()); } } selfDirtyForbidden(node) { return this._selfDirtyForbidden.has(node.graphNodeId()); } }