在GIS应用中buffer,也就是缓冲是很普通和重要的实现,具体就是以一个空间对象(geometry)按照一定的缓冲半径进行扩展后形成新的空间对象,生成的空间对象为面类型(Polygon)。点线面都可以进行缓冲处理。
1、基本介绍
在QGIS中,buffer作为QgsGeometry类的一个成员函数,格式如下:
QgsGeometry buffer (double distance, int segments) const
QgsGeometry buffer( double distance,int segments,Qgis::EndCapStyle endCapStyle,Qgis::JoinStyle joinStyle,
double miterLimit
) const
其中distance是缓冲半径,单位同地图;segments为拟合点个数,个数越多生成的边界越光滑;其余参数针对连接点和端点样式设置。
调用例子:
//点缓冲,10个地图单位
QgsGeometry geoPoint = QgsGeometry::fromPointXY(10,10);
QgsGeometry geoPointBuffer = geoPoint.buffer(10,40);
//线缓冲,10个地图单位
QgsGeometry geoLine = QgsGeometry::fromPolylineXY(lineXY);//lineXY为点串
QgsGeometry geoLineBuffer = geoLine.buffer(10,40)
在现实应用中地图单位有可能是度、米等,大家习惯上多采用缓冲xx米,因此在实际应用中要进行单位转换。比如上面的例子,假设地图单位是度(degrees),则调用为缓冲10度,显然这种使用不是太符合实际情况。
2、单位转换
可以使用QgsUnitTypes::fromUnitToUnitFactor()获取不同单位间的转换系数。跟踪QGIS源码中涉及单位转换的都是用这个来实现的,而且同一组转换系数是固定。(由此也产生了疑问:地球椭圆的特性决定不一致性,尤其是区域涉及大范围会导致计算的差异更大。网上也有很多关于这方面的帖子,都是涉及参考坐标系、投影等测绘知识,这里不再讨论。)
3、封装
/**
* 点缓冲,缓冲半径单位米
* @brief SHGeoHelper::bufferByMetre
* @param xy
* @param off 缓冲半径,单位米
* @param mapCanvas
* @return
*/
QgsGeometry SHGeoHelper::bufferByMeter(QgsGeometry geo, float off, QgsMapCanvas *mapCanvas){
if (!mapCanvas)return geo;
if (off <= 0)return geo;
QgsUnitTypes::DistanceUnit unit = mapCanvas->mapUnits();
double factor = QgsUnitTypes::fromUnitToUnitFactor(QgsUnitTypes::DistanceMeters, unit);
double distance = factor * off;
return geo.buffer(distance, 36);
}
4、界面效果
5、延伸思考
在gis应用中有点击查询的需求,也就是鼠标点击地图上某处,查询与点击处存在相交的空间对象。为了提高命中率,在实际开发中往往是点击处缓冲出一个区域,再用这个区域来进行查询。这种情况下缓冲单位为米就不是太恰当,因为在不同比例尺下,以米为单位的缓冲区域可能会过大或过小,此时采用像素为单位进行缓冲就比较合适,这使在不同比例尺下缓冲出来的区域相对当前视口都是大小一致的。
此时就需要计算当前窗口像素和地图单位的转换系数,并通过此将指定像素值转换为地图单位下的对应值。