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;
}
Пример #3
0
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 );
}