2026-07-30 12:06:02 +08:00
# include "MainWindow.h"
# include <array>
# include <QComboBox>
# include <QLabel>
# include <QPushButton>
# include <QResizeEvent>
# include <QSignalBlocker>
# include <QStatusBar>
# include "RemoteGuideClient.h"
# include "IVrUtils.h"
# include "Version.h"
# include "ui_MainWindow.h"
namespace {
QString NonEmpty ( const QString & value , const QString & fallback )
{
const QString trimmed = value . trimmed ( ) ;
return trimmed . isEmpty ( ) ? fallback : trimmed ;
}
bool IsKnownAircraftModel ( const QString & modelType )
{
const QString normalized = modelType . trimmed ( ) . toUpper ( ) ;
return normalized = = QStringLiteral ( " A320 " ) | |
2026-08-26 14:42:13 +08:00
normalized = = QStringLiteral ( " B737 " ) | |
normalized = = QStringLiteral ( " 其他 " ) ;
2026-07-30 12:06:02 +08:00
}
QString FormatModelVerification ( const QString & expectedModel ,
const QString & detectedModel ,
bool modelMatched )
{
const QString expected = expectedModel . trimmed ( ) . toUpper ( ) ;
const QString detected = detectedModel . trimmed ( ) . toUpper ( ) ;
if ( ! IsKnownAircraftModel ( detected ) ) {
return QStringLiteral ( " 未知 " ) ;
}
if ( ! IsKnownAircraftModel ( expected ) ) {
return QStringLiteral ( " 实测(%1) " ).arg(detected) ;
}
if ( modelMatched ) {
return QStringLiteral ( " 匹配(%1) " ).arg(detected) ;
}
if ( detected . compare ( expected , Qt : : CaseInsensitive ) ! = 0 ) {
return QStringLiteral ( " 不匹配(%1) " ).arg(detected) ;
}
return QStringLiteral ( " 未知 " ) ;
}
} // namespace
MainWindow : : MainWindow ( int discoveryPort , QWidget * parent )
: QMainWindow ( parent )
, ui ( new Ui : : MainWindow )
{
ui - > setupUi ( this ) ;
setWindowTitle ( QStringLiteral ( " 停机引导远程显示 %1 " )
. arg ( QString : : fromLatin1 (
PARKINGSPACEGUIDEVIEW_FULL_VERSION_STRING ) ) ) ;
const QString versionWithBuildTime = QStringLiteral ( " %1_%2%3%4%5%6%7 " )
. arg ( QString : : fromLatin1 (
PARKINGSPACEGUIDEVIEW_FULL_VERSION_STRING ) )
. arg ( YEAR )
. arg ( MONTH , 2 , 10 , QChar ( ' 0 ' ) )
. arg ( DAY , 2 , 10 , QChar ( ' 0 ' ) )
. arg ( HOUR , 2 , 10 , QChar ( ' 0 ' ) )
. arg ( MINUTE , 2 , 10 , QChar ( ' 0 ' ) )
. arg ( SECOND , 2 , 10 , QChar ( ' 0 ' ) ) ;
ui - > versionLabel - > setText ( versionWithBuildTime ) ;
statusBar ( ) - > addPermanentWidget ( ui - > versionLabel ) ;
connect ( ui - > windowButton , & QPushButton : : clicked ,
this , & QWidget : : showMinimized ) ;
connect ( ui - > closeWindowButton , & QPushButton : : clicked ,
this , & QWidget : : close ) ;
m_client = new RemoteGuideClient ( discoveryPort , this ) ;
connect ( m_client , & RemoteGuideClient : : ConnectionStateChanged ,
this , & MainWindow : : HandleConnectionState ) ;
connect ( m_client , & RemoteGuideClient : : StatusReceived ,
this , & MainWindow : : ApplyStatus ) ;
connect ( m_client , & RemoteGuideClient : : GuidanceRunningChanged ,
this , [ this ] ( bool running ) {
const bool wasRunning = m_guidanceRunning ;
m_guidanceRunning = running ;
if ( wasRunning & & ! running ) {
const QSignalBlocker blocker ( ui - > modelCombo ) ;
ui - > modelCombo - > setCurrentIndex ( 0 ) ;
}
UpdateControls ( ) ;
} ) ;
connect ( m_client , & RemoteGuideClient : : CommandFinished ,
this , & MainWindow : : HandleCommandFinished ) ;
connect ( ui - > modelCombo ,
QOverload < int > : : of ( & QComboBox : : currentIndexChanged ) ,
this ,
[ this ] ( int index ) {
if ( index > 0 & & m_client & & m_client - > IsConnected ( ) ) {
m_commandPending = true ;
UpdateControls ( ) ;
m_client - > SelectModel ( ui - > modelCombo - > currentText ( ) ) ;
}
UpdateControls ( ) ;
} ) ;
connect ( ui - > startButton , & QPushButton : : clicked , this , [ this ] ( ) {
m_commandPending = true ;
UpdateControls ( ) ;
m_client - > StartGuidance (
ui - > modelCombo - > currentIndex ( ) > 0
? ui - > modelCombo - > currentText ( )
: QString ( ) ) ;
} ) ;
connect ( ui - > stopButton , & QPushButton : : clicked , this , [ this ] ( ) {
m_commandPending = true ;
UpdateControls ( ) ;
m_client - > StopGuidance ( ) ;
} ) ;
ApplyStatus ( QJsonObject ( ) ) ;
HandleConnectionState ( false ,
QStringLiteral ( " 正在搜索停机引导设备…… " ) ,
QString ( ) ,
QString ( ) ) ;
}
MainWindow : : ~ MainWindow ( )
{
delete ui ;
}
void MainWindow : : ApplyStatus ( const QJsonObject & status )
{
ui - > stateImage - > SetStatus ( status ) ;
int stateCode = status . value ( " guideStateCode " ) . toInt ( 12 ) ;
if ( stateCode < 1 | | stateCode > 24 ) {
stateCode = 12 ;
}
ApplyGuideState ( stateCode , status . value ( " guideText " ) . toString ( ) ) ;
ui - > targetIdLabel - > setText ( NonEmpty (
status . value ( " targetId " ) . toString ( ) , QStringLiteral ( " T001 " ) ) ) ;
ui - > parkIdLabel - > setText ( NonEmpty (
status . value ( " parkId " ) . toString ( ) , QStringLiteral ( " 未知 " ) ) ) ;
QString expectedModel = status . value ( " expectedModelType " )
. toString ( ) . trimmed ( ) ;
if ( m_guidanceRunning & & IsKnownAircraftModel ( expectedModel ) & &
ui - > modelCombo - > currentText ( ) ! = expectedModel ) {
const QSignalBlocker blocker ( ui - > modelCombo ) ;
ui - > modelCombo - > setCurrentText ( expectedModel ) ;
}
if ( expectedModel . isEmpty ( ) & & ui - > modelCombo - > currentIndex ( ) > 0 ) {
expectedModel = ui - > modelCombo - > currentText ( ) ;
}
const QString detectedModel = NonEmpty (
status . value ( " modelType " ) . toString ( ) , QStringLiteral ( " 未知 " ) ) ;
ui - > modelMatchLabel - > setText ( FormatModelVerification (
expectedModel ,
detectedModel ,
status . value ( " modelMatched " ) . toBool ( ) ) ) ;
const int personCount = status . value ( " personCount " ) . toInt ( 0 ) ;
ui - > personLabel - > setText ( status . value ( " personInChockRegion " ) . toBool ( )
? QStringLiteral ( " 已检测 " )
: QStringLiteral ( " 未检测 " ) ) ;
ui - > personCountLabel - > setText ( QString : : number ( personCount ) ) ;
SetMetric ( ui - > distanceLabel , status , " distanceToStop " ,
QStringLiteral ( " 毫米 " ) ) ;
SetMetric ( ui - > offsetLabel , status , " lateralOffset " ,
QStringLiteral ( " 毫米 " ) ) ;
SetMetric ( ui - > yawLabel , status , " bodyYawAngle " , QStringLiteral ( " 度 " ) ) ;
SetMetric ( ui - > speedLabel , status , " aircraftSpeed " , QStringLiteral ( " 米/秒 " ) ) ;
}
void MainWindow : : ApplyGuideState ( int stateCode , const QString & guideText )
{
const GuidePresentation & presentation = PresentationForState ( stateCode ) ;
ui - > stateNameLabel - > setText ( presentation . name ) ;
QString stateText = QStringLiteral ( " %1 %2 " )
. arg ( stateCode )
. arg ( presentation . name ) ;
const QString trimmedGuideText = guideText . trimmed ( ) ;
if ( ! trimmedGuideText . isEmpty ( ) ) {
stateText + = QStringLiteral ( " / %1 " ) . arg ( trimmedGuideText ) ;
}
ui - > guideStateLabel - > setText ( stateText ) ;
if ( stateCode ! = m_currentStateCode ) {
m_currentStateCode = stateCode ;
ui - > stateCodeLabel - > setText (
QStringLiteral ( " 状态 #%1 " ) . arg ( stateCode , 2 , 10 , QChar ( ' 0 ' ) ) ) ;
}
}
void MainWindow : : UpdateControls ( )
{
ui - > modelCombo - > setEnabled ( m_connected & &
! m_guidanceRunning & &
! m_commandPending ) ;
ui - > startButton - > setEnabled ( m_connected & &
! m_guidanceRunning & &
! m_commandPending ) ;
ui - > stopButton - > setEnabled ( m_connected & &
m_guidanceRunning & &
! m_commandPending ) ;
}
void MainWindow : : SetMetric ( QLabel * label ,
const QJsonObject & status ,
const char * field ,
const QString & unit ,
int precision ,
double divisor )
{
const double safeDivisor = divisor = = 0.0 ? 1.0 : divisor ;
const double value = status . value ( QString : : fromLatin1 ( field ) )
. toDouble ( 0.0 ) / safeDivisor ;
label - > setText ( QString : : number ( value , ' f ' , precision ) + unit ) ;
}
void MainWindow : : HandleConnectionState ( bool connected ,
const QString & message ,
const QString & deviceName ,
const QString & address )
{
Q_UNUSED ( message ) ;
Q_UNUSED ( deviceName ) ;
Q_UNUSED ( address ) ;
m_connected = connected ;
m_commandPending = false ;
m_guidanceRunning = connected & & m_client
? m_client - > IsGuidanceRunning ( )
: false ;
if ( ! connected ) {
const QSignalBlocker blocker ( ui - > modelCombo ) ;
ui - > modelCombo - > setCurrentIndex ( 0 ) ;
}
ui - > deviceLabel - > setText ( connected
? QStringLiteral ( " 已连接 " )
: QStringLiteral ( " 未连接 " ) ) ;
UpdateControls ( ) ;
}
void MainWindow : : HandleCommandFinished ( const QString & command ,
bool ok ,
const QString & message ,
const QJsonObject & response )
{
Q_UNUSED ( response ) ;
Q_UNUSED ( message ) ;
m_commandPending = false ;
if ( ok & & command = = QStringLiteral ( " start " ) ) {
m_guidanceRunning = true ;
} else if ( ok & & command = = QStringLiteral ( " stop " ) ) {
m_guidanceRunning = false ;
const QSignalBlocker blocker ( ui - > modelCombo ) ;
ui - > modelCombo - > setCurrentIndex ( 0 ) ;
} else if ( ! ok & & command = = QStringLiteral ( " select_model " ) ) {
const QSignalBlocker blocker ( ui - > modelCombo ) ;
ui - > modelCombo - > setCurrentIndex ( 0 ) ;
}
if ( m_client & & m_client - > IsConnected ( ) ) {
m_guidanceRunning = m_client - > IsGuidanceRunning ( ) ;
}
UpdateControls ( ) ;
}
void MainWindow : : resizeEvent ( QResizeEvent * event )
{
QMainWindow : : resizeEvent ( event ) ;
}
const MainWindow : : GuidePresentation &
MainWindow : : PresentationForState ( int stateCode )
{
static const std : : array < GuidePresentation , 24 > states = { {
{ QStringLiteral ( " 泊位引导启动 " ) , QStringLiteral ( " START-OF-DOCKING " ) , QStringLiteral ( " WAIT " ) , QStringLiteral ( " 系统已进入泊位引导等待状态。 " ) , QStringLiteral ( " 等待运行箭头或接近率条出现,并确认机型正确。 " ) , QStringLiteral ( " warn " ) } ,
{ QStringLiteral ( " 捕获 " ) , QStringLiteral ( " CAPTURE " ) , QStringLiteral ( " CAPTURE " ) , QStringLiteral ( " 运行箭头和飞机类型表示系统正在搜索接近中的飞机。 " ) , QStringLiteral ( " 确认机型正确,沿引导线低速滑行。 " ) , QStringLiteral ( " good " ) } ,
{ QStringLiteral ( " 跟踪 " ) , QStringLiteral ( " TRACKING " ) , QStringLiteral ( " TRACKING " ) , QStringLiteral ( " 中心线和转向箭头提示飞机位置及修正方向。 " ) , QStringLiteral ( " 按红色箭头小幅修正方向,保持低速。 " ) , QStringLiteral ( " good " ) } ,
{ QStringLiteral ( " 接近率 " ) , QStringLiteral ( " CLOSING RATE " ) , QStringLiteral ( " CLOSING " ) , QStringLiteral ( " 数字和接近率条显示距停止位置的剩余距离。 " ) , QStringLiteral ( " 保持低速并按箭头修正,准备在 STOP 出现时停车。 " ) , QStringLiteral ( " good " ) } ,
{ QStringLiteral ( " 对准中心线 " ) , QStringLiteral ( " ALIGNED TO CENTRE " ) , QStringLiteral ( " ALIGNED " ) , QStringLiteral ( " 显示距离但无转向箭头,表示飞机已对准中心线。 " ) , QStringLiteral ( " 继续低速向停止位滑行。 " ) , QStringLiteral ( " good " ) } ,
{ QStringLiteral ( " 慢速 " ) , QStringLiteral ( " SLOW " ) , QStringLiteral ( " SLOW " ) , QStringLiteral ( " 飞机接近速度高于当前区域的允许速度。 " ) , QStringLiteral ( " 立即减速,观察是否恢复正常接近率显示。 " ) , QStringLiteral ( " warn " ) } ,
{ QStringLiteral ( " 方位引导 " ) , QStringLiteral ( " AZIMUTH GUIDANCE " ) , QStringLiteral ( " GUIDANCE " ) , QStringLiteral ( " 位置箭头和转向箭头共同提示方位修正。 " ) , QStringLiteral ( " 按转向箭头修正并保持低速。 " ) , QStringLiteral ( " good " ) } ,
{ QStringLiteral ( " 到达停止位置 " ) , QStringLiteral ( " STOP POSITION " ) , QStringLiteral ( " STOP " ) , QStringLiteral ( " 飞机已经到达正确停止位置。 " ) , QStringLiteral ( " 立即停车,等待地面确认。 " ) , QStringLiteral ( " stop " ) } ,
{ QStringLiteral ( " 泊位引导完成 " ) , QStringLiteral ( " DOCKING COMPLETED " ) , QStringLiteral ( " OK " ) , QStringLiteral ( " 泊位引导流程已经完成。 " ) , QStringLiteral ( " 保持停稳,等待地面服务。 " ) , QStringLiteral ( " good " ) } ,
{ QStringLiteral ( " 越位 " ) , QStringLiteral ( " OVERSHOOT " ) , QStringLiteral ( " TOO FAR " ) , QStringLiteral ( " 飞机已经越过目标停止位置。 " ) , QStringLiteral ( " 立即停止,等待人工处置。 " ) , QStringLiteral ( " stop " ) } ,
{ QStringLiteral ( " 提前停止 " ) , QStringLiteral ( " STOP SHORT " ) , QStringLiteral ( " STOP OK " ) , QStringLiteral ( " 飞机已静止,但尚未到达预定停止位置。 " ) , QStringLiteral ( " 等待地面确认是否继续或结束。 " ) , QStringLiteral ( " warn " ) } ,
{ QStringLiteral ( " 等待 " ) , QStringLiteral ( " WAIT " ) , QStringLiteral ( " WAIT " ) , QStringLiteral ( " 系统等待视野恢复或重新检测到飞机。 " ) , QStringLiteral ( " 保持等待,在接近率条恢复前不要继续。 " ) , QStringLiteral ( " warn " ) } ,
{ QStringLiteral ( " 异常慢速-恶劣天气 " ) , QStringLiteral ( " SLOW - WEATHER " ) , QStringLiteral ( " SLOW " ) , QStringLiteral ( " 天气原因导致系统进入异常慢速捕获模式。 " ) , QStringLiteral ( " 低速等待接近率条出现。 " ) , QStringLiteral ( " warn " ) } ,
{ QStringLiteral ( " 异常慢速-飞机丢失 " ) , QStringLiteral ( " SLOW - LOST " ) , QStringLiteral ( " SLOW " ) , QStringLiteral ( " 引导过程中暂时丢失飞机目标。 " ) , QStringLiteral ( " 低速等待系统重新检测飞机。 " ) , QStringLiteral ( " warn " ) } ,
{ QStringLiteral ( " 飞机验证失败 " ) , QStringLiteral ( " ID FAIL " ) , QStringLiteral ( " STOP ID FAIL " ) , QStringLiteral ( " 检测机型与选择机型验证失败。 " ) , QStringLiteral ( " 停止飞机,等待人工复核,不得自行继续。 " ) , QStringLiteral ( " stop " ) } ,
{ QStringLiteral ( " 机位受阻 " ) , QStringLiteral ( " GATE BLOCKED " ) , QStringLiteral ( " WAIT GATE BLOCK " ) , QStringLiteral ( " 机位前方或进近视野存在障碍。 " ) , QStringLiteral ( " 等待障碍物清除,未恢复前不要继续。 " ) , QStringLiteral ( " warn " ) } ,
{ QStringLiteral ( " 视野受阻 " ) , QStringLiteral ( " VIEW BLOCKED " ) , QStringLiteral ( " WAIT VIEW BLOCK " ) , QStringLiteral ( " 传感器视野受阻,当前无法可靠检测飞机。 " ) , QStringLiteral ( " 等待视野恢复,必要时切换人工引导。 " ) , QStringLiteral ( " warn " ) } ,
{ QStringLiteral ( " SBU停止 " ) , QStringLiteral ( " SBU STOP " ) , QStringLiteral ( " STOP SBU " ) , QStringLiteral ( " 自动引导因不可恢复错误进入安全备份状态。 " ) , QStringLiteral ( " 立即停止并使用人工引导,不得自行恢复。 " ) , QStringLiteral ( " stop " ) } ,
{ QStringLiteral ( " 速度过快 " ) , QStringLiteral ( " TOO FAST " ) , QStringLiteral ( " STOP TOO FAST " ) , QStringLiteral ( " 飞机速度超出系统可以安全处理的范围。 " ) , QStringLiteral ( " 立即停止飞机,等待系统重启或人工引导。 " ) , QStringLiteral ( " stop " ) } ,
{ QStringLiteral ( " 紧急停止 " ) , QStringLiteral ( " EMERGENCY STOP " ) , QStringLiteral ( " STOP " ) , QStringLiteral ( " 现场急停或急停线路断开已经触发。 " ) , QStringLiteral ( " 立即停止,等待现场确认和处置。 " ) , QStringLiteral ( " stop " ) } ,
{ QStringLiteral ( " 挡轮挡 " ) , QStringLiteral ( " CHOCKS ON " ) , QStringLiteral ( " CHOCK ON " ) , QStringLiteral ( " 轮挡区域人员检测已完成。 " ) , QStringLiteral ( " 保持停稳,进入地面保障流程。 " ) , QStringLiteral ( " good " ) } ,
{ QStringLiteral ( " 系统错误 " ) , QStringLiteral ( " ERROR " ) , QStringLiteral ( " ERROR " ) , QStringLiteral ( " 系统发生错误,自动引导不可继续。 " ) , QStringLiteral ( " 停止自动引导并通知维护人员。 " ) , QStringLiteral ( " stop " ) } ,
{ QStringLiteral ( " 系统故障 " ) , QStringLiteral ( " SYSTEM BREAKDOWN " ) , QStringLiteral ( " BLACK " ) , QStringLiteral ( " 系统发生严重故障,自动引导不可用。 " ) , QStringLiteral ( " 使用人工备份程序。 " ) , QStringLiteral ( " maint " ) } ,
{ QStringLiteral ( " 电源故障 " ) , QStringLiteral ( " POWER FAILURE " ) , QStringLiteral ( " BLACK " ) , QStringLiteral ( " 显示和引导系统电源中断。 " ) , QStringLiteral ( " 使用人工备份程序并检查供电。 " ) , QStringLiteral ( " maint " ) }
} } ;
if ( stateCode < 1 | | stateCode > static_cast < int > ( states . size ( ) ) ) {
stateCode = 12 ;
}
return states [ static_cast < size_t > ( stateCode - 1 ) ] ;
}