ONCE.20.2. Funciones de gestión de la Base de Datos

Una vez vista toda la teoría acerca de la Base de Datos interna de AutoCAD, pasaremos a la práctica estudiando las funciones que nos permiten gestionarla. En este apartado vamos a tratar cuatro grupos de funciones distintos: funciones para trabajar con conjuntos designados, funciones que gestionan nombres de entidades, funciones para acceder a los datos de las entidades y funciones específicas para gestionar objetos no gráficos. Todas ellas, convenientemente combinadas (y con algunas funciones de manejo de listas concretas), nos darán acceso libre y directo a la Base de Datos de AutoCAD 14.

De todas formas no vamos a ver dichas funciones de un modo ordenado. Para sacarle más partido a la explicación las mezclaremos, de este modo podremos ir siguiendo paso a paso el modo de acceder a la Base de Datos.

 

ONCE.20.2.1. Crear un conjunto de selección

Si bien las funciones del tipo GET... nos permitían obtener del usuario puntos, distancias, ángulos y demás, evidente es que necesitaremos otro tipo de funciones con las que obtener entidades completas o grupos de entidades para su proceso. Este conjunto de funciones SS... son las que vamos a comenzar a ver con SSGET, aunque como ya hemos dicho no veremos las demás en orden temático.

(SSGET [modo] [punto1 [punto2]] [lista_puntos] [lista_filtros])

La función SSGET acepta el conjunto designado de entidades. Se puede utilizar sin parámetros así:

(SSGET)

SSGET presenta el mensaje Designar objetos: en línea de comandos (Select objects: en versiones inglesas de AutoCAD). La designación puede hacerse mediante cualquiera de los modos de designación permitidos: por un punto, una ventana, una captura, un polígono, etcétera. En el momento de pulsar INTRO, la función acepta del conjunto de designación, presentando un mensaje del tipo <Conjunto de selección: n> (<Selection set: n> en ingles), donde n es un número de orden entero que representa el conjunto de selección actual.

La forma lógica de utilización de SSGET pasa por el almacenamiento en una variable del conjunto de selección en cuestión, el cual luego podrá ser llamado por los diversos comandos de AutoCAD o por otra función de AutoLISP para su proceso. Por ejemplo:

(SETQ Conjunto (SSGET))

(COMMAND "_.move" Conjunto "" "10,0" "")

NOTA: Recordemos la utilidad del punto (.) antes del comando por si estuviera redefinido (MÓDULO SIETE).

Esta rutina solicita al usuario una designación de objetos, los cuales serán recogidos en un conjunto de selección y guardados en la variable Conjunto. Posteriormente, se desplazan los objetos una distancia de 10 unidades de dibujo en el eje X.

NOTA: Si queremos hacer pruebas en línea de comandos para comprobar la funcionalidad de SSGET, una vez ejecutada la función, podemos hacer una llamada a cualquier comando que solicite designar objetos e introducir el nombre de la variable como conjunto de selección, pero con el signo de cerrar admiración (!) por delante. Desde rutinas o programas AutoLISP no es necesario incluir dicho símbolo, evidentemente.

NOTA: La diferencia entre SSGET y el comando DESIGNA es evidente. SSGET permite designar cualquier conjunto y guardarlo en una variable; de este modo podemos disponer de varios conjuntos de selección para ser utilizados. DESIGNA permite designar una serie de objetos que se incluirán en un conjunto de selección, el cual puede ser referenciado posteriormente mediante el modo Previo de selección; en el momento en que volvamos a hacer DESIGNA el conjunto anterior desaparece. Además no tiene sentido guardar en una variable el resultado de un DESIGNA ya que luego no funciona a la hora llamarlo para algún comando. DESIGNA viene muy bien para su utilización en macros, en los programas de AutoLISP usaremos como norma general SSGET.

El argumento modo especifica el método de designación. modo puede tener cualquiera de los siguiente valores:

· "P". Crea un conjunto de selección con el último conjunto de objetos previamente seleccionado. Equivale al modo de designación Previo.

· "U". Crea un conjunto de selección con la última entidad añadida a la Base de Datos del dibujo de las visibles en pantalla, es decir la última entidad dibujada y no borrada de las visibles en pantalla. Equivale al modo de designación Último.

· "I". Crea un conjunto de selección con el conjunto implícito designado (variable PICKFIRST de AutoCAD activada).

· p1. Crea un conjunto de selección con la entidad que pasa por el punto p1. Equivale a señalar ese punto en la pantalla. El resultado dependerá del modo o modos de referencia a objetos actuales, es decir del valor de la variable OSMODE.

· "V" p1 p2. Crea un conjunto de selección a partir de la Ventana cuyos vértices son los puntos p1 y p2. Ambos puntos no se pueden omitir.

· "C" p1 p2. Crea un conjunto de selección a partir de la Captura cuyos puntos son los puntos p1 y p2. Ambos puntos no se pueden omitir.

· "PV" lista_puntos. Crea un conjunto de selección a partir del Polígono-Ventana cuyos vértices son los puntos indicados en la lista. La lista no se puede omitir.

· "PC" lista_puntos. Crea un conjunto de selección a partir del Polígono-Captura cuyos vértices son los puntos indicados en la lista. La lista no se puede omitir.

· "B" lista_puntos. Crea un conjunto de selección a partir del Borde cuyos vértices son los puntos indicados en la lista. La lista no se puede omitir.

· "X". Crea un conjunto de selección todas las entidades de la Base de Datos, visibles o no visibles en pantalla. Equivale al modo de designación Todo.

NOTA: Los valores entre comillas son cadenas que deben indicarse como tales.

NOTA: Los valores entre comillas representan a los modos de designación de AutoCAD 14 y se introducen como cadenas por ser una llamada a dichos modos. Es por ello, que en versiones idiomáticas diferentes a la castellana han de indicarse de forma conveniente. Por ejemplo, en lugar de "U" indicar "L", para Último; es factible la sintaxis "_L" , por ejemplo, para cualquier versión idiomática del programa.

Veamos un ejemplo sencillo. La siguiente rutina dibuja una línea en pantalla y luego la borra:

(COMMAND "_.line" "0,0" "100,100" "")
(COMMAND "_.erase" (SSGET "_l") "")

Otro ejemplo; éste dibuja un rectángulo y luego lo borra también:

(COMMAND "_.rectang" "100,100" "300,300")
(SETQ Conjunto (SSGET "_c" ’(100 100) ’(300 300)))
(COMMAND "_.erase" Conjunto "")

Además de todo esto, disponemos de la posibilidad de introducir filtros de selección. Estos filtros han de ser listas de asociaciones que filtran o realizan una criba de los objetos según determinadas condiciones, quedándose con aquellas entidades de la Base de Datos que cumplen dichas condiciones.

Se puede añadir una lista de filtros a cualquiera de las modalidades de selección expuesta arriba. Los filtros de selección se añaden detrás de los parámetros propios de selección (como "P", "V" p1 p2 o "X").

Las listas de filtros hacen referencia a las propiedades de la entidad, como el color, su capa, tipo de línea, etc. O también a puntos u otras características. Para construir una lista de filtro deberemos construir la propia lista con cada una de sus sublistas, las cuales serán las características o propiedades de las entidades que queremos filtrar. Las sublistas pueden ser pares punteados construidos con CONS o no.

Así, un ejemplo muy típico es aquel que permite seleccionar todos los objetos de un dibujo que tengan unas determinadas características. Por ejemplo, para designar todos los círculos del dibujo actual, que además estén en la capa PIEZA y tengan asignado el color rojo, haríamos:

(SSGET "x" (LIST (CONS 0 "CIRCLE")
-----------------(CONS 8 "Pieza")
-----------------(CONS 62 1)
-----------)
)

Construimos pues una lista con LIST que recoge las condiciones del filtro, que no son otra cosa sino propiedades de la entidad. AutoLISP explorará toda ("X") la Base de Datos del dibujo actual y seleccionará ("SSGET") las entidades que posean dichas propiedades.

Otro ejemplo puede ser la designación o selección de todas la líneas que comiencen en un punto:

(SSGET "x" (LIST (CONS 0 "LINE")
-----------------’(10 10.0 10.0 0.0)
-----------)
)

Como se ve aquí, la segunda condición no es par punteado, ya que dice relación a los puntos iniciales de las líneas (en este caso de coordenadas X = 10, Y = 10 y Z =0), por lo que se construye como una lista normal (con el apóstrofo ’ de literal).

Las listas de filtros pueden ser enteramente construidas como literales también. En el primero de los ejemplos sería así:

(SSGET "x" ’((0 . "CIRCLE")
-------------(8 . "Pieza")
-------------(62 . 1)
------------)
)

En estos casos habremos de describir correctamente la notación de los pares punteados, es decir: el primer valor, un espacio, el punto, otro espacio y el segundo valor, todo ello entre paréntesis. Aunque resulta más elegante y sencillo, quizás, hacer mediante CONS.

En principio, cada elemento de una lista de filtros de selección se añade como una condición más que se debe cumplir. Sin embargo, existe la posibilidad de añadir operadores relacionales y booleanos a estos filtros. Esto se realiza con el código especial –4, por ejemplo:

(SSGET "x" (LIST (CONS 0 "TEXT")
-----------------(CONS –4 "<=")
-----------------(CONS 40 5)
-----------)
)

El operador relacional, que ha de ser una cadena, se aplica a la condición que le siga en la lista. En este último ejemplo, SSGET selecciona entidades de texto cuya altura (código 40) sea menor o igual ("<=") que 5 unidades de dibujo.

La tabla siguiente muestra cuáles son los operadores relacionales que se pueden incluir en los filtros, con su correspondiente descripción:

Operador relacional ------ Descripción

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

"*"
---------------------- Cualquier valor (siempre verdadero)
"=" ---------------------- Igual que
"!=" --------------------- Distinto de
"+/=" -------------------- Distinto de
"<>" --------------------- Distinto de
"<" ---------------------- Menor que
"<=" --------------------- Menor o igual que
">" ---------------------- Mayor que
">=" --------------------- Mayor o igual que
"&" ---------------------- AND binario (sólo grupos de números enteros)
"&=" --------------------- Igual a enmascarado binario (sólo grupos de números enteros)

No se puede especificar un nombre de capa menor o igual que otro (ni por orden alfabético), por ejemplo, por lo que estos operadores se aplican sólo a datos numéricos. Para establecer filtros con los datos textuales o alfanuméricos se utilizan los caracteres comodín explicados con la función WCMATCH, en la sección ONCE.12..

Para condiciones que afectan a puntos es factible agrupar operadores en grupos de tres, separados por comas. Por ejemplo:

(SSGET "x" (LIST (CONS 0 "LINE")
-----------------(CONS –4 "<,>,*")
-----------------’(11 10 100)
-----------)
)

En este ejemplo se buscan todas las líneas cuyas coordenadas de punto final sean: en X menores que 10, en Y mayores que 100 y sus coordenadas Z cualesquiera.

Como hemos dicho, además de operadores relacionales, los cuales afectan sólo a la siguiente condición, se pueden agrupar condiciones mediante operadores booleanos, empleando un operador de comienzo y otro de final. Estos operadores también se especifican con el código –4 y son los de la tabla de este archivo.

En el ejemplo siguiente se designarán todos los textos de la capa NOTAS y todos los arcos de radio 10:

(SSGET "X" ’((-4 . "<OR")
-------------(-4 . "<AND")(0 . "TEXT")(8 . "NOTAS")(-4 . "AND>")
-------------(-4 . "<AND")(0 . "ARC") (40 . 10) (-4 . "AND>")
-------------(-4 . "OR>")
------------)
)

Los conjuntos de selección ocupan archivos temporales de AutoCAD. Por esa razón existe una limitación en cuanto al número máximo de conjuntos almacenados en variables, que es de 128 a la vez. Una vez alcanzado este límite, SSGET rechaza la posibilidad de crear un nuevo conjunto y devuelve nil. Para acceder a más conjuntos de selección es preciso eliminar alguno de los almacenados poniendo la variable a nil.

 

ONCE.20.2.2. Obtener el nombre de una entidad

Una vez seleccionadas las entidades y agrupadas en un conjunto de selección, deberemos extraer el nombre de la que o las que nos interesen para trabajar con ellas.

Como sabemos, en la Base de Datos la entidades se encuentran referenciadas mediante un nombre que es en realidad un número hexadecimal que indica la posición en memoria. Este nombre es único para cada entidad en cada sesión de dibujo, de forma que la identifica inequívocamente y la distingue de todas las demás del dibujo.

Por todo ello, para capturar una entidad, y solo esa, de un conjunto de selección lo más lógico es referirse a su nombre, y para extraer su nombre disponemos de la función SSNAME.

(SSNAME conjunto índice)

SSNAME devuelve el nombre de entidad (código –1), del conjunto de selección especificado, situada en el lugar indicado por el índice. Las entidades dentro de un conjunto comienzan a numerarse por el 0. Así, en un conjunto con cuatro entidades, éstas estarían numeradas de 0 a 3. Veamos un ejemplo:

(SETQ Entidad (SSNAME (SSGET) 0))

De esta forma designaríamos una o varias entidades en pantalla cuando nos lo pidiera SSGET y el nombre de la primera de ellas (SSNAME con índice 0) se guardaría en la variable Entidad.

Una vez obtenido el nombre de una entidad, puede ser procesado por otras funciones que veremos a continuación.

NOTA: Los nombres que devuelve SSNAME son sólo de entidades principales; esta función no puede acceder a las entidades que forman parte de una polilínea o un bloque.

 

ONCE.20.2.3. Extraer la lista de una entidad

Ahora que ya hemos designado una entidad y que podemos conocer su nombre, sólo queda extraer su lista de definición para poder modificarla o editarla. Para ello disponemos de la función ENTGET.

(ENTGET nombre_entidad [lista_aplicaciones])

Esta función ENTGET busca en la Base de Datos el nombre indicado de una entidad y devuelve la lista completa correspondiente a esa entidad. Se observa que se requiere el nombre de una entidad (código –1 en Base de Datos) y por lo tanto se hace necesario obtenerlo previamente con SSNAME —u otras que veremos—.

El ejemplo típico de descubrimiento de esta función (combinada con las anteriores) es:

(SETQ ListaEntidad (ENTGET (SSNAME (SSGET) 0)))

Con este ejemplo obtendremos la lista de definición en Base de Datos de cualquier entidad que designemos en pantalla y lo guardaremos en la variable ListaEntidad para su posterior proceso; si designamos varias sólo aceptará la primera de ellas (debido al índice 0 de SSNAME, como sabemos). Una lista de un círculo designado, por ejemplo, podría ser:

((-1 . <Nombre de objeto: 2770500>)
(0 . "CIRCLE")
(5 . "20")
(100 . "AcDbEntity")
(67 . 0)
(8 . "0")
(100 . "AcDbCircle")
(10 144.409 168.958 0.0)
(40 . 17.2339)
(210 0.0 0.0 1.0)
)

NOTA: Ahora podremos comprobar de manera factible toda la teoría explicada anteriormente sobre la Base de Datos de AutoCAD 14.

La manera más sencilla y utilizada de acceder a los datos de una entidad es mediante ASSOC (ya estudiada), para obtener la lista de asociaciones deseada, y luego con CAR, CDR, CADR, CADDR, etc., para capturar sus componentes (recordemos que funciones del tipo NTH no funcionan directamente con pares punteados).

De este modo, en el ejemplo anterior, y si hubiésemos designado el círculo cuya lista se propone, podríamos extraer la capa en la que se encuentra directamente:

(SETQ Capa (CDR (ASSOC 8 ListaEntidad)))

Lo que hacemos aquí es guardar en Capa el segundo elemento (CDR) de la sublista de asociación cuyo primer elemento (ASSOC) sea 8 (código para la capa).

NOTA: Recuérdese la necesidad de utilizar CDR y no CADR para capturar el segundo elemento de un par punteado.

Si quisiéramos extraer ahora por ejemplo la coordenada Y del centro del círculo haríamos:

(SET CentroY (CADDR (ASSOC 10 ListaEntidad)))

Ya que esta lista no es par punteado, el primer elemento saldría con CAR (el código 10 de coordenadas del centro para un círculo), el segundo con CADR (la coordenada X) y el tercero (coordenada Y) con CADDR. Para la coordenada Z utilizaríamos CADDDR.

NOTA: Como se explicó en su momento, las coordenadas de los puntos de las entidades se expresan en el Sistema de Coordenadas de Entidad o de Objeto (SCE o SCO según la denominación adoptada). En la mayoría de las entidades dibujadas en el Sistema de Coordenadas Universal SCU, las coordenadas en la base de datos coinciden con las universales. Pero si se han dibujado en cualquier Sistema de Coordenadas Personal (SCP), se hace necesario recurrir a la función TRANS para efectuar las conversiones.

Por último decir que el argumento opcional lista_aplicaciones de ENTGET permite incluir en la lista devuelta los datos extendidos de entidades (los que siguen al código específico –3). De este tema hablaremos en la sección ONCE.20.2.14..

 

ONCE.20.2.4. Actualizar lista y Base de Datos

Una vez accedido al elemento que nos interesa, deberemos realizar los cambios necesarios en la lista para modificar la entidad. Para ello utilizaremos básicamente funciones del tipo SUBST o APPEND, ya explicadas.

NOTA: Recordar que nos estamos moviendo entre listas y que cualquier función de manejo de listas nos puede ser útil: CONS, LIST, etcétera.

Así pues, retomemos el ejemplo anterior del círculo. Tras escribir:

(SETQ ListaEntidad (ENTGET (SSNAME (SSGET) 0)))

y designar un círculo, AutoLISP nos devuelve:

((-1 . <Nombre de objeto: 2770500>)
(0 . "CIRCLE")
(5 . "20")
(100 . "AcDbEntity")
(67 . 0)
(8 . "0")
(100 . "AcDbCircle")
(10 144.409 168.958 0.0)
(40 . 17.2339)
(210 0.0 0.0 1.0)
)

Si ahora quisiéramos, por ejemplo, cambiar la capa del círculo, habríamos de hacer:

(SETQ ListaEntidad (SUBST (CONS 8 "Ejes") (CONS 8 "0") ListaEntidad))

NOTA: Si la capa no existe se crea.

Como hemos de saber ya, CONS nos devolverá la nueva lista renovada. Si ocurre algún error, CONS devolverá la lista sin renovar.

Pero si quisiéramos en este caso cambiar el color del círculo, no podríamos utilizar CONS, ya que la lista del color (código 62) no aparece porque es PorCapa, por lo que no podemos decir que sustituya una nueva lista por otra que no existe.

En estos casos se utiliza APPEND, que nos permite añadir nuevos elementos a la lista por su manera de actuar. Así pues, para cambiar el círculo de color haríamos:

(SETQ ListaEntidad (APPEND ListaEntidad (LIST (CONS 62 1))))

NOTA: Todo ello en línea de comandos.

NOTA: Procúrese con APPEND añadir a la lista de una entidad una nueva lista, y no una nueva lista a la lista de una entidad. Es decir, la lista general irá antes, como argumento de APPEND, que la lista que debe agregarse. Si se realiza esto al revés, la nueva lista se añadirá por delante a la lista de la entidad y esto hará que no funcione correctamente. Como norma general los dos primeros elementos de una lista de entidad habrán de ser el nombre (con código -1) y el tipo (código 0), respectivamente; con las restantes sublistas (capa, color, punto inicial, centro, tipo de línea...) no importa el orden generalmente.

La razón de tener que formar una lista con la propia lista de asociación del color es que, si no lo hacemos, APPEND añade los valores de la lista sin asociar y provoca un error bad list. Si recordamos, APPEND toma los componentes de las listas y los junta todos en una. Si hacemos que la lista de par punteado se encuentre dentro de otra lista, APPEND tomará el par punteado como un solo elemento y se lo añadirá al resto (que también son sublistas) de la lista de la entidad.

NOTA: Repásense estas funciones en la sección ONCE.17..

Hemos de comprender que actualizar así la variable que contiene la lista de la entidad no actualiza el dibujo. Esta variable contiene una copia de la definición de la entidad en la Base de Datos, pero no la definición propiamente dicha.

Para actualizar pues, y como paso último, la Base de Datos de AutoCAD y que los objetos se vean realmente modificados, debemos recurrir a una función que se encarga de ello:

(ENTMOD lista_entidad)

ENTMOD pues actualiza la lista de una entidad en la Base de Datos de AutoCAD 14. Su funcionamiento es tan sencillo como pasarle como argumento único la lista de la entidad que hay que modificar, y ella se encarga del resto.

Así pues, en el ejemplo del círculo que venimos arrastrando sólo quedaría escribir:

(ENTMOD ListaEntidad)

para que ese círculo cambiara su capa y su color.

El funcionamiento principal de modificación de las entidades de la Base de Datos se basa en los pasos que hemos venido siguiendo, esto es, la designación de la entidad o entidades que queremos tratar, la obtención de sus nombres y con ello sus listas, la modificación de las mismas y, por último, la actualización de la Base de Datos mediante ENTMOD. El resto de las funciones que veremos aquí se refieren a otros tipos de extraer nombres de entidades o sus listas, o de trabajar con los conjuntos.

La función ENTMOD presenta algunas restricciones en cuanto al tipo de dato que puede actualizar para una entidad. No puede modificar ni el nombre de entidad (código –1) ni el tipo (código 0), evidentemente. Si se modifica el nombre de estilo de texto, tipo de línea o nombre de bloque, estos deben estar previamente definidos o cargados en el. Si se modifica el nombre de capa en cambio, se crea una nueva capa si no existiera previamente —como hemos podido comprobar—. Si se modifica la lista de una entidad principal, se actualiza su imagen en pantalla. Si se modifica la lista de una subentidad (vértices de polilínea o atributos) la imagen en pantalla no cambia hasta que se utiliza ENTUPD (la veremos a continuación).

No se pueden modificar con ENTMOD entidades de ventanas gráficas (tipo VIEWPORT). Tampoco las entidades incluidas en la definición de un bloque.

(ENTUPD nombre_entidad)

Como hemos comentado pues, mediante ENTMOD se actualiza en la Base de Datos una entidad a la que se le han cambiado sus características. Si se trata de una entidad principal, ENTMOD regenera directamente la entidad y ésta se visualiza en pantalla ya actualizada. Pero si se modifica un componente de una entidad compuesta —como vértices de una polilínea o un atributo de un bloque—, aunque se actualice la Base de Datos el aspecto de la entidad no cambiará en pantalla hasta que se produzca una regeneración general de todo el dibujo.

Mediante ENTUPD, indicando simplemente el nombre de la entidad (por ejemplo, el vértice de una polilínea modificada), se busca cuál es la cabecera de esa entidad y se regenera, con lo que se actualiza su aspecto en pantalla. En general, ENTUPD regenera la entidad cuyo nombre se especifique, incluidas todas las subentidades.

Pues llegados a este punto, ya podemos ver algún ejemplo un poco más trabajado. El siguiente es un ejemplo típico de toda la vida. Un programa AutoLISP que permite cambiar la capa actual de trabajo simplemente designando un objeto que se encuentre en la capa a la que queremos cambiar. Además, y para introducir una pequeña variación, las demás capas serán desactivadas. El listado sencillo es el siguiente:

(DEFUN C:DesCapa ()
--(SETQ ListaEnt (ENTGET (SSNAME (SSGET) 0)))
--(SETQ ListaCapa (ASSOC 8 ListaEnt))
--(SETQ Capa (CDR ListaCapa))
--(SETVAR "CLAYER" Capa)
--(COMMAND "_.layer" "_off" "*" "_n" "")
)

Como podemos ver, aquí se crea un nuevo comando de AutoCAD llamado DESCAPA para realizar lo propuesto. Lo primero es solicitar al usuario un objeto (SSGET), si se seleccionan varios únicamente se elige el primero después (índice 0 de SSNAME), y se guarda su lista de especificación (ENTGET) en la variable ListaEnt. A continuación se extrae la lista de la capa (código 8 con ASSOC) de la lista completa ListaEnt y se guarda en ListaCapa, y luego se almacena en la variable Capa la capa en cuestión, que es el segundo elemento (CDR) del par punteado que guarda la capa (ListaCapa). Por último se establece dicha capa como actual con la variable CLAYER y se desactivan todas las demás (exceptuando la actual, como decimos) con el comando CAPA (LAYER en inglés) de AutoCAD 14.

NOTA: Al recibir el comando CAPA desde un archivo .LSP, AutoCAD lo activa en su modo de línea de comandos automáticamente, por lo que no es necesario indicar –CAPA (o incluso _.-LAYER). Esa notación es más que nada para macros, aunque puede ser interesante incluirla aquí para no perder la costumbre.


En el ejemplo que acabamos de ver, es factible seleccionar más de un objeto y, aunque sólo se elija el primero después, no parece lógico utilizar este método en este caso. A continuación conoceremos una función que nos abrirá los ojos un poco más en este sentido.

 

ONCE.20.2.5. Nombre de entidad por un punto

Existen diversos comandos de AutoCAD que procesan entidades teniendo en cuenta el punto de designación con el que se ha actuado sobre las mismas, es el caso por ejemplo del comando PARTE. Veamos la sintaxis de la siguiente función:

(ENTSEL [mensaje_solicitud])

La función ENTSEL espera a que el usuario designe una única entidad mediante un punto y devuelve una lista cuyo primer elemento es el nombre de la entidad (código –1) designada, y su segundo elemento las coordenadas X, Y y Z del punto de designación. De esta forma se tienen asociados ambos valores para procesarlos posteriormente.

Esta lista devuelta por ENSEL se puede indicar en las llamadas a los comandos de AutoCAD que requieren señalar una entidad por un punto. Así por ejemplo, si en línea de comandos hacemos:

(SET PuntoParte (ENTSEL))

y marcamos un punto de una línea, por ejemplo. Y después ejecutamos el comando PARTE, y como primer punto para seleccionar objeto le decimos:

!PuntoParte

dicho punto será aceptado por el comando de manera normal.

Se puede indicar una cadena de texto como argumento opcional de ENTSEL; esta cadena es un mensaje de solicitud. Por ejemplo:


(SETQ NomEnt (ENSET "Designar entidad por un punto: "))

Si no se especifica un mensaje, ENTSEL presenta el mismo que SSGET o DESIGNA, pero en singular, es decir, si para esos dos comentados era Designar objetos:, para ENTSEL es Designar objeto: (Select object: en inglés).

Una vez visto ENTSEL nos parecerá más lógico utilizarlo para el ejemplo anterior DESCAPA. El ejercicio tratado con ENTSEL, y un poco más trabajado, se presenta en el siguiente archivo.

El ejemplo es tan sencillo que se ha definido todo él en una sola orden de usuario nueva.

Tras designar el objeto por un punto (ENTSEL) y guardar su nombre y punto de designación (que es lo que devuelve ENTSEL) en Ent, se guarda en EntName únicamente su nombre, extrayendo el primer elemento de la lista con CAR.

A continuación se guarda en Capa el segundo elemento (CDR) del par punteado que comience con 8 (ASSOC) dentro de la lista de la entidad (ENTGET) cuyo nombre es EntName.

Por último se define la capa como actual, esta vez con el propio comando CAPA y se acaba el programa. El resto se corresponde con el procedimiento de rigor de control de errores y control de variables de AutoCAD.

 

ONCE.20.2.6. Añadir, eliminar y localizar entidades

Veremos ahora tres funciones que nos permitirán añadir, eliminar y localizar una entidad dentro de un conjunto de selección. Pero antes, expliquemos un poco otra que nos permite averiguar el número de entidades de un conjunto. Su sintaxis es:

(SSLENGTH conjunto)

Como decimos, SSLENGTH determina el número de entidades que existen en el conjunto de selección indicado. El número es siempre entero positivo, salvo si es mayor de 32.767, en cuyo caso es un número real. Veamos un ejemplo simple:

(SETQ Conjunto (SSGET "_l")) (SSLENGTH Conjunto)

SSLENGTH devolverá siempre 1 en este caso, ya que SSGET almacena en Conjunto el último ("_l") objeto dibujado y visible. Sencillo.

Por otro lado, para añadir una entidad a un conjunto de selección ya existente se utiliza la función SSADD. Su sintaxis es la siguiente:

(SSADD [nombre_entidad [conjunto]])

Si se emplea sin ningún argumento construye un conjunto de selección vacío, si elementos. Si se indica sólo un nombre de entidad, construye un conjunto de selección que contiene sólo esa entidad. Si se especifica un nombre de entidad y también un conjunto de selección existente, añade la entidad al conjunto, con lo que este pasa a tener un elemento más.

La función SSADD siempre devuelve un valor de conjunto. Si se indica sin argumentos o sólo con el nombre de una entidad, dado que crea un conjunto nuevo, devuelve su valor. Si se especifica un conjunto ya existente, devuelve ese mismo valor especificado puesto que el efecto es añadirle una entidad, pero el identificador del conjunto sigue siendo el mismo.

El siguiente ejemplo muestra el funcionamiento de SSADD:

(DEFUN C:BorraEnt ()
--(SETQ Entidades (SSGET))
--(SETQ NuevaEntidad (CAR (ENTSEL "Designar objeto que se añadirá: ")))
--(SSADD NuevaEntidad Entidades)
--(COMMAND "_.erase" Entidades "")
)

Este programa permite designar un conjunto de objetos en pantalla con SSGET para luego añadir uno al conjunto, seleccionándolo mediante ENTSEL. SSADD añade el nuevo objeto al conjunto de selección Entidades ya existente, lo cual se puede comprobar cuando en la última línea se borran los objetos del conjunto.

(SSDEL nombre_entidad conjunto)

SSDEL, por su lado, elimina la entidad, cuyo nombre se especifique, del conjunto de selección indicado. Digamos que es el proceso contrario a SSADD.

El nombre del conjunto sigue siendo el mismo y por eso SSDEL devuelve ese nombre. Si la entidad no existe en el conjunto, SSDEL devuelve nil.

El siguiente ejemplo de SSDEL es el contrario del anterior:

(DEFUN C:BorraEnt2 ()
--(SETQ Entidades (SSGET))
--(SETQ ViejaEntidad (CAR (ENTSEL "Designar objeto que se eliminará: ")))
--(SSDEL ViejaEntidad Entidades)
--(COMMAND "_.erase" Entidades "")
)

Este programa permite designar un conjunto de objetos en pantalla con SSGET para luego eliminar uno del conjunto, seleccionándolo mediante ENTSEL. SSDEL elimina el nuevo objeto del conjunto de selección Entidades ya existente, lo cual se puede comprobar cuando en la última línea se borran los objetos del conjunto.

(SSMEMB nombre_entidad conjunto)

Esta última función de esta sección examina el conjunto de selección especificado para ver si la entidad cuyo nombre se indica está en él. Si la encuentra devuelve su nombre, si no devuelve nil.

 

 

ONCE.20.2.7. Aplicar y determinar pinzamientos

(SSSETFIRST conjunto_pinzamientos conjunto_seleccionados)

Esta función aplica pinzamientos a los conjuntos especificados. Los pinzamientos se aplican al primer conjunto, pero sin que queden sus entidades seleccionadas. Si se indica un segundo conjunto, además de aplicar pinzamientos, sus entidades quedan seleccionadas. Si hay entidades comunes en ambos conjuntos, sólo se pinza y selecciona del segundo, ignorándose el primero. La función devuelve una lista con los dos conjuntos de selección.

(SSGETFIRST)

Esta función devuelve una lista con dos conjuntos de selección: el primero con todas las entidades del dibujo que tienen aplicados pinzamientos pero sin estar seleccionadas, y el segundo con todas las entidades que además de tener aplicados pinzamientos están seleccionadas.

 

ONCE.20.2.8. Obtener nombre con modo de selección

(SSNAMEX conjunto [índice])

Esta función, al igual que SSNAME, devuelve el nombre de la entidad del conjunto especificado que se encuentre en el lugar determinado por índice. La diferencia con la otra función de nombre casi igual, es que SSNAMEX, junto con dicho nombre, devuelve también los datos que describen el tipo de selección realizada sobre dicha entidad por el usuario.

Los datos son devueltos en forma de una lista con sublistas, una para cada entidad, de la forma:

(id_selección nombre_entidad (datos))

Cada una de estas sublistas tiene tres elementos, como vemos. Dichos elementos se comentan detalladamente a continuación.

— id_selección es un número identificador del método de selección empleado con la entidad. Los números posibles se indican en la siguiente tabla:

Identificador ----- Descripción

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

0 ----------------- Selección no específica (Último, Previo, Todo...)

1 ----------------- Designación mediante cursor

2 ----------------- Ventana o Polígono-Ventana

3 ----------------- Captura o Polígono-Captura

4 ----------------- Borde

— nombre_entidad es el número hexacimal que es nombre de la entidad; el del código –1.

— datos es el conjunto de datos de información sobre el tipo de selección para la entidad. Si la selección ha sido no específica (identificador 0) no hay datos añadidos. Si ha sido señalado directamente con el cursor (identificador 1), se ofrece una lista con el punto de designación. Dependiendo del punto de vista 3D, el punto de designación se puede representar como una lista infinita, un rayo (semi-infinita) o un segmento de línea (finita). El punto en cuestión se ofrece en una lista con sus tres coordenadas, precedida esta lista por un código que puede ser uno de los siguientes:

Código ------------------ Descripción

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

0 ------------------------ Línea infinita

1 ------------------------ Rayo semi-infinito

2 ------------------------ Segmento de línea finito

Además, a las tres coordenadas sigue un vector opcional que describe la dirección de la línea infinita o el desplazamiento al otro extremo del segmento de línea. Si se omite en el listado, significa que el punto de vista es en planta. Por ejemplo, la siguiente lista es devuelta para un objeto designado en el punto de X = 50 e Y = 50 en una vista en planta del SCU:

(1 <Nombre de objeto: 26a0b07> (0 (50.0 50.0)))

Si la selección es del tipo Ventana o Captura, sus datos se ofrecen en una lista que empieza por un identificador de polígono con número negativo (-1, -2, -3, etc.) y después sublistas con todos los vértices del rectángulo o polígono, indicándose en cada una el tipo de punto (0, 1 ó 2) y las tres coordenadas. Por ejemplo, la siguiente lista es devuelta por una designación de Captura en una vista en planta:

((3 <Nombre de objeto: 26a0c12> -1 ) ((-1 (0 (20.0 10.0 0.0)))
(0 (50.0 10.0 0.0))
(0 (50.0 40.0 0.0))
(0 (20.0 40.0 0.0))
)
)

Si la selección es del tipo Borde, los datos son una lista de puntos de intersección entre la línea de Borde y la entidad. Por ejemplo, la siguiente lista es devuelta por una designación de Borde, que ha intersectado con la entidad en el punto 32,56.

(4 <Nombre de objeto: 26a5c09> (0 (32.0 56.0 0.0)))

 

ONCE.20.2.9. Otras formas de obtener nombres

Como hemos comprobado para acceder a una entidad en la Base de Datos necesitamos su nombre. Funciones que lo extraigan hemos visto hasta ahora SSNAME, SSNAMEX y ENTSEL, pero existen también otras que cumplen esa misión dependiendo de la situación en la que nos encontremos. Veámoslas.

(ENTNEXT [nombre_entidad])

Esta función devuelve el nombre de la primera entidad de la Base de Datos que sigue a la entidad cuyo nombre se indica en nombre_entidad. Como vemos, este argumento o parámetro de la sintaxis de ENTNEXT es opcional, y es que si no lo especificamos, la función devuelve el nombre de la primera entidad no eliminada de la Base de Datos.

Un ejemplo típico de uso de ENTNEXT es la de rastrear de modo repetitivo la Base de Datos del dibujo para obtener todos los nombres de todas las entidades de dibujo (de un dibujo no muy extenso, claro está), o los de las tres primeras, por ejemplo:

(SETQ Entidad1 (ENTNEXT))
(SETQ Entidad2 (ENTNEXT Entidad1))
(SETQ Entidad3 (ENTNEXT Entidad2))

ENTNEXT no sólo accede a las entidades principales, sino también a las contenidas en ellas. Así pues, otro ejemplo más lógico y utilizado se refiere a la extracción de todos los vértices de una polilínea no optimizada, o los atributos de un bloque. Se puede poner como condición que recorra todas las entidades hasta que encuentre "SEQUEND".

Si lo que queremos es saber a qué polilínea de antigua definición pertenece determinado vértice, habrá que ir explorando todas las polilíneas del dibujo hasta dar con alguna característica de dicho vértice. En dicho momento, y tras la entidad "SEQEND", se extrae el valor del código –2 que da el nombre de la entidad principal.

(ENTLAST)

Esta función devuelve el nombre de la última entidad principal no eliminada de la Base de Datos. Sólo entidades principales.

Habitualmente se utiliza para capturar el nombre de una entidad recién dibujada mediante COMMAND desde un programa AutoLISP. Presenta la gran ventaja de que obtiene el nombre de la entidad aunque no sea visible en pantalla o se encuentre en una capa inutilizada.

En el siguiente ejemplo, la variable EntidadLínea almacena el nombre de la entidad tipo línea recién dibujada, sin necesidad de tener que designarla. Con este nombre ya es posible acceder a la Base de Datos y realizar las operaciones convenientes:

(COMMAND "_.line" "0,0" "100,100" "")
(SETQ EntidadLínea (ENTLAST))
(NENTSEL [mensaje_solicitud])

Esta función permite acceder en la Base de Datos a una entidad que se encuentre formando parte de una entidad compuesta (polilínea no optimizada o bloque). La cadena de texto opcional es el mensaje para la solicitud de designación de entidad.

Cuando la entidad que se designa no forma parte de otra compuesta, NENTSEL devuelve la misma información que ENTSEL, es decir, una lista cuyo primer elemento es el nombre de la entidad y su segundo elemento el punto de designación.

Cuando con NENTSEL se designa un componente de una polilínea no optimizada, devuelve una lista cuyo primer elemento es el nombre de la subentidad, es decir el vértice (tipo de entidad "VERTEX") inicial del segmento de polilínea designado. El segundo elemento de la lista sigue siendo el punto de designación. Por ejemplo:

(NENTSEL "Designar segmento de polilínea: ")

podría devolver:

(<Nombre de objeto: 26b004e> (5.65 6.32 0.0))

Cuando con NENTSEL se designa un componente de un bloque devuelve una lista con cuatro elementos:

— El primer elemento es el nombre de la entidad componente del bloque, extraída de la
tabla de símbolos con la definición de ese bloque.

— El segundo elemento es una lista con las coordenadas del punto de designación.

— El tercer elemento es una lista que contiene a su vez cuatro listas: es la matriz de transformación del Sistema de Coordenadas Modelo (SCM) al Universal (SCU). El Sistema de Coordenadas Modelo (SCM) es aquél al que están referidas todas las coordenadas en la definición del bloque. Su origen es el punto de inserción del bloque. La matriz de transformación permite trasladar las coordenadas de la definición del bloque al Sistema de Coordenadas Universal (SCU), para a partir de ahí referirlas al Sistema de Coordenadas más conveniente para el usuario.

— El cuarto elemento es una lista con el nombre de entidad que contiene a la designada. Si existen varios bloques anidados, la lista contiene todos los nombres desde el bloque más interior hasta el más exterior de los que engloban a la entidad designada.

Por ejemplo, la designación de una entidad que forma parte de un bloque, que a su vez se encuentra incluido en otro bloque podría hacer que NENTSEL devolviera:

(<Nombre de objeto: 26c009d>
(6.65 5.67 0.0)
( (1.0 0.0 0.0)
(0.0 1.0 0.0)
(0.0 0.0 1.0)
(5.021 4.021 0.0)
)
(<Nombre de objeto: 26c010e> <Nombre de objeto: 26c01ba>)
)

La excepción a lo dicho son los atributos contenidos en un bloque. Si se designa un atributo, NENTSEL devuelve una lista con sólo dos elementos: el nombre de la entidad de atributo y el punto de designación.

(NENTSELP [mensaje_solicitud][punto])

De manera similar a la función anterior, NENTSELP permite acceder a todos los datos de definición de entidades contenidas en un bloque. Se puede especificar un mensaje de solicitud y un punto de designación.

NENTSELP obtiene una matriz de transformación de 4 Ž 4 elementos definida así:

M00 -------- M01 -------- M02 -------- M03

M10 -------- M11 -------- M12 -------- M13

M20 -------- M21 -------- M22 -------- M23

M30 -------- M31 -------- M32 -------- M33

Las tres primeras columnas de la matriz expresan la escala y rotación, y a cuarta columna es un vector de traslación. La última fila de la matriz no se toma en cuenta en las funciones que operan con este tipo de matrices. Esta matriz sirve para aplicar transformaciones a puntos.

(HANDENT identificador)

Devuelve el nombre de la entidad asociada al rótulo o identificador indicado. Hasta ahora se ha visto que los nombres de entidades eran únicos y las identificaban inequívocamente. Pero al terminar la sesión y salir de AutoCAD, esos nombres se pierden. En cambio, los identificadores se asocian a cada entidad y no cambian en las diferentes sesiones de dibujo. Estos identificadores se obtienen en la Base de Datos mediante el código 5.

Para comprobarlo podemos ejecutar el comando DDMODIFY con cualquier objeto. En el cuadro de diálogo que despliega este comando, arriba a la derecha, aparece el identificador en cuestión de cada objeto. Si deseamos, podemos extraer luego la lista de dicho objeto —con un simple (ENTGET (CAR (ENTSEL)))— para ver que asociado al código 5 se encuentra dicho identificador.

 

ONCE.20.2.10. Borrar/recuperar entidades

Veremos ahora una función muy sencilla que elimina o recupera una entidad. Esta función es:

(ENTDEL nombre_entidad)

ENTDEL elimina de la Base de Datos la entidad, cuyo nombre se indica, si existe en ella en el dibujo actual; ENTDEL recupera la entidad cuyo nombre se indica si había sido previamente borrada de la Base de Datos.

Esto quiere decir que las entidades borradas con ENTDEL pueden ser posteriormente recuperadas con el mismo ENTDEL, antes de salir de la actual sesión de dibujo evidentemente. Al salir del dibujo actual, las entidades borradas con ENTDEL se pierden definitivamente, sin haber posibilidad de recuperación.

ENTDEL solo accede a entidades principales; no es posible eliminar vértices de polilíneas sin optimizar ni atributos de bloque.

Ejemplo:

(DEFUN C:Eli ()
--(SETQ Nombre (CAR (ENTSEL "Designar un objeto para ser borrado: ")))
--(ENTDEL Nombre)
--(INITGET 1 "Sí No")
--(SETQ Recup (GETKWORD "¿Recuperarlo ahora (S/N)? "))
--(IF (= Recup "Sí")
--(ENTDEL Nombre)
)

Este ejemplo permite eliminar cualquier objeto del dibujo actual. Tras ello, nos ofrece la posibilidad de recuperarlo o no.

 

ONCE.20.2.11. Obtener rectángulo de texto

La función TEXTBOX devuelve las coordenadas de la caja de abarque o rectángulo contenedor de una entidad texto cuya lista se especifique. Su sintaxis es la que sigue:

(TEXTBOX lista_entidad_texto)

lista_entidad_texto puede ser la lista completa de la entidad de texto en cuestión o una lista parcial que contenga únicamente el valor de cadena del texto (par punteado con código 1 en la lista de entidad de texto). Por ejemplo:

(TEXTBOX (ENTGET (CAR (ENTSEL "Seleccione texto: "))))

Este ejemplo trabaja con la lista completa de un texto; el siguiente únicamente con la sublista de asociación de la cadena de texto:

(TEXTBOX ’((1 . "Hola")))

Si se indica sólo la lista parcial con el texto, se utilizan los valores actuales por defecto de los parámetros de definición del texto. Si se indica la lista completa, se utilizan los valores contenidos en ella.


Las coordenadas devueltas por
TEXTBOX son el vértice inferior izquierdo y el superior derecho del rectángulo de abarque, tomándose siempre como punto de inserción el 0,0,0. El primer punto únicamente es diferente de 0 cuando se trata de un texto de generación vertical o contiene letras con astas verticales por debajo de la línea de base.

 

ONCE.20.2.12. Construcción de una entidad

(ENTMAKE [lista_entidad])

Esta función permite añadir una entidad nueva al dibujo, construyendo directamente su lista completa en la Base de Datos. Si la lista introducida es correcta, devuelve esa lista. En caso contrario devuelve nil. Las listas se indican generalmente como literales, con QUOTE (’).

La lista debe contener todas las sublistas de asociaciones necesarias para definir completamente cada tipo de entidad. Si se omite alguna se produce un error. Es posible omitir algún dato optativo y entonces se asume la opción por defecto. Así por ejemplo si no se indica la capa, la entidad construida asume la capa actual.

Una forma cómoda de añadir una nueva entidad a la Base de Datos es partir de una entidad ya existente, obtener su lista con ENTGET modificar y añadir lo que sea preciso y crear la nueva entidad con ENTMAKE. Esto evita tener que construir la lista completa desde el programa en AutoLISP.

El tipo de entidad debe ir siempre en inglés, como sabemos (por ejemplo "CIRCLE", "LINE", "ARC", etc.) y debe ser el primer o segundo elemento de la lista. Lógicamente, todos los códigos de las sublistas de asociaciones deberán ser correctos.

Para construir una entidad compleja como definiciones de bloques, referencias de bloque con atributos, o polilíneas no optimizadas, es preciso construir todas las listas necesarias empleando varias veces ENTMAKE: la lista de cabecera o de la entidad principal, las listas con cada subentidad componente y la lista final del tipo "SEQEND" o "ENDBLK" para las definiciones de bloque.

Aunque para explorar todas las entidades contenidas en las definiciones de bloque con ENTNEXT no es necesario buscar un tipo de entidad final (como "SEQEND" para las polilíneas y atributos) pues al llegar a la última ENTNEXT devuelve nil, a la hora de construir las listas completas de la definición de un bloque, es preciso añadir como última lista un tipo de entidad llamado "ENDBLK".

Por ejemplo, para construir un cuadrado como polilínea no optimizada, evidentemente con cuatro vértices, en la capa actual y con color rojo (número 1) se podría hacer:

(ENTMAKE ’((0 . "POLYLINE")
-----------(62 . 1)
-----------(66 . 1)
-----------(70 . 1)
----------)
)

(ENTMAKE ’((0 . "VERTEX")
-----------(10 0.0 0.0 0.0)
----------)
)

(ENTMAKE ’((0 . "VERTEX")
-----------(10 0.0 10.0 0.0)
----------)
)

(ENTMAKE ’((0 . "VERTEX")
-----------(10 10.0 10.0 0.0)
----------)
)

(ENTMAKE ’((0 . "VERTEX")
-----------(10 10.0 0.0 0.0)
----------)
)

(ENTMAKE ’((0 . "SEQEND")
----------)
)

En la cabecera de la polilínea, el código 66 debe ir seguido obligatoriamente del valor 1 que indica que siguen vértices. Para que la polilínea sea cerrada, hay que incluir una lista con código 70 y valor 1.

NOTA: También se pueden construir directamente listas de objetos no gráficos mediante ENTMAKE.

(ENTMAKEX [lista_entidad])

Esta función es similar a ENTMAKE, pero la entidad se crea sin propietario. Se suministra una lista correcta de definición y se crea un objeto, gráfico o no gráfico. Pero al no tener propietario, este objeto no se escribe en los archivos .DWG o .DXF.

 

ONCE.20.2.13. Manejo de tablas de símbolos

Existe una serie de funciones específicas para gestionar los objetos no gráficos de AutoCAD. Es posible modificar algunos de los datos de estos objetos, aunque la mayoría de ellos no se pueden crear expresamente mediante ENTMAKE El grupo de objetos de diccionario se denomina así por contener el tipo de símbolo DICTIONARY y aparecer en los formatos de intercambio DXF en ese grupo. Pero en realidad contiene dos tipos de objetos no gráficos incorporados en la Versión 13 de AutoCAD: estilos de línea múltiple y grupos de selección.

Veremos a continuación dichas funciones.

(TBLNEXT nombre_tabla [retroceso])

Esta función devuelve una lista con el contenido de la tabla de símbolos cuyo nombre se indique. El nombre tiene que ser "LAYER", "LTYPE", "VIEW", "STYLE", "BLOCK", "UCS", "VPORT", "DIMSTYLE" o "APPID", que son los únicos admitidos. La función devuelve la primera tabla de símbolos existente de ese tipo, la primera vez que se utiliza. Después va devolviendo las siguientes conforme se utiliza repetidamente.

Por ejemplo, en un dibujo con tres capas: 0, PIEZA y OCULTAS, TBLNEXT se utilizaría tres veces para obtener las características de las tres capas. Al escribir:

(TBLNEXT "layer")

se devuelve:

((0 . "LAYER")
(2 . "0")
(6 . "CONTINUOUS")
(70 . 0)
(62 . 7)
)

La capa 0 tiene asociados un tipo de línea CONTINUOUS y un color 7 (blanco). Empleando de nuevo TBLNEXT se devuelve la siguiente definición de capa. Al escribir:

(TBLNEXT "layer")

se devuelve:

((0 . "LAYER")
(2 . "PIEZA")
(6 . "CONTINUOUS")
(70 . 0)
(62 . 1)
)

La capa PIEZA tiene asociados un tipo de línea CONTINUOUS y un color 1 (rojo). Por último, al escribir:

(TBLNEXT "layer")

se devuelve:

((0 . "LAYER")
(2 . "OCULTAS")
(6 . "TRAZOS")
(70 .3)
)

La capa OCULTAS tiene asociados un tipo de línea TRAZOS y un color 3 (verde).

Si se empleara TBLNEXT para la tabla LAYER por cuarta vez, se devolvería nil puesto que ya no existen más definiciones de capas.

Para examinar los componentes de la definición de un bloque, se accede a su tabla de símbolos mediante (TBLNEXT "block") o TBLSEARCH (que ahora veremos). El código -2 de la lista devuelta, contiene el nombre de la primera entidad de la definición del bloque. Se obtiene y se suministra a ENTNEXT, de manera que sucesivos ENTNEXT van devolviendo todas las listas de los componentes del bloque, hasta que al llegar a la última ENTNEXT devuelva nil.

Si el argumento retroceso no se omite y tiene un valor diferente de nil la función TBLNEXT empieza a buscar desde la primera tabla de símbolos.

(TBLSEARCH nombre_tabla símbolo [siguiente])

Esta función busca en el tipo de tabla que se indique, el nombre de símbolo especificado a continuación y devuelve la lista correspondiente. De esta forma se puede buscar por ejemplo directamente la lista correspondiente a la capa llamada PIEZA, haciendo:

(TBLSEARCH "layer" "pieza")

Normalmente se utiliza para determinar si existe una capa, un estilo de texto, etcétera. En el ejemplo siguiente se controla la existencia de carga de un tipo de línea:

(TBLSERACH "LTYPE" "Vías")

Si el tipo de línea existe se devuelve su lista de definición, si no existe se devuelve nil. Esto puede ser muy útil, ya que, como sabemos por ejemplo, el tipo de línea no se representa en la definición de una entidad si es PorCapa, por lo que no surtirá efecto alguno el que un usuario intente asignar, mediante un programa, dicho tipo de línea a una entidad si no está cargado. Nos preocuparemos de comprobar su existencia para emitir un mensaje de error si no estuviera cargado.


Si se pretendiera acceder a la definición de un estilo de texto definido en el dibujo y llamado
TS1, haciendo (TBLSEARCH "STYLE" "TS1"), podría ser devuelta la siguiente lista:

((0 . "STYLE")
(2 . "TS1")
(3 . "ROMANS")
(4 . "")
(70 .0)
(40 . 0.0)
(41 . 1.0)
(50 . 0.0)
(71 . 0)
)

El contenido de la tabla informa que el estilo está basado en la fuente o tipo de letra ROMANS, con altura 0, factor de proporción 1, ángulo de inclinación 0 y generación normal.

Si el argumento siguiente no se omite y tiene un valor diferente de nil el contador de TBLNEXT se ajusta de manera que la próxima llamada de TBLNEXT buscará la siguiente tabla a la obtenida por TBLSEARCH.

(TBLOBJNAME nombre_tabla símbolo)

Busca en la tabla indicada el nombre de símbolo especificado, devolviendo el nombre de entidad de dicha tabla (recordemos que la función anterior hacía lo mismo pero devolvía la lista completa). A pesar de no ser objetos gráficos, las tablas de símbolos pueden gestionarse mediante ENTGET y ENTMOD como si fueran entidades gráficas. Para ello se necesita suministrar su nombre de entidad (código -1) y éste es el que obtiene TBLOBJNAME. Este mecanismo permite modificar directamente en la Base de Datos el nombre de un estilo de texto, el color asociado a una capa, etc. Muy interesante; además puede utilizarse como la anterior para controlar la existencia de este tipo de objetos.

(SNVALID nombre_tabla [indicador])

Esta función comprueba la validez de los caracteres del nombre de tabla de símbolos. Si es un nombre válido devuelve T y en caso contrario nil. Los nombres deben contener sólo caracteres alfanuméricos y caracteres especiales como el de dólar $, guión de subrayado _ y guión normal -. También muy utilizado a la hora de comprobar si los nombres son válidos.

(NAMEDOBJDICT)

Esta función es básica para acceder a todos los objetos no gráficos del grupo de diccionarios. Devuelve el nombre de entidad del diccionario de objetos no gráficos del dibujo actual. Se utiliza en las funciones de exploración de esos objetos DICTNEXT y DICTSEARCH.

(DICTNEXT nombre_diccionario [retroceso])

Devuelve la lista con el contenido de objetos no gráficos del grupo de diccionarios. El nombre de diccionario suministrado debe haberse obtenido previamente mediante NAMEDOBJDICT. La función devuelve el primer objeto de diccionario cuando se utiliza por primera vez. Después devuelve sucesivamente los demás objetos no gráficos hasta el último, tras el cual devuelve nil. Su funcionamiento es similar a TBLNEXT.

Actualmente, los dos únicos objetos no gráficos accesibles en el grupo de diccionarios son los estilos de línea múltiple ACAD_MLINESTYLE y los grupos de selección ACAD_GROUP, por lo que DICTNEXT devolverá dos listas: la primera con los nombres de todos los estilos de línea múltiple creados y la segunda con los nombres de todos los grupos de selección creados.

Si el argumento retroceso no se omite y tiene un valor diferente de nil la función DICTNEXT empieza a buscar desde el primer objeto no gráfico de diccionario.

(DICTSEARCH nombre_diccionario símbolo [retroceso])

Esta función busca en el grupo de diccionarios el tipo de objeto no gráfico indicado en símbolo y devuelve la lista correspondiente. El tipo de objeto sólo puede ser "ACAD_MLINESTYLE", para los estilos de línea múltiple, y "ACAD_GROUP", para los grupos de selección. La lista devuelta es la misma que en DICTNEXT.

Si el argumento siguiente no se omite y tiene un valor diferente de nil el contador de DICTNEXT se ajusta de manera que la próxima llamada de DICTNEXT buscará la siguiente tabla a la obtenida por DICTSEARCH.

(DICTADD nombre_diccionario símbolo nuevo_objeto)

Añade el nuevo objeto no gráfico al diccionario especificado. Los objetos no gráficos son estilos de línea múltiple y grupos de selección. El argumento símbolo es el nombre clave del objeto que se va a añadir.

(DICTREMOVE nombre_diccionario símbolo)

Elimina el objeto no gráfico indicado en símbolo del diccionario especificado.

(DICTRENAME nombre_diccionario símbolo_antiguo símbolo_nuevo)

Cambia el nombre de la entrada representada por símbolo_antiguo, por el nuevo nombre indicado a continuación en el diccionario especificado en primer lugar.

 

ONCE.20.2.14. Funciones relativas a datos extendidos

En AutoCAD, al emplear aplicaciones ADS o ARX, en la Base de Datos del dibujo se añade un nuevo tipo de tabla de símbolos llamado "APPID". Cada tabla de este tipo contiene el nombre de una aplicación ADS o ARX utilizada para datos extendidos de entidades. De esta forma, cada tipo de aplicación puede añadir los datos necesarios para su funcionamiento a las entidades de AutoCAD. Como en los demás casos, estos datos son accesibles a través de listas de asociaciones. Para distinguirlos del resto comienzan con el código -3.

(REGAPP nombre_aplicación)

Esta función registra un nombre de aplicación externa en el actual dibujo de AutoCAD. Registrando las aplicaciones con un nombre, es posible después acceder a los datos extendidos de las entidades. Si el registro de la aplicación es correcto, REGAPP devuelve el nombre registrado. En caso contrario (por ejemplo al especificar un nombre de aplicación que ya existe), devuelve nil. El nombre puede contener hasta 31 caracteres alfanuméricos y algunos especiales como dólar $, subrayado _ y guión -. Una vez registrado, el nombre de la aplicación se añade en la Base de Datos como un tabla de símbolos del tipo "APPID".

Si en la función ENTGET se especifica una lista de nombres de aplicaciones registrados con REGAPP, la lista devuelta incluye también el código -3 que es el denominado centinela o indicador de que la entidad contiene datos extendidos, y todas las listas de datos que siguen a dicho código. Estos datos se encuentran asociados a códigos de 1000 a 1071. Los datos extendidos propios de AutoCAD 14 se obtienen indicando como nombre de aplicación el de "ACAD". Por ejemplo:

(ENTGET (ENTLAST) ’("acad"))

Sólo algunos tipos de entidades contienen en AutoCAD datos extendidos, como por ejemplo las ventanas gráficas, los bloques de sombreados, las cotas, directrices y tolerancias geométricas.

(XDROOM nombre_entidad)

XDROOM devuelve el espacio de memoria disponible para los datos extendidos de la entidad cuyo nombre se indica. El espacio máximo disponible para cada entidad es de 16383 octetos. El valor devuelto por XDROOM es entonces la diferencia entre este máximo y lo que ocupan las datos extendidos ya existentes para la entidad. Por ejemplo:

(XDROOM (ENTLAST))

podría devolver:

16264

(XDSIZE lista_datos_extendidos)

Devuelve la longitud, en octetos o bytes, que la lista indicada ocupa cuando es añadida como datos extendidos de una entidad. Es complementario del anterior XDROOM y se utiliza para controlar cuánto van ocupando en memoria los datos extendidos de una entidad.

La lista debe contener un nombre de aplicación previamente registrado con REGAPP. Si existen varios nombres de aplicaciones, se forma una lista que englobe a las demás (por ejemplo con LIST).

Hasta aquí todas las funciones relacionadas directamente con el acceso a la Base de Datos de AutoCAD 14. A continuación, estudiaremos cuatro ejemplos de programas completos que nos ayudarán a la comprensión práctica de este tema.

El primer ejemplo que veremos se corresponde con un programa que permite distribuir un texto indicado por el usuario a lo cargo de cualquier entidad de condición curva, sea arco, círculo, elipse, polilínea o spline, y/o de líneas. El listado del programa se encuentra en este archivo.

El programa tiene el siguiente funcionamiento. El comando nuevo de AutoCAD TXCURVA, llama primero a la función datos_txcurva y después a txcurva.

La función de datos solicita en primer lugar la altura del texto y la separación entre el texto y la curva en la cual se va a alinear. Un valor positivo deja al texto a un lado o "por encima" y un valor negativo por el otro lado o "por debajo", siempre según el sentido de creación de la curva. Para ambos datos, ofrece como valores por defecto los últimos utilizados (cosa que ya hemos estudiado con otros ejemplos).

El programa crea un bloque que le resulta necesario para insertarlo con el comando GRADUA (MEASURE). Este bloque contiene simplemente un punto y se le da el nombre de $txcurva. El carácter $ al principio es para distinguirlo de otros bloques que pueda contener el dibujo. Este bloque será limpiado al final se la rutina. Primero se comprueba mediante TBLSEARCH si ya existe.

Para el espaciado entre caracteres el programa tiene en cuenta el estilo actual, extraído de la variable de AutoCAD TEXSTYLE. El código 41 contiene la anchura del estilo. El producto de ese factor por la altura y una cantidad de 1.2 es el espaciado entre caracteres. Se trata de un cálculo estimativo. El valor adecuado dependerá del estilo de texto. Más adelante se tendrán en cuenta determinados caracteres como "i", "l", "j", etcétera para modificar ese espaciado.

Se solicita designar la entidad para alinear el texto. Se establece un control por si se falla en la designación. La función ENTSEL sólo permite designar una entidad. A continuación se extrae el tipo de entidad (código 0) y se almacena en tent. Si el tipo de entidad no es una de las válidas para graduar, se visualiza un mensaje de advertencia y se vuelve a solicitar.

Se llama al comando GRADUA, con el espaciado entre caracteres calculado más arriba, y se inserta el bloque $txcurva alineándolo con la curva. Con SSGET "_p" se almacena el conjunto de puntos de graduación, y se averigua su número en lconj. Se utiliza lontx para controlar el número máximo de caracteres que caben a lo largo de la curva. Se ofrece esa información al usuario y se solicita el texto que se alineará (cadtx). Se almacena su longitud en lontx y si es superior a la máxima, se vuelve a solicitar.

Por su lado, en la función txcurva se inicializa la variable ntx que controla el número de orden de cada carácter en la cadena de texto para alinear, y desig que almacena un conjunto de selección vacío con SSADD.

A continuación se establece un ciclo que se repetirá tantas veces como caracteres haya en la cadena de texto. Se extraen de la cadena los caracteres uno a uno. Se averigua en el conjunto de bloques de punto el punto de inserción (código 10) y el ángulo de inserción (código 50), mediante el mecanismo con SSNAME, ENTGET y ASSOC que ya conocemos.

El punto de inserción de cada carácter se calcula a partir del punto de inserción del bloque, llevando en perpendicular una distancia igual a la separación indicada por el usuario. Si el carácter es estrecho ("l", "i", "I", "j" o "1"), se desplaza previamente el punto de inserción hacia delante una sexta parte de la altura del texto. Si es "m", se desplaza hacia atrás. Con esto se persigue que esos caracteres no se solapen o se queden más pegados al precedente que al siguiente. Se traslada el ángulo de rotación de radianes a grados, puesto que así hay que indicarlo en el comando TEXTO. Se van insertando los caracteres uno a uno. Se añade cada uno al conjunto de selección desig para poder almacenar mediante el comando DESIGNA dicho conjunto. Esto permitirá referirse posteriormente a todo el texto a la vez con el modo Previo.

Por último se borran todas las inserciones del bloque y se redibuja. El resto de mecanismos de control de errores y demás ya está lo suficientemente explicado.

El segundo programa traza una línea de tubería en tres dimensiones. Tuberías y codos se generan mediante mallas. El trazado deberá haber sido previamente mediante líneas (sólo líneas), de forma que los extremos de los tramos se toquen. El listado en el siguiente archivo.

La función inic_tubos solicita la designación de líneas que son los ejes del trazado de tubos, una a una y en orden. Establece un control con WHILE para garantizar que se ha designado alguna entidad. Examina el conjunto designado para rechazar las entidades que no sean líneas. Si no existen líneas o sólo hay una, visualiza mensajes de advertencia. Al final, el conjunto lin contiene únicamente las entidades de línea señaladas por el usuario.

La función datos_tubos va solicitando los datos necesarios. En primer lugar el diámetro exterior de los tubos, después el de los codos (ofreciendo como opción por defecto el mismo que para los tubos y evitando que sea menor que el de ellos). Las variables almacenan en cada caso el valor de los radios. A continuación se pide el radio interior de curvatura del codo. Por último la precisión del mallado para las superficies de cada tubo.

Las curvas de apoyo para el trazado se situarán en una capa cuyo nombre se forma con el de la capa actual y un prefijo $c-.

Se toman los tres primeros puntos de la conducción (primer punto de la primera línea y primer y último punto de la segunda línea) y se almacenan esos puntos en el Sistema de Coordenadas de Entidad que es como se encuentran en la Base de Datos. Se trasladan esos puntos al SCP actual. Se almacenan también los nombres de las entidades de línea a que pertenecen. Por último se inicializa el contador de tramos n, y se pone a cierto T la variable prim para controlar que se trata del primer tramo que se dibuja.

tramo_tubos se encarga de dibujar cada tramo con su tubo y su codo. Establece el SCP adecuado de acuerdo con el plano formado por las dos líneas que definen el tramo. Calcula el ángulo formado por esas líneas en el nuevo SCP y la distancia dis del vértice a la que termina el tubo y empieza el codo. Calcula la precisión de mallado tabcod del codo de acuerdo con el ángulo abarcado por el mismo.

Cambia a un nuevo SCP perpendicular al anterior para trazar los círculos que van a definir las mallas. Los centros de estos círculos serán los puntos en que empieza y termina el tubo pri y prf. Se trazan los círculos y se forman listas que contengan el nombre de cada uno con un punto de designación (del tipo de las devueltas por ENTSEL). Hay que tener la precaución de trasladar los puntos al SCP actual.

El codo se va a trazar como una superficie de revolución y esto obliga a dibujar el eje y almacenarlo también como una lista con nombre y punto de designación. Si se trata del primer tramo, o bien si el diámetro del codo es igual al de la tubería, entonces se evita dibujar las mallas de transición entre ambos diámetros, que visualizan el espesor del codo.

Una vez trazadas todas las curvas, se generan las mallas con SUPREGLA y SUPREV. Se cambian las curvas de apoyo a la capa capl. Una vez recorrido el primer tramo se cambia la variable de control prim a nil para el resto de tramos.

act_tubos se encarga de actualizar los valores de las variables para empezar el nuevo tramo en la repetitiva. Almacena la distancia dis de final del último tramo para utilizarla en disant como distancia de principio del nuevo tramo. Calcula los puntos necesarios para obtener el SCP del plano formado por las dos líneas del nuevo tramo y suma uno al contador n.

La subrutina tramof_tubos dibuja el tramo final, alterando el orden de los puntos utilizados para formar el SCP adecuado. Dibuja los últimos círculos y obtiene las mallas correspondientes. Para obtener los puntos necesarios, siempre se parte del SCE de la Base de Datos y de su traslado al SCP actual.

c:tubos es la función que compone el comando de AutoCAD. Llama a la función inic_tubos y establece una condición. Si el usuario ha designado más de una entidad de línea, entonces pueden trazarse los tubos. En caso contrario se visualiza un mensaje *No vale*.

Por lo demás, funciones de control de errores y demás.

Veamos un tercer ejemplo que maneja un cuadro de diálogo. El siguiente programa actúa como DDMODIFY a pequeña escala, es decir, permite modificar las propiedades de una entidad y/o visualizarlas, pero en este caso sólo de círculos. Concretamente se puede actuar sobre las coordenadas del centro del círculo, su radio, capa, tipo de línea y color. Veamos primeramente el diseño en DCL (en este archivo) y el aspecto del cuadro de diálogo en cuestión:

El cuadro es este:

El programa en AutoLISP está en este archivo.

Se define un nuevo comando MODICIR y una abreviatura MC a él. Tras la declaraciones de rigor, el programa llama a la función Datos, en la cual se nos pide designar un círculo. Se comprueba si realmente es un círculo extrayendo el par punteado de su nombre; si no lo es se vuelve a realizar la pregunta y, si sí es un círculo, se llama a la función Cuadro.

Cuadro carga el letrero de diálogo y rellena sus casillas accediendo a la lista de la entidad. En el caso del punto del centro, se distingue entre tomar las coordenadas de la lista de la entidad designada o del punto designado mediante el botón Designar punto <, dependiendo pues si se entra al cuadro por primera vez o tras haber designado un nuevo centro. Una vez hecho esto se establecen las correspondencias de los ACTION_TILE.

La función Designar permite designar un nuevo centro y vuelve al cuadro. Recuérdese la técnica ya comentada de asignar una variable a lo devuelto por START_DIALOG y de hacerla nil al entrar al cuadro para que no dé problemas. También hemos de tener presente la posibilidad de cargar o no cargar el cuadro, dependiendo de si ya lo estuviera porque se viene de Designar, o si no lo estuviera porque se acaba de ejecutar el comando.

Tras pulsar el botón Aceptar se nos manda a la subrutina Tiles, la cual lo primero que hace es llevarnos a ControlDCL. ControlDCL controla si alguna casilla del letrero está vacía. Si así fuera, se muestra un mensaje de error, se resalta la casilla y da valor T a la variable ErrorDCL, que hace que el cuadro no se cierre al establecer esa condición en el ACTION_TILE para accept.

Después de ControlDCL seguimos en Tiles. En esta subrutina se asignan los valores correspondientes a cada una de las variables implicadas, extrayéndolo de los propios tiles. En el caso del radio se comprueba que no sea cero o negativo; si así fuera se establece ErrorDCL a T para lo mismo que lo explicado anteriormente. En el caso del tipo de línea y del color, se comprueba que el tipo esté cargado y que el color no sea menor de 0 ni mayor de 256, respectivamente. Y se hace lo propio con ErrorDCL.

Tras acabar aquí, nos vamos a Aceptar, que se encarga de modificar la lista y sustituirla en la Base de Datos. En los casos del centro, el radio y la capa no hay problema alguno, simplemente hay que sustituir una lista por otra. Pero en el caso del tipo de línea y el color, el problema se presenta.

Si el tipo de línea es PorCapa, en la lista de definición de la Base de Datos el par punteado correspondiente no aparecerá, por lo que habrá que añadirlo (APPEND). Pero si es distinto de PorCapa, el par punteado sí aparece, así que habrá que sustituirlo (SUBST). En el caso del color ocurre exactamente lo mismo.

Por último, se introducen los cambios en la Base de Datos y se cierra el cuadro.

El resto corresponde a lo que ya conocemos: control de errores AutoLISP y otras características de relleno.

El último ejemplo dice relación a un programa que permite juntar dos curvas splines en una sola. La única condición es que deben tocarse. Se pueden juntar sucesivas splines dos a dos. Veamos el listado en este archivo:

El programa utiliza el comando EDITSPLINE con la primera spline y, mediante la opción Ajustar, subopción aÑadir, va añadiendo todos los puntos de ajuste de la segunda spline. Las tangencias en el punto de contacto de ambas splines se pierden. Según cuál de las dos se señale primero, la curva final resultante diferirá ligeramente. Esto se hace apreciable sobre todo en el primer tramo de la segunda spline que se junta.

La función inicial solicita señalar las splines que unir. Se establece mediante WHILE un primer control para obligar al usuario a que señale al menos una entidad. La función ENTSEL se utiliza para señalar una única entidad por un punto. Una vez señalada una entidad, es preciso comprobar que se trata de una spline. Esto se hace accediendo a la Base de Datos y extrayendo el tipo de entidad, asociado al código 0. Además, podría tratarse de una spline cerrada, en cuyo caso no sería posible juntarle a otra. Las splines de este tipo tienen un valor impar asociado al código 70. Por eso se extrae dicho valor, se divide entre 2 y se obtiene el resto mediante REM. Si es 1 significa que el valor es impar y por lo tanto una spline cerrada.

En resumen, si la entidad señalada por el usuario no es spline, o es una spline cerrada, entonces se vuelve a solicitar su designación. Cuando se obtiene una entidad correcta, su nombre de identificación (extraído con CAR) se almacena en splb. A continuación se solicita señalar la spline para juntar. Se establecen los mismos controles, pero se añade otra posibilidad. Si la entidad señalada es un spline no cerrada, se comprueba si se trata de la misma curva señalada en primer lugar. Esto se hace comparando los dos nombres de identificación splb y splj. Sólo cuando no sean iguales, se aceptará la segunda spline.

La función para juntar extrae las listas en la Base de Datos de ambas splines mediante ENTGET y las almacena en lisb y lisj. Los vértices de ajuste se encuentran en sucesivas sublistas con código 11. Mediante MEMBER se extrae el resto de lista a partir de la primera aparición de un vértice. Así, la lista lisv contiene las coordenadas de todos los vértices en sublistas asociadas al código 11. El número de vértices de ajuste se obtiene de la sublista asociada al código 74. Los vértices extremos, que son el primero y último de la spline se obtienen mediante NTH. Se almacenan en pb1 y pb2.

La misma operación se realiza con la lista de la segunda spline que se juntará a la primera. Sus datos se almacenan en las mismas variables, pues los de la primera spline ya no interesan, una vez obtenidos sus vértices extremos. Así, lisv contendrá la lista con sublistas de vértices, numv el número de vértices y pj1 y pj2 los vértices extremos de la segunda spline.

Se utiliza COND para examinar las cuatro posibilidad y ver por qué extremos se tocan las splines. Si no se tocan, se visualiza un mensaje y se aborta el programa mediante QUIT. En función de qué extremos se toquen, se invierte la lista de vértices o se modifica pb2 para que almacene siempre el punto de contacto. Se utiliza EQUAL para comparar la igualdad de puntos, estableciendo una cifra de aproximación.

El mecanismo de unión de las splines va a ser el siguiente: mediante el comando EDITSPLINE se designa la primera curva. Se utiliza la opción Ajustar y dentro de ella la subopción aÑadir. Se señala el vértice de contacto como punto a partir del cual añadir los demás, y se van proporcionando en orden todos los vértices de la segunda spline que quedan así incorporados a la primera. Pero como el número de vértices es variable, la expresión debe formarse concatenando una cadena de texto que después será convertida en expresión de AutoLISP y evaluada mediante el mecanismo (EVAL (READ expr)) ya estudiado, que comentamos en su momento de pasada y aquí lo vemos en acción.

Los vértices se suministran extrayéndolos de la lista lisv con NTH y CDR. Una vez añadidos todos los vértices de la segunda spline a la primera, se borra aquélla mediante ENTDEL. Se redibuja la spline global resultante mediante REDRAW. Si las splines tienen muchos vértices, la operación de juntar puede llevar unos cuantos segundos de tiempo.

 

18ª fase intermedia de ejercicios

· Realizar un programa que facilite la modificación global de las propiedades de varios textos a la vez.

· Realizar un programa que permita juntar dos polilíneas 3D en una sola.

· Diseñar un programa que haga resaltar las inserciones de todos los bloques de un dibujo utilizando la generación de vectores virtuales (explicado esto en la sección ONCE.18.2.). Las inserciones serán resaltadas poniéndolas en relieve mediante vídeo inverso y, al mismo tiempo, visualizando una flecha virtual que señale el punto de inserción de cada bloque.