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