平滑连接圆心

我试图沿着管子的中心绘制一条路径.我必须使用的数据是圆的中心点,它们描述了管道中每转的起点和终点的管道.

通过管道的笔直部分绘制路径是微不足道的,但是我不确定如何接近弯头.两个圆之间的任何转弯应具有恒定的半径.因此,我可以访问此圆上的两个点以及该点上圆线的方向.

有人知道我将如何从中计算出其余的圆吗?

编辑:

附加了逼真的管道草图.

因此,假装曲线不会像地狱般摇晃,蓝线表示圆形,红色表示中心点,绿色表示通过中心的路径.

解决方法:

>澄清

管到处都具有相同的圆形直径,因此不会由于弯曲而导致变形!输入是2个端点点(管的中心)P0,P1和2个向量(管的法线/方向)N0,N1

>解决方案

以插值三次为例

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

因此,写出已知数据的方程式,求解您需要的每个轴的a0,a1,a2,a3系数(2D:x,y),然后您可以在弯曲边的任意点获得中心点及其法线,这就是你需要.

现在,一些通用方程式:

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是向量!
> t是标量

现在添加已知数据

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

因此,如果我没有犯任何愚蠢的错误,那么系数为:

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

因此,现在只需将泛型方程编码为具有输入参数t和输出p(t)和n(t)的某个函数和/或渲染圆或管段,并在for循环中调用此函数,例如:

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

[edit1] 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);
    }
//---------------------------------------------------------------------------

视觉上最好看法线的大小为M_PI(3.1415 …),这就是上面代码的样子:

我的代码使用我的向量库,因此您只需要编写如下函数:

vector_ld(a,x,y,z); //a[]={ x,y,z }
vector_mul(a,b,c);  //a[]=b[] x c[]
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[]|

这很容易(希望我没有忘记复制…)…

上一篇:如何在python中成为一个圆圈?


下一篇:java – 选择多边形线上的随机点