void QgsDelimitedTextProvider::scanFile( bool buildIndexes )
{
  QStringList messages;

  // assume the layer is invalid until proven otherwise

  mLayerValid = false;
  mValid = false;
  mRescanRequired = false;

  clearInvalidLines();

  // Initiallize indexes

  resetIndexes();
  bool buildSpatialIndex = buildIndexes && mSpatialIndex != 0;

  // No point building a subset index if there is no geometry, as all
  // records will be included.

  bool buildSubsetIndex = buildIndexes && mBuildSubsetIndex && mGeomRep != GeomNone;

  if ( ! mFile->isValid() )
  {
    // uri is invalid so the layer must be too...

    messages.append( tr( "File cannot be opened or delimiter parameters are not valid" ) );
    reportErrors( messages );
    QgsDebugMsg( "Delimited text source invalid - filename or delimiter parameters" );
    return;
  }

  // Open the file and get number of rows, etc. We assume that the
  // file has a header row and process accordingly. Caller should make
  // sure that the delimited file is properly formed.

  if ( mGeomRep == GeomAsWkt )
  {
    mWktFieldIndex = mFile->fieldIndex( mWktFieldName );
    if ( mWktFieldIndex < 0 )
    {
      messages.append( tr( "%0 field %1 is not defined in delimited text file" ).arg( "Wkt" ).arg( mWktFieldName ) );
    }
  }
  else if ( mGeomRep == GeomAsXy )
  {
    mXFieldIndex = mFile->fieldIndex( mXFieldName );
    mYFieldIndex = mFile->fieldIndex( mYFieldName );
    if ( mXFieldIndex < 0 )
    {
      messages.append( tr( "%0 field %1 is not defined in delimited text file" ).arg( "X" ).arg( mWktFieldName ) );
    }
    if ( mYFieldIndex < 0 )
    {
      messages.append( tr( "%0 field %1 is not defined in delimited text file" ).arg( "Y" ).arg( mWktFieldName ) );
    }
  }
  if ( messages.size() > 0 )
  {
    reportErrors( messages );
    QgsDebugMsg( "Delimited text source invalid - missing geometry fields" );
    return;
  }

  // Scan the entire file to determine
  // 1) the number of fields (this is handled by QgsDelimitedTextFile mFile
  // 2) the number of valid features.  Note that the selection of valid features
  //    should match the code in QgsDelimitedTextFeatureIterator
  // 3) the geometric extents of the layer
  // 4) the type of each field
  //
  // Also build subset and spatial indexes.

  QStringList parts;
  long nEmptyRecords = 0;
  long nBadFormatRecords = 0;
  long nIncompatibleGeometry = 0;
  long nInvalidGeometry = 0;
  long nEmptyGeometry = 0;
  mNumberFeatures = 0;
  mExtent = QgsRectangle();

  QList<bool> isEmpty;
  QList<bool> couldBeInt;
  QList<bool> couldBeDouble;

  while ( true )
  {
    QgsDelimitedTextFile::Status status = mFile->nextRecord( parts );
    if ( status == QgsDelimitedTextFile::RecordEOF ) break;
    if ( status != QgsDelimitedTextFile::RecordOk )
    {
      nBadFormatRecords++;
      recordInvalidLine( tr( "Invalid record format at line %1" ) );
      continue;
    }
    // Skip over empty records
    if ( recordIsEmpty( parts ) )
    {
      nEmptyRecords++;
      continue;
    }

    // Check geometries are valid
    bool geomValid = true;

    if ( mGeomRep == GeomAsWkt )
    {
      if ( mWktFieldIndex >= parts.size() || parts[mWktFieldIndex].isEmpty() )
      {
        nEmptyGeometry++;
        geomValid = false;
      }
      else
      {
        // Get the wkt - confirm it is valid, get the type, and
        // if compatible with the rest of file, add to the extents

        QString sWkt = parts[mWktFieldIndex];
        QgsGeometry *geom = 0;
        if ( !mWktHasPrefix && sWkt.indexOf( WktPrefixRegexp ) >= 0 )
          mWktHasPrefix = true;
        if ( !mWktHasZM && sWkt.indexOf( WktZMRegexp ) >= 0 )
          mWktHasZM = true;
        geom = geomFromWkt( sWkt, mWktHasPrefix, mWktHasZM );

        if ( geom )
        {
          QGis::WkbType type = geom->wkbType();
          if ( type != QGis::WKBNoGeometry )
          {
            if ( mGeometryType == QGis::UnknownGeometry || geom->type() == mGeometryType )
            {
              mGeometryType = geom->type();
              if ( mNumberFeatures == 0 )
              {
                mNumberFeatures++;
                mWkbType = type;
                mExtent = geom->boundingBox();
              }
              else
              {
                mNumberFeatures++;
                if ( geom->isMultipart() ) mWkbType = type;
                QgsRectangle bbox( geom->boundingBox() );
                mExtent.combineExtentWith( &bbox );
              }
              if ( buildSpatialIndex )
              {
                QgsFeature f;
                f.setFeatureId( mFile->recordId() );
                f.setGeometry( geom );
                mSpatialIndex->insertFeature( f );
                // Feature now has ownership of geometry, so set to null
                // here to avoid deleting twice.
                geom = 0;
              }
            }
            else
            {
              nIncompatibleGeometry++;
              geomValid = false;
            }
          }
          if ( geom ) delete geom;
        }
        else
        {
          geomValid = false;
          nInvalidGeometry++;
          recordInvalidLine( tr( "Invalid WKT at line %1" ) );
        }
      }
    }
    else if ( mGeomRep == GeomAsXy )
    {
      // Get the x and y values, first checking to make sure they
      // aren't null.

      QString sX = mXFieldIndex < parts.size() ? parts[mXFieldIndex] : "";
      QString sY = mYFieldIndex < parts.size() ? parts[mYFieldIndex] : "";
      if ( sX.isEmpty() && sY.isEmpty() )
      {
        geomValid = false;
        nEmptyGeometry++;
      }
      else
      {
        QgsPoint pt;
        bool ok = pointFromXY( sX, sY, pt, mDecimalPoint, mXyDms );

        if ( ok )
        {
          if ( mNumberFeatures > 0 )
          {
            mExtent.combineExtentWith( pt.x(), pt.y() );
          }
          else
          {
            // Extent for the first point is just the first point
            mExtent.set( pt.x(), pt.y(), pt.x(), pt.y() );
            mWkbType = QGis::WKBPoint;
            mGeometryType = QGis::Point;
          }
          mNumberFeatures++;
          if ( buildSpatialIndex && qIsFinite( pt.x() ) && qIsFinite( pt.y() ) )
          {
            QgsFeature f;
            f.setFeatureId( mFile->recordId() );
            f.setGeometry( QgsGeometry::fromPoint( pt ) );
            mSpatialIndex->insertFeature( f );
          }
        }
        else
        {
          geomValid = false;
          nInvalidGeometry++;
          recordInvalidLine( tr( "Invalid X or Y fields at line %1" ) );
        }
      }
    }
    else
    {
      mWkbType = QGis::WKBNoGeometry;
      mNumberFeatures++;
    }

    if ( ! geomValid ) continue;

    if ( buildSubsetIndex ) mSubsetIndex.append( mFile->recordId() );


    // If we are going to use this record, then assess the potential types of each colum

    for ( int i = 0; i < parts.size(); i++ )
    {

      QString &value = parts[i];
      if ( value.isEmpty() )
        continue;

      // try to convert attribute values to integer and double

      while ( couldBeInt.size() <= i )
      {
        isEmpty.append( true );
        couldBeInt.append( false );
        couldBeDouble.append( false );
      }
      if ( isEmpty[i] )
      {
        isEmpty[i] = false;
        couldBeInt[i] = true;
        couldBeDouble[i] = true;
      }
      if ( couldBeInt[i] )
      {
        value.toInt( &couldBeInt[i] );
      }
      if ( couldBeDouble[i] )
      {
        if ( ! mDecimalPoint.isEmpty() )
        {
          value.replace( mDecimalPoint, "." );
        }
        value.toDouble( &couldBeDouble[i] );
      }
    }
  }

  // Now create the attribute fields.  Field types are integer by preference,
  // failing that double, failing that text.

  QStringList fieldNames = mFile->fieldNames();
  mFieldCount = fieldNames.size();
  attributeColumns.clear();
  attributeFields.clear();

  QString csvtMessage;
  QStringList csvtTypes = readCsvtFieldTypes( mFile->fileName(), &csvtMessage );

  for ( int i = 0; i < fieldNames.size(); i++ )
  {
    // Skip over WKT field ... don't want to display in attribute table
    if ( i == mWktFieldIndex ) continue;

    // Add the field index lookup for the column
    attributeColumns.append( i );
    QVariant::Type fieldType = QVariant::String;
    QString typeName = "text";
    if ( i < csvtTypes.size() )
    {
      if ( csvtTypes[i] == "integer" )
      {
        fieldType = QVariant::Int;
        typeName = "integer";
      }
      else if ( csvtTypes[i] == "real" )
      {
        fieldType = QVariant::Double;
        typeName = "double";
      }
    }
    else if ( i < couldBeInt.size() )
    {
      if ( couldBeInt[i] )
      {
        fieldType = QVariant::Int;
        typeName = "integer";
      }
      else if ( couldBeDouble[i] )
      {
        fieldType = QVariant::Double;
        typeName = "double";
      }
    }
    attributeFields.append( QgsField( fieldNames[i], fieldType, typeName ) );
  }


  QgsDebugMsg( "Field count for the delimited text file is " + QString::number( attributeFields.size() ) );
  QgsDebugMsg( "geometry type is: " + QString::number( mWkbType ) );
  QgsDebugMsg( "feature count is: " + QString::number( mNumberFeatures ) );

  QStringList warnings;
  if ( ! csvtMessage.isEmpty() ) warnings.append( csvtMessage );
  if ( nBadFormatRecords > 0 )
    warnings.append( tr( "%1 records discarded due to invalid format" ).arg( nBadFormatRecords ) );
  if ( nEmptyGeometry > 0 )
    warnings.append( tr( "%1 records discarded due to missing geometry definitions" ).arg( nEmptyGeometry ) );
  if ( nInvalidGeometry > 0 )
    warnings.append( tr( "%1 records discarded due to invalid geometry definitions" ).arg( nInvalidGeometry ) );
  if ( nIncompatibleGeometry > 0 )
    warnings.append( tr( "%1 records discarded due to incompatible geometry types" ).arg( nIncompatibleGeometry ) );

  reportErrors( warnings );

  // Decide whether to use subset ids to index records rather than simple iteration through all
  // If more than 10% of records are being skipped, then use index.  (Not based on any experimentation,
  // could do with some analysis?)

  if ( buildSubsetIndex )
  {
    long recordCount = mFile->recordCount();
    recordCount -= recordCount / SUBSET_ID_THRESHOLD_FACTOR;
    mUseSubsetIndex = mSubsetIndex.size() < recordCount;
    if ( ! mUseSubsetIndex ) mSubsetIndex = QList<quintptr>();
  }

  mUseSpatialIndex = buildSpatialIndex;

  mValid = mGeometryType != QGis::UnknownGeometry;
  mLayerValid = mValid;

  // If it is valid, then watch for changes to the file
  connect( mFile, SIGNAL( fileUpdated() ), this, SLOT( onFileUpdated() ) );


}
Example #2
0
bool QgsOgrFeatureIterator::readFeature( gdal::ogr_feature_unique_ptr fet, QgsFeature &feature ) const
{
  feature.setId( OGR_F_GetFID( fet.get() ) );
  feature.initAttributes( mSource->mFields.count() );
  feature.setFields( mSource->mFields ); // allow name-based attribute lookups

  bool useIntersect = !mRequest.filterRect().isNull();
  bool geometryTypeFilter = mSource->mOgrGeometryTypeFilter != wkbUnknown;
  if ( mFetchGeometry || useIntersect || geometryTypeFilter )
  {
    OGRGeometryH geom = OGR_F_GetGeometryRef( fet.get() );

    if ( geom )
    {
      QgsGeometry g = QgsOgrUtils::ogrGeometryToQgsGeometry( geom );

      // Insure that multipart datasets return multipart geometry
      if ( QgsWkbTypes::isMultiType( mSource->mWkbType ) && !g.isMultipart() )
      {
        g.convertToMultiType();
      }

      feature.setGeometry( g );
    }
    else
      feature.clearGeometry();

    if ( mSource->mOgrGeometryTypeFilter == wkbGeometryCollection &&
         geom && wkbFlatten( OGR_G_GetGeometryType( geom ) ) == wkbGeometryCollection )
    {
      // OK
    }
    else if ( ( useIntersect && ( !feature.hasGeometry()
                                  || ( mRequest.flags() & QgsFeatureRequest::ExactIntersect && !feature.geometry().intersects( mFilterRect ) )
                                  || ( !( mRequest.flags() & QgsFeatureRequest::ExactIntersect ) && !feature.geometry().boundingBoxIntersects( mFilterRect ) )
                                )
              )
              || ( geometryTypeFilter && ( !feature.hasGeometry() || QgsOgrProvider::ogrWkbSingleFlatten( ( OGRwkbGeometryType )feature.geometry().wkbType() ) != mSource->mOgrGeometryTypeFilter ) ) )
    {
      return false;
    }
  }

  if ( !mFetchGeometry )
  {
    feature.clearGeometry();
  }

  // fetch attributes
  if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes )
  {
    QgsAttributeList attrs = mRequest.subsetOfAttributes();
    for ( QgsAttributeList::const_iterator it = attrs.constBegin(); it != attrs.constEnd(); ++it )
    {
      getFeatureAttribute( fet.get(), feature, *it );
    }
  }
  else
  {
    // all attributes
    const auto fieldCount = mSource->mFields.count();
    for ( int idx = 0; idx < fieldCount; ++idx )
    {
      getFeatureAttribute( fet.get(), feature, idx );
    }
  }

  return true;
}
void QgsVectorLayerEditBuffer::updateFeatureGeometry( QgsFeature &f )
{
  if ( mChangedGeometries.contains( f.id() ) )
    f.setGeometry( mChangedGeometries[f.id()] );
}
Example #4
0
bool QgsOgrFeatureIterator::readFeature( OGRFeatureH fet, QgsFeature& feature )
{
  feature.setFeatureId( OGR_F_GetFID( fet ) );
  feature.initAttributes( mSource->mFields.count() );
  feature.setFields( &mSource->mFields ); // allow name-based attribute lookups

  bool useIntersect = mRequest.flags() & QgsFeatureRequest::ExactIntersect;
  bool geometryTypeFilter = mSource->mOgrGeometryTypeFilter != wkbUnknown;
  if ( mFetchGeometry || useIntersect || geometryTypeFilter )
  {
    OGRGeometryH geom = OGR_F_GetGeometryRef( fet );

    if ( geom )
    {
      if ( mGeometrySimplifier )
        mGeometrySimplifier->simplifyGeometry( geom );

      // get the wkb representation
      int memorySize = OGR_G_WkbSize( geom );
      unsigned char *wkb = new unsigned char[memorySize];
      OGR_G_ExportToWkb( geom, ( OGRwkbByteOrder ) QgsApplication::endian(), wkb );

      QgsGeometry* geometry = feature.geometry();
      if ( !geometry ) feature.setGeometryAndOwnership( wkb, memorySize ); else geometry->fromWkb( wkb, memorySize );
    }
    else
      feature.setGeometry( 0 );

    if (( useIntersect && ( !feature.geometry() || !feature.geometry()->intersects( mRequest.filterRect() ) ) )
        || ( geometryTypeFilter && ( !feature.geometry() || QgsOgrProvider::ogrWkbSingleFlatten(( OGRwkbGeometryType )feature.geometry()->wkbType() ) != mSource->mOgrGeometryTypeFilter ) ) )
    {
      OGR_F_Destroy( fet );
      return false;
    }
  }

  if ( !mFetchGeometry )
  {
    feature.setGeometry( 0 );
  }

  // fetch attributes
  if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes )
  {
    const QgsAttributeList& attrs = mRequest.subsetOfAttributes();
    for ( QgsAttributeList::const_iterator it = attrs.begin(); it != attrs.end(); ++it )
    {
      getFeatureAttribute( fet, feature, *it );
    }
  }
  else
  {
    // all attributes
    for ( int idx = 0; idx < mSource->mFields.count(); ++idx )
    {
      getFeatureAttribute( fet, feature, idx );
    }
  }

  return true;
}
Example #5
0
void QgsGeometryTypeCheck::fixError( QgsGeometryCheckError* error, int method, int /*mergeAttributeIndex*/, Changes &changes ) const
{
  QgsFeature feature;
  if ( !mFeaturePool->get( error->featureId(), feature ) )
  {
    error->setObsolete();
    return;
  }
  QgsAbstractGeometryV2* geom = feature.geometry()->geometry();

  // Check if error still applies
  QgsWKBTypes::Type type = QgsWKBTypes::flatType( geom->wkbType() );
  if (( mAllowedTypes & ( 1 << type ) ) != 0 )
  {
    error->setObsolete();
    return;
  }

  // Fix with selected method
  if ( method == NoChange )
  {
    error->setFixed( method );
  }
  else if ( method == Convert )
  {
    // Check if corresponding single type is allowed
    if ( QgsWKBTypes::isMultiType( type ) && (( 1 << QgsWKBTypes::singleType( type ) ) & mAllowedTypes ) != 0 )
    {
      // Explode multi-type feature into single-type features
      for ( int iPart = 1, nParts = geom->partCount(); iPart < nParts; ++iPart )
      {
        QgsFeature newFeature;
        newFeature.setAttributes( feature.attributes() );
        newFeature.setGeometry( new QgsGeometry( QgsGeomUtils::getGeomPart( geom, iPart )->clone() ) );
        mFeaturePool->addFeature( newFeature );
        changes[newFeature.id()].append( Change( ChangeFeature, ChangeAdded ) );
      }
      // Recycle feature for part 0
      feature.setGeometry( new QgsGeometry( QgsGeomUtils::getGeomPart( geom, 0 )->clone() ) );
      mFeaturePool->updateFeature( feature );
      changes[feature.id()].append( Change( ChangeFeature, ChangeChanged ) );
    }
    // Check if corresponding multi type is allowed
    else if ( QgsWKBTypes::isSingleType( type ) && (( 1 << QgsWKBTypes::multiType( type ) ) & mAllowedTypes ) != 0 )
    {
      QgsGeometryCollectionV2* geomCollection = nullptr;
      switch ( QgsWKBTypes::multiType( type ) )
      {
        case QgsWKBTypes::MultiPoint:
        {
          geomCollection = new QgsMultiPointV2();
          break;
        }
        case QgsWKBTypes::MultiLineString:
        {
          geomCollection = new QgsMultiLineStringV2();
          break;
        }
        case QgsWKBTypes::MultiPolygon:
        {
          geomCollection = new QgsMultiPolygonV2();
          break;
        }
        case QgsWKBTypes::MultiCurve:
        {
          geomCollection = new QgsMultiCurveV2();
          break;
        }
        case QgsWKBTypes::MultiSurface:
        {
          geomCollection = new QgsMultiSurfaceV2();
          break;
        }
        default:
          break;
      }
      if ( !geomCollection )
      {
        error->setFixFailed( tr( "Unknown geometry type" ) );
      }
      else
      {
        geomCollection->addGeometry( geom->clone() );

        feature.setGeometry( new QgsGeometry( geomCollection ) );
        mFeaturePool->updateFeature( feature );
        changes[feature.id()].append( Change( ChangeFeature, ChangeChanged ) );
      }
    }
    // Delete feature
    else
    {
      mFeaturePool->deleteFeature( feature );
      changes[error->featureId()].append( Change( ChangeFeature, ChangeRemoved ) );
    }
    error->setFixed( method );
  }
  else if ( method == Delete )
  {
    mFeaturePool->deleteFeature( feature );
    error->setFixed( method );
    changes[error->featureId()].append( Change( ChangeFeature, ChangeRemoved ) );
  }
  else
  {
    error->setFixFailed( tr( "Unknown method" ) );
  }
}
bool QgsGeometryAnalyzer::dissolve( QgsVectorLayer* layer, const QString& shapefileName,
                                    bool onlySelectedFeatures, int uniqueIdField, QProgressDialog* p )
{
    if ( !layer )
    {
        return false;
    }
    QgsVectorDataProvider* dp = layer->dataProvider();
    if ( !dp )
    {
        return false;
    }
    bool useField = false;
    if ( uniqueIdField == -1 )
    {
        uniqueIdField = 0;
    }
    else
    {
        useField = true;
    }

    QGis::WkbType outputType = dp->geometryType();
    QgsCoordinateReferenceSystem crs = layer->crs();

    QgsVectorFileWriter vWriter( shapefileName, dp->encoding(), layer->fields(), outputType, &crs );
    QgsFeature currentFeature;
    QMultiMap<QString, QgsFeatureId> map;

    if ( onlySelectedFeatures )
    {
        //use QgsVectorLayer::featureAtId
        const QgsFeatureIds selection = layer->selectedFeaturesIds();
        QgsFeatureIds::const_iterator it = selection.constBegin();
        for ( ; it != selection.constEnd(); ++it )
        {
            if ( !layer->getFeatures( QgsFeatureRequest().setFilterFid( *it ) ).nextFeature( currentFeature ) )
            {
                continue;
            }
            map.insert( currentFeature.attribute( uniqueIdField ).toString(), currentFeature.id() );
        }
    }
    else
    {
        QgsFeatureIterator fit = layer->getFeatures();
        while ( fit.nextFeature( currentFeature ) )
        {
            map.insert( currentFeature.attribute( uniqueIdField ).toString(), currentFeature.id() );
        }
    }

    QgsGeometry *dissolveGeometry = nullptr; //dissolve geometry
    QMultiMap<QString, QgsFeatureId>::const_iterator jt = map.constBegin();
    QgsFeature outputFeature;
    while ( jt != map.constEnd() )
    {
        QString currentKey = jt.key();
        int processedFeatures = 0;
        bool first = true;
        //take only selection
        if ( onlySelectedFeatures )
        {
            //use QgsVectorLayer::featureAtId
            const QgsFeatureIds selection = layer->selectedFeaturesIds();
            if ( p )
            {
                p->setMaximum( selection.size() );
            }
            while ( jt != map.constEnd() && ( jt.key() == currentKey || !useField ) )
            {
                if ( p && p->wasCanceled() )
                {
                    break;
                }
                if ( selection.contains( jt.value() ) )
                {
                    if ( p )
                    {
                        p->setValue( processedFeatures );
                    }
                    if ( !layer->getFeatures( QgsFeatureRequest().setFilterFid( jt.value() ) ).nextFeature( currentFeature ) )
                    {
                        continue;
                    }
                    if ( first )
                    {
                        outputFeature.setAttributes( currentFeature.attributes() );
                        first = false;
                    }
                    dissolveFeature( currentFeature, processedFeatures, &dissolveGeometry );
                    ++processedFeatures;
                }
                ++jt;
            }
        }
        //take all features
        else
        {
            int featureCount = layer->featureCount();
            if ( p )
            {
                p->setMaximum( featureCount );
            }
            while ( jt != map.constEnd() && ( jt.key() == currentKey || !useField ) )
            {
                if ( p )
                {
                    p->setValue( processedFeatures );
                }

                if ( p && p->wasCanceled() )
                {
                    break;
                }
                if ( !layer->getFeatures( QgsFeatureRequest().setFilterFid( jt.value() ) ).nextFeature( currentFeature ) )
                {
                    continue;
                }
                {
                    outputFeature.setAttributes( currentFeature.attributes() );
                    first = false;
                }
                dissolveFeature( currentFeature, processedFeatures, &dissolveGeometry );
                ++processedFeatures;
                ++jt;
            }
        }
        outputFeature.setGeometry( dissolveGeometry );
        vWriter.addFeature( outputFeature );
    }
    return true;
}
bool QgsGeometryAnalyzer::buffer( QgsVectorLayer* layer, const QString& shapefileName, double bufferDistance,
                                  bool onlySelectedFeatures, bool dissolve, int bufferDistanceField, QProgressDialog* p )
{
    if ( !layer )
    {
        return false;
    }

    QgsVectorDataProvider* dp = layer->dataProvider();
    if ( !dp )
    {
        return false;
    }

    QGis::WkbType outputType = QGis::WKBPolygon;
    if ( dissolve )
    {
        outputType = QGis::WKBMultiPolygon;
    }
    QgsCoordinateReferenceSystem crs = layer->crs();

    QgsVectorFileWriter vWriter( shapefileName, dp->encoding(), layer->fields(), outputType, &crs );
    QgsFeature currentFeature;
    QgsGeometry *dissolveGeometry = nullptr; //dissolve geometry (if dissolve enabled)

    //take only selection
    if ( onlySelectedFeatures )
    {
        //use QgsVectorLayer::featureAtId
        const QgsFeatureIds selection = layer->selectedFeaturesIds();
        if ( p )
        {
            p->setMaximum( selection.size() );
        }

        int processedFeatures = 0;
        QgsFeatureIds::const_iterator it = selection.constBegin();
        for ( ; it != selection.constEnd(); ++it )
        {
            if ( p )
            {
                p->setValue( processedFeatures );
            }

            if ( p && p->wasCanceled() )
            {
                break;
            }
            if ( !layer->getFeatures( QgsFeatureRequest().setFilterFid( *it ) ).nextFeature( currentFeature ) )
            {
                continue;
            }
            bufferFeature( currentFeature, processedFeatures, &vWriter, dissolve, &dissolveGeometry, bufferDistance, bufferDistanceField );
            ++processedFeatures;
        }

        if ( p )
        {
            p->setValue( selection.size() );
        }
    }
    //take all features
    else
    {
        QgsFeatureIterator fit = layer->getFeatures();

        int featureCount = layer->featureCount();
        if ( p )
        {
            p->setMaximum( featureCount );
        }
        int processedFeatures = 0;

        while ( fit.nextFeature( currentFeature ) )
        {
            if ( p )
            {
                p->setValue( processedFeatures );
            }
            if ( p && p->wasCanceled() )
            {
                break;
            }
            bufferFeature( currentFeature, processedFeatures, &vWriter, dissolve, &dissolveGeometry, bufferDistance, bufferDistanceField );
            ++processedFeatures;
        }
        if ( p )
        {
            p->setValue( featureCount );
        }
    }

    if ( dissolve )
    {
        QgsFeature dissolveFeature;
        if ( !dissolveGeometry )
        {
            QgsDebugMsg( "no dissolved geometry - should not happen" );
            return false;
        }
        dissolveFeature.setGeometry( dissolveGeometry );
        vWriter.addFeature( dissolveFeature );
    }
    return true;
}
bool QgsGeometryAnalyzer::convexHull( QgsVectorLayer* layer, const QString& shapefileName,
                                      bool onlySelectedFeatures, int uniqueIdField, QProgressDialog* p )
{
    if ( !layer )
    {
        return false;
    }
    QgsVectorDataProvider* dp = layer->dataProvider();
    if ( !dp )
    {
        return false;
    }
    bool useField = false;
    if ( uniqueIdField == -1 )
    {
        uniqueIdField = 0;
    }
    else
    {
        useField = true;
    }
    QgsFields fields;
    fields.append( QgsField( QString( "UID" ), QVariant::String ) );
    fields.append( QgsField( QString( "AREA" ), QVariant::Double ) );
    fields.append( QgsField( QString( "PERIM" ), QVariant::Double ) );

    QGis::WkbType outputType = QGis::WKBPolygon;
    QgsCoordinateReferenceSystem crs = layer->crs();

    QgsVectorFileWriter vWriter( shapefileName, dp->encoding(), fields, outputType, &crs );
    QgsFeature currentFeature;
    QgsGeometry* dissolveGeometry = nullptr; //dissolve geometry
    QMultiMap<QString, QgsFeatureId> map;

    if ( onlySelectedFeatures )
    {
        //use QgsVectorLayer::featureAtId
        const QgsFeatureIds selection = layer->selectedFeaturesIds();
        QgsFeatureIds::const_iterator it = selection.constBegin();
        for ( ; it != selection.constEnd(); ++it )
        {
#if 0
            if ( p )
            {
                p->setValue( processedFeatures );
            }
            if ( p && p->wasCanceled() )
            {
                // break; // it may be better to do something else here?
                return false;
            }
#endif
            if ( !layer->getFeatures( QgsFeatureRequest().setFilterFid( *it ) ).nextFeature( currentFeature ) )
            {
                continue;
            }
            map.insert( currentFeature.attribute( uniqueIdField ).toString(), currentFeature.id() );
        }
    }
    else
    {
        QgsFeatureIterator fit = layer->getFeatures();
        while ( fit.nextFeature( currentFeature ) )
        {
#if 0
            if ( p )
            {
                p->setValue( processedFeatures );
            }
            if ( p && p->wasCanceled() )
            {
                // break; // it may be better to do something else here?
                return false;
            }
#endif
            map.insert( currentFeature.attribute( uniqueIdField ).toString(), currentFeature.id() );
        }
    }

    QMultiMap<QString, QgsFeatureId>::const_iterator jt = map.constBegin();
    while ( jt != map.constEnd() )
    {
        QString currentKey = jt.key();
        int processedFeatures = 0;
        //take only selection
        if ( onlySelectedFeatures )
        {
            //use QgsVectorLayer::featureAtId
            const QgsFeatureIds selection = layer->selectedFeaturesIds();
            if ( p )
            {
                p->setMaximum( selection.size() );
            }
            processedFeatures = 0;
            while ( jt != map.constEnd() && ( jt.key() == currentKey || !useField ) )
            {
                if ( p && p->wasCanceled() )
                {
                    break;
                }
                if ( selection.contains( jt.value() ) )
                {
                    if ( p )
                    {
                        p->setValue( processedFeatures );
                    }
                    if ( !layer->getFeatures( QgsFeatureRequest().setFilterFid( jt.value() ) ).nextFeature( currentFeature ) )
                    {
                        continue;
                    }
                    convexFeature( currentFeature, processedFeatures, &dissolveGeometry );
                    ++processedFeatures;
                }
                ++jt;
            }
            QList<double> values;
            if ( !dissolveGeometry )
            {
                QgsDebugMsg( "no dissolved geometry - should not happen" );
                return false;
            }
            dissolveGeometry = dissolveGeometry->convexHull();
            values = simpleMeasure( dissolveGeometry );
            QgsAttributes attributes( 3 );
            attributes[0] = QVariant( currentKey );
            attributes[1] = values.at( 0 );
            attributes[2] = values.at( 1 );
            QgsFeature dissolveFeature;
            dissolveFeature.setAttributes( attributes );
            dissolveFeature.setGeometry( dissolveGeometry );
            vWriter.addFeature( dissolveFeature );
        }
        //take all features
        else
        {
            int featureCount = layer->featureCount();
            if ( p )
            {
                p->setMaximum( featureCount );
            }
            processedFeatures = 0;
            while ( jt != map.constEnd() && ( jt.key() == currentKey || !useField ) )
            {
                if ( p )
                {
                    p->setValue( processedFeatures );
                }

                if ( p && p->wasCanceled() )
                {
                    break;
                }
                if ( !layer->getFeatures( QgsFeatureRequest().setFilterFid( jt.value() ) ).nextFeature( currentFeature ) )
                {
                    continue;
                }
                convexFeature( currentFeature, processedFeatures, &dissolveGeometry );
                ++processedFeatures;
                ++jt;
            }
            QList<double> values;
            // QgsGeometry* tmpGeometry = 0;
            if ( !dissolveGeometry )
            {
                QgsDebugMsg( "no dissolved geometry - should not happen" );
                return false;
            }
            dissolveGeometry = dissolveGeometry->convexHull();
            // values = simpleMeasure( tmpGeometry );
            values = simpleMeasure( dissolveGeometry );
            QgsAttributes attributes;
            attributes[0] = QVariant( currentKey );
            attributes[1] = QVariant( values[ 0 ] );
            attributes[2] = QVariant( values[ 1 ] );
            QgsFeature dissolveFeature;
            dissolveFeature.setAttributes( attributes );
            dissolveFeature.setGeometry( dissolveGeometry );
            vWriter.addFeature( dissolveFeature );
        }
    }
    return true;
}
bool QgsGeometryAnalyzer::extent( QgsVectorLayer* layer,
                                  const QString& shapefileName,
                                  bool onlySelectedFeatures,
                                  QProgressDialog * )
{
    if ( !layer )
    {
        return false;
    }

    QgsVectorDataProvider* dp = layer->dataProvider();
    if ( !dp )
    {
        return false;
    }

    QGis::WkbType outputType = QGis::WKBPolygon;
    QgsCoordinateReferenceSystem crs = layer->crs();

    QgsFields fields;
    fields.append( QgsField( QString( "MINX" ), QVariant::Double ) );
    fields.append( QgsField( QString( "MINY" ), QVariant::Double ) );
    fields.append( QgsField( QString( "MAXX" ), QVariant::Double ) );
    fields.append( QgsField( QString( "MAXY" ), QVariant::Double ) );
    fields.append( QgsField( QString( "CNTX" ), QVariant::Double ) );
    fields.append( QgsField( QString( "CNTY" ), QVariant::Double ) );
    fields.append( QgsField( QString( "AREA" ), QVariant::Double ) );
    fields.append( QgsField( QString( "PERIM" ), QVariant::Double ) );
    fields.append( QgsField( QString( "HEIGHT" ), QVariant::Double ) );
    fields.append( QgsField( QString( "WIDTH" ), QVariant::Double ) );

    QgsVectorFileWriter vWriter( shapefileName, dp->encoding(), fields, outputType, &crs );

    QgsRectangle rect;
    if ( onlySelectedFeatures )  // take only selection
    {
        rect = layer->boundingBoxOfSelected();
    }
    else
    {
        rect = layer->extent();
    }

    double minx = rect.xMinimum();
    double miny = rect.yMinimum();
    double maxx = rect.xMaximum();
    double maxy = rect.yMaximum();
    double height = rect.height();
    double width = rect.width();
    double cntx = minx + ( width / 2.0 );
    double cnty = miny + ( height / 2.0 );
    double area = width * height;
    double perim = ( 2 * width ) + ( 2 * height );

    QgsFeature feat;
    QgsAttributes attrs( 10 );
    attrs[0] = QVariant( minx );
    attrs[1] = QVariant( miny );
    attrs[2] = QVariant( maxx );
    attrs[3] = QVariant( maxy );
    attrs[4] = QVariant( cntx );
    attrs[5] = QVariant( cnty );
    attrs[6] = QVariant( area );
    attrs[7] = QVariant( perim );
    attrs[8] = QVariant( height );
    attrs[9] = QVariant( width );
    feat.setAttributes( attrs );
    feat.setGeometry( QgsGeometry::fromRect( rect ) );
    vWriter.addFeature( feat );
    return true;
}
Example #10
0
void QgsMapToolOffsetCurve::applyOffset()
{
  QgsVectorLayer* layer = currentVectorLayer();
  if ( !layer )
  {
    deleteRubberBandAndGeometry();
    notifyNotVectorLayer();
    return;
  }

  // no modification
  if ( !mGeometryModified )
  {
    deleteRubberBandAndGeometry();
    layer->destroyEditCommand();
    deleteDistanceWidget();
    return;
  }

  if ( mMultiPartGeometry )
  {
    mModifiedGeometry.convertToMultiType();
  }

  layer->beginEditCommand( tr( "Offset curve" ) );

  bool editOk;
  if ( mSourceLayerId == layer->id() && !mForceCopy )
  {
    editOk = layer->changeGeometry( mModifiedFeature, &mModifiedGeometry );
  }
  else
  {
    QgsFeature f;
    f.setGeometry( mModifiedGeometry );

    //add empty values for all fields (allows inserting attribute values via the feature form in the same session)
    QgsAttributes attrs( layer->fields().count() );
    const QgsFields& fields = layer->fields();
    for ( int idx = 0; idx < fields.count(); ++idx )
    {
      attrs[idx] = QVariant();
    }
    f.setAttributes( attrs );
    editOk = layer->addFeature( f );
  }

  if ( editOk )
  {
    layer->endEditCommand();
  }
  else
  {
    layer->destroyEditCommand();
  }

  deleteRubberBandAndGeometry();
  deleteDistanceWidget();
  delete mSnapVertexMarker;
  mSnapVertexMarker = nullptr;
  mForceCopy = false;
  mCanvas->refresh();
}
bool QgsPostgresFeatureIterator::fetchFeature( QgsFeature& feature )
{
  feature.setValid( false );

  if ( mClosed )
    return false;

  if ( mFeatureQueue.empty() )
  {
    QString fetch = QString( "FETCH FORWARD %1 FROM %2" ).arg( mFeatureQueueSize ).arg( mCursorName );
    QgsDebugMsgLevel( QString( "fetching %1 features." ).arg( mFeatureQueueSize ), 4 );
    if ( mConn->PQsendQuery( fetch ) == 0 ) // fetch features asynchronously
    {
      QgsMessageLog::logMessage( QObject::tr( "Fetching from cursor %1 failed\nDatabase error: %2" ).arg( mCursorName ).arg( mConn->PQerrorMessage() ), QObject::tr( "PostGIS" ) );
    }

    QgsPostgresResult queryResult;
    for ( ;; )
    {
      queryResult = mConn->PQgetResult();
      if ( !queryResult.result() )
        break;

      if ( queryResult.PQresultStatus() != PGRES_TUPLES_OK )
      {
        QgsMessageLog::logMessage( QObject::tr( "Fetching from cursor %1 failed\nDatabase error: %2" ).arg( mCursorName ).arg( mConn->PQerrorMessage() ), QObject::tr( "PostGIS" ) );
        break;
      }

      int rows = queryResult.PQntuples();
      if ( rows == 0 )
        continue;

      for ( int row = 0; row < rows; row++ )
      {
        mFeatureQueue.enqueue( QgsFeature() );
        getFeature( queryResult, row, mFeatureQueue.back() );
      } // for each row in queue
    }
  }

  if ( mFeatureQueue.empty() )
  {
    QgsDebugMsg( QString( "Finished after %1 features" ).arg( mFetched ) );
    close();

    mSource->mShared->ensureFeaturesCountedAtLeast( mFetched );

    return false;
  }

  // Now return the next feature from the queue
  if ( !mFetchGeometry )
  {
    feature.setGeometryAndOwnership( 0, 0 );
  }
  else
  {
    QgsGeometry* featureGeom = mFeatureQueue.front().geometryAndOwnership();
    feature.setGeometry( featureGeom );
  }
  feature.setFeatureId( mFeatureQueue.front().id() );
  feature.setAttributes( mFeatureQueue.front().attributes() );

  mFeatureQueue.dequeue();
  mFetched++;

  feature.setValid( true );
  feature.setFields( &mSource->mFields ); // allow name-based attribute lookups

  return true;
}
Example #12
0
void QgsGeometryAngleCheck::fixError( QgsGeometryCheckError *error, int method, int /*mergeAttributeIndex*/, Changes &changes ) const
{
  QgsFeature feature;
  if ( !mFeaturePool->get( error->featureId(), feature ) )
  {
    error->setObsolete();
    return;
  }
  QgsGeometry g = feature.geometry();
  QgsAbstractGeometry *geometry = g.geometry();
  QgsVertexId vidx = error->vidx();

  // Check if point still exists
  if ( !vidx.isValid( geometry ) )
  {
    error->setObsolete();
    return;
  }

  // Check if error still applies
  int n = QgsGeometryCheckerUtils::polyLineSize( geometry, vidx.part, vidx.ring );
  if ( n == 0 )
  {
    error->setObsolete();
    return;
  }
  const QgsPoint &p1 = geometry->vertexAt( QgsVertexId( vidx.part, vidx.ring, ( vidx.vertex - 1 + n ) % n ) );
  const QgsPoint &p2 = geometry->vertexAt( vidx );
  const QgsPoint &p3 = geometry->vertexAt( QgsVertexId( vidx.part, vidx.ring, ( vidx.vertex + 1 ) % n ) );
  QgsVector v21, v23;
  try
  {
    v21 = QgsVector( p1.x() - p2.x(), p1.y() - p2.y() ).normalized();
    v23 = QgsVector( p3.x() - p2.x(), p3.y() - p2.y() ).normalized();
  }
  catch ( const QgsException & )
  {
    error->setObsolete();
    return;
  }
  double angle = std::acos( v21 * v23 ) / M_PI * 180.0;
  if ( angle >= mMinAngle )
  {
    error->setObsolete();
    return;
  }

  // Fix error
  if ( method == NoChange )
  {
    error->setFixed( method );
  }
  else if ( method == DeleteNode )
  {
    if ( !QgsGeometryCheckerUtils::canDeleteVertex( geometry, vidx.part, vidx.ring ) )
    {
      error->setFixFailed( tr( "Resulting geometry is degenerate" ) );
    }
    else if ( !geometry->deleteVertex( error->vidx() ) )
    {
      error->setFixFailed( tr( "Failed to delete vertex" ) );
    }
    else
    {
      changes[error->featureId()].append( Change( ChangeNode, ChangeRemoved, vidx ) );
      if ( QgsGeometryUtils::sqrDistance2D( p1, p3 ) < QgsGeometryCheckPrecision::tolerance() * QgsGeometryCheckPrecision::tolerance()
           && QgsGeometryCheckerUtils::canDeleteVertex( geometry, vidx.part, vidx.ring ) &&
           geometry->deleteVertex( error->vidx() ) ) // error->vidx points to p3 after removing p2
      {
        changes[error->featureId()].append( Change( ChangeNode, ChangeRemoved, QgsVertexId( vidx.part, vidx.ring, ( vidx.vertex + 1 ) % n ) ) );
      }
      feature.setGeometry( g );
      mFeaturePool->updateFeature( feature );
      error->setFixed( method );
    }
  }
  else
  {
    error->setFixFailed( tr( "Unknown method" ) );
  }
}