void QgsGeometryValidator::validatePolygon( int idx, const QgsPolygon &polygon ) { // check if holes are inside polygon for ( int i = 1; !mStop && i < polygon.size(); i++ ) { if ( !ringInRing( polygon[i], polygon[0] ) ) { QString msg = QObject::tr( "ring %1 of polygon %2 not in exterior ring" ).arg( i ).arg( idx ); QgsDebugMsg( msg ); emit errorFound( QgsGeometry::Error( msg ) ); mErrorCount++; } } // check holes for intersections for ( int i = 1; !mStop && i < polygon.size(); i++ ) { for ( int j = i + 1; !mStop && j < polygon.size(); j++ ) { checkRingIntersections( idx, i, polygon[i], idx, j, polygon[j] ); } } // check if rings are self-intersecting for ( int i = 0; !mStop && i < polygon.size(); i++ ) { validatePolyline( i, polygon[i], true ); } }
QDomElement QgsWFSServer::createPolygonElem( QgsGeometry* geom, QDomDocument& doc ) const { if ( !geom ) { return QDomElement(); } QDomElement polygonElem = doc.createElement( "gml:Polygon" ); QgsPolygon poly = geom->asPolygon(); for ( int i = 0; i < poly.size(); ++i ) { QString boundaryName; if ( i == 0 ) { boundaryName = "outerBoundaryIs"; } else { boundaryName = "innerBoundaryIs"; } QDomElement boundaryElem = doc.createElementNS( "http://www.opengis.net/gml", boundaryName ); QDomElement ringElem = doc.createElement( "gml:LinearRing" ); QDomElement coordElem = createCoordinateElem( poly.at( i ), doc ); ringElem.appendChild( coordElem ); boundaryElem.appendChild( ringElem ); polygonElem.appendChild( boundaryElem ); } return polygonElem; }
void QgsHighlight::paintPolygon( QPainter *p, QgsPolygon polygon ) { // OddEven fill rule by default QPainterPath path; p->setPen( mPen ); p->setBrush( mBrush ); for ( int i = 0; i < polygon.size(); i++ ) { if ( polygon[i].empty() ) continue; QPolygonF ring; ring.reserve( polygon[i].size() + 1 ); for ( int j = 0; j < polygon[i].size(); j++ ) { //adding point only if it is more than a pixel appart from the previous one const QPointF cur = toCanvasCoordinates( polygon[i][j] ) - pos(); if ( 0 == j || std::abs( ring.back().x() - cur.x() ) > 1 || std::abs( ring.back().y() - cur.y() ) > 1 ) { ring.push_back( cur ); } } ring.push_back( ring[ 0 ] ); path.addPolygon( ring ); } p->drawPath( path ); }
void QgsHighlight::paintPolygon( QPainter *p, QgsPolygon polygon ) { QPolygonF poly; // just ring outlines, no fill p->setPen( mPen ); p->setBrush( Qt::NoBrush ); for ( int i = 0; i < polygon.size(); i++ ) { QPolygonF ring( polygon[i].size() + 1 ); for ( int j = 0; j < polygon[i].size(); j++ ) { ring[ j ] = toCanvasCoordinates( polygon[i][j] ) - pos(); } ring[ polygon[i].size()] = ring[ 0 ]; p->drawPolygon( ring ); if ( i == 0 ) poly = ring; else poly = poly.subtracted( ring ); } // just fill, no outline p->setPen( Qt::NoPen ); p->setBrush( mBrush ); p->drawPolygon( poly ); }
std::unique_ptr<QgsPolygonV2> QgsGeometryFactory::fromPolygon( const QgsPolygon &polygon ) { std::unique_ptr< QgsPolygonV2 > poly( new QgsPolygonV2() ); QList<QgsCurve *> holes; for ( int i = 0; i < polygon.size(); ++i ) { std::unique_ptr< QgsLineString > l = linestringFromPolyline( polygon.at( i ) ); l->close(); if ( i == 0 ) { poly->setExteriorRing( l.release() ); } else { holes.push_back( l.release() ); } } poly->setInteriorRings( holes ); return poly; }
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 }
int QgsVectorLayerEditUtils::addTopologicalPoints( QgsGeometry* geom ) { if ( !L->hasGeometryType() ) return 1; if ( !geom ) { return 1; } int returnVal = 0; QGis::WkbType wkbType = geom->wkbType(); switch ( wkbType ) { //line case QGis::WKBLineString25D: case QGis::WKBLineString: { 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 QGis::WKBMultiLineString25D: case QGis::WKBMultiLineString: { 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 QGis::WKBPolygon25D: case QGis::WKBPolygon: { 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 QGis::WKBMultiPolygon25D: case QGis::WKBMultiPolygon: { 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; }
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 }
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; QList<FeatureLayer>::ConstIterator FeatureListEnd = mFeatureList1.end(); QgsPolygon pol; QgsMultiPolygon mpol; QgsPolyline segm; QgsPolyline ls; QgsMultiPolyline mls; QList<FeatureLayer> fls; TopolErrorShort* err; double distance; for ( it = mFeatureList1.begin(); it != FeatureListEnd; ++it ) { if ( !( ++i % 100 ) ) { emit progress( i ); } if ( testCancelled() ) { break; } QgsGeometry* g1 = it->feature.geometry(); // switching by type here, because layer can contain both single and multi version geometries switch ( g1->wkbType() ) { case QGis::WKBLineString: case QGis::WKBLineString25D: ls = g1->asPolyline(); for ( int i = 1; i < ls.size(); ++i ) { distance = 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::fromPolyline( 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 QGis::WKBPolygon: case QGis::WKBPolygon25D: pol = g1->asPolygon(); for ( int i = 0; i < pol.size(); ++i ) { for ( int j = 1; j < pol[i].size(); ++j ) { distance = 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::fromPolyline( segm ); err = new TopolErrorShort( g1->boundingBox(), conflict, fls ); errorList << err; //break on getting the first error break; } } } break; case QGis::WKBMultiLineString: case QGis::WKBMultiLineString25D: mls = g1->asMultiPolyline(); for ( int k = 0; k < mls.size(); ++k ) { QgsPolyline& ls = mls[k]; for ( int i = 1; i < ls.size(); ++i ) { distance = 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::fromPolyline( segm ); err = new TopolErrorShort( g1->boundingBox(), conflict, fls ); errorList << err; //break on getting the first error break; } } } break; case QGis::WKBMultiPolygon: case QGis::WKBMultiPolygon25D: mpol = g1->asMultiPolygon(); for ( int k = 0; k < mpol.size(); ++k ) { QgsPolygon& 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::fromPolyline( segm ); err = new TopolErrorShort( g1->boundingBox(), conflict, fls ); errorList << err; //break on getting the first error break; } } } } break; default: continue; } } return errorList; }