Гладкие кривые Гильберта - PullRequest
0 голосов
/ 21 мая 2018

Я пытаюсь сгладить путь, пройденный по кривой Гильберта .Я могу определить точки и соединить их прямыми линиями, но мне нужен путь, который не слишком сильно срезает края.Я попытался соединить кривую, используя кривые Безье более высоких и более высоких порядков, но это не работает, на пути всегда присутствуют «перегибы», когда я пытаюсь восстановить их:

enter image description here

Мне кажется, что это решенная проблема, но я не ищу правильных терминов.

1 Ответ

0 голосов
/ 22 мая 2018

Как насчет использования кусочных кубиков для этого ... Неважно, если BEZIER SPLINE или что-то еще.Вам просто нужно соединить патчи с правильной последовательностью вызова точки, которую вы явно не сделали.Вот мой пример использования моей интерполяционной кубики с правильной последовательностью вызовов:

smooth hilbert

Серый - это оригинальная кривая Гильберта в виде черепах и Акваэто интерполированная кубическая кривая для тех же точек ...

Было любопытно, поэтому я хотел реализовать это, но мне потребовалось время, чтобы выяснить и реализовать 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 Я пытался, что они этого не делали, потому что округлениеограниченный очень близко к краям, и увеличивающаяся рекурсия также масштабирует его, так что разрыв остается.

Я использовал AnsiString тип из VCL , который является строкой (доступ по индексу 1!)способный к строковой арифметике, такой как добавление строки и т.д ...

Я также использую мой шаблон динамического списка так:
List<double> 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 (старый стильpi) так, что это должно быть легко ...

Функция:

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

сгенерирует графическую строку черепахи s, представляющую n -ую итерацию кривой Гильберта.a это просто масштабирование (длина линии), поэтому вся кривая вписывается в единицу площади <0,1>.

Для получения дополнительной информации см. Связанные:

...