单频测向插件地图与表盘实现
下面按地图/表盘(BearingMeter)两块说明,并单独把paintEvent的“图层”顺序说清楚。
1. 地图(UIFIXDFPlugin)
入口:InitControl()里给quickWidget加载qrc:/Resource/main.qml,从根对象里用findChild找到objectName == "MapItem"的Map,后续用QMetaObject::invokeMethod调 QML 上的函数(如rotationAngle、setLine、setMarkerLocation等)。
QML 结构(逻辑分层)(main.qml):
| 层次 | 内容 |
|---|---|
| 根 | Rectangle(RootItem) |
| 地图主体 | Map { objectName: "MapItem" },离线Plugin { name: 'mud' } |
| 地理要素 | 多个MapQuickItem(mapMarker…mapMarker10:Image+Text编号,rotation绑定罗盘)、多条MapPolyline(bearingLine…bearingLine10示向线)、MapCircle(目标圈等) |
| 交互 | 最上层MouseArea铺满Map,onPositionChanged里map.toCoordinate发coordinateUpdated |
与测向相关的 C++ 调用示例(表盘数据同步到地图):HandleBearingMeter里更新主标记转角、示向线段、中心跟随等:
_dfWidget->bearingMeterCtrl->SetData(cData.azimuth, cData.angleProbability, cData.compassAngle, cData.averageValue, cData.maxProbability, cData.levelData, cData.quality); QMetaObject::invokeMethod(mapElement, "rotationAngle", Q_ARG(QVariant, cData.compassAngle)); double lat=0.05*sin((cData.maxProbability-90)/180*3.1415926*-1)+ cData.Latitude; double lon=0.05*cos((cData.maxProbability-90)/180*3.1415926*-1)+ cData.Longitude; QMetaObject::invokeMethod(mapElement, "setLine", Q_ARG(QVariant, cData.Latitude),Q_ARG(QVariant, cData.Longitude),Q_ARG(QVariant, lat),Q_ARG(QVariant, lon)); QMetaObject::invokeMethod(mapElement, "setMarkerLocation",Q_ARG(QVariant, cData.Latitude),Q_ARG(QVariant, cData.Longitude)); if(_isFollowLoctaion)QMetaObject::invokeMethod(mapElement, "setMapCenter", Q_ARG(QVariant, cData.Latitude),Q_ARG(QVariant, cData.Longitude));QML 里对应接口(主标记转角 + 主示向线):
function rotationAngle(angle){ mapMarker.rotation = angle+180 } function setLine(x1,y1,x2,y2) { bearingLine.path = [ QtPositioning.coordinate(x1, y1), QtPositioning.coordinate(x2, y2) ] }结论:地图不是 Widget 里的paintEvent,而是Qt QuickMap+ 若干MapQuickItem/MapPolyline;与单频测向插件的耦合点是mapElement上的 JS 函数 + 信号coordinateUpdated。
2. 表盘 / 罗盘(测向表头)——BearingMeter
UI 里控件名是bearingMeterCtrl,类型为BearingMeter(SystemControl/BearingMeter),和地图是两个并列控件(uifixdfplugin.ui里QQuickWidget与BearingMeter同层 layout),表盘全部是单个QWidget+QPainter顺序绘制,没有QGraphicsScene/ 多图层对象,所谓“图层”就是paintEvent里调用私有Draw*的先后顺序(后画的盖住先画的)。
可视为“图层”的叠放顺序(自下而上)
- 图例
DrawLegend(顶部条带,红/绿/黄三角示意) - 外框网格
drawRect矩形 - 表盘底色与外环
DrawGauge(绿/红半圆弧) - 角度–幅度极坐标填充
DrawAngleLevel(内圈圆 + 蓝色多边形包络) - 十字线
DrawCorossLine - 刻度
DrawWatchScale(钟表 12 格)或DrawAngleScale(72 格,5° 一档) - 可选
DrawConfidenceArea(当前实现基本为空) - 指针:绿=实时
DrawRealtime,红=最优DrawBestBearing,黄=均值DrawAvgBearing - 轴心圆点
DrawRound - 方位字 N/E/S/W + 小指南针三角
DrawSigns(车头模式时整体旋转360° - compassAngle) - 车头/正北模式占位
DrawNorthBearing/DrawRelativeBearing(rotate(_compassAngle)等,车体贴图被#if关掉时几乎无视觉) - 概率封闭曲线
DrawProbit(可选) - 鼠标光标径向线
DrawCursorLine(圆内跟踪) - 数值面板
DrawOptimaValue/DrawCurrValue+「方位图」标题 - 侧向电平/质量柱状门限
DrawLevelThreshold/DrawQualityThreshold(若打开)
数据更新:插件侧SetData(...)写入方位、概率图、compassAngle等,并发SignalUpdateUI()→update()触发重绘;另外有100msQTimer周期性update(),所以表盘会稳定刷新。
3. 小结对照
| 项目 | 实现方式 |
|---|---|
| 地图 | QQuickWidget+main.qml的Map;要素为MapQuickItem/MapPolyline/MouseArea |
| 表盘 | BearingMeter自定义QWidget,无 Scene 图层,整屏一架QPainter,paintEvent里按上表顺序Draw* |
| 地图与表盘联动 | 同一套cData:表盘SetData;地图invokeMethod(rotationAngle/setLine/setMarkerLocation/...) |