cg-Cad

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