Autolisp

Bom, pela enquete, parece que lisp ainda é um assunto interessante!! Que bom, afinal isso livra a gente de muito pepino, hehehe.

O intuíto desta página será dar uma introdução ao autolisp, para que você, que ainda não sabe nada, ou muito pouco do assunto, saiba ao menos de onde começar.

Já aviso, isso não é um curso de autolisp, não é completo e nem tem a pretenção de ser. Acredito muito que a melhor maneira de aprender é o método Sr. Miagui de aprender, hehehe.

Primeiro o jeito difícil, depois o jeito fácil....

A primeira coisa que você deverá saber, é que autolisp não é uma linguagem de programação propriamente dita, na verdade é um pequeno pedaço do LISP, muito usado ainda no linux...

A sintaxe é dela é o que se chama PRÉ FIXADA. Existem três tipo de notação pré fixada, infixada e pós fixada. Mas onde se usa isso?

Exemplos:
Notação pós fixada
HP48, sem dúvida a melhor calculadora científica, financeira, programável, [adjetivos mil], que já conheci. Quem teve ou tem uma sabe do que eu estou falando.... Mesmo a HP50, a meu ver não chegou ao seus pés... Nela somamos dois números assim:

Escrevemos os argumentos, depois o operador. Aí clicamos Enter e obtemos o resultado.

Notação infixada
É como escrevemos no excel, por exemplo:


Escrevemos o primeiro operando(1), em seguida o operador (+), por fim o segundo operando (2)

Notação préfixada
É o que o autolisp usa!!! adivinha como que faz:


Colocamos em primeiro o OPERADOR (+), depois os oprandos (1 e 2)

Mas... e porque os parenteses????
Bom, isso é pra delimitar o escopo do operador.
Imagine a conta:


( * 3 ( + 1 2 ) )

Se não colocamos os parenteses, como vamos saber o que soma e o que multiplica?
Claro existe uma definição melhor pra isso. Procura na wikipédia...
 Note que se escrevêssemos no excel, faríamos:

fx = 3 * ( 1 + 2 )

 E ainda, a sintaxe do autolisp permite fazer isso:


( + 1 2 3 4 )

Economizando parenteses....

Bom, agora que já sabemos a estrutura básica da sintaxe, o que mais precisamos saber???

Primeiro, que é aconselhável usar uma IDE. O AutoCAD possui sua própria IDE para escrever programas em autolisp, é o VLIDE.

Então digite VLIDE na linha de comando, pressione ENTER e veva a tela que se abre:


Note é que apenas um editor de texto metido, hehehe

Você notou que o texto é colorido? Esse é uma feature de todos os IDEs. Eles colorem o texto pelo tipo de objeto. no caso do lisp, temos:



As cores ajudam na visualização do código.

E agora? Agora, você deveria saber formular algorítimos para resolver seus problemas...
Mas como assim?

É o seguinte, escrever porgramas em autolisp, C, C++, VB, java é simples, é so uma questão de sintaxe... o difícil é formular a idéia do algorítimo.


Por exemplo. Precisamos de um programa que numere os pontos de uma poligonal. Simples, não? existem milhares de soluções pra isso já, na internet.... Mas, pense, o que será preciso para escrever este programa?

Veja:

  1. Um nome, para chamarmos ele
  2. Depois de chamarmos, ele deverá pedir a seleção de uma polilinha.
  3. Se temos a polilinha, vamos numerar!! 
  4. Começa com que número?
  5. Temos que obter os vértices da polilinha.
  6. Iterar sobre cada um deles, escrevendo o texto.

Parece simples não? E é!!! Este é o nosso algorítimo para este caso.

E se quisermos somar o comprimento de linhas selecionadas?, novamente, precisamos definir o algorítimo:

  1. Nome para chamarmos o comando
  2. Pedir a seleção de linhas
  3. Iterar em cada linha, calculando seu comprimento e somando com o total anterior
  4. devolver o resultado

Agora, como fazemos cada passo desses? Já dizia, jack, vamos por parte, hehehe

Já definimos o algorítimo, então já temos o problema. Dividimos cada parte dele num problema menor. Agora, vamos resolver um por um.

No primeiro programa, precisamos saber como criar um comando que podemos chamar na linha de comando. Em visual lisp (é o autolisp colorido do VLIDE), fazemos asim:



(defun c:nome_do_comando variaveis locais )
 
;faz alguma coisa legal
)



Note os parentese em vermelho, a função defun em azul, o nome do comando em preto
 Agora, escreva isso no VLIDE e salve com o nome que você quiser:



Já resolvemos o primeiro problema. Agora, como pedimos a seleção de uma polilinha?
Aqui vamos fazer uma pausa, porque eu não vou explicar todas as funções do visual lisp. Então sugiro você dar uma olhada no help .


No geral, as funções que pedem alguma coisa na linha de comando do AutoCAD, começam com GET. Então vamos olhar as funções que começam com G!! Se não achar nada, podemos procurar por entity. No visual lisp, as coisas que estão desenhadas na tela do cad são entities (entidades, ou objetos).

Eu encontrei esta: ENTSEL


Vamos ver sua sintaxe:
( entsel [msg] )


E como usamos isso? Confesso que quando comecei a aprender a programar, eu olhava para as funções e nem desconfiava o que era aquilo entre colchetes, hehehehe


Quando algo está entre colchetes no help do visual lisp, é porque é um argumento (ou operando) que é opcional. Neste caso colocar uma [msg] é opcional.


Se fizermos isto na linha de comando do dad:





Percebeu? Ele colocou o texto "Select Object". Mas e se colocarmos outro text, por exemplo:





Ficou bacana, né? E se clicamos a polilinha, será escrito na linha de comando:
Command: ( entsel "\nSelecione a polilinha:" )
Selecione a polilinha:(<Entityname 7fffb5b65a0> (1818.91 577.047 0.0))



Mas o que é isso? Olhando no help (!!!!), são dois valores.

O primeiro < entity 7fffb5b65a0="" name:="" > é um ponteiro para a polilinha ( em C, ponteiro um objeto que nos dá acesso a algo maior, sem blá, blá, blá ). É como o seu CPF, ou RG, ou C.U. (este é um blog de respeito!!).

O segundo valor nada mais é que as coordenadas do cursos na hora do clique (Hum, isso poderá ser útil!!).

Já sabemos como selecionar a polilinha. Precisamos salvar isso numa varivel para usar depois. Mas como salvamos alguma coisa numa variavel em autolisp??

Antes, queriamos pegar (get) alguma coisa. Agora queremos salvar, setar, definir como (set), uma variável. Então no help, encontramos SETQ .


Sua sintaxe é:

setq variavel entsel "\nSelecione a polilinha" ) )


Onde 'variável' será quem armazena alguma coisa e 'valor' é ess alguma coisa. Juntando as duas funções, teremos:

( setq variavel ( entsel "\nSelecione a polilinha" ) )

Já pedimos a seleção, já definimos o comando. Vamos juntar tudo!!




Percebe?. Agora salve. Na linha de comando do cad, digite APPLOAD. Se você ainda não sabe, este é o comando que carrega a nossa lisp para podermos usar como se fosse um comando


Só que aí em umas pegadinhas. O comando só pode ser usado se definimos ele com a função defun e se colocamos o prefixo C: no seu nome.

Olhe novamente para o código. Viu? ( defun c:... 

sem o defun, o autolisp pensará que ( nome_do_comando ) é uma função definida pelo usuário. Em autolisp chamamos isso de subrorina (eu pelo menos... ) e esta está sendo CHAMADA e não DEFINIDA.

E se esquecemos do C:, a subrotina não é acessivel na linha de comando como se fosse um comando. a unica forma de chamar seria assim:

( nome_da_subrotina )


Bom, se você já carregou, digite nome_do_comando, na linha de comando!!




Chique, não??

Resolvemos dois problemas!! Agora, precisamos iterar sobre os vértices dessa polilinha.

Iterações em algorítimos se fazem com FOR, DO, WHILE... REPEAT...

Todas as liguagens de programação tem uma estrutura de looping. o Lisp não é diferente. Nele, temos o FOREACH, o WHILE e o REPEAT.

Para iterar, normalmente tambem precisamos de um contador, que é incrementado a cada looping da iteração.

Já temos o ponteiro para  a polilinha ( Entity Name.... ) Mas precisamos do objeto em si, com suas propriedades. No AutoCAD cada objeto é armazenado como uma lista de propriedades, e estas propriedades são classificadas segundo seu significado.


Por exemplo:



((
-1 

< Entity name: 7fffb5b65c0 >
)  (


"LINE"

;tipo de objeto
(
330 
.       
< entity fffb5a19f0 >
)  (


"B3C"

;handle
(
100 

"AcDbEntity"
)  (
67 

0
)  (
410 

"Model"
)  (


"0"

;layer
(
100 

"AcDbLine"
)  (
10 
1840.14 725.607 0.0

;ponto inicial
(
11 
1931.3 769.302 0.0

;ponto final
(
210 
0.0 0.0 1.0
))

Esta é a lista de uma LINE. Para obter a lista de um objeto qualquer, digite, na linha de comando:


(entget ( car (entsel ) ) )


Não se preocupe em não entender a inha acima agora. é so pra testar.

Olhando para a lista, vemos que temos uma lista organizada, onde cada item é uma outra lista, que contem 3 ou mais coisas.

Basicamente cada item é um objeto que possui um identificador e um valor. o Ponto serve para delimitar onde termina o identificador e onde começa o valor.

Assim:
 0 (zero) serve para dizer qual o tipo do objeto, que pode ser "LINE", "LWPOLYLINE", etc
8, é o layer do objeto
10, é a coordenada inicial (no caso de lines)
11, é a coorenada final (no caso de lines)
410, diz se está no model ou paper (na verdade em qual espaço se encontra o objeto)


Para polilinhas, temos,

IdentificadorValorDescrição
0"LWPOLYLINE"Tipo de objeto
8"0"layer da polilinha
905Número de vértices
101 2Coordenadas X e Y em OCS do vértice. tem um desses para cada vértice

Claro que tem mais um monte de outros. Veja quais são em DXF ENTITIES

Então é só escolher os identificadores que começam com 10 para obter as coordenadas, correto? Sim Daniel Sam!!!

Lembra que eu disse que tem o FOREACH? Então. Sua sintaxe é:

(FOREACH var lista 
 ;faz algo legal
)

Ele faz um looping, atribuindo o valor do item Nésimo à variavel 'var' e executa alguma coisa com esta variável.

Volte no seu programa.

Pegamos a polilinha e armazenamos seu ponteiro na variável chamada 'variavel'

Mas esta variavel também armazena o ponto clicado. No momento ele não nos interessa. Vamos pegar somente o promeiro elemento que é o ponteiro. Pra pegar o primeiro elemento de uma lista, podemos usar a função:

( NTH N lista )

(Ah, resolvemos mais um pequeno problema. Como pegar o Nésimo item de uma lista!!!)

E como fazemos para obter a LISTA????

Uma pausa!!



o Ponteiro ( Entiny Name.... ) chamamos de ENAME.
a lista que o ENAME aponta é o ELIST




Para obter o ELIST, usamos a função

( ENTGET ename ) 

 Juntando então estes pedaços, temos:




(defun c:nome_do_comando variavel ename elist )
  
;pede a selecao da polilinha
  (setq variavel (entsel "\nSelecione a polilinha"))
  
;pega o ename da polilinha
  (setq ename nth variavel ) )
  
;pega o elist da polilinha
  (setq elist (entget ename ) )
  
;itera sobre os item da elist
  (foreach obj elist
    
;faz algo legal 
    )
)




Agora, falta sabermos como desenhar um texto, como verificar se o item OBJ é uma coordemada ou outra coisa e outros probleminhas menores!!

Lembra que eu falei sobre subrotinas?
Bom, podemos usar uma que eu ja fiz, é a draw-text.

Sua sintaxe é assim:
(draw-text str pt lay rot alt st ali )

Onde:
str, STRING é o texto que queremos escrever
pt, ( X Y ), coordenadas
lay, STRING, nome do layer que o texto ficará
rot, REAL, rotação em radianos em relação ao WCS
alt, REAL, altura do texto
st, STRING, é o textstyle
ali, STRING, mc, bc, l, ml.... alinhamento do texto

ou se você preferir, poderá simplesmente fazer:

( command "._text" pt alt rot str "" )

Eu particularmente não gosto do command... Você até pode achar mais simples, mas quando for usar DCL, talvez vocÊ entenda porque não usar ele.....


De qualquer forma, resolvemos mais um pedaço do problema. Vou supor que você escreveu a segunda opção, usando o command. Mas para que você entenda a idéia de subrotina, vamos escrever ele como uma subrotina, assim:



;subrotina que desenha textos
(defun draw-text (str pt lay rot alt st ali)
  (
command
    
"._text" "J" ali ;alinhamento do text
    pt               ;ponto de iserção do texto
    alt              ;altura do texto
    rot              ;rotação
    str              ;o texto a ser escrito
    )
  )



Esta subrotina, irá funcionar?
Talvez. Se o OSNAP estiver ligado, pode ser que ele atrapalhe!!
Se o estilo de texto não existir, dá erro!!
Se o estilo de texto existir e tiver altura de texto diferente de zero, dá erro!!!
Então esses são os motivos pelos quais eu não gosto do COMMAND ...
A principio, deixe assim mesmo. Depois melhoramos o nosso programa.

Lembra do FOREACH ? e o ELIST?

no ELIST, precisamos somente daqueles items que se identificam com o ID=10

então, precisamos testar, se o identificador é realmente o 10.
Pra isso, podemos adicionar um IF!!!

Qual a sintaxe do IF? O help, diz:

(if teste
    ( then_alguma_coisa ) ; se teste é diferente de NIL
    ; [ (else_outra_coisa ) ] ; se teste é nil
)

Em lisp, tudo menos o NIL é verdadeiro.

Vamos, lá, fica assim:


Note que adicionei algumas funções que não comentei. São elas: CAR, CDR.Nada de mais.

Agora vamos testar!! Salve a lisp, Carregue com APPLOAD

O que faltou???
Incrementar o contador, claro!!!!

Vamos fazer uma pequena alteração no programa. Localize a linha depois do If:



Escreva :
 (setq cont (1+ cont ) ) 
Nesta linha

Peraí, eu posso escrever função dentro de outra função?

Pode, mas tome cuidado. O lisp sempre devolve o último argumento avaliado (putz, nem eu entendi isso... )

É assim, se um bloo e parenteses faz uma porção de coisas, por exemplo:

( setq a 1 b ( + a 1 ) )

Isso retorna 2. Pois 1 é armazenado em 'a', depois a é somado a 1, o resultado é armazanado em 'b'
O armazenamento em 'b' 'r a última coisa avaliada, efetuada, calculada, no bloco do setq. então isso é retornado....

Então voltemos ao código....

Salve. Carregue com APPLOAD. Teste!!!

Deu certo??

Então use o UNDO para desfazer....
O que acontece? Precisa fazer UNDO tantas vezes quanto o número de vértices, certo?

Isso não é o comportamento mais desejado. Seria interessante que com apenas UM UNDO, desfizesse tudo.

Este é outro problema, correto?

Outra coisa, clique F2. Olhe a linha de comando.... tosco né? Precisamos que não escreva nada alem do necessário!!! Isso é ainda mais interessante qnado compilamos a nossa lisp para VLX... para proteger o código.

Pior ainda, ligue o OSNAP e deixe o INSERT ligado...

Pode ser que os textos se sobreponham todos na mesma coordenada!!!! pois o comando texto pode achar o INSERT do primeiro ou de um texto qualquer!!!

Não vou colar o código todo aqui. Quero que você o digite!!! Miaghi, lembra???

Gostou? Compartilha!!!

Na próxima, eu digo como resolver esses probleminhas acima!!!


Um abraço ao Luis Silva, que havia salvo as imagens em um documento do WORD para consulta e me possibilitou arrumar o tutorial!!

LinkWithin

Related Posts Plugin for WordPress, Blogger...