ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

单频测向插件地图与表盘实现

单频测向插件地图与表盘实现

单频测向插件地图与表盘实现


下面按地图/表盘(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*的先后顺序(后画的盖住先画的)。

可视为“图层”的叠放顺序(自下而上)

  1. 图例DrawLegend(顶部条带,红/绿/黄三角示意)
  2. 外框网格drawRect矩形
  3. 表盘底色与外环DrawGauge(绿/红半圆弧)
  4. 角度–幅度极坐标填充DrawAngleLevel(内圈圆 + 蓝色多边形包络)
  5. 十字线DrawCorossLine
  6. 刻度DrawWatchScale(钟表 12 格)或DrawAngleScale(72 格,5° 一档)
  7. 可选DrawConfidenceArea(当前实现基本为空)
  8. 指针:绿=实时DrawRealtime,红=最优DrawBestBearing,黄=均值DrawAvgBearing
  9. 轴心圆点DrawRound
  10. 方位字 N/E/S/W + 小指南针三角DrawSigns(车头模式时整体旋转360° - compassAngle)
  11. 车头/正北模式占位DrawNorthBearing/DrawRelativeBearing(rotate(_compassAngle)等,车体贴图被#if关掉时几乎无视觉)
  12. 概率封闭曲线DrawProbit(可选)
  13. 鼠标光标径向线DrawCursorLine(圆内跟踪)
  14. 数值面板DrawOptimaValue/DrawCurrValue+「方位图」标题
  15. 侧向电平/质量柱状门限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/...)
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进