QgsAbstractGeometry *densifyGeometry( const QgsAbstractGeometry *geom, int extraNodesPerSegment = 1, double distance = 1 ) { std::unique_ptr< QgsAbstractGeometry > segmentizedCopy; if ( QgsWkbTypes::isCurvedType( geom->wkbType() ) ) { segmentizedCopy.reset( geom->segmentize() ); geom = segmentizedCopy.get(); } if ( QgsWkbTypes::geometryType( geom->wkbType() ) == QgsWkbTypes::LineGeometry ) { return doDensify( static_cast< const QgsLineString * >( geom ), extraNodesPerSegment, distance ); } else { // polygon const QgsPolygon *polygon = static_cast< const QgsPolygon * >( geom ); QgsPolygon *result = new QgsPolygon(); result->setExteriorRing( doDensify( static_cast< const QgsLineString * >( polygon->exteriorRing() ), extraNodesPerSegment, distance ) ); for ( int i = 0; i < polygon->numInteriorRings(); ++i ) { result->addInteriorRing( doDensify( static_cast< const QgsLineString * >( polygon->interiorRing( i ) ), extraNodesPerSegment, distance ) ); } return result; } }
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; }
QgsAbstractGeometry *orthogonalizeGeom( const QgsAbstractGeometry *geom, int maxIterations, double tolerance, double lowerThreshold, double upperThreshold ) { std::unique_ptr< QgsAbstractGeometry > segmentizedCopy; if ( QgsWkbTypes::isCurvedType( geom->wkbType() ) ) { segmentizedCopy.reset( geom->segmentize() ); geom = segmentizedCopy.get(); } if ( QgsWkbTypes::geometryType( geom->wkbType() ) == QgsWkbTypes::LineGeometry ) { return doOrthogonalize( static_cast< QgsLineString * >( geom->clone() ), maxIterations, tolerance, lowerThreshold, upperThreshold ); } else { // polygon const QgsPolygon *polygon = static_cast< const QgsPolygon * >( geom ); QgsPolygon *result = new QgsPolygon(); result->setExteriorRing( doOrthogonalize( static_cast< QgsLineString * >( polygon->exteriorRing()->clone() ), maxIterations, tolerance, lowerThreshold, upperThreshold ) ); for ( int i = 0; i < polygon->numInteriorRings(); ++i ) { result->addInteriorRing( doOrthogonalize( static_cast< QgsLineString * >( polygon->interiorRing( i )->clone() ), maxIterations, tolerance, lowerThreshold, upperThreshold ) ); } return result; } }
double QgsGeometryAnalyzer::perimeterMeasure( QgsGeometry* geometry, QgsDistanceArea& measure ) { double value = 0.00; if ( geometry->isMultipart() ) { QgsMultiPolygon poly = geometry->asMultiPolygon(); QgsMultiPolygon::iterator it; QgsPolygon::iterator jt; for ( it = poly.begin(); it != poly.end(); ++it ) { for ( jt = it->begin(); jt != it->end(); ++jt ) { value = value + measure.measure( QgsGeometry::fromPolyline( *jt ) ); } } } else { QgsPolygon::iterator jt; QgsPolygon poly = geometry->asPolygon(); for ( jt = poly.begin(); jt != poly.end(); ++jt ) { value = value + measure.measure( QgsGeometry::fromPolyline( *jt ) ); } } return value; }
static bool _check_intersecting_rings( const QgsPolygon &polygon ) { // At this point we assume that input polygons are valid according to the OGC definition. // This means e.g. no duplicate points, polygons are simple (no butterfly shaped polygon with self-intersection), // internal rings are inside exterior rings, rings do not cross each other, no dangles. // There is however an issue with polygons where rings touch: // +---+ // | | // | +-+-+ // | | | | // | +-+ | // | | // +-----+ // This is a valid polygon with one exterior and one interior ring that touch at one point, // but poly2tri library does not allow interior rings touch each other or exterior ring. // TODO: Handle the situation better - rather than just detecting the problem, try to fix // it by converting touching rings into one ring. if ( polygon.numInteriorRings() > 0 ) { QList<QgsGeometry> geomRings; geomRings << QgsGeometry( polygon.exteriorRing()->clone() ); for ( int i = 0; i < polygon.numInteriorRings(); ++i ) geomRings << QgsGeometry( polygon.interiorRing( i )->clone() ); for ( int i = 0; i < geomRings.count(); ++i ) for ( int j = i + 1; j < geomRings.count(); ++j ) { if ( geomRings[i].intersects( geomRings[j] ) ) return false; } } return true; }
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 ); } }
static QgsPolygon *_transform_polygon_to_new_base( const QgsPolygon &polygon, const QgsPoint &pt0, const QMatrix4x4 *toNewBase ) { QgsPolygon *p = new QgsPolygon; p->setExteriorRing( _transform_ring_to_new_base( *polygon.exteriorRing(), pt0, toNewBase ) ); for ( int i = 0; i < polygon.numInteriorRings(); ++i ) p->addInteriorRing( _transform_ring_to_new_base( *polygon.interiorRing( i ), pt0, toNewBase ) ); return p; }
QgsGeometry *QgsRubberBand::asGeometry() { QgsGeometry *geom = NULL; switch ( mGeometryType ) { case QGis::Polygon: { QgsPolygon polygon; QList< QList<QgsPoint> >::const_iterator it = mPoints.constBegin(); for ( ; it != mPoints.constEnd(); ++it ) { polygon.append( getPolyline( *it ) ); } geom = QgsGeometry::fromPolygon( polygon ); break; } case QGis::Point: { QgsMultiPoint multiPoint; QList< QList<QgsPoint> >::const_iterator it = mPoints.constBegin(); for ( ; it != mPoints.constEnd(); ++it ) { multiPoint += getPolyline( *it ); } geom = QgsGeometry::fromMultiPoint( multiPoint ); break; } case QGis::Line: default: { if ( mPoints.size() > 0 ) { if ( mPoints.size() > 1 ) { QgsMultiPolyline multiPolyline; QList< QList<QgsPoint> >::const_iterator it = mPoints.constBegin(); for ( ; it != mPoints.constEnd(); ++it ) { multiPolyline.append( getPolyline( *it ) ); } geom = QgsGeometry::fromMultiPolyline( multiPolyline ); } else { geom = QgsGeometry::fromPolyline( getPolyline( mPoints[0] ) ); } } break; } } return geom; }
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; }
void QgsMapToolCapture::validateGeometry() { QgsSettings settings; if ( settings.value( QStringLiteral( "qgis/digitizing/validate_geometries" ), 1 ).toInt() == 0 ) return; if ( mValidator ) { mValidator->deleteLater(); mValidator = nullptr; } mGeomErrors.clear(); while ( !mGeomErrorMarkers.isEmpty() ) { delete mGeomErrorMarkers.takeFirst(); } QgsGeometry geom; switch ( mCaptureMode ) { case CaptureNone: case CapturePoint: return; case CaptureLine: if ( size() < 2 ) return; geom = QgsGeometry( mCaptureCurve.curveToLine() ); break; case CapturePolygon: if ( size() < 3 ) return; QgsLineString *exteriorRing = mCaptureCurve.curveToLine(); exteriorRing->close(); QgsPolygon *polygon = new QgsPolygon(); polygon->setExteriorRing( exteriorRing ); geom = QgsGeometry( polygon ); break; } if ( geom.isNull() ) return; QgsGeometry::ValidationMethod method = QgsGeometry::ValidatorQgisInternal; if ( settings.value( QStringLiteral( "qgis/digitizing/validate_geometries" ), 1 ).toInt() == 2 ) method = QgsGeometry::ValidatorGeos; mValidator = new QgsGeometryValidator( geom, nullptr, method ); connect( mValidator, &QgsGeometryValidator::errorFound, this, &QgsMapToolCapture::addError ); mValidator->start(); QgsDebugMsgLevel( QStringLiteral( "Validation started" ), 4 ); }
QgsGeometry QgsInternalGeometryEngine::extrude( double x, double y ) const { QVector<QgsLineString *> linesToProcess; const QgsMultiCurve *multiCurve = qgsgeometry_cast< const QgsMultiCurve * >( mGeometry ); if ( multiCurve ) { for ( int i = 0; i < multiCurve->partCount(); ++i ) { linesToProcess << static_cast<QgsLineString *>( multiCurve->geometryN( i )->clone() ); } } const QgsCurve *curve = qgsgeometry_cast< const QgsCurve * >( mGeometry ); if ( curve ) { linesToProcess << static_cast<QgsLineString *>( curve->segmentize() ); } std::unique_ptr<QgsMultiPolygon> multipolygon( linesToProcess.size() > 1 ? new QgsMultiPolygon() : nullptr ); QgsPolygon *polygon = nullptr; if ( !linesToProcess.empty() ) { std::unique_ptr< QgsLineString > secondline; for ( QgsLineString *line : qgis::as_const( linesToProcess ) ) { QTransform transform = QTransform::fromTranslate( x, y ); secondline.reset( line->reversed() ); secondline->transform( transform ); line->append( secondline.get() ); line->addVertex( line->pointN( 0 ) ); polygon = new QgsPolygon(); polygon->setExteriorRing( line ); if ( multipolygon ) multipolygon->addGeometry( polygon ); } if ( multipolygon ) return QgsGeometry( multipolygon.release() ); else return QgsGeometry( polygon ); } return QgsGeometry(); }
QgsAbstractGeometryV2* QgsGeometryImport::fromRect( const QgsRectangle& rect ) { QgsPolyline ring; ring.append( QgsPoint( rect.xMinimum(), rect.yMinimum() ) ); ring.append( QgsPoint( rect.xMaximum(), rect.yMinimum() ) ); ring.append( QgsPoint( rect.xMaximum(), rect.yMaximum() ) ); ring.append( QgsPoint( rect.xMinimum(), rect.yMaximum() ) ); ring.append( QgsPoint( rect.xMinimum(), rect.yMinimum() ) ); QgsPolygon polygon; polygon.append( ring ); return fromPolygon( polygon ); }
void TestQgsTessellator::testBadCoordinates() { // triangulation would crash for me with this polygon if there is no simplification // to remove the coordinates that are very close to each other QgsPolygon polygon; polygon.fromWkt( "POLYGON((1 1, 2 1, 2.0000001 1.0000001, 2.0000002 1.0000001, 2.0000001 1.0000002, 2.0000002 1.0000002, 3 2, 1 2, 1 1))" ); QList<TriangleCoords> tc; tc << TriangleCoords( QVector3D( 1, 2, 0 ), QVector3D( 2, 1, 0 ), QVector3D( 3, 2, 0 ) ); tc << TriangleCoords( QVector3D( 1, 2, 0 ), QVector3D( 1, 1, 0 ), QVector3D( 2, 1, 0 ) ); QgsTessellator t( 0, 0, false ); t.addPolygon( polygon, 0 ); QVERIFY( checkTriangleOutput( t.data(), false, tc ) ); }
void TestQgsTessellator::asMultiPolygon() { QgsPolygon polygon; polygon.fromWkt( "POLYGON((1 1, 2 1, 3 2, 1 2, 1 1))" ); QgsPolygon polygonZ; polygonZ.fromWkt( "POLYGONZ((1 1 1, 2 1 2, 3 2 3, 1 2 4, 1 1 1))" ); QgsTessellator t( 0, 0, false ); t.addPolygon( polygon, 0 ); QCOMPARE( t.asMultiPolygon()->asWkt(), QStringLiteral( "MultiPolygonZ (((1 2 0, 2 1 0, 3 2 0, 1 2 0)),((1 2 0, 1 1 0, 2 1 0, 1 2 0)))" ) ); QgsTessellator t2( 0, 0, false ); t2.addPolygon( polygonZ, 0 ); QCOMPARE( t2.asMultiPolygon()->asWkt(), QStringLiteral( "MultiPolygonZ (((1 2 4, 2 1 2, 3 2 3, 1 2 4)),((1 2 4, 1 1 1, 2 1 2, 1 2 4)))" ) ); }
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 ); }
static bool _check_intersecting_rings( const QgsPolygon &polygon ) { QList<QgsGeometry> geomRings; geomRings << QgsGeometry( polygon.exteriorRing()->clone() ); for ( int i = 0; i < polygon.numInteriorRings(); ++i ) geomRings << QgsGeometry( polygon.interiorRing( i )->clone() ); // we need to make sure that the polygon has no rings with self-intersection: that may // crash the tessellator. The original geometry maybe have been valid and the self-intersection // was introduced when transforming to a new base (in a rare case when all points are not in the same plane) for ( int i = 0; i < geomRings.count(); ++i ) { if ( !geomRings[i].isSimple() ) return false; } // At this point we assume that input polygons are valid according to the OGC definition. // This means e.g. no duplicate points, polygons are simple (no butterfly shaped polygon with self-intersection), // internal rings are inside exterior rings, rings do not cross each other, no dangles. // There is however an issue with polygons where rings touch: // +---+ // | | // | +-+-+ // | | | | // | +-+ | // | | // +-----+ // This is a valid polygon with one exterior and one interior ring that touch at one point, // but poly2tri library does not allow interior rings touch each other or exterior ring. // TODO: Handle the situation better - rather than just detecting the problem, try to fix // it by converting touching rings into one ring. if ( polygon.numInteriorRings() > 0 ) { for ( int i = 0; i < geomRings.count(); ++i ) for ( int j = i + 1; j < geomRings.count(); ++j ) { if ( geomRings[i].intersects( geomRings[j] ) ) return false; } } return true; }
double QgsGrassGisLib::G_area_of_polygon( const double *x, const double *y, int n ) { QgsPolyline polyline; for ( int i = 0; i < n; i++ ) { polyline.append( QgsPoint( x[i], y[i] ) ); } QgsPolygon polygon; polygon.append( polyline ); QgsGeometry* geo = QgsGeometry::fromPolygon( polygon ); double area = mDistanceArea.measure( geo ); delete geo; if ( !mCrs.geographicFlag() ) { area *= qPow( G_database_units_to_meters_factor(), 2 ); } return area; }
double _minimum_distance_between_coordinates( const QgsPolygon &polygon ) { double min_d = 1e20; auto it = polygon.vertices_begin(); if ( it == polygon.vertices_end() ) return min_d; QgsPoint p0 = *it; ++it; for ( ; it != polygon.vertices_end(); ++it ) { QgsPoint p1 = *it; double d = p0.distance( p1 ); if ( d < min_d ) min_d = d; p0 = p1; } return min_d; }
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 TestQgsTessellator::testWalls() { QgsPolygon polygonZ; polygonZ.fromWkt( "POLYGONZ((1 1 1, 2 1 2, 3 2 3, 1 2 4, 1 1 1))" ); QList<TriangleCoords> tc; tc << TriangleCoords( QVector3D( 1, 2, 14 ), QVector3D( 2, 1, 12 ), QVector3D( 3, 2, 13 ) ); tc << TriangleCoords( QVector3D( 1, 2, 14 ), QVector3D( 1, 1, 11 ), QVector3D( 2, 1, 12 ) ); tc << TriangleCoords( QVector3D( 1, 1, 11 ), QVector3D( 1, 2, 14 ), QVector3D( 1, 1, 1 ) ); tc << TriangleCoords( QVector3D( 1, 1, 1 ), QVector3D( 1, 2, 14 ), QVector3D( 1, 2, 4 ) ); tc << TriangleCoords( QVector3D( 1, 2, 14 ), QVector3D( 3, 2, 13 ), QVector3D( 1, 2, 4 ) ); tc << TriangleCoords( QVector3D( 1, 2, 4 ), QVector3D( 3, 2, 13 ), QVector3D( 3, 2, 3 ) ); tc << TriangleCoords( QVector3D( 3, 2, 13 ), QVector3D( 2, 1, 12 ), QVector3D( 3, 2, 3 ) ); tc << TriangleCoords( QVector3D( 3, 2, 3 ), QVector3D( 2, 1, 12 ), QVector3D( 2, 1, 2 ) ); tc << TriangleCoords( QVector3D( 2, 1, 12 ), QVector3D( 1, 1, 11 ), QVector3D( 2, 1, 2 ) ); tc << TriangleCoords( QVector3D( 2, 1, 2 ), QVector3D( 1, 1, 11 ), QVector3D( 1, 1, 1 ) ); QgsTessellator tZ( 0, 0, false ); tZ.addPolygon( polygonZ, 10 ); QVERIFY( checkTriangleOutput( tZ.data(), false, tc ) ); }
void TestQgsTessellator::testBasic() { QgsPolygon polygon; polygon.fromWkt( "POLYGON((1 1, 2 1, 3 2, 1 2, 1 1))" ); QgsPolygon polygonZ; polygonZ.fromWkt( "POLYGONZ((1 1 0, 2 1 0, 3 2 0, 1 2 0, 1 1 0))" ); QList<TriangleCoords> tc; tc << TriangleCoords( QVector3D( 1, 2, 0 ), QVector3D( 2, 1, 0 ), QVector3D( 3, 2, 0 ) ); tc << TriangleCoords( QVector3D( 1, 2, 0 ), QVector3D( 1, 1, 0 ), QVector3D( 2, 1, 0 ) ); QVector3D up( 0, 0, 1 ); // surface normal pointing straight up QList<TriangleCoords> tcNormals; tcNormals << TriangleCoords( QVector3D( 1, 2, 0 ), QVector3D( 2, 1, 0 ), QVector3D( 3, 2, 0 ), up, up, up ); tcNormals << TriangleCoords( QVector3D( 1, 2, 0 ), QVector3D( 1, 1, 0 ), QVector3D( 2, 1, 0 ), up, up, up ); // without normals QgsTessellator t( 0, 0, false ); t.addPolygon( polygon, 0 ); QVERIFY( checkTriangleOutput( t.data(), false, tc ) ); QgsTessellator tZ( 0, 0, false ); tZ.addPolygon( polygonZ, 0 ); QVERIFY( checkTriangleOutput( tZ.data(), false, tc ) ); // with normals QgsTessellator tN( 0, 0, true ); tN.addPolygon( polygon, 0 ); QVERIFY( checkTriangleOutput( tN.data(), true, tcNormals ) ); QgsTessellator tNZ( 0, 0, true ); tNZ.addPolygon( polygonZ, 0 ); QVERIFY( checkTriangleOutput( tNZ.data(), true, tcNormals ) ); }
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 QgsTessellator::addPolygon( const QgsPolygon &polygon, float extrusionHeight ) { if ( _minimum_distance_between_coordinates( polygon ) < 0.001 ) { // when the distances between coordinates of input points are very small, // the triangulation likes to crash on numerical errors - when the distances are ~ 1e-5 // Assuming that the coordinates should be in a projected CRS, we should be able // to simplify geometries that may cause problems and avoid possible crashes QgsGeometry polygonSimplified = QgsGeometry( polygon.clone() ).simplify( 0.001 ); const QgsPolygon *polygonSimplifiedData = qgsgeometry_cast<const QgsPolygon *>( polygonSimplified.constGet() ); if ( _minimum_distance_between_coordinates( *polygonSimplifiedData ) < 0.001 ) { // Failed to fix that. It could be a really tiny geometry... or maybe they gave us // geometry in unprojected lat/lon coordinates QgsMessageLog::logMessage( "geometry's coordinates are too close to each other and simplification failed - skipping", "3D" ); } else { addPolygon( *polygonSimplifiedData, extrusionHeight ); } return; } if ( !_check_intersecting_rings( polygon ) ) { // skip the polygon - it would cause a crash inside poly2tri library QgsMessageLog::logMessage( "polygon rings intersect each other - skipping", "3D" ); return; } const QgsCurve *exterior = polygon.exteriorRing(); QList< std::vector<p2t::Point *> > polylinesToDelete; QHash<p2t::Point *, float> z; std::vector<p2t::Point *> polyline; const QVector3D pNormal = _calculateNormal( exterior, mOriginX, mOriginY ); const int pCount = exterior->numPoints(); // Polygon is a triangle if ( pCount == 4 ) { QgsPoint pt; QgsVertexId::VertexType vt; for ( int i = 0; i < 3; i++ ) { exterior->pointAt( i, pt, vt ); mData << pt.x() - mOriginX << pt.z() << - pt.y() + mOriginY; if ( mAddNormals ) mData << pNormal.x() << pNormal.z() << - pNormal.y(); } } else { if ( !qgsDoubleNear( pNormal.length(), 1, 0.001 ) ) return; // this should not happen - pNormal should be normalized to unit length QVector3D pXVector, pYVector; _normalVectorToXYVectors( pNormal, pXVector, pYVector ); // so now we have three orthogonal unit vectors defining new base // let's build transform matrix. We actually need just a 3x3 matrix, // but Qt does not have good support for it, so using 4x4 matrix instead. QMatrix4x4 toNewBase( pXVector.x(), pXVector.y(), pXVector.z(), 0, pYVector.x(), pYVector.y(), pYVector.z(), 0, pNormal.x(), pNormal.y(), pNormal.z(), 0, 0, 0, 0, 0 ); // our 3x3 matrix is orthogonal, so for inverse we only need to transpose it QMatrix4x4 toOldBase = toNewBase.transposed(); const QgsPoint ptFirst( exterior->startPoint() ); _ringToPoly2tri( exterior, ptFirst, toNewBase, polyline, z ); polylinesToDelete << polyline; // TODO: robustness (no nearly duplicate points, invalid geometries ...) double x0 = ptFirst.x(), y0 = ptFirst.y(), z0 = ( std::isnan( ptFirst.z() ) ? 0 : ptFirst.z() ); if ( polyline.size() == 3 && polygon.numInteriorRings() == 0 ) { for ( std::vector<p2t::Point *>::iterator it = polyline.begin(); it != polyline.end(); it++ ) { p2t::Point *p = *it; QVector4D ptInNewBase( p->x, p->y, z[p], 0 ); QVector4D nPoint = toOldBase * ptInNewBase; const double fx = nPoint.x() - mOriginX + x0; const double fy = nPoint.y() - mOriginY + y0; const double fz = nPoint.z() + extrusionHeight + z0; mData << fx << fz << -fy; if ( mAddNormals ) mData << pNormal.x() << pNormal.z() << - pNormal.y(); } } else if ( polyline.size() >= 3 ) { p2t::CDT *cdt = new p2t::CDT( polyline ); // polygon holes for ( int i = 0; i < polygon.numInteriorRings(); ++i ) { std::vector<p2t::Point *> holePolyline; const QgsCurve *hole = polygon.interiorRing( i ); _ringToPoly2tri( hole, ptFirst, toNewBase, holePolyline, z ); cdt->AddHole( holePolyline ); polylinesToDelete << holePolyline; } try { cdt->Triangulate(); std::vector<p2t::Triangle *> triangles = cdt->GetTriangles(); for ( size_t i = 0; i < triangles.size(); ++i ) { p2t::Triangle *t = triangles[i]; for ( int j = 0; j < 3; ++j ) { p2t::Point *p = t->GetPoint( j ); QVector4D ptInNewBase( p->x, p->y, z[p], 0 ); QVector4D nPoint = toOldBase * ptInNewBase; const double fx = nPoint.x() - mOriginX + x0; const double fy = nPoint.y() - mOriginY + y0; const double fz = nPoint.z() + extrusionHeight + z0; mData << fx << fz << -fy; if ( mAddNormals ) mData << pNormal.x() << pNormal.z() << - pNormal.y(); } } } catch ( ... ) { QgsMessageLog::logMessage( "Triangulation failed. Skipping polygon...", "3D" ); } delete cdt; } for ( int i = 0; i < polylinesToDelete.count(); ++i ) qDeleteAll( polylinesToDelete[i] ); } // add walls if extrusion is enabled if ( extrusionHeight != 0 ) { _makeWalls( *exterior, false, extrusionHeight, mData, mAddNormals, mOriginX, mOriginY ); for ( int i = 0; i < polygon.numInteriorRings(); ++i ) _makeWalls( *polygon.interiorRing( i ), true, extrusionHeight, mData, mAddNormals, mOriginX, mOriginY ); } }
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 ); } } } } }
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 }
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; }
void TestQgsDistanceArea::measureAreaAndUnits() { QgsDistanceArea da; da.setSourceCrs( 3452 ); da.setEllipsoidalMode( false ); da.setEllipsoid( "NONE" ); QgsCoordinateReferenceSystem daCRS; daCRS.createFromSrsId( da.sourceCrsId() ); QgsPolyline ring; ring << QgsPoint( 0, 0 ) << QgsPoint( 1, 0 ) << QgsPoint( 1, 1 ) << QgsPoint( 2, 1 ) << QgsPoint( 2, 2 ) << QgsPoint( 0, 2 ) << QgsPoint( 0, 0 ); QgsPolygon poly; poly << ring; QgsGeometry polygon( QgsGeometry::fromPolygon( poly ) ); // We check both the measured area AND the units, in case the logic regarding // ellipsoids and units changes in future double area = da.measureArea( &polygon ); QgsUnitTypes::AreaUnit units = da.areaUnits(); QgsDebugMsg( QString( "measured %1 in %2" ).arg( area ).arg( QgsUnitTypes::toString( units ) ) ); QVERIFY(( qgsDoubleNear( area, 3.0, 0.00000001 ) && units == QgsUnitTypes::AreaSquareDegrees ) || ( qgsDoubleNear( area, 37176087091.5, 0.1 ) && units == QgsUnitTypes::AreaSquareMeters ) ); da.setEllipsoid( "WGS84" ); area = da.measureArea( &polygon ); units = da.areaUnits(); QgsDebugMsg( QString( "measured %1 in %2" ).arg( area ).arg( QgsUnitTypes::toString( units ) ) ); QVERIFY(( qgsDoubleNear( area, 3.0, 0.00000001 ) && units == QgsUnitTypes::AreaSquareDegrees ) || ( qgsDoubleNear( area, 37176087091.5, 0.1 ) && units == QgsUnitTypes::AreaSquareMeters ) ); da.setEllipsoidalMode( true ); area = da.measureArea( &polygon ); units = da.areaUnits(); QgsDebugMsg( QString( "measured %1 in %2" ).arg( area ).arg( QgsUnitTypes::toString( units ) ) ); // should always be in Meters Squared QGSCOMPARENEAR( area, 37416879192.9, 0.1 ); QCOMPARE( units, QgsUnitTypes::AreaSquareMeters ); // test converting the resultant area area = da.convertAreaMeasurement( area, QgsUnitTypes::AreaSquareMiles ); QGSCOMPARENEAR( area, 14446.7378, 0.001 ); // now try with a source CRS which is in feet ring.clear(); ring << QgsPoint( 1850000, 4423000 ) << QgsPoint( 1851000, 4423000 ) << QgsPoint( 1851000, 4424000 ) << QgsPoint( 1852000, 4424000 ) << QgsPoint( 1852000, 4425000 ) << QgsPoint( 1851000, 4425000 ) << QgsPoint( 1850000, 4423000 ); poly.clear(); poly << ring; polygon = QgsGeometry::fromPolygon( poly ); da.setSourceCrs( 27469 ); da.setEllipsoidalMode( false ); // measurement should be in square feet area = da.measureArea( &polygon ); units = da.areaUnits(); QgsDebugMsg( QString( "measured %1 in %2" ).arg( area ).arg( QgsUnitTypes::toString( units ) ) ); QGSCOMPARENEAR( area, 2000000, 0.001 ); QCOMPARE( units, QgsUnitTypes::AreaSquareFeet ); // test converting the resultant area area = da.convertAreaMeasurement( area, QgsUnitTypes::AreaSquareYards ); QGSCOMPARENEAR( area, 222222.2222, 0.001 ); da.setEllipsoidalMode( true ); // now should be in Square Meters again area = da.measureArea( &polygon ); units = da.areaUnits(); QgsDebugMsg( QString( "measured %1 in %2" ).arg( area ).arg( QgsUnitTypes::toString( units ) ) ); QGSCOMPARENEAR( area, 184149.37, 1.0 ); QCOMPARE( units, QgsUnitTypes::AreaSquareMeters ); // test converting the resultant area area = da.convertAreaMeasurement( area, QgsUnitTypes::AreaSquareYards ); QgsDebugMsg( QString( "measured %1 in sq yrds" ).arg( area ) ); QGSCOMPARENEAR( area, 220240.8172549, 0.00001 ); }
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 }
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(); }