I want to rotate a pixmap from its xAxis, but it just rotates from top left corner.(I want it to be rotated from the center) here is my code:
QTransform *X = new QTransform();
X->translate(pixmap().size().width() / 2, pixmap().size().height() / 2);
X->rotate(rtn, Qt::XAxis); //rtn is an angle
setTransform(*X);
It seems that the translate method does not change the origin point to the center of my pixmap.
Now I want some help to solve this problem.
ok, the problem was that I didn't translate back my transformation after rotate method, this is the appropriate rotation from center on xAxis:
setTransform(QTransform().translate(pixmap().size().width() / 2, pixmap().size().height() / 2).rotate(rtn, Qt::XAxis).translate(-pixmap().size().width() / 2, -pixmap().size().height() / 2));
Related
In my Flutter app, I have drawn a rectangle in one coordinate system on a Google Map and I want to rotate this coordinate system around the coordinate (0,0). How this can be done is described here: Rotation matrix. I have implemented the rotation of coordinates like this in my app:
class Coordinate {
Coordinate(this.x, this.y);
double x;
double y;
void rotate(double angle) {
// angle is in degrees, convert to radians
final double angleInRadians = angle * (math.pi / 180);
final double oldX = x;
final double oldY = y;
final double newX = oldX * math.cos(angleInRadians) - oldY * math.sin(angleInRadians);
final double newY = oldX * math.sin(angleInRadians) + oldY * math.cos(angleInRadians);
x = newX;
y = newY;
}
}
Using this to rotate four corners of a rectangle works fine for some places in the world, like Australia and a place near (0,0). In this picture, you can see the rotation of the red rectangle on the top around the point (0,0) (bottom left) to the rotated red rectangle on the bottom right:
Please ignore all the markers and non-red lines. The next to images show a rectangle like the one in the picture above which I again rotate around (0,0) using the code above, but as you can see in the second image, the red rectangle is not a rectangle anymore, but a parallelogram instead.
I cannot find an explanation for this. The questions I ask myself are: Why does the code work for some places but not for others? Why does the rectangle transform to a perfect parallelogram instead of whatever other shape with the points possibly all around the world? As it is working for some locations, the problem cannot be that I have mixed up some of the coordinates or something like that, it has to do something with the calculation of the edges of the rotated rectangle. But I cannot find out what I did wrong here.
REMINDER: IGNORE ALL MARKERS AND NON-RED LINES
I'm writing a gauge widget, using QT, that is constructed from 2 separate images, one as background and the other as Needle. I reimplement paintEvent function as follow:
void myGaugeWidget::paintEvent(QPaintEvent *pe)
{
QPainter painter(this);
QPixmap bkgImage(bkgImgPath);
painter.drawPixmap(0, 0, width(), height(), bkgImage);
const double thetaDeg = 30.0;
QPixmap needle(needles[i].imgPath);
int needleWidth = 200;
int needleHeight = 200;
int anchorX = 20;
int anchorY = 30;
const int centerX = width()/2;
const int centerY = height()/2;
QTransform rm = QTransform().translate(-anchorX,- anchorY).rotate(thetaDeg).translate(centerX,centerY);
needle = needle.transformed(rm);
painter.drawPixmap(0,0, needle);
}
this code rotates my needle correctly but its position is not correct.
can anybody help me?
thanks.
This most likely would depend on your images and widget size. I have tried your code and it seems to me that QTransform().translate() is not doing anything in a QPixmap. I tried to give extreme values for translate() and removed rotate() - the image does not move.
I already have have my own implementation for a gauge. This is with painter transformation instead of the image. My images are of dimensions:
Gauge Background: 252x252 (there is some external blurring effects around the circle boundaries, making the background image larger than it seems)
Needle: 7x72 ( the image dimensions wrap around the boundaries of the needle itself)
Needle roation center (with respect to the background): 126, 126 (divide background size by 2)
The needle image points upward
For this setup, here is my paintEvent() with some explanations:
void myGaugeWidget::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
//draw the background which is same size as the widget.
painter.drawPixmap(0, 0, bg.width(), bg.height(), bg);
//Calculate the angle of rotation.
//The gauge I am using has a cutout angle of 120 degrees at the bottom (symmetric)
float needleAngle = -120/*offset for start rotation*/ + ((value-minValue)*240/*total sweep of the gauge*//(maxValue-minValue));
painter.save();
//translate the painter to the roation center and then perform the rotation
painter.translate(126, 126);
painter.rotate(needleAngle);
//translate the rotated canvas to adjust for the height of the needle.
//If you don't do this, your needle's tip will be at the rotation center
painter.translate(0, -72);
//draw the needle and adjust for the width with the x value
painter.drawPixmap(-needle.width()/2, 0, needle.width(), needle.height(), needle);
painter.restore();
}
Here is what I want to do.
I need to draw in a QGraphicsView a series of rectangles that are aligned left and right. By this I mean that if rectangle i has posion (0,y) rectangle i+1 needs to have position (0,max) where max is such that the right side of the rectangle "touches" the right side of the QGraphicsView.
When the window is resized I need to recalculate the value of max such that the rectangle is always touching the right side of the screen.
Here is how I add my scene (this references a class that inherits QGraphicsView)
scene = new QGraphicsScene(this);
this->setScene(scene);
this->setAlignment(Qt::AlignTop|Qt::AlignLeft);
To add a rectangle that touches the left border I add it a (0,yvalue,width,height).
How do I calculate the value of X so that that the rectangle will touch the right border?
Ok. So this should go in the resize event of the QGraphicsView. But this does what I wanted:
void AView::resized(){
scene->clear();
QSize newsize = this->size();
qreal w = newsize.width()*.99;
qreal h = newsize.height()*.99;
this->setSceneRect(0,0,w,h);
scene->setSceneRect(0,0,w,h);
qreal rectwidth = 100;
qreal newx = w - rectwidth;
left = new QGraphicsRectItem(0,0,rectwidth,100);
left->setBrush(QBrush(Qt::red));
right = new QGraphicsRectItem(newx,100,rectwidth,100);
right->setBrush(QColor(Qt::blue));
scene->addItem(left);
scene->addItem(right);
}
In this way the blue rectangle is pretty much always at the border. Aslo there is no stretching of the image. There is a gap between the right borders which increases due to the window resizing, but it seems that the size returned by this->size() is slightly larger than the "white area" that you see on screen. Adding the .99 gives a much better results from my experiments.
This little example should calculate the shift and move all items from a selection or list of items, based on alignment you desire (I showed right, but let, center, top, bottom would be the same).
QRectF refRect = scene()->sceneRect();
QList<QGraphicsItem*> sel = allItemsYouWantAligned; // scene()->selectedItems(); for example
foreach(QGraphicsItem* selItem, sel)
{
qreal dx = 0, dy = 0;
QRectF itemRect = selItem->mapToScene(selItem->boundingRect()).boundingRect();
if(align_right)
dx = refRect.right() - itemRect.right();
else
.. calculate either dx or dy on how you want to align
selItem->moveBy(dx, dy);
}
Re-reading the question - I see you don't really need to move rectangle, but create new larger and larger rectangles.
Your solution is simple enough. If you want to resize instead of move -
you would have to setRect() on your items by dx increment:
QRectF r = selItem->rect();
r.setWidth(r.width + dx);
selItem->setRect(r);
i want to rotate 3D an Image called img1 in Flex. I want to rotate it around y axis 180 degree. I can do this by using 3D effect already built in Flex but i want to do a bit more different.
I want during rotating, there's another image called img2 appear on back of img1 (in default case, the image appear on the back is img1) and when rotating finish, the image will be img2.
How can i do this ?
Thank you.
If you need no perspective effect, it's quite easy to do. A rough implementation (not tested!):
// Event.ENTER_FRAME event listener
void on_enter_frame(event:Event):void
{
// m_angle is a member of the class/flex component where on_enter_frame is declared
// ANGLE_DELTA is just a constant
m_angle += ANGLE_DELTA;
// Angle clamping to the range [0, PI * 2)
m_angle %= Math.PI * 2;
if (m_angle < 0)
m_angle += Math.PI * 2;
// If we currently look at the front side...
if (m_angle < Math.PI)
{
img1.visible = true;
img2.visible = false;
img1.scaleX = Math.cos(m_angle);
}
else
{
img1.visible = false;
img2.visible = true;
// If you omit negation, the back-side image will be mirrored
img2.scaleX = -Math.cos(m_angle);
}
}
So every frame we increase the rotation angle, clamp it to the range [0, PI * 2). Then depending on the value of the rotation angle, we hide/show the pair of your images, and then perform x-scaling of the visible image.
Thank you, now i found a solution. Please check it here, it's very easy to do.
http://forums.adobe.com/thread/921258
My application is using Qt.
I have a class which is inheriting QGraphicsPixmapItem.
When applying transformations on these items (for instance, rotations), the origin of the item (or the pivot point) is always the top left corner.
I'd like to change this origin, so that, for instance, when setting the position of the item, this would put actually change the center of the pixmap.
Or, if I'm applying a rotation, the rotation's origin would be the center of the pixmap.
I haven't found a way to do it straight out of the box with Qt, so I thougth of reimplementing itemChange() like this :
QVariant JGraphicsPixmapItem::itemChange(GraphicsItemChange Change, const QVariant& rValue)
{
switch (Change)
{
case QGraphicsItem::ItemPositionHasChanged:
// Emulate a pivot point in the center of the image
this->translate(this->boundingRect().width() / 2,
this->boundingRect().height() / 2);
break;
case QGraphicsItem::ItemTransformHasChanged:
break;
}
return QGraphicsItem::itemChange(Change, rValue);
}
I thought this would work, as Qt's doc mentions that the position of an item and its transform matrix are two different concepts.
But it is not working.
Any idea ?
You're overthinking it. QGraphicsPixmapItem already has this functionality built in. See the setOffset method.
So to set the item origin at its centre, just do setOffset( -0.5 * QPointF( width(), height() ) ); every time you set the pixmap.
The Qt-documentation about rotating:
void QGraphicsItem::rotate ( qreal angle )
Rotates the current item
transformation angle degrees clockwise
around its origin. To translate around
an arbitrary point (x, y), you need to
combine translation and rotation with
setTransform().
Example:
// Rotate an item 45 degrees around (0, 0).
item->rotate(45);
// Rotate an item 45 degrees around (x, y).
item->setTransform(QTransform().translate(x, y).rotate(45).translate(-x, -y));
You need to create a rotate function, that translate the object to the parent's (0, 0) corner do the rotation and move the object to the original location.