gctl_toolkits/archive/fractopo/FractalTopo.h
2024-09-10 20:25:18 +08:00

525 lines
12 KiB
C++

#ifndef _FRACTAL_TOPO_H
#define _FRACTAL_TOPO_H
#include <iostream>
#include <sstream>
#include <fstream>
#include <math.h>
#include <string.h>
#include <ctime>
#include <stdlib.h>
#include <stdio.h>
#include "ctime"
#include "unistd.h"
#include "ctype.h"
#define max(a,b) a>b?a:b;
#define PARA "-p"
#define RANGE "-r"
#define PREDEFINED "-t"
#define GAUSS "-g"
#define OUTPUT "-o"
#define BOLDRED "\033[1m\033[31m"
#define RESET "\033[0m"
#define pi (4.0*atan(1.0))
using namespace std;
struct posi
{
double x,y,v;
};
//滤波器函数参数组
struct elliFilter
{
double muX,muY,sigma,theta,Lx,Ly,magnify,rho;
};
double sign(double input)
{
if (input >= 0.0) return 1.0;
else return -1.0;
}
double ElliFilter(int type,double x,double y,elliFilter elf)
{
double xd,yd,filter;
xd = x - elf.muX; yd = y - elf.muY;
double xyModule = sqrt(pow(xd,2)+pow(yd,2)+1e-20);
double t = sign(yd)*acos(xd/xyModule);
double weight = sqrt(pow(elf.Lx*cos(t - elf.theta*pi/180.0),2) + pow(elf.Ly*sin(t - elf.theta*pi/180.0),2));
if(type) //如果type为真则使用arctan构造加权函数
{
filter = pi - 2.0*atan(elf.rho*weight*xyModule - elf.rho*elf.sigma);
filter = filter/(pi + 2.0*atan(elf.rho*elf.sigma));
}
//type为假则使用以e为底的幂函数构造加权函数
else filter = elf.magnify*pow(2.0,-1.0*weight*weight*xyModule*xyModule/(elf.sigma*elf.sigma));
return filter;
}
class FracTopo
{
public:
FracTopo();
~FracTopo();
int topo_gener_regular();//生成随机地形
int output_regular();//输出文件
int gauss_filter_regular();
int topo_gener_random();
int output_random();
int gauss_filter_random();
int run(double*,double*,double*,double*,char*);
private:
double xmin,xmax,dx,ymin,ymax,dy;
double ld,lu,rd,ru;
int xnum,ynum,order_x,order_y,imax;
double H;
double randmax;
elliFilter filter_N;
int ntotal;
int random_num;
double** topo;
double** topo_range;
posi* topo_random;
int ifarctan;
};
FracTopo::FracTopo()
{
topo = NULL;
topo_range = NULL;
topo_random = NULL;
}
FracTopo::~FracTopo()
{
if (topo!=NULL)
{
for(int j=0; j<ntotal; j++) delete[] topo[j];
delete[] topo;
}
if (topo_range!=NULL)
{
for (int i = 0; i < xnum; i++) delete[] topo_range[i];
delete[] topo_range;
}
if (topo_random!=NULL)
{
delete[] topo_random;
}
}
int FracTopo::topo_gener_regular()
{
int i,j,m,n,R,jmax;
double temp = 1e10;
double random;
xnum = (xmax-xmin)/dx+1;
ynum = (ymax-ymin)/dy+1;
xmax = xmin+(xnum-1)*dx;
ymax = ymin+(ynum-1)*dy;
order_x = ceil(log(xnum)/log(2));
order_y = ceil(log(ynum)/log(2));
imax = max(order_x,order_y);
ntotal = (int)pow(2.0,imax)+1; //总数据点数为2的imax次方加1
topo = new double* [ntotal];//开辟二维动态数组
for(i=0; i<ntotal; i++) topo[i] = new double [ntotal];
topo_range = new double* [xnum];
for(i=0; i<xnum; i++) topo_range[i] = new double [ynum];
for (i=0; i<ntotal; i++)//设定地形数据初始值,角点数据必须给出
{
for (j=0; j<ntotal; j++)
{
if (i==0&&j==0)
{
topo[i][j]=ld;//角点初始值;
}
else if (i==ntotal-1&&j==0)
{
topo[i][j]=lu;//角点初始值;
}
else if (i==0&&j==ntotal-1)
{
topo[i][j]=rd;//角点初始值;
}
else if (i==ntotal-1&&j==ntotal-1)
{
topo[i][j]=ru;//角点初始值;
}
else
{
topo[i][j]=temp;//非角点数值初始化为1e10
}
}
}
srand((unsigned) time(NULL));
for (i=1; i<=imax; i++)//开始迭代,生成正方形区域随机地形
{
R=int(double(ntotal-1)/pow(2.0,i));
jmax=int(pow(4.0,i-1));
for (j=1; j<=jmax; j++)
{
random=2*randmax*rand()/RAND_MAX-randmax;
m=2*R*(j-(ceil((double)j/pow(2.0,i-1))-1) * pow(2.0,i-1))-R;
n=2*R*(ceil((double)j/pow(2.0,i-1)))-R;
topo[m][n]=(topo[m-R][n-R]+topo[m+R][n-R]+topo[m-R][n+R]+topo[m+R][n+R])/4+random;
}
for (j=1; j<=jmax; j++)
{
m=2*R*(j-(ceil((double)j/pow(2.0,i-1))-1)* pow(2.0,i-1))-R;
n=2*R*(ceil((double)j/pow(2.0,i-1)))-R;
if (topo[m][n-R]==temp)
{
random=2*randmax*rand()/RAND_MAX-randmax;
if ((n-R)!=0)
{
topo[m][n-R]=(topo[m][n-2*R]+topo[m-R][n-R]+topo[m+R][n-R]+topo[m][n])/4+random;
}
else
{
topo[m][n-R]=(topo[m-R][n-R]+topo[m+R][n-R]+topo[m][n])/3+random;
}
}
if (topo[m-R][n]==temp)
{
random=2*randmax*rand()/RAND_MAX-randmax;
if ((m-R)!=0)
{
topo[m-R][n]=(topo[m-R][n-R]+topo[m-2*R][n]+topo[m][n]+topo[m-R][n+R])/4+random;
}
else
{
topo[m-R][n]=(topo[m-R][n-R]+topo[m][n]+topo[m-R][n+R])/3+random;
}
}
if (topo[m+R][n]==temp)
{
random=2*randmax*rand()/RAND_MAX-randmax;
if ((m+R)!=(ntotal-1))
{
topo[m+R][n]=(topo[m+R][n-R]+topo[m][n]+topo[m+2*R][n]+topo[m+R][n+R])/4+random;
}
else
{
topo[m+R][n]=(topo[m+R][n-R]+topo[m][n]+topo[m+R][n+R])/3+random;
}
}
if (topo[m][n+R]==temp)
{
random=2*randmax*rand()/RAND_MAX-randmax;
if ((n+R)!=(ntotal-1))
{
topo[m][n+R]=(topo[m][n]+topo[m-R][n+R]+topo[m+R][n+R]+topo[m][n+2*R])/4+random;
}
else
{
topo[m][n+R]=(topo[m][n]+topo[m-R][n+R]+topo[m+R][n+R])/3+random;
}
}
}
randmax=pow(2.0,-H)*randmax;
}
for (int j=0; j<ntotal; j++)//按预设区域剪裁数组
{
for (int i=0; i<ntotal; i++)
{
if (i<xnum&&j<ynum)
{
topo_range[i][j]=topo[i][j];
}
}
}
return 0;
}
int FracTopo::topo_gener_random()
{
int i,j,m,n,R,jmax;
double temp = 1e+10;
double random;
dx=dy=ceil(sqrt((xmax-xmin)*(ymax-ymin)/random_num));//按照随机点数预估节点步长
xnum = (xmax-xmin)/dx+1;
ynum = (ymax-ymin)/dy+1;
xmax = xmin+(xnum-1)*dx;
ymax = ymin+(ynum-1)*dy;
order_x = ceil(log(xnum)/log(2));
order_y = ceil(log(ynum)/log(2));
imax = max(order_x,order_y);
ntotal = (int)pow(2.0,imax)+1; //总数据点数为2的imax次方加1
topo = new double* [ntotal];//开辟二维动态数组
for(i=0; i<ntotal; i++) topo[i] = new double [ntotal];
topo_random = new posi [random_num];
for (i=0; i<ntotal; i++)//设定地形数据初始值,角点数据必须给出
{
for (j=0; j<ntotal; j++)
{
if (i==0&&j==0)
{
topo[i][j]=ld;//角点初始值;
}
else if (i==ntotal-1&&j==0)
{
topo[i][j]=lu;//角点初始值;
}
else if (i==0&&j==ntotal-1)
{
topo[i][j]=rd;//角点初始值;
}
else if (i==ntotal-1&&j==ntotal-1)
{
topo[i][j]=ru;//角点初始值;
}
else
{
topo[i][j]=temp;//非角点数值初始化为1e10
}
}
}
srand((unsigned) time(NULL));
for (i=1; i<=imax; i++)//开始迭代,生成正方形区域随机地形
{
R=int(double(ntotal-1)/pow(2.0,i));
jmax=int(pow(4.0,i-1));
for (j=1; j<=jmax; j++)
{
random=2*randmax*rand()/RAND_MAX-randmax;
m=2*R*(j-(ceil((double)j/pow(2.0,i-1))-1) * pow(2.0,i-1))-R;
n=2*R*(ceil((double)j/pow(2.0,i-1)))-R;
topo[m][n]=(topo[m-R][n-R]+topo[m+R][n-R]+topo[m-R][n+R]+topo[m+R][n+R])/4+random;
}
for (j=1; j<=jmax; j++)
{
m=2*R*(j-(ceil((double)j/pow(2.0,i-1))-1)* pow(2.0,i-1))-R;
n=2*R*(ceil((double)j/pow(2.0,i-1)))-R;
if (topo[m][n-R]==temp)
{
random=2*randmax*rand()/RAND_MAX-randmax;
if ((n-R)!=0)
{
topo[m][n-R]=(topo[m][n-2*R]+topo[m-R][n-R]+topo[m+R][n-R]+topo[m][n])/4+random;
}
else
{
topo[m][n-R]=(topo[m-R][n-R]+topo[m+R][n-R]+topo[m][n])/3+random;
}
}
if (topo[m-R][n]==temp)
{
random=2*randmax*rand()/RAND_MAX-randmax;
if ((m-R)!=0)
{
topo[m-R][n]=(topo[m-R][n-R]+topo[m-2*R][n]+topo[m][n]+topo[m-R][n+R])/4+random;
}
else
{
topo[m-R][n]=(topo[m-R][n-R]+topo[m][n]+topo[m-R][n+R])/3+random;
}
}
if (topo[m+R][n]==temp)
{
random=2*randmax*rand()/RAND_MAX-randmax;
if ((m+R)!=(ntotal-1))
{
topo[m+R][n]=(topo[m+R][n-R]+topo[m][n]+topo[m+2*R][n]+topo[m+R][n+R])/4+random;
}
else
{
topo[m+R][n]=(topo[m+R][n-R]+topo[m][n]+topo[m+R][n+R])/3+random;
}
}
if (topo[m][n+R]==temp)
{
random=2*randmax*rand()/RAND_MAX-randmax;
if ((n+R)!=(ntotal-1))
{
topo[m][n+R]=(topo[m][n]+topo[m-R][n+R]+topo[m+R][n+R]+topo[m][n+2*R])/4+random;
}
else
{
topo[m][n+R]=(topo[m][n]+topo[m-R][n+R]+topo[m+R][n+R])/3+random;
}
}
}
randmax=pow(2.0,-H)*randmax;
}
srand((unsigned) time(NULL));
int temp_m,temp_n;
double len_ld,len_lu,len_ru,len_rd;
for (int i = 0; i < random_num; i++)
{
topo_random[i].x = (xmax-xmin)*rand()/RAND_MAX+xmin;
topo_random[i].y = (ymax-ymin)*rand()/RAND_MAX+ymin;
temp_m = floor((topo_random[i].x - xmin)/dx);
temp_n = floor((topo_random[i].y - ymin)/dy);
len_ld = sqrt(pow(xmin+dx*temp_m - topo_random[i].x,2)+pow(ymin+dy*temp_n - topo_random[i].y,2));
len_lu = sqrt(pow(xmin+dx*temp_m - topo_random[i].x,2)+pow(ymin+dy*(temp_n+1) - topo_random[i].y,2));
len_ru = sqrt(pow(xmin+dx*(temp_m+1) - topo_random[i].x,2)+pow(ymin+dy*(temp_n+1) - topo_random[i].y,2));
len_rd = sqrt(pow(xmin+dx*(temp_m+1) - topo_random[i].x,2)+pow(ymin+dy*temp_n - topo_random[i].y,2));
topo_random[i].v = (topo[temp_m][temp_n]*len_ld+topo[temp_m+1][temp_n]*len_rd+topo[temp_m+1][temp_n+1]*len_ru+topo[temp_m][temp_n+1]*len_lu)/(len_lu+len_ru+len_rd+len_ld);
}
return 0;
}
int FracTopo::output_regular()
{
time_t now = time(0);
char* dt = ctime(&now);
cout << "# A fractal terrain data generated by fractopo on " << dt;
cout << "# For more information please connect zhangyi.cugwuhan@gmail.com" << endl;
cout << "# use -h option to see help information" << endl;
cout << "# range=" << xmin << "/" << dx << "/" << xmax << "/" << ymin << "/" << dy << "/" << ymax << endl;
cout << "# x y elevation" << endl;
for (int j=0; j<ynum; j++)
{
for (int i=0; i<xnum; i++)
{
cout<<xmin+i*dx<<" "<<ymin+j*dy<<" "<<topo_range[i][j]<<endl;
}
}
return 0;
}
int FracTopo::output_random()
{
time_t now = time(0);
char* dt = ctime(&now);
cout << "# A fractal terrain data generated by fractopo on " << dt;
cout << "# For more information please connect zhangyi.cugwuhan@gmail.com" << endl;
cout << "# use -h option to see help information" << endl;
cout << "# x y elevation" << endl;
for (int i = 0; i < random_num; i++)
{
cout<<topo_random[i].x<<" "<<topo_random[i].y<<" "<<topo_random[i].v<<endl;
}
return 0;
}
int FracTopo::gauss_filter_regular()
{
for (int j=0; j<ynum; j++)
{
for (int i=0; i<xnum; i++)
{
topo_range[i][j] *= ElliFilter(ifarctan,xmin+i*dx,ymin+j*dy,filter_N);
}
}
return 0;
}
int FracTopo::gauss_filter_random()
{
for (int i = 0; i < random_num; i++)
{
topo_random[i].v *= ElliFilter(ifarctan,topo_random[i].x,topo_random[i].y,filter_N);
}
return 0;
}
int FracTopo::run(double* range,double* topo,double* para,double* gauss,char* filterType)
{
if (!strcmp(filterType,"pow"))
ifarctan = 0;
else if (!strcmp(filterType,"atan"))
ifarctan = 1;
if (*(range+5)==1e+30)
{
xmin = *range; xmax = *(range+1);
ymin = *(range+2); ymax = *(range+3);
random_num = *(range+4);
ld = *topo; lu = *(topo+1); ru = *(topo+2); rd = *(topo+3);
H = *para; randmax = *(para+1);
topo_gener_random();
if (*gauss!=1e+30)
{
filter_N.muX = *gauss;
filter_N.muY = *(gauss+1);
filter_N.sigma = *(gauss+2);
filter_N.theta = *(gauss+3);
filter_N.Lx = *(gauss+4);
filter_N.Ly = *(gauss+5);
filter_N.magnify = *(gauss+6);
filter_N.rho = *(gauss+7);
gauss_filter_random();
}
output_random();
}
else
{
xmin = *range; xmax = *(range+1);
ymin = *(range+2); ymax = *(range+3);
dx = *(range+4); dy = *(range+5);
ld = *topo; lu = *(topo+1); ru = *(topo+2); rd = *(topo+3);
H = *para; randmax = *(para+1);
topo_gener_regular();
if (*gauss!=1e+30)
{
filter_N.muX = *gauss;
filter_N.muY = *(gauss+1);
filter_N.sigma = *(gauss+2);
filter_N.theta = *(gauss+3);
filter_N.Lx = *(gauss+4);
filter_N.Ly = *(gauss+5);
filter_N.magnify = *(gauss+6);
filter_N.rho = *(gauss+7);
gauss_filter_regular();
}
output_regular();
}
return 0;
}
#endif