Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
El bloque de código es una función exclusiva de Dynamo que vincula dinámicamente un entorno de programación visual con uno basado en texto. El bloque de código tiene acceso a todos los nodos de Dynamo y puede definir un gráfico completo en un nodo. Lea este capítulo detenidamente, ya que el bloque de código es un elemento fundamental de Dynamo.
Dynamo es un excelente punto de partida para empezar a codificar en el mundo AEC. Puede que le interesen algunas de estas secciones para iniciar su recorrido por la codificación:


En esta sección, encontrará una serie de lecciones sobre la creación de geometría con DesignScript. Para continuar, copie el contenido de DesignScript de ejemplo en bloques de código de Dynamo.
// copy this code into a Code Block
// to start writing DesignScript
x = "Let's create some geometry!";Python es un lenguaje de programación muy utilizado cuya popularidad tiene mucho que ver con su estilo de sintaxis. Es altamente legible, lo que hace que su aprendizaje sea más sencillo que el de muchos otros idiomas. Python admite módulos y paquetes, y se puede incrustar en aplicaciones existentes. Para obtener información sobre cómo empezar a trabajar con Python, un buen recurso es la página "Getting Started" (Guía de introducción) de Python.org.
Los bloques de código son una ventana a DesignScript, el lenguaje de programación que es la base de Dynamo. Creado desde cero para admitir flujos de trabajo de diseño exploratorios, DesignScript es un lenguaje legible y conciso que ofrece información inmediata a pequeños fragmentos de código y también se adapta a interacciones grandes y complejas. DesignScript también forma la columna vertebral del motor que impulsa la mayoría de los aspectos subyacentes de Dynamo. Como casi todas las funciones de los nodos y las interacciones de Dynamo tienen una relación de uno a uno con el lenguaje de creación de secuencias de comandos, se ofrecen oportunidades únicas de desplazarse entre secuencias de comandos e interacciones basadas en nodos de forma fluida.
Para los principiantes, los nodos se pueden convertir automáticamente en sintaxis de texto para facilitar el aprendizaje de DesignScript o para reducir el tamaño de secciones de gráficos de mayor tamaño. Esto se realiza mediante un proceso denominado "de nodo a código", que se describe con más detalle en la sección . Los usuarios con más experiencia pueden utilizar bloques de código para crear combinaciones personalizadas de funciones existentes y relaciones creadas por el usuario mediante una gran cantidad de paradigmas de codificación estándar. En un nivel intermedio entre los principiantes y los usuarios avanzados, hay disponibles un gran número de accesos directos y fragmentos de código que agilizarán los diseños. Si bien el término "bloque de código" puede intimidar un poco a los que no son programadores, es una herramienta eficaz y fácil de usar. Un principiante puede utilizar de forma eficaz el bloque de código con una mínima creación de código y un usuario avanzado puede establecer definiciones de secuencias de comandos que se pueden recuperar en cualquier parte de una definición de Dynamo.
Los métodos Intersect, Trim y SelectTrim se utilizan principalmente en geometrías dimensionales inferiores como puntos, curvas y superficies. Por otra parte, la geometría sólida cuenta con un conjunto adicional de métodos para modificar la forma después de su creación, tanto sustrayendo material de forma similar a Trim como combinando elementos para formar un todo mayor.
El método Union utiliza dos objetos sólidos para crear un único objeto sólido a partir del espacio cubierto por ambos objetos. El espacio solapado entre los objetos se combina en la forma final. Este ejemplo combina una esfera y un cubo en una forma de esfera-cubo sólida:
En resumen, los bloques de código son una interfaz de creación de secuencias de comandos de texto dentro de un entorno de creación de secuencias de comandos visuales. Se pueden utilizar como números, cadenas, fórmulas y otros tipos de datos. El bloque de código se ha diseñado para Dynamo, por lo que se pueden definir variables arbitrarias en el bloque de código y esas variables se añaden automáticamente a las entradas del nodo:
Con los bloques de código, un usuario dispone de flexibilidad para decidir cómo especificar entradas. A continuación, se indican varias formas de crear un punto básico con coordenadas (10, 5, 0):
A medida que aprende más sobre las funciones disponibles en la biblioteca, es posible que le sea más rápido escribir "Point.ByCoordinates" que buscar en la biblioteca y encontrar el nodo adecuado. Por ejemplo, al escribir "Point.", Dynamo mostrará una lista de posibles funciones que aplicar a un punto. Esto hace que la creación de secuencias de comandos sea más intuitiva y le ayudará a aprender a aplicar funciones en Dynamo.
El bloque de código se encuentra en Core > Entrada > Acciones > Bloque de código. O, simplemente, de forma más rápida, haga doble clic en el lienzo para que aparezca el bloque de código. Este nodo se utiliza con tanta frecuencia que se le han proporcionado privilegios completos de doble clic.
Los bloques de código también son flexibles en relación con los tipos de datos. El usuario puede definir rápidamente números, cadenas y fórmulas, y el bloque de código generará la salida deseada.
En la imagen siguiente, puede comprobar que la forma tradicional de trabajo es algo prolija: el usuario busca el nodo previsto en la interfaz, lo añade al lienzo y, a continuación, introduce los datos. Con el bloque de código, el usuario puede hacer doble clic en el lienzo para desplegar el nodo y escribir el tipo de datos correcto con la sintaxis básica.
Los nodos "number" y "string" son dos ejemplos de nodos de Dynamo que posiblemente estén obsoletos en comparación con el bloque de código.
"Forma tradicional"
Bloques de código

El método Difference, al igual que Trim, resta el contenido del sólido de la herramienta de entrada del sólido base. En este ejemplo, se extrae una pequeña hendidura de una esfera:
El método Intersect devuelve el sólido solapado entre dos entradas sólidas. En el siguiente ejemplo, Difference se ha cambiado a Intersect y el sólido resultante es el vacío que falta que se ha eliminado inicialmente:

Las siguientes secuencias de comandos de Python generan matrices de puntos para varios ejemplos. Se deben pegar en un nodo Python Script, como se indica a continuación:
python_points_1
out_points = []
for i in range(11):
sub_points = []
for j in range(11):
z = 0
if (i == 5 and j == 5):
z = 1
elif (i == 8 and j == 2):
z = 1
sub_points.append(Point.ByCoordinates(i, j, z))
out_points.append(sub_points)
OUT = out_pointspython_points_2
out_points = []
for i in range(11):
z = 0
if (i == 2):
z = 1
out_points.append(Point.ByCoordinates(i, 0, z))
OUT = out_pointspython_points_3
out_points = []
for i in range(11):
z = 0
if (i == 7):
z = -1
out_points.append(Point.ByCoordinates(i, 5, z))
OUT = out_pointspython_points_4
python_points_5
El objeto geométrico más sencillo de la biblioteca de geometría estándar de Dynamo es un punto. Toda la geometría se crea mediante funciones especiales denominadas constructores, que devuelven un nuevo ejemplar de ese tipo de geometría específico. En Dynamo, los constructores empiezan por el nombre del tipo de objeto, en este caso, "Point", seguido del método de construcción. Para crear un punto tridimensional especificado con las coordenadas cartesianas X, Y y Z, utilice el constructor ByCoordinates:
Los constructores de Dynamo se designan normalmente con el prefijo By y, al invocar estas funciones, se devuelve un objeto recién creado de ese tipo. Este objeto recién creado se almacena en la variable designada a la izquierda del signo igual.
Los objetos de los diseños computacionales rara vez se crean explícitamente en su posición y forma finales y, con mayor frecuencia, se convierten, se giran y se colocan de cualquier otro modo a partir de la geometría existente. Las matemáticas vectoriales sirven como una especie de andamiaje geométrico para proporcionar dirección y orientación a la geometría, así como para conceptualizar movimientos a través del espacio 3D sin representación visual.
Como elemento más básico, un vector representa una posición en el espacio 3D y a menudo se considera el punto final de una flecha desde la posición (0, 0, 0) hasta esa posición. Los vectores se pueden crear con el constructor ByCoordinates utilizando la posición X, Y y Z del objeto vectorial que se acaba de crear. Observe que los objetos vectoriales no son objetos geométricos y no aparecen en la ventana de Dynamo. Sin embargo, la información sobre un vector recién creado o modificado se puede imprimir en la ventana de la consola:
Un conjunto de operaciones matemáticas se define en objetos vectoriales, lo que permite sumar, restar, multiplicar y, en general, desplazar objetos en un espacio 3D, tal y como desplazaría números reales en un espacio unidimensional en una línea numérica.
En los diseños computacionales, las curvas y las superficies se utilizan con frecuencia como el andamiaje subyacente para crear la geometría posterior. Para que esta geometría inicial se pueda utilizar como base para la geometría posterior, la secuencia de comandos debe poder extraer cualidades como, por ejemplo, la posición y la orientación en toda el área del objeto. Tanto las curvas como las superficies admiten esta extracción y este proceso se denomina parametrización.
Todos los puntos de una curva se pueden considerar como si tuvieran un parámetro único que oscila entre 0 y 1. Si creáramos una NurbsCurve a partir de varios puntos de control o interpolación, el primer punto tendría el parámetro 0 y el último, el parámetro 1. Es imposible saber por adelantado cuál es el parámetro exacto para cualquier punto intermedio, lo que puede parecer una limitación grave, aunque se mitiga mediante una serie de funciones de utilidad. Las superficies tienen una parametrización similar a la de las curvas, aunque con dos parámetros en lugar de uno, denominados u y v. Si creáramos una superficie con los siguientes puntos:
p1 tendría el parámetro u = 0 v = 0, mientras que p9 tendría los parámetros u = 1 v = 1.
La parametrización no resulta especialmente útil a la hora de determinar los puntos utilizados para generar curvas. Su principal finalidad es determinar las ubicaciones si se utilizan los puntos intermedios generados por los constructores NurbsCurve y NurbsSurface.
Las curvas presentan el método PointAtParameter, que utiliza un único argumento doble entre 0 y 1, y devuelve el objeto de punto en ese parámetro. Por ejemplo, esta secuencia de comandos busca los puntos en los parámetros 0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9 y 1:
El componente análogo bidimensional a una NurbsCurve es la NurbsSurface y, al igual que la NurbsCurve de forma libre, las NurbsSurfaces se pueden crear con dos métodos básicos: la introducción de un conjunto de puntos base y la interpolación entre ellos por parte de Dynamo, y la especificación explícita de los puntos de control de la superficie. Al igual que las curvas de forma libre, las superficies interpoladas son útiles cuando un diseñador conoce con precisión la forma que debe adoptar una superficie o si un diseño requiere que la superficie pase por los puntos de restricción. Por otra parte, las superficies creadas mediante puntos de control pueden ser más útiles para los diseños exploratorios a través de varios niveles de suavizado.
Para crear una superficie interpolada, simplemente genere una colección bidimensional de puntos que se aproxime a la forma de una superficie. La colección debe ser rectangular, es decir, no irregular. El método NurbsSurface.ByPoints crea una superficie a partir de estos puntos.
s1 = Sphere.ByCenterPointRadius(
CoordinateSystem.Identity().Origin, 6);
s2 = Sphere.ByCenterPointRadius(
CoordinateSystem.Identity().Origin.Translate(4, 0,
0), 6);
combined = s1.Union(s2);s = Sphere.ByCenterPointRadius(
CoordinateSystem.Identity().Origin, 6);
tool = Sphere.ByCenterPointRadius(
CoordinateSystem.Identity().Origin.Translate(10, 0,
0), 6);
result = s.Difference(tool);s = Sphere.ByCenterPointRadius(
CoordinateSystem.Identity().Origin, 6);
tool = Sphere.ByCenterPointRadius(
CoordinateSystem.Identity().Origin.Translate(10, 0,
0), 6);
result = s.Intersect(tool);out_points = []
for i in range(11):
z = 0
if (i == 5):
z = 1
out_points.append(Point.ByCoordinates(i, 10, z))
OUT = out_pointsout_points = []
for i in range(11):
sub_points = []
for j in range(11):
z = 0
if (i == 1 and j == 1):
z = 2
elif (i == 8 and j == 1):
z = 2
elif (i == 2 and j == 6):
z = 2
sub_points.append(Point.ByCoordinates(i, j, z))
out_points.append(sub_points)
OUT = out_points





Los puntos se pueden utilizar para crear geometría dimensional superior como, por ejemplo, líneas. Se puede utilizar el constructor ByStartPointEndPoint para crear un objeto de línea entre dos puntos:
De forma similar, las líneas se pueden utilizar para crear geometría de superficie dimensional superior, por ejemplo, mediante el constructor Loft, que utiliza una serie de líneas o curvas e interpola una superficie entre ellas.
Las superficies también se pueden utilizar para crear geometría sólida dimensional superior, por ejemplo, mediante el engrosado de la superficie a una distancia especificada. Muchos objetos tienen funciones enlazadas a ellos denominadas métodos, que permiten al programador ejecutar comandos en ese objeto específico. Entre los métodos comunes a todas las partes de geometría, se incluyen Translate y Rotate, que trasladan (desplazan) y rotan la geometría una cantidad especificada. Las superficies presentan el método Thicken, que utiliza una única entrada, un número que especifica el nuevo grosor de la superficie.
Los comandos de intersección pueden extraer geometría dimensional inferior de objetos dimensionales superiores. Esta geometría dimensional inferior extraída puede formar la base para una geometría dimensional superior en un proceso cíclico de creación, extracción y recreación. En este ejemplo, se utiliza el sólido generado para crear una superficie y se utiliza la superficie para crear una curva.

La adición de vectores se define como la suma de los componentes de dos vectores y se puede entender como el vector resultante si las dos flechas de vector de componente se colocan "de la punta a la cola". La adición de vectores se realiza con el método Add y se representa con el diagrama de la izquierda.
Del mismo modo, se pueden restar dos objetos vectoriales entre sí mediante el método Subtract. La resta de vectores se puede entender como la dirección que va desde el primer vector hasta el segundo.
La multiplicación de vectores se puede entender como el desplazamiento del punto final de un vector en su propia dirección mediante un factor de escala especificado.
A menudo, al ajustar la escala de un vector, es deseable que su longitud sea exactamente igual a la cantidad de escala ajustada. Esto se puede conseguir fácilmente. Para ello, debe normalizarse primero un vector, en otras palabras, se debe establecer la longitud del vector en un valor exactamente igual a uno.
c sigue apuntando en la misma dirección que a (1, 2, 3), aunque ahora tiene una longitud exactamente igual a 5.
Existen dos métodos adicionales en las matemáticas vectoriales que no tienen equivalentes claros con las matemáticas unidimensionales: el producto vectorial y el producto escalar. El producto vectorial permite generar un vector ortogonal (a 90 grados) a dos vectores existentes. Por ejemplo, el producto vectorial de los ejes X e Y es el eje Z, aunque los dos vectores de entrada no tienen que ser ortogonales entre sí. Un vector de producto vectorial se calcula con el método Cross.
Una función adicional, aunque algo más avanzada, de matemáticas vectoriales es el producto escalar. El producto escalar entre dos vectores es un número real (no un objeto vectorial) que hace referencia al ángulo entre dos vectores, aunque no exactamente. Una de las propiedades útiles de este tipo de producto es que el producto escalar entre dos vectores será 0 solo si son perpendiculares. El producto escalar se calcula con el método Dot.

De forma similar, las superficies presentan el método PointAtParameter, que utiliza dos argumentos, el parámetro u y v del punto generado.
Aunque la extracción de puntos individuales en una curva y una superficie puede ser útil, a menudo, es necesario que las secuencias de comandos conozcan las características geométricas específicas de un parámetro, como la dirección hacia la que está orientada la curva o la superficie. El método CoordinateSystemAtParameter no solo busca la posición, sino un CoordinateSystem orientado en el parámetro de una curva o una superficie. Por ejemplo, el siguiente archivo de comandos extrae objetos CoordinateSystem orientados a lo largo de una superficie de revolución y utiliza la orientación de los objetos CoordinateSystem para generar líneas que permanecen en la dirección normal a la superficie:
Como se ha mencionado anteriormente, la parametrización no siempre es uniforme a lo largo de una curva o una superficie, lo que significa que el parámetro 0.5 no siempre se corresponde con el punto medio y 0.25 no siempre se corresponde con el punto un cuarto a lo largo de una curva o una superficie. Para evitar esta limitación, las curvas presentan un conjunto adicional de comandos de parametrización que permiten buscar un punto en longitudes específicas a lo largo de una curva.
pts = [ [p1, p2, p3],
[p4, p5, p6],
[p7, p8, p9] ];pts = {};
pts[0] = Point.ByCoordinates(4, 0, 0);
pts[1] = Point.ByCoordinates(6, 0, 1);
pts[2] = Point.ByCoordinates(4, 0, 2);
pts[3] = Point.ByCoordinates(4, 0, 3);
pts[4] = Point.ByCoordinates(4, 0, 4);
pts[5] = Point.ByCoordinates(3, 0, 5);
pts[6] = Point.ByCoordinates(4, 0, 6);
crv = NurbsCurve.ByPoints(pts);
pts_at_param = crv.PointAtParameter(0..1..#11);
// draw Lines to help visualize the points
lines = Line.ByStartPointEndPoint(pts_at_param,
Point.ByCoordinates(4, 6, 0));También se pueden crear NurbsSurfaces de forma libre mediante la especificación de los puntos de control subyacentes de una superficie. Al igual que las NurbsCurves, se puede considerar que los puntos de control representan una malla cuadrilateral con segmentos rectos que, en función del grado de la superficie, se suaviza hasta alcanzar la forma de superficie final. Para crear una NurbsSurface mediante puntos de control, incluya dos parámetros adicionales en NurbsSurface.ByPoints, que indiquen los grados de las curvas subyacentes en ambas direcciones de la superficie.
Podemos aumentar el grado de la NurbsSurface para cambiar la geometría de superficie resultante:
Del mismo modo que las superficies se pueden crear mediante la interpolación entre un conjunto de puntos de entrada, estas se pueden crear mediante la interpolación entre un conjunto de curvas base. Esta operación se denomina solevado. Las curvas solevadas se crean mediante el constructor Surface.ByLoft con una colección de curvas de entrada como único parámetro.
Las superficies de revolución son un tipo adicional de superficie creada mediante el barrido de una curva base alrededor de un eje central. Si las superficies interpoladas son el elemento análogo bidimensional a las curvas interpoladas, las superficies de revolución son el elemento análogo bidimensional a los círculos y los arcos.
Las superficies de revolución se especifican mediante una curva base que representa la "arista" de la superficie; un origen de eje, el punto base de la superficie; una dirección de eje, la dirección central del "núcleo", y un ángulo inicial y final de barrido. Se utilizan como entrada en el constructor Surface.Revolve.
Aunque Dynamo puede crear diversas formas geométricas complejas, las primitivas geométricas simples forman la espina dorsal de cualquier diseño computacional: expresadas directamente en la forma diseñada final o utilizadas como andamiaje a partir del que se genera geometría más compleja.
Aunque no es estrictamente una parte de la geometría, CoordinateSystem es una herramienta importante para crear geometría. Un objeto CoordinateSystem realiza un seguimiento de las transformaciones geométricas y de posición, como la rotación, el corte y la escala.
Para crear un CoordinateSystem centrado en un punto con x = 0, y = 0 y z = 0 sin transformaciones de rotación, escala o corte, basta con llamar al constructor Identity:
Los objetos CoordinateSystem con transformaciones geométricas se encuentran fuera del ámbito de este capítulo, aunque otro constructor permite crear un sistema de coordenadas en un punto específico, CoordinateSystem.ByOriginVectors:
La primitiva geométrica más sencilla es un punto, que representa una ubicación de cero dimensiones en un espacio tridimensional. Como se ha mencionado anteriormente, existen varias formas diferentes de crear un punto en un sistema de coordenadas específico: Point.ByCoordinates crea un punto con las coordenadas X, Y y Z especificadas; Point.ByCartesianCoordinates crea un punto con las coordenadas X, Y y Z especificadas en un determinado sistema de coordenadas; Point.ByCylindricalCoordinates crea un punto en un cilindro con un radio, un ángulo de rotación y una altura, y Point.BySphericalCoordinates crea un punto en una esfera con un radio y dos ángulos de rotación.
En este ejemplo, se muestran puntos creados en varios sistemas de coordenadas:
La siguiente primitiva de Dynamo dimensional superior es un segmento de línea, que representa un número infinito de puntos entre dos puntos finales. Las líneas se pueden crear indicando explícitamente los dos puntos de contorno con el constructor Line.ByStartPointEndPoint o especificando un punto inicial, una dirección y una longitud en esa dirección, Line.ByStartPointDirectionLength.
Dynamo tiene objetos que representan los tipos más básicos de primitivas geométricas en tres dimensiones: cubos, creados con Cuboid.ByLengths; conos, creados con Cone.ByPointsRadius y Cone.ByPointsRadii; cilindros, creados con Cylinder.ByRadiusHeight, y esferas, creadas con Sphere.ByCenterPointRadius.
Con Dynamo 2.0, podemos especificar una plantilla por defecto (.py extension) para utilizarla al abrir la ventana de Python por primera vez. Esta ha sido una petición deseada durante mucho tiempo, ya que agiliza el uso de Python en Dynamo. La capacidad de utilizar una plantilla nos permite disponer de importaciones por defecto listas para usar cuando deseamos desarrollar una secuencia de comandos de Python personalizada.
Esta plantilla se encuentra en la ubicación APPDATA de la instalación de Dynamo.
Por lo general, suele ser ( %appdata%\Dynamo\Dynamo Core\{version}\ ).
Para utilizar esta función, debemos añadir la siguiente línea en el archivo DynamoSettings.xml. (Edítelo en el Bloc de notas).
Cuando aparece <PythonTemplateFilePath />, solo tenemos que sustituir esto por lo siguiente:
Nota: Sustituya CURRENTUSER por su nombre de usuario.
A continuación, debemos crear una plantilla con la funcionalidad integrada que deseamos utilizar. En este caso, insertaremos las importaciones relacionadas con Revit y algunos de los demás elementos habituales al trabajar con Revit.
Puede iniciar un documento del Bloc de notas en blanco y pegar el siguiente código:
Una vez hecho esto, guarde este archivo como PythonTemplate.py en la ubicación APPDATA.
Una vez que se haya definido la plantilla de Python, Dynamo la buscará cada vez que se coloque un nodo de Python. Si no se encuentra, se mostrará la ventana de Python por defecto.
Si se encuentra la plantilla de Python (como, por ejemplo, nuestra plantilla de Revit), aparecerán todos los elementos por defecto integrados.
Aquí encontrará información adicional (de Radu Gidei) sobre esta excelente incorporación. https://github.com/DynamoDS/Dynamo/pull/8122
Existen dos formas fundamentales de crear curvas de forma libre en Dynamo: especificar una colección de puntos y conseguir que Dynamo interpole una curva suavizada entre ellos, o un método de nivel más bajo mediante la especificación de los puntos de control subyacentes de una curva de un determinado grado. Las curvas interpoladas son útiles cuando un diseñador conoce exactamente la forma que debe adoptar una línea o si el diseño tiene restricciones específicas en cuanto a la ubicación que la curva puede o no atravesar. Las curvas especificadas mediante puntos de control son, en esencia, una serie de segmentos de línea recta que un algoritmo suaviza para formar una curva final. La especificación de una curva mediante puntos de control puede resultar útil para explorar formas de curva con diferentes grados de suavizado o cuando se requiere una continuidad suave entre segmentos de curva.
Para crear una curva interpolada, simplemente transfiera un conjunto de puntos al método NurbsCurve.ByPoints.
// create a point with the following x, y, and z
// coordinates:
x = 10;
y = 2.5;
z = -6;
p = Point.ByCoordinates(x, y, z);// create a point on a sphere with the following radius,
// theta, and phi rotation angles (specified in degrees)
radius = 5;
theta = 75.5;
phi = 120.3;
cs = CoordinateSystem.Identity();
p = Point.BySphericalCoordinates(cs, radius, theta,
phi);// create two points:
p1 = Point.ByCoordinates(3, 10, 2);
p2 = Point.ByCoordinates(-15, 7, 0.5);
// construct a line between p1 and p2
l = Line.ByStartPointEndPoint(p1, p2);// create points:
p1 = Point.ByCoordinates(3, 10, 2);
p2 = Point.ByCoordinates(-15, 7, 0.5);
p3 = Point.ByCoordinates(5, -3, 5);
p4 = Point.ByCoordinates(-5, -6, 2);
p5 = Point.ByCoordinates(9, -10, -2);
p6 = Point.ByCoordinates(-11, -12, -4);
// create lines:
l1 = Line.ByStartPointEndPoint(p1, p2);
l2 = Line.ByStartPointEndPoint(p3, p4);
l3 = Line.ByStartPointEndPoint(p5, p6);
// loft between cross section lines:
surf = Surface.ByLoft([l1, l2, l3]);p1 = Point.ByCoordinates(3, 10, 2);
p2 = Point.ByCoordinates(-15, 7, 0.5);
p3 = Point.ByCoordinates(5, -3, 5);
p4 = Point.ByCoordinates(-5, -6, 2);
l1 = Line.ByStartPointEndPoint(p1, p2);
l2 = Line.ByStartPointEndPoint(p3, p4);
surf = Surface.ByLoft([l1, l2]);
// true indicates to thicken both sides of the Surface:
solid = surf.Thicken(4.75, true);p1 = Point.ByCoordinates(3, 10, 2);
p2 = Point.ByCoordinates(-15, 7, 0.5);
p3 = Point.ByCoordinates(5, -3, 5);
p4 = Point.ByCoordinates(-5, -6, 2);
l1 = Line.ByStartPointEndPoint(p1, p2);
l2 = Line.ByStartPointEndPoint(p3, p4);
surf = Surface.ByLoft([l1, l2]);
solid = surf.Thicken(4.75, true);
p = Plane.ByOriginNormal(Point.ByCoordinates(2, 0, 0),
Vector.ByCoordinates(1, 1, 1));
int_surf = solid.Intersect(p);
int_line = int_surf.Intersect(Plane.ByOriginNormal(
Point.ByCoordinates(0, 0, 0),
Vector.ByCoordinates(1, 0, 0)));// construct a Vector object
v = Vector.ByCoordinates(1, 2, 3);
s = v.X + " " + v.Y + " " + v.Z;a = Vector.ByCoordinates(5, 5, 0);
b = Vector.ByCoordinates(4, 1, 0);
// c has value x = 9, y = 6, z = 0
c = a.Add(b);a = Vector.ByCoordinates(5, 5, 0);
b = Vector.ByCoordinates(4, 1, 0);
// c has value x = 1, y = 4, z = 0
c = a.Subtract(b);a = Vector.ByCoordinates(4, 4, 0);
// c has value x = 20, y = 20, z = 0
c = a.Scale(5);a = Vector.ByCoordinates(1, 2, 3);
a_len = a.Length;
// set the a's length equal to 1.0
b = a.Normalized();
c = b.Scale(5);
// len is equal to 5
len = c.Length;a = Vector.ByCoordinates(1, 0, 1);
b = Vector.ByCoordinates(0, 1, 1);
// c has value x = -1, y = -1, z = 1
c = a.Cross(b);a = Vector.ByCoordinates(1, 2, 1);
b = Vector.ByCoordinates(5, -8, 4);
// d has value -7
d = a.Dot(b);pts = {};
pts[0] = Point.ByCoordinates(4, 0, 0);
pts[1] = Point.ByCoordinates(3, 0, 1);
pts[2] = Point.ByCoordinates(4, 0, 2);
pts[3] = Point.ByCoordinates(4, 0, 3);
pts[4] = Point.ByCoordinates(4, 0, 4);
pts[5] = Point.ByCoordinates(5, 0, 5);
pts[6] = Point.ByCoordinates(4, 0, 6);
pts[7] = Point.ByCoordinates(4, 0, 7);
crv = NurbsCurve.ByPoints(pts);
axis_origin = Point.ByCoordinates(0, 0, 0);
axis = Vector.ByCoordinates(0, 0, 1);
surf = Surface.ByRevolve(crv, axis_origin, axis, 90,
140);
cs_array = surf.CoordinateSystemAtParameter(
(0..1..#7)<1>, (0..1..#7)<2>);
def make_line(cs : CoordinateSystem) {
lines_start = cs.Origin;
lines_end = cs.Origin.Translate(cs.ZAxis, -0.75);
return = Line.ByStartPointEndPoint(lines_start,
lines_end);
}
lines = make_line(Flatten(cs_array));// python_points_1 is a set of Points generated with
// a Python script found in Chapter 12, Section 10
surf = NurbsSurface.ByPoints(python_points_1);// python_points_1 is a set of Points generated with
// a Python script found in Chapter 12, Section 10
// create a surface of degree 2 with smooth segments
surf = NurbsSurface.ByPoints(python_points_1, 2, 2);// python_points_1 is a set of Points generated with
// a Python script found in Chapter 12, Section 10
// create a surface of degree 6
surf = NurbsSurface.ByPoints(python_points_1, 6, 6);// python_points_2, 3, and 4 are generated with
// Python scripts found in Chapter 12, Section 10
c1 = NurbsCurve.ByPoints(python_points_2);
c2 = NurbsCurve.ByPoints(python_points_3);
c3 = NurbsCurve.ByPoints(python_points_4);
loft = Surface.ByLoft([c1, c2, c3]);pts = {};
pts[0] = Point.ByCoordinates(4, 0, 0);
pts[1] = Point.ByCoordinates(3, 0, 1);
pts[2] = Point.ByCoordinates(4, 0, 2);
pts[3] = Point.ByCoordinates(4, 0, 3);
pts[4] = Point.ByCoordinates(4, 0, 4);
pts[5] = Point.ByCoordinates(5, 0, 5);
pts[6] = Point.ByCoordinates(4, 0, 6);
pts[7] = Point.ByCoordinates(4, 0, 7);
crv = NurbsCurve.ByPoints(pts);
axis_origin = Point.ByCoordinates(0, 0, 0);
axis = Vector.ByCoordinates(0, 0, 1);
surf = Surface.ByRevolve(crv, axis_origin, axis, 0,
360);// create a CoordinateSystem at x = 0, y = 0, z = 0,
// no rotations, scaling, or sheering transformations
cs = CoordinateSystem.Identity();



























// create a CoordinateSystem at a specific location,
// no rotations, scaling, or sheering transformations
x_pos = 3.6;
y_pos = 9.4;
z_pos = 13.0;
origin = Point.ByCoordinates(x_pos, y_pos, z_pos);
identity = CoordinateSystem.Identity();
cs = CoordinateSystem.ByOriginVectors(origin,
identity.XAxis, identity.YAxis, identity.ZAxis);// create a point with x, y, and z coordinates
x_pos = 1;
y_pos = 2;
z_pos = 3;
pCoord = Point.ByCoordinates(x_pos, y_pos, z_pos);
// create a point in a specific coordinate system
cs = CoordinateSystem.Identity();
pCoordSystem = Point.ByCartesianCoordinates(cs, x_pos,
y_pos, z_pos);
// create a point on a cylinder with the following
// radius and height
radius = 5;
height = 15;
theta = 75.5;
pCyl = Point.ByCylindricalCoordinates(cs, radius, theta,
height);
// create a point on a sphere with radius and two angles
phi = 120.3;
pSphere = Point.BySphericalCoordinates(cs, radius,
theta, phi);p1 = Point.ByCoordinates(-2, -5, -10);
p2 = Point.ByCoordinates(6, 8, 10);
// a line segment between two points
l2pts = Line.ByStartPointEndPoint(p1, p2);
// a line segment at p1 in direction 1, 1, 1 with
// length 10
lDir = Line.ByStartPointDirectionLength(p1,
Vector.ByCoordinates(1, 1, 1), 10);// create a cuboid with specified lengths
cs = CoordinateSystem.Identity();
cub = Cuboid.ByLengths(cs, 5, 15, 2);
// create several cones
p1 = Point.ByCoordinates(0, 0, 10);
p2 = Point.ByCoordinates(0, 0, 20);
p3 = Point.ByCoordinates(0, 0, 30);
cone1 = Cone.ByPointsRadii(p1, p2, 10, 6);
cone2 = Cone.ByPointsRadii(p2, p3, 6, 0);
// make a cylinder
cylCS = cs.Translate(10, 0, 0);
cyl = Cylinder.ByRadiusHeight(cylCS, 3, 10);
// make a sphere
centerP = Point.ByCoordinates(-10, -10, 0);
sph = Sphere.ByCenterPointRadius(centerP, 5);<PythonTemplateFilePath>
<string>C:\Users\CURRENTUSER\AppData\Roaming\Dynamo\Dynamo Core\2.0\PythonTemplate.py</string>
</PythonTemplateFilePath>import clr
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *
from Autodesk.Revit.DB.Structure import *
clr.AddReference('RevitAPIUI')
from Autodesk.Revit.UI import *
clr.AddReference('System')
from System.Collections.Generic import List
clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.GeometryConversion)
clr.ImportExtensions(Revit.Elements)
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument
uidoc=DocumentManager.Instance.CurrentUIApplication.ActiveUIDocument
#Preparing input from dynamo to revit
element = UnwrapElement(IN[0])
#Do some action in a Transaction
TransactionManager.Instance.EnsureInTransaction(doc)
TransactionManager.Instance.TransactionTaskDone()
OUT = elementLa curva generada interseca cada uno de los puntos de entrada, comenzando y terminando en el primer y el último punto del conjunto, respectivamente. Se puede utilizar un parámetro periódico opcional para crear una curva periódica cerrada. Dynamo rellenará automáticamente el segmento que falta, por lo que no es necesario un punto final duplicado (idéntico al punto inicial).
Las NurbsCurves se generan de forma muy similar, con puntos de entrada que representan los puntos finales de un segmento de línea recta y un segundo parámetro que especifica la cantidad y el tipo de suavizado de la curva, que se denomina grado. * Una curva con el grado 1 no presenta suavizado; es una polilínea.
Una curva con el grado 2 se suaviza de forma que esta se interseque con el punto medio de los segmentos de polilínea y sea tangente a él:
Dynamo admite curvas NURBS (B-spline racional no uniforme) hasta un grado 20; la siguiente secuencia de comandos ilustra el efecto que tiene el aumento de niveles de suavizado en la forma de una curva:
Tenga en cuenta que debe tener al menos un punto de control más que el grado de la curva.
Otra ventaja de crear curvas mediante vértices de control es la capacidad de mantener la tangencia entre segmentos de curva individuales. Para ello, se extrae la dirección entre los dos últimos puntos de control y se continúa esta dirección con los dos primeros puntos de control de la curva siguiente. En el siguiente ejemplo, se crean dos curvas NURBS independientes que son, no obstante, tan suaves como una curva:
Muchos de los ejemplos mostrados hasta ahora se han centrado en la creación de geometría dimensional superior a partir de objetos dimensionales inferiores. Los métodos de intersección permiten que esta geometría dimensional superior genere objetos dimensionales inferiores, mientras que los comandos de recorte y de selección de recorte permiten que el archivo de comandos modifique las formas geométricas una vez creadas.
El método Intersect se define en todas las partes de la geometría de Dynamo, lo que significa que, en teoría, cualquier elemento de geometría se puede intersecar con cualquier otro. Naturalmente, algunas intersecciones no tienen sentido, como las intersecciones que involucran puntos, ya que el objeto resultante siempre será el propio punto de entrada. Las demás combinaciones posibles de intersecciones entre objetos se describen en el siguiente gráfico. En la siguiente tabla, se muestra el resultado de varias operaciones de intersección:
En el siguiente ejemplo muy sencillo, se muestra la intersección de un plano con una NurbsSurface. La intersección genera una matriz de NurbsCurves, que se puede utilizar como cualquier otra NurbsCurve.
El método Trim es muy similar al método Intersect, ya que se define para casi cada elemento de geometría. Sin embargo, existen muchas más limitaciones en el método Trim que en Intersect.
Algo que se debe tener en cuenta en los métodos Trim es el requisito de un punto de "selección", un punto que determina la geometría que se descartará y las partes que se deben conservar. Dynamo busca y descarta la geometría recortada más cercana al punto de selección.
Algunos objetos de geometría se pueden crear indicando de forma explícita las coordenadas X, Y y Z en un espacio tridimensional. Sin embargo, con mayor frecuencia, la geometría se desplaza a su posición final mediante transformaciones geométricas en el propio objeto o en su CoordinateSystem subyacente.
La transformación geométrica más sencilla es una traslación, que desplaza un objeto un número determinado de unidades en las direcciones X, Y y Z.
Aunque todos los objetos de Dynamo se pueden trasladar mediante la adición del método .Translate al final del nombre del objeto, las transformaciones más complejas requieren transformar el objeto de un CoordinateSystem subyacente a un nuevo CoordinateSystem. Por ejemplo, para girar un objeto 45 grados alrededor del eje X, debemos transformar el objeto de su CoordinateSystem existente sin rotación a un CoordinateSystem que se había girado 45 grados alrededor del eje X con el método .Transform:
Además de trasladarse y rotarse, los objetos CoordinateSystem también se pueden crear cortados o con su escala ajustada. Se puede ajustar la escala de un CoordinateSystem con el método .Scale:
Los objetos CoordinateSystem cortados se crean mediante la introducción de vectores no ortogonales en el constructor CoordinateSystem.
La escala y el corte son transformaciones geométricas más complejas que la rotación y la traslación, por lo que no todos los objetos de Dynamo pueden someterse a ellas. En la siguiente tabla, se describen los objetos de Dynamo que pueden tener objetos CoordinateSystem con escala no uniforme y cortados.
Las funciones se pueden crear en un bloque de código y recuperar en cualquier parte de una definición de Dynamo. Esto crea otra capa de control en un archivo paramétrico y se puede ver como una versión de texto de un nodo personalizado. En este caso, se puede acceder fácilmente al bloque de código "principal", que se encuentra en cualquier parte del gráfico. No se necesitan cables.
En la primera línea, aparece la palabra clave "def", después el nombre de la función y, a continuación, los nombres de las entradas entre paréntesis. Las llaves definen el cuerpo de la función. Se devuelve un valor con "return =". Los bloques de código que definen una función no tienen puertos de entrada o salida porque se invocan desde otros bloques de código.
num_pts = 6;
s = Math.Sin(0..360..#num_pts) * 4;
pts = Point.ByCoordinates(1..30..#num_pts, s, 0);
int_curve = NurbsCurve.ByPoints(pts);pts = Point.ByCoordinates(Math.Cos(0..350..#10),
Math.Sin(0..350..#10), 0);
// create an closed curve
crv = NurbsCurve.ByPoints(pts, true);
// the same curve, if left open:
crv2 = NurbsCurve.ByPoints(pts.Translate(5, 0, 0),
false);num_pts = 6;
pts = Point.ByCoordinates(1..30..#num_pts,
Math.Sin(0..360..#num_pts) * 4, 0);
// a B-Spline curve with degree 1 is a polyline
ctrl_curve = NurbsCurve.ByControlPoints(pts, 1);num_pts = 6;
pts = Point.ByCoordinates(1..30..#num_pts,
Math.Sin(0..360..#num_pts) * 4, 0);
// a B-Spline curve with degree 2 is smooth
ctrl_curve = NurbsCurve.ByControlPoints(pts, 2);num_pts = 6;
pts = Point.ByCoordinates(1..30..#num_pts,
Math.Sin(0..360..#num_pts) * 4, 0);
def create_curve(pts : Point[], degree : int)
{
return = NurbsCurve.ByControlPoints(pts,
degree);
}
ctrl_crvs = create_curve(pts, 1..11);pts_1 = {};
pts_1[0] = Point.ByCoordinates(0, 0, 0);
pts_1[1] = Point.ByCoordinates(1, 1, 0);
pts_1[2] = Point.ByCoordinates(5, 0.2, 0);
pts_1[3] = Point.ByCoordinates(9, -3, 0);
pts_1[4] = Point.ByCoordinates(11, 2, 0);
crv_1 = NurbsCurve.ByControlPoints(pts_1, 3);
pts_2 = {};
pts_2[0] = pts_1[4];
end_dir = pts_1[4].Subtract(pts_1[3].AsVector());
pts_2[1] = Point.ByCoordinates(pts_2[0].X + end_dir.X,
pts_2[0].Y + end_dir.Y, pts_2[0].Z + end_dir.Z);
pts_2[2] = Point.ByCoordinates(15, 1, 0);
pts_2[3] = Point.ByCoordinates(18, -2, 0);
pts_2[4] = Point.ByCoordinates(21, 0.5, 0);
crv_2 = NurbsCurve.ByControlPoints(pts_2, 3);// create a point at x = 1, y = 2, z = 3
p = Point.ByCoordinates(1, 2, 3);
// translate the point 10 units in the x direction,
// -20 in y, and 50 in z
// p2’s new position is x = 11, y = -18, z = 53
p2 = p.Translate(10, -20, 50);





Plano
Curva
Punto
Curva
Curva
Sólido
Superficie
Curva
Curva
Sólido
Sí
No
No
Superficie
-
Sí
Sí
Sí
Sí
Sólido
-
-
Sí
Sí
Sí
Con:
Superficie
Curva
Plano
Sólido
Superficie
Curva
Punto
Punto, curva
Superficie
Curva
Punto
Punto
Punto
Curva
Uso: Punto
Curva
Plano
Superficie
Sólido
En: Curva
Sí
No
No
No
No
Polígono
-


No
No
No
Línea
Sí
Sí
Plano
No
No
Punto
Sí
Sí
Polígono
No
No
Sólido
No
No
Superficie
No
No
Texto
No
No
Arco
No
No
NurbsCurve
Sí
Sí
NurbsSurface
No
No




Círculo
// python_points_5 is a set of Points generated with
// a Python script found in Chapter 12, Section 10
surf = NurbsSurface.ByPoints(python_points_5, 3, 3);
WCS = CoordinateSystem.Identity();
pl = Plane.ByOriginNormal(WCS.Origin.Translate(0, 0,
0.5), WCS.ZAxis);
// intersect surface, generating three closed curves
crvs = surf.Intersect(pl);
crvs_moved = crvs.Translate(0, 0, 10);// python_points_5 is a set of Points generated with
// a Python script found in Chapter 12, Section 10
surf = NurbsSurface.ByPoints(python_points_5, 3, 3);
tool_pts = Point.ByCoordinates((-10..20..10)<1>,
(-10..20..10)<2>, 1);
tool = NurbsSurface.ByPoints(tool_pts);
pick_point = Point.ByCoordinates(8, 1, 3);
result = surf.Trim(tool, pick_point);cube = Cuboid.ByLengths(CoordinateSystem.Identity(),
10, 10, 10);
new_cs = CoordinateSystem.Identity();
new_cs2 = new_cs.Rotate(Point.ByCoordinates(0, 0),
Vector.ByCoordinates(1,0,0.5), 25);
// get the existing coordinate system of the cube
old_cs = CoordinateSystem.Identity();
cube2 = cube.Transform(old_cs, new_cs2);cube = Cuboid.ByLengths(CoordinateSystem.Identity(),
10, 10, 10);
new_cs = CoordinateSystem.Identity();
new_cs2 = new_cs.Scale(20);
old_cs = CoordinateSystem.Identity();
cube2 = cube.Transform(old_cs, new_cs2);new_cs = CoordinateSystem.ByOriginVectors(
Point.ByCoordinates(0, 0, 0),
Vector.ByCoordinates(-1, -1, 1),
Vector.ByCoordinates(-0.4, 0, 0));
old_cs = CoordinateSystem.Identity();
cube = Cuboid.ByLengths(CoordinateSystem.Identity(),
5, 5, 5);
new_curves = cube.Transform(old_cs, new_cs);Invoque la función con otro bloque de código en el mismo archivo asignando el nombre y la misma cantidad de argumentos. Funciona igual que los nodos predefinidos de la biblioteca.
Descargue el archivo de ejemplo. Para ello, haga clic en el vínculo siguiente.
En el Apéndice, se incluye una lista completa de los archivos de ejemplo.
En este ejercicio, crearemos una definición genérica que creará esferas a partir de una lista de entrada de puntos. El radio de estas esferas depende de la propiedad Z de cada punto.
Comencemos con un intervalo de diez valores que abarca de 0 a 100. Conecte estos nodos a un nodo Point.ByCoordinates para crear una línea diagonal.
Cree un bloque de código e introduzca nuestra definición.
Utilice estas líneas de código:
El parámetro inputPt es el nombre que se le ha asignado para representar los puntos que controlarán la función. En este momento, la función no realiza ninguna acción, pero la ampliaremos en los pasos siguientes.
Al añadir la función de bloque de código, se coloca un comentario y una variable sphereRadius que consulta la posición Z de cada punto. Recuerde que inputPt.Z no necesita paréntesis como método. Se trata de una consulta de las propiedades de un elemento existente, por lo que no se necesita ninguna entrada:
Ahora, vamos a recuperar la función que hemos creado en otro bloque de código. Si hacemos doble clic en el lienzo para crear un nuevo bloque de código y escribimos sphereB, observaremos que Dynamo sugiere la función sphereByZ que hemos definido. La función se ha añadido a la biblioteca de IntelliSense. ¡Genial!
Ahora llamamos a la función y creamos una variable denominada Pt para conectar los puntos creados en los pasos anteriores:
En la salida, podemos observar que todos los valores son nulos. ¿Por qué ocurre eso? Al definir la función, calculamos la variable sphereRadius, pero no hemos definido qué debe devolver la función como una salida. Podemos solucionar esto en el siguiente paso.
Un paso importante es definir la salida de la función mediante la adición de la línea
return = sphereRadius;a la función sphereByZ.Ahora vemos que la salida del bloque de código nos proporciona las coordenadas Z de cada punto.
Ahora vamos a crear esferas reales mediante la edición de la función principal.
Definamos primero una esfera con la siguiente línea de código:
sphere=Sphere.ByCenterPointRadius(inputPt,sphereRadius);.A continuación, cambiamos el valor de retorno para que sea sphere en lugar de sphereRadius:
return = sphere;. Esto nos proporciona unas esferas gigantes en la vista preliminar de Dynamo.
1. Para reducir el tamaño de estas esferas, actualicemos el valor de sphereRadius mediante la adición de un divisor:
sphereRadius = inputPt.Z/20;. Ahora podemos ver las esferas separadas y empezar a entender la relación entre el radio y el valor Z.
En el nodo Point.ByCoordinates, al cambiar el encaje de Más corto a Producto vectorial, creamos una rejilla de puntos. La función sphereByZ sigue estando totalmente activa, por lo que todos los puntos crean esferas con radios basados en valores Z.
Y, solo para tantear el terreno, conectamos la lista original de números a la entrada X de Point.ByCoordinates. Ahora tenemos un cubo de esferas.
Nota: Si el cálculo tarda mucho en completarse en el equipo, pruebe a cambiar el valor #10 por un valor como #5.
Recuerde que la función sphereByZ que hemos creado es una función genérica, por lo que podemos recuperar la hélice de una lección anterior y aplicarle la función.
Como paso final, vamos a controlar la relación de radio con un parámetro definido por el usuario. Para ello, debemos crear una entrada nueva para la función y reemplazar el divisor 20 por un parámetro.
Actualice la definición de sphereByZ a:
Actualice el bloque de código secundario mediante la adición de una variable "ratio" a la entrada:
sphereByZ(Pt,ratio);. Conecte un control deslizante a la entrada de bloque de código recién creada y varíe el tamaño de los radios en función de la relación de radio.

def sphereByZ(inputPt)
{
};def sphereByZ(inputPt,radiusRatio)
{
//get Z Value, ise ot to drive radius of sphere
sphereRadius=inputPt.Z;
};sphereByZ(Pt)def sphereByZ(inputPt,radiusRatio)
{
//get Z Value, use it to drive radius of sphere
sphereRadius=inputPt.Z/radiusRatio;
//Define Sphere Geometry
sphere=Sphere.ByCenterPointRadius(inputPt,sphereRadius);
//Define output for function
return sphere;
};/*This is a multi-line comment,
which continues for
multiple lines*/
def FunctionName(in1,in2)
{
//This is a comment
sum = in1+in2;
return sum;
};FunctionName(in1,in2);












Existen varios métodos básicos de abreviatura en el bloque de código que, sencillamente, facilitan mucho la administración de datos. A continuación, vamos a desglosar los conceptos básicos y analizar cómo se puede utilizar la abreviatura para crear y consultar datos.
Tipo de datos
Dynamo estándar
Bloque de código equivalente
Números
El método para definir rangos y secuencias se puede reducir a un método básico de abreviatura. Utilice la imagen siguiente como guía de la sintaxis "..." para definir una lista de datos numéricos con un bloque de código. Una vez que aprendemos a utilizar esta notación, crear datos numéricos es un proceso realmente eficaz:
En este ejemplo, un rango de números se sustituye por una sintaxis de bloque de código que define
beginning..end..step-size;. Representados numéricamente, obtenemos lo siguiente:0..10..1;.Observe que la sintaxis
0..10..1;es equivalente a0..10;. Un tamaño de paso de 1 es el valor por defecto de la notación de abreviatura. Por lo tanto,0..10;proporciona una secuencia de 0 a 10 con un tamaño de paso de 1.
La creación de rangos avanzados nos permite trabajar con listas de listas de una forma sencilla. En los ejemplos siguientes, se aísla una variable de la notación de rango principal y se crea otro rango de dicha lista.
1. Mediante la creación de rangos anidados, compare la notación con el símbolo "#" frente a la notación sin este símbolo. Se aplica la misma lógica que en los rangos básicos, pero se vuelve un poco más compleja.
2. Podemos definir un subrango en cualquier lugar dentro del rango principal; observe que también podemos tener dos subrangos.
3. Al controlar el valor "fin" de un rango, se crean más rangos de longitudes diferentes.
Como ejercicio lógico, compare las dos abreviaturas anteriores e intente analizar el modo en que los subrangos y la notación # controlan la salida.
Además de crear listas con la función de abreviatura, también podemos crear listas sobre la marcha. Estas listas pueden contener una amplia gama de tipos de elementos y también se pueden consultar (recuerde que las listas son objetos en sí mismas). En resumen, con el bloque de código se crean listas y se consultan los elementos de una lista con corchetes.
1. Cree listas rápidamente con cadenas y consulte las listas mediante el índice de elementos.
2. Cree listas con variables y realice consultas mediante la notación de abreviatura de rango.
Además, el proceso de gestión con listas anidadas es similar. Tenga en cuenta el orden de la lista y recuerde utilizar varios conjuntos de corchetes:
1. Defina una lista de listas.
2. Consulte una lista con notación de un solo corchete.
3. Consulte un elemento con notación de doble corchete.
Descargue el archivo de ejemplo. Para ello, haga clic en el vínculo siguiente.
En el Apéndice, se incluye una lista completa de los archivos de ejemplo.
En este ejercicio, vamos a poner en práctica nuestras nuevas habilidades de abreviación para crear una superficie de cáscaras de huevo con mucho estilo y definida por rangos y fórmulas. A lo largo de este ejercicio, observe cómo utilizamos el bloque de código y los nodos existentes en Dynamo en tándem: se utiliza el bloque de código para la elevación de datos pesados mientras que los nodos de Dynamo se disponen visualmente para determinar la legibilidad de la definición.
Comience por crear una superficie conectando los nodos anteriores. En lugar de utilizar un nodo numérico para definir la anchura y la longitud, haga doble clic en el lienzo y escriba 100; en un bloque de código.
Defina un rango entre 0 y 1 con 50 divisiones. Para ello, escriba
0..1..#50en un bloque de código.Conecte el rango en Surface.PointAtParameter, que toma los valores u y v entre 0 y 1 a lo largo de la superficie. No olvide cambiar el encaje a Producto vectorial. Para ello, haga clic con el botón derecho en el nodo Surface.PointAtParameter.
En este paso, utilizamos nuestra primera función para mover la rejilla de puntos hacia arriba en el eje Z. Esta rejilla controlará una superficie generada a partir de la función subyacente. Añada nuevos nodos, como se muestra en la imagen siguiente.
Utilizamos un bloque de código con la línea:
(0..Math.Sin(x*360)..#50)*5;. Para descomponerlo rápidamente, vamos a definir un rango con una fórmula dentro de él. Esta fórmula es la función de seno. La función de seno recibe entradas de grado en Dynamo, por lo que, para obtener una onda sinusoidal completa, multiplicamos los valores x (es decir, la entrada de rango de 0 a 1) por 360. A continuación, queremos que haya el mismo número de divisiones que de puntos de rejilla de control para cada fila, por lo que definimos cincuenta subdivisiones con #50. Por último, el multiplicador de 5 simplemente aumenta la amplitud de la traslación para que podamos ver el efecto en la vista preliminar de Dynamo.
Aunque el bloque de código anterior, no era totalmente paramétrico. Deseamos controlar sus parámetros de forma dinámica, por lo que reemplazaremos la línea del paso anterior por
(0..Math.Sin(x*360*cycles)..#List.Count(x))*amp;. Esto nos permite definir estos valores en función de las entradas.
Al cambiar los controles deslizantes (de 0 a 10), obtenemos resultados interesantes.
Al realizar una transposición en el rango de números, se invierte la dirección de la onda cortina:
transposeList = List.Transpose(sineList);.
Se obtiene una superficie de cáscara de huevo distorsionada al añadir los elementos sineList y transposeList:
eggShellList = sineList+transposeList;.
Cambiemos los valores de los controles deslizantes especificados a continuación para "calmar las aguas" de este algoritmo.
Por último, vamos a consultar las partes aisladas de los datos con el bloque de código. Para regenerar la superficie con un rango específico de puntos, añada el bloque de código anterior entre los nodos Geometry.Translate y NurbsSurface.ByPoints. Tiene la siguiente línea de texto: sineStrips[0..15..1];. De este modo, se seleccionarán las primeras 16 filas de puntos (de 50). Al volver a crear la superficie, podemos ver que hemos generado una parte aislada de la rejilla de puntos.
En el paso final, para que este bloque de código sea más paramétrico, la consulta se controla mediante un control deslizante que va de 0 a 1. Para ello, utilizaremos esta línea de código:
sineStrips[0..((List.Count(sineStrips)-1)*u)];. Esto puede resultar confuso, pero la línea de código nos proporciona una forma rápida de modificar la longitud de la lista con un multiplicador entre 0 y 1.
Un valor de 0.53 en el control deslizante crea una superficie justo después del punto medio de la rejilla.
Como se puede esperar, un control deslizante de 1 crea una superficie a partir de la rejilla completa de puntos.
En el gráfico visual, podemos resaltar los bloques de código y ver cada una de sus funciones.
1. El primer bloque de código sustituye al nodo Number.
2. El segundo bloque de código sustituye al nodo Number Range.
3. El tercer bloque de código sustituye a los nodos List.Transpose, List.Count y Number Range.
4. El cuatro bloque de código consulta una lista de listas y sustituye al nodo List.GetItemAtIndex.
Es posible que haya observado que en los nombres de los nodos de Dynamo se da un elemento común: cada nodo utiliza una sintaxis ".". Esto se debe a que el texto de la parte inicial de cada nodo representa la sintaxis real para las secuencias de comandos y "." (o notación de puntos) separa un elemento de los posibles métodos a los que es posible invocar. Esto permite traducir fácilmente las secuencias de comandos visuales a secuencias de comandos basadas en texto.
Como analogía general para la notación de puntos, ¿cómo podemos tratar una manzana paramétrica en Dynamo? A continuación se indican algunos métodos que ejecutaremos en la manzana antes de decidir consumirla. (Nota: estos no son métodos reales de Dynamo):
El ejemplo de secuencia es similar, excepto que se utiliza un símbolo "#" para indicar que deseamos que haya 15 valores en la lista en lugar de una lista que llegue hasta 15. En este caso, se define lo siguiente: beginning..#ofSteps..step-size:. La sintaxis real de la secuencia es 0..#15..2.
Ahora vamos a introducir el símbolo "#" del paso anterior en la sección "tamaño-de-paso" de la sintaxis. Ahora, tenemos un rango de números que abarca de "inicio" a "fin" y la notación de "tamaño de paso" distribuye uniformemente un número de valores entre los dos elementos: beginning..end..#ofSteps.
Cadenas
Secuencias
Rangos
Obtener elemento en índice
Crear lista
Concatenar cadenas
Instrucciones condicionales
Nodo(s)
Bloque de código equivalente
Nota
Cualquier operador (+, &&, >=, Not, etc.)
+, &&, >=, !, etc.
Tenga en cuenta que "Not" se convierte en "!", pero el nodo se denomina "Not" para distinguirlo de "Factorial".
Boolean True
true;
Se deben respetar las minúsculas.
Boolean False
false;
Se deben respetar las minúsculas.


















Manazana.color
rojo
¿Está madura la manzana?
Manzana.madura
verdadero
¿Cuánto pesa la manzana?
Manzana.peso
170 g
¿De dónde viene la manzana?
Manzana.padre
árbol
¿Qué crea la manzana?
Manzana.hijo
semillas
¿Esta manzana se ha producido de forma local?
Manzana.distanciaDeHuerta
96 km
A juzgar por las salidas de la tabla de arriba, esta parece una manzana sabrosa. Creo que voy a Manzana.comer.
Con la analogía de manzana en mente, fijémonos en Point.ByCoordinates y veamos cómo podemos crear un punto mediante el bloque de código.
La sintaxis del bloque de código Point.ByCoordinates(0,10); proporciona el mismo resultado que el nodo Point.ByCoordinates en Dynamo, excepto que permite crear un punto mediante un nodo. Esto es más eficaz que conectar un nodo independiente a "X" e "Y".
Al utilizar Point.ByCoordinates en el bloque de código, se especifican las entradas en el mismo orden que en el nodo (X,Y) predefinido.
Puede invocar cualquier nodo normal de la biblioteca a través de un bloque de código siempre que el nodo no sea un nodo de "IU" especial, los que tienen una función de interfaz de usuario especial. Por ejemplo, puede invocar a Circle.ByCenterPointRadius, pero no tendría mucho sentido invocar a un nodo Watch 3D.
Los nodos normales (la mayoría de los incluidos en la biblioteca) suelen ser de tres tipos. Descubrirá que la biblioteca se organiza teniendo en cuenta estas categorías. Los métodos o nodos de estos tres tipos se tratan de forma diferente cuando se invocan desde un bloque de código.
Crear: crea (o construye) algo.
Acción: realiza una acción sobre algún elemento.
Consulta: obtiene una propiedad de algún elemento que ya existe.
La categoría "Crear" genera geometría desde cero. En el bloque de código, los valores se introducen de izquierda a derecha. Estas entradas están en el mismo orden que las entradas del nodo de arriba abajo.
Si comparamos el nodo Line.ByStartPointEndPoint y la sintaxis correspondiente en el bloque de código, vemos que se obtienen los mismos resultados.
Una acción es algo que se hace a un objeto de un tipo concreto. Dynamo utiliza la notación de puntos, común a muchos idiomas de codificación, para aplicar una acción a un elemento. Una vez que tenga el elemento, escriba un punto y, a continuación, el nombre de la acción. La entrada del método de acción se coloca entre paréntesis, del mismo modo que con los métodos de creación, solo que no es necesario especificar la primera entrada que se ve en el nodo correspondiente. En su lugar, especificamos el elemento en el que realizamos la acción:
El nodo Point.Add es un nodo de acción, por lo que la sintaxis funciona de forma algo distinta.
Las entradas son (1) el punto y (2) el vector que añadir. En un bloque de código, hemos designado al punto (el elemento) "pt". Para añadir un vector denominado "vec" a "pt", escribimos pt.Add(vec), o elemento, punto, acción. La acción Add (añadir) solo tiene una entrada o todas las entradas del nodo Point.Add menos la primera. La primera entrada del nodo Point.Add es el punto en sí.
Los métodos de consulta obtienen una propiedad de un objeto. Dado que el objeto en sí es la entrada, no es necesario especificar ninguna entrada. No se requieren paréntesis.
El encaje con nodos es algo diferente al encaje con el bloque de código. Con los nodos, el usuario hace clic con el botón derecho en el nodo y selecciona la opción de encaje que se va a utilizar. Con el bloque de código, el usuario tiene mucho más control sobre la estructura de los datos. El método de abreviatura del bloque de código utiliza guías de replicación para definir cómo se deben emparejar varias listas unidimensionales. Los números entre corchetes angulares "<>" definen la jerarquía de la lista anidada: <1>,<2>,<3>, etc.
En este ejemplo, se utiliza un método abreviado para definir dos rangos (la siguiente sección de este capítulo contiene más información sobre el método abreviado). En resumen,
0..1;es equivalente a{0,1}y-3..-7es equivalente a{-3,-4,-5,-6,-7}. El resultado nos proporciona listas de 2 valores X y 5 valores Y. Si no utilizamos guías de replicación con estas listas no coincidentes, obtenemos una lista de dos puntos, que es la longitud de la lista más corta. Con las guías de replicación, podemos encontrar todas las combinaciones posibles de 2 y 5 coordenadas (o un producto vectorial).Mediante la sintaxis Point.ByCoordinates
(x_vals<1>,y_vals<2>);, se obtienen dos listas con cinco elementos en cada lista.Mediante la sintaxis Point.ByCoordinates
(x_vals<2>,y_vals<1>);, se obtienen cinco listas con dos elementos en cada lista.
Con esta notación, también podemos especificar cuál será la lista dominante: dos listas de cinco elementos o cinco listas de dos elementos. En el ejemplo, al cambiar el orden de las guías de replicación, el resultado es una lista de filas de puntos o una lista de columnas de puntos en una rejilla.
Aunque pueda hacer falta algo de tiempo para acostumbrarse a los métodos de bloqueo anteriores, en Dynamo existe una función denominada "nodo para código" que facilita el proceso. Para utilizar esta función, seleccione una matriz de nodos en el gráfico de Dynamo, haga clic con el botón derecho en el lienzo y seleccione "Nodo para código". Dynamo comprime estos nodos en un bloque de código con todas las entradas y salidas. No solo es una excelente herramienta para aprender a utilizar bloques de código, sino que también permite trabajar con un gráfico Dynamo más eficaz y paramétrico. Concluiremos el siguiente ejercicio utilizando "Nodo para código", así que no se lo pierda.
Descargue el archivo de ejemplo. Para ello, haga clic en el vínculo siguiente.
En el Apéndice, se incluye una lista completa de los archivos de ejemplo.
Para mostrar la eficacia del bloque de código, vamos a convertir una definición de campo atractor existente al lenguaje del bloque de código. Al trabajar con una definición existente, se muestra cómo se relaciona el bloque de código con las secuencias de comandos visuales y es útil para aprender a utilizar la sintaxis de DesignScript.
Comience volviendo a crear la definición de la imagen anterior (o abriendo el archivo de muestra).
Observe que el encaje en Point.ByCoordinates se ha establecido en Producto vectorial.
Cada punto de una rejilla se desplaza hacia arriba en la dirección Z en función de su distancia con respecto al punto de referencia.
Se vuelve a crear una superficie y se engrosa, lo que genera una curvatura en la geometría relativa a la distancia con respecto al punto de referencia.
Para empezar, definamos primero el punto de referencia: Point.ByCoordinates
(x,y,0);. Utilizaremos la misma sintaxis de Point.ByCoordinates que se especifica en la parte superior del nodo de punto de referencia.Las variables x e y se insertan en el bloque de código para que podamos actualizarlas dinámicamente con los controles deslizantes.
Añada algunos controles deslizantes a las entradas del bloque de código que vayan del -50 al 50. De este modo, podemos abarcar la rejilla por defecto de Dynamo.
En la segunda línea del bloque de código, definimos una abreviatura para reemplazar el nodo de secuencia numérica:
coordsXY = (-50..50..#11);. Abordaremos más detalladamente este tema en la siguiente sección. Por ahora, observe que este método abreviado es equivalente al nodo Number Sequence de la secuencia de comandos visual.
Ahora vamos a crear una rejilla de puntos a partir de la secuencia coordsXY. Para ello, vamos a utilizar la sintaxis Point.ByCoordinates, pero también debemos iniciar un producto vectorial de la lista de la misma forma que lo hicimos en la secuencia de comandos visual. Para ello, escribimos la siguiente línea:
gridPts = Point.ByCoordinates(coordsXY<1>,coordsXY<2>,0);. Los corchetes angulares indican la referencia de producto vectorial.Observe en el nodo Watch3D que tenemos una rejilla de puntos en la rejilla de Dynamo.
Ahora llega la parte compleja: mover la rejilla de puntos hacia arriba según su distancia con respecto al punto de referencia. Llamaremos primero a este nuevo conjunto de puntos transPts. Como la traslación es una acción que se lleva a cabo en un elemento existente, en lugar de utilizar
Geometry.Translate..., utilizamosgridPts.Translate.Al leer el nodo real en el lienzo, vemos que hay tres entradas. La geometría que se va a trasladar ya se ha definido porque llevamos a cabo la acción en ese elemento (con gridPts.Translate). Las dos entradas restantes se insertarán en los paréntesis de las funciones: dirección y distancia.
Definir la dirección es sencillo; utilizamos
Vector.ZAxis()para realizar un movimiento vertical.La distancia entre el punto de referencia y cada punto de rejilla aún debe calcularse. Por lo tanto, lo hacemos como una acción al punto de referencia del mismo modo:
refPt.DistanceTo(gridPts).La última línea de código nos proporciona los puntos convertidos:
transPts=gridPts.Translate(Vector.ZAxis(),refPt.DistanceTo(gridPts));.
Ahora tenemos una rejilla de puntos con la estructura de datos adecuada para crear una superficie NURBS. Creamos la superficie mediante
srf = NurbsSurface.ByControlPoints(transPts);.
Por último, para añadir cierta profundidad a la superficie, construimos un sólido mediante
solid = srf.Thicken(5);. En este caso, hemos engrosado la superficie 5 unidades en el código, pero siempre podríamos definirla como una variable, denominándola "thickness" (grosor), por ejemplo, y después controlar ese valor con un control deslizante.
La función "nodo para código" automatiza todo el ejercicio que acabamos de completar con un solo clic. No solo es una herramienta eficaz para crear definiciones personalizadas y bloques de código reutilizables, sino que también es una herramienta muy útil para aprender a usar las secuencias de comandos de Dynamo:
Empiece con la secuencia de comandos visual existente del paso 1 del ejercicio. Seleccione todos los nodos, haga clic con el botón derecho en el lienzo y seleccione "Nodo para código". Así de fácil.
Dynamo crea de forma automática una versión basada en texto del gráfico visual, con el encaje incluido. Pruebe esta función con las secuencias de comandos visuales y aproveche las posibilidades del bloque de código.

¿De qué color es la manzana?































Ahora que hemos mostrado cómo utilizar las secuencias de comandos de Python en Dynamo, vamos a echar un vistazo a la conexión de bibliotecas de Revit en el entorno de secuencias de comandos. Recuerde que hemos importado los nodos estándar de Python y nuestros nodos centrales de Dynamo con las tres primeras líneas del bloque de código mostrado a continuación. Para importar los nodos de Revit, los elementos de Revit y el administrador de documentos de Revit, solo hemos de añadir algunas líneas más:
Esto nos permite acceder a la API de Revit y disponer de secuencias de comandos personalizadas para cualquier tarea de Revit. La combinación del proceso de programación visual con las secuencias de comandos de la API de Revit, mejora significativamente la colaboración y el desarrollo de herramientas. Por ejemplo, un administrador de BIM y un diseñador de esquemas pueden trabajar juntos en el mismo gráfico. En esta colaboración, pueden mejorar el diseño y la ejecución del modelo.
El plan tras el proyecto de Dynamo es ampliar el alcance de la implementación de plataformas. A medida que Dynamo añada más programas a la lista, los usuarios obtendrán acceso a las API específicas de plataforma desde el entorno de secuencias de comandos de Python. Aunque Revit representa el caso real de esta sección, podemos prever más capítulos en el futuro que ofrecerán módulos de aprendizaje completos sobre secuencias de comandos en otras plataformas. Además, hay muchas bibliotecas de a las que se puede acceder ahora y que se pueden importar a Dynamo.
En los siguientes ejemplos, se muestran métodos para implementar operaciones específicas de Revit desde Dynamo mediante el uso de Python. Para obtener una descripción más detallada de la relación de Python con Dynamo y Revit, consulte la . Otro recurso útil para Python y Revit es el proyecto .
Cree un nuevo proyecto de Revit.
Descargue el archivo de ejemplo. Para ello, haga clic en el vínculo siguiente.
En el Apéndice, se incluye una lista completa de los archivos de ejemplo.
En estos ejercicios, vamos a explorar secuencias de comandos básicas de Python en Dynamo for Revit. El ejercicio se centrará en el uso de los archivos y elementos de Revit, así como en la comunicación entre Revit y Dynamo.
Este es un método sencillo para recuperar los elementos doc, uiapp y app del archivo de Revit vinculado a la sesión de Dynamo. Es posible que los programadores que hayan trabajado antes en la API de Revit reconozcan los elementos de la lista de inspección. Si estos elementos no le resultan familiares, no hay problema; vamos a usar otros ejemplos en los ejercicios siguientes.
A continuación, se indica cómo vamos a importar los servicios de Revit y recuperar los datos del documento en Dynamo.
Eche un vistazo al nodo de Python en Dynamo. También puede encontrar el código a continuación:
Descargue el archivo de ejemplo. Para ello, haga clic en el vínculo siguiente.
En el Apéndice, se incluye una lista completa de los archivos de ejemplo.
En este ejercicio, crearemos una curva de modelo simple en Revit mediante el nodo de Dynamo Python.
Empiece creando una nueva familia de masas conceptuales en Revit.
Abra la carpeta de masas conceptuales y utilice el archivo de plantilla Metric Mass.rft.
En Revit, utilice el método abreviado de teclado un para que se muestre la configuración de unidades del proyecto y cambie la unidad de longitud a metros.
Inicie Dynamo y cree el conjunto de nodos de la imagen siguiente. Crearemos primero dos puntos de referencia en Revit a partir de los nodos de Dynamo.
Cree un bloque de código y asígnele el valor
"0;".Conecte este valor a un nodo ReferencePoint.ByCoordinates para las entradas X, Y y Z.
Cree tres controles deslizantes que vayan de -100 a 100 con un tamaño de paso de 1.
Eche un vistazo al nodo de Python en Dynamo. A continuación, se muestra el código completo.
System.Array: Revit necesita una matriz del sistema como entrada (en lugar de una lista de Python). Esta es solo una línea de código más, pero prestar atención a los tipos de argumentos facilitará la programación de Python en Revit.
En Dynamo, hemos creado dos puntos de referencia con una línea que los conecta mediante Python. Vamos a ir un poco más lejos en el siguiente ejercicio.
Descargue el archivo de ejemplo. Para ello, haga clic en el vínculo siguiente.
En el Apéndice, se incluye una lista completa de los archivos de ejemplo.
Este es un ejercicio sencillo, pero hace hincapié en la conexión de los datos y la geometría de Revit con Dynamo y viceversa. Comencemos abriendo Revit-StructuralFraming.rvt. Una vez abierto, inicie Dynamo y abra el archivo Revit-StructuralFraming.dyn.
Este archivo de Revit es totalmente básico. Dos curvas de referencia: una dibujada en el nivel 1 y la otra dibujada en el nivel 2. Queremos llevar estas curvas a Dynamo y mantener una conexión activa.
En este archivo, tenemos un conjunto de nodos conectados a cinco entradas de un nodo de Python.
Nodos Select Model Element: pulse el botón de selección para cada uno de ellos y seleccione la curva correspondiente en Revit.
Code Block: mediante la sintaxis
0..1..#x;, conecte un control deslizante de enteros que abarque de 0 a 20 en la entrada x. De este modo, se designa el número de vigas que se dibujarán entre las dos curvas.Structural Framing Types: en el menú desplegable, elija la viga por defecto W12x26.
Este código de Python es un poco más denso, pero los comentarios del código describen lo que sucede en el proceso.
En Revit, tenemos una matriz de vigas que abarca las dos curvas como elementos estructurales. Nota: Este no es un ejemplo realista; los elementos estructurales se utilizan como ejemplo de ejemplares nativos de Revit creados a partir de Dynamo.
En Dynamo, también podemos ver los resultados. Las vigas del nodo Watch3D hacen referencia a la geometría consultada desde los elementos de Revit.
Observe que existe un proceso continuo de traslación de datos del entorno de Revit al entorno de Dynamo. En resumen, así es como se desarrolla el proceso:
Se selecciona el elemento de Revit.
Se convierte el elemento de Revit en curva de Dynamo.
Se divide la curva de Dynamo en una serie de puntos de Dynamo.
Se utilizan los puntos de Dynamo entre dos curvas para crear líneas de Dynamo.
Esto puede parecer un poco pesado, pero la secuencia de comandos hace que sea tan sencillo como editar la curva en Revit y volver a ejecutar el solucionador (aunque es posible que deba suprimir las vigas anteriores al hacerlo). Esto se debe al hecho de que hemos colocado vigas en Python, lo que rompe la asociación que tienen los nodos OOTB.
Con una actualización de las curvas de referencia de Revit, obtenemos una nueva matriz de vigas.
¿Por qué habría que utilizar la programación textual en el entorno de programación visual de Dynamo? La programación visual tiene muchas ventajas. Permite crear programas sin necesidad de aprender sintaxis especial en una interfaz visual intuitiva. Sin embargo, un programa visual se puede sobrecargar y, a veces, su funcionalidad puede ser reducida. Por ejemplo, Python ofrece métodos mucho más eficaces para escribir instrucciones condicionales (if/then) y bucles. Python es una potente herramienta que permite ampliar las funciones de Dynamo y reemplazar muchos nodos por unas pocas líneas de código concisas.
Programa visual:
Programa textual:
Al igual que los bloques de código, los nodos de Python son una interfaz de secuencias de comandos dentro de un entorno de programación visual. El nodo de Python se encuentra en la biblioteca, en Secuencias de comandos > Editor > Secuencia de comandos de Python.
Al hacer doble clic en el nodo, se abre el editor de secuencias de comandos de Python (también puede hacer clic con el botón derecho en el nodo y seleccionar Editar). Observará que aparece texto modelo en la parte superior como ayuda para hacer referencia a las bibliotecas necesarias. Las entradas se almacenan en la matriz IN. Los valores se devuelven a Dynamo asignándolos a la variable OUT.
La biblioteca Autodesk.DesignScript.Geometry permite utilizar la notación de puntos como ocurre con los bloques de código. Para obtener más información sobre la sintaxis de Dynamo, consulte y la (Para descargar este documento PDF, haga clic con el botón derecho en el vínculo y seleccione "Guardar vínculo como"). Al escribir un tipo de geometría como, por ejemplo, "Point.", se muestra una lista de métodos para crear y consultar puntos.
Los métodos incluyen constructores como ByCoordinates, acciones como Add y consultas como las coordenadas X, Y y Z.
Descargue el archivo de ejemplo. Para ello, haga clic en el vínculo siguiente.
En el Apéndice, se incluye una lista completa de los archivos de ejemplo.
En este ejemplo, vamos a escribir una secuencia de comandos de Python que crea patrones a partir de un módulo sólido y lo vamos a convertir en un nodo personalizado. Vamos a crear primero nuestro módulo sólido mediante nodos de Dynamo.
Rectangle.ByWidthLength: cree un rectángulo que será la base del sólido.
Surface.ByPatch: conecte el rectángulo con la entrada "closedCurve" para crear la superficie inferior.
Geometry.Translate: conecte el rectángulo a la entrada "geometry" para desplazarlo hacia arriba y utilice un bloque de código para especificar el grosor de base del sólido.
Polygon.Points: consulte el rectángulo trasladado para extraer los puntos de esquina.
Geometry.Translate: utilice un bloque de código para crear una lista de cuatro valores correspondientes a los cuatro puntos y traslade una esquina del sólido hacia arriba.
Ahora que tenemos las superficies superior e inferior, solevaremos los dos perfiles para crear los lados del sólido.
List.Create: conecte el rectángulo inferior y el polígono superior a las entradas de índice.
Surface.ByLoft: soleve los dos perfiles para crear los lados del sólido.
List.Create: conecte las superficies superior, lateral e inferior a las entradas de índice para crear una lista de superficies.
Ahora que ya tenemos el sólido, soltaremos un nodo de secuencia de comandos de Python en el espacio de trabajo.
Para añadir entradas adicionales al nodo, haga clic en el icono + del nodo. Las entradas se denominan IN[0], IN[1] y así sucesivamente para indicar que representan elementos de una lista.
Empezaremos definiendo las entradas y la salida. Haga doble clic en el nodo para abrir el editor de Python. Siga el código mostrado a continuación para modificarlo en el editor.
Este código cobrará más sentido a medida que avancemos en el ejercicio. A continuación, debemos pensar en qué información se requiere para disponer la matriz de nuestro módulo sólido. En primer lugar, es necesario conocer las dimensiones del sólido para determinar la distancia de traslación. Debido a un error del cuadro delimitador, tendremos que utilizar la geometría de curva de borde para crear un cuadro delimitador.
Eche un vistazo al nodo de Python en Dynamo. Observe que estamos utilizando la misma sintaxis que vemos en los títulos de los nodos de Dynamo. Eche un vistazo al código comentado que aparece a continuación.
Ya que vamos a trasladar y girar los módulos sólidos, vamos a utilizar la operación Geometry.Transform. Al observar el nodo Geometry.Transform, vemos que vamos a necesitar un sistema de coordenadas de origen y un sistema de coordenadas de destino para transformar el sólido. El origen es el sistema de coordenadas de contexto del sólido, mientras que el destino será un sistema de coordenadas diferente para cada módulo de matriz. Esto significa que tendremos que crear un bucle a través de los valores de X e Y para transformar el sistema de coordenadas de forma diferente en cada caso.
Haga clic en Ejecutar y, a continuación, guarde el código. Conecte el nodo de Python con la secuencia de comandos existente como se indica a continuación.
Conecte la salida de Solid.ByJoinedSurfaces como la primera entrada para el nodo de Python y utilice un bloque de código para definir las demás entradas.
Cree un nodo Topology.Edges y utilice la salida del nodo de Python como entrada.
Por último, cree un nodo Edge.CurveGeometry y utilice la salida de Topology.Edges como entrada.
Pruebe a cambiar el valor de semilla para crear patrones diferentes. También puede cambiar los parámetros del módulo sólido para obtener distintos efectos.
Ahora que hemos creado una secuencia de comandos de Python útil, vamos a guardarla como un nodo personalizado. Seleccione el nodo de la secuencia de comandos de Python, haga clic con el botón derecho en el espacio de trabajo y seleccione "Crear nodo personalizado".
Asigne un nombre, una descripción y una categoría.
Se abrirá un nuevo espacio de trabajo en el que se puede editar el nodo personalizado.
Inputs: cambie los nombres de las entradas para que sean más descriptivos y añada tipos de datos y valores por defecto.
Output: cambie el nodo de la salida.
Guarde el nodo como un archivo .dyf; debería ver que el nodo personalizado refleja los cambios que acabamos de realizar.
import sys
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
# Import RevitNodes
clr.AddReference("RevitNodes")
import Revit
# Import Revit elements
from Revit.Elements import *
# Import DocumentManager
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
import Systemimport clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
solid = IN[0]
seed = IN[1]
xCount = IN[2]
yCount = IN[3]
solids = []
yDist = solid.BoundingBox.MaxPoint.Y-solid.BoundingBox.MinPoint.Y
xDist = solid.BoundingBox.MaxPoint.X-solid.BoundingBox.MinPoint.X
for i in xRange:
for j in yRange:
fromCoord = solid.ContextCoordinateSystem
toCoord = fromCoord.Rotate(solid.ContextCoordinateSystem.Origin,Vector.ByCoordinates(0,0,1),(90*(i+j%val)))
vec = Vector.ByCoordinates((xDist*i),(yDist*j),0)
toCoord = toCoord.Translate(vec)
solids.append(solid.Transform(fromCoord,toCoord))
OUT = solidsConecte cada control deslizante a un nodo ReferencePoint.ByCoordinates.
Añada un nodo de Python al espacio de trabajo, haga clic en el botón "+" del nodo para añadir otra entrada y conecte los dos puntos de referencia en cada entrada. Abra el nodo de Python.
Levels: seleccione "Level 1".
Se crean vigas de Revit mediante referencias a líneas de Dynamo.
Se generan superficies de Dynamo mediante una consulta sobre la geometría de las vigas de Revit.
Polygon.ByPoints: utilice los puntos trasladados para reconstruir el polígono superior.
Surface.ByPatch: conecte el polígono para crear la superficie superior.
Solid.ByJoinedSurfaces: una las superficies para crear el módulo sólido.

# Load the Python Standard and DesignScript Libraries
import sys
import clr
#Import DocumentManager
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
#Place your code below this line
doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
app = uiapp.Application
#Assign your output to the OUT variable
OUT = [doc,uiapp,app]import sys
import clr
# Import RevitNodes
clr.AddReference("RevitNodes")
import Revit
#Import Revit elements
from Revit.Elements import *
import System
#define inputs
startRefPt = IN[0]
endRefPt = IN[1]
#define system array to match with required inputs
refPtArray = System.Array[ReferencePoint]([startRefPt, endRefPt])
#create curve by reference points in Revit
OUT = CurveByPoints.ByReferencePoints(refPtArray)import clr
#import Dynamo Geometry
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
# Import RevitNodes
clr.AddReference("RevitNodes")
import Revit
# Import Revit elements
from Revit.Elements import *
import System
#Query Revit elements and convert them to Dynamo Curves
crvA=IN[0].Curves[0]
crvB=IN[1].Curves[0]
#Define input Parameters
framingType=IN[3]
designLevel=IN[4]
#Define "out" as a list
OUT=[]
for val in IN[2]:
#Define Dynamo Points on each curve
ptA=Curve.PointAtParameter(crvA,val)
ptB=Curve.PointAtParameter(crvB,val)
#Create Dynamo line
beamCrv=Line.ByStartPointEndPoint(ptA,ptB)
#create Revit Element from Dynamo Curves
beam = StructuralFraming.BeamByCurve(beamCrv,designLevel,framingType)
#convert Revit Element into list of Dynamo Surfaces
OUT.append(beam.Faces)# Load the Python Standard and DesignScript Libraries
import sys
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
# The inputs to this node will be stored as a list in the IN variables.
#The solid module to be arrayed
solid = IN[0]
#A Number that determines which rotation pattern to use
seed = IN[1]
#The number of solids to array in the X and Y axes
xCount = IN[2]
yCount = IN[3]
#Create an empty list for the arrayed solids
solids = []
# Place your code below this line
# Assign your output to the OUT variable.
OUT = solids# Load the Python Standard and DesignScript Libraries
import sys
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
# The inputs to this node will be stored as a list in the IN variables.
#The solid module to be arrayed
solid = IN[0]
#A Number that determines which rotation pattern to use
seed = IN[1]
#The number of solids to array in the X and Y axes
xCount = IN[2]
yCount = IN[3]
#Create an empty list for the arrayed solids
solids = []
#Create an empty list for the edge curves
crvs = []
# Place your code below this line
#Loop through edges an append corresponding curve geometry to the list
for edge in solid.Edges:
crvs.append(edge.CurveGeometry)
#Get the bounding box of the curves
bbox = BoundingBox.ByGeometry(crvs)
#Get the x and y translation distance based on the bounding box
yDist = bbox.MaxPoint.Y-bbox.MinPoint.Y
xDist = bbox.MaxPoint.X-bbox.MinPoint.X
# Assign your output to the OUT variable.
OUT = solids# Load the Python Standard and DesignScript Libraries
import sys
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
# The inputs to this node will be stored as a list in the IN variables.
#The solid module to be arrayed
solid = IN[0]
#A Number that determines which rotation pattern to use
seed = IN[1]
#The number of solids to array in the X and Y axes
xCount = IN[2]
yCount = IN[3]
#Create an empty list for the arrayed solids
solids = []
#Create an empty list for the edge curves
crvs = []
# Place your code below this line
#Loop through edges an append corresponding curve geometry to the list
for edge in solid.Edges:
crvs.append(edge.CurveGeometry)
#Get the bounding box of the curves
bbox = BoundingBox.ByGeometry(crvs)
#Get the x and y translation distance based on the bounding box
yDist = bbox.MaxPoint.Y-bbox.MinPoint.Y
xDist = bbox.MaxPoint.X-bbox.MinPoint.X
#Get the source coordinate system
fromCoord = solid.ContextCoordinateSystem
#Loop through x and y
for i in range(xCount):
for j in range(yCount):
#Rotate and translate the coordinate system
toCoord = fromCoord.Rotate(solid.ContextCoordinateSystem.Origin, Vector.ByCoordinates(0,0,1), (90*(i+j%seed)))
vec = Vector.ByCoordinates((xDist*i),(yDist*j),0)
toCoord = toCoord.Translate(vec)
#Transform the solid from the source coord syste, to the target coord system and append to the list
solids.append(solid.Transform(fromCoord,toCoord))
# Assign your output to the OUT variable.
OUT = solids




























La sección Cambios en el lenguaje proporciona una descripción general de las actualizaciones y modificaciones realizadas en el lenguaje de Dynamo en cada versión. Estos cambios pueden afectar a la funcionalidad, el rendimiento y el uso, y esta guía ayudará a los usuarios a comprender cuándo y por qué adaptarse a estas actualizaciones.
Cambio en la sintaxis de list@level de "@-1" a "@L1"
Nueva sintaxis de list@level para usar list@L1 en lugar de list@-1.
Motivo: alinear la sintaxis del código con la vista previa y la interfaz de usuario; las pruebas de usuario muestran que esta nueva sintaxis es más comprensible.
Implementación de los tipos Int y Double en TS para que coincidan con los tipos de Dynamo
No se permiten las funciones sobrecargadas en las que los argumentos solo difieren por cardinalidad
Los gráficos antiguos que utilizan sobrecargas que se han eliminado deben usar por defecto las sobrecargas de mayor rango.
Motivo: eliminar la ambigüedad sobre qué función específica se está ejecutando.
Desactivación de la promoción de matriz con guías de replicación
Conversión de las variables de los bloques imperativos en locales al ámbito del bloque imperativo
Los valores de variable definidos dentro de los bloques de código imperativo no se verán alterados por los cambios realizados dentro de los bloques imperativos que hacen referencia a ellos.
Conversión de las variables en inmutables para desactivar la actualización asociativa en los nodos de bloque de código
Compilación de todos los nodos de la interfaz de usuario en métodos estáticos
Admisión de sentencias de retorno sin asignación
"=" no es necesario ni en definiciones de función ni en código imperativo.
Migración de los nombres de métodos antiguos en CBN
Se ha cambiado el nombre de muchos nodos para mejorar la legibilidad y la ubicación en la interfaz de usuario del navegador de biblioteca.
Lista como limpieza de diccionario
Problemas conocidos:
Los conflictos de espacio de nombres en los bloques imperativos provocan la aparición de puertos de entrada inesperados. Consulte el para obtener más información. Para evitar esto, defina la función fuera del bloque imperativo de la siguiente manera:
Se han realizado varias mejoras en el lenguaje de la versión 2.0 de Dynamo. El principal motivo para hacerlo fue simplificar el lenguaje. Se ha hecho hincapié en hacer que DesignScript sea más comprensible y fácil de usar con el objetivo de hacerlo más eficaz y flexible y mejorar la comprensibilidad por parte del usuario final.
A continuación se muestra la lista de cambios de la versión 2.0 explicada:
Sintaxis de List@Level simplificada
Los métodos sobrecargados con parámetros que solo difieren por rango no son válidos
Compilación de todos los nodos de la interfaz de usuario como métodos estáticos
Desactivada la promoción a lista cuando se utiliza con guías de replicación/encaje
Nueva sintaxis de list@level para usar list@L1 en lugar de list@-1
Las funciones sobrecargadas son problemáticas por varios motivos:
Es posible que una función sobrecargada indicada por un nodo de interfaz de usuario en el gráfico no sea la misma sobrecarga que se ejecuta en tiempo de ejecución.
La resolución del método es costosa y no funciona bien para funciones sobrecargadas.
Es difícil comprender el comportamiento de replicación de funciones sobrecargadas.
Tomemos BoundingBox.ByGeometry como ejemplo (había dos funciones sobrecargadas en versiones anteriores de Dynamo); en un caso toma un argumento de un solo valor y en el otro toma una lista de geometrías como argumento:
Si el usuario coloca el primer nodo en el lienzo y conecta una lista de geometrías, espera que la replicación se active, pero esto nunca sucede porque se llamará a la segunda sobrecarga en tiempo de ejecución, como se muestra a continuación:
En la versión 2.0, no se permiten las funciones sobrecargadas que solo difieren en la cardinalidad de los parámetros por este motivo. Esto significa que, para las funciones sobrecargadas que tienen el mismo número y tipo de parámetros, pero que tienen uno o más parámetros que difieren solo en el rango, la sobrecarga que se define primero siempre se impone, mientras que el resto las descarta el compilador. La principal ventaja de realizar esta simplificación es la de simplificar la lógica de resolución del método al tener una ruta rápida para seleccionar las funciones candidatas.
En la biblioteca de geometría de la versión 2.0, la primera sobrecarga del ejemplo d BoundingBox.ByGeometry se retiró y la segunda se conservó, por lo que si el nodo estuviera destinado a replicarse, es decir, a usarse en el contexto de la primera, tendría que usarse con la opción de encaje más corta (o más larga), o en un bloque de código con guías de replicación:
Podemos ver en este ejemplo que el nodo de mayor rango se puede usar tanto en una llamada replicada como en una no replicada y, por lo tanto, siempre se prefiere a una sobrecarga de menor rango. Por lo tanto, como regla general, siempre se recomienda a los autores de nodos que descarten las sobrecargas de menor rango en favor de los métodos de mayor rango, de modo que el compilador de DesignScript siempre llame al método de mayor rango al ser el primero y único que encuentra.
En el ejemplo siguiente, se han definido dos sobrecargas de la función foo. En las versiones 1.x, no está claro qué sobrecarga se ejecuta en tiempo de ejecución. El usuario podría esperar que se ejecute foo(a:int, b:int) de la segunda sobrecarga, en cuyo caso se esperaría que el método se replicara tres veces y devolviese un valor de 10 tres veces. En realidad, lo que se devuelve es un único valor de 10, ya que lo que se invoca es la primera sobrecarga con el parámetro list.
En la versión 2.0, siempre se elige el primer método definido sobre el resto. Se hace valer el orden de llegada.
En cada uno de los siguientes casos, se toma la primera sobrecarga definida. Tenga en cuenta que se considera exclusivamente el orden de definición de las funciones, y no el rango de los parámetros, aunque se recomienda dar preferencia a los métodos con parámetros de mayor rango en el caso de los nodos definidos por el usuario y los nodos Zero-Touch.
En Dynamo 1.x, los nodos de la interfaz de usuario (bloques sin código) se compilaban en métodos y propiedades de ejemplar respectivamente. Por ejemplo, el nodo Point.X se compilaba en pt.X y Curve.PointAtParameter se compilaba en curve.PointAtParameter(param). Este comportamiento presentaba dos problemas:
A. La función que representaba el nodo de la interfaz de usuario no siempre era la misma función que se ejecutaba en tiempo de ejecución.
Un ejemplo típico es el nodo Translate. Hay varios nodos Translate que toman el mismo número y tipos de argumentos, tales como: Geometry.Translate, Mesh.Translate y FamilyInstance.Translate. Debido al hecho de que los nodos se compilaban como métodos de ejemplar, la acción de pasar un FamilyInstance a un nodo Geometry.Translate sorprendentemente funcionaba, ya que en tiempo de ejecución enviaba la llamada al método de instancia Translate en un FamilyInstance. Obviamente, esto era engañoso para los usuarios, ya que el nodo no hacía lo que decía.
B. El segundo problema era que los métodos de ejemplar no funcionaban con matrices heterogéneas.
En tiempo de ejecución, el motor de ejecución necesita averiguar a qué función se debe enviar. Si la entrada es una lista, digamos list.Translate(), ya que es costoso revisar cada elemento de una lista y buscar métodos en su tipo, la lógica de resolución del método simplemente asumía que el tipo de destino era el mismo que el tipo del primer elemento e intentaba buscar el método Translate() definido en ese tipo. De esta forma, si el tipo del primer elemento no coincidía con el tipo objetivo del método (o incluso si era null o una lista vacía), se producía un error en toda la lista, incluso si había otros tipos en la lista que coincidiesen.
Por ejemplo, si se pasaba una entrada de lista con los siguientes tipos [Arc, Line] a Arc.CenterPoint, el resultado contenía un punto central para el arco y un valor de null para la línea según lo previsto. Sin embargo, si se invertía el orden, todo el resultado era nulo, ya que el primer elemento no superaba la comprobación de resolución del método:
En la versión 2.0, ambos problemas se resuelven mediante la compilación de los nodos de interfaz de usuario como propiedades estáticas y métodos estáticos.
Con los métodos estáticos, la resolución del método en tiempo de ejecución es más sencilla y se repiten todos los elementos de la lista de entrada. Por ejemplo:
La semántica de foo.Bar() (método de ejemplar) debe verificar el tipo de foo y también comprobar si es una lista o no y, luego, compararlo con las funciones candidatas. Esto es mucho trabajo. Por otro lado, la semántica de Foo.Bar(foo) (método estático) solo necesita verificar una función con el tipo de parámetro foo.
Esto es lo que sucede en la versión 2.0:
Un nodo de propiedad de la interfaz de usuario se compila en un getter estático: el motor genera una versión estática de un getter para cada propiedad. Por ejemplo, un nodo Point.X se compila en un captador estático Point.get_X(pt). Tenga en cuenta que también se puede llamar al getter estático mediante su alias: Point.X(pt) en un nodo de bloque de código.
Un nodo de método de interfaz de usuario se compila en la versión estática: el motor genera el método estático correspondiente para el nodo. Por ejemplo, el nodo Curve.PointAtParameter se compila en Curve.PointAtParameter(curve: Curve, parameter:double) en lugar de curve.PointAtParameter(parameter)
Nota: No hemos eliminado la compatibilidad con el método de ejemplar con este cambio, por lo que los métodos de ejemplar existentes utilizados en CBN, como pt.X y curve.PointAtParameter(parameter) en los ejemplos anteriores, seguirán funcionando.
Este ejemplo funcionaba anteriormente en la versión 1.x, ya que el gráfico se compilaba en point.X; y encontraba la propiedad X en el objeto de punto. Ahora falla en la versión 2.0, ya que el código compilado Vector.X(point) solo espera un tipo de Vector:
Coherente/comprensible: los métodos estáticos aclaran cualquier ambigüedad sobre qué método se ejecutará en tiempo de ejecución. El método siempre coincide con el nodo de la interfaz de usuario utilizado en el gráfico que el usuario espera que se llame.
Compatible: existe una mejor correlación entre el código y el programa visual.
Informativo: el paso de entradas de lista heterogéneas a los nodos ahora produce valores no nulos para los tipos que acepta el nodo y valores nulos para los tipos que no implementan el nodo. Los resultados son más predecibles y proporcionan una mejor indicación de cuáles son los tipos permitidos para el nodo.
Dado que Dynamo admite sobrecargas de funciones en general, aún puede confundirse si hay otra función sobrecargada con la misma cantidad de parámetros. Por ejemplo, en el siguiente gráfico, si conectamos un valor numérico a la entrada direction de Curve.Extrude y un vector a la entrada distance de Curve.Extrude, ambos nodos continúan funcionando, lo cual no es un comportamiento esperado. En este caso, aunque los nodos se compilan en métodos estáticos, el motor sigue sin poder establecer una diferencia en tiempo de ejecución y elige cualquiera de ellos en función del tipo de entrada.
El cambio a la semántica del método estático introdujo los siguientes efectos secundarios que vale la pena mencionar aquí como cambios relacionados con el lenguaje de la versión 2.0.
1. Pérdida del comportamiento polimórfico:
Consideremos un ejemplo de nodos TSpline en ProtoGeometry (tenga en cuenta que TSplineTopology se hereda del tipo de Topology base): el nodo Topology.Edges que se antes se compilaba en el método de ejemplar, object.Edges, ahora se compila en el método estático, Topology.Edges(object). La llamada antes se resolvía polimórficamente en el método de clase derivada, TsplineTopology.Edges, después de enviarse el método mediante el tipo de objeto del tiempo de ejecución.
Por su parte, el nuevo comportamiento estático se veía forzado a llamar al método de clase base, Topology.Edges. De este modo, este nodo devolvió objetos Edge de clase base en lugar de los objetos de clase derivada de tipo TSplineEdge.
Se trata de una regresión, ya que los nodos TSpline descendentes que esperaban la presencia de TSplineEdges comenzaron a fallar.
El problema se solucionó añadiendo una verificación de tiempo de ejecución en la lógica de envío del método para contrastar el tipo de ejemplar con el tipo o un subtipo del primer parámetro del método. En el caso de una lista de entrada, hemos simplificado el envío del método para comprobar simplemente el tipo del primer elemento. Por lo tanto, la solución final resulta del equilibrio de una búsqueda de método en parte estática y en parte dinámica.
Nuevo comportamiento polimórfico en la versión 2.0:
En este caso, dado que el primer elemento a es una TSpline, es el método derivado TSplineTopology.Edges el que se invoca en tiempo de ejecución. De este modo, devuelve null para el tipo de Topology base b.
En el segundo caso, dado que el tipo de Topology general b es el primer elemento, se llama al método de Topology.Edges base. Dado que Topology.Edges también acepta el tipo de TSplineTopology derivado, usar a como entrada devuelve Edges tanto para la entrada a como para la b.
2. Regresiones por la generación de listas externas redundantes
Hay una diferencia principal entre los métodos de ejemplar y los métodos estáticos en lo que respecta al comportamiento de la guía de replicación. Con los métodos de ejemplar, las entradas de un solo valor con guías de replicación no se promueven a listas, mientras que en los métodos estáticos sí se promueven.
Considere el ejemplo del nodo Surface.PointAtParameter con encaje cruzado, una sola entrada de superficie y matrices de valores de parámetros de u y v. El método de ejemplar lo compila en:
lo que genera una matriz de puntos 2D.
El método estático lo compila en:
lo que genera una lista de puntos 3D con una lista exterior redundante.
Este efecto secundario de compilar nodos de interfaz de usuario en métodos estáticos podría provocar regresiones en los casos de uso existentes. Este problema se ha solucionado desactivando la promoción de las entradas de un solo valor a listas cuando se utilizan con guías de replicación o encaje (consulte el siguiente punto).
4. Desactivada la promoción a lista con guías de replicación/encaje
En la versión 1.x había dos casos en los que los valores únicos se promovían a listas:
Cuando las entradas de menor rango se pasaban a funciones que esperaban entradas de mayor rango.
Cuando las entradas de menor rango se pasaban a funciones que esperaban el mismo rango, pero donde los argumentos de entrada iban acompañados de guías de replicación o utilizaban encaje.
En la versión 2.0, ya no se admite este último caso al impedir la promoción a lista en tales escenarios.
En el siguiente gráfico de la versión 1.x, una guía de nivel de replicación por cada uno de los elementos y e z forzaba la promoción de matriz de rango 1 para cada uno de ellos, razón por la cual el rango de resultado era de 3 (1 por cada elemento x, y y z). En realidad, el usuario esperaría que el resultado fuera de rango 1, ya que no es del todo obvio que la presencia de guías de replicación para entradas de un solo valor añada niveles al resultado.
En la versión 2.0, la presencia de guías de replicación por cada uno de los argumentos de valor único y y z no provoca una promoción que dé como resultado una lista con la misma dimensión que la lista 1D de entrada de x.
La regresión mencionada anteriormente y causada por la compilación de métodos estáticos con la generación de listas externas redundantes también se ha abordado con este cambio de lenguaje.
Continuando con el mismo ejemplo anterior, vimos que una llamada a un método estático, como:
generaba una lista de puntos 3D en Dynamo 1.x. Esto sucedía debido a la promoción de la primera superficie de argumento de valor único a una lista cuando se usaba con una guía de replicación.
En la versión 2.0, hemos deshabilitado la promoción de argumentos de valor único a listas cuando se usan con guías de replicación o encaje. Así que ahora la llamada a:
simplemente devuelve una lista 2D, ya que la superficie no se promueve.
Este cambio elimina ahora la adición de un nivel de lista redundante y también resuelve la regresión causada por la transición a la compilación de método estático.
Legible: los resultados se ajustan a las expectativas del usuario y son más fáciles de comprender.
Compatible: los nodos de interfaz de usuario (con opción de encaje) y los CBN que utilizan guías de replicación ofrecen resultados compatibles.
Coherente:
Los métodos de ejemplar y los métodos estáticos son coherentes (se solucionan los problemas relacionados con la semántica del método estático).
Los nodos con entradas y con argumentos predeterminados se comportan de forma coherente (consulte el punto siguiente).
DesignScript ha admitido tradicionalmente dos paradigmas de programación: la programación asociativa y la programación imperativa. El código asociativo crea un gráfico de dependencias a partir de las sentencias del programa en las que las variables tienen una dependencia entre sí. La actualización de una variable puede activar actualizaciones para todas las demás variables que dependen de ella. Esto significa que la secuencia de ejecución de sentencias en un bloque asociativo no se basa en su orden, sino en las relaciones de dependencia entre las variables.
En el siguiente ejemplo, la secuencia de ejecución del código son las líneas 1 -> 2 -> 3 -> 2. Dado que b tiene una dependencia de a, cuando a se actualiza en la línea 3, la ejecución salta a la línea 2 nuevamente para actualizar b con el nuevo valor de a.
Por el contrario, si el mismo código se ejecuta en un contexto imperativo, las sentencias se ejecutan en un flujo lineal de arriba hacia abajo. Por lo tanto, los bloques de código imperativos son adecuados para la ejecución secuencial de construcciones de código, como bucles y condiciones if-else.
1. Variables con dependencia cíclica:
En ciertos casos, una dependencia cíclica entre variables puede no ser tan obvia, como ocurre en el caso siguiente. En los casos en los que el compilador no puede detectar el ciclo estáticamente, podría darse un ciclo de tiempo de ejecución indefinido.
2. Variables dependientes de sí mismas:
Si una variable depende de sí misma, ¿debe acumularse su valor o debe restablecerse a su valor original en cada actualización?
En este ejemplo de geometría, dado que el valor b del cubo depende de sí mismo y del cilindro, a, al mover el control deslizante, ¿debería moverse agujero a lo largo del bloque o debería crearse un efecto acumulativo por el que se añadieran varios agujeros a lo largo de la ruta por cada actualización de la posición del control deslizante?
3. Actualización de propiedades de variables:
4. Actualización de funciones:
A partir de la experiencia, hemos comprobado que la actualización asociativa no resulta útil en los nodos de bloque de código dentro de un contexto de gráfico de flujo de datos basado en nodos. Antes de que estuviesen disponibles los entornos de programación visual, la única forma de explorar las opciones era cambiar explícitamente los valores de algunas de las variables en el programa. Los programas basados en texto mantienen un historial completo de las actualizaciones de una variable, mientras que, en un entorno de programación visual, solo se muestra el último valor de una variable.
Si lo ha utilizado algún usuario, lo más probable es que haya sido sin saberlo, lo que provoca más daño que beneficio. Por lo tanto, en la versión 2.0, decidimos ocultar la asociatividad en el uso de nodos de bloque de código haciendo que las variables sean inmutables, mientras que seguimos conservando la actualización asociativa solo como característica nativa del motor DS. Este es otro cambio realizado con la idea de simplificar la experiencia del usuario a la hora de crear secuencias de comandos.
La actualización asociativa se ha deshabilitado en los CBN al impedir la redefinición de variables:
La indexación de listas aún se permite en los bloques de código
Se ha realizado una excepción para la indexación de listas y todavía se permite en la versión 2.0 con la asignación de operadores de índice.
En el siguiente ejemplo, se observa que la lista a se inicializa, pero se puede sobrescribir posteriormente con una asignación de operador de índice, y que las variables que dependen de a se actualizarían asociativamente, como se ve en el valor de c. Además, la vista preliminar del nodo muestra los valores actualizados de a tras la redefinición de uno o varios de sus elementos.
Hemos realizado cambios en la regla sobre el ámbito imperativo en la versión 2.0 para desactivar escenarios complicados de actualización entre lenguajes diferentes.
En Dynamo 1.x, la secuencia de ejecución de la siguiente secuencia de comandos se daría desde las líneas 1 -> 2 -> 4 -> 6 -> 4, donde un cambio se propaga desde el ámbito del lenguaje externo al interno. Dado que y se actualiza en el bloque asociativo externo y dado que x en el bloque imperativo tiene una dependencia de y, el control se pasa del programa asociativo externo al lenguaje imperativo en la línea 4.
La secuencia de ejecución en el siguiente ejemplo sería la de las líneas: 1 -> 2 -> 4 -> 2, donde el cambio se propagaría desde el ámbito del lenguaje interno al externo.
Los escenarios anteriores hacen referencia a la actualización entre lenguajes, que, al igual que la actualización asociativa, no es muy útil en los nodos de bloque de código. Para deshabilitar los escenarios complejos de actualización entre lenguajes, hemos hecho que las variables en el ámbito imperativo sean locales.
En el siguiente ejemplo de Dynamo 2.0:
La variable x definida en el bloque imperativo ahora es local al ámbito imperativo.
Los valores de x e y en el ámbito externo siguen siendo 1 y 2 respectivamente.
Cualquier variable local dentro de un bloque imperativo debe devolverse si se va a acceder a su valor en un ámbito externo.
Véase el siguiente ejemplo:
y se copia localmente dentro del ámbito imperativo.
El valor de x local para el ámbito imperativo es 4.
La actualización del valor de y en el ámbito externo sigue provocando la actualización de x debido a la actualización entre lenguajes, pero está desactivada en los bloques de código de la versión 2.0 debido a la inmutabilidad de las variables.
En Dynamo 1.x, las listas y los diccionarios se representaban mediante un único contenedor unificado que se podía indexar mediante un índice entero o mediante una clave no integral. En la siguiente tabla se resume la separación entre listas y diccionarios en la versión 2.0 y las reglas del nuevo tipo de datos Dictionary:
[]La sintaxis de inicialización de la lista se ha cambiado de llaves {} a corchetes [] en la versión 2.0. Todas las secuencias de comandos de la versión 1.x se migran automáticamente a la nueva sintaxis cuando se abren en la versión 2.0.
Nota sobre los atributos de argumento por defecto en los nodos Zero Touch:
Tenga en cuenta que la migración automática no funciona con la sintaxis antigua utilizada en los atributos de argumento por defecto. Los autores de nodos tendrían que actualizar manualmente las definiciones de método de Zero-Touch para utilizar la nueva sintaxis en los atributos de argumento por defecto DefaultArgumentAttribute si fuera necesario.
Nota sobre la indexación:
El nuevo comportamiento de indexación ha cambiado en algunos casos. La indexación en una lista/diccionario con una lista arbitraria de índices/claves mediante el operador [] ahora conserva la estructura de listas de la lista de entrada de índices/claves. Anteriormente, siempre devolvía una lista de valores 1D:
Las {} (sintaxis de llaves) para la inicialización del diccionario solo se pueden utilizar en el
formato de par clave-valor, en el que solo se permite una cadena para <key> y los pares clave-valor múltiples se separan mediante comas.
El método Zero-Touch Dictionary.ByKeysValues se puede utilizar como una forma más versátil de inicializar un diccionario pasando una lista de claves y valores respectivamente con todas las comodidades que ofrece el uso de métodos Zero-Touch, como las guías de replicación, etc.
Experimentamos con la idea de usar expresiones arbitrarias para las claves en la sintaxis de inicialización de clave-valor del diccionario y descubrimos que podía conducir a resultados confusos, especialmente cuando una sintaxis como {keys : vals} (tanto keys como vals representaban listas) interfería con otras características del lenguaje de DesignScript, como la replicación, y producía resultados diferentes desde el nodo inicializador de Zero Touch.
Por ejemplo, podría haber otros casos, como esta sentencia, en los que sería difícil definir el comportamiento esperado:
Añadir más sintaxis de guía de replicación, etc., a la mezcla, no solo identificadores, iría en contra de la idea de simplificar el lenguaje.
Podríamos ampliar las claves del diccionario para admitir expresiones arbitrarias en el futuro, pero también tendremos que asegurarnos de que la interacción con otras características del lenguaje sea coherente e inteligible a costa de añadir complejidad en lugar de hacer que el sistema sea un poco menos potente pero simple de entender. Siempre hay una forma alternativa de abordar esto mediante el uso del método Dictionary.ByKeysValues(keyList, valueList), lo cual no es tan exagerado.
1. Nodo Zero-Touch que devuelve un diccionario de .NET como un diccionario de Dynamo.
Veamos el siguiente método de C# de Zero-Touch que devuelve un IDictionary:
El valor de retorno del nodo ZT correspondiente se calcula según las referencias de un diccionario de Dynamo:
2. Los nodos de retorno múltiple se previsualizan como diccionarios.
El nodo Zero Touch que devuelve IDiccionario con el atributo de retorno múltiple devuelve un diccionario de Dynamo:
3. El diccionario de Dynamo se puede transferir como entrada al nodo Zero-Touch que acepta diccionarios .NET.
Método ZT con un parámetro IDictionary:
El nodo ZT acepta el diccionario de Dynamo como entrada:
Los diccionarios son pares clave-valor sin ordenar. De acuerdo con esta idea, no se garantiza que las vistas previas de los pares clave-valor de los nodos que devuelven diccionarios sigan el orden de los valores devueltos por los nodos.
Sin embargo, hemos hecho una excepción con los nodos de retorno múltiple que tienen definidos MultiReturnAttribute. En el siguiente ejemplo, el nodo DateTime.Components es un nodo de "retorno múltiple" y la vista preliminar del nodo refleja sus pares clave-valor para que estén en el mismo orden que el de los puertos de salida del nodo, que también es el orden en que se especifican las salidas en función de los MultiReturnAttribute en la definición del nodo.
Tenga en cuenta también que las vistas preliminares de los bloques de código no se ordenan, a diferencia del nodo de interfaz de usuario, ya que la información del puerto de salida (en forma de atributo de retorno múltiple) no existe para el nodo de bloque de código:
Las variables de los bloques asociativos son inmutables para evitar la actualización asociativa
Las variables de los bloques imperativos son locales al ámbito imperativo
Separación de listas y diccionarios
El valor de x e y en el ámbito asociativo exterior sigue siendo 1 y 2 respectivamente.
a[“foo”] = 1;
b = {“foo” : 1, “bar” : 2, “baz” : 3};
a[“bar”] = 2;
a = {}; // Crea un diccionario vacío
a[“baz”] = 3;
Indexación de diccionarios
Indexación de claves
La sintaxis de indexación sigue siendo la misma
b = a[“bar”];
b = a[“bar”];
Claves de diccionario
Cualquier tipo de clave era válido
Solo son válidas las claves de cadena
a = {};
a = {“false” : 23, “point” : 12};
a[false] = 23;
a[point] = 12;
Inicialización de lista
a = {1, 2, 3};
a = [1, 2, 3];
Lista vacía
a = {};
a = [];
Inicialización del diccionario
Se puede añadir al mismo diccionario dinámicamente:
Solo pueden crear diccionarios nuevos:
a = {};
a = {“foo” : 1, “bar” : 2};



























pnt = Autodesk.Point.ByCoordinates;
lne = Autodesk.Line.ByStartPointEndPoint;
[Imperative]
{
x = 1;
start = pnt(0,0,0);
end = pnt(x,x,x);
line = lne(start,end);
return = line;
};BoundingBox BoundingBox.ByGeometry(geometry: Geometry) {...}
BoundingBox BoundingBox.ByGeometry(geometry: Geometry[]) {...}BoundingBox.ByGeometry(geometry<1>);1)
foo(a: int[], b: int); ✓
foo(a: int, b: int); ✕2)
foo(x: int, y: int); ✓
foo(x: int[], y: int[]); ✕x = [arc, line];
y = x.CenterPoint; // y = [centerpoint, null] ✓x = [line, arc];
y = x.CenterPoint; // y = null ✕surface<1>.PointAtParameter(u<1>, v<2>);Surface.PointAtParameter(surface<1>, u<2>, v<3>);x = 1..5;
y = 0;
z = 0;
p = Point.ByCoordinates(x<1>, y<2>, z<3>); // cross-lacingSurface.PointAtParameter(surface<1>, u<2>, v<3>); Surface.PointAtParameter(surface<1>, u<2>, v<3>);1. a = 1;
2. b = a * 2;
3. a = 2;a = 1;
b = a;
a = b;a = 1;
b = 1;
b = b + a + 2; // b = 4
a = 4; // b = 10 or b = 7?1: def foo(x: A) { x.prop = ...; return x; }
2: a = A.A();
3: p = a.prop;
4: a1 = foo(a); // will p update?1: def foo(v: double) { return v * 2; }// define “foo”
2: x = foo(5); // first definition of “foo” called
3: def foo(v: int) { return v * 3; } // overload of “foo” defined, will x update?1: x = 1;
2: y = 2;
3: [Imperative] {
4: x = 2 * y;
5: }
6: y = 3;1: x = 1;
2: y = x * 2;
3: [Imperative] {
4: x = 3;
5: }x = 1;
y = x * 2;
i = [Imperative] {
x = 3;
return x;
}1: x = 1;
2: y = 2;
3: [Imperative] {
4: x = 2 * y;
5: }
6: y = 3; // x = 1, y = 3Given:
a = {“foo” : 1, “bar” : 2};
1.x:
b = a[{“foo”, {“bar”}}];
returns {1, 2}
2.0:
b = a[[“foo”, [“bar”]]];
returns [1, [2]];dict = {<key> : <value>, …}; dict = {["foo", "bar"] : "baz" };