Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Add methods to test whether graduated ranges overlap or have gaps
  • Loading branch information
nyalldawson committed Jun 12, 2015
1 parent fccd8e5 commit 604f7e5
Show file tree
Hide file tree
Showing 5 changed files with 216 additions and 1 deletion.
12 changes: 12 additions & 0 deletions python/core/symbology-ng/qgsgraduatedsymbolrendererv2.sip
Expand Up @@ -131,6 +131,18 @@ class QgsGraduatedSymbolRendererV2 : QgsFeatureRendererV2
//! Moves the category at index position from to index position to.
void moveClass( int from, int to );

/** Tests whether classes assigned to the renderer have ranges which overlap.
* @returns true if ranges overlap
* @note added in QGIS 2.10
*/
bool rangesOverlap() const;

/** Tests whether classes assigned to the renderer have gaps between the ranges.
* @returns true if ranges have gaps
* @note added in QGIS 2.10
*/
bool rangesHaveGaps() const;

void sortByValue( Qt::SortOrder order = Qt::AscendingOrder );
void sortByLabel( Qt::SortOrder order = Qt::AscendingOrder );

Expand Down
50 changes: 50 additions & 0 deletions src/core/symbology-ng/qgsgraduatedsymbolrendererv2.cpp
Expand Up @@ -1547,6 +1547,56 @@ void QgsGraduatedSymbolRendererV2::sortByValue( Qt::SortOrder order )
}
}

bool QgsGraduatedSymbolRendererV2::rangesOverlap() const
{
QgsRangeList sortedRanges = mRanges;
qSort( sortedRanges.begin(), sortedRanges.end(), valueLessThan );

QgsRangeList::const_iterator it = sortedRanges.constBegin();
if ( it == sortedRanges.constEnd() )
return false;

if (( *it ).upperValue() < ( *it ).lowerValue() )
return true;

double prevMax = ( *it ).upperValue();
it++;

for ( ; it != sortedRanges.constEnd(); ++it )
{
if (( *it ).upperValue() < ( *it ).lowerValue() )
return true;

if (( *it ).lowerValue() < prevMax )
return true;

prevMax = ( *it ).upperValue();
}
return false;
}

bool QgsGraduatedSymbolRendererV2::rangesHaveGaps() const
{
QgsRangeList sortedRanges = mRanges;
qSort( sortedRanges.begin(), sortedRanges.end(), valueLessThan );

QgsRangeList::const_iterator it = sortedRanges.constBegin();
if ( it == sortedRanges.constEnd() )
return false;

double prevMax = ( *it ).upperValue();
it++;

for ( ; it != sortedRanges.constEnd(); ++it )
{
if ( !qgsDoubleNear( ( *it ).lowerValue(), prevMax ) )
return true;

prevMax = ( *it ).upperValue();
}
return false;
}

bool labelLessThan( const QgsRendererRangeV2 &r1, const QgsRendererRangeV2 &r2 )
{
return QString::localeAwareCompare( r1.label(), r2.label() ) < 0;
Expand Down
12 changes: 12 additions & 0 deletions src/core/symbology-ng/qgsgraduatedsymbolrendererv2.h
Expand Up @@ -173,6 +173,18 @@ class CORE_EXPORT QgsGraduatedSymbolRendererV2 : public QgsFeatureRendererV2
//! Moves the category at index position from to index position to.
void moveClass( int from, int to );

/** Tests whether classes assigned to the renderer have ranges which overlap.
* @returns true if ranges overlap
* @note added in QGIS 2.10
*/
bool rangesOverlap() const;

/** Tests whether classes assigned to the renderer have gaps between the ranges.
* @returns true if ranges have gaps
* @note added in QGIS 2.10
*/
bool rangesHaveGaps() const;

void sortByValue( Qt::SortOrder order = Qt::AscendingOrder );
void sortByLabel( Qt::SortOrder order = Qt::AscendingOrder );

Expand Down
2 changes: 1 addition & 1 deletion tests/src/core/CMakeLists.txt
Expand Up @@ -161,6 +161,6 @@ ADD_QGIS_TEST(painteffectregistrytest testqgspainteffectregistry.cpp)
ADD_QGIS_TEST(statisticalsummarytest testqgsstatisticalsummary.cpp)
ADD_QGIS_TEST(histogramtest testqgshistogram.cpp)
ADD_QGIS_TEST(pallabelingtest testqgspallabeling.cpp)

ADD_QGIS_TEST(graduatedsymbolrenderertest testqgsgraduatedsymbolrenderer.cpp)


141 changes: 141 additions & 0 deletions tests/src/core/testqgsgraduatedsymbolrenderer.cpp
@@ -0,0 +1,141 @@
/***************************************************************************
testqgsgraduatedsymbolrenderer.cpp
----------------------------------
Date : May 2015
Copyright : (C) 2015 Nyall Dawson
Email : nyall dot dawson at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include <QtTest/QtTest>
#include <QObject>
#include <QString>
#include <QStringList>
#include <QSettings>
#include <QSharedPointer>

#include "qgsgraduatedsymbolrendererv2.h"

class TestQgsGraduatedSymbolRenderer: public QObject
{
Q_OBJECT

private slots:
void initTestCase();// will be called before the first testfunction is executed.
void cleanupTestCase();// will be called after the last testfunction was executed.
void init();// will be called before each testfunction is executed.
void cleanup();// will be called after every testfunction.
void rangesOverlap();
void rangesHaveGaps();


private:
};

void TestQgsGraduatedSymbolRenderer::initTestCase()
{

}

void TestQgsGraduatedSymbolRenderer::cleanupTestCase()
{

}

void TestQgsGraduatedSymbolRenderer::init()
{

}

void TestQgsGraduatedSymbolRenderer::cleanup()
{

}

void TestQgsGraduatedSymbolRenderer::rangesOverlap()
{
QgsGraduatedSymbolRendererV2 renderer;
//test with no ranges
QVERIFY( !renderer.rangesOverlap() );

//test with inverted range
QgsRendererRangeV2 inverted;
inverted.setLowerValue( 3.1 );
inverted.setUpperValue( 1.2 );
renderer.addClass( inverted );
QVERIFY( renderer.rangesOverlap() );
renderer.deleteAllClasses();

//test non-overlapping ranges
QgsRendererRangeV2 range1;
range1.setLowerValue( 1.1 );
range1.setUpperValue( 3.2 );
QgsRendererRangeV2 range2;
range2.setLowerValue( 6.4 );
range2.setUpperValue( 7.2 );
QgsRendererRangeV2 range3;
range3.setLowerValue( 3.2 );
range3.setUpperValue( 6.4 );

renderer.addClass( range1 );
renderer.addClass( range2 );
renderer.addClass( range3 );

QVERIFY( !renderer.rangesOverlap() );

//add overlapping class
QgsRendererRangeV2 range4;
range4.setLowerValue( 7.0 );
range4.setUpperValue( 8.4 );
renderer.addClass( range4 );

QVERIFY( renderer.rangesOverlap() );
}

void TestQgsGraduatedSymbolRenderer::rangesHaveGaps()
{
QgsGraduatedSymbolRendererV2 renderer;
//test with no ranges
QVERIFY( !renderer.rangesHaveGaps() );

//test with inverted range
QgsRendererRangeV2 inverted;
inverted.setLowerValue( 3.1 );
inverted.setUpperValue( 1.2 );
renderer.addClass( inverted );
QVERIFY( !renderer.rangesHaveGaps() );
renderer.deleteAllClasses();

//test ranges without gaps ranges
QgsRendererRangeV2 range1;
range1.setLowerValue( 1.1 );
range1.setUpperValue( 3.2 );
QgsRendererRangeV2 range2;
range2.setLowerValue( 6.4 );
range2.setUpperValue( 7.2 );
QgsRendererRangeV2 range3;
range3.setLowerValue( 3.2 );
range3.setUpperValue( 6.4 );

renderer.addClass( range1 );
renderer.addClass( range2 );
renderer.addClass( range3 );

QVERIFY( !renderer.rangesHaveGaps() );

//add gaps in ranges
QgsRendererRangeV2 range4;
range4.setLowerValue( 8.0 );
range4.setUpperValue( 8.4 );
renderer.addClass( range4 );

QVERIFY( renderer.rangesHaveGaps() );
}

QTEST_MAIN( TestQgsGraduatedSymbolRenderer )
#include "testqgsgraduatedsymbolrenderer.moc"

0 comments on commit 604f7e5

Please sign in to comment.