bool QgsPointDisplacementRenderer::renderFeature( QgsFeature& feature, QgsRenderContext& context, int layer, bool selected, bool drawVertexMarker ) { Q_UNUSED( drawVertexMarker ); Q_UNUSED( context ); Q_UNUSED( layer ); //check, if there is already a point at that position if ( !feature.constGeometry() ) return false; QgsSymbolV2* symbol = firstSymbolForFeature( mRenderer, feature, context ); //if the feature has no symbol (eg, no matching rule in a rule-based renderer), skip it if ( !symbol ) return false; //point position in screen coords const QgsGeometry* geom = feature.constGeometry(); QGis::WkbType geomType = geom->wkbType(); if ( geomType != QGis::WKBPoint && geomType != QGis::WKBPoint25D ) { //can only render point type return false; } if ( selected ) mSelectedFeatures.insert( feature.id() ); double searchDistance = mTolerance * QgsSymbolLayerV2Utils::mapUnitScaleFactor( context, mToleranceUnit, mToleranceMapUnitScale ); QList<QgsFeatureId> intersectList = mSpatialIndex->intersects( searchRect( feature.constGeometry()->asPoint(), searchDistance ) ); if ( intersectList.empty() ) { mSpatialIndex->insertFeature( feature ); // create new group DisplacementGroup newGroup; newGroup.insert( feature.id(), qMakePair( feature, symbol ) ); mDisplacementGroups.push_back( newGroup ); // add to group index mGroupIndex.insert( feature.id(), mDisplacementGroups.count() - 1 ); return true; } //go through all the displacement group maps and search an entry where the id equals the result of the spatial search QgsFeatureId existingEntry = intersectList.at( 0 ); int groupIdx = mGroupIndex[ existingEntry ]; DisplacementGroup& group = mDisplacementGroups[groupIdx]; // add to a group group.insert( feature.id(), qMakePair( feature, symbol ) ); // add to group index mGroupIndex.insert( feature.id(), groupIdx ); return true; }
bool QgsPointDisplacementRenderer::renderFeature( QgsFeature& feature, QgsRenderContext& context, int layer, bool selected, bool drawVertexMarker ) { Q_UNUSED( drawVertexMarker ); //point position in screen coords QgsGeometry* geom = feature.geometry(); QGis::WkbType geomType = geom->wkbType(); if ( geomType != QGis::WKBPoint && geomType != QGis::WKBPoint25D ) { //can only render point type return false; } QPointF pt; _getPoint( pt, context, geom->asWkb() ); //get list of labels and symbols QStringList labelAttributeList; QList<QgsMarkerSymbolV2*> symbolList; if ( mDisplacementIds.contains( feature.id() ) ) { //create the symbol for the whole display group if the id is the first entry in a display group QList<QMap<QgsFeatureId, QgsFeature> >::iterator it = mDisplacementGroups.begin(); for ( ; it != mDisplacementGroups.end(); ++it ) { //create the symbol for the whole display group if the id is the first entry in a display group if ( feature.id() == it->begin().key() ) { QMap<QgsFeatureId, QgsFeature>::iterator attIt = it->begin(); for ( ; attIt != it->end(); ++attIt ) { if ( mDrawLabels ) { labelAttributeList << getLabel( attIt.value() ); } else { labelAttributeList << QString(); } symbolList << dynamic_cast<QgsMarkerSymbolV2*>( firstSymbolForFeature( mRenderer, attIt.value() ) ); } } } } else //only one feature { symbolList << dynamic_cast<QgsMarkerSymbolV2*>( firstSymbolForFeature( mRenderer, feature ) ); if ( mDrawLabels ) { labelAttributeList << getLabel( feature ); } else { labelAttributeList << QString(); } } if ( symbolList.isEmpty() && labelAttributeList.isEmpty() ) { return true; //display all point symbols for one posi } //draw symbol double diagonal = 0; double currentWidthFactor; //scale symbol size to map unit and output resolution QList<QgsMarkerSymbolV2*>::const_iterator it = symbolList.constBegin(); for ( ; it != symbolList.constEnd(); ++it ) { if ( *it ) { currentWidthFactor = QgsSymbolLayerV2Utils::lineWidthScaleFactor( context, ( *it )->outputUnit() ); double currentDiagonal = sqrt( 2 * (( *it )->size() * ( *it )->size() ) ) * currentWidthFactor; if ( currentDiagonal > diagonal ) { diagonal = currentDiagonal; } } } QgsSymbolV2RenderContext symbolContext( context, QgsSymbolV2::MM, 1.0, selected ); double circleAdditionPainterUnits = symbolContext.outputLineWidth( mCircleRadiusAddition ); double radius = qMax(( diagonal / 2 ), labelAttributeList.size() * diagonal / 2 / M_PI ) + circleAdditionPainterUnits; //draw Circle drawCircle( radius, symbolContext, pt, symbolList.size() ); QList<QPointF> symbolPositions; QList<QPointF> labelPositions; calculateSymbolAndLabelPositions( pt, labelAttributeList.size(), radius, diagonal, symbolPositions, labelPositions ); //draw mid point if ( labelAttributeList.size() > 1 ) { if ( mCenterSymbol ) { mCenterSymbol->renderPoint( pt, &feature, context, layer, selected ); } else { context.painter()->drawRect( QRectF( pt.x() - symbolContext.outputLineWidth( 1 ), pt.y() - symbolContext.outputLineWidth( 1 ), symbolContext.outputLineWidth( 2 ), symbolContext.outputLineWidth( 2 ) ) ); } } //draw symbols on the circle drawSymbols( feature, context, symbolList, symbolPositions, selected ); //and also the labels drawLabels( pt, symbolContext, labelPositions, labelAttributeList ); return true; }
bool QgsPointDistanceRenderer::renderFeature( QgsFeature& feature, QgsRenderContext& context, int layer, bool selected, bool drawVertexMarker ) { Q_UNUSED( drawVertexMarker ); Q_UNUSED( context ); Q_UNUSED( layer ); //check if there is already a point at that position if ( !feature.hasGeometry() ) return false; QgsMarkerSymbol* symbol = firstSymbolForFeature( feature, context ); //if the feature has no symbol (eg, no matching rule in a rule-based renderer), skip it if ( !symbol ) return false; //point position in screen coords QgsGeometry geom = feature.geometry(); QgsWkbTypes::Type geomType = geom.wkbType(); if ( QgsWkbTypes::flatType( geomType ) != QgsWkbTypes::Point ) { //can only render point type return false; } QString label; if ( mDrawLabels ) { label = getLabel( feature ); } QgsCoordinateTransform xform = context.coordinateTransform(); QgsFeature transformedFeature = feature; if ( xform.isValid() ) { geom.transform( xform ); transformedFeature.setGeometry( geom ); } double searchDistance = mTolerance * QgsSymbolLayerUtils::mapUnitScaleFactor( context, mToleranceUnit, mToleranceMapUnitScale ); QgsPoint point = transformedFeature.geometry().asPoint(); QList<QgsFeatureId> intersectList = mSpatialIndex->intersects( searchRect( point, searchDistance ) ); if ( intersectList.empty() ) { mSpatialIndex->insertFeature( transformedFeature ); // create new group ClusteredGroup newGroup; newGroup << GroupedFeature( transformedFeature, symbol, selected, label ); mClusteredGroups.push_back( newGroup ); // add to group index mGroupIndex.insert( transformedFeature.id(), mClusteredGroups.count() - 1 ); mGroupLocations.insert( transformedFeature.id(), point ); } else { // find group with closest location to this point (may be more than one within search tolerance) QgsFeatureId minDistFeatureId = intersectList.at( 0 ); double minDist = mGroupLocations.value( minDistFeatureId ).distance( point ); for ( int i = 1; i < intersectList.count(); ++i ) { QgsFeatureId candidateId = intersectList.at( i ); double newDist = mGroupLocations.value( candidateId ).distance( point ); if ( newDist < minDist ) { minDist = newDist; minDistFeatureId = candidateId; } } int groupIdx = mGroupIndex[ minDistFeatureId ]; ClusteredGroup& group = mClusteredGroups[groupIdx]; // calculate new centroid of group QgsPoint oldCenter = mGroupLocations.value( minDistFeatureId ); mGroupLocations[ minDistFeatureId ] = QgsPoint(( oldCenter.x() * group.size() + point.x() ) / ( group.size() + 1.0 ), ( oldCenter.y() * group.size() + point.y() ) / ( group.size() + 1.0 ) ); // add to a group group << GroupedFeature( transformedFeature, symbol, selected, label ); // add to group index mGroupIndex.insert( transformedFeature.id(), groupIdx ); } return true; }
void QgsPointDisplacementRenderer::drawGroup( const DisplacementGroup& group, QgsRenderContext& context ) { const QgsFeature& feature = group.begin().value(); bool selected = mSelectedFeatures.contains( feature.id() ); // maybe we should highlight individual features instead of the whole group? QPointF pt; _getPoint( pt, context, feature.geometry()->asWkb() ); //get list of labels and symbols QStringList labelAttributeList; QList<QgsMarkerSymbolV2*> symbolList; for ( DisplacementGroup::const_iterator attIt = group.constBegin(); attIt != group.constEnd(); ++attIt ) { labelAttributeList << ( mDrawLabels ? getLabel( attIt.value() ) : QString() ); QgsFeature& f = const_cast<QgsFeature&>( attIt.value() ); // other parts of API use non-const ref to QgsFeature :-/ symbolList << dynamic_cast<QgsMarkerSymbolV2*>( firstSymbolForFeature( mRenderer, f ) ); } //draw symbol double diagonal = 0; double currentWidthFactor; //scale symbol size to map unit and output resolution QList<QgsMarkerSymbolV2*>::const_iterator it = symbolList.constBegin(); for ( ; it != symbolList.constEnd(); ++it ) { if ( *it ) { currentWidthFactor = QgsSymbolLayerV2Utils::lineWidthScaleFactor( context, ( *it )->outputUnit(), ( *it )->mapUnitScale() ); double currentDiagonal = sqrt( 2 * (( *it )->size() * ( *it )->size() ) ) * currentWidthFactor; if ( currentDiagonal > diagonal ) { diagonal = currentDiagonal; } } } QgsSymbolV2RenderContext symbolContext( context, QgsSymbolV2::MM, 1.0, selected ); double circleAdditionPainterUnits = symbolContext.outputLineWidth( mCircleRadiusAddition ); double radius = qMax(( diagonal / 2 ), labelAttributeList.size() * diagonal / 2 / M_PI ) + circleAdditionPainterUnits; //draw Circle drawCircle( radius, symbolContext, pt, symbolList.size() ); QList<QPointF> symbolPositions; QList<QPointF> labelPositions; calculateSymbolAndLabelPositions( pt, labelAttributeList.size(), radius, diagonal, symbolPositions, labelPositions ); //draw mid point if ( labelAttributeList.size() > 1 ) { if ( mCenterSymbol ) { mCenterSymbol->renderPoint( pt, &feature, context, -1, selected ); } else { context.painter()->drawRect( QRectF( pt.x() - symbolContext.outputLineWidth( 1 ), pt.y() - symbolContext.outputLineWidth( 1 ), symbolContext.outputLineWidth( 2 ), symbolContext.outputLineWidth( 2 ) ) ); } } //draw symbols on the circle drawSymbols( feature, context, symbolList, symbolPositions, selected ); //and also the labels drawLabels( pt, symbolContext, labelPositions, labelAttributeList ); }