Use window/viewport to flip QPainter y-axis

10,776

Solution 1

Use class QMatrix. It specifies 2D transformations. QMatrix is set to QPainter.

But remember, in your case, if you convert your widget's coords to Cartesian coords, you will have to put first point at (-10,-10) (not at (-10,10) as you did mentioned) to draw a rect, which has center at (0,0), because Y-axis now grows up and X-Axis now grows right.

All you need is to transform your coord system this way:

  • translate origin from (0,0) to the middle of the widget:
    alt text

  • scale Y-axis by -1 factor:
    alt text

Here is the code, typed in paintEvent() function of a widget:

QPainter pn( this );

int w_2 = width() / 2;
int h_2 = height() / 2;

{ // X- and Y-Axis drawing
    pn.setPen( Qt::blue );
    pn.drawLine( 0, h_2, width(), h_2);     // X-Axis
    pn.drawLine( w_2, 0 , w_2, height() );  // Y-Axis
}

QMatrix m;
m.translate( w_2, h_2 );
m.scale( 1, -1 );

pn.setMatrix( m );
pn.setPen( Qt::NoPen );
pn.setBrush( QBrush( Qt::blue, Qt::Dense4Pattern ) );
pn.drawRect( -10, -10, 20, 20 );

result:
alt text

update apr 07, 2014

This question was asked a long time ago and many things have changed since. For those asking themselves the same question today (beginnings of 2014) then my personal answer is that since Qt 4.3 it is possible to solve problem with text flipping more easier.

You are right. Text also gets filpped because it is drawn with the same painter. You can draw text at the end, when all flipped drawings are done, if it is possible. This method is not convinient because of new calculations of texts position. Also you will need to drop settings for painter. Now I would recommend you to use QGraphicsView, because of huge support of 2D painting. Also for each QGraphicsItem ItemIgnoresTransformations flag can be set, which allows it to ignore inherited transformations (i.e., its position is still anchored to its parent, but the parent or view rotation, zoom or shear transformations are ignored). This flag is useful for keeping text label items horizontal and unscaled, so they will still be readable if the graphics view is transformed

Solution 2

The above answer will also flip text, "p" will be "b". To avoid that you have to flip back the y-axis before text is drawn, and you have to change sign on y-coord for the text position when you draw it. This is a little bit ugly I think, or is there a better way?

Solution 3

As stated above, drawing text also appears flipped upside down. There is an easy solution to it, see below. We will temporary disable the world transform for the text drawing. Note that text is not scaled anymore.

in your painting code we want to draw text on coordinate QPointF P;

Painter pn( this );

// calculate the point with the transform
QPointF p = pm.transform().map(P);

// Disable Transform temporary
pn.setWorldMatrixEnabled(false);

// draw it ordinary, no scaling etc
pn.drawText(p, QString("HI FRIENDS!"));

// Enable the transform again
pn.setWorldMatrixEnabled(true);

Solution 4

I needed to flip the y-axis in order to paint lines and polygons using Qt from points defined in Java coordinates. I imagine others will need to do this in porting from Java to Qt coordinate systems. The discussion above was helpful. My solution was:

painter.translate(0,height());
painter.scale(1.0, -1.0);

and then proceed to draw the lines and polygons.

Share:
10,776

Related videos on Youtube

sidewinderguy
Author by

sidewinderguy

I'm a software engineer by trade and by hobby. I've been addicted to computers since I was 8 and so far theres no sign of that changing. My biggest interests right now are graphics/opengl, AI, game dev, embedded programming for ARM, OS development, and user interfaces. My educational background is in Physics, Math, and Computer Systems Engineering. I mostly use C++ and Python, but I've been known to dabble in JavaScript, Lua, old-school C, and others. Someday I'd like to sit down and make my own programming language just for the learning experience, but I doubt I'll ever have time - also, I usually just lie down until the feeling goes away.

Updated on May 12, 2022

Comments

  • sidewinderguy
    sidewinderguy almost 2 years

    I'm using Qt 4.7 QPainter to draw some polygons, etc into a widget. I am hoping to alter the coordinate system so that (0,0) is at the center of my widget, and the x/y axis behave in a standard "Cartesian" way (ie. y increases going "up" and decreases going "down"). In other words, I want the coordinates to be "math"-like not "computer graphics"-like, if you know what I mean. :-)

    I'm trying to do this using setViewport() and setWindow() rather than do the math myself, as it would be nice to be able to just call the draw methods directly with my coordinates.

    Here's what I've got so far:

    // Setup coordinates
    double screenWidth = width();
    double screenHeight = height();
    
    double windowWidth = 100.0;
    double windowHeight = (screenHeight / screenWidth) * windowWidth;
    
    painter.setViewport(0, 0, screenWidth, screenHeight);
    painter.setWindow(-(windowWidth / 2.0), -(windowHeight / 2.0), windowWidth, windowHeight);
    
    // Draw stuff
    painter.setPen(Qt::NoPen);
    painter.setBrush(Qt::blue);
    painter.drawRect(-10, -10, 20, 20);
    

    Now this works just fine, in that it draws a nice blue square in the middle of the screen. The problem is, I have to say that the upper left corner is (-10, -10). I'd like to be able to make it (-10, 10), as that is what it would be in Cartesian coords.

    I tried messing with setWindow/setViewport to get this "y-axis flip", but to no avail. This seems like a really easy/basic thing to do, but after scouring the Qt docs and the web, I can't figure it out!

    Thanks,
    Chris

  • bkausbk
    bkausbk about 10 years
    Correct, however it need to be mentioned, that texts also gets flipped. That is mostly not desired!