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 
 |