void visitData( const IData& d ) override { QgsFeatureId id = d.getIdentifier(); QgsGeometry* g = mLocator->mGeoms.value( id ); if ( g->intersects( mGeomPt ) ) mList << QgsPointLocator::Match( QgsPointLocator::Area, mLocator->mLayer, id, 0, QgsPoint() ); }
void QgsMeshCalcUtils::populateMaskFilter( QgsMeshMemoryDatasetGroup &filter, const QgsGeometry &mask ) const { filter.clearDatasets(); std::shared_ptr<QgsMeshMemoryDataset> output = create( filter ); output->time = mTimes[0]; const QVector<int> trianglesToNativeFaces = triangularMesh()->trianglesToNativeFaces(); const QVector<QgsMeshVertex> &vertices = triangularMesh()->vertices(); if ( mOutputType == QgsMeshDatasetGroupMetadata::DataOnVertices ) { int nativeVertexCount = mMeshLayer->dataProvider()->vertexCount(); for ( int i = 0; i < nativeVertexCount; ++i ) { const QgsPointXY point( vertices[i] ); if ( mask.contains( &point ) ) { output->values[i].set( D_TRUE ); } else { output->values[i].set( D_FALSE ); } } } else { const QVector<QgsMeshFace> &triangles = triangularMesh()->triangles(); for ( int i = 0; i < triangles.size(); ++i ) { const QgsMeshFace face = triangles[i]; const QgsGeometry geom = QgsMeshUtils::toGeometry( face, vertices ); const QgsRectangle bbox = geom.boundingBox(); if ( mask.intersects( bbox ) ) { output->values[i].set( D_TRUE ); } else { output->values[i].set( D_FALSE ); } } } filter.addDataset( output ); }
void QgsOverlayAnalyzer::intersectFeature( QgsFeature& f, QgsVectorFileWriter* vfw, QgsVectorLayer* vl, QgsSpatialIndex* index ) { QgsGeometry* featureGeometry = f.geometry(); QgsGeometry* intersectGeometry = 0; QgsFeature overlayFeature; if ( !featureGeometry ) { return; } QList<int> intersects; intersects = index->intersects( featureGeometry->boundingBox() ); QList<int>::const_iterator it = intersects.constBegin(); QgsFeature outFeature; for ( ; it != intersects.constEnd(); ++it ) { if ( !vl->featureAtId( *it, overlayFeature, true, true ) ) { continue; } if ( featureGeometry->intersects( overlayFeature.geometry() ) ) { intersectGeometry = featureGeometry->intersection( overlayFeature.geometry() ); outFeature.setGeometry( intersectGeometry ); QgsAttributeMap attributeMapA = f.attributeMap(); QgsAttributeMap attributeMapB = overlayFeature.attributeMap(); combineAttributeMaps( attributeMapA, attributeMapB ); outFeature.setAttributeMap( attributeMapA ); //add it to vector file writer if ( vfw ) { vfw->addFeature( outFeature ); } } } }
void QgsOverlayAnalyzer::intersectFeature( QgsFeature& f, QgsVectorFileWriter* vfw, QgsVectorLayer* vl, QgsSpatialIndex* index ) { if ( !f.hasGeometry() ) { return; } QgsGeometry featureGeometry = f.geometry(); QgsGeometry intersectGeometry; QgsFeature overlayFeature; QList<QgsFeatureId> intersects; intersects = index->intersects( featureGeometry.boundingBox() ); QList<QgsFeatureId>::const_iterator it = intersects.constBegin(); QgsFeature outFeature; for ( ; it != intersects.constEnd(); ++it ) { if ( !vl->getFeatures( QgsFeatureRequest().setFilterFid( *it ) ).nextFeature( overlayFeature ) ) { continue; } if ( featureGeometry.intersects( overlayFeature.geometry() ) ) { intersectGeometry = featureGeometry.intersection( overlayFeature.geometry() ); outFeature.setGeometry( intersectGeometry ); QgsAttributes attributesA = f.attributes(); QgsAttributes attributesB = overlayFeature.attributes(); combineAttributeMaps( attributesA, attributesB ); outFeature.setAttributes( attributesA ); //add it to vector file writer if ( vfw ) { vfw->addFeature( outFeature ); } } } }
bool QgsGPXFeatureIterator::readRoute( const QgsRoute &rte, QgsFeature &feature ) { if ( rte.points.isEmpty() ) return false; QgsGeometry *geometry = readRouteGeometry( rte ); if ( !mFilterRect.isNull() ) { if ( ( rte.xMax < mFilterRect.xMinimum() ) || ( rte.xMin > mFilterRect.xMaximum() ) || ( rte.yMax < mFilterRect.yMinimum() ) || ( rte.yMin > mFilterRect.yMaximum() ) ) { delete geometry; return false; } if ( !geometry->intersects( mFilterRect ) ) //use geos for precise intersection test { delete geometry; return false; } } if ( !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) ) { feature.setGeometry( *geometry ); delete geometry; } else { delete geometry; } feature.setId( rte.id ); feature.setValid( true ); feature.setFields( mSource->mFields ); // allow name-based attribute lookups feature.initAttributes( mSource->mFields.count() ); readAttributes( feature, rte ); return true; }
bool QgsGPXFeatureIterator::readTrack( const QgsTrack &trk, QgsFeature &feature ) { //QgsDebugMsg( QString( "GPX feature track segments: %1" ).arg( trk.segments.size() ) ); QgsGeometry *geometry = readTrackGeometry( trk ); if ( !mFilterRect.isNull() ) { if ( ( trk.xMax < mFilterRect.xMinimum() ) || ( trk.xMin > mFilterRect.xMaximum() ) || ( trk.yMax < mFilterRect.yMinimum() ) || ( trk.yMin > mFilterRect.yMaximum() ) ) { delete geometry; return false; } if ( !geometry->intersects( mFilterRect ) ) //use geos for precise intersection test { delete geometry; return false; } } if ( !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) ) { feature.setGeometry( *geometry ); delete geometry; } else { delete geometry; } feature.setId( trk.id ); feature.setValid( true ); feature.setFields( mSource->mFields ); // allow name-based attribute lookups feature.initAttributes( mSource->mFields.count() ); readAttributes( feature, trk ); return true; }
bool QgsGPXFeatureIterator::readRoute( const QgsRoute& rte, QgsFeature& feature ) { if ( rte.points.size() == 0 ) return false; QgsGeometry* theGeometry = readRouteGeometry( rte ); if ( mRequest.filterType() == QgsFeatureRequest::FilterRect ) { const QgsRectangle& rect = mRequest.filterRect(); if (( rte.xMax < rect.xMinimum() ) || ( rte.xMin > rect.xMaximum() ) || ( rte.yMax < rect.yMinimum() ) || ( rte.yMin > rect.yMaximum() ) ) return false; if ( !theGeometry->intersects( rect ) ) //use geos for precise intersection test { delete theGeometry; return false; } } if ( !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) ) { feature.setGeometry( theGeometry ); } else { delete theGeometry; } feature.setFeatureId( rte.id ); feature.setValid( true ); feature.setFields( &mSource->mFields ); // allow name-based attribute lookups feature.initAttributes( mSource->mFields.count() ); readAttributes( feature, rte ); return true; }
void QgsOverlayAnalyzer::intersectFeature( QgsFeature &f, QgsVectorFileWriter *vfw, QgsVectorLayer *vl, QgsSpatialIndex *index ) { if ( !f.hasGeometry() ) { return; } QgsGeometry featureGeometry = f.geometry(); QgsGeometry intersectGeometry; QgsFeature overlayFeature; QList<QgsFeatureId> intersects = index->intersects( featureGeometry.boundingBox() ); QgsFeatureRequest req = QgsFeatureRequest().setFilterFids( intersects.toSet() ); QgsFeatureIterator intersectIt = vl->getFeatures( req ); QgsFeature outFeature; while ( intersectIt.nextFeature( overlayFeature ) ) { if ( featureGeometry.intersects( overlayFeature.geometry() ) ) { intersectGeometry = featureGeometry.intersection( overlayFeature.geometry() ); outFeature.setGeometry( intersectGeometry ); QgsAttributes attributesA = f.attributes(); QgsAttributes attributesB = overlayFeature.attributes(); combineAttributeMaps( attributesA, attributesB ); outFeature.setAttributes( attributesA ); //add it to vector file writer if ( vfw ) { vfw->addFeature( outFeature ); } } } }
void CDTMapToolSelectTrainingSamples::canvasReleaseEvent(QgsMapMouseEvent *e) { if ( e->button() == Qt::LeftButton ) { if ( mDragging ) { mCanvas->panActionEnd( e->pos() ); mDragging = false; } else // add pan to mouse cursor { // transform the mouse pos to map coordinates QgsPoint center = mCanvas->getCoordinateTransform()->toMapPoint( e->x(), e->y() ); mCanvas->setExtent( QgsRectangle( center, center ) ); mCanvas->refresh(); } } else if (e->button()==Qt::RightButton) { QgsVectorLayer* vlayer = NULL; if ( !mapCanvas->currentLayer() || ( vlayer = qobject_cast<QgsVectorLayer *>( mapCanvas->currentLayer() ) ) == NULL ) return; QRect selectRect( 0, 0, 0, 0 ); int boxSize = 1; selectRect.setLeft ( e->pos().x() - boxSize ); selectRect.setRight ( e->pos().x() + boxSize ); selectRect.setTop ( e->pos().y() - boxSize ); selectRect.setBottom( e->pos().y() + boxSize ); const QgsMapToPixel* transform = mapCanvas->getCoordinateTransform(); QgsPoint ll = transform->toMapCoordinates( selectRect.left(), selectRect.bottom() ); QgsPoint ur = transform->toMapCoordinates( selectRect.right(), selectRect.top() ); QgsPolyline points; points.push_back(ll); points.push_back(QgsPoint( ur.x(), ll.y() )); points.push_back(ur); points.push_back(QgsPoint( ll.x(), ur.y() )); QgsPolygon polygon; polygon.push_back(points); QgsGeometry selectGeom = *(QgsGeometry::fromPolygon(polygon) ); if ( mapCanvas->mapSettings().hasCrsTransformEnabled() ) { QgsCoordinateTransform ct( mapCanvas->mapSettings().destinationCrs(), vlayer->crs() ); selectGeom.transform( ct ); } QgsFeatureIterator fit = vlayer->getFeatures( QgsFeatureRequest().setFilterRect( selectGeom.boundingBox() ).setFlags( QgsFeatureRequest::ExactIntersect ) ); QgsFeature f; qint64 closestFeatureId = 0; bool foundSingleFeature = false; double closestFeatureDist = std::numeric_limits<double>::max(); while ( fit.nextFeature( f ) ) { QgsGeometry* g = f.geometry(); if ( !selectGeom.intersects( g ) ) continue; foundSingleFeature = true; double distance = g->distance( selectGeom ); if ( distance <= closestFeatureDist ) { closestFeatureDist = distance; closestFeatureId = f.attribute("GridCode").toInt(); } } if ( foundSingleFeature ) addSingleSample( closestFeatureId ); } }
void QgsMapToolSelectUtils::setSelectFeatures( QgsMapCanvas* canvas, QgsGeometry* selectGeometry, bool doContains, bool doDifference, bool singleSelect ) { if ( selectGeometry->type() != QGis::Polygon ) { return; } QgsVectorLayer* vlayer = QgsMapToolSelectUtils::getCurrentVectorLayer( canvas ); if ( vlayer == nullptr ) { return; } // toLayerCoordinates will throw an exception for any 'invalid' points in // the rubber band. // For example, if you project a world map onto a globe using EPSG 2163 // and then click somewhere off the globe, an exception will be thrown. //QgsGeometry selectGeomTrans( *selectGeometry ); //if ( canvas->mapSettings().hasCrsTransformEnabled() ) //{ // try // { // QgsCoordinateTransform ct( canvas->mapSettings().destinationCrs(), vlayer->crs() ); // selectGeomTrans.transform( ct ); // } // catch ( QgsCsException &cse ) // { // Q_UNUSED( cse ); // // catch exception for 'invalid' point and leave existing selection unchanged // QgsLogger::warning( "Caught CRS exception " + QString( __FILE__ ) + ": " + QString::number( __LINE__ ) ); // LOG_INFO( "CRS Exception\nSelection extends beyond layer's coordinate system" ); // return; // } //} QgsGeometry selectGeomTrans; try{ selectGeomTrans = toLayerCoordinates( canvas, selectGeometry, vlayer ); } catch ( QgsCsException & ) { return; } QApplication::setOverrideCursor( Qt::WaitCursor ); QgsDebugMsg( "Selection layer: " + vlayer->name() ); QgsDebugMsg( "Selection polygon: " + selectGeomTrans.exportToWkt() ); QgsDebugMsg( "doContains: " + QString( doContains ? "T" : "F" ) ); QgsDebugMsg( "doDifference: " + QString( doDifference ? "T" : "F" ) ); QgsRenderContext context = QgsRenderContext::fromMapSettings( canvas->mapSettings() ); QgsFeatureRendererV2* r = vlayer->rendererV2(); if ( r ) r->startRender( context, vlayer->pendingFields() ); QgsFeatureRequest request; request.setFilterRect( selectGeomTrans.boundingBox() ); request.setFlags( QgsFeatureRequest::ExactIntersect ); if ( r ) request.setSubsetOfAttributes( r->usedAttributes(), vlayer->pendingFields() ); else request.setSubsetOfAttributes( QgsAttributeList() ); QgsFeatureIterator fit = vlayer->getFeatures( request ); QgsFeatureIds newSelectedFeatures; QgsFeature f; QgsFeatureId closestFeatureId = 0; bool foundSingleFeature = false; double closestFeatureDist = std::numeric_limits<double>::max(); while ( fit.nextFeature( f ) ) { #if (VERSION_INT >= 21601) context.expressionContext().setFeature( f ); //taken from QGIS 2.16.1 // make sure to only use features that are visible if ( r && !r->willRenderFeature( f, context ) ) #else if ( r && !r->willRenderFeature( f ) ) #endif continue; QgsGeometry* g = f.geometry(); if ( doContains ) { if ( !selectGeomTrans.contains( g ) ) continue; } else { if ( !selectGeomTrans.intersects( g ) ) continue; } if ( singleSelect ) { foundSingleFeature = true; double distance = g->distance( selectGeomTrans ); if ( distance <= closestFeatureDist ) { closestFeatureDist = distance; closestFeatureId = f.id(); } } else { newSelectedFeatures.insert( f.id() ); } } if ( singleSelect && foundSingleFeature ) { newSelectedFeatures.insert( closestFeatureId ); } if ( r ) r->stopRender( context ); QgsDebugMsg( "Number of new selected features: " + QString::number( newSelectedFeatures.size() ) ); if ( doDifference ) { QgsFeatureIds layerSelectedFeatures = vlayer->selectedFeaturesIds(); QgsFeatureIds selectedFeatures; QgsFeatureIds deselectedFeatures; QgsFeatureIds::const_iterator i = newSelectedFeatures.constEnd(); while ( i != newSelectedFeatures.constBegin() ) { --i; if ( layerSelectedFeatures.contains( *i ) ) { deselectedFeatures.insert( *i ); } else { selectedFeatures.insert( *i ); } } vlayer->modifySelection( selectedFeatures, deselectedFeatures ); } else { SelectFeatures( vlayer, newSelectedFeatures ); // vlayer->setSelectedFeatures( newSelectedFeatures ); } QApplication::restoreOverrideCursor(); }
QgsGeometry* QgsTransectSample::clipBufferLine( const QgsGeometry& stratumGeom, QgsGeometry* clippedBaseline, double tolerance ) { if ( !stratumGeom || !clippedBaseline || clippedBaseline->wkbType() == QgsWkbTypes::Unknown ) { return nullptr; } QgsGeometry usedBaseline = *clippedBaseline; if ( mBaselineSimplificationTolerance >= 0 ) { //int verticesBefore = usedBaseline->asMultiPolyline().count(); usedBaseline = clippedBaseline->simplify( mBaselineSimplificationTolerance ); if ( usedBaseline.isEmpty() ) { return nullptr; } //int verticesAfter = usedBaseline->asMultiPolyline().count(); //debug: write to file /*QgsVectorFileWriter debugWriter( "/tmp/debug.shp", "utf-8", QgsFields(), QgsWkbTypes::LineString, &( mStrataLayer->crs() ) ); QgsFeature debugFeature; debugFeature.setGeometry( usedBaseline ); debugWriter.addFeature( debugFeature );*/ } double currentBufferDist = tolerance; int maxLoops = 10; for ( int i = 0; i < maxLoops; ++i ) { //loop with tolerance: create buffer, convert buffer to line, clip line by stratum, test if result is (single) line QgsGeometry clipBaselineBuffer = usedBaseline.buffer( currentBufferDist, 8 ); if ( clipBaselineBuffer.isEmpty() ) { continue; } //it is also possible that clipBaselineBuffer is a multipolygon QgsGeometry bufferLine; //buffer line or multiline QgsGeometry bufferLineClipped; QgsMultiPolyline mpl; if ( clipBaselineBuffer.isMultipart() ) { QgsMultiPolygon bufferMultiPolygon = clipBaselineBuffer.asMultiPolygon(); if ( bufferMultiPolygon.size() < 1 ) { continue; } for ( int j = 0; j < bufferMultiPolygon.size(); ++j ) { int size = bufferMultiPolygon.at( j ).size(); for ( int k = 0; k < size; ++k ) { mpl.append( bufferMultiPolygon.at( j ).at( k ) ); } } bufferLine = QgsGeometry::fromMultiPolyline( mpl ); } else { QgsPolygon bufferPolygon = clipBaselineBuffer.asPolygon(); if ( bufferPolygon.size() < 1 ) { continue; } int size = bufferPolygon.size(); mpl.reserve( size ); for ( int j = 0; j < size; ++j ) { mpl.append( bufferPolygon[j] ); } bufferLine = QgsGeometry::fromMultiPolyline( mpl ); } bufferLineClipped = bufferLine.intersection( stratumGeom ); if ( bufferLineClipped.isEmpty() && bufferLineClipped.type() == QgsWkbTypes::LineGeometry ) { //if stratumGeom is a multipolygon, bufferLineClipped must intersect each part bool bufferLineClippedIntersectsStratum = true; if ( stratumGeom.wkbType() == QgsWkbTypes::MultiPolygon || stratumGeom.wkbType() == QgsWkbTypes::MultiPolygon25D ) { QVector<QgsPolygon> multiPoly = stratumGeom.asMultiPolygon(); QVector<QgsPolygon>::const_iterator multiIt = multiPoly.constBegin(); for ( ; multiIt != multiPoly.constEnd(); ++multiIt ) { QgsGeometry poly = QgsGeometry::fromPolygon( *multiIt ); if ( !poly.intersects( bufferLineClipped ) ) { bufferLineClippedIntersectsStratum = false; break; } } } if ( bufferLineClippedIntersectsStratum ) { return new QgsGeometry( bufferLineClipped ); } } currentBufferDist /= 2; } return nullptr; //no solution found even with reduced tolerances }
QgsGeometry* QgsTransectSample::clipBufferLine( QgsGeometry* stratumGeom, QgsGeometry* clippedBaseline, double tolerance ) { if ( !stratumGeom || !clippedBaseline || clippedBaseline->wkbType() == QGis::WKBUnknown ) { return 0; } double currentBufferDist = tolerance; int maxLoops = 10; for ( int i = 0; i < maxLoops; ++i ) { //loop with tolerance: create buffer, convert buffer to line, clip line by stratum, test if result is (single) line QgsGeometry* clipBaselineBuffer = clippedBaseline->buffer( currentBufferDist, 8 ); if ( !clipBaselineBuffer ) { delete clipBaselineBuffer; continue; } //it is also possible that clipBaselineBuffer is a multipolygon QgsGeometry* bufferLine = 0; //buffer line or multiline QgsGeometry* bufferLineClipped = 0; QgsMultiPolyline mpl; if ( clipBaselineBuffer->isMultipart() ) { QgsMultiPolygon bufferMultiPolygon = clipBaselineBuffer->asMultiPolygon(); if ( bufferMultiPolygon.size() < 1 ) { delete clipBaselineBuffer; continue; } for ( int j = 0; j < bufferMultiPolygon.size(); ++j ) { int size = bufferMultiPolygon.at( j ).size(); for ( int k = 0; k < size; ++k ) { mpl.append( bufferMultiPolygon.at( j ).at( k ) ); } } bufferLine = QgsGeometry::fromMultiPolyline( mpl ); } else { QgsPolygon bufferPolygon = clipBaselineBuffer->asPolygon(); if ( bufferPolygon.size() < 1 ) { delete clipBaselineBuffer; continue; } int size = bufferPolygon.size(); for ( int j = 0; j < size; ++j ) { mpl.append( bufferPolygon[j] ); } bufferLine = QgsGeometry::fromMultiPolyline( mpl ); } bufferLineClipped = bufferLine->intersection( stratumGeom ); if ( bufferLineClipped && bufferLineClipped->type() == QGis::Line ) { //if stratumGeom is a multipolygon, bufferLineClipped must intersect each part bool bufferLineClippedIntersectsStratum = true; if ( stratumGeom->wkbType() == QGis::WKBMultiPolygon || stratumGeom->wkbType() == QGis::WKBMultiPolygon25D ) { QVector<QgsPolygon> multiPoly = stratumGeom->asMultiPolygon(); QVector<QgsPolygon>::const_iterator multiIt = multiPoly.constBegin(); for ( ; multiIt != multiPoly.constEnd(); ++multiIt ) { QgsGeometry* poly = QgsGeometry::fromPolygon( *multiIt ); if ( !poly->intersects( bufferLineClipped ) ) { bufferLineClippedIntersectsStratum = false; delete poly; break; } delete poly; } } if ( bufferLineClippedIntersectsStratum ) { return bufferLineClipped; } } delete bufferLineClipped; delete clipBaselineBuffer; delete bufferLine; currentBufferDist /= 2; } return 0; //no solution found even with reduced tolerances }
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; }
QgsFeatureIds QgsMapToolSelectUtils::getMatchingFeatures( QgsMapCanvas *canvas, const QgsGeometry &selectGeometry, bool doContains, bool singleSelect ) { QgsFeatureIds newSelectedFeatures; if ( selectGeometry.type() != QgsWkbTypes::PolygonGeometry ) return newSelectedFeatures; QgsVectorLayer *vlayer = QgsMapToolSelectUtils::getCurrentVectorLayer( canvas ); if ( !vlayer ) return newSelectedFeatures; // toLayerCoordinates will throw an exception for any 'invalid' points in // the rubber band. // For example, if you project a world map onto a globe using EPSG 2163 // and then click somewhere off the globe, an exception will be thrown. QgsGeometry selectGeomTrans = selectGeometry; try { QgsCoordinateTransform ct( canvas->mapSettings().destinationCrs(), vlayer->crs(), QgsProject::instance() ); if ( !ct.isShortCircuited() && selectGeomTrans.type() == QgsWkbTypes::PolygonGeometry ) { // convert add more points to the edges of the rectangle // improve transformation result QgsPolygonXY poly( selectGeomTrans.asPolygon() ); if ( poly.size() == 1 && poly.at( 0 ).size() == 5 ) { const QgsPolylineXY &ringIn = poly.at( 0 ); QgsPolygonXY newpoly( 1 ); newpoly[0].resize( 41 ); QgsPolylineXY &ringOut = newpoly[0]; ringOut[ 0 ] = ringIn.at( 0 ); int i = 1; for ( int j = 1; j < 5; j++ ) { QgsVector v( ( ringIn.at( j ) - ringIn.at( j - 1 ) ) / 10.0 ); for ( int k = 0; k < 9; k++ ) { ringOut[ i ] = ringOut[ i - 1 ] + v; i++; } ringOut[ i++ ] = ringIn.at( j ); } selectGeomTrans = QgsGeometry::fromPolygonXY( newpoly ); } } selectGeomTrans.transform( ct ); } catch ( QgsCsException &cse ) { Q_UNUSED( cse ); // catch exception for 'invalid' point and leave existing selection unchanged QgsDebugMsg( QStringLiteral( "Caught CRS exception " ) ); QgisApp::instance()->messageBar()->pushMessage( QObject::tr( "CRS Exception" ), QObject::tr( "Selection extends beyond layer's coordinate system" ), Qgis::Warning, QgisApp::instance()->messageTimeout() ); return newSelectedFeatures; } QgsDebugMsgLevel( "Selection layer: " + vlayer->name(), 3 ); QgsDebugMsgLevel( "Selection polygon: " + selectGeomTrans.asWkt(), 3 ); QgsDebugMsgLevel( "doContains: " + QString( doContains ? "T" : "F" ), 3 ); QgsRenderContext context = QgsRenderContext::fromMapSettings( canvas->mapSettings() ); context.expressionContext() << QgsExpressionContextUtils::layerScope( vlayer ); std::unique_ptr< QgsFeatureRenderer > r; if ( vlayer->renderer() ) { r.reset( vlayer->renderer()->clone() ); r->startRender( context, vlayer->fields() ); } QgsFeatureRequest request; request.setFilterRect( selectGeomTrans.boundingBox() ); request.setFlags( QgsFeatureRequest::ExactIntersect ); if ( r ) request.setSubsetOfAttributes( r->usedAttributes( context ), vlayer->fields() ); else request.setNoAttributes(); QgsFeatureIterator fit = vlayer->getFeatures( request ); QgsFeature f; QgsFeatureId closestFeatureId = 0; bool foundSingleFeature = false; double closestFeatureDist = std::numeric_limits<double>::max(); while ( fit.nextFeature( f ) ) { context.expressionContext().setFeature( f ); // make sure to only use features that are visible if ( r && !r->willRenderFeature( f, context ) ) continue; QgsGeometry g = f.geometry(); if ( doContains ) { if ( !selectGeomTrans.contains( g ) ) continue; } else { if ( !selectGeomTrans.intersects( g ) ) continue; } if ( singleSelect ) { foundSingleFeature = true; double distance = g.distance( selectGeomTrans ); if ( distance <= closestFeatureDist ) { closestFeatureDist = distance; closestFeatureId = f.id(); } } else { newSelectedFeatures.insert( f.id() ); } } if ( singleSelect && foundSingleFeature ) { newSelectedFeatures.insert( closestFeatureId ); } if ( r ) r->stopRender( context ); QgsDebugMsg( "Number of new selected features: " + QString::number( newSelectedFeatures.size() ) ); return newSelectedFeatures; }
bool QgsSpatialFilter::evaluate( const QgsFeature& f ) const { if ( !mGeom ) { return true; } QgsGeometry* geom = ( new QgsFeature( f ) )->geometry(); switch ( mSpatialType ) { case BBOX: return geom->intersects( mGeom->boundingBox() ); break; case CONTAINS: return geom->contains( mGeom ); break; case CROSSES: return geom->crosses( mGeom ); break; case DISJOINT: return geom->disjoint( mGeom ); break; case EQUALS: return geom->equals( mGeom ); break; case INTERSECTS: return geom->intersects( mGeom ); break; case OVERLAPS: return geom->overlaps( mGeom ); break; case TOUCHES: return geom->touches( mGeom ); break; case WITHIN: return geom->within( mGeom ); break; case UNKNOWN: default: break; } return false; }