• Nenhum resultado encontrado

Introdução à Programação com AutoLisp. António Menezes Leitão

N/A
N/A
Protected

Academic year: 2021

Share "Introdução à Programação com AutoLisp. António Menezes Leitão"

Copied!
96
0
0

Texto

(1)

Introdução à Programação com AutoLisp

António Menezes Leitão

(2)

Conteúdo

1 Regiões e Volumes 2

1.1 Regiões . . . 2

1.2 Operações Funcionais . . . 5

1.3 Tratamento de Erros . . . 10

1.4 Trifólios, Quadrifólios e Outros Fólios . . . 14

1.5 Álgebra de Regiões . . . 16 1.6 Superfícies e Volumes . . . 28 1.6.1 Combinação de Sólidos . . . 28 1.7 Corte de Regiões . . . 41 1.8 Extrusões . . . 45 1.8.1 Extrusão Simples . . . 46

1.8.2 Extrusão ao Longo de um Caminho . . . 58

1.8.3 Extrusão com Transformação . . . 61

1.8.4 Colunas de Gaudí . . . 62

1.9 Revoluções . . . 67

1.9.1 Superfícies de Revolução . . . 68

1.9.2 Sólidos de Revolução . . . 72

1.10 Interpolação de Secções . . . 77

1.10.1 Interpolação por Secções . . . 77

1.10.2 Interpolação com Guiamento . . . 79

2 Transformações 83 2.1 Translação . . . 84 2.2 Rotação . . . 84 2.3 Reflexão . . . 85 2.4 Escala . . . 86 2.5 A Ópera de Sydney . . . 86

(3)

1

Regiões e Volumes

Até agora temos lidado apenas com curvas e sólidos simples. Nesta secção vamos discutir regiões e volumes criados a partir da união, intersecção e subtracção de regiões e volumes mais simples e ainda volumes obtidos a partir da extrusão de curvas e regiões.

1.1 Regiões

Em AutoCad, uma região é uma superfície bidimensional delimitada por uma curva plana fechada que não se intersecta. Embora visualmente seme-lhantes, uma região e uma curva que a delimita são entidades geométricas completamente diferentes. Como iremos ver, essa diferença torna-se notó-ria quando se usam regiões para a cnotó-riação de entidades mais complexas, como sejam os sólidos cuja secção é uma região.

As regiões criam-se a partir de curvas já existentes. “Curva,” neste con-texto, designa qualquer sequência de linhas poligonais, arcos, círculos, ar-cos de elipse, e splines.1

Para se criar uma região, o AutoCad disponibiliza o comando region. Este comando deve ser aplicado fornecendo uma sequência de curvas como argumento, terminando com um enter que, como já vimos, corresponde a usar uma string vazia. Para especificarmos a sequência de curvas teremos de ter referências para elas. Isso pode ser feito através das funções que acedem à base de dados de entidades geométricas, tais como entlast, entnexte entget descritas na secção ??.

A título de exemplo, consideremos as seguintes expressões:

(command "_.pline" (xy 0 0) (xy 2 0) (xy 1 1) (xy 0 0) "") (command "_.region" (entlast) "")

A primeira expressão cria uma linha poligonal fechada. A segunda ex-pressão transforma essa linha poligonal numa região poligonal. Reparemos no uso da função entlast para aceder à entidade criada imediatamente antes, i.e., a linha poligonal.2

Uma das virtudes das regiões é poderem ser usadas como ponto de partida para operações algébricas de combinação de regiões, como seja a união de regiões (comando union), a intersecção de regiões (comando

1As linhas poligonais tridimensionais (construídas pelo comando 3dpoly) não são

sus-ceptíveis de serem usadas para formar regiões. No entanto, é possível aplicar-lhes o co-mando explode para as converter numa sequência de lines que já pode constituir a fron-teira de uma região. Algumas operações do AutoCad fazem essa conversão automatica-mente, mas não é recomendável depender disso.

2Após a criação da região, as curvas que estão na sua origem serão eliminadas se o valor

da variável AutoCad delobj for 1 ou 2, e serão preservadas se o valor da variável for 0. A nossa recomendação é a de manter essa variável com o valor 2.

(4)

Figura 1: Uma região triângular e uma região circular.

intersect) e a subtracção de regiões (comando subtract). Para exem-plificarmos estas operações, comecemos por considerar a seguinte sequên-cia de expressões que criam, separadamente, uma região triângular e uma região circular:

(command "_.pline" (xy 0 0) (xy 2 0) (xy 1 1) (xy 0 0) "") (command "_.region" (entlast) "")

(setq triangulo (entlast))

(command "_.circle" (xy 1 1) 0.5) (command "_.region" (entlast) "") (setq circulo (entlast))

O resultado da avaliação destas expressões encontra-se na Figura 1. Como se pode ver pelas atribuições presentes nas expressões anteriores, para além da criação das duas figuras geométricas, resulta ainda a associ-ação dos nomes triangulo e circulo a cada uma delas. A partir destes nomes, podemos agora explorar diferentes operações de combinação de regiões. Por exemplo, para a união de regiões R0∪ R1, podemos escrever:

(command "_.union" triangulo circulo "")

Note-se que a operação union recebe todas as entidades a unir, de-vendo ser terminada com um enter, ou seja, a string vazia para a pseudo-função command. O resultado da união entre o triângulo e o círculo encontra-se no canto superior esquerdo da Figura 2.

Uma outra possibilidade é a intersecção de regiões R0∩ R1, que se obtém

(5)

Figura 2: Operações de combinação de regiões aplicadas a uma região tri-angular e a uma região circular. No canto superior esquerdo está repre-sentada a união e no direito a intersecção. No canto inferior esquerdo está representada a subtraccão do primeiro pelo segundo e no direito a subtrac-cão do segundo pelo primeiro.

(command "_.intersect" triangulo circulo "")

O resultado, neste caso, está representado no canto superior direito da Figura 2.

A terceira possibilidade é a subtracção de regiões R0 \ R1. Para isso,

temos de ter em conta que o AutoCad permite subtrair a um conjunto de regiões, outro conjunto de regiões. Isto implica que temos de terminar a selecção de cada conjunto com o respectivo enter:

(command "_.subtract" triangulo "" circulo "")

A subtracção do círculo ao triângulo especificada na expressão anterior está representada no canto inferior esquerdo da Figura 2.

Finalmente, como a subtracção não é uma operação comutativa, pode-mos ainda fazer a subtracção inversa visível no canto inferior direito da Figura 2. Para isso, escrevemos:

(command "_.subtract" circulo "" triangulo "")

Do ponto de vista matemático, uma região é um conjunto de pontos no espaço bidimensional e, nesta interpretação, a operação de união de re-giões não é mais do que a união de conjuntos de pontos e todas as opera-ções de combinação de regiões correspondem directamente a operaopera-ções de

(6)

conjuntos. Por exemplo, a intersecção de duas regiões não é mais do que o conjunto de pontos que pertencem, simultaneamente, às duas regiões, ou seja, é a intersecção de conjuntos de pontos; a subtracção de regiões não é mais do que o conjunto de pontos que pertencem à primeira região e não pertencem à segunda, ou seja, é a subtracção de conjuntos de pontos. 1.2 Operações Funcionais

Vimos que as operações de união, intersecção e diferença de regiões per-mitem construir regiões complexas à custa de outras regiões mais simples. Infelizmente, o processo de criação dessas regiões compostas é excessiva-mente complexo.

A razão desta complexidade está, essencialmente, no facto de as opera-ções não serem funcionais, i.e., não se comportarem como funopera-ções que re-cebem regiões como argumentos e que produzem regiões como resultados. Isso é perfeitamente visível nos exemplos anteriores em que é constante-mente necessário usar a função entlast para “recuperar” a região que foi criada imediatamente antes, de modo a usá-la nas operações subsequentes. Para se perceber bem aquilo que estamos a perder em termos de sim-plicidade de notação, podemos estabeler uma analogia com as expressões aritméticas: imaginemos que, em Lisp, as operações aritméticas fundamen-tais, como a soma e o produto de números, não produziam um número como resultado, apenas deixavam esse resultado acessível através da fun-ção entlast. Neste caso, mesmo uma funfun-ção aritmética tão simples como

f (x, y, z, w) = (x − y) × (z + w) já não poderia ser definida como

(defun f (x y z w) (* (- x y) (+ z w)))

e teria de ser definida na forma:

(defun f (x y z w / r1 r2) (- x y) (setq r1 (entlast)) (+ z w) (setq r2 (entlast)) (* r1 r2) (entlast))

Notemos como, na segunda versão, fomos obrigados a usar variáveis temporárias para guardar os resultados intermédios “recuperados,” de modo a usá-los nas operação seguinte. Basta uma mera comparação para con-cluirmos que a primeira versão, que considera as operações + e * como sendo funções que produzem números a partir de números, é muito mais compacta e inteligível que a segunda.

(7)

É precisamente este problema que ocorre com a forma como o AutoCad implementa as operações de união, intersecção e subtracção de regiões e, na verdade, todas as restantes operações que passem pelo uso da pseudo-função command, incluindo a criação de todas as figuras geométricas bási-cas, como sejam os círculos e os triângulos. Como vimos a função command devolve sempre nil precisamente porque o AutoCad apenas está interes-sado nos seus efeitos secundários, nomeadamente, a criação das entidades gráficas. Infelizmente, para quem deseja usar essas entidades como ponto de partida para a criação de outras entidades mais complexas, esse facto torna-se um obstáculo profundamente irritante que obriga à introdução de um número exagerado de variáveis para guardar os resultados intermédios que pretendemos usar nas operações seguintes.

Para se resolver este problema, temos de dar um cariz funcional às ope-rações de criação e de combinação de entidades. Para termos um caso con-creto de trabalho, recuperemos a sequência de expressões do exemplo grá-fico anterior e pensemos no modo de o tornar mais funcional.

O primeiro passo consiste em transformar a criação das entidades bási-cas, como a linha poligonal e a circunferência, em funções que produzem, como valor, as entidades correspondentes. Para isso, tal como anterior-mente, vamos invocar o comando apropriado mas, adicionalanterior-mente, vamos também recuperar a entidade recém-criada através da função entlast de forma a devolvê-la como resultado:

(defun pline-pontos (pontos) (command "_.pline")

(foreach ponto pontos (command ponto)) (command "")

(entlast))

(defun circulo (centro raio) (command "_.circle" centro raio) (entlast))

Naturalmente, teremos de implementar de modo idêntico todas as ou-tras entidades básicas que consideremos relevantes, como sejam as elipses, os arcos, etc. Por exemplo, para criar um polígono, i.e., uma linha poligo-nal fechada, teremos de redefinir a função poligono que introduzimos na secção ??:

(defun poligono (pontos) (command "_.pline")

(foreach ponto pontos (command ponto)) (command "_close")

(entlast))

Do mesmo modo, quando criamos uma spline devemos produzir a nova entidade como resultado:

(8)

(defun spline-pontos (pontos) (command "_.spline")

(foreach ponto pontos (command ponto)) (command "" "" "")

(entlast))

O passo seguinte consiste em definir a operação básica de criação de regiões que irá receber uma entidade (criada pelas funções anteriores) e que, após criar a região, devolve a entidade correspondente. Uma versão básica será:

(defun regiao (entidade)

(command "_.region" entidade "") (entlast))

O terceiro e último passo será a definição das operações de união, inter-secção e subtracção de regiões. Nestes casos, a abordagem terá de ser di-ferente pois, contrariamente às operações anteriores, estas não criam qual-quer nova região, antes operando através da modificação da primeira região e da eliminação da segunda. Por exemplo, se a uma região subtrairmos ou-tra, o resultado não é uma nova região mas sim a própria primeira região modificada pela subtracção da segunda. Assim, no caso da união, intersec-ção e subtracintersec-ção, não devemos usar a funintersec-ção entlast, devemos apenas devolver a primeira região:

(defun uniao (r0 r1) (command "_.union" r0 r1 "") r0) (defun interseccao (r0 r1) (command "_.intersect" r0 r1 "") r0) (defun subtraccao (r0 r1) (command "_.subtract" r0 "" r1 "") r0)

Agora que temos as operações básicas reescritas de forma a terem um comportamento funcional, já podemos reescrever o exemplo anterior num formato mais claro. Para isso, basta concentrarmo-nos no que pretendemos fazer: criar um triângulo, um círculo e unir as regiões respectivas. Esta descrição transcreve-se directamente para a seguinte expressão:

(uniao (regiao

(pline-pontos

(list (xy 0 0) (xy 2 0) (xy 1 1) (xy 0 0)))) (regiao

(circulo (xy 1 1) 0.5)))

(9)

(command "_.pline" (xy 0 0) (xy 2 0) (xy 1 1) (xy 0 0) "") (command "_.region" (entlast) "")

(setq triangulo (entlast))

(command "_.circle" (xy 1 1) 0.5) (command "_.region" (entlast) "") (setq circulo (entlast))

Notemos como o encadeamento presente na versão funcional torna mais claro o que se está a fazer, por oposição à abordagem não funcional onde é necessário ir guardando os resultados intermédios para posterior utiliza-ção.

Na realidade, a definição que apresentámos para a função regiao é excessivamente limitativa, pois opera apenas com uma entidade, enquanto que a operação correspondente do AutoCad opera com qualquer número delas. Este facto faz com que não seja possível usar a função regiao para criar regiões delimitadas por sequências arbitrárias de curvas, como sejam, plines, arcos de circunferência ou elipse, splines, etc. Assim, para não per-dermos funcionalidade, é conveniente generalizarmos a função regiao para aceitar também listas de entidades. No entanto, para não complicar-mos o seu uso no caso comum em que, de facto, apenas tecomplicar-mos uma enti-dade, vamos manter o mesmo número de parâmetros, mas vamos identifi-car se o argumento correspondente é uma entidade ou uma lista de entida-des.

Por exemplo, no caso da função regiao, podemos ter:

(defun regiao (entidade) (command "_.region") (if (listp entidade)

(foreach entidade-i entidade (command entidade-i)) (command entidade))

(command "") (entlast))

Como podemos ver, a função testa se o argumento é uma lista. Se for, então envia todas as entidades contidas na lista argumento para o Au-toCad, caso contrário, envia apenas o argumento. Este comportamento permite-nos usar a função quer com uma entidade como argumento, quer com uma lista de entidades como argumento:

_$ (regiao (circulo (xy 10 10) 1)) <Entity name: 7be30060>

_$ (regiao

(list (pline-pontos (list (xy 1 2) (xy 3 4)))

(pline-pontos (list (xy 3 4) (xy 4 2) (xy 1 2))))) <Entity name: 7be300b8>

Infelizmente, esta modificação ainda não é suficiente para lidar com o caso das linhas poligonais construídas pelo comando line. Este comando,

(10)

ao contrários dos comandos pline e 3dpoly, cria, não uma, mas tantas entidades quantos os segmentos que o utilizador tiver especificado.3 Isso implica que a função entlast, quando aplicada após o uso do comando line, não devolve a linha poligonal mas apenas o último segmento criado. Este comportamento é visível no seguinte exemplo:

_$ (line-pontos (list (xyz 1 2 3) (xyz 0 0 3) (xyz 1 0 3) (xyz 1 2 3))) nil

_$ (obtem-propriedade (entlast) ponto-inicial:) (1.0 0.0 3.0)

Como podemos ver, o ponto inicial que foi retornado é apenas o do úl-timo segmento da linha poligonal. Assim, para podermos usar todos os segmentos de uma line para a criação de uma região, temos de juntar as entidades respectivas numa lista. Esta lista representa a “entidade” linha poligonal, possuindo como “subentidades” cada um dos segmentos da li-nha poligonal.

Um modo simples de criarmos essa lista consiste em iterarmos as en-tidades que foram produzidas imediatamente após o início do comando line. Na secção ?? definimos a função entidades-desde precisamente para esse fim. Esta função apenas precisa de saber qual é a entidade de “partida” e colecciona numa listas todas as entidades que se lhe seguem. Para termos a entidade de partida geramos o primeiro segmento da linha poligonal e guardamos essa entidade antes de passarmos ao AutoCad os restantes pontos da linha. É precisamente isso que é feito pela segunte fun-ção:

(defun line-pontos (pontos / primeira-entidade) (command "_.line" (car pontos) (cadr pontos)) (setq primeira-entidade (entlast))

(foreach p (cddr pontos) (command p)) (command "")

(entidades-desde primeira-entidade))

Usando esta redefinição da função line-pontos já é possível capturar todos os segmentos da linha poligonal gerada com o comando line:

3Em teoria, o comando 3dpoly seria sempre preferível a usar pline ou line pois,

tal como o line (e contrariamente ao pline), o comando 3dpoly permite a construção de linhas poligonais tridimensionais e, tal como o pline (e contrariamente ao line), o comando 3dpoly cria uma única entidade.

Infelizmente, as operações de criação de regiões da versão actual do AutoCad nem sem-pre conseguem lidar com regiões formadas por linhas produzidas pelo comando 3dpoly, pelo que, nesses casos, somos obrigados a socorrermo-nos do comando line.

(11)

_$ (line-pontos

(list (xyz 1 2 3) (xyz 0 0 3) (xyz 1 0 3) (xyz 1 2 3))) (<Entity name: 78ea9e48> <Entity name: 78ea9e50> <Entity name: 78ea9e58>)

O problema, agora, é que não é possível usar directamente uma line no lugar de uma pline pelo simples facto de que a line devolve uma lista de entidades e a pline devolve uma só entidade. No exemplo da região que criámos atrás, isso implica que se substituirmos a função pline-pontos pela função line-pontos, iremos obter um erro que resulta de termos preparado a função regiao para lidar com uma entidade ou com uma lista de entidades, mas não a preparámos para lidar com listas de listas de entidades. Felizmente, é relativamente trivial aplicar uma solução recur-siva para o problema: o conjunto de subentidades de uma “entidade” é a própria entidade, no caso de esta não ser uma lista, e é a concatenação do conjunto de subentidades de cada elemento, no caso de esta ser uma lista. Deste modo, podemos redefinir a função região como se segue:

(defun regiao (entidade) (command "_.region") (subentidade entidade) (command "")

(entlast))

A função subentidade é responsável por passar os argumentos do co-mando para o AutoCad, mas desmembrando todas as listas até ficar apenas com entidades:

(defun subentidade (entidade) (if (listp entidade)

(foreach entidade-i entidade (subentidade entidade-i)) (command entidade)))

Desta forma, já é possível fazermos combinações arbitrárias de “enti-dades” produzidas pela função line-pontos com outras entidades “nor-mais.”

1.3 Tratamento de Erros

Até agora, a maioria das funções que definimos, quando invocadas com ar-gumentos incorrectos, abortam a sua execução. Este comportamento é ade-quado pois não faz sentido continuar a execução de uma função quando já foram encontradas situações excepcionais que não foi possível resolver.

(12)

Para exemplificar, imaginemos que pretendemos fazer uma região a par-tir de um círculo mas em que, por alguma razão, o círculo tem um raio negativo:

_$ (regiao (circulo (xy 0 0) -1)) ; error: Function cancelled

O erro anterior mostra que antes de tentar formar a região o AutoCad abortou a execução pois não conseguiu sequer criar o círculo.

Infelizmente, as operações de criação de regiões, em geral, não repor-tam ao Auto Lisp qualquer tipo de erros. Por exemplo, se tentarmos criar uma região a partir de uma única recta (que, obviamente, não é apropriada para formar uma região), não será gerado nenhum erro:

_$ (regiao (pline-pontos (list (xy 1 2) (xy 3 4)))) <Entity name: 7be1ff58>

Uma vez que é impossível criar uma região a partir de um único seg-mento de recta, que entidade é que foi devolvida como resultado? De acordo com a definição que demos para a função regiao, a resposta é simples: a última que tiver sido criada antes da tentativa abortada de for-mação da região. No exemplo anterior isso deverá corresponder ao próprio segmento de recta usado como argumento que, obviamente, não pode ser considerado uma região. Infelizmente, o AutoCad não reportou qualquer erro, embora o erro tenha de facto ocorrido e ainda esteja visível na janela de interacção do AutoCad através da mensagem:

0 loops extracted. 0 Regions created.

Este comportamento é altamente pernicioso para quem pretende pro-gramar o AutoCad: os programadores são humanos e errare humanum est, sendo de crucial importância que o computador nos informe de todas as situações em que ele não conseguiu cumprir as nossas “ordens.” Se ele não nos informar desses erros assim que eles ocorrem, a computação prosse-guirá com valores incorrectos que irão provocar novos erros mais adiante e, como é evidente, quanto mais tarde for reportado um erro, mais difícil será identificar a sua verdadeira causa.

Por este motivo, precisamos de tornar as nossas funções mais robustas de modo a detectarmos e reportarmos a ocorrência de erros tão cedo quanto possível.

Comecemos por lidar com a questão do reporte de erros. Para isso, o mais simples será usarmos a função princ para apresentarmos um texto a descrever o erro e, de seguida, invocarmos a função exit para abortar o programa. Esta última função, para além de abortar o programa, escreve

(13)

ainda uma mensagem adicional a informar desse facto. Para combinarmos estas duas operações, é conveniente definirmos uma função:4

(defun erro (mensagem) (princ "; ERRO: ") (princ mensagem) (exit))

Como exemplo de utilização desta função, consideremos o seguinte programa:

_$ (defun testa-divisao (x y) (if (= y 0)

(erro "divisao por zero!") (/ x y)))

TESTA-DIVISAO

_$ (testa-divisao 6 2) 3

_$ (testa-divisao 6 0) ; ERRO: divisao por zero! ; error: quit / exit abort

Como se pode ver, sempre que a função testa-divisao se apercebe que iria fazer uma divisão por zero, ela gera um erro com a mensagem apropriada e aborta a computação.

Tendo o reporte de erros tratado, podemos agora ocuparmo-nos da de-tecção de erros. Uma vez que no caso das operações de criação de regiões o AutoCad não nos avisa quando um erro ocorre, teremos de usar um mé-todo indirecto de detecção de erros. Para isso, podemos basearmo-nos no facto de as operações do AutoCad, em geral, terem efeitos secundários vi-síveis pois são criadas uma ou mais novas entidades geométricas como re-sultado da aplicação dessas operações. Assim, uma possibilidade simples consiste em identificarmos a última entidade criada previamente à invo-cação de um comando e computarmos a lista de entidades criadas poste-riormente à invocação desse comando. Se essa lista for vazia, é porque o comando não conseguiu criar nenhuma nova entidade. Para obtermos essa lista, podemos usar a função entidades-desde, descrita na Secção ??, aplicando-a à última entidade criada.

Este raciocínio sugere a seguinte redefinição para a função regiao:

4O Auto Lisp disponibiliza mecanismos mais sofisticados para efectuar o reporte de

(14)

(defun regiao (entidade / ultima-entidade novas-entidades) (setq ultima-entidade (entlast))

(command "_.region") (subentidade entidade) (command "")

(setq novas-entidades (cdr (entidades-desde ultima-entidade))) (if (null novas-entidades)

(erro "Nao foi possivel aplicar a operacao") (car novas-entidades)))

Usando esta função, já o exemplo anterior se “comporta” melhor:

_$ (regiao (pline-pontos (list (xy 1 2) (xy 3 4)))) ; ERRO: Nao foi possivel aplicar a operacao

; error: quit / exit abort

Uma vez que o potencial para erros não detectados também existe nou-tras funções, também estas deverão ser modificadas para incluirem a detec-ção e reporte de erros. Contudo, como o mecanismo de detecdetec-ção e reporte de erros é igual para todas, será conveniente centralizá-lo. Para isso, vamos definir duas funções, uma para inicializar uma variável global com a última entidade existente antes da aplicação da operação e outra para verificar que a aplicação da operação criou as novas entidades esperadas, retornando-as como resultado ou abortando o programa caso tal não tenha acontecido:

(setq ultima-entidade nil)

(defun inicio-operacao ()

(setq ultima-entidade (entlast)))

(defun fim-operacao (/ novas-entidades) (setq novas-entidades

(if (null ultima-entidade) (todas-entidades)

(cdr (entidades-desde ultima-entidade)))) (cond ((null novas-entidades)

(erro "Nao foi possivel criar a entidade")) ((null (cdr novas-entidades))

(car novas-entidades)) (t

novas-entidades)))

Notemos que a função lida não só com o caso em que não existiam quaisquer entidades previamente à aplicação da operação, mas também com o caso em que apenas é criada uma nova entidade após a aplicação da operação.

Usando as duas funções anteriores, podemos redefinir a função regiao de modo a ficar mais simples:

(15)

Figura 3: Trifólios, quadrifólios, pentafólios e outros “fólios” numa janela da Catedral de São Pedro, em Exeter, Inglaterra. Fotografia de Chris Last.

(defun regiao (entidade) (inicio-operacao) (command "_.region") (subentidade entidade) (command "")

(fim-operacao))

1.4 Trifólios, Quadrifólios e Outros Fólios

O trifólio é um elemento arquitectural que teve enorme divulgação durante o período Gótico. Trata-se de ornamentações constituidas por três círculos tangentes dispostos em torno de um centro, usualmente associadas ao topo das janelas Góticas mas que podem ocorrer em vários outros locais.

Para além do trifólio, a arquitectura Gótica também explorou o qua-drifólio, o pentafólio e outros “fólios.” Na Figura 3 apresentamos vários exemplos deste elemento, a par de algumas suas derivações.

Nesta secção vamos usar as operações que permitem criar e combi-nar regiões para construir trifólios, quadrifólios e, mais genericamente, n-fólios. Por agora vamos considerar apenas o trifólio.

Para determinarmos os parâmetros de um trifólio vamos reportar-nos à Figura 4 onde apresentamos um trifólio “deitado.” Nessa figura, podemos identificar re como o raio exterior do trifólio, rf como o raio de cada

“fo-lha” do trifólio, ρ a distância do centro de cada folha ao centro do trifólio e ri o raio do círculo interior do trifólio. Uma vez que o trifólio divide a

circunferência em três partes iguais, o ângulo α corresponderá necessaria-mente a metade de um terço da circunferência, ou seja, α = π3. No caso de

(16)

ri

re

rf

α ρ

Figura 4: Os parâmetros de um trifólio.

um quadrifólio teremos, obviamente, α = π4 e no caso geral de um n-fólio teremos α = πn.

Empregando as relações trigonométricas podemos relacionar os parâ-metros do trifólio uns com os outros:

rf = ρ sin α

ri= ρ cos α

ρ + rf = re

Se assumirmos que o parâmetro fundamental é o raio exterior do trifólio, re, então podemos deduzir que:

ρ = re 1 + sinπn rf = re 1 +sin1π n ri = re cosπn 1 + sinπn

A partir destas equações, podemos decompor o processo de criação de um n-fólio como a união de uma sucessão de círculos de raio rf dispostos

circularmente com um último círculo central de raio ri. Transcrevendo para

Lisp, temos:

(defun n-folio (p re n) (uniao

(folhas-folio p re n)

(circulo-interior-folio p re n)))

(17)

(defun circulo-interior-folio (p re n) (regiao (circulo p (* re (/ (cos (/ pi n)) (+ 1 (sin (/ pi n))))))))

Para a função folhas-folio, responsável por criar as folhas dispos-tas circularmente, vamos considerar o emprego de coordenadas polares. Cada folha (de raio ri) será colocada numa coordenada polar determinada

pelo raio ρ e por um ângulo φ que vamos recursivamente incrementando de ∆φ = 2πn. O caso básico corresponderá, neste caso, termos apenas uma

fo-lha. Este algoritmo será implementado pela função uniao-circulos que será invocada pela função folhas-folio com os valores pré-calculados de ρ, ∆φ e rf. Para simplificar, vamos considerar um ângulo φ inicial de

zero. Assim, temos:

(defun uniao-circulos (p ro fi d-fi rf n) (if (= n 1)

(regiao (circulo (+pol p ro fi) rf)) (uniao

(regiao (circulo (+pol p ro fi) rf))

(uniao-circulos p ro (+ fi d-fi) d-fi rf (1- n)))))

(defun folhas-folio (p re n) (uniao-circulos p (/ re (+ 1 (sin (/ pi n)))) 0 (/ 2*pi n) (/ re (+ 1 (/ 1 (sin (/ pi n))))) n))

Com base nestas funções, podemos criar um trifólio ao lado de um qua-drifólio, tal como apresentamos na Figura 5, simplesmente avaliando as seguintes expressões:

(n-folio (xy 0 0) 1 3) (n-folio (xy 2.5 0) 1 4)

Naturalmente, podemos usar a função para gerar outros “fólios.” A Figura 6 mostra um pentafólio, um hexafólio, um heptafólio e um octofólio. 1.5 Álgebra de Regiões

Tendo um mecanismo genérico para a construção de n-fólios, é tentador explorar os seus limites, em particular quando reduzimos o número de fo-lhas. O que será um fólio de duas folhas?

Infelizmente, quando experimentamos criar um destes “bifólios,” rece-bemos uma resposta desanimadora:

(18)

Figura 5: Um trifólio e um quadrifólio.

Figura 6: Fólios com número de folhas crescente. De cima para baixo e da esquerda para a direita estão representados um pentafólio, um hexafólio, um heptafólio, um octofólio, um eneafólio e um decafólio.

(19)

Figura 7: Um bifólio.

_$ (n-folio (xy 0 0) 1 2)

; ERRO: Nao foi possivel aplicar a operacao

A razão do erro torna-se evidente quando observamos o aspecto do bi-fólio semi-criado no AutoCad e que se encontra representado na Figura 7: o raio do círculo interior vai-se reduzindo à medida que diminui o número de fólios até se tornar simplesmente zero. De facto, para n = 2, o raio do círculo interior fica

ri = re cosπ2 1 + sinπ2 ou seja, ri = re 0 2 = 0

Uma vez que o AutoCad não conseguiu criar a região correspondente por esta ter área zero, o nosso processo de detecção de erros detectou a situação e avisou-nos do problema.

Não é difícil corrigir o problema inserindo um teste na função n-folio que evite fazer a união das folhas com o círculo interior quando este tem raio zero. Contudo, essa não é a melhor opção pois, do ponto de vista matemático, o algoritmo de construção de fólios que tínhamos idealizado continua perfeitamente correcto: a união de um círculo de raio zero aos círculos correspondentes às folhas não deveria alterar o resultado, pois o círculo de raio zero corresponde à região vazia ∅ que é, obviamente, um elemento neutro da união de regiões. Este é um comportamento funda-mental que deveria ser assegurado pelas operações que lidam com regiões.

(20)

De nada serve usar a matemática como inspiração para os nossos algorit-mos se a linguagem onde escrevealgorit-mos esses algoritalgorit-mos não nos garante as mesmas propriedades da matemática.

Esta diferença entre a matemática e o AutoCad ocorre por uma ques-tão de conveniência: se, por distracção, estivermos a intersectar duas re-giões que nada têm em comum, é-nos útil que o AutoCad nos avise desse facto pois, muito provavelmente, isso corresponde a um erro. Infelizmente, essa conveniência do AutoCad torna-se numa inconveniência quando nos obriga a reestruturar algoritmos que, do ponto de vista matemático, estão perfeitamente correctos. Esta diferença de pontos de vista prende-se com o facto de o AutoCad estar mais orientado para um utilizador que pretende desenhar interactivamente do que para um utilizador que pretende dese-nhar programaticamente. Este último, como consequência da forte ligação existente entre a programação e a matemática, tem de lidar com conceitos matemáticos que simplesmente não são tidos em conta durante o desenho interactivo.

Assim, embora a região vazia seja um elemento fundamental da álge-bra de regiões, ela não está contemplada na implementação de regiões que o AutoCad disponibiliza. Contudo, nada nos impede de a introduzir como conceito novo. Assim, a bem da preservação do rigor matemático do nosso algoritmo de construção de fólios, é preferível tornar explícito o conceito de região vazia. Esta região, que não tem qualquer significado para o Au-toCad, terá de ser tratada especialmente por nós de modo a preservar as propriedades matemáticas da união, intersecção e subtracção de regiões.

Para isso, comecemos por introduzir um construtor e um reconhecedor de regiões vazias. Em termos de representação, apenas temos de conseguir distinguir a região vazia das regiões “normais” (entidades) criadas pelo AutoCad, o que conseguimos facilmente empregando, por exemplo, o nú-mero zero.

(defun regiao-vazia () 0)

(defun regiao-vazia? (regiao) (= regiao 0))

Para garantirmos que a região vazia é um elemento neutro da união de regiões, temos de detectar se algumas das regiões argumento é a região vazia, caso em que devolvemos a outra região:

(21)

(defun uniao (r0 r1) (cond ((regiao-vazia? r0) r1) ((regiao-vazia? r1) r0) (t (command "_.union" r0 r1 "") r0)))

Com base nesta nova possibilidade de criar regiões vazias, podemos agora redefinir a função circulo-interior-folio de modo a que, quando o número de folhas for dois, a função devolve uma região vazia:

(defun circulo-interior-folio (p re n) (if (= n 2) (regiao-vazia) (regiao (circulo p (* re (/ (cos (/ pi n)) (+ 1 (sin (/ pi n)))))))))

Empregando esta redefinição da função, já é possível avaliar a expres-são (n-folio (xy 0 0) 1 2) sem gerar qualquer erro e produzindo o bifólio correcto.5

A introdução do conceito de região vazia vem agora simplificar algu-mas situações. Por exemplo, a função uniao-circulos, que recordamos em seguida, embora cumpra a sua obrigação, é desnecessariamente com-plexa.

(defun uniao-circulos (p ro fi d-fi rf n) (if (= n 1)

(regiao (circulo (+pol p ro fi) rf)) (uniao

(regiao (circulo (+pol p ro fi) rf))

(uniao-circulos p ro (+ fi d-fi) d-fi rf (1- n)))))

Reparemos que a função anterior repete, no caso de paragem, a mesma expressão que emprega no caso recursivo. Para simplificarmos a função, comecemos por perceber que o que ela faz, quando atinge o caso de para-gem n = 1, é computar

5Sendo possível gerar bifólios, trifólios, quatrifólios e n-fólios, é legítimo pensar

tam-bém nos conceitos de unifólio e de zerofólio e tentar imaginar as suas formas. Infelizmente, aqui chocamos com limites matemáticos mais difíceis de ultrapassar: quando o número de fólios é um, o raio rido círculo interior fica negativo, perdendo todo o sentido geométrico;

quando o número de fólios é zero, a situação é igualmente absurda, pois o ângulo α torna-se uma impossibilidade devido à divisão por zero. Por estes motivos, o bifólio é o limite inferior dos n-fólios.

(22)

(regiao (circulo (+pol p ro fi) rf))

Imaginemos agora que a função estabelecia a condição de paragem para n = 0. A sua definição seria então da seguinte forma:

(defun uniao-circulos (p ro fi d-fi rf n) (if (= n 0)

??? (uniao

(regiao (circulo (+pol p ro fi) rf))

(uniao-circulos p ro (+ fi d-fi) d-fi rf (1- n)))))

Para sabermos qual seria o valor correcto ??? a retornar no caso de pa-ragem, basta-nos pensar que para que esta nova definição seja compatível com a anterior, será necessário que o resultado da sua invocação seja igual, ou equivalente, ao que obtíamos com a definição anterior. Ora, para n = 1, a nova definição produz, como resultado:

(uniao (regiao (circulo (+pol p ro fi) rf))

(uniao-circulos p ro (+ fi d-fi) d-fi rf 0))

Naturalmente, para que haja equivalência entre as duas computações, é necessário que (uniao-circulos p ro (+ fi d-fi) d-fi rf 0) seja a região vazia. Assim, torna-se evidente que a definição correcta da função uniao-circulosé

(defun uniao-circulos (p ro fi d-fi rf n) (if (= n 0)

(regiao-vazia) (uniao

(regiao (circulo (+pol p ro fi) rf))

(uniao-circulos p ro (+ fi d-fi) d-fi rf (1- n)))))

Como podemos ver, a última definição é muito mais simples e clara que a primeira, embora faça uso de um conceito matemático fundamental que não tem expressão nativa no AutoCad. É nossa responsabilidade, como programadores, sermos capazes de dotar as linguagens em que queremos trabalhar dos mecanismos que entendemos serem-nos úteis para facilitar esse trabalho.

Através da introdução do conceito de região vazia é agora trivial defi-nir muitos outros operadores de mais alto nível. Por exemplo, para gene-ralizarmos a união de conjuntos de regiões a regiões arbitrárias podemos definir a função unioes que recebe uma lista com todas as regiões a unir. Se essa lista está vazia, a resposta óbvia será, como anteriormente, a região vazia:

(23)

(defun unioes (regioes) (if (null regioes)

(regiao-vazia) (uniao

(car regioes)

(unioes (cdr regioes)))))

No caso de pretendermos a intersecção de um conjunto de regiões já a situação parece mais complicada. Embora seja trivial escrever um primeiro esboço

(defun interseccoes (regioes) (if (null regioes)

???

(interseccao (car regioes)

(interseccoes (cdr regioes)))))

já não é tão evidente saber o que colocar no lugar de ???. Para melhor percebermos o problema, podemos fazer uma analogia com os problemas de somar uma lista de números e de multiplicar uma lista de números. O primeiro é resolvido trivialmente pela seguinte função:

(defun soma (numeros) (if (null numeros)

0

(+ (car numeros)

(soma (cdr numeros)))))

Para o segundo problema, temos de perceber o papel fundamental que o zero representa na função anterior. Naquele contexto, o zero representa o elemento neutro da adição, pois só assim faz sentido que possamos ir reduzindo o problema de somar vários números a problemas sucessiva-mente mais simples, em que somamos cada vez menos números, até já não termos quaisquer números para somar. Nesse momento, para que as somas que ainda estão pendentes possam computar o resultado correcto, é funda-mental que o valor da função para uma lista vazia de números não afecte as somas, algo que só pode ser obtido se esse valor for o elemento neutro da soma. Do mesmo modo, para a definição da função que multiplica to-dos os números de uma lista apenas temos de pensar no elemento neutro da multiplicação—o número um—e usá-lo como valor da função quando a lista de números está vazia, i.e.:

(defun produto (numeros) (if (null numeros)

1

(* (car numeros)

(produto (cdr numeros)))))

Tal como considerámos que a região vazia era o elemento neutro da união de regiões, para achar a intersecção dessas regiões também teremos

(24)

que encontrar o elemento neutro da intersecção de regiões. Felizmente, não é difícil concluir que esse elemento neutro é, necessariamente, a região universal U , i.e., a região que inclui todos os pontos do plano. Assim, já podemos definir:

(defun interseccoes (regioes) (if (null regioes)

(regiao-universal) (interseccao

(car regioes)

(interseccoes (cdr regioes)))))

Infelizmente, o AutoCad não implementa o conceito de região universal e, por isso, à semelhança do que fizemos para a região vazia, teremos de ser nós a providenciar este conceito. Assim, vamos começar por definir um construtor e um reconhecedor para esta nova entidade:

(defun regiao-universal () 1)

(defun regiao-universal? (regiao) (= regiao 1))

Note-se que empregámos o número um como representação para que não possa ser confundido nem com uma entidade “normal,” nem com a representação da região vazia. De seguida, temos apenas de redefinir as operações de união, intersecção e subtracção de regiões de modo a imple-mentar o comportamento matemático pretendido, nomeadamente, as se-guintes equações da álgebra de regiões:6

R ∪ ∅ = ∅ ∪ R = R R ∪ U = U ∪ R = U

R ∪ R = R R ∩ ∅ = ∅ ∩ R = ∅ R ∩ U = U ∩ R = R

6Estas equações são apenas um subconjunto das equações que seria possível

implemen-tar. Por exemplo, poderá ser razoável incluir também as equações:

∅ \ R = ∅ R \ R = ∅

No entanto, a implementação dessas equações poderia involutariamente “mascarar” ver-dadeiros erros nos nossos programas. De facto, embora possa estar matematicamente cor-recto, do ponto de vista algorítmico não parece fazer muito sentido que se subtraia a uma região a própria região. Por este motivo, implementámos apenas as equações que algorit-micamente nos são úteis.

(25)

R ∩ R = R R \ ∅ = R

Traduzindo as equações anteriores para Lisp, obtemos:

(defun uniao (r0 r1) (cond ((regiao-vazia? r0) r1) ((regiao-vazia? r1) r0) ((or (regiao-universal? r0) (regiao-universal? r1)) (regiao-universal)) ((eq r0 r1) r0) (t (command "_.union" r0 r1 "") r0))) (defun interseccao (r0 r1) (cond ((regiao-universal? r0) r1) ((regiao-universal? r1) r0) ((or (regiao-vazia? r0) (regiao-vazia? r1)) (regiao-vazia)) ((eq r0 r1) r0) (t (command "_.intersect" r0 r1 "") r0))) (defun subtraccao (r0 r1) (cond ((regiao-vazia? r1) r0) (t (command "_.subtract" r0 "" r1 "") r0)))

Usando estas definições, já é possível escrevermos algoritmos de acordo com a nossa imaginação sem termos de nos preocupar com as idiossincra-sias do AutoCad no que diz respeito à combinação de regiões.

Exercicio 1.1 A álgebra de regiões que elaborámos encontra-se incompleta por não incluir a operação de complemento de uma região. O complemento RCde uma região R define-se

como a subtracção à região universal U da região R:

RC= U \ R

A operação de complemento permite representar o conceito de buraco. Um buraco com a forma da região R obtém-se simplesmente através RC. Um buraco não tem representação

(26)

é buraco mas, do ponto de vista matemático, o conceito faz todo o sentido, desde que as operações algébricas sobre regiões o saibam interpretar. Por exemplo, dado o buraco RC

1,

posso aplicá-lo a uma região R0através da intersecção das duas regiões R0∩ RC1. Como

o AutoCad não sabe lidar com complementos de regiões, a operação terá de ser traduzida em termos de outras operações já conhecidas. Neste caso, a subtracção é uma escolha óbvia pois R0∩ RC1 = R0\ R1.

Para completar a álgebra de buracos é necessário definir o resultado das operações de união, intersecção e subtracção quando aplicadas a buracos. Defina matematicamente essas operações, bem como a combinação entre regiões “normais” e buracos.

Exercicio 1.2 Uma vez que o AutoCad não implementa o conceito de complemento, defina um construtor para complementos de regiões. O construtor deverá receber a região da qual se pretende o complemento e deverá devolver um objecto que represente simbolicamente o complemento da região. Não se esqueça que o complemento do complemento de uma região é a própria região.

Defina também um reconhecedor de complementos que poderá receber qualquer tipo de objecto e devolverá verdade apenas para aqueles que representam complementos de regiões.

Exercicio 1.3 Redefina as operações de união, intersecção e subtracção de regiões de modo a lidarem com complementos de regiões.

Exercicio 1.4 Considere a construção de uma região composta por uma união recursiva de polígonos regulares sucessivamente mais pequenos e centrados nos vértices do polígono imediatamente maior, tal como se pode ver nos três exemplos apresentados na seguinte figura:

Tal como acontecia com a função vertices-poligono-regular definida na Sec-ção ??, cada um destes polígonos é caracterizado por estar inscrito numa circunferência de raio r centrada num ponto p, por ter um “primeiro” vértice que faz um ângulo φ com o eixo dos X e por ter um determinado número de lados n. Para além disso, a construção dos polígonos regulares é feita de modo a que cada vértice seja o centro de um novo polígono idêntico, mas inscrito num círculo cujo raio é uma fracção (dada por αr) do raio r, sendo

este processo repetido um determinado número de níveis. Por exemplo, na figura anterior, a imagem mais à esquerda foi feita com p = (0, 0), r = 1, φ = 0, αr= 0.3, n = 4 e com um

número de níveis igual a 2. No conjunto, as imagens foram produzidas pela avaliação das seguintes expressões:

(poligonos-recursivos (xy 0 0) 1 0 0.3 4 2) (poligonos-recursivos (xy 3 0) 1 pi/3 0.3 3 3) (poligonos-recursivos (xy 6 0) 1 0 0.3 5 4)

(27)

Figura 8: As torres Petronas, localizadas em Kuala Lumpur, na Malasia. Fotografia de Mel Starrs.

(28)

Exercicio 1.5 As torres Petronas foram desenhadas pelo arquitecto Argentino César Pelli e foram consideradas os edifícios mais altos do mundo desde 1998 até 2004. A Figura 8 mostra uma perspectiva do topo de uma das torres.

A secção das torres, fortemente inspirada em motivos islâmicos, é composta por dois quadrados rodados de um quarto de círculo que se intersectam e ao qual se adicionam círculos nos pontos de intersecção, tal como se pode ver no seguinte esquema construtivo.

l

Note-se que os círculos são tangentes às arestas imaginárias que ligam os vértices. Defina uma função Auto Lisp denominada seccao-petronas que recebe o centro da secção e a largura l e produzem a secção da torre Petronas. Sugestão: use as funções poligono-regulare uniao-circulos para gerar as regiões relevantes.

Exercicio 1.6 Defina a função torre-petronas que, a partir do centro da base, constrói uma sucessão de secções da torre Petronas de modo a reproduzir a geometria real da torre Petronas, tal como se ilustra na seguinte perspectiva onde a função foi invocada duas vezes em posições diferentes:

(29)

Figura 9: Combinações de volumes. A imagem da esquerda representa a união de um cubo com uma esfera, a imagem do centro representa a inter-secção do cubo com a esfera e a da direita representa a subtracção do cubo pela esfera.

1.6 Superfícies e Volumes

Nas secções anteriores definimos um conjunto de operações que consti-tuem uma álgebra de regiões. Nesta secção vamos estender essas operações para o tratamento de superfícies e volumes.

1.6.1 Combinação de Sólidos

Uma das técnicas mais simples para a modelação de sólidos é a da geo-metria construtiva de sólidos. Esta abordagem baseia-se na combinação de formas tridimensionais simples, como paralelipípedos, esferas, pirâmides, cilindros, toros, etc. Estas formas denominam-se primitivas e a combina-ção é feita usando operações de conjuntos como a união, a interseccombina-ção e a subtracção de volumes.

A Figura 9 exemplifica estas operações para dois sólidos—um cubo e uma esfera. A imagem da esquerda apresenta a união dos dois sólidos, obtida a partir da seguinte sequência de expressões em Auto Lisp:

(command "_.box" (xyz 0 0 0) (xyz 1 1 1)) (setq cubo (entlast))

(command "_.sphere" (xyz 1 1 1) 0.5) (setq esfera (entlast))

(command "_.union" cubo esfera "")

Ainda na Figura 9, a imagem do centro apresenta a intersecção dos mesmos sólidos (obtida com a operação intersect e a imagem da di-reita apresenta a subtracção do cubo pela esfera (obtida com a operação

(30)

subtract). Uma vez que as operações que o AutoCad disponibiliza para operar com volumes são exactamente as mesmas que disponibiliza para operar com regiões, tudo o que definimos nas secções anteriores para re-giões é aplicável a volumes. De facto, do ponto de vista matemático, tal como uma região pode ser vista com um conjunto de pontos no espaço bidi-mensional, também um sólido pode ser visto como um conjunto de pontos no espaço tridimensional. Nesta interpretação, as operações de combinação de sólidos correspondem directamente às mesmas operações de conjuntos que empregámos para as regiões.

De modo a facilitar a composição funcional de volumes, vamos seguir a mesma abordagem que explorámos para as regiões e vamos definir fun-ções para a construção dos sólidos fundamentais que produzem, como re-sultado, a entidade criada pelo AutoCad. Por exemplo, para uma esfera, podemos definir:

(defun esfera (centro raio)

(command "_.sphere" centro raio) (entlast))

Para a caixa, temos:

(defun caixa (p0 p1) (command "_.box" p0 p1) (entlast))

Com estas duas funções, podemos reescrever o exemplo anterior mais simplesmente como:

(uniao

(caixa (xyz 0 0 0) (xyz 1 1 1)) (esfera (xyz 1 1 1) 0.5))

Exercicio 1.7 Pretende-se modelar uma bacia de pedra idêntica à que se apresenta na ima-gem seguinte:

(31)

Os parâmetros relevantes para a bacia encontram-se representados no alçado frontal, planta e alçado lateral apresentados na imagem seguinte:

e P r P r e e P r

Defina uma função denominada bacia que constroi uma bacia idêntica à da figura anterior.

Vários outros sólidos fundamentais podem ser definidos de modo idên-tico. Por exemplo, um cilindro pode ser definido pelo centro e raio da base e pelo centro do topo:

(defun cilindro (centro-base raio centro-topo)

(command "_.cylinder" centro-base raio "_Axis" centro-topo) (entlast))

Como exemplo de utilização, consideremos três cilindros dispostos se-gundo os eixos X, Y e Z. A união destes cilindros está visível no lado esquerdo da Figura 10 e foi gerada pela expressão

(unioes

(list (cilindro (xyz -1 0 0) 1 (xyz 1 0 0)) (cilindro (xyz 0 -1 0) 1 (xyz 0 1 0)) (cilindro (xyz 0 0 -1) 1 (xyz 0 0 1))))

Este objecto tem a propriedade de, quando visto em planta, alçado late-ral e alçado frontal, se reduzir a um quadrado. No lado direito da mesma figura encontra-se um sólido ainda mais interessante. Ele foi gerado pela intersecção dos mesmos três cilindros, produzindo um objecto que, obvia-mente, não é uma esfera mas que, tal como a esfera, projecta um círculo em planta, em alçado frontal e em alçado lateral.

Para melhor percebermos a diferença entre o objecto construído pela in-tersecção dos cilindros e uma verdadeira esfera, podemos subtrair a esfera

(32)

Figura 10: A união e intersecção de três cilindros dispostos ortogonal-mente.

ao objecto. Para podermos “espreitar” o interior do objecto, vamos usar uma esfera com um raio (muito) ligeiramente maior que o dos cilindros:

(subtraccao (interseccoes

(list (cilindro (xyz -1 0 0) 1 (xyz 1 0 0)) (cilindro (xyz 0 -1 0) 1 (xyz 0 1 0)) (cilindro (xyz 0 0 -1) 1 (xyz 0 0 1)))) (esfera (xyz 0 0 0) 1.01))

O resultado encontra-se representado na Figura 11.

Exercicio 1.8 Considere a seguinte cobertura feita de abóbadas em arco romano:

Defina uma função denominada cobertura-arcos-romanos que tem como parâ-metros o centro da cobertura, o raio do círculo que circunscreve a cobertura, a espessura da cobertura e o número de arcos a colocar e que produz coberturas como as apresentadas acima. Assegure-se que a sua função consegue gerar a seguinte cobertura de apenas três arcos:

(33)

Figura 11: Subtracção de uma esfera à intersecção de três cilindros disposto ortogonalmente. A esfera tem um raio 1% superior ao dos cilindros por forma a permitir visualizar o interior.

Exercicio 1.9 Pretende-se modelar uma banheira de pedra idêntica à que se apresenta na imagem seguinte:

(34)

Os parâmetros relevantes para a banheira encontram-se representados no alçado fron-tal, planta e alçado lateral apresentados na imagem seguinte:

P r r l e P r r P r e e

Defina uma função denominada banheira que constroi uma banheira idêntica à da figura anterior.

(35)

A imagem representa um abrigo de forma paralelipipédica construído com tubos ci-líndricos cortados de modo a que o espaço interior tenha a forma de um quarto de esfera. Note que os tubos cilíndricos possuem uma espessura que é 10% do raio. Note ainda a relação entre o raio do quarto de esfera e o dos cilindros.

Defina uma função que constrói o abrigo a partir do centro da esfera, da altura do paralelipípedo e do número de tubos a colocar ao longo da altura.

Exercicio 1.11 Refaça o exercício anterior mas agora considerando a orientação dos tubos visivel na imagem seguinte:

Exercicio 1.12 Refaça o exercício anterior mas agora considerando a orientação dos tubos visivel na imagem seguinte:

(36)

Para além de esferas, caixas e cilindros, existem vários outros sólidos elementares úteis como, por exemplo, o cone. Este pode ser construído através da seguinte definição:

(defun cone (centro-base raio-base centro-topo)

(command "_.cone" centro-base raio-base "_Axis" centro-topo) (entlast))

Exercicio 1.13 Considere a construção de uma “esfera” de cones tal como se apresenta na seguinte imagem:

Note que todos os cones têm o seu vértice no mesmo ponto e estão orientados de modo a que o centro da base fica assente numa esfera virtual. Note que todos os “meridianos” e “paralelos” possuem o mesmo número de cones e note também que o raio da base dos cones diminui à medida que nos aproximamos dos “pólos” para que os cones não interfiram uns com os outros.

(37)

Exercicio 1.14 Considere uma variação sobre a “esfera” de cones do exercício anterior em que, ao invés de diminuirmos o raio da base dos cones à medida que nos aproximamos dos pólos, diminuímos o número de cones, tal como se apresenta na seguinte imagem:

Escreva um programa em Auto Lisp capaz de construir esta “esfera” de cones.

Exercicio 1.15 Defina uma função em Auto Lisp capaz de criar cascas esféricas perfuradas, tal como as que se apresentam em seguida:

A função deverá ter como argumentos o centro, raio e espessura da casca esférica, e o raio e número de perfurações a realizar ao longo do “equador.” Este número deverá diminuir à medida que nos aproximamos dos “pólos.”

Exercicio 1.16 Considere a seguinte construção feita a partir de um arranjo aleatório de esferas perfuradas:

(38)

Para modelar a imagem anterior, defina uma função que recebe dois pontos que defi-nem os limites de um volume imaginário (paralelo aos eixos coordenados) dentro do qual estão localizados os centros das esferas e ainda o valor mínimo e máximo do raio de cada esfera, a espessura da casca, o número de esferas a criar e, finalmente os parâmetros neces-sários para realizar o mesmo tipo de perfurações em cada esfera.

Note que o interior da construção deverá estar desimpedido, i.e., tal como se ilustra no seguinte corte:

Se truncarmos um cone no seu topo, obtemos um tronco de cone. Este pode também ser visto como uma generalização do cilindro em que os raios da base e do topo podem ser diferentes. Para um tronco de cone, temos de especificar o centro e raio da base e o centro e raio do topo.

Para construirmos um tronco de cone basta fazermos uma pequena va-riação na invocação do comando cone:

(39)

Figura 12: Três troncos de pirâmide construídos com diferentes ângulos de rotação da base. Da esquerda para a direita o ângulo de rotação é 0, π42.

(defun tronco-cone (centro-base raio-base centro-topo raio-topo) (command "_.cone" centro-base raio-base

"_Top" raio-topo "_Axis" centro-topo) (entlast))

Semelhante ao tronco de cone, mas com uma base poligonal, temos o tronco de pirâmide. O tronco de pirâmide pode ser definido usando o co-mando AutoCad pyramid. Para isso, temos de especificar o número de lados, o centro da base, o raio da circunferência que circunscreve a base, o ângulo de rotação da base, o centro do topo e o raio da circunferência que circunscreve o topo:

(defun tronco-piramide (lados centro-base raio-base angulo centro-topo raio-topo) (command "_.pyramid"

"_Sides" lados centro-base

(raio&angulo raio-base angulo) "_Top" raio-topo

"_Axis" centro-topo) (entlast))

A Figura 12 apresenta o efeito do ângulo de rotação e foi gerada pela avaliação das seguintes expressões:

(tronco-piramide 3 (xyz 0 0 0) 2 0 (xyz 0 0 1) 1) (tronco-piramide 3 (xyz 5 0 0) 2 pi/4 (xyz 5 0 1) 1) (tronco-piramide 3 (xyz 10 0 0) 2 pi/2 (xyz 10 0 1) 1)

O tronco de pirâmide pode ser particularizado de duas maneiras dife-rentes. Se o raio da circunferência do topo for zero, o tronco de pirâmide degenera numa pirâmide. Se o raio da circunferência do topo for igual ao raio da circunferência da base, o tronco de pirâmide degenera num prisma. Assim, podemos definir:

(defun piramide (lados centro-base raio angulo centro-topo) (tronco-piramide

(40)

(defun prisma (lados centro-base raio angulo centro-topo) (tronco-piramide

lados centro-base raio angulo centro-topo raio))

Exercicio 1.17 Um cubo impossível (também conhecido por cubo irracional) é uma famosa ilusão de óptica em que um cubo é apresentado de tal forma que aparenta ter algumas das arestas à frente de outras, numa configuração aparentemente impossível. A imagem seguinte mostra um cubo impossível gerado em AutoCad.

Defina uma função cubo-impossivel que cria cubos impossíveis.

Exercicio 1.18 Um toro é uma superfície de revolução gerada pela translação de um círculo em torno de um eixo coplanar com o círculo mas que não toca o círculo. Defina uma função toroque, a partir do centro do toro, do raio de translação e do raio do círculo, constrói e devolve um toro.

Exercicio 1.19 Considere um cubo construído a partir de um arranjo de cubos mais peque-nos, tal como se apresenta na imagem seguinte:

(41)

Como é fácil de ver, os cubos pequenos possuem, cada um, um terço do lado do cubo construído. Defina uma função que, a partir das coordenadas de um vértice do cubo e do comprimento do lado do cubo a construir, constrói este cubo respeitando o arranjo de cubos pequenos que aparece na imagem anterior.

Exercicio 1.20 A esponja de Menger é um conhecido fractal descoberto pelo matemático Karl Menger. A seguinte imagem mostra vários estágios da construção de uma esponja de Menger.

À semelhança do exercício anterior, a construção de uma esponja de Menger pode ser feita através da composição de cubos mais pequenos, com a nuance de se substituirem os cubos pequenos por (sub-)esponjas de Menger. Naturalmente, no caso de uma implemen-tação em computador, esta recursão infinita é impraticável e, por isso, há que estabelecer uma condição de paragem, a partir da qual não se cria uma (sub-)esponja de Menger mas sim cubo.

(42)

Figura 13: A criação de um tetraedro por sucessivos cortes num paralelilí-pedo envolvente.

Defina a função esponja-menger que recebe as coordenadas de um vértice da es-ponja, a dimensão da esponja e o grau de profundidade desejado para a recursão.

1.7 Corte de Regiões

Para além das operações de união, intersecção e subtracção, o AutoCad dis-ponibiliza a operação de corte. Esta operação permite modificar uma região através do seu corte por um plano. Como é habitual, o AutoCad provi-dencia várias formas diferentes de operar um corte. Uma das mais simples consiste em empregar três pontos para especificar o plano de corte e um quarto ponto localizado de um lado ou outro desse plano para especificar qual a região que se pretende preservar após o corte.

A título de exemplo, consideremos a modelação de um tetraedro. O tetraedro é o mais simples dos sólidos platónicos e caracteriza-se por ser um poliedro de quatro lados triangulares. Esses quatro lados unem-se em quatro vértices que especificam totalmente o tetraedro. Embora o AutoCad disponibilize várias operações para modelar alguns dos sólidos fundamen-tais, como o paralelipípedo ou a pirâmide regular, não disponibiliza uma operação específica para criar tetraedros. Para implementar esta operação, podemos produzir o tetraedro através de cortes num paralelipípedo que envolva totalmente os quatro vértices do tetraedro, tal como apresentamos na Figura 13.

Para especificarmos o paralelipípedo envolvente, basta-nos calcular os valores máximo e mínimo das coordenadas dos vértices do tetraedro. Em seguida, cortamos o paralelipípedo usando os quatro planos corresponden-tes às faces do tetraedro, planos esses definidos pelas combinações dos qua-tro vértices tomados três a três. A função que implementa este processo tem a seguinte forma:

(43)

(defun tetraedro (p0 p1 p2 p3 / pmin pmax solido) (setq pmin (xyz (min (cx p0) (cx p1) (cx p2) (cx p3))

(min (cy p0) (cy p1) (cy p2) (cy p3)) (min (cz p0) (cz p1) (cz p2) (cz p3))) pmax (xyz (max (cx p0) (cx p1) (cx p2) (cx p3))

(max (cy p0) (cy p1) (cy p2) (cy p3)) (max (cz p0) (cz p1) (cz p2) (cz p3))) solido (caixa pmin pmax))

(command "_.slice" solido "" "_3p" p0 p1 p2 p3) (command "_.slice" solido "" "_3p" p1 p2 p3 p0) (command "_.slice" solido "" "_3p" p2 p3 p0 p1) (command "_.slice" solido "" "_3p" p3 p0 p1 p2) solido)

A Figura 13 apresenta as várias fases do processo de “lapidação” do paralelipípedo até se obter o tetraedro.

Exercicio 1.21 A imagem seguinte representa sucessivas iterações da pirâmide de Sier-pi ´nski,7também denominada tetrix. A pirâmide de Sierpi ´nski é um fractal tridimensional que se pode produzir de forma recursiva a partir de um tetraedro imaginário cujos pontos médios de cada aresta constituem os vértices de sub-pirâmides de Sierpi ´nski.

Defina a função sierpinski que, a partir das coordenadas dos quatro vértices e do nível de recursão pretendido, cria a pirâmide de Sierpi ´nski correspondente.

Uma outra forma de se especificar um plano de corte é através de um ponto por onde o plano passa e de outro ponto que define, juntamente com o primeiro, a direcção normal ao plano. Um terceiro ponto, localizado atrás ou à frente deste plano, define qual a região que se pretende preservar com o corte. Para simplificar ainda mais a utilização desta operação, vamos con-vencionar que, ao invés dos três pontos, vamos antes utilizar um ponto por onde passa o plano de corte e um vector unitário que define a direcção nor-mal ao plano. A direcção deste vector definirá também a região a descartar com o corte. Uma vez que a origem do vector é irrelevante, sendo apenas importante a sua direcção, podemos usar um ponto tridimensional para o representar. A definição da função de corte fica então:

7Wacław Sierpi ´nski foi um matemático polaco que deu enormes contribuições à teoria

dos conjuntos e à topologia. Sierpi ´nski descreveu uma versão bidimensional desta pirâ-mida em 1915.

(44)

Figura 14: Gomos de uma esfera. Da direita para a esquerda, o ângulo entre os planos de corte varia desde 0 até π em incrementos de π/6.

(defun corte (p normal regiao)

(command "_.slice" regiao "" "_zaxis" p

(+c p normal) (-c p normal)) regiao)

Como exemplo de utilização desta operação consideremos a criação de um “gomo” (de ângulo de abertura φ) de uma esfera de raio r centrada em p. O gomo é obtido através de dois cortes verticais na esfera.

(defun gomo-esfera (p r fi) (corte p (cil 1 fi 0) (corte p (cil 1 0 0) (esfera p r))))

A Figura 14 apresenta gomos com diferentes aberturas gerados pela se-guinte expressão:

(foreach i (enumera 0 5 1)

(gomo-esfera (xyz (* i 2) 0 0) 1 (* i (/ pi 6))))

Frequentemente, os planos de corte que pretenderemos empregar terão normais paralelas aos eixos coordenados. Para facilitar esses casos, vamos definir constantes apropriadas:

(45)

(setq origem (xyz 0 0 0) eixo-x (xyz 1 0 0) eixo-y (xyz 0 1 0) eixo-z (xyz 0 0 1) -eixo-x (xyz -1 0 0) -eixo-y (xyz 0 -1 0) -eixo-z (xyz 0 0 -1))

Usando estas constantes, podemos facilmente construir sólidos com for-mas complexas. Por exemplo, um oitavo de uma esfera obtém-se trivial-mente através de três cortes:

(corte origem eixo-x

(corte origem eixo-y

(corte origem eixo-z

(esfera origem 2))))

Exercicio 1.22 Considere a calota esférica que se apresenta em seguida, caracterizada pelos dois pontos P0e P1e pelo diâmetro d da base da calota.

P0

P1

C d

Defina a função calota-esferica que recebe os pontos P0e P1 e o diâmetro d da

base da calota. Sugestão: determine a posição e dimensão da esfera e empregue um plano de corte apropriado.

Exercicio 1.23 Do ponto de vista matemático, o corte de uma região por um plano não é mais do que uma intersecção entre essa região e um semi-espaço infinito delimitado por esse plano. Com esta interpretação, podemos criar um oitavo de esfera com a expressão:

(interseccoes (list

(esfera origem 2) (plano origem eixo-x) (plano origem eixo-y) (plano origem eixo-z)))

Infelizmente, o AutoCad não sabe representar regiões de dimensão infinita, pelo que esta visão matemática não é possível sem algum esforço de programação.

Defina a operação plano que, a partir de um ponto e um vector normal ao plano, “cria” o semi-plano infinito correspondente. Para ser consistente com a operação de corte definida atrás, é conveniente considerar que a direcção do vector normal ao plano define a região do espaço que é para excluir.

Redefina ainda a função interseccao de modo a que a intersecção entre uma região e um plano seja transformada num corte.

(46)

Figura 15: Um detalhe do Kunst- und Ausstellungshalle. Fotografia de Hanneke Kardol.

1.8 Extrusões

Vimos nas secções anteriores que o AutoCad disponibiliza um conjunto de sólidos pré-definidos tais como esferas, paralelipípedos, pirâmides, etc. Através da composição desses sólidos é possível modelar formas bastante mais complexas mas, em qualquer caso, essas formas serão sempre decom-poníveis nas formas básicas que estão na sua génese.

Infelizmente, muitas das formas que a nossa imaginação consegue con-ceber não são fáceis de construir apenas através da composição dos sólidos pré-definidos. A título de exemplo, consideremos o Kunst- und Ausstel-lungshalle, um edifício desenhado pelo arquitecto vienense Gustav Peichl e destinado a ser um centro de exposições e de comunicações. Este edifício é de forma quadrada mas um dos “cantos” deste quadrado é cortado por uma sinusóide, representada na Figura 15.

Como é óbvio, se pretendermos modelar a parede ondulada do Kunst-und Ausstellungshalle não haverá nenhum sólido pré-definido que possa-mos usar como ponto de partida para a sua construção.

Felizmente, o AutoCad fornece um conjunto de funcionalidades que permite resolver facilmente alguns destes problemas de modelação. Nesta secção vamos considerar duas dessas funcionalidades, em particular a ex-trusão simples (comando extrude) e a exex-trusão ao longo de um caminho (comando sweep).

(47)

Figura 16: Um polígono arbitrário.

1.8.1 Extrusão Simples

Mecanicamente falando, a extrusão é um processo de fabrico que consiste em fazer passar uma quantidade de material moldável através de uma ma-triz com a forma desejada de modo a produzir peças cuja secção é determi-nada por essa matriz.

No AutoCad, a extrusão é uma operação metaforicamente idêntica à que é usada em fabrico mecânico, embora se parta apenas da matriz que é “extendida” na direcção desejada, assim produzindo uma forma geomé-trica cuja secção é igual à matriz. A extrusão é realizada pelo comando AutoCad extrude que recebe, como argumentos, a sequência de formas que se vão extrudir e o comprimento da extrusão pretendida. Note-se que o AutoCad permite extrudir linhas poligonais, arcos, splines, círculos, elip-ses, regiões, etc. Se o objecto a extrudir for aberto, a extrusão produz ne-cessariamente uma superfície, caso contrário é ainda possível escolher se se pretende produzir uma superfície (fechada) ou um sólido.8 Se o objecto a extrudir tiver linhas que se auto-intersectam a extrusão não é realizável. Convém ter presente que existem algumas limitações no processo de extru-são que impedem a extruextru-são de forma excessivamente complexas.

A título de exemplo, consideremos a Figura 16 onde se mostra um polí-gono arbitrário assente no plano XY . A sua construção e a sua extrusão na direcção Z (para uma altura unitária) são obtidas pelas seguintes expres-sões:

8Esta escolha só é possível a partir do AutoCad 2011. Nesta versão, o comando extrude

disponibiliza uma opção adicional denominada mode que permite ao utilizador especificar se pretende que a extrusão produza uma superfície (usando mode surface) ou um sólido (usando mode solid).

(48)

Figura 17: Um sólido (à esquerda) e uma superfície (à direita) produzidas pela extrusão de um polígono.

(command "_.pline"

(xy 0 2) (xy 0 5) (xy 5 3) (xy 13 3) (xy 13 6) (xy 3 6) (xy 6 7) (xy 15 7) (xy 15 2) (xy 1 2) (xy 1 0) (xy 0 2) "") (command "_.extrude" "_mode" "_solid" (entlast) "" 1)

Note-se que o comando extrude espera receber uma sequência de for-mas planas que serão todas extrudidas simultaneamente. A sequência terá de ser terminada por um “enter” que simulámos através da string vazia. Fi-nalmente, o último argumento do comando é a “altura” da extrusão, i.e., o deslocamento da secção ao longo do eixo Z. A forma resultante está repre-sentada à esquerda, na Figura 17

Na mesma figura, à direita, está representada a extrusão alternativa, que no lugar de produzir sólidos produz superfícies. Esta extrusão pode

Referências

Documentos relacionados

Dentro deste contexto, este trabalho faz a aplicação do método de elementos finitos com a finalidade de avaliar a rigidez torsional, bem como a massa de um chassis tipo space

É apresentada tela com todas as operações compromissadas do ativo informado , a partir da data do sistema, em ordem crescente de data de retorno.. Quando do fim das informações,

Objetivos: identificar a prevalência do diagnóstico de enfermagem Risco de quedas nas internações de pacientes adultos, em unidades clínicas e cirúrgicas, caracterizar o

Aos olhos dos neoliberais a pobreza é vista como a incapacidade do homem de cuidar de si mesmo e não como culpa do sistema que não dá espaço de trabalho para todos, ou seja, na

O confrade mineiro, que foi casado com Meimei e amigo bem próximo de Chico Xavier, fala sobre seu convívio com o saudoso.. médium e diz que Chico e

A implementação do algoritmo em imagens, caso em estudo neste projeto, o processo de criação dos modelos substitutos locais, enunciado no ponto anterior, e a criação de um modelo

Os corta-circuitos têm duas funções: Funciona como interruptor principal para fornecer electricidade ao consumidor e, corta o fornecimento para proteger o gerador quando existir

O CONSORCIO DE DESENVOLVIMENTO DA REGIÃO DE GOVERNO DE SÃO JOÃO DA BOA VISTA – SAMU, inscrito no CNPJ sob o nº 52.356.268/0004-07, torna público que se acha aberta nesta unidade,