void QgsPolygonV2::setExteriorRing( QgsCurve *ring ) { if ( !ring ) { return; } if ( ring->hasCurvedSegments() ) { //need to segmentize ring as polygon does not support curves QgsCurve *line = ring->segmentize(); delete ring; ring = line; } QgsLineString *lineString = qgsgeometry_cast< QgsLineString *>( ring ); if ( lineString && !lineString->isClosed() ) { lineString->close(); } mExteriorRing.reset( ring ); //set proper wkb type setZMTypeFromSubGeometry( ring, QgsWkbTypes::Polygon ); //match dimensionality for rings for ( QgsCurve *ring : qgis::as_const( mInteriorRings ) ) { ring->convertTo( mExteriorRing->wkbType() ); } clearCache(); }
//! Generalize the WKB-geometry using the BBOX of the original geometry static QgsGeometry generalizeWkbGeometryByBoundingBox( QgsWkbTypes::Type wkbType, const QgsAbstractGeometry& geometry, const QgsRectangle &envelope ) { unsigned int geometryType = QgsWkbTypes::singleType( QgsWkbTypes::flatType( wkbType ) ); // If the geometry is already minimal skip the generalization int minimumSize = geometryType == QgsWkbTypes::LineString ? 2 : 5; if ( geometry.nCoordinates() <= minimumSize ) { return QgsGeometry( geometry.clone() ); } const double x1 = envelope.xMinimum(); const double y1 = envelope.yMinimum(); const double x2 = envelope.xMaximum(); const double y2 = envelope.yMaximum(); // Write the generalized geometry if ( geometryType == QgsWkbTypes::LineString ) { QgsLineString* lineString = new QgsLineString(); lineString->addVertex( QgsPointV2( x1, y1 ) ); lineString->addVertex( QgsPointV2( x2, y2 ) ); return QgsGeometry( lineString ); } else { return QgsGeometry::fromRect( envelope ); } }
void QgsPolygonV2::addInteriorRing( QgsCurve *ring ) { if ( !ring ) return; if ( ring->hasCurvedSegments() ) { //can't add a curved ring to a QgsPolygonV2 QgsLineString *segmented = ring->curveToLine(); delete ring; ring = segmented; } QgsLineString *lineString = qgsgeometry_cast< QgsLineString *>( ring ); if ( lineString && !lineString->isClosed() ) { lineString->close(); } if ( mWkbType == QgsWkbTypes::Polygon25D ) { ring->convertTo( QgsWkbTypes::LineString25D ); mInteriorRings.append( ring ); } else { QgsCurvePolygon::addInteriorRing( ring ); } clearCache(); }
// Need NO or >1 points. Duplicate first if only one. static bool lwline_make_geos_friendly( QgsLineString &line ) { if ( line.numPoints() == 1 ) // 0 is fine, 2 is fine { line.addVertex( line.startPoint() ); } return true; }
QDomElement QgsCircularString::asGML2( QDomDocument &doc, int precision, const QString &ns ) const { // GML2 does not support curves QgsLineString *line = curveToLine(); QDomElement gml = line->asGML2( doc, precision, ns ); delete line; return gml; }
QString QgsCircularString::asJSON( int precision ) const { // GeoJSON does not support curves QgsLineString *line = curveToLine(); QString json = line->asJSON( precision ); delete line; return json; }
void QgsMapToolCapture::setPoints( const QVector<QgsPointXY> &pointList ) { QgsLineString *line = new QgsLineString( pointList ); mCaptureCurve.clear(); mCaptureCurve.addCurve( line ); mSnappingMatches.clear(); for ( int i = 0; i < line->length(); ++i ) mSnappingMatches.append( QgsPointLocator::Match() ); }
void QgsTriangle::setExteriorRing( QgsCurve *ring ) { if ( !ring ) { return; } if ( ring->hasCurvedSegments() ) { //need to segmentize ring as polygon does not support curves QgsCurve *line = ring->segmentize(); delete ring; ring = line; } if ( ( ring->numPoints() > 4 ) || ( ring->numPoints() < 3 ) ) { delete ring; return; } else if ( ring->numPoints() == 4 ) { if ( !ring->isClosed() ) { delete ring; return; } } else if ( ring->numPoints() == 3 ) { if ( ring->isClosed() ) { delete ring; return; } QgsLineString *lineString = static_cast< QgsLineString *>( ring ); if ( !lineString->isClosed() ) { lineString->close(); } ring = lineString; } if ( !validateGeom( ring->vertexAt( QgsVertexId( 0, 0, 0 ) ), ring->vertexAt( QgsVertexId( 0, 0, 1 ) ), ring->vertexAt( QgsVertexId( 0, 0, 2 ) ) ) ) { delete ring; return; } mExteriorRing.reset( ring ); //set proper wkb type setZMTypeFromSubGeometry( ring, QgsWkbTypes::Triangle ); clearCache(); }
QgsLineString *QgsCompoundCurve::curveToLine( double tolerance, SegmentationToleranceType toleranceType ) const { QgsLineString *line = new QgsLineString(); std::unique_ptr< QgsLineString > currentLine; for ( const QgsCurve *curve : mCurves ) { currentLine.reset( curve->curveToLine( tolerance, toleranceType ) ); line->append( currentLine.get() ); } return line; }
int QgsVectorLayerEditUtils::addRing( const QList<QgsPoint>& ring, const QgsFeatureIds& targetFeatureIds, QgsFeatureId* modifiedFeatureId ) { QgsLineString* ringLine = new QgsLineString(); QgsPointSequence ringPoints; QList<QgsPoint>::const_iterator ringIt = ring.constBegin(); for ( ; ringIt != ring.constEnd(); ++ringIt ) { ringPoints.append( QgsPointV2( ringIt->x(), ringIt->y() ) ); } ringLine->setPoints( ringPoints ); return addRing( ringLine, targetFeatureIds, modifiedFeatureId ); }
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 ); }
QgsLineString *QgsCircularString::curveToLine( double tolerance, SegmentationToleranceType toleranceType ) const { QgsLineString *line = new QgsLineString(); QgsPointSequence points; int nPoints = numPoints(); for ( int i = 0; i < ( nPoints - 2 ) ; i += 2 ) { segmentize( pointN( i ), pointN( i + 1 ), pointN( i + 2 ), points, tolerance, toleranceType ); } line->setPoints( points ); return line; }
QgsLineString *QgsLineString::reversed() const { QgsLineString *copy = clone(); std::reverse( copy->mX.begin(), copy->mX.end() ); std::reverse( copy->mY.begin(), copy->mY.end() ); if ( copy->is3D() ) { std::reverse( copy->mZ.begin(), copy->mZ.end() ); } if ( copy->isMeasure() ) { std::reverse( copy->mM.begin(), copy->mM.end() ); } return copy; }
bool QgsTriangle::fromWkb( QgsConstWkbPtr &wkbPtr ) { clear(); if ( !wkbPtr ) { return false; } QgsWkbTypes::Type type = wkbPtr.readHeader(); if ( QgsWkbTypes::flatType( type ) != QgsWkbTypes::Triangle ) { return false; } mWkbType = type; QgsWkbTypes::Type ringType; switch ( mWkbType ) { case QgsWkbTypes::TriangleZ: ringType = QgsWkbTypes::LineStringZ; break; case QgsWkbTypes::TriangleM: ringType = QgsWkbTypes::LineStringM; break; case QgsWkbTypes::TriangleZM: ringType = QgsWkbTypes::LineStringZM; break; default: ringType = QgsWkbTypes::LineString; break; } int nRings; wkbPtr >> nRings; if ( nRings > 1 ) { return false; } QgsLineString *line = new QgsLineString(); line->fromWkbPoints( ringType, wkbPtr ); if ( !mExteriorRing ) { mExteriorRing = line; } return true; }
int QgsMapToolCapture::addCurve( QgsCurve *c ) { if ( !c ) { return 1; } if ( !mRubberBand ) { mRubberBand = createRubberBand( mCaptureMode == CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry ); } QgsLineString *lineString = c->curveToLine(); QgsPointSequence linePoints; lineString->points( linePoints ); delete lineString; QgsPointSequence::const_iterator ptIt = linePoints.constBegin(); for ( ; ptIt != linePoints.constEnd(); ++ptIt ) { mRubberBand->addPoint( QgsPointXY( ptIt->x(), ptIt->y() ) ); } if ( !mTempRubberBand ) { mTempRubberBand = createRubberBand( mCaptureMode == CapturePolygon ? QgsWkbTypes::PolygonGeometry : QgsWkbTypes::LineGeometry, true ); } else { mTempRubberBand->reset(); } QgsPoint endPt = c->endPoint(); mTempRubberBand->addPoint( QgsPointXY( endPt.x(), endPt.y() ) ); //add last point of c //transform back to layer CRS in case map CRS and layer CRS are different QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mCanvas->currentLayer() ); QgsCoordinateTransform ct = mCanvas->mapSettings().layerTransform( vlayer ); if ( ct.isValid() ) { c->transform( ct, QgsCoordinateTransform::ReverseTransform ); } mCaptureCurve.addCurve( c ); for ( int i = 0; i < c->length(); ++i ) mSnappingMatches.append( QgsPointLocator::Match() ); return 0; }
QString QgsMultiSurface::asJSON( int precision ) const { // GeoJSON does not support curves QString json = QStringLiteral( "{\"type\": \"MultiPolygon\", \"coordinates\": [" ); Q_FOREACH ( const QgsAbstractGeometry *geom, mGeometries ) { if ( dynamic_cast<const QgsSurface*>( geom ) ) { json += '['; QgsPolygonV2* polygon = static_cast<const QgsSurface*>( geom )->surfaceToPolygon(); QgsLineString* exteriorLineString = polygon->exteriorRing()->curveToLine(); QgsPointSequence exteriorPts; exteriorLineString->points( exteriorPts ); json += QgsGeometryUtils::pointsToJSON( exteriorPts, precision ) + ", "; delete exteriorLineString; for ( int i = 0, n = polygon->numInteriorRings(); i < n; ++i ) { QgsLineString* interiorLineString = polygon->interiorRing( i )->curveToLine(); QgsPointSequence interiorPts; interiorLineString->points( interiorPts ); json += QgsGeometryUtils::pointsToJSON( interiorPts, precision ) + ", "; delete interiorLineString; } if ( json.endsWith( QLatin1String( ", " ) ) ) { json.chop( 2 ); // Remove last ", " } delete polygon; json += QLatin1String( "], " ); } } if ( json.endsWith( QLatin1String( ", " ) ) ) { json.chop( 2 ); // Remove last ", " } json += QLatin1String( "] }" ); return json; }
static bool ring_make_geos_friendly( QgsCurve *ring ) { if ( ring->nCoordinates() == 0 ) return false; // earlier we allowed in only geometries with straight segments QgsLineString *linestring = qgsgeometry_cast<QgsLineString *>( ring ); // close the ring if not already closed (2d only) QgsPoint p1 = linestring->startPoint(), p2 = linestring->endPoint(); if ( p1.x() != p2.x() || p1.y() != p2.y() ) linestring->addVertex( p1 ); // must have at least 4 coordinates to be accepted by GEOS while ( linestring->nCoordinates() < 4 ) linestring->addVertex( p1 ); return true; }
bool QgsCompoundCurve::deleteVertex( QgsVertexId position ) { QVector< QPair<int, QgsVertexId> > curveIds = curveVertexId( position ); if ( curveIds.size() == 1 ) { if ( !mCurves.at( curveIds.at( 0 ).first )->deleteVertex( curveIds.at( 0 ).second ) ) { clearCache(); //bbox may have changed return false; } if ( mCurves.at( curveIds.at( 0 ).first )->numPoints() == 0 ) { removeCurve( curveIds.at( 0 ).first ); } } else if ( curveIds.size() == 2 ) { Q_ASSERT( curveIds.at( 1 ).first == curveIds.at( 0 ).first + 1 ); Q_ASSERT( curveIds.at( 0 ).second.vertex == mCurves.at( curveIds.at( 0 ).first )->numPoints() - 1 ); Q_ASSERT( curveIds.at( 1 ).second.vertex == 0 ); QgsPoint startPoint = mCurves.at( curveIds.at( 0 ).first ) ->startPoint(); QgsPoint endPoint = mCurves.at( curveIds.at( 1 ).first ) ->endPoint(); if ( QgsWkbTypes::flatType( mCurves.at( curveIds.at( 0 ).first )->wkbType() ) == QgsWkbTypes::LineString && QgsWkbTypes::flatType( mCurves.at( curveIds.at( 1 ).first )->wkbType() ) == QgsWkbTypes::CircularString && mCurves.at( curveIds.at( 1 ).first )->numPoints() > 3 ) { QgsPoint intermediatePoint; QgsVertexId::VertexType type; mCurves.at( curveIds.at( 1 ).first ) ->pointAt( 2, intermediatePoint, type ); mCurves.at( curveIds.at( 0 ).first )->moveVertex( QgsVertexId( 0, 0, mCurves.at( curveIds.at( 0 ).first )->numPoints() - 1 ), intermediatePoint ); } else if ( !mCurves.at( curveIds.at( 0 ).first )->deleteVertex( curveIds.at( 0 ).second ) ) { clearCache(); //bbox may have changed return false; } if ( QgsWkbTypes::flatType( mCurves.at( curveIds.at( 0 ).first )->wkbType() ) == QgsWkbTypes::CircularString && mCurves.at( curveIds.at( 0 ).first )->numPoints() > 0 && QgsWkbTypes::flatType( mCurves.at( curveIds.at( 1 ).first )->wkbType() ) == QgsWkbTypes::LineString ) { QgsPoint intermediatePoint = mCurves.at( curveIds.at( 0 ).first ) ->endPoint(); mCurves.at( curveIds.at( 1 ).first )->moveVertex( QgsVertexId( 0, 0, 0 ), intermediatePoint ); } else if ( !mCurves.at( curveIds.at( 1 ).first )->deleteVertex( curveIds.at( 1 ).second ) ) { clearCache(); //bbox may have changed return false; } if ( mCurves.at( curveIds.at( 0 ).first )->numPoints() == 0 && mCurves.at( curveIds.at( 1 ).first )->numPoints() != 0 ) { mCurves.at( curveIds.at( 1 ).first )->moveVertex( QgsVertexId( 0, 0, 0 ), startPoint ); removeCurve( curveIds.at( 0 ).first ); } else if ( mCurves.at( curveIds.at( 0 ).first )->numPoints() != 0 && mCurves.at( curveIds.at( 1 ).first )->numPoints() == 0 ) { mCurves.at( curveIds.at( 0 ).first )->moveVertex( QgsVertexId( 0, 0, mCurves.at( curveIds.at( 0 ).first )->numPoints() - 1 ), endPoint ); removeCurve( curveIds.at( 1 ).first ); } else if ( mCurves.at( curveIds.at( 0 ).first )->numPoints() == 0 && mCurves.at( curveIds.at( 1 ).first )->numPoints() == 0 ) { removeCurve( curveIds.at( 1 ).first ); removeCurve( curveIds.at( 0 ).first ); QgsLineString *line = new QgsLineString(); line->insertVertex( QgsVertexId( 0, 0, 0 ), startPoint ); line->insertVertex( QgsVertexId( 0, 0, 1 ), endPoint ); mCurves.insert( curveIds.at( 0 ).first, line ); } else { QgsPoint endPointOfFirst = mCurves.at( curveIds.at( 0 ).first ) ->endPoint(); QgsPoint startPointOfSecond = mCurves.at( curveIds.at( 1 ).first ) ->startPoint(); if ( endPointOfFirst != startPointOfSecond ) { QgsLineString *line = new QgsLineString(); line->insertVertex( QgsVertexId( 0, 0, 0 ), endPointOfFirst ); line->insertVertex( QgsVertexId( 0, 0, 1 ), startPointOfSecond ); mCurves.insert( curveIds.at( 1 ).first, line ); } } } bool success = !curveIds.isEmpty(); if ( success ) { clearCache(); //bbox changed } return success; }
void QgsCompoundCurve::addVertex( const QgsPoint &pt ) { if ( mCurves.isEmpty() || mWkbType == QgsWkbTypes::Unknown ) { setZMTypeFromSubGeometry( &pt, QgsWkbTypes::CompoundCurve ); } //is last curve QgsLineString QgsCurve *lastCurve = nullptr; if ( !mCurves.isEmpty() ) { lastCurve = mCurves.at( mCurves.size() - 1 ); } QgsLineString *line = nullptr; if ( !lastCurve || QgsWkbTypes::flatType( lastCurve->wkbType() ) != QgsWkbTypes::LineString ) { line = new QgsLineString(); mCurves.append( line ); if ( lastCurve ) { line->addVertex( lastCurve->endPoint() ); } lastCurve = line; } else //create new QgsLineString* with point in it { line = static_cast<QgsLineString *>( lastCurve ); } line->addVertex( pt ); clearCache(); }