官方示例

首先看一下官方文档中的矩形工具源码:

class RectangleMapTool(QgsMapToolEmitPoint):def __init__(self, canvas):self.canvas = canvasQgsMapToolEmitPoint.__init__(self, self.canvas)self.rubberBand = QgsRubberBand(self.canvas, QgsWkbTypes.PolygonGeometry)self.rubberBand.setColor(QColor(255, 0, 0, 100))self.rubberBand.setWidth(1)self.reset()def reset(self):self.startPoint = self.endPoint = Noneself.isEmittingPoint = Falseself.rubberBand.reset(True)def canvasPressEvent(self, e):self.startPoint = self.toMapCoordinates(e.pos())self.endPoint = self.startPointself.isEmittingPoint = Trueself.showRect(self.startPoint, self.endPoint)def canvasReleaseEvent(self, e):self.isEmittingPoint = Falser = self.rectangle()if r is not None:print("Rectangle:", r.xMinimum(), r.yMinimum(), r.xMaximum(), r.yMaximum())def canvasMoveEvent(self, e):if not self.isEmittingPoint:returnself.endPoint = self.toMapCoordinates(e.pos())self.showRect(self.startPoint, self.endPoint)def showRect(self, startPoint, endPoint):self.rubberBand.reset(QgsWkbTypes.PolygonGeometry)if startPoint.x() == endPoint.x() or startPoint.y() == endPoint.y():returnpoint1 = QgsPointXY(startPoint.x(), startPoint.y())point2 = QgsPointXY(startPoint.x(), endPoint.y())point3 = QgsPointXY(endPoint.x(), endPoint.y())point4 = QgsPointXY(endPoint.x(), startPoint.y())self.rubberBand.addPoint(point1, False)self.rubberBand.addPoint(point2, False)self.rubberBand.addPoint(point3, False)self.rubberBand.addPoint(point4, True)  # true to update canvasself.rubberBand.show()def rectangle(self):if self.startPoint is None or self.endPoint is None:return Noneelif self.startPoint.x() == self.endPoint.x() or self.startPoint.y() == self.endPoint.y():return Nonereturn QgsRectangle(self.startPoint, self.endPoint)def deactivate(self):super(RectangleMapTool, self).deactivate()self.deactivated.emit()self.reset()

文档中的有些语法还是QGIS2的写法,比如QGis.Polygon在QGIS3中应该用QgsWkbTypes.PolygonGeometry、QgsPoint在QGIS3中对应QgsPointXY,这里我已经做了更改。

源码解析

  • 首先继承QgsMapToolEmitPoint类
  • 重写canvasPressEvent、canvasReleaseEvent、canvasMoveEvent
  • 使用QgsRubberBand渲染绘制的图形(支持PolygonGeometry、PointGeometry、LineGeometry)

具体思路是当鼠标按压画布时,触发canvasPressEvent,得到第一个点self.startPoint,鼠标拖动后触发canvasMoveEvent,得到第二个点,使用这两个点绘制一个矩形,鼠标释放时触发canvasReleaseEvent,结束绘制。

注:每次绘制前都要清除之前的图形,否则会出现拖影,使用rubberBand的reset方法:

self.rubberBand.reset(QgsWkbTypes.PolygonGeometry)

实现多边形绘制

QGIS自带的矢量编辑工具中已经有多边形绘制工具,如下:

接下来我们添加一个自动垂直绘制的功能,源码如下:

class PolygonMapTool(QgsMapToolEmitPoint):def __init__(self, canvas):self.canvas = canvasQgsMapToolEmitPoint.__init__(self, self.canvas)self.rubberBand = QgsRubberBand(self.canvas, QgsWkbTypes.PolygonGeometry)self.rubberBand.setColor(QColor(255, 0, 0, 100))self.rubberBand.setWidth(1)self.reset()def reset(self):self.is_start = False  # 开始绘图self.is_vertical = False  # 垂直画线self.cursor_point = Noneself.points = []self.rubberBand.reset(True)def canvasPressEvent(self, event):if event.button() == Qt.LeftButton:self.points.append(self.cursor_point)self.is_start = Trueelif event.button() == Qt.RightButton:# 右键结束绘制if self.is_start:self.is_start = Falseself.cursor_point = Noneself.show_polygon()self.points = []else:passelse:passdef canvasMoveEvent(self, event):self.cursor_point = event.mapPoint()if not self.is_start:returnself.show_polygon()def show_polygon(self):self.rubberBand.reset(QgsWkbTypes.PolygonGeometry)  # 防止拖影first_point = self.points[0]last_point = self.points[-1]self.rubberBand.addPoint(first_point, False)for point in self.points[1:-1]:self.rubberBand.addPoint(point, False)if self.cursor_point:self.rubberBand.addPoint(QgsPointXY(last_point.x(), last_point.y()), False)else:self.rubberBand.addPoint(QgsPointXY(last_point.x(), last_point.y()), True)self.rubberBand.show()return# 光标所在点if self.is_vertical and len(self.points) >= 2:countdown_second_point = self.points[-2]cursor_point_x = self.cursor_point.x()cursor_point_y = self.cursor_point.y()diff_x = int(math.fabs(last_point.x() - countdown_second_point.x()))diff_y = int(math.fabs(last_point.y() - countdown_second_point.y()))if diff_x > diff_y:# 最后一条线的x,y差值比较cursor_point_x = equation(countdown_second_point.x(), countdown_second_point.y(), last_point.x(),last_point.y(), self.cursor_point.y(), solve_type='x')else:cursor_point_y = equation(countdown_second_point.x(), countdown_second_point.y(), last_point.x(),last_point.y(), self.cursor_point.x(), solve_type='y')_cursor_point = QgsPointXY(cursor_point_x, cursor_point_y)self.cursor_point = _cursor_pointself.rubberBand.addPoint(self.cursor_point, True)self.rubberBand.show()def deactivate(self):super(PolygonMapTool, self).deactivate()self.deactivated.emit()self.reset()

其中equation算法是自己实现的,原理就是直角三角形直角边平方和等于斜边平方(),自行理解,使用到了sympy库(第一次使用,好强大。。。),源码如下:

def equation(x1, y1, x2, y2, f, solve_type='x'):'''已知两点坐标和第三个点x或y,求对应的y或x:param x1:第一个点x坐标:param y1:第一个点y坐标:param x2:第二个点x坐标:param y2:第二个点y坐标:param f:x或y的坐标值:param solve_type:'x'或'y',默认'x':return:'''if solve_type == 'x':x = symbols('x')y = fs = solve((x - x1) ** 2 + (y - y1) ** 2 - (x2 - x1) ** 2 - (y2 - y1) ** 2 - (x - x2) ** 2 - (y - y2) ** 2, x)return s[0]else:y = symbols('y')x = fs = solve((x - x1) ** 2 + (y - y1) ** 2 - (x2 - x1) ** 2 - (y2 - y1) ** 2 - (x - x2) ** 2 - (y - y2) ** 2, y)return s[0]

截图

矩形

多边形

QGIS自定义地图工具相关推荐

  1. DOTA无法加载服务器指定的地图,Dota2自定义地图工具怎么安装_Dota2自定义地图工具常见问题处理方法...

    Dota 2 创意工坊工具的早期测试(Alpha)版本已经发布,如果你有新奇的想法可以使用工具开发制作自己的地图,为Dota 2再添砖瓦. 如果是抱着"玩"的心态小编建议就不要下载 ...

  2. OpenLayers 3自定义地图工具条(一)

    对于一个WEB地图应用来说,地图工具条可以说是不可或缺的一个部分,但由于一些样式.功能往往并不能满足实际项目需要,所以仍要对此部分进行定制,从这里将说明如何利用Oplenayers 3根据项目要求做一 ...

  3. QGIS自定义符号的原理与实践——以北京市标准地图为例

     01 符号概述 符号(Symbol)是地图和GIS的核心概念.QGIS使用渲染器(Renderer)完成图层在地图窗口中的绘制,即所谓的图层渲染.图层渲染之前需要告诉渲染器使用什么符号渲染图层,如果 ...

  4. power bi自定义地图_如何使用自定义形状图在Power BI中创建地理图

    power bi自定义地图 介绍 (Introduction) This is the third article of a series dedicated to discovering geogr ...

  5. ROS自定义地图(CAD、手绘等)

    0x00 概述 在前面的文章中,我们介绍如何自动导航时,都是基于使用gmapping或者hector_mapping创建的地图.当然使用其他的建图方法创建的地图也可以,但是目前为止,无论使用哪种建图方 ...

  6. echarts自定义地图总结(VUE)

    需求: 全国地图中内蒙古地区分为蒙东.蒙西,河北省地区分为河北.冀北,需要自定义地图. 思路: 从json文件上做文章,例如整个中国地图的json里包含各个省的json,各个省包含各个市的json,以 ...

  7. 百度地图API详解之自定义地图类型

    个人博客原文地址:http://www.jiazhengblog.com/blog/2011/10/08/422/ 今天的文章主要介绍如何利用地图API实现自定义地图. 百度地图API目前默认支持两种 ...

  8. php网页地图上自定义,如何添加在线自定义地图

    在奥维互动地图浏览器中,除内置的在线地图外,用户还可以添加自定义地图,如在线电子地图和航拍图等,以满足用户对特定地图的需求. 1.正常添加在线电子地图的前提条件 (1)被添加的地图采用墨卡托投影方式, ...

  9. 手把手教你绘制自定义地图

    1. 内容概述 自定义地图组件支持使用用户自己绘制的地图绑定和呈现数据. 我们可以直接在设计器中绘制自定义地图,只需导入底图图片,进行描边和调整标记点,即可使用. 如下图所示,我们根据一张商场的平面图 ...

  10. jvectormap的自定义地图和区域上色、图片标记

    jvectormap的自定义地图和区域上色.图片标记 因为网上例子太少,上手实属不易,所以在这里跟大家分享一下我的使用! (第一次写,因为粘贴代码卡死几次,重写了几次,心累 ╥﹏╥-) 这里就简单的介 ...

最新文章

  1. python的cfg是什么模块_cfg4py:一个严肃的Python配置模块应有的风格-层级式、部署环境自适应、自动补全...
  2. 详解C++移动语义std::move()
  3. string index out of range_Java 12 骚操作, String居然还能这样玩!
  4. 一种同于计算机键盘的测试装置,一种计算机键盘按键测试装置
  5. 如何查看linux的版本?
  6. 一次简单的 JVM 调优,性能提升了15%
  7. Tomcat(二)环境变量配置
  8. Rhino导入Revit生成体量幕墙的方法和操作要点
  9. Cesium gltf(1.70)三维人物动画制作
  10. PC端 流光溢彩 Arduino
  11. U盘被写保护无法格式化(我用win10,同样成功格式化了U盘)
  12. 家用计算机音效部件图示,唱吧新版自定义音效设置方法(附上最佳音效设置参数图)...
  13. 服务器ip总是被封,怎么办?
  14. css学习记录第一天(选择器)
  15. java 将json转成utf 8_C# JSON转换以及编码转换
  16. html如何查看字体样式,css2.0文档查阅及字体样式
  17. 联想小新 win10电脑系统安装教程
  18. pip 下载安装包及依赖包 并安装
  19. java后台程序员转android 之《三B》 支付宝支付 client join server 及采坑记录
  20. cmake教程(cmake教程pdf)

热门文章

  1. 快来喝杯Java(初级第一章)
  2. 160页PPT神经网络图,颜色形状随意DIY
  3. newifi路由器 php,newifi路由器有线桥接教程
  4. 个人网页制作(教你制作简单网页)
  5. nginx日志中$request_body 十六进制字符(\\x22) 引号问题处理记录
  6. tmux的安装及用法
  7. 豫教科计算机资源管理教案,豫科版小学五年级上册信息技术教案(全册.doc
  8. php mcrypt blowfish,php加密算法blowfish
  9. Blender插件安装不显示问题
  10. FMI飞马网 | 人工智能/大数据/程序/语言/项目管理/机器学习/Python书籍免费赠书