31 #include <QDomDocument> 47 if ( points.isEmpty() )
54 mX.resize( points.count() );
55 mY.resize( points.count() );
56 double *x = mX.data();
57 double *y = mY.data();
62 mZ.resize( points.count() );
67 mM.resize( points.count() );
85 int pointCount = std::min( x.size(), y.size() );
86 if ( x.size() == pointCount )
92 mX = x.mid( 0, pointCount );
94 if ( y.size() == pointCount )
100 mY = y.mid( 0, pointCount );
102 if ( !z.isEmpty() && z.count() >= pointCount )
105 if ( z.size() == pointCount )
111 mZ = z.mid( 0, pointCount );
114 if ( !m.isEmpty() && m.count() >= pointCount )
117 if ( m.size() == pointCount )
123 mM = m.mid( 0, pointCount );
156 mX.reserve( points.size() );
157 mY.reserve( points.size() );
171 mX[1] = segment.
endX();
173 mY[1] = segment.
endY();
185 if ( mX.count() != otherLine->mX.count() )
188 for (
int i = 0; i < mX.count(); ++i )
229 bool res =
snapToGridPrivate( hSpacing, vSpacing, dSpacing, mSpacing, mX, mY, mZ, mM,
230 result->mX, result->mY, result->mZ, result->mM );
232 return result.release();
239 if ( mX.count() <= 2 )
242 double prevX = mX.at( 0 );
243 double prevY = mY.at( 0 );
245 bool useZ = hasZ && useZValues;
246 double prevZ = useZ ? mZ.at( 0 ) : 0;
248 int remaining = mX.count();
249 while ( i < remaining )
251 double currentX = mX.at( i );
252 double currentY = mY.at( i );
253 double currentZ = useZ ? mZ.at( i ) : 0;
279 const int nb = mX.size();
282 const double *x = mX.constData();
283 const double *y = mY.constData();
284 QPointF *dest = points.data();
285 for (
int i = 0; i < nb; ++i )
287 *dest++ = QPointF( *x++, *y++ );
305 importVerticesFromWkb( wkbPtr );
311 double xmin = std::numeric_limits<double>::max();
312 double ymin = std::numeric_limits<double>::max();
313 double xmax = -std::numeric_limits<double>::max();
314 double ymax = -std::numeric_limits<double>::max();
316 for (
double x : mX )
323 for (
double y : mY )
355 int binarySize =
sizeof( char ) +
sizeof( quint32 ) +
sizeof( quint32 );
359 wkbArray.resize( binarySize );
362 wkb << static_cast<quint32>(
wkbType() );
389 QDomElement elemLineString = doc.createElementNS( ns, QStringLiteral(
"LineString" ) );
392 return elemLineString;
396 return elemLineString;
404 QDomElement elemLineString = doc.createElementNS( ns, QStringLiteral(
"LineString" ) );
407 return elemLineString;
410 return elemLineString;
430 int size = mX.size();
432 for (
int i = 1; i < size; ++i )
434 dx = mX.at( i ) - mX.at( i - 1 );
435 dy = mY.at( i ) - mY.at( i - 1 );
436 length += std::sqrt( dx * dx + dy * dy );
467 Q_UNUSED( tolerance );
468 Q_UNUSED( toleranceType );
484 if ( i < 0 || i >= mX.size() )
489 double x = mX.at( i );
490 double y = mY.at( i );
491 double z = std::numeric_limits<double>::quiet_NaN();
492 double m = std::numeric_limits<double>::quiet_NaN();
510 else if ( hasZ && hasM )
533 if ( index >= 0 && index < mX.size() )
534 return mX.at( index );
541 if ( index >= 0 && index < mY.size() )
542 return mY.at( index );
549 if ( index >= 0 && index < mX.size() )
556 if ( index >= 0 && index < mY.size() )
571 for (
int i = 0; i < nPoints; ++i )
573 pts.push_back(
pointN( i ) );
581 if ( points.isEmpty() )
588 const QgsPoint &firstPt = points.at( 0 );
589 bool hasZ = firstPt.
is3D();
594 mX.resize( points.size() );
595 mY.resize( points.size() );
598 mZ.resize( points.size() );
606 mM.resize( points.size() );
613 for (
int i = 0; i < points.size(); ++i )
615 mX[i] = points.at( i ).x();
616 mY[i] = points.at( i ).y();
619 double z = points.at( i ).z();
620 mZ[i] = std::isnan( z ) ? 0 : z;
624 double m = points.at( i ).m();
625 mM[i] = std::isnan( m ) ? 0 : m;
678 mZ.insert( mZ.count(), mX.size() - mZ.size(), std::numeric_limits<double>::quiet_NaN() );
691 mM.insert( mM.count(), mX.size() - mM.size(), std::numeric_limits<double>::quiet_NaN() );
701 std::reverse( copy->mX.begin(), copy->mX.end() );
702 std::reverse( copy->mY.begin(), copy->mY.end() );
705 std::reverse( copy->mZ.begin(), copy->mZ.end() );
709 std::reverse( copy->mM.begin(), copy->mM.end() );
733 if ( path.isEmpty() || path.currentPosition() != QPointF( mX.at( 0 ), mY.at( 0 ) ) )
735 path.moveTo( mX.at( 0 ), mY.at( 0 ) );
738 for (
int i = 1; i < nPoints; ++i )
740 path.lineTo( mX.at( i ), mY.at( i ) );
753 return compoundCurve;
758 if ( mX.size() < 2 || mY.size() < 2 )
762 if ( startDistance > 0 )
764 double currentLen = std::sqrt( std::pow( mX.at( 0 ) - mX.at( 1 ), 2 ) +
765 std::pow( mY.at( 0 ) - mY.at( 1 ), 2 ) );
766 double newLen = currentLen + startDistance;
767 mX[ 0 ] = mX.at( 1 ) + ( mX.at( 0 ) - mX.at( 1 ) ) / currentLen * newLen;
768 mY[ 0 ] = mY.at( 1 ) + ( mY.at( 0 ) - mY.at( 1 ) ) / currentLen * newLen;
771 if ( endDistance > 0 )
773 int last = mX.size() - 1;
774 double currentLen = std::sqrt( std::pow( mX.at( last ) - mX.at( last - 1 ), 2 ) +
775 std::pow( mY.at( last ) - mY.at( last - 1 ), 2 ) );
776 double newLen = currentLen + endDistance;
777 mX[ last ] = mX.at( last - 1 ) + ( mX.at( last ) - mX.at( last - 1 ) ) / currentLen * newLen;
778 mY[ last ] = mY.at( last - 1 ) + ( mY.at( last ) - mY.at( last - 1 ) ) / currentLen * newLen;
784 auto result = qgis::make_unique< QgsLineString >();
786 return result.release();
791 return QStringLiteral(
"LineString" );
807 double *zArray =
nullptr;
813 std::unique_ptr< double[] > dummyZ;
814 if ( !hasZ || !transformZ )
816 dummyZ.reset(
new double[nPoints]() );
817 zArray = dummyZ.get();
832 for (
int i = 0; i < nPoints; ++i )
835 t.map( mX.at( i ), mY.at( i ), &x, &y );
840 mZ[i] = mZ.at( i ) * zScale + zTranslate;
844 mM[i] = mM.at( i ) * mScale + mTranslate;
858 if ( position.
vertex < 0 || position.
vertex > mX.size() )
868 mX.insert( position.
vertex, vertex.
x() );
869 mY.insert( position.
vertex, vertex.
y() );
872 mZ.insert( position.
vertex, vertex.
z() );
876 mM.insert( position.
vertex, vertex.
m() );
884 if ( position.
vertex < 0 || position.
vertex >= mX.size() )
888 mX[position.
vertex] = newPos.
x();
889 mY[position.
vertex] = newPos.
y();
892 mZ[position.
vertex] = newPos.
z();
896 mM[position.
vertex] = newPos.
m();
904 if ( position.
vertex >= mX.size() || position.
vertex < 0 )
909 mX.remove( position.
vertex );
910 mY.remove( position.
vertex );
913 mZ.remove( position.
vertex );
917 mM.remove( position.
vertex );
957 double sqrDist = std::numeric_limits<double>::max();
958 double leftOfDist = std::numeric_limits<double>::max();
960 double prevLeftOfX = 0.0;
961 double prevLeftOfY = 0.0;
963 double segmentPtX, segmentPtY;
968 int size = mX.size();
969 if ( size == 0 || size == 1 )
974 for (
int i = 1; i < size; ++i )
976 double prevX = mX.at( i - 1 );
977 double prevY = mY.at( i - 1 );
978 double currentX = mX.at( i );
979 double currentY = mY.at( i );
981 if ( testDist < sqrDist )
984 segmentPt.
setX( segmentPtX );
985 segmentPt.
setY( segmentPtY );
986 vertexAfter.
part = 0;
987 vertexAfter.
ring = 0;
998 if (
qgsDoubleNear( testDist, leftOfDist ) && left != prevLeftOf && prevLeftOf != 0 )
1011 leftOfDist = testDist;
1012 prevLeftOfX = prevX;
1013 prevLeftOfY = prevY;
1015 else if ( testDist < leftOfDist )
1018 leftOfDist = testDist;
1049 if ( numPoints == 1 )
1050 return QgsPoint( mX.at( 0 ), mY.at( 0 ) );
1052 double totalLineLength = 0.0;
1053 double prevX = mX.at( 0 );
1054 double prevY = mY.at( 0 );
1060 double currentX = mX.at( i );
1061 double currentY = mY.at( i );
1062 double segmentLength = std::sqrt( std::pow( currentX - prevX, 2.0 ) +
1063 std::pow( currentY - prevY, 2.0 ) );
1068 sumX += segmentLength * 0.5 * ( currentX + prevX );
1069 sumY += segmentLength * 0.5 * ( currentY + prevY );
1075 return QgsPoint( mX.at( 0 ), mY.at( 0 ) );
1077 return QgsPoint( sumX / totalLineLength, sumY / totalLineLength );
1091 for (
int i = 0; i < maxIndex; ++i )
1093 sum += 0.5 * ( mX.at( i ) * mY.at( i + 1 ) - mY.at( i ) * mX.at( i + 1 ) );
1097 void QgsLineString::importVerticesFromWkb(
const QgsConstWkbPtr &wkb )
1103 mX.resize( nVertices );
1104 mY.resize( nVertices );
1105 hasZ ? mZ.resize( nVertices ) : mZ.clear();
1106 hasM ? mM.resize( nVertices ) : mM.clear();
1107 double *x = mX.data();
1108 double *y = mY.data();
1109 double *m = hasM ? mM.data() :
nullptr;
1110 double *z = hasZ ? mZ.data() :
nullptr;
1111 for (
int i = 0; i < nVertices; ++i )
1144 if ( mX.count() < 2 )
1154 double previousX = mX.at(
numPoints() - 2 );
1155 double previousY = mY.at(
numPoints() - 2 );
1156 double currentX = mX.at( 0 );
1157 double currentY = mY.at( 0 );
1158 double afterX = mX.at( 1 );
1159 double afterY = mY.at( 1 );
1162 else if ( vertex.
vertex == 0 )
1175 double previousX = mX.at( vertex.
vertex - 1 );
1176 double previousY = mY.at( vertex.
vertex - 1 );
1177 double currentX = mX.at( vertex.
vertex );
1178 double currentY = mY.at( vertex.
vertex );
1179 double afterX = mX.at( vertex.
vertex + 1 );
1180 double afterY = mY.at( vertex.
vertex + 1 );
1187 if ( startVertex.
vertex < 0 || startVertex.
vertex >= mX.count() - 1 )
1190 double dx = mX.at( startVertex.
vertex + 1 ) - mX.at( startVertex.
vertex );
1191 double dy = mY.at( startVertex.
vertex + 1 ) - mY.at( startVertex.
vertex );
1192 return std::sqrt( dx * dx + dy * dy );
1217 mZ.reserve( nPoints );
1218 for (
int i = 0; i < nPoints; ++i )
1248 mM.reserve( nPoints );
1249 for (
int i = 0; i < nPoints; ++i )
1280 std::swap( mX, mY );
1294 addZValue( std::numeric_limits<double>::quiet_NaN() );
1308 int size = mX.size();
1310 double *srcX = mX.data();
1311 double *srcY = mY.data();
1312 double *srcM = hasM ? mM.data() :
nullptr;
1313 double *srcZ = hasZ ? mZ.data() :
nullptr;
1315 double *destX = srcX;
1316 double *destY = srcY;
1317 double *destM = srcM;
1318 double *destZ = srcZ;
1320 int filteredPoints = 0;
1321 for (
int i = 0; i < size; ++i )
1325 double z = hasZ ? *srcZ++ : std::numeric_limits<double>::quiet_NaN();
1326 double m = hasM ? *srcM++ : std::numeric_limits<double>::quiet_NaN();
1328 if ( filter(
QgsPoint( x, y, z, m ) ) )
1340 mX.resize( filteredPoints );
1341 mY.resize( filteredPoints );
1343 mZ.resize( filteredPoints );
1345 mM.resize( filteredPoints );
bool isMeasure() const
Returns true if the geometry contains m values.
static QString pointsToJSON(const QgsPointSequence &points, int precision)
Returns a geoJSON coordinates string.
bool dropZValue() override
Drops any z-dimensions which exist in the geometry.
void append(const QgsLineString *line)
Appends the contents of another line string to the end of this line string.
A rectangle specified with double values.
bool isEmpty() const override
Returns true if the geometry is empty.
void setPoints(const QgsPointSequence &points)
Resets the line string to match the specified list of points.
void points(QgsPointSequence &pt) const override
Returns a list of points within the curve.
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 moveVertex(QgsVertexId position, const QgsPoint &newPos) override
Moves a vertex within the geometry.
int dimension() const override
Returns the inherent dimension of the geometry.
static double lineAngle(double x1, double y1, double x2, double y2)
Calculates the direction of line joining two points in radians, clockwise from the north direction...
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 (...
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).
QString geometryType() const override
Returns a unique string representing the geometry type.
bool fromWkb(QgsConstWkbPtr &wkb) override
Sets the geometry from a WKB string.
static QDomElement pointsToGML2(const QgsPointSequence &points, QDomDocument &doc, int precision, const QString &ns, const QgsAbstractGeometry::AxisOrder &axisOrder=QgsAbstractGeometry::AxisOrder::XY)
Returns a gml::coordinates DOM element.
QgsPoint centroid() const override
Returns the centroid 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.
A class to represent a 2D point.
double endY() const
Returns the segment's end y-coordinate.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
void setYAt(int index, double y)
Sets the y-coordinate of the specified node in the line string.
void clearCache() const override
Clears any cached parameters associated with the geometry, e.g., bounding boxes.
SegmentationToleranceType
Segmentation tolerance as maximum angle or maximum difference between approximation and circle...
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.
bool pointAt(int node, QgsPoint &point, QgsVertexId::VertexType &type) const override
Returns the point and vertex id of a point within the curve.
static endian_t endian()
Returns whether this machine uses big or little endian.
void clear() override
Clears the geometry, ie reset it to a null geometry.
QgsPoint endPoint() const override
Returns the end point of the curve.
static bool hasZ(Type type)
Tests whether a WKB type contains the z-dimension.
static Type dropM(Type type)
Drops the m dimension (if present) for a WKB type and returns the new type.
void setXAt(int index, double x)
Sets the x-coordinate of the specified node in the line string.
void addCurve(QgsCurve *c)
Adds a curve to the geometry (takes ownership)
QgsWkbTypes::Type mWkbType
int numPoints() const override
Returns the number of points in the curve.
bool convertTo(QgsWkbTypes::Type type) override
Converts the geometry to a specified type.
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...
QString wktTypeStr() const
Returns the WKT type string of the geometry.
bool deleteVertex(QgsVertexId position) override
Deletes a vertex within the geometry.
static QString pointsToWKT(const QgsPointSequence &points, int precision, bool is3D, bool isMeasure)
Returns a WKT coordinate list.
Type
The WKB type describes the number of dimensions a geometry has.
double startX() const
Returns the segment's start x-coordinate.
bool fromWkt(const QString &wkt) override
Sets the geometry from a WKT string.
static Type addM(Type type)
Adds the m dimension to a WKB type and returns the new type.
void addVertex(const QgsPoint &pt)
Adds a new vertex to the end of the line string.
QPolygonF asQPolygonF() const override
Returns a QPolygonF representing the points.
Utility class for identifying a unique vertex within a geometry.
QgsLineString * reversed() const override
Returns a reversed copy of the curve, where the direction of the curve has been flipped.
bool equals(const QgsCurve &other) const override
Checks whether this curve exactly equals another curve.
double yAt(int index) const override
Returns the y-coordinate of the specified node in the line string.
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...
void setZMTypeFromSubGeometry(const QgsAbstractGeometry *subggeom, QgsWkbTypes::Type baseGeomType)
Updates the geometry type based on whether sub geometries contain z or m values.
static QDomElement pointsToGML3(const QgsPointSequence &points, QDomDocument &doc, int precision, const QString &ns, bool is3D, const QgsAbstractGeometry::AxisOrder &axisOrder=QgsAbstractGeometry::AxisOrder::XY)
Returns a gml::posList DOM element.
static Type addZ(Type type)
Adds the z dimension to a WKB type and returns the new type.
T qgsgeometry_cast(const QgsAbstractGeometry *geom)
void close()
Closes the line string by appending the first point to the end of the line, if it is not already clos...
void transform(const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection d=QgsCoordinateTransform::ForwardTransform, bool transformZ=false) override SIP_THROW(QgsCsException)
Transforms the geometry using a coordinate transform.
Abstract base class for curved geometry type.
void swapXy() override
Swaps the x and y coordinates from the geometry.
void sumUpArea(double &sum) const override
Sums up the area of the curve by iterating over the vertices (shoelace formula).
QgsWkbTypes::Type wkbType() const
Returns the WKB type of the geometry.
Point geometry type, with support for z-dimension and m-values.
QString asWkt(int precision=17) const override
Returns a WKT representation of the geometry.
AxisOrder
Axis order for GML generation.
QgsPoint startPoint() const override
Returns the starting point of the curve.
Represents a single 2D line segment, consisting of a 2D start and end vertex only.
QgsLineString * clone() const override
Clones the geometry by performing a deep copy.
QString asJson(int precision=17) const override
Returns a GeoJSON representation of the geometry.
void setX(double x)
Sets the point's x-coordinate.
virtual bool isClosed() const
Returns true if the curve is closed.
bool snapToGridPrivate(double hSpacing, double vSpacing, double dSpacing, double mSpacing, const QVector< double > &srcX, const QVector< double > &srcY, const QVector< double > &srcZ, const QVector< double > &srcM, QVector< double > &outX, QVector< double > &outY, QVector< double > &outZ, QVector< double > &outM) const
Helper function for QgsCurve subclasses to snap to grids.
double segmentLength(QgsVertexId startVertex) const override
Returns the length of the segment of the geometry which begins at startVertex.
void setY(double y)
Sets the point's y-coordinate.
QVector< QgsPoint > QgsPointSequence
double endX() const
Returns the segment's end x-coordinate.
static Type dropZ(Type type)
Drops the z dimension (if present) for a WKB type and returns the new type.
QgsLineString * 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...
void drawAsPolygon(QPainter &p) const override
Draws the curve as a polygon on the specified QPainter.
static QgsPointSequence pointsFromWKT(const QString &wktCoordinateList, bool is3D, bool isMeasure)
Returns a list of points contained in a WKT string.
double vertexAngle(QgsVertexId vertex) const override
Returns approximate angle at a vertex.
Line string geometry type, with support for z-dimension and m-values.
static int leftOfLine(double x, double y, double x1, double y1, double x2, double y2)
Returns a value < 0 if the point (x, y) is left of the line from (x1, y1) -> ( x2, y2).
QByteArray asWkb() const override
Returns a WKB representation of the geometry.
QgsPoint pointN(int i) const
Returns the specified point from inside the line string.
void addToPainterPath(QPainterPath &path) const override
Adds a curve to a painter path.
bool dropMValue() override
Drops any measure values which exist in the geometry.
static void pointsToWKB(QgsWkbPtr &wkb, const QgsPointSequence &points, bool is3D, bool isMeasure)
Returns a LinearRing { uint32 numPoints; Point points[numPoints]; }.
double xAt(int index) const override
Returns the x-coordinate of the specified node in the line string.
static Type zmType(Type type, bool hasZ, bool hasM)
Returns the modified input geometry type according to hasZ / hasM.
static double sqrDistToLine(double ptX, double ptY, double x1, double y1, double x2, double y2, double &minDistX, double &minDistY, double epsilon)
Returns the squared distance between a point and a line.
virtual bool convertTo(QgsWkbTypes::Type type)
Converts the geometry to a specified type.
static bool hasM(Type type)
Tests whether a WKB type contains m values.
Compound curve geometry type.
QgsRectangle calculateBoundingBox() const override
Default calculator for the minimal bounding box for the geometry.
QgsLineString * createEmptyWithSameType() const override
Creates a new geometry with the same class and same WKB type as the original and transfers ownership...
double length() const override
Returns the length of the geometry.
QgsCompoundCurve * toCurveType() const override
Returns the geometry converted to the more generic curve type QgsCompoundCurve.
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...
double startY() const
Returns the segment's start y-coordinate.
int nCoordinates() const override
Returns the number of nodes contained in the geometry.
static Type flatType(Type type)
Returns the flat type for a WKB type.
QgsWkbTypes::Type readHeader() const
readHeader
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.
bool addZValue(double zValue=0) override
Adds a z-dimension to the geometry, initialized to a preset value.
void draw(QPainter &p) const override
Draws the geometry using the specified QPainter.
bool addMValue(double mValue=0) override
Adds a measure to the geometry, initialized to a preset value.
void extend(double startDistance, double endDistance)
Extends the line geometry by extrapolating out the start or end of the line by a specified distance...