QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgslinestring.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgslinestring.cpp
3  -------------------
4  begin : September 2014
5  copyright : (C) 2014 by Marco Hugentobler
6  email : marco at sourcepole dot ch
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include "qgslinestring.h"
19 #include "qgsapplication.h"
20 #include "qgscompoundcurve.h"
21 #include "qgscoordinatetransform.h"
22 #include "qgsgeometryutils.h"
23 #include "qgsmaptopixel.h"
24 #include "qgswkbptr.h"
25 #include "qgslinesegment.h"
26 #include "qgsgeometrytransformer.h"
27 #include "qgsfeedback.h"
28 
29 #include <nlohmann/json.hpp>
30 #include <cmath>
31 #include <memory>
32 #include <QPainter>
33 #include <limits>
34 #include <QDomDocument>
35 #include <QJsonObject>
36 
37 #include "qgsbox3d.h"
38 
39 /***************************************************************************
40  * This class is considered CRITICAL and any change MUST be accompanied with
41  * full unit tests.
42  * See details in QEP #17
43  ****************************************************************************/
44 
46 {
48 }
49 
50 QgsLineString::QgsLineString( const QVector<QgsPoint> &points )
51 {
52  if ( points.isEmpty() )
53  {
55  return;
56  }
57  QgsWkbTypes::Type ptType = points.at( 0 ).wkbType();
59  mX.resize( points.count() );
60  mY.resize( points.count() );
61  double *x = mX.data();
62  double *y = mY.data();
63  double *z = nullptr;
64  double *m = nullptr;
65  if ( QgsWkbTypes::hasZ( mWkbType ) )
66  {
67  mZ.resize( points.count() );
68  z = mZ.data();
69  }
70  if ( QgsWkbTypes::hasM( mWkbType ) )
71  {
72  mM.resize( points.count() );
73  m = mM.data();
74  }
75 
76  for ( const QgsPoint &pt : points )
77  {
78  *x++ = pt.x();
79  *y++ = pt.y();
80  if ( z )
81  *z++ = pt.z();
82  if ( m )
83  *m++ = pt.m();
84  }
85 }
86 
87 QgsLineString::QgsLineString( const QVector<double> &x, const QVector<double> &y, const QVector<double> &z, const QVector<double> &m, bool is25DType )
88 {
90  int pointCount = std::min( x.size(), y.size() );
91  if ( x.size() == pointCount )
92  {
93  mX = x;
94  }
95  else
96  {
97  mX = x.mid( 0, pointCount );
98  }
99  if ( y.size() == pointCount )
100  {
101  mY = y;
102  }
103  else
104  {
105  mY = y.mid( 0, pointCount );
106  }
107  if ( !z.isEmpty() && z.count() >= pointCount )
108  {
110  if ( z.size() == pointCount )
111  {
112  mZ = z;
113  }
114  else
115  {
116  mZ = z.mid( 0, pointCount );
117  }
118  }
119  if ( !m.isEmpty() && m.count() >= pointCount )
120  {
122  if ( m.size() == pointCount )
123  {
124  mM = m;
125  }
126  else
127  {
128  mM = m.mid( 0, pointCount );
129  }
130  }
131 }
132 
134 {
136  mX.resize( 2 );
137  mX[ 0 ] = p1.x();
138  mX[ 1 ] = p2.x();
139  mY.resize( 2 );
140  mY[ 0 ] = p1.y();
141  mY[ 1 ] = p2.y();
142  if ( p1.is3D() )
143  {
145  mZ.resize( 2 );
146  mZ[ 0 ] = p1.z();
147  mZ[ 1 ] = p2.z();
148  }
149  if ( p1.isMeasure() )
150  {
152  mM.resize( 2 );
153  mM[ 0 ] = p1.m();
154  mM[ 1 ] = p2.m();
155  }
156 }
157 
158 QgsLineString::QgsLineString( const QVector<QgsPointXY> &points )
159 {
161  mX.reserve( points.size() );
162  mY.reserve( points.size() );
163  for ( const QgsPointXY &p : points )
164  {
165  mX << p.x();
166  mY << p.y();
167  }
168 }
169 
171 {
173  mX.resize( 2 );
174  mY.resize( 2 );
175  mX[0] = segment.startX();
176  mX[1] = segment.endX();
177  mY[0] = segment.startY();
178  mY[1] = segment.endY();
179 }
180 
181 static double cubicInterpolate( double a, double b,
182  double A, double B, double C, double D )
183 {
184  return A * b * b * b + 3 * B * b * b * a + 3 * C * b * a * a + D * a * a * a;
185 }
186 
187 QgsLineString *QgsLineString::fromBezierCurve( const QgsPoint &start, const QgsPoint &controlPoint1, const QgsPoint &controlPoint2, const QgsPoint &end, int segments )
188 {
189  if ( segments == 0 )
190  return new QgsLineString();
191 
192  QVector<double> x;
193  x.resize( segments + 1 );
194  QVector<double> y;
195  y.resize( segments + 1 );
196  QVector<double> z;
197  double *zData = nullptr;
198  if ( start.is3D() && end.is3D() && controlPoint1.is3D() && controlPoint2.is3D() )
199  {
200  z.resize( segments + 1 );
201  zData = z.data();
202  }
203  QVector<double> m;
204  double *mData = nullptr;
205  if ( start.isMeasure() && end.isMeasure() && controlPoint1.isMeasure() && controlPoint2.isMeasure() )
206  {
207  m.resize( segments + 1 );
208  mData = m.data();
209  }
210 
211  double *xData = x.data();
212  double *yData = y.data();
213  const double step = 1.0 / segments;
214  double a = 0;
215  double b = 1.0;
216  for ( int i = 0; i < segments; i++, a += step, b -= step )
217  {
218  if ( i == 0 )
219  {
220  *xData++ = start.x();
221  *yData++ = start.y();
222  if ( zData )
223  *zData++ = start.z();
224  if ( mData )
225  *mData++ = start.m();
226  }
227  else
228  {
229  *xData++ = cubicInterpolate( a, b, start.x(), controlPoint1.x(), controlPoint2.x(), end.x() );
230  *yData++ = cubicInterpolate( a, b, start.y(), controlPoint1.y(), controlPoint2.y(), end.y() );
231  if ( zData )
232  *zData++ = cubicInterpolate( a, b, start.z(), controlPoint1.z(), controlPoint2.z(), end.z() );
233  if ( mData )
234  *mData++ = cubicInterpolate( a, b, start.m(), controlPoint1.m(), controlPoint2.m(), end.m() );
235  }
236  }
237 
238  *xData = end.x();
239  *yData = end.y();
240  if ( zData )
241  *zData = end.z();
242  if ( mData )
243  *mData = end.m();
244 
245  return new QgsLineString( x, y, z, m );
246 }
247 
248 QgsLineString *QgsLineString::fromQPolygonF( const QPolygonF &polygon )
249 {
250  QVector< double > x;
251  QVector< double > y;
252  x.resize( polygon.count() );
253  y.resize( polygon.count() );
254  double *xData = x.data();
255  double *yData = y.data();
256 
257  const QPointF *src = polygon.data();
258  for ( int i = 0 ; i < polygon.size(); ++ i )
259  {
260  *xData++ = src->x();
261  *yData++ = src->y();
262  src++;
263  }
264 
265  return new QgsLineString( x, y );
266 }
267 
268 bool QgsLineString::equals( const QgsCurve &other ) const
269 {
270  const QgsLineString *otherLine = qgsgeometry_cast< const QgsLineString * >( &other );
271  if ( !otherLine )
272  return false;
273 
274  if ( mWkbType != otherLine->mWkbType )
275  return false;
276 
277  if ( mX.count() != otherLine->mX.count() )
278  return false;
279 
280  for ( int i = 0; i < mX.count(); ++i )
281  {
282  if ( !qgsDoubleNear( mX.at( i ), otherLine->mX.at( i ) )
283  || !qgsDoubleNear( mY.at( i ), otherLine->mY.at( i ) ) )
284  return false;
285 
286  if ( is3D() && !qgsDoubleNear( mZ.at( i ), otherLine->mZ.at( i ) ) )
287  return false;
288 
289  if ( isMeasure() && !qgsDoubleNear( mM.at( i ), otherLine->mM.at( i ) ) )
290  return false;
291  }
292 
293  return true;
294 }
295 
297 {
298  return new QgsLineString( *this );
299 }
300 
302 {
303  mX.clear();
304  mY.clear();
305  mZ.clear();
306  mM.clear();
308  clearCache();
309 }
310 
312 {
313  return mX.isEmpty();
314 }
315 
316 int QgsLineString::indexOf( const QgsPoint &point ) const
317 {
318  const int size = mX.size();
319  if ( size == 0 )
320  return -1;
321 
322  const double *x = mX.constData();
323  const double *y = mY.constData();
324  const bool useZ = is3D();
325  const bool useM = isMeasure();
326  const double *z = useZ ? mZ.constData() : nullptr;
327  const double *m = useM ? mM.constData() : nullptr;
328 
329  for ( int i = 0; i < size; ++i )
330  {
331  if ( qgsDoubleNear( *x, point.x() )
332  && qgsDoubleNear( *y, point.y() )
333  && ( !useZ || qgsDoubleNear( *z, point.z() ) )
334  && ( !useM || qgsDoubleNear( *m, point.m() ) ) )
335  return i;
336 
337  x++;
338  y++;
339  if ( useZ )
340  z++;
341  if ( useM )
342  m++;
343  }
344  return -1;
345 }
346 
347 bool QgsLineString::isValid( QString &error, Qgis::GeometryValidityFlags flags ) const
348 {
349  if ( !isEmpty() && ( numPoints() < 2 ) )
350  {
351  error = QObject::tr( "LineString has less than 2 points and is not empty." );
352  return false;
353  }
354  return QgsCurve::isValid( error, flags );
355 }
356 
357 QgsLineString *QgsLineString::snappedToGrid( double hSpacing, double vSpacing, double dSpacing, double mSpacing ) const
358 {
359  // prepare result
360  std::unique_ptr<QgsLineString> result { createEmptyWithSameType() };
361 
362  bool res = snapToGridPrivate( hSpacing, vSpacing, dSpacing, mSpacing, mX, mY, mZ, mM,
363  result->mX, result->mY, result->mZ, result->mM );
364  if ( res )
365  return result.release();
366  else
367  return nullptr;
368 }
369 
370 bool QgsLineString::removeDuplicateNodes( double epsilon, bool useZValues )
371 {
372  if ( mX.count() <= 2 )
373  return false; // don't create degenerate lines
374  bool result = false;
375  double prevX = mX.at( 0 );
376  double prevY = mY.at( 0 );
377  bool hasZ = is3D();
378  bool useZ = hasZ && useZValues;
379  double prevZ = useZ ? mZ.at( 0 ) : 0;
380  int i = 1;
381  int remaining = mX.count();
382  while ( i < remaining )
383  {
384  double currentX = mX.at( i );
385  double currentY = mY.at( i );
386  double currentZ = useZ ? mZ.at( i ) : 0;
387  if ( qgsDoubleNear( currentX, prevX, epsilon ) &&
388  qgsDoubleNear( currentY, prevY, epsilon ) &&
389  ( !useZ || qgsDoubleNear( currentZ, prevZ, epsilon ) ) )
390  {
391  result = true;
392  // remove point
393  mX.removeAt( i );
394  mY.removeAt( i );
395  if ( hasZ )
396  mZ.removeAt( i );
397  remaining--;
398  }
399  else
400  {
401  prevX = currentX;
402  prevY = currentY;
403  prevZ = currentZ;
404  i++;
405  }
406  }
407  return result;
408 }
409 
411 {
412  if ( mX.empty() )
413  return false;
414 
415  return qgsDoubleNear( mX.first(), mX.last() ) &&
416  qgsDoubleNear( mY.first(), mY.last() );
417 }
418 
420 {
421  bool closed = isClosed2D();
422 
423  if ( is3D() && closed )
424  closed &= qgsDoubleNear( mZ.first(), mZ.last() ) || ( std::isnan( mZ.first() ) && std::isnan( mZ.last() ) );
425  return closed;
426 }
427 
429 {
430  if ( mX.empty() )
431  return false;
432 
433  if ( !mBoundingBox.isNull() )
434  {
435  return mBoundingBox.intersects( rectangle );
436  }
437  const int nb = mX.size();
438 
439  // We are a little fancy here!
440  if ( nb > 40 )
441  {
442  // if a large number of vertices, take some sample vertices at 1/5th increments through the linestring
443  // and test whether any are inside the rectangle. Maybe we can shortcut a lot of iterations by doing this!
444  // (why 1/5th? it's picked so that it works nicely for polygon rings which are almost rectangles, so the vertex extremities
445  // will fall on approximately these vertex indices)
446  if ( rectangle.contains( mX.at( 0 ), mY.at( 0 ) ) ||
447  rectangle.contains( mX.at( static_cast< int >( nb * 0.2 ) ), mY.at( static_cast< int >( nb * 0.2 ) ) ) ||
448  rectangle.contains( mX.at( static_cast< int >( nb * 0.4 ) ), mY.at( static_cast< int >( nb * 0.4 ) ) ) ||
449  rectangle.contains( mX.at( static_cast< int >( nb * 0.6 ) ), mY.at( static_cast< int >( nb * 0.6 ) ) ) ||
450  rectangle.contains( mX.at( static_cast< int >( nb * 0.8 ) ), mY.at( static_cast< int >( nb * 0.8 ) ) ) ||
451  rectangle.contains( mX.at( nb - 1 ), mY.at( nb - 1 ) ) )
452  return true;
453  }
454 
455  // Be even MORE fancy! Given that bounding box calculation is non-free, cached, and we don't
456  // already have it, we start performing the bounding box calculation while we are testing whether
457  // each point falls inside the rectangle. That way if we end up testing the majority of the points
458  // anyway, we can update the cached bounding box with the results we've calculated along the way
459  // and save future calls to calculate the bounding box!
460  double xmin = std::numeric_limits<double>::max();
461  double ymin = std::numeric_limits<double>::max();
462  double xmax = -std::numeric_limits<double>::max();
463  double ymax = -std::numeric_limits<double>::max();
464 
465  const double *x = mX.constData();
466  const double *y = mY.constData();
467  bool foundPointInRectangle = false;
468  for ( int i = 0; i < nb; ++i )
469  {
470  const double px = *x++;
471  xmin = std::min( xmin, px );
472  xmax = std::max( xmax, px );
473  const double py = *y++;
474  ymin = std::min( ymin, py );
475  ymax = std::max( ymax, py );
476 
477  if ( !foundPointInRectangle && rectangle.contains( px, py ) )
478  {
479  foundPointInRectangle = true;
480 
481  // now... we have a choice to make. If we've already looped through the majority of the points
482  // in this linestring then let's just continue to iterate through the remainder so that we can
483  // complete the overall bounding box calculation we've already mostly done. If however we're only
484  // just at the start of iterating the vertices, we shortcut out early and leave the bounding box
485  // uncalculated
486  if ( i < nb * 0.5 )
487  return true;
488  }
489  }
490 
491  // at this stage we now know the overall bounding box of the linestring, so let's cache
492  // it so we don't ever have to calculate this again. We've done all the hard work anyway!
493  mBoundingBox = QgsRectangle( xmin, ymin, xmax, ymax, false );
494 
495  if ( foundPointInRectangle )
496  return true;
497 
498  // NOTE: if none of the points in the line actually fell inside the rectangle, it doesn't
499  // exclude that the OVERALL bounding box of the linestring itself intersects the rectangle!!
500  // So we fall back to the parent class method which compares the overall bounding box against
501  // the rectangle... and this will be very cheap now that we've already calculated and cached
502  // the linestring's bounding box!
503  return QgsCurve::boundingBoxIntersects( rectangle );
504 }
505 
506 QVector< QgsVertexId > QgsLineString::collectDuplicateNodes( double epsilon, bool useZValues ) const
507 {
508  QVector< QgsVertexId > res;
509  if ( mX.count() <= 1 )
510  return res;
511 
512  const double *x = mX.constData();
513  const double *y = mY.constData();
514  bool hasZ = is3D();
515  bool useZ = hasZ && useZValues;
516  const double *z = useZ ? mZ.constData() : nullptr;
517 
518  double prevX = *x++;
519  double prevY = *y++;
520  double prevZ = z ? *z++ : 0;
521 
522  QgsVertexId id;
523  for ( int i = 1; i < mX.count(); ++i )
524  {
525  double currentX = *x++;
526  double currentY = *y++;
527  double currentZ = useZ ? *z++ : 0;
528  if ( qgsDoubleNear( currentX, prevX, epsilon ) &&
529  qgsDoubleNear( currentY, prevY, epsilon ) &&
530  ( !useZ || qgsDoubleNear( currentZ, prevZ, epsilon ) ) )
531  {
532  id.vertex = i;
533  res << id;
534  }
535  else
536  {
537  prevX = currentX;
538  prevY = currentY;
539  prevZ = currentZ;
540  }
541  }
542  return res;
543 }
544 
545 QPolygonF QgsLineString::asQPolygonF() const
546 {
547  const int nb = mX.size();
548  QPolygonF points( nb );
549 
550  const double *x = mX.constData();
551  const double *y = mY.constData();
552  QPointF *dest = points.data();
553  for ( int i = 0; i < nb; ++i )
554  {
555  *dest++ = QPointF( *x++, *y++ );
556  }
557  return points;
558 }
559 
561 {
562  if ( !wkbPtr )
563  {
564  return false;
565  }
566 
567  QgsWkbTypes::Type type = wkbPtr.readHeader();
569  {
570  return false;
571  }
572  mWkbType = type;
573  importVerticesFromWkb( wkbPtr );
574  return true;
575 }
576 
577 // duplicated code from calculateBoundingBox3d to avoid useless z computation
579 {
580  if ( mX.empty() )
581  return QgsRectangle();
582 
583  auto result = std::minmax_element( mX.begin(), mX.end() );
584  const double xmin = *result.first;
585  const double xmax = *result.second;
586  result = std::minmax_element( mY.begin(), mY.end() );
587  const double ymin = *result.first;
588  const double ymax = *result.second;
589  return QgsRectangle( xmin, ymin, xmax, ymax, false );
590 }
591 
593 {
594 
595  if ( mX.empty() )
596  {
597  return QgsBox3d();
598  }
599 
600  if ( mBoundingBox.isNull() )
601  {
603  }
604 
605  QgsBox3d out;
606  if ( is3D() )
607  {
608  auto result = std::minmax_element( mZ.begin(), mZ.end() );
609  const double zmin = *result.first;
610  const double zmax = *result.second;
612  }
613  else
614  {
615  out = QgsBox3d( mBoundingBox.xMinimum(), mBoundingBox.yMinimum(), std::numeric_limits< double >::quiet_NaN(), mBoundingBox.xMaximum(), mBoundingBox.yMaximum(), std::numeric_limits< double >::quiet_NaN() );
616  }
617  return out;
618 }
619 
620 void QgsLineString::scroll( int index )
621 {
622  const int size = mX.size();
623  if ( index < 1 || index >= size - 1 )
624  return;
625 
626  const bool useZ = is3D();
627  const bool useM = isMeasure();
628 
629  QVector<double> newX( size );
630  QVector<double> newY( size );
631  QVector<double> newZ( useZ ? size : 0 );
632  QVector<double> newM( useM ? size : 0 );
633  auto it = std::copy( mX.constBegin() + index, mX.constEnd() - 1, newX.begin() );
634  it = std::copy( mX.constBegin(), mX.constBegin() + index, it );
635  *it = *newX.constBegin();
636  mX = std::move( newX );
637 
638  it = std::copy( mY.constBegin() + index, mY.constEnd() - 1, newY.begin() );
639  it = std::copy( mY.constBegin(), mY.constBegin() + index, it );
640  *it = *newY.constBegin();
641  mY = std::move( newY );
642  if ( useZ )
643  {
644  it = std::copy( mZ.constBegin() + index, mZ.constEnd() - 1, newZ.begin() );
645  it = std::copy( mZ.constBegin(), mZ.constBegin() + index, it );
646  *it = *newZ.constBegin();
647  mZ = std::move( newZ );
648  }
649  if ( useM )
650  {
651  it = std::copy( mM.constBegin() + index, mM.constEnd() - 1, newM.begin() );
652  it = std::copy( mM.constBegin(), mM.constBegin() + index, it );
653  *it = *newM.constBegin();
654  mM = std::move( newM );
655  }
656 }
657 
658 /***************************************************************************
659  * This class is considered CRITICAL and any change MUST be accompanied with
660  * full unit tests.
661  * See details in QEP #17
662  ****************************************************************************/
663 bool QgsLineString::fromWkt( const QString &wkt )
664 {
665  clear();
666 
667  QPair<QgsWkbTypes::Type, QString> parts = QgsGeometryUtils::wktReadBlock( wkt );
668 
670  return false;
671  mWkbType = parts.first;
672 
673  QString secondWithoutParentheses = parts.second;
674  secondWithoutParentheses = secondWithoutParentheses.remove( '(' ).remove( ')' ).simplified().remove( ' ' );
675  parts.second = parts.second.remove( '(' ).remove( ')' );
676  if ( ( parts.second.compare( QLatin1String( "EMPTY" ), Qt::CaseInsensitive ) == 0 ) ||
677  secondWithoutParentheses.isEmpty() )
678  return true;
679 
681  // There is a non number in the coordinates sequence
682  // LineString ( A b, 1 2)
683  if ( points.isEmpty() )
684  return false;
685 
686  setPoints( points );
687  return true;
688 }
689 
690 int QgsLineString::wkbSize( QgsAbstractGeometry::WkbFlags ) const
691 {
692  int binarySize = sizeof( char ) + sizeof( quint32 ) + sizeof( quint32 );
693  binarySize += numPoints() * ( 2 + is3D() + isMeasure() ) * sizeof( double );
694  return binarySize;
695 }
696 
697 QByteArray QgsLineString::asWkb( WkbFlags flags ) const
698 {
699  QByteArray wkbArray;
700  wkbArray.resize( QgsLineString::wkbSize( flags ) );
701  QgsWkbPtr wkb( wkbArray );
702  wkb << static_cast<char>( QgsApplication::endian() );
703  wkb << static_cast<quint32>( wkbType() );
704  QgsPointSequence pts;
705  points( pts );
706  QgsGeometryUtils::pointsToWKB( wkb, pts, is3D(), isMeasure() );
707  return wkbArray;
708 }
709 
710 /***************************************************************************
711  * This class is considered CRITICAL and any change MUST be accompanied with
712  * full unit tests.
713  * See details in QEP #17
714  ****************************************************************************/
715 
716 QString QgsLineString::asWkt( int precision ) const
717 {
718  QString wkt = wktTypeStr() + ' ';
719 
720  if ( isEmpty() )
721  wkt += QLatin1String( "EMPTY" );
722  else
723  {
724  QgsPointSequence pts;
725  points( pts );
727  }
728  return wkt;
729 }
730 
731 QDomElement QgsLineString::asGml2( QDomDocument &doc, int precision, const QString &ns, const AxisOrder axisOrder ) const
732 {
733  QgsPointSequence pts;
734  points( pts );
735 
736  QDomElement elemLineString = doc.createElementNS( ns, QStringLiteral( "LineString" ) );
737 
738  if ( isEmpty() )
739  return elemLineString;
740 
741  elemLineString.appendChild( QgsGeometryUtils::pointsToGML2( pts, doc, precision, ns, axisOrder ) );
742 
743  return elemLineString;
744 }
745 
746 QDomElement QgsLineString::asGml3( QDomDocument &doc, int precision, const QString &ns, const QgsAbstractGeometry::AxisOrder axisOrder ) const
747 {
748  QgsPointSequence pts;
749  points( pts );
750 
751  QDomElement elemLineString = doc.createElementNS( ns, QStringLiteral( "LineString" ) );
752 
753  if ( isEmpty() )
754  return elemLineString;
755 
756  elemLineString.appendChild( QgsGeometryUtils::pointsToGML3( pts, doc, precision, ns, is3D(), axisOrder ) );
757  return elemLineString;
758 }
759 
761 {
762  QgsPointSequence pts;
763  points( pts );
764  return
765  {
766  { "type", "LineString" },
767  { "coordinates", QgsGeometryUtils::pointsToJson( pts, precision ) }
768  };
769 }
770 
771 QString QgsLineString::asKml( int precision ) const
772 {
773  QString kml;
774  if ( isRing() )
775  {
776  kml.append( QLatin1String( "<LinearRing>" ) );
777  }
778  else
779  {
780  kml.append( QLatin1String( "<LineString>" ) );
781  }
782  bool z = is3D();
783  kml.append( QLatin1String( "<altitudeMode>" ) );
784  if ( z )
785  {
786  kml.append( QLatin1String( "absolute" ) );
787  }
788  else
789  {
790  kml.append( QLatin1String( "clampToGround" ) );
791  }
792  kml.append( QLatin1String( "</altitudeMode>" ) );
793  kml.append( QLatin1String( "<coordinates>" ) );
794 
795  int nPoints = mX.size();
796  for ( int i = 0; i < nPoints; ++i )
797  {
798  if ( i > 0 )
799  {
800  kml.append( QLatin1String( " " ) );
801  }
802  kml.append( qgsDoubleToString( mX[i], precision ) );
803  kml.append( QLatin1String( "," ) );
804  kml.append( qgsDoubleToString( mY[i], precision ) );
805  if ( z )
806  {
807  kml.append( QLatin1String( "," ) );
808  kml.append( qgsDoubleToString( mZ[i], precision ) );
809  }
810  else
811  {
812  kml.append( QLatin1String( ",0" ) );
813  }
814  }
815  kml.append( QLatin1String( "</coordinates>" ) );
816  if ( isRing() )
817  {
818  kml.append( QLatin1String( "</LinearRing>" ) );
819  }
820  else
821  {
822  kml.append( QLatin1String( "</LineString>" ) );
823  }
824  return kml;
825 }
826 
827 /***************************************************************************
828  * This class is considered CRITICAL and any change MUST be accompanied with
829  * full unit tests.
830  * See details in QEP #17
831  ****************************************************************************/
832 
833 double QgsLineString::length() const
834 {
835  double total = 0;
836  const int size = mX.size();
837  if ( size < 2 )
838  return 0;
839 
840  const double *x = mX.constData();
841  const double *y = mY.constData();
842  double dx, dy;
843 
844  double prevX = *x++;
845  double prevY = *y++;
846 
847  for ( int i = 1; i < size; ++i )
848  {
849  dx = *x - prevX;
850  dy = *y - prevY;
851  total += std::sqrt( dx * dx + dy * dy );
852 
853  prevX = *x++;
854  prevY = *y++;
855  }
856  return total;
857 }
858 
859 std::tuple<std::unique_ptr<QgsCurve>, std::unique_ptr<QgsCurve> > QgsLineString::splitCurveAtVertex( int index ) const
860 {
861  const bool useZ = is3D();
862  const bool useM = isMeasure();
863 
864  const int size = mX.size();
865  if ( size == 0 )
866  return std::make_tuple( std::make_unique< QgsLineString >(), std::make_unique< QgsLineString >() );
867 
868  index = std::clamp( index, 0, size - 1 );
869 
870  const int part1Size = index + 1;
871  QVector< double > x1( part1Size );
872  QVector< double > y1( part1Size );
873  QVector< double > z1( useZ ? part1Size : 0 );
874  QVector< double > m1( useM ? part1Size : 0 );
875 
876  const double *sourceX = mX.constData();
877  const double *sourceY = mY.constData();
878  const double *sourceZ = useZ ? mZ.constData() : nullptr;
879  const double *sourceM = useM ? mM.constData() : nullptr;
880 
881  double *destX = x1.data();
882  double *destY = y1.data();
883  double *destZ = useZ ? z1.data() : nullptr;
884  double *destM = useM ? m1.data() : nullptr;
885 
886  std::copy( sourceX, sourceX + part1Size, destX );
887  std::copy( sourceY, sourceY + part1Size, destY );
888  if ( useZ )
889  std::copy( sourceZ, sourceZ + part1Size, destZ );
890  if ( useM )
891  std::copy( sourceM, sourceM + part1Size, destM );
892 
893  const int part2Size = size - index;
894  if ( part2Size < 2 )
895  return std::make_tuple( std::make_unique< QgsLineString >( x1, y1, z1, m1 ), std::make_unique< QgsLineString >() );
896 
897  QVector< double > x2( part2Size );
898  QVector< double > y2( part2Size );
899  QVector< double > z2( useZ ? part2Size : 0 );
900  QVector< double > m2( useM ? part2Size : 0 );
901  destX = x2.data();
902  destY = y2.data();
903  destZ = useZ ? z2.data() : nullptr;
904  destM = useM ? m2.data() : nullptr;
905  std::copy( sourceX + index, sourceX + size, destX );
906  std::copy( sourceY + index, sourceY + size, destY );
907  if ( useZ )
908  std::copy( sourceZ + index, sourceZ + size, destZ );
909  if ( useM )
910  std::copy( sourceM + index, sourceM + size, destM );
911 
912  if ( part1Size < 2 )
913  return std::make_tuple( std::make_unique< QgsLineString >(), std::make_unique< QgsLineString >( x2, y2, z2, m2 ) );
914  else
915  return std::make_tuple( std::make_unique< QgsLineString >( x1, y1, z1, m1 ), std::make_unique< QgsLineString >( x2, y2, z2, m2 ) );
916 }
917 
919 {
920  if ( is3D() )
921  {
922  double total = 0;
923  const int size = mX.size();
924  if ( size < 2 )
925  return 0;
926 
927  const double *x = mX.constData();
928  const double *y = mY.constData();
929  const double *z = mZ.constData();
930  double dx, dy, dz;
931 
932  double prevX = *x++;
933  double prevY = *y++;
934  double prevZ = *z++;
935 
936  for ( int i = 1; i < size; ++i )
937  {
938  dx = *x - prevX;
939  dy = *y - prevY;
940  dz = *z - prevZ;
941  total += std::sqrt( dx * dx + dy * dy + dz * dz );
942 
943  prevX = *x++;
944  prevY = *y++;
945  prevZ = *z++;
946  }
947  return total;
948  }
949  else
950  {
951  return length();
952  }
953 }
954 
956 {
957  if ( numPoints() < 1 )
958  {
959  return QgsPoint();
960  }
961  return pointN( 0 );
962 }
963 
965 {
966  if ( numPoints() < 1 )
967  {
968  return QgsPoint();
969  }
970  return pointN( numPoints() - 1 );
971 }
972 
973 /***************************************************************************
974  * This class is considered CRITICAL and any change MUST be accompanied with
975  * full unit tests.
976  * See details in QEP #17
977  ****************************************************************************/
978 
979 QgsLineString *QgsLineString::curveToLine( double tolerance, SegmentationToleranceType toleranceType ) const
980 {
981  Q_UNUSED( tolerance )
982  Q_UNUSED( toleranceType )
983  return clone();
984 }
985 
987 {
988  return mX.size();
989 }
990 
992 {
993  return mX.size();
994 }
995 
997 {
998  if ( i < 0 || i >= mX.size() )
999  {
1000  return QgsPoint();
1001  }
1002 
1003  double x = mX.at( i );
1004  double y = mY.at( i );
1005  double z = std::numeric_limits<double>::quiet_NaN();
1006  double m = std::numeric_limits<double>::quiet_NaN();
1007 
1008  bool hasZ = is3D();
1009  if ( hasZ )
1010  {
1011  z = mZ.at( i );
1012  }
1013  bool hasM = isMeasure();
1014  if ( hasM )
1015  {
1016  m = mM.at( i );
1017  }
1018 
1021  {
1023  }
1024  else if ( hasZ && hasM )
1025  {
1027  }
1028  else if ( hasZ )
1029  {
1030  t = QgsWkbTypes::PointZ;
1031  }
1032  else if ( hasM )
1033  {
1034  t = QgsWkbTypes::PointM;
1035  }
1036  return QgsPoint( t, x, y, z, m );
1037 }
1038 
1039 /***************************************************************************
1040  * This class is considered CRITICAL and any change MUST be accompanied with
1041  * full unit tests.
1042  * See details in QEP #17
1043  ****************************************************************************/
1044 
1045 double QgsLineString::xAt( int index ) const
1046 {
1047  if ( index >= 0 && index < mX.size() )
1048  return mX.at( index );
1049  else
1050  return 0.0;
1051 }
1052 
1053 double QgsLineString::yAt( int index ) const
1054 {
1055  if ( index >= 0 && index < mY.size() )
1056  return mY.at( index );
1057  else
1058  return 0.0;
1059 }
1060 
1061 void QgsLineString::setXAt( int index, double x )
1062 {
1063  if ( index >= 0 && index < mX.size() )
1064  mX[ index ] = x;
1065  clearCache();
1066 }
1067 
1068 void QgsLineString::setYAt( int index, double y )
1069 {
1070  if ( index >= 0 && index < mY.size() )
1071  mY[ index ] = y;
1072  clearCache();
1073 }
1074 
1075 /***************************************************************************
1076  * This class is considered CRITICAL and any change MUST be accompanied with
1077  * full unit tests.
1078  * See details in QEP #17
1079  ****************************************************************************/
1080 
1082 {
1083  pts.clear();
1084  int nPoints = numPoints();
1085  pts.reserve( nPoints );
1086  for ( int i = 0; i < nPoints; ++i )
1087  {
1088  pts.push_back( pointN( i ) );
1089  }
1090 }
1091 
1092 void QgsLineString::setPoints( size_t size, const double *x, const double *y, const double *z, const double *m )
1093 {
1094  clearCache(); //set bounding box invalid
1095 
1096  if ( size <= 0 )
1097  {
1098  clear();
1099  return;
1100  }
1101 
1102  const bool hasZ = static_cast< bool >( z );
1103  const bool hasM = static_cast< bool >( m );
1104 
1105  if ( hasZ && hasM )
1106  {
1108  }
1109  else if ( hasZ )
1110  {
1112  }
1113  else if ( hasM )
1114  {
1116  }
1117  else
1118  {
1120  }
1121 
1122  mX.resize( size );
1123  mY.resize( size );
1124  double *destX = mX.data();
1125  double *destY = mY.data();
1126  double *destZ = nullptr;
1127  if ( hasZ )
1128  {
1129  mZ.resize( size );
1130  destZ = mZ.data();
1131  }
1132  else
1133  {
1134  mZ.clear();
1135  }
1136  double *destM = nullptr;
1137  if ( hasM )
1138  {
1139  mM.resize( size );
1140  destM = mM.data();
1141  }
1142  else
1143  {
1144  mM.clear();
1145  }
1146 
1147  for ( size_t i = 0; i < size; ++i )
1148  {
1149  *destX++ = *x++;
1150  *destY++ = *y++;
1151  if ( hasZ )
1152  {
1153  *destZ++ = *z++;
1154  }
1155  if ( hasM )
1156  {
1157  *destM++ = *m++;
1158  }
1159  }
1160 }
1161 
1163 {
1164  clearCache(); //set bounding box invalid
1165 
1166  if ( points.isEmpty() )
1167  {
1168  clear();
1169  return;
1170  }
1171 
1172  //get wkb type from first point
1173  const QgsPoint &firstPt = points.at( 0 );
1174  bool hasZ = firstPt.is3D();
1175  bool hasM = firstPt.isMeasure();
1176 
1178 
1179  mX.resize( points.size() );
1180  mY.resize( points.size() );
1181  if ( hasZ )
1182  {
1183  mZ.resize( points.size() );
1184  }
1185  else
1186  {
1187  mZ.clear();
1188  }
1189  if ( hasM )
1190  {
1191  mM.resize( points.size() );
1192  }
1193  else
1194  {
1195  mM.clear();
1196  }
1197 
1198  for ( int i = 0; i < points.size(); ++i )
1199  {
1200  mX[i] = points.at( i ).x();
1201  mY[i] = points.at( i ).y();
1202  if ( hasZ )
1203  {
1204  double z = points.at( i ).z();
1205  mZ[i] = std::isnan( z ) ? 0 : z;
1206  }
1207  if ( hasM )
1208  {
1209  double m = points.at( i ).m();
1210  mM[i] = std::isnan( m ) ? 0 : m;
1211  }
1212  }
1213 }
1214 
1215 /***************************************************************************
1216  * This class is considered CRITICAL and any change MUST be accompanied with
1217  * full unit tests.
1218  * See details in QEP #17
1219  ****************************************************************************/
1220 
1222 {
1223  if ( !line )
1224  {
1225  return;
1226  }
1227 
1228  if ( numPoints() < 1 )
1229  {
1231  }
1232 
1233  // do not store duplicate points
1234  if ( numPoints() > 0 &&
1235  line->numPoints() > 0 &&
1236  endPoint() == line->startPoint() )
1237  {
1238  mX.pop_back();
1239  mY.pop_back();
1240 
1241  if ( is3D() )
1242  {
1243  mZ.pop_back();
1244  }
1245  if ( isMeasure() )
1246  {
1247  mM.pop_back();
1248  }
1249  }
1250 
1251  mX += line->mX;
1252  mY += line->mY;
1253 
1254  if ( is3D() )
1255  {
1256  if ( line->is3D() )
1257  {
1258  mZ += line->mZ;
1259  }
1260  else
1261  {
1262  // if append line does not have z coordinates, fill with NaN to match number of points in final line
1263  mZ.insert( mZ.count(), mX.size() - mZ.size(), std::numeric_limits<double>::quiet_NaN() );
1264  }
1265  }
1266 
1267  if ( isMeasure() )
1268  {
1269  if ( line->isMeasure() )
1270  {
1271  mM += line->mM;
1272  }
1273  else
1274  {
1275  // if append line does not have m values, fill with NaN to match number of points in final line
1276  mM.insert( mM.count(), mX.size() - mM.size(), std::numeric_limits<double>::quiet_NaN() );
1277  }
1278  }
1279 
1280  clearCache(); //set bounding box invalid
1281 }
1282 
1284 {
1285  QgsLineString *copy = clone();
1286  std::reverse( copy->mX.begin(), copy->mX.end() );
1287  std::reverse( copy->mY.begin(), copy->mY.end() );
1288  if ( copy->is3D() )
1289  {
1290  std::reverse( copy->mZ.begin(), copy->mZ.end() );
1291  }
1292  if ( copy->isMeasure() )
1293  {
1294  std::reverse( copy->mM.begin(), copy->mM.end() );
1295  }
1296  return copy;
1297 }
1298 
1299 void QgsLineString::visitPointsByRegularDistance( const double distance, const std::function<bool ( double, double, double, double, double, double, double, double, double, double, double, double )> &visitPoint ) const
1300 {
1301  if ( distance < 0 )
1302  return;
1303 
1304  double distanceTraversed = 0;
1305  const int totalPoints = numPoints();
1306  if ( totalPoints == 0 )
1307  return;
1308 
1309  const double *x = mX.constData();
1310  const double *y = mY.constData();
1311  const double *z = is3D() ? mZ.constData() : nullptr;
1312  const double *m = isMeasure() ? mM.constData() : nullptr;
1313 
1314  double prevX = *x++;
1315  double prevY = *y++;
1316  double prevZ = z ? *z++ : 0.0;
1317  double prevM = m ? *m++ : 0.0;
1318 
1319  if ( qgsDoubleNear( distance, 0.0 ) )
1320  {
1321  visitPoint( prevX, prevY, prevZ, prevM, prevX, prevY, prevZ, prevM, prevX, prevY, prevZ, prevM );
1322  return;
1323  }
1324 
1325  double pZ = std::numeric_limits<double>::quiet_NaN();
1326  double pM = std::numeric_limits<double>::quiet_NaN();
1327  double nextPointDistance = distance;
1328  for ( int i = 1; i < totalPoints; ++i )
1329  {
1330  double thisX = *x++;
1331  double thisY = *y++;
1332  double thisZ = z ? *z++ : 0.0;
1333  double thisM = m ? *m++ : 0.0;
1334 
1335  const double segmentLength = std::sqrt( ( thisX - prevX ) * ( thisX - prevX ) + ( thisY - prevY ) * ( thisY - prevY ) );
1336  while ( nextPointDistance < distanceTraversed + segmentLength || qgsDoubleNear( nextPointDistance, distanceTraversed + segmentLength ) )
1337  {
1338  // point falls on this segment - truncate to segment length if qgsDoubleNear test was actually > segment length
1339  const double distanceToPoint = std::min( nextPointDistance - distanceTraversed, segmentLength );
1340  double pX, pY;
1341  QgsGeometryUtils::pointOnLineWithDistance( prevX, prevY, thisX, thisY, distanceToPoint, pX, pY,
1342  z ? &prevZ : nullptr, z ? &thisZ : nullptr, z ? &pZ : nullptr,
1343  m ? &prevM : nullptr, m ? &thisM : nullptr, m ? &pM : nullptr );
1344 
1345  if ( !visitPoint( pX, pY, pZ, pM, prevX, prevY, prevZ, prevM, thisX, thisY, thisZ, thisM ) )
1346  return;
1347 
1348  nextPointDistance += distance;
1349  }
1350 
1351  distanceTraversed += segmentLength;
1352  prevX = thisX;
1353  prevY = thisY;
1354  prevZ = thisZ;
1355  prevM = thisM;
1356  }
1357 }
1358 
1359 QgsPoint *QgsLineString::interpolatePoint( const double distance ) const
1360 {
1361  if ( distance < 0 )
1362  return nullptr;
1363 
1365  if ( is3D() )
1366  pointType = QgsWkbTypes::PointZ;
1367  if ( isMeasure() )
1368  pointType = QgsWkbTypes::addM( pointType );
1369 
1370  std::unique_ptr< QgsPoint > res;
1371  visitPointsByRegularDistance( distance, [ & ]( double x, double y, double z, double m, double, double, double, double, double, double, double, double )->bool
1372  {
1373  res = std::make_unique< QgsPoint >( pointType, x, y, z, m );
1374  return false;
1375  } );
1376  return res.release();
1377 }
1378 
1379 QgsLineString *QgsLineString::curveSubstring( double startDistance, double endDistance ) const
1380 {
1381  if ( startDistance < 0 && endDistance < 0 )
1382  return createEmptyWithSameType();
1383 
1384  endDistance = std::max( startDistance, endDistance );
1385 
1386  const int totalPoints = numPoints();
1387  if ( totalPoints == 0 )
1388  return clone();
1389 
1390  QVector< QgsPoint > substringPoints;
1391  substringPoints.reserve( totalPoints );
1392 
1394  if ( is3D() )
1395  pointType = QgsWkbTypes::PointZ;
1396  if ( isMeasure() )
1397  pointType = QgsWkbTypes::addM( pointType );
1398 
1399  const double *x = mX.constData();
1400  const double *y = mY.constData();
1401  const double *z = is3D() ? mZ.constData() : nullptr;
1402  const double *m = isMeasure() ? mM.constData() : nullptr;
1403 
1404  double distanceTraversed = 0;
1405  double prevX = *x++;
1406  double prevY = *y++;
1407  double prevZ = z ? *z++ : 0.0;
1408  double prevM = m ? *m++ : 0.0;
1409  bool foundStart = false;
1410 
1411  if ( startDistance < 0 )
1412  startDistance = 0;
1413 
1414  for ( int i = 1; i < totalPoints; ++i )
1415  {
1416  double thisX = *x++;
1417  double thisY = *y++;
1418  double thisZ = z ? *z++ : 0.0;
1419  double thisM = m ? *m++ : 0.0;
1420 
1421  const double segmentLength = std::sqrt( ( thisX - prevX ) * ( thisX - prevX ) + ( thisY - prevY ) * ( thisY - prevY ) );
1422 
1423  if ( distanceTraversed <= startDistance && startDistance < distanceTraversed + segmentLength )
1424  {
1425  // start point falls on this segment
1426  const double distanceToStart = startDistance - distanceTraversed;
1427  double startX, startY;
1428  double startZ = 0;
1429  double startM = 0;
1430  QgsGeometryUtils::pointOnLineWithDistance( prevX, prevY, thisX, thisY, distanceToStart, startX, startY,
1431  z ? &prevZ : nullptr, z ? &thisZ : nullptr, z ? &startZ : nullptr,
1432  m ? &prevM : nullptr, m ? &thisM : nullptr, m ? &startM : nullptr );
1433  substringPoints << QgsPoint( pointType, startX, startY, startZ, startM );
1434  foundStart = true;
1435  }
1436  if ( foundStart && ( distanceTraversed + segmentLength > endDistance ) )
1437  {
1438  // end point falls on this segment
1439  const double distanceToEnd = endDistance - distanceTraversed;
1440  double endX, endY;
1441  double endZ = 0;
1442  double endM = 0;
1443  QgsGeometryUtils::pointOnLineWithDistance( prevX, prevY, thisX, thisY, distanceToEnd, endX, endY,
1444  z ? &prevZ : nullptr, z ? &thisZ : nullptr, z ? &endZ : nullptr,
1445  m ? &prevM : nullptr, m ? &thisM : nullptr, m ? &endM : nullptr );
1446  substringPoints << QgsPoint( pointType, endX, endY, endZ, endM );
1447  }
1448  else if ( foundStart )
1449  {
1450  substringPoints << QgsPoint( pointType, thisX, thisY, thisZ, thisM );
1451  }
1452 
1453  prevX = thisX;
1454  prevY = thisY;
1455  prevZ = thisZ;
1456  prevM = thisM;
1457  distanceTraversed += segmentLength;
1458  if ( distanceTraversed >= endDistance )
1459  break;
1460  }
1461 
1462  // start point is the last node
1463  if ( !foundStart && qgsDoubleNear( distanceTraversed, startDistance ) )
1464  {
1465  substringPoints << QgsPoint( pointType, prevX, prevY, prevZ, prevM )
1466  << QgsPoint( pointType, prevX, prevY, prevZ, prevM );
1467  }
1468 
1469  return new QgsLineString( substringPoints );
1470 }
1471 
1472 /***************************************************************************
1473  * This class is considered CRITICAL and any change MUST be accompanied with
1474  * full unit tests.
1475  * See details in QEP #17
1476  ****************************************************************************/
1477 
1478 void QgsLineString::draw( QPainter &p ) const
1479 {
1480  p.drawPolyline( asQPolygonF() );
1481 }
1482 
1483 void QgsLineString::addToPainterPath( QPainterPath &path ) const
1484 {
1485  int nPoints = numPoints();
1486  if ( nPoints < 1 )
1487  {
1488  return;
1489  }
1490 
1491  if ( path.isEmpty() || path.currentPosition() != QPointF( mX.at( 0 ), mY.at( 0 ) ) )
1492  {
1493  path.moveTo( mX.at( 0 ), mY.at( 0 ) );
1494  }
1495 
1496  for ( int i = 1; i < nPoints; ++i )
1497  {
1498  path.lineTo( mX.at( i ), mY.at( i ) );
1499  }
1500 }
1501 
1502 void QgsLineString::drawAsPolygon( QPainter &p ) const
1503 {
1504  p.drawPolygon( asQPolygonF() );
1505 }
1506 
1508 {
1509  QgsCompoundCurve *compoundCurve = new QgsCompoundCurve();
1510  compoundCurve->addCurve( clone() );
1511  return compoundCurve;
1512 }
1513 
1514 void QgsLineString::extend( double startDistance, double endDistance )
1515 {
1516  if ( mX.size() < 2 || mY.size() < 2 )
1517  return;
1518 
1519  // start of line
1520  if ( startDistance > 0 )
1521  {
1522  double currentLen = std::sqrt( std::pow( mX.at( 0 ) - mX.at( 1 ), 2 ) +
1523  std::pow( mY.at( 0 ) - mY.at( 1 ), 2 ) );
1524  double newLen = currentLen + startDistance;
1525  mX[ 0 ] = mX.at( 1 ) + ( mX.at( 0 ) - mX.at( 1 ) ) / currentLen * newLen;
1526  mY[ 0 ] = mY.at( 1 ) + ( mY.at( 0 ) - mY.at( 1 ) ) / currentLen * newLen;
1527  }
1528  // end of line
1529  if ( endDistance > 0 )
1530  {
1531  int last = mX.size() - 1;
1532  double currentLen = std::sqrt( std::pow( mX.at( last ) - mX.at( last - 1 ), 2 ) +
1533  std::pow( mY.at( last ) - mY.at( last - 1 ), 2 ) );
1534  double newLen = currentLen + endDistance;
1535  mX[ last ] = mX.at( last - 1 ) + ( mX.at( last ) - mX.at( last - 1 ) ) / currentLen * newLen;
1536  mY[ last ] = mY.at( last - 1 ) + ( mY.at( last ) - mY.at( last - 1 ) ) / currentLen * newLen;
1537  }
1538 }
1539 
1541 {
1542  auto result = std::make_unique< QgsLineString >();
1543  result->mWkbType = mWkbType;
1544  return result.release();
1545 }
1546 
1548 {
1549  const QgsLineString *otherLine = qgsgeometry_cast<const QgsLineString *>( other );
1550  if ( !otherLine )
1551  return -1;
1552 
1553  const int size = mX.size();
1554  const int otherSize = otherLine->mX.size();
1555  if ( size > otherSize )
1556  {
1557  return 1;
1558  }
1559  else if ( size < otherSize )
1560  {
1561  return -1;
1562  }
1563 
1564  if ( is3D() && !otherLine->is3D() )
1565  return 1;
1566  else if ( !is3D() && otherLine->is3D() )
1567  return -1;
1568  const bool considerZ = is3D();
1569 
1570  if ( isMeasure() && !otherLine->isMeasure() )
1571  return 1;
1572  else if ( !isMeasure() && otherLine->isMeasure() )
1573  return -1;
1574  const bool considerM = isMeasure();
1575 
1576  for ( int i = 0; i < size; i++ )
1577  {
1578  const double x = mX[i];
1579  const double otherX = otherLine->mX[i];
1580  if ( x < otherX )
1581  {
1582  return -1;
1583  }
1584  else if ( x > otherX )
1585  {
1586  return 1;
1587  }
1588 
1589  const double y = mY[i];
1590  const double otherY = otherLine->mY[i];
1591  if ( y < otherY )
1592  {
1593  return -1;
1594  }
1595  else if ( y > otherY )
1596  {
1597  return 1;
1598  }
1599 
1600  if ( considerZ )
1601  {
1602  const double z = mZ[i];
1603  const double otherZ = otherLine->mZ[i];
1604 
1605  if ( z < otherZ )
1606  {
1607  return -1;
1608  }
1609  else if ( z > otherZ )
1610  {
1611  return 1;
1612  }
1613  }
1614 
1615  if ( considerM )
1616  {
1617  const double m = mM[i];
1618  const double otherM = otherLine->mM[i];
1619 
1620  if ( m < otherM )
1621  {
1622  return -1;
1623  }
1624  else if ( m > otherM )
1625  {
1626  return 1;
1627  }
1628  }
1629  }
1630  return 0;
1631 }
1632 
1634 {
1635  return QStringLiteral( "LineString" );
1636 }
1637 
1639 {
1640  return 1;
1641 }
1642 
1643 /***************************************************************************
1644  * This class is considered CRITICAL and any change MUST be accompanied with
1645  * full unit tests.
1646  * See details in QEP #17
1647  ****************************************************************************/
1648 
1650 {
1651  double *zArray = nullptr;
1652  bool hasZ = is3D();
1653  int nPoints = numPoints();
1654 
1655  // it's possible that transformCoords will throw an exception - so we need to use
1656  // a smart pointer for the dummy z values in order to ensure that they always get cleaned up
1657  std::unique_ptr< double[] > dummyZ;
1658  if ( !hasZ || !transformZ )
1659  {
1660  dummyZ.reset( new double[nPoints]() );
1661  zArray = dummyZ.get();
1662  }
1663  else
1664  {
1665  zArray = mZ.data();
1666  }
1667  ct.transformCoords( nPoints, mX.data(), mY.data(), zArray, d );
1668  clearCache();
1669 }
1670 
1671 void QgsLineString::transform( const QTransform &t, double zTranslate, double zScale, double mTranslate, double mScale )
1672 {
1673  int nPoints = numPoints();
1674  bool hasZ = is3D();
1675  bool hasM = isMeasure();
1676  double *x = mX.data();
1677  double *y = mY.data();
1678  double *z = hasZ ? mZ.data() : nullptr;
1679  double *m = hasM ? mM.data() : nullptr;
1680  for ( int i = 0; i < nPoints; ++i )
1681  {
1682  double xOut, yOut;
1683  t.map( *x, *y, &xOut, &yOut );
1684  *x++ = xOut;
1685  *y++ = yOut;
1686  if ( hasZ )
1687  {
1688  *z = *z * zScale + zTranslate;
1689  z++;
1690  }
1691  if ( hasM )
1692  {
1693  *m = *m * mScale + mTranslate;
1694  m++;
1695  }
1696  }
1697  clearCache();
1698 }
1699 
1700 /***************************************************************************
1701  * This class is considered CRITICAL and any change MUST be accompanied with
1702  * full unit tests.
1703  * See details in QEP #17
1704  ****************************************************************************/
1705 
1706 bool QgsLineString::insertVertex( QgsVertexId position, const QgsPoint &vertex )
1707 {
1708  if ( position.vertex < 0 || position.vertex > mX.size() )
1709  {
1710  return false;
1711  }
1712 
1713  if ( mWkbType == QgsWkbTypes::Unknown || mX.isEmpty() )
1714  {
1716  }
1717 
1718  mX.insert( position.vertex, vertex.x() );
1719  mY.insert( position.vertex, vertex.y() );
1720  if ( is3D() )
1721  {
1722  mZ.insert( position.vertex, vertex.z() );
1723  }
1724  if ( isMeasure() )
1725  {
1726  mM.insert( position.vertex, vertex.m() );
1727  }
1728  clearCache(); //set bounding box invalid
1729  return true;
1730 }
1731 
1732 bool QgsLineString::moveVertex( QgsVertexId position, const QgsPoint &newPos )
1733 {
1734  if ( position.vertex < 0 || position.vertex >= mX.size() )
1735  {
1736  return false;
1737  }
1738  mX[position.vertex] = newPos.x();
1739  mY[position.vertex] = newPos.y();
1740  if ( is3D() && newPos.is3D() )
1741  {
1742  mZ[position.vertex] = newPos.z();
1743  }
1744  if ( isMeasure() && newPos.isMeasure() )
1745  {
1746  mM[position.vertex] = newPos.m();
1747  }
1748  clearCache(); //set bounding box invalid
1749  return true;
1750 }
1751 
1753 {
1754  if ( position.vertex >= mX.size() || position.vertex < 0 )
1755  {
1756  return false;
1757  }
1758 
1759  mX.remove( position.vertex );
1760  mY.remove( position.vertex );
1761  if ( is3D() )
1762  {
1763  mZ.remove( position.vertex );
1764  }
1765  if ( isMeasure() )
1766  {
1767  mM.remove( position.vertex );
1768  }
1769 
1770  if ( numPoints() == 1 )
1771  {
1772  clear();
1773  }
1774 
1775  clearCache(); //set bounding box invalid
1776  return true;
1777 }
1778 
1779 /***************************************************************************
1780  * This class is considered CRITICAL and any change MUST be accompanied with
1781  * full unit tests.
1782  * See details in QEP #17
1783  ****************************************************************************/
1784 
1786 {
1787  if ( mWkbType == QgsWkbTypes::Unknown || mX.isEmpty() )
1788  {
1790  }
1791 
1792  mX.append( pt.x() );
1793  mY.append( pt.y() );
1794  if ( is3D() )
1795  {
1796  mZ.append( pt.z() );
1797  }
1798  if ( isMeasure() )
1799  {
1800  mM.append( pt.m() );
1801  }
1802  clearCache(); //set bounding box invalid
1803 }
1804 
1805 double QgsLineString::closestSegment( const QgsPoint &pt, QgsPoint &segmentPt, QgsVertexId &vertexAfter, int *leftOf, double epsilon ) const
1806 {
1807  double sqrDist = std::numeric_limits<double>::max();
1808  double leftOfDist = std::numeric_limits<double>::max();
1809  int prevLeftOf = 0;
1810  double prevLeftOfX = 0.0;
1811  double prevLeftOfY = 0.0;
1812  double testDist = 0;
1813  double segmentPtX, segmentPtY;
1814 
1815  if ( leftOf )
1816  *leftOf = 0;
1817 
1818  int size = mX.size();
1819  if ( size == 0 || size == 1 )
1820  {
1821  vertexAfter = QgsVertexId( 0, 0, 0 );
1822  return -1;
1823  }
1824  for ( int i = 1; i < size; ++i )
1825  {
1826  double prevX = mX.at( i - 1 );
1827  double prevY = mY.at( i - 1 );
1828  double currentX = mX.at( i );
1829  double currentY = mY.at( i );
1830  testDist = QgsGeometryUtils::sqrDistToLine( pt.x(), pt.y(), prevX, prevY, currentX, currentY, segmentPtX, segmentPtY, epsilon );
1831  if ( testDist < sqrDist )
1832  {
1833  sqrDist = testDist;
1834  segmentPt.setX( segmentPtX );
1835  segmentPt.setY( segmentPtY );
1836  vertexAfter.part = 0;
1837  vertexAfter.ring = 0;
1838  vertexAfter.vertex = i;
1839  }
1840  if ( leftOf && qgsDoubleNear( testDist, sqrDist ) )
1841  {
1842  int left = QgsGeometryUtils::leftOfLine( pt.x(), pt.y(), prevX, prevY, currentX, currentY );
1843  // if left equals 0, the test could not be performed (e.g. point in line with segment or on segment)
1844  // so don't set leftOf in this case, and hope that there's another segment that's the same distance
1845  // where we can perform the check
1846  if ( left != 0 )
1847  {
1848  if ( qgsDoubleNear( testDist, leftOfDist ) && left != prevLeftOf && prevLeftOf != 0 )
1849  {
1850  // we have two possible segments each with equal distance to point, but they disagree
1851  // on whether or not the point is to the left of them.
1852  // so we test the segments themselves and flip the result.
1853  // see https://stackoverflow.com/questions/10583212/elegant-left-of-test-for-polyline
1854  *leftOf = -QgsGeometryUtils::leftOfLine( currentX, currentY, prevLeftOfX, prevLeftOfY, prevX, prevY );
1855  }
1856  else
1857  {
1858  *leftOf = left;
1859  }
1860  prevLeftOf = *leftOf;
1861  leftOfDist = testDist;
1862  prevLeftOfX = prevX;
1863  prevLeftOfY = prevY;
1864  }
1865  else if ( testDist < leftOfDist )
1866  {
1867  *leftOf = left;
1868  leftOfDist = testDist;
1869  prevLeftOf = 0;
1870  }
1871  }
1872  }
1873  return sqrDist;
1874 }
1875 
1876 /***************************************************************************
1877  * This class is considered CRITICAL and any change MUST be accompanied with
1878  * full unit tests.
1879  * See details in QEP #17
1880  ****************************************************************************/
1881 
1882 bool QgsLineString::pointAt( int node, QgsPoint &point, Qgis::VertexType &type ) const
1883 {
1884  if ( node < 0 || node >= numPoints() )
1885  {
1886  return false;
1887  }
1888  point = pointN( node );
1889  type = Qgis::VertexType::Segment;
1890  return true;
1891 }
1892 
1894 {
1895  if ( mX.isEmpty() )
1896  return QgsPoint();
1897 
1898  int numPoints = mX.count();
1899  if ( numPoints == 1 )
1900  return QgsPoint( mX.at( 0 ), mY.at( 0 ) );
1901 
1902  double totalLineLength = 0.0;
1903  double prevX = mX.at( 0 );
1904  double prevY = mY.at( 0 );
1905  double sumX = 0.0;
1906  double sumY = 0.0;
1907 
1908  for ( int i = 1; i < numPoints ; ++i )
1909  {
1910  double currentX = mX.at( i );
1911  double currentY = mY.at( i );
1912  double segmentLength = std::sqrt( std::pow( currentX - prevX, 2.0 ) +
1913  std::pow( currentY - prevY, 2.0 ) );
1914  if ( qgsDoubleNear( segmentLength, 0.0 ) )
1915  continue;
1916 
1917  totalLineLength += segmentLength;
1918  sumX += segmentLength * 0.5 * ( currentX + prevX );
1919  sumY += segmentLength * 0.5 * ( currentY + prevY );
1920  prevX = currentX;
1921  prevY = currentY;
1922  }
1923 
1924  if ( qgsDoubleNear( totalLineLength, 0.0 ) )
1925  return QgsPoint( mX.at( 0 ), mY.at( 0 ) );
1926  else
1927  return QgsPoint( sumX / totalLineLength, sumY / totalLineLength );
1928 
1929 }
1930 
1931 /***************************************************************************
1932  * This class is considered CRITICAL and any change MUST be accompanied with
1933  * full unit tests.
1934  * See details in QEP #17
1935  ****************************************************************************/
1936 
1937 void QgsLineString::sumUpArea( double &sum ) const
1938 {
1939  int maxIndex = numPoints() - 1;
1940 
1941  for ( int i = 0; i < maxIndex; ++i )
1942  {
1943  sum += 0.5 * ( mX.at( i ) * mY.at( i + 1 ) - mY.at( i ) * mX.at( i + 1 ) );
1944  }
1945 }
1946 
1947 void QgsLineString::importVerticesFromWkb( const QgsConstWkbPtr &wkb )
1948 {
1949  bool hasZ = is3D();
1950  bool hasM = isMeasure();
1951  int nVertices = 0;
1952  wkb >> nVertices;
1953  mX.resize( nVertices );
1954  mY.resize( nVertices );
1955  hasZ ? mZ.resize( nVertices ) : mZ.clear();
1956  hasM ? mM.resize( nVertices ) : mM.clear();
1957  double *x = mX.data();
1958  double *y = mY.data();
1959  double *m = hasM ? mM.data() : nullptr;
1960  double *z = hasZ ? mZ.data() : nullptr;
1961  for ( int i = 0; i < nVertices; ++i )
1962  {
1963  wkb >> *x++;
1964  wkb >> *y++;
1965  if ( hasZ )
1966  {
1967  wkb >> *z++;
1968  }
1969  if ( hasM )
1970  {
1971  wkb >> *m++;
1972  }
1973  }
1974  clearCache(); //set bounding box invalid
1975 }
1976 
1977 /***************************************************************************
1978  * This class is considered CRITICAL and any change MUST be accompanied with
1979  * full unit tests.
1980  * See details in QEP #17
1981  ****************************************************************************/
1982 
1984 {
1985  if ( numPoints() < 1 || isClosed() )
1986  {
1987  return;
1988  }
1989  addVertex( startPoint() );
1990 }
1991 
1993 {
1994  if ( mX.count() < 2 )
1995  {
1996  //undefined
1997  return 0.0;
1998  }
1999 
2000  if ( vertex.vertex == 0 || vertex.vertex >= ( numPoints() - 1 ) )
2001  {
2002  if ( isClosed() )
2003  {
2004  double previousX = mX.at( numPoints() - 2 );
2005  double previousY = mY.at( numPoints() - 2 );
2006  double currentX = mX.at( 0 );
2007  double currentY = mY.at( 0 );
2008  double afterX = mX.at( 1 );
2009  double afterY = mY.at( 1 );
2010  return QgsGeometryUtils::averageAngle( previousX, previousY, currentX, currentY, afterX, afterY );
2011  }
2012  else if ( vertex.vertex == 0 )
2013  {
2014  return QgsGeometryUtils::lineAngle( mX.at( 0 ), mY.at( 0 ), mX.at( 1 ), mY.at( 1 ) );
2015  }
2016  else
2017  {
2018  int a = numPoints() - 2;
2019  int b = numPoints() - 1;
2020  return QgsGeometryUtils::lineAngle( mX.at( a ), mY.at( a ), mX.at( b ), mY.at( b ) );
2021  }
2022  }
2023  else
2024  {
2025  double previousX = mX.at( vertex.vertex - 1 );
2026  double previousY = mY.at( vertex.vertex - 1 );
2027  double currentX = mX.at( vertex.vertex );
2028  double currentY = mY.at( vertex.vertex );
2029  double afterX = mX.at( vertex.vertex + 1 );
2030  double afterY = mY.at( vertex.vertex + 1 );
2031  return QgsGeometryUtils::averageAngle( previousX, previousY, currentX, currentY, afterX, afterY );
2032  }
2033 }
2034 
2035 double QgsLineString::segmentLength( QgsVertexId startVertex ) const
2036 {
2037  if ( startVertex.vertex < 0 || startVertex.vertex >= mX.count() - 1 )
2038  return 0.0;
2039 
2040  double dx = mX.at( startVertex.vertex + 1 ) - mX.at( startVertex.vertex );
2041  double dy = mY.at( startVertex.vertex + 1 ) - mY.at( startVertex.vertex );
2042  return std::sqrt( dx * dx + dy * dy );
2043 }
2044 
2045 /***************************************************************************
2046  * This class is considered CRITICAL and any change MUST be accompanied with
2047  * full unit tests.
2048  * See details in QEP #17
2049  ****************************************************************************/
2050 
2051 bool QgsLineString::addZValue( double zValue )
2052 {
2053  if ( QgsWkbTypes::hasZ( mWkbType ) )
2054  return false;
2055 
2056  clearCache();
2057  if ( mWkbType == QgsWkbTypes::Unknown )
2058  {
2060  return true;
2061  }
2062 
2064 
2065  mZ.clear();
2066  int nPoints = numPoints();
2067  mZ.reserve( nPoints );
2068  for ( int i = 0; i < nPoints; ++i )
2069  {
2070  mZ << zValue;
2071  }
2072  return true;
2073 }
2074 
2075 bool QgsLineString::addMValue( double mValue )
2076 {
2077  if ( QgsWkbTypes::hasM( mWkbType ) )
2078  return false;
2079 
2080  clearCache();
2081  if ( mWkbType == QgsWkbTypes::Unknown )
2082  {
2084  return true;
2085  }
2086 
2088  {
2090  }
2091  else
2092  {
2094  }
2095 
2096  mM.clear();
2097  int nPoints = numPoints();
2098  mM.reserve( nPoints );
2099  for ( int i = 0; i < nPoints; ++i )
2100  {
2101  mM << mValue;
2102  }
2103  return true;
2104 }
2105 
2107 {
2108  if ( !is3D() )
2109  return false;
2110 
2111  clearCache();
2113  mZ.clear();
2114  return true;
2115 }
2116 
2118 {
2119  if ( !isMeasure() )
2120  return false;
2121 
2122  clearCache();
2124  mM.clear();
2125  return true;
2126 }
2127 
2129 {
2130  std::swap( mX, mY );
2131  clearCache();
2132 }
2133 
2135 {
2136  if ( type == mWkbType )
2137  return true;
2138 
2139  clearCache();
2140  if ( type == QgsWkbTypes::LineString25D )
2141  {
2142  //special handling required for conversion to LineString25D
2143  dropMValue();
2144  addZValue( std::numeric_limits<double>::quiet_NaN() );
2146  return true;
2147  }
2148  else
2149  {
2150  return QgsCurve::convertTo( type );
2151  }
2152 }
2153 
2155 {
2156  if ( !transformer )
2157  return false;
2158 
2159  bool hasZ = is3D();
2160  bool hasM = isMeasure();
2161  int size = mX.size();
2162 
2163  double *srcX = mX.data();
2164  double *srcY = mY.data();
2165  double *srcM = hasM ? mM.data() : nullptr;
2166  double *srcZ = hasZ ? mZ.data() : nullptr;
2167 
2168  bool res = true;
2169  for ( int i = 0; i < size; ++i )
2170  {
2171  double x = *srcX;
2172  double y = *srcY;
2173  double z = hasZ ? *srcZ : std::numeric_limits<double>::quiet_NaN();
2174  double m = hasM ? *srcM : std::numeric_limits<double>::quiet_NaN();
2175  if ( !transformer->transformPoint( x, y, z, m ) )
2176  {
2177  res = false;
2178  break;
2179  }
2180 
2181  *srcX++ = x;
2182  *srcY++ = y;
2183  if ( hasM )
2184  *srcM++ = m;
2185  if ( hasZ )
2186  *srcZ++ = z;
2187 
2188  if ( feedback && feedback->isCanceled() )
2189  {
2190  res = false;
2191  break;
2192  }
2193  }
2194  clearCache();
2195  return res;
2196 }
2197 
2198 void QgsLineString::filterVertices( const std::function<bool ( const QgsPoint & )> &filter )
2199 {
2200  bool hasZ = is3D();
2201  bool hasM = isMeasure();
2202  int size = mX.size();
2203 
2204  double *srcX = mX.data();
2205  double *srcY = mY.data();
2206  double *srcM = hasM ? mM.data() : nullptr;
2207  double *srcZ = hasZ ? mZ.data() : nullptr;
2208 
2209  double *destX = srcX;
2210  double *destY = srcY;
2211  double *destM = srcM;
2212  double *destZ = srcZ;
2213 
2214  int filteredPoints = 0;
2215  for ( int i = 0; i < size; ++i )
2216  {
2217  double x = *srcX++;
2218  double y = *srcY++;
2219  double z = hasZ ? *srcZ++ : std::numeric_limits<double>::quiet_NaN();
2220  double m = hasM ? *srcM++ : std::numeric_limits<double>::quiet_NaN();
2221 
2222  if ( filter( QgsPoint( x, y, z, m ) ) )
2223  {
2224  filteredPoints++;
2225  *destX++ = x;
2226  *destY++ = y;
2227  if ( hasM )
2228  *destM++ = m;
2229  if ( hasZ )
2230  *destZ++ = z;
2231  }
2232  }
2233 
2234  mX.resize( filteredPoints );
2235  mY.resize( filteredPoints );
2236  if ( hasZ )
2237  mZ.resize( filteredPoints );
2238  if ( hasM )
2239  mM.resize( filteredPoints );
2240 
2241  clearCache();
2242 }
2243 
2244 void QgsLineString::transformVertices( const std::function<QgsPoint( const QgsPoint & )> &transform )
2245 {
2246  bool hasZ = is3D();
2247  bool hasM = isMeasure();
2248  int size = mX.size();
2249 
2250  double *srcX = mX.data();
2251  double *srcY = mY.data();
2252  double *srcM = hasM ? mM.data() : nullptr;
2253  double *srcZ = hasZ ? mZ.data() : nullptr;
2254 
2255  for ( int i = 0; i < size; ++i )
2256  {
2257  double x = *srcX;
2258  double y = *srcY;
2259  double z = hasZ ? *srcZ : std::numeric_limits<double>::quiet_NaN();
2260  double m = hasM ? *srcM : std::numeric_limits<double>::quiet_NaN();
2261  QgsPoint res = transform( QgsPoint( x, y, z, m ) );
2262  *srcX++ = res.x();
2263  *srcY++ = res.y();
2264  if ( hasM )
2265  *srcM++ = res.m();
2266  if ( hasZ )
2267  *srcZ++ = res.z();
2268  }
2269  clearCache();
2270 }
QgsRectangle::intersects
bool intersects(const QgsRectangle &rect) const SIP_HOLDGIL
Returns true when rectangle intersects with other rectangle.
Definition: qgsrectangle.h:349
QgsCurve
Abstract base class for curved geometry type.
Definition: qgscurve.h:35
qgsgeometrytransformer.h
QgsVertexId::part
int part
Part number.
Definition: qgsvertexid.h:89
QgsCoordinateTransform::transformCoords
void transformCoords(int numPoint, double *x, double *y, double *z, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward) const SIP_THROW(QgsCsException)
Transform an array of coordinates to the destination CRS.
Definition: qgscoordinatetransform.cpp:705
QgsLineString::pointN
QgsPoint pointN(int i) const
Returns the specified point from inside the line string.
Definition: qgslinestring.cpp:996
QgsLineString::setYAt
void setYAt(int index, double y)
Sets the y-coordinate of the specified node in the line string.
Definition: qgslinestring.cpp:1068
QgsVertexId::vertex
int vertex
Vertex number.
Definition: qgsvertexid.h:95
QgsLineString::xAt
double xAt(int index) const override
Returns the x-coordinate of the specified node in the line string.
Definition: qgslinestring.cpp:1045
QgsLineString::zData
const double * zData() const
Returns a const pointer to the z vertex data, or nullptr if the linestring does not have z values.
Definition: qgslinestring.h:437
QgsCurve::isRing
virtual bool isRing() const SIP_HOLDGIL
Returns true if the curve is a ring.
Definition: qgscurve.cpp:65
QgsWkbTypes::dropM
static Type dropM(Type type) SIP_HOLDGIL
Drops the m dimension (if present) for a WKB type and returns the new type.
Definition: qgswkbtypes.h:1255
QgsWkbTypes::Point
@ Point
Definition: qgswkbtypes.h:72
QgsGeometryUtils::pointsToJson
static json pointsToJson(const QgsPointSequence &points, int precision)
Returns coordinates as json object.
Definition: qgsgeometryutils.cpp:1320
QgsLineString::transform
void transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection d=Qgis::TransformDirection::Forward, bool transformZ=false) override SIP_THROW(QgsCsException)
Transforms the geometry using a coordinate transform.
Definition: qgslinestring.cpp:1649
QgsLineString::endPoint
QgsPoint endPoint() const override SIP_HOLDGIL
Returns the end point of the curve.
Definition: qgslinestring.cpp:964
QgsLineSegment2D
Represents a single 2D line segment, consisting of a 2D start and end vertex only.
Definition: qgslinesegment.h:31
QgsLineString::length
double length() const override SIP_HOLDGIL
Returns the planar, 2-dimensional length of the geometry.
Definition: qgslinestring.cpp:833
QgsLineString::asWkt
QString asWkt(int precision=17) const override
Returns a WKT representation of the geometry.
Definition: qgslinestring.cpp:716
qgslinestring.h
QgsLineString::addMValue
bool addMValue(double mValue=0) override
Adds a measure to the geometry, initialized to a preset value.
Definition: qgslinestring.cpp:2075
QgsLineString::isValid
bool isValid(QString &error, Qgis::GeometryValidityFlags flags=Qgis::GeometryValidityFlags()) const override
Checks validity of the geometry, and returns true if the geometry is valid.
Definition: qgslinestring.cpp:347
QgsWkbTypes::Point25D
@ Point25D
Definition: qgswkbtypes.h:125
QgsPoint
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:48
QgsWkbTypes::LineString25D
@ LineString25D
Definition: qgswkbtypes.h:126
qgswkbptr.h
QgsLineString::asGml2
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.
Definition: qgslinestring.cpp:731
qgsmaptopixel.h
QgsLineString::addToPainterPath
void addToPainterPath(QPainterPath &path) const override
Adds a curve to a painter path.
Definition: qgslinestring.cpp:1483
QgsLineString::yAt
double yAt(int index) const override
Returns the y-coordinate of the specified node in the line string.
Definition: qgslinestring.cpp:1053
qgscompoundcurve.h
QgsWkbTypes::flatType
static Type flatType(Type type) SIP_HOLDGIL
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:732
QgsAbstractGeometry::parts
QgsGeometryConstPartIterator parts() const
Returns Java-style iterator for traversal of parts of the geometry.
Definition: qgsabstractgeometry.cpp:308
QgsLineString::centroid
QgsPoint centroid() const override
Returns the centroid of the geometry.
Definition: qgslinestring.cpp:1893
QgsWkbTypes::LineString
@ LineString
Definition: qgswkbtypes.h:73
QgsRectangle::yMinimum
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:198
QgsGeometryUtils::sqrDistToLine
static double sqrDistToLine(double ptX, double ptY, double x1, double y1, double x2, double y2, double &minDistX, double &minDistY, double epsilon) SIP_HOLDGIL
Returns the squared distance between a point and a line.
Definition: qgsgeometryutils.cpp:203
QgsWkbTypes::addZ
static Type addZ(Type type) SIP_HOLDGIL
Adds the z dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:1176
QgsLineString::calculateBoundingBox3d
QgsBox3d calculateBoundingBox3d() const
Calculates the minimal 3D bounding box for the geometry.
Definition: qgslinestring.cpp:592
QgsLineString::snappedToGrid
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.
Definition: qgslinestring.cpp:357
QgsLineString::curveToLine
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.
Definition: qgslinestring.cpp:979
QgsAbstractGeometry::wktTypeStr
QString wktTypeStr() const
Returns the WKT type string of the geometry.
Definition: qgsabstractgeometry.cpp:181
QgsWkbTypes::LineStringM
@ LineStringM
Definition: qgswkbtypes.h:100
QgsGeometryUtils::lineAngle
static double lineAngle(double x1, double y1, double x2, double y2) SIP_HOLDGIL
Calculates the direction of line joining two points in radians, clockwise from the north direction.
Definition: qgsgeometryutils.cpp:1641
QgsFeedback::isCanceled
bool isCanceled() const SIP_HOLDGIL
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:67
QgsPoint::z
double z
Definition: qgspoint.h:71
QgsLineString::drawAsPolygon
void drawAsPolygon(QPainter &p) const override
Draws the curve as a polygon on the specified QPainter.
Definition: qgslinestring.cpp:1502
QgsLineString::yData
const double * yData() const
Returns a const pointer to the y vertex data.
Definition: qgslinestring.h:424
QgsLineString::segmentLength
double segmentLength(QgsVertexId startVertex) const override
Returns the length of the segment of the geometry which begins at startVertex.
Definition: qgslinestring.cpp:2035
QgsWkbTypes::LineStringZ
@ LineStringZ
Definition: qgswkbtypes.h:87
QgsLineString::setXAt
void setXAt(int index, double x)
Sets the x-coordinate of the specified node in the line string.
Definition: qgslinestring.cpp:1061
QgsWkbTypes::Type
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:69
QgsAbstractGeometry::SegmentationToleranceType
SegmentationToleranceType
Segmentation tolerance as maximum angle or maximum difference between approximation and circle.
Definition: qgsabstractgeometry.h:120
QgsAbstractGeometry::mWkbType
QgsWkbTypes::Type mWkbType
Definition: qgsabstractgeometry.h:1119
QgsLineString::scroll
void scroll(int firstVertexIndex) final
Scrolls the curve vertices so that they start with the vertex at the given index.
Definition: qgslinestring.cpp:620
QgsGeometryUtils::leftOfLine
static int leftOfLine(const double x, const double y, const double x1, const double y1, const double x2, const double y2) SIP_HOLDGIL
Returns a value < 0 if the point (x, y) is left of the line from (x1, y1) -> (x2, y2).
Definition: qgsgeometryutils.cpp:605
QgsLineString
Line string geometry type, with support for z-dimension and m-values.
Definition: qgslinestring.h:44
QgsLineString::draw
void draw(QPainter &p) const override
Draws the geometry using the specified QPainter.
Definition: qgslinestring.cpp:1478
QgsLineString::addZValue
bool addZValue(double zValue=0) override
Adds a z-dimension to the geometry, initialized to a preset value.
Definition: qgslinestring.cpp:2051
QgsLineString::toCurveType
QgsCompoundCurve * toCurveType() const override
Returns the geometry converted to the more generic curve type QgsCompoundCurve.
Definition: qgslinestring.cpp:1507
QgsGeometryUtils::pointsFromWKT
static QgsPointSequence pointsFromWKT(const QString &wktCoordinateList, bool is3D, bool isMeasure)
Returns a list of points contained in a WKT string.
Definition: qgsgeometryutils.cpp:1132
QgsRectangle
A rectangle specified with double values.
Definition: qgsrectangle.h:41
qgslinesegment.h
QgsLineString::xData
const double * xData() const
Returns a const pointer to the x vertex data.
Definition: qgslinestring.h:413
qgsDoubleToString
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition: qgis.h:2204
QgsLineString::isEmpty
bool isEmpty() const override SIP_HOLDGIL
Returns true if the geometry is empty.
Definition: qgslinestring.cpp:311
QgsLineString::nCoordinates
int nCoordinates() const override SIP_HOLDGIL
Returns the number of nodes contained in the geometry.
Definition: qgslinestring.cpp:991
QgsCurve::clearCache
void clearCache() const override
Clears any cached parameters associated with the geometry, e.g., bounding boxes.
Definition: qgscurve.cpp:293
QgsLineString::collectDuplicateNodes
QVector< QgsVertexId > collectDuplicateNodes(double epsilon=4 *std::numeric_limits< double >::epsilon(), bool useZValues=false) const
Returns a list of any duplicate nodes contained in the geometry, within the specified tolerance.
Definition: qgslinestring.cpp:506
qgsapplication.h
QgsAbstractGeometry::isMeasure
bool isMeasure() const SIP_HOLDGIL
Returns true if the geometry contains m values.
Definition: qgsabstractgeometry.h:228
QgsLineString::fromBezierCurve
static QgsLineString * fromBezierCurve(const QgsPoint &start, const QgsPoint &controlPoint1, const QgsPoint &controlPoint2, const QgsPoint &end, int segments=30)
Returns a new linestring created by segmentizing the bezier curve between start and end,...
Definition: qgslinestring.cpp:187
QgsWkbTypes::PointM
@ PointM
Definition: qgswkbtypes.h:99
MathUtils::leftOf
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'. Negative values mean left ...
Definition: MathUtils.cpp:292
QgsRectangle::xMaximum
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:183
QgsPoint::y
double y
Definition: qgspoint.h:70
QgsWkbTypes::addM
static Type addM(Type type) SIP_HOLDGIL
Adds the m dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:1201
precision
int precision
Definition: qgswfsgetfeature.cpp:103
QgsWkbTypes::PointZM
@ PointZM
Definition: qgswkbtypes.h:112
QgsLineString::clone
QgsLineString * clone() const override
Clones the geometry by performing a deep copy.
Definition: qgslinestring.cpp:296
QgsLineString::isClosed2D
bool isClosed2D() const override SIP_HOLDGIL
Returns true if the curve is closed.
Definition: qgslinestring.cpp:410
QgsLineString::boundingBoxIntersects
bool boundingBoxIntersects(const QgsRectangle &rectangle) const override SIP_HOLDGIL
Returns true if the bounding box of this geometry intersects with a rectangle.
Definition: qgslinestring.cpp:428
QgsAbstractGeometry::wkbType
QgsWkbTypes::Type wkbType() const SIP_HOLDGIL
Returns the WKB type of the geometry.
Definition: qgsabstractgeometry.h:206
QgsLineString::asKml
QString asKml(int precision=17) const override
Returns a KML representation of the geometry.
Definition: qgslinestring.cpp:771
QgsLineString::compareToSameClass
int compareToSameClass(const QgsAbstractGeometry *other) const final
Compares to an other geometry of the same class, and returns a integer for sorting of the two geometr...
Definition: qgslinestring.cpp:1547
QgsWkbTypes::Unknown
@ Unknown
Definition: qgswkbtypes.h:71
QgsAbstractGeometry::AxisOrder
AxisOrder
Axis order for GML generation.
Definition: qgsabstractgeometry.h:138
QgsLineString::convertTo
bool convertTo(QgsWkbTypes::Type type) override
Converts the geometry to a specified type.
Definition: qgslinestring.cpp:2134
QgsLineString::insertVertex
bool insertVertex(QgsVertexId position, const QgsPoint &vertex) override
Inserts a vertex into the geometry.
Definition: qgslinestring.cpp:1706
QgsGeometryUtils::pointsToWKB
static void pointsToWKB(QgsWkbPtr &wkb, const QgsPointSequence &points, bool is3D, bool isMeasure)
Returns a LinearRing { uint32 numPoints; Point points[numPoints]; }.
Definition: qgsgeometryutils.cpp:1219
qgsDoubleNear
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:2265
QgsConstWkbPtr
A const WKB pointer.
Definition: qgswkbptr.h:137
QgsLineString::transformVertices
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.
Definition: qgslinestring.cpp:2244
QgsLineString::moveVertex
bool moveVertex(QgsVertexId position, const QgsPoint &newPos) override
Moves a vertex within the geometry.
Definition: qgslinestring.cpp:1732
QgsFeedback
Base class for feedback objects to be used for cancellation of something running in a worker thread.
Definition: qgsfeedback.h:44
QgsLineString::setPoints
void setPoints(size_t size, const double *x, const double *y, const double *z=nullptr, const double *m=nullptr)
Resets the line string to match the specified point data.
Definition: qgslinestring.cpp:1092
QgsLineString::asQPolygonF
QPolygonF asQPolygonF() const override
Returns a QPolygonF representing the points.
Definition: qgslinestring.cpp:545
QgsLineString::indexOf
int indexOf(const QgsPoint &point) const final
Returns the index of the first vertex matching the given point, or -1 if a matching vertex is not fou...
Definition: qgslinestring.cpp:316
QgsLineString::QgsLineString
QgsLineString() SIP_HOLDGIL
Constructor for an empty linestring geometry.
Definition: qgslinestring.cpp:45
QgsLineString::asWkb
QByteArray asWkb(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const override
Definition: qgslinestring.cpp:697
QgsLineString::asJsonObject
json asJsonObject(int precision=17) const override
Returns a json object representation of the geometry.
Definition: qgslinestring.cpp:760
QgsRectangle::contains
bool contains(const QgsRectangle &rect) const SIP_HOLDGIL
Returns true when rectangle contains other rectangle.
Definition: qgsrectangle.h:363
QgsGeometryUtils::averageAngle
static double averageAngle(double x1, double y1, double x2, double y2, double x3, double y3) SIP_HOLDGIL
Calculates the average angle (in radians) between the two linear segments from (x1,...
Definition: qgsgeometryutils.cpp:1662
QgsGeometryUtils::pointOnLineWithDistance
static QgsPoint pointOnLineWithDistance(const QgsPoint &startPoint, const QgsPoint &directionPoint, double distance) SIP_HOLDGIL
Returns a point a specified distance toward a second point.
Definition: qgsgeometryutils.cpp:616
QgsLineString::fromQPolygonF
static QgsLineString * fromQPolygonF(const QPolygonF &polygon)
Returns a new linestring from a QPolygonF polygon input.
Definition: qgslinestring.cpp:248
QgsLineString::asGml3
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.
Definition: qgslinestring.cpp:746
QgsPoint::setX
void setX(double x) SIP_HOLDGIL
Sets the point's x-coordinate.
Definition: qgspoint.h:297
QgsWkbTypes::LineStringZM
@ LineStringZM
Definition: qgswkbtypes.h:113
QgsLineString::splitCurveAtVertex
std::tuple< std::unique_ptr< QgsCurve >, std::unique_ptr< QgsCurve > > splitCurveAtVertex(int index) const final
Splits the curve at the specified vertex index, returning two curves which represent the portion of t...
Definition: qgslinestring.cpp:859
QgsWkbTypes::hasM
static bool hasM(Type type) SIP_HOLDGIL
Tests whether a WKB type contains m values.
Definition: qgswkbtypes.h:1130
QgsLineString::length3D
double length3D() const SIP_HOLDGIL
Returns the length in 3D world of the line string.
Definition: qgslinestring.cpp:918
QgsWkbTypes::PointZ
@ PointZ
Definition: qgswkbtypes.h:86
QgsApplication::endian
static endian_t endian()
Returns whether this machine uses big or little endian.
Definition: qgsapplication.cpp:1404
QgsPoint::m
double m
Definition: qgspoint.h:72
qgscoordinatetransform.h
QgsWkbTypes::zmType
static Type zmType(Type type, bool hasZ, bool hasM) SIP_HOLDGIL
Returns the modified input geometry type according to hasZ / hasM.
Definition: qgswkbtypes.h:831
QgsLineString::clear
void clear() override
Clears the geometry, ie reset it to a null geometry.
Definition: qgslinestring.cpp:301
QgsWkbTypes::dropZ
static Type dropZ(Type type) SIP_HOLDGIL
Drops the z dimension (if present) for a WKB type and returns the new type.
Definition: qgswkbtypes.h:1237
QgsRectangle::xMinimum
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:188
QgsWkbPtr
WKB pointer handler.
Definition: qgswkbptr.h:43
QgsCurve::isValid
bool isValid(QString &error, Qgis::GeometryValidityFlags flags=Qgis::GeometryValidityFlags()) const override
Checks validity of the geometry, and returns true if the geometry is valid.
Definition: qgscurve.cpp:247
QgsCurve::snapToGridPrivate
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.
Definition: qgscurve.cpp:316
qgsbox3d.h
QgsLineString::mData
const double * mData() const
Returns a const pointer to the m vertex data, or nullptr if the linestring does not have m values.
Definition: qgslinestring.h:453
QgsAbstractGeometry
Abstract base class for all geometries.
Definition: qgsabstractgeometry.h:79
QgsLineString::sumUpArea
void sumUpArea(double &sum) const override
Sums up the area of the curve by iterating over the vertices (shoelace formula).
Definition: qgslinestring.cpp:1937
QgsLineString::interpolatePoint
QgsPoint * interpolatePoint(double distance) const override
Returns an interpolated point on the curve at the specified distance.
Definition: qgslinestring.cpp:1359
qgsgeometryutils.h
QgsAbstractGeometry::is3D
bool is3D() const SIP_HOLDGIL
Returns true if the geometry is 3D and contains a z-value.
Definition: qgsabstractgeometry.h:219
QgsLineString::curveSubstring
QgsLineString * curveSubstring(double startDistance, double endDistance) const override
Returns a new curve representing a substring of this curve.
Definition: qgslinestring.cpp:1379
QgsLineString::extend
void extend(double startDistance, double endDistance)
Extends the line geometry by extrapolating out the start or end of the line by a specified distance.
Definition: qgslinestring.cpp:1514
QgsPointXY
A class to represent a 2D point.
Definition: qgspointxy.h:58
QgsLineString::dropMValue
bool dropMValue() override
Drops any measure values which exist in the geometry.
Definition: qgslinestring.cpp:2117
QgsGeometryUtils::pointsToGML3
static QDomElement pointsToGML3(const QgsPointSequence &points, QDomDocument &doc, int precision, const QString &ns, bool is3D, QgsAbstractGeometry::AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY)
Returns a gml::posList DOM element.
Definition: qgsgeometryutils.cpp:1282
Qgis::VertexType
VertexType
Types of vertex.
Definition: qgis.h:1356
QgsLineString::fromWkt
bool fromWkt(const QString &wkt) override
Sets the geometry from a WKT string.
Definition: qgslinestring.cpp:663
QgsLineString::dimension
int dimension() const override SIP_HOLDGIL
Returns the inherent dimension of the geometry.
Definition: qgslinestring.cpp:1638
QgsLineString::append
void append(const QgsLineString *line)
Appends the contents of another line string to the end of this line string.
Definition: qgslinestring.cpp:1221
QgsRectangle::yMaximum
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:193
QgsLineString::swapXy
void swapXy() override
Swaps the x and y coordinates from the geometry.
Definition: qgslinestring.cpp:2128
QgsPointSequence
QVector< QgsPoint > QgsPointSequence
Definition: qgsabstractgeometry.h:52
QgsLineString::wkbSize
int wkbSize(QgsAbstractGeometry::WkbFlags flags=QgsAbstractGeometry::WkbFlags()) const override
Returns the length of the QByteArray returned by asWkb()
Definition: qgslinestring.cpp:690
QgsLineString::close
void close()
Closes the line string by appending the first point to the end of the line, if it is not already clos...
Definition: qgslinestring.cpp:1983
QgsLineString::pointAt
bool pointAt(int node, QgsPoint &point, Qgis::VertexType &type) const override
Returns the point and vertex id of a point within the curve.
Definition: qgslinestring.cpp:1882
QgsLineString::addVertex
void addVertex(const QgsPoint &pt)
Adds a new vertex to the end of the line string.
Definition: qgslinestring.cpp:1785
QgsGeometryUtils::pointsToWKT
static QString pointsToWKT(const QgsPointSequence &points, int precision, bool is3D, bool isMeasure)
Returns a WKT coordinate list.
Definition: qgsgeometryutils.cpp:1236
QgsCompoundCurve::addCurve
void addCurve(QgsCurve *c, bool extendPrevious=false)
Adds a curve to the geometry (takes ownership).
Definition: qgscompoundcurve.cpp:583
QgsLineString::filterVertices
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...
Definition: qgslinestring.cpp:2198
QgsVertexId
Utility class for identifying a unique vertex within a geometry.
Definition: qgsvertexid.h:30
QgsGeometryUtils::pointsToGML2
static QDomElement pointsToGML2(const QgsPointSequence &points, QDomDocument &doc, int precision, const QString &ns, QgsAbstractGeometry::AxisOrder axisOrder=QgsAbstractGeometry::AxisOrder::XY)
Returns a gml::coordinates DOM element.
Definition: qgsgeometryutils.cpp:1255
QgsAbstractGeometryTransformer
An abstract base class for classes which transform geometries by transforming input points to output ...
Definition: qgsgeometrytransformer.h:32
QgsLineString::deleteVertex
bool deleteVertex(QgsVertexId position) override
Deletes a vertex within the geometry.
Definition: qgslinestring.cpp:1752
QgsVertexId::ring
int ring
Ring number.
Definition: qgsvertexid.h:92
QgsLineString::geometryType
QString geometryType() const override SIP_HOLDGIL
Returns a unique string representing the geometry type.
Definition: qgslinestring.cpp:1633
QgsLineString::calculateBoundingBox
QgsRectangle calculateBoundingBox() const override
Default calculator for the minimal bounding box for the geometry.
Definition: qgslinestring.cpp:578
QgsLineString::fromWkb
bool fromWkb(QgsConstWkbPtr &wkb) override
Sets the geometry from a WKB string.
Definition: qgslinestring.cpp:560
QgsAbstractGeometry::convertTo
virtual bool convertTo(QgsWkbTypes::Type type)
Converts the geometry to a specified type.
Definition: qgsabstractgeometry.cpp:256
QgsWkbTypes::hasZ
static bool hasZ(Type type) SIP_HOLDGIL
Tests whether a WKB type contains the z-dimension.
Definition: qgswkbtypes.h:1080
QgsBox3d
A 3-dimensional box composed of x, y, z coordinates.
Definition: qgsbox3d.h:38
segment
QLineF segment(int index, QRectF rect, double radius)
Definition: qgsshapegenerator.cpp:25
QgsLineString::equals
bool equals(const QgsCurve &other) const override
Checks whether this curve exactly equals another curve.
Definition: qgslinestring.cpp:268
QgsLineString::isClosed
bool isClosed() const override SIP_HOLDGIL
Returns true if the curve is closed.
Definition: qgslinestring.cpp:419
Qgis::TransformDirection
TransformDirection
Indicates the direction (forward or inverse) of a transform.
Definition: qgis.h:1235
QgsConstWkbPtr::readHeader
QgsWkbTypes::Type readHeader() const
readHeader
Definition: qgswkbptr.cpp:54
QgsCurve::mBoundingBox
QgsRectangle mBoundingBox
Cached bounding box.
Definition: qgscurve.h:342
QgsPoint::setY
void setY(double y) SIP_HOLDGIL
Sets the point's y-coordinate.
Definition: qgspoint.h:308
QgsAbstractGeometry::boundingBoxIntersects
virtual bool boundingBoxIntersects(const QgsRectangle &rectangle) const SIP_HOLDGIL
Returns true if the bounding box of this geometry intersects with a rectangle.
Definition: qgsabstractgeometry.cpp:390
QgsLineString::reversed
QgsLineString * reversed() const override
Returns a reversed copy of the curve, where the direction of the curve has been flipped.
Definition: qgslinestring.cpp:1283
QgsGeometryUtils::wktReadBlock
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 (...
Definition: qgsgeometryutils.cpp:1351
QgsAbstractGeometry::setZMTypeFromSubGeometry
void setZMTypeFromSubGeometry(const QgsAbstractGeometry *subggeom, QgsWkbTypes::Type baseGeomType)
Updates the geometry type based on whether sub geometries contain z or m values.
Definition: qgsabstractgeometry.cpp:77
QgsLineString::numPoints
int numPoints() const override SIP_HOLDGIL
Returns the number of points in the curve.
Definition: qgslinestring.cpp:986
QgsLineString::closestSegment
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.
Definition: qgslinestring.cpp:1805
QgsLineString::points
void points(QgsPointSequence &pt) const override
Returns a list of points within the curve.
Definition: qgslinestring.cpp:1081
QgsCoordinateTransform
Class for doing transforms between two map coordinate systems.
Definition: qgscoordinatetransform.h:57
QgsLineString::removeDuplicateNodes
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...
Definition: qgslinestring.cpp:370
QgsLineString::createEmptyWithSameType
QgsLineString * createEmptyWithSameType() const override
Creates a new geometry with the same class and same WKB type as the original and transfers ownership.
Definition: qgslinestring.cpp:1540
QgsLineString::startPoint
QgsPoint startPoint() const override SIP_HOLDGIL
Returns the starting point of the curve.
Definition: qgslinestring.cpp:955
qgsfeedback.h
QgsPoint::x
double x
Definition: qgspoint.h:69
QgsRectangle::isNull
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
Definition: qgsrectangle.h:479
QgsLineString::vertexAngle
double vertexAngle(QgsVertexId vertex) const override
Returns approximate angle at a vertex.
Definition: qgslinestring.cpp:1992
QgsCompoundCurve
Compound curve geometry type.
Definition: qgscompoundcurve.h:31
QgsLineString::visitPointsByRegularDistance
void visitPointsByRegularDistance(double distance, const std::function< bool(double x, double y, double z, double m, double startSegmentX, double startSegmentY, double startSegmentZ, double startSegmentM, double endSegmentX, double endSegmentY, double endSegmentZ, double endSegmentM) > &visitPoint) const
Visits regular points along the linestring, spaced by distance.
Definition: qgslinestring.cpp:1299
QgsAbstractGeometryTransformer::transformPoint
virtual bool transformPoint(double &x, double &y, double &z, double &m)=0
Transforms the point defined by the coordinates (x, y, z) and the specified m value.
QgsLineString::dropZValue
bool dropZValue() override
Drops any z-dimensions which exist in the geometry.
Definition: qgslinestring.cpp:2106