cg-Cad

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

BEZ1 implementa un classico algoritmo per disegnare le Curve di Bézier *.
BEZ1 (per restare in tema) fa uso di matrici.

Bézier definisce la curva P(u) in funzione della posizione di n+1 punti di controllo p.
P(u)=ni=0piBi,n(u)
Bi,n(u) è detta blending function
Bi,n(u)=C(n,i)ui(1-u)n-i
C(n,i) è il coefficiente binomiale
C(n,i)=n!/(i!(n-1)!)
Le Bi,n(u) costituiscono la chiave del comportamento delle curve di Bézier.

BEZ1

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

   Disegna la Curva di Bezier
   grazie ad una serie di punti p1
   ed un 'array' P di Punti di Controllo

   Implementa in AutoLISP l'algoritmo 21.8
   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 " Punti di Controllo della Curva di Bezier"))
 (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 disPuntiControllo ( NR NC lista / i j x y z )
 (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))
 )
)

(defun Cb ( N i / j a )
 (setq a 1)
 (setq j (+ i 1))
 (while (<= j N)
  (setq a (* a j))
  (setq j (1+ j))
 )
 (setq j 1)
 (while (<= j (- N i))
  (setq a (/ (* 1.0 a) j))
  (setq j (1+ j))
 )
 (setq a a)
)

(defun BBlend ( i N u / j v )
 (setq v (Cb N i))
 (setq j 1)
 (while (<= j i)
  (setq v (* v u))
  (setq j (1+ j))
 )
 (setq j 1)
 (while (<= j (- N i))
  (setq v (* v (- 1 u)))
  (setq j (1+ j))
 )
 (setq v v)
)

(defun Bezier ( xx yy zz u N P / i b e pnt )
 (setq xx 0 yy 0 zz 0)
 (setq i 0)
 (while (<= i N)
  (setq b (BBlend i N u))
  (setq e (nth 0 (nth i P)))
  (setq xx (+ xx (* e b)))
  (setq e (nth 1 (nth i P)))
  (setq yy (+ yy (* e b)))
  (setq e (nth 2 (nth i P)))
  (setq zz (+ zz (* e b)))
  (setq i (1+ i))
 )
 (setq x xx)
 (setq y yy)
 (setq z zz)
 (setq pnt (list x y z))
)

(defun c:bez1 ( / snapp ; salva la variabile di sistema OSMODE
                  NR NC ; numero righe e colonne dell'array P
                  P     ; array Punti di Controllo Curva di Bezier
                  i     ; contatore
                  N     ; grado del polinomio
                  x y z ; coordinate del punto sulla curva p1
                  p1    ; punto sulla Curva
                  steps ; numero punti p1
 )
 (setvar "cmdecho" 0)
 (setq snapp (getvar "osmode"))
 (command "_osnap" "_non")
 (setq x 0 y 0 z 0)
 (setq NR 4 NC 3 N 3)
 (setq steps (getint "\nNumero punti per disegnare la curva [100]: "))
 (if (= steps nil)(setq steps 100))
 (setq P (xyzArray NR NC " P")) ; Input Punti di Controllo
 (disPuntiControllo NR NC P)    ; Disegna i Punti di Controllo
 (setq i 0)
 ;|
    Disegna la Curva di Bezier
 |;
 (while (< i steps)
  (setq p1 (Bezier x y z (/ i (* steps 1.0)) N P))
  (command "_point" p1)
  (setq i (1+ i))
 )
 (setvar "osmode" snapp)
 (command "_redraw")
 (setvar "cmdecho" 1)
 (princ)
)
;;;eof

Test del Lisp

Command: bez1
Numero punti per disegnare la curva [100]: Invio
Inizializzazione Matrice P dei Punti di Controllo della Curva di Bezier
Inserire elemento P[0],[0]: 0
Inserire elemento P[0],[1]: 0
Inserire elemento P[1],[0]: 1
Inserire elemento P[1],[1]: 2
Inserire elemento P[2],[0]: 3
Inserire elemento P[2],[1]: 2
Inserire elemento P[3],[0]: 4
Inserire elemento P[3],[1]: 0

BEZ1.LSP

BEZ2

BEZ2 consente di scegliere il grado del polinomio d'approssimazione (n=3..7) e di immettere i valori dei punti di controllo (n=4..8) della curva, da tastiera o da disegno.

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

   Disegna la Curva di Bezier
   grazie ad una serie di punti p1
   ed un 'array' P di n Punti di Controllo, n=[4..8]

   Implementa in AutoLISP l'algoritmo 21.8
   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 " Punti di Controllo della Curva di Bezier"))
 (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 " Punti di Controllo della Curva di Bezier"))
 (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 disPuntiControllo ( NR NC lista / i j x y z )
 (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))
 )
)

(defun Cb ( N i / j a )
 (setq a 1)
 (setq j (+ i 1))
 (while (<= j N)
  (setq a (* a j))
  (setq j (1+ j))
 )
 (setq j 1)
 (while (<= j (- N i))
  (setq a (/ (* 1.0 a) j))
  (setq j (1+ j))
 )
 (setq a a)
)

(defun BBlend ( i N u / j v )
 (setq v (Cb N i))
 (setq j 1)
 (while (<= j i)
  (setq v (* v u))
  (setq j (1+ j))
 )
 (setq j 1)
 (while (<= j (- N i))
  (setq v (* v (- 1 u)))
  (setq j (1+ j))
 )
 (setq v v)
)

(defun Bezier ( xx yy zz u N P / i b e pnt )
 (setq xx 0 yy 0 zz 0)
 (setq i 0)
 (while (<= i N)
  (setq b (BBlend i N u))
  (setq e (nth 0 (nth i P)))
  (setq xx (+ xx (* e b)))
  (setq e (nth 1 (nth i P)))
  (setq yy (+ yy (* e b)))
  (setq e (nth 2 (nth i P)))
  (setq zz (+ zz (* e b)))
  (setq i (1+ i))
 )
 (setq x xx)
 (setq y yy)
 (setq z zz)
 (setq pnt (list x y z))
)

(defun c:bez2 ( / snapp ; salva la variabile di sistema OSMODE
                  N     ; grado del polinomio [3,7]
                  P     ; array Punti di Controllo Curva di Bezier
                  NR    ; numero righe di P (NR=N+1)
                  NC    ; numero colonne di P (NC=3 x y z)
                  i     ; contatore
                  rsp   ; input Punti di Controllo tastiera/disegno
                  x y z ; coordinate del punto sulla curva p1
                  p1    ; punto sulla Curva
                  steps ; numero punti p1
 )
 (setvar "cmdecho" 0)
 (setq snapp (getvar "osmode"))
 (command "_osnap" "_non")
 (setq x 0 y 0 z 0)
 (while
  (progn
   (initget (+ 2 4)) ; N>0  
   (setq N (getint "\nGrado del polinomio <3..7> [3]: "))
   (if (= N nil)
    (progn
     (setq N 3)
     nil
    )
    T
   )
   (if (and (>= N 3)(<= N 7)) nil T)
  )
 )
 (setq NR (+ N 1) NC 3)
 (initget (+ 2 4)) ; steps>0
 (setq steps 
  (getint "\nNumero punti della curva [100]: ")
 )
 (if (= steps nil)(setq steps 100))
 (initget "t T d D")
 (setq rsp 
  (getkword "\nInput punti controllo tastiera o disegno? <t,d> [d]: ")
 )
 (if (or (= rsp "t")(= rsp "T"))
  (progn
   (setq P (xyzArray NR NC " P")) ; Input Punti di Controllo (tastiera)
   (disPuntiControllo NR NC P)    ; Disegna i Punti di Controllo
  )
  (progn
   (setq P (xyzList NR " P"))     ; Input Punti di Controllo (disegno)
   (disPuntiControllo NR NC P)    ; Disegna i Punti di Controllo
  )
 )
 (setq i 0)
 ;|
    Disegna la Curva di Bezier
 |;
 (while (< i steps)
  (setq p1 (Bezier x y z (/ i (* steps 1.0)) N P))
  (command "_point" p1)
  (setq i (1+ i))
 )
 (setvar "osmode" snapp)
 (command "_redraw")
 (setvar "cmdecho" 1)
 (princ)
)
;;;eof

Test del Lisp

Command: bez2
Grado del polinomio <3..7> [3]: 5
Numero punti della curva [100]: Invio
Input punti controllo tastiera o disegno? <t,d> [d]: t
Inizializzazione Matrice P Punti di Controllo della Curva di Bezier
Inserire elemento P[0],[0]: 1
Inserire elemento P[0],[1]: 0
Inserire elemento P[1],[0]: 2
Inserire elemento P[1],[1]: 0
Inserire elemento P[2],[0]: 2
Inserire elemento P[2],[1]: 2
Inserire elemento P[3],[0]: 0
Inserire elemento P[3],[1]: 2
Inserire elemento P[4],[0]: 0
Inserire elemento P[4],[1]: 0
Inserire elemento P[5],[0]: 1
Inserire elemento P[5],[1]: 0

BEZ2.LSP

Command: bez2
Grado del polinomio <3..7> [3]: 7
Numero punti della curva [100]: Invio
Input punti controllo tastiera o disegno? <t,d> [d]: Invio
Inizializzazione Matrice P Punti di Controllo della Curva di Bezier
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...
Seleziona 7 Punto di Controllo...
Seleziona 8 Punto di Controllo...

BEZ2.LSP

BEZ2.LSP

BEZ3

BEZ3 disegna la Curva grazie ad una serie di linee.

[...]

(defun c:bez3 ( / snapp ; salva la variabile di sistema OSMODE
                  N     ; grado del polinomio [3,7]
                  P     ; array Punti di Controllo Curva di Bezier
                  NR    ; numero righe di P (NR=N+1)
                  NC    ; numero colonne di P (NC=3 x y z)
                  i     ; contatore
                  rsp   ; input Punti di Controllo tastiera/disegno
                  x y z ; coordinate del punto sulla curva p1
                  p1,p2 ; estremi della linea
                  steps ; numero punti p1,p2
 )
 (setvar "cmdecho" 0)
 (setq snapp (getvar "osmode"))
 (command "_osnap" "_non")
 (setq x 0 y 0 z 0)
 (while
  (progn
   (initget (+ 2 4)) ; N>0  
   (setq N (getint "\nGrado del polinomio <3..7> [3]: "))
   (if (= N nil)
    (progn
     (setq N 3)
     nil
    )
    T
   )
   (if (and (>= N 3)(<= N 7)) nil T)
  )
 )
 (setq NR (+ N 1) NC 3)
 (initget (+ 2 4)) ; steps>0
 (setq steps 
  (getint "\nNumero punti della curva [100]: ")
 )
 (if (= steps nil)(setq steps 100))
 (initget "t T d D")
 (setq rsp 
  (getkword "\nInput punti controllo tastiera o disegno? <t,d> [d]: ")
 )
 (if (or (= rsp "t")(= rsp "T"))
  (progn
   (setq P (xyzArray NR NC " P")) ; Input Punti di Controllo (tastiera)
   (disPuntiControllo NR NC P)    ; Disegna i Punti di Controllo
  )
  (progn
   (setq P (xyzList NR " P"))     ; Input Punti di Controllo (disegno)
   (disPuntiControllo NR NC P)    ; Disegna i Punti di Controllo
  )
 )
 (setq p1 (Bezier 0 0 0 0 N P))
 (setq i 1)
 ;|
    Disegna la Curva di Bezier
 |;
 (while (< i steps)
  (setq p2 (Bezier x y z (/ i (* steps 1.0)) N P))
  (command "_line" p1 p2 "")
  (setq p1 p2)
  (setq i (1+ i))
 )
 (setvar "osmode" snapp)
 (command "_redraw")
 (setvar "cmdecho" 1)
 (princ)
)
;;;eof

BEZ3.LSP

Per approfondire:

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

P. Bézier è stato il primo ad usare la modellazione di superfici al computer nella progettazione automobilistica; il suo sistema UNISURF, usato dai progettisti a partire dal 1972, è stato utilizzato per definire le carrozzerie di diverse auto prodotte dalla Renault.

function C(n,i:integer):integer;
var j,a:integer;

begin
   a := 1;
   for j := i+1 to n do a := a*j;
   for j := 1 to n-i do a := a div j;
   C := a
end;

function BBlend(i,n:integer;u:real):real;
var j:integer;v:real;

begin
   v := C(n,i);
   for j := 1 to i do v := v*u;
   for j := 1 to n-i do v := v*(1-u);
   BBlend := v
end;

procedure Bezier(var x,y,z:real;u:real;n:integer;var p:xyzArray);
var i:integer;b:real;

begin
   x := 0;y := 0;z := 0;
   for i := 0 to n do begin
      b := BBlend(i,n,u);
      x := x+p[i,1]*b;
      y := y+p[i,2]*b;
      z := z+p[i,3]*b
   end
end;

procedure DrawCurve;
var ControlPoints: xyzArray;i: integer;x,y,z: real;

begin
   for i := 0 to 3 do ControlPoints[i,3] := 0;
   ControlPoints[0,1] := 0;ControlPoints[0,2] := 0;
   ControlPoints[1,1] := 1;ControlPoints[1,2] := 2;
   ControlPoints[2,1] := 3;ControlPoints[2,2] := 2;
   ControlPoints[3,1] := 4;ControlPoints[3,2] := 0;

   for i := 0 to 40 do begin
      Bezier(x,y,z,i/40,3,ControlPoints);
      if i=0 then MoveTo(x,y) else LineTo(x,y)
   end
end;

Lisp »Tips 'n Tricks

Ultimo Aggiornamento_Last Update: 21 Giugno 2005