add
mapcavas添加功能:镜像和旋转,并保存配置
This commit is contained in:
@ -12,6 +12,9 @@ const double AppSettings::kDefaultScanSpeed = 1.0;
|
||||
const double AppSettings::kDefaultReturnSpeed = 5.0;
|
||||
const int AppSettings::kDefaultGonggaShanRecordPort = 666;
|
||||
const AppSettings::HyperimgDisplayMode AppSettings::kDefaultHyperimgDisplayMode = HyperimgDisplayMode::Waterfall;
|
||||
const bool AppSettings::kDefaultImageHorizontalMirror = true;
|
||||
const bool AppSettings::kDefaultImageVerticalMirror = true;
|
||||
const int AppSettings::kDefaultImageRotation = 0;
|
||||
|
||||
AppSettings::AppSettings()
|
||||
: m_settings(QSettings::IniFormat, QSettings::UserScope,
|
||||
@ -216,3 +219,33 @@ void AppSettings::setHyperimgDisplayMode(HyperimgDisplayMode mode)
|
||||
{
|
||||
m_settings.setValue("Display/HyperimgDisplayMode", static_cast<int>(mode));
|
||||
}
|
||||
|
||||
bool AppSettings::imageHorizontalMirror() const
|
||||
{
|
||||
return m_settings.value("Display/ImageHorizontalMirror", kDefaultImageHorizontalMirror).toBool();
|
||||
}
|
||||
|
||||
void AppSettings::setImageHorizontalMirror(bool value)
|
||||
{
|
||||
m_settings.setValue("Display/ImageHorizontalMirror", value);
|
||||
}
|
||||
|
||||
bool AppSettings::imageVerticalMirror() const
|
||||
{
|
||||
return m_settings.value("Display/ImageVerticalMirror", kDefaultImageVerticalMirror).toBool();
|
||||
}
|
||||
|
||||
void AppSettings::setImageVerticalMirror(bool value)
|
||||
{
|
||||
m_settings.setValue("Display/ImageVerticalMirror", value);
|
||||
}
|
||||
|
||||
int AppSettings::imageRotation() const
|
||||
{
|
||||
return m_settings.value("Display/ImageRotation", kDefaultImageRotation).toInt();
|
||||
}
|
||||
|
||||
void AppSettings::setImageRotation(int value)
|
||||
{
|
||||
m_settings.setValue("Display/ImageRotation", ((value % 360) + 360) % 360);
|
||||
}
|
||||
|
||||
@ -73,6 +73,18 @@ public:
|
||||
// 图像显示模式
|
||||
HyperimgDisplayMode hyperimgDisplayMode() const;
|
||||
void setHyperimgDisplayMode(HyperimgDisplayMode mode);
|
||||
|
||||
// 图像显示变换(左右镜像/上下镜像/旋转),全局生效
|
||||
bool imageHorizontalMirror() const;
|
||||
void setImageHorizontalMirror(bool value);
|
||||
|
||||
bool imageVerticalMirror() const;
|
||||
void setImageVerticalMirror(bool value);
|
||||
|
||||
// 旋转角度,取值 0、90、180、270
|
||||
int imageRotation() const;
|
||||
void setImageRotation(int value);
|
||||
|
||||
// 在此处添加更多参数的 getter/setter ...
|
||||
|
||||
private:
|
||||
@ -94,4 +106,7 @@ private:
|
||||
static const double kDefaultReturnSpeed;
|
||||
static const int kDefaultGonggaShanRecordPort;
|
||||
static const HyperimgDisplayMode kDefaultHyperimgDisplayMode;
|
||||
static const bool kDefaultImageHorizontalMirror;
|
||||
static const bool kDefaultImageVerticalMirror;
|
||||
static const int kDefaultImageRotation;
|
||||
};
|
||||
|
||||
@ -959,6 +959,9 @@ void HPPA::initMenubarToolbar()
|
||||
|
||||
ui.mActionPan->setIcon(QIcon(":/svg/resources/icons/svg/pan.svg"));
|
||||
ui.mActionSpectral->setIcon(QIcon(":/svg/resources/icons/svg/spectral.svg"));
|
||||
ui.mActionRotation90->setIcon(QIcon(":/svg/resources/icons/svg/rotate90.svg"));
|
||||
ui.mActionVerticalMirror->setIcon(QIcon(":/svg/resources/icons/svg/VerticalMirror.svg"));
|
||||
ui.mActionHorizontalMirror->setIcon(QIcon(":/svg/resources/icons/svg/HorizontalMirror.svg"));
|
||||
|
||||
connect(ui.mActionPan, &QAction::toggled, this, [=](bool checked) {
|
||||
if (checked)
|
||||
@ -974,6 +977,34 @@ void HPPA::initMenubarToolbar()
|
||||
ui.mActionSpectral->setIcon(QIcon(":/svg/resources/icons/svg/spectral.svg"));
|
||||
});
|
||||
|
||||
connect(ui.mActionRotation90, &QAction::triggered, this, [=](bool) {
|
||||
QWidget* currentWidget = m_imageViewerTabWidget->currentWidget();
|
||||
if (!currentWidget) return;
|
||||
|
||||
QList<Mapcavas*> canvases = currentWidget->findChildren<Mapcavas*>();
|
||||
if (canvases.isEmpty()) return;
|
||||
|
||||
canvases[0]->rotateImage90();
|
||||
});
|
||||
connect(ui.mActionVerticalMirror, &QAction::triggered, this, [=](bool) {
|
||||
QWidget* currentWidget = m_imageViewerTabWidget->currentWidget();
|
||||
if (!currentWidget) return;
|
||||
|
||||
QList<Mapcavas*> canvases = currentWidget->findChildren<Mapcavas*>();
|
||||
if (canvases.isEmpty()) return;
|
||||
|
||||
canvases[0]->toggleVerticalMirror();
|
||||
});
|
||||
connect(ui.mActionHorizontalMirror, &QAction::triggered, this, [=](bool) {
|
||||
QWidget* currentWidget = m_imageViewerTabWidget->currentWidget();
|
||||
if (!currentWidget) return;
|
||||
|
||||
QList<Mapcavas*> canvases = currentWidget->findChildren<Mapcavas*>();
|
||||
if (canvases.isEmpty()) return;
|
||||
|
||||
canvases[0]->toggleHorizontalMirror();
|
||||
});
|
||||
|
||||
// 使用样式表设置透明背景
|
||||
toolBar->setStyleSheet(R"(
|
||||
QToolBar {
|
||||
|
||||
@ -32,6 +32,9 @@
|
||||
<file>resources/icons/svg/tree_tri_down.svg</file>
|
||||
<file>resources/icons/svg/tree_tri_right.svg</file>
|
||||
<file>resources/icons/svg/mIconRaster.svg</file>
|
||||
<file>resources/icons/svg/HorizontalMirror.svg</file>
|
||||
<file>resources/icons/svg/rotate90.svg</file>
|
||||
<file>resources/icons/svg/VerticalMirror.svg</file>
|
||||
</qresource>
|
||||
<qresource prefix="/png">
|
||||
<file>resources/icons/png/Spectral_Insight_27.png</file>
|
||||
|
||||
24
HPPA/HPPA.ui
24
HPPA/HPPA.ui
@ -203,6 +203,9 @@ QToolBar QToolButton:hover {
|
||||
<addaction name="actionOpenDirectory"/>
|
||||
<addaction name="mActionPan"/>
|
||||
<addaction name="mActionSpectral"/>
|
||||
<addaction name="mActionVerticalMirror"/>
|
||||
<addaction name="mActionHorizontalMirror"/>
|
||||
<addaction name="mActionRotation90"/>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusBar">
|
||||
<property name="styleSheet">
|
||||
@ -758,6 +761,27 @@ QPushButton:pressed
|
||||
<string>贡嘎山旋转平台</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="mActionVerticalMirror">
|
||||
<property name="text">
|
||||
<string>上下镜像</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="mActionHorizontalMirror">
|
||||
<property name="text">
|
||||
<string>左右镜像</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>左右镜像</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="mActionRotation90">
|
||||
<property name="text">
|
||||
<string>旋转90度</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>旋转90度</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<customwidgets>
|
||||
|
||||
@ -49,7 +49,8 @@ Mapcavas::Mapcavas(QWidget* pParent) :QGraphicsView(pParent)
|
||||
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
setFrameShape(QFrame::NoFrame);
|
||||
|
||||
m_displayMode = AppSettings::instance().hyperimgDisplayMode();
|
||||
loadSettings();
|
||||
//addSceneCoordinateSystem();
|
||||
}
|
||||
|
||||
Mapcavas::~Mapcavas()
|
||||
@ -57,6 +58,94 @@ Mapcavas::~Mapcavas()
|
||||
|
||||
}
|
||||
|
||||
void Mapcavas::loadSettings()
|
||||
{
|
||||
updateDisplayMode();
|
||||
|
||||
//更新控制图像变换的变量m_imageTransformState
|
||||
AppSettings& settings = AppSettings::instance();
|
||||
m_imageTransformState.horizontalMirror = settings.imageHorizontalMirror();
|
||||
m_imageTransformState.verticalMirror = settings.imageVerticalMirror();
|
||||
m_imageTransformState.rotation = settings.imageRotation();
|
||||
}
|
||||
|
||||
void Mapcavas::applyImageTransform()
|
||||
{
|
||||
if (m_GraphicsPixmapItemHandle == nullptr)
|
||||
return;
|
||||
|
||||
const double sx = m_imageTransformState.horizontalMirror ? -1.0 : 1.0;
|
||||
const double sy = m_imageTransformState.verticalMirror ? -1.0 : 1.0;
|
||||
const QPointF center = m_GraphicsPixmapItemHandle->boundingRect().center();
|
||||
|
||||
QTransform transform_all;
|
||||
transform_all.translate(center.x(), center.y());// 围绕图片中心变换
|
||||
transform_all.scale(sx, sy);
|
||||
transform_all.rotate(m_imageTransformState.rotation);
|
||||
transform_all.translate(-center.x(), -center.y());
|
||||
|
||||
// setTransform 是替换而非叠加,因此可对已显示的图像重复调用
|
||||
m_GraphicsPixmapItemHandle->setTransform(transform_all);
|
||||
|
||||
//QPointF itemOrigin(0, 0);
|
||||
//QPointF sceneOrigin = m_GraphicsPixmapItemHandle->mapToScene(itemOrigin);
|
||||
//QPointF sceneOrigin2 = m_GraphicsPixmapItemHandle->scenePos();
|
||||
|
||||
// 变换后重新定位十字叉,使其始终跟随同一个图像像素
|
||||
repositionCrosshair();
|
||||
}
|
||||
|
||||
void Mapcavas::repositionCrosshair()
|
||||
{
|
||||
if (!m_hLine || !m_vLine || !m_GraphicsPixmapItemHandle)
|
||||
return;
|
||||
|
||||
const QPointF scenePt = m_GraphicsPixmapItemHandle->mapToScene(m_crosshairItemPos);
|
||||
m_hLine->setPos(scenePt);
|
||||
m_vLine->setPos(scenePt);
|
||||
}
|
||||
|
||||
void Mapcavas::refreshImageTransform()
|
||||
{
|
||||
if (!HasImage())
|
||||
return;
|
||||
|
||||
applyImageTransform();
|
||||
|
||||
if (m_displayMode == AppSettings::HyperimgDisplayMode::Full)
|
||||
{
|
||||
ensureSceneVisible();
|
||||
}
|
||||
else if (m_displayMode == AppSettings::HyperimgDisplayMode::Waterfall)
|
||||
{
|
||||
ensureWaterfallVisible();
|
||||
}
|
||||
}
|
||||
|
||||
void Mapcavas::rotateImage90()
|
||||
{
|
||||
AppSettings& settings = AppSettings::instance();
|
||||
settings.setImageRotation(settings.imageRotation() + 90);
|
||||
loadSettings();
|
||||
refreshImageTransform();
|
||||
}
|
||||
|
||||
void Mapcavas::toggleHorizontalMirror()
|
||||
{
|
||||
AppSettings& settings = AppSettings::instance();
|
||||
settings.setImageHorizontalMirror(!settings.imageHorizontalMirror());
|
||||
loadSettings();
|
||||
refreshImageTransform();
|
||||
}
|
||||
|
||||
void Mapcavas::toggleVerticalMirror()
|
||||
{
|
||||
AppSettings& settings = AppSettings::instance();
|
||||
settings.setImageVerticalMirror(!settings.imageVerticalMirror());
|
||||
loadSettings();
|
||||
refreshImageTransform();
|
||||
}
|
||||
|
||||
void Mapcavas::updateDisplayMode()
|
||||
{
|
||||
m_displayMode = AppSettings::instance().hyperimgDisplayMode();
|
||||
@ -79,14 +168,12 @@ void Mapcavas::SetImage(QPixmap *image)
|
||||
m_GraphicsPixmapItemHandle->setPixmap(*image);
|
||||
}
|
||||
|
||||
if (m_displayMode == AppSettings::HyperimgDisplayMode::Full)
|
||||
{
|
||||
ensureSceneVisible();
|
||||
}
|
||||
else if (m_displayMode == AppSettings::HyperimgDisplayMode::Waterfall)
|
||||
{
|
||||
ensureWaterfallVisible();
|
||||
}
|
||||
refreshImageTransform();
|
||||
}
|
||||
|
||||
QGraphicsPixmapItem* Mapcavas::pixmapItemHandle()
|
||||
{
|
||||
return m_GraphicsPixmapItemHandle;
|
||||
}
|
||||
|
||||
void Mapcavas::ensureSceneVisible()
|
||||
@ -108,40 +195,88 @@ void Mapcavas::ensureSceneVisible()
|
||||
|
||||
void Mapcavas::ensureWaterfallVisible()
|
||||
{
|
||||
resetTransform();
|
||||
|
||||
auto items = this->scene()->items();
|
||||
if (items.isEmpty())
|
||||
if (!HasImage())
|
||||
return;
|
||||
|
||||
auto scene_rect = this->scene()->itemsBoundingRect();
|
||||
resetTransform();
|
||||
|
||||
QGraphicsPixmapItem* item = m_GraphicsPixmapItemHandle;
|
||||
const QRectF item_rect = item->boundingRect();
|
||||
if (item_rect.isEmpty())
|
||||
return;
|
||||
|
||||
// 图像已经应用了 m_imageTransformState 的镜像/旋转,这里以场景中的实际位置为准
|
||||
const QRectF scene_rect = item->sceneBoundingRect();
|
||||
|
||||
qreal view_width = viewport()->rect().width();
|
||||
qreal view_height = viewport()->rect().height();
|
||||
if (view_width <= 0.0 || view_height <= 0.0)
|
||||
return;
|
||||
if (scene_rect.width() <= 0.0 || scene_rect.height() <= 0.0)
|
||||
return;
|
||||
|
||||
double x_scale = view_width / scene_rect.width();
|
||||
double y_scale = view_height / scene_rect.height();
|
||||
// 图像坐标中:x 为扫描线空间轴(固定),y 为采集帧数(不断增长),最新一帧位于 y 最大处。
|
||||
// 经过镜像/旋转后,增长轴可能竖直(0°/180°)或水平(90°/270°)。
|
||||
const QPointF growth_dir = item->mapToScene(QPointF(0.0, 1.0))
|
||||
- item->mapToScene(QPointF(0.0, 0.0));
|
||||
const bool growth_vertical = qAbs(growth_dir.y()) >= qAbs(growth_dir.x());
|
||||
|
||||
double scale_factor = qMin(x_scale, y_scale) * 0.9;
|
||||
// 最新一帧(图像底边中心)在场景中的位置,用于判断应该贴哪条边
|
||||
const QPointF newest_scene = item->mapToScene(
|
||||
QPointF(item_rect.width() / 2.0, item_rect.height()));
|
||||
|
||||
scale(x_scale, x_scale);
|
||||
m_scale *= x_scale;
|
||||
|
||||
// 计算缩放后的图片可见高度
|
||||
qreal scaled_height = scene_rect.height() * x_scale;
|
||||
|
||||
// 根据图片高度决定 Y 坐标
|
||||
qreal center_y;
|
||||
if (scaled_height <= view_height)
|
||||
if (growth_vertical)
|
||||
{
|
||||
center_y = scene_rect.center().y();
|
||||
// 竖直瀑布:空间轴横向铺满视图宽度,最新一帧固定在上/下边缘
|
||||
const double x_scale = view_width / scene_rect.width();
|
||||
scale(x_scale, x_scale);
|
||||
m_scale *= x_scale;
|
||||
|
||||
// 计算缩放后的图片可见高度
|
||||
qreal scaled_height = scene_rect.height() * x_scale;
|
||||
|
||||
qreal center_y;
|
||||
if (scaled_height <= view_height)
|
||||
{
|
||||
center_y = scene_rect.center().y();
|
||||
}
|
||||
else
|
||||
{
|
||||
qreal half_view_height = view_height / 2.0 / x_scale;
|
||||
if (newest_scene.y() >= scene_rect.center().y())
|
||||
center_y = scene_rect.bottom() - half_view_height; // 最新帧在下方,贴底
|
||||
else
|
||||
center_y = scene_rect.top() + half_view_height; // 最新帧在上方,贴顶
|
||||
}
|
||||
|
||||
centerOn(scene_rect.center().x(), center_y);
|
||||
}
|
||||
else
|
||||
{
|
||||
qreal half_view_height = view_height / 2.0 / x_scale;
|
||||
center_y = scene_rect.bottom() - half_view_height;
|
||||
}
|
||||
// 水平瀑布:空间轴竖向铺满视图高度,最新一帧固定在左/右边缘
|
||||
const double y_scale = view_height / scene_rect.height();
|
||||
scale(y_scale, y_scale);
|
||||
m_scale *= y_scale;
|
||||
|
||||
centerOn(scene_rect.center().x(), center_y);
|
||||
// 计算缩放后的图片可见宽度
|
||||
qreal scaled_width = scene_rect.width() * y_scale;
|
||||
|
||||
qreal center_x;
|
||||
if (scaled_width <= view_width)
|
||||
{
|
||||
center_x = scene_rect.center().x();
|
||||
}
|
||||
else
|
||||
{
|
||||
qreal half_view_width = view_width / 2.0 / y_scale;
|
||||
if (newest_scene.x() >= scene_rect.center().x())
|
||||
center_x = scene_rect.right() - half_view_width; // 最新帧在右侧,贴右
|
||||
else
|
||||
center_x = scene_rect.left() + half_view_width; // 最新帧在左侧,贴左
|
||||
}
|
||||
|
||||
centerOn(center_x, scene_rect.center().y());
|
||||
}
|
||||
}
|
||||
|
||||
bool Mapcavas::HasImage()
|
||||
@ -164,21 +299,32 @@ void Mapcavas::updateCrosshair(double sceneX, double sceneY)
|
||||
if (!m_hLine)
|
||||
{
|
||||
m_hLine = m_qtGraphicsScene->addLine(0, 0, 0, 0, pen);
|
||||
m_hLine->setFlag(QGraphicsItem::ItemIgnoresTransformations, true);
|
||||
m_hLine->setZValue(1e9);
|
||||
}
|
||||
if (!m_vLine)
|
||||
{
|
||||
m_vLine = m_qtGraphicsScene->addLine(0, 0, 0, 0, pen);
|
||||
m_vLine->setFlag(QGraphicsItem::ItemIgnoresTransformations, true);
|
||||
m_vLine->setZValue(1e9);
|
||||
}
|
||||
|
||||
m_hLine->setPen(pen);
|
||||
m_vLine->setPen(pen);
|
||||
|
||||
m_hLine->setLine(sceneX - m_CrosshairHalfLen, sceneY,
|
||||
sceneX + m_CrosshairHalfLen, sceneY);
|
||||
m_vLine->setLine(sceneX, sceneY - m_CrosshairHalfLen,
|
||||
sceneX, sceneY + m_CrosshairHalfLen);
|
||||
// 设置 ItemIgnoresTransformations 后,图元的原点依旧按场景坐标定位,
|
||||
// 但局部坐标不再受视图缩放影响(1 单位 = 1 屏幕像素)。
|
||||
// 这里把锚点记录在图像(图元)坐标系中,再据此定位十字叉:
|
||||
// 这样点击某个像素后,无论滚轮缩放还是镜像/旋转图像,十字叉都锚定在该像素上。
|
||||
const QPointF scenePt(sceneX + 0.5, sceneY + 0.5);
|
||||
m_crosshairItemPos = m_GraphicsPixmapItemHandle->mapFromScene(scenePt);
|
||||
|
||||
repositionCrosshair();
|
||||
|
||||
m_hLine->setLine(-m_CrosshairHalfLen, 0.0,
|
||||
m_CrosshairHalfLen, 0.0);
|
||||
m_vLine->setLine(0.0, -m_CrosshairHalfLen,
|
||||
0.0, m_CrosshairHalfLen);
|
||||
}
|
||||
|
||||
void Mapcavas::removeCrosshair()
|
||||
@ -197,6 +343,7 @@ void Mapcavas::removeCrosshair()
|
||||
delete m_vLine;
|
||||
m_vLine = nullptr;
|
||||
}
|
||||
m_crosshairItemPos = QPointF();
|
||||
}
|
||||
|
||||
|
||||
@ -376,3 +523,91 @@ MapTool* Mapcavas::mapTool() const
|
||||
{
|
||||
return m_mapTool;
|
||||
}
|
||||
|
||||
void Mapcavas::addSceneCoordinateSystem()
|
||||
{
|
||||
const double length = 200.0;
|
||||
const double arrowSize = 10.0;
|
||||
|
||||
// 坐标系作为参考叠加层,需要始终绘制在图像和其他图元之上;
|
||||
// 十字叉使用更大的 Z 值(1e9),因此这里取一个略小的值。
|
||||
const double zOrder = 1e8;
|
||||
|
||||
// X 轴
|
||||
QPen xPen(Qt::red);
|
||||
xPen.setWidth(2);
|
||||
|
||||
QGraphicsLineItem* xAxis = m_qtGraphicsScene->addLine(
|
||||
0, 0,
|
||||
length, 0,
|
||||
xPen
|
||||
);
|
||||
xAxis->setZValue(zOrder);
|
||||
|
||||
// X 箭头
|
||||
QPolygonF xArrow;
|
||||
xArrow << QPointF(length, 0)
|
||||
<< QPointF(length - arrowSize, -arrowSize / 2)
|
||||
<< QPointF(length - arrowSize, arrowSize / 2);
|
||||
|
||||
QGraphicsPolygonItem* xArrowItem = m_qtGraphicsScene->addPolygon(
|
||||
xArrow,
|
||||
xPen,
|
||||
QBrush(Qt::red)
|
||||
);
|
||||
xArrowItem->setZValue(zOrder);
|
||||
|
||||
|
||||
// Y 轴
|
||||
QPen yPen(Qt::green);
|
||||
yPen.setWidth(2);
|
||||
|
||||
QGraphicsLineItem* yAxis = m_qtGraphicsScene->addLine(
|
||||
0, 0,
|
||||
0, length,
|
||||
yPen
|
||||
);
|
||||
yAxis->setZValue(zOrder);
|
||||
|
||||
// Y 箭头
|
||||
QPolygonF yArrow;
|
||||
yArrow << QPointF(0, length)
|
||||
<< QPointF(-arrowSize / 2, length - arrowSize)
|
||||
<< QPointF(arrowSize / 2, length - arrowSize);
|
||||
|
||||
QGraphicsPolygonItem* yArrowItem = m_qtGraphicsScene->addPolygon(
|
||||
yArrow,
|
||||
yPen,
|
||||
QBrush(Qt::green)
|
||||
);
|
||||
yArrowItem->setZValue(zOrder);
|
||||
|
||||
|
||||
// 原点
|
||||
QGraphicsEllipseItem* originItem = m_qtGraphicsScene->addEllipse(
|
||||
-4, -4,
|
||||
8, 8,
|
||||
QPen(Qt::blue),
|
||||
QBrush(Qt::blue)
|
||||
);
|
||||
originItem->setZValue(zOrder);
|
||||
|
||||
|
||||
// X 标签
|
||||
QGraphicsTextItem* xText = m_qtGraphicsScene->addText("X");
|
||||
xText->setDefaultTextColor(Qt::red);
|
||||
xText->setPos(length + 5, -15);
|
||||
xText->setZValue(zOrder);
|
||||
|
||||
// Y 标签
|
||||
QGraphicsTextItem* yText = m_qtGraphicsScene->addText("Y");
|
||||
yText->setDefaultTextColor(Qt::green);
|
||||
yText->setPos(5, length + 5);
|
||||
yText->setZValue(zOrder);
|
||||
|
||||
// 原点标签
|
||||
QGraphicsTextItem* originText = m_qtGraphicsScene->addText("(0, 0)");
|
||||
originText->setDefaultTextColor(Qt::blue);
|
||||
originText->setPos(5, 5);
|
||||
originText->setZValue(zOrder);
|
||||
}
|
||||
|
||||
@ -61,6 +61,16 @@ public:
|
||||
void unsetMapTool(MapTool* tool);
|
||||
MapTool* mapTool() const;
|
||||
|
||||
QGraphicsPixmapItem* pixmapItemHandle();
|
||||
|
||||
// 图像显示变换(左右镜像/上下镜像/旋转),状态保存在 AppSettings 中全局生效
|
||||
void rotateImage90();
|
||||
void toggleHorizontalMirror();
|
||||
void toggleVerticalMirror();
|
||||
|
||||
// 把当前的镜像/旋转重新应用到已经显示的图像,并按显示模式重新适配视图
|
||||
void refreshImageTransform();
|
||||
|
||||
protected:
|
||||
QGraphicsScene *m_qtGraphicsScene;
|
||||
private:
|
||||
@ -79,9 +89,24 @@ private:
|
||||
double m_CrosshairHalfLen = 10.0;
|
||||
QGraphicsLineItem* m_hLine = nullptr; // horizontal line
|
||||
QGraphicsLineItem* m_vLine = nullptr; // vertical line
|
||||
QPointF m_crosshairItemPos; // 十字叉锚点,保存在图像(图元)坐标系
|
||||
|
||||
AppSettings::HyperimgDisplayMode m_displayMode;
|
||||
|
||||
struct ImageTransformState
|
||||
{
|
||||
bool horizontalMirror = true;
|
||||
bool verticalMirror = true;
|
||||
int rotation = 90*3; // 0、90、180、270
|
||||
};
|
||||
ImageTransformState m_imageTransformState;
|
||||
|
||||
void applyImageTransform();
|
||||
void repositionCrosshair();
|
||||
void loadSettings();
|
||||
|
||||
void addSceneCoordinateSystem();
|
||||
|
||||
signals:
|
||||
void leftMouseButtonPressed(int, int, QVector<double>, QVector<double>);
|
||||
};
|
||||
|
||||
@ -37,21 +37,35 @@ void MapToolSpectral::canvasMousePressEvent(QMouseEvent* e)
|
||||
if (!canvas())
|
||||
return;
|
||||
|
||||
const QPointF scenePt = canvas()->mapToScene(e->pos());
|
||||
const int x = static_cast<int>(std::floor(scenePt.x()));
|
||||
const int y = static_cast<int>(std::floor(scenePt.y()));
|
||||
//获取图像元素
|
||||
QGraphicsPixmapItem* item = canvas()->pixmapItemHandle();
|
||||
QPointF scenePos = item->pos();
|
||||
QPointF scenePos2 = item->scenePos();
|
||||
|
||||
if (item==nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QPointF scenePt = canvas()->mapToScene(e->pos());
|
||||
int x_scenePt = static_cast<int>(std::floor(scenePt.x()));
|
||||
int y_scenePt = static_cast<int>(std::floor(scenePt.y()));
|
||||
|
||||
QPointF itemPt = item->mapFromScene(scenePt);
|
||||
int x_itemPt = static_cast<int>(std::floor(itemPt.x()));
|
||||
int y_itemPt = static_cast<int>(std::floor(itemPt.y()));
|
||||
|
||||
auto* imageLayer = canvas()->imageLayer();
|
||||
RasterLayer* rl = imageLayer ? imageLayer->layer() : nullptr;
|
||||
if (rl && rl->isValidPixel(x, y))
|
||||
if (rl && rl->isValidPixel(x_itemPt, y_itemPt))
|
||||
{
|
||||
canvas()->updateCrosshair(x + 0.5, y + 0.5);
|
||||
canvas()->updateCrosshair(x_scenePt + 0.5, y_scenePt + 0.5);
|
||||
|
||||
QVector<double> wavelengths;
|
||||
QVector<double> spectrum;
|
||||
if (rl->readPixelSpectrum(x, y, wavelengths, spectrum))
|
||||
if (rl->readPixelSpectrum(x_itemPt, y_itemPt, wavelengths, spectrum))
|
||||
{
|
||||
emit spectralClicked(x, y, wavelengths, spectrum);
|
||||
emit spectralClicked(x_itemPt, y_itemPt, wavelengths, spectrum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user