From 754375f6609f9ddeda62b589ceea1747f2942343 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Wed, 10 Jun 2020 20:46:37 +1000 Subject: [PATCH] Improve method for calculation of rectangle centers More numerically stable in the case of massive rectangles. This is the ultimate cause behind #36898 -- during rendering of the worldwide layer in Winkel Tripel the inverse transform fails, so the renderer sets a "maximal" filter extent for the layer (+/- double max). The previous method for calculating the rectangles center would fail, because it would overflow. The new method handles this case and correctly returns 0,0. Fixes bounding boxes show incorrectly when simplication is enabled for a layer in certain projections. Fixes #36898 Refs #30686 (partial fix -- this report includes two different bugs) --- src/core/geometry/qgsrectangle.h | 2 +- tests/src/core/testqgsrectangle.cpp | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/core/geometry/qgsrectangle.h b/src/core/geometry/qgsrectangle.h index 911b72863ff6..fa2edc89f7d0 100644 --- a/src/core/geometry/qgsrectangle.h +++ b/src/core/geometry/qgsrectangle.h @@ -227,7 +227,7 @@ class CORE_EXPORT QgsRectangle /** * Returns the center point of the rectangle. */ - QgsPointXY center() const { return QgsPointXY( mXmin + width() / 2, mYmin + height() / 2 ); } + QgsPointXY center() const { return QgsPointXY( mXmax * 0.5 + mXmin * 0.5, mYmin * 0.5 + mYmax * 0.5 ); } /** * Scale the rectangle around its center point. diff --git a/tests/src/core/testqgsrectangle.cpp b/tests/src/core/testqgsrectangle.cpp index a5ee0977b079..74e50c151e9f 100644 --- a/tests/src/core/testqgsrectangle.cpp +++ b/tests/src/core/testqgsrectangle.cpp @@ -43,6 +43,7 @@ class TestQgsRectangle: public QObject void scale(); void snappedToGrid(); void distanceToPoint(); + void center(); }; void TestQgsRectangle::isEmpty() @@ -404,5 +405,22 @@ void TestQgsRectangle::distanceToPoint() QGSCOMPARENEAR( rect.distance( QgsPointXY( 25, 115 ) ), 7.071068, 0.00001 ); } +void TestQgsRectangle::center() +{ + QgsRectangle rect( 10, 100, 20, 110 ); + QCOMPARE( rect.center().x(), 15.0 ); + QCOMPARE( rect.center().y(), 105.0 ); + rect = QgsRectangle( 10, 100, 10, 100 ); + QCOMPARE( rect.center().x(), 10.0 ); + QCOMPARE( rect.center().y(), 100.0 ); + rect = QgsRectangle( -10, -100, 10, 100 ); + QCOMPARE( rect.center().x(), 0.0 ); + QCOMPARE( rect.center().y(), 0.0 ); + // a "maximal" rect + rect = QgsRectangle( std::numeric_limits::lowest(), std::numeric_limits::lowest(), std::numeric_limits::max(), std::numeric_limits::max() ); + QCOMPARE( rect.center().x(), 0.0 ); + QCOMPARE( rect.center().y(), 0.0 ); +} + QGSTEST_MAIN( TestQgsRectangle ) #include "testqgsrectangle.moc"