1、为图层添加渲染器和读取器,分离图层基础信息、渲染和读写;

2、LayerTreeLayerNode持有MapLayer图层引用,为右键菜单做准备;
3、改名:imageviewer → mapcavas,mapcavas持有MapLayer图层引用,为刷新图像做准备;
This commit is contained in:
tangchao0503
2026-02-25 15:08:06 +08:00
parent e3b2d136d3
commit bdf956ed99
13 changed files with 659 additions and 286 deletions

View File

@ -265,29 +265,29 @@ sizePolicy1.setHeightForWidth(graphicsView_delete->sizePolicy().hasHeightForWidt
//dock_layers->setMaximumHeight(498); //dock_layers->setMaximumHeight(498);
//高光谱查看 //高光谱查看
QDockWidget* dock_hyperimgViewer = new CustomDockWidgetBase(QString::fromLocal8Bit("hyimgViewer"), this); QDockWidget* dock_hyperimgViewer = new CustomDockWidgetBase(QString::fromLocal8Bit("hyimgViewer"), this);
dock_hyperimgViewer->setObjectName("hyimgViewer"); dock_hyperimgViewer->setObjectName("hyimgViewer");
QWidget* dock_hyperimgViewerWidgetContents = new QWidget(); QWidget* dock_hyperimgViewerWidgetContents = new QWidget();
dock_hyperimgViewerWidgetContents->setObjectName(QString::fromUtf8("dock_hyperimgViewerWidgetContents")); dock_hyperimgViewerWidgetContents->setObjectName(QString::fromUtf8("dock_hyperimgViewerWidgetContents"));
QGridLayout* gridLayout_hyperimgViewer = new QGridLayout(dock_hyperimgViewerWidgetContents); QGridLayout* gridLayout_hyperimgViewer = new QGridLayout(dock_hyperimgViewerWidgetContents);
gridLayout_hyperimgViewer->setSpacing(6); gridLayout_hyperimgViewer->setSpacing(6);
gridLayout_hyperimgViewer->setObjectName(QString::fromUtf8("gridLayout_hyperimgViewer")); gridLayout_hyperimgViewer->setObjectName(QString::fromUtf8("gridLayout_hyperimgViewer"));
gridLayout_hyperimgViewer->setVerticalSpacing(6); gridLayout_hyperimgViewer->setVerticalSpacing(6);
gridLayout_hyperimgViewer->setContentsMargins(1, 2, 1, 2); gridLayout_hyperimgViewer->setContentsMargins(1, 2, 1, 2);
m_imageViewerTabWidget = new QTabWidget(); m_imageViewerTabWidget = new QTabWidget();
//m_imageViewerTabWidget->tabBar()->setFixedHeight(40);//没有效果在qss中设置高度才有效果为啥 //m_imageViewerTabWidget->tabBar()->setFixedHeight(40);//没有效果在qss中设置高度才有效果为啥
m_imageViewerTabWidget->clear();//必须放在最前面首先删除所有的tab m_imageViewerTabWidget->clear();//必须放在最前面首先删除所有的tab
QToolButton* maxButton = new QToolButton(); QToolButton* maxButton = new QToolButton();
maxButton->setIcon(style()->standardIcon(QStyle::SP_TitleBarMaxButton)); maxButton->setIcon(style()->standardIcon(QStyle::SP_TitleBarMaxButton));
connect(maxButton, SIGNAL(clicked()), dock_hyperimgViewer, SLOT(toggleMaximize())); connect(maxButton, SIGNAL(clicked()), dock_hyperimgViewer, SLOT(toggleMaximize()));
m_imageViewerTabWidget->setCornerWidget(maxButton, Qt::TopRightCorner); m_imageViewerTabWidget->setCornerWidget(maxButton, Qt::TopRightCorner);
//onCreateTab(0); //onCreateTab(0);
//m_imageViewerTabWidget->setTabsClosable(true);//这样每页都会有关闭按钮 //m_imageViewerTabWidget->setTabsClosable(true);//这样每页都会有关闭按钮
connect(m_imageViewerTabWidget, SIGNAL(currentChanged(int)), this, SLOT(onTabWidgetCurrentChanged(int))); connect(m_imageViewerTabWidget, SIGNAL(currentChanged(int)), this, SLOT(onTabWidgetCurrentChanged(int)));
m_imageViewerTabWidget->setStyleSheet(R"( m_imageViewerTabWidget->setStyleSheet(R"(
QTabBar::tab { QTabBar::tab {
background: #0E1C4C; background: #0E1C4C;
color: white; color: white;
@ -676,7 +676,6 @@ void HPPA::initMenubarToolbar()
} }
)"); )");
QWidget* topWidget = new QWidget(); QWidget* topWidget = new QWidget();
topWidget->setStyleSheet("background-color: #040125;"); topWidget->setStyleSheet("background-color: #040125;");
QVBoxLayout* verticalLayout_topWidget = new QVBoxLayout(topWidget); QVBoxLayout* verticalLayout_topWidget = new QVBoxLayout(topWidget);
@ -934,8 +933,6 @@ void HPPA::createOneMotorScenario()
m_tabManager->showTab(m_omc); m_tabManager->showTab(m_omc);
m_view3DModelManager->switchScenario(View3DModelManager::ScenarioType::OneMotor); m_view3DModelManager->switchScenario(View3DModelManager::ScenarioType::OneMotor);
//右上角轮播 //右上角轮播
@ -964,8 +961,6 @@ void HPPA::createPlantPhenotypeScenario()
m_tabManager->showTab(m_pc); m_tabManager->showTab(m_pc);
m_tabManager->showTab(m_tmc); m_tabManager->showTab(m_tmc);
m_view3DModelManager->switchScenario(View3DModelManager::ScenarioType::PlantPhenotype); m_view3DModelManager->switchScenario(View3DModelManager::ScenarioType::PlantPhenotype);
//右上角轮播 //右上角轮播
@ -1078,7 +1073,7 @@ void HPPA::onStartRecordStep1()
m_RecordState -= 1; m_RecordState -= 1;
ui.action_start_recording->setText(QString::fromLocal8Bit("采集")); ui.action_start_recording->setText(QString::fromLocal8Bit("采集"));
ui.mainToolBar->widgetForAction(ui.action_start_recording)->setStyleSheet("QWidget{background-color:rgb(0,255,0);}"); ui.mainToolBar->widgetForAction(ui.action_start_recording)->setStyleSheet("QWidget{background-color:rgb(0,255,0);}");
} }
return; return;
} }
@ -1124,42 +1119,41 @@ void HPPA::onStartRecordStep1()
void HPPA::onCreateTab(int trackNumber) void HPPA::onCreateTab(int trackNumber)
{ {
if (trackNumber >= 0) if (trackNumber >= 0)
{ {
m_numberOfRecording = trackNumber; m_numberOfRecording = trackNumber;
QWidget* tabTmp = new QWidget(); QWidget* tabTmp = new QWidget();
QGridLayout* GridLayout = new QGridLayout(); QGridLayout* GridLayout = new QGridLayout();
GridLayout->addWidget(new ImageViewer(tabTmp)); GridLayout->addWidget(new mapcavas(tabTmp));
tabTmp->setLayout(GridLayout); tabTmp->setLayout(GridLayout);
m_imageViewerTabWidget->addTab(tabTmp, QString::number(trackNumber + 1)); m_imageViewerTabWidget->addTab(tabTmp, QString::number(trackNumber + 1));
m_imageViewerTabWidget->setCurrentIndex(trackNumber); m_imageViewerTabWidget->setCurrentIndex(trackNumber);
} }
} }
void HPPA::onTabWidgetCurrentChanged(int index)//代码新建一个tab会调用onTabWidgetCurrentChanged函数 void HPPA::onTabWidgetCurrentChanged(int index)//代码新建一个tab会调用onTabWidgetCurrentChanged函数
{ {
if (index < 0)//当删除所有tab时index=-1 if (index < 0)//当删除所有tab时index=-1
{ {
return; return;
} }
//记录当前
m_TabWidgetCurrentIndex = index;
//记录当前 //获取绘图控件
m_TabWidgetCurrentIndex = index; QWidget* currentWidget = m_imageViewerTabWidget->widget(index);
QList<mapcavas*> currentImageViewer = currentWidget->findChildren<mapcavas*>();
//获取绘图控件 //先disconnect然后再connect否则每次切换一次都会connect一次会累积connect很多次
QWidget* currentWidget = m_imageViewerTabWidget->widget(index); disconnect(currentImageViewer[0], SIGNAL(leftMouseButtonPressed(int, int)), this, SLOT(onLeftMouseButtonPressed(int, int)));
QList<ImageViewer*> currentImageViewer = currentWidget->findChildren<ImageViewer*>(); connect(currentImageViewer[0], SIGNAL(leftMouseButtonPressed(int, int)), this, SLOT(onLeftMouseButtonPressed(int, int)));
//先disconnect然后再connect否则每次切换一次都会connect一次会累积connect很多次
disconnect(currentImageViewer[0], SIGNAL(leftMouseButtonPressed(int, int)), this, SLOT(onLeftMouseButtonPressed(int, int)));
connect(currentImageViewer[0], SIGNAL(leftMouseButtonPressed(int, int)), this, SLOT(onLeftMouseButtonPressed(int, int)));
} }
void HPPA::onActionOpenDirectory() void HPPA::onActionOpenDirectory()
@ -1169,34 +1163,6 @@ void HPPA::onActionOpenDirectory()
QDesktopServices::openUrl(QUrl::fromLocalFile(QString::fromStdString(directory))); QDesktopServices::openUrl(QUrl::fromLocalFile(QString::fromStdString(directory)));
//QDesktopServices::openUrl(QUrl("file:C:\ASD", QUrl::TolerantMode));
////std::cout << "保存影像文件!" << std::endl;
//
//FileOperation * fileOperation = new FileOperation();
//string directory = fileOperation->getDirectoryFromString();
//string sourceImg = directory + "\\tmp_image";
//string sourceHdr = sourceImg + ".hdr";
//
//QString FileName2Save = QFileDialog::getSaveFileName(this,tr("save image"));
//if (FileName2Save.length()>0)
//{
// string targetImg = FileName2Save.toStdString();
// string targetHdr = targetImg + ".hdr";
// emit CopyFileThreadSignal(QString::fromStdString(sourceHdr), QString::fromStdString(targetHdr));
// emit CopyFileThreadSignal(QString::fromStdString(sourceImg), QString::fromStdString(targetImg));
// this->setEnabled(false);
//}
//else
//{
// std::cout << "文件名长度:" << FileName2Save.length() << std::endl;
//}
} }
@ -1274,6 +1240,7 @@ void HPPA::onLeftMouseButtonPressed(int x, int y)
QLineSeries* series = new QLineSeries(); QLineSeries* series = new QLineSeries();
//series->clear();////////////////////////////// //series->clear();//////////////////////////////
QString imagerSelected = mImagerGroup->checkedAction()->objectName(); QString imagerSelected = mImagerGroup->checkedAction()->objectName();
if (imagerSelected == "mActionPica_L" || imagerSelected == "mActionCorning_410" || imagerSelected == "mActionPika_XC2") if (imagerSelected == "mActionPica_L" || imagerSelected == "mActionCorning_410" || imagerSelected == "mActionPika_XC2")
{ {
@ -1385,7 +1352,6 @@ void HPPA::onPlotRgbImage()
int height = m_cam_label->height(); int height = m_cam_label->height();
QPixmap fitpixmap = pixmap.scaled(width, height, Qt::KeepAspectRatio, Qt::SmoothTransformation); //按比例缩放 QPixmap fitpixmap = pixmap.scaled(width, height, Qt::KeepAspectRatio, Qt::SmoothTransformation); //按比例缩放
m_cam_label->setPixmap(fitpixmap); m_cam_label->setPixmap(fitpixmap);
} }
@ -1444,6 +1410,53 @@ void HPPA::onExit()
void HPPA::onOpenImg() void HPPA::onOpenImg()
{ {
// 1) 弹出文件对话框获取uri
QString uri = QFileDialog::getOpenFileName(this, tr("Open Image"), QString(), tr("Raster Files (*.bil *.hdr *.tif *.tiff *.img *.raw);;All Files (*)"));
if (uri.isEmpty())
return;
// 2) 创建 RasterLayer然后添加到图层管理器
if (!m_LayerTreeModel || !m_RasterGroup)
{
QMessageBox::warning(this, tr("Error"), tr("Layer model is not initialized."));
return;
}
QFileInfo fi(uri);
QString baseName = fi.completeBaseName();
// Create RasterLayer and wrap in LayerTreeLayerNode
RasterLayer* rl = new RasterLayer(baseName, uri);
auto* layerNode = new LayerTreeLayerNode(rl);
m_LayerTreeModel->addLayer(m_RasterGroup, layerNode);
// 3) 渲染一副图像并保存到 C:\2
RasterLayer::RenderParams params; // use defaults
QImage img = rl->render(params);
if (img.isNull())
{
QMessageBox::warning(this, tr("Render failed"), tr("Failed to render image from %1").arg(uri));
return;
}
QDir outDir("C:/2");
if (!outDir.exists())
{
if (!outDir.mkpath("."))
{
QMessageBox::warning(this, tr("Save failed"), tr("Failed to create output directory C:/2"));
return;
}
}
QString outPath = outDir.filePath(baseName + "_render.png");
if (!img.save(outPath))
{
QMessageBox::warning(this, tr("Save failed"), tr("Failed to save rendered image to %1").arg(outPath));
return;
}
QMessageBox::information(this, tr("Saved"), tr("Rendered image saved to %1").arg(outPath));
} }
void HPPA::onconnect() void HPPA::onconnect()
@ -1638,7 +1651,7 @@ void HPPA::onFocus2(int command)
QWidget* tabTmp = new QWidget(); QWidget* tabTmp = new QWidget();
QGridLayout* GridLayout = new QGridLayout(); QGridLayout* GridLayout = new QGridLayout();
GridLayout->addWidget(new ImageViewer(tabTmp)); GridLayout->addWidget(new mapcavas(tabTmp));
tabTmp->setLayout(GridLayout); tabTmp->setLayout(GridLayout);
@ -1726,28 +1739,28 @@ void HPPA::recordWhiteFinish()
void HPPA::onPlotHyperspectralImageRgbImage(int fileNumber, int frameNumber) void HPPA::onPlotHyperspectralImageRgbImage(int fileNumber, int frameNumber)
{ {
//使用机械臂采集时,会在停止采集后的瞬间又开始采集,会导致上次采集最后发射的信号调用此槽函数报错 //使用机械臂采集时,会在停止采集后的瞬间又开始采集,会导致上次采集最后发射的信号调用此槽函数报错
QAction* checked = moveplatformActionGroup->checkedAction(); QAction* checked = moveplatformActionGroup->checkedAction();
QString checkedName = checked->objectName(); QString checkedName = checked->objectName();
if (frameNumber == -1 && checkedName == "mAction_RobotArm") if (frameNumber == -1 && checkedName == "mAction_RobotArm")
{ {
return; return;
} }
//return; //return;
//获取绘图控件 //获取绘图控件
QWidget* currentWidget = m_imageViewerTabWidget->widget(fileNumber); QWidget* currentWidget = m_imageViewerTabWidget->widget(fileNumber);
QList<ImageViewer*> currentImageViewer = currentWidget->findChildren<ImageViewer*>(); QList<mapcavas*> currentImageViewer = currentWidget->findChildren<mapcavas*>();
currentImageViewer[0]->DisplayFrameNumber(m_Imager->getFrameCounter());//界面中显示已经采集的帧数 currentImageViewer[0]->DisplayFrameNumber(m_Imager->getFrameCounter());//界面中显示已经采集的帧数
//创建需要显示的图像--opencv版本 //创建需要显示的图像--opencv版本
ImageProcessor imageProcessor; ImageProcessor imageProcessor;
//cv::Mat rgbImage(*m_Imager->getRgbImage()->m_matRgbImage, cv::Range(0, m_Imager->getFrameCounter()), cv::Range::all());//2022.3.18重构的 //cv::Mat rgbImage(*m_Imager->getRgbImage()->m_matRgbImage, cv::Range(0, m_Imager->getFrameCounter()), cv::Range::all());//2022.3.18重构的
cv::Mat rgbImage(*m_Imager->getMatRgbImage(), cv::Range(0, m_Imager->getFrameCounter()), cv::Range::all()); cv::Mat rgbImage(*m_Imager->getMatRgbImage(), cv::Range(0, m_Imager->getFrameCounter()), cv::Range::all());
cv::Mat rgbImageStretched = imageProcessor.CStretch(rgbImage, 0.02); cv::Mat rgbImageStretched = imageProcessor.CStretch(rgbImage, 0.02);
//在界面中显示图像 //在界面中显示图像
currentImageViewer[0]->SetImage(&QPixmap::fromImage(imageProcessor.Mat2QImage(rgbImageStretched)));//绘制图像 currentImageViewer[0]->SetImage(&QPixmap::fromImage(imageProcessor.Mat2QImage(rgbImageStretched)));//绘制图像
//20241225 //20241225
//保存拉伸后的rgb //保存拉伸后的rgb
@ -1768,12 +1781,12 @@ void HPPA::onPlotHyperspectralImageRgbImage(int fileNumber, int frameNumber)
void HPPA::PlotSpectral(int state) void HPPA::PlotSpectral(int state)
{ {
if (state == 1) if (state == 1)
{ {
//显示影像 //显示影像
QWidget* currentWidget = m_imageViewerTabWidget->currentWidget(); QWidget* currentWidget = m_imageViewerTabWidget->currentWidget();
QList<ImageViewer*> currentImageViewer = currentWidget->findChildren<ImageViewer*>(); QList<mapcavas*> currentImageViewer = currentWidget->findChildren<mapcavas*>();
currentImageViewer[0]->DisplayFrameNumber(m_Imager->getFocusFrameCounter());//界面中显示已经采集的帧数 currentImageViewer[0]->DisplayFrameNumber(m_Imager->getFocusFrameCounter());//界面中显示已经采集的帧数
ImageProcessor imageProcessor; ImageProcessor imageProcessor;
//cv::Mat grayImage(*m_Imager->getRgbImage()->m_matFocusGrayImage, cv::Range::all(), cv::Range::all());//2022.3.18重构的 //cv::Mat grayImage(*m_Imager->getRgbImage()->m_matFocusGrayImage, cv::Range::all(), cv::Range::all());//2022.3.18重构的
@ -1782,26 +1795,26 @@ void HPPA::PlotSpectral(int state)
currentImageViewer[0]->SetImage(&QPixmap::fromImage(m_Imager->getQImageFocusGrayImage()));//绘制图像 currentImageViewer[0]->SetImage(&QPixmap::fromImage(m_Imager->getQImageFocusGrayImage()));//绘制图像
//绘制光谱 //绘制光谱
QLineSeries* series = new QLineSeries(); QLineSeries* series = new QLineSeries();
//series->clear();////////////////////////////// //series->clear();//////////////////////////////
int sampleCount = m_Imager->getSampleCount(); int sampleCount = m_Imager->getSampleCount();
for (size_t i = 0; i < sampleCount; i++) for (size_t i = 0; i < sampleCount; i++)
{ {
//malloc申请的内存用法1可以当做数组用 //malloc申请的内存用法1可以当做数组用
//series->append(i, m_Imager->buffer[i + 5 * 900]); //series->append(i, m_Imager->buffer[i + 5 * 900]);
//series->append(i, m_Imager->buffer[900 * 150 + i]); //series->append(i, m_Imager->buffer[900 * 150 + i]);
series->append(i, m_Imager->buffer[1368 * 150 + i]); series->append(i, m_Imager->buffer[1368 * 150 + i]);
} }
QChart* chart = new QChart(); QChart* chart = new QChart();
chart->legend()->hide(); chart->legend()->hide();
chart->addSeries(series); chart->addSeries(series);
chart->createDefaultAxes(); chart->createDefaultAxes();
//chart->setTitle("Simple line chart example"); //chart->setTitle("Simple line chart example");
m_chartView->setChart(chart); m_chartView->setChart(chart);
} }
else else
{ {
//改变界面上的按钮文字 //改变界面上的按钮文字

View File

@ -125,7 +125,9 @@
<ClCompile Include="PowerControl.cpp" /> <ClCompile Include="PowerControl.cpp" />
<ClCompile Include="QDoubleSlider.cpp" /> <ClCompile Include="QDoubleSlider.cpp" />
<ClCompile Include="QMotorDoubleSlider.cpp" /> <ClCompile Include="QMotorDoubleSlider.cpp" />
<ClCompile Include="RasterDataProvider.cpp" />
<ClCompile Include="RasterLayer.cpp" /> <ClCompile Include="RasterLayer.cpp" />
<ClCompile Include="RasterRenderer.cpp" />
<ClCompile Include="resononImager.cpp" /> <ClCompile Include="resononImager.cpp" />
<ClCompile Include="ResononNirImager.cpp" /> <ClCompile Include="ResononNirImager.cpp" />
<ClCompile Include="RgbCameraOperation.cpp" /> <ClCompile Include="RgbCameraOperation.cpp" />
@ -194,6 +196,8 @@
<QtMoc Include="LayerTreeLayerNode.h" /> <QtMoc Include="LayerTreeLayerNode.h" />
<QtMoc Include="MapLayer.h" /> <QtMoc Include="MapLayer.h" />
<QtMoc Include="RasterLayer.h" /> <QtMoc Include="RasterLayer.h" />
<ClInclude Include="RasterDataProvider.h" />
<ClInclude Include="RasterRenderer.h" />
<ClInclude Include="utility_tc.h" /> <ClInclude Include="utility_tc.h" />
<QtMoc Include="aboutWindow.h" /> <QtMoc Include="aboutWindow.h" />
<ClInclude Include="hppaConfigFile.h" /> <ClInclude Include="hppaConfigFile.h" />

View File

@ -160,6 +160,12 @@
<ClCompile Include="RasterLayer.cpp"> <ClCompile Include="RasterLayer.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="RasterDataProvider.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="RasterRenderer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<QtMoc Include="fileOperation.h"> <QtMoc Include="fileOperation.h">
@ -287,6 +293,12 @@
<ClInclude Include="irisximeaimager.h"> <ClInclude Include="irisximeaimager.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="RasterDataProvider.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="RasterRenderer.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<QtUic Include="FocusDialog.ui"> <QtUic Include="FocusDialog.ui">

View File

@ -5,240 +5,217 @@
#include <QPoint> #include <QPoint>
#include "ImageViewer.h" #include "ImageViewer.h"
#include "RasterLayer.h"
#define VIEW_CENTER viewport()->rect().center() #define VIEW_CENTER viewport()->rect().center()
#define VIEW_WIDTH viewport()->rect().width() #define VIEW_WIDTH viewport()->rect().width()
#define VIEW_HEIGHT viewport()->rect().height() #define VIEW_HEIGHT viewport()->rect().height()
mapcavas::mapcavas(QWidget* pParent) :QGraphicsView(pParent)
ImageViewer::ImageViewer(QWidget* pParent) :QGraphicsView(pParent)
{ {
setRenderHint(QPainter::Antialiasing); setRenderHint(QPainter::Antialiasing);
setRenderHint(QPainter::SmoothPixmapTransform); setRenderHint(QPainter::SmoothPixmapTransform);
setDragMode(QGraphicsView::ScrollHandDrag); setDragMode(QGraphicsView::ScrollHandDrag);
// <20>ؼ<EFBFBD><D8BC><EFBFBD><E3A3BA>ʹ<EFBFBD><EFBFBD> Qt Ĭ<>ϵ<EFBFBD> anchor<6F><72><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Լ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> // ʹ<EFBFBD><EFBFBD> Qt Ĭ<><C4AC> anchor <EFBFBD><EFBFBD>Ϊ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
setTransformationAnchor(QGraphicsView::NoAnchor); setTransformationAnchor(QGraphicsView::NoAnchor);
setResizeAnchor(QGraphicsView::NoAnchor); setResizeAnchor(QGraphicsView::NoAnchor);
m_qtGraphicsScene = new QGraphicsScene(this); m_qtGraphicsScene = new QGraphicsScene(this);
this->setScene(m_qtGraphicsScene); this->setScene(m_qtGraphicsScene);
m_qtGraphicsScene->setSceneRect(-1e6, -1e6, 2e6, 2e6); m_qtGraphicsScene->setSceneRect(-1e6, -1e6, 2e6, 2e6);
m_framNumberLabel = new QLabel(this); m_framNumberLabel = new QLabel(this);
m_framNumberLabel->setAlignment(Qt::AlignHCenter); m_framNumberLabel->setAlignment(Qt::AlignHCenter);
m_framNumberLabel->setAlignment(Qt::AlignVCenter); m_framNumberLabel->setAlignment(Qt::AlignVCenter);
QFont ft; QFont ft;
ft.setPointSize(14); ft.setPointSize(14);
m_framNumberLabel->setFont(ft); m_framNumberLabel->setFont(ft);
m_framNumberLabel->setText("0"); m_framNumberLabel->setText("0");
m_GraphicsPixmapItemHandle = nullptr; m_GraphicsPixmapItemHandle = nullptr;
m_scale = 1.0; m_scale = 1.0;
m_zoomDelta = 0.1; m_zoomDelta = 0.1;
m_translateSpeed = 1.0; m_translateSpeed = 1.0;
m_bMouseTranslate = false; m_bMouseTranslate = false;
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setFrameShape(QFrame::NoFrame); setFrameShape(QFrame::NoFrame);
} }
ImageViewer::~ImageViewer() mapcavas::~mapcavas()
{ {
} }
void ImageViewer::DisplayFrameNumber(int frameNumber) void mapcavas::DisplayFrameNumber(int frameNumber)
{ {
m_framNumberLabel->setText(QString::number(frameNumber)); m_framNumberLabel->setText(QString::number(frameNumber));
m_framNumberLabel->adjustSize(); m_framNumberLabel->adjustSize();
} }
void ImageViewer::SetImage(QPixmap *image) void mapcavas::SetImage(QPixmap *image)
{ {
if (!HasImage()) if (!HasImage())
{ {
m_GraphicsPixmapItemHandle = m_qtGraphicsScene->addPixmap(*image); m_GraphicsPixmapItemHandle = m_qtGraphicsScene->addPixmap(*image);
} }
else else
{ {
m_GraphicsPixmapItemHandle->setPixmap(*image); m_GraphicsPixmapItemHandle->setPixmap(*image);
} }
ensureSceneVisible(); ensureSceneVisible();
} }
void ImageViewer::ensureSceneVisible() void mapcavas::ensureSceneVisible()
{ {
resetTransform(); resetTransform();
auto view_rect = viewport()->rect(); auto view_rect = viewport()->rect();
auto scene_rect = this->scene()->itemsBoundingRect(); auto scene_rect = this->scene()->itemsBoundingRect();
double x_ratio = view_rect.width() / scene_rect.width(); double x_ratio = view_rect.width() / scene_rect.width();
double y_ratio = view_rect.height() / scene_rect.height(); double y_ratio = view_rect.height() / scene_rect.height();
double scale_factor = std::min(x_ratio, y_ratio) * 0.9; double scale_factor = std::min(x_ratio, y_ratio) * 0.9;
scale(scale_factor, scale_factor); scale(scale_factor, scale_factor);
m_scale *= scale_factor; m_scale *= scale_factor;
centerOn(scene_rect.center()); centerOn(scene_rect.center());
} }
bool ImageViewer::HasImage() bool mapcavas::HasImage()
{ {
if (m_GraphicsPixmapItemHandle == nullptr) if (m_GraphicsPixmapItemHandle == nullptr)
{ {
return false; return false;
} }
else else
{ {
return true; return true;
} }
} }
void ImageViewer::wheelEvent(QWheelEvent *event) void mapcavas::wheelEvent(QWheelEvent *event)
{ {
//qDebug() << "---------------+++++++++++++++++++++++++++++++++++++++++++++++++++ "; if (HasImage())
//if (true)//HasImage() {
//{ QPointF oldPos = mapToScene(event->pos());
// //Χ<><CEA7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŵ<EFBFBD><C5B4><EFBFBD>https://blog.csdn.net/GoForwardToStep/article/details/77035287?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.channel_param
// // <20><>ȡ<EFBFBD><C8A1>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>view<65><77>λ<EFBFBD><CEBB>;
// QPointF cursorPoint = event->pos();
// // <20><>ȡ<EFBFBD><C8A1>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>scene<6E><65>λ<EFBFBD><CEBB>;
// QPointF scenePos = this->mapToScene(QPoint(cursorPoint.x(), cursorPoint.y()));
// // <20><>ȡview<65>Ŀ<EFBFBD><C4BF><EFBFBD>; QPoint scrollAmount = event->angleDelta();
// qreal viewWidth = this->viewport()->width(); scrollAmount.y() > 0 ? zoomIn() : zoomOut();
// qreal viewHeight = this->viewport()->height();
// // <20><>ȡ<EFBFBD><C8A1>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD>λ<EFBFBD><CEBB><EFBFBD><EFBFBD><E0B5B1>view<65><77>С<EFBFBD>ĺ<EFBFBD><C4BA>ݱ<EFBFBD><DDB1><EFBFBD>; QPointF newPos = mapToScene(event->pos());
// qreal hScale = cursorPoint.x() / viewWidth;
// qreal vScale = cursorPoint.y() / viewHeight;
QPointF delta = newPos - oldPos;
// // <20><><EFBFBD>ֵĹ<D6B5><C4B9><EFBFBD><EFBFBD><EFBFBD> translate(delta.x(), delta.y());
// QPoint scrollAmount = event->angleDelta(); }
// // <20><>ֵ<EFBFBD><D6B5>ʾ<EFBFBD><CABE><EFBFBD><EFBFBD>Զ<EFBFBD><D4B6>ʹ<EFBFBD><CAB9><EFBFBD>߷Ŵ<DFB7><C5B4><EFBFBD>ֵ<EFBFBD><D6B5>ʾ<EFBFBD><CABE><EFBFBD><EFBFBD>ʹ<EFBFBD><CAB9><EFBFBD><EFBFBD><EFBFBD><EFBFBD>С
// scrollAmount.y() > 0 ? zoomIn() : zoomOut();
// // <20><>scene<6E><65><EFBFBD><EFBFBD>ת<EFBFBD><D7AA>Ϊ<EFBFBD>Ŵ<EFBFBD><C5B4><EFBFBD>С<EFBFBD><D0A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>;
// QPointF viewPoint = this->matrix().map(scenePos);
// // ͨ<><CDA8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>view<65>Ŵ<EFBFBD><C5B4><EFBFBD>С<EFBFBD><D0A1><EFBFBD><EFBFBD>չʾscene<6E><65>λ<EFBFBD><CEBB>;
// horizontalScrollBar()->setValue(int(viewPoint.x() - viewWidth * hScale));
// verticalScrollBar()->setValue(int(viewPoint.y() - viewHeight * vScale));
//}
if (HasImage())
{
QPointF oldPos = mapToScene(event->pos());
QPoint scrollAmount = event->angleDelta();
scrollAmount.y() > 0 ? zoomIn() : zoomOut();
QPointF newPos = mapToScene(event->pos());
QPointF delta = newPos - oldPos;
translate(delta.x(), delta.y());
}
//QGraphicsView::wheelEvent(event);//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
} }
void ImageViewer::scaling(qreal scaleFactor) void mapcavas::scaling(qreal scaleFactor)
{ {
//qDebug() << this->sceneRect(); scale(scaleFactor, scaleFactor);
scale(scaleFactor, scaleFactor);
} }
void ImageViewer::mousePressEvent(QMouseEvent *event) void mapcavas::mousePressEvent(QMouseEvent *event)
{ {
if (event->button()==Qt::LeftButton) if (event->button()==Qt::LeftButton)
{ {
m_bMouseTranslate = true; m_bMouseTranslate = true;
m_lastMousePos = event->pos(); m_lastMousePos = event->pos();
//qDebug() << mapToScene(m_lastMousePos); emit leftMouseButtonPressed(mapToScene(m_lastMousePos).x(), mapToScene(m_lastMousePos).y());
}
emit leftMouseButtonPressed(mapToScene(m_lastMousePos).x(), mapToScene(m_lastMousePos).y()); QGraphicsView::mousePressEvent(event);
}
//If you do not perform all the necessary work in your implementation of the virtual function, you may need to call the base class's implementation.
QGraphicsView::mousePressEvent(event);
} }
void ImageViewer::mouseMoveEvent(QMouseEvent *event) void mapcavas::mouseMoveEvent(QMouseEvent *event)
{ {
if (m_bMouseTranslate){ if (m_bMouseTranslate){
QPointF mouseDelta = mapToScene(event->pos()) - mapToScene(m_lastMousePos); QPointF mouseDelta = mapToScene(event->pos()) - mapToScene(m_lastMousePos);
translate(mouseDelta.x(),mouseDelta.y()); translate(mouseDelta.x(),mouseDelta.y());
} }
m_lastMousePos = event->pos(); m_lastMousePos = event->pos();
QGraphicsView::mousePressEvent(event); QGraphicsView::mousePressEvent(event);
} }
void ImageViewer::mouseReleaseEvent(QMouseEvent *event) void mapcavas::mouseReleaseEvent(QMouseEvent *event)
{ {
m_bMouseTranslate = false; m_bMouseTranslate = false;
QGraphicsView::mouseReleaseEvent(event); QGraphicsView::mouseReleaseEvent(event);
} }
void ImageViewer::mouseDoubleClickEvent(QMouseEvent *event) void mapcavas::mouseDoubleClickEvent(QMouseEvent *event)
{ {
QGraphicsView::mouseDoubleClickEvent(event); QGraphicsView::mouseDoubleClickEvent(event);
} }
void ImageViewer::zoomIn() void mapcavas::zoomIn()
{ {
zoom(1 + m_zoomDelta); zoom(1 + m_zoomDelta);
} }
void ImageViewer::zoomOut() void mapcavas::zoomOut()
{ {
zoom(1 - m_zoomDelta); zoom(1 - m_zoomDelta);
} }
void ImageViewer::zoom(float scaleFactor) void mapcavas::zoom(float scaleFactor)
{ {
// <20><>ֹ<EFBFBD><D6B9>С<EFBFBD><D0A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD> qreal factor = transform().scale(scaleFactor, scaleFactor).mapRect(QRectF(0, 0, 1, 1)).width();
qreal factor = transform().scale(scaleFactor, scaleFactor).mapRect(QRectF(0, 0, 1, 1)).width(); if (factor < 0.07 || factor > 100)
if (factor < 0.07 || factor > 100) return;
return;
scale(scaleFactor, scaleFactor); scale(scaleFactor, scaleFactor);
m_scale *= scaleFactor; m_scale *= scaleFactor;
} }
void ImageViewer::setTranslateSpeed(qreal speed) void mapcavas::setTranslateSpeed(qreal speed)
{ {
// <20><><EFBFBD><EFBFBD><EFBFBD>ٶȷ<D9B6>Χ Q_ASSERT_X(speed >= 0.0 && speed <= 2.0,
Q_ASSERT_X(speed >= 0.0 && speed <= 2.0, "InteractiveView::setTranslateSpeed", "Speed should be in range [0.0, 2.0].");
"InteractiveView::setTranslateSpeed", "Speed should be in range [0.0, 2.0]."); m_translateSpeed = speed;
m_translateSpeed = speed;
} }
qreal ImageViewer::translateSpeed() const qreal mapcavas::translateSpeed() const
{ {
return m_translateSpeed; return m_translateSpeed;
} }
void ImageViewer::setZoomDelta(qreal delta) void mapcavas::setZoomDelta(qreal delta)
{ {
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Χ Q_ASSERT_X(delta >= 0.0 && delta <= 1.0,
Q_ASSERT_X(delta >= 0.0 && delta <= 1.0, "InteractiveView::setZoomDelta", "Delta should be in range [0.0, 1.0].");
"InteractiveView::setZoomDelta", "Delta should be in range [0.0, 1.0]."); m_zoomDelta = delta;
m_zoomDelta = delta;
} }
qreal ImageViewer::zoomDelta() const qreal mapcavas::zoomDelta() const
{ {
return m_zoomDelta; return m_zoomDelta;
}
// new: set associated raster layer
void mapcavas::setLayers(RasterLayer* layer)
{
m_rasterLayer = layer;
}
// new: refresh the map by rendering using the RasterLayer's render method
void mapcavas::freshmap()
{
if (!m_rasterLayer) return;
RasterLayer::RenderParams params; // default params; could be extended
QImage img = m_rasterLayer->render(params);
if (img.isNull()) return;
QPixmap pm = QPixmap::fromImage(img);
SetImage(&pm);
} }

View File

@ -1,15 +1,18 @@
#ifndef IMAGE_VIEWER #ifndef MAPCAVAS_H
#define IMAGE_VIEWER #define MAPCAVAS_H
#include "QGraphicsView" #include "QGraphicsView"
#include "qlabel.h" #include "qlabel.h"
class ImageViewer :public QGraphicsView
class RasterLayer; // forward
class mapcavas : public QGraphicsView
{ {
Q_OBJECT Q_OBJECT
public: public:
ImageViewer(QWidget* pParent = NULL); mapcavas(QWidget* pParent = NULL);
~ImageViewer(); ~mapcavas();
void DisplayFrameNumber(int frameNumber); void DisplayFrameNumber(int frameNumber);
@ -38,12 +41,18 @@ public:
// <20><><EFBFBD>ŵ<EFBFBD><C5B5><EFBFBD><EFBFBD><EFBFBD> // <20><><EFBFBD>ŵ<EFBFBD><C5B5><EFBFBD><EFBFBD><EFBFBD>
void setZoomDelta(qreal delta); void setZoomDelta(qreal delta);
qreal zoomDelta() const; qreal zoomDelta() const;
// new: set raster layer and refresh map
void setLayers(RasterLayer* layer);
void freshmap();
protected: protected:
QGraphicsScene *m_qtGraphicsScene; QGraphicsScene *m_qtGraphicsScene;
private: private:
QGraphicsPixmapItem *m_GraphicsPixmapItemHandle; QGraphicsPixmapItem *m_GraphicsPixmapItemHandle;
QLabel *m_framNumberLabel;//<2F><>ʾʵʱ<CAB5>ɼ<EFBFBD><C9BC><EFBFBD><EFBFBD><EFBFBD>֡<EFBFBD><D6A1> QLabel *m_framNumberLabel;//<2F><>ʾʵʱ<CAB5>ɼ<EFBFBD><C9BC><EFBFBD><EFBFBD><EFBFBD>֡<EFBFBD><D6A1>
RasterLayer* m_rasterLayer = nullptr; // associated raster layer
qreal m_translateSpeed; // ƽ<><C6BD><EFBFBD>ٶ<EFBFBD> qreal m_translateSpeed; // ƽ<><C6BD><EFBFBD>ٶ<EFBFBD>
qreal m_zoomDelta; // <20><><EFBFBD>ŵ<EFBFBD><C5B5><EFBFBD><EFBFBD><EFBFBD> qreal m_zoomDelta; // <20><><EFBFBD>ŵ<EFBFBD><C5B5><EFBFBD><EFBFBD><EFBFBD>

View File

@ -4,3 +4,19 @@ LayerTreeLayerNode::LayerTreeLayerNode(MapLayer* layer, QObject* parent)
: LayerTreeNode(layer ? layer->name() : QString(), parent), m_layer(layer) : LayerTreeNode(layer ? layer->name() : QString(), parent), m_layer(layer)
{ {
} }
LayerTreeNode::Type LayerTreeLayerNode::type() const
{
return Type::Layer;
}
// <20><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB> MapLayer ָ<><EFBFBD><EBA3A8>ӵ<EFBFBD>У<EFBFBD>
void LayerTreeLayerNode::setMapLayer(MapLayer* layer)
{
m_layer = layer;
}
MapLayer* LayerTreeLayerNode::mapLayer() const
{
return m_layer;
}

View File

@ -7,14 +7,13 @@ class LayerTreeLayerNode : public LayerTreeNode
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit LayerTreeLayerNode(MapLayer* layer, explicit LayerTreeLayerNode(MapLayer* layer, QObject* parent = nullptr);
QObject* parent = nullptr);
Type type() const override { return Type::Layer; } Type type() const override;
// <20><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB> MapLayer ָ<><EFBFBD><EBA3A8>ӵ<EFBFBD>У<EFBFBD> // <20><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB> MapLayer ָ<><EFBFBD><EBA3A8>ӵ<EFBFBD>У<EFBFBD>
void setMapLayer(MapLayer* layer) { m_layer = layer; } void setMapLayer(MapLayer* layer);
MapLayer* mapLayer() const { return m_layer; } MapLayer* mapLayer() const;
private: private:
MapLayer* m_layer = nullptr; MapLayer* m_layer = nullptr;

123
HPPA/RasterDataProvider.cpp Normal file
View File

@ -0,0 +1,123 @@
#include "RasterDataProvider.h"
#include <QString>
#include <QDebug>
#if HPPA_HAVE_GDAL
#include <gdal_priv.h>
#include <cpl_conv.h>
#endif
RasterDataProvider::RasterDataProvider(const QString& uri)
: m_uri(uri), m_dataset(nullptr)
{
}
RasterDataProvider::~RasterDataProvider()
{
close();
}
bool RasterDataProvider::open()
{
#if HPPA_HAVE_GDAL
GDALAllRegister();
m_dataset = (GDALDataset*)GDALOpen((const char*)m_uri.toLocal8Bit().constData(), GA_ReadOnly);
if (!m_dataset) {
qWarning() << "RasterDataProvider: failed to open dataset:" << m_uri;
return false;
}
return true;
#else
Q_UNUSED(m_uri);
qWarning() << "RasterDataProvider: GDAL not available, open will fail.";
return false;
#endif
}
void RasterDataProvider::close()
{
#if HPPA_HAVE_GDAL
if (m_dataset) {
GDALClose((GDALDatasetH)m_dataset);
m_dataset = nullptr;
}
#else
m_dataset = nullptr;
#endif
}
int RasterDataProvider::bandCount() const
{
#if HPPA_HAVE_GDAL
if (!m_dataset) return 0;
return m_dataset->GetRasterCount();
#else
Q_UNUSED(this);
return 0;
#endif
}
int RasterDataProvider::width() const
{
#if HPPA_HAVE_GDAL
if (!m_dataset) return 0;
return m_dataset->GetRasterXSize();
#else
Q_UNUSED(this);
return 0;
#endif
}
int RasterDataProvider::height() const
{
#if HPPA_HAVE_GDAL
if (!m_dataset) return 0;
return m_dataset->GetRasterYSize();
#else
Q_UNUSED(this);
return 0;
#endif
}
std::vector<double> RasterDataProvider::bandWavelengths() const
{
std::vector<double> res;
#if HPPA_HAVE_GDAL
if (!m_dataset) return res;
for (int i = 1; i <= m_dataset->GetRasterCount(); ++i) {
GDALRasterBand* band = m_dataset->GetRasterBand(i);
if (!band) continue;
// Attempt to read wavelength from metadata (commonly "Wavelength" or "wavelength")
const char* val = band->GetMetadataItem("Wavelength");
if (!val) val = band->GetMetadataItem("wavelength");
if (val) {
double v = atof(val);
res.push_back(v);
} else {
// push a negative to indicate unknown
res.push_back(-1.0);
}
}
#endif
return res;
}
bool RasterDataProvider::readBandAsFloat(int bandIndex, std::vector<float>& outBuffer) const
{
#if HPPA_HAVE_GDAL
if (!m_dataset) return false;
int bands = m_dataset->GetRasterCount();
if (bandIndex < 0 || bandIndex >= bands) return false;
GDALRasterBand* band = m_dataset->GetRasterBand(bandIndex + 1);
if (!band) return false;
int w = m_dataset->GetRasterXSize();
int h = m_dataset->GetRasterYSize();
outBuffer.assign(w * h, 0.0f);
CPLErr err = band->RasterIO(GF_Read, 0, 0, w, h, outBuffer.data(), w, h, GDT_Float32, 0, 0);
return err == CE_None;
#else
Q_UNUSED(bandIndex);
Q_UNUSED(outBuffer);
return false;
#endif
}

44
HPPA/RasterDataProvider.h Normal file
View File

@ -0,0 +1,44 @@
#pragma once
#include <QString>
#include <vector>
#if __has_include(<gdal_priv.h>)
#define HPPA_HAVE_GDAL 1
#include <gdal_priv.h>
#include <cpl_conv.h>
#else
#define HPPA_HAVE_GDAL 0
#endif
class RasterDataProvider
{
public:
explicit RasterDataProvider(const QString& uri);
~RasterDataProvider();
bool open();
void close();
int bandCount() const;
int width() const;
int height() const;
// Returns per-band wavelength metadata if available. If not available, returns empty vector.
std::vector<double> bandWavelengths() const;
// Read a single band (0-based index) into a float buffer of size width()*height().
// Returns true on success.
bool readBandAsFloat(int bandIndex, std::vector<float>& outBuffer) const;
QString uri() const { return m_uri; }
private:
QString m_uri;
#if HPPA_HAVE_GDAL
GDALDataset* m_dataset = nullptr;
#else
// no-op when GDAL not available
void* m_dataset = nullptr;
#endif
};

View File

@ -1,12 +1,48 @@
#include "RasterLayer.h" #include "RasterLayer.h"
#include "RasterDataProvider.h"
#include "RasterRenderer.h"
RasterLayer::RasterLayer(const QString& name, const QString& uri) RasterLayer::RasterLayer(const QString& name, const QString& uri)
: MapLayer(name, uri) : MapLayer(name, uri)
{ {
// lazy creation
} }
MapLayer::LayerType RasterLayer::layerType() const MapLayer::LayerType RasterLayer::layerType() const
{ {
return MapLayer::LayerType::Raster; return MapLayer::LayerType::Raster;
} }
RasterDataProvider* RasterLayer::dataProvider() const
{
return m_provider ? m_provider.get() : nullptr;
}
RasterRenderer* RasterLayer::renderer() const
{
return m_renderer ? m_renderer.get() : nullptr;
}
bool RasterLayer::openDataProvider()
{
if (!m_provider) m_provider = std::make_unique<RasterDataProvider>(dataPath());
if (!m_provider) return false;
bool ok = m_provider->open();
if (ok && !m_renderer) m_renderer = std::make_unique<RasterRenderer>(m_provider.get());
return ok;
}
QImage RasterLayer::render(const RenderParams& params)
{
if (!m_provider) {
if (!openDataProvider()) return QImage();
}
if (!m_renderer) m_renderer = std::make_unique<RasterRenderer>(m_provider.get());
RasterRenderer::Params p;
p.rWave = params.rWave;
p.gWave = params.gWave;
p.bWave = params.bWave;
p.minValue = params.minValue;
p.maxValue = params.maxValue;
return m_renderer->render(p);
}

View File

@ -1,6 +1,11 @@
#pragma once #pragma once
#include "MapLayer.h" #include "MapLayer.h"
#include <memory>
#include <QImage>
class RasterDataProvider;
class RasterRenderer;
class RasterLayer : public MapLayer class RasterLayer : public MapLayer
{ {
@ -10,5 +15,25 @@ public:
LayerType layerType() const override; LayerType layerType() const override;
// future: renderer, data provider, etc. // Access provider/renderer
RasterDataProvider* dataProvider() const;
RasterRenderer* renderer() const;
// Create or open provider based on this layer's uri
bool openDataProvider();
struct RenderParams {
double rWave = 665.0; // default wavelengths (nm)
double gWave = 560.0;
double bWave = 490.0;
double minValue = 0.0; // optional stretch
double maxValue = 255.0;
};
// Render the raster using current provider and renderer. Returns an empty QImage on failure.
QImage render(const RenderParams& params);
private:
std::unique_ptr<RasterDataProvider> m_provider;
std::unique_ptr<RasterRenderer> m_renderer;
}; };

86
HPPA/RasterRenderer.cpp Normal file
View File

@ -0,0 +1,86 @@
#include "RasterRenderer.h"
#include "RasterDataProvider.h"
#include <QDebug>
#include <algorithm>
RasterRenderer::RasterRenderer(RasterDataProvider* provider)
: m_provider(provider)
{
}
void RasterRenderer::stretchTo8bit(const std::vector<float>& in, std::vector<unsigned char>& out, float minVal, float maxVal)
{
size_t n = in.size();
out.resize(n);
if (maxVal <= minVal) {
std::fill(out.begin(), out.end(), 0);
return;
}
float denom = 1.0f / (maxVal - minVal);
for (size_t i = 0; i < n; ++i) {
float v = (in[i] - minVal) * denom;
v = std::min(std::max(v, 0.0f), 1.0f);
out[i] = static_cast<unsigned char>(v * 255.0f);
}
}
QImage RasterRenderer::render(const Params& params)
{
if (!m_provider) return QImage();
int bands = m_provider->bandCount();
int w = m_provider->width();
int h = m_provider->height();
if (w <= 0 || h <= 0) return QImage();
// Find nearest bands for requested wavelengths if wavelengths available
std::vector<double> wavelengths = m_provider->bandWavelengths();
auto chooseBandIndexForWave = [&](double wave)->int {
if (wavelengths.empty()) {
// fallback: select R,G,B as first three bands
if (bands >= 3) return (wave==params.rWave?0:(wave==params.gWave?1:2));
if (bands >= 1) return 0;
return -1;
}
int best = -1; double bestDiff = 1e12;
for (int i = 0; i < (int)wavelengths.size(); ++i) {
if (wavelengths[i] < 0) continue;
double d = std::abs(wavelengths[i] - wave);
if (d < bestDiff) { bestDiff = d; best = i; }
}
if (best >= 0) return best;
// fallback
return std::min(2, bands-1);
};
int rIdx = chooseBandIndexForWave(params.rWave);
int gIdx = chooseBandIndexForWave(params.gWave);
int bIdx = chooseBandIndexForWave(params.bWave);
std::vector<float> rbuf, gbuf, bbuf;
if (rIdx >= 0) m_provider->readBandAsFloat(rIdx, rbuf);
if (gIdx >= 0) m_provider->readBandAsFloat(gIdx, gbuf);
if (bIdx >= 0) m_provider->readBandAsFloat(bIdx, bbuf);
std::vector<unsigned char> r8, g8, b8;
float minV = static_cast<float>(params.minValue);
float maxV = static_cast<float>(params.maxValue);
if (!rbuf.empty()) stretchTo8bit(rbuf, r8, minV, maxV);
if (!gbuf.empty()) stretchTo8bit(gbuf, g8, minV, maxV);
if (!bbuf.empty()) stretchTo8bit(bbuf, b8, minV, maxV);
QImage out(w, h, QImage::Format_RGB888);
for (int y = 0; y < h; ++y) {
unsigned char* scan = out.scanLine(y);
for (int x = 0; x < w; ++x) {
int idx = y * w + x;
unsigned char rc = (r8.size() > (size_t)idx) ? r8[idx] : 0;
unsigned char gc = (g8.size() > (size_t)idx) ? g8[idx] : 0;
unsigned char bc = (b8.size() > (size_t)idx) ? b8[idx] : 0;
scan[x*3 + 0] = rc;
scan[x*3 + 1] = gc;
scan[x*3 + 2] = bc;
}
}
return out;
}

29
HPPA/RasterRenderer.h Normal file
View File

@ -0,0 +1,29 @@
#pragma once
#include <QImage>
#include <vector>
class RasterDataProvider;
class RasterRenderer
{
public:
struct Params {
double rWave = 665.0;
double gWave = 560.0;
double bWave = 490.0;
double minValue = 0.0;
double maxValue = 255.0;
};
explicit RasterRenderer(RasterDataProvider* provider);
// Render to an 8-bit RGB image. Returns empty image on failure.
QImage render(const Params& params);
private:
RasterDataProvider* m_provider;
// helper to map float buffer to 8-bit with min/max stretch
static void stretchTo8bit(const std::vector<float>& in, std::vector<unsigned char>& out, float minVal, float maxVal);
};