因为最近接了一个计算降雨时洼地汇水情况的任务,便苦逼的写下了这个算法。因为对GIS相关知识以前并没有过了解,因此算法可能存在诸多疏漏或错误欢迎评论指正。本算法只是一个理想化模型的demo,不包括地表渗水,蒸发等因素。此外,算法中使用的DEM并不是C#中标准的ArcGis相关类,而是自己写的伪代码(偷点懒,先把算法赶出来再说- -)。
本算法从区域的最低点开始,不断向四周递归的淹没临近栅格。使用List来保存最低点数据(从最低到第二低到第三低....),将本次淹没点周围的栅格加入List,直到已淹没的n个栅格能够容纳该区域内的降水总体积而不溢出。
然后上代码了,转用的话麻烦注明一下出处:
using System;
using System.Collections.Generic;
/**
* @author mengwei
* @E-mail:[email protected]
* @version 创建时间:2018/7/3
* 本程序为基于DEM(并不是标准的DEM,DEM部分算是伪代码)的降雨淹没算法,模拟一个小区域内降雨淹没的范围
* 本算法仅作为一个简单的理想化demo,还应考虑渗水量(根据地表类型)等因素
* 如有错误或意见欢迎讨论
*/
namespace WaterSpread
{
class WaterSpread
{
public class Point:IComparable
{
public int X; //横坐标
public int Y; //纵坐标
public int h; //高程值
public Point(int X,int Y,int h)
{
this.X = X;
this.Y = Y;
this.h = h;
}
int IComparable.CompareTo(Point other)
{
Point otherPoint = (Point)other;
return (this.h < otherPoint.h ? -1 : (this.h == otherPoint.h ? 0 : 1));
}
}
private int length; //栅格总长度
private int width; //栅格总宽度
private bool[,] isFlooded; //栅格是否被淹没
private bool[,] borderPoints; //用于标识水位边界点
private Point[,] DEM; //dem数据
private int waterFall; //降水量
private int s; //一个栅格的面积
private List depthList = new List(); //一个按高程从小到大排列的List
//构造函数
public WaterSpread(Point[,] dem,int fall,int _s)
{
s = _s;
waterFall = fall;
DEM = dem;
length = dem.GetLength(0);
width = dem.GetLength(1);
isFlooded = new bool[length, width];
borderPoints = new bool[length, width];
}
///
/// 种子扩散算法淹没分析
/// 起始点为洼地最低点
///
/// 淹没起始点横坐标
/// 淹没起始点纵坐标
public void waterSpreading(int posX,int posY)
{
//若该点未被淹没
if (!isFlooded[posX, posY])
{
isFlooded[posX, posY] = true;
//寻找该点周围未被淹没的栅格加入队列
int lowest = int.MaxValue;
//取临近的八个栅格,从未淹没的栅格中寻找最低点
for(int i = posX - 1; i < posX + 2; i++)
{
for(int j = posY - 1; j < posY + 2; j++)
{
if(i >= 0 && i < length && j >= 0 && j < width)
if (!isFlooded[i, j] && !(i == posX && j ==posY))
{
depthList.Add(DEM[i, j]);
depthList.Sort(); //对List进行重排序
}
}
}
//若水位线高于临近最低点
if (depthList[0] != null)
lowest = depthList[0].h;
if(lowest < waterDepth())
{
Point curr = depthList[0];
depthList.Remove(curr);
//递归继续向List的第一个Point淹没
waterSpreading(curr.X,curr.Y);
}
}
}
///
/// 计算当前淹没区域的水位距地平面的距离
///
public int waterDepth()
{
int n = 0; //淹没栅格总数
int h = 0;
int totalDepth = 0; //各个已淹没栅格淹没深度之和
for(int i = 0; i < length; i++)
for(int j=0;j
namespace WaterSpread
{
class test
{
//测试用例
static void Main(string[] args)
{
WaterSpread.Point[,] testDEM = new WaterSpread.Point[1, 3];
testDEM[0, 0] = new WaterSpread.Point(0, 0, -5);
testDEM[0, 1] = new WaterSpread.Point(0, 1, -7);
testDEM[0, 2] = new WaterSpread.Point(0, 2, -6);
WaterSpread ws = new WaterSpread(testDEM,1,1);
ws.waterSpreading(0, 1);
ws.showFlooded();
}
}
}