平滑的希尔伯特曲线 [英] Smooth Hilbert curves
问题描述
我正在努力消除
我觉得这是一个解决的问题,但我不是在寻找正确的术语。 p>
如何使用分段立方体来实现此功能... BEZIER SPLINE 或其他什么都无关紧要。您只需要将补丁与适当的点呼叫序列连接起来,而您显然不会这样做。这里是我的示例,使用
Gray是龟图形原始Hilbert曲线,Aqua是相同点的内插三次曲线...
很好奇,所以我想实现这个功能,但花了一段时间找出并实现了 2D 希尔伯特曲线(我用过乌龟图形)以前从未使用过它们。这里 OpenGL VCL C ++ 源代码为:
$ b
// - -------------------------------------------------- ------------------------
double ha = 0.0; AnsiString hs =; // turtle graphics
List< double> PNT; // 2D点列表
// --------------------------------------- ------------------------------------
void turtle_mirror(AnsiString& s)//交换l,r
{
int i,l; char c;
for(l = s.Length(),i = 1; i <= 1; i ++)
{
c = s [i];
if(c =='l')s [i] ='r';
if(c =='r')s [i] ='l';
}
}
// ---------------------------------- -----------------------------------------
void turtle_hilbert(AnsiString& amp; amp; ; s,double& a,int n)//计算希尔伯特曲线turtle string s,n次迭代的线段大小a
{
int i,l; char c;
AnsiString s0;
if(s ==){l = 1; S = frfrf; } //假设左下角开始时的初始希尔伯特曲线变为
(i = 0; i< n; i ++)
{
s0 = s; //生成器
if(int(i& 1)== 0)//甚至传递
{
turtle_mirror(s0); s =r+ s0 +rf;
turtle_mirror(s0); S + = S0 + LFL + S0;
turtle_mirror(s0); S + = FR + S0;
}
else {//奇数传递
turtle_mirror(s0); s =r+ s0 +f;
turtle_mirror(s0); S + = S0 + FL + S0;
turtle_mirror(s0); S + = RFR + S0;
}
l = l + l + 1; //调整比例
}
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 <= 1; 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; //清除列表
xy.add(x); //添加点
xy.add(y);
for(i = 1; i <= 1; 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曲线覆盖< -1,+ 1>范围
if(hs ==)
{
turtle_hilbert(hs,ha,3); // init turtle string
turtle_compute(pnt,-0.9,-0.9,0.0,1.8 * ha,hs); //用于曲线拟合的初始点列表
}
//渲染hs,ha作为乌龟图形
glColor3f(0.4,0.4,0.4);
turtle_draw(-0.9,-0.9,0.0,1.8 * ha,hs);
//渲染pnt []作为插值立方体
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 {//这里创建调用序列(选择控制点)
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; (j = 0; j <2; 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])); (t = 0.0; t <= 1.0; t + = 0.05)//单曲线片段/片段
{
tt = t * t;
}
;
ttt = tt * t; (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
!)访问,能够像字符串算术一样添加字符串等等。 b
$ b
我也使用我的动态列表模板,所以:
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 (旧式api)完成的,因此移植应该很简单...
函数:
void turtle_hilbert(AnsiString& s,double& a,int n) ;
会生成乌龟图形字符串 欲了解更多信息,请参阅相关内容: //blackoverflow.com/a/30438865/2521214\">如何产生多点线性插值? I'm trying to smooth out the path taken by a Hilbert curve. I can define the points and connect them by straight lines, but I want a path that doesn't take the edges so sharply. I attempted to connect the curve using Bezier curves of higher and higher orders but this doesn't work, there are always 'kinks' in the path as I try to reconnect them: I feel like this a solved problem, but I'm not searching for the right terms. How about using piecewise cubics for this... Does not really matter if BEZIER SPLINE or whatever. You just need to connect the patches with proper point call sequence which you clearly did not do. Here is my example using my Interpolation cubics with proper call sequence: Gray is the turtle graphics original Hilbert curve and Aqua is the interpolated cubic curve for the same points ... Was curious so I wanted to implement this but Took me a while to figure out and implement 2D Hilbert curves (I used turtle graphics) as I never used them before. Here OpenGL VCL C++ source code for this: I do not think the curves would self-intersect and for all the I used I also use mine dynamic list template so:
for the curve points you can use any dynamic list structure you got at your disposal instead. The rendering is done by OpenGL 1.0 (old style api) so porting that should be easy ... Function: will generate turtle graphics string For more info see related: 这篇关于平滑的希尔伯特曲线的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋! s
n
- 希尔伯特曲线迭代。 a
只是缩放(线长),所以整个曲线适合单位平方 <0,1>< / code>。
//---------------------------------------------------------------------------
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
I tried they did not because the rounding is confined very near to the edges and increasing recursion will scale it too so the gap remains.AnsiString
type from VCL which is string (accessed from index 1
!) capable of string arithmetics like adding string etc ...List<double> xxx;
is the same as double xxx[];
xxx.add(5);
adds 5
to end of the list
xxx[7]
access array element (safe)
xxx.dat[7]
access array element (unsafe but fast direct access)
xxx.num
is the actual used size of the array
xxx.reset()
clears the array and set xxx.num=0
xxx.allocate(100)
preallocate space for 100
itemsvoid turtle_hilbert(AnsiString &s,double &a,int n);
s
representing the n
-th Hilbert curve iteration. The a
is just scaling (line length) so the entire curve fit into unit square <0,1>
.