feat: testing on how to flatten tree structures
This commit is contained in:
@ -24,7 +24,7 @@
|
||||
"input-elements": "link:../packages/input-elements",
|
||||
"jsondiffpatch": "^0.6.0",
|
||||
"meshline": "^3.2.0",
|
||||
"plantarium-nodes-math": "link:../nodes/math/pkg",
|
||||
"plantarium-nodes-math": "link:../nodes/max/plantarium/math/pkg",
|
||||
"three": "^0.159.0",
|
||||
"three.meshline": "^1.4.0"
|
||||
},
|
||||
|
@ -53,7 +53,7 @@
|
||||
|
||||
<div class="wrapper" data-node-id={node.id}>
|
||||
<div class="content">
|
||||
{node.type} / {node.id}
|
||||
{node.type.split("/").pop()}
|
||||
</div>
|
||||
<div
|
||||
class="click-target"
|
||||
|
@ -5,17 +5,17 @@
|
||||
|
||||
export let node: Node;
|
||||
export let input: NodeInput;
|
||||
export let id: string;
|
||||
export let label: string;
|
||||
|
||||
const graph = getGraphManager();
|
||||
|
||||
let value = node?.props?.[id] ?? input.value;
|
||||
let value = node?.props?.[label] ?? input.value;
|
||||
|
||||
$: if (node?.props?.[id] !== value) {
|
||||
node.props = { ...node.props, [id]: value };
|
||||
$: if (node?.props?.[label] !== value) {
|
||||
node.props = { ...node.props, [label]: value };
|
||||
graph.execute();
|
||||
}
|
||||
</script>
|
||||
|
||||
<label for="asd">{id}</label>
|
||||
<label for="asd">{label}</label>
|
||||
<Input {input} bind:value />
|
||||
|
@ -69,7 +69,7 @@
|
||||
>
|
||||
{#key id && graphId}
|
||||
<div class="content" class:disabled={$inputSockets.has(socketId)}>
|
||||
<NodeInput {node} {input} {id} />
|
||||
<NodeInput {node} {input} label={input?.title || id} />
|
||||
</div>
|
||||
|
||||
{#if node?.tmp?.type?.inputs?.[id]?.internal !== true}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { writable, type Writable } from "svelte/store";
|
||||
import type { Graph, Node, Edge, Socket, NodeRegistry, RuntimeExecutor, } from "@nodes/s";
|
||||
import type { Graph, Node, Edge, Socket, NodeRegistry, RuntimeExecutor, } from "@nodes/s";
|
||||
import { HistoryManager } from "./history-manager";
|
||||
import * as templates from "./graphs";
|
||||
import EventEmitter from "./helpers/EventEmitter";
|
||||
@ -145,6 +145,8 @@ export class GraphManager extends EventEmitter<{ "save": Graph }> {
|
||||
this.status.set("loading");
|
||||
this.id.set(graph.id);
|
||||
|
||||
this.nodeRegistry.load();
|
||||
|
||||
for (const node of this.graph.nodes) {
|
||||
const nodeType = this.nodeRegistry.getNode(node.type);
|
||||
if (!nodeType) {
|
||||
@ -165,6 +167,7 @@ export class GraphManager extends EventEmitter<{ "save": Graph }> {
|
||||
|
||||
this.loaded = true;
|
||||
logger.log(`Graph loaded in ${performance.now() - a}ms`);
|
||||
setTimeout(() => this.execute(), 100);
|
||||
}
|
||||
|
||||
|
||||
|
@ -20,8 +20,8 @@ export function grid(width: number, height: number) {
|
||||
visible: false,
|
||||
},
|
||||
position: [x * 30, y * 40],
|
||||
props: i == 0 ? { value: 0 } : {},
|
||||
type: i == 0 ? "input/float" : "math",
|
||||
props: i == 0 ? { value: 0 } : { op_type: 1, a: 2, b: i },
|
||||
type: i == 0 ? "max/plantarium/input-float" : "max/plantarium/math",
|
||||
});
|
||||
|
||||
graph.edges.push([i, 0, i + 1, i === amount - 1 ? "input" : "a",]);
|
||||
|
@ -10,7 +10,7 @@ export function tree(depth: number): Graph {
|
||||
},
|
||||
{
|
||||
id: 1,
|
||||
type: "math",
|
||||
type: "max/plantarium/math",
|
||||
position: [-40, -10]
|
||||
}
|
||||
]
|
||||
@ -33,13 +33,13 @@ export function tree(depth: number): Graph {
|
||||
|
||||
nodes.push({
|
||||
id: id0,
|
||||
type: "math",
|
||||
type: "max/plantarium/math",
|
||||
position: [x, y],
|
||||
});
|
||||
edges.push([id0, 0, parent, "a"]);
|
||||
nodes.push({
|
||||
id: id1,
|
||||
type: "math",
|
||||
type: "max/plantarium/math",
|
||||
position: [x, y + 35],
|
||||
});
|
||||
edges.push([id1, 0, parent, "b"]);
|
||||
|
@ -1,22 +1,58 @@
|
||||
import type { NodeRegistry, NodeType } from "@nodes/types";
|
||||
|
||||
import * as d from "plantarium-nodes-math";
|
||||
function binaryArrayToNumber(binaryArray: number[]): number {
|
||||
let result = 0;
|
||||
for (let i = 0; i < binaryArray.length; i++) {
|
||||
result = (result << 1) + binaryArray[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const nodeTypes: NodeType[] = [
|
||||
{
|
||||
id: "input/float",
|
||||
id: "max/plantarium/input-float",
|
||||
inputs: {
|
||||
"value": { type: "float", value: 0.1, internal: true },
|
||||
},
|
||||
outputs: ["float"],
|
||||
execute: ({ value }) => { return value }
|
||||
execute: ({ value }) => { return [0, 1, 0, value] }
|
||||
},
|
||||
{
|
||||
id: d.get_id(),
|
||||
inputs: JSON.parse(d.get_input_types()),
|
||||
outputs: d.get_outputs(),
|
||||
execute: ({ op_type, a, b }) => {
|
||||
return d.execute(op_type, a, b);
|
||||
id: "max/plantarium/math",
|
||||
inputs: {
|
||||
"op_type": { title: "type", type: "select", labels: ["add", "subtract", "multiply", "divide"], value: 0 },
|
||||
"a": { type: "float" },
|
||||
"b": { type: "float" },
|
||||
},
|
||||
outputs: ["float"],
|
||||
execute: ({ op_type, a, b }: { op_type: number, a: number, b: number }) => {
|
||||
|
||||
const res = [1, 3, -1, op_type, 0, 0];
|
||||
|
||||
const bitmask = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
||||
|
||||
console.log({ a, b });
|
||||
|
||||
if (Array.isArray(a)) {
|
||||
res[4] = res.length;
|
||||
res.push(...a);
|
||||
bitmask[1] = 1;
|
||||
console.log("A", res.length, a.length);
|
||||
} else {
|
||||
res[4] = a;
|
||||
}
|
||||
|
||||
if (Array.isArray(b)) {
|
||||
res[5] = res.length;
|
||||
res.push(...b);
|
||||
bitmask[2] = 1;
|
||||
} else {
|
||||
res[5] = b;
|
||||
}
|
||||
|
||||
res[2] = binaryArrayToNumber(bitmask);
|
||||
|
||||
return res
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -28,11 +64,41 @@ const nodeTypes: NodeType[] = [
|
||||
}
|
||||
]
|
||||
|
||||
export class RemoteNodeRegistry implements NodeRegistry {
|
||||
|
||||
private nodes: Map<string, NodeType> = new Map();
|
||||
|
||||
constructor(private url: string) { }
|
||||
|
||||
async load(nodeIds: string[]) {
|
||||
for (const id of nodeIds) {
|
||||
const response = await fetch(`${this.url}/nodes/${id}`);
|
||||
const node = this.getNode(id);
|
||||
if (node) {
|
||||
this.nodes.set(id, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getNode(id: string) {
|
||||
return this.nodes.get(id);
|
||||
}
|
||||
|
||||
getAllNodes() {
|
||||
return [...this.nodes.values()];
|
||||
}
|
||||
}
|
||||
|
||||
export class MemoryNodeRegistry implements NodeRegistry {
|
||||
getNode(id: string): NodeType | undefined {
|
||||
|
||||
async load(nodeIds: string[]) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
getNode(id: string) {
|
||||
return nodeTypes.find((nodeType) => nodeType.id === id);
|
||||
}
|
||||
getAllNodes(): NodeType[] {
|
||||
getAllNodes() {
|
||||
return [...nodeTypes];
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,93 @@
|
||||
import type { Graph, NodeRegistry, NodeType, RuntimeExecutor } from "@nodes/types";
|
||||
|
||||
|
||||
function numberToBinaryArray(number: number): number[] {
|
||||
const binaryArray: number[] = [];
|
||||
for (let i = 31; i >= 0; i--) {
|
||||
const bit = (number >> i) & 1;
|
||||
binaryArray.push(bit);
|
||||
}
|
||||
return binaryArray;
|
||||
}
|
||||
|
||||
function evaluate_node([node_type, ...args]: number[]) {
|
||||
|
||||
// Float node
|
||||
if (node_type === 0) {
|
||||
return args[0];
|
||||
}
|
||||
|
||||
console.log(args);
|
||||
|
||||
// Math node
|
||||
if (node_type === 1) {
|
||||
if (args[0] === 0) {
|
||||
return args[1] + args[2];
|
||||
} else if (args[0] === 1) {
|
||||
return args[1] - args[2];
|
||||
} else if (args[0] === 2) {
|
||||
return args[1] * args[1];
|
||||
} else {
|
||||
return args[1] / args[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function read_node(index: number, params: number[], depth = 0) {
|
||||
if (depth > 20) {
|
||||
throw new Error("Max depth reached");
|
||||
}
|
||||
|
||||
const node_type = params[index];
|
||||
const amount_of_args = params[index + 1];
|
||||
const bitmask = params[index + 2];
|
||||
console.log("READ_NODE", index, { node_type, bitmask, amount_of_args });
|
||||
|
||||
const mask = numberToBinaryArray(bitmask);
|
||||
|
||||
// there are not nodes connected to this node, lets evaluate
|
||||
if (bitmask === 0) {
|
||||
console.log("EVALUATE", index, params);
|
||||
}
|
||||
|
||||
const args = [];
|
||||
|
||||
for (let i = 0; i < amount_of_args; i++) {
|
||||
const isNode = mask[i] === 1;
|
||||
if (isNode) {
|
||||
console.log("NODE", index + 3 + i, params.slice(index + 3 + i, index + 3 + i + 5));
|
||||
args[i] = read_node(params[index + 3 + i], params, depth + 1);
|
||||
} else {
|
||||
args[i] = params[index + 3 + i];
|
||||
}
|
||||
}
|
||||
|
||||
console.log({ node_type, amount_of_args, args, bitmask });
|
||||
return evaluate_node([node_type, ...args]);
|
||||
|
||||
}
|
||||
|
||||
function split_params(params: number[]) {
|
||||
const result = [];
|
||||
let index = 0;
|
||||
while (index < params.length) {
|
||||
const amount_of_args = params[index + 1];
|
||||
const node_size = 3 + amount_of_args;
|
||||
result.push(params.slice(index, index + node_size));
|
||||
index += node_size;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function evaluate(params: number[]) {
|
||||
console.log("PARAMS", split_params(params));
|
||||
const node = read_node(0, params);
|
||||
|
||||
console.log("RESULT: ", node);
|
||||
|
||||
}
|
||||
|
||||
export class MemoryRuntimeExecutor implements RuntimeExecutor {
|
||||
|
||||
constructor(private registry: NodeRegistry) { }
|
||||
@ -130,7 +218,12 @@ export class MemoryRuntimeExecutor implements RuntimeExecutor {
|
||||
}
|
||||
|
||||
// return the result of the parent of the output node
|
||||
return results[outputNode.tmp?.parents?.[0].id as number] as string
|
||||
const res = results[outputNode.tmp?.parents?.[0].id as number] as string
|
||||
|
||||
evaluate(res);
|
||||
|
||||
|
||||
return res;
|
||||
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user