QGIS API Documentation  3.2.0-Bonn (bc43194)
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 
27 #include <cmath>
28 #include <memory>
29 #include <QPainter>
30 #include <limits>
31 #include <QDomDocument>
32 
33 
34 /***************************************************************************
35  * This class is considered CRITICAL and any change MUST be accompanied with
36  * full unit tests.
37  * See details in QEP #17
38  ****************************************************************************/
39 
41 {
43 }
44 
45 QgsLineString::QgsLineString( const QVector<QgsPoint> &points )
46 {
47  if ( points.isEmpty() )
48  {
50  return;
51  }
52  QgsWkbTypes::Type ptType = points.at( 0 ).wkbType();
54  mX.resize( points.count() );
55  mY.resize( points.count() );
56  double *x = mX.data();
57  double *y = mY.data();
58  double *z = nullptr;
59  double *m = nullptr;
60  if ( QgsWkbTypes::hasZ( mWkbType ) )
61  {
62  mZ.resize( points.count() );
63  z = mZ.data();
64  }
65  if ( QgsWkbTypes::hasM( mWkbType ) )
66  {
67  mM.resize( points.count() );
68  m = mM.data();
69  }
70 
71  for ( const QgsPoint &pt : points )
72  {
73  *x++ = pt.x();
74  *y++ = pt.y();
75  if ( z )
76  *z++ = pt.z();
77  if ( m )
78  *m++ = pt.m();
79  }
80 }
81 
82 QgsLineString::QgsLineString( const QVector<double> &x, const QVector<double> &y, const QVector<double> &z, const QVector<double> &m )
83 {
85  int pointCount = std::min( x.size(), y.size() );
86  if ( x.size() == pointCount )
87  {
88  mX = x;
89  }
90  else
91  {
92  mX = x.mid( 0, pointCount );
93  }
94  if ( y.size() == pointCount )
95  {
96  mY = y;
97  }
98  else
99  {
100  mY = y.mid( 0, pointCount );
101  }
102  if ( !z.isEmpty() && z.count() >= pointCount )
103  {
105  if ( z.size() == pointCount )
106  {
107  mZ = z;
108  }
109  else
110  {
111  mZ = z.mid( 0, pointCount );
112  }
113  }
114  if ( !m.isEmpty() && m.count() >= pointCount )
115  {
117  if ( m.size() == pointCount )
118  {
119  mM = m;
120  }
121  else
122  {
123  mM = m.mid( 0, pointCount );
124  }
125  }
126 }
127 
129 {
131  mX.resize( 2 );
132  mX[ 0 ] = p1.x();
133  mX[ 1 ] = p2.x();
134  mY.resize( 2 );
135  mY[ 0 ] = p1.y();
136  mY[ 1 ] = p2.y();
137  if ( p1.is3D() )
138  {
140  mZ.resize( 2 );
141  mZ[ 0 ] = p1.z();
142  mZ[ 1 ] = p2.z();
143  }
144  if ( p1.isMeasure() )
145  {
147  mM.resize( 2 );
148  mM[ 0 ] = p1.m();
149  mM[ 1 ] = p2.m();
150  }
151 }
152 
153 QgsLineString::QgsLineString( const QVector<QgsPointXY> &points )
154 {
156  mX.reserve( points.size() );
157  mY.reserve( points.size() );
158  for ( const QgsPointXY &p : points )
159  {
160  mX << p.x();
161  mY << p.y();
162  }
163 }
164 
166 {
168  mX.resize( 2 );
169  mY.resize( 2 );
170  mX[0] = segment.startX();
171  mX[1] = segment.endX();
172  mY[0] = segment.startY();
173  mY[1] = segment.endY();
174 }
175 
176 bool QgsLineString::equals( const QgsCurve &other ) const
177 {
178  const QgsLineString *otherLine = qgsgeometry_cast< const QgsLineString * >( &other );
179  if ( !otherLine )
180  return false;
181 
182  if ( mWkbType != otherLine->mWkbType )
183  return false;
184 
185  if ( mX.count() != otherLine->mX.count() )
186  return false;
187 
188  for ( int i = 0; i < mX.count(); ++i )
189  {
190  if ( !qgsDoubleNear( mX.at( i ), otherLine->mX.at( i ) )
191  || !qgsDoubleNear( mY.at( i ), otherLine->mY.at( i ) ) )
192  return false;
193 
194  if ( is3D() && !qgsDoubleNear( mZ.at( i ), otherLine->mZ.at( i ) ) )
195  return false;
196 
197  if ( isMeasure() && !qgsDoubleNear( mM.at( i ), otherLine->mM.at( i ) ) )
198  return false;
199  }
200 
201  return true;
202 }
203 
205 {
206  return new QgsLineString( *this );
207 }
208 
210 {
211  mX.clear();
212  mY.clear();
213  mZ.clear();
214  mM.clear();
216  clearCache();
217 }
218 
220 {
221  return mX.isEmpty();
222 }
223 
224 QgsLineString *QgsLineString::snappedToGrid( double hSpacing, double vSpacing, double dSpacing, double mSpacing ) const
225 {
226  // prepare result
227  std::unique_ptr<QgsLineString> result { createEmptyWithSameType() };
228 
229  bool res = snapToGridPrivate( hSpacing, vSpacing, dSpacing, mSpacing, mX, mY, mZ, mM,
230  result->mX, result->mY, result->mZ, result->mM );
231  if ( res )
232  return result.release();
233  else
234  return nullptr;
235 }
236 
237 bool QgsLineString::removeDuplicateNodes( double epsilon, bool useZValues )
238 {
239  if ( mX.count() <= 2 )
240  return false; // don't create degenerate lines
241  bool result = false;
242  double prevX = mX.at( 0 );
243  double prevY = mY.at( 0 );
244  bool hasZ = is3D();
245  bool useZ = hasZ && useZValues;
246  double prevZ = useZ ? mZ.at( 0 ) : 0;
247  int i = 1;
248  int remaining = mX.count();
249  while ( i < remaining )
250  {
251  double currentX = mX.at( i );
252  double currentY = mY.at( i );
253  double currentZ = useZ ? mZ.at( i ) : 0;
254  if ( qgsDoubleNear( currentX, prevX, epsilon ) &&
255  qgsDoubleNear( currentY, prevY, epsilon ) &&
256  ( !useZ || qgsDoubleNear( currentZ, prevZ, epsilon ) ) )
257  {
258  result = true;
259  // remove point
260  mX.removeAt( i );
261  mY.removeAt( i );
262  if ( hasZ )
263  mZ.removeAt( i );
264  remaining--;
265  }
266  else
267  {
268  prevX = currentX;
269  prevY = currentY;
270  prevZ = currentZ;
271  i++;
272  }
273  }
274  return result;
275 }
276 
277 QPolygonF QgsLineString::asQPolygonF() const
278 {
279  const int nb = mX.size();
280  QPolygonF points( nb );
281 
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 )
286  {
287  *dest++ = QPointF( *x++, *y++ );
288  }
289  return points;
290 }
291 
293 {
294  if ( !wkbPtr )
295  {
296  return false;
297  }
298 
299  QgsWkbTypes::Type type = wkbPtr.readHeader();
301  {
302  return false;
303  }
304  mWkbType = type;
305  importVerticesFromWkb( wkbPtr );
306  return true;
307 }
308 
310 {
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();
315 
316  for ( double x : mX )
317  {
318  if ( x < xmin )
319  xmin = x;
320  if ( x > xmax )
321  xmax = x;
322  }
323  for ( double y : mY )
324  {
325  if ( y < ymin )
326  ymin = y;
327  if ( y > ymax )
328  ymax = y;
329  }
330  return QgsRectangle( xmin, ymin, xmax, ymax );
331 }
332 
333 /***************************************************************************
334  * This class is considered CRITICAL and any change MUST be accompanied with
335  * full unit tests.
336  * See details in QEP #17
337  ****************************************************************************/
338 
339 bool QgsLineString::fromWkt( const QString &wkt )
340 {
341  clear();
342 
343  QPair<QgsWkbTypes::Type, QString> parts = QgsGeometryUtils::wktReadBlock( wkt );
344 
345  if ( QgsWkbTypes::flatType( parts.first ) != QgsWkbTypes::LineString )
346  return false;
347  mWkbType = parts.first;
348 
349  setPoints( QgsGeometryUtils::pointsFromWKT( parts.second, is3D(), isMeasure() ) );
350  return true;
351 }
352 
353 QByteArray QgsLineString::asWkb() const
354 {
355  int binarySize = sizeof( char ) + sizeof( quint32 ) + sizeof( quint32 );
356  binarySize += numPoints() * ( 2 + is3D() + isMeasure() ) * sizeof( double );
357 
358  QByteArray wkbArray;
359  wkbArray.resize( binarySize );
360  QgsWkbPtr wkb( wkbArray );
361  wkb << static_cast<char>( QgsApplication::endian() );
362  wkb << static_cast<quint32>( wkbType() );
363  QgsPointSequence pts;
364  points( pts );
365  QgsGeometryUtils::pointsToWKB( wkb, pts, is3D(), isMeasure() );
366  return wkbArray;
367 }
368 
369 /***************************************************************************
370  * This class is considered CRITICAL and any change MUST be accompanied with
371  * full unit tests.
372  * See details in QEP #17
373  ****************************************************************************/
374 
375 QString QgsLineString::asWkt( int precision ) const
376 {
377  QString wkt = wktTypeStr() + ' ';
378  QgsPointSequence pts;
379  points( pts );
380  wkt += QgsGeometryUtils::pointsToWKT( pts, precision, is3D(), isMeasure() );
381  return wkt;
382 }
383 
384 QDomElement QgsLineString::asGml2( QDomDocument &doc, int precision, const QString &ns, const AxisOrder axisOrder ) const
385 {
386  QgsPointSequence pts;
387  points( pts );
388 
389  QDomElement elemLineString = doc.createElementNS( ns, QStringLiteral( "LineString" ) );
390 
391  if ( isEmpty() )
392  return elemLineString;
393 
394  elemLineString.appendChild( QgsGeometryUtils::pointsToGML2( pts, doc, precision, ns, axisOrder ) );
395 
396  return elemLineString;
397 }
398 
399 QDomElement QgsLineString::asGml3( QDomDocument &doc, int precision, const QString &ns, const QgsAbstractGeometry::AxisOrder axisOrder ) const
400 {
401  QgsPointSequence pts;
402  points( pts );
403 
404  QDomElement elemLineString = doc.createElementNS( ns, QStringLiteral( "LineString" ) );
405 
406  if ( isEmpty() )
407  return elemLineString;
408 
409  elemLineString.appendChild( QgsGeometryUtils::pointsToGML3( pts, doc, precision, ns, is3D(), axisOrder ) );
410  return elemLineString;
411 }
412 
413 QString QgsLineString::asJson( int precision ) const
414 {
415  QgsPointSequence pts;
416  points( pts );
417 
418  return "{\"type\": \"LineString\", \"coordinates\": " + QgsGeometryUtils::pointsToJSON( pts, precision ) + '}';
419 }
420 
421 /***************************************************************************
422  * This class is considered CRITICAL and any change MUST be accompanied with
423  * full unit tests.
424  * See details in QEP #17
425  ****************************************************************************/
426 
427 double QgsLineString::length() const
428 {
429  double length = 0;
430  int size = mX.size();
431  double dx, dy;
432  for ( int i = 1; i < size; ++i )
433  {
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 );
437  }
438  return length;
439 }
440 
442 {
443  if ( numPoints() < 1 )
444  {
445  return QgsPoint();
446  }
447  return pointN( 0 );
448 }
449 
451 {
452  if ( numPoints() < 1 )
453  {
454  return QgsPoint();
455  }
456  return pointN( numPoints() - 1 );
457 }
458 
459 /***************************************************************************
460  * This class is considered CRITICAL and any change MUST be accompanied with
461  * full unit tests.
462  * See details in QEP #17
463  ****************************************************************************/
464 
465 QgsLineString *QgsLineString::curveToLine( double tolerance, SegmentationToleranceType toleranceType ) const
466 {
467  Q_UNUSED( tolerance );
468  Q_UNUSED( toleranceType );
469  return static_cast<QgsLineString *>( clone() );
470 }
471 
473 {
474  return mX.size();
475 }
476 
478 {
479  return mX.size();
480 }
481 
483 {
484  if ( i < 0 || i >= mX.size() )
485  {
486  return QgsPoint();
487  }
488 
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();
493 
494  bool hasZ = is3D();
495  if ( hasZ )
496  {
497  z = mZ.at( i );
498  }
499  bool hasM = isMeasure();
500  if ( hasM )
501  {
502  m = mM.at( i );
503  }
504 
507  {
509  }
510  else if ( hasZ && hasM )
511  {
513  }
514  else if ( hasZ )
515  {
517  }
518  else if ( hasM )
519  {
521  }
522  return QgsPoint( t, x, y, z, m );
523 }
524 
525 /***************************************************************************
526  * This class is considered CRITICAL and any change MUST be accompanied with
527  * full unit tests.
528  * See details in QEP #17
529  ****************************************************************************/
530 
531 double QgsLineString::xAt( int index ) const
532 {
533  if ( index >= 0 && index < mX.size() )
534  return mX.at( index );
535  else
536  return 0.0;
537 }
538 
539 double QgsLineString::yAt( int index ) const
540 {
541  if ( index >= 0 && index < mY.size() )
542  return mY.at( index );
543  else
544  return 0.0;
545 }
546 
547 void QgsLineString::setXAt( int index, double x )
548 {
549  if ( index >= 0 && index < mX.size() )
550  mX[ index ] = x;
551  clearCache();
552 }
553 
554 void QgsLineString::setYAt( int index, double y )
555 {
556  if ( index >= 0 && index < mY.size() )
557  mY[ index ] = y;
558  clearCache();
559 }
560 
561 /***************************************************************************
562  * This class is considered CRITICAL and any change MUST be accompanied with
563  * full unit tests.
564  * See details in QEP #17
565  ****************************************************************************/
566 
568 {
569  pts.clear();
570  int nPoints = numPoints();
571  for ( int i = 0; i < nPoints; ++i )
572  {
573  pts.push_back( pointN( i ) );
574  }
575 }
576 
578 {
579  clearCache(); //set bounding box invalid
580 
581  if ( points.isEmpty() )
582  {
583  clear();
584  return;
585  }
586 
587  //get wkb type from first point
588  const QgsPoint &firstPt = points.at( 0 );
589  bool hasZ = firstPt.is3D();
590  bool hasM = firstPt.isMeasure();
591 
593 
594  mX.resize( points.size() );
595  mY.resize( points.size() );
596  if ( hasZ )
597  {
598  mZ.resize( points.size() );
599  }
600  else
601  {
602  mZ.clear();
603  }
604  if ( hasM )
605  {
606  mM.resize( points.size() );
607  }
608  else
609  {
610  mM.clear();
611  }
612 
613  for ( int i = 0; i < points.size(); ++i )
614  {
615  mX[i] = points.at( i ).x();
616  mY[i] = points.at( i ).y();
617  if ( hasZ )
618  {
619  double z = points.at( i ).z();
620  mZ[i] = std::isnan( z ) ? 0 : z;
621  }
622  if ( hasM )
623  {
624  double m = points.at( i ).m();
625  mM[i] = std::isnan( m ) ? 0 : m;
626  }
627  }
628 }
629 
630 /***************************************************************************
631  * This class is considered CRITICAL and any change MUST be accompanied with
632  * full unit tests.
633  * See details in QEP #17
634  ****************************************************************************/
635 
637 {
638  if ( !line )
639  {
640  return;
641  }
642 
643  if ( numPoints() < 1 )
644  {
646  }
647 
648  // do not store duplicit points
649  if ( numPoints() > 0 &&
650  line->numPoints() > 0 &&
651  endPoint() == line->startPoint() )
652  {
653  mX.pop_back();
654  mY.pop_back();
655 
656  if ( is3D() )
657  {
658  mZ.pop_back();
659  }
660  if ( isMeasure() )
661  {
662  mM.pop_back();
663  }
664  }
665 
666  mX += line->mX;
667  mY += line->mY;
668 
669  if ( is3D() )
670  {
671  if ( line->is3D() )
672  {
673  mZ += line->mZ;
674  }
675  else
676  {
677  // if append line does not have z coordinates, fill with NaN to match number of points in final line
678  mZ.insert( mZ.count(), mX.size() - mZ.size(), std::numeric_limits<double>::quiet_NaN() );
679  }
680  }
681 
682  if ( isMeasure() )
683  {
684  if ( line->isMeasure() )
685  {
686  mM += line->mM;
687  }
688  else
689  {
690  // if append line does not have m values, fill with NaN to match number of points in final line
691  mM.insert( mM.count(), mX.size() - mM.size(), std::numeric_limits<double>::quiet_NaN() );
692  }
693  }
694 
695  clearCache(); //set bounding box invalid
696 }
697 
699 {
700  QgsLineString *copy = clone();
701  std::reverse( copy->mX.begin(), copy->mX.end() );
702  std::reverse( copy->mY.begin(), copy->mY.end() );
703  if ( copy->is3D() )
704  {
705  std::reverse( copy->mZ.begin(), copy->mZ.end() );
706  }
707  if ( copy->isMeasure() )
708  {
709  std::reverse( copy->mM.begin(), copy->mM.end() );
710  }
711  return copy;
712 }
713 
714 /***************************************************************************
715  * This class is considered CRITICAL and any change MUST be accompanied with
716  * full unit tests.
717  * See details in QEP #17
718  ****************************************************************************/
719 
720 void QgsLineString::draw( QPainter &p ) const
721 {
722  p.drawPolyline( asQPolygonF() );
723 }
724 
725 void QgsLineString::addToPainterPath( QPainterPath &path ) const
726 {
727  int nPoints = numPoints();
728  if ( nPoints < 1 )
729  {
730  return;
731  }
732 
733  if ( path.isEmpty() || path.currentPosition() != QPointF( mX.at( 0 ), mY.at( 0 ) ) )
734  {
735  path.moveTo( mX.at( 0 ), mY.at( 0 ) );
736  }
737 
738  for ( int i = 1; i < nPoints; ++i )
739  {
740  path.lineTo( mX.at( i ), mY.at( i ) );
741  }
742 }
743 
744 void QgsLineString::drawAsPolygon( QPainter &p ) const
745 {
746  p.drawPolygon( asQPolygonF() );
747 }
748 
750 {
751  QgsCompoundCurve *compoundCurve = new QgsCompoundCurve();
752  compoundCurve->addCurve( clone() );
753  return compoundCurve;
754 }
755 
756 void QgsLineString::extend( double startDistance, double endDistance )
757 {
758  if ( mX.size() < 2 || mY.size() < 2 )
759  return;
760 
761  // start of line
762  if ( startDistance > 0 )
763  {
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;
769  }
770  // end of line
771  if ( endDistance > 0 )
772  {
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;
779  }
780 }
781 
783 {
784  auto result = qgis::make_unique< QgsLineString >();
785  result->mWkbType = mWkbType;
786  return result.release();
787 }
788 
790 {
791  return QStringLiteral( "LineString" );
792 }
793 
795 {
796  return 1;
797 }
798 
799 /***************************************************************************
800  * This class is considered CRITICAL and any change MUST be accompanied with
801  * full unit tests.
802  * See details in QEP #17
803  ****************************************************************************/
804 
806 {
807  double *zArray = nullptr;
808  bool hasZ = is3D();
809  int nPoints = numPoints();
810 
811  // it's possible that transformCoords will throw an exception - so we need to use
812  // a smart pointer for the dummy z values in order to ensure that they always get cleaned up
813  std::unique_ptr< double[] > dummyZ;
814  if ( !hasZ || !transformZ )
815  {
816  dummyZ.reset( new double[nPoints]() );
817  zArray = dummyZ.get();
818  }
819  else
820  {
821  zArray = mZ.data();
822  }
823  ct.transformCoords( nPoints, mX.data(), mY.data(), zArray, d );
824  clearCache();
825 }
826 
827 void QgsLineString::transform( const QTransform &t, double zTranslate, double zScale, double mTranslate, double mScale )
828 {
829  int nPoints = numPoints();
830  bool hasZ = is3D();
831  bool hasM = isMeasure();
832  for ( int i = 0; i < nPoints; ++i )
833  {
834  qreal x, y;
835  t.map( mX.at( i ), mY.at( i ), &x, &y );
836  mX[i] = x;
837  mY[i] = y;
838  if ( hasZ )
839  {
840  mZ[i] = mZ.at( i ) * zScale + zTranslate;
841  }
842  if ( hasM )
843  {
844  mM[i] = mM.at( i ) * mScale + mTranslate;
845  }
846  }
847  clearCache();
848 }
849 
850 /***************************************************************************
851  * This class is considered CRITICAL and any change MUST be accompanied with
852  * full unit tests.
853  * See details in QEP #17
854  ****************************************************************************/
855 
856 bool QgsLineString::insertVertex( QgsVertexId position, const QgsPoint &vertex )
857 {
858  if ( position.vertex < 0 || position.vertex > mX.size() )
859  {
860  return false;
861  }
862 
863  if ( mWkbType == QgsWkbTypes::Unknown || mX.isEmpty() )
864  {
866  }
867 
868  mX.insert( position.vertex, vertex.x() );
869  mY.insert( position.vertex, vertex.y() );
870  if ( is3D() )
871  {
872  mZ.insert( position.vertex, vertex.z() );
873  }
874  if ( isMeasure() )
875  {
876  mM.insert( position.vertex, vertex.m() );
877  }
878  clearCache(); //set bounding box invalid
879  return true;
880 }
881 
882 bool QgsLineString::moveVertex( QgsVertexId position, const QgsPoint &newPos )
883 {
884  if ( position.vertex < 0 || position.vertex >= mX.size() )
885  {
886  return false;
887  }
888  mX[position.vertex] = newPos.x();
889  mY[position.vertex] = newPos.y();
890  if ( is3D() && newPos.is3D() )
891  {
892  mZ[position.vertex] = newPos.z();
893  }
894  if ( isMeasure() && newPos.isMeasure() )
895  {
896  mM[position.vertex] = newPos.m();
897  }
898  clearCache(); //set bounding box invalid
899  return true;
900 }
901 
903 {
904  if ( position.vertex >= mX.size() || position.vertex < 0 )
905  {
906  return false;
907  }
908 
909  mX.remove( position.vertex );
910  mY.remove( position.vertex );
911  if ( is3D() )
912  {
913  mZ.remove( position.vertex );
914  }
915  if ( isMeasure() )
916  {
917  mM.remove( position.vertex );
918  }
919 
920  if ( numPoints() == 1 )
921  {
922  clear();
923  }
924 
925  clearCache(); //set bounding box invalid
926  return true;
927 }
928 
929 /***************************************************************************
930  * This class is considered CRITICAL and any change MUST be accompanied with
931  * full unit tests.
932  * See details in QEP #17
933  ****************************************************************************/
934 
936 {
937  if ( mWkbType == QgsWkbTypes::Unknown || mX.isEmpty() )
938  {
940  }
941 
942  mX.append( pt.x() );
943  mY.append( pt.y() );
944  if ( is3D() )
945  {
946  mZ.append( pt.z() );
947  }
948  if ( isMeasure() )
949  {
950  mM.append( pt.m() );
951  }
952  clearCache(); //set bounding box invalid
953 }
954 
955 double QgsLineString::closestSegment( const QgsPoint &pt, QgsPoint &segmentPt, QgsVertexId &vertexAfter, int *leftOf, double epsilon ) const
956 {
957  double sqrDist = std::numeric_limits<double>::max();
958  double leftOfDist = std::numeric_limits<double>::max();
959  int prevLeftOf = 0;
960  double prevLeftOfX = 0.0;
961  double prevLeftOfY = 0.0;
962  double testDist = 0;
963  double segmentPtX, segmentPtY;
964 
965  if ( leftOf )
966  *leftOf = 0;
967 
968  int size = mX.size();
969  if ( size == 0 || size == 1 )
970  {
971  vertexAfter = QgsVertexId( 0, 0, 0 );
972  return -1;
973  }
974  for ( int i = 1; i < size; ++i )
975  {
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 );
980  testDist = QgsGeometryUtils::sqrDistToLine( pt.x(), pt.y(), prevX, prevY, currentX, currentY, segmentPtX, segmentPtY, epsilon );
981  if ( testDist < sqrDist )
982  {
983  sqrDist = testDist;
984  segmentPt.setX( segmentPtX );
985  segmentPt.setY( segmentPtY );
986  vertexAfter.part = 0;
987  vertexAfter.ring = 0;
988  vertexAfter.vertex = i;
989  }
990  if ( leftOf && qgsDoubleNear( testDist, sqrDist ) )
991  {
992  int left = QgsGeometryUtils::leftOfLine( pt.x(), pt.y(), prevX, prevY, currentX, currentY );
993  // if left equals 0, the test could not be performed (e.g. point in line with segment or on segment)
994  // so don't set leftOf in this case, and hope that there's another segment that's the same distance
995  // where we can perform the check
996  if ( left != 0 )
997  {
998  if ( qgsDoubleNear( testDist, leftOfDist ) && left != prevLeftOf && prevLeftOf != 0 )
999  {
1000  // we have two possible segments each with equal distance to point, but they disagree
1001  // on whether or not the point is to the left of them.
1002  // so we test the segments themselves and flip the result.
1003  // see https://stackoverflow.com/questions/10583212/elegant-left-of-test-for-polyline
1004  *leftOf = -QgsGeometryUtils::leftOfLine( currentX, currentY, prevLeftOfX, prevLeftOfY, prevX, prevY );
1005  }
1006  else
1007  {
1008  *leftOf = left;
1009  }
1010  prevLeftOf = *leftOf;
1011  leftOfDist = testDist;
1012  prevLeftOfX = prevX;
1013  prevLeftOfY = prevY;
1014  }
1015  else if ( testDist < leftOfDist )
1016  {
1017  *leftOf = left;
1018  leftOfDist = testDist;
1019  prevLeftOf = 0;
1020  }
1021  }
1022  }
1023  return sqrDist;
1024 }
1025 
1026 /***************************************************************************
1027  * This class is considered CRITICAL and any change MUST be accompanied with
1028  * full unit tests.
1029  * See details in QEP #17
1030  ****************************************************************************/
1031 
1032 bool QgsLineString::pointAt( int node, QgsPoint &point, QgsVertexId::VertexType &type ) const
1033 {
1034  if ( node < 0 || node >= numPoints() )
1035  {
1036  return false;
1037  }
1038  point = pointN( node );
1040  return true;
1041 }
1042 
1044 {
1045  if ( mX.isEmpty() )
1046  return QgsPoint();
1047 
1048  int numPoints = mX.count();
1049  if ( numPoints == 1 )
1050  return QgsPoint( mX.at( 0 ), mY.at( 0 ) );
1051 
1052  double totalLineLength = 0.0;
1053  double prevX = mX.at( 0 );
1054  double prevY = mY.at( 0 );
1055  double sumX = 0.0;
1056  double sumY = 0.0;
1057 
1058  for ( int i = 1; i < numPoints ; ++i )
1059  {
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 ) );
1064  if ( qgsDoubleNear( segmentLength, 0.0 ) )
1065  continue;
1066 
1067  totalLineLength += segmentLength;
1068  sumX += segmentLength * 0.5 * ( currentX + prevX );
1069  sumY += segmentLength * 0.5 * ( currentY + prevY );
1070  prevX = currentX;
1071  prevY = currentY;
1072  }
1073 
1074  if ( qgsDoubleNear( totalLineLength, 0.0 ) )
1075  return QgsPoint( mX.at( 0 ), mY.at( 0 ) );
1076  else
1077  return QgsPoint( sumX / totalLineLength, sumY / totalLineLength );
1078 
1079 }
1080 
1081 /***************************************************************************
1082  * This class is considered CRITICAL and any change MUST be accompanied with
1083  * full unit tests.
1084  * See details in QEP #17
1085  ****************************************************************************/
1086 
1087 void QgsLineString::sumUpArea( double &sum ) const
1088 {
1089  int maxIndex = numPoints() - 1;
1090 
1091  for ( int i = 0; i < maxIndex; ++i )
1092  {
1093  sum += 0.5 * ( mX.at( i ) * mY.at( i + 1 ) - mY.at( i ) * mX.at( i + 1 ) );
1094  }
1095 }
1096 
1097 void QgsLineString::importVerticesFromWkb( const QgsConstWkbPtr &wkb )
1098 {
1099  bool hasZ = is3D();
1100  bool hasM = isMeasure();
1101  int nVertices = 0;
1102  wkb >> nVertices;
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 )
1112  {
1113  wkb >> *x++;
1114  wkb >> *y++;
1115  if ( hasZ )
1116  {
1117  wkb >> *z++;
1118  }
1119  if ( hasM )
1120  {
1121  wkb >> *m++;
1122  }
1123  }
1124  clearCache(); //set bounding box invalid
1125 }
1126 
1127 /***************************************************************************
1128  * This class is considered CRITICAL and any change MUST be accompanied with
1129  * full unit tests.
1130  * See details in QEP #17
1131  ****************************************************************************/
1132 
1134 {
1135  if ( numPoints() < 1 || isClosed() )
1136  {
1137  return;
1138  }
1139  addVertex( startPoint() );
1140 }
1141 
1143 {
1144  if ( mX.count() < 2 )
1145  {
1146  //undefined
1147  return 0.0;
1148  }
1149 
1150  if ( vertex.vertex == 0 || vertex.vertex >= ( numPoints() - 1 ) )
1151  {
1152  if ( isClosed() )
1153  {
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 );
1160  return QgsGeometryUtils::averageAngle( previousX, previousY, currentX, currentY, afterX, afterY );
1161  }
1162  else if ( vertex.vertex == 0 )
1163  {
1164  return QgsGeometryUtils::lineAngle( mX.at( 0 ), mY.at( 0 ), mX.at( 1 ), mY.at( 1 ) );
1165  }
1166  else
1167  {
1168  int a = numPoints() - 2;
1169  int b = numPoints() - 1;
1170  return QgsGeometryUtils::lineAngle( mX.at( a ), mY.at( a ), mX.at( b ), mY.at( b ) );
1171  }
1172  }
1173  else
1174  {
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 );
1181  return QgsGeometryUtils::averageAngle( previousX, previousY, currentX, currentY, afterX, afterY );
1182  }
1183 }
1184 
1185 double QgsLineString::segmentLength( QgsVertexId startVertex ) const
1186 {
1187  if ( startVertex.vertex < 0 || startVertex.vertex >= mX.count() - 1 )
1188  return 0.0;
1189 
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 );
1193 }
1194 
1195 /***************************************************************************
1196  * This class is considered CRITICAL and any change MUST be accompanied with
1197  * full unit tests.
1198  * See details in QEP #17
1199  ****************************************************************************/
1200 
1201 bool QgsLineString::addZValue( double zValue )
1202 {
1203  if ( QgsWkbTypes::hasZ( mWkbType ) )
1204  return false;
1205 
1206  clearCache();
1207  if ( mWkbType == QgsWkbTypes::Unknown )
1208  {
1210  return true;
1211  }
1212 
1214 
1215  mZ.clear();
1216  int nPoints = numPoints();
1217  mZ.reserve( nPoints );
1218  for ( int i = 0; i < nPoints; ++i )
1219  {
1220  mZ << zValue;
1221  }
1222  return true;
1223 }
1224 
1225 bool QgsLineString::addMValue( double mValue )
1226 {
1227  if ( QgsWkbTypes::hasM( mWkbType ) )
1228  return false;
1229 
1230  clearCache();
1231  if ( mWkbType == QgsWkbTypes::Unknown )
1232  {
1234  return true;
1235  }
1236 
1238  {
1240  }
1241  else
1242  {
1244  }
1245 
1246  mM.clear();
1247  int nPoints = numPoints();
1248  mM.reserve( nPoints );
1249  for ( int i = 0; i < nPoints; ++i )
1250  {
1251  mM << mValue;
1252  }
1253  return true;
1254 }
1255 
1257 {
1258  if ( !is3D() )
1259  return false;
1260 
1261  clearCache();
1263  mZ.clear();
1264  return true;
1265 }
1266 
1268 {
1269  if ( !isMeasure() )
1270  return false;
1271 
1272  clearCache();
1274  mM.clear();
1275  return true;
1276 }
1277 
1279 {
1280  std::swap( mX, mY );
1281  clearCache();
1282 }
1283 
1285 {
1286  if ( type == mWkbType )
1287  return true;
1288 
1289  clearCache();
1290  if ( type == QgsWkbTypes::LineString25D )
1291  {
1292  //special handling required for conversion to LineString25D
1293  dropMValue();
1294  addZValue( std::numeric_limits<double>::quiet_NaN() );
1296  return true;
1297  }
1298  else
1299  {
1300  return QgsCurve::convertTo( type );
1301  }
1302 }
1303 
1304 void QgsLineString::filterVertices( const std::function<bool ( const QgsPoint & )> &filter )
1305 {
1306  bool hasZ = is3D();
1307  bool hasM = isMeasure();
1308  int size = mX.size();
1309 
1310  double *srcX = mX.data();
1311  double *srcY = mY.data();
1312  double *srcM = hasM ? mM.data() : nullptr;
1313  double *srcZ = hasZ ? mZ.data() : nullptr;
1314 
1315  double *destX = srcX;
1316  double *destY = srcY;
1317  double *destM = srcM;
1318  double *destZ = srcZ;
1319 
1320  int filteredPoints = 0;
1321  for ( int i = 0; i < size; ++i )
1322  {
1323  double x = *srcX++;
1324  double y = *srcY++;
1325  double z = hasZ ? *srcZ++ : std::numeric_limits<double>::quiet_NaN();
1326  double m = hasM ? *srcM++ : std::numeric_limits<double>::quiet_NaN();
1327 
1328  if ( filter( QgsPoint( x, y, z, m ) ) )
1329  {
1330  filteredPoints++;
1331  *destX++ = x;
1332  *destY++ = y;
1333  if ( hasM )
1334  *destM++ = m;
1335  if ( hasZ )
1336  *destZ++ = z;
1337  }
1338  }
1339 
1340  mX.resize( filteredPoints );
1341  mY.resize( filteredPoints );
1342  if ( hasZ )
1343  mZ.resize( filteredPoints );
1344  if ( hasM )
1345  mM.resize( filteredPoints );
1346 
1347  clearCache();
1348 }
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.
Definition: qgsrectangle.h:40
bool isEmpty() const override
Returns true if the geometry is empty.
double y
Definition: qgspoint.h:42
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.
Definition: qgspointxy.h:43
double endY() const
Returns the segment&#39;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)
Definition: qgis.h:251
TransformDirection
Enum used to indicate the direction (forward or inverse) of the transform.
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.
Definition: qgscurve.cpp:217
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.
Definition: qgswkbtypes.h:768
static Type dropM(Type type)
Drops the m dimension (if present) for a WKB type and returns the new type.
Definition: qgswkbtypes.h:938
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.
Definition: qgswkbtypes.h:67
double startX() const
Returns the segment&#39;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.
Definition: qgswkbtypes.h:889
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.
Definition: qgswkbtypes.h:864
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.
Definition: qgscurve.h:35
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).
void transformCoords(int numPoint, double *x, double *y, double *z, TransformDirection direction=ForwardTransform) const SIP_THROW(QgsCsException)
Transform an array of coordinates to the destination CRS.
QgsWkbTypes::Type wkbType() const
Returns the WKB type of the geometry.
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:37
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&#39;s x-coordinate.
Definition: qgspoint.h:213
virtual bool isClosed() const
Returns true if the curve is closed.
Definition: qgscurve.cpp:39
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:238
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&#39;s y-coordinate.
Definition: qgspoint.h:224
QVector< QgsPoint > QgsPointSequence
double endX() const
Returns the segment&#39;s end x-coordinate.
static Type dropZ(Type type)
Drops the z dimension (if present) for a WKB type and returns the new type.
Definition: qgswkbtypes.h:920
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.
Definition: qgslinestring.h:43
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.
Class for doing transforms between two map coordinate systems.
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.
Definition: qgswkbtypes.h:526
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.
double z
Definition: qgspoint.h:43
static bool hasM(Type type)
Tests whether a WKB type contains m values.
Definition: qgswkbtypes.h:818
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&#39;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.
Definition: qgswkbtypes.h:427
QgsWkbTypes::Type readHeader() const
readHeader
Definition: qgswkbptr.cpp:53
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 &#39;thepoint&#39; is left or right of the line from &#39;p1&#39; to &#39;p2&#39;. Negativ values mean left a...
Definition: MathUtils.cpp:292
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.
double m
Definition: qgspoint.h:44
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...
double x
Definition: qgspoint.h:41