¿Implementando una interfaz gráfica basada en nodos?

Me gustaría implementar una interfaz nodal, básicamente un DAG donde cada nodo realiza una operación en sus conexiones de entrada y genera algo (que puede conectarse a otro nodo)

Algunas aplicaciones de ejemplo:

  • Manzanas “Shake” – captura de pantalla
  • The Foundrys “Nuke” : captura de pantalla
  • MindNode : captura de pantalla
  • vvvv : capturas de pantalla
  • Quartz Composer – captura de pantalla

Como primer objective, me gustaría tener una aplicación gráfica con solo 2 nodos. Un “número” que simplemente genera un número fijo, y un nodo “Agregar”, que toma dos entradas y genera la sum de los dos.

Como la gente ha respondido hasta ahora, tengo una idea aproximada de cómo representar los datos en código, por ejemplo en Python‘y buscando pseudo-código:

class Number: def __init__(self, value): self.value = value def eval(self): return self.value class Add: def __init__(self, input1, input2): self.input1 = input1 self.input2 = input2 def eval(self): return self.input1.eval() + self.input2.eval() a = Number(20) b = Number(72) adder = Add(a, b) print adder.eval() 

¿Cómo podría ser acerca de envolver una GUI personalizada alrededor de esto? Algo parecido a lo siguiente, pero un poco menos dibujado a mano!

maqueta de interfaz de usuario nodal

¿Por dónde empezar? Actualmente planeo escribirlo en Objective-C / Cocoa, aunque estoy más que abierto a sugerencias para otros idiomas.

Related of "¿Implementando una interfaz gráfica basada en nodos?"

Comenzaría por modelar algunas interfaces básicas (en el sentido OOP, no en el sentido GUI). Me parece que tendrás un nodo que aceptará una colección de entradas y una sola salida. No dio ninguna indicación de cuán amplios son los tipos de datos, pero querrá algún método adecuado para representar sus entradas / salidas. Para su primer objective, este podría ser un número entero.

En algún lenguaje genérico de estilo OOP (espero que tenga sentido):

 class Node { Node[] inputs; T eval(); } class AdderNode extends Node { int eval() { int accum = 0; for (inputs : i) accum += i.eval(); return i; } } class ConstNode extends Node { int eval() { return I; } } AdderNode a; a.inputs.add(ConstNode<2>()); a.inputs.add(ConstNode<3>()); a.eval(); 

Puede ampliar esto reemplazando int con alguna clase abstracta, genérica o interfaz. La implementación real variará según el idioma real, por supuesto.

Empezaría por modelar las operaciones interesantes. En última instancia, los conectará a una UI, pero ese es el volante y el pedal del acelerador, no el motor.

Lo que intenta construir tiene mucho en común con los lenguajes de progtwigción: variables, valores, tipos, expresiones, evaluación, etc. Muchas de las metáforas son aplicables y pueden proporcionar alguna orientación.

Si está utilizando .NET 3.5, tiene la opción de Árboles de Expresión , que le permiten representar y comstackr expresiones de código en tiempo de ejecución.

Por ejemplo, para modelar tu primer objective:

 using System.Linq.Expressions; ConstantExpression theNumber2 = Expression.Constant(2); ConstantExpression theNumber3 = Expression.Constant(3); BinaryExpression add2And3 = Expression.Add(theNumber2, theNumber3); 

Para invocar la expresión, necesitamos envolver add2And3 con un método. Esto se hace con una expresión lambda:

 Expression> add2And3Lambda = Expression.Lambda>(add2And3); 

Func representa un método que no toma parámetros y devuelve un int . En C #, el código representado por add2And3Lambda sería:

 () => 2 + 3 

Entonces, lo que tenemos es un árbol de expresiones cuya raíz es un método. Debido a que un método es llamable , podemos comstackr el árbol en una instancia del tipo de delegado subyacente:

 Func add2And3Func = add2And3Lambda.Compile(); 

Ahora podemos invocar el código que construimos:

 int theNumber5 = add2And3Func(); 

Todas las expresiones disponibles para lenguajes .NET son compatibles.

Imagina que cada nodo en tu gráfica tiene una Expression asociada. Eso podría darle una idea del poder de los árboles de expresión y cómo podrían ayudarlo con esta tarea.

Todos los sistemas de nodos tienen en común que describen un lenguaje de progtwigción funcional. Una función toma múltiples parámetros y devuelve un solo resultado, sin importar para qué propósito fue diseñada. Algunos ejemplos:

  • Gráficos: Desenfoque (Imagen, Kernel, Radio) -> Imagen

  • Matemáticas: Suma (Número, Número) -> Número

  • Relacional: Filtro (Tabla, Predicado) -> Tabla

Básicamente eso se reduce a una firma de función como Func (C #).

Se enfrentará a la pregunta de cómo hacer que su sistema de nodos sea persistente. ¿Desea hacer que el resultado de un nodo sea utilizable como parámetro solo por otro nodo (árbol) o por varios nodos (gráfico)?

Ejemplo de un árbol, tienen directamente los parámetros a nodos hijos:

 Add( Multiply( Constant(5), Constant(4) ), Multiply( Constant(5), Constant(3) ) ) 

Ejemplo de un gráfico, almacene todos los nodos en una lista y solo use referencias:

 A := Constant(5) B := Constant(4) C := Constant(3) D := Func(Multiply, A, B) E := Func(Multiply, A, C) F := Func(Add, D, E) 

Encontré información útil sobre cómo implementar dicha interfaz en Cocoa:

  • Introducción a Cuarzo e Introducción a Cuarzo II : describe el dibujo básico en un NSView
  • FlowChartView en Cocoadev: prácticamente lo que estaba buscando, una implementación de la interfaz Quartz Composer.

Tal vez Bwise tiene algo de interés?

En la mitad inferior de esta página, se muestra un ejemplo del uso de bwise para crear un bloque de multiplicación que toma dos números como entrada.

Implementé un gráfico de ejecución como el que describe en este proyecto: GRSFramework

El código fuente se puede encontrar aquí .

Actualmente estoy trabajando para lanzar una versión mejor y más limpia de este sistema en el proyecto ExecutionGraph .
Podría ser de interés para usted también.

Luego también está la biblioteca TensorFlow de Google que tiene un sistema similar implementado TensorFlow

Me topé con este hilo mientras buscaba una solución similar. Recientemente encontré un buen proyecto en github https://github.com/nodebox/nodebox que parece ser exactamente lo que estás buscando. Al menos uno podría extraer y adoptar los componentes del editor del proyecto.

Saludos, Stephan