[Qgis-developer] QgsRubberBand 1px shift

Martin Dobias wonder.sk at gmail.com
Mon May 2 09:04:32 EDT 2011


Hi Radim

On Mon, May 2, 2011 at 1:13 PM, Radim Blazek <radim.blazek at gmail.com> wrote:
> Hi,
> I am observing QgsRubberBand 1px shift with GRASS region. You can
> verify comparing a layer with full region extent (e.g. r.mapcalc
> test=1 or v.in.region output=test) with current region. After a long
> QGIS code inspection I have discovered quite strange piece of code in
> QT:
>
> qpaintengine_x11.cpp:
>
> // use the same rounding as in qrasterizer.cpp (6 bit fixed point)
> static const qreal aliasedCoordinateDelta = 0.5 - 0.015625;

As far as I understand this, Qt treats pixels to be squares (x,y) to
(x+1,y+1), where x and y are integers. Therefore a horizontal line
(0,1) - (10,1) is located exactly between the row 0 and row 1. Indeed
when rendering with antialiasing turned on, and 1pixel pen width the
line spans two rows, each with 50% opacity. When rendering without
antialiasing, Qt probably wants to avoid rounding errors and shifts
everything by 0.5px, therefore the same line (0,1) - (10,1) fits
exactly the pixels on row 1.

The magic constant 0.15625 is actually 1/64 and it is apparently there
to produce equivalent results to the native Qt rasterizer which works
in fixed precision of 1/64 px.

Btw. this simple script illustrates the behavior:

from PyQt4.QtCore import *
from PyQt4.QtGui import *
import sys
a = QApplication(sys.argv)
pix = QPixmap(64, 64)
pix.fill()
p = QPainter(pix)
p.drawLine(QPointF(0,0), QPointF(10,0)) # no antialiasing
p.setRenderHint(QPainter.Antialiasing)
p.drawLine(QPointF(0,2), QPointF(10,2))
p.end()

pix.save("antitest.png")

> using QPainter::Antialiasing hint in fact solves the problem:
>
> --- src/gui/qgsmapcanvasitem.cpp        (revision 15861)
> +++ src/gui/qgsmapcanvasitem.cpp        (working copy)
> @@ -42,6 +42,7 @@
>                               const QStyleOptionGraphicsItem * option,
>                               QWidget * widget )
>  {
> +  painter->setRenderHint(QPainter::Antialiasing);
>   paint( painter ); // call the derived item's drawing routines
>  }
>
> May I apply the patch? I hope that just setting the hint should not
> harm but I don't want to break anything in QGIS core few days before
> release.

Shouldn't we actually use the antialiasing flag from map canvas
instead of hardcoding antialiasing on? Like that the offset in
rendered map and canvas items should be equal.

Cau
Martin


More information about the Qgis-developer mailing list