473 lines
14 KiB
C++
473 lines
14 KiB
C++
#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);
|
||
}
|
||
}
|