25 #include <QPainterPath> 47 if ( mCurves.size() != otherCurve->mCurves.size() )
50 for (
int i = 0; i < mCurves.size(); ++i )
52 if ( *mCurves.at( i ) != *otherCurve->mCurves.at( i ) )
61 auto result = qgis::make_unique< QgsCompoundCurve >();
63 return result.release();
68 return QStringLiteral(
"CompoundCurve" );
81 mCurves.append( static_cast<QgsCurve *>( c->
clone() ) );
93 mCurves.append( static_cast<QgsCurve *>( c->
clone() ) );
107 qDeleteAll( mCurves );
114 if ( mCurves.empty() )
120 for (
int i = 1; i < mCurves.size(); ++i )
146 for (
int i = 0; i <
nCurves; ++i )
149 wkbPtr -= 1 +
sizeof( int );
162 currentCurve->
fromWkb( wkbPtr );
163 mCurves.append( currentCurve );
178 QString defaultChildWkbType = QStringLiteral(
"LineString%1%2" ).arg(
is3D() ? QStringLiteral(
"Z" ) : QString(),
isMeasure() ? QStringLiteral(
"M" ) : QString() );
181 for (
const QString &childWkt : blocks )
194 if ( !mCurves.back()->fromWkt( childWkt ) )
205 for (
const QgsCurve *curve : qgis::as_const( mCurves ) )
207 hasZ = hasZ || curve->is3D();
208 hasM = hasM || curve->isMeasure();
222 int binarySize =
sizeof( char ) +
sizeof( quint32 ) +
sizeof( quint32 );
223 QVector<QByteArray> wkbForCurves;
224 for (
const QgsCurve *curve : mCurves )
226 QByteArray wkbForCurve = curve->asWkb();
227 binarySize += wkbForCurve.length();
228 wkbForCurves << wkbForCurve;
232 wkbArray.resize( binarySize );
235 wkb << static_cast<quint32>(
wkbType() );
236 wkb << static_cast<quint32>( mCurves.size() );
237 for (
const QByteArray &wkbForCurve : qgis::as_const( wkbForCurves ) )
247 for (
const QgsCurve *curve : mCurves )
249 QString childWkt = curve->asWkt( precision );
250 if ( qgsgeometry_cast<const QgsLineString *>( curve ) )
253 childWkt = childWkt.mid( childWkt.indexOf(
'(' ) );
255 wkt += childWkt +
',';
257 if ( wkt.endsWith(
',' ) )
268 std::unique_ptr< QgsLineString > line(
curveToLine() );
269 QDomElement gml = line->asGml2( doc, precision, ns, axisOrder );
275 QDomElement compoundCurveElem = doc.createElementNS( ns, QStringLiteral(
"CompositeCurve" ) );
278 return compoundCurveElem;
280 for (
const QgsCurve *curve : mCurves )
282 QDomElement curveMemberElem = doc.createElementNS( ns, QStringLiteral(
"curveMember" ) );
283 QDomElement curveElem = curve->asGml3( doc, precision, ns, axisOrder );
284 curveMemberElem.appendChild( curveElem );
285 compoundCurveElem.appendChild( curveMemberElem );
288 return compoundCurveElem;
294 std::unique_ptr< QgsLineString > line(
curveToLine() );
295 QString json = line->asJson( precision );
302 for (
const QgsCurve *curve : mCurves )
304 length += curve->length();
311 if ( mCurves.empty() )
315 return mCurves.at( 0 )->startPoint();
320 if ( mCurves.empty() )
324 return mCurves.at( mCurves.size() - 1 )->
endPoint();
330 if ( mCurves.empty() )
335 mCurves[0]->points( pts );
336 for (
int i = 1; i < mCurves.size(); ++i )
339 mCurves[i]->points( pList );
354 for (
int i = 0; i <
nCurves; ++i )
356 nPoints += mCurves.at( i )->numPoints() - 1;
364 if ( mCurves.isEmpty() )
369 if ( !curve->isEmpty() )
378 std::unique_ptr< QgsLineString > currentLine;
379 for (
const QgsCurve *curve : mCurves )
381 currentLine.reset( curve->curveToLine( tolerance, toleranceType ) );
382 line->
append( currentLine.get() );
393 std::unique_ptr<QgsCurve> gridified( static_cast< QgsCurve * >( curve->snappedToGrid( hSpacing, vSpacing, dSpacing, mSpacing ) ) );
396 result->mCurves.append( gridified.release() );
400 if ( result->mCurves.empty() )
403 return result.release();
409 const QVector< QgsCurve * > curves = mCurves;
415 if ( curve->numPoints() == 0 ||
qgsDoubleNear( curve->length(), 0.0, epsilon ) )
418 delete mCurves.takeAt( i );
426 curve->moveVertex(
QgsVertexId( -1, -1, 0 ), lastEnd );
437 if ( i < 0 || i >= mCurves.size() )
441 return mCurves.at( i );
448 if ( mCurves.empty() )
477 if ( i < 0 || i >= mCurves.size() )
482 delete mCurves.takeAt( i );
495 if ( !mCurves.isEmpty() )
497 lastCurve = mCurves.at( mCurves.size() - 1 );
504 mCurves.append( line );
521 for (
const QgsCurve *curve : mCurves )
529 for (
QgsCurve *curve : qgis::as_const( mCurves ) )
531 curve->transform( ct, d, transformZ );
538 for (
QgsCurve *curve : qgis::as_const( mCurves ) )
540 curve->transform( t, zTranslate, zScale, mTranslate, mScale );
548 for (
const QgsCurve *curve : mCurves )
550 curve->addToPainterPath( pp );
558 for (
const QgsCurve *curve : mCurves )
560 curve->addToPainterPath( pp );
567 QVector< QPair<int, QgsVertexId> > curveIds = curveVertexId( position );
568 if ( curveIds.empty() )
572 int curveId = curveIds.at( 0 ).first;
573 if ( curveId >= mCurves.size() )
578 bool success = mCurves.at( curveId )->insertVertex( curveIds.at( 0 ).second, vertex );
588 QVector< QPair<int, QgsVertexId> > curveIds = curveVertexId( position );
589 QVector< QPair<int, QgsVertexId> >::const_iterator idIt = curveIds.constBegin();
590 for ( ; idIt != curveIds.constEnd(); ++idIt )
592 mCurves.at( idIt->first )->moveVertex( idIt->second, newPos );
595 bool success = !curveIds.isEmpty();
605 QVector< QPair<int, QgsVertexId> > curveIds = curveVertexId( position );
606 if ( curveIds.size() == 1 )
608 if ( !mCurves.at( curveIds.at( 0 ).first )->
deleteVertex( curveIds.at( 0 ).second ) )
613 if ( mCurves.at( curveIds.at( 0 ).first )->
numPoints() == 0 )
618 else if ( curveIds.size() == 2 )
620 Q_ASSERT( curveIds.at( 1 ).first == curveIds.at( 0 ).first + 1 );
621 Q_ASSERT( curveIds.at( 0 ).second.vertex == mCurves.at( curveIds.at( 0 ).first )->
numPoints() - 1 );
622 Q_ASSERT( curveIds.at( 1 ).second.vertex == 0 );
627 mCurves.at( curveIds.at( 1 ).first )->
numPoints() > 3 )
631 mCurves.at( curveIds.at( 1 ).first ) ->
pointAt( 2, intermediatePoint, type );
632 mCurves.at( curveIds.at( 0 ).first )->
moveVertex(
633 QgsVertexId( 0, 0, mCurves.at( curveIds.at( 0 ).first )->
numPoints() - 1 ), intermediatePoint );
635 else if ( !mCurves.at( curveIds.at( 0 ).first )->
deleteVertex( curveIds.at( 0 ).second ) )
641 mCurves.at( curveIds.at( 0 ).first )->
numPoints() > 0 &&
644 QgsPoint intermediatePoint = mCurves.at( curveIds.at( 0 ).first ) ->
endPoint();
647 else if ( !mCurves.at( curveIds.at( 1 ).first )->
deleteVertex( curveIds.at( 1 ).second ) )
652 if ( mCurves.at( curveIds.at( 0 ).first )->
numPoints() == 0 &&
653 mCurves.at( curveIds.at( 1 ).first )->
numPoints() != 0 )
658 else if ( mCurves.at( curveIds.at( 0 ).first )->
numPoints() != 0 &&
659 mCurves.at( curveIds.at( 1 ).first )->
numPoints() == 0 )
661 mCurves.at( curveIds.at( 0 ).first )->
moveVertex(
665 else if ( mCurves.at( curveIds.at( 0 ).first )->
numPoints() == 0 &&
666 mCurves.at( curveIds.at( 1 ).first )->
numPoints() == 0 )
671 line->insertVertex(
QgsVertexId( 0, 0, 0 ), startPoint );
672 line->insertVertex(
QgsVertexId( 0, 0, 1 ), endPoint );
673 mCurves.insert( curveIds.at( 0 ).first, line );
677 QgsPoint endPointOfFirst = mCurves.at( curveIds.at( 0 ).first ) ->
endPoint();
679 if ( endPointOfFirst != startPointOfSecond )
684 mCurves.insert( curveIds.at( 1 ).first, line );
689 bool success = !curveIds.isEmpty();
697 QVector< QPair<int, QgsVertexId> > QgsCompoundCurve::curveVertexId(
QgsVertexId id )
const 699 QVector< QPair<int, QgsVertexId> > curveIds;
701 int currentVertexIndex = 0;
702 for (
int i = 0; i < mCurves.size(); ++i )
704 int increment = mCurves.at( i )->numPoints() - 1;
705 if (
id.vertex >= currentVertexIndex &&
id.vertex <= currentVertexIndex + increment )
707 int curveVertexId =
id.vertex - currentVertexIndex;
711 vid.
vertex = curveVertexId;
712 curveIds.append( qMakePair( i, vid ) );
713 if ( curveVertexId == increment && i < ( mCurves.size() - 1 ) )
716 curveIds.append( qMakePair( i + 1, vid ) );
720 currentVertexIndex += increment;
733 int currentVertexId = 0;
734 for (
int j = 0; j < mCurves.size(); ++j )
736 int nCurvePoints = mCurves.at( j )->numPoints();
737 if ( ( node - currentVertexId ) < nCurvePoints )
739 return ( mCurves.at( j )->pointAt( node - currentVertexId, point, type ) );
741 currentVertexId += ( nCurvePoints - 1 );
748 int currentVertexId = 0;
749 for (
int j = 0; j < mCurves.size(); ++j )
751 int nCurvePoints = mCurves.at( j )->numPoints();
752 if ( ( index - currentVertexId ) < nCurvePoints )
754 return mCurves.at( j )->xAt( index - currentVertexId );
756 currentVertexId += ( nCurvePoints - 1 );
763 int currentVertexId = 0;
764 for (
int j = 0; j < mCurves.size(); ++j )
766 int nCurvePoints = mCurves.at( j )->numPoints();
767 if ( ( index - currentVertexId ) < nCurvePoints )
769 return mCurves.at( j )->yAt( index - currentVertexId );
771 currentVertexId += ( nCurvePoints - 1 );
778 for (
QgsCurve *curve : qgis::as_const( mCurves ) )
780 curve->filterVertices( filter );
787 for (
const QgsCurve *curve : mCurves )
789 curve->sumUpArea( sum );
804 for (
const QgsCurve *curve : mCurves )
806 if ( curve->hasCurvedSegments() )
816 QVector< QPair<int, QgsVertexId> > curveIds = curveVertexId( vertex );
817 if ( curveIds.size() == 1 )
819 QgsCurve *curve = mCurves[curveIds.at( 0 ).first];
820 return curve->
vertexAngle( curveIds.at( 0 ).second );
822 else if ( curveIds.size() > 1 )
824 QgsCurve *curve1 = mCurves[curveIds.at( 0 ).first];
825 QgsCurve *curve2 = mCurves[curveIds.at( 1 ).first];
826 double angle1 = curve1->
vertexAngle( curveIds.at( 0 ).second );
827 double angle2 = curve2->
vertexAngle( curveIds.at( 1 ).second );
838 QVector< QPair<int, QgsVertexId> > curveIds = curveVertexId( startVertex );
840 for (
auto it = curveIds.constBegin(); it != curveIds.constEnd(); ++it )
842 length += mCurves.at( it->first )->segmentLength( it->second );
850 for (
int i = mCurves.count() - 1; i >= 0; --i )
852 QgsCurve *reversedCurve = mCurves.at( i )->reversed();
865 for (
QgsCurve *curve : qgis::as_const( mCurves ) )
867 curve->addZValue( zValue );
880 for (
QgsCurve *curve : qgis::as_const( mCurves ) )
882 curve->addMValue( mValue );
894 for (
QgsCurve *curve : qgis::as_const( mCurves ) )
908 for (
QgsCurve *curve : qgis::as_const( mCurves ) )
918 for (
QgsCurve *curve : qgis::as_const( mCurves ) )
bool isMeasure() const
Returns true if the geometry contains m values.
QgsPoint startPoint() const override
Returns the starting point of the curve.
bool insertVertex(QgsVertexId position, const QgsPoint &vertex) override
Inserts a vertex into the geometry.
void append(const QgsLineString *line)
Appends the contents of another line string to the end of this line string.
QgsCompoundCurve * clone() const override
Clones the geometry by performing a deep copy.
A rectangle specified with double values.
bool addMValue(double mValue=0) override
Adds a measure to the geometry, initialized to a preset value.
void addToPainterPath(QPainterPath &path) const override
Adds a curve to a painter path.
double xAt(int index) const override
Returns the x-coordinate of the specified node in the line string.
QgsAbstractGeometry & operator=(const QgsAbstractGeometry &geom)
bool addZValue(double zValue=0) override
Adds a z-dimension to the geometry, initialized to a preset value.
QgsLineString * curveToLine(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const override
Returns a new line string geometry corresponding to a segmentized approximation of the curve...
static QPair< QgsWkbTypes::Type, QString > wktReadBlock(const QString &wkt)
Parses a WKT block of the format "TYPE( contents )" and returns a pair of geometry type to contents (...
int dimension() const override
Returns the inherent dimension of the geometry.
static double averageAngle(double x1, double y1, double x2, double y2, double x3, double y3)
Calculates the average angle (in radians) between the two linear segments from (x1, y1) to (x2, y2) and (x2, y2) to (x3, y3).
void sumUpArea(double &sum) const override
Sums up the area of the curve by iterating over the vertices (shoelace formula).
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
void swapXy() override
Swaps the x and y coordinates from the geometry.
double closestSegment(const QgsPoint &pt, QgsPoint &segmentPt, QgsVertexId &vertexAfter, int *leftOf=nullptr, double epsilon=4 *std::numeric_limits< double >::epsilon()) const override
Searches for the closest segment of the geometry to a given point.
QString asJson(int precision=17) const override
Returns a GeoJSON representation of the geometry.
double vertexAngle(QgsVertexId vertex) const override
Returns approximate angle at a vertex.
virtual double vertexAngle(QgsVertexId vertex) const =0
Returns approximate angle at a vertex.
virtual bool addMValue(double mValue=0)=0
Adds a measure to the geometry, initialized to a preset value.
bool deleteVertex(QgsVertexId position) override
Deletes a vertex within the geometry.
void clearCache() const override
Clears any cached parameters associated with the geometry, e.g., bounding boxes.
double segmentLength(QgsVertexId startVertex) const override
Returns the length of the segment of the geometry which begins at startVertex.
SegmentationToleranceType
Segmentation tolerance as maximum angle or maximum difference between approximation and circle...
void clear() override
Clears the geometry, ie reset it to a null geometry.
static endian_t endian()
Returns whether this machine uses big or little endian.
QgsCompoundCurve * createEmptyWithSameType() const override
Creates a new geometry with the same class and same WKB type as the original and transfers ownership...
static bool hasZ(Type type)
Tests whether a WKB type contains the z-dimension.
QgsCompoundCurve & operator=(const QgsCompoundCurve &curve)
static QStringList wktGetChildBlocks(const QString &wkt, const QString &defaultType=QString())
Parses a WKT string and returns of list of blocks contained in the WKT.
static Type dropM(Type type)
Drops the m dimension (if present) for a WKB type and returns the new type.
void addCurve(QgsCurve *c)
Adds a curve to the geometry (takes ownership)
QgsPoint vertexAt(QgsVertexId) const override
Returns the point corresponding to a specified vertex id.
QgsWkbTypes::Type mWkbType
bool pointAt(int node, QgsPoint &point, QgsVertexId::VertexType &type) const override
Returns the point and vertex id of a point within the curve.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
virtual QgsPoint endPoint() const =0
Returns the end point of the curve.
QString wktTypeStr() const
Returns the WKT type string of the geometry.
Type
The WKB type describes the number of dimensions a geometry has.
static Type addM(Type type)
Adds the m dimension to a WKB type and returns the new type.
double length() const override
Returns the length of the geometry.
void addVertex(const QgsPoint &pt)
Adds a new vertex to the end of the line string.
QString asWkt(int precision=17) const override
Returns a WKT representation of the geometry.
Utility class for identifying a unique vertex within a geometry.
bool removeDuplicateNodes(double epsilon=4 *std::numeric_limits< double >::epsilon(), bool useZValues=false) override
Removes duplicate nodes from the geometry, wherever removing the nodes does not result in a degenerat...
QString geometryType() const override
Returns a unique string representing the geometry type.
double yAt(int index) const override
Returns the y-coordinate of the specified node in the line string.
bool hasCurvedSegments() const override
Returns true if the geometry contains curved segments.
void setZMTypeFromSubGeometry(const QgsAbstractGeometry *subggeom, QgsWkbTypes::Type baseGeomType)
Updates the geometry type based on whether sub geometries contain z or m values.
static Type addZ(Type type)
Adds the z dimension to a WKB type and returns the new type.
T qgsgeometry_cast(const QgsAbstractGeometry *geom)
Abstract base class for curved geometry type.
bool moveVertex(QgsVertexId position, const QgsPoint &newPos) override
Moves a vertex within the geometry.
QgsWkbTypes::Type wkbType() const
Returns the WKB type of the geometry.
Point geometry type, with support for z-dimension and m-values.
void draw(QPainter &p) const override
Draws the geometry using the specified QPainter.
AxisOrder
Axis order for GML generation.
virtual bool isClosed() const
Returns true if the curve is closed.
void removeCurve(int i)
Removes a curve from the geometry.
int nCurves() const
Returns the number of curves in the geometry.
bool fromWkt(const QString &wkt) override
Sets the geometry from a WKT string.
bool isEmpty() const override
Returns true if the geometry is empty.
QVector< QgsPoint > QgsPointSequence
void combineExtentWith(const QgsRectangle &rect)
Expands the rectangle so that it covers both the original rectangle and the given rectangle...
static Type dropZ(Type type)
Drops the z dimension (if present) for a WKB type and returns the new type.
void drawAsPolygon(QPainter &p) const override
Draws the curve as a polygon on the specified QPainter.
void addVertex(const QgsPoint &pt)
Adds a vertex to the end of the geometry.
bool equals(const QgsCurve &other) const override
Checks whether this curve exactly equals another curve.
QgsCurve * clone() const override=0
Clones the geometry by performing a deep copy.
QgsCompoundCurve * reversed() const override
Returns a reversed copy of the curve, where the direction of the curve has been flipped.
virtual bool addZValue(double zValue=0)=0
Adds a z-dimension to the geometry, initialized to a preset value.
Line string geometry type, with support for z-dimension and m-values.
QgsRectangle calculateBoundingBox() const override
Default calculator for the minimal bounding box for the geometry.
const QgsCurve * curveAt(int i) const
Returns the curve at the specified index.
void points(QgsPointSequence &pts) const override
Returns a list of points within the curve.
QByteArray asWkb() const override
Returns a WKB representation of the geometry.
QDomElement asGml3(QDomDocument &doc, int precision=17, const QString &ns="gml", QgsAbstractGeometry::AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY) const override
Returns a GML3 representation of the geometry.
bool removeDuplicateNodes(double epsilon=4 *std::numeric_limits< double >::epsilon(), bool useZValues=false) override
Removes duplicate nodes from the geometry, wherever removing the nodes does not result in a degenerat...
static bool hasM(Type type)
Tests whether a WKB type contains m values.
Compound curve geometry type.
Circular string geometry type.
void filterVertices(const std::function< bool(const QgsPoint &) > &filter) override
Filters the vertices from the geometry in place, removing any which do not return true for the filter...
void close()
Appends first point if not already closed.
virtual bool dropMValue()=0
Drops any measure values which exist in the geometry.
bool dropZValue() override
Drops any z-dimensions which exist in the geometry.
~QgsCompoundCurve() override
QgsCompoundCurve * snappedToGrid(double hSpacing, double vSpacing, double dSpacing=0, double mSpacing=0) const override
Makes a new geometry with all the points or vertices snapped to the closest point of the grid...
bool dropMValue() override
Drops any measure values which exist in the geometry.
static Type flatType(Type type)
Returns the flat type for a WKB type.
QgsWkbTypes::Type readHeader() const
readHeader
int numPoints() const override
Returns the number of points in the curve.
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
double ANALYSIS_EXPORT leftOf(const QgsPoint &thepoint, const QgsPoint *p1, const QgsPoint *p2)
Returns whether 'thepoint' is left or right of the line from 'p1' to 'p2'. Negativ values mean left a...
QDomElement asGml2(QDomDocument &doc, int precision=17, const QString &ns="gml", QgsAbstractGeometry::AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY) const override
Returns a GML2 representation of the geometry.
bool insertVertex(QgsVertexId position, const QgsPoint &vertex) override
Inserts a vertex into the geometry.
virtual bool dropZValue()=0
Drops any z-dimensions which exist in the geometry.
static double closestSegmentFromComponents(T &container, ComponentType ctype, const QgsPoint &pt, QgsPoint &segmentPt, QgsVertexId &vertexAfter, int *leftOf, double epsilon)
void transform(const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection d=QgsCoordinateTransform::ForwardTransform, bool transformZ=false) override SIP_THROW(QgsCsException)
Transforms the geometry using a coordinate transform.
bool fromWkb(QgsConstWkbPtr &wkb) override
Sets the geometry from a WKB string.
QgsPoint endPoint() const override
Returns the end point of the curve.
virtual bool fromWkb(QgsConstWkbPtr &wkb)=0
Sets the geometry from a WKB string.