I am using QGraphicsView
together with a custom implementation of a QAbstractGraphicsItem
to draw an arrow and an ellipse both can rotate around the central point of the graphics item (for this reason the example does not have the translation part). The desired behavior that I want is to be able to draw a blue line that goes from the center of the ellipse to its edge at the angle of the arrow (the real application will show a circular section instead of a line). Moreover, for easier understanding of what is going on in the drawing the two main axes of the ellipse are drawn in red and green. Here is my item:
Header
#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;
};
Implementation
#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);
}
My problem is that, as I turn around my arrow, the line that I draw on the ellipse only coincide when the arrow is aligned with the ellipse's axis (either x
or y) as you can see in the attached images. Any ideas on what am I doing wrong?
This repo contains the minimal complete verifiable example.
The following images show a gui whit 5 parameters:
- Arrow angle (deg): is the rotation of the arrow from the x axis in degrees with positive direction clockwise
- Ellipse x: dimension of the x radii of the ellipse
- Ellipse y: dimension of the y radii of the ellipse
- Ellipse rot: rotation of the ellipse from the x axis in degrees with positive direction clockwise
- Scale: is the scale of the drawn arrow.
The above image shows the arrow pointing to the right at an angle 0 and the y-direction (green line) of the ellipse pointing up at an angle 90 indicating that the ellipse has a rotation 0. The blue line and the arrow tip are coincident. Desired behaviour.
The above image shows the arrow pointing "southeast" at an angle of 45 degrees and the x-direction (red line) of the ellipse pointing right at an angle 0 (the ellipse is not rotated). The blue line is not coincident with the arrow tip although it was drawn at the same angle as the one used to draw the arrow. Not the desired behavior.
The above image shows the arrow pointing "south-southeast" at an angle of 80 degrees and the x-direction (red line) of the ellipse pointing right at an angle 0 (the ellipse is not rotated). The blue line is not coincident with the arrow tip although it was drawn at the same angle as the one used to draw the arrow. Not the desired behavior.
The above image shows the arrow pointing "south" at an angle of 90 degrees and the x-direction (red line) of the ellipse pointing right at an angle 0 (the ellipse is not rotated). The blue line is coincident with the arrow tip. Desired behavior.
The above image shows the arrow pointing "east-southeast" at an angle of 20 degrees and the x-direction (red line) of the ellipse pointing right at an angle 0 (the ellipse is not rotated). The blue line is not coincident with the arrow tip although it was drawn at the same angle as the one used to draw the arrow. Not the desired behavior.
The above image shows the arrow pointing "east-southeast" at an angle of 20 degrees and the x-direction (red line) of the ellipse pointing "east-southeast" at an angle 20 (the ellipse is rotated 20 degrees). The blue line is coincident with the arrow tip. Desired behavior.
The above image shows the arrow pointing "east-southeast" at an angle of 20 degrees and the x-direction (red line) of the ellipse pointing "southeast" at an angle 60 (the ellipse is rotated 60 degrees). The blue line is not coincident with the arrow tip. Not the desired behavior.
The above image shows the arrow pointing "east-southeast" at an angle of 20 degrees and the x-direction (red line) of the ellipse pointing "southeast" at an angle 95 (the ellipse is rotated 95 degrees). The blue line is not coincident with the arrow tip. Not the desired behavior.
The above image shows the arrow pointing "east-southeast" at an angle of 20 degrees and the x-direction (red line) of the ellipse pointing "southeast" at an angle 110 (the ellipse is rotated 110 degrees). The blue line is coincident with the arrow tip. Desired behavior.
From these images, it looks like the painter (after rotating for drawing) first draws the circle and the line and then scales the two axes to make it an ellipse. This is what makes the angle of the blue line not be the same as the one of the arrow.