Professional Documents
Culture Documents
Interfaces de programacin
AutoCAD dispone varios entornos de programacin, la seleccin del tipo de interfaz a emplear para crear una aplicacin depender de las necesidades de la aplicacin y de la experiencia o conocimientos del programador/es: AutoLISP es una adaptacin del lenguaje de programacin CommonLISP para AutoCAD. Es sencillo de aprender y al mismo tiempo potente. AutoCAD cuenta con un intrprete interno de LISP que permite introducir cdigo desde la lnea 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 aplicacin 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 programacin basado en objetos que utiliza ntegramente la sintaxis del lenguaje Visual Basic y permite usar controles ActiveX. Permite tambin la integracin 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 programacin de lenguaje compilado para el desarrollo de aplicaciones de AutoCAD. El entorno de programacin ObjectARX incluye varias bibliotecas de vnculos dinmicos (DLL) que ofrecen acceso directo a las estructuras de la base de datos, el sistema de grficos y los dispositivos de geometra de AutoCAD De momento nos centraremos en la programacin sobre AutoCAD utilizando el interprete interno de AutoLISP para pasar en breve al entorno de Visual LISP y posteriormente a la programacin en VBA.
Caractersticas de AutoLISP
El LISP fue desarrollado a finales de los aos 50 por John McCarthy, es el segundo lenguaje de programacin ms antiguo solo precedido por Fortran. Uno de los campos en los que es ms empleado es en la investigacin en inteligencia artificial. Su nombre proviene de LISt Procesing (Procesado de listas), pues se basa en el uso de listas en lugar de datos numricos. Aunque hay quien mantiene en tono jocoso que su nombre proviene de Lost In Stupid Parenthesis. AutoLISP aade al LISP algunas funciones especialmente diseadas para la manipulacin de las entidades de AutoCAD. AutoLISP es un lenguaje evaluado. El cdigo se convierte a lenguaje mquina (ceros y unos) y se almacena en la memoria temporal. No es tan lento como los lenguajes interpretados, ni tan rpido como los compilados : en los lenguajes interpretados, se va traduciendo el programa a cdigo mquina (el idioma de los ordenadores) a medida que se ejecuta en los lenguajes compilados, el cdigo fuente (texto) del programa se traduce a cdigo mquina generando un archivo ejecutable (.EXE) que es el que ejecutar el programa Hay quien dice que AutoLISP es lento comparndolo con otros lenguajes como Pascal o C, especialmente cuando se utilizan muchas funciones matemticas. Sin embargo, cuando se utiliza manipulando smbolos los resultados son muy distintos. Esto hace de AutoLISP un excelente lenguaje para la programacin de sistemas CAD, ya que un sistema CAD no es ms que un entorno de manipulacin de smbolos grficos. Una de las caractersticas ms 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 informacin se puede modificar, extraer e incluso aadir ms entidades al dibujo o informacin adicional. La mayora de los primeros lenguajes de programacin 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 informacin de los objetos de AutoCAD para determinar de que informacin se dispone, preguntndole a los objetos por ellos mismos. AutoLISP no es estrictamente un lenguaje orientado al objeto, pero contiene bastantes caractersticas 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 r edefinir los comandos de AutoCAD para que funcionen de forma distinta, por ejemplo podramos redefinir el comando POLIGONO para que dibuje polgonos estrellados en lugar de los regulares. Una mencin especial merece el uso de AutoLISP en la realizacin de programas paramtricos y en el diseo semiautomtico, ya que entre el 60% y el 80% del diseo est dedicado a la modificacin de diseos previos. En los programas paramtricos, el usuario introduce una serie de datos o parmetros a partir de los cuales el programa realiza el diseo 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 creacin 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 programacin. Adems aade nuevos comandos para permitir la interaccin 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 captulos del curso se trabajar desde la ventana de comandos de AutoCAD. A partir del tercer captulo 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 cdigo, es decir escribir el cdigo todo seguido. Esto es debido a que cada vez que se pulsa Intro, AutoCAD evala lo que se ha escrito en segundo lugar, al terminar la sesin de trabajo en AutoCAD se perdern todos los datos almacenados en la memoria temporal
Ejemplo: (+ 1 2) Ejecuta la funcin + que realiza la suma de los argumentos 1 y 2 devuelve el resultado 3. (+ 31 22 -3) Ejecuta la funcin + que realiza la suma de los argumentos 31, 22 y -3 devuelve el resultado 50. Prueba tambin: (- 17 2) (+ 2.5 22.8) (- 0.25 22.5) (+ 12 -2 31 -7.5) Ejemplo: (+ (* 2 3) 2) devuelve 8. Recuerda que primero evala la lista interior y devuelve su resultado a la exterior. (+ 7 (/ 5.0 2) -3) devuelve 6.5. Qu sucedera si al escribir la expresin (+ 1 (/ 5.0 2)) nos olvidsemos de escribir el ltimo parntesis? Haz la prueba, veras que AutoCAD te indica que falta 1 parntesis de cierre. Si el interprete de comandos de AutoCAD encuentra un parntesis de apertura, supone que todo lo que vaya a continuacin hasta el parntesis de cierre es una expresin de AutoLISP. De modo que enva esa expresin al interprete de AutoLISP para que la evale. En el siguiente captulo veremos algunas de las operaciones matemticas que se pueden realizar con AutoLISP.
Notacin empleada
Para describir las funciones de AutoLISP que se expliquen a lo largo del curso se seguir la siguiente notacin: (FUNCIN Argumentos_necesarios [Argumentos_opcionales] ) Los nombres de las funciones de AutoLISP y el cdigo a teclear se mostrarn en negrita.
Convenciones recomendadas
En este apartado se indicarn una serie de convenciones recomendables a la hora de programar. Alguna de ellas puede que an no las entiendas, pero no te preocupes porque las iremos recordando a medida que avancemos en el curso. para los comentarios incluidos en el cdigo, se recomienda utilizar el siguiente mtodo: ;;; Antes del cdigo de las funciones, explicando su funcionamiento ;; En medio del cdigo del programa ; Para explicar una lnea de cdigo. A diferencia de las anteriores, esta no se inserta en la columna 1, se insertar al terminar el cdigo de la lnea que comenta es muy recomendable utilizar un formato tabulado para el cdigo evitar el uso de variables globales innecesarias
utilizar los comandos de AutoCAD y sus opciones en Ingls y precedidos por ._ no abusar de la funcin SETQ no utilizar T, MIN, MAX, LAST como smbolos (nombres de variables y funciones) recuperar el valor inicial de las variables de sistema de AutoCAD que han sido modificadas aadir unas lneas al final del programa para indicar el nombre del nuevo comando, autor, etc. no introducir demasiado cdigo en la funcin principal incluir una funcin de tratamiento de errores evitar que el usuario pueda introducir datos errneos 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
Qu es una variable?
No sabes qu es una variable? Recuerdas cuando en la escuela te decan Tengo 3 melones, le doy uno a Juan y despus de comprar otros 2, me com uno porque tena hambre. Pues los melones son una variable. Nosotros hacamos: 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 ms que un valor que vara (o puede hacerlo) a lo largo del tiempo. Pero podamos haber llamado a la variable yo z, y por qu no melones?
(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 tena la variable b en ese momento, no se estableci ninguna relacin entre ambas variables. Tambin se puede asignar valores no numricos a las variables. Por ejemplo, una cadena de texto. Las cadenas de texto son secuencias de uno o ms caracteres encerrados entre comillas. Dentro de una cadena de texto pueden insertarse una serie de carcteres de control: \\ representa al smbolo \ \ representa al smbolo \n representa un cambio de lnea (retorno del carro) \t representa una tabulacin (setq a \tBienvenido al Curso Introduccin a la programacin en AutoCAD ) En este caso adems, 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 cdigo. Pero tambin supone que se requiera ms cuidado para no pasar a una funcin 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 nmero. Existen una serie de smbolos predefinidos: T Representa al valor lgico Cierto o Verdadero. nil Representa al valor lgico 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 Vaco o Falso. Para almacenar el radio de la circunferencia de permetro 6 unidades en una variable podemos teclear: (setq rad (/ 6 (* 2 PI))) Podramos crear una circunferencia e indicar !rad a AutoCAD cuando nos pregunte por el radio deseado. Ejemplo: Por qu las siguientes expresiones estn 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 funcin suma, sino a una variable de valor 23. De modo que el primer termino de la expresin anterior ahora no es una funcin, por lo que da un error. Para recuperar el modo habitual de trabajo de la funcin + es necesario cerrar la sesin actual de AutoCAD e iniciar una nueva sesin.
(1+ <nmero> )
Esta funcin incrementa en una unidad el nmero indicado como argumento. (1+ 5) devuelve 6. Ojo entre 1 y + no debe haber ningn espacio, ya que el nombre de la funcin es 1+. (1+ 2.5) devuelve 3.5 (1+ 0) devuelve 1 (1+ -7) devuelve -6 Una aplicacin bastante habitual de esta funcin es la de incrementar ndices o contadores: (setq i 1) (setq i (1+ i)) devuelve 2
(1- <nmero> )
Esta funcin reduce en una unidad el nmero indicado. (1- 5) devuelve 4. Ojo entre 1 y - no debe haber ningn espacio, ya que el nombre de la funcin es 1-. (1- 2.5) devuelve 1.5
(GETINT [mensaje] )
Solicita del usuario un nmero entero. En caso de que el usuario introduzca un nmero real o cualquier otro dato que no sea un nmero entero, AutoCAD recordar mediante un mensaje que est solicitando un nmero entero y no finalizar la ejecucin de la funcin hasta que se introduzca un valor entero, o se pulse ESC para cancelar su ejecucin. (getint) Puede indicarse un mensaje de solicitud opcional, que facilite al usuario informacin acerca de lo que se est pidiendo. El mensaje debe ser una cadena de texto y por tanto debe estar entre comillas. (getint Cuntos aos tienes?:) Podemos asignar el valor introducido por el usuario a una variable y as utilizarlo despus. (setq edad (getint Cuntos aos tienes?:)) (setq edad (+ edad 1)) nos dar la edad que tendrs el prximo ao. Tambin puedes crear una variable que contenga el mensaje de solicitud de la funcin GETINT (setq mens Cuntos aos tienes?:) (setq edad (getint mens)) 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 Cuntos aos tienes?:) (setq edad (getint mens)) Que pasar si como respuesta a la solicitud de la edad del usuario se introduce !a. Parece lgico que le estamos indicando el valor de la variable a, que contiene el valor numrico 27, de modo que la variable edad debera 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 funcin 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 ejecucin, no puede volver a ejecutarse y nos muestra el mensaje anterior.
(GETREAL [mensaje] )
Solicita del usuario un nmero real. En caso de que el usuario introduzca un nmero entero, el interprete de AutoLISP lo considerar como un real. Si se introduce cualquier otro tipo de dato que no sea numrico, recordar mediante un mensaje que est solicitando un nmero real y no finalizar la ejecucin de la funcin hasta que se introduzca un valor numrico, o se pulse ESC para cancelar su ejecucin. (getreal) Puede indicarse un mensaje de solicitud opcional, que facilite al usuario informacin 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 Cuntos kilos pesas?:)) (setq peso (- peso 1)) nos dar el peso que tendrs si adelgazas un kilo. Tambin puedes crear una variable que contenga el mensaje de solicitud de la funcin GETREAL (setq mens Cuntos kilos pesas?:) (setq peso (getreal mens))
Despus de indicar el nombre de la funcin, se deben indicar entre parntesis los argumentos y las variables locales, separados por una barra inclinada: los argumentos son valores que recibir la funcin cuando sea ejecutada por el usuario, o llamada desde otras funciones las variables locales son aquellas variables que se emplearn tan solo dentro de la funcin que queremos definir, de modo que restringimos su uso al entorno de la funcin Por ltimo, se aaden las expresiones que ejecutar la funcin. Veamos algunos ejemplos: (defun 2+ ( valor ) (+ valor 2)) En este caso hemos definido una nueva funcin llamada 2+, que recibe como argumento un nmero y realiza la suma de ese nmero y 2. Las funciones de AutoLISP las ejecutamos escribiendo directamente desde la lnea 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 expresin ejecutada, que en el caso anterior es (+ valor 2). Que sucede si tratamos de ejecutar la funcin sin pasar ningn argumento, o pasando un argumento que no sea de tipo numrico?. Veamos: (2+ ) indica ; error: argumentos insuficientes (2+ texto) indica ; error: tipo de argumento errneo: numberp: texto" (2+ 1 2) indica ; error: demasiados argumentos Podras pensar que el nmero indicado se almacena en una variable llamada valor, pero no es as. Puedes comprobarlo escribiendo !valor en la lnea de comandos, lo que nos devolver nil. En la funcin 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 razn: (2+ 5) devuelve 7 !valor devuelve nil La funcin 2+ recibe como argumento un nmero, que almacena en la variable valor. Pero el mbito de aplicacin es local, es decir una vez que salgamos de la funcin 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 nmero entero 5 cuando llamamos a la funcin 2+ con la expresin (2+ 4) tenemos que valor es 4 dentro de la funcin 2+ asignamos (setq valor (+ valor 2)) de modo que valor ser 6 pero como se trata de una variable local, al salir de la funcin 2+ recuperamos el valor que tena la variable valor antes de llamar a la funcin, 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 funcin 2+ le asignamos a valor el valor devuelto por la funcin, que es 6. De modo que valor ser 6. Retoquemos un poco ms la funcin 2+ (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 funcin 2+ declaramos una variable a la que se le asigna el valor que recibe como argumento la funcin. (2+ 4) Que valor tendrn ahora las variables valor e inicial? Vamos a comprobarlo: !valor devuelve nil tal como suceda en el ejemplo anterior !inicial devuelve 4 Observa que valor se comporta como una variable local, solo se emplea dentro de la funcin. Sin embargo inicial es de mbito global, es decir se sigue empleando al salir de la funcin. Vamos a modificar un poquito ms nuestra funcin: (defun 2+ ( valor / inicial ) (setq inicial valor valor (+ valor 2))) Ahora hemos aadido 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 modificacin de la funcin 2+
(defun 2+ ( / valor ) (setq valor (getint Nmero: )) (setq valor (+ valor 2))) Ahora la funcin 2+ no tiene argumentos, as que para ejecutarla tan solo debemos poner su nombre entre parntesis: (2+) La variable valor es de mbito local y se emplea GETINT para solicitar un nmero 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 debern aadir a la lista de variables locales dentro de las definiciones de las funciones de usuario.
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:
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 cmo funcionan estas ventanas. Estamos ante un editor de textos, como otro cualquiera, pero con utilidades especficas para la programacin 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:
Es en esta pantalla donde vamos a escribir el cdigo de nuestra rutina RAG, pero antes un pequeo comentario Es bastante habitual aadir al principio de los archivos de AutoLISP unas lneas de comentarios indicando el nombre del autor, fecha, nombre de los comandos y/o funciones definidas en el archivo, y una breve descripcin de estos. De modo que al cdigo anterior le aadiremos unas lneas en la cabecera del archivo: ;;;____________________Eduardo Magdalena____________________;;; ;;;_________________________RAG.LSP___________________________;;; ;;;_______________________Versin 1.0_________________________;;; ;;;________________________21/02/2002_________________________;;; ;;; Esta funcin 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 LISP realiza las tabulaciones automticamente. Y aunque se pueden eliminar o modificar a nuestro gusto (aadiendo o quitando espacios y tabulaciones), lo recomendable es mantener el formato por defecto para el cdigo. Veamos como queda la funcin RAG en el editor:
En primer lugar observamos que el cdigo 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 parntesis en color rojo (setq a 2.0) los nmeros en color verde 2.0 los textos en color rosa (en este ejemplo no aparece ningn texto, pero veremos algunos ejemplos ms adelante) Soy un texto el resto de elementos, como los nombres de las funciones y de las variables utilizadas, se muestran en color negro Adems, las funciones de usuario se destacarn escribindose en maysculas RAG. Este formato de colores se utilizar tambin en los artculos de este curso, tal como se muestra en el cdigo de la funcin RAG anterior. El formato coloreado del cdigo se puede desactivar, o se pueden modificar los colores predefinidos para los diferentes elementos. Pero el mantener el formato de colores para el cdigo, 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 funcin de AutoLISP es SETQ, de modo que nos indica que hemos escrito mal el nombre de la funcin. En cuanto a la tabulacin, tal vez llame la atencin el ltimo parntesis (el de cierre de la funcin defun), ya que no est a la misma altura que su parntesis de apertura. Hay editores para AutoLISP que insertan los parntesis de cierre a la misma altura que sus correspondientes parntesis de apertura y hay otros editores que insertan los parntesis de cierre tabulados, tal como hace (por defecto) el editor de Visual LISP. Una vez escrito el cdigo de la funcin RAG, tan solo nos queda guardarlo en un archivo. Es recomendable crear un directorio (carpeta) en el que guardar todas nuestras rutinas. Veremos ms adelante que se pueden guardar varias funciones y varios comandos en un mismo archivo de AutoLISP, aunque en este caso slo se ha definido una nueva funcin de usuario. Se le suele dar a los archivos de AutoLISP el mismo nombre del comando o funcin que est definida en l, podemos guardar esta rutina en el archivo klhsduif.lsp pero luego no la reconoceramos. As que lo mejor ser guardar el cdigo de la funcin 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 funcin llamada GAR que reciba como argumento un ngulo en grados decimales y que devuelva ese ngulo en radianes. Es prcticamente igual a la funcin 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 cmo lo vamos a hacer. Como esta rutina es muy sencilla no es necesario escribir el pseudocdigo (ni hacer un diagrama de flujo), tan solo hay que pensar un poco en lo que se va a hacer. Guarda el cdigo de la funcin GAR en un archivo llamado GAR.lsp en el directorio donde tengas tus rutinas.
Pulsando sobre el icono . Tecleando la combinacin 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 algn error en el proceso de carga del archivo, en la consola de Visual LISP se nos indicara el tipo de error que se ha producido. De modo que habria que modificar el cdigo 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 mtodo para cargar un archivo de AutoLISP en AutoCAD (seleccionando en el men de AutoCAD Herr>AutoLISP >Cargar aplicacin) muestra un letrero de dilogo en el que se selecciona el archivo a cargar y se pulsa el botn Cargar.
Este mtodo ofrece dos ventajas: se puede seleccionar ms de un archivo permite descargar las funciones de AutoLISP definidas en los archivos seleccionados
La funcin LOAD permite cargar en AutoCAD el archivo de AutoLISP que se indique. Por ejemplo para cargar el archivo RAG sera: (load rag) No hace falta indicar la extensin del archivo. Escribiendo as el nombre del archivo solo cargar el archivo RAG.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: (load c:\rutinas\rag.lsp) Pero si lo hiciramos as nos dara un error, ya que AutoCAD no reconoce el carcter \, 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 expresin 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 funcin de AutoLISP, podamos indicarle al usuario que no se ha encontrado el archivo. Como indica el siguiente pseudocdigo: Si test = 0 ==> Mensaje al usuario Archivo no encontrado Esto es todo, de momento, sobre la carga de archivos de AutoLISP en AutoCAD. Ms adelante veremos otros mtodos para cargar nuestras rutinas. Veamos como sera la funcin GAR propuesta en el tema anterior: ;;;_____________________Eduardo Magdalena_____________________;;; ;;;_________________________GAR.LSP___________________________;;; ;;;_______________________Versin 1.0_________________________;;; ;;;________________________21/02/2002_________________________;;; ;;; Esta funcin 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 funcin RAG, no?
Opciones de AutoCAD
Tambin 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.
(ABS numero)
Esta funcin devuelve el valor absoluto del nmero que se le pase como argumento. Por ejemplo: (abs 23.8) devuelve 23.8 (abs -23.8) tambin devuelve 23.8 Si el nmero que recibe como argumento es entero, devuelve un nmero entero y si es un nmero real, devuelve un real. (abs -7) devuelve 7 (abs -7.0) devuelve 7.0 (abs 0) devuelve 0
(FIX numero)
Esta funcin devuelve la parte entera de un nmero. De modo que devuelve un nmero entero. Ojo! esta funcin no redondea, sino que elimina lo que est detrs del punto decimal. (fix 15.8) devuelve 15. (fix -15.8) devuelve -15 (fix 0.99) devuelve 0 (fix -0.99) devuelve 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
(SQRT numero)
Esta funcin devuelve la raiz cuadrada del numero que recibe como argumento. Siempre devuelve un nmero real, no entero. (sqrt 4) devuelve 2.0 (sqrt 2.0) devuelve 1.41
(EXP num)
Devuelve el nmero e ( e = 2.71828 ) elevado al nmero num. Siempre devuelve un nmero real. (exp 1) devuelve 2.71828 (exp 2) devuelve 7.38906
(LOG numero)
Esta funcin devuelve el logaritmo neperiano del nmero que recibe como argumento. (log 1) devuelve 0.0 (log 2) devuelve 0.693147
(CAR lista)
Esta funcin 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 funcin 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)
Basndonos en las dos funciones anteriores y recordando que podemos ejecutar listas de instrucciones dentro de otras (a esto le llamamos anidamiento): Cmo se obtendra 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, cmo obtenemos la coordenada Z? Pues, volviendo a aplicar la funcin CDR para llegar a la coordenada Z (cdr pto) devuelve (Y Z) (cdr (cdr pto)) devuelve (Z) Podras pensar que escribiendo (cdr (cdr pto)) obtenemos la coordenada Z, sin embargo no es as. La expresin (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: X ==> (car pto) Y ==> (car (cdr pto)) Z ==> (car (cdr (cdr pto)))
Cmo obtendramos 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?
(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
Cmo 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 cmo 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
(LENGTH lista)
En la variable pto tenamos 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 slo tendrn 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 producindose un error en nuestra rutina. As que necesitamos conocer el nmero de elementos que tienen las listas. Para ello se utiliza la funcin length, que devuelve el nmero 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) devolvera 2. Y qu devolvera (length lst) ? siendo lst = ((a b) (c d) (e f)). Pues devolvera 3, ya que lst es una lista con 3 elementos, que a su vez son listas de dos elementos cada una. Qu devolvera (length (car lst)) ? El nmero de elementos del primer elemento de lst, es decir el nmero de elementos de (a b), que es 2.
AutoCAD en realidad no habla un nico idioma, sino que es bilingue, dispone de una l engua que es la que muestra (que corresponde con la versin idiomtica del programa: Castellano, Francs, etc) y una lengua interna, el Ingls. De modo que los comandos de AutoCAD (y sus opciones) se pueden escribir en Castellano o en ingls. Pero para diferenciar unos de otros a los comandos en la lengua nativa de AutoCAD (Ingls) se les antepone un guin 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 tambin se deben indicar en ingls anteponiendo un guin bajo. Por ejemplo: (command _circle (list 0.0 0.0) _d 25.0) Esta lnea dibuja una circunferencia de Dimetro 25 con centro en el origen.
Operaciones de comparacin
En este artculo 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 nmeros, tambin 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 maysculas que en minsculas. (= LISP Lisp) devuelve nil Estamos comparando expresiones, as que: (= (+ 1 5) (/ 12 2)) devuelve T porque ambas expresiones devuelven como resultado 6. La funcin = puede aceptar ms 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).
Macro de ejemplo
Veamos como se hara el ejercicio propuesto en el artculo anterior: Crear un nuevo comando llamado CIRCPERIque dibuje una circunferencia indicando su centro y la longitud de su permetro. Qu es lo primero que hay que hacer? Esta respuesta tiene que ser instintiva, como un acto reflejo: El pseudocdigo. Siempre comenzaremos nuestras rutinas escribiendo el pseudocdigo (o haciendo un diagrama de flujo) de lo que se pretende hacer. Bien, cmo podra ser el pseudocdigo de esta rutina?, vamos a ver: 1. Pedir al usuario el centro de la circunferencia. 2. Pedir al usuario el permetro de la circunferencia.
3. Calcular el radio de la circunferencia a partir de su permetro. 4. Dibujar la circunferencia. Una vez que terminamos el pseudocdigo, ya tenemos el 80% de la rutina. Si el pseudocdigo es correcto, el traducirlo a cdigo es de lo ms simple. Iniciamos en editor de Visual LISP Herr. > AutoLISP > Editor de Visual LISP y creamos una nueva macro. Primero hay que aadir la definicin del nuevo comando CIRCPERI: (defun C:CIRCPERI ( ) Vamos a ver que es lo que nos indica el pseudocdigo: 1) Pedir al usuario el centro de la circunferencia. Podramos escribir (getpoint Centro de la circunferencia) pero tendramos que almacenar el punto indicado en una variable, as que aadiremos (setq pto (getpoint Centro de la circunferencia)) almacena el punto centro de la circunferencia en la variable pto. 2) Pedir al usuario el permetro de la circunferencia . Por ejemplo (setq peri (getint Permetro:)) pero al usargetint, solo permite obtener nmero enteros. As que podramos cambiarlo por: (setq peri (getreal Permetro:)) almacena el permetro de la circunferencia en la variable peri 3) Calcular el radio de la circunferencia a partir de su permetro . Peri = 2* pi * rad as que rad = Peri / ( 2 * pi). Traduciendo esta frmula a cdigo: (setq rad (/ peri (* pi 2))) calcula el valor del radio de la circunferencia 4) Dibujar la circunferencia (command _.circle pto rad) dibuja la circunferencia Slo nos falta una cosa. Recuerda: El nmero de parntesis de apertura tiene que ser igual al nmero de parntesis de cierre . As que: ) El cdigo completo de la rutina sera: (defun C:CIRCPERI ( ) (setq pto (getpoint Centro de la circunferencia)) (setq peri (getreal Permetro:)) (setq rad (/ peri (* pi 2))) (command _.circle pto rad) ) Tambin deberas aadir comentarios al cdigo y una cabecera con varias lneas de comentarios en el archivo .LSP indicando: El nombre de la rutina, fecha, autor, etc. Te das cuenta de la importancia del pseudocdigo? Al programar nos ha guiado paso a paso.
(NOT expr)
A esta funcin le gusta llevarle la contraria a la expresin que recibe como argumento. si la expresin devuelve nil, entonces NOT devuelve T. si la expresin 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 expresin: (and (not c) 5) Como c es T, (not c) devuelve nil. Al no cumplirse la primera expresin de AND, esta devuelve nil y no contina evaluando.
En este caso la condicin devuelve nil y al no existir expresin no cumple, no hara nada ms. Qu valor devolvera IF? El de siempre, el valor de la ltima expresin evaluada, que en este caso ha sido la propia condicin que devuelve nil. De modo que IF devolver nil. (if (= 2 3) (alert Los nmeros son iguales) (alert Los nmeros son distintos) ) En este caso el cdigo se ha escrito en varias lneas y tabulado para facilitar su comprensin. Ahora si tenemos una expresin no cumple, que ser evaluada ya que la condicin devuelve nil. Veamos el siguiente ejemplo: (setq liminf (getint \nLmite inferior:)) (setq limsup (getint \nLmite superior:)) (if (> liminf limsup) (alert El lmite superior debe ser mayor que el inferior) (setq limsup (getint \nLmite superior:)) (setqintervalo (- limsup liminf)) (setq intervalo (- limsup liminf)) ) Viendo el cdigo anterior, tal vez pienses que si la condicin (> liminf limsup) se cumple, entonces se evaluar la lnea siguiente de cdigo completa. Pero no es as, se evala la expresin si cumple, que es la primera expresin(alert El lmite superior debe ser mayor que el inferior). Si la condicin no se cumple, devuelve nil, se evaluar la expresin no cumple, que en este caso ser (setqlimsup (getint \nLmite superior)). Tanto la expresin si cumple, como la no cumple solo pueden ser una nica expresin . El ejemplo de cdigo anterior nos dara un error ya que IF no puede tener ms que 3 expresiones: La condicin La expresin si cumple La expresin no cumple
(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 evalundose la expresin no cumple. Otro mtodo para hacer lo mismo, sera: (if var1 (alert Variable definida) (alert Variable no definida) ) Si var1 es distinto de nil, se evala la expresin si cumple. En caso de que var1 sea nil, se evaluara la expresin no cumple.
((= 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)) ) 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.
(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. Tambin devuelve nil. Se utiliza principalmente para avisar al usuario en caso de error, o para mostrar alguna informacin importante. (alert Error: Dato no vlido)
(TERPRI)
En artculo correspondiente a las Operaciones de comparacin, creamos un nuevo comando para AutoCAD denominado CIRCPERI. Si has cargado y ejecutado el comando, habrs observado que los mensajes para solicitar el centro de la circunferencia y su permetro aparecen en la misma lnea de la ventana de comandos y sin separacin entre s, estn pegados. Para que los mensajes aparezcan en lneas distintas, se puede emplear la funcin TERPRI. Esta funcin mueve el cursor a una nueva lnea en la ventana de comandos de AutoCAD, y devuelve nil. El cdigo de la rutina quedara as: (defun C:CIRCPERI ( ) (setq pto (getpoint Centro de la circunferencia)) (terpri) (setq peri (getreal Permetro:)) (terpri) (setq rad (/ peri (* pi 2))) (command _.circle pto rad) ) As los mensajes de solicitud aparecern en lneas separadas.
(setq peri (getreal \nPermetro:)) (setq rad (/ peri (* pi 2))) (command _.circle pto rad) ) Un par de cosas ms con respecto a esta rutina Cuando se crea un archivo LISP en el que est definido un nuevo comando es bastante til aadir al final de todo el cdigo algo similar a (prompt \nNuevo comando CIRCPERI cargado) Esta lnea se pondra despus del parntesis de cierre de defun. Es decir, que cuando se ejecuta CIRCPERI desde AutoCAD esta lnea no se evala. 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 slo se mostrar al cargar el archivo. Por otro lado si recordamos la estructura de la funcin DEFUN: (DEFUN nombre_funcin ( argumentos / variables_locales ) expr1 expr2 ) Veremos que en la rutina CIRCPERI no hemos indicado variables locales, as que todas las variables sern globales. Es decir que al ejecutar CIRCPERI y dibujar un crculo, 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. Slo habra que cambiar la siguiente lnea (defun C:CIRCPERI ( / pto peri rad ) OJO! la barra inclinada / hay que ponerla, sino seran argumentos y no variables locales. El cdigo completo de la rutina es el siguiente: ;;;____________________Eduardo Magdalena____________________;;; ;;;______________________CIRCPERI.LSP_________________________;;; ;;;_______________________Versin 1.1_________________________;;; ;;;________________________26/02/2002_________________________;;; ;;; Comando para dibujar una circunferencia indicando su centro y la longitud ;;; de su permetro. (defun C:CIRCPERI ( / pto peri rad ) (setq pto (getpoint \nCentro de la circunferencia)) (setq peri (getreal \nPermetro:)) (setq rad (/ peri (* pi 2))) (command _.circle pto rad) ) (prompt \nNuevo comando CIRCPERI cargado)
No guardadas. La informacin asignada a este tipo de entidades no se guarda. Un ejemplo de este tipo de variables es acadver. En el dibujo. La mayora 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 definicin 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 mayora 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 mtodos para modificar los valores asignados a las variables de sistema de AutoCAD: Tecleando el nombre de la variable, como si fuese un comando ms 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 algn comando de AutoCAD. Por ejemplo circlerad almacena el radio de la ltima circunferencia creada con el comando crculo.
(GETVAR variable)
Esta funcin devuelve el valor asociado a la variable que recibe como argumento. Por ejemplo: (getvar osmode) (getvar blipmode) (getvar acadver)
(ITOA entero)
Convierte un entero en un texto. Integer TO Atom. (itoa 24) devuelve 24
(ATOI texto)
Hace justo lo contrario que la funcin anterior. Convierte un texto en un nmero. 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 nmero devuelve cero. (atoi 15.3) devuelve 15 (atoi 15.99999) devuelve 15
(FLOAT numero)
Convierte un nmero en real, as que lo lgico es que reciba un entero como argumento. (float 5) devuelve 5.0
pero tambin podemos pasar un nmero real como argumento (float 5.36) que devuelve 5.36 lo cual sera una tontera porque en ese caso la funcin 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
Vamos ahora a modificar un poco la macro CIRCPERI. Tenamos el siguiente cdigo: (defun C:CIRCPERI ( / pto peri rad ) (setq pto (getpoint \nCentro de la circunferencia: )) (setq peri (getreal \nPermetro: )) (setq rad (/ peri (* pi 2))) (command _.circle pto rad) ) (prompt \nNuevo comando CIRCPERI cargado) Si sustituimos la funcin getreal por getdist adems de poder escribir un permetro directamente, tambin podremos indicarlo mediante dos puntos.
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 cdigo del punto 3. Podramos hacerlo de dos formas: (setvar cmdecho cmd0) Esta lnea de cdigo asignara a cmdecho el valor que tena 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 cdigo quedara 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 \nPermetro: )) (setq rad (/ peri (* pi 2))) (command _.circle pto rad) (if (= cmd0 1) (setvar cmdecho 1) ) ) (prompt \nNuevo comando CIRCPERI cargado)
Recuerda, antes de ponerse a escribir cdigo hay que: escribir el pseudocdigo. Veamos, podamos hacer algo as: 1. Obtener el centro de la circunferencia 2. 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 ingls donuts) as que buscaremos otro nombre para nuestra rutina, por ejemplo ARAND. Es mejor utilizar nombres ms bien cortos y que evoquen a la funcin que tiene el comando. La primera lnea de cdigo es la definicin de la funcin: (defun C:ARAND ( ) Ms adelante podremos aadir las variables locales, si es que existen. 1) Obtener el centro de la circunferencia. Podra 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 crculo exterior: (setq rade (getreal \nRadio exterior: )) 5) Dibujar el circulo exterior (command _.circle pto rade) Y por ltimo cerramos el parntesis de la funcin defun ) El cdigo 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 aadiremos 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. Aadir una lnea al final del cdigo para que muestre un mensaje indicando el nombre del nuevo comando al cargar la funcin. 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. Aadir una lnea al final de la funcin para que la salida del programa sea limpia. El cdigo despus de realizar las mejoras anteriores sera: (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: )) (command _.circle pto rad) (if (= cmd0 1) (setvar cmdecho 1) ) (princ) ) (prompt \nNuevo comando ARAND cargado) Adems 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 algn 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 despus 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
Al seleccionar Control nos ofrece las siguientes posibilidades: Indique una opcin de control DESHACER [Todas/Ninguna/Una] <Todas>: Con la opcin Todas seleccionada (es la opcin por defecto), AutoCAD almacena en el archivo temporal UNDO.ac$ la informacin sobre los comandos ejecutados en el dibujo actual y por tanto que se pueden deshacer. Tambin almacena en el archivo temporal REDO.ac$ la informacin sobre los comandos del dibujo actual que se han deshecho. Estos archivos se almacenan en el directorio temporal del sistema operativo. Esta opcin permite deshacer todos los comandos realizados en el dibujo durante la sesin actual. Si se selecciona la opcin Una, tan slo se podr deshacer el ltimo comando ejecutado. Quedando desactivadas todas las opciones del comando DESHACER excepto Control e Indique el nmero de operaciones a deshacer <1>: Seleccionando la opcin 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 opcin 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 opcin Marca. De este modo activas una marca, a la que podrs volver en cualquier momento ejecutando DESHACER con la opcin Retorno. Al encontrar una marca AutoCAD mostrar el mensaje Marca encontrada. Si en lugar de volver a la marca lo que quieres es deshacer un nmero determinado de comandos, puedes ejecutar el comando H o DESHACER indicando el nmero de comandos a deshacer. Adems, puedes definir tantas marcas como desees, y cada vez que ejecutes DESHACER con la opcin Retorno volvers a la marca anterior. Si no existen ms marcas, o si no se ha definido ninguna marca, AutoCAD preguntar si se desea deshacer todo.
Auto
Algunos comandos de AutoCAD, estn formadas por un grupo de rdenes. De modo que el comando H no anulara todo el grupo de comandos ejecutados, sino slo el ltimo. Activando esta opcin se agrupan estos comandos en uno slo, a efectos de la aplicacin de los comandos H y DESHACER.
Inicio y Fin
Estas dos opciones tambin 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 opcin Auto est activada, AutoCAD coloca automticamente un DESHACER Inicio y un DESHACER Fin al principio y final de las opciones de los mens, y deja inutilizadas estas opciones de forma manual. Con la opcin Auto desactivada, las opciones Inicio y Fin se ejecutan de forma anloga a como se hace con Marca y Retorno. Si se vuelve a ejecutar la opcin Inicio sin haber ejecutado la opcin Fin para cerrar un grupo anterior, AutoCAD entiende que se quiere cerrar el grupo anterior y abrir uno nuevo.
(command _.undo _begin) (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: )) (command _.circle pto rad) (if (= cmd0 1) (setvar cmdecho 1) ) (command _undo _end) (princ) ) (prompt \nNuevo comando ARAND cargado) Deberamos aadir estas dos lneas en la macro CIRCPERI? Pues no es necesario, puesto que en CIRCPERI 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.
(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 lnea (setq error0 *error* *error* ERRORES) se asigna a la variable error0 la antigua funcin de tratamiento de errores, *error*. Y se define la funcin de tratamiento de errores como nuestra funcin ERRORES. Por supuesto, le decimos que use nuestra funcin de tratamiento de errores al principio del cdigo. Pero siempre despus de desactivar el eco de mensajes. Hemos redefinido la funcin de tratamiento de errores, pero al terminar la rutina debemos dejarlo todo como estaba antes. As que recuperamos la funcin de tratamiento de errores inicial, la que ofrece AutoLISP por defecto. Lo haramos con la siguiente lnea: (setq *error* erro0) que se debe poner antes de volver a activar el eco de mensajes. Para probar la funcin de tratamiento de errores debemos cargarla en AutoCAD. En la rutina CIRCPERI haramos exactamente lo mismo: (defun C:CIRCPERI ( / pto peri rad cmd0 error0 ) (if (= (setq cmd0 (getvar cmdecho)) 1) (setvar cmdecho 0) ) (setq error0 *error* *error* ERRORES) (setq pto (getpoint \nCentro de la circunferencia: )) (setq peri (getdist \nPermetro: )) (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 continuacin redefinimos la funcin de tratamiento de errores, despus viene el cdigo de la funcin, se restituye la funcin 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 funcin de tratamiento de errores y la ofrecida por defecto por AutoLISP? Pues casi ninguna, de momento tan slo se diferencia en que si el error que se ha produci do tiene por descripcin 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: Descripcin del error. Un gran cambio, no? Bueno los cambios vamos a hacerlos ahora que ya sabemos como funciona la funcin ERRORES. Cada tipo de error ofrece una descripcin especfica y adems existe un cdigo numrico asociado a la variable de sistema ERRNO en la que se almacena el cdigo correspondiente al ltimo error que se ha producido. Puedes ver en este enlace una lista de los cdigos y mensajes de error de AutoLISP. Qu sucede si el usuario introduce un dato incorrecto al solicitarle el permetro? En ese caso, en la siguiente lnea (setq rad (/ peri (* pi 2))) se producira un error, inicindose la funcin de tratamiento de errores. Cuando se produce el error, ya se ha evaluado la lnea (setq error0 *error* *error* ERRORES) en CIRCPERI, de modo que hemos redefinido la funcin de tratamiento de errores. As que se ejecuta la funcin ERRORES, que muestra la descripcin del error que se produjo. Pero, salimos de la funcin ERRORES y no hemos recuperado el valor de la funcin de tratamiento de errores que nos ofrece por defecto AutoLISP. Y tambin se ha desactivado el eco de mensajes, pero no recuperamos su valor inicial. De modo que vamos a modificar la funcin ERRORES para aadir estos pequeos 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 funcin ERRORES restituye el valor inicial del eco de mensajes y la funcin de tratamiento de errores inicial. Puede extraar que se utilicen las variables cmd0 y error0 dentro de la funcin ERRORES, ya que estaban definidas como variables locales en CIRCPERI. Cuando definimos una variable local en una funcin, esta variable se puede utilizar slo dentro de esa funcin. Pero, si desde CIRCPERI llamamos a otra funcin, por ejemplo ERRORES, en realidad estamos dentro deERRORES, que est dentro de CIRCPERI. As que seguimos dentro de CIRCPERI. Otra de las principales aplicaciones de redefinir la funcin de tratamiento de errores tiene que ver con el tema anterior, los comandos deshacer en las rutinas de AutoLISP. Si nos fijamos en el cdigo de la rutina ARAND, vemos que la primera lnea es (command _.undo _begin) Qu sucedera si se produce un error despus de dibujar el segundo crculo? Dara un error, y terminara el comando sin ejecutar la lnea (command _.undo _end). Con lo cual para deshacer la arandela deberamos ejecutar el comando H (deshacer) dos veces, una por cada crculo. Es ms, imagina que nuestra rutina no dibuja 2 circunferencias sino 120 y que el error se produce al dibujar la circunferencia ensima Podramos entonces modificar la funcin de tratamiento de errores y aadir la lnea de cdigo: (command _.undo _end) Ahora, bastara con ejecutar el comando deshacer una nica vez para que se deshaga todo lo que hizo el comando ARAND. Podemos incluso decirle a la funcin 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 funcin ERRORES ya lo hace por nosotros. Para terminar este artculo, vamos a aadir una nueva opcin a CIRCPERI. Se trata de que ofrezca por defecto el permetro de la ltima circunferencia dibujada. Podramos 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) (prompt \nPermetro: ) (progn (prompt \nPermetro <) (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 tena en la anterior ejecucin de CIRCPERI. Veamos ahora cmo funciona el siguiente trozo de cdigo: (if (not rad) (prompt \nPermetro: ) (progn (prompt \nPermetro <) (prompt (rtos (* rad 2 pi) 2 2)) (prompt >: ) ) ) Si rad es igual a nil, no se ha definido, significa que es la primera vez que se ejecuta el comando CIRCPERI en el dibujo actual. En este caso se muestra un mensaje solicitando el permetro del crculo. 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 ejecucin de CIRCPERI. Tambin muestra un mensaje solicitando el permetro, pero entre los caracteres < y > se indica adems el valor de la variable global rad. (if (setq peri (getdist)) (setq rad (/ peri (* 2 pi))) ) A continuacin se solicita una distancia. No se ha indicado ningn mensaje en la funcin getdist, ya que el mensaje de solicitud se muestra en las lneas anteriores. Si se indica un permetro, ya sea por medio de dos puntos o escribindolo 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 crculo creado con CIRCPERI. (command _.circle pto rad) Por ltimo dibuja el crculo. 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 crculo, en lugar de utilizar la variable rad como global. El cdigo sera 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 \nPermetro: ) (progn (prompt \nPermetro <) (prompt (rtos (* (getvar circlerad) 2 pi) 2 2)) (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 permetro del ltimo crculo dibujado en AutoCAD, independientemente de si dicho crculo 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 \nPermetro: ) (progn (prompt \nPermetro <) (prompt (rtos (* (getvar circlerad) 2 pi) 2 2)) (prompt >: ) ) )
Si an no se ha creado ningn crculo en el dibujo, la variable circlerad tendr asociado el valor 0.0. En este caso solicita el permetro sin ofrecer ningn valor por defecto, y en caso contrario ofrece por defecto el permetro del ltimo crculo creado. (if (setq peri (getdist)) (setq rad (/ peri (* 2 pi))) (setq rad (getvar circlerad)) ) Si se introduce un permetro, por medio de dos puntos o escribindolo se calcula el radio correspondiente. En caso de que se pulse Intro, se asocia a la variable rad el radio del ltimo crculo dibujado.
modo
Es un nmero 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 funcin. El argumento modo es en realidad un cdigo 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 4 > No admite valores negativos como respuesta 8 > Permite indicar un punto fuera de los lmites del dibujo. An cuando estos estn activados. 16 > Este valor no se utiliza actualmente 32 > Dibuja la lnea o rectngulo elsticos con lneas discontnuas en lugar de contnuas 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 expresin de AutoLISP. Bien, veamos como se utiliza initget. Por ejemplo, si queremos que el usuario introduzca un nmero entero y que no pueda pulsar Intro como respuesta, haramos lo siguiente: (initget 1) (setq numero (getint \nNmero entero: )) Initget modifica a la siguiente funcin de solicitud de datos, es decir, getint. Si adems queremos que no pueda indicar 0 como respuesta, entonces sumamos sus respectivos cdigos, el 1para que no se pueda indicar Intro como respuesta y el 2 para que no se pueda indicar 0. (initget (+ 1 2)) (setq numero (getint \nNmero entero: )) Tambin podemos indicar directamente (initget 3) en lugar de (initget (+ 1 2)). Si el usuario indica como respuesta0 o Intro, AutoCAD le dir que ese dato no es vlido y que introduzca un dato correcto. Si queremos que adems se indique un nmero positivo, entonces deberamos poner: (initget 7) (setq numero (getint \nNmero entero: )) Ya que 7 = 1 + 2 + 4 Veamos ahora como funciona el cdigo 8 como argumento modo de Initget. 8 > Permite indicar un punto fuera de los lmites del dibujo. An cuando estos estn activados. Supongamos que tenemos los lmites del dibujo de AutoCAD activados (comando LIMITES) en ese caso no podemos indicar puntos fuera de esos lmites. De modo que si se solicita un punto al usuario conGETPOINT deber indicarlo dentro de los lmites del dibujo. Pero si antes de solicitar el punto se ejecuta (initget 8)entonces si nos dejara. El cdigo 16 no se utiliza. El cdigo 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 lnea, o un rectngulo, elstico con origen en el punto base pto. Estas lneas y rectngulos elsticos se muestran con lnea continua. Pero si antes de la funcin de solicitud se aade (initget 32)se mostraran con lneas discontinuas. Por ejemplo: (setq pt1 (getpoint \nPunto base: )) (initget 32) (setq pt2 (getpoint pt1 \nSegundo punto: )) En este ejemplo aparece una lnea discontinua. Y en el siguiente un rectngulo con lneas discontinuas. (setq pt1 (getpoint \nPunto base: )) (initget 32) (setq pt2 (getcorner pt1 \nSegundo punto: )) Veamos ahora como funciona el cdigo 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 aadir (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 cdigo 128 permite indicar una expresin 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. (initget 128) (setq ang (getreal \nIntroducir ngulo: )) En este caso el usuario podra 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 cdigo de la macro CIRCPERI encontraremos la siguiente lnea: (setq pto (getpoint \nCentro de la circunferencia: )) deberamos aadir alguna limitacin 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 devolveraGetpoint. Despus al intentar dibujar el crculo (command _.circle pto rad) se producira un error. As que debemos impedir que el usuario introduzca Intro como respuesta, de modo que aadiramos (initget 1) antes de la funcin getpoint. Como estamos solicitando un punto, el cdigo 2 no tiene sentido y lo mismo sucede con el 4. El cdigo 8 permite indicar un punto fuera de los lmites del dibujo, an cuando estos estn activados. Este cdigo si podramos utilizarlo, aunque si el usuario trabaja con los lmites activados, estn activados y ya est. Si quiere que los desactive l, no? Porque supongo que los tendr activados por algn motivo. As que no le aadimos a initget el cdigo 8. El cdigo 32 no tiene sentido aqu, pues no aparece la lnea base. Y el cdigo 64 tampoco ya que estamos solicitando un punto, no una distancia. El cdigo 128 permite introducir como respuesta una expresin de AutoLISP. Este cdigo tambin se podra indicar, pero lo habitual es no hacerlo. Se podra utilizar en casos en los que el usuario pudiera utilizar una expresin 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 cdigo quedara: (initget 1) (setq pto (getpoint \nCentro de la circunferencia: )) Sigamos modificando la rutina CIRCPERI: Unas lneas despus de la solicitud del centro de la circunferencia, se solicita su permetro: (if (setq peri (getdist)) (setq rad (/ peri (* 2 pi))) (setq rad (getvar circlerad)) ) Deberamos aadir la funcin initget con el cdigo 1 antes de la funcin getdist? Veamos como funciona esta parte del cdigo: Si el usuario introduce una distancia, se evala la condicin 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 evala la condicin no cumple del IF, es decir: (setq rad (getvar circlerad)) Si aadimos antes del getdist la expresin (initget 1), el usuario no podr indicar Intro, as que nunca se ejecutara la expresin no cumple. Por tanto no aadimos el cdigo 1 a Initget. El permetro del crculo no puede ser ni cero ni un nmero negativo, de modo que podemos aadir a initget los cdigos 2 y 4. Tambin podramos aadir el cdigo 64 para que GETdist devuelva la distancia en 2D. Pero normalmente no conviene aadir este cdigo, 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 ningn crculo, la variable de sistema circlerad tiene el valor 0.0. En este caso, no ofrecemos la opcin de seleccionar el radio del ltimo crculo dibujado pulsando Intro, ya que no existe ningn crculo dibujado previamente. En este caso, no deberamos 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 cdigo completo de la rutina: (defun C:CIRCPERI ( / pto rad peri cmd0 ) (if (= (setq cmd0 (getvar cmdecho)) 1) (setvar cmdecho 0) ) (initget 1) (setq pto (getpoint \nCentro de la circunferencia: )) (if (= (getvar circlerad) 0.0) (progn (prompt \nPermetro: ) (initget 7) ) (progn (prompt \nPermetro <) (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. Prcticamente es igual que la solicitud del centro del crculo en CIRCPERI, as que le aadimos tambin el cdigo 1 a Initget: (initget 1) (setq pto (getpoint \nCentro de la arandela: )) A continuacin solicita los radios interior y exterior de la arandela. En los que podemos evitar que el usuario indique como respuesta Intro, 0 o un nmero negativo. Por lo tanto aadiremos Initget con el modo 7. Veamos el cdigo 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)
Si el usuario indica D o Diam, o dimetro, entonces asigna a la variable rad la cadena de texto Dimetro. Luego al entrar en el IF, (= rad Diametro) devuelve T as que evala la expresin si cumple (setq rad (getreal\nDimetro interior: )) que pide un dimetro 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 dimetro. As que al dibujar la circunferencia (command _.circle pto rad) dibujara una circunferencia del doble del dimetro de lo que ha dicho el usuario. El cdigo debera ser: (initget 7 Dimetro) (setq rad (getreal \nRadio interior / Dimetro: )) (if (= rad Dimetro) (setq rad (/ (getreal \nDimetro interior: ) 2.0)) ) Pero, Qu pasa si el usuario hace lo siguiente? Indica D como respuesta al radio interior. Indica -50 o 0 como dimetro. Pues que asignara a la variable rad el resultado de dividir -50 o 0 entre 2.0. Por tanto tendramos una circunferencia con radio negativo o cero. Recuerda que initget solo tiene efecto sobre la siguiente funcin de solicitud de datos, de modo que tenemos que aadir de nuevo la funcin Initget antes de preguntar por el dimetro: (initget 7 Dimetro) (setq rad (getreal \nRadio interior / Dimetro: )) (if (= rad Dimetro) (progn (initget 7) (setq rad (/ (getreal \nDimetro interior: ) 2.0)) ) ) Se ha aadido la funcin Progn ya que sino, solo se puede ejecutar una expresin como condicin si-cumple delIF. Para el radio o dimetro exterior se hara exactamente lo mismo. Por tanto el cdigo 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 Dimetro) (setq rad (getdist pto\nRadio interior / Dimetro: )) (if (= rad Dimetro) (progn (initget 7) (setq rad (/ (getreal \nDimetro interior: ) 2.0)) ) ) (command _.circle pto rad) (initget 7 Dimetro) (setq rad (getdist pto \nRadio exterior / Dimetro: )) (if (= rad Dimetro) (progn (initget 7) (setq rad (/ (getreal \nDimetro exterior: ) 2.0)) ) ) (command _.circle pto rad) (if (= cmd0 1) (setvar cmdecho 1) ) (command _undo _end) (princ) ) (prompt \nNuevo comando ARAND cargado)
(GETKWORD [mensaje])
Esta funcin de AutoLISP se utiliza para obtener una opcin indicada por el usuario. Se utiliza en combinacin con INITGET, por ejemplo: (initget DEShacer Nuevo Repetir) (setq opc (getkword \nDEShacer / Nuevo / Repetir: )) En este caso el usuario tan slo podr indicar como respuesta una de las palabras clave de la funcin Initget y 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 nmero 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 opcin DEShacer) ) ((= opc Nuevo) (alert Has seleccionado la opcin Nuevo) ) (T (alert Has seleccionado la opcin Repetir) ) ) As en funcin de la opcin que indique el usuario se hace una cosa u otra.
Las expresiones en While son opcionales, de modo que podemos crear un bucle en el que solo se indique la condicin: (while (not (setq pt (getpoint \nPunto inicial: )))) En este caso la condicin 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 funcin 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 tpico 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 nmeros reales: (if (< a b) (setq flag1 nil) (setq flag1 T) ) (while flag1 (prompt \na NO es menor que b) (setq b (getreal \nIntroduzca un nmero: )) (if (< a b) (setq flag1 nil) ) ) En este caso: Si a es menor que b > flag1 = nil Si a NO es menor que b > flag1 = T Luego la funcin While evala la condicin flag1 que devolver su valor nil o T. Si es flag1 = nil (a es menor que b) no evala las expresiones pues no se verifica la condicin. Si es flag1 = T (a NO es menor que b) se verifica la condicin 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 funcin While, al igual que vimos con IF y COND, como condicin podemos utilizar expresiones lgicas. 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 nmero positivo: )) ) En este ejemplo, el bucle se ejecutar hasta que se indique un valor para b positivo y mayor que a.
(initget 7 Dimetro) (setq rad (getdist pto \nRadio exterior / Dimetro: )) (if (= rad Dimetro) (progn (initget 7) (setq rad (/ (getreal \nDimetro 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 rade para el exterior. As podremos comparar si rade es mayor que radi. Podramos sustituir el cdigo anterior por el siguiente: (while (or (not rade) (not (< radi rade))) (initget 7 Dimetro) (setq rade (getreal \nRadio exterior / Dimetro: )) (if (= rade Dimetro) (progn (initget 7) (setq rade (/ (getreal \nDimetro exterior: ) 2.0)) ) ) ) (command _.circle pto rade) La primera vez que se evala la condicin del bucle, no se ha asignado an ningn 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 condicin (not rade) la segunda ni siquiera se evala (por suerte, puesto que al no estar definida rade nos dara un error). La condicin se verifica y ejecuta las expresiones que estn a continuacin, 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 vlido as que dibujamos la circunferencia exterior. El cdigo completo sera: (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 Dimetro) (setq radi (getdist pto \nRadio interior / Dimetro: )) (if (= radi Dimetro) (progn (initget 7) (setq radi (/ (getreal \nDimetro interior: ) 2.0)) ) ) (command _.circle pto radi) (while (or (not rade) (not (< radi rade))) (initget 7 Dimetro) (setq rade (getdist pto \nRadio exterior / Dimetro: )) (if (= rade Dimetro) (progn (initget 7) (setq rade (/ (getreal \nDimetro exterior: ) 2.0)) ) ) ) (command _.circle pto rade) (if (= cmd0 1) (setvar cmdecho 1)
(CHR entero)
Esta funcin devuelve el carcter al que le corresponde el cdigo ASCII indicado. Por ejemplo: (chr 65) devuelve A (chr 97) devuelve a
(ASCII texto)
Devuelve el cdigo ASCII (un nmero entero) correspondiente al primer carcter de la cadena de texto indicada. (ascii Abcde) devuelve 65 (ascii A) tambin devuelve 65 porque lo nico que importa es el primer carcter de la cadena de texto.
@ Equivale a una letra. . Equivale a un carcter que no sea alfanumrico (ni letras ni nmeros). * Equivale a una cadena de caracteres. ? Equivale a un carcter cualquiera. ~ Equivale a una negacin. Por ejemplo (wcmatch AutoLISP ~B*) comprueba que el texto no empieza por B. [...] Nos permite indicar varios caracteres. Por ejemplo (wcmatch AutoLISP [AB]*) comprueba si el texto comienza por A o por B. Tambin podramos 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) devolvera T. Pero cmo 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 apstrofo delante de uno de los caracteres comodines de los patrones, le estamos diciendo que queremos usar el literal, es decir, lo que ponemos a continuacin tal cual est. Pues tema visto. As que podemos ahora modificar la macro CIRCPERI. Tenamos las siguientes lneas en la macro: (prompt \nPermetro <) (prompt (rtos (* (getvar circlerad)2 pi) 2 2)) (prompt >: ) Podramos concatenar las cadenas de texto y ejecutar una nica vez la funcin prompt: (prompt (strcat \nPermetro < (rtos (* (getvar circlerad) 2 pi) 2 2) >: )) Vamos ahora a crear un nuevo comando llamado CIRCULOM que nos permitir dibujar mltiples circunferencias concntricas. Y comenzaremos como siempre por el pseudocdigo. Podra ser algo as: 1. Pedir el centro de las circunferencias. 2. Mientras se indique un punto o radio. 1. Dibujar un crculo. Al escribir el cdigo, lo primero es definir el nuevo comando: (defun C:CIRCULOM ( / ) De momento no ponemos las variables locales, porque an no tenemos ni variables ni nada. Las aadiremos al terminar la macro. 1. Pedir el centro de los crculos. Por ejemplo as: (setq pto (getpoint \nCentro: )) Tal vez pienses no deberamos poner antes un INITGET? Pues seguramente, pero no nos paremos ahora con eso. Primero a ver si hacemos que funcione la rutina, despus 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. Fjate que no se ha cerrado el while, porque an tenemos que aadir 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 parntesis de cierre de While y el de la funcin. El cdigo 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 cdigo. Vamos a comenzar limitando las posibles respuestas de los usuarios con Initget: Aadimos (initget 1) antes de la solicitud Getpoint, para que el usuario no pueda indicar Intro como respuesta. Y aadimos (initget 6) antes de getdistpara que no permita ni cero ni un nmero negativo. Observa que (initget 6) se vuelve a poner otra vez dentro del bucle While. Si no lo hiciramos al indicar el primer radio no permitira responder con cero ni con un nmero negativo. Sin embargo, para el segundo radio y todos los siguientes si que nos dejara. Para que no lo permita, hay que incluir la funcin Initgetantes de que se ejecute de nuevo Getdist, de modo que se aade dentro del bucle While. Otras mejoras seran: Aadir las variables a la lista de variables locales de la funcin. Desactivar el eco de mensajes. Aadir una salida limpia a la funcin. Aadir una lnea fuera de la funcin para que indique el nombre del comando al cargar la macro. Aadir el comando Deshacer Inicio al principio de la rutina y Deshacer Fin al terminarla. El cdigo 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) ) (if (= cmd0 1) (setvar cmdecho 1) ) (command _.undo _end) (princ) ) (prompt \nNuevo comando CIRCULOM cargado)
Ya hemos visto algunas funciones para manejar listas: CAR, CDR, LIST pero hay muchas ms. En este tema veremos algunas de las que nos faltan.
(LAST lista)
Esta funcin devuelve el ltimo elemento de la lista que recibe como argumento. De modo que si hacemos: (setq pto (getpoint \nPunto de insercin: )) (setq z (last pto)) En la variable z almacenamos la coordenada Z del punto pto, siempre que el punto est en 3D porque si est en 2D almacenara la coordenada Y. Los puntos son listas del tipo (10.0 20.0 0.0).
(REVERSE lista)
Devuelve la lista que recibe como argumento pero en orden inverso. (reverse lst) devolver (manzanas naranjas peras limones) Bien, pues para aadir un elemento al final de una lista podemos utilizar cons y reverse: (setq lst (reverse (cons pltanos (reverse lst)))) Veamos como funciona la lnea de cdigo anterior: (reverse lst) devuelve la lista en orden inverso (cons pltanos (reverse lst)) aade pltanos 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 (consplatanos (reverse lst))))
(ACAD_STRLSORT lista)
Esta funcin devuelve una lista con sus elementos, que debern ser cadenas de texto, ordenados alfabticamente. Por ejemplo: (acad_strlsort lst) devolver (limones manzanas naranjas peras pltanos)
Con lo cual, escribira todos los textos en la ventana de comandos de AutoCAD. Se ha utilizado el mismo nombre de variable p, pero podra haberse cambiado: (foreach pepe lsttxt (princ pepe)) Supongamos ahora que tenemos una lista de nmeros: (setq lst (list 5.0 -1.5 2.6 3.8 9.7)) Para sumar los nmeros podramos 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 define numcomo el nmero que est en la posicin i. Sumamos a total ese nmero 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. Tambin podra hacerse sin emplear contadores, como hicimos antes. Y tambin podemos hacerlo con FOREACH, veamos: (foreach p lst (setq total (+ total p))) Todo lo que antes ponamos en un bucle se pone ahora en una sola lnea de cdigo.
La funcin 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.
(VER)
Esta funcin devuelve una cadena de texto con la versin de AutoLISP que se est ejecutando. Por ejemplo: Visual LISP 2000 (es). Entre parntesis indica la versin idiomtica, en este caso Espaol.
(TEXTSCR)
Se utiliza para pasar a pantalla de texto y siempre devuelve nil. Se suele emplear cuando se quiere mostrar mucha informacin en pantalla de texto.
(GRAPHSCR)
Pasa a pantalla grfica y tambin devuelve nil. Se utiliza para asegurarnos que el usuario est viendo la pantalla grfica, por ejemplo para indicar un punto. Especialmente se utilizar si antes se ha pasado a pantalla de texto.
(TEXTPAGE)
Esta funcin es anloga a TEXTSCR. Pasa a pantalla de texto y tambin devuelve nil. Tal vez te ests preguntando Cuntas funciones nos quedan an? Pues entre otras cosas, la siguiente funcin nos servir para ver las funciones de AutoLISP que hemos visto y las que nos quedan.
(QUOTE expresin)
Esta funcin recibe una expresin y devuelve su literal, es decir devuelve la expresin tal cual, sin evaluar. (quote +) devolver + Esto es lo mismo que hacamos en APPLY y MAPCAR: (apply + (list 2.0 3.5 6.8)) pues el apstrofo es el diminutivo o el alias de la funcin QUOTE. (quote (setq a texto b 10.0)) devolver (SETQ A texto B 10.0) sera lo mismo escribir: (setq a texto b 10.0)
Pero no podremos escribir esta ltima lnea en la ventana de comandos de AutoCAD, por que el interprete de comandos no detecta el parntesis en primer lugar y piensa que no es una expresin de AutoLISP sino un comando de AutoCAD. Podemos utilizar un truco para evaluar la expresin desde la ventana de comandos: (progn (setq a texto b 10.0)) PROGN en realidad no hace nada, simplemente nos serva para salvar la limitacin de IF de indicar ms de 1 expresin, ya que evala las expresiones que contiene y devuelve el resultado de la ltima expresin evaluada. En este caso nos sirve para contener la expresin 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. Tambin funcionara 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 tambin: (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 errneo: numberp: A a es el nombre de una variable, es un smbolo, 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 evala peroQUOTE no evala la expresin 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 ms: (setq maximo (apply (quote max) (quote (10.5 15.2 9.3)))) (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 expresin)
Esta funcin evala la expresin 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 ms 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 smbolo. 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 evala.
(READ texto)
Esta funcin lee el texto que recibe y devuelve la primera palabra pero como un literal, un smbolo, 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 parntesis lo considera un mismo trmino. Es algo similar a escribir en la ventana de comandos de AutoCAD, si no se pone un parntesis delante no dejar escribir espacios en blanco. Pues este es otro mtodo para crear una lista, por tanto: (apply max (read (15.2 9.3 15.5))) devolver el mximo de la lista de nmeros 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 expresin de AutoLISP y evaluarla: (setq txt (getstring T \nExpresin de AutoLISP: )) (setq valor (eval (read txt)))
En este caso asignamos a valor el resultado de evaluar una expresin de AutoLISP introducida por el usuario.
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 cargaran todos directamente en la memoria y si tenemos bastantes funciones seguimos teniendo el mismo problema que antes. Cmo podemos solucionarlo? Pues cargando las funciones solo cuando hacen falta. Por ejemplo, supongamos que en el comando C:CIRPERI se utiliza la funcin RAG. Tenemos dos opciones: 1. Incluir la funcin RAG en el archivo Circperi.lsp. De este modo al cargarse el archivo se cargar la funcin RAG. Esto se suele hacer para las funciones que slo se utilizan en un comando determinado. 2. Pero si la funcin RAG deseamos utilizarla en otros comandos, es mejor utilizar el siguiente mtodo: Incluir la funcin RAG en un archivo independiente Rag.lsp y aadir la siguiente lnea de cdigo 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 funcin Autoload del archivo ACADDOC.LSP. Y al cargarse el archivo Circperi.lsp se cargar mediante la funcinLoad el archivo Rag.lsp. Utilizando este mtodo podemos utilizar una misma funcin en mltiples rutinas, tan solo debemos asegurarnos de que dicha funcin 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 cdigo 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 mdulo o aplicacin para AutoCAD, podis sobreescribir vuestros archivos. Existen otros dos mtodos para cargar automticamente rutinas de AutoLISP. El primero consiste en utilizar la opcin 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 mtodo para cargar automticamente las rutinas de AutoLISP es editando los mens de AutoCAD, pero esto lo veremos ms adelante.
S::STARTUP
Existe otro mtodo para ejecutar cdigo automticamente. Hemos visto que AutoCAD utiliza una funcin de tratamiento de errores por defecto que se llamaba *error* y tambin hemos visto que podamos redefinirla creando nuestra propia funcin de tratamiento de errores. Bien, pues AutoCAD tambin tiene una funcin interna que se ejecuta automticamente 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 funcin de otro tipo. Para definir la funcin S::STARTUP se utiliza DEFUN, al igual que para cualquier otra funcin. (defun S::STARTUP ( / ) (setq directorio c:\\rutinas\\) ) La funcin 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 parntesis o unas comillas, por ejemplo, modificaran totalmente nuestras funciones. Cuando adems estas funciones se van a ejecutar automticamente, como en los ejemplos que se han expuesto, la precaucin al programar debe ser mxima.
(FINDFILE archivo)
Esta funcin 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) debera devolver c:\\autoexec.bat, suponiendo que vuestro PC tiene Autoexec.bat, claro (findfile c:\\noexisto.bat) debera 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 AUTOLOAD 2. Antes de abrir un fichero de texto, ya sea para leerlo o escribir en l. 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, deberamos modificar el cdigo de la funcin 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 ;; estn 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 )
(CLOSE descriptor_archivo)
Cierra el archivo cuyo descriptor se indica y devuelve nil. Fjate en lo importante que es guardar el descriptor del archivo en una variable, ya que si no lo hacemos no slo no podremos leer o escribir en el archivo, tampoco podremos cerrarlo. (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 adiccin) de modo que debemos saber de antemano lo que vamos a hacer con el archivo, y SLO 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 cuestin de especial inters es que si abrimos un archivo de texto existente en modo escritura w, nos habremos cargado todo lo que tena anteriormente dicho archivo. As que mucho cuidado con los archivos que se abren en modo escritura.
(READ-CHAR [descriptor_archivo])
Lee un carcter del archivo cuyo descriptor se indica y devuelve su cdigo ASCII. (read-char darch) devuelve 34, que es el cdigo 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 cdigo ASCII
(READ-LINE [descriptor_archivo])
Esta funcin lee una lnea del archivo de texto indicado. (read-line darch) devolver Curso de AutoLISP\ Observa que las comillas iniciales del archivo ya las habamos ledo con la funcin 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 lnea de nuestro archivo as que si volvemos a repetir la lnea 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.