Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[FEATURE] Data-defined rotation and size for categorized and graduate…
…d 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
  • Loading branch information
wonder committed Jul 20, 2010
1 parent 75890ae commit a96d3d7
Show file tree
Hide file tree
Showing 16 changed files with 418 additions and 87 deletions.
20 changes: 20 additions & 0 deletions python/core/symbology-ng-core.sip
Expand Up @@ -249,6 +249,16 @@ public:
QgsVectorColorRampV2* sourceColorRamp();
void setSourceColorRamp(QgsVectorColorRampV2* ramp /Transfer/);

//! @note added in 1.6
void setRotationField( QString fieldName );
//! @note added in 1.6
QString rotationField() const;

//! @note added in 1.6
void setSizeScaleField( QString fieldName );
//! @note added in 1.6
QString sizeScaleField() const;

protected:

QgsSymbolV2* symbolForValue(QVariant value);
Expand Down Expand Up @@ -348,6 +358,16 @@ public:
QgsVectorColorRampV2* sourceColorRamp();
void setSourceColorRamp(QgsVectorColorRampV2* ramp /Transfer/);

//! @note added in 1.6
void setRotationField( QString fieldName );
//! @note added in 1.6
QString rotationField() const;

//! @note added in 1.6
void setSizeScaleField( QString fieldName );
//! @note added in 1.6
QString sizeScaleField() const;

protected:
QgsSymbolV2* symbolForValue(double value);
};
Expand Down
86 changes: 82 additions & 4 deletions src/core/symbology-ng/qgscategorizedsymbolrendererv2.cpp
Expand Up @@ -120,8 +120,8 @@ QgsSymbolV2* QgsCategorizedSymbolRendererV2::symbolForValue( QVariant value )
QgsDebugMsg( "attribute value not found: " + value.toString() );
return NULL;
}
else
return *it;

return *it;
}

QgsSymbolV2* QgsCategorizedSymbolRendererV2::symbolForFeature( QgsFeature& feature )
Expand All @@ -134,8 +134,40 @@ QgsSymbolV2* QgsCategorizedSymbolRendererV2::symbolForFeature( QgsFeature& featu
return NULL;
}

// find the right category
return symbolForValue( *ita );
// find the right symbol for the category
QgsSymbolV2* symbol = symbolForValue( *ita );

if ( mRotationFieldIdx == -1 && mSizeScaleFieldIdx == -1 )
return symbol; // no data-defined rotation/scaling - just return the symbol

// find out rotation, size scale
double rotation = 0;
double sizeScale = 1;
if ( mRotationFieldIdx != -1 )
rotation = attrMap[mRotationFieldIdx].toDouble();
if ( mSizeScaleFieldIdx != -1 )
sizeScale = attrMap[mSizeScaleFieldIdx].toDouble();

// take a temporary symbol (or create it if doesn't exist)
QgsSymbolV2* tempSymbol = mTempSymbols[ita->toString()];

// modify the temporary symbol and return it
if ( tempSymbol->type() == QgsSymbolV2::Marker )
{
QgsMarkerSymbolV2* markerSymbol = static_cast<QgsMarkerSymbolV2*>( tempSymbol );
if ( mRotationFieldIdx != -1 )
markerSymbol->setAngle( rotation );
if ( mSizeScaleFieldIdx != -1 )
markerSymbol->setSize( sizeScale * static_cast<QgsMarkerSymbolV2*>( symbol )->size() );
}
else if ( tempSymbol->type() == QgsSymbolV2::Line )
{
QgsLineSymbolV2* lineSymbol = static_cast<QgsLineSymbolV2*>( tempSymbol );
if ( mSizeScaleFieldIdx != -1 )
lineSymbol->setWidth( sizeScale * static_cast<QgsLineSymbolV2*>( symbol )->width() );
}

return tempSymbol;
}

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

mRotationFieldIdx = ( mRotationField.isEmpty() ? -1 : vlayer->fieldNameIndex( mRotationField ) );
mSizeScaleFieldIdx = ( mSizeScaleField.isEmpty() ? -1 : vlayer->fieldNameIndex( mSizeScaleField ) );

QgsCategoryList::iterator it = mCategories.begin();
for ( ; it != mCategories.end(); ++it )
{
it->symbol()->startRender( context );

if ( mRotationFieldIdx != -1 || mSizeScaleFieldIdx != -1 )
{
QgsSymbolV2* tempSymbol = it->symbol()->clone();
tempSymbol->setRenderHints(( mRotationFieldIdx != -1 ? QgsSymbolV2::DataDefinedRotation : 0 ) |
( mSizeScaleFieldIdx != -1 ? QgsSymbolV2::DataDefinedSizeScale : 0 ) );
tempSymbol->startRender( context );
mTempSymbols[ it->value().toString()] = tempSymbol;
}
}

}

void QgsCategorizedSymbolRendererV2::stopRender( QgsRenderContext& context )
{
QgsCategoryList::iterator it = mCategories.begin();
for ( ; it != mCategories.end(); ++it )
it->symbol()->stopRender( context );

// cleanup mTempSymbols
QHash<QString, QgsSymbolV2*>::iterator it2 = mTempSymbols.begin();
for ( ; it2 != mTempSymbols.end(); ++it2 )
{
it2.value()->stopRender( context );
delete it2.value();
}
mTempSymbols.clear();
}

QList<QString> QgsCategorizedSymbolRendererV2::usedAttributes()
{
QList<QString> lst;
lst.append( mAttrName );
if ( !mRotationField.isEmpty() )
lst.append( mRotationField );
if ( !mSizeScaleField.isEmpty() )
lst.append( mSizeScaleField );
return lst;
}

Expand All @@ -241,6 +301,8 @@ QgsFeatureRendererV2* QgsCategorizedSymbolRendererV2::clone()
if ( mSourceColorRamp )
r->setSourceColorRamp( mSourceColorRamp->clone() );
r->setUsingSymbolLevels( usingSymbolLevels() );
r->setRotationField( rotationField() );
r->setSizeScaleField( sizeScaleField() );
return r;
}

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

QDomElement rotationElem = element.firstChildElement( "rotation" );
if ( !rotationElem.isNull() )
r->setRotationField( rotationElem.attribute( "field" ) );

QDomElement sizeScaleElem = element.firstChildElement( "sizescale" );
if ( !sizeScaleElem.isNull() )
r->setSizeScaleField( sizeScaleElem.attribute( "field" ) );

// TODO: symbol levels
return r;
}
Expand Down Expand Up @@ -360,6 +430,14 @@ QDomElement QgsCategorizedSymbolRendererV2::save( QDomDocument& doc )
rendererElem.appendChild( colorRampElem );
}

QDomElement rotationElem = doc.createElement( "rotation" );
rotationElem.setAttribute( "field", mRotationField );
rendererElem.appendChild( rotationElem );

QDomElement sizeScaleElem = doc.createElement( "sizescale" );
sizeScaleElem.setAttribute( "field", mSizeScaleField );
rendererElem.appendChild( sizeScaleElem );

return rendererElem;
}

Expand Down
16 changes: 16 additions & 0 deletions src/core/symbology-ng/qgscategorizedsymbolrendererv2.h
Expand Up @@ -96,18 +96,34 @@ class CORE_EXPORT QgsCategorizedSymbolRendererV2 : public QgsFeatureRendererV2
QgsVectorColorRampV2* sourceColorRamp();
void setSourceColorRamp( QgsVectorColorRampV2* ramp );

//! @note added in 1.6
void setRotationField( QString fieldName ) { mRotationField = fieldName; }
//! @note added in 1.6
QString rotationField() const { return mRotationField; }

//! @note added in 1.6
void setSizeScaleField( QString fieldName ) { mSizeScaleField = fieldName; }
//! @note added in 1.6
QString sizeScaleField() const { return mSizeScaleField; }

protected:
QString mAttrName;
QgsCategoryList mCategories;
QgsSymbolV2* mSourceSymbol;
QgsVectorColorRampV2* mSourceColorRamp;
QString mRotationField;
QString mSizeScaleField;

//! attribute index (derived from attribute name in startRender)
int mAttrNum;
int mRotationFieldIdx, mSizeScaleFieldIdx;

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

//! temporary symbols, used for data-defined rotation and scaling
QHash<QString, QgsSymbolV2*> mTempSymbols;

void rebuildHash();

QgsSymbolV2* symbolForValue( QVariant value );
Expand Down
78 changes: 77 additions & 1 deletion src/core/symbology-ng/qgsgraduatedsymbolrendererv2.cpp
Expand Up @@ -120,31 +120,89 @@ QgsSymbolV2* QgsGraduatedSymbolRendererV2::symbolForFeature( QgsFeature& feature
}

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


if ( mRotationFieldIdx == -1 && mSizeScaleFieldIdx == -1 )
return symbol; // no data-defined rotation/scaling - just return the symbol

// find out rotation, size scale
double rotation = 0;
double sizeScale = 1;
if ( mRotationFieldIdx != -1 )
rotation = attrMap[mRotationFieldIdx].toDouble();
if ( mSizeScaleFieldIdx != -1 )
sizeScale = attrMap[mSizeScaleFieldIdx].toDouble();

// take a temporary symbol (or create it if doesn't exist)
QgsSymbolV2* tempSymbol = mTempSymbols[symbol];

// modify the temporary symbol and return it
if ( tempSymbol->type() == QgsSymbolV2::Marker )
{
QgsMarkerSymbolV2* markerSymbol = static_cast<QgsMarkerSymbolV2*>( tempSymbol );
if ( mRotationFieldIdx != -1 )
markerSymbol->setAngle( rotation );
if ( mSizeScaleFieldIdx != -1 )
markerSymbol->setSize( sizeScale * static_cast<QgsMarkerSymbolV2*>( symbol )->size() );
}
else if ( tempSymbol->type() == QgsSymbolV2::Line )
{
QgsLineSymbolV2* lineSymbol = static_cast<QgsLineSymbolV2*>( tempSymbol );
if ( mSizeScaleFieldIdx != -1 )
lineSymbol->setWidth( sizeScale * static_cast<QgsLineSymbolV2*>( symbol )->width() );
}
return tempSymbol;
}

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

mRotationFieldIdx = ( mRotationField.isEmpty() ? -1 : vlayer->fieldNameIndex( mRotationField ) );
mSizeScaleFieldIdx = ( mSizeScaleField.isEmpty() ? -1 : vlayer->fieldNameIndex( mSizeScaleField ) );

QgsRangeList::iterator it = mRanges.begin();
for ( ; it != mRanges.end(); ++it )
{
it->symbol()->startRender( context );

if ( mRotationFieldIdx != -1 || mSizeScaleFieldIdx != -1 )
{
QgsSymbolV2* tempSymbol = it->symbol()->clone();
tempSymbol->setRenderHints(( mRotationFieldIdx != -1 ? QgsSymbolV2::DataDefinedRotation : 0 ) |
( mSizeScaleFieldIdx != -1 ? QgsSymbolV2::DataDefinedSizeScale : 0 ) );
tempSymbol->startRender( context );
mTempSymbols[ it->symbol()] = tempSymbol;
}
}
}

void QgsGraduatedSymbolRendererV2::stopRender( QgsRenderContext& context )
{
QgsRangeList::iterator it = mRanges.begin();
for ( ; it != mRanges.end(); ++it )
it->symbol()->startRender( context );

// cleanup mTempSymbols
QHash<QgsSymbolV2*, QgsSymbolV2*>::iterator it2 = mTempSymbols.begin();
for ( ; it2 != mTempSymbols.end(); ++it2 )
{
it2.value()->stopRender( context );
delete it2.value();
}
mTempSymbols.clear();
}

QList<QString> QgsGraduatedSymbolRendererV2::usedAttributes()
{
QList<QString> lst;
lst.append( mAttrName );
if ( !mRotationField.isEmpty() )
lst.append( mRotationField );
if ( !mSizeScaleField.isEmpty() )
lst.append( mSizeScaleField );
return lst;
}

Expand Down Expand Up @@ -196,6 +254,8 @@ QgsFeatureRendererV2* QgsGraduatedSymbolRendererV2::clone()
if ( mSourceColorRamp )
r->setSourceColorRamp( mSourceColorRamp->clone() );
r->setUsingSymbolLevels( usingSymbolLevels() );
r->setRotationField( rotationField() );
r->setSizeScaleField( sizeScaleField() );
return r;
}

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

QDomElement rotationElem = element.firstChildElement( "rotation" );
if ( !rotationElem.isNull() )
r->setRotationField( rotationElem.attribute( "field" ) );

QDomElement sizeScaleElem = element.firstChildElement( "sizescale" );
if ( !sizeScaleElem.isNull() )
r->setSizeScaleField( sizeScaleElem.attribute( "field" ) );

// TODO: symbol levels
return r;
}
Expand Down Expand Up @@ -458,6 +526,14 @@ QDomElement QgsGraduatedSymbolRendererV2::save( QDomDocument& doc )
rendererElem.appendChild( modeElem );
}

QDomElement rotationElem = doc.createElement( "rotation" );
rotationElem.setAttribute( "field", mRotationField );
rendererElem.appendChild( rotationElem );

QDomElement sizeScaleElem = doc.createElement( "sizescale" );
sizeScaleElem.setAttribute( "field", mSizeScaleField );
rendererElem.appendChild( sizeScaleElem );

return rendererElem;
}

Expand Down
16 changes: 16 additions & 0 deletions src/core/symbology-ng/qgsgraduatedsymbolrendererv2.h
Expand Up @@ -107,15 +107,31 @@ class CORE_EXPORT QgsGraduatedSymbolRendererV2 : public QgsFeatureRendererV2
QgsVectorColorRampV2* sourceColorRamp();
void setSourceColorRamp( QgsVectorColorRampV2* ramp );

//! @note added in 1.6
void setRotationField( QString fieldName ) { mRotationField = fieldName; }
//! @note added in 1.6
QString rotationField() const { return mRotationField; }

//! @note added in 1.6
void setSizeScaleField( QString fieldName ) { mSizeScaleField = fieldName; }
//! @note added in 1.6
QString sizeScaleField() const { return mSizeScaleField; }

protected:
QString mAttrName;
QgsRangeList mRanges;
Mode mMode;
QgsSymbolV2* mSourceSymbol;
QgsVectorColorRampV2* mSourceColorRamp;
QString mRotationField;
QString mSizeScaleField;

//! attribute index (derived from attribute name in startRender)
int mAttrNum;
int mRotationFieldIdx, mSizeScaleFieldIdx;

//! temporary symbols, used for data-defined rotation and scaling
QHash<QgsSymbolV2*, QgsSymbolV2*> mTempSymbols;

QgsSymbolV2* symbolForValue( double value );
};
Expand Down
1 change: 1 addition & 0 deletions src/gui/CMakeLists.txt
Expand Up @@ -65,6 +65,7 @@ symbology-ng/qgssinglesymbolrendererv2widget.h
symbology-ng/qgscategorizedsymbolrendererv2widget.h
symbology-ng/qgsgraduatedsymbolrendererv2widget.h
symbology-ng/qgsrulebasedrendererv2widget.h
symbology-ng/qgsrendererv2widget.h
symbology-ng/qgsrendererv2propertiesdialog.h
symbology-ng/qgsstylev2managerdialog.h
symbology-ng/qgssymbollevelsv2dialog.h
Expand Down

0 comments on commit a96d3d7

Please sign in to comment.