autolisp gera

210
http://www.emagdalena.es/2012/10/06/ Introducción a la programación en AutoCAD Tabla de contenidos de Introducción a la programación en AutoCAD 1. Primeros pasos con AutoLISP 2. Las variables en AutoLISP 3. Operaciones matemáticas básicas 4. Solicitar números al usuario 5. Funciones de usuario y nuevos comandos 6. Introducción al entorno de Visual LISP 7. Cargar los archivos de AutoLISP 8. Operaciones matemáticas en AutoLISP 9. Solicitar textos y puntos al usuario 10. Funciones para manejar listas 11. Ejecutar comandos de AutoCAD 12. Operaciones de comparación 13. Operaciones lógicas en AutoLISP 14. Estructuras condicionales simples 15. Estructuras condicionales múltiples 16. Mostrar textos al usuario en AutoLisp 17. Las variables de sistema de AutoCAD 18. Funciones de conversión de datos en AutoLISP 19. Obtener distancias y ángulos del usuario 20. El comando deshacer en las rutinas de AutoLISP 21. Funciones de tratamiento de errores en AutoLISP

Upload: gerardo-lopez-zamora

Post on 25-Apr-2017

340 views

Category:

Documents


13 download

TRANSCRIPT

Page 1: Autolisp Gera

http://www.emagdalena.es/2012/10/06/Introducción a la programación en AutoCAD

Tabla de contenidos de Introducción a la programación en AutoCAD1. Primeros pasos con AutoLISP2. Las variables en AutoLISP

3. Operaciones matemáticas básicas

4. Solicitar números al usuario

5. Funciones de usuario y nuevos comandos

6. Introducción al entorno de Visual LISP

7. Cargar los archivos de AutoLISP

8. Operaciones matemáticas en AutoLISP

9. Solicitar textos y puntos al usuario

10. Funciones para manejar listas

11. Ejecutar comandos de AutoCAD

12. Operaciones de comparación

13. Operaciones lógicas en AutoLISP

14. Estructuras condicionales simples

15. Estructuras condicionales múltiples

16. Mostrar textos al usuario en AutoLisp

17. Las variables de sistema de AutoCAD

18. Funciones de conversión de datos en AutoLISP

19. Obtener distancias y ángulos del usuario

20. El comando deshacer en las rutinas de AutoLISP

21. Funciones de tratamiento de errores en AutoLISP

22. Limitar las respuestas de los usuarios

Page 2: Autolisp Gera

23. Limitar las respuestas de los usuarios (II)

24. Estructuras repetitivas: Bucles

25. Funciones para manipular cadenas de texto

26. Trabajar con ángulos y distancias

27. Funciones avanzadas para manejar listas

28. Aplicar funciones a los elementos de una lista

29. Literales y otras funciones de utilidad

30. Carga automática de los archivos de AutoLISP

31. Operaciones con archivos

32. Leer y escribir archivos de texto

Primeros pasos con AutoLISP

Objetivos del cursoAprovechando que actualmente dispongo de algo más de tiempo, me he decidido a desempolvar y re-editar algún curso que he creado hace ya bastante tiempo, trataré de actualizar el contenido para que funcione con las últimas versiones de AutoCAD.

Con este curso no se pretende formar a expertos programadores. Más bien, se pretende acercar el lenguaje de programación AutoLISP a los usuarios de AutoCAD, para que puedan crear utilidades y pequeñas aplicaciones que les ahorren tiempo y cálculos en sus trabajos.

Para seguir el curso no son necesarios conocimientos de programación, tan sólo es preciso tener unas nociones básicas de AutoCAD y del entorno Windows.

Otro de los objetivos del curso es el de ver a AutoCAD no como un programa de dibujo, sino como una potente base de datos gráficos. Y descubrir como funciona esa base de datos.

Page 3: Autolisp Gera

Código de una macro en AutoLISP

Merece la pena aprender a programar sobre AutoCADDesde luego que puede merecer la pena. Puede agilizar y facilitar enormemente el trabajo con AutoCAD.

Puede que existan en el mercado aplicaciones de diseño mucho más potentes para trabajar en 3D de forma paramétrica, como SolidWorks o Catia, pero AutoCAD se sigue utilizando habitualmente en infinidad de aplicaciones. Para trabajar en 2D sigue siendo la aplicación de CAD de referencia y su formato de archivo .DWG es un estándar en la importación y exportación de archivos convirtiéndose en uno de los formatos de archivo más utilizados para intercambiar partes de un diseño con clientes, proveedores y colaboradores.

Page 4: Autolisp Gera

AutoLISP es un lenguaje sencillo de aprender y a diferencia de otros lenguajes de programación se pueden crear programas interesantes y realmente útiles casi desde el primer momento.

Muchas veces, la mayoría del tiempo empleado en crear una macro o programa se emplea en depurar el código (corregir errores). La planificación y el análisis previo de la macro es de suma importancia para evitarlo. El primer paso para escribir una macro consiste en escribir en un papel con un lenguaje simple lo que se desea que realice el programa, a esto se le denomina pseudocódigo. Un método algo más avanzado y eficaz es utilizar diagramas de flujo.

Cuando ya empieces a programar en AutoLISP por ti solo, te será muy útil reunir todas las anotaciones sobre proyectos de aplicaciones y macros en una libreta o bloc de notas. También puedes utilizar Evernote o cualquier otro sistema que te permita almacenar de información o gestionar las macros que has creado.

Interfaces de programaciónAutoCAD dispone varios entornos de programación, la selección del tipo de interfaz a emplear para crear una aplicación dependerá de las necesidades de la aplicación y de la experiencia o conocimientos del programador/es:

AutoLISP es una adaptación del lenguaje de programación CommonLISP para AutoCAD. Es sencillo de aprender y al mismo tiempo potente. AutoCAD cuenta con un intérprete interno de LISP que permiteintroducir código desde la línea de comandos o cargar programas desde archivos externos. Puedes utilizar AutoLISP para automatizar tareas repetitivas y crear nuevos comandos de AutoCAD

ActiveX Automation constituye una alternativa moderna al AutoLISP. Puedes acceder y controlar objetos de AutoCAD desde cualquier aplicación que utilice un controlador Automation como Visual Basic y Delphi, o cualquiera de las aplicaciones que dispongan de Visual Basic for Applications (VBA)

VBA es un entorno de programación basado en objetos que utiliza íntegramente la sintaxis del lenguaje Visual Basic y permite usar controles ActiveX. Permite también la integración con otras aplicaciones que utilizan VBA como MS Office o MS Project. Las ediciones de desarrollo de MS Visual Basic, que se adquieren por separado, complementan AutoCAD VBA con componentes adicionales como un dispositivo externo de base de datos y funcionalidades de escritura de informes

ObjectARX es un entorno de programación de lenguaje compilado para el desarrollo de aplicaciones de AutoCAD. El entorno de programación ObjectARX incluye varias bibliotecas de vínculos dinámicos (DLL) que ofrecen acceso directo a las estructuras de la base de datos, el sistema de gráficos y los dispositivos de geometría de AutoCAD

Page 5: Autolisp Gera

De momento nos centraremos en la programación sobre AutoCAD utilizando el interprete interno de AutoLISP para pasar en breve al entorno de Visual LISP y posteriormente a la programación en VBA.

Características de AutoLISPEl LISP fue desarrollado a finales de los años 50 por John McCarthy, es el segundo lenguaje de programación más antiguo solo precedido por Fortran. Uno de los campos en los que es más empleado es en la investigación en inteligencia artificial. Su nombre proviene de LISt Procesing (Procesado de listas), pues se basa en el uso de listas en lugar de datos numéricos. Aunque hay quien mantiene en tono jocoso que su nombre proviene de “Lost In Stupid Parenthesis”.

AutoLISP añade al LISP algunas funciones especialmente diseñadas para la manipulación de las entidades de AutoCAD.

AutoLISP es un lenguaje evaluado. El código se convierte a lenguaje máquina (ceros y unos) y se almacena en la memoria temporal. No es tan lento como los lenguajes interpretados, ni tan rápido como los compilados:

en los lenguajes interpretados, se va traduciendo el programa a código máquina (el idioma de los ordenadores) a medida que se ejecuta

en los lenguajes compilados, el código fuente (texto) del programa se traduce a código máquina generando un archivo ejecutable (.EXE) que es el que ejecutará el programa

Hay quien dice que AutoLISP es lento comparándolo con otros lenguajes como Pascal o C, especialmente cuando se utilizan muchas funciones matemáticas. Sin embargo, cuando se utiliza manipulando símbolos los resultados son muy distintos. Esto hace de AutoLISP un excelente lenguaje para la programación de sistemas CAD, ya que un sistema CAD no es más que un entorno de manipulación de símbolos gráficos.

Una de las características más importantes de AutoLISP es la posibilidad de acceder a la base de datos de los dibujos de AutoCAD. Donde podemos acceder a las capas, estilos de texto, sistemas de coordenadas personales (SCP)… así como a todas las entidades del dibujo. Esta información se puede modificar, extraer e incluso añadir más entidades al dibujo o información adicional.

La mayoría de los primeros lenguajes de programación de alto nivel como C o Pascal son lenguajes procedimentales, se ejecutan una serie de instrucciones paso a paso a partir de unos datos. En AutoLISP en lugar de seguir instrucciones prefijadas, se puede acceder a la información de los objetos de AutoCAD para determinar de que información se dispone, preguntándole a los objetos por ellos mismos.

Page 6: Autolisp Gera

AutoLISP no es estrictamente un lenguaje orientado al objeto, pero contiene bastantes características de estos tipos de lenguajes debido a que puede interactuar con los objetos contenidos en los dibujos.

AutoLISP permite crear nuevos comandos para AutoCAD, que se ejecuten como cualquier otra orden. Es posible incluso redefinir los comandos de AutoCAD para que funcionen de forma distinta, por ejemplo podríamos redefinir el comando “POLIGONO” para que dibuje polígonos estrellados en lugar de los regulares.

Una mención especial merece el uso de AutoLISP en la realización de programas paramétricos y en eldiseño semiautomático, ya que entre el 60% y el 80% del diseño está dedicado a la modificación de diseños previos. En los programas paramétricos, el usuario introduce una serie de datos o parámetros a partir de los cuales el programa realiza el diseño completo de un elemento u objeto. Esta puede ser sin ninguna duda una de las mayores aplicaciones de AutoLISP.

AutoLISP se ha mejorado con la creación de Visual LISP que ofrece un entorno de desarrollo integrado dentro de AutoCAD.

Visual LISP incluye un compilador, un depurador y diversas utilidades para facilitar la programación.

Además añade nuevos comandos para permitir la interacción con objetos que utilizan ActiveX. Otra de las novedades que aporta Visual LISP son los reactores de objetos que permiten que AutoLISP responda a eventos.

En los dos primeros capítulos del curso se trabajará desde la ventana de comandos de AutoCAD. A partir del tercer capítulo ya crearemos nuestras macros en archivos de texto utilizando el entorno de Visual LISP proporcionado por AutoCAD.

Existen dos inconvenientes al emplear AutoLISP desde la ventana de comandos de AutoCAD:

en primer lugar el reducido espacio con el que se cuenta en la ventana de comandos de AutoCAD y la dificultad que supone el no tabular el código, es decir escribir el código todo seguido. Esto es debido a que cada vez que se pulsa Intro, AutoCAD evalúa lo que se ha escrito

en segundo lugar, al terminar la sesión de trabajo en AutoCAD se perderán todos los datos almacenados en la memoria temporal

Expresiones y procedimientos de evaluaciónUn programa en AutoLISP consiste en una serie de expresiones del tipo “(función argumentos)“.

Page 7: Autolisp Gera

Cada expresión comienza con un paréntesis de apertura al que sigue el nombre de una función de AutoLISP (o una función creada por el usuario) y una serie de argumentos (a veces opcionales) que dependen de la función indicada y van separados por al menos un espacio en blanco. Cada expresión termina con un paréntesis de cierre, esto es muy importante pues el número de paréntesis de apertura debe ser igual al de cierre.

Cada expresión de AutoLISP devuelve un valor.

Un argumento también puede ser una expresión, creándose así una estructura formada por expresiones (listas) anidadas unas dentro de otras; de modo que la más interior devolverá su resultado como un argumento a la lista exterior.

Cuando existen listas anidadas (unas dentro de otras), primero se evalúan las más interiores.

Los primeros ejemplos que vamos a ver son sencillos y cortitos, así que puedes teclearlos directamente en la ventana de comandos de AutoCAD.

Ejemplo:

(+ 1 2) Ejecuta la función + que realiza la suma de los argumentos 1 y 2 devuelve el resultado 3.

(+ 31 22 -3) Ejecuta la función + que realiza la suma de los argumentos 31, 22 y -3 devuelve el resultado 50.

Prueba también:

(- 17 2)

(+ 2.5 22.8)

(- 0.25 22.5)

(+ 12 -2 31 -7.5)

Ejemplo:

(+ (* 2 3) 2) devuelve 8. Recuerda que primero evalúa la lista interior y devuelve su resultado a la exterior.

(+ 7 (/ 5.0 2) -3) devuelve 6.5.

¿Qué sucedería si al escribir la expresión (+ 1 (/ 5.0 2)) nos olvidásemos de escribir el último paréntesis? Haz la prueba, veras que AutoCAD te indica que falta 1 paréntesis de cierre.

Si el interprete de comandos de AutoCAD encuentra un paréntesis de apertura, supone que todo lo que vaya a continuación hasta el paréntesis de cierre es una expresión de

Page 8: Autolisp Gera

AutoLISP. De modo que envía esa expresión al interprete de AutoLISP para que la evalúe.

En el siguiente capítulo veremos algunas de las operaciones matemáticas que se pueden realizar con AutoLISP.

Tipos de objetos y datosLos elementos de las expresiones de AutoLISP pueden ser símbolos, valores concretos y también otras expresiones. Se pueden distinguir los siguientes tipos de elementos:

Símbolos: Cualquier elemento que no sea un valor concreto. Por ejemplo una variable, una función

Enteros: Números enteros comprendidos entre -32000 y 32000

Reales: Números reales (180 es un número entero, pero 180.0 es un número real)

Cadenas de texto: Texto con una longitud máxima de 132 caracteres

Descriptores de archivo: Representan un archivo de texto ASCII abierto

Nombres de entidades de AutoCAD: Nombre en hexadecimal de una entidad del dibujo

Conjuntos designados por el usuario: Conjuntos de entidades de AutoCAD

Funciones de usuario: Funciones definidas por el usuario

Funciones de AutoLISP: Funciones o comandos predefinidos de AutoLISP

Ejemplo:(+ 5 2) devuelve 7.

(+ 5 2.0) devuelve 7.0.

En el primer caso todos los argumentos son números enteros, y el resultado de su suma es un número entero. En el segundo caso, tenemos un número real, así que el resultado es un número real. Para que comprendas la importancia de esta distinción, realiza el siguiente ejemplo:

(/ 5 2)

(/ 5 2.0)

Una de las mayores virtudes de AutoLISP es que pueden ejecutarse expresiones en medio de un comando de AutoCAD.

Ejemplo:

Page 9: Autolisp Gera

Ejecuta el comando “LINEA” e indica el primer punto, activa el forzado ortogonal (F8) y teclea… (+ 11 25)Esto devuelve el resultado de la suma al comando que se estaba ejecutando. Por eso dibuja una línea de 36 mm de longitud en la dirección que indicaba el cursor.

Prueba ahora indicando el radio de la circunferencia (- 70 25) al utilizar el comando llamado “CIRCULO” (mal llamado, pues debería ser “circunferencia”).

Podemos emplear también la constante PI = 3.14159… para realizar cálculos. Por ejemplo, ejecuta de nuevo el comando “CIRCULO” y cuando pregunte el radio de la circunferencia, teclea (/ 6 (* 2 PI)). Obtendremos una circunferencia de perímetro 6.

Notación empleadaPara describir las funciones de AutoLISP que se expliquen a lo largo del curso se seguirá la siguiente notación:

(FUNCIÓN Argumentos_necesarios [Argumentos_opcionales] )

Los nombres de las funciones de AutoLISP y el código a teclear se mostrarán en negrita.

Convenciones recomendadasEn este apartado se indicarán una serie de convenciones recomendables a la hora de programar. Alguna de ellas puede que aún no las entiendas, pero no te preocupes porque las iremos recordando a medida que avancemos en el curso.

para los comentarios incluidos en el código, se recomienda utilizar el siguiente método:o ;;; Antes del código de las funciones, explicando su funcionamiento

o ;; En medio del código del programa

o ; Para explicar una línea de código. A diferencia de las anteriores, esta no se inserta en la columna 1, se insertará al terminar el código de la línea que comenta

es muy recomendable utilizar un formato tabulado para el código

evitar el uso de variables globales innecesarias

utilizar los comandos de AutoCAD y sus opciones en Inglés y precedidos por “._”

no abusar de la función “SETQ”

no utilizar T, MIN, MAX, LAST como símbolos (nombres de variables y funciones)

Page 10: Autolisp Gera

recuperar el valor inicial de las variables de sistema de AutoCAD que han sido modificadas

añadir unas líneas al final del programa para indicar el nombre del nuevo comando, autor, etc.

no introducir demasiado código en la función principal

incluir una función de tratamiento de errores

evitar que el usuario pueda introducir datos erróneos

en general es recomendable que, tras ejecutar el nuevo comando, si se ejecuta el comando “DESHACER” (“H”) se deshagan todos los cambios realizados por el comando

 Convenciones utilizadas en el curso El código en AutoLISP se mostrará en negrita y con los siguientes colores:

o los paréntesis de apertura y cierre se mostrarán en rojo ( )

o las funciones de AutoLISP se mostrarán en azul setq

o los números se mostrarán en verde 125.6 12

o los textos se mostrarán en rosa “/nDesigne un punto: “

o los comentarios se mostrarán en púrpura ;Esto es un comentario

o las funciones de usuario se mostrarán en mayúsculas (GAR 90.0) 

Artículo siguiente →

Introducción a la programación en AutoCADTabla de contenidos de Introducción a la programación en AutoCAD1. Primeros pasos con AutoLISP2. Las variables en AutoLISP

3. Operaciones matemáticas básicas

4. Solicitar números al usuario

Page 11: Autolisp Gera

5. Funciones de usuario y nuevos comandos

6. Introducción al entorno de Visual LISP

7. Cargar los archivos de AutoLISP

8. Operaciones matemáticas en AutoLISP

9. Solicitar textos y puntos al usuario

10. Funciones para manejar listas

11. Ejecutar comandos de AutoCAD

12. Operaciones de comparación

13. Operaciones lógicas en AutoLISP

14. Estructuras condicionales simples

15. Estructuras condicionales múltiples

16. Mostrar textos al usuario en AutoLisp

17. Las variables de sistema de AutoCAD

18. Funciones de conversión de datos en AutoLISP

19. Obtener distancias y ángulos del usuario

20. El comando deshacer en las rutinas de AutoLISP

21. Funciones de tratamiento de errores en AutoLISP

22. Limitar las respuestas de los usuarios

23. Limitar las respuestas de los usuarios (II)

24. Estructuras repetitivas: Bucles

25. Funciones para manipular cadenas de texto

26. Trabajar con ángulos y distancias

27. Funciones avanzadas para manejar listas

28. Aplicar funciones a los elementos de una lista

29. Literales y otras funciones de utilidad

30. Carga automática de los archivos de AutoLISP

Page 12: Autolisp Gera

31. Operaciones con archivos

32. Leer y escribir archivos de texto

Las variables en AutoLISP

¿Qué es una variable?¿No sabes qué es una variable? Recuerdas cuando en la escuela te decían “Tengo 3 melones, le doy uno a Juan y después de comprar otros 2, me comí uno porque tenía hambre”. Pues los melones son una variable. Nosotros hacíamos: 1º tengo 3 melones x=3 (x es nuestra variable). Luego le doy uno a Juan x = 3-1=2. Compro otros dos x = 2+2=4 y me comí uno x=4-1. Así que x=3. “x” no es más que un valor que varía (o puede hacerlo) a lo largo del tiempo. Pero podíamos haber llamado a la variable “y”o “z”, y ¿por qué no “melones”?

(SETQ Variable1 Valor1 [Variable2 Valor2 ... ] )En el artículo anterior logramos dibujar una circunferencia de 6 mm de indicando el radio de la circunferencia a través de la expresión en AutoLISP (/ 6 (* 2 PI)). Pero que sucede si queremos utilizar el valor obtenido por(/ 6 (* 2 PI)) para realizar otra operación, tendremos que volver a teclear la expresión anterior.

¿Existe alguna opción para almacenar en memoria los resultados de una operación, tal como hace una calculadora? Desde luego que si, AutoLISP permite almacenar miles de datos en variables, que se almacenan en la memoria del ordenador.

La función de AutoLISP empleada para definir variables y asignarles un valor es SETQ y permite definir varias variables en una misma expresión. La función SETQ devuelve el valor de la última variable definida.

Con respecto a los nombres utilizados para designar a los símbolos creados por el usuario (variables y funciones):

no son sensibles a las mayúsculas. Es lo mismo bloque, BLOQUE y Bloque no pueden contener espacios en blanco, ni los caracteres ” ( ) . ; ‘

pueden contener números, pero no estar formados únicamente por ellos

no utilizaremos nombres de variables que coincidan con los nombres de las funciones de AutoLISP ni de las variables de sistema de AutoCAD

Page 13: Autolisp Gera

no existe límite en cuanto al número de caracteres, pero es recomendable emplear nombre cortos y descriptivos.

no es necesario declarar previamente las variables, como sucede en otros lenguajes de programación. En AutoLISP una misma variable puede contener primero un número entero, luego uno real, después una cadena de texto, etc.

Ejemplo:

(setq a 3) Esta expresión crea la variable a y le asigna el valor 3. Devuelve el valor de la variable a.

¿Que valor crees que devolverá (setq b (+ 1 3) melones 23.0)? Fíjate que se han definido dos variables b ymelones de valor 4 y 23.0 respectivamente. Como melones ha sido la última variable evaluada, la expresión anterior devuelve su valor.

Si el interprete de comandos de AutoCAD recibe una palabra precedida por el signo de exclamación “!“, comprobará si ese termino ha sido empleado como un símbolo (nombre de variable o una función de usuario) de AutoLISP. En cuyo caso devolverá su valor y en caso contrario devolverá nil, que es lo mismo que nada o vacío. Por ejemplo: !a devuelve 3.

Prueba también las siguientes expresiones y comprueba los valores asignados a las variables:

(setq c (+ b 3)) Los valores de las variables también pueden utilizarse para realizar operaciones y asignar el resultado de dichas operaciones a una variable.

(setq d b) Se puede definir una variable igual al valor de otra variable.

(setq a 3.5) Se puede modificar el valor asociado a una variable, por eso se llama variable.

(setq b 2.0) ¿Qué sucede con el valor de la variable d? ¿Tomará el nuevo valor asignado a la variable b o seguirá con el anterior? Al definir la variable d se le asigno el valor que tenía la variable b en ese momento, no se estableció ninguna relación entre ambas variables.

También se puede asignar valores no numéricos a las variables. Por ejemplo, una cadena de texto. Las cadenas de texto son secuencias de uno o más caracteres encerrados entre comillas. Dentro de una cadena de texto pueden insertarse una serie de carácteres de control:

\\ representa al símbolo \ \” representa al símbolo “

\n representa un cambio de línea (retorno del carro)

\t representa una tabulación

Page 14: Autolisp Gera

(setq a “\tBienvenido al Curso Introducción a la programación en AutoCAD” )

En este caso además, hay que notar que en la variable a primero se almacenaba un valor entero, luego uno real y ahora una cadena de texto. La posibilidad de reutilizar variables con distintos tipos de datos puede ser muy útil, pues dota al programador de una gran flexibilidad al escribir el código. Pero también supone que se requiera más cuidado para no pasar a una función una variable con un tipo de dato incorrecto. Por ejemplo:(+ a b) ya que ahora la variable a contiene una cadena de texto en lugar de un número.

Existen una serie de símbolos predefinidos:

T Representa al valor lógico Cierto o Verdadero. nil Representa al valor lógico Falso.

(setq b T)

(setq c nil)

En este caso, a la variable a se le ha asignado una cadena de texto, a la variable b el valor Cierto o Verdadero y a la variable c el valor Vacío o Falso.

Para almacenar el radio de la circunferencia de perímetro 6 unidades en una variable podemos teclear:

(setq rad (/ 6 (* 2 PI)))

Podríamos crear una circunferencia e indicar !rad a AutoCAD cuando nos pregunte por el radio deseado.

Ejemplo: ¿Por qué las siguientes expresiones están mal?

(setq 157 25)

(setq rad 5 Rad 4)

(setq b Curso de AutoLISP)

Por último veamos porque no debemos emplear para los nombres de las variables los nombres de las funciones de AutoLISP.

(setq + 23) En este caso asignamos a la variable + el valor 23.

Prueba (+ 5 2.5) Ahora + no representa a la función suma, sino a una variable de valor 23. De modo que el primer termino de la expresión anterior ahora no es una función, por lo que da un error. Para recuperar el modo habitual de trabajo de la función + es necesario cerrar la sesión actual de AutoCAD e iniciar una nueva sesión.

Operaciones matemáticas básicas

Page 15: Autolisp Gera

En los artículos anteriores ya vimos algún ejemplo de como funcionan las funciones matemáticas básicas (suma, resta, división y multiplicación). Ahora explicaremos su funcionamiento con mayor profundidad.

(+ [número1 número2 ... ] )Suma los números indicados como argumentos y devuelve el resultado de dicha suma. Si todos los números de la lista son enteros, el resultado también será entero.

(+ 3 9) devuelve 12

(+ 3.0 9) devuelve 12.0

(setq a (+ 3 9 4)) devuelve 16 y lo almacena en la variable a

(+ 3.5 -1) devuelve 2.5

Prueba ahora la siguiente expresión:

(setq a (+ a 2.5)) devuelve 18.5

Hemos asignado a la variable a el resultado de una operación en la que usamos el anterior valor asignado a la variable a como uno de los argumentos de la operación.

Si le pasamos a la función + un único número como argumento, nos devuelve ese número.

(+ 12.5) devuelve 12.5

(+ -7.0) devuelve -7.0

Si ejecutamos la función suma sin argumentos, devuelve 0.

(+ ) devuelve 0

La expresión (+ .5 2) nos dará un error. Los números reales siempre deben comenzar por un número entero, incluso si es cero, seguido de la parte decimal.

(+ 0.5 2) devuelve 2.5

(+ 3 -0.6) devuelve 2.4

(- [número1 número2 ... ] )Resta al primer número todos los siguientes números pasados como argumentos. Si todos los números de la lista son enteros, el resultado también será entero.

(- 11.0 5) devuelve 6.0

Page 16: Autolisp Gera

(- 11 5) devuelve 6

(setq a (- 12 5 4)) devuelve 3 y lo almacena en la variable a

(- 3.5 -1) devuelve -4.5

(setq a (- a 2.5)) devuelve 0.5 y lo almacena en la variable a.

Si le pasamos a la función - un único número como argumento, nos devuelve ese número cambiado de signo.

(- 12.5) devuelve -12.5

(- -7.0) devuelve 7.0

En la expresión anterior, el primer signo “-” representa a la función resta, mientras que el segundo representa el signo de un número negativo.

Si ejecutamos la función resta sin argumentos, devuelve 0.

(- ) devuelve 0

(* [número1 número2 ... ] )Multiplica los números indicados como argumentos y devuelve el resultado de dicho producto. Si todos los números de la lista son enteros, el resultado también será entero.

(* 3 9) devuelve 27

(* 3.0 9) devuelve 27.0

(setq a (* 3 9 4)) devuelve 108 y lo almacena en la variable a

(* 3.5 -1) devuelve -3.5

Prueba ahora la siguiente expresión:

(setq a (* a 2.5)) devuelve 270.0

Si le pasamos a la función * un único número como argumento, nos devuelve ese número.

(* 12.5) devuelve 12.5

(* -7.0) devuelve -7.0

Si ejecutamos la función * sin argumentos, devuelve 0.

(* ) devuelve 0

(/ [número1 número2 ... ] )

Page 17: Autolisp Gera

Divide el primer número entre el siguiente y devuelve el resultado. Si se pasan más de dos números como argumentos, el primer número se dividirá entre el producto de los restantes números.

(/ 45 5 3) devuelve 3

(/ 11 5.5) devuelve 2.0

En esta función es muy importante recordar que si todos los números de la lista son enteros, el resultado también será entero.

(/ 7 2) devuelve 3

(/ 7 2.0) devuelve 3.5

(setq a (/ 12.5 4 2)) devuelve 1.5625 y lo almacena en la variable a

(/ 3.5 -1) devuelve -3.5

(setq a (/ a 0.5)) devuelve 3.125 y lo almacena en la variable a

Si le pasamos a la función / un único número como argumento, nos devuelve ese número.

(/ 12.5) devuelve 12.5

(/ -7.0) devuelve -7.0

Si ejecutamos la función / sin argumentos, devuelve 0.

(/ ) devuelve 0

(1+ <número> )Esta función incrementa en una unidad el número indicado como argumento.

(1+ 5) devuelve 6. Ojo entre “1” y “+” no debe haber ningún espacio, ya que el nombre de la función es “1+“.

(1+ 2.5) devuelve 3.5

(1+ 0) devuelve 1

(1+ -7) devuelve -6

Una aplicación bastante habitual de esta función es la de incrementar índices o contadores:

(setq i 1)

(setq i (1+ i)) devuelve 2

(1- <número> )

Page 18: Autolisp Gera

Esta función reduce en una unidad el número indicado.

(1- 5) devuelve 4. Ojo entre “1” y “-” no debe haber ningún espacio, ya que el nombre de la función es “1-“.

(1- 2.5) devuelve 1.5

(1- 0) devuelve -1

(1- -1) devuelve -2

Solicitar números al usuario

En este artículo veremos dos funciones de AutoLISP que nos permitirán solicitar al usuario un número entero o real. Esto nos permitirá interactuar con el usuario y pedirle información.

(GETINT [mensaje] )Solicita del usuario un número entero. En caso de que el usuario introduzca un número real o cualquier otro dato que no sea un número entero, AutoCAD recordará mediante un mensaje que está solicitando un número entero y no finalizará la ejecución de la función hasta que se introduzca un valor entero, o se pulse ESC para cancelar su ejecución.

(getint)

Puede indicarse un mensaje de solicitud opcional, que facilite al usuario información acerca de lo que se está pidiendo. El mensaje debe ser una cadena de texto y por tanto debe estar entre comillas.

(getint “¿Cuántos años tienes?:“)

Podemos asignar el valor introducido por el usuario a una variable y así utilizarlo después.

(setq edad (getint “¿Cuántos años tienes?:“))

(setq edad (+ edad 1)) nos dará la edad que tendrás el próximo año.

También puedes crear una variable que contenga el mensaje de solicitud de la función GETINT

(setq mens “¿Cuántos años tienes?:“)

(setq edad (getint mens))

Page 19: Autolisp Gera

En este caso mens es una variable que almacena una cadena de texto, pero no es una cadena de texto. Por lo tanto, no debe ir entre comillas.

Prueba ahora el siguiente ejemplo:

(setq a 27 mens “¿Cuántos años tienes?:“)

(setq edad (getint mens))

Que pasará si como respuesta a la solicitud de la edad del usuario se introduce !a. Parece lógico que le estamos indicando el valor de la variable a, que contiene el valor numérico 27, de modo que la variable edad debería tomar el valor 27, pero observaras que no es así. Haz la prueba: nos indicará que es “Imposible volver a entrar en LISP.”. Esto es debido a que al ejecutar la función GETINT se está ejecutando el interprete de LISP, y al indicar !a como respuesta estamos diciendo que ejecute el interprete de LISP para obtener el valor asociado a la variable a. Como el interprete de LISP ya está en ejecución, no puede volver a ejecutarse y nos muestra el mensaje anterior.

(GETREAL [mensaje] )Solicita del usuario un número real. En caso de que el usuario introduzca un número entero, el interprete de AutoLISP lo considerará como un real. Si se introduce cualquier otro tipo de dato que no sea numérico, recordará mediante un mensaje que está solicitando un número real y no finalizará la ejecución de la función hasta que se introduzca un valor numérico, o se pulse ESC para cancelar su ejecución.

(getreal)

Puede indicarse un mensaje de solicitud opcional, que facilite al usuario información acerca de lo que se está pidiendo. El mensaje debe ser una cadena de texto y por tanto debe estar entre comillas.

(setq peso (getreal “¿Cuántos kilos pesas?:“))

(setq peso (- peso 1)) nos dará el peso que tendrás si adelgazas un kilo.

También puedes crear una variable que contenga el mensaje de solicitud de la función GETREAL

(setq mens “¿Cuántos kilos pesas?:“)

(setq peso (getreal mens))

Funciones de usuario y nuevos comandos

Page 20: Autolisp Gera

Definir funciones de usuarioHemos visto tan solo algunas de las funciones de AutoLISP, pero también es posible crear nuestras propias funciones. Es más, podemos redefinir las funciones de AutoLISP e incluso los comandos de AutoCAD. La instrucción de AutoLISP que nos permitirá crear nuestras propias funciones, denominadas funciones de usuario, se llama DEFUN.

(DEFUN <función> ( [argumentos] / [variables_locales] ) [expr1] [expr2] …)El primer argumento representa el nombre de la función de usuario que queremos definir. Hay que tener cuidado de no emplear los nombres de las funciones de AutoLISP, ya que en dicho caso se redefinirían.

Después de indicar el nombre de la función, se deben indicar entre paréntesis los argumentos y las variables locales, separados por una barra inclinada:

los argumentos son valores que recibirá la función cuando sea ejecutada por el usuario, o llamada desde otras funciones

las variables locales son aquellas variables que se emplearán tan solo dentro de la función que queremos definir, de modo que restringimos su uso al entorno de la función

Por último, se añaden las expresiones que ejecutará la función. Veamos algunos ejemplos:

(defun 2+ ( valor ) (+ valor 2))

En este caso hemos definido una nueva función llamada “2+“, que recibe como argumento un número y realiza la suma de ese número y 2. Las funciones de AutoLISP las ejecutamos escribiendo directamente desde la línea de comandos, bien pues las funciones de usuario se ejecutan exactamente igual. Prueba:

(2+ 5) devuelve 7

(2+ 0) devuelve 2

(2+ -2) devuelve 0

Defun devuelve el resultado de la última expresión ejecutada, que en el caso anterior es (+ valor 2).

¿Que sucede si tratamos de ejecutar la función sin pasar ningún argumento, o pasando un argumento que no sea de tipo numérico?. Veamos:

(2+ ) indica “; error: argumentos insuficientes”

Page 21: Autolisp Gera

(2+ “texto“) indica “; error: tipo de argumento erróneo: numberp: “texto””

(2+ 1 2) indica “; error: demasiados argumentos”

Podrías pensar que el número indicado se almacena en una variable llamada “valor“, pero no es así. Puedes comprobarlo escribiendo !valor en la línea de comandos, lo que nos devolverá nil.

En la función anterior tenemos un argumento y no hay variables locales. La vamos a modificar un poco:

(defun 2+ ( valor ) (setq valor (+ valor 2)))

Ahora seguro que estas totalmente convencido de que el resultado obtenido se almacena en la variable “valor“. Pues comprobemos si tienes razón:

(2+ 5) devuelve 7

!valor devuelve nil

La función “2+” recibe como argumento un número, que almacena en la variable “valor“. Pero el ámbito de aplicación es local, es decir una vez que salgamos de la función “2+” la variable “valor” recupera su valor inicial, que en este caso es nil. Vamos con otra prueba…

(setq valor 5) devuelve 5

(2+ 4) devuelve 6

¿Que valor crees que tendrá la variable valor? Pensemos un poco.

inicialmente valor era nil al ejecutar (setq valor 5) asignamos a la variable valor el número entero 5

cuando llamamos a la función “2+” con la expresión (2+ 4) tenemos que “valor” es 4

dentro de la función “2+” asignamos (setq valor (+ valor 2)) de modo que “valor” será 6

pero como se trata de una variable local, al salir de la función “2+” recuperamos el valor que tenía la variable “valor” antes de llamar a la función, de modo que valor será 5

por tanto, si tecleamos !valor devolverá 5

Pero, que pasa si ejecutamos (setq valor (2+ 4)). Se repiten los puntos 1-4 anteriores, pero al salir de la función “2+” le asignamos a “valor” el valor devuelto por la función, que es 6. De modo que “valor” será 6.

Retoquemos un poco más la función “2+”

Page 22: Autolisp Gera

(defun 2+ ( valor ) (setq inicial valor valor (+ valor 2)))

y borremos el contenido de “valor”. Para ello simplemente le asignamos nil.

(setq valor nil)

En este caso, dentro de la función “2+” declaramos una variable a la que se le asigna el valor que recibe como argumento la función.

(2+ 4)

¿Que valor tendrán ahora las variables “valor” e “inicial“? Vamos a comprobarlo:

!valor devuelve nil tal como sucedía en el ejemplo anterior

!inicial devuelve 4

Observa que “valor” se comporta como una variable local, solo se emplea dentro de la función. Sin embargo “inicial” es de ámbito global, es decir se sigue empleando al salir de la función. Vamos a modificar un poquito más nuestra función:

(defun 2+ ( valor / inicial ) (setq inicial valor valor (+ valor 2)))

Ahora hemos añadido la variable “inicial” a la lista de variables locales, con lo que su ámbito será local. Para comprobarlo…

!inicial devuelve 4

(setq inicial nil)

!inicial devuelve nil

(2+ 3)

!inicial devuelve nil

Bueno, vamos con la última modificación de la función “2+”

(defun 2+ ( / valor ) (setq valor (getint “Número: “)) (setq valor (+ valor 2)))

Ahora la función “2+” no tiene argumentos, así que para ejecutarla tan solo debemos poner su nombre entre paréntesis:

(2+)

La variable “valor” es de ámbito local y se emplea GETINT para solicitar un número al usuario.

Lo habitual es que se trate de evitar el uso de variables globales innecesarias. De modo que las variables que no sean globales, se deberán añadir a la lista de variables locales dentro de las definiciones de las funciones de usuario.

Crear nuevos comandos de AutoCAD

Page 23: Autolisp Gera

La función de AutoLISP DEFUN no solo permite crear funciones de usuario, también permite crear nuevos comandos de AutoCAD.

Siguiendo con el ejemplo anterior…

(defun C:2+ ( / valor ) (setq valor (getint “Número: “)) (setq valor (+ valor 2)))

Si anteponemos al nombre de la función a definir “C:” en lugar de crear una función de usuario, se crea un nuevo comando de AutoCAD. La función seguirá funcionando exactamente igual, la única diferencia está en el modo de ejecutarse. Ahora no es necesario poner el nombre de la función entre paréntesis, sino que se escribe directamente en la ventana de comandos de AutoCAD.

2+

También se puede ejecutar poniendo el nombre de la función precedido de “C:” entre paréntesis.

(C:2+)

En caso de que el nuevo comando creado necesite algún argumento, tan solo podrá ejecutarse del último modo.

(defun C:2+ ( valor / inicial ) (setq inicial valor valor (+ valor 2)))

(C:2+ 2) devuelve 4

Si escribimos directamente “2+” AutoCAD mostrará el mensaje “error: argumentos insuficientes”.

Si tratamos de escribir “2+ 2” en la ventana de comandos de AutoCAD veremos que al escribir el espacio entre el nombre de la función y el argumento, AutoCAD ejecuta lo que cree que es un comando. Por este motivo ahora sólo podríamos ejecutar la función si la llamamos escribiendo (C:2+ 2) en la ventana de comandos de AutoCAD.

La función que hemos creado solo nos servirá para la sesión actual de AutoCAD. Es más, tan solo está definida la función 2+ en el dibujo actual, de modo que si hay más dibujos abiertos, en ellos no estará definida.

En el siguiente tema veremos como guardar nuestras funciones en archivos de texto, a la vez que comenzamos a trabajar con el entorno de Visual LISP.

Introducción al entorno de Visual LISP

Page 24: Autolisp Gera

Archivos de código fuente en AutoLISPYa hemos visto que las funciones de AutoLISP se pueden ejecutar directamente desde la ventana de comandos de AutoCAD. Pero el escribir el código directamente en AutoCAD tiene varios inconvenientes, como ya se comentó en el primer artículo del curso:

el reducido tamaño de la ventana de comandos de AutoCAD la dificultad de escribir todo el código seguido, sin tabular. Esto es debido a que

cada vez que se pulsa Intro, AutoCAD evalúa lo que se ha escrito

el código no se almacena en ningún sitio, así que se perderá al cerrar el dibujo actual o AutoCAD

De modo que en la ventana de comandos de AutoCAD tan sólo se escribirán pequeñas líneas de código que no interese guardar. Suele emplearse por tanto para hacer pruebas y depurar código, aunque también se puede utilizar como una ayuda más para el diseño con AutoCAD.

El código de las funciones de AutoLISP se escribe en un editor de textos ASCII, para que así se puedan almacenar. Se puede emplear cualquier editor de texto que permita tan solo códigos ASCII, por ejemplo el bloc de notas de Windows. Otros editores, como MS Word, insertan códigos para diferenciar los estilos de texto, las tabulaciones, etc. y no se pueden emplear para escribir las rutinas de AutoLISP, ya que el interprete de AutoLISP no sabe interpretar esos códigos.

Además del bloc de notas, existen muchos otros editores de texto que se pueden emplear para escribir código fuente en AutoLISP. Algunos de estos editores, disponen de utilidades para la programación (permitiendo incluso emplearlos para distintos lenguajes de programación). Otros editores están ya enfocados a la programación en LISP o AutoLISP.

Desde la versión 14, AutoCAD incorpora un editor para AutoLISP, en el que tenemos entre otras las siguientes utilidades:

evaluación de paréntesis durante la programación posibilidad de compilar el código, consiguiendo así aumentar su velocidad de

ejecución

depurador de código específico para AutoLISP con opciones para: Ejecutar el código paso a paso, indicar puntos de parada, evaluar expresiones y valores de variables, etc.

diferenciar el código fuente con distintos colores

tabulado automático del código

Page 25: Autolisp Gera

utilidades para gestionar proyectos con varios archivos de código

carga de los archivos en AutoCAD

Nosotros seguiremos utilizando la ventana de comandos de AutoCAD para ver como trabajan las funciones de AutoLISP, y nos iremos al editor de Visual Lisp para crear nuevas funciones y comandos.

Los archivos de AutoLISP son archivos de texto con extensión LSP.

Nuestra primera función de usuarioAntes de comenzar con el editor de Visual LISP, vamos a crear nuestra primera función de usuario: Se trata de una función para convertir un ángulo de radianes a grados decimales, algo que nos será muy útil en muchas de las macros que creemos a lo largo del curso. El código de la función sería el siguiente:

(defun RAG ( ang )

(/ (* ang 180.0) pi)

)

Hay tres reglas básicas que sigue AutoLISP:

1. el número de paréntesis de apertura debe ser igual al número de paréntesis de cierre

2. primero se evaluan las listas más interiores

3. toda función de AutoLISP devuelve un resultado

El interprete de AutoLISP no evalúa los retornos de carro (Intros), de modo que el código se podía haber escrito todo seguido, en una misma línea:

(defun RAG ( ang ) (/ (* ang 180.0) pi) )

pero así es más difícil de leer. Esta función tiene muy poco código, pero imagina una función mucho mayor escrita toda en la misma línea.

Fíjate en que la segunda línea se presenta tabulada, de modo que no comienza a la misma altura que el resto, sino que está desplazada hacia la derecha. Esto nos indica que está incluida dentro de una lista de nivel superior, la de la función defun.

No es necesario tabular el código, pero facilita su lectura y además nos permite detectar posibles errores con los paréntesis (Regla número 1).

Pi es una constante que ya está definida en AutoLISP, pi equivale al número 3.141592…

En la primera línea “(defun RAG ( ang )” definimos la función RAG (Radianes A Grados) que recibe un argumento “ang” (el ángulo en radianes).

Page 26: Autolisp Gera

Veamos como funciona la segunda línea: Por la Regla número 2, primero se evaluará la lista interior (* ang180.0) que multiplica el ángulo en radianes “ang” por 180.0 y devuelve el resultado a la lista de nivel superior (recuerda la Regla número 3) que lo divide entre pi = 3.141592… devolviendo a su vez el resultado de la división (el ángulo en grados decimales) a la lista de nivel superior, defun.

La última línea cierra la lista de la función defun, cumpliendo así con la Regla número 1.

Recordemos la estructura de la función de AutoLISP defun: (DEFUN <función> ( [argumentos] / [variables_locales] ) [expresión1] [expresión2] …) . En la función RAG tenemos un argumento y no se han declarado variables locales (por lo que no es necesario poner el caracter “/“), además solo tenemos una expresión (/ (* ang 180.0) pi) . Como se dijo en el tema anterior, defun devuelve el resultado de la última expresión, que en nuestro caso resulta ser el ángulo ya convertido a grados decimales.

Nuestra función RAG se ejecutaría así:

(RAG 1.57)

siendo 1.57 el ángulo en radianes, y devolvería ese ángulo en grados decimales (aproximadamente 90º).

No es necesario poner el nombre de la función RAG en mayúsculas, ya que AutoLISP no diferencia las mayúsculas de las minúsculas (salvo en contadas excepciones al trabajar con textos, como ya veremos). A lo largo de los artículos del curso se mostrarán los nombres de las funciones de usuario en mayúsculas simplemente para que se diferencien perfectamente del resto del código.

Los comentarios en el códigoEs imprescindible añadir comentarios al código para explicar qué es lo que hace y cómo se hace.

En AutoLISP todo lo que en una línea va después de un punto y coma (como este ;) se considera un comentario, de modo que no se evalúa. Da igual poner uno, dos o 45 puntos y comas seguidos, al poner el primero AutoLISP ya sabe que todo lo que está a continuación, en esa línea, es un comentario.

Tal vez pienses que no es tan importante añadir explicaciones en el código. Pero si tienes que leer una rutina que creaste hace meses serán muy útiles, por que seguramente no recordaras muy bien como funciona. Además, si alguien va a leer alguna de vuestras rutinas le facilitaras mucho la labor. Al igual que a ti te será más sencillo leer y entender una rutina con abundantes comentarios.

Para los comentarios incluidos en el código, se recomienda utilizar el siguiente método:

;;; Antes del código de las funciones, explicando su funcionamiento

Page 27: Autolisp Gera

;; En medio del código del programa

; Para explicar una línea de código. A diferencia de las anteriores, esta no se inserta en la columna 1, sino al terminar el código de la línea que comenta

Por ejemplo, la función RAG con comentarios podría quedar así:

;;; Esta función recibe el valor de un ángulo en radianes y lo devuelve en grados decimales.

(defun RAG ( ang ) ; Recibe un ángulo en radianes

(/ (* ang 180.0) pi)

;; Multiplica el ángulo en radianes por 180.0 y lo divide por pi.

)

El editor de Visual LISPEl editor de Visual LISP se inicia desde AutoCAD de varias formas:

Ejecutando el comando de AutoCAD “VLIDE“. Desde el menú desplegable de AutoCAD “Herr–>AutoLISP–>Editor de Visual

LISP“

Mostrará algo similar a la siguiente imagen:

Page 28: Autolisp Gera

El editor de Visual LISP

Al abrir el editor veremos dos ventanas, “consola de Visual LISP” y “Rastreo“. De momento no nos vamos a parar a ver para qué sirven o cómo funcionan estas ventanas.

Estamos ante un editor de textos, como otro cualquiera, pero con utilidades específicas para la programación en AutoLISP. De modo que para crear un nuevo archivo hacemos lo mismo que en cualquier editor de textos: “Archivo–>Nuevo archivo” (o pulsa Control + N).

Aparece una nueva ventana, tal como puede verse en la siguiente imagen:

Page 29: Autolisp Gera

Nueva ventana de código en el editor Visual LISP

Es en esta pantalla donde vamos a escribir el código de nuestra rutina RAG, pero antes un pequeño comentario…

Es bastante habitual añadir al principio de los archivos de AutoLISP unas líneas de comentarios indicando el nombre del autor, fecha, nombre de los comandos y/o funciones definidas en el archivo, y una breve descripción de estos. De modo que al código anterior le añadiremos unas líneas en la cabecera del archivo:

;;;____________________Eduardo Magdalena____________________;;;

;;;_________________________RAG.LSP___________________________;;;

;;;_______________________Versión 1.0_________________________;;;

;;;________________________21/02/2002_________________________;;;

;;; Esta función recibe el valor de un ángulo en radianes y lo devuelve en grados decimales.

(defun RAG ( ang ) ; Recibe un ángulo en radianes

(/ (* ang 180.0) pi)

;; Multiplica el ángulo en radianes por 180.0 y lo divide por pi.

Page 30: Autolisp Gera

)

El editor de Visual LISP realiza las tabulaciones automáticamente. Y aunque se pueden eliminar o modificar a nuestro gusto (añadiendo o quitando espacios y tabulaciones), lo recomendable es mantener el formato por defecto para el código. Veamos como queda la función RAG en el editor:

La función RAG en el editor de Visual LISP

En primer lugar observamos que el código tiene distintos colores. Esto es simplemente una ayuda visual para diferenciar los diferentes elementos de nuestras rutinas:

las funciones de AutoLISP se muestran de color azul setq los comentarios en morado ;Esto es un comentario

los paréntesis en color rojo (setq a 2.0)

los números en color verde 2.0

los textos en color rosa (en este ejemplo no aparece ningún texto, pero veremos algunos ejemplos más adelante) “Soy un texto“

el resto de elementos, como los nombres de las funciones y de las variables utilizadas, se muestran en color negro

Page 31: Autolisp Gera

Además, las funciones de usuario se destacarán escribiéndose en mayúsculas RAG.

Este formato de colores se utilizará también en los artículos de este curso, tal como se muestra en el código de la función RAG anterior.

El formato coloreado del código se puede desactivar, o se pueden modificar los colores predefinidos para los diferentes elementos. Pero el mantener el formato de colores para el código, nos puede ayudar a detectar errores.

Por ejemplo, si ponemos “(setw radianes 1.57)”

SETW aparecerá en negro y no en azul, por que la función de AutoLISP es SETQ, de modo que nos indica que hemos escrito mal el nombre de la función.

En cuanto a la tabulación, tal vez llame la atención el último paréntesis (el de cierre de la función defun), ya que no está a la misma altura que su paréntesis de apertura. Hay editores para AutoLISP que insertan los paréntesis de cierre a la misma altura que sus correspondientes paréntesis de apertura y hay otros editores que insertan los paréntesis de cierre tabulados, tal como hace (por defecto) el editor de Visual LISP.

Una vez escrito el código de la función RAG, tan solo nos queda guardarlo en un archivo. Es recomendable crear un directorio (carpeta) en el que guardar todas nuestras rutinas.

Veremos más adelante que se pueden guardar varias funciones y varios comandos en un mismo archivo de AutoLISP, aunque en este caso sólo se ha definido una nueva función de usuario.

Se le suele dar a los archivos de AutoLISP el mismo nombre del comando o función que esté definida en él, podemos guardar esta rutina en el archivo “klhsduif.lsp” pero luego no la reconoceríamos. Así que lo mejor será guardar el código de la función RAG en el archivo “RAG.lsp“, dentro del directorio que hemos creado para almacenar nuestras rutinas. Así que selecciona “Archivo –> Guardar como” e indica la ruta y el nombre del archivo.

Ahora puedes intentar crear una función llamada GAR que reciba como argumento un ángulo en grados decimales y que devuelva ese ángulo en radianes. Es prácticamente igual a la función que acabamos de ver. Pero recuerda… Antes de empezar a programar (como antes de hacer casi cualquier cosa) conviene pensar en lo que se va a hacer y en cómo lo vamos a hacer. Como esta rutina es muy sencilla no es necesario escribir el pseudocódigo (ni hacer un diagrama de flujo), tan solo hay que pensar un poco en lo que se va a hacer. Guarda el código de la función GAR en un archivo llamado “GAR.lsp” en el directorio donde tengas tus rutinas.

Cargar los archivos de AutoLISP

Page 32: Autolisp Gera

Para que la función RAG que creamos en el artículo anterior se pueda ejecutar en AutoCAD, hay que cargar el archivo de AutoLISP en el que está definida. Existen varias formas de cargar los archivos de AutoLISP, pero de momento tan solo vamos a ver tres:

1. Cargar un archivo desde el editor de Visual LISP2. En el menú desplegable de AutoCAD “Herr–>AutoLISP–>Cargar aplicación…“.

3. Utilizando la función de AutoLISP LOAD.

Si estamos en el editor de Visual LISP y tenemos abierto un archivo con una rutina, para cargarla en AutoCAD podemos:

Seleccionar en los menús desplegables del Visual LISP “Herramientas –> Cargar texto en editor“.

Pulsando sobre el icono  .

Tecleando la combinación de teclas CTRL+ALT+E.

Al cargar el archivo, aparece la Consola de Visual LISP mostrando un mensaje parecido al siguiente: “; N formularios cargado de #<editor “RUTA/rag.lsp”>. En caso de que se produzca algún error en el proceso de carga del archivo, en la consola de Visual LISP se nos indicaría el tipo de error que se ha producido. De modo que habria que modificar el código para corregir ese error antes de cargar la rutina.

Una vez cargada la rutina en AutoCAD, podemos probar si funciona. Teclea directamente en la ventana de comandos de AutoCAD:

(RAG 0) (RAG pi)

(RAG (/ pi 4))

El segundo método para cargar un archivo de AutoLISP en AutoCAD (seleccionando en el menú de AutoCAD “Herr–>AutoLISP–>Cargar aplicación…“) muestra un letrero de diálogo en el que se selecciona el archivo a cargar y se pulsa el botón “Cargar“.

Page 33: Autolisp Gera

Cargar / Descargar aplicaciones

Este método ofrece dos ventajas:

se puede seleccionar más de un archivo permite descargar las funciones de AutoLISP definidas en los archivos

seleccionados

(LOAD archivo [resultado_si_falla])La función LOAD permite cargar en AutoCAD el archivo de AutoLISP que se indique. Por ejemplo para cargar el archivo RAG sería:

(load “rag“)

No hace falta indicar la extensión del archivo. Escribiendo así el nombre del archivo solo cargará el archivoRAG.LSP si está en uno de los directorios de soporte de AutoCAD o en el directorio actual. En caso contrario hay que indicar la ruta completa:

Page 34: Autolisp Gera

(load “c:\rutinas\rag.lsp“)

Pero si lo hiciéramos así nos daría un error, ya que AutoCAD no reconoce el carácter “\“, de modo que hay que escribirlo de forma algo especial. Para AutoLISP el caracter “\” hay que indicarlo de cualquiera de esas 2 formas: “\\” o “/“. Por lo tanto escribiremos:

(load “c:\\rutinas\\rag.lsp“)

o

(load “c:/rutinas/rag.lsp“)

En caso de que no se encuentre el archivo, la expresión load puede ejecutar lo que se indique en [resultado_si_falla]. Por ejemplo:

(load “rag” (setq test 0))

En este caso, si no se encuentra el archivo RAG.lsp a la variable test se le asigna el valor cero. Suele emplearse para que, cuando se ejecute LOAD desde dentro de una función de AutoLISP, podamos indicarle al usuario que no se ha encontrado el archivo. Como indica el siguiente pseudocódigo:

Si test = 0 ==> Mensaje al usuario “Archivo no encontrado”

Esto es todo, de momento, sobre la carga de archivos de AutoLISP en AutoCAD. Más adelante veremos otros métodos para cargar nuestras rutinas.

Veamos como sería la función GAR propuesta en el tema anterior:

;;;_____________________Eduardo Magdalena_____________________;;;

;;;_________________________GAR.LSP___________________________;;;

;;;_______________________Versión 1.0_________________________;;;

;;;________________________21/02/2002_________________________;;;

;;; Esta función recibe el valor de un ángulo en grados decimales y lo devuelve en radianes.

(defun GAR ( ang ) ; Recibe un ángulo en grados decimales

(/ (* ang pi) 180.0) 

;; Multiplica el ángulo en grados decimales por Pi y lo divide por 180.0.

)

Es muy muy parecida a la función RAG, no?

Crear un directorio para los archivos de AutoLISP

Page 35: Autolisp Gera

Supongamos que el directorio que hemos creado para almacenar nuestras rutinas es “C:\Rutinas“. Veamos como añadirlo a los directorios de soporte de AutoLISP:

Inicia AutoCAD. En el menú desplegable “Herr” selecciona “Opciones…“. Así aparece un letrero de diálogo que nos permitirá configurar AutoCAD. En la primera pestaña “Archivos” tenemos una opción denominada “Ruta de búsqueda de archivos de soporte“. Si no está expandida, para ver su contenido pulsamos con el ratón sobre el + que aparece a la izquierda.

Para añadir un nuevo directorio de soporte pulsamos el botón “Añadir” que se encuentra a la derecha del cuadro de diálogo. Esto creará una nueva etiqueta, en la que podemos escribir la ruta del directorio o pulsar el botón “Examinar” para seleccionarlo. Ya hemos añadido “C:\Rutinas” a los directorios de soporte de AutoCAD.

Opciones de AutoCAD

También podemos subir o bajar el nuevo directorio en la lista de directorios de soporte. Esto se hace para definir las prioridades, es decir donde buscar primero. De modo que si subimos nuestro directorio hasta el primer lugar (como en la imagen), este será el primer directorio en el que busque AutoCAD.

Operaciones matemáticas en AutoLISP

Page 36: Autolisp Gera

Hemos visto las operaciones matemáticas básicas: suma, resta, multiplicación y división y las funciones 1+ y1-. Ahora vamos con otras funciones de AutoLISP que nos permitiran realizar casi cualquier operación matemática en nuestras rutinas.

(ABS numero)Esta función devuelve el valor absoluto del número que se le pase como argumento. Por ejemplo:

(abs 23.8) devuelve 23.8

(abs -23.8) también devuelve 23.8

Si el número que recibe como argumento es entero, devuelve un número entero y si es un número real, devuelve un real.

(abs -7) devuelve 7

(abs -7.0) devuelve 7.0

(abs 0) devuelve 0

(FIX numero)Esta función devuelve la parte entera de un número. De modo que devuelve un número entero. Ojo! esta función no redondea, sino que elimina lo que está detrás del punto decimal.

(fix 15.8) devuelve 15.

(fix -15.8) devuelve -15

(fix 0.99) devuelve 0

(fix -0.99) devuelve 0

(REM numero1 numero2 [numero3] …)Esta función devuelve el resto de la división de numero1 entre numero 2.

(rem 2.5 2) devuelve 0.5

(rem 3 2) devuelve 1

Cuando se indican más de 2 números (rem 1 2 3) es equivalente a (rem (rem 1 2) 3). Es decir, primero calcula el resto de la división entre 1 y 2, que es 1, y después lo divide entre 3 y devuelve su resto, que es 1.

Page 37: Autolisp Gera

Si todos los números que recibe como argumentos son enteros, devuelve un número entero y si alguno de ellos es un número real, devuelve un real.

(rem 3 2.0) devuelve 1.0

(SIN angulo)Devuelve el seno de un ángulo indicado en radianes.

(sin 0) devuelve 0.0

(sin (/ pi 2)) devuelve 1.0

(COS angulo)Funciona igual que la anterior, pero devuelve el coseno del ángulo, que recibe en radianes.

(cos 0) devuelve 1.0

(cos pi) devuelve -1.0

(ATAN numero 1 [numero2])Devuelve el arco cuya tangente sea numero1. Por ejemplo:

(atan 0) devuelve 0.0 ya que el ángulo que tiene tangente 0 es el 0.0

Si se indica un segundo número (atan num1 num2) lo que hace es dividir num1 entre num2 y devuelve el arco cuya tangente sea el resultado de la división. Esto se hace para facilitar lo siguiente…

(atan (sin angulo) (cos angulo)) devuelve angulo

(SQRT numero)Esta función devuelve la raiz cuadrada del numero que recibe como argumento. Siempre devuelve un número real, no entero.

(sqrt 4) devuelve 2.0

(sqrt 2.0) devuelve 1.41…

(EXPT num exp)Devuelve el número num elevado al exponente exp.

(expt 2 2) devuelve 4

(expt 2 3) devuelve 8

Page 38: Autolisp Gera

Si todos los números que recibe como argumentos son enteros, devuelve un número entero y si alguno de ellos es un número real, devuelve un real.

(expt 3 2.0) devuelve 9.0

(EXP num)Devuelve el número e ( e = 2.71828… ) elevado al número num. Siempre devuelve un número real.

(exp 1) devuelve 2.71828

(exp 2) devuelve 7.38906

(LOG numero)Esta función devuelve el logaritmo neperiano del número que recibe como argumento.

(log 1) devuelve 0.0

(log 2) devuelve 0.693147

(GCD entero1 entero2)Esta función recibe dos números enteros y devuelve su máximo común divisor (o denominador). Siempre devuelve un número entero.

(gcd 15 5) devuelve 5

(gcd 9 33) devuelve 3

(MAX num1 num2 …)Devuelve el mayor de los números que recibe como argumentos.

(max 2 4 1 3 6) devuelve 6

(max 8 4 -9) devuelve 8

Si todos los números que recibe como argumentos son enteros, devuelve un número entero y si alguno de ellos es un número real, devuelve un real.

(max 8 4.0 -9) devuelve 8.0

(MIN num1 num2 …)Devuelve el menor de los números que recibe como argumentos.

(min 2 3 6) devuelve 2

Page 39: Autolisp Gera

(min 8 4 -9) devuelve -9

Si todos los números que recibe como argumentos son enteros, devuelve un número entero y si alguno de ellos es un número real, devuelve un real.

(min 8 4.0 -9) devuelve -9.0

Pues ya están vistas todas las funciones matemáticas… Enhorabuena!!!

Solicitar textos y puntos al usuario

Recuerdas las funciones GETINT y GETREAL? Nos sirven para solicitar al usuario un número entero y real, respectivamente. Pues la función que se utiliza para solicitar textos al usuario es muy parecida.

(GETSTRING [modo] [mensaje])Se puede ejecutar sin parámetros (getstring) pero no es recomendable. Se suele indicar un mensaje de texto que explique al usuario lo que se le está solicitando. Por ejemplo:

(getstring “¿Cuál es tu nombre?“)

Supongamos que te llamas Pepe, a (getstring “¿Cuál es tu nombre?“) responderías Pepe y ya está. Incluso se podría asignar el nombre que indique el usuario a una variable:

(setq nombre (getstring “¿Cuál es tu nombre?“))

Pero que sucede si te llamas José Luis? Pues que en cuanto pulses el espacio es como si hubieras pulsado Intro. No nos permite insertar textos con espacios. Para que admita textos con espacios, debemos hacer un pequeño cambio:

(setq nombre (getstring T “¿Cuál es tu nombre?”))

Le estamos indicando el argumento [modo] = T. Este argumento puede ser cualquier expresión de AutoLISP, en este caso le pasamos el valor T = Cierto, verdadero. Si no se indica el modo, o si al evaluarlo devuelvenil = Falso, vacío; entonces no admite espacios. Y si se pone cualquier expresión que al evaluarse no devuelva nil, permite espacios.

(setq nombre (getstring (+ 1 2) “¿Cuál es tu nombre?“)) permite responder con espacios, ya que (+ 1 2)devuelve 3 que es distinto de nil.

(setq nombre (getstring (setq var1 nil) “¿Cuál es tu nombre?“)) no permite responder con espacios, ya que (setq var1 nil) devuelve nil.

Para solicitar puntos se utilizan dos funciones que también son parecidas a GETINT y a GETREAL.

Page 40: Autolisp Gera

(GETPOINT [pto_base] [mensaje])Esta función le pide un punto al usuario y devuelve una lista con las coordenadas del punto indicado. El usuario puede indicar el punto en pantalla con el ratón o tecleando sus coordenadas, tal y como se haría al dibujar en AutoCAD.

Se puede ejecutar sin parámetros (getpoint) pero no es recomendable. Se suele indicar un mensaje de texto que explique al usuario lo que se le está solicitando. Por ejemplo:

(getpoint “Punto inicial“)

Lo habitual es que además ese punto se almacene en una variable

(setq pto (getpoint “Punto inicial“))

Así asignamos a la variable pto algo parecido a lo siguiente: (120.56 135.88 0.0)

Veamos ahora para que sirve el argumento opcional [pto_base] aprovechando que tenemos el punto ptodefinido.

(getpoint pto “Siguiente punto:“)

Aparece una línea elástica entre el punto pto y la posición del cursor.

(GETCORNER pto_base [mensaje])Esta función se utiliza también para solicitar puntos al usuario. En este caso el punto base no es opcional, hay que indicarlo. Veamos la diferencia entre las dos expresiones siguientes:

(getpoint pto “Siguiente punto:“)

(getcorner pto “Siguiente punto:“)

Al utilizar getpoint, se muestra una línea elástica entre el punto pto y la posición del cursor. Si se utilizagetcorner, en lugar de una línea elástica, aparece un rectángulo.

Fijémonos un momento en lo que devuelven tanto getpoint como getcorner: (125.68 117.68 0.0). Se trata de una lista, una lista con las corrdenadas de un punto. Bien, pues en el próximo artículo veremos algunas funciones para manejar listas.

Funciones para manejar listas

AutoLISP es un lenguaje de programación basado en listas así que es lógico que el tratamiento que reciban las listas de elementos sea muy bueno. Por otra parte, en AutoCAD nos encontraremos listas continuamente y en todas partes, desde las coordenadas de los puntos como se indicaba en el artículo anterior, hasta los datos de las

Page 41: Autolisp Gera

entidades que son almacenados en la base de datos de AutoCAD. Así que vamos a introducir ahora una serie de funciones para manipular listas de elementos.

(CAR lista)Esta función devuelve el primer elemento de la lista que recibe como argumento.

De modo que si (siguiendo con el ejemplo del tema anterior) en la variable pto hemos asignado el valor devuelto por getpoint, tenemos una lista con las coordenadas X, Y y Z del punto designado. Supongamos que pto = (10.0 20.0 0.0).

(car pto) devuelve la coordenada X del punto pto. Es decir 10.0

(CDR lista)Esta función devuelve la lista que recibe como argumento pero sin el primer elemento.

(cdr pto) devolverá una lista formada por las coordenadas Y y Z del punto pto. Es decir, (20.0 0.0)

(CADR lista)Basándonos en las dos funciones anteriores y recordando que podemos ejecutar listas de instrucciones dentro de otras (a esto le llamamos anidamiento): ¿Cómo se obtendría la coordenada Y del punto pto? Veamos:

CDR devuelve la lista sin el primer elemento CAR devuelve el primer elemento de una lista

De modo que (cdr pto) devuelve (Y Z). Así que para obtener la coordenada Y podemos escribir:

(car (cdr pto)) devuelve la coordenada Y del punto pto.

y, ¿cómo obtenemos la coordenada Z? Pues, volviendo a aplicar la función CDR para llegar a la coordenada Z

(cdr pto) devuelve (Y Z) (cdr (cdr pto)) devuelve (Z)

Podrías pensar que escribiendo (cdr (cdr pto)) obtenemos la coordenada Z, sin embargo no es así. La expresión (cdr (cdr pto)) devuelve “una lista” con un único elemento, la coordenada Z del punto pto. Para obtener la coordenada Z del punto pto tenemos que escribir:

(car (cdr (cdr pto))) devuelve la coordenada Z del punto pto.

En resumen, las coordenadas del punto pto se obtendrian mediante:

Page 42: Autolisp Gera

X ==> (car pto) Y ==> (car (cdr pto))

Z ==> (car (cdr (cdr pto)))

Otras funciones combinando CAR y CDRSi en las expresiones indicadas anteriormente para obtener las coordenadas X, Y y Z ponemos las letras A y D de cAr y cDr en mayúsculas, lo anterior quedaría:

X ==> (cAr pto) Y ==> (cAr (cDr pto))

Z ==> (cAr (cDr (cDr pto)))

Este ejemplo es simplemente para introducir una simple regla de mnemotecnia ya que las funciones CAR y CDR se pueden agrupar. Para ello, existen una serie de funciones que se denominan juntando las Aes y las Des de cAr y cDr respectivamente. El ejemplo anterior, queda:

X ==> (cAr pto) Y ==> (cAr (cDr pto)) == (cADr pto)

Z ==> (cAr (cDr (cDr pto))) == (cADDr pto)

Esto nos servirá como regla para recordar el nombre de estas funciones. Debes recordar también que tan solo se permiten 4 niveles de anidación, así que entre la c y la r solo puede haber 4 letras (Aes o Des).

Supongamos que tenemos la siguiente lista asignada a la variable lst = ((“a” “b”) (“c” “d”) (“e” “f”)). OJO!! es una lista en la que sus elementos son a su vez listas.

Puedes definir la variable lst escribiendo: (setq lst (list (list “a” “b“)  (list “c” “d“)  (list “e” “f“)))

¿Cómo obtendríamos “a” ?? (car lst) devuelve (“a” “b”) que es el primer elemento de lst, y “a” es el primer

elemento de (“a” “b”)así que: (car (car lst)) devuelve “a”, o lo que es lo mismo:

(cAAr lst) devuelve “a”

y el elemento “c”?

Page 43: Autolisp Gera

(cDr lst) devuelve la lista sin el primer elemento, es decir ((“c” “d”) (“e” “f”)). Ahora si hacemos (cAr (cDr lst)) devuelve el primer elemento de la lista anterior,

es decir (“c” “d”).

Así que (cAr (cAr (cDr lst))) devuelve “c”, o lo que es lo mismo:

(cAADr lst) devuelve “c”

Cómo obtener “d” ? (cDr lst) devuelve ((“c” “d”) (“e” “f”)) (cAr (cDr lst)) devuelve el primer elemento de ((“c” “d”) (“e” “f”)), es decir

devuelve (“c” “d”)

Si ahora hacemos (cDr (cAr (cDr lst))) obtenemos (“d”), que no es lo mismo que “d”. Ya que se trata de una lista cuyo primer elemento es “d”.

Así que (cAr (cDr (cAr (cDr lst)))) devuelve “d”, o lo que es lo mismo:

(cADADr lst) devuelve “d”

Y cómo obtener “e” ? (cDr lst) devuelve ((“c” “d”) (“e” “f”)) y (cDr (cDr lst)) devuelve ((“e” “f”)). Ojo! se trata de una lista cuyo primer (y

único) elemento es a su vez otra lista con dos elementos.

Así que (cAr (cDr (cDr lst))) devuelve (“e” “f”), de modo que

(cAr (cAr (cDr (cDr lst)))) devuelve “e”, o lo que es lo mismo:

(cAADDr lst) devuelve “e”

Por último, veamos cómo se obtiene “f”. (cAr (cDr (cDr lst))) devuelve (“e” “f”) tal como se vio en el ejemplo anterior. Así que (cDr (cAr (cDr (cDr lst)))) devuelve (“f”), que os recuerdo que se trata de

una lista y que no es lo mismo que “f”.

Por tanto (cAr (cDr (cAr (cDr (cDr lst))))) devuelve “f”.

Podríamos pensar que (cADADDr lst) también devuelve “f”. Pero al ejecutar esta línea AutoCAD nos dice que la función cADADDr no está definida.

Ya dijimos antes que se pueden agrupar hasta 4 funciones cAr y cDr, pero aquí estamos intentando agrupar 5, y lógicamente no podemos. Para obtener “f” podríamos escribir, por ejemplo:

Page 44: Autolisp Gera

(cAr (cDADDr lst)) (cADADr (cDr lst))

(LENGTH lista)En la variable pto teníamos una lista con las coordenadas de un punto, pero si solo trabajamos en 2D, la coordenada Z no nos interesa. Así que muchas veces los puntos tan sólo tendrán 2 coordenadas (X Y). Pero para un programa no es lo mismo que tenga 2 que 3 coordenadas, a lo mejor va a buscar la coordenada Z y no existe produciéndose un error en nuestra rutina.

Así que necesitamos conocer el número de elementos que tienen las listas. Para ello se utiliza la funciónlength, que devuelve el número de elementos de la lista que recibe como argumento. Por ejemplo:

(length pto) devuelve 3. y si el punto pto estuviera en 2D (X Y) devolvería 2.

Y qué devolvería (length lst) ? siendo lst = ((“a” “b”) (“c” “d”) (“e” “f”)). Pues devolvería 3, ya que lst es una lista con 3 elementos, que a su vez son listas de dos elementos cada una.

Qué devolvería (length (car lst)) ? El número de elementos del primer elemento de lst, es decir el número de elementos de (“a” “b”), que es 2.

(LIST elemento1 elemento2 …)Esta función devuelve una lista formada por los elementos indicados. De modo que se utiliza para crear listas. Por ejemplo:

(list 1 2 3) devuelve (1 2 3)

(list “pepe” 2 “Juan“) devuelve (“pepe” 2 “Juan”)

Veamos que hace la siguiente expresión:

(list (list “a” “b“) “c” (list “d” “e“) “f“)

Recuerda que en AutoLISP cuando nos encontramos con listas anidadas unas dentro de otras, siempre se evalúan primero las listas interiores.

(list “a” “b“) devuelve (“a” “b”) (list “d” “e“) devuelve (“d” “e”)

Así que (list (list “a” “b“) “c” (list “d” “e“) “f“) devuelve la siguiente lista ((“a” “b”) “c” (“d” “e”) “f”).

Ejecutar comandos de AutoCAD

Page 45: Autolisp Gera

Una de las mayores ventajas de la programación en AutoLISP es la posibilidad de ejecutar directamente comandos de AutoCAD en nuestras rutinas.

(COMMAND “comando” [datos])Esta es la función que nos permite ejecutar comandos de AutoCAD. Hay dos cosas a tener en cuenta con esta función:

siempre devuelve nil los nombres de los comandos de AutoCAD, y sus opciones, se indican como

textos por lo que van incluidos entre comillas

(command “linea” (list 0.0 0.0) (list 100.0 200.0)) Dibujará una línea desde el origen al punto 100,200. Pero, nos falta algo: Al dibujar líneas en AutoCAD se van indicando puntos y siempre pide “Siguiente punto:” de modo que para terminar el comando “LINEA” hay que pulsar INTRO. Pues ese Intro también hay que pasárlo a la función command:

(command “linea” (list 0.0 0.0) (list 100.0 200.0) “”)

Lo realmente potente de COMMAND es que podemos ejecutar casi todos los comandos de AutoCAD. Cuáles no? Son muy pocos, por ejemplo “Nuevo” para empezar un dibujo nuevo. Pero todos los comandos de dibujo, edición, etc se pueden ejecutar.

Los datos dependerán del comando de AutoCAD indicado. Por ejemplo para el comando “circulo“, será:

(command “circulo” (list 0.0 0.0) 25.0) Esto dibujará una circunferencia de radio 25 con centro en el origen.

Los idiomas de AutoCADSupongamos que no disponemos de una versión en castellano de AutoCAD, sino que está en inglés, o en Francés, o Chino Mandarín; qué pasa si ejecutamos esto:

(command “linea” (list 0.0 0.0) (list 100.0 200.0) “”)

AutoCAD no conocerá el comando “linea“, así que nos dará un error. Por suerte se puede solucionar, ya que sino un programa realizado para AutoCAD en Francés sólo serviría para las versiones en Francés.

AutoCAD en realidad no “habla” un único idioma, sino que es bilingue, dispone de una lengua que es la que muestra (que corresponde con la versión idiomática del programa: Castellano, Francés, etc) y una lengua interna, el Inglés.

Page 46: Autolisp Gera

De modo que los comandos de AutoCAD (y sus opciones) se pueden escribir en Castellano o en inglés. Pero para diferenciar unos de otros a los comandos en la lengua nativa de AutoCAD (Inglés) se les antepone un guión bajo:

(command “_circle” (list 0.0 0.0) 25.0)

(command “_line” (list 0.0 0.0) (list 100.0 200.0) “”)

Las opciones de los comandos también se deben indicar en inglés anteponiendo un guión bajo. Por ejemplo:

(command “_circle” (list 0.0 0.0) “_d” 25.0) Esta línea dibuja una circunferencia de Diámetro 25 con centro en el origen.

Comandos de AutoCAD originalesPor otra parte, ya se ha dicho anteriormente que los comandos de AutoCAD se podrían redefinir para que funcionen de forma distinta. Así se podría cambiar el comando “circulo” para que dibuje pentágonos y el comando “linea” para que dibuje circunferencias.

Si redefinimos el comando línea para que dibuje circunferencias, entonces deberíamos indicar algo similar a (command “linea” centro radio) en lugar de (command “linea” pt0 pt1″”). Pero cómo haríamos entonces para dibujar una línea?

Para ejecutar los comandos originales de AutoCAD, y no los redefinidos (si lo están) debemos anteponer al nombre del comando un punto, por ejemplo:

(command “.circulo” (list 0.0 0.0) 25.0)

(command “.linea” (list 0.0 0.0) (list 100.0 200.0) “”)

Podemos además indicar los comandos en Inglés anteponiendo un guión bajo así que también los podríamos escribir así:

(command “._circle” (list 0.0 0.0) 25.0)

(command “_.circle” (list 0.0 0.0) 25.0)

Da igual si se pone antes el punto o el guión bajo.

Redefinir un comando de AutoCADPara redefinir un comando de AutoCAD debemos:

1. Ejecutar el comando “ANULADEF” (En Inglés “undefine“) indicando el nombre del comando a redefinir. De este modo se elimina la definición del comando de AutoCAD, y la única forma de ejecutarlo será anteponiendo al nombre del comando un punto.

2. Crear y cargar una macro en la que esté definido un nuevo comando con el nombre del comando que acabamos de anular.

Page 47: Autolisp Gera

Veamos un ejemplo:

1. primero anulamos la definición del comando línea.1. Podemos hacerlo desde AutoCAD con el comando “ANULADEF” (En

inglés “undefine“)

2. o desde AutoLISP ejecutando: (command “anuladef” “linea“) o (command “_undefine” “_line“)

2. podemos comprobar que el comando línea ya no funciona

1. Puedes tratar de ejecutarlo en castellano, en inglés, directamente en AutoCAD o en una expresión de AutoLISP

2. la única forma de ejecutarlo es anteponiendo a su nombre un punto “.linea“.

3. Iniciamos el editor de Visual LISP: “Herr. –>AutoLISP –> Editor de Visual LISP”

1. Creamos la macro que se indica a continuación, la guardamos y la cargamos en AutoCAD

(defun C:LINEA ( )

(setq pt (getpoint “Centro del círculo: “))

(setq rad (getreal “Radio del círculo“))

(command “._circle” pt rad)

)

Ahora el comando “linea” dibujará círculos.

Para recuperar el valor original del comando podemos hacer dos cosas:

1. cerrar AutoCAD y abrirlo de nuevo, de modo que la macro que hemos creado se borre de la memoria del ordenador

2. ejecutar el comando de AutoCAD “redefine” (En Inglés es igual, pero con un guión bajo delante) e indicarel nombre del comando del que queremos recuperar su definición original, es decir “linea“.

Bueno, por último un ejercicio: Crear una macro que defina un nuevo comando de Autocad llamadoCIRCPERI que dibuje una circunferencia indicando su centro y la longitud de su perímetro.

Operaciones de comparación

Page 48: Autolisp Gera

En este artículo veremos las funciones de AutoLISP que nos permiten realizar comparaciones, por ejemplo, para ver si algo es mayor que algo, o menor, o si es igual.

(= expr1 expr2 …)Compara si expr1 devuelve el mismo resultado que expr2, en caso afirmativo devuelve T y en caso contrario devuelve nil.

(= 5 (+ 1 4)) devuelve T porque (+ 1 4) devuelve 5

(= 5 (+ 1 4.0)) devuelve T aunque (+ 1 4.0) devuelve 5.0 y no 5. Pero 5 y 5.0 valen lo mismo, no?

(= 5 5.0) devuelve T

No solo podemos evaluar números, también textos:

(setq txt1 “Curso de Lisp“)

(= txt1 “Curso de Lisp“) devuelve T

(= txt1 “Curso de LISP“) devuelve nil. No es lo mismo un texto en mayúsculas que en minúsculas.

(= “LISP” “Lisp“) devuelve nil

Estamos comparando expresiones, así que:

(= (+ 1 5) (/ 12 2)) devuelve T porque ambas expresiones devuelven como resultado 6.

La función = puede aceptar más de dos expresiones:

(= 6 (+ 1 5) 6.0 (/ 12 2)) devuelve T, pues las cuatro expresiones devuelven 6 o 6.0 (que vale lo mismo).

(/= expr1 expr2 …)Es muy similar a la anterior. Devuelve T si las expresiones no devuelven el mismo valor y devuelve nil si todas las expresiones devuelven el mismo valor.

(/= 6 6.0) devuelve nil, porque 6 y 6.0 no son distintos (valen lo mismo).

(/= (+ 5 5) (/ 12 2)) devuelve T, pues la primera expresión devuelve 10 y la segunda 6.

(/= “LISP” “Lisp“) devuelve T

(< expr1 expr2 …)Compara si expr1 es menor q expr2

(< 4 5) devuelve T, ya que 4 es menor que 5

Page 49: Autolisp Gera

(< 4 -5) devuelve nil

(< 5 5.0) devuelve nil

Si se ponen más de 2 expresiones, se comprueba que estén ordenadas de menor a mayor y devuelve T si lo están y nil si no lo están.

(< 1 2 3) devuelve T

(< 1 2 0) devuelve nil

(< (+ 1 2) (* 2 2.0) (/ 12 2)) devuelve T

También podemos comparar textos. El interprete de AutoLISP evalúa los códigos ASCII de los textos. Es decir los ordena alfabéticamente de la “a” a la “z”.

(< “Albacete” “Barcelona“) devuelve T

(< “a” “c“) devuelve T

(< “d” “c“) devuelve nil

(< “C” “c“) devuelve T, puesto que los códigos ASCII de la mayúsculas son inferiores a los de las letras minúsculas.

Los códigos ASCII, son una serie de números que se asignaron a las letras del alfabeto y a algunos de los carácteres más usuales.

El carácter “a” tiene asociado el código 97, la “b” el 98, etc. hasta la “z”.

El carácter “A” tiene asociado el código 65, la “B” el 66, etc. hasta la “Z”.

(> expr1 expr2 …)Supongo que ya os imagináis como funciona, no? Comprueba si las expresiones están ordenadas de mayor a menor.

(> 5 3) devuelve T

(> -2 3) devuelve nil

(> 5 2 3) devuelve nil

(> 5 4 3) devuelve T

Y ahora con los textos:

(> “a” “c“) devuelve nil, pues el código ASCII de “a” es menor que el de “c”.

(<= expr1 expr2 …)Comprueba si las expresiones son menores o iguales que las anteriores.

Page 50: Autolisp Gera

(<= 1 2 2.0 3) devuelve T

(<= 1 3.0 2 3) devuelve nil

(>= expr1 expr2 …)Comprueba si las expresiones son mayores o iguales que las anteriores

(>= 3 2 2.0 1) devuelve T

(>= 3 1.0 2 1) devuelve nil

(>= 3 3 3 3) devuelve T

Macro de ejemploVeamos como se haría el ejercicio propuesto en el artículo anterior: Crear un nuevo comando llamadoCIRCPERI que dibuje una circunferencia indicando su centro y la longitud de su perímetro.

¿Qué es lo primero que hay que hacer? Esta respuesta tiene que ser instintiva, como un acto reflejo: El pseudocódigo.

Siempre comenzaremos nuestras rutinas escribiendo el pseudocódigo (o haciendo un diagrama de flujo) de lo que se pretende hacer. Bien, cómo podría ser el pseudocódigo de esta rutina?, vamos a ver:

1. Pedir al usuario el centro de la circunferencia.2. Pedir al usuario el perímetro de la circunferencia.

3. Calcular el radio de la circunferencia a partir de su perímetro.

4. Dibujar la circunferencia.

Una vez que terminamos el pseudocódigo, ya tenemos el 80% de la rutina. Si el pseudocódigo es correcto, el traducirlo a código es de lo más simple.

Iniciamos en editor de Visual LISP “Herr. –> AutoLISP –> Editor de Visual LISP” y creamos una nueva macro. Primero hay que añadir la definición del nuevo comando CIRCPERI:

(defun C:CIRCPERI ( )

Vamos a ver que es lo que nos indica el pseudocódigo:

1) Pedir al usuario el centro de la circunferencia. Podríamos escribir (getpoint “Centro de la circunferencia”) pero tendríamos que almacenar el punto indicado en una variable, así que añadiremos…

Page 51: Autolisp Gera

(setq pto (getpoint “Centro de la circunferencia“)) ‘almacena el punto centro de la circunferencia en la variable pto.

2) Pedir al usuario el perímetro de la circunferencia. Por ejemplo (setq peri (getint “Perímetro:“)) pero al usar getint, solo permite obtener número enteros. Así que podríamos cambiarlo por:

(setq peri (getreal “Perímetro:“)) ‘almacena el perímetro de la circunferencia en la variable peri

3) Calcular el radio de la circunferencia a partir de su perímetro. Peri = 2* pi * rad así que rad = Peri / ( 2 * pi). Traduciendo esta fórmula a código:

(setq rad (/ peri (* pi 2))) ‘calcula el valor del radio de la circunferencia

4) Dibujar la circunferencia

(command “_.circle” pto rad) ‘dibuja la circunferencia

Sólo nos falta una cosa. Recuerda: El número de paréntesis de apertura tiene que ser igual al número de paréntesis de cierre. Así que:

)

El código completo de la rutina sería:

(defun C:CIRCPERI ( )

(setq pto (getpoint “Centro de la circunferencia“))

(setq peri (getreal “Perímetro:“))

(setq rad (/ peri (* pi 2)))

(command “_.circle” pto rad)

)

También deberías añadir comentarios al código y una cabecera con varias líneas de comentarios en el archivo .LSP indicando: El nombre de la rutina, fecha, autor, etc.

¿Te das cuenta de la importancia del pseudocódigo? Al programar nos ha guiado paso a paso.

Operaciones lógicas en AutoLISP

Existe una serie de funciones de AutoLISP que nos permiten realizar operaciones lógicas. Suelen emplearse en combinación con las operaciones de comparación.

(AND expr1 expr2 …)

Page 52: Autolisp Gera

Esta función devuelve T si ninguna de las expresiones que recibe como argumento es (devuelve) nil. Si una sola de las expresiones devuelve nil, la función AND devolverá nil. Es decir, comprueba que se cumplan todas las expresiones que recibe como argumento.

(and (< 3 4) (= 5 5.0)) devuelve T, porque las dos expresiones devuelven T

(and (> 3 4) (= 5 5.0)) devuelve nil, porque (> 3 4) devuelve nil

En el ejemplo anterior, como la primera expresión (> 3 4) devuelve nil, ya no se continúan evaluando el resto de expresiones. Cómo hay una expresión que devuelve nil, AND devolverá nil. De modo que la expresión (=5 5.0) ya no se evalúa.

Vamos a complicarlo un poco… Qué devolverá la siguiente expresión?

(and (= 5 5.0) (< 3 4) “Soy un texto” 5.8)

Preguntando de otra forma: ¿Alguna de las expresiones que recibe AND como argumentos es nil? No, así que AND devuelve T.

(setq a “Soy otro texto” b 15 c T d nil)

(and a b) devolverá T

(and a d) devolverá nil porque d es nil

(and a b c d) devolverá nil, porque d es nil

(OR expr1 expr2 …)Devuelve nil si todas las expresiones son nil. En caso de que alguna de las expresiones no devuelva nil, OR devuelve T. Es decir, comprueba si alguna de las expresiones se cumple.

(or (/= 5 5.0) (> 3 4)) devuelve nil, porque ambas expresiones son nil

(or (= 5 5.0) (> 3 4)) devuelve T, pues la primera expresión se cumple

En el ejemplo anterior, como la primera expresión (= 5 5.0) devuelve T, ya no se continúan evaluando el resto de expresiones. Cómo hay una expresión que devuelve T, OR devolverá T. De modo que la expresión (> 3 4)ya no se evalúa.

(setq a “Soy otro texto” b 15 c T d nil)

(or a b) devuelve T

(or c d) devuelve nil

(or d d) devuelve nil

(EQUAL expr1 expr2 [precision])

Page 53: Autolisp Gera

En el tema anterior vimos la función de comparación = que nos sirve para determinar si dos números o textos son iguales. Pero que pasa si queremos comparar otra cosa, por ejemplo dos listas (como dos puntos).

(setq pt1 (list 10.0 20.0 0.0) pt2 (list 10.0 (* 10.0 2) 0.0) pt3 (list 9.99 20.0 0.0) pt4 (list 9.99 20.02 0.0))

Al comparar estas listas (puntos) con la función = siempre nos devuelve nil. Aunque pt1 y pt2 sean iguales, y muy parecidos a pt3 y pt4. Por tanto, la función = no nos servirá para comparar listas. Para comparar dos listas se utilizará la función EQUAL.

(equal 5 5.0) devuelve T, al igual que la función =, porque 5 vale lo mismo que 5.0

(equal pt1 pt2) devuelve T

EQUAL además ofrece un argumento opcional… [precisión]. Veamos como funciona :

(equal 4.99 5.0 0.1) devuelve T, porque compara 4.99 y 5 pero con una precisión de 0.1. Así que con esa precisión 4.99 == 5.0

Sin embargo, si subimos la precisión…

(equal 4.99 5.0 0.001) devuelve nil

¿Y qué pasa con las listas? ¿También podemos indicarle una precisión? Veamos..

(equal pt1 pt3 0.1) devuelve T, porque compara los elementos de las listas (coordenadas) con la precisión que hemos indicado, 0.1

Si subimos la precisión…

(equal pt1 pt3 0.001) devuelve nil

(equal pt1 pt4 0.01) devuelve nil

(equal pt1 pt4 0.02) devuelve T, porque la precisión es 0.02 que es exactamente la diferencia entre 20.02 y20

El utilizar una precisión muy elevada no implica que todas las comparaciones devuelvan T, todo dependerá de los valores a comparar:

(equal 15 20 100) devuelve T

(equal 5000 4200 100) devuelve nil

(NOT expr)A esta función le gusta llevarle la contraria a la expresión que recibe como argumento.

si la expresión devuelve nil, entonces NOT devuelve T.

Page 54: Autolisp Gera

si la expresión devuelve cualquier cosa que no sea nil, entonces NOT devuelve nil.

(not 5) devuelve nil

(not “Texto“) devuelve nil

(not (+ 5 1)) devuelve nil

Si hacemos…

(setq a 5 b nil c T d “Nuevo texto“)

(not b) devolverá T, porque b es nil

(not c) devolverá nil.

Veamos que devuelve la siguiente expresión:

(and (not c) 5)

Como c es T, (not c) devuelve nil. Al no cumplirse la primera expresión de AND, esta devuelve nil y no continúa evaluando.

Estructuras condicionales simples

Hasta ahora nuestro código ha sido completamente lineal, las líneas de código que escribíamos se ejecutaban una tras otra en el mismo orden. En este tema veremos un tipo de funciones que nos permitirán bifurcar el código, de modo que ya no exista un único camino sino dos o más. Veamos un ejemplo en pseudocódigo:

1. Introducir el límite inferior2. Introducir el límite superior

3. ¿El límite superior es menor que el inferior?

1. SI–> Mensaje “El límite superior debe ser mayor que el inferior”

2. NO –> intervalo = límite superior – límite inferior

(IF condición expr_si_cumple [expr_no_cumple])La función IF es una de las más empleadas al programar. Devuelve el valor de la última expresión evaluada. Si condición es distinto de nil, entonces evalúa la expr_si_cumple. Si condición devuelve nil evalúa laexpr_no_cumple, si existe y si no existe no hace nada. Veamos algunos ejemplos:

Page 55: Autolisp Gera

(if (= 2 2.0) (alert “Los números son iguales“))

La condición a evaluar es: (= 2 2.0) en la que tenemos un número entero 2 y uno real 2.0, pero su valor es el mismo. Aunque sean de distinto tipo 2 y 2.0 valen igual. Así que la condición devuelve T, evaluándose la condición si cumple que muestra un mensaje de alerta. La función IF devuelve el valor de la última expresión evaluada, es decir alert, que es nil.

(if (= 2 3) (alert “Los números son iguales“))

En este caso la condición devuelve nil y al no existir expresión no cumple, no haría nada más. ¿Qué valor devolvería IF? El de siempre, el valor de la última expresión evaluada, que en este caso ha sido la propia condición que devuelve nil. De modo que IF devolverá nil.

(if  (= 2 3)

(alert “Los números son iguales“)

(alert “Los números son distintos“)

)

En este caso el código se ha escrito en varias líneas y tabulado para facilitar su comprensión. Ahora si tenemos una expresión no cumple, que será evaluada ya que la condición devuelve nil.

Veamos el siguiente ejemplo:

(setq liminf (getint “\nLímite inferior:“))

(setq limsup (getint “\nLímite superior:”))

(if (> liminf limsup)

(alert “El límite superior debe ser mayor que el inferior“) (setq limsup (getint “\nLímite superior:“)) (setq intervalo (- limsup liminf))

(setq intervalo (- limsup liminf))

)

Viendo el código anterior, tal vez pienses que si la condición (> liminf limsup) se cumple, entonces se evaluará la línea siguiente de código completa. Pero no es así, se evalúa la expresión si cumple, que es la primera expresión (alert “El límite superior debe ser mayor que el inferior“).

Si la condición no se cumple, devuelve nil, se evaluará la expresión no cumple, que en este caso será (setqlimsup (getint “\nLímite superior“)).

Page 56: Autolisp Gera

Tanto la expresión si cumple, como la no cumple solo pueden ser una única expresión. El ejemplo de código anterior nos daría un error ya que IF no puede tener más que 3 expresiones:

La condición La expresión si cumple

La expresión no cumple

(PROGN expr1 expr2 …)Para que se pueda indicar más de una expresión si cumple, o no cumple, en la función IF se suele emplear la función PROGN. El valor devuelto por PROGN es el de la última expresión que recibe como argumento. Esta función en realidad no hace nada, tan solo nos permite agrupar una serie de expresiones.

¿Cómo quedaría el ejemplo anterior?

(setq liminf (getint “\nLímite inferior:“))

(setq limsup (getint “\nLímite superior:“))

(if (> liminf limsup)

(progn

(alert “El límite superior debe ser mayor que el inferior“)

(setq limsup (getint “\nLímite superior:“))

(setq intervalo (- limsup liminf))

)

(setq intervalo (- limsup liminf))

)

En este caso la condición si cumple es todo lo siguiente:

(progn

(alert “El límite superior debe ser mayor que el inferior“)

(setq limsup (getint “\nLímite superior:“))

(setq intervalo (- limsup liminf))

)

Si se cumple la condición, se evalúa la condición si cumple, es decir el progn. De modo que se van evaluando las expresiones contenidas en la función PROGN, que devuelve el

Page 57: Autolisp Gera

valor de la última expresión(setq intervalo (- limsup liminf)), que será el valor de la variable intervalo.

En caso de que la condición no se cumpla, se evalúa la condición no cumple, (setq intervalo (- limsup liminf)) que curiosamente también devuelve el valor de la variable intervalo.

Veamos ahora algunos ejemplos más de estructuras condicionales:

(if (and (= 2 2.0) (< 2 3))

(alert “Las dos condiciones se cumplen“)

(alert “Al menos una condición no se cumple“)

)

En este caso la condición es (and (= 2 2.0) (< 2 3)) que en este caso devolvería T, ya que se verifican las dos expresiones que recibe la función AND.

(if (not var1)

(alert “Variable no definida“)

(alert “Variable definida“)

)

En este caso si var1 es nil, (not var1) devolverá T, indicando que la variable no se ha definido. En caso contrario, (not var1) devolverá nil evaluándose la expresión no cumple. Otro método para hacer lo mismo, sería:

(if var1

(alert “Variable definida“)

(alert “Variable no definida“)

)

Si var1 es distinto de nil, se evalúa la expresión si cumple. En caso de que var1 sea nil, se evaluaría la expresión no cumple.

Estructuras condicionales múltiples

Con la función IF tan solo podemos indicar una condición y dos opciones, si cumple y no cumple. Veamos ahora como se pueden indicar varias condiciones con sus respectivas expresiones si cumple.

Page 58: Autolisp Gera

(COND (condicion1 [expr1_1] [expr1_2] … ) [ (condicion2 [expr2_1] [expr2_2] … ) ] … )Esta función es similar a IF en cuanto a que se indican condiciones y una serie de expresiones que se evaluaran si se verifica cada condición. En este caso no existe la limitación de indicar tan sólo una única expresión si cumple, se pueden indicar tantas como se desee. COND evaluará la primera condición encontrada, si se verifica evaluará las expresiones si cumple de dicha condición. En caso de que no se verifique, evaluará la siguiente expresión.

Por lo tanto, COND evaluará las expresiones si cumple de la primera condición que se verifique. Y devolverá el resultado de evaluar la última expresión si cumple. Pongamos un ejemplo:

(cond

((= a b)

(alert “A y B son iguales“)

(setq b (getreal “Introduzca de nuevo B: “))

)

((< a c)

(alert “A es menor que C“)

)

((< a b))

(T

(alert “A no es igual a B“)

(alert “A no es menor que C“)

(alert “A no es menor que B“)

)

)

Supongamos ahora que antes de la expresión COND, hemos definido (setq a 2 b 2.0 c 3.5). En este caso, al entrar en COND se evaluará la primera condición (= a b) que se verifica, de modo que se evaluaran las expresiones si cumple de

Page 59: Autolisp Gera

esta condición: (alert “A y B son iguales“) y (setq b (getreal “Introduzca de nuevo B: “)) finalizando la expresión COND que devuelve el nuevo valor de b.

Aunque la siguiente condición (< a c) se cumple, no se evalúa, ya que existe una condición anterior que también se cumplía.

En caso de que se hubiera definido (setq a 2 b 2.5 c 3.5) la primera condición (= a b) no se verifica, de modo que se evalúa la segunda condición (< a c) que si se cumple. Evaluándose sus expresiones si cumple (alert“A es menor que C“) que devuelve nil.

Si fuera (setq a 2 b 2.5 c 1.5) la primera condición en cumplirse sería la tercera (< a b) que no tiene expresiones si cumple. ¿Qué devolverá entonces la función COND? Pues el valor de la última expresión evaluada, es decir el valor devuelto por la condición (< a b) que es T.

Por último, si tenemos (setq a 2 b 1.0 c 1.5) ninguna de las tres condiciones anteriores se verifica, de modo que pasamos a la siguiente condición T, que lógicamente siempre devuelve T, así que siempre se verifica. Esto se suele utilizar mucho en la función COND, añadir como última condición una que se verifique siempre. En lugar de T se podía haber puesto (not nil) o (= 1 1.0) que también son expresiones que siempre se cumplen. ¿Para qué añadir una expresión que siempre se cumple? Muy sencillo, para incluir el código que se desea ejecutar en caso de que no se verifique ninguna de las condiciones anteriores.

¿Y qué sucede si se pone la condición T como primera condición? Pues sucede que las que estén a continuación nunca se evaluarán, ya que T siempre se cumplirá. Si en el ejemplo anterior hubiéramos puesto:

(cond

(T

(alert “A no es igual a B“)

(alert “A no es menor que C“)

(alert “A no es menor que B“)

)

((= a b)

(alert “A y B son iguales“)

(setq b (getreal “Introduzca de nuevo B: “))

)

((< a c)

(alert “A es menor que C“)

)

Page 60: Autolisp Gera

((< a b))

)

Independientemente de los valores de las variables a b y c siempre nos mostrará los mensajes de alerta indicando que “A no es igual a B“, “A no es menor que C” y “A no es menor que B“.

Mostrar textos al usuario en AutoLisp

Hay varias funciones para mostrar textos al usuario en AutoLisp. De momento vamos a ver un par de ellas, pero habrá más.

(PROMPT mensaje)Muestra el texto indicado como argumento en pantalla, y siempre devuelve nil.

(prompt “Bienvenidos al Curso“)

(ALERT mensaje)Muestra el texto que recibe como argumento en un letrero. También devuelve nil. Se utiliza principalmente para avisar al usuario en caso de error, o para mostrar alguna información importante.

(alert “Error: Dato no válido“)

(TERPRI)En artículo correspondiente a las Operaciones de comparación, creamos un nuevo comando para AutoCAD denominado CIRCPERI. Si has cargado y ejecutado el comando, habrás observado que los mensajes para solicitar el centro de la circunferencia y su perímetro aparecen en la misma línea de la ventana de comandos y sin separación entre sí, están pegados.

Para que los mensajes aparezcan en líneas distintas, se puede emplear la función TERPRI. Esta función mueve el cursor a una nueva línea en la ventana de comandos de AutoCAD, y devuelve nil. El código de la rutina quedaría así:

(defun C:CIRCPERI ( )

(setq pto (getpoint “Centro de la circunferencia“)) (terpri)

(setq peri (getreal “Perímetro:“)) (terpri)

(setq rad (/ peri (* pi 2)))

Page 61: Autolisp Gera

(command “_.circle” pto rad)

)

Así los mensajes de solicitud aparecerán en líneas separadas.

Los caracteres de controlComo ya se ha comentado anteriormente, AutoLISP no reconoce una serie de caracteres. Por ejemplo, al indicar la ruta de un archivo no reconoce el carácter “\” y hay que indicarlo así: “\\“. Pues existen más caracteres de control predefinidos:

\\ Equivale al caracter \ \” Equivale al caracter “

\e Equivale a ESCape

\n Equivale al retorno de carro

\r Equivale a pulsar Intro

\t Equivale a pulsar la tecla del tabulador

\” nos permite escribir las comillas dentro de un texto. Por ejemplo:

(alert “Esto son un par de comillas \” o no?“)

La única comilla que se tiene que ver es la que está escrita así: \” . Las otras nos indican donde comienza y termina el texto, nada más.

(alert “Texto en línea 1\nTexto en línea 2“)

Se pone 1\nTexto todo junto. Para qué poner espacios?

(alert “Texto en línea 1\n Texto en línea 2“)

Si lo ponemos así, añade un espacio en blanco al principio de la segunda línea. Por eso se pone todo seguido.

(alert “Texto en línea 1\n\tTexto en línea 2“)

En este ejemplo la segunda línea está tabulada.

Entonces, ¿cómo quedaría el código de la rutina CIRCPERI utilizando caracteres de control, en lugar de la función (TERPRI)?

(defun C:CIRCPERI ( )

(setq pto (getpoint “\nCentro de la circunferencia“))

(setq peri (getreal “\nPerímetro:“))

Page 62: Autolisp Gera

(setq rad (/ peri (* pi 2)))

(command “_.circle” pto rad)

)

Un par de cosas más con respecto a esta rutina… Cuando se crea un archivo LISP en el que está definido un nuevo comando es bastante útil añadir al final de todo el código algo similar a…

(prompt “\nNuevo comando CIRCPERI cargado“)

Esta línea se pondría después del paréntesis de cierre de defun. Es decir, que cuando se ejecuta CIRCPERIdesde AutoCAD esta línea no se evalúa. ¿Para qué ponerla entonces? Pues muy sencillo… para que cuando se cargue el archivo en AutoCAD muestre en pantalla: Nuevo comando CIRCPERI cargado. Así el usuario sabe cual es el nombre del comando definido en el archivo que se acaba de cargar. De modo que el mensaje sólo se mostrará al cargar el archivo.

Por otro lado… si recordamos la estructura de la función DEFUN: (DEFUN nombre_función ( argumentos / variables_locales ) expr1 expr2 …)

Veremos que en la rutina CIRCPERI no hemos indicado variables locales, así que todas las variables serán globales. Es decir que al ejecutar CIRCPERI y dibujar un círculo, luego nos quedan accesibles los valores de las variables pto, peri y rad desde AutoCAD, ocupando y malgastando memoria. Así que vamos a ponerlas como locales. Sólo habría que cambiar la siguiente línea…

(defun C:CIRCPERI ( / pto peri rad )

OJO! la barra inclinada / hay que ponerla, sino serían argumentos y no variables locales.

El código completo de la rutina es el siguiente:

;;;____________________Eduardo Magdalena____________________;;;

;;;______________________CIRCPERI.LSP_________________________;;;

;;;_______________________Versión 1.1_________________________;;;

;;;________________________26/02/2002_________________________;;;

;;; Comando para dibujar una circunferencia indicando su centro y la longitud

;;; de su perímetro.

(defun C:CIRCPERI ( / pto peri rad )

(setq pto (getpoint “\nCentro de la circunferencia“))

(setq peri (getreal “\nPerímetro:“))

(setq rad (/ peri (* pi 2)))

Page 63: Autolisp Gera

(command “_.circle” pto rad)

)

(prompt “\nNuevo comando CIRCPERI cargado“)

Las variables de sistema de AutoCAD

El modo en que funciona el entorno de AutoCAD, y la forma de trabajar de muchos de sus comandos, se ven afectados por los valores asignados a las variables de sistema. Podría decirse que controlan como trabaja AutoCAD. Por lo tanto, se pueden modificar los valores asignados a las variables de sistema para personalizar AutoCAD para un usuario en concreto, para un tipo de trabajo determinado, e incluso para un archivo de dibujo. De modo que nos facilite el trabajo.

Tipos de variables de sistemaLas variables de sistema pueden almacenar distintos tipos de datos, en función de la información que contengan. Podrían clasificarse del siguiente modo:

Activada / Desactivada. Muchas variables de sistema sólo admiten dos opciones: Activada y Desactivada. Normalmente tienen asignado el valor “0” cuando están desactivadas, y “1″ cuando están activadas. Un ejemplo de este tipo de variables es “blipmode“.

Números enteros. Otras variables tienen más de dos posibilidades, para lo que asignan un número entero para cada opción. Normalmente emplean números correlativos, empezando desde el cero. Una variable que utiliza este tipo de datos es “coords“.

Códigos binarios. Algunas variables pueden emplear varias opciones a la vez, para lo que suelen emplear códigos binarios. A cada opción se le asigna el número resultante de elevar 2 a n. Asignando an números enteros correlativos a partir del cero. Es decir, los valores para las distintas opciones serán: 1,2,4,8,16,32,etc. De modo que para seleccionar la primera y cuarta opciones, hay que asignar a la variable la suma de sus valores: 1+8 = 9. Un ejemplo muy interesante de este tipo de variables es “osmode“.

Números reales. Las variables que almacenan valores de ángulos o distancias, por ejemplo, utilizan este tipo de valores. Un ejemplo de este tipo es la variable “chamfera“.

Puntos. Este tipo de entidades almacenan las coordenadas de un punto, un buen ejemplo es “ucsorg“.

Page 64: Autolisp Gera

Cadenas de texto. Hay bastantes variables que almacenan cadenas de texto, como nombres de archivos o rutas de directorios. Ejemplos de este tipo de variables son “acadver” y “acadprefix“.

Modificar los valores de las variables de sistemaPodríamos clasificar las variables de sistema en función del lugar en el que se guardan:

No guardadas. La información asignada a este tipo de entidades no se guarda. Un ejemplo de este tipo de variables es “acadver“.

En el dibujo. La mayoría de las variables de sistema son de este tipo, de modo que cada dibujo trabajará con unos valores determinados para las variables de sistema. Esto hace sumamente importante la definición de los valores de las variables de sistema en las plantillas utilizadas para crear nuevos dibujos. Un ejemplo de variable guardada en el dibujo es “luprec“.

En el registro. Algunas variables de sistema se guardan en el registro de Windows. Por ejemplo “attdia“.

La mayoría de las variables de sistema de AutoCAD pueden editarse, modificando el valor que tengan asignado. Pero algunas variables son de solo lectura, de modo que no se pueden modificar, tan solo leer. Un ejemplo de variable de solo lectura es “cdate“.

Hay varios métodos para modificar los valores asignados a las variables de sistema de AutoCAD:

Tecleando el nombre de la variable, como si fuese un comando más de AutoCAD. Ejecutando el comando “MODIVAR” e indicando la variable a modificar.

Algunos comandos de AutoCAD permiten modificar los valores asignados a algunas variables de sistema. Por ejemplo el comando “MARCAAUX” permite modificar el valor asignado a la variable “blipmode“.

Algunas variables se modifican al ejecutar algún comando de AutoCAD. Por ejemplo “circlerad” almacena el radio de la última circunferencia creada con el comando “círculo“.

Las variables de sistema en los programas de AutoLISP

Page 65: Autolisp Gera

Los programadores suelen leer y modificar el contenido de algunas variables de sistema de AutoCAD, ya que esto les permite definir el modo en el que desean que se comporte AutoCAD o algunos comandos de AutoCAD.

Esto puede ocasionar cambios en los valores asignados a algunas de las variables de sistema. Al programar deberías seguir los siguientes consejos para que esto no suceda:

Deberías guardar los valores iniciales de las variables de sistema que se necesite modificar, y asignarles sus valores iniciales al terminar el programa.

Crear una función de tratamiento de errores, de modo que si se produce algún error al ejecutar el programa se restablezcan los valores iniciales de las variables de sistema. La creación de funciones de tratamiento de errores la trataremos más adelante.

(GETVAR variable)Esta función devuelve el valor asociado a la variable que recibe como argumento. Por ejemplo:

(getvar “osmode“)

(getvar “blipmode“)

(getvar “acadver“)

(SETVAR variable nuevo_valor)Asigna a la variable indicada un nuevo valor, y devuelve dicho valor.

(setvar “blipmode” 0)

(setvar “osmode” 32)

Veamos un ejemplo combinando las funciones GETVAR y SETVAR. Escribe lo siguiente en la línea de comandos de AutoCAD:

(getvar “luprec“)

(setvar “luprec” 2)

(getvar “luprec“)

Funciones de conversión de datos en AutoLISP

Vamos a ver una serie de funciones que nos permitirán pasar un entero a real, a un texto o al revés…

Page 66: Autolisp Gera

(ITOA entero)Convierte un entero en un texto. Integer TO Atom.

(itoa 24) devuelve “24”

(ATOI texto)Hace justo lo contrario que la función anterior. Convierte un texto en un número. Atom TO Integer

(atoi “24“) devuelve 24

(atoi “-7“) devuelve -7

Y que pasa si hacemos… (atoi “soy un texto“) pues que devuelve 0. Siempre que escribes algo que no sea un número devuelve cero.

(atoi “15.3“) devuelve 15

(atoi “15.99999“) devuelve 15

(FLOAT numero)Convierte un número en real, así que lo lógico es que reciba un entero como argumento.

(float 5) devuelve 5.0

pero también podemos pasar un número real como argumento… (float 5.36) que devuelve 5.36 lo cual sería una tontería porque en ese caso la función float no hace nada.

(ATOF texto)Convierte un texto en real.

(atof “15.7“) devuelve 15.7

(atof “15“) devuelve 15.0

(atof “-15.7“) devuelve -15.7

(atof “soy un texto“) devuelve 0.0

(RTOS numero [modo [precision]])La última función de este tipo que vamos a ver es algo más complicada, pero no mucho. Convierte un real en texto. Real TO String.

(rtos 2.5) devuelve “2.5”

Page 67: Autolisp Gera

(rtos 2) devuelve “2” y no “2.0”

Veamos para qué sirven los argumentos opcionales [modo [precisión]]. Modo, permite indicar un tipo para expresar los números, es decir, permite seleccionar el formato utilizado para los números. Hay 5 opciones:

Formato científico. Decimal. Es el que se usa habitualmente.

Pies y pulgadas.

Pies y pulgadas en fracciones.

Fracciones.

Por ejemplo…

(rtos 2.5 5) devuelve “2 1/2”

(rtos 2.5 1) devuelve “2.5000E+00”

Precisión nos permite definir el número de decimales que deseamos, por ejemplo:

(rtos 1.23456789 2 3) devuelve 1.235 así que redondea el número para que tenga 3 decimales.

(rtos 9.99 2 0) devuelve 10

Obtener distancias y ángulos del usuario

Hemos visto como se obtienen números, puntos y textos del usuario. Ahora le vamos a solicitar directamente una distancia o un ángulo.

(GETDIST [pto_base] [mensaje])Solicita una distancia y devuelve esa distancia como un número real. El usuario podrá indicar la distancia por medio de un número o indicando 2 puntos en pantalla.

(getdist “Distancia de desplazamiento:“)

El mensaje es opcional, pero casi siempre se utiliza. También podemos asignar el resultado a una variable:

(setq dist1 (getdist “Distancia de desplazamiento:“))

En muchas ocasiones se puede reemplazar a la función GETREAL por GETDIST si lo que se pide se puede relacionar con alguna distancia del dibujo. Por ejemplo, en nuestra

Page 68: Autolisp Gera

rutina CIRCPERI podríamos dibujar una circunferencia de perímetro la longitud de una recta.

El argumento opcional [pto_base] funciona de modo similar a como lo hace en GETPOINT permitiendo indicar la distancia a partir de un punto de origen ya predefinido:

(setq pto (getpoint “Punto base“))

(setq dist1 (getdist pto “Distancia de desplazamiento:“))

(GETANGLE [pto_base] [mensaje])Solicita un ángulo al usuario que puede escribirlo o designarlo por medio de dos puntos. Devuelve el ángulo en radianes, aunque el usuario lo escribiría en las unidades actuales (generalmente grados decimales). Por ejemplo, a la expresión:

(getangle “Ángulo: “)

el usuario responde… 180.0

y getangle, devuelve pi.

Esta función toma como origen de ángulos el actual, que suele coincidir con el sentido positivo del eje X delSCU (Sistema de Coordenadas Universal). Pero siempre considerará como sentido positivo de los ángulos el antihorario.

El parámetro opcional [pto_base] permite indicar un punto a partir del cual indicar el ángulo.

(GETORIENT [pto_base] [mensaje])Es casi igual a GETANGLE, y también se utiliza para solicitar un ángulo al usuario. La única diferencia es que el origen de ángulos siempre es el del sentido positivo del eje X del SCU (Sistema de Coordenadas Universal).

(getangle “Ángulo: “)

Añadir algunos cambios a nuestra macro CIRCPERIVamos ahora a modificar un poco la macro CIRCPERI. Teníamos el siguiente código:

(defun C:CIRCPERI ( / pto peri rad )

(setq pto (getpoint “\nCentro de la circunferencia: “))

(setq peri (getreal “\nPerímetro: “))

Page 69: Autolisp Gera

(setq rad (/ peri (* pi 2)))

(command “_.circle” pto rad)

)

(prompt “\nNuevo comando CIRCPERI cargado“)

Si sustituimos la función getreal por getdist además de poder escribir un perímetro directamente, también podremos indicarlo mediante dos puntos.

Eco de mensajes en las macros de AutoLISPPor otra parte, Si habéis ejecutado el comando CIRCPERI veréis que lo de los mensajes queda mejor que al principio pero tampoco es perfecto ya que aparecen unos textos en la ventana de comandos que no se sabe de dónde salen:

Centro de la circunferencia:

Perímetro: Designe segundo punto: _.circle Precise punto central para círculo o

[3P/2P/Ttr (tangente tangente radio)]:

Precise radio de círculo o [Diámetro]: 23.00636765228087

Esto queda bastante feo y como hay que ser profesionales, vamos a ponerlo bien. Hemos visto las funcionesGETVAR y SETVAR que nos permiten acceder a las variables de sistema de AutoCAD. Pues hay una variable que controla el “eco de mensajes“, es decir, el que aparezcan esos mensajes en pantalla. La variable se llama CMDECHO y solo admite dos valores posibles:

0 Desactivada 1 Activada

Por defecto debería estar activada (1) así que se verían los mensajes raros de antes.

¿Cómo evitamos que aparezcan estos mensajes? Pues desactivando la variable.

Pero no conviene modificar los valores de las variables de sistema, porque tal vez el usuario los quiera mantener como estaban. De modo que se desactivará momentáneamente el valor de la variable en medio de la macro y al terminar la rutina se dejará con su valor inicial, es decir tal como estaba.

Esto es más bien una filosofía de vida: “Si al entrar en un sitio, la puerta estaba cerrada, vuelve a cerrarla”

Así que nuestro código quedaría…

(defun C:CIRCPERI ( / pto peri rad )

(setvar “cmdecho” 0) ; Desactiva el eco de mensajes

Page 70: Autolisp Gera

(setq pto (getpoint “\nCentro de la circunferencia: “))

(setq peri (getdist “\nPerímetro: “))

(setq rad (/ peri (* pi 2)))

(command “_.circle” pto rad)

(setvar “cmdecho” 1) ; Vuelve a activar el eco de mensajes

)

(prompt “\nNuevo comando CIRCPERI cargado“)

Efectivamente los mensajes raros desaparecen, pero… ¿Qué pasa si al entrar en una habitación, la puerta ya estaba abierta? ¿la cerramos o la dejamos abierta de nuevo?. Lo mejor es que todo quede “tal como lo encontramos”. Así nadie nos dirá… “¿Por qué cerraste la puerta?”. Y si lo dice, le respondes: “Perdona, pero mi macro, deja las cosas tal y como estaban, así que o ya estaba cerrada antes o la cerraron después”.

Si cmdecho está inicialmente desactivada nuestra rutina la desactiva, o lo intenta, y luego la activa al final de la macro. Quedando por lo tanto cmdecho activada. Así que vamos a modificar el código para que cmdechoquede con el valor que tenía antes de ejecutar la macro…

Lo primero que tenemos que saber es si la puerta está cerrada, si está cerrada la abrimos y si ya está abierta no hacemos nada, simplemente pasamos.

(getvar “cmdecho“) me dirá si cmdecho está activada o desactivada. Veamos que es lo que hay que hacer:

1. Si la puerta está cerrada, la abro. Es decir, si cmdecho está activada, la desactivo.

2. Aquí metemos el código de la macro CIRCPERI

3. Si antes de entrar la puerta estaba cerrada, entonces la cierro. Es decir, si cmdecho estaba activada, entonces la vuelvo a activar.

El punto 1 suena claramente a una estructura condicional simple, así que emplearemos la función IF:

(if (= (getvar “cmdecho“) 1)

(setvar “cmdecho” 0)

)

¿Y cómo haríamos al final de la rutina en el punto 3? Sería otro condicional, pero necesitamos conocer el valor que tenía inicialmente la variable cmdecho para saber si estaba activada o desactivada. De modo que hay que modificar el código anterior para que en el punto 1 se almacene el valor de cmdecho.

Page 71: Autolisp Gera

(if (= (setq cmd0 (getvar “cmdecho“)) 1)

(setvar “cmdecho” 0)

)

De este modo la variable cmd0 almacena el valor inicial de cmdecho. Es bastante habitual almacenar los valores iniciales en variables cuyo nombre sea del tipo cmd0, osm0 o blip0 pues el 0 nos indica que almacena el valor inicial.

Ahora ya podemos poner el código del punto 3. Podríamos hacerlo de dos formas:

(setvar “cmdecho” cmd0)

Esta línea de código asignaría a cmdecho el valor que tenía inicialmente.

(if (= cmd0 1)

(setvar “cmdecho” 1)

)

En este caso, si cmdecho estaba inicialmente activada entonces la activa. Si no estaba inicialmente activada, es decir estaba desactivada, entonces no hace nada porque cmdecho ya está desactivada, al igual que al principio.

El código quedaría así:

(defun C:CIRCPERI ( / pto peri rad cmd0 )

(if (= (setq cmd0 (getvar “cmdecho“)) 1)

(setvar “cmdecho” 0)

)

(setq pto (getpoint “\nCentro de la circunferencia: “))

(setq peri (getdist “\nPerímetro: “))

(setq rad (/ peri (* pi 2)))

(command “_.circle” pto rad)

(if (= cmd0 1)

(setvar “cmdecho” 1)

)

)

(prompt “\nNuevo comando CIRCPERI cargado“)

Salida limpia de las macros de AutoLISP

Page 72: Autolisp Gera

Al ejecutar ahora la rutina los mensajes son más limpios. Sin embargo al final muestra el valor devuelto por la última expresión evaluada de la función:

Si la variable cmdecho inicialmente es 0. La condición del if devuelve nil, se termina la función y se muestra en la pantalla nil

Si la variable cmdecho inicialmente es 1. La condición del if devuelve T, se evalúa la condición-si-cumple del if (setvar “cmdecho” 1) que devuelve 1, se termina la función y se muestra en la pantalla 1

Para que la salida de nuestras macros sea “limpia” añadiremos al final del código una función que devuelvauna cadena de texto vacía, así no escribirá nada.

Podríamos pensar en utilizar la expresión (prompt “”) al terminar nuestras macros. Sin embargo la expresión anterior no devuelve una cadena de texto vacía sino que devuelve nil.

Suelen emplearse las funciones (princ) o (prin1) que aún no hemos visto, pero que devuelven una cadena de texto vacía.

Finalmente el código resultante será:

(defun C:CIRCPERI ( / pto peri rad cmd0 )

(if (= (setq cmd0 (getvar “cmdecho“)) 1)

(setvar “cmdecho” 0)

)

(setq pto (getpoint “\nCentro de la circunferencia: “))

(setq peri (getdist “\nPerímetro: “))

(setq rad (/ peri (* pi 2)))

(command “_.circle” pto rad)

(if (= cmd0 1)

(setvar “cmdecho” 1)

)

(prin1)

)

(prompt “\nNuevo comando CIRCPERI cargado“)

El comando deshacer en las rutinas de AutoLISP

Page 73: Autolisp Gera

En este artículo no vamos a ver ninguna función de AutoLISP. Vamos a crear un nuevo comando y a repasar un poco la macro de CIRCPERI.

Comenzaremos creando un nuevo comando para dibujar arandelas en 2D:

El programa solicitará al usuario el centro de la arandela, el diámetro interior y el exterior

Se dibujarán dos circunferencias concéncricas con los diámetros indicados

Recuerda, antes de ponerse a escribir código hay que: escribir el pseudocódigo. Veamos, podíamos hacer algo así:

1. Obtener el centro de la circunferencia2. Obtener el radio de la circunferencia interior

3. Dibujar la circunferencia interior

4. Obtener el radio de la circunferencia exterior

5. Dibujar la circunferencia exterior

AutoCAD ya tiene un comando que se llama arandela (en inglés donuts) así que buscaremos otro nombre para nuestra rutina, por ejemplo ARAND. Es mejor utilizar nombres más bien cortos y que evoquen a la función que tiene el comando.

La primera línea de código es la definición de la función:

(defun C:ARAND ( )

Más adelante podremos añadir las variables locales, si es que existen.

1) Obtener el centro de la circunferencia. Podría ser algo así:

(setq pto (getpoint “\nCentro de la arandela: “))

2) Obtener el radio de la circunferencia interior:

(setq radi (getreal “\nRadio interior: “))

3) Dibujar el circulo interior

(command “_.circle” pto radi)

4) Obtener el radio del círculo exterior:

(setq rade (getreal “\nRadio exterior: “))

5) Dibujar el circulo exterior

(command “_.circle” pto rade)

Page 74: Autolisp Gera

Y por último cerramos el paréntesis de la función defun

)

El código completo queda así:

(defun C:ARAND ( )

(setq pto (getpoint “\nCentro de la arandela: “))

(setq radi (getreal “\nRadio interior: “))

(command “_.circle” pto radi)

(setq rade (getreal “\nRadio exterior: “))

(command “_.circle” pto rade)

)

Ahora vamos a retocar un poco el comando, le añadiremos las siguientes mejoras:

Desactivar el eco de mensajes, es decir desactivar la variable cmdecho al iniciar la rutina.

Recuperar el valor inicial de cmdecho al terminar la macro.

Añadir una línea al final del código para que muestre un mensaje indicando el nombre del nuevo comando al cargar la función.

Poner las variables como locales.

En lugar de utilizar GETREAL para obtener el radio, usaremos GETDIST con el centro de las circunferencias como punto base.

Añadir una línea al final de la función para que la salida del programa sea limpia.

El código después de realizar las mejoras anteriores sería:

(defun C:ARAND ( / pto rad cmd0 )

(if (= (setq cmd0 (getvar “cmdecho“)) 1)

(setvar “cmdecho” 0)

)

(setq pto (getpoint “\nCentro de la arandela: “))

(setq rad (getdist pto “\nRadio interior: “))

(command “_.circle” pto rad)

(setq rad (getdist pto “\nRadio exterior: “))

Page 75: Autolisp Gera

(command “_.circle” pto rad)

(if (= cmd0 1)

(setvar “cmdecho” 1)

)(princ)

)

(prompt “\nNuevo comando ARAND cargado“)

Además de las mejoras indicadas anteriormente, ahora la variable rad se utiliza tanto para almacenar el radio de la circunferencia interior como el de la exterior. ¿Puede dar lugar esto a algún problema? Veamos:

En primer lugar obtenemos el centro de la circunferencia y la asignamos a la variable pto.

(setq pto (getpoint “\nCentro de la arandela: “))

Solicitamos el radio de la circunferencia interior y lo asignamos a la variable rad.

(setq rad (getdist pto “\nRadio interior: “))

y dibujamos la circunferencia interior

(command “_.circle” pto rad)

El radio de la circunferencia interior no lo vamos a volver a utilizar en nuestra rutina, de modo que podemos reutilizar esa variable y asignarle otro valor, el radio de la circunferencia exterior.

(setq rad (getdist pto “\nRadio exterior: “))

Ahora la variable rad almacena el radio de la circunferencia exterior y pto el centro de las dos circunferencias, de modo que dibujamos la circunferencia exterior.

(command “_.circle” pto rad)

De este modo ahorramos una variable. Así que recuerda:

Si es posible, conviene reutilizar las variables.

Si cargamos la macro y ejecutamos el comando ARAND dibujaremos una arandela formada por dos circunferencias. ¿Pero qué pasa si después de dibujar la circunferencia ejecutamos el comando “H” (deshacer) de AutoCAD? Pues que “deshace el último comando ejecutado” que no es ARAND sino(command “_.circle” pto rad) de modo que deshace la circunferencia exterior. Pero la interior no.

Control de deshacer comandos

Page 76: Autolisp Gera

El comando “DESHACER” de AutoCAD es distinto al comando “H“. En realidad, “H” es una opción de “DESHACER“. Al ejecutar este comando, AutoCAD muestra el siguiente mensaje: “Indique el número de operaciones a deshacer o [Auto/Control/Inicio/Fin/Marca/Retorno] <1>:“. Veamos como funcionan estas opciones:

“Número de operaciones a deshacer”La opción por defecto es indicar el número de operaciones a deshacer, que por defecto tiene el valor 1. Esta opción funciona exactamente igual que el comando “H“. Pero, podemos indicarle un número de operaciones superior a 1 (cualquier número entero entre 1 y 32.767). Esta opción es útil para deshacer los cambios realizados por los últimos “n” comandos.

“Control”Al seleccionar “Control” nos ofrece las siguientes posibilidades: “Indique una opción de control DESHACER [Todas/Ninguna/Una] <Todas>:”

Con la opción “Todas” seleccionada (es la opción por defecto), AutoCAD almacena en el archivo temporal “UNDO.ac$” la información sobre los comandos ejecutados en el dibujo actual y por tanto que se pueden deshacer. También almacena en el archivo temporal “REDO.ac$” la información sobre los comandos del dibujo actual que se han deshecho. Estos archivos se almacenan en el directorio temporal del sistema operativo. Esta opción permite deshacer todos los comandos realizados en el dibujo durante la sesión actual.

Si se selecciona la opción “Una“, tan sólo se podrá deshacer el último comando ejecutado. Quedando desactivadas todas las opciones del comando “DESHACER” excepto “Control” e “Indique el número de operaciones a deshacer <1>:“

Seleccionando la opción “Ninguna” se elimina la capacidad de revocar de los comandos “H” y “DESHACER“, quedando estos desactivados. Y ya no se utilizan los archivos temporales anteriormente citados.

Lo recomendable es tener siempre activada la opción “Todas“.

“Marca y Retorno”Estas dos opciones funcionan en pareja. Supongamos que vamos a ejecutar una serie de comandos en el dibujo actual, pero no sabemos si el resultado obtenido será el deseado. En este caso, antes de comenzar puedes ejecutar el comando “DESHACER” y seleccionar la opción “Marca“. De este modo activas una marca, a la que podrás volver en cualquier momento ejecutando “DESHACER” con la opción “Retorno“. Al encontrar una marca AutoCAD mostrará el mensaje “Marca encontrada“.

Page 77: Autolisp Gera

Si en lugar de volver a la marca lo que quieres es deshacer un número determinado de comandos, puedes ejecutar el comando “H” o “DESHACER” indicando el número de comandos a deshacer.

Además, puedes definir tantas marcas como desees, y cada vez que ejecutes “DESHACER” con la opción “Retorno” volverás a la marca anterior. Si no existen más marcas, o si no se ha definido ninguna marca, AutoCAD preguntará si se desea deshacer todo.

“Auto”Algunos comandos de AutoCAD, están formadas por un grupo de órdenes. De modo que el comando “H” no anularía todo el grupo de comandos ejecutados, sino sólo el último. Activando esta opción se agrupan estos comandos en uno sólo, a efectos de la aplicación de los comandos “H” y “DESHACER“.

“Inicio y Fin”Estas dos opciones también funcionan juntas. Con ellas podemos agrupar una serie de comandos, de modo que sean tratados como uno solo al ejecutar “H” o “DESHACER“.

Si “DESHACER” con la opción “Auto” está activada, AutoCAD coloca automáticamente un “DESHACER” “Inicio” y un “DESHACER” “Fin” al principio y final de las opciones de los menús, y deja inutilizadas estas opciones de forma manual.

Con la opción “Auto” desactivada, las opciones “Inicio” y “Fin” se ejecutan de forma análoga a como se hace con “Marca” y “Retorno“. Si se vuelve a ejecutar la opción “Inicio” sin haber ejecutado la opción “Fin” para cerrar un grupo anterior, AutoCAD entiende que se quiere cerrar el grupo anterior y abrir uno nuevo.

El comando deshacer en las rutinas de AutoLISPUtilizando las opciones anteriores del comando deshacer, se puede lograr que todo el código de nuestras rutinas funcione como si se tratase de un único comando.

Añadiremos al inicio de nuestra rutina “deshacer” “inicio” y al final de la rutina “deshacer” “fin“. Veamos:

(defun C:ARAND ( / pto rad cmd0 )

(command “_.undo” “_begin“)

(if (= (setq cmd0 (getvar “cmdecho“)) 1)

(setvar “cmdecho” 0)

)

Page 78: Autolisp Gera

(setq pto (getpoint “\nCentro de la arandela: “))

(setq rad (getdist pto “\nRadio interior: “))

(command “_.circle” pto rad)

(setq rad (getdist pto “\nRadio exterior: “))

(command “_.circle” pto rad)

(if (= cmd0 1)

(setvar “cmdecho” 1)

)

(command “_undo” “_end“)

(princ)

)

(prompt “\nNuevo comando ARAND cargado“)

¿Deberíamos añadir estas dos líneas en la macro CIRCPERI? Pues no es necesario, puesto que enCIRCPERI tan solo utilizamos un comando. Así que el comando de AutoCAD “H” va a deshacer ese comando. En cambio en ARAND se dibujan dos circunferencias con dos comandos de AutoCAD.

Funciones de tratamiento de errores en AutoLISP

Las rutinas que hemos creado (CIRCPERI y ARAND) no están terminadas todavía. Para terminarlas debemos realizar dos modificaciones:

Controlar lo que hace la rutina en caso de que se produzca un error durante su ejecución.

Impedir que el usuario introduzca datos erróneos. Por ejemplo, que indique cero como radio de una circunferencia.

En este artículo se tratará el primero de los dos puntos anteriores, y en el siguiente se verá el segundo punto.

Si nos fijamos en el código de la macro ARAND: ¿Qué sucede si el usuario como respuesta a la petición del radio interior pulsa Intro? Pues que se asigna a la variable rad el valor nil. De modo que se producirá un error al evaluar la siguiente línea de código: (command “_.circle” pto rad). En el siguiente tema veremos cómo se puede evitar que el usuario introduzca datos erróneos. Por ejemplo, evitar que como respuesta a la petición del radio interior se introduzca Intro.

Page 79: Autolisp Gera

Pero una cosa está clara, no siempre vamos a poder controlar todos los posibles errores en nuestras macros. De modo que necesitamos una función de tratamiento de errores que informe al usuario del tipo de error que se produce. Por ejemplo, indicarle al usuario que ha introducido un dato incorrecto. AutoCAD en este caso nos dice: “; error: tipo de argumento erróneo: numberp: nil”

AutoLISP dispone de una función de tratamiento de errores por defecto. Dicha función se llama *error* y recibe como argumento una cadena de texto con la descripción del error que se ha producido.

Podemos redefinir la función de tratamiento de errores que ofrece AutoLISP, de modo que se puede personalizar a nuestro gusto en función de nuestros intereses. Así pues, vamos a crear una función de tratamiento de errores a la que llamaremos ERRORES:

(defun ERRORES ( mens )

(if (= mens “quitar / salir abandonar“)

(princ)

(princ (strcat “\nError: ” mens ” “))

)

(princ)

)

No nos paremos demasiado aquí  ya lo veremos bien más adelante. Hemos creado una función llamadaERRORES para el tratamiento de errores en nuestras rutinas. Ahora habría que decirle al comando ARANDque utilice esta nueva función de tratamiento de errores.

Pero antes, conviene explicar cómo se pueden redefinir las funciones de AutoLISP. Hay dos métodos:

1. Crear una función con el mismo nombre. Por ejemplo, (defun SIN … Esto redefinirá la función SIN de AutoLISP.

2. Asignarle un valor distinto mediante setq. Por ejemplo, si hacemos (setq sin cos) la función SIN de AutoLISP pasará a funcionar como la función COS, devolviendo el coseno de un ángulo en lugar de el seno. (sin 0.0) ahora devolvería 1.0 en lugar de 0.

Veamos ahora el código de la función ARAND ya modificada:

(defun C:ARAND ( / pto rad cmd0 error0 )

(command “_.undo” “_begin“)

(if (= (setq cmd0 (getvar “cmdecho“)) 1)

Page 80: Autolisp Gera

(setvar “cmdecho” 0)

)

(setq error0 *error* *error* ERRORES)

(setq pto (getpoint “\nCentro de la arandela: “))

(setq rad (getdist pto “\nRadio interior: “))

(command “_.circle” pto rad)

(setq rad (getdist pto “\nRadio exterior: “))

(command “_.circle” pto rad)

(setq *error* error0)

(if (= cmd0 1)

(setvar “cmdecho” 1)

)

(command “_.undo” “_end“)

(princ)

)

(prompt “\nNuevo comando ARAND cargado“)

En la línea (setq error0 *error* *error* ERRORES) se asigna a la variable error0 la antigua función de tratamiento de errores, *error*. Y se define la función de tratamiento de errores como nuestra funciónERRORES.

Por supuesto, le decimos que use nuestra función de tratamiento de errores al principio del código. Pero siempre después de desactivar el eco de mensajes.

Hemos redefinido la función de tratamiento de errores, pero al terminar la rutina debemos dejarlo todo como estaba antes. Así que recuperamos la función de tratamiento de errores inicial, la que ofrece AutoLISP por defecto. Lo haríamos con la siguiente línea: (setq *error* erro0) que se debe poner antes de volver a activar el eco de mensajes.

Para probar la función de tratamiento de errores debemos cargarla en AutoCAD.

En la rutina CIRCPERI haríamos exactamente lo mismo:

(defun C:CIRCPERI ( / pto peri rad cmd0 error0 )

(if (= (setq cmd0 (getvar “cmdecho“)) 1)

(setvar “cmdecho” 0)

Page 81: Autolisp Gera

)

(setq error0 *error* *error* ERRORES)

(setq pto (getpoint “\nCentro de la circunferencia: “))

(setq peri (getdist “\nPerímetro: “))

(setq rad (/ peri (* pi 2)))

(command “_.circle” pto rad)

(setq *error* error0)

(if (= cmd0 1)

(setvar “cmdecho” 1)

)

(princ)

)

(prompt “\nNuevo comando CIRCPERI cargado“)

Repasemos un poco el funcionamiento de la rutina CIRCPERI: Lo primero que hacemos es desactivar el eco de mensajes, a continuación redefinimos la función de tratamiento de errores, después viene el código de la función, se restituye la función de tratamiento de errores de AutoLISP y se recupera el valor inicial de “cmdecho” (que controla el eco de mensajes).

¿Qué diferencia existe entre nuestra función de tratamiento de errores y la ofrecida por defecto por AutoLISP?

Pues casi ninguna, de momento tan sólo se diferencia en que si el error que se ha producido tiene por descripción “quitar / salir abandonar“, que equivale a pulsar la tecla de ESCape, no hace nada. Si el error no se ha producido por pulsar ESC, sino por otra causa, entonces mostrará un mensaje indicando: “Error: Descripción del error“. Un “gran” cambio, no? Bueno los cambios vamos a hacerlos ahora que ya sabemos como funciona la función ERRORES.

Cada tipo de error ofrece una descripción específica y además existe un código numérico asociado a la variable de sistema ERRNO en la que se almacena el código correspondiente al último error que se ha producido. Puedes ver en este enlace una lista de los códigos y mensajes de error de AutoLISP.

¿Qué sucede si el usuario introduce un dato incorrecto al solicitarle el perímetro? En ese caso, en la siguiente línea (setq rad (/ peri (* pi 2))) se produciría un error, iniciándose la función de tratamiento de errores. Cuando se produce el error, ya se ha evaluado la línea (setq error0 *error* *error* ERRORES) enCIRCPERI, de modo que hemos

Page 82: Autolisp Gera

redefinido la función de tratamiento de errores. Así que se ejecuta la funciónERRORES, que muestra la descripción del error que se produjo. Pero, salimos de la función ERRORES y no hemos recuperado el valor de la función de tratamiento de errores que nos ofrece por defecto AutoLISP. Y también se ha desactivado el eco de mensajes, pero no recuperamos su valor inicial.

De modo que vamos a modificar la función ERRORES para añadir estos pequeños cambios:

(defun ERRORES ( mens )

(setq *error* error0)

(if (= mens “quitar / salir abandonar“)

(princ)

(princ (strcat “\nError: ” mens ” “))

)

(if (= cmd0 1)

(setvar “cmdecho” 1)

)

(princ)

)

Ahora nuestra función ERRORES restituye el valor inicial del eco de mensajes y la función de tratamiento de errores inicial. Puede extrañar que se utilicen las variables cmd0 y error0 dentro de la función ERRORES, ya que estaban definidas como variables locales en CIRCPERI.

Cuando definimos una variable local en una función, esta variable se puede utilizar sólo dentro de esa función. Pero, si desde CIRCPERI “llamamos” a otra función, por ejemplo ERRORES, en realidad estamos dentro de ERRORES, que está dentro de CIRCPERI. Así que seguimos dentro de CIRCPERI.

Otra de las principales aplicaciones de redefinir la función de tratamiento de errores tiene que ver con el tema anterior, los comandos deshacer en las rutinas de AutoLISP.

Si nos fijamos en el código de la rutina ARAND, vemos que la primera línea es (command “_.undo” “_begin“) Qué sucedería si se produce un error después de dibujar el segundo círculo? Daría un error, y terminaría el comando sin ejecutar la línea (command “_.undo” “_end“). Con lo cual para deshacer la arandela deberíamos ejecutar el comando “H” (deshacer) dos veces, una por cada círculo. Es más, imagina que nuestra rutina no dibuja 2 circunferencias sino 120 y que el error se produce al dibujar la circunferencia enésima…

Page 83: Autolisp Gera

Podríamos entonces modificar la función de tratamiento de errores y añadir la línea de código:

(command “_.undo” “_end“)

Ahora, bastaría con ejecutar el comando deshacer una única vez para que se deshaga todo lo que hizo el comando ARAND.

Podemos incluso decirle a la función ERRORES que si se produce un error, ejecute el comando deshacer directamente:

(defun ERRORES ( mens )

(setq *error* error0)

(if (= mens “quitar / salir abandonar“)

(princ)

(princ (strcat “\nError: ” mens ” “))

)

(command “_.undo” “_end“)

(command “_.undo” “”)

(if (= cmd0 1)

(setvar “cmdecho” 1)

)

(princ)

)

En este caso si se produce un error ni siquiera hace falta ejecutar el comando deshacer, la funciónERRORES ya lo hace por nosotros.

Para terminar este artículo, vamos a añadir una nueva opción a CIRCPERI. Se trata de que ofrezca por defecto el perímetro de la última circunferencia dibujada. Podríamos hacer lo siguiente:

(defun C:CIRCPERI ( / pto peri cmd0 )

(if (= (setq cmd0 (getvar “cmdecho“)) 1)

(setvar “cmdecho” 0)

)

(setq pto (getpoint “\nCentro de la circunferencia: “))

(if (not rad)

Page 84: Autolisp Gera

(prompt “\nPerímetro: “)

(progn

(prompt “\nPerímetro <“)

(prompt (rtos (* rad 2 pi) 2 2))

(prompt “>: “)

)

)

(if (setq peri (getdist))

(setq rad (/ peri (* 2 pi)))

)

(command “_.circle” pto rad)

(if (= cmd0 1)

(setvar “cmdecho” 1)

)

(princ)

)

(prompt “\nNuevo comando CIRCPERI cargado“)

Ponemos la variable rad como global, así se puede recuperar el valor que tenía en la anterior ejecución deCIRCPERI. Veamos ahora cómo funciona el siguiente trozo de código:

(if (not rad)

(prompt “\nPerímetro: “)

(progn

(prompt “\nPerímetro <“)

(prompt (rtos (* rad 2 pi) 2 2))

(prompt “>: “)

)

)

Page 85: Autolisp Gera

Si rad es igual a nil, no se ha definido, significa que es la primera vez que se ejecuta el comando CIRCPERIen el dibujo actual. En este caso se muestra un mensaje solicitando el perímetro del círculo.

Si no es la primera vez que se ejecuta CIRCPERI, la variable rad tendrá asociado un valor, correspondiente al radio del circulo creado en la última ejecución de CIRCPERI. También muestra un mensaje solicitando el perímetro, pero entre los caracteres “<” y “>” se indica además el valor de la variable global rad.

(if (setq peri (getdist))

(setq rad (/ peri (* 2 pi)))

)

A continuación se solicita una distancia. No se ha indicado ningún mensaje en la función getdist, ya que el mensaje de solicitud se muestra en las líneas anteriores. Si se indica un perímetro, ya sea por medio de dos puntos o escribiéndolo directamente, entonces se calcula su radio. Si como respuesta a getdist se pulsa Intro, a la variable peri se asigna el valor nil, que es devuelto por setq. De modo que en este caso no hace nada, por lo tanto la variable rad sigue almacenando el radio del último círculo creado con CIRCPERI.

(command “_.circle” pto rad)

Por último dibuja el círculo.

AutoCAD dispone de una variable de sistema llamada CIRCLERAD en la que almacena el valor del último circulo dibujado. Así que podemos utilizar esta variable de sistema para obtener el radio del último círculo, en lugar de utilizar la variable rad como global. El código sería el siguiente:

(defun C:CIRCPERI ( / pto rad peri cmd0 )

(if (= (setq cmd0 (getvar “cmdecho“)) 1)

(setvar “cmdecho” 0)

)

(setq pto (getpoint “\nCentro de la circunferencia: “))

(if (= (getvar “circlerad“) 0.0)

(prompt “\nPerímetro: “)

(progn

(prompt “\nPerímetro <“)

(prompt (rtos (* (getvar “circlerad“) 2 pi) 2 2))

Page 86: Autolisp Gera

(prompt “>: “)

)

)

(if (setq peri (getdist))

(setq rad (/ peri (* 2 pi)))

(setq rad (getvar “circlerad“))

)

(command “_.circle” pto rad)

(if (= cmd0 1)

(setvar “cmdecho” 1)

)

(princ)

)

(prompt “\nNuevo comando CIRCPERI cargado“)

Ahora ofrecerá por defecto el perímetro del último círculo dibujado en AutoCAD, independientemente de si dicho círculo se creo con la rutina CIRCPERI, con el comando CIRCULO o por cualquier otro medio. Veamos como funcionan los cambios que hemos realizado:

(if (= (getvar “circlerad“) 0.0)

(prompt “\nPerímetro: “)

(progn

(prompt “\nPerímetro <“)

(prompt (rtos (* (getvar “circlerad“) 2 pi) 2 2))

(prompt “>: “)

)

)

Si aún no se ha creado ningún círculo en el dibujo, la variable circlerad tendrá asociado el valor 0.0. En este caso solicita el perímetro sin ofrecer ningún valor por defecto, y en caso contrario ofrece por defecto el perímetro del último círculo creado.

(if (setq peri (getdist))

Page 87: Autolisp Gera

(setq rad (/ peri (* 2 pi)))

(setq rad (getvar “circlerad“))

)

Si se introduce un perímetro, por medio de dos puntos o escribiéndolo se calcula el radio correspondiente. En caso de que se pulse Intro, se asocia a la variable rad el radio del último círculo dibujado.

Limitar las respuestas de los usuarios

En el artículo anterior vimos las funciones de tratamiento de errores, que nos permiten controlar lo que sucede cuando se produce un error en nuestras macros. En esta ocasión intentaremos que no se produzcan alguno de los posibles errores en las macros.

Los errores pueden deberse a que el código no funciona bien por que se ha empleado mal alguna función de AutoLISP o se ha ejecutado incorrectamente un comando de AutoCAD, por ejemplo, pero estos no son los tipos de errores que corregiremos en este tema. Más adelante veremos métodos de depuración de nuestras rutinas y corregiremos los errores debidos a un código fuente incorrecto.

Ahora trataremos otro tipo de errores, los que se producen cuando el usuario introduce datos erróneos  Por ejemplo, cuando se solicita un número positivo y el usuario indica cero o un número negativo.

(INITGET [modo] [palabras_clave])Esta función se utiliza para modificar el funcionamiento de otras funciones de AutoLISP, en concreto aquellas funciones en las que se solicitan datos al usuario. Por ejemplo: GETpoint, GETreal, GETint, … casi todas comienzan por GET así que se suelen denominar funciones de tipo GET.

Initget siempre devuelve nil. Y si se indica solo, sin argumentos, no hace nada. Tan solo devuelve nil. Así que vamos a ver para que sirven los argumentos de Initget:

“modo”Es un número entero que nos permitirá limitar los datos que se puedan introducir en la siguiente solicitud de datos al usuario. Initget NUNCA funciona por si sola, siempre se utiliza para modificar el funcionamiento de otra función.

El argumento modo es en realidad un código binario, que puede tener los siguientes valores:

1 –> No admite valores nulos, es decir que se indique Intro como respuesta 2 –> No admite el 0 como respuesta

Page 88: Autolisp Gera

4 –> No admite valores negativos como respuesta

8 –> Permite indicar un punto fuera de los límites del dibujo. Aún cuando estos están activados.

16 –> Este valor no se utiliza actualmente

32 –> Dibuja la línea o rectángulo elásticos con líneas discontínuas en lugar de contínuas

64 –> Hace que GETdist devuelva la distancia en 2D. Es como si proyectase la distancia real sobre el plano XY.

128 –> Permite introducir como respuesta una expresión de AutoLISP.

Bien, veamos como se utiliza initget. Por ejemplo, si queremos que el usuario introduzca un número entero y que no pueda pulsar Intro como respuesta, haríamos lo siguiente:

(initget 1)

(setq numero (getint “\nNúmero entero: “))

Initget modifica a la siguiente función de solicitud de datos, es decir, getint.

Si además queremos que no pueda indicar 0 como respuesta, entonces sumamos sus respectivos códigos, el1 para que no se pueda indicar Intro como respuesta y el 2 para que no se pueda indicar 0.

(initget (+ 1 2))

(setq numero (getint “\nNúmero entero: “))

También podemos indicar directamente (initget 3) en lugar de (initget (+ 1 2)). Si el usuario indica como respuesta 0 o Intro, AutoCAD le dirá que ese dato no es válido y que introduzca un dato correcto.

Si queremos que además se indique un número positivo, entonces deberíamos poner:

(initget 7)

(setq numero (getint “\nNúmero entero: “))

Ya que 7 = 1 + 2 + 4

Veamos ahora como funciona el código 8 como argumento modo de Initget.

8 –> Permite indicar un punto fuera de los límites del dibujo. Aún cuando estos están activados.

Supongamos que tenemos los límites del dibujo de AutoCAD activados (comando LIMITES) en ese caso no podemos indicar puntos fuera de esos límites. De

Page 89: Autolisp Gera

modo que si se solicita un punto al usuario conGETPOINT deberá indicarlo dentro de los límites del dibujo. Pero si antes de solicitar el punto se ejecuta(initget 8) entonces si nos dejaría.

El código 16 no se utiliza. El código 32 se utiliza en funciones de solicitud en las que se indica un punto

base, por ejemplo:

(getpoint pto “\nIndicar punto:“)

(getcorner pto “\nIndicar punto:“)

En estos casos aparece una línea, o un rectángulo, elástico con origen en el punto base pto. Estas líneas y rectángulos elásticos se muestran con línea continua. Pero si antes de la función de solicitud se añade(initget 32) se mostraran con líneas discontinuas. Por ejemplo:

(setq pt1 (getpoint “\nPunto base: “))

(initget 32)

(setq pt2 (getpoint pt1 “\nSegundo punto: “))

En este ejemplo aparece una línea discontinua. Y en el siguiente un rectángulo con líneas discontinuas.

(setq pt1 (getpoint “\nPunto base: “))

(initget 32)

(setq pt2 (getcorner pt1 “\nSegundo punto: “))

Veamos ahora como funciona el código 64

64–> Hace que GETdist devuelva la distancia en 2D. Es como si proyectase la distancia real sobre el plano XY.

Getdist solicita una distancia, que se puede escribir directamente, o se pueden indicar dos puntos en pantalla. En este caso, getdist devolverá la distancia real entre esos dos puntos. Si lo que nos interesa obtener es la distancia de sus proyecciones sobre el plano XY actual se añadirá (initget 64) antes de la ejecutar getdist. Por ejemplo:

(setq pt1 (getpoint “\nPunto base: “))

(initget 64)

(setq dist12 (getdist pt1 “\nSegundo punto: “))

Por último, el código 128 permite indicar una expresión de AutoLISP como respuesta. Por ejemplo, podemos utilizar nuestra rutina RAG (Radianes A Grados decimales) para indicar un ángulo en grados decimales cuando nosotros lo tenemos en radianes.

Page 90: Autolisp Gera

(initget 128)

(setq ang (getreal “\nIntroducir ángulo: “))

En este caso el usuario podría indicar como respuesta a la solicitud del ángulo: (RAG (/ pi 4)) Es decir, un ángulo de 45º.

Pues llegados a este punto, antes de ver el segundo argumento de (INITGET [modo] [palabras_clave]), es decir, las palabras clave. Vamos a modificar nuestras rutinas ARAND y CIRCPERI.

Si revisamos el código de la macro CIRCPERI encontraremos la siguiente línea:

(setq pto (getpoint “\nCentro de la circunferencia: “))

¿deberíamos añadir alguna limitación como respuesta del usuario? Veamos:

Si el usuario pulsa Intro como respuesta a la variable pto se le asocia el valor nil, que es lo que devolvería Getpoint. Después al intentar dibujar el círculo (command “_.circle” pto rad) se produciría un error. Así que debemos impedir que el usuario introduzca Intro como respuesta, de modo que añadiríamos (initget 1) antes de la función getpoint.

Como estamos solicitando un punto, el código 2 no tiene sentido y lo mismo sucede con el 4.

El código 8 permite indicar un punto fuera de los límites del dibujo, aún cuando estos están activados. Este código si podríamos utilizarlo, aunque si el usuario trabaja con los límites activados, están activados y ya está. Si quiere que los desactive él, no? Porque supongo que los tendrá activados por algún motivo. Así que no le añadimos a initget el código 8.

El código 32 no tiene sentido aquí, pues no aparece la línea base.

Y el código 64 tampoco ya que estamos solicitando un punto, no una distancia.

El código 128 permite introducir como respuesta una expresión de AutoLISP. Este código también se podría indicar, pero lo habitual es no hacerlo. Se podría utilizar en casos en los que el usuario pudiera utilizar una expresión de AutoLISP para calcular el dato. Como en el ejemplo que vimos antes, si tiene un ángulo en radianes y lo tiene que indicar en grados decimales. Aquí nos pide un punto, así que no tiene demasiado sentido.

Definitivamente el código quedaría:

(initget 1)

(setq pto (getpoint “\nCentro de la circunferencia: “))

Page 91: Autolisp Gera

Sigamos modificando la rutina CIRCPERI: Unas líneas después de la solicitud del centro de la circunferencia, se solicita su perímetro:

(if (setq peri (getdist))

(setq rad (/ peri (* 2 pi)))

(setq rad (getvar “circlerad“))

)

¿Deberíamos añadir la función initget con el código 1 antes de la función getdist?

Veamos como funciona esta parte del código: Si el usuario introduce una distancia, se evalúa la condición si cumple del IF es decir:

(setq rad (/ peri (* 2 pi)))

Y si el usuario pulsa Intro, se asigna a peri el valor nil y evalúa la condición no cumple del IF, es decir:

(setq rad (getvar “circlerad“))

Si añadimos antes del getdist la expresión (initget 1), el usuario no podrá indicar Intro, así que nunca se ejecutaría la expresión no cumple. Por tanto no añadimos el código 1 a Initget.

El perímetro del círculo no puede ser ni cero ni un número negativo, de modo que podemos añadir ainitget los códigos 2 y 4.

También podríamos añadir el código 64 para que GETdist devuelva la distancia en 2D. Pero normalmente no conviene añadir este código, excepto cuando la distancia “deba ser” siempre ser en 2D.

Una última nota sobre CIRCPERI: Cuando ejecutamos la macro por primera vez en un dibujo en el que no se ha dibujado ningún círculo, la variable de sistema “circlerad” tiene el valor 0.0. En este caso, no ofrecemos la opción de seleccionar el radio del último círculo dibujado pulsando Intro, ya que no existe ningún círculo dibujado previamente. En este caso, no deberíamos indicar el modo 6 a Initget, sino el 7 para que tampoco permita al usuario indicar Intro como respuesta. Veamos como se soluciona en el código completo de la rutina:

(defun C:CIRCPERI ( / pto rad peri cmd0 )

(if (= (setq cmd0 (getvar “cmdecho“)) 1)

(setvar “cmdecho” 0)

)

(initget 1)

Page 92: Autolisp Gera

(setq pto (getpoint “\nCentro de la circunferencia: “))

(if (= (getvar “circlerad“) 0.0)

(progn

(prompt “\nPerímetro: “)

(initget 7)

)

(progn

(prompt “\nPerímetro <“)

(prompt (rtos (* (getvar “circlerad“) 2 pi) 2 2))

(prompt “>: “)

(initget 6)

)

)

(if (setq peri (getdist))

(setq rad (/ peri (* 2 pi)))

(setq rad (getvar “circlerad“))

)

(command “_.circle” pto rad)

(if (= cmd0 1)

(setvar “cmdecho” 1)

)

(princ)

)

(prompt “\nNuevo comando CIRCPERI cargado“)

Vamos ahora a modificar la rutina ARAND. La primera solicitud que tenemos en ARAND es la del centro de la arandela. Prácticamente es igual que la solicitud del centro del círculo en CIRCPERI, así que le añadimos también el código 1 a Initget:

(initget 1)

(setq pto (getpoint “\nCentro de la arandela: “))

Page 93: Autolisp Gera

A continuación solicita los radios interior y exterior de la arandela. En los que podemos evitar que el usuario indique como respuesta Intro, 0 o un número negativo. Por lo tanto añadiremos Initget con el modo 7. Veamos el código completo:

(defun C:ARAND ( / pto rad cmd0 )

(command “_.undo” “_begin“)

(if (= (setq cmd0 (getvar “cmdecho“)) 1)

(setvar “cmdecho” 0)

)

(initget 1)

(setq pto (getpoint “\nCentro de la arandela: “))

(initget 7)

(setq rad (getdist pto “\nRadio interior: “))

(command “_.circle” pto rad)

(initget 7)

(setq rad (getdist pto “\nRadio exterior: “))

(command “_.circle” pto rad)

(if (= cmd0 1)

(setvar “cmdecho” 1)

)

(command “_undo” “_end“)

(princ)

)

(prompt “\nNuevo comando ARAND cargado“)

Limitar las respuestas de los usuarios (II)

(initget [modo] [palabras_clave])En el último artículo del curso comenzamos a ver la función INITGET y vimos como funcionaba el argumento[modo] ahora vamos con [palabras_clave]:

Page 94: Autolisp Gera

[palabras_clave] nos permite indicar una serie de textos (palabras) que también serán aceptados como respuesta en la siguiente función de solicitud de datos. Por ejemplo:

(initget 7 “Diámetro Perímetro“)

(setq rad (getdist “\nRadio del circulo / Diámetro / Perímetro :“))

como respuesta a getdist podemos indicar una distancia, ya sea escribiendo un valor numérico o mediante dos puntos, pero ahora también aceptará como respuesta “Diámetro” y “Perímetro“. El modo 7 impide que se indique como respuesta Intro, cero o un número negativo.

Si indicamos como respuesta una distancia, asocia esa distancia a la varible rad. Si indicamos como respuesta “Diámetro“, asocia a la variable rad la cadena de

texto “Diámetro“.

Si indicamos como respuesta “Perímetro“, asocia a la variable rad la cadena de texto “Perímetro“.

En [palabras_clave] indicamos una serie de palabras, separadas por espacios, que servirán como respuesta a la siguiente función de solicitud de datos.

No hace falta escribir el nombre completo de la palabra, como hicimos antes, basta con que el usuario introduzca como respuesta las letras que aparecen en mayúsculas. Es decir, la D o la P.

En el siguiente ejemplo:

(initget 7 “Diámetro desHacer“)

(setq rad (getdist “\nRadio del circulo / Diámetro / desHacer: “))

Para seleccionar la opción “Diámetro” habrá que escribir al menos la D. Pero para seleccionar “desHacer” al menos habrá que escribir H. También aceptaría “diá” para el diámetro y “desh” para deshacer.

Sin embargo no aceptará “de” ni “des” para seleccionar “desHacer“. Fíjate que al menos deben indicarse las letras en mayúsculas.

Por otra parte, aceptará tanto “diá” como “dia” sin tilde para seleccionar “Diámetro“.

Supongamos que tenemos el siguiente código:

(initget 7 “Diámetro desHacer“)

(setq rad (getdist “\nRadio del circulo: “))

En este caso getdist aceptará como respuestas a la petición del radio de la circunferencia “Diámetro” y “desHacer“. Pero al no indicar estas opciones en el mensaje de getdist, el usuario no sabrá que existen. De modo que es recomendable indicar al usuario las opciones que puede seleccionar:

Page 95: Autolisp Gera

(initget 7 “Diámetro desHacer“)

(setq rad (getdist “\nRadio del circulo / Diámetro / desHacer :“))

Como mejor se ve es con un ejemplo así que, vamos a modificar la rutina ARAND añadiendo una opción para indicar el diámetro en lugar del radio. Tenemos que modificar las siguientes líneas:

(initget 7)

(setq rad (getreal “\nRadio interior: “))

Primero añadimos “Diámetro” a la lista de palabras clave de initget:

(initget 7 “Diámetro“)

Y a continuación le decimos al usuario que existe una opción llamada “Diámetro” que puede seleccionar como respuesta:

(setq rad (getreal “\nRadio interior / Diametro: “))

De esta forma ya hemos añadido la opción “Diámetro”

Pero, ¿qué sucede si el usuario indica como respuesta la opción “Diámetro“? Pues que asignamos a la variable rad la cadena de texto “Diámetro” y en la siguiente línea (command “_.circle” pto rad) al intentar dibujar la circunferencia, nos da un error.

Así que hay que modificar la rutina añadiendo a continuación algo parecido a:

Si el usuario selecciona la opción “Diámetro” –> Preguntamos por el diámetro.

Pues esto en AutoLISP, sería:

(if (= rad “Diámetro“)

(setq rad (getreal “\nDiámetro interior: “))

)

Hay que tener especial cuidado con la condición del IF (= rad “Diámetro“) ya que hay que indicar la palabra clave tal y como aparece en la lista de palabras clave de initget.

Es decir, no funcionaría si ponemos (= rad “diámetro“) o (= rad “Diametro“) ya que en el primer caso no ponemos la “D” en mayúsculas y en el segundo no hemos tildado la “a”.

Fíjate en lo que hace el código anterior:

Si el usuario indica una distancia la asigna a la variable rad y luego (if (= rad “Diámetro“)… devuelvenil, puesto que rad es distinto de “Diámetro“.

Si el usuario indica D o Diam, o diámetro, entonces asigna a la variable rad la cadena de texto “Diámetro“. Luego al entrar en el IF, (= rad

Page 96: Autolisp Gera

“Diametro“) devuelve T así que evalúa la expresión si cumple (setq rad (getreal “\nDiámetro interior: “)) que pide un diámetro al usuario y lo asigna a la variable rad.

Pero rad viene de radio, porque en esta variable almacenamos el radio de la circunferencia y no el diámetro. Así que al dibujar la circunferencia (command “_.circle” pto rad) dibujaría una circunferencia del doble del diámetro de lo que ha dicho el usuario.

El código debería ser:

(initget 7 “Diámetro“)

(setq rad (getreal “\nRadio interior / Diámetro: “))

(if (= rad “Diámetro“)

(setq rad (/ (getreal “\nDiámetro interior: “) 2.0))

)

Pero, ¿Qué pasa si el usuario hace lo siguiente?

Indica D como respuesta al radio interior. Indica -50 o 0 como diámetro.

Pues que asignaría a la variable rad el resultado de dividir -50 o 0 entre 2.0. Por tanto tendríamos una circunferencia con radio negativo o cero.

Recuerda que initget solo tiene efecto sobre la siguiente función de solicitud de datos, de modo que tenemos que añadir de nuevo la función Initget antes de preguntar por el diámetro:

(initget 7 “Diámetro“)

(setq rad (getreal “\nRadio interior / Diámetro: “))

(if (= rad “Diámetro“)

(progn

(initget 7)

(setq rad (/ (getreal “\nDiámetro interior: “) 2.0))

)

)

Se ha añadido la función Progn ya que sino, solo se puede ejecutar una expresión como condición si-cumple del IF.

Page 97: Autolisp Gera

Para el radio o diámetro exterior se haría exactamente lo mismo. Por tanto el código completo será:

(defun C:ARAND ( / pto rad cmd0 )

(command “_.undo” “_begin“)

(if (= (setq cmd0 (getvar “cmdecho“)) 1)

(setvar “cmdecho” 0)

)

(initget 1)

(setq pto (getpoint “\nCentro de la arandela: “))

(initget 7 “Diámetro“)

(setq rad (getdist pto”\nRadio interior / Diámetro: “))

(if (= rad “Diámetro“)

(progn

(initget 7)

(setq rad (/ (getreal “\nDiámetro interior: “) 2.0))

)

)

(command “_.circle” pto rad)

(initget 7 “Diámetro“)

(setq rad (getdist pto “\nRadio exterior / Diámetro: “))

(if (= rad “Diámetro“)

(progn

(initget 7)

(setq rad (/ (getreal “\nDiámetro exterior: “) 2.0))

)

)

(command “_.circle” pto rad)

(if (= cmd0 1)

(setvar “cmdecho” 1)

Page 98: Autolisp Gera

)

(command “_undo” “_end“)

(princ)

)

(prompt “\nNuevo comando ARAND cargado“)

(GETKWORD [mensaje])Esta función de AutoLISP se utiliza para obtener una opción indicada por el usuario. Se utiliza en combinación con INITGET, por ejemplo:

(initget “DEShacer Nuevo Repetir“)

(setq opc (getkword “\nDEShacer / Nuevo / Repetir: “))

En este caso el usuario tan sólo podrá indicar como respuesta una de las palabras clave de la función Initgety se la asigna a la variable opc.

No hemos indicado el modo en Initget, tal solo las palabras clave. En la rutina ARAND nos interesaba que apareciera el modo 7 para que no se indique como respuesta Intro, 0 o un número negativo. Pero no es obligatorio indicar siempre un modo.

Un ejemplo bastante habitual en las macros es el siguiente:

(initget “DEShacer Nuevo Repetir“)

(setq opc (getkword “\nDEShacer / Nuevo / Repetir: “))

(cond

((= opc “DEShacer“)

(alert “Has seleccionado la opción DEShacer“)

)

((= opc “Nuevo“)

(alert “Has seleccionado la opción Nuevo“)

)

(T

(alert “Has seleccionado la opción Repetir“)

)

)

Así en función de la opción que indique el usuario se hace una cosa u otra.

Page 99: Autolisp Gera

Estructuras repetitivas: Bucles

Hasta hace poco tan sólo podíamos crear programas cuya ejecución fuera lineal:

Haz esto Ahora esto otro

Luego vimos las estructuras condicionales IF y COND que ya nos permiten jugar un poco más y hacer que nuestros programas no fueran tan lineales. Ahora vamos a ver funciones que nos permitirá crear repeticiones de código y algo que tal vez te suene, los bucles, que se utilizan mucho en programación.

(WHILE condición [expr1] [expr2] …)La función while ejecuta las expresiones indicadas MIENTRAS se cumpla la condición, y devuelve el valor de la última expresión evaluada. Por ejemplo:

(setq i 0)

(while (< i 10)

(prompt “\n“)

(prompt (itoa i))

(setq i (1+ i))

)

Mientras i sea menor que 10, ejecuta las expresiones. Es decir, escribirá en la ventana de comandos de AutoCAD los números del 0 al 9. Cuando (setq i (1+ i)) asigna a la variable i el valor 10, la condición del bucle ya no se verifica, de modo que termina el bucle. La función While devolverá el valor de la última expresión evaluada, es decir 10.

Este es un típico ejemplo de bucle, una estructura repetitiva con un índice o contador, en este caso i, que puede ir aumentando o disminuyendo.

Fíjate que una de las expresiones que se ejecutan dentro del bucle es (setq i (1+ i)) es decir, movemos el contador. Si no lo hiciéramos i siempre sería menor que 10 y se entraría en un bucle sin fin, que da lugar a un error.

Veamos el siguiente ejemplo:

(setq i 10)

(while (< i 10)

Page 100: Autolisp Gera

(prompt “\n“)

(prompt (itoa i))

(setq i (1+ i))

)

En este caso i tiene asignado el valor 10 antes de entrar en el bucle, de modo que la condición (< i 10) no se cumpliría y por tanto no se ejecutarán las expresiones siguientes. While devuelve el valor de la última expresión evaluada, que en este caso es la condición así que devuelve nil.

Las expresiones en While son opcionales, de modo que podemos crear un bucle en el que solo se indique la condición:

(while (not (setq pt (getpoint “\nPunto inicial: “))))

En este caso la condición es (not (setq pt (getpoint “\nPunto inicial: “))) es decir, pide un punto al usuario y lo almacena en la variable pt.

Si el usuario indica un punto, pt = (X Y Z) que es distinto de nil, (not (setq pt (getpoint “\nPunto inicial: “))) devolverá nil y saldrá de la función While.

Si el usuario indica Intro, getpoint devolverá nil y lo almacenará en la variable pt, de modo que (not(setq pt (getpoint “\nPunto inicial: “))) devolverá T, y preguntará de nuevo por un punto.

Por lo tanto, mientras no se indica un punto, sigue preguntando.

Otro ejemplo típico de bucles es en el que se utilizan algunas variables como flags (banderas o banderillas)para indicar si algo está activado o desactivado o para controlar distintos valores. Veamos un ejemplo, supongamos que a y b son dos variables que almacenan dos números reales:

(if (< a b)

(setq flag1 nil)

(setq flag1 T)

)

(while flag1

(prompt “\na NO es menor que b“)

(setq b (getreal “\nIntroduzca un número: “))

(if (< a b)

(setq flag1 nil)

Page 101: Autolisp Gera

)

)

En este caso:

Si a es menor que b –> flag1 = nil Si a NO es menor que b –> flag1 = T

Luego la función While evalúa la condición flag1 que devolverá su valor nil o T.

Si es flag1 = nil (a es menor que b) no evalúa las expresiones pues no se verifica la condición.

Si es flag1 = T (a NO es menor que b) se verifica la condición así que se ejecutan las expresiones. Primero nos dice que a no es menor que b, nos vuelve a pedir el valor de b y comprueba si a es menor que el nuevo valor de b en cuyo caso asigna a la banderilla flag1 el valor nil para salir del bucle.

Es decir, mientas a NO sea menor que b, nos pedirá un nuevo valor de b.

En la función While, al igual que vimos con IF y COND, como condición podemos utilizar expresiones lógicas. Por ejemplo:

(while (or (< a b) (< b 0.0))

(prompt “\na NO es menor que b, o b es negativo“)

(setq b (getreal “\nIntroduzca un número positivo: “))

)

En este ejemplo, el bucle se ejecutará hasta que se indique un valor para b positivo y mayor que a.

(REPEAT cantidad [expr1] [expr2])La función repeat ejecuta las expresiones indicadas el número de veces que se indique en cantidad y devuelve el resultado de la última expresión evaluada.

(repeat 10 (prompt “\nEste curso es demasiado fácil para mi“))

También podríamos asignar la cantidad a repetir a una variable:

(setq Bart_Simpson (getint “\nNúmero de repeticiones para Bart: “))

(repeat Bart_Simpson (prompt “\nNo hace falta fuego en un simulacro de incendio“))

En este caso escribiría en la pizarra, es decir la ventana de comandos de AutoCAD, esa frase tantas veces como le indiquemos.

Page 102: Autolisp Gera

También podemos obtener la cantidad por medio de una función de AutoLISP, como resultado de una operación:

(repeat (+ 4 5) (prompt “Este curso me parece muy sencillo“))

o suponiendo que las variables a y b tengan asignados dos números enteros:

(prompt “Inspector Gadget, este mensaje se autodestruirá en…“)

(setq i 0)

(repeat (+ a b)

(prompt “\t“)

(prompt (itoa i))

(setq i (1+ i))

)

¿Pero qué sucede si a o b son un número real y no un entero? ¿repetirá las expresiones 2.5 veces? Pues no, nos dará un error. Por eso hay que estar bien seguros de que la cantidad indicada es un número entero y no un real. Incluso si como cantidad indicamos un número entero sin decimales, como 2.0, dará un error.

Vamos a modificar la rutina ARAND para hacer que el segundo radio siempre sea mayor que el primero. El código correspondiente al círculo exterior era el siguiente:

(initget 7 “Diámetro“)

(setq rad (getdist pto “\nRadio exterior / Diámetro: “))

(if (= rad “Diámetro“)

(progn

(initget 7)

(setq rad (/ (getreal “\nDiámetro exterior: “) 2.0))

)

)

(command “_.circle” pto rad)

Lo primero que vamos a cambiar es el nombre de las variables. En lugar de utilizar la variable rad tanto para el radio interior como para el exterior, vamos a utilizar la variable radi para el radio interior y la variable radepara el exterior. Así podremos comparar si rade es mayor que radi.

Podríamos sustituir el código anterior por el siguiente:

Page 103: Autolisp Gera

(while (or (not rade) (not (< radi rade)))

(initget 7 “Diámetro“)

(setq rade (getreal “\nRadio exterior / Diámetro: “))

(if (= rade “Diámetro“)

(progn

(initget 7)

(setq rade (/ (getreal “\nDiámetro exterior: “) 2.0))

)

)

)

(command “_.circle” pto rade)

La primera vez que se evalúa la condición del bucle, no se ha asignado aún ningún valor al radio exterior. De modo que rade = nil y (not rade) devolverá T.

Como (or (not rade) (not (< radi rade))) comprueba que al menos se verifique una de las dos condiciones, al verificarse la primera condición (not rade) la segunda ni siquiera se evalúa (por suerte, puesto que al no estar definida rade nos daría un error). La condición se verifica y ejecuta las expresiones que están a continuación, que nos piden un valor para el radio exterior.

Es decir, mientras no se indique el radio exterior o este sea menor que el radio interior se ejecuta el bucle, que nos pide un nuevo valor para el radio exterior. Al salir del bucle ya tenemos un radio exterior válido así que dibujamos la circunferencia exterior. El código completo sería:

(defun C:ARAND ( / pto radi rade cmd0 )

(command “_.undo” “_begin“)

(if (= (setq cmd0 (getvar “cmdecho“)) 1)

(setvar “cmdecho” 0)

)

(initget 1)

(setq pto (getpoint “\nCentro de la arandela: “))

(initget 7 “Diámetro“)

(setq radi (getdist pto “\nRadio interior / Diámetro: “))

Page 104: Autolisp Gera

(if (= radi “Diámetro“)

(progn

(initget 7)

(setq radi (/ (getreal “\nDiámetro interior: “) 2.0))

)

)

(command “_.circle” pto radi)

(while (or (not rade) (not (< radi rade)))

(initget 7 “Diámetro“)

(setq rade (getdist pto “\nRadio exterior / Diámetro: “))

(if (= rade “Diámetro“)

(progn

(initget 7)

(setq rade (/ (getreal “\nDiámetro exterior: “) 2.0))

)

)

)

(command “_.circle” pto rade)

(if (= cmd0 1)

(setvar “cmdecho” 1)

)

(command “_.undo” “_end“)

(princ)

)

(prompt “\nNuevo comando ARAND cargado“)

Funciones para manipular cadenas de texto

Page 105: Autolisp Gera

En este artículo veremos las funciones que incorpora AutoLISP para manipular cadenas de texto.

(CHR entero)Esta función devuelve el carácter al que le corresponde el código ASCII indicado. Por ejemplo:

(chr 65) devuelve “A”

(chr 97) devuelve “a”

(ASCII texto)Devuelve el código ASCII (un número entero) correspondiente al primer carácter de la cadena de texto indicada.

(ascii “Abcde“) devuelve 65

(ascii “A“) también devuelve 65 porque lo único que importa es el primer carácter de la cadena de texto.

(STRLEN texto1 [texto2] …)Esta función devuelve la longitud (número de caracteres) de la cadena de texto que recibe como argumento.

(strlen “AutoLISP“) devuelve 8

También podemos asignar una cadena de texto a una variable y comprobar después su longitud con strlen:

(setq txt1 “AutoLISP“)

(strlen txt1)

Si se indica más de una cadena de texto, devolverá la suma de sus longitudes:

(strlen “AutoLISP” “AutoCAD“) devuelve 15

(STRCASE texto [modo])Se utiliza para convertir un texto en mayúsculas o minúsculas. Por ejemplo:

(strcase “AutoLISP“) devuelve “AUTOLISP”

Si se indica el argumento opcional [modo] con un valor distinto de nil, entonces devuelve el texto en minúsculas.

(strcase “AutoLISP” T) devuelve “autolisp”

Page 106: Autolisp Gera

(STRCAT texto1 [texto2] …)Esta función concatena (une) varias cadenas de texto.

(strcat “Hola” “Mundo“) devolvería “HolaMundo”

Para que las dos palabras anteriores aparezcan separadas se pueden hacer dos cosas:

Añadir el espacio en una de las palabras: (strcat “Hola ” “Mundo“) Añadir el espacio como otra cadena de texto: (strcat “Hola” ” ” “Mundo“)

Esta función se utiliza mucho para concatenar los mensajes que se muestran al usuario. Por ejemplo:

(setq i 10)

(setq rad (getreal (strcat “\nRadio <” (itoa i) “>: “)))

Pedirá un número real al usuario y mostrará el siguiente mensaje en la ventana de AutoCAD: Radio <10>:

(SUBSTR texto pos_inicial [longitud])Esta función devuelve parte de la cadena de texto que recibe como argumento, a partir de la posición inicial que se indique.

(substr “AutoLISP” 5) devuelve el texto a partir del quinto carácter, es decir “LISP“.

(substr “AutoLISP” 1) devuelve el texto entero “AutoLISP”.

(substr “AutoLISP” 15) devuelve “” es decir, una cadena de texto vacía puesto que el texto indicado tiene menos de 15 caracteres.

También se puede indicar la longitud, es decir el número de caracteres que se desean obtener.

(substr “AutoLISP” 5 2) devuelve “LI“. A partir del quinto carácter devuelve 2 caracteres.

(substr “AutoLISP” 5 10) devolverá “LISP“, porque tan sólo tenemos 4 caracteres más, a partir del quinto, y no diez.

(WCMATCH cadena patrón)Esta función se utiliza para comparar si una cadena de texto verifica o cumple un patrón, en caso de que lo verifique devuelve T y si no lo verifica devuelve nil.

(wcmatch “AutoLISP” “A*“) devolverá T ya que comprueba si “AutoLISP” comienza por “A“.

(wcmatch “AutoLISP” “a*“) devolverá nil, puesto que “A” es distinto de “a“.

Page 107: Autolisp Gera

Los patrones son cadenas de texto en las que se pueden emplear determinados símbolos comodín:

# Equivale a un dígito. @ Equivale a una letra.

. Equivale a un carácter que no sea alfanumérico (ni letras ni números).

* Equivale a una cadena de caracteres.

? Equivale a un carácter cualquiera.

~ Equivale a una negación.

o Por ejemplo (wcmatch “AutoLISP” “~B*“) comprueba que el texto no empieza por “B“.

[...] Nos permite indicar varios caracteres.

o Por ejemplo (wcmatch “AutoLISP” “[AB]*“) comprueba si el texto comienza por “A” o por “B“.

o También podríamos indicar un rango: (wcmatch “AutoLISP” “[A-F]*“) comprueba si el texto comienza por “A“, “B“, “C“, … hasta la “F“.

Incluso podemos comprobar con dos patrones distintos, separados por una coma: (wcmatch “AutoLISP” “A*,*LISP“) devolvería T.

¿Pero cómo hacemos entonces para saber si un texto tiene una coma? no podemos hacer los siguiente:(wcmatch “Curso, de AutoLISP” “*,*”) ya que en este caso le estamos indicando dos patrones, como en el ejemplo anterior.

Tendremos que hacerlo así: (wcmatch “Curso, de AutoLISP” “*’,*“) al anteponer el apóstrofo ‘ delante de uno de los caracteres comodines de los patrones, le estamos diciendo que queremos usar el literal, es decir, lo que ponemos a continuación tal cual está.

Pues tema visto. Así que podemos ahora modificar la macro CIRCPERI. Teníamos las siguientes líneas en la macro:

(prompt “\nPerímetro <“)

(prompt (rtos (* (getvar “circlerad“)2 pi) 2 2))

(prompt “>: “)

Podríamos concatenar las cadenas de texto y ejecutar una única vez la función prompt:

(prompt (strcat “\nPerímetro <” (rtos (* (getvar “circlerad“) 2 pi) 2 2) “>: “))

Page 108: Autolisp Gera

Vamos ahora a crear un nuevo comando llamado CIRCULOM que nos permitirá dibujar múltiples circunferencias concéntricas. Y comenzaremos como siempre por el pseudocódigo. Podría ser algo así:

1. Pedir el centro de las circunferencias.2. Mientras se indique un punto o radio.

1. Dibujar un círculo.

Al escribir el código, lo primero es definir el nuevo comando:

(defun C:CIRCULOM ( / )

De momento no ponemos las variables locales, porque aún no tenemos ni variables ni nada. Las añadiremos al terminar la macro.

1. Pedir el centro de los círculos. Por ejemplo así:

(setq pto (getpoint “\nCentro: “))

Tal vez pienses… ¿no deberíamos poner antes un INITGET? Pues seguramente, pero no nos paremos ahora con eso. Primero a ver si hacemos que funcione la rutina, después ya nos preocuparemos de que funcione bien.

2. Mientras se indique un punto o radio. Esto lo podemos hacer con While:

(while (setq rad (getdist pto “\nRadio [Intro para terminar]: “))

Pide puntos o distancias, para usarlas como radio, hasta que se pulse Intro. Fíjate que no se ha cerrado elwhile, porque aún tenemos que añadir las expresiones que van dentro.

Y nos falta solo dibujar la circunferencia. Así de sencillo:

(command “_.circle” pto rad)

nos faltan dos cosas para terminar: El paréntesis de cierre de While y el de la función. El código completo queda así:

(defun C:CIRCULOM ( / )

(setq pto (getpoint “\nCentro: “))

(while (setq rad (getdist pto “\nRadio [Intro para terminar]: “))

(command “_.circle” pto rad)

)

)

Ahora es cuando vamos a introducir las mejoras y a retocar el código. Vamos a comenzar limitando las posibles respuestas de los usuarios con Initget:

Page 109: Autolisp Gera

Añadimos (initget 1) antes de la solicitud Getpoint, para que el usuario no pueda indicar Intro como respuesta.

Y añadimos (initget 6) antes de getdistpara que no permita ni cero ni un número negativo.

o Observa que (initget 6) se vuelve a poner otra vez dentro del bucle While. Si no lo hiciéramos  al indicar el primer radio no permitiría responder con cero ni con un número negativo. Sin embargo, para el segundo radio y todos los siguientes si que nos dejaría. Para que no lo permita, hay que incluir la función Initget antes de que se ejecute de nuevo Getdist, de modo que se añade dentro del bucle While.

Otras mejoras serían:

Añadir las variables a la lista de variables locales de la función. Desactivar el eco de mensajes.

Añadir una salida limpia a la función.

Añadir una línea fuera de la función para que indique el nombre del comando al cargar la macro.

Añadir el comando Deshacer Inicio al principio de la rutina y Deshacer Fin al terminarla.

El código de la macro queda así:

(defun C:CIRCULOM ( / pto rad cmd0 )

(command “_.undo” “_begin“)

(if (= (setq cmd0 (getvar “cmdecho“)) 1)

(setvar “cmdecho” 0)

)

(initget 1)

(setq pto (getpoint “\nCentro: “))

(initget 6)

(while (setq rad (getdist pto “\nRadio [Intro para terminar]: “))

(command “_.circle” pto rad)

(initget 6)

)

Page 110: Autolisp Gera

(if (= cmd0 1)

(setvar “cmdecho” 1)

)

(command “_.undo” “_end“)

(princ)

)

(prompt “\nNuevo comando CIRCULOM cargado“)

Trabajar con ángulos y distancias

AutoLISP proporciona una serie de funciones para trabajar con ángulos y distancias, comenzaremos viendo los ángulos:

(ANGLE pt1 pt2)Esta función devuelve el ángulo formado por la línea que va desde pt1 hasta pt2. El origen de ángulos será el eje X y el sentido antihorario se considera positivo. Por ejemplo:

(setq pt1 (getpoint “\nPunto1: “))

(setq pt2 (getpoint pt1 “\nPunto2: “))

(setq ang (angle pt1 pt2))

Hay que fijarse en cual es el punto que se indica primero en la función angle, porque si hacemos:

(setq ang2 (angle pt2 pt1))

Obtendremos un ángulo distinto, el anterior más pi o menos pi. Por lo tanto: No es lo mismo el ángulo de pt1a pt2 que el ángulo de pt2 a pt1.

Si los puntos están en 3D, los proyecta sobre el plano XY y devuelve el ángulo formado por sus proyecciones

(DISTANCE pt1 pt2)Devuelve la distancia en 3D entre los puntos pt1 y pt2. Si uno de los puntos está en 2D, es decir no tiene coordenada Z, se ignora la coordenada Z del otro punto devolviendo la distancia en 2D.

Page 111: Autolisp Gera

(setq pt1 (getpoint “\nPunto1: “))

(setq pt2 (getpoint pt1 “\nPunto2: “))

(setq dist12 (distance pt1 pt2))

En este caso, (setq dist21 (distance pt2 pt1)) sería igual a dist12. Ya que la distancia del punto pt1 al pt2es igual que la distancia del punto pt2 al pt1.

(POLAR ptobase ang dist)Esta función se utiliza para obtener un punto por medio de coordenadas polares a partir de un punto base. Por ejemplo:

(setq pt1 (getpoint “\nPunto1: “))

(setq pt2 (polar pt1 0.0 50.0))

Esto asignaría a la variable pt2 un punto que está a 50 unidades en la dirección del eje X a partir del punto base pt1. Si hiciéramos:

(command “_.line” pt1 pt2 “”)

Dibujaríamos una línea horizontal de 50 unidades, desde pt1 hasta pt2.

Hay que observar que en (polar pt1 0.0 50.0) se indica primero el punto base, luego un ángulo en radianes y por último una distancia. De modo que:

(setq pt2 (polar pt1 (/ pi 2.0) 50.0))

Devolverá un punto que está a 50 unidades en la dirección del eje Y a partir del punto base pt1. Ya que en este caso se ha indicado un ángulo de (/ pi 2.0) es decir, 90º.

Funciones avanzadas para manejar listas

Ya hemos visto algunas funciones para manejar listas: CAR, CDR, LIST pero hay muchas más. En este tema veremos algunas de las que nos faltan.

(LAST lista)Esta función devuelve el último elemento de la lista que recibe como argumento. De modo que si hacemos:

(setq pto (getpoint “\nPunto de inserción: “))

(setq z (last pto))

Page 112: Autolisp Gera

En la variable z almacenamos la coordenada Z del punto pto, siempre que el punto esté en 3D porque si está en 2D almacenaría la coordenada Y. Los puntos son listas del tipo (10.0 20.0 0.0).

(NTH numero lista)El ejemplo anterior no sería muy útil para obtener la coordenada Y, ya que si indicamos un punto en 3D devolverá la coordenada Z. Entonces, ¿cómo podemos obtener la coordenada Y? ya vimos un método:

(CADR pto)

Pero supongamos que tenemos una lista de 27 elementos, y queremos obtener el elemento 22. ¿Cómo lo haríamos? No podemos utilizar (cADDD…..DDDr pto) ya que sólo nos permite agrupar 4 funciones cAr y cDr. De modo que tendríamos que hacer (cADDD (cDDDD (cDDDDr ….. pto). Pero hacerlo así es bastante engorroso.

Devuelve el elemento cuyo número de orden se indica de la lista.

(nth 2 pto) devolverá la coordenada Y, no? Pues no!. Los elementos de una lista se empiezan a numerar desde cero.

Por ejemplo:

(nth 0 pto) devolverá la coordenada X del punto pto. (nth 1 pto) devolverá la coordenada Y del punto pto.

(nth 2 pto) devolverá la coordenada Z del punto pto, si existe y si no existe devolverá nil.

(MEMBER elemento lista)Supongamos que tenemos una lista como la siguiente:

(setq lst (list “peras” “melones” “sandias” “perros” “plátanos“))

para comprobar si “perros” pertenece a la lista lst se utiliza la función MEMBER.

Con esta función, si el elemento indicado pertenece a la lista devolverá la lista a partir de ese elemento. Por ejemplo:

(member “perros” lst) devolverá (“perros” “plátanos”)

Si el elemento no pertenece a la lista, devolverá nil.

(member “gatos” lst) devuelve nil

Page 113: Autolisp Gera

(SUBST elem_nuevo elem_antiguo lista)Esta función reemplaza un elemento de una lista por su nuevo valor. Por ejemplo, para reemplazar “perros” por “naranjas“:

(subst “naranjas” “perros” lst) devuelve la lista con el elemento que se ha modificado (“peras” “melones” “sandias” “naranjas” “plátanos”). Pero la variable lst sigue almacenando la lista anterior(“peras” “melones” “sandias” “perros” “plátanos”).

Para modificar la lista almacenada en la variable lst tenemos que asignarle el valor devuelto por SUBST:

(setq lst (subst “naranjas” “perros” lst))

(CONS elemento lista)Supongamos que queremos añadir un nuevo elemento “limones” a la siguiente lista:

(setq lst (list “peras” “naranjas” “manzanas“))

Podríamos hacerlo con list, pero sería algo complicado:

(setq lst (list “limones” (car lst) (cadr lst) (caddr lst)))

Para una lista de 3 elementos se puede hacer, pero… ¿Y si tenemos 30 elementos?

La función cons añade un elemento a la lista indicada. El nuevo elemento se sitúa en el primer lugar. Es decir:

(cons “limones” lst) devolverá (“limones” “peras” “naranjas” “manzanas”)

Y al igual que sucedía con SUBST, si sólo hacemos (cons “limones” lst) no estamos asignando la lista resultante a la variable lst. Deberíamos hacerlo así:

(setq lst (cons “limones” lst))

Pero… y si lo que queremos es añadir un elemento al final de la lista? Antes de ver como sería, veamos otra función:

(REVERSE lista)Devuelve la lista que recibe como argumento pero en orden inverso.

(reverse lst) devolverá (“manzanas” “naranjas” “peras” “limones”)

Bien, pues para añadir un elemento al final de una lista podemos utilizar cons y reverse:

Page 114: Autolisp Gera

(setq lst (reverse (cons “plátanos” (reverse lst))))

Veamos como funciona la línea de código anterior:

(reverse lst) devuelve la lista en orden inverso (cons “plátanos” (reverse lst)) añade “plátanos” como primer elemento de la

lista invertida

por último volvemos a invertir el orden de la lista y lo asignamos a la variable lst: (setq lst (reverse(cons “platanos” (reverse lst))))

(ACAD_STRLSORT lista)Esta función devuelve una lista con sus elementos, que deberán ser cadenas de texto, ordenados alfabéticamente. Por ejemplo:

(acad_strlsort lst) devolverá (“limones” “manzanas” “naranjas” “peras” “plátanos”)

(APPEND lista1 [lista2] …)Esta función une dos o más listas y devuelve la lista resultante. Si tenemos dos listas:

(setq lst1 (list “peras” “naranjas” “manzanas“))

(setq lst2 (list “fresas” “limones“))

y que queremos unirlas…

(append lst1 lst2) devolverá (“peras” “naranjas” “manzanas” “fresas” “limones”)

Aplicar funciones a los elementos de una lista

Supongamos que tenemos una lista de puntos:

(setq lstptos (list (list 0.0 0.0) (list 10.0 0.0) (list 10.0 10.0) (list 0.0 10.0)))

Es decir, lstptos es una lista con cuatro elementos correspondientes a los vértices de un cuadrado de lado 10. Supongamos que queremos dibujar un círculo en cada uno de los puntos de lstptos. Hasta ahora podíamos hacerlo así:

(setq i 0 nent (length lstptos))

(while (< i nent)

(setq pt (nth i lstptos))

(command “_.circle” pt 1.0)

Page 115: Autolisp Gera

(setq i (1+ i))

)

La variable i nos servirá como índice o contador en el bucle While, por eso le asignamos inicialmente el valor inicial 0, porque los elementos de una lista se numeran empezando desde cero. Es bastante habitual que los nombres de las variables utilizadas como contadores sean i j k … También asignamos a nent el número de elementos de la lista lstptos, porque sino no sabremos como salir del bucle ni hasta que elemento llegar.

El bucle se ejecutará mientras el contador sea menor que nent es decir, se ejecutará para cada elemento delstptos. La primera línea de código dentro del bucle (setq pt (nth i lstptos)) obtiene el elemento número i delstptos, que es un punto, y a continuación dibuja una circunferencia en él de radio 1.0. Finalmente aumentamos el contador para que pase al siguiente punto (setq i (1+ i)). Esta última línea es muy importante, si no estuviera la variable i sería siempre igual a cero y el bucle no tendría fin. Por lo que dibujaría infinitos círculos en el primer punto de lstptos y daría lugar a un error.

Veamos otro método para dibujar los círculos en los vértices de lstptos:

(while lstptos

(setq pt (car lstptos))

(command “_.circle” pt 1.0)

(setq lstptos (cdr lstptos))

)

En este caso, el bucle se ejecutará mientras tengamos puntos en la lista es decir, mientras lstptos sea distinto de nil. Se define pt como el primer punto de la lista lstptos, se dibuja una circunferencia de radio 1.0 con centro en pt y por último se mueve el contador. Pero, ¿qué contador? Si no existe! Pues, (setq lstptos(cdr lstptos)) eliminamos el primer elemento de la lista lstptos. De modo que lstptos va perdiendo un elemento (punto) cada vez que se ejecuta el bucle. Llega un momento en el que lstptos = ((0.0 10.0)) y al evaluarse (setq lstptos (cdr lstptos)) se asignará a lstptos el valor devuelto por CDR, es decir nil. Con lo cual deja de ejecutarse el bucle.

El inconveniente de este segundo método es que se varía el valor asignado a la variable lstptos, que finalmente valdrá nil. Por lo que la lista de puntos inicial se perderá.

Bien, pero AutoLISP es un excelente lenguaje de programación para trabajar con listas. De modo que tenemos algunos métodos que son mejores, y eso es lo que vamos a ver en este artículo.

(FOREACH variable lista expresion)

Page 116: Autolisp Gera

Esta función permite aplicar una expresión para cada elemento de la lista que recibe como argumento. La variable simboliza a un elemento de dicha lista, por lo que se suele utilizar en la expresión. Por ejemplo:

(foreach p lstptos (command “_.circle” p 1.0))

La línea de código anterior representa el tercer método para dibujar los círculos en los puntos de lstptos. A la variable la llamamos p y la expresión a ejecutar para cada elemento de la lista es: (command “_.circle” p1.0) dónde p es un elemento de la lista.

En caso de tener una lista de cadenas de texto, podria hacerse lo siguiente:

(setq lsttxt (list “Curso” “de” “AutoLISP“))

(foreach p lsttxt (prompt p))

Con lo cual, escribiría todos los textos en la ventana de comandos de AutoCAD. Se ha utilizado el mismo nombre de variable p, pero podría haberse cambiado:

(foreach pepe lsttxt (princ pepe))

Supongamos ahora que tenemos una lista de números:

(setq lst (list 5.0 -1.5 2.6 3.8 9.7))

Para sumar los números podríamos hacer lo siguiente:

(setq i 0 nent (length lst) total 0.0)

(while (< i nent)

(setq num (nth i lst))

(setq total (+ total num))

(setq i (1+ i))

)

Inicialmente definimos la variable total como 0.0, el bucle se ejecutará para cada elemento de lst y se definenum como el número que está en la posición i. Sumamos a total ese número y movemos el contador. Cuando se entra por primera vez en el bucle, num = 5.0 de modo que total = 0.0 + 5.0. Al volver a entrar en el bucle num = -1.5 de modo que total = 5.0 + (-1.5) y así hasta que se llega al último elemento de lst.

También podría hacerse sin emplear contadores, como hicimos antes. Y también podemos hacerlo conFOREACH, veamos:

(foreach p lst (setq total (+ total p)))

Todo lo que antes poníamos en un bucle se pone ahora en una sola línea de código.

(APPLY nombre_función lista)

Page 117: Autolisp Gera

Aplica la función que recibe como argumento a todos los elementos de la lista. El nombre de la función a utilizar en APPLY se indicará precedida por el símbolo ‘ para que AutoCAD interprete que le estamos pasando ese texto tal cual. El ejemplo anterior sería:

(setq total (apply ‘+ lst))

En (apply ‘+ lst) estamos aplicando la función + a todos los elemento de lst, equivale a (+ 5.0 -1.5 2.6 3.8 9.7), y el resultado se lo asignamos a la variable total.

Digamos que ‘+ es el nombre que utilizamos en AutoLISP para hacer referencia a la función +, ya que + es la función propiamente y no su nombre. Prueba lo siguiente en la ventana de comando de AutoCAD:

(list “pepe” + 5.0) y fíjate en lo que devuelve (“pepe” #<SUBR @0244f5a8 +> 5.0)

Y ahora prueba con el literal, es decir con el carácter ‘ delante del +

(list “pepe” ‘+ 5.0) devuelve (“pepe” + 5.0)

¿Entiendes ahora porque ponemos ‘+? Para que no evalúe la función, ya que devolvería #<SUBR @0244f5a8 y nos daría un error.

Veamos un par de ejemplos más:

(apply ‘max lst) devolverá el mayor número de lst

(apply ‘min lst) devolverá el menor número de lst

Si tuviéramos una lista cuyos elementos fueran textos:

(setq lsttxt (list “Curso” “de” “AutoLISP“))

para unir los textos:

(setq txt (apply ‘strcat lsttxt))

De modo que txt = “CursodeAutoLISP” todo junto.

(MAPCAR nombre_función lista1 [lista2]…)Esta función aplica la función de AutoLISP que recibe como argumento a los elementos de las listas. Como así no se va a entender veamos algunos ejemplos:

Supongamos que tenemos dos puntos:

(setq pt1 (getpoint “\nPunto 1: “))

(setq pt2 (getpoint pt1 “\nPunto 2: “))

Los puntos son listas con 2 o 3 elementos, en función de si tienen 2 o 3 coordenadas.

Page 118: Autolisp Gera

Vamos a determinar el vector con origen en pt1 y final en pt2. Tenemos que calcular las coordenadas X Y Z del vector, que son el resultado de restar las respectivas coordenadas X Y Z de pt1 a las de pt2. Podemos obtener el vector así:

(setq vector

(list (- (car pt2) (car pt1))

(- (cadr pt2) (cadr pt1))

(- (caddr pt2) (caddr pt1))

)

)

Siendo:

la coordenada X (- (car pt2) (car pt1))  la coordenada Y (- (cadr pt2) (cadr pt1)) 

la coordenada Z (- (caddr pt2) (caddr pt1))

Bien, pues esto mismo lo podemos hacer con MAPCAR

(setq vector (mapcar ‘- pt2 pt1))

La función que recibe mapcar es - y lo que hace es aplicarla a los elementos de pt2 y pt1, de modo que resta sus coordenadas X, las Y y las Z.

APPLY devuelve un elemento y MAPCAR una lista.

Cálculo del módulo de un vectorVamos a complicar un poco el tema. Si quisiéramos obtener el módulo de un vector tendríamos que calcular la raíz cuadrada de la suma de sus coordenadas al cuadrado:

1. (mapcar ‘* vector vector) devolverá una lista con las coordenadas del vector al cuadrado, ya que las estamos multiplicando por si mismas.

2. Para sumarlas utilizamos APPLY (apply ‘+ (mapcar ‘* vector vector))

3. Para terminar solo nos falta hacer la raíz cuadrada de lo anterior

(setq modulo (sqrt (apply ‘+ (mapcar ‘* vector vector))))

Cálculo del producto escalar de dos vectores

Page 119: Autolisp Gera

Veamos otro ejemplo en el que se combinan APPLY y MAPCAR. Sean v1 y v2 dos vectores vamos a calcular su producto escalar.

(setq v1 (list 10.0 10.0 0.0))

(setq v2 (list 5.0 0.0 0.0))

El producto escalar de los vectores v1 y v2 es la suma de los productos de las coordenadas de v1 por las dev2. Podríamos hacerlo así:

(setq pescalar

(+

(* (car v1) (car v2))

(* (cadr v1) (cadr v2))

(* (cadr v1) (cadr v2))

)

)

Pero resulta más sencillo utilizando MAPCAR y APPLY:

1. Primero multiplicamos las coordenadas de ambos vectores (mapcar ‘* v1 v2)2. y luego las sumamos, de modo que…

(setq pescalar (apply ‘+ (mapcar ‘* v1 v2)))

(LAMBDA (lista_argumentos / variables_locales) expresión1 [expresión2] …)Tal vez el formato de la función LAMBDA recuerde algo a DEFUN.

LAMBDA también se utiliza para definir una función, pero a diferencia de DEFUN la función no se almacena en ningún lugar, en este caso es temporal. Por tanto solo se puede ejecutar donde se defina. Además la función creada no tiene nombre, por lo que tampoco podríamos llamarla desde otra parte de nuestro código.

Utilizarla sola sin APPLY o MAPCAR no tiene sentido.

Supongamos que queremos obtener el punto medio de dos puntos:

(setq pt1 (getpoint “\nPunto 1: “))

(setq pt2 (getpoint pt1 “\nPunto 2: “))

Page 120: Autolisp Gera

Las coordenadas del punto medio serán las coordenadas de pt1 más las de pt2 divididas por 2.0.

Para sumar sus coordenadas: (mapcar ‘+ pt1 pt2)

Bien… pero ahora, ¿Cómo las dividimos por 2.0? Podemos hacer lo siguiente:

(mapcar ‘/ (mapcar ‘+ pt1 pt2) (list 2.0 2.0 2.0))

Donde creamos una lista (list 2.0 2.0 2.0) y dividimos los elementos de (mapcar ‘+ pt1 pt2) entre los elementos de la lista anterior (2.0 2.0 2.0).

Recordemos… (mapcar ‘+ pt1 pt2) devuelve la suma de las coordenadas de pt1 y pt2. Si necesitamos dividirla por 2.0. podemos crear una función que reciba un número y lo divida por 2.0 devolviendo el resultado:

(defun 2/ ( num ) (/ num 2.0))

Y ahora pasar a MAPCAR la nueva función 2/ para que divida cada elemento de (mapcar ‘+ pt1 pt2) por 2.0

(mapcar ’2/ (mapcar ‘+ pt1 pt2))

Pero también podemos hacerlo de otra forma, utilizando la función LAMBDA en lugar de DEFUN. Primero veamos como sería nuestra función definida mediante LAMDA:

(lambda ( num ) (/ num 2.0))

Es muy parecido a lo que hicimos con DEFUN. Pero la función definida mediante LAMBDA no tiene nombre y no se almacena en ningún sitio, es temporal, de modo que no podemos llamarla. ¿Dónde debemos utilizar LAMBDA? Pues directamente en MAPCAR, donde hay que indicar el nombre de la función:

(mapcar ‘(lambda ( num ) (/ num 2.0)) (mapcar ‘+ pt1 pt2))

Por tanto, cuando queremos aplicar APPLY o MAPCAR a una o varias listas y ejecutar una función que no existe en AutoLISP, podemos crearla previamente con DEFUN o utilizar la función LAMBDA para definirla in situ.

Literales y otras funciones de utilidad

(VER)Esta función devuelve una cadena de texto con la versión de AutoLISP que se está ejecutando. Por ejemplo: “Visual LISP 2000 (es)“. Entre paréntesis indica la versión idiomática, en este caso Español.

Page 121: Autolisp Gera

Pantalla de texto y pantalla gráficaEn AutoCAD podemos pasar de pantalla gráfica a la pantalla de texto, y al revés, pulsando la tecla de funciónF2. En AutoLISP también existen algunas funciones para hacerlo directamente desde el código de nuestras rutinas.

(TEXTSCR)Se utiliza para pasar a pantalla de texto y siempre devuelve nil. Se suele emplear cuando se quiere mostrar mucha información en pantalla de texto.

(GRAPHSCR)Pasa a pantalla gráfica y también devuelve nil. Se utiliza para asegurarnos que el usuario está viendo la pantalla gráfica, por ejemplo para indicar un punto. Especialmente se utilizará si antes se ha pasado a pantalla de texto.

(TEXTPAGE)Esta función es análoga a TEXTSCR. Pasa a pantalla de texto y también devuelve nil.

Tal vez te estés preguntando ¿Cuántas funciones nos quedan aún? Pues entre otras cosas, la siguiente función nos servirá para ver las funciones de AutoLISP que hemos visto y las que nos quedan.

(ATOMS-FAMILY formato [lista_simbolos])Esta función devuelve una lista con los símbolos que se han definido en el dibujo actual. ¿Qué es un símbolo? Pues un nombre de variable de AutoLISP, el nombre de una función de usuario que hemos creado y también todos los nombres de las funciones propias de AutoLISP.

El argumento formato puede tener dos valores:

0 para que devuelva una lista con los nombres de los símbolos. 1 para que devuelva una lista, pero siendo sus elementos cadenas de texto.

Veamos ahora algún ejemplo. Al escribir la línea siguiente sabrás cuantas funciones faltan:

(atoms-family 0) esto mostrará una lista con los nombres de todos los símbolos definidos en el dibujo actual.

(atoms-family 1) así los elementos de la lista anterior serán cadenas de texto.

Page 122: Autolisp Gera

En las listas anteriores es difícil encontrar algo. ¿Recuerdas la función acad_strlsort? Permitía organizar alfabéticamente una lista de cadenas de texto.

(acad_strlsort (atoms-family 1)) devolverá la lista anterior ordenada alfabéticamente

Están todas las funciones de AutoLISP, pero hay otras muchas funciones que aparecen en la lista y no son funciones de AutoLISP. Así que no te asustes, que no son tantas.

Recordemos el formato de esta función: (ATOMS-FAMILY formato [lista_simbolos]) y veamos que es eso de la lista de símbolos

Para saber si unas funciones determinadas existen, es decir si están definidas, creamos una lista con sus nombres y se lo pasamos como argumento a atoms-family

(atoms-family 1 (list “car” “cdr“)) devolverá una lista con sus nombres (“CAR” “CDR”)

Aunque lo habitual no es emplear esta función para detectar si están definidas las funciones de AutoLISP, sino para detectar nuestras propias funciones y variables:

(atoms-family 1 (list “car” “cdr” “variable“)) devuelve (“CAR” “CDR” nil) ya que el símbolo “variable” no tiene asociado ninguna función, ni variable de AutoLISP.

Si definimos:

(setq variable 12.5)

(atoms-family 1 (list “car” “cdr” “variable“)) devolverá (“CAR” “CDR” “VARIABLE”) devuelve el nombre de la variable, no su valor.

Si definimos una función de usuario:

(defun 2+ ( numero / ) (+ numero 2.0))

La función 2+ recibe un número y le suma 2.0.

(atoms-family 1 (list “car” “cdr” “2+“)) devolverá (“CAR” “CDR” “2+”)

(QUOTE expresión)Esta función recibe una expresión y devuelve su literal, es decir devuelve la expresión tal cual, sin evaluar.

(quote +) devolverá +

Esto es lo mismo que hacíamos en APPLY y MAPCAR:

(apply ‘+ (list 2.0 3.5 6.8))

pues el apóstrofo ‘ es el diminutivo o el alias de la función QUOTE.

(quote (setq a “texto” b 10.0)) devolverá (SETQ A “texto” B 10.0)

sería lo mismo escribir:

Page 123: Autolisp Gera

‘(setq a “texto” b 10.0)

Pero no podremos escribir esta última línea en la ventana de comandos de AutoCAD, por que el interprete de comandos no detecta el paréntesis en primer lugar y piensa que no es una expresión de AutoLISP sino un comando de AutoCAD. Podemos utilizar un truco para evaluar la expresión desde la ventana de comandos:

(progn ‘(setq a “texto” b 10.0))

PROGN en realidad no hace nada, simplemente nos servía para salvar la limitación de IF de indicar más de 1 expresión, ya que evalúa las expresiones que contiene y devuelve el resultado de la última expresión evaluada. En este caso nos sirve para contener la expresión de AutoLISP anterior.

Ahora si devolverá (setq A “pepe” B 10.0). Pero no hemos asignado valores a las variables, ya que (setq A “pepe” B 10.0) no se ha evaluado.Puedes hacer la prueba escribiendo !a o !b en la ventana de comandos de AutoCAD.

(quote (15.0 10.6 9.2)) devolverá (15.0 10.6 9.2) es decir, devuelve una lista. También funcionaría con ‘(15.0 10.6 9.2)

Por tanto en lugar de:

(apply ‘+ (list 2.0 3.5 6.8))

podemos poner:

(apply ‘+ (quote (2.0 3.5 6.8)))

y también:

(apply ‘+ ‘(2.0 3.5 6.8))

De modo que podemos usar QUOTE y ‘ para crear listas. Pero con excepciones, ya que si hacemos:

(setq a 2.0)

(apply ‘+ ‘(a 3.5 6.8)) indicará: ; error: tipo de argumento erróneo: numberp: A

a es el nombre de una variable, es un símbolo, cuya variable tiene asociado el valor 2.0

(apply ‘+ (list a 3.5 6.8)) esto si funcionará porque (list a 3.5 6.8) devolverá (2.0 3.5 6.8), LIST se evalúa pero QUOTE no evalúa la expresión que recibe.

Resumiendo: Podemos crear listas con QUOTE o con ‘ pero siempre que conozcamos los elementos de dichas listas, y que estos sean valores concretos no determinados a partir de expresiones o almacenados en variables.

Algunos ejemplos más:

(setq maximo (apply (quote max) (quote (10.5 15.2 9.3))))

Page 124: Autolisp Gera

(setq minimo (apply ‘min ‘(10.5 15.2 9.3)))

(foreach p ‘((0.0 0.0 0.0) (10.0 10.0 0.0)) (command “_.circle” p 1.0))

(setq vector (mapcar ‘- ‘(10.0 10.0 0.0) ‘(5.0 0.0 0.0)))

(setq ptomed (mapcar ‘(lambda ( num ) (/ num 2.0)) (mapcar ‘+ ‘(10.0 10.0 0.0) ‘(5.0 0.0 0.0))))

(EVAL expresión)Esta función evalúa la expresión que recibe.

(eval 2.5) devuelve el resultado de evaluar 2.5, es decir devuelve 2.5

(eval “Soy una cadena de texto“) devolverá “Soy una cadena de texto”

Pero veamos un ejemplo algo más complicado:

(setq a 15.5)

(setq b (quote a))

¿Qué valor tendrá asignado b?

(quote a) es el nombre de la variable a, es decir el símbolo. Así que b tendrá asociado el nombre de la variable a.

(+ b 10.0) dará un error

(eval b) devolverá 15.5 de modo que podemos hacer lo siguiente:

(+ (eval b) 10.0) devolverá 25.5

(eval ‘(+ 10.0 5.5)) devolverá 15.5 ya que ‘(+ 10.0 5.5) devuelve (+ 10.0 5.5) y eval, lo evalúa.

(READ texto)Esta función lee el texto que recibe y devuelve la primera palabra pero como un literal, un símbolo, no como una cadena de texto.

(read “AutoLISP“) devuelve AUTOLISP

(read “Curso de AutoLISP“) devolverá CURSO

(read “(15.2 9.3 15.5)“) en este caso devolverá (15.2 9.3 15.5) porque al detectar el paréntesis lo considera un mismo término. Es algo similar a escribir en la ventana de comandos de AutoCAD, si no se pone un paréntesis delante no dejará escribir espacios en blanco. Pues este es otro método para crear una lista, por tanto:

Page 125: Autolisp Gera

(apply ‘max (read “(15.2 9.3 15.5)“)) devolverá el máximo de la lista de números indicados

Y que pasa si hacemos:

(setq txt “(setq a 5.5)“)

(read txt) devolverá (setq a 5.5)

y ahora podemos evaluarlo con EVAL

(eval (read txt)) devolverá 5.5 y asigna a la variable a el valor 5.5

¿Para qué sirve esto? Por ejemplo para solicitar al usuario una expresión de AutoLISP y evaluarla:

(setq txt (getstring T “\nExpresión de AutoLISP: “))

(setq valor (eval (read txt)))

En este caso asignamos a valor el resultado de evaluar una expresión de AutoLISP introducida por el usuario.

(SET literal_de_símbolo expresión)Esta función es muy parecida a SETQ, se diferencia en que espera el literal de un símbolo. Veamos algunos ejemplos:

(setq num1 5.0) asigna a la variable num1 el valor 5.0

(set num2 5.5) da un error, ya que espera un literal

(set ‘num2 5.5) asigna a la variable num2 el valor 5.5

Si probamos:

(setq (read “num1“) 5.0) nos da un error, ya que SETQ no acepta una expresión como símbolo.

Sin embargo SET si lo acepta:

(set (read “num2“) 15.0) asigna a la variable num2 el valor 15.0

Carga automática de los archivos de AutoLISP

Page 126: Autolisp Gera

Carga automática de los archivos de AutoLISPAutoCAD carga automáticamente dos archivos de AutoLISP, si es que existen y se encuentran en los directorios de soporte. Se trata del ACAD.LSP y el ACADDOC.LSP.

El archivo ACAD.LSP se carga al iniciar AutoCAD y el ACADDOC.LSP se carga siempre que se abre un dibujo, o se crea un dibujo nuevo. De modo que las funciones contenidas en el ACAD.LSP tan sólo estarán cargadas en el dibujo que se abre al iniciar AutoCAD, mientras que las funciones contenidas en el ACADDOC.LSP estarán cargadas en todos los dibujos.

Lo lógico será entonces guardar nuestras funciones en el ACADDOC.LSP y no en el ACAD.LSP.

El ACAD.LSP se utilizará tan solo para almacenar aquellas funciones que nos interese ejecutar al cargar AutoCAD. Por ejemplo, podemos utilizar el archivo ACAD.LSP para mostrar una imagen, foto, al iniciar AutoCAD.

Si tenemos alguna rutina que se utilice mucho, o que se suele ejecutar en todos los dibujos la meteremos en el ACADDOC.LSP

¿Qué rutinas meteremos en el ACADDOC.LSP? Conviene que no sean demasiadas, para que dicho archivo sea más manejable y además para no ocupar demasiado espacio en la memoria del ordenador. Por tanto, solo incluiremos en el ACADDOC.LSP las rutinas más empleadas. Por ejemplo una función de tratamiento de errores, o las funciones GAR y RAG que se utilizan bastante, y además son bastante pequeñas.

¿Qué pasa si metemos también nuestra función C:CIRCPERI? Pues no pasaría nada pero… ¿Vas a dibujar circunferencias dadas por su perímetro en “todos” los dibujos? no creo, por eso no merece la pena añadirla al ACADDOC.LSP, ya que si hacemos lo mismo con todas nuestras rutinas el archivo ACADDOC.LSP tendría un tamaño descomunal.

Podemos guardar la rutina CIRCPERI en un archivo independiente y cargarlo desde el ACADDOC.LSP. En el caso de la rutina CIRCPER, podemos guardarla en el archivo CIRCPERI.LSP, dentro de uno de los directorios de soporte de AutoCAD, e incluir la siguiente línea en el ACADDOC.LSP:

(load “circperi.lsp” (alert “Archivo Circperi.lsp no encontrado“))

De este modo tenemos la rutina CIRCPERI en un archivo independiente, lo que nos soluciona parte del problema, ya que el archivo ACADDOC.LSP será bastante corto y si queremos modificar la rutina CIRCPERI tan solo tenemos que manipular un archivo en el que únicamente está definida dicha función.

Pero seguimos teniendo algunos problemas: Si nuestra colección de rutinas es muy extensa tenemos que añadir una línea de código como la anterior para cada rutina, lo que

Page 127: Autolisp Gera

se traducirá en un archivo ACADDOC.LSP bastante grande y difícil de manipular. Además, el mayor inconveniente es que todas nuestras rutinas se cargarían en memoria automáticamente para cada archivo de dibujo, con lo que estaremos sobrecargando la memoria del ordenador de forma innecesaria.

(AUTOLOAD archivo lista_comandos)La función AUTOLOAD es similar a LOAD, también nos permite cargar archivos de AutoLISP pero sólo aquellos archivos que contengan comandos, por ejemplo C:CIRCPERI pero no servirá para archivos en los que solo tengamos funciones como GAR y RAG.

¿Qué ventaja tiene el utilizar AUTOLOAD en lugar de LOAD? Al utilizar AUTOLOAD los archivos no se cargan automáticamente, simplemente se predispone a AutoCAD para que los cargue en cuanto se ejecute uno de los comandos indicados como argumentos en la lista de comandos.

Por ejemplo, si tenemos un archivo con 3 comandos:

(defun C:comando1 ( / ) ….)

(defun C:comando2 ( / ) ….)

(defun nosoyuncomando ( / ) ….)

(defun C:comando3 ( / ) ….)

En el archivo ACADDOC.LSP podríamos añadir la siguiente línea:

(autoload “archivo.lsp” ‘(“comando1” “comando2“))

Al iniciar un dibujo, se carga el ACADDOC.LSP y se evalúa la línea anterior, pero archivo.lsp no se cargará hasta que se ejecute el comando1 o el comando2. Sin embargo no se cargará si ejecutamos el comando3, ya que no lo hemos incluido en la lista de comandos. Además, al ejecutar uno de los dos comandos anteriores se carga el archivo, de modo que la función nosoyuncomando también se cargará, al igual que elcomando3.

¿Y qué pasa con los archivos de AutoLISP que no tienen comandos, es decir en los que solo hay funciones? Pues tendremos que cargarlos con LOAD, con lo cual se cargarían todos directamente en la memoria y si tenemos bastantes funciones seguimos teniendo el mismo problema que antes.

¿Cómo podemos solucionarlo? Pues cargando las funciones solo cuando hacen falta. Por ejemplo, supongamos que en el comando C:CIRPERI se utiliza la función RAG. Tenemos dos opciones:

Page 128: Autolisp Gera

1. Incluir la función RAG en el archivo Circperi.lsp. De este modo al cargarse el archivo se cargará la función RAG. Esto se suele hacer para las funciones que sólo se utilizan en un comando determinado.

2. Pero si la función RAG deseamos utilizarla en otros comandos, es mejor utilizar el siguiente método: Incluir la función RAG en un archivo independiente Rag.lsp y añadir la siguiente línea de código dentro del archivo Circperi.lsp: (load “Rag.lsp” (alert “Archivo Rag.lsp no encontrado“))

En el segundo modo, el archivo Circperi.lsp se cargará cuando se ejecute uno de los comandos indicados en la función Autoload del archivo ACADDOC.LSP. Y al cargarse el archivo Circperi.lsp se cargará mediante la función Load el archivo Rag.lsp. Utilizando este método podemos utilizar una misma función en múltiples rutinas, tan solo debemos asegurarnos de que dicha función esté definida, es decir que se ha cargado el archivo en el que se encuentre.

Los archivos ACAD.LSP y ACADDOC.LSP no tienen porque existir. Si no existen pueden crearse, teniendo en cuenta que se deben guardar en uno de los directorios de soporte de AutoCAD. En caso de que ya existan, se pueden editar para incluir el código deseado. Conviene hacer una copia de seguridad de estos archivos porque muchos programadores crean sus propios archivos ACAD.LSP y ACADDOC.LSP de modo que al instalar un módulo o aplicación para AutoCAD, podéis sobreescribir vuestros archivos.

Existen otros dos métodos para cargar automáticamente rutinas de AutoLISP. El primero consiste en utilizar la opción disponible en el menú de AutoCAD “Herr –> AutoLISP –> Cargar” ya que en el letrero de dialogo que aparece se pueden cargar rutinas y se pueden seleccionar las rutinas que se desean cargan al inicio.

El tercer método para cargar automáticamente las rutinas de AutoLISP es editando los menús de AutoCAD, pero esto lo veremos más adelante.

Ejecución automática de código de AutoLISPHemos visto que el archivo ACADDOC.LSP se carga automáticamente en todos los dibujos pero ¿Cómo podemos ejecutar automáticamente una función al iniciarse un dibujo?

Supongamos que tenemos definida la función GAR dentro del archivo ACADDOC.LSP:

(defun GAR …)

Para ejecutarla, tan sólo debemos añadir en dicho archivo la siguiente línea de código:

(GAR)

En caso de que dicha función tenga argumentos, estos deben indicarse:

Page 129: Autolisp Gera

(GAR 3.141592)

¿Cómo ejecutaríamos automáticamente el comando C:CIRCPERI?

Una vez cargado el comando, para ejecutarlo desde la ventana de comandos de AutoCAD podemos escribir directamente su nombre CIRCPERI para ejecutarlo. Sin embargo, desde un archivo de AutoLISP no podemos ejecutarlo así. Tenemos que hacerlo de esta otra forma:

(C:CIRCPERI)

De modo que podríamos incluir en el archivo ACADDOC.LSP las dos siguientes líneas de código:

(load “circperi.lsp” (alert “Archivo Circperi.lsp no encontrado“)) ; Carga el comando

(C:CIRCPERI) ; Ejecuta el comando

¿Sería mejor utilizar AUTOLOAD en lugar que LOAD en el ejemplo anterior? Pues no. Utilizar AUTOLOADno tendría mucho sentido, puesto que al ejecutar el comando el archivo en el que esté definido se cargaría, por tanto podemos cargarlo ya antes.

Existe otro método para ejecutar código directamente. Se trata de escribirlo directamente, es decir sin meterlo dentro de ninguna función o comando. Por ejemplo, si incluimos las siguientes líneas de código en el archivo ACADDOC.LSP nos permitirá dibujar un circulo dado su centro y su perímetro:

(setq pto (getpoint “\nCentro del círculo: “))

(setq peri (getdist pto “\nPerímetro: “))

(command “_.circle” pto (/ peri (* 2.0 PI)))

Pero en este caso, el código anterior solo se ejecuta una vez. Si queremos dibujar otro círculo dado su perímetro, no tendríamos la función CIRCPERI definida.

¿Para qué se suele utilizar este método?

Por ejemplo, para mostrar mensajes informativos o de bienvenida:

(alert “¿Estas seguro de que quieres utilizar AutoCAD?“)

(alert “¿Estas realmente seguro?“)

(alert “¿Seguro, seguro?“)

Aunque no os aconsejo que utilicéis este ejemplo, os cansaríais de él a los 5 minutos.

Además de mensajes de bienvenida podéis hacer otras cosas más útiles, como asignar valores iniciales a algunas variables:

(setq directorio “c:\\rutinas\\“)

Page 130: Autolisp Gera

También podéis modificar el valor de alguna variable de sistema de AutoCAD:

(setvar “osmode” 7)

S::STARTUPExiste otro método para ejecutar código automáticamente. Hemos visto que AutoCAD utiliza una función de tratamiento de errores por defecto que se llamaba *error* y también hemos visto que podíamos redefinirla creando nuestra propia función de tratamiento de errores. Bien, pues AutoCAD también tiene una función interna que se ejecuta automáticamente se trata de S::STARTUP.

El que las funciones *error* y S::STARTUP tengan estos nombres tan raros es para evitar que a alguien se le ocurra denominar así a alguna función de otro tipo.

Para definir la función S::STARTUP se utiliza DEFUN, al igual que para cualquier otra función.

(defun S::STARTUP ( / )

(setq directorio “c:\\rutinas\\“)

)

La función S::STARTUP podemos utilizarla para los mismos ejemplos que se daban antes.

Por último, para terminar el tema, un consejo: Al programar hay que tener bastante cuidado para no cometer errores, ya que el omitir un simple paréntesis o unas comillas, por ejemplo, modificaran totalmente nuestras funciones. Cuando además estas funciones se van a ejecutar automáticamente, como en los ejemplos que se han expuesto, la precaución al programar debe ser máxima.

Operaciones con archivos

Antes de comenzar con el tema de lectura y escritura de archivos, veamos una pequeña rutina: CARGALISP

CARGALISP recibirá una lista como la siguiente: ((“c:\\rutinas\\lisp1.lsp” (“gar” “rag”)) (“c:\\rutinas\\lisp2.lsp” (“inverso” “tg”)))

En la que cada elemento es a su vez otra lista formada por el nombre de un archivo de AutoLISP (con su ruta, si es necesario) y una lista con los nombres de las funciones (o variables globales) definidas en dicho archivo. Por ejemplo, en el caso anterior se supone

Page 131: Autolisp Gera

que en el archivo “c:\\rutinas\\lisp1.lsp” están definidas las funciones “gar” y “rag” y que en el archivo “c:\\rutinas\\lisp2.lsp” están definidas las funciones “inverso” y “tg“.

CARGALISP cargará los archivos de AutoLISP indicados si no estaban definidas, o cargadas que es lo mismo, las funciones indicadas para cada archivo.

(defun CARGALISP ( lst / )

(while lst

(if (not (apply ‘and (atoms-family 1 (cdar lst))))

(progn

(load (caar lst))

(prompt (strcat “\nCargando archivo “ (caar lst) “…“))

)

)

(setq lst (cdr lst))

)

)

Tal como está la macro funciona perfectamente. Pero puede producirse un pequeño error. ¿Qué pasa si no existe, o no se encuentra, el archivo lisp1.lsp o cualquiera de los archivos de la lista que reciba CARGALISP?

(FINDFILE archivo)Esta función nos permite comprobar la existencia de un archivo. Si el archivo existe devuelve su nombre y si no existe, o no lo encuentra en la ruta indicada, devolverá nil.

En caso de que no se indique la ruta en la que debe buscar el archivo, lo buscará en los directorios de soporte de AutoCAD.

(findfile “c:\\autoexec.bat“) debería devolver “c:\\autoexec.bat“, suponiendo que vuestro PC tiene Autoexec.bat, claro…

(findfile “c:\\noexisto.bat“) debería devolver nil

FINDFILE en realidad no hace nada, tan solo se utiliza para comprobar la existencia de un archivo. Entonces, ¿Cuando se utilizará FINDFILE? Pues os voy a poner varios ejemplos en los que se suele utilizar:

1. Antes de cargar un archivo con LOAD o AUTOLOAD2. Antes de abrir un fichero de texto, ya sea para leerlo o escribir en él.

Page 132: Autolisp Gera

3. Antes de “abrir” un archivo de dibujo en AutoCAD.

4. Antes de cargar y utilizar un archivo DCL (Letrero de dialogo) en AutoLISP.

Por tanto, deberíamos modificar el código de la función CARGALISP para comprobar la existencia de los archivos a cargar.

(defun CARGALISP ( lst / )

(while lst

(if (not (apply ‘and (atoms-family 1 (cdar lst))))

;; Comprueba si todas las funciones del primer elemento de la lista

;; están cargadas

(if (not (findfile (caar lst)))

(alert (strcat “No se ha encontrado el archivo ” (caar lst)))

;; No se encuentra el archivo

(progn

(load (caar lst))

;; Carga el archivo

(prompt (strcat “\nCargando archivo ” (caar lst) “…“))

;; Indica que se ha cargado el archivo

)

;; Se encuentra el archivo

)

)

(setq lst (cdr lst))

;; Pasa al siguiente elemento de la lista

)

;; Para cada elemento de la lista

)

Page 133: Autolisp Gera

(GETFILED titulo_letrero archivo_defecto extensión_defecto modo)Esta función nos permitirá seleccionar un archivo, ya veremos más adelante como seleccionar varios archivos. GETFILED muestra un letrero de gestión de archivos típico de Windows.

Podemos pasar a GETFILED el título del letrero, el archivo seleccionado por defecto y la extensión de archivos que se buscará por defecto. GETFILED devuelve el nombre y ruta del archivo seleccionado.

El argumento modo es de tipo binario y ofrece los siguientes valores:

1 –> Para designar un archivo nuevo, es decir, que no exista. 2 –> Desactiva la casilla “Teclearlo”.

4 –> Permite indicar cualquier extensión.

8 –> Devuelve el nombre del archivo, sin la ruta

(getfiled “Selecciona un archivo” “c:\\autoexec.bat” “bat” 0)

No pasa nada al pulsar en Abrir, ya que no se abre el archivo. GETFILED tan solo nos deja seleccionarlo y devuelve su nombre.

(getfiled “Selecciona un archivo nuevo” “” “” 1)

Leer y escribir archivos de texto

AutoLISP nos permite leer y escribir archivos de texto ASCII. Al utilizar archivos de texto en nuestras rutinas debemos siempre seguir los siguientes pasos:

1. Comprobar si existe el archivo.2. Abrir el archivo.

3. Leer o escribir en el archivo.

4. Cerrar el archivo.

Page 134: Autolisp Gera

(OPEN archivo modo)Esta función nos permite abrir un archivo de texto y devuelve un “descriptor de archivo“.

¿Qué es un descriptor de archivo? Es algo similar a un canal por el que se comunica AutoCAD con dicho archivo. Podemos abrir varios archivos, es decir abrir varios canales de comunicación, de modo que al leer o escribir en un archivo, tenemos que saber cual es el canal de comunicación por el que vamos a recibir o enviar datos, es decir necesitamos conocer el descriptor del archivo.

Hay tres formas de abrir un archivo de texto, en función de lo que se quiera hacer a continuación con dicho archivo. El argumento modo es el encargado de diferenciar estas tres formas distintas de abrir archivos:

Podemos abrir un archivo para leerlo –> modo “r” Podemos abrir un archivo de texto para escribir en él comenzando desde la

primera línea –> modo “w”

Podemos abrir un archivo de texto para escribir en él a partir de la última línea –> modo “a”

Para abrir el archivo autoexec.bat en modo lectura:

(open “c:\\autoexec.bat” “r“)

Devuelve #<file “c:\\autoexec.bat”> es decir, el descriptor del archivo o nil si el archivo no existe.

Aunque en la línea anterior se abre el archivo autoexec.bat en modo lectura, luego no podríamos hacer nada con él ya que no hemos guardado el descriptor de archivo. Es decir, no podemos decirle a AutoCAD que lea texto por el canal de comunicación que hemos abierto, ya que no conocemos el descriptor del archivo. Incluso tampoco podríamos cerrarlo y quedará abierto en la memoria hasta que se cierre la sesión de AutoACD. ¿Cómo se debe utilizar entonces la función OPEN?

(setq darch (open “c:\\autoexec.bat” “r“))

De este modo el valor devuelto por OPEN, el descriptor de archivo, se almacena en la variable darch.

Antes de ver como leer o escribir en los archivos de texto, veamos como tendriamos que cerrarlos.

(CLOSE descriptor_archivo)Cierra el archivo cuyo descriptor se indica y devuelve nil. Fíjate en lo importante que es guardar el descriptor del archivo en una variable, ya que si no lo hacemos no sólo no podremos leer o escribir en el archivo, tampoco podremos cerrarlo.

Page 135: Autolisp Gera

(close darch)

Hay que tener una cosa en cuenta al trabajar con archivos de texto: Al abrir un archivo de texto debemos indicar el modo (lectura, escritura, o adicción) de modo que debemos saber de antemano lo que vamos a hacer con el archivo, y SÓLO podremos hacer una cosa, o leer o escribir. Aunque podemos abrir un archivo en modo escritura, escribir en él, cerrarlo, abrirlo en modo lectura, leer y volver a cerrarlo.

Otra cuestión de especial interés es que si abrimos un archivo de texto existente en modo escritura “w“, nos habremos cargado todo lo que tenía anteriormente dicho archivo. Así que mucho cuidado con los archivos que se abren en modo escritura.

Escritura de archivos de textoPara crear un archivo de texto debemos abrirlo en modo escritura:

(setq darch (open “c:\\nuevo.txt” “w“))

Devuelve #<file “c:\\nuevo.txt”> el descriptor del archivo abierto, que se almacena en la variable darch.

También podemos abrir el archivo en modo aditivo, para continuar escribiendo a partir de la última línea de texto del archivo.

Bien, ya tenemos abierto nuestro archivo de texto, vamos a escribir en él:

(PRIN1 [expresión [descriptor_archivo]])Esta función escribe una expresión en el archivo cuyo descriptor se indique. Si no se indica el descriptor de archivo, la expresión se escribirá en la ventana de comandos de AutoCAD. Veamos algunos ejemplos:

(setq a 5.5 b “Curso de AutoLISP“)

(prin1 a) escribirá el valor de la expresión a en la ventana de comandos de AutoCAD, es decir, escribirá 5.5

Si ejecutas las dos líneas de código anteriores desde la ventana de comandos de AutoCAD, veras que (prin1a) parece devolver 5.55.5 en realidad devuelve 5.5 pero el eco de mensajes, repite el valor devuelto por la expresión (prin1 a) es decir 5.5 Por eso, aparece 5.55.5

(prin1 b darch)

Escribirá en “Curso de AutoLISP” con las comillas incluidas en el archivo C:\Nuevo.txt.

Fíjate que PRIN1 puede escribir tanto cadenas de texto como números. Sin embargo la función PROMPT tan sólo puede recibir como argumento una cadena de texto.

(prin1 ‘a) escribe A

Page 136: Autolisp Gera

(prin1 (+ 15 5.5)) escribe 20.5

Hemos indicado una expresión como argumento, si utilizamos PROMPT en lugar de PRIN1 dará un error.

(prin1 ‘(+ 15 5.5)) escribe (+ 15 5.5)

Si no se indica la expresión a escribir, escribe una cadena nula

(prin1)

Por eso se suele emplear como última expresión de los comandos, para que la salida de nuestras rutinas sea limpia y no se vea el eco de mensajes de la última expresión evaluada.

(prin1 (strcat “\t” b)) devuelve “\tCurso de AutoLISP”

PRIN1 no entiende los caracteres de control como “\n” “\t” etc.

(PRINT [expresión [descriptor_archivo]])Esta función es muy parecida a PRIN1, veamos en que se diferencian.

(progn (prin1 a) (prin1 a)) escribe 5.55.5

(progn (print a) (print a)) escribe 5.5 pasa a otra línea y escribe 5.5

Es decir, PRINT salta de línea antes de escribir la expresión indicada. PRINT escribe la expresión en una línea nueva.

(print) devuelve una cadena nula, por eso también se emplea como última expresión de los comandos

(print (strcat “\t” b)) devuelve “\tCurso de AutoLISP“, es decir PRINT tampoco entiende los caracteres de control.

Por supuesto, al igual que sucede con PRIN1 si se indica un descriptor de archivo en lugar de escribir en la ventana de comandos de AutoCAD lo hará en un archivo.

(PRINC [expresión [descriptor_archivo]])Esta función también es muy parecida a las anteriores.

(progn (princ a) (princ a)) escribe 5.55.5

(princ) devuelve una cadena nula, por eso también se emplea como última expresión de los comandos.

(princ (strcat “\t” b)) ahora escribe “Curso de AutoLISP” pero tabulado.

Por tanto, PRINC se diferencia de las anteriores en que si interpreta el significado de los caracteres de control.

Page 137: Autolisp Gera

Al igual que las funciones anteriores, si se indica un descriptor de archivo escribirá en dicho archivo en lugar de hacerlo en la ventana de comandos de AutoCAD.

(princ “\nBienvenido al curso… ” darch)

(WRITE-CHAR código_ASCII [descriptor_archivo])Esta función permite escribir un carácter  recibe como argumento su código ASCII. Si se indica el descriptor de archivo lo escribirá en el archivo y sino lo escribirá en la ventana de comandos de AutoCAD.

(write-char 65) escribe A.

Es lo mismo que escribir (write-char (ascii “A“))

(WRITE-LINE texto [descriptor_archivo])Esta función escribe una línea de texto entera. El primer argumento debe ser una cadena de texto, no una expresión. Y si se indica un descriptor de archivo, escribirá la línea de texto en el archivo, en caso contrario la escribe en la ventana de comandos de AutoCAD.

(write-line “Curso de AutoLISP“)

También se puede escribir en un archivo indicando el descriptor correspondiente

(write-line “Muchas gracias” darch)

Ahora podemos cerrar el archivo de texto que hemos abierto

(close darch)

Lectura de archivos de textoPara leer un archivo de texto debemos abrirlo en modo lectura y guardar su descriptor en una variable que podamos utilizar después:

(setq darch (open “c:\\nuevo” “r“))

(READ-CHAR [descriptor_archivo])Lee un carácter del archivo cuyo descriptor se indica y devuelve su código ASCII.

(read-char darch) devuelve 34, que es el código ASCII del primer caracter del archivo de texto, que es unas comillas ”

Si no se indica el descriptor, lo lee de la ventana de comandos de AutoCAD.

(read-char) espera a que introduzcas un caracter y devolverá su código ASCII

(READ-LINE [descriptor_archivo])

Page 138: Autolisp Gera

Esta función lee una línea del archivo de texto indicado.

(read-line darch) devolverá “Curso de AutoLISP\””

Observa que las comillas iniciales del archivo ya las habíamos leído con la función anterior read-char.

Al leer un archivo de texto vamos avanzando en él, de modo que si volvemos a escribir la linea anterior

(read-line darch) devolverá “Bienvenido al curso… Muchas gracias”

Esta es la última línea de nuestro archivo así que si volvemos a repetir la línea anterior

(read-line darch) devolverá nil

De este modo sabremos que hemos llegado al final del archivo y podremos cerrarlo

(close darch)

Si intentamos volver a leer ahora en el archivo obtendremos un error.

Si no se indica el descriptor de archivo, la leerá de la ventana de comandos de AutoCAD.

(read-line) escribe una palabra o frase y devolverá una cadena de texto con lo que has escrito.

Como ya adelantó hace unos días nuestro amigo Gabriel, empezaremos hablando de algunos caracteres especiales básicos en Autolisp, no sin antes aclarar que la mayoría de comentarios y notaciones empleadas a partir de ahora han sido tomadas de los libros cuya bibliografía paso a detallar, y que recomiendo le echéis un vistazo: Autor: Jose Antonio Tajadura y Javier López Tit: Autolisp 12,13,14 Edit: Mc Graw Hill Autor:Reinaldo togores y César Otero Tit: Programación en Autocad con Visual Lisp Ed.: Mc Graw Hill 

1º Punto y coma: ; Sirve para añadir comentarios o aclaraciones que nos ayuden a entender mejor nuestra rutina. Todo lo que vaya detrás del punto y coma, en realidad podríamos borrarlo y el programa no sufriría alteraciones. Así que este carácter sólo lo usaremos para esto. 2º Paréntesis: ( ) Debe haber el mismo número de paréntesis de apertura que de cierre. De lo contrario se producirá un error. Los utilizaremos para preceder cualquier comando de Autolisp y para dar fin a dicho comando. 3º Comillas: " " Se utilizan para encerrar expresiones de texto que queremos que aparezcan en la pantalla, ya sea en la línea de comando o en una ventana. Todo lo que esté entre comillas será considerado como una cadena de texto, incluso los paréntesis, comas, punto y comas.... Como los paréntesis, debe haber un número par de comillas. 4º Punto: . Se usa como punto decimal. 

Page 139: Autolisp Gera

5º Apóstrofo: ‘ Equivale al comando (QUOTE). Devuelve el literal de la expresión. 6º Contrabarra: \ Dentro de una cadena de texto podemos incluir una contrabarra seguida de uno de los siguientes caracteres: \n: Retorno de carro, nueva línea \r: Return \t: tabulador Es decir. Si escribimos: (GETPOINT pt "\nSeñala un punto") , cuando Autolisp evalúe esta expresión, antes de escribir "Señala un punto" en la línea de comando, hará un salto de carro para que no aparezcan dos o más expresiones distintas, unas a continuación de otras. 7º Cierre admiración: ! Sirve para extraer desde la línea de comandos, el valor de una variable. Ej.: (SETQ radio 5.639) Si tecleamos !radio en la línea de comandos nos aparecerá 5.639 

ACLARACIONES *Autolisp no distingue entre mayúsculas y minúsculas. *Es conveniente usar el nombre de las órdenes de Autocad en inglés. Si trabajamos con Autocad español y queremos saber el nombre en inglés tecleamos en la línea de comando: (GETCNAME "orden en catellano") Ej.: (GETCNAME “texto”) y aparece "_text" *Autolisp siempre trabaja en radianes *PI es el número 3.1415926....., por lo que ninguna variable podrá llamarse PI. *T es el símbolo de True, cierto, por lo que ninguna variable podrá llamarse T. *nil es el símbolo de falso, por lo que ninguna variable podrá llamarse nil. Siempre aparecerá en minúsculas, nunca NIL. 

(DEFUN <simb> <arg>) DEFINIR FUNCIONES Las distintas funciones que forman una rutina se definen mediante el comando (DEFUN <simb> <arg>) Dentro de una rutina podrá haber decenas de funciones. Lo que suele hacerse es crear una función principal, desde la cual se irán llamando al resto de funciones secundarias. Es como si tuviésemos varias rutinas dentro de otras. <simb> es el nombre de nuestra función <arg> es el nombre de las variables que vamos a tener dentro de esta función Importante: Las variables pueden ser locales o globales. Esto quiere decir que: Si son globales, podremos seguir utilizándolas fuera de esta función. Si son locales, sólo tendrán valor dentro de esta función. Tanto unas como otras van entre paréntesis. Las locales van precedidas de una barra / Si ponemos un paréntesis sin nada (), daremos por supuesto que todas son globales. Hay que tener en cuenta que en rutinas muy largas, donde existen muchas variables, y donde utilizamos otras rutinas, cuantas más variables globales tengamos, más lentos pueden ser los cálculos. Una ver gargada una rutina, para ejecutarla en otras ocasiones dentro de la misma sesión de Autocad sin tener que volver a cargarla, debemos añadir c: delante del nombre de la función, para que, tecleando dicho nombre en la línea de comando ya arranque de nuevo. 

Page 140: Autolisp Gera

(SETQ <simb1> <expr1> <simb2> <expr2>.....) ATRIBUIR VALORES 

Pues eso, sirve para atribuir valores a una variable. 

Ej: (SETQ radio 5 x 155.36 y 785.961 nombre "Soy un monstruo") Si tecleamos esto en la línea de comandos y luego vamos tecleando sucesivamente: !radio aparece 5 !x aparece 155.36 !y aparece 785.961 !nombre aparece "Soy un monstruo" 

(PROMPT <mensaje>) ESCRIBE MENSAJE Escribe un mensaje en la línea de comandos 

(TERPRI) SALTA A UNA NUEVA LINEA 

(GETPOINT <punto> <mensaje>) INTRODUCE UN PUNTOBien mediante señalamiento en pantalla, o bien mediante teclado. Ej.: (SETQ pt (GETPOINT "\nIntroduce un punto:")) Después de introducir un punto, sus coordenadas se almacenan en la variable pt. 

(COMMAND <arg>) EJECUTA UNA ORDEN DE AUTOCAD Decir antes de nada que es recomendable utilizar el nombre de la orden en inglés, precedido de un guión bajo. Así, independientemente de la versión de Autocad y del idioma, salvo en casos excepcionales, nuestra rutina funcionará siempre. Ej.: (COMMAND "_line" pt '(150 120) "") En este caso dibuja una línea desde el punto pt, cuyas coordenadas ya habrán sido determinadas antes, hasta el punto de coordenadas x=150 e y=120. El nombre de la orden debe ir siempre entre comillas, así como cualquier opción propia de la orden, como por ejemplo el "enter" final. 

Ejemplo general: Copiar esta rutina en el editor de Visual Lisp. 

Código:;;;;;;;;;;;;Rutina para dibujar tres líneas desde un punto. (DEFUN c:dib_lineas ( / pt1 pt2 pt3 pt4) ;(DEFUN c:dib_lineas ()     (PROMPT "\nEste programa dibuja tres línas desde un punto")     (SETQ pt1 (GETPOINT "\nPrimer punto: "))     (SETQ pt2 (GETPOINT "\nSegundo punto: "))     (COMMAND "_line" pt1 pt2 "")     (SETQ pt3 (GETPOINT "\nTercer punto: "))     (COMMAND "_line" pt1 pt3 "")     (SETQ pt4 (GETPOINT "\nCuarto punto: "))     (COMMAND "_line" pt1 pt4 "") )

Page 141: Autolisp Gera

Como observaréis, hemos creado una función llamada dib_lineas, a la que hemos añadido el prefijo c: para poder ejecutarla cuando queramos desde la línea de comandos, una vez la hayamos cargado, como ya se explicó en el TEMA 1. Esta función contiene 4 variables que le hemos dado carácter local, con lo que, una vez termine, se perderán los valores de sus variables. Sin embargo, si cambias el punto y coma de la segunda línea ;(DEFUN c:dib_lineas () y lo pasáis a la primera línea (DEFUN c:dib_lineas ( / pt1 pt2 pt3 pt4), la rutina queda exactamente igual, pero ahora las variables son globales y podemos utilizarlas en otro momento o conocer su valor tecleando en la línea de comando: !pt1, !pt2..... Haced la prueba de las dos maneras. También observaréis que hemos utilizado \n para salto de línea. Podéis eliminarlo y ver lo que pasa. Un detalle importante. A mi me gusta poner el abre paréntesis y el cierra paréntesis en la misma línea. Pero si se hace muy largo, como es el caso del cierra paréntesis de una función, me gusta ponerlo en la línea vertical del que abre. 

Y con esto doy por terminada esta lección. Como siempre, si alguien desea añadir o rectificar algo, pues ya sabe.

Tema 1. Introducción : Funciones MatemáticasAutor: Robierzo

Pasare a describir las Distintas Funciones de lisp porción Temas.

Empecemos Por La de Matemáticas.

+ Suma

- Resta

* Multiplicación

/ División

Resto rem De Una División de neteros

1 + suma 1

1 - resta 1

Absoluto valor abs

fijar la instancia de parte Entera de la onu del numero real de

flotar convierte ONU entero es verdadera ONU

Page 142: Autolisp Gera

Máximo mcd Común denominador

min El Más Pequeño de la ONU Grupo

max el alcalde de la ONU Grupo

sqrt La Raíz cuadrada

expt exponente

exp Potencia de correos, base De Los logaritmos Naturales

log logaritmo natuar

cvunit conversor de unidades

Sigamos porciones del SE de Como Usan ESTAS Funciones.

ONU Tiene Lisp MODO Particular de expresar Las Operaciones Matemáticas

, Segun Tengo entendido sí deriva de la notación polaca inversa, no es Igual Pero sí le asemeja.

las Operaciones sí Escriben poniendo de como prefijo el Operador

Sumar EJEMPLO porción párrafo 2 + 3 pondremos

+ Suma

(2 + 3) devuelve 5, Supuesto Por

(+ 4 5,6 -2) da 7,6, baño distraction este Caso es Contacto La Suma de Dos numeros Positivos mas negativo de la ONU

Les comento algoritmo, no Hace Falta ESCRIBIR UN Programa párr verificar ESTO,

tan solo Pongan en La Línea de Comandos de Acad la Operación tal de como la que arriba de Puesto, parentesis abren, el signo mas, el 2, el 3, Cierran parentesis y dan introducción entrar y podran ver el Resultado en la linea de comando.

TODAS Y ASI párr Las Operaciones

- Resta

(- 9 7)

(- 8 4 0.5)

Multiplica

(* 6 7)

Page 143: Autolisp Gera

(* 2 -3 1.5)

División

(/ 12 6)

(/ 11 6), división Que fijense aire pasa ESTA, y here vale lea pena Hablar Sobre Enteros int y reales.

11 y 6 hijo dos Enteros y porción del tanto lo daran de Como Resultado La Parte Entera de la división Que Sera 1

ahora si tan solo Ponen el divisor de bienes como, el Resultado sueros sin verdadera

(/ 11 6.0)

expresada Que Decir basta Para Qué mar Número ONU debe verdadera Tener do a instancia de parte decimal, aunque sean 0

6 es enterovirus ONU

6.0 es reales ONU

Presten ATENCIÓN A ESTE TEMA, YA QUE ES MOTIVO DE ERRORES QUE SON CASI IMPOSIBLES AVECES DE DETECTAR.

bueno Por Ahora los dejo, Pero los antes les dejo Una Lección Completa, lamentablemente no está en inglés, Pero es lo Único Que Tengo a mano

Cita:

Definiciones de función

-------------------------------------------------- ------------------------------

1 - Matemáticas

-------------------------------------------------- ------------------------------

+ ..... Adds

(+ 2 3) devuelve 5

(+ 4 5,6 -2) devuelve 7,6

Después (setq un 20 b 9)

(+ Ab) devuelve 29

-------------------------------------------------- ------------------------------

- ..... Resta

Page 144: Autolisp Gera

(- 9 7) devuelve 2

(- 8 4 0,5) devuelve 3,5

Después (setq un 20 b 9)

(- Ab) devuelve 11

(- ba) devuelve -11

(- A) devuelve -20. Cuando se suministra sólo un argumento, su valor se resta de 0, la señal de conmutación de cualquier número.

-------------------------------------------------- ------------------------------

* ..... Multiplica

(* 6 7) devuelve 42

(* 2 -3 1.5) devuelve -9,0

Después (setq un 3 b 4.5)

(* Ab) devuelve 13,5

(* Aa) devuelve 9

-------------------------------------------------- ------------------------------

/ ..... Divide

(/ 12 6) devuelve 2

(/ 11 6) devuelve 1 (División usando sólo números enteros ignora cualquier resto. Cuidado con los "división entera.")

(/ 11 6.0) devuelve 1,833333

(/ 12 3 2) devuelve 2

(/ 12 -2,0) devuelve -6.0

-------------------------------------------------- ------------------------------

rem ..... Devuelve un resto resultante de la división

(10 rem 3) devuelve 1

(10 rem 5) devuelve 0

(Rem 6,2 1,2) devuelve 0,2

-------------------------------------------------- ------------------------------

1 + ..... Incrementos de 1

Page 145: Autolisp Gera

(1 + 16) devuelve 17

Después (setq un 21)

(1 + a) devuelve 22. Usado con setq, esto sirve como un contador de bucle de iteración. Por ejemplo, (setq c (1 + C)).

(1 + -4) devuelve -3

-------------------------------------------------- ------------------------------

1 - ..... Disminuye por 1

(1 - 16) devuelve 15

Después (setq un -8)

(1 - a) devuelve -9

-------------------------------------------------- ------------------------------

abs ..... Devuelve el absoluto de un número

(Abs 7,0) devuelve 7,0

(Abs -6) devuelve 6

-------------------------------------------------- ------------------------------

fijar ..... Descarta parte fraccionaria de un número y devuelve un entero

(Fix 7. 1) devuelve 7

(Fijar 7,9) devuelve 7

(Fijar -4,6) devuelve -4

-------------------------------------------------- ------------------------------

float ..... Convierte un número a un número real (número de punto flotante decimal)

(Float 5) devuelve 5,0

(Float 5.82) devuelve 5,82

-------------------------------------------------- ------------------------------

mcd ..... Devuelve el mayor factor (divisor), común a dos o más enteros. Los argumentos deben ser enteros positivos.

(Mcd 21 39) devuelve 3

(Mcd 102 138) devuelve 6

(Mcd 30 45 60) devuelve 15

Page 146: Autolisp Gera

Autodesk dice que esta función devuelve el "máximo común denominador" (una frase sin sentido). Es mejor pensar en él como "máximo común divisor".

-------------------------------------------------- ------------------------------

min ..... Devuelve el más pequeño (el más bajo) de dos o más números

(Min 8 3 11,88 14 6) devuelve 3,0

(Min 13 -28 2 66) devuelve -28

-------------------------------------------------- ------------------------------

max ..... Devuelve el mayor de dos o más números

(Max 8 3 11,88 14 6) devuelve 14,0

(Max -22 -2 16) devuelve 16

-------------------------------------------------- ------------------------------

sqrt ..... Devuelve la raíz cuadrada de un número como una verdadera

(Sqrt 16) devuelve 4,0

(Sqrt 2,0) devuelve 1,414214

-------------------------------------------------- ------------------------------

expt ..... Eleva un número dado para una potencia dada

(Expt 3 4) devuelve 81

(Expt 2.0 5.0) devuelve 32

(Expt 3 -2) devuelve 0 (exponentes negativos aplicados a los números enteros pueden aparecer para dar resultados incorrectos, debido a la división entera)

(Expt 3,0 -2,0) devuelve 0,111111

(Expt 256 0,25) devuelve 4,0

Después (setq un 2,25 b 0,5)

(Expt ab) devuelve 1,5

-------------------------------------------------- ------------------------------

exp ..... Devuelve e elevado a una potencia dada

(Exp 1.0) devuelve 2.71828

(Exp 2,14) devuelve 8.49944

(Exp 0.4) devuelve 1.49182

Page 147: Autolisp Gera

(-2,0 Exp) devuelve 0,135335

El número de Euler, e, es la base de los logaritmos naturales, y es aproximadamente igual a 2,71828. Se utiliza para simplificar ciertas fórmulas de cálculo. Comparar ingrese a continuación.

-------------------------------------------------- ------------------------------

iniciar ..... Devuelve el logaritmo natural (base e) de un número. Comparación exp anteriormente.

(Log 3) devuelve 1.09861

(Log 1.82) devuelve 0,598837

(Log 0.25) devuelve -1.38629

-------------------------------------------------- ------------------------------

cvunit ..... Convierte un valor o una lista de valores, de una unidad a otra. El primer argumento es el número a convertir, el segundo argumento es la unidad desde la que se va a convertir, el tercer argumento es la unidad a la que está convirtiendo.

(Cvunit 10 "pulgadas" "mm") devuelve 254.0

(Cvunit 100 "mm" "pulgadas") devuelve 3.93701

(Cvunit 25 "libras" "kg") devuelve 11.3398

(Cvunit (lista 6 5 24) "pulgadas" "pies") devuelve (0,5 0.416667 2.0)

Después (setq un 1 b 2)

(Cvunit una "pulgada" "mm") devuelve 25,4

(Cvunit (list (eval a) (eval b)) "pulgadas" "mm") devuelve (25.4 50.8)

Los nombres de las unidades para el segundo y tercer argumentos deben escribirse tal y como aparecen en el archivo ACAD.UNT. La función cvunit depende de los valores en ACAD.UNT. Por lo tanto, para la mayoría de las conversiones, se prefiere la simple multiplicación o división por el factor apropiado dentro de la expresión AutoLISP sobre la dependencia de un archivo externo.

;*** --------------------------------------------------;;; https://portafoliolisp.wordpress.com/;;; [email protected];;; Septiembre 2012;*** --------------------------------------------------

;; Imnporta: Dibuja Puntos y coordenadas en Model Space(defun c:puntoi()

(setq archivo (getfiled "Selecciona un archivo de puntos" "" "txt" 4))

(setq arch (open archivo "r"))

Page 148: Autolisp Gera

(setq line T) (while line (setq x (read-line arch))

(setq y (read-line arch)) (setq pt (list (atof x) (atof y)))

(command "point" pt "")(setq pt2 (list (+ (atof x) 3) (atof y) ))(command "text" pt2 1 "" (strcat "x=" x "

y=" y) "") ) (close arch))

; Exporta: Escribe coordenadas de puntos en un archivo TXT(defun c:puntoe() (setq conjunto (ssget '((0 . "POINT")))) (setq largo (sslength conjunto))

(setq archivo (getfiled "Selecciona un archivo nuevo" "" "txt" 1))

(setq arch (open archivo "w")) (setq k 0) (repeat largo (setq cod (ssname conjunto k))

(setq lista (entget cod)) (setq pt (cdr (assoc 10 lista))) (setq x (nth 0 pt)) (setq y (nth 1 pt)) (setq x (rtos x 2 0)) (setq y (rtos y 2 0)) (write-line x arch) (write-line y arch) (setq k (+ k 1))

) (close arch)

)

EJEMEPLO PTS

3416166271315345364627639234322462761333419796276133

RETICULA EN AUTOLISPA continuación se muestra el código fuente para la creación de una retícula para un plano topográfico ya sea de líneas o cruces, basado en 2 puntos capturados por el usuario,

Page 149: Autolisp Gera

distancia entre cotas, altura del texto y tamaño de cruces en caso de elegir ésta opción.;Archivo: RETICULA.LSP;Funcion: RET;Descripcion: Dibuja en pantalla una cuadricula ya sea con lineas o cruces; de las coordenadas cerradas capturando para ello 2 puntos,; distancia entre cotas, altura de texto y tamaño de cruces en; caso de elegir esa opción.;Autor: Carlos Alberto Faz Alcalá;Fecha: Febrero de 2008(defun c:ret ()(setq ocmd (getvar "cmdecho")oblp (getvar "blipmode")oosm (getvar "osmode"))(setvar "cmdecho" 0)(setvar "blipmode" 0)(command "_LAYER" "_m" "RETICULA" "_c" "8" "" "")(initget 1)(setq p1 (getpoint "1ra. Esquina:"))(terpri)(initget 1)(setq p2 (getcorner p1 "2da. Esquina:"))(terpri)(initget (+ 2 4))(setq ancho (getint "Distancia entre cotas <100>: "))(terpri)(if (= ancho nil)(setq ancho 100))(initget (+ 2 4))(setq ht (getreal "Altura del texto <2.5>: "))(terpri)(if (= ht nil)(setq ht 2.5))(setq xmin (min (car

p1) (car p2)))(setq ymin (min (cadr p1) (cadr p2)))(setq xmax (max (car p1) (car p2)))(setq ymax (max (cadr p1) (cadr p2)))(if (< xmin 0)(setq ix1 (* (fix (/ xmin ancho)) ancho))(setq ix1 (+ (* (fix (/ xmin ancho)) ancho) ancho)))

Page 150: Autolisp Gera

(if (< xmax 0)(setq ix2 (- (* (fix (/ xmax ancho)) ancho) ancho))(setq ix2 (* (fix (/ xmax ancho)) ancho)))(if (< ymin 0)(setq iy1 (* (fix (/ ymin ancho)) ancho))(setq iy1 (+ (* (fix (/ ymin ancho)) ancho) ancho)))(if (< ymax 0)(setq iy2 (- (* (fix (/ ymax ancho)) ancho) ancho))(setq iy2 (* (fix (/ ymax ancho)) ancho)))(initget "Cruz Linea")(setq op (getkword "Escoja tipo de cuadricula [Cruz/Linea] <C>: "))(if (or (= op "Cruz") (= op \n))(cruz)(linea))(command "_pline" p1 (list (car p1) (cadr p2)) p2 (list (car p2) (cadr p1)) "_c")(command "_style" "" "" ht "" "" "" "" "")(if (= xmin (- ix1 ancho))(setq ix1 xmin))(if (= xmax (+ ix2 ancho))(setq ix2 xmax))(if (= ymin (- iy1 ancho))(setq iy1 ymin))(if (= ymax (+ iy2 ancho))(setq iy2 ymax))(setq ix ix1)(while (<= ix ix2)(setq tex (strcat "X=" (ponercomas ix)))(command "_text" "_mr" (list ix (-

ymin 5.0)) '90.0 tex)(command "_change" "_l" "" "_P" "_C" "2" "")(setq ix (+ ix ancho)))(setq iy iy1)(while (<= iy iy2)(setq tex (strcat "Y=" (ponercomas iy)))(command "_text" "_mr" (list (- xmin 5.0) iy) '0.0 tex)

Page 151: Autolisp Gera

(command "_change" "_l" "" "_P" "_C" "2" "")(setq iy (+ iy ancho)))

(setvar "cmdecho" ocmd)(setvar "blipmode" oblp)(setvar "osmode" oosm)(princ))

(defun cruz ()(initget (+ 2 4))(setq tc (getreal "Tamaño de cruz <5>: "))(terpri)(if (= tc nil)(setq tc 5.0))(setq tc (/ tc 2))(setvar "osmode" 0)(if (= xmin (- ix1 ancho))(setq ix1 xmin))(if (= xmax (+ ix2 ancho))(setq ix2 xmax))(if (= ymin (- iy1 ancho))(setq iy1 ymin))(if (= ymax (+ iy2 ancho))(setq iy2 ymax))(setq ix ix1)(while (<= ix ix2)(setq iy iy1)(while (<= iy iy2)(setq x1 (- ix tc)x2 (+ ix tc)y1 (+ iy tc)y2 (- iy tc))(if (< x1 xmin)(setq x1 xmin))(if (> x2 xmax)

Page 152: Autolisp Gera

(setq x2 xmax))(if (> y1 ymax)(setq y1 ymax))(if (< y2 ymin)(setq y2 ymin))

SERVICIOS INTEGRALES EN COMPUTACION

SINCOW

MANUAL DE AUTOLISP

PREPARADO POR: ING. GUSTAVO NAVAS

www.sincows.com [email protected] ISLA FERNANDINA N42-52 (CIUDADELA JIPIJAPA), TELE/FAX: 2920-890, 2431-356 QUITO-ECUADOR

www.sincows.com

[email protected]

Servicios Integrales en ComputaciónSINCOWMANUAL DE AutoLISP Realizado por: ING.GUSTAVO NAVAS R. I. INTRODUCCIÓN Dentro del AutoCAD nos encontramos un lenguaje de programación que usa un interprete de nombre AutoLISP, este es una forma común del lenguaje LISP, el cual a su vez es el lenguaje más antiguo en aplicaciones de inteligencia artificial. El AutoLISP coexiste con el AutoCAD y puede ser usado en cualquier momento que se este editando un dibujo. Este lenguaje provee herramientas comunes a otros paquetes de programación para estructurar el flujo de un programa, manipula datos del AutoCAD, así como datos propios, tiene opciones de entrada y salida I/O para la creación y lectura de archivos ASCII. Presenta además la capacidad de poder activar cualquier comando que venga dentro del AutoCAD así como también puede manipular informaciones propias de un dibujo realizado en AutoCAD, tal es el caso de manejar entidades (Líneas, arcos, círculos, poli-líneas, etc.), así como también tipos de líneas, estilos "styles", niveles "Layers", etc. El lenguaje LISP original tenía la posibilidad de definir funciones en forma recursiva, esto

Page 153: Autolisp Gera

significa que la función era usada al interior de si misma asignándole las variables de entrada, esta

capacidad presenta también el AutoLISP. Mas lamentablemente no hay información sobre el uso del AutoLISP con funciones recursivas, pero cualquier libro que haga referencia a la recursividad en el lenguaje LISP puede ser de ayuda para el estudio de funciones recursivas dentro del AutoLISP, pues con algunos cambios los programas en LISP podrán ser ejecutados al interior del AutoLISP, en particular la versión de XLISP es la más recomendada pues es la que presenta el mayor parecido con el AutoLISP. Los paréntesis son vitales para escribir cualquier instrucción en AutoLISP, sea esta una simple expresión o sea un programa completo, digamos además que el abrir y cerrar paréntesis permiten al AutoCAD distinguir entre los comandos propios del paquete y las expresiones del AutoLISP. Cada vez que el AutoCAD detecta un paréntesis abierto, interpreta que se refiere a una expresión de AutoLISP y esta pasa en su totalidad, hasta el paréntesis que la cierra, a ser evaluada por el AutoLISP, el cual da un resultado al AutoCAD que puede usarlo y continuar con sus operaciones propias. Toda expresión dentro del AutoLISP presenta el siguiente formato: (Nombre-de-la-función argumento-1 argumento-2 ......) El nombre de la función, que puede ser propio del AutoLISP o creado por el usuario, relaciona a los argumentos que vienen a continuación. Los argumentos a su vez pueden ser otras funciones, variables o constantes. Veamos por ejemplo la siguiente expresión dada en AutoLISP: (* 3 2) Expresión AutoLISP Resultado (+ 5 3) 8 (+ 2 4 5) 11 (/ 5 3) 1

(/ 5.0 3) 1.6667 (- 15 3 8) 4 (+ (* 2 3) 1 (- 4 7)) 4 Expresiones aritméticas en AutoLISP y su resultado.

La expresión anterior se podrá tipiar en cualquier momento, como ya se dijo anteriormente, y corresponderá a la operación de multiplicación de los argumentos que vengan a continuación en este caso los valores constantes de 3 y 2, el AutoLISP evaluará esa expresión dando un valor de 6. En la tabla No. 1 se puede apreciar algunas expresiones aritméticas en AutoLISP y el resultado que daría el programa. Para mayor información sobre las expresiones aritméticas véase pág 6. II. SETEADO INICIAL Antes de correr cualquier programa de AutoLISP, es indispensable setear cierto tipo de información dentro del DOS. En primer lugar setearemos las variables LISPHEAP y LISPSTACK, lo cual se hará desde el DOS de la siguiente manera: SET LISPHEAP=20000 SET LISPSTACK=8000 Los valores de 20000 y 8000 pueden ser cambiados, pero las sumas de estas dos cantidades no puede exceder de 45000. Otra variable que requiere ser seteada antes de trabajar con el AutoCAD es ACADFREERAM, la cual permite setear mayor cantidad de memoria RAM libre para uso del AutoCAD. Se tipiará en pantalla lo siguiente: SET ACADFREERAM=20 El valor de 20 también puede ser alterado de acuerdo a las necesidades del usuario, pero no se recomiendan valores mayores a 32, ni menores a 20. Si el valor de esta variable no es seteado el AutoCAD le asignará un valor de 14. III. VARIABLES

Page 154: Autolisp Gera

2 Isla Fernandina N42-52 (Ciudadela Jipijapa) Teléfono/fax: 920-890, 431-356

En el inicio del AutoLISP, éste no fue llamado con este nombre y fue más bien llamado "variables y expresiones" "variables and expressions" para la construcción de macros. Existen unas variables propias del sistema que podrán ser manipuladas a través del comando SETVAR. Una variable en AutoLISP representa cualquier cosa que no sea un valor constante. Se usan variables de todo tipo. El AutoLISP permite sustituir variables en lugar de valores constantes, es posible asignar un valor al nombre de una variable. Es posible unir la información del nombre de una variable explícitamente en un macro, es posible además usar el nombre de las variables con expresiones para desarrollar cálculos y/o tomar decisiones lógicas. El nombre de una variable es una colección de letras y números, siempre y cuando el primer carácter sea una letra. En la tabla II se pueden apreciar nombres de variables apropiadas y nombres de variables incorrectas.

Nombres de variables Correctas Incorrectas f 37 esta 45t punto11 ry*4 que23s x$ etc ft+ui

╔═══════════════════════════════════════════════════════════════╗ CARACTERES NO RECOMENDADOS PARA NOMBRES DE VARIABLES CARACTERES RESERVADOS O ILEGALES: . ' " ; ( ) FUNCIONES DEL AUTOLISP: ~ * = > < + - / CARACTERES NO RECOMENDADOS: ! ? ` \ ^ o cualquier carácter Control ╚══════════════════════════════════════════════════════════════╝El valor que se asigna a una variable puede ser

de cuatro tipos: Variable string: Tiene valores de texto ubicadas ente comillas para identificar el valor como un string. Algunas variables del sistema (Ver comando SETVAR) son del tipo string, tal es el caso de la variable CELTYPE, que tiene asignado un valor "BYLAYER" entre otras. Enteras: Son números positivos o negativos los cuales no tienen fracciones o puntos decimales. El valor de 5 sería un típico ejemplo de un valor entero mientras que el valor 5.0 será considerado por el AutoLISP como un valor real y no como un valor entero. Los valores enteros deberán estar entre -32768 y +32767. Para valores enteros fuera de estos rangos causará valores erróneos. Algunas variables del sistema toman valores enteros, tal es el caso de la variable BLIPMODE que puede tomar valores de 0 para desactivado y 1 para activado. Reales: Es un número que incluye decimales de punto flotante. Si se desea escribir el valor de 0.134 no se lo podrá escribir como .134, pues esto producirá un error, por lo que tendremos que escribirlo con el 0 inicial. Algunas variables del sistema tienen asignados valores reales. Demos algunos ejemplo de este tipo de variables: FILLETRAD, TEXTSIZE, AREA, etc. Listas: Es una variable que contiene más de un valor o una serie de valores. Los puntos o coordenadas son un tipo de listas que están constituidos por dos (2D) o tres (3D) elementos numéricos y que representan una coordenada. En las variables del sistema de nombre LASTPOINT, LIMMIN, LIMMAX, etc tienen asignado variables del tipo coordenada.

Page 155: Autolisp Gera

Pickset: Una tabla que contiene puntos de elementos gráficos, del set de selección creados con cualquier opción de selección de objetos en AutoCAD, por ejemplo: window, crossing, etc. Ename (Nombre de una entidad): Este es un tipo de variable que representa al nombre de una entidad. A partir de ella se podrá generar una lista donde este comprendida toda la información respecto a la entidad, ver comando ENTGET página 12. ATOMLIST Se recomienda no usar nombres de funciones del AutoLISP, como nombres de variables. El ATOMLIST es una variable en el AutoLISP que guarda todos los nombres de funciones definidas y nombres de variables. Se puede mirar esta lista tipiado lo siguiente: !atomlist Apareciendo entonces en pantalla lo que se ilustra en la 4:

3 Isla Fernandina N42-52 (Ciudadela Jipijapa) Teléfono/fax: 920-890, 431-356 Quito-Ecuador

www.sincows.com

[email protected]

Servicios Integrales en ComputaciónSINCOWCommand: !ATOMLIST (INTERS GRREAD GRTEXT GRDRAW GRCLEAR TBLSEARCH TBLNEXT ENTUPD ENTMOD ENTSEL ENTLAST ENTNEXT ENTDEL ENTGET SSMEMB SSDEL SSADD SSLENGTH SSNAME SSGET ANGTOS RTOS COMMAND OSNAP REDRAW GRAPHSCR TEXTSCR POLAR DISTANCE ANGLE INITGET GETKWORD GETCORNER GETINT GETSTRING GETORIENT GETANGLE GETREAL GETDIST GETPOINT MENUCMD PROMPT SETVAR GETVAR TERPRI PRINC PRIN1 PRINT WRITE-LINE READ-LINE WRITE-CHAR READ-CHAR CLOSE OPEN STRCASE ITOA ATOF ATOI CHR ASCII SUBSTR STRCAT STRLEN PAUSE PI MINUSP ZEROP NUMBERP FLOAT FIX SQRT SIN LOG EXPT EXP COS ATAN 1- 1+ ABS MAX MIN NOT OR AND > >= /= = >= /= =

FUNCIONES ARITMÉTICAS

+ Suma números

Sintaxis: (+ . . . )Valor retornado: Suma de todos los argumentos numéricos.

- Sustrae n números

Sintaxis: (- . . . )Valor retornado: La diferencia entre el primer argumentoy la suma de los restantes argumentos

Page 156: Autolisp Gera

* Multiplica números

Sintaxis: (* . . . )Valor retornado: Producto de todos los argumentosnuméricos.

/ Divide números

Sintaxis: (/ . . . )Valor retornado: El cociente del primer argumentodividido por el producto de los demás argumentos.

~ Devuelve el operador NOT binario (complemento de 1) delargumento

Sintaxis: (~ )Valor retornado=-.

1+ Incrementa un número en uno

Sintaxis: (1+ )Valor retornado=1+n(entero ó real según n sea entero ó real.)

1- Disminuye en uno un número.

Sintaxis: (1- )Valor retornado=n-1 (entero ó real según n sea enteroó real.)

ABS Convierte un número a su valor absoluto

Sintaxis: (ABS )Valor retornado=el valor absoluto de n.

ATAN Calcula el arcotangente

Sintaxis: (ATAN n2)Valor retornado=Arcotangente de n1/n2.Valor en radianes entre /2 y -/2.

COS Calcula el coseno de un ángulo expresado en radianes

Page 157: Autolisp Gera

Sintaxis: (COS )Valor retornado=El coseno de ang

SIN Calcula el seno de un ángulo expresado en radianes

Sintaxis: (SIN )Valor retornado=El seno de ang

EXP Calcula el antilogaritmo neperiano de un numero

Sintaxis:(EXP )Valor

retornado: número real igual a en

EXPT Calcula el resultado de elevar un número a una potencia

Sintaxis:(EXPT )Valor retornado: número real o entero

GDC Calcula el máximo común denominador de dos enteros

Sintaxis: (GDC )Valor retornado=El valor del máximo común denominador

LOG Calcula el logaritmo neperiano de un número real

Sintaxis: (LOG )Valor retornado=Un número real.

LOGAND Devuelve el resultado de una Y lógica (AND) deuna lista de números enteros a nivel binario.

Sintaxis: (LOGAND ...)Valor retornado: Un número entero.

LOGIOR Devuelve el resultado de una O lógica (OR) de unalista de números enteros a nivel binario.

Sintaxis: (LOGIOR ...)Valor retornado: Un número entero

LSH Desplazamientom a nivel binario del contenido de unregistro (defase) de (entero) en un valor (entero).Si es positivo se desplaza hacia la izquierda, si

Page 158: Autolisp Gera

negativo, hacia la derecha.Valor retornado: Un número entero.

Sintaxis: (LSH )

MAX Extrae el mayor valor de una serie de números

Sintaxis: (MAX ...)Valor retornado=El mayor valor encontrado.

MIN Extrae el menor valor de una serie de números

Sintaxis: (MIN ...)Valor retornado=El menor valor encontrado.

MINUSP Comprueba si un número es menor que 0

Sintaxis: (MINUSP )Valor retornado=T si el argumento n es un número y es negativonil en caso contrario.

REM Calcula el resto de la división entre dos números

Sintaxis: (REM )Valor retornado: El resto de dividir n1 entre n2..

SQRT Calcula la raíz cuadrada de un número

Sintaxis: (SQRT )Valor retornado=Un número real, raíz cuadrada de n

ZEROP Comprueba si un

número es 0

Sintaxis: (ZEROP )Valor retornado:T si el elemento es 0nil en caso contrario.

FUNCIONES DE RELACIÓN

= Comprueba la igualdad numérica

Page 159: Autolisp Gera

Sintaxis: (= ...)Valor retornado:T si todos los argumentos (números o cadenas decaracteres) se evalúan como igualesnuméricamentenil en caso contrario

Las cadenas son comparadas en esta función y en las siguientesen base a su valor numérico ASCII

/= Comprueba la desigualdad numérica

Sintaxis: (/= ) ...)Valor retornado:T si todos los argumentos (números o cadenas decaracteres) no se evalúan como igualesnuméricamentenil en caso contrario

< Comprueba la relación “menor que” entre los argumentos

Sintaxis: (< ...)Valor retornado:T si cada argumento es numéricamente menor queel argumento de su derechanil en caso contrario

> Comprueba la relación “mayor que” entre los argumentos

Sintaxis: (> ) ...)Valor retornado:T si cada argumento es numéricamente mayor queel argumento de su derechanil en caso contrario

= ...)Valor retornado:T si cada argumento es numéricamente mayor óigual que el argumento de su derechanil en caso contrario

AND Comprueba los valores de una serie de expresiones. (Ylógico)

Page 160: Autolisp Gera

Sintaxis: (AND ...)Valor retornado:T si todos los argumentos se evalúan con unvalor no nulonil en caso contrario.

OR Comprueba de izquierda a derecha una serie de expresioneshasta hallar la primera que se evalúa con un valor nonulo. (O lógico)

Sintaxis: (OR ...)Valor retornado:T si alguno de los argumentos se evalúa con unvalor no nulonil en caso contrario

EQ Comprueba si los

valores atribuidos a ambas expresionesson idénticas

Sintaxis: (EQ )Valor retornado:T si las dos expresiones están ligadas a losmismos datosnil en caso contrario

EQUAL Comprueba si dos expresiones se evalúan con valoresiguales

Sintaxis: (EQUAL margen de error )Valor retornado:T si las dos expresiones se evalúan como lamisma cosanil en caso contrario.

Si las dos expresiones son números reales se puede incluir unmargen de error

FUNCIONES DE ASIGNACIÓN

SETQ Liga el nombre de símbolos al valor de una expresión

Sintaxis: (SETQ < Símbolo> < Símbolo> ...)

Page 161: Autolisp Gera

Valor retornado:El devuelto por el último argumento de la función.

SETVAR Cambia el valor de variables del sistema.

Sintaxis:(SETVAR )La variable del sistema no podrá ser sólo de lecturay el nuevo valor asignado será de los que el sistemapueda aceptar.Valor retornado:El nuevo valor de la variable del sistema

TYPE Extrae el tipo de dato de un argumento.

Sintaxis: (TYPE )Valor retornado: El tipo de dato como una cadena enmayúsculasREAL: numero enteroFILE: descriptor de ficheroSTR: cadenasINT: numero entero.SYM: símbolosLIST: listas y funciones de usuarioSUBR: funciones internas.......

FUNCIONES GRÁFICAS

ANGLE Calcula el ángulo que formaría una recta definida por dospuntos con la dirección positiva del eje X del SCP actual(si los puntos son 3D se proyectan sobre el plano deconstrucción actual)

Sintaxis: ( ANGLE )Valor retornado:Un ángulo en radianes

DISTANCE Calcula la distancia entre dos puntos

Sintaxis: ( DISTANCE )Valor retornado:Un número real, que es la distancia

Page 162: Autolisp Gera

en unidades dedibujo entre los dos puntos suministrados comoargumentos.

POLAR Computa un punto en relación a un punto dado.

Sintaxis: ( POLAR )Valor retornado:Las coordenadas de un punto situado en el ángulo“ang” y a una distancia “dis” del punto “pt” todoello con relación al SCP actual. El ángulo siemprese refiere al plano de construcción actual.

INTERS Calcula el punto de intersección entre dos líneas

Sintaxis: ( INTERS extend)Valor retornado:Un punto que indica el punto de intersección de lalínea definida por pt1 y pt2 y la línea definidapor pt3 y pt4, si no se encuentra ningún punto deintersección la función retorna un nilExtend: Si extend se evalúa como nil, las líneas seprolongan hasta encontrar el punto de intersección, encaso contrario ó si no se codifica, sólo se busca laintersección en la longitud de los segmentos definidospor los puntos

COMMAND Ejecuta ordenes Autocad

Sintaxis:(COMMAND

[argumentos válidos]...)Valor retornado: nil

OSNAP Aplica a un punto un modo de referencia Autocad

Sintaxis: (OSNAP )Valor retornado:Una lista de punto resultante del modo dereferenciar objetos que se esté aplicando alargumento pt

Page 163: Autolisp Gera

El funcionamiento de esta orden depende del valor de lavariable del sistema “apertura “ y del punto de vista 3Dactual.

FUNCIONES DE ENTRADA INTERACTIVA.

GETPOINT Detiene la ejecución del programa para que el usuariointroduzca un punto.

Sintaxis: (GETPOINT pt [mensaje])pt: punto de base opcionalmensaje: cadena opcional que será presentada en elárea de ordenes/peticiones de la pantalla, en elmomento de la solicitud del

puntoValor retornado:El punto introducido, como una lista de númerosreales.

GETDIST Detiene la ejecución del programa para que el usuariointroduzca una distancia

Sintaxis: (GETDIST pt [mensaje])pt: punto de base opcionalmensaje: cadena opcional que será presentada en elárea de ordenes/peticiones de la pantalla, en elmomento de la solicitud de la distanciaValor retornado: Un número real

GETANGLE Detiene la ejecución del programa para que el usuariointroduzca un ángulo.

Sintaxis: (GETANGLE pt [mensaje])pt: punto de base opcionalmensaje: cadena opcional que será presentada en elárea de ordenes/peticiones de la pantalla, en elmomento de la solicitud del ánguloValor retornado: El valor del ángulo en radianes

GETORIENT Detiene la ejecución del programa para que el usuariointroduzca un ángulo.

Sintaxis: (GETORIENT pt [mensaje])pt: punto de base opcional

Page 164: Autolisp Gera

mensaje: cadena opcional que será presentada en elárea de ordenes/peticiones de la pantalla, en elmomento de la solicitud del ánguloValor retornado:El valor del ángulo en radianes

La diferencia con GETANGLE radica en que el ángulo que devuelveGETORIENT no se ve afectado por las variables del sistemaAutocad angbase y angdir.Es útil por tanto para introducir y guardar información angularabsoluta.

GETCORNER Detiene la ejecución del programa para que el usuariointroduzca un punto, y traza un rectángulo de “bandaelástica” en la pantalla a medida que el usuario mueve eldispositivo señalador

Sintaxis: (GETCORNER [mensaje])pt: Primera esquina del rectángulo.mensaje: cadena opcional que será presentada en elárea de

ordenes/peticiones de la pantalla, en elmomento de la solicitud de la otra esquina.Valor retornado:El punto introducido por el usuario

GETVAR Extrae un valor almacenado en una variable del sistema deAutoCAD

Sintaxis: (GETVAR )Valor retornado: valor de la variable del sistemaespecificada.GETINT Detiene la ejecución del programa para que el usuariointroduzca un número entero.

Sintaxis: (GETINT [mensaje])mensaje: cadena opcional que será presentada en elárea de ordenes/peticiones de la pantalla, en elmomento de la solicitud del enteroValor retornado:El entero introducido por el usuario

GETREAL Detiene la ejecución del programa para que el usuariointroduzca un número real

Page 165: Autolisp Gera

Sintaxis: (GETREAL [mensaje])mensaje: cadena opcional que será presentada en elárea de ordenes/peticiones de la pantalla, en elmomento de la solicitud del número realValor retornado:El real introducido por el usuario

GETFILED Presenta un cuadro de dialogo de nombres de archivos yespera una entrada de usuario.

Sintaxis:(GETFILED

)parámetros:valor entero que controla el comportamiento delcuadro de dialogo.(Ver manual)Valor retornado:El nombre del archivo seleccionado como una cadenanil si no se selecciona ninguno.

GETSTRING Detiene la ejecución del programa para que el usuariointroduzca una cadena de caracteres

Sintaxis: (GETSTRING [espacio] [mensaje])Espacio: Si este argumento es distinto de nil,la cadena introducida puede contener espacios enblanco.mensaje: cadena opcional que será presentada enel área de ordenes/peticiones de la pantalla, en elmomento de la solicitud de la

cadenaValor retornado:La cadena introducida ó una cadena vacía (“”) si elusuario pulsó Enter sin teclear caracteres.

GETKWORD Detiene la ejecución del programa para que el usuariointroduzca una cadena de caracteres. Esta funcióncomprueba la validez de lo introducido basándose en una

Page 166: Autolisp Gera

lista de palabras válidas establecidas usando la funciónINIGET

Sintaxis: (GETKWORD [mensaje])mensaje: cadena opcional que será presentada enel área de ordenes/peticiones de la pantalla, en elmomento de la solicitud de la cadenaValor retornado:La cadena introducida ó una cadena vacía (“”) si elusuariopulsó Enter sin teclear caracteres.

INIGET Comprueba la validez de las repuestas para una función“GET...” (ver manual Autolisp)

FUNCIONES PARA GESTIÓN DE LISTAS

CREACIÓN DE LISTAS

LIST Crea una lista a partir de un número de expresiones

Sintaxis: ( LIST ...)Valor retornado: Una lista de los argumentos de lafunción.

APPEND Funde varias listas en una

Sintaxis: (APPEND ...........)Valor retornado: Una lista única

CONS Añade al principio de una lista como primer elemento unaexpresión

Sintaxis: (CONS )Valor retornado: La nueva lista

EXTRACCIÓN DE ELEMENTOS DE UNA LISTA

LENGHT Cuenta los elementos de una lista

Sintaxis: (LENGHT )Valor retornado: El número entero correspondiente.

CAR Extrae el primer elemento de una lista.

Page 167: Autolisp Gera

Sintaxis: (CAR )Valor retornado: El primer elemento de la lista

CDR Extrae una nueva lista donde están todos los elemento dela lista menos el primero.

Sintaxis: (CDR )Valor retornado: la nueva lista

CAAR, CADR , CDDR, CADAR, etc.Todas las posibles

oncatenaciones hasta un cuarto nivelde las funciones CAR y CADR.

LAST Extrae el último elemento de una lista

Sintaxis: (LAST )Valor retornado: el último elemento de la lista.

NTH Extrae un elemento de una lista a partir de especificarsu posición en ella (pos)

Sintaxis: (NTH )las posiciones dentro de la lista son numeradas deizquierda a derecha empezando por la posición 0Valor retornado:El elemento encontrado, o nil si no se encontró.

ASSOC Localiza sublistas en una lista de asociacionesutilizando elemento como palabra clave, y donde éste puede ser cualquier expresión válida susceptible deaparecer como primer elemento de una de las sublistas

Lista de asociaciones:((calve1 inf1)(clave2 inf2...)(clave3 inf3...)...)

Sintaxis: (ASSOC )Valor retornado:La primera sublista encontrada. Si la clave noaparece devuelve nil

MANIPULACIÓN DE LISTAS

Page 168: Autolisp Gera

MEMBER Busca la primera aparición de una expresión en una listay devuelve el resto de la lista a partir de la expresiónencontrada.

Sintaxis: (MEMBER )Valor retornado:una lista donde el primer elemento es la expresiónencontrada y el resto, el resto de la lista hasta elfinal. Si no se encuentra la expresión devuelve nil.

REVERSE Invierte un lista

Sintaxis: (REVERSE )Valor retornado: La lista con sus miembros en ordeninverso.

LISTP Comprueba si un argumento es una lista

Sintaxis: (LISTP )Valor retornado:T si la expresión es una listanil en caso contrario

SUBST Busca en una lista un miembro especificado y sustituyecada aparición de éste por otro especificado

Sintaxis:(SUBST )Valor retornado: La lista modificada.

FOREACHProcesa uno a uno los elementos de una lista y evalúacada expresión para cada uno de los elemento de la listaSintaxis: (FOREACH ...)vari variable de memoria a la que FOREACH ligarasecuencialmente los valores de la listasuministrada y que normalmente será usada enla expresión.Valor retornado:El resultado de la última expresión evaluada.

FUNCIONES DE CONDICIÓN

COND Lee una serie de listas. Evalúa las expresiones restantesencontradas en la primera lista cuyo primer elemento no

Page 169: Autolisp Gera

se evalúe como nulo y pasa por alto las restantes listas

Sintaxis: (COND ………..)

Valor retornado: El retornado por la última expresión delas lista evaluada. Si no se evalúa ninguna lista , lafunción COND devuelve nil

IF Evalúa una expresión Autolisp basándose en si unaexpresión de comprobación inicial se evalúa como no nula

Sintaxis:(IF 

[expresión si test es=nil ])Valor retornado:El valor retornado por expresión evaluada;nil en otro caso.

PROGN Evalúa secuencialmente una serie de expresiones.

Sintaxis: (PROGN ...)Valor retornado: La última expresión evaluada

FUNCIONES PARA GESTIÓN DE CICLOS.

REPEAT Evalúa repetidamente una serie de una ó mas expresionesAutolisp un número determinado de veces.

Sintaxis: (REPEAT ...)n: Entero que indica el nº de repeticiones arealizar.Valor retornado:El resultado de la última expresión evaluada

WHILE Evalúa repetidamente una serie de una ó más expresionesAutolisp basándose en si una expresión de comprobacióninicial se evalúa como un valor nulo ó no nulo.

Sintaxis: (WHILE ...)Test: Expresión de comprobación, que hace quelas demás

Page 170: Autolisp Gera

expresiones se evalúenmientras ésta se mantenga distinta denil.Valor retornado: El resultado de la última expresiónevaluada

FUNCIONES PARA GESTIÓN DE FICHEROS.

LOAD Carga un archivo Autolisp en la memoria y evalúa lasexpresiones en el archivo.

Sintaxis: (LOAD [reserror] )nombre de fichero: cadena de caracteres con ennombre, sin extensión .lsp, del fichero.Si no se indica ningún camino se busca elfichero según el camino de acceso abibliotecas Autocad.(recordar que para obtener la contrabarra enuna cadena de caracteres es necesarioteclearla dos veces \\ o en su lugar, una vezla barra derecha /).reserror: valor vuelto por la función en el caso deque la carga del fichero fracase. Si no seproporciona este argumento, la funciónpresenta un mensaje de error AutoLISPValor retornado: El de la última expresión evaluada, sila carga es buena.

Los ficheros que se quiere sean cargados al iniciarse la sesión deleditor de dibujo tendrán que estar especificados en el ficheroACAD.LSP que Autocad carga automáticamente.

OPEN Abre un archivo de disco para leer o almacenar datos

Sintaxis:(OPEN )clave de acceso: cadena de una letra minúscula"r": Abre un fichero para lectura"w": Abre un fichero para escritura"a": Abre un fichero para escribir añadiendonuevos datos al final del mismo. sitúael puntero al final del ficheroabierto. Conviene comprobar que noexiste una marca de CTRL Z(código ASCII

Page 171: Autolisp Gera

decimal 26) de final de texto, ya queen ese caso no es posible añadir datos.Valor retornado: El descriptor de fichero utilizado porlas funciones de

Entrada/Salida a fichero, portanto se deberá atribuir a un símbolo que permitareferirse a ese descriptor.

CLOSE Cierra un archivo abierto

Sintaxis:(CLOSE )Valor retornado: nulo

FINDFILE Localiza un archivo en la ruta de búsqueda de archivos deAutocad.

Sintaxis: (FINDFILE )Valor retornado: una cadena de caracteres con el nombrecompleto del archivo indicando la ruta delocalización.

FUNCIONES DE LECTURA Y ESCRITURA

ESCRITURA

PRIN1 Imprime una expresión AutoLISP en el área de ordenes ó laescribe en un archivo abierto en modo de escritura.

Sintaxis: (PRIN1 [expresión [descriptor de fichero]])Valor retornado: el argumento de la expresión

PRINC Imprime una expresión AutoLISP en el área de ordenes ó laescribe en un archivo. (La diferencia con PRIN1 es quePRINC evalúa los caracteres de control que aparezcan enla expresión).

Sintaxis: (PRINC [expresión [descriptor de fichero]])Valor retornado: el argumento de la expresión

PRINT Imprime un salto de línea , una expresión AutoLISP y unespacio en el área de ordenes ó lo escribe en un archivo.

Page 172: Autolisp Gera

Sintaxis: (PRINT [expresión [descriptor de fichero]])Valor retornado: el argumento de la expresión

PROMPT Presenta una cadena de caracteres en el área de ordenes.(Evalúa caracteres de control)

Sintaxis: (PROMPT )Valor retornado: nulo

WRITE-CHAR Escribe un solo carácter en el área de ordenes ó bien enun fichero abierto.

Sintaxis:(WRITE-CHAR [descriptor de fichero])Valor retornado: El código ASCII para los caracteresescritos

WRITE-LINE Escribe una cadena de caracteres en al área de ordenes óbien en un archivo (evalúa caracteres de

control.

Sintaxis: (WRITE-LINE [descriptor de fichero])Valor retornado: La cadena de caracteres.

TERPRI Imprime un salto de línea en el área de ordenes.

Sintaxis: (TERPRI)Valor retornado: nulo

LECTURA

READ-CHAR Lee caracteres procedentes del bufer del teclado o de unarchivo abierto en modo de lectura.

Sintaxis: (READ-CHAR [descriptor de fichero])Valor retornado: El código ASCII para el carácter leído.

READ-LINE Lee una cadena de caracteres procedentes del bufer delteclado o de un archivo abierto en modo de lectura.

Sintaxis: (READ-LINE [descriptor de fichero])Valor retornado: la cadena leída. Cuando se alcanza elfinal de un archivo de lectura el valor retornado es nil.

Page 173: Autolisp Gera

Ejemplo:

(SETQ A 10 B “HOLA”)“HOLA”

(PRIN1 A)1010

(PRIN1 “\nCASA”)“\nCASA”“\nCASA”

(PRINC A)1010

(PRINC “\nCASA”)“CASA“\nCASA”

(PRINT A)10 10

(PRINT “\nCASA”)“\nCASA” “\nCASA”

(PROMPT “\nCASA”)CASAnil

(WRITE-CHAR A)10

(WRITE-CHAR 67)C67

(WRITE-LINE B)HOLA“HOLA”

(WRITE-LINE “\nCASA”)CASA“CASA”

FUNCIONES MONOLÍNEA

APPLY Devuelve el resultado de ejecutar la "función" tomando

Page 174: Autolisp Gera

como argumentos los elementos de la "lista"

Sintaxis: ( APPLY )Valor retornado: El devuelto por el argumento de lafunciónEjemplo:

1.- (APPLY '+ '( 1 2 3 ))=1 + 2 + 3=6

2.- (APPLY 'STRCAT '("A" "B" "C")="ABC"

MAPCAR Devuelve el resultado de ejecutar la "función" tomandocomo argumentos de función los elementos sucesivos de"lista 1" ............."lista n"

Sintaxis: ( MAPCAR .... )

Valor retornado: una lista con las sucesivas soluciones.

Ejemplo:

1.- (MAPCAR '+ '(10 20 30 ) '(4 3 2))=(14 23 32)

2.- (MAPCAR 'MAX '(2 4) '(7 -5) '(-8 20)=(8 20)

3.- (SETQ A 10 B 20 C 30)(MAPCAR '1+ (LIST A B C)=(11 21 31)

LAMBDA Define una función sin darle un nombre. El conjunto deexpresiones se aplica sobre los argumentos

Sintaxis:(LAMBDA ...)Valor retornado: el resultado de la última evaluación.Se suele utilizar combinada con APPLY y MAPCAR.

Ejemplo:

1.- (APPLY'(LAMBDA( X Y Z )(* X (- Y Z ) ))'( 5 20 14 ))

Page 175: Autolisp Gera

Resultado=30

2.- (MAPCAR'( LAMBDA( X Y Z )(* X (- Y Z ) ))'( 5 6 )'( 20 30 )'(14 0 ))Resultado=( 30 180 )

FUNCIONES DE CONVERSIÓN Y TRANSFORMACIÓN

RTOS Convierte un número real en una cadena de caracteres

Sintaxis: (RTOS [modo [precisión]])numero: número real (o entero que tomará como real)modo (opcional): entero del 1 al 5 que determina elformato numérico de la cadena:1. Unidades científicas2. Unidades decimales3. Pies y pulgadas I (fracción decimal)4. Pies y pulgadas II (fracción propia)5. Unidades fraccionariasprecisión (opcional): entero que determina el número dedecimales de precisión en la cadenaSi no se especifican los argumentos modo y precisión seasume el establecido por la variables de Autocad LUNITS yLUPRECValor retornado: Una cadena de caracteres

Ejemplo: (RTOS 5.6 2 4)=> “5.6000"

DISTOF Convierte un cadena en un número real, con un determinadoformato de visualización.

Sintaxis: (DISTOF [ modo])Cadena: cadena de caracteres que expresa un valornumérico.modo (opcional): entero del 1 al 5 que

Page 176: Autolisp Gera

indica el formatonumérico del número real expresado en la cadena (Elcódigo se corresponde con el dado en la funciónanterior), la función deberá ser capaz de interpretar elargumento cadena de acuerdo con el modo especificado:Si no se especifica el argumento modo se asume elestablecido por la variable de Autocad LUNITSValor retornado: Un número real

ANGTOS Convierte un número (que representa un ángulo enradianes) en una cadena de caracteres

Sintaxis: (ANGTOS [modo [precisión]])numero: valor del ángulo en radianes.modo (opcional): entero del 1 al 5 que determina elformato numérico en la cadena:0. Grados sexagesimales.1. Grados, minutos y segundos2. Grados centesimales.3. Radianes4. Unidades geodésicas.

precisión (opcional): entero que determina el número dedecimales de precisión en la cadenaSi no se especifican los argumentos modo y precisión seasume el establecido por la variables de Autocad LUNITS yLUPRECValor retornado: Una cadena de caracteres.

ANGTOF Convierte una cadena de caracteres en un número real querepresenta un ángulo

Sintaxis: (ANGTOF [ modo])Cadena: cadena de caracteres que expresa un valornumérico de ángulomodo (opcional): entero del 1 al 4 que indica el formatonumérico del ángulo expresado en la cadena (El código secorresponde con el dado en la función anterior), lafunción deberá ser capaz de interpretar el argumento dela cadena de acuerdo con el modo especificado:Si no se especifica el argumento modo se asume elestablecido por la variable de Autocad LUNITSValor retornado: Un valor correspondiente al numérico de unángulo en radianes.

Page 177: Autolisp Gera

CVUNIT

Convierte un número ó lista de números de una unidad demedida a otra (Las cadenas que representan unidades demedida válidas en esta función están almacenadas en elfichero ACAD.UNT)

Sintaxis: (CVUNIT )cadvie: cadena de unidad de medida vieja.cadnue: cadena de unidad de medida nueva.Valor retornado: Un número o lista de números convertida a launidad de medida nueva.

TRANS Transforma las coordenadas de un punto de un sistema decoordenadas a otro.

Sintaxis:(TRANS

[desp])codvie: código que expresa el sistema de coordenadas enel cual se expresa el punto.codnue: código que expresa el sistema de coordenadas enel cual se quiere expresar el punto0. SCU1. SCP2. SCV (visualización)3. SCV espacio papeldesp : si es distinto de nil, entiende el primerargumento como un desplazamiento.Valor retornado: Una lista de punto con sus coordenadastransformadas.

READ Extrae datos de una cadena de caracteres

Sintaxis: (READ )Valor retornado: El primer ítem de una cadena de caracteres óla primera lista si la cadena contiene listas.

Ejemplo:

Page 178: Autolisp Gera

(READ “hola a todos”) hola(READ “(20 30 40)”) (20 30 40)

ASCII Convierte el primer carácter de una cadena de caracteresa su código ASCII

Sintaxis: (ASCII )Valor retornado: Un entero que representa el código ASCII

ATOF Convierte una cadena de caracteres en un número real

Sintaxis: (ATOF )Valor retornado: un número real

ATOI Convierte una cadena de caracteres en un número entero

Sintaxis: (ATOF )Valor retornado: un número entero

CHR Convierte un número entero que representa un carácterASCII en la cadena de un sólo carácter

correspondiente

Sintaxis: (CHR )Valor retornado: una cadena de un sólo carácter

ITOA Convierte un entero en una cadena de caracteres

Sintaxis: (ITOA )Valor retornado: una cadena de caracteres

FIX Convierte un número real en entero.

Sintaxis: (FIX )Valor retornado: El número entero que resulta de quitar losdecimales al real.

FLOAT Convierte un número entero en real.

Sintaxis: (FLOAT )Valor retornado: un numero real

FUNCIONES DE CONTROL DE PANTALLA.

Page 179: Autolisp Gera

REDRAW Redibuja la pantalla de presentación (ó las entidadesespecificadas)

Sintaxis: (REDRAW ) (sintaxis simplificada para el redibujadode la pantalla)Valor retornado: nil

GRAPHSCR Fuerza la presentación de pantalla gráfica en sistema depantalla única.

Sintaxis: (GRAPHSCR)Valor retornado: nulo

TEXTSCR Presenta la pantalla texto en sistemas de pantalla única

Sintaxis: (TEXTSCR)Valor retornado: nulo

TEXTPAGE Presenta la pantalla texto en sistemas de pantalla únicay la limpia

Sintaxis: (TEXTPAGE)Valor retornado: nulo

VPORTS Extrae los números de identificación de las ventanasgráficas

Sintaxis: (VPORTS)Valor retornado: Una lista de sublistas donde los elementos decada sublista son:1. El número de identificación de cada ventana gráfica.2. Coordenadas de la esquina inferior izquierda(coordenadas normalizadas).3. Coordenadas de las esquina superior derecha..

FUNCIONES PARA MANEJAR CADENAS DE TEXTO

READ Extrae datos de una cadena de caracteres

Sintaxis: (READ )Valor retornado: El primer ítem de una cadena de caracteres óla primera lista si la cadena contiene listas.

Page 180: Autolisp Gera

STRCASE Convierte los caracteres de una

cadena a minúsculas omayúsculas

Sintaxis: (STRCASE )[modo])conversión a minúsculas: modo=/ nilconversión a mayúsculas : modo=nil ó no se presenta.Valor retornado: La cadena convertida

STRCAT Empalma (concatena) dos ó mas cadenas

Sintaxis: (STRCAT ["cadena2"]...........)Valor retornado: Una sola cadena empalmada.

STRLEN Cuenta los caracteres de una cadena

Sintaxis: (STRLEN )Valor retornado: Un número entero

SUBSTR Extrae una porción de una cadena de caracteres.

Sintaxis: (SUBSTR [ long ])inicio: número entero que indica la posición de primercarácter a extraer.long: longitud de la subcadena a extraer ( si no se daproporciona la subcadena desde la posición inicialhasta el final)Valor retornado: La subcadena extraída

OTRAS FUNCIONES DE UTILIDAD

EVAL Evalúa expresiones

Sintaxis:(EVAL )Valor retornado: El valor retornado por la expresión evaluadaEn la línea de ordenes la abreviatura es el signo !

QUOTE Procesa una instrucción sin evaluarla

Sintaxis:(QUOTE )Valor retornado: La expresión sin evaluarlaLa sintaxis alternativa es el apóstrofo. No puede usarse en elindicador Command.

Page 181: Autolisp Gera

NULL Comprueba si una expresión se evalúa como nulo

Sintaxis: (NULL )Valor retornado:T si la expresión evaluada es nulonil en caso contrario.

QUIT Fuerza a la rutina actual a abandonar el procesamiento.

Sintaxis: (QUIT)Valor retornado:El mensaje “quit/exit abort” (abandonar/salir abortar)

NUMBERP Comprueba si la evaluación de una función es un número

Sintaxis: (NUMBERP )Valor retornado:T si la expresión evaluada es un numeronil en caso contrario.