QVector<QgsPoint> QgsMapToolSimplify::getPointList( QgsFeature& f ) { QgsGeometry* line = f.geometry(); if (( line->type() != QGis::Line && line->type() != QGis::Polygon ) || line->isMultipart() ) { return QVector<QgsPoint>(); } if (( line->type() == QGis::Line ) ) { return line->asPolyline(); } else { if ( line->asPolygon().size() > 1 ) { return QVector<QgsPoint>(); } return line->asPolygon()[0]; } }
int QgsMapToolDeleteRing::ringNumInPolygon( const QgsGeometry &g, int vertexNr ) { QgsPolygon polygon = g.asPolygon(); for ( int ring = 0; ring < polygon.count(); ring++ ) { if ( vertexNr < polygon[ring].count() ) return ring; vertexNr -= polygon[ring].count(); } return -1; }
QgsGeometry QgsMapToolDeleteRing::ringUnderPoint( const QgsPoint &p, QgsFeatureId &fid, int &partNum, int &ringNum ) { //There is no clean way to find if we are inside the ring of a feature, //so we iterate over all the features visible in the canvas //If several rings are found at this position, the smallest one is chosen, //in order to be able to delete a ring inside another ring QgsFeatureIterator fit = vlayer->getFeatures( QgsFeatureRequest().setFilterRect( toLayerCoordinates( vlayer, mCanvas->extent() ) ) ); QgsFeature f; QgsGeometry g; QgsGeometry ringGeom; QgsMultiPolygon pol; QgsPolygon tempPol; QgsGeometry tempGeom; double area = std::numeric_limits<double>::max(); while ( fit.nextFeature( f ) ) { g = f.geometry(); if ( g.isNull() ) continue; if ( g.wkbType() == QgsWkbTypes::Polygon || g.wkbType() == QgsWkbTypes::Polygon25D ) { pol = QgsMultiPolygon() << g.asPolygon(); } else { pol = g.asMultiPolygon(); } for ( int i = 0; i < pol.size() ; ++i ) { //for each part if ( pol[i].size() > 1 ) { for ( int j = 1; j < pol[i].size(); ++j ) { tempPol = QgsPolygon() << pol[i][j]; tempGeom = QgsGeometry::fromPolygon( tempPol ); if ( tempGeom.area() < area && tempGeom.contains( &p ) ) { fid = f.id(); partNum = i; ringNum = j; area = tempGeom.area(); ringGeom = tempGeom; } } } } } return ringGeom; }
bool QgsSimplifyFeature::simplifyPolygon( QgsFeature& polygonFeature, double tolerance ) { QgsGeometry* polygon = polygonFeature.geometry(); if ( polygon->type() != QGis::Polygon ) { return false; } QVector<QgsPoint> resultPoints = simplifyPoints( polygon->asPolygon()[0], tolerance ); //resultPoints.push_back(resultPoints[0]); QVector<QgsPolyline> poly; poly.append( resultPoints ); polygonFeature.setGeometry( QgsGeometry::fromPolygon( poly ) ); return true; }
void QgsRubberBand::addGeometry( const QgsGeometry& geom, QgsVectorLayer* layer ) { if ( geom.isEmpty() ) { return; } //maprender object of canvas const QgsMapSettings& ms = mMapCanvas->mapSettings(); int idx = mPoints.size(); switch ( geom.wkbType() ) { case QgsWkbTypes::Point: case QgsWkbTypes::Point25D: { QgsPoint pt; if ( layer ) { pt = ms.layerToMapCoordinates( layer, geom.asPoint() ); } else { pt = geom.asPoint(); } addPoint( pt, false, idx ); removeLastPoint( idx, false ); } break; case QgsWkbTypes::MultiPoint: case QgsWkbTypes::MultiPoint25D: { QgsMultiPoint mpt = geom.asMultiPoint(); for ( int i = 0; i < mpt.size(); ++i, ++idx ) { QgsPoint pt = mpt[i]; if ( layer ) { addPoint( ms.layerToMapCoordinates( layer, pt ), false, idx ); removeLastPoint( idx, false ); } else { addPoint( pt, false, idx ); removeLastPoint( idx, false ); } } } break; case QgsWkbTypes::LineString: case QgsWkbTypes::LineString25D: { QgsPolyline line = geom.asPolyline(); for ( int i = 0; i < line.count(); i++ ) { if ( layer ) { addPoint( ms.layerToMapCoordinates( layer, line[i] ), false, idx ); } else { addPoint( line[i], false, idx ); } } } break; case QgsWkbTypes::MultiLineString: case QgsWkbTypes::MultiLineString25D: { QgsMultiPolyline mline = geom.asMultiPolyline(); for ( int i = 0; i < mline.size(); ++i, ++idx ) { QgsPolyline line = mline[i]; if ( line.isEmpty() ) { --idx; } for ( int j = 0; j < line.size(); ++j ) { if ( layer ) { addPoint( ms.layerToMapCoordinates( layer, line[j] ), false, idx ); } else { addPoint( line[j], false, idx ); } } } } break; case QgsWkbTypes::Polygon: case QgsWkbTypes::Polygon25D: { QgsPolygon poly = geom.asPolygon(); QgsPolyline line = poly[0]; for ( int i = 0; i < line.count(); i++ ) { if ( layer ) { addPoint( ms.layerToMapCoordinates( layer, line[i] ), false, idx ); } else { addPoint( line[i], false, idx ); } } } break; case QgsWkbTypes::MultiPolygon: case QgsWkbTypes::MultiPolygon25D: { QgsMultiPolygon multipoly = geom.asMultiPolygon(); for ( int i = 0; i < multipoly.size(); ++i, ++idx ) { QgsPolygon poly = multipoly[i]; QgsPolyline line = poly[0]; for ( int j = 0; j < line.count(); ++j ) { if ( layer ) { addPoint( ms.layerToMapCoordinates( layer, line[j] ), false, idx ); } else { addPoint( line[j], false, idx ); } } } } break; case QgsWkbTypes::Unknown: default: return; } setVisible( true ); updateRect(); update(); }
void QgsMapToolAddPart::canvasReleaseEvent( QMouseEvent * e ) { //check if we operate on a vector layer QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mCanvas->currentLayer() ); if ( !vlayer ) { notifyNotVectorLayer(); return; } if ( !vlayer->isEditable() ) { notifyNotEditableLayer(); return; } //inform user at the begin of the digitising action that the island tool only works if exactly one feature is selected int nSelectedFeatures = vlayer->selectedFeatureCount(); QString selectionErrorMsg; if ( nSelectedFeatures < 1 ) { selectionErrorMsg = tr( "No feature selected. Please select a feature with the selection tool or in the attribute table" ); } else if ( nSelectedFeatures > 1 ) { selectionErrorMsg = tr( "Several features are selected. Please select only one feature to which an part should be added." ); } if ( !selectionErrorMsg.isEmpty() ) { QMessageBox::critical( 0, tr( "Error. Could not add part." ), selectionErrorMsg ); stopCapturing(); return; } int errorCode; switch ( mode() ) { case CapturePoint: { QgsPoint layerPoint; QgsPoint mapPoint; if ( nextPoint( e->pos(), layerPoint, mapPoint ) != 0 ) { QgsDebugMsg( "nextPoint failed" ); return; } vlayer->beginEditCommand( tr( "Part added" ) ); errorCode = vlayer->addPart( QList<QgsPoint>() << layerPoint ); } break; case CaptureLine: case CapturePolygon: { //add point to list and to rubber band if ( e->button() == Qt::LeftButton ) { int error = addVertex( e->pos() ); if ( error == 1 ) { QgsDebugMsg( "current layer is not a vector layer" ); return; } else if ( error == 2 ) { //problem with coordinate transformation QMessageBox::information( 0, tr( "Coordinate transform error" ), tr( "Cannot transform the point to the layers coordinate system" ) ); return; } startCapturing(); return; } else if ( e->button() != Qt::RightButton ) { deleteTempRubberBand(); return; } if ( mode() == CapturePolygon ) { //close polygon closePolygon(); //avoid intersections QgsGeometry* geom = QgsGeometry::fromPolygon( QgsPolygon() << points().toVector() ); if ( geom ) { geom->avoidIntersections(); QgsPolygon poly = geom->asPolygon(); if ( poly.size() < 1 ) { stopCapturing(); delete geom; vlayer->destroyEditCommand(); return; } setPoints( geom->asPolygon()[0].toList() ); delete geom; } } vlayer->beginEditCommand( tr( "Part added" ) ); errorCode = vlayer->addPart( points() ); stopCapturing(); } break; default: Q_ASSERT( !"invalid capture mode" ); errorCode = 6; break; } QString errorMessage; switch ( errorCode ) { case 0: { //add points to other features to keep topology up-to-date int topologicalEditing = QgsProject::instance()->readNumEntry( "Digitizing", "/TopologicalEditing", 0 ); if ( topologicalEditing ) { addTopologicalPoints( points() ); } vlayer->endEditCommand(); mCanvas->refresh(); return; } case 1: errorMessage = tr( "Selected feature is not multi part." ); break; case 2: errorMessage = tr( "New part's geometry is not valid." ); break; case 3: errorMessage = tr( "New polygon ring not disjoint with existing polygons." ); break; case 4: errorMessage = tr( "No feature selected. Please select a feature with the selection tool or in the attribute table" ); break; case 5: errorMessage = tr( "Several features are selected. Please select only one feature to which an island should be added." ); break; case 6: errorMessage = tr( "Selected geometry could not be found" ); break; } QMessageBox::critical( 0, tr( "Error, could not add part" ), errorMessage ); vlayer->destroyEditCommand(); }
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 }
void QgsDxfExport::addFeature( const QgsSymbolV2RenderContext& ctx, const QString& layer, const QgsSymbolLayerV2* symbolLayer, const QgsSymbolV2* symbol ) { const QgsFeature* fet = ctx.feature(); if ( !fet ) { return; } QgsGeometry* geom = fet->geometry(); if ( geom ) { int c = 0; if ( mSymbologyExport != NoSymbology ) { c = colorFromSymbolLayer( symbolLayer, ctx ); } double width = -1; if ( mSymbologyExport != NoSymbology && symbolLayer ) { width = symbolLayer->dxfWidth( *this, ctx ); } QString lineStyleName = "CONTINUOUS"; if ( mSymbologyExport != NoSymbology ) { lineStyleName = lineStyleFromSymbolLayer( symbolLayer ); } QGis::WkbType geometryType = geom->wkbType(); //single point if ( geometryType == QGis::WKBPoint || geometryType == QGis::WKBPoint25D ) { writePoint( geom->asPoint(), layer, c, fet, symbolLayer, symbol ); } //multipoint if ( geometryType == QGis::WKBMultiPoint || geometryType == QGis::WKBMultiPoint25D ) { QgsMultiPoint multiPoint = geom->asMultiPoint(); QgsMultiPoint::const_iterator it = multiPoint.constBegin(); for ( ; it != multiPoint.constEnd(); ++it ) { writePoint( *it, layer, c, fet, symbolLayer, symbol ); } } //single line if ( geometryType == QGis::WKBLineString || geometryType == QGis::WKBLineString25D ) { writePolyline( geom->asPolyline(), layer, lineStyleName, c, width, false ); } //multiline if ( geometryType == QGis::WKBMultiLineString || geometryType == QGis::WKBMultiLineString25D ) { QgsMultiPolyline multiLine = geom->asMultiPolyline(); QgsMultiPolyline::const_iterator lIt = multiLine.constBegin(); for ( ; lIt != multiLine.constEnd(); ++lIt ) { writePolyline( *lIt, layer, lineStyleName, c, width, false ); } } //polygon if ( geometryType == QGis::WKBPolygon || geometryType == QGis::WKBPolygon25D ) { QgsPolygon polygon = geom->asPolygon(); QgsPolygon::const_iterator polyIt = polygon.constBegin(); for ( ; polyIt != polygon.constEnd(); ++polyIt ) //iterate over rings { writePolyline( *polyIt, layer, lineStyleName, c, width, true ); } } //multipolygon or polygon if ( geometryType == QGis::WKBMultiPolygon || geometryType == QGis::WKBMultiPolygon25D ) { QgsMultiPolygon mp = geom->asMultiPolygon(); QgsMultiPolygon::const_iterator mpIt = mp.constBegin(); for ( ; mpIt != mp.constEnd(); ++mpIt ) { QgsPolygon::const_iterator polyIt = mpIt->constBegin(); for ( ; polyIt != mpIt->constEnd(); ++polyIt ) { writePolyline( *polyIt, layer, lineStyleName, c, width, true ); } } } } }
void QgsMapToolOffsetCurve::prepareGeometry( const QgsPointLocator::Match &match, QgsFeature &snappedFeature ) { QgsVectorLayer *vl = match.layer(); if ( !vl ) { return; } mOriginalGeometry = QgsGeometry(); mManipulatedGeometry = QgsGeometry(); mModifiedPart = -1; mModifiedRing = -1; //assign feature part by vertex number (snap to vertex) or by before vertex number (snap to segment) QgsGeometry geom = snappedFeature.geometry(); if ( geom.isNull() ) { return; } mOriginalGeometry = geom; QgsWkbTypes::Type geomType = geom.wkbType(); if ( QgsWkbTypes::geometryType( geomType ) == QgsWkbTypes::LineGeometry ) { if ( !match.hasEdge() ) { return; } if ( !geom.isMultipart() ) { mManipulatedGeometry = geom; } else { int vertex = match.vertexIndex(); QgsVertexId vertexId; geom.vertexIdFromVertexNr( vertex, vertexId ); mModifiedPart = vertexId.part; QgsMultiPolylineXY multiLine = geom.asMultiPolyline(); mManipulatedGeometry = QgsGeometry::fromPolylineXY( multiLine.at( mModifiedPart ) ); } } else if ( QgsWkbTypes::geometryType( geomType ) == QgsWkbTypes::PolygonGeometry ) { if ( !match.hasEdge() && match.hasArea() ) { if ( !geom.isMultipart() ) { mManipulatedGeometry = geom; } else { // get the correct part QgsMultiPolygonXY mpolygon = geom.asMultiPolygon(); for ( int part = 0; part < mpolygon.count(); part++ ) // go through the polygons { const QgsPolygonXY &polygon = mpolygon[part]; QgsGeometry partGeo = QgsGeometry::fromPolygonXY( polygon ); const QgsPointXY layerCoords = match.point(); if ( partGeo.contains( &layerCoords ) ) { mModifiedPart = part; mManipulatedGeometry = partGeo; } } } } else if ( match.hasEdge() ) { int vertex = match.vertexIndex(); QgsVertexId vertexId; geom.vertexIdFromVertexNr( vertex, vertexId ); QgsDebugMsg( QStringLiteral( "%1" ).arg( vertexId.ring ) ); if ( !geom.isMultipart() ) { QgsPolygonXY poly = geom.asPolygon(); // if has rings if ( poly.count() > 0 ) { mModifiedRing = vertexId.ring; mManipulatedGeometry = QgsGeometry::fromPolygonXY( QgsPolygonXY() << poly.at( mModifiedRing ) ); } else { mManipulatedGeometry = QgsGeometry::fromPolygonXY( poly ); } } else { mModifiedPart = vertexId.part; // get part, get ring QgsMultiPolygonXY multiPoly = geom.asMultiPolygon(); // if has rings if ( multiPoly.at( mModifiedPart ).count() > 0 ) { mModifiedRing = vertexId.ring; mManipulatedGeometry = QgsGeometry::fromPolygonXY( QgsPolygonXY() << multiPoly.at( mModifiedPart ).at( mModifiedRing ) ); } else { mManipulatedGeometry = QgsGeometry::fromPolygonXY( multiPoly.at( mModifiedPart ) ); } } } } }
int QgsVectorLayerEditUtils::addTopologicalPoints( const QgsGeometry& geom ) { if ( !L->hasGeometryType() ) return 1; if ( geom.isEmpty() ) { return 1; } int returnVal = 0; QgsWkbTypes::Type wkbType = geom.wkbType(); switch ( wkbType ) { //line case QgsWkbTypes::LineString25D: case QgsWkbTypes::LineString: { QgsPolyline theLine = geom.asPolyline(); QgsPolyline::const_iterator line_it = theLine.constBegin(); for ( ; line_it != theLine.constEnd(); ++line_it ) { if ( addTopologicalPoints( *line_it ) != 0 ) { returnVal = 2; } } break; } //multiline case QgsWkbTypes::MultiLineString25D: case QgsWkbTypes::MultiLineString: { QgsMultiPolyline theMultiLine = geom.asMultiPolyline(); QgsPolyline currentPolyline; for ( int i = 0; i < theMultiLine.size(); ++i ) { QgsPolyline::const_iterator line_it = currentPolyline.constBegin(); for ( ; line_it != currentPolyline.constEnd(); ++line_it ) { if ( addTopologicalPoints( *line_it ) != 0 ) { returnVal = 2; } } } break; } //polygon case QgsWkbTypes::Polygon25D: case QgsWkbTypes::Polygon: { QgsPolygon thePolygon = geom.asPolygon(); QgsPolyline currentRing; for ( int i = 0; i < thePolygon.size(); ++i ) { currentRing = thePolygon.at( i ); QgsPolyline::const_iterator line_it = currentRing.constBegin(); for ( ; line_it != currentRing.constEnd(); ++line_it ) { if ( addTopologicalPoints( *line_it ) != 0 ) { returnVal = 2; } } } break; } //multipolygon case QgsWkbTypes::MultiPolygon25D: case QgsWkbTypes::MultiPolygon: { QgsMultiPolygon theMultiPolygon = geom.asMultiPolygon(); QgsPolygon currentPolygon; QgsPolyline currentRing; for ( int i = 0; i < theMultiPolygon.size(); ++i ) { currentPolygon = theMultiPolygon.at( i ); for ( int j = 0; j < currentPolygon.size(); ++j ) { currentRing = currentPolygon.at( j ); QgsPolyline::const_iterator line_it = currentRing.constBegin(); for ( ; line_it != currentRing.constEnd(); ++line_it ) { if ( addTopologicalPoints( *line_it ) != 0 ) { returnVal = 2; } } } } break; } default: break; } return returnVal; }
int QgsVectorLayerEditUtils::addTopologicalPoints( const QgsGeometry &geom ) { if ( !mLayer->isSpatial() ) return 1; if ( geom.isNull() ) { return 1; } int returnVal = 0; QgsWkbTypes::Type wkbType = geom.wkbType(); switch ( QgsWkbTypes::geometryType( wkbType ) ) { //line case QgsWkbTypes::LineGeometry: { if ( !QgsWkbTypes::isMultiType( wkbType ) ) { QgsPolylineXY line = geom.asPolyline(); QgsPolylineXY::const_iterator line_it = line.constBegin(); for ( ; line_it != line.constEnd(); ++line_it ) { if ( addTopologicalPoints( *line_it ) != 0 ) { returnVal = 2; } } } else { QgsMultiPolylineXY multiLine = geom.asMultiPolyline(); QgsPolylineXY currentPolyline; for ( int i = 0; i < multiLine.size(); ++i ) { QgsPolylineXY::const_iterator line_it = currentPolyline.constBegin(); for ( ; line_it != currentPolyline.constEnd(); ++line_it ) { if ( addTopologicalPoints( *line_it ) != 0 ) { returnVal = 2; } } } } break; } case QgsWkbTypes::PolygonGeometry: { if ( !QgsWkbTypes::isMultiType( wkbType ) ) { QgsPolygonXY polygon = geom.asPolygon(); QgsPolylineXY currentRing; for ( int i = 0; i < polygon.size(); ++i ) { currentRing = polygon.at( i ); QgsPolylineXY::const_iterator line_it = currentRing.constBegin(); for ( ; line_it != currentRing.constEnd(); ++line_it ) { if ( addTopologicalPoints( *line_it ) != 0 ) { returnVal = 2; } } } } else { QgsMultiPolygonXY multiPolygon = geom.asMultiPolygon(); QgsPolygonXY currentPolygon; QgsPolylineXY currentRing; for ( int i = 0; i < multiPolygon.size(); ++i ) { currentPolygon = multiPolygon.at( i ); for ( int j = 0; j < currentPolygon.size(); ++j ) { currentRing = currentPolygon.at( j ); QgsPolylineXY::const_iterator line_it = currentRing.constBegin(); for ( ; line_it != currentRing.constEnd(); ++line_it ) { if ( addTopologicalPoints( *line_it ) != 0 ) { returnVal = 2; } } } } } break; } case QgsWkbTypes::PointGeometry: case QgsWkbTypes::UnknownGeometry: case QgsWkbTypes::NullGeometry: break; } return returnVal; }
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; }