RHINO USER MEETING DAY RHINOSCRIPT - PYTHON | DISEÑO D ISEÑO ALGORÍTMICO ALGORÍTMICO
PROFESOR ADOLFO NADAL SERRANO
RHINO USER MEETING DAY RHINOSCRIPT - PYTHON
ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS
TOPOLOGÍA DE LA GEOMETRÍA NURBS [Non-Uniform Rational Bezier Splines]
RHINO USER MEETING DAY RHINOSCRIPT - PYTHON
ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS
TOPOLOGÍA DE LA GEOMETRÍA NURBS [Non-Uniform Rational Bezier Splines]
RHINO USER MEETING DAY RHINOSCRIPT - PYTHON
ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS
I. NOCIONES BÁSICAS DE PROGRAMACIÓN Aproximarse a la topología NURBS implica un conocimiento amplio de la descripción geométrica de los objetos a partir de fórmulas matemáticas y, de manera implícita, del comportamiento y descripción de las mismas en los entresijos del ordenador. Es, por tanto, imprescindible, iniciarse en el apasionante mundo de la programación, y, si bien no llegaremos a ser programadores profesionales, sí podremos entender y crear geometrías complejas a través de rutinas y “scripts”, pequeños programas hechos a medida que nos dan acceso directo al núcleo de Rhino, así como sus funciones y métodos. 1. Scripts, ejecución secuencial y programación orientada a objetos
Generalmente, la manera más sencilla de comenzar un código es mediante la utilización de “comandos” u “órdenes” dadas en una secuencia determinada. Podríamos decir que el modo más primitivo de escribir código es mediante macros, secuencias de órdenes ordenadas de una manera determinada y que siempre llevan a cabo la misma labor. Las macros no permiten interacción con el usuario y son bastante limitadas, si bien son muy útiles a la hora de abordar problemas que requieren mucho esfuerzo o tiempo y que pueden automatizarse (por ejemplo, una secuencia de acciones que abre una imagen, cambia su brillo y su opacidad, la recorta, y la vuelve a guardar). Todos los parámetros implicados en una macro deben estar predefinidos de antemano, no pudiendo dejar ni una sola variable sin determinar. En el ejemplo anterior, si quisiéramos cambiar el brillo de una imagen, debemos especificar exactamente el nuevo valor de brillo, así como, a la hora de recortarla, cuáles son los píxeles que definen el cuadro delimitador del corte. Un script, en cambio, permite cierta interacción con el ususario, así como el uso de variables. Esto implica mayor flexibilidad, pero también mayor riesgo de error. Los scripts son, en lo que a nosotros nos concierne, el siguiente paso en la “inteligencia” de la programación. Dedicaremos a continuación una buena parte de tiempo a describir y cualificar cómo escribir scripts y sus diferentes funcionalidades, desde la creación de geometrías complejas hasta la automatización de procesos de creación de planos para la fabricación, exportación de archivos y otras utilidades varias. Tanto las macros como los scripts, sin embargo, comparten una propiedad fundamental: ambos se basan en una secuencia de órdenes que el ordenador interpreta linealmente. La programación orientada a objetos permite la descripción de objetos [instancias de clases] mediante una serie de “características” [propiedades] y “comportamientos” [métodos], que son capaces de interactuar entre sí mediante una serie de reglas compartidas definidas a través de dichos comportamientos. Dicho paradigma excede el nivel que queremos alcanzar con el presente manual, por lo que lo dejaremos para ediciones posteriores. 2. Macros
Aunque no es el tema principal que nos ocupa, una leve introducción a las macros no hace mal, y nos ayudará a entender los conceptos básicos que hemos descrito anteriormente. Valga de ejemplo una escalera de caracol: para dibujar una escalera de caracol necesitaríamos repetir un objeto (escalón), copiarlo en altura, y rotarlo una serie de grados. Después, tendríamos que tomar el último elemento u objeto creado (es decir, el escalón que acabamos de copiar) y repetir la operación una serie de veces hasta que terminemos de rellenar el espacio necesario. Hacer esto a mano podría suponernos un buen rato de modelado, aburrido y tedioso. Podemos evitar innecesarias horas delante del monitor si somos capaces de describir [y posteriormente transcribir] las órdenes necesarias en una secuencia que el ordenador pueda entender. A saber: 1. Selecciona el escalón que quieras repetir 2. Copia dicho escalón 3. Mueve el escalón verticalmente una distancia establecida para la huella, por ejemplo: 15cm. 4. Rota el escalón un cierto ángulo (por ejemplo: 10º) alrededor de un eje (por ejemplo uno vertical en 0,0) Podríamos, además, implementar un último paso que repitiera el proceso una serie de veces, como por ejemplo 15,
RHINO USER MEETING DAY RHINOSCRIPT - PYTHON
ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI[O]LOGICS
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 R hino escritas de manera secuencial para crear una función automatizada. Así pues, es “scripting” en su nivel más bajo, y veremos que es accesible a cualquier usuario de Rhino, incluso si no tiene conocimientos de programación. Todo lo que necesitamos, como hemos dicho, es un conocimiento aceptable de Rhino, algo de experiencia en modelado, y cierto gusto por la experimentación. Para escribir una macro precisamos: - Nuestro propio interés - Los archivos de ayuda de Rhino, que describen todos los comandos así como sus opciones - Posiblemente el editor “MacroEditor”, que permite ejecutar y analizar nuestras macros. Aquí exponemos algunas de las claves que nos permiten comunicarnos con nuestra herramienta en forma de normas sencillas de sintaxis [puedes ver un listado completo en ingés en http://www.rhino3d.com/4/help/information/rhino_scripting. htm]: Símbolo Nombre
Explicación
-
Guión
_
Guión Bajo
! ; \
Signo exclamación Punto y coma Barra invertida
Pause w r <
Pause
Cancela la aparición de ventanas asociadas a comandos. Todos los comandos pueden, además, escribirse o llamarse mediante scripts, por lo que es una opción destacada a la hora de escribir los literales o “strings” [ya veremos lo que es ésto más adelante]. Ejecuta el comando en inglés. Necesario para que las macros sean ejecutables independientemente del idioma en el que estemos usando Rhino actualmente. Cancela los comandos en ejecución. Permite introducir un comentario, que no será leido por rhino Si el comando no comienza por “!” y termina con la barra invertida “\”, la macro se ejecutará en la línea de comandos sin pulsar enter, de manera que se puede introducir más información. Esto es útil para construir un comando a partir de dígitos, decimales, ángulos [tal como “<45”] y que se encuentran en botones, creando un “teclado numérico” en la pantalla. Para una macro para input de usuario. Usar coordenadas “World Coordinates” en vez de coordenadas del plano de trabajo. Las coordenadas relativas son relativas a la posición actual del cursor. Input de ángulo en grados.
Menor que
Y aquí podemos analizar nuestra pequeña macro: Linea
Código
Explicación
1 2 3 4 5 6 7 8 9 10 11
! _Copy _pause 0,0,0 0,0,1 _enter
Comando copia con espera para intervención de usuario [selección] Punto inicio [copia] Punto final [copia] Finalizar comando
_selLast
Seleccionar último objeto creado
_rotate _pause 0,0,0 10 _enter
Comando rotar con espera para intervención de usuario Punto para el eje de rotación Ángulo de rotación Finalizar Comando
RHINO USER MEETING DAY RHINOSCRIPT - PYTHON
ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS
3. ¿Dónde escribimos las macros?
Perfecto, sabemos escribir un ejemplo de macro, pero, ¿dónde la guardamos? La respuesta es muy sencilla: dado que una macro equivale, a efectos prácticos, a un comando, no hay mejor manera que asociarla a un botón. Aunque hay diferentes maneras de hacer esto, aquí explicaremos las más sencilla y directa. Manteniendo pulsada la tecla Shift mientras ponemos el cursor sobre cualquier botón nos permite Mover o Editar los botones [figura 2]. Edita el botón y aparecerá un menú como el de la figura 3. Menu Emergente
Mover/Editar (Shift+hover) Copiar/Vincular (Ctrl+hover)
[Fig 2. Menú Editar/Mover]
[Fig 3 Menú de edición de botones]
En el espacio reservado para el comando del botón izquierdo del ratón pega el conjunto de órdenes que hemos descrito para nuestra macro. Puedes cambiar la leyenda del mismo. Para guardar los cambios, acepta. Cuando cliques sobre el icono del botón, se ejecutará la macro. Puedes también editar el aspecto del botón, pero eso lo dejaremos para después, cuando tratemos la personalización de la interfaz. Puedes probar tus macros en el editor de macros. Dicho editor es, además, una herramienta útil para excribir macros y detectar posibles errores. Usa el comando “ejecutar” de la ventana de edición para probar tu código. 4. Variables y scripts
Una vez nos hemos familiarizado con el comportamiento básico de las macros, podemos empezar a pensar en sistemas
RHINO USER MEETING DAY RHINOSCRIPT - PYTHON
ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI[O]LOGICS
dos] y de modelado. Las limitaciones de las macros han dado lugar, por tanto, a los scripts, una suerte de lugar indefinido entre simples secuencias de órdenes y programas compilados. Así pues, las macros pueden realizar operaciones matemáticas, evaluar condicionantes, responder al entorno y comunicarse con el ususario. Rhinoceros, en su versión 4, implementa VBScript, lo que significa que aquello que es válido para VBScript, lo es también para RhinoScript. Rhinoceros v5 implementa además python, por lo que habrá que ir incorporando lentamente este lenguaje a nuestro día a día. “Traducir” RhinoScript en lenguaje natural [con el que nos comunicamos tú y yo] no debe ser muy complicado a este nivel. Inicialmente, los lenguajes de programación eran un conjunto de ceros y unos, que con el tiempo [el paso de generaciones de lenguajes en su sentido más estricto] se han conseguido hacer fácilmente entendibles para seres humanos. Las primeras generaciones de lenguaje “código máquina” son muy difíciles de entender, y no tienen cabida entre la mayoría de nosotros. Afortunadamente, se ha evolucionado en los sucesivos desarrollos generacionales hacia una mayor encapsulación que abriese el marco de la programación a gente no necesariamente iniciada. Por ejemplo, es posible que queramos guardar unas curvas de nuestro modelo en 3D para modificarlas o borrarlas posteriormente, o tal vez necesitemos conocer la fecha para saber si el software ha expirado; ninguno de estos datos está disponible cuando se ha escrito el script y serán sólamente accesibles a través de variables. Pero volviendo a lo que nos ocupa, sabemos que a menudo necesitamos almacenar información para realizar los cálculos que nos lleven, poco a poco, a la resolución de problemas complejos. Dichos cálculos forman parte de un todo que podemos denominar algoritmo: una secuencia de órdenes determinada, que en un tiempo finito, da un resultado concreto y correcto. El almacenamiento de información para su uso en los algoritmos se puede [y debe] llevar a cabo mediante variables, contenedores de información que constan básicamente de: - Nombre: El nombre es un dato simbólico que se refiere a información almacenada en memoria. Dicho nombre puede ser cualquiera en rVB, con las siguientes salvedades: · Comenzará por carácter alfabético · Contendrá menos de 255 caracteres · No se permiten espacios en blanco, puntos, ni caracteres especiales (!,”, : ; , ...) · No pueden emplearse palabras reservadas del lenguaje - Tipo: indica el tipo de información que almacena una variable. Por ejemplo, y sin entrar en mas detalles, las variables Single y Double pueden ocupar números reales muy grandes. Además, hay otro tipo de variables, las denominadas variant , que son como una variable estándar que “admite cualquier tipo de dato.” - Alcance [“tiempo de vida”]: · Global: para variables declaradas fuera de funciones y subrutinas y accesibles desde cualquier parte del código. · Local: variables declaradas dentro de funciones y subrutinas, no se podrá tener acceso a ellas desde otra parte del código. Esto es, si declaro una variable dentro de una función, solamente podré acceder a ella mientras me encuentre en la función. Si quiero, posteriormente, usar el valor de la misma, deberé pasarla como referencia bien como valor. algunNumero = RhinoScriptSyntax.GetInteger(“Introduce un número”,0,50,100)
En este ejemplo, “algunNumero” es sencillamente un “placeholder” para un valor determinado, que obtendremos cuando se ejecute el script [en tiempo de ejecución]. Está claro que, cuando estamos escribiendo el script no conocemos el valor de la variable. Fíjate además que el nombre de la variable algunNumero no tiene tilde, ya que sería considerado un carácter
RHINO USER MEETING DAY RHINOSCRIPT - PYTHON
ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS
El uso de las variables debe incluir tres pasos: - Declarar y comentar la variable [esto puede hacerse o no, en función del alcance de la misma]. - Inicializar la variable [asignar un valor inicial] - Programar las debidas instrucciones. Tipo
Tamaño
Rango
Boolean Byte Integer Long Single Double Carácter String Date
1 Bit Entero Corto: 1 Byte Entero: 2 Bytes Entero: 4 Bytes Real Simple Precisión: 4 bytes Real Doble Precisión 1 Byte Cadena de caracteres Fecha
True/False De -128 a 127 De -32768 a 32767 De -232/2 a (232/2-1) Real Real De -128 a 127 Texto 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. Python, al contrario que vbScript, nos dota de un sistema potente y bastante útil para lidiar con este asunto. Tanto los “tuples” como las “listas” son estructuras de información capaces de agrupar variables; puedes pensar en ellas como “contenedores” de información, una especie de bandeja donde podemos colocar los platos de una buena comida.
[Fig 4. Ejemplos cotidianos de arrays: una granja solar, un contenedor]
5. Declaración e inicialización de variables en rVB y Python
De igual manera que tu interlocutor te preguntará quién es Pepe a tu afirmación “ayer fui al cine con Pepe”, si no le conoce, RhinoScript solicita saber con quién está tratando, es decir, requiere saber qué variables vas a utilizar durante la ejecución del script. Si bien esto es cierto para scripts escritos con VB, python es más directo y admite la declaración e inicicalización simultánea de variables. Generalmente es necesario y suficiente “presentar” [declarar] una variable antes de usarla, es decir, valdría con afirmar “Pepe es un amigo”. En rVB se declaran las variables utilizando la palabra reservada Dim, de la siguiente manera: Dim nombreVar
Dim algunNumero Esto es todo lo que necesitamos hacer para hacer saber a Rhino que vamos a utilizar una variable cuyo nombre es algunNumero. Para arrays, esto funciona exactamente igual, ya que se comportan como una variable: Dim nombreArr
Dim conjuntoNumeros En python, sin embargo, podemos declarar las variables al mismo tiempo que las usamos, según asignamos valores (es decir según inicializamos las variables). Python, además, distingue entre listas, tuples, y variables. Tanto las listas como los
RHINO USER MEETING DAY RHINOSCRIPT - PYTHON
ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI[O]LOGICS
De este modo, el equivalente a lo visto anteriormente en Python sería: nombreVar = valorVar algunNumero = 25 Queda patente que la declaración e inicialización de la variable se hacen de manera simultánea. Asimismo, veremos que se puede comenzar por el valor None, una especie de “Ninguno”, una manera de decir que la variable no tiene contenido. De este modo podemos declarar una variable sin valor, y asignarle un valor posteriormente. Además, este “no valor” None es el que devuelven las funciones de RhinoScript cuando fallan. Es la manera que tiene Rhino de decirnos “no lo sé”. algunNumero = None ... algunNumero = 25 La asignación del valor se hace mediante el símbolo “=”, que asigna el valor de la derecha al elemento que se encuentre a su izquierda. Así pues a=1, asigna el valor 1 a la variable de nombre “a”. El tipo de valor que asignemos a la variable determinará el tipo de la variable, de manera que si asignamos un número la variable tendrá carácter numérico, y si asignamos, por ejemplo, una cadena de caracteres, tendrá tipo “String”. El nombre de la variable hace que podamos entender lo que ésta contiene. Podríamos asignar algunNumero = “Presidente”, y RhinoScript lo entendería perfectamente. Sin embargo, nos llevaría a error con absoluta seguridad. Esta asignación se vuelve ligeramente más compleja cuando tratamos con listas. Las listas, como hemos dicho anteriormente, son conjuntos de elementos, por lo que habrá que asignar un conjunto como valor inicial: conjuntoNumeros = [ ] #esto indica que el conjunto está vacío conjuntoNumeros = [val1,val2,val3,val4,val5]
Una vez más, el nombre es independiente de los valores que contiene la variable [esto es, es para “uso humano” solamente], por lo que es más que recomendable tener un nombre descriptivo, sencillo de recordar, y corto, para evitar errores de tipografía. 6. Asignación de valores
Al igual que para inicializar variables, la asignación de valores hace uso del símbolo “=”, y funciona de la misma manera. Durante la ejecución del script podemos cambiar el tipo de valor que almacena la variable, pero esto no es recomendable por coherencia y claridad. además, los seres humanos tenemos muy mala memoria, está casi garanztizado que no seremos capaces de recordar la razón por la que hicimos esto o lo otro dos días después de haberlo hecho, así que es una buena práctica mantener una coherencia en todo el código. 7. Obtención/acceso de valores; cambio de los mismos.
Necesariamente, si almacenamos información, necesitaremos acceder a ella, tal vez únicamente para conocer su estado, tal vez para modificarla o hacer algún tipo de tarea. La manera de acceder a la inormación es tan sencilla como escribir lo siguiente: queNumero = algunNumero O, por ejemplo, imprimir su valor en la pantalla (línea de comandos) print algunNumero
RHINO USER MEETING DAY RHINOSCRIPT - PYTHON
ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS
otroNumero = math.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: import rhinoscriptsyntax as rss def simpleOperation(): algunNumero = None otroNumero = None algunNumero = 90 otroNumero = math.sin(algunNumero) print algunNumero print otroNumero otroNumero = otroNumero +10 print otroNumero return call simpleOperation()
8. Estructura del código
Acabas de ver [¡y escribir!] posiblemente tu primer script, ¡enhorabuna! Verás que la estructura del código es muy simple, y consta esencialmente, de las siguientes partes reconocibles a simple vista: · importación de rhinoscriptsyntax · declaración de variables globales [ya lo veremos en un futuro...] · declaración de funciones mediante la palabra reservada def ····bloques de código de función [indentado] · llamadas a dichas funciones con la palabra “call” 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. La importación, por ejemplo, nos permite acceder a funciones nativas de Rhinoscript de manera sencilla. Estas funciones son preexistentes y se denominan métodos. 9. Funciones y subrutinas
Todo lo que debes saber de funciones y subrutinas es que son bloques de código con un nombre asignado [de manera que puedas “llamarlas” o usarlas cuando lo necesites], una serie de “argumentos” [datos que necesitan para ejecutar correctamente] y un resultado, que puedes decidir pasar o no.Ya ahondaremos en este tema al tiempo que comencemos a escribir scripts más complejos. Recuerda: - Las subrutinas son bloques de código que expresan la secuencia de ejecución del programa. Deben ser llamadas desde fuera y tienen la capacidad de llamar asimismo a otras subrutinas y funciones. - Las funciones bloques de código, grupos de órdenes en secuencia que se agrupan por su lógica. Cada función debe tener una única finalidad. Las funciones, si están debidamente escritas, podrán reutilizarse para varios códigos.
RHINO USER MEETING DAY RHINOSCRIPT - PYTHON
ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI[O]LOGICS
10. Ejemplo de código:
Puedes comenzar a escribir el siguiente script en el editor de scripts de Rhino, que puedes ejecutar mediante el comando _EditScript. Por defecto, a partir de la versión 5.0 de Rhino, el editor de Scripts será Monkey. El script crea una serie de puntos en el modelo tridimensional de Rhino que tengas abierto. Verás que, una vez terminado el script, estos objetos son una parte más del mismo, y que podrás transformarlos, editarlos, o borrarlos a tu antojo. Procura copiar el script exactamente como se escribe; de otro modo podrías tener problemas de sintaxis con los que es más que probable que no estés familiarizado, por lo que podrías bloquearte. Recuerda, es mala idea generalmente tratar de resolver problemas relacionados con estos asuntos durante más de 30-60 minutos sin consultar la ayuda de una persona más experta. Se trata de aprender, no de desesperar. Verás que al copiar el código en tu editor de scripts, algunas palabras cambian de color, son palabras reservadas de python. Aquellas líneas precedidas de # [almohadilla] son comentarios, y no serán leidas por Rhino. Son para uso humano. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
#example 1: create a series of points/spheres import rhinoscriptsyntax as rss def createPoints(): print “This denition (function) creates points using 3 loops” maxX = 10 maxY = 10 maxZ = 10
for i in range (maxX): for j in range (maxY): for k in range (maxZ): ptarr = [i,k,j] pt = rss.AddPoint(ptarr) sp = rss.AddSphere(pt,0.25) rss.ObjectColor(pt,(i*255/maxX,j*255/maxY,k*255/maxZ)) rss.ObjectColor(sp,(i*255/maxX,j*255/maxY,k*255/maxZ))
createPoints()
Fíjate en la descripción del script línea por línea para entender exactamente qué ocurre. 1 3 5 6-20 6 8-10 12 13 14 15 16
Comentario para el ususario o lector del script que comenta lo que éste hace
Importación de Rhinoscriptsyntax para poder acceder a los métodos nativos del mismo Comienzo de la función “createPoints”, o signatura de la misma mediante la palabra reservada def, nombre, y argumentos o parámetros (paréntesis), seguido de dos puntos (“:”) para indicar que viene a continuación.. Cuerpo de la función. Observa que está indentado Llamada a la función de python print, que imprime un mensaje en la ventana de comando. El mensaje se escribe entre comillas para indicar a python que se trata de una cadena de caracteres. Declaración e inicialización de las variables maxX, maxY, y maxZ, todas con el mismo valor. Iniciación de un bucle o loop que se ejecutará 10 veces (0,1,2,3,4,5,6,7,8,9) Iniciación de un bucle o loop que se ejecutará 10 veces (0,1,2,3,4,5,6,7,8,9) para cada una de las 10 anteriores. Iniciación de un bucle o loop que se ejecutará 10 veces (0,1,2,3,4,5,6,7, 8,9) para cada una de las 100 anteriores. En total, el blo que de código que se encuentra entre las líneas 15 y 20 se ejecutará 10*10*10 = 1000 veces (en sólo 3 líneas!). Declaración e inicialización de una lista con 3 valores (un punto!!) Añadimos el punto al modelo. Obser va que el método AddPoint (que ya está definido por Rhino) viene precedido de “rss.”, el nombre que hemos puesto a nuestra importación de r hinoscriptsyntax. Asimismo, para que python pueda añadir el punto al modelo deberemos darle la información de x, y, z (es decir, las coordenadas en el espacio). Nosotros guardamos estas coorde-
RHINO USER MEETING DAY RHINOSCRIPT - PYTHON
ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS
[Fig 5 Resultado del script]
RHINO USER MEETING DAY RHINOSCRIPT - PYTHON
ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI[O]LOGICS
RHINO USER MEETING DAY RHINOSCRIPT - PYTHON
ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS
II. PROGRAMACIÓN Y TOPOLOGÍA 1. Editor de rhinopython
El editor, además de espacio para el texto del scrit, incluye el compilador y “debugger”, una 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 ”. Para editar un script de python, usa el comando “_EditPythonScript ”. El debugger es un programa que ayuda a encontrar errores en el script, especialmente de sintaxis, por lo que te será sencillo corregir tus scripts durante su ejecución, mediante la visualización de variables en tiempo real y la detección de errores de sintaxis. El “highlighter ”, o reconocimiento automático de palabras reservadas, permite que éstas aparezcan automáticamente en colores que identificarán varios tipos: generalmente azul para palabras de Python, verde para los comentarios, rojo para cadenas de caracteres, y n egro para el resto en general.
1.1. Opciones principales del editor Las principales operaciones que se pueden realizar son: - Editar scripts: en la ventana de edición, donde debes copiar los scripts que hemos escrito anteriormente. - Consultar la librería, en la ventana de métodos nativos de Rhinoceros. - Consultar la ayuda, haciendo doble click sobre el método que se quiere consultar. La ayuda es muy sencilla y explicativa, e incluye lo siguiente: · Nombre del comando, con una breve descripción de su funcionamiento · Sintaxis y uso: atributos [input] y valores de retorno [output] · Ejemplo, que puedes copiar y pegar directamente en la ventana del editor de scripts. Título de script
Menú
Pestañas de edición Librería general y rhino Canvas de edición de código
Diálogo de creación
Depurar (debug) Ejecutar
RHINO USER MEETING DAY RHINOSCRIPT - PYTHON
ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI[O]LOGICS
- Para ejecutar un script usa el botón de play; esto ejecutará el script actual [la pestaña activa]. - “Debug” los scripts consite en encontrar fallos en el script. Como hemos dicho, esto se realiza visualizando los calores de las variables en líneas seleccionadas y el estado del script en cada momento. De esta manera podemos encontrar errores comunes tales como: · Confusión entre tipos de datos; por ejemplo, una variable debería tener valor numérico y contiene una cadena de caracteres o alfabéticos. · Errores en la definición de variables, y sus nombres. · Errores de sintaxis; por ejemplo, en símbolos, “(),=.” y otros · Errores en el paso de variables en las funciones. 1.2. Instalando el editor. Interfaz.
No es necesario que instales ningún software o extensión adicional, el editor viene ya de serie con la instalación de Rhino v5. Como ves en la figura 6, la interfaz es muy clara. Es probable que únicamente necesites usar los botones principales, que dan acceso a las funciones de edición, corrección y ejecución de scripts. Para abrir Monkey, ve a la pestaña que aparece en la barra de menún, “Monkey”, y haz click sobre “Monkey Editor”. 2. Vectores y puntos: una sencilla base de geometrías complejas 2.1. Puntos
En Rhinoceros, los puntos son las entidades geométricas más sencillas que hay. Tienen tres componentes, que corresponden a su localización x,y,z respecto del plano de trabajo universal. Un punto se describe, por tanto de la siguiente manera:
[Fig 8 Punto en espacio cartesiano R3: A(a1,a2,a3)]
[Fig 9. Vector v en espacio cartesiano R3: v(v1, v2,v3). El punto de apli-
RHINO USER MEETING DAY RHINOSCRIPT - PYTHON
ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS
aPoint = [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 lista o tuple con las coordenadas del mismo: import rhinoscriptsyntax as rss x = 10 y= 3 z = 7 aPoint = [x,y,z] rss.AddPoint (aPoint)
2.2. Vectores
Los vectores también se describen por conjuntos de coordenadas, listas que contienen [x,y,z]. En este sentido, son exactamente iguales que los puntos, y tienen el mismo comportamiento. La única diferencia estriba en que, por defecto, todos los vectores están basados en [0,0,0]. Las operaciones más sencillas con vectores incluyen suma, diferencia, y escalado, que responden a los siguientes métodos: - Suma: VectorAdd (vec1,vec2) - Sustracción: VectorSubtract (vec1,vec2) - Escalado: VectorScale (vec1,vec2) Donde vec1 y vec2 son arrays de 3 componentes, exactamente igual que en el caso de puntos. 3. Curvas
Podemos entender las curvas como entidades controlables a partir de puntos. Las líneas, polilíneas y curvas están basadas en puntos de control, que definen su geometría, continuidad, y tangencias. Los conceptos básicos que debemos conocer en curvas son los siguientes: - Dominio de una curva: es el conjunto de valores reales que resultan que hace que se cumpla la ecuación de la misma. En f(x) = axn+bx(n-1)+(...)+g, por ejemplo, el dominio es el conjunto de valores de x que hacen que f(x) tenga un valor real. Esto mismo aplica a las curvas NURBS, si bien hemos de ser conscientes que las curvas tienen un principio y un final determinado, y que sus ecuaciones, a las que no podemos acceder, son más complejas. Sin embargo, existe una clara correspondencia entre dichos valores y la curva, que podemos ver en la figura 12. La ecuación paramétrica de una recta es como sigue: (x,y) = (x1,y1) + k(v1,v2) Como recordarás de álgebra, puedes hallar culquier punto de la recta con un vector director y un valor de k, el parámetro. Esto aplica exactamente a las curvas NURBs, si bien su topología es algo más compleja. Es suficiente con que recuerdes que a cada valor de k le corresponde un punto en la recta, y por tanto, en el espacio. - Puntos de control: puntos que definen el polígono de control, a partir del cual se define, en función del tipo de continuidad [es decir, el grado], la curva final. Con RhinoScript es relativamente sencillo obtener este tipo de información, de la misma manera que somos capaces de acceder a los datos de X,Y,Z, de un punto y modificarlo. Las operaciones más comunes son las siguientes: · Evaluar el dominio de una curva. · Crear puntos sobre curvas con RhinoScript. · Crear curvas a través de puntos o usando los puntos como puntos de control de la curva. De todos modos, este tipo de operaciones los veremos a continuación en el siguiente apartado, “Topología de la Geometría NURBS II, Geometría computacional básica 2”. En los scripts que siguen verás que cada una de las funciones incluye a la anterior, de modo que puedes “activar” y “des-
RHINO USER MEETING DAY RHINOSCRIPT - PYTHON
ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI[O]LOGICS
P0
P6
P1 P5
P7
P2 P4 P8 P3
dom(0)+ dom(0)+ dom(0)+ dom(0)+ dom(0)+ dom(0)+ dom(0)+ 1*step 2*step 3*step 4*step 5*step 6*step 7*step
dom(0) valor mínimo dominio
dom(1) valor máximo dominio
[Fig 12. Concepto de dominio de una curva. Los valores Dom(0) [min] y Dom(1) [max] no son necesariamente 0 y 1 y son asignados por Rhino.
El código está comentado, de manera que puedes entender cada p aso una vez lo vayas copiando en el editor de scripts. III. SCRIPTS RELACIONADOS En este punto, presentamos dos scripts. El primero incluye funciones de creación de puntos. El segundo, análisis de curvas, dominios y puntos de control. Ambos comienzan por “Option Explicit”. 1. Puntos
Como verás, la creación de puntos es muy sencilla, y se realiza mediante el método [función nativa] de Rhino “Rhino. AddPoint”. Esta función requiere de una matriz de componentes (x,y,z), como hemos visto anteriormente. La subrutina Main tiene una serie de funciones, crecientes en complejidad. doSinglePoint añade un punto al modelo en las coordenadas dadas. Prueba a cambiarlas y ejecutar el script. Para ejecutar una única función descoméntala, y comenta el resto. Haz esto con cada una de las funciones cambiando los valores. doPointGrid utiliza dos “loops” [estructuras do...] 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 createPoints (en la página11) 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] ... end if. Intenta 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 podría aprovechar los mismos puntos para crear una polilínea [la única dife-
RHINO USER MEETING DAY RHINOSCRIPT - PYTHON
ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS
doComplexComponentGrid podría crear, además del perímetro, una curva con los mismos puntos. Esta curva estaría contenida dentro del perímetro. import rhinoscriptsyntax as rss #Script written by
#Script NOT copyrighted #Script versión martes, 29 de junio de 2010 18:21:34 #A series of VERY SIMPLE functions to demonstrate the VERY BASICS of NURBS geometry #In later sessions we will explore how to enhance our lofting capabilities import rhinoscriptsyntax as rss def doSinglePoint(): #This adds a single point in 0,0,0 #We need to enter the 3D coordinates dening the point in an array (collection of objects) rss.AddPoint(20,20,0) def doSinglePointWithAnnotation(): rss.AddPoint(20,20,0) rss.AddTextDot(“A point here”,[20,20,0]) def doPointGrid(): for i in range (10): for j in range (10): rss.AddPoint(i,j,0) rss.AddTextDot(“Pt at: “ + str(i) + “ “ + str(j),[i,j,0]) def doLine(): rss.AddLine([0,0,0],[0,20,0]) def doLines(): maxX = 10 maxY = 10 for i in range(1,maxX): for j in range(1,maxY): rss.AddLine([i,j,0],[i-1,j-1,0]) rss.EnableRedraw(False) #doSinglePoint() #doSinglePointWithAnnotation() #doPointGrid() #doLine() #doLines() rss.EnableRedraw(True)
2. Curvas
La función ShowDomain muestra el concepto de dominio de una curva. Para ello, crea un punto en la curva y muestra, mediante un “textDot” o anotación, el valor del dominio en ese punto. El script requiere una curva, que deberá ser seleccionada por el usuario. Veremos más sobre curvas en el siguiente apartado. import rhinoscriptsyntax as rss def showDomain(): crv = rss.GetObject (“Get curve to evaluate”,4) dom = rss.CurveDomain(crv) rss.AddPoint(rss.EvaluateCurve(crv,dom[0])) rss.AddPoint(rss.EvaluateCurve(crv,dom[1])) rss.AddTextDot(“Dom[0] is: “ + str(dom[0]),rss.EvaluateCurve(crv,dom[0])) rss.AddTextDot(“Dom[1] is: “ + str(dom[1]),rss.EvaluateCurve(crv,dom[1]))
RHINO USER MEETING DAY RHINOSCRIPT - PYTHON
ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI[O]LOGICS
RHINO USER MEETING DAY RHINOSCRIPT - PYTHON
ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS
TOPOLOGÍA DE LA GEOMETRÍA NURBS II [Non-Uniform Rational Bezier Splines]
RHINO USER MEETING DAY RHINOSCRIPT - PYTHON
ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS
I. GEOMETRÍA COMPUTACIONAL BÁSICA 2 - RECTAS Y CURVAS NURBS 1. El dominio de curvas en Rhino y Rhinoscript:
La representación del dominio de curvas en Rhinoceros responde a una serie de características y conceptos que debemos conocer si pretendemos crear scripts o rutinas que incluyan trabajo con líneas, polilíneas, curvas o curvas mixtas, sea cual sea su creación. Es importante resaltar asimismo que los conceptos que siguen aplican a todas las curvas por igual, con independencia de su grado o manera de creación. · En álgebra, el dominio de una curva se refiere al conjunto de valores de la variable independiente (normalmente “x” para los cuales existe un valor real de la variable dependiente (normalmente “y”). Para más información, vuelve a ver la figura 12 del apartado anterior. · En geometría computacional, sea cual sea la representación de la curva, el dominio responde a la definición interna de la misma en R1 (es decir, en el espacio de la curva). Así pues, en Rhino 4 oscila entre 0 y 1, mientras que en Rhino 5 entre 0 y la longitud de la curva. En cualquier caso, 0 representa el origen de la curva, y 1 (o su longitud) el final de la misma. · El dominio responde a la curvatura de la curva, por lo que una división del dominio en n partes iguales no se traduce necesariamente en n segmentos de la misma longitud. · Debemos saber, a la hora de usar curvas para superficies, cuál es el origen y el final de la curva, porque esto influirá en comandos como “loft”, por ejemplo. El comando “_flip”, invierte el sentido de una curva. CRV DOMAIN (0)
CURVE OBJECT MAIN PROPERTIES: ID, DOMAIN, DEGREE - ID: UNIQUE IDENTIFIER ASSIGNED BY RHINO AT THE TIME OF CREATION - DOMAIN: INTERNAL DEFINITION OF A CURVE. IT IS A VALUE BETWEEN 0 & 1, WHERE 0 REPRESENTS THE START OF THE CURVE AND 1 THE END. IT DOES NOT REFER TO ITS LENGTH, RATHER TO ITS CURVATURE
CRV DOMAIN (X)
CRV DOMAIN (0)
CRV DOMAIN (Y)
CRV DOMAIN (Z)
CRV DOMAIN (1)
[Fig 1. Dominio 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
RHINO USER MEETING DAY RHINOSCRIPT - PYTHON
ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI[O]LOGICS
import rhinoscriptsyntax as rss def showDomain(): crv = rss.GetObject (“Get curve to evaluate”,4) dom = rss.CurveDomain(crv) rss.AddPoint(rss.EvaluateCurve(crv,dom[0])) rss.AddPoint(rss.EvaluateCurve(crv,dom[1])) rss.AddTextDot(“Dom[0] is: “ + str(dom[0]),rss.EvaluateCurve(crv,dom[0])) rss.AddTextDot(“Dom[1] is: “ + str(dom[1]),rss.EvaluateCurve(crv,dom[1])) showDomain()
Por lo tanto, recuerda que cualquier punto de una curva puede expresarse de dos modos: (i) en referencia al espacio cartesiano [su posición x,y,z en el espacio], y (ii) en referencia a la curva a la que pertenece, mediante su dominio [que tomará un valor entre 0 y 1 en Rhino v4, o entre 0 y su longitud en Rhino v5]. 3. Curvas a partir de puntos
Rhinoceros permite la generación de una gran variedad de curvas, entre las que se encuentran: - Por puntos de control - Interpoladas [a través de puntos] - Interpoladas en superficie [la curva estará contenida en ella] - Por manejadores [define un punto y su tangencia] - Trazar [bosquejar] curvas: boceto - Trazar en malla poligonal/superficie - Cónicas - Promedios Todas estas curvas pueden modificarse una vez terminadas. La modificación se hace generalmente a partir de los puntos de control, bien por adición y substracción, bien por su modificación. Los puntos de control se comportan como objetos del dibujo, e incluyen una serie de propiedades., que siguen: - Posición - Peso: grado de influencia sobre la curvatura de la curva [a mayor peso, más cerca estará la curva de pasar por el punto de control]. Existen otras técnicas avanzadas de creación de curvas, tales como: - Fluir a lo largo de una superficie - Curvas UVN [aplicadas sobre superficies] Curva por puntos de control Curva por interpolación Curva por interpolación en superficies Curva por manejadores Trazar Trazar sobre malla Cónicas y parábolas Hélice y espiral Curvas promedio Activar puntos de control Activar puntos de edición/ desactivar seleccionados Ocultar caras posteriores de polígono de control Mover UVN, toque ligero UVN Insertar nodo/ punto de edición
Extender/Empalmar /Achaflanar línea
Simplificar Insertar/Eliminar puntos de control Subcurva Insertar línea en curva Booleana de curvas
Cambiar modo de arrastre Editar con manejadores Añadir nodo Eliminar nodo
RHINO USER MEETING DAY RHINOSCRIPT - PYTHON
ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS
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 super ficies complejas, como por ejemplo fachadas estructurales. La edición de las curvas se realiza, como hemos dicho, a partir de sus puntos de control, fácilmente accesibles tanto explícitamente [modelando] como implícitamente [a partir de RhinoScript]. II. SUPERFICIES Y POLISUPERFICIES EN RHINOCEROS 1. Direcciones en superficies
- Direcciones U y V: · Las superficies son más o menos rectangulares. Las superficies tienen tres direcciones, U, V y normal. Las direcciones U, V y normal se pueden visualizar con el comando Dir. Las direcciones U y V son como el tejido de ropa o de una tela. La dirección U se indica con la flecha roja y la dirección V con la flecha verde. La dirección normal se indica con flechas blancas. Las direcciones U, V y normal se corresponderían a las direcciones X, Y y Z de la superficie. · Estas direcciones se utilizan para el mapeado de texturas y la inserción de puntos de control. - Dirección normal: · En las superficies, la normal es una dirección que señala hacia la parte “exterior” o “superior” de la superficie, y es perpendicular a la superficie en el punto de cálculo. Para polisuperficies cerradas (cono, cilindro, caja, etc.) o sólidos de una superficie (esfera, toroide), la normal siempre está orientada “hacia fuera”. Sin embargo, en una superficie o polisuperficie abierta la dirección de la normal depende de cómo se creó y puede ser arbitraria. · El comando Dir muestra la dirección de la normal de un objeto.
[Fig 3. Dirección en una superficie]
2. Concepto y manejo de dominios de superficies en Rhinoscript
· Al igual que en curvas, el dominio en superficies es la representación geométrica interna que nos permite obtener puntos sobre la superficie en R2 (es decir, sobre el “espacio binario” de la superficie). · Toda superficie tiene dos dominios, uno en la dirección “u” y otro en la dirección “v”, de manera que, mediante la combinación de dos parámetros “i” (correspondiente a u) y “j” (correspondiente a v), se puede hallar y calcular la posición de un punto en la superficie (que, de nuevo, puede expresarse en términos de R2 o R3). Coloquialmente podríamos decir que u y v corresponden a las componentes ”X” e “Y” sobre un plano [en el que sabemos, por ejemplo, que la componente Z es 0], pero sobre la superficie. · Para una polisuperficie, el dominio se calcula para cada una de las superficies componente, por lo que es muy conveniente modelar con superficies. 3. R2 y R3 [“espacio superficie” y espacio cartesiano]
R2
el espacio bidimensional de la superficie [coordenadas implícitas la geometría].
RHINO USER MEETING DAY RHINOSCRIPT - PYTHON
ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI[O]LOGICS
a la superficie a la que pertenece, mediante su dominio [mediante dos valores entre DomMin y DomMax, si dichos valores no se han normalizado para que sean DomMin = 0 y DomMax = 1]. · Normalizado: con la opción Sí, los intervalos de los parámetros U y V se escalan para que los valores resultantes estén entre cero y uno (en lugar de usar el valor del parámetro real). Esta opción es útil cuando desea saber el porcentaje del espacio de los parámetros del punto designado sin tener que calcularlo según el dominio de la superficie. Con la opción No, se proporcionan los valores de los parámetros U y V no escalados. Véase también Dominio. · Nota: Cuando se selecciona una polisuperficie, Rhino calcula el resultado de la superficie componente en la posición designada. Si la superficie es recortada, Rhino usará la superficie no recortada.
[Fig 4. Expresión de superficies y puntos sobre superficies. Dominio]
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 dichos programas. - Precauciones usando el comando “loft”: · Como norma general, las curvas deben tener el mismo número de puntos de control · Asimismo, hemos de ser cuidadosos con el sentido de las mismas, así como su alineación.
RHINO USER MEETING DAY RHINOSCRIPT - PYTHON
ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS
FILA 1 Superficie por 3 ó 4 puntos Superficie por curvas de borde Superficie a partir de curvas planas Superficie rectangular Extruir curva FILA 2 Loft - transición Superficie por network de curvas Superficie parche Sweep 1/2 railes
FILA 3 Superficie de revolución Cubrir objetos con superficie Mapa de alturas desde imagen Superficie desde rejilla de puntos
[Fig 5. Principales herramientas relativas a generación y ectracción d e información de superficies]
RHINO USER MEETING DAY RHINOSCRIPT - PYTHON
ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI[O]LOGICS
RHINO USER MEETING DAY RHINOSCRIPT - PYTHON
ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS
DISEÑO CON PYTHONSCRIPT [Cubierta de un estadio]
RHINO USER MEETING DAY RHINOSCRIPT - PYTHON
ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS
I. UN EJEMPLO SENCILLO DE APLICACIÓN DE RHINOSCRIPT 1. Objetivo:
El objetivo del script es practicar los métodos más usuales en rhinoscript, tales como la selección de objetos existentes, y el trabajo con puntos. Además, crearemos superficies automáticamente mediante la interacción directa con el usuario. Aplicaremos el script inicialmente a un conjunto de curvas indiferenciado para comprobar y entender su funcionamiento. Posteriormente entenderemos cómo utilizar el mismo sobre una superficie diseñada para albergar una cubierta de un estadio. Para ello, intentaremos seguir una estrategia en complejidad ascendente, comenzando por los métodos más sencillos hasta conseguir tener un script complejo. RhinoPython es perfectamente compatible con grasshopper, por lo que será nuestro lenguaje de programación preferido. 2. Comenzando: los “babystepts”: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
1 3 5
#example: get a curve, a number of divisions, and divide curve import rhinoscriptsyntax as rss def getCurves(): print “This denition (function) gets curves in series of three”
crv = rss.GetObject(“Select curve”,4) if not crv: return divNr = rss.GetInteger(“Nr of divisions”,4,6,20) if not divNr: return divPts = rss.DivideCurve(crv,divNr) rss.AddPoints(divPts)
getCurves()
Comentario para el ususario o lector del script que comenta lo que éste hace
12 13
Importación de Rhinoscriptsyntax para poder acceder a los métodos nativos del mismo Comienzo de la función “getCurves”, o signatura de la misma mediante la palabra reservada def, nombre, y argumentos o parámetros (paréntesis), seguido de dos puntos (“:”) para indicar que viene a continuación.. Cuerpo de la función. Observa que está indentado Llamada a la función de python print, que imprime un mensaje en la ventana de comando. El mensaje se escribe entre comillas para indicar a python que se trata de una cadena de caracteres. Declaración e inicialización de la variable crv, que albergará la curva que seleccione el usuario por medio delmétodo nativo de Rhino GetObject. Para seleccionar curvas, utiliza el filtro de tipo 4. Si tienes dificultades entendiendo lo que esto significa, puedes usar la ayuda de RhinoScript. Nos aseguramos que el usuario ha seleccionado una curva, de manera que, si no es así, salimos de la función Solicitud de un número de divisiones determinado por parte del usuario Una vez más, no aseguramos el éxito de la función mediante la comprobación de la correcta introducción de datos por el ususario. Llamada al método nativo de Rhino para dividir la cur va Añadir puntos en cada una de las divisiones
15
Llamada a la ejecución de la función
6-13 6 8
9 10 11
Como ves, este sencillo script divide una curva del modelo y añade una serie de puntos sobre cada una de las divisiones. Esta es la base de nuestro pequeño programa, ya que dividiremos las curvas en una serie de segmentos sobre los cuales crearemos las superficies que van a constituir la cubierta. Como puedes entrever, el número de divisiones producirá un efecto diferente, tal y como puedes ver en la figura a continuación. Como es evidente, podrías
RHINO USER MEETING DAY RHINOSCRIPT - PYTHON
ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI[O]LOGICS
[Fig 1.Ejemplo de cubierta de estadio]
Como puedes imaginar, lo que se puede hacer con una curva se puede hacer con 3 curvas. En este caso, y al tratarse de un número pequeño de inputs por parte del usuario, no deberíamos tener demasiado problema en repetir el proceso tres veces. Sin embargo, para un mayor número de inputs, deberíamos considerar trabajar con bucles que nos permitan hacer una única selección. Iremos viendo esto en pasos sucesivos, pero de momento vamos a conformarnos con conseguir que cada paso aumente la complejidad del script. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
1-9
#example 1: get a curve, a number of divisions, and divide curve #imports import rhinoscriptsyntax as rss #dene functions def getCurves(): print “This denition (function) gets curves in series of three” crv = rss.GetObject(“Select rst curve”,4) if not crv: return crv1 = rss.GetObject(“Select second curve”,4) if not crv1: return crv2 = rss.GetObject(“Select third curve”,4) if not crv2: return divNr = rss.GetInteger(“Nr of divisions or segments”,4,4,20) if not divNr: return
divPts = rss.DivideCurve(crv,divNr) rss.AddPoints(divPts) divPts1 = rss.DivideCurve(crv1,divNr) rss.AddPoints(divPts1) divPts2 = rss.DivideCurve(crv2,divNr) rss.AddPoints(divPts2)
#call function = tell rhino to execute the function getCurves()
Estas líneas deben ser conocidas a estas alturas
RHINO USER MEETING DAY RHINOSCRIPT - PYTHON
ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI [O] LOGICS
Para desarrollar el progama, calcularemos el punto medio entre dos dados, y así formaremos una estructura con forma de diamante, tal como ves en la figura 2. No existe una función para hallar el punto medio dados dos puntos por coordenadas, pero nosotros podemos escribir un algoritmo que funcione para nuestros propósitos. 1 2 3 4 5
1 2 3 4 5
#function to calculate mid pt between 2 given points def MidPt(pt1,pt2): midPt = None midPt = [(pt1[0]+pt2[0])/2,(pt1[1]+pt2[1])/2,(pt1[2]+pt2[2])/2] return midPt
Comentario que describe el uso de la función Declaración de la función con la palabra reservada def, argumentos entre paréntesis, y dos puntos. Los argumentos son los inputs que precisa la función, en este caso dos puntos (definidos por sus coordenadas). Declaración de la variable midPt, o punto medio. Este punto medio deberá contener el resultado de nuestros cálculos, es decir, el punto medio de dos dados. Cálculo del punto medio Retorno de la función: punto medio
[Fig 2. Puntos medios en la curva intermedia]
Como se ve, podemos llamar la función desde cualquier otro punto del código. Evidentemente, esto nos permite reusar bloques de código tantas veces como nos sea necesario. Puedes copiar y pegar dichos bloques de código tantas veces como sea necesario. Puedes incluso crear bibliotecas de código para reusarlas, del mismo modo que funcionan los métodos nativos de rhino. 3. Crea curvas a partir de los puntos:
Para crear curvas debes disponer primero de un conjunto de puntos, que has de agrupar en listas. Prueba, por
RHINO USER MEETING DAY RHINOSCRIPT - PYTHON
ADOLFO NADAL SERRANO MAS. ARCHITECT - ARCHI[O]LOGICS
Con estos dos bloques de código, el script queda del siguiente modo: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
28 29-31 29
30 31 34-37
#example 1: get a curve, a number of divisions, and divide curve #imports import rhinoscriptsyntax as rss #dene functions def getCurves(): print “This denition (function) gets curves in series of three” crv = rss.GetObject(“Select rst curve”,4) if not crv: return crv1 = rss.GetObject(“Select second curve”,4) if not crv1: return crv2 = rss.GetObject(“Select third curve”,4) if not crv2: return divNr = rss.GetInteger(“Nr of divisions or segments”,4,4,20) if not divNr: return
divPts = rss.DivideCurve(crv,divNr) rss.AddPoints(divPts) divPts1 = rss.DivideCurve(crv1,divNr) rss.AddPoints(divPts1) divPts2 = rss.DivideCurve(crv2,divNr) rss.AddPoints(divPts2) #loop to generate mid pts midPts = [] for i in range (len(divPts1)-1): midPts.append(MidPt(divPts1[i],divPts1[i+1])) rss.AddPoints (midPts) #generate base curves basecrv1 = rss.AddCurve([divPts[0],midPts[0],divPts2[0],divPts[0]],1) basecrv2 = rss.AddCurve([divPts[1],midPts[0],divPts2[1]],divPts[1],1) basecrv3 = rss.AddCurve([divPts[0],midPts[0],divPts[1]],divPts[0],1) basecrv4 = rss.AddCurve([divPts2[0],midPts[0],divPts2[1]],divPts2[0],1)
#function to calculate mid pt between 2 given points def MidPt(pt1,pt2): midPt = None midPt = [(pt1[0]+pt2[0])/2,(pt1[1]+pt2[1])/2,(pt1[2]+pt2[2])/2] return midPt #call function = tell rhino to execute the function getCurves()
Declaración de la lista que va a contenter a los puntos como una lista vacía. Iremos llenando la lista dentro del bucle Bucle para generar los puntos medios en la curva intermedia Esta línea es fundamental. Decimos a Rhinoscript que, para cada uno de los puntos en los que hemos dividido la curva intermedia, repita la línea 30. Es decir, para cada punto (desde el 0 hasta el penúltimo para ser más exactos), cogeremos el punto actual y el siguiente, y llamaremos a la función Midt(punto actual, punto siguiente), obteniendo de esta manera el punto medio correspondiente. Llamada a la función punto medio y guardado de su valor en la variable midPts. “Append” añade cada uno de los puntos obtenidos a la lista de puntos medios. Añadir puntos al modelo. Añadimos las curvas correspondientes como base para las super ficies del modelo. En total son 4 curvas.