27 #include <QDomElement> 34 , mLabelAttributeName( labelAttributeName )
36 , mTolerance( 0.00001 )
38 , mCircleColor( QColor( 125, 125, 125 ) )
39 , mCircleRadiusAddition( 0 )
40 , mMaxLabelScaleDenominator( -1 )
41 , mSpatialIndex( NULL )
74 mRenderer->
toSld( doc, element );
80 Q_UNUSED( drawVertexMarker );
88 QgsSymbolV2* symbol = firstSymbolForFeature( mRenderer, feature );
104 mSelectedFeatures.insert( feature.
id() );
107 if ( intersectList.empty() )
111 DisplacementGroup newGroup;
112 newGroup.insert( feature.
id(), qMakePair( feature, symbol ) );
113 mDisplacementGroups.push_back( newGroup );
115 mGroupIndex.insert( feature.
id(), mDisplacementGroups.count() - 1 );
122 int groupIdx = mGroupIndex[ existingEntry ];
123 DisplacementGroup& group = mDisplacementGroups[groupIdx];
126 group.insert( feature.
id(), qMakePair( feature, symbol ) );
128 mGroupIndex.insert( feature.
id(), groupIdx );
132 void QgsPointDisplacementRenderer::drawGroup(
const DisplacementGroup& group,
QgsRenderContext& context )
134 const QgsFeature& feature = group.begin().value().first;
135 bool selected = mSelectedFeatures.contains( feature.
id() );
141 QStringList labelAttributeList;
142 QList<QgsMarkerSymbolV2*> symbolList;
144 for ( DisplacementGroup::const_iterator attIt = group.constBegin(); attIt != group.constEnd(); ++attIt )
146 labelAttributeList << ( mDrawLabels ? getLabel( attIt.value().first ) : QString() );
147 symbolList << dynamic_cast<QgsMarkerSymbolV2*>( attIt.value().second );
152 double currentWidthFactor;
154 QList<QgsMarkerSymbolV2*>::const_iterator it = symbolList.constBegin();
155 for ( ; it != symbolList.constEnd(); ++it )
160 double currentDiagonal = sqrt( 2 * (( *it )->size() * ( *it )->size() ) ) * currentWidthFactor;
161 if ( currentDiagonal > diagonal )
163 diagonal = currentDiagonal;
170 double circleAdditionPainterUnits = symbolContext.
outputLineWidth( mCircleRadiusAddition );
171 double radius = qMax(( diagonal / 2 ), labelAttributeList.size() * diagonal / 2 /
M_PI ) + circleAdditionPainterUnits;
174 drawCircle( radius, symbolContext, pt, symbolList.size() );
176 QList<QPointF> symbolPositions;
177 QList<QPointF> labelPositions;
178 calculateSymbolAndLabelPositions( pt, labelAttributeList.size(), radius, diagonal, symbolPositions, labelPositions );
181 if ( labelAttributeList.size() > 1 )
185 mCenterSymbol->
renderPoint( pt, &feature, context, -1, selected );
194 drawSymbols( feature, context, symbolList, symbolPositions, selected );
196 drawLabels( pt, symbolContext, labelPositions, labelAttributeList );
207 QList<QString> attributeList;
208 if ( !mLabelAttributeName.isEmpty() )
210 attributeList.push_back( mLabelAttributeName );
216 return attributeList;
283 mDisplacementGroups.clear();
286 mSelectedFeatures.clear();
288 if ( mLabelAttributeName.isEmpty() )
297 if ( mMaxLabelScaleDenominator > 0 && context.
rendererScale() > mMaxLabelScaleDenominator )
314 QgsDebugMsg(
"QgsPointDisplacementRenderer::stopRender" );
318 for ( QList<DisplacementGroup>::const_iterator it = mDisplacementGroups.begin(); it != mDisplacementGroups.end(); ++it )
319 drawGroup( *it, context );
321 mDisplacementGroups.clear();
323 delete mSpatialIndex;
325 mSelectedFeatures.clear();
339 labelFont.fromString( symbologyElem.attribute(
"labelFont",
"" ) );
341 r->
setCircleWidth( symbologyElem.attribute(
"circleWidth",
"0.4" ).toDouble() );
346 r->
setTolerance( symbologyElem.attribute(
"tolerance",
"0.00001" ).toDouble() );
349 QDomElement embeddedRendererElem = symbologyElem.firstChildElement(
"renderer-v2" );
350 if ( !embeddedRendererElem.isNull() )
356 QDomElement centerSymbolElem = symbologyElem.firstChildElement(
"symbol" );
357 if ( !centerSymbolElem.isNull() )
359 r->
setCenterSymbol( QgsSymbolLayerV2Utils::loadSymbol<QgsMarkerSymbolV2>( centerSymbolElem ) );
367 rendererElement.setAttribute(
"type",
"pointDisplacement" );
368 rendererElement.setAttribute(
"labelAttributeName", mLabelAttributeName );
369 rendererElement.setAttribute(
"labelFont", mLabelFont.toString() );
370 rendererElement.setAttribute(
"circleWidth", QString::number( mCircleWidth ) );
373 rendererElement.setAttribute(
"circleRadiusAddition", QString::number( mCircleRadiusAddition ) );
374 rendererElement.setAttribute(
"maxLabelScaleDenominator", QString::number( mMaxLabelScaleDenominator ) );
375 rendererElement.setAttribute(
"tolerance", QString::number( mTolerance ) );
379 QDomElement embeddedRendererElem = mRenderer->
save( doc );
380 rendererElement.appendChild( embeddedRendererElem );
385 rendererElement.appendChild( centerSymbolElem );
387 return rendererElement;
411 return QgsRectangle( p.
x() - mTolerance, p.
y() - mTolerance, p.
x() + mTolerance, p.
y() + mTolerance );
414 void QgsPointDisplacementRenderer::printInfoDisplacementGroups()
416 int nGroups = mDisplacementGroups.size();
417 QgsDebugMsg(
"number of displacement groups:" + QString::number( nGroups ) );
418 for (
int i = 0; i < nGroups; ++i )
420 QgsDebugMsg(
"***************displacement group " + QString::number( i ) );
421 DisplacementGroup::const_iterator it = mDisplacementGroups.at( i ).constBegin();
422 for ( ; it != mDisplacementGroups.at( i ).constEnd(); ++it )
429 QString QgsPointDisplacementRenderer::getLabel(
const QgsFeature& f )
433 if ( mLabelIndex >= 0 && mLabelIndex < attrs.count() )
435 attribute = attrs[mLabelIndex].toString();
442 delete mCenterSymbol;
443 mCenterSymbol = symbol;
448 void QgsPointDisplacementRenderer::calculateSymbolAndLabelPositions(
const QPointF& centerPoint,
int nPosition,
double radius,
449 double symbolDiagonal, QList<QPointF>& symbolPositions, QList<QPointF>& labelShifts )
const 451 symbolPositions.clear();
458 else if ( nPosition == 1 )
460 symbolPositions.append( centerPoint );
461 labelShifts.append( QPointF( symbolDiagonal / 2.0, -symbolDiagonal / 2.0 ) );
465 double fullPerimeter = 2 *
M_PI;
466 double angleStep = fullPerimeter / nPosition;
469 for ( currentAngle = 0.0; currentAngle < fullPerimeter; currentAngle += angleStep )
471 double sinusCurrentAngle = sin( currentAngle );
472 double cosinusCurrentAngle = cos( currentAngle );
473 QPointF positionShift( radius * sinusCurrentAngle, radius * cosinusCurrentAngle );
474 QPointF labelShift(( radius + symbolDiagonal / 2 ) * sinusCurrentAngle, ( radius + symbolDiagonal / 2 ) * cosinusCurrentAngle );
475 symbolPositions.append( centerPoint + positionShift );
476 labelShifts.append( labelShift );
480 void QgsPointDisplacementRenderer::drawCircle(
double radiusPainterUnits,
QgsSymbolV2RenderContext& context,
const QPointF& centerPoint,
int nSymbols )
483 if ( nSymbols < 2 || !p )
489 QPen circlePen( mCircleColor );
491 p->setPen( circlePen );
492 p->drawArc( QRectF( centerPoint.x() - radiusPainterUnits, centerPoint.y() - radiusPainterUnits, 2 * radiusPainterUnits, 2 * radiusPainterUnits ), 0, 5760 );
495 void QgsPointDisplacementRenderer::drawSymbols(
const QgsFeature& f,
QgsRenderContext& context,
const QList<QgsMarkerSymbolV2*>& symbolList,
const QList<QPointF>& symbolPositions,
bool selected )
497 QList<QPointF>::const_iterator symbolPosIt = symbolPositions.constBegin();
498 QList<QgsMarkerSymbolV2*>::const_iterator symbolIt = symbolList.constBegin();
499 for ( ; symbolPosIt != symbolPositions.constEnd() && symbolIt != symbolList.constEnd(); ++symbolPosIt, ++symbolIt )
503 ( *symbolIt )->renderPoint( *symbolPosIt, &f, context, -1, selected );
508 void QgsPointDisplacementRenderer::drawLabels(
const QPointF& centerPoint,
QgsSymbolV2RenderContext& context,
const QList<QPointF>& labelShifts,
const QStringList& labelList )
516 QPen labelPen( mLabelColor );
517 p->setPen( labelPen );
520 QFont pixelSizeFont = mLabelFont;
521 pixelSizeFont.setPixelSize( context.
outputLineWidth( mLabelFont.pointSizeF() * 0.3527 ) );
522 QFont scaledFont = pixelSizeFont;
524 p->setFont( scaledFont );
526 QFontMetricsF fontMetrics( pixelSizeFont );
527 QPointF currentLabelShift;
529 QList<QPointF>::const_iterator labelPosIt = labelShifts.constBegin();
530 QStringList::const_iterator text_it = labelList.constBegin();
532 for ( ; labelPosIt != labelShifts.constEnd() && text_it != labelList.constEnd(); ++labelPosIt, ++text_it )
534 currentLabelShift = *labelPosIt;
535 if ( currentLabelShift.x() < 0 )
537 currentLabelShift.setX( currentLabelShift.x() - fontMetrics.width( *text_it ) );
539 if ( currentLabelShift.y() > 0 )
541 currentLabelShift.setY( currentLabelShift.y() + fontMetrics.ascent() );
544 QPointF drawingPoint( centerPoint + currentLabelShift );
546 p->translate( drawingPoint.x(), drawingPoint.y() );
548 p->drawText( QPointF( 0, 0 ), *text_it );
561 if ( symbolList.size() < 1 )
566 return symbolList.at( 0 );
571 if ( renderer->
type() ==
"pointDisplacement" )
576 if ( renderer->
type() ==
"singleSymbol" ||
577 renderer->
type() ==
"categorizedSymbol" ||
578 renderer->
type() ==
"graduatedSymbol" ||
579 renderer->
type() ==
"RuleRenderer" )
583 return pointRenderer;
QgsFeatureId id() const
Get the feature id for this feature.
#define RENDERER_TAG_NAME
virtual bool willRenderFeature(QgsFeature &feat)
return whether the renderer will render a feature or not.
A rectangle specified with double values.
virtual QgsSymbolV2 * originalSymbolForFeature(QgsFeature &feature)
Return symbol for feature.
~QgsPointDisplacementRenderer()
QList< QgsSymbolV2 * > QgsSymbolV2List
virtual QgsSymbolV2 * originalSymbolForFeature(QgsFeature &feat) override
Proxy that will call this method on the embedded renderer.
static const unsigned char * _getPoint(QPointF &pt, QgsRenderContext &context, const unsigned char *wkb)
static QgsFeatureRendererV2 * create(QDomElement &symbologyElem)
create a renderer from XML element
void setLabelAttributeName(const QString &name)
int fieldNameIndex(const QString &fieldName) const
Look up field's index from name also looks up case-insensitive if there is no match otherwise...
double rendererScale() const
void setLabelFont(const QFont &f)
virtual QDomElement save(QDomDocument &doc)
store renderer info to XML element
void setCenterSymbol(QgsMarkerSymbolV2 *symbol)
Sets the center symbol (takes ownership)
QgsGeometry * geometry() const
Get the geometry object associated with this feature.
QgsLegendSymbologyList legendSymbologyItems(QSize iconSize) override
return a list of symbology items for the legend
#define FID_TO_STRING(fid)
virtual QgsLegendSymbolList legendSymbolItems(double scaleDenominator=-1, QString rule="")
return a list of item text / symbol
void setMaxLabelScaleDenominator(double d)
Container of fields for a vector layer.
static QgsPointDisplacementRenderer * convertFromRenderer(const QgsFeatureRendererV2 *renderer)
creates a QgsPointDisplacementRenderer from an existing renderer.
WkbType
Used for symbology operations.
static QColor decodeColor(QString str)
QDomElement save(QDomDocument &doc) override
store renderer info to XML element
virtual QgsSymbolV2List symbolsForFeature(QgsFeature &feat) override
Proxy that will call this method on the embedded renderer.
virtual QList< QString > usedAttributes()=0
QgsPointDisplacementRenderer(const QString &labelAttributeName="")
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
void startRender(QgsRenderContext &context, const QgsFields &fields) override
QList< QgsFeatureId > intersects(QgsRectangle rect) const
returns features that intersect the specified rectangle
virtual QgsLegendSymbologyList legendSymbologyItems(QSize iconSize)
return a list of symbology items for the legend
virtual void startRender(QgsRenderContext &context, const QgsFields &fields)=0
static QString encodeColor(QColor color)
virtual void stopRender(QgsRenderContext &context)=0
static QDomElement saveSymbol(QString symbolName, QgsSymbolV2 *symbol, QDomDocument &doc)
virtual QgsSymbolV2List symbols()=0
for symbol levels
virtual QgsSymbolV2List originalSymbolsForFeature(QgsFeature &feat)
Equivalent of originalSymbolsForFeature() call extended to support renderers that may use more symbol...
virtual QgsFeatureRendererV2 * clone() const =0
void setEmbeddedRenderer(QgsFeatureRendererV2 *r)
Sets embedded renderer (takes ownership)
void startRender(QgsRenderContext &context, const QgsFields *fields=0)
virtual void toSld(QDomDocument &doc, QDomElement &element) const override
used from subclasses to create SLD Rule elements following SLD v1.1 specs
void setLabelColor(const QColor &c)
virtual QgsSymbolV2 * clone() const override
const QgsAttributes & attributes() const
double rasterScaleFactor() const
QGis::WkbType wkbType() const
Returns type of wkb (point / linestring / polygon etc.)
static QgsFeatureRendererV2 * defaultRenderer(QGis::GeometryType geomType)
return a new renderer - used by default in vector layers
void renderPoint(const QPointF &point, const QgsFeature *f, QgsRenderContext &context, int layer=-1, bool selected=false)
QgsLegendSymbolList legendSymbolItems(double scaleDenominator=-1, QString rule="") override
A class to represent a point.
bool renderFeature(QgsFeature &feature, QgsRenderContext &context, int layer=-1, bool selected=false, bool drawVertexMarker=false) override
Reimplemented from QgsFeatureRendererV2.
QList< QPair< QString, QPixmap > > QgsLegendSymbologyList
void setCircleRadiusAddition(double d)
void stopRender(QgsRenderContext &context) override
virtual void toSld(QDomDocument &doc, QDomElement &element) const
used from subclasses to create SLD Rule elements following SLD v1.1 specs
A renderer that automatically displaces points with the same position.
void setCircleWidth(double w)
Contains information about the context of a rendering operation.
bool insertFeature(const QgsFeature &f)
add feature to index
virtual QgsSymbolV2 * symbolForFeature(QgsFeature &feature) override
Proxy that will call this method on the embedded renderer.
void stopRender(QgsRenderContext &context)
static double lineWidthScaleFactor(const QgsRenderContext &c, QgsSymbolV2::OutputUnit u, const QgsMapUnitScale &scale=QgsMapUnitScale())
Returns the line width scale factor depending on the unit and the paint device.
virtual QgsSymbolV2List symbols() override
Proxy that will call this method on the embedded renderer.
virtual QgsSymbolV2List symbolsForFeature(QgsFeature &feat)
return list of symbols used for rendering the feature.
static QgsFeatureRendererV2 * load(QDomElement &symbologyElem)
create a renderer from XML element
void setCircleColor(const QColor &c)
QgsRenderContext & renderContext()
virtual int capabilities() override
Proxy that will call this method on the embedded renderer.
virtual bool willRenderFeature(QgsFeature &feat) override
Proxy that will call this method on the embedded renderer.
double outputLineWidth(double width) const
virtual int capabilities()
returns bitwise OR-ed capabilities of the renderer
QgsPoint asPoint() const
return contents of the geometry as a point if wkbType is WKBPoint, otherwise returns [0...
virtual QList< QString > usedAttributes() override
Partial proxy that will call this method on the embedded renderer.
QList< QPair< QString, QgsSymbolV2 * > > QgsLegendSymbolList
virtual QgsSymbolV2 * symbolForFeature(QgsFeature &feature)=0
to be overridden
const unsigned char * asWkb() const
Returns the buffer containing this geometry in WKB format.
QgsFeatureRendererV2 * clone() const override
void setTolerance(double t)
virtual QgsSymbolV2List originalSymbolsForFeature(QgsFeature &feat) override
Proxy that will call this method on the embedded renderer.