RhinoScript

61
INTRODUCCIÓN A PROGRAMACIÓN, DISEÑO ALGORÍTMICO Y AUTOMATIZACIÓN DE PROCESOS ETSAM / DELEGACION DE ALUMNOS DISEÑO PARAMETRICO Y ALGORITMICO PROFESOR ADOLFO NADAL SERRANO

description

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

Transcript of RhinoScript

Page 1: RhinoScript

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

ETSAM / DELEGACION DE ALUMNOSDISEÑO PARAMETRICO Y ALGORITMICO

PROFESOR ADOLFO NADAL SERRANO

Page 2: RhinoScript

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 pue-da inventar, puede explorar relaciones muy rápida y sistemáticamente de acuerdo a reglas preesta-blecidas. 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 funcionalida-des a sus productos.

De este modo, estos continuos avances permiten conceptualizar mejor los diseños, estimular y predecir el compor-tamiento 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, venta-nas, 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 valora-ció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 interme-dia 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.

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 2 ]

Page 3: RhinoScript

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 3 ]

Page 4: RhinoScript

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

[ 4 ]

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

Page 5: RhinoScript

[ 5 ]

Page 6: RhinoScript

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 or-denador. 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 re-quieren mucho esfuerzo o tiempo y que pueden automatizarse (por ejemplo, una secuencia de acciones que abre una ima-gen, 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 flexi-bilidad, pero también mayor riesgo de error. Los scripts son, en lo que a nosotros nos concierne, el siguiente paso en la “inte-ligencia” 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 se-cuencia 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 enten-der 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 (es-caló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 ho-ras 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 secuen-cia de órdenes predeterminadas que el programa ejecuta.

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 6 ]

Page 7: RhinoScript

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 accesi-ble 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 sen-cillas de sintaxis [puedes ver un listado completo en ingés en http://www.rhino3d.com/4/help/information/rhino_scripting.htm]:

Y aquí podemos analizar nuestra pequeña macro:

Código

! _Copy _pause0,0,00,0,1_enter

_selLast

_rotate _pause0,0,010_enter

Linea

1234567891011

Explicación

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

Seleccionar último objeto creado

Comando rotar con espera para intervención de usuarioPunto para el eje de rotaciónÁngulo de rotaciónFinalizar Comando

[Fig 1. Escalera creada con macro]

Nombre

Guión

Guión Bajo

Signo exclamaciónPunto y comaBarra invertida

Pause

Menor que

Símbolo

-

_

!; \

Pausewr<

Explicación

Cancela la aparición de ventanas asociadas a comandos. Todos los comandos pueden, además, escribirse o lla-marse 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 rhinoSi el comando no comienza por “!” y termina con la barra invertida “\”, la macro se ejecutará en la línea de coman-dos 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.

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 7 ]

Page 8: RhinoScript

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 diferen-tes 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.

En el espacio reservado para el comando del botón izquierdo del ratón pega el conjunto de órdenes que hemos des-crito 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-

Menu Emergente

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

[Fig 2. Menú Editar/Mover]

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

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 8 ]

Page 9: RhinoScript

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 con-dicionantes, 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 noso-tros. 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ál-culos 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 varia-bles, 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 nom-bre 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 obtendre-mos 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.

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 9 ]

Page 10: RhinoScript

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.

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 eje-cució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 al-gunNumero. 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é”.

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

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 10 ]

Page 11: RhinoScript

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 determi-nará 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 = “Presi-dente”, 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 conjun-tos 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” sola-mente], 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 capa-ces 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 esta-do, 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 modifi-car 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:

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 11 ]

Page 12: RhinoScript

Option ExplicitCall Main()Sub Main()

Dim algunNumeroDim otroumero

algunNumero = 90otroNumero = Rhino.Sin(algunNumero)

Rhino.Print algunNumeroRhino.print otroNumero

otroNumero = otroNumero +10Rhino.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 sim-ple, 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 correc-tamente] 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 coman-do _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 termi-nado 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 re-solver 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 hu-mano. Verás además, que las palabras contenidas entre comillas [“...”], son consideradas cadenas de caracteres literales.

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 12 ]

Page 13: RhinoScript

Fíjate en la descripción del script línea por línea para entender exactamente qué ocurre.

Option Explicit‘Comentarios‘Aquí declaración de variables globales, si procede

‘Llamada a la subrutina principalCall Main()

‘Comienzo de la subrutina principalSub Main()

‘Órdenes en secuencia‘Uso de un métodoRhino.EnableRedraw(False)‘Llamada a funciones personalizadasCall DoSinglePointCall DoPointGrid‘Uso de métodoRhino.EnableRedraw(True)

End Sub‘Fin de subrutina

‘Comienzo de una funciónFunction DoSinglePoint

‘Órdenes en secuencia, incluyen métodos y otrosRhino.AddPoint(array(0,0,0))

End Function‘Fin de la función

‘Comienzo de una funciónFunction 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 valueDim i, jDim maxX : maxX = 9Dim maxY : maxY = 9For i =0 To maxXFor j=0 To maxYRhino.AddPoint(array(i,j,0))NextNext

End Function

‘Fin de la función

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 principalComienzo 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]

12345678910111213141516171819202122232425262728293031323334353637383940414243

1 -5

69

1214

15172224252934 -3637-4142

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 13 ]

Page 14: RhinoScript

II. PROGRAMACIÓN Y TOPOLOGÍA 1. CodeMonkey Code Monkey [vulgarmente “monkey”] es actualmente el mejor editor de scripts para Rhino. Incluye el editor, compila-dor 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 en-contrar 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 explica-tiva, 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 cade-na 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]

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 14 ]

Page 15: RhinoScript

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 princi-pales, 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”.

Crear nuevo script

Abrir script

Guardar scriptGuardar scripts activos en pestañas

Guardar como...

Ejecutar scriptCorregir script

Colocar punto de análisis

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

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

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 15 ]

Page 16: RhinoScript

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 corres-ponden 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 10 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 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.]

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 16 ]

Page 17: RhinoScript

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 basa-das 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 determi-nado, y que sus ecuaciones, a las que no podemos acceder, son más complejas. Sin embargo, existe una clara corresponden-cia entre dichos valores y la curva, que podemos ver en la figura 12.

- Puntos de control: puntos que definen el polígono de control, a partir del cual se define, en función del tipo de conti-nuidad [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 Geo-metrí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 “des-activar” los sucesivos pasos a medida que vas avanzando. Te recomiendo que borres los objetos creados en cada uno antes

dom(1)valor máximo dominio

dom(0)valor mínimo dominio

dom(0)+4*step

dom(0)+5*step

dom(0)+6*step

dom(0)+7*step

dom(0)+3*step

dom(0)+2*step

dom(0)+1*step

P0

P1

P2

P3

P4

P5

P6

P7

P8

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

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 17 ]

Page 18: RhinoScript

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 eje-cutar una única función descoméntala, y comenta el resto. Haz esto con cada una de las funciones cambiando los valores. Do-PointGrid 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 debe-mos 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 seleccio-nada por el usuario. Veremos más sobre curvas en el siguiente apartado.

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 18 ]

Page 19: RhinoScript

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 capabilitiesCall Main()Sub Main()

Rhino.EnableRedraw(False)‘Call DoSinglePoint‘Call DoSinglePointWithAnnotation‘Call DoPointGrid‘Call DoPointGridWithHeight‘Call DoLine‘Call DoLines‘Call DoLineGrid‘Call DoSimpleComponentGrid‘Call DoComplexComponentGridCall DoLoftSurface‘Call DoComplexComponentGridWithLoftSurfaceRhino.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 keywordDim ptpt = (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 valueDim i, jDim maxX : maxX = 9Dim maxY : maxY = 9For i =0 To maxXFor j=0 To maxYRhino.AddPoint(array(i,j,0))NextNext

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 valueDim i, jDim maxX : maxX = 9Dim maxY : maxY = 9

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 19 ]

Page 20: RhinoScript

For i =0 To maxXFor j=0 To maxYRhino.AddPoint(array(i,j,i*j))NextNext

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 DoLinesDim i, jDim maxX : maxX = 9Dim 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-1For i=1 To maxXFor j=1 To maxYCall Rhino.AddLine(array(i-1,j-1,0),array(i,j,0))NextNext

End Function

Function DoLineGridDim i, jDim maxX : maxX = 9Dim 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-1For i=1 To maxXFor j=1 To maxYCall Rhino.AddLine(array(i-1,j,0),array(i,j,0))Call Rhino.AddLine(array(i,j-1,0),array(i,j,0))NextNext

End Function

Function DoSimpleComponentGridDim i, jDim maxX : maxX = 9Dim maxY : maxY = 9Dim 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 wellFor i=1 To maxXFor j=1 To maxYpt1 = 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))NextNext

End Function

Function DoComplexComponentGridDim i, jDim maxX : maxX = 9Dim maxY : maxY = 9Dim 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

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 20 ]

Page 21: RhinoScript

‘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 varia-bles that we can use later onFor i=1 To maxXFor j=1 To maxYpt1 = 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))NextNext

End Function

Function DoLoftSurface‘A loft surface takes at least 2 curves‘We need to create these and STORE them for future useDim curve1, curve2curve1 = 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 = 10Dim domainStepSize : domainStepSize = domain/nrStepsDim iFor i= crvDomain(0) To crvDomain(1) Step domainStepSizeDim arrPt : arrPt = Rhino.EvaluateCurve(strCrv,i)Rhino.AddPoint arrPtNext

End Function

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 21 ]

Page 22: RhinoScript

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

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 22 ]

Page 23: RhinoScript

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 23 ]

Page 24: RhinoScript

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

[ 24 ]

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

Page 25: RhinoScript

[ 25 ]

Page 26: RhinoScript

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 cur-vas 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 (normal-mente “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.

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)]

CURVE OBJECTMAIN 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 (0)<CRV DOMAIN (X)<...<CRV DOMAIN (Z)<CRV DOMAIN (1)

CRV DOMAIN (0)

CRV DOMAIN (X)

CRV DOMAIN (Y) CRV DOMAIN (Z)

CRV DOMAIN (1)[Fig 1. Dominio de una curva]

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 26 ]

Page 27: RhinoScript

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 pun-tos 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 facha-das estructurales. La edición de las curvas se realiza, como hemos dicho, a partir de sus puntos de control, fácilmente accesi-bles tanto explícitamente [modelando] como implícitamente [a partir de RhinoScript].

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 27 ]

Page 28: RhinoScript

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.

Curva por puntos de control

Activar puntos de controlActivar puntos de edición/desactivar seleccionados

Insertar/Eliminar puntos de control

Simpli�car

Ocultar caras posteriores de polígono de control

De�nir peso de puntos de controlEliminar nodo

Añadir nodoEditar con manejadores

Cambiar modo de arrastre

Mover UVN, toque ligero UVNInsertar nodo/punto de edición

Cerrar curvas abiertasEliminar subcurva

Extraer subcurva

SubcurvaInsertar línea en curva

Booleana de curvas

Curva por interpolaciónCurva por interpolación en super�ciesCurva por manejadoresTrazarTrazar sobre malla

Extender/Empalmar/Acha�anar línea

Cónicas y parábolasHélice y espiral

Curvas promedio

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

[Fig 3. Dirección en una superficie]

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 28 ]

Page 29: RhinoScript

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, median-te 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 espa-cio 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 resultan-tes 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 por-centaje 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]

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 29 ]

Page 30: RhinoScript

4. Creación de superficies, puntos y nubes de puntos, curvas

- 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 di-chos 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 auto-má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, calcu-lando 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.

Superficie por 3 ó 4 puntosFILA 1

FILA 2

FILA 3

Superficie por curvas de bordeSuperficie a partir de curvas planasSuperficie rectangularExtruir curva

Loft - transiciónSuperficie por network de curvasSuperficie parcheSweep 1/2 railes

Superficie de revoluciónCubrir objetos con superficieMapa de alturas desde imagenSuperficie desde rejilla de puntos

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

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 30 ]

Page 31: RhinoScript

- DoSinglePointWithNormal y DoSinglePointWithNormalScaled crea, además del punto anterior, otro en la nor-mal 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, de-bermos 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 resul-tante 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.VectorS-cale (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.Vecto-rAdd (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.

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 31 ]

Page 32: RhinoScript

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.2Call 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 VDim 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 surfaceDim arrPt : arrPt = Rhino.EvaluateSurface(strSrf,array((maxUDomain+minUDomain)/2,(minVDomain+maxVDomain)/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 VDim 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 surfaceDim arrPt : arrPt = Rhino.EvaluateSurface(strSrf,array((maxUDomain+minUDomain)/2,(minVDomain+maxVDomain)/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+maxVDomain)/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 VDim Udomain : Udomain = Rhino.SurfaceDomain(strSrf,0)Dim Vdomain : Vdomain = Rhino.SurfaceDomain(strSrf,1)

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 32 ]

Page 33: RhinoScript

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 surfaceDim arrPt : arrPt = Rhino.EvaluateSurface(strSrf,array((maxUDomain+minUDomain)/2,(minVDomain+maxVDomain)/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+maxVDomain)/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 ASKarrNormalPt = Rhino.VectorScale(arrNormalPt,scaleFactor)‘As all other vectors, it is STILL -despite the scaling!!!- based on (0,0,0), so we need to “transla-te” 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 VDim 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 INFODim srfUDomain : srfUDomain = maxUDomain-minUDomainDim srfVDomain : srfVDomain = maxVDomain-minVDomain‘Let us decide how many “divisions” we need in each directionDim nrUSteps : nrUSteps = 5Dim domainUStepSize : domainUStepSize = srfUDomain/nrUStepsDim nrVSteps : nrVSteps = 5Dim 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, jFor i= minUDomain To maxUDomain Step domainUStepSizeFor j= minVDomain To maxVDomain Step domainVStepSizeDim arrPt : arrPt = Rhino.EvaluateSurface(strSrf,array(i,j))Rhino.AddPoint arrPtNextNext

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 VDim 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 INFODim srfUDomain : srfUDomain = maxUDomain-minUDomainDim srfVDomain : srfVDomain = maxVDomain-minVDomain

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 33 ]

Page 34: RhinoScript

‘Let us decide how many “divisions” we need in each directionDim nrUSteps : nrUSteps = 5Dim domainUStepSize : domainUStepSize = srfUDomain/nrUStepsDim nrVSteps : nrVSteps = 5Dim 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, jFor i= minUDomain To maxUDomain Step domainUStepSizeFor j= minVDomain To maxVDomain Step domainVStepSizeDim arrPt : arrPt = Rhino.EvaluateSurface(strSrf,array(i,j))Rhino.AddPoint arrPtDim 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)NextNext

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 VDim 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 INFODim srfUDomain : srfUDomain = maxUDomain-minUDomainDim srfVDomain : srfVDomain = maxVDomain-minVDomain‘Let us decide how many “divisions” we need in each directionDim nrUSteps : nrUSteps = 5Dim domainUStepSize : domainUStepSize = srfUDomain/nrUStepsDim nrVSteps : nrVSteps = 5Dim 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, jFor i= minUDomain To maxUDomain Step domainUStepSizeFor j= minVDomain To maxVDomain Step domainVStepSizeDim arrPt : arrPt = Rhino.EvaluateSurface(strSrf,array(i,j))Rhino.AddPoint arrPtDim srfFrame : srfFrame = Rhino.SurfaceFrame (strSrf, array(i,j))Dim arrNormalPt : arrNormalPt = srfFrame(3)‘Remember to scale before the addition takes placearrNormalPt = Rhino.VectorScale(arrNormalPt,scaleFactor)arrNormalPt = Rhino.VectorAdd(arrPt,arrNormalPt)Dim strNormalPt : strNormalPt = Rhino.AddPoint(arrNormalPt)Call Rhino.ObjectColor(strNormalPt,vbBlue)NextNext

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

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 34 ]

Page 35: RhinoScript

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 35 ]

Page 36: RhinoScript

SUPERFICIES Y COMPONENTESdiseño paramétrico con scripting

[ 36 ]

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

Page 37: RhinoScript

[ 37 ]

Page 38: RhinoScript

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 dependen-cia 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 animacio-nes 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-

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 38 ]

Page 39: RhinoScript

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.

Aun a riesgo de ser excesivamente insistentes, incluyo otro ejemplo del uso del método Rhino. SurfaceDomain [recuer-da que el lenguaje natural para la programación es, por excelencia, el inglés]:

Const rhObjectSurface = 8Dim strObject, arrDomU, arrDomVstrObject = 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-

[Fig 2. Familia de componentes sobre una superficie]

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 39 ]

Page 40: RhinoScript

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 compo-nentes en función de la distancia a este punto]. En la línea 13 usamos el comando GetPoint que nos devuelve direcata-mente las coordenadas del punto. · El primer paso es subdividir la superficie en función de su dominio, por lo que deberemos tener en conside-ració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 compo-nente [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 lla-mando 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.

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))

12345678910111213141516171819202122232425262728293031323334353637383940414243

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 40 ]

Page 41: RhinoScript

‘-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 (strCrv2, arrFrPt(k-1,l-1)(0),array(dblDist/d,dblDist/d,dblDist/d)) Call Rhino.ScaleObject (strCrv4, arrFrPt(k-1,l-1)(0),array(dblDist/d,dblDist/d,dblDist/d)) Else Call Rhino.ScaleObject (strCrv2, arrFrPt(k-1,l-1)(0), array(0.9,0.9,0.9)) Call Rhino.ScaleObject (strCrv4, arrFrPt(k-1,l-1)(0), array(0.9,0.9,0.9)) End If

‘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.FirstObjectEnd Function

4445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 41 ]

Page 42: RhinoScript

INTRODUCCIÓN AL DISEÑO ALGORÍTMICO

[ 42 ]

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

Page 43: RhinoScript

[ 43 ]

Page 44: RhinoScript

GEOMETRÍA COMPUTACIONAL AVANZADA

I. INTRODUCCIÓN AL DISEÑO ALGORÍTMICO1. 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 de-terminada. 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 geome-trí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]

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 44 ]

Page 45: RhinoScript

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 usa-das en arquitectura y construcción, las cuales son restrictivas en su uso y posibilidades [y por tanto ejercen un papel homo-geneizante], el diseño algorítmico nos permite la creación de herramientas “ad-hoc”. Esta metodología permite crear herra-mientas 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.

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 ecua-ciones recursivas, de ahí su complejidad. Veamos el código que nos permite crear este tipo de geometría recursiva en Rhino.

1 -1 triangle 2 - 4 triangles 3 - 16 triangles

Option Explicit‘Script written by Adolfo Nadal‘Script by archi·o·logics www.archiologics.com

‘How to create a recursive sierpinski pyramidCall 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-------> UBOUNDuserLength=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, tetrah4Dim Curve0, Curve1, Curve2, Curve3, Curve4, Curve5, CurvesDim Srf0, Srf1, Srf2, Srf3, PolySurface, Surfaces, userLengthCurve0 = 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)

123456789101112131415161718192021222324252627

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

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 45 ]

Page 46: RhinoScript

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 surfacesPolySurface = 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 themCurves=array(Curve0, Curve1, Curve2, Curve3, Curve4, Curve5)Call Rhino.DeleteObjects(Curves)‘ if length less than x then do not subdivideIf (minLength > userLength) Then

‘--------------------------------------‘Surfaces=array(Srf0, Srf1, Srf2, Srf3)‘Call Rhino.DeleteObjects(Surfaces)‘--------------------------------------Call Rhino.DeleteObject(PolySurface)‘ get pointsvertexPts = 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 coor-dinatemidPt0 = 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 functionsubdivideTetrahedron tetrah0,userLengthsubdivideTetrahedron tetrah1,userLengthsubdivideTetrahedron tetrah2,userLengthsubdivideTetrahedron tetrah3,userLength

End IfEnd Function

282930313233343536373839404142434445464748495051525354555657585960616263646566676869

70

71

72

73

74

7576777879808182838485

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 46 ]

Page 47: RhinoScript

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.

Aunque está perfectamente comentado, vamos a ver brevemente las partes más relevantes del código:

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án-gulo 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.

BASE SURFACE

mid 1

mid 2

mid 3

SUBDIVISION ELEVATION

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 principalComienzo 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 nuevoCalcular 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

1 -5

6

9-1114

15

1821-2425-3031-3637-40425052-5355-90

556069-7475-7880-83

85

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

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 47 ]

Page 48: RhinoScript

Option Explicit‘Script written by Adolfo Nadal ‘Script by archi·o·logics www.archiologics.com

‘How to create a recursive structureCall recursiveExample()

Sub recursiveExample()Dim triangletriangle = Rhino.GetObject(“select your triangle”,8)‘ in brackets whatever you want Rhino to ask the userRhino.EnableRedraw FalsesubdivideTriangle(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, triangle3Dim 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 anythingRhino.SelectObject triangleRhino.Command(“_DupBorder enter”)triangleCrv = Rhino.FirstObjecttriangleLength = Rhino.CurveLength(triangleCrv)‘ the FIRST OBJECT COMMAND returns the LAST OBJECT CREATED BY THE USERIf(triangleLength > 10) Then

‘ centerptcenterPoint = CurveAreaCentroid(triangleCrv)‘ normalsrfParam = Rhino.SurfaceClosestPoint(triangle, centerPoint(0))srfNormal = Rhino.SurfaceNormal(triangle, srfParam)‘ get corners of each trianglevertexPts = Rhino.PolylineVertices(triangleCrv)‘ get midpoints of each edge‘ in the vertexPts the first () tells which point it is, the second the coordinatemidPt0 = 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 vectorsrfNormal = Rhino.VectorUnitize(srfNormal)srfNormal = Rhino.VectorScale(srfNormal, triangleLength*0.1)‘move midpoints by normalmidPt0 = 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 directiontriangle0 = 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 functionsubdivideTriangle(triangle0)subdivideTriangle(triangle1)subdivideTriangle(triangle2)

123456789101112131415161718192021222324252627282930313233343536373839404142

43

44

454647484950515253545556575859606162

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 48 ]

Page 49: RhinoScript

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 independiente-mente de su posición.

Aunque está perfectamente comentado, vamos a ver brevemente las partes más relevantes del código:

‘borrar el triángulo originalRhino.DeleteObjects Array(triangle, triangleCrv)

End IfEnd Function

63646566

Llamada a la subrutina principalObtenció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 triangularDuplicar el borde mediante acceso al comando de RhinoObtenció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] enton-ces 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ónFinalizar la función

61013172027-30272829

3032

3436373942-4447-4850-5255-5760-626466

[Fig 4. Resultado del fractal]

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 49 ]

Page 50: RhinoScript

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 prin-cipales 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.

Option Explicit‘Script written by Adolfo Nadal ‘Script by archi·o·logics www.archiologics.com

‘How to create an oriented sculptureCall 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)

1234567891011121314151617

1819202122

23

[Fig 5. Escultura automática]

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 50 ]

Page 51: RhinoScript

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

2425262728293031323334353637383940414243

44

45

46474849505152535455565758596061626364656667686970717273747576777879808182838485

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 51 ]

Page 52: RhinoScript

Adjuntamos de nuevo una breve descripción del código:

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 introduci-do 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 sustancial-mente la cantidad de geometría del modelo.

Subrutina principal: en ésta se obtienen todos los objetos e inputs necesariosComienzo de la función MakePyramidObtenció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 fun-ciones 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

8-1315-8517

20-27

30-34

36-39

42-4648-6065-71

73-788182-83

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 52 ]

Page 53: RhinoScript

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))

123456789101112131415161718192021222324252627282930313233343536373839

[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]

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 53 ]

Page 54: RhinoScript

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,arrVNPtmp))(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,finalColorArrayEnd 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

40414243444546474849

50515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 54 ]

Page 55: RhinoScript

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:Subrutina principal: en ésta se obtienen todos los objetos e inputs necesariosObtención del objeto malla por el usuarioObtención del número de vértices de la mallaDeclaració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 guarda-das], 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 de-fecto, en (0,0,0).· Obtención del valor del vector normal proyectado. Inicialmente será igual que el normal, pero con su coor-denada 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 correspon-dientes.· 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.

6-7471014-16

18-20

22-26

28-3133

36-60

363738

394041

42

44

48

495051545556-5863

6465-7073

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 55 ]

Page 56: RhinoScript

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

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, de-finiendo 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.

Array de vértices

0123........N

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

Array de caras Ejemplo

0123...M

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

CARA

92

VÉRTICES[INDICES]

32

29

55

VÉRTICES [COORDENADAS]

(x32,y32,z32)

(x29,y29,z29)

(x55,y55,z55)

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

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 56 ]

Page 57: RhinoScript

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 57 ]

Page 58: RhinoScript

CONCLUSIONES

[ 58 ]

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

Page 59: RhinoScript

[ 59 ]

Page 60: RhinoScript

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 presen-tació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.

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 60 ]

Page 61: RhinoScript

ETSAM - DELEGACION ALUMNOSDISEÑO PARAMÉTRICO Y ALGORITMICO - INTRODUCCIONADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS - ARCHIOLOGICS.COM

[ 61 ]