diff --git a/.qmake.stash b/.qmake.stash deleted file mode 100644 index 0d0b187..0000000 --- a/.qmake.stash +++ /dev/null @@ -1,23 +0,0 @@ -QMAKE_CXX.QT_COMPILER_STDCXX = 201703L -QMAKE_CXX.QMAKE_GCC_MAJOR_VERSION = 11 -QMAKE_CXX.QMAKE_GCC_MINOR_VERSION = 4 -QMAKE_CXX.QMAKE_GCC_PATCH_VERSION = 0 -QMAKE_CXX.COMPILER_MACROS = \ - QT_COMPILER_STDCXX \ - QMAKE_GCC_MAJOR_VERSION \ - QMAKE_GCC_MINOR_VERSION \ - QMAKE_GCC_PATCH_VERSION -QMAKE_CXX.INCDIRS = \ - /usr/include/c++/11 \ - /usr/include/x86_64-linux-gnu/c++/11 \ - /usr/include/c++/11/backward \ - /usr/lib/gcc/x86_64-linux-gnu/11/include \ - /usr/local/include \ - /usr/include/x86_64-linux-gnu \ - /usr/include -QMAKE_CXX.LIBDIRS = \ - /usr/lib/gcc/x86_64-linux-gnu/11 \ - /usr/lib/x86_64-linux-gnu \ - /usr/lib \ - /lib/x86_64-linux-gnu \ - /lib diff --git a/Doc/~$设计规格说明书0918.doc b/Doc/~$设计规格说明书0918.doc new file mode 100644 index 0000000..938a93f Binary files /dev/null and b/Doc/~$设计规格说明书0918.doc differ diff --git a/Doc/软件设计规格说明书0918.doc b/Doc/软件设计规格说明书0918.doc deleted file mode 100644 index 34c523c..0000000 Binary files a/Doc/软件设计规格说明书0918.doc and /dev/null differ diff --git a/Doc/软件设计规格说明书1011.doc b/Doc/软件设计规格说明书1011.doc new file mode 100644 index 0000000..04431ff Binary files /dev/null and b/Doc/软件设计规格说明书1011.doc differ diff --git a/Doc/软件需求规格说明书0919.docx b/Doc/软件需求规格说明书0919.docx deleted file mode 100644 index 1c2db91..0000000 Binary files a/Doc/软件需求规格说明书0919.docx and /dev/null differ diff --git a/Doc/软件需求规格说明书1011.docx b/Doc/软件需求规格说明书1011.docx new file mode 100644 index 0000000..47ccd3a Binary files /dev/null and b/Doc/软件需求规格说明书1011.docx differ diff --git a/README.md b/README.md deleted file mode 100644 index bc7d9e2..0000000 --- a/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# Drone_project - diff --git a/Src/build.sh b/Src/build.sh new file mode 100755 index 0000000..3c0317c --- /dev/null +++ b/Src/build.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash + +# Drone_project 构建脚本(放在 Src 目录),在工程根创建 build 目录(shadow build) +set -e + +echo "=== 构建 Drone_project 项目(Src/build.sh) ===" + +# 解析路径:脚本目录 -> 工程根目录 -> 构建目录 +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +ROOT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)" +BUILD_DIR="${ROOT_DIR}/build" +PRO_FILE="${ROOT_DIR}/drone_ui.pro" + +# 检查 qmake +if ! command -v qmake >/dev/null 2>&1; then + echo "✗ 未找到系统 qmake。请先安装:sudo apt install -y qtbase5-dev qtwebengine5-dev qtwebchannel5-dev qml-module-qtwebchannel qtpositioning5-dev" + exit 1 +fi +QMAKE_BIN="qmake" +echo "使用 qmake: ${QMAKE_BIN} (from PATH)" + +# 准备构建目录(shadow build,位于工程根) +echo "1. 准备构建目录: ${BUILD_DIR} ..." +mkdir -p "${BUILD_DIR}" || exit 1 +rm -rf "${BUILD_DIR}"/* + +# 生成构建文件 +echo "2. 生成构建文件 (.pro: ${PRO_FILE}) ..." +( + cd "${BUILD_DIR}" && "${QMAKE_BIN}" "${PRO_FILE}" +) || { echo "✗ qmake 失败"; exit 1; } + +# 编译 +echo "3. 编译项目..." +JOBS=4 +if command -v nproc >/dev/null 2>&1; then JOBS="$(nproc)"; fi +( + cd "${BUILD_DIR}" && make -j"${JOBS}" +) || { echo "✗ 编译失败"; exit 1; } + +# 检查生成产物 +if [ -f "${BUILD_DIR}/Drone_project" ]; then + echo "✓ 编译成功!可执行文件位置: ${BUILD_DIR}/Drone_project" +else + echo "✗ 没找到可执行文件 ${BUILD_DIR}/Drone_project" + exit 1 +fi + +echo "=== 构建完成 ===" diff --git a/src/core/main.cpp b/Src/core/main.cpp similarity index 100% rename from src/core/main.cpp rename to Src/core/main.cpp diff --git a/src/models/detectiondata.cpp b/Src/models/detectiondata.cpp similarity index 100% rename from src/models/detectiondata.cpp rename to Src/models/detectiondata.cpp diff --git a/src/models/detectiondata.h b/Src/models/detectiondata.h similarity index 100% rename from src/models/detectiondata.h rename to Src/models/detectiondata.h diff --git a/src/models/dronedata.cpp b/Src/models/dronedata.cpp similarity index 100% rename from src/models/dronedata.cpp rename to Src/models/dronedata.cpp diff --git a/src/models/dronedata.h b/Src/models/dronedata.h similarity index 100% rename from src/models/dronedata.h rename to Src/models/dronedata.h diff --git a/src/pages/datapage.cpp b/Src/pages/datapage.cpp similarity index 100% rename from src/pages/datapage.cpp rename to Src/pages/datapage.cpp diff --git a/src/pages/datapage.h b/Src/pages/datapage.h similarity index 100% rename from src/pages/datapage.h rename to Src/pages/datapage.h diff --git a/Src/pages/dronedata.cpp b/Src/pages/dronedata.cpp new file mode 100755 index 0000000..173881c --- /dev/null +++ b/Src/pages/dronedata.cpp @@ -0,0 +1,216 @@ +#include "dronedata.h" +#include +#include +#include + +/** + * 无人机数据模型实现 + * 管理单架无人机的状态信息和数据更新 + */ + +DroneData::DroneData(const QString& id, const QString& name, QObject* parent) + : QObject(parent) + , id_(id) + , name_(name) + , connected_(false) + , position_(0, 0, 0) + , expectedPosition_(0, 0, 0) + , velocity_(0, 0, 0) + , expectedVelocity_(0, 0, 0) + , attitude_(0, 0, 0) + , simulationTimer_(new QTimer(this)) + , simulationStep_(0) +{ + // 设置模拟数据更新定时器 + simulationTimer_->setInterval(500); // 500ms更新一次,减少更新频率 + connect(simulationTimer_, &QTimer::timeout, this, &DroneData::updateSimulationData); +} + +void DroneData::setConnected(bool connected) { + if (connected_ != connected) { + connected_ = connected; + emit connectionChanged(connected); + emit dataChanged(); + } +} + +void DroneData::setPosition(const QVector3D& pos) { + if (position_ != pos) { + position_ = pos; + emit dataChanged(); + } +} + +void DroneData::setExpectedPosition(const QVector3D& pos) { + if (expectedPosition_ != pos) { + expectedPosition_ = pos; + emit dataChanged(); + } +} + +void DroneData::setVelocity(const QVector3D& vel) { + if (velocity_ != vel) { + velocity_ = vel; + emit dataChanged(); + } +} + +void DroneData::setExpectedVelocity(const QVector3D& vel) { + if (expectedVelocity_ != vel) { + expectedVelocity_ = vel; + emit dataChanged(); + } +} + +void DroneData::setAttitude(const QVector3D& att) { + if (attitude_ != att) { + attitude_ = att; + emit dataChanged(); + } +} + +void DroneData::startSimulation() { + if (!simulationTimer_->isActive()) { + simulationTimer_->start(); + qDebug() << "开始模拟无人机" << name_ << "的数据更新"; + } +} + +void DroneData::stopSimulation() { + if (simulationTimer_->isActive()) { + simulationTimer_->stop(); + qDebug() << "停止模拟无人机" << name_ << "的数据更新"; + } +} + +void DroneData::updateSimulationData() { + if (!connected_) return; + + simulationStep_++; + + // 模拟位置变化(简单的正弦波运动) + float t = simulationStep_ * 0.01f; + float x = 10.0f * qSin(t) + 50.0f; + float y = 10.0f * qCos(t) + 50.0f; + float z = 5.0f * qSin(t * 0.5f) + 30.0f; + + setPosition(QVector3D(x, y, z)); + + // 模拟速度变化 + float vx = 10.0f * qCos(t); + float vy = -10.0f * qSin(t); + float vz = 5.0f * qCos(t * 0.5f) * 0.5f; + + setVelocity(QVector3D(vx, vy, vz)); + + // 模拟姿态变化 + float roll = 5.0f * qSin(t * 0.3f); + float pitch = 3.0f * qCos(t * 0.4f); + float yaw = t * 10.0f; + + setAttitude(QVector3D(roll, pitch, yaw)); + + // 期望位置稍微滞后于实际位置 + setExpectedPosition(QVector3D(x + 2.0f, y + 1.0f, z + 0.5f)); + setExpectedVelocity(QVector3D(vx * 0.9f, vy * 0.9f, vz * 0.9f)); +} + +/** + * 无人机管理器实现 + * 管理多架无人机的创建、删除和切换 + */ + +DroneManager::DroneManager(QObject* parent) + : QObject(parent) + , currentDroneId_("") +{ +} + +DroneManager::~DroneManager() { + qDeleteAll(drones_); +} + +void DroneManager::addDrone(const QString& id, const QString& name) { + // 检查是否已存在 + for (auto* drone : drones_) { + if (drone->getId() == id) { + qDebug() << "无人机" << id << "已存在"; + return; + } + } + + // 创建新无人机 + auto* drone = new DroneData(id, name, this); + drones_.append(drone); + + // 如果是第一架无人机,设为当前选中 + if (currentDroneId_.isEmpty()) { + setCurrentDrone(id); + } + + // 设置连接状态,但不启动模拟(暂时禁用) + drone->setConnected(true); + // 暂时禁用模拟数据更新,避免格式化问题 + // QTimer::singleShot(1000, drone, &DroneData::startSimulation); + + emit droneAdded(id); + qDebug() << "添加无人机:" << id << name; +} + +void DroneManager::removeDrone(const QString& id) { + for (int i = 0; i < drones_.size(); ++i) { + if (drones_[i]->getId() == id) { + auto* drone = drones_[i]; + drone->stopSimulation(); + drone->deleteLater(); + drones_.removeAt(i); + + // 如果删除的是当前选中的无人机,切换到其他无人机 + if (currentDroneId_ == id) { + if (!drones_.isEmpty()) { + setCurrentDrone(drones_[0]->getId()); + } else { + currentDroneId_ = ""; + emit currentDroneChanged(""); + } + } + + emit droneRemoved(id); + qDebug() << "删除无人机:" << id; + return; + } + } +} + +DroneData* DroneManager::getDrone(const QString& id) const { + for (auto* drone : drones_) { + if (drone->getId() == id) { + return drone; + } + } + return nullptr; +} + +DroneData* DroneManager::getCurrentDrone() const { + return getDrone(currentDroneId_); +} + +QVector DroneManager::getAllDrones() const { + return drones_; +} + +void DroneManager::setCurrentDrone(const QString& id) { + if (currentDroneId_ != id && getDrone(id) != nullptr) { + currentDroneId_ = id; + emit currentDroneChanged(id); + qDebug() << "切换当前无人机到:" << id; + } +} + +QStringList DroneManager::getDroneIds() const { + QStringList ids; + for (auto* drone : drones_) { + ids.append(drone->getId()); + } + return ids; +} diff --git a/Src/pages/dronedata.h b/Src/pages/dronedata.h new file mode 100755 index 0000000..42842c9 --- /dev/null +++ b/Src/pages/dronedata.h @@ -0,0 +1,108 @@ +#ifndef DRONEDATA_H +#define DRONEDATA_H + +#include +#include +#include +#include +#include +#include + +/** + * 无人机数据模型类 + * 用于管理单架无人机的所有状态信息,包括位置、速度、姿态等 + */ +class DroneData : public QObject { + Q_OBJECT + +public: + explicit DroneData(const QString& id, const QString& name, QObject* parent = nullptr); + + // 基本信息 + QString getId() const { return id_; } + QString getName() const { return name_; } + bool isConnected() const { return connected_; } + + // 位置信息 + QVector3D getPosition() const { return position_; } + QVector3D getExpectedPosition() const { return expectedPosition_; } + + // 速度信息 + QVector3D getVelocity() const { return velocity_; } + QVector3D getExpectedVelocity() const { return expectedVelocity_; } + + // 姿态信息 + QVector3D getAttitude() const { return attitude_; } + + // 设置方法 + void setConnected(bool connected); + void setPosition(const QVector3D& pos); + void setExpectedPosition(const QVector3D& pos); + void setVelocity(const QVector3D& vel); + void setExpectedVelocity(const QVector3D& vel); + void setAttitude(const QVector3D& att); + + // 模拟数据更新(用于演示) + void startSimulation(); + void stopSimulation(); + +signals: + void dataChanged(); + void connectionChanged(bool connected); + +private slots: + void updateSimulationData(); + +private: + QString id_; + QString name_; + bool connected_; + + // 位置、速度、姿态数据 + QVector3D position_; + QVector3D expectedPosition_; + QVector3D velocity_; + QVector3D expectedVelocity_; + QVector3D attitude_; + + // 模拟数据更新定时器 + QTimer* simulationTimer_; + int simulationStep_; +}; + +/** + * 无人机管理器类 + * 用于管理多架无人机,提供切换和查询功能 + */ +class DroneManager : public QObject { + Q_OBJECT + +public: + explicit DroneManager(QObject* parent = nullptr); + ~DroneManager(); + + // 无人机管理 + void addDrone(const QString& id, const QString& name); + void removeDrone(const QString& id); + DroneData* getDrone(const QString& id) const; + DroneData* getCurrentDrone() const; + QVector getAllDrones() const; + + // 当前选中无人机 + void setCurrentDrone(const QString& id); + QString getCurrentDroneId() const { return currentDroneId_; } + + // 获取所有无人机ID列表 + QStringList getDroneIds() const; + +signals: + void currentDroneChanged(const QString& id); + void droneAdded(const QString& id); + void droneRemoved(const QString& id); + +private: + QVector drones_; + QString currentDroneId_; +}; + +#endif // DRONEDATA_H diff --git a/Src/pages/dronemanagementpage.cpp b/Src/pages/dronemanagementpage.cpp new file mode 100755 index 0000000..2d039bd --- /dev/null +++ b/Src/pages/dronemanagementpage.cpp @@ -0,0 +1,447 @@ +#include "dronemanagementpage.h" +#include +#include +#include +#include + +/** + * 无人机管理页面实现 + * 负责无人机连接管理、状态显示、添加删除无人机等功能 + */ + +DroneManagementPage::DroneManagementPage(QWidget* parent) + : QWidget(parent) + , mainFrame_(nullptr) + , droneTable_(nullptr) + , controlGroup_(nullptr) + , statusGroup_(nullptr) + , droneIdEdit_(nullptr) + , droneNameEdit_(nullptr) + , addDroneBtn_(nullptr) + , removeDroneBtn_(nullptr) + , connectBtn_(nullptr) + , disconnectBtn_(nullptr) + , refreshBtn_(nullptr) + , totalDronesLabel_(nullptr) + , connectedDronesLabel_(nullptr) + , selectedDroneLabel_(nullptr) + , positionLabel_(nullptr) + , velocityLabel_(nullptr) + , attitudeLabel_(nullptr) + , droneManager_(nullptr) + , refreshTimer_(nullptr) + , selectedDroneId_("") +{ + setupUI(); + + // 设置定时刷新 + refreshTimer_ = new QTimer(this); + connect(refreshTimer_, &QTimer::timeout, this, &DroneManagementPage::onRefreshData); + // 暂时禁用定时刷新,避免格式化问题 + // refreshTimer_->start(2000); // 每2秒刷新一次,减少刷新频率 +} + +DroneManagementPage::~DroneManagementPage() { + if (refreshTimer_) { + refreshTimer_->stop(); + } +} + +void DroneManagementPage::setDroneManager(DroneManager* manager) { + droneManager_ = manager; + + if (droneManager_) { + // 连接信号 + connect(droneManager_, &DroneManager::droneAdded, this, &DroneManagementPage::onDroneDataChanged); + connect(droneManager_, &DroneManager::droneRemoved, this, &DroneManagementPage::onDroneDataChanged); + connect(droneManager_, &DroneManager::currentDroneChanged, this, &DroneManagementPage::onDroneDataChanged); + + // 初始化表格数据 + updateDroneTable(); + updateStatusDisplay(); + } +} + +void DroneManagementPage::setupUI() { + auto* mainLayout = new QVBoxLayout(this); + mainLayout->setSpacing(10); + mainLayout->setContentsMargins(10, 10, 10, 10); + + // 创建主框架 + mainFrame_ = new QFrame(this); + mainFrame_->setStyleSheet("QFrame{background:#f8f9fa; border:1px solid #dee2e6; border-radius:8px;}"); + + auto* frameLayout = new QVBoxLayout(mainFrame_); + frameLayout->setSpacing(15); + frameLayout->setContentsMargins(15, 15, 15, 15); + + setupDroneTable(); + setupControlPanel(); + setupStatusPanel(); + + frameLayout->addWidget(droneTable_, 2); + frameLayout->addWidget(controlGroup_, 1); + frameLayout->addWidget(statusGroup_, 1); + + mainLayout->addWidget(mainFrame_); +} + +void DroneManagementPage::setupDroneTable() { + droneTable_ = new QTableWidget(this); + droneTable_->setColumnCount(8); + droneTable_->setHorizontalHeaderLabels({ + "无人机ID", "名称", "连接状态", "位置(X,Y,Z)", + "速度(X,Y,Z)", "姿态(Roll,Pitch,Yaw)", "预期位置", "预期速度" + }); + + // 设置表格属性 + droneTable_->setAlternatingRowColors(true); + droneTable_->setSelectionBehavior(QAbstractItemView::SelectRows); + droneTable_->setSelectionMode(QAbstractItemView::SingleSelection); + droneTable_->setSortingEnabled(false); + + // 设置列宽 + QHeaderView* header = droneTable_->horizontalHeader(); + header->setStretchLastSection(true); + header->setSectionResizeMode(QHeaderView::ResizeToContents); + + // 连接选择变化信号 + connect(droneTable_, &QTableWidget::itemSelectionChanged, this, &DroneManagementPage::onDroneSelectionChanged); +} + +void DroneManagementPage::setupControlPanel() { + controlGroup_ = new QGroupBox("无人机控制", this); + auto* groupLayout = new QVBoxLayout(controlGroup_); + groupLayout->setSpacing(10); + + // 添加无人机区域 + auto* addLayout = new QHBoxLayout(); + addLayout->addWidget(new QLabel("ID:", this)); + droneIdEdit_ = new QLineEdit(this); + droneIdEdit_->setPlaceholderText("输入无人机ID"); + addLayout->addWidget(droneIdEdit_); + + addLayout->addWidget(new QLabel("名称:", this)); + droneNameEdit_ = new QLineEdit(this); + droneNameEdit_->setPlaceholderText("输入无人机名称"); + addLayout->addWidget(droneNameEdit_); + + addDroneBtn_ = new QPushButton("添加无人机", this); + addDroneBtn_->setStyleSheet("QPushButton{background:#28a745; color:white; border:none; padding:8px 16px; border-radius:4px;}"); + connect(addDroneBtn_, &QPushButton::clicked, this, &DroneManagementPage::onAddDroneClicked); + addLayout->addWidget(addDroneBtn_); + + groupLayout->addLayout(addLayout); + + // 操作按钮区域 + auto* actionLayout = new QHBoxLayout(); + + removeDroneBtn_ = new QPushButton("删除选中", this); + removeDroneBtn_->setStyleSheet("QPushButton{background:#dc3545; color:white; border:none; padding:8px 16px; border-radius:4px;}"); + connect(removeDroneBtn_, &QPushButton::clicked, this, &DroneManagementPage::onRemoveDroneClicked); + actionLayout->addWidget(removeDroneBtn_); + + connectBtn_ = new QPushButton("连接", this); + connectBtn_->setStyleSheet("QPushButton{background:#007bff; color:white; border:none; padding:8px 16px; border-radius:4px;}"); + connect(connectBtn_, &QPushButton::clicked, this, &DroneManagementPage::onConnectDroneClicked); + actionLayout->addWidget(connectBtn_); + + disconnectBtn_ = new QPushButton("断开", this); + disconnectBtn_->setStyleSheet("QPushButton{background:#6c757d; color:white; border:none; padding:8px 16px; border-radius:4px;}"); + connect(disconnectBtn_, &QPushButton::clicked, this, &DroneManagementPage::onDisconnectDroneClicked); + actionLayout->addWidget(disconnectBtn_); + + refreshBtn_ = new QPushButton("刷新", this); + refreshBtn_->setStyleSheet("QPushButton{background:#17a2b8; color:white; border:none; padding:8px 16px; border-radius:4px;}"); + connect(refreshBtn_, &QPushButton::clicked, this, &DroneManagementPage::onRefreshData); + actionLayout->addWidget(refreshBtn_); + + groupLayout->addLayout(actionLayout); +} + +void DroneManagementPage::setupStatusPanel() { + statusGroup_ = new QGroupBox("状态信息", this); + auto* groupLayout = new QVBoxLayout(statusGroup_); + groupLayout->setSpacing(8); + + // 统计信息 + auto* statsLayout = new QHBoxLayout(); + totalDronesLabel_ = new QLabel("总无人机数: 0", this); + totalDronesLabel_->setStyleSheet("QLabel{font-weight:bold; color:#495057;}"); + statsLayout->addWidget(totalDronesLabel_); + + connectedDronesLabel_ = new QLabel("已连接: 0", this); + connectedDronesLabel_->setStyleSheet("QLabel{font-weight:bold; color:#28a745;}"); + statsLayout->addWidget(connectedDronesLabel_); + + groupLayout->addLayout(statsLayout); + + // 选中无人机信息 + selectedDroneLabel_ = new QLabel("未选择无人机", this); + selectedDroneLabel_->setStyleSheet("QLabel{font-weight:bold; color:#007bff;}"); + groupLayout->addWidget(selectedDroneLabel_); + + // 详细信息 + auto* detailLayout = new QHBoxLayout(); + positionLabel_ = new QLabel("位置: --", this); + detailLayout->addWidget(positionLabel_); + + velocityLabel_ = new QLabel("速度: --", this); + detailLayout->addWidget(velocityLabel_); + + attitudeLabel_ = new QLabel("姿态: --", this); + detailLayout->addWidget(attitudeLabel_); + + groupLayout->addLayout(detailLayout); +} + +void DroneManagementPage::updateDroneTable() { + if (!droneManager_) return; + + droneTable_->setRowCount(0); + + auto drones = droneManager_->getAllDrones(); + for (auto* drone : drones) { + addDroneToTable(drone); + } +} + +void DroneManagementPage::addDroneToTable(DroneData* drone) { + if (!drone) return; + + int row = droneTable_->rowCount(); + droneTable_->insertRow(row); + + // 设置行数据 + droneTable_->setItem(row, 0, new QTableWidgetItem(drone->getId())); + droneTable_->setItem(row, 1, new QTableWidgetItem(drone->getName())); + + // 连接状态 + auto* statusItem = new QTableWidgetItem(drone->isConnected() ? "已连接" : "未连接"); + statusItem->setBackground(QColor(drone->isConnected() ? "#d4edda" : "#f8d7da")); + droneTable_->setItem(row, 2, statusItem); + + // 位置信息 + droneTable_->setItem(row, 3, new QTableWidgetItem(getPositionString(drone->getPosition()))); + droneTable_->setItem(row, 4, new QTableWidgetItem(getVelocityString(drone->getVelocity()))); + droneTable_->setItem(row, 5, new QTableWidgetItem(getAttitudeString(drone->getAttitude()))); + droneTable_->setItem(row, 6, new QTableWidgetItem(getPositionString(drone->getExpectedPosition()))); + droneTable_->setItem(row, 7, new QTableWidgetItem(getVelocityString(drone->getExpectedVelocity()))); + + // 连接数据变化信号 + connect(drone, &DroneData::dataChanged, this, &DroneManagementPage::onDroneDataChanged); + connect(drone, &DroneData::connectionChanged, this, &DroneManagementPage::onDroneConnectionChanged); +} + +void DroneManagementPage::removeDroneFromTable(const QString& droneId) { + for (int i = 0; i < droneTable_->rowCount(); ++i) { + auto* item = droneTable_->item(i, 0); + if (item && item->text() == droneId) { + droneTable_->removeRow(i); + break; + } + } +} + +void DroneManagementPage::updateDroneRow(DroneData* drone) { + if (!drone) return; + + for (int i = 0; i < droneTable_->rowCount(); ++i) { + auto* item = droneTable_->item(i, 0); + if (item && item->text() == drone->getId()) { + // 更新连接状态 + auto* statusItem = droneTable_->item(i, 2); + if (statusItem) { + statusItem->setText(drone->isConnected() ? "已连接" : "未连接"); + statusItem->setBackground(QColor(drone->isConnected() ? "#d4edda" : "#f8d7da")); + } + + // 更新位置信息 + droneTable_->setItem(i, 3, new QTableWidgetItem(getPositionString(drone->getPosition()))); + droneTable_->setItem(i, 4, new QTableWidgetItem(getVelocityString(drone->getVelocity()))); + droneTable_->setItem(i, 5, new QTableWidgetItem(getAttitudeString(drone->getAttitude()))); + droneTable_->setItem(i, 6, new QTableWidgetItem(getPositionString(drone->getExpectedPosition()))); + droneTable_->setItem(i, 7, new QTableWidgetItem(getVelocityString(drone->getExpectedVelocity()))); + break; + } + } +} + +void DroneManagementPage::updateStatusDisplay() { + if (!droneManager_) return; + + auto drones = droneManager_->getAllDrones(); + int totalCount = drones.size(); + int connectedCount = 0; + + for (auto* drone : drones) { + if (drone->isConnected()) { + connectedCount++; + } + } + + totalDronesLabel_->setText(QString("总无人机数: %1").arg(totalCount)); + connectedDronesLabel_->setText(QString("已连接: %1").arg(connectedCount)); + + // 更新选中无人机信息 + if (!selectedDroneId_.isEmpty()) { + auto* selectedDrone = droneManager_->getDrone(selectedDroneId_); + if (selectedDrone) { + selectedDroneLabel_->setText(QString("选中: %1 (%2)").arg(selectedDrone->getName()).arg(selectedDrone->getId())); + positionLabel_->setText(QString("位置: %1").arg(getPositionString(selectedDrone->getPosition()))); + velocityLabel_->setText(QString("速度: %1").arg(getVelocityString(selectedDrone->getVelocity()))); + attitudeLabel_->setText(QString("姿态: %1").arg(getAttitudeString(selectedDrone->getAttitude()))); + } + } else { + selectedDroneLabel_->setText("未选择无人机"); + positionLabel_->setText("位置: --"); + velocityLabel_->setText("速度: --"); + attitudeLabel_->setText("姿态: --"); + } +} + +void DroneManagementPage::updateControlButtons() { + bool hasSelection = !selectedDroneId_.isEmpty(); + removeDroneBtn_->setEnabled(hasSelection); + connectBtn_->setEnabled(hasSelection); + disconnectBtn_->setEnabled(hasSelection); +} + +QString DroneManagementPage::getStatusColor(bool connected) const { + return connected ? "#28a745" : "#dc3545"; +} + +QString DroneManagementPage::getPositionString(const QVector3D& pos) const { + return QString("(%1, %2, %3)") + .arg(QString::number(pos.x(), 'f', 2)) + .arg(QString::number(pos.y(), 'f', 2)) + .arg(QString::number(pos.z(), 'f', 2)); +} + +QString DroneManagementPage::getVelocityString(const QVector3D& vel) const { + return QString("(%1, %2, %3)") + .arg(QString::number(vel.x(), 'f', 2)) + .arg(QString::number(vel.y(), 'f', 2)) + .arg(QString::number(vel.z(), 'f', 2)); +} + +QString DroneManagementPage::getAttitudeString(const QVector3D& att) const { + return QString("(%1°, %2°, %3°)") + .arg(QString::number(att.x(), 'f', 1)) + .arg(QString::number(att.y(), 'f', 1)) + .arg(QString::number(att.z(), 'f', 1)); +} + +void DroneManagementPage::onAddDroneClicked() { + QString id = droneIdEdit_->text().trimmed(); + QString name = droneNameEdit_->text().trimmed(); + + if (id.isEmpty()) { + QMessageBox::warning(this, "警告", "请输入无人机ID"); + return; + } + + if (name.isEmpty()) { + name = QString("无人机_%1").arg(id); + } + + if (droneManager_) { + // 检查是否已存在 + if (droneManager_->getDrone(id)) { + QMessageBox::warning(this, "警告", "无人机ID已存在"); + return; + } + + droneManager_->addDrone(id, name); + droneIdEdit_->clear(); + droneNameEdit_->clear(); + + QMessageBox::information(this, "成功", "无人机添加成功"); + } +} + +void DroneManagementPage::onRemoveDroneClicked() { + if (selectedDroneId_.isEmpty()) { + QMessageBox::warning(this, "警告", "请先选择要删除的无人机"); + return; + } + + int ret = QMessageBox::question(this, "确认删除", + QString("确定要删除无人机 %1 吗?").arg(selectedDroneId_), + QMessageBox::Yes | QMessageBox::No); + + if (ret == QMessageBox::Yes && droneManager_) { + droneManager_->removeDrone(selectedDroneId_); + selectedDroneId_.clear(); + updateStatusDisplay(); + updateControlButtons(); + } +} + +void DroneManagementPage::onConnectDroneClicked() { + if (selectedDroneId_.isEmpty()) { + QMessageBox::warning(this, "警告", "请先选择要连接的无人机"); + return; + } + + if (droneManager_) { + auto* drone = droneManager_->getDrone(selectedDroneId_); + if (drone && !drone->isConnected()) { + drone->setConnected(true); + emit droneConnectionRequested(selectedDroneId_, true); + } + } +} + +void DroneManagementPage::onDisconnectDroneClicked() { + if (selectedDroneId_.isEmpty()) { + QMessageBox::warning(this, "警告", "请先选择要断开的无人机"); + return; + } + + if (droneManager_) { + auto* drone = droneManager_->getDrone(selectedDroneId_); + if (drone && drone->isConnected()) { + drone->setConnected(false); + emit droneConnectionRequested(selectedDroneId_, false); + } + } +} + +void DroneManagementPage::onDroneSelectionChanged() { + int currentRow = droneTable_->currentRow(); + if (currentRow >= 0) { + auto* item = droneTable_->item(currentRow, 0); + if (item) { + selectedDroneId_ = item->text(); + if (droneManager_) { + droneManager_->setCurrentDrone(selectedDroneId_); + } + emit droneSelected(selectedDroneId_); + } + } else { + selectedDroneId_.clear(); + } + + updateStatusDisplay(); + updateControlButtons(); +} + +void DroneManagementPage::onRefreshData() { + if (droneManager_) { + updateDroneTable(); + updateStatusDisplay(); + } +} + +void DroneManagementPage::onDroneDataChanged() { + if (droneManager_) { + updateDroneTable(); + updateStatusDisplay(); + } +} + +void DroneManagementPage::onDroneConnectionChanged(bool connected) { + Q_UNUSED(connected) + onDroneDataChanged(); +} diff --git a/Src/pages/dronemanagementpage.h b/Src/pages/dronemanagementpage.h new file mode 100755 index 0000000..725e83b --- /dev/null +++ b/Src/pages/dronemanagementpage.h @@ -0,0 +1,95 @@ +#ifndef DRONEMANAGEMENTPAGE_H +#define DRONEMANAGEMENTPAGE_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../models/dronedata.h" + +/** + * 无人机管理页面类 + * 负责无人机连接管理、状态显示、添加删除无人机等功能 + */ +class DroneManagementPage : public QWidget { + Q_OBJECT + +public: + explicit DroneManagementPage(QWidget* parent = nullptr); + ~DroneManagementPage(); + + // 设置无人机管理器 + void setDroneManager(DroneManager* manager); + +signals: + void droneSelected(const QString& droneId); + void droneConnectionRequested(const QString& droneId, bool connect); + +private slots: + void onAddDroneClicked(); + void onRemoveDroneClicked(); + void onConnectDroneClicked(); + void onDisconnectDroneClicked(); + void onDroneSelectionChanged(); + void onRefreshData(); + void onDroneDataChanged(); + void onDroneConnectionChanged(bool connected); + +private: + void setupUI(); + void setupDroneTable(); + void setupControlPanel(); + void setupStatusPanel(); + void updateDroneTable(); + void updateStatusDisplay(); + void updateControlButtons(); + void addDroneToTable(DroneData* drone); + void removeDroneFromTable(const QString& droneId); + void updateDroneRow(DroneData* drone); + + // 获取状态颜色 + QString getStatusColor(bool connected) const; + QString getPositionString(const QVector3D& pos) const; + QString getVelocityString(const QVector3D& vel) const; + QString getAttitudeString(const QVector3D& att) const; + + // UI组件 + QFrame* mainFrame_; + QTableWidget* droneTable_; + QGroupBox* controlGroup_; + QGroupBox* statusGroup_; + + // 控制面板组件 + QLineEdit* droneIdEdit_; + QLineEdit* droneNameEdit_; + QPushButton* addDroneBtn_; + QPushButton* removeDroneBtn_; + QPushButton* connectBtn_; + QPushButton* disconnectBtn_; + QPushButton* refreshBtn_; + + // 状态显示组件 + QLabel* totalDronesLabel_; + QLabel* connectedDronesLabel_; + QLabel* selectedDroneLabel_; + QLabel* positionLabel_; + QLabel* velocityLabel_; + QLabel* attitudeLabel_; + + // 数据管理 + DroneManager* droneManager_; + QTimer* refreshTimer_; + QString selectedDroneId_; +}; + +#endif // DRONEMANAGEMENTPAGE_H + diff --git a/Src/pages/mapbridge.cpp b/Src/pages/mapbridge.cpp new file mode 100644 index 0000000..c462d65 --- /dev/null +++ b/Src/pages/mapbridge.cpp @@ -0,0 +1,16 @@ +#include "mapbridge.h" +#include + +MapBridge::MapBridge(QObject *parent) + : QObject(parent) +{ +} + +void MapBridge::onClick(double lng, double lat) +{ + emit mapClicked(lng, lat); +} + +void MapBridge::onMapReady() { + emit mapReady(); +} diff --git a/Src/pages/mapbridge.h b/Src/pages/mapbridge.h new file mode 100644 index 0000000..401dd5f --- /dev/null +++ b/Src/pages/mapbridge.h @@ -0,0 +1,21 @@ +#ifndef MAPBRIDGE_H +#define MAPBRIDGE_H + +#include +#include + +class MapBridge : public QObject { + Q_OBJECT +public: + explicit MapBridge(QObject *parent = nullptr); + +signals: + void mapClicked(double lng, double lat); + void mapReady(); + +public slots: + Q_INVOKABLE void onClick(double lng, double lat); + void onMapReady(); +}; + +#endif // MAPBRIDGE_H diff --git a/Src/pages/mappage.cpp b/Src/pages/mappage.cpp new file mode 100644 index 0000000..d4f2953 --- /dev/null +++ b/Src/pages/mappage.cpp @@ -0,0 +1,2257 @@ +#include "mappage.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mapbridge.h" +// 新增:A*与容器所需头文件 +#include +#include +#include +#include + +MapPage::MapPage(QWidget *parent) : QWidget(parent), + bridge_(nullptr), + channel_(nullptr), + mapArea_(nullptr), + heightCombo_(nullptr), + downloadMapBtn_(nullptr), + mapView_(nullptr), + setThreatBtn_(nullptr), + pathPlanningBtn_(nullptr), + areaCoverageBtn_(nullptr), + coordInput_(nullptr), + locateBtn_(nullptr), + searchMapBtn_(nullptr), + baseFontSize_(10), + pathOverlayId_("pathOverlay"), + startMarkerId_("startMarker"), + endMarkerId_("endMarker"), + currentPathData_(""), + coverageOverlayId_("coverageOverlay"), + areaOverlayId_("areaOverlay"), + currentCoveragePathData_(""), + isDrawing_(false), + drawingShape_(""), + drawingPoints_(), + threatAreas_(), + threatDialog_(nullptr), + planningDialog_(nullptr), + coverageDialog_(nullptr), + locateDialog_(nullptr) { + setupUI(); + enableGeolocation(); + qDebug() << "MapPage 构造函数完成"; + threatDialog_ = new ThreatAreaDialog(this, this); + planningDialog_ = new PathPlanningDialog(this, this); + coverageDialog_ = new AreaCoverageDialog(this, this); + locateDialog_ = new LocateDialog(this); + CustomWebEnginePage* page = qobject_cast(mapView_->page()); + if (page) { + connect(page, &CustomWebEnginePage::consoleMessage, this, &MapPage::onConsoleMessage); + } + connect(bridge_, &MapBridge::mapReady, this, &MapPage::onMapReadyFromJS); +} + +MapPage::~MapPage() {} + +void MapPage::setupUI() { + auto* mainLayout = new QVBoxLayout(this); + mainLayout->setSpacing(8); + mainLayout->setContentsMargins(0, 0, 0, 0); + + auto* title = new QLabel("路径监控"); + title->setProperty("class", "section"); + mainLayout->addWidget(title); + + mainLayout->addWidget(createMapControlsWidget()); + + setupMapArea(); + mainLayout->addWidget(mapArea_, 1); + + setupControlBar(); + mainLayout->addWidget(createControlBarWidget()); +} + +void MapPage::setupMapArea() { + mapArea_ = new QFrame(this); + mapArea_->setMinimumHeight(520); + auto* layout = new QVBoxLayout(mapArea_); + layout->setContentsMargins(0, 0, 0, 0); + + mapView_ = new QWebEngineView(mapArea_); + mapView_->setPage(new CustomWebEnginePage(mapView_)); + layout->addWidget(mapView_); + + // Setup WebChannel and bridge before loading HTML + channel_ = new QWebChannel(this); + bridge_ = new MapBridge(this); + connect(bridge_, &MapBridge::mapClicked, this, &MapPage::handleMapClick); + channel_->registerObject("bridge", bridge_); + mapView_->page()->setWebChannel(channel_); + + qDebug() << "WebChannel and bridge set up before page load"; + + const QString defaultHtml = R"( + + + + + + + 卫星和路网图 + + + + + + + +
+ + + )"; + mapView_->setHtml(defaultHtml, QUrl()); + connect(mapView_->page(), &QWebEnginePage::loadFinished, this, &MapPage::onPageLoaded); +} + +void MapPage::setupControlBar() { + // 控制条设置 +} + +QWidget* MapPage::createControlBarWidget() { + auto* bar = new QWidget(this); + auto* layout = new QHBoxLayout(bar); + layout->setContentsMargins(0, 0, 0, 0); + + auto* heightLabel = new QLabel("航线高度:"); + layout->addWidget(heightLabel); + + heightCombo_ = new QComboBox(); + heightCombo_->addItems({"30.00", "50.00", "80.00"}); + heightCombo_->setFixedWidth(100); + connect(heightCombo_, QOverload::of(&QComboBox::currentTextChanged), + this, &MapPage::onHeightChanged); + layout->addWidget(heightCombo_); + + layout->addStretch(1); + + // 添加地图检索按钮 + searchMapBtn_ = new QPushButton("地图检索"); + searchMapBtn_->setProperty("primary", true); + connect(searchMapBtn_, &QPushButton::clicked, this, &MapPage::onSearchMapClicked); + layout->addWidget(searchMapBtn_); + + + downloadMapBtn_ = new QPushButton("地图下载"); + downloadMapBtn_->setProperty("primary", true); + connect(downloadMapBtn_, &QPushButton::clicked, this, &MapPage::onDownloadMapClicked); + layout->addWidget(downloadMapBtn_); + + // 添加新按钮 - 为了整洁,将它们分组在布局末尾 + setThreatBtn_ = new QPushButton("设置威胁区域"); + setThreatBtn_->setProperty("primary", true); + connect(setThreatBtn_, &QPushButton::clicked, this, &MapPage::onSetThreatClicked); + layout->addWidget(setThreatBtn_); + + pathPlanningBtn_ = new QPushButton("路径规划"); + pathPlanningBtn_->setProperty("primary", true); + connect(pathPlanningBtn_, &QPushButton::clicked, this, &MapPage::onPathPlanningClicked); + layout->addWidget(pathPlanningBtn_); + + areaCoverageBtn_ = new QPushButton("区域覆盖规划"); + areaCoverageBtn_->setProperty("primary", true); + connect(areaCoverageBtn_, &QPushButton::clicked, this, &MapPage::onAreaCoverageClicked); + layout->addWidget(areaCoverageBtn_); + + auto* loadPathBtn = new QPushButton("加载保存路径"); + connect(loadPathBtn, &QPushButton::clicked, this, &MapPage::loadSavedPath); + layout->addWidget(loadPathBtn); + + return bar; +} + +#ifdef INCLUDE_AREA_SEARCH +void MapPage::onAreaSearchClicked() { + searchDialog_->exec(); +} +#endif + +void MapPage::enableGeolocation() { + if (mapView_) { + QWebEngineSettings* settings = mapView_->settings(); + settings->setAttribute(QWebEngineSettings::JavascriptEnabled, true); + settings->setAttribute(QWebEngineSettings::LocalStorageEnabled, true); + + // Set geolocation permission for the map domain + connect(mapView_->page(), &QWebEnginePage::featurePermissionRequested, + [this](const QUrl &securityOrigin, QWebEnginePage::Feature feature) { + if (feature == QWebEnginePage::Geolocation) { + mapView_->page()->setFeaturePermission(securityOrigin, feature, QWebEnginePage::PermissionGrantedByUser); + qDebug() << "Geolocation permission granted for:" << securityOrigin.toString(); + } + }); + + qDebug() << "Geolocation enabled and permission handler set up"; + } +} + +void MapPage::onHeightChanged() { + emit heightChanged(heightCombo_->currentText()); + qDebug() << "航线高度变更为:" << heightCombo_->currentText(); +} + +void MapPage::onDownloadMapClicked() { + emit downloadMapRequested(); + qDebug() << "地图下载请求"; +} + +void MapPage::onSetThreatClicked() { + threatDialog_->exec(); // 打开模态对话框 + // 执行JS添加overlay (示例) + mapView_->page()->runJavaScript("addThreatArea();"); // 假设JS函数 +} + +void MapPage::onPathPlanningClicked() { + if (planningDialog_->exec() == QDialog::Accepted) { + QString pathData = planningDialog_->getPathData(); + if (pathData.isEmpty()) { + qDebug() << "No path data available"; + return; + } + + // Path is already visualized in planPath, but re-visualize if needed + visualizePath(pathData); + } +} + +void MapPage::onAreaCoverageClicked() { + if (coverageDialog_->exec() == QDialog::Accepted) { + QString pathData = coverageDialog_->getCoveragePathData(); + if (pathData.isEmpty()) { + qDebug() << "No coverage path data available"; + return; + } + visualizeCoveragePath(pathData); + } +} + + +void MapPage::runMapJavaScript(const QString& js) { + if (mapView_) { + mapView_->page()->runJavaScript(js); + } +} + +void MapPage::clearPathOverlays() { + QString js = QString(R"( + if (window.map) { + console.log('Clearing all path overlays...'); + + // Remove path polyline + if (window.%1) { + window.map.remove(window.%1); + window.%1 = null; + console.log('Removed path polyline'); + } + + // Remove start marker + if (window.%2) { + window.map.remove(window.%2); + window.%2 = null; + console.log('Removed start marker'); + } + + // Remove end marker + if (window.%3) { + window.map.remove(window.%3); + window.%3 = null; + console.log('Removed end marker'); + } + + // Clear intermediate markers + if (!window.intermediates) { + window.intermediates = []; + } + for (var i = 0; i < window.intermediates.length; i++) { + if (window.intermediates[i]) { + window.map.remove(window.intermediates[i]); + console.log('Removed intermediate marker ' + i); + } + } + window.intermediates = []; + + console.log('All path overlays cleared successfully'); + } else { + console.log('Map not available for clearing'); + } + )").arg(pathOverlayId_, startMarkerId_, endMarkerId_); + runMapJavaScript(js); + qDebug() << "路径覆盖物清除完成"; +} + +void MapPage::visualizeCoveragePath(const QString& pathData) { + QString js = QString(R"( + if (window.map) { + var pathCoords = JSON.parse("%1"); + console.log('Visualizing coverage path with ' + pathCoords.length + ' points'); + + // Remove existing coverage overlay if any + if (window.%2) { + window.map.remove(window.%2); + window.%2 = null; + } + + // Create new polyline for coverage path (green, dashed) + var polyline = new AMap.Polyline({ + path: pathCoords, + strokeColor: "#4CAF50", + strokeOpacity: 0.8, + strokeWeight: 4, + strokeStyle: "dashed", + strokeDasharray: [8, 4], + zIndex: 2 + }); + polyline.setMap(window.map); + window.%2 = polyline; + + // Clear existing coverage intermediates + if (!window.coverageIntermediates) { + window.coverageIntermediates = []; + } + for (var i = 0; i < window.coverageIntermediates.length; i++) { + if (window.coverageIntermediates[i]) { + window.map.remove(window.coverageIntermediates[i]); + } + } + window.coverageIntermediates = []; + + // Add intermediate markers for coverage points + for (var i = 0; i < pathCoords.length; i += 5) { // Every 5th point for visibility + var marker = new AMap.Marker({ + position: pathCoords[i], + content: '
C' + (i/5 + 1) + '
', + zIndex: 15 + }); + marker.setMap(window.map); + window.coverageIntermediates.push(marker); + } + + // Fit view + var allOverlays = [polyline].concat(window.coverageIntermediates); + if (allOverlays.length > 0) { + window.map.setFitView(allOverlays, {padding: [50, 50, 50, 50]}); + } + + console.log('Coverage path visualization completed'); + } + )").arg(pathData, coverageOverlayId_); + runMapJavaScript(js); + currentCoveragePathData_ = pathData; + qDebug() << "区域覆盖路径可视化完成"; +} + +void MapPage::clearCoverageOverlays() { + QString js = QString(R"( + if (window.map) { + console.log('Clearing all coverage overlays...'); + + // Remove coverage polyline + if (window.%1) { + window.map.remove(window.%1); + window.%1 = null; + console.log('Removed coverage polyline'); + } + + // Remove area overlay if exists + if (window.%2) { + window.map.remove(window.%2); + window.%2 = null; + console.log('Removed area overlay'); + } + + // Clear coverage intermediates + if (!window.coverageIntermediates) { + window.coverageIntermediates = []; + } + for (var i = 0; i < window.coverageIntermediates.length; i++) { + if (window.coverageIntermediates[i]) { + window.map.remove(window.coverageIntermediates[i]); + } + } + window.coverageIntermediates = []; + + console.log('All coverage overlays cleared successfully'); + } else { + console.log('Map not available for clearing'); + } + )").arg(coverageOverlayId_, areaOverlayId_); + runMapJavaScript(js); + qDebug() << "区域覆盖覆盖物清除完成"; +} + + +void MapPage::visualizeCoverageAreaCircle(double centerLng, double centerLat, double radiusKm) { + // 使用统一的 areaOverlayId_ 存放区域 overlay(Circle) + // km -> m + double radiusM = radiusKm * 1000.0; + QString js = QString(R"( + if (window.map) { + if (window.%1) { window.map.remove(window.%1); window.%1 = null; } + var circle = new AMap.Circle({ + center: new AMap.LngLat(%2, %3), + radius: %4, + fillColor: '#3F51B5', + fillOpacity: 0.15, + strokeColor: '#3F51B5', + strokeWeight: 2 + }); + circle.setMap(window.map); + window.%1 = circle; + window.map.setFitView([circle], {padding:[40,40,40,40]}); + } + )").arg(areaOverlayId_) + .arg(centerLng, 0, 'f', 6) + .arg(centerLat, 0, 'f', 6) + .arg(radiusM, 0, 'f', 3); + runMapJavaScript(js); +} + +void MapPage::visualizeCoverageAreaPolygon(const QList>& vertices) { + // 使用统一的 areaOverlayId_ 存放区域 overlay(Polygon) + QString path = "["; + for (int i = 0; i < vertices.size(); ++i) { + if (i > 0) path += ","; + path += QString("[%1,%2]").arg(vertices[i].first, 0, 'f', 6).arg(vertices[i].second, 0, 'f', 6); + } + path += "]"; + QString js = QString(R"( + if (window.map) { + if (window.%1) { window.map.remove(window.%1); window.%1 = null; } + var polygon = new AMap.Polygon({ + path: %2, + fillColor: '#3F51B5', + fillOpacity: 0.15, + strokeColor: '#3F51B5', + strokeWeight: 2 + }); + polygon.setMap(window.map); + window.%1 = polygon; + window.map.setFitView([polygon], {padding:[40,40,40,40]}); + } + )").arg(areaOverlayId_).arg(path); + runMapJavaScript(js); +} + + +double MapPage::parseLng(const QString& coord) const { + // Handle both "[lng, lat]" and "lng, lat" + QRegExp rx("^\\s*\\[?\\s*([\\d.-]+)\\s*,"); + if (rx.indexIn(coord) != -1) { + return rx.cap(1).toDouble(); + } + return 0.0; +} + +double MapPage::parseLat(const QString& coord) const { + // Handle both "[lng, lat]" and "lng, lat" + QRegExp rx(",\\s*([\\d.-]+)\\s*\\]?\\s*$"); + if (rx.indexIn(coord) != -1) { + return rx.cap(1).toDouble(); + } + return 0.0; +} + +void MapPage::showMarker(double lng, double lat, const QString& label, const QString& color, int index) { + QString markerId = (index == 0) ? startMarkerId_ : endMarkerId_; + QString js = QString(R"( + if (window.map) { + // Only remove if it's a different position + if (window.%1 && (window.%1.getPosition().lng != %2 || window.%1.getPosition().lat != %3)) { + window.map.remove(window.%1); + } + if (!window.%1 || (window.%1.getPosition().lng != %2 || window.%1.getPosition().lat != %3)) { + var marker = new AMap.Marker({ + position: new AMap.LngLat(%2, %3), + content: '
%5
', + zIndex: 100 + (%6 === 0 ? 10 : 5) // Start marker gets higher z-index + }); + marker.setMap(window.map); + window.%1 = marker; + } + } + )").arg(markerId, QString::number(lng), QString::number(lat), color, label, QString::number(index)); + runMapJavaScript(js); +} + +void MapPage::addClickListener() { + QString js = R"( + console.log('Adding click listener...'); + function addListener() { + if (window.map && window.bridge && window.mapReady) { + // Remove existing listener if any + if (window.clickListener) { + window.clickListener.remove(); + console.log('Removed existing listener'); + } + window.clickListener = window.map.on('click', function(e) { + console.log('Map clicked at: ' + e.lnglat.getLng() + ', ' + e.lnglat.getLat()); + window.bridge.onClick(e.lnglat.getLng(), e.lnglat.getLat()); + }); + console.log('Click listener added successfully'); + return true; + } + return false; + } + if (addListener()) { + // Already ready + } else { + console.log('Map or bridge not ready - polling...'); + var attempts = 0; + var maxAttempts = 100; // 10 seconds at 100ms intervals + var interval = setInterval(function() { + attempts++; + if (addListener()) { + clearInterval(interval); + } else if (attempts >= maxAttempts) { + clearInterval(interval); + console.error('Failed to add listener after ' + maxAttempts + ' attempts'); + } + }, 100); + } + )"; + runMapJavaScript(js); +} + +void MapPage::removeClickListener() { + QString js = R"( + if (window.clickListener) { + window.clickListener.remove(); + window.clickListener = null; + } + )"; + runMapJavaScript(js); +} + +void MapPage::visualizePath(const QString& pathData) { + if (isMapReady_) { + // 直接执行JS + QString js = QString(R"( + if (window.map) { + var pathCoords = JSON.parse("%1"); + console.log('Visualizing path with ' + pathCoords.length + ' points'); + + // Remove existing path overlay if any + if (window.%2) { + window.map.remove(window.%2); + window.%2 = null; + } + + // Create new polyline + var polyline = new AMap.Polyline({ + path: pathCoords, + strokeColor: "#3366FF", + strokeOpacity: 1, + strokeWeight: 5, + strokeStyle: "solid", + strokeDasharray: [10, 5], + zIndex: 1 + }); + polyline.setMap(window.map); + window.%2 = polyline; + + // Clear existing intermediate markers + if (!window.intermediates) { + window.intermediates = []; + } + for (var i = 0; i < window.intermediates.length; i++) { + if (window.intermediates[i]) { + window.map.remove(window.intermediates[i]); + } + } + window.intermediates = []; + + // Add intermediate markers as small dots (excluding start and end) + for (var i = 1; i < pathCoords.length - 1; i++) { + var marker = new AMap.Marker({ + position: pathCoords[i], + content: '
', + zIndex: 10, + offset: new AMap.Pixel(-4, -4) + }); + marker.setMap(window.map); + window.intermediates.push(marker); + } + + // Fit view to show all elements + var allOverlays = []; + if (window.startMarker) allOverlays.push(window.startMarker); + if (window.endMarker) allOverlays.push(window.endMarker); + allOverlays.push(polyline); + allOverlays = allOverlays.concat(window.intermediates); + + if (allOverlays.length > 0) { + window.map.setFitView(allOverlays, {padding: [50, 50, 50, 50]}); + } + + console.log('Path visualization completed with ' + window.intermediates.length + ' intermediate point markers (no labels)'); + } + )").arg(pathData, pathOverlayId_); + runMapJavaScript(js); + qDebug() << "路径可视化完成"; + } else { + // 等待就绪 + connect(this, &MapPage::mapReady, [this, pathData](){ + visualizePath(pathData); // 递归调用一次 + disconnect(this, &MapPage::mapReady, nullptr, nullptr); // 清理 + }); + qDebug() << "等待地图就绪后可视化路径"; + } +} + +void MapPage::onPageLoaded(bool ok) { + if (ok) { + qDebug() << "Page loaded successfully"; + + // Ensure bridge is properly registered with WebChannel + if (channel_ && bridge_) { + channel_->registerObject("bridge", bridge_); + qDebug() << "Bridge registered with WebChannel"; + + // Check readiness after a short delay + QTimer::singleShot(500, this, [this]() { + runMapJavaScript("console.log('Readiness check: mapReady=' + !!window.mapReady + ', bridge exists=' + !!window.bridge);"); + // 如果地图已就绪且bridge可用,添加点击监听器(JS侧会处理) + runMapJavaScript("if (window.mapReady && window.bridge) { addClickListener(); } else { console.log('Waiting for map and bridge to be ready...'); }"); + }); + } else { + qDebug() << "ERROR: Channel or bridge is null!"; + } + } else { + qDebug() << "Page load failed"; + } +} + +void MapPage::onSearchMapClicked() { + if (locateDialog_->exec() == QDialog::Accepted) { + double lng = locateDialog_->getLongitude(); + double lat = locateDialog_->getLatitude(); + + // 执行JS移动地图中心(使用window.map以匹配全局变量) + QString js = QString("window.map.setCenter([%1, %2]); window.map.setZoom(15);").arg(lng).arg(lat); + mapView_->page()->runJavaScript(js); + } +} + +// Implement ThreatAreaDialog methods +ThreatAreaDialog::ThreatAreaDialog(QWidget *parent, MapPage* mapPage) : QDialog(parent), mapPage_(mapPage), drawingPoints_() { + setWindowTitle("设置威胁区域"); + setMinimumSize(600, 500); + auto* layout = new QVBoxLayout(this); + layout->setSpacing(15); + layout->setContentsMargins(20, 20, 20, 20); + + // 威胁区域基本信息组 + auto* basicGroup = new QGroupBox("基本信息"); + basicGroup->setStyleSheet("QGroupBox { font-weight: bold; margin-top: 10px; }"); + auto* basicLayout = new QGridLayout(basicGroup); + basicLayout->setSpacing(10); + + // 威胁类型 + basicLayout->addWidget(new QLabel("威胁类型:"), 0, 0); + typeCombo_ = new QComboBox(); + typeCombo_->addItems({"导弹威胁", "雷达干扰", "防空火力", "禁飞区域", "其他"}); + typeCombo_->setStyleSheet("QComboBox { padding: 5px; border: 1px solid #ccc; border-radius: 4px; }"); + basicLayout->addWidget(typeCombo_, 0, 1); + + // 威胁等级 + basicLayout->addWidget(new QLabel("威胁等级:"), 0, 2); + levelCombo_ = new QComboBox(); + levelCombo_->addItems({"高", "中", "低"}); + levelCombo_->setStyleSheet("QComboBox { padding: 5px; border: 1px solid #ccc; border-radius: 4px; }"); + basicLayout->addWidget(levelCombo_, 0, 3); + + layout->addWidget(basicGroup); + + // 添加形状选择 + basicLayout->addWidget(new QLabel("形状:"), 1, 0); + shapeCombo_ = new QComboBox(); + shapeCombo_->addItems({"圆形", "矩形"}); + shapeCombo_->setStyleSheet("QComboBox { padding: 5px; border: 1px solid #ccc; border-radius: 4px; }"); + connect(shapeCombo_, QOverload::of(&QComboBox::currentIndexChanged), this, &ThreatAreaDialog::onShapeChanged); + basicLayout->addWidget(shapeCombo_, 1, 1); + + // 添加颜色选择(假设用于 overlay 颜色) + basicLayout->addWidget(new QLabel("颜色:"), 1, 2); + colorCombo_ = new QComboBox(); + colorCombo_->addItems({"红色", "黄色", "蓝色"}); + basicLayout->addWidget(colorCombo_, 1, 3); + + layout->addWidget(basicGroup); + + // 时间设置组 (保持不变) + auto* timeGroup = new QGroupBox("威胁区域存在时间"); + timeGroup->setStyleSheet("QGroupBox { font-weight: bold; margin-top: 10px; }"); + auto* timeLayout = new QVBoxLayout(timeGroup); + + // 开始时间 + auto* startTimeLayout = new QHBoxLayout(); + startTimeLayout->addWidget(new QLabel("开始时间:")); + startTimeEdit_ = new QDateTimeEdit(QDateTime::currentDateTime()); + startTimeEdit_->setDisplayFormat("yyyy-MM-dd hh:mm:ss"); + startTimeEdit_->setCalendarPopup(true); + startTimeEdit_->setStyleSheet("QDateTimeEdit { padding: 5px; border: 1px solid #ccc; border-radius: 4px; }"); + startTimeLayout->addWidget(startTimeEdit_); + startTimeLayout->addStretch(); + timeLayout->addLayout(startTimeLayout); + + // 结束时间 + auto* endTimeLayout = new QHBoxLayout(); + endTimeLayout->addWidget(new QLabel("结束时间:")); + endTimeEdit_ = new QDateTimeEdit(QDateTime::currentDateTime().addSecs(3600)); // 默认1小时后 + endTimeEdit_->setDisplayFormat("yyyy-MM-dd hh:mm:ss"); + endTimeEdit_->setCalendarPopup(true); + endTimeEdit_->setStyleSheet("QDateTimeEdit { padding: 5px; border: 1px solid #ccc; border-radius: 4px; }"); + endTimeLayout->addWidget(endTimeEdit_); + endTimeLayout->addStretch(); + timeLayout->addLayout(endTimeLayout); + + layout->addWidget(timeGroup); + + // 动态输入 widget + circleInputWidget_ = new QWidget(); + auto* circleLayout = new QFormLayout(circleInputWidget_); + centerLngInput_ = new QLineEdit(); + centerLngInput_->setPlaceholderText("中心经度"); + circleLayout->addRow("中心经度:", centerLngInput_); + centerLatInput_ = new QLineEdit(); + centerLatInput_->setPlaceholderText("中心纬度"); + circleLayout->addRow("中心纬度:", centerLatInput_); + radiusInput_ = new QLineEdit(); + radiusInput_->setPlaceholderText("半径 (米)"); + circleLayout->addRow("半径 (米):", radiusInput_); + layout->addWidget(circleInputWidget_); + + rectangleInputWidget_ = new QWidget(); + auto* rectLayout = new QVBoxLayout(rectangleInputWidget_); + rectPointsTable_ = new QTableWidget(4, 2); + rectPointsTable_->setHorizontalHeaderLabels({"经度", "纬度"}); + for (int i = 0; i < 4; ++i) { + rectPointsTable_->setItem(i, 0, new QTableWidgetItem("")); + rectPointsTable_->setItem(i, 1, new QTableWidgetItem("")); + } + rectLayout->addWidget(rectPointsTable_); + layout->addWidget(rectangleInputWidget_); + rectangleInputWidget_->setVisible(false); + + // 按钮 (保持 drawOnMapBtn_ 等) + auto* buttonLayout = new QHBoxLayout(); + buttonLayout->addStretch(); + + drawOnMapBtn_ = new QPushButton("在地图上绘制"); + drawOnMapBtn_->setStyleSheet("QPushButton { padding: 8px 20px; background: #4CAF50; color: white; border-radius: 4px; }"); + connect(drawOnMapBtn_, &QPushButton::clicked, this, &ThreatAreaDialog::startDrawingThreatArea); + buttonLayout->addWidget(drawOnMapBtn_); + + auto* addBtn = new QPushButton("添加区域"); + addBtn->setProperty("primary", true); + addBtn->setStyleSheet("QPushButton { padding: 8px 20px; background: #2196f3; color: white; border-radius: 4px; }"); + buttonLayout->addWidget(addBtn); + + auto* cancelBtn = new QPushButton("取消"); + cancelBtn->setStyleSheet("QPushButton { padding: 8px 20px; background: #f5f5f5; border: 1px solid #ddd; border-radius: 4px; }"); + buttonLayout->addWidget(cancelBtn); + + layout->addLayout(buttonLayout); + + // 连接信号槽 + connect(addBtn, &QPushButton::clicked, this, &ThreatAreaDialog::addArea); + connect(cancelBtn, &QPushButton::clicked, this, &QDialog::reject); + + // 初始化 areaTable_ + auto* tableGroup = new QGroupBox("已添加威胁区域"); + auto* tableLayout = new QVBoxLayout(tableGroup); + areaTable_ = new QTableWidget(); + areaTable_->setColumnCount(6); + areaTable_->setHorizontalHeaderLabels({"类型", "等级", "开始时间", "结束时间", "形状", "细节"}); + areaTable_->setSelectionBehavior(QAbstractItemView::SelectRows); // 整行选择 + connect(areaTable_, &QTableWidget::itemSelectionChanged, this, [this]() { + auto selected = areaTable_->selectedItems(); + if (!selected.isEmpty()) { + selectedRow_ = selected.first()->row(); + } else { + selectedRow_ = -1; + } + }); + tableLayout->addWidget(areaTable_); + + // 添加编辑/删除按钮 + auto* buttonLayoutTable = new QHBoxLayout(); + editBtn_ = new QPushButton("编辑选中区域"); + connect(editBtn_, &QPushButton::clicked, this, &ThreatAreaDialog::editArea); + buttonLayoutTable->addWidget(editBtn_); + + deleteBtn_ = new QPushButton("删除选中区域"); + connect(deleteBtn_, &QPushButton::clicked, this, &ThreatAreaDialog::deleteArea); + buttonLayoutTable->addWidget(deleteBtn_); + + tableLayout->addLayout(buttonLayoutTable); + layout->addWidget(tableGroup); + + // 填充现有区域 + const auto& areas = mapPage_->getThreatAreas(); + for (const auto& area : areas) { + int row = areaTable_->rowCount(); + areaTable_->insertRow(row); + areaTable_->setItem(row, 0, new QTableWidgetItem(area["type"].toString())); + areaTable_->setItem(row, 1, new QTableWidgetItem(area["level"].toString())); + areaTable_->setItem(row, 2, new QTableWidgetItem(area["startTime"].toString())); + areaTable_->setItem(row, 3, new QTableWidgetItem(area["endTime"].toString())); + areaTable_->setItem(row, 4, new QTableWidgetItem(area["shape"].toString())); + QString details; + if (area["shape"].toString() == "circle") { + details = QString("中心: %1,%2 半径: %3m").arg(area["centerLng"].toDouble()).arg(area["centerLat"].toDouble()).arg(area["radius"].toDouble()); + } else { + details = "矩形点..."; // 简化 + } + areaTable_->setItem(row, 5, new QTableWidgetItem(details)); + } +} + +void ThreatAreaDialog::onShapeChanged(int index) { + currentShape_ = shapeCombo_->currentText(); + circleInputWidget_->setVisible(index == 0); + rectangleInputWidget_->setVisible(index == 1); +} + +void ThreatAreaDialog::startDrawingThreatArea() { + if (!mapPage_) return; + currentShape_ = shapeCombo_->currentText(); + QMessageBox::information(this, "提示", QString("现在在地图上绘制%1。点击添加点。").arg(currentShape_)); + hide(); // 隐藏对话框以允许地图交互 + mapPage_->enableDrawingMode(currentShape_ == "圆形" ? "circle" : "rectangle"); + connect(mapPage_, &MapPage::mapClicked, this, &ThreatAreaDialog::handleDrawingClick); // 临时连接 +} + +void ThreatAreaDialog::handleDrawingClick(double lng, double lat) { + drawingPoints_.append(qMakePair(lng, lat)); + if (currentShape_ == "圆形" && drawingPoints_.size() == 2) { + // 计算中心和半径 + double centerLng = drawingPoints_[0].first; + double centerLat = drawingPoints_[0].second; + double dx = drawingPoints_[1].first - centerLng; + double dy = drawingPoints_[1].second - centerLat; + double radius = sqrt(dx*dx + dy*dy) * 111000; // 粗略转换为米 (1度 ~ 111km) + centerLngInput_->setText(QString::number(centerLng)); + centerLatInput_->setText(QString::number(centerLat)); + radiusInput_->setText(QString::number(radius)); + finishDrawing(); + } else if (currentShape_ == "矩形" && drawingPoints_.size() == 2) { + // 计算矩形四个点 (假设两个对角点) + double minLng = qMin(drawingPoints_[0].first, drawingPoints_[1].first); + double maxLng = qMax(drawingPoints_[0].first, drawingPoints_[1].first); + double minLat = qMin(drawingPoints_[0].second, drawingPoints_[1].second); + double maxLat = qMax(drawingPoints_[0].second, drawingPoints_[1].second); + rectPointsTable_->setItem(0, 0, new QTableWidgetItem(QString::number(minLng))); + rectPointsTable_->setItem(0, 1, new QTableWidgetItem(QString::number(minLat))); + rectPointsTable_->setItem(1, 0, new QTableWidgetItem(QString::number(maxLng))); + rectPointsTable_->setItem(1, 1, new QTableWidgetItem(QString::number(minLat))); + rectPointsTable_->setItem(2, 0, new QTableWidgetItem(QString::number(maxLng))); + rectPointsTable_->setItem(2, 1, new QTableWidgetItem(QString::number(maxLat))); + rectPointsTable_->setItem(3, 0, new QTableWidgetItem(QString::number(minLng))); + rectPointsTable_->setItem(3, 1, new QTableWidgetItem(QString::number(maxLat))); + finishDrawing(); + } +} + +void ThreatAreaDialog::finishDrawing() { + mapPage_->disableDrawingMode(); + disconnect(mapPage_, &MapPage::mapClicked, this, &ThreatAreaDialog::handleDrawingClick); + drawingPoints_.clear(); + show(); + addArea(); // 自动添加绘制结果到表格和地图 + QMessageBox::information(this, "完成", "绘制完成,已自动添加区域。"); +} + +void ThreatAreaDialog::addArea() { + // 验证输入并添加 overlay + QVariantMap params; + params["type"] = typeCombo_->currentText(); + params["level"] = levelCombo_->currentText(); + params["startTime"] = startTimeEdit_->dateTime().toString(); + params["endTime"] = endTimeEdit_->dateTime().toString(); + + // 颜色映射 + QString colorStr = colorCombo_->currentText(); + QString hexColor; + if (colorStr == "红色") hexColor = "#FF0000"; + else if (colorStr == "黄色") hexColor = "#FFFF00"; + else if (colorStr == "蓝色") hexColor = "#0000FF"; + else hexColor = "#FF0000"; // 默认红色 + params["color"] = hexColor; + + params["shape"] = currentShape_; + + bool valid = true; + if (currentShape_ == "圆形") { + bool ok; + params["centerLng"] = centerLngInput_->text().toDouble(&ok); + valid &= ok; + params["centerLat"] = centerLatInput_->text().toDouble(&ok); + valid &= ok; + double radius = radiusInput_->text().toDouble(&ok); + valid &= ok && radius > 0; + params["radius"] = radius; + if (!valid) { + QMessageBox::warning(this, "错误", "无效的圆形参数(经纬度/半径必须是正数)"); + return; + } + mapPage_->addThreatOverlay("circle", params); + } else { + QList points; + for (int i = 0; i < 4; ++i) { + QVariantMap point; + point["lng"] = rectPointsTable_->item(i, 0)->text().toDouble(); + point["lat"] = rectPointsTable_->item(i, 1)->text().toDouble(); + points.append(point); + } + params["points"] = points; + mapPage_->addThreatOverlay("rectangle", params); + } + qDebug() << "添加威胁区域"; + QMessageBox::information(this, "提示", "威胁区域已添加"); + // 插入到表格 + int row = areaTable_->rowCount(); + areaTable_->insertRow(row); + areaTable_->setItem(row, 0, new QTableWidgetItem(params["type"].toString())); + areaTable_->setItem(row, 1, new QTableWidgetItem(params["level"].toString())); + areaTable_->setItem(row, 2, new QTableWidgetItem(params["startTime"].toString())); + areaTable_->setItem(row, 3, new QTableWidgetItem(params["endTime"].toString())); + areaTable_->setItem(row, 4, new QTableWidgetItem(params["shape"].toString())); + QString details; + if (params["shape"].toString() == "圆形") { + details = QString("中心: %1,%2 半径: %3m").arg(params["centerLng"].toDouble()).arg(params["centerLat"].toDouble()).arg(params["radius"].toDouble()); + } else { + details = "矩形点: ..."; // 可以扩展 + } + areaTable_->setItem(row, 5, new QTableWidgetItem(details)); + accept(); +} + +// Implement missing methods +void ThreatAreaDialog::updateThreatStats() { + qDebug() << "更新威胁统计"; +} + +void ThreatAreaDialog::editArea() { + if (selectedRow_ < 0 || selectedRow_ >= mapPage_->getThreatAreas().size()) { + QMessageBox::warning(this, "错误", "请选择一个区域编辑"); + return; + } + auto& area = mapPage_->getThreatAreas()[selectedRow_]; + typeCombo_->setCurrentText(area["type"].toString()); + levelCombo_->setCurrentText(area["level"].toString()); + startTimeEdit_->setDateTime(QDateTime::fromString(area["startTime"].toString())); + endTimeEdit_->setDateTime(QDateTime::fromString(area["endTime"].toString())); + colorCombo_->setCurrentText(area["color"].toString()); + shapeCombo_->setCurrentText(area["shape"].toString()); + + if (area["shape"].toString() == "circle") { + centerLngInput_->setText(QString::number(area["centerLng"].toDouble())); + centerLatInput_->setText(QString::number(area["centerLat"].toDouble())); + radiusInput_->setText(QString::number(area["radius"].toDouble())); + } else { + // 填充矩形表格 + QList points = area["points"].toList(); + for (int i = 0; i < 4 && i < points.size(); ++i) { + QVariantMap p = points[i].toMap(); + rectPointsTable_->setItem(i, 0, new QTableWidgetItem(QString::number(p["lng"].toDouble()))); + rectPointsTable_->setItem(i, 1, new QTableWidgetItem(QString::number(p["lat"].toDouble()))); + } + } + // 更新后,用户可以修改并点击"添加区域"来覆盖(或实现更新逻辑) + QMessageBox::information(this, "提示", "已加载选中区域数据,请修改后点击添加更新。"); +} + +void ThreatAreaDialog::deleteArea() { + if (selectedRow_ < 0 || selectedRow_ >= mapPage_->getThreatAreas().size()) { + QMessageBox::warning(this, "错误", "请选择一个区域删除"); + return; + } + mapPage_->removeThreatOverlay(selectedRow_); + areaTable_->removeRow(selectedRow_); + selectedRow_ = -1; + QMessageBox::information(this, "成功", "已删除选中区域"); +} + +// In MapPage class +void MapPage::removeThreatOverlay(int index) { + if (index < 0 || index >= threatAreas_.size()) return; + QVariantMap area = threatAreas_.at(index); + QString overlayId = area["id"].toString(); + runMapJavaScript(QString("if (window.%1) { window.map.remove(window.%1); window.%1 = null; }").arg(overlayId)); + threatAreas_.removeAt(index); + // 无需 clearMap 和重绘 +} + +PathPlanningDialog::PathPlanningDialog(QWidget *parent, MapPage* mapPage) : QDialog(parent), mapPage_(mapPage), pathData_("") { + setWindowTitle("路径规划"); + setMinimumSize(600, 500); + auto* layout = new QVBoxLayout(this); + layout->setContentsMargins(20, 20, 20, 20); + + auto* formLayout = new QFormLayout(); + + startInput_ = new QLineEdit(); + startInput_->setPlaceholderText("格式: 经度,纬度 或 [经度, 纬度]"); + formLayout->addRow("起点坐标:", startInput_); + + endInput_ = new QLineEdit(); + endInput_->setPlaceholderText("格式: 经度,纬度 或 [经度, 纬度]"); + formLayout->addRow("终点坐标:", endInput_); + + layout->addLayout(formLayout); + + // Selection buttons + auto* selectLayout = new QHBoxLayout(); + selectStartBtn_ = new QPushButton("选择起点"); + connect(selectStartBtn_, &QPushButton::clicked, [this](){ + if (!mapPage_) return; + QMessageBox::information(this, "提示", "现在在地图上点击选择起点。"); + selectingStart_ = true; + selectingEnd_ = false; + mapPage_->addClickListener(); + mapPage_->show(); // 确保地图可见 + // 无需隐藏对话框,因为非模态 + }); + selectLayout->addWidget(selectStartBtn_); + + selectEndBtn_ = new QPushButton("选择终点"); + connect(selectEndBtn_, &QPushButton::clicked, [this](){ + if (!mapPage_) return; + QMessageBox::information(this, "提示", "现在在地图上点击选择终点。"); + selectingStart_ = false; + selectingEnd_ = true; + mapPage_->addClickListener(); + mapPage_->show(); // 确保地图可见 + // 无需隐藏对话框,因为非模态 + }); + selectLayout->addWidget(selectEndBtn_); + layout->addLayout(selectLayout); + + // Apply buttons + auto* applyLayout = new QHBoxLayout(); + applyStartBtn_ = new QPushButton("应用起点"); + applyEndBtn_ = new QPushButton("应用终点"); + connect(applyStartBtn_, &QPushButton::clicked, this, &PathPlanningDialog::applyStartPoint); + connect(applyEndBtn_, &QPushButton::clicked, this, &PathPlanningDialog::applyEndPoint); + applyLayout->addWidget(applyStartBtn_); + applyLayout->addWidget(applyEndBtn_); + layout->addLayout(applyLayout); + + // Connect to map click signal + if (mapPage_) { + connect(mapPage_, &MapPage::mapClicked, this, &PathPlanningDialog::onMapClick); + } else { + qDebug() << "Warning: No MapPage provided for PathPlanningDialog, map clicking disabled."; + } + + pathTable_ = new QTableWidget(); + pathTable_->setColumnCount(2); + pathTable_->setHorizontalHeaderLabels({"经度", "纬度"}); + layout->addWidget(pathTable_); + + auto* pathButtonsLayout = new QHBoxLayout(); + planBtn_ = new QPushButton("规划路径"); + connect(planBtn_, &QPushButton::clicked, this, &PathPlanningDialog::planPath); + pathButtonsLayout->addWidget(planBtn_); + + clearBtn_ = new QPushButton("清除路径规划"); + connect(clearBtn_, &QPushButton::clicked, this, &PathPlanningDialog::clearPath); + pathButtonsLayout->addWidget(clearBtn_); + layout->addLayout(pathButtonsLayout); + + auto* buttonLayout = new QHBoxLayout(); + buttonLayout->addStretch(); + + auto* confirmBtn = new QPushButton("确认"); + connect(confirmBtn, &QPushButton::clicked, this, &QDialog::accept); + buttonLayout->addWidget(confirmBtn); + + auto* cancelBtn = new QPushButton("取消"); + connect(cancelBtn, &QPushButton::clicked, this, &QDialog::reject); + buttonLayout->addWidget(cancelBtn); + + layout->addLayout(buttonLayout); +} + +void PathPlanningDialog::applyStartPoint() { + if (mapPage_) { + QString coord = startInput_->text(); + if (!coord.isEmpty()) { + double lng = mapPage_->parseLng(coord); + double lat = mapPage_->parseLat(coord); + if (lng != 0.0 && lat != 0.0) { + mapPage_->showMarker(lng, lat, "S", "#4CAF50", 0); + QMessageBox::information(this, "成功", "起点已应用到地图"); + } else { + QMessageBox::warning(this, "错误", "起点坐标格式无效"); + } + } else { + QMessageBox::warning(this, "错误", "未选择起点"); + } + } +} + +void PathPlanningDialog::applyEndPoint() { + if (mapPage_) { + QString coord = endInput_->text(); + if (!coord.isEmpty()) { + double lng = mapPage_->parseLng(coord); + double lat = mapPage_->parseLat(coord); + if (lng != 0.0 && lat != 0.0) { + mapPage_->showMarker(lng, lat, "E", "#FF9800", 1); + QMessageBox::information(this, "成功", "终点已应用到地图"); + } else { + QMessageBox::warning(this, "错误", "终点坐标格式无效"); + } + } else { + QMessageBox::warning(this, "错误", "未选择终点"); + } + } +} + +void PathPlanningDialog::planPath() { + QString start = startInput_->text(); + QString end = endInput_->text(); + if (start.isEmpty()) { + QMessageBox::warning(this, "错误", "未选择起点"); + return; + } + if (end.isEmpty()) { + QMessageBox::warning(this, "错误", "未选择终点"); + return; + } + + double startLng = mapPage_->parseLng(start); + double startLat = mapPage_->parseLat(start); + double endLng = mapPage_->parseLng(end); + double endLat = mapPage_->parseLat(end); + + if (startLng == 0.0 || startLat == 0.0 || endLng == 0.0 || endLat == 0.0) { + QMessageBox::warning(this, "错误", "坐标格式无效"); + return; + } + + // Show start and end markers before planning + mapPage_->showMarker(startLng, startLat, "S", "#4CAF50", 0); + mapPage_->showMarker(endLng, endLat, "E", "#FF9800", 1); + + // 获取威胁区域 + const auto &areas = mapPage_->getThreatAreas(); + + auto straightLinePlan = [&](QList>& pts){ + pts.clear(); + pts.append(qMakePair(startLng, startLat)); + double dx = endLng - startLng; + double dy = endLat - startLat; + for (int i = 1; i < 9; ++i) { + double t = static_cast(i) / 9.0; + double pointLng = startLng + t * dx; + double pointLat = startLat + t * dy; + pts.append(qMakePair(pointLng, pointLat)); + } + pts.append(qMakePair(endLng, endLat)); + }; + + QList> pathPoints; + bool usedAStar = false; + + if (!areas.isEmpty()) { + // 构建包围盒 + double minLng = std::min(startLng, endLng); + double maxLng = std::max(startLng, endLng); + double minLat = std::min(startLat, endLat); + double maxLat = std::max(startLat, endLat); + for (const auto &a : areas) { + QString shape = a.value("shape").toString(); + if (shape == "circle" || shape == "圆形") { + double clng = a.value("centerLng").toDouble(); + double clat = a.value("centerLat").toDouble(); + double r_m = a.value("radius").toDouble(); + // 将米粗略转经纬度范围扩展(1度约111km) + double d = r_m / 111000.0 + 0.002; // 加点缓冲 + minLng = std::min(minLng, clng - d); + maxLng = std::max(maxLng, clng + d); + minLat = std::min(minLat, clat - d); + maxLat = std::max(maxLat, clat + d); + } else { // rectangle / 矩形 + QList pts = a.value("points").toList(); + for (const auto &pv : pts) { + auto p = pv.toMap(); + double lng = p.value("lng").toDouble(); + double lat = p.value("lat").toDouble(); + minLng = std::min(minLng, lng); + maxLng = std::max(maxLng, lng); + minLat = std::min(minLat, lat); + maxLat = std::max(maxLat, lat); + } + } + } + + // 网格参数 + int gridW = 80; // 列数 + int gridH = 80; // 行数 + // 避免经纬度范围过小导致除零 + double spanLng = std::max(1e-6, maxLng - minLng); + double spanLat = std::max(1e-6, maxLat - minLat); + + auto iclamp = [&](int v, int lo, int hi){ return v < lo ? lo : (v > hi ? hi : v); }; + auto lngToX = [&](double lng){ return iclamp(int((lng - minLng) / spanLng * (gridW - 1) + 0.5), 0, gridW - 1); }; + auto latToY = [&](double lat){ return iclamp(int((lat - minLat) / spanLat * (gridH - 1) + 0.5), 0, gridH - 1); }; + auto xToLng = [&](int x){ return minLng + (double(x) / (gridW - 1)) * spanLng; }; + auto yToLat = [&](int y){ return minLat + (double(y) / (gridH - 1)) * spanLat; }; + + // 障碍网格 + std::vector blocked(size_t(gridW * gridH), 0); + + constexpr double PI_VAL = 3.14159265358979323846; + auto haversineMeters = [&](double lat1,double lng1,double lat2,double lng2){ + const double R = 6371000.0; + auto deg2rad = [&](double d){ return d * PI_VAL / 180.0; }; + double dLat = deg2rad(lat2 - lat1); + double dLng = deg2rad(lng2 - lng1); + double a = sin(dLat/2)*sin(dLat/2) + cos(deg2rad(lat1))*cos(deg2rad(lat2))*sin(dLng/2)*sin(dLng/2); + double c = 2 * atan2(sqrt(a), sqrt(1-a)); + return R * c; + }; + + auto inCircle = [&](double lng,double lat,double clng,double clat,double r_m){ + return haversineMeters(lat, lng, clat, clng) <= r_m; + }; + auto inRect = [&](double lng,double lat,const QList& pts){ + // 采用点在矩形外接框内(假设矩形边平行经纬线) + double minx= 1e9, maxx=-1e9, miny=1e9, maxy=-1e9; + for (const auto &pv : pts) { + auto p = pv.toMap(); + minx = std::min(minx, p.value("lng").toDouble()); + maxx = std::max(maxx, p.value("lng").toDouble()); + miny = std::min(miny, p.value("lat").toDouble()); + maxy = std::max(maxy, p.value("lat").toDouble()); + } + return lng >= minx && lng <= maxx && lat >= miny && lat <= maxy; + }; + + // 标记威胁为障碍 + for (int y = 0; y < gridH; ++y) { + for (int x = 0; x < gridW; ++x) { + double lng = xToLng(x); + double lat = yToLat(y); + bool hit = false; + for (const auto &a : areas) { + QString shape = a.value("shape").toString(); + if (shape == "circle" || shape == "圆形") { + if (inCircle(lng, lat, a.value("centerLng").toDouble(), a.value("centerLat").toDouble(), a.value("radius").toDouble())) { hit = true; break; } + } else { + if (inRect(lng, lat, a.value("points").toList())) { hit = true; break; } + } + } + blocked[size_t(y*gridW + x)] = hit ? 1 : 0; + } + } + + // A* + struct Node { int x,y; double g,h; int px,py; }; + auto idx = [&](int x,int y){ return y*gridW + x; }; + std::vector gscore(size_t(gridW*gridH), std::numeric_limits::infinity()); + std::vector parent(size_t(gridW*gridH), -1); + const double SQRT2 = 1.41421356237; + auto heuristic = [&](int x,int y){ + // 八方向栅格的octile启发:dx + dy + (sqrt(2)-2)*min(dx,dy) + double dx = std::abs(x - lngToX(endLng)); + double dy = std::abs(y - latToY(endLat)); + double h = (dx > dy) ? (dx + (SQRT2 - 1.0) * dy) : (dy + (SQRT2 - 1.0) * dx); + return h; + }; + auto cmp = [](const Node &a, const Node &b){ return (a.g + a.h) > (b.g + b.h); }; + std::priority_queue, decltype(cmp)> open(cmp); + + int sx = lngToX(startLng), sy = latToY(startLat); + int ex = lngToX(endLng), ey = latToY(endLat); + if (blocked[size_t(idx(sx,sy))]) { + // 若起点落在障碍,尝试在周围寻找最近可行点 + bool found=false; + for (int r=1; r<5 && !found; ++r) { + for (int dy=-r; dy<=r; ++dy) for (int dx=-r; dx<=r; ++dx) { + int nx = iclamp(sx+dx,0,gridW-1); int ny = iclamp(sy+dy,0,gridH-1); + if (!blocked[size_t(idx(nx,ny))]) { sx=nx; sy=ny; found=true; break; } + } + } + } + if (blocked[size_t(idx(ex,ey))]) { + bool found=false; + for (int r=1; r<5 && !found; ++r) { + for (int dy=-r; dy<=r; ++dy) for (int dx=-r; dx<=r; ++dx) { + int nx = iclamp(ex+dx,0,gridW-1); int ny = iclamp(ey+dy,0,gridH-1); + if (!blocked[size_t(idx(nx,ny))]) { ex=nx; ey=ny; found=true; break; } + } + } + } + + if (!blocked[size_t(idx(sx,sy))] && !blocked[size_t(idx(ex,ey))]) { + gscore[size_t(idx(sx,sy))] = 0.0; + open.push(Node{sx,sy,0.0,heuristic(sx,sy),-1,-1}); + std::vector closed(size_t(gridW*gridH), 0); + const int dirs[8][2] = {{1,0},{-1,0},{0,1},{0,-1},{1,1},{1,-1},{-1,1},{-1,-1}}; + bool found=false; + while (!open.empty()) { + Node cur = open.top(); open.pop(); + int ci = idx(cur.x,cur.y); + if (closed[size_t(ci)]) continue; + closed[size_t(ci)] = 1; + parent[size_t(ci)] = (cur.px<0?-1:idx(cur.px,cur.py)); + if (cur.x == ex && cur.y == ey) { found = true; break; } + for (auto &d : dirs) { + int nx = cur.x + d[0]; int ny = cur.y + d[1]; + if (nx<0||nx>=gridW||ny<0||ny>=gridH) continue; + int ni = idx(nx,ny); + if (blocked[size_t(ni)]) continue; + double step = ((d[0]==0||d[1]==0)?1.0:SQRT2); + // 可选:轻微转弯代价,减少之字路;这里用与前一方向对比(若有父节点) + double turnPenalty = 0.0; + // 简化:不记录方向,这里不加转弯罚;如需更直,可设置 turnPenalty = 0.05 当方向改变时。 + double cost = cur.g + step + turnPenalty; + if (cost < gscore[size_t(ni)]) { + gscore[size_t(ni)] = cost; + open.push(Node{nx,ny,cost,heuristic(nx,ny),cur.x,cur.y}); + } + } + } + + if (found) { + usedAStar = true; + // 回溯路径 + QList> rev; + int cx = ex, cy = ey; + int ci = idx(cx,cy); + rev.append(qMakePair(cx,cy)); + while (parent[size_t(ci)] != -1) { + int pi = parent[size_t(ci)]; + int px = pi % gridW; int py = pi / gridW; + rev.append(qMakePair(px,py)); + ci = pi; cx = px; cy = py; + } + // 采样并转经纬度 + pathPoints.clear(); + for (int i = rev.size()-1; i >= 0; --i) { + int x = rev[i].first; int y = rev[i].second; + pathPoints.append(qMakePair(xToLng(x), yToLat(y))); + } + } + } + } + + if (!usedAStar) { + // 无威胁或寻路失败:回退直线插值 + straightLinePlan(pathPoints); + } + + // 约束可见性平滑:在不穿越威胁的前提下尽量拉直路径 + if (pathPoints.size() > 2) { + // 米制平面近似,保证几何与判交稳定 + double midLat = (pathPoints.first().second + pathPoints.last().second) / 2.0; + constexpr double PI_S = 3.14159265358979323846; + double cosLat = std::cos(midLat * PI_S / 180.0); + double mPerDegLat = 111000.0; + double mPerDegLng = 111000.0 * std::max(0.1, cosLat); + + auto toXY = [&](double lng, double lat){ + double x = (lng - pathPoints.first().first) * mPerDegLng; + double y = (lat - pathPoints.first().second) * mPerDegLat; + return qMakePair(x, y); + }; + + auto segIntersectsCircle = [&](double ax,double ay,double bx,double by,double cx,double cy,double r){ + double dx = bx - ax, dy = by - ay; + if (dx == 0 && dy == 0) { + double ex = ax - cx, ey = ay - cy; return std::sqrt(ex*ex + ey*ey) <= r; + } + double t = ((cx - ax)*dx + (cy - ay)*dy) / (dx*dx + dy*dy); + t = std::max(0.0, std::min(1.0, t)); + double px = ax + t*dx, py = ay + t*dy; + double ex = px - cx, ey = py - cy; return (ex*ex + ey*ey) <= r*r; + }; + auto segIntersectsAABB = [&](double ax,double ay,double bx,double by,double minx,double miny,double maxx,double maxy){ + // Liang–Barsky 裁剪:u1<=u2 则相交;点在盒内也算相交 + auto inside = [&](double x,double y){ return x>=minx && x<=maxx && y>=miny && y<=maxy; }; + if (inside(ax,ay) || inside(bx,by)) return true; + double dx = bx - ax, dy = by - ay; + double p[4] = {-dx, dx, -dy, dy}; + double q[4] = {ax - minx, maxx - ax, ay - miny, maxy - ay}; + double u1 = 0.0, u2 = 1.0; + for (int i=0;i<4;++i){ + if (p[i] == 0) { if (q[i] < 0) return false; } + else { + double r = q[i] / p[i]; + if (p[i] < 0) { u1 = std::max(u1, r); } + else { u2 = std::min(u2, r); } + if (u1 > u2) return false; + } + } + return true; + }; + auto segmentClear = [&](const QPair& A, const QPair& B){ + auto a = toXY(A.first, A.second); + auto b = toXY(B.first, B.second); + for (const auto &t : areas) { + QString shape = t.value("shape").toString(); + if (shape == "circle" || shape == "圆形") { + auto c = toXY(t.value("centerLng").toDouble(), t.value("centerLat").toDouble()); + double r = t.value("radius").toDouble(); + if (segIntersectsCircle(a.first,a.second,b.first,b.second,c.first,c.second,r)) return false; + } else { + // 轴对齐矩形 + double minLng= 1e9, maxLng=-1e9, minLat=1e9, maxLat=-1e9; + QList pts = t.value("points").toList(); + for (const auto &pv : pts) { + auto p = pv.toMap(); + minLng = std::min(minLng, p.value("lng").toDouble()); + maxLng = std::max(maxLng, p.value("lng").toDouble()); + minLat = std::min(minLat, p.value("lat").toDouble()); + maxLat = std::max(maxLat, p.value("lat").toDouble()); + } + auto mn = toXY(minLng, minLat); + auto mx = toXY(maxLng, maxLat); + if (segIntersectsAABB(a.first,a.second,b.first,b.second, std::min(mn.first,mx.first), std::min(mn.second,mx.second), std::max(mn.first,mx.first), std::max(mn.second,mx.second))) return false; + } + } + return true; + }; + + // 贪心可见性"拉直":每次连接最远可见点 + QList> smooth; + smooth.append(pathPoints.first()); + int i = 0; + while (i < pathPoints.size()-1) { + int j = pathPoints.size()-1; + // 从远到近找最远可见 + for (; j > i+1; --j) { + if (segmentClear(pathPoints[i], pathPoints[j])) break; + } + smooth.append(pathPoints[j]); + i = j; + } + + // 数量范围控制 + const int MIN_POINTS = 2; // 允许无威胁时仅S/E + const int MAX_POINTS = 50; + QList> finalPts; + if ((int)smooth.size() > MAX_POINTS) { + finalPts.append(smooth.first()); + int need = MAX_POINTS - 2; + for (int k = 1; k <= need; ++k) { + double t = double(k) / double(need + 1); + int idx = int(std::round(t * (smooth.size() - 1))); + idx = std::clamp(idx, 1, smooth.size()-2); + finalPts.append(smooth[idx]); + } + finalPts.append(smooth.last()); + } else if ((int)smooth.size() < MIN_POINTS && (int)pathPoints.size() >= MIN_POINTS) { + finalPts = pathPoints; // 极少见,保持原始 + } else { + finalPts = smooth; + } + pathPoints = finalPts; + } + + // 更新表格 + pathTable_->clear(); + pathTable_->setHorizontalHeaderLabels({"经度", "纬度"}); + pathTable_->setRowCount(pathPoints.size()); + for (int i = 0; i < pathPoints.size(); ++i) { + pathTable_->setItem(i, 0, new QTableWidgetItem(QString::number(pathPoints[i].first, 'f', 6))); + pathTable_->setItem(i, 1, new QTableWidgetItem(QString::number(pathPoints[i].second, 'f', 6))); + } + + // 生成 JSON + QString pathData = "["; + for (int i = 0; i < pathPoints.size(); ++i) { + if (i > 0) pathData += ","; + pathData += QString("[%1, %2]").arg(pathPoints[i].first, 0, 'f', 6).arg(pathPoints[i].second, 0, 'f', 6); + } + pathData += "]"; + + // 保存并可视化 + pathData_ = pathData; + if (mapPage_) { + mapPage_->visualizePath(pathData_); + } + + if (usedAStar) + QMessageBox::information(this, "成功", "路径规划完成:已避开威胁区域"); + else + QMessageBox::information(this, "成功", "路径规划完成(未检测到威胁或已回退为直线)"); +} + +QString PathPlanningDialog::getPathData() const { + return pathData_; +} + +// Add clearPath implementation +void PathPlanningDialog::clearPath() { + if (mapPage_) { + mapPage_->clearPathOverlays(); + } + startInput_->clear(); + endInput_->clear(); + pathTable_->setRowCount(0); + pathData_ = ""; + QMessageBox::information(this, "成功", "路径规划已清除"); +} + +void PathPlanningDialog::onMapClick(double lng, double lat) { + QString coord = QString("[%1, %2]").arg(lng, 0, 'f', 6).arg(lat, 0, 'f', 6); + if (selectingStart_) { + startInput_->setText(coord); + mapPage_->showMarker(lng, lat, "S", "#4CAF50", 0); + selectingStart_ = false; + mapPage_->removeClickListener(); + QMessageBox::information(this, "成功", "起点已选择"); + // 无需隐藏地图或显示对话框,用户可继续交互 + } else if (selectingEnd_) { + endInput_->setText(coord); + mapPage_->showMarker(lng, lat, "E", "#FF9800", 1); + selectingEnd_ = false; + mapPage_->removeClickListener(); + QMessageBox::information(this, "成功", "终点已选择"); + // 无需隐藏地图或显示对话框 + } +} + +AreaCoverageDialog::AreaCoverageDialog(QWidget* parent, MapPage* mapPage) : QDialog(parent), mapPage_(mapPage), coveragePathData_("") { + setWindowTitle("区域覆盖路径规划"); + setMinimumSize(700, 600); + auto* mainLayout = new QVBoxLayout(this); + mainLayout->setContentsMargins(20, 20, 20, 20); + mainLayout->setSpacing(15); + + // Shape selection + auto* shapeLayout = new QHBoxLayout(); + shapeLayout->addWidget(new QLabel("区域形状:")); + shapeCombo_ = new QComboBox(); + shapeCombo_->addItems({"圆形", "多边形"}); + connect(shapeCombo_, QOverload::of(&QComboBox::currentIndexChanged), this, &AreaCoverageDialog::onShapeChanged); + shapeLayout->addWidget(shapeCombo_); + shapeLayout->addStretch(); + mainLayout->addLayout(shapeLayout); + + // Dynamic inputs based on shape + QWidget* inputWidget = new QWidget(); + auto* inputLayout = new QVBoxLayout(inputWidget); + mainLayout->addWidget(inputWidget); + + // Circle inputs (default) + circleWidget_ = setupCircleInputs(); + inputLayout->addWidget(circleWidget_); + + // Polygon inputs (hidden initially) + polygonWidget_ = setupPolygonInputs(); + inputLayout->addWidget(polygonWidget_); + + // Search mode + auto* modeGroupBox = new QGroupBox("搜索模式"); + auto* modeLayout = new QHBoxLayout(modeGroupBox); + efficiencyRadio_ = new QRadioButton("高效率"); + fullRangeRadio_ = new QRadioButton("全范围"); + efficiencyRadio_->setChecked(true); + modeGroup_ = new QButtonGroup(this); + modeGroup_->addButton(efficiencyRadio_); + modeGroup_->addButton(fullRangeRadio_); + modeLayout->addWidget(efficiencyRadio_); + modeLayout->addWidget(fullRangeRadio_); + modeLayout->addStretch(); + mainLayout->addWidget(modeGroupBox); + + // Drone count + auto* droneLayout = new QHBoxLayout(); + droneLayout->addWidget(new QLabel("无人机数量:")); + droneCountSpin_ = new QSpinBox(); + droneCountSpin_->setRange(1, 10); + droneCountSpin_->setValue(1); + droneLayout->addWidget(droneCountSpin_); + droneLayout->addStretch(); + mainLayout->addLayout(droneLayout); + + // Path table + pathTable_ = new QTableWidget(); + pathTable_->setColumnCount(2); + pathTable_->setHorizontalHeaderLabels({"经度", "纬度"}); + pathTable_->setMinimumHeight(150); + mainLayout->addWidget(pathTable_); + + // Plan buttons + auto* planButtonsLayout = new QHBoxLayout(); + planBtn_ = new QPushButton("规划路径"); + connect(planBtn_, &QPushButton::clicked, this, &AreaCoverageDialog::planCoveragePath); + planButtonsLayout->addWidget(planBtn_); + + clearBtn_ = new QPushButton("清除规划"); + connect(clearBtn_, &QPushButton::clicked, this, &AreaCoverageDialog::clearCoverage); + planButtonsLayout->addWidget(clearBtn_); + planButtonsLayout->addStretch(); + mainLayout->addLayout(planButtonsLayout); + + // Confirm/Cancel + auto* buttonLayout = new QHBoxLayout(); + buttonLayout->addStretch(); + auto* confirmBtn = new QPushButton("确认"); + connect(confirmBtn, &QPushButton::clicked, this, &QDialog::accept); + buttonLayout->addWidget(confirmBtn); + auto* cancelBtn = new QPushButton("取消"); + connect(cancelBtn, &QPushButton::clicked, this, &QDialog::reject); + buttonLayout->addWidget(cancelBtn); + mainLayout->addLayout(buttonLayout); + + // Connect map clicks + connect(mapPage_, &MapPage::mapClicked, this, &AreaCoverageDialog::onMapClick); + + // Connect table selection for polygon + connect(verticesTable_, &QTableWidget::currentCellChanged, this, [this](int currentRow, int currentColumn, int previousRow, int previousColumn) { + Q_UNUSED(currentColumn); + Q_UNUSED(previousRow); + Q_UNUSED(previousColumn); + currentVertexRow_ = currentRow; + }); + + onShapeChanged(0); // Initialize with circle +} + +QWidget* AreaCoverageDialog::setupCircleInputs() { + auto* circleWidget = new QWidget(); + auto* circleLayout = new QFormLayout(circleWidget); + centerLngInput_ = new QLineEdit(); + centerLngInput_->setPlaceholderText("中心经度"); + circleLayout->addRow("中心经度:", centerLngInput_); + centerLatInput_ = new QLineEdit(); + centerLatInput_->setPlaceholderText("中心纬度"); + circleLayout->addRow("中心纬度:", centerLatInput_); + radiusInput_ = new QLineEdit(); + radiusInput_->setPlaceholderText("半径 (km)"); + radiusInput_->setText("1.0"); + circleLayout->addRow("半径 (km):", radiusInput_); + return circleWidget; +} + +QWidget* AreaCoverageDialog::setupPolygonInputs() { + auto* polyWidget = new QWidget(); + auto* polyLayout = new QVBoxLayout(polyWidget); + + verticesTable_ = new QTableWidget(); + verticesTable_->setColumnCount(2); + verticesTable_->setHorizontalHeaderLabels({"经度", "纬度"}); + polyLayout->addWidget(verticesTable_); + + auto* polyButtonsLayout = new QHBoxLayout(); + addVertexBtn_ = new QPushButton("添加顶点"); + connect(addVertexBtn_, &QPushButton::clicked, this, &AreaCoverageDialog::addVertex); + polyButtonsLayout->addWidget(addVertexBtn_); + removeVertexBtn_ = new QPushButton("移除顶点"); + connect(removeVertexBtn_, &QPushButton::clicked, this, &AreaCoverageDialog::removeVertex); + polyButtonsLayout->addWidget(removeVertexBtn_); + selectVertexBtn_ = new QPushButton("地图选择顶点"); + connect(selectVertexBtn_, &QPushButton::clicked, this, &AreaCoverageDialog::selectVertexOnMap); + polyButtonsLayout->addWidget(selectVertexBtn_); + polyButtonsLayout->addStretch(); + polyLayout->addLayout(polyButtonsLayout); + + return polyWidget; +} + +void AreaCoverageDialog::onShapeChanged(int index) { + if (index == 0) { // Circle + circleWidget_->setVisible(true); + polygonWidget_->setVisible(false); + } else { // Polygon + circleWidget_->setVisible(false); + polygonWidget_->setVisible(true); + } +} + +void AreaCoverageDialog::addVertex() { + int row = verticesTable_->rowCount(); + verticesTable_->insertRow(row); + verticesTable_->setItem(row, 0, new QTableWidgetItem("0.000000")); + verticesTable_->setItem(row, 1, new QTableWidgetItem("0.000000")); + vertices_.append(qMakePair(0.0, 0.0)); +} + +void AreaCoverageDialog::removeVertex() { + int row = verticesTable_->currentRow(); + if (row >= 0) { + vertices_.removeAt(row); + verticesTable_->removeRow(row); + } +} + +void AreaCoverageDialog::selectVertexOnMap() { + if (currentVertexRow_ < 0) { + addVertex(); + currentVertexRow_ = verticesTable_->rowCount() - 1; + } + QMessageBox::information(this, "提示", "点击地图选择顶点位置"); + selectingVertex_ = true; + mapPage_->addClickListener(); +} + +void AreaCoverageDialog::onMapClick(double lng, double lat) { + if (selectingVertex_) { + if (currentVertexRow_ >= 0 && currentVertexRow_ < verticesTable_->rowCount()) { + verticesTable_->setItem(currentVertexRow_, 0, new QTableWidgetItem(QString::number(lng, 'f', 6))); + verticesTable_->setItem(currentVertexRow_, 1, new QTableWidgetItem(QString::number(lat, 'f', 6))); + vertices_[currentVertexRow_] = qMakePair(lng, lat); + mapPage_->showMarker(lng, lat, QString::number(currentVertexRow_ + 1), "#2196F3", currentVertexRow_); + selectingVertex_ = false; + mapPage_->removeClickListener(); + QMessageBox::information(this, "成功", "顶点已更新"); + } + } +} + +void AreaCoverageDialog::planCoveragePath() { + // Update vertices from table for polygon + if (shapeCombo_->currentIndex() == 1) { + vertices_.clear(); + for (int i = 0; i < verticesTable_->rowCount(); ++i) { + double lng = verticesTable_->item(i, 0) ? verticesTable_->item(i, 0)->text().toDouble() : 0.0; + double lat = verticesTable_->item(i, 1) ? verticesTable_->item(i, 1)->text().toDouble() : 0.0; + vertices_.append(qMakePair(lng, lat)); + } + } + + // Validate inputs based on shape + if (shapeCombo_->currentIndex() == 0) { // Circle + bool ok1, ok2, ok3; + double centerLng = centerLngInput_->text().toDouble(&ok1); + double centerLat = centerLatInput_->text().toDouble(&ok2); + double radiusKm = radiusInput_->text().toDouble(&ok3); + if (!ok1 || !ok2 || !ok3 || radiusKm <= 0.0) { + QMessageBox::warning(this, "错误", "无效的圆形参数"); + return; + } + if (mapPage_) mapPage_->visualizeCoverageAreaCircle(centerLng, centerLat, radiusKm); + + // 生成"割草式"覆盖路径(水平扫掠线) + QList> path; + // 将 km 转为度近似(纬度 1 度≈111 km, 经度需乘以 cos(lat)) + constexpr double KM_PER_DEG_LAT = 111.0; + double cosLat = std::max(0.1, std::cos(centerLat * 3.14159265358979323846 / 180.0)); + double degLatPerKm = 1.0 / KM_PER_DEG_LAT; + double degLngPerKm = 1.0 / (KM_PER_DEG_LAT * cosLat); + double rLat = radiusKm * degLatPerKm; + // double rLng = radiusKm * degLngPerKm; // 移除未使用变量 + + // 步距:根据效率/全范围选择 + bool efficiency = efficiencyRadio_->isChecked(); + double laneSpacingKm = efficiency ? (radiusKm / 8.0) : (radiusKm / 12.0); + laneSpacingKm = std::max(0.05, laneSpacingKm); // 最小 50m + double laneSpacingLat = laneSpacingKm * degLatPerKm; + + // 扫掠:从下到上,按 y 递增;每条线在圆内求 x 范围 + int lineIdx = 0; + for (double y = centerLat - rLat; y <= centerLat + rLat + 1e-9; y += laneSpacingLat) { + double dy = (y - centerLat) / degLatPerKm; // 转回 km + double maxDxKm = std::max(0.0, std::sqrt(std::max(0.0, radiusKm*radiusKm - dy*dy))); + double dxLng = (maxDxKm * degLngPerKm); + double xLeft = centerLng - dxLng; + double xRight = centerLng + dxLng; + if (xRight < xLeft) std::swap(xLeft, xRight); + if (lineIdx % 2 == 0) { + path.append(qMakePair(xLeft, y)); + path.append(qMakePair(xRight, y)); + } else { + path.append(qMakePair(xRight, y)); + path.append(qMakePair(xLeft, y)); + } + ++lineIdx; + } + + // 更新表格与 JSON + pathTable_->setRowCount(path.size()); + for (int i = 0; i < path.size(); ++i) { + pathTable_->setItem(i, 0, new QTableWidgetItem(QString::number(path[i].first, 'f', 6))); + pathTable_->setItem(i, 1, new QTableWidgetItem(QString::number(path[i].second, 'f', 6))); + } + QString json = "["; + for (int i = 0; i < path.size(); ++i) { + if (i) json += ","; + json += QString("[%1,%2]").arg(path[i].first,0,'f',6).arg(path[i].second,0,'f',6); + } + json += "]"; + coveragePathData_ = json; + } else { // Polygon + if (vertices_.size() < 3) { + QMessageBox::warning(this, "错误", "多边形至少需要3个顶点"); + return; + } + if (mapPage_) mapPage_->visualizeCoverageAreaPolygon(vertices_); + + // 计算多边形包围盒 + double minLng = 180, maxLng = -180, minLat = 90, maxLat = -90; + for (auto &v : vertices_) { + minLng = qMin(minLng, v.first); + maxLng = qMax(maxLng, v.first); + minLat = qMin(minLat, v.second); + maxLat = qMax(maxLat, v.second); + } + // 行距:依据高度模式(效率/全范围)调整密度 + bool efficiency = efficiencyRadio_->isChecked(); + double latSpan = maxLat - minLat; + double lanes = efficiency ? 16.0 : 24.0; + lanes = std::max(6.0, lanes); + double laneStep = (latSpan > 1e-9) ? (latSpan / lanes) : 0.0005; + + auto pointInPolygon = [&](double x, double y){ + // 射线法 + bool inside = false; + int n = vertices_.size(); + for (int i = 0, j = n - 1; i < n; j = i++) { + double xi = vertices_[i].first, yi = vertices_[i].second; + double xj = vertices_[j].first, yj = vertices_[j].second; + bool intersect = ((yi > y) != (yj > y)) && + (x < (xj - xi) * (y - yi) / ((yj - yi) == 0 ? 1e-12 : (yj - yi)) + xi); + if (intersect) inside = !inside; + } + return inside; + }; + + QList> path; + int lineIdx = 0; + for (double y = minLat; y <= maxLat + 1e-12; y += laneStep) { + // 在该水平线采样若干点,取位于多边形内的连续段 + int samples = 64; + QList> linePts; + for (int s = 0; s <= samples; ++s) { + double t = double(s) / double(samples); + double x = minLng + t * (maxLng - minLng); + if (pointInPolygon(x, y)) { + linePts.append(qMakePair(x, y)); + } + } + if (!linePts.isEmpty()) { + if (lineIdx % 2 == 0) { + for (auto &p : linePts) path.append(p); + } else { + for (int k = linePts.size()-1; k >= 0; --k) path.append(linePts[k]); + } + ++lineIdx; + } + } + + // 更新表格与 JSON + pathTable_->setRowCount(path.size()); + for (int i = 0; i < path.size(); ++i) { + pathTable_->setItem(i, 0, new QTableWidgetItem(QString::number(path[i].first, 'f', 6))); + pathTable_->setItem(i, 1, new QTableWidgetItem(QString::number(path[i].second, 'f', 6))); + } + QString json = "["; + for (int i = 0; i < path.size(); ++i) { + if (i) json += ","; + json += QString("[%1,%2]").arg(path[i].first,0,'f',6).arg(path[i].second,0,'f',6); + } + json += "]"; + coveragePathData_ = json; + } + + // Visualize immediately + if (mapPage_) { + mapPage_->visualizeCoveragePath(coveragePathData_); + } + + // 简要提示 + int drones = droneCountSpin_->value(); + bool isEfficiency = efficiencyRadio_->isChecked(); + QString mode = isEfficiency ? "高效率" : "全范围"; + QMessageBox::information(this, "成功", QString("覆盖路径规划完成 (%1模式, %2架无人机)").arg(mode).arg(drones)); +} + +void AreaCoverageDialog::generateMockCoveragePath() { + // Placeholder: actual generation in planCoveragePath + qDebug() << "生成模拟覆盖路径"; +} + +void AreaCoverageDialog::clearCoverage() { + if (mapPage_) { + mapPage_->clearCoverageOverlays(); + } + pathTable_->setRowCount(0); + coveragePathData_ = ""; + vertices_.clear(); + verticesTable_->setRowCount(0); + centerLngInput_->clear(); + centerLatInput_->clear(); + radiusInput_->clear(); + QMessageBox::information(this, "成功", "覆盖规划已清除"); +} + + +// Implement LocateDialog methods +LocateDialog::LocateDialog(QWidget *parent) : QDialog(parent), lng_(0.0), lat_(0.0) { + setWindowTitle("地图定位"); + setMinimumSize(400, 200); + auto* layout = new QVBoxLayout(this); + layout->setContentsMargins(20, 20, 20, 20); + + auto* formLayout = new QFormLayout(); + + lngInput_ = new QLineEdit(); + lngInput_->setPlaceholderText("请输入经度"); + formLayout->addRow("经度:", lngInput_); + + latInput_ = new QLineEdit(); + latInput_->setPlaceholderText("请输入纬度"); + formLayout->addRow("纬度:", latInput_); + + layout->addLayout(formLayout); + + auto* buttonLayout = new QHBoxLayout(); + buttonLayout->addStretch(); + + auto* confirmBtn = new QPushButton("确认"); + buttonLayout->addWidget(confirmBtn); + + auto* cancelBtn = new QPushButton("取消"); + buttonLayout->addWidget(cancelBtn); + + layout->addLayout(buttonLayout); + + connect(confirmBtn, &QPushButton::clicked, this, &LocateDialog::onConfirm); + connect(cancelBtn, &QPushButton::clicked, this, &QDialog::reject); +} + + +void LocateDialog::onConfirm() { + bool ok1, ok2; + lng_ = lngInput_->text().toDouble(&ok1); + lat_ = latInput_->text().toDouble(&ok2); + + if (ok1 && ok2) { + accept(); + } else { + QMessageBox::warning(this, "错误", "请输入有效的经纬度坐标"); + } +} + +double LocateDialog::getLongitude() const { + return lng_; +} + +double LocateDialog::getLatitude() const { + return lat_; +} + +// 更新 handleMapClick 以支持绘制模式 +void MapPage::handleMapClick(double lng, double lat) { + qDebug() << "Map clicked in C++: lng=" << lng << ", lat=" << lat; + emit mapClicked(lng, lat); // 始终发出信号,dialog 会根据模式处理 + // 如果在绘制模式,可以在这里添加额外逻辑,但由于连接在 dialog 中,保持简单 +} + +// 移除不必要的 handleDrawingClick +// void MapPage::handleDrawingClick(double lng, double lat) { } + +void MapPage::onConsoleMessage(QWebEnginePage::JavaScriptConsoleMessageLevel level, const QString &message, int lineNumber, const QString &sourceID) { + qDebug() << "Console message:" << level << message << "at line" << lineNumber << "source:" << sourceID; +} + +// Implement MapPage missing methods +QWidget* MapPage::createMapControlsWidget() { + auto* widget = new QWidget(this); + auto* layout = new QHBoxLayout(widget); + layout->setContentsMargins(0, 0, 0, 0); + return widget; +} + +// 在 MapPage 中实现 +void MapPage::enableDrawingMode(const QString& shape) { + isDrawing_ = true; + drawingShape_ = shape; + drawingPoints_.clear(); + addClickListener(); +} + +void MapPage::disableDrawingMode() { + isDrawing_ = false; + removeClickListener(); +} + +void MapPage::addThreatOverlay(const QString& shape, const QVariantMap& params) { + QString overlayId = "threat_" + QString::number(threatAreas_.size()); // 唯一 ID + QVariantMap paramsWithId = params; + paramsWithId["id"] = overlayId; + + QString js; + if (shape == "circle") { + js = QString(R"( + var circle = new AMap.Circle({ + center: new AMap.LngLat(%1, %2), + radius: %3, + fillColor: '%4', + fillOpacity: 0.3, + strokeColor: '%4', + strokeWeight: 2 + }); + circle.setMap(window.map); + window.%5 = circle; // 存储以便移除 + window.map.setFitView([circle]); // 缩放到 overlay + )").arg(params["centerLng"].toDouble()).arg(params["centerLat"].toDouble()) + .arg(params["radius"].toDouble()).arg(params["color"].toString()).arg(overlayId); + } else if (shape == "rectangle") { + QString path = "["; + QList points = params["points"].toList(); + for (int i = 0; i < points.size(); ++i) { + QVariantMap p = points[i].toMap(); + if (i > 0) path += ","; + path += QString("[%1,%2]").arg(p["lng"].toDouble()).arg(p["lat"].toDouble()); + } + path += "]"; + js = QString(R"( + var polygon = new AMap.Polygon({ + path: %1, + fillColor: '%2', + fillOpacity: 0.3, + strokeColor: '%2', + strokeWeight: 2 + }); + polygon.setMap(window.map); + window.%5 = polygon; // 存储以便移除 + window.map.setFitView([polygon]); // 缩放到 overlay + )").arg(path).arg(params["color"].toString()).arg(overlayId); + } + runMapJavaScript(js + " console.log('Overlay added: " + overlayId + "'); "); + threatAreas_.append(paramsWithId); // 存储带 ID +} + +void MapPage::onMapReadyFromJS() { + isMapReady_ = true; + emit mapReady(); +} + +void MapPage::loadSavedPath() { + QFile file("task_path.json"); + if (file.open(QIODevice::ReadOnly)) { + QString pathData = file.readAll(); + file.close(); + if (!pathData.isEmpty()) { + visualizePath(pathData); + QMessageBox::information(this, "成功", "已加载并展示保存的路径"); + } else { + QMessageBox::warning(this, "错误", "保存路径为空"); + } + } else { + QMessageBox::warning(this, "错误", "无法打开保存文件"); + } +} diff --git a/Src/pages/mappage.h b/Src/pages/mappage.h new file mode 100644 index 0000000..3385f71 --- /dev/null +++ b/Src/pages/mappage.h @@ -0,0 +1,300 @@ +#ifndef MAPPAGE_H +#define MAPPAGE_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mapbridge.h" + +class CustomWebEnginePage : public QWebEnginePage { + Q_OBJECT +signals: + void consoleMessage(QWebEnginePage::JavaScriptConsoleMessageLevel level, const QString &message, int lineNumber, const QString &sourceID); +public: + CustomWebEnginePage(QObject* parent = nullptr) : QWebEnginePage(parent) {} +protected: + void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString& message, int lineNumber, const QString& sourceID) override { + qDebug() << "JS 消息 (级别:" << level << "):" << message << " (行:" << lineNumber << ", 来源:" << sourceID << ")"; + emit consoleMessage(level, message, lineNumber, sourceID); + } +}; + +// 前向声明 +class MapPage; +class ThreatAreaDialog; +class PathPlanningDialog; +class AreaCoverageDialog; + +#ifdef INCLUDE_AREA_SEARCH +class AreaSearchDialog; +#endif + +class ThreatAreaDialog : public QDialog { + Q_OBJECT +public: + ThreatAreaDialog(QWidget* parent = nullptr, MapPage* mapPage = nullptr); +private slots: + void addArea(); + void updateThreatStats(); + void startDrawingThreatArea(); + void onShapeChanged(int index); + void handleDrawingClick(double lng, double lat); + void finishDrawing(); + void editArea(); + void deleteArea(); +private: + QComboBox* typeCombo_; + QDateTimeEdit* startTimeEdit_; + QDateTimeEdit* endTimeEdit_; + QComboBox* shapeCombo_; + QComboBox* colorCombo_; + QTableWidget* areaTable_; + QLineEdit* coordInput_; + QPushButton* drawOnMapBtn_; + + // 新增输入字段 + QWidget* circleInputWidget_; + QWidget* rectangleInputWidget_; + QLineEdit* centerLngInput_; + QLineEdit* centerLatInput_; + QLineEdit* radiusInput_; + QTableWidget* rectPointsTable_; + + MapPage* mapPage_; + QString currentShape_; + QList> drawingPoints_; + QComboBox* levelCombo_; + QPushButton* editBtn_; + QPushButton* deleteBtn_; + int selectedRow_ = -1; +}; + +class MapPage; + +class PathPlanningDialog : public QDialog { + Q_OBJECT +public: + PathPlanningDialog(QWidget* parent = nullptr, MapPage* mapPage = nullptr); + QString getStartCoord() const { return startInput_->text(); } + QString getEndCoord() const { return endInput_->text(); } + QString getPathData() const; +private slots: + void planPath(); + void applyStartPoint(); + void applyEndPoint(); + void onMapClick(double lng, double lat); + void clearPath(); +private: + QLineEdit* startInput_; + QLineEdit* endInput_; + QTableWidget* pathTable_; + QPushButton* planBtn_; + QPushButton* clearBtn_; + QPushButton* applyStartBtn_; + QPushButton* applyEndBtn_; + QPushButton* selectStartBtn_; + QPushButton* selectEndBtn_; + MapPage* mapPage_; + QString pathData_; + bool selectingStart_ = false; + bool selectingEnd_ = false; +}; + +class AreaCoverageDialog : public QDialog { + Q_OBJECT +public: + AreaCoverageDialog(QWidget* parent = nullptr, MapPage* mapPage = nullptr); + QString getCoveragePathData() const { return coveragePathData_; } +private slots: + void onShapeChanged(int index); + void addVertex(); + void removeVertex(); + void selectVertexOnMap(); + void planCoveragePath(); + void clearCoverage(); + void onMapClick(double lng, double lat); +private: + QWidget* setupCircleInputs(); + QWidget* setupPolygonInputs(); + void generateMockCoveragePath(); + QComboBox* shapeCombo_; + QLineEdit* centerLngInput_; + QLineEdit* centerLatInput_; + QLineEdit* radiusInput_; + QTableWidget* verticesTable_; + QPushButton* addVertexBtn_; + QPushButton* removeVertexBtn_; + QPushButton* selectVertexBtn_; + QButtonGroup* modeGroup_; + QRadioButton* efficiencyRadio_; + QRadioButton* fullRangeRadio_; + QSpinBox* droneCountSpin_; + QTableWidget* pathTable_; + QPushButton* planBtn_; + QPushButton* clearBtn_; + QWidget* circleWidget_; + QWidget* polygonWidget_; + MapPage* mapPage_; + QString coveragePathData_; + bool selectingVertex_ = false; + int currentVertexRow_ = -1; + QList> vertices_; +}; + +class LocateDialog : public QDialog { + Q_OBJECT +public: + LocateDialog(QWidget* parent = nullptr); + double getLongitude() const; + double getLatitude() const; +private slots: + void onConfirm(); +private: + QLineEdit* lngInput_; + QLineEdit* latInput_; + double lng_; + double lat_; +}; + +#ifdef INCLUDE_AREA_SEARCH +class AreaSearchDialog : public QDialog { + Q_OBJECT +public: + AreaSearchDialog(QWidget* parent = nullptr); +private slots: + void onConfirm(); +private: + QLineEdit* minLngInput_; + QLineEdit* minLatInput_; + QLineEdit* maxLngInput_; + QLineEdit* maxLatInput_; +}; +#endif + +class MapPage : public QWidget { + Q_OBJECT + +public: + explicit MapPage(QWidget* parent = nullptr); + ~MapPage(); + QWebEngineView* getMapView() const { return mapView_; } + + QComboBox* getHeightCombo() const { return heightCombo_; } + QPushButton* getDownloadMapBtn() const { return downloadMapBtn_; } + +signals: + void heightChanged(const QString& height); + void downloadMapRequested(); + void setThreatRequested(); + void pathPlanningRequested(); + void areaCoverageRequested(); + void mapClicked(double lng, double lat); + void mapReady(); // 新信号:地图初始化完成 + +private slots: + void onHeightChanged(); + void onDownloadMapClicked(); + void onSetThreatClicked(); + void onPathPlanningClicked(); + void onAreaCoverageClicked(); +#ifdef INCLUDE_AREA_SEARCH + void onAreaSearchClicked(); +#endif + void onSearchMapClicked(); + void onConsoleMessage(QWebEnginePage::JavaScriptConsoleMessageLevel level, const QString &message, int lineNumber, const QString &sourceID); + void onPageLoaded(bool ok); + void loadSavedPath(); + void onMapReadyFromJS(); + +public slots: + void addClickListener(); + void removeClickListener(); + void handleMapClick(double lng, double lat); + void visualizePath(const QString& pathData); + void clearPathOverlays(); + void runMapJavaScript(const QString& js); + double parseLng(const QString& coord) const; + double parseLat(const QString& coord) const; + void showMarker(double lng, double lat, const QString& label, const QString& color, int index); + void visualizeCoveragePath(const QString& pathData); + void clearCoverageOverlays(); + void visualizeCoverageAreaCircle(double centerLng, double centerLat, double radiusKm); + void visualizeCoverageAreaPolygon(const QList>& vertices); + void enableDrawingMode(const QString& shape); + void disableDrawingMode(); + void addThreatOverlay(const QString& shape, const QVariantMap& params); + void removeThreatOverlay(int index); + +private: + void setupUI(); + void setupMapControls(); + void setupMapArea(); + void setupControlBar(); + void enableGeolocation(); + QWidget* createMapControlsWidget(); + QWidget* createControlBarWidget(); + + QFrame* mapArea_; + QComboBox* heightCombo_; + QPushButton* downloadMapBtn_; + QWebEngineView* mapView_; + QPushButton* setThreatBtn_; + QPushButton* pathPlanningBtn_; + QPushButton* areaCoverageBtn_; +#ifdef INCLUDE_AREA_SEARCH + QPushButton* areaSearchBtn_; +#endif + QLineEdit* coordInput_; + QPushButton* locateBtn_; + QPushButton* searchMapBtn_; + ThreatAreaDialog* threatDialog_; + PathPlanningDialog* planningDialog_; + AreaCoverageDialog* coverageDialog_; + LocateDialog* locateDialog_; +#ifdef INCLUDE_AREA_SEARCH + AreaSearchDialog* searchDialog_; +#endif + int baseFontSize_ = 10; + QString pathOverlayId_ = "pathOverlay"; + QString startMarkerId_ = "startMarker"; + QString endMarkerId_ = "endMarker"; + QString currentPathData_; + MapBridge* bridge_; + QWebChannel* channel_; + QString coverageOverlayId_ = "coverageOverlay"; + QString areaOverlayId_ = "areaOverlay"; + QString currentCoveragePathData_; + bool isDrawing_ = false; + QString drawingShape_; + QList> drawingPoints_; + QList threatAreas_; + bool isMapReady_ = false; // 跟踪地图就绪状态 + +public: + const QList& getThreatAreas() const { return threatAreas_; } +}; + +#endif // MAPPAGE_H diff --git a/Src/pages/mappage_remote.cpp b/Src/pages/mappage_remote.cpp new file mode 100644 index 0000000..519cfb0 --- /dev/null +++ b/Src/pages/mappage_remote.cpp @@ -0,0 +1,1824 @@ +#include "mappage.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mapbridge.h" + +MapPage::MapPage(QWidget *parent) : QWidget(parent), + mapArea_(nullptr), + heightCombo_(nullptr), + downloadMapBtn_(nullptr), + mapView_(nullptr), + setThreatBtn_(nullptr), + pathPlanningBtn_(nullptr), + areaCoverageBtn_(nullptr), + coordInput_(nullptr), + locateBtn_(nullptr), + searchMapBtn_(nullptr), + threatDialog_(nullptr), + planningDialog_(nullptr), + coverageDialog_(nullptr), + locateDialog_(nullptr), + baseFontSize_(10), + pathOverlayId_("pathOverlay"), + startMarkerId_("startMarker"), + endMarkerId_("endMarker"), + currentPathData_(""), + bridge_(nullptr), + channel_(nullptr), + coverageOverlayId_("coverageOverlay"), + areaOverlayId_("areaOverlay"), + currentCoveragePathData_(""), + isDrawing_(false), + drawingShape_(""), + drawingPoints_(), + threatAreas_() { + setupUI(); + enableGeolocation(); + qDebug() << "MapPage 构造函数完成"; + threatDialog_ = new ThreatAreaDialog(this, this); + planningDialog_ = new PathPlanningDialog(this, this); + coverageDialog_ = new AreaCoverageDialog(this, this); + locateDialog_ = new LocateDialog(this); + CustomWebEnginePage* page = qobject_cast(mapView_->page()); + if (page) { + connect(page, &CustomWebEnginePage::consoleMessage, this, &MapPage::onConsoleMessage); + } +} + +MapPage::~MapPage() {} + +void MapPage::setupUI() { + auto* mainLayout = new QVBoxLayout(this); + mainLayout->setSpacing(8); + mainLayout->setContentsMargins(0, 0, 0, 0); + + auto* title = new QLabel("路径监控"); + title->setProperty("class", "section"); + mainLayout->addWidget(title); + + mainLayout->addWidget(createMapControlsWidget()); + + setupMapArea(); + mainLayout->addWidget(mapArea_, 1); + + setupControlBar(); + mainLayout->addWidget(createControlBarWidget()); +} + +void MapPage::setupMapArea() { + mapArea_ = new QFrame(this); + mapArea_->setMinimumHeight(520); + auto* layout = new QVBoxLayout(mapArea_); + layout->setContentsMargins(0, 0, 0, 0); + + mapView_ = new QWebEngineView(mapArea_); + mapView_->setPage(new CustomWebEnginePage(mapView_)); + layout->addWidget(mapView_); + + // Setup WebChannel and bridge before loading HTML + channel_ = new QWebChannel(this); + bridge_ = new MapBridge(this); + connect(bridge_, &MapBridge::mapClicked, this, &MapPage::handleMapClick); + channel_->registerObject("bridge", bridge_); + mapView_->page()->setWebChannel(channel_); + + qDebug() << "WebChannel and bridge set up before page load"; + + const QString defaultHtml = R"( + + + + + + + 卫星和路网图 + + + + + + + +
+ + + )"; + mapView_->setHtml(defaultHtml, QUrl()); + connect(mapView_->page(), &QWebEnginePage::loadFinished, this, &MapPage::onPageLoaded); +} + +void MapPage::setupControlBar() { + // 控制条设置 +} + +QWidget* MapPage::createControlBarWidget() { + auto* bar = new QWidget(this); + auto* layout = new QHBoxLayout(bar); + layout->setContentsMargins(0, 0, 0, 0); + + auto* heightLabel = new QLabel("航线高度:"); + layout->addWidget(heightLabel); + + heightCombo_ = new QComboBox(); + heightCombo_->addItems({"30.00", "50.00", "80.00"}); + heightCombo_->setFixedWidth(100); + connect(heightCombo_, QOverload::of(&QComboBox::currentTextChanged), + this, &MapPage::onHeightChanged); + layout->addWidget(heightCombo_); + + layout->addStretch(1); + + // 添加地图检索按钮 + searchMapBtn_ = new QPushButton("地图检索"); + searchMapBtn_->setProperty("primary", true); + connect(searchMapBtn_, &QPushButton::clicked, this, &MapPage::onSearchMapClicked); + layout->addWidget(searchMapBtn_); + + + downloadMapBtn_ = new QPushButton("地图下载"); + downloadMapBtn_->setProperty("primary", true); + connect(downloadMapBtn_, &QPushButton::clicked, this, &MapPage::onDownloadMapClicked); + layout->addWidget(downloadMapBtn_); + + // 添加新按钮 - 为了整洁,将它们分组在布局末尾 + setThreatBtn_ = new QPushButton("设置威胁区域"); + setThreatBtn_->setProperty("primary", true); + connect(setThreatBtn_, &QPushButton::clicked, this, &MapPage::onSetThreatClicked); + layout->addWidget(setThreatBtn_); + + pathPlanningBtn_ = new QPushButton("路径规划"); + pathPlanningBtn_->setProperty("primary", true); + connect(pathPlanningBtn_, &QPushButton::clicked, this, &MapPage::onPathPlanningClicked); + layout->addWidget(pathPlanningBtn_); + + areaCoverageBtn_ = new QPushButton("区域覆盖规划"); + areaCoverageBtn_->setProperty("primary", true); + connect(areaCoverageBtn_, &QPushButton::clicked, this, &MapPage::onAreaCoverageClicked); + layout->addWidget(areaCoverageBtn_); + + // Clear path button moved to PathPlanningDialog + + return bar; +} + +void MapPage::enableGeolocation() { + if (mapView_) { + QWebEngineSettings* settings = mapView_->settings(); + settings->setAttribute(QWebEngineSettings::JavascriptEnabled, true); + settings->setAttribute(QWebEngineSettings::LocalStorageEnabled, true); + + // Set geolocation permission for the map domain + connect(mapView_->page(), &QWebEnginePage::featurePermissionRequested, + [this](const QUrl &securityOrigin, QWebEnginePage::Feature feature) { + if (feature == QWebEnginePage::Geolocation) { + mapView_->page()->setFeaturePermission(securityOrigin, feature, QWebEnginePage::PermissionGrantedByUser); + qDebug() << "Geolocation permission granted for:" << securityOrigin.toString(); + } + }); + + qDebug() << "Geolocation enabled and permission handler set up"; + } +} + +void MapPage::onHeightChanged() { + emit heightChanged(heightCombo_->currentText()); + qDebug() << "航线高度变更为:" << heightCombo_->currentText(); +} + +void MapPage::onDownloadMapClicked() { + emit downloadMapRequested(); + qDebug() << "地图下载请求"; +} + +void MapPage::onSetThreatClicked() { + threatDialog_->exec(); // 打开模态对话框 + // 执行JS添加overlay (示例) + mapView_->page()->runJavaScript("addThreatArea();"); // 假设JS函数 +} + +void MapPage::onPathPlanningClicked() { + if (planningDialog_->exec() == QDialog::Accepted) { + QString pathData = planningDialog_->getPathData(); + if (pathData.isEmpty()) { + qDebug() << "No path data available"; + return; + } + + // Path is already visualized in planPath, but re-visualize if needed + visualizePath(pathData); + } +} + +void MapPage::onAreaCoverageClicked() { + if (coverageDialog_->exec() == QDialog::Accepted) { + QString pathData = coverageDialog_->getCoveragePathData(); + if (pathData.isEmpty()) { + qDebug() << "No coverage path data available"; + return; + } + visualizeCoveragePath(pathData); + } +} + + + +void MapPage::runMapJavaScript(const QString& js) { + if (mapView_) { + mapView_->page()->runJavaScript(js); + } +} + + + +void MapPage::clearPathOverlays() { + QString js = QString(R"( + if (window.map) { + console.log('Clearing all path overlays...'); + + // Remove path polyline + if (window.%1) { + window.map.remove(window.%1); + window.%1 = null; + console.log('Removed path polyline'); + } + + // Remove start marker + if (window.%2) { + window.map.remove(window.%2); + window.%2 = null; + console.log('Removed start marker'); + } + + // Remove end marker + if (window.%3) { + window.map.remove(window.%3); + window.%3 = null; + console.log('Removed end marker'); + } + + // Clear intermediate markers + if (!window.intermediates) { + window.intermediates = []; + } + for (var i = 0; i < window.intermediates.length; i++) { + if (window.intermediates[i]) { + window.map.remove(window.intermediates[i]); + console.log('Removed intermediate marker ' + i); + } + } + window.intermediates = []; + + console.log('All path overlays cleared successfully'); + } else { + console.log('Map not available for clearing'); + } + )").arg(pathOverlayId_, startMarkerId_, endMarkerId_); + runMapJavaScript(js); + qDebug() << "路径覆盖物清除完成"; +} + +void MapPage::visualizeCoveragePath(const QString& pathData) { + QString js = QString(R"( + if (window.map) { + var pathCoords = JSON.parse("%1"); + console.log('Visualizing coverage path with ' + pathCoords.length + ' points'); + + // Remove existing coverage overlay if any + if (window.%2) { + window.map.remove(window.%2); + window.%2 = null; + } + + // Create new polyline for coverage path (green, dashed) + var polyline = new AMap.Polyline({ + path: pathCoords, + strokeColor: "#4CAF50", + strokeOpacity: 0.8, + strokeWeight: 4, + strokeStyle: "dashed", + strokeDasharray: [8, 4], + zIndex: 2 + }); + polyline.setMap(window.map); + window.%2 = polyline; + + // Clear existing coverage intermediates + if (!window.coverageIntermediates) { + window.coverageIntermediates = []; + } + for (var i = 0; i < window.coverageIntermediates.length; i++) { + if (window.coverageIntermediates[i]) { + window.map.remove(window.coverageIntermediates[i]); + } + } + window.coverageIntermediates = []; + + // Add intermediate markers for coverage points + for (var i = 0; i < pathCoords.length; i += 5) { // Every 5th point for visibility + var marker = new AMap.Marker({ + position: pathCoords[i], + content: '
C' + (i/5 + 1) + '
', + zIndex: 15 + }); + marker.setMap(window.map); + window.coverageIntermediates.push(marker); + } + + // Fit view + var allOverlays = [polyline].concat(window.coverageIntermediates); + if (allOverlays.length > 0) { + window.map.setFitView(allOverlays, {padding: [50, 50, 50, 50]}); + } + + console.log('Coverage path visualization completed'); + } + )").arg(pathData, coverageOverlayId_); + runMapJavaScript(js); + currentCoveragePathData_ = pathData; + qDebug() << "区域覆盖路径可视化完成"; +} + +void MapPage::clearCoverageOverlays() { + QString js = QString(R"( + if (window.map) { + console.log('Clearing all coverage overlays...'); + + // Remove coverage polyline + if (window.%1) { + window.map.remove(window.%1); + window.%1 = null; + console.log('Removed coverage polyline'); + } + + // Remove area overlay if exists + if (window.%2) { + window.map.remove(window.%2); + window.%2 = null; + console.log('Removed area overlay'); + } + + // Clear coverage intermediates + if (!window.coverageIntermediates) { + window.coverageIntermediates = []; + } + for (var i = 0; i < window.coverageIntermediates.length; i++) { + if (window.coverageIntermediates[i]) { + window.map.remove(window.coverageIntermediates[i]); + } + } + window.coverageIntermediates = []; + + console.log('All coverage overlays cleared successfully'); + } else { + console.log('Map not available for clearing'); + } + )").arg(coverageOverlayId_, areaOverlayId_); + runMapJavaScript(js); + qDebug() << "区域覆盖覆盖物清除完成"; +} + + +double MapPage::parseLng(const QString& coord) const { + // Handle both "[lng, lat]" and "lng, lat" + QRegExp rx("^\\s*\\[?\\s*([\\d.-]+)\\s*,"); + if (rx.indexIn(coord) != -1) { + return rx.cap(1).toDouble(); + } + return 0.0; +} + +double MapPage::parseLat(const QString& coord) const { + // Handle both "[lng, lat]" and "lng, lat" + QRegExp rx(",\\s*([\\d.-]+)\\s*\\]?\\s*$"); + if (rx.indexIn(coord) != -1) { + return rx.cap(1).toDouble(); + } + return 0.0; +} + +void MapPage::showMarker(double lng, double lat, const QString& label, const QString& color, int index) { + QString markerId = (index == 0) ? startMarkerId_ : endMarkerId_; + QString js = QString(R"( + if (window.map) { + // Only remove if it's a different position + if (window.%1 && (window.%1.getPosition().lng != %2 || window.%1.getPosition().lat != %3)) { + window.map.remove(window.%1); + } + if (!window.%1 || (window.%1.getPosition().lng != %2 || window.%1.getPosition().lat != %3)) { + var marker = new AMap.Marker({ + position: new AMap.LngLat(%2, %3), + content: '
%5
', + zIndex: 100 + (%6 === 0 ? 10 : 5) // Start marker gets higher z-index + }); + marker.setMap(window.map); + window.%1 = marker; + } + } + )").arg(markerId, QString::number(lng), QString::number(lat), color, label, QString::number(index)); + runMapJavaScript(js); +} + +void MapPage::addClickListener() { + QString js = R"( + console.log('Adding click listener...'); + function addListener() { + if (window.map && window.bridge && window.mapReady) { + // Remove existing listener if any + if (window.clickListener) { + window.clickListener.remove(); + console.log('Removed existing listener'); + } + window.clickListener = window.map.on('click', function(e) { + console.log('Map clicked at: ' + e.lnglat.getLng() + ', ' + e.lnglat.getLat()); + window.bridge.onClick(e.lnglat.getLng(), e.lnglat.getLat()); + }); + console.log('Click listener added successfully'); + return true; + } + return false; + } + if (addListener()) { + // Already ready + } else { + console.log('Map or bridge not ready - polling...'); + var attempts = 0; + var maxAttempts = 100; // 10 seconds at 100ms intervals + var interval = setInterval(function() { + attempts++; + if (addListener()) { + clearInterval(interval); + } else if (attempts >= maxAttempts) { + clearInterval(interval); + console.error('Failed to add listener after ' + maxAttempts + ' attempts'); + } + }, 100); + } + )"; + runMapJavaScript(js); +} + +void MapPage::removeClickListener() { + QString js = R"( + if (window.clickListener) { + window.clickListener.remove(); + window.clickListener = null; + } + )"; + runMapJavaScript(js); +} + +void MapPage::visualizePath(const QString& pathData) { + QString js = QString(R"( + if (window.map) { + var pathCoords = JSON.parse("%1"); + console.log('Visualizing path with ' + pathCoords.length + ' points'); + + // Remove existing path overlay if any + if (window.%2) { + window.map.remove(window.%2); + window.%2 = null; + } + + // Create new polyline + var polyline = new AMap.Polyline({ + path: pathCoords, + strokeColor: "#3366FF", + strokeOpacity: 1, + strokeWeight: 5, + strokeStyle: "solid", + strokeDasharray: [10, 5], + zIndex: 1 + }); + polyline.setMap(window.map); + window.%2 = polyline; + + // Clear existing intermediate markers + if (!window.intermediates) { + window.intermediates = []; + } + for (var i = 0; i < window.intermediates.length; i++) { + if (window.intermediates[i]) { + window.map.remove(window.intermediates[i]); + } + } + window.intermediates = []; + + // Add intermediate markers (excluding start and end) + for (var i = 1; i < pathCoords.length - 1; i++) { + var marker = new AMap.Marker({ + position: pathCoords[i], + content: '
' + (i + 1) + '
', + zIndex: 10 + }); + marker.setMap(window.map); + window.intermediates.push(marker); + console.log('Added intermediate marker ' + (i + 1) + ' at: ' + pathCoords[i]); + } + + // Fit view to show all elements + var allOverlays = []; + if (window.startMarker) allOverlays.push(window.startMarker); + if (window.endMarker) allOverlays.push(window.endMarker); + allOverlays.push(polyline); + allOverlays = allOverlays.concat(window.intermediates); + + if (allOverlays.length > 0) { + window.map.setFitView(allOverlays, {padding: [50, 50, 50, 50]}); + } + + console.log('Path visualization completed with ' + window.intermediates.length + ' intermediate points'); + } + )").arg(pathData, pathOverlayId_); + runMapJavaScript(js); + qDebug() << "路径可视化完成"; +} + +void MapPage::onPageLoaded(bool ok) { + if (ok) { + qDebug() << "Page loaded successfully"; + + // Ensure bridge is properly registered with WebChannel + if (channel_ && bridge_) { + channel_->registerObject("bridge", bridge_); + qDebug() << "Bridge registered with WebChannel"; + + // Check readiness after a short delay + QTimer::singleShot(500, this, [this]() { + runMapJavaScript("console.log('Readiness check: mapReady=' + !!window.mapReady + ', bridge exists=' + !!window.bridge);"); + // 如果地图已就绪且bridge可用,添加点击监听器(JS侧会处理) + runMapJavaScript("if (window.mapReady && window.bridge) { addClickListener(); } else { console.log('Waiting for map and bridge to be ready...'); }"); + }); + } else { + qDebug() << "ERROR: Channel or bridge is null!"; + } + } else { + qDebug() << "Page load failed"; + } +} + +void MapPage::onSearchMapClicked() { + if (locateDialog_->exec() == QDialog::Accepted) { + double lng = locateDialog_->getLongitude(); + double lat = locateDialog_->getLatitude(); + + // 执行JS移动地图中心(使用window.map以匹配全局变量) + QString js = QString("window.map.setCenter([%1, %2]); window.map.setZoom(15);").arg(lng).arg(lat); + mapView_->page()->runJavaScript(js); + } +} + +// Implement ThreatAreaDialog methods +ThreatAreaDialog::ThreatAreaDialog(QWidget *parent, MapPage* mapPage) : QDialog(parent), mapPage_(mapPage), drawingPoints_() { + setWindowTitle("设置威胁区域"); + setMinimumSize(600, 500); + auto* layout = new QVBoxLayout(this); + layout->setSpacing(15); + layout->setContentsMargins(20, 20, 20, 20); + + // 威胁区域基本信息组 + auto* basicGroup = new QGroupBox("基本信息"); + basicGroup->setStyleSheet("QGroupBox { font-weight: bold; margin-top: 10px; }"); + auto* basicLayout = new QGridLayout(basicGroup); + basicLayout->setSpacing(10); + + // 威胁类型 + basicLayout->addWidget(new QLabel("威胁类型:"), 0, 0); + typeCombo_ = new QComboBox(); + typeCombo_->addItems({"导弹威胁", "雷达干扰", "防空火力", "禁飞区域", "其他"}); + typeCombo_->setStyleSheet("QComboBox { padding: 5px; border: 1px solid #ccc; border-radius: 4px; }"); + basicLayout->addWidget(typeCombo_, 0, 1); + + // 威胁等级 + basicLayout->addWidget(new QLabel("威胁等级:"), 0, 2); + levelCombo_ = new QComboBox(); + levelCombo_->addItems({"高", "中", "低"}); + levelCombo_->setStyleSheet("QComboBox { padding: 5px; border: 1px solid #ccc; border-radius: 4px; }"); + basicLayout->addWidget(levelCombo_, 0, 3); + + layout->addWidget(basicGroup); + + // 添加形状选择 + basicLayout->addWidget(new QLabel("形状:"), 1, 0); + shapeCombo_ = new QComboBox(); + shapeCombo_->addItems({"圆形", "矩形"}); + shapeCombo_->setStyleSheet("QComboBox { padding: 5px; border: 1px solid #ccc; border-radius: 4px; }"); + connect(shapeCombo_, QOverload::of(&QComboBox::currentIndexChanged), this, &ThreatAreaDialog::onShapeChanged); + basicLayout->addWidget(shapeCombo_, 1, 1); + + // 添加颜色选择(假设用于 overlay 颜色) + basicLayout->addWidget(new QLabel("颜色:"), 1, 2); + colorCombo_ = new QComboBox(); + colorCombo_->addItems({"红色", "黄色", "蓝色"}); + basicLayout->addWidget(colorCombo_, 1, 3); + + layout->addWidget(basicGroup); + + // 时间设置组 (保持不变) + auto* timeGroup = new QGroupBox("威胁区域存在时间"); + timeGroup->setStyleSheet("QGroupBox { font-weight: bold; margin-top: 10px; }"); + auto* timeLayout = new QVBoxLayout(timeGroup); + + // 开始时间 + auto* startTimeLayout = new QHBoxLayout(); + startTimeLayout->addWidget(new QLabel("开始时间:")); + startTimeEdit_ = new QDateTimeEdit(QDateTime::currentDateTime()); + startTimeEdit_->setDisplayFormat("yyyy-MM-dd hh:mm:ss"); + startTimeEdit_->setCalendarPopup(true); + startTimeEdit_->setStyleSheet("QDateTimeEdit { padding: 5px; border: 1px solid #ccc; border-radius: 4px; }"); + startTimeLayout->addWidget(startTimeEdit_); + startTimeLayout->addStretch(); + timeLayout->addLayout(startTimeLayout); + + // 结束时间 + auto* endTimeLayout = new QHBoxLayout(); + endTimeLayout->addWidget(new QLabel("结束时间:")); + endTimeEdit_ = new QDateTimeEdit(QDateTime::currentDateTime().addSecs(3600)); // 默认1小时后 + endTimeEdit_->setDisplayFormat("yyyy-MM-dd hh:mm:ss"); + endTimeEdit_->setCalendarPopup(true); + endTimeEdit_->setStyleSheet("QDateTimeEdit { padding: 5px; border: 1px solid #ccc; border-radius: 4px; }"); + endTimeLayout->addWidget(endTimeEdit_); + endTimeLayout->addStretch(); + timeLayout->addLayout(endTimeLayout); + + layout->addWidget(timeGroup); + + // 动态输入 widget + circleInputWidget_ = new QWidget(); + auto* circleLayout = new QFormLayout(circleInputWidget_); + centerLngInput_ = new QLineEdit(); + centerLngInput_->setPlaceholderText("中心经度"); + circleLayout->addRow("中心经度:", centerLngInput_); + centerLatInput_ = new QLineEdit(); + centerLatInput_->setPlaceholderText("中心纬度"); + circleLayout->addRow("中心纬度:", centerLatInput_); + radiusInput_ = new QLineEdit(); + radiusInput_->setPlaceholderText("半径 (米)"); + circleLayout->addRow("半径 (米):", radiusInput_); + layout->addWidget(circleInputWidget_); + + rectangleInputWidget_ = new QWidget(); + auto* rectLayout = new QVBoxLayout(rectangleInputWidget_); + rectPointsTable_ = new QTableWidget(4, 2); + rectPointsTable_->setHorizontalHeaderLabels({"经度", "纬度"}); + for (int i = 0; i < 4; ++i) { + rectPointsTable_->setItem(i, 0, new QTableWidgetItem("")); + rectPointsTable_->setItem(i, 1, new QTableWidgetItem("")); + } + rectLayout->addWidget(rectPointsTable_); + layout->addWidget(rectangleInputWidget_); + rectangleInputWidget_->setVisible(false); + + // 按钮 (保持 drawOnMapBtn_ 等) + auto* buttonLayout = new QHBoxLayout(); + buttonLayout->addStretch(); + + drawOnMapBtn_ = new QPushButton("在地图上绘制"); + drawOnMapBtn_->setStyleSheet("QPushButton { padding: 8px 20px; background: #4CAF50; color: white; border-radius: 4px; }"); + connect(drawOnMapBtn_, &QPushButton::clicked, this, &ThreatAreaDialog::startDrawingThreatArea); + buttonLayout->addWidget(drawOnMapBtn_); + + auto* addBtn = new QPushButton("添加区域"); + addBtn->setProperty("primary", true); + addBtn->setStyleSheet("QPushButton { padding: 8px 20px; background: #2196f3; color: white; border-radius: 4px; }"); + buttonLayout->addWidget(addBtn); + + auto* cancelBtn = new QPushButton("取消"); + cancelBtn->setStyleSheet("QPushButton { padding: 8px 20px; background: #f5f5f5; border: 1px solid #ddd; border-radius: 4px; }"); + buttonLayout->addWidget(cancelBtn); + + layout->addLayout(buttonLayout); + + // 连接信号槽 + connect(addBtn, &QPushButton::clicked, this, &ThreatAreaDialog::addArea); + connect(cancelBtn, &QPushButton::clicked, this, &QDialog::reject); + + // 初始化 areaTable_ + auto* tableGroup = new QGroupBox("已添加威胁区域"); + auto* tableLayout = new QVBoxLayout(tableGroup); + areaTable_ = new QTableWidget(); + areaTable_->setColumnCount(6); + areaTable_->setHorizontalHeaderLabels({"类型", "等级", "开始时间", "结束时间", "形状", "细节"}); + areaTable_->setSelectionBehavior(QAbstractItemView::SelectRows); // 整行选择 + connect(areaTable_, &QTableWidget::itemSelectionChanged, this, [this]() { + auto selected = areaTable_->selectedItems(); + if (!selected.isEmpty()) { + selectedRow_ = selected.first()->row(); + } else { + selectedRow_ = -1; + } + }); + tableLayout->addWidget(areaTable_); + + // 添加编辑/删除按钮 + auto* buttonLayoutTable = new QHBoxLayout(); + editBtn_ = new QPushButton("编辑选中区域"); + connect(editBtn_, &QPushButton::clicked, this, &ThreatAreaDialog::editArea); + buttonLayoutTable->addWidget(editBtn_); + + deleteBtn_ = new QPushButton("删除选中区域"); + connect(deleteBtn_, &QPushButton::clicked, this, &ThreatAreaDialog::deleteArea); + buttonLayoutTable->addWidget(deleteBtn_); + + tableLayout->addLayout(buttonLayoutTable); + layout->addWidget(tableGroup); + + // 填充现有区域 + const auto& areas = mapPage_->getThreatAreas(); + for (const auto& area : areas) { + int row = areaTable_->rowCount(); + areaTable_->insertRow(row); + areaTable_->setItem(row, 0, new QTableWidgetItem(area["type"].toString())); + areaTable_->setItem(row, 1, new QTableWidgetItem(area["level"].toString())); + areaTable_->setItem(row, 2, new QTableWidgetItem(area["startTime"].toString())); + areaTable_->setItem(row, 3, new QTableWidgetItem(area["endTime"].toString())); + areaTable_->setItem(row, 4, new QTableWidgetItem(area["shape"].toString())); + QString details; + if (area["shape"].toString() == "circle") { + details = QString("中心: %1,%2 半径: %3m").arg(area["centerLng"].toDouble()).arg(area["centerLat"].toDouble()).arg(area["radius"].toDouble()); + } else { + details = "矩形点..."; // 简化 + } + areaTable_->setItem(row, 5, new QTableWidgetItem(details)); + } +} + +void ThreatAreaDialog::onShapeChanged(int index) { + currentShape_ = shapeCombo_->currentText(); + circleInputWidget_->setVisible(index == 0); + rectangleInputWidget_->setVisible(index == 1); +} + +void ThreatAreaDialog::startDrawingThreatArea() { + if (!mapPage_) return; + currentShape_ = shapeCombo_->currentText(); + QMessageBox::information(this, "提示", QString("现在在地图上绘制%1。点击添加点。").arg(currentShape_)); + hide(); // 隐藏对话框以允许地图交互 + mapPage_->enableDrawingMode(currentShape_ == "圆形" ? "circle" : "rectangle"); + connect(mapPage_, &MapPage::mapClicked, this, &ThreatAreaDialog::handleDrawingClick); // 临时连接 +} + +void ThreatAreaDialog::handleDrawingClick(double lng, double lat) { + drawingPoints_.append(qMakePair(lng, lat)); + if (currentShape_ == "圆形" && drawingPoints_.size() == 2) { + // 计算中心和半径 + double centerLng = drawingPoints_[0].first; + double centerLat = drawingPoints_[0].second; + double dx = drawingPoints_[1].first - centerLng; + double dy = drawingPoints_[1].second - centerLat; + double radius = sqrt(dx*dx + dy*dy) * 111000; // 粗略转换为米 (1度 ~ 111km) + centerLngInput_->setText(QString::number(centerLng)); + centerLatInput_->setText(QString::number(centerLat)); + radiusInput_->setText(QString::number(radius)); + finishDrawing(); + } else if (currentShape_ == "矩形" && drawingPoints_.size() == 2) { + // 计算矩形四个点 (假设两个对角点) + double minLng = qMin(drawingPoints_[0].first, drawingPoints_[1].first); + double maxLng = qMax(drawingPoints_[0].first, drawingPoints_[1].first); + double minLat = qMin(drawingPoints_[0].second, drawingPoints_[1].second); + double maxLat = qMax(drawingPoints_[0].second, drawingPoints_[1].second); + rectPointsTable_->setItem(0, 0, new QTableWidgetItem(QString::number(minLng))); + rectPointsTable_->setItem(0, 1, new QTableWidgetItem(QString::number(minLat))); + rectPointsTable_->setItem(1, 0, new QTableWidgetItem(QString::number(maxLng))); + rectPointsTable_->setItem(1, 1, new QTableWidgetItem(QString::number(minLat))); + rectPointsTable_->setItem(2, 0, new QTableWidgetItem(QString::number(maxLng))); + rectPointsTable_->setItem(2, 1, new QTableWidgetItem(QString::number(maxLat))); + rectPointsTable_->setItem(3, 0, new QTableWidgetItem(QString::number(minLng))); + rectPointsTable_->setItem(3, 1, new QTableWidgetItem(QString::number(maxLat))); + finishDrawing(); + } +} + +void ThreatAreaDialog::finishDrawing() { + mapPage_->disableDrawingMode(); + disconnect(mapPage_, &MapPage::mapClicked, this, &ThreatAreaDialog::handleDrawingClick); + drawingPoints_.clear(); + show(); + addArea(); // 自动添加绘制结果到表格和地图 + QMessageBox::information(this, "完成", "绘制完成,已自动添加区域。"); +} + +void ThreatAreaDialog::addArea() { + // 验证输入并添加 overlay + QVariantMap params; + params["type"] = typeCombo_->currentText(); + params["level"] = levelCombo_->currentText(); + params["startTime"] = startTimeEdit_->dateTime().toString(); + params["endTime"] = endTimeEdit_->dateTime().toString(); + + // 颜色映射 + QString colorStr = colorCombo_->currentText(); + QString hexColor; + if (colorStr == "红色") hexColor = "#FF0000"; + else if (colorStr == "黄色") hexColor = "#FFFF00"; + else if (colorStr == "蓝色") hexColor = "#0000FF"; + else hexColor = "#FF0000"; // 默认红色 + params["color"] = hexColor; + + params["shape"] = currentShape_; + + bool valid = true; + if (currentShape_ == "圆形") { + bool ok; + params["centerLng"] = centerLngInput_->text().toDouble(&ok); + valid &= ok; + params["centerLat"] = centerLatInput_->text().toDouble(&ok); + valid &= ok; + double radius = radiusInput_->text().toDouble(&ok); + valid &= ok && radius > 0; + params["radius"] = radius; + if (!valid) { + QMessageBox::warning(this, "错误", "无效的圆形参数(经纬度/半径必须是正数)"); + return; + } + mapPage_->addThreatOverlay("circle", params); + } else { + QList points; + for (int i = 0; i < 4; ++i) { + QVariantMap point; + point["lng"] = rectPointsTable_->item(i, 0)->text().toDouble(); + point["lat"] = rectPointsTable_->item(i, 1)->text().toDouble(); + points.append(point); + } + params["points"] = points; + mapPage_->addThreatOverlay("rectangle", params); + } + qDebug() << "添加威胁区域"; + QMessageBox::information(this, "提示", "威胁区域已添加"); + // 插入到表格 + int row = areaTable_->rowCount(); + areaTable_->insertRow(row); + areaTable_->setItem(row, 0, new QTableWidgetItem(params["type"].toString())); + areaTable_->setItem(row, 1, new QTableWidgetItem(params["level"].toString())); + areaTable_->setItem(row, 2, new QTableWidgetItem(params["startTime"].toString())); + areaTable_->setItem(row, 3, new QTableWidgetItem(params["endTime"].toString())); + areaTable_->setItem(row, 4, new QTableWidgetItem(params["shape"].toString())); + QString details; + if (params["shape"].toString() == "圆形") { + details = QString("中心: %1,%2 半径: %3m").arg(params["centerLng"].toDouble()).arg(params["centerLat"].toDouble()).arg(params["radius"].toDouble()); + } else { + details = "矩形点: ..."; // 可以扩展 + } + areaTable_->setItem(row, 5, new QTableWidgetItem(details)); + accept(); +} + +// Implement missing methods +void ThreatAreaDialog::updateThreatStats() { + qDebug() << "更新威胁统计"; +} + +void ThreatAreaDialog::editArea() { + if (selectedRow_ < 0 || selectedRow_ >= mapPage_->getThreatAreas().size()) { + QMessageBox::warning(this, "错误", "请选择一个区域编辑"); + return; + } + auto& area = mapPage_->getThreatAreas()[selectedRow_]; + typeCombo_->setCurrentText(area["type"].toString()); + levelCombo_->setCurrentText(area["level"].toString()); + startTimeEdit_->setDateTime(QDateTime::fromString(area["startTime"].toString())); + endTimeEdit_->setDateTime(QDateTime::fromString(area["endTime"].toString())); + colorCombo_->setCurrentText(area["color"].toString()); + shapeCombo_->setCurrentText(area["shape"].toString()); + + if (area["shape"].toString() == "circle") { + centerLngInput_->setText(QString::number(area["centerLng"].toDouble())); + centerLatInput_->setText(QString::number(area["centerLat"].toDouble())); + radiusInput_->setText(QString::number(area["radius"].toDouble())); + } else { + // 填充矩形表格 + QList points = area["points"].toList(); + for (int i = 0; i < 4 && i < points.size(); ++i) { + QVariantMap p = points[i].toMap(); + rectPointsTable_->setItem(i, 0, new QTableWidgetItem(QString::number(p["lng"].toDouble()))); + rectPointsTable_->setItem(i, 1, new QTableWidgetItem(QString::number(p["lat"].toDouble()))); + } + } + // 更新后,用户可以修改并点击"添加区域"来覆盖(或实现更新逻辑) + QMessageBox::information(this, "提示", "已加载选中区域数据,请修改后点击添加更新。"); +} + +void ThreatAreaDialog::deleteArea() { + if (selectedRow_ < 0 || selectedRow_ >= mapPage_->getThreatAreas().size()) { + QMessageBox::warning(this, "错误", "请选择一个区域删除"); + return; + } + mapPage_->removeThreatOverlay(selectedRow_); + areaTable_->removeRow(selectedRow_); + selectedRow_ = -1; + QMessageBox::information(this, "成功", "已删除选中区域"); +} + +// In MapPage class +void MapPage::removeThreatOverlay(int index) { + if (index < 0 || index >= threatAreas_.size()) return; + QVariantMap area = threatAreas_.at(index); + QString overlayId = area["id"].toString(); + runMapJavaScript(QString("if (window.%1) { window.map.remove(window.%1); window.%1 = null; }").arg(overlayId)); + threatAreas_.removeAt(index); + // 无需 clearMap 和重绘 +} + +PathPlanningDialog::PathPlanningDialog(QWidget *parent, MapPage* mapPage) : QDialog(parent), mapPage_(mapPage), pathData_("") { + setWindowTitle("路径规划"); + setMinimumSize(600, 500); + auto* layout = new QVBoxLayout(this); + layout->setContentsMargins(20, 20, 20, 20); + + auto* formLayout = new QFormLayout(); + + startInput_ = new QLineEdit(); + startInput_->setPlaceholderText("格式: 经度,纬度 或 [经度, 纬度]"); + formLayout->addRow("起点坐标:", startInput_); + + endInput_ = new QLineEdit(); + endInput_->setPlaceholderText("格式: 经度,纬度 或 [经度, 纬度]"); + formLayout->addRow("终点坐标:", endInput_); + + layout->addLayout(formLayout); + + // Selection buttons + auto* selectLayout = new QHBoxLayout(); + selectStartBtn_ = new QPushButton("选择起点"); + connect(selectStartBtn_, &QPushButton::clicked, [this](){ + QMessageBox::information(this, "提示", "现在可以点击地图选择起点。"); + selectingStart_ = true; + selectingEnd_ = false; + mapPage_->addClickListener(); + }); + selectLayout->addWidget(selectStartBtn_); + + selectEndBtn_ = new QPushButton("选择终点"); + connect(selectEndBtn_, &QPushButton::clicked, [this](){ + QMessageBox::information(this, "提示", "现在可以点击地图选择终点。"); + selectingStart_ = false; + selectingEnd_ = true; + mapPage_->addClickListener(); + }); + selectLayout->addWidget(selectEndBtn_); + layout->addLayout(selectLayout); + + // Apply buttons + auto* applyLayout = new QHBoxLayout(); + applyStartBtn_ = new QPushButton("应用起点"); + applyEndBtn_ = new QPushButton("应用终点"); + connect(applyStartBtn_, &QPushButton::clicked, this, &PathPlanningDialog::applyStartPoint); + connect(applyEndBtn_, &QPushButton::clicked, this, &PathPlanningDialog::applyEndPoint); + applyLayout->addWidget(applyStartBtn_); + applyLayout->addWidget(applyEndBtn_); + layout->addLayout(applyLayout); + + // Connect to map click signal + connect(mapPage_, &MapPage::mapClicked, this, &PathPlanningDialog::onMapClick); + + pathTable_ = new QTableWidget(); + pathTable_->setColumnCount(2); + pathTable_->setHorizontalHeaderLabels({"经度", "纬度"}); + layout->addWidget(pathTable_); + + auto* pathButtonsLayout = new QHBoxLayout(); + planBtn_ = new QPushButton("规划路径"); + connect(planBtn_, &QPushButton::clicked, this, &PathPlanningDialog::planPath); + pathButtonsLayout->addWidget(planBtn_); + + clearBtn_ = new QPushButton("清除路径规划"); + connect(clearBtn_, &QPushButton::clicked, this, &PathPlanningDialog::clearPath); + pathButtonsLayout->addWidget(clearBtn_); + layout->addLayout(pathButtonsLayout); + + auto* buttonLayout = new QHBoxLayout(); + buttonLayout->addStretch(); + + auto* confirmBtn = new QPushButton("确认"); + connect(confirmBtn, &QPushButton::clicked, this, &QDialog::accept); + buttonLayout->addWidget(confirmBtn); + + auto* cancelBtn = new QPushButton("取消"); + connect(cancelBtn, &QPushButton::clicked, this, &QDialog::reject); + buttonLayout->addWidget(cancelBtn); + + layout->addLayout(buttonLayout); +} + +void PathPlanningDialog::applyStartPoint() { + if (mapPage_) { + QString coord = startInput_->text(); + if (!coord.isEmpty()) { + double lng = mapPage_->parseLng(coord); + double lat = mapPage_->parseLat(coord); + if (lng != 0.0 && lat != 0.0) { + mapPage_->showMarker(lng, lat, "1", "#4CAF50", 0); + QMessageBox::information(this, "成功", "起点已应用到地图"); + } else { + QMessageBox::warning(this, "错误", "起点坐标格式无效"); + } + } else { + QMessageBox::warning(this, "错误", "未选择起点"); + } + } +} + +void PathPlanningDialog::applyEndPoint() { + if (mapPage_) { + QString coord = endInput_->text(); + if (!coord.isEmpty()) { + double lng = mapPage_->parseLng(coord); + double lat = mapPage_->parseLat(coord); + if (lng != 0.0 && lat != 0.0) { + mapPage_->showMarker(lng, lat, "6", "#FF9800", 1); + QMessageBox::information(this, "成功", "终点已应用到地图"); + } else { + QMessageBox::warning(this, "错误", "终点坐标格式无效"); + } + } else { + QMessageBox::warning(this, "错误", "未选择终点"); + } + } +} + +void PathPlanningDialog::planPath() { + QString start = startInput_->text(); + QString end = endInput_->text(); + if (start.isEmpty()) { + QMessageBox::warning(this, "错误", "未选择起点"); + return; + } + if (end.isEmpty()) { + QMessageBox::warning(this, "错误", "未选择终点"); + return; + } + + double startLng = mapPage_->parseLng(start); + double startLat = mapPage_->parseLat(start); + double endLng = mapPage_->parseLng(end); + double endLat = mapPage_->parseLat(end); + + if (startLng == 0.0 || startLat == 0.0 || endLng == 0.0 || endLat == 0.0) { + QMessageBox::warning(this, "错误", "坐标格式无效"); + return; + } + + // Show start and end markers before planning + mapPage_->showMarker(startLng, startLat, "1", "#4CAF50", 0); + mapPage_->showMarker(endLng, endLat, "6", "#FF9800", 1); + + // Generate intermediate points using linear interpolation (10 points total: start + 8 intermediates + end) + QList> pathPoints; + pathPoints.append(qMakePair(startLng, startLat)); + + double dx = endLng - startLng; + double dy = endLat - startLat; + for (int i = 1; i < 9; ++i) { + double t = static_cast(i) / 9.0; + double pointLng = startLng + t * dx; + double pointLat = startLat + t * dy; + pathPoints.append(qMakePair(pointLng, pointLat)); + } + + pathPoints.append(qMakePair(endLng, endLat)); + + // Clear and update table, reset headers to ensure they persist + pathTable_->clear(); + pathTable_->setHorizontalHeaderLabels({"经度", "纬度"}); + pathTable_->setRowCount(pathPoints.size()); + for (int i = 0; i < pathPoints.size(); ++i) { + pathTable_->setItem(i, 0, new QTableWidgetItem(QString::number(pathPoints[i].first, 'f', 6))); + pathTable_->setItem(i, 1, new QTableWidgetItem(QString::number(pathPoints[i].second, 'f', 6))); + } + + // Generate JSON path data + QString pathData = "["; + for (int i = 0; i < pathPoints.size(); ++i) { + if (i > 0) pathData += ","; + pathData += QString("[%1, %2]").arg(pathPoints[i].first, 0, 'f', 6).arg(pathPoints[i].second, 0, 'f', 6); + } + pathData += "]"; + + // Store for getPathData + pathData_ = pathData; + + // Visualize the path immediately + if (mapPage_) { + mapPage_->visualizePath(pathData_); + } + + QMessageBox::information(this, "成功", "路径规划完成,包含8个中间点实现平滑路径"); +} + +QString PathPlanningDialog::getPathData() const { + return pathData_; +} + +// Add clearPath implementation +void PathPlanningDialog::clearPath() { + if (mapPage_) { + mapPage_->clearPathOverlays(); + } + startInput_->clear(); + endInput_->clear(); + pathTable_->setRowCount(0); + pathData_ = ""; + QMessageBox::information(this, "成功", "路径规划已清除"); +} + +void PathPlanningDialog::onMapClick(double lng, double lat) { + QString coord = QString("[%1, %2]").arg(lng, 0, 'f', 6).arg(lat, 0, 'f', 6); + if (selectingStart_) { + startInput_->setText(coord); + mapPage_->showMarker(lng, lat, "1", "#4CAF50", 0); + selectingStart_ = false; + mapPage_->removeClickListener(); + QMessageBox::information(this, "成功", "起点已选择"); + } else if (selectingEnd_) { + endInput_->setText(coord); + mapPage_->showMarker(lng, lat, "6", "#FF9800", 1); + selectingEnd_ = false; + mapPage_->removeClickListener(); + QMessageBox::information(this, "成功", "终点已选择"); + } +} + +AreaCoverageDialog::AreaCoverageDialog(QWidget* parent, MapPage* mapPage) : QDialog(parent), mapPage_(mapPage), coveragePathData_("") { + setWindowTitle("区域覆盖路径规划"); + setMinimumSize(700, 600); + auto* mainLayout = new QVBoxLayout(this); + mainLayout->setContentsMargins(20, 20, 20, 20); + mainLayout->setSpacing(15); + + // Shape selection + auto* shapeLayout = new QHBoxLayout(); + shapeLayout->addWidget(new QLabel("区域形状:")); + shapeCombo_ = new QComboBox(); + shapeCombo_->addItems({"圆形", "多边形"}); + connect(shapeCombo_, QOverload::of(&QComboBox::currentIndexChanged), this, &AreaCoverageDialog::onShapeChanged); + shapeLayout->addWidget(shapeCombo_); + shapeLayout->addStretch(); + mainLayout->addLayout(shapeLayout); + + // Dynamic inputs based on shape + QWidget* inputWidget = new QWidget(); + auto* inputLayout = new QVBoxLayout(inputWidget); + mainLayout->addWidget(inputWidget); + + // Circle inputs (default) + circleWidget_ = setupCircleInputs(); + inputLayout->addWidget(circleWidget_); + + // Polygon inputs (hidden initially) + polygonWidget_ = setupPolygonInputs(); + inputLayout->addWidget(polygonWidget_); + + // Search mode + auto* modeGroupBox = new QGroupBox("搜索模式"); + auto* modeLayout = new QHBoxLayout(modeGroupBox); + efficiencyRadio_ = new QRadioButton("高效率"); + fullRangeRadio_ = new QRadioButton("全范围"); + efficiencyRadio_->setChecked(true); + modeGroup_ = new QButtonGroup(this); + modeGroup_->addButton(efficiencyRadio_); + modeGroup_->addButton(fullRangeRadio_); + modeLayout->addWidget(efficiencyRadio_); + modeLayout->addWidget(fullRangeRadio_); + modeLayout->addStretch(); + mainLayout->addWidget(modeGroupBox); + + // Drone count + auto* droneLayout = new QHBoxLayout(); + droneLayout->addWidget(new QLabel("无人机数量:")); + droneCountSpin_ = new QSpinBox(); + droneCountSpin_->setRange(1, 10); + droneCountSpin_->setValue(1); + droneLayout->addWidget(droneCountSpin_); + droneLayout->addStretch(); + mainLayout->addLayout(droneLayout); + + // Path table + pathTable_ = new QTableWidget(); + pathTable_->setColumnCount(2); + pathTable_->setHorizontalHeaderLabels({"经度", "纬度"}); + pathTable_->setMinimumHeight(150); + mainLayout->addWidget(pathTable_); + + // Plan buttons + auto* planButtonsLayout = new QHBoxLayout(); + planBtn_ = new QPushButton("规划路径"); + connect(planBtn_, &QPushButton::clicked, this, &AreaCoverageDialog::planCoveragePath); + planButtonsLayout->addWidget(planBtn_); + + clearBtn_ = new QPushButton("清除规划"); + connect(clearBtn_, &QPushButton::clicked, this, &AreaCoverageDialog::clearCoverage); + planButtonsLayout->addWidget(clearBtn_); + planButtonsLayout->addStretch(); + mainLayout->addLayout(planButtonsLayout); + + // Confirm/Cancel + auto* buttonLayout = new QHBoxLayout(); + buttonLayout->addStretch(); + auto* confirmBtn = new QPushButton("确认"); + connect(confirmBtn, &QPushButton::clicked, this, &QDialog::accept); + buttonLayout->addWidget(confirmBtn); + auto* cancelBtn = new QPushButton("取消"); + connect(cancelBtn, &QPushButton::clicked, this, &QDialog::reject); + buttonLayout->addWidget(cancelBtn); + mainLayout->addLayout(buttonLayout); + + // Connect map clicks + connect(mapPage_, &MapPage::mapClicked, this, &AreaCoverageDialog::onMapClick); + + // Connect table selection for polygon + connect(verticesTable_, &QTableWidget::currentCellChanged, this, [this](int currentRow, int currentColumn, int previousRow, int previousColumn) { + Q_UNUSED(currentColumn); + Q_UNUSED(previousRow); + Q_UNUSED(previousColumn); + currentVertexRow_ = currentRow; + }); + + onShapeChanged(0); // Initialize with circle +} + +QWidget* AreaCoverageDialog::setupCircleInputs() { + auto* circleWidget = new QWidget(); + auto* circleLayout = new QFormLayout(circleWidget); + centerLngInput_ = new QLineEdit(); + centerLngInput_->setPlaceholderText("中心经度"); + circleLayout->addRow("中心经度:", centerLngInput_); + centerLatInput_ = new QLineEdit(); + centerLatInput_->setPlaceholderText("中心纬度"); + circleLayout->addRow("中心纬度:", centerLatInput_); + radiusInput_ = new QLineEdit(); + radiusInput_->setPlaceholderText("半径 (km)"); + radiusInput_->setText("1.0"); + circleLayout->addRow("半径 (km):", radiusInput_); + return circleWidget; +} + +QWidget* AreaCoverageDialog::setupPolygonInputs() { + auto* polyWidget = new QWidget(); + auto* polyLayout = new QVBoxLayout(polyWidget); + + verticesTable_ = new QTableWidget(); + verticesTable_->setColumnCount(2); + verticesTable_->setHorizontalHeaderLabels({"经度", "纬度"}); + polyLayout->addWidget(verticesTable_); + + auto* polyButtonsLayout = new QHBoxLayout(); + addVertexBtn_ = new QPushButton("添加顶点"); + connect(addVertexBtn_, &QPushButton::clicked, this, &AreaCoverageDialog::addVertex); + polyButtonsLayout->addWidget(addVertexBtn_); + removeVertexBtn_ = new QPushButton("移除顶点"); + connect(removeVertexBtn_, &QPushButton::clicked, this, &AreaCoverageDialog::removeVertex); + polyButtonsLayout->addWidget(removeVertexBtn_); + selectVertexBtn_ = new QPushButton("地图选择顶点"); + connect(selectVertexBtn_, &QPushButton::clicked, this, &AreaCoverageDialog::selectVertexOnMap); + polyButtonsLayout->addWidget(selectVertexBtn_); + polyButtonsLayout->addStretch(); + polyLayout->addLayout(polyButtonsLayout); + + return polyWidget; +} + +void AreaCoverageDialog::onShapeChanged(int index) { + if (index == 0) { // Circle + circleWidget_->setVisible(true); + polygonWidget_->setVisible(false); + } else { // Polygon + circleWidget_->setVisible(false); + polygonWidget_->setVisible(true); + } +} + +void AreaCoverageDialog::addVertex() { + int row = verticesTable_->rowCount(); + verticesTable_->insertRow(row); + verticesTable_->setItem(row, 0, new QTableWidgetItem("0.000000")); + verticesTable_->setItem(row, 1, new QTableWidgetItem("0.000000")); + vertices_.append(qMakePair(0.0, 0.0)); +} + +void AreaCoverageDialog::removeVertex() { + int row = verticesTable_->currentRow(); + if (row >= 0) { + vertices_.removeAt(row); + verticesTable_->removeRow(row); + } +} + +void AreaCoverageDialog::selectVertexOnMap() { + if (currentVertexRow_ < 0) { + addVertex(); + currentVertexRow_ = verticesTable_->rowCount() - 1; + } + QMessageBox::information(this, "提示", "点击地图选择顶点位置"); + selectingVertex_ = true; + mapPage_->addClickListener(); +} + +void AreaCoverageDialog::onMapClick(double lng, double lat) { + if (selectingVertex_) { + if (currentVertexRow_ >= 0 && currentVertexRow_ < verticesTable_->rowCount()) { + verticesTable_->setItem(currentVertexRow_, 0, new QTableWidgetItem(QString::number(lng, 'f', 6))); + verticesTable_->setItem(currentVertexRow_, 1, new QTableWidgetItem(QString::number(lat, 'f', 6))); + vertices_[currentVertexRow_] = qMakePair(lng, lat); + mapPage_->showMarker(lng, lat, QString::number(currentVertexRow_ + 1), "#2196F3", currentVertexRow_); + selectingVertex_ = false; + mapPage_->removeClickListener(); + QMessageBox::information(this, "成功", "顶点已更新"); + } + } +} + +void AreaCoverageDialog::planCoveragePath() { + // Update vertices from table for polygon + if (shapeCombo_->currentIndex() == 1) { + vertices_.clear(); + for (int i = 0; i < verticesTable_->rowCount(); ++i) { + double lng = verticesTable_->item(i, 0) ? verticesTable_->item(i, 0)->text().toDouble() : 0.0; + double lat = verticesTable_->item(i, 1) ? verticesTable_->item(i, 1)->text().toDouble() : 0.0; + vertices_.append(qMakePair(lng, lat)); + } + } + + // Validate inputs based on shape + if (shapeCombo_->currentIndex() == 0) { // Circle + bool ok1 = centerLngInput_->text().toDouble() != 0.0; + bool ok2 = centerLatInput_->text().toDouble() != 0.0; + bool ok3; + double radiusKm = radiusInput_->text().toDouble(&ok3); + if (!ok1 || !ok2 || !ok3 || radiusKm <= 0) { + QMessageBox::warning(this, "错误", "无效的圆形参数"); + return; + } + // Generate spiral path + generateMockCoveragePath(); // Will use circle params + } else { // Polygon + if (vertices_.size() < 3) { + QMessageBox::warning(this, "错误", "多边形至少需要3个顶点"); + return; + } + // Generate zigzag path + generateMockCoveragePath(); // Will use vertices + } + + // Visualize area first (mock polygon or circle) + // For simplicity, skip detailed area overlay, focus on path + + // Show path in table and store data + pathTable_->setRowCount(0); + // Assume generateMockCoveragePath populates a list of points + // For now, mock some points + QList> mockPath; + double radiusKm = radiusInput_->text().toDouble(); // Define radius + if (shapeCombo_->currentIndex() == 0) { + // Spiral around center + double centerLng = centerLngInput_->text().toDouble(); + double centerLat = centerLatInput_->text().toDouble(); + double r = 0.0; + double step = radiusKm / 20.0; // 20 steps + for (int i = 0; i < 100; ++i) { // 100 points + double angle = i * 0.2; // radians + r += step / 10.0; // Increase radius slowly + double dx = r * cos(angle); + double dy = r * sin(angle); + // Approximate km to degrees: ~1/111 deg per km + double pointLng = centerLng + (dx / 111.0); + double pointLat = centerLat + (dy / 111.0); + mockPath.append(qMakePair(pointLng, pointLat)); + if (r >= radiusKm) break; + } + } else { + // Zigzag along polygon bounding box + double minLng = 180, maxLng = -180, minLat = 90, maxLat = -90; + for (auto& v : vertices_) { + minLng = qMin(minLng, v.first); + maxLng = qMax(maxLng, v.first); + minLat = qMin(minLat, v.second); + maxLat = qMax(maxLat, v.second); + } + double width = maxLng - minLng; + double height = maxLat - minLat; + int numLines = 10; + for (int line = 0; line < numLines; ++line) { + double y = minLat + (height / numLines) * line; + for (double x = minLng; x <= maxLng; x += width / 20.0) { + mockPath.append(qMakePair(x, y)); + } + // Zigzag back + if (line < numLines - 1) { + y = minLat + (height / numLines) * (line + 1); + for (double x = maxLng; x >= minLng; x -= width / 20.0) { + mockPath.append(qMakePair(x, y)); + } + } + } + } + + // Adjust for drone count: divide path into segments + int drones = droneCountSpin_->value(); + if (drones > 1) { + // For mock, just use full path; in real, assign segments + } + + // Populate table (sample first 20 points) + int displayCount = qMin(20, (int)mockPath.size()); + pathTable_->setRowCount(displayCount); + for (int i = 0; i < displayCount; ++i) { + pathTable_->setItem(i, 0, new QTableWidgetItem(QString::number(mockPath[i].first, 'f', 6))); + pathTable_->setItem(i, 1, new QTableWidgetItem(QString::number(mockPath[i].second, 'f', 6))); + } + + // Generate JSON + QString json = "["; + for (int i = 0; i < (int)mockPath.size(); ++i) { + if (i > 0) json += ","; + json += QString("[%1,%2]").arg(mockPath[i].first, 0, 'f', 6).arg(mockPath[i].second, 0, 'f', 6); + } + json += "]"; + coveragePathData_ = json; + + // Visualize immediately + if (mapPage_) { + mapPage_->visualizeCoveragePath(coveragePathData_); + } + + bool isEfficiency = efficiencyRadio_->isChecked(); + QString mode = isEfficiency ? "高效率" : "全范围"; + QMessageBox::information(this, "成功", QString("覆盖路径规划完成 (%1模式, %2架无人机)").arg(mode).arg(drones)); +} + +void AreaCoverageDialog::generateMockCoveragePath() { + // Placeholder: actual generation in planCoveragePath + qDebug() << "生成模拟覆盖路径"; +} + +void AreaCoverageDialog::clearCoverage() { + if (mapPage_) { + mapPage_->clearCoverageOverlays(); + } + pathTable_->setRowCount(0); + coveragePathData_ = ""; + vertices_.clear(); + verticesTable_->setRowCount(0); + centerLngInput_->clear(); + centerLatInput_->clear(); + radiusInput_->clear(); + QMessageBox::information(this, "成功", "覆盖规划已清除"); +} + + +// Implement LocateDialog methods +LocateDialog::LocateDialog(QWidget *parent) : QDialog(parent), lng_(0.0), lat_(0.0) { + setWindowTitle("地图定位"); + setMinimumSize(400, 200); + auto* layout = new QVBoxLayout(this); + layout->setContentsMargins(20, 20, 20, 20); + + auto* formLayout = new QFormLayout(); + + lngInput_ = new QLineEdit(); + lngInput_->setPlaceholderText("请输入经度"); + formLayout->addRow("经度:", lngInput_); + + latInput_ = new QLineEdit(); + latInput_->setPlaceholderText("请输入纬度"); + formLayout->addRow("纬度:", latInput_); + + layout->addLayout(formLayout); + + auto* buttonLayout = new QHBoxLayout(); + buttonLayout->addStretch(); + + auto* confirmBtn = new QPushButton("确认"); + buttonLayout->addWidget(confirmBtn); + + auto* cancelBtn = new QPushButton("取消"); + buttonLayout->addWidget(cancelBtn); + + layout->addLayout(buttonLayout); + + connect(confirmBtn, &QPushButton::clicked, this, &LocateDialog::onConfirm); + connect(cancelBtn, &QPushButton::clicked, this, &QDialog::reject); +} + + +void LocateDialog::onConfirm() { + bool ok1, ok2; + lng_ = lngInput_->text().toDouble(&ok1); + lat_ = latInput_->text().toDouble(&ok2); + + if (ok1 && ok2) { + accept(); + } else { + QMessageBox::warning(this, "错误", "请输入有效的经纬度坐标"); + } +} + +double LocateDialog::getLongitude() const { + return lng_; +} + +double LocateDialog::getLatitude() const { + return lat_; +} + +// 更新 handleMapClick 以支持绘制模式 +void MapPage::handleMapClick(double lng, double lat) { + qDebug() << "Map clicked in C++: lng=" << lng << ", lat=" << lat; + emit mapClicked(lng, lat); // 始终发出信号,dialog 会根据模式处理 + // 如果在绘制模式,可以在这里添加额外逻辑,但由于连接在 dialog 中,保持简单 +} + +// 移除不必要的 handleDrawingClick +// void MapPage::handleDrawingClick(double lng, double lat) { } + +void MapPage::onConsoleMessage(QWebEnginePage::JavaScriptConsoleMessageLevel level, const QString &message, int lineNumber, const QString &sourceID) { + qDebug() << "Console message:" << level << message << "at line" << lineNumber << "source:" << sourceID; +} + +// Implement MapPage missing methods +QWidget* MapPage::createMapControlsWidget() { + auto* widget = new QWidget(this); + auto* layout = new QHBoxLayout(widget); + layout->setContentsMargins(0, 0, 0, 0); + return widget; +} + +// 在 MapPage 中实现 +void MapPage::enableDrawingMode(const QString& shape) { + isDrawing_ = true; + drawingShape_ = shape; + drawingPoints_.clear(); + addClickListener(); +} + +void MapPage::disableDrawingMode() { + isDrawing_ = false; + removeClickListener(); +} + +void MapPage::addThreatOverlay(const QString& shape, const QVariantMap& params) { + QString overlayId = "threat_" + QString::number(threatAreas_.size()); // 唯一 ID + QVariantMap paramsWithId = params; + paramsWithId["id"] = overlayId; + + QString js; + if (shape == "circle") { + js = QString(R"( + var circle = new AMap.Circle({ + center: new AMap.LngLat(%1, %2), + radius: %3, + fillColor: '%4', + fillOpacity: 0.3, + strokeColor: '%4', + strokeWeight: 2 + }); + circle.setMap(window.map); + window.%5 = circle; // 存储以便移除 + window.map.setFitView([circle]); // 缩放到 overlay + )").arg(params["centerLng"].toDouble()).arg(params["centerLat"].toDouble()) + .arg(params["radius"].toDouble()).arg(params["color"].toString()).arg(overlayId); + } else if (shape == "rectangle") { + QString path = "["; + QList points = params["points"].toList(); + for (int i = 0; i < points.size(); ++i) { + QVariantMap p = points[i].toMap(); + if (i > 0) path += ","; + path += QString("[%1,%2]").arg(p["lng"].toDouble()).arg(p["lat"].toDouble()); + } + path += "]"; + js = QString(R"( + var polygon = new AMap.Polygon({ + path: %1, + fillColor: '%2', + fillOpacity: 0.3, + strokeColor: '%2', + strokeWeight: 2 + }); + polygon.setMap(window.map); + window.%5 = polygon; // 存储以便移除 + window.map.setFitView([polygon]); // 缩放到 overlay + )").arg(path).arg(params["color"].toString()).arg(overlayId); + } + runMapJavaScript(js + " console.log('Overlay added: " + overlayId + "'); "); + threatAreas_.append(paramsWithId); // 存储带 ID +} diff --git a/Src/pages/mappage_remote.h b/Src/pages/mappage_remote.h new file mode 100644 index 0000000..b041fc3 --- /dev/null +++ b/Src/pages/mappage_remote.h @@ -0,0 +1,308 @@ +#ifndef MAPPAGE_H +#define MAPPAGE_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // 添加 +#include +#include +#include +#include +#include +#include +#include // 添加以支持输入验证警告 +#include // 添加QGroupBox支持 +#include // 添加QRadioButton支持 +#include +#include +#include +#include +#include "mapbridge.h" + +class CustomWebEnginePage : public QWebEnginePage { + Q_OBJECT +signals: + void consoleMessage(QWebEnginePage::JavaScriptConsoleMessageLevel level, const QString &message, int lineNumber, const QString &sourceID); +public: + CustomWebEnginePage(QObject* parent = nullptr) : QWebEnginePage(parent) {} +protected: + void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString& message, int lineNumber, const QString& sourceID) override { + qDebug() << "JS 消息 (级别:" << level << "):" << message << " (行:" << lineNumber << ", 来源:" << sourceID << ")"; + emit consoleMessage(level, message, lineNumber, sourceID); + } +}; + +// 移除前向声明 +// class ThreatAreaDialog; +// class AreaSearchDialog; +// class PathPlanningDialog; + +// 前向声明 +class MapPage; + +// 定义类 +class ThreatAreaDialog : public QDialog { + Q_OBJECT +public: + ThreatAreaDialog(QWidget* parent = nullptr, MapPage* mapPage = nullptr); // 添加 MapPage 参数 +private slots: + void addArea(); + void updateThreatStats(); + void startDrawingThreatArea(); + void onShapeChanged(int index); // 新增槽函数,处理形状变化 + void handleDrawingClick(double lng, double lat); // 新增 + void finishDrawing(); // 新增 + void editArea(); // 新增:编辑选中区域 + void deleteArea(); // 新增:删除选中区域 +private: + QComboBox* typeCombo_; + QDateTimeEdit* startTimeEdit_; + QDateTimeEdit* endTimeEdit_; + QComboBox* shapeCombo_; // 已存在,但确保用于圆形/矩形 + QComboBox* colorCombo_; + QTableWidget* areaTable_; + QLineEdit* coordInput_; + QPushButton* drawOnMapBtn_; + + // 新增输入字段 + QWidget* circleInputWidget_; + QWidget* rectangleInputWidget_; + QLineEdit* centerLngInput_; + QLineEdit* centerLatInput_; + QLineEdit* radiusInput_; + QTableWidget* rectPointsTable_; + + MapPage* mapPage_; // 添加 MapPage 引用 + QString currentShape_; // 当前形状 + QList> drawingPoints_; // 新增临时绘制点 + QComboBox* levelCombo_; // 新增,存储威胁等级 + QPushButton* editBtn_; // 新增编辑按钮 + QPushButton* deleteBtn_; // 新增删除按钮 + int selectedRow_ = -1; // 跟踪选中行 +}; + + +class MapPage; + +class PathPlanningDialog : public QDialog { + Q_OBJECT +public: + PathPlanningDialog(QWidget* parent = nullptr, MapPage* mapPage = nullptr); + QString getStartCoord() const { return startInput_->text(); } + QString getEndCoord() const { return endInput_->text(); } + QString getPathData() const; +private slots: + void planPath(); + void applyStartPoint(); + void applyEndPoint(); + void onMapClick(double lng, double lat); + void clearPath(); +private: + QLineEdit* startInput_; + QLineEdit* endInput_; + QTableWidget* pathTable_; + QPushButton* planBtn_; + QPushButton* clearBtn_; + QPushButton* applyStartBtn_; + QPushButton* applyEndBtn_; + QPushButton* selectStartBtn_; + QPushButton* selectEndBtn_; + MapPage* mapPage_; + QString pathData_; + bool selectingStart_ = false; + bool selectingEnd_ = false; +}; + +class AreaCoverageDialog : public QDialog { + Q_OBJECT +public: + AreaCoverageDialog(QWidget* parent = nullptr, MapPage* mapPage = nullptr); + QString getCoveragePathData() const { return coveragePathData_; } +private slots: + void onShapeChanged(int index); + void addVertex(); + void removeVertex(); + void selectVertexOnMap(); + void planCoveragePath(); + void clearCoverage(); + void onMapClick(double lng, double lat); +private: + QWidget* setupCircleInputs(); + QWidget* setupPolygonInputs(); + void generateMockCoveragePath(); + QComboBox* shapeCombo_; + // Circle inputs + QLineEdit* centerLngInput_; + QLineEdit* centerLatInput_; + QLineEdit* radiusInput_; + // Polygon inputs + QTableWidget* verticesTable_; + QPushButton* addVertexBtn_; + QPushButton* removeVertexBtn_; + QPushButton* selectVertexBtn_; + // Mode and drones + QButtonGroup* modeGroup_; + QRadioButton* efficiencyRadio_; + QRadioButton* fullRangeRadio_; + QSpinBox* droneCountSpin_; + // Path + QTableWidget* pathTable_; + QPushButton* planBtn_; + QPushButton* clearBtn_; + QWidget* circleWidget_; + QWidget* polygonWidget_; + MapPage* mapPage_; + QString coveragePathData_; + bool selectingVertex_ = false; + int currentVertexRow_ = -1; + QList> vertices_; +}; + + +// 添加LocateDialog类定义 +class LocateDialog : public QDialog { + Q_OBJECT +public: + LocateDialog(QWidget* parent = nullptr); + double getLongitude() const; + double getLatitude() const; +private slots: + void onConfirm(); +private: + QLineEdit* lngInput_; + QLineEdit* latInput_; + double lng_; + double lat_; +}; + +/** + * 地图监控页面类 + * 负责地图监控界面的构建和路径规划功能 + */ +class MapPage : public QWidget { + Q_OBJECT + +public: + explicit MapPage(QWidget* parent = nullptr); + ~MapPage(); + + // 获取组件引用 + QComboBox* getHeightCombo() const { return heightCombo_; } + QPushButton* getDownloadMapBtn() const { return downloadMapBtn_; } + + // 添加新信号 + signals: + void heightChanged(const QString& height); + void downloadMapRequested(); + void setThreatRequested(); + void pathPlanningRequested(); + void areaCoverageRequested(); + void mapClicked(double lng, double lat); + +private slots: + void onHeightChanged(); + void onDownloadMapClicked(); + + // 添加新槽函数 + void onSetThreatClicked(); + void onPathPlanningClicked(); + void onAreaCoverageClicked(); + + // 添加新槽 + void onSearchMapClicked(); // 新增声明 + void onConsoleMessage(QWebEnginePage::JavaScriptConsoleMessageLevel level, const QString &message, int lineNumber, const QString &sourceID); + void onPageLoaded(bool ok); + +public slots: + void addClickListener(); + void removeClickListener(); + void handleMapClick(double lng, double lat); + void visualizePath(const QString& pathData); + void clearPathOverlays(); // 清除路径覆盖物 + void runMapJavaScript(const QString& js); // 添加公共方法运行JS + double parseLng(const QString& coord) const; + double parseLat(const QString& coord) const; + void showMarker(double lng, double lat, const QString& label, const QString& color, int index); + void visualizeCoveragePath(const QString& pathData); + void clearCoverageOverlays(); + void enableDrawingMode(const QString& shape); + void disableDrawingMode(); + void addThreatOverlay(const QString& shape, const QVariantMap& params); // 添加威胁 overlay + void removeThreatOverlay(int index); // 新增:移除特定 overlay + +private: + void setupUI(); + void setupMapControls(); + void setupMapArea(); + void setupControlBar(); + + // 添加新方法 + void enableGeolocation(); + + // 创建UI组件的辅助方法 + QWidget* createMapControlsWidget(); + QWidget* createControlBarWidget(); + + // UI组件 + QFrame* mapArea_; + QComboBox* heightCombo_; + QPushButton* downloadMapBtn_; + QWebEngineView* mapView_; + + // 添加新按钮成员 + QPushButton* setThreatBtn_; + QPushButton* pathPlanningBtn_; + QPushButton* areaCoverageBtn_; + + // 添加新组件 + QLineEdit* coordInput_; + QPushButton* locateBtn_; + QPushButton* searchMapBtn_; + + // 添加对话框成员 + ThreatAreaDialog* threatDialog_; + PathPlanningDialog* planningDialog_; + AreaCoverageDialog* coverageDialog_; + LocateDialog* locateDialog_; + + // 添加基字体大小(用于缩放) + int baseFontSize_ = 10; // 默认基字体大小,根据您的样式调整 + + // 路径规划相关成员 + QString pathOverlayId_ = "pathOverlay"; + QString startMarkerId_ = "startMarker"; + QString endMarkerId_ = "endMarker"; + QString currentPathData_; // 存储当前路径数据 + + // Bridge members + MapBridge* bridge_; + QWebChannel* channel_; + + // Coverage related + QString coverageOverlayId_ = "coverageOverlay"; + QString areaOverlayId_ = "areaOverlay"; + QString currentCoveragePathData_; + + // 绘制模式 + bool isDrawing_ = false; + QString drawingShape_; // "circle" or "rectangle" + QList> drawingPoints_; // 临时绘制点 + QList threatAreas_; // 新增:存储已添加的威胁区域 + +public: + const QList& getThreatAreas() const { return threatAreas_; } // 新增 getter +}; + +// 移除所有类定义,从h文件移出 + +#endif // MAPPAGE_H diff --git a/Src/pages/taskdata.cpp b/Src/pages/taskdata.cpp new file mode 100755 index 0000000..76e42c2 --- /dev/null +++ b/Src/pages/taskdata.cpp @@ -0,0 +1,252 @@ +#include "taskdata.h" +#include + +/** + * 任务数据模型实现 + * 负责管理单个任务的所有状态信息和操作 + */ + +TaskData::TaskData(const QString& id, const QString& droneId, TaskType type, QObject* parent) + : QObject(parent) + , id_(id) + , droneId_(droneId) + , type_(type) + , status_(TaskStatus::Pending) + , createdTime_(QDateTime::currentDateTime()) +{ +} + +void TaskData::setStatus(TaskStatus status) { + if (status_ != status) { + status_ = status; + emit statusChanged(status_); + } +} + +void TaskData::setDescription(const QString& description) { + description_ = description; +} + +void TaskData::setStartPosition(const QVector3D& pos) { + startPosition_ = pos; +} + +void TaskData::setEndPosition(const QVector3D& pos) { + endPosition_ = pos; +} + +void TaskData::addWaypoint(const QVector3D& waypoint) { + waypoints_.append(waypoint); +} + +void TaskData::setWaypoints(const QVector& waypoints) { + waypoints_ = waypoints; +} + +void TaskData::startTask() { + if (status_ == TaskStatus::Pending) { + setStatus(TaskStatus::InProgress); + startTime_ = QDateTime::currentDateTime(); + emit taskStarted(); + } +} + +void TaskData::completeTask() { + if (status_ == TaskStatus::InProgress) { + setStatus(TaskStatus::Completed); + endTime_ = QDateTime::currentDateTime(); + emit taskCompleted(); + } +} + +void TaskData::cancelTask() { + if (status_ == TaskStatus::Pending || status_ == TaskStatus::InProgress) { + setStatus(TaskStatus::Cancelled); + endTime_ = QDateTime::currentDateTime(); + emit taskCancelled(); + } +} + +void TaskData::failTask(const QString& reason) { + if (status_ == TaskStatus::InProgress) { + failureReason_ = reason; + setStatus(TaskStatus::Failed); + endTime_ = QDateTime::currentDateTime(); + emit taskFailed(reason); + } +} + +void TaskData::recallTask() { + if (status_ == TaskStatus::InProgress) { + setStatus(TaskStatus::Recalled); + endTime_ = QDateTime::currentDateTime(); + emit taskRecalled(); + } +} + +int TaskData::getDuration() const { + if (startTime_.isValid() && endTime_.isValid()) { + return startTime_.secsTo(endTime_); + } else if (startTime_.isValid()) { + return startTime_.secsTo(QDateTime::currentDateTime()); + } + return 0; +} + +QString TaskData::getStatusString() const { + switch (status_) { + case TaskStatus::Pending: return "待执行"; + case TaskStatus::InProgress: return "执行中"; + case TaskStatus::Completed: return "执行成功"; + case TaskStatus::Cancelled: return "任务取消"; + case TaskStatus::Failed: return "执行失败"; + case TaskStatus::Recalled: return "已召回"; + default: return "未知状态"; + } +} + +QString TaskData::getTypeString() const { + switch (type_) { + case TaskType::Patrol: return "巡逻任务"; + case TaskType::Inspection: return "巡检任务"; + case TaskType::Delivery: return "配送任务"; + case TaskType::Search: return "搜索任务"; + case TaskType::Emergency: return "紧急任务"; + default: return "未知类型"; + } +} + +/** + * 任务管理器实现 + * 负责管理多个任务的生命周期和状态 + */ + +TaskManager::TaskManager(QObject* parent) + : QObject(parent) +{ +} + +TaskManager::~TaskManager() { + qDeleteAll(tasks_); +} + +TaskData* TaskManager::createTask(const QString& droneId, TaskType type, const QString& description) { + QString taskId = QString("TASK_%1_%2").arg(droneId).arg(QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss")); + + auto* task = new TaskData(taskId, droneId, type, this); + task->setDescription(description); + + tasks_.append(task); + + // 连接信号 + connect(task, &TaskData::statusChanged, this, [this, taskId](TaskStatus status) { + emit taskStatusChanged(taskId, status); + }); + + emit taskCreated(taskId); + return task; +} + +void TaskManager::removeTask(const QString& taskId) { + for (int i = 0; i < tasks_.size(); ++i) { + if (tasks_[i]->getId() == taskId) { + tasks_[i]->deleteLater(); + tasks_.removeAt(i); + emit taskRemoved(taskId); + break; + } + } +} + +TaskData* TaskManager::getTask(const QString& taskId) const { + for (auto* task : tasks_) { + if (task->getId() == taskId) { + return task; + } + } + return nullptr; +} + +QVector TaskManager::getAllTasks() const { + return tasks_; +} + +QVector TaskManager::getTasksByDrone(const QString& droneId) const { + QVector result; + for (auto* task : tasks_) { + if (task->getDroneId() == droneId) { + result.append(task); + } + } + return result; +} + +QVector TaskManager::getTasksByStatus(TaskStatus status) const { + QVector result; + for (auto* task : tasks_) { + if (task->getStatus() == status) { + result.append(task); + } + } + return result; +} + +int TaskManager::getTaskCount() const { + return tasks_.size(); +} + +int TaskManager::getTaskCountByStatus(TaskStatus status) const { + int count = 0; + for (auto* task : tasks_) { + if (task->getStatus() == status) { + count++; + } + } + return count; +} + +int TaskManager::getTaskCountByDrone(const QString& droneId) const { + int count = 0; + for (auto* task : tasks_) { + if (task->getDroneId() == droneId) { + count++; + } + } + return count; +} + +void TaskManager::startTask(const QString& taskId) { + auto* task = getTask(taskId); + if (task) { + task->startTask(); + } +} + +void TaskManager::completeTask(const QString& taskId) { + auto* task = getTask(taskId); + if (task) { + task->completeTask(); + } +} + +void TaskManager::cancelTask(const QString& taskId) { + auto* task = getTask(taskId); + if (task) { + task->cancelTask(); + } +} + +void TaskManager::failTask(const QString& taskId, const QString& reason) { + auto* task = getTask(taskId); + if (task) { + task->failTask(reason); + } +} + +void TaskManager::recallTask(const QString& taskId) { + auto* task = getTask(taskId); + if (task) { + task->recallTask(); + } +} + diff --git a/Src/pages/taskdata.h b/Src/pages/taskdata.h new file mode 100755 index 0000000..5c6e5ae --- /dev/null +++ b/Src/pages/taskdata.h @@ -0,0 +1,151 @@ +#ifndef TASKDATA_H +#define TASKDATA_H + +#include +#include +#include +#include +#include + +/** + * 任务状态枚举 + * 定义无人机任务的各种执行状态 + */ +enum class TaskStatus { + Pending, // 待执行 + InProgress, // 执行中 + Completed, // 执行成功 + Cancelled, // 任务取消 + Failed, // 执行失败 + Recalled // 通信范围内取消召回 +}; + +/** + * 任务类型枚举 + * 定义不同类型的无人机任务 + */ +enum class TaskType { + Patrol, // 巡逻任务 + Inspection, // 巡检任务 + Delivery, // 配送任务 + Search, // 搜索任务 + Emergency // 紧急任务 +}; + +/** + * 任务数据模型类 + * 用于管理单个任务的所有信息,包括状态、类型、执行时间等 + */ +class TaskData : public QObject { + Q_OBJECT + +public: + explicit TaskData(const QString& id, const QString& droneId, TaskType type, QObject* parent = nullptr); + + // 基本信息 + QString getId() const { return id_; } + QString getDroneId() const { return droneId_; } + TaskType getType() const { return type_; } + TaskStatus getStatus() const { return status_; } + QString getDescription() const { return description_; } + + // 时间信息 + QDateTime getCreatedTime() const { return createdTime_; } + QDateTime getStartTime() const { return startTime_; } + QDateTime getEndTime() const { return endTime_; } + int getDuration() const; // 返回任务持续时间(秒) + + // 位置信息 + QVector3D getStartPosition() const { return startPosition_; } + QVector3D getEndPosition() const { return endPosition_; } + QVector getWaypoints() const { return waypoints_; } + + // 设置方法 + void setStatus(TaskStatus status); + void setDescription(const QString& description); + void setStartPosition(const QVector3D& pos); + void setEndPosition(const QVector3D& pos); + void addWaypoint(const QVector3D& waypoint); + void setWaypoints(const QVector& waypoints); + + // 状态转换 + void startTask(); + void completeTask(); + void cancelTask(); + void failTask(const QString& reason); + void recallTask(); + + // 获取状态描述 + QString getStatusString() const; + QString getTypeString() const; + QString getFailureReason() const { return failureReason_; } + +signals: + void statusChanged(TaskStatus status); + void taskStarted(); + void taskCompleted(); + void taskCancelled(); + void taskFailed(const QString& reason); + void taskRecalled(); + +private: + QString id_; + QString droneId_; + TaskType type_; + TaskStatus status_; + QString description_; + QString failureReason_; + + // 时间信息 + QDateTime createdTime_; + QDateTime startTime_; + QDateTime endTime_; + + // 位置信息 + QVector3D startPosition_; + QVector3D endPosition_; + QVector waypoints_; +}; + +/** + * 任务管理器类 + * 用于管理多个任务,提供任务查询和状态管理功能 + */ +class TaskManager : public QObject { + Q_OBJECT + +public: + explicit TaskManager(QObject* parent = nullptr); + ~TaskManager(); + + // 任务管理 + TaskData* createTask(const QString& droneId, TaskType type, const QString& description = ""); + void removeTask(const QString& taskId); + TaskData* getTask(const QString& taskId) const; + QVector getAllTasks() const; + QVector getTasksByDrone(const QString& droneId) const; + QVector getTasksByStatus(TaskStatus status) const; + + // 统计信息 + int getTaskCount() const; + int getTaskCountByStatus(TaskStatus status) const; + int getTaskCountByDrone(const QString& droneId) const; + + // 任务执行 + void startTask(const QString& taskId); + void completeTask(const QString& taskId); + void cancelTask(const QString& taskId); + void failTask(const QString& taskId, const QString& reason); + void recallTask(const QString& taskId); + +signals: + void taskCreated(const QString& taskId); + void taskRemoved(const QString& taskId); + void taskStatusChanged(const QString& taskId, TaskStatus status); + +private: + QVector tasks_; +}; + +#endif // TASKDATA_H + diff --git a/src/pages/taskdecisionpage.cpp b/Src/pages/taskdecisionpage.cpp similarity index 65% rename from src/pages/taskdecisionpage.cpp rename to Src/pages/taskdecisionpage.cpp index 7363d6d..92b0e38 100644 --- a/src/pages/taskdecisionpage.cpp +++ b/Src/pages/taskdecisionpage.cpp @@ -1,5 +1,8 @@ #include "taskdecisionpage.h" #include +#include "mappage.h" // For PathPlanningDialog and MapPage +#include // Added for file operations +#include // Added for saving paths TaskDecisionPage::TaskDecisionPage(QWidget* parent) : QWidget(parent) @@ -10,7 +13,9 @@ TaskDecisionPage::TaskDecisionPage(QWidget* parent) , generateBtn_(nullptr) , currentStep_(0) , isTargetClear_(true) - , previewMapPage_(nullptr) + , pathData_("") + , searchData_("") + , pathHistory_() // 初始化空列表 { setupUI(); } @@ -53,11 +58,6 @@ void TaskDecisionPage::setupUI() { mainLayout->addLayout(contentLayout, 1); - // 右侧预览区:嵌入MapPage - previewMapPage_ = new MapPage(); - previewMapPage_->setMinimumWidth(300); - mainLayout->addWidget(previewMapPage_); - // 初始化 onStepChanged(0); } @@ -102,9 +102,59 @@ QWidget* TaskDecisionPage::createStep2Widget() { pathResult_->setReadOnly(true); layout->addWidget(pathResult_); - auto* btn = new QPushButton("生成路径"); - connect(btn, &QPushButton::clicked, this, &TaskDecisionPage::onGeneratePath); - layout->addWidget(btn); + auto* btnLayout = new QHBoxLayout(); + auto* genBtn = new QPushButton("生成路径"); + connect(genBtn, &QPushButton::clicked, this, &TaskDecisionPage::onGeneratePath); + btnLayout->addWidget(genBtn); + + previewBtn_ = new QPushButton("预览路径"); + previewBtn_->setEnabled(false); + connect(previewBtn_, &QPushButton::clicked, this, [this](){ + if (!pathData_.isEmpty()) { + MapPage* previewMap = new MapPage(); + previewMap->setWindowTitle("路径预览"); + previewMap->resize(800, 600); + + // 等待页面加载完成后可视化路径 + connect(previewMap->getMapView()->page(), &QWebEnginePage::loadFinished, [previewMap, this](bool ok){ + if (ok) { + previewMap->visualizePath(pathData_); + } else { + QMessageBox::warning(this, "错误", "地图加载失败,无法预览路径"); + } + }); + + previewMap->show(); + } + }); + btnLayout->addWidget(previewBtn_); + + // 新增:保存按钮 + auto* saveBtn = new QPushButton("保存当前路径"); + connect(saveBtn, &QPushButton::clicked, this, &TaskDecisionPage::saveCurrentPath); + btnLayout->addWidget(saveBtn); + + layout->addLayout(btnLayout); + + // 新增:历史路径列表 + historyList_ = new QListWidget(); + historyList_->setSelectionMode(QAbstractItemView::SingleSelection); + layout->addWidget(new QLabel("历史路径:")); + layout->addWidget(historyList_); + + // 双击历史项预览 + connect(historyList_, &QListWidget::itemDoubleClicked, this, [this](QListWidgetItem* item){ + QString histPath = item->data(Qt::UserRole).toString(); + if (!histPath.isEmpty()) { + MapPage* histPreview = new MapPage(); + histPreview->setWindowTitle("历史路径预览"); + histPreview->resize(800, 600); + connect(histPreview->getMapView()->page(), &QWebEnginePage::loadFinished, [histPreview, histPath](bool ok){ + if (ok) histPreview->visualizePath(histPath); + }); + histPreview->show(); + } + }); return widget; } @@ -195,15 +245,40 @@ void TaskDecisionPage::onTargetClearChanged(bool clear) { roughCoord_->setVisible(!clear); } +// 修改onGeneratePath()为非模态 void TaskDecisionPage::onGeneratePath() { - // 模拟调用地图规划 - pathData_ = "路径生成: 从起点到目标,长度5km,时间10min"; - pathResult_->setText(pathData_); - QMessageBox::information(this, "路径规划", "路径已生成!"); - - // 更新预览地图:绘制路径 - QString js = "window.map.add(new AMap.Polyline({path: [[116.3,39.9], [116.4,39.9], [116.4,40.0]], strokeColor: '#FF0000'}));"; - previewMapPage_->runMapJavaScript(js); + QString start = startCoord_->text(); + QString target = isTargetClear_ ? targetCoord_->text() : roughCoord_->text(); + + if (start.isEmpty() || target.isEmpty()) { + QMessageBox::warning(this, "错误", "请输入起点和目标坐标"); + return; + } + + MapPage* planningMap = new MapPage(this); // 指定parent为TaskDecisionPage,确保窗口管理 + planningMap->setWindowTitle("路径规划地图"); + planningMap->resize(800, 600); // 设置合理大小 + planningMap->show(); // 立即显示地图窗口 + + PathPlanningDialog* dialog = new PathPlanningDialog(this, planningMap); + dialog->show(); // 非模态显示对话框 + + connect(dialog, &QDialog::finished, [this, dialog, planningMap](int result){ + if (result == QDialog::Accepted) { + pathData_ = dialog->getPathData(); + pathResult_->setText(pathData_); + previewBtn_->setEnabled(true); + + // 添加到历史 + pathHistory_.append(pathData_); + updateHistoryList(); + + QMessageBox::information(this, "路径规划", "路径已生成并保存到历史,可预览!"); + } + planningMap->hide(); // 隐藏地图 + delete dialog; + delete planningMap; // 清理 + }); } void TaskDecisionPage::onRecommendDrones() { @@ -225,10 +300,6 @@ void TaskDecisionPage::onReplanSearch() { coverage_->setText("覆盖范围: 90%"); searchData_ = "搜索策略生成"; QMessageBox::information(this, "规划", "搜索策略已重新规划!"); - - // 更新预览地图:绘制搜索区域 - QString js = "window.map.add(new AMap.Polygon({path: [[116.3,39.9], [116.5,39.9], [116.5,40.1], [116.3,40.1]], fillColor: '#00FF00'}));"; - previewMapPage_->runMapJavaScript(js); } void TaskDecisionPage::onAddTargetType() { @@ -264,7 +335,12 @@ void TaskDecisionPage::onGenerateTask() { taskPreview_->setText(preview); // 生成任务包(模拟保存JSON) - QMessageBox::information(this, "生成", "任务数据包已生成!"); + QFile file("task_path.json"); + if (file.open(QIODevice::WriteOnly)) { + file.write(pathData_.toUtf8()); + file.close(); + } + QMessageBox::information(this, "生成", "任务数据包已生成!路径保存到task_path.json"); } void TaskDecisionPage::onNextStep() { @@ -283,3 +359,29 @@ void TaskDecisionPage::onPrevStep() { onStepChanged(currentStep_ - 1); } } + +// 新增函数:更新历史列表 +void TaskDecisionPage::updateHistoryList() { + historyList_->clear(); + for (int i = 0; i < pathHistory_.size(); ++i) { + QListWidgetItem* item = new QListWidgetItem(QString("路径 %1").arg(i+1)); + item->setData(Qt::UserRole, pathHistory_[i]); + historyList_->addItem(item); + } +} + +// 新增函数:保存当前路径到文件(可选扩展) +void TaskDecisionPage::saveCurrentPath() { + if (pathData_.isEmpty()) { + QMessageBox::warning(this, "错误", "无当前路径可保存"); + return; + } + QFile file(QString("saved_path_%1.json").arg(QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss"))); + if (file.open(QIODevice::WriteOnly)) { + file.write(pathData_.toUtf8()); + file.close(); + QMessageBox::information(this, "成功", "当前路径已保存到文件"); + } else { + QMessageBox::warning(this, "错误", "保存失败"); + } +} diff --git a/src/pages/taskdecisionpage.h b/Src/pages/taskdecisionpage.h similarity index 88% rename from src/pages/taskdecisionpage.h rename to Src/pages/taskdecisionpage.h index eaddb00..7014dc9 100644 --- a/src/pages/taskdecisionpage.h +++ b/Src/pages/taskdecisionpage.h @@ -16,7 +16,7 @@ #include #include #include // 添加以支持QSpinBox -#include "mappage.h" // 添加用于嵌入MapPage +#include // 添加以支持QList class TaskDecisionPage : public QWidget { Q_OBJECT @@ -42,6 +42,8 @@ private: QWidget* createStep3Widget(); // 区域搜索策略 QWidget* createStep4Widget(); // 打击目标清单 QWidget* createStep5Widget(); // 任务预览与生成 + void updateHistoryList(); + void saveCurrentPath(); // 成员变量 QStackedWidget* contentStack_; @@ -49,6 +51,8 @@ private: QPushButton* prevBtn_; QPushButton* nextBtn_; QPushButton* generateBtn_; + QPushButton* previewBtn_; + QListWidget* historyList_; // 新增:历史路径列表 // 步骤1 QRadioButton* clearYes_; @@ -79,9 +83,8 @@ private: // 假设的路径/搜索数据(实际中从地图调用) QString pathData_; QString searchData_; + QList pathHistory_; // 新增:存储历史路径 - // 预览地图:使用MapPage - MapPage* previewMapPage_; }; #endif // TASKDECISIONPAGE_H diff --git a/Src/pages/taskdetailspage.cpp b/Src/pages/taskdetailspage.cpp new file mode 100755 index 0000000..1921e6b --- /dev/null +++ b/Src/pages/taskdetailspage.cpp @@ -0,0 +1,633 @@ +#include "taskdetailspage.h" +#include +#include +#include +#include +#include + +/** + * 任务执行详情页面实现 + * 负责展示所有任务的执行状态、进度和详细信息 + */ + +TaskDetailsPage::TaskDetailsPage(QWidget* parent) + : QWidget(parent) + , mainFrame_(nullptr) + , taskTable_(nullptr) + , filterGroup_(nullptr) + , controlGroup_(nullptr) + , statusGroup_(nullptr) + , statusFilter_(nullptr) + , droneFilter_(nullptr) + , typeFilter_(nullptr) + , clearFilterBtn_(nullptr) + , startTaskBtn_(nullptr) + , completeTaskBtn_(nullptr) + , cancelTaskBtn_(nullptr) + , failTaskBtn_(nullptr) + , recallTaskBtn_(nullptr) + , refreshBtn_(nullptr) + , totalTasksLabel_(nullptr) + , pendingTasksLabel_(nullptr) + , inProgressTasksLabel_(nullptr) + , completedTasksLabel_(nullptr) + , failedTasksLabel_(nullptr) + , cancelledTasksLabel_(nullptr) + , recalledTasksLabel_(nullptr) + , selectedTaskLabel_(nullptr) + , progressBar_(nullptr) + , taskManager_(nullptr) + , droneManager_(nullptr) + , refreshTimer_(nullptr) + , selectedTaskId_("") + , currentStatusFilter_(TaskStatus::Pending) + , currentDroneFilter_("") + , currentTypeFilter_(TaskType::Patrol) +{ + setupUI(); + + // 设置定时刷新 + refreshTimer_ = new QTimer(this); + connect(refreshTimer_, &QTimer::timeout, this, &TaskDetailsPage::onRefreshTasks); + // 暂时禁用定时刷新,避免格式化问题 + // refreshTimer_->start(3000); // 每3秒刷新一次,减少刷新频率 +} + +TaskDetailsPage::~TaskDetailsPage() { + if (refreshTimer_) { + refreshTimer_->stop(); + } +} + +void TaskDetailsPage::setTaskManager(TaskManager* taskManager) { + taskManager_ = taskManager; + + if (taskManager_) { + // 连接信号 + connect(taskManager_, &TaskManager::taskCreated, this, &TaskDetailsPage::onTaskDataChanged); + connect(taskManager_, &TaskManager::taskRemoved, this, &TaskDetailsPage::onTaskDataChanged); + connect(taskManager_, &TaskManager::taskStatusChanged, this, &TaskDetailsPage::onTaskStatusChanged); + + // 初始化表格数据 + updateTaskTable(); + updateStatusDisplay(); + } +} + +void TaskDetailsPage::setDroneManager(DroneManager* droneManager) { + droneManager_ = droneManager; + + if (droneManager_) { + // 连接无人机变化信号 + connect(droneManager_, &DroneManager::droneAdded, this, &TaskDetailsPage::onTaskDataChanged); + connect(droneManager_, &DroneManager::droneRemoved, this, &TaskDetailsPage::onTaskDataChanged); + + // 更新无人机筛选列表 + onTaskDataChanged(); + } +} + +void TaskDetailsPage::setupUI() { + auto* mainLayout = new QVBoxLayout(this); + mainLayout->setSpacing(10); + mainLayout->setContentsMargins(10, 10, 10, 10); + + // 创建主框架 + mainFrame_ = new QFrame(this); + mainFrame_->setStyleSheet("QFrame{background:#f8f9fa; border:1px solid #dee2e6; border-radius:8px;}"); + + auto* frameLayout = new QVBoxLayout(mainFrame_); + frameLayout->setSpacing(15); + frameLayout->setContentsMargins(15, 15, 15, 15); + + setupFilterPanel(); + setupTaskTable(); + setupControlPanel(); + setupStatusPanel(); + + frameLayout->addWidget(filterGroup_, 0); + frameLayout->addWidget(taskTable_, 2); + frameLayout->addWidget(controlGroup_, 0); + frameLayout->addWidget(statusGroup_, 1); + + mainLayout->addWidget(mainFrame_); +} + +void TaskDetailsPage::setupFilterPanel() { + filterGroup_ = new QGroupBox("任务筛选", this); + auto* groupLayout = new QHBoxLayout(filterGroup_); + groupLayout->setSpacing(10); + + // 状态筛选 + groupLayout->addWidget(new QLabel("状态:", this)); + statusFilter_ = new QComboBox(this); + statusFilter_->addItem("全部状态", -1); + statusFilter_->addItem("待执行", static_cast(TaskStatus::Pending)); + statusFilter_->addItem("执行中", static_cast(TaskStatus::InProgress)); + statusFilter_->addItem("执行成功", static_cast(TaskStatus::Completed)); + statusFilter_->addItem("任务取消", static_cast(TaskStatus::Cancelled)); + statusFilter_->addItem("执行失败", static_cast(TaskStatus::Failed)); + statusFilter_->addItem("已召回", static_cast(TaskStatus::Recalled)); + connect(statusFilter_, QOverload::of(&QComboBox::currentIndexChanged), this, &TaskDetailsPage::onFilterChanged); + groupLayout->addWidget(statusFilter_); + + // 无人机筛选 + groupLayout->addWidget(new QLabel("无人机:", this)); + droneFilter_ = new QComboBox(this); + droneFilter_->addItem("全部无人机", ""); + connect(droneFilter_, QOverload::of(&QComboBox::currentIndexChanged), this, &TaskDetailsPage::onFilterChanged); + groupLayout->addWidget(droneFilter_); + + // 类型筛选 + groupLayout->addWidget(new QLabel("类型:", this)); + typeFilter_ = new QComboBox(this); + typeFilter_->addItem("全部类型", -1); + typeFilter_->addItem("巡逻任务", static_cast(TaskType::Patrol)); + typeFilter_->addItem("巡检任务", static_cast(TaskType::Inspection)); + typeFilter_->addItem("配送任务", static_cast(TaskType::Delivery)); + typeFilter_->addItem("搜索任务", static_cast(TaskType::Search)); + typeFilter_->addItem("紧急任务", static_cast(TaskType::Emergency)); + connect(typeFilter_, QOverload::of(&QComboBox::currentIndexChanged), this, &TaskDetailsPage::onFilterChanged); + groupLayout->addWidget(typeFilter_); + + // 清除筛选按钮 + clearFilterBtn_ = new QPushButton("清除筛选", this); + clearFilterBtn_->setStyleSheet("QPushButton{background:#6c757d; color:white; border:none; padding:6px 12px; border-radius:4px;}"); + connect(clearFilterBtn_, &QPushButton::clicked, this, [this]() { + statusFilter_->setCurrentIndex(0); + droneFilter_->setCurrentIndex(0); + typeFilter_->setCurrentIndex(0); + onFilterChanged(); + }); + groupLayout->addWidget(clearFilterBtn_); + + groupLayout->addStretch(); +} + +void TaskDetailsPage::setupTaskTable() { + taskTable_ = new QTableWidget(this); + taskTable_->setColumnCount(10); + taskTable_->setHorizontalHeaderLabels({ + "任务ID", "无人机", "类型", "状态", "描述", + "创建时间", "开始时间", "结束时间", "持续时间", "失败原因" + }); + + // 设置表格属性 + taskTable_->setAlternatingRowColors(true); + taskTable_->setSelectionBehavior(QAbstractItemView::SelectRows); + taskTable_->setSelectionMode(QAbstractItemView::SingleSelection); + taskTable_->setSortingEnabled(false); + + // 设置列宽 + QHeaderView* header = taskTable_->horizontalHeader(); + header->setStretchLastSection(true); + header->setSectionResizeMode(QHeaderView::ResizeToContents); + + // 连接选择变化信号 + connect(taskTable_, &QTableWidget::itemSelectionChanged, this, &TaskDetailsPage::onTaskSelectionChanged); +} + +void TaskDetailsPage::setupControlPanel() { + controlGroup_ = new QGroupBox("任务控制", this); + auto* groupLayout = new QHBoxLayout(controlGroup_); + groupLayout->setSpacing(10); + + startTaskBtn_ = new QPushButton("开始任务", this); + startTaskBtn_->setStyleSheet("QPushButton{background:#28a745; color:white; border:none; padding:8px 16px; border-radius:4px;}"); + connect(startTaskBtn_, &QPushButton::clicked, this, &TaskDetailsPage::onStartTaskClicked); + groupLayout->addWidget(startTaskBtn_); + + completeTaskBtn_ = new QPushButton("完成任务", this); + completeTaskBtn_->setStyleSheet("QPushButton{background:#007bff; color:white; border:none; padding:8px 16px; border-radius:4px;}"); + connect(completeTaskBtn_, &QPushButton::clicked, this, &TaskDetailsPage::onCompleteTaskClicked); + groupLayout->addWidget(completeTaskBtn_); + + cancelTaskBtn_ = new QPushButton("取消任务", this); + cancelTaskBtn_->setStyleSheet("QPushButton{background:#ffc107; color:black; border:none; padding:8px 16px; border-radius:4px;}"); + connect(cancelTaskBtn_, &QPushButton::clicked, this, &TaskDetailsPage::onCancelTaskClicked); + groupLayout->addWidget(cancelTaskBtn_); + + failTaskBtn_ = new QPushButton("标记失败", this); + failTaskBtn_->setStyleSheet("QPushButton{background:#dc3545; color:white; border:none; padding:8px 16px; border-radius:4px;}"); + connect(failTaskBtn_, &QPushButton::clicked, this, &TaskDetailsPage::onFailTaskClicked); + groupLayout->addWidget(failTaskBtn_); + + recallTaskBtn_ = new QPushButton("召回任务", this); + recallTaskBtn_->setStyleSheet("QPushButton{background:#6f42c1; color:white; border:none; padding:8px 16px; border-radius:4px;}"); + connect(recallTaskBtn_, &QPushButton::clicked, this, &TaskDetailsPage::onRecallTaskClicked); + groupLayout->addWidget(recallTaskBtn_); + + refreshBtn_ = new QPushButton("刷新", this); + refreshBtn_->setStyleSheet("QPushButton{background:#17a2b8; color:white; border:none; padding:8px 16px; border-radius:4px;}"); + connect(refreshBtn_, &QPushButton::clicked, this, &TaskDetailsPage::onRefreshTasks); + groupLayout->addWidget(refreshBtn_); + + groupLayout->addStretch(); +} + +void TaskDetailsPage::setupStatusPanel() { + statusGroup_ = new QGroupBox("任务统计", this); + auto* groupLayout = new QVBoxLayout(statusGroup_); + groupLayout->setSpacing(8); + + // 统计信息 + auto* statsLayout = new QHBoxLayout(); + totalTasksLabel_ = new QLabel("总任务数: 0", this); + totalTasksLabel_->setStyleSheet("QLabel{font-weight:bold; color:#495057;}"); + statsLayout->addWidget(totalTasksLabel_); + + pendingTasksLabel_ = new QLabel("待执行: 0", this); + pendingTasksLabel_->setStyleSheet("QLabel{color:#6c757d;}"); + statsLayout->addWidget(pendingTasksLabel_); + + inProgressTasksLabel_ = new QLabel("执行中: 0", this); + inProgressTasksLabel_->setStyleSheet("QLabel{color:#007bff;}"); + statsLayout->addWidget(inProgressTasksLabel_); + + completedTasksLabel_ = new QLabel("已完成: 0", this); + completedTasksLabel_->setStyleSheet("QLabel{color:#28a745;}"); + statsLayout->addWidget(completedTasksLabel_); + + groupLayout->addLayout(statsLayout); + + // 第二行统计 + auto* statsLayout2 = new QHBoxLayout(); + failedTasksLabel_ = new QLabel("失败: 0", this); + failedTasksLabel_->setStyleSheet("QLabel{color:#dc3545;}"); + statsLayout2->addWidget(failedTasksLabel_); + + cancelledTasksLabel_ = new QLabel("取消: 0", this); + cancelledTasksLabel_->setStyleSheet("QLabel{color:#ffc107;}"); + statsLayout2->addWidget(cancelledTasksLabel_); + + recalledTasksLabel_ = new QLabel("召回: 0", this); + recalledTasksLabel_->setStyleSheet("QLabel{color:#6f42c1;}"); + statsLayout2->addWidget(recalledTasksLabel_); + + groupLayout->addLayout(statsLayout2); + + // 选中任务信息 + selectedTaskLabel_ = new QLabel("未选择任务", this); + selectedTaskLabel_->setStyleSheet("QLabel{font-weight:bold; color:#007bff;}"); + groupLayout->addWidget(selectedTaskLabel_); + + // 进度条 + progressBar_ = new QProgressBar(this); + progressBar_->setVisible(false); + groupLayout->addWidget(progressBar_); +} + +void TaskDetailsPage::updateTaskTable() { + if (!taskManager_) return; + + taskTable_->setRowCount(0); + + auto tasks = taskManager_->getAllTasks(); + for (auto* task : tasks) { + // 应用筛选条件 + bool showTask = true; + + // 状态筛选 + if (currentStatusFilter_ != TaskStatus::Pending && task->getStatus() != currentStatusFilter_) { + showTask = false; + } + + // 无人机筛选 + if (!currentDroneFilter_.isEmpty() && task->getDroneId() != currentDroneFilter_) { + showTask = false; + } + + // 类型筛选 + if (currentTypeFilter_ != TaskType::Patrol && task->getType() != currentTypeFilter_) { + showTask = false; + } + + if (showTask) { + addTaskToTable(task); + } + } +} + +void TaskDetailsPage::addTaskToTable(TaskData* task) { + if (!task) return; + + int row = taskTable_->rowCount(); + taskTable_->insertRow(row); + + // 设置行数据 + taskTable_->setItem(row, 0, new QTableWidgetItem(task->getId())); + taskTable_->setItem(row, 1, new QTableWidgetItem(task->getDroneId())); + taskTable_->setItem(row, 2, new QTableWidgetItem(task->getTypeString())); + taskTable_->setItem(row, 3, new QTableWidgetItem(task->getStatusString())); + taskTable_->setItem(row, 4, new QTableWidgetItem(task->getDescription())); + taskTable_->setItem(row, 5, new QTableWidgetItem(formatDateTime(task->getCreatedTime()))); + taskTable_->setItem(row, 6, new QTableWidgetItem(formatDateTime(task->getStartTime()))); + taskTable_->setItem(row, 7, new QTableWidgetItem(formatDateTime(task->getEndTime()))); + taskTable_->setItem(row, 8, new QTableWidgetItem(formatDuration(task->getDuration()))); + taskTable_->setItem(row, 9, new QTableWidgetItem(task->getFailureReason())); + + // 设置状态颜色 + auto* statusItem = taskTable_->item(row, 3); + if (statusItem) { + statusItem->setBackground(QColor(getStatusColor(task->getStatus()))); + } + + // 连接数据变化信号 + connect(task, &TaskData::statusChanged, this, &TaskDetailsPage::onTaskDataChanged); +} + +void TaskDetailsPage::updateTaskRow(TaskData* task) { + if (!task) return; + + for (int i = 0; i < taskTable_->rowCount(); ++i) { + auto* item = taskTable_->item(i, 0); + if (item && item->text() == task->getId()) { + // 更新所有列 + taskTable_->setItem(i, 1, new QTableWidgetItem(task->getDroneId())); + taskTable_->setItem(i, 2, new QTableWidgetItem(task->getTypeString())); + taskTable_->setItem(i, 3, new QTableWidgetItem(task->getStatusString())); + taskTable_->setItem(i, 4, new QTableWidgetItem(task->getDescription())); + taskTable_->setItem(i, 5, new QTableWidgetItem(formatDateTime(task->getCreatedTime()))); + taskTable_->setItem(i, 6, new QTableWidgetItem(formatDateTime(task->getStartTime()))); + taskTable_->setItem(i, 7, new QTableWidgetItem(formatDateTime(task->getEndTime()))); + taskTable_->setItem(i, 8, new QTableWidgetItem(formatDuration(task->getDuration()))); + taskTable_->setItem(i, 9, new QTableWidgetItem(task->getFailureReason())); + + // 更新状态颜色 + auto* statusItem = taskTable_->item(i, 3); + if (statusItem) { + statusItem->setBackground(QColor(getStatusColor(task->getStatus()))); + } + break; + } + } +} + +void TaskDetailsPage::removeTaskFromTable(const QString& taskId) { + for (int i = 0; i < taskTable_->rowCount(); ++i) { + auto* item = taskTable_->item(i, 0); + if (item && item->text() == taskId) { + taskTable_->removeRow(i); + break; + } + } +} + +void TaskDetailsPage::updateStatusDisplay() { + if (!taskManager_) return; + + int totalCount = taskManager_->getTaskCount(); + int pendingCount = taskManager_->getTaskCountByStatus(TaskStatus::Pending); + int inProgressCount = taskManager_->getTaskCountByStatus(TaskStatus::InProgress); + int completedCount = taskManager_->getTaskCountByStatus(TaskStatus::Completed); + int failedCount = taskManager_->getTaskCountByStatus(TaskStatus::Failed); + int cancelledCount = taskManager_->getTaskCountByStatus(TaskStatus::Cancelled); + int recalledCount = taskManager_->getTaskCountByStatus(TaskStatus::Recalled); + + totalTasksLabel_->setText(QString("总任务数: %1").arg(totalCount)); + pendingTasksLabel_->setText(QString("待执行: %1").arg(pendingCount)); + inProgressTasksLabel_->setText(QString("执行中: %1").arg(inProgressCount)); + completedTasksLabel_->setText(QString("已完成: %1").arg(completedCount)); + failedTasksLabel_->setText(QString("失败: %1").arg(failedCount)); + cancelledTasksLabel_->setText(QString("取消: %1").arg(cancelledCount)); + recalledTasksLabel_->setText(QString("召回: %1").arg(recalledCount)); + + // 更新选中任务信息 + if (!selectedTaskId_.isEmpty()) { + auto* selectedTask = taskManager_->getTask(selectedTaskId_); + if (selectedTask) { + selectedTaskLabel_->setText(QString("选中: %1 (%2)").arg(selectedTask->getDescription()).arg(selectedTask->getId())); + + // 显示进度条(仅对执行中的任务) + if (selectedTask->getStatus() == TaskStatus::InProgress) { + progressBar_->setVisible(true); + int duration = selectedTask->getDuration(); + progressBar_->setValue(qMin(duration, 100)); // 简单的进度显示 + } else { + progressBar_->setVisible(false); + } + } + } else { + selectedTaskLabel_->setText("未选择任务"); + progressBar_->setVisible(false); + } +} + +void TaskDetailsPage::updateControlButtons() { + bool hasSelection = !selectedTaskId_.isEmpty(); + TaskStatus selectedStatus = TaskStatus::Pending; + + if (hasSelection && taskManager_) { + auto* selectedTask = taskManager_->getTask(selectedTaskId_); + if (selectedTask) { + selectedStatus = selectedTask->getStatus(); + } + } + + // 根据任务状态启用/禁用按钮 + startTaskBtn_->setEnabled(hasSelection && selectedStatus == TaskStatus::Pending); + completeTaskBtn_->setEnabled(hasSelection && selectedStatus == TaskStatus::InProgress); + cancelTaskBtn_->setEnabled(hasSelection && (selectedStatus == TaskStatus::Pending || selectedStatus == TaskStatus::InProgress)); + failTaskBtn_->setEnabled(hasSelection && selectedStatus == TaskStatus::InProgress); + recallTaskBtn_->setEnabled(hasSelection && selectedStatus == TaskStatus::InProgress); +} + +QString TaskDetailsPage::getStatusColor(TaskStatus status) const { + switch (status) { + case TaskStatus::Pending: return "#f8d7da"; // 浅红色 + case TaskStatus::InProgress: return "#d1ecf1"; // 浅蓝色 + case TaskStatus::Completed: return "#d4edda"; // 浅绿色 + case TaskStatus::Cancelled: return "#fff3cd"; // 浅黄色 + case TaskStatus::Failed: return "#f8d7da"; // 浅红色 + case TaskStatus::Recalled: return "#e2e3e5"; // 浅灰色 + default: return "#ffffff"; + } +} + +QString TaskDetailsPage::getStatusIcon(TaskStatus status) const { + switch (status) { + case TaskStatus::Pending: return "⏳"; + case TaskStatus::InProgress: return "🔄"; + case TaskStatus::Completed: return "✅"; + case TaskStatus::Cancelled: return "❌"; + case TaskStatus::Failed: return "❌"; + case TaskStatus::Recalled: return "🔙"; + default: return "❓"; + } +} + +QString TaskDetailsPage::getTypeColor(TaskType type) const { + switch (type) { + case TaskType::Patrol: return "#007bff"; + case TaskType::Inspection: return "#28a745"; + case TaskType::Delivery: return "#ffc107"; + case TaskType::Search: return "#17a2b8"; + case TaskType::Emergency: return "#dc3545"; + default: return "#6c757d"; + } +} + +QString TaskDetailsPage::formatDateTime(const QDateTime& dateTime) const { + if (!dateTime.isValid()) { + return "--"; + } + return dateTime.toString("yyyy-MM-dd hh:mm:ss"); +} + +QString TaskDetailsPage::formatDuration(int seconds) const { + if (seconds <= 0) { + return "--"; + } + + int hours = seconds / 3600; + int minutes = (seconds % 3600) / 60; + int secs = seconds % 60; + + if (hours > 0) { + return QString("%1h %2m %3s").arg(hours).arg(minutes).arg(secs); + } else if (minutes > 0) { + return QString("%1m %2s").arg(minutes).arg(secs); + } else { + return QString("%1s").arg(secs); + } +} + +QString TaskDetailsPage::formatPosition(const QVector3D& pos) const { + return QString("(%1, %2, %3)") + .arg(QString::number(pos.x(), 'f', 2)) + .arg(QString::number(pos.y(), 'f', 2)) + .arg(QString::number(pos.z(), 'f', 2)); +} + +void TaskDetailsPage::onRefreshTasks() { + if (taskManager_) { + updateTaskTable(); + updateStatusDisplay(); + } +} + +void TaskDetailsPage::onFilterChanged() { + // 更新筛选条件 + int statusIndex = statusFilter_->currentIndex(); + currentStatusFilter_ = (statusIndex == 0) ? TaskStatus::Pending : static_cast(statusFilter_->currentData().toInt()); + + int droneIndex = droneFilter_->currentIndex(); + currentDroneFilter_ = (droneIndex == 0) ? "" : droneFilter_->currentText(); + + int typeIndex = typeFilter_->currentIndex(); + currentTypeFilter_ = (typeIndex == 0) ? TaskType::Patrol : static_cast(typeFilter_->currentData().toInt()); + + // 重新更新表格 + updateTaskTable(); +} + +void TaskDetailsPage::onTaskSelectionChanged() { + int currentRow = taskTable_->currentRow(); + if (currentRow >= 0) { + auto* item = taskTable_->item(currentRow, 0); + if (item) { + selectedTaskId_ = item->text(); + } + } else { + selectedTaskId_.clear(); + } + + updateStatusDisplay(); + updateControlButtons(); +} + +void TaskDetailsPage::onStartTaskClicked() { + if (selectedTaskId_.isEmpty()) { + QMessageBox::warning(this, "警告", "请先选择要开始的任务"); + return; + } + + if (taskManager_) { + taskManager_->startTask(selectedTaskId_); + emit taskActionRequested(selectedTaskId_, "start"); + } +} + +void TaskDetailsPage::onCompleteTaskClicked() { + if (selectedTaskId_.isEmpty()) { + QMessageBox::warning(this, "警告", "请先选择要完成的任务"); + return; + } + + if (taskManager_) { + taskManager_->completeTask(selectedTaskId_); + emit taskActionRequested(selectedTaskId_, "complete"); + } +} + +void TaskDetailsPage::onCancelTaskClicked() { + if (selectedTaskId_.isEmpty()) { + QMessageBox::warning(this, "警告", "请先选择要取消的任务"); + return; + } + + int ret = QMessageBox::question(this, "确认取消", + QString("确定要取消任务 %1 吗?").arg(selectedTaskId_), + QMessageBox::Yes | QMessageBox::No); + + if (ret == QMessageBox::Yes && taskManager_) { + taskManager_->cancelTask(selectedTaskId_); + emit taskActionRequested(selectedTaskId_, "cancel"); + } +} + +void TaskDetailsPage::onFailTaskClicked() { + if (selectedTaskId_.isEmpty()) { + QMessageBox::warning(this, "警告", "请先选择要标记失败的任务"); + return; + } + + bool ok; + QString reason = QInputDialog::getText(this, "任务失败", "请输入失败原因:", QLineEdit::Normal, "", &ok); + + if (ok && !reason.isEmpty() && taskManager_) { + taskManager_->failTask(selectedTaskId_, reason); + emit taskActionRequested(selectedTaskId_, "fail"); + } +} + +void TaskDetailsPage::onRecallTaskClicked() { + if (selectedTaskId_.isEmpty()) { + QMessageBox::warning(this, "警告", "请先选择要召回的任务"); + return; + } + + int ret = QMessageBox::question(this, "确认召回", + QString("确定要召回任务 %1 吗?").arg(selectedTaskId_), + QMessageBox::Yes | QMessageBox::No); + + if (ret == QMessageBox::Yes && taskManager_) { + taskManager_->recallTask(selectedTaskId_); + emit taskActionRequested(selectedTaskId_, "recall"); + } +} + +void TaskDetailsPage::onTaskStatusChanged(const QString& taskId, TaskStatus status) { + Q_UNUSED(taskId) + Q_UNUSED(status) + onTaskDataChanged(); +} + +void TaskDetailsPage::onTaskDataChanged() { + if (taskManager_) { + updateTaskTable(); + updateStatusDisplay(); + updateControlButtons(); + + // 更新无人机筛选列表 + if (droneManager_) { + droneFilter_->clear(); + droneFilter_->addItem("全部无人机", ""); + + auto drones = droneManager_->getAllDrones(); + for (auto* drone : drones) { + droneFilter_->addItem(QString("%1 (%2)").arg(drone->getName()).arg(drone->getId()), drone->getId()); + } + } + } +} diff --git a/Src/pages/taskdetailspage.h b/Src/pages/taskdetailspage.h new file mode 100755 index 0000000..4fae9e3 --- /dev/null +++ b/Src/pages/taskdetailspage.h @@ -0,0 +1,117 @@ +#ifndef TASKDETAILSPAGE_H +#define TASKDETAILSPAGE_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../pages/taskdata.h" +#include "../models/dronedata.h" + +/** + * 任务执行详情页面类 + * 负责展示所有任务的执行状态、进度和详细信息 + */ +class TaskDetailsPage : public QWidget { + Q_OBJECT + +public: + explicit TaskDetailsPage(QWidget* parent = nullptr); + ~TaskDetailsPage(); + + // 设置管理器 + void setTaskManager(TaskManager* taskManager); + void setDroneManager(DroneManager* droneManager); + +signals: + void taskActionRequested(const QString& taskId, const QString& action); + +private slots: + void onRefreshTasks(); + void onFilterChanged(); + void onTaskSelectionChanged(); + void onStartTaskClicked(); + void onCompleteTaskClicked(); + void onCancelTaskClicked(); + void onFailTaskClicked(); + void onRecallTaskClicked(); + void onTaskStatusChanged(const QString& taskId, TaskStatus status); + void onTaskDataChanged(); + +private: + void setupUI(); + void setupTaskTable(); + void setupControlPanel(); + void setupStatusPanel(); + void setupFilterPanel(); + void updateTaskTable(); + void updateStatusDisplay(); + void updateControlButtons(); + void addTaskToTable(TaskData* task); + void updateTaskRow(TaskData* task); + void removeTaskFromTable(const QString& taskId); + + // 获取状态颜色和图标 + QString getStatusColor(TaskStatus status) const; + QString getStatusIcon(TaskStatus status) const; + QString getTypeColor(TaskType type) const; + + // 格式化显示 + QString formatDateTime(const QDateTime& dateTime) const; + QString formatDuration(int seconds) const; + QString formatPosition(const QVector3D& pos) const; + + // UI组件 + QFrame* mainFrame_; + QTableWidget* taskTable_; + QGroupBox* filterGroup_; + QGroupBox* controlGroup_; + QGroupBox* statusGroup_; + + // 筛选面板组件 + QComboBox* statusFilter_; + QComboBox* droneFilter_; + QComboBox* typeFilter_; + QPushButton* clearFilterBtn_; + + // 控制面板组件 + QPushButton* startTaskBtn_; + QPushButton* completeTaskBtn_; + QPushButton* cancelTaskBtn_; + QPushButton* failTaskBtn_; + QPushButton* recallTaskBtn_; + QPushButton* refreshBtn_; + + // 状态显示组件 + QLabel* totalTasksLabel_; + QLabel* pendingTasksLabel_; + QLabel* inProgressTasksLabel_; + QLabel* completedTasksLabel_; + QLabel* failedTasksLabel_; + QLabel* cancelledTasksLabel_; + QLabel* recalledTasksLabel_; + QLabel* selectedTaskLabel_; + QProgressBar* progressBar_; + + // 数据管理 + TaskManager* taskManager_; + DroneManager* droneManager_; + QTimer* refreshTimer_; + QString selectedTaskId_; + + // 筛选条件 + TaskStatus currentStatusFilter_; + QString currentDroneFilter_; + TaskType currentTypeFilter_; +}; + +#endif // TASKDETAILSPAGE_H diff --git a/src/pages/videopage.cpp b/Src/pages/videopage.cpp similarity index 100% rename from src/pages/videopage.cpp rename to Src/pages/videopage.cpp diff --git a/src/pages/videopage.h b/Src/pages/videopage.h similarity index 100% rename from src/pages/videopage.h rename to Src/pages/videopage.h diff --git a/src/pages/visionmodelpage.cpp b/Src/pages/visionmodelpage.cpp similarity index 100% rename from src/pages/visionmodelpage.cpp rename to Src/pages/visionmodelpage.cpp diff --git a/src/pages/visionmodelpage.h b/Src/pages/visionmodelpage.h similarity index 100% rename from src/pages/visionmodelpage.h rename to Src/pages/visionmodelpage.h diff --git a/src/resources/app.qrc b/Src/resources/app.qrc similarity index 100% rename from src/resources/app.qrc rename to Src/resources/app.qrc diff --git a/src/ui/mainwindow.cpp b/Src/ui/mainwindow.cpp similarity index 97% rename from src/ui/mainwindow.cpp rename to Src/ui/mainwindow.cpp index 6cb0e96..bbe5f02 100644 --- a/src/ui/mainwindow.cpp +++ b/Src/ui/mainwindow.cpp @@ -26,6 +26,8 @@ // 添加TaskDecisionPage包含 #include "../pages/taskdecisionpage.h" +#include "../pages/dronemanagementpage.h" +#include "../pages/taskdetailspage.h" // 在文件顶部添加extern声明 // extern DroneManager* globalDroneManager; @@ -73,12 +75,16 @@ MainWindow::MainWindow(QWidget *parent) auto* pageMap = buildMapPage(); // 先地图 auto* pageVideo = buildVideoPage(); // 然后视频 auto* pageData = buildDataPage(); + auto* pageDroneMgmt = buildDroneManagementPage(); auto* pageTask = buildTaskDecisionPage(); // 新页面 + auto* pageTaskDetails = buildTaskDetailsPage(); auto* pageVision = buildVisionModelPage(); pages_->addWidget(pageMap); pages_->addWidget(pageVideo); pages_->addWidget(pageData); + pages_->addWidget(pageDroneMgmt); pages_->addWidget(pageTask); + pages_->addWidget(pageTaskDetails); pages_->addWidget(pageVision); // 右侧状态信息(两页共用静态占位) @@ -199,7 +205,9 @@ QWidget* MainWindow::buildSideNav() { makeBtn("视频监控", &MainWindow::showMapPage); // 显示原地图内容 makeBtn("地图监控", &MainWindow::showVideoPage); // 显示原视频内容 makeBtn("数据监控", &MainWindow::showDataPage); + makeBtn("无人机管理", &MainWindow::showDroneManagementPage); makeBtn("任务决策", &MainWindow::showTaskDecisionPage); + makeBtn("任务详情", &MainWindow::showTaskDetailsPage); makeBtn("视觉模型", &MainWindow::showVisionModelPage); v->addStretch(1); @@ -484,13 +492,27 @@ QWidget* MainWindow::buildRightStatusPanel() { void MainWindow::showVideoPage() { pages_->setCurrentIndex(0); } void MainWindow::showMapPage() { pages_->setCurrentIndex(1); } void MainWindow::showDataPage() { pages_->setCurrentIndex(2); } -void MainWindow::showTaskDecisionPage() { pages_->setCurrentIndex(3); } -void MainWindow::showVisionModelPage() { pages_->setCurrentIndex(4); } +void MainWindow::showDroneManagementPage() { pages_->setCurrentIndex(3); } +void MainWindow::showTaskDecisionPage() { pages_->setCurrentIndex(4); } +void MainWindow::showTaskDetailsPage() { pages_->setCurrentIndex(5); } +void MainWindow::showVisionModelPage() { pages_->setCurrentIndex(6); } QWidget* MainWindow::buildDataPage() { return new DataPage(this); // 使用DataPage类 } +QWidget* MainWindow::buildTaskDecisionPage() { + return new TaskDecisionPage(this); // 使用新类 +} + +QWidget* MainWindow::buildDroneManagementPage() { + return new DroneManagementPage(this); +} + +QWidget* MainWindow::buildTaskDetailsPage() { + return new TaskDetailsPage(this); +} + QWidget* MainWindow::buildVisionModelPage() { auto* page = new QWidget(this); auto* v = new QVBoxLayout(page); @@ -519,12 +541,6 @@ QWidget* MainWindow::buildVisionModelPage() { return page; } - -// 添加新页面构建函数(简单占位) -QWidget* MainWindow::buildTaskDecisionPage() { - return new TaskDecisionPage(this); // 使用新类 -} - // 初始化无人机数据 void MainWindow::initializeDrones() { // 添加4架无人机 diff --git a/src/ui/mainwindow.h b/Src/ui/mainwindow.h similarity index 90% rename from src/ui/mainwindow.h rename to Src/ui/mainwindow.h index 248137e..2436213 100644 --- a/src/ui/mainwindow.h +++ b/Src/ui/mainwindow.h @@ -13,8 +13,9 @@ #include "../pages/visionmodelpage.h" #include "../utils/stylehelper.h" -// 添加TaskDecisionPage包含 #include "../pages/taskdecisionpage.h" +#include "../pages/dronemanagementpage.h" +#include "../pages/taskdetailspage.h" class QStackedWidget; class QPushButton; @@ -39,6 +40,8 @@ private: QWidget* buildVisionModelPage(); // 视觉模型:顶部输入框 QWidget* buildRightStatusPanel(); // 右侧信息栏(两页共用) QWidget* buildTaskDecisionPage(); // 任务决策页面 + QWidget* buildDroneManagementPage(); // 无人机管理页面 + QWidget* buildTaskDetailsPage(); // 任务详情页面 void initializeDrones(); // 初始化无人机数据 private slots: @@ -47,6 +50,8 @@ private slots: void showDataPage(); void showVisionModelPage(); void showTaskDecisionPage(); + void showDroneManagementPage(); + void showTaskDetailsPage(); void onDroneSelectionChanged(); void onCurrentDroneChanged(const QString& droneId); void updateDroneStatus(); diff --git a/src/utils/config.cpp b/Src/utils/config.cpp similarity index 100% rename from src/utils/config.cpp rename to Src/utils/config.cpp diff --git a/src/utils/config.h b/Src/utils/config.h similarity index 100% rename from src/utils/config.h rename to Src/utils/config.h diff --git a/src/utils/errorhandler.cpp b/Src/utils/errorhandler.cpp similarity index 100% rename from src/utils/errorhandler.cpp rename to Src/utils/errorhandler.cpp diff --git a/src/utils/errorhandler.h b/Src/utils/errorhandler.h similarity index 100% rename from src/utils/errorhandler.h rename to Src/utils/errorhandler.h diff --git a/src/utils/logger.cpp b/Src/utils/logger.cpp similarity index 100% rename from src/utils/logger.cpp rename to Src/utils/logger.cpp diff --git a/src/utils/logger.h b/Src/utils/logger.h similarity index 100% rename from src/utils/logger.h rename to Src/utils/logger.h diff --git a/src/utils/stylehelper.cpp b/Src/utils/stylehelper.cpp similarity index 100% rename from src/utils/stylehelper.cpp rename to Src/utils/stylehelper.cpp diff --git a/src/utils/stylehelper.h b/Src/utils/stylehelper.h similarity index 100% rename from src/utils/stylehelper.h rename to Src/utils/stylehelper.h diff --git a/build.sh b/build.sh deleted file mode 100755 index 562e59e..0000000 --- a/build.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/bash - -# Drone_project项目构建脚本(shadow build,系统 qmake) - -echo "=== 构建Drone_project项目 ===" - -# 仅使用系统 qmake,确保团队环境一致 -if ! command -v qmake >/dev/null 2>&1; then - echo "✗ 未找到系统 qmake。请先安装:sudo apt install -y qtbase5-dev qtwebengine5-dev" - exit 1 -fi -QMAKE_BIN="qmake" -echo "使用 qmake: ${QMAKE_BIN} (from PATH)" - -# 准备构建目录(shadow build) -echo "1. 准备构建目录..." -mkdir -p build || exit 1 -rm -rf build/* - -# 进入构建目录并生成构建文件 -echo "2. 生成构建文件..." -( - cd build && "${QMAKE_BIN}" ../drone_ui.pro -) || { echo "✗ qmake 失败"; exit 1; } - -# 编译项目 -echo "3. 编译项目..." -( - cd build && make -j -) || { echo "✗ 编译失败"; exit 1; } - -# 检查编译结果 -if [ -f "build/Drone_project" ]; then - echo "✓ 编译成功!可执行文件位置: build/Drone_project" -else - echo "✗ 没找到可执行文件 build/Drone_project" - exit 1 -fi - -echo "=== 构建完成 ===" - - - diff --git a/build/.qmake.stash b/build/.qmake.stash index 42569a7..0d0b187 100644 --- a/build/.qmake.stash +++ b/build/.qmake.stash @@ -1,5 +1,5 @@ -QMAKE_CXX.QT_COMPILER_STDCXX = 201402L -QMAKE_CXX.QMAKE_GCC_MAJOR_VERSION = 9 +QMAKE_CXX.QT_COMPILER_STDCXX = 201703L +QMAKE_CXX.QMAKE_GCC_MAJOR_VERSION = 11 QMAKE_CXX.QMAKE_GCC_MINOR_VERSION = 4 QMAKE_CXX.QMAKE_GCC_PATCH_VERSION = 0 QMAKE_CXX.COMPILER_MACROS = \ @@ -8,15 +8,15 @@ QMAKE_CXX.COMPILER_MACROS = \ QMAKE_GCC_MINOR_VERSION \ QMAKE_GCC_PATCH_VERSION QMAKE_CXX.INCDIRS = \ - /usr/include/c++/9 \ - /usr/include/x86_64-linux-gnu/c++/9 \ - /usr/include/c++/9/backward \ - /usr/lib/gcc/x86_64-linux-gnu/9/include \ + /usr/include/c++/11 \ + /usr/include/x86_64-linux-gnu/c++/11 \ + /usr/include/c++/11/backward \ + /usr/lib/gcc/x86_64-linux-gnu/11/include \ /usr/local/include \ /usr/include/x86_64-linux-gnu \ /usr/include QMAKE_CXX.LIBDIRS = \ - /usr/lib/gcc/x86_64-linux-gnu/9 \ + /usr/lib/gcc/x86_64-linux-gnu/11 \ /usr/lib/x86_64-linux-gnu \ /usr/lib \ /lib/x86_64-linux-gnu \ diff --git a/build/Drone_project b/build/Drone_project index d9c457b..c67bd28 100755 Binary files a/build/Drone_project and b/build/Drone_project differ diff --git a/build/Makefile b/build/Makefile index c82beeb..6d5f084 100644 --- a/build/Makefile +++ b/build/Makefile @@ -37,7 +37,7 @@ MOVE = mv -f TAR = tar -cf COMPRESS = gzip -9f DISTNAME = Drone_project1.0.0 -DISTDIR = /home/wangjing/uav/Drone_project/build/.tmp/Drone_project1.0.0 +DISTDIR = /home/qinxinqi/桌面/Drone_project/build/.tmp/Drone_project1.0.0 LINK = g++ LFLAGS = -Wl,-O1 -Wl,-rpath-link,/usr/lib/x86_64-linux-gnu LIBS = $(SUBLIBS) /usr/lib/x86_64-linux-gnu/libQt5WebEngineWidgets.so /usr/lib/x86_64-linux-gnu/libQt5PrintSupport.so /usr/lib/x86_64-linux-gnu/libQt5Widgets.so /usr/lib/x86_64-linux-gnu/libQt5WebEngineCore.so /usr/lib/x86_64-linux-gnu/libQt5Quick.so /usr/lib/x86_64-linux-gnu/libQt5Gui.so /usr/lib/x86_64-linux-gnu/libQt5QmlModels.so /usr/lib/x86_64-linux-gnu/libQt5WebChannel.so /usr/lib/x86_64-linux-gnu/libQt5Qml.so /usr/lib/x86_64-linux-gnu/libQt5Network.so /usr/lib/x86_64-linux-gnu/libQt5Positioning.so /usr/lib/x86_64-linux-gnu/libQt5Core.so -lGL -lpthread @@ -52,37 +52,49 @@ OBJECTS_DIR = ./ ####### Files -SOURCES = ../src/core/main.cpp \ - ../src/ui/mainwindow.cpp \ - ../src/models/dronedata.cpp \ - ../src/models/detectiondata.cpp \ - ../src/pages/videopage.cpp \ - ../src/pages/mappage.cpp \ - ../src/pages/datapage.cpp \ - ../src/pages/visionmodelpage.cpp \ - ../src/utils/stylehelper.cpp \ - ../src/pages/taskdecisionpage.cpp \ - ../src/utils/config.cpp \ - ../src/utils/logger.cpp \ - ../src/utils/errorhandler.cpp qrc_app.cpp \ +SOURCES = ../Src/core/main.cpp \ + ../Src/ui/mainwindow.cpp \ + ../Src/models/dronedata.cpp \ + ../Src/models/detectiondata.cpp \ + ../Src/pages/videopage.cpp \ + ../Src/pages/mappage.cpp \ + ../Src/pages/mapbridge.cpp \ + ../Src/pages/datapage.cpp \ + ../Src/pages/taskdata.cpp \ + ../Src/pages/visionmodelpage.cpp \ + ../Src/utils/stylehelper.cpp \ + ../Src/pages/taskdecisionpage.cpp \ + ../Src/pages/dronemanagementpage.cpp \ + ../Src/pages/taskdetailspage.cpp \ + ../Src/utils/config.cpp \ + ../Src/utils/logger.cpp \ + ../Src/utils/errorhandler.cpp qrc_app.cpp \ moc_mainwindow.cpp \ moc_dronedata.cpp \ moc_detectiondata.cpp \ moc_videopage.cpp \ moc_mappage.cpp \ + moc_mapbridge.cpp \ moc_datapage.cpp \ + moc_taskdata.cpp \ moc_visionmodelpage.cpp \ - moc_taskdecisionpage.cpp + moc_taskdecisionpage.cpp \ + moc_dronemanagementpage.cpp \ + moc_taskdetailspage.cpp OBJECTS = main.o \ mainwindow.o \ dronedata.o \ detectiondata.o \ videopage.o \ mappage.o \ + mapbridge.o \ datapage.o \ + taskdata.o \ visionmodelpage.o \ stylehelper.o \ taskdecisionpage.o \ + dronemanagementpage.o \ + taskdetailspage.o \ config.o \ logger.o \ errorhandler.o \ @@ -92,9 +104,13 @@ OBJECTS = main.o \ moc_detectiondata.o \ moc_videopage.o \ moc_mappage.o \ + moc_mapbridge.o \ moc_datapage.o \ + moc_taskdata.o \ moc_visionmodelpage.o \ - moc_taskdecisionpage.o + moc_taskdecisionpage.o \ + moc_dronemanagementpage.o \ + moc_taskdetailspage.o DIST = /usr/lib/x86_64-linux-gnu/qt5/mkspecs/features/spec_pre.prf \ /usr/lib/x86_64-linux-gnu/qt5/mkspecs/common/unix.conf \ /usr/lib/x86_64-linux-gnu/qt5/mkspecs/common/linux.conf \ @@ -184,30 +200,38 @@ DIST = /usr/lib/x86_64-linux-gnu/qt5/mkspecs/features/spec_pre.prf \ /usr/lib/x86_64-linux-gnu/qt5/mkspecs/features/exceptions.prf \ /usr/lib/x86_64-linux-gnu/qt5/mkspecs/features/yacc.prf \ /usr/lib/x86_64-linux-gnu/qt5/mkspecs/features/lex.prf \ - ../../drone_ui.pro ../src/ui/mainwindow.h \ - ../src/models/dronedata.h \ - ../src/models/detectiondata.h \ - ../src/pages/videopage.h \ - ../src/pages/mappage.h \ - ../src/pages/datapage.h \ - ../src/pages/visionmodelpage.h \ - ../src/utils/stylehelper.h \ - ../src/pages/taskdecisionpage.h \ - ../src/utils/config.h \ - ../src/utils/logger.h \ - ../src/utils/errorhandler.h ../src/core/main.cpp \ - ../src/ui/mainwindow.cpp \ - ../src/models/dronedata.cpp \ - ../src/models/detectiondata.cpp \ - ../src/pages/videopage.cpp \ - ../src/pages/mappage.cpp \ - ../src/pages/datapage.cpp \ - ../src/pages/visionmodelpage.cpp \ - ../src/utils/stylehelper.cpp \ - ../src/pages/taskdecisionpage.cpp \ - ../src/utils/config.cpp \ - ../src/utils/logger.cpp \ - ../src/utils/errorhandler.cpp + ../../drone_ui.pro ../Src/ui/mainwindow.h \ + ../Src/models/dronedata.h \ + ../Src/models/detectiondata.h \ + ../Src/pages/videopage.h \ + ../Src/pages/mappage.h \ + ../Src/pages/mapbridge.h \ + ../Src/pages/datapage.h \ + ../Src/pages/taskdata.h \ + ../Src/pages/visionmodelpage.h \ + ../Src/utils/stylehelper.h \ + ../Src/pages/taskdecisionpage.h \ + ../Src/pages/dronemanagementpage.h \ + ../Src/pages/taskdetailspage.h \ + ../Src/utils/config.h \ + ../Src/utils/logger.h \ + ../Src/utils/errorhandler.h ../Src/core/main.cpp \ + ../Src/ui/mainwindow.cpp \ + ../Src/models/dronedata.cpp \ + ../Src/models/detectiondata.cpp \ + ../Src/pages/videopage.cpp \ + ../Src/pages/mappage.cpp \ + ../Src/pages/mapbridge.cpp \ + ../Src/pages/datapage.cpp \ + ../Src/pages/taskdata.cpp \ + ../Src/pages/visionmodelpage.cpp \ + ../Src/utils/stylehelper.cpp \ + ../Src/pages/taskdecisionpage.cpp \ + ../Src/pages/dronemanagementpage.cpp \ + ../Src/pages/taskdetailspage.cpp \ + ../Src/utils/config.cpp \ + ../Src/utils/logger.cpp \ + ../Src/utils/errorhandler.cpp QMAKE_TARGET = Drone_project DESTDIR = TARGET = Drone_project @@ -309,7 +333,7 @@ Makefile: ../drone_ui.pro /usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++/qmake. /usr/lib/x86_64-linux-gnu/qt5/mkspecs/features/yacc.prf \ /usr/lib/x86_64-linux-gnu/qt5/mkspecs/features/lex.prf \ ../drone_ui.pro \ - ../src/resources/app.qrc + ../Src/resources/app.qrc $(QMAKE) -o Makefile ../drone_ui.pro /usr/lib/x86_64-linux-gnu/qt5/mkspecs/features/spec_pre.prf: /usr/lib/x86_64-linux-gnu/qt5/mkspecs/common/unix.conf: @@ -401,7 +425,7 @@ Makefile: ../drone_ui.pro /usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++/qmake. /usr/lib/x86_64-linux-gnu/qt5/mkspecs/features/yacc.prf: /usr/lib/x86_64-linux-gnu/qt5/mkspecs/features/lex.prf: ../drone_ui.pro: -../src/resources/app.qrc: +../Src/resources/app.qrc: qmake: FORCE @$(QMAKE) -o Makefile ../drone_ui.pro @@ -416,10 +440,10 @@ dist: distdir FORCE distdir: FORCE @test -d $(DISTDIR) || mkdir -p $(DISTDIR) $(COPY_FILE) --parents $(DIST) $(DISTDIR)/ - $(COPY_FILE) --parents ../src/resources/app.qrc $(DISTDIR)/ + $(COPY_FILE) --parents ../Src/resources/app.qrc $(DISTDIR)/ $(COPY_FILE) --parents /usr/lib/x86_64-linux-gnu/qt5/mkspecs/features/data/dummy.cpp $(DISTDIR)/ - $(COPY_FILE) --parents ../src/ui/mainwindow.h ../src/models/dronedata.h ../src/models/detectiondata.h ../src/pages/videopage.h ../src/pages/mappage.h ../src/pages/datapage.h ../src/pages/visionmodelpage.h ../src/utils/stylehelper.h ../src/pages/taskdecisionpage.h ../src/utils/config.h ../src/utils/logger.h ../src/utils/errorhandler.h $(DISTDIR)/ - $(COPY_FILE) --parents ../src/core/main.cpp ../src/ui/mainwindow.cpp ../src/models/dronedata.cpp ../src/models/detectiondata.cpp ../src/pages/videopage.cpp ../src/pages/mappage.cpp ../src/pages/datapage.cpp ../src/pages/visionmodelpage.cpp ../src/utils/stylehelper.cpp ../src/pages/taskdecisionpage.cpp ../src/utils/config.cpp ../src/utils/logger.cpp ../src/utils/errorhandler.cpp $(DISTDIR)/ + $(COPY_FILE) --parents ../Src/ui/mainwindow.h ../Src/models/dronedata.h ../Src/models/detectiondata.h ../Src/pages/videopage.h ../Src/pages/mappage.h ../Src/pages/mapbridge.h ../Src/pages/datapage.h ../Src/pages/taskdata.h ../Src/pages/visionmodelpage.h ../Src/utils/stylehelper.h ../Src/pages/taskdecisionpage.h ../Src/pages/dronemanagementpage.h ../Src/pages/taskdetailspage.h ../Src/utils/config.h ../Src/utils/logger.h ../Src/utils/errorhandler.h $(DISTDIR)/ + $(COPY_FILE) --parents ../Src/core/main.cpp ../Src/ui/mainwindow.cpp ../Src/models/dronedata.cpp ../Src/models/detectiondata.cpp ../Src/pages/videopage.cpp ../Src/pages/mappage.cpp ../Src/pages/mapbridge.cpp ../Src/pages/datapage.cpp ../Src/pages/taskdata.cpp ../Src/pages/visionmodelpage.cpp ../Src/utils/stylehelper.cpp ../Src/pages/taskdecisionpage.cpp ../Src/pages/dronemanagementpage.cpp ../Src/pages/taskdetailspage.cpp ../Src/utils/config.cpp ../Src/utils/logger.cpp ../Src/utils/errorhandler.cpp $(DISTDIR)/ clean: compiler_clean @@ -446,9 +470,9 @@ benchmark: first compiler_rcc_make_all: qrc_app.cpp compiler_rcc_clean: -$(DEL_FILE) qrc_app.cpp -qrc_app.cpp: ../src/resources/app.qrc \ +qrc_app.cpp: ../Src/resources/app.qrc \ /usr/lib/qt5/bin/rcc - /usr/lib/qt5/bin/rcc -name app ../src/resources/app.qrc -o qrc_app.cpp + /usr/lib/qt5/bin/rcc -name app ../Src/resources/app.qrc -o qrc_app.cpp compiler_moc_predefs_make_all: moc_predefs.h compiler_moc_predefs_clean: @@ -456,55 +480,80 @@ compiler_moc_predefs_clean: moc_predefs.h: /usr/lib/x86_64-linux-gnu/qt5/mkspecs/features/data/dummy.cpp g++ -pipe -O2 -std=gnu++1z -Wall -Wextra -dM -E -o moc_predefs.h /usr/lib/x86_64-linux-gnu/qt5/mkspecs/features/data/dummy.cpp -compiler_moc_header_make_all: moc_mainwindow.cpp moc_dronedata.cpp moc_detectiondata.cpp moc_videopage.cpp moc_mappage.cpp moc_datapage.cpp moc_visionmodelpage.cpp moc_taskdecisionpage.cpp +compiler_moc_header_make_all: moc_mainwindow.cpp moc_dronedata.cpp moc_detectiondata.cpp moc_videopage.cpp moc_mappage.cpp moc_mapbridge.cpp moc_datapage.cpp moc_taskdata.cpp moc_visionmodelpage.cpp moc_taskdecisionpage.cpp moc_dronemanagementpage.cpp moc_taskdetailspage.cpp compiler_moc_header_clean: - -$(DEL_FILE) moc_mainwindow.cpp moc_dronedata.cpp moc_detectiondata.cpp moc_videopage.cpp moc_mappage.cpp moc_datapage.cpp moc_visionmodelpage.cpp moc_taskdecisionpage.cpp -moc_mainwindow.cpp: ../src/ui/mainwindow.h \ - ../src/models/dronedata.h \ - ../src/models/detectiondata.h \ - ../src/pages/visionmodelpage.h \ - ../src/utils/stylehelper.h \ - ../src/pages/taskdecisionpage.h \ - ../src/pages/mappage.h \ + -$(DEL_FILE) moc_mainwindow.cpp moc_dronedata.cpp moc_detectiondata.cpp moc_videopage.cpp moc_mappage.cpp moc_mapbridge.cpp moc_datapage.cpp moc_taskdata.cpp moc_visionmodelpage.cpp moc_taskdecisionpage.cpp moc_dronemanagementpage.cpp moc_taskdetailspage.cpp +moc_mainwindow.cpp: ../Src/ui/mainwindow.h \ + ../Src/models/dronedata.h \ + ../Src/models/detectiondata.h \ + ../Src/pages/visionmodelpage.h \ + ../Src/utils/stylehelper.h \ + ../Src/pages/taskdecisionpage.h \ + ../Src/pages/dronemanagementpage.h \ + ../Src/pages/taskdetailspage.h \ + ../Src/pages/taskdata.h \ moc_predefs.h \ /usr/lib/qt5/bin/moc - /usr/lib/qt5/bin/moc $(DEFINES) --include /home/wangjing/uav/Drone_project/build/moc_predefs.h -I/usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++ -I/home/wangjing/uav/Drone_project -I/usr/include/x86_64-linux-gnu/qt5 -I/usr/include/x86_64-linux-gnu/qt5/QtWebEngineWidgets -I/usr/include/x86_64-linux-gnu/qt5/QtPrintSupport -I/usr/include/x86_64-linux-gnu/qt5/QtWidgets -I/usr/include/x86_64-linux-gnu/qt5/QtWebEngineCore -I/usr/include/x86_64-linux-gnu/qt5/QtQuick -I/usr/include/x86_64-linux-gnu/qt5/QtGui -I/usr/include/x86_64-linux-gnu/qt5/QtQmlModels -I/usr/include/x86_64-linux-gnu/qt5/QtWebChannel -I/usr/include/x86_64-linux-gnu/qt5/QtQml -I/usr/include/x86_64-linux-gnu/qt5/QtNetwork -I/usr/include/x86_64-linux-gnu/qt5/QtPositioning -I/usr/include/x86_64-linux-gnu/qt5/QtCore -I. -I/usr/include/c++/9 -I/usr/include/x86_64-linux-gnu/c++/9 -I/usr/include/c++/9/backward -I/usr/lib/gcc/x86_64-linux-gnu/9/include -I/usr/local/include -I/usr/include/x86_64-linux-gnu -I/usr/include ../src/ui/mainwindow.h -o moc_mainwindow.cpp + /usr/lib/qt5/bin/moc $(DEFINES) --include /home/qinxinqi/桌面/Drone_project/build/moc_predefs.h -I/usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++ -I/home/qinxinqi/桌面/Drone_project -I/usr/include/x86_64-linux-gnu/qt5 -I/usr/include/x86_64-linux-gnu/qt5/QtWebEngineWidgets -I/usr/include/x86_64-linux-gnu/qt5/QtPrintSupport -I/usr/include/x86_64-linux-gnu/qt5/QtWidgets -I/usr/include/x86_64-linux-gnu/qt5/QtWebEngineCore -I/usr/include/x86_64-linux-gnu/qt5/QtQuick -I/usr/include/x86_64-linux-gnu/qt5/QtGui -I/usr/include/x86_64-linux-gnu/qt5/QtQmlModels -I/usr/include/x86_64-linux-gnu/qt5/QtWebChannel -I/usr/include/x86_64-linux-gnu/qt5/QtQml -I/usr/include/x86_64-linux-gnu/qt5/QtNetwork -I/usr/include/x86_64-linux-gnu/qt5/QtPositioning -I/usr/include/x86_64-linux-gnu/qt5/QtCore -I. -I/usr/include/c++/11 -I/usr/include/x86_64-linux-gnu/c++/11 -I/usr/include/c++/11/backward -I/usr/lib/gcc/x86_64-linux-gnu/11/include -I/usr/local/include -I/usr/include/x86_64-linux-gnu -I/usr/include ../Src/ui/mainwindow.h -o moc_mainwindow.cpp -moc_dronedata.cpp: ../src/models/dronedata.h \ +moc_dronedata.cpp: ../Src/models/dronedata.h \ moc_predefs.h \ /usr/lib/qt5/bin/moc - /usr/lib/qt5/bin/moc $(DEFINES) --include /home/wangjing/uav/Drone_project/build/moc_predefs.h -I/usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++ -I/home/wangjing/uav/Drone_project -I/usr/include/x86_64-linux-gnu/qt5 -I/usr/include/x86_64-linux-gnu/qt5/QtWebEngineWidgets -I/usr/include/x86_64-linux-gnu/qt5/QtPrintSupport -I/usr/include/x86_64-linux-gnu/qt5/QtWidgets -I/usr/include/x86_64-linux-gnu/qt5/QtWebEngineCore -I/usr/include/x86_64-linux-gnu/qt5/QtQuick -I/usr/include/x86_64-linux-gnu/qt5/QtGui -I/usr/include/x86_64-linux-gnu/qt5/QtQmlModels -I/usr/include/x86_64-linux-gnu/qt5/QtWebChannel -I/usr/include/x86_64-linux-gnu/qt5/QtQml -I/usr/include/x86_64-linux-gnu/qt5/QtNetwork -I/usr/include/x86_64-linux-gnu/qt5/QtPositioning -I/usr/include/x86_64-linux-gnu/qt5/QtCore -I. -I/usr/include/c++/9 -I/usr/include/x86_64-linux-gnu/c++/9 -I/usr/include/c++/9/backward -I/usr/lib/gcc/x86_64-linux-gnu/9/include -I/usr/local/include -I/usr/include/x86_64-linux-gnu -I/usr/include ../src/models/dronedata.h -o moc_dronedata.cpp + /usr/lib/qt5/bin/moc $(DEFINES) --include /home/qinxinqi/桌面/Drone_project/build/moc_predefs.h -I/usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++ -I/home/qinxinqi/桌面/Drone_project -I/usr/include/x86_64-linux-gnu/qt5 -I/usr/include/x86_64-linux-gnu/qt5/QtWebEngineWidgets -I/usr/include/x86_64-linux-gnu/qt5/QtPrintSupport -I/usr/include/x86_64-linux-gnu/qt5/QtWidgets -I/usr/include/x86_64-linux-gnu/qt5/QtWebEngineCore -I/usr/include/x86_64-linux-gnu/qt5/QtQuick -I/usr/include/x86_64-linux-gnu/qt5/QtGui -I/usr/include/x86_64-linux-gnu/qt5/QtQmlModels -I/usr/include/x86_64-linux-gnu/qt5/QtWebChannel -I/usr/include/x86_64-linux-gnu/qt5/QtQml -I/usr/include/x86_64-linux-gnu/qt5/QtNetwork -I/usr/include/x86_64-linux-gnu/qt5/QtPositioning -I/usr/include/x86_64-linux-gnu/qt5/QtCore -I. -I/usr/include/c++/11 -I/usr/include/x86_64-linux-gnu/c++/11 -I/usr/include/c++/11/backward -I/usr/lib/gcc/x86_64-linux-gnu/11/include -I/usr/local/include -I/usr/include/x86_64-linux-gnu -I/usr/include ../Src/models/dronedata.h -o moc_dronedata.cpp -moc_detectiondata.cpp: ../src/models/detectiondata.h \ +moc_detectiondata.cpp: ../Src/models/detectiondata.h \ moc_predefs.h \ /usr/lib/qt5/bin/moc - /usr/lib/qt5/bin/moc $(DEFINES) --include /home/wangjing/uav/Drone_project/build/moc_predefs.h -I/usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++ -I/home/wangjing/uav/Drone_project -I/usr/include/x86_64-linux-gnu/qt5 -I/usr/include/x86_64-linux-gnu/qt5/QtWebEngineWidgets -I/usr/include/x86_64-linux-gnu/qt5/QtPrintSupport -I/usr/include/x86_64-linux-gnu/qt5/QtWidgets -I/usr/include/x86_64-linux-gnu/qt5/QtWebEngineCore -I/usr/include/x86_64-linux-gnu/qt5/QtQuick -I/usr/include/x86_64-linux-gnu/qt5/QtGui -I/usr/include/x86_64-linux-gnu/qt5/QtQmlModels -I/usr/include/x86_64-linux-gnu/qt5/QtWebChannel -I/usr/include/x86_64-linux-gnu/qt5/QtQml -I/usr/include/x86_64-linux-gnu/qt5/QtNetwork -I/usr/include/x86_64-linux-gnu/qt5/QtPositioning -I/usr/include/x86_64-linux-gnu/qt5/QtCore -I. -I/usr/include/c++/9 -I/usr/include/x86_64-linux-gnu/c++/9 -I/usr/include/c++/9/backward -I/usr/lib/gcc/x86_64-linux-gnu/9/include -I/usr/local/include -I/usr/include/x86_64-linux-gnu -I/usr/include ../src/models/detectiondata.h -o moc_detectiondata.cpp + /usr/lib/qt5/bin/moc $(DEFINES) --include /home/qinxinqi/桌面/Drone_project/build/moc_predefs.h -I/usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++ -I/home/qinxinqi/桌面/Drone_project -I/usr/include/x86_64-linux-gnu/qt5 -I/usr/include/x86_64-linux-gnu/qt5/QtWebEngineWidgets -I/usr/include/x86_64-linux-gnu/qt5/QtPrintSupport -I/usr/include/x86_64-linux-gnu/qt5/QtWidgets -I/usr/include/x86_64-linux-gnu/qt5/QtWebEngineCore -I/usr/include/x86_64-linux-gnu/qt5/QtQuick -I/usr/include/x86_64-linux-gnu/qt5/QtGui -I/usr/include/x86_64-linux-gnu/qt5/QtQmlModels -I/usr/include/x86_64-linux-gnu/qt5/QtWebChannel -I/usr/include/x86_64-linux-gnu/qt5/QtQml -I/usr/include/x86_64-linux-gnu/qt5/QtNetwork -I/usr/include/x86_64-linux-gnu/qt5/QtPositioning -I/usr/include/x86_64-linux-gnu/qt5/QtCore -I. -I/usr/include/c++/11 -I/usr/include/x86_64-linux-gnu/c++/11 -I/usr/include/c++/11/backward -I/usr/lib/gcc/x86_64-linux-gnu/11/include -I/usr/local/include -I/usr/include/x86_64-linux-gnu -I/usr/include ../Src/models/detectiondata.h -o moc_detectiondata.cpp -moc_videopage.cpp: ../src/pages/videopage.h \ +moc_videopage.cpp: ../Src/pages/videopage.h \ moc_predefs.h \ /usr/lib/qt5/bin/moc - /usr/lib/qt5/bin/moc $(DEFINES) --include /home/wangjing/uav/Drone_project/build/moc_predefs.h -I/usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++ -I/home/wangjing/uav/Drone_project -I/usr/include/x86_64-linux-gnu/qt5 -I/usr/include/x86_64-linux-gnu/qt5/QtWebEngineWidgets -I/usr/include/x86_64-linux-gnu/qt5/QtPrintSupport -I/usr/include/x86_64-linux-gnu/qt5/QtWidgets -I/usr/include/x86_64-linux-gnu/qt5/QtWebEngineCore -I/usr/include/x86_64-linux-gnu/qt5/QtQuick -I/usr/include/x86_64-linux-gnu/qt5/QtGui -I/usr/include/x86_64-linux-gnu/qt5/QtQmlModels -I/usr/include/x86_64-linux-gnu/qt5/QtWebChannel -I/usr/include/x86_64-linux-gnu/qt5/QtQml -I/usr/include/x86_64-linux-gnu/qt5/QtNetwork -I/usr/include/x86_64-linux-gnu/qt5/QtPositioning -I/usr/include/x86_64-linux-gnu/qt5/QtCore -I. -I/usr/include/c++/9 -I/usr/include/x86_64-linux-gnu/c++/9 -I/usr/include/c++/9/backward -I/usr/lib/gcc/x86_64-linux-gnu/9/include -I/usr/local/include -I/usr/include/x86_64-linux-gnu -I/usr/include ../src/pages/videopage.h -o moc_videopage.cpp + /usr/lib/qt5/bin/moc $(DEFINES) --include /home/qinxinqi/桌面/Drone_project/build/moc_predefs.h -I/usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++ -I/home/qinxinqi/桌面/Drone_project -I/usr/include/x86_64-linux-gnu/qt5 -I/usr/include/x86_64-linux-gnu/qt5/QtWebEngineWidgets -I/usr/include/x86_64-linux-gnu/qt5/QtPrintSupport -I/usr/include/x86_64-linux-gnu/qt5/QtWidgets -I/usr/include/x86_64-linux-gnu/qt5/QtWebEngineCore -I/usr/include/x86_64-linux-gnu/qt5/QtQuick -I/usr/include/x86_64-linux-gnu/qt5/QtGui -I/usr/include/x86_64-linux-gnu/qt5/QtQmlModels -I/usr/include/x86_64-linux-gnu/qt5/QtWebChannel -I/usr/include/x86_64-linux-gnu/qt5/QtQml -I/usr/include/x86_64-linux-gnu/qt5/QtNetwork -I/usr/include/x86_64-linux-gnu/qt5/QtPositioning -I/usr/include/x86_64-linux-gnu/qt5/QtCore -I. -I/usr/include/c++/11 -I/usr/include/x86_64-linux-gnu/c++/11 -I/usr/include/c++/11/backward -I/usr/lib/gcc/x86_64-linux-gnu/11/include -I/usr/local/include -I/usr/include/x86_64-linux-gnu -I/usr/include ../Src/pages/videopage.h -o moc_videopage.cpp -moc_mappage.cpp: ../src/pages/mappage.h \ +moc_mappage.cpp: ../Src/pages/mappage.h \ + ../Src/pages/mapbridge.h \ moc_predefs.h \ /usr/lib/qt5/bin/moc - /usr/lib/qt5/bin/moc $(DEFINES) --include /home/wangjing/uav/Drone_project/build/moc_predefs.h -I/usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++ -I/home/wangjing/uav/Drone_project -I/usr/include/x86_64-linux-gnu/qt5 -I/usr/include/x86_64-linux-gnu/qt5/QtWebEngineWidgets -I/usr/include/x86_64-linux-gnu/qt5/QtPrintSupport -I/usr/include/x86_64-linux-gnu/qt5/QtWidgets -I/usr/include/x86_64-linux-gnu/qt5/QtWebEngineCore -I/usr/include/x86_64-linux-gnu/qt5/QtQuick -I/usr/include/x86_64-linux-gnu/qt5/QtGui -I/usr/include/x86_64-linux-gnu/qt5/QtQmlModels -I/usr/include/x86_64-linux-gnu/qt5/QtWebChannel -I/usr/include/x86_64-linux-gnu/qt5/QtQml -I/usr/include/x86_64-linux-gnu/qt5/QtNetwork -I/usr/include/x86_64-linux-gnu/qt5/QtPositioning -I/usr/include/x86_64-linux-gnu/qt5/QtCore -I. -I/usr/include/c++/9 -I/usr/include/x86_64-linux-gnu/c++/9 -I/usr/include/c++/9/backward -I/usr/lib/gcc/x86_64-linux-gnu/9/include -I/usr/local/include -I/usr/include/x86_64-linux-gnu -I/usr/include ../src/pages/mappage.h -o moc_mappage.cpp + /usr/lib/qt5/bin/moc $(DEFINES) --include /home/qinxinqi/桌面/Drone_project/build/moc_predefs.h -I/usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++ -I/home/qinxinqi/桌面/Drone_project -I/usr/include/x86_64-linux-gnu/qt5 -I/usr/include/x86_64-linux-gnu/qt5/QtWebEngineWidgets -I/usr/include/x86_64-linux-gnu/qt5/QtPrintSupport -I/usr/include/x86_64-linux-gnu/qt5/QtWidgets -I/usr/include/x86_64-linux-gnu/qt5/QtWebEngineCore -I/usr/include/x86_64-linux-gnu/qt5/QtQuick -I/usr/include/x86_64-linux-gnu/qt5/QtGui -I/usr/include/x86_64-linux-gnu/qt5/QtQmlModels -I/usr/include/x86_64-linux-gnu/qt5/QtWebChannel -I/usr/include/x86_64-linux-gnu/qt5/QtQml -I/usr/include/x86_64-linux-gnu/qt5/QtNetwork -I/usr/include/x86_64-linux-gnu/qt5/QtPositioning -I/usr/include/x86_64-linux-gnu/qt5/QtCore -I. -I/usr/include/c++/11 -I/usr/include/x86_64-linux-gnu/c++/11 -I/usr/include/c++/11/backward -I/usr/lib/gcc/x86_64-linux-gnu/11/include -I/usr/local/include -I/usr/include/x86_64-linux-gnu -I/usr/include ../Src/pages/mappage.h -o moc_mappage.cpp -moc_datapage.cpp: ../src/pages/datapage.h \ +moc_mapbridge.cpp: ../Src/pages/mapbridge.h \ moc_predefs.h \ /usr/lib/qt5/bin/moc - /usr/lib/qt5/bin/moc $(DEFINES) --include /home/wangjing/uav/Drone_project/build/moc_predefs.h -I/usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++ -I/home/wangjing/uav/Drone_project -I/usr/include/x86_64-linux-gnu/qt5 -I/usr/include/x86_64-linux-gnu/qt5/QtWebEngineWidgets -I/usr/include/x86_64-linux-gnu/qt5/QtPrintSupport -I/usr/include/x86_64-linux-gnu/qt5/QtWidgets -I/usr/include/x86_64-linux-gnu/qt5/QtWebEngineCore -I/usr/include/x86_64-linux-gnu/qt5/QtQuick -I/usr/include/x86_64-linux-gnu/qt5/QtGui -I/usr/include/x86_64-linux-gnu/qt5/QtQmlModels -I/usr/include/x86_64-linux-gnu/qt5/QtWebChannel -I/usr/include/x86_64-linux-gnu/qt5/QtQml -I/usr/include/x86_64-linux-gnu/qt5/QtNetwork -I/usr/include/x86_64-linux-gnu/qt5/QtPositioning -I/usr/include/x86_64-linux-gnu/qt5/QtCore -I. -I/usr/include/c++/9 -I/usr/include/x86_64-linux-gnu/c++/9 -I/usr/include/c++/9/backward -I/usr/lib/gcc/x86_64-linux-gnu/9/include -I/usr/local/include -I/usr/include/x86_64-linux-gnu -I/usr/include ../src/pages/datapage.h -o moc_datapage.cpp + /usr/lib/qt5/bin/moc $(DEFINES) --include /home/qinxinqi/桌面/Drone_project/build/moc_predefs.h -I/usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++ -I/home/qinxinqi/桌面/Drone_project -I/usr/include/x86_64-linux-gnu/qt5 -I/usr/include/x86_64-linux-gnu/qt5/QtWebEngineWidgets -I/usr/include/x86_64-linux-gnu/qt5/QtPrintSupport -I/usr/include/x86_64-linux-gnu/qt5/QtWidgets -I/usr/include/x86_64-linux-gnu/qt5/QtWebEngineCore -I/usr/include/x86_64-linux-gnu/qt5/QtQuick -I/usr/include/x86_64-linux-gnu/qt5/QtGui -I/usr/include/x86_64-linux-gnu/qt5/QtQmlModels -I/usr/include/x86_64-linux-gnu/qt5/QtWebChannel -I/usr/include/x86_64-linux-gnu/qt5/QtQml -I/usr/include/x86_64-linux-gnu/qt5/QtNetwork -I/usr/include/x86_64-linux-gnu/qt5/QtPositioning -I/usr/include/x86_64-linux-gnu/qt5/QtCore -I. -I/usr/include/c++/11 -I/usr/include/x86_64-linux-gnu/c++/11 -I/usr/include/c++/11/backward -I/usr/lib/gcc/x86_64-linux-gnu/11/include -I/usr/local/include -I/usr/include/x86_64-linux-gnu -I/usr/include ../Src/pages/mapbridge.h -o moc_mapbridge.cpp -moc_visionmodelpage.cpp: ../src/pages/visionmodelpage.h \ +moc_datapage.cpp: ../Src/pages/datapage.h \ moc_predefs.h \ /usr/lib/qt5/bin/moc - /usr/lib/qt5/bin/moc $(DEFINES) --include /home/wangjing/uav/Drone_project/build/moc_predefs.h -I/usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++ -I/home/wangjing/uav/Drone_project -I/usr/include/x86_64-linux-gnu/qt5 -I/usr/include/x86_64-linux-gnu/qt5/QtWebEngineWidgets -I/usr/include/x86_64-linux-gnu/qt5/QtPrintSupport -I/usr/include/x86_64-linux-gnu/qt5/QtWidgets -I/usr/include/x86_64-linux-gnu/qt5/QtWebEngineCore -I/usr/include/x86_64-linux-gnu/qt5/QtQuick -I/usr/include/x86_64-linux-gnu/qt5/QtGui -I/usr/include/x86_64-linux-gnu/qt5/QtQmlModels -I/usr/include/x86_64-linux-gnu/qt5/QtWebChannel -I/usr/include/x86_64-linux-gnu/qt5/QtQml -I/usr/include/x86_64-linux-gnu/qt5/QtNetwork -I/usr/include/x86_64-linux-gnu/qt5/QtPositioning -I/usr/include/x86_64-linux-gnu/qt5/QtCore -I. -I/usr/include/c++/9 -I/usr/include/x86_64-linux-gnu/c++/9 -I/usr/include/c++/9/backward -I/usr/lib/gcc/x86_64-linux-gnu/9/include -I/usr/local/include -I/usr/include/x86_64-linux-gnu -I/usr/include ../src/pages/visionmodelpage.h -o moc_visionmodelpage.cpp + /usr/lib/qt5/bin/moc $(DEFINES) --include /home/qinxinqi/桌面/Drone_project/build/moc_predefs.h -I/usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++ -I/home/qinxinqi/桌面/Drone_project -I/usr/include/x86_64-linux-gnu/qt5 -I/usr/include/x86_64-linux-gnu/qt5/QtWebEngineWidgets -I/usr/include/x86_64-linux-gnu/qt5/QtPrintSupport -I/usr/include/x86_64-linux-gnu/qt5/QtWidgets -I/usr/include/x86_64-linux-gnu/qt5/QtWebEngineCore -I/usr/include/x86_64-linux-gnu/qt5/QtQuick -I/usr/include/x86_64-linux-gnu/qt5/QtGui -I/usr/include/x86_64-linux-gnu/qt5/QtQmlModels -I/usr/include/x86_64-linux-gnu/qt5/QtWebChannel -I/usr/include/x86_64-linux-gnu/qt5/QtQml -I/usr/include/x86_64-linux-gnu/qt5/QtNetwork -I/usr/include/x86_64-linux-gnu/qt5/QtPositioning -I/usr/include/x86_64-linux-gnu/qt5/QtCore -I. -I/usr/include/c++/11 -I/usr/include/x86_64-linux-gnu/c++/11 -I/usr/include/c++/11/backward -I/usr/lib/gcc/x86_64-linux-gnu/11/include -I/usr/local/include -I/usr/include/x86_64-linux-gnu -I/usr/include ../Src/pages/datapage.h -o moc_datapage.cpp -moc_taskdecisionpage.cpp: ../src/pages/taskdecisionpage.h \ - ../src/pages/mappage.h \ +moc_taskdata.cpp: ../Src/pages/taskdata.h \ moc_predefs.h \ /usr/lib/qt5/bin/moc - /usr/lib/qt5/bin/moc $(DEFINES) --include /home/wangjing/uav/Drone_project/build/moc_predefs.h -I/usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++ -I/home/wangjing/uav/Drone_project -I/usr/include/x86_64-linux-gnu/qt5 -I/usr/include/x86_64-linux-gnu/qt5/QtWebEngineWidgets -I/usr/include/x86_64-linux-gnu/qt5/QtPrintSupport -I/usr/include/x86_64-linux-gnu/qt5/QtWidgets -I/usr/include/x86_64-linux-gnu/qt5/QtWebEngineCore -I/usr/include/x86_64-linux-gnu/qt5/QtQuick -I/usr/include/x86_64-linux-gnu/qt5/QtGui -I/usr/include/x86_64-linux-gnu/qt5/QtQmlModels -I/usr/include/x86_64-linux-gnu/qt5/QtWebChannel -I/usr/include/x86_64-linux-gnu/qt5/QtQml -I/usr/include/x86_64-linux-gnu/qt5/QtNetwork -I/usr/include/x86_64-linux-gnu/qt5/QtPositioning -I/usr/include/x86_64-linux-gnu/qt5/QtCore -I. -I/usr/include/c++/9 -I/usr/include/x86_64-linux-gnu/c++/9 -I/usr/include/c++/9/backward -I/usr/lib/gcc/x86_64-linux-gnu/9/include -I/usr/local/include -I/usr/include/x86_64-linux-gnu -I/usr/include ../src/pages/taskdecisionpage.h -o moc_taskdecisionpage.cpp + /usr/lib/qt5/bin/moc $(DEFINES) --include /home/qinxinqi/桌面/Drone_project/build/moc_predefs.h -I/usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++ -I/home/qinxinqi/桌面/Drone_project -I/usr/include/x86_64-linux-gnu/qt5 -I/usr/include/x86_64-linux-gnu/qt5/QtWebEngineWidgets -I/usr/include/x86_64-linux-gnu/qt5/QtPrintSupport -I/usr/include/x86_64-linux-gnu/qt5/QtWidgets -I/usr/include/x86_64-linux-gnu/qt5/QtWebEngineCore -I/usr/include/x86_64-linux-gnu/qt5/QtQuick -I/usr/include/x86_64-linux-gnu/qt5/QtGui -I/usr/include/x86_64-linux-gnu/qt5/QtQmlModels -I/usr/include/x86_64-linux-gnu/qt5/QtWebChannel -I/usr/include/x86_64-linux-gnu/qt5/QtQml -I/usr/include/x86_64-linux-gnu/qt5/QtNetwork -I/usr/include/x86_64-linux-gnu/qt5/QtPositioning -I/usr/include/x86_64-linux-gnu/qt5/QtCore -I. -I/usr/include/c++/11 -I/usr/include/x86_64-linux-gnu/c++/11 -I/usr/include/c++/11/backward -I/usr/lib/gcc/x86_64-linux-gnu/11/include -I/usr/local/include -I/usr/include/x86_64-linux-gnu -I/usr/include ../Src/pages/taskdata.h -o moc_taskdata.cpp + +moc_visionmodelpage.cpp: ../Src/pages/visionmodelpage.h \ + moc_predefs.h \ + /usr/lib/qt5/bin/moc + /usr/lib/qt5/bin/moc $(DEFINES) --include /home/qinxinqi/桌面/Drone_project/build/moc_predefs.h -I/usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++ -I/home/qinxinqi/桌面/Drone_project -I/usr/include/x86_64-linux-gnu/qt5 -I/usr/include/x86_64-linux-gnu/qt5/QtWebEngineWidgets -I/usr/include/x86_64-linux-gnu/qt5/QtPrintSupport -I/usr/include/x86_64-linux-gnu/qt5/QtWidgets -I/usr/include/x86_64-linux-gnu/qt5/QtWebEngineCore -I/usr/include/x86_64-linux-gnu/qt5/QtQuick -I/usr/include/x86_64-linux-gnu/qt5/QtGui -I/usr/include/x86_64-linux-gnu/qt5/QtQmlModels -I/usr/include/x86_64-linux-gnu/qt5/QtWebChannel -I/usr/include/x86_64-linux-gnu/qt5/QtQml -I/usr/include/x86_64-linux-gnu/qt5/QtNetwork -I/usr/include/x86_64-linux-gnu/qt5/QtPositioning -I/usr/include/x86_64-linux-gnu/qt5/QtCore -I. -I/usr/include/c++/11 -I/usr/include/x86_64-linux-gnu/c++/11 -I/usr/include/c++/11/backward -I/usr/lib/gcc/x86_64-linux-gnu/11/include -I/usr/local/include -I/usr/include/x86_64-linux-gnu -I/usr/include ../Src/pages/visionmodelpage.h -o moc_visionmodelpage.cpp + +moc_taskdecisionpage.cpp: ../Src/pages/taskdecisionpage.h \ + moc_predefs.h \ + /usr/lib/qt5/bin/moc + /usr/lib/qt5/bin/moc $(DEFINES) --include /home/qinxinqi/桌面/Drone_project/build/moc_predefs.h -I/usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++ -I/home/qinxinqi/桌面/Drone_project -I/usr/include/x86_64-linux-gnu/qt5 -I/usr/include/x86_64-linux-gnu/qt5/QtWebEngineWidgets -I/usr/include/x86_64-linux-gnu/qt5/QtPrintSupport -I/usr/include/x86_64-linux-gnu/qt5/QtWidgets -I/usr/include/x86_64-linux-gnu/qt5/QtWebEngineCore -I/usr/include/x86_64-linux-gnu/qt5/QtQuick -I/usr/include/x86_64-linux-gnu/qt5/QtGui -I/usr/include/x86_64-linux-gnu/qt5/QtQmlModels -I/usr/include/x86_64-linux-gnu/qt5/QtWebChannel -I/usr/include/x86_64-linux-gnu/qt5/QtQml -I/usr/include/x86_64-linux-gnu/qt5/QtNetwork -I/usr/include/x86_64-linux-gnu/qt5/QtPositioning -I/usr/include/x86_64-linux-gnu/qt5/QtCore -I. -I/usr/include/c++/11 -I/usr/include/x86_64-linux-gnu/c++/11 -I/usr/include/c++/11/backward -I/usr/lib/gcc/x86_64-linux-gnu/11/include -I/usr/local/include -I/usr/include/x86_64-linux-gnu -I/usr/include ../Src/pages/taskdecisionpage.h -o moc_taskdecisionpage.cpp + +moc_dronemanagementpage.cpp: ../Src/pages/dronemanagementpage.h \ + ../Src/models/dronedata.h \ + moc_predefs.h \ + /usr/lib/qt5/bin/moc + /usr/lib/qt5/bin/moc $(DEFINES) --include /home/qinxinqi/桌面/Drone_project/build/moc_predefs.h -I/usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++ -I/home/qinxinqi/桌面/Drone_project -I/usr/include/x86_64-linux-gnu/qt5 -I/usr/include/x86_64-linux-gnu/qt5/QtWebEngineWidgets -I/usr/include/x86_64-linux-gnu/qt5/QtPrintSupport -I/usr/include/x86_64-linux-gnu/qt5/QtWidgets -I/usr/include/x86_64-linux-gnu/qt5/QtWebEngineCore -I/usr/include/x86_64-linux-gnu/qt5/QtQuick -I/usr/include/x86_64-linux-gnu/qt5/QtGui -I/usr/include/x86_64-linux-gnu/qt5/QtQmlModels -I/usr/include/x86_64-linux-gnu/qt5/QtWebChannel -I/usr/include/x86_64-linux-gnu/qt5/QtQml -I/usr/include/x86_64-linux-gnu/qt5/QtNetwork -I/usr/include/x86_64-linux-gnu/qt5/QtPositioning -I/usr/include/x86_64-linux-gnu/qt5/QtCore -I. -I/usr/include/c++/11 -I/usr/include/x86_64-linux-gnu/c++/11 -I/usr/include/c++/11/backward -I/usr/lib/gcc/x86_64-linux-gnu/11/include -I/usr/local/include -I/usr/include/x86_64-linux-gnu -I/usr/include ../Src/pages/dronemanagementpage.h -o moc_dronemanagementpage.cpp + +moc_taskdetailspage.cpp: ../Src/pages/taskdetailspage.h \ + ../Src/pages/taskdata.h \ + ../Src/models/dronedata.h \ + moc_predefs.h \ + /usr/lib/qt5/bin/moc + /usr/lib/qt5/bin/moc $(DEFINES) --include /home/qinxinqi/桌面/Drone_project/build/moc_predefs.h -I/usr/lib/x86_64-linux-gnu/qt5/mkspecs/linux-g++ -I/home/qinxinqi/桌面/Drone_project -I/usr/include/x86_64-linux-gnu/qt5 -I/usr/include/x86_64-linux-gnu/qt5/QtWebEngineWidgets -I/usr/include/x86_64-linux-gnu/qt5/QtPrintSupport -I/usr/include/x86_64-linux-gnu/qt5/QtWidgets -I/usr/include/x86_64-linux-gnu/qt5/QtWebEngineCore -I/usr/include/x86_64-linux-gnu/qt5/QtQuick -I/usr/include/x86_64-linux-gnu/qt5/QtGui -I/usr/include/x86_64-linux-gnu/qt5/QtQmlModels -I/usr/include/x86_64-linux-gnu/qt5/QtWebChannel -I/usr/include/x86_64-linux-gnu/qt5/QtQml -I/usr/include/x86_64-linux-gnu/qt5/QtNetwork -I/usr/include/x86_64-linux-gnu/qt5/QtPositioning -I/usr/include/x86_64-linux-gnu/qt5/QtCore -I. -I/usr/include/c++/11 -I/usr/include/x86_64-linux-gnu/c++/11 -I/usr/include/c++/11/backward -I/usr/lib/gcc/x86_64-linux-gnu/11/include -I/usr/local/include -I/usr/include/x86_64-linux-gnu -I/usr/include ../Src/pages/taskdetailspage.h -o moc_taskdetailspage.cpp compiler_moc_objc_header_make_all: compiler_moc_objc_header_clean: @@ -522,66 +571,85 @@ compiler_clean: compiler_rcc_clean compiler_moc_predefs_clean compiler_moc_heade ####### Compile -main.o: ../src/core/main.cpp ../src/ui/mainwindow.h \ - ../src/models/dronedata.h \ - ../src/models/detectiondata.h \ - ../src/pages/visionmodelpage.h \ - ../src/utils/stylehelper.h \ - ../src/pages/taskdecisionpage.h \ - ../src/pages/mappage.h \ - ../src/utils/logger.h \ - ../src/utils/config.h - $(CXX) -c $(CXXFLAGS) $(INCPATH) -o main.o ../src/core/main.cpp - -mainwindow.o: ../src/ui/mainwindow.cpp ../src/ui/mainwindow.h \ - ../src/models/dronedata.h \ - ../src/models/detectiondata.h \ - ../src/pages/visionmodelpage.h \ - ../src/utils/stylehelper.h \ - ../src/pages/taskdecisionpage.h \ - ../src/pages/mappage.h \ - ../src/pages/videopage.h \ - ../src/pages/datapage.h - $(CXX) -c $(CXXFLAGS) $(INCPATH) -o mainwindow.o ../src/ui/mainwindow.cpp - -dronedata.o: ../src/models/dronedata.cpp ../src/models/dronedata.h - $(CXX) -c $(CXXFLAGS) $(INCPATH) -o dronedata.o ../src/models/dronedata.cpp - -detectiondata.o: ../src/models/detectiondata.cpp ../src/models/detectiondata.h - $(CXX) -c $(CXXFLAGS) $(INCPATH) -o detectiondata.o ../src/models/detectiondata.cpp - -videopage.o: ../src/pages/videopage.cpp ../src/pages/videopage.h - $(CXX) -c $(CXXFLAGS) $(INCPATH) -o videopage.o ../src/pages/videopage.cpp - -mappage.o: ../src/pages/mappage.cpp ../src/pages/mappage.h \ - ../src/utils/config.h \ - ../src/utils/logger.h - $(CXX) -c $(CXXFLAGS) $(INCPATH) -o mappage.o ../src/pages/mappage.cpp - -datapage.o: ../src/pages/datapage.cpp ../src/pages/datapage.h \ - ../src/models/dronedata.h \ - ../src/models/detectiondata.h - $(CXX) -c $(CXXFLAGS) $(INCPATH) -o datapage.o ../src/pages/datapage.cpp - -visionmodelpage.o: ../src/pages/visionmodelpage.cpp ../src/pages/visionmodelpage.h - $(CXX) -c $(CXXFLAGS) $(INCPATH) -o visionmodelpage.o ../src/pages/visionmodelpage.cpp - -stylehelper.o: ../src/utils/stylehelper.cpp ../src/utils/stylehelper.h - $(CXX) -c $(CXXFLAGS) $(INCPATH) -o stylehelper.o ../src/utils/stylehelper.cpp - -taskdecisionpage.o: ../src/pages/taskdecisionpage.cpp ../src/pages/taskdecisionpage.h \ - ../src/pages/mappage.h - $(CXX) -c $(CXXFLAGS) $(INCPATH) -o taskdecisionpage.o ../src/pages/taskdecisionpage.cpp - -config.o: ../src/utils/config.cpp ../src/utils/config.h - $(CXX) -c $(CXXFLAGS) $(INCPATH) -o config.o ../src/utils/config.cpp - -logger.o: ../src/utils/logger.cpp ../src/utils/logger.h \ - ../src/utils/config.h - $(CXX) -c $(CXXFLAGS) $(INCPATH) -o logger.o ../src/utils/logger.cpp - -errorhandler.o: ../src/utils/errorhandler.cpp ../src/utils/errorhandler.h - $(CXX) -c $(CXXFLAGS) $(INCPATH) -o errorhandler.o ../src/utils/errorhandler.cpp +main.o: ../Src/core/main.cpp ../Src/ui/mainwindow.h \ + ../Src/models/dronedata.h \ + ../Src/models/detectiondata.h \ + ../Src/pages/visionmodelpage.h \ + ../Src/utils/stylehelper.h \ + ../Src/pages/taskdecisionpage.h \ + ../Src/pages/dronemanagementpage.h \ + ../Src/pages/taskdetailspage.h \ + ../Src/pages/taskdata.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o main.o ../Src/core/main.cpp + +mainwindow.o: ../Src/ui/mainwindow.cpp ../Src/ui/mainwindow.h \ + ../Src/models/dronedata.h \ + ../Src/models/detectiondata.h \ + ../Src/pages/visionmodelpage.h \ + ../Src/utils/stylehelper.h \ + ../Src/pages/taskdecisionpage.h \ + ../Src/pages/dronemanagementpage.h \ + ../Src/pages/taskdetailspage.h \ + ../Src/pages/taskdata.h \ + ../Src/pages/videopage.h \ + ../Src/pages/mappage.h \ + ../Src/pages/mapbridge.h \ + ../Src/pages/datapage.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o mainwindow.o ../Src/ui/mainwindow.cpp + +dronedata.o: ../Src/models/dronedata.cpp ../Src/models/dronedata.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o dronedata.o ../Src/models/dronedata.cpp + +detectiondata.o: ../Src/models/detectiondata.cpp ../Src/models/detectiondata.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o detectiondata.o ../Src/models/detectiondata.cpp + +videopage.o: ../Src/pages/videopage.cpp ../Src/pages/videopage.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o videopage.o ../Src/pages/videopage.cpp + +mappage.o: ../Src/pages/mappage.cpp ../Src/pages/mappage.h \ + ../Src/pages/mapbridge.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o mappage.o ../Src/pages/mappage.cpp + +mapbridge.o: ../Src/pages/mapbridge.cpp ../Src/pages/mapbridge.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o mapbridge.o ../Src/pages/mapbridge.cpp + +datapage.o: ../Src/pages/datapage.cpp ../Src/pages/datapage.h \ + ../Src/models/dronedata.h \ + ../Src/models/detectiondata.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o datapage.o ../Src/pages/datapage.cpp + +taskdata.o: ../Src/pages/taskdata.cpp ../Src/pages/taskdata.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o taskdata.o ../Src/pages/taskdata.cpp + +visionmodelpage.o: ../Src/pages/visionmodelpage.cpp ../Src/pages/visionmodelpage.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o visionmodelpage.o ../Src/pages/visionmodelpage.cpp + +stylehelper.o: ../Src/utils/stylehelper.cpp ../Src/utils/stylehelper.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o stylehelper.o ../Src/utils/stylehelper.cpp + +taskdecisionpage.o: ../Src/pages/taskdecisionpage.cpp ../Src/pages/taskdecisionpage.h \ + ../Src/pages/mappage.h \ + ../Src/pages/mapbridge.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o taskdecisionpage.o ../Src/pages/taskdecisionpage.cpp + +dronemanagementpage.o: ../Src/pages/dronemanagementpage.cpp ../Src/pages/dronemanagementpage.h \ + ../Src/models/dronedata.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o dronemanagementpage.o ../Src/pages/dronemanagementpage.cpp + +taskdetailspage.o: ../Src/pages/taskdetailspage.cpp ../Src/pages/taskdetailspage.h \ + ../Src/pages/taskdata.h \ + ../Src/models/dronedata.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o taskdetailspage.o ../Src/pages/taskdetailspage.cpp + +config.o: ../Src/utils/config.cpp ../Src/utils/config.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o config.o ../Src/utils/config.cpp + +logger.o: ../Src/utils/logger.cpp ../Src/utils/logger.h \ + ../Src/utils/config.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o logger.o ../Src/utils/logger.cpp + +errorhandler.o: ../Src/utils/errorhandler.cpp ../Src/utils/errorhandler.h + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o errorhandler.o ../Src/utils/errorhandler.cpp qrc_app.o: qrc_app.cpp $(CXX) -c $(CXXFLAGS) $(INCPATH) -o qrc_app.o qrc_app.cpp @@ -601,15 +669,27 @@ moc_videopage.o: moc_videopage.cpp moc_mappage.o: moc_mappage.cpp $(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_mappage.o moc_mappage.cpp +moc_mapbridge.o: moc_mapbridge.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_mapbridge.o moc_mapbridge.cpp + moc_datapage.o: moc_datapage.cpp $(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_datapage.o moc_datapage.cpp +moc_taskdata.o: moc_taskdata.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_taskdata.o moc_taskdata.cpp + moc_visionmodelpage.o: moc_visionmodelpage.cpp $(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_visionmodelpage.o moc_visionmodelpage.cpp moc_taskdecisionpage.o: moc_taskdecisionpage.cpp $(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_taskdecisionpage.o moc_taskdecisionpage.cpp +moc_dronemanagementpage.o: moc_dronemanagementpage.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_dronemanagementpage.o moc_dronemanagementpage.cpp + +moc_taskdetailspage.o: moc_taskdetailspage.cpp + $(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_taskdetailspage.o moc_taskdetailspage.cpp + ####### Install install: FORCE diff --git a/build/config.o b/build/config.o index 31fdde6..c097f21 100644 Binary files a/build/config.o and b/build/config.o differ diff --git a/build/datapage.o b/build/datapage.o index 40774c0..729bb35 100644 Binary files a/build/datapage.o and b/build/datapage.o differ diff --git a/build/detectiondata.o b/build/detectiondata.o index ce626c6..348c283 100644 Binary files a/build/detectiondata.o and b/build/detectiondata.o differ diff --git a/build/dronedata.o b/build/dronedata.o index 44a9de3..022d65a 100644 Binary files a/build/dronedata.o and b/build/dronedata.o differ diff --git a/build/dronemanagementpage.o b/build/dronemanagementpage.o new file mode 100644 index 0000000..c02529e Binary files /dev/null and b/build/dronemanagementpage.o differ diff --git a/build/errorhandler.o b/build/errorhandler.o index 1e30954..e7efef2 100644 Binary files a/build/errorhandler.o and b/build/errorhandler.o differ diff --git a/build/logger.o b/build/logger.o index bb69148..16783a0 100644 Binary files a/build/logger.o and b/build/logger.o differ diff --git a/build/main.o b/build/main.o index 099ddcf..5abcb35 100644 Binary files a/build/main.o and b/build/main.o differ diff --git a/build/mainwindow.o b/build/mainwindow.o index 579f4a8..2076f73 100644 Binary files a/build/mainwindow.o and b/build/mainwindow.o differ diff --git a/build/mapbridge.o b/build/mapbridge.o new file mode 100644 index 0000000..a2988dd Binary files /dev/null and b/build/mapbridge.o differ diff --git a/build/mappage.o b/build/mappage.o index 19b3bde..2290579 100644 Binary files a/build/mappage.o and b/build/mappage.o differ diff --git a/build/moc_datapage.cpp b/build/moc_datapage.cpp index 68e0813..28b2319 100644 --- a/build/moc_datapage.cpp +++ b/build/moc_datapage.cpp @@ -7,7 +7,7 @@ *****************************************************************************/ #include -#include "../src/pages/datapage.h" +#include "../Src/pages/datapage.h" #include #include #if !defined(Q_MOC_OUTPUT_REVISION) diff --git a/build/moc_datapage.o b/build/moc_datapage.o index a29ad7f..a74c65e 100644 Binary files a/build/moc_datapage.o and b/build/moc_datapage.o differ diff --git a/build/moc_detectiondata.cpp b/build/moc_detectiondata.cpp index e10fd2e..edcf2b3 100644 --- a/build/moc_detectiondata.cpp +++ b/build/moc_detectiondata.cpp @@ -7,7 +7,7 @@ *****************************************************************************/ #include -#include "../src/models/detectiondata.h" +#include "../Src/models/detectiondata.h" #include #include #if !defined(Q_MOC_OUTPUT_REVISION) diff --git a/build/moc_detectiondata.o b/build/moc_detectiondata.o index 71d3000..bb58da8 100644 Binary files a/build/moc_detectiondata.o and b/build/moc_detectiondata.o differ diff --git a/build/moc_dronedata.cpp b/build/moc_dronedata.cpp index 3b4da1e..11d23a4 100644 --- a/build/moc_dronedata.cpp +++ b/build/moc_dronedata.cpp @@ -7,7 +7,7 @@ *****************************************************************************/ #include -#include "../src/models/dronedata.h" +#include "../Src/models/dronedata.h" #include #include #if !defined(Q_MOC_OUTPUT_REVISION) diff --git a/build/moc_dronedata.o b/build/moc_dronedata.o index 563cde3..4dda7a5 100644 Binary files a/build/moc_dronedata.o and b/build/moc_dronedata.o differ diff --git a/build/moc_dronemanagementpage.cpp b/build/moc_dronemanagementpage.cpp new file mode 100644 index 0000000..f320c53 --- /dev/null +++ b/build/moc_dronemanagementpage.cpp @@ -0,0 +1,198 @@ +/**************************************************************************** +** Meta object code from reading C++ file 'dronemanagementpage.h' +** +** Created by: The Qt Meta Object Compiler version 67 (Qt 5.15.3) +** +** WARNING! All changes made in this file will be lost! +*****************************************************************************/ + +#include +#include "../Src/pages/dronemanagementpage.h" +#include +#include +#if !defined(Q_MOC_OUTPUT_REVISION) +#error "The header file 'dronemanagementpage.h' doesn't include ." +#elif Q_MOC_OUTPUT_REVISION != 67 +#error "This file was generated using the moc from 5.15.3. It" +#error "cannot be used with the include files from this version of Qt." +#error "(The moc has changed too much.)" +#endif + +QT_BEGIN_MOC_NAMESPACE +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED +struct qt_meta_stringdata_DroneManagementPage_t { + QByteArrayData data[15]; + char stringdata0[254]; +}; +#define QT_MOC_LITERAL(idx, ofs, len) \ + Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \ + qptrdiff(offsetof(qt_meta_stringdata_DroneManagementPage_t, stringdata0) + ofs \ + - idx * sizeof(QByteArrayData)) \ + ) +static const qt_meta_stringdata_DroneManagementPage_t qt_meta_stringdata_DroneManagementPage = { + { +QT_MOC_LITERAL(0, 0, 19), // "DroneManagementPage" +QT_MOC_LITERAL(1, 20, 13), // "droneSelected" +QT_MOC_LITERAL(2, 34, 0), // "" +QT_MOC_LITERAL(3, 35, 7), // "droneId" +QT_MOC_LITERAL(4, 43, 24), // "droneConnectionRequested" +QT_MOC_LITERAL(5, 68, 7), // "connect" +QT_MOC_LITERAL(6, 76, 17), // "onAddDroneClicked" +QT_MOC_LITERAL(7, 94, 20), // "onRemoveDroneClicked" +QT_MOC_LITERAL(8, 115, 21), // "onConnectDroneClicked" +QT_MOC_LITERAL(9, 137, 24), // "onDisconnectDroneClicked" +QT_MOC_LITERAL(10, 162, 23), // "onDroneSelectionChanged" +QT_MOC_LITERAL(11, 186, 13), // "onRefreshData" +QT_MOC_LITERAL(12, 200, 18), // "onDroneDataChanged" +QT_MOC_LITERAL(13, 219, 24), // "onDroneConnectionChanged" +QT_MOC_LITERAL(14, 244, 9) // "connected" + + }, + "DroneManagementPage\0droneSelected\0\0" + "droneId\0droneConnectionRequested\0" + "connect\0onAddDroneClicked\0" + "onRemoveDroneClicked\0onConnectDroneClicked\0" + "onDisconnectDroneClicked\0" + "onDroneSelectionChanged\0onRefreshData\0" + "onDroneDataChanged\0onDroneConnectionChanged\0" + "connected" +}; +#undef QT_MOC_LITERAL + +static const uint qt_meta_data_DroneManagementPage[] = { + + // content: + 8, // revision + 0, // classname + 0, 0, // classinfo + 10, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 2, // signalCount + + // signals: name, argc, parameters, tag, flags + 1, 1, 64, 2, 0x06 /* Public */, + 4, 2, 67, 2, 0x06 /* Public */, + + // slots: name, argc, parameters, tag, flags + 6, 0, 72, 2, 0x08 /* Private */, + 7, 0, 73, 2, 0x08 /* Private */, + 8, 0, 74, 2, 0x08 /* Private */, + 9, 0, 75, 2, 0x08 /* Private */, + 10, 0, 76, 2, 0x08 /* Private */, + 11, 0, 77, 2, 0x08 /* Private */, + 12, 0, 78, 2, 0x08 /* Private */, + 13, 1, 79, 2, 0x08 /* Private */, + + // signals: parameters + QMetaType::Void, QMetaType::QString, 3, + QMetaType::Void, QMetaType::QString, QMetaType::Bool, 3, 5, + + // slots: parameters + QMetaType::Void, + QMetaType::Void, + QMetaType::Void, + QMetaType::Void, + QMetaType::Void, + QMetaType::Void, + QMetaType::Void, + QMetaType::Void, QMetaType::Bool, 14, + + 0 // eod +}; + +void DroneManagementPage::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) +{ + if (_c == QMetaObject::InvokeMetaMethod) { + auto *_t = static_cast(_o); + (void)_t; + switch (_id) { + case 0: _t->droneSelected((*reinterpret_cast< const QString(*)>(_a[1]))); break; + case 1: _t->droneConnectionRequested((*reinterpret_cast< const QString(*)>(_a[1])),(*reinterpret_cast< bool(*)>(_a[2]))); break; + case 2: _t->onAddDroneClicked(); break; + case 3: _t->onRemoveDroneClicked(); break; + case 4: _t->onConnectDroneClicked(); break; + case 5: _t->onDisconnectDroneClicked(); break; + case 6: _t->onDroneSelectionChanged(); break; + case 7: _t->onRefreshData(); break; + case 8: _t->onDroneDataChanged(); break; + case 9: _t->onDroneConnectionChanged((*reinterpret_cast< bool(*)>(_a[1]))); break; + default: ; + } + } else if (_c == QMetaObject::IndexOfMethod) { + int *result = reinterpret_cast(_a[0]); + { + using _t = void (DroneManagementPage::*)(const QString & ); + if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&DroneManagementPage::droneSelected)) { + *result = 0; + return; + } + } + { + using _t = void (DroneManagementPage::*)(const QString & , bool ); + if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&DroneManagementPage::droneConnectionRequested)) { + *result = 1; + return; + } + } + } +} + +QT_INIT_METAOBJECT const QMetaObject DroneManagementPage::staticMetaObject = { { + QMetaObject::SuperData::link(), + qt_meta_stringdata_DroneManagementPage.data, + qt_meta_data_DroneManagementPage, + qt_static_metacall, + nullptr, + nullptr +} }; + + +const QMetaObject *DroneManagementPage::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject; +} + +void *DroneManagementPage::qt_metacast(const char *_clname) +{ + if (!_clname) return nullptr; + if (!strcmp(_clname, qt_meta_stringdata_DroneManagementPage.stringdata0)) + return static_cast(this); + return QWidget::qt_metacast(_clname); +} + +int DroneManagementPage::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QWidget::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + if (_id < 10) + qt_static_metacall(this, _c, _id, _a); + _id -= 10; + } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) { + if (_id < 10) + *reinterpret_cast(_a[0]) = -1; + _id -= 10; + } + return _id; +} + +// SIGNAL 0 +void DroneManagementPage::droneSelected(const QString & _t1) +{ + void *_a[] = { nullptr, const_cast(reinterpret_cast(std::addressof(_t1))) }; + QMetaObject::activate(this, &staticMetaObject, 0, _a); +} + +// SIGNAL 1 +void DroneManagementPage::droneConnectionRequested(const QString & _t1, bool _t2) +{ + void *_a[] = { nullptr, const_cast(reinterpret_cast(std::addressof(_t1))), const_cast(reinterpret_cast(std::addressof(_t2))) }; + QMetaObject::activate(this, &staticMetaObject, 1, _a); +} +QT_WARNING_POP +QT_END_MOC_NAMESPACE diff --git a/build/moc_dronemanagementpage.o b/build/moc_dronemanagementpage.o new file mode 100644 index 0000000..77e7852 Binary files /dev/null and b/build/moc_dronemanagementpage.o differ diff --git a/build/moc_mainwindow.cpp b/build/moc_mainwindow.cpp index ff514b0..a826504 100644 --- a/build/moc_mainwindow.cpp +++ b/build/moc_mainwindow.cpp @@ -7,7 +7,7 @@ *****************************************************************************/ #include -#include "../src/ui/mainwindow.h" +#include "../Src/ui/mainwindow.h" #include #include #if !defined(Q_MOC_OUTPUT_REVISION) @@ -22,8 +22,8 @@ QT_BEGIN_MOC_NAMESPACE QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED struct qt_meta_stringdata_MainWindow_t { - QByteArrayData data[12]; - char stringdata0[184]; + QByteArrayData data[14]; + char stringdata0[228]; }; #define QT_MOC_LITERAL(idx, ofs, len) \ Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \ @@ -39,16 +39,19 @@ QT_MOC_LITERAL(3, 26, 11), // "showMapPage" QT_MOC_LITERAL(4, 38, 12), // "showDataPage" QT_MOC_LITERAL(5, 51, 19), // "showVisionModelPage" QT_MOC_LITERAL(6, 71, 20), // "showTaskDecisionPage" -QT_MOC_LITERAL(7, 92, 23), // "onDroneSelectionChanged" -QT_MOC_LITERAL(8, 116, 21), // "onCurrentDroneChanged" -QT_MOC_LITERAL(9, 138, 7), // "droneId" -QT_MOC_LITERAL(10, 146, 17), // "updateDroneStatus" -QT_MOC_LITERAL(11, 164, 19) // "updateDetectionInfo" +QT_MOC_LITERAL(7, 92, 23), // "showDroneManagementPage" +QT_MOC_LITERAL(8, 116, 19), // "showTaskDetailsPage" +QT_MOC_LITERAL(9, 136, 23), // "onDroneSelectionChanged" +QT_MOC_LITERAL(10, 160, 21), // "onCurrentDroneChanged" +QT_MOC_LITERAL(11, 182, 7), // "droneId" +QT_MOC_LITERAL(12, 190, 17), // "updateDroneStatus" +QT_MOC_LITERAL(13, 208, 19) // "updateDetectionInfo" }, "MainWindow\0showVideoPage\0\0showMapPage\0" "showDataPage\0showVisionModelPage\0" - "showTaskDecisionPage\0onDroneSelectionChanged\0" + "showTaskDecisionPage\0showDroneManagementPage\0" + "showTaskDetailsPage\0onDroneSelectionChanged\0" "onCurrentDroneChanged\0droneId\0" "updateDroneStatus\0updateDetectionInfo" }; @@ -60,7 +63,7 @@ static const uint qt_meta_data_MainWindow[] = { 8, // revision 0, // classname 0, 0, // classinfo - 9, 14, // methods + 11, 14, // methods 0, 0, // properties 0, 0, // enums/sets 0, 0, // constructors @@ -68,15 +71,17 @@ static const uint qt_meta_data_MainWindow[] = { 0, // signalCount // slots: name, argc, parameters, tag, flags - 1, 0, 59, 2, 0x08 /* Private */, - 3, 0, 60, 2, 0x08 /* Private */, - 4, 0, 61, 2, 0x08 /* Private */, - 5, 0, 62, 2, 0x08 /* Private */, - 6, 0, 63, 2, 0x08 /* Private */, - 7, 0, 64, 2, 0x08 /* Private */, - 8, 1, 65, 2, 0x08 /* Private */, - 10, 0, 68, 2, 0x08 /* Private */, - 11, 0, 69, 2, 0x08 /* Private */, + 1, 0, 69, 2, 0x08 /* Private */, + 3, 0, 70, 2, 0x08 /* Private */, + 4, 0, 71, 2, 0x08 /* Private */, + 5, 0, 72, 2, 0x08 /* Private */, + 6, 0, 73, 2, 0x08 /* Private */, + 7, 0, 74, 2, 0x08 /* Private */, + 8, 0, 75, 2, 0x08 /* Private */, + 9, 0, 76, 2, 0x08 /* Private */, + 10, 1, 77, 2, 0x08 /* Private */, + 12, 0, 80, 2, 0x08 /* Private */, + 13, 0, 81, 2, 0x08 /* Private */, // slots: parameters QMetaType::Void, @@ -85,7 +90,9 @@ static const uint qt_meta_data_MainWindow[] = { QMetaType::Void, QMetaType::Void, QMetaType::Void, - QMetaType::Void, QMetaType::QString, 9, + QMetaType::Void, + QMetaType::Void, + QMetaType::Void, QMetaType::QString, 11, QMetaType::Void, QMetaType::Void, @@ -103,10 +110,12 @@ void MainWindow::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, case 2: _t->showDataPage(); break; case 3: _t->showVisionModelPage(); break; case 4: _t->showTaskDecisionPage(); break; - case 5: _t->onDroneSelectionChanged(); break; - case 6: _t->onCurrentDroneChanged((*reinterpret_cast< const QString(*)>(_a[1]))); break; - case 7: _t->updateDroneStatus(); break; - case 8: _t->updateDetectionInfo(); break; + case 5: _t->showDroneManagementPage(); break; + case 6: _t->showTaskDetailsPage(); break; + case 7: _t->onDroneSelectionChanged(); break; + case 8: _t->onCurrentDroneChanged((*reinterpret_cast< const QString(*)>(_a[1]))); break; + case 9: _t->updateDroneStatus(); break; + case 10: _t->updateDetectionInfo(); break; default: ; } } @@ -141,13 +150,13 @@ int MainWindow::qt_metacall(QMetaObject::Call _c, int _id, void **_a) if (_id < 0) return _id; if (_c == QMetaObject::InvokeMetaMethod) { - if (_id < 9) + if (_id < 11) qt_static_metacall(this, _c, _id, _a); - _id -= 9; + _id -= 11; } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) { - if (_id < 9) + if (_id < 11) *reinterpret_cast(_a[0]) = -1; - _id -= 9; + _id -= 11; } return _id; } diff --git a/build/moc_mainwindow.o b/build/moc_mainwindow.o index b2ee70f..c51301a 100644 Binary files a/build/moc_mainwindow.o and b/build/moc_mainwindow.o differ diff --git a/build/moc_mapbridge.cpp b/build/moc_mapbridge.cpp new file mode 100644 index 0000000..04a5498 --- /dev/null +++ b/build/moc_mapbridge.cpp @@ -0,0 +1,166 @@ +/**************************************************************************** +** Meta object code from reading C++ file 'mapbridge.h' +** +** Created by: The Qt Meta Object Compiler version 67 (Qt 5.15.3) +** +** WARNING! All changes made in this file will be lost! +*****************************************************************************/ + +#include +#include "../Src/pages/mapbridge.h" +#include +#include +#if !defined(Q_MOC_OUTPUT_REVISION) +#error "The header file 'mapbridge.h' doesn't include ." +#elif Q_MOC_OUTPUT_REVISION != 67 +#error "This file was generated using the moc from 5.15.3. It" +#error "cannot be used with the include files from this version of Qt." +#error "(The moc has changed too much.)" +#endif + +QT_BEGIN_MOC_NAMESPACE +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED +struct qt_meta_stringdata_MapBridge_t { + QByteArrayData data[8]; + char stringdata0[58]; +}; +#define QT_MOC_LITERAL(idx, ofs, len) \ + Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \ + qptrdiff(offsetof(qt_meta_stringdata_MapBridge_t, stringdata0) + ofs \ + - idx * sizeof(QByteArrayData)) \ + ) +static const qt_meta_stringdata_MapBridge_t qt_meta_stringdata_MapBridge = { + { +QT_MOC_LITERAL(0, 0, 9), // "MapBridge" +QT_MOC_LITERAL(1, 10, 10), // "mapClicked" +QT_MOC_LITERAL(2, 21, 0), // "" +QT_MOC_LITERAL(3, 22, 3), // "lng" +QT_MOC_LITERAL(4, 26, 3), // "lat" +QT_MOC_LITERAL(5, 30, 8), // "mapReady" +QT_MOC_LITERAL(6, 39, 7), // "onClick" +QT_MOC_LITERAL(7, 47, 10) // "onMapReady" + + }, + "MapBridge\0mapClicked\0\0lng\0lat\0mapReady\0" + "onClick\0onMapReady" +}; +#undef QT_MOC_LITERAL + +static const uint qt_meta_data_MapBridge[] = { + + // content: + 8, // revision + 0, // classname + 0, 0, // classinfo + 4, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 2, // signalCount + + // signals: name, argc, parameters, tag, flags + 1, 2, 34, 2, 0x06 /* Public */, + 5, 0, 39, 2, 0x06 /* Public */, + + // slots: name, argc, parameters, tag, flags + 6, 2, 40, 2, 0x0a /* Public */, + 7, 0, 45, 2, 0x0a /* Public */, + + // signals: parameters + QMetaType::Void, QMetaType::Double, QMetaType::Double, 3, 4, + QMetaType::Void, + + // slots: parameters + QMetaType::Void, QMetaType::Double, QMetaType::Double, 3, 4, + QMetaType::Void, + + 0 // eod +}; + +void MapBridge::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) +{ + if (_c == QMetaObject::InvokeMetaMethod) { + auto *_t = static_cast(_o); + (void)_t; + switch (_id) { + case 0: _t->mapClicked((*reinterpret_cast< double(*)>(_a[1])),(*reinterpret_cast< double(*)>(_a[2]))); break; + case 1: _t->mapReady(); break; + case 2: _t->onClick((*reinterpret_cast< double(*)>(_a[1])),(*reinterpret_cast< double(*)>(_a[2]))); break; + case 3: _t->onMapReady(); break; + default: ; + } + } else if (_c == QMetaObject::IndexOfMethod) { + int *result = reinterpret_cast(_a[0]); + { + using _t = void (MapBridge::*)(double , double ); + if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&MapBridge::mapClicked)) { + *result = 0; + return; + } + } + { + using _t = void (MapBridge::*)(); + if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&MapBridge::mapReady)) { + *result = 1; + return; + } + } + } +} + +QT_INIT_METAOBJECT const QMetaObject MapBridge::staticMetaObject = { { + QMetaObject::SuperData::link(), + qt_meta_stringdata_MapBridge.data, + qt_meta_data_MapBridge, + qt_static_metacall, + nullptr, + nullptr +} }; + + +const QMetaObject *MapBridge::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject; +} + +void *MapBridge::qt_metacast(const char *_clname) +{ + if (!_clname) return nullptr; + if (!strcmp(_clname, qt_meta_stringdata_MapBridge.stringdata0)) + return static_cast(this); + return QObject::qt_metacast(_clname); +} + +int MapBridge::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + if (_id < 4) + qt_static_metacall(this, _c, _id, _a); + _id -= 4; + } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) { + if (_id < 4) + *reinterpret_cast(_a[0]) = -1; + _id -= 4; + } + return _id; +} + +// SIGNAL 0 +void MapBridge::mapClicked(double _t1, double _t2) +{ + void *_a[] = { nullptr, const_cast(reinterpret_cast(std::addressof(_t1))), const_cast(reinterpret_cast(std::addressof(_t2))) }; + QMetaObject::activate(this, &staticMetaObject, 0, _a); +} + +// SIGNAL 1 +void MapBridge::mapReady() +{ + QMetaObject::activate(this, &staticMetaObject, 1, nullptr); +} +QT_WARNING_POP +QT_END_MOC_NAMESPACE diff --git a/build/moc_mapbridge.o b/build/moc_mapbridge.o new file mode 100644 index 0000000..595fa7a Binary files /dev/null and b/build/moc_mapbridge.o differ diff --git a/build/moc_mappage.cpp b/build/moc_mappage.cpp index 359b1aa..48ec68e 100644 --- a/build/moc_mappage.cpp +++ b/build/moc_mappage.cpp @@ -7,9 +7,10 @@ *****************************************************************************/ #include -#include "../src/pages/mappage.h" +#include "../Src/pages/mappage.h" #include #include +#include #if !defined(Q_MOC_OUTPUT_REVISION) #error "The header file 'mappage.h' doesn't include ." #elif Q_MOC_OUTPUT_REVISION != 67 @@ -22,8 +23,8 @@ QT_BEGIN_MOC_NAMESPACE QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED struct qt_meta_stringdata_CustomWebEnginePage_t { - QByteArrayData data[1]; - char stringdata0[20]; + QByteArrayData data[8]; + char stringdata0[116]; }; #define QT_MOC_LITERAL(idx, ofs, len) \ Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \ @@ -32,10 +33,19 @@ struct qt_meta_stringdata_CustomWebEnginePage_t { ) static const qt_meta_stringdata_CustomWebEnginePage_t qt_meta_stringdata_CustomWebEnginePage = { { -QT_MOC_LITERAL(0, 0, 19) // "CustomWebEnginePage" +QT_MOC_LITERAL(0, 0, 19), // "CustomWebEnginePage" +QT_MOC_LITERAL(1, 20, 14), // "consoleMessage" +QT_MOC_LITERAL(2, 35, 0), // "" +QT_MOC_LITERAL(3, 36, 45), // "QWebEnginePage::JavaScriptCon..." +QT_MOC_LITERAL(4, 82, 5), // "level" +QT_MOC_LITERAL(5, 88, 7), // "message" +QT_MOC_LITERAL(6, 96, 10), // "lineNumber" +QT_MOC_LITERAL(7, 107, 8) // "sourceID" }, - "CustomWebEnginePage" + "CustomWebEnginePage\0consoleMessage\0\0" + "QWebEnginePage::JavaScriptConsoleMessageLevel\0" + "level\0message\0lineNumber\0sourceID" }; #undef QT_MOC_LITERAL @@ -45,22 +55,41 @@ static const uint qt_meta_data_CustomWebEnginePage[] = { 8, // revision 0, // classname 0, 0, // classinfo - 0, 0, // methods + 1, 14, // methods 0, 0, // properties 0, 0, // enums/sets 0, 0, // constructors 0, // flags - 0, // signalCount + 1, // signalCount + + // signals: name, argc, parameters, tag, flags + 1, 4, 19, 2, 0x06 /* Public */, + + // signals: parameters + QMetaType::Void, 0x80000000 | 3, QMetaType::QString, QMetaType::Int, QMetaType::QString, 4, 5, 6, 7, 0 // eod }; void CustomWebEnginePage::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) { - (void)_o; - (void)_id; - (void)_c; - (void)_a; + if (_c == QMetaObject::InvokeMetaMethod) { + auto *_t = static_cast(_o); + (void)_t; + switch (_id) { + case 0: _t->consoleMessage((*reinterpret_cast< QWebEnginePage::JavaScriptConsoleMessageLevel(*)>(_a[1])),(*reinterpret_cast< const QString(*)>(_a[2])),(*reinterpret_cast< int(*)>(_a[3])),(*reinterpret_cast< const QString(*)>(_a[4]))); break; + default: ; + } + } else if (_c == QMetaObject::IndexOfMethod) { + int *result = reinterpret_cast(_a[0]); + { + using _t = void (CustomWebEnginePage::*)(QWebEnginePage::JavaScriptConsoleMessageLevel , const QString & , int , const QString & ); + if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&CustomWebEnginePage::consoleMessage)) { + *result = 0; + return; + } + } + } } QT_INIT_METAOBJECT const QMetaObject CustomWebEnginePage::staticMetaObject = { { @@ -89,11 +118,29 @@ void *CustomWebEnginePage::qt_metacast(const char *_clname) int CustomWebEnginePage::qt_metacall(QMetaObject::Call _c, int _id, void **_a) { _id = QWebEnginePage::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + if (_id < 1) + qt_static_metacall(this, _c, _id, _a); + _id -= 1; + } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) { + if (_id < 1) + *reinterpret_cast(_a[0]) = -1; + _id -= 1; + } return _id; } + +// SIGNAL 0 +void CustomWebEnginePage::consoleMessage(QWebEnginePage::JavaScriptConsoleMessageLevel _t1, const QString & _t2, int _t3, const QString & _t4) +{ + void *_a[] = { nullptr, const_cast(reinterpret_cast(std::addressof(_t1))), const_cast(reinterpret_cast(std::addressof(_t2))), const_cast(reinterpret_cast(std::addressof(_t3))), const_cast(reinterpret_cast(std::addressof(_t4))) }; + QMetaObject::activate(this, &staticMetaObject, 0, _a); +} struct qt_meta_stringdata_ThreatAreaDialog_t { - QByteArrayData data[3]; - char stringdata0[26]; + QByteArrayData data[13]; + char stringdata0[149]; }; #define QT_MOC_LITERAL(idx, ofs, len) \ Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \ @@ -104,10 +151,23 @@ static const qt_meta_stringdata_ThreatAreaDialog_t qt_meta_stringdata_ThreatArea { QT_MOC_LITERAL(0, 0, 16), // "ThreatAreaDialog" QT_MOC_LITERAL(1, 17, 7), // "addArea" -QT_MOC_LITERAL(2, 25, 0) // "" +QT_MOC_LITERAL(2, 25, 0), // "" +QT_MOC_LITERAL(3, 26, 17), // "updateThreatStats" +QT_MOC_LITERAL(4, 44, 22), // "startDrawingThreatArea" +QT_MOC_LITERAL(5, 67, 14), // "onShapeChanged" +QT_MOC_LITERAL(6, 82, 5), // "index" +QT_MOC_LITERAL(7, 88, 18), // "handleDrawingClick" +QT_MOC_LITERAL(8, 107, 3), // "lng" +QT_MOC_LITERAL(9, 111, 3), // "lat" +QT_MOC_LITERAL(10, 115, 13), // "finishDrawing" +QT_MOC_LITERAL(11, 129, 8), // "editArea" +QT_MOC_LITERAL(12, 138, 10) // "deleteArea" }, - "ThreatAreaDialog\0addArea\0" + "ThreatAreaDialog\0addArea\0\0updateThreatStats\0" + "startDrawingThreatArea\0onShapeChanged\0" + "index\0handleDrawingClick\0lng\0lat\0" + "finishDrawing\0editArea\0deleteArea" }; #undef QT_MOC_LITERAL @@ -117,7 +177,7 @@ static const uint qt_meta_data_ThreatAreaDialog[] = { 8, // revision 0, // classname 0, 0, // classinfo - 1, 14, // methods + 8, 14, // methods 0, 0, // properties 0, 0, // enums/sets 0, 0, // constructors @@ -125,9 +185,23 @@ static const uint qt_meta_data_ThreatAreaDialog[] = { 0, // signalCount // slots: name, argc, parameters, tag, flags - 1, 0, 19, 2, 0x08 /* Private */, + 1, 0, 54, 2, 0x08 /* Private */, + 3, 0, 55, 2, 0x08 /* Private */, + 4, 0, 56, 2, 0x08 /* Private */, + 5, 1, 57, 2, 0x08 /* Private */, + 7, 2, 60, 2, 0x08 /* Private */, + 10, 0, 65, 2, 0x08 /* Private */, + 11, 0, 66, 2, 0x08 /* Private */, + 12, 0, 67, 2, 0x08 /* Private */, // slots: parameters + QMetaType::Void, + QMetaType::Void, + QMetaType::Void, + QMetaType::Void, QMetaType::Int, 6, + QMetaType::Void, QMetaType::Double, QMetaType::Double, 8, 9, + QMetaType::Void, + QMetaType::Void, QMetaType::Void, 0 // eod @@ -140,10 +214,16 @@ void ThreatAreaDialog::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int (void)_t; switch (_id) { case 0: _t->addArea(); break; + case 1: _t->updateThreatStats(); break; + case 2: _t->startDrawingThreatArea(); break; + case 3: _t->onShapeChanged((*reinterpret_cast< int(*)>(_a[1]))); break; + case 4: _t->handleDrawingClick((*reinterpret_cast< double(*)>(_a[1])),(*reinterpret_cast< double(*)>(_a[2]))); break; + case 5: _t->finishDrawing(); break; + case 6: _t->editArea(); break; + case 7: _t->deleteArea(); break; default: ; } } - (void)_a; } QT_INIT_METAOBJECT const QMetaObject ThreatAreaDialog::staticMetaObject = { { @@ -175,154 +255,250 @@ int ThreatAreaDialog::qt_metacall(QMetaObject::Call _c, int _id, void **_a) if (_id < 0) return _id; if (_c == QMetaObject::InvokeMetaMethod) { - if (_id < 1) + if (_id < 8) qt_static_metacall(this, _c, _id, _a); - _id -= 1; + _id -= 8; } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) { - if (_id < 1) + if (_id < 8) *reinterpret_cast(_a[0]) = -1; - _id -= 1; + _id -= 8; } return _id; } -struct qt_meta_stringdata_AreaSearchDialog_t { - QByteArrayData data[1]; - char stringdata0[17]; +struct qt_meta_stringdata_PathPlanningDialog_t { + QByteArrayData data[9]; + char stringdata0[88]; }; #define QT_MOC_LITERAL(idx, ofs, len) \ Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \ - qptrdiff(offsetof(qt_meta_stringdata_AreaSearchDialog_t, stringdata0) + ofs \ + qptrdiff(offsetof(qt_meta_stringdata_PathPlanningDialog_t, stringdata0) + ofs \ - idx * sizeof(QByteArrayData)) \ ) -static const qt_meta_stringdata_AreaSearchDialog_t qt_meta_stringdata_AreaSearchDialog = { +static const qt_meta_stringdata_PathPlanningDialog_t qt_meta_stringdata_PathPlanningDialog = { { -QT_MOC_LITERAL(0, 0, 16) // "AreaSearchDialog" +QT_MOC_LITERAL(0, 0, 18), // "PathPlanningDialog" +QT_MOC_LITERAL(1, 19, 8), // "planPath" +QT_MOC_LITERAL(2, 28, 0), // "" +QT_MOC_LITERAL(3, 29, 15), // "applyStartPoint" +QT_MOC_LITERAL(4, 45, 13), // "applyEndPoint" +QT_MOC_LITERAL(5, 59, 10), // "onMapClick" +QT_MOC_LITERAL(6, 70, 3), // "lng" +QT_MOC_LITERAL(7, 74, 3), // "lat" +QT_MOC_LITERAL(8, 78, 9) // "clearPath" }, - "AreaSearchDialog" + "PathPlanningDialog\0planPath\0\0" + "applyStartPoint\0applyEndPoint\0onMapClick\0" + "lng\0lat\0clearPath" }; #undef QT_MOC_LITERAL -static const uint qt_meta_data_AreaSearchDialog[] = { +static const uint qt_meta_data_PathPlanningDialog[] = { // content: 8, // revision 0, // classname 0, 0, // classinfo - 0, 0, // methods + 5, 14, // methods 0, 0, // properties 0, 0, // enums/sets 0, 0, // constructors 0, // flags 0, // signalCount + // slots: name, argc, parameters, tag, flags + 1, 0, 39, 2, 0x08 /* Private */, + 3, 0, 40, 2, 0x08 /* Private */, + 4, 0, 41, 2, 0x08 /* Private */, + 5, 2, 42, 2, 0x08 /* Private */, + 8, 0, 47, 2, 0x08 /* Private */, + + // slots: parameters + QMetaType::Void, + QMetaType::Void, + QMetaType::Void, + QMetaType::Void, QMetaType::Double, QMetaType::Double, 6, 7, + QMetaType::Void, + 0 // eod }; -void AreaSearchDialog::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) +void PathPlanningDialog::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) { - (void)_o; - (void)_id; - (void)_c; - (void)_a; + if (_c == QMetaObject::InvokeMetaMethod) { + auto *_t = static_cast(_o); + (void)_t; + switch (_id) { + case 0: _t->planPath(); break; + case 1: _t->applyStartPoint(); break; + case 2: _t->applyEndPoint(); break; + case 3: _t->onMapClick((*reinterpret_cast< double(*)>(_a[1])),(*reinterpret_cast< double(*)>(_a[2]))); break; + case 4: _t->clearPath(); break; + default: ; + } + } } -QT_INIT_METAOBJECT const QMetaObject AreaSearchDialog::staticMetaObject = { { +QT_INIT_METAOBJECT const QMetaObject PathPlanningDialog::staticMetaObject = { { QMetaObject::SuperData::link(), - qt_meta_stringdata_AreaSearchDialog.data, - qt_meta_data_AreaSearchDialog, + qt_meta_stringdata_PathPlanningDialog.data, + qt_meta_data_PathPlanningDialog, qt_static_metacall, nullptr, nullptr } }; -const QMetaObject *AreaSearchDialog::metaObject() const +const QMetaObject *PathPlanningDialog::metaObject() const { return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject; } -void *AreaSearchDialog::qt_metacast(const char *_clname) +void *PathPlanningDialog::qt_metacast(const char *_clname) { if (!_clname) return nullptr; - if (!strcmp(_clname, qt_meta_stringdata_AreaSearchDialog.stringdata0)) + if (!strcmp(_clname, qt_meta_stringdata_PathPlanningDialog.stringdata0)) return static_cast(this); return QDialog::qt_metacast(_clname); } -int AreaSearchDialog::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +int PathPlanningDialog::qt_metacall(QMetaObject::Call _c, int _id, void **_a) { _id = QDialog::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + if (_id < 5) + qt_static_metacall(this, _c, _id, _a); + _id -= 5; + } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) { + if (_id < 5) + *reinterpret_cast(_a[0]) = -1; + _id -= 5; + } return _id; } -struct qt_meta_stringdata_PathPlanningDialog_t { - QByteArrayData data[1]; - char stringdata0[19]; +struct qt_meta_stringdata_AreaCoverageDialog_t { + QByteArrayData data[12]; + char stringdata0[132]; }; #define QT_MOC_LITERAL(idx, ofs, len) \ Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \ - qptrdiff(offsetof(qt_meta_stringdata_PathPlanningDialog_t, stringdata0) + ofs \ + qptrdiff(offsetof(qt_meta_stringdata_AreaCoverageDialog_t, stringdata0) + ofs \ - idx * sizeof(QByteArrayData)) \ ) -static const qt_meta_stringdata_PathPlanningDialog_t qt_meta_stringdata_PathPlanningDialog = { +static const qt_meta_stringdata_AreaCoverageDialog_t qt_meta_stringdata_AreaCoverageDialog = { { -QT_MOC_LITERAL(0, 0, 18) // "PathPlanningDialog" +QT_MOC_LITERAL(0, 0, 18), // "AreaCoverageDialog" +QT_MOC_LITERAL(1, 19, 14), // "onShapeChanged" +QT_MOC_LITERAL(2, 34, 0), // "" +QT_MOC_LITERAL(3, 35, 5), // "index" +QT_MOC_LITERAL(4, 41, 9), // "addVertex" +QT_MOC_LITERAL(5, 51, 12), // "removeVertex" +QT_MOC_LITERAL(6, 64, 17), // "selectVertexOnMap" +QT_MOC_LITERAL(7, 82, 16), // "planCoveragePath" +QT_MOC_LITERAL(8, 99, 13), // "clearCoverage" +QT_MOC_LITERAL(9, 113, 10), // "onMapClick" +QT_MOC_LITERAL(10, 124, 3), // "lng" +QT_MOC_LITERAL(11, 128, 3) // "lat" }, - "PathPlanningDialog" + "AreaCoverageDialog\0onShapeChanged\0\0" + "index\0addVertex\0removeVertex\0" + "selectVertexOnMap\0planCoveragePath\0" + "clearCoverage\0onMapClick\0lng\0lat" }; #undef QT_MOC_LITERAL -static const uint qt_meta_data_PathPlanningDialog[] = { +static const uint qt_meta_data_AreaCoverageDialog[] = { // content: 8, // revision 0, // classname 0, 0, // classinfo - 0, 0, // methods + 7, 14, // methods 0, 0, // properties 0, 0, // enums/sets 0, 0, // constructors 0, // flags 0, // signalCount + // slots: name, argc, parameters, tag, flags + 1, 1, 49, 2, 0x08 /* Private */, + 4, 0, 52, 2, 0x08 /* Private */, + 5, 0, 53, 2, 0x08 /* Private */, + 6, 0, 54, 2, 0x08 /* Private */, + 7, 0, 55, 2, 0x08 /* Private */, + 8, 0, 56, 2, 0x08 /* Private */, + 9, 2, 57, 2, 0x08 /* Private */, + + // slots: parameters + QMetaType::Void, QMetaType::Int, 3, + QMetaType::Void, + QMetaType::Void, + QMetaType::Void, + QMetaType::Void, + QMetaType::Void, + QMetaType::Void, QMetaType::Double, QMetaType::Double, 10, 11, + 0 // eod }; -void PathPlanningDialog::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) +void AreaCoverageDialog::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) { - (void)_o; - (void)_id; - (void)_c; - (void)_a; + if (_c == QMetaObject::InvokeMetaMethod) { + auto *_t = static_cast(_o); + (void)_t; + switch (_id) { + case 0: _t->onShapeChanged((*reinterpret_cast< int(*)>(_a[1]))); break; + case 1: _t->addVertex(); break; + case 2: _t->removeVertex(); break; + case 3: _t->selectVertexOnMap(); break; + case 4: _t->planCoveragePath(); break; + case 5: _t->clearCoverage(); break; + case 6: _t->onMapClick((*reinterpret_cast< double(*)>(_a[1])),(*reinterpret_cast< double(*)>(_a[2]))); break; + default: ; + } + } } -QT_INIT_METAOBJECT const QMetaObject PathPlanningDialog::staticMetaObject = { { +QT_INIT_METAOBJECT const QMetaObject AreaCoverageDialog::staticMetaObject = { { QMetaObject::SuperData::link(), - qt_meta_stringdata_PathPlanningDialog.data, - qt_meta_data_PathPlanningDialog, + qt_meta_stringdata_AreaCoverageDialog.data, + qt_meta_data_AreaCoverageDialog, qt_static_metacall, nullptr, nullptr } }; -const QMetaObject *PathPlanningDialog::metaObject() const +const QMetaObject *AreaCoverageDialog::metaObject() const { return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject; } -void *PathPlanningDialog::qt_metacast(const char *_clname) +void *AreaCoverageDialog::qt_metacast(const char *_clname) { if (!_clname) return nullptr; - if (!strcmp(_clname, qt_meta_stringdata_PathPlanningDialog.stringdata0)) + if (!strcmp(_clname, qt_meta_stringdata_AreaCoverageDialog.stringdata0)) return static_cast(this); return QDialog::qt_metacast(_clname); } -int PathPlanningDialog::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +int AreaCoverageDialog::qt_metacall(QMetaObject::Call _c, int _id, void **_a) { _id = QDialog::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + if (_id < 7) + qt_static_metacall(this, _c, _id, _a); + _id -= 7; + } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) { + if (_id < 7) + *reinterpret_cast(_a[0]) = -1; + _id -= 7; + } return _id; } struct qt_meta_stringdata_LocateDialog_t { @@ -420,8 +596,8 @@ int LocateDialog::qt_metacall(QMetaObject::Call _c, int _id, void **_a) return _id; } struct qt_meta_stringdata_MapPage_t { - QByteArrayData data[16]; - char stringdata0[249]; + QByteArrayData data[58]; + char stringdata0[826]; }; #define QT_MOC_LITERAL(idx, ofs, len) \ Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \ @@ -436,25 +612,81 @@ QT_MOC_LITERAL(2, 22, 0), // "" QT_MOC_LITERAL(3, 23, 6), // "height" QT_MOC_LITERAL(4, 30, 20), // "downloadMapRequested" QT_MOC_LITERAL(5, 51, 18), // "setThreatRequested" -QT_MOC_LITERAL(6, 70, 19), // "areaSearchRequested" -QT_MOC_LITERAL(7, 90, 21), // "pathPlanningRequested" -QT_MOC_LITERAL(8, 112, 15), // "onHeightChanged" -QT_MOC_LITERAL(9, 128, 20), // "onDownloadMapClicked" -QT_MOC_LITERAL(10, 149, 18), // "onSetThreatClicked" -QT_MOC_LITERAL(11, 168, 19), // "onAreaSearchClicked" -QT_MOC_LITERAL(12, 188, 21), // "onPathPlanningClicked" -QT_MOC_LITERAL(13, 210, 18), // "onSearchMapClicked" -QT_MOC_LITERAL(14, 229, 16), // "runMapJavaScript" -QT_MOC_LITERAL(15, 246, 2) // "js" +QT_MOC_LITERAL(6, 70, 21), // "pathPlanningRequested" +QT_MOC_LITERAL(7, 92, 21), // "areaCoverageRequested" +QT_MOC_LITERAL(8, 114, 10), // "mapClicked" +QT_MOC_LITERAL(9, 125, 3), // "lng" +QT_MOC_LITERAL(10, 129, 3), // "lat" +QT_MOC_LITERAL(11, 133, 8), // "mapReady" +QT_MOC_LITERAL(12, 142, 15), // "onHeightChanged" +QT_MOC_LITERAL(13, 158, 20), // "onDownloadMapClicked" +QT_MOC_LITERAL(14, 179, 18), // "onSetThreatClicked" +QT_MOC_LITERAL(15, 198, 21), // "onPathPlanningClicked" +QT_MOC_LITERAL(16, 220, 21), // "onAreaCoverageClicked" +QT_MOC_LITERAL(17, 242, 18), // "onSearchMapClicked" +QT_MOC_LITERAL(18, 261, 16), // "onConsoleMessage" +QT_MOC_LITERAL(19, 278, 45), // "QWebEnginePage::JavaScriptCon..." +QT_MOC_LITERAL(20, 324, 5), // "level" +QT_MOC_LITERAL(21, 330, 7), // "message" +QT_MOC_LITERAL(22, 338, 10), // "lineNumber" +QT_MOC_LITERAL(23, 349, 8), // "sourceID" +QT_MOC_LITERAL(24, 358, 12), // "onPageLoaded" +QT_MOC_LITERAL(25, 371, 2), // "ok" +QT_MOC_LITERAL(26, 374, 13), // "loadSavedPath" +QT_MOC_LITERAL(27, 388, 16), // "onMapReadyFromJS" +QT_MOC_LITERAL(28, 405, 16), // "addClickListener" +QT_MOC_LITERAL(29, 422, 19), // "removeClickListener" +QT_MOC_LITERAL(30, 442, 14), // "handleMapClick" +QT_MOC_LITERAL(31, 457, 13), // "visualizePath" +QT_MOC_LITERAL(32, 471, 8), // "pathData" +QT_MOC_LITERAL(33, 480, 17), // "clearPathOverlays" +QT_MOC_LITERAL(34, 498, 16), // "runMapJavaScript" +QT_MOC_LITERAL(35, 515, 2), // "js" +QT_MOC_LITERAL(36, 518, 8), // "parseLng" +QT_MOC_LITERAL(37, 527, 5), // "coord" +QT_MOC_LITERAL(38, 533, 8), // "parseLat" +QT_MOC_LITERAL(39, 542, 10), // "showMarker" +QT_MOC_LITERAL(40, 553, 5), // "label" +QT_MOC_LITERAL(41, 559, 5), // "color" +QT_MOC_LITERAL(42, 565, 5), // "index" +QT_MOC_LITERAL(43, 571, 21), // "visualizeCoveragePath" +QT_MOC_LITERAL(44, 593, 21), // "clearCoverageOverlays" +QT_MOC_LITERAL(45, 615, 27), // "visualizeCoverageAreaCircle" +QT_MOC_LITERAL(46, 643, 9), // "centerLng" +QT_MOC_LITERAL(47, 653, 9), // "centerLat" +QT_MOC_LITERAL(48, 663, 8), // "radiusKm" +QT_MOC_LITERAL(49, 672, 28), // "visualizeCoverageAreaPolygon" +QT_MOC_LITERAL(50, 701, 28), // "QList >" +QT_MOC_LITERAL(51, 730, 8), // "vertices" +QT_MOC_LITERAL(52, 739, 17), // "enableDrawingMode" +QT_MOC_LITERAL(53, 757, 5), // "shape" +QT_MOC_LITERAL(54, 763, 18), // "disableDrawingMode" +QT_MOC_LITERAL(55, 782, 16), // "addThreatOverlay" +QT_MOC_LITERAL(56, 799, 6), // "params" +QT_MOC_LITERAL(57, 806, 19) // "removeThreatOverlay" }, "MapPage\0heightChanged\0\0height\0" "downloadMapRequested\0setThreatRequested\0" - "areaSearchRequested\0pathPlanningRequested\0" - "onHeightChanged\0onDownloadMapClicked\0" - "onSetThreatClicked\0onAreaSearchClicked\0" - "onPathPlanningClicked\0onSearchMapClicked\0" - "runMapJavaScript\0js" + "pathPlanningRequested\0areaCoverageRequested\0" + "mapClicked\0lng\0lat\0mapReady\0onHeightChanged\0" + "onDownloadMapClicked\0onSetThreatClicked\0" + "onPathPlanningClicked\0onAreaCoverageClicked\0" + "onSearchMapClicked\0onConsoleMessage\0" + "QWebEnginePage::JavaScriptConsoleMessageLevel\0" + "level\0message\0lineNumber\0sourceID\0" + "onPageLoaded\0ok\0loadSavedPath\0" + "onMapReadyFromJS\0addClickListener\0" + "removeClickListener\0handleMapClick\0" + "visualizePath\0pathData\0clearPathOverlays\0" + "runMapJavaScript\0js\0parseLng\0coord\0" + "parseLat\0showMarker\0label\0color\0index\0" + "visualizeCoveragePath\0clearCoverageOverlays\0" + "visualizeCoverageAreaCircle\0centerLng\0" + "centerLat\0radiusKm\0visualizeCoverageAreaPolygon\0" + "QList >\0vertices\0" + "enableDrawingMode\0shape\0disableDrawingMode\0" + "addThreatOverlay\0params\0removeThreatOverlay" }; #undef QT_MOC_LITERAL @@ -464,28 +696,50 @@ static const uint qt_meta_data_MapPage[] = { 8, // revision 0, // classname 0, 0, // classinfo - 12, 14, // methods + 34, 14, // methods 0, 0, // properties 0, 0, // enums/sets 0, 0, // constructors 0, // flags - 5, // signalCount + 7, // signalCount // signals: name, argc, parameters, tag, flags - 1, 1, 74, 2, 0x06 /* Public */, - 4, 0, 77, 2, 0x06 /* Public */, - 5, 0, 78, 2, 0x06 /* Public */, - 6, 0, 79, 2, 0x06 /* Public */, - 7, 0, 80, 2, 0x06 /* Public */, + 1, 1, 184, 2, 0x06 /* Public */, + 4, 0, 187, 2, 0x06 /* Public */, + 5, 0, 188, 2, 0x06 /* Public */, + 6, 0, 189, 2, 0x06 /* Public */, + 7, 0, 190, 2, 0x06 /* Public */, + 8, 2, 191, 2, 0x06 /* Public */, + 11, 0, 196, 2, 0x06 /* Public */, // slots: name, argc, parameters, tag, flags - 8, 0, 81, 2, 0x08 /* Private */, - 9, 0, 82, 2, 0x08 /* Private */, - 10, 0, 83, 2, 0x08 /* Private */, - 11, 0, 84, 2, 0x08 /* Private */, - 12, 0, 85, 2, 0x08 /* Private */, - 13, 0, 86, 2, 0x08 /* Private */, - 14, 1, 87, 2, 0x0a /* Public */, + 12, 0, 197, 2, 0x08 /* Private */, + 13, 0, 198, 2, 0x08 /* Private */, + 14, 0, 199, 2, 0x08 /* Private */, + 15, 0, 200, 2, 0x08 /* Private */, + 16, 0, 201, 2, 0x08 /* Private */, + 17, 0, 202, 2, 0x08 /* Private */, + 18, 4, 203, 2, 0x08 /* Private */, + 24, 1, 212, 2, 0x08 /* Private */, + 26, 0, 215, 2, 0x08 /* Private */, + 27, 0, 216, 2, 0x08 /* Private */, + 28, 0, 217, 2, 0x0a /* Public */, + 29, 0, 218, 2, 0x0a /* Public */, + 30, 2, 219, 2, 0x0a /* Public */, + 31, 1, 224, 2, 0x0a /* Public */, + 33, 0, 227, 2, 0x0a /* Public */, + 34, 1, 228, 2, 0x0a /* Public */, + 36, 1, 231, 2, 0x0a /* Public */, + 38, 1, 234, 2, 0x0a /* Public */, + 39, 5, 237, 2, 0x0a /* Public */, + 43, 1, 248, 2, 0x0a /* Public */, + 44, 0, 251, 2, 0x0a /* Public */, + 45, 3, 252, 2, 0x0a /* Public */, + 49, 1, 259, 2, 0x0a /* Public */, + 52, 1, 262, 2, 0x0a /* Public */, + 54, 0, 265, 2, 0x0a /* Public */, + 55, 2, 266, 2, 0x0a /* Public */, + 57, 1, 271, 2, 0x0a /* Public */, // signals: parameters QMetaType::Void, QMetaType::QString, 3, @@ -493,6 +747,8 @@ static const uint qt_meta_data_MapPage[] = { QMetaType::Void, QMetaType::Void, QMetaType::Void, + QMetaType::Void, QMetaType::Double, QMetaType::Double, 9, 10, + QMetaType::Void, // slots: parameters QMetaType::Void, @@ -501,7 +757,27 @@ static const uint qt_meta_data_MapPage[] = { QMetaType::Void, QMetaType::Void, QMetaType::Void, - QMetaType::Void, QMetaType::QString, 15, + QMetaType::Void, 0x80000000 | 19, QMetaType::QString, QMetaType::Int, QMetaType::QString, 20, 21, 22, 23, + QMetaType::Void, QMetaType::Bool, 25, + QMetaType::Void, + QMetaType::Void, + QMetaType::Void, + QMetaType::Void, + QMetaType::Void, QMetaType::Double, QMetaType::Double, 9, 10, + QMetaType::Void, QMetaType::QString, 32, + QMetaType::Void, + QMetaType::Void, QMetaType::QString, 35, + QMetaType::Double, QMetaType::QString, 37, + QMetaType::Double, QMetaType::QString, 37, + QMetaType::Void, QMetaType::Double, QMetaType::Double, QMetaType::QString, QMetaType::QString, QMetaType::Int, 9, 10, 40, 41, 42, + QMetaType::Void, QMetaType::QString, 32, + QMetaType::Void, + QMetaType::Void, QMetaType::Double, QMetaType::Double, QMetaType::Double, 46, 47, 48, + QMetaType::Void, 0x80000000 | 50, 51, + QMetaType::Void, QMetaType::QString, 53, + QMetaType::Void, + QMetaType::Void, QMetaType::QString, QMetaType::QVariantMap, 53, 56, + QMetaType::Void, QMetaType::Int, 42, 0 // eod }; @@ -515,15 +791,39 @@ void MapPage::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, voi case 0: _t->heightChanged((*reinterpret_cast< const QString(*)>(_a[1]))); break; case 1: _t->downloadMapRequested(); break; case 2: _t->setThreatRequested(); break; - case 3: _t->areaSearchRequested(); break; - case 4: _t->pathPlanningRequested(); break; - case 5: _t->onHeightChanged(); break; - case 6: _t->onDownloadMapClicked(); break; - case 7: _t->onSetThreatClicked(); break; - case 8: _t->onAreaSearchClicked(); break; - case 9: _t->onPathPlanningClicked(); break; - case 10: _t->onSearchMapClicked(); break; - case 11: _t->runMapJavaScript((*reinterpret_cast< const QString(*)>(_a[1]))); break; + case 3: _t->pathPlanningRequested(); break; + case 4: _t->areaCoverageRequested(); break; + case 5: _t->mapClicked((*reinterpret_cast< double(*)>(_a[1])),(*reinterpret_cast< double(*)>(_a[2]))); break; + case 6: _t->mapReady(); break; + case 7: _t->onHeightChanged(); break; + case 8: _t->onDownloadMapClicked(); break; + case 9: _t->onSetThreatClicked(); break; + case 10: _t->onPathPlanningClicked(); break; + case 11: _t->onAreaCoverageClicked(); break; + case 12: _t->onSearchMapClicked(); break; + case 13: _t->onConsoleMessage((*reinterpret_cast< QWebEnginePage::JavaScriptConsoleMessageLevel(*)>(_a[1])),(*reinterpret_cast< const QString(*)>(_a[2])),(*reinterpret_cast< int(*)>(_a[3])),(*reinterpret_cast< const QString(*)>(_a[4]))); break; + case 14: _t->onPageLoaded((*reinterpret_cast< bool(*)>(_a[1]))); break; + case 15: _t->loadSavedPath(); break; + case 16: _t->onMapReadyFromJS(); break; + case 17: _t->addClickListener(); break; + case 18: _t->removeClickListener(); break; + case 19: _t->handleMapClick((*reinterpret_cast< double(*)>(_a[1])),(*reinterpret_cast< double(*)>(_a[2]))); break; + case 20: _t->visualizePath((*reinterpret_cast< const QString(*)>(_a[1]))); break; + case 21: _t->clearPathOverlays(); break; + case 22: _t->runMapJavaScript((*reinterpret_cast< const QString(*)>(_a[1]))); break; + case 23: { double _r = _t->parseLng((*reinterpret_cast< const QString(*)>(_a[1]))); + if (_a[0]) *reinterpret_cast< double*>(_a[0]) = std::move(_r); } break; + case 24: { double _r = _t->parseLat((*reinterpret_cast< const QString(*)>(_a[1]))); + if (_a[0]) *reinterpret_cast< double*>(_a[0]) = std::move(_r); } break; + case 25: _t->showMarker((*reinterpret_cast< double(*)>(_a[1])),(*reinterpret_cast< double(*)>(_a[2])),(*reinterpret_cast< const QString(*)>(_a[3])),(*reinterpret_cast< const QString(*)>(_a[4])),(*reinterpret_cast< int(*)>(_a[5]))); break; + case 26: _t->visualizeCoveragePath((*reinterpret_cast< const QString(*)>(_a[1]))); break; + case 27: _t->clearCoverageOverlays(); break; + case 28: _t->visualizeCoverageAreaCircle((*reinterpret_cast< double(*)>(_a[1])),(*reinterpret_cast< double(*)>(_a[2])),(*reinterpret_cast< double(*)>(_a[3]))); break; + case 29: _t->visualizeCoverageAreaPolygon((*reinterpret_cast< const QList >(*)>(_a[1]))); break; + case 30: _t->enableDrawingMode((*reinterpret_cast< const QString(*)>(_a[1]))); break; + case 31: _t->disableDrawingMode(); break; + case 32: _t->addThreatOverlay((*reinterpret_cast< const QString(*)>(_a[1])),(*reinterpret_cast< const QVariantMap(*)>(_a[2]))); break; + case 33: _t->removeThreatOverlay((*reinterpret_cast< int(*)>(_a[1]))); break; default: ; } } else if (_c == QMetaObject::IndexOfMethod) { @@ -551,18 +851,32 @@ void MapPage::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, voi } { using _t = void (MapPage::*)(); - if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&MapPage::areaSearchRequested)) { + if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&MapPage::pathPlanningRequested)) { *result = 3; return; } } { using _t = void (MapPage::*)(); - if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&MapPage::pathPlanningRequested)) { + if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&MapPage::areaCoverageRequested)) { *result = 4; return; } } + { + using _t = void (MapPage::*)(double , double ); + if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&MapPage::mapClicked)) { + *result = 5; + return; + } + } + { + using _t = void (MapPage::*)(); + if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&MapPage::mapReady)) { + *result = 6; + return; + } + } } } @@ -595,13 +909,13 @@ int MapPage::qt_metacall(QMetaObject::Call _c, int _id, void **_a) if (_id < 0) return _id; if (_c == QMetaObject::InvokeMetaMethod) { - if (_id < 12) + if (_id < 34) qt_static_metacall(this, _c, _id, _a); - _id -= 12; + _id -= 34; } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) { - if (_id < 12) + if (_id < 34) *reinterpret_cast(_a[0]) = -1; - _id -= 12; + _id -= 34; } return _id; } @@ -626,15 +940,28 @@ void MapPage::setThreatRequested() } // SIGNAL 3 -void MapPage::areaSearchRequested() +void MapPage::pathPlanningRequested() { QMetaObject::activate(this, &staticMetaObject, 3, nullptr); } // SIGNAL 4 -void MapPage::pathPlanningRequested() +void MapPage::areaCoverageRequested() { QMetaObject::activate(this, &staticMetaObject, 4, nullptr); } + +// SIGNAL 5 +void MapPage::mapClicked(double _t1, double _t2) +{ + void *_a[] = { nullptr, const_cast(reinterpret_cast(std::addressof(_t1))), const_cast(reinterpret_cast(std::addressof(_t2))) }; + QMetaObject::activate(this, &staticMetaObject, 5, _a); +} + +// SIGNAL 6 +void MapPage::mapReady() +{ + QMetaObject::activate(this, &staticMetaObject, 6, nullptr); +} QT_WARNING_POP QT_END_MOC_NAMESPACE diff --git a/build/moc_mappage.o b/build/moc_mappage.o index 3e98f0a..6ad3c93 100644 Binary files a/build/moc_mappage.o and b/build/moc_mappage.o differ diff --git a/build/moc_taskdata.cpp b/build/moc_taskdata.cpp new file mode 100644 index 0000000..f57f40c --- /dev/null +++ b/build/moc_taskdata.cpp @@ -0,0 +1,376 @@ +/**************************************************************************** +** Meta object code from reading C++ file 'taskdata.h' +** +** Created by: The Qt Meta Object Compiler version 67 (Qt 5.15.3) +** +** WARNING! All changes made in this file will be lost! +*****************************************************************************/ + +#include +#include "../Src/pages/taskdata.h" +#include +#include +#if !defined(Q_MOC_OUTPUT_REVISION) +#error "The header file 'taskdata.h' doesn't include ." +#elif Q_MOC_OUTPUT_REVISION != 67 +#error "This file was generated using the moc from 5.15.3. It" +#error "cannot be used with the include files from this version of Qt." +#error "(The moc has changed too much.)" +#endif + +QT_BEGIN_MOC_NAMESPACE +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED +struct qt_meta_stringdata_TaskData_t { + QByteArrayData data[11]; + char stringdata0[113]; +}; +#define QT_MOC_LITERAL(idx, ofs, len) \ + Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \ + qptrdiff(offsetof(qt_meta_stringdata_TaskData_t, stringdata0) + ofs \ + - idx * sizeof(QByteArrayData)) \ + ) +static const qt_meta_stringdata_TaskData_t qt_meta_stringdata_TaskData = { + { +QT_MOC_LITERAL(0, 0, 8), // "TaskData" +QT_MOC_LITERAL(1, 9, 13), // "statusChanged" +QT_MOC_LITERAL(2, 23, 0), // "" +QT_MOC_LITERAL(3, 24, 10), // "TaskStatus" +QT_MOC_LITERAL(4, 35, 6), // "status" +QT_MOC_LITERAL(5, 42, 11), // "taskStarted" +QT_MOC_LITERAL(6, 54, 13), // "taskCompleted" +QT_MOC_LITERAL(7, 68, 13), // "taskCancelled" +QT_MOC_LITERAL(8, 82, 10), // "taskFailed" +QT_MOC_LITERAL(9, 93, 6), // "reason" +QT_MOC_LITERAL(10, 100, 12) // "taskRecalled" + + }, + "TaskData\0statusChanged\0\0TaskStatus\0" + "status\0taskStarted\0taskCompleted\0" + "taskCancelled\0taskFailed\0reason\0" + "taskRecalled" +}; +#undef QT_MOC_LITERAL + +static const uint qt_meta_data_TaskData[] = { + + // content: + 8, // revision + 0, // classname + 0, 0, // classinfo + 6, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 6, // signalCount + + // signals: name, argc, parameters, tag, flags + 1, 1, 44, 2, 0x06 /* Public */, + 5, 0, 47, 2, 0x06 /* Public */, + 6, 0, 48, 2, 0x06 /* Public */, + 7, 0, 49, 2, 0x06 /* Public */, + 8, 1, 50, 2, 0x06 /* Public */, + 10, 0, 53, 2, 0x06 /* Public */, + + // signals: parameters + QMetaType::Void, 0x80000000 | 3, 4, + QMetaType::Void, + QMetaType::Void, + QMetaType::Void, + QMetaType::Void, QMetaType::QString, 9, + QMetaType::Void, + + 0 // eod +}; + +void TaskData::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) +{ + if (_c == QMetaObject::InvokeMetaMethod) { + auto *_t = static_cast(_o); + (void)_t; + switch (_id) { + case 0: _t->statusChanged((*reinterpret_cast< TaskStatus(*)>(_a[1]))); break; + case 1: _t->taskStarted(); break; + case 2: _t->taskCompleted(); break; + case 3: _t->taskCancelled(); break; + case 4: _t->taskFailed((*reinterpret_cast< const QString(*)>(_a[1]))); break; + case 5: _t->taskRecalled(); break; + default: ; + } + } else if (_c == QMetaObject::IndexOfMethod) { + int *result = reinterpret_cast(_a[0]); + { + using _t = void (TaskData::*)(TaskStatus ); + if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&TaskData::statusChanged)) { + *result = 0; + return; + } + } + { + using _t = void (TaskData::*)(); + if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&TaskData::taskStarted)) { + *result = 1; + return; + } + } + { + using _t = void (TaskData::*)(); + if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&TaskData::taskCompleted)) { + *result = 2; + return; + } + } + { + using _t = void (TaskData::*)(); + if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&TaskData::taskCancelled)) { + *result = 3; + return; + } + } + { + using _t = void (TaskData::*)(const QString & ); + if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&TaskData::taskFailed)) { + *result = 4; + return; + } + } + { + using _t = void (TaskData::*)(); + if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&TaskData::taskRecalled)) { + *result = 5; + return; + } + } + } +} + +QT_INIT_METAOBJECT const QMetaObject TaskData::staticMetaObject = { { + QMetaObject::SuperData::link(), + qt_meta_stringdata_TaskData.data, + qt_meta_data_TaskData, + qt_static_metacall, + nullptr, + nullptr +} }; + + +const QMetaObject *TaskData::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject; +} + +void *TaskData::qt_metacast(const char *_clname) +{ + if (!_clname) return nullptr; + if (!strcmp(_clname, qt_meta_stringdata_TaskData.stringdata0)) + return static_cast(this); + return QObject::qt_metacast(_clname); +} + +int TaskData::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + if (_id < 6) + qt_static_metacall(this, _c, _id, _a); + _id -= 6; + } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) { + if (_id < 6) + *reinterpret_cast(_a[0]) = -1; + _id -= 6; + } + return _id; +} + +// SIGNAL 0 +void TaskData::statusChanged(TaskStatus _t1) +{ + void *_a[] = { nullptr, const_cast(reinterpret_cast(std::addressof(_t1))) }; + QMetaObject::activate(this, &staticMetaObject, 0, _a); +} + +// SIGNAL 1 +void TaskData::taskStarted() +{ + QMetaObject::activate(this, &staticMetaObject, 1, nullptr); +} + +// SIGNAL 2 +void TaskData::taskCompleted() +{ + QMetaObject::activate(this, &staticMetaObject, 2, nullptr); +} + +// SIGNAL 3 +void TaskData::taskCancelled() +{ + QMetaObject::activate(this, &staticMetaObject, 3, nullptr); +} + +// SIGNAL 4 +void TaskData::taskFailed(const QString & _t1) +{ + void *_a[] = { nullptr, const_cast(reinterpret_cast(std::addressof(_t1))) }; + QMetaObject::activate(this, &staticMetaObject, 4, _a); +} + +// SIGNAL 5 +void TaskData::taskRecalled() +{ + QMetaObject::activate(this, &staticMetaObject, 5, nullptr); +} +struct qt_meta_stringdata_TaskManager_t { + QByteArrayData data[8]; + char stringdata0[80]; +}; +#define QT_MOC_LITERAL(idx, ofs, len) \ + Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \ + qptrdiff(offsetof(qt_meta_stringdata_TaskManager_t, stringdata0) + ofs \ + - idx * sizeof(QByteArrayData)) \ + ) +static const qt_meta_stringdata_TaskManager_t qt_meta_stringdata_TaskManager = { + { +QT_MOC_LITERAL(0, 0, 11), // "TaskManager" +QT_MOC_LITERAL(1, 12, 11), // "taskCreated" +QT_MOC_LITERAL(2, 24, 0), // "" +QT_MOC_LITERAL(3, 25, 6), // "taskId" +QT_MOC_LITERAL(4, 32, 11), // "taskRemoved" +QT_MOC_LITERAL(5, 44, 17), // "taskStatusChanged" +QT_MOC_LITERAL(6, 62, 10), // "TaskStatus" +QT_MOC_LITERAL(7, 73, 6) // "status" + + }, + "TaskManager\0taskCreated\0\0taskId\0" + "taskRemoved\0taskStatusChanged\0TaskStatus\0" + "status" +}; +#undef QT_MOC_LITERAL + +static const uint qt_meta_data_TaskManager[] = { + + // content: + 8, // revision + 0, // classname + 0, 0, // classinfo + 3, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 3, // signalCount + + // signals: name, argc, parameters, tag, flags + 1, 1, 29, 2, 0x06 /* Public */, + 4, 1, 32, 2, 0x06 /* Public */, + 5, 2, 35, 2, 0x06 /* Public */, + + // signals: parameters + QMetaType::Void, QMetaType::QString, 3, + QMetaType::Void, QMetaType::QString, 3, + QMetaType::Void, QMetaType::QString, 0x80000000 | 6, 3, 7, + + 0 // eod +}; + +void TaskManager::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) +{ + if (_c == QMetaObject::InvokeMetaMethod) { + auto *_t = static_cast(_o); + (void)_t; + switch (_id) { + case 0: _t->taskCreated((*reinterpret_cast< const QString(*)>(_a[1]))); break; + case 1: _t->taskRemoved((*reinterpret_cast< const QString(*)>(_a[1]))); break; + case 2: _t->taskStatusChanged((*reinterpret_cast< const QString(*)>(_a[1])),(*reinterpret_cast< TaskStatus(*)>(_a[2]))); break; + default: ; + } + } else if (_c == QMetaObject::IndexOfMethod) { + int *result = reinterpret_cast(_a[0]); + { + using _t = void (TaskManager::*)(const QString & ); + if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&TaskManager::taskCreated)) { + *result = 0; + return; + } + } + { + using _t = void (TaskManager::*)(const QString & ); + if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&TaskManager::taskRemoved)) { + *result = 1; + return; + } + } + { + using _t = void (TaskManager::*)(const QString & , TaskStatus ); + if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&TaskManager::taskStatusChanged)) { + *result = 2; + return; + } + } + } +} + +QT_INIT_METAOBJECT const QMetaObject TaskManager::staticMetaObject = { { + QMetaObject::SuperData::link(), + qt_meta_stringdata_TaskManager.data, + qt_meta_data_TaskManager, + qt_static_metacall, + nullptr, + nullptr +} }; + + +const QMetaObject *TaskManager::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject; +} + +void *TaskManager::qt_metacast(const char *_clname) +{ + if (!_clname) return nullptr; + if (!strcmp(_clname, qt_meta_stringdata_TaskManager.stringdata0)) + return static_cast(this); + return QObject::qt_metacast(_clname); +} + +int TaskManager::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QObject::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + if (_id < 3) + qt_static_metacall(this, _c, _id, _a); + _id -= 3; + } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) { + if (_id < 3) + *reinterpret_cast(_a[0]) = -1; + _id -= 3; + } + return _id; +} + +// SIGNAL 0 +void TaskManager::taskCreated(const QString & _t1) +{ + void *_a[] = { nullptr, const_cast(reinterpret_cast(std::addressof(_t1))) }; + QMetaObject::activate(this, &staticMetaObject, 0, _a); +} + +// SIGNAL 1 +void TaskManager::taskRemoved(const QString & _t1) +{ + void *_a[] = { nullptr, const_cast(reinterpret_cast(std::addressof(_t1))) }; + QMetaObject::activate(this, &staticMetaObject, 1, _a); +} + +// SIGNAL 2 +void TaskManager::taskStatusChanged(const QString & _t1, TaskStatus _t2) +{ + void *_a[] = { nullptr, const_cast(reinterpret_cast(std::addressof(_t1))), const_cast(reinterpret_cast(std::addressof(_t2))) }; + QMetaObject::activate(this, &staticMetaObject, 2, _a); +} +QT_WARNING_POP +QT_END_MOC_NAMESPACE diff --git a/build/moc_taskdata.o b/build/moc_taskdata.o new file mode 100644 index 0000000..a07e500 Binary files /dev/null and b/build/moc_taskdata.o differ diff --git a/build/moc_taskdecisionpage.cpp b/build/moc_taskdecisionpage.cpp index a2d51a6..89bc4c2 100644 --- a/build/moc_taskdecisionpage.cpp +++ b/build/moc_taskdecisionpage.cpp @@ -7,7 +7,7 @@ *****************************************************************************/ #include -#include "../src/pages/taskdecisionpage.h" +#include "../Src/pages/taskdecisionpage.h" #include #include #if !defined(Q_MOC_OUTPUT_REVISION) diff --git a/build/moc_taskdecisionpage.o b/build/moc_taskdecisionpage.o index 19f21a3..2eeb2ef 100644 Binary files a/build/moc_taskdecisionpage.o and b/build/moc_taskdecisionpage.o differ diff --git a/build/moc_taskdetailspage.cpp b/build/moc_taskdetailspage.cpp new file mode 100644 index 0000000..d81bd4d --- /dev/null +++ b/build/moc_taskdetailspage.cpp @@ -0,0 +1,188 @@ +/**************************************************************************** +** Meta object code from reading C++ file 'taskdetailspage.h' +** +** Created by: The Qt Meta Object Compiler version 67 (Qt 5.15.3) +** +** WARNING! All changes made in this file will be lost! +*****************************************************************************/ + +#include +#include "../Src/pages/taskdetailspage.h" +#include +#include +#if !defined(Q_MOC_OUTPUT_REVISION) +#error "The header file 'taskdetailspage.h' doesn't include ." +#elif Q_MOC_OUTPUT_REVISION != 67 +#error "This file was generated using the moc from 5.15.3. It" +#error "cannot be used with the include files from this version of Qt." +#error "(The moc has changed too much.)" +#endif + +QT_BEGIN_MOC_NAMESPACE +QT_WARNING_PUSH +QT_WARNING_DISABLE_DEPRECATED +struct qt_meta_stringdata_TaskDetailsPage_t { + QByteArrayData data[17]; + char stringdata0[260]; +}; +#define QT_MOC_LITERAL(idx, ofs, len) \ + Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \ + qptrdiff(offsetof(qt_meta_stringdata_TaskDetailsPage_t, stringdata0) + ofs \ + - idx * sizeof(QByteArrayData)) \ + ) +static const qt_meta_stringdata_TaskDetailsPage_t qt_meta_stringdata_TaskDetailsPage = { + { +QT_MOC_LITERAL(0, 0, 15), // "TaskDetailsPage" +QT_MOC_LITERAL(1, 16, 19), // "taskActionRequested" +QT_MOC_LITERAL(2, 36, 0), // "" +QT_MOC_LITERAL(3, 37, 6), // "taskId" +QT_MOC_LITERAL(4, 44, 6), // "action" +QT_MOC_LITERAL(5, 51, 14), // "onRefreshTasks" +QT_MOC_LITERAL(6, 66, 15), // "onFilterChanged" +QT_MOC_LITERAL(7, 82, 22), // "onTaskSelectionChanged" +QT_MOC_LITERAL(8, 105, 18), // "onStartTaskClicked" +QT_MOC_LITERAL(9, 124, 21), // "onCompleteTaskClicked" +QT_MOC_LITERAL(10, 146, 19), // "onCancelTaskClicked" +QT_MOC_LITERAL(11, 166, 17), // "onFailTaskClicked" +QT_MOC_LITERAL(12, 184, 19), // "onRecallTaskClicked" +QT_MOC_LITERAL(13, 204, 19), // "onTaskStatusChanged" +QT_MOC_LITERAL(14, 224, 10), // "TaskStatus" +QT_MOC_LITERAL(15, 235, 6), // "status" +QT_MOC_LITERAL(16, 242, 17) // "onTaskDataChanged" + + }, + "TaskDetailsPage\0taskActionRequested\0" + "\0taskId\0action\0onRefreshTasks\0" + "onFilterChanged\0onTaskSelectionChanged\0" + "onStartTaskClicked\0onCompleteTaskClicked\0" + "onCancelTaskClicked\0onFailTaskClicked\0" + "onRecallTaskClicked\0onTaskStatusChanged\0" + "TaskStatus\0status\0onTaskDataChanged" +}; +#undef QT_MOC_LITERAL + +static const uint qt_meta_data_TaskDetailsPage[] = { + + // content: + 8, // revision + 0, // classname + 0, 0, // classinfo + 11, 14, // methods + 0, 0, // properties + 0, 0, // enums/sets + 0, 0, // constructors + 0, // flags + 1, // signalCount + + // signals: name, argc, parameters, tag, flags + 1, 2, 69, 2, 0x06 /* Public */, + + // slots: name, argc, parameters, tag, flags + 5, 0, 74, 2, 0x08 /* Private */, + 6, 0, 75, 2, 0x08 /* Private */, + 7, 0, 76, 2, 0x08 /* Private */, + 8, 0, 77, 2, 0x08 /* Private */, + 9, 0, 78, 2, 0x08 /* Private */, + 10, 0, 79, 2, 0x08 /* Private */, + 11, 0, 80, 2, 0x08 /* Private */, + 12, 0, 81, 2, 0x08 /* Private */, + 13, 2, 82, 2, 0x08 /* Private */, + 16, 0, 87, 2, 0x08 /* Private */, + + // signals: parameters + QMetaType::Void, QMetaType::QString, QMetaType::QString, 3, 4, + + // slots: parameters + QMetaType::Void, + QMetaType::Void, + QMetaType::Void, + QMetaType::Void, + QMetaType::Void, + QMetaType::Void, + QMetaType::Void, + QMetaType::Void, + QMetaType::Void, QMetaType::QString, 0x80000000 | 14, 3, 15, + QMetaType::Void, + + 0 // eod +}; + +void TaskDetailsPage::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) +{ + if (_c == QMetaObject::InvokeMetaMethod) { + auto *_t = static_cast(_o); + (void)_t; + switch (_id) { + case 0: _t->taskActionRequested((*reinterpret_cast< const QString(*)>(_a[1])),(*reinterpret_cast< const QString(*)>(_a[2]))); break; + case 1: _t->onRefreshTasks(); break; + case 2: _t->onFilterChanged(); break; + case 3: _t->onTaskSelectionChanged(); break; + case 4: _t->onStartTaskClicked(); break; + case 5: _t->onCompleteTaskClicked(); break; + case 6: _t->onCancelTaskClicked(); break; + case 7: _t->onFailTaskClicked(); break; + case 8: _t->onRecallTaskClicked(); break; + case 9: _t->onTaskStatusChanged((*reinterpret_cast< const QString(*)>(_a[1])),(*reinterpret_cast< TaskStatus(*)>(_a[2]))); break; + case 10: _t->onTaskDataChanged(); break; + default: ; + } + } else if (_c == QMetaObject::IndexOfMethod) { + int *result = reinterpret_cast(_a[0]); + { + using _t = void (TaskDetailsPage::*)(const QString & , const QString & ); + if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&TaskDetailsPage::taskActionRequested)) { + *result = 0; + return; + } + } + } +} + +QT_INIT_METAOBJECT const QMetaObject TaskDetailsPage::staticMetaObject = { { + QMetaObject::SuperData::link(), + qt_meta_stringdata_TaskDetailsPage.data, + qt_meta_data_TaskDetailsPage, + qt_static_metacall, + nullptr, + nullptr +} }; + + +const QMetaObject *TaskDetailsPage::metaObject() const +{ + return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject; +} + +void *TaskDetailsPage::qt_metacast(const char *_clname) +{ + if (!_clname) return nullptr; + if (!strcmp(_clname, qt_meta_stringdata_TaskDetailsPage.stringdata0)) + return static_cast(this); + return QWidget::qt_metacast(_clname); +} + +int TaskDetailsPage::qt_metacall(QMetaObject::Call _c, int _id, void **_a) +{ + _id = QWidget::qt_metacall(_c, _id, _a); + if (_id < 0) + return _id; + if (_c == QMetaObject::InvokeMetaMethod) { + if (_id < 11) + qt_static_metacall(this, _c, _id, _a); + _id -= 11; + } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) { + if (_id < 11) + *reinterpret_cast(_a[0]) = -1; + _id -= 11; + } + return _id; +} + +// SIGNAL 0 +void TaskDetailsPage::taskActionRequested(const QString & _t1, const QString & _t2) +{ + void *_a[] = { nullptr, const_cast(reinterpret_cast(std::addressof(_t1))), const_cast(reinterpret_cast(std::addressof(_t2))) }; + QMetaObject::activate(this, &staticMetaObject, 0, _a); +} +QT_WARNING_POP +QT_END_MOC_NAMESPACE diff --git a/build/moc_taskdetailspage.o b/build/moc_taskdetailspage.o new file mode 100644 index 0000000..e08b2d3 Binary files /dev/null and b/build/moc_taskdetailspage.o differ diff --git a/build/moc_videopage.cpp b/build/moc_videopage.cpp index 3c255c5..5eb9652 100644 --- a/build/moc_videopage.cpp +++ b/build/moc_videopage.cpp @@ -7,7 +7,7 @@ *****************************************************************************/ #include -#include "../src/pages/videopage.h" +#include "../Src/pages/videopage.h" #include #include #if !defined(Q_MOC_OUTPUT_REVISION) diff --git a/build/moc_videopage.o b/build/moc_videopage.o index 9d4ec43..8962613 100644 Binary files a/build/moc_videopage.o and b/build/moc_videopage.o differ diff --git a/build/moc_visionmodelpage.cpp b/build/moc_visionmodelpage.cpp index baafe4f..70e4391 100644 --- a/build/moc_visionmodelpage.cpp +++ b/build/moc_visionmodelpage.cpp @@ -7,7 +7,7 @@ *****************************************************************************/ #include -#include "../src/pages/visionmodelpage.h" +#include "../Src/pages/visionmodelpage.h" #include #include #if !defined(Q_MOC_OUTPUT_REVISION) diff --git a/build/moc_visionmodelpage.o b/build/moc_visionmodelpage.o index c1c41d4..eeaa199 100644 Binary files a/build/moc_visionmodelpage.o and b/build/moc_visionmodelpage.o differ diff --git a/build/qrc_app.o b/build/qrc_app.o index 853f7aa..5294d65 100644 Binary files a/build/qrc_app.o and b/build/qrc_app.o differ diff --git a/build/stylehelper.o b/build/stylehelper.o index d67c70f..1c2fea1 100644 Binary files a/build/stylehelper.o and b/build/stylehelper.o differ diff --git a/build/taskdata.o b/build/taskdata.o new file mode 100644 index 0000000..00377ab Binary files /dev/null and b/build/taskdata.o differ diff --git a/build/taskdecisionpage.o b/build/taskdecisionpage.o index 83f9b2e..0ab544e 100644 Binary files a/build/taskdecisionpage.o and b/build/taskdecisionpage.o differ diff --git a/build/taskdetailspage.o b/build/taskdetailspage.o new file mode 100644 index 0000000..4a6eb2a Binary files /dev/null and b/build/taskdetailspage.o differ diff --git a/build/videopage.o b/build/videopage.o index c362875..e3ef047 100644 Binary files a/build/videopage.o and b/build/videopage.o differ diff --git a/build/visionmodelpage.o b/build/visionmodelpage.o index 7dbc4d7..94751fb 100644 Binary files a/build/visionmodelpage.o and b/build/visionmodelpage.o differ diff --git a/debug_location.sh b/debug_location.sh deleted file mode 100755 index e24a5ca..0000000 --- a/debug_location.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash - -echo "=== 运行Drone_project并捕获所有日志 ===" -echo "程序将在15秒后自动停止" -echo "" - -# 先运行程序看看所有输出 -timeout 15s ./build/Drone_project 2>&1 | tee /tmp/drone_output.log - -echo "" -echo "=== 查找定位相关日志 ===" -grep -E "(🗺️|📍|🔐|🌐|✅|❌|🏠|👂|MapPage|地图|定位|GPS|IP|北京|坐标|JS|INFO|WARN|ERROR|qDebug)" /tmp/drone_output.log || echo "未找到定位相关日志" - -echo "" -echo "=== 显示前20行日志 ===" -head -20 /tmp/drone_output.log - -echo "" -echo "=== 调试完成 ===" diff --git a/drone_ui b/drone_ui deleted file mode 100644 index 9765119..0000000 Binary files a/drone_ui and /dev/null differ diff --git a/drone_ui.pro b/drone_ui.pro index f7b4454..a668a42 100644 --- a/drone_ui.pro +++ b/drone_ui.pro @@ -1,36 +1,44 @@ -QT += core widgets webenginewidgets positioning +QT += core widgets webenginewidgets positioning webchannel CONFIG += c++17 TEMPLATE = app TARGET = Drone_project SOURCES += \ - src/core/main.cpp \ - src/ui/mainwindow.cpp \ - src/models/dronedata.cpp \ - src/models/detectiondata.cpp \ - src/pages/videopage.cpp \ - src/pages/mappage.cpp \ - src/pages/datapage.cpp \ - src/pages/visionmodelpage.cpp \ - src/utils/stylehelper.cpp \ - src/pages/taskdecisionpage.cpp \ - src/utils/config.cpp \ - src/utils/logger.cpp \ - src/utils/errorhandler.cpp + Src/core/main.cpp \ + Src/ui/mainwindow.cpp \ + Src/models/dronedata.cpp \ + Src/models/detectiondata.cpp \ + Src/pages/videopage.cpp \ + Src/pages/mappage.cpp \ + Src/pages/mapbridge.cpp \ + Src/pages/datapage.cpp \ + Src/pages/taskdata.cpp \ + Src/pages/visionmodelpage.cpp \ + Src/utils/stylehelper.cpp \ + Src/pages/taskdecisionpage.cpp \ + Src/pages/dronemanagementpage.cpp \ + Src/pages/taskdetailspage.cpp \ + Src/utils/config.cpp \ + Src/utils/logger.cpp \ + Src/utils/errorhandler.cpp HEADERS += \ - src/ui/mainwindow.h \ - src/models/dronedata.h \ - src/models/detectiondata.h \ - src/pages/videopage.h \ - src/pages/mappage.h \ - src/pages/datapage.h \ - src/pages/visionmodelpage.h \ - src/utils/stylehelper.h \ - src/pages/taskdecisionpage.h \ - src/utils/config.h \ - src/utils/logger.h \ - src/utils/errorhandler.h + Src/ui/mainwindow.h \ + Src/models/dronedata.h \ + Src/models/detectiondata.h \ + Src/pages/videopage.h \ + Src/pages/mappage.h \ + Src/pages/mapbridge.h \ + Src/pages/datapage.h \ + Src/pages/taskdata.h \ + Src/pages/visionmodelpage.h \ + Src/utils/stylehelper.h \ + Src/pages/taskdecisionpage.h \ + Src/pages/dronemanagementpage.h \ + Src/pages/taskdetailspage.h \ + Src/utils/config.h \ + Src/utils/logger.h \ + Src/utils/errorhandler.h RESOURCES += \ - src/resources/app.qrc + Src/resources/app.qrc diff --git a/drone_ui.pro.user b/drone_ui.pro.user deleted file mode 100644 index a29a861..0000000 --- a/drone_ui.pro.user +++ /dev/null @@ -1,271 +0,0 @@ - - - - - - EnvironmentId - {d6548bba-c6d9-4cdb-a6a4-a3221e622b53} - - - ProjectExplorer.Project.ActiveTarget - 0 - - - ProjectExplorer.Project.EditorSettings - - true - true - true - - Cpp - - CppGlobal - - - - QmlJS - - QmlJSGlobal - - - 2 - UTF-8 - false - 4 - false - 0 - 80 - true - true - 1 - 0 - false - true - false - 2 - true - true - 0 - 8 - true - false - 1 - true - true - true - *.md, *.MD, Makefile - false - true - true - - - - ProjectExplorer.Project.PluginSettings - - - true - false - true - true - true - true - - false - - - 0 - true - - true - true - Builtin.DefaultTidyAndClazy - 6 - true - - - - true - - - - - ProjectExplorer.Project.Target.0 - - Desktop - Desktop Qt 5.15.2 GCC 64bit - Desktop Qt 5.15.2 GCC 64bit - qt.qt5.5152.gcc_64_kit - 0 - 0 - 0 - - 0 - /home/wangjing/uav/Drone_project/build/Desktop_Qt_5_15_2_GCC_64bit-Debug - /home/wangjing/uav/Drone_project/build/Desktop_Qt_5_15_2_GCC_64bit-Debug - - - true - QtProjectManager.QMakeBuildStep - false - - - - true - Qt4ProjectManager.MakeStep - - 2 - 构建 - 构建 - ProjectExplorer.BuildSteps.Build - - - - true - Qt4ProjectManager.MakeStep - clean - - 1 - 清除 - 清除 - ProjectExplorer.BuildSteps.Clean - - 2 - false - - false - - Debug - Qt4ProjectManager.Qt4BuildConfiguration - 2 - - - /home/wangjing/uav/Drone_project/build/Desktop_Qt_5_15_2_GCC_64bit-Release - /home/wangjing/uav/Drone_project/build/Desktop_Qt_5_15_2_GCC_64bit-Release - - - true - QtProjectManager.QMakeBuildStep - false - - - - true - Qt4ProjectManager.MakeStep - - 2 - 构建 - 构建 - ProjectExplorer.BuildSteps.Build - - - - true - Qt4ProjectManager.MakeStep - clean - - 1 - 清除 - 清除 - ProjectExplorer.BuildSteps.Clean - - 2 - false - - false - - Release - Qt4ProjectManager.Qt4BuildConfiguration - 0 - 0 - - - 0 - /home/wangjing/uav/Drone_project/build/Desktop_Qt_5_15_2_GCC_64bit-Profile - /home/wangjing/uav/Drone_project/build/Desktop_Qt_5_15_2_GCC_64bit-Profile - - - true - QtProjectManager.QMakeBuildStep - false - - - - true - Qt4ProjectManager.MakeStep - - 2 - 构建 - 构建 - ProjectExplorer.BuildSteps.Build - - - - true - Qt4ProjectManager.MakeStep - clean - - 1 - 清除 - 清除 - ProjectExplorer.BuildSteps.Clean - - 2 - false - - false - - Profile - Qt4ProjectManager.Qt4BuildConfiguration - 0 - 0 - 0 - - 3 - - - 0 - 部署 - 部署 - ProjectExplorer.BuildSteps.Deploy - - 1 - - false - ProjectExplorer.DefaultDeployConfiguration - - 1 - - true - true - 0 - true - - 2 - - false - -e cpu-cycles --call-graph dwarf,4096 -F 250 - - Qt4ProjectManager.Qt4RunConfiguration: - /home/wangjing/uav/Drone_project/drone_ui.pro - false - true - true - true - /home/wangjing/uav/Drone_project/build/Desktop_Qt_5_15_2_GCC_64bit-Debug - - 1 - - - - ProjectExplorer.Project.TargetCount - 1 - - - ProjectExplorer.Project.Updater.FileVersion - 22 - - - Version - 22 - - diff --git a/saved_path_20251016_165658.json b/saved_path_20251016_165658.json new file mode 100644 index 0000000..63bef2c --- /dev/null +++ b/saved_path_20251016_165658.json @@ -0,0 +1 @@ +[[116.352767, 39.881271],[116.348819, 39.905636]] \ No newline at end of file diff --git a/saved_path_20251016_165714.json b/saved_path_20251016_165714.json new file mode 100644 index 0000000..178f35c --- /dev/null +++ b/saved_path_20251016_165714.json @@ -0,0 +1 @@ +[[116.380526, 39.895891],[116.427218, 39.946445]] \ No newline at end of file diff --git a/src/pages/mappage.cpp b/src/pages/mappage.cpp deleted file mode 100644 index 576a464..0000000 --- a/src/pages/mappage.cpp +++ /dev/null @@ -1,928 +0,0 @@ -#include "mappage.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include // Added for QMessageBox -#include // Added for QRadioButton -#include // Added for QDateTimeEdit -#include // Added for QGroupBox - -/** - * 地图监控页面实现 - * 负责地图监控界面的构建和路径规划功能 - */ - -MapPage::MapPage(QWidget* parent) - : QWidget(parent) - , mapArea_(nullptr) - , heightCombo_(nullptr) - , downloadMapBtn_(nullptr) - , mapView_(nullptr) - , setThreatBtn_(nullptr) - , areaSearchBtn_(nullptr) - , pathPlanningBtn_(nullptr) - , coordInput_(nullptr) - , locateBtn_(nullptr) - , searchMapBtn_(nullptr) - , threatDialog_(nullptr) - , searchDialog_(nullptr) - , planningDialog_(nullptr) - , locateDialog_(nullptr) - , baseFontSize_(10) - -{ - setupUI(); - enableGeolocation(); // 启用geolocation - qDebug() << "MapPage 构造函数完成"; - - // 初始化对话框 - threatDialog_ = new ThreatAreaDialog(this); - searchDialog_ = new AreaSearchDialog(this); - planningDialog_ = new PathPlanningDialog(this); - locateDialog_ = new LocateDialog(this); // 确保初始化 -} - -MapPage::~MapPage() { - // Qt会自动清理子对象 -} - -void MapPage::setupUI() { - auto* mainLayout = new QVBoxLayout(this); - mainLayout->setSpacing(8); - mainLayout->setContentsMargins(0, 0, 0, 0); - - // 标题 - auto* title = new QLabel("路径监控"); - title->setProperty("class", "section"); - mainLayout->addWidget(title); - - // 地图类型切换 - mainLayout->addWidget(createMapControlsWidget()); - - // 地图区域 - setupMapArea(); - mainLayout->addWidget(mapArea_, 1); - - // 控制条 - setupControlBar(); - mainLayout->addWidget(createControlBarWidget()); -} - -void MapPage::setupMapControls() { - // 地图控制设置 -} - -QWidget* MapPage::createMapControlsWidget() { - auto* top = new QWidget(this); - auto* layout = new QHBoxLayout(top); - layout->setContentsMargins(0, 0, 0, 0); - - layout->addStretch(1); - return top; -} - -void MapPage::setupMapArea() { - mapArea_ = new QFrame(this); - mapArea_->setMinimumHeight(520); - // 使用全局样式 - - auto* layout = new QVBoxLayout(mapArea_); - layout->setContentsMargins(0, 0, 0, 0); - - mapView_ = new QWebEngineView(mapArea_); - mapView_->setPage(new CustomWebEnginePage(mapView_)); - layout->addWidget(mapView_); - - // 添加加载完成调试 - connect(mapView_, &QWebEngineView::loadFinished, this, [this](bool ok) { - qDebug() << (ok ? "地图 HTML 加载成功" : "地图 HTML 加载失败"); - }); - - // 添加默认地图加载 - const QString defaultHtml = R"( - - - - - - - 卫星和路网图 - - - - - - -
- - - )"; -mapView_->setHtml(defaultHtml, QUrl("https://webapi.amap.com/")); -} - -void MapPage::setupControlBar() { - // 控制条设置 -} - -QWidget* MapPage::createControlBarWidget() { - auto* bar = new QWidget(this); - auto* layout = new QHBoxLayout(bar); - layout->setContentsMargins(0, 0, 0, 0); - - auto* heightLabel = new QLabel("航线高度:"); - layout->addWidget(heightLabel); - - heightCombo_ = new QComboBox(); - heightCombo_->addItems({"30.00", "50.00", "80.00"}); - heightCombo_->setFixedWidth(100); - connect(heightCombo_, QOverload::of(&QComboBox::currentTextChanged), - this, &MapPage::onHeightChanged); - layout->addWidget(heightCombo_); - - layout->addStretch(1); - - // 添加地图检索按钮 - searchMapBtn_ = new QPushButton("地图检索"); - searchMapBtn_->setProperty("primary", true); - connect(searchMapBtn_, &QPushButton::clicked, this, &MapPage::onSearchMapClicked); - layout->addWidget(searchMapBtn_); - - downloadMapBtn_ = new QPushButton("地图下载"); - downloadMapBtn_->setProperty("primary", true); - connect(downloadMapBtn_, &QPushButton::clicked, this, &MapPage::onDownloadMapClicked); - layout->addWidget(downloadMapBtn_); - - // 添加新按钮 - 为了整洁,将它们分组在布局末尾 - setThreatBtn_ = new QPushButton("设置威胁区域"); - setThreatBtn_->setProperty("primary", true); - connect(setThreatBtn_, &QPushButton::clicked, this, &MapPage::onSetThreatClicked); - layout->addWidget(setThreatBtn_); - - areaSearchBtn_ = new QPushButton("区域搜索"); - areaSearchBtn_->setProperty("primary", true); - connect(areaSearchBtn_, &QPushButton::clicked, this, &MapPage::onAreaSearchClicked); - layout->addWidget(areaSearchBtn_); - - pathPlanningBtn_ = new QPushButton("路径规划"); - pathPlanningBtn_->setProperty("primary", true); - connect(pathPlanningBtn_, &QPushButton::clicked, this, &MapPage::onPathPlanningClicked); - layout->addWidget(pathPlanningBtn_); - - return bar; -} - -// 添加缺失的实现 -void MapPage::onHeightChanged() { - emit heightChanged(heightCombo_->currentText()); - qDebug() << "航线高度变更为:" << heightCombo_->currentText(); -} - -void MapPage::onDownloadMapClicked() { - emit downloadMapRequested(); - qDebug() << "地图下载请求"; -} - -// 新槽函数实现 -void MapPage::onSetThreatClicked() { - threatDialog_->exec(); // 打开模态对话框 - // 执行JS添加overlay (示例) - mapView_->page()->runJavaScript("addThreatArea();"); // 假设JS函数 -} - -void MapPage::onAreaSearchClicked() { - searchDialog_->exec(); -} - -void MapPage::onPathPlanningClicked() { - planningDialog_->exec(); -} - -// 添加resizeEvent实现 -void MapPage::resizeEvent(QResizeEvent *event) { - QWidget::resizeEvent(event); - - // 移除所有设置以防止无限resize循环 - // 只计算scale用于调试 - const int initialWidth = 800; - float scale = qMax(1.0f, static_cast(width()) / initialWidth); - - qDebug() << "MapPage resized with scale:" << scale; -} - -// 添加enableGeolocation实现 -void MapPage::enableGeolocation() { - if (mapView_) { - QWebEngineSettings* settings = mapView_->settings(); - settings->setAttribute(QWebEngineSettings::JavascriptEnabled, true); - settings->setAttribute(QWebEngineSettings::LocalStorageEnabled, true); - // 启用geolocation - mapView_->page()->setFeaturePermission(QUrl("https://webapi.amap.com/"), QWebEnginePage::Geolocation, QWebEnginePage::PermissionGrantedByUser); - } -} - -// 移除类定义 -// class ThreatAreaDialog : public QDialog { ... }; - -// 实现成员函数 -ThreatAreaDialog::ThreatAreaDialog(QWidget* parent) : QDialog(parent) { - setWindowTitle("设置威胁区域"); - setMinimumSize(600, 500); - auto* layout = new QVBoxLayout(this); - layout->setSpacing(15); - layout->setContentsMargins(20, 20, 20, 20); - - // 威胁区域基本信息组 - auto* basicGroup = new QGroupBox("基本信息"); - basicGroup->setStyleSheet("QGroupBox { font-weight: bold; margin-top: 10px; }"); - auto* basicLayout = new QGridLayout(basicGroup); - basicLayout->setSpacing(10); - - // 威胁类型 - basicLayout->addWidget(new QLabel("威胁类型:"), 0, 0); - typeCombo_ = new QComboBox(); - typeCombo_->addItems({"导弹威胁", "雷达干扰", "防空火力", "禁飞区域", "其他"}); - typeCombo_->setStyleSheet("QComboBox { padding: 5px; border: 1px solid #ccc; border-radius: 4px; }"); - basicLayout->addWidget(typeCombo_, 0, 1); - - // 威胁等级 - basicLayout->addWidget(new QLabel("威胁等级:"), 0, 2); - auto* levelCombo = new QComboBox(); - levelCombo->addItems({"高", "中", "低"}); - levelCombo->setStyleSheet("QComboBox { padding: 5px; border: 1px solid #ccc; border-radius: 4px; }"); - basicLayout->addWidget(levelCombo, 0, 3); - - // 时间设置组 - auto* timeGroup = new QGroupBox("威胁区域存在时间"); - timeGroup->setStyleSheet("QGroupBox { font-weight: bold; margin-top: 10px; }"); - auto* timeLayout = new QVBoxLayout(timeGroup); - - // 时间模式选择 - auto* timeModeLayout = new QHBoxLayout(); - auto* singleTimeMode = new QRadioButton("单时间点"); - auto* timeRangeMode = new QRadioButton("时间段"); - singleTimeMode->setChecked(true); - timeModeLayout->addWidget(singleTimeMode); - timeModeLayout->addWidget(timeRangeMode); - timeModeLayout->addStretch(); - timeLayout->addLayout(timeModeLayout); - - // 单时间点设置 - auto* singleTimeWidget = new QWidget(); - auto* singleTimeLayout = new QHBoxLayout(singleTimeWidget); - singleTimeLayout->setContentsMargins(0, 0, 0, 0); - - singleTimeLayout->addWidget(new QLabel("时间:")); - timeEdit_ = new QDateTimeEdit(QDateTime::currentDateTime()); - timeEdit_->setDisplayFormat("yyyy-MM-dd hh:mm:ss"); - timeEdit_->setCalendarPopup(true); - timeEdit_->setStyleSheet("QDateTimeEdit { padding: 5px; border: 1px solid #ccc; border-radius: 4px; }"); - singleTimeLayout->addWidget(timeEdit_); - - auto* setCurrentBtn = new QPushButton("设为当前时间"); - setCurrentBtn->setStyleSheet("QPushButton { padding: 5px 10px; background: #e3f2fd; border: 1px solid #2196f3; border-radius: 4px; color: #1976d2; }"); - singleTimeLayout->addWidget(setCurrentBtn); - singleTimeLayout->addStretch(); - timeLayout->addWidget(singleTimeWidget); - - // 时间模式选择器已定义,用于UI切换 - - // 时间段设置 - auto* timeRangeWidget = new QWidget(); - auto* timeRangeLayout = new QVBoxLayout(timeRangeWidget); - timeRangeLayout->setContentsMargins(0, 0, 0, 0); - - // 开始时间 - auto* startTimeLayout = new QHBoxLayout(); - startTimeLayout->addWidget(new QLabel("开始时间:")); - auto* startTimeEdit = new QDateTimeEdit(QDateTime::currentDateTime()); - startTimeEdit->setDisplayFormat("yyyy-MM-dd hh:mm:ss"); - startTimeEdit->setCalendarPopup(true); - startTimeEdit->setStyleSheet("QDateTimeEdit { padding: 5px; border: 1px solid #ccc; border-radius: 4px; }"); - startTimeLayout->addWidget(startTimeEdit); - - auto* setStartCurrentBtn = new QPushButton("设为当前"); - setStartCurrentBtn->setStyleSheet("QPushButton { padding: 5px 10px; background: #e8f5e8; border: 1px solid #4caf50; border-radius: 4px; color: #2e7d32; }"); - startTimeLayout->addWidget(setStartCurrentBtn); - startTimeLayout->addStretch(); - timeRangeLayout->addLayout(startTimeLayout); - - // 结束时间 - auto* endTimeLayout = new QHBoxLayout(); - endTimeLayout->addWidget(new QLabel("结束时间:")); - auto* endTimeEdit = new QDateTimeEdit(QDateTime::currentDateTime().addSecs(3600)); // 默认1小时后 - endTimeEdit->setDisplayFormat("yyyy-MM-dd hh:mm:ss"); - endTimeEdit->setCalendarPopup(true); - endTimeEdit->setStyleSheet("QDateTimeEdit { padding: 5px; border: 1px solid #ccc; border-radius: 4px; }"); - endTimeLayout->addWidget(endTimeEdit); - - auto* setEndCurrentBtn = new QPushButton("设为当前"); - setEndCurrentBtn->setStyleSheet("QPushButton { padding: 5px 10px; background: #e8f5e8; border: 1px solid #4caf50; border-radius: 4px; color: #2e7d32; }"); - endTimeLayout->addWidget(setEndCurrentBtn); - endTimeLayout->addStretch(); - timeRangeLayout->addLayout(endTimeLayout); - - // 持续时间显示和快速设置 - auto* durationLayout = new QHBoxLayout(); - auto* durationLabel = new QLabel("持续时间: 1小时"); - durationLabel->setStyleSheet("QLabel { color: #666; font-weight: bold; }"); - durationLayout->addWidget(durationLabel); - durationLayout->addStretch(); - - // 快速时间设置按钮 - auto* quickTimeLayout = new QHBoxLayout(); - auto* quick1Hour = new QPushButton("1小时"); - auto* quick4Hour = new QPushButton("4小时"); - auto* quick1Day = new QPushButton("1天"); - auto* quick1Week = new QPushButton("1周"); - - QString quickBtnStyle = "QPushButton { padding: 4px 8px; background: #f5f5f5; border: 1px solid #ddd; border-radius: 3px; font-size: 11px; }"; - quick1Hour->setStyleSheet(quickBtnStyle); - quick4Hour->setStyleSheet(quickBtnStyle); - quick1Day->setStyleSheet(quickBtnStyle); - quick1Week->setStyleSheet(quickBtnStyle); - - quickTimeLayout->addWidget(quick1Hour); - quickTimeLayout->addWidget(quick4Hour); - quickTimeLayout->addWidget(quick1Day); - quickTimeLayout->addWidget(quick1Week); - quickTimeLayout->addStretch(); - - durationLayout->addLayout(quickTimeLayout); - timeRangeLayout->addLayout(durationLayout); - - timeLayout->addWidget(timeRangeWidget); - timeRangeWidget->setVisible(false); // 默认隐藏 - - // 连接时间模式切换信号 - connect(singleTimeMode, &QRadioButton::toggled, [singleTimeWidget, timeRangeWidget](bool checked) { - singleTimeWidget->setVisible(checked); - timeRangeWidget->setVisible(!checked); - }); - connect(timeRangeMode, &QRadioButton::toggled, [singleTimeWidget, timeRangeWidget](bool checked) { - singleTimeWidget->setVisible(!checked); - timeRangeWidget->setVisible(checked); - }); - - // 连接单时间点信号 - connect(setCurrentBtn, &QPushButton::clicked, [this]() { - timeEdit_->setDateTime(QDateTime::currentDateTime()); - }); - - // 连接时间段信号 - connect(setStartCurrentBtn, &QPushButton::clicked, [startTimeEdit]() { - startTimeEdit->setDateTime(QDateTime::currentDateTime()); - }); - connect(setEndCurrentBtn, &QPushButton::clicked, [endTimeEdit]() { - endTimeEdit->setDateTime(QDateTime::currentDateTime()); - }); - - // 连接快速时间设置 - connect(quick1Hour, &QPushButton::clicked, [startTimeEdit, endTimeEdit, durationLabel]() { - QDateTime start = QDateTime::currentDateTime(); - QDateTime end = start.addSecs(3600); - startTimeEdit->setDateTime(start); - endTimeEdit->setDateTime(end); - durationLabel->setText("持续时间: 1小时"); - }); - connect(quick4Hour, &QPushButton::clicked, [startTimeEdit, endTimeEdit, durationLabel]() { - QDateTime start = QDateTime::currentDateTime(); - QDateTime end = start.addSecs(4 * 3600); - startTimeEdit->setDateTime(start); - endTimeEdit->setDateTime(end); - durationLabel->setText("持续时间: 4小时"); - }); - connect(quick1Day, &QPushButton::clicked, [startTimeEdit, endTimeEdit, durationLabel]() { - QDateTime start = QDateTime::currentDateTime(); - QDateTime end = start.addDays(1); - startTimeEdit->setDateTime(start); - endTimeEdit->setDateTime(end); - durationLabel->setText("持续时间: 1天"); - }); - connect(quick1Week, &QPushButton::clicked, [startTimeEdit, endTimeEdit, durationLabel]() { - QDateTime start = QDateTime::currentDateTime(); - QDateTime end = start.addDays(7); - startTimeEdit->setDateTime(start); - endTimeEdit->setDateTime(end); - durationLabel->setText("持续时间: 1周"); - }); - - // 连接时间变化信号,更新持续时间显示 - connect(startTimeEdit, &QDateTimeEdit::dateTimeChanged, [startTimeEdit, endTimeEdit, durationLabel]() { - qint64 seconds = startTimeEdit->dateTime().secsTo(endTimeEdit->dateTime()); - if (seconds > 0) { - int hours = seconds / 3600; - int minutes = (seconds % 3600) / 60; - if (hours > 0) { - durationLabel->setText(QString("持续时间: %1小时%2分钟").arg(hours).arg(minutes)); - } else { - durationLabel->setText(QString("持续时间: %1分钟").arg(minutes)); - } - } else { - durationLabel->setText("持续时间: 无效时间段"); - durationLabel->setStyleSheet("QLabel { color: #f44336; font-weight: bold; }"); - } - }); - connect(endTimeEdit, &QDateTimeEdit::dateTimeChanged, [startTimeEdit, endTimeEdit, durationLabel]() { - qint64 seconds = startTimeEdit->dateTime().secsTo(endTimeEdit->dateTime()); - if (seconds > 0) { - int hours = seconds / 3600; - int minutes = (seconds % 3600) / 60; - if (hours > 0) { - durationLabel->setText(QString("持续时间: %1小时%2分钟").arg(hours).arg(minutes)); - } else { - durationLabel->setText(QString("持续时间: %1分钟").arg(minutes)); - } - durationLabel->setStyleSheet("QLabel { color: #666; font-weight: bold; }"); - } else { - durationLabel->setText("持续时间: 无效时间段"); - durationLabel->setStyleSheet("QLabel { color: #f44336; font-weight: bold; }"); - } - }); - - // 坐标设置组 - auto* coordGroup = new QGroupBox("坐标设置"); - coordGroup->setStyleSheet("QGroupBox { font-weight: bold; margin-top: 10px; }"); - auto* coordLayout = new QVBoxLayout(coordGroup); - - // 坐标输入方式选择 - auto* coordMethodLayout = new QHBoxLayout(); - auto* manualInput = new QRadioButton("手动输入"); - auto* mapClick = new QRadioButton("地图点击选择"); - manualInput->setChecked(true); - coordMethodLayout->addWidget(manualInput); - coordMethodLayout->addWidget(mapClick); - coordMethodLayout->addStretch(); - coordLayout->addLayout(coordMethodLayout); - - // 坐标输入区域 - auto* coordInputLayout = new QHBoxLayout(); - coordInputLayout->addWidget(new QLabel("坐标:")); - - coordInput_ = new QLineEdit(); - coordInput_->setPlaceholderText("格式: 经度,纬度 (例: 116.397,39.909)"); - coordInput_->setStyleSheet("QLineEdit { padding: 5px; border: 1px solid #ccc; border-radius: 4px; }"); - coordInputLayout->addWidget(coordInput_, 1); - - auto* getCurrentPosBtn = new QPushButton("获取当前位置"); - getCurrentPosBtn->setStyleSheet("QPushButton { padding: 5px 10px; background: #e3f2fd; border: 1px solid #2196f3; border-radius: 4px; color: #1976d2; }"); - coordInputLayout->addWidget(getCurrentPosBtn); - coordLayout->addLayout(coordInputLayout); - - // 坐标示例和帮助 - auto* coordHelp = new QLabel("支持格式: 单点(116.397,39.909) | 多点(116.397,39.909;116.398,39.910) | 区域(116.397,39.909,116.398,39.910)"); - coordHelp->setStyleSheet("QLabel { color: #666; font-size: 11px; }"); - coordHelp->setWordWrap(true); - coordLayout->addWidget(coordHelp); - - // 连接坐标选择信号 - connect(manualInput, &QRadioButton::toggled, coordInput_, &QLineEdit::setEnabled); - connect(mapClick, &QRadioButton::toggled, [this](bool checked) { - coordInput_->setEnabled(!checked); - if (checked) { - coordInput_->setPlaceholderText("请在地图上点击选择坐标..."); - } else { - coordInput_->setPlaceholderText("格式: 经度,纬度 (例: 116.397,39.909)"); - } - }); - connect(getCurrentPosBtn, &QPushButton::clicked, [this]() { - // 这里可以集成GPS定位功能 - coordInput_->setText("116.397,39.909"); // 示例坐标 - }); - - // 图形设置组 - auto* shapeGroup = new QGroupBox("图形设置"); - shapeGroup->setStyleSheet("QGroupBox { font-weight: bold; margin-top: 10px; }"); - auto* shapeLayout = new QGridLayout(shapeGroup); - shapeLayout->setSpacing(10); - - shapeLayout->addWidget(new QLabel("图形类型:"), 0, 0); - shapeCombo_ = new QComboBox(); - shapeCombo_->addItems({"圆形", "多边形", "矩形", "椭圆"}); - shapeCombo_->setStyleSheet("QComboBox { padding: 5px; border: 1px solid #ccc; border-radius: 4px; }"); - shapeLayout->addWidget(shapeCombo_, 0, 1); - - shapeLayout->addWidget(new QLabel("颜色:"), 0, 2); - colorCombo_ = new QComboBox(); - colorCombo_->addItems({"红色", "黄色", "蓝色", "绿色", "紫色", "橙色"}); - colorCombo_->setStyleSheet("QComboBox { padding: 5px; border: 1px solid #ccc; border-radius: 4px; }"); - shapeLayout->addWidget(colorCombo_, 0, 3); - - // 添加所有组到主布局 - layout->addWidget(basicGroup); - layout->addWidget(timeGroup); - layout->addWidget(coordGroup); - layout->addWidget(shapeGroup); - - // 威胁区域列表组 - auto* listGroup = new QGroupBox("威胁区域列表"); - listGroup->setStyleSheet("QGroupBox { font-weight: bold; margin-top: 10px; }"); - auto* listLayout = new QVBoxLayout(listGroup); - - // 表格 - areaTable_ = new QTableWidget(0, 6); - areaTable_->setHorizontalHeaderLabels({"威胁类型", "威胁等级", "时间", "坐标", "图形", "操作"}); - areaTable_->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); - areaTable_->setAlternatingRowColors(true); - areaTable_->setSelectionBehavior(QAbstractItemView::SelectRows); - areaTable_->setStyleSheet("QTableWidget { gridline-color: #e0e0e0; }"); - listLayout->addWidget(areaTable_); - - // 表格操作按钮 - auto* tableButtons = new QHBoxLayout(); - auto* addBtn = new QPushButton("添加威胁区域"); - auto* editBtn = new QPushButton("编辑选中"); - auto* deleteBtn = new QPushButton("删除选中"); - auto* clearBtn = new QPushButton("清空列表"); - - // 设置按钮样式 - addBtn->setStyleSheet("QPushButton { padding: 8px 16px; background: #4caf50; color: white; border: none; border-radius: 4px; font-weight: bold; }"); - editBtn->setStyleSheet("QPushButton { padding: 8px 16px; background: #2196f3; color: white; border: none; border-radius: 4px; }"); - deleteBtn->setStyleSheet("QPushButton { padding: 8px 16px; background: #f44336; color: white; border: none; border-radius: 4px; }"); - clearBtn->setStyleSheet("QPushButton { padding: 8px 16px; background: #ff9800; color: white; border: none; border-radius: 4px; }"); - - tableButtons->addWidget(addBtn); - tableButtons->addWidget(editBtn); - tableButtons->addWidget(deleteBtn); - tableButtons->addWidget(clearBtn); - tableButtons->addStretch(); - listLayout->addLayout(tableButtons); - - layout->addWidget(listGroup); - - // 威胁区域统计组 - auto* statsGroup = new QGroupBox("威胁区域统计"); - statsGroup->setStyleSheet("QGroupBox { font-weight: bold; margin-top: 10px; }"); - auto* statsLayout = new QHBoxLayout(statsGroup); - - auto* totalLabel = new QLabel("总计: 0个"); - auto* currentLabel = new QLabel("当前威胁: 0个"); - auto* futureLabel = new QLabel("未来威胁: 0个"); - auto* historyLabel = new QLabel("历史威胁: 0个"); - - totalLabel->setStyleSheet("QLabel { color: #333; font-weight: bold; }"); - currentLabel->setStyleSheet("QLabel { color: #f44336; font-weight: bold; }"); - futureLabel->setStyleSheet("QLabel { color: #ff9800; font-weight: bold; }"); - historyLabel->setStyleSheet("QLabel { color: #9e9e9e; font-weight: bold; }"); - - statsLayout->addWidget(totalLabel); - statsLayout->addWidget(currentLabel); - statsLayout->addWidget(futureLabel); - statsLayout->addWidget(historyLabel); - statsLayout->addStretch(); - - layout->addWidget(statsGroup); - - // 底部按钮区域 - auto* buttons = new QHBoxLayout(); - auto* previewBtn = new QPushButton("预览效果"); - auto* saveBtn = new QPushButton("保存设置"); - auto* cancelBtn = new QPushButton("取消"); - - // 设置底部按钮样式 - previewBtn->setStyleSheet("QPushButton { padding: 10px 20px; background: #9c27b0; color: white; border: none; border-radius: 4px; font-weight: bold; }"); - saveBtn->setStyleSheet("QPushButton { padding: 10px 20px; background: #4caf50; color: white; border: none; border-radius: 4px; font-weight: bold; }"); - cancelBtn->setStyleSheet("QPushButton { padding: 10px 20px; background: #757575; color: white; border: none; border-radius: 4px; }"); - - buttons->addStretch(); - buttons->addWidget(previewBtn); - buttons->addWidget(saveBtn); - buttons->addWidget(cancelBtn); - layout->addLayout(buttons); - - // 连接信号槽 - connect(addBtn, &QPushButton::clicked, this, &ThreatAreaDialog::addArea); - connect(editBtn, &QPushButton::clicked, [this]() { - int row = areaTable_->currentRow(); - if (row >= 0) { - // 编辑选中行 - QMessageBox::information(this, "编辑", "编辑功能待实现"); - } else { - QMessageBox::warning(this, "提示", "请先选择要编辑的行"); - } - }); - connect(deleteBtn, &QPushButton::clicked, [this]() { - int row = areaTable_->currentRow(); - if (row >= 0) { - areaTable_->removeRow(row); - } else { - QMessageBox::warning(this, "提示", "请先选择要删除的行"); - } - }); - connect(clearBtn, &QPushButton::clicked, [this]() { - if (QMessageBox::question(this, "确认", "确定要清空所有威胁区域吗?") == QMessageBox::Yes) { - areaTable_->setRowCount(0); - } - }); - connect(previewBtn, &QPushButton::clicked, [this]() { - QMessageBox::information(this, "预览", "威胁区域预览功能待实现"); - }); - connect(cancelBtn, &QPushButton::clicked, this, &QDialog::reject); - connect(saveBtn, &QPushButton::clicked, this, &QDialog::accept); -} - -void ThreatAreaDialog::addArea() { - // 验证输入 - if (coordInput_->text().isEmpty()) { - QMessageBox::warning(this, "输入错误", "请输入坐标信息!"); - return; - } - - // 验证时间设置 - QDateTime currentTime = QDateTime::currentDateTime(); - QDateTime threatTime = timeEdit_->dateTime(); - - // 检查时间是否合理(不能是过去时间,除非是历史记录) - if (threatTime < currentTime.addDays(-1)) { - int ret = QMessageBox::question(this, "时间确认", - "设置的威胁时间较早,是否确认添加?\n" - "这可能是历史威胁记录。", - QMessageBox::Yes | QMessageBox::No); - if (ret == QMessageBox::No) { - return; - } - } - - int row = areaTable_->rowCount(); - areaTable_->insertRow(row); - - // 威胁类型 - areaTable_->setItem(row, 0, new QTableWidgetItem(typeCombo_->currentText())); - - // 威胁等级 (默认为"中") - areaTable_->setItem(row, 1, new QTableWidgetItem("中")); - - // 时间信息 - 根据当前选择的时间模式来设置 - QString timeInfo; - - // 判断威胁状态 - QString status; - if (threatTime > currentTime) { - status = "未来威胁"; - } else if (threatTime >= currentTime.addDays(-1)) { - status = "当前威胁"; - } else { - status = "历史威胁"; - } - - timeInfo = QString("%1: %2").arg(status).arg(threatTime.toString("yyyy-MM-dd hh:mm:ss")); - areaTable_->setItem(row, 2, new QTableWidgetItem(timeInfo)); - - // 根据威胁状态设置行颜色 - QTableWidgetItem* timeItem = areaTable_->item(row, 2); - if (status == "未来威胁") { - timeItem->setBackground(QColor(255, 243, 224)); // 浅橙色 - } else if (status == "当前威胁") { - timeItem->setBackground(QColor(255, 235, 238)); // 浅红色 - } else { - timeItem->setBackground(QColor(245, 245, 245)); // 浅灰色 - } - - // 坐标 - areaTable_->setItem(row, 3, new QTableWidgetItem(coordInput_->text())); - - // 图形信息 - QString shapeInfo = QString("%1 (%2)").arg(shapeCombo_->currentText()).arg(colorCombo_->currentText()); - areaTable_->setItem(row, 4, new QTableWidgetItem(shapeInfo)); - - // 操作按钮 - auto* actionWidget = new QWidget(); - auto* actionLayout = new QHBoxLayout(actionWidget); - actionLayout->setContentsMargins(2, 2, 2, 2); - actionLayout->setSpacing(2); - - auto* editBtn = new QPushButton("编辑"); - auto* deleteBtn = new QPushButton("删除"); - - editBtn->setStyleSheet("QPushButton { padding: 2px 6px; background: #2196f3; color: white; border: none; border-radius: 2px; font-size: 10px; }"); - deleteBtn->setStyleSheet("QPushButton { padding: 2px 6px; background: #f44336; color: white; border: none; border-radius: 2px; font-size: 10px; }"); - - actionLayout->addWidget(editBtn); - actionLayout->addWidget(deleteBtn); - actionLayout->addStretch(); - - areaTable_->setCellWidget(row, 5, actionWidget); - - // 连接操作按钮 - connect(editBtn, &QPushButton::clicked, [this, row]() { - // 编辑功能 - QMessageBox::information(this, "编辑", QString("编辑第 %1 行").arg(row + 1)); - }); - - connect(deleteBtn, &QPushButton::clicked, [this, row]() { - if (QMessageBox::question(this, "确认删除", "确定要删除这个威胁区域吗?") == QMessageBox::Yes) { - areaTable_->removeRow(row); - } - }); - - // 清空输入框 - coordInput_->clear(); - - // 显示成功消息 - QMessageBox::information(this, "添加成功", "威胁区域已添加到列表中!"); - - // 更新统计信息 - updateThreatStats(); -} - -// 更新威胁区域统计信息 -void ThreatAreaDialog::updateThreatStats() { - // 这里需要访问统计标签,但由于它们是局部变量,我们暂时跳过 - // 在实际应用中,应该将统计标签作为成员变量存储 - qDebug() << "威胁区域统计已更新"; -} - -void ThreatAreaDialog::resizeEvent(QResizeEvent *event) { - QDialog::resizeEvent(event); -} - -// 类似 for AreaSearchDialog -AreaSearchDialog::AreaSearchDialog(QWidget* parent) : QDialog(parent) { - setWindowTitle("区域搜索"); - auto* layout = new QVBoxLayout(this); - - filterCombo_ = new QComboBox(); - filterCombo_->addItems({"所有", "导弹威胁", "雷达干扰"}); - layout->addWidget(new QLabel("过滤类型:")); - layout->addWidget(filterCombo_); - - resultTable_ = new QTableWidget(0, 4); - resultTable_->setHorizontalHeaderLabels({"类型", "时间", "位置", "详情"}); - layout->addWidget(resultTable_); - - QPushButton* searchBtn = new QPushButton("搜索"); - layout->addWidget(searchBtn); -} - -void AreaSearchDialog::resizeEvent(QResizeEvent *event) { - QDialog::resizeEvent(event); -} - -// 类似 for PathPlanningDialog -PathPlanningDialog::PathPlanningDialog(QWidget* parent) : QDialog(parent) { - setWindowTitle("路径规划"); - auto* layout = new QVBoxLayout(this); - - startInput_ = new QLineEdit("起点坐标"); - endInput_ = new QLineEdit("终点坐标"); - layout->addWidget(startInput_); - layout->addWidget(endInput_); - - pathTable_ = new QTableWidget(0, 2); - pathTable_->setHorizontalHeaderLabels({"点", "坐标"}); - layout->addWidget(pathTable_); - - QPushButton* planBtn = new QPushButton("规划"); - layout->addWidget(planBtn); -} - -void PathPlanningDialog::resizeEvent(QResizeEvent *event) { - QDialog::resizeEvent(event); -} - -// 添加onLocateClicked实现 -void MapPage::onSearchMapClicked() { - if (locateDialog_->exec() == QDialog::Accepted) { - double lng = locateDialog_->getLongitude(); - double lat = locateDialog_->getLatitude(); - - // 执行JS移动地图中心(使用window.map以匹配全局变量) - QString js = QString("window.map.setCenter([%1, %2]); window.map.setZoom(15);").arg(lng).arg(lat); - mapView_->page()->runJavaScript(js); - } -} - -// 移除旧的onLocateClicked -// void MapPage::onLocateClicked() { ... } - -// 添加LocateDialog实现 -LocateDialog::LocateDialog(QWidget* parent) : QDialog(parent) { - setWindowTitle("地图检索"); - auto* layout = new QVBoxLayout(this); - - lngInput_ = new QLineEdit(); - lngInput_->setPlaceholderText("输入经度 (例如: 116.397)"); - layout->addWidget(new QLabel("经度:")); - layout->addWidget(lngInput_); - - latInput_ = new QLineEdit(); - latInput_->setPlaceholderText("输入纬度 (例如: 39.909)"); - layout->addWidget(new QLabel("纬度:")); - layout->addWidget(latInput_); - - auto* buttons = new QHBoxLayout(); - auto* confirmBtn = new QPushButton("确认"); - auto* cancelBtn = new QPushButton("取消"); - buttons->addStretch(); - buttons->addWidget(confirmBtn); - buttons->addWidget(cancelBtn); - buttons->addStretch(); - layout->addLayout(buttons); - - connect(confirmBtn, &QPushButton::clicked, this, &LocateDialog::onConfirm); - connect(cancelBtn, &QPushButton::clicked, this, &QDialog::reject); -} - -void LocateDialog::onConfirm() { - bool okLng, okLat; - lng_ = lngInput_->text().toDouble(&okLng); - lat_ = latInput_->text().toDouble(&okLat); - - if (!okLng || !okLat) { - QMessageBox::warning(this, "输入错误", "请输入有效的经纬度值!"); - return; - } - - accept(); -} - -double LocateDialog::getLongitude() const { return lng_; } -double LocateDialog::getLatitude() const { return lat_; } - -// 添加公共方法实现 -void MapPage::runMapJavaScript(const QString& js) { - if (mapView_) { - mapView_->page()->runJavaScript(js); - } -} - diff --git a/src/pages/mappage.h b/src/pages/mappage.h deleted file mode 100644 index dd6d339..0000000 --- a/src/pages/mappage.h +++ /dev/null @@ -1,182 +0,0 @@ -#ifndef MAPPAGE_H -#define MAPPAGE_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include // 添加 -#include -#include -#include -#include -#include -#include -#include // 添加以支持输入验证警告 -#include // 添加QGroupBox支持 -#include // 添加QRadioButton支持 - -class CustomWebEnginePage : public QWebEnginePage { - Q_OBJECT -public: - CustomWebEnginePage(QObject* parent = nullptr) : QWebEnginePage(parent) {} -protected: - void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString& message, int lineNumber, const QString& sourceID) override { - qDebug() << "JS 消息 (级别:" << level << "):" << message << " (行:" << lineNumber << ", 来源:" << sourceID << ")"; - } -}; - -// 移除前向声明 -// class ThreatAreaDialog; -// class AreaSearchDialog; -// class PathPlanningDialog; - -// 定义类 -class ThreatAreaDialog : public QDialog { - Q_OBJECT -public: - ThreatAreaDialog(QWidget* parent = nullptr); -private slots: - void addArea(); - void updateThreatStats(); -protected: - void resizeEvent(QResizeEvent *event) override; -private: - QComboBox* typeCombo_; - QDateTimeEdit* timeEdit_; - QComboBox* shapeCombo_; - QComboBox* colorCombo_; - QTableWidget* areaTable_; - QLineEdit* coordInput_; -}; - -class AreaSearchDialog : public QDialog { - Q_OBJECT -public: - AreaSearchDialog(QWidget* parent = nullptr); -protected: - void resizeEvent(QResizeEvent *event) override; -private: - QComboBox* filterCombo_; - QTableWidget* resultTable_; -}; - -class PathPlanningDialog : public QDialog { - Q_OBJECT -public: - PathPlanningDialog(QWidget* parent = nullptr); -protected: - void resizeEvent(QResizeEvent *event) override; -private: - QLineEdit* startInput_; - QLineEdit* endInput_; - QTableWidget* pathTable_; -}; - -// 添加LocateDialog类定义 -class LocateDialog : public QDialog { - Q_OBJECT -public: - LocateDialog(QWidget* parent = nullptr); - double getLongitude() const; - double getLatitude() const; -private slots: - void onConfirm(); -private: - QLineEdit* lngInput_; - QLineEdit* latInput_; - double lng_; - double lat_; -}; - -/** - * 地图监控页面类 - * 负责地图监控界面的构建和路径规划功能 - */ -class MapPage : public QWidget { - Q_OBJECT - -public: - explicit MapPage(QWidget* parent = nullptr); - ~MapPage(); - - // 获取组件引用 - QComboBox* getHeightCombo() const { return heightCombo_; } - QPushButton* getDownloadMapBtn() const { return downloadMapBtn_; } - - // 添加新信号 - signals: - void heightChanged(const QString& height); - void downloadMapRequested(); - void setThreatRequested(); - void areaSearchRequested(); - void pathPlanningRequested(); - -private slots: - void onHeightChanged(); - void onDownloadMapClicked(); - - // 添加新槽函数 - void onSetThreatClicked(); - void onAreaSearchClicked(); - void onPathPlanningClicked(); - - // 添加新槽 - void onSearchMapClicked(); // 新增声明 - -public slots: - void runMapJavaScript(const QString& js); // 添加公共方法运行JS - -protected: - void resizeEvent(QResizeEvent *event) override; - -private: - void setupUI(); - void setupMapControls(); - void setupMapArea(); - void setupControlBar(); - - // 添加新方法 - void enableGeolocation(); - - // 创建UI组件的辅助方法 - QWidget* createMapControlsWidget(); - QWidget* createControlBarWidget(); - - // UI组件 - QFrame* mapArea_; - QComboBox* heightCombo_; - QPushButton* downloadMapBtn_; - QWebEngineView* mapView_; - - // 添加新按钮成员 - QPushButton* setThreatBtn_; - QPushButton* areaSearchBtn_; - QPushButton* pathPlanningBtn_; - - // 添加新组件 - QLineEdit* coordInput_; - QPushButton* locateBtn_; - QPushButton* searchMapBtn_; - - // 添加对话框成员 - ThreatAreaDialog* threatDialog_; - AreaSearchDialog* searchDialog_; - PathPlanningDialog* planningDialog_; - LocateDialog* locateDialog_; - - // 添加基字体大小(用于缩放) - int baseFontSize_ = 10; // 默认基字体大小,根据您的样式调整 -}; - -// 移除所有类定义,从h文件移出 - -#endif // MAPPAGE_H