Page 1

ETSAM / DELEGACION DE ALUMNOS DISEÑO PARAMETRICO Y ALGORITMICO

PROFESOR ADOLFO NADAL SERRANO INTRODUCCIÓN A PROGRAMACIÓN, DISEÑO ALGORÍTMICO Y AUTOMATIZACIÓN DE PROCESOS


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

Los problemas de diseño no pueden ser resueltos sin la ayuda de un computador, siendo la maquina un complemento y no un substituto del talento creativo, la computadora mientras no pueda inventar, puede explorar relaciones muy rápida y sistemáticamente de acuerdo a reglas preestablecidas. El computador funciona como una extensión natural de la habilidad analítica del hombre. Chermayeff, Community and Privacy (1963:166)

1. OBJETIVOS DEL CURSO Los objetivos del curso son, por un lado, conseguir la familiaridad del alumno con sistemas y software de modelado tridimensional, y, por otro, la introducción de metodologías innovadoras de diseño. El CAD no es una tecnología estática, y que, una vez aplicada, proporciona todas sus posibilidades a los equipos de diseño de forma definitiva. Sus capacidades van evolucionando con el tiempo, al mismo ritmo que los equipos se hacen más potentes y se abaratan, permitiendo que los desarrolladores de aplicaciones incorporen nuevas características y funcionalidades a sus productos. De este modo, estos continuos avances permiten conceptualizar mejor los diseños, estimular y predecir el comportamiento de nuevas soluciones, realizar estimaciones de costes y compartir diseños con clientes y empresas del sector. En definitiva, hemos de responder de manera efectiva y eficiente a las tendencias del sector mediante un pensamiento creativo: - A través de la simplificación de las tareas no críticas, tales como las tradicionales de diseño y dibujo (muros, ventanas, pilares, escaleras,...). - El diseño en tres dimensiones debe ser una obviedad. Esto implica obtener grandes mejoras de productividad y calidad a través del diseño espacial. - La distribución del trabajo entre grupos o profesionales distintos. - La automatización de las mediciones de las unidades que componen el proyecto, y como consecuencia su valoración, reduciendo el tiempo que debe dedicar el profesional para conseguir el coste de la obra. - La automatización de procesos generativos de forma. 2. PLANIFICACIÓN DEL CURSO DE INTRODUCCION El módulo básico trata de conseguir el dominio básico de la herramienta en lo que concierne a creación de macros y rutinas simples con el uso de RhinoScript.

El módulo constará de 20 horas lectivas distribuidas en 4 días de la siguiente manera: a. Bloque 1: Introducción Día 1 (28 enero): Sesión inicial de introducción: macros y código, conceptos básicos (2 horas) Sesión intermedia de trabajo con arrays en el plano (3 horas) Día 2 (29 enero): Sesión final de trabajo con superficies y componentes (5 horas) Día 3 (30 enero): Modificación de geometría por medio de atractores (5 horas) Día 4 (31 enero): Sesión inicial de preparación de geometría (1 hora) y sesión final de creación automática de planos para cortadora láser (3 horas). Impresión y realización de maquetas si procede.

[ 2 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 3 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

TOPOLOGÍA DE LA GEOMETRÍA NURBS [Non-Uniform Rational Bezier Splines]

[ 4 ]


[ 5 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

I. NOCIONES BÁSICAS DE PROGRAMACIÓN Aproximarse a la topología NURBS implica un conocimiento amplio de la descripción geométrica de los objetos a partir de fórmulas matemáticas y, de manera implícita, del comportamiento y descripción de las mismas en los entresijos del ordenador. Es, por tanto, imprescindible, iniciarse en el apasionante mundo de la programación, y, si bien no llegaremos a ser programadores profesionales, sí podremos entender y crear geometrías complejas a través de rutinas y “scripts”, pequeños programas hechos a medida que nos dan acceso directo al núcleo de Rhino, así como sus funciones y métodos. 1. Scripts, ejecución secuencial y programación orientada a objetos Generalmente, la manera más sencilla de comenzar un código es mediante la utilización de “comandos” u “órdenes” dadas en una secuencia determinada. Podríamos decir que el modo más primitivo de escribir código es mediante macros, secuencias de órdenes ordenadas de una manera determinada y que siempre llevan a cabo la misma labor. Las macros no permiten interacción con el usuario y son bastante limitadas, si bien son muy útiles a la hora de abordar problemas que requieren mucho esfuerzo o tiempo y que pueden automatizarse (por ejemplo, una secuencia de acciones que abre una imagen, cambia su brillo y su opacidad, la recorta, y la vuelve a guardar). Todos los parámetros implicados en una macro deben estar predefinidos de antemano, no pudiendo dejar ni una sola variable sin determinar. En el ejemplo anterior, si quisiéramos cambiar el brillo de una imagen, debemos especificar exactamente el nuevo valor de brillo, así como, a la hora de recortarla, cuáles son los píxeles que definen el cuadro delimitador del corte. Un script, en cambio, permite cierta interacción con el ususario, así como el uso de variables. Esto implica mayor flexibilidad, pero también mayor riesgo de error. Los scripts son, en lo que a nosotros nos concierne, el siguiente paso en la “inteligencia” de la programación. Dedicaremos a continuación una buena parte de tiempo a describir y cualificar cómo escribir scripts y sus diferentes funcionalidades, desde la creación de geometrías complejas hasta la automatización de procesos de creación de planos para la fabricación, exportación de archivos y otras utilidades varias. Tanto las macros como los scripts, sin embargo, comparten una propiedad fundamental: ambos se basan en una secuencia de órdenes que el ordenador interpreta linealmente. La programación orientada a objetos permite la descripción de objetos [instancias de clases] mediante una serie de “características” [propiedades] y “comportamientos” [métodos], que son capaces de interactuar entre sí mediante una serie de reglas compartidas definidas a través de dichos comportamientos. Dicho paradigma excede el nivel que queremos alcanzar con el presente manual, por lo que lo dejaremos para ediciones posteriores. 2. Macros Aunque no es el tema principal que nos ocupa, una leve introducción a las macros no hace mal, y nos ayudará a entender los conceptos básicos que hemos descrito anteriormente. Valga de ejemplo una escalera de caracol: para dibujar una escalera de caracol necesitaríamos repetir un objeto (escalón), copiarlo en altura, y rotarlo una serie de grados. Después, tendríamos que tomar el último elemento u objeto creado (es decir, el escalón que acabamos de copiar) y repetir la operación una serie de veces hasta que terminemos de rellenar el espacio necesario. Hacer esto a mano podría suponernos un buen rato de modelado, aburrido y tedioso. Podemos evitar innecesarias horas delante del monitor si somos capaces de describir [y posteriormente transcribir] las órdenes necesarias en una secuencia que el ordenador pueda entender. A saber: 1. Selecciona el escalón que quieras repetir 2. Copia dicho escalón 3. Mueve el escalón verticalmente una distancia establecida para la huella, por ejemplo: 15cm. 4. Rota el escalón un cierto ángulo (por ejemplo: 10º) alrededor de un eje (por ejemplo uno vertical en 0,0) Podríamos, además, implementar un último paso que repitiera el proceso una serie de veces, como por ejemplo 15, pero de momento vamos a dejarlo aquí para facilitar la simplicidad del código. En todo caso, una macro es una lista o secuencia de órdenes predeterminadas que el programa ejecuta.

[ 6 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

Una vez tenemos claro lo que necesitamos hacer, debemos poder transcribir todo en un lenguaje que pueda entender e interpretar el ordenador. Usaremos el término macro para describir un conjunto de órdenes ordinarias de Rhino escritas de manera secuencial para crear una función automatizada. Así pues, es “scripting” en su nivel más bajo, y veremos que es accesible a cualquier usuario de Rhino, incluso si no tiene conocimientos de programación. Todo lo que necesitamos, como hemos dicho, es un conocimiento aceptable de Rhino, algo de experiencia en modelado, y cierto gusto por la experimentación. Para escribir una macro precisamos: - Nuestro propio interés - Los archivos de ayuda de Rhino, que describen todos los comandos así como sus opciones - Posiblemente el editor “MacroEditor”, que permite ejecutar y analizar nuestras macros. Aquí exponemos algunas de las claves que nos permiten comunicarnos con nuestra herramienta en forma de normas sencillas de sintaxis [puedes ver un listado completo en ingés en http://www.rhino3d.com/4/help/information/rhino_scripting. htm]:

Símbolo Nombre

Explicación

-

Guión

_

Guión Bajo

! ; \

Signo exclamación Punto y coma Barra invertida

Pause w r <

Pause

Cancela la aparición de ventanas asociadas a comandos. Todos los comandos pueden, además, escribirse o llamarse mediante scripts, por lo que es una opción destacada a la hora de escribir los literales o “strings” [ya veremos lo que es ésto más adelante]. Ejecuta el comando en inglés. Necesario para que las macros sean ejecutables independientemente del idioma en el que estemos usando Rhino actualmente. Cancela los comandos en ejecución. Permite introducir un comentario, que no será leido por rhino Si el comando no comienza por “!” y termina con la barra invertida “\”, la macro se ejecutará en la línea de comandos sin pulsar enter, de manera que se puede introducir más información. Esto es útil para construir un comando a partir de dígitos, decimales, ángulos [tal como “<45”] y que se encuentran en botones, creando un “teclado numérico” en la pantalla. Para una macro para input de usuario. Usar coordenadas “World Coordinates” en vez de coordenadas del plano de trabajo. Las coordenadas relativas son relativas a la posición actual del cursor. Input de ángulo en grados.

Menor que

Y aquí podemos analizar nuestra pequeña macro: Linea

Código

Explicación

1 2 3 4 5 6 7 8 9 10 11

! _Copy _pause 0,0,0 0,0,1 _enter

Comando copia con espera para intervención de usuario [selección] Punto inicio [copia] Punto final [copia] Finalizar comando

_selLast

Seleccionar último objeto creado

_rotate _pause 0,0,0 10 _enter

Comando rotar con espera para intervención de usuario Punto para el eje de rotación Ángulo de rotación Finalizar Comando

[Fig 1. Escalera creada con macro]

[ 7 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

3. ¿Dónde escribimos las macros? Perfecto, sabemos escribir un ejemplo de macro, pero, ¿dónde la guardamos? La respuesta es muy sencilla: dado que una macro equivale, a efectos prácticos, a un comando, no hay mejor manera que asociarla a un botón. Aunque hay diferentes maneras de hacer esto, aquí explicaremos las más sencilla y directa. Manteniendo pulsada la tecla Shift mientras ponemos el cursor sobre cualquier botón nos permite Mover o Editar los botones [figura 2]. Edita el botón y aparecerá un menú como el de la figura 3. Menu Emergente

Mover/Editar (Shift+hover) Copiar/Vincular (Ctrl+hover)

[Fig 2. Menú Editar/Mover]

[Fig 3 Menú de edición de botones]

En el espacio reservado para el comando del botón izquierdo del ratón pega el conjunto de órdenes que hemos descrito para nuestra macro. Puedes cambiar la leyenda del mismo. Para guardar los cambios, acepta. Cuando cliques sobre el icono del botón, se ejecutará la macro. Puedes también editar el aspecto del botón, pero eso lo dejaremos para después, cuando tratemos la personalización de la interfaz. Puedes probar tus macros en el editor de macros. Dicho editor es, además, una herramienta útil para excribir macros y detectar posibles errores. Usa el comando “ejecutar” de la ventana de edición para probar tu código. 4. Variables y scripts Una vez nos hemos familiarizado con el comportamiento básico de las macros, podemos empezar a pensar en sistemas más complejos que requieran interacción usuario-ordenador y la introducción de variables para dicha interacción, es decir, sistemas dinámicos que son capaces de manejar distintas situaciones. El funcionamiento de los scripts es similar, si bien se requieren conocimientos de lenguajes de programación [es decir, no vale solamente con copiar y pegar nombres de coman-

[ 8 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

dos] y de modelado. Las limitaciones de las macros han dado lugar, por tanto, a los scripts, una suerte de lugar indefinido entre simples secuencias de órdenes y programas compilados. Así pues, las macros pueden realizar operaciones matemáticas, evaluar condicionantes, responder al entorno y comunicarse con el ususario. Rhinoceros, en su versión 4, implementa VBScript, lo que significa que aquello que es válido para VBScript, lo es también para RhinoScript. Rhinoceros v5 implementa además python, por lo que habrá que ir incorporando lentamente este lenguaje a nuestro día a día. “Traducir” VBScript en lenguaje natural [con el que nos comunicamos tú y yo] no debe ser muy complicado a este nivel. Inicialmente, los lenguajes de programación eran un conjunto de ceros y unos, que con el tiempo [el paso de generaciones de lenguajes en su sentido más estricto] se han conseguido hacer fácilmente entendibles para seres humanos. Las primeras generaciones de lenguaje “código máquina” son muy difíciles de entender, y no tienen cabida entre la mayoría de nosotros. Afortunadamente, se ha evolucionado en los sucesivos desarrollos generacionales hacia una mayor encapsulación que abriese el marco de la programación a gente no necesariamente iniciada [VBasic pertenece a BASIC, una familia de la tercera generación de lenguajes]. Por ejemplo, es posible que queramos guardar unas curvas de nuestro modelo en 3D para modificarlas o borrarlas posteriormente, o tal vez necesitemos conocer la fecha para saber si el software ha expirado; ninguno de estos datos está disponible cuando se ha escrito el script y serán sólamente accesibles a través de variables. Pero volviendo a lo que nos ocupa, sabemos que a menudo necesitamos almacenar información para realizar los cálculos que nos lleven, poco a poco, a la resolución de problemas complejos. Dichos cálculos forman parte de un todo que podemos denominar algoritmo: una secuencia de órdenes determinada, que en un tiempo finito, da un resultado concreto y correcto. El almacenamiento de información para su uso en los algoritmos se puede [y debe] llevar a cabo mediante variables, contenedores de información que constan básicamente de: - Nombre: El nombre es un dato simbólico que se refiere a información almacenada en memoria. Dicho nombre puede ser cualquiera en rVB, con las siguientes salvedades: · Comenzará por carácter alfabético · Contendrá menos de 255 caracteres · No se permiten espacios en blanco, puntos, ni caracteres especiales (!,”, : ; , ...) · No pueden emplearse palabras reservadas del lenguaje - Tipo: indica el tipo de información que almacena una variable. Por ejemplo, y sin entrar en mas detalles, las variables Single y Double pueden ocupar números reales muy grandes. Además, hay otro tipo de variables, las denominadas variant, que son como una variable estándar que “admite cualquier tipo de dato.” - Alcance [“tiempo de vida”]: · Global: para variables declaradas fuera de funciones y subrutinas y accesibles desde cualquier parte del código. · Local: variables declaradas dentro de funciones y subrutinas, no se podrá tener acceso a ellas desde otra parte del código. Esto es, si declaro una variable dentro de una función, solamente podré acceder a ella mientras me encuentre en la función. Si quiero, posteriormente, usar el valor de la misma, deberé pasarla como referencia bien como valor. algunNumero = Rhino.GetInteger(“Introduce un número”,0,50,100) En este ejemplo, “algunNumero” es sencillamente un “placeholder” para un valor determinado, que obtendremos cuando se ejecute el script [en tiempo de ejecución]. Está claro que, cuando estamos escribiendo el script no conocemos el valor de la variable. Fíjate además que el nombre de la variable algunNumero no tiene tilde, ya que sería considerado un carácter especial, cuyo uso está prohibido para la nomenglatura en código [visita de nuevo las características de los nombres si tienes alguna duda]. Recuerda que el lenguaje de código por excelencia es el inglés.

[ 9 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

El uso de las variables debe incluir tres pasos: - Declarar y comentar la variable [usar la palabra reservada “Dim”]. - Inicializar la variable. [asignar un valor inicial] - Programar las debidas instrucciones. Tipo Tamaño Rango Boolean 1 Bit True/False Byte Entero Corto: 1 Byte De -128 a 127 Integer Entero: 2 Bytes De -32768 a 32767 Long Entero: 4 Bytes De -232/2 a (232/2-1) Single Real Simple Precisión: 4 bytes Real Double Real Doble Precisión Real Carácter 1 Byte De -128 a 127 String Cadena de caracteres Texto Date Fecha Fecha

Es posible que en ocasiones [y de hecho, la mayoría de las veces sucede] deseemos agrupar variables, tales como “Nombre”, “Empresa”, “Cargo”, “Sueldo”, o cualquier otro. VBScript nos dota de un sistema [aunque ciertamente deficiente en algunos sentidos] bastante útil para lidiar con este asunto. Las “arrays” son una estructura de información capaz de agrupar variables; puedes pensar en arrays como “contenedores” de información, una especie de bandeja donde podemos colocar los platos de una buena comida.

[Fig 4. Ejemplos cotidianos de arrays: una granja solar, un contenedor]

5. Declaración e inicialización de variables De igual manera que tu interlocutor te preguntará quién es Pepe a tu afirmación “ayer fui al cine con Pepe”, si no le conoce, RhinoScript solicita saber con quién está tratando, es decir, requiere saber qué variables vas a utilizar durante la ejecución del script. Es suficiente con “presentar” [declarar] la variable antes de usarla, es decir, es suficiente con decir que es una variable [en el ejemplo valdría con decir Pepe es un amigo]. En rVB declararemos las variables utilizando la palabra reservada Dim, de la siguiente manera: Dim nombreVar Dim algunNumero Esto es todo lo que necesitamos hacer para hacer saber a Rhino que vamos a utilizar una variable cuyo nombre es algunNumero. Para arrays, esto funciona exactamente igual, ya que se comportan como una variable: Dim nombreArr Dim conjuntoNumeros Y para Dynamic Arrays [ya veremos qué significa esto más adelante]: Dim nombreArr() En este caso “()” indica al programa que la cantidad de objetos que contiene la array (su dimensión) puede cambiar. Una vez declaradas las variables, debemos proceder a su inicialización. Inicializar una variable no es más que asignarle un primer valor, si bien RhinoScript le asigna un valor por defecto, Null, que nos sirve para controlar si la variable se ha usado o no. Es la manera que tiene Rhino de decirnos “no lo sé”.

[ 10 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

La asignación del valor se hace mediante el símbolo “=”, que asigna el valor de la derecha al elemento que se encuentre a su izquierda. Así pues a=1, asigna el valor 1 a la variable de nombre “a”. El tipo de valor que asignemos a la variable determinará el tipo de la variable, de manera que si asignamos un número la variable tendrá carácter numérico, y si asignamos, por ejemplo, una cadena de caracteres, tendrá tipo “String”.

Dim algunNumero algunNumero = 0

El nombre de la variable hace que podamos entender lo que ésta contiene. Podríamos asignar algunNumero = “Presidente”, y RhinoScript lo entendería perfectamente. Sin embargo, nos llevaría a error con absoluta seguridad. Esta asignación se vuelve ligeramente más compleja cuando tratamos con matrices. Las matrices [“arrays”] son conjuntos de elementos, por lo que habrá que asignar un conjunto como valor inicial:

Dim conjuntoNumeros conjuntoNumeros = array(0,1,2,3,4,5,6,7,8,9)

Una vez más, el nombre es independiente de los valores que contiene la variable [esto es, es para “uso humano” solamente], por lo que es más que recomendable tener un nombre descriptivo, sencillo de recordar, y corto, para evitar errores de tipografía. 6. Asignación de valores Al igual que para inicializar variables, la asignación de valores hace uso del símbolo “=”, y funciona de la misma manera. Durante la ejecución del script podemos cambiar el tipo de valor que almacena la variable, pero esto no es recomendable por coherencia y claridad. además, los seres humanos tenemos muy mala memoria, está casi garanztizado que no seremos capaces de recordar la razón por la que hicimos esto o lo otro dos días después de haberlo hecho, así que es una buena práctica mantener una coherencia en todo el código. 7. Obtención/acceso de valores; cambio de los mismos. Necesariamente, si almacenamos información, necesitaremos acceder a ella, tal vez únicamente para conocer su estado, tal vez para modificarla o hacer algún tipo de tarea. La manera de acceder a la inormación es tan sencilla como escribir lo siguiente:

queNumero = algunNumero

O, por ejemplo, imprimir su valor en la pantalla

Rhino.Print algunNumero

En el primer caso hemos asignado el valor de la variable “algunNumero” a la variable “queNumero”. En el segundo caso, hemos dicho a Rhino qe imprima en la línea comandos el valor de algunNumero. Evidentemente, podemos también modificar el valor de la variable o usarlo en alguna operación matemática

Dim otroNumero otroNumero = Rhino.sin(algunNumero)

otroNumero = otroNumero + 10

De nuevo, hemos usado la función “sin” [seno] para calcular el valor del seno de algunNumero, y asignar dicho valor a la variable otroNumero. Después, hemos modificado el valor de otroNumero incrementandolo en 10. Recomiendo que pruebes este conjunto de operaciones en un sencillo script, que se podría transcribir como sigue:

[ 11 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

Option Explicit Call Main() Sub Main() Dim algunNumero Dim otroumero algunNumero = 90 otroNumero = Rhino.Sin(algunNumero) Rhino.Print algunNumero Rhino.print otroNumero otroNumero = otroNumero +10 Rhino.print otroNumero End Sub

8. Estructura del código de rVB Acabas de ver [¡y escribir!] posiblemente tu primer script, ¡enhorabuna! Verás que la estructura del código es muy simple, y consta esencialmente, de las siguientes partes reconocibles a simple vista: · declaración de variables globales [ya lo veremos en un futuro...] · llamadas a subrutinas [al menos a la subrutina principal “Main”] con la palabra “Call” · subrutina principal [bloque de código delimitado entre “Sub Main” y “End Sub”] · otras subrutinas [bloques de código delimitados entre “Sub Nombre” y “End Sub”] · funciones [bloques de código delimitados entre “Function Nombre (argumentos)” y “End Function”] Puede parecer que la estructura es algo compleja, sin embargo, cuando comencemos a escribir, veremos que es mucho más sencilla de lo que aparenta. En este caso, más es menos. 9. Funciones y subrutinas Todo lo que debes saber de funciones y subrutinas es que son bloques de código con un nombre asignado [de manera que puedas “llamarlas” o usarlas cuando lo necesites], una serie de “argumentos” [datos que necesitan para ejecutar correctamente] y un resultado, que puedes decidir pasar o no.Ya ahondaremos en este tema al tiempo que comencemos a escribir scripts más complejos. Recuerda: - Las subrutinas son bloques de código que expresan la secuencia de ejecución del programa. Deben ser llamadas desde fuera y tienen la capacidad de llamar asimismo a otras subrutinas y funciones. - Las funciones bloques de código, grupos de órdenes en secuencia que se agrupan por su lógica. Cada función debe tener una única finalidad. Las funciones, si están debidamente escritas, podrán reutilizarse para varios códigos. - Métodos: los métodos son funciones ya escritas que pertenecen a librerías preexistentes. En el caso de Rhinoceros, se accede a ellos mediante el prefijo “Rhino.”, lo que indica que la función está en un paquete con ese nombre. 10. Ejemplo de código: Puedes comenzar a escribir el siguiente script en el editor de scripts de Rhino, que puedes ejecutar mediante el comando _EditScript. Por defecto, a partir de la versión 5.0 de Rhino, el editor de Scripts será Monkey. El script crea una serie de puntos en el modelo tridimensional de Rhino que tengas abierto. Verás que, una vez terminado el script, estos objetos son una parte más del mismo, y que podrás transformarlos, editarlos, o borrarlos a tu antojo. Procura copiar el script exactamente como se escribe; de otro modo podrías tener problemas de sintaxis con los que es más que probable que no estés familiarizado, por lo que podrías bloquearte. Recuerda, es mala idea generalmente tratar de resolver problemas relacionados con estos asuntos durante más de 30-60 minutos sin consultar la ayuda de una persona más experta. Se trata de aprender, no de desesperar. Verás que al copiar el código en tu editor de scripts, algunas palabras cambian de color, son palabras reservadas para el lenguaje VBasic. Aquellas líneas precedidas de ‘ [apóstrofe] son comentarios, y no serán leidas por Rhino. Son para uso humano. Verás además, que las palabras contenidas entre comillas [“...”], son consideradas cadenas de caracteres literales.

[ 12 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43

1 -5 6 9 12 14 15 17 22 24 25 29 34 -36 37-41 42

[ 13 ]

Option Explicit ‘Comentarios ‘Aquí declaración de variables globales, si procede ‘Llamada a la subrutina principal Call Main() ‘Comienzo de la subrutina principal Sub Main() ‘Órdenes en secuencia ‘Uso de un método Rhino.EnableRedraw(False) ‘Llamada a funciones personalizadas Call DoSinglePoint Call DoPointGrid ‘Uso de método Rhino.EnableRedraw(True) End Sub ‘Fin de subrutina ‘Comienzo de una función Function DoSinglePoint ‘Órdenes en secuencia, incluyen métodos y otros Rhino.AddPoint(array(0,0,0)) End Function ‘Fin de la función ‘Comienzo de una función Function DoPointGrid ‘Órdenes en secuencia, incluyen métodos y otros. Además, podemos incluir comentarios ‘This adds a grid of i*j points starting in 0,0,0 ‘In order to do this we use two NESTED for loops, or flow structures implying repetition ‘Note that every single iteration in the loop the variables have a different value Dim i, j Dim maxX : maxX = 9 Dim maxY : maxY = 9 For i =0 To maxX For j=0 To maxY Rhino.AddPoint(array(i,j,0)) Next Next End Function ‘Fin de la función

Fíjate en la descripción del script línea por línea para entender exactamente qué ocurre. Option Explicit pide a Rhino que mire que TODAS las variables se han declarado antes de usarse, esto esútil para verificar la corrección del script. Las líneas 2,3 y 5 son comentarios. Llamada a la subrutina principal Comienzo de la subrutina, que abarca hasta la línea 18, cuando se cierra. Todo el bloque enrte la línea 9 y la 18 se considera subrutina. Método que dice a Rhino que no dibuje nada en la pantalla [apaga el refresco de la pantalla] Llamada a la función “DoSinglePoint”, bloque de código entre líneas 22 y 26. Rhino ejecutará todo el código contenido ente dichas líneas antes de proceder a ejecutar la línea 15 [esto es, “salta a la función”]. Llamada a la función “DoPointGrid”, bloque de código entre líneas 29 y 42. Método que dice a Rhino que ya puede dibujar de nuevo [reactiva el refresco de la pantalla] Comienzo de la función DoSinglePoint, que se llama en la línea 14. Comando que añade un punto en 0,0,0. Fíjate en la palabra array: está creando un conjunto con tres números. Fin de la función, ahora Rhino ya puede ejecutar la línea 15 [“salta” de nuevo a la subrutina]. Comienzo de la función DoPointGrid, que se llama en la línea 15. Declaraciones de las variables que se van a usar en el script. Dos loops [no te preocupes, ya iremos viendo qué significa eso] que crean filas y columnas de puntos. Fin de la función, ahora Rhino puede ejecutar la línea 16 [“salta” a la subrutina]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

II. PROGRAMACIÓN Y TOPOLOGÍA 1. CodeMonkey Code Monkey [vulgarmente “monkey”] es actualmente el mejor editor de scripts para Rhino. Incluye el editor, compilador y “debugger”, herramienta que permite localizar y corregir errores en el código. En realidad, todo lo necesario para escribir scripts es un editor de texto (notePad, wordPad, o cualquier otro). Este texto es después interpretado, compilado y ejecutado por los “intérpretes”, compilador y motor correspondientes. Rhinoceros incorpora su propio editor de texto, accesible mediante el comando “_editscript”. Monkey incluye, además del editor, funciones como autocompletar, ayuda dinámica y un “debugger”. El debugger es un programa que ayuda a encontrar errores en el script, especialmente de sintaxis, por lo que te será sencillo corregir tus scripts durante su ejecución, mediante la visualización de variables en tiempo real y la detección de errores de sintaxis. El “highlighter”, o reconocimiento automático de palabras reservadas, permite que éstas aparezcan automáticamente en colores que identificarán varios tipos: generalmente azul para palabras de vBasic, gris para los comentarios, verde para cadenas de caracteres, y negro para el resto en general. 1.1. Opciones principales de CodeMonkey Las principales operaciones que se pueden realizar con CodeMonkey son: - Editar scripts: en la ventana de edición, donde debes copiar los scripts que hemos escrito anteriormente. - Consultar la librería, en la ventana de métodos nativos de Rhinoceros. - Consultar la ayuda, haciendo doble click sobre el método que se quiere consultar. La ayuda es muy sencilla y explicativa, e incluye lo siguiente: · Nombre del comando, con una breve descripción de su funcionamiento · Sintaxis y uso: atributos [input] y valores de retorno [output] · Ejemplo, que puedes copiar y pegar directamente en la ventana del editor de scripts. - Para ejecutar un script usa el botón de play; esto ejecutará el script actual [la pestaña activa]. - “Debug” los scripts consite en encontrar fallos en el script. Como hemos dicho, esto se realiza visualizando los calores de las variables en líneas seleccionadas y el estado del script en cada momento. De esta manera podemos encontrar errores comunes tales como: · Confusión entre tipos de datos; por ejemplo, una variable debería tener valor numérico y contiene una cadena de caracteres o alfabéticos. · Errores en la definición de variables, y sus nombres. · Errores de sintaxis; por ejemplo, en símbolos, “(),=.” y otros · Errores en el paso de variables en las funciones. 1.2. Instalando Monkey Si usas la versión SR5 de Rhinoceros, no es necesario que instales Monkey, será el editor de scripts predeterminado. Sin embargo, si eres usuario de SR4, deberáas descargarte el software de la página de McNeel. Monkey es un plugin gratuito. Una vez instalado, deberá aparecer por defecto en la barra de menús; si no es así, ve a >Herramientas>Opciones>Plugins, y asegúrate de que está cargado correctamente y que se carga de manera automática en cada apertura del programa.

[Fig 5. Comando para abrir el editor CodeMonkey]

[ 14 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[Fig 6. Elementos principales de la interfaz de Code Monkey]

Ejecutar script Corregir script Colocar punto de análisis

Guardar como... Guardar scripts activos en pestañas Guardar script Abrir script Crear nuevo script

[Fig 7. Menú de Monkey con los principales iconos de comando]

1.3. Interfaz de CodeMonkey Como ves en las figuras 2 y 3, la interfaz es muy clara. Es probable que únicamente necesites usar los botones principales, que dan acceso a las funciones de edición, corrección y ejecución de scripts. Para abrir Monkey, ve a la pestaña que aparece en la barra de menún, “Monkey”, y haz click sobre “Monkey Editor”.

[ 15 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

2. Vectores y puntos: una sencilla base de geometrías complejas 2.1. Puntos En Rhinoceros, los puntos son las entidades geométricas más sencillas que hay. Tienen tres componentes, que corresponden a su localización x,y,z respecto del plano de trabajo universal. Un punto se describe, por tanto de la siguiente manera: Dim aPoint aPoint = array(x,y,z) Si quisiéramos definir un punto en 10,3,7, por ejemplo, lo podríamos hacer de la siguiente manera creando una array con las coordenadas del mismo: Dim x,y,z, aPoint x = 10 y= 3 z=7 aPoint = array(x,y,z) Rhino.AddPoint aPoint

[Fig 8 Punto en espacio cartesiano R3: A(a1,a2,a3)]

[Fig 9. Vector v en espacio cartesiano R3: v(v1, v2,v3). El punto de aplicación (base) del vector es (0,0,0) por defecto.]

[Fig 10 Punto en espacio cartesiano R3: A(a1,a2,a3)]

[Fig 11. Vector v en espacio cartesiano R3: v(v1, v2,v3). El punto de aplicación (base) del vector es (0,0,0) por defecto.]

[ 16 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

2.2. Vectores Los vectores también se describen por conjuntos de coordenadas, arrays que contienen (x,y,z). En este sentido, son exactamente iguales que los puntos, y tienen el mismo comportamiento. La única diferencia estriba en que, por defecto, todos los vectores están basados en (0,0,0). Las operaciones más sencillas con vectores incluyen suma, diferencia, y escalado, que responden a los siguientes métodos: - Suma: VectorAdd (vec1,vec2) - Sustracción: VectorSubtract (vec1,vec2) - Escalado: VectorScale (vec1,vec2) Donde vec1 y vec2 son arrays de 3 componentes, exactamente igual que en el caso de puntos. 3. Curvas Podemos entender las curvas como entidades controlables a partir de puntos. Las líneas, polilíneas y curvas están basadas en puntos de control, que definen su geometría, continuidad, y tangencias. Los conceptos básicos que debemos conocer en curvas son los siguientes: - Dominio de una curva: es el conjunto de valores reales que resultan que hace que se cumpla la ecuación de la misma. En f(x) = axn+bx(n-1)+(...)+g, por ejemplo, el dominio es el conjunto de valores de x que hacen que f(x) tenga un valor real. Esto mismo aplica a las curvas NURBS, si bien hemos de ser conscientes que las curvas tienen un principio y un final determinado, y que sus ecuaciones, a las que no podemos acceder, son más complejas. Sin embargo, existe una clara correspondencia entre dichos valores y la curva, que podemos ver en la figura 12.

P0

P6

P1 P5

P2

P7

P4 P8 P3

dom(0)+ dom(0)+ dom(0)+ dom(0)+ dom(0)+ dom(0)+ dom(0)+ 1*step 2*step 3*step 4*step 5*step 6*step 7*step

dom(0) valor mínimo dominio

dom(1) valor máximo dominio

[Fig 12. Concepto de dominio de una curva. Los valores Dom(0) [min] y Dom(1) [max] no son necesariamente 0 y 1 y son asignados por Rhino.

- Puntos de control: puntos que definen el polígono de control, a partir del cual se define, en función del tipo de continuidad [es decir, el grado], la curva final. Con RhinoScript es relativamente sencillo obtener este tipo de información, de la misma manera que somos capaces de acceder a los datos de X,Y,Z, de un punto y modificarlo. Las operaciones más comunes son las siguientes: · Evaluar el dominio de una curva. · Crear puntos sobre curvas con RhinoScript. · Crear curvas a través de puntos o usando los puntos como puntos de control de la curva. De todos modos, este tipo de operaciones los veremos a continuación en el siguiente apartado, “Topología de la Geometría NURBS II, Geometría computacional básica 2”. En los scripts que siguen verás que cada una de las funciones incluye a la anterior, de modo que puedes “activar” y “desactivar” los sucesivos pasos a medida que vas avanzando. Te recomiendo que borres los objetos creados en cada uno antes

[ 17 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

de ejecutar el siguiente, para que puedas comparar los resultados sin miedo a esquivocarte.

El código está comentado, de manera que puedes entender cada paso una vez lo vayas copiando en el editor de scripts.

III. SCRIPTS RELACIONADOS En este punto, presentamos dos scripts. El primero incluye funciones de creación de puntos. El segundo, análisis de curvas, dominios y puntos de control. Ambos comienzan por “Option Explicit”. 1. Puntos Como verás, la creación de puntos es muy sencilla, y se realiza mediante el método [función nativa] de Rhino “Rhino. AddPoint”. Esta función requiere de una matriz de componentes (x,y,z), como hemos visto anteriormente. La subrutina Main tiene una serie de funciones, crecientes en complejidad. DoSinglePoint añade un punto al modelo en las coordenadas dadas. Prueba a cambiarlas y ejecutar el script. Para ejecutar una única función descoméntala, y comenta el resto. Haz esto con cada una de las funciones cambiando los valores. DoPointGrid utiliza dos “loops” [estructuras For...Next] para crear una malla de puntos, lo que hace por medio de filas y columnas [crea una columna con j puntos, luego otra... hasta que hace i columnas con j puntos cada una, en total n = j*i puntos]. El siguiente paso es crear una malla tridimensional, para lo cual DoPointGridWithHeight añade un valor distinto de cero para la componente Z del punto. la fórmula utilizada para crear Z puede cambiar. Prueba a cambiarla para ver los distintos resultados. Una vez que hemos manejado puntos en 3D, podemos proceder a crear líneas. Para ello, examina DoLine, una función que crea una línea a partir de dos puntos definidos explícitamente por su punto origen y punto final [cada uno de ellos por sus coordenadas X,Y,Z agrupadas en una array]. DoLines crea líneas a partir de los puntos en una recta, de la misma manera que creábamos los puntos en la función DoPointGrid. Fíjate en que hay que esperar a tener al menos dos puntos creados para proceder a una línea [para tener en cuenta esta condición usamos el código condicional If [condición] then ... End If. Finalmente procedemos a crear una malla de líneas, siguiendo el mismo procedimiento que para DoLines, pero en ambas direcciones (esto es, en X y en Y). DoSimpleComponentGrid aprovecha los mismos puntos para crear una polilínea [la única diferencia estriba en que tenemos ahora un único conjunto de puntos]. Recuerda que para cerrar una polilínea debemos hacer coincidir el primer punto con el último; es decir, para un cuadrado tendremos 5 puntos [ya que el último será igual que el primero si queremos cerrar el polígono]. DoComplexComponentGrid crea, además del perímetro, una curva con los mismos puntos. Esta curva estará contenida dentro del perímetro. DoComplexComponentGridWithLoftSurface creará, además, una superficie entre las curvas anteriores, de manera que tendremos un inicio de volumetría. 2. Curvas La función ShowDomain muestra el concepto de dominio de una curva. Para ello, crea un punto en la curva y muestra, mediante un “textDot” o anotación, el valor del dominio en ese punto. El script requiere una curva, que deberá ser seleccionada por el usuario. Veremos más sobre curvas en el siguiente apartado.

[ 18 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

1. Puntos Option Explicit ‘Script written by <Adolfo Nadal [archiologics.com]> ‘Script NOT copyrighted ‘Script versión martes, 29 de junio de 2010 18:21:34 ‘A series of VERY SIMPLE functions to demonstrate the VERY BASICS of NURBS geometry ‘In later sessions we will explore how to enhance our lofting capabilities Call Main() Sub Main() Rhino.EnableRedraw(False) ‘Call DoSinglePoint ‘Call DoSinglePointWithAnnotation ‘Call DoPointGrid ‘Call DoPointGridWithHeight ‘Call DoLine ‘Call DoLines ‘Call DoLineGrid ‘Call DoSimpleComponentGrid ‘Call DoComplexComponentGrid Call DoLoftSurface ‘Call DoComplexComponentGridWithLoftSurface Rhino.EnableRedraw(True) End Sub Function DoSinglePoint ‘This adds a single point in 0,0,0 ‘We need to enter the 3D coordinates defining the point in an array (collection of objects) Rhino.AddPoint(array(0,0,0)) End Function Function DoSinglePointWithAnnotation ‘This adds a single point in 0,0,0 ‘We need to enter the 3D coordinates defining the point in an array (collection of objects) ‘We also need to store the point in a variable in order to use its information later ‘There is no need to use the “call” keyword when storing result values in variables ‘To DECLARE variables it is necessary to use the dim keyword Dim pt pt = (array(0,0,0)) Call Rhino.AddPoint(pt) Call Rhino.AddTextDot(“Point located at: “ & pt(0) & “,” & pt(1) & “,” & pt(2) ,pt) End Function Function DoPointGrid ‘This adds a grid of i*j points starting in 0,0,0 ‘In order to do this we use two NESTED for loops, or flow structures implying repetition ‘Note that every single iteration in the loop the variables have a different value Dim i, j Dim maxX : maxX = 9 Dim maxY : maxY = 9 For i =0 To maxX For j=0 To maxY Rhino.AddPoint(array(i,j,0)) Next Next End Function Function DoPointGridWithHeight ‘This adds a grid of i*j points starting in 0,0,i*j ‘In order to do this we use two NESTED for loops, or flow structures implying repetition ‘Note that every single iteration in the loop the variables have a different value Dim i, j Dim maxX : maxX = 9 Dim maxY : maxY = 9

[ 19 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

For i =0 To maxX For j=0 To maxY Rhino.AddPoint(array(i,j,i*j)) Next Next End Function Function DoLine ‘A straight line takes 2 points (beginning and end point of a segment) Call Rhino.AddLine(array(0,0,0),array(0,1,0)) End Function Function DoLines Dim i, j Dim maxX : maxX = 9 Dim maxY : maxY = 9 ‘We need to make this call as many times as lines we want to have ‘Note i and j start at 1, since we use i-1 For i=1 To maxX For j=1 To maxY Call Rhino.AddLine(array(i-1,j-1,0),array(i,j,0)) Next Next End Function Function DoLineGrid Dim i, j Dim maxX : maxX = 9 Dim maxY : maxY = 9 ‘We need to make this call as many times as lines we want to have ‘Note i and j start at 1, since we use i-1 For i=1 To maxX For j=1 To maxY Call Rhino.AddLine(array(i-1,j,0),array(i,j,0)) Call Rhino.AddLine(array(i,j-1,0),array(i,j,0)) Next Next End Function Function DoSimpleComponentGrid Dim i, j Dim maxX : maxX = 9 Dim maxY : maxY = 9 Dim pt1,pt2,pt3,pt4 ‘We need to make this call as many times as lines we want to have ‘Note i and j start at 1, since we use i-1 ‘Note also that, in order to close the polyline, we must introduce the first point as the last as well For i=1 To maxX For j=1 To maxY pt1 = array(i-1,j-1,0) pt2 = array(i-1,j,0) pt3 = array(i,j,0) pt4 = array(i,j-1,0) Call Rhino.AddPolyline(array(pt1,pt2,pt3,pt4,pt1)) Next Next End Function Function DoComplexComponentGrid Dim i, j Dim maxX : maxX = 9 Dim maxY : maxY = 9 Dim pt1,pt2,pt3,pt4,pt5 ‘We need to make this call as many times as lines we want to have ‘Note i and j start at 1, since we use i-1

[ 20 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

‘Note also that, in order to close the polyline, we must introduce the first point as the last as well ‘In this case we also introduce a curve that uses the same CONTROL points ‘Since a polyline takes multiple points, the best practice is to create them and store them in variables that we can use later on For i=1 To maxX For j=1 To maxY pt1 = array(i-1,j-1,0) pt2 = array(i-1,j,0) pt3 = array(i,j,0) pt4 = array(i,j-1,0) pt5 = array(i,j-1,j) Call Rhino.AddPolyline(array(pt1,pt2,pt3,pt4,pt1)) Call Rhino.AddCurve(array(pt1,pt2,pt3,pt4,pt1)) Call Rhino.AddCurve(array(pt1,pt2,pt3,pt5,pt1)) Next Next End Function Function DoLoftSurface ‘A loft surface takes at least 2 curves ‘We need to create these and STORE them for future use Dim curve1, curve2 curve1 = Rhino.AddCurve(array(array(0,0,0),array(0,1,0),array(1,1,0),array(1,0,0),array(0,0,0))) curve2 = Rhino.AddPolyline(array(array(0,0,0),array(0,1,0),array(1,1,0),array(1,0,0),array(0,0,0))) Call Rhino.AddLoftSrf(array(curve1,curve2)) End Function

2. Curvas Option Explicit ‘Script written by Adolfo Nadal [archiologics.com] ‘Script NOT copyrighted ‘Script versión jueves, 01 de julio de 2010 12:40:53 ‘A series of VERY SIMPLE functions to demonstrate the VERY BASICS of NURBS curves Call Main() Sub Main() Dim strCrv : strCrv = Rhino.GetObject (“Select the curve to be analyzed”,4) DoSinglePoint (strCrv) DoMultiplePoints (strCrv) ShowDomain(strCrv) End Sub Function DoSinglePoint(strCrv) Dim crvDomain : crvDomain = Rhino.CurveDomain(strCrv) Dim domain : domain = crvDomain(1)-crvDomain(0) Dim arrPt : arrPt = Rhino.EvaluateCurve(strCrv,crvDomain(0)+domain/2) Dim strPt : strPt = Rhino.AddPoint (arrPt) Call Rhino.ObjectColor(strPt,vbRed) End Function Function DoMultiplePoints(strCrv) Dim crvDomain : crvDomain = Rhino.CurveDomain(strCrv) Dim domain : domain = crvDomain(1)-crvDomain(0) Dim nrSteps : nrSteps = 10 Dim domainStepSize : domainStepSize = domain/nrSteps Dim i For i= crvDomain(0) To crvDomain(1) Step domainStepSize Dim arrPt : arrPt = Rhino.EvaluateCurve(strCrv,i) Rhino.AddPoint arrPt Next End Function

[ 21 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

Function ShowDomain(strCrv) Dim pt : pt = Rhino.GetPoint(“point”) Dim curveParam : curveParam = Rhino.CurveClosestPoint(strCrv,pt) Dim ptOnCrv : ptOnCrv = Rhino.EvaluateCurve(strCrv,curveParam) Call Rhino.AddTextDot(“Parameter: “ & curveParam, ptOnCrv) End Function

[ 22 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 23 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

TOPOLOGÍA DE LA GEOMETRÍA NURBS II [Non-Uniform Rational Bezier Splines]

[ 24 ]


[ 25 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

I. GEOMETRÍA COMPUTACIONAL BÁSICA 2 - RECTAS Y CURVAS NURBS 1. El dominio de curvas en Rhino y Rhinoscript: La representación del dominio de curvas en Rhinoceros responde a una serie de características y conceptos que debemos conocer si pretendemos crear scripts o rutinas que incluyan trabajo con líneas, polilíneas, curvas o curvas mixtas, sea cual sea su creación. Es importante resaltar asimismo que los conceptos que siguen aplican a todas las curvas por igual, con independencia de su grado o manera de creación. · En álgebra, el dominio de una curva se refiere al conjunto de valores de la variable independiente (normalmente “x” para los cuales existe un valor real de la variable dependiente (normalmente “y”). Para más información, vuelve a ver la figura 12 del apartado anterior. · En geometría computacional, sea cual sea la representación de la curva, el dominio responde a la definición interna de la misma en R1 (es decir, en el espacio de la curva). Así pues, en Rhino 4 oscila entre 0 y 1, mientras que en Rhino 5 entre 0 y la longitud de la curva. En cualquier caso, 0 representa el origen de la curva, y 1 (o su longitud) el final de la misma. · El dominio responde a la curvatura de la curva, por lo que una división del dominio en n partes iguales no se traduce necesariamente en n segmentos de la misma longitud. · Debemos saber, a la hora de usar curvas para superficies, cuál es el origen y el final de la curva, porque esto influirá en comandos como “loft”, por ejemplo. El comando “_flip”, invierte el sentido de una curva. CRV DOMAIN (0)

CURVE OBJECT MAIN PROPERTIES: ID, DOMAIN, DEGREE - ID: UNIQUE IDENTIFIER ASSIGNED BY RHINO AT THE TIME OF CREATION - DOMAIN: INTERNAL DEFINITION OF A CURVE. IT IS A VALUE BETWEEN 0 & 1, WHERE 0 REPRESENTS THE START OF THE CURVE AND 1 THE END. IT DOES NOT REFER TO ITS LENGTH, RATHER TO ITS CURVATURE

CRV DOMAIN (X)

CRV DOMAIN (0)<CRV DOMAIN (X)<...<CRV DOMAIN (Z)<CRV DOMAIN (1)

CRV DOMAIN (Y)

CRV DOMAIN (Z)

[Fig 1. Dominio de una curva]

CRV DOMAIN (1)

2. Espacio R1 (curva) y espacio R3 (cartesiano): Así pues, parece obvio que podemos referirnos a los puntos de una curva aproximándonos a ellos de dos maneras distintas: por un lado, mediante su localización en el espacio, es decir, por sus coordenadas (X,Y,Z); por otro, por su posición en la curva, es decir, por su domino (d). Esto responde claramente a la diferencia entre R3 [espacio cartesiano] y R1 [espacio unidimensional de la curva]: · R1 es el espacio unidimensional de la curva, definido por un único valor [dominio] · R3 es el espacio tridimensional cartesiano, definido por tres valores [array(x,y,z)]

[ 26 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

Option Explicit ‘Script written by Adolfo Nadal ‘Script copyrighted by archi[o]logics www.archiologics.com ‘Script update jueves, 02 de febrero de 2012 9:02:43, V.0.0.0. Call Main() Sub Main() Dim strCrv : strCrv = Rhino.GetObject (“Select your curve”,4) Dim dom dom = Rhino.CurveDomain(strCrv) Dim begPt, finPt begPt = Rhino.EvaluateCurve(strCrv,dom(0)) finPt = Rhino.EvaluateCurve(strCrv,dom(1)) Rhino.AddPoint begPt Rhino.AddPoint finPt Rhino.Print “El inicio del dominio de la curva [dom(0) es: “ & dom(0) & “ y corresponde al punto: “ & Rhino.Pt2Str(begPt) Rhino.Print “El final del dominio de la curva [dom(0) es: “ & dom(1) & “ y corresponde al punto: “ & Rhino.Pt2Str(finPt) End Sub

Por lo tanto, recuerda que cualquier punto de una curva puede expresarse de dos modos: (i) en referencia al espacio cartesiano [su posición x,y,z en el espacio], y (ii) en referencia a la curva a la que pertenece, mediante su dominio [que tomará un valor entre 0 y 1 en Rhino v4, o entre 0 y su longitud en Rhino v5]. 3. Curvas a partir de puntos Rhinoceros permite la generación de una gran variedad de curvas, entre las que se encuentran: - Por puntos de control - Interpoladas [a través de puntos] - Interpoladas en superficie [la curva estará contenida en ella] - Por manejadores [define un punto y su tangencia] - Trazar [bosquejar] curvas: boceto - Trazar en malla poligonal/superficie - Cónicas - Promedios Todas estas curvas pueden modificarse una vez terminadas. La modificación se hace generalmente a partir de los puntos de control, bien por adición y substracción, bien por su modificación. Los puntos de control se comportan como objetos del dibujo, e incluyen una serie de propiedades., que siguen: - Posición - Peso: grado de influencia sobre la curvatura de la curva [a mayor peso, más cerca estará la curva de pasar por el punto de control]. Existen otras técnicas avanzadas de creación de curvas, tales como: - Fluir a lo largo de una superficie - Curvas UVN [aplicadas sobre superficies] Dichas técnica interpolan de una u otra manera la curva original sobre la superficie seleccionada. La primera admite guardado de historial, por lo que es muy útil a la hora de crear curvas sobre superficies complejas, como por ejemplo fachadas estructurales. La edición de las curvas se realiza, como hemos dicho, a partir de sus puntos de control, fácilmente accesibles tanto explícitamente [modelando] como implícitamente [a partir de RhinoScript].

[ 27 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

Curva por puntos de control Curva por interpolación Curva por interpolación en superficies Curva por manejadores Trazar Trazar sobre malla Cónicas y parábolas Hélice y espiral Curvas promedio Activar puntos de control Activar puntos de edición/ desactivar seleccionados Ocultar caras posteriores de polígono de control Mover UVN, toque ligero UVN Insertar nodo/ punto de edición

Extender/Empalmar /Achaflanar línea Simplificar Insertar/Eliminar puntos de control Cambiar modo de arrastre Editar con manejadores Añadir nodo Eliminar nodo Definir peso de puntos de control

Subcurva Insertar línea en curva Booleana de curvas

Cerrar curvas abiertas Eliminar subcurva Extraer subcurva

[Fig 2. Herramientas de creación y edición de curvas - II]

II. SUPERFICIES Y POLISUPERFICIES EN RHINOCEROS 1. Direcciones en superficies - Direcciones U y V: · Las superficies son más o menos rectangulares. Las superficies tienen tres direcciones, U, V y normal. Las direcciones U, V y normal se pueden visualizar con el comando Dir. Las direcciones U y V son como el tejido de ropa o de una tela. La dirección U se indica con la flecha roja y la dirección V con la flecha verde. La dirección normal se indica con flechas blancas. Las direcciones U, V y normal se corresponderían a las direcciones X, Y y Z de la superficie. · Estas direcciones se utilizan para el mapeado de texturas y la inserción de puntos de control. - Dirección normal: · En las superficies, la normal es una dirección que señala hacia la parte “exterior” o “superior” de la superficie, y es perpendicular a la superficie en el punto de cálculo. Para polisuperficies cerradas (cono, cilindro, caja, etc.) o sólidos de una superficie (esfera, toroide), la normal siempre está orientada “hacia fuera”. Sin embargo, en una superficie o polisuperficie abierta la dirección de la normal depende de cómo se creó y puede ser arbitraria. · El comando Dir muestra la dirección de la normal de un objeto.

[Fig 3. Dirección en una superficie]

[ 28 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

2. Concepto y manejo de dominios de superficies en Rhinoscript · Al igual que en curvas, el dominio en superficies es la representación geométrica interna que nos permite obtener puntos sobre la superficie en R2 (es decir, sobre el “espacio binario” de la superficie). · Toda superficie tiene dos dominios, uno en la dirección “u” y otro en la dirección “v”, de manera que, mediante la combinación de dos parámetros “i” (correspondiente a u) y “j” (correspondiente a v), se puede hallar y calcular la posición de un punto en la superficie (que, de nuevo, puede expresarse en términos de R2 o R3). Coloquialmente podríamos decir que u y v corresponden a las componentes ”X” e “Y” sobre un plano [en el que sabemos, por ejemplo, que la componente Z es 0], pero sobre la superficie. · Para una polisuperficie, el dominio se calcula para cada una de las superficies componente, por lo que es muy conveniente modelar con superficies.

3. R2 y R3 [“espacio superficie” y espacio cartesiano] · R2 es el espacio bidimensional de la superficie [coordenadas implícitas a la geometría]. · R3 es el espacio tridimensional cartesiano, eso ya lo sabíamos. de anteriores descripciones. · Como sabemos, cualquier punto de una superficie puede expresarse de dos modos: (i) en referencia al espacio cartesiano (su posición x,y,z en el espacio en las coordenadas de dibujo y coordenadas globales), y (ii) en referencia a la superficie a la que pertenece, mediante su dominio [mediante dos valores entre DomMin y DomMax, si dichos valores no se han normalizado para que sean DomMin = 0 y DomMax = 1]. · Normalizado: con la opción Sí, los intervalos de los parámetros U y V se escalan para que los valores resultantes estén entre cero y uno (en lugar de usar el valor del parámetro real). Esta opción es útil cuando desea saber el porcentaje del espacio de los parámetros del punto designado sin tener que calcularlo según el dominio de la superficie. Con la opción No, se proporcionan los valores de los parámetros U y V no escalados. Véase también Dominio. · Nota: Cuando se selecciona una polisuperficie, Rhino calcula el resultado de la superficie componente en la posición designada. Si la superficie es recortada, Rhino usará la superficie no recortada.

[Fig 4. Expresión de superficies y puntos sobre superficies. Dominio]

[ 29 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

4. Creación de superficies, puntos y nubes de puntos, curvas FILA 1 Superficie por 3 ó 4 puntos Superficie por curvas de borde Superficie a partir de curvas planas Superficie rectangular Extruir curva FILA 2 Loft - transición Superficie por network de curvas Superficie parche Sweep 1/2 railes

FILA 3 Superficie de revolución Cubrir objetos con superficie Mapa de alturas desde imagen Superficie desde rejilla de puntos

[Fig 5. Principales herramientas relativas a generación y ectracción de información de superficies]

- Los métodos más comunes de creación de superficies son: · Superficies a partir de puntos: rectangulares, por 3 ó 4 puntos, ajustar plano a través de puntos. · Superficies a partir de curvas: loft, sweep extrusión, patchwork, revolución, a partir de una red de curvas. · De la misma manera pueden crearse polisuperficies y sólidos. Dejaremos la edición de sólidos por el moment, ya que éstos requieren de un conocimiento propio de modelado con caras que no incluimos en este manual. Si eres un usuario habitual de programas de modelado 3D para animación [como por ejemplo Autodesk Maya o Autodesk 3DMax] entonces es probable que te interesen, pero los encontrarás limitados con respecto a las limitaciones de dichos programas.

- Precauciones usando el comando “loft”: · Como norma general, las curvas deben tener el mismo número de puntos de control · Asimismo, hemos de ser cuidadosos con el sentido de las mismas, así como su alineación. III. SCRIPTS RELACIONADOS Llegados a este punto, es interesante ver cómo aplican todos estos coneptos al diseño implícito y la generación automática de geometría a través de la programación. De nuevo, se presenta un script con una serie de funciones [que puedes ir activando y desactivando a tu gusto] que describo brevemente a continuación: - La subrutina Main contiene todas las funciones que puedes activar y desactivar. Recuerda una vez más que para desactivarlas, lo que realmente hacemos es comentar la línea donde ésta se llama, de manera que RhinoScript salte la línea y no ejecute la función [dado que nunca se llama]. - DoSinglePoint crea un punto en el medio de la superficie. Hace esto calculando los rangos de dominio, calculando su punto medio [del dominio] y evaluando la superficie para ese conjunto de dominios [matriz con dos valores de dominio, uno para u, otro para v]. Al evaluar [Rhino.EvaluateSurface] la superficie, RhinoScript nos devuelve las coordenadas del punto en R3, por lo que ya podemos añadirlo al modelo mediante AddPoint. Si además asignamos el resultado de esa operación a una variable, somos capaces de acceder a sus propiedades, y cambiar el color del objeto punto.

[ 30 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

- DoSinglePointWithNormal y DoSinglePointWithNormalScaled crea, además del punto anterior, otro en la normal a la superficie en dicho punto. En el segundo caso se escala la normal. En el código verás que hay una serie de pasos que hay que seguir para conseguirlo: · En primer lugar, es importante saber que el comando SurfaceFrame retorna una serie de valores, de los cuales [en este caso] nos interesa solamente la normal. Visita la ayuda para saber exactamente qué devuelve la función. · La normal, como buen vector que es, está basado en (0,0,0). Por esta razón, si calculamos la normal y creamos un punto con sus coordenadas, veremos que está muy cerca del origen de coordenadas. Para solucionar esto, debermos sumar el normal al punto de la superficie donde hemos obtenido la normal. De esta manera, el vector normal estará localizado en su sitio. · Por último, no hay garantía de que el vector normal sea unitario. Recuerda que si quieres que lo sea, deberás hacerlo unitario antes de moverlo a su sitio, de otra manera el escalado se realizará sobre las coordenadas del resultante de la suma y verás un resultado incorrecto. Los pasos a seguir son, por tanto: (i) Obtener un punto en la superficie. Usa el método Rhino.EvaluateSurface. (ii) Hallar el SurfaceFrame en ese punto. (iii) Elegir solamente la información que precisamos, consultar la ayuda si es necesario. (iv) Escalar el vector por su longitud para que resulte unitario [opcional]. Usa el método Rhino.VectorScale (arrVec,arrayScaleFactors). (v) Volver a escalar el vector a una longitud determinada [opcional] (vi) Mover el vector a su sitio sumandolo a la posición del punto original. Usa el método Rhino.VectorAdd (arrVec1,arrVec2).

· Prueba el siguiente dummy de script para reforzar estos conceptos.

Option Explicit ‘Script written by Adolfo Nadal ‘Script copyrighted by archi[o]logics www.archiologics.com ‘Script update viernes, 03 de febrero de 2012 12:12:19, V.0.0.0. Call Main() Sub Main() Dim strPt1,strPt2 strPt1 = Rhino.GetObject (“Select Point1”,1) strPt2 = Rhino.GetObject (“Select Point2”,1) Dim arrpt1, arrpt2 arrPt1 = Rhino.PointCoordinates (strPt1) arrPt2 = Rhino.PointCoordinates (strPt2) Dim arrPt3 arrPt3 = Rhino.AddVector (arrPt1,arrPt2) Dim strPt3 strPt3 = Rhino.AddPoint(arrPt3) End Sub

- DoMultiplePoints y las subsiguientes realizan las mismas operaciones que sus correspondientes funciones pero con más puntos. Observa la manera de hallar los puntos mediante la definición de un “step”, la longitud del segmento en el dominio para ir incrementando su valor. El número de pasos influirá en la longitud de dicho segmento, lo que tendrá su correspondencia en la distancia entre cada punto en la superficie final. - Por último, showDomain muestra el dominio de la superficie a efectos prácticos.

[ 31 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

Option Explicit ‘Script written by Adolfo Nadal [archiologics.com] ‘A series of VERY SIMPLE functions to demonstrate the VERY BASICS of NURBS surfaces Call Main() Sub Main() Dim strSrf : strSrf = Rhino.GetObject (“Select the surface to be analyzed”,8) Dim scaleFactor : scaleFactor = 0.2 Call DoSinglePoint (strSrf) Call DoSinglePointWithNormal(strSrf) Call DoSinglePointWithNormalScaled(strSrf,scaleFactor) Call DoMultiplePoints (strSrf) Call DoMultiplePointsWithNormal (strSrf) Call DoMultiplePointsWithNormalScaled (strSrf,scaleFactor) ShowDomain(strSrf) End Sub Function DoSinglePoint(strSrf) ‘There exist two directions, U and V, therefore 2 domains ‘Note we name those with 0 for U and 1 for V Dim Udomain : Udomain = Rhino.SurfaceDomain(strSrf,0) Dim Vdomain : Vdomain = Rhino.SurfaceDomain(strSrf,1) Dim minUDomain : minUDomain = UDomain(0) Dim maxUDomain : maxUDomain = UDomain(1) Dim minVDomain : minVDomain = VDomain(0) Dim maxVDomain : maxVDomain = VDomain(1) ‘Create a point in the middle of the surface Dim arrPt : arrPt = Rhino.EvaluateSurface(strSrf,array((maxUDomain+minUDomain)/2,(minVDomain+maxVDoma in)/2)) Dim strPt : strPt = Rhino.AddPoint (arrPt) Call Rhino.ObjectColor(strPt,vbRed) End Function Function DoSinglePointWithNormal(strSrf) ‘There exist two directions, U and V, therefore 2 domains ‘Note we name those with 0 for U and 1 for V Dim Udomain : Udomain = Rhino.SurfaceDomain(strSrf,0) Dim Vdomain : Vdomain = Rhino.SurfaceDomain(strSrf,1) Dim minUDomain : minUDomain = UDomain(0) Dim maxUDomain : maxUDomain = UDomain(1) Dim minVDomain : minVDomain = VDomain(0) Dim maxVDomain : maxVDomain = VDomain(1) ‘Create a point in the middle of the surface Dim arrPt : arrPt = Rhino.EvaluateSurface(strSrf,array((maxUDomain+minUDomain)/2,(minVDomain+maxVDoma in)/2)) Dim strPt : strPt = Rhino.AddPoint (arrPt) Call Rhino.ObjectColor(strPt,vbRed) ‘How do we obtain a normal? Use Surface frame, which returns many things! (see Monkey help) Dim srfFrame : srfFrame = Rhino.SurfaceFrame (strSrf, array((maxUDomain+minUDomain)/2,(minVDomain+maxV Domain)/2)) Dim arrNormalPt : arrNormalPt = srfFrame(3) ‘But, as all other, this vector is based on (0,0,0), we need to “translate” it to its actual position ‘This is, relative to arrPt ‘So we add both vectors (remember: points and vectors behave the same way: arrays of 3 components) arrNormalPt = Rhino.VectorAdd(arrPt,arrNormalPt) Dim strNormalPt : strNormalPt = Rhino.AddPoint(arrNormalPt) Call Rhino.ObjectColor(strNormalPt,vbGreen) End Function Function DoSinglePointWithNormalScaled(strSrf,scaleFactor) ‘There exist two directions, U and V, therefore 2 domains ‘Note we name those with 0 for U and 1 for V Dim Udomain : Udomain = Rhino.SurfaceDomain(strSrf,0) Dim Vdomain : Vdomain = Rhino.SurfaceDomain(strSrf,1)

[ 32 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

Dim minUDomain : minUDomain = UDomain(0) Dim maxUDomain : maxUDomain = UDomain(1) Dim minVDomain : minVDomain = VDomain(0) Dim maxVDomain : maxVDomain = VDomain(1) ‘Create a point in the middle of the surface Dim arrPt : arrPt = Rhino.EvaluateSurface(strSrf,array((maxUDomain+minUDomain)/2,(minVDomain+maxVDoma in)/2)) Dim strPt : strPt = Rhino.AddPoint (arrPt) Call Rhino.ObjectColor(strPt,vbRed) ‘How do we obtain the normal? We use the Surface frame, which returns many things! (see Monkey help) Dim srfFrame : srfFrame = Rhino.SurfaceFrame (strSrf, array((maxUDomain+minUDomain)/2,(minVDomain+maxV Domain)/2)) Dim arrNormalPt : arrNormalPt = srfFrame(3) ‘Before moving the point we need to scale it, otherwise, it will be displaced!!!!!! ‘Should you have any question or coment on this, do not hesitate to ASK arrNormalPt = Rhino.VectorScale(arrNormalPt,scaleFactor) ‘As all other vectors, it is STILL -despite the scaling!!!- based on (0,0,0), so we need to “translate” it to its actual position ‘This is, relative to arrPt ‘So we add both vectors (remember points and vectors behave the same way, just arrays of 3 components) arrNormalPt = Rhino.VectorAdd(arrPt,arrNormalPt) Dim strNormalPt : strNormalPt = Rhino.AddPoint(arrNormalPt) Call Rhino.ObjectColor(strNormalPt,vbGreen) End Function Function DoMultiplePoints(strSrf) ‘There exist two directions, U and V, therefore 2 domains ‘Note we name those with 0 for U and 1 for V Dim Udomain : Udomain = Rhino.SurfaceDomain(strSrf,0) Dim Vdomain : Vdomain = Rhino.SurfaceDomain(strSrf,1) Dim minUDomain : minUDomain = UDomain(0) Dim maxUDomain : maxUDomain = UDomain(1) Dim minVDomain : minVDomain = VDomain(0) Dim maxVDomain : maxVDomain = VDomain(1) ‘FROM HERE IT DIFFERS FROM DOSINGLEPOINT: WE NEED MORE INFO Dim srfUDomain : srfUDomain = maxUDomain-minUDomain Dim srfVDomain : srfVDomain = maxVDomain-minVDomain ‘Let us decide how many “divisions” we need in each direction Dim nrUSteps : nrUSteps = 5 Dim domainUStepSize : domainUStepSize = srfUDomain/nrUSteps Dim nrVSteps : nrVSteps = 5 Dim domainVStepSize : domainVStepSize = srfVDomain/nrVSteps ‘Let us use those in order to populate the surface with points ‘In vbScript: “give me a point and i will move the world” Dim i, j For i= minUDomain To maxUDomain Step domainUStepSize For j= minVDomain To maxVDomain Step domainVStepSize Dim arrPt : arrPt = Rhino.EvaluateSurface(strSrf,array(i,j)) Rhino.AddPoint arrPt Next Next End Function Function DoMultiplePointsWithNormal(strSrf) ‘There exist two directions, U and V, therefore 2 domains ‘Note we name those with 0 for U and 1 for V Dim Udomain : Udomain = Rhino.SurfaceDomain(strSrf,0) Dim Vdomain : Vdomain = Rhino.SurfaceDomain(strSrf,1) Dim minUDomain : minUDomain = UDomain(0) Dim maxUDomain : maxUDomain = UDomain(1) Dim minVDomain : minVDomain = VDomain(0) Dim maxVDomain : maxVDomain = VDomain(1) ‘FROM HERE IT DIFFERS FROM DOSINGLEPOINT: WE NEED MORE INFO Dim srfUDomain : srfUDomain = maxUDomain-minUDomain Dim srfVDomain : srfVDomain = maxVDomain-minVDomain

[ 33 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

‘Let us decide how many “divisions” we need in each direction Dim nrUSteps : nrUSteps = 5 Dim domainUStepSize : domainUStepSize = srfUDomain/nrUSteps Dim nrVSteps : nrVSteps = 5 Dim domainVStepSize : domainVStepSize = srfVDomain/nrVSteps ‘Let us use those in order to populate the surface with points ‘In vbScript: “give me a point and i will move the world” Dim i, j For i= minUDomain To maxUDomain Step domainUStepSize For j= minVDomain To maxVDomain Step domainVStepSize Dim arrPt : arrPt = Rhino.EvaluateSurface(strSrf,array(i,j)) Rhino.AddPoint arrPt Dim srfFrame : srfFrame = Rhino.SurfaceFrame (strSrf, array(i,j)) Dim arrNormalPt : arrNormalPt = srfFrame(3) arrNormalPt = Rhino.VectorAdd(arrPt,arrNormalPt) Dim strNormalPt : strNormalPt = Rhino.AddPoint(arrNormalPt) Call Rhino.ObjectColor(strNormalPt,vbGreen) Next Next End Function Function DoMultiplePointsWithNormalScaled(strSrf,scaleFactor) ‘There exist two directions, U and V, therefore 2 domains ‘Note we name those with 0 for U and 1 for V Dim Udomain : Udomain = Rhino.SurfaceDomain(strSrf,0) Dim Vdomain : Vdomain = Rhino.SurfaceDomain(strSrf,1) Dim minUDomain : minUDomain = UDomain(0) Dim maxUDomain : maxUDomain = UDomain(1) Dim minVDomain : minVDomain = VDomain(0) Dim maxVDomain : maxVDomain = VDomain(1) ‘FROM HERE IT DIFFERS FROM DOSINGLEPOINT: WE NEED MORE INFO Dim srfUDomain : srfUDomain = maxUDomain-minUDomain Dim srfVDomain : srfVDomain = maxVDomain-minVDomain ‘Let us decide how many “divisions” we need in each direction Dim nrUSteps : nrUSteps = 5 Dim domainUStepSize : domainUStepSize = srfUDomain/nrUSteps Dim nrVSteps : nrVSteps = 5 Dim domainVStepSize : domainVStepSize = srfVDomain/nrVSteps ‘Let us use those in order to populate the surface with points ‘In vbScript: “give me a point and i will move the world” Dim i, j For i= minUDomain To maxUDomain Step domainUStepSize For j= minVDomain To maxVDomain Step domainVStepSize Dim arrPt : arrPt = Rhino.EvaluateSurface(strSrf,array(i,j)) Rhino.AddPoint arrPt Dim srfFrame : srfFrame = Rhino.SurfaceFrame (strSrf, array(i,j)) Dim arrNormalPt : arrNormalPt = srfFrame(3) ‘Remember to scale before the addition takes place arrNormalPt = Rhino.VectorScale(arrNormalPt,scaleFactor) arrNormalPt = Rhino.VectorAdd(arrPt,arrNormalPt) Dim strNormalPt : strNormalPt = Rhino.AddPoint(arrNormalPt) Call Rhino.ObjectColor(strNormalPt,vbBlue) Next Next End Function Function ShowDomain(strSrf) Dim pt : pt = Rhino.GetPoint(“point”) Dim arrSrfParam : arrSrfParam = Rhino.SurfaceClosestPoint(strSrf,pt) Dim ptOnCrv : ptOnCrv = Rhino.EvaluateSurface(strSrf,arrSrfParam) Call Rhino.AddTextDot(“Parameter U: “ & arrSrfParam(0) & “, Parameter V: “ & arrSrfParam(1), ptOnCrv) End Function

[ 34 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 35 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

SUPERFICIES Y COMPONENTES diseño paramétrico con scripting

[ 36 ]


[ 37 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

I. GEOMETRÍA COMPUTACIONAL BÁSICA 3 - SUPERFICIES Y COMPONENTES 1. Qué son y para qué sirven Los componentes son familias o grupos de elementos que tienen un comportamiento determinado y una dependencia geométrica definida. Esto significa que, para componentes descritos a partir de, por ejemplo, cuatro puntos, podemos obtener infinitas variaciones dentro de su misma lógica [esto es, podríamos definir un conjunto de elementos geométricos que comparten la propiedad de poder ser creados y/o definidos a partir de cuatro puntos cualesquiera]. La figura 1 ilustra de manera muy sencilla este concepto. - Por ejemplo, un cubo y un prisma rectangular cualquiera pueden ser instancias de la misma familia de componentes si los hemos creado con base a 4 puntos de una cara y la altura del mismo. La variación de la colocación de estos puntos nos da infinitas posibilidades, si bien todas ellas responden a la misma familia. Cada una de las polisuperficies obtenidas será un componente.

Obviamente, podemos [y debemos!] crear componentes más complejos, que reflejen condiciones proyectuales u otras, tales como: · Condiciones atmosféricas · Condiciones de programa · Condiciones constructivas · Condiciones estructurales · Condiciones estéticas · Cualquier otra condición que se te ocurra Según vayas ganando destreza en la programación podrás implementar sistemas que incorporen condiciones más complejas, o importar y exportar información de archivos de texto, excel, u otros. Asimismo, serás capaz de crear animaciones y sistemas paramétricos complejos. Es posible que, incluso, estés interesado en el diseño algorítmico [de hecho, si estás leyendo este manual, es muy probable que así sea]. Durante el desarrollo de los siguientes temas iremos destacando posibles formas de interactuación, así como incrementaremos la dificultad de los ejercicios y el tratamiento de geometría. Pero recuerda, no se trata de crear formas complicadas, sino complejas; esto es, no gratuitas, sino “informadas”, es decir, que respondan a condiciones externas u otras, como acabamos de explicar hace tan solo un momento. 2. La superficie como base para componentes En el ejemplo de la figura 1, hemos reconocido nuestra capacidad de crear componentes a partir de elementos geométricos muy simples, en este caso puntos. Por tanto, si somos capaces de obtener información de puntos de cualquier ente geométrico, podremos reproducir dichos componentes sobre, por ejemplo, una malla o una superficie. De esta forma ha-

[ 38 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

cemos posible crear componentes en superficies, y se hace fundamental ser capaces de obtener información depuntos de superficies y otras entidades geométricas, métodos que hemos analizado y desarrollado anteriorment en el punto anterior. ya ves que es muy importante manejar con fluidez los conceptos de dominio y normal que hemos visto en la sesión anterior. Recordemos brevemente cómo obtener puntos de una superficie: · Los puntos se obtendrán a partir de una superficie mediante su evaluación en unos parámetros de dominio determinados [sus coordenadas (u,v)] en el espacio R2 de la superficie del caso. · Ya sabes que los métodos rhinoScript que debes emplear son: Rhino.EvaluateSurface (strObject,arrParameter); Evalúa una superficie en unos parámetros u,v. Devuelve una matriz con las coordenadas del punto en R3. En error, devuelve el valor “Null”. Rhino.SurfaceDomain(strObject, intDirection); Devuelve el dominio de una superficie en la dirección especificada. En errod, “Null” Requiere la dirección para U o V; 0 = U, o 1 = V.

[Fig 2. Familia de componentes sobre una superficie]

Aun a riesgo de ser excesivamente insistentes, incluyo otro ejemplo del uso del método Rhino. SurfaceDomain [recuerda que el lenguaje natural para la programación es, por excelencia, el inglés]: Const rhObjectSurface = 8 Dim strObject, arrDomU, arrDomV strObject = Rhino.GetObject(“Select a surface”, rhObjectSurface) If Rhino.IsSurface(strObject) Then arrDomU = Rhino.SurfaceDomain(strObject, 0) arrDomV = Rhino.SurfaceDomain(strObject, 1) Rhino.Print “Domain in U direction: “ & CStr(arrDomU(0)) & “ to “ & CStr(arrDomU(1)) Rhino.Print “Domain in V direction: “ & CStr(arrDomV(0)) & “ to “ & CStr(arrDomV(1)) End If

Verás que creamos una serie de superficies. El comando que utilizamos es “_Loft”, y lo llamaremos desde RhinoScript con el método Rhino.Command “comando”,0. El 0 significa que el comando no se imprimirá en la pantalla, por lo que su ejecución será más rápida y eficiente. · Rhino.AddLofSurface sería una opción a la hora de crear superficies a partir de curvas. Sin embargo, ajustar los puntos de costura es difícil. Por ello emplearemos la línea de comandos directamente. · También podemos emplear Rhino.AddSrfPt, lo que crea una superficie por puntos (3 ó 4). Es el equivalente al comando crear superficie por puntos. II. SCRIPTS RELACIONADOS El script que verás a continuación usa lo que hemos aprendido sobre de distribuciones de puntos en superficies para crear componentes en 3D, que se comportarán como polisuperficies. En este caso, de hecho, todo el conjunto se comportará como un objeto único. Los pasos a seguir se describen a continuación: · Elegir la superficie base, el número de subdivisiones lo puedes controlar dentro del script directamente [se

[ 39 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

lección en línea 12, fíjate que el “8” es superficies]. · Elegir un punto de atracción, a partir del cual modificaremos los componentes [el script escalará los componentes en función de la distancia a este punto]. En la línea 13 usamos el comando GetPoint que nos devuelve direcatamente las coordenadas del punto. · El primer paso es subdividir la superficie en función de su dominio, por lo que deberemos tener en consideración que las subdivisiones no tendrán necesariamente el mismo tamaño. [líneas 18 a 42]. · Una vez tenemos los puntos ordenados en una matriz, podemos proceder a hacer el componente, mediante las siguientes fases: - Calcular las normales para copiar las polilíneas que nos darán el desarrollo volumétrico del componente [líneas 43 a 62] - Crear las polilíneas base para las superficies [líneas 63 a 66]. - Escalar las polilíneas de acuerdo a su distancia hasta un punto [ver variable “d”], líneas 68 a 80. - Crear las superficies desde las polilíneas en la superficie y las polilíneas escaladas. Esto se hace llamando la función “CommandLoft”, que crea las superficies mediante lofts. Líneas 83 a 85. - Finalmente, uniendo las superficies creadas. Ten en cuenta el orden en las que las introduces, es necesario que sean contiguas para que el comando funcione. Línea 87. - Por último, limpia los objetos innecesarios [las curvas y polilíneas auxiliares que nos sirvieron de base], en la línea 91. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43

Option Explicit ‘Script written by Adolfo Nadal ‘Script NOT copyrighted ‘Script versión Monday, November 09, 2009 5:44:41 PM ‘How To create a component-based system On a surface using attractor(s) ‘This uses “hand-made” lofting Call Main() Sub Main() Dim l,k,u,v, dblDist, strCrv, strCrv2,strCrv3, strCrv4 Dim strSrf : strSrf = Rhino.GetObject (“Select your surface”,8) Dim arrPt : arrPt = Rhino.GetPoint (“Select your point”) Dim d : d = 25 Dim intU : intU = 40 Dim intV : intV = 20 ReDim arrFrPt(intU, intV) Dim UDomain : UDomain = Rhino.SurfaceDomain (strSrf,0) Dim VDomain : VDomain = Rhino.SurfaceDomain (strSrf,1) Dim UStep : UStep = (UDomain(1)-UDomain(0))/intU Dim VStep : VStep = (VDomain(1)-VDomain(0))/intV Rhino.EnableRedraw(False) For l = 0 To intV For k = 0 To intU u = UDomain(0) + UStep * k v = VDomain(0) + VStep *l arrFrPt(k,l) = Rhino.SurfaceFrame (strSrf, array(u,v)) dblDist = Rhino.distance (arrPt,arrFrPt(k,l)(0)) ‘Some calls To make clear what we are doing! ‘Call Rhino.AddPoint (arrFrPt(k,l)(0)) If l Mod 2=0 And k Mod 2=0 And l>0 And k>0 Then ‘-FIRST PART ‘-On SURFACE ‘Then we Do the curves On the surface ‘We Do this using arrFrPt(k,l)(0) Dim arrPt1 : arrPt1 = arrFrPt(k,l)(0) Dim arrPt2 : arrPt2 = arrFrPt(k-2,l)(0) Dim arrPt3 : arrPt3 = arrFrPt(k-2,l-2)(0) Dim arrPt4 : arrPt4 = arrFrPt(k,l-2)(0) strCrv = Rhino.Addpolyline(array(arrPt1,arrPt2,arrPt3,arrPt4,arrPt1)) strCrv2 = Rhino.Addpolyline(array(arrPt1,arrPt2,arrPt3,arrPt4,arrPt1))

[ 40 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105

‘-SECOND PART ‘--COMPONENT- ‘And the corresponding ones according To the surface normal: Let us ‘1: obtain the normal vector For Each corner of the component ‘[We Do this using arrFrPt(k,l)(3) And adding this To the actual position of ‘the point On the surface] ‘- pay attention To the vector “chalk explanation” ‘2: scale these according To a certain factor we want To measure (optional) ‘3: draw 4 surfaces For Each side And the rest of the component [good moment ‘To create a couple of ex ‘tra functions -we skip that, even If it Is very bad coding practice] Dim arrNormalPt1 : arrNormalPt1 = (arrFrPt(k,l)(3)) Dim arrNormalPt2 : arrNormalPt2 = (arrFrPt(k-2,l)(3)) Dim arrNormalPt3 : arrNormalPt3 = (arrFrPt(k-2,l-2)(3)) Dim arrNormalPt4 : arrNormalPt4 = (arrFrPt(k,l-2)(3)) arrNormalPt1 = Rhino.VectorAdd(arrPt1,arrNormalPt1) arrNormalPt2 = Rhino.VectorAdd(arrPt2,arrNormalPt2) arrNormalPt3 = Rhino.VectorAdd(arrPt3,arrNormalPt3) arrNormalPt4 = Rhino.VectorAdd(arrPt4,arrNormalPt4) strCrv3 = Rhino.Addpolyline(array(arrNormalPt1,arrNormalPt2,arrNormalPt3,_ arrNormalPt4,arrNormalPt1)) strCrv4 = Rhino.Addpolyline(array(arrNormalPt1,arrNormalPt2,arrNormalPt3,_ arrNormalPt4,arrNormalPt1)) ‘-THIRD PART ‘-SURFACING If dblDist < d*0.9 Then Call Rhino.ScaleObject d,dblDist/d,dblDist/d)) Call Rhino.ScaleObject d,dblDist/d,dblDist/d)) Else Call Rhino.ScaleObject array(0.9,0.9,0.9)) Call Rhino.ScaleObject array(0.9,0.9,0.9)) End If

(strCrv2, arrFrPt(k-1,l-1)(0),array(dblDist/ (strCrv4, arrFrPt(k-1,l-1)(0),array(dblDist/

(strCrv2, arrFrPt(k-1,l-1)(0), (strCrv4, arrFrPt(k-1,l-1)(0),

‘Rhino.Print “Before Lofting” Dim strSrf1: strSrf1 = CommandLoft(strCrv,strCrv2) Dim strSrf2: strSrf2 = CommandLoft(strCrv2,strCrv4) Dim strSrf3: strSrf3 = CommandLoft(strCrv3,strCrv4) ‘Rhino.Print “After Lofting” Call Rhino.JoinSurfaces(array(strSrf1,strSrf2,strSrf3),True) ‘-FOURTH PART ‘-CLEANING UP Rhino.DeleteObjects(array(strCrv,strCrv2,strCrv3,strCrv4)) End If Next Next Rhino.HideObject(strSrf) Rhino.EnableRedraw(True) End Sub Function CommandLoft(Poly,Crv) Call Rhino.Command (“_selnone “,0) Call Rhino.SelectObjects (Array(Poly,Crv)) Call Rhino.Command (“_-loft _enter _enter “,0) Call Rhino.Command (“_selnone “,0) CommandLoft = Rhino.FirstObject End Function

[ 41 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

INTRODUCCIÓN AL DISEÑO ALGORÍTMICO

[ 42 ]


[ 43 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

GEOMETRÍA COMPUTACIONAL AVANZADA I. INTRODUCCIÓN AL DISEÑO ALGORÍTMICO 1. Qué es el diseño algorítmico - El diseño algorítmico es todo aquel diseño que implica una serie de algoritmos, descritos e implementados bien implícitamente en el diseño, bien explícitamente. Aplicado a la arquitectura es en la gran mayoría de las veces sustituido por la expresión “diseño paramétrico”, de manera claramente errónea. Como sabemos, el diseó paramétrico es mucho más reductivo [todos los cuadrados son rectángulos, pero no todos los rectángulos son cuadrados]. Así pues, estamos frente a diseño generativo, aquél que se define mediante relaciones y procesos interrelacionados de una manera determinada y que se resuelve de una manera correcta. Dichas relaciones de comportamiento afectan a la morfología de los todos los elementos implicados en el proceso estético, constructivo, y de composición. Como consecuencia, podemos diseñar un edificio a partir de las condiciones que lo definen, que nosotros, como diseñadores, debemos tratar de identificar y modelar. A modo de resumen, el diseño algorítmico se ocupa del proceso, de la creación de un sistema, no de una solución determinada. La solución de dicho sistema es una consecuencia de la evaluación del proceso, no un fin en si mismo. 2. Cómo comenzar el diseño algorítmico No deberías intentar diseñar con metodologías implícitas si no tienes unos conocimientos fundamentales de geometría [revisa los capítulos dedicados a topología de geometría NURBS antes de embarcarte en esta apasionante aventura]. Una vez dominados los conceptos básicos de geometría, podemos comenzar a pensar en diseñar el “origen” de dicha geometría, es decir, en vez de basar una serie de componentes en una distribución más o menos lógica, homogénea, explícita de geometría bien puntos, curvas...], podemos: · Modificar los componentes en función de condicionantes de diseño · Modificar el punto de partida, para que responda a condicionantes de diseño Los ejemplos que se muestran a continuación tratan de explicar, de manera clara y sencilla, cuáles son estos dos puntos de vista. A través de los ejemplos expuestos iremos viendo distintas aproximaciones al asunto del diseño algorítmico.

[Fig 1. Ejemplo de geometría generada mediante funciones recursivas]

[ 44 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

3. Herramienta y método El diseño algorítmico es a la vez herramienta y método. Al contrario que la mayoría de herramientas proyectuales usadas en arquitectura y construcción, las cuales son restrictivas en su uso y posibilidades [y por tanto ejercen un papel homogeneizante], el diseño algorítmico nos permite la creación de herramientas “ad-hoc”. Esta metodología permite crear herramientas concretas para problemas concretos, o soluciones que, a modo de guante, se adapten perfectamente a la forma de los problemas. Dichas herramientas se podrán adaptar sin demasiado esfuerzo a las neceisdades de otro tipo de problemas. II. CASOS DE EJEMPLO: 1. Recursividad I: pirámides de Sierpinski. El triángulo de Sierpinski es un fractal que se puede construir a partir de cualquier triángulo. El fractal consiste en la subdivisión del triángulo en otros cuatro, cuyos lados se obtienen de la división de los lados del original en dos. De cada punto medio de los lados del triángulo original nacen los vértices de los finales, de la manera que se indica en el gráfico de la figura 2. Eso se efectúa de forma indefinida para cada uno de los triángulos obtenidos, o hasta que se consigue una condición de borde. La pirámide se contruye de idéntica manera, partiendo de 4 puntos, en vez de solamente 3.

1 -1 triangle

2 - 4 triangles

3 - 16 triangles

[Fig 2. Desarrollo del triángulo de Sierpinski en pasos sucesivos]

Fíjate en la última frase del párrafo anterior: “esto se efectúa [repite] de forma indefinida para cada uno de los triángulos obtenidos [en cada una de las subdivisiones sucesivas]...” Esta es la definición práctica de recursividad: una operación de la cual se obtiene un objeto topológicamente idéntico al anterior, y que se repite en el propio resultado. Los fractales son ecuaciones recursivas, de ahí su complejidad. Veamos el código que nos permite crear este tipo de geometría recursiva en Rhino. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27

[ 45 ]

Option Explicit ‘Script written by Adolfo Nadal ‘Script by archi·o·logics www.archiologics.com ‘How to create a recursive sierpinski pyramid Call recursiveExample_tetrah() Sub recursiveExample_tetrah() Dim tetrah, userLength ‘tetrah = Rhino.GetObjects(“select your points”) tetrah = Rhino.GetPoints(False,False,”pick points”,,4) ‘ in brackets whatever you want Rhino to ask the user ‘ HOW CAN I KNOW THE DIMENSION OF AN ARRAY-------> UBOUND userLength=Rhino.GetReal(“enter minimum length for pyramid edeges”,1,1,10) subdivideTetrahedron tetrah, userLength End Sub Function subdivideTetrahedron(tetrah, userLength) ‘ ‘blue: vb script ‘ ‘black words we made up, Rhino does not understand (can teach it) Dim Length0, Length1, Length2, Length3, Length4, Length5, arrLength, minLength, vertexPts, midPt0, midPt1, midPt2, midPt3, midPt4, midPt5, tetrah0, tetrah1, tetrah2, tetrah3, tetrah4 Dim Curve0, Curve1, Curve2, Curve3, Curve4, Curve5, Curves Dim Srf0, Srf1, Srf2, Srf3, PolySurface, Surfaces, userLength Curve0 = Rhino.AddCurve(array(tetrah(0),tetrah(1)),1) Curve1 = Rhino.AddCurve(array(tetrah(1),tetrah(2)),1) Curve2 = Rhino.AddCurve(array(tetrah(2),tetrah(0)),1)


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85

Curve3 = Rhino.AddCurve(array(tetrah(0),tetrah(3)),1) Curve4 = Rhino.AddCurve(array(tetrah(1),tetrah(3)),1) Curve5 = Rhino.AddCurve(array(tetrah(2),tetrah(3)),1) Length0 = Rhino.CurveLength(curve0) Length1 = Rhino.CurveLength(curve1) Length2 = Rhino.CurveLength(curve2) Length3 = Rhino.CurveLength(curve3) Length4 = Rhino.CurveLength(curve4) Length5 = Rhino.CurveLength(curve5) Srf0 = Rhino.AddSrfPt(array(tetrah(0),tetrah(1),tetrah(2),tetrah(0))) Srf1 = Rhino.AddSrfPt(array(tetrah(0),tetrah(3),tetrah(2),tetrah(0))) Srf2 = Rhino.AddSrfPt(array(tetrah(0),tetrah(3),tetrah(1),tetrah(0))) Srf3 = Rhino.AddSrfPt(array(tetrah(1),tetrah(3),tetrah(2),tetrah(1))) ‘ in Rhino.JoinSurfaces, false does not delete input surfaces PolySurface = Rhino.JoinSurfaces(array(Srf0, Srf1, Srf2, Srf3), True) ‘--------------------------------------------------------------------------‘ what is the minimum length of the 6 lines ‘arrLength= Array(Length0,Length1,Length2,Length3, Length4,Length5) ‘minLength = Rhino.Min(arrLength) ‘ or ‘minLength = Rhino.Min(Length0,Length1,Length2,Length3,Length4,Length5) ‘--------------------------------------------------------------------------minLength = Length0 ‘this deletes the curves in every iteration since we do not want them Curves=array(Curve0, Curve1, Curve2, Curve3, Curve4, Curve5) Call Rhino.DeleteObjects(Curves) ‘ if length less than x then do not subdivide If (minLength > userLength) Then ‘-------------------------------------‘Surfaces=array(Srf0, Srf1, Srf2, Srf3) ‘Call Rhino.DeleteObjects(Surfaces) ‘-------------------------------------Call Rhino.DeleteObject(PolySurface) ‘ get points vertexPts = tetrah ‘ ‘ this is an array: this array is a list of points, which are arrays themselves ‘ get midpoints ‘ ‘ midPt0 = ((x+x1)/2,(y+y1)/2,(z+z1)/2) ‘ ‘ everything in an array is separated by commas ‘ ‘ in the vertexPts the first () tells which point it is, the second () tells the coordinate midPt0 = Array((vertexPts(0)(0)+vertexPts(1)(0))/2,(vertexPts(0)(1)+vertexPts(1)(1))/2, (vertexPts(0)(2)+vertexPts(1)(2))/2) midPt1 = Array((vertexPts(1)(0)+vertexPts(2)(0))/2,(vertexPts(1)(1)+vertexPts(2)(1))/2, (vertexPts(1)(2)+vertexPts(2)(2))/2) midPt2 = Array((vertexPts(2)(0)+vertexPts(0)(0))/2,(vertexPts(2)(1)+vertexPts(0)(1))/2, (vertexPts(2)(2)+vertexPts(0)(2))/2) midPt3 = Array((vertexPts(0)(0)+vertexPts(3)(0))/2,(vertexPts(0)(1)+vertexPts(3)(1))/2, (vertexPts(0)(2)+vertexPts(3)(2))/2) midPt4 = Array((vertexPts(1)(0)+vertexPts(3)(0))/2,(vertexPts(1)(1)+vertexPts(3)(1))/2, (vertexPts(1)(2)+vertexPts(3)(2))/2) midPt5 = Array((vertexPts(2)(0)+vertexPts(3)(0))/2,(vertexPts(2)(1)+vertexPts(3)(1))/2, (vertexPts(2)(2)+vertexPts(3)(2))/2) tetrah0 = array(vertexPts(0),midPt0,midPt2,midPt3) tetrah1 = array(midPt0,vertexPts(1),midPt1,midPt4) tetrah2 = array(midPt1,vertexPts(2),midPt2,midPt5) tetrah3 = array(midPt3,midPt4,midPt5,vertexPts(3)) ‘ recursevelly call this function subdivideTetrahedron tetrah0,userLength subdivideTetrahedron tetrah1,userLength subdivideTetrahedron tetrah2,userLength subdivideTetrahedron tetrah3,userLength End If End Function

[ 46 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

En este caso, seleccionaremos 4 puntos, 3 correspondientes a la base de la pirámide, y el último a la altura de la misma. No importa la forma, puesto que el programa se ocupa de dividir los segmentos correspondientes independientemente de su posición. 1 -5 6

9-11 14 15

18 21-24 25-30 31-36 37-40 42 50 52-53 55-90 55 60 69-74 75-78 80-83 85

Aunque está perfectamente comentado, vamos a ver brevemente las partes más relevantes del código: Option Explicit pide a Rhino que mire que TODAS las variables se han declarado antes de usarse, esto esútil para verificar la corrección del script. Las líneas 2,3 y 5 son comentarios. Llamada a la subrutina principal Comienzo de la subrutina, que abarca hasta la línea 16, cuando se cierra. Todo el bloque enrte la línea 9 y la 16 se considera subrutina. Declaración de la variable tetrah, y adquisición de las coordenadas de los 4 puntos que se necesitan para la ejecución del script. En esta línea establecemos el límite de la subdivisión: cuando una de las aristas de la pirámide alcance la longitud especificada, el script dejará de correr. Llamada a la función principal de subdivisión “subdivideTetrahedron”, que se llamará a si misma en las líneas 80 a 83. Fíjate que la función necesita solamente los cuatro puntos de la matriz tetrah, y la condición de parada de la función. Si no introducimos dicha función, el programa correría hasta agotar la memoria del ordenador [es decir, ¡subdiviría hasta el infinito!] Comienzo de la función SubdivideTetrahedron, que se llama en la línea 15. Declaraciones de las variables que se van a usar en el script. Creación de las líneas auxiliares que nos van a permitir hacer la subdivisión [de estas líneas se obtiene el punto medio]. Otención de la longitud de cada una de dichas líneas. Creación de las cuatro superficies que constituyen las caras de la pirámide. Unión de dichas superficies en una única polisuperficie. Asignación de la longitu del primer borde como mínima distancia para comprobar si se debe continuar ejecutando el script. Borrado de las curvas auxiliares. Es aquí donde se hace el truco completo. Evaluaremos la condiciones que hemos establecido y, si procede, se llamará de nuevo a la función “subdivideTetrahedron” ¡desde ella misma! Veamos en detalle: Evaluación de la condición de longitud de artista mediante la estructura de control de flujo “If... then...end if” Borrar la polisuperficie hecha hasta ahora, ya que vamos a subdividir de nuevo Calcular todos los puntos medios que necesitamos, 6 en total. Crear las pirámides con los puntos obtenidos, son cuatro caras a partir de 6 puntos. Llamar la función de nuevo para cada uno de los tetraedros, esto es, subdividir cada una de las pirámides nuevas en tantas veces como para la orginal [el crecimiento de geometría es claramente exponencial, como puedes ver. Final de la función

2. Recursividad II: un pabellón panelizado. El pabellón que se propone surge de la misma idea de subdivisión recursiva. El fractal propuesto es semejante al triángulo de Sierpinski, pero toma cierto volumen de la manera en que se muestra en la figura 3. El triángulo medio se desplaza en la dirección normal al primero, de manera que los triángulos perimetrales se colocan con cierta pendiente. Para cada uno de estos elementos, el proceso se repite hasta que el perímetro del triángulo alcanza un límite mínimo por debajo del cual no hay más recursividad y se detiene la subdivisión.

mid 1

mid 2

mid 3

BASE SURFACE

SUBDIVISION

[Fig 3. Desarrollo del triángulo de Sierpinski modificado]

[ 47 ]

ELEVATION


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62

Option Explicit ‘Script written by Adolfo Nadal ‘Script by archi·o·logics www.archiologics.com ‘How to create a recursive structure Call recursiveExample() Sub recursiveExample() Dim triangle triangle = Rhino.GetObject(“select your triangle”,8) ‘ in brackets whatever you want Rhino to ask the user Rhino.EnableRedraw False subdivideTriangle(triangle) Rhino.EnableRedraw True End Sub Function subdivideTriangle(triangle) ‘blue: vb script ‘black words we made up, Rhino does not understand (can teach it) Dim triangleLength, vertexPts, midPt0, midPt1, midPt2, triangle0, triangle1, triangle2, triangle3 Dim centerPoint, triangleCrv, srfParam, srfNormal ‘1 extract a polyline from a surface ‘to extract a line the best is to write the command directly, therefore we us that. We need ‘to do what the command requires, therefore enter ‘we do not write the brackets, since we do not need to return anything Rhino.SelectObject triangle Rhino.Command(“_DupBorder enter”) triangleCrv = Rhino.FirstObject triangleLength = Rhino.CurveLength(triangleCrv) ‘ the FIRST OBJECT COMMAND returns the LAST OBJECT CREATED BY THE USER If(triangleLength > 10) Then ‘ centerpt centerPoint = CurveAreaCentroid(triangleCrv) ‘ normal srfParam = Rhino.SurfaceClosestPoint(triangle, centerPoint(0)) srfNormal = Rhino.SurfaceNormal(triangle, srfParam) ‘ get corners of each triangle vertexPts = Rhino.PolylineVertices(triangleCrv) ‘ get midpoints of each edge ‘ in the vertexPts the first () tells which point it is, the second the coordinate midPt0 = Array((vertexPts(0)(0)+vertexPts(1)(0))/2,(vertexPts(0)(1)+vertexPts(1)(1))/2, (vertexPts(0)(2)+vertexPts(1)(2))/2) midPt1 = Array((vertexPts(1)(0)+vertexPts(2)(0))/2,(vertexPts(1)(1)+vertexPts(2)(1))/2, (vertexPts(1)(2)+vertexPts(2)(2))/2) midPt2 = Array((vertexPts(2)(0)+vertexPts(0)(0))/2,(vertexPts(2)(1)+vertexPts(0)(1))/2, (vertexPts(2)(2)+vertexPts(0)(2))/2) ‘ now we have the three midpoints ‘ scale and normalize vector srfNormal = Rhino.VectorUnitize(srfNormal) srfNormal = Rhino.VectorScale(srfNormal, triangleLength*0.1) ‘move midpoints by normal midPt0 = Rhino.VectorAdd(midPt0, srfNormal) midPt1 = Rhino.VectorAdd(midPt1, srfNormal) midPt2 = Rhino.VectorAdd(midPt2, srfNormal) ‘ draw 4 new triangles based on midpoints ‘ order is important to know the normal direction triangle0 = Rhino.AddSrfPt(array(vertexPts(0), midPt0, midPt2)) triangle1 = Rhino.AddSrfPt(array(vertexPts(1), midPt1, midPt0)) triangle2 = Rhino.AddSrfPt(array(vertexPts(2), midPt2, midPt1)) ‘recursively call this function subdivideTriangle(triangle0) subdivideTriangle(triangle1) subdivideTriangle(triangle2)

[ 48 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

63 64 65 66

‘borrar el triángulo original Rhino.DeleteObjects Array(triangle, triangleCrv) End If End Function

Al contrario que en el caso anterior, este script está basado en una superficie, de la cual extraeremos el borde, y que servirá de base para encontrar los vértices que necesitamos. Es un proceso distinto para alcanzar el mismo resultado. Una vez más, la forma no es relevante, puesto que el programa se ocupa de dividir los segmentos correspondientes independientemente de su posición. 6 10 13 17 20 27-30 27 28 29 30 32 34 36 37 39 42-44 47-48 50-52 55-57 60-62 64 66

Aunque está perfectamente comentado, vamos a ver brevemente las partes más relevantes del código: Llamada a la subrutina principal Obtención del triángulo inicial, restringido a superficie. Llamada de la función subdivideTriangle, que ejecuta la subdivisión. Comienzo de la función subdivideTriangle. Declaraciones de las variables principales que se necesitan para la ejecución del script. Obtención del perímetro de los triángulos para evaluarlo como condición para continuar las subdivisiones. Seleccionar la superficie triangular Duplicar el borde mediante acceso al comando de Rhino Obtención de dicho objeto accediendo a la lista de objetos creada de Rhino. El primer objeto en la lista es el último objeto creado. Medición de la curva de perímetro obtenida en el paso anterior. Evaluación de la condición de subdivisión. Si cumple la condición [el perímetro es menor de 10 unidades en este caso] entonces se ejecutarán las siguientes líneas [ de la 33 a la 64]. Cálculo del centroide del triángulo. Obtención del punto de centroide en la superficie, mediante el comando “SurfaceClosestPoint” Obtención de la normal a la superficie en ese punto. Obtención de los vértices del borde de la superficie. Obtención de los puntos medios de cada arista. Escalar el vector normal para una distancia deseada: ha de hallarse el vector unitario primero, luego escalarlo. Aplicar la transformación del vector normal a cada uno de los puntos medios hallados con anterioridad. Creación de los tres triángulos que después se subdividirán. Llamar la función subdivideTriangle con cada una de las superficies de los triángulos obtenidos por subdivisión. Borrar el triángulo que ha dado origen a la subdivisión Finalizar la función

[Fig 4. Resultado del fractal]

[ 49 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

3. Aleatoriedad y dirección: una escultura automática En este caso vamos a aplicar scripting para la realización de un elemento escultórico automatizado. De nuevo, a partir de una figura geométrica, crearemos las condiciones para obtener una estructura reiterativa, guiada por un punto. Los principales pasos que se siguen son los siguientes: - Obtención del elemento base - Elección aleatoria de una cara - Creación a partir de dicha cara de una pirámide triangular - Repetición del proceso con una de las caras de la pirámide. Así pues, la idea es crear una pirámide a partir de una cara dada, seleccionar una cara [que no sea la ya obtenida] de dicha pirámide y continuar el proceso de manera indefinida hasta que se cumpla una condición determinada. Para orientar el proceso, se selecciona además un punto “atractor”, hacia el que se orientará la superficie automáticamente. Así pues, la distancia a ese punto podrá servir de condición para la finalización del proceso de creación de geometría.

[Fig 5. Escultura automática]

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23

Option Explicit ‘Script written by Adolfo Nadal ‘Script by archi·o·logics www.archiologics.com ‘How to create an oriented sculpture Call Main() Sub Main() Dim strObject : strObject = Rhino.GetObject (“Select your surface”,8) Dim arrPt : arrPt = Rhino.GetPoint (“Select your attractor”) Dim stopDist : stopDist = Rhino.GetReal (“Select minimum distance for pyramid to stop”) Call MakePyramid(strObject,arrPt, stopDist) End Sub Function MakePyramid(strObject,arrPt,stopDist) ‘Obtain center of surface Dim ctPt : ctPt = Rhino.EvaluateSurface(strObject, Rhino.SurfaceClosestPoint(strObject, Rhino.SurfaceAreaCentroid(strObject)(0))) ‘Make vector to point (scale by border length Dim dirVec dirVec = arrPt dirVec = Rhino.SurfaceNormal(strObject,Rhino.SurfaceClosestPoint(strObject, Rhino. SurfaceAreaCentroid(strObject)(0))) ‘dirVec = Rhino.PointSubtract(arrPt,ctPt)

[ 50 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85

[ 51 ]

dirVec = Rhino.VectorUnitize (dirVec) ‘dirVec = Rhino.VectorScale(dirVec,0.5) dirVec = Rhino.VectorAdd(dirVec,ctPt) ‘Make pyramid Dim arrFaces, face1,face2,face3, border Dim arrPts border = Rhino.JoinCurves(Rhino.DuplicateEdgeCurves(strObject),vbtrue)(0) arrPts = Rhino.PolylineVertices(border) Rhino.DeleteObject border face1 = Rhino.AddSrfPt(array(arrPts(0),arrPts(1),dirVec)) face2 = Rhino.AddSrfPt(array(arrPts(1),arrPts(2),dirVec)) face3 = Rhino.AddSrfPt(array(arrPts(2),arrPts(0),dirVec)) arrFaces = array(face1,face2,face3) ‘Obtain face closest to point with centroid Dim arrCtPt1,arrCtPt2,arrCtPt3 arrCtPt1 = Rhino.EvaluateSurface(face1, Rhino.SurfaceClosestPoint(face1, Rhino. SurfaceAreaCentroid(face1)(0))) arrCtPt2 = Rhino.EvaluateSurface(face2, Rhino.SurfaceClosestPoint(face2, Rhino. SurfaceAreaCentroid(face2)(0))) arrCtPt3 = Rhino.EvaluateSurface(face3, Rhino.SurfaceClosestPoint(face3, Rhino. SurfaceAreaCentroid(face3)(0))) Dim arrCtPts : arrCtPts = array(arrCtPt1,arrCtPt2,arrCtPt3) Dim minDist,j, winner, curDist minDist = 1000000 For j = 0 To Ubound(arrCtPts) curDist = Rhino.Distance(arrCtPts(j),arrPt) If curDist<minDist Then minDist = curDist winner = j End If If curDist<stopDist Then Exit Function End If Next Rhino.Print “winner “ & winner ‘do new surfaces with holes and delete former Dim arrBorderI(2), inBorderI(2) arrBorderI(0) = Rhino.JoinCurves(Rhino.DuplicateEdgeCurves(face1),vbtrue)(0) arrBorderI(1) = Rhino.JoinCurves(Rhino.DuplicateEdgeCurves(face2),vbtrue)(0) arrBorderI(2) = Rhino.JoinCurves(Rhino.DuplicateEdgeCurves(face3),vbtrue)(0) inBorderI(0) = Rhino.ScaleObject (arrBorderI(0),arrCtPt1,array(0.85,0.85,0.85),vbTrue) inBorderI(1) = Rhino.ScaleObject (arrBorderI(1),arrCtPt2,array(0.9,0.9,0.9),vbTrue) inBorderI(2) = Rhino.ScaleObject (arrBorderI(2),arrCtPt3,array(0.6,0.6,0.6),vbTrue) Dim i For i = 0 To Ubound(arrBorderI) Rhino.SelectObjects(array(arrBorderI(i),inBorderI(i))) Rhino.Command “-_Loft _enter _enter”,0 Rhino.UnselectAllObjects Next ‘repeat process until condition is met MakePyramid arrFaces(winner),arrPt,stopDist Rhino.DeleteObjects arrFaces Rhino.DeleteObject strObject End Function


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

8-13 15-85 17

20-27 30-34

36-39

42-46 48-60 65-71 73-78 81 82-83

Adjuntamos de nuevo una breve descripción del código: Subrutina principal: en ésta se obtienen todos los objetos e inputs necesarios Comienzo de la función MakePyramid Obtención del centroide de las superficies. Fíjate que en este caso hemos incluido unas funciones dentro de otras, de manera que los resultados de las de más dentro sirven de inoput a las siguientes. Siempre que tengas este tipo de estructura de funciones comienza a leer de dentro hacia fuera, de la más interna a la más externa. Este es el orden en el que Rhino ejecutará el código. Obtención del vector normal de la superficie. Dicho vector se normaliza [se hace unitario], y posteriormente debe “colocarse en su sitio”, para lo cual es necesario añadirlo al centroide. Obtenemos el borde de la superficie triangular, para poder escalarlo posteriormente. La idea es crear, con dichas curvas, una superficie con un hueco en el centro. Podríamos simplificar el proceso si no hacemos los huecos, la diferencia la ves en la figura 5. Creación de las superficies de la pirámide. Nos servirán para hallar la distancia del centroide al atractor, condición de parada del script. Si la distancia es menor que la mínima introducida por el usuario en la línea 11, entonces para la función, y por tanto el script. Obtención de los centroides de cada una de las caras. Obtención del centroide más cercano al punto atractor. Obtención de los bordes de las superficies y de los bordes interiores [que son los primeros escalados un porcentaje distinto para cada cara]. Superficies de loft entre dichas curvas. Repetición de todo el proceso. Si se ha llegado hasta aquí, entonces no hemos llegado lo suficientemente cerca al punto. Borrar objetos innecesarios

4. Utilidades I: Cálculo y visualización de pendientes en un terreno a partir de una malla tridimensional. A continuación mostraremos cómo el diseño algorítmico y la programación pueden aplicarse fácilmente a la creación de herramientas personalizadas. A veces es preciso modelar terrenos, e inmediatamenet después usar dichos modelos de terrenos para detectar zonas en las que, debido a la pendiente, no es posible construir. Podríamos pensar, además, en incluir zonas en las que el terreno tenga forma cóncava, susceptible de albergar corrientes de agua. Esta segunda parte te la dejo a ti como ejercicio. Hay algunos pasos previos al ahora de realizar este ejercicio. - Si partes de una superficie, crea la malla correspondiente - Si tienes alguna cara con cuatro vértices [quads], conviértelos a triángulos. En caso contrario, no deberás hacer nada y ya puedes aplicar el script. El script es relativamente sencillo, todo lo que debes hacer se reduce a los siguientes pasos: - Obtener los vértices de la malla - Calcular el ángulo de cada cara, relativo a la horizonal - Convertir el ángulo a las unidades correspondientes, para poder identificar las zonas de mayor y menor pendiente dentro de la malla. - Calcular, para cada vértice, el ángulo medio de todas las caras que comparte . En función del ángulo, asignar un color a cada vértice de la malla - Finalmente, asignar dicho color a cada uno de los vértices para su displau. En este caso, será un color no visible en el renderizado, sí en modo sombreado o “shaded” . De nuevo, como ejercicio, puedes probar a intentar asignar los intervalos de pendientes en función de input introducido por el usuario, de manera que sea él quien decida qué intervalos de pendiente son apropiados para cada actuación. Como es habitual, a continuación presentamos una descripción del código, que pretende complementar la que ya se ha incluido en el mismo rvb como comentarios. Verás, al probar el script, que la resolución de los gradientes es mayor cuanto mayor es el número de caras. Es responsabilidad tuya manejar la malla para optimizar el resultado sin incrementar sustancialmente la cantidad de geometría del modelo.

[ 52 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[Fig 6. Script aplicado a mallas de distinta densidad sobre el mismo terreno - la resolución de la definición es sensiblemente mejor en la malla de la izquierda]

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39

[ 53 ]

Option Explicit ‘Script written by Adolfo Nadal ‘Script by archi[o]logics www.archiologics.com Call Main() Sub Main() Dim strmesh : strmesh = Rhino.GetObject (“Select your terrain mesh”,32) ‘nrVC = number of vertices Dim nrVC : nrVC = Rhino.MeshVertexCount(strmesh)-1 ‘arrV = vertices ‘arrVN = vertex normals Dim arrV,arrVN arrVN = Rhino.MeshVertexNormals (strMesh) arrV = Rhino.MeshVertices(strMesh) ‘arrVNP = vertex normals projected (z = z of mesh vertex) Dim arrVNP ReDim arrVNP(nrVC) ‘arrVC = nr times vertices Color has changed for each vertex Dim arrVC() ReDim arrVC(nrVC) Dim arrVCRGB() ReDim arrVCRGB(nrVC) Dim i For i = 0 To Ubound (arrVCRGB) arrVCRGB(i) = Array(0,0,0) Next Dim arrFV : arrFV = Rhino.MeshFaceVertices(strMesh) ‘face vertices contains the index of the vertices contained in arrV Dim j, k For j = 0 To Ubound (arrFV) For k = 0 To Ubound (arrFV(j)) Dim arrVNtmp, arrVNPtmp,arrVtmp arrVtmp = arrV(arrFV(j)(k))


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98

arrVNtmp = arrVN(arrFV(j)(k)) arrVNtmp = Rhino.VectorAdd(arrVNtmp,arrVtmp) arrVNPtmp = arrVNtmp arrVNPtmp(2) = arrVtmp(2) arrVC(arrFV(j)(k)) = arrVC(arrFV(j)(k)) + 1 ‘calc angle Dim angle angle = 90-Rhino.Angle2(array(arrVtmp,arrVNtmp),array(arrVtmp,arrVN Ptmp))(0) angle = Rhino.ToRadians(angle) angle = rad2Slope(angle) ‘add up value Dim arrColor arrColor = calcColor(angle) arrVCRGB(arrFV(j)(k))(0) = arrVCRGB(arrFV(j)(k))(0) + arrColor(0) arrVCRGB(arrFV(j)(k))(1) = arrVCRGB(arrFV(j)(k))(1) + arrColor(1) arrVCRGB(arrFV(j)(k))(2) = arrVCRGB(arrFV(j)(k))(2) + arrColor(2) Next Next ‘Divide values Dim finalColorArray ReDim finalColorArray(nrVC) For i = 0 To Ubound (arrVCRGB) If arrVC(i)>0 Then arrVCRGB(i) = Rhino.VectorScale(arrVCRGB(i),1/arrVC(i)) End If finalColorArray(i) = RGB(arrVCRGB(i)(0),arrVCRGB(i)(1),arrVCRGB(i)(2)) Next ‘Change mesh color Rhino.MeshVertexColors strMesh,finalColorArray End Sub Function rad2Slope (radians) rad2Slope = Rhino.TanH(radians) End Function Function calcColor(angle) If angle <= 0.17183 Then calcColor = array(0,150,0) End If If 0.17183 < angle And angle <= 0.34334 Then calcColor = array(145,255,0) End If If 0.34334 < angle And angle <= 0.45739 Then calcColor = array(255,255,0) End If If 0.45739 < angle And angle <= 0.68428 Then calcColor = array(255,145,0) End If If angle > 0.68428 Then calcColor = array(255,0,0) End If End Function

[ 54 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

Un vistazo rápido al script permite ver que está divido en 3 partes: - Subrutina principal, desde donde se ejecutan las diferentes funciones - Función rad2Slope, que calcula la correspondencia en tanto por ciento de in ángulo medido en radianes - Función calcColor, que calcula los valores RGB de color en función del ángulo. Puedes cambiar dichos valores en las líneas correspondientes. Echemos un vistazo rápido al código:

6-74 7 10 14-16 18-20

22-26 28-31 33

36-60

36 37 38 39 40 41 42 44 48

49 50 51 54 55 56-58 63 64 65-70 73

[ 55 ]

Subrutina principal: en ésta se obtienen todos los objetos e inputs necesarios Obtención del objeto malla por el usuario Obtención del número de vértices de la malla Declaración de las variables que contienen las normales de los vértices y los vértices de la malla [ambos son arrays de arrays de [x,y,z]. Cálculo de la proyección zobre el plano Z=0 de las normales de los vértices. Esto nos permitirá calcular el ángulo de la normal respecto al plano horizontal para la asignación de color posterior. Como cada vértice comparte más de una cara [excepto los vértices que formen el borde de la malla], deberemos obtener varias normales, y la media entre ellas. Esto lo haremos teniendo en cuenta las veces que cada vértice ha sido incluido en un cálculo de color. Guardado en una matriz de cuántas veces se ha accedido a un vértice concreto de la malla, así como de su color “acumulado”. Al terminar, haremos la media del color con el número de veces que se haya “visitado” cada vértice. Inicialización de la matriz de colores, con valores 0,0,0 para Red, Green y Blue [RGB] Acceso a las caras de la malla. La información que contienen éstas son los índices de los vértices que se han guardado en la variable arrV, que almacena todas las coordenadas de los vértices de manera ordenada. Explicaremos la tpología de las mallas posteriormente. Todo el truco, realmente, está en estas líneas, veamos detenidamente: en primer lugar, es necesario acceder a cada cara de la malla, y para cada cara a cada vértice. En cada vértice calcularemos su normal, su normal proyectada [que ya tenemos guardadas], así como el ángulo ente ellas. Con este ángulo calcularemos el color correspondiente y lo añadiremos al color “acumulado” de cada vértice. Para cada vértice, aumentaremos su número de “visitas” en 1, con el fin de calcular finalmente la media de color acumulado con todas las visitas: - Loop a lo largo de todas las caras - Loop para todos los vértices de cada cara: · Declaración de las variables que van a albergar temporalmente los siguientes valores: x,y,z del vértice; x,y,z de la normal del vértice; x,y,z de la proyección de la normal del vértice · Obtención del valor correspondiente a las coordenadas del vértice · Obtención del valor correspondiente a las coordenadas del vector normal al vértice · Desplazamiento del vector normal a su “situación real”. Recuerda que los vectores están basados, por defecto, en (0,0,0). · Obtención del valor del vector normal proyectado. Inicialmente será igual que el normal, pero con su coordenada z a la misma altura que el punto base del vector normal. · Asignación de la coordenada z del vector proyectado para ponerla a la misma altura que la coordenada z del vértice [punto de aplicación del vector normal]. · Declaración de la variable ángulo, que guardará el ángulo incialmente en grados [49], luego en radianes [50] y finalmente en tanto por uno [51], según vayamos usando las funciones de transformación correspondientes. · Cálculo del ángulo entre el vector normal y su proyección · Transformación del ángulo a radianes · Transformación del ángulo de radianes a tanto por uno: llamada a la función rad2Slope de las líneas 76-78. · Declaración de la variable color, para sumarla al total en RGB · Cálculo del color a partir del ángulo en tanto por uno. Llamada a la función calcColor de las líneas 80-98. · Asignacion de los valores RGB. Fin de los loops. Una vez tenemos todos los valores acumulados, podemos proceder a calcular las medias. Esto es sencillo, y podemos hacerlo con un loop sobre todos los vértices de la malla. Declaración de la variable finalColorArray, que albergará los colores definitivos. Dimensionar la matriz con el número de vértices. Estructura de loop: asignación de los colores. Finalmente, asignar la matriz de colores a la malla.


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

5. Topología de las mallas: una explicación sencilla

Array de vértices

Array de caras

0 1 2 3 . . . . . . . . N

0 1 2 3 . . . M

(x0,y0,z0) (x1,y1,z1) (x2,y2,z2) (x3,y3,z3) . . . . . . . . (xN,yN,zN)

(M0,M0,M0) (M1,M1,M1) (M2,M2,M2) (M3,M3,M3) . . . (NM,NM,NM)

Ejemplo CARA 92

VÉRTICES [INDICES]

VÉRTICES [COORDENADAS]

32

(x32,y32,z32)

29

(x29,y29,z29)

55

(x55,y55,z55)

[Fig 7. Topología de una malla con el ejemplo de una cara]

La topología de las mallas es realmente sencilla: se trata de dos matrices independientes. - Por un lado, la matriz que alberga los vértices [puntos en el espacio] - Por otro, una matriz que alberga índices, que corresponden a aquéllos de la anterior. De esta manera, para cada cara se establece una correspondencia ente los índices de los vértices y dichos puntos, definiendo cada cara. Así, la malla es un conjunto de caras, que no son más que unas referencias a la nube de puntos. Esta estructura evita la repetición de puntos innecesaria, puesto que la mayoría de vértices son compartidos por varias caras.

[ 56 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 57 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

CONCLUSIONES

[ 58 ]


[ 59 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

El manual permite un conocimiento profundo de la herramienta de diseño. Sin embargo, el mayor énfasis se ha puesto en la aplicación de la misma a la metodología, creando un ambiente híbrido que busca, a través de una cierta confusión inicial, la inmersión efectiva en procesos reales de diseño. Partiendo de una introducción básica a la herramienta, el manual comienza rápidamente a ganar en complejidad, tocando puntos de modelado en 2 y 3 dimensiones, representación y diagramática de proyectos, así como asuntos de presentación y comunicación de los mismos. Finalmente, se hace una introducción a las potencialidades del diseño algorítmico a través de scripting [una vertiente relativamente desconocida pero que ofrece muchas posibilidades], en la que se tocan puntos de recursividad, animaciones, exportación de archivos a Excel y otros formatos, y personalización de la interfaz. Así pues, el manual es un compendio eficiente y sugerente de métodos que pueden aplicarse por arquitectos, diseñadores, gestores de obra y proyectos, en todas las fases del mismo, desde su concepción, promoción y construcción, hasta la gestión posterior del mismo.

[ 60 ]


ETSAM - DELEGACION ALUMNOS DISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCION

ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 61 ]

RhinoScript  

RhinoScript manual for beginners that includes a comprehensive introduction to NURBS geometry and surface evaluation

Read more
Read more
Similar to
Popular now
Just for you