QGIS API Documentation  2.18.21-Las Palmas (9fba24a)
qgslinestringv2.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgslinestringv2.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 "qgslinestringv2.h"
19 #include "qgsapplication.h"
20 #include "qgscompoundcurvev2.h"
21 #include "qgscoordinatetransform.h"
22 #include "qgsgeometryutils.h"
23 #include "qgsmaptopixel.h"
24 #include "qgswkbptr.h"
25 
26 #include <QPainter>
27 #include <limits>
28 #include <QDomDocument>
29 #include <QtCore/qmath.h>
30 
31 
32 /***************************************************************************
33  * This class is considered CRITICAL and any change MUST be accompanied with
34  * full unit tests.
35  * See details in QEP #17
36  ****************************************************************************/
37 
39 {
41 }
42 
44 {}
45 
46 bool QgsLineStringV2::operator==( const QgsCurveV2& other ) const
47 {
48  const QgsLineStringV2* otherLine = dynamic_cast< const QgsLineStringV2* >( &other );
49  if ( !otherLine )
50  return false;
51 
52  if ( mWkbType != otherLine->mWkbType )
53  return false;
54 
55  if ( mX.count() != otherLine->mX.count() )
56  return false;
57 
58  for ( int i = 0; i < mX.count(); ++i )
59  {
60  if ( !qgsDoubleNear( mX.at( i ), otherLine->mX.at( i ) )
61  || !qgsDoubleNear( mY.at( i ), otherLine->mY.at( i ) ) )
62  return false;
63 
64  if ( is3D() && !qgsDoubleNear( mZ.at( i ), otherLine->mZ.at( i ) ) )
65  return false;
66 
67  if ( isMeasure() && !qgsDoubleNear( mM.at( i ), otherLine->mM.at( i ) ) )
68  return false;
69  }
70 
71  return true;
72 }
73 
74 bool QgsLineStringV2::operator!=( const QgsCurveV2& other ) const
75 {
76  return !operator==( other );
77 }
78 
80 {
81  return new QgsLineStringV2( *this );
82 }
83 
85 {
86  mX.clear();
87  mY.clear();
88  mZ.clear();
89  mM.clear();
91  clearCache();
92 }
93 
95 {
96  if ( !wkbPtr )
97  {
98  return false;
99  }
100 
101  QgsWKBTypes::Type type = wkbPtr.readHeader();
103  {
104  return false;
105  }
106  mWkbType = type;
107  importVerticesFromWkb( wkbPtr );
108  return true;
109 }
110 
111 void QgsLineStringV2::fromWkbPoints( QgsWKBTypes::Type type, const QgsConstWkbPtr& wkb )
112 {
113  mWkbType = type;
114  importVerticesFromWkb( wkb );
115 }
116 
118 {
119  double xmin = std::numeric_limits<double>::max();
120  double ymin = std::numeric_limits<double>::max();
121  double xmax = -std::numeric_limits<double>::max();
122  double ymax = -std::numeric_limits<double>::max();
123 
124  Q_FOREACH ( double x, mX )
125  {
126  if ( x < xmin )
127  xmin = x;
128  if ( x > xmax )
129  xmax = x;
130  }
131  Q_FOREACH ( double y, mY )
132  {
133  if ( y < ymin )
134  ymin = y;
135  if ( y > ymax )
136  ymax = y;
137  }
138  return QgsRectangle( xmin, ymin, xmax, ymax );
139 }
140 
141 /***************************************************************************
142  * This class is considered CRITICAL and any change MUST be accompanied with
143  * full unit tests.
144  * See details in QEP #17
145  ****************************************************************************/
146 
148 {
149  clear();
150 
152 
153  if ( QgsWKBTypes::flatType( parts.first ) != QgsWKBTypes::LineString )
154  return false;
155  mWkbType = parts.first;
156 
157  setPoints( QgsGeometryUtils::pointsFromWKT( parts.second, is3D(), isMeasure() ) );
158  return true;
159 }
160 
162 {
163  int size = sizeof( char ) + sizeof( quint32 ) + sizeof( quint32 );
164  size += numPoints() * ( 2 + is3D() + isMeasure() ) * sizeof( double );
165  return size;
166 }
167 
168 unsigned char* QgsLineStringV2::asWkb( int& binarySize ) const
169 {
170  binarySize = wkbSize();
171  unsigned char* geomPtr = new unsigned char[binarySize];
172  QgsWkbPtr wkb( geomPtr, binarySize );
173  wkb << static_cast<char>( QgsApplication::endian() );
174  wkb << static_cast<quint32>( wkbType() );
175  QgsPointSequenceV2 pts;
176  points( pts );
177  QgsGeometryUtils::pointsToWKB( wkb, pts, is3D(), isMeasure() );
178  return geomPtr;
179 }
180 
181 /***************************************************************************
182  * This class is considered CRITICAL and any change MUST be accompanied with
183  * full unit tests.
184  * See details in QEP #17
185  ****************************************************************************/
186 
187 QString QgsLineStringV2::asWkt( int precision ) const
188 {
189  QString wkt = wktTypeStr() + ' ';
190  QgsPointSequenceV2 pts;
191  points( pts );
192  wkt += QgsGeometryUtils::pointsToWKT( pts, precision, is3D(), isMeasure() );
193  return wkt;
194 }
195 
196 QDomElement QgsLineStringV2::asGML2( QDomDocument& doc, int precision, const QString& ns ) const
197 {
198  QgsPointSequenceV2 pts;
199  points( pts );
200 
201  QDomElement elemLineString = doc.createElementNS( ns, "LineString" );
202  elemLineString.appendChild( QgsGeometryUtils::pointsToGML2( pts, doc, precision, ns ) );
203 
204  return elemLineString;
205 }
206 
207 QDomElement QgsLineStringV2::asGML3( QDomDocument& doc, int precision, const QString& ns ) const
208 {
209  QgsPointSequenceV2 pts;
210  points( pts );
211 
212  QDomElement elemLineString = doc.createElementNS( ns, "LineString" );
213  elemLineString.appendChild( QgsGeometryUtils::pointsToGML3( pts, doc, precision, ns, is3D() ) );
214  return elemLineString;
215 }
216 
217 QString QgsLineStringV2::asJSON( int precision ) const
218 {
219  QgsPointSequenceV2 pts;
220  points( pts );
221 
222  return "{\"type\": \"LineString\", \"coordinates\": " + QgsGeometryUtils::pointsToJSON( pts, precision ) + '}';
223 }
224 
225 /***************************************************************************
226  * This class is considered CRITICAL and any change MUST be accompanied with
227  * full unit tests.
228  * See details in QEP #17
229  ****************************************************************************/
230 
232 {
233  double length = 0;
234  int size = mX.size();
235  double dx, dy;
236  for ( int i = 1; i < size; ++i )
237  {
238  dx = mX.at( i ) - mX.at( i - 1 );
239  dy = mY.at( i ) - mY.at( i - 1 );
240  length += sqrt( dx * dx + dy * dy );
241  }
242  return length;
243 }
244 
246 {
247  if ( numPoints() < 1 )
248  {
249  return QgsPointV2();
250  }
251  return pointN( 0 );
252 }
253 
255 {
256  if ( numPoints() < 1 )
257  {
258  return QgsPointV2();
259  }
260  return pointN( numPoints() - 1 );
261 }
262 
263 /***************************************************************************
264  * This class is considered CRITICAL and any change MUST be accompanied with
265  * full unit tests.
266  * See details in QEP #17
267  ****************************************************************************/
268 
270 {
271  Q_UNUSED( tolerance );
272  Q_UNUSED( toleranceType );
273  return static_cast<QgsLineStringV2*>( clone() );
274 }
275 
277 {
278  return mX.size();
279 }
280 
282 {
283  if ( i < 0 || i >= mX.size() )
284  {
285  return QgsPointV2();
286  }
287 
288  double x = mX.at( i );
289  double y = mY.at( i );
290  double z = 0;
291  double m = 0;
292 
293  bool hasZ = is3D();
294  if ( hasZ )
295  {
296  z = mZ.at( i );
297  }
298  bool hasM = isMeasure();
299  if ( hasM )
300  {
301  m = mM.at( i );
302  }
303 
306  {
308  }
309  else if ( hasZ && hasM )
310  {
312  }
313  else if ( hasZ )
314  {
316  }
317  else if ( hasM )
318  {
320  }
321  return QgsPointV2( t, x, y, z, m );
322 }
323 
324 /***************************************************************************
325  * This class is considered CRITICAL and any change MUST be accompanied with
326  * full unit tests.
327  * See details in QEP #17
328  ****************************************************************************/
329 
330 double QgsLineStringV2::xAt( int index ) const
331 {
332  if ( index >= 0 && index < mX.size() )
333  return mX.at( index );
334  else
335  return 0.0;
336 }
337 
338 double QgsLineStringV2::yAt( int index ) const
339 {
340  if ( index >= 0 && index < mY.size() )
341  return mY.at( index );
342  else
343  return 0.0;
344 }
345 
346 double QgsLineStringV2::zAt( int index ) const
347 {
348  if ( index >= 0 && index < mZ.size() )
349  return mZ.at( index );
350  else
351  return 0.0;
352 }
353 
354 double QgsLineStringV2::mAt( int index ) const
355 {
356  if ( index >= 0 && index < mM.size() )
357  return mM.at( index );
358  else
359  return 0.0;
360 }
361 
362 void QgsLineStringV2::setXAt( int index, double x )
363 {
364  if ( index >= 0 && index < mX.size() )
365  mX[ index ] = x;
366  clearCache();
367 }
368 
369 void QgsLineStringV2::setYAt( int index, double y )
370 {
371  if ( index >= 0 && index < mY.size() )
372  mY[ index ] = y;
373  clearCache();
374 }
375 
376 void QgsLineStringV2::setZAt( int index, double z )
377 {
378  if ( index >= 0 && index < mZ.size() )
379  mZ[ index ] = z;
380 }
381 
382 void QgsLineStringV2::setMAt( int index, double m )
383 {
384  if ( index >= 0 && index < mM.size() )
385  mM[ index ] = m;
386 }
387 
388 /***************************************************************************
389  * This class is considered CRITICAL and any change MUST be accompanied with
390  * full unit tests.
391  * See details in QEP #17
392  ****************************************************************************/
393 
395 {
396  pts.clear();
397  int nPoints = numPoints();
398  for ( int i = 0; i < nPoints; ++i )
399  {
400  pts.push_back( pointN( i ) );
401  }
402 }
403 
405 {
406  clearCache(); //set bounding box invalid
407 
408  if ( points.isEmpty() )
409  {
410  clear();
411  return;
412  }
413 
414  //get wkb type from first point
415  const QgsPointV2& firstPt = points.at( 0 );
416  bool hasZ = firstPt.is3D();
417  bool hasM = firstPt.isMeasure();
418 
420 
421  mX.resize( points.size() );
422  mY.resize( points.size() );
423  if ( hasZ )
424  {
425  mZ.resize( points.size() );
426  }
427  else
428  {
429  mZ.clear();
430  }
431  if ( hasM )
432  {
433  mM.resize( points.size() );
434  }
435  else
436  {
437  mM.clear();
438  }
439 
440  for ( int i = 0; i < points.size(); ++i )
441  {
442  mX[i] = points.at( i ).x();
443  mY[i] = points.at( i ).y();
444  if ( hasZ )
445  {
446  mZ[i] = points.at( i ).z();
447  }
448  if ( hasM )
449  {
450  mM[i] = points.at( i ).m();
451  }
452  }
453 }
454 
455 /***************************************************************************
456  * This class is considered CRITICAL and any change MUST be accompanied with
457  * full unit tests.
458  * See details in QEP #17
459  ****************************************************************************/
460 
462 {
463  if ( !line )
464  {
465  return;
466  }
467 
468  if ( numPoints() < 1 )
469  {
471  }
472 
473  // do not store duplicit points
474  if ( numPoints() > 0 &&
475  line->numPoints() > 0 &&
476  endPoint() == line->startPoint() )
477  {
478  mX.pop_back();
479  mY.pop_back();
480 
481  if ( is3D() )
482  {
483  mZ.pop_back();
484  }
485  if ( isMeasure() )
486  {
487  mM.pop_back();
488  }
489  }
490 
491  mX += line->mX;
492  mY += line->mY;
493 
494  if ( is3D() )
495  {
496  if ( line->is3D() )
497  {
498  mZ += line->mZ;
499  }
500  else
501  {
502  // if append line does not have z coordinates, fill with 0 to match number of points in final line
503  mZ.insert( mZ.count(), mX.size() - mZ.size(), 0 );
504  }
505  }
506 
507  if ( isMeasure() )
508  {
509  if ( line->isMeasure() )
510  {
511  mM += line->mM;
512  }
513  else
514  {
515  // if append line does not have m values, fill with 0 to match number of points in final line
516  mM.insert( mM.count(), mX.size() - mM.size(), 0 );
517  }
518  }
519 
520  clearCache(); //set bounding box invalid
521 }
522 
524 {
525  QgsLineStringV2* copy = clone();
526  std::reverse( copy->mX.begin(), copy->mX.end() );
527  std::reverse( copy->mY.begin(), copy->mY.end() );
528  if ( copy->is3D() )
529  {
530  std::reverse( copy->mZ.begin(), copy->mZ.end() );
531  }
532  if ( copy->isMeasure() )
533  {
534  std::reverse( copy->mM.begin(), copy->mM.end() );
535  }
536  return copy;
537 }
538 
539 /***************************************************************************
540  * This class is considered CRITICAL and any change MUST be accompanied with
541  * full unit tests.
542  * See details in QEP #17
543  ****************************************************************************/
544 
546 {
547  p.drawPolyline( asQPolygonF() );
548 }
549 
551 {
552  int nPoints = numPoints();
553  if ( nPoints < 1 )
554  {
555  return;
556  }
557 
558  if ( path.isEmpty() || path.currentPosition() != QPointF( mX.at( 0 ), mY.at( 0 ) ) )
559  {
560  path.moveTo( mX.at( 0 ), mY.at( 0 ) );
561  }
562 
563  for ( int i = 1; i < nPoints; ++i )
564  {
565  path.lineTo( mX.at( i ), mY.at( i ) );
566  }
567 }
568 
570 {
571  p.drawPolygon( asQPolygonF() );
572 }
573 
575 {
577  for ( int i = 0; i < mX.count(); ++i )
578  {
579  points << QPointF( mX.at( i ), mY.at( i ) );
580  }
581  return points;
582 }
583 
585 {
586  QgsCompoundCurveV2* compoundCurve = new QgsCompoundCurveV2();
587  compoundCurve->addCurve( clone() );
588  return compoundCurve;
589 }
590 
591 /***************************************************************************
592  * This class is considered CRITICAL and any change MUST be accompanied with
593  * full unit tests.
594  * See details in QEP #17
595  ****************************************************************************/
596 
598 {
599  double* zArray = mZ.data();
600 
601  bool hasZ = is3D();
602  int nPoints = numPoints();
603  bool useDummyZ = !hasZ || !transformZ;
604  if ( useDummyZ )
605  {
606  zArray = new double[nPoints];
607  for ( int i = 0; i < nPoints; ++i )
608  {
609  zArray[i] = 0;
610  }
611  }
612  ct.transformCoords( nPoints, mX.data(), mY.data(), zArray, d );
613  if ( useDummyZ )
614  {
615  delete[] zArray;
616  }
617  clearCache();
618 }
619 
621 {
622  int nPoints = numPoints();
623  for ( int i = 0; i < nPoints; ++i )
624  {
625  qreal x, y;
626  t.map( mX.at( i ), mY.at( i ), &x, &y );
627  mX[i] = x;
628  mY[i] = y;
629  }
630  clearCache();
631 }
632 
633 /***************************************************************************
634  * This class is considered CRITICAL and any change MUST be accompanied with
635  * full unit tests.
636  * See details in QEP #17
637  ****************************************************************************/
638 
639 bool QgsLineStringV2::insertVertex( QgsVertexId position, const QgsPointV2& vertex )
640 {
641  if ( position.vertex < 0 || position.vertex > mX.size() )
642  {
643  return false;
644  }
645 
646  if ( mWkbType == QgsWKBTypes::Unknown || mX.isEmpty() )
647  {
649  }
650 
651  mX.insert( position.vertex, vertex.x() );
652  mY.insert( position.vertex, vertex.y() );
653  if ( is3D() )
654  {
655  mZ.insert( position.vertex, vertex.z() );
656  }
657  if ( isMeasure() )
658  {
659  mM.insert( position.vertex, vertex.m() );
660  }
661  clearCache(); //set bounding box invalid
662  return true;
663 }
664 
665 bool QgsLineStringV2::moveVertex( QgsVertexId position, const QgsPointV2& newPos )
666 {
667  if ( position.vertex < 0 || position.vertex >= mX.size() )
668  {
669  return false;
670  }
671  mX[position.vertex] = newPos.x();
672  mY[position.vertex] = newPos.y();
673  if ( is3D() && newPos.is3D() )
674  {
675  mZ[position.vertex] = newPos.z();
676  }
677  if ( isMeasure() && newPos.isMeasure() )
678  {
679  mM[position.vertex] = newPos.m();
680  }
681  clearCache(); //set bounding box invalid
682  return true;
683 }
684 
686 {
687  if ( position.vertex >= mX.size() || position.vertex < 0 )
688  {
689  return false;
690  }
691 
692  mX.remove( position.vertex );
693  mY.remove( position.vertex );
694  if ( is3D() )
695  {
696  mZ.remove( position.vertex );
697  }
698  if ( isMeasure() )
699  {
700  mM.remove( position.vertex );
701  }
702 
703  if ( numPoints() == 1 )
704  {
705  clear();
706  }
707 
708  clearCache(); //set bounding box invalid
709  return true;
710 }
711 
712 /***************************************************************************
713  * This class is considered CRITICAL and any change MUST be accompanied with
714  * full unit tests.
715  * See details in QEP #17
716  ****************************************************************************/
717 
719 {
720  if ( mWkbType == QgsWKBTypes::Unknown || mX.isEmpty() )
721  {
723  }
724 
725  mX.append( pt.x() );
726  mY.append( pt.y() );
727  if ( is3D() )
728  {
729  mZ.append( pt.z() );
730  }
731  if ( isMeasure() )
732  {
733  mM.append( pt.m() );
734  }
735  clearCache(); //set bounding box invalid
736 }
737 
738 double QgsLineStringV2::closestSegment( const QgsPointV2& pt, QgsPointV2& segmentPt, QgsVertexId& vertexAfter, bool* leftOf, double epsilon ) const
739 {
740  double sqrDist = std::numeric_limits<double>::max();
741  double testDist = 0;
742  double segmentPtX, segmentPtY;
743 
744  int size = mX.size();
745  if ( size == 0 || size == 1 )
746  {
747  vertexAfter = QgsVertexId( 0, 0, 0 );
748  return -1;
749  }
750  for ( int i = 1; i < size; ++i )
751  {
752  double prevX = mX.at( i - 1 );
753  double prevY = mY.at( i - 1 );
754  double currentX = mX.at( i );
755  double currentY = mY.at( i );
756  testDist = QgsGeometryUtils::sqrDistToLine( pt.x(), pt.y(), prevX, prevY, currentX, currentY, segmentPtX, segmentPtY, epsilon );
757  if ( testDist < sqrDist )
758  {
759  sqrDist = testDist;
760  segmentPt.setX( segmentPtX );
761  segmentPt.setY( segmentPtY );
762  if ( leftOf )
763  {
764  *leftOf = ( QgsGeometryUtils::leftOfLine( pt.x(), pt.y(), prevX, prevY, currentX, currentY ) < 0 );
765  }
766  vertexAfter.part = 0;
767  vertexAfter.ring = 0;
768  vertexAfter.vertex = i;
769  }
770  }
771  return sqrDist;
772 }
773 
774 /***************************************************************************
775  * This class is considered CRITICAL and any change MUST be accompanied with
776  * full unit tests.
777  * See details in QEP #17
778  ****************************************************************************/
779 
780 bool QgsLineStringV2::pointAt( int node, QgsPointV2& point, QgsVertexId::VertexType& type ) const
781 {
782  if ( node < 0 || node >= numPoints() )
783  {
784  return false;
785  }
786  point = pointN( node );
788  return true;
789 }
790 
792 {
793  if ( mX.isEmpty() )
794  return QgsPointV2();
795 
796  int numPoints = mX.count();
797  if ( numPoints == 1 )
798  return QgsPointV2( mX.at( 0 ), mY.at( 0 ) );
799 
800  double totalLineLength = 0.0;
801  double prevX = mX.at( 0 );
802  double prevY = mY.at( 0 );
803  double sumX = 0.0;
804  double sumY = 0.0;
805 
806  for ( int i = 1; i < numPoints ; ++i )
807  {
808  double currentX = mX.at( i );
809  double currentY = mY.at( i );
810  double segmentLength = sqrt( qPow( currentX - prevX, 2.0 ) +
811  qPow( currentY - prevY, 2.0 ) );
812  if ( qgsDoubleNear( segmentLength, 0.0 ) )
813  continue;
814 
815  totalLineLength += segmentLength;
816  sumX += segmentLength * 0.5 * ( currentX + prevX );
817  sumY += segmentLength * 0.5 * ( currentY + prevY );
818  prevX = currentX;
819  prevY = currentY;
820  }
821 
822  if ( qgsDoubleNear( totalLineLength, 0.0 ) )
823  return QgsPointV2( mX.at( 0 ), mY.at( 0 ) );
824  else
825  return QgsPointV2( sumX / totalLineLength, sumY / totalLineLength );
826 
827 }
828 
829 /***************************************************************************
830  * This class is considered CRITICAL and any change MUST be accompanied with
831  * full unit tests.
832  * See details in QEP #17
833  ****************************************************************************/
834 
835 void QgsLineStringV2::sumUpArea( double& sum ) const
836 {
837  int maxIndex = numPoints() - 1;
838  for ( int i = 0; i < maxIndex; ++i )
839  {
840  sum += 0.5 * ( mX.at( i ) * mY.at( i + 1 ) - mY.at( i ) * mX.at( i + 1 ) );
841  }
842 }
843 
844 void QgsLineStringV2::importVerticesFromWkb( const QgsConstWkbPtr& wkb )
845 {
846  bool hasZ = is3D();
847  bool hasM = isMeasure();
848  int nVertices = 0;
849  wkb >> nVertices;
850  mX.resize( nVertices );
851  mY.resize( nVertices );
852  hasZ ? mZ.resize( nVertices ) : mZ.clear();
853  hasM ? mM.resize( nVertices ) : mM.clear();
854  for ( int i = 0; i < nVertices; ++i )
855  {
856  wkb >> mX[i];
857  wkb >> mY[i];
858  if ( hasZ )
859  {
860  wkb >> mZ[i];
861  }
862  if ( hasM )
863  {
864  wkb >> mM[i];
865  }
866  }
867  clearCache(); //set bounding box invalid
868 }
869 
870 /***************************************************************************
871  * This class is considered CRITICAL and any change MUST be accompanied with
872  * full unit tests.
873  * See details in QEP #17
874  ****************************************************************************/
875 
877 {
878  if ( numPoints() < 1 || isClosed() )
879  {
880  return;
881  }
882  addVertex( startPoint() );
883 }
884 
886 {
887  if ( mX.count() < 2 )
888  {
889  //undefined
890  return 0.0;
891  }
892 
893  if ( vertex.vertex == 0 || vertex.vertex >= ( numPoints() - 1 ) )
894  {
895  if ( isClosed() )
896  {
897  double previousX = mX.at( numPoints() - 2 );
898  double previousY = mY.at( numPoints() - 2 );
899  double currentX = mX.at( 0 );
900  double currentY = mY.at( 0 );
901  double afterX = mX.at( 1 );
902  double afterY = mY.at( 1 );
903  return QgsGeometryUtils::averageAngle( previousX, previousY, currentX, currentY, afterX, afterY );
904  }
905  else if ( vertex.vertex == 0 )
906  {
907  return QgsGeometryUtils::lineAngle( mX.at( 0 ), mY.at( 0 ), mX.at( 1 ), mY.at( 1 ) );
908  }
909  else
910  {
911  int a = numPoints() - 2;
912  int b = numPoints() - 1;
913  return QgsGeometryUtils::lineAngle( mX.at( a ), mY.at( a ), mX.at( b ), mY.at( b ) );
914  }
915  }
916  else
917  {
918  double previousX = mX.at( vertex.vertex - 1 );
919  double previousY = mY.at( vertex.vertex - 1 );
920  double currentX = mX.at( vertex.vertex );
921  double currentY = mY.at( vertex.vertex );
922  double afterX = mX.at( vertex.vertex + 1 );
923  double afterY = mY.at( vertex.vertex + 1 );
924  return QgsGeometryUtils::averageAngle( previousX, previousY, currentX, currentY, afterX, afterY );
925  }
926 }
927 
928 /***************************************************************************
929  * This class is considered CRITICAL and any change MUST be accompanied with
930  * full unit tests.
931  * See details in QEP #17
932  ****************************************************************************/
933 
934 bool QgsLineStringV2::addZValue( double zValue )
935 {
936  if ( QgsWKBTypes::hasZ( mWkbType ) )
937  return false;
938 
939  clearCache();
941  {
943  return true;
944  }
945 
947 
948  mZ.clear();
949  int nPoints = numPoints();
950  mZ.reserve( nPoints );
951  for ( int i = 0; i < nPoints; ++i )
952  {
953  mZ << zValue;
954  }
955  return true;
956 }
957 
958 bool QgsLineStringV2::addMValue( double mValue )
959 {
960  if ( QgsWKBTypes::hasM( mWkbType ) )
961  return false;
962 
963  clearCache();
965  {
967  return true;
968  }
969 
971  {
973  }
974  else
975  {
977  }
978 
979  mM.clear();
980  int nPoints = numPoints();
981  mM.reserve( nPoints );
982  for ( int i = 0; i < nPoints; ++i )
983  {
984  mM << mValue;
985  }
986  return true;
987 }
988 
990 {
991  if ( !is3D() )
992  return false;
993 
994  clearCache();
996  mZ.clear();
997  return true;
998 }
999 
1001 {
1002  if ( !isMeasure() )
1003  return false;
1004 
1005  clearCache();
1007  mM.clear();
1008  return true;
1009 }
1010 
1012 {
1013  if ( type == mWkbType )
1014  return true;
1015 
1016  clearCache();
1017  if ( type == QgsWKBTypes::LineString25D )
1018  {
1019  //special handling required for conversion to LineString25D
1020  dropMValue();
1021  addZValue();
1023  return true;
1024  }
1025  else
1026  {
1027  return QgsCurveV2::convertTo( type );
1028  }
1029 }
QString wktTypeStr() const
Returns the WKT type string of the geometry.
void clear()
double xAt(int index) const
Returns the x-coordinate of the specified node in the line string.
virtual bool insertVertex(QgsVertexId position, const QgsPointV2 &vertex) override
Inserts a vertex into the geometry.
void transformCoords(int numPoint, double *x, double *y, double *z, TransformDirection direction=ForwardTransform) const
Transform an array of coordinates to a different Coordinate System If the direction is ForwardTransfo...
static unsigned index
void close()
Closes the line string by appending the first point to the end of the line, if it is not already clos...
A rectangle specified with double values.
Definition: qgsrectangle.h:35
virtual QgsPointV2 centroid() const override
Returns the centroid of the geometry.
QDomElement asGML2(QDomDocument &doc, int precision=17, const QString &ns="gml") const override
Returns a GML2 representation of the geometry.
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 (...
QPointF currentPosition() const
virtual bool fromWkb(QgsConstWkbPtr wkb) override
Sets the geometry from a WKB string.
QDomNode appendChild(const QDomNode &newChild)
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...
void append(const T &value)
iterator begin()
void push_back(const T &value)
void points(QgsPointSequenceV2 &pt) const override
Returns a list of points within the curve.
void draw(QPainter &p) const override
Draws the geometry using the specified QPainter.
static double averageAngle(double x1, double y1, double x2, double y2, double x3, double y3)
Angle between two linear segments.
static Type addZ(Type type)
Adds the z dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:757
static bool hasM(Type type)
Tests whether a WKB type contains m values.
Definition: qgswkbtypes.h:714
QPoint map(const QPoint &point) const
static void pointsToWKB(QgsWkbPtr &wkb, const QgsPointSequenceV2 &points, bool is3D, bool isMeasure)
Returns a LinearRing { uint32 numPoints; Point points[numPoints]; }.
SegmentationToleranceType
Segmentation tolerance as maximum angle or maximum difference between approximation and circle...
void drawPolyline(const QPointF *points, int pointCount)
virtual bool fromWkt(const QString &wkt) override
Sets the geometry from a WKT string.
TransformDirection
Enum used to indicate the direction (forward or inverse) of the transform.
const T & at(int i) const
bool operator==(const QgsCurveV2 &other) const override
void insert(int i, const T &value)
static QString pointsToJSON(const QgsPointSequenceV2 &points, int precision)
Returns a geoJSON coordinates string.
Abstract base class for all geometries.
void drawPolygon(const QPointF *points, int pointCount, Qt::FillRule fillRule)
virtual bool addZValue(double zValue=0) override
Adds a z-dimension to the geometry, initialized to a preset value.
void moveTo(const QPointF &point)
void setX(double x)
Sets the point&#39;s x-coordinate.
Definition: qgspointv2.h:124
static double leftOfLine(double x, double y, double x1, double y1, double x2, double y2)
Returns < 0 if point(x/y) is left of the line x1,y1 -> x2,y2.
virtual QgsRectangle calculateBoundingBox() const override
Default calculator for the minimal bounding box for the geometry.
void append(const QgsLineStringV2 *line)
Appends the contents of another line string to the end of this line string.
QDomElement createElementNS(const QString &nsURI, const QString &qName)
double z() const
Returns the point&#39;s z-coordinate.
Definition: qgspointv2.h:80
static bool hasZ(Type type)
Tests whether a WKB type contains the z-dimension.
Definition: qgswkbtypes.h:667
double y() const
Returns the point&#39;s y-coordinate.
Definition: qgspointv2.h:74
virtual QgsPointV2 endPoint() const override
Returns the end point of the curve.
static endian_t endian()
Returns whether this machine uses big or little endian.
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Compare two doubles (but allow some difference)
Definition: qgis.h:353
void setY(double y)
Sets the point&#39;s y-coordinate.
Definition: qgspointv2.h:130
int size() const
bool pointAt(int node, QgsPointV2 &point, QgsVertexId::VertexType &type) const override
Returns the point and vertex id of a point within the curve.
virtual bool deleteVertex(QgsVertexId position) override
Deletes a vertex within the geometry.
void addToPainterPath(QPainterPath &path) const override
Adds a curve to a painter path.
double ANALYSIS_EXPORT max(double x, double y)
Returns the maximum of two doubles or the first argument if both are equal.
T * data()
void clear()
virtual bool dropMValue() override
Drops any measure values which exist in the geometry.
static Type dropZ(Type type)
Drops the z dimension (if present) for a WKB type and returns the new type.
Definition: qgswkbtypes.h:811
static Type addM(Type type)
Adds the m dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:781
void resize(int size)
virtual void clearCache() const override
Clears any cached parameters associated with the geometry, eg bounding boxes.
Definition: qgscurvev2.h:120
virtual bool addMValue(double mValue=0) override
Adds a measure to the geometry, initialized to a preset value.
virtual bool isClosed() const
Returns true if the curve is closed.
Definition: qgscurvev2.cpp:29
Utility class for identifying a unique vertex within a geometry.
Line string geometry type, with support for z-dimension and m-values.
QDomElement asGML3(QDomDocument &doc, int precision=17, const QString &ns="gml") const override
Returns a GML3 representation of the geometry.
static QString pointsToWKT(const QgsPointSequenceV2 &points, int precision, bool is3D, bool isMeasure)
Returns a WKT coordinate list.
void lineTo(const QPointF &endPoint)
void setPoints(const QgsPointSequenceV2 &points)
Resets the line string to match the specified list of points.
bool isMeasure() const
Returns true if the geometry contains m values.
Point geometry type, with support for z-dimension and m-values.
Definition: qgspointv2.h:34
bool isEmpty() const
void remove(int i)
virtual double length() const override
Returns the length of the geometry.
virtual QgsLineStringV2 * clone() const override
Clones the geometry by performing a deep copy.
unsigned char * asWkb(int &binarySize) const override
Returns a WKB representation of the geometry.
double x() const
Returns the point&#39;s x-coordinate.
Definition: qgspointv2.h:68
QString asWkt(int precision=17) const override
Returns a WKT representation of the geometry.
void setZMTypeFromSubGeometry(const QgsAbstractGeometryV2 *subggeom, QgsWKBTypes::Type baseGeomType)
Updates the geometry type based on whether sub geometries contain z or m values.
void pop_back()
void setZAt(int index, double z)
Sets the z-coordinate of the specified node in the line string.
bool operator!=(const QgsCurveV2 &other) const override
void setYAt(int index, double y)
Sets the y-coordinate of the specified node in the line string.
QString asJSON(int precision=17) const override
Returns a GeoJSON representation of the geometry.
static QDomElement pointsToGML3(const QgsPointSequenceV2 &points, QDomDocument &doc, int precision, const QString &ns, bool is3D)
Returns a gml::posList DOM element.
Compound curve geometry type.
void reserve(int size)
void setXAt(int index, double x)
Sets the x-coordinate of the specified node in the line string.
double yAt(int index) const
Returns the y-coordinate of the specified node in the line string.
bool convertTo(QgsWKBTypes::Type type) override
Converts the geometry to a specified type.
double vertexAngle(QgsVertexId vertex) const override
Returns approximate angle at a vertex.
virtual bool convertTo(QgsWKBTypes::Type type)
Converts the geometry to a specified type.
double closestSegment(const QgsPointV2 &pt, QgsPointV2 &segmentPt, QgsVertexId &vertexAfter, bool *leftOf, double epsilon) const override
Searches for the closest segment of the geometry to a given point.
static Type dropM(Type type)
Drops the m dimension (if present) for a WKB type and returns the new type.
Definition: qgswkbtypes.h:828
virtual QgsPointV2 startPoint() const override
Returns the starting point of the curve.
void addCurve(QgsCurveV2 *c)
Adds a curve to the geometr (takes ownership)
QgsAbstractGeometryV2 * toCurveType() const override
Returns the geometry converted to the more generic curve type QgsCompoundCurveV2. ...
void addVertex(const QgsPointV2 &pt)
Adds a new vertex to the end of the line string.
const T & at(int i) const
double zAt(int index) const
Returns the z-coordinate of the specified node in the line string.
virtual QgsLineStringV2 * curveToLine(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const override
Returns a new line string geometry corresponding to a segmentized approximation of the curve...
static QgsPointSequenceV2 pointsFromWKT(const QString &wktCoordinateList, bool is3D, bool isMeasure)
Returns a list of points contained in a WKT string.
virtual bool dropZValue() override
Drops any z-dimensions which exist in the geometry.
bool isEmpty() const
QgsWKBTypes::Type wkbType() const
Returns the WKB type of the geometry.
void transform(const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection d=QgsCoordinateTransform::ForwardTransform, bool transformZ=false) override
Transforms the geometry using a coordinate transform.
void drawAsPolygon(QPainter &p) const override
Draws the curve as a polygon on the specified QPainter.
bool isEmpty() const
int count(const T &value) const
virtual QgsLineStringV2 * reversed() const override
Returns a reversed copy of the curve, where the direction of the curve has been flipped.
Class for doing transforms between two map coordinate systems.
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.
static Type flatType(Type type)
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:366
QPolygonF asQPolygonF() const
Returns a QPolygonF representing the line string.
double ANALYSIS_EXPORT leftOf(Point3D *thepoint, Point3D *p1, Point3D *p2)
Returns whether &#39;thepoint&#39; is left or right of the line from &#39;p1&#39; to &#39;p2&#39;.
QgsWKBTypes::Type readHeader() const
Definition: qgswkbptr.cpp:38
double mAt(int index) const
Returns the m value of the specified node in the line string.
int wkbSize() const override
Returns the size of the WKB representation of the geometry.
void sumUpArea(double &sum) const override
Sums up the area of the curve by iterating over the vertices (shoelace formula).
Abstract base class for curved geometry type.
Definition: qgscurvev2.h:32
int size() const
iterator end()
double m() const
Returns the point&#39;s m value.
Definition: qgspointv2.h:86
virtual void clear() override
Clears the geometry, ie reset it to a null geometry.
static QDomElement pointsToGML2(const QgsPointSequenceV2 &points, QDomDocument &doc, int precision, const QString &ns)
Returns a gml::coordinates DOM element.
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
virtual bool moveVertex(QgsVertexId position, const QgsPointV2 &newPos) override
Moves a vertex within the geometry.
int numPoints() const override
Returns the number of points in the curve.
QgsPointV2 pointN(int i) const
Returns the specified point from inside the line string.
void setMAt(int index, double m)
Sets the m value of the specified node in the line string.