GIS工程技术与项目管理

博客园 首页 新随笔 联系 订阅 管理

三维场景下的通视分析作为GIS中一种重要的分析功能,可应用于旅游中的风景评价,房地产中视线遮挡判断,以及通讯中的信号覆盖,或军事上的火力覆盖等多方面,具有计算结果直观等优点。而通视分析的类型大致有:一点对整个区域的通视面积计算,两点之间的通视性判断,多点通视面积的交集计算,由被覆盖的可视面积反求待定位置与高度等。本文章着重讲解三维场景下前两种通视分析类型的算法和编码。

一点对整个区域的通视面积计算是在给定观察位置后,首先计算此位置与区域内其他顶点之间是否通视,将主要通过下面介绍的TracePoint()函数来实现,然后依据通视与否给三维场景中的其他顶点赋黑白颜色。具体代码如下:

bool SinglePointVisibilityAnalysis::VisibilitySinglePointStart(double xaxisnumber, double yaxisnumber, float zaxisadded)

{

    int     x, y;

    double x_Pos, y_Pos;

    double dx,dy;

    double z_Pos,dz;

    m_byRsVisibility = new BYTE[m_iRows * m_iColumns];                         //准备设置黑白两种颜色来区分可见与不可见区域

    m_byGsVisibility = new BYTE[m_iRows * m_iColumns];

    m_byBsVisibility = new BYTE[m_iRows * m_iColumns];

       

    if(!m_p3dDEMGrid->IsInGrid(xaxisnumber, yaxisnumber))                 //使用索引的时候注意还原i和j,使用位置的时候注意原点和单位格网长度

    {

        AfxMessageBox("Point not in Grid");

        return false;                        //点击的位置不在DEM网格内,直接返回

    }

    //-----------------------------------------------------

    long index = 0;

    x_Pos   = xaxisnumber;           //点击位置处X值

    y_Pos   = yaxisnumber;           //点击位置处Y值

    index   = m_iColumns*(y_Pos - m_dYMin)/m_iYCellSize+(x_Pos - m_dXMin)/m_iXCellSize;        //通过点击的位置来计算顶点数组中的索引

   

    z_Pos   = m_p3dDEMPoints[index][2] + zaxisadded;//点击位置处Z值加上用户输入的高度数值

    //-----------------------------------------------------

   

    for(y=0; y<m_iRows ; y++)                     //对输入网格Y轴开始循环

    {

        for(x=0; x<m_iColumns; x++) //对输入网格X轴循环

        {

                 if( m_p3dDEMGrid->IsNodata(x,y))//如果为非赋值数据

                 {

                     long tIndex = y * m_iColumns + x;    //计算在顶点数组中的索引

                     m_byRsVisibility[tIndex] = 150; //颜色分量                                           

                     m_byGsVisibility[tIndex] = 150;                                      

                     m_byBsVisibility[tIndex] = 150;

                     continue;                        //继续下次循环

                 }

                 index = y*m_iColumns + x;        //计算在顶点数组中的索引

                 dx      = x_Pos - (m_dXMin + x*m_iXCellSize);

                 dy      = y_Pos - (m_dYMin + y*m_iYCellSize);//用户点击处与(x,y)位置处之间实际坐标的差值,也可看成两向量相减

                 dz      = z_Pos - m_p3dDEMPoints[index][2]; //用户点击处与(x,y)位置处之间高度的差值

                 //-----------------------------------------

                 if( TracePoint(x, y, dx, dy, dz) )   //若为真,则说明两位置之间是可以相互看见的

                 {

                     m_byRsVisibility[index] = 250;      //代表照亮(x,y)处

                     m_byGsVisibility[index] = 250;      //代表照亮(x,y)处

                     m_byBsVisibility[index] = 250;      //代表照亮(x,y)处

                 }

                 else

                 {

                     m_byRsVisibility[index] = 30;   //代表(x,y)处不可见

                     m_byGsVisibility[index] = 30;   //代表(x,y)处不可见

                     m_byBsVisibility[index] = 30;   //代表(x,y)处不可见

                 }

           

        }

    }

SetVisibilitySinglePointSurfaceColor();//将m_byBsVisibility[]应用到最后的显示中

return true;

}

bool SinglePointVisibilityAnalysis::TracePoint(int x, int y, double dx, double dy, double dz)

{

    double ix, iy, iz, id, d, dist;

    d = fabs(dx) > fabs(dy) ? fabs(dx) : fabs(dy);        //取dx、dy中绝对值较大的一个

    if( d > 0 )                              //已经取得绝对值,一般是大于零

    {

        dist    = sqrt(dx*dx + dy*dy);           //得到两顶点之间的距离

        dx      /= d;                        //dx变成-1 与1之间的一个数

        dy      /= d;                        //dy变成-1 与1之间的一个数

        dz      /= d;                        //总的高程差被分成几个部分

        d       = dist / d;                  //步数

        long index0 = y*m_iColumns + x;     //要计算的这个点在顶点数组中的索引

        id      = 0.0;

        ix      = x + 0.5;                          

        iy      = y + 0.5;

        iz      = m_p3dDEMPoints[index0][2];//准备计算的这个顶点的高程数值

        while( id < dist )

        {

            id += d;                    //id的数值每次循环增加一步

            ix += dx;                   //X轴的数值增加,向观察处靠近

            iy += dy;                   //Y轴的数值增加,向观察处靠近

            iz += dz;                   //原始高度增加高程差的一个部分

            x   = (int)ix;               //取整,看处于第几列

            y   = (int)iy;               //取整,看处于第几行

            int index = y*m_iColumns + x;    //计算在顶点数组中的索引

            if( !m_p3dDEMGrid->IsInGrid(x, y))

            {

                 return( true );

            }

            else if( iz < m_p3dDEMPoints[index][2] )          //说明在靠近观察处的过程中,有顶点的高程超过了视线上的高程,所以看不见要计算的顶点

            {

                 return( false );

            }

            else if( iz > m_dZMax )//若超过整个DEM的最高值,那肯定从观察处看见要计算的顶点

            {

                 return( true );

            }

        }

    }

    return( true );

}

     两顶点之间的通视就可采用TracePoint(.)函数来计算。


原始场景图


单点通视图


两点通视判断图

posted on 2008-04-11 15:30  飞羽  阅读(979)  评论(0编辑  收藏  举报