Skip to content

Commit 604f7e5

Browse files
committed
Add methods to test whether graduated ranges overlap or have gaps
1 parent fccd8e5 commit 604f7e5

File tree

5 files changed

+216
-1
lines changed

5 files changed

+216
-1
lines changed

python/core/symbology-ng/qgsgraduatedsymbolrendererv2.sip

+12
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,18 @@ class QgsGraduatedSymbolRendererV2 : QgsFeatureRendererV2
131131
//! Moves the category at index position from to index position to.
132132
void moveClass( int from, int to );
133133

134+
/** Tests whether classes assigned to the renderer have ranges which overlap.
135+
* @returns true if ranges overlap
136+
* @note added in QGIS 2.10
137+
*/
138+
bool rangesOverlap() const;
139+
140+
/** Tests whether classes assigned to the renderer have gaps between the ranges.
141+
* @returns true if ranges have gaps
142+
* @note added in QGIS 2.10
143+
*/
144+
bool rangesHaveGaps() const;
145+
134146
void sortByValue( Qt::SortOrder order = Qt::AscendingOrder );
135147
void sortByLabel( Qt::SortOrder order = Qt::AscendingOrder );
136148

src/core/symbology-ng/qgsgraduatedsymbolrendererv2.cpp

+50
Original file line numberDiff line numberDiff line change
@@ -1547,6 +1547,56 @@ void QgsGraduatedSymbolRendererV2::sortByValue( Qt::SortOrder order )
15471547
}
15481548
}
15491549

1550+
bool QgsGraduatedSymbolRendererV2::rangesOverlap() const
1551+
{
1552+
QgsRangeList sortedRanges = mRanges;
1553+
qSort( sortedRanges.begin(), sortedRanges.end(), valueLessThan );
1554+
1555+
QgsRangeList::const_iterator it = sortedRanges.constBegin();
1556+
if ( it == sortedRanges.constEnd() )
1557+
return false;
1558+
1559+
if (( *it ).upperValue() < ( *it ).lowerValue() )
1560+
return true;
1561+
1562+
double prevMax = ( *it ).upperValue();
1563+
it++;
1564+
1565+
for ( ; it != sortedRanges.constEnd(); ++it )
1566+
{
1567+
if (( *it ).upperValue() < ( *it ).lowerValue() )
1568+
return true;
1569+
1570+
if (( *it ).lowerValue() < prevMax )
1571+
return true;
1572+
1573+
prevMax = ( *it ).upperValue();
1574+
}
1575+
return false;
1576+
}
1577+
1578+
bool QgsGraduatedSymbolRendererV2::rangesHaveGaps() const
1579+
{
1580+
QgsRangeList sortedRanges = mRanges;
1581+
qSort( sortedRanges.begin(), sortedRanges.end(), valueLessThan );
1582+
1583+
QgsRangeList::const_iterator it = sortedRanges.constBegin();
1584+
if ( it == sortedRanges.constEnd() )
1585+
return false;
1586+
1587+
double prevMax = ( *it ).upperValue();
1588+
it++;
1589+
1590+
for ( ; it != sortedRanges.constEnd(); ++it )
1591+
{
1592+
if ( !qgsDoubleNear( ( *it ).lowerValue(), prevMax ) )
1593+
return true;
1594+
1595+
prevMax = ( *it ).upperValue();
1596+
}
1597+
return false;
1598+
}
1599+
15501600
bool labelLessThan( const QgsRendererRangeV2 &r1, const QgsRendererRangeV2 &r2 )
15511601
{
15521602
return QString::localeAwareCompare( r1.label(), r2.label() ) < 0;

src/core/symbology-ng/qgsgraduatedsymbolrendererv2.h

+12
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,18 @@ class CORE_EXPORT QgsGraduatedSymbolRendererV2 : public QgsFeatureRendererV2
173173
//! Moves the category at index position from to index position to.
174174
void moveClass( int from, int to );
175175

176+
/** Tests whether classes assigned to the renderer have ranges which overlap.
177+
* @returns true if ranges overlap
178+
* @note added in QGIS 2.10
179+
*/
180+
bool rangesOverlap() const;
181+
182+
/** Tests whether classes assigned to the renderer have gaps between the ranges.
183+
* @returns true if ranges have gaps
184+
* @note added in QGIS 2.10
185+
*/
186+
bool rangesHaveGaps() const;
187+
176188
void sortByValue( Qt::SortOrder order = Qt::AscendingOrder );
177189
void sortByLabel( Qt::SortOrder order = Qt::AscendingOrder );
178190

tests/src/core/CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,6 @@ ADD_QGIS_TEST(painteffectregistrytest testqgspainteffectregistry.cpp)
161161
ADD_QGIS_TEST(statisticalsummarytest testqgsstatisticalsummary.cpp)
162162
ADD_QGIS_TEST(histogramtest testqgshistogram.cpp)
163163
ADD_QGIS_TEST(pallabelingtest testqgspallabeling.cpp)
164-
164+
ADD_QGIS_TEST(graduatedsymbolrenderertest testqgsgraduatedsymbolrenderer.cpp)
165165
166166
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
/***************************************************************************
2+
testqgsgraduatedsymbolrenderer.cpp
3+
----------------------------------
4+
Date : May 2015
5+
Copyright : (C) 2015 Nyall Dawson
6+
Email : nyall dot dawson at gmail dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
#include <QtTest/QtTest>
16+
#include <QObject>
17+
#include <QString>
18+
#include <QStringList>
19+
#include <QSettings>
20+
#include <QSharedPointer>
21+
22+
#include "qgsgraduatedsymbolrendererv2.h"
23+
24+
class TestQgsGraduatedSymbolRenderer: public QObject
25+
{
26+
Q_OBJECT
27+
28+
private slots:
29+
void initTestCase();// will be called before the first testfunction is executed.
30+
void cleanupTestCase();// will be called after the last testfunction was executed.
31+
void init();// will be called before each testfunction is executed.
32+
void cleanup();// will be called after every testfunction.
33+
void rangesOverlap();
34+
void rangesHaveGaps();
35+
36+
37+
private:
38+
};
39+
40+
void TestQgsGraduatedSymbolRenderer::initTestCase()
41+
{
42+
43+
}
44+
45+
void TestQgsGraduatedSymbolRenderer::cleanupTestCase()
46+
{
47+
48+
}
49+
50+
void TestQgsGraduatedSymbolRenderer::init()
51+
{
52+
53+
}
54+
55+
void TestQgsGraduatedSymbolRenderer::cleanup()
56+
{
57+
58+
}
59+
60+
void TestQgsGraduatedSymbolRenderer::rangesOverlap()
61+
{
62+
QgsGraduatedSymbolRendererV2 renderer;
63+
//test with no ranges
64+
QVERIFY( !renderer.rangesOverlap() );
65+
66+
//test with inverted range
67+
QgsRendererRangeV2 inverted;
68+
inverted.setLowerValue( 3.1 );
69+
inverted.setUpperValue( 1.2 );
70+
renderer.addClass( inverted );
71+
QVERIFY( renderer.rangesOverlap() );
72+
renderer.deleteAllClasses();
73+
74+
//test non-overlapping ranges
75+
QgsRendererRangeV2 range1;
76+
range1.setLowerValue( 1.1 );
77+
range1.setUpperValue( 3.2 );
78+
QgsRendererRangeV2 range2;
79+
range2.setLowerValue( 6.4 );
80+
range2.setUpperValue( 7.2 );
81+
QgsRendererRangeV2 range3;
82+
range3.setLowerValue( 3.2 );
83+
range3.setUpperValue( 6.4 );
84+
85+
renderer.addClass( range1 );
86+
renderer.addClass( range2 );
87+
renderer.addClass( range3 );
88+
89+
QVERIFY( !renderer.rangesOverlap() );
90+
91+
//add overlapping class
92+
QgsRendererRangeV2 range4;
93+
range4.setLowerValue( 7.0 );
94+
range4.setUpperValue( 8.4 );
95+
renderer.addClass( range4 );
96+
97+
QVERIFY( renderer.rangesOverlap() );
98+
}
99+
100+
void TestQgsGraduatedSymbolRenderer::rangesHaveGaps()
101+
{
102+
QgsGraduatedSymbolRendererV2 renderer;
103+
//test with no ranges
104+
QVERIFY( !renderer.rangesHaveGaps() );
105+
106+
//test with inverted range
107+
QgsRendererRangeV2 inverted;
108+
inverted.setLowerValue( 3.1 );
109+
inverted.setUpperValue( 1.2 );
110+
renderer.addClass( inverted );
111+
QVERIFY( !renderer.rangesHaveGaps() );
112+
renderer.deleteAllClasses();
113+
114+
//test ranges without gaps ranges
115+
QgsRendererRangeV2 range1;
116+
range1.setLowerValue( 1.1 );
117+
range1.setUpperValue( 3.2 );
118+
QgsRendererRangeV2 range2;
119+
range2.setLowerValue( 6.4 );
120+
range2.setUpperValue( 7.2 );
121+
QgsRendererRangeV2 range3;
122+
range3.setLowerValue( 3.2 );
123+
range3.setUpperValue( 6.4 );
124+
125+
renderer.addClass( range1 );
126+
renderer.addClass( range2 );
127+
renderer.addClass( range3 );
128+
129+
QVERIFY( !renderer.rangesHaveGaps() );
130+
131+
//add gaps in ranges
132+
QgsRendererRangeV2 range4;
133+
range4.setLowerValue( 8.0 );
134+
range4.setUpperValue( 8.4 );
135+
renderer.addClass( range4 );
136+
137+
QVERIFY( renderer.rangesHaveGaps() );
138+
}
139+
140+
QTEST_MAIN( TestQgsGraduatedSymbolRenderer )
141+
#include "testqgsgraduatedsymbolrenderer.moc"

0 commit comments

Comments
 (0)