在数学中,斐波那契数列是一组整数,其中每个数字都是前两个数字的和。
前10个斐波纳契数是: 1,1,2,3,5,8,13,21,34,55,...
本教程将计算斐波那契数,并使用它们来构建TH2Poly,从而产生“斐波那契螺旋”,方法是绘制绘制连接斐波那契平铺中正方形的相对角的圆弧。
下面给出具体代码步骤:
创建新画板:
TCanvas *C = new TCanvas("C", "C", 800, 600);
设定框架线宽:
C->SetFrameLineWidth(0);
创建TH2Poly:
TH2Poly *h2pf = new TH2Poly();
设置TH2Poly参数:
h2pf->SetTitle(Form("The first %d Fibonacci numbers",N)); //标题
h2pf->SetMarkerColor(kRed-2); //记号颜色
h2pf->SetStats(0); //不显示统计信息
设置Fibonacci数列迭代参数:
double f0 = 0.;
double f1 = 1.;
double ft;
将与斐波那契数N对应的bin加到h2pf:
AddFibonacciBin(h2pf, f1);
将Fibonacci数添加到h2pf中:
for (int i=0; i<=N; i++) {
ft = f1;
f1 = f0 + f1;
f0 = ft;
AddFibonacciBin(h2pf, f1);
}
绘制TH2Poly图:
h2pf->Draw("A COL L TEXT");
上面代码中存在一个自定义函数AddFibonacciBin,下面给出其代码解释:
定义四个局部参数:
double X1 = 0.;
double Y1 = 0.; //当前的斐波那契
double X2 = 1.; //方形位置
double Y2 = 1.;
定义静态变量:
static int MoveId = 0;
定义bin值四周参数:
static double T = 1.; //当前bin值的上限
static double B = 0.; //bin值的当前下限
static double L = 0.; //bin值的当前左侧限制
static double R = 1.; //bin值的当前右侧限制
设置所需绘制的位置变量
const int NP = 50; //建立当前bin的点数
double px[NP]; //bin值X的位置
double py[NP]; //bin值Y的位置
定义pi/2:
double pi2 = TMath::Pi()/2;
根据不同参数调节不同方向的参量:
switch (MoveId) {
case 1:
R = R+N;
X2 = R;
Y2 = T;
X1 = X2-N;
Y1 = Y2-N;
px[0] = X1;
py[0] = Y2;
px[1] = X1;
py[1] = Y1;
px[NP-1] = X2;
py[NP-1] = Y2;
Arc(NP,3*pi2,(double)N,px,py);
break;
case 2:
T = T+N;
X2 = R;
Y2 = T;
X1 = X2-N;
Y1 = Y2-N;
px[0] = X1;
py[0] = Y1;
px[1] = X2;
py[1] = Y1;
px[NP-1] = X1;
py[NP-1] = Y2;
Arc(NP,0.,(double)N,px,py);
break;
case 3:
L = L-N;
X1 = L;
Y1 = B;
X2 = X1+N;
Y2 = Y1+N;
px[0] = X2;
py[0] = Y1;
px[1] = X2;
py[1] = Y2;
px[NP-1] = X1;
py[NP-1] = Y1;
Arc(NP,pi2,(double)N,px,py);
break;
case 4:
B = B-N;
X1 = L;
Y1 = B;
X2 = X1+N;
Y2 = Y1+N;
px[0] = X2;
py[0] = Y2;
px[1] = X1;
py[1] = Y2;
px[NP-1] = X2;
py[NP-1] = Y1;
Arc(NP,2*pi2,(double)N,px,py);
break;
}
将计算后的变量添加进h2pf:
if (MoveId==0) h2pf->AddBin(X1,Y1,X2,Y2); //第一个是一个正方形
else h2pf->AddBin(NP, px ,py); //其他的是一个圆弧
填充h2pf:
h2pf->Fill((X1+X2)/2.5, (Y1+Y2)/2.5, N);
改变MoveID,使得下一个数变换方向:
MoveId++;
if (MoveId==5) MoveId=1;
在这个函数中,调用到另外一个自定义函数Arc,用来在点2到n-2的圆弧上添加点。下面给出具体代码:
定义角度增量:
double da = TMath::Pi()/(2*(n-2));
循环添加参数:
for (int i = 2; i<=n-2; i++) {
a = a+da;
px[i] = r*TMath::Cos(a) + px[0];
py[i] = r*TMath::Sin(a) + py[0];
}
代码地址:https://github.com/root-project/root/blob/master/tutorials/hist/Fibonacci.C