构建规则格网进行体积计算
总体步骤:
- 生成凸包多边形
- 构建规则格网
- 计算体积
构建规则格网进行体积计算的第一大步骤----生成凸包多边形
生成凸包多边形又有快速凸包法、Gram Scan法等方法。
在文章[凸包多边形生成算法—快速凸包法]中,我们根据散点集生成凸包点
本文章进行构建规则格网以及计算体积的介绍
1.构建规则格网
根据散点集计算出的四个顶点,确定规则格网的边界。
这里可以创建两个新的类
点类----gridpoint:表示每一个格网中心点对象
格网类----Grid:表示整个格网对象
class gridpoint
{
public float x,y,h;
public int n;//标记网格点是否在凸包内。1在,0或2不在
}
class Grid
{
//格网的xmax,xmin,ymax,ymin从peaks中获取
public float xmax, xmin, ymax, ymin;
public float L;//网格边长
public double r;//搜索半径
public int in_num;//凸包内网格数
public List<gridpoint> gridps = new List<gridpoint>();//所有格网点g
}
//方法在文章后面给出
1.1生成所有格网点
//获取格网中心点的坐标
public void GetGridpoint(List<point> peaks)
{
xmax = (float)peaks[2].x;
xmin = (float)peaks[0].x;
ymax = (float)peaks[1].y;
ymin = (float)peaks[3].y;//格网边界
//搜索半径
r = (ymax - ymin + xmax - xmin) *0.5 * 0.4;
int m = (int)((ymax-ymin)/L);//网格数
int n = (int)((xmax-xmin)/L);
//格网中线点坐标
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
gridpoint gp = new gridpoint();
gp.n = 0;
gp.x = xmin + j * L + L / 2;
gp.y = ymin + i * L + L / 2;
gridps.Add(gp);
}
}
}
此步得到所有格网点中心的坐标(x,y),不包含h,h由散点插值得到
2.计算体积
第一步:计算凸包所包含的所有格网点
第二步:插值计算凸包所包含的格网点的高程
第三步:根据公式计算体积
2.1计算凸包所包含的所有格网点
格网点类中有个属性n,用于标识是否在凸包内。
判断点是否位于凸包内的方法:
for遍历所有的散点
for遍历凸包的每一条边
if(点的y坐标位于边两个端点的y之间)//只可能与2或0条边水平相交 判断点是否位于线的左侧,若是,该点的n 加1;
n == 0 无交点 点在凸包的右侧
n == 2 两个单侧边交点,点位于凸包的左侧
n == 1 一个但侧边交点,点位于凸包的内部
//函数---判断点是否在线左边
public int judge(gridpoint a,point b,point c)
{
double m = (c.x - b.x) / (c.y - b.y) * (a.y - b.y) + b.x;
if (m > a.x)//点a在线bc左边,单线交点+1
{
return 1;
}
else
return 0;
}
//函数---判断点是否在凸包内
public void Find_in(List<point> convex)
{
for (int i = 0; i < gridps.Count; i++)//遍历每一个网格点
{
for (int j = 0; j < convex.Count-1; j++)//遍历凸包点
{
if (gridps[i].y<Math.Max(convex[j].y, convex[j+1].y)
&&
gridps[i].y>=Math.Min(convex[j].y, convex[j + 1].y)
)
{
gridps[i].n += judge(gridps[i], convex[j], convex[j + 1]);
}
}
}
}
2.2插值计算凸包内格网点的高程
对凸包内部的格网点进行插值计算。
注意,这里计算的是格网单元四个顶点的高程
首先需要设置一个搜索半径,用于搜索待插值点周围的散点,然后根据反距离权重计算
函数—输入散点集,待插点坐标,返回待插点高程
//函数---插值计算点高程,进而计算网格顶点高程
public double Get_h(List<point> allps ,float X,float Y)
{
double D=0,h_sum=0,D_sum=0;
double h;
for (int i = 0; i < allps.Count; i++)
{
D = Math.Sqrt((allps[i].x-X)*(allps[i].x - X) +(allps[i].y - Y) *(allps[i].y - Y));
if (D<r)
{
//反距离加权
D_sum += allps[i].h / D;
h_sum += 1 / D;
}
}
h = D_sum / h_sum;
return h;
}
2.3计算体积
//体积计算
public double Cal_V(List<point> allps,double h0)
{
double V = 0;
for (int i = 0; i < gridps.Count; i++)//遍历所有网格点
{
if (gridps[i].n == 1)//凸包内部的点
{
in_num +=1;
//内部点的四个格网顶点高程
double h1 = Get_h(allps, gridps[i].x - L / 2, gridps[i].y - L / 2);
double h2 = Get_h(allps, gridps[i].x + L / 2, gridps[i].y + L / 2);
double h3 = Get_h(allps, gridps[i].x - L / 2, gridps[i].y + L / 2);
double h4 = Get_h(allps, gridps[i].x + L / 2, gridps[i].y - L / 2);
//计算公式
V += ((h1 + h2 + h3 + h4) / 4 - h0) * L * L;
}
}
return V;
}