QgsGeometry* QgsMapToolOffsetCurve::createOriginGeometry( QgsVectorLayer* vl, const QgsPointLocator::Match& match, QgsFeature& snappedFeature )
{
  if ( !vl )
  {
    return 0;
  }

  mMultiPartGeometry = false;
  //assign feature part by vertex number (snap to vertex) or by before vertex number (snap to segment)
  int partVertexNr = match.vertexIndex();

  if ( vl == currentVectorLayer() && !mForceCopy )
  {
    //don't consider selected geometries, only the snap result
    return convertToSingleLine( snappedFeature.geometryAndOwnership(), partVertexNr, mMultiPartGeometry );
  }
  else //snapped to a background layer
  {
    //if source layer is polygon / multipolygon, create a linestring from the snapped ring
    if ( vl->geometryType() == QGis::Polygon )
    {
      //make linestring from polygon ring and return this geometry
      return linestringFromPolygon( snappedFeature.geometry(), partVertexNr );
    }

    //for background layers, try to merge selected entries together if snapped feature is contained in selection
    const QgsFeatureIds& selection = vl->selectedFeaturesIds();
    if ( selection.size() < 1 || !selection.contains( match.featureId() ) )
    {
      return convertToSingleLine( snappedFeature.geometryAndOwnership(), partVertexNr, mMultiPartGeometry );
    }
    else
    {
      //merge together if several features
      QgsFeatureList selectedFeatures = vl->selectedFeatures();
      QgsFeatureList::iterator selIt = selectedFeatures.begin();
      QgsGeometry* geom = selIt->geometryAndOwnership();
      ++selIt;
      for ( ; selIt != selectedFeatures.end(); ++selIt )
      {
        QgsGeometry* combined = geom->combine( selIt->geometry() );
        delete geom;
        geom = combined;
      }

      //if multitype, return only the snapped to geometry
      if ( geom->isMultipart() )
      {
        delete geom;
        return convertToSingleLine( snappedFeature.geometryAndOwnership(), match.vertexIndex(), mMultiPartGeometry );
      }

      return geom;
    }
  }
}
void QgsGeometryAnalyzer::bufferFeature( QgsFeature& f, int nProcessedFeatures, QgsVectorFileWriter* vfw, bool dissolve,
    QgsGeometry& dissolveGeometry, double bufferDistance, int bufferDistanceField )
{
  if ( !f.hasGeometry() )
  {
    return;
  }

  double currentBufferDistance;
  QgsGeometry featureGeometry = f.geometry();
  QgsGeometry bufferGeometry;

  //create buffer
  if ( bufferDistanceField == -1 )
  {
    currentBufferDistance = bufferDistance;
  }
  else
  {
    currentBufferDistance = f.attribute( bufferDistanceField ).toDouble();
  }
  bufferGeometry = featureGeometry.buffer( currentBufferDistance, 5 );

  if ( dissolve )
  {
    if ( nProcessedFeatures == 0 )
    {
      dissolveGeometry = bufferGeometry;
    }
    else
    {
      dissolveGeometry = dissolveGeometry.combine( bufferGeometry );
    }
  }
  else //dissolve
  {
    QgsFeature newFeature;
    newFeature.setGeometry( bufferGeometry );
    newFeature.setAttributes( f.attributes() );

    //add it to vector file writer
    if ( vfw )
    {
      vfw->addFeature( newFeature );
    }
  }
}
QgsGeometry QgsGeometryAnalyzer::dissolveFeature( const QgsFeature& f, const QgsGeometry& dissolveInto )
{
  if ( !f.hasGeometry() )
  {
    return dissolveInto;
  }

  QgsGeometry featureGeometry = f.geometry();

  if ( dissolveInto.isEmpty() )
  {
    return featureGeometry;
  }
  else
  {
    return dissolveInto.combine( featureGeometry );
  }
}
void QgsGeometryAnalyzer::convexFeature( QgsFeature& f, int nProcessedFeatures, QgsGeometry& dissolveGeometry )
{
  if ( !f.hasGeometry() )
  {
    return;
  }

  QgsGeometry featureGeometry = f.geometry();
  QgsGeometry convexGeometry = featureGeometry.convexHull();

  if ( nProcessedFeatures == 0 )
  {
    dissolveGeometry = convexGeometry;
  }
  else
  {
    dissolveGeometry = dissolveGeometry.combine( convexGeometry );
  }
}