吊打百度脚踢高德/原创自研跨平台地图组件/标注点多边形矩形圆形/动态绘制和拖曳调整

张开发
2026/4/16 13:13:48 15 分钟阅读

分享文章

吊打百度脚踢高德/原创自研跨平台地图组件/标注点多边形矩形圆形/动态绘制和拖曳调整
一、前言说明动态绘图是地图组件的一个很核心的功能开启后可以直接在地图上绘制标注点、折线、多边形、矩形、圆形等在所有第三方的地图中比如天地图、百度地图、高德地图、腾讯地图、谷歌地图等都提供了这些接口每一家都有不同的方式调用经过大量的对比实践发现谷歌地图是做的最好的其次是天地图体验最不友好的是百度地图。谷歌地图对应的覆盖物开启编辑后不仅可以拉伸调整大小还可以整体的拖曳覆盖物移动矩形还可以四个角度和上下左右拉伸调整要的就是这个效果尤其是折线如果鼠标按下在折线段上可以拖曳移动的很可惜很多厂家都没做这个功能可能实现起来比较复杂吧还有一个就是百度地图的圆形居然是个多边形模拟的矩形也是一个多边形不能整体拉伸拖动一个点移动居然矩形变成了多边形很是鸡肋啊不知道大厂的程序员怎么写的实在是差劲。天地图排第二就差一点那就是多边形和折线不支持整体拖曳调整位置。要实现和谷歌地图一样的编辑图形效果用qwidget绘制还是很容易的相对来说简单一些最大的难点就一个如何计算鼠标按下的地方在折线条上不在折线的点上也算尝试了各种方法最终采用内置的QPainterPathStroker来实现QPainterPathStroker可以对一个整体的QPainterPath对象轮廓两侧放大最终形成一个多边形区域比如一条折线就是一个放大的多边形弯弯绕绕的有粗细然后拿到这个多边形QPolygonF就可以判断按下的点是不是在里面在里面就表示按在了折线上。二、效果图三、代码使用#includedrawhelper.h#includemaputil.h#includeoverlayhelper.hQListQColorDrawHelper::colorsQListQColor();QColorDrawHelper::getRandColor(){if(colors.count()0){colorsQColor(0,176,180)QColor(0,113,193)QColor(255,192,0);colorsQColor(72,103,149)QColor(185,87,86)QColor(0,177,125);colorsQColor(214,77,84)QColor(71,164,233)QColor(34,163,169);colorsQColor(59,123,156)QColor(162,121,197)QColor(72,202,245);colorsQColor(0,150,121)QColor(111,9,176)QColor(250,170,20);}returncolors.at(rand()%colors.count());}OverlayBase*DrawHelper::overlayNULL;QVectorPointWorldCoordDrawHelper::coordsQVectorPointWorldCoord();voidDrawHelper::doMouseEvent(MapWidget*map,intmouseType,QMouseEvent*mouseEvent,PointWorldCoord pressCoord,PointWorldCoord currentCoord){//取出经纬度坐标QPointF pressPointpressCoord.rawPoint();QPointF currentPointcurrentCoord.rawPoint();//鼠标移动事件必须另外的判断boolright(mouseEvent-button()Qt::RightButton);if(mouseTypeMouseType_Move){right(mouseEvent-buttons()Qt::RightButton);}QMetaObject::invokeMethod(map,mapEvent,Q_ARG(int,mouseType),Q_ARG(bool,right),Q_ARG(QPointF,currentPoint));//不同鼠标动作进行不同的绘制OverlayType drawTypemap-getDrawType();if(mouseTypeMouseType_Press){if(drawTypeOverlayType_Polyline){if(!overlay){coordsQVectorPointWorldCoord()currentCoord;overlayOverlayHelper::addPolyline(map,draw_polyline,coords,QColor(0,177,125),3);}}elseif(drawTypeOverlayType_Polygon){if(!overlay){coordsQVectorPointWorldCoord()currentCoord;overlayOverlayHelper::addPolygon(map,draw_polygon,coords,QColor(71,164,233),3,QColor(71,164,233,50));}}}elseif(mouseTypeMouseType_Move){if(drawTypeOverlayType_Polyline){if(overlayoverlay-overlayType()OverlayType_Polyline){//更新最后一个坐标为当前坐标coords[coords.size()-1]currentCoord;OverlayHelper::setPolylineData(overlay,coords);}}elseif(drawTypeOverlayType_Polygon){if(overlayoverlay-overlayType()OverlayType_Polygon){//更新最后一个坐标为当前坐标coords[coords.size()-1]currentCoord;OverlayHelper::setPolygonData(overlay,coords);}}elseif(drawTypeOverlayType_Rectangle){if(!overlay){overlaymap-addRectangle(draw_rectangle,pressPoint,currentPoint,QColor(214,77,84),3,QColor(214,77,84,30));}else{OverlayHelper::updateRectangle(overlay,pressPoint,currentPoint,QColor(),0,QColor());}}elseif(drawTypeOverlayType_Circle){//根据两点之间的距离计算半径qreal distanceMapUtil::getDistance(pressPoint,currentPoint);qreal radiusMapUtil::getDegreesFromMeters(distance);if(!overlay){overlaymap-addCircle(draw_circle,pressPoint,radius,QColor(162,121,197),4,QColor(162,121,197,50));}else{OverlayHelper::updateCircle(overlay,QPointF(),radius,QColor(),0,QColor());}}}elseif(mouseTypeMouseType_Release){if(right){//移除最后一个点/一般最后两个点是重复的if(overlay){if(overlay-overlayType()OverlayType_Polyline){coords.remove(coords.size()-1);//coords.removeLast();OverlayHelper::setPolylineData(overlay,coords);}elseif(overlay-overlayType()OverlayType_Polygon){coords.remove(coords.size()-1);//coords.removeLast();OverlayHelper::setPolygonData(overlay,coords);}}//右键取消绘图overlayNULL;coords.clear();map-setDrawType(OverlayType_None);}elseif(drawTypeOverlayType_Shape){intsize10rand()%20;map-addShape(draw_shape,pressPoint,getRandColor(),size);}elseif(drawTypeOverlayType_Label){intsize15rand()%20;introtaterand()%360;map-addLabel(draw_label,pressPoint,getRandColor(),测试文字,2,size,rotate);}elseif(drawTypeOverlayType_Marker){map-addMarker(draw_marker,pressPoint,QString(),QPixmap(:/mapimage/marker.png));}elseif(drawTypeOverlayType_Polyline){if(overlayoverlay-overlayType()OverlayType_Polyline){coordscurrentCoord;OverlayHelper::setPolylineData(overlay,coords);}}elseif(drawTypeOverlayType_Polygon){if(overlayoverlay-overlayType()OverlayType_Polygon){coordscurrentCoord;OverlayHelper::setPolygonData(overlay,coords);}}elseif(drawTypeOverlayType_Rectangle||drawTypeOverlayType_Circle){overlayNULL;coords.clear();}}elseif(mouseTypeMouseType_DbClick){}}四、相关地址国内站点https://gitee.com/feiyangqingyun国际站点https://github.com/feiyangqingyun个人作品https://blog.csdn.net/feiyangqingyun/article/details/97565652文件地址https://pan.baidu.com/s/1ZxG-oyUKe286LPMPxOrO2A 提取码o05q 文件名bin_mapwidget.zip五、功能特点支持各种地图源包括天地图、高德地图、腾讯地图、谷歌地图、微软地图等。标准WGS-84地球坐标系采用默卡托投影可以拓展其他坐标系和投影规则。支持在线和离线两种场景需求可以自定义在线瓦片地址格式和离线瓦片地址格式。多线程下载和加载瓦片图片文件多线程绘制自动缓存瓦片文件。在线模式下可以开启是否缓存文件指定缓存路径将下载的瓦片文件存放到本地默认优先从缓存文件查找如果存在缓存文件则加载缓存文件不存在则联网下载。可以拖动地图鼠标滚轮放大和缩小地图以鼠标所在位置作为缩放中心点提供缩放控件手动单击进行操作。多图层机制支持多个瓦片叠加图层和图形绘制图层全部采用双缓冲技术所有的图形和瓦片全部绘制到一个图片文件上最终再将图片文件绘制到地图控件。不可见区域的图层包括覆盖物不会触发绘制降低CPU占用。预加载机制默认绘制的图层大小以当前区域往四周放大两倍这样在鼠标拖动和缩放的时候不会看到明显的加载过程体验更佳。内置了多种图形覆盖物包括坐标点、文本、标注点、折线、多边形、矩形、圆形等可以设置边框颜色粗细、填充颜色和透明度等参数。标注点支持旋转角度和提示文本其中提示文本可以设置在标注点的相对位置标注点图片支持gif动图可以动态切换静态图和动图。标注点和提示文本可以设置相对位置位置包括左侧、右侧、上侧、下侧、中间、左上角、右上角、左下角、右下角。标注点默认按照底部居中对齐一般圆形图标可以设置中心点对齐。标注点提示文本可设置背景颜色透明度、颜色边框和粗细支持换行和多行文字。所有的图形可以动态更新前景色、颜色粗细、背景颜色、颜色透明度等。支持删除单个图形、删除一种类型的图形、删除所有图形、隐藏单个或者所有图形等。支持动态绘制各种图形开启后直接在地图上鼠标按下绘制鼠标右键结束绘制非常方便快捷。在对应图形区域鼠标按下发出图形单击信号精准识别单击区域比如折线以鼠标在折线条上作为判断依据多边形区域以鼠标在整个多边形区域内为准而不是以矩形区域包括圆形也是以圆形内部为准。可以动态启动禁用比例尺、十字线、缩放控件、地图拖曳、键盘操作、滚轮缩放、双击放大、鼠标追踪等特性。可以任意指定经纬度区域进行瓦片拼接保存成图片文件也可以直接对整个可视区域或者缓存区域的地图图片文件保存。支持任意多边形轮廓保存成图片比如某个行政区的瓦片保存。图形可以动态设置zindex层叠顺序值越大越显示在前面内部维护着一个zindex表默认按照添加的先后顺序增加后面添加的显示在前面主动设置后按照设置的zindex来绘制。支持将QWidget对象作为覆盖物添加到地图控件中跟随地图移动位置极大提高灵活性比如可以将自定义控件直接作为地图控件的子对象加入进去。内置MarkerMove轨迹移动类支持历史轨迹数据回放和实时轨迹移动可设置图标、轨迹线的颜色和粗细、移动速度、移动间隔、平滑移动等支持多条轨迹线条同时移动。内置MarkerLine航迹规划类支持动态添加航迹点显示对应箭头可以动态拖曳调整航迹点的位置选中点高亮显示。大量使用按需绘制机制包括内部提供合理的默认值来触发绘制也可以手动传入参数指定是否需要立即绘制比如删除了某个覆盖物有些频繁的操作可以不指定立即绘制等操作完成后再统一一起绘制效率更高。默认开启缓存瓦片机制所有加载过的瓦片文件都存储在内存中下次再次绘制直接从内存取出来绘制既不需要从联网获取也不需要从缓存文件获取直接内存取出来绘制响应迅速效率最高体验最佳。支持批量添加覆盖物比如几万个标注点和圆形都是瞬间完成绘制相比web网页的方式性能提升百倍以上。支持街道图、卫星图、混合图、路网图等各种图层可以任意叠加N个图层甚至杂交不同地图厂家的瓦片文件。纯QWidget绘制非qml也非web不依赖qml或者浏览器控件支持极低性能的嵌入式环境。原创轻量级5000行代码架构漂亮注释详细拓展方便容易学习适合各种初学者和进阶者方便二次开发。支持任意Qt版本、任意系统、任意编译器包括嵌入式linux和各种国产电脑环境。古法编程不含任何AI代码品质保证。

更多文章