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" );
79 for (
const QgsCurve *c : curve.mCurves )
81 mCurves.append( static_cast<QgsCurve *>( c->
clone() ) );
91 for (
const QgsCurve *c : curve.mCurves )
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 );
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 );
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 (
const QgsCurve *curve : mCurves )
780 curve->sumUpArea( sum );
795 for (
const QgsCurve *curve : mCurves )
797 if ( curve->hasCurvedSegments() )
807 QVector< QPair<int, QgsVertexId> > curveIds = curveVertexId( vertex );
808 if ( curveIds.size() == 1 )
810 QgsCurve *curve = mCurves[curveIds.at( 0 ).first];
811 return curve->
vertexAngle( curveIds.at( 0 ).second );
813 else if ( curveIds.size() > 1 )
815 QgsCurve *curve1 = mCurves[curveIds.at( 0 ).first];
816 QgsCurve *curve2 = mCurves[curveIds.at( 1 ).first];
817 double angle1 = curve1->
vertexAngle( curveIds.at( 0 ).second );
818 double angle2 = curve2->
vertexAngle( curveIds.at( 1 ).second );
829 QVector< QPair<int, QgsVertexId> > curveIds = curveVertexId( startVertex );
831 for (
auto it = curveIds.constBegin(); it != curveIds.constEnd(); ++it )
833 length += mCurves.at( it->first )->segmentLength( it->second );
841 for (
int i = mCurves.count() - 1; i >= 0; --i )
843 QgsCurve *reversedCurve = mCurves.at( i )->reversed();
856 for (
QgsCurve *curve : qgis::as_const( mCurves ) )
858 curve->addZValue( zValue );
871 for (
QgsCurve *curve : qgis::as_const( mCurves ) )
873 curve->addMValue( mValue );
885 for (
QgsCurve *curve : qgis::as_const( mCurves ) )
899 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.
QDomElement asGml2(QDomDocument &doc, int precision=17, const QString &ns="gml") const override
Returns a GML2 representation of the geometry.
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)
Angle between two linear segments.
void sumUpArea(double &sum) const override
Sums up the area of the curve by iterating over the vertices (shoelace formula).
bool removeDuplicateNodes(double epsilon=4 *DBL_EPSILON, bool useZValues=false) override
Removes duplicate nodes from the geometry, wherever removing the nodes does not result in a degenerat...
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.
bool removeDuplicateNodes(double epsilon=4 *DBL_EPSILON, bool useZValues=false) override
Removes duplicate nodes from the geometry, wherever removing the nodes does not result in a degenerat...
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)
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Compare two doubles (but allow some difference)
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.
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.
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.
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)
Expand the rectangle so that 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.
QDomElement asGml3(QDomDocument &doc, int precision=17, const QString &ns="gml") const override
Returns a GML3 representation 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.
static bool hasM(Type type)
Tests whether a WKB type contains m values.
Compound curve geometry type.
Circular string geometry type.
double closestSegment(const QgsPoint &pt, QgsPoint &segmentPt, QgsVertexId &vertexAfter, int *leftOf=nullptr, double epsilon=4 *DBL_EPSILON) const override
Searches for the closest segment of the geometry to a given point.
void transform(const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection d=QgsCoordinateTransform::ForwardTransform, bool transformZ=false) override
Transforms the geometry using a coordinate transform.
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...
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)
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.