gpt4 book ai didi

c++ - QGraphicsScene/View 比例理解

转载 作者:太空狗 更新时间:2023-10-29 21:14:29 25 4
gpt4 key购买 nike

我迷失了对 QGraphicsScene/View 的比例值的理解。

下面是我如何在场景中放置目标。

QPointF Mainwindow::pointLocation(double bearing, double range){
int offset = 90; //used to offset Cartesian system
double centerX = baseSceneSize/2;//push my center location out to halfway point
double centerY = baseSceneSize/2;
double newX = centerX + qCos(qDegreesToRadians(bearing - offset)) * range;
double newY = centerY + qSin(qDegreesToRadians(bearing - offset)) * range;
QPointF newPoint = QPointF(newX, newY);
return newPoint;

}

所以每个目标都有方位和范围。只要我不缩放或缩放场景,这些值就足够了。我的问题是我需要实现缩放。

这里是出错的地方:

我的目标是方位角 270,范围 10。

当应用程序运行时,我的垂直 slider 的值为零,我可以在我的 View 中看到这个目标。我不应该。我只需要在 slider 达到值 10 时才能看到此目标。只需将 slider 上的每个位置值视为 1 海里即可。因此,如果目标位于 10 海里,则只有当 slider >= 10 时,它才应该可见。

这是我进行缩放的方式:

void MainWindow:: on_PlotSlider_sliderMoved(int position){
const qreal factor = 1.01;
viewScaleValue = qPow(factor, -position);//-position to invert the scale
QMatrix matrix;
matrix.scale(viewScaleValue, viewScaleValue);
view->setMatrix(matrix);
}

我试过使 View 变大,场景变大,但没有任何效果。

这是我的场景设置:

view = ui->GraphicsView;
scene = new QGraphicsScene(this);
int baseSize = 355;
scene->setSceneRect(0,0,baseSize,baseSize);
baseSceneSize = scene->sceneRect().width();
view->setScene(scene);

如何获取目标范围并将其推到场景中,使其与 slider 值对齐?

最佳答案

QGraphicsView::fitInView 是您选择显示范围和居中 View 所需的一切。

以下是您可能的做法。这是一个完整的例子。

screenshot of the example

// https://github.com/KubaO/stackoverflown/tree/master/questions/scene-radar-40680065
#include <QtWidgets>
#include <random>

首先,让我们获取随机目标位置。场景按比例缩放。海里:因此场景中的任何坐标都应采用这些单位。这只是一个约定:否则场景不关心, View 也不关心。引用点位于 0,0:所有范围/方位角均相对于原点。

QPointF randomPosition() {
static std::random_device dev;
static std::default_random_engine eng(dev());
static std::uniform_real_distribution<double> posDis(-100., 100.); // NM
return {posDis(eng), posDis(eng)};
}

然后,为了帮助打开和关闭场景项目组(例如标线),为它们设置一个空的父项目会有所帮助:

class EmptyItem : public QGraphicsItem {
public:
QRectF boundingRect() const override { return QRectF(); }
void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) override {}
};

场景管理员设置显示。空项目充当项目集合,可以轻松地将它们隐藏/可见,而无需修改子项目。他们还强制执行其子级的相对 Z 顺序。

class SceneManager : public QObject {
Q_OBJECT
Q_PROPERTY(bool microGraticuleVisible READ microGraticuleVisible WRITE setMicroGraticuleVisible)
QGraphicsScene m_scene;
QPen m_targetPen{Qt::green, 1};
EmptyItem m_target, m_center, m_macroGraticule, m_microGraticule;

可以在 View 上安装事件过滤器,以在调整 View 大小时发出信号。这可用于在调整大小的情况下保持 View 居中:

    bool eventFilter(QObject *watched, QEvent *event) override {
if (event->type() == QEvent::Resize
&& qobject_cast<QGraphicsView*>(watched))
emit viewResized();
return QObject::eventFilter(watched, event);
}

场景具有以下 Z 顺序:中心交叉、宏观和微观网格,然后目标在顶部。

public:
SceneManager() {
m_scene.addItem(&m_center);
m_scene.addItem(&m_macroGraticule);
m_scene.addItem(&m_microGraticule);
m_scene.addItem(&m_target);
m_targetPen.setCosmetic(true);
addGraticules();
}

我们可以监 View 形 View 以调整大小;我们还公开了微格线的可见性。

    void monitor(QGraphicsView *view) { view->installEventFilter(this); }
QGraphicsScene * scene() { return &m_scene; }
Q_SLOT void setMicroGraticuleVisible(bool vis) { m_microGraticule.setVisible(vis); }
bool microGraticuleVisible() const { return m_microGraticule.isVisible(); }
Q_SIGNAL void viewResized();

目标可以随机生成。目标在 View 坐标中具有固定大小。不过,它的位置会受到任何场景到 View 转换的影响。

目标和标线的笔是修饰笔:它们的宽度以 View 设备单位(像素)而非场景单位给出。

    void newTargets(int count = 200) {
qDeleteAll(m_target.childItems());
for (int i = 0; i < count; ++i) {
auto target = new QGraphicsEllipseItem(-1.5, -1.5, 3., 3., &m_target);
target->setPos(randomPosition());
target->setPen(m_targetPen);
target->setBrush(m_targetPen.color());
target->setFlags(QGraphicsItem::ItemIgnoresTransformations);
}
}

格线是以原点(范围引用点)为中心的同心圆和原点的十字。原点十字在 View 单位中具有固定大小 - 这由 ItemIgnoresTransformations 标志指示。

   void addGraticules() {
QPen pen{Qt::white, 1};
pen.setCosmetic(true);
auto center = {QLineF{-5.,0.,5.,0.}, QLineF{0.,-5.,0.,5.}};
for (auto l : center) {
auto c = new QGraphicsLineItem{l, &m_center};
c->setFlags(QGraphicsItem::ItemIgnoresTransformations);
c->setPen(pen);
}
for (auto range = 10.; range < 101.; range += 10.) {
auto circle = new QGraphicsEllipseItem(0.-range, 0.-range, 2.*range, 2.*range, &m_macroGraticule);
circle->setPen(pen);
}
pen = QPen{Qt::white, 1, Qt::DashLine};
pen.setCosmetic(true);
for (auto range = 2.5; range < 9.9; range += 2.5) {
auto circle = new QGraphicsEllipseItem(0.-range, 0.-range, 2.*range, 2.*range, &m_microGraticule);
circle->setPen(pen);
}
}
};

场景单元和 View 之间的映射维护如下:

  1. 每次更改 View 范围(例如从组合框)时,QGraphicsView::fitInView 方法都会以场景单位(海里)为单位调用一个矩形。这会处理所有的缩放、居中等。例如。要选择 10NM 的范围,我们将调用 view.fitInView(QRect{-10.,-10.,20.,20.), Qt::KeepAspectRatio)

    <
  2. 可以根据给定范围的需要禁用/启用标线,以使 View 整洁。

    int main(int argc, char ** argv) {
    QApplication app{argc, argv};
    SceneManager mgr;
    mgr.newTargets();

    QWidget w;
    QGridLayout layout{&w};
    QGraphicsView view;
    QComboBox combo;
    QPushButton newTargets{"New Targets"};
    layout.addWidget(&view, 0, 0, 1, 2);
    layout.addWidget(&combo, 1, 0);
    layout.addWidget(&newTargets, 1, 1);

    view.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    view.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    view.setBackgroundBrush(Qt::black);
    view.setScene(mgr.scene());
    view.setRenderHint(QPainter::Antialiasing);
    mgr.monitor(&view);

    combo.addItems({"10", "25", "50", "100"});
    auto const recenterView = [&]{
    auto range = combo.currentText().toDouble();
    view.fitInView(-range, -range, 2.*range, 2.*range, Qt::KeepAspectRatio);
    mgr.setMicroGraticuleVisible(range <= 20.);
    };
    QObject::connect(&combo, &QComboBox::currentTextChanged, recenterView);
    QObject::connect(&mgr, &SceneManager::viewResized, recenterView);
    QObject::connect(&newTargets, &QPushButton::clicked, [&]{ mgr.newTargets(); });
    w.show();
    return app.exec();
    }

    #include "main.moc"

关于c++ - QGraphicsScene/View 比例理解,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40680065/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com