summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFriedrich W. H. Kossebau <kossebau@kde.org>2016-07-24 21:53:22 (GMT)
committerFriedrich W. H. Kossebau <kossebau@kde.org>2016-07-25 13:55:56 (GMT)
commitc18308456d909ef576b53ab69da890ab8b32ab5e (patch)
tree51aac299b59e3f957389af22e589c9211082792a
parente9dc1098c4513ed0e043f2e428827df1fa9104c1 (diff)
GeoPainter: consistent qreal-based API, separate regionFromPixmapRect()
Summary: GeoPainter API had a mixture of int and qreal-based methods, and internally was inconsistently relaying to int or qreal-based QPainter methods. Regions used for painting rects and ellipses depend on whether anti-aliasing is enabled or not, and can result in offsets of at least 1 pixel. So calculations now tries to respect that. GeoPainter::regionFromRect() was used for getting the region of pixmaps being rendered. Especially in non-anti-aliased mode though this does not match, also is there no stroke-width on painting pixmaps. A special GeoPainter::regionFromPixmapRect() should serve that purpose now. Reviewers: nienhueser, shentey, rahn, #marble Reviewed By: rahn, #marble Differential Revision: https://phabricator.kde.org/D2279
-rw-r--r--src/bindings/python/sip/GeoPainter.sip2
-rw-r--r--src/lib/marble/GeoPainter.cpp110
-rw-r--r--src/lib/marble/GeoPainter.h22
-rw-r--r--src/lib/marble/routing/RoutingLayer.cpp4
4 files changed, 97 insertions, 41 deletions
diff --git a/src/bindings/python/sip/GeoPainter.sip b/src/bindings/python/sip/GeoPainter.sip
index 660ac4e..d1b22e6 100644
--- a/src/bindings/python/sip/GeoPainter.sip
+++ b/src/bindings/python/sip/GeoPainter.sip
@@ -46,7 +46,7 @@ public:
QRegion regionFromPolygon (const Marble::GeoDataLinearRing& linearRing, Qt::FillRule fillRule, qreal strokeWidth = 3) const;
QRegion regionFromRect (const Marble::GeoDataCoordinates& centerPosition, qreal width, qreal height, bool isGeoProjected = 0, qreal strokeWidth = 3) const;
GeoPainter (QPaintDevice* paintDevice, const Marble::ViewportParams* viewportParams, Marble::MapQuality mapQuality = NormalQuality);
- void drawRoundedRect(const Marble::GeoDataCoordinates& centerPosition, int width, int height, int xRnd = 25, int yRnd = 25);
+ void drawRoundedRect(const Marble::GeoDataCoordinates& centerPosition, qreal width, qreal height, qreal xRnd = 25, qreal yRnd = 25);
};
// GeoPainter
diff --git a/src/lib/marble/GeoPainter.cpp b/src/lib/marble/GeoPainter.cpp
index 6d7ae26..d1b1087 100644
--- a/src/lib/marble/GeoPainter.cpp
+++ b/src/lib/marble/GeoPainter.cpp
@@ -259,7 +259,7 @@ void GeoPainter::drawPoint ( const GeoDataCoordinates & position )
if ( visible ) {
// Draw all the x-repeat-instances of the point on the screen
for( int it = 0; it < pointRepeatNum; ++it ) {
- QPainter::drawPoint( d->m_x[it], y );
+ QPainter::drawPoint(QPointF(d->m_x[it], y));
}
}
}
@@ -287,8 +287,8 @@ QRegion GeoPainter::regionFromPoint ( const GeoDataPoint & point,
void GeoPainter::drawText ( const GeoDataCoordinates & position,
const QString & text,
- int xOffset, int yOffset,
- int width, int height,
+ qreal xOffset, qreal yOffset,
+ qreal width, qreal height,
const QTextOption & option )
{
// Of course in theory we could have the "isGeoProjected" parameter used
@@ -306,12 +306,14 @@ void GeoPainter::drawText ( const GeoDataCoordinates & position,
if ( visible ) {
// Draw all the x-repeat-instances of the point on the screen
+ const qreal posY = y - yOffset;
for( int it = 0; it < pointRepeatNum; ++it ) {
- if (width == 0 && height == 0) {
- QPainter::drawText( d->m_x[it] + xOffset, y + yOffset, text );
+ const qreal posX = d->m_x[it] + xOffset;
+ if (width == 0.0 && height == 0.0) {
+ QPainter::drawText(QPointF(posX, posY), text);
}
else {
- QRectF boundingRect(d->m_x[it] + xOffset, y + yOffset, width, height);
+ const QRectF boundingRect(posX, posY, width, height);
QPainter::drawText( boundingRect, text, option );
}
}
@@ -332,17 +334,10 @@ void GeoPainter::drawEllipse ( const GeoDataCoordinates & centerPosition,
if ( visible ) {
// Draw all the x-repeat-instances of the point on the screen
+ const qreal rx = width / 2.0;
+ const qreal ry = height / 2.0;
for( int it = 0; it < pointRepeatNum; ++it ) {
- // Have to compensate truncate rounding of conversion from real to int
- // for all of rx, ry, rw, rh (given int-based method called).
- // (and the 0.5 base-offset for the middle of center pixel). E.g. should
- // x=5, w=3 -> rx = 4, rw = 3
- // x=5, w=3.5 -> rx = 4, rw = 3
- // x=5, w=4 -> rx = 3, rw = 4
- // x=5, w=5 -> rx = 3, rw = 5
- QPainter::drawEllipse(d->m_x[it] - static_cast<int>(width / 2.0),
- y - static_cast<int>(height / 2.0),
- width, height);
+ QPainter::drawEllipse(QPointF(d->m_x[it], y), rx, ry);
}
}
}
@@ -409,13 +404,19 @@ QRegion GeoPainter::regionFromEllipse ( const GeoDataCoordinates & centerPositio
QRegion regions;
if ( visible ) {
+ // only a hint, a backend could still ignore it, but we cannot know more
+ const bool antialiased = testRenderHint(QPainter::Antialiasing);
+
+ const qreal halfStrokeWidth = strokeWidth/2.0;
+ const int startY = antialiased ? (qFloor(y - halfStrokeWidth)) : (qFloor(y+0.5 - halfStrokeWidth));
+ const int endY = antialiased ? (qCeil(y + height + halfStrokeWidth)) : (qFloor(y+0.5 + height + halfStrokeWidth));
// Draw all the x-repeat-instances of the point on the screen
for( int it = 0; it < pointRepeatNum; ++it ) {
- regions += QRegion(d->m_x[it] - static_cast<int>((width + strokeWidth) / 2.0),
- y - static_cast<int>((height + strokeWidth) / 2.0),
- width + strokeWidth,
- height + strokeWidth,
- QRegion::Ellipse );
+ const qreal x = d->m_x[it];
+ const int startX = antialiased ? (qFloor(x - halfStrokeWidth)) : (qFloor(x+0.5 - halfStrokeWidth));
+ const int endX = antialiased ? (qCeil(x + width + halfStrokeWidth)) : (qFloor(x+0.5 + width + halfStrokeWidth));
+
+ regions += QRegion(startX, startY, endX - startX, endY - startY, QRegion::Ellipse);
}
}
return regions;
@@ -482,8 +483,10 @@ void GeoPainter::drawImage ( const GeoDataCoordinates & centerPosition,
if ( visible ) {
// Draw all the x-repeat-instances of the point on the screen
+ const qreal posY = y - (image.height() / 2.0);
for( int it = 0; it < pointRepeatNum; ++it ) {
- QPainter::drawImage( d->m_x[it] - ( image.width() / 2 ), y - ( image.height() / 2 ), image );
+ const qreal posX = d->m_x[it] - (image.width() / 2.0);
+ QPainter::drawImage(QPointF(posX, posY), image);
}
}
// }
@@ -503,15 +506,46 @@ void GeoPainter::drawPixmap ( const GeoDataCoordinates & centerPosition,
if ( visible ) {
// Draw all the x-repeat-instances of the point on the screen
+ const qreal posY = y - (pixmap.height() / 2.0);
for( int it = 0; it < pointRepeatNum; ++it ) {
- QPainter::drawPixmap( d->m_x[it] - ( pixmap.width() / 2 ),
- y - ( pixmap.height() / 2 ), pixmap );
+ const qreal posX = d->m_x[it] - (pixmap.width() / 2.0);
+ QPainter::drawPixmap(QPointF(posX, posY), pixmap);
}
}
// }
}
+QRegion GeoPainter::regionFromPixmapRect(const GeoDataCoordinates & centerCoordinates,
+ int width, int height,
+ int margin) const
+{
+ const int fullWidth = width + 2 * margin;
+ const int fullHeight = height + 2 * margin;
+ int pointRepeatNum;
+ qreal y;
+ bool globeHidesPoint;
+
+ const bool visible = d->m_viewport->screenCoordinates(centerCoordinates,
+ d->m_x, y, pointRepeatNum,
+ QSizeF(fullWidth, fullHeight), globeHidesPoint);
+
+ QRegion regions;
+
+ if (visible) {
+ // cmp. GeoPainter::drawPixmap() position calculation
+ // QPainter::drawPixmap seems to qRound the passed position
+ const int posY = qRound(y - (height / 2.0)) - margin;
+ for (int it = 0; it < pointRepeatNum; ++it) {
+ const int posX = qRound(d->m_x[it] - (width / 2.0)) - margin;
+ regions += QRegion(posX, posY, width, height);
+ }
+ }
+
+ return regions;
+}
+
+
void GeoPainter::drawPolyline ( const GeoDataLineString & lineString,
const QString& labelText,
LabelPositionFlags labelPositionFlags,
@@ -854,10 +888,10 @@ void GeoPainter::drawRect ( const GeoDataCoordinates & centerCoordinates,
if ( visible ) {
// Draw all the x-repeat-instances of the point on the screen
+ const qreal posY = y - height / 2.0;
for( int it = 0; it < pointRepeatNum; ++it ) {
- QPainter::drawRect(d->m_x[it] - static_cast<int>(width / 2.0),
- y - static_cast<int>(height / 2.0),
- width, height );
+ const qreal posX = d->m_x[it] - width / 2.0;
+ QPainter::drawRect(QRectF(posX, posY, width, height));
}
}
}
@@ -884,12 +918,18 @@ QRegion GeoPainter::regionFromRect ( const GeoDataCoordinates & centerCoordinate
QRegion regions;
if ( visible ) {
+ // only a hint, a backend could still ignore it, but we cannot know more
+ const bool antialiased = testRenderHint(QPainter::Antialiasing);
+
+ const qreal halfStrokeWidth = strokeWidth/2.0;
+ const int startY = antialiased ? (qFloor(y - halfStrokeWidth)) : (qFloor(y+0.5 - halfStrokeWidth));
+ const int endY = antialiased ? (qCeil(y + height + halfStrokeWidth)) : (qFloor(y+0.5 + height + halfStrokeWidth));
// Draw all the x-repeat-instances of the point on the screen
for( int it = 0; it < pointRepeatNum; ++it ) {
- regions += QRegion( d->m_x[it] - static_cast<int>((width + strokeWidth) / 2.0),
- y - static_cast<int>((height + strokeWidth) / 2.0),
- width + strokeWidth,
- height + strokeWidth );
+ const qreal x = d->m_x[it];
+ const int startX = antialiased ? (qFloor(x - halfStrokeWidth)) : (qFloor(x+0.5 - halfStrokeWidth));
+ const int endX = antialiased ? (qCeil(x + width + halfStrokeWidth)) : (qFloor(x+0.5 + width + halfStrokeWidth));
+ regions += QRegion(startX, startY, endX - startX, endY - startY);
}
}
return regions;
@@ -902,8 +942,8 @@ QRegion GeoPainter::regionFromRect ( const GeoDataCoordinates & centerCoordinate
void GeoPainter::drawRoundedRect(const GeoDataCoordinates &centerPosition,
- int width, int height,
- int xRnd, int yRnd )
+ qreal width, qreal height,
+ qreal xRnd, qreal yRnd)
{
int pointRepeatNum;
qreal y;
@@ -914,8 +954,10 @@ void GeoPainter::drawRoundedRect(const GeoDataCoordinates &centerPosition,
if ( visible ) {
// Draw all the x-repeat-instances of the point on the screen
+ const qreal posY = y - height / 2.0;
for( int it = 0; it < pointRepeatNum; ++it ) {
- QPainter::drawRoundedRect(d->m_x[it] - ( width / 2 ), y - ( height / 2 ), width, height, xRnd, yRnd);
+ const qreal posX = d->m_x[it] - width / 2.0;
+ QPainter::drawRoundedRect(QRectF(posX, posY, width, height), xRnd, yRnd);
}
}
}
diff --git a/src/lib/marble/GeoPainter.h b/src/lib/marble/GeoPainter.h
index 89a0807..2e752af 100644
--- a/src/lib/marble/GeoPainter.h
+++ b/src/lib/marble/GeoPainter.h
@@ -221,8 +221,8 @@ class MARBLE_EXPORT GeoPainter : public ClipPainter
further influenced.
*/
void drawText ( const GeoDataCoordinates & position, const QString & text,
- int xOffset = 0, int yOffset = 0,
- int width = 0, int height = 0,
+ qreal xOffset = 0.0, qreal yOffset = 0.0,
+ qreal width = 0.0, qreal height = 0.0,
const QTextOption & option = QTextOption() );
@@ -289,6 +289,20 @@ class MARBLE_EXPORT GeoPainter : public ClipPainter
void drawPixmap ( const GeoDataCoordinates & centerPosition,
const QPixmap & pixmap /*, bool isGeoProjected = false */ );
+/*!
+ \brief Creates a region for a rectangle for a pixmap at a given position.
+
+ A QRegion object is created that represents the area covered by
+ GeoPainter::drawPixmap(). This can be used e.g. for input event handling
+ for objects that have been painted using GeoPainter::drawPixmap().
+
+ The \a margin allows to extrude the QRegion by "margin" pixels on every side.
+
+ \see GeoDataCoordinates
+*/
+ QRegion regionFromPixmapRect(const GeoDataCoordinates &centerCoordinates,
+ int width, int height,
+ int margin = 0) const;
/*!
\brief Draws a given line string (a "polyline").
@@ -442,8 +456,8 @@ class MARBLE_EXPORT GeoPainter : public ClipPainter
\see GeoDataCoordinates
*/
void drawRoundedRect(const GeoDataCoordinates &centerPosition,
- int width, int height,
- int xRnd = 25, int yRnd = 25 );
+ qreal width, qreal height,
+ qreal xRnd = 25.0, qreal yRnd = 25.0);
diff --git a/src/lib/marble/routing/RoutingLayer.cpp b/src/lib/marble/routing/RoutingLayer.cpp
index 9895db3..a20fdf3 100644
--- a/src/lib/marble/routing/RoutingLayer.cpp
+++ b/src/lib/marble/routing/RoutingLayer.cpp
@@ -219,7 +219,7 @@ void RoutingLayerPrivate::renderPlacemarks( GeoPainter *painter )
painter->drawPixmap( pos, pixmap );
}
- QRegion region = painter->regionFromRect( pos, m_targetPixmap.width(), m_targetPixmap.height() );
+ const QRegion region = painter->regionFromPixmapRect(pos, m_targetPixmap.width(), m_targetPixmap.height());
m_placemarks.push_back( ModelRegion( index, region ) );
}
}
@@ -380,7 +380,7 @@ void RoutingLayerPrivate::renderRequest( GeoPainter *painter )
if ( pos.isValid() ) {
QPixmap pixmap = m_routeRequest->pixmap( i );
painter->drawPixmap( pos, pixmap );
- QRegion region = painter->regionFromRect( pos, pixmap.width(), pixmap.height() );
+ const QRegion region = painter->regionFromPixmapRect(pos, pixmap.width(), pixmap.height());
m_regions.push_front( RequestRegion( i, region ) );
}
}