FOREACH
- Evalúa cada expresión para todos los miembros de una
lista
-
(foreach
nombre lista expresión ...
)
- Recorre la lista, asignando sucesivamente cada elemento de la lista a la
variable nombre y evaluando de esta manera cada
expresión para cada uno de los elementos de la lista
representados por nombre. Puede especificar tantas
expresiones como desee. La función FOREACH devuelve el
resultado de la última expresión evaluada.
VLAX-FOR
- Efectúa una iteración a través de una colección de
objetos evaluando cada expresión
-
(vlax-for
símbolo colección [expresión1 [expresión2 ...]]
)
- El argumento símbolo será asignado a cada Objeto-VLA de la
colección. El argumento colección representa un objeto ActiveX
del tipo colección. [expresión1 [expresión2 ...]]
son las expresiones a evaluar. La función devuelve el valor de la
última expresión evaluada para el último objeto de la
colección.
Ejemplos de iteraciones con FOREACH:
Esta pequeña subrutina, parte de un programa mayor, imprime en
pantalla en formato de columna la lista que se le pase como argumento. En el
ejemplo se usa para imprimir de manera ordenada la lista de definición
deuna entidad polilínea (AutoCAD 2000).
;;;Listado de entidades
;;;Salida por pantalla
(defun disp_l (lis_e /)
(foreach sublista lis_e
(print sublista)
) ;_ fin de foreach
(princ) ;evita la repetición de la última línea
) ;_ fin de defun
Command: (entget(car(entsel)))
Select object: ((-1 . <Entity name: 1487558>) (0 . "LWPOLYLINE") (330 . <Entity
name: 14874f8>) (5 . "2B") (100 . "AcDbEntity") (67 . 0) (410 . "Model") (8 .
"0") (100 . "AcDbPolyline") (90 . 4) (70 . 0) (43 . 0.0) (38 . 0.0) (39 . 0.0)
(10 99.3432 134.975) (40 . 0.0) (41 . 0.0) (42 . 0.0) (10 130.202 185.828) (40
. 0.0) (41 . 0.0) (42 . 0.0) (10 202.747 163.648) (40 . 0.0) (41 . 0.0) (42 .
0.0) (10 269.336 215.041) (40 . 0.0) (41 . 0.0) (42 . 0.0) (210 0.0 0.0 1.0))
La lista impresa en pantalla resulta difícil de leer, al no estar ordenada en columna
Command: (disp_l (entget(car(entsel))))
(-1 . <Entity name: 1487558>)
(0 . "LWPOLYLINE")
(330 . <Entity name: 14874f8>)
(5 . "2B")
(100 . "AcDbEntity")
(67 . 0)
(410 . "Model")
(8 . "0")
(100 . "AcDbPolyline")
(90 . 4)
(70 . 0)
(43 . 0.0)
(38 . 0.0)
(39 . 0.0)
(10 99.3432 134.975)
(40 . 0.0)
(41 . 0.0)
(42 . 0.0)
(10 130.202 185.828)
(40 . 0.0)
(41 . 0.0)
(42 . 0.0)
(10 202.747 163.648)
(40 . 0.0)
(41 . 0.0)
(42 . 0.0)
(10 269.336 215.041)
(40 . 0.0)
(41 . 0.0)
(42 . 0.0)
(210 0.0 0.0 1.0)
Ejemplos de iteraciones con VLAX-FOR:
LISTADO DE CAPAS
Considerado desde el punto de vista de la jerarquía de objetos
ActiveX a la que podemos acceder con Visual LISP,
AutoCAD y sus dibujos consisten en muchos objetos diferentes
tales como tipos de líneas, capas, bloques, etc. Estos objetos se
agrupan en colecciones. Las colecciones de Bloques (Block), Grupos (Group),
Conjuntos de Selección (SelectionSet), EspacioModelo (ModelSpace) y
EspacioPapel (PaperSpace) pueden contener una variedad de objetos
gráficos diferentes, tales como líneas, arcos, texto, etc. Todas
las demás colecciones contienen objetos de un sólo tipo.
Las colecciones AutoCAD son de base cero, es decir que se enumeran a partir de
cero en sentido ascendente. Algunas colecciones poseen objetos de manera
automática. Por ejemplo, la colección Layers (capas) simpre
contiene un objeto capa de nombre "0", mientras que otras se
encuentran vacías inicialmente.
Sutphin, J. AutoCAD 2000 VBA Programmers Reference, pág 47.
La rutina que exponemos a continuación extrae los nombres de las
capas de un dibujo aplicando la función VLAX-FOR a la
colección "Layers". Para obtener la colección
"Layers" tenemos que recorrer la jerarquía de
objetos, a partir del único objeto accesible públicamente que es
el objeto "Application" (Aplicación). La secuencia a
seguir es la siguiente:
- Obtener el objeto "Aplicación":
(vlax-get-acad-object)
- Obtener el objeto "Documento Activo" es decir, el dibujo en que
se trabaja:
(vla-get-ActiveDocument (vlax-get-acad-object))
En caso de que se vaya a hacer referencia a este objeto en múltiples
ocasiones, sería conveniente extraerlo una sóla vez y guardarlo
en una variable global:
(setq *EsteDibujo* (vla-get-ActiveDocument (vlax-get-acad-object)))
Esta línea la situamos fuera del defun. Se ejecutaría al
cargar el programa.
- Obtener la colección "Layers" (Capas):
(vlax-get *EsteDibujo* "Layers" )
Una vez obtenida la colección de capas se aplica mediante VLAX-FOR a
cada objeto-VLA de dicha colección la función
(setq ListaCapas (cons (vlax-get objeto-VLA "Name")
*ListaCapas*))
Aquí primero extraemos el nombre de la capa. El nombre de cada objeto
"Layer" se encuentra en la propiedad "Name" y se puede
extraer mediante (vlax-get objeto-VLA "Name")
. Una vez obtenido el
nombre de la capa, la incluimos mediante CONS en una variable local ListaCapas.
Esta lista contendrá al terminar el ciclo de VLAX-FOR
los nombres de
todas las capas del dibujo activo. Ya para terminar, ordenamos la lista de
capas mediante la función ACAD_STRLSORT
. Esta lista serviría, por
ejemplo para llenar una casilla de lista en un cuadro de diálogo creado
mediante el lenguaje DCL.
;;;Función ListaCapas
;;;Devuelve una lista con los nombres de capas ordenados alfabéticamente
;;;Obsérvese la posibilidad aquí demostrada de tener una función y una variable
;;;con idéntico nombre en un mismo entorno. Para ello será necesario que dicha
;;;variable, en este caso ListaCapas sea una variable local de la función.
(setq *EsteDibujo* (vla-get-ActiveDocument (vlax-get-acad-object)))
;se ejecuta previamente
(defun ListaCapas (/ ListaCapas)
(vlax-for objeto-VLA (vlax-get *EsteDibujo* "Layers")
(setq ListaCapas (cons (vlax-get objeto-VLA "Name") ListaCapas))
;el mismo nombre se utiliza para la variable local que guarda
;temporalmente el listado de capas.
) ;_ fin de vlax-for
(acad_strlsort ListaCapas)
) ;_ fin de defun
Ejemplo de su utilización:
Command: (LOAD "C:/Mis documentos/Lisp/Fuentes/ListaCapas.lsp") LISTACAPAS
Command: !*EsteDibujo*
<#VLA-OBJECT IAcadDocument 00eb6aa4>
Command: (listaCapas)
("0" "DEFPOINTS" "DOTACIONES" "IT" "RBA" "RE-2" "RI" "RI-1" "RIA" "SG-EL"
"SG-M" "SGP")
Más adelante se estudiará en más detalle el acceso a
los objetos ActiveX desde Visual LISP.
Unos ejemplos para concluir...
Como ejemplo del empleo dentro de AutoCAD de estas últimas funciones
estudiadas, aquí van algunas pequeñas utilidades creadas por
Vladimir Nesterovsky. La primera
de ellas, SEL2LST crea una lista de nombres de entidad a partir de un
conjunto de selección. La segunda, LST2SEL, realiza el proceso inverso,
creando un conjunto de selección a partir de una lista de nombres de
entidad:
;;;SEL2LST
;;;Recibe un conjunto de selección y devuelve una lista
(defun sel2lst( sel / n l)
(repeat (setq n (sslength sel))
(setq n (1- n) l (cons (ssname ss n) l))
)
)
;;;LST2SEL
;;;La función opuesta, recibe una lista y devuelve un conjunto de selección
(defun lst2sel(l / ss)
(setq ss (ssadd))
(foreach e l (ssadd e ss))
)
La siguiente función extrae el resto de una lista l a partir
del término n indicado en el primer argumento:
(defun cdnr ( n l )
(repeat n
(setq l (cdr l))
)
)
La función STRTOL recibe una cadena de caracteres s y
devuelve los caracteres aislados (cadenas de un sólo carácter)
agrupados en una lista:
(defun strtol ( s / lst c )
(repeat (setq c (strlen s))
(setq
lst (cons (substr s c 1) lst)
c (1- c)
)
)
lst
)
Como se ve, esta puede ser otra vía para abordar el desarrollo del
predicado PALINDROMOP: obtener mediante STRTOL la cadena de
caracteres en forma de lista y entonces compararla con la lista invertida por
reverse:
(defun palindromop (cadena)
(setq cadena (strtol cadena))
(equal cadena (reverse cadena))
)
;; Created by Vladimir Nesterovsky
;; YOU MAY USE THIS FUNCTION AS IT IS FOR ANY PURPOSE
;; AT YOUR OWN RISK IF YOU RETAIN THIS NOTICE COMPLETE
;; AND UNALTERED. NO WARRANTIES GIVEN WHATSOEVER.