非常有趣的问题。我想把它实现到
我的4D渲染引擎中,因为我很好奇它会是什么样子,但我太懒了,也没有能力从数学上解决ND超越问题。
相反,我提出了不同的解决方案。这不是一个
斐波那契栅格 !!! 相反,我将
超球或n-球的参数方程扩展成
超螺旋,然后只需调整螺旋参数,使点更或多或少地等距分布。
我知道这听起来很糟糕,但并不难,而且结果看起来对我来说是正确的(最终解决了一些愚蠢的拼写错误/复制粘贴错误)
主要思路是使用n维参数方程计算超球的表面点,从角度和半径计算。这里是实现:
请参见
[编辑2]。现在问题归结为两个主要问题:
compute number of screws
so if we want that our points are equidistant so they must lye on the spiral path in equidistances (see bullet #2) but also the screws itself should have the same distance between each other. For that we can exploit geometrical properties of the hypersphere. Let start with 2D:
![2D spiral](https://istack.dev59.com/2ZXpR.webp)
so simply screws = r/d
. The number of points can be also inferred as points = area/d^2 = PI*r^2/d^2
.
so we can simply write 2D spiral as:
t = <0.0,1.0>
a = 2.0*M_PI*screws*t;
x = r*t*cos(a);
y = r*t*sin(a);
To be more simple we can assume r=1.0
so d=d/r
(and just scale the points later). Then the expansions (each dimension just adds angle parameter) look like this:
2D:
screws=1.0/d
points=M_PI/(d*d)
a = 2.0*M_PI*t*screws
x = t*cos(a)
y = t*sin(a)
3D:
screws=M_PI/d
points=4.0*M_PI/(d*d)
a= M_PI*t
b=2.0*M_PI*t*screws
x=cos(a)
y=sin(a)*cos(b)
z=sin(a)*sin(b)
4D:
screws = M_PI/d;
points = 3.0*M_PI*M_PI*M_PI/(4.0*d*d*d);
a= M_PI*t;
b= M_PI*t*screws;
c=2.0*M_PI*t*screws*screws;
x=cos(a) ;
y=sin(a)*cos(b) ;
z=sin(a)*sin(b)*cos(c);
w=sin(a)*sin(b)*sin(c);
Now beware points for 4D are just my assumption. I empirically found out that they relate to constant/d^3
but not exactly. The screws are different for each angle. Mine assumption is that there is no other scale than screws^i
but it might need some constant tweaking (did not do analysis of the resulting point-cloud as the result look ok to me)
Now we can generate any point on spiral from single parameter t=<0.0,1.0>
.
Note if you reverse the equation so d=f(points)
you can have points as input value but beware its just approximate number of points not exact !!!
generate step on spirals so points are equidistant
This is the part I skip the algebraic mess and use fitting instead. I simply binary search delta t
so the resulting point is d
distant to previous point. So simply generate point t=0
and then binary search t
near estimated position until is d
distant to the start point. Then repeat this until t<=1.0
...
You can use binary search or what ever. I know its not as fast as O(1)
algebraic approach but no need to derive the stuff for each dimension... Looks 10 iterations are enough for fitting so its not that slow either.
这是我使用C++/GL/VCL实现的4D引擎:
void ND_mesh::set_HyperSpiral(int N,double r,double d)
{
int i,j;
reset(N);
d/=r;
double dd=d*d;
if (n==2)
{
int i0,i;
double a,da,t,dt,dtt;
double x,y,x0,y0;
double screws=1.0/d;
double points=M_PI/(d*d);
dbg=points;
da=2.0*M_PI*screws;
x0=0.0; pnt.add(x0);
y0=0.0; pnt.add(y0);
dt=0.1*(1.0/points);
for (t=0.0,i0=0,i=1;;i0=i,i++)
{
for (dtt=dt,j=0;j<10;j++,dtt*=0.5)
{
t+=dtt;
a=da*t;
x=(t*cos(a))-x0; x*=x;
y=(t*sin(a))-y0; y*=y;
if ((!j)&&(x+y<dd)){ j--; t-=dtt; dtt*=4.0; continue; }
if (x+y>dd) t-=dtt;
}
if (t>1.0) break;
a=da*t;
x0=t*cos(a); pnt.add(x0);
y0=t*sin(a); pnt.add(y0);
as2(i0,i);
}
}
if (n==3)
{
int i0,i;
double a,b,da,db,t,dt,dtt;
double x,y,z,x0,y0,z0;
double screws=M_PI/d;
double points=4.0*M_PI/(d*d);
dbg=points;
da= M_PI;
db=2.0*M_PI*screws;
x0=1.0; pnt.add(x0);
y0=0.0; pnt.add(y0);
z0=0.0; pnt.add(z0);
dt=0.1*(1.0/points);
for (t=0.0,i0=0,i=1;;i0=i,i++)
{
for (dtt=dt,j=0;j<10;j++,dtt*=0.5)
{
t+=dtt;
a=da*t;
b=db*t;
x=cos(a) -x0; x*=x;
y=sin(a)*cos(b)-y0; y*=y;
z=sin(a)*sin(b)-z0; z*=z;
if ((!j)&&(x+y+z<dd)){ j--; t-=dtt; dtt*=4.0; continue; }
if (x+y+z>dd) t-=dtt;
}
if (t>1.0) break;
a=da*t;
b=db*t;
x0=cos(a) ; pnt.add(x0);
y0=sin(a)*cos(b); pnt.add(y0);
z0=sin(a)*sin(b); pnt.add(z0);
as2(i0,i);
}
}
if (n==4)
{
int i0,i;
double a,b,c,da,db,dc,t,dt,dtt;
double x,y,z,w,x0,y0,z0,w0;
double screws = M_PI/d;
double points=3.0*M_PI*M_PI*M_PI/(4.0*d*d*d);
dbg=points;
da= M_PI;
db= M_PI*screws;
dc=2.0*M_PI*screws*screws;
x0=1.0; pnt.add(x0);
y0=0.0; pnt.add(y0);
z0=0.0; pnt.add(z0);
w0=0.0; pnt.add(w0);
dt=0.1*(1.0/points);
for (t=0.0,i0=0,i=1;;i0=i,i++)
{
for (dtt=dt,j=0;j<10;j++,dtt*=0.5)
{
t+=dtt;
a=da*t;
b=db*t;
c=dc*t;
x=cos(a) -x0; x*=x;
y=sin(a)*cos(b) -y0; y*=y;
z=sin(a)*sin(b)*cos(c)-z0; z*=z;
w=sin(a)*sin(b)*sin(c)-w0; w*=w;
if ((!j)&&(x+y+z+w<dd)){ j--; t-=dtt; dtt*=4.0; continue; }
if (x+y+z+w>dd) t-=dtt;
} dt=dtt;
if (t>1.0) break;
a=da*t;
b=db*t;
c=dc*t;
x0=cos(a) ; pnt.add(x0);
y0=sin(a)*cos(b) ; pnt.add(y0);
z0=sin(a)*sin(b)*cos(c); pnt.add(z0);
w0=sin(a)*sin(b)*sin(c); pnt.add(w0);
as2(i0,i);
}
}
for (i=0;i<pnt.num;i++) pnt.dat[i]*=r;
for (i=0;i<s1.num;i++) s1.dat[i]*=n;
for (i=0;i<s2.num;i++) s2.dat[i]*=n;
for (i=0;i<s3.num;i++) s3.dat[i]*=n;
for (i=0;i<s4.num;i++) s4.dat[i]*=n;
}
在这里,“n=N”表示设置维度,“r”表示半径,“d”表示点之间的期望距离。我使用了很多未在此处声明的内容,但重要的是,“pnt []”列出了对象上的点列表,“as2(i0,i1)”将从索引“i0,i1”处的点添加到网格中的线。
以下是一些屏幕截图...
3D透视图:
![3D perspective](https://istack.dev59.com/otUes.webp)
4D视角:
![4D perspective](https://istack.dev59.com/wMh6p.webp)
超平面w=0.0
的4D截面:
![4D cross-section w=0.0](https://istack.dev59.com/urcVz.gif)
并且同样具有更多的点和更大的半径:
![4D cross-section w=0.0 HQ](https://istack.dev59.com/7JcZ4.gif)
形状随着旋转而变化,其中包括其动画...
[编辑1] 更多代码/信息
这是我的引擎网格类的样子:
#ifndef _ND_mesh_h
#define _ND_mesh_h
#include "list.h"
#include "nd_reper.h"
enum _render_enum
{
_render_Wireframe=0,
_render_Polygon,
_render_enums
};
const AnsiString _render_txt[]=
{
"Wireframe",
"Polygon"
};
enum _view_enum
{
_view_Orthographic=0,
_view_Perspective,
_view_CrossSection,
_view_enums
};
const AnsiString _view_txt[]=
{
"Orthographic",
"Perspective",
"Cross section"
};
struct dim_reduction
{
int view;
double coordinate;
double focal_length;
dim_reduction() { view=_view_Perspective; coordinate=-3.5; focal_length=2.0; }
dim_reduction(dim_reduction& a) { *this=a; }
~dim_reduction() {}
dim_reduction* operator = (const dim_reduction *a) { *this=*a; return this; }
};
class ND_mesh
{
public:
int n;
List<double> pnt;
List<int> s1;
List<int> s2;
List<int> s3;
List<int> s4;
DWORD col;
int dbg;
ND_mesh() { reset(0); }
ND_mesh(ND_mesh& a) { *this=a; }
~ND_mesh() {}
ND_mesh* operator = (const ND_mesh *a) { *this=*a; return this; }
void as1(int a0) { s1.add(a0); }
void as2(int a0,int a1) { s2.add(a0); s2.add(a1); }
void as3(int a0,int a1,int a2) { s3.add(a0); s3.add(a1); s3.add(a2); }
void as4(int a0,int a1,int a2,int a3){ s4.add(a0); s4.add(a1); s4.add(a2); s4.add(a3); }
void reset(int N);
void set_HyperTetrahedron(int N,double a);
void set_HyperCube (int N,double a);
void set_HyperSphere (int N,double r,int points);
void set_HyperSpiral (int N,double r,double d);
void glDraw(ND_reper &rep,dim_reduction *cfg,int render);
};
#define _cube(a0,a1,a2,a3,a4,a5,a6,a7) { as4(a1,a2,a4,a7); as4(a0,a1,a2,a4); as4(a2,a4,a6,a7); as4(a1,a2,a3,a7); as4(a1,a4,a5,a7); }
void ND_mesh::reset(int N)
{
dbg=0;
if (N>=0) n=N;
pnt.num=0;
s1.num=0;
s2.num=0;
s3.num=0;
s4.num=0;
col=0x00AAAAAA;
}
void ND_mesh::set_HyperSpiral(int N,double r,double d)
{
int i,j;
reset(N);
d/=r;
double dd=d*d;
if (n==2)
{
int i0,i;
double a,da,t,dt,dtt;
double x,y,x0,y0;
double screws=1.0/d;
double points=M_PI/(d*d);
dbg=points;
da=2.0*M_PI*screws;
x0=0.0; pnt.add(x0);
y0=0.0; pnt.add(y0);
dt=0.1*(1.0/points);
for (t=0.0,i0=0,i=1;;i0=i,i++)
{
for (dtt=dt,j=0;j<10;j++,dtt*=0.5)
{
t+=dtt;
a=da*t;
x=(t*cos(a))-x0; x*=x;
y=(t*sin(a))-y0; y*=y;
if ((!j)&&(x+y<dd)){ j--; t-=dtt; dtt*=4.0; continue; }
if (x+y>dd) t-=dtt;
}
if (t>1.0) break;
a=da*t;
x0=t*cos(a); pnt.add(x0);
y0=t*sin(a); pnt.add(y0);
as2(i0,i);
}
}
if (n==3)
{
int i0,i;
double a,b,da,db,t,dt,dtt;
double x,y,z,x0,y0,z0;
double screws=M_PI/d;
double points=4.0*M_PI/(d*d);
dbg=points;
da= M_PI;
db=2.0*M_PI*screws;
x0=1.0; pnt.add(x0);
y0=0.0; pnt.add(y0);
z0=0.0; pnt.add(z0);
dt=0.1*(1.0/points);
for (t=0.0,i0=0,i=1;;i0=i,i++)
{
for (dtt=dt,j=0;j<10;j++,dtt*=0.5)
{
t+=dtt;
a=da*t;
b=db*t;
x=cos(a) -x0; x*=x;
y=sin(a)*cos(b)-y0; y*=y;
z=sin(a)*sin(b)-z0; z*=z;
if ((!j)&&(x+y+z<dd)){ j--; t-=dtt; dtt*=4.0; continue; }
if (x+y+z>dd) t-=dtt;
}
if (t>1.0) break;
a=da*t;
b=db*t;
x0=cos(a) ; pnt.add(x0);
y0=sin(a)*cos(b); pnt.add(y0);
z0=sin(a)*sin(b); pnt.add(z0);
as2(i0,i);
}
}
if (n==4)
{
int i0,i;
double a,b,c,da,db,dc,t,dt,dtt;
double x,y,z,w,x0,y0,z0,w0;
double screws = M_PI/d;
double points=3.0*M_PI*M_PI*M_PI/(4.0*d*d*d);
dbg=points;
da= M_PI;
db= M_PI*screws;
dc=2.0*M_PI*screws*screws;
x0=1.0; pnt.add(x0);
y0=0.0; pnt.add(y0);
z0=0.0; pnt.add(z0);
w0=0.0; pnt.add(w0);
dt=0.1*(1.0/points);
for (t=0.0,i0=0,i=1;;i0=i,i++)
{
for (dtt=dt,j=0;j<10;j++,dtt*=0.5)
{
t+=dtt;
a=da*t;
b=db*t;
c=dc*t;
x=cos(a) -x0; x*=x;
y=sin(a)*cos(b) -y0; y*=y;
z=sin(a)*sin(b)*cos(c)-z0; z*=z;
w=sin(a)*sin(b)*sin(c)-w0; w*=w;
if ((!j)&&(x+y+z+w<dd)){ j--; t-=dtt; dtt*=4.0; continue; }
if (x+y+z+w>dd) t-=dtt;
} dt=dtt;
if (t>1.0) break;
a=da*t;
b=db*t;
c=dc*t;
x0=cos(a) ; pnt.add(x0);
y0=sin(a)*cos(b) ; pnt.add(y0);
z0=sin(a)*sin(b)*cos(c); pnt.add(z0);
w0=sin(a)*sin(b)*sin(c); pnt.add(w0);
as2(i0,i);
}
}
for (i=0;i<pnt.num;i++) pnt.dat[i]*=r;
for (i=0;i<s1.num;i++) s1.dat[i]*=n;
for (i=0;i<s2.num;i++) s2.dat[i]*=n;
for (i=0;i<s3.num;i++) s3.dat[i]*=n;
for (i=0;i<s4.num;i++) s4.dat[i]*=n;
}
void ND_mesh::glDraw(ND_reper &rep,dim_reduction *cfg,int render)
{
int N,i,j,i0,i1,i2,i3;
const int n0=0,n1=n,n2=n+n,n3=n2+n,n4=n3+n;
double a,b,w,F,*p0,*p1,*p2,*p3,_zero=1e-6;
vector<4> v;
List<double> tmp,t0;
List<double> S1,S2,S3,S4;
#define _swap(aa,bb) { double *p=aa.dat; aa.dat=bb.dat; bb.dat=p; int q=aa.siz; aa.siz=bb.siz; bb.siz=q; q=aa.num; aa.num=bb.num; bb.num=q; }
tmp.allocate(pnt.num); tmp.num=pnt.num;
for (i=0;i<pnt.num;i+=n)
{
v.ld(0.0,0.0,0.0,0.0);
for (j=0;j<n;j++) v.a[j]=pnt.dat[i+j];
rep.l2g(v,v);
for (j=0;j<n;j++) tmp.dat[i+j]=v.a[j];
}
S1.allocate(s1.num*n); S1.num=0; for (i=0;i<s1.num;i++) for (j=0;j<n;j++) S1.add(tmp.dat[s1.dat[i]+j]);
S2.allocate(s2.num*n); S2.num=0; for (i=0;i<s2.num;i++) for (j=0;j<n;j++) S2.add(tmp.dat[s2.dat[i]+j]);
S3.allocate(s3.num*n); S3.num=0; for (i=0;i<s3.num;i++) for (j=0;j<n;j++) S3.add(tmp.dat[s3.dat[i]+j]);
S4.allocate(s4.num*n); S4.num=0; for (i=0;i<s4.num;i++) for (j=0;j<n;j++) S4.add(tmp.dat[s4.dat[i]+j]);
for (N=n;N>2;)
{
N--;
if (cfg[N].view==_view_Orthographic){}
if (cfg[N].view==_view_Perspective)
{
w=cfg[N].coordinate;
F=cfg[N].focal_length;
for (i=0;i<S1.num;i+=n)
{
a=S1.dat[i+N]-w;
if (a>=F) a=F/a; else a=0.0;
for (j=0;j<n;j++) S1.dat[i+j]*=a;
}
for (i=0;i<S2.num;i+=n)
{
a=S2.dat[i+N]-w;
if (a>=F) a=F/a; else a=0.0;
for (j=0;j<n;j++) S2.dat[i+j]*=a;
}
for (i=0;i<S3.num;i+=n)
{
a=S3.dat[i+N]-w;
if (a>=F) a=F/a; else a=0.0;
for (j=0;j<n;j++) S3.dat[i+j]*=a;
}
for (i=0;i<S4.num;i+=n)
{
a=S4.dat[i+N]-w;
if (a>=F) a=F/a; else a=0.0;
for (j=0;j<n;j++) S4.dat[i+j]*=a;
}
}
if (cfg[N].view==_view_CrossSection)
{
w=cfg[N].coordinate;
_swap(S1,tmp); for (S1.num=0,i=0;i<tmp.num;i+=n1)
{
p0=tmp.dat+i+n0;
if (fabs(p0[N]-w)<=_zero)
{
for (j=0;j<n;j++) S1.add(p0[j]);
}
}
_swap(S2,tmp); for (S2.num=0,i=0;i<tmp.num;i+=n2)
{
p0=tmp.dat+i+n0; a=p0[N]; b=p0[N];
p1=tmp.dat+i+n1; if (a>p1[N]) a=p1[N]; if (b<p1[N]) b=p1[N];
if (fabs(a-w)+fabs(b-w)<=_zero)
{
for (j=0;j<n;j++) S2.add(p0[j]);
for (j=0;j<n;j++) S2.add(p1[j]);
continue;
}
if ((a<=w)&&(b>=w))
{
a=(w-p0[N])/(p1[N]-p0[N]);
for (j=0;j<n;j++) S1.add(p0[j]+a*(p1[j]-p0[j]));
}
}
_swap(S3,tmp); for (S3.num=0,i=0;i<tmp.num;i+=n3)
{
p0=tmp.dat+i+n0; a=p0[N]; b=p0[N];
p1=tmp.dat+i+n1; if (a>p1[N]) a=p1[N]; if (b<p1[N]) b=p1[N];
p2=tmp.dat+i+n2; if (a>p2[N]) a=p2[N]; if (b<p2[N]) b=p2[N];
if (fabs(a-w)+fabs(b-w)<=_zero)
{
for (j=0;j<n;j++) S3.add(p0[j]);
for (j=0;j<n;j++) S3.add(p1[j]);
for (j=0;j<n;j++) S3.add(p2[j]);
continue;
}
if ((a<=w)&&(b>=w))
{
t0.num=0;
i0=0; if (p0[N]<w-_zero) i0=1; if (p0[N]>w+_zero) i0=2;
i1=0; if (p1[N]<w-_zero) i1=1; if (p1[N]>w+_zero) i1=2;
i2=0; if (p2[N]<w-_zero) i2=1; if (p2[N]>w+_zero) i2=2;
if (i0+i1==3){ a=(w-p0[N])/(p1[N]-p0[N]); for (j=0;j<n;j++) t0.add(p0[j]+a*(p1[j]-p0[j])); }
if (i1+i2==3){ a=(w-p1[N])/(p2[N]-p1[N]); for (j=0;j<n;j++) t0.add(p1[j]+a*(p2[j]-p1[j])); }
if (i2+i0==3){ a=(w-p2[N])/(p0[N]-p2[N]); for (j=0;j<n;j++) t0.add(p2[j]+a*(p0[j]-p2[j])); }
if (!i0) for (j=0;j<n;j++) t0.add(p0[j]);
if (!i1) for (j=0;j<n;j++) t0.add(p1[j]);
if (!i2) for (j=0;j<n;j++) t0.add(p2[j]);
if (t0.num==n1) for (j=0;j<t0.num;j++) S1.add(t0.dat[j]);
if (t0.num==n2) for (j=0;j<t0.num;j++) S2.add(t0.dat[j]);
if (t0.num==n3) for (j=0;j<t0.num;j++) S3.add(t0.dat[j]);
}
}
_swap(S4,tmp); for (S4.num=0,i=0;i<tmp.num;i+=n4)
{
p0=tmp.dat+i+n0; a=p0[N]; b=p0[N];
p1=tmp.dat+i+n1; if (a>p1[N]) a=p1[N]; if (b<p1[N]) b=p1[N];
p2=tmp.dat+i+n2; if (a>p2[N]) a=p2[N]; if (b<p2[N]) b=p2[N];
p3=tmp.dat+i+n3; if (a>p3[N]) a=p3[N]; if (b<p3[N]) b=p3[N];
if (fabs(a-w)+fabs(b-w)<=_zero)
{
for (j=0;j<n;j++) S4.add(p0[j]);
for (j=0;j<n;j++) S4.add(p1[j]);
for (j=0;j<n;j++) S4.add(p2[j]);
for (j=0;j<n;j++) S4.add(p3[j]);
continue;
}
if ((a<=w)&&(b>=w))
{
t0.num=0;
i0=0; if (p0[N]<w-_zero) i0=1; if (p0[N]>w+_zero) i0=2;
i1=0; if (p1[N]<w-_zero) i1=1; if (p1[N]>w+_zero) i1=2;
i2=0; if (p2[N]<w-_zero) i2=1; if (p2[N]>w+_zero) i2=2;
i3=0; if (p3[N]<w-_zero) i3=1; if (p3[N]>w+_zero) i3=2;
if (i0+i1==3){ a=(w-p0[N])/(p1[N]-p0[N]); for (j=0;j<n;j++) t0.add(p0[j]+a*(p1[j]-p0[j])); }
if (i1+i2==3){ a=(w-p1[N])/(p2[N]-p1[N]); for (j=0;j<n;j++) t0.add(p1[j]+a*(p2[j]-p1[j])); }
if (i2+i0==3){ a=(w-p2[N])/(p0[N]-p2[N]); for (j=0;j<n;j++) t0.add(p2[j]+a*(p0[j]-p2[j])); }
if (i0+i3==3){ a=(w-p0[N])/(p3[N]-p0[N]); for (j=0;j<n;j++) t0.add(p0[j]+a*(p3[j]-p0[j])); }
if (i1+i3==3){ a=(w-p1[N])/(p3[N]-p1[N]); for (j=0;j<n;j++) t0.add(p1[j]+a*(p3[j]-p1[j])); }
if (i2+i3==3){ a=(w-p2[N])/(p3[N]-p2[N]); for (j=0;j<n;j++) t0.add(p2[j]+a*(p3[j]-p2[j])); }
if (!i0) for (j=0;j<n;j++) t0.add(p0[j]);
if (!i1) for (j=0;j<n;j++) t0.add(p1[j]);
if (!i2) for (j=0;j<n;j++) t0.add(p2[j]);
if (!i3) for (j=0;j<n;j++) t0.add(p3[j]);
if (t0.num==n1) for (j=0;j<t0.num;j++) S1.add(t0.dat[j]);
if (t0.num==n2) for (j=0;j<t0.num;j++) S2.add(t0.dat[j]);
if (t0.num==n3) for (j=0;j<t0.num;j++) S3.add(t0.dat[j]);
if (t0.num==n4) for (j=0;j<t0.num;j++) S4.add(t0.dat[j]);
}
}
}
}
glColor4ubv((BYTE*)(&col));
if (render==_render_Wireframe)
{
for (i=0;i<S2.num;i++) S1.add(S2.dat[i]);
for (i=0;i<S3.num;i++) S1.add(S3.dat[i]);
for (i=0;i<S4.num;i++) S1.add(S4.dat[i]);
glPointSize(5.0);
glBegin(GL_POINTS);
glNormal3d(0.0,0.0,1.0);
if (n==2) for (i=0;i<S1.num;i+=n1) glVertex2dv(S1.dat+i);
if (n>=3) for (i=0;i<S1.num;i+=n1) glVertex3dv(S1.dat+i);
glEnd();
glPointSize(1.0);
glBegin(GL_LINES);
glNormal3d(0.0,0.0,1.0);
if (n==2)
{
for (i=0;i<S2.num;i+=n1) glVertex2dv(S2.dat+i);
for (i=0;i<S3.num;i+=n3)
{
glVertex2dv(S3.dat+i+n0); glVertex2dv(S3.dat+i+n1);
glVertex2dv(S3.dat+i+n1); glVertex2dv(S3.dat+i+n2);
glVertex2dv(S3.dat+i+n2); glVertex2dv(S3.dat+i+n0);
}
for (i=0;i<S4.num;i+=n4)
{
glVertex2dv(S4.dat+i+n0); glVertex2dv(S4.dat+i+n1);
glVertex2dv(S4.dat+i+n1); glVertex2dv(S4.dat+i+n2);
glVertex2dv(S4.dat+i+n2); glVertex2dv(S4.dat+i+n0);
glVertex2dv(S4.dat+i+n0); glVertex2dv(S4.dat+i+n3);
glVertex2dv(S4.dat+i+n1); glVertex2dv(S4.dat+i+n3);
glVertex2dv(S4.dat+i+n2); glVertex2dv(S4.dat+i+n3);
}
}
if (n>=3)
{
for (i=0;i<S2.num;i+=n1) glVertex3dv(S2.dat+i);
for (i=0;i<S3.num;i+=n3)
{
glVertex3dv(S3.dat+i+n0); glVertex3dv(S3.dat+i+n1);
glVertex3dv(S3.dat+i+n1); glVertex3dv(S3.dat+i+n2);
glVertex3dv(S3.dat+i+n2); glVertex3dv(S3.dat+i+n0);
}
for (i=0;i<S4.num;i+=n4)
{
glVertex3dv(S4.dat+i+n0); glVertex3dv(S4.dat+i+n1);
glVertex3dv(S4.dat+i+n1); glVertex3dv(S4.dat+i+n2);
glVertex3dv(S4.dat+i+n2); glVertex3dv(S4.dat+i+n0);
glVertex3dv(S4.dat+i+n0); glVertex3dv(S4.dat+i+n3);
glVertex3dv(S4.dat+i+n1); glVertex3dv(S4.dat+i+n3);
glVertex3dv(S4.dat+i+n2); glVertex3dv(S4.dat+i+n3);
}
}
glEnd();
}
if (render==_render_Polygon)
{
double nor[3],a[3],b[3],q;
#define _triangle2(ss,p0,p1,p2) \
{ \
glVertex2dv(ss.dat+i+p0); \
glVertex2dv(ss.dat+i+p1); \
glVertex2dv(ss.dat+i+p2); \
}
#define _triangle3(ss,p0,p1,p2) \
{ \
for(j=0;(j<3)&&(j<n);j++) \
{ \
a[j]=ss.dat[i+p1+j]-ss.dat[i+p0+j]; \
b[j]=ss.dat[i+p2+j]-ss.dat[i+p1+j]; \
} \
for(;j<3;j++){ a[j]=0.0; b[j]=0.0; } \
nor[0]=(a[1]*b[2])-(a[2]*b[1]); \
nor[1]=(a[2]*b[0])-(a[0]*b[2]); \
nor[2]=(a[0]*b[1])-(a[1]*b[0]); \
q=sqrt((nor[0]*nor[0])+(nor[1]*nor[1])+(nor[2]*nor[2])); \
if (q>1e-10) q=1.0/q; else q-0.0; \
for (j=0;j<3;j++) nor[j]*=q; \
glNormal3dv(nor); \
glVertex3dv(ss.dat+i+p0); \
glVertex3dv(ss.dat+i+p1); \
glVertex3dv(ss.dat+i+p2); \
}
#define _triangle3b(ss,p0,p1,p2) \
{ \
glNormal3dv(nor3.dat+(i/n)); \
glVertex3dv(ss.dat+i+p0); \
glVertex3dv(ss.dat+i+p1); \
glVertex3dv(ss.dat+i+p2); \
}
glBegin(GL_TRIANGLES);
if (n==2)
{
glNormal3d(0.0,0.0,1.0);
for (i=0;i<S3.num;i+=n3) _triangle2(S3,n0,n1,n2);
for (i=0;i<S4.num;i+=n4)
{
_triangle2(S4,n0,n1,n2);
_triangle2(S4,n3,n0,n1);
_triangle2(S4,n3,n1,n2);
_triangle2(S4,n3,n2,n0);
}
}
if (n>=3)
{
for (i=0;i<S3.num;i+=n3) _triangle3 (S3,n0,n1,n2);
for (i=0;i<S4.num;i+=n4)
{
_triangle3(S4,n0,n1,n2);
_triangle3(S4,n3,n0,n1);
_triangle3(S4,n3,n1,n2);
_triangle3(S4,n3,n2,n0);
}
glNormal3d(0.0,0.0,1.0);
}
glEnd();
#undef _triangle2
#undef _triangle3
}
#undef _swap
}
#undef _cube
#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
个项目的空间
因此,您需要将其移植到任何可用的列表中(例如
std:vector<>
)。我还使用了5x5转换矩阵,其中:
void ND_reper::g2l (vector<4> &l,vector<4> &g); // global xyzw -> local xyzw
void ND_reper::l2g (vector<4> &g,vector<4> &l); // global xyzw <- local xyzw
将点转换为全局或本地坐标(通过将直接或反向矩阵乘以点)。由于其仅在渲染中使用一次,因此您可以忽略它并复制点(无旋转)... 在同一标题中还有一些常量:
const double pi = M_PI;
const double pi2 =2.0*M_PI;
const double pipol=0.5*M_PI;
const double deg=M_PI/180.0;
const double rad=180.0/M_PI;
我还整合了向量和矩阵数学模板到变换矩阵头文件中,因此vector<n>
是n维向量,matrix<n>
是n*n
的方阵,但仅用于渲染,因此您可以忽略它。如果您感兴趣,这里有一些链接,从中得出了所有这些内容:
枚举和尺寸缩小仅用于渲染。 cfg
保存每个维度应如何缩减为2D。
AnsiString
是来自VCL的自我重定位字符串,因此请使用您的环境中提供的char*
或string类。 DWORD
只是无符号32位整数。希望我没有忘记什么...