[2/12]

ONCE.5. CREAR Y DECLARAR VARIABLES

Una vez visto lo visto, vamos a ver como podemos introducir valores en variables para no perderlos. A esto se le llama declarar variables.

Una variable es un espacio en memoria donde se guardará, con un nombre que indiquemos, un valor concreto, una cadena de texto, un resultado de una expresión, etcétera. El comando para declarar variables en AutoLISP es SETQ y su sintaxis es la que sigue:

(SETQ nombre_variable1 expresión1 [nombre_variable2 expresión2...])

De esta manera introducimos valores en nombres de variables, por ejemplo:

(SETQ x 12.33)

Esta proposición almacena un valor real de 12,33 unidades en una variable con nombre x.

Al escribir una función SETQ atribuyendo a una variable un valor, AutoLISP devuelve dicho valor al hacer INTRO. AutoLISP siempre tiene que devolver algo al ejecutar una función.

Como indica la sintaxis, podemos dar más de un valor a más de un nombre de variable a la vez en una función SETQ, por ejemplo:

(SETQ x 54 y 12 z 23)

En este caso, AutoLISP devuelve el valor de la última variable declarada. Esto no es muy recomendable si las expresiones o elementos de la lista son muy complicados, ya que puede dar lugar a errores. A veces, aunque no siempre, es preferible utilizar tantas SETQ como variables haya que declarar que hacerlo todo en una sola línea.

Si declaramos una variable que no existía, se crea y se guarda en memoria con su valor; si la variable ya existía cambiará su valor por el nuevo.

NOTA: Al comenzar un dibujo nuevo, abrir uno existente o salir de AutoCAD, el valor de las variables se pierde de la memoria.

Podemos, como hemos dicho, atribuir valores de cadena a variables de la siguiente forma:

(SETQ ciudad "Bilbao")

y combinar cadenas con valores numéricos y/o expresiones:

(SETQ ciudad "Bilbao" x (+ 23 45 23) v1 77.65)

De esta forma, se guardará cada contenido en su sitio. Las variables que contienen cadenas textuales han de ir entre comillas dobles (""). A estas variables se las conoce en el mundo de la informática como variables alfanuméricas o cadenas, y pueden contener cualquier carácter ASCII. Las otras variables son numéricas, y únicamente contendrán datos numéricos.

NOTA: De forma diferente a otros lenguajes de programación, en AutoLISP no hay que diferenciar de ninguna manera los nombres de variables numéricas de los de variables alfanuméricas o cadenas.

Para comprobar nosotros mismos el valor de una variable declarada, y como se expuso al principio de este MÓDULO ONCE, podemos evaluarla directamente introduciendo su nombre, en la línea de comandos, precedido del carácter de cierre de exclamación (!). Por ejemplo, declaradas las variables anteriores (ciudad, x y v1), podemos examinar su valor de la siguiente manera:

!ciudad devuelve "Bilbao"
!x
devuelve 91
!v1
devuelve 77.65


Así pues, imaginemos que queremos escribir unas pequeñas líneas de código que calculen el área y el perímetro de un círculo, según unos datos fijos proporcionados. Podríamos escribir la siguiente secuencia en orden, acabando cada línea con
INTRO:

(SETQ Radio 50)
(SETQ Area (* PI Radio Radio))
(SETQ Perim (* 2 PI Radio))

De esta forma, si ahora tecleamos lo siguiente se producen las evaluaciones indicadas:

!area devuelve 7853.98
¡perim
devuelve 314.159

NOTA: Como sabemos es indiferente el uso de mayúsculas y minúsculas. Además, decir que podemos (lo podríamos haber hecho con la variable Area) introducir tildes y/o eñes en nombres de variable pero, por compatibilidad, es lógico y mucho mejor no hacerlo.

NOTA: Es posible declarar variables con nombres de funciones inherentes de AutoLISP, pero cuidado, si hacemos estos perderemos la definición propia de la misma y ya no funcionará, a no ser que cambiemos de sesión de dibujo. Así mismo, tampoco debemos reasignar valores diferentes a constantes (que en realidad son variables, porque podemos cambiarlas) propias de AutoLISP como PI. La siguiente función que veremos nos ayudará a evitar esto.

NOTA: Si queremos ver el valor de una variable no declarada, AutoLISP devuelve nil.

Al estar los valores guardados en variables, podemos utilizarlos para otras operaciones sin necesidad de volver a calcularlos. Teniendo en cuenta el último ejemplo, podríamos hacer:

(+ area perim)

para que devuelva el resultado de la adición de las dos variables. O incluso, podemos guardar dicho resultado en otra variable, para no perderlo, así por ejemplo:

(SETQ total (+ area perim))

Después podremos comprobar su valor escribiendo !total.

Lo que no podemos es realizar, por ejemplo, operaciones matemáticas con variables alfanuméricas entre sí, o con numéricas y alfanuméricas mezcladas (aunque las cadenas contengan números no dejan de ser cadenas textuales). Veamos la siguiente secuencia y sus resultados:

(SETQ x 34) devuelve 34
(SETQ y "ami")
devuelve "ami"
(SETQ z "guitos")
devuelve "guitos"
(SETQ w "12")
devuelve "12"
(SETQ p 10)
devuelve 10
(+ x p)
devuelve 44
(+ p y)
devuelve error: bad argument type
(+ x w)
devuelve error: bad argument type
(+ y z)
devuelve error: bad argument type

En otros lenguajes de programación podemos concatenar cadenas de texto con el símbolo de suma +, en AutoLISP no. AutoLISP ya posee sus propios mecanismos —que ya estudiaremos— para realizar esta función. Tampoco podemos, como vemos, operar con cadenas y valores numéricos, sean como sean y contuvieren lo que contuvieren.

Veamos algunos ejemplos más de SETQ:

(SETQ ancho (* l k) largo (+ x1 x2) alto (* ancho 2))


NOTA: Como vemos, podemos definir una variable con una expresión que incluya el nombre de otra definida anteriormente, aunque sea en la misma línea.

(SETQ x (= 20 20))

Esta variable x guardaría el valor verdadero (T).

(SETQ zon (* (/ 3 2) 24 (EXPT 10 4)))
(SETQ f (1+ f))

Este último ejemplo es lo que se denomina, en el mundo de la programación informática, un contador-suma. Guarda el valor de f más una unidad en la propia variable f (se autosuma 1).

Cambiando a otra cosa, vamos a comentar la posibilidad de perder la definición de una función AutoLISP por declarar una variable con su nombre. Existe una función que muestra todos los símbolos actuales definidos. Esta función es:

(ATOMS-FAMILY formato [lista_símbolos])

ATOMS-FAMILY, como decimos, muestra una lista con todos los símbolos definidos actualmente. En esta lista entran tanto las subrs (funciones inherentes) de AutoLISP como las funciones y variables definidas y declaradas por el usuario cargadas en la actual sesión de dibujo. De esta forma podemos consultar dicha lista para ver si tenemos la posibilidad de dar ese nombre de variable que estamos pensando. Ahí tendremos todas las funciones propias e inherentes, además de las variables ya creadas.

Como podemos observar en la sintaxis, esta función necesita un parámetro o argumento obligatorio llamado formato. formato sólo puede tomar dos valores: 0 ó 1. Si es 0, los símbolos se devuelven en una lista, separando cada nombre de otro por un espacio en blanco. Si es 1, los símbolos se devuelven entre comillas (separados también por espacios blancos) para su mejor comparación y examen. Cuestión de gustos; la verdad es que no se encuentra un símbolo tan fácilmente entre la marabunta de términos.

Pero con el argumento optativo podemos depurar o filtrar al máximo la búsqueda; de esta manera es de la que más se utiliza. Con lista_símbolos hacemos que se examinen solamente los nombres que incluyamos en la lista. Estos símbolos habrán de ir encerrados entre comillas y ser precedidos del apóstrofo (’) por ser una lista literal. El resultado es otra lista en la que, los símbolos ya existentes aparecen en su sitio, en el mismo lugar de orden donde se escribieron y, en el lugar de los no existentes aparece nil.

Si por ejemplo queremos saber si el nombre de variable total existe ya como símbolo, sea función inherente, propia o variable ya declarada, y deseamos el resultado como simple lista escribiremos:

(ATOMS-FAMILY 0 ’("total"))

y AutoLISP, si no existe el símbolo, devolverá:

(nil)

Si aún no hemos declarado ninguna variable y escribimos:

(ATOMS-FAMILY 0 ’("tot" "setq" "w" ">=" "sqrt" "suma"))

AutoLISP devolverá:

(nil SETQ nil >= SQRT nil)

Y si lo escribimos así (con 1 para formato):

(ATOMS-FAMILY 1 ’("tot" "setq" "w" ">=" "sqrt" "suma"))

AutoLISP devolverá:

(nil "SETQ" nil ">=" "SQRT" nil)

 

ONCE.5.1. A vueltas con el apóstrofo (’)

Ya hemos utilizado un par de veces este símbolo y, también, hemos explicado por encima su función. Vamos ahora a ampliar esa información.

El símbolo de apóstrofo (’) no es otra cosa, como ya se comentó, que una abreviatura de la función QUOTE de AutoLISP. Dicha función tiene la siguiente sintaxis de programación:

(QUOTE expresión)

o también:

expresión)


NOTA
: Nótese que tras QUOTE hay un espacio pero, si se utiliza el apóstrofo no hay que introducirlo.

Esta función se puede utilizar con cualquier expresión de AutoLISP. Lo que hace es evitar que se evalúen los símbolos y los toma como literales. Devuelve siempre el literal de la expresión indicada, sin evaluar. Por ejemplo:

(QUOTE (SETQ x 22.5)) devuelve (SETQ x 22.5)
(QUOTE hola)
devuelve HOLA
(QUOTE (+ 3 3 3))
devuelve (+ 3 3 3)


Hay que tener cuidado al utilizar el apóstrofo de abreviatura de
QUOTE, ya que desde la línea de comandos no lo vamos a poder utilizar. Recordemos que AutoCAD sólo reconoce que estamos escribiendo algo en AutoLISP en la línea de comandos cuando comenzamos por el paréntesis de apertura (, o a lo sumo por la exclamación final !, para evaluar variables directamente. Expresiones como las siguientes:

’(DEFUN diblin () "Nada")
’a
’var12

sólo podremos introducirlas desde un archivo ASCII (como veremos en seguida).

Pues este comando es muy utilizado a la hora de introducir directamente, por ejemplo, las coordenadas de un punto, ya que estas coordenadas son en el fondo una lista y que no ha de ser evaluada. Por ejemplo ’(50 50).

Lo mismo nos ha ocurrido con la lista de ATOMS-FAMILY. Ésta no ha de evaluarse (no tiene otras funciones añadidas, es simplemente un grupo de cadenas), por lo que ha de introducirse como literal.

Una lista que no tiene función añadida, por ejemplo (50 50 –23) produce un error de bad function en AutoLISP, a no ser que se introduzca como literal:

(QUOTE (50 50 –23)) devuelve (50 50 –23)

NOTA: En la mayoría de las funciones de AutoLISP, al introducir un literal de expresión la haremos con el apóstrofo directamente, ya que con QUOTE no funcionará. QUOTE sólo tendrá validez cuando se utilice solo, sin más funciones.

 

ONCE.6. PROGRAMANDO EN UN ARCHIVO ASCII

Hasta ahora hemos visto muchos ejemplos de funciones en AutoLISP, pero todos ellos los hemos tecleado desde la línea de comandos de AutoCAD. Esto resulta un poco engorroso, ya que si quisiéramos volver a teclearlos tendríamos que escribirlos de nuevo. Sabemos que existe la posibilidad de copiar y pegar en línea de comandos, aún así es pesado tener que volver a copiar y pegar cada una de las líneas introducidas.

Existe la posibilidad de crear archivos ASCII con una serie de funciones AutoLISP (programa) que se vayan ejecutando una detrás de otra al ser cargado, el programa, en AutoCAD. Ésta es la verdadera forma de trabajar con AutoLISP. La escritura en línea de comandos está relegada a pruebas de funcionamiento de funciones.

Con este método, no sólo tenemos la posibilidad de editar unas línea y correrlas (ejecutarlas) bajo AutoCAD, sino que además podremos elaborar programas extensos que tendremos la posibilidad de cargar desde disco en cualquier sesión de dibujo, en cualquier momento.

Incluso, como veremos, es factible la creación de órdenes o comandos para AutoCAD 14 que, siendo no otra cosa que programas en AutoLISP, podremos ejecutar con sólo teclear su nombre. Estos programas manejarán la Base de Datos de AutoCAD, operarán con objetos de dibujo, utilizarán cuadros de diálogo o no como interfaz, y un larguísimo etcétera. La programación en AutoLISP, unida a estructuras de menús, tipos de línea, patrones de sombreado y demás estudiado en este curso, nos permitirá llegar a crear verdaderas aplicaciones verticales para AutoCAD 14.

Pero para desarrollar un programa en un archivo ASCII y luego poder cargarlo en AutoCAD, no debemos simplemente escribir las expresiones que ya hemos aprendido y punto. Hay que seguir una lógica y hay que indicarle a AutoCAD, al principio del programa, que estamos escribiendo un programa en AutoLISP, precisamente.

Un archivo ASCII puede contener varios programas o funciones de usuario en AutoLISP. Se suelen escribir procurando no sobrepasar los 80 caracteres por línea para su edición más cómoda y, además, se suelen sangrar en mayor o menor medida las entradas de algunas líneas, dependiendo de la función —ya nos iremos familiarizando con esto— para dar claridad al programa.

Un programa de AutoLISP se compone de una serie de funciones AutoLISP que se ejecutan una detrás de la otra produciendo diferentes resultados. El caso sería el mismo que ir introduciendo renglón a renglón en la línea de comandos. Pero en un archivo ASCII hay que introducir todas las funciones dentro de la lista de argumentos de otra que las engloba. Esta función es DEFUN y su sintaxis es:

(DEFUN nombre_función lista_argumentos expresión1 [expresión2...])

DEFUN define una función de usuario. Su paréntesis de apertura es lo primero que debe aparecer en un programa AutoLISP y su paréntesis de cierre lo último tras todas las funciones intermedias (después puede haber otros DEFUN).

nombre_función es el nombre que le vamos a dar a nuestra función y lista_argumentos es una lista de argumentos globales o locales para la función. Los argumentos o variables globales son aquellos que se almacenan en memoria y permanecen en ella; son todas las variables que hemos definiendo hasta ahora. Estas variables pueden ser utilizadas por otros programas AutoLISP o ser evaluadas directamente en línea de comandos mediante el carácter !.

Los símbolos locales son variables temporales. Estas se almacenan en memoria sólo de manera temporal, hasta que se termina la función en curso. Una vez ocurrido esto desaparecen y no pueden ser utilizados por otros programas ni evaluados en línea de comandos. Estos símbolos locales han de estar indicados en la lista después de una barra (/). Esta barra tiene que estar separada del primer símbolo local por un espacio en blanco y del último símbolo global —si lo hubiera— por un espacio blanco también. Veamos unos ejemplos:

(DEFUN func (x)... variable global: x
(DEFUN func (x y)...
variables globales: x y
(DEFUN func (x / u z)...
variable global: x variables locales: u z
(DEFUN func (/ x s)...
variables locales: x s

Si el símbolo local se encontrara ya creado antes de ser utilizado en la función definida, recupera el valor que tenía al principio una vez terminada la función. Si no se especifican como locales al definir una función, todos los símbolos declarados con SETQ dentro de ella son globales.

NOTA: De momento vamos a olvidarnos de variables globales y locales, ya que todas las funciones que definamos por ahora tendrán una lista de argumentos vacía. Más adelante se profundizará en este tema.

Después de esto, aparecerán todas las expresiones del programa, o sea, las funciones de AutoLISP o de usuario ya definidas que formen el conjunto del programa. Al final, deberá cerrarse el paréntesis de DEFUN.

Así pues, ya podemos crear nuestro primer programa en AutoLISP. Este programa calculará la raíz cuadrada de un número, definidos anteriormente en una variables. Veamos cómo es el pequeño programa:

(DEFUN () Raiz
--(SETQ X 25)
--(SQRT X)
)


NOTA IMPORTANTE DE SINTAXIS: EN LOS PROGRAMAS INCLUIREMOS LOS SANGRANDOS EN FORMA DE GUIONES, PERO ESTOS NO DEBEN SER INCLUIDOS REALMENTE EN EL CÓDIGO, SINO QUE SERÁN SUSTITUIDOS POR ESPACIOS BLANCOS.


Vamos a comentarlo un poco. Definimos, lo primero, la función llamada
Raiz con una lista de argumento vacía. A continuación, asignamos con SETQ el valor 25 a la variable X y calculamos su raíz cuadrada. Al final, cerramos el paréntesis de DEFUN. Simple.

NOTA: La razón para sangrar las líneas se debe a la comodidad de ver qué paréntesis cierran a qué otros. De un golpe de vista se aprecia perfectamente.

NOTA: Es irrelevante la utilización de mayúsculas o minúsculas en la programación en AutoLISP (excepto en cadenas literales, lógicamente).

Podíamos haber hecho el programa sin variable, simplemente poniendo el valor tras la función de la raíz cuadrada, pero es otro modo de recordar y practicar. Escribámoslo y guardémoslo con extensión .LSP. Como nombre es recomendable darle el mismo que a la función, es decir, que el nombre del archivo quedaría así: RAIZ.LSP. Esto no tiene por qué sentar cátedra.

Vamos ahora a cargar nuestra nueva función en AutoCAD. El procedimiento es sencillo y siempre el mismo. Desde Herr.>Cargar aplicación... accedemos al cuadro Cargar archivos AutoLISP, ADS y ARX. En este cuadro, pinchando en Archivo... se nos abre un nuevo cuadro para buscar y seleccionar el archivo. Tras seleccionarlo (y pulsar Abrir) volveremos al cuadro anterior donde pulsaremos el botón Cargar. De esta forma cargamos el archivo para poder ser utilizado.

NOTA: Si en este cuadro comentado activamos la casilla Guardar lista, tendremos accesibles en la lista Archivos a cargar todos los archivos cargados desde la activación de la casilla. De esta forma podremos modificar un archivo .LSP y, rápidamente, volver a cargarlo escogiéndolo de esta lista y pulsando Cargar. Realmente la lista se guarda en un archivo llamado APPLOAD.DFS y que estará guardado en el directorio al que haga referencia el acceso directo que arranca AutoCAD en su casilla Iniciar en:.

El botón Descargar descarga de memoria la aplicación designada y, el botón Suprimir, elimina una entrada de la lista.

NOTA: Este cuadro de diálogo aparece también con el comando APPLOAD de AutoCAD 14.

Una vez cargada la función sólo queda ejecutarla. Para ello deberemos indicarla entre paréntesis, esto es (en la línea de comandos):


(RAIZ)

y AutoCAD devuelve:

2.23607

La razón de que haya que ejecutarlas entre paréntesis es porque es una función AutoLISP; es una función definida por el usuario, pero no deja de ser AutoLISP. Pero existe una forma de no tener que escribir los paréntesis para ejecutar una nueva orden de usuario. Esta forma consiste en colocar justo delante del nombre de la nueva función los caracteres C: (una ce y dos puntos). De la siguiente manera quedaría con el ejemplo anterior:

(DEFUN () C:Raiz
--(SETQ X 25)
--(SQRT X)
)

Así, únicamente habríamos de escribir en la línea de comandos:

RAIZ

para que devuelva el mismo resultado. De esta forma, RAIZ es un nuevo comando totalmente integrado en AutoCAD, el cual podríamos ejecutar desde la línea de comandos o hacer una llamada a él desde un botón de una barra de herramientas, o desde una opción de menú, etcétera.

NOTA: Las funciones definidas mediante este método no admiten variables globales, sólo locales.

NOTA: Las mayúsculas o minúsculas son también irrelevantes a la hora de llamar a un función de usuario, al igual que ocurre con los comandos de AutoCAD.

 

5ª fase intermedia de ejercicios

· Realizar un programa AutoLISP que calcule la suma de los diez primeros números.

· Realizar un programa que compare valores mayores.

· Realizar un programa que asigne valores a 3 variables y luego las multiplique todas entre sí.

 

ONCE.7. CAPTURA Y MANEJO BÁSICO DE DATOS
ONCE.7.1. Aceptación de puntos

Tras lo estudiado parece ser que vamos entrando poco a poco y de lleno en el mundo de la programación en AutoLISP. Sin embargo, aún puede parecernos algo ilógico el poder realizar un programa que calcule una serie operaciones con cantidades fijas, sin poder variar de números cada vez que se ejecute el programa, por ejemplo. En esta sección ONCE.7. vamos a aprender la forma que tenemos de pedirle datos al usuario para luego operar con ellos. Comenzaremos por los puntos.

Todo lo que se refiere a captura de datos, tiene en AutoLISP un nombre propio que es GET.... Si nos damos cuenta, se ha indicado con punto suspensivos porque "GET" como tal no existe como función, sino una serie de ellas que comienzan con esas letras. Pues bien, todas estas funciones del tipo GET... nos proporcionarán las posibilidad de preguntar al usuario por un texto, por el valor de una distancia, por la situación de un punto, etc. para luego operar a nuestro antojo con dichos valores.

La primera función de este tipo que vamos a estudiar tiene la sintaxis:

(GETPOINT [punto_base] [mensaje])


GETPOINT solicita un punto al usuario. Esta función aguarda a que se introduzca un punto, bien sea por teclado o señalando en pantalla como habitualmente lo hacemos con AutoCAD, y devuelve las coordenadas de dicho punto en forma de lista de tres valores reales (X, Y y Z). Para probarla podemos escribir en la línea de comandos:

(GETPOINT)

A continuación, señalamos un punto (o lo digitamos) y AutoLISP devuelve las coordenadas de dicho punto. Estas coordenadas, como hemos dicho, están en forma de lista, es decir, entre paréntesis y separadas entre sí por espacios en blanco (es una típica lista de AutoLISP como hemos visto alguna ya).

La potencia de esta función se desarrolla al guardar las coordenadas indicadas en una variable, para que no se pierdan. En el momento en que capturamos los datos y los almacenamos en una variable ya podemos utilizarlos posteriormente. Para almacenar los datos utilizaremos la función SETQ estudiada, de la siguiente manera por ejemplo:

(DEFUN C:CapturaPunto ()
--(SETQ Punto (GETPOINT))
)

Como sabemos, para ejecutar esta nueva orden habrá que escribir en la línea de comandos de AutoCAD:

CAPTURAPUNTO

Con el argumento opcional mensaje de GETPOINT tendremos la posibilidad de incluir un mensaje en la línea de comandos a la hora de solicitar un punto. Así, podríamos variar un poco el programa anterior de la siguiente manera:

(DEFUN C:CapturaPunto ()
--(SETQ Punto (GETPOINT "Introducir un punto: "))
)

De esta forma se visualizará el mensaje indicado (siempre entre comillas) a la hora de solicitar el punto.

El argumento punto_base permite introducir un punto base de coordenadas (2D ó 3D), a partir del cual se visualizará una línea elástica hasta que indiquemos un punto. Viene a ser algo así como la manera de dibujar líneas en AutoCAD: se indica un punto y la línea se "engancha" a él hasta señalar el segundo. De todas formas no tiene nada que ver. Para indicar este punto de base lo podemos hacer mediante una variable que contenga un punto o directamente con una lista sin evaluar (con apóstrofo), como vimos:

(GETPOINT ’(50 50) "Introducir un punto: ")

NOTA: Apréciese el espacio tras ...punto: . Es puramente decorativo. Produciría mal efecto al aparecer en pantalla el mensaje si no estuviera este espacio. Pruébese.

Pero, ¿qué hacemos ahora con este punto? Hemos comenzado a ver la manera de obtener datos del usuario, pero poco podremos hacer si no somos capaces de procesarlos después, al margen de las típicas —que no inútiles— operaciones matemáticas y de comparación. Para avanzar un poco más, vamos a hacer un inciso en la manera de capturar datos y vamos a ver la función COMMAND de AutoLISP.

La función COMMAND permite llamar a comandos de AutoCAD desde AutoLISP. Sus argumentos son las propias órdenes de AutoCAD y sus opciones correspondientes. La manera de indicarle estas órdenes y opciones del programa a la función COMMAND es entre comillas dobles (""), aunque también podremos indicar puntos en forma de lista (o no), valores en formato de expresión matemática y otros. La sintaxis de COMMAND es la siguiente:

(COMMAND [comando] [opciones...])

Así por ejemplo, podemos ejecutar la siguiente función desde la línea de comandos:

(COMMAND "linea" ’(50 50) ’(100 100) "")

Esto es, ejecutar el comando LINEA, darle 50,50 como primer punto y 100,100 como segundo punto. Al final, un INTRO ("") para acabar la orden. La base es exactamente la misma que cuando escribíamos la macro de un botón: hay que ir escribiendo comandos y opciones como si fuera directamente en línea de comandos. La diferencia es que no hay que introducir ningún carácter para indicar un INTRO, simplemente al escribir "LINEA" se ejecuta el comando, o al escribir ’(50 50) se introduce el punto. Es por ello que, al final haya que escribir un par de comillas dobles (sin espacio intermedio) para acabar la orden LINEA, y es que estas comillas indican un INTRO.

Como vemos, la manera de escribir las coordenadas de un punto es mediante un lista sin evaluar (con apóstrofo). Pero es perfectamente lícito (sólo con la función COMMAND) introducirlas como algo que se escribiría por teclado, es decir, de la siguiente forma:

(COMMAND "linea" "50,50" "100,100" "")

como ocurre con el comando LINEA. Esto no lo podremos hacer con el resto de funciones.

NOTA: Al igual que en las macros y en los menús, sería más recomendable, por aquello del soporte idiomático del programa en AutoLISP, escribir funciones como la anterior de esta otra forma: (COMMAND "_line" ‘(50 50) ‘(100 100) "").

Así pues, podríamos reciclar nuestro ejemplo de GETPOINT de la siguiente forma:

(DEFUN C:DibCirc ()
--(SETQ Centro (GETPOINT "Introducir un punto: "))
--(COMMAND "_circle" Centro "10")
)


Este programa pedirá un punto al usuario y dibujará un círculo de radio 10 con centro en dicho punto. Sencillo.

NOTA: Si damos un nombre de un comando de AutoCAD a una función definida por nosotros, recordar lo explicado en el MÓDULO NUEVE sobre redefinición de órdenes. Y si queremos realizar un programa que sea totalmente compatible con todas las versiones idiomáticas de AutoCAD y, además, evitar la posibilidad de que en una máquina haya órdenes predefinidas, utilizaremos los comandos con el guión de subrayado y el punto juntos, de la forma: _.line.

NOTA: Las órdenes de AutoCAD que leen directamente información del teclado, como TEXTODIN (DTEXT) o BOCETO (SKETCH), no funcionan correctamente con la función COMMAND, por lo que no se pueden utilizar. Si se utiliza una llamada a la orden SCRIPT mediante COMMAND deberá ser la última llamada.

Al principio de este MÓDULO vimos que existían tres variables o símbolos predefinidos de AutoLISP. Entre ellas estaba PAUSE, y dijimos que se utilizaba con la función COMMAND. La forma de hacerlo es introducir este símbolo predefinido como argumento de COMMAND, esto hará que el comando en curso, al que haya llamado la función, se interrumpa para que el usuario introduzca algún dato. La mecánica es la misma que se utilizaba al escribir un carácter de contrabarra en las macros de los menús o los botones de barras de herramientas. Por ejemplo:

(COMMAND "_circle" ’(50 50) pause)

Este ejemplo situará el centro de un círculo en el punto de coordenadas 50,50 y esperará a que el usuario introduzca el radio (o diámetro), sea por teclado o indicando en pantalla. Podemos hacer zooms, encuadres y demás (siempre transparentes) hasta introducir lo solicitado, momento en el cual se devolverá el control a la función COMMAND y terminará el comando.

NOTA: De hecho, el símbolo PAUSE contiene el valor predefinido de contrabarra. Únicamente deberemos evaluarlo en línea de comandos (!pause) para comprobarlo. El resultado de esta evaluación será "\\", ya que \\, como está indicado en el punto 8. de la sección ONCE.2.3. (en este MÓDULO), es el código para el carácter contrabarra. Por compatibilidad, podemos introducir la cadena "\\" en lugar de PAUSE con funciones COMMAND.

Terminado el inciso de la función COMMAND, vamos a seguir explicando otra función similar a GETPOINT. Esta nueva se llama GETCORNER y su sintaxis es la siguiente:

(GETCORNER punto_base [mensaje])

La misión de GETCORNER es exactamente la misma que la de GETPOINT (solicitar y aceptar un punto), la única diferencia es la forma de visualizar dinámicamente el arrastre. Con GETCORNER, en lugar de ser una línea elástica (como ocurría con GETPOINT con punto base), es un rectángulo elástico. Esto nos lleva a deducir que esta función necesita obligatoriamente que se indique un punto de base para el rectángulo (vemos en la sintaxis que es argumento obligatorio). Así:

(GETCORNER ’(50 50))

situará la esquina primera del rectángulo elástico en coordenadas 50,50 y esperará que se señale, o se indique por teclado, el punto opuesto por la diagonal. Devolverá el punto señalado por el usuario en forma de lista.

El punto base se expresa respecto al SCP actual. Si se indica un punto de base 3D no se tiene en cuenta su coordenada Z, evidentemente: siempre se toma como tal el valor actual de la elevación.

El argumento mensaje funciona de la misma forma que con GETPOINT, es decir, escribe el texto en línea de comandos al solicitar el punto. Veamos un pequeño ejemplo con esta función:

(DEFUN C:Caja ()
--(SETQ Esq1 ’(100 100))
--(SETQ Esq2 (GETCORNER Esq1 "Indique 2º punto de la diagonal del
--rectángulo: "))
--(COMMAND "rectang" Esq1 Esq2)
)

Este ejemplo dibuja un rectángulo cuya diagonal se sitúa entre el punto 100,100 y el designado por el usuario. Al final, AutoLISP devuelve nil. Esto no significa que haya habido algún fallo, sino que, como dijimos, AutoLISP siempre ha de devolver algo, cuando no hay nada que devolver, el resultado será nil.

La separación en dos de la tercera línea es únicamente problema de espacio en estas páginas. Al escribirlo en un archivo ASCII deberemos hacerlo todo seguido, en este caso. En otros casos, si el mensaje que presentaremos en pantalla excede el número de caracteres que caben en la línea de comandos, podemos recurrir al código \n, expuesto al principio de este MÓDULO con el resto de los códigos admitidos. \n representa un salto de línea con retorno de carro, pero no un INTRO. De esta forma, el programa anterior mostraría la siguiente línea en pantalla:

Indique 2º punto de la diagonal del rectángulo:

Pero si lo escribimos de la siguiente forma, por ejemplo:

(DEFUN C:Caja ()
--(SETQ Esq1 ’(100 100))
--(SETQ Esq2 (GETCORNER Esq1 "Indique 2º punto\nde la diagonal\ndel
--rectángulo: "))
(COMMAND "rectang" Esq1 Esq2)
)

mostrará:

Indique 2º punto
de la diagonal
del rectángulo:

NOTA IMPORTANTE DE SINTAXIS: Mientras no se indique lo contrario, si se separan las líneas en la escritura de los programas de estas páginas, es exclusivamente por falta de espacio. En la práctica, al escribir un programa en un editor ASCII, cada vez que damos un INTRO para saltar a la línea siguiente, para el intérprete de AutoLISP es un espacio en blanco. Por eso si escribimos lo siguiente:

(DEFUN C:MiProg
--(SETQ X 5)
--(COMM
--AND "linea" X ’(10 10) "")
)

el resultado de la tercera línea, que podemos ver en el historial de la línea de comandos pulsando F2 para conmutar a pantalla de texto, será el siguiente:

(COMM AND "linea" X ’(10 10) "")

lo que producirá un error null function de AutoLISP. Sin embargo, si el programa fuera:

(DEFUN C:MiProg
--(SETQ X 5)
--(COMMAND
--"linea" X ’(10 10) "")
)

y siempre que tras COMMAND no exista ningún espacio, el resultado sería:

(COMMAND "linea" X ’(10 10) "")


que es perfectamente correcto. Si lo que queremos es separar en líneas textos literales que aparecerán por pantalla (por que no caben en una sola línea), utilizaremos el código
\n explicado. Por lo general, escribiremos todas las línea seguidas en el archivo de texto, a no ser que nos resulte incómoda su extremada longitud para la edición.

 

 

ONCE.7.2. Captura de datos numéricos

Siguiendo con las funciones de solicitud de datos, vamos a pasar ahora a explicar cómo preguntar por datos numéricos al usuario. Para este tipo de misión disponemos en AutoLISP de dos funciones, GETINT y GETREAL.

(GETINT [mensaje])

La función GETINT —cuya sintaxis se indica— solicita y acepta un número entero introducido por el usuario. El valor de dicho número ha de estar comprendido entre –32768 y 32767. Si se introduce un valor real o un dato no numérico, AutoLISP devuelve un mensaje de error indicando que ha de ser un número entero y solicita un nuevo número. El mensaje de error proporcionado es similar (aunque no igual) al que produce el comando MATRIZ (ARRAY en inglés) de AutoCAD 14 al introducir un número con decimales (real) cuando pregunta por número de filas o de columnas.

mensaje proporciona la posibilidad de escribir un mensaje a la hora de solicitar el valor; es opcional. Como todos los textos literales y cadenas, el mensaje indicado irá encerrado entre comillas dobles. Un ejemplo:

(GETINT "Introduzca el número de vueltas de la rosca: ")

(GETREAL [mensaje])


GETREAL es totalmente similar a la función anterior, salvo que acepta número reales. Estos números pueden tener todos los decimales que se quiera introducir, separado de la parte entera por el punto decimal (.). Si se introduce un número entero se toma como real, es decir, con un decimal igual a 0 (28 = 28.0) y, si se introduce un carácter no numérico se produce un error de AutoLISP, proporcionando la opción de repetir la entrada. El argumento mensaje funciona igual que con GETINT.

Veamos un ejemplo de un pequeño programa con GETINT y GETREAL:

;Programa que realiza el producto
;entre un número entero y un número real.
(DEFUN C:Producto (); Comienzo de la función de usuario.
--(SETQ Ent (GETINT "Introduzca un número entero: ")); Número entero.
--(SETQ Real (GETREAL "Introduzca un número real: ")); Número real.
--(* Ent Real); Producto.
); Fin de función de usuario.
;Fin del programa

Como vemos, los comentarios (precedidos del carácter ;) se pueden incluir en cualquier parte del programa. Como se explicó en el punto 10. de la sección ONCE.2.3., también podemos incluir comentarios en medio de las líneas utilizando los caracteres ;| para la apertura y |; para el cierre (son los caracteres de punto y coma y barra vertical). De la siguiente forma:

(SETQ X ;| se guarda en x |; 5 ;|el valor 5|;)

O incluso en varias líneas:

(SETQ X ;| se guarda
en x |; 5 ;|el valor 5|;)


NOTA: Al contrario de cómo ocurría en los archivos ASCII de personalización, en un archivo de código AutoLISP no se hace necesario un INTRO al final de la última línea para que funcione el programa. Aunque no viene mal introducirlo por comodidad y para no perder la costumbre.

 

ONCE.7.3. Distancias y ángulos

Las tres funciones siguientes nos permitirán solicitar distancias y ángulos al usuario. La función GETDIST acepta el valor de una distancia introducida y su sintaxis es la siguiente:

(GETDIST [punto_base] [mensaje])

El valor de la distancia puede ser introducida por teclado o directamente indicando dos puntos en pantalla, como muchas distancias en AutoCAD. Si se introduce por teclado el formato ha de ser el establecido por el comando UNIDADES (UNITS). Pero independientemente de este formato, GETDIST devuelve siempre un número real.

mensaje funciona como en todas las funciones explicadas. Y punto_base permite incluir un punto de base a partir del cual se visualizará una línea elástica hasta introducir un segundo punto para la distancia.

Veamos un ejemplo con GETDIST:

(DEFUN C:Circulo2 ()
--(SETQ Centro (GETPOINT "Introduzca el centro del círculo: "))
--(SETQ Radio (GETDIST Centro "Introduzca el radio del círculo: "))
--(COMMAND "_circle" Centro Radio)
)

Este ejemplo pide el centro de un futuro círculo y, al pedir el radio ya está "enganchado" a dicho centro; se introduce el segundo punto del radio y el círculo se dibuja. Al final AutoLISP devuelve nil.

NOTA: Pruébese que podemos utilizar los modos de referencia a objetos (Punto Final, Punto Medio, Centro...), los filtros (.XY, .YZ...) y demás con todos los pequeños programas que estamos aprendiendo a hacer.

(GETANGLE [punto_base] [mensaje])

GETANGLE espera a que el usuario introduzca un ángulo y devuelve su valor. Dicho ángulo puede ser introducido por teclado —según formato actual de UNIDADES (UNITS)— o mediante dos puntos en pantalla con el cursor. El valor devuelto siempre será un número real en radianes. Hay que tener en cuenta que los ángulos se devuelven considerando como origen el indicado en la variable de AutoCAD ANGBASE, pero medidos en el sentido antihorario (independientemente de lo que especifique la variable ANGDIR). Se utiliza esta función sobre todo para medir ángulos relativos.

NOTA: El orden de introducción de los puntos (si se hace con el dispositivo señalador) influye en el ángulo medido. Por ejemplo, si desde un punto A a otro B de miden 30 grados, desde el punto B al A se medirán 210 grados.

Si se indica un punto base se muestra la típica línea elástica. Si se escribe un punto de base 3D, el ángulo se mide sobre el plano XY actual únicamente. Si no se indica punto de base se solicitan los dos puntos y se calcula el ángulo de la línea que une ambos en radianes.

mensaje funciona como en las funciones anteriores. Veamos un pequeño ejemplo:

(DEFUN C:GiraSCP ()
--(SETQ AngRad (GETANGLE "Introduzca un ángulo: "))
--(SETQ AngGrad (/ (* AngRad 180) PI))
(COMMAND "_ucs" "_x" AngGrad)
)


El programa solicita el ángulo para imprimir un giro al SCP con respecto al eje X y lo guarda en
AngRad (como sabemos el resultado de GETANGLE es en radianes). Después guarda en AngGrad la conversión del ángulo pedido a grados sexagesimales. Por último, gira el SCP el ángulo en cuestión alrededor del eje X.

(GETORIENT [punto_base] [mensaje])

La función inherente a AutoLISP GETORIENT funciona de forma parecida a la anterior. La diferencia con GETANGLE estriba en que, GETORIENT devuelve los ángulos con el origen 0 grados siempre en la posición positiva del eje X del SCP actual y el sentido positivo antihorario, independientemente de los valores de las variables ANGBASE y ANGDIR de AutoCAD. Se utiliza esta función sobre todo para medir ángulos absolutos.

Al igual que con GETANGLE, el valor devuelto es siempre en radianes y, si el punto de base es 3D, el ángulo de mide sobre el plano XY actual.

Para comprender bien la diferencia entre ambas funciones de captura de ángulos vamos a ver un ejemplo simple. Si tuviéramos el origen de ángulos definido en el eje Y negativo y el sentido positivo como horario, lo que entendemos por un ángulo de 45 grados (con respecto a la horizontal), produciría un valor de 45 grados con la función GETORIENT y un valor de 135 grados con la función GETANGLE (ambos en radianes).

Si indicamos dos puntos en pantalla que unidos describan una línea a 45 grados (con respecto a la horizontal), el ángulo se mide desde el origen indicado en UNIDADES (UNITS) con GETANGLE y desde el lado positivo del eje X con GETORIENT (las 3 de la esfera de un reloj) hasta dicha línea y siempre en sentido antihorario (con ambas funciones). De ahí los dos tipos de resultado.

Evidentemente, si indicamos un ángulo por teclado el resultado siempre será el mismo.

El ejemplo de la función anterior puede aplicarse a ésta. Habremos de tener mucho cuidado a la hora de entrar los ángulos señalando puntos, debido a las características de ambas funciones, ya que pueden generar resultados erróneos de giro del SCP.

 

ONCE.7.4. Solicitud de cadenas de texto

Con AutoLISP también tenemos la posibilidad de solicitar, y posteriormente procesar, cadenas de texto. La función para realizar esto es GETSTRING. Podemos ver su sintaxis a continuación:

(GETSTRING [T] [mensaje])

GETSTRING acepta una cadena de caracteres introducida por teclado y devuelve dicha cadena, precisamente en forma de cadena (entre comillas). Ejemplo:

(GETSTRING)

Si introducimos las siguientes cadenas devuelve lo que se indica:

AutoCAD devuelve "AutoCAD"
123456 devuelve "123456"
INTRO
devuelve ""


El argumento opcional
T (o equivalente) de la función especifica la posibilidad de introducir espacios blancos en la cadena. T es el símbolo predefinido del que hemos hablado más de una vez; es el carácter de cierto o verdadero. Si no se incluye, o se incluye otro u otros cualesquiera, GETSTRING no aceptará espacios blancos y, en momento en que se introduzca uno se tomará como un INTRO y se acabará la función. Si se incluye este argumento, GETSTRING aceptará espacios blancos y sólo será posible terminar con INTRO.

mensaje actúa como siempre. Veamos unos ejemplos:


(GETSTRING "Introduce un texto sin espacios: ")
(GETSTRING T "Introduce cualquier texto: ")
(GETSTRING (= 3 3) "Introduce cualquier texto: ")
(GETSTRING (/= 3 3) "Introduce un texto sin espacios: ")

Si se introduce una contrabarra (\) en cualquier posición, en dicha posición se devuelven dos contrabarras (\\) que, como sabemos, es el código para el carácter contrabarra. Esto será útil a la hora del manejo de archivos, que ya estudiaremos.


NOTA: Como se ha visto en el tercero de los primeros ejemplos de esta función, si se introduce un
INTRO (o un espacio también si no se admiten), AutoLISP devuelve una cadena vacía (""). Si se admiten espacios y sólo se teclean espacios, se devuelven dichos espacios como cadena.

NOTA: Si se introducen más de 132 caracteres, AutoLISP sólo devuelve los 132 primeros, desechando los restantes.

 

ONCE.7.5. Establecer modos para funciones GET...

Antes de ver la última función de este tipo, y para comprender su funcionamiento, hemos de introducir una nueva función AutoLISP muy utilizada y versátil. Esta función es INITGET y su sintaxis es:

(INITGET [modo] [palabras_clave])

La función INITGET especifica el modo en que va a operar la siguiente función del tipo GET..., esto es, la primera que se encuentre tras ella. Este modo se indica con el argumento modo, y es un número entero cuyo valor especifica un bit de control que determina los valores no permitidos para la siguiente función GET.... Los valores son los que siguen:

Valor de bit --------- Modo

-----------------------------------------------------------------------------------------

1 ------------------ No admite valores nulos, es decir, INTRO como respuesta.

2 ------------------ No admite el valor cero (0).

4 ------------------ No admite valores negativos.

8 ------------------ No verifica límites, aunque estén activados.

16 ----------------- (No se utiliza).

32 ----------------- Dibuja la línea o el rectángulo elásticos con línea de trazos en
-------------------- lugar de continua.

64 ----------------- Hace que la función GETDIST devuelva distancias 2D.

128 ---------------- Permite introducir datos arbitrarios por teclado. Tiene prioridad
-------------------- sobre el valor
1.

Para ver la manera de utilizar esto pongamos un ejemplo. Imaginemos que queremos solicitar un número al usuario para realizar una cierta copia de objetos. Dicho número, evidentemente, habrá de ser entero (utilizaremos GETINT), pero además no puede ser negativo (no podemos copiar un objeto –24 veces). Pues para controlar dicho filtro, escribiremos lo siguiente:


(INITGET 4); Establece que el siguiente GETINT no admita valores negativos
(GETINT "Introduzca el número de copias: "); Solicita el número de copias

De esta forma, si el usuario introduce un número negativo, AutoLISP devuelve un mensaje de error diciendo que el número ha de ser positivo, y vuelve a solicitarlo.

Pero siguiendo con nuestro ejemplo, nos percatamos de que tampoco se podría introducir un valor de cero, porque no se puede copiar un objeto 0 veces. Habremos de indicarle también a GETINT que tampoco admita el cero como respuesta. Para especificar varios valores a la vez debemos sumarlos. Así pues, como el modo de no admitir negativos es el 4 y el de no admitir el cero es el 2, el valor final del bit sería un 6 (4 + 2 = 6). De esta forma haríamos:

(INITGET 6)
(GETINT "Introduzca número de copias: ")

Y para "redondear" el ejemplo, que menos que evitar que introduzca un INTRO a la pregunta, es decir, obligar al usuario a introducir un valor:

(INITGET 7)
(GETINT "Introduzca número de copias: ")

Esto es resultado de sumar los tres valores de bits correspondientes (1 + 2 + 4 = 7).

El modo en INITGET también puede indicarse como suma de valores de bits. Por ejemplo, el último caso podría haberse escrito así:

(INITGET (+ 1 2 4))
(GETINT "Introduzca número de copias: ")

Si se vuelve a utilizar ahora otra función del tipo GET... habría que especificar otro INITGET si fuera necesario, ya que cada uno sólo afecta a la función GET... que le sigue y solamente a esa.

NOTA: INITGET siempre devuelve nil.

Los modos establecidos con INITGET sólo se tienen en cuenta para las funciones GET... con las cuales tienen sentido. Así, no tiene sentido establecer un modo que no admita valores negativos con una función GETPOINT, puesto que ésta devuelve un punto como una lista de tres elementos y las listas no pueden ser negativas por definición. En la siguiente tabla se muestran los modos que tienen sentido con las diferentes funciones tipo GET....

Función Valores de bits de modo con sentido para la función

-------------------------------------------------------------------------------------

GETINT 1 --- 2 --- 4 --------------------- 128

GETREAL 1 --- 2 --- 4 --------------------- 128

GETDIST 1 --- 2 --- 4 --------- 32 --- 64 - 128

GETANGLE 1 --- 2 --------------- 32 -------- 128

GETORIENT 1 --- 2 -------------- 32 -------- 128

GETPOINT 1 --------------- 8 --- 32 -------- 128

GETCORNER 1 --------------- 8 --- 32 -------- 128

GETSTRING ---------------------------------------

GETKWORD 1 --------------------------------- 128


El valor 128 es el más especifico. Se utiliza para tener la posibilidad de responder a una solicitud de función GET... por ejemplo con una expresión AutoLISP. Ésta se aceptaría como una cadena de texto y se podría evaluar posteriormente mediante la función EVAL (tal como veremos). Como el valor 128 tiene prioridad sobre el valor de bit 1, se aceptaría también un INTRO en la forma de una cadena de texto vacía "".

Veamos un pequeño programa de ejemplo de todo esto e intentemos comprenderlo. El listado es el que sigue:

; Nuevo comando CircEjes de AutoCAD
(DEFUN CircEjes (/ Centro Radio)
--(INITGET 1)
--(SETQ Centro (GETPOINT "Centro del círculo: "))
--(INITGET (+ 1 2 4))
--(SETQ Radio (GETDIST Centro "Radio del círculo: "))
--(COMMAND "_circle" Centro Radio)
--(INITGET 1)
--(COMMAND "_line" Centro "_qua" "\\" "")
--(COMMAND "_line" Centro "_qua" "\\" "")
--(COMMAND "_line" Centro "_qua" "\\" "")
--(COMMAND "_line" Centro "_qua" "\\" "")
)

(DEFUN C:CircEjes ()
--(CircEjes)
)

; Fin de CircEjes


En este ejemplo se observan algunas prácticas habituales a la hora de desarrollar programas en AutoLISP. La primera dice relación a la estructuración de programas. Como se ve, primero se define una función de usuario CircEjes y luego el propio comando de AutoCAD (C:CircEjes) con el mismo nombre. Esto se suele realizar así, primero por estructurar los programas: la definición de la orden de usuario (C:CircEjes) no contiene la secuencia de rutinas del programa en sí, sino una llamada a las funciones de usuario (en este caso sólo una, CircEjes) necesarias para ejecutar la orden. Y, segundo, por claridad estructural a la hora de observar el listado de un programa: podemos acceder directamente al comando de usuario (C:CircEjes) para ver como va llamando sucesivamente a diferentes funciones e ir comprobando cada una de ellas. Por lo tanto, bajo la definición del comando en sí, únicamente aparecerán llamadas a funciones (entre paréntesis porque son funciones de AutoLISP sin los caracteres C:) y algunas otras funciones que ya veremos; por ejemplo para establecer valores de variables antes y después de las llamadas, etcétera.

Por otro lado también podemos apreciar la declaración de las dos variables que utilizará el programa como locales en los argumentos de DEFUN. Como se explicó, la manera de declarar variables locales es con una barra y, después de un espacio, sus nombres separados también por espacios. Y la diferencia que había con las globales, es que las locales desaparecen de memoria en cuanto se acaba de ejecutar el programa, o sea, no ocuparán memoria inútilmente. Si al acabar el programa intentamos evaluar alguna en la línea de comandos mediante el carácter !, el resultado será nil.

Otra de las características importantes de definir, por un lado la función de usuario y por el otro el comando de AutoCAD, es la posibilidad de introducir variables globales en los argumentos de las funciones creadas con DEFUN. Recordemos que si definimos con DEFUN una función del tipo C: (comando de AutoCAD) no se pueden introducir variables globales en sus argumentos. Recordemos también que si no se introduce argumento alguno, todas las variables declaradas con SETQ serán globales (seguirán en memoria al terminar el programa). Esto puede ser útil cuando otro programa AutoLISP necesita de esas variables para funcionar.

Por último, hemos de recordar también que si introducimos variables globales y locales juntas como argumentos de DEFUN, entre la última global y la barra, y entre la barra y la primera local habrá de haber un espacio blanco. Además siempre estarán en el orden global-local.

El programa del ejemplo en sí es un poco rudimentario, pero con los conocimientos que poseemos hasta ahora no podemos hacer más. Simplemente dibuja (de un modo un poco chapucero y manual) un círculo con sus cuatro ejes —sólo hasta el círculo, sin sobresalir—. Pide el centro y el radio, dibuja el círculo y, luego, va dibujando líneas (cuatro) desde el centro hasta un punto que ha de indicar el usuario. El punto que debe indicarse ha de ser un cuadrante (aunque no es obligatorio, pero si no se indica el programa no funcionará bien). El modo de referencia Cuadrante se activa automáticamente tras "engancharse" la línea al centro del círculo.

 

ONCE.7.5.1. Palabras clave

Hemos dejado un poco colgada la explicación de INITGET, a falta de explicar el segundo de sus argumentos palabras_clave. Vamos a ver para que sirve exactamente.

El argumento palabras_clave es una cadena de texto que define una serie de respuestas alternativas para las funciones del tipo GET.... Vamos a ver un ejemplo para entender esto. Imaginemos que queremos solicitar un punto para el final de una línea, lo haremos con GETPOINT. Sabemos que dicho punto lo podemos introducir directamente en pantalla o por teclado. Pero, en este caso, también nos interesa que se acepten otros caracteres, por ejemplo una "H" para deshacer el tramo último y una "C" para cerrar. Como bien sabemos, si introducimos un carácter no numérico con GETPOINT AutoLISP nos dará un mensaje de error. Pero si definimos qué caracteres se pueden aceptar (los expuestos) GETPOINT los capturará sin ningún problema. Esto lo realizamos desde INITGET. Vamos a ver el ejemplo:

(INITGET 1 "H C")
(GETPOINT "Introducir nuevo punto: ")

En este caso GETPOINT no acepta INTRO como respuesta (valor de bit 1), pero si aceptará un carácter H o un carácter C (da lo mismo mayúsculas que minúsculas). Los caracteres han de indicarse entre comillas —es una cadena— y separados entre sí por un espacio blanco.

Si las respuestas posibles tienen una o varias letras como abreviatura mínima necesaria para identificar dicha respuesta, se indican esas letras en mayúsculas en INITGET y el resto en minúsculas. Por ejemplo:

(INITGET "desHacer Cerrar")

Este ejemplo aceptará como respuesta válida H (o h), C (o c) y las palabras completas DESHACER y CERRAR (tanto mayúsculas como minúsculas). Es exactamente lo mismo que podemos apreciar en el comando MATRIZ (ARRAY en inglés) de AutoCAD, por ejemplo. Tras teclearlo y designar los objetos correspondientes, el comando expone:

Matriz Rectangular o Polar (<R>/P):

Podemos escribir R, P, Rectangular o Polar, cualquiera de las opciones. Si ésta fuera una orden de usuario, la función INITGET podría haber sido:

(INITGET "Rectangular Polar")

Hemos de tener cuidado con esto de las abreviaturas porque a veces, incluso con los propios mensajes que emite AutoCAD, parece que hay mucha gente que tiene problemas. En el caso siguiente:

(INITGET "DESactivar")

no se admite ni D ni DE, sino DES (como abreviatura válida) y la palabra completa DESACTIVAR; tanto mayúsculas como minúsculas todas las opciones.

La abreviatura es pues el mínimo número de caracteres en que debe coincidir la respuesta del usuario con la alternativa indicada en INITGET. A partir de ahí, se admiten más caracteres por parte del usuario hasta la longitud de la respuesta alternativa completa. Por ejemplo:

(INITGET 1 "Cont")

admitiría C, CO, CON o CONT (mayúsculas o minúsculas), pero no CONTINUA o CONTINUAR.

NOTA: Es norma lógica indicar, como mínimo, el bit 1 en estos tipos de INITGET con palabras clave para que no se admita el INTRO como respuesta, ya que es necesaria una de las opciones.

También el posible indicar la abreviatura junto a la respuesta completa en mayúsculas y separada por una coma (aunque recomendamos el método anterior). Por ejemplo:

(INITGET 1 "DESACTIVAR,DES")

equivale a

(INITGET 1 "DESactivar")

NOTA: Todas las funciones GET... admiten palabras clave.

Un ejemplo sencillo aunque no funcional:

(DEFUN C:Prueba ()
--(INITGET 1 "desHacer Cerrar")
(GETPOINT "desHacer/Cerrar/<Primer punto>: ")
)

Este ejemplo no realiza nada, y es que aún no hemos aprendido a procesas estos datos de palabras clave. Pero es una buena muestra de lo que sería un mensaje típico de AutoCAD en la línea de comandos. El programa muestra:


desHacer/Cerrar/<Primer punto>:

La opción por defecto (entre corchete angulares) es señalar un punto en pantalla (o por teclado), aunque podemos acceder a otras dos opciones alternativas mediante los caracteres H y C (o sus palabras completas) respectivamente. Al acceder a estas opciones el programa no hace nada y es que, como decimos, hace falta procesar esta entrada de usuario (ya se verá).

Al indicar cualquiera de las opciones anteriores, AutoLISP devuelve la palabra clave, entre comillas, correspondiente indicada en INITGET.

Pues vista esta característica de las palabras clave, ya podemos estudiar la última de las funciones GET..., la cual emplazamos para después de INITGET y es GETKWORD. La sintaxis de GETKWORD es:

(GETKWORD [mensaje])

Esta función solicita únicamente una de una serie de palabras clave indicadas en INITGET de la forma explicada. Sólo sirve para palabras clave, y nada más. Solicitará dichas palabras y, si no se introduce alguna de ellas, da un mensaje de error y vuele a indicar la solicitud. Por ejemplo:

(INITGET 1 "Sí No")
(GETKWORD "Cerrar el muro (Sí/No): ")

Tras esta pregunta podríamos teclear, como sabemos, o S o N o o NO (incluso el "sí" sin tilde y tanto mayúsculas como minúsculas). Pero sólo podríamos realizar dichas entradas, ninguna más.

La función GETKWORD devuelve, como cadena de texto, la opción especificada tal y como se indicó en INITGET. Si no se especificó ninguna devuelve nil.

 

6ª fase intermedia de ejercicios

· Realizar un programa que dibuje aros (arandelas sin relleno) solicitando el centro, el diámetro interior y el diámetro exterior.

· Realizar el mismo ejercicio anterior pero solicitando el centro, el radio intermedio del aro (mitad entre interior y exterior) y el grosor del mismo.

· Practicar la característica de palabras clave con algún ejercicio inventado, aunque no se procesen las entradas de estas palabras.

Autor: Jonathan Préstamo Rodríguez.
Para: La Web del Programador.