Suavemente conectando centros de círculo

Intento dibujar un camino a través del interior de un tubo, a lo largo del centro. Los datos con los que tengo que trabajar son los puntos centrales de los círculos que describen el tubo al comienzo y al final de cada vuelta en la tubería.

Dibujar el camino a través de las secciones rectas de la tubería es trivial, pero no estoy seguro de cómo acercarme a las curvas. Cualquier giro entre dos círculos debe ser de radio constante. Así que tengo acceso a dos puntos en este círculo, y la dirección de la línea del círculo en ese punto.

¿Alguien sabe cómo calcularía el rest del círculo a partir de esto?

Editar:

Adjunto un boceto fotorrealista de una tubería.

¡Es como si estuviera en la tubería!

Así que pretenda que la curva no es tambaleante como el infierno, las líneas azules indican el círculo, el rojo los puntos centrales, y el verde el camino a través del centro.

  1. Aclaración

    el tubo tiene el mismo diámetro circular en todas partes, por lo que no hay distorsión debido a la flexión. la entrada es de 2 puntos finales (centros de tubo) P0,P1 y 2 vectores (normal / dirección del tubo) N0,N1

    codo de tubo

  2. Solución

    Utilice interpolación cúbica, por ejemplo, esta

     p(t)=a0+a1*t+a2*t*t+a3*t*t*t t=<0,1.0> 

    entonces escriba ecuaciones para los datos conocidos, resuelva los coeficientes a0,a1,a2,a3 para cada eje que necesite (2D: x,y ) y luego puede obtener el punto central y su normal en cualquier punto a lo largo del lado de la curva, que es necesitas.

    Ahora algunas ecuaciones genéricas:

     p(t)=a0+a1*t+ a2*t*t+ a3*t*t*t // circle center position n(t)= a1 +2.0*a2*t +3.0*a3*t*t // circle orientation 
    • p,n,a0,a1,a2,a3 son vectores !!!
    • t es escalar

    Ahora agregue los datos conocidos

     I. t=0 -> p(0)=P0 P0=a0 a0=P0 II. t=0 -> n(0)=N0 N0=a1 a1=N0 III. t=1 -> p(1)=P1 P1=a0+a1+a2+a3 P1=P0+N0+a2+a3 a2=P1-P0-N0-a3 IV. t=1 -> n(1)=N1 N1=a1+2.0*a2+3.0*a3 N1=N0+2.0*(P1-P0-N0-a3)+3.0*a3 a3=N1+N0-2.0*(P1-P0) III. a2=P1-P0-N0-(N1+N0-2.0*(P1-P0)) a2=P1-P0-N0-N1-N0+2.0*(P1-P0) a2=P1-P0-N1+2.0*(P1-P0-N0) a2=3.0*(P1-P0)-N1-2.0*N0 

    Entonces, si no cometí ningún error tonto, los coeficientes son:

     a0=P0 a1=N0 a2=3.0*(P1-P0)-N1-2.0*N0 a3=N1+N0-2.0*(P1-P0) 

    Entonces, simplemente codifique ecuaciones genéricas en alguna función con el parámetro de entrada t y la salida p(t) n(t) y / o represente el segmento del círculo o tubo y la invoque para el bucle, por ejemplo, así:

     for (t=0.0;t<=1.0;t+=0.1) f(t); 

[edit1] Implementación de C ++

 //--------------------------------------------------------------------------- void glCircle3D(double *pos,double *nor,double r,bool _fill) { int i,n=36; double a,da=divide(pi2,n),p[3],dp[3],x[3],y[3]; if (fabs(nor[0]-nor[1])>1e-6) vector_ld(x,nor[1],nor[0],nor[2]); else if (fabs(nor[0]-nor[2])>1e-6) vector_ld(x,nor[2],nor[1],nor[0]); else if (fabs(nor[1]-nor[2])>1e-6) vector_ld(x,nor[0],nor[2],nor[1]); else vector_ld(x,1.0,0.0,0.0); vector_mul(x,x,nor); vector_mul(y,x,nor); vector_len(x,x,r); vector_len(y,y,r); if (_fill) { glBegin(GL_TRIANGLE_FAN); glVertex3dv(pos); } else glBegin(GL_LINE_STRIP); for (a=0.0,i=0;i<=n;i++,a+=da) { vector_mul(dp,x,cos(a)); vector_add(p,pos,dp); vector_mul(dp,y,sin(a)); vector_add(p,p ,dp); glVertex3dv(p); } glEnd(); } //--------------------------------------------------------------------------- void tube(double *P0,double *N0,double *P1,double *N1,double R) { int i; double a0[3],a1[3],a2[3],a3[3],p[3],n[3],t,tt,ttt; // compute coefficients for (i=0;i<3;i++) { a0[i]=P0[i]; a1[i]=N0[i]; a2[i]=(3.0*(P1[i]-P0[i]))-N1[i]-(2.0*N0[i]); a3[i]=N1[i]+N0[i]-2.0*(P1[i]-P0[i]); } // step through curve from t=0 to t=1 for (t=0.0;t<=1.0;t+=0.02) { tt=t*t; ttt=tt*t; // compute circle position and orientation for (i=0;i<3;i++) { p[i]=a0[i]+(a1[i]*t)+(a2[i]*tt)+(a3[i]*ttt); n[i]=a1[i]+(2.0*a2[i]*t)+(3.0*a3[i]*tt); } // render it glCircle3D(p,n,R,false); } } //--------------------------------------------------------------------------- void test() { // tube parameters double P0[3]={-1.0, 0.0, 0.0},N0[3]={+1.0,-1.0, 0.0},p[3]; double P1[3]={+1.0,+1.0, 0.0},N1[3]={ 0.0,+1.0, 0.0}; // just normalize normals to size 3.1415... vector_len(N0,N0,M_PI); vector_len(N1,N1,M_PI); // draw normals to visula confirmation of tube direction glBegin(GL_LINES); glColor3f(0.0,0.0,1.0); vector_add(p,P0,N0); glVertex3dv(P0); glVertex3dv(p); glColor3f(0.0,0.0,1.0); vector_add(p,P1,N1); glVertex3dv(P1); glVertex3dv(p); glEnd(); // render tube glColor3f(1.0,1.0,1.0); tube(P0,N0,P1,N1,0.2); } //--------------------------------------------------------------------------- 

Visualmente se ve mejor cuando las normales son del tamaño M_PI (3.1415...) así es como busca el código anterior:

tubería C ++

el código de mina usa la biblioteca de vectores de minas, así que solo necesitas codificar funciones como:

 vector_ld(a,x,y,z); //a[]={ x,y,z } vector_mul(a,b,c); //a[]=b[] xc[] vector_mul(a,b,c); //a[]=b[] * c vector_add(a,b,c); //a[]=b[] + c[] vector_sub(a,b,c); //a[]=b[] - c[] vector_len(a,b,c); //a[]=b[]* c / |b[]| 

lo cual es fácil (espero no haberme olvidado de copiar algo ...) ...