Example #1
0
void RgShortestPathWidget::exportPath()
{
  RgExportDlg dlg( this );
  if ( !dlg.exec() )
    return;

  QgsVectorLayer *vl = dlg.mapLayer();
  if ( vl == NULL )
    return;

  QgsPoint p1, p2;
  QgsGraph *path = getPath( p1, p2 );
  if ( path == NULL )
    return;

  QgsCoordinateTransform ct( mPlugin->iface()->mapCanvas()->mapSettings().destinationCrs(),
                             vl->crs() );

  int startVertexIdx = path->findVertex( p1 );
  int stopVertexIdx  = path->findVertex( p2 );

  double time = 0.0;
  double cost = 0.0;

  Unit timeUnit = Unit::byName( mPlugin->timeUnitName() );
  Unit distanceUnit = Unit::byName( mPlugin->distanceUnitName() );

  QgsPolyline p;
  while ( startVertexIdx != stopVertexIdx )
  {
    if ( stopVertexIdx < 0 )
      break;

    QgsGraphArcIdList l = path->vertex( stopVertexIdx ).inArc();
    if ( l.empty() )
      break;
    const QgsGraphArc& e = path->arc( l.front() );

    cost += e.property( 0 ).toDouble();
    time += e.property( 1 ).toDouble();

    p.push_front( ct.transform( path->vertex( e.inVertex() ).point() ) );
    stopVertexIdx = e.outVertex();
  }
  p.push_front( ct.transform( p1 ) );

  QgsFeature f;
  f.initAttributes( vl->pendingFields().count() );
  f.setGeometry( QgsGeometry::fromPolyline( p ) );
  f.setAttribute( 0, cost / distanceUnit.multipler() );
  f.setAttribute( 1, time / timeUnit.multipler() );
  QgsFeatureList features;
  features << f;
  vl->dataProvider()->addFeatures( features );
  vl->updateExtents();

  mPlugin->iface()->mapCanvas()->update();
  delete path;
}
Example #2
0
void QgsGPXFeatureIterator::readAttributes( QgsFeature& feature, const QgsWaypoint& wpt )
{
  // add attributes if they are wanted
  for ( int i = 0; i < mSource->mFields.count(); ++i )
  {
    switch ( mSource->indexToAttr[i] )
    {
      case QgsGPXProvider::NameAttr:
        feature.setAttribute( i, QVariant( wpt.name ) );
        break;
      case QgsGPXProvider::EleAttr:
        if ( wpt.ele != -std::numeric_limits<double>::max() )
          feature.setAttribute( i, QVariant( wpt.ele ) );
        break;
      case QgsGPXProvider::SymAttr:
        feature.setAttribute( i, QVariant( wpt.sym ) );
        break;
      case QgsGPXProvider::CmtAttr:
        feature.setAttribute( i, QVariant( wpt.cmt ) );
        break;
      case QgsGPXProvider::DscAttr:
        feature.setAttribute( i, QVariant( wpt.desc ) );
        break;
      case QgsGPXProvider::SrcAttr:
        feature.setAttribute( i, QVariant( wpt.src ) );
        break;
      case QgsGPXProvider::URLAttr:
        feature.setAttribute( i, QVariant( wpt.url ) );
        break;
      case QgsGPXProvider::URLNameAttr:
        feature.setAttribute( i, QVariant( wpt.urlname ) );
        break;
    }
  }
}
Example #3
0
    void eval_columns()
    {
      QgsFields fields;
      fields.append( QgsField( "x1" ) );
      fields.append( QgsField( "x2" ) );
      fields.append( QgsField( "foo", QVariant::Int ) );

      QgsFeature f;
      f.initAttributes( 3 );
      f.setAttribute( 2, QVariant( 20 ) );

      // good exp
      QgsExpression exp( "foo + 1" );
      bool prepareRes = exp.prepare( fields );
      QCOMPARE( prepareRes, true );
      QCOMPARE( exp.hasEvalError(), false );
      QVariant res = exp.evaluate( &f );
      QCOMPARE( res.type(), QVariant::Int );
      QCOMPARE( res.toInt(), 21 );

      // bad exp
      QgsExpression exp2( "bar + 1" );
      bool prepareRes2 = exp2.prepare( fields );
      QCOMPARE( prepareRes2, false );
      QCOMPARE( exp2.hasEvalError(), true );
      QVariant res2 = exp2.evaluate( &f );
      QCOMPARE( res2.type(), QVariant::Invalid );
    }
Example #4
0
void QgsOgrFeatureIterator::getFeatureAttribute( OGRFeatureH ogrFet, QgsFeature & f, int attindex ) const
{
  if ( mSource->mFirstFieldIsFid && attindex == 0 )
  {
    f.setAttribute( 0, static_cast<qint64>( OGR_F_GetFID( ogrFet ) ) );
    return;
  }

  int attindexWithoutFid = ( mSource->mFirstFieldIsFid ) ? attindex - 1 : attindex;
  bool ok = false;
  QVariant value = QgsOgrUtils::getOgrFeatureAttribute( ogrFet, mSource->mFieldsWithoutFid, attindexWithoutFid, mSource->mEncoding, &ok );
  if ( !ok )
    return;

  f.setAttribute( attindex, value );
}
Example #5
0
bool QgsVectorLayerImport::addFeature( QgsFeature& feat )
{
  QgsAttributes attrs = feat.attributes();

  QgsFeature newFeat;
  if ( feat.constGeometry() )
    newFeat.setGeometry( *feat.constGeometry() );

  newFeat.initAttributes( mAttributeCount );

  for ( int i = 0; i < attrs.count(); ++i )
  {
    // add only mapped attributes (un-mapped ones will not be present in the
    // destination layer)
    int dstIdx = mOldToNewAttrIdx.value( i, -1 );
    if ( dstIdx < 0 )
      continue;

    QgsDebugMsgLevel( QString( "moving field from pos %1 to %2" ).arg( i ).arg( dstIdx ), 3 );
    newFeat.setAttribute( dstIdx, attrs.at( i ) );
  }

  mFeatureBuffer.append( newFeat );

  if ( mFeatureBuffer.count() >= FEATURE_BUFFER_SIZE )
  {
    return flushBuffer();
  }

  return true;
}
void QgsOgrFeatureIterator::getFeatureAttribute( OGRFeatureH ogrFet, QgsFeature & f, int attindex )
{
  OGRFieldDefnH fldDef = OGR_F_GetFieldDefnRef( ogrFet, attindex );

  if ( ! fldDef )
  {
    QgsDebugMsg( "ogrFet->GetFieldDefnRef(attindex) returns NULL" );
    return;
  }

  QVariant value;

  if ( OGR_F_IsFieldSet( ogrFet, attindex ) )
  {
    switch ( P->mAttributeFields[attindex].type() )
    {
      case QVariant::String: value = QVariant( P->mEncoding->toUnicode( OGR_F_GetFieldAsString( ogrFet, attindex ) ) ); break;
      case QVariant::Int: value = QVariant( OGR_F_GetFieldAsInteger( ogrFet, attindex ) ); break;
      case QVariant::Double: value = QVariant( OGR_F_GetFieldAsDouble( ogrFet, attindex ) ); break;
        //case QVariant::DateTime: value = QVariant(QDateTime::fromString(str)); break;
      default: assert( NULL && "unsupported field type" );
    }
  }
  else
  {
    value = QVariant( QString::null );
  }

  f.setAttribute( attindex, value );
}
Example #7
0
void QgsGPXFeatureIterator::readAttributes( QgsFeature& feature, const QgsTrack& trk )
{
  // add attributes if they are wanted
  for ( int i = 0; i < mSource->mFields.count(); ++i )
  {
    switch ( mSource->indexToAttr[i] )
    {
      case QgsGPXProvider::NameAttr:
        feature.setAttribute( i, QVariant( trk.name ) );
        break;
      case QgsGPXProvider::NumAttr:
        if ( trk.number != std::numeric_limits<int>::max() )
          feature.setAttribute( i, QVariant( trk.number ) );
        break;
      case QgsGPXProvider::CmtAttr:
        feature.setAttribute( i, QVariant( trk.cmt ) );
        break;
      case QgsGPXProvider::DscAttr:
        feature.setAttribute( i, QVariant( trk.desc ) );
        break;
      case QgsGPXProvider::SrcAttr:
        feature.setAttribute( i, QVariant( trk.src ) );
        break;
      case QgsGPXProvider::URLAttr:
        feature.setAttribute( i, QVariant( trk.url ) );
        break;
      case QgsGPXProvider::URLNameAttr:
        feature.setAttribute( i, QVariant( trk.urlname ) );
        break;
    }
  }

}
void QgsWFSFeatureIterator::copyFeature( const QgsFeature* f, QgsFeature& feature, bool fetchGeometry )
{
  Q_UNUSED( fetchGeometry );

  if ( !f )
  {
    return;
  }

  //copy the geometry
  const QgsGeometry* geometry = f->constGeometry();
  if ( geometry && fetchGeometry )
  {
    const unsigned char *geom = geometry->asWkb();
    int geomSize = geometry->wkbSize();
    unsigned char* copiedGeom = new unsigned char[geomSize];
    memcpy( copiedGeom, geom, geomSize );

    QgsGeometry *g = new QgsGeometry();
    g->fromWkb( copiedGeom, geomSize );
    feature.setGeometry( g );
  }
  else
  {
    feature.setGeometry( nullptr );
  }

  //and the attributes
  feature.initAttributes( mSource->mFields.size() );
  for ( int i = 0; i < mSource->mFields.size(); i++ )
  {
    const QVariant &v = f->attributes().value( i );
    if ( v.type() != mSource->mFields.at( i ).type() )
      feature.setAttribute( i, QgsVectorDataProvider::convertValue( mSource->mFields.at( i ).type(), v.toString() ) );
    else
      feature.setAttribute( i, v );
  }

  //id and valid
  feature.setValid( true );
  feature.setFeatureId( f->id() );
  feature.setFields( mSource->mFields ); // allow name-based attribute lookups
}
Example #9
0
bool QgsVectorLayerTools::copyMoveFeatures( QgsVectorLayer* layer, QgsFeatureRequest& request, double dx, double dy, QString* errorMsg ) const
{
    bool res = false;
    if ( !layer || !layer->isEditable() )
    {
        return false;
    }

    QgsFeatureIterator fi = layer->getFeatures( request );
    QgsFeature f;
    QgsAttributeList pkAttrList = layer->pkAttributeList();

    int browsedFeatureCount = 0;
    int couldNotWriteCount = 0;
    int noGeometryCount = 0;

    QgsFeatureIds fidList;

    while ( fi.nextFeature( f ) )
    {
        browsedFeatureCount++;
        // remove pkey values
        Q_FOREACH ( auto idx, pkAttrList )
        {
            f.setAttribute( idx, QVariant() );
        }
        // translate
        if ( f.hasGeometry() )
        {
            QgsGeometry geom = f.geometry();
            geom.translate( dx, dy );
            f.setGeometry( geom );
#ifdef QGISDEBUG
            const QgsFeatureId fid = f.id();
#endif
            // paste feature
            if ( !layer->addFeature( f, false ) )
            {
                couldNotWriteCount++;
                QgsDebugMsg( QString( "Could not add new feature. Original copied feature id: %1" ).arg( fid ) );
            }
            else
            {
                fidList.insert( f.id() );
            }
        }
        else
        {
            noGeometryCount++;
        }
    }
void QgsDelimitedTextFeatureIterator::fetchAttribute( QgsFeature& feature, int fieldIdx, const QStringList& tokens )
{
  if ( fieldIdx < 0 || fieldIdx >= mSource->attributeColumns.count() ) return;
  int column = mSource->attributeColumns[fieldIdx];
  if ( column < 0 || column >= tokens.count() ) return;
  const QString &value = tokens[column];
  QVariant val;
  switch ( mSource->mFields[fieldIdx].type() )
  {
    case QVariant::Int:
    {
      int ivalue = 0;
      bool ok = false;
      if ( ! value.isEmpty() ) ivalue = value.toInt( &ok );
      if ( ok )
        val = QVariant( ivalue );
      else
        val = QVariant( mSource->mFields[fieldIdx].type() );
      break;
    }
    case QVariant::Double:
    {
      double dvalue = 0.0;
      bool ok = false;
      if ( ! value.isEmpty() )
      {
        if ( mSource->mDecimalPoint.isEmpty() )
        {
          dvalue = value.toDouble( &ok );
        }
        else
        {
          dvalue = QString( value ).replace( mSource->mDecimalPoint, "." ).toDouble( &ok );
        }
      }
      if ( ok )
      {
        val = QVariant( dvalue );
      }
      else
      {
        val = QVariant( mSource->mFields[fieldIdx].type() );
      }
      break;
    }
    default:
      val = QVariant( value );
      break;
  }
  feature.setAttribute( fieldIdx, val );
}
void QgsVectorLayerFeatureIterator::FetchJoinInfo::addJoinedAttributesDirect( QgsFeature& f, const QVariant& joinValue ) const
{
  // no memory cache, query the joined values by setting substring
  QString subsetString = joinLayer->dataProvider()->subsetString(); // provider might already have a subset string
  QString bkSubsetString = subsetString;
  if ( !subsetString.isEmpty() )
  {
    subsetString.append( " AND " );
  }

  QString joinFieldName;
  if ( joinInfo->joinFieldName.isEmpty() && joinInfo->joinFieldIndex >= 0 && joinInfo->joinFieldIndex < joinLayer->pendingFields().count() )
    joinFieldName = joinLayer->pendingFields().field( joinInfo->joinFieldIndex ).name();   // for compatibility with 1.x
  else
    joinFieldName = joinInfo->joinFieldName;

  subsetString.append( "\"" + joinFieldName + "\"" + " = " + "\"" + joinValue.toString() + "\"" );
  joinLayer->dataProvider()->setSubsetString( subsetString, false );

  // select (no geometry)
  QgsFeatureRequest request;
  request.setFlags( QgsFeatureRequest::NoGeometry );
  request.setSubsetOfAttributes( attributes );
  QgsFeatureIterator fi = joinLayer->getFeatures( request );

  // get first feature
  QgsFeature fet;
  if ( fi.nextFeature( fet ) )
  {
    int index = indexOffset;
    const QgsAttributes& attr = fet.attributes();
    for ( int i = 0; i < attr.count(); ++i )
    {
      if ( i == joinField )
        continue;

      f.setAttribute( index++, attr[i] );
    }
  }
  else
  {
    // no suitable join feature found, keeping empty (null) attributes
  }

  joinLayer->dataProvider()->setSubsetString( bkSubsetString, false );
}
void QgsOgrFeatureIterator::getFeatureAttribute( OGRFeatureH ogrFet, QgsFeature & f, int attindex )
{
  OGRFieldDefnH fldDef = OGR_F_GetFieldDefnRef( ogrFet, attindex );

  if ( ! fldDef )
  {
    QgsDebugMsg( "ogrFet->GetFieldDefnRef(attindex) returns NULL" );
    return;
  }

  QVariant value;

  if ( OGR_F_IsFieldSet( ogrFet, attindex ) )
  {
    switch ( mSource->mFields.at( attindex ).type() )
    {
      case QVariant::String: value = QVariant( mSource->mEncoding->toUnicode( OGR_F_GetFieldAsString( ogrFet, attindex ) ) ); break;
      case QVariant::Int: value = QVariant( OGR_F_GetFieldAsInteger( ogrFet, attindex ) ); break;
#if defined(GDAL_VERSION_NUM) && GDAL_VERSION_NUM >= 2000000
      case QVariant::LongLong: value = QVariant( OGR_F_GetFieldAsInteger64( ogrFet, attindex ) ); break;
#endif
      case QVariant::Double: value = QVariant( OGR_F_GetFieldAsDouble( ogrFet, attindex ) ); break;
      case QVariant::Date:
      case QVariant::DateTime:
      {
        int year, month, day, hour, minute, second, tzf;

        OGR_F_GetFieldAsDateTime( ogrFet, attindex, &year, &month, &day, &hour, &minute, &second, &tzf );
        if ( mSource->mFields.at( attindex ).type() == QVariant::Date )
          value = QDate( year, month, day );
        else
          value = QDateTime( QDate( year, month, day ), QTime( hour, minute, second ) );
      }
      break;
      default:
        assert( 0 && "unsupported field type" );
    }
  }
  else
  {
    value = QVariant( QString::null );
  }

  f.setAttribute( attindex, value );
}
Example #13
0
bool QgsMssqlFeatureIterator::fetchFeature( QgsFeature& feature )
{
  feature.setValid( false );

  if ( !mQuery )
    return false;

  if ( !mQuery->isActive() )
  {
    QgsDebugMsg( "Read attempt on inactive query" );
    return false;
  }

  if ( mQuery->next() )
  {
    feature.initAttributes( mSource->mFields.count() );
    feature.setFields( &mSource->mFields ); // allow name-based attribute lookups

    for ( int i = 0; i < mAttributesToFetch.count(); i++ )
    {
      QVariant v = mQuery->value( i );
      feature.setAttribute( mAttributesToFetch[i], mQuery->value( i ) );
    }

    if ( mFidCol >= 0 )
    {
      feature.setFeatureId( mQuery->value( mFidCol ).toLongLong() );
    }

    if ( mGeometryCol >= 0 )
    {
      QByteArray ar = mQuery->value( mGeometryCol ).toByteArray();
      unsigned char* wkb = mParser.ParseSqlGeometry(( unsigned char* )ar.data(), ar.size() );
      if ( wkb )
      {
        feature.setGeometryAndOwnership( wkb, mParser.GetWkbLen() );
      }
    }

    feature.setValid( true );
    return true;
  }
  return false;
}
void QgsVectorLayerFeatureIterator::FetchJoinInfo::addJoinedAttributesCached( QgsFeature& f, const QVariant& joinValue ) const
{
  const QHash<QString, QgsAttributes>& memoryCache = joinInfo->cachedAttributes;
  QHash<QString, QgsAttributes>::const_iterator it = memoryCache.find( joinValue.toString() );
  if ( it == memoryCache.constEnd() )
    return; // joined value not found -> leaving the attributes empty (null)

  int index = indexOffset;

  const QgsAttributes& featureAttributes = it.value();
  for ( int i = 0; i < featureAttributes.count(); ++i )
  {
    // skip the join field to avoid double field names (fields often have the same name)
    if ( i == joinField )
      continue;

    f.setAttribute( index++, featureAttributes[i] );
  }
}
Example #15
0
bool QgsOgrUtils::readOgrFeatureAttributes( OGRFeatureH ogrFet, const QgsFields& fields, QgsFeature& feature, QTextCodec* encoding )
{
  // read all attributes
  feature.initAttributes( fields.count() );
  feature.setFields( fields );

  if ( !ogrFet )
    return false;

  bool ok = false;
  for ( int idx = 0; idx < fields.count(); ++idx )
  {
    QVariant value = getOgrFeatureAttribute( ogrFet, fields, idx, encoding, &ok );
    if ( ok )
    {
      feature.setAttribute( idx, value );
    }
  }
  return true;
}
bool QgsOracleFeatureIterator::fetchFeature( QgsFeature& feature )
{
    feature.setValid( false );

    if ( !mQry.isActive() )
        return false;

    for ( ;; )
    {
        feature.initAttributes( mSource->mFields.count() );
        feature.setGeometry( 0 );

        if ( mRewind )
        {
            mRewind = false;
            if ( !mQry.first() )
                return true;
        }
        else if ( !mQry.next() )
        {
            return false;
        }

        int col = 0;

        if (( mRequest.flags() & QgsFeatureRequest::NoGeometry ) == 0 ||
                (( mRequest.flags() & QgsFeatureRequest::ExactIntersect ) != 0 && !mConnection->hasSpatial() ) )
        {
            QByteArray *ba = static_cast<QByteArray*>( mQry.value( col++ ).data() );
            unsigned char *copy = new unsigned char[ba->size()];
            memcpy( copy, ba->constData(), ba->size() );

            feature.setGeometryAndOwnership( copy, ba->size() );

            if ( !mConnection->hasSpatial() &&
                    mRequest.filterType() == QgsFeatureRequest::FilterRect &&
                    ( mRequest.flags() & QgsFeatureRequest::ExactIntersect ) != 0 &&
                    ( !feature.geometry() || !feature.geometry()->intersects( mRequest.filterRect() ) ) )
            {
                // skip feature that don't intersect with our rectangle
                QgsDebugMsg( "no intersect" );
                continue;
            }


            if (( mRequest.flags() & QgsFeatureRequest::NoGeometry ) != 0 )
            {
                feature.setGeometryAndOwnership( 0, 0 );
            }
        }

        QgsFeatureId fid = 0;

        switch ( mSource->mPrimaryKeyType )
        {
        case pktInt:
            // get 64bit integer from result
            fid = mQry.value( col++ ).toLongLong();
            if ( mAttributeList.contains( mSource->mPrimaryKeyAttrs[0] ) )
                feature.setAttribute( mSource->mPrimaryKeyAttrs[0], fid );
            break;

        case pktRowId:
        case pktFidMap:
        {
            QList<QVariant> primaryKeyVals;

            if ( mSource->mPrimaryKeyType == pktFidMap )
            {
                foreach ( int idx, mSource->mPrimaryKeyAttrs )
                {
                    const QgsField &fld = mSource->mFields[idx];

                    QVariant v = mQry.value( col );
                    if ( v.type() != fld.type() )
                        v = QgsVectorDataProvider::convertValue( fld.type(), v.toString() );
                    primaryKeyVals << v;

                    if ( mAttributeList.contains( idx ) )
                        feature.setAttribute( idx, v );

                    col++;
                }
            }
            else
            {
                primaryKeyVals << mQry.value( col++ );
            }

            fid = mSource->mShared->lookupFid( QVariant( primaryKeyVals ) );
        }
        break;

        case pktUnknown:
            Q_ASSERT( !"FAILURE: cannot get feature with unknown primary key" );
            return false;
        }
bool QgsPostgresFeatureIterator::getFeature( QgsPostgresResult &queryResult, int row, QgsFeature &feature )
{
  try
  {
    feature.initAttributes( P->fields().count() );

    int col = 0;

    if ( !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) )
    {
      int returnedLength = ::PQgetlength( queryResult.result(), row, col );
      if ( returnedLength > 0 )
      {
        unsigned char *featureGeom = new unsigned char[returnedLength + 1];
        memset( featureGeom, 0, returnedLength + 1 );
        memcpy( featureGeom, PQgetvalue( queryResult.result(), row, col ), returnedLength );
        feature.setGeometryAndOwnership( featureGeom, returnedLength + 1 );
      }
      else
      {
        feature.setGeometryAndOwnership( 0, 0 );
      }

      col++;
    }

    QgsFeatureId fid = 0;

    bool subsetOfAttributes = mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes;
    const QgsAttributeList& fetchAttributes = mRequest.subsetOfAttributes();

    switch ( P->mPrimaryKeyType )
    {
      case QgsPostgresProvider::pktOid:
      case QgsPostgresProvider::pktTid:
      case QgsPostgresProvider::pktInt:
        fid = P->mConnectionRO->getBinaryInt( queryResult, row, col++ );
        if ( P->mPrimaryKeyType == QgsPostgresProvider::pktInt &&
             ( !subsetOfAttributes || fetchAttributes.contains( P->mPrimaryKeyAttrs[0] ) ) )
          feature.setAttribute( P->mPrimaryKeyAttrs[0], fid );
        break;

      case QgsPostgresProvider::pktFidMap:
      {
        QList<QVariant> primaryKeyVals;

        foreach ( int idx, P->mPrimaryKeyAttrs )
        {
          const QgsField &fld = P->field( idx );

          QVariant v = P->convertValue( fld.type(), queryResult.PQgetvalue( row, col ) );
          primaryKeyVals << v;

          if ( !subsetOfAttributes || fetchAttributes.contains( idx ) )
            feature.setAttribute( idx, v );

          col++;
        }

        fid = P->lookupFid( QVariant( primaryKeyVals ) );
      }
      break;

      case QgsPostgresProvider::pktUnknown:
        Q_ASSERT( !"FAILURE: cannot get feature with unknown primary key" );
        return false;
    }

    feature.setFeatureId( fid );
    QgsDebugMsgLevel( QString( "fid=%1" ).arg( fid ), 4 );

    // iterate attributes
    if ( subsetOfAttributes )
    {
      foreach ( int idx, fetchAttributes )
        getFeatureAttribute( idx, queryResult, row, col, feature );
    }
    else
    {
      for ( int idx = 0; idx < P->mAttributeFields.count(); ++idx )
        getFeatureAttribute( idx, queryResult, row, col, feature );
    }

    return true;
  }
bool QgsPostgresFeatureIterator::getFeature( QgsPostgresResult &queryResult, int row, QgsFeature &feature )
{
    try
    {
        feature.initAttributes( P->fields().count() );

        int col = 0;

        if ( !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) )
        {
            int returnedLength = ::PQgetlength( queryResult.result(), row, col );
            if ( returnedLength > 0 )
            {
                unsigned char *featureGeom = new unsigned char[returnedLength + 1];
                memset( featureGeom, 0, returnedLength + 1 );
                memcpy( featureGeom, PQgetvalue( queryResult.result(), row, col ), returnedLength );

                // modify 2.5D WKB types to make them compliant with OGR
                unsigned int wkbType;
                memcpy( &wkbType, featureGeom + 1, sizeof( wkbType ) );

                // convert unsupported types to supported ones
                switch ( wkbType )
                {
                case 15:
                    // 2D polyhedral => multipolygon
                    wkbType = 6;
                    break;
                case 1015:
                    // 3D polyhedral => multipolygon
                    wkbType = 1006;
                    break;
                case 17:
                    // 2D triangle => polygon
                    wkbType = 3;
                    break;
                case 1017:
                    // 3D triangle => polygon
                    wkbType = 1003;
                    break;
                case 16:
                    // 2D TIN => multipolygon
                    wkbType = 6;
                    break;
                case 1016:
                    // TIN => multipolygon
                    wkbType = 1006;
                    break;
                }
                // convert from postgis types to qgis types
                if ( wkbType >= 1000 )
                {
                    wkbType = wkbType - 1000 + QGis::WKBPoint25D - 1;
                }
                memcpy( featureGeom + 1, &wkbType, sizeof( wkbType ) );

                // change wkb type of inner geometries
                if ( wkbType == QGis::WKBMultiPoint25D ||
                        wkbType == QGis::WKBMultiLineString25D ||
                        wkbType == QGis::WKBMultiPolygon25D )
                {
                    unsigned int numGeoms = *(( int* )( featureGeom + 5 ) );
                    unsigned char* wkb = featureGeom + 9;
                    for ( unsigned int i = 0; i < numGeoms; ++i )
                    {
                        unsigned int localType;
                        memcpy( &localType, wkb + 1, sizeof( localType ) );
                        switch ( localType )
                        {
                        case 15:
                            // 2D polyhedral => multipolygon
                            localType = 6;
                            break;
                        case 1015:
                            // 3D polyhedral => multipolygon
                            localType = 1006;
                            break;
                        case 17:
                            // 2D triangle => polygon
                            localType = 3;
                            break;
                        case 1017:
                            // 3D triangle => polygon
                            localType = 1003;
                            break;
                        case 16:
                            // 2D TIN => multipolygon
                            localType = 6;
                            break;
                        case 1016:
                            // TIN => multipolygon
                            localType = 1006;
                            break;
                        }
                        if ( localType >= 1000 )
                        {
                            localType = localType - 1000 + QGis::WKBPoint25D - 1;
                        }
                        memcpy( wkb + 1, &localType, sizeof( localType ) );

                        // skip endian and type info
                        wkb += sizeof( unsigned int ) + 1;

                        // skip coordinates
                        switch ( wkbType )
                        {
                        case QGis::WKBMultiPoint25D:
                            wkb += sizeof( double ) * 3;
                            break;
                        case QGis::WKBMultiLineString25D:
                        {
                            unsigned int nPoints = *(( int* ) wkb );
                            wkb += sizeof( nPoints );
                            wkb += sizeof( double ) * 3 * nPoints;
                        }
                        break;
                        default:
                        case QGis::WKBMultiPolygon25D:
                        {
                            unsigned int nRings = *(( int* ) wkb );
                            wkb += sizeof( nRings );
                            for ( unsigned int j = 0; j < nRings; ++j )
                            {
                                unsigned int nPoints = *(( int* ) wkb );
                                wkb += sizeof( nPoints );
                                wkb += sizeof( double ) * 3 * nPoints;
                            }
                        }
                        break;
                        }
                    }
                }

                feature.setGeometryAndOwnership( featureGeom, returnedLength + 1 );
            }
            else
            {
                feature.setGeometryAndOwnership( 0, 0 );
            }

            col++;
        }

        QgsFeatureId fid = 0;

        bool subsetOfAttributes = mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes;
        const QgsAttributeList& fetchAttributes = mRequest.subsetOfAttributes();

        switch ( P->mPrimaryKeyType )
        {
        case QgsPostgresProvider::pktOid:
        case QgsPostgresProvider::pktTid:
        case QgsPostgresProvider::pktInt:
            fid = P->mConnectionRO->getBinaryInt( queryResult, row, col++ );
            if ( P->mPrimaryKeyType == QgsPostgresProvider::pktInt &&
                    ( !subsetOfAttributes || fetchAttributes.contains( P->mPrimaryKeyAttrs[0] ) ) )
                feature.setAttribute( P->mPrimaryKeyAttrs[0], fid );
            break;

        case QgsPostgresProvider::pktFidMap:
        {
            QList<QVariant> primaryKeyVals;

            foreach ( int idx, P->mPrimaryKeyAttrs )
            {
                const QgsField &fld = P->field( idx );

                QVariant v = P->convertValue( fld.type(), queryResult.PQgetvalue( row, col ) );
                primaryKeyVals << v;

                if ( !subsetOfAttributes || fetchAttributes.contains( idx ) )
                    feature.setAttribute( idx, v );

                col++;
            }

            fid = P->lookupFid( QVariant( primaryKeyVals ) );
        }
        break;

        case QgsPostgresProvider::pktUnknown:
            Q_ASSERT( !"FAILURE: cannot get feature with unknown primary key" );
            return false;
        }

        feature.setFeatureId( fid );
        QgsDebugMsgLevel( QString( "fid=%1" ).arg( fid ), 4 );

        // iterate attributes
        if ( subsetOfAttributes )
        {
            foreach ( int idx, fetchAttributes )
                getFeatureAttribute( idx, queryResult, row, col, feature );
        }
        else
        {
            for ( int idx = 0; idx < P->mAttributeFields.count(); ++idx )
                getFeatureAttribute( idx, queryResult, row, col, feature );
        }

        return true;
    }
bool QgsPostgresFeatureIterator::getFeature( QgsPostgresResult &queryResult, int row, QgsFeature &feature )
{
    feature.initAttributes( mSource->mFields.count() );

    int col = 0;

    if ( mFetchGeometry )
    {
        int returnedLength = ::PQgetlength( queryResult.result(), row, col );
        if ( returnedLength > 0 )
        {
            unsigned char *featureGeom = new unsigned char[returnedLength + 1];
            memcpy( featureGeom, PQgetvalue( queryResult.result(), row, col ), returnedLength );
            memset( featureGeom + returnedLength, 0, 1 );

            unsigned int wkbType;
            memcpy( &wkbType, featureGeom + 1, sizeof( wkbType ) );
            QgsWKBTypes::Type newType = QgsPostgresConn::wkbTypeFromOgcWkbType( wkbType );

            if (( unsigned int )newType != wkbType )
            {
                // overwrite type
                unsigned int n = newType;
                memcpy( featureGeom + 1, &n, sizeof( n ) );
            }

            // PostGIS stores TIN as a collection of Triangles.
            // Since Triangles are not supported, they have to be converted to Polygons
            const int nDims = 2 + ( QgsWKBTypes::hasZ( newType ) ? 1 : 0 ) + ( QgsWKBTypes::hasM( newType ) ? 1 : 0 );
            if ( wkbType % 1000 == 16 )
            {
                unsigned int numGeoms;
                memcpy( &numGeoms, featureGeom + 5, sizeof( unsigned int ) );
                unsigned char *wkb = featureGeom + 9;
                for ( unsigned int i = 0; i < numGeoms; ++i )
                {
                    const unsigned int localType = QgsWKBTypes::singleType( newType ); // polygon(Z|M)
                    memcpy( wkb + 1, &localType, sizeof( localType ) );

                    // skip endian and type info
                    wkb += sizeof( unsigned int ) + 1;

                    // skip coordinates
                    unsigned int nRings;
                    memcpy( &nRings, wkb, sizeof( int ) );
                    wkb += sizeof( int );
                    for ( unsigned int j = 0; j < nRings; ++j )
                    {
                        unsigned int nPoints;
                        memcpy( &nPoints, wkb, sizeof( int ) );
                        wkb += sizeof( nPoints ) + sizeof( double ) * nDims * nPoints;
                    }
                }
            }

            feature.setGeometryAndOwnership( featureGeom, returnedLength + 1 );
        }
        else
        {
            feature.setGeometryAndOwnership( 0, 0 );
        }

        col++;
    }

    QgsFeatureId fid = 0;

    bool subsetOfAttributes = mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes;
    const QgsAttributeList& fetchAttributes = mRequest.subsetOfAttributes();

    switch ( mSource->mPrimaryKeyType )
    {
    case pktOid:
    case pktTid:
    case pktInt:
        fid = mConn->getBinaryInt( queryResult, row, col++ );
        if ( mSource->mPrimaryKeyType == pktInt &&
                ( !subsetOfAttributes || fetchAttributes.contains( mSource->mPrimaryKeyAttrs[0] ) ) )
            feature.setAttribute( mSource->mPrimaryKeyAttrs[0], fid );
        break;

    case pktFidMap:
    {
        QList<QVariant> primaryKeyVals;

        Q_FOREACH ( int idx, mSource->mPrimaryKeyAttrs )
        {
            const QgsField &fld = mSource->mFields.at( idx );

            QVariant v = QgsPostgresProvider::convertValue( fld.type(), queryResult.PQgetvalue( row, col ) );
            primaryKeyVals << v;

            if ( !subsetOfAttributes || fetchAttributes.contains( idx ) )
                feature.setAttribute( idx, v );

            col++;
        }

        fid = mSource->mShared->lookupFid( QVariant( primaryKeyVals ) );

    }
    break;

    case pktUnknown:
        Q_ASSERT( !"FAILURE: cannot get feature with unknown primary key" );
        return false;
    }

    feature.setFeatureId( fid );
    QgsDebugMsgLevel( QString( "fid=%1" ).arg( fid ), 4 );

    // iterate attributes
    if ( subsetOfAttributes )
    {
        Q_FOREACH ( int idx, fetchAttributes )
            getFeatureAttribute( idx, queryResult, row, col, feature );
    }
    else
    {
        for ( int idx = 0; idx < mSource->mFields.count(); ++idx )
bool QgsVirtualLayerFeatureIterator::fetchFeature( QgsFeature &feature )
{
  feature.setValid( false );

  if ( mClosed )
  {
    return false;
  }


  bool skipFeature = false;
  do
  {
    if ( mQuery->step() != SQLITE_ROW )
    {
      return false;
    }

    feature.setFields( mSource->mFields, /* init */ true );

    if ( mSource->mDefinition.uid().isNull() &&
         mRequest.filterType() != QgsFeatureRequest::FilterFid )
    {
      // no id column => autoincrement
      feature.setId( mFid++ );
    }
    else
    {
      // first column: uid
      feature.setId( mQuery->columnInt64( 0 ) );
    }

    int n = mQuery->columnCount();
    int i = 0;
    const auto constMAttributes = mAttributes;
    for ( int idx : constMAttributes )
    {
      int type = mQuery->columnType( i + 1 );
      switch ( type )
      {
        case SQLITE_INTEGER:
          feature.setAttribute( idx, mQuery->columnInt64( i + 1 ) );
          break;
        case SQLITE_FLOAT:
          feature.setAttribute( idx, mQuery->columnDouble( i + 1 ) );
          break;
        case SQLITE_TEXT:
        default:
          feature.setAttribute( idx, mQuery->columnText( i + 1 ) );
          break;
      };
      i++;
    }
    if ( n > mAttributes.size() + 1 )
    {
      // geometry field
      QByteArray blob( mQuery->columnBlob( n - 1 ) );
      if ( blob.size() > 0 )
      {
        feature.setGeometry( spatialiteBlobToQgsGeometry( blob.constData(), blob.size() ) );
      }
      else
      {
        feature.clearGeometry();
      }
    }

    feature.setValid( true );
    geometryToDestinationCrs( feature, mTransform );

    // if the FilterRect has not been applied on the query
    // apply it here by skipping features until they intersect
    if ( mSource->mDefinition.uid().isNull() && feature.hasGeometry() && mSource->mDefinition.hasDefinedGeometry() && !mFilterRect.isNull() )
    {
      if ( mRequest.flags() & QgsFeatureRequest::ExactIntersect )
      {
        // using exact test when checking for intersection
        skipFeature = !mRectEngine->intersects( feature.geometry().constGet() );
      }
      else
      {
        // check just bounding box against rect when not using intersection
        skipFeature = !feature.geometry().boundingBox().intersects( mFilterRect );
      }
    }
  }
  while ( skipFeature );

  return true;
}
Example #21
0
bool QgsGrassFeatureIterator::fetchFeature( QgsFeature& feature )
{
  if ( mClosed )
    return false;

  feature.setValid( false );
  int cat = -1, type = -1, id = -1;
  QgsFeatureId featureId = -1;

  QgsDebugMsgLevel( "entered.", 3 );

  /* TODO: handle editing
  if ( P->isEdited() || P->isFrozen() || !P->mValid )
  {
    close();
    return false;
  }
  */

  // TODO: is this necessary? the same is checked below
  if ( !QgsGrassProvider::isTopoType( mSource->mLayerType )  && ( mSource->mCidxFieldIndex < 0 || mNextCidx >= mSource->mCidxFieldNumCats ) )
  {
    close();
    return false; // No features, no features in this layer
  }

  bool filterById = mRequest.filterType() == QgsFeatureRequest::FilterFid;

  // Get next line/area id
  int found = 0;
  while ( true )
  {
    QgsDebugMsgLevel( QString( "mNextTopoId = %1" ).arg( mNextTopoId ), 3 );
    if ( mSource->mLayerType == QgsGrassProvider::TOPO_POINT || mSource->mLayerType == QgsGrassProvider::TOPO_LINE )
    {
      if ( mNextTopoId > Vect_get_num_lines( mSource->mMap ) ) break;
      id = mNextTopoId;
      type = Vect_read_line( mSource->mMap, 0, 0, mNextTopoId++ );
      if ( !( type & mSource->mGrassType ) ) continue;
      featureId = id;
    }
    else if ( mSource->mLayerType == QgsGrassProvider::TOPO_NODE )
    {
      if ( mNextTopoId > Vect_get_num_nodes( mSource->mMap ) ) break;
      id = mNextTopoId;
      type = 0;
      mNextTopoId++;
      featureId = id;
    }
    else
    {
      if ( mNextCidx >= mSource->mCidxFieldNumCats ) break;

      Vect_cidx_get_cat_by_index( mSource->mMap, mSource->mCidxFieldIndex, mNextCidx++, &cat, &type, &id );
      // Warning: selection array is only of type line/area of current layer -> check type first
      if ( !( type & mSource->mGrassType ) )
        continue;

      // The 'id' is a unique id of a GRASS geometry object (point, line, area)
      // but it cannot be used as QgsFeatureId because one geometry object may
      // represent more features because it may have more categories.
      featureId = makeFeatureId( id, cat );
    }

    if ( filterById && featureId != mRequest.filterFid() )
      continue;

    // it is correct to use id with mSelection because mSelection is only used
    // for geometry selection
    if ( !mSelection[id] )
      continue;

    found = 1;
    break;
  }
  if ( !found )
  {
    close();
    return false; // No more features
  }
  QgsDebugMsgLevel( QString( "cat = %1 type = %2 id = %3 fatureId = %4" ).arg( cat ).arg( type ).arg( id ).arg( featureId ), 3 );

  feature.setFeatureId( featureId );
  feature.initAttributes( mSource->mFields.count() );
  feature.setFields( &mSource->mFields ); // allow name-based attribute lookups

  if ( mRequest.flags() & QgsFeatureRequest::NoGeometry )
    feature.setGeometry( 0 );
  else
    setFeatureGeometry( feature, id, type );

  if ( ! QgsGrassProvider::isTopoType( mSource->mLayerType ) )
  {
    if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes )
      setFeatureAttributes( cat, &feature, mRequest.subsetOfAttributes() );
    else
      setFeatureAttributes( cat, &feature );
  }
  else
  {
    feature.setAttribute( 0, id );
#if GRASS_VERSION_MAJOR < 7
    if ( mSource->mLayerType == QgsGrassProvider::TOPO_POINT || mSource->mLayerType == QgsGrassProvider::TOPO_LINE )
#else
    /* No more topo points in GRASS 7 */
    if ( mSource->mLayerType == QgsGrassProvider::TOPO_LINE )
#endif
    {
      feature.setAttribute( 1, QgsGrassProvider::primitiveTypeName( type ) );

      int node1, node2;
      Vect_get_line_nodes( mSource->mMap, id, &node1, &node2 );
      feature.setAttribute( 2, node1 );
      if ( mSource->mLayerType == QgsGrassProvider::TOPO_LINE )
      {
        feature.setAttribute( 3, node2 );
      }
    }

    if ( mSource->mLayerType == QgsGrassProvider::TOPO_LINE )
    {
      if ( type == GV_BOUNDARY )
      {
        int left, right;
        Vect_get_line_areas( mSource->mMap, id, &left, &right );
        feature.setAttribute( 4, left );
        feature.setAttribute( 5, right );
      }
    }
    else if ( mSource->mLayerType == QgsGrassProvider::TOPO_NODE )
    {
      QString lines;
      int nlines = Vect_get_node_n_lines( mSource->mMap, id );
      for ( int i = 0; i < nlines; i++ )
      {
        int line = Vect_get_node_line( mSource->mMap, id, i );
        if ( i > 0 ) lines += ",";
        lines += QString::number( line );
      }
      feature.setAttribute( 1, lines );
    }
  }

  feature.setValid( true );

  return true;
}
int QgsTransectSample::createSample( QProgressDialog* pd )
{
  Q_UNUSED( pd );

  if ( !mStrataLayer || !mStrataLayer->isValid() )
  {
    return 1;
  }

  if ( !mBaselineLayer || !mBaselineLayer->isValid() )
  {
    return 2;
  }

  //stratum id is not necessarily an integer
  QVariant::Type stratumIdType = QVariant::Int;
  if ( !mStrataIdAttribute.isEmpty() )
  {
    stratumIdType = mStrataLayer->pendingFields().field( mStrataIdAttribute ).type();
  }

  //create vector file writers for output
  QgsFields outputPointFields;
  outputPointFields.append( QgsField( "id", stratumIdType ) );
  outputPointFields.append( QgsField( "station_id", QVariant::Int ) );
  outputPointFields.append( QgsField( "stratum_id", stratumIdType ) );
  outputPointFields.append( QgsField( "station_code", QVariant::String ) );
  outputPointFields.append( QgsField( "start_lat", QVariant::Double ) );
  outputPointFields.append( QgsField( "start_long", QVariant::Double ) );

  QgsVectorFileWriter outputPointWriter( mOutputPointLayer, "utf-8", outputPointFields, QGis::WKBPoint,
                                         &( mStrataLayer->crs() ) );
  if ( outputPointWriter.hasError() != QgsVectorFileWriter::NoError )
  {
    return 3;
  }

  outputPointFields.append( QgsField( "bearing", QVariant::Double ) ); //add bearing attribute for lines
  QgsVectorFileWriter outputLineWriter( mOutputLineLayer, "utf-8", outputPointFields, QGis::WKBLineString,
                                        &( mStrataLayer->crs() ) );
  if ( outputLineWriter.hasError() != QgsVectorFileWriter::NoError )
  {
    return 4;
  }

  QgsFields usedBaselineFields;
  usedBaselineFields.append( QgsField( "stratum_id", stratumIdType ) );
  usedBaselineFields.append( QgsField( "ok", QVariant::String ) );
  QgsVectorFileWriter usedBaselineWriter( mUsedBaselineLayer, "utf-8", usedBaselineFields, QGis::WKBLineString,
                                          &( mStrataLayer->crs() ) );
  if ( usedBaselineWriter.hasError() != QgsVectorFileWriter::NoError )
  {
    return 5;
  }

  //debug: write clipped buffer bounds with stratum id to same directory as out_point
  QFileInfo outputPointInfo( mOutputPointLayer );
  QString bufferClipLineOutput = outputPointInfo.absolutePath() + "/out_buffer_clip_line.shp";
  QgsFields bufferClipLineFields;
  bufferClipLineFields.append( QgsField( "id", stratumIdType ) );
  QgsVectorFileWriter bufferClipLineWriter( bufferClipLineOutput, "utf-8", bufferClipLineFields, QGis::WKBLineString, &( mStrataLayer->crs() ) );

  //configure distanceArea depending on minDistance units and output CRS
  QgsDistanceArea distanceArea;
  distanceArea.setSourceCrs( mStrataLayer->crs().srsid() );
  if ( mMinDistanceUnits == Meters )
  {
    distanceArea.setEllipsoidalMode( true );
  }
  else
  {
    distanceArea.setEllipsoidalMode( false );
  }

  //possibility to transform output points to lat/long
  QgsCoordinateTransform toLatLongTransform( mStrataLayer->crs(), QgsCoordinateReferenceSystem( 4326, QgsCoordinateReferenceSystem::EpsgCrsId ) );

  //init random number generator
  mt_srand( QTime::currentTime().msec() );

  QgsFeatureRequest fr;
  fr.setSubsetOfAttributes( QStringList() << mStrataIdAttribute << mMinDistanceAttribute << mNPointsAttribute, mStrataLayer->pendingFields() );
  QgsFeatureIterator strataIt = mStrataLayer->getFeatures( fr );

  QgsFeature fet;
  int nTotalTransects = 0;
  int nFeatures = 0;

  if ( pd )
  {
    pd->setMaximum( mStrataLayer->featureCount() );
  }

  while ( strataIt.nextFeature( fet ) )
  {
    if ( pd )
    {
      pd->setValue( nFeatures );
    }
    if ( pd && pd->wasCanceled() )
    {
      break;
    }

    if ( !fet.constGeometry() )
    {
      continue;
    }
    const QgsGeometry* strataGeom = fet.constGeometry();

    //find baseline for strata
    QVariant strataId = fet.attribute( mStrataIdAttribute );
    QgsGeometry* baselineGeom = findBaselineGeometry( strataId.isValid() ? strataId : -1 );
    if ( !baselineGeom )
    {
      continue;
    }

    double minDistance = fet.attribute( mMinDistanceAttribute ).toDouble();
    double minDistanceLayerUnits = minDistance;
    //if minDistance is in meters and the data in degrees, we need to apply a rough conversion for the buffer distance
    double bufferDist = bufferDistance( minDistance );
    if ( mMinDistanceUnits == Meters && mStrataLayer->crs().mapUnits() == QGis::DecimalDegrees )
    {
      minDistanceLayerUnits = minDistance / 111319.9;
    }

    QgsGeometry* clippedBaseline = strataGeom->intersection( baselineGeom );
    if ( !clippedBaseline || clippedBaseline->wkbType() == QGis::WKBUnknown )
    {
      delete clippedBaseline;
      continue;
    }
    QgsGeometry* bufferLineClipped = clipBufferLine( strataGeom, clippedBaseline, bufferDist );
    if ( !bufferLineClipped )
    {
      delete clippedBaseline;
      continue;
    }

    //save clipped baseline to file
    QgsFeature blFeature;
    blFeature.setGeometry( *clippedBaseline );
    blFeature.setAttribute( "stratum_id", strataId );
    blFeature.setAttribute( "ok", "f" );
    usedBaselineWriter.addFeature( blFeature );

    //start loop to create random points along the baseline
    int nTransects = fet.attribute( mNPointsAttribute ).toInt();
    int nCreatedTransects = 0;
    int nIterations = 0;
    int nMaxIterations = nTransects * 50;

    QgsSpatialIndex sIndex; //to check minimum distance
    QMap< QgsFeatureId, QgsGeometry* > lineFeatureMap;

    while ( nCreatedTransects < nTransects && nIterations < nMaxIterations )
    {
      double randomPosition = (( double )mt_rand() / MD_RAND_MAX ) * clippedBaseline->length();
      QgsGeometry* samplePoint = clippedBaseline->interpolate( randomPosition );
      ++nIterations;
      if ( !samplePoint )
      {
        continue;
      }
      QgsPoint sampleQgsPoint = samplePoint->asPoint();
      QgsPoint latLongSamplePoint = toLatLongTransform.transform( sampleQgsPoint );

      QgsFeature samplePointFeature;
      samplePointFeature.setGeometry( samplePoint );
      samplePointFeature.setAttribute( "id", nTotalTransects + 1 );
      samplePointFeature.setAttribute( "station_id", nCreatedTransects + 1 );
      samplePointFeature.setAttribute( "stratum_id", strataId );
      samplePointFeature.setAttribute( "station_code", strataId.toString() + "_" + QString::number( nCreatedTransects + 1 ) );
      samplePointFeature.setAttribute( "start_lat", latLongSamplePoint.y() );
      samplePointFeature.setAttribute( "start_long", latLongSamplePoint.x() );

      //find closest point on clipped buffer line
      QgsPoint minDistPoint;

      int afterVertex;
      if ( bufferLineClipped->closestSegmentWithContext( sampleQgsPoint, minDistPoint, afterVertex ) < 0 )
      {
        continue;
      }

      //bearing between sample point and min dist point (transect direction)
      double bearing = distanceArea.bearing( sampleQgsPoint, minDistPoint ) / M_PI * 180.0;

      QgsPolyline sampleLinePolyline;
      QgsPoint ptFarAway( sampleQgsPoint.x() + ( minDistPoint.x() - sampleQgsPoint.x() ) * 1000000,
                          sampleQgsPoint.y() + ( minDistPoint.y() - sampleQgsPoint.y() ) * 1000000 );
      QgsPolyline lineFarAway;
      lineFarAway << sampleQgsPoint << ptFarAway;
      QgsGeometry* lineFarAwayGeom = QgsGeometry::fromPolyline( lineFarAway );
      QgsGeometry* lineClipStratum = lineFarAwayGeom->intersection( strataGeom );
      if ( !lineClipStratum )
      {
        delete lineFarAwayGeom; delete lineClipStratum;
        continue;
      }

      //cancel if distance between sample point and line is too large (line does not start at point
      if ( lineClipStratum->distance( *samplePoint ) > 0.000001 )
      {
        delete lineFarAwayGeom; delete lineClipStratum;
        continue;
      }

      //if lineClipStratum is a multiline, take the part line closest to sampleQgsPoint
      if ( lineClipStratum->wkbType() == QGis::WKBMultiLineString
           || lineClipStratum->wkbType() == QGis::WKBMultiLineString25D )
      {
        QgsGeometry* singleLine = closestMultilineElement( sampleQgsPoint, lineClipStratum );
        if ( singleLine )
        {
          delete lineClipStratum;
          lineClipStratum = singleLine;
        }
      }

      //cancel if length of lineClipStratum is too small
      double transectLength = distanceArea.measure( lineClipStratum );
      if ( transectLength < mMinTransectLength )
      {
        delete lineFarAwayGeom; delete lineClipStratum;
        continue;
      }

      //search closest existing profile. Cancel if dist < minDist
      if ( otherTransectWithinDistance( lineClipStratum, minDistanceLayerUnits, minDistance, sIndex, lineFeatureMap, distanceArea ) )
      {
        delete lineFarAwayGeom; delete lineClipStratum;
        continue;
      }

      QgsFeatureId fid( nCreatedTransects );
      QgsFeature sampleLineFeature( fid );
      sampleLineFeature.setGeometry( lineClipStratum );
      sampleLineFeature.setAttribute( "id", nTotalTransects + 1 );
      sampleLineFeature.setAttribute( "station_id", nCreatedTransects + 1 );
      sampleLineFeature.setAttribute( "stratum_id", strataId );
      sampleLineFeature.setAttribute( "station_code", strataId.toString() + "_" + QString::number( nCreatedTransects + 1 ) );
      sampleLineFeature.setAttribute( "start_lat", latLongSamplePoint.y() );
      sampleLineFeature.setAttribute( "start_long", latLongSamplePoint.x() );
      sampleLineFeature.setAttribute( "bearing", bearing );
      outputLineWriter.addFeature( sampleLineFeature );

      //add point to file writer here.
      //It can only be written if the corresponding transect has been as well
      outputPointWriter.addFeature( samplePointFeature );

      sIndex.insertFeature( sampleLineFeature );
      Q_NOWARN_DEPRECATED_PUSH
      lineFeatureMap.insert( fid, sampleLineFeature.geometryAndOwnership() );
      Q_NOWARN_DEPRECATED_POP

      delete lineFarAwayGeom;
      ++nTotalTransects;
      ++nCreatedTransects;
    }
    delete clippedBaseline;

    QgsFeature bufferClipFeature;
    bufferClipFeature.setGeometry( bufferLineClipped );
    bufferClipFeature.setAttribute( "id", strataId );
    bufferClipLineWriter.addFeature( bufferClipFeature );
    //delete bufferLineClipped;

    //delete all line geometries in spatial index
    QMap< QgsFeatureId, QgsGeometry* >::iterator featureMapIt = lineFeatureMap.begin();
    for ( ; featureMapIt != lineFeatureMap.end(); ++featureMapIt )
    {
      delete( featureMapIt.value() );
    }
    lineFeatureMap.clear();
    delete baselineGeom;

    ++nFeatures;
  }

  if ( pd )
  {
    pd->setValue( mStrataLayer->featureCount() );
  }

  return 0;
}
bool QgsSpatiaLiteFeatureIterator::getFeature( sqlite3_stmt *stmt, QgsFeature &feature )
{
  bool subsetAttributes = mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes;

  int ret = sqlite3_step( stmt );
  if ( ret == SQLITE_DONE )
  {
    // there are no more rows to fetch
    return false;
  }
  if ( ret != SQLITE_ROW )
  {
    // some unexpected error occurred
    QgsMessageLog::logMessage( QObject::tr( "SQLite error getting feature: %1" ).arg( QString::fromUtf8( sqlite3_errmsg( mHandle->handle() ) ) ), QObject::tr( "SpatiaLite" ) );
    return false;
  }

  // one valid row has been fetched from the result set
  if ( !mFetchGeometry )
  {
    // no geometry was required
    feature.setGeometryAndOwnership( 0, 0 );
  }

  feature.initAttributes( mSource->mFields.count() );
  feature.setFields( mSource->mFields ); // allow name-based attribute lookups

  int ic;
  int n_columns = sqlite3_column_count( stmt );
  for ( ic = 0; ic < n_columns; ic++ )
  {
    if ( ic == 0 )
    {
      if ( mHasPrimaryKey )
      {
        // first column always contains the ROWID (or the primary key)
        QgsFeatureId fid = sqlite3_column_int64( stmt, ic );
        QgsDebugMsgLevel( QString( "fid=%1" ).arg( fid ), 3 );
        feature.setFeatureId( fid );
      }
      else
      {
        // autoincrement a row number
        mRowNumber++;
        feature.setFeatureId( mRowNumber );
      }
    }
    else if ( mFetchGeometry && ic == mGeomColIdx )
    {
      getFeatureGeometry( stmt, ic, feature );
    }
    else
    {
      if ( subsetAttributes )
      {
        if ( ic <= mRequest.subsetOfAttributes().size() )
        {
          int attrIndex = mRequest.subsetOfAttributes()[ic-1];
          feature.setAttribute( attrIndex, getFeatureAttribute( stmt, ic, mSource->mFields.at( attrIndex ).type() ) );
        }
      }
      else
      {
        int attrIndex = ic - 1;
        feature.setAttribute( attrIndex, getFeatureAttribute( stmt, ic, mSource->mFields.at( attrIndex ).type() ) );
      }
    }
  }

  return true;
}
bool QgsPostgresFeatureIterator::getFeature( QgsPostgresResult &queryResult, int row, QgsFeature &feature )
{
  feature.initAttributes( mSource->mFields.count() );

  int col = 0;

  if ( mFetchGeometry )
  {
    int returnedLength = ::PQgetlength( queryResult.result(), row, col );
    if ( returnedLength > 0 )
    {
      unsigned char *featureGeom = new unsigned char[returnedLength + 1];
      memcpy( featureGeom, PQgetvalue( queryResult.result(), row, col ), returnedLength );
      memset( featureGeom + returnedLength, 0, 1 );

      // modify 2.5D WKB types to make them compliant with OGR
      unsigned int wkbType;
      memcpy( &wkbType, featureGeom + 1, sizeof( wkbType ) );
      wkbType = QgsPostgresConn::wkbTypeFromOgcWkbType( wkbType );
      memcpy( featureGeom + 1, &wkbType, sizeof( wkbType ) );

      // change wkb type of inner geometries
      if ( wkbType == QGis::WKBMultiPoint25D ||
           wkbType == QGis::WKBMultiLineString25D ||
           wkbType == QGis::WKBMultiPolygon25D )
      {
        unsigned int numGeoms;
        memcpy( &numGeoms, featureGeom + 5, sizeof( unsigned int ) );
        unsigned char *wkb = featureGeom + 9;
        for ( unsigned int i = 0; i < numGeoms; ++i )
        {
          unsigned int localType;
          memcpy( &localType, wkb + 1, sizeof( localType ) );
          localType = QgsPostgresConn::wkbTypeFromOgcWkbType( localType );
          memcpy( wkb + 1, &localType, sizeof( localType ) );

          // skip endian and type info
          wkb += sizeof( unsigned int ) + 1;

          // skip coordinates
          switch ( wkbType )
          {
            case QGis::WKBMultiPoint25D:
              wkb += sizeof( double ) * 3;
              break;
            case QGis::WKBMultiLineString25D:
            {
              unsigned int nPoints;
              memcpy( &nPoints, wkb, sizeof( int ) );
              wkb += sizeof( int ) + sizeof( double ) * 3 * nPoints;
            }
            break;
            default:
            case QGis::WKBMultiPolygon25D:
            {
              unsigned int nRings;
              memcpy( &nRings, wkb, sizeof( int ) );
              wkb += sizeof( int );
              for ( unsigned int j = 0; j < nRings; ++j )
              {
                unsigned int nPoints;
                memcpy( &nPoints, wkb, sizeof( int ) );
                wkb += sizeof( nPoints ) + sizeof( double ) * 3 * nPoints;
              }
            }
            break;
          }
        }
      }

      feature.setGeometryAndOwnership( featureGeom, returnedLength + 1 );
    }
    else
    {
      feature.setGeometryAndOwnership( 0, 0 );
    }

    col++;
  }

  QgsFeatureId fid = 0;

  bool subsetOfAttributes = mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes;
  const QgsAttributeList& fetchAttributes = mRequest.subsetOfAttributes();

  switch ( mSource->mPrimaryKeyType )
  {
    case pktOid:
    case pktTid:
    case pktInt:
      fid = mConn->getBinaryInt( queryResult, row, col++ );
      if ( mSource->mPrimaryKeyType == pktInt &&
           ( !subsetOfAttributes || fetchAttributes.contains( mSource->mPrimaryKeyAttrs[0] ) ) )
        feature.setAttribute( mSource->mPrimaryKeyAttrs[0], fid );
      break;

    case pktFidMap:
    {
      QList<QVariant> primaryKeyVals;

      Q_FOREACH ( int idx, mSource->mPrimaryKeyAttrs )
      {
        const QgsField &fld = mSource->mFields[idx];

        QVariant v = QgsPostgresProvider::convertValue( fld.type(), queryResult.PQgetvalue( row, col ) );
        primaryKeyVals << v;

        if ( !subsetOfAttributes || fetchAttributes.contains( idx ) )
          feature.setAttribute( idx, v );

        col++;
      }

      fid = mSource->mShared->lookupFid( QVariant( primaryKeyVals ) );

    }
    break;

    case pktUnknown:
      Q_ASSERT( !"FAILURE: cannot get feature with unknown primary key" );
      return false;
  }

  feature.setFeatureId( fid );
  QgsDebugMsgLevel( QString( "fid=%1" ).arg( fid ), 4 );

  // iterate attributes
  if ( subsetOfAttributes )
  {
    Q_FOREACH ( int idx, fetchAttributes )
      getFeatureAttribute( idx, queryResult, row, col, feature );
  }
  else
  {
    for ( int idx = 0; idx < mSource->mFields.count(); ++idx )
bool QgsSqlAnywhereFeatureIterator::nextFeature( QgsFeature& feature, SqlAnyStatement *stmt )
{
  feature.setValid( false );

  bool fetchGeometry = !( mRequest.flags() & QgsFeatureRequest::NoGeometry );
  bool subsetAttributes = mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes;

  if ( mClosed )
    return false;

  if ( !P->mConnRO || !P->mConnRO->isAlive() )
  {
    SaDebugMsg( "No database connection." );
    return false;
  }

  bool    ok;
  int     id;
  a_sqlany_data_value geom;
  unsigned char *geomBuf = NULL;


  ok = ( stmt != NULL && stmt->fetchNext() );

  // if no more rows...
  if ( !ok )
    return false;

  if ( !fetchGeometry )
    feature.setGeometryAndOwnership( 0, 0 );

  int numAttributes = P->fields().count(); // also used later for sanity check

  feature.initAttributes( numAttributes );
  feature.setFields( &P->mAttributeFields ); // allow name-based attribute lookups

  int i = 0;
  int numcols = stmt->numCols();
  int colidx = 0; // Refers to which column we're on in "feature" (the row)
  for ( i = 0; i < numcols; i++ )
  {
    if ( i == 0 )
    {
      // first column always contains primary key
      ok = stmt->getInt( i, id );
      if ( !ok ) break;
      QgsDebugMsgLevel( QString( "pid=%1" ).arg( id ), 3 );
      feature.setFeatureId( id );
    }
    else if ( i == 1 && fetchGeometry )
    {
      // second column contains QKB geometry value
      ok = stmt->getColumn( i, &geom );
      if ( !ok ) break;
      QgsDebugMsgLevel( QString( "retrieved geometry column" ), 3 );
      geomBuf = new unsigned char[ *geom.length + 1 ];
      memset( geomBuf, '\0', *geom.length );
      memcpy( geomBuf, geom.buffer, *geom.length );
      feature.setGeometryAndOwnership( geomBuf, *geom.length + 1 );
    }
    else
    {
      if ( i == 1 )
      {
        feature.setGeometryAndOwnership( 0, 0 ); // no geometry to fetch
      }
      int attrIndex = subsetAttributes ? mRequest.subsetOfAttributes()[colidx++] : colidx++;
      QVariant val;
      ok = stmt->getQVariant( i, val ); // ok may be false if value was NULL, but this is a valid return

      // Sanity check before setting the attribute value
      if ( colidx - 1 == i  // First column is always pk, so colidx should be at least 1 behind
           || ( colidx - 1 == i - 1 && fetchGeometry ) // if fetchGeometry is true, colidx should be 2 behind
           || attrIndex >= numAttributes ) // index should always be less than the count
      {
        SaDebugMsg( QString( "Error retrieving feature column %1 with attribute index %2" ).arg( i ).arg( attrIndex ) );
        return false;
      }
      // So now this should not crash.
      feature.setAttribute( attrIndex, val );
    }

  }

  feature.setValid( true );
  return true;
}