Skip to content
Permalink
Browse files

Allow QgsRectangle constructors to bypass the automatic normalization

step, when they know in advance they are already normalized

This step isn't free, and can add up when many rectangles are
constructed
  • Loading branch information
nyalldawson committed Feb 23, 2021
1 parent 885387f commit d007901f14f7218fd32d7ab3c7350fdb2a73a1e1
@@ -29,19 +29,27 @@ Examples are storing a layer extent or the current view extent of a map

QgsRectangle(); // optimised constructor for null rectangle - no need to call normalize here

explicit QgsRectangle( double xMin, double yMin = 0, double xMax = 0, double yMax = 0 ) /HoldGIL/;
explicit QgsRectangle( double xMin, double yMin = 0, double xMax = 0, double yMax = 0, bool normalize = true ) /HoldGIL/;
%Docstring
Constructor
Constructs a QgsRectangle from a set of x and y minimum and maximum coordinates.

The rectangle will be normalized after creation. Since QGIS 3.20, if ``normalize`` is ``False`` then
the normalization step will not be applied automatically.
%End

QgsRectangle( const QgsPointXY &p1, const QgsPointXY &p2 ) /HoldGIL/;
QgsRectangle( const QgsPointXY &p1, const QgsPointXY &p2, bool normalize = true ) /HoldGIL/;
%Docstring
Construct a rectangle from two points. The rectangle is normalized after construction.
Construct a rectangle from two points.

The rectangle is normalized after construction. Since QGIS 3.20, if ``normalize`` is ``False`` then
the normalization step will not be applied automatically.
%End

QgsRectangle( const QRectF &qRectF ) /HoldGIL/;
%Docstring
Construct a rectangle from a QRectF. The rectangle is normalized after construction.
Construct a rectangle from a QRectF.

The rectangle is NOT normalized after construction.
%End

QgsRectangle( const QgsRectangle &other ) /HoldGIL/;
@@ -67,16 +75,20 @@ and ``width`` and ``height``.
.. versionadded:: 3.0
%End

void set( const QgsPointXY &p1, const QgsPointXY &p2 );
void set( const QgsPointXY &p1, const QgsPointXY &p2, bool normalize = true );
%Docstring
Sets the rectangle from two :py:class:`QgsPoints`. The rectangle is
normalised after construction.
Sets the rectangle from two :py:class:`QgsPoints`.

The rectangle is normalised after construction. Since QGIS 3.20, if ``normalize`` is ``False`` then
the normalization step will not be applied automatically.
%End

void set( double xMin, double yMin, double xMax, double yMax );
void set( double xMin, double yMin, double xMax, double yMax, bool normalize = true );
%Docstring
Sets the rectangle from four points. The rectangle is
normalised after construction.
Sets the rectangle from four points.

The rectangle is normalised after construction. Since QGIS 3.20, if ``normalize`` is ``False`` then
the normalization step will not be applied automatically.
%End

void setXMinimum( double x ) /HoldGIL/;
@@ -45,23 +45,38 @@ class CORE_EXPORT QgsRectangle
//! Constructor for a null rectangle
QgsRectangle() = default; // optimised constructor for null rectangle - no need to call normalize here

//! Constructor
explicit QgsRectangle( double xMin, double yMin = 0, double xMax = 0, double yMax = 0 ) SIP_HOLDGIL
/**
* Constructs a QgsRectangle from a set of x and y minimum and maximum coordinates.
*
* The rectangle will be normalized after creation. Since QGIS 3.20, if \a normalize is FALSE then
* the normalization step will not be applied automatically.
*/
explicit QgsRectangle( double xMin, double yMin = 0, double xMax = 0, double yMax = 0, bool normalize = true ) SIP_HOLDGIL
: mXmin( xMin )
, mYmin( yMin )
, mXmax( xMax )
, mYmax( yMax )
{
normalize();
if ( normalize )
QgsRectangle::normalize();
}

//! Construct a rectangle from two points. The rectangle is normalized after construction.
QgsRectangle( const QgsPointXY &p1, const QgsPointXY &p2 ) SIP_HOLDGIL
/**
* Construct a rectangle from two points.
*
* The rectangle is normalized after construction. Since QGIS 3.20, if \a normalize is FALSE then
* the normalization step will not be applied automatically.
*/
QgsRectangle( const QgsPointXY &p1, const QgsPointXY &p2, bool normalize = true ) SIP_HOLDGIL
{
set( p1, p2 );
set( p1, p2, normalize );
}

//! Construct a rectangle from a QRectF. The rectangle is normalized after construction.
/**
* Construct a rectangle from a QRectF.
*
* The rectangle is NOT normalized after construction.
*/
QgsRectangle( const QRectF &qRectF ) SIP_HOLDGIL
{
mXmin = qRectF.topLeft().x();
@@ -99,29 +114,35 @@ class CORE_EXPORT QgsRectangle
static QgsRectangle fromCenterAndSize( QgsPointXY center, double width, double height );

/**
* Sets the rectangle from two QgsPoints. The rectangle is
* normalised after construction.
* Sets the rectangle from two QgsPoints.
*
* The rectangle is normalised after construction. Since QGIS 3.20, if \a normalize is FALSE then
* the normalization step will not be applied automatically.
*/
void set( const QgsPointXY &p1, const QgsPointXY &p2 )
void set( const QgsPointXY &p1, const QgsPointXY &p2, bool normalize = true )
{
mXmin = p1.x();
mXmax = p2.x();
mYmin = p1.y();
mYmax = p2.y();
normalize();
if ( normalize )
QgsRectangle::normalize();
}

/**
* Sets the rectangle from four points. The rectangle is
* normalised after construction.
* Sets the rectangle from four points.
*
* The rectangle is normalised after construction. Since QGIS 3.20, if \a normalize is FALSE then
* the normalization step will not be applied automatically.
*/
void set( double xMin, double yMin, double xMax, double yMax )
void set( double xMin, double yMin, double xMax, double yMax, bool normalize = true )
{
mXmin = xMin;
mYmin = yMin;
mXmax = xMax;
mYmax = yMax;
normalize();
if ( normalize )
QgsRectangle::normalize();
}

/**
@@ -615,17 +615,9 @@ void QgsRubberBand::updateRect()
{
QgsPointXY p( point.x() + mTranslationOffsetX, point.y() + mTranslationOffsetY );
p = m2p.transform( p );
QgsRectangle rect( p.x() - w, p.y() - w, p.x() + w, p.y() + w );

if ( r.isEmpty() )
{
// Get rectangle of the first point
r = rect;
}
else
{
r.combineExtentWith( rect );
}
// no need to normalize the rectangle -- we know it is already normal
QgsRectangle rect( p.x() - w, p.y() - w, p.x() + w, p.y() + w, false );
r.combineExtentWith( rect );
}
}

@@ -27,6 +27,10 @@ class TestQgsRectangle: public QObject
private slots:
void isEmpty();
void fromWkt();
void constructor();
void constructorTwoPoints();
void set();
void setXY();
void fromCenter();
void manipulate();
void regression6194();
@@ -82,6 +86,88 @@ void TestQgsRectangle::fromWkt()
QVERIFY( QgsRectangle::fromWkt( QStringLiteral( "POLYGON((0 0,1 0,1 1,0 1))" ) ).isEmpty() );
}

void TestQgsRectangle::constructor()
{
QgsRectangle r( 1, 2, 13, 14 );
QCOMPARE( r.xMinimum(), 1.0 );
QCOMPARE( r.xMaximum(), 13.0 );
QCOMPARE( r.yMinimum(), 2.0 );
QCOMPARE( r.yMaximum(), 14.0 );

// auto normalized
QgsRectangle r2( 13, 14, 1, 2 );
QCOMPARE( r2.xMinimum(), 1.0 );
QCOMPARE( r2.xMaximum(), 13.0 );
QCOMPARE( r2.yMinimum(), 2.0 );
QCOMPARE( r2.yMaximum(), 14.0 );

// no normalization
QgsRectangle r3( 13, 14, 1, 2, false );
QCOMPARE( r3.xMinimum(), 13.0 );
QCOMPARE( r3.xMaximum(), 1.0 );
QCOMPARE( r3.yMinimum(), 14.0 );
QCOMPARE( r3.yMaximum(), 2.0 );
}

void TestQgsRectangle::constructorTwoPoints()
{
QgsRectangle r( QgsPointXY( 1, 2 ), QgsPointXY( 13, 14 ) );
QCOMPARE( r.xMinimum(), 1.0 );
QCOMPARE( r.xMaximum(), 13.0 );
QCOMPARE( r.yMinimum(), 2.0 );
QCOMPARE( r.yMaximum(), 14.0 );

// auto normalized
QgsRectangle r2( QgsPointXY( 13, 14 ), QgsPointXY( 1, 2 ) );
QCOMPARE( r2.xMinimum(), 1.0 );
QCOMPARE( r2.xMaximum(), 13.0 );
QCOMPARE( r2.yMinimum(), 2.0 );
QCOMPARE( r2.yMaximum(), 14.0 );

// no normalization
QgsRectangle r3( QgsPointXY( 13, 14 ), QgsPointXY( 1, 2 ), false );
QCOMPARE( r3.xMinimum(), 13.0 );
QCOMPARE( r3.xMaximum(), 1.0 );
QCOMPARE( r3.yMinimum(), 14.0 );
QCOMPARE( r3.yMaximum(), 2.0 );
}

void TestQgsRectangle::set()
{
QgsRectangle r( QgsPointXY( 1, 2 ), QgsPointXY( 13, 14 ) );
// auto normalized
r.set( QgsPointXY( 13, 14 ), QgsPointXY( 1, 2 ) );
QCOMPARE( r.xMinimum(), 1.0 );
QCOMPARE( r.xMaximum(), 13.0 );
QCOMPARE( r.yMinimum(), 2.0 );
QCOMPARE( r.yMaximum(), 14.0 );

// no normalization
r.set( QgsPointXY( 13, 14 ), QgsPointXY( 1, 2 ), false );
QCOMPARE( r.xMinimum(), 13.0 );
QCOMPARE( r.xMaximum(), 1.0 );
QCOMPARE( r.yMinimum(), 14.0 );
QCOMPARE( r.yMaximum(), 2.0 );
}

void TestQgsRectangle::setXY()
{
QgsRectangle r( QgsPointXY( 111, 112 ), QgsPointXY( 113, 114 ) );
// auto normalized
r.set( 13, 14, 1, 2 );
QCOMPARE( r.xMinimum(), 1.0 );
QCOMPARE( r.xMaximum(), 13.0 );
QCOMPARE( r.yMinimum(), 2.0 );
QCOMPARE( r.yMaximum(), 14.0 );

// no normalization
r.set( 13, 14, 1, 2, false );
QCOMPARE( r.xMinimum(), 13.0 );
QCOMPARE( r.xMaximum(), 1.0 );
QCOMPARE( r.yMinimum(), 14.0 );
QCOMPARE( r.yMaximum(), 2.0 );
}

void TestQgsRectangle::fromCenter()
{
QgsRectangle rect = QgsRectangle::fromCenterAndSize( QgsPointXY( 12, 21 ), 20, 40 );

0 comments on commit d007901

Please sign in to comment.