【问题标题】:Smooth Hilbert curves平滑希尔伯特曲线
【发布时间】:2018-05-21 20:33:59
【问题描述】:

我正在尝试平滑Hilbert curve 所走的路径。我可以定义这些点并用直线将它们连接起来,但我想要一条边缘不会那么锐利的路径。我尝试使用更高阶和更高阶的贝塞尔曲线连接曲线,但这不起作用,当我尝试重新连接它们时,路径中总是存在“扭结”:

我觉得这是一个已解决的问题,但我没有在寻找合适的术语。

【问题讨论】:

  • 如何定义曲线中包含哪些点以及丢弃哪些点?连接所有点的平滑曲线可能会自相交。
  • @meowgoesthedog 很好的问题,但我不需要它来达到所有的点,而是接近它们,并保持流畅。
  • 这里没有使用一条贝塞尔曲线。相反,您将多条贝塞尔曲线(每条有四个控制点)拼凑在一起。您想要的是样条曲线(可能是B-spline)。
  • 您刚刚错误地连接了曲线,更高阶的曲线将无济于事,反而会产生自相交问题。为此,坚持使用 4 点立方并以分段方式执行此操作...查看我的答案(尤其是计算 p0,p1,p2,p3 点的部分)和其中的链接
  • @Hooked 我尝试在这里实现 3D 外观 Mapping Hilbert values to 3D points 是结果(也摆脱了 2D 的海龟 gfx)

标签: math graphics curve-fitting bezier


【解决方案1】:

如何使用分段三次......如果 BEZIER SPLINE 或其他什么都没有关系。你只需要用你显然没有做的正确的点调用序列来连接补丁。这是我使用 my Interpolation cubics 并具有正确调用顺序的示例:

Gray 是海龟图形原始 Hilbert 曲线,Aqua 是相同点的插值三次曲线 ...

很好奇,所以我想实现这个,但我花了一些时间来弄清楚并实现 2D 希尔伯特曲线(我使用了海龟图形),因为我以前从未使用过它们。这里是 OpenGL VCL C++ 源代码:

//---------------------------------------------------------------------------
double ha=0.0; AnsiString hs="";    // turtle graphics
List<double> pnt;                   // 2D point list
//---------------------------------------------------------------------------
void turtle_mirror(AnsiString &s)   // swap l,r
    {
    int i,l; char c;
    for (l=s.Length(),i=1;i<=l;i++)
        {
        c=s[i];
        if (c=='l') s[i]='r';
        if (c=='r') s[i]='l';
        }
    }
//---------------------------------------------------------------------------
void turtle_hilbert(AnsiString &s,double &a,int n)  // compute hilbert curve turtle string s , line segment size a for n iterations
    {
    int i,l; char c;
    AnsiString s0;
    if (s=="") { l=1; s="frfrf"; }  // init hilbert curve assuming starting bottom left turned up
    for (i=0;i<n;i++)
        {
        s0=s;                   // generator
        if (int(i&1)==0)        // even pass
            {
            turtle_mirror(s0); s ="r"+s0+"rf";
            turtle_mirror(s0); s+=s0+"lfl"+s0;
            turtle_mirror(s0); s+="fr"+s0;
            }
        else{                   // odd pass
            turtle_mirror(s0); s ="r"+s0+"f";
            turtle_mirror(s0); s+=s0+"fl"+s0;
            turtle_mirror(s0); s+="rfr"+s0;
            }
        l=l+l+1;                // adjust scale
        }
    a=1.0/double(l);
    }
//---------------------------------------------------------------------------
void turtle_draw(double x,double y,double dx,double dy,const AnsiString &s)
    {
    int i,l; char c;
    double q;
    l=s.Length();
    glBegin(GL_LINE_STRIP);
    glVertex2d(x,y);
    for (i=1;i<=l;i++)
        {
        c=s[i];
        if (c=='f') { x+=dx; y+=dy; glVertex2d(x,y); }
        if (c=='l') { q=dx; dx=-dy; dy= q; }
        if (c=='r') { q=dx; dx= dy; dy=-q; }
        }
    glEnd();
    }
//---------------------------------------------------------------------------
void turtle_compute(List<double> &xy,double x,double y,double dx,double dy,const AnsiString &s)
    {
    int i,l; char c;
    double q;
    l=s.Length();
    xy.num=0;   // clear list
    xy.add(x);  // add point
    xy.add(y);
    for (i=1;i<=l;i++)
        {
        c=s[i];
        if (c=='f') { x+=dx; y+=dy; xy.add(x); xy.add(y); }
        if (c=='l') { q=dx; dx=-dy; dy= q; }
        if (c=='r') { q=dx; dx= dy; dy=-q; }
        }
    glEnd();
    }
//---------------------------------------------------------------------------
void gl_draw()
    {
    //_redraw=false;
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    GLint id;
    glUseProgram(prog_id);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glMatrixMode(GL_TEXTURE);
    glLoadIdentity();
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glDisable(GL_DEPTH_TEST);
    glDisable(GL_TEXTURE_2D);

    // hilber curve covering <-1,+1> range
    if (hs=="")
        {
        turtle_hilbert(hs,ha,3);                        // init turtle string
        turtle_compute(pnt,-0.9,-0.9,0.0,1.8*ha,hs);    // init point list for curve fit
        }
    // render hs,ha as turtle graphics
    glColor3f(0.4,0.4,0.4);
    turtle_draw(-0.9,-0.9,0.0,1.8*ha,hs);
    // render pnt[] as interpolation cubics
    int i,j;
    double  d1,d2,t,tt,ttt,*p0,*p1,*p2,*p3,a0[2],a1[2],a2[2],a3[2],p[2];
    glColor3f(0.2,0.7,1.0);
    glBegin(GL_LINE_STRIP);
    for (i=-2;i<pnt.num;i+=2) // process whole curve
        { // here create the call sequence (select control points)
        j=i-2; if (j<0) j=0; if (j>=pnt.num) j=pnt.num-2; p0=pnt.dat+j;
        j=i  ; if (j<0) j=0; if (j>=pnt.num) j=pnt.num-2; p1=pnt.dat+j;
        j=i+2; if (j<0) j=0; if (j>=pnt.num) j=pnt.num-2; p2=pnt.dat+j;
        j=i+4; if (j<0) j=0; if (j>=pnt.num) j=pnt.num-2; p3=pnt.dat+j;
        for (j=0;j<2;j++) // compute curve parameters
            {
            d1=0.5*(p2[j]-p0[j]);
            d2=0.5*(p3[j]-p1[j]);
            a0[j]=p1[j];
            a1[j]=d1;
            a2[j]=(3.0*(p2[j]-p1[j]))-(2.0*d1)-d2;
            a3[j]=d1+d2+(2.0*(-p2[j]+p1[j]));
            }
        for (t=0.0;t<=1.0;t+=0.05)  // single curve patch/segment
            {
            tt=t*t;
            ttt=tt*t;
            for (j=0;j<2;j++) p[j]=a0[j]+(a1[j]*t)+(a2[j]*tt)+(a3[j]*ttt);
            glVertex2dv(p);
            }
        }
    glEnd();
    glFlush();
    SwapBuffers(hdc);
    }
//---------------------------------------------------------------------------

我不认为曲线会自相交,对于我尝试过的所有n,它们都不会自相交,因为舍入非常靠近边缘,并且增加递归也会对其进行缩放,因此间隙仍然存在。

我使用了来自 VCLAnsiString 类型,它是字符串(从索引 1 访问!)能够进行字符串运算,例如添加字符串等...

我也使用我的动态列表模板,所以:
List&lt;double&gt; xxx;double xxx[]; 相同
xxx.add(5);5 添加到列表末尾
xxx[7]访问数组元素(安全)
xxx.dat[7]访问数组元素(不安全但快速直接访问)
xxx.num是数组实际使用的大小
xxx.reset() 清除数组并设置xxx.num=0
xxx.allocate(100)100 项目预分配空间

对于曲线点,您可以使用您可以随意使用的任何动态列表结构。

渲染是由 OpenGL 1.0(旧式 api)完成的,所以移植应该很容易......

功能:

void turtle_hilbert(AnsiString &s,double &a,int n);

将生成乌龟图形字符串s,代表n-th Hilbert 曲线迭代。 a 只是缩放(线长),因此整个曲线适合单位正方形 &lt;0,1&gt;

欲了解更多信息,请参阅相关:

【讨论】:

    猜你喜欢
    • 2023-04-09
    • 2011-10-16
    • 2017-08-31
    • 1970-01-01
    • 2018-07-17
    • 2021-03-16
    • 1970-01-01
    • 1970-01-01
    • 2018-08-16
    相关资源
    最近更新 更多