Manual-Labeling-Tool/Manual-Labeling-Client/Manual-Label-Tool-Widget/ManualLabelToolWidget.cpp

473 lines
14 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include "ManualLabelToolWidget.h"
#include <qdockwidget.h>
#include <qgslayertreeview.h>
#include <qgslayertreemodel.h>
#include <qgslayertreemapcanvasbridge.h>
#include <qlabel.h>
#include <qstatusbar.h>
#include <QMenuBar>
#include <QToolBar>
#include <qgsmapcanvas.h>
#include <qgsrasterlayer.h>
#include <qgsmaptoolpan.h>
#include <qgsunittypes.h>
#include <QString>
#include <qgis.h>
#include <QgsMapSettings.h>
#include <QFile>
#include <QFileDialog>
#include <QDialog>
#include <QApplication>
#include <QScreen>
#include <QString>
#include <qfileinfo.h>
#include <qdir.h>
#include <qgsmaplayer.h>
#include <qgsproject.h>
#include "WidgetSettingClass.h"
#include "LAMPDataManagerDialog.h"
#include <qgsproviderregistry.h>
#include <qgsapplication.h>
//#include <qgslayertreeview.h>
#include <qgslayertree.h>
#include <qgslayerpropertiesdialog.h>
#include "QBatchStaticEchoDialog.h"
#include "QImageCursorWidget.h"
#include <QToolButton.h>
#include <QgsMapToolZoom.h>
#include <QgsMapToolIdentify.h>
#include "CustomCursorTool.h"
#include "qgslayerpropertiesdialog.h"
#include "windLayerTreeViewMenuProvider.h"
//QgsUnitTypes
ManualLabelToolWidget::ManualLabelToolWidget(QWidget* parent)
: QMainWindow(parent)
{
this->init_UI();
}
ManualLabelToolWidget::~ManualLabelToolWidget()
{
}
void ManualLabelToolWidget::init_UI()
{
// 初始大小
{
this->setWindowTitle(tr(u8"微波风能分析软件"));
// 获取主屏幕的可用区域(不包含任务栏)
QRect availableGeometry = QApplication::primaryScreen()->availableGeometry();
// 计算期望的窗口大小例如屏幕可用区域的80%
int width = availableGeometry.width() * 0.8;
int height = availableGeometry.height() * 0.8;
// 调整窗口大小
resize(width, height);
// 可选:将窗口移动到屏幕中央
move(availableGeometry.center() - rect().center());
}
{
datamanagerDialog = new LampDataManager(this);
onshowDatamanagerActionTriggered();
}
//地图控制
{
// 1. inti map canvas
this->map_canvas = new QgsMapCanvas(this);
this->setCentralWidget((this->map_canvas));
// 2. map tool pan
this->map_tool_pan = new QgsMapToolPan(this->map_canvas);
this->map_canvas->setMapTool(this->map_tool_pan);
// 关键缓存与渲染配置
map_canvas->setCachingEnabled(true); // 启用缓存,这是实现分块加载效果的关键[citation:6][citation:8]
map_canvas->setParallelRenderingEnabled(true); // 启用并行渲染以提高性能[citation:6]
// 3. map layer manager
this->map_layerTreeView = new QgsLayerTreeView(this);
// 4. create map model
this->map_layerModel = new QgsLayerTreeModel(QgsProject::instance()->layerTreeRoot(), this);
this->map_layerModel->setFlag(QgsLayerTreeModel::AllowNodeRename); // 允许重命名
this->map_layerModel->setFlag(QgsLayerTreeModel::AllowNodeReorder); // 允许调整顺序
this->map_layerModel->setFlag(QgsLayerTreeModel::AllowNodeChangeVisibility); // 允许改变可见性
this->map_layerModel->setFlag(QgsLayerTreeModel::ShowLegendAsTree); // 以树状图显示图例
this->map_layerModel->setAutoCollapseLegendNodes(10); // 自动折叠过多图例项
this->map_layerTreeView->setModel(this->map_layerModel);
this->map_layer_Bridge = new QgsLayerTreeMapCanvasBridge(QgsProject::instance()->layerTreeRoot(), this->map_canvas, this);
this->layerTreeDock = new QDockWidget(tr(u8"图层管理器"), this);
this->layerTreeDock->setWidget(this->map_layerTreeView);
layerTreeDock->setWidget(this->map_layerTreeView);
layerTreeDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
this->addDockWidget(Qt::LeftDockWidgetArea, this->layerTreeDock);
windLayerTreeViewMenuProvider* mLayerTreeViewMenuProvider = new windLayerTreeViewMenuProvider(map_layerTreeView, map_canvas, this);
this->map_layerTreeView->setMenuProvider(mLayerTreeViewMenuProvider);
}
// 状态工具栏
{
appStatusBar = this->statusBar(); // 获取或创建状态栏
scaleLabel = new QLabel(tr(u8"比例尺:"));
CoordinaryTextLabel = new QLabel(tr(u8"坐标系:"));
PointXYLabel = new QLabel(tr(u8"坐标:"));
UnitLabel = new QLabel(tr(u8"单位:"));
appStatusBar->addPermanentWidget(PointXYLabel); //
appStatusBar->addPermanentWidget(scaleLabel); //
appStatusBar->addPermanentWidget(UnitLabel); //
appStatusBar->addPermanentWidget(CoordinaryTextLabel); //
// 连接比例尺变化信号
connect(map_canvas, SIGNAL(scaleChanged(double)), this, SLOT(updateScaleLabel(double)));
connect(map_canvas, SIGNAL(xyCoordinates(const QgsPointXY&)), this, SLOT(updateCoordinateLabel(const QgsPointXY&)));
connect(map_canvas, SIGNAL(extentsChanged()), this, SLOT(onMapExtentsChanged()));
}
// 菜单栏
{
menubar = this->menuBar();
// 在菜单栏上添加"文件"和"编辑"菜单
fileMenu = menubar->addMenu(tr(u8"文件"));
// 向"文件"菜单中添加菜单项QAction
newAction = fileMenu->addAction(tr(u8"新建"));
fileMenu->addSeparator(); // 添加分割线[1,5](@ref)
openMenu = fileMenu->addMenu(tr(u8"打开"));
openRasterFolderAction = openMenu->addAction(tr(u8"打开影像文件夹"));
openRasterAction = openMenu->addAction(tr(u8"打开影像"));
openSLCRasterAction = openMenu->addAction(tr(u8"SLC影像"));
openLampWindDataAction = openMenu->addAction(tr(u8"风场数据"));
// 事件绑定
QObject::connect(this->openRasterAction, SIGNAL(triggered()), this, SLOT(openRaster()));
QObject::connect(this->openLampWindDataAction, SIGNAL(triggered()), this->datamanagerDialog, SLOT(openLampWindDataFile()));
editMenu = menubar->addMenu(tr(u8"编辑"));
SARWindInversionMenu = menubar->addMenu(tr(u8"SAR风场反演"));
SARImageImportAction = SARWindInversionMenu->addAction(tr(u8"SAR数据导入"));
SARInversionAtion = SARWindInversionMenu->addAction(tr(u8"SAR风场分析工具"));
SARInversionResulutShowAtion = SARWindInversionMenu->addAction(tr(u8"风场数据结果展示"));
//SARWindAysysMenu = SARWindInversionMenu->addMenu(tr(u8"风场分析"));
//SARImageAysysAction = SARWindAysysMenu->addAction(tr(u8"目标时间序列分析"));
QObject::connect(SARInversionAtion, SIGNAL(triggered()), this, SLOT(onshowSARInversionAtionTriggered()));
}
// 图像工具
{
datatoolbar = new QToolBar(tr(u8"工具"));
showDatamanagerAction = datatoolbar->addAction(tr(u8"数据管理"));
mapToolActionGroup = new QActionGroup(this);
ZoomInToolbtn = new QAction(tr(u8"放大"));
ZoomInToolbtn->setCheckable(true);
mapToolActionGroup->addAction(ZoomInToolbtn);
ZoomOutToolbtn = new QAction(tr(u8"缩小"));
ZoomOutToolbtn->setCheckable(true);
mapToolActionGroup->addAction(ZoomOutToolbtn);
MapPanToolbtn = new QAction(tr(u8"平移"));
MapPanToolbtn->setCheckable(true);
MapPanToolbtn->setChecked(true);
mapToolActionGroup->addAction(MapPanToolbtn);
IdentifyToolbtn = new QAction(tr(u8"识别"));
IdentifyToolbtn->setCheckable(true);
mapToolActionGroup->addAction(IdentifyToolbtn);
cursorAction = new QAction(tr(u8"游标"));
cursorAction->setCheckable(true);
mapToolActionGroup->addAction(cursorAction);
datatoolbar->addAction(ZoomInToolbtn);
datatoolbar->addAction(ZoomOutToolbtn);
datatoolbar->addAction(MapPanToolbtn);
datatoolbar->addAction(cursorAction);
m_mapToolPan = new QgsMapToolPan(this->map_canvas);
m_mapToolZoomIn = new QgsMapToolZoom(this->map_canvas, false);
m_mapToolZoomOut = new QgsMapToolZoom(this->map_canvas, true);
m_mapIdentifyToolPan = new QgsMapToolIdentify(this->map_canvas);
m_CustomCursorTool = new CustomCursorTool(this->map_canvas);
ZoomInToolbtn->setText(u8"放大");
ZoomOutToolbtn->setText(u8"缩小");
MapPanToolbtn->setText(u8"平移");
IdentifyToolbtn->setText(u8"识别");
connect(mapToolActionGroup, &QActionGroup::triggered, this, &ManualLabelToolWidget::onMapToolActionTriggered);
//QObject::connect(cursorAction, SIGNAL(triggered()), this, SLOT(onCursorImageToolTriggered()));
QObject::connect(showDatamanagerAction, SIGNAL(triggered()), this, SLOT(onshowDatamanagerActionTriggered()));
this->addToolBar(Qt::TopToolBarArea, datatoolbar);
}
// AI标注工具栏
{
AiLabelToolBar = new QToolBar(tr(u8"AI标注工具栏"), this);
this->addToolBar(Qt::LeftToolBarArea, AiLabelToolBar);
}
// 检查插件
{
QString qgisPrefixPath = WidgetSettingClass::instance().getExeDirectionApplicationPath();
// 3. 显式设置插件目录确保QGIS能找到动态提供者
QString pluginPath = qgisPrefixPath + "/plugins";
QgsApplication::setPluginPath(pluginPath);
// 4. 设置QGIS的共享数据目录包含proj.db等
QString pkgDataPath = qgisPrefixPath + "/share/qgis";
QgsApplication::setPkgDataPath(pkgDataPath);
QgsApplication::initQgis();
QStringList providers = QgsProviderRegistry::instance()->providerList();
qDebug() << u8"已注册的提供者:" << providers;
// 检查 "mesh_memory" 或相关的 "mdal" 提供者是否存在
if (providers.contains("mesh_memory")) {
qDebug() << u8"'mesh_memory' 提供者可用。";
}
else {
qDebug() << u8"警告:未找到相关的网格数据提供者。";
}
if (providers.contains("mdal")) {
qDebug() << u8"'mdal' 提供者可用,它可能包含在 'mdal' 中。";
}
else {
qDebug() << u8"警告:未找到相关的网格数据提供者。";
}
}
}
void ManualLabelToolWidget::open()
{
}
void ManualLabelToolWidget::openRaster()
{
QString lastFileDialogPath = WidgetSettingClass::instance().getLastFileDialogPath();
if (lastFileDialogPath.isEmpty()) {
lastFileDialogPath = ".";
}
// 打开影像
// 2. 选择多个文件
QString lampwindPath = QFileDialog::getOpenFileName(
this,
tr(u8"请选择影像文件"),
lastFileDialogPath,
tr(LAMPWINDDATAFILEFILTER)
);
QString filename = QFileInfo(lampwindPath).fileName();
QgsRasterLayer* rasterLayer = new QgsRasterLayer(lampwindPath, filename);
if (!rasterLayer->isValid()) {
qDebug() << "Failed to load raster layer!";
// 错误处理
return;
}
this->AddLayers(rasterLayer);
}
void ManualLabelToolWidget::updateCoordinateLabel(const QgsPointXY& point)
{
QString coordText = QString(tr(u8"坐标X:%1 Y:%2")).arg(QString::number(point.x(), 'f', 2)).arg(QString::number(point.y(), 'f', 2));
PointXYLabel->setText(coordText);
}
void ManualLabelToolWidget::onMapExtentsChanged()
{
QgsRectangle currentExtent = map_canvas->extent();
//// 现在你可以使用这个范围信息了,例如:
//// 1. 打印范围坐标
//qDebug() << "新范围 - Xmin:" << currentExtent.xMinimum()
// << "Ymin:" << currentExtent.yMinimum()
// << "Xmax:" << currentExtent.xMaximum()
// << "Ymax:" << currentExtent.yMaximum();
}
void ManualLabelToolWidget::AddLayers(QgsMapLayer* layer)
{
if (!layer || !layer->isValid()) {
qDebug() << "无效图层,无法添加!";
return;
}
if (QgsProject::instance()->mapLayers().size() == 0) {
// 检查图层是否有效且拥有定义的坐标系
if (layer && layer->isValid() && layer->crs().isValid()) {
// 将地图画布的目标坐标系设置为与图层一致
map_canvas->mapSettings().setDestinationCrs(layer->crs());
// 可选:将地图范围缩放至该图层的全范围,提供更好的初始视图
map_canvas->setExtent(layer->extent());
// 刷新画布,使更改生效
map_canvas->refresh();
qDebug() << "图层数量为1已同步画布坐标系至" << layer->crs().description();
}
}
QgsProject::instance()->addMapLayer(layer);
}
void ManualLabelToolWidget::updateScaleLabel(double scale)
{
QString scaleText = QString(tr(u8"比例尺1:%1")).arg(QString::number(scale, 'f', 0));
scaleLabel->setText(scaleText);
Qgis::DistanceUnit unit = map_canvas->mapUnits();
QString unitString;
if (unit == Qgis::DistanceUnit::Meters) {
unitString = tr(u8"");
}
else if (unit == Qgis::DistanceUnit::Degrees) {
unitString = tr(u8"");
}
else if (unit == Qgis::DistanceUnit::Feet) {
unitString = tr(u8"英尺");
}
else {
unitString = tr(u8"未知");
}
UnitLabel->setText(QString(tr(u8"单位:%1")).arg(unitString));
QgsCoordinateReferenceSystem currentCrs = map_canvas->mapSettings().destinationCrs();
QString description = currentCrs.description();
QString authid = currentCrs.authid();
if (description == "") {
CoordinaryTextLabel->setText(QString(tr(u8"坐标系:未知")));
}
else {
CoordinaryTextLabel->setText(QString(tr(u8"坐标系:%1")).arg(description));
}
}
void ManualLabelToolWidget::onshowDatamanagerActionTriggered()
{
if (nullptr == datamanagerDialog) {
datamanagerDialog = new LampDataManager(this);
}
else {}
QRect parentGeometry = this->geometry();
QSize dialogSize = datamanagerDialog->size();
// 计算居中位置
int x = parentGeometry.x() + (parentGeometry.width() - dialogSize.width()) / 2;
int y = parentGeometry.y() + (parentGeometry.height() - dialogSize.height()) / 2;
// 设置对话框位置
datamanagerDialog->move(x, y);
datamanagerDialog->show();
datamanagerDialog->raise(); // 确保对话框在最前面
datamanagerDialog->activateWindow(); // 激活对话框获取焦点
}
void ManualLabelToolWidget::setupLayerTreeContextMenu()
{
// 启用图层树视图的默认上下文菜单
this->map_layerTreeView->setMenuProvider(this->map_layerTreeView->menuProvider());
// 或者自定义菜单
this->map_layerTreeView->setContextMenuPolicy(Qt::CustomContextMenu);
connect(this->map_layerTreeView, &QgsLayerTreeView::customContextMenuRequested,
this, &ManualLabelToolWidget::onLayerTreeContextMenu);
}
void ManualLabelToolWidget::onLayerTreeContextMenu(const QPoint& pos)
{
QModelIndex index = map_layerTreeView->indexAt(pos);
if (!index.isValid())
return;
QgsLayerTreeNode* node = map_layerTreeView->layerTreeModel()->index2node(index);
if (!node)
return;
QMenu* menu = new QMenu(this);
if (QgsLayerTree::isLayer(node))
{
QgsMapLayer* layer = QgsLayerTree::toLayer(node)->layer();
if (layer)
{
// 添加属性表菜单项
QAction* attributeTableAction = menu->addAction(tr("打开属性表"));
// 添加图层属性菜单项
QAction* layerPropertiesAction = menu->addAction(tr("图层属性"));
}
}
menu->exec(map_layerTreeView->mapToGlobal(pos));
delete menu;
}
void ManualLabelToolWidget::onshowSARInversionAtionTriggered()
{
QBatchStaticEchoDialog* d = new QBatchStaticEchoDialog(this);
d->show();
}
void ManualLabelToolWidget::onMapToolActionTriggered(QAction* action)
{
if (action == ZoomInToolbtn) {
this->map_canvas->setMapTool(m_mapToolZoomIn);
}
else if (action == ZoomOutToolbtn) {
this->map_canvas->setMapTool(m_mapToolZoomOut);
}
else if (action == MapPanToolbtn) {
this->map_canvas->setMapTool(m_mapToolPan);
}
else if (action == IdentifyToolbtn) {
this->map_canvas->setMapTool(m_mapIdentifyToolPan);
}
else if (action == cursorAction) {
this->map_canvas->setMapTool(m_CustomCursorTool);
if (!cursorInfoDialog)
{
cursorInfoDialog = new QImageCursorWidget(this); // 游标显示窗口
}
QObject::connect(m_CustomCursorTool, &CustomCursorTool::identifyResultChange, cursorInfoDialog, &QImageCursorWidget::showCursor, Qt::ConnectionType::AutoConnection);
cursorInfoDialog->show();
map_canvas->setCursor(Qt::CrossCursor);
}
else {
map_canvas->setCursor(Qt::CursorShape::ArrowCursor);
}
}