在实际项目中,有时候会遇到这样的需求,根据DEM地形数据,我们需要根据某两点的连线,找到经过的所有山顶点和凹陷点。
山顶点指哪些在特定邻域分析范围内,该点都比周围点高的区域。凹陷点指哪些在特定邻域分析范围内,该点都比周围点低的区域区域。DEM数据提供了丰富的地形信息,基于DEM数据如何正确有效的提取这些地形特征信息,在数字地形分析中具有重要意义。
对于客户所遇到的这种需求,下面跟着我一起来看看在SuperMap iObjects c++中,是如何实现吧。
首先,我们还是需要明确的一点,前期的数据处理,在这里包括dem数据的入库,在程序开发中不是每一次都要进行的操作,也不是具体的业务需求,所以所以我们通常都是使用SuperMap提供的专门用于前期处理数据的iDesktop软件工作进行数据的入库,处理。先在桌面软件中,将数据制作完成,地图配图,保存为工作空间文件(*.smwu),组件开发直接打开数据即可,程序开发只实现业务需求。
数据准备
这里,我们首先需要将拿到的DEM地形数据先导入到SuperMap的数据源(*.udb或者*.udbx)中,不管是tif还是其他格式的数据都一样.
注意:导入的时候,数据类型需要修改为“栅格”,不能按照默认的影像方式导入。
关于如何SuperMap iObjects c++环境的部署,以及如何打开数据不清楚的小伙伴,这里可以参考之前的博客:
环境配置(windows环境VS + Qt):SuperMap iObjects for C++ 入门详解(VS + Qt)_supermapsupport的博客-优快云博客
环境配置(windows+MFC):SuperMap iObjects C++之MFC快速入门_supermapsupport的博客-优快云博客_sumpermap c++配置
环境配置(Qt Creator):https://blog.youkuaiyun.com/supermapsupport/article/details/52609945
数据源管理:SuperMap iObjects C++之数据源管理_supermapsupport的博客-优快云博客_supermap怎么打开udb数据源
好了,程序也建好了,数据也准备好了,下面就一起来看看功能是如何实现的吧:
- 、计算山顶点(凸点):
第一步:
拿到对应的栅格数据,在SuperMap iObjects c++中,栅格数据的对象类型为UGDatasetRaster ;
第二步:确定需要分析的目标线,我们需要分析的就是从起点到终点的所有途径点,所以我们需要把这个起始点确定好。
第三步:确定一个分析系数:想要结果的精细度是更精细还是略微粗糙,越精细,分析的点越多,得到的结果越密集,反之,这里,我们把这个分析系数命名为interval;
完整实现步骤:
传入参数:
demDataset:栅格数据集;
Geoline:待分析的路线;
Interval:分析系数;
实现代码参考:
UGPoint2Ds* MMapControl::FindHeightPoint(UGDatasetRaster *demDataset, UGGeoLine *geoline, UGdouble interval)
{
try {
UGPoint2Ds *heightPoints=new UGPoint2Ds();
if(interval==0.0)
{
interval=demDataset->GetBounds().Width()/demDataset->GetWidth();
}
UGdouble num=geoline->GetLength()/interval;
for (int i=1;i<num-1;i++) {
UGdouble distanceBack = num * (i-1);
UGdouble distanceNow = num * i;
UGdouble distanceNext = num * (i+1);
UGPoint2D point2dBack = geoline->FindPointOnLineByDistance(distanceBack);
UGPoint2D point2dNow = geoline->FindPointOnLineByDistance(distanceNow);
UGPoint2D point2dNext = geoline->FindPointOnLineByDistance(distanceNext);
UGPoint pointBack;
demDataset->XYToGrid(point2dBack,pointBack);
UGPoint pointNow;
demDataset->XYToGrid(point2dNow,pointNow);
UGPoint pointNext;
demDataset->XYToGrid(point2dNext,pointNext);
UGdouble heightBack = demDataset->GetValue(pointBack.x, pointBack.y);
UGdouble heightNow = demDataset->GetValue(pointNow.x, pointNow.y);
UGdouble heightNext = demDataset->GetValue(pointNext.x, pointNext.y);
double BN = heightBack - heightNow;
double NN = heightNow - heightNext;
if (BN * NN < 0)
{
if (BN < 0)
{
heightPoints->Add(point2dNow);
}
}
}
return heightPoints;
} catch (double d) {
}
}
关键代码分析:
1、UGdouble num=geoline->GetLength()/interval;
根据分析系数,求出我们将在线上等距离提取出多少个点进行分析,系数interval越小,分析精细越高,反之。
2、根据在线上按照等距离查找,找到相连的三个点坐标;
UGPoint2D point2dBack = geoline->FindPointOnLineByDistance(distanceBack);
UGPoint2D point2dNow = geoline->FindPointOnLineByDistance(distanceNow);
UGPoint2D point2dNext = geoline->FindPointOnLineByDistance(distanceNext);
3、根据demDataset->XYToGrid拿到对应点位在栅格数据集中所处的行列号,结果UGPoint 的x就是所处的行号,y就是所处的列号;
UGPoint pointBack;
demDataset->XYToGrid(point2dBack,pointBack);
UGPoint pointNow;
demDataset->XYToGrid(point2dNow,pointNow);
UGPoint pointNext;
demDataset->XYToGrid(point2dNext,pointNext);
4、根据栅格数据集GetValue的方法可以分别拿到相连三个点位的高程值;
UGdouble heightBack = demDataset->GetValue(pointBack.x, pointBack.y);
UGdouble heightNow = demDataset->GetValue(pointNow.x, pointNow.y);
UGdouble heightNext = demDataset->GetValue(pointNext.x, pointNext.y);
5、判断中间那个点是否是转折点;
double BN = heightBack - heightNow;
double NN = heightNow - heightNext;
if (BN * NN < 0)
{
if (BN < 0)
{
heightPoints->Add(point2dNow);
}
}
通过简单的数学公式比较,如果三个点所构成的折线,两条线的方向是相反的,并且前面一条线的方向是朝上的(第一个点的高度比第二个点的高度小),那中间那个点就是山顶点,就可以添加到凸点的点集合里面,最后作为结果统一返回。
2.、计算凹陷点(凹点)
计算凹点的实现思路跟上面是一样的,只是最后的数学公式换一下
if (BN * NN < 0)
{
if (BN > 0)
{
lowPoints->Add(point2dNow);
}
}
如果三个点所构成的折线,两条线的方向是相反的,并且前面一条线的方向是朝下的(第一个点的高度比第二个点的高度大),那第二个点就是凹陷点,就可以添加到凹点的点集合里面,最后作为结果统一返回。
下面是一份简单的结果展示,是将返回的结果点分布添加到跟踪图层进行临时展示,其中红色代表凸点,蓝色代表凹点:
如果结果数据需要存储起来,可以参考一下博客,将对象添加到数据集中进行保存,方便后续使用,SuperMap iObjects c++中对数据的增删改查都是通过UGRecordset,这也是一个非常重要,并且使用较多的一个关键类。具体的使用方法,参考之前的博客:
https://blog.youkuaiyun.com/supermapsupport/article/details/111913924