用曲线连接图中的点的算法

时间:2018-08-05 02:31:04

标签: algorithm math graph

我需要开发一种算法,该算法以非线性的方式连接点,即使用 平滑曲线 下图:

insert description of image here

问题是我无法找到最佳解决方案,无论是使用Bezier CurvesPolimonial InterpolationCurve Adjustment还是其他方式。

简而言之,我需要一个公式,根据上图对点进行插值,从而在一个坐标和另一个坐标之间生成N个中间点。

在上图中,第一个坐标(c1)为(x = 1,y = 220),第二个坐标(c2)为(x = 2,y = 40)。

因此,如果我想在c1和c2之间创建4个中间坐标,则必须得到一个由4个元素组成的数组(x,y),如下所示:

[1.2, 180], [1.4, 140], [1.6, 120], [1.8, 80]

有人有什么想法吗?

1 个答案:

答案 0 :(得分:3)

我认为任何Piecewise curve interpolation都应该这样做。下面是一个 C ++ 示例:

//---------------------------------------------------------------------------
const int n=7;      // points
const int n2=n+n;
float pnt[n2]=      // points x,y ...
    {
    1.0, 220.0,
    2.0,  40.0,
    3.0,-130.0,
    4.0,-170.0,
    5.0,- 40.0,
    6.0,  90.0,
    7.0, 110.0,
    };
//---------------------------------------------------------------------------
void getpnt(float *p,float t)   // t = <0,n-1>
    {
    int i,ii;
    float *p0,*p1,*p2,*p3,a0,a1,a2,a3,d1,d2,tt,ttt;
    // handle t out of range
    if (t<=      0.0f){ p[0]=pnt[0]; p[1]=pnt[1]; return; }
    if (t>=float(n-1)){ p[0]=pnt[n2-2]; p[1]=pnt[n2-1]; return; }
    // select patch
    i=floor(t);             // start point of patch
    t-=i;                   // parameter <0,1>
    i<<=1; tt=t*t; ttt=tt*t;
    // control points
    ii=i-2; if (ii<0) ii=0; if (ii>=n2) ii=n2-2; p0=pnt+ii;
    ii=i  ; if (ii<0) ii=0; if (ii>=n2) ii=n2-2; p1=pnt+ii;
    ii=i+2; if (ii<0) ii=0; if (ii>=n2) ii=n2-2; p2=pnt+ii;
    ii=i+4; if (ii<0) ii=0; if (ii>=n2) ii=n2-2; p3=pnt+ii;
    // loop all dimensions
    for (i=0;i<2;i++)
        {
        // compute polynomial coeficients
        d1=0.5*(p2[i]-p0[i]);
        d2=0.5*(p3[i]-p1[i]);
        a0=p1[i];
        a1=d1;
        a2=(3.0*(p2[i]-p1[i]))-(2.0*d1)-d2;
        a3=d1+d2+(2.0*(-p2[i]+p1[i]));
        // compute point coordinate
        p[i]=a0+(a1*t)+(a2*tt)+(a3*ttt);
        }
    }
//---------------------------------------------------------------------------
void gl_draw()
    {
    glClearColor(1.0,1.0,1.0,1.0);
    glClear(GL_COLOR_BUFFER_BIT);
    glDisable(GL_DEPTH_TEST);
    glDisable(GL_TEXTURE_2D);

    // set 2D view 
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glScalef(1.0/5.0,1.0/500.0,1.0);
    glTranslatef(-4.0,0.0,0.0);

    // render lines
    glColor3f(1.0,0.0,0.0);
    glBegin(GL_LINE_STRIP);
    float p[2],t;
    for (t=0.0;t<=float(n-1);t+=0.1f)
        {
        getpnt(p,t);
        glVertex2fv(p);
        }
    glEnd();

    // render points
    glPointSize(4.0);
    glColor3f(0.0,0.0,1.0);
    glBegin(GL_POINTS);
    for (int i=0;i<n2;i+=2) glVertex2fv(pnt+i);
    glEnd();
    glPointSize(1.0);

    glFinish();
    SwapBuffers(hdc);
    }
//---------------------------------------------------------------------------

这里预览:

preview

您可以看到它很简单,您只需要n个控制点pnt(我从图形中提取)并进行插值... getpnt函数将计算参数t=<0,n-1>处理的曲线。在内部,它仅选择要使用的三次面片并将其计算为单次三次曲线。在gl_draw中,您可以了解如何使用它来获取介于两者之间的点。

由于您的控制点均匀地分布在x轴上:

x = <1,7>
t = <0,6>

我可以写:

x = t+1
t = x-1

所以您也可以为任何x计算任意点...

形状不完全匹配您的图形,因为选定的控制点不是正确的控制点。任何局部最小值/最大值应作为控制点,有时也更安全地使用非弯曲点。曲线的起点和终点形状暗示了隐藏的起点和终点控制点,该点未在图中显示。您可以使用任意数量的点,但是要注意,如果破坏x均匀分布,那么您将失去直接从t计算x的能力!

由于我们不知道图形是如何创建的,所以只能猜测...