QGIS API Documentation  2.18.3-Las Palmas (77b8c3d)
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 elemCurve = doc.createElementNS( ns, "Curve" );
213  QDomElement elemSegments = doc.createElementNS( ns, "segments" );
214  QDomElement elemArcString = doc.createElementNS( ns, "LineStringSegment" );
215  elemArcString.appendChild( QgsGeometryUtils::pointsToGML3( pts, doc, precision, ns, is3D() ) );
216  elemSegments.appendChild( elemArcString );
217  elemCurve.appendChild( elemSegments );
218 
219  return elemCurve;
220 }
221 
222 QString QgsLineStringV2::asJSON( int precision ) const
223 {
224  QgsPointSequenceV2 pts;
225  points( pts );
226 
227  return "{\"type\": \"LineString\", \"coordinates\": " + QgsGeometryUtils::pointsToJSON( pts, precision ) + '}';
228 }
229 
230 /***************************************************************************
231  * This class is considered CRITICAL and any change MUST be accompanied with
232  * full unit tests.
233  * See details in QEP #17
234  ****************************************************************************/
235 
237 {
238  double length = 0;
239  int size = mX.size();
240  double dx, dy;
241  for ( int i = 1; i < size; ++i )
242  {
243  dx = mX.at( i ) - mX.at( i - 1 );
244  dy = mY.at( i ) - mY.at( i - 1 );
245  length += sqrt( dx * dx + dy * dy );
246  }
247  return length;
248 }
249 
251 {
252  if ( numPoints() < 1 )
253  {
254  return QgsPointV2();
255  }
256  return pointN( 0 );
257 }
258 
260 {
261  if ( numPoints() < 1 )
262  {
263  return QgsPointV2();
264  }
265  return pointN( numPoints() - 1 );
266 }
267 
268 /***************************************************************************
269  * This class is considered CRITICAL and any change MUST be accompanied with
270  * full unit tests.
271  * See details in QEP #17
272  ****************************************************************************/
273 
275 {
276  Q_UNUSED( tolerance );
277  Q_UNUSED( toleranceType );
278  return static_cast<QgsLineStringV2*>( clone() );
279 }
280 
282 {
283  return mX.size();
284 }
285 
287 {
288  if ( i < 0 || i >= mX.size() )
289  {
290  return QgsPointV2();
291  }
292 
293  double x = mX.at( i );
294  double y = mY.at( i );
295  double z = 0;
296  double m = 0;
297 
298  bool hasZ = is3D();
299  if ( hasZ )
300  {
301  z = mZ.at( i );
302  }
303  bool hasM = isMeasure();
304  if ( hasM )
305  {
306  m = mM.at( i );
307  }
308 
311  {
313  }
314  else if ( hasZ && hasM )
315  {
317  }
318  else if ( hasZ )
319  {
321  }
322  else if ( hasM )
323  {
325  }
326  return QgsPointV2( t, x, y, z, m );
327 }
328 
329 /***************************************************************************
330  * This class is considered CRITICAL and any change MUST be accompanied with
331  * full unit tests.
332  * See details in QEP #17
333  ****************************************************************************/
334 
335 double QgsLineStringV2::xAt( int index ) const
336 {
337  if ( index >= 0 && index < mX.size() )
338  return mX.at( index );
339  else
340  return 0.0;
341 }
342 
343 double QgsLineStringV2::yAt( int index ) const
344 {
345  if ( index >= 0 && index < mY.size() )
346  return mY.at( index );
347  else
348  return 0.0;
349 }
350 
351 double QgsLineStringV2::zAt( int index ) const
352 {
353  if ( index >= 0 && index < mZ.size() )
354  return mZ.at( index );
355  else
356  return 0.0;
357 }
358 
359 double QgsLineStringV2::mAt( int index ) const
360 {
361  if ( index >= 0 && index < mM.size() )
362  return mM.at( index );
363  else
364  return 0.0;
365 }
366 
367 void QgsLineStringV2::setXAt( int index, double x )
368 {
369  if ( index >= 0 && index < mX.size() )
370  mX[ index ] = x;
371  clearCache();
372 }
373 
374 void QgsLineStringV2::setYAt( int index, double y )
375 {
376  if ( index >= 0 && index < mY.size() )
377  mY[ index ] = y;
378  clearCache();
379 }
380 
381 void QgsLineStringV2::setZAt( int index, double z )
382 {
383  if ( index >= 0 && index < mZ.size() )
384  mZ[ index ] = z;
385 }
386 
387 void QgsLineStringV2::setMAt( int index, double m )
388 {
389  if ( index >= 0 && index < mM.size() )
390  mM[ index ] = m;
391 }
392 
393 /***************************************************************************
394  * This class is considered CRITICAL and any change MUST be accompanied with
395  * full unit tests.
396  * See details in QEP #17
397  ****************************************************************************/
398 
400 {
401  pts.clear();
402  int nPoints = numPoints();
403  for ( int i = 0; i < nPoints; ++i )
404  {
405  pts.push_back( pointN( i ) );
406  }
407 }
408 
410 {
411  clearCache(); //set bounding box invalid
412 
413  if ( points.isEmpty() )
414  {
415  clear();
416  return;
417  }
418 
419  //get wkb type from first point
420  const QgsPointV2& firstPt = points.at( 0 );
421  bool hasZ = firstPt.is3D();
422  bool hasM = firstPt.isMeasure();
423 
425 
426  mX.resize( points.size() );
427  mY.resize( points.size() );
428  if ( hasZ )
429  {
430  mZ.resize( points.size() );
431  }
432  else
433  {
434  mZ.clear();
435  }
436  if ( hasM )
437  {
438  mM.resize( points.size() );
439  }
440  else
441  {
442  mM.clear();
443  }
444 
445  for ( int i = 0; i < points.size(); ++i )
446  {
447  mX[i] = points.at( i ).x();
448  mY[i] = points.at( i ).y();
449  if ( hasZ )
450  {
451  mZ[i] = points.at( i ).z();
452  }
453  if ( hasM )
454  {
455  mM[i] = points.at( i ).m();
456  }
457  }
458 }
459 
460 /***************************************************************************
461  * This class is considered CRITICAL and any change MUST be accompanied with
462  * full unit tests.
463  * See details in QEP #17
464  ****************************************************************************/
465 
467 {
468  if ( !line )
469  {
470  return;
471  }
472 
473  if ( numPoints() < 1 )
474  {
476  }
477 
478  // do not store duplicit points
479  if ( numPoints() > 0 &&
480  line->numPoints() > 0 &&
481  endPoint() == line->startPoint() )
482  {
483  mX.pop_back();
484  mY.pop_back();
485 
486  if ( is3D() )
487  {
488  mZ.pop_back();
489  }
490  if ( isMeasure() )
491  {
492  mM.pop_back();
493  }
494  }
495 
496  mX += line->mX;
497  mY += line->mY;
498 
499  if ( is3D() )
500  {
501  if ( line->is3D() )
502  {
503  mZ += line->mZ;
504  }
505  else
506  {
507  // if append line does not have z coordinates, fill with 0 to match number of points in final line
508  mZ.insert( mZ.count(), mX.size() - mZ.size(), 0 );
509  }
510  }
511 
512  if ( isMeasure() )
513  {
514  if ( line->isMeasure() )
515  {
516  mM += line->mM;
517  }
518  else
519  {
520  // if append line does not have m values, fill with 0 to match number of points in final line
521  mM.insert( mM.count(), mX.size() - mM.size(), 0 );
522  }
523  }
524 
525  clearCache(); //set bounding box invalid
526 }
527 
529 {
530  QgsLineStringV2* copy = clone();
531  std::reverse( copy->mX.begin(), copy->mX.end() );
532  std::reverse( copy->mY.begin(), copy->mY.end() );
533  if ( copy->is3D() )
534  {
535  std::reverse( copy->mZ.begin(), copy->mZ.end() );
536  }
537  if ( copy->isMeasure() )
538  {
539  std::reverse( copy->mM.begin(), copy->mM.end() );
540  }
541  return copy;
542 }
543 
544 /***************************************************************************
545  * This class is considered CRITICAL and any change MUST be accompanied with
546  * full unit tests.
547  * See details in QEP #17
548  ****************************************************************************/
549 
551 {
552  p.drawPolyline( asQPolygonF() );
553 }
554 
556 {
557  int nPoints = numPoints();
558  if ( nPoints < 1 )
559  {
560  return;
561  }
562 
563  if ( path.isEmpty() || path.currentPosition() != QPointF( mX.at( 0 ), mY.at( 0 ) ) )
564  {
565  path.moveTo( mX.at( 0 ), mY.at( 0 ) );
566  }
567 
568  for ( int i = 1; i < nPoints; ++i )
569  {
570  path.lineTo( mX.at( i ), mY.at( i ) );
571  }
572 }
573 
575 {
576  p.drawPolygon( asQPolygonF() );
577 }
578 
580 {
582  for ( int i = 0; i < mX.count(); ++i )
583  {
584  points << QPointF( mX.at( i ), mY.at( i ) );
585  }
586  return points;
587 }
588 
590 {
591  QgsCompoundCurveV2* compoundCurve = new QgsCompoundCurveV2();
592  compoundCurve->addCurve( clone() );
593  return compoundCurve;
594 }
595 
596 /***************************************************************************
597  * This class is considered CRITICAL and any change MUST be accompanied with
598  * full unit tests.
599  * See details in QEP #17
600  ****************************************************************************/
601 
603 {
604  double* zArray = mZ.data();
605 
606  bool hasZ = is3D();
607  int nPoints = numPoints();
608  bool useDummyZ = !hasZ || !transformZ;
609  if ( useDummyZ )
610  {
611  zArray = new double[nPoints];
612  for ( int i = 0; i < nPoints; ++i )
613  {
614  zArray[i] = 0;
615  }
616  }
617  ct.transformCoords( nPoints, mX.data(), mY.data(), zArray, d );
618  if ( useDummyZ )
619  {
620  delete[] zArray;
621  }
622  clearCache();
623 }
624 
626 {
627  int nPoints = numPoints();
628  for ( int i = 0; i < nPoints; ++i )
629  {
630  qreal x, y;
631  t.map( mX.at( i ), mY.at( i ), &x, &y );
632  mX[i] = x;
633  mY[i] = y;
634  }
635  clearCache();
636 }
637 
638 /***************************************************************************
639  * This class is considered CRITICAL and any change MUST be accompanied with
640  * full unit tests.
641  * See details in QEP #17
642  ****************************************************************************/
643 
644 bool QgsLineStringV2::insertVertex( QgsVertexId position, const QgsPointV2& vertex )
645 {
646  if ( position.vertex < 0 || position.vertex > mX.size() )
647  {
648  return false;
649  }
650 
651  if ( mWkbType == QgsWKBTypes::Unknown || mX.isEmpty() )
652  {
654  }
655 
656  mX.insert( position.vertex, vertex.x() );
657  mY.insert( position.vertex, vertex.y() );
658  if ( is3D() )
659  {
660  mZ.insert( position.vertex, vertex.z() );
661  }
662  if ( isMeasure() )
663  {
664  mM.insert( position.vertex, vertex.m() );
665  }
666  clearCache(); //set bounding box invalid
667  return true;
668 }
669 
670 bool QgsLineStringV2::moveVertex( QgsVertexId position, const QgsPointV2& newPos )
671 {
672  if ( position.vertex < 0 || position.vertex >= mX.size() )
673  {
674  return false;
675  }
676  mX[position.vertex] = newPos.x();
677  mY[position.vertex] = newPos.y();
678  if ( is3D() && newPos.is3D() )
679  {
680  mZ[position.vertex] = newPos.z();
681  }
682  if ( isMeasure() && newPos.isMeasure() )
683  {
684  mM[position.vertex] = newPos.m();
685  }
686  clearCache(); //set bounding box invalid
687  return true;
688 }
689 
691 {
692  if ( position.vertex >= mX.size() || position.vertex < 0 )
693  {
694  return false;
695  }
696 
697  mX.remove( position.vertex );
698  mY.remove( position.vertex );
699  if ( is3D() )
700  {
701  mZ.remove( position.vertex );
702  }
703  if ( isMeasure() )
704  {
705  mM.remove( position.vertex );
706  }
707 
708  if ( numPoints() == 1 )
709  {
710  clear();
711  }
712 
713  clearCache(); //set bounding box invalid
714  return true;
715 }
716 
717 /***************************************************************************
718  * This class is considered CRITICAL and any change MUST be accompanied with
719  * full unit tests.
720  * See details in QEP #17
721  ****************************************************************************/
722 
724 {
725  if ( mWkbType == QgsWKBTypes::Unknown || mX.isEmpty() )
726  {
728  }
729 
730  mX.append( pt.x() );
731  mY.append( pt.y() );
732  if ( is3D() )
733  {
734  mZ.append( pt.z() );
735  }
736  if ( isMeasure() )
737  {
738  mM.append( pt.m() );
739  }
740  clearCache(); //set bounding box invalid
741 }
742 
743 double QgsLineStringV2::closestSegment( const QgsPointV2& pt, QgsPointV2& segmentPt, QgsVertexId& vertexAfter, bool* leftOf, double epsilon ) const
744 {
745  double sqrDist = std::numeric_limits<double>::max();
746  double testDist = 0;
747  double segmentPtX, segmentPtY;
748 
749  int size = mX.size();
750  if ( size == 0 || size == 1 )
751  {
752  vertexAfter = QgsVertexId( 0, 0, 0 );
753  return -1;
754  }
755  for ( int i = 1; i < size; ++i )
756  {
757  double prevX = mX.at( i - 1 );
758  double prevY = mY.at( i - 1 );
759  double currentX = mX.at( i );
760  double currentY = mY.at( i );
761  testDist = QgsGeometryUtils::sqrDistToLine( pt.x(), pt.y(), prevX, prevY, currentX, currentY, segmentPtX, segmentPtY, epsilon );
762  if ( testDist < sqrDist )
763  {
764  sqrDist = testDist;
765  segmentPt.setX( segmentPtX );
766  segmentPt.setY( segmentPtY );
767  if ( leftOf )
768  {
769  *leftOf = ( QgsGeometryUtils::leftOfLine( pt.x(), pt.y(), prevX, prevY, currentX, currentY ) < 0 );
770  }
771  vertexAfter.part = 0;
772  vertexAfter.ring = 0;
773  vertexAfter.vertex = i;
774  }
775  }
776  return sqrDist;
777 }
778 
779 /***************************************************************************
780  * This class is considered CRITICAL and any change MUST be accompanied with
781  * full unit tests.
782  * See details in QEP #17
783  ****************************************************************************/
784 
785 bool QgsLineStringV2::pointAt( int node, QgsPointV2& point, QgsVertexId::VertexType& type ) const
786 {
787  if ( node < 0 || node >= numPoints() )
788  {
789  return false;
790  }
791  point = pointN( node );
793  return true;
794 }
795 
797 {
798  if ( mX.isEmpty() )
799  return QgsPointV2();
800 
801  int numPoints = mX.count();
802  if ( numPoints == 1 )
803  return QgsPointV2( mX.at( 0 ), mY.at( 0 ) );
804 
805  double totalLineLength = 0.0;
806  double prevX = mX.at( 0 );
807  double prevY = mY.at( 0 );
808  double sumX = 0.0;
809  double sumY = 0.0;
810 
811  for ( int i = 1; i < numPoints ; ++i )
812  {
813  double currentX = mX.at( i );
814  double currentY = mY.at( i );
815  double segmentLength = sqrt( qPow( currentX - prevX, 2.0 ) +
816  qPow( currentY - prevY, 2.0 ) );
817  if ( qgsDoubleNear( segmentLength, 0.0 ) )
818  continue;
819 
820  totalLineLength += segmentLength;
821  sumX += segmentLength * 0.5 * ( currentX + prevX );
822  sumY += segmentLength * 0.5 * ( currentY + prevY );
823  prevX = currentX;
824  prevY = currentY;
825  }
826 
827  if ( qgsDoubleNear( totalLineLength, 0.0 ) )
828  return QgsPointV2( mX.at( 0 ), mY.at( 0 ) );
829  else
830  return QgsPointV2( sumX / totalLineLength, sumY / totalLineLength );
831 
832 }
833 
834 /***************************************************************************
835  * This class is considered CRITICAL and any change MUST be accompanied with
836  * full unit tests.
837  * See details in QEP #17
838  ****************************************************************************/
839 
840 void QgsLineStringV2::sumUpArea( double& sum ) const
841 {
842  int maxIndex = numPoints() - 1;
843  if ( maxIndex == 1 )
844  return; //no area, just a single line
845 
846  for ( int i = 0; i < maxIndex; ++i )
847  {
848  sum += 0.5 * ( mX.at( i ) * mY.at( i + 1 ) - mY.at( i ) * mX.at( i + 1 ) );
849  }
850 }
851 
852 void QgsLineStringV2::importVerticesFromWkb( const QgsConstWkbPtr& wkb )
853 {
854  bool hasZ = is3D();
855  bool hasM = isMeasure();
856  int nVertices = 0;
857  wkb >> nVertices;
858  mX.resize( nVertices );
859  mY.resize( nVertices );
860  hasZ ? mZ.resize( nVertices ) : mZ.clear();
861  hasM ? mM.resize( nVertices ) : mM.clear();
862  for ( int i = 0; i < nVertices; ++i )
863  {
864  wkb >> mX[i];
865  wkb >> mY[i];
866  if ( hasZ )
867  {
868  wkb >> mZ[i];
869  }
870  if ( hasM )
871  {
872  wkb >> mM[i];
873  }
874  }
875  clearCache(); //set bounding box invalid
876 }
877 
878 /***************************************************************************
879  * This class is considered CRITICAL and any change MUST be accompanied with
880  * full unit tests.
881  * See details in QEP #17
882  ****************************************************************************/
883 
885 {
886  if ( numPoints() < 1 || isClosed() )
887  {
888  return;
889  }
890  addVertex( startPoint() );
891 }
892 
894 {
895  if ( mX.count() < 2 )
896  {
897  //undefined
898  return 0.0;
899  }
900 
901  if ( vertex.vertex == 0 || vertex.vertex >= ( numPoints() - 1 ) )
902  {
903  if ( isClosed() )
904  {
905  double previousX = mX.at( numPoints() - 2 );
906  double previousY = mY.at( numPoints() - 2 );
907  double currentX = mX.at( 0 );
908  double currentY = mY.at( 0 );
909  double afterX = mX.at( 1 );
910  double afterY = mY.at( 1 );
911  return QgsGeometryUtils::averageAngle( previousX, previousY, currentX, currentY, afterX, afterY );
912  }
913  else if ( vertex.vertex == 0 )
914  {
915  return QgsGeometryUtils::lineAngle( mX.at( 0 ), mY.at( 0 ), mX.at( 1 ), mY.at( 1 ) );
916  }
917  else
918  {
919  int a = numPoints() - 2;
920  int b = numPoints() - 1;
921  return QgsGeometryUtils::lineAngle( mX.at( a ), mY.at( a ), mX.at( b ), mY.at( b ) );
922  }
923  }
924  else
925  {
926  double previousX = mX.at( vertex.vertex - 1 );
927  double previousY = mY.at( vertex.vertex - 1 );
928  double currentX = mX.at( vertex.vertex );
929  double currentY = mY.at( vertex.vertex );
930  double afterX = mX.at( vertex.vertex + 1 );
931  double afterY = mY.at( vertex.vertex + 1 );
932  return QgsGeometryUtils::averageAngle( previousX, previousY, currentX, currentY, afterX, afterY );
933  }
934 }
935 
936 /***************************************************************************
937  * This class is considered CRITICAL and any change MUST be accompanied with
938  * full unit tests.
939  * See details in QEP #17
940  ****************************************************************************/
941 
942 bool QgsLineStringV2::addZValue( double zValue )
943 {
944  if ( QgsWKBTypes::hasZ( mWkbType ) )
945  return false;
946 
947  clearCache();
949  {
951  return true;
952  }
953 
955 
956  mZ.clear();
957  int nPoints = numPoints();
958  mZ.reserve( nPoints );
959  for ( int i = 0; i < nPoints; ++i )
960  {
961  mZ << zValue;
962  }
963  return true;
964 }
965 
966 bool QgsLineStringV2::addMValue( double mValue )
967 {
968  if ( QgsWKBTypes::hasM( mWkbType ) )
969  return false;
970 
971  clearCache();
973  {
975  return true;
976  }
977 
979  {
981  }
982  else
983  {
985  }
986 
987  mM.clear();
988  int nPoints = numPoints();
989  mM.reserve( nPoints );
990  for ( int i = 0; i < nPoints; ++i )
991  {
992  mM << mValue;
993  }
994  return true;
995 }
996 
998 {
999  if ( !is3D() )
1000  return false;
1001 
1002  clearCache();
1004  mZ.clear();
1005  return true;
1006 }
1007 
1009 {
1010  if ( !isMeasure() )
1011  return false;
1012 
1013  clearCache();
1015  mM.clear();
1016  return true;
1017 }
1018 
1020 {
1021  if ( type == mWkbType )
1022  return true;
1023 
1024  clearCache();
1025  if ( type == QgsWKBTypes::LineString25D )
1026  {
1027  //special handling required for conversion to LineString25D
1028  dropMValue();
1029  addZValue();
1031  return true;
1032  }
1033  else
1034  {
1035  return QgsCurveV2::convertTo( type );
1036  }
1037 }
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:757
static bool hasM(Type type)
Tests whether a WKB type contains m values.
Definition: qgswkbtypes.h:714
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]; }.
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)
static bool hasZ(Type type)
Tests whether a WKB type contains the z-dimension.
Definition: qgswkbtypes.h:667
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)
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
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.
QgsWKBTypes::Type readHeader() const
Definition: qgswkbptr.cpp:38
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: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:121
virtual bool addMValue(double mValue=0) override
Adds a measure to the geometry, initialized to a preset value.
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()
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.
Compound curve geometry type.
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: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
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
virtual bool isClosed() const
Returns true if the curve is closed.
Definition: qgscurvev2.cpp:29
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.
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
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.