[QGIS Commit] r13389 - in trunk/qgis: python/core
src/core/symbology-ng src/gui/symbology-ng src/ui
svn_qgis at osgeo.org
svn_qgis at osgeo.org
Sun Apr 25 18:32:53 EDT 2010
Author: wonder
Date: 2010-04-25 18:32:53 -0400 (Sun, 25 Apr 2010)
New Revision: 13389
Modified:
trunk/qgis/python/core/symbology-ng-core.sip
trunk/qgis/src/core/symbology-ng/qgsmarkersymbollayerv2.cpp
trunk/qgis/src/core/symbology-ng/qgsmarkersymbollayerv2.h
trunk/qgis/src/core/symbology-ng/qgssinglesymbolrendererv2.cpp
trunk/qgis/src/core/symbology-ng/qgssinglesymbolrendererv2.h
trunk/qgis/src/core/symbology-ng/qgssymbolv2.cpp
trunk/qgis/src/core/symbology-ng/qgssymbolv2.h
trunk/qgis/src/gui/symbology-ng/qgssinglesymbolrendererv2widget.cpp
trunk/qgis/src/gui/symbology-ng/qgssinglesymbolrendererv2widget.h
trunk/qgis/src/gui/symbology-ng/qgssymbolv2selectordialog.cpp
trunk/qgis/src/gui/symbology-ng/qgssymbolv2selectordialog.h
trunk/qgis/src/ui/qgssymbolv2selectordialogbase.ui
Log:
[FEATURE] Data-defined size and rotation for single symbol renderer in symbology-ng. (ticket #2585)
Developed by 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)
Modified: trunk/qgis/python/core/symbology-ng-core.sip
===================================================================
--- trunk/qgis/python/core/symbology-ng-core.sip 2010-04-25 22:12:05 UTC (rev 13388)
+++ trunk/qgis/python/core/symbology-ng-core.sip 2010-04-25 22:32:53 UTC (rev 13389)
@@ -133,6 +133,12 @@
QgsSymbolV2* symbol() const;
void setSymbol(QgsSymbolV2* s /Transfer/);
+ void setRotationField(QString fieldName);
+ QString rotationField() const;
+
+ void setSizeScaleField(QString fieldName);
+ QString sizeScaleField() const;
+
virtual QString dump();
virtual QgsFeatureRendererV2* clone() /Factory/;
@@ -453,7 +459,7 @@
%End
public:
- QgsSymbolV2RenderContext( QgsRenderContext& c, QgsSymbolV2::OutputUnit u , qreal alpha = 1.0, bool selected = false );
+ QgsSymbolV2RenderContext( QgsRenderContext& c, QgsSymbolV2::OutputUnit u , qreal alpha = 1.0, bool selected = false, int renderHints = 0 );
~QgsSymbolV2RenderContext();
QgsRenderContext& renderContext();
@@ -468,6 +474,11 @@
bool selected() const;
void setSelected( bool selected ) const;
+ int renderHints() const;
+ void setRenderHints( int hints );
+
+ // Colour used for selections
+
static QColor selectionColor();
double outputLineWidth(double width) const;
@@ -510,6 +521,12 @@
Fill
};
+ enum RenderHint
+ {
+ DataDefinedSizeScale = 1,
+ DataDefinedRotation = 2
+ };
+
virtual ~QgsSymbolV2();
//! return new default symbol for specified geometry type
@@ -556,6 +573,12 @@
OutputUnit outputUnit() const;
void setOutputUnit( OutputUnit u );
+ qreal alpha() const;
+ void setAlpha( qreal alpha );
+
+ int renderHints() const;
+ void setRenderHints( int hints );
+
protected:
QgsSymbolV2(SymbolType type, QgsSymbolLayerV2List layers /Transfer/); // can't be instantiated
Modified: trunk/qgis/src/core/symbology-ng/qgsmarkersymbollayerv2.cpp
===================================================================
--- trunk/qgis/src/core/symbology-ng/qgsmarkersymbollayerv2.cpp 2010-04-25 22:12:05 UTC (rev 13388)
+++ trunk/qgis/src/core/symbology-ng/qgsmarkersymbollayerv2.cpp 2010-04-25 22:32:53 UTC (rev 13389)
@@ -68,102 +68,72 @@
mBrush = QBrush( mColor );
mPen = QPen( mBorderColor );
mPen.setWidthF( context.outputLineWidth( mPen.widthF() ) );
+
QColor selColor = context.selectionColor();
mSelBrush = QBrush( selColor );
mSelPen = QPen( selColor == mColor ? selColor : mBorderColor );
mSelPen.setWidthF( mPen.widthF() );
- mPolygon.clear();
+ bool hasDataDefinedRotation = context.renderHints() & QgsSymbolV2::DataDefinedRotation;
+ bool hasDataDefinedSize = context.renderHints() & QgsSymbolV2::DataDefinedSizeScale;
- double scaledSize = context.outputPixelSize( mSize );
- double half = scaledSize / 2.0;
+ // use either QPolygonF or QPainterPath for drawing
+ // TODO: find out whether drawing directly doesn't bring overhead - if not, use it for all shapes
+ if ( !prepareShape() ) // drawing as a polygon
+ {
+ if ( preparePath() ) // drawing as a painter path
+ {
+ // some markers can't be drawn as a polygon (circle, cross)
+ // For these set the selected border color to the selected color
- if ( mName == "rectangle" )
- {
- mPolygon = QPolygonF( QRectF( QPointF( -half, -half ), QPointF( half, half ) ) );
+ if ( mName != "circle" )
+ mSelPen.setColor( selColor );
+ }
+ else
+ {
+ QgsDebugMsg( "unknown symbol" );
+ return;
+ }
}
- else if ( mName == "diamond" )
+
+ QMatrix transform;
+
+ // scale the shape (if the size is not going to be modified)
+ if ( !hasDataDefinedSize )
{
- mPolygon << QPointF( -half, 0 ) << QPointF( 0, half )
- << QPointF( half, 0 ) << QPointF( 0, -half );
+ double scaledSize = context.outputPixelSize( mSize );
+ double half = scaledSize / 2.0;
+ transform.scale( half, half );
}
- else if ( mName == "pentagon" )
+
+ // rotate if the rotation is not going to be changed during the rendering
+ if ( !hasDataDefinedRotation && mAngle != 0 )
{
- mPolygon << QPointF( half * sin( DEG2RAD( 288.0 ) ), - half * cos( DEG2RAD( 288.0 ) ) )
- << QPointF( half * sin( DEG2RAD( 216.0 ) ), - half * cos( DEG2RAD( 216.0 ) ) )
- << QPointF( half * sin( DEG2RAD( 144.0 ) ), - half * cos( DEG2RAD( 144.0 ) ) )
- << QPointF( half * sin( DEG2RAD( 72.0 ) ), - half * cos( DEG2RAD( 72.0 ) ) )
- << QPointF( 0, - half );
+ transform.rotate( mAngle );
}
- else if ( mName == "triangle" )
- {
- mPolygon << QPointF( -half, half ) << QPointF( half, half ) << QPointF( 0, -half );
- }
- else if ( mName == "equilateral_triangle" )
- {
- mPolygon << QPointF( half * sin( DEG2RAD( 240.0 ) ), - half * cos( DEG2RAD( 240.0 ) ) )
- << QPointF( half * sin( DEG2RAD( 120.0 ) ), - half * cos( DEG2RAD( 120.0 ) ) )
- << QPointF( 0, -half );
- }
- else if ( mName == "star" )
- {
- double sixth = half / 6;
- mPolygon << QPointF( 0, -half )
- << QPointF( -sixth, -sixth )
- << QPointF( -half, -sixth )
- << QPointF( -sixth, 0 )
- << QPointF( -half, half )
- << QPointF( 0, + sixth )
- << QPointF( half, half )
- << QPointF( + sixth, 0 )
- << QPointF( half, -sixth )
- << QPointF( + sixth, -sixth );
- }
- else if ( mName == "regular_star" )
- {
- double r = half;
- double inner_r = r * cos( DEG2RAD( 72.0 ) ) / cos( DEG2RAD( 36.0 ) );
+ if ( !mPolygon.isEmpty() )
+ mPolygon = transform.map( mPolygon );
+ else
+ mPath = transform.map( mPath );
- mPolygon << QPointF( inner_r * sin( DEG2RAD( 324.0 ) ), - inner_r * cos( DEG2RAD( 324.0 ) ) ) // 324
- << QPointF( r * sin( DEG2RAD( 288.0 ) ) , - r * cos( DEG2RAD( 288 ) ) ) // 288
- << QPointF( inner_r * sin( DEG2RAD( 252.0 ) ), - inner_r * cos( DEG2RAD( 252.0 ) ) ) // 252
- << QPointF( r * sin( DEG2RAD( 216.0 ) ) , - r * cos( DEG2RAD( 216.0 ) ) ) // 216
- << QPointF( 0, inner_r ) // 180
- << QPointF( r * sin( DEG2RAD( 144.0 ) ) , - r * cos( DEG2RAD( 144.0 ) ) ) // 144
- << QPointF( inner_r * sin( DEG2RAD( 108.0 ) ), - inner_r * cos( DEG2RAD( 108.0 ) ) ) // 108
- << QPointF( r * sin( DEG2RAD( 72.0 ) ) , - r * cos( DEG2RAD( 72.0 ) ) ) // 72
- << QPointF( inner_r * sin( DEG2RAD( 36.0 ) ), - inner_r * cos( DEG2RAD( 36.0 ) ) ) // 36
- << QPointF( 0, -half ); // 0
- }
- else if ( mName == "arrow" )
+ if ( !hasDataDefinedRotation && !hasDataDefinedSize )
{
- double eight = half / 4;
- double quarter = half / 2;
-
- mPolygon << QPointF( 0, -half )
- << QPointF( quarter, -quarter )
- << QPointF( eight, -quarter )
- << QPointF( eight, half )
- << QPointF( -eight, half )
- << QPointF( -eight, -quarter )
- << QPointF( -quarter, -quarter );
+ // we can use the cached marker
+ // TODO: use caching only when drawing to screen (not printer)
+ prepareCache( context );
}
else
{
- // some markers can't be drawn as a polygon (circle, cross)
- // For these set the selected border color to the selected color
-
- if ( mName != "circle" ) mSelPen.setColor( selColor );
+ mCache = QImage();
+ mSelCache = QImage();
}
+}
- // rotate if needed
- if ( mAngle != 0 )
- mPolygon = QMatrix().rotate( mAngle ).map( mPolygon );
- // cache the marker
- // TODO: use caching only when drawing to screen (not printer)
- // TODO: decide whether to use QImage or QPixmap - based on the render context
+void QgsSimpleMarkerSymbolLayerV2::prepareCache( QgsSymbolV2RenderContext& context )
+{
+ double scaledSize = context.outputPixelSize( mSize );
// calculate necessary image size for the cache
double pw = (( mPen.widthF() == 0 ? 1 : mPen.widthF() ) + 1 ) / 2 * 2; // make even (round up); handle cosmetic pen
@@ -185,6 +155,8 @@
// Construct the selected version of the Cache
+ QColor selColor = context.selectionColor();
+
mSelCache = QImage( QSize( imageSize, imageSize ), QImage::Format_ARGB32_Premultiplied );
mSelCache.fill( 0 );
@@ -224,6 +196,127 @@
{
}
+bool QgsSimpleMarkerSymbolLayerV2::prepareShape()
+{
+ mPolygon.clear();
+
+ if ( mName == "rectangle" )
+ {
+ mPolygon = QPolygonF( QRectF( QPointF( -1, -1 ), QPointF( 1, 1 ) ) );
+ return true;
+ }
+ else if ( mName == "diamond" )
+ {
+ mPolygon << QPointF( -1, 0 ) << QPointF( 0, 1 )
+ << QPointF( 1, 0 ) << QPointF( 0, -1 );
+ return true;
+ }
+ else if ( mName == "pentagon" )
+ {
+ mPolygon << QPointF( sin( DEG2RAD( 288.0 ) ), - cos( DEG2RAD( 288.0 ) ) )
+ << QPointF( sin( DEG2RAD( 216.0 ) ), - cos( DEG2RAD( 216.0 ) ) )
+ << QPointF( sin( DEG2RAD( 144.0 ) ), - cos( DEG2RAD( 144.0 ) ) )
+ << QPointF( sin( DEG2RAD( 72.0 ) ), - cos( DEG2RAD( 72.0 ) ) )
+ << QPointF( 0, -1 );
+ return true;
+ }
+ else if ( mName == "triangle" )
+ {
+ mPolygon << QPointF( -1, 1 ) << QPointF( 1, 1 ) << QPointF( 0, -1 );
+ return true;
+ }
+ else if ( mName == "equilateral_triangle" )
+ {
+ mPolygon << QPointF( sin( DEG2RAD( 240.0 ) ), - cos( DEG2RAD( 240.0 ) ) )
+ << QPointF( sin( DEG2RAD( 120.0 ) ), - cos( DEG2RAD( 120.0 ) ) )
+ << QPointF( 0, -1 );
+ return true;
+ }
+ else if ( mName == "star" )
+ {
+ double sixth = 1.0 / 3;
+
+ mPolygon << QPointF( 0, -1 )
+ << QPointF( -sixth, -sixth )
+ << QPointF( -1, -sixth )
+ << QPointF( -sixth, 0 )
+ << QPointF( -1, 1 )
+ << QPointF( 0, + sixth )
+ << QPointF( 1, 1 )
+ << QPointF( + sixth, 0 )
+ << QPointF( 1, -sixth )
+ << QPointF( + sixth, -sixth );
+ return true;
+ }
+ else if ( mName == "regular_star" )
+ {
+ double inner_r = cos( DEG2RAD( 72.0 ) ) / cos( DEG2RAD( 36.0 ) );
+
+ mPolygon << QPointF( inner_r * sin( DEG2RAD( 324.0 ) ), - inner_r * cos( DEG2RAD( 324.0 ) ) ) // 324
+ << QPointF( sin( DEG2RAD( 288.0 ) ) , - cos( DEG2RAD( 288 ) ) ) // 288
+ << QPointF( inner_r * sin( DEG2RAD( 252.0 ) ), - inner_r * cos( DEG2RAD( 252.0 ) ) ) // 252
+ << QPointF( sin( DEG2RAD( 216.0 ) ) , - cos( DEG2RAD( 216.0 ) ) ) // 216
+ << QPointF( 0, inner_r ) // 180
+ << QPointF( sin( DEG2RAD( 144.0 ) ) , - cos( DEG2RAD( 144.0 ) ) ) // 144
+ << QPointF( inner_r * sin( DEG2RAD( 108.0 ) ), - inner_r * cos( DEG2RAD( 108.0 ) ) ) // 108
+ << QPointF( sin( DEG2RAD( 72.0 ) ) , - cos( DEG2RAD( 72.0 ) ) ) // 72
+ << QPointF( inner_r * sin( DEG2RAD( 36.0 ) ), - inner_r * cos( DEG2RAD( 36.0 ) ) ) // 36
+ << QPointF( 0, -1 ); // 0
+ return true;
+ }
+ else if ( mName == "arrow" )
+ {
+ double eight = 1.0 / 4;
+ double quarter = 1.0 / 2;
+
+ mPolygon << QPointF( 0, -1 )
+ << QPointF( 0.5, -0.5 )
+ << QPointF( 0.25, -0.25 )
+ << QPointF( 0.25, 1 )
+ << QPointF( -0.25, 1 )
+ << QPointF( -0.25, -0.5 )
+ << QPointF( -0.5, -0.5 );
+ return true;
+ }
+
+ return false;
+}
+
+bool QgsSimpleMarkerSymbolLayerV2::preparePath()
+{
+ mPath = QPainterPath();
+
+ if ( mName == "circle" )
+ {
+ mPath.addEllipse( QRectF( -1, -1, 2, 2 ) ); // x,y,w,h
+ return true;
+ }
+ else if ( mName == "cross" )
+ {
+ mPath.moveTo( -1, 0 );
+ mPath.lineTo( 1, 0 ); // horizontal
+ mPath.moveTo( 0, -1 );
+ mPath.lineTo( 0, 1 ); // vertical
+ return true;
+ }
+ else if ( mName == "cross2" )
+ {
+ mPath.moveTo( -1, -1 );
+ mPath.lineTo( 1, 1 );
+ mPath.moveTo( 1, -1 );
+ mPath.lineTo( -1, 1 );
+ return true;
+ }
+ else if ( mName == "line" )
+ {
+ mPath.moveTo( 0, -1 );
+ mPath.lineTo( 0, 1 ); // vertical line
+ return true;
+ }
+
+ return false;
+}
+
void QgsSimpleMarkerSymbolLayerV2::renderPoint( const QPointF& point, QgsSymbolV2RenderContext& context )
{
QgsRenderContext& rc = context.renderContext();
@@ -233,11 +326,48 @@
return;
}
- QImage &img = context.selected() ? mSelCache : mCache;
- double s = img.width() / context.renderContext().rasterScaleFactor();
- p->drawImage( QRectF( point.x() - s / 2.0 + context.outputLineWidth( mOffset.x() ),
- point.y() - s / 2.0 + context.outputLineWidth( mOffset.y() ),
- s, s ), img );
+ bool hasDataDefinedRotation = context.renderHints() & QgsSymbolV2::DataDefinedRotation;
+ bool hasDataDefinedSize = context.renderHints() & QgsSymbolV2::DataDefinedSizeScale;
+
+ if ( !hasDataDefinedRotation && !hasDataDefinedSize )
+ {
+ // we will use cached image
+ QImage &img = context.selected() ? mSelCache : mCache;
+ double s = img.width() / context.renderContext().rasterScaleFactor();
+ p->drawImage( QRectF( point.x() - s / 2.0 + context.outputLineWidth( mOffset.x() ),
+ point.y() - s / 2.0 + context.outputLineWidth( mOffset.y() ),
+ s, s ), img );
+ }
+ else
+ {
+ QMatrix transform;
+
+ // move to the desired position
+ transform.translate( point.x() + context.outputLineWidth( mOffset.x() ),
+ point.y() + context.outputLineWidth( mOffset.y() ) );
+
+ // resize if necessary
+ if ( hasDataDefinedSize )
+ {
+ double scaledSize = context.outputPixelSize( mSize );
+ double half = scaledSize / 2.0;
+ transform.scale( half, half );
+ }
+
+ // rotate if necessary
+ if ( mAngle != 0 )
+ {
+ transform.rotate( mAngle );
+ }
+
+ p->setBrush( context.selected() ? mSelBrush : mBrush );
+ p->setPen( context.selected() ? mSelPen : mPen );
+
+ if ( !mPolygon.isEmpty() )
+ p->drawPolygon( transform.map( mPolygon ) );
+ else
+ p->drawPath( transform.map( mPath ) );
+ }
}
@@ -268,37 +398,8 @@
}
else
{
- double scaledSize = context.outputPixelSize( mSize );
- double half = scaledSize / 2.0;
- if ( mAngle != 0 )
- {
- p->save();
- p->rotate( mAngle );
- }
-
- if ( mName == "circle" )
- {
- p->drawEllipse( QRectF( -half, -half, half*2, half*2 ) ); // x,y,w,h
- }
- else if ( mName == "cross" )
- {
- p->drawLine( QPointF( -half, 0 ), QPointF( half, 0 ) ); // horizontal
- p->drawLine( QPointF( 0, -half ), QPointF( 0, half ) ); // vertical
- }
- else if ( mName == "cross2" )
- {
- p->drawLine( QPointF( -half, -half ), QPointF( half, half ) );
- p->drawLine( QPointF( -half, half ), QPointF( half, -half ) );
- }
- else if ( mName == "line" )
- {
- p->drawLine( QPointF( 0, -half ), QPointF( 0, half ) ); // vertical line
- }
-
- if ( mAngle != 0 )
- p->restore();
+ p->drawPath( mPath );
}
-
}
@@ -363,6 +464,8 @@
selPainter.setPen( Qt::NoPen );
selPainter.drawEllipse( QPointF( 0, 0 ), pictureSize*0.6, pictureSize*0.6 );
renderer.render( &selPainter, rect );
+
+ mOrigSize = mSize; // save in case the size would be data defined
}
void QgsSvgMarkerSymbolLayerV2::stopRender( QgsSymbolV2RenderContext& context )
@@ -382,15 +485,18 @@
QPointF outputOffset = QPointF( context.outputLineWidth( mOffset.x() ), context.outputLineWidth( mOffset.y() ) );
p->translate( point + outputOffset );
+ if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale )
+ {
+ double s = mSize / mOrigSize;
+ p->scale( s, s );
+ }
+
if ( mAngle != 0 )
p->rotate( mAngle );
QPicture &pct = context.selected() ? mSelPicture : mPicture;
p->drawPicture( 0, 0, pct );
- if ( mAngle != 0 )
- p->rotate( -mAngle );
-
p->restore();
}
@@ -555,7 +661,7 @@
QFontMetrics fm( mFont );
mChrOffset = QPointF( fm.width( mChr ) / 2, -fm.ascent() / 2 );
-
+ mOrigSize = mSize; // save in case the size would be data defined
}
void QgsFontMarkerSymbolLayerV2::stopRender( QgsSymbolV2RenderContext& context )
@@ -572,6 +678,13 @@
p->save();
p->translate( point );
+
+ if ( context.renderHints() & QgsSymbolV2::DataDefinedSizeScale )
+ {
+ double s = mSize / mOrigSize;
+ p->scale( s, s );
+ }
+
if ( mAngle != 0 )
p->rotate( mAngle );
Modified: trunk/qgis/src/core/symbology-ng/qgsmarkersymbollayerv2.h
===================================================================
--- trunk/qgis/src/core/symbology-ng/qgsmarkersymbollayerv2.h 2010-04-25 22:12:05 UTC (rev 13388)
+++ trunk/qgis/src/core/symbology-ng/qgsmarkersymbollayerv2.h 2010-04-25 22:32:53 UTC (rev 13389)
@@ -53,10 +53,16 @@
void drawMarker( QPainter* p, QgsSymbolV2RenderContext& context );
+ bool prepareShape();
+ bool preparePath();
+
+ void prepareCache( QgsSymbolV2RenderContext& context );
+
QColor mBorderColor;
QPen mPen;
QBrush mBrush;
QPolygonF mPolygon;
+ QPainterPath mPath;
QString mName;
QImage mCache;
QPen mSelPen;
@@ -114,6 +120,7 @@
QString mPath;
QPicture mPicture;
QPicture mSelPicture;
+ double mOrigSize;
};
@@ -170,6 +177,7 @@
QPointF mChrOffset;
QFont mFont;
+ double mOrigSize;
};
Modified: trunk/qgis/src/core/symbology-ng/qgssinglesymbolrendererv2.cpp
===================================================================
--- trunk/qgis/src/core/symbology-ng/qgssinglesymbolrendererv2.cpp 2010-04-25 22:12:05 UTC (rev 13388)
+++ trunk/qgis/src/core/symbology-ng/qgssinglesymbolrendererv2.cpp 2010-04-25 22:32:53 UTC (rev 13389)
@@ -4,11 +4,16 @@
#include "qgssymbolv2.h"
#include "qgssymbollayerv2utils.h"
+#include "qgslogger.h"
+#include "qgsfeature.h"
+#include "qgsvectorlayer.h"
+
#include <QDomDocument>
#include <QDomElement>
QgsSingleSymbolRendererV2::QgsSingleSymbolRendererV2( QgsSymbolV2* symbol )
- : QgsFeatureRendererV2( "singleSymbol" )
+ : QgsFeatureRendererV2( "singleSymbol" ),
+ mTempSymbol( NULL )
{
mSymbol = symbol;
}
@@ -20,22 +25,93 @@
QgsSymbolV2* QgsSingleSymbolRendererV2::symbolForFeature( QgsFeature& feature )
{
- return mSymbol;
+ if ( mRotationFieldIdx == -1 && mSizeScaleFieldIdx == -1 )
+ return mSymbol;
+
+ double rotation = 0;
+ double sizeScale = 1;
+ if ( mRotationFieldIdx != -1 )
+ {
+ rotation = feature.attributeMap()[mRotationFieldIdx].toDouble();
+ }
+ if ( mSizeScaleFieldIdx != -1 )
+ {
+ sizeScale = feature.attributeMap()[mSizeScaleFieldIdx].toDouble();
+ }
+
+ if ( mTempSymbol->type() == QgsSymbolV2::Marker )
+ {
+ QgsMarkerSymbolV2* markerSymbol = static_cast<QgsMarkerSymbolV2*>( mTempSymbol );
+ if ( mRotationFieldIdx != -1 )
+ markerSymbol->setAngle( rotation );
+ if ( mSizeScaleFieldIdx != -1 )
+ markerSymbol->setSize( sizeScale * mOrigSize );
+ }
+ else if ( mTempSymbol->type() == QgsSymbolV2::Line )
+ {
+ QgsLineSymbolV2* lineSymbol = static_cast<QgsLineSymbolV2*>( mTempSymbol );
+ if ( mSizeScaleFieldIdx != -1 )
+ lineSymbol->setWidth( sizeScale * mOrigSize );
+ }
+
+ return mTempSymbol;
}
void QgsSingleSymbolRendererV2::startRender( QgsRenderContext& context, const QgsVectorLayer *vlayer )
{
+ mRotationFieldIdx = ( mRotationField.isEmpty() ? -1 : vlayer->fieldNameIndex( mRotationField ) );
+ mSizeScaleFieldIdx = ( mSizeScaleField.isEmpty() ? -1 : vlayer->fieldNameIndex( mSizeScaleField ) );
+
mSymbol->startRender( context );
+
+ if ( mRotationFieldIdx != -1 || mSizeScaleFieldIdx != -1 )
+ {
+ // we are going to need a temporary symbol
+ mTempSymbol = mSymbol->clone();
+
+ int hints = 0;
+ if ( mRotationFieldIdx != -1 ) hints |= QgsSymbolV2::DataDefinedRotation;
+ if ( mSizeScaleFieldIdx != -1 ) hints |= QgsSymbolV2::DataDefinedSizeScale;
+ mTempSymbol->setRenderHints( hints );
+
+ mTempSymbol->startRender( context );
+
+ if ( mSymbol->type() == QgsSymbolV2::Marker )
+ {
+ mOrigSize = static_cast<QgsMarkerSymbolV2*>( mSymbol )->size();
+ }
+ else if ( mSymbol->type() == QgsSymbolV2::Line )
+ {
+ mOrigSize = static_cast<QgsLineSymbolV2*>( mSymbol )->width();
+ }
+ else
+ {
+ mOrigSize = 0;
+ }
+ }
}
void QgsSingleSymbolRendererV2::stopRender( QgsRenderContext& context )
{
mSymbol->stopRender( context );
+
+ if ( mRotationFieldIdx != -1 || mSizeScaleFieldIdx != -1 )
+ {
+ // we are going to need a temporary symbol
+ mTempSymbol->stopRender( context );
+ delete mTempSymbol;
+ mTempSymbol = NULL;
+ }
}
QList<QString> QgsSingleSymbolRendererV2::usedAttributes()
{
- return QList<QString>();
+ QList<QString> lst;
+ if ( !mRotationField.isEmpty() )
+ lst.append( mRotationField );
+ if ( !mSizeScaleField.isEmpty() )
+ lst.append( mSizeScaleField );
+ return lst;
}
QgsSymbolV2* QgsSingleSymbolRendererV2::symbol() const
@@ -58,6 +134,8 @@
{
QgsSingleSymbolRendererV2* r = new QgsSingleSymbolRendererV2( mSymbol->clone() );
r->setUsingSymbolLevels( usingSymbolLevels() );
+ r->setRotationField( rotationField() );
+ r->setSizeScaleField( sizeScaleField() );
return r;
}
@@ -84,6 +162,14 @@
// delete symbols if there are any more
QgsSymbolLayerV2Utils::clearSymbolMap( symbolMap );
+ 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;
}
@@ -99,6 +185,14 @@
QDomElement symbolsElem = QgsSymbolLayerV2Utils::saveSymbols( symbols, "symbols", doc );
rendererElem.appendChild( symbolsElem );
+ 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;
}
Modified: trunk/qgis/src/core/symbology-ng/qgssinglesymbolrendererv2.h
===================================================================
--- trunk/qgis/src/core/symbology-ng/qgssinglesymbolrendererv2.h 2010-04-25 22:12:05 UTC (rev 13388)
+++ trunk/qgis/src/core/symbology-ng/qgssinglesymbolrendererv2.h 2010-04-25 22:32:53 UTC (rev 13389)
@@ -22,6 +22,12 @@
QgsSymbolV2* symbol() const;
void setSymbol( QgsSymbolV2* s );
+ void setRotationField( QString fieldName ) { mRotationField = fieldName; }
+ QString rotationField() const { return mRotationField; }
+
+ void setSizeScaleField( QString fieldName ) { mSizeScaleField = fieldName; }
+ QString sizeScaleField() const { return mSizeScaleField; }
+
virtual QString dump();
virtual QgsFeatureRendererV2* clone();
@@ -43,6 +49,13 @@
protected:
QgsSymbolV2* mSymbol;
+ QString mRotationField;
+ QString mSizeScaleField;
+
+ // temporary stuff for rendering
+ int mRotationFieldIdx, mSizeScaleFieldIdx;
+ QgsSymbolV2* mTempSymbol;
+ double mOrigSize;
};
Modified: trunk/qgis/src/core/symbology-ng/qgssymbolv2.cpp
===================================================================
--- trunk/qgis/src/core/symbology-ng/qgssymbolv2.cpp 2010-04-25 22:12:05 UTC (rev 13388)
+++ trunk/qgis/src/core/symbology-ng/qgssymbolv2.cpp 2010-04-25 22:32:53 UTC (rev 13389)
@@ -18,7 +18,7 @@
#include <cmath>
QgsSymbolV2::QgsSymbolV2( SymbolType type, QgsSymbolLayerV2List layers )
- : mType( type ), mLayers( layers ), mOutputUnit( MM ), mAlpha( 1.0 )
+ : mType( type ), mLayers( layers ), mOutputUnit( MM ), mAlpha( 1.0 ), mRenderHints( 0 )
{
// check they're all correct symbol layers
@@ -127,14 +127,14 @@
void QgsSymbolV2::startRender( QgsRenderContext& context )
{
- QgsSymbolV2RenderContext symbolContext( context, mOutputUnit, mAlpha );
+ QgsSymbolV2RenderContext symbolContext( context, mOutputUnit, mAlpha, false, mRenderHints );
for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
( *it )->startRender( symbolContext );
}
void QgsSymbolV2::stopRender( QgsRenderContext& context )
{
- QgsSymbolV2RenderContext symbolContext( context, mOutputUnit, mAlpha );
+ QgsSymbolV2RenderContext symbolContext( context, mOutputUnit, mAlpha, false, mRenderHints );
for ( QgsSymbolLayerV2List::iterator it = mLayers.begin(); it != mLayers.end(); ++it )
( *it )->stopRender( symbolContext );
}
@@ -245,8 +245,8 @@
////////////////////
-QgsSymbolV2RenderContext::QgsSymbolV2RenderContext( QgsRenderContext& c, QgsSymbolV2::OutputUnit u, qreal alpha, bool selected )
- : mRenderContext( c ), mOutputUnit( u ), mAlpha( alpha ), mSelected( selected )
+QgsSymbolV2RenderContext::QgsSymbolV2RenderContext( QgsRenderContext& c, QgsSymbolV2::OutputUnit u, qreal alpha, bool selected, int renderHints )
+ : mRenderContext( c ), mOutputUnit( u ), mAlpha( alpha ), mSelected( selected ), mRenderHints( renderHints )
{
}
@@ -347,7 +347,7 @@
void QgsMarkerSymbolV2::renderPoint( const QPointF& point, QgsRenderContext& context, int layer, bool selected )
{
- QgsSymbolV2RenderContext symbolContext( context, mOutputUnit, mAlpha, selected );
+ QgsSymbolV2RenderContext symbolContext( context, mOutputUnit, mAlpha, selected, mRenderHints );
if ( layer != -1 )
{
if ( layer >= 0 && layer < mLayers.count() )
@@ -416,7 +416,7 @@
void QgsLineSymbolV2::renderPolyline( const QPolygonF& points, QgsRenderContext& context, int layer, bool selected )
{
- QgsSymbolV2RenderContext symbolContext( context, mOutputUnit, mAlpha, selected );
+ QgsSymbolV2RenderContext symbolContext( context, mOutputUnit, mAlpha, selected, mRenderHints );
if ( layer != -1 )
{
if ( layer >= 0 && layer < mLayers.count() )
@@ -452,7 +452,7 @@
void QgsFillSymbolV2::renderPolygon( const QPolygonF& points, QList<QPolygonF>* rings, QgsRenderContext& context, int layer, bool selected )
{
- QgsSymbolV2RenderContext symbolContext( context, mOutputUnit, mAlpha, selected );
+ QgsSymbolV2RenderContext symbolContext( context, mOutputUnit, mAlpha, selected, mRenderHints );
if ( layer != -1 )
{
if ( layer >= 0 && layer < mLayers.count() )
Modified: trunk/qgis/src/core/symbology-ng/qgssymbolv2.h
===================================================================
--- trunk/qgis/src/core/symbology-ng/qgssymbolv2.h 2010-04-25 22:12:05 UTC (rev 13388)
+++ trunk/qgis/src/core/symbology-ng/qgssymbolv2.h 2010-04-25 22:32:53 UTC (rev 13389)
@@ -35,6 +35,12 @@
Fill
};
+ enum RenderHint
+ {
+ DataDefinedSizeScale = 1,
+ DataDefinedRotation = 2
+ };
+
virtual ~QgsSymbolV2();
//! return new default symbol for specified geometry type
@@ -84,6 +90,9 @@
qreal alpha() const { return mAlpha; }
void setAlpha( qreal alpha ) { mAlpha = alpha; }
+ void setRenderHints( int hints ) { mRenderHints = hints; }
+ int renderHints() { return mRenderHints; }
+
protected:
QgsSymbolV2( SymbolType type, QgsSymbolLayerV2List layers ); // can't be instantiated
@@ -96,6 +105,8 @@
/**Symbol opacity (in the range 0 - 1)*/
qreal mAlpha;
+
+ int mRenderHints;
};
///////////////////////
@@ -103,7 +114,7 @@
class CORE_EXPORT QgsSymbolV2RenderContext
{
public:
- QgsSymbolV2RenderContext( QgsRenderContext& c, QgsSymbolV2::OutputUnit u , qreal alpha = 1.0, bool selected = false );
+ QgsSymbolV2RenderContext( QgsRenderContext& c, QgsSymbolV2::OutputUnit u , qreal alpha = 1.0, bool selected = false, int renderHints = 0 );
~QgsSymbolV2RenderContext();
QgsRenderContext& renderContext() { return mRenderContext; }
@@ -118,6 +129,9 @@
bool selected() const { return mSelected; }
void setSelected( bool selected ) { mSelected = selected; }
+ int renderHints() const { return mRenderHints; }
+ void setRenderHints( int hints ) { mRenderHints = hints; }
+
// Colour used for selections
static QColor selectionColor();
@@ -133,6 +147,7 @@
QgsSymbolV2::OutputUnit mOutputUnit;
qreal mAlpha;
bool mSelected;
+ int mRenderHints;
};
Modified: trunk/qgis/src/gui/symbology-ng/qgssinglesymbolrendererv2widget.cpp
===================================================================
--- trunk/qgis/src/gui/symbology-ng/qgssinglesymbolrendererv2widget.cpp 2010-04-25 22:12:05 UTC (rev 13388)
+++ trunk/qgis/src/gui/symbology-ng/qgssinglesymbolrendererv2widget.cpp 2010-04-25 22:32:53 UTC (rev 13389)
@@ -3,10 +3,13 @@
#include "qgssinglesymbolrendererv2.h"
#include "qgssymbolv2.h"
+#include "qgslogger.h"
#include "qgsvectorlayer.h"
#include "qgssymbolv2selectordialog.h"
+#include <QMenu>
+
QgsRendererV2Widget* QgsSingleSymbolRendererV2Widget::create( QgsVectorLayer* layer, QgsStyleV2* style, QgsFeatureRendererV2* renderer )
{
return new QgsSingleSymbolRendererV2Widget( layer, style, renderer );
@@ -43,8 +46,46 @@
layout->addWidget( mSelector );
setLayout( layout );
+ // advanced actions - data defined rendering
+ QMenu* advMenu = mSelector->advancedMenu();
+
+ mRotationMenu = new QMenu( tr( "Rotation field" ) );
+ mSizeScaleMenu = new QMenu( tr( "Size scale field" ) );
+
+ populateMenu( mRotationMenu, SLOT( rotationFieldSelected() ), mRenderer->rotationField() );
+ populateMenu( mSizeScaleMenu, SLOT( sizeScaleFieldSelected() ), mRenderer->sizeScaleField() );
+
+ advMenu->addMenu( mRotationMenu );
+ advMenu->addMenu( mSizeScaleMenu );
}
+void QgsSingleSymbolRendererV2Widget::populateMenu( QMenu* menu, const char* slot, QString fieldName )
+{
+ QAction* aNo = menu->addAction( tr( "- no field -" ), this, slot );
+ aNo->setCheckable( true );
+ menu->addSeparator();
+
+ bool hasField = false;
+ const QgsFieldMap& flds = mLayer->pendingFields();
+ for ( QgsFieldMap::const_iterator it = flds.begin(); it != flds.end(); ++it )
+ {
+ const QgsField& fld = it.value();
+ if ( fld.type() == QVariant::Int || fld.type() == QVariant::Double )
+ {
+ QAction* a = menu->addAction( fld.name(), this, slot );
+ a->setCheckable( true );
+ if ( fieldName == fld.name() )
+ {
+ a->setChecked( true );
+ hasField = true;
+ }
+ }
+ }
+
+ if ( !hasField )
+ aNo->setChecked( true );
+}
+
QgsSingleSymbolRendererV2Widget::~QgsSingleSymbolRendererV2Widget()
{
delete mSingleSymbol;
@@ -66,3 +107,50 @@
mRenderer->setSymbol( mSingleSymbol->clone() );
}
+void QgsSingleSymbolRendererV2Widget::rotationFieldSelected()
+{
+ QObject* s = sender();
+ if ( s == NULL )
+ return;
+
+ QAction* a = qobject_cast<QAction*>( s );
+ if ( a == NULL )
+ return;
+
+ QString fldName = a->text();
+
+ updateMenu( mRotationMenu, fldName );
+
+ if ( fldName == tr( "- no field -" ) )
+ fldName = QString();
+
+ mRenderer->setRotationField( fldName );
+}
+
+void QgsSingleSymbolRendererV2Widget::sizeScaleFieldSelected()
+{
+ QObject* s = sender();
+ if ( s == NULL )
+ return;
+
+ QAction* a = qobject_cast<QAction*>( s );
+ if ( a == NULL )
+ return;
+
+ QString fldName = a->text();
+
+ updateMenu( mSizeScaleMenu, fldName );
+
+ if ( fldName == tr( "- no field -" ) )
+ fldName = QString();
+
+ mRenderer->setSizeScaleField( fldName );
+}
+
+void QgsSingleSymbolRendererV2Widget::updateMenu( QMenu* menu, QString fieldName )
+{
+ foreach( QAction* a, menu->actions() )
+ {
+ a->setChecked( a->text() == fieldName );
+ }
+}
Modified: trunk/qgis/src/gui/symbology-ng/qgssinglesymbolrendererv2widget.h
===================================================================
--- trunk/qgis/src/gui/symbology-ng/qgssinglesymbolrendererv2widget.h 2010-04-25 22:12:05 UTC (rev 13388)
+++ trunk/qgis/src/gui/symbology-ng/qgssinglesymbolrendererv2widget.h 2010-04-25 22:32:53 UTC (rev 13389)
@@ -6,6 +6,8 @@
class QgsSingleSymbolRendererV2;
class QgsSymbolV2SelectorDialog;
+class QMenu;
+
class GUI_EXPORT QgsSingleSymbolRendererV2Widget : public QgsRendererV2Widget
{
Q_OBJECT
@@ -22,10 +24,20 @@
public slots:
void changeSingleSymbol();
+ void rotationFieldSelected();
+ void sizeScaleFieldSelected();
+
protected:
+
+ void populateMenu( QMenu* menu, const char* slot, QString fieldName );
+ void updateMenu( QMenu* menu, QString fieldName );
+
QgsSingleSymbolRendererV2* mRenderer;
QgsSymbolV2SelectorDialog* mSelector;
QgsSymbolV2* mSingleSymbol;
+
+ QMenu* mRotationMenu;
+ QMenu* mSizeScaleMenu;
};
Modified: trunk/qgis/src/gui/symbology-ng/qgssymbolv2selectordialog.cpp
===================================================================
--- trunk/qgis/src/gui/symbology-ng/qgssymbolv2selectordialog.cpp 2010-04-25 22:12:05 UTC (rev 13388)
+++ trunk/qgis/src/gui/symbology-ng/qgssymbolv2selectordialog.cpp 2010-04-25 22:32:53 UTC (rev 13389)
@@ -14,15 +14,18 @@
#include <QStandardItemModel>
#include <QInputDialog>
#include <QKeyEvent>
+#include <QMenu>
QgsSymbolV2SelectorDialog::QgsSymbolV2SelectorDialog( QgsSymbolV2* symbol, QgsStyleV2* style, QWidget* parent, bool embedded )
- : QDialog( parent )
+ : QDialog( parent ), mAdvancedMenu( NULL )
{
mStyle = style;
mSymbol = symbol;
setupUi( this );
+ btnAdvanced->hide(); // advanced button is hidden by default
+
// can be embedded in renderer properties dialog
if ( embedded )
{
@@ -262,3 +265,14 @@
double transparencyPercent = ( 1 - alpha ) * 100;
mTransparencyLabel->setText( tr( "Transparency: %1%" ).arg(( int ) transparencyPercent ) );
}
+
+QMenu* QgsSymbolV2SelectorDialog::advancedMenu()
+{
+ if ( mAdvancedMenu == NULL )
+ {
+ mAdvancedMenu = new QMenu;
+ btnAdvanced->setMenu( mAdvancedMenu );
+ btnAdvanced->show();
+ }
+ return mAdvancedMenu;
+}
Modified: trunk/qgis/src/gui/symbology-ng/qgssymbolv2selectordialog.h
===================================================================
--- trunk/qgis/src/gui/symbology-ng/qgssymbolv2selectordialog.h 2010-04-25 22:12:05 UTC (rev 13388)
+++ trunk/qgis/src/gui/symbology-ng/qgssymbolv2selectordialog.h 2010-04-25 22:32:53 UTC (rev 13389)
@@ -9,6 +9,8 @@
class QgsStyleV2;
class QgsSymbolV2;
+class QMenu;
+
class GUI_EXPORT QgsSymbolV2SelectorDialog : public QDialog, private Ui::QgsSymbolV2SelectorDialogBase
{
Q_OBJECT
@@ -16,6 +18,9 @@
public:
QgsSymbolV2SelectorDialog( QgsSymbolV2* symbol, QgsStyleV2* style, QWidget* parent = NULL, bool embedded = false );
+ //! return menu for "advanced" button - create it if doesn't exist and show the advanced button
+ QMenu* advancedMenu();
+
protected:
void populateSymbolView();
void updateSymbolPreview();
@@ -46,6 +51,7 @@
protected:
QgsStyleV2* mStyle;
QgsSymbolV2* mSymbol;
+ QMenu* mAdvancedMenu;
};
#endif
Modified: trunk/qgis/src/ui/qgssymbolv2selectordialogbase.ui
===================================================================
--- trunk/qgis/src/ui/qgssymbolv2selectordialogbase.ui 2010-04-25 22:12:05 UTC (rev 13388)
+++ trunk/qgis/src/ui/qgssymbolv2selectordialogbase.ui 2010-04-25 22:32:53 UTC (rev 13389)
@@ -29,7 +29,7 @@
</size>
</property>
<property name="frameShape">
- <enum>QFrame::Box</enum>
+ <enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
@@ -222,6 +222,13 @@
</spacer>
</item>
<item>
+ <widget class="QPushButton" name="btnAdvanced">
+ <property name="text">
+ <string>Advanced</string>
+ </property>
+ </widget>
+ </item>
+ <item>
<widget class="QPushButton" name="btnAddToStyle">
<property name="text">
<string>Add to style</string>
More information about the QGIS-commit
mailing list