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