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 mCurves.reserve( curve.mCurves.size() );
82 mCurves.append( c->
clone() );
94 mCurves.append( c->
clone() );
108 qDeleteAll( mCurves );
115 if ( mCurves.empty() )
121 for (
int i = 1; i < mCurves.size(); ++i )
147 for (
int i = 0; i <
nCurves; ++i )
150 wkbPtr -= 1 +
sizeof( int );
163 currentCurve->
fromWkb( wkbPtr );
164 mCurves.append( currentCurve );
179 QString defaultChildWkbType = QStringLiteral(
"LineString%1%2" ).arg(
is3D() ? QStringLiteral(
"Z" ) : QString(),
isMeasure() ? QStringLiteral(
"M" ) : QString() );
182 for (
const QString &childWkt : blocks )
195 if ( !mCurves.back()->fromWkt( childWkt ) )
206 for (
const QgsCurve *curve : qgis::as_const( mCurves ) )
208 hasZ = hasZ || curve->is3D();
209 hasM = hasM || curve->isMeasure();
223 int binarySize =
sizeof( char ) +
sizeof( quint32 ) +
sizeof( quint32 );
224 QVector<QByteArray> wkbForCurves;
225 wkbForCurves.reserve( mCurves.size() );
226 for (
const QgsCurve *curve : mCurves )
228 QByteArray wkbForCurve = curve->asWkb();
229 binarySize += wkbForCurve.length();
230 wkbForCurves << wkbForCurve;
234 wkbArray.resize( binarySize );
237 wkb << static_cast<quint32>(
wkbType() );
238 wkb << static_cast<quint32>( mCurves.size() );
239 for (
const QByteArray &wkbForCurve : qgis::as_const( wkbForCurves ) )
249 for (
const QgsCurve *curve : mCurves )
251 QString childWkt = curve->asWkt( precision );
252 if ( qgsgeometry_cast<const QgsLineString *>( curve ) )
255 childWkt = childWkt.mid( childWkt.indexOf(
'(' ) );
257 wkt += childWkt +
',';
259 if ( wkt.endsWith(
',' ) )
270 std::unique_ptr< QgsLineString > line(
curveToLine() );
271 QDomElement gml = line->asGml2( doc, precision, ns, axisOrder );
277 QDomElement compoundCurveElem = doc.createElementNS( ns, QStringLiteral(
"CompositeCurve" ) );
280 return compoundCurveElem;
282 for (
const QgsCurve *curve : mCurves )
284 QDomElement curveMemberElem = doc.createElementNS( ns, QStringLiteral(
"curveMember" ) );
285 QDomElement curveElem = curve->asGml3( doc, precision, ns, axisOrder );
286 curveMemberElem.appendChild( curveElem );
287 compoundCurveElem.appendChild( curveMemberElem );
290 return compoundCurveElem;
296 std::unique_ptr< QgsLineString > line(
curveToLine() );
297 QString json = line->asJson( precision );
304 for (
const QgsCurve *curve : mCurves )
306 length += curve->length();
313 if ( mCurves.empty() )
317 return mCurves.at( 0 )->startPoint();
322 if ( mCurves.empty() )
326 return mCurves.at( mCurves.size() - 1 )->
endPoint();
332 if ( mCurves.empty() )
337 mCurves[0]->points( pts );
338 for (
int i = 1; i < mCurves.size(); ++i )
341 mCurves[i]->points( pList );
356 for (
int i = 0; i <
nCurves; ++i )
358 nPoints += mCurves.at( i )->numPoints() - 1;
366 if ( mCurves.isEmpty() )
371 if ( !curve->isEmpty() )
380 std::unique_ptr< QgsLineString > currentLine;
381 for (
const QgsCurve *curve : mCurves )
383 currentLine.reset( curve->curveToLine( tolerance, toleranceType ) );
384 line->
append( currentLine.get() );
395 std::unique_ptr<QgsCurve> gridified( static_cast< QgsCurve * >( curve->snappedToGrid( hSpacing, vSpacing, dSpacing, mSpacing ) ) );
398 result->mCurves.append( gridified.release() );
402 if ( result->mCurves.empty() )
405 return result.release();
411 const QVector< QgsCurve * > curves = mCurves;
417 if ( curve->numPoints() == 0 ||
qgsDoubleNear( curve->length(), 0.0, epsilon ) )
420 delete mCurves.takeAt( i );
428 curve->moveVertex(
QgsVertexId( -1, -1, 0 ), lastEnd );
439 if ( i < 0 || i >= mCurves.size() )
443 return mCurves.at( i );
450 if ( mCurves.empty() )
479 if ( i < 0 || i >= mCurves.size() )
484 delete mCurves.takeAt( i );
497 if ( !mCurves.isEmpty() )
499 lastCurve = mCurves.at( mCurves.size() - 1 );
506 mCurves.append( line );
523 for (
const QgsCurve *curve : mCurves )
531 for (
QgsCurve *curve : qgis::as_const( mCurves ) )
533 curve->transform( ct, d, transformZ );
540 for (
QgsCurve *curve : qgis::as_const( mCurves ) )
542 curve->transform( t, zTranslate, zScale, mTranslate, mScale );
550 for (
const QgsCurve *curve : mCurves )
552 curve->addToPainterPath( pp );
560 for (
const QgsCurve *curve : mCurves )
562 curve->addToPainterPath( pp );
569 QVector< QPair<int, QgsVertexId> > curveIds = curveVertexId( position );
570 if ( curveIds.empty() )
574 int curveId = curveIds.at( 0 ).first;
575 if ( curveId >= mCurves.size() )
580 bool success = mCurves.at( curveId )->insertVertex( curveIds.at( 0 ).second, vertex );
590 QVector< QPair<int, QgsVertexId> > curveIds = curveVertexId( position );
591 QVector< QPair<int, QgsVertexId> >::const_iterator idIt = curveIds.constBegin();
592 for ( ; idIt != curveIds.constEnd(); ++idIt )
594 mCurves.at( idIt->first )->moveVertex( idIt->second, newPos );
597 bool success = !curveIds.isEmpty();
607 QVector< QPair<int, QgsVertexId> > curveIds = curveVertexId( position );
608 if ( curveIds.size() == 1 )
610 if ( !mCurves.at( curveIds.at( 0 ).first )->
deleteVertex( curveIds.at( 0 ).second ) )
615 if ( mCurves.at( curveIds.at( 0 ).first )->
numPoints() == 0 )
620 else if ( curveIds.size() == 2 )
622 Q_ASSERT( curveIds.at( 1 ).first == curveIds.at( 0 ).first + 1 );
623 Q_ASSERT( curveIds.at( 0 ).second.vertex == mCurves.at( curveIds.at( 0 ).first )->
numPoints() - 1 );
624 Q_ASSERT( curveIds.at( 1 ).second.vertex == 0 );
629 mCurves.at( curveIds.at( 1 ).first )->
numPoints() > 3 )
633 mCurves.at( curveIds.at( 1 ).first ) ->
pointAt( 2, intermediatePoint, type );
634 mCurves.at( curveIds.at( 0 ).first )->
moveVertex(
635 QgsVertexId( 0, 0, mCurves.at( curveIds.at( 0 ).first )->
numPoints() - 1 ), intermediatePoint );
637 else if ( !mCurves.at( curveIds.at( 0 ).first )->
deleteVertex( curveIds.at( 0 ).second ) )
643 mCurves.at( curveIds.at( 0 ).first )->
numPoints() > 0 &&
646 QgsPoint intermediatePoint = mCurves.at( curveIds.at( 0 ).first ) ->
endPoint();
649 else if ( !mCurves.at( curveIds.at( 1 ).first )->
deleteVertex( curveIds.at( 1 ).second ) )
654 if ( mCurves.at( curveIds.at( 0 ).first )->
numPoints() == 0 &&
655 mCurves.at( curveIds.at( 1 ).first )->
numPoints() != 0 )
660 else if ( mCurves.at( curveIds.at( 0 ).first )->
numPoints() != 0 &&
661 mCurves.at( curveIds.at( 1 ).first )->
numPoints() == 0 )
663 mCurves.at( curveIds.at( 0 ).first )->
moveVertex(
667 else if ( mCurves.at( curveIds.at( 0 ).first )->
numPoints() == 0 &&
668 mCurves.at( curveIds.at( 1 ).first )->
numPoints() == 0 )
673 line->insertVertex(
QgsVertexId( 0, 0, 0 ), startPoint );
674 line->insertVertex(
QgsVertexId( 0, 0, 1 ), endPoint );
675 mCurves.insert( curveIds.at( 0 ).first, line );
679 QgsPoint endPointOfFirst = mCurves.at( curveIds.at( 0 ).first ) ->
endPoint();
681 if ( endPointOfFirst != startPointOfSecond )
686 mCurves.insert( curveIds.at( 1 ).first, line );
691 bool success = !curveIds.isEmpty();
699 QVector< QPair<int, QgsVertexId> > QgsCompoundCurve::curveVertexId(
QgsVertexId id )
const 701 QVector< QPair<int, QgsVertexId> > curveIds;
703 int currentVertexIndex = 0;
704 for (
int i = 0; i < mCurves.size(); ++i )
706 int increment = mCurves.at( i )->numPoints() - 1;
707 if (
id.vertex >= currentVertexIndex &&
id.vertex <= currentVertexIndex + increment )
709 int curveVertexId =
id.vertex - currentVertexIndex;
713 vid.
vertex = curveVertexId;
714 curveIds.append( qMakePair( i, vid ) );
715 if ( curveVertexId == increment && i < ( mCurves.size() - 1 ) )
718 curveIds.append( qMakePair( i + 1, vid ) );
722 currentVertexIndex += increment;
735 int currentVertexId = 0;
736 for (
int j = 0; j < mCurves.size(); ++j )
738 int nCurvePoints = mCurves.at( j )->numPoints();
739 if ( ( node - currentVertexId ) < nCurvePoints )
741 return ( mCurves.at( j )->pointAt( node - currentVertexId, point, type ) );
743 currentVertexId += ( nCurvePoints - 1 );
750 int currentVertexId = 0;
751 for (
int j = 0; j < mCurves.size(); ++j )
753 int nCurvePoints = mCurves.at( j )->numPoints();
754 if ( ( index - currentVertexId ) < nCurvePoints )
756 return mCurves.at( j )->xAt( index - currentVertexId );
758 currentVertexId += ( nCurvePoints - 1 );
765 int currentVertexId = 0;
766 for (
int j = 0; j < mCurves.size(); ++j )
768 int nCurvePoints = mCurves.at( j )->numPoints();
769 if ( ( index - currentVertexId ) < nCurvePoints )
771 return mCurves.at( j )->yAt( index - currentVertexId );
773 currentVertexId += ( nCurvePoints - 1 );
780 for (
QgsCurve *curve : qgis::as_const( mCurves ) )
782 curve->filterVertices( filter );
789 for (
QgsCurve *curve : qgis::as_const( mCurves ) )
798 for (
const QgsCurve *curve : mCurves )
800 curve->sumUpArea( sum );
815 for (
const QgsCurve *curve : mCurves )
817 if ( curve->hasCurvedSegments() )
827 QVector< QPair<int, QgsVertexId> > curveIds = curveVertexId( vertex );
828 if ( curveIds.size() == 1 )
830 QgsCurve *curve = mCurves[curveIds.at( 0 ).first];
831 return curve->
vertexAngle( curveIds.at( 0 ).second );
833 else if ( curveIds.size() > 1 )
835 QgsCurve *curve1 = mCurves[curveIds.at( 0 ).first];
836 QgsCurve *curve2 = mCurves[curveIds.at( 1 ).first];
837 double angle1 = curve1->
vertexAngle( curveIds.at( 0 ).second );
838 double angle2 = curve2->
vertexAngle( curveIds.at( 1 ).second );
849 QVector< QPair<int, QgsVertexId> > curveIds = curveVertexId( startVertex );
851 for (
auto it = curveIds.constBegin(); it != curveIds.constEnd(); ++it )
853 length += mCurves.at( it->first )->segmentLength( it->second );
861 for (
int i = mCurves.count() - 1; i >= 0; --i )
863 QgsCurve *reversedCurve = mCurves.at( i )->reversed();
874 double distanceTraversed = 0;
875 for (
const QgsCurve *curve : mCurves )
877 const double thisCurveLength = curve->
length();
878 if ( distanceTraversed + thisCurveLength > distance ||
qgsDoubleNear( distanceTraversed + thisCurveLength, distance ) )
881 const double distanceToPoint = std::min( distance - distanceTraversed, thisCurveLength );
884 return curve->interpolatePoint( distanceToPoint );
887 distanceTraversed += thisCurveLength;
895 if ( startDistance < 0 && endDistance < 0 )
898 endDistance = std::max( startDistance, endDistance );
899 std::unique_ptr< QgsCompoundCurve > substring = qgis::make_unique< QgsCompoundCurve >();
901 double distanceTraversed = 0;
902 for (
const QgsCurve *curve : mCurves )
904 const double thisCurveLength = curve->length();
905 if ( distanceTraversed + thisCurveLength < startDistance )
911 std::unique_ptr< QgsCurve > part( curve->curveSubstring( startDistance - distanceTraversed, endDistance - distanceTraversed ) );
913 substring->addCurve( part.release() );
916 distanceTraversed += thisCurveLength;
917 if ( distanceTraversed > endDistance )
921 return substring.release();
931 for (
QgsCurve *curve : qgis::as_const( mCurves ) )
933 curve->addZValue( zValue );
946 for (
QgsCurve *curve : qgis::as_const( mCurves ) )
948 curve->addMValue( mValue );
960 for (
QgsCurve *curve : qgis::as_const( mCurves ) )
974 for (
QgsCurve *curve : qgis::as_const( mCurves ) )
984 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 transformVertices(const std::function< QgsPoint(const QgsPoint &) > &transform) override
Transforms the vertices from the geometry in place, applying the transform function to every vertex...
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.
virtual double length() const
Returns the length 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.
QgsGeometryConstPartIterator parts() const
Returns Java-style iterator for traversal of parts 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.
QgsPoint * interpolatePoint(double distance) const override
Returns an interpolated point on the curve at the specified distance.
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.
QgsCompoundCurve * curveSubstring(double startDistance, double endDistance) const override
Returns a new curve representing a substring of this curve.
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.