一、前言说明地图的二次开发中显示实时轨迹或者轨迹回放都是必备的功能也是目前最流行的无人机系统中的核心功能这个功能思考了很久主要是考虑需要哪些接口比如可设置标注点的图片、移动的速度、移动的间隔、数据轨迹的颜色、移动轨迹的颜色等可以是传入轨迹点集合进行轨迹回放也可以动态append添加新的点做实时轨迹显示轨迹点必须是平滑移动根据移动的速度自动生成中间的点比如两个点之间距离是1000米速度是100米每次则需要在这两个点之间产生9个点进行均等分定时器每次取出一个点移动过去如果没有这个处理则上一个点移动到下一个点都是瞬间移动过去理论上很难看因为实际上很可能是慢慢的平滑移动过去的。一般都会绘制一个实时的轨迹为了突出接口丰富方便用户使用这里还增加函数可以动态设置数据轨迹以及实时轨迹线是否可见不需要的时候可以设置不可见每种轨迹都可以动态设置颜色和粗细上述功能全部封装成了movemarker类只需要new就可以用有几条就new几个实例就行多次反复测试效果非常棒不枉费这些天这么久才把这个类思考好。我写程序一般是写草稿设计好思考好然后再写持续迭代这个习惯保持了快20年廉颇老矣哎年轻真好。二、效果图三、相关代码#includemovemarker.h#includemaputil.h#includeoverlayhelper.hMoveMarker::MoveMarker(MapWidget*mapWidget,constQStringflag,constQPixmappixmap,constQListQPointFpoints,intspeed,intinterval,boolsmooth,boolmoveInCenter):QObject(mapWidget){//生成对应覆盖物的唯一标识this-dataLineFlagdataLine_flag;this-moveLineFlagmoveLine_flag;this-moveMarkerFlagmoveMarker_flag;this-mapWidgetmapWidget;this-pixmappixmap;this-speedspeed;this-smoothsmooth;this-moveInCentermoveInCenter;//约定第一个点是起始点/如果只有一个点则说明是动态添加数据生成轨迹/多个点则是历史轨迹回放angle0;homeQPointF(121.424362,31.175942);intcountpoints.count();if(count0){homepoints.first();}//多个数据则说明是轨迹回放/设置到可视区域/实时轨迹则设置起点作为中心点if(count1){mapWidget-setAutoView(points);angleMapUtil::getAngle(points.at(0),points.at(1));//传入速度也就是每次移动的距离/逐个取出点生成平滑的点if(smooth){for(inti0;icount-1;i){this-pointsMapUtil::getLinePoints(points.at(i),points.at(i1),speed);}}else{this-pointspoints;}}else{this-pointspoints;mapWidget-setCenter(home.x(),home.y());}//添加数据轨迹线mapWidget-addPolyline(dataLineFlag,points,QColor(255,0,0),5);//添加移动轨迹线mapWidget-addPolyline(moveLineFlag,QListQPointF()home,QColor(0,0,0),3);//添加移动标注点markermapWidget-addMarker(moveMarkerFlag,home.x(),home.y(),QString(),pixmap,angle,2);//定时器移动标注点timernewQTimer(this);connect(timer,SIGNAL(timeout()),this,SLOT(move()));timer-setInterval(interval);}MoveMarker::~MoveMarker(){//停止定时器timer-stop();this-points.clear();//删除覆盖物mapWidget-deleteOverlay(dataLineFlag);mapWidget-deleteOverlay(moveLineFlag);mapWidget-deleteOverlay(moveMarkerFlag);}voidMoveMarker::start(){index0;if(points.count()1){angleMapUtil::getAngle(points.at(0),points.at(1));}timer-start();this-move();}voidMoveMarker::pause(){timer-stop();}voidMoveMarker::next(){timer-start();}voidMoveMarker::stop(){timer-stop();this-reset();}voidMoveMarker::append(qreal lng,qreal lat){QPointFcurPoint(lng,lat);QPointF prePointpoints.last();if(smooth){this-pointsMapUtil::getLinePoints(prePoint,curPoint,speed);}else{this-pointscurPoint;}//添加到数据轨迹mapWidget-addPolylineData(dataLineFlag,curPoint.x(),curPoint.y());}voidMoveMarker::setInterval(intinterval){timer-setInterval(interval);}voidMoveMarker::setSmooth(boolsmooth){this-smoothsmooth;}voidMoveMarker::setMoveInCenter(boolmoveInCenter){this-moveInCentermoveInCenter;}voidMoveMarker::setDataLineVisible(boolvisible){mapWidget-setOverlayVisible(dataLineFlag,visible);}voidMoveMarker::setMoveLineVisible(boolvisible){mapWidget-setOverlayVisible(moveLineFlag,visible);}voidMoveMarker::setDataLineColor(constQColorcolor,intwidth){mapWidget-updatePolyline(dataLineFlag,QListQPointF(),color,width);}voidMoveMarker::setMoveLineColor(constQColorcolor,intwidth){mapWidget-updatePolyline(moveLineFlag,QListQPointF(),color,width);}voidMoveMarker::setText(constQStringtext,constQColortextColor,inttextAlign,inttextOffset,constQStringfontName,intfontSize,constQColorbgColor,intbgAlpha,constQColorborderColor,intborderWidth){OverlayHelper::updateText(marker,text,textColor,textAlign,textOffset,fontName,fontSize,bgColor,bgAlpha,borderColor,borderWidth);}voidMoveMarker::move(){//每次索引递增index;//到了末尾则重来if(indexpoints.count()){this-reset();return;}//过滤重复的坐标QPointF curPointpoints.at(index);QPointF prePointpoints.at(index-1);if(prePointcurPoint){this-move();return;}//移动到新的位置/带旋转角度intangleMapUtil::getAngle(prePoint,curPoint);//mapWidget-updateMarker(moveMarkerFlag, curPoint.x(), curPoint.y(), , QPixmap(), angle);mapWidget-addPolylineData(moveLineFlag,curPoint.x(),curPoint.y());//最新点一直作为中心点if(moveInCenter){mapWidget-setCenter(curPoint.x(),curPoint.y());}}voidMoveMarker::reset(){//复位索引index0;//移动到起始点//mapWidget-updateMarker(moveMarkerFlag, home.x(), home.y(), QString(), QPixmap(), angle, 2);//移动轨迹复位mapWidget-setPolylineData(moveLineFlag,QListQPointF()home);}四、相关地址国内站点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动图可以动态切换静态图和动图。标注点和提示文本可以设置相对位置位置包括左侧、右侧、上侧、下侧、中间、左上角、右上角、左下角、右下角。标注点默认按照底部居中对齐一般圆形图标可以设置中心点对齐。标注点提示文本可设置背景颜色透明度、颜色边框和粗细支持html富文本。所有的覆盖物可以动态更新前景色、颜色粗细、背景颜色、颜色透明度等。支持删除单个覆盖物、删除一种类型的覆盖物、删除所有覆盖物、隐藏指定覆盖物等。可以动态启动禁用比例尺、十字线、缩放控件、地图拖曳、键盘操作、滚轮缩放、双击放大等特性。可以任意指定经纬度区域进行瓦片拼接保存成图片文件也可以直接对整个可视区域或者缓存区域的地图图片文件保存。支持任意多边形轮廓保存成图片比如某个行政区的瓦片保存。覆盖物可以动态设置zindex层叠顺序值越大越显示在前面内部维护着一个zindex表默认按照添加的先后顺序增加后面添加的显示在前面主动设置后按照设置的zindex来绘制。支持将QWidget对象作为覆盖物添加到地图控件中跟随地图移动位置极大提高灵活性比如可以将自定义控件直接作为地图控件的子对象加入进去。内置moveMarker轨迹移动类支持历史轨迹数据回放和实时轨迹移动可设置图标、轨迹线的颜色和粗细、移动速度、移动间隔、平滑移动等支持多条轨迹线条同时移动。大量使用按需绘制机制包括内部提供合理的默认值来触发绘制也可以手动传入参数指定是否需要立即绘制比如删除了某个覆盖物有些频繁的操作可以不指定立即绘制等操作完成后再统一一起绘制效率更高。默认开启缓存瓦片机制所有加载过的瓦片文件都存储在内存中下次再次绘制直接从内存取出来绘制既不需要从联网获取也不需要从缓存文件获取直接内存取出来绘制响应迅速效率最高体验最佳。支持批量添加覆盖物比如几万个标注点和圆形都是瞬间完成绘制相比web网页的方式性能提升百倍以上。支持街道图、卫星图、混合图、路网图等各种图层可以任意叠加N个图层甚至杂交不同地图厂家的瓦片文件。纯QWidget绘制非qml也非web不依赖qml或者浏览器控件支持极低性能的嵌入式环境。支持任意Qt版本、任意系统、任意编译器包括嵌入式linux和各种国产电脑环境。古法编程不含任何AI代码品质保证。
实时轨迹/轨迹回放/多条轨迹同时回放/轨迹平滑移动/移动速度和间隔/自动旋转角度
一、前言说明地图的二次开发中显示实时轨迹或者轨迹回放都是必备的功能也是目前最流行的无人机系统中的核心功能这个功能思考了很久主要是考虑需要哪些接口比如可设置标注点的图片、移动的速度、移动的间隔、数据轨迹的颜色、移动轨迹的颜色等可以是传入轨迹点集合进行轨迹回放也可以动态append添加新的点做实时轨迹显示轨迹点必须是平滑移动根据移动的速度自动生成中间的点比如两个点之间距离是1000米速度是100米每次则需要在这两个点之间产生9个点进行均等分定时器每次取出一个点移动过去如果没有这个处理则上一个点移动到下一个点都是瞬间移动过去理论上很难看因为实际上很可能是慢慢的平滑移动过去的。一般都会绘制一个实时的轨迹为了突出接口丰富方便用户使用这里还增加函数可以动态设置数据轨迹以及实时轨迹线是否可见不需要的时候可以设置不可见每种轨迹都可以动态设置颜色和粗细上述功能全部封装成了movemarker类只需要new就可以用有几条就new几个实例就行多次反复测试效果非常棒不枉费这些天这么久才把这个类思考好。我写程序一般是写草稿设计好思考好然后再写持续迭代这个习惯保持了快20年廉颇老矣哎年轻真好。二、效果图三、相关代码#includemovemarker.h#includemaputil.h#includeoverlayhelper.hMoveMarker::MoveMarker(MapWidget*mapWidget,constQStringflag,constQPixmappixmap,constQListQPointFpoints,intspeed,intinterval,boolsmooth,boolmoveInCenter):QObject(mapWidget){//生成对应覆盖物的唯一标识this-dataLineFlagdataLine_flag;this-moveLineFlagmoveLine_flag;this-moveMarkerFlagmoveMarker_flag;this-mapWidgetmapWidget;this-pixmappixmap;this-speedspeed;this-smoothsmooth;this-moveInCentermoveInCenter;//约定第一个点是起始点/如果只有一个点则说明是动态添加数据生成轨迹/多个点则是历史轨迹回放angle0;homeQPointF(121.424362,31.175942);intcountpoints.count();if(count0){homepoints.first();}//多个数据则说明是轨迹回放/设置到可视区域/实时轨迹则设置起点作为中心点if(count1){mapWidget-setAutoView(points);angleMapUtil::getAngle(points.at(0),points.at(1));//传入速度也就是每次移动的距离/逐个取出点生成平滑的点if(smooth){for(inti0;icount-1;i){this-pointsMapUtil::getLinePoints(points.at(i),points.at(i1),speed);}}else{this-pointspoints;}}else{this-pointspoints;mapWidget-setCenter(home.x(),home.y());}//添加数据轨迹线mapWidget-addPolyline(dataLineFlag,points,QColor(255,0,0),5);//添加移动轨迹线mapWidget-addPolyline(moveLineFlag,QListQPointF()home,QColor(0,0,0),3);//添加移动标注点markermapWidget-addMarker(moveMarkerFlag,home.x(),home.y(),QString(),pixmap,angle,2);//定时器移动标注点timernewQTimer(this);connect(timer,SIGNAL(timeout()),this,SLOT(move()));timer-setInterval(interval);}MoveMarker::~MoveMarker(){//停止定时器timer-stop();this-points.clear();//删除覆盖物mapWidget-deleteOverlay(dataLineFlag);mapWidget-deleteOverlay(moveLineFlag);mapWidget-deleteOverlay(moveMarkerFlag);}voidMoveMarker::start(){index0;if(points.count()1){angleMapUtil::getAngle(points.at(0),points.at(1));}timer-start();this-move();}voidMoveMarker::pause(){timer-stop();}voidMoveMarker::next(){timer-start();}voidMoveMarker::stop(){timer-stop();this-reset();}voidMoveMarker::append(qreal lng,qreal lat){QPointFcurPoint(lng,lat);QPointF prePointpoints.last();if(smooth){this-pointsMapUtil::getLinePoints(prePoint,curPoint,speed);}else{this-pointscurPoint;}//添加到数据轨迹mapWidget-addPolylineData(dataLineFlag,curPoint.x(),curPoint.y());}voidMoveMarker::setInterval(intinterval){timer-setInterval(interval);}voidMoveMarker::setSmooth(boolsmooth){this-smoothsmooth;}voidMoveMarker::setMoveInCenter(boolmoveInCenter){this-moveInCentermoveInCenter;}voidMoveMarker::setDataLineVisible(boolvisible){mapWidget-setOverlayVisible(dataLineFlag,visible);}voidMoveMarker::setMoveLineVisible(boolvisible){mapWidget-setOverlayVisible(moveLineFlag,visible);}voidMoveMarker::setDataLineColor(constQColorcolor,intwidth){mapWidget-updatePolyline(dataLineFlag,QListQPointF(),color,width);}voidMoveMarker::setMoveLineColor(constQColorcolor,intwidth){mapWidget-updatePolyline(moveLineFlag,QListQPointF(),color,width);}voidMoveMarker::setText(constQStringtext,constQColortextColor,inttextAlign,inttextOffset,constQStringfontName,intfontSize,constQColorbgColor,intbgAlpha,constQColorborderColor,intborderWidth){OverlayHelper::updateText(marker,text,textColor,textAlign,textOffset,fontName,fontSize,bgColor,bgAlpha,borderColor,borderWidth);}voidMoveMarker::move(){//每次索引递增index;//到了末尾则重来if(indexpoints.count()){this-reset();return;}//过滤重复的坐标QPointF curPointpoints.at(index);QPointF prePointpoints.at(index-1);if(prePointcurPoint){this-move();return;}//移动到新的位置/带旋转角度intangleMapUtil::getAngle(prePoint,curPoint);//mapWidget-updateMarker(moveMarkerFlag, curPoint.x(), curPoint.y(), , QPixmap(), angle);mapWidget-addPolylineData(moveLineFlag,curPoint.x(),curPoint.y());//最新点一直作为中心点if(moveInCenter){mapWidget-setCenter(curPoint.x(),curPoint.y());}}voidMoveMarker::reset(){//复位索引index0;//移动到起始点//mapWidget-updateMarker(moveMarkerFlag, home.x(), home.y(), QString(), QPixmap(), angle, 2);//移动轨迹复位mapWidget-setPolylineData(moveLineFlag,QListQPointF()home);}四、相关地址国内站点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动图可以动态切换静态图和动图。标注点和提示文本可以设置相对位置位置包括左侧、右侧、上侧、下侧、中间、左上角、右上角、左下角、右下角。标注点默认按照底部居中对齐一般圆形图标可以设置中心点对齐。标注点提示文本可设置背景颜色透明度、颜色边框和粗细支持html富文本。所有的覆盖物可以动态更新前景色、颜色粗细、背景颜色、颜色透明度等。支持删除单个覆盖物、删除一种类型的覆盖物、删除所有覆盖物、隐藏指定覆盖物等。可以动态启动禁用比例尺、十字线、缩放控件、地图拖曳、键盘操作、滚轮缩放、双击放大等特性。可以任意指定经纬度区域进行瓦片拼接保存成图片文件也可以直接对整个可视区域或者缓存区域的地图图片文件保存。支持任意多边形轮廓保存成图片比如某个行政区的瓦片保存。覆盖物可以动态设置zindex层叠顺序值越大越显示在前面内部维护着一个zindex表默认按照添加的先后顺序增加后面添加的显示在前面主动设置后按照设置的zindex来绘制。支持将QWidget对象作为覆盖物添加到地图控件中跟随地图移动位置极大提高灵活性比如可以将自定义控件直接作为地图控件的子对象加入进去。内置moveMarker轨迹移动类支持历史轨迹数据回放和实时轨迹移动可设置图标、轨迹线的颜色和粗细、移动速度、移动间隔、平滑移动等支持多条轨迹线条同时移动。大量使用按需绘制机制包括内部提供合理的默认值来触发绘制也可以手动传入参数指定是否需要立即绘制比如删除了某个覆盖物有些频繁的操作可以不指定立即绘制等操作完成后再统一一起绘制效率更高。默认开启缓存瓦片机制所有加载过的瓦片文件都存储在内存中下次再次绘制直接从内存取出来绘制既不需要从联网获取也不需要从缓存文件获取直接内存取出来绘制响应迅速效率最高体验最佳。支持批量添加覆盖物比如几万个标注点和圆形都是瞬间完成绘制相比web网页的方式性能提升百倍以上。支持街道图、卫星图、混合图、路网图等各种图层可以任意叠加N个图层甚至杂交不同地图厂家的瓦片文件。纯QWidget绘制非qml也非web不依赖qml或者浏览器控件支持极低性能的嵌入式环境。支持任意Qt版本、任意系统、任意编译器包括嵌入式linux和各种国产电脑环境。古法编程不含任何AI代码品质保证。