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 ); }
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