Lisp »Tips 'n Tricks
»Funzioni ricorsive in AutoLISP
»1
| 2
| 3
| 4
| 5
| 6
| 7 a
, b
, c
, d
, e
Permutazioni di n elementi (parte II) + un'applicazione
Perm2.lsp
Questo lisp chiede se gli elementi da permutare sono numeri o lettere ed il loro numero.
;;;
;;; perm2.lsp - 2 Marzo 2004
;;; (C) 2004 by Claudio Piccini.
;;; www.cg-cad.com
;;;
;;; Permutazioni di n elementi
;;;
(defun permuta (ls k n i)
(if (= k (- n 1))
(stampa ls)
(progn
(setq i k)
(while (< i n)
(scambia i k)
(permuta ls (+ k 1) n i)
(scambia i k)
(setq i (1+ i))
)
)
)
)
(defun stampa (ls / e)
(setq e 0)
(repeat (length ls)
(princ (nth e ls))
(princ " ")
(setq e (1+ e))
)
(princ "\n")
)
(defun scambia (i j / temp a b q lss)
(setq temp (nth i ls))
(if (/= i j)
(progn
(setq a (nth j ls))
(setq q 0)
(repeat (length ls)
(setq b (nth q ls))
(cond
((= q i)
(setq lss (append lss (list a)))
)
((= q j)
(setq lss (append lss (list temp)))
)
((and (/= q i)(/= q j))
(setq lss (append lss (list b)))
)
)
(setq q (1+ q))
)
(setq ls lss)
(setq lss nil)
)
)
)
(defun c:perm ( / rs x i n k ls )
(setvar "cmdecho" 0)
(setq i 0)
(setq k 0)
(initget "N n L l")
(setq rs (getkword "\nNumeri o lettere? (n/l): "))
(cond
((or (= rs "n") (= rs "N") (= rs nil))
(setq rs "N")
)
((or (= rs "l") (= rs "L"))
(setq rs "L")
)
)
(if (= rs "N")
(progn
(setq n (getint "\nQuanti numeri? "))
(repeat n
(setq x (getint "\nNumero? "))
(setq ls (append ls (list x)))
)
)
(progn
(setq n (getint "\nQuante lettere? "))
(repeat n
(setq x (getstring "\nLettera? "))
(setq ls (append ls (list x)))
)
)
)
(permuta ls 0 n i)
(setvar "cmdecho" 1)
(princ)
)
;;;eof
|
Test del LISP
Command: perm
Numeri o lettere? (n/l): l
Quante lettere? 3
Lettera? p
Lettera? i
Lettera? o
p i o
p o i
i p o
i o p
o i p
o p i
Command: perm
Numeri o lettere? (n/l): Invio
Quanti numeri? 3
Numero? 3
Numero? 6
Numero? 2
3 6 2
3 2 6
6 3 2
6 2 3
2 6 3
2 3 6
Pl.lsp
Questo lisp mostra la distanza totale tra n punti permutati.
;;;
;;; pl.lsp - 2 Marzo 2004
;;; (C) 2004 by Claudio Piccini.
;;; www.cg-cad.com
;;;
;;; distanza totale
;;; tra n punti permutati.
;;;
(defun permuta (ls k n i)
(if (= k (- n 1))
(sommadist ls)
(progn
(setq i k)
(while (< i n)
(scambia i k)
(permuta ls (+ k 1) n i)
(scambia i k)
(setq i (1+ i))
)
)
)
)
(defun sommadist (ls / k n p1 p2 dist)
(setq k 0)
(setq n (length ls))
(while (< k (- n 1))
(setq p1 (nth k ls))
(setq p2 (nth (1+ k) ls))
(setq dist (distance p1 p2))
(setq somma (+ dist somma))
(setq k (1+ k))
)
)
(defun scambia (i j / temp a b q lss)
(setq temp (nth i ls))
(if (/= i j)
(progn
(setq a (nth j ls))
(setq q 0)
(repeat (length ls)
(setq b (nth q ls))
(cond
((= q i)
(setq lss (append lss (list a)))
)
((= q j)
(setq lss (append lss (list temp)))
)
((and (/= q i)(/= q j))
(setq lss (append lss (list b)))
)
)
(setq q (1+ q))
)
(setq ls lss)
(setq lss nil)
)
)
)
(defun c:pl ( / ss ls n i somma n k kk ent punto)
(setvar "cmdecho" 0)
(setq i 0)
(setq k 0)
(setq somma 0.0)
(setq ss (ssget "X" '((0 . "POINT"))))
(setq n (sslength ss))
(if (/= n nil) ; estraggo i punti
(progn
(setq kk 0)
(repeat n
(setq ent (entget (ssname ss kk)))
(setq punto (assoc 10 ent))
(setq punto (cdr punto))
(setq ls (append ls (list punto)))
(setq kk (1+ kk))
)
(setq n (length ls))
(permuta ls 0 n i)
(princ "\nsomma delle distanze: ")
(princ somma)
)
)
(setvar "cmdecho" 1)
(princ)
)
;;;eof
|
Analisi del LISP
(setq ss (ssget "X" '((0 . "POINT")))) con questa istruzione seleziono tutti i punti presenti nel disegno, e salvo la selezione nella lista ss.
Per conoscere quanti punti ho selezionato adopero l'istruzione: (setq n (sslength ss)) e per espodere la selezione entità per entità impiego l'istruzione (setq ent (entget (ssname ss kk))), dove kk è una variabile-contatore.
Ad esempio con kk=0:
Command: (setq ent (entget (ssname ss 0)))
((-1 . <Entity name: 19a1c90>) (0 . "POINT") (330 . <Entity name: 19a18f8>) (5
. "39572") (100 . "AcDbEntity") (67 . 0) (410 . "Model") (8 . "SIMBOLI") (100 .
"AcDbPoint") (10 2.46265 -1.77469 0.0) (210 0.0 0.0 1.0) (50 . 0.0))
Il codice 0 dichiara che l'entità è un punto (ma questo è ovvio perché ho usato il filtro '((0 . "POINT")) per selezionare solo punti).
Il codice 10 contiene le coordinate x,y,z del punto; quindi da questa lista si deve estrarre il codice 10.
Con la funzione (assoc codice ent): (setq punto (assoc 10 ent))
Command: (setq punto (assoc 10 ent))
(10 2.46265 -1.77469 0.0)
Adesso nella variabile punto è memorizzata la lista con il codice 10 e le coordinate x,y,z del punto.
Command: !punto
(10 2.46265 -1.77469 0.0)
Per eliminare il codice 10 dalla lista uso una delle funzioni CAR di Autolisp e cioè (cdr), (setq punto (cdr punto)):
Command: (setq punto (cdr punto))
(2.46265 -1.77469 0.0)
Ovviamente è possibile compattare tutte le istruzioni in una sola lista:
(setq punto (cdr (assoc 10 (entget (ssname ss kk))))) e si risparmia (pure) una variabile, ma è più facile commettere errori e dimenticare qualche parentesi chiusa.
Command: (setq punto (cdr (assoc 10 (entget (ssname ss 2)))))
(5.346 -0.299623 0.0)
Adesso posso salvare il punto nella lista ls: (setq ls (append ls (list punto))).
Tutto questo deve essere ripetuto n volte, dove n è il numero dei punti presenti nella lista ss. Come? con la funzione (repeat).
(setq kk 0)
(repeat n
(setq ent (entget (ssname ss kk)))
(setq punto (assoc 10 ent))
(setq punto (cdr punto))
(setq ls (append ls (list punto)))
(setq kk (1+ kk))
)
Però facendo attenzione a racchiudere le istruzioni all'interno della funzione (if) perché la selezione ss potrebbe essere vuota e quindi n=nil.
(if (/= n nil) ; estraggo i punti
(progn
(setq kk 0)
(repeat n
(setq ent (entget (ssname ss kk)))
(setq punto (assoc 10 ent))
(setq punto (cdr punto))
(setq ls (append ls (list punto)))
(setq kk (1+ kk))
)
(setq n (length ls))
(permuta ls 0 n i)
...
Lisp »Tips 'n Tricks
Ultimo Aggiornamento_Last Update: 3 Marzo 2004
|