339 lines
7.3 KiB
C++
339 lines
7.3 KiB
C++
#include "stdafx.h"
|
|
#include <iostream>
|
|
#include <cmath>
|
|
|
|
#include <QWheelEvent>
|
|
#include <QPoint>
|
|
|
|
#include "ImageViewer.h"
|
|
#include "RasterLayer.h"
|
|
#include "MapTool.h"
|
|
|
|
|
|
#define VIEW_CENTER viewport()->rect().center()
|
|
#define VIEW_WIDTH viewport()->rect().width()
|
|
#define VIEW_HEIGHT viewport()->rect().height()
|
|
|
|
Mapcavas::Mapcavas(QWidget* pParent) :QGraphicsView(pParent)
|
|
{
|
|
setRenderHint(QPainter::Antialiasing);
|
|
setRenderHint(QPainter::SmoothPixmapTransform);
|
|
setDragMode(QGraphicsView::ScrollHandDrag);
|
|
|
|
// 使用 Qt 默认 anchor 行为以外的配置
|
|
setTransformationAnchor(QGraphicsView::NoAnchor);
|
|
setResizeAnchor(QGraphicsView::NoAnchor);
|
|
|
|
m_qtGraphicsScene = new QGraphicsScene(this);
|
|
this->setScene(m_qtGraphicsScene);
|
|
m_qtGraphicsScene->setSceneRect(-1e6, -1e6, 2e6, 2e6);
|
|
|
|
m_framNumberLabel = new QLabel(this);
|
|
m_framNumberLabel->setAlignment(Qt::AlignHCenter);
|
|
m_framNumberLabel->setAlignment(Qt::AlignVCenter);
|
|
|
|
QFont ft;
|
|
ft.setPointSize(14);
|
|
m_framNumberLabel->setFont(ft);
|
|
m_framNumberLabel->setText("0");
|
|
|
|
|
|
m_GraphicsPixmapItemHandle = nullptr;
|
|
|
|
m_scale = 1.0;
|
|
m_zoomDelta = 0.1;
|
|
m_translateSpeed = 1.0;
|
|
m_bMouseTranslate = false;
|
|
|
|
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
|
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
|
setFrameShape(QFrame::NoFrame);
|
|
}
|
|
|
|
Mapcavas::~Mapcavas()
|
|
{
|
|
|
|
}
|
|
|
|
void Mapcavas::DisplayFrameNumber(int frameNumber)
|
|
{
|
|
m_framNumberLabel->setText(QString::number(frameNumber));
|
|
m_framNumberLabel->adjustSize();
|
|
}
|
|
|
|
void Mapcavas::SetImage(QPixmap *image)
|
|
{
|
|
if (!HasImage())
|
|
{
|
|
m_GraphicsPixmapItemHandle = m_qtGraphicsScene->addPixmap(*image);
|
|
}
|
|
else
|
|
{
|
|
m_GraphicsPixmapItemHandle->setPixmap(*image);
|
|
}
|
|
ensureSceneVisible();
|
|
}
|
|
|
|
void Mapcavas::ensureSceneVisible()
|
|
{
|
|
resetTransform();
|
|
|
|
auto view_rect = viewport()->rect();
|
|
auto scene_rect = this->scene()->itemsBoundingRect();
|
|
|
|
double x_ratio = view_rect.width() / scene_rect.width();
|
|
double y_ratio = view_rect.height() / scene_rect.height();
|
|
double scale_factor = std::min(x_ratio, y_ratio) * 0.9;
|
|
|
|
scale(scale_factor, scale_factor);
|
|
m_scale *= scale_factor;
|
|
|
|
centerOn(scene_rect.center());
|
|
}
|
|
|
|
bool Mapcavas::HasImage()
|
|
{
|
|
if (m_GraphicsPixmapItemHandle == nullptr)
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
void Mapcavas::updateCrosshair(double sceneX, double sceneY)
|
|
{
|
|
QPen pen(Qt::red, 2.0);
|
|
pen.setCosmetic(true); // constant screen-width regardless of zoom
|
|
|
|
if (!m_hLine)
|
|
{
|
|
m_hLine = m_qtGraphicsScene->addLine(0, 0, 0, 0, pen);
|
|
m_hLine->setZValue(1e9);
|
|
}
|
|
if (!m_vLine)
|
|
{
|
|
m_vLine = m_qtGraphicsScene->addLine(0, 0, 0, 0, pen);
|
|
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);
|
|
}
|
|
|
|
void Mapcavas::removeCrosshair()
|
|
{
|
|
if (m_hLine)
|
|
{
|
|
if (m_hLine->scene())
|
|
m_hLine->scene()->removeItem(m_hLine);
|
|
delete m_hLine;
|
|
m_hLine = nullptr;
|
|
}
|
|
if (m_vLine)
|
|
{
|
|
if (m_vLine->scene())
|
|
m_vLine->scene()->removeItem(m_vLine);
|
|
delete m_vLine;
|
|
m_vLine = nullptr;
|
|
}
|
|
}
|
|
|
|
|
|
void Mapcavas::wheelEvent(QWheelEvent *event)
|
|
{
|
|
// Always let the tool have a chance first
|
|
if (m_mapTool)
|
|
{
|
|
m_mapTool->canvasWheelEvent(event);
|
|
}
|
|
|
|
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());
|
|
}
|
|
}
|
|
|
|
void Mapcavas::scaling(qreal scaleFactor)
|
|
{
|
|
scale(scaleFactor, scaleFactor);
|
|
}
|
|
|
|
void Mapcavas::mousePressEvent(QMouseEvent *event)
|
|
{
|
|
if (m_mapTool)
|
|
{
|
|
m_mapTool->canvasMousePressEvent(event);
|
|
QGraphicsView::mousePressEvent(event);
|
|
return;
|
|
}
|
|
QGraphicsView::mousePressEvent(event);
|
|
}
|
|
|
|
void Mapcavas::mouseMoveEvent(QMouseEvent *event)
|
|
{
|
|
if (m_mapTool)
|
|
{
|
|
m_mapTool->canvasMouseMoveEvent(event);
|
|
QGraphicsView::mousePressEvent(event);
|
|
return;
|
|
}
|
|
|
|
QGraphicsView::mousePressEvent(event);
|
|
}
|
|
|
|
void Mapcavas::mouseReleaseEvent(QMouseEvent *event)
|
|
{
|
|
if (m_mapTool)
|
|
{
|
|
m_mapTool->canvasMouseReleaseEvent(event);
|
|
QGraphicsView::mouseReleaseEvent(event);
|
|
return;
|
|
}
|
|
|
|
QGraphicsView::mouseReleaseEvent(event);
|
|
}
|
|
|
|
void Mapcavas::mouseDoubleClickEvent(QMouseEvent *event)
|
|
{
|
|
if (m_mapTool)
|
|
{
|
|
m_mapTool->canvasMouseDoubleClickEvent(event);
|
|
return;
|
|
}
|
|
|
|
QGraphicsView::mouseDoubleClickEvent(event);
|
|
}
|
|
|
|
void Mapcavas::zoomIn()
|
|
{
|
|
zoom(1 + m_zoomDelta);
|
|
}
|
|
|
|
void Mapcavas::zoomOut()
|
|
{
|
|
zoom(1 - m_zoomDelta);
|
|
}
|
|
|
|
void Mapcavas::zoom(float scaleFactor)
|
|
{
|
|
qreal factor = transform().scale(scaleFactor, scaleFactor).mapRect(QRectF(0, 0, 1, 1)).width();
|
|
if (factor < 0.07 || factor > 100)
|
|
return;
|
|
|
|
scale(scaleFactor, scaleFactor);
|
|
m_scale *= scaleFactor;
|
|
}
|
|
|
|
void Mapcavas::setTranslateSpeed(qreal speed)
|
|
{
|
|
Q_ASSERT_X(speed >= 0.0 && speed <= 2.0,
|
|
"InteractiveView::setTranslateSpeed", "Speed should be in range [0.0, 2.0].");
|
|
m_translateSpeed = speed;
|
|
}
|
|
|
|
qreal Mapcavas::translateSpeed() const
|
|
{
|
|
return m_translateSpeed;
|
|
}
|
|
|
|
void Mapcavas::setZoomDelta(qreal delta)
|
|
{
|
|
Q_ASSERT_X(delta >= 0.0 && delta <= 1.0,
|
|
"InteractiveView::setZoomDelta", "Delta should be in range [0.0, 1.0].");
|
|
m_zoomDelta = delta;
|
|
}
|
|
|
|
qreal Mapcavas::zoomDelta() const
|
|
{
|
|
return m_zoomDelta;
|
|
}
|
|
|
|
// new: set associated raster layer
|
|
void Mapcavas::setLayers(RasterLayer* layer)
|
|
{
|
|
m_rasterLayer = layer;
|
|
}
|
|
|
|
RasterLayer* Mapcavas::rasterLayer() const
|
|
{
|
|
return m_rasterLayer;
|
|
}
|
|
|
|
// new: refresh the map by rendering using the RasterLayer's render method
|
|
void Mapcavas::freshmap()
|
|
{
|
|
if (!m_rasterLayer) return;
|
|
|
|
RasterLayer::RenderParams params = m_rasterLayer->currentRenderParams();
|
|
QImage img = m_rasterLayer->render(params);
|
|
if (img.isNull()) return;
|
|
|
|
QPixmap pm = QPixmap::fromImage(img);
|
|
SetImage(&pm);
|
|
}
|
|
|
|
void Mapcavas::freshmap(const RasterLayer::RenderParams& params)
|
|
{
|
|
if (!m_rasterLayer) return;
|
|
|
|
QImage img = m_rasterLayer->render(params);
|
|
if (img.isNull()) return;
|
|
|
|
QPixmap pm = QPixmap::fromImage(img);
|
|
SetImage(&pm);
|
|
}
|
|
|
|
// MapTool management
|
|
void Mapcavas::setMapTool(MapTool* tool)
|
|
{
|
|
if (m_mapTool)
|
|
{
|
|
m_mapTool->deactivate();
|
|
}
|
|
|
|
m_mapTool = tool;
|
|
|
|
if (m_mapTool)
|
|
{
|
|
// Disable built-in drag mode so the tool controls everything
|
|
setDragMode(QGraphicsView::NoDrag);
|
|
m_mapTool->activate();
|
|
}
|
|
else
|
|
{
|
|
// Restore legacy drag mode when no tool
|
|
setDragMode(QGraphicsView::ScrollHandDrag);
|
|
}
|
|
}
|
|
|
|
void Mapcavas::unsetMapTool(MapTool* tool)
|
|
{
|
|
if (m_mapTool && m_mapTool == tool)
|
|
{
|
|
m_mapTool->deactivate();
|
|
m_mapTool = nullptr;
|
|
setDragMode(QGraphicsView::ScrollHandDrag);
|
|
}
|
|
}
|
|
|
|
MapTool* Mapcavas::mapTool() const
|
|
{
|
|
return m_mapTool;
|
|
}
|