cg-Cad

Lisp »Tips 'n Tricks »Lisp & Array »1 »2 »3 »4 »5 »6 »7 »8 »9 »10

BSPL implementa un algoritmo per disegnare le Curve B-spline *.
Legge dal file DATI.TXT le coordinate x,y,z dei punti di controllo (vedi tutorial n.58).

La tecnica B-spline (grazie ad un particolare insieme di funzioni di miscelamento) consente un controllo locale (e quindi maggiore) sulla forma della curva rispetto alla Curva di Bézier e alle curve d'interpolazione (spline).
                        P(u)=ni=0piNi,k(u)

 Ni,1(u)= 1 se ti<=u<ti+1
        = 0 negli altri casi

 Ni,k(u)=[(u-ti)Ni,k-1(u)/ti+k-1-ti]+[(ti+k-u)Ni+1,k-1(u)/ti+k-ti+1]  

L'intervallo in cui è compreso il parametro u è 0<=u<=n-k+2

I valori di collegamento da t0 a tn+k sono scelti in base alla regola:
        0     se i<l
    ti= i-k+1 se k<=i<=n
        n-k+2 se i>n
Il lisp implementa tutto ciò facendo uso di una funzione ricorsiva (vedi Tutorial n.36 in 'AutoLISP Tips & Tricks Volume I').

BSPL

;|
   BSPL.LSP (27 Giugno 2005)
   Copyright (C) 2005 Claudio Piccini.
   All rights reserved
   www.cg-cad.com

   Disegna B-spline non periodiche

   Legge dal file DATI.TXT le coordinate x,y,z dei punti di controllo
   Struttura del file DATI.TXT:
   '(
   (x y z)
   ...
   (x y z)
   )

   Implementa in AutoLISP l'algoritmo 21.15
   in 'Principi di CG', Newman, Sproull (McGraw-Hill)
|;

(defun xyzArray ( NR NC nome / i j L X e str ) 
 (setq str (strcat "\nInizializzazione Matrice" nome " dei Punti di Controllo della B-spline"))
 (princ str)
 (setq i 0)
 (while (< i NR)
  (setq j 0)
  (while (< j NC)
   (if (= j 2)
    (setq e 0.0) ; Z=0
    (progn
     (setq str (strcat "\nInserire elemento " nome "[" (itoa i) "],[" (itoa j) "]: ")) 
     (initget 1)
     (setq e (getreal str))
    )
   )
   (setq L (append L (list e)))
   (setq j (1+ j))
  )
  (setq X (append X (list L)))
  (setq L nil)
  (setq i (1+ i))
 )
 (setq X X)
)

(defun xyzList ( NR nome / i L X p1 str ) 
 (setq str (strcat "\nInizializzazione Matrice" nome " dei Punti di Controllo della B-spline"))
 (princ str)
 (setq i 1)
 (repeat NR
  (setq str (strcat "\nSeleziona " (itoa i) " Punto di Controllo..."))
  (setq p1 (getpoint str))
  (setq L (append L (list (car p1)(cadr p1)(caddr p1))))
  (setq X (append X (list L)))
  (setq L nil)
  (setq i (1+ i))
 )
 (setq X X)
)

(defun xyzFile ( / nDir nf 
                   NR NC lista 
                   str i j e 
                   punto X 
 )
 (setq nDir (getvar "dwgprefix"))
 (setq nf (strcat nDir "dati.txt"))
 (setq lista (load nf))
 (setq NR (length lista))
 (setq str (strcat "\nnumero righe file DATI.TXT=" (itoa NR)))
 (princ str)
 (setq NC (length (car lista)))
 (setq str (strcat "\nnumero colonne file DATI.TXT=" (itoa NC)))
 (princ str)
 (setq i 0)
 (while (< i NR)
  (setq j 0)
  (while (< j NC)
   (setq e (nth j (nth i lista)))
   (setq punto (append punto (list e)))
   (setq j (1+ j))
  )
  (setq X (append X (list punto))) 
  (setq punto nil)
  (setq i (1+ i))
 )
 (setq X X)
)

(defun disPuntiControllo ( NR NC lista / i j x y z )
 (command "_color" 1)
 (setq i 0)
 (while (< i NR)
  (setq j 0)
  (while (< j NC)
   (setq x (nth j (nth i lista)))
   (setq y (nth (+ j 1) (nth i lista)))
   (setq z (nth (+ j 2) (nth i lista)))
   (command "_point" (list x y z))
   (setq j (1+ j))
  )
  (setq i (1+ i))
 )
 (command "_color" "BYLAYER")
)

(defun Knot ( i / knt )
 (cond 
  ((< i knotK)(setq knt 0))
  ((and (<= i knotN)(>= i knotK))(setq knt (+ (- i knotK) 1)))
  ((> i knotN)(setq knt (+ (- knotN knotK) 2)))
 )
 (setq knt knt)
)

(defun NBlend ( i k u / tt v )
 (if (= k 1)
  (progn
   (setq v 0)
   (if (and (<= (Knot i) u)(< u (Knot (+ i 1))))
    (setq v 1)
   )
  )
  (progn
   (setq v 0)
   (setq tt (- (Knot (- (+ i k) 1))(Knot i)))
   (if (/= tt 0)
    (setq v (/ (* (- u (Knot i))(NBlend i (- k 1) u)) (* 1.0 tt)))
   )
   (setq tt (- (Knot (+ i k))(Knot (+ i 1)))) 
   (if (/= tt 0)
    (setq v (+ v (/ (* (- (Knot (+ i k)) u)(NBlend (+ i 1)(- k 1) u)) (* 1.0 tt))))
   )
  )
 )
 (setq v v)
)

(defun BSpline ( x y z u N k P / i b e pnt )
 (setq x 0 y 0 z 0)
 (setq i 0)
 (while (<= i N)
  (setq b (NBlend i k u))
  (setq e (nth 0 (nth i P)))
  (setq x (+ x (* e b)))
  (setq e (nth 1 (nth i P)))
  (setq y (+ y (* e b)))
  (setq e (nth 2 (nth i P)))
  (setq z (+ z (* e b)))
  (setq i (1+ i))
 )
 (setq pnt (list x y z))
)

(defun c:bspl ( / snapp str
                  N P NR NC
                  i k knotN knotK 
                  u incr inter rsp
                  x y z p1 steps
 )
 (setvar "cmdecho" 0)
 (setq snapp (getvar "osmode"))
 (command "_osnap" "_non")
 (setq x 0 y 0 z 0)
 (while 
  (progn
   (initget (+ 2 4)) ; k>0  
   (setq k (getint "\nOrdine di continuita' della curva <2..7> [3]: "))
   (if (= k nil)
    (progn
     (setq k 3)
     nil
    )
    T
   )
   (if (and (>= k 2)(<= k 7)) nil T)
  )
 )
 (while 
  (progn
   (initget (+ 1 2 4))
   (setq str (strcat "\nGrado del polinomio <" (itoa (- k 1)) "..10>: "))   
   (setq N (getint str))
   (if (and (>= N (- k 1))(<= N 10)) nil T)
  )
 )
 (setq knotK k)
 (setq knotN N)
 (setq NR (+ N 1) NC 3)
 (initget (+ 2 4)) ; steps>0
 (setq steps (getint "\nNumero punti per disegnare la curva [100]: "))
 (if (= steps nil)(setq steps 100))
 (initget "t T d D f F")
 (setq rsp (getkword "\nInput punti di controllo tastiera,disegno,file? <t,d,f> [d]: "))
 (cond 
  ((or (= rsp "t")(= rsp "T"))
   (setq P (xyzArray NR NC " P")) ; Input Punti di Controllo (tastiera)
   (disPuntiControllo NR NC P)    ; Disegna i Punti di Controllo
  )
  ((or (= rsp "d")(= rsp "D")(= rsp nil))
   (setq P (xyzList NR " P"))  ; Input Punti di Controllo (disegno)
   (disPuntiControllo NR NC P) ; Disegna i Punti di Controllo
  )
  ((or (= rsp "f")(= rsp "F"))
   (setq P (xyzFile))          ; Input Punti di Controllo (file DATI.TXT)
   (disPuntiControllo NR NC P) ; Disegna i Punti di Controllo
  )
 )
 (setq incr (/ (+ (- N k) 2)(- (* 1.0 steps) 1)))
 (setq inter 0)
 (setq i 0)
 ;|
    Disegna la B-spline
 |;
 (while (< i steps)
  (setq p1 (BSpline x y z inter N k P))
  (setq inter (+ inter incr))
  (command "_point" p1)
  (setq i (1+ i))
 )
 (setvar "osmode" snapp)
 (command "_redraw")
 (setvar "cmdecho" 1)
 (princ)
)
;;;eof

Test del Lisp

DATI.TXT:
'(
(0 0 0)
(1 1 0)
(2 0 0)
)

Command: bspl
Ordine di continuita' della curva <2..7> [3]: Invio
Grado del polinomio <2..10>: 2
Numero punti per disegnare la curva [100]: Invio
Input punti di controllo tastiera,disegno,file? <t,d,f> [d]: f
numero righe file DATI.TXT=3
numero colonne file DATI.TXT=3

BSPL.LSP

DATI.TXT:
'(
(0 0 0)
(1 1 0)
(1 1 0)
(1 1 0)
(2 0 0)
)

Command: bspl
Ordine di continuita' della curva <2..7> [3]: Invio
Grado del polinomio <2..10>: 4
Numero punti per disegnare la curva [100]: Invio
Input punti di controllo tastiera,disegno,file? <t,d,f> [d]: f
numero righe file DATI.TXT=5
numero colonne file DATI.TXT=3

BSPL.LSP

Command: bspl
Ordine di continuita' della curva <2..7> [3]: 5
Grado del polinomio <4..10>: 5
Numero punti per disegnare la curva [100]: 1000
Input punti di controllo tastiera,disegno,file? <t,d,f> [d]: Invio
Inizializzazione Matrice P dei Punti di Controllo della B-spline
Seleziona 1 Punto di Controllo...
Seleziona 2 Punto di Controllo...
Seleziona 3 Punto di Controllo...
Seleziona 4 Punto di Controllo...
Seleziona 5 Punto di Controllo...
Seleziona 6 Punto di Controllo...

BSPL.LSP

DATI.TXT:
'(
(0 0 0 "p0")
(-0.5 0.25 0 "p1")
(-0.5 1 0 "p2")
(0 2 0 "p3")
(0 3 0 "p4")
(-4 4 0 "p5")
)

Command: bspl
Ordine di continuita' della curva <2..7> [3]: Invio
Grado del polinomio <2..10>: 5
Numero punti per disegnare la curva [100]: 1000
Input punti di controllo tastiera,disegno,file? <t,d,f> [d]: f
numero righe file DATI.TXT=6
numero colonne file DATI.TXT=4

BSPL.LSP

DATI.TXT:
'(
(0 0 0 "p0")
(-1 0.25 0 "p1 modificato")
(-0.5 1 0 "p2")
(0 2 0 "p3")
(0 3 0 "p4")
(-4 4 0 "p5")
)

Command: bspl
Ordine di continuita' della curva <2..7> [3]: Invio
Grado del polinomio <2..10>: 5
Numero punti per disegnare la curva [100]: 1000
Input punti di controllo tastiera,disegno,file? <t,d,f> [d]: f
numero righe file DATI.TXT=6
numero colonne file DATI.TXT=4

BSPL.LSP

Trick

La variabile t è chiamata nel sorgente lisp tt (poteva anche essere chiamata nodo o zippo ma non t), perché?

BSPL.LSP

(*) W.M. Newman, R.F. Sproull, Principi di Computer Graphics - 1987, McGraw-Hill

var knotK,knotN : integer;

function Knot(i:integer):integer;
begin
   if i<knotK then Knot := 0
   else if i>knotN then Knot := knotN-knotK+2
   else Knot := i-knotK+1
end;

function NBlend(i,k:integer;u:real):real;
var
   t : integer;
   v : real;

begin
   if k=1 then
      begin
         v := 0;
         if (Knot(i)<=u) and (u<Knot(i+1)) then v := 1
      end
   else
      begin
         v := 0;
         t := Knot(i+k-1)-Knot(i);
         if t<>0 then v := (u-Knot(i))*NBlend(i,k-1,u)/t;
         t := Knot(i+k)-Knot(i+1);
         if t<>0 then v := v+(Knot(i+k)-u)*NBlend(i+1,k-1,u)/t
      end;
   NBlend := v
end;

procedure BSpline(var x,y,z : real; 
                      u     : real;
                      n,k   : integer;
                      P     : xyzArray);
var
   i : integer;
   b : real;

begin
   knotK := k; knotN := n;
   x := 0; y := 0; z := 0;
   for i := 0 to n do begin
      b := NBlend(i,k,u);
      x := x+P[i,1]*b;
      y := y+P[i,2]*b;
      z := z+P[i,3]*b
   end
end;

Lisp »Tips 'n Tricks

Ultimo Aggiornamento_Last Update: 27 Giugno 2005