Escolar Documentos
Profissional Documentos
Cultura Documentos
NDICE DE CONTENIDOS
INTRODUCCIN
PRIMERA PARTE:
EL ENTORNO DE DESARROLLO VISUAL LISP
1. VISUAL LISP
2. EL ENTORNO DE DESARROLLO VISUAL LISP
o
o
o
o
o
SEGUNDA PARTE:
TCNICAS FUNDAMENTALES DE LA PROGRAMACIN LISP
1. TIPOS DE DATOS
o
o
o
TOMOS
TOMOS SIMBLICOS (S-ATOMS)
CONSTANTES
NMEROS
CADENAS DE TEXTO
LISTAS Y CONSES
LISTAS DE UN NIVEL
LISTAS ANIDADAS
LISTAS DE ASOCIACIN (A-LIST)
LA LISTA VACA (NIL)
FUNCIN TYPE: EXAMEN DEL TIPO DE DATO
FUNCIONES RECURSIVAS
EXTRACCIN DE LOS VRTICES DE UNA
POLILNEA
FUNCIONES ITERATIVAS
REPETICIN UN NMERO DETERMINADO
DE VECES
ITERACIONES SOBRE ELEMENTOS DE UNA
SECUENCIA
CICLOS DEPENDIENTES DE UNA
CONDICIONAL
FUNCIONES DE MAPEADO SOBRE SECUENCIAS
EXTRACCIN DE LOS VRTICES DE UNA
POLILNEA
Una solucin ms eficaz.
CUNDO RECURSIN Y CUNDO ITERACIN?
TERCERA PARTE:
ACCESO A LA BASE DE DATOS GEOMTRICA
Visual LISP
La Ventana de la Aplicacin
Cut
Borra el texto seleccionado de la Consola y lo transfiere al
Portapapeles de Windows**.
Copy
Copia el texto seleccionado al Portapapeles de
Windows**.
Paste
Pega el contenido del Portapapeles de Windows en la
posicin indicada por el cursor**.
Clear Console window
Vaca la Ventana de la Consola.
Find
Busca el texto especificado en la Consola.
Inspect
Barras de Herramientas
Men Contextual
Teclas Rpidas
Copias de Seguridad
Autocad
Otras Ventanasde Visual LISP, incluyendo las de otros ficheros abiertos
para su edicin.
La Consola Visual LISP
La ventana de Inspeccin de objetos LISP y AutoCAD.
El Trace Stack, que guarda la memoria de pila de errores.
El Symbol Service para la gestin de Smbolos.
La Utilidad de Apropos.
La Utilidad de Watch.
Utilidades de Depuracin
Slo tres de las herramientas se encuentran disponibles cuando est activa la
ventana del Editor:
<CTRL> + <S>
Guarda el contenido de la ventana activa del Editor.
<CTRL> + <ALT> + <S>
Guarda el contenido de la ventana activa del Editor con
otro nombre de archivo.
<CTRL> + <SHIFT> + <S>
Guarda el contenido de todas las ventanas de Editor
abiertas.
<CTRL> + <F4>
Cierra la ventana de Editor activa.
<CTRL> + <P>
Insertar Fecha.
Insertar Hora.
Definir el formato de fecha y
hora.
Insertar el contenido de un
archivo de texto en el lugar
indicado por el cursor
Comandos de Bsqueda:
<CTRL> + <F>
Buscar texto.
<CTRL> + <H>
Buscar y sustituir texto.
<CTRL> + <BARRA ESPACIADORA>
<CTRL> + <W>
Aadir una expresin a la ventana de Vigilancia (WATCH).
<F9>
Aade o suprime un punto de interrupcin en la posicin
actual del cursor.
<CTRL> + <SHIFT> + <F9>
Suprime todos los puntos de interrupcin.
<CTRL> + <F9>
Busca y resalta el cdigo que dio origen a la ltima
interrupcin.
Herramientas de Desarrollo:
<ALT> + <F6>
Ajusta la ventana activa al espacio disponible en pantalla.
Comprobacin del cierre de parntesis
Las combinaciones de teclas <CTRL> + <(> y <CTRL> +
<)> permiten localizar el parntesis de apertura o el
parntesis de cierre respectivamente que corresponda a
partir de la posicin donde se sita el cursor. Si se pulsa
simultneamente <SHIFT> el texto quedar seleccionado
(en vdeo inverso).
Completar Texto
Cuando ya se ha tecleado un nombre anteriormente, El
editor VLISP facilita el incorporarlo de nuevo al
documento con slo teclear los caracteres iniciales. Si en
el ejemplo de arriba quisiramos teclear de nuevo el
nombre de la funcin PosVert bastara teclear Po y
despus pulsar <CTRL> + <BARRA ESPACIADORA>. Si
en lugar de encontrar PosVert encontrara el nombre de
variable pos, bastara con volver a pulsar <CTRL> +
<BARRA ESPACIADORA> cuantas veces fuera necesaro
para llegar al texto deseado.
TIPOS DE DATOS
LISTAS
a
juan
45
()
(juan)
(a juan 45 z5mn)
((juan 45) a
((z5mn)))
z5mn
CONJUNTOS DE SELECCIN
Los conjuntos de seleccin son grupos compuestos por
uno o varios objetos (entidades). Las rutinas de AutoLISP
permiten aadir o suprimir de forma interactiva objetos
de los conjuntos de seleccin.
NOMBRES DE ENTIDAD
Un nombre de entidad es un identificador numrico
asignado a los objetos de un dibujo. En realidad, se trata
de un puntero a un archivo mantenido por AutoCAD, en el
que AutoLISP puede encontrar el registro de la base de
datos de objetos. Este puntero suele cambiar de una
sesin de trabajo a otra.
DESCRIPTORES DE ARCHIVO
Los descriptores de archivo son identificadores
alfanumricos asignados a archivos abiertos por Visual
LISP. Cuando sea necesario que una funcin de Visual
LISP lea o escriba en un archivo, debe hacerse referencia
a su identificador.
SUBRUTINAS, SUBRUTINAS EXTERNAS Y
FUNCIONES DE USUARIO
Funciones Nativas LISP o funciones externas cargadas
desde archivos compilados FAS VLX y archivos fuente
LISP.
TABLAS DE PAGINACIN
OBJETOS Y TIPOS DE DATOS ACTIVEX
Objetos propios y determinados formatos para los datos
que se pasan a los mtodos ActiveX.
FUNCIN TYPE
Devuelve el tipo de un elemento designado
(type elemento)
LISTAS Y CONSES
La lista vaca puede por lo tanto ser expresada como (), ya que
se trata de una lista sin elementos.
Una lista punteada (dotted list) es una cuyo ltimo cons no
tiene NIL como su CDR, sino otro objeto de informacin (que
tampoco ser un CONS, ya que entonces el CONS
anteriormente mencionado no hubiera sido el ltimo CONS de
la lista).
LISTAS DE UN NIVEL
Contienen slo tomos.
LISTAS ANIDADAS
Contienen a su vez otras listas que se dicen anidadas.
Estas listas anidadas suelen ser conocidas como sublistas. El nmero de niveles de anidacin no est
restringido ni en su profundidad ni en su complejidad. El
nivel ms externo lo llamamos nivel superior o primer
nivel. A los elementos que conforman este nivel los
llamamos elementos de primer nivel.
LISTAS DE ASOCIACIN (A-LIST)
Son listas anidadas que se utilizan con frecuencia como
estructura de datos en LISP. Una A-LIST es una lista de
pares (CONSES) en que cada par constituye una
asociacin. El CAR de uno de estos pares se conoce como
la CLAVE y el CDR constituye el DATO. Una ventaja de la
representacin como A-LIST es la posibilidad de
incrementarla aadindole nuevas entradas al principio
de la lista. Ms an, como la funcin de bsqueda ASSOC
recorre la A-LIST de manera ordenada, las nuevas
entradas pueden "enmascarar" las ms antiguas de
manera que la informacin puede ser modificada de
forma no destructiva.
LA LISTA VACA (NIL)
Como se dijo antes, es la que no contiene ningn
elemento. Se indica como () y recibe un nombre
particular, el de NIL.
La lista vaca tiene un status peculiar en LISP. Es a la vez
un tomo y una lista. Como smbolo representa el valor
lgico de FALSO:
_$ ()
nil
_$ (atom nil)
T
_$ (listp nil)
T
CIERTO Y FALSO
Su negacin (not nil) sera el smbolo T que representa la
condicin lgica de CIERTO.
(type dato)
La funcin TYPE permite examinar el tipo a que corresponde
un dato determinado. Los datos que evalan como NIL (por
ejemplo tomos simblicos no vinculados a un valor)
devuelven nil.
INT
Nmeros Enteros
REAL
Nmeros de Coma Decimal Flotante
LIST
Listas
STR
Cadenas
SYM
Smbolos
Tipos AutoCAD:
ENAME
Nombres de entidades
FILE
Descriptores de archivo
PAGETB
Tablas de Paginacin de Funciones
PICKSET
Conjuntos de seleccin
SUBR
Funciones AutoLISP internas o funciones cargadas desde
archivos (FAS o VLX) compilados.
USUBR
Funciones de usuario cargadas desde ficheros fuente LSP.
EXRXSUBR
Aplicaciones ObjectARX Externas.
Tipos ActiveX:
SAFEARRAY
Matriz del tipo Safearray. Las matrices que se pasan a los
mtodos ActiveX deben ser del tipo safearray. Estas
matrices son seguras (safe) porque no es posible el
asignar de manera accidental valores fuera de los lmites
de la matriz provocando una excepcin de datos.
VARIANT
Datos del tipo Variant. Los Variant son en esencia
estructuras que se auto-definen y que pueden contener
diferentes tipos de datos. Por ejemplo, cadenas, enteros
y matrices pueden ser representados por Variants. Junto
a los datos se guarda la informacin que identifica el tipo
de dato. Esta caracterstica de auto-definicin hace de los
Variant tiles medios para pasar parmetros a los
servidores ActiveX.
VLA-object
Objetos ActiveX
FUNCIONES
5
FUNCIONES DE ACCESO A LISTAS
CAR
CAR admite un nico argumento que debe ser una lista o
una expresin cuyo valor sea una lista y devuelve el
primer elemento de dicha lista. Como LISP siempre
interpreta una lista como una llamada a una funcin,
necesitamos una manera de pasar una lista a CAR sin que
LISP trate de procesarla como llamada a funcin.
QUOTE
Con este objetivo se suministra la funcin QUOTE . Una
lista dentro de una funcin QUOTE no se tratar de evaluar
como llamada a una funcin. La llamada a la funcin
QUOTE se puede abreviar utilizando el signo apstrofe <
>.
Funciones CDR y NTH:
CDR
EJEMPLOS:
La funcin CONS
(vl-prin1-to-string object)
Devuelve la representacin como cadena de cualquier
objeto LISP tal como si fuera la salida de la funcin PRIN1
_$ (setq file_id (open "test.tmp" "w"))
#<file "test.tmp">
_$ (vl-prin1-to-string file_id)
"#<file \"test.tmp\">"
(vl-princ-to-string object)
Devuelve la representacin como cadena de cualquier
objeto LISP tal como si fuera la salida de la funcin
PRINC
_$ (setq file_id (open "test.tmp" "w"))
#<file "test.tmp">
_$ (vl-princ-to-string file_id)
"#<file test.tmp>"
(vl-string->list string)
Convierte una cadena en una lista de cdigos de carcter
numricos ASCII
_$ (vl-string->list "Madrid")
(77 97 100 114 105 100)
(vl-string-elt string position)
Devuelve la representacin ASCII del carcter situado en
la posicin especificada en una cadena. El primer carcter
ocupa la posicin cero
_$ (vl-string-elt "Madrid" 0)
77
_$ (chr 77)
"M"
_$
(vl-string-left-trim character-set string)
Quita los caracteres especificados del inicio de una
cadena
_$ (vl-string-left-trim "PRE" "PREFIJO")
"FIJO"
(vl-string-mismatch cad1 cad2 [pos1 pos2 ignorarcaja])
DEFUN
DEFUN-Q
FOREACH
FUNCTION
IF
LAMBDA
REPEAT
SETQ
TRACE
UNTRACE
VLAX-FOR
WHILE
LA PRIMITIVA DEFUN
_$ (doble 1)
2
Un programa Lisp usualmente incluye una coleccin de tales
defuns, asemejndose en ello a un fichero de definiciones de
procedimientos en lenguajes tales como C o Pascal.
Pero, segn puntualiza Graham, "algo muy diferente est
sucediendo aqu. Las funciones Lisp son objetos por s mismas.
Lo que realmente hace DEFUN es construir una funcin y
guardarla bajo el nombre que aparece como primer
argumento." Paul Graham, On Lisp, pg. 10
Podemos acceder a la funcin asociada al smbolo DOBLE
utilizando la funcin Visual LISP vl-symbol-value:
_$ (vl-symbol-value 'DOBLE)
#<USUBR @045677ac DOBLE>
En versiones anteriores de AutoLISP la funcin creada con
defun era una lista:
Command: (defun doble (x) (* x 2))
DOBLE
Command: !doble
((X) (* X 2))
Command: (car doble)
(X)
Command: (cdr doble)
((* X 2))
En Visual LISP la funcin de usuario creada con defun es una
funcin compilada que contiene instrucciones en lenguaje de
mquina, por lo tanto en Autocad 2000 obtendremos:
Command: (defun doble (x) (* x 2))
DOBLE
Command: !doble
#<SUBR @01d5ba28 DOBLE>
Command: (car doble)
SIN
(sin ang)
Devuelve el seno de un ngulo expresado en radianes.
COS
(cos ang)
Devuelve el coseno de un ngulo expresado en radianes.
ATAN
(atan num1 [num2])
Devuelve el arcotangente de num1, en radianes, si se le
suministra solamente num1. Si se suministraran ambos
argumentos num1 y num2, ATAN devuelve el arcotangente
de num1/num2, en radianes. Si num2 fuera cero, devolver
un ngulo de ms o menos 1.570796 radianes (+90
grados o 90 grados), segn el signo de num1. El rango
de ngulos devuelto es -pi/2 a +pi/2 radianes.
Funciones de conversin:
(defun infinito ( )
(setq *INF* 2.0)
(while (not (VL-INFP *INF*))
(mapcar
'(lambda (x) (* x x))
'(1 2 3))
Pero una vez incluida la expresin dentro de FUNCTION el
compilador podr optimizar la expresin lambda:
(mapcar
(function (lambda (x) (* x x)))
'(1 2 3))
Lo que redundar en un incremento de la velocidad de
ejecucin al generarse el correspondiente cdigo optimizado en
lenguaje de mquina.
LOAD
.vlx
.fas
.lsp
PREDICADOS
Permiten comprobar caractersticas relacionadas con el
tipo de dato con que se est operando en cada momento.
Devuelve T (cierto) si la condicin se cumple y nil (falso)
en caso contrario.
PREDICADOS GENERALES: Suelen distinguirse
por terminar el nombre de la funcin en la letra P
que significa predicado. Se utiliza la siguiente regla
para decidir si la P est precedida por un guin: si el
nombre del predicado se forma aadiendo la P a un
nombre existente, tal como el nombre de un tipo de
dato, se aade un guin slo en el caso de que el
nombre original incluya alguno (BOUNDP, LISTP,
NUMBERP sin guin VL-FILE-DIRECTORY-P, VLAXERASED-P con guin). Los predicados que fueron
introducidos con Visual LISP se conocen por los
prefijos que se adicionan VL-, VLAX- o VLR- (VLCONSP, VLAX-PROPERTY-AVAILABLE-P, VLR-ADDEDP). En casos como VL-CONSP se hace una excepcin
a la regla anterior, puesto que en realidad se est
renombrando un predicado standard de Common
LISP.
PREDICADOS SOBRE TOMOS Y LISTAS
PREDICADOS ARITMTICOS: Corresponden a las
funciones de comparacin (mayor que, menor que,
igual a...).
OTROS PREDICADOS DEFINIDOS POR EL
USUARIO: muestra de la extensibilidad de LISP.
OPERADORES LGICOS
Corresponden a las operaciones Booleanas bsicas. LISP
suministra tres operadores sobre valores Booleanos: and,
or, y not. De ellos, and y or son tambin en cierto modo
estructuras de control ya que sus argumentos son
evaluados condicionalmente. Permiten agrupar las
condiciones de prueba, casi siempre a partir de la
VL-SYMBOLP
Identifica si un objeto especificado es o no un smbolo.
(vl-symbolp objeto)
Devuelve T si el objeto es un smbolo y nil si se trata de
una constante (nmero o cadena) o una lista.
Este predicado ha sido incorporado por Visual LISP
_$ (vl-symbolp 'a)
T
_$ (vl-symbolp 15)
nil
_$ (vl-symbolp "abc")
nil
_$ (vl-symbolp '(a b c))
nil
BOUNDP
Cuando se trata de un tomo simblico, puede ser
necesario determinar si tiene asociado un valor. BOUNDP
verifica la existencia de dicha asociacin.
(boundp sm)
Devuelve T si sm tiene un valor asociado. Si no hay
ningn valor asociado a sm (o se ha asociado a nil),
boundp devuelve nil. Si sm es un smbolo no definido, se
crea y se asocia a nil de forma automtica.
NUMRICOS:
NUMBERP
Los tomos no simblicos o constantes pueden ser
nmeros o cadenas. NUMBERP comprueba si el objeto es
un nmero (real o entero)
(numberp elemento)
Devuelve T si elemento es un valor numrico y devuelve
nil en caso contrario. El predicado complementario
STRINGP, que comprobara si se trata de una cadena no
est definido en Visual LISP, aunque se puede encontrar
entre los mensajes de error a la hora de depurar un
programa. En el ejemplo que sigue el mensaje "STRINGP
2" significara que se ha recibido un valor numrico (2)
en lugar del argumento esperado del tipo cadena.
_$ (strcat 2 "b")
; error: bad argument type:
stringp 2
MINUSP
Tratndose de valores numricos en ocasiones se deber
comprobar si son negativos. MINUSP realiza dicha
comprobacin.
(minusp nmero)
Devuelve T si nmero es negativo y nil en caso contrario.
MEMBER
Es un tipo particular de predicado, que comprueba si un
tomo pertenece a una lista dada.
(member expr lista)
Si expr no aparece en la lista, member devuelve NIL. En
caso de encontrarlo, devuelve el resto de la lista, desde el
primer caso de la expresin encontrada. Lo devuelto por
MEMBER acta como T (cierto) ya que cualquier valor no
nulo actuar como la negacin de NIL (not NIL), es
decir, cierto. Debe tenerse cuidado en el caso de los
tomos simblicos de pasar el nombre del smbolo
precedido de QUOTE <'>.
NOT
Negacin lgica. Cualquier expresin cuyo valor no sea
NIL evala como falsa. En cambio, (not NIL) evala como
T. Esto sucede puesto que cualquier cosa que no tenga el
valor NIL (o la lista vaca) evala en LISP como T (cierto).
OR
Devuelve el OR lgico de una lista de expresiones
(or expr...)
La funcin o calcula las expresiones de izquierda a
derecha en busca de una expresin distinta de nil. Si la
encuentra, OR deja de realizar clculos y devuelve T. Si el
valor de todas las expresiones es nil, or devuelve nil.
AND
Devuelve el operador lgico AND de una lista de
expresiones
(and expr ...)
Si alguna de las expresiones da como resultado nil, se
interrumpe la operacin y la funcin devuelve nil; en caso
contrario, devuelve T.
FUNCIONES LGICAS BINARIAS
~ (NOT binario)
LOGAND (AND lgico binario)
LOGIOR (OR lgico binario)
BOOLE (operador lgico binario de carcter
general)
6 5 4
0 0 1
64 32 16
0 0 16
4 + 2=22
3
0
8
0
2
1
4
4
1
1
2
2
0
0
1
0
VALOR
BINARIO
1
10
11
100
101
110
111
1000
1001
1010
10000
100000
1000000
1100100
100000000
1000000000
1111110100
18
1024 10000000000
(lsh 9 1)
=> (1 0 1 0)
00001101
00010110
00000100
CONVERSIN DECIMAL->BINARIO
;;;Binario.lsp
;;;El ciclo continuar hasta que LSH devuelva un
valor negativo
;;;significando que se ha llegado al final de la
palabra (posicin
;;;extrema izquierda). El valor binario es devuelto
en formato de lista.
;;;
;;; Funcin auxiliar Bit: devuelve el valor decimal
del bit en la posicin indicada.
;;;
(defun Bit (pos) (lsh 1 (1- pos)))
;;;
;;;
;;Funcin utilizada como acumulador del valor de la
posicin
;;;
(defun PosBit ()
(if (null posicion)
(setq posicion 1)
(setq posicion (1+ posicion))
) ;_ fin de if
) ;_ fin de defun
;;;
;;;
;;;Funcin para procesamiento del nmero decimal
;;;Recibe como argumento el predicado a aplicar
;;;segn sea el argumento numrico positivo o
negativo
;;;
(defun ConvierteBinario (numdec predicado / posicion
numbin)
(while (not (minusp (bit (1- (PosBit)))))
(setq numbin
(cons
(if
(apply
predicado
(list (logand (bit posicion) (fix
numdec)) 0)
) ;_ fin de apply
1
0
) ;_ fin de if
numbin
) ;_ fin de cons
) ;_ fin de setq
) ;_ fin de while
) ;_ fin de defun
;;;
;;;Funcin principal
;;;Tiene en cuenta si se trata de un nmero positivo
o negativo:
;;;
(defun Binario (numdec /)
(if (minusp numdec)
(ConvierteBinario (~ numdec) '=)
(ConvierteBinario numdec '/=)
) ;_ fin de if
) ;_ fin de defun
A diferencia de la funcin BASE, se obtiene una respuesta
correcta tanto de enteros positivos como negativos:
CONVERSIN BINARIO->DECIMAL
;;;
(defun Decimal (numbin /)
(cond
((STD-DOTTED-PAIR-P numbin)
(terpri)
(princ numbin)
(princ " no es un valor admitido.")
(princ)
)
((listp numbin)
;;si es lista, convierte los trminos
(setq
numbin ;;que sean cadenas en nmeros (o tomos
simblicos si fueran letras)
(mapcar
(function (lambda (term)
(if
(stringp term)
(read term)
term
) ;_ fin de if
) ;_ fin de lambda
) ;_ fin de function
numbin
) ;_ fin de mapcar
) ;_ fin de setq
(ConvierteDecimal numbin)
)
((numberp numbin)
;;si es nmero lo convierte en cadena para
despus hacerlo lista
(setq numbin (Numero->Lista numbin))
(ConvierteDecimal numbin)
)
((stringp numbin)
(setq numbin (mapcar 'read (Cadena->Lista
numbin)))
(ConvierteDecimal numbin)
)
(t
(terpri)
(princ numbin)
(princ " no es un valor admitido.")
(princ)
)
) ;_ fin de cond
) ;_ fin de defun
A continuacin algunos ejemplos tomados de la consola de
VISUAL Lisp:
_$
(boole 1
1 1)
1
_$
(boole 2
1 0)
1
_$
(boole 4
0 1)
1
_$
(boole 8
0 0)
-1
Operacin
Booleana
AND
6 (4 + 2)
XOR
7 (4 + 2 +
OR
Ambos son 1
Slo uno de ellos es
igual a 1
Cualquiera de ellos es
1)
8
NOR
1
Ambos son 0
(complemento de 1)
INTEGERP
Comprueba si el argumento es un nmero entero.
(defun integerp (dato)(eq (type dato) 'INT))
REALP
Comprueba si el argumento es un nmero real.
(defun realp (dato)(eq (type dato) 'REAL))
STRINGP
Comprueba si el argumento es una cadena.
(defun stringp (dato)(eq (type dato) 'STR))
Tipos de Datos AutoCAD:
ENAMEP
Comprueba si el argumento es un nombre de entidad.
SAFEARRAYP
Comprueba si el argumento es una Matriz del tipo Safearray.
(defun safearrayp (dato)(eq (type dato) 'SAFEARRAY))
VARIANTP
Comprueba si el argumento es del tipo Variant.
(defun variantp (dato)(eq (type dato) 'VARIANT))
VLA-OBJECT-P
Comprueba si el argumento es un Objeto ActiveX.
(defun vla-object-p (dato)(eq (type dato) 'VLAobject))
ESTRUCTURAS CONDICIONALES
CONDICIONAL IF
ESTRUCTURA IF-THEN-ELSE
Evala expresiones condicionalmente:
(if expr_prueba expr_then [expr_else])
Si expr_prueba no es nil, evala expr_then;
en caso contrario evala expr_else.
La funcin if devuelve el valor de la expresin
seleccionada. Si expr_else no existe y expr_prueba es
nil, entonces la funcin if devuelve nil.
Funcin PROGN
Calcula las expresiones secuencialmente y devuelve el
valor de la ltima expresin
(progn [expr]...)
Se suele utilizar progn para calcular varias expresiones
cuando slo se espera, como en cada una de las ramas
del IF, una sola expresin.
CONDICIONALES DE USO GENERAL
(trace busca_en_lista)
podemos seguir en la ventana TRACE de Visual LISP los pasos
seguidos en la evaluacin de esta funcin:
Entering (BUSCA_EN_LISTA (A B) (2 nil "sdf" (A B)
"KLM" 77 21 nil))
Entering (BUSCA_EN_LISTA (A B) (nil "sdf" (A B)
"KLM" 77 21 nil))
Entering (BUSCA_EN_LISTA (A B) ("sdf" (A B) "KLM"
77 21 nil))
Entering (BUSCA_EN_LISTA (A B) ((A B) "KLM" 77
21 nil))
Result: ((A B) "KLM" 77 21 nil)
Result: ((A B) "KLM" 77 21 nil)
Result: ((A B) "KLM" 77 21 nil)
Result: ((A B) "KLM" 77 21 nil)
Los objetivos perseguidos implican el recorrido de la lista,
elemento a elemento, comparando cada uno con la expresin
dada. La manera ms sencilla para extraer un elemento de la
lista (el primero) es utilizar la funcin CAR. Un segundo
elemento pudiera extraerse con CADR y as sucesivamente.
Pero este mtodo sera demasiado rgido si queremos que la
funcin sea aplicable a una lista de cualquier longitud.
Una solucin estara en que si el primer elemento no es el
buscado, volviramos a ejecutar la funcin pero que esta vez
el segundo argumento (lista) fuera el resto de la lista, quitando
el primer trmino ya analizado: (cdr lista).
As continuaramos probando el primer trmino (CAR de la
lista) del resto (CDR) de la lista hasta que o termine la lista o
que el primer trmino sea el elemento buscado.
Las condiciones que se prueban corresponden a los tres casos
posibles al suministrar a la funcin BUSCA_EN_LISTA dos
argumentos, el primero de los cuales puede ser un tomo o
una lista y el segundo debe evaluar como una lista, incluso
vaca.
Los datos que sirven para definir cada una de los objetos
grficos de AutoCAD estn organizados en forma de una lista
ITERACIONES SIMPLES
REPEAT
Evala cada expresin el nmero de veces que se
especifique en el argumento entero, y devuelve el valor
de la ltima expresin
(repeat entero expresin ...)
El argumento entero debe ser un nmero entero
positivo.
Ejemplos de iteraciones con REPEAT:
FACTORIAL ITERATIVO
Como primer ejemplo analizaremos la funcin FACT2
propuesta por Dennis Shinn <jeeper@halcyon.com> en
el newsgroup comp.cad.autocaden septiembre de 1996.
La explicacin es nuestra traduccin libre del original.
(defun fact2 (n / x y)
(setq x 1 y 1)
(repeat (1- n)
(setq x (1+ x) y (* x y) )
)
)
En la primera lnea se asigna el valor inicial correcto a las
dos variable que llamamos x e y.
La repeticin se establece para un nmero especfico de
veces segn el nmero que se pase como argumento a la
funcin. Puesto que la operacin del clculo del factorial
implica la cantidad de nmeros a multiplicar menos 1,
establecemos en (1- n) el nmero de repeticiones.
Ahora vienen los clculos matemticos: (setq x (1+ x)
y (* x y))
Durante cada iteracin de esta expresin, la x se
incrementa por un valor de 1 cada vez, e y se incrementa
como el producto de ella misma y el prximo valor mayor
de x, etc., etc.
Obsrvese que no se ha implementado un control de
errores, que es algo deseable en un lenguaje de
programacin. Tanto 0 como 1 quedan indefinidos, ya que
ninguno de los dos permitir que ocurra la iteracin. El
REPEAT simplemente no repite. Vale, sin embargo para
demostrar las posibilidades de un verdadero lenguaje de
programacin (como LISP) para realizar verdaderas
operaciones de recursin e iteracin.
Como muestra de una implementacin para atrapar
posibles errores podramos crear otra rutina fact3 que
llame a la rutina fact2 slo en los casos apropiados:
(defun fact3 (n)
(cond
((and (numberp n)(> n 1))
(fact2 n)
)
((= n 1) 1)
(t nil)
)
)
) ;_ fin de equal
) ;_ fin de not
(setq resultado nil)
) ;_ fin de if
(setq cont (1+ cont))
) ;_ fin de repeat
resultado
) ;_ fin de defun
ITERACIONES SOBRE ELEMENTOS DE UNA SECUENCIA
FOREACH
Evala cada expresin para todos los miembros de una
lista
(foreach nombre lista expresin ...)
Recorre la lista, asignando sucesivamente cada elemento
de la lista a la variable nombre y evaluando de esta
manera cada expresin para cada uno de los elementos
de la lista representados por nombre. Puede especificar
tantas expresiones como desee. La funcin FOREACH
devuelve el resultado de la ltima expresin evaluada.
VLAX-FOR
Efecta una iteracin a travs de una coleccin de objetos
evaluando cada expresin
(vlax-for smbolo coleccin [expresin1
[expresin2 ...]])
El argumento smbolo ser asignado a cada Objeto-VLA
de la coleccin. El argumento coleccin representa un
objeto ActiveX del tipo coleccin. [expresin1
[expresin2 ...]] son las expresiones a evaluar. La funcin
devuelve el valor de la ltima expresin evaluada para el
ltimo objeto de la coleccin.
Ejemplos de iteraciones con FOREACH:
(43 . 0.0)
(38 . 0.0)
(39 . 0.0)
(10 99.3432 134.975)
(40 . 0.0)
(41 . 0.0)
(42 . 0.0)
(10 130.202 185.828)
(40 . 0.0)
(41 . 0.0)
(42 . 0.0)
(10 202.747 163.648)
(40 . 0.0)
(41 . 0.0)
(42 . 0.0)
(10 269.336 215.041)
(40 . 0.0)
(41 . 0.0)
(42 . 0.0)
(210 0.0 0.0 1.0)
Ejemplos de iteraciones con VLAX-FOR:
LISTADO DE CAPAS
inicialmente.
Sutphin, J. AutoCAD 2000 VBA Programmers Reference, pg 47.
La rutina que exponemos a continuacin extrae los nombres de
las capas de un dibujo aplicando la funcin VLAX-FOR a la
coleccin "Layers". Para obtener la coleccin "Layers"
tenemos que recorrer la jerarqua de objetos, a partir del nico
objeto accesible pblicamente que es el objeto "Application"
(Aplicacin). La secuencia a seguir es la siguiente:
1. Obtener el objeto "Aplicacin": (vlax-get-acad-object)
2. Obtener el objeto "Documento Activo" es decir, el dibujo
en que se trabaja: (vla-get-ActiveDocument (vlaxget-acad-object))
En caso de que se vaya a hacer referencia a este objeto
en mltiples ocasiones, sera conveniente extraerlo una
sla vez y guardarlo en una variable global:
(setq *EsteDibujo* (vla-get-ActiveDocument
(vlax-get-acad-object)))
Esta lnea la situamos fuera del defun. Se ejecutara al
cargar el programa.
3. Obtener la coleccin "Layers" (Capas): (vlax-get
*EsteDibujo* "Layers" )
Una vez obtenida la coleccin de capas se aplica mediante
VLAX-FOR a cada objeto-VLA de dicha coleccin la funcin
(setq ListaCapas (cons (vlax-get objeto-VLA "Name")
*ListaCapas*))
Aqu primero extraemos el nombre de la capa. El nombre de
cada objeto "Layer" se encuentra en la propiedad "Name" y se
puede extraer mediante (vlax-get objeto-VLA "Name"). Una
vez obtenido el nombre de la capa, la incluimos mediante
CONS en una variable local ListaCapas. Esta lista contendr al
terminar el ciclo de VLAX-FOR los nombres de todas las capas
del dibujo activo. Ya para terminar, ordenamos la lista de capas
mediante la funcin ACAD_STRLSORT. Esta lista servira, por
ejemplo para llenar una casilla de lista en un cuadro de dilogo
creado mediante el lenguaje DCL.
;;;Funcin ListaCapas
)
lst
)
Como se ve, esta puede ser otra va para abordar el desarrollo
del predicado PALINDROMOP: obtener mediante STRTOL la
cadena de caracteres en forma de lista y entonces compararla
con la lista invertida por reverse:
(defun palindromop (cadena)
(setq cadena (strtol cadena))
(equal cadena (reverse cadena))
)
CICLOS DEPENDIENTES DE UNA CONDICIONAL
MAPCAR
(mapcar funcin lista1 ... listan)
MAPCAR opera sobre los elementos sucesivos de las listas.
Primero se aplica la funcin al CAR de cada lista, entonces
al CADR de cada una y as sucesivamente. Lo ideal sera
que todas las listas fueran de igual longitud. Si no lo
fueran, la iteracin concluye al agotarse la lista ms corta
y los elementos en exceso de las dems listas se ignoran.
MAPCAR devuelve una lista con los resultados de las
sucesivas llamadas a la funcin. Por ejemplo:
_1$ (mapcar 'cons '(a b c) '(1 2 3))
((A . 1) (B . 2) (C . 3))
Una expresin-LAMBDA puede ser utilizada con MAPCAR.
Esto resulta til cuando algunos de los argumentos de
funcin son constantes o se proporcionan mediante
variables u otros mtodos.
Sobre la funcin MAPCAR seguramente no encontraremos una
explicacin ms entusiasta que la de Vladimir Nemerovski a
quien citamos a continuacin:
Ahora trataremos de MAPCAR. Esta es una funcin que
requiere:
1. un smbolo dentro de QUOTE
Y hay algo ms. Digamos que tengo esta funcin que SUMA
todos sus argumentos. Es un '+, que puedo invocar como:
(+ 1 2) (+ 1 2 3) etc.
Ahora cuando escribo (mapcar '+ '(1 2 3) '(4 5 6)) es lo
mismo que (list (+ 1 4)(+ 2 5)(+ 3 6)) Tambin puedo
escribir (mapcar '+ '(1 2 3)'(4 5 6)'(7 8 9)), que
equivale a (list (+ 1 4 7)(+ 2 5 8)(+ 3 6 9)) etc.
De manera que tenemos algo ms de flexibilidad aqu. Por
supuesto que yo ser el responsable de suministrar a la
funcin invocada con el nmero adecuado de argumentos que
le sern alimentados por MAPCAR, ya que de otra manera
obtendr un error de DEMASIADOS/MUY POCOS ARGUMENTOS
cuando LISP eventualmente la evale.
Fuente:
Subject: A short course in LISP, LAMBDA,
QUOTE, MAPCAR...
Date: Sat, 02 Nov 1996 08:50:38 -0800
From: Lu <learly@ix.netcom.com>
VLAX-MAP-COLLECTION
Aplica una funcin a todos los objetos de una coleccin.
(vlax-map-collection coleccin funcin)
El argumento coleccin representa un Objeto-VLA de tipo
coleccin. El argumento funcin ser un smbolo o una
expresin-LAMBDA que ser aplicada a coleccin.
Ejemplo de utilizacin de VLAX-MAP-COLLECTION:
) ;_ fin de defun
Obsrvese el uso de la funcin FUNCTION que fuerza la
compilacin de las dos expresiones-LAMBDA. Se utiliza en
lugar de QUOTE (o apstrofe) procurando una mayor eficacia y
rapidez.
Esta segunda formulacin resulta ms clara y ms econmica
en cuanto a esfuerzo de programacin. Por otra parte, supera
las limitaciones de Visual LISP en cuanto a la recursin que
pudiera provocar en caso de polilneas con un gran nmero de
vrtices un error por desbordamiento de pila.
Nota: esta funcin devuelve los resultados correctos para
Visual LISP en AutoCAD 2000. Sin embargo hemos encontrado
que falla si se ejecuta desde el IDE Visual LISP para la versin
14. El error se encuentra en los valores de la lista de
asociacin para el objeto LWPOLYLINE que se obtienen desde
este entorno:
(entget(car(entsel))) aplicado a una LWpolyline en la lnea
de comandos de AutoCAD R14 devuelve:
Command: (entget(car(entsel)))
Select object:
((-1 . <Entity name: 43b0500>) (0 . "LWPOLYLINE")
(5 . "20")
(100 . "AcDbEntity") (67 . 0) (8 . "0") (100 .
"AcDbPolyline")
(90 . 7) (70 . 0) (43 . 0.0) (38 . 0.0) (39 . 0.0)
(10 103.882 154.494) (40 . 0.0) (41 . 0.0) (42 . 0.0)
(10 180.771 201.906) (40 . 0.0) (41 . 0.0) (42 . 0.0)
(10 186.224 143.05) (40 . 0.0) (41 . 0.0) (42 . 0.0)
(10 267.476 167.028) (40 . 0.0) (41 . 0.0) (42 . 0.0)
(10 256.569 105.994) (40 . 0.0) (41 . 0.0) (42 . 0.0)
(10 298.558 123.432) (40 . 0.0) (41 . 0.0) (42 . 0.0)
(10 293.651 89.1) (40 . 0.0) (41 . 0.0) (42 . 0.0)
(210 0.0 0.0 1.0))
Obsrvese que las listas asociadas al cdigo 10 contienen dos
nmeros reales adems del cdigo de asociacin: (10 256.569
(setq math-formula
'(+ 3 (* (- 5 pi) 4 (/ 3 7))(* 15 2))
)
Math-formula contiene listas dentro de listas dentro de listas.
;; la lista vaca
;; si el primer
;; sumar al nmero
;; si es cualquier
;; ignorarlo,
;; o se trata de
;; y sumar al
>(num-nums math-formula)
1> (NUM-NUMS (+ 3 (* (- 5 PI) 4 (/ 3 7)) (* 15 2)))
2> (NUM-NUMS (3 (* (- 5 PI) 4 (/ 3 7)) (* 15 2)))
3> (NUM-NUMS ((* (- 5 PI) 4 (/ 3 7)) (* 15 2)))
4> (NUM-NUMS (* (- 5 PI) 4 (/ 3 7)))
5> (NUM-NUMS ((- 5 PI) 4 (/ 3 7)))
6> (NUM-NUMS (- 5 PI))
7> (NUM-NUMS (5 PI))
8> (NUM-NUMS (PI))
9> (NUM-NUMS NIL)
<9 (NUM-NUMS 0)
<8 (NUM-NUMS 0)
<7 (NUM-NUMS 1)
<6 (NUM-NUMS 1)
6> (NUM-NUMS (4 (/ 3 7)))
7> (NUM-NUMS ((/ 3 7)))
8> (NUM-NUMS (/ 3 7))
9> (NUM-NUMS (3 7))
10> (NUM-NUMS (7))
11> (NUM-NUMS NIL)
<11 (NUM-NUMS 0)
<10 (NUM-NUMS 1)
<9 (NUM-NUMS 2)
<8 (NUM-NUMS 2)
8> (NUM-NUMS NIL)
<8 (NUM-NUMS 0)
<7 (NUM-NUMS 2)
<6 (NUM-NUMS 3)
<5 (NUM-NUMS 4)
<4 (NUM-NUMS 4)
4> (NUM-NUMS ((* 15 2)))
5> (NUM-NUMS (* 15 2))
6> (NUM-NUMS (15 2))
7> (NUM-NUMS (2))
8> (NUM-NUMS NIL)
<8 (NUM-NUMS 0)
<7 (NUM-NUMS 1)
<6 (NUM-NUMS 2)
<5 (NUM-NUMS 2)
5> (NUM-NUMS NIL)
<5 (NUM-NUMS 0)
<4 (NUM-NUMS 2)
<3 (NUM-NUMS 6)
<2 (NUM-NUMS 7)
<1 (NUM-NUMS 7)
7
Sera difcil definir num-nums de forma iterativa. No es imposible, pero exige el saber
utilizar una pila para simular la recursin.
(progn
(opn_l)(setq s_c 0)
(repeat (sslength s_set)
(if (setq n_e (ssname s_set s_c))(setq
lis_e (entget n_e (list "*"))))
(setq cont 0)
(prn_l lis_e)
(if
(or
(= (cdr (assoc 0 lis_e))
"POLYLINE")
(= (cdr (assoc 0 lis_e)) "INSERT")
)
(progn
(setq ctrl t)
(while (and ctrl (setq n_e (entnext
n_e)))
(setq cont 0)
(if (= (cdr (assoc 0 (setq lis_e
(entget n_e (list "*"))))) "SEQEND")
(progn (setq ctrl nil)(prn_l
lis_e))
(prn_l lis_e)
)
)
)
)
(setq s_c (1+ s_c))
)
(close if_w)
)
)
)
;;Programa Principal LIS: Salida por pantalla
(defun c:lis ( / n_e lis_e ctrl cont)
(if (setq n_e (car (entsel)))(setq lis_e (entget
n_e (list "*"))))
(setq cont 0)
(disp_l lis_e)
(setq ctrl t)
(while (and ctrl (setq n_e (entnext n_e)))
(setq cont 0)
C O N
SPLINE
PLINE.DWG
Utilizando los parmetros por defecto de AutoCAD, y
adaptando las polilneas con EDITPOL(PEDIT)/SPLINE, el
resultado ha sido el siguiente:
Polilnea sin adaptar:
PLINE DWG
238.770
bytes
Polilnea adaptada a B-Spline: B-SPLINE DWG 1.930.838
bytes
B-SPLIN1 DWG
375.520
LA SOLUCIN SpLINE
SPLINE DWG
109.090 bytes
De SpLINES a PolyLINES:
110.228 bytes
C O N V E R S I N
PolyLINE>SpLINE
)
)
;;Funcin Principal/Command line function
(defun c:pl2sp ( / oce)
(setq oce (getvar "cmdecho"))
(setvar "cmdecho" 0)
(vertex (pl_sel))
(redraw)
(setvar "cmdecho" oce)
(princ)
)
;;----------------FIN DEL
PROGRAMA----------------------Many of you have posted requests to the Wizard's Lab asking how to use Visual LISP to
interface with other automated productivity tools like Microsoft Excel. This article is the first in a
series that shows you how to create such an interface. First I'll explain the basics and then we'll
start looking at the larger task: using Visual LISP to tie other automated programs into your CAD
drawings. As you'll see it's all about productivity gains.
Note: You can download the code used in this tutorial from here (1.5 KB).
What Is Automation?
Microsoft Windows holds some very powerful automation programs that, with some programming,
you can use to control (drive) other programs you've installed. Generally this mechanism is
referred to as automation. The Windows operating system has a series of guidelines that you
can follow to create an application that accepts automation.
An automated program publishes or sends information to the operating system, which defines the
types of commands the program supports and how other programs are to go about
communicating with it. That process is basically standardized. But as you might have guessed,
beyond that each program has its own unique way for other programs to drive it automatically.
Automating certain tasks can achieve marvelous results. A simple illustration is to tie drawing
information from a bill of materials into a spreadsheet for further analysis or reporting purposes.
Another: to import text generated by a word-processing application into a drawing so that you
don't have to reenter data. Or this: integrating a database containing details about elements used
in the drawing to determine loads or costs. Your only limit here is the power of your imagination.
This arena is a wonderful place for wizards to play!
Beginning a Conversation
First, let's look at the theory behind automation and then look at how to apply that theory in Visual
LISP.
The automation process begins when one program establishes a communications link to another
program. Any application built to run on the Windows OS can be automated if the developer
provides the required parts. During installation, the name of each application is placed in the
Windows Systems Registry and that name is used to reference the application from another
program. Learning that System Registry name is your first step. In most cases you can guess at
the name with reasonable accuracy. The name to activate a program such as Microsoft Excel is
simply Excel.Appliction. The dot that appears between the name Excel and the word Application
is a standard divider used when referencing an object inside Windows. If the application name is
not obvious then you have some detective work to do. Most applications will include some
documentation about automation that will provide assistance.
Once you know the name of the application object, open the application. (Of course it should go
without saying that you can't automate an application that isn't already installed on your PC.) To
begin automating an application, you can either communicate with an instance of the program
that is already running or you can create a new instance of the program. That is, you can open an
existing channel to the program or create a new channel by copying the program to memory and
working with the copy.
The requirements of your interface dictate your choice here. If you want to create a new
document or worksheet, create a new channel to the application. If you want to look up
information in the program, open the program. The main difference is in how much time is
required to establish communication. Opening an existing application in memory is significantly
faster than creating a new instance.
The following list defines a few terms that you should know as you begin to create an interface
that automates an application. One word of caution though, all the documents about automation
are likely written from the perspective of Visual BASIC and not Visual LISP. As a Visual LISP
programmer, you must translate this information into more relevant terms. We'll get to that a bit
later on. Here's the list of terms:
You must supply the name of the application you will be automating for each of these methods. If
the application is not available, a nil result is returned indicating that your request for an
automation link has failed. Otherwise, an object reference is returned. Save that result using
SETQ in your Visual LISP program. The following expression attempts to link to either a running
copy of Excel or to create a new instance of it if one is not currently available.
(setq xL (vlax-get-or-create-object
"Excel.Application"))
When this expression has completed, the symbol xL will be nil if Excel could not be located on the
computer. Otherwise xL contains the object reference to a running copy of the program. You will
use the object reference from this point forward to communicate with that specific instance of
Excel.
If you want to be sure that you are working with an exclusive instance of Excel, use the (VLAXCREATE-OBJECT) method. That way, if Excel is already running, a new copy is started in the
computer so that your application does not interfere with any other spreadsheets that may be
open and in use. Or use (VLAX-GET-OBJECT) and simply use an already running copy of Excel.
This option is useful when you are working with an active spreadsheet and simply want to move
data between it and a drawing. In all the cases, you will get an object reference if the link is
successful or a nil result if the link could not be established.
We can use the result immediately as in the following code segment:
Object libraries are declared in a file with an OLB extension, which you can usually find in the
same folder as the application executable files. Use Windows Explorer to locate the file (use the
Find option in the Tools drop-down menu and search for all files that have an extension of OLB).
You can either code the entire path to the object library into your application, use a variable to
house that information in case you want to change it later on, or have your program locate the file
you need.
Use the Visual LISP function (VLAX-IMPORT-TYPE-LIBRARY) to import the library into your
program. On import, a new host of functions becomes available to use in the interface you're
creating. Do this import only once in an application.
The Visual LISP documentation recommends that the import function be run at the topmost level
in your program, just like the (VL-LOAD-COM) expression. That method prevents attempts at
loading the type library more than once. You don't want to import a library more than once
because it is time consuming and could possibly foul symbol assignments you have already
made. Another way to prevent importing a library twice is to employ a conditional as in the
following expression:
dialog box in the Visual LISP editor, supply the prefix you specified during the import. In most
cases the list returned is extensive, including items that take you to the information in the online
help for the application to which you are interfacing. For example, you can learn what the
parameters of a given function might be by looking at the help data.
You must interpret this information from a Visual BASIC programming point of view because most
automation programming is done using Visual BASIC not Visual LISP. However, using the
methods described so farespecially the import object library functionVisual LISP is just as
powerful a tool. But remember that it is only found in AutoCAD.
To access the APROPOS feature in Visual LISP:
1.
2.
3.
4.
5.
Remember that the list only reveals object names. You must go into the other application and find
the associated information in the help system.
What's Next?
So far you've learned that you can use Visual LISP to interface with another program such as
Excel through the use of the OLE or automation system. You've also seen how to establish a link
to the automation tools from another application.
The next steps involve the actual sending and receiving of data using the interface. This requires
that you use either the VLAX-GET and VLAX-PUT functions or that you allow Visual LISP to
import a new library of functions as defined in an OLB (Object Library) file. Check out the scrolls
and potions in the Wizard's Lab to see how this might be accomplished or join me next month
when we'll explore how to transfer data to Excel.
Until then, keep on programmin'.
Continuing on, we want to create a command called ZAP that erases all the objects in
the drawing. To do this we'll need to execute the ERASE command, input the ALL
option (all three characters), and then an additional ENTER to get out of the
command.
So how do we tell Visual LISP to hit ENTER? A pair of double quotes will do. For those
of you who have customized menus, this is the equivalent of using a semicolon to
represent an ENTER.
(defun c:ZAP ()
(command "erase" "all" "")
)
So how are we going to create a square? We'll execute the POLYGON command,
make the object four-sided, select the EDGE option, and pause twice to let the user
pick the two corners that will make up our square. If you're lost, please go into the
POLYGON command in AutoCAD and go through all of these steps manually. Let's
look at the code.
(defun c:SQ ()
(command "polygon" "4" "E" pause pause)
)
Using pause in a Visual LISP routine will instruct the program to wait for user input.
Those two pauses will enable the user to pick the two corners of the square. This is
equivalent of the backslash \ in menu customization. So what do we have so far?
(defun c:ZP ()
(command "zoom" "p")
)
(defun c:ZAP ()
(command "erase" "all")
)
(defun c:SQ ()
(command "polygon" "4" "e" pause pause)
)
Figure 1. The APPLOAD dialog makes it easy to load your Visual LISP
routines.