QPainter drawPie не рисует начальный угол в правильном положении - PullRequest
0 голосов
/ 30 марта 2019

Я использую QGraphicsView вместе с пользовательской реализацией QAbstractGraphicsItem для рисования стрелки и эллипса, которые могут вращаться вокруг центральной точки графического элемента (по этой причине в примере отсутствует часть перевода) , Желаемое поведение, которое я хочу, это иметь возможность рисовать синюю линию, которая идет от центра эллипса к его краю под углом стрелки (реальное приложение будет показывать круглое сечение вместо линии). Кроме того, для облегчения понимания того, что происходит на чертеже, две основные оси эллипса изображены красным и зеленым. Вот мой товар:

Заголовок

#include <QAbstractGraphicsShapeItem>

class EllipseItem : public QAbstractGraphicsShapeItem
{
public:
  double ellipse_x;
  double ellipse_y;
  double ellipse_rot;
  double arrow_angle;
  double arrow_scale;

  virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
  virtual QRectF boundingRect() const;
};

Осуществление

#include "ellipseitem.h"

#include <QPainter>

void EllipseItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
  Q_UNUSED(option);
  Q_UNUSED(widget);

  painter->setPen(pen());
  painter->setBrush(brush());

  QPolygonF arrow;
  arrow.append(QPointF(0, -arrow_scale / 2));
  arrow.append(QPointF(arrow_scale * 3 / 4, 0));
  arrow.append(QPointF(0, arrow_scale / 2));
  arrow.append(QPointF(-arrow_scale / 4, 0));
  painter->save();
  painter->rotate(arrow_angle);
  painter->drawPolygon(arrow);
  painter->restore();

  painter->save();
  painter->rotate(ellipse_rot);
  painter->drawEllipse(QPointF(0, 0), ellipse_x, ellipse_y);
  painter->setPen(QPen(Qt::red));
  painter->drawPie(QRectF(-ellipse_x, -ellipse_y, 2 * ellipse_x, 2 * ellipse_y), 0, 0);
  painter->setPen(QPen(Qt::green));
  painter->drawPie(QRectF(-ellipse_x, -ellipse_y, 2 * ellipse_x, 2 * ellipse_y), 90 * 16, 0);
  painter->setPen(QPen(Qt::blue));
  double angle = arrow_angle - ellipse_rot;
  painter->drawPie(QRectF(-ellipse_x, -ellipse_y, 2 * ellipse_x, 2 * ellipse_y), -(angle)*16, 0);
  painter->restore();
}

QRectF EllipseItem::boundingRect() const
{
  double mx = std::max(ellipse_x, std::max(ellipse_y, arrow_scale * 3 / 4));
  return QRectF(-mx, -mx, 2 * mx, 2 * mx);
}

Моя проблема в том, что, когда я поворачиваюсь вокруг своей стрелки, линия, которую я рисую на эллипсе, совпадает только тогда, когда стрелка совмещена с осью эллипса (либо x, либо у), как вы можете видеть на приложенных изображениях , Есть идеи, что я делаю не так?

В этом репо содержится минимально полный проверяемый пример.

На следующих изображениях показаны 5 основных параметров:

  1. Угол стрелки (град): это поворот стрелки от оси x в градусах с положительным направлением по часовой стрелке
  2. Эллипс x: размер радиусов x эллипса
  3. Ellipse y: размерность радиусов y эллипса
  4. Ellipse rot: вращение эллипса от оси x в градусах с положительным направлением по часовой стрелке
  5. Масштаб: масштаб нарисованной стрелки.

Ellipse angle: 0, Arrow angle: 0 На изображении выше показана стрелка, указывающая вправо под углом 0, и направление y (зеленая линия) эллипса, направленное вверх под углом 90, указывающее, что эллипс имеет вращение 0. Синяя линия и наконечник стрелки совпадают , Желаемое поведение. Ellipse angle: 0, Arrow angle: 45 На изображении выше показана стрелка, указывающая «юго-восток» под углом 45 градусов, и направление x (красная линия) эллипса, направленное вправо на угол 0 (эллипс не вращается). Синяя линия не совпадает с наконечником стрелки, хотя она была нарисована под тем же углом, который использовался для рисования стрелки. Не желаемое поведение. Ellipse angle: 0, Arrow angle: 80 На изображении выше показана стрелка, указывающая «юг-юго-восток» под углом 80 градусов, и направление х (красная линия) эллипса, направленное вправо на угол 0 (эллипс не вращается). Синяя линия не совпадает с наконечником стрелки, хотя она была нарисована под тем же углом, который использовался для рисования стрелки. Не желаемое поведение. Ellipse angle: 0, Arrow angle: 90 На изображении выше показана стрелка, указывающая «на юг» под углом 90 градусов, и направление x (красная линия) эллипса, направленное вправо на угол 0 (эллипс не вращается). Синяя линия совпадает с наконечником стрелки. Желаемое поведение. Ellipse angle: 0, Arrow angle: 20 На изображении выше показана стрелка, указывающая «восток-юго-восток» под углом 20 градусов, и направление х (красная линия) эллипса, направленное вправо на угол 0 (эллипс не вращается). Синяя линия не совпадает с наконечником стрелки, хотя она была нарисована под тем же углом, который использовался для рисования стрелки. Не желаемое поведение. Ellipse angle: 20, Arrow angle: 20 На изображении выше показана стрелка, указывающая «восток-юго-восток» под углом 20 градусов, и направление x (красная линия) эллипса, указывающее «восток-юго-восток» под углом 20 (эллипс повернут на 20 градусов). Синяя линия совпадает с наконечником стрелки. Желаемое поведение. Ellipse angle: 60, Arrow angle: 20 На изображении выше показана стрелка, указывающая «восток-юго-восток» под углом 20 градусов, и направление х (красная линия) эллипса, указывающее «юго-восток» под углом 60 (эллипс повернут на 60 градусов). Синяя линия не совпадает с наконечником стрелки. Не желаемое поведение. Ellipse angle: 95, Arrow angle: 20На изображении выше показана стрелка, указывающая «восток-юго-восток» под углом 20 градусов, и направление х (красная линия) эллипса, указывающее «юго-восток» под углом 95 (эллипс повернут на 95 градусов).Синяя линия не совпадает с наконечником стрелки.Не желаемое поведение.Ellipse angle: 110, Arrow angle: 20 На приведенном выше рисунке показана стрелка, указывающая «восток-юго-восток» под углом 20 градусов, и направление х (красная линия) эллипса, указывающее «юго-восток» под углом 110 (эллипсповорачивается на 110 градусов).Синяя линия совпадает с наконечником стрелки.Желаемое поведение.

Из этих изображений выглядит, как художник (после поворота для рисования) сначала рисует круг и линию, а затем масштабирует две оси, чтобы сделать его эллипсом.Это то, что делает угол синей линии не таким, как угол стрелки.

1 Ответ

0 голосов
/ 01 апреля 2019

Проблема в том, что при использовании drawPie поведение такое же, как если бы вычислялись точки на окружности с заданными startAngle и startAngle+spawnAngle, а затем они масштабировались с помощью мажорного и минорного эллипса. ось. Решение (которое полностью реализовано в прилагаемом репозитории git ) заключается в следующем:

  double ang = 45;
  double ang_ellipse = atan2(sin(ang * M_PI / 180) * x_axis_radii, cos(ang * M_PI / 180) * y_axis_radii) * 180.0 / M_PI;
  painter.drawPie(QRectF(-x_axis_radii, -y_axis_radii, 2 * x_axis_radii, 2* y_axis_radii), ang_ellipse * 16, 0);

Это, по существу, пересчитывает угол с учетом x и y смещения эллипса, чтобы убедиться, что угол после смещения круга является желаемым.

...