PDA

View Full Version : Qt 4.3.0 clipping problem?



macbeth
12th June 2007, 19:21
Hello everyone!

I compiled Qt 4.3.0 when it was released and my application behaves quite weird...(it worked using Qt 4.2.3) I am not sure, but maybe I've found a bug in clipping, but I'd rather ask here first...

so, the code is rather simple:


int main(int argc, char *argv[]){
QApplication app(argc, argv);
int height = 500;
int width = 600;
QPixmap myPixmap(width, height);
QPainter myPainter(&myPixmap);
myPainter.translate(0,height);
//make the coordinate system look like this:
// -y ^
// |
// |
// |
// |
// ----------->
// 0,0 +x
QRectF myRect( 100.001, -100, width-200, -(height-200) ); //**here lies the problem, I guess
myPainter.setClipRect(myRect, Qt::ReplaceClip);
myPainter.fillRect(0, 0, width, -height, Qt::cyan);
myPainter.setClipRect(myRect, Qt::NoClip);
myPixmap.save("out.png", "PNG");
return 0;
}


using this code I get an image with a cyan rectangle in the middle, as expected.
However, if I change that one marked line to:

QRectF myRect( 100, -100, width-200, -(height-200) );
the image is entirely black...

Am I doing something wrong, or do you find it weird, too?

Thanks for answer...

wysota
13th June 2007, 01:59
I think this is not a bug in clipping. Or at least not a bug in clipping only. QRect suffers from a backward compatibility "feature" and you might be experiencing it right now. Quoting the docs:

QPoint QRect::bottomRight () const
Returns the position of the rectangle's bottom-right corner.
Note that for historical reasons this function returns QPoint(left() + width() -1, top() + height() - 1).

The thing you experience might be somehow related to that (don't ask me how, I have no idea), although it's a long shot (but it looks like an off-by-one issue).

What happens if you first fill the pixmap with transparency? Is the image still black? Or is it transparent?

macbeth
13th June 2007, 10:07
If I fill the pixmap with transparency using

myPixmap.fill(QColor(0,0,0,0));
after I create it, then the image is transparent, not black...

Ad QRect -- you're right, maybe the problem is there, but it gives me the same if I use myRect.bottom() and myRect.y() + myRect.height()...

I tried to look, what does the clipping region look like using boundingRegion:


QRectF myRect( 100, -100, width-200, -(height-200) );
cout << "myRect: left: " << myRect.left() << " right: " << myRect.x() + myRect.width() << " top: " << myRect.top() << " bottom: " << myRect.y() + myRect.height() << endl;
myPainter.setClipRect(myRect, Qt::ReplaceClip);
QRectF clipRect = myPainter.clipRegion().boundingRect();
cout << "clipRect: left: " << clipRect.left() << " right: " << clipRect.x() + clipRect.width() << " top: " << clipRect.top() << " bottom: " << clipRect.y() + clipRect.height() << endl;


The output is:


myRect: left: 100 right: 500 top: -100 bottom: -400
clipRect: left: 0 right: 0 top: 0 bottom: 0


:confused:

wysota
13th June 2007, 11:41
So the bottom line is that clipping is not set at all. You could try expressing the clip coordinates in device metrics not logical ones (i.e. [100, 100, width-200, height-200]).

magland
13th June 2007, 11:53
I would be interested to see the output if you tried the following in place of what you have already tried:



QRectF myRect,clipRect;
myRect=( 100, -100, width-200, -(height-200) );
cout << "myRect: left: " << myRect.left() << " right: " << myRect.x() + myRect.width() << " top: " << myRect.top() << " bottom: " << myRect.y() + myRect.height() << endl;
myPainter.setClipRect(myRect, Qt::ReplaceClip);
clipRect = myPainter.clipRegion().boundingRect();
cout << "clipRect: left: " << clipRect.left() << " right: " << clipRect.x() + clipRect.width() << " top: " << clipRect.top() << " bottom: " << clipRect.y() + clipRect.height() << endl;

myRect=( 100.001, -100, width-200, -(height-200) );
cout << "myRect: left: " << myRect.left() << " right: " << myRect.x() + myRect.width() << " top: " << myRect.top() << " bottom: " << myRect.y() + myRect.height() << endl;
myPainter.setClipRect(myRect, Qt::ReplaceClip);
clipRect = myPainter.clipRegion().boundingRect();
cout << "clipRect: left: " << clipRect.left() << " right: " << clipRect.x() + clipRect.width() << " top: " << clipRect.top() << " bottom: " << clipRect.y() + clipRect.height() << endl;

myRect=( 99, -100, width-200, -(height-200) );
cout << "myRect: left: " << myRect.left() << " right: " << myRect.x() + myRect.width() << " top: " << myRect.top() << " bottom: " << myRect.y() + myRect.height() << endl;
myPainter.setClipRect(myRect, Qt::ReplaceClip);
clipRect = myPainter.clipRegion().boundingRect();
cout << "clipRect: left: " << clipRect.left() << " right: " << clipRect.x() + clipRect.width() << " top: " << clipRect.top() << " bottom: " << clipRect.y() + clipRect.height() << endl;

myRect=( 100, -100-(height-200), width-200, +(height-200) );
cout << "myRect: left: " << myRect.left() << " right: " << myRect.x() + myRect.width() << " top: " << myRect.top() << " bottom: " << myRect.y() + myRect.height() << endl;
myPainter.setClipRect(myRect, Qt::ReplaceClip);
clipRect = myPainter.clipRegion().boundingRect();
cout << "clipRect: left: " << clipRect.left() << " right: " << clipRect.x() + clipRect.width() << " top: " << clipRect.top() << " bottom: " << clipRect.y() + clipRect.height() << endl;

myRect=( 100.001, -100-(height-200), width-200, +(height-200) );
cout << "myRect: left: " << myRect.left() << " right: " << myRect.x() + myRect.width() << " top: " << myRect.top() << " bottom: " << myRect.y() + myRect.height() << endl;
myPainter.setClipRect(myRect, Qt::ReplaceClip);
clipRect = myPainter.clipRegion().boundingRect();
cout << "clipRect: left: " << clipRect.left() << " right: " << clipRect.x() + clipRect.width() << " top: " << clipRect.top() << " bottom: " << clipRect.y() + clipRect.height() << endl;


myRect=( 99, -100-(height-200), width-200, +(height-200) );
cout << "myRect: left: " << myRect.left() << " right: " << myRect.x() + myRect.width() << " top: " << myRect.top() << " bottom: " << myRect.y() + myRect.height() << endl;
myPainter.setClipRect(myRect, Qt::ReplaceClip);
clipRect = myPainter.clipRegion().boundingRect();
cout << "clipRect: left: " << clipRect.left() << " right: " << clipRect.x() + clipRect.width() << " top: " << clipRect.top() << " bottom: " << clipRect.y() + clipRect.height() << endl;



... perhaps it has something to do with the negative height???

macbeth
13th June 2007, 13:23
[edited!]
Thanks, guys, it seems that QPainter clips rectangles some other way that it clips paths... According to magland's suggestion, I've found out that rectangle must have positive height (and probably width, too)... so it won't be clipped as (I) expected, if you start rectangle at -100 and set height to -300, you must start rectangle at -400 at set height to 300...

Have a look at this example (rather confusing difference, I think...):


QRectF myRect( 100, -100, width-200, -(height-200) );
cout << "myRect: left: " << myRect.left() << " right: " << myRect.x() + myRect.width() << " top: " << myRect.top() << " bottom: " << myRect.y() + myRect.height() << endl;
myPainter.setClipRect(myRect, Qt::ReplaceClip);
QRectF clipRect = myPainter.clipRegion().boundingRect();
cout << "clipRect: left: " << clipRect.left() << " right: " << clipRect.x() + clipRect.width() << " top: " << clipRect.top() << " bottom: " << clipRect.y() + clipRect.height() << endl;

QPainterPath myPath;
myPath.addRect(myRect);
myPainter.setClipPath( myPath, Qt::ReplaceClip );
clipRect = myPainter.clipRegion().boundingRect();
cout << "clipPath: left: " << clipRect.left() << " right: " << clipRect.x() + clipRect.width() << " top: " << clipRect.top() << " bottom: " << clipRect.y() + clipRect.height() << endl;


output:

myRect: left: 100 right: 500 top: -100 bottom: -400
clipRect: left: 0 right: 0 top: 0 bottom: 0
clipPath: left: 100 right: 500 top: -400 bottom: -100



@magland:

myRect: left: 100 right: 500 top: -100 bottom: -400
clipRect: left: 0 right: 0 top: 0 bottom: 0

myRect: left: 100.001 right: 500.001 top: -100 bottom: -400
clipRect: left: 100 right: 500 top: -400 bottom: -100 //this is ok, because it is treated as a path, not as a rect (setClipRect calls setClipPath, if the coords are not integers)

myRect: left: 99 right: 499 top: -100 bottom: -400
clipRect: left: 0 right: 0 top: 0 bottom: 0

myRect: left: 100 right: 500 top: -400 bottom: -100
clipRect: left: 100 right: 500 top: -400 bottom: -100 //this is ok, because clipping rect has coords: x: 100; y: -400; width: 400; *height: 300*

myRect: left: 100.001 right: 500.001 top: -400 bottom: -100
clipRect: left: 100 right: 500 top: -400 bottom: -100

myRect: left: 99 right: 499 top: -400 bottom: -100
clipRect: left: 99 right: 499 top: -400 bottom: -100


So it seems like a bit of inconsistency there I guess... for example there is no problem with using negative proportions in fillRect(), etc.

wysota
13th June 2007, 18:56
You can call QRectF::normalized() to get the proper rect. It might be worth suggesting Trolls to include that call in setClipRect() if it's not there.