zoukankan      html  css  js  c++  java
  • 基于分形随机生成月面数字高程模型

    一些前置知识或说明

    分形:通常被定义为“一个粗糙或零碎的几何形状,可以分成数个部分,且每一部分都(至少近似地)是整体缩小后的形状”,即具有自相似的性质。

    通俗的说,分形即是某一个几何形状,它可以分成若干部分,每一部分放大后和整个图形类似,并且每一部分被分开的子图形也具有此种性质。在本文的应用中只需大概理解即可,不必深究。

    Diamond-square algorithm:

    即钻石形-正方形算法。算法过程如图所示。用此算法来生成随机而又自然的高程数据。根据分形理论分为若干子问题。每一子问题处理一个正方形内的部分高程数据。其过程如下

    对于每个子问题:

    1.初始状态为正方形四角高程数据已知,随机范围[-s,s]已知。即图1

    2.计算中心点数据,即钻石的尖点(上下左右四个钻石)。计算方法为算出四角平均值之后再加上在[-s,s]内随机的数据。如图2

    3.计算钻石顶面的中心点,方法同2。如图3

    4.此子问题解决,将此问题分解为四个子问题,即四个小正方形,并把s置为0.5s后重复上述过程。如图4,5

    初始化可根据问题具体内容给出四角的高程值以及光滑度,即s的取值。

    月面石块以及撞击坑数量的数学模型 :根据统计数据建立出月球平缓月海内石块数量nor与石块直径d_r的函数关系如下:

    \[ lg(nor)=-2.589\times lg(d_r)-3.3955 \]

    平缓月海内撞击坑数量noc与撞击坑直径d_c的函数关系如下:

    \[ lg(noc)=-2\times lg(d_c)-1\quad ,d_c\leq40\\ lg(noc)=-3\times lg(d_c)+0.62\quad ,d_c>40 \]

    月面撞击坑形状的数学模型

    上述函数数据来源于:张伍, 党兆龙, 贾阳, 等. 月面数字地形构造方法研究[J]. 航天器环境工程, 2008, 25(4):301-306.感兴趣的读者请自行查阅

    生成过程

    1. 生成月面地形

      1.1根据Diamond-square algorithm随机填充高程点,生成月面的自然起伏。

    2. 生成撞击坑,给出最小撞击坑直径

      2.1 由最小直径,根据上述数学模型计算出撞击坑数量noc

      2.2 在[1,noc]范围内随机生成数量random_n

      2.3 根据random_n反向计算对应直径d_c

      2.4 随机生成撞击坑中心点x,y,并随机此撞击坑类型(新鲜,年轻,年老)

      2.5 根据撞击坑形状的数学模型计算并填充高程点

      2.6 循环上述过程noc

    3. 生成石块

      3.1 方法同上,石块形状模型取标准抛物线

    4. 输出高程数据

    生成结果

    采用此方法生成1km x 1km ,分辨率为0.5m的月面高程模型,输出2000000xyz点对

    生成结果在global mapper中预览如下:



    可以看出效果还是可以接受的。

    代码

    #include<bits/stdc++.h>
    
    using namespace std;
    const int MAX=2e3+3;
    const double min_rock_d=1.5;
    const double min_crater_d=10;
    const int length=2e3;
    const double resolution=0.5;
    const double smoothness=25;
    const double h1_d[3][2]= {0.23,0.17,0.11,0.25,0.19,0.13}; //h1_d[i][0] for lower_limit, h1_d[i][1] for upper_limit
    const double h2_d[3][2]= {0.022,0.016,0.008,0.06,0.045,0.03}; // ditto
    
    
    double dem[MAX][MAX];
    bool vis[MAX][MAX];
    struct node
    {
        int xs,xt,ys,yt;
        double s;
        node(int _xs,int _xt,int _ys,int _yt,double _s):xs(_xs),xt(_xt),ys(_ys),yt(_yt),s(_s){}
    };
    
    inline double sq(double x)
    {
        return x*x;
    }
    
    inline double rock(double d,double h,double x,double y)
    {
        double res=h-4.0*h*(sq(x)+sq(y))/sq(d);
        if(res<0)return 0.0;
        return res;
    }
    
    inline double crater(double d,double h1,double h2,double x,double y)
    {
        x=sqrt(sq(x)+sq(y));
        double res;
        double rd=rand()%2+1;
        if(x+rd<=d/2)
            res=4.0*h1/sq(d)*sq(x)+h2-h1;
        else
            res=-4.0*h2/sq(d)*sq(x)+4.0*h2/d*(x);
        if(x+rd>d/2&&res<0)
            return 0.0;
        return res;
    }
    
    inline int c_d_n(double d)
    {
        if(d<=40.0)
            return int(pow(10.0,-2.0*log10(d)-1.0)*length*length/4);
        else
            return int(pow(10.0,-3.0*log10(d)+0.62)*length*length/4);
    }
    inline double c_n_d(int n)
    {
        double nn=double(n)/sq(double(length/2));
        if(n<65)
            return pow(10.0,(log10(nn)-0.62)/-3.0);
        else
            return pow(10.0,(log10(nn)+1.0)/-2.0);
    }
    inline int r_d_n(double d)
    {
        return int(pow(10.0,-2.589*log10(d)-3.3955)*length*length/4);
    }
    inline double r_n_d(int n)
    {
        double nn=double(n)/sq(double(length/2));
        return pow(10.0,(log10(nn)+3.3955)/-2.589);
    }
    
    void fill_rock(double d,double h,int xs,int xt,int ys,int yt,int xm,int ym)
    {
        if(xs<0)xs=0;
        if(xt>=length)xt=length-1;
        if(ys<0)ys=0;
        if(yt>=length)yt=length-1;
        for(int i=xs; i<=xt; i++)
            for(int j=ys; j<=yt; j++)
            {
                double xx=double(i-xm)*resolution,yy=double(j-ym)*resolution;
                dem[i][j]+=rock(d,h,xx,yy);
            }
    }
    void fill_crater(double d,double h1,double h2,int xs,int xt,int ys,int yt,int xm,int ym)
    {
        if(xs<0)xs=0;
        if(xt>=length)xt=length-1;
        if(ys<0)ys=0;
        if(yt>=length)yt=length-1;
        for(int i=xs; i<=xt; i++)
            for(int j=ys; j<=yt; j++)
            {
                double xx=double(i-xm)*resolution,yy=double(j-ym)*resolution;
                dem[i][j]+=crater(d,h1,h2,xx,yy);
                vis[i][j]=1;
            }
    }
    
    void terrain_genaration(void)
    {
        srand(time(0));
        queue<node>Q;
        Q.push(node(0,length-1,0,length-1,smoothness));
        dem[0][0]=dem[0][length-1]=dem[length-1][0]=dem[length-1][length-1]=10.0;
        while(!Q.empty())
        {
            node cur=Q.front();
            Q.pop();
            if(cur.xt-cur.xs<2)continue;
            int xs=cur.xs,xt=cur.xt,ys=cur.ys,yt=cur.yt;
            int mx=(xs+xt)>>1,my=(ys+yt)>>1;
            double rd=double(rand()%int(max(cur.s*2000.0,1.0)))/1000.0-cur.s;
            double avg=(dem[xs][ys]+dem[xs][yt]+dem[xt][ys]+dem[xt][yt])/4.0;
            dem[mx][my]=avg+rd;
            rd=double(rand()%int(max(cur.s*2000.0,1.0)))/1000.0-cur.s;
            dem[xs][my]=avg+rd;
            rd=double(rand()%int(max(cur.s*2000.0,1.0)))/1000.0-cur.s;
            dem[xt][my]=avg+rd;
            rd=double(rand()%int(max(cur.s*2000.0,1.0)))/1000.0-cur.s;
            dem[mx][ys]=avg+rd;
            rd=double(rand()%int(max(cur.s*2000.0,1.0)))/1000.0-cur.s;
            dem[mx][yt]=avg+rd;
            double nxts=cur.s/2.0;
            Q.push(node(xs,mx,ys,my,nxts));
            Q.push(node(mx,xt,ys,my,nxts));
            Q.push(node(xs,mx,my,yt,nxts));
            Q.push(node(mx,xt,my,yt,nxts));
        }
    }
    
    void Creater(int noc,int a,int b)
    {
        double minn=1e9+7;
        for(int i=0;i<a;i++)
        {
            int num=rand()%noc+b;
            double d=c_n_d(num);
            minn=min(minn,d);
            int t=rand()%3;
            double h1=h1_d[t][0]+(h1_d[t][1]-h1_d[t][0])*double(rand()%10+1)/10.0;
            h1*=d;
            double h2=h2_d[t][0]+(h2_d[t][1]-h2_d[t][0])*double(rand()%10+1)/10.0;
            h2*=d;
            int r=int(d/resolution);
            int x=rand()%length,y=rand()%length;
            while(vis[x][y])
            {
                x=rand()%length;
                y=rand()%length;
            }
            fill_crater(d,h1,h2,x-r,x+r,y-r,y+r,x,y);
        }
    }
    
    int main()
    {
        srand(time(0));
        terrain_genaration();
        int noc=c_d_n(min_crater_d);
        cout<<"noc="<<noc<<endl;
        Creater(noc,noc*0.3,noc*2.5);
        Creater(noc,noc*0.2,noc*0.5);
        Creater(noc,noc*0.15,2);
        int nor=r_d_n(min_rock_d);
        cout<<"nor="<<nor<<endl;
        for(int i=0; i<nor; i++)
        {
            int num=rand()%nor+1;
            double d=r_n_d(num);
            double h=double(rand()%50+50)/100.0*d;
            int r=int(d/resolution)/2;
            int x=rand()%length,y=rand()%length;
            fill_rock(d,h,x-r,x+r,y-r,y+r,x,y);
        }
        FILE *fpwrite=fopen("maptest.txt","w");
        for(int i=0;i<500;i++)
            for(int j=0;j<500;j++)
            {
                int si=i*4,ti=i*4+4,sj=j*4,tj=j*4+4;
                for(int k=si;k<ti;k++)
                    for(int l=sj;l<tj;l++)
                        fprintf(fpwrite,"%.5f %.5f %.5f\n",double(k)*0.5,double(l)*0.5,dem[k][l]);
            }
    }
    
    
    

    交流

    如果本文有什么错误或漏洞诚邀读者指正。如果有什么问题也欢迎与我交流。

    邮箱:SChLiu907@gmail.com

  • 相关阅读:
    HDU Railroad (记忆化)
    HDU 1227 Fast Food
    HDU 3008 Warcraft
    asp vbscript 检测客户端浏览器和操作系统(也可以易于升级到ASP.NET)
    Csharp 讀取大文本文件數據到DataTable中,大批量插入到數據庫中
    csharp 在万年历中计算显示农历日子出错
    csharp create ICS file extension
    CSS DIV Shadow
    DataTable search keyword
    User select fontface/color/size/backgroundColor设置 字体,颜色,大小,背景色兼容主流浏览器
  • 原文地址:https://www.cnblogs.com/cryingrain/p/12289525.html
Copyright © 2011-2022 走看看