Skip to content

Commit

Permalink
Add support for more data definable properties to diagrams:
Browse files Browse the repository at this point in the history
- Distance
- Priority
- ZIndex
- IsObstacle
- Show
- AlwaysShow
- Diagram Start Angle
  • Loading branch information
nyalldawson committed Jan 23, 2017
1 parent 07315bf commit 336b603
Show file tree
Hide file tree
Showing 16 changed files with 300 additions and 4 deletions.
7 changes: 7 additions & 0 deletions python/core/qgsdiagramrenderer.sip
Expand Up @@ -44,6 +44,13 @@ class QgsDiagramLayerSettings
OutlineWidth, /*!< Outline width */
PositionX, /*! x-coordinate data defined diagram position */
PositionY, /*! y-coordinate data defined diagram position */
Distance, /*! Distance to diagram from feature */
Priority, /*! Diagram priority (between 0 and 10) */
ZIndex, /*! Z-index for diagram ordering */
IsObstacle, /*! Whether diagram features act as obstacles for other diagrams/labels */
Show, /*! Whether to show the diagram */
AlwaysShow, /*! Whether the diagram should always be shown, even if it overlaps other diagrams/labels */
StartAngle, /*! Angle offset for pie diagram */
};

QgsDiagramLayerSettings();
Expand Down
9 changes: 9 additions & 0 deletions src/core/qgsdiagramrenderer.cpp
Expand Up @@ -145,6 +145,13 @@ void QgsDiagramLayerSettings::init()
sPropertyNameMap.insert( OutlineWidth, "outlineWidth" );
sPropertyNameMap.insert( PositionX, "positionX" );
sPropertyNameMap.insert( PositionY, "positionY" );
sPropertyNameMap.insert( Distance, "distance" );
sPropertyNameMap.insert( Priority, "priority" );
sPropertyNameMap.insert( ZIndex, "zIndex" );
sPropertyNameMap.insert( IsObstacle, "isObstacle" );
sPropertyNameMap.insert( Show, "show" );
sPropertyNameMap.insert( AlwaysShow, "alwaysShow" );
sPropertyNameMap.insert( StartAngle, "startAngle" );
}
}

Expand Down Expand Up @@ -450,6 +457,8 @@ void QgsDiagramRenderer::renderDiagram( const QgsFeature& feature, QgsRenderCont
s.penColor = properties.valueAsColor( QgsDiagramLayerSettings::OutlineColor, c.expressionContext(), s.penColor );
c.expressionContext().setOriginalValueVariable( s.penWidth );
s.penWidth = properties.valueAsDouble( QgsDiagramLayerSettings::OutlineWidth, c.expressionContext(), s.penWidth );
c.expressionContext().setOriginalValueVariable( s.angleOffset / 16.0 );
s.angleOffset = 16.0 * properties.valueAsDouble( QgsDiagramLayerSettings::StartAngle, c.expressionContext(), s.angleOffset / 16.0 );
}

mDiagram->renderDiagram( feature, c, s, pos );
Expand Down
7 changes: 7 additions & 0 deletions src/core/qgsdiagramrenderer.h
Expand Up @@ -85,6 +85,13 @@ class CORE_EXPORT QgsDiagramLayerSettings
OutlineWidth, //!< Outline width
PositionX, //! x-coordinate data defined diagram position
PositionY, //! y-coordinate data defined diagram position
Distance, //! Distance to diagram from feature
Priority, //! Diagram priority (between 0 and 10)
ZIndex, //! Z-index for diagram ordering
IsObstacle, //! Whether diagram features act as obstacles for other diagrams/labels
Show, //! Whether to show the diagram
AlwaysShow, //! Whether the diagram should always be shown, even if it overlaps other diagrams/labels
StartAngle, //! Angle offset for pie diagram
};

QgsDiagramLayerSettings();
Expand Down
64 changes: 60 additions & 4 deletions src/core/qgsvectorlayerdiagramprovider.cpp
Expand Up @@ -217,6 +217,23 @@ QgsLabelFeature* QgsVectorLayerDiagramProvider::registerDiagram( QgsFeature& fea
}
}

// data defined show diagram? check this before doing any other processing
if ( mSettings.properties().hasProperty( QgsDiagramLayerSettings::Show )
&& mSettings.properties().property( QgsDiagramLayerSettings::Show )->isActive() )
{
bool show = mSettings.properties().valueAsInt( QgsDiagramLayerSettings::Show, context.expressionContext(), true );
if ( !show )
return nullptr;
}

// data defined obstacle?
bool isObstacle = mSettings.isObstacle();
if ( mSettings.properties().hasProperty( QgsDiagramLayerSettings::IsObstacle )
&& mSettings.properties().property( QgsDiagramLayerSettings::IsObstacle )->isActive() )
{
isObstacle = mSettings.properties().valueAsInt( QgsDiagramLayerSettings::IsObstacle, context.expressionContext(), isObstacle );
}

//convert geom to geos
QgsGeometry geom = feat.geometry();
QgsGeometry extentGeom = QgsGeometry::fromRect( mapSettings.visibleExtent() );
Expand Down Expand Up @@ -246,7 +263,7 @@ QgsLabelFeature* QgsVectorLayerDiagramProvider::registerDiagram( QgsFeature& fea

GEOSGeometry* geosObstacleGeomClone = nullptr;
QScopedPointer<QgsGeometry> scopedObstacleGeom;
if ( mSettings.isObstacle() && obstacleGeometry && QgsPalLabeling::geometryRequiresPreparation( *obstacleGeometry, context, mSettings.coordinateTransform(), &extentGeom ) )
if ( isObstacle && obstacleGeometry && QgsPalLabeling::geometryRequiresPreparation( *obstacleGeometry, context, mSettings.coordinateTransform(), &extentGeom ) )
{
QgsGeometry preparedObstacleGeom = QgsPalLabeling::prepareGeometry( *obstacleGeometry, context, mSettings.coordinateTransform(), &extentGeom );
geosObstacleGeomClone = preparedObstacleGeom.exportToGeos();
Expand All @@ -270,7 +287,14 @@ QgsLabelFeature* QgsVectorLayerDiagramProvider::registerDiagram( QgsFeature& fea

// feature to the layer
bool alwaysShow = mSettings.showAllDiagrams();
if ( mSettings.properties().hasProperty( QgsDiagramLayerSettings::AlwaysShow )
&& mSettings.properties().property( QgsDiagramLayerSettings::AlwaysShow )->isActive() )
{
context.expressionContext().setOriginalValueVariable( alwaysShow );
alwaysShow = mSettings.properties().valueAsInt( QgsDiagramLayerSettings::AlwaysShow, context.expressionContext(), alwaysShow );
}

// old style show
int ddColShow = mSettings.showColumn;
if ( ddColShow >= 0 && ! feat.attribute( ddColShow ).isNull() )
{
Expand Down Expand Up @@ -330,8 +354,7 @@ QgsLabelFeature* QgsVectorLayerDiagramProvider::registerDiagram( QgsFeature& fea
lf->setHasFixedAngle( true );
lf->setFixedAngle( 0 );
lf->setAlwaysShow( alwaysShow );
lf->setIsObstacle( mSettings.isObstacle() );
lf->setZIndex( mSettings.zIndex() );
lf->setIsObstacle( isObstacle );
if ( geosObstacleGeomClone )
{
lf->setObstacleGeometry( geosObstacleGeomClone );
Expand All @@ -343,8 +366,41 @@ QgsLabelFeature* QgsVectorLayerDiagramProvider::registerDiagram( QgsFeature& fea
lf->setAttributes( feat.attributes() );
}

// data defined priority?
if ( mSettings.properties().hasProperty( QgsDiagramLayerSettings::Priority )
&& mSettings.properties().property( QgsDiagramLayerSettings::Priority )->isActive() )
{
context.expressionContext().setOriginalValueVariable( mSettings.priority() );
double priorityD = mSettings.properties().valueAsDouble( QgsDiagramLayerSettings::Priority, context.expressionContext(), mSettings.getPriority() );
priorityD = qBound( 0.0, priorityD, 10.0 );
priorityD = 1 - priorityD / 10.0; // convert 0..10 --> 1..0
lf->setPriority( priorityD );
}

// z-Index
double zIndex = mSettings.zIndex();
if ( mSettings.properties().hasProperty( QgsDiagramLayerSettings::ZIndex )
&& mSettings.properties().property( QgsDiagramLayerSettings::ZIndex )->isActive() )
{
context.expressionContext().setOriginalValueVariable( zIndex );
zIndex = mSettings.properties().valueAsDouble( QgsDiagramLayerSettings::ZIndex, context.expressionContext(), zIndex );
}
lf->setZIndex( zIndex );

// label distance
QgsPoint ptZero = mapSettings.mapToPixel().toMapCoordinates( 0, 0 );
QgsPoint ptOne = mapSettings.mapToPixel().toMapCoordinates( 1, 0 );
lf->setDistLabel( ptOne.distance( ptZero ) * mSettings.distance() );
double dist = mSettings.distance();

if ( mSettings.properties().hasProperty( QgsDiagramLayerSettings::Distance )
&& mSettings.properties().property( QgsDiagramLayerSettings::Distance )->isActive() )
{
context.expressionContext().setOriginalValueVariable( dist );
dist = mSettings.properties().valueAsDouble( QgsDiagramLayerSettings::Distance, context.expressionContext(), dist );
}

dist *= ptOne.distance( ptZero );

lf->setDistLabel( dist );
return lf;
}
217 changes: 217 additions & 0 deletions tests/src/core/testqgsdiagram.cpp
Expand Up @@ -288,6 +288,223 @@ class TestQgsDiagram : public QObject
QVERIFY( imageCheck( "piediagram_datadefined_outline" ) );
}

void testDataDefinedStartAngle()
{
QgsDiagramSettings ds;
QColor col1 = Qt::red;
QColor col2 = Qt::yellow;
col1.setAlphaF( 0.5 );
col2.setAlphaF( 0.5 );
ds.categoryColors = QList<QColor>() << col1 << col2;
ds.categoryAttributes = QList<QString>() << "\"Pilots\"" << "\"Cabin Crew\"";
ds.maxScaleDenominator = -1;
ds.minScaleDenominator = -1;
ds.minimumSize = 0;
ds.penColor = Qt::green;
ds.penWidth = .5;
ds.scaleByArea = true;
ds.sizeType = QgsUnitTypes::RenderMillimeters;
ds.size = QSizeF( 15, 15 );
ds.angleOffset = 0;

QgsSingleCategoryDiagramRenderer *dr = new QgsSingleCategoryDiagramRenderer();
dr->setDiagram( new QgsPieDiagram() );
dr->setDiagramSettings( ds );
mPointsLayer->setDiagramRenderer( dr );

QgsDiagramLayerSettings dls = QgsDiagramLayerSettings();
dls.setPlacement( QgsDiagramLayerSettings::OverPoint );
dls.setShowAllDiagrams( true );

//setup data defined start angle
dls.properties().setProperty( QgsDiagramLayerSettings::StartAngle, new QgsExpressionBasedProperty( "\"Importance\"/20.0 * 360.0", true ) );

mPointsLayer->setDiagramLayerSettings( dls );

QVERIFY( imageCheck( "piediagram_datadefined_startangle" ) );
}

void testDataDefinedDistance()
{
QgsDiagramSettings ds;
QColor col1 = Qt::red;
QColor col2 = Qt::yellow;
col1.setAlphaF( 0.5 );
col2.setAlphaF( 0.5 );
ds.categoryColors = QList<QColor>() << col1 << col2;
ds.categoryAttributes = QList<QString>() << "\"Pilots\"" << "\"Cabin Crew\"";
ds.maxScaleDenominator = -1;
ds.minScaleDenominator = -1;
ds.minimumSize = 0;
ds.penColor = Qt::green;
ds.penWidth = .5;
ds.scaleByArea = true;
ds.sizeType = QgsUnitTypes::RenderMillimeters;
ds.size = QSizeF( 15, 15 );
ds.angleOffset = 0;

QgsSingleCategoryDiagramRenderer *dr = new QgsSingleCategoryDiagramRenderer();
dr->setDiagram( new QgsPieDiagram() );
dr->setDiagramSettings( ds );
mPointsLayer->setDiagramRenderer( dr );

QgsDiagramLayerSettings dls = QgsDiagramLayerSettings();
dls.setPlacement( QgsDiagramLayerSettings::AroundPoint );
dls.setShowAllDiagrams( true );

//setup data defined distance
dls.properties().setProperty( QgsDiagramLayerSettings::Distance, new QgsExpressionBasedProperty( "\"Staff\"*2", true ) );

mPointsLayer->setDiagramLayerSettings( dls );

QVERIFY( imageCheck( "piediagram_datadefined_distance" ) );
}

void testDataDefinedShow()
{
QgsDiagramSettings ds;
QColor col1 = Qt::red;
QColor col2 = Qt::yellow;
col1.setAlphaF( 0.5 );
col2.setAlphaF( 0.5 );
ds.categoryColors = QList<QColor>() << col1 << col2;
ds.categoryAttributes = QList<QString>() << "\"Pilots\"" << "\"Cabin Crew\"";
ds.maxScaleDenominator = -1;
ds.minScaleDenominator = -1;
ds.minimumSize = 0;
ds.penColor = Qt::green;
ds.penWidth = .5;
ds.scaleByArea = true;
ds.sizeType = QgsUnitTypes::RenderMillimeters;
ds.size = QSizeF( 15, 15 );
ds.angleOffset = 0;

QgsSingleCategoryDiagramRenderer *dr = new QgsSingleCategoryDiagramRenderer();
dr->setDiagram( new QgsPieDiagram() );
dr->setDiagramSettings( ds );
mPointsLayer->setDiagramRenderer( dr );

QgsDiagramLayerSettings dls = QgsDiagramLayerSettings();
dls.setPlacement( QgsDiagramLayerSettings::OverPoint );
dls.setShowAllDiagrams( true );

//setup data defined show
dls.properties().setProperty( QgsDiagramLayerSettings::Show, new QgsExpressionBasedProperty( "\"Pilots\"=1", true ) );

mPointsLayer->setDiagramLayerSettings( dls );

QVERIFY( imageCheck( "piediagram_datadefined_show" ) );
}

void testDataDefinedPriority()
{
QgsDiagramSettings ds;
QColor col1 = Qt::red;
QColor col2 = Qt::yellow;
col1.setAlphaF( 0.5 );
col2.setAlphaF( 0.5 );
ds.categoryColors = QList<QColor>() << col1 << col2;
ds.categoryAttributes = QList<QString>() << "\"Pilots\"" << "\"Cabin Crew\"";
ds.maxScaleDenominator = -1;
ds.minScaleDenominator = -1;
ds.minimumSize = 0;
ds.penColor = Qt::green;
ds.penWidth = .5;
ds.scaleByArea = true;
ds.sizeType = QgsUnitTypes::RenderMillimeters;
ds.size = QSizeF( 50, 50 );
ds.angleOffset = 0;

QgsSingleCategoryDiagramRenderer *dr = new QgsSingleCategoryDiagramRenderer();
dr->setDiagram( new QgsPieDiagram() );
dr->setDiagramSettings( ds );
mPointsLayer->setDiagramRenderer( dr );

QgsDiagramLayerSettings dls = QgsDiagramLayerSettings();
dls.setPlacement( QgsDiagramLayerSettings::OverPoint );
dls.setShowAllDiagrams( false );

//setup data defined priority
dls.properties().setProperty( QgsDiagramLayerSettings::Priority, new QgsExpressionBasedProperty( "\"importance\"/2", true ) );

mPointsLayer->setDiagramLayerSettings( dls );

QVERIFY( imageCheck( "piediagram_datadefined_priority" ) );
}

void testDataDefinedZIndex()
{
QgsDiagramSettings ds;
QColor col1 = Qt::red;
QColor col2 = Qt::yellow;
ds.categoryColors = QList<QColor>() << col1 << col2;
ds.categoryAttributes = QList<QString>() << "\"Pilots\"" << "\"Cabin Crew\"";
ds.maxScaleDenominator = -1;
ds.minScaleDenominator = -1;
ds.minimumSize = 0;
ds.penColor = Qt::green;
ds.penWidth = .5;
ds.scaleByArea = true;
ds.sizeType = QgsUnitTypes::RenderMillimeters;
ds.size = QSizeF( 50, 50 );
ds.angleOffset = 0;

QgsSingleCategoryDiagramRenderer *dr = new QgsSingleCategoryDiagramRenderer();
dr->setDiagram( new QgsPieDiagram() );
dr->setDiagramSettings( ds );
mPointsLayer->setDiagramRenderer( dr );

QgsDiagramLayerSettings dls = QgsDiagramLayerSettings();
dls.setPlacement( QgsDiagramLayerSettings::OverPoint );
dls.setShowAllDiagrams( true );

//setup data defined z index
dls.properties().setProperty( QgsDiagramLayerSettings::ZIndex, new QgsExpressionBasedProperty( "\"importance\"/2", true ) );

mPointsLayer->setDiagramLayerSettings( dls );

QVERIFY( imageCheck( "piediagram_datadefined_zindex" ) );
}

void testDataDefinedAlwaysShow()
{
QgsDiagramSettings ds;
QColor col1 = Qt::red;
QColor col2 = Qt::yellow;
col1.setAlphaF( 0.5 );
col2.setAlphaF( 0.5 );
ds.categoryColors = QList<QColor>() << col1 << col2;
ds.categoryAttributes = QList<QString>() << "\"Pilots\"" << "\"Cabin Crew\"";
ds.maxScaleDenominator = -1;
ds.minScaleDenominator = -1;
ds.minimumSize = 0;
ds.penColor = Qt::green;
ds.penWidth = .5;
ds.scaleByArea = true;
ds.sizeType = QgsUnitTypes::RenderMillimeters;
ds.size = QSizeF( 50, 50 );
ds.angleOffset = 0;

QgsSingleCategoryDiagramRenderer *dr = new QgsSingleCategoryDiagramRenderer();
dr->setDiagram( new QgsPieDiagram() );
dr->setDiagramSettings( ds );
mPointsLayer->setDiagramRenderer( dr );

QgsDiagramLayerSettings dls = QgsDiagramLayerSettings();
dls.setPlacement( QgsDiagramLayerSettings::OverPoint );
dls.setShowAllDiagrams( false );

//setup data defined priority (required to only show certain diagrams)
dls.properties().setProperty( QgsDiagramLayerSettings::Priority, new QgsExpressionBasedProperty( "\"importance\"/2", true ) );
//setup data defined "always show"
dls.properties().setProperty( QgsDiagramLayerSettings::AlwaysShow, new QgsExpressionBasedProperty( "\"Staff\">=6", true ) );


mPointsLayer->setDiagramLayerSettings( dls );

QVERIFY( imageCheck( "piediagram_datadefined_alwaysshow" ) );
}


void testDataDefinedBackgroundColor()
{
Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 336b603

Please sign in to comment.