Отображение значений Гильберта в 3D-точки - PullRequest
8 голосов
/ 31 января 2009

У меня есть набор значений Гильберта (длина от начала кривой Гильберта до заданной точки).

Как лучше всего преобразовать эти значения в 3D-точки? Исходная кривая Гильберта не была в 3D, так что, думаю, мне нужно было выбрать нужный мне уровень кривой Гильберта. Хотя у меня есть общая длина кривой (то есть максимальное значение в наборе).

Возможно, существует существующая реализация? Какая-нибудь библиотека, которая позволила бы мне работать с кривой / значениями Гильберта? Язык не имеет большого значения.

Ответы [ 2 ]

3 голосов
/ 01 февраля 2009

Не ответ о трехмерном преобразовании, но здесь есть хороший алгоритм и обсуждение значений Гильберта Двумерное пространственное хеширование с кривыми заполнения пространства

С MIT

4 algorithms for the n-dimensional Hilbert Space-Filling Curve

* A. R. Butz, "Alternative Algorithm for Hilbert's Space-Filling Curve",
  IEEE Trans. Comp., April, 1971, pp 424-426. [Butz 1971]

* S. W. Thomas, "hilbert.c" in the Utah Raster Toolkit circa 1993,
  http://web.mit.edu/afs/athena/contrib/urt/src/urt3.1/urt-3.1b.tar.gz

* D. Moore, Fast Hilbert Curves in C, without Recursion

* J.K.Lawder, Calculation of Mappings Between One and n-dimensional Values Using the Hilbert Space-filling Curve, [JL1_00]
1 голос
/ 23 мая 2018

Если я правильно понял ваш вопрос, у вас есть некоторое расстояние по длине кривой l от начальной точки 3D-кривой Гильберта и вы хотите получить координаты, соответствующие этой точке.

если вы предварительно сгенерируете всю трехмерную кривую Гильберта (куб единицы покрытия) в виде полилинии , то все расположенные в последовательности точки находятся на одинаковом расстоянии между предыдущей и следующей точками. Таким образом, вы можете вычислить свою точку, используя кусочно-линейную интерполяцию .

Это то, как я генерирую и визуализирую 2D / 3D кривая Гильберта in C ++ :

//---------------------------------------------------------------------------
#ifndef _Hilbert_vector_h
#define _Hilbert_vector_h
//---------------------------------------------------------------------------
#include "list.h"
//---------------------------------------------------------------------------
void Hilbert2D(List<double> &pnt,double x,double y,double z,double a,int n)
    {
    int i,j,m;
    double x0,y0,x1,y1,q;
    for (m=4*3,i=1,j=2;j<=n;j++,i+=i+1) m*=4; a/=i; // m = needed size of pnt[]
    pnt.num=0;
    // init generator
          pnt.add(x); pnt.add(y); pnt.add(z);
    y+=a; pnt.add(x); pnt.add(y); pnt.add(z);
    x+=a; pnt.add(x); pnt.add(y); pnt.add(z);
    y-=a; pnt.add(x); pnt.add(y); pnt.add(z);
    x0=x-0.5*a; // center of generator
    y0=y+0.5*a;
    // iterative subdivision
    for (j=2;j<=n;j++)
        {
        // mirror/rotate 2 qudrants
        x1=x0; y1=y0; m=pnt.num;
        for (i=m;i>=3;)
            {
            i--; z=pnt.dat[i]   ;
            i--; y=pnt.dat[i]-y0;
            i--; x=pnt.dat[i]-x0;
            q=x; x=+y; y=-q;    // z+
            pnt.dat[i+0]=(x1+x);
            pnt.dat[i+1]=(y1-y);
            pnt.dat[i+2]=(   z);
            }
        for (y1+=2.0*a,i=m;i>=3;)
            {
            i--; z=pnt.dat[i]   ;
            i--; y=pnt.dat[i]-y0;
            i--; x=pnt.dat[i]-x0;
            q=x; x=-y; y=+q;    // z-
            pnt.add(x1+x);
            pnt.add(y1+y);
            pnt.add(   z);
            }
        // mirror the rest
        x0+=a; y0+=a; m=pnt.num;
        for (i=m;i>=3;)
            {
            i--; z=pnt.dat[i]   ;
            i--; y=pnt.dat[i]-y0;
            i--; x=pnt.dat[i]-x0;
            pnt.add(x0-x);
            pnt.add(y0+y);
            pnt.add(   z);
            }
        a*=2.0;
        }
/*
        // rotations
        q=x; x=+y; y=-q;    // z+
        q=x; x=-y; y=+q;    // z-
*/
    }
//---------------------------------------------------------------------------
void Hilbert3D(List<double> &pnt,double x,double y,double z,double a,int n)
    {
    int i,j,m;
    double x0,y0,z0,x1,y1,z1,q;
    for (m=8*3,i=1,j=2;j<=n;j++,i+=i+1) m*=8; a/=i; // m = needed size of pnt[]
    pnt.num=0;
    // init generator
          pnt.add(x); pnt.add(y); pnt.add(z);
    z-=a; pnt.add(x); pnt.add(y); pnt.add(z);
    x+=a; pnt.add(x); pnt.add(y); pnt.add(z);
    z+=a; pnt.add(x); pnt.add(y); pnt.add(z);
    y+=a; pnt.add(x); pnt.add(y); pnt.add(z);
    z-=a; pnt.add(x); pnt.add(y); pnt.add(z);
    x-=a; pnt.add(x); pnt.add(y); pnt.add(z);
    z+=a; pnt.add(x); pnt.add(y); pnt.add(z);
    x0=x+0.5*a; // center of generator
    y0=y-0.5*a;
    z0=z-0.5*a;
    // iterative subdivision
    for (j=2;j<=n;j++)
        {
        // mirror/rotate qudrants
        x1=x0; y1=y0; z1=z0; m=pnt.num;
        for (i=m;i>=3;)
            {
            i--; z=pnt.dat[i]-z0;
            i--; y=pnt.dat[i]-y0;
            i--; x=pnt.dat[i]-x0;
            q=y; y=-z; z=+q;    // x-
            pnt.dat[i+0]=(x1+x);
            pnt.dat[i+1]=(y1+y);
            pnt.dat[i+2]=(z1-z);
            }
        for (z1-=2.0*a,i=m;i>=3;)
            {
            i--; z=pnt.dat[i]-z0;
            i--; y=pnt.dat[i]-y0;
            i--; x=pnt.dat[i]-x0;
            q=z; z=+x; x=-q;    // y+
            q=y; y=+z; z=-q;    // x+
            pnt.add(x1-x);
            pnt.add(y1+y);
            pnt.add(z1+z);
            }
        for (x1+=2.0*a,i=m;i>=3;)
            {
            i--; z=pnt.dat[i]-z0;
            i--; y=pnt.dat[i]-y0;
            i--; x=pnt.dat[i]-x0;
            q=y; y=+z; z=-q;    // x+
            pnt.add(x1+x);
            pnt.add(y1+y);
            pnt.add(z1+z);
            }
        for (z1+=2.0*a,i=m;i>=3;)
            {
            i--; z=pnt.dat[i]-z0;
            i--; y=pnt.dat[i]-y0;
            i--; x=pnt.dat[i]-x0;
            q=z; z=+x; x=-q;    // y+
            pnt.add(x1-x);
            pnt.add(y1-y);
            pnt.add(z1+z);
            }
        // mirror octants
        x0+=a; y0+=a; z0-=a; m=pnt.num;
        for (i=m;i>=3;)
            {
            i--; z=pnt.dat[i]-z0;
            i--; y=pnt.dat[i]-y0;
            i--; x=pnt.dat[i]-x0;
            pnt.add(x0+x);
            pnt.add(y0-y);
            pnt.add(z0+z);
            }
        a*=2.0;
        }
/*
        // rotations
        q=z; z=+x; x=-q;    // y+
        q=z; z=-x; x=+q;    // y-
        q=y; y=+z; z=-q;    // x+
        q=y; y=-z; z=+q;    // x-
        q=x; x=+y; y=-q;    // z+
        q=x; x=-y; y=+q;    // z-
*/
    }
//---------------------------------------------------------------------------
void pnt_draw2(List<double> &pnt)   // piecewise linear
    {
    int i;
    glBegin(GL_LINE_STRIP);
    for (i=0;i<pnt.num;i+=3) glVertex3dv(pnt.dat+i);
    glEnd();
    }
//---------------------------------------------------------------------------
void pnt_draw4(List<double> &pnt)   // piecewise cubic
    {
    int i,j;
    double  d1,d2,t,tt,ttt,*p0,*p1,*p2,*p3,a0[3],a1[3],a2[3],a3[3],p[3];
    glBegin(GL_LINE_STRIP);
    for (i=-3;i<pnt.num;i+=3)
        {
        j=i-3; if (j>pnt.num-3) j=pnt.num-3; if (j<0) j=0; p0=pnt.dat+j;
        j=i  ; if (j>pnt.num-3) j=pnt.num-3; if (j<0) j=0; p1=pnt.dat+j;
        j=i+3; if (j>pnt.num-3) j=pnt.num-3; if (j<0) j=0; p2=pnt.dat+j;
        j=i+6; if (j>pnt.num-3) j=pnt.num-3; if (j<0) j=0; p3=pnt.dat+j;
        for (j=0;j<3;j++)
            {
            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.1)   // single curve patch/segment
            {
            tt=t*t;
            ttt=tt*t;
            for (j=0;j<3;j++) p[j]=a0[j]+(a1[j]*t)+(a2[j]*tt)+(a3[j]*ttt);
            glVertex3dv(p);
            }
        }
    glEnd();
    }
//---------------------------------------------------------------------------
#endif
//---------------------------------------------------------------------------

Я использовал мой шаблон динамического списка так:


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 элементов

Но вместо этого вы можете использовать динамический или даже статический массив 1D , поскольку число точек в кривой Гильберта легко вычисляется (m в начале каждой функции Гильберта).

Использование просто, просто сделайте что-то вроде этого:

List<double> pnt;
Hilbert3D(pnt,-0.8,-0.8,+0.8,1.6,n); 

Где n - количество итераций, а pnt - линейный список (x,y,z) координат для каждой точки (3 числа на точку). начальная позиция и начальный размер установлены для покрытия куба с центром вокруг (0,0,0) с половинным размером 0.8 <-0.8,+0.8>.

Теперь просто вычислите единичную длину между точками, индекс ближайшей точки кривой Гильберта слева и параметр (расстояние до него), который просто линейно интерполируется. Вот C ++ пример:

if (pnt.num>=6)
    {
    int i;
    double x,y,z,t,l,dl;
    dl=sqrt(                                                    // base distance between points
            ((pnt[0]-pnt[3])*(pnt[0]-pnt[3]))
           +((pnt[1]-pnt[4])*(pnt[1]-pnt[4]))
           +((pnt[2]-pnt[5])*(pnt[2]-pnt[5]))
            );
    l=double(Form1->sb_t->Position)/double(Form1->sb_t->Max);   // <0,1>
    l*=dl*double((pnt.num/3)-1);                                // <0,Hilbert_curve_lenght>
    i=floor(l/dl); t=(l-(double(i)*dl))/dl; i*=3;               // index in pnt[] and single line segment paramerer
    x=pnt[i+0]+(pnt[i+3]-pnt[i+0])*t;                           // linear interpolation
    y=pnt[i+1]+(pnt[i+4]-pnt[i+1])*t;
    z=pnt[i+2]+(pnt[i+5]-pnt[i+2])*t;
    glColor3f(0.0,1.0,0.0); t=0.05;                             // render of marker
    glBegin(GL_LINES);
    glVertex3d(x-t,y-t,z); glVertex3d(x+t,y+t,z);
    glVertex3d(x+t,y-t,z); glVertex3d(x-t,y+t,z);
    glVertex3d(x,y-t,z-t); glVertex3d(x,y+t,z+t);
    glVertex3d(x,y-t,z+t); glVertex3d(x,y+t,z-t);
    glVertex3d(x-t,y,z-t); glVertex3d(x+t,y,z+t);
    glVertex3d(x+t,y,z-t); glVertex3d(x-t,y,z+t);
    glEnd();
    }

2D просмотр:

2D

3D-просмотр:

3D

...