Example #1
0
    void eval_columns()
    {
        QgsFieldMap fields;
        fields[4] = QgsField( "foo", QVariant::Int );

        QgsFeature f;
        f.addAttribute( 4, 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 #2
0
bool QgsGPXProvider::nextFeature( QgsFeature& feature )
{
  feature.setValid( false );
  bool result = false;

  QgsAttributeList::const_iterator iter;

  if ( mFeatureType == WaypointType )
  {
    // go through the list of waypoints and return the first one that is in
    // the bounds rectangle
    for ( ; mWptIter != data->waypointsEnd(); ++mWptIter )
    {
      const QgsWaypoint* wpt;
      wpt = &( *mWptIter );
      if ( boundsCheck( wpt->lon, wpt->lat ) )
      {
        feature.setFeatureId( wpt->id );
        result = true;

        // some wkb voodoo
        if ( mFetchGeom )
        {
          char* geo = new char[21];
          std::memset( geo, 0, 21 );
          geo[0] = QgsApplication::endian();
          geo[geo[0] == QgsApplication::NDR ? 1 : 4] = QGis::WKBPoint;
          std::memcpy( geo + 5, &wpt->lon, sizeof( double ) );
          std::memcpy( geo + 13, &wpt->lat, sizeof( double ) );
          feature.setGeometryAndOwnership(( unsigned char * )geo, sizeof( wkbPoint ) );
        }
        feature.setValid( true );

        // add attributes if they are wanted
        for ( iter = mAttributesToFetch.begin(); iter != mAttributesToFetch.end(); ++iter )
        {
          switch ( *iter )
          {
            case NameAttr:
              feature.addAttribute( NameAttr, QVariant( wpt->name ) );
              break;
            case EleAttr:
              if ( wpt->ele != -std::numeric_limits<double>::max() )
                feature.addAttribute( EleAttr, QVariant( wpt->ele ) );
              break;
            case SymAttr:
              feature.addAttribute( SymAttr, QVariant( wpt->sym ) );
              break;
            case CmtAttr:
              feature.addAttribute( CmtAttr, QVariant( wpt->cmt ) );
              break;
            case DscAttr:
              feature.addAttribute( DscAttr, QVariant( wpt->desc ) );
              break;
            case SrcAttr:
              feature.addAttribute( SrcAttr, QVariant( wpt->src ) );
              break;
            case URLAttr:
              feature.addAttribute( URLAttr, QVariant( wpt->url ) );
              break;
            case URLNameAttr:
              feature.addAttribute( URLNameAttr, QVariant( wpt->urlname ) );
              break;
          }
        }

        ++mWptIter;
        break;
      }
    }
  }

  else if ( mFeatureType == RouteType )
  {
    // go through the routes and return the first one that is in the bounds
    // rectangle
    for ( ; mRteIter != data->routesEnd(); ++mRteIter )
    {
      const QgsRoute* rte;
      rte = &( *mRteIter );

      if ( rte->points.size() == 0 )
        continue;
      const QgsRectangle& b( *mSelectionRectangle );
      if (( rte->xMax >= b.xMinimum() ) && ( rte->xMin <= b.xMaximum() ) &&
          ( rte->yMax >= b.yMinimum() ) && ( rte->yMin <= b.yMaximum() ) )
      {
        // some wkb voodoo
        int nPoints = rte->points.size();
        char* geo = new char[9 + 16 * nPoints];
        std::memset( geo, 0, 9 + 16 * nPoints );
        geo[0] = QgsApplication::endian();
        geo[geo[0] == QgsApplication::NDR ? 1 : 4] = QGis::WKBLineString;
        std::memcpy( geo + 5, &nPoints, 4 );
        for ( uint i = 0; i < rte->points.size(); ++i )
        {
          std::memcpy( geo + 9 + 16 * i, &rte->points[i].lon, sizeof( double ) );
          std::memcpy( geo + 9 + 16 * i + 8, &rte->points[i].lat, sizeof( double ) );
        }

        //create QgsGeometry and use it for intersection test
        //if geometry is to be fetched, it is attached to the feature, otherwise we delete it
        QgsGeometry* theGeometry = new QgsGeometry();
        theGeometry->fromWkb(( unsigned char * )geo, 9 + 16 * nPoints );
        bool intersection = theGeometry->intersects( b );//use geos for precise intersection test

        if ( !intersection )
        {
          delete theGeometry;
        }
        else
        {
          if ( mFetchGeom )
          {
            feature.setGeometry( theGeometry );
          }
          else
          {
            delete theGeometry;
          }
          feature.setFeatureId( rte->id );
          result = true;
          feature.setValid( true );

          // add attributes if they are wanted
          for ( iter = mAttributesToFetch.begin(); iter != mAttributesToFetch.end(); ++iter )
          {
            switch ( *iter )
            {
              case NameAttr:
                feature.addAttribute( NameAttr, QVariant( rte->name ) );
                break;
              case NumAttr:
                if ( rte->number != std::numeric_limits<int>::max() )
                  feature.addAttribute( NumAttr, QVariant( rte->number ) );
                break;
              case CmtAttr:
                feature.addAttribute( CmtAttr, QVariant( rte->cmt ) );
                break;
              case DscAttr:
                feature.addAttribute( DscAttr, QVariant( rte->desc ) );
                break;
              case SrcAttr:
                feature.addAttribute( SrcAttr, QVariant( rte->src ) );
                break;
              case URLAttr:
                feature.addAttribute( URLAttr, QVariant( rte->url ) );
                break;
              case URLNameAttr:
                feature.addAttribute( URLNameAttr, QVariant( rte->urlname ) );
                break;
            }
          }

          ++mRteIter;
          break;

        }

        //++mRteIter;
        //xbreak;
      }
    }
  }

  else if ( mFeatureType == TrackType )
  {
    // go through the tracks and return the first one that is in the bounds
    // rectangle
    for ( ; mTrkIter != data->tracksEnd(); ++mTrkIter )
    {
      const QgsTrack* trk;
      trk = &( *mTrkIter );

      QgsDebugMsg( QString( "GPX feature track segments: %1" ).arg( trk->segments.size() ) );
      if ( trk->segments.size() == 0 )
        continue;

      // A track consists of several segments. Add all those segments into one.
      int totalPoints = 0;;
      for ( std::vector<QgsTrackSegment>::size_type i = 0; i < trk->segments.size(); i ++ )
      {
        totalPoints += trk->segments[i].points.size();
      }
      if ( totalPoints == 0 )
        continue;
      QgsDebugMsg( "GPX feature track total points: " + QString::number( totalPoints ) );
      const QgsRectangle& b( *mSelectionRectangle );
      if (( trk->xMax >= b.xMinimum() ) && ( trk->xMin <= b.xMaximum() ) &&
          ( trk->yMax >= b.yMinimum() ) && ( trk->yMin <= b.yMaximum() ) )
      {
        // some wkb voodoo
        char* geo = new char[9 + 16 * totalPoints];
        if ( !geo )
        {
          QgsDebugMsg( "Too large track!!!" );
          return false;
        }
        std::memset( geo, 0, 9 + 16 * totalPoints );
        geo[0] = QgsApplication::endian();
        geo[geo[0] == QgsApplication::NDR ? 1 : 4] = QGis::WKBLineString;
        std::memcpy( geo + 5, &totalPoints, 4 );

        int thisPoint = 0;
        for ( std::vector<QgsTrackSegment>::size_type k = 0; k < trk->segments.size(); k++ )
        {
          int nPoints = trk->segments[k].points.size();
          for ( int i = 0; i < nPoints; ++i )
          {
            std::memcpy( geo + 9 + 16 * thisPoint,     &trk->segments[k].points[i].lon, sizeof( double ) );
            std::memcpy( geo + 9 + 16 * thisPoint + 8, &trk->segments[k].points[i].lat, sizeof( double ) );
            thisPoint++;
          }
        }

        //create QgsGeometry and use it for intersection test
        //if geometry is to be fetched, it is attached to the feature, otherwise we delete it
        QgsGeometry* theGeometry = new QgsGeometry();
        theGeometry->fromWkb(( unsigned char * )geo, 9 + 16 * totalPoints );
        bool intersection = theGeometry->intersects( b );//use geos for precise intersection test

        if ( !intersection ) //no intersection, delete geometry and move on
        {
          delete theGeometry;
        }
        else //intersection
        {
          if ( mFetchGeom )
          {
            feature.setGeometry( theGeometry );
          }
          else
          {
            delete theGeometry;
          }
          feature.setFeatureId( trk->id );
          result = true;

          feature.setValid( true );

          // add attributes if they are wanted
          for ( iter = mAttributesToFetch.begin(); iter != mAttributesToFetch.end(); ++iter )
          {
            switch ( *iter )
            {
              case NameAttr:
                feature.addAttribute( NameAttr, QVariant( trk->name ) );
                break;
              case NumAttr:
                if ( trk->number != std::numeric_limits<int>::max() )
                  feature.addAttribute( NumAttr, QVariant( trk->number ) );
                break;
              case CmtAttr:
                feature.addAttribute( CmtAttr, QVariant( trk->cmt ) );
                break;
              case DscAttr:
                feature.addAttribute( DscAttr, QVariant( trk->desc ) );
                break;
              case SrcAttr:
                feature.addAttribute( SrcAttr, QVariant( trk->src ) );
                break;
              case URLAttr:
                feature.addAttribute( URLAttr, QVariant( trk->url ) );
                break;
              case URLNameAttr:
                feature.addAttribute( URLNameAttr, QVariant( trk->urlname ) );
                break;
            }
          }

          ++mTrkIter;
          break;
        }
      }

    }
  }
  if ( result )
  {
    feature.setValid( true );
  }
  return result;
}
bool QgsDelimitedTextProvider::nextFeature( QgsFeature& feature )
{
  // before we do anything else, assume that there's something wrong with
  // the feature
  feature.setValid( false );
  while ( !mStream->atEnd() )
  {
    QString line = readLine( mStream ); // Default local 8 bit encoding
    if ( line.isEmpty() )
      continue;

    // lex the tokens from the current data line
    QStringList tokens = splitLine( line );

    while ( tokens.size() < mFieldCount )
      tokens.append( QString::null );

    QgsGeometry *geom = 0;

    if ( mWktFieldIndex >= 0 )
    {
      try
      {
        QString &sWkt = tokens[mWktFieldIndex];
        // Remove Z and M coordinates if present, as currently fromWkt doesn't
        // support these.
        if ( mWktHasZM )
        {
          sWkt.remove( mWktZMRegexp ).replace( mWktCrdRegexp, "\\1" );
        }

        geom = QgsGeometry::fromWkt( sWkt );
      }
      catch ( ... )
      {
        geom = 0;
      }

      if ( geom && geom->wkbType() != mWkbType )
      {
        delete geom;
        geom = 0;
      }
      mFid++;
      if ( geom && !boundsCheck( geom ) )
      {
        delete geom;
        geom = 0;
      }
    }
    else if ( mXFieldIndex >= 0 && mYFieldIndex >= 0 )
    {
      QString sX = tokens[mXFieldIndex];
      QString sY = tokens[mYFieldIndex];

      if ( !mDecimalPoint.isEmpty() )
      {
        sX.replace( mDecimalPoint, "." );
        sY.replace( mDecimalPoint, "." );
      }

      bool xOk, yOk;
      double x = sX.toDouble( &xOk );
      double y = sY.toDouble( &yOk );
      if ( xOk && yOk )
      {
        mFid++;
        if ( boundsCheck( x, y ) )
        {
          geom = QgsGeometry::fromPoint( QgsPoint( x, y ) );
        }
      }
    }

    if ( !geom && mWkbType != QGis::WKBNoGeometry )
    {
      mInvalidLines << line;
      continue;
    }

    // At this point the current feature values are valid

    feature.setValid( true );

    feature.setFeatureId( mFid );

    if ( geom )
      feature.setGeometry( geom );

    for ( QgsAttributeList::const_iterator i = mAttributesToFetch.begin();
          i != mAttributesToFetch.end();
          ++i )
    {
      int fieldIdx = *i;
      if ( fieldIdx < 0 || fieldIdx >= attributeColumns.count() )
        continue; // ignore non-existant fields

      QString &value = tokens[attributeColumns[fieldIdx]];
      QVariant val;
      switch ( attributeFields[fieldIdx].type() )
      {
        case QVariant::Int:
          if ( !value.isEmpty() )
            val = QVariant( value );
          else
            val = QVariant( attributeFields[fieldIdx].type() );
          break;
        case QVariant::Double:
          if ( !value.isEmpty() )
            val = QVariant( value.toDouble() );
          else
            val = QVariant( attributeFields[fieldIdx].type() );
          break;
        default:
          val = QVariant( value );
          break;
      }
      feature.addAttribute( fieldIdx, val );
    }

    // We have a good line, so return
    return true;

  } // !mStream->atEnd()

  // End of the file. If there are any lines that couldn't be
  // loaded, display them now.
  if ( mShowInvalidLines && !mInvalidLines.isEmpty() )
  {
    mShowInvalidLines = false;
    QgsMessageOutput* output = QgsMessageOutput::createMessageOutput();
    output->setTitle( tr( "Error" ) );
    output->setMessage( tr( "Note: the following lines were not loaded because QGIS was "
                            "unable to determine values for the x and y coordinates:\n" ),
                        QgsMessageOutput::MessageText );

    output->appendMessage( "Start of invalid lines." );
    for ( int i = 0; i < mInvalidLines.size(); ++i )
      output->appendMessage( mInvalidLines.at( i ) );
    output->appendMessage( "End of invalid lines." );

    output->showMessage();

    // We no longer need these lines.
    mInvalidLines.clear();
  }

  return false;

} // nextFeature
bool QgsDelimitedTextProvider::nextFeature( QgsFeature& feature )
{
  // before we do anything else, assume that there's something wrong with
  // the feature
  feature.setValid( false );
  while ( ! mStream->atEnd() )
  {
    double x = 0.0;
    double y = 0.0;
    QString line = mStream->readLine(); // Default local 8 bit encoding

    // lex the tokens from the current data line
    QStringList tokens;
    if ( mDelimiterType == "regexp" )
      tokens = line.split( mDelimiterRegexp );
    else
      tokens = line.split( mDelimiter );

    bool xOk = false;
    bool yOk = false;

    // Skip indexing malformed lines.
    if ( attributeFields.size() == tokens.size() )
    {
      x = tokens[mXFieldIndex].toDouble( &xOk );
      y = tokens[mYFieldIndex].toDouble( &yOk );
    }

    if ( !( xOk && yOk ) )
    {
      // Accumulate any lines that weren't ok, to report on them
      // later, and look at the next line in the file, but only if
      // we need to.
      QgsDebugMsg( "Malformed line : " + line );
      if ( mShowInvalidLines )
        mInvalidLines << line;

      continue;
    }

    // Give every valid line in the file an id, even if it's not
    // in the current extent or bounds.
    ++mFid;             // increment to next feature ID

    // skip the feature if it's out of current bounds
    if ( ! boundsCheck( x, y ) )
      continue;

    // at this point, one way or another, the current feature values
    // are valid
    feature.setValid( true );

    feature.setFeatureId( mFid );

    QByteArray  buffer;
    QDataStream s( &buffer, static_cast<QIODevice::OpenMode>( QIODevice::WriteOnly ) ); // open on buffers's data

    switch ( QgsApplication::endian() )
    {
      case QgsApplication::NDR :
        // we're on a little-endian platform, so tell the data
        // stream to use that
        s.setByteOrder( QDataStream::LittleEndian );
        s << ( quint8 )1; // 1 is for little-endian
        break;
      case QgsApplication::XDR :
        // don't change byte order since QDataStream is big endian by default
        s << ( quint8 )0; // 0 is for big-endian
        break;
      default :
        qDebug( "%s:%d unknown endian", __FILE__, __LINE__ );
        //delete [] geometry;
        return false;
    }

    s << ( quint32 )QGis::WKBPoint;
    s << x;
    s << y;

    unsigned char* geometry = new unsigned char[buffer.size()];
    memcpy( geometry, buffer.data(), buffer.size() );

    feature.setGeometryAndOwnership( geometry, sizeof( wkbPoint ) );

    for ( QgsAttributeList::const_iterator i = mAttributesToFetch.begin();
          i != mAttributesToFetch.end();
          ++i )
    {
      QVariant val;
      switch ( attributeFields[*i].type() )
      {
        case QVariant::Int:
          val = QVariant( tokens[*i].toInt() );
          break;
        case QVariant::Double:
          val = QVariant( tokens[*i].toDouble() );
          break;
        default:
          val = QVariant( tokens[*i] );
          break;
      }
      feature.addAttribute( *i, val );
    }

    // We have a good line, so return
    return true;

  } // ! textStream EOF

  // End of the file. If there are any lines that couldn't be
  // loaded, display them now.

  if ( mShowInvalidLines && !mInvalidLines.isEmpty() )
  {
    mShowInvalidLines = false;
    QgsMessageOutput* output = QgsMessageOutput::createMessageOutput();
    output->setTitle( tr( "Error" ) );
    output->setMessage( tr( "Note: the following lines were not loaded because Qgis was "
                            "unable to determine values for the x and y coordinates:\n" ),
                        QgsMessageOutput::MessageText );

    output->appendMessage( "Start of invalid lines." );
    for ( int i = 0; i < mInvalidLines.size(); ++i )
      output->appendMessage( mInvalidLines.at( i ) );
    output->appendMessage( "End of invalid lines." );

    output->showMessage();

    // We no longer need these lines.
    mInvalidLines.empty();
  }

  return false;

} // nextFeature