QGIS API Documentation  2.14.0-Essen
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 "qgscoordinatetransform.h"
21 #include "qgsgeometryutils.h"
22 #include "qgsmaptopixel.h"
23 #include "qgswkbptr.h"
24 
25 #include <QPainter>
26 #include <limits>
27 #include <QDomDocument>
28 #include <QtCore/qmath.h>
29 
30 
31 /***************************************************************************
32  * This class is considered CRITICAL and any change MUST be accompanied with
33  * full unit tests.
34  * See details in QEP #17
35  ****************************************************************************/
36 
38 {
40 }
41 
43 {}
44 
45 bool QgsLineStringV2::operator==( const QgsCurveV2& other ) const
46 {
47  const QgsLineStringV2* otherLine = dynamic_cast< const QgsLineStringV2* >( &other );
48  if ( !otherLine )
49  return false;
50 
51  if ( mWkbType != otherLine->mWkbType )
52  return false;
53 
54  if ( mX.count() != otherLine->mX.count() )
55  return false;
56 
57  for ( int i = 0; i < mX.count(); ++i )
58  {
59  if ( !qgsDoubleNear( mX.at( i ), otherLine->mX.at( i ) )
60  || !qgsDoubleNear( mY.at( i ), otherLine->mY.at( i ) ) )
61  return false;
62 
63  if ( is3D() && !qgsDoubleNear( mZ.at( i ), otherLine->mZ.at( i ) ) )
64  return false;
65 
66  if ( isMeasure() && !qgsDoubleNear( mM.at( i ), otherLine->mM.at( i ) ) )
67  return false;
68  }
69 
70  return true;
71 }
72 
73 bool QgsLineStringV2::operator!=( const QgsCurveV2& other ) const
74 {
75  return !operator==( other );
76 }
77 
79 {
80  return new QgsLineStringV2( *this );
81 }
82 
84 {
85  mX.clear();
86  mY.clear();
87  mZ.clear();
88  mM.clear();
90  clearCache();
91 }
92 
94 {
95  if ( !wkbPtr )
96  {
97  return false;
98  }
99 
100  QgsWKBTypes::Type type = wkbPtr.readHeader();
102  {
103  return false;
104  }
105  mWkbType = type;
106  importVerticesFromWkb( wkbPtr );
107  return true;
108 }
109 
110 void QgsLineStringV2::fromWkbPoints( QgsWKBTypes::Type type, const QgsConstWkbPtr& wkb )
111 {
112  mWkbType = type;
113  importVerticesFromWkb( wkb );
114 }
115 
117 {
118  double xmin = std::numeric_limits<double>::max();
119  double ymin = std::numeric_limits<double>::max();
120  double xmax = -std::numeric_limits<double>::max();
121  double ymax = -std::numeric_limits<double>::max();
122 
123  Q_FOREACH ( double x, mX )
124  {
125  if ( x < xmin )
126  xmin = x;
127  if ( x > xmax )
128  xmax = x;
129  }
130  Q_FOREACH ( double y, mY )
131  {
132  if ( y < ymin )
133  ymin = y;
134  if ( y > ymax )
135  ymax = y;
136  }
137  return QgsRectangle( xmin, ymin, xmax, ymax );
138 }
139 
140 /***************************************************************************
141  * This class is considered CRITICAL and any change MUST be accompanied with
142  * full unit tests.
143  * See details in QEP #17
144  ****************************************************************************/
145 
147 {
148  clear();
149 
151 
152  if ( QgsWKBTypes::flatType( parts.first ) != QgsWKBTypes::parseType( geometryType() ) )
153  return false;
154  mWkbType = parts.first;
155 
156  setPoints( QgsGeometryUtils::pointsFromWKT( parts.second, is3D(), isMeasure() ) );
157  return true;
158 }
159 
161 {
162  int size = sizeof( char ) + sizeof( quint32 ) + sizeof( quint32 );
163  size += numPoints() * ( 2 + is3D() + isMeasure() ) * sizeof( double );
164  return size;
165 }
166 
167 unsigned char* QgsLineStringV2::asWkb( int& binarySize ) const
168 {
169  binarySize = wkbSize();
170  unsigned char* geomPtr = new unsigned char[binarySize];
171  QgsWkbPtr wkb( geomPtr, binarySize );
172  wkb << static_cast<char>( QgsApplication::endian() );
173  wkb << static_cast<quint32>( wkbType() );
174  QgsPointSequenceV2 pts;
175  points( pts );
176  QgsGeometryUtils::pointsToWKB( wkb, pts, is3D(), isMeasure() );
177  return geomPtr;
178 }
179 
180 /***************************************************************************
181  * This class is considered CRITICAL and any change MUST be accompanied with
182  * full unit tests.
183  * See details in QEP #17
184  ****************************************************************************/
185 
186 QString QgsLineStringV2::asWkt( int precision ) const
187 {
188  QString wkt = wktTypeStr() + ' ';
189  QgsPointSequenceV2 pts;
190  points( pts );
191  wkt += QgsGeometryUtils::pointsToWKT( pts, precision, is3D(), isMeasure() );
192  return wkt;
193 }
194 
195 QDomElement QgsLineStringV2::asGML2( QDomDocument& doc, int precision, const QString& ns ) const
196 {
197  QgsPointSequenceV2 pts;
198  points( pts );
199 
200  QDomElement elemLineString = doc.createElementNS( ns, "LineString" );
201  elemLineString.appendChild( QgsGeometryUtils::pointsToGML2( pts, doc, precision, ns ) );
202 
203  return elemLineString;
204 }
205 
206 QDomElement QgsLineStringV2::asGML3( QDomDocument& doc, int precision, const QString& ns ) const
207 {
208  QgsPointSequenceV2 pts;
209  points( pts );
210 
211  QDomElement elemCurve = doc.createElementNS( ns, "Curve" );
212  QDomElement elemSegments = doc.createElementNS( ns, "segments" );
213  QDomElement elemArcString = doc.createElementNS( ns, "LineStringSegment" );
214  elemArcString.appendChild( QgsGeometryUtils::pointsToGML3( pts, doc, precision, ns, is3D() ) );
215  elemSegments.appendChild( elemArcString );
216  elemCurve.appendChild( elemSegments );
217 
218  return elemCurve;
219 }
220 
221 QString QgsLineStringV2::asJSON( int precision ) const
222 {
223  QgsPointSequenceV2 pts;
224  points( pts );
225 
226  return "{\"type\": \"LineString\", \"coordinates\": " + QgsGeometryUtils::pointsToJSON( pts, precision ) + '}';
227 }
228 
229 /***************************************************************************
230  * This class is considered CRITICAL and any change MUST be accompanied with
231  * full unit tests.
232  * See details in QEP #17
233  ****************************************************************************/
234 
236 {
237  double length = 0;
238  int size = mX.size();
239  double dx, dy;
240  for ( int i = 1; i < size; ++i )
241  {
242  dx = mX.at( i ) - mX.at( i - 1 );
243  dy = mY.at( i ) - mY.at( i - 1 );
244  length += sqrt( dx * dx + dy * dy );
245  }
246  return length;
247 }
248 
250 {
251  if ( numPoints() < 1 )
252  {
253  return QgsPointV2();
254  }
255  return pointN( 0 );
256 }
257 
259 {
260  if ( numPoints() < 1 )
261  {
262  return QgsPointV2();
263  }
264  return pointN( numPoints() - 1 );
265 }
266 
267 /***************************************************************************
268  * This class is considered CRITICAL and any change MUST be accompanied with
269  * full unit tests.
270  * See details in QEP #17
271  ****************************************************************************/
272 
274 {
275  return static_cast<QgsLineStringV2*>( clone() );
276 }
277 
279 {
280  return mX.size();
281 }
282 
284 {
285  if ( i < 0 || i >= mX.size() )
286  {
287  return QgsPointV2();
288  }
289 
290  double x = mX.at( i );
291  double y = mY.at( i );
292  double z = 0;
293  double m = 0;
294 
295  bool hasZ = is3D();
296  if ( hasZ )
297  {
298  z = mZ.at( i );
299  }
300  bool hasM = isMeasure();
301  if ( hasM )
302  {
303  m = mM.at( i );
304  }
305 
308  {
310  }
311  else if ( hasZ && hasM )
312  {
314  }
315  else if ( hasZ )
316  {
318  }
319  else if ( hasM )
320  {
322  }
323  return QgsPointV2( t, x, y, z, m );
324 }
325 
326 /***************************************************************************
327  * This class is considered CRITICAL and any change MUST be accompanied with
328  * full unit tests.
329  * See details in QEP #17
330  ****************************************************************************/
331 
332 double QgsLineStringV2::xAt( int index ) const
333 {
334  if ( index >= 0 && index < mX.size() )
335  return mX.at( index );
336  else
337  return 0.0;
338 }
339 
340 double QgsLineStringV2::yAt( int index ) const
341 {
342  if ( index >= 0 && index < mY.size() )
343  return mY.at( index );
344  else
345  return 0.0;
346 }
347 
348 double QgsLineStringV2::zAt( int index ) const
349 {
350  if ( index >= 0 && index < mZ.size() )
351  return mZ.at( index );
352  else
353  return 0.0;
354 }
355 
356 double QgsLineStringV2::mAt( int index ) const
357 {
358  if ( index >= 0 && index < mM.size() )
359  return mM.at( index );
360  else
361  return 0.0;
362 }
363 
364 void QgsLineStringV2::setXAt( int index, double x )
365 {
366  if ( index >= 0 && index < mX.size() )
367  mX[ index ] = x;
368  clearCache();
369 }
370 
371 void QgsLineStringV2::setYAt( int index, double y )
372 {
373  if ( index >= 0 && index < mY.size() )
374  mY[ index ] = y;
375  clearCache();
376 }
377 
378 void QgsLineStringV2::setZAt( int index, double z )
379 {
380  if ( index >= 0 && index < mZ.size() )
381  mZ[ index ] = z;
382 }
383 
384 void QgsLineStringV2::setMAt( int index, double m )
385 {
386  if ( index >= 0 && index < mM.size() )
387  mM[ index ] = m;
388 }
389 
390 /***************************************************************************
391  * This class is considered CRITICAL and any change MUST be accompanied with
392  * full unit tests.
393  * See details in QEP #17
394  ****************************************************************************/
395 
397 {
398  pts.clear();
399  int nPoints = numPoints();
400  for ( int i = 0; i < nPoints; ++i )
401  {
402  pts.push_back( pointN( i ) );
403  }
404 }
405 
407 {
408  clearCache(); //set bounding box invalid
409 
410  if ( points.isEmpty() )
411  {
412  clear();
413  return;
414  }
415 
416  //get wkb type from first point
417  const QgsPointV2& firstPt = points.at( 0 );
418  bool hasZ = firstPt.is3D();
419  bool hasM = firstPt.isMeasure();
420 
422 
423  mX.resize( points.size() );
424  mY.resize( points.size() );
425  if ( hasZ )
426  {
427  mZ.resize( points.size() );
428  }
429  else
430  {
431  mZ.clear();
432  }
433  if ( hasM )
434  {
435  mM.resize( points.size() );
436  }
437  else
438  {
439  mM.clear();
440  }
441 
442  for ( int i = 0; i < points.size(); ++i )
443  {
444  mX[i] = points.at( i ).x();
445  mY[i] = points.at( i ).y();
446  if ( hasZ )
447  {
448  mZ[i] = points.at( i ).z();
449  }
450  if ( hasM )
451  {
452  mM[i] = points.at( i ).m();
453  }
454  }
455 }
456 
457 /***************************************************************************
458  * This class is considered CRITICAL and any change MUST be accompanied with
459  * full unit tests.
460  * See details in QEP #17
461  ****************************************************************************/
462 
464 {
465  if ( !line )
466  {
467  return;
468  }
469 
470  if ( numPoints() < 1 )
471  {
473  }
474 
475  // do not store duplicit points
476  if ( numPoints() > 0 &&
477  line->numPoints() > 0 &&
478  endPoint() == line->startPoint() )
479  {
480  mX.pop_back();
481  mY.pop_back();
482 
483  if ( is3D() )
484  {
485  mZ.pop_back();
486  }
487  if ( isMeasure() )
488  {
489  mM.pop_back();
490  }
491  }
492 
493  mX += line->mX;
494  mY += line->mY;
495 
496  if ( is3D() )
497  {
498  if ( line->is3D() )
499  {
500  mZ += line->mZ;
501  }
502  else
503  {
504  // if append line does not have z coordinates, fill with 0 to match number of points in final line
505  mZ.insert( mZ.count(), mX.size() - mZ.size(), 0 );
506  }
507  }
508 
509  if ( isMeasure() )
510  {
511  if ( line->isMeasure() )
512  {
513  mM += line->mM;
514  }
515  else
516  {
517  // if append line does not have m values, fill with 0 to match number of points in final line
518  mM.insert( mM.count(), mX.size() - mM.size(), 0 );
519  }
520  }
521 
522  clearCache(); //set bounding box invalid
523 }
524 
526 {
527  QgsLineStringV2* copy = clone();
528  std::reverse( copy->mX.begin(), copy->mX.end() );
529  std::reverse( copy->mY.begin(), copy->mY.end() );
530  if ( copy->is3D() )
531  {
532  std::reverse( copy->mZ.begin(), copy->mZ.end() );
533  }
534  if ( copy->isMeasure() )
535  {
536  std::reverse( copy->mM.begin(), copy->mM.end() );
537  }
538  return copy;
539 }
540 
541 /***************************************************************************
542  * This class is considered CRITICAL and any change MUST be accompanied with
543  * full unit tests.
544  * See details in QEP #17
545  ****************************************************************************/
546 
548 {
549  p.drawPolyline( asQPolygonF() );
550 }
551 
553 {
554  int nPoints = numPoints();
555  if ( nPoints < 1 )
556  {
557  return;
558  }
559 
560  if ( path.isEmpty() || path.currentPosition() != QPointF( mX.at( 0 ), mY.at( 0 ) ) )
561  {
562  path.moveTo( mX.at( 0 ), mY.at( 0 ) );
563  }
564 
565  for ( int i = 1; i < nPoints; ++i )
566  {
567  path.lineTo( mX.at( i ), mY.at( i ) );
568  }
569 }
570 
572 {
573  p.drawPolygon( asQPolygonF() );
574 }
575 
577 {
579  for ( int i = 0; i < mX.count(); ++i )
580  {
581  points << QPointF( mX.at( i ), mY.at( i ) );
582  }
583  return points;
584 }
585 
586 /***************************************************************************
587  * This class is considered CRITICAL and any change MUST be accompanied with
588  * full unit tests.
589  * See details in QEP #17
590  ****************************************************************************/
591 
593 {
594  double* zArray = mZ.data();
595 
596  bool hasZ = is3D();
597  int nPoints = numPoints();
598  if ( !hasZ )
599  {
600  zArray = new double[nPoints];
601  for ( int i = 0; i < nPoints; ++i )
602  {
603  zArray[i] = 0;
604  }
605  }
606  ct.transformCoords( nPoints, mX.data(), mY.data(), zArray, d );
607  if ( !hasZ )
608  {
609  delete[] zArray;
610  }
611  clearCache();
612 }
613 
615 {
616  int nPoints = numPoints();
617  for ( int i = 0; i < nPoints; ++i )
618  {
619  qreal x, y;
620  t.map( mX.at( i ), mY.at( i ), &x, &y );
621  mX[i] = x;
622  mY[i] = y;
623  }
624  clearCache();
625 }
626 
627 /***************************************************************************
628  * This class is considered CRITICAL and any change MUST be accompanied with
629  * full unit tests.
630  * See details in QEP #17
631  ****************************************************************************/
632 
633 bool QgsLineStringV2::insertVertex( QgsVertexId position, const QgsPointV2& vertex )
634 {
635  if ( position.vertex < 0 || position.vertex > mX.size() )
636  {
637  return false;
638  }
639 
640  if ( mWkbType == QgsWKBTypes::Unknown || mX.isEmpty() )
641  {
643  }
644 
645  mX.insert( position.vertex, vertex.x() );
646  mY.insert( position.vertex, vertex.y() );
647  if ( is3D() )
648  {
649  mZ.insert( position.vertex, vertex.z() );
650  }
651  if ( isMeasure() )
652  {
653  mM.insert( position.vertex, vertex.m() );
654  }
655  clearCache(); //set bounding box invalid
656  return true;
657 }
658 
659 bool QgsLineStringV2::moveVertex( QgsVertexId position, const QgsPointV2& newPos )
660 {
661  if ( position.vertex < 0 || position.vertex >= mX.size() )
662  {
663  return false;
664  }
665  mX[position.vertex] = newPos.x();
666  mY[position.vertex] = newPos.y();
667  if ( is3D() && newPos.is3D() )
668  {
669  mZ[position.vertex] = newPos.z();
670  }
671  if ( isMeasure() && newPos.isMeasure() )
672  {
673  mM[position.vertex] = newPos.m();
674  }
675  clearCache(); //set bounding box invalid
676  return true;
677 }
678 
680 {
681  if ( position.vertex >= mX.size() || position.vertex < 0 )
682  {
683  return false;
684  }
685 
686  mX.remove( position.vertex );
687  mY.remove( position.vertex );
688  if ( is3D() )
689  {
690  mZ.remove( position.vertex );
691  }
692  if ( isMeasure() )
693  {
694  mM.remove( position.vertex );
695  }
696 
697  if ( numPoints() == 1 )
698  {
699  clear();
700  }
701 
702  clearCache(); //set bounding box invalid
703  return true;
704 }
705 
706 /***************************************************************************
707  * This class is considered CRITICAL and any change MUST be accompanied with
708  * full unit tests.
709  * See details in QEP #17
710  ****************************************************************************/
711 
713 {
714  if ( mWkbType == QgsWKBTypes::Unknown || mX.isEmpty() )
715  {
717  }
718 
719  mX.append( pt.x() );
720  mY.append( pt.y() );
721  if ( is3D() )
722  {
723  mZ.append( pt.z() );
724  }
725  if ( isMeasure() )
726  {
727  mM.append( pt.m() );
728  }
729  clearCache(); //set bounding box invalid
730 }
731 
732 double QgsLineStringV2::closestSegment( const QgsPointV2& pt, QgsPointV2& segmentPt, QgsVertexId& vertexAfter, bool* leftOf, double epsilon ) const
733 {
734  double sqrDist = std::numeric_limits<double>::max();
735  double testDist = 0;
736  double segmentPtX, segmentPtY;
737 
738  int size = mX.size();
739  if ( size == 0 )
740  {
741  vertexAfter = QgsVertexId( 0, 0, 0 );
742  return sqrDist;
743  }
744  else if ( size == 1 )
745  {
746  segmentPt = pointN( 0 );
747  vertexAfter = QgsVertexId( 0, 0, 1 );
748  return QgsGeometryUtils::sqrDistance2D( pt, segmentPt );
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  if ( maxIndex == 1 )
839  return; //no area, just a single line
840 
841  for ( int i = 0; i < maxIndex; ++i )
842  {
843  sum += 0.5 * ( mX.at( i ) * mY.at( i + 1 ) - mY.at( i ) * mX.at( i + 1 ) );
844  }
845 }
846 
847 void QgsLineStringV2::importVerticesFromWkb( const QgsConstWkbPtr& wkb )
848 {
849  bool hasZ = is3D();
850  bool hasM = isMeasure();
851  int nVertices = 0;
852  wkb >> nVertices;
853  mX.resize( nVertices );
854  mY.resize( nVertices );
855  hasZ ? mZ.resize( nVertices ) : mZ.clear();
856  hasM ? mM.resize( nVertices ) : mM.clear();
857  for ( int i = 0; i < nVertices; ++i )
858  {
859  wkb >> mX[i];
860  wkb >> mY[i];
861  if ( hasZ )
862  {
863  wkb >> mZ[i];
864  }
865  if ( hasM )
866  {
867  wkb >> mM[i];
868  }
869  }
870  clearCache(); //set bounding box invalid
871 }
872 
873 /***************************************************************************
874  * This class is considered CRITICAL and any change MUST be accompanied with
875  * full unit tests.
876  * See details in QEP #17
877  ****************************************************************************/
878 
880 {
881  if ( numPoints() < 1 || isClosed() )
882  {
883  return;
884  }
885  addVertex( startPoint() );
886 }
887 
889 {
890  if ( mX.count() < 2 )
891  {
892  //undefined
893  return 0.0;
894  }
895 
896  if ( vertex.vertex == 0 || vertex.vertex >= ( numPoints() - 1 ) )
897  {
898  if ( isClosed() )
899  {
900  double previousX = mX.at( numPoints() - 2 );
901  double previousY = mY.at( numPoints() - 2 );
902  double currentX = mX.at( 0 );
903  double currentY = mY.at( 0 );
904  double afterX = mX.at( 1 );
905  double afterY = mY.at( 1 );
906  return QgsGeometryUtils::averageAngle( previousX, previousY, currentX, currentY, afterX, afterY );
907  }
908  else if ( vertex.vertex == 0 )
909  {
910  return QgsGeometryUtils::lineAngle( mX.at( 0 ), mY.at( 0 ), mX.at( 1 ), mY.at( 1 ) );
911  }
912  else
913  {
914  int a = numPoints() - 2;
915  int b = numPoints() - 1;
916  return QgsGeometryUtils::lineAngle( mX.at( a ), mY.at( a ), mX.at( b ), mY.at( b ) );
917  }
918  }
919  else
920  {
921  double previousX = mX.at( vertex.vertex - 1 );
922  double previousY = mY.at( vertex.vertex - 1 );
923  double currentX = mX.at( vertex.vertex );
924  double currentY = mY.at( vertex.vertex );
925  double afterX = mX.at( vertex.vertex + 1 );
926  double afterY = mY.at( vertex.vertex + 1 );
927  return QgsGeometryUtils::averageAngle( previousX, previousY, currentX, currentY, afterX, afterY );
928  }
929 }
930 
931 /***************************************************************************
932  * This class is considered CRITICAL and any change MUST be accompanied with
933  * full unit tests.
934  * See details in QEP #17
935  ****************************************************************************/
936 
937 bool QgsLineStringV2::addZValue( double zValue )
938 {
939  if ( QgsWKBTypes::hasZ( mWkbType ) )
940  return false;
941 
942  clearCache();
944  {
946  return true;
947  }
948 
950 
951  mZ.clear();
952  int nPoints = numPoints();
953  mZ.reserve( nPoints );
954  for ( int i = 0; i < nPoints; ++i )
955  {
956  mZ << zValue;
957  }
958  return true;
959 }
960 
961 bool QgsLineStringV2::addMValue( double mValue )
962 {
963  if ( QgsWKBTypes::hasM( mWkbType ) )
964  return false;
965 
966  clearCache();
968  {
970  return true;
971  }
972 
974  {
976  }
977  else
978  {
980  }
981 
982  mM.clear();
983  int nPoints = numPoints();
984  mM.reserve( nPoints );
985  for ( int i = 0; i < nPoints; ++i )
986  {
987  mM << mValue;
988  }
989  return true;
990 }
991 
993 {
994  if ( !is3D() )
995  return false;
996 
997  clearCache();
999  mZ.clear();
1000  return true;
1001 }
1002 
1004 {
1005  if ( !isMeasure() )
1006  return false;
1007 
1008  clearCache();
1010  mM.clear();
1011  return true;
1012 }
1013 
1015 {
1016  if ( type == mWkbType )
1017  return true;
1018 
1019  clearCache();
1020  if ( type == QgsWKBTypes::LineString25D )
1021  {
1022  //special handling required for conversion to LineString25D
1023  dropMValue();
1024  addZValue();
1026  return true;
1027  }
1028  else
1029  {
1030  return QgsCurveV2::convertTo( type );
1031  }
1032 }
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...
void clear()
virtual bool insertVertex(QgsVertexId position, const QgsPointV2 &vertex) override
Inserts a vertex into the geometry.
static unsigned index
QgsWKBTypes::Type wkbType() const
Returns the WKB type of the geometry.
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.
QgsPointV2 pointN(int i) const
Returns the specified point from inside the line string.
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)
double x() const
Returns the point&#39;s x-coordinate.
Definition: qgspointv2.h:68
iterator begin()
void push_back(const T &value)
void points(QgsPointSequenceV2 &pt) const override
Returns a list of points within the curve.
QPolygonF asQPolygonF() const
Returns a QPolygonF representing the line string.
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:746
static bool hasM(Type type)
Tests whether a WKB type contains m values.
Definition: qgswkbtypes.h:703
QPoint map(const QPoint &point) const
double xAt(int index) const
Returns the x-coordinate of the specified node in the line string.
static void pointsToWKB(QgsWkbPtr &wkb, const QgsPointSequenceV2 &points, bool is3D, bool isMeasure)
Returns a LinearRing { uint32 numPoints; Point points[numPoints]; }.
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.
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.
void transform(const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection d=QgsCoordinateTransform::ForwardTransform) override
Transforms the geometry using a coordinate transform.
QDomElement createElementNS(const QString &nsURI, const QString &qName)
static bool hasZ(Type type)
Tests whether a WKB type contains the z-dimension.
Definition: qgswkbtypes.h:656
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.
QString wktTypeStr() const
Returns the WKT type string of the geometry.
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Definition: qgis.h:285
void setY(double y)
Sets the point&#39;s y-coordinate.
Definition: qgspointv2.h:130
double zAt(int index) const
Returns the z-coordinate of the specified node in the line string.
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 y() const
Returns the point&#39;s y-coordinate.
Definition: qgspointv2.h:74
double ANALYSIS_EXPORT max(double x, double y)
Returns the maximum of two doubles or the first argument if both are equal.
virtual QgsLineStringV2 * curveToLine() const override
Returns a new line string geometry corresponding to a segmentized approximation of the curve...
QgsWKBTypes::Type readHeader() const
Definition: qgswkbptr.cpp:37
T * data()
void clear()
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
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:800
static Type addM(Type type)
Adds the m dimension to a WKB type and returns the new type.
Definition: qgswkbtypes.h:770
void resize(int size)
virtual void clearCache() const override
Clears any cached parameters associated with the geometry, eg bounding boxes.
Definition: qgscurvev2.h:116
virtual bool addMValue(double mValue=0) override
Adds a measure to the geometry, initialized to a preset value.
static double sqrDistance2D(const QgsPointV2 &pt1, const QgsPointV2 &pt2)
Returns the squared 2D distance between two points.
Utility class for identifying a unique vertex within a geometry.
bool isMeasure() const
Returns true if the geometry contains m values.
double z() const
Returns the point&#39;s z-coordinate.
Definition: qgspointv2.h:80
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.
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.
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()
virtual QString geometryType() const override
Returns a unique string representing the geometry type.
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.
double yAt(int index) const
Returns the y-coordinate of the specified node in the line string.
static QDomElement pointsToGML3(const QgsPointSequenceV2 &points, QDomDocument &doc, int precision, const QString &ns, bool is3D)
Returns a gml::posList DOM element.
double mAt(int index) const
Returns the m value of the specified node in the line string.
void reserve(int size)
void setXAt(int index, double x)
Sets the x-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:817
virtual QgsPointV2 startPoint() const override
Returns the starting point of the curve.
void addVertex(const QgsPointV2 &pt)
Adds a new vertex to the end of the line string.
const T & at(int i) const
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
virtual bool isClosed() const
Returns true if the curve is closed.
Definition: qgscurvev2.cpp:27
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.
double m() const
Returns the point&#39;s m value.
Definition: qgspointv2.h:86
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
static Type parseType(const QString &wktStr)
Attempts to extract the WKB type from a WKT string.
Definition: qgswkbtypes.cpp:32
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;.
int wkbSize() const override
Returns the size of the WKB representation of the geometry.
void sumUpArea(double &sum) const override
Calculates the area of the curve.
Abstract base class for curved geometry type.
Definition: qgscurvev2.h:32
int size() const
iterator end()
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.
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.
void setMAt(int index, double m)
Sets the m value of the specified node in the line string.