Skip to content

Commit a96d3d7

Browse files
author
wonder
committed
[FEATURE] Data-defined rotation and size for categorized and graduated renderer (symbology-ng)
Developed for Faunalia (http://www.faunalia.it) with funding from Regione Toscana - Sistema Informativo per la Gestione del Territorio e dell' Ambiente [RT-SIGTA]. For the project: "Sviluppo di prodotti software GIS open-source basati sui prodotti QuantumGIS e Postgis (CIG 037728516E)" git-svn-id: http://svn.osgeo.org/qgis/trunk@13946 c8812cc2-4d05-0410-92ff-de0c093fc19c
1 parent 75890ae commit a96d3d7

16 files changed

+418
-87
lines changed

python/core/symbology-ng-core.sip

+20
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,16 @@ public:
249249
QgsVectorColorRampV2* sourceColorRamp();
250250
void setSourceColorRamp(QgsVectorColorRampV2* ramp /Transfer/);
251251

252+
//! @note added in 1.6
253+
void setRotationField( QString fieldName );
254+
//! @note added in 1.6
255+
QString rotationField() const;
256+
257+
//! @note added in 1.6
258+
void setSizeScaleField( QString fieldName );
259+
//! @note added in 1.6
260+
QString sizeScaleField() const;
261+
252262
protected:
253263

254264
QgsSymbolV2* symbolForValue(QVariant value);
@@ -348,6 +358,16 @@ public:
348358
QgsVectorColorRampV2* sourceColorRamp();
349359
void setSourceColorRamp(QgsVectorColorRampV2* ramp /Transfer/);
350360

361+
//! @note added in 1.6
362+
void setRotationField( QString fieldName );
363+
//! @note added in 1.6
364+
QString rotationField() const;
365+
366+
//! @note added in 1.6
367+
void setSizeScaleField( QString fieldName );
368+
//! @note added in 1.6
369+
QString sizeScaleField() const;
370+
351371
protected:
352372
QgsSymbolV2* symbolForValue(double value);
353373
};

src/core/symbology-ng/qgscategorizedsymbolrendererv2.cpp

+82-4
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,8 @@ QgsSymbolV2* QgsCategorizedSymbolRendererV2::symbolForValue( QVariant value )
120120
QgsDebugMsg( "attribute value not found: " + value.toString() );
121121
return NULL;
122122
}
123-
else
124-
return *it;
123+
124+
return *it;
125125
}
126126

127127
QgsSymbolV2* QgsCategorizedSymbolRendererV2::symbolForFeature( QgsFeature& feature )
@@ -134,8 +134,40 @@ QgsSymbolV2* QgsCategorizedSymbolRendererV2::symbolForFeature( QgsFeature& featu
134134
return NULL;
135135
}
136136

137-
// find the right category
138-
return symbolForValue( *ita );
137+
// find the right symbol for the category
138+
QgsSymbolV2* symbol = symbolForValue( *ita );
139+
140+
if ( mRotationFieldIdx == -1 && mSizeScaleFieldIdx == -1 )
141+
return symbol; // no data-defined rotation/scaling - just return the symbol
142+
143+
// find out rotation, size scale
144+
double rotation = 0;
145+
double sizeScale = 1;
146+
if ( mRotationFieldIdx != -1 )
147+
rotation = attrMap[mRotationFieldIdx].toDouble();
148+
if ( mSizeScaleFieldIdx != -1 )
149+
sizeScale = attrMap[mSizeScaleFieldIdx].toDouble();
150+
151+
// take a temporary symbol (or create it if doesn't exist)
152+
QgsSymbolV2* tempSymbol = mTempSymbols[ita->toString()];
153+
154+
// modify the temporary symbol and return it
155+
if ( tempSymbol->type() == QgsSymbolV2::Marker )
156+
{
157+
QgsMarkerSymbolV2* markerSymbol = static_cast<QgsMarkerSymbolV2*>( tempSymbol );
158+
if ( mRotationFieldIdx != -1 )
159+
markerSymbol->setAngle( rotation );
160+
if ( mSizeScaleFieldIdx != -1 )
161+
markerSymbol->setSize( sizeScale * static_cast<QgsMarkerSymbolV2*>( symbol )->size() );
162+
}
163+
else if ( tempSymbol->type() == QgsSymbolV2::Line )
164+
{
165+
QgsLineSymbolV2* lineSymbol = static_cast<QgsLineSymbolV2*>( tempSymbol );
166+
if ( mSizeScaleFieldIdx != -1 )
167+
lineSymbol->setWidth( sizeScale * static_cast<QgsLineSymbolV2*>( symbol )->width() );
168+
}
169+
170+
return tempSymbol;
139171
}
140172

141173
int QgsCategorizedSymbolRendererV2::categoryIndexForValue( QVariant val )
@@ -206,22 +238,50 @@ void QgsCategorizedSymbolRendererV2::startRender( QgsRenderContext& context, con
206238
// find out classification attribute index from name
207239
mAttrNum = vlayer ? vlayer->fieldNameIndex( mAttrName ) : -1;
208240

241+
mRotationFieldIdx = ( mRotationField.isEmpty() ? -1 : vlayer->fieldNameIndex( mRotationField ) );
242+
mSizeScaleFieldIdx = ( mSizeScaleField.isEmpty() ? -1 : vlayer->fieldNameIndex( mSizeScaleField ) );
243+
209244
QgsCategoryList::iterator it = mCategories.begin();
210245
for ( ; it != mCategories.end(); ++it )
246+
{
211247
it->symbol()->startRender( context );
248+
249+
if ( mRotationFieldIdx != -1 || mSizeScaleFieldIdx != -1 )
250+
{
251+
QgsSymbolV2* tempSymbol = it->symbol()->clone();
252+
tempSymbol->setRenderHints(( mRotationFieldIdx != -1 ? QgsSymbolV2::DataDefinedRotation : 0 ) |
253+
( mSizeScaleFieldIdx != -1 ? QgsSymbolV2::DataDefinedSizeScale : 0 ) );
254+
tempSymbol->startRender( context );
255+
mTempSymbols[ it->value().toString()] = tempSymbol;
256+
}
257+
}
258+
212259
}
213260

214261
void QgsCategorizedSymbolRendererV2::stopRender( QgsRenderContext& context )
215262
{
216263
QgsCategoryList::iterator it = mCategories.begin();
217264
for ( ; it != mCategories.end(); ++it )
218265
it->symbol()->stopRender( context );
266+
267+
// cleanup mTempSymbols
268+
QHash<QString, QgsSymbolV2*>::iterator it2 = mTempSymbols.begin();
269+
for ( ; it2 != mTempSymbols.end(); ++it2 )
270+
{
271+
it2.value()->stopRender( context );
272+
delete it2.value();
273+
}
274+
mTempSymbols.clear();
219275
}
220276

221277
QList<QString> QgsCategorizedSymbolRendererV2::usedAttributes()
222278
{
223279
QList<QString> lst;
224280
lst.append( mAttrName );
281+
if ( !mRotationField.isEmpty() )
282+
lst.append( mRotationField );
283+
if ( !mSizeScaleField.isEmpty() )
284+
lst.append( mSizeScaleField );
225285
return lst;
226286
}
227287

@@ -241,6 +301,8 @@ QgsFeatureRendererV2* QgsCategorizedSymbolRendererV2::clone()
241301
if ( mSourceColorRamp )
242302
r->setSourceColorRamp( mSourceColorRamp->clone() );
243303
r->setUsingSymbolLevels( usingSymbolLevels() );
304+
r->setRotationField( rotationField() );
305+
r->setSizeScaleField( sizeScaleField() );
244306
return r;
245307
}
246308

@@ -308,6 +370,14 @@ QgsFeatureRendererV2* QgsCategorizedSymbolRendererV2::create( QDomElement& eleme
308370
r->setSourceColorRamp( QgsSymbolLayerV2Utils::loadColorRamp( sourceColorRampElem ) );
309371
}
310372

373+
QDomElement rotationElem = element.firstChildElement( "rotation" );
374+
if ( !rotationElem.isNull() )
375+
r->setRotationField( rotationElem.attribute( "field" ) );
376+
377+
QDomElement sizeScaleElem = element.firstChildElement( "sizescale" );
378+
if ( !sizeScaleElem.isNull() )
379+
r->setSizeScaleField( sizeScaleElem.attribute( "field" ) );
380+
311381
// TODO: symbol levels
312382
return r;
313383
}
@@ -360,6 +430,14 @@ QDomElement QgsCategorizedSymbolRendererV2::save( QDomDocument& doc )
360430
rendererElem.appendChild( colorRampElem );
361431
}
362432

433+
QDomElement rotationElem = doc.createElement( "rotation" );
434+
rotationElem.setAttribute( "field", mRotationField );
435+
rendererElem.appendChild( rotationElem );
436+
437+
QDomElement sizeScaleElem = doc.createElement( "sizescale" );
438+
sizeScaleElem.setAttribute( "field", mSizeScaleField );
439+
rendererElem.appendChild( sizeScaleElem );
440+
363441
return rendererElem;
364442
}
365443

src/core/symbology-ng/qgscategorizedsymbolrendererv2.h

+16
Original file line numberDiff line numberDiff line change
@@ -96,18 +96,34 @@ class CORE_EXPORT QgsCategorizedSymbolRendererV2 : public QgsFeatureRendererV2
9696
QgsVectorColorRampV2* sourceColorRamp();
9797
void setSourceColorRamp( QgsVectorColorRampV2* ramp );
9898

99+
//! @note added in 1.6
100+
void setRotationField( QString fieldName ) { mRotationField = fieldName; }
101+
//! @note added in 1.6
102+
QString rotationField() const { return mRotationField; }
103+
104+
//! @note added in 1.6
105+
void setSizeScaleField( QString fieldName ) { mSizeScaleField = fieldName; }
106+
//! @note added in 1.6
107+
QString sizeScaleField() const { return mSizeScaleField; }
108+
99109
protected:
100110
QString mAttrName;
101111
QgsCategoryList mCategories;
102112
QgsSymbolV2* mSourceSymbol;
103113
QgsVectorColorRampV2* mSourceColorRamp;
114+
QString mRotationField;
115+
QString mSizeScaleField;
104116

105117
//! attribute index (derived from attribute name in startRender)
106118
int mAttrNum;
119+
int mRotationFieldIdx, mSizeScaleFieldIdx;
107120

108121
//! hashtable for faster access to symbols
109122
QHash<QString, QgsSymbolV2*> mSymbolHash;
110123

124+
//! temporary symbols, used for data-defined rotation and scaling
125+
QHash<QString, QgsSymbolV2*> mTempSymbols;
126+
111127
void rebuildHash();
112128

113129
QgsSymbolV2* symbolForValue( QVariant value );

src/core/symbology-ng/qgsgraduatedsymbolrendererv2.cpp

+77-1
Original file line numberDiff line numberDiff line change
@@ -120,31 +120,89 @@ QgsSymbolV2* QgsGraduatedSymbolRendererV2::symbolForFeature( QgsFeature& feature
120120
}
121121

122122
// find the right category
123-
return symbolForValue( ita->toDouble() );
123+
QgsSymbolV2* symbol = symbolForValue( ita->toDouble() );
124124

125+
126+
if ( mRotationFieldIdx == -1 && mSizeScaleFieldIdx == -1 )
127+
return symbol; // no data-defined rotation/scaling - just return the symbol
128+
129+
// find out rotation, size scale
130+
double rotation = 0;
131+
double sizeScale = 1;
132+
if ( mRotationFieldIdx != -1 )
133+
rotation = attrMap[mRotationFieldIdx].toDouble();
134+
if ( mSizeScaleFieldIdx != -1 )
135+
sizeScale = attrMap[mSizeScaleFieldIdx].toDouble();
136+
137+
// take a temporary symbol (or create it if doesn't exist)
138+
QgsSymbolV2* tempSymbol = mTempSymbols[symbol];
139+
140+
// modify the temporary symbol and return it
141+
if ( tempSymbol->type() == QgsSymbolV2::Marker )
142+
{
143+
QgsMarkerSymbolV2* markerSymbol = static_cast<QgsMarkerSymbolV2*>( tempSymbol );
144+
if ( mRotationFieldIdx != -1 )
145+
markerSymbol->setAngle( rotation );
146+
if ( mSizeScaleFieldIdx != -1 )
147+
markerSymbol->setSize( sizeScale * static_cast<QgsMarkerSymbolV2*>( symbol )->size() );
148+
}
149+
else if ( tempSymbol->type() == QgsSymbolV2::Line )
150+
{
151+
QgsLineSymbolV2* lineSymbol = static_cast<QgsLineSymbolV2*>( tempSymbol );
152+
if ( mSizeScaleFieldIdx != -1 )
153+
lineSymbol->setWidth( sizeScale * static_cast<QgsLineSymbolV2*>( symbol )->width() );
154+
}
155+
return tempSymbol;
125156
}
126157

127158
void QgsGraduatedSymbolRendererV2::startRender( QgsRenderContext& context, const QgsVectorLayer *vlayer )
128159
{
129160
// find out classification attribute index from name
130161
mAttrNum = vlayer ? vlayer->fieldNameIndex( mAttrName ) : -1;
131162

163+
mRotationFieldIdx = ( mRotationField.isEmpty() ? -1 : vlayer->fieldNameIndex( mRotationField ) );
164+
mSizeScaleFieldIdx = ( mSizeScaleField.isEmpty() ? -1 : vlayer->fieldNameIndex( mSizeScaleField ) );
165+
132166
QgsRangeList::iterator it = mRanges.begin();
133167
for ( ; it != mRanges.end(); ++it )
168+
{
134169
it->symbol()->startRender( context );
170+
171+
if ( mRotationFieldIdx != -1 || mSizeScaleFieldIdx != -1 )
172+
{
173+
QgsSymbolV2* tempSymbol = it->symbol()->clone();
174+
tempSymbol->setRenderHints(( mRotationFieldIdx != -1 ? QgsSymbolV2::DataDefinedRotation : 0 ) |
175+
( mSizeScaleFieldIdx != -1 ? QgsSymbolV2::DataDefinedSizeScale : 0 ) );
176+
tempSymbol->startRender( context );
177+
mTempSymbols[ it->symbol()] = tempSymbol;
178+
}
179+
}
135180
}
136181

137182
void QgsGraduatedSymbolRendererV2::stopRender( QgsRenderContext& context )
138183
{
139184
QgsRangeList::iterator it = mRanges.begin();
140185
for ( ; it != mRanges.end(); ++it )
141186
it->symbol()->startRender( context );
187+
188+
// cleanup mTempSymbols
189+
QHash<QgsSymbolV2*, QgsSymbolV2*>::iterator it2 = mTempSymbols.begin();
190+
for ( ; it2 != mTempSymbols.end(); ++it2 )
191+
{
192+
it2.value()->stopRender( context );
193+
delete it2.value();
194+
}
195+
mTempSymbols.clear();
142196
}
143197

144198
QList<QString> QgsGraduatedSymbolRendererV2::usedAttributes()
145199
{
146200
QList<QString> lst;
147201
lst.append( mAttrName );
202+
if ( !mRotationField.isEmpty() )
203+
lst.append( mRotationField );
204+
if ( !mSizeScaleField.isEmpty() )
205+
lst.append( mSizeScaleField );
148206
return lst;
149207
}
150208

@@ -196,6 +254,8 @@ QgsFeatureRendererV2* QgsGraduatedSymbolRendererV2::clone()
196254
if ( mSourceColorRamp )
197255
r->setSourceColorRamp( mSourceColorRamp->clone() );
198256
r->setUsingSymbolLevels( usingSymbolLevels() );
257+
r->setRotationField( rotationField() );
258+
r->setSizeScaleField( sizeScaleField() );
199259
return r;
200260
}
201261

@@ -392,6 +452,14 @@ QgsFeatureRendererV2* QgsGraduatedSymbolRendererV2::create( QDomElement& element
392452
r->setMode( Quantile );
393453
}
394454

455+
QDomElement rotationElem = element.firstChildElement( "rotation" );
456+
if ( !rotationElem.isNull() )
457+
r->setRotationField( rotationElem.attribute( "field" ) );
458+
459+
QDomElement sizeScaleElem = element.firstChildElement( "sizescale" );
460+
if ( !sizeScaleElem.isNull() )
461+
r->setSizeScaleField( sizeScaleElem.attribute( "field" ) );
462+
395463
// TODO: symbol levels
396464
return r;
397465
}
@@ -458,6 +526,14 @@ QDomElement QgsGraduatedSymbolRendererV2::save( QDomDocument& doc )
458526
rendererElem.appendChild( modeElem );
459527
}
460528

529+
QDomElement rotationElem = doc.createElement( "rotation" );
530+
rotationElem.setAttribute( "field", mRotationField );
531+
rendererElem.appendChild( rotationElem );
532+
533+
QDomElement sizeScaleElem = doc.createElement( "sizescale" );
534+
sizeScaleElem.setAttribute( "field", mSizeScaleField );
535+
rendererElem.appendChild( sizeScaleElem );
536+
461537
return rendererElem;
462538
}
463539

src/core/symbology-ng/qgsgraduatedsymbolrendererv2.h

+16
Original file line numberDiff line numberDiff line change
@@ -107,15 +107,31 @@ class CORE_EXPORT QgsGraduatedSymbolRendererV2 : public QgsFeatureRendererV2
107107
QgsVectorColorRampV2* sourceColorRamp();
108108
void setSourceColorRamp( QgsVectorColorRampV2* ramp );
109109

110+
//! @note added in 1.6
111+
void setRotationField( QString fieldName ) { mRotationField = fieldName; }
112+
//! @note added in 1.6
113+
QString rotationField() const { return mRotationField; }
114+
115+
//! @note added in 1.6
116+
void setSizeScaleField( QString fieldName ) { mSizeScaleField = fieldName; }
117+
//! @note added in 1.6
118+
QString sizeScaleField() const { return mSizeScaleField; }
119+
110120
protected:
111121
QString mAttrName;
112122
QgsRangeList mRanges;
113123
Mode mMode;
114124
QgsSymbolV2* mSourceSymbol;
115125
QgsVectorColorRampV2* mSourceColorRamp;
126+
QString mRotationField;
127+
QString mSizeScaleField;
116128

117129
//! attribute index (derived from attribute name in startRender)
118130
int mAttrNum;
131+
int mRotationFieldIdx, mSizeScaleFieldIdx;
132+
133+
//! temporary symbols, used for data-defined rotation and scaling
134+
QHash<QgsSymbolV2*, QgsSymbolV2*> mTempSymbols;
119135

120136
QgsSymbolV2* symbolForValue( double value );
121137
};

src/gui/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ symbology-ng/qgssinglesymbolrendererv2widget.h
6565
symbology-ng/qgscategorizedsymbolrendererv2widget.h
6666
symbology-ng/qgsgraduatedsymbolrendererv2widget.h
6767
symbology-ng/qgsrulebasedrendererv2widget.h
68+
symbology-ng/qgsrendererv2widget.h
6869
symbology-ng/qgsrendererv2propertiesdialog.h
6970
symbology-ng/qgsstylev2managerdialog.h
7071
symbology-ng/qgssymbollevelsv2dialog.h

0 commit comments

Comments
 (0)