std::unique_ptr< QgsMultiPolygon > QgsGeometryFactory::fromMultiPolygonXY( const QgsMultiPolygonXY &multipoly ) { std::unique_ptr< QgsMultiPolygon > mp = qgis::make_unique< QgsMultiPolygon >(); for ( int i = 0; i < multipoly.size(); ++i ) { mp->addGeometry( fromPolygonXY( multipoly.at( i ) ).release() ); } return mp; }
ErrorList topolTest::checkGaps( QgsVectorLayer *layer1, QgsVectorLayer *layer2, bool isExtent ) { Q_UNUSED( layer2 ); int i = 0; ErrorList errorList; GEOSContextHandle_t geosctxt = QgsGeos::getGEOSHandler(); // could be enabled for lines and points too // so duplicate rule may be removed? if ( layer1->geometryType() != QgsWkbTypes::PolygonGeometry ) { return errorList; } QList<FeatureLayer>::iterator it; QgsGeometry g1; QList<GEOSGeometry *> geomList; qDebug() << mFeatureList1.count() << " features in list!"; for ( it = mFeatureList1.begin(); it != mFeatureList1.end(); ++it ) { qDebug() << "reading features-" << i; if ( !( ++i % 100 ) ) { emit progress( i ); } if ( testCanceled() ) { break; } g1 = it->feature.geometry(); if ( g1.isNull() ) { continue; } if ( !_canExportToGeos( g1 ) ) { continue; } if ( !g1.isGeosValid() ) { qDebug() << "invalid geometry found..skipping.." << it->feature.id(); continue; } if ( g1.isMultipart() ) { QgsMultiPolygonXY polys = g1.asMultiPolygon(); for ( int m = 0; m < polys.count(); m++ ) { QgsPolygonXY polygon = polys[m]; QgsGeometry polyGeom = QgsGeometry::fromPolygonXY( polygon ); geomList.push_back( QgsGeos::asGeos( polyGeom ).release() ); } } else { geomList.push_back( QgsGeos::asGeos( g1 ).release() ); } } GEOSGeometry **geomArray = new GEOSGeometry*[geomList.size()]; for ( int i = 0; i < geomList.size(); ++i ) { //qDebug() << "filling geometry array-" << i; geomArray[i] = geomList.at( i ); } qDebug() << "creating geometry collection-"; if ( geomList.isEmpty() ) { //qDebug() << "geometry list is empty!"; delete [] geomArray; return errorList; } GEOSGeometry *collection = nullptr; collection = GEOSGeom_createCollection_r( geosctxt, GEOS_MULTIPOLYGON, geomArray, geomList.size() ); qDebug() << "performing cascaded union..might take time..-"; GEOSGeometry *unionGeom = GEOSUnionCascaded_r( geosctxt, collection ); //delete[] geomArray; QgsGeometry test = QgsGeos::geometryFromGeos( unionGeom ); //qDebug() << "wktmerged - " << test.exportToWkt(); QString extentWkt = test.boundingBox().asWktPolygon(); QgsGeometry extentGeom = QgsGeometry::fromWkt( extentWkt ); QgsGeometry bufferExtent = extentGeom.buffer( 2, 3 ); //qDebug() << "extent wkt - " << bufferExtent->exportToWkt(); QgsGeometry diffGeoms = bufferExtent.difference( test ); if ( !diffGeoms ) { qDebug() << "difference result 0-"; return errorList; } //qDebug() << "difference gometry - " << diffGeoms->exportToWkt(); QVector<QgsGeometry> geomColl = diffGeoms.asGeometryCollection(); QgsGeometry canvasExtentPoly = QgsGeometry::fromWkt( qgsInterface->mapCanvas()->extent().asWktPolygon() ); for ( int i = 1; i < geomColl.count() ; ++i ) { QgsGeometry conflictGeom = geomColl[i]; if ( isExtent ) { if ( canvasExtentPoly.disjoint( conflictGeom ) ) { continue; } if ( canvasExtentPoly.crosses( conflictGeom ) ) { conflictGeom = conflictGeom.intersection( canvasExtentPoly ); } } QgsRectangle bBox = conflictGeom.boundingBox(); FeatureLayer ftrLayer1; ftrLayer1.layer = layer1; QList<FeatureLayer> errorFtrLayers; errorFtrLayers << ftrLayer1 << ftrLayer1; TopolErrorGaps *err = new TopolErrorGaps( bBox, conflictGeom, errorFtrLayers ); errorList << err; } return errorList; }
QgsGeometry QgsMapToolDeletePart::partUnderPoint( QPoint point, QgsFeatureId &fid, int &partNum ) { QgsFeature f; QgsGeometry geomPart; switch ( vlayer->geometryType() ) { case QgsWkbTypes::PointGeometry: case QgsWkbTypes::LineGeometry: { QgsPointLocator::Match match = mCanvas->snappingUtils()->snapToCurrentLayer( point, QgsPointLocator::Types( QgsPointLocator::Vertex | QgsPointLocator::Edge ) ); if ( !match.isValid() ) return geomPart; int snapVertex = match.vertexIndex(); vlayer->getFeatures( QgsFeatureRequest().setFilterFid( match.featureId() ) ).nextFeature( f ); QgsGeometry g = f.geometry(); if ( !g.isMultipart() ) { fid = match.featureId(); return QgsGeometry::fromPointXY( match.point() ); } else if ( QgsWkbTypes::geometryType( g.wkbType() ) == QgsWkbTypes::PointGeometry ) { fid = match.featureId(); partNum = snapVertex; return QgsGeometry::fromPointXY( match.point() ); } else if ( QgsWkbTypes::geometryType( g.wkbType() ) == QgsWkbTypes::LineGeometry ) { QgsMultiPolylineXY mline = g.asMultiPolyline(); for ( int part = 0; part < mline.count(); part++ ) { if ( snapVertex < mline[part].count() ) { fid = match.featureId(); partNum = part; return QgsGeometry::fromPolylineXY( mline[part] ); } snapVertex -= mline[part].count(); } } break; } case QgsWkbTypes::PolygonGeometry: { QgsPointLocator::Match match = mCanvas->snappingUtils()->snapToCurrentLayer( point, QgsPointLocator::Area ); if ( !match.isValid() ) return geomPart; vlayer->getFeatures( QgsFeatureRequest().setFilterFid( match.featureId() ) ).nextFeature( f ); QgsGeometry g = f.geometry(); if ( g.isNull() ) return geomPart; QgsPointXY layerCoords = toLayerCoordinates( vlayer, point ); if ( !g.isMultipart() ) { fid = f.id(); return geomPart; } QgsMultiPolygonXY mpolygon = g.asMultiPolygon(); for ( int part = 0; part < mpolygon.count(); part++ ) // go through the polygons { const QgsPolygonXY &polygon = mpolygon[part]; QgsGeometry partGeo = QgsGeometry::fromPolygonXY( polygon ); if ( partGeo.contains( &layerCoords ) ) { fid = f.id(); partNum = part; return partGeo; } } break; } default: { break; } } return geomPart; }
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 ) ); } } } } }
void QgsMapToolOffsetCurve::applyOffset( double offset, Qt::KeyboardModifiers modifiers ) { if ( !mLayer || offset == 0.0 ) { cancel(); notifyNotVectorLayer(); return; } updateGeometryAndRubberBand( offset ); // no modification if ( !mGeometryModified ) { mLayer->destroyEditCommand(); cancel(); return; } if ( mModifiedPart >= 0 ) { QgsGeometry geometry; int partIndex = 0; QgsWkbTypes::Type geomType = mOriginalGeometry.wkbType(); if ( QgsWkbTypes::geometryType( geomType ) == QgsWkbTypes::LineGeometry ) { QgsMultiPolylineXY newMultiLine; QgsMultiPolylineXY multiLine = mOriginalGeometry.asMultiPolyline(); QgsMultiPolylineXY::const_iterator it = multiLine.constBegin(); for ( ; it != multiLine.constEnd(); ++it ) { if ( partIndex == mModifiedPart ) { newMultiLine.append( mModifiedGeometry.asPolyline() ); } else { newMultiLine.append( *it ); } partIndex++; } geometry = QgsGeometry::fromMultiPolylineXY( newMultiLine ); } else { QgsMultiPolygonXY newMultiPoly; const QgsMultiPolygonXY multiPoly = mOriginalGeometry.asMultiPolygon(); QgsMultiPolygonXY::const_iterator multiPolyIt = multiPoly.constBegin(); for ( ; multiPolyIt != multiPoly.constEnd(); ++multiPolyIt ) { if ( partIndex == mModifiedPart ) { if ( mModifiedGeometry.isMultipart() ) { // not a ring if ( mModifiedRing <= 0 ) { // part became mulitpolygon, that means discard original rings from the part newMultiPoly += mModifiedGeometry.asMultiPolygon(); } else { // ring became multipolygon, oh boy! QgsPolygonXY newPoly; int ringIndex = 0; QgsPolygonXY::const_iterator polyIt = multiPolyIt->constBegin(); for ( ; polyIt != multiPolyIt->constEnd(); ++polyIt ) { if ( ringIndex == mModifiedRing ) { const QgsMultiPolygonXY ringParts = mModifiedGeometry.asMultiPolygon(); QgsPolygonXY newRings; QgsMultiPolygonXY::const_iterator ringIt = ringParts.constBegin(); for ( ; ringIt != ringParts.constEnd(); ++ringIt ) { // the different parts of the new rings cannot have rings themselves newRings.append( ringIt->at( 0 ) ); } newPoly += newRings; } else { newPoly.append( *polyIt ); } ringIndex++; } newMultiPoly.append( newPoly ); } } else { // original part had no ring if ( mModifiedRing == -1 ) { newMultiPoly.append( mModifiedGeometry.asPolygon() ); } else { QgsPolygonXY newPoly; int ringIndex = 0; QgsPolygonXY::const_iterator polyIt = multiPolyIt->constBegin(); for ( ; polyIt != multiPolyIt->constEnd(); ++polyIt ) { if ( ringIndex == mModifiedRing ) { newPoly.append( mModifiedGeometry.asPolygon().at( 0 ) ); } else { newPoly.append( *polyIt ); } ringIndex++; } newMultiPoly.append( newPoly ); } } } else { newMultiPoly.append( *multiPolyIt ); } partIndex++; } geometry = QgsGeometry::fromMultiPolygonXY( newMultiPoly ); } geometry.convertToMultiType(); mModifiedGeometry = geometry; } else if ( mModifiedRing >= 0 ) { // original geometry had some rings if ( mModifiedGeometry.isMultipart() ) { // not a ring if ( mModifiedRing == 0 ) { // polygon became mulitpolygon, that means discard original rings from the part // keep the modified geometry as is } else { QgsPolygonXY newPoly; const QgsPolygonXY poly = mOriginalGeometry.asPolygon(); // ring became multipolygon, oh boy! int ringIndex = 0; QgsPolygonXY::const_iterator polyIt = poly.constBegin(); for ( ; polyIt != poly.constEnd(); ++polyIt ) { if ( ringIndex == mModifiedRing ) { QgsMultiPolygonXY ringParts = mModifiedGeometry.asMultiPolygon(); QgsPolygonXY newRings; QgsMultiPolygonXY::const_iterator ringIt = ringParts.constBegin(); for ( ; ringIt != ringParts.constEnd(); ++ringIt ) { // the different parts of the new rings cannot have rings themselves newRings.append( ringIt->at( 0 ) ); } newPoly += newRings; } else { newPoly.append( *polyIt ); } ringIndex++; } mModifiedGeometry = QgsGeometry::fromPolygonXY( newPoly ); } } else { // simple case where modified geom is a polygon (not multi) QgsPolygonXY newPoly; const QgsPolygonXY poly = mOriginalGeometry.asPolygon(); int ringIndex = 0; QgsPolygonXY::const_iterator polyIt = poly.constBegin(); for ( ; polyIt != poly.constEnd(); ++polyIt ) { if ( ringIndex == mModifiedRing ) { newPoly.append( mModifiedGeometry.asPolygon().at( 0 ) ); } else { newPoly.append( *polyIt ); } ringIndex++; } mModifiedGeometry = QgsGeometry::fromPolygonXY( newPoly ); } } if ( !mModifiedGeometry.isGeosValid() ) { emit messageEmitted( tr( "Generated geometry is not valid." ), Qgis::Critical ); // no cancel, continue editing. return; } mLayer->beginEditCommand( tr( "Offset curve" ) ); bool editOk; if ( !mCtrlHeldOnFirstClick && !( modifiers & Qt::ControlModifier ) ) { editOk = mLayer->changeGeometry( mModifiedFeature, mModifiedGeometry ); } else { QgsFeature f; f.setGeometry( mModifiedGeometry ); //add empty values for all fields (allows inserting attribute values via the feature form in the same session) QgsAttributes attrs( mLayer->fields().count() ); const QgsFields &fields = mLayer->fields(); for ( int idx = 0; idx < fields.count(); ++idx ) { attrs[idx] = QVariant(); } f.setAttributes( attrs ); editOk = mLayer->addFeature( f ); } if ( editOk ) { mLayer->endEditCommand(); } else { mLayer->destroyEditCommand(); emit messageEmitted( QStringLiteral( "Could not apply offset" ), Qgis::Critical ); } deleteRubberBandAndGeometry(); deleteUserInputWidget(); mLayer->triggerRepaint(); mLayer = nullptr; }
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; }
ErrorList topolTest::checkSegmentLength( double tolerance, QgsVectorLayer *layer1, QgsVectorLayer *layer2, bool isExtent ) { Q_UNUSED( layer1 ); Q_UNUSED( layer2 ); Q_UNUSED( isExtent ); int i = 0; ErrorList errorList; QgsFeature f; QList<FeatureLayer>::iterator it; QgsPolygonXY pol; QgsMultiPolygonXY mpol; QgsPolylineXY segm; QgsPolylineXY ls; QgsMultiPolylineXY mls; QList<FeatureLayer> fls; TopolErrorShort *err = nullptr; double distance; for ( it = mFeatureList1.begin(); it != mFeatureList1.end(); ++it ) { if ( !( ++i % 100 ) ) { emit progress( i ); } if ( testCanceled() ) { break; } QgsGeometry g1 = it->feature.geometry(); // switching by type here, because layer can contain both single and multi version geometries switch ( g1.wkbType() ) { case QgsWkbTypes::LineString: case QgsWkbTypes::LineString25D: ls = g1.asPolyline(); for ( int i = 1; i < ls.size(); ++i ) { distance = std::sqrt( ls[i - 1].sqrDist( ls[i] ) ); if ( distance < tolerance ) { fls.clear(); fls << *it << *it; segm.clear(); segm << ls[i - 1] << ls[i]; QgsGeometry conflict = QgsGeometry::fromPolylineXY( segm ); err = new TopolErrorShort( g1.boundingBox(), conflict, fls ); //err = new TopolErrorShort(g1->boundingBox(), QgsGeometry::fromPolyline(segm), fls); errorList << err; //break on getting the first error break; } } break; case QgsWkbTypes::Polygon: case QgsWkbTypes::Polygon25D: pol = g1.asPolygon(); for ( int i = 0; i < pol.size(); ++i ) { for ( int j = 1; j < pol[i].size(); ++j ) { distance = std::sqrt( pol[i][j - 1].sqrDist( pol[i][j] ) ); if ( distance < tolerance ) { fls.clear(); fls << *it << *it; segm.clear(); segm << pol[i][j - 1] << pol[i][j]; QgsGeometry conflict = QgsGeometry::fromPolylineXY( segm ); err = new TopolErrorShort( g1.boundingBox(), conflict, fls ); errorList << err; //break on getting the first error break; } } } break; case QgsWkbTypes::MultiLineString: case QgsWkbTypes::MultiLineString25D: mls = g1.asMultiPolyline(); for ( int k = 0; k < mls.size(); ++k ) { QgsPolylineXY &ls = mls[k]; for ( int i = 1; i < ls.size(); ++i ) { distance = std::sqrt( ls[i - 1].sqrDist( ls[i] ) ); if ( distance < tolerance ) { fls.clear(); fls << *it << *it; segm.clear(); segm << ls[i - 1] << ls[i]; QgsGeometry conflict = QgsGeometry::fromPolylineXY( segm ); err = new TopolErrorShort( g1.boundingBox(), conflict, fls ); errorList << err; //break on getting the first error break; } } } break; case QgsWkbTypes::MultiPolygon: case QgsWkbTypes::MultiPolygon25D: mpol = g1.asMultiPolygon(); for ( int k = 0; k < mpol.size(); ++k ) { QgsPolygonXY &pol = mpol[k]; for ( int i = 0; i < pol.size(); ++i ) { for ( int j = 1; j < pol[i].size(); ++j ) { distance = pol[i][j - 1].sqrDist( pol[i][j] ); if ( distance < tolerance ) { fls.clear(); fls << *it << *it; segm.clear(); segm << pol[i][j - 1] << pol[i][j]; QgsGeometry conflict = QgsGeometry::fromPolylineXY( segm ); err = new TopolErrorShort( g1.boundingBox(), conflict, fls ); errorList << err; //break on getting the first error break; } } } } break; default: continue; } } return errorList; }
void QgsGeometryValidator::run() { mErrorCount = 0; switch ( mMethod ) { case QgsGeometry::ValidatorGeos: { char *r = nullptr; geos::unique_ptr g0( mGeometry.exportToGeos() ); GEOSContextHandle_t handle = QgsGeometry::getGEOSHandler(); if ( !g0 ) { emit errorFound( QgsGeometry::Error( QObject::tr( "GEOS error: could not produce geometry for GEOS (check log window)" ) ) ); } else { GEOSGeometry *g1 = nullptr; char res = GEOSisValidDetail_r( handle, g0.get(), GEOSVALID_ALLOW_SELFTOUCHING_RING_FORMING_HOLE, &r, &g1 ); if ( res != 1 ) { if ( g1 ) { const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( handle, g1 ); unsigned int n; if ( GEOSCoordSeq_getSize_r( handle, cs, &n ) && n == 1 ) { double x, y; GEOSCoordSeq_getX_r( handle, cs, 0, &x ); GEOSCoordSeq_getY_r( handle, cs, 0, &y ); emit errorFound( QgsGeometry::Error( QObject::tr( "GEOS error: %1" ).arg( r ), QgsPointXY( x, y ) ) ); mErrorCount++; } GEOSGeom_destroy_r( handle, g1 ); } else { emit errorFound( QgsGeometry::Error( QObject::tr( "GEOS error: %1" ).arg( r ) ) ); mErrorCount++; } GEOSFree_r( handle, r ); } } break; } case QgsGeometry::ValidatorQgisInternal: { QgsWkbTypes::Type flatType = QgsWkbTypes::flatType( mGeometry.wkbType() ); //if ( flatType == QgsWkbTypes::Point || flatType == QgsWkbTypes::MultiPoint ) // break; if ( flatType == QgsWkbTypes::LineString ) { validatePolyline( 0, mGeometry.asPolyline() ); } else if ( flatType == QgsWkbTypes::MultiLineString ) { QgsMultiPolylineXY mp = mGeometry.asMultiPolyline(); for ( int i = 0; !mStop && i < mp.size(); i++ ) validatePolyline( i, mp[i] ); } else if ( flatType == QgsWkbTypes::Polygon ) { validatePolygon( 0, mGeometry.asPolygon() ); } else if ( flatType == QgsWkbTypes::MultiPolygon ) { QgsMultiPolygonXY mp = mGeometry.asMultiPolygon(); for ( int i = 0; !mStop && i < mp.size(); i++ ) { validatePolygon( i, mp[i] ); } for ( int i = 0; !mStop && i < mp.size(); i++ ) { if ( mp[i].isEmpty() ) { emit errorFound( QgsGeometry::Error( QObject::tr( "polygon %1 has no rings" ).arg( i ) ) ); mErrorCount++; continue; } for ( int j = i + 1; !mStop && j < mp.size(); j++ ) { if ( mp[j].isEmpty() ) continue; if ( ringInRing( mp[i][0], mp[j][0] ) ) { emit errorFound( QgsGeometry::Error( QObject::tr( "polygon %1 inside polygon %2" ).arg( i ).arg( j ) ) ); mErrorCount++; } else if ( ringInRing( mp[j][0], mp[i][0] ) ) { emit errorFound( QgsGeometry::Error( QObject::tr( "polygon %1 inside polygon %2" ).arg( j ).arg( i ) ) ); mErrorCount++; } else { checkRingIntersections( i, 0, mp[i][0], j, 0, mp[j][0] ); } } } } else if ( flatType == QgsWkbTypes::Unknown ) { QgsDebugMsg( QObject::tr( "Unknown geometry type" ) ); emit errorFound( QgsGeometry::Error( QObject::tr( "Unknown geometry type %1" ).arg( mGeometry.wkbType() ) ) ); mErrorCount++; } if ( mStop ) { emit errorFound( QgsGeometry::Error( QObject::tr( "Geometry validation was aborted." ) ) ); } else if ( mErrorCount > 0 ) { emit errorFound( QgsGeometry::Error( QObject::tr( "Geometry has %1 errors." ).arg( mErrorCount ) ) ); } #if 0 else { emit errorFound( QgsGeometry::Error( QObject::tr( "Geometry is valid." ) ) ); } #endif break; } } }
QgsGeometry QgsMapToolDeletePart::partUnderPoint( QPoint point, QgsFeatureId &fid, int &partNum ) { QgsFeature f; QgsGeometry geomPart; switch ( vlayer->geometryType() ) { case QgsWkbTypes::PointGeometry: case QgsWkbTypes::LineGeometry: { QgsPointLocator::Match match = mCanvas->snappingUtils()->snapToCurrentLayer( point, QgsPointLocator::Types( QgsPointLocator::Vertex | QgsPointLocator::Edge ) ); if ( !match.isValid() ) return geomPart; int snapVertex = match.vertexIndex(); vlayer->getFeatures( QgsFeatureRequest().setFilterFid( match.featureId() ) ).nextFeature( f ); QgsGeometry g = f.geometry(); if ( !g.isMultipart() ) { fid = match.featureId(); return QgsGeometry::fromPointXY( match.point() ); } if ( g.wkbType() == QgsWkbTypes::MultiPoint || g.wkbType() == QgsWkbTypes::MultiPoint25D ) { fid = match.featureId(); partNum = snapVertex; return QgsGeometry::fromPointXY( match.point() ); } if ( g.wkbType() == QgsWkbTypes::MultiLineString || g.wkbType() == QgsWkbTypes::MultiLineString25D ) { QgsMultiPolylineXY mline = g.asMultiPolyline(); for ( int part = 0; part < mline.count(); part++ ) { if ( snapVertex < mline[part].count() ) { fid = match.featureId(); partNum = part; return QgsGeometry::fromPolylineXY( mline[part] ); } snapVertex -= mline[part].count(); } } break; } case QgsWkbTypes::PolygonGeometry: { QgsPointXY layerCoords = toLayerCoordinates( vlayer, point ); double searchRadius = QgsTolerance::vertexSearchRadius( mCanvas->currentLayer(), mCanvas->mapSettings() ); QgsRectangle selectRect( layerCoords.x() - searchRadius, layerCoords.y() - searchRadius, layerCoords.x() + searchRadius, layerCoords.y() + searchRadius ); QgsFeatureIterator fit = vlayer->getFeatures( QgsFeatureRequest().setFilterRect( selectRect ) ); fit.nextFeature( f ); QgsGeometry g = f.geometry(); if ( g.isNull() ) return geomPart; if ( !g.isMultipart() ) { fid = f.id(); return geomPart; } QgsMultiPolygonXY mpolygon = g.asMultiPolygon(); for ( int part = 0; part < mpolygon.count(); part++ ) // go through the polygons { const QgsPolygonXY &polygon = mpolygon[part]; QgsGeometry partGeo = QgsGeometry::fromPolygonXY( polygon ); if ( partGeo.contains( &layerCoords ) ) { fid = f.id(); partNum = part; return partGeo; } } break; } default: { break; } } return geomPart; }