Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Curvas y Superficies
Representación paramétrica:
u=0
(x,y,z)
P(u) u=1
z
Sea:
x(u ) = a3 x u 3 + a 2 x u 2 + a1x u + a 0 x
y (u ) = a3 y u 3 + a 2 y u 2 + a1 y u + a 0 y
z (u ) = a3 z u 3 + a 2 z u 2 + a1z u + a0 z
Pˆ (u ) = Pˆ ( x(u ), y (u ), z (u ) ) = aˆ 3u 3 + aˆ 2 u 2 + aˆ1u + aˆ 0
u ∈ [0,1]
u 3
a3 x a2 x a1x a0 x 2
u
Pˆ (u ) = a3 y a2 y a1 y a 0 y 1
u
a3 z a2 z a1z a 0 z
1
P ( 0) = a 0
P (1) = a3 + a 2 + a1 + a 0
P u (0) = a1
P u (1) = 3a3 + 2a 2 + 1a1
Resolviendo para a0, a1, a2, a3 se tiene:
a 0 = P(0)
a1 = P u (0)
a 2 = −3P(0) + 3P(1) − 2 P u (0) − P u (1)
a3 = 2 P(0) − 2 P(1) + P u (0) + P u (1)
Llamemos:
F1 (u ) = 2u 3 − 3u 2 + 1
F2 (u ) = −2u 3 + 3u 2
F3 (u ) = u 3 − 2u 2 + u
F4 (u ) = u 3 − u 2
Luego:
En forma Matricial
P = u3 [ u2 ]
u 1 [a3 a2 a1 a0 ]
T
Sea :
U = [u 3 u 2 u1 1]
A = [a3 a 2 a1 a0 ]
P = [F1 F2 F3 [
F4 ] P0 P1 Pou P1u ]T
P = FB
[
F = (2u 3 − 3u 2 + 1) (− 2u 3
+ 3u 2 ) (u 3
− 2u 2 + u ) (u 3
]
− u2 )
2 −2 1 1
− 3 3 − 2 − 1
F = u3 [ u2 u 1 ]
0 0 1 0
114404240 0
443
=M
F = UM
P = UMB para P = UA
Luego
A = MB
P (u ) = UMB u ∈ [0,1]
Las curvas anteriores definidas por los puntos de comienzo y finales,
además de sus pendientes, se llaman curvas de Hermite.
Pu(u)
tz
tx ty
t = t x2 + t y2 + t z2 = 1
Se define:
k = Pu
luego P u = k * t
[
B = P0 P1 P0u P1u ]
T
Se puede escribir como:
B = [P0 k1t1 ]
T
P1 k0t0
Sólo variando k
6.3 Reparametrización
Algunas veces se requiere cambiar los parámetros de una curva, sin
variar la posición ni la forma de ésta. Veamos el caso general:
uj vj
ui vi
[
B = Pi Pj Pi u Pju ]
T
→ B = qi [ qj qiv q vj ]
T
qi = Pi
q j = Pj
v = au + b
Así
dv = a du
vi = au i + b
v j = au j + b
v j − vi = a(u j − u i )
v j − vi
a=
u j − ui
du 1 1 u
= ⇒ Pv = P
dv a a
Luego:
u j − ui
qiv = Pi u
v j − vi
u j − ui
q vj = Pju
v j − vi
ui vi=1 u=1
u=0
u j − ui
qiv = Pi u = (u j − u i )Pi u
v j − vi
q 0v = (u j − u i )Pi v
[q 0 q1 q0u q1u ]
T
= k [P1 P2 P3 P4 ]
T
(1)
P(u ) = UMB
Luego:
[P1 P2 P3 P4 ] = [U 1 U 2 U 3 U 4 ] MB
T T
De aquí
B = M −1 [U 1 U 2 U 3 U 4 ] [P1 P4 ]
T −1 T
P2 P3
k = M −1 [U 1 U 2 U 3 U 4 ]
T −1
B = k [P1 P4 ]
T
P2 P3
De donde:
[P1 P2 P3 P4 ] = k −1 B
1 0 0 0
0 0 0 1
k=
− 11 / 2 9 − 9 / 2 1
−1 9 / 2 − 9 11 / 2
1 0 0 0
20 / 27 7 / 27 4 / 27 − 2 / 27
k=
7 / 27 20 / 27 2 / 27 − 4 / 27
0 1 0 0
Sea
P = [P1 P4 ]
T
P2 P3
P = UMB B = kP
P = UMKP con Mk = N
P = UNP
− 9 / 2 27 / 2 − 27 / 2 9 / 2
9 − 45 / 2 18 − 9 / 2
N=
− 11 / 2 9 −9/2 1
1 0 0 0
Expandiendo se llega a
( ) ( ) ( )
P = − 4,5u 3 + 9u 2 − 5,5u + 1 P1 + 13,5u 3 − 22,5u 2 + 9u P2 + 13,5u 3 + 18u 2 − 4,5u P3 +
(4,5u 3
)
− 4,5u 2 + u P4
Se puede describir una curva que pasa por los puntos P0 y Pn, y se
aproxima a los puntos intermedios:
n
P (u ) = ∑ Pk BEZ k ,n (u ) u ∈ [0,1]
k =0
BEZ k ,n (u ) = C (n, k ) u k (1 − u ) n − k
Donde:
n!
C (n, k ) =
k!(n − k )!
En forma sucesiva se puede definir:
n
x(u ) = ∑ xk BEZ k ,n (u )
k =0
n
y (u ) = ∑ yk BEZ k ,n (u )
k =0
n
z (u ) = ∑ zk BEZ k ,n (u )
k =0
P1 P1 P2 P1
P3
P0 P2 P0 P3 P0
P2
P2
P1 P3
P0
P0 P4
P3
P1
P2
6.6.1 Propiedades de curvas de Bezier
Una propiedad útil es que la curva siempre pasa por el primer y último
punto de control.
Condiciones de borde:
P(0) = P0
P(1) = Pn
Las derivadas:
Segundas derivadas:
P3
P2
P4
P1 P1=P5
6.6.2 Composición de Curvas
P1
P2 a3
P0 a0
a1 a2
a0=P2 y los tres puntos P1, (a0,P2), a1 deben ser colineales para tener
continuidad de 1º derivada.
BEZ 0,3 (u ) = (1 − u ) 3
BEZ 1,3 (u ) = 3u (1 − u ) 2
BEZ 2,3 (u ) = 3u 2 (1 − u )
BEZ 3,3 (u ) = u 3
En forma Matricial:
P1
P 2
[
P (u ) = u 3 u2 ]
u 1 • M BEZ • 3
P
4
P
−1 3 − 3 1
3 −6 3 0
M BEZ =
− 3 3 0 0
1 0 0 0
m n
P (u , v) = ∑∑ Pj ,k BEZ j ,m (v) BEZ k ,n (u )
j =0 k =0
Con Pj,k que especifica una ubicación de (m+1) por (n+1) puntos de
control.
P30 P31 P32
P33
P20
u P21
P22 P23
P10
P11
P12
P13
P00
P01
P02
v P03
−1 3 − 3 1
3 −6 3 0
M BEZ =
− 3 3 0 0
1 0 0 0
Pu (0,0)
Pv (0,0)
P00
v
P u (0,0) = 3 ( P10 − P00 )
P v (0,0) = 3 ( P01 − P00 )
P uv (0,0) = 9 ( P00 − P01 − P10 + P11 )
Por ejemplo:
a = P01 − P00
b = P10 − P00
N = a×b
S0
S1
S2
C
Por ejemplo, la curva C está formada por los arcos S0, S1 y S2. A su vez S0,
S1 y S2 podrían ser curvas de Bezier, las cuales están definidas por los
polinomios de Bernstein.
6.8.1 Construcción de Splines usando polinomios
como base.
De la siguiente curva:
g(t)
b(t)
Puntos knet
Soporte
1 2
a (t ) = t
2
2
3 3
b(t ) = − t −
4 2
1
c(t ) = (3 − t ) 2
2
4
P (t ) = ∑ Pk g k (t )
k =0
donde
gk (t ) = g (t − k ) k = 0, 1, 2, 3, 4
Se tiene que P(t) en cada “span” está dado por una suma de
polinomios, con un peso Pk para cada uno de ellos.
Ejemplo:
P (t ) = P0 g (t ) 0 ≤ t ≤1
P (t ) = P0 g (t ) + P1 g (t − 1) 1≤ t ≤ 2
P (t ) = P0 g (t ) + P1 g (t − 1) + P2 g (t − 2) 2≤t ≤3
↓
etc
g(t)
g0 g1 g2 g3 g4
3/4
1/2
1 2 3 4 5 6 7 t
P0 P1
2
P2
t=1 4
P4
5 P4
6
De lo anterior se desprende que en un stan o barrido cualquier parte de
esa curva equivale a una suma de polinomios ponderados por los
puntos de control.
n
P (u ) = ∑ Pk Bk ,d (u ) u mín ≤ u ≤ u máx
k =0
2 ≤ d ≤ n +1
1 si u k ≤ u ≤ u k +1
Bk ,1 (u ) =
0 otro caso
u − uk u −u
Bk ,d (u ) = Bk ,d −1 (u ) + k + d Bk +1,d −1 (u )
u k + d −1 − u k u k + d − u k +1
Donde cada función Blending está definida sobre d intervalos del rango
total de u.
Los valores para umín y umáx dependen del número de puntos de control,
el valor elegido para d y de como se eligen los subintervalos (vector
knot).
El valor 0/0 se asume como 0 en caso de ocurrir en la fórmula anterior.
Por ejemplo:
Ejemplo:
n=d =3
{0, 1, 2, 3, 4, 5, 6}
y el rango de u es de 0 a 6, con n+d=6 subintervalos.
Con n+1=4 puntos de control, la curva está descrita por n+1=4 funciones
Blending.
Cada una de las cuatro funciones Blending span d=3 subintervalos del
rango total de u.
Así
1 2
2 u 0 ≤ u ≤1
1 1
B0,3 (u ) = u (2 − u ) + (u − 1)(3 − u ) 1 ≤ u ≤ 2
2 2
1
2 (3 − u ) 2≤u≤3
2
1
2 (u − 1) 1≤ u ≤ 2
2
1 1
B1,3 (u ) = (u − 1) (3 − u ) + (u − 2)(4 − u ) 2≤u≤3
2 2
1
2 (4 − u ) 3≤u ≤ 4
2
1
2 (u − 2) 2≤u≤3
2
1 1
B2,3 (u ) = (u − 2) (4 − u ) + (u − 3)(5 − u ) 3≤u ≤ 4
2 2
1
2 (5 − u ) 4≤u≤5
2
1
2 (u − 3) 3≤u ≤ 4
2
1 1
B3,3 (u ) = (u − 3) (5 − u ) + (u − 4)(6 − u ) 4≤u≤5
2 2
1
2 (6 − u ) 5≤u ≤6
2
B0,3(u) B1,3(u)
1 2 3 4 5 6 1 2 3 4 5 6
B2,3(u) B3,3(u)
1 2 3 4 5 6 1 2 3 4 5 6
Todas las funciones Blending están presentes entre ud-1=2 y un+1=4. Este
es el rango de la curva polinomial. En este rango, la suma de las
funciones es igual a 1.
P1 P2
P0 P3
1
Pcomienzo = ( P0 + P1 )
2
1
Pfinal = ( P2 + P3 )
2
También las derivadas están dadas por:
P 'comienzo = P1 − P0
P ' final = P3 − P2
0 0≤ j≤d
uj = j − d + 1 d≤ j≤n
n − d + 2 j>n
Con esta asignación los primeros d knots tienen un valor 0 y los últimos d
knots tienen un valor n-d+2.
Ejemplo:
knot vector = {u 0 , u1 , u 2 , u 3 , u 4 , u 5 , u 6 , u 7 , u8 }
{0, 0, 0, 1, 2, 3, 3, 3}
1
2 u (4 − 3u ) 0 ≤ u <1
B1,3 (u ) =
1 (2 − u ) 2 1≤ u < 2
2
1 2
2 u 0 ≤ u <1
1 1
B2,3 (u ) = u (2 − u ) + (u − 1) (3 − u ) 1≤ u < 2
2 2
1
2 (3 − u ) 2≤u<3
2
1
2 (u − 1) 1≤ u < 2
2
B3,3 (u ) =
1 (3 − u )(3u − 5) 2≤u<3
2
B4,3 (u ) = (u − 2) 2 2≤u<3
B0,3(u) B1,3(u)
1
0,6
0,5 1 2
B2,3(u) B3,3(u)
0,6 0,6
1 2 1 2 u
3 3
B4,3(u)
1 2 u
3
6.9 Superficies
Esto es similar al caso Bezier. En efecto, la ecuación de la superficie es:
n1 n2
P (u, v) = ∑ ∑P
k1 = 0 k 2 = 0
k 1, k 2 Bk1,d 1 (u ) Bk 2,d 2 (u )
∑W k Pk Bk ,d (u )
P (u ) = k =0
n
∑W
k =0
k Bk ,d (u )
6.9.2 NURBS
Se puede hacer esto con una spline definida por el vector knot abierto:
{0, 0, 0, 1, 1, 1}
las funciones de peso son:
W0 = W 2 = 1
r
W1 = 0 ≤ r <1
1− r2
r
P0 B0,3 + P1 B1,3 + P2 B2,3
(1 − r )
P (u ) =
r
B0,3 + B1,3 + B2,3
(1 − r )
1
r> , W1 > 1 (hiperbola)
2
1
r = , W1 = 1 ( parábola )
2
1
r = , W1 < 1 (elipse)
2
r = 0, W1 = 0 ( segmento recto)
P1
Hipérbola
P0 Parábola
Elipse
Segmento Recto
Se puede también generar un cuarto de círculo eligiendo W1=cosφ y
eligiendo los puntos de control:
P0=(0,1) P1=(1,1)
φ
P2=(1,0)
GLint nNumPoints = 4;
GLfloat ctrlPoints[4][3]=
{{ -4.0f, 0.0f, 0.0f}, // Punto final
{ -6.0f, 4.0f, 0.0f}, // Punto de control
{ 6.0f, -4.0f, 0.0f}, // Punto de control
{ 4.0f, 0.0f, 0.0f }}; // Punto final
Definimos la Curva Bezier
// Usa funciones de más alto nivel para mapear una rejilla, y evaluar todo
if(h == 0)
h = 1;
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
rango=8;
glFrustum(-rango,rango, -rango, rango, 100000,250000);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0,0,-120000);
}
//---------------------------------------------------------------------------
void __fastcall TFormMain::RenderGLScene()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
DrawObjects();
glFlush();
}
//---------------------------------------------------------------------------
void __fastcall TFormMain::DrawObjects()
{
//Define la Bezier, Sólo necesitamos ejecutar ésto una vez y puede
// estar en la función de inicio
glMap1f(GL_MAP1_VERTEX_3, // Tipo de dato generado
0.0f, // Rango menor de u
100.0f, // Rango superior de u
3, // Distancia entre los puntos almacenados
nNumPoints, // numero de puntos de control
&ctrlPoints[0][0]); // Matriz de puntos de control
// Activa el evaluador
glEnable(GL_MAP1_VERTEX_3);
glColor3f(0,1,0);
glMapGrid1d(100,0.0,100.0);
// Rota la malla sobre sí misma para que sea más fácil de ver
glRotatef(45.0f, 0.0f, 1.0f, 0.0f);
glRotatef(60.0f, 1.0f, 0.0f, 0.0f);
glMap2f(GL_MAP2_VERTEX_3,
0.0f,
10.0f,
3,
3,
0.0f,
10.0f,
9,
3,
&ctrlPoints[0][0][0]);
// Activa el evaluador
glEnable(GL_MAP2_VERTEX_3);
GLint nNumPoints = 3;
TFormMain *FormMain;
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
if(h == 0)
h = 1;
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
rango=6;
glFrustum(-rango,rango, -rango, rango, 100000,250000);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0,0,-150000);
}
//---------------------------------------------------------------------------
void __fastcall TFormMain::DrawObjects()
{
void DrawPoints(void)
{
int i;
glPointSize(5.0f);
glBegin(GL_POINTS);
for(i = 0; i < nNumPoints; i++)
glVertex2fv(ctrlPoints[i][i]);
glEnd();
}
Las funciones NURBS de la librería glu proporcionan utilidades de alto nivel para
generar superficies. No debemos llamar explícitamente a los evaluadores o
establecer los mapas y rejillas. Para generar una NURBS, primero creamos un
objeto NURBS al que nos referiremos cada vez que llamemos a las funciones
NURBS relacionadas para modificar la apariencia de la curva o superficie.
Una vez que hemos creado un generador NURBS, podemos definir varias
propiedades NURBS de alto nivel, como esta:
// Genera la NURBS
// Comienza la definición NURBS
gluBeginSurface(pNurb);
// Evalua la superficie
gluNurbsSurface(pNurb, // Puntero al generador NURBS
8, Knots, // Núm. de nudos y matriz de nudos direcc. u
8, Knots, // Núm. de nudos y matriz de nudos direcc. v
4 * 3, // Distancia entre puntos de control direcc. u
3, // Distancia entre puntos de control direcc. v
&ctrlPoints[0][0][0], // Puntos de control
4, 4, // Ordenes u y v de superficie
GL_MAP2_VERTEX_3); // Tipo de superficie
// superficie terminada
gluEndSurface(pNurb);
GLfloat Knots[8] = {0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f};
TFormMain *FormMain;
//---------------------------------------------------------------------------
__fastcall TFormMain::TFormMain(TComponent* Owner)
: TForm(Owner)
{
Application->OnIdle = IdleLoop;
size = 50.0f;
}
//---------------------------------------------------------------------------
void __fastcall TFormMain::FormCreate(TObject *Sender)
{
hdc = GetDC(Handle);
SetPixelFormatDescriptor();
hrc = wglCreateContext(hdc);
if(hrc == NULL)
ShowMessage(":-)~ hrc == NULL");
if(wglMakeCurrent(hdc, hrc) == false)
ShowMessage("Could not MakeCurrent");
w = ClientWidth;
h = ClientHeight;
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
if(h == 0)
h = 1;
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
rango=30;
glFrustum(-rango,rango, -rango, rango, 100000,250000);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(35,-15,-150000);
glRotatef(30,0,1,1);
}
//---------------------------------------------------------------------------
void __fastcall TFormMain::RenderGLScene()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
DrawObjects();
glFlush();
}
//---------------------------------------------------------------------------
void __fastcall TFormMain::DrawObjects()
{
GLUnurbsObj *pNurb=NULL;
gluNurbsSurface(pNurb,
8, Knots,
8, Knots,
4 * 3,
3,
&ctrlPoints[0][0][0],
4, 4,
GL_MAP2_VERTEX_3);
createSurface();
drawSurface();
}
//---------------------------------------------------------------------------
void __fastcall TFormMain::FormPaint(TObject *Sender)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glFlush();
DrawObjects();
}
//---------------------------------------------------------------------------
oid __fastcall TFormMain::Salir1Click(TObject *Sender)
{
exit(0);
}
//---------------------------------------------------------------------------
void createSurface()
{
GLfloat materialDiffuse[] = { 1.0, 0.0, 0.0, 1.0 };
GLfloat materialSpecular[] = { 1.0 ,0.0, 0.0, 1.0 };
GLfloat materialShininess[] = { 80 };
GLfloat specular[]= {1.0f, 1.0f, 1.0f, 1.0f};
GLfloat specref1[]={1.0f,1.0f,1.0f,1.0f};
glEnable( GL_LIGHTING );
glEnable( GL_LIGHT0 );
glDepthFunc( GL_LEQUAL );
glEnable( GL_DEPTH_TEST );
glEnable( GL_AUTO_NORMAL );
glEnable( GL_NORMALIZE );
nurbSurface = gluNewNurbsRenderer();
gluNurbsProperty( nurbSurface, GLU_SAMPLING_TOLERANCE, 25.0 );
gluNurbsProperty( nurbSurface, GLU_DISPLAY_MODE, GLU_FILL );
}
void drawSurface()
{
GLfloat knots[26] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1 };