525 lines
12 KiB
C++
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 |