QGIS API Documentation  2.10.1-Pisa
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgscompoundcurvev2.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgscompoundcurvev2.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 "qgscompoundcurvev2.h"
19 #include "qgsapplication.h"
20 #include "qgscircularstringv2.h"
21 #include "qgsgeometryutils.h"
22 #include "qgslinestringv2.h"
23 #include "qgswkbptr.h"
24 #include <QPainter>
25 #include <QPainterPath>
26 
27 
29 {
30 
31 }
32 
34 {
35  clear();
36 }
37 
39 {
40  foreach ( const QgsCurveV2* c, curve.mCurves )
41  {
42  mCurves.append( static_cast<QgsCurveV2*>( c->clone() ) );
43  }
44 }
45 
47 {
48  if ( &curve != this )
49  {
50  QgsCurveV2::operator=( curve );
51  foreach ( const QgsCurveV2* c, curve.mCurves )
52  {
53  mCurves.append( static_cast<QgsCurveV2*>( c->clone() ) );
54  }
55  }
56  return *this;
57 }
58 
60 {
61  return new QgsCompoundCurveV2( *this );
62 }
63 
65 {
66  qDeleteAll( mCurves );
67  mCurves.clear();
69 }
70 
72 {
73  if ( mCurves.size() < 1 )
74  {
75  return QgsRectangle();
76  }
77 
78  QgsRectangle bbox = mCurves.at( 0 )->calculateBoundingBox();
79  for ( int i = 1; i < mCurves.size(); ++i )
80  {
81  QgsRectangle curveBox = mCurves.at( i )->calculateBoundingBox();
82  bbox.combineExtentWith( &curveBox );
83  }
84  return bbox;
85 }
86 
87 bool QgsCompoundCurveV2::fromWkb( const unsigned char* wkb )
88 {
89  clear();
90  if ( !wkb )
91  {
92  return false;
93  }
94 
95  QgsConstWkbPtr wkbPtr( wkb );
96  QgsWKBTypes::Type type = wkbPtr.readHeader();
98  {
99  return false;
100  }
101  mWkbType = type;
102 
103  int nCurves;
104  wkbPtr >> nCurves;
105  QgsCurveV2* currentCurve = 0;
106  int currentCurveSize = 0;
107  for ( int i = 0; i < nCurves; ++i )
108  {
109  wkbPtr += 1; //skip endian
110  QgsWKBTypes::Type curveType;
111  wkbPtr >> curveType;
112  wkbPtr -= ( 1 + sizeof( int ) );
113  if ( QgsWKBTypes::flatType( curveType ) == QgsWKBTypes::LineString )
114  {
115  currentCurve = new QgsLineStringV2();
116  }
117  else if ( QgsWKBTypes::flatType( curveType ) == QgsWKBTypes::CircularString )
118  {
119  currentCurve = new QgsCircularStringV2();
120  }
121  else
122  {
123  return false;
124  }
125  currentCurve->fromWkb( wkbPtr );
126  currentCurveSize = currentCurve->wkbSize();
127  mCurves.append( currentCurve );
128  wkbPtr += currentCurveSize;
129  }
130  return true;
131 }
132 
134 {
135  clear();
136 
138 
139  if ( QgsWKBTypes::flatType( parts.first ) != QgsWKBTypes::parseType( geometryType() ) )
140  return false;
141  mWkbType = parts.first;
142 
143  QString defaultChildWkbType = QString( "LineString%1%2" ).arg( is3D() ? "Z" : "" ).arg( isMeasure() ? "M" : "" );
144 
145  foreach ( const QString& childWkt, QgsGeometryUtils::wktGetChildBlocks( parts.second, defaultChildWkbType ) )
146  {
148 
149  if ( QgsWKBTypes::flatType( childParts.first ) == QgsWKBTypes::LineString )
150  mCurves.append( new QgsLineStringV2() );
151  else if ( QgsWKBTypes::flatType( childParts.first ) == QgsWKBTypes::CircularString )
152  mCurves.append( new QgsCircularStringV2() );
153  else
154  {
155  clear();
156  return false;
157  }
158  if ( !mCurves.back()->fromWkt( childWkt ) )
159  {
160  clear();
161  return false;
162  }
163  }
164  return true;
165 }
166 
168 {
169  int size = sizeof( char ) + sizeof( quint32 ) + sizeof( quint32 );
170  foreach ( const QgsCurveV2 *curve, mCurves )
171  {
172  size += curve->wkbSize();
173  }
174  return size;
175 }
176 
177 unsigned char* QgsCompoundCurveV2::asWkb( int& binarySize ) const
178 {
179  binarySize = wkbSize();
180  unsigned char* geomPtr = new unsigned char[binarySize];
181  QgsWkbPtr wkb( geomPtr );
182  wkb << static_cast<char>( QgsApplication::endian() );
183  wkb << static_cast<quint32>( wkbType() );
184  wkb << static_cast<quint32>( mCurves.size() );
185  foreach ( const QgsCurveV2* curve, mCurves )
186  {
187  int curveWkbLen = 0;
188  unsigned char* curveWkb = curve->asWkb( curveWkbLen );
189  memcpy( wkb, curveWkb, curveWkbLen );
190  wkb += curveWkbLen;
191  delete[] curveWkb;
192  }
193  return geomPtr;
194 }
195 
196 QString QgsCompoundCurveV2::asWkt( int precision ) const
197 {
198  QString wkt = wktTypeStr() + " (";
199  foreach ( const QgsCurveV2* curve, mCurves )
200  {
201  QString childWkt = curve->asWkt( precision );
202  if ( dynamic_cast<const QgsLineStringV2*>( curve ) )
203  {
204  // Type names of linear geometries are omitted
205  childWkt = childWkt.mid( childWkt.indexOf( "(" ) );
206  }
207  wkt += childWkt + ",";
208  }
209  if ( wkt.endsWith( "," ) )
210  {
211  wkt.chop( 1 );
212  }
213  wkt += ")";
214  return wkt;
215 }
216 
217 QDomElement QgsCompoundCurveV2::asGML2( QDomDocument& doc, int precision, const QString& ns ) const
218 {
219  // GML2 does not support curves
220  QgsLineStringV2* line = curveToLine();
221  QDomElement gml = line->asGML2( doc, precision, ns );
222  delete line;
223  return gml;
224 }
225 
226 QDomElement QgsCompoundCurveV2::asGML3( QDomDocument& doc, int precision, const QString& ns ) const
227 {
228  QDomElement elemCurve = doc.createElementNS( ns, "Curve" );
229 
230  QDomElement elemSegments = doc.createElementNS( ns, "segments" );
231 
232  foreach ( const QgsCurveV2* curve, mCurves )
233  {
234  if ( dynamic_cast<const QgsLineStringV2*>( curve ) )
235  {
236  QList<QgsPointV2> pts;
237  curve->points( pts );
238 
239  QDomElement elemLineStringSegment = doc.createElementNS( ns, "LineStringSegment" );
240  elemLineStringSegment.appendChild( QgsGeometryUtils::pointsToGML3( pts, doc, precision, ns, is3D() ) );
241  elemSegments.appendChild( elemLineStringSegment );
242  }
243  else if ( dynamic_cast<const QgsCircularStringV2*>( curve ) )
244  {
245  QList<QgsPointV2> pts;
246  curve->points( pts );
247 
248  QDomElement elemArcString = doc.createElementNS( ns, "ArcString" );
249  elemArcString.appendChild( QgsGeometryUtils::pointsToGML3( pts, doc, precision, ns, is3D() ) );
250  elemSegments.appendChild( elemArcString );
251  }
252  }
253  elemCurve.appendChild( elemSegments );
254  return elemCurve;
255 }
256 
257 QString QgsCompoundCurveV2::asJSON( int precision ) const
258 {
259  // GeoJSON does not support curves
260  QgsLineStringV2* line = curveToLine();
261  QString json = line->asJSON( precision );
262  delete line;
263  return json;
264 }
265 
267 {
268  double length = 0;
270  for ( ; curveIt != mCurves.constEnd(); ++curveIt )
271  {
272  length += ( *curveIt )->length();
273  }
274  return length;
275 }
276 
278 {
279  if ( mCurves.size() < 1 )
280  {
281  return QgsPointV2();
282  }
283  return mCurves.at( 0 )->startPoint();
284 }
285 
287 {
288  if ( mCurves.size() < 1 )
289  {
290  return QgsPointV2();
291  }
292  return mCurves.at( mCurves.size() - 1 )->endPoint();
293 }
294 
296 {
297  pts.clear();
298  if ( mCurves.size() < 1 )
299  {
300  return;
301  }
302 
303  mCurves[0]->points( pts );
304  for ( int i = 1; i < mCurves.size(); ++i )
305  {
306  QList<QgsPointV2> pList;
307  mCurves[i]->points( pList );
308  pList.removeFirst(); //first vertex already added in previous line
309  pts.append( pList );
310  }
311 }
312 
314 {
315  int nPoints = 0;
316  int nCurves = mCurves.size();
317  for ( int i = 0; i < nCurves; ++i )
318  {
319  nPoints += mCurves.at( i )->numPoints() - 1; //last vertex is equal to first of next section
320  }
321  nPoints += 1; //last vertex was removed above
322  return nPoints;
323 }
324 
326 {
328  QgsLineStringV2* line = new QgsLineStringV2();
329  QgsLineStringV2* currentLine = 0;
330  for ( ; curveIt != mCurves.constEnd(); ++curveIt )
331  {
332  currentLine = ( *curveIt )->curveToLine();
333  line->append( currentLine );
334  delete currentLine;
335  }
336  return line;
337 }
338 
340 {
341  if ( i >= mCurves.size() )
342  {
343  return 0;
344  }
345  return mCurves.at( i );
346 }
347 
349 {
350  if ( c )
351  {
352  mCurves.append( c );
353 
355  {
357  }
358  }
359 }
360 
362 {
363  if ( mCurves.size() - 1 < i )
364  {
365  return;
366  }
367 
368  delete( mCurves[i] );
369  mCurves.removeAt( i );
370 }
371 
373 {
375  {
377  }
378 
379  //is last curve QgsLineStringV2
380  QgsCurveV2* lastCurve = 0;
381  if ( mCurves.size() > 0 )
382  {
383  lastCurve = mCurves.at( mCurves.size() - 1 );
384  }
385 
386  QgsLineStringV2* line = 0;
387  if ( !lastCurve || lastCurve->geometryType() != "LineString" )
388  {
389  line = new QgsLineStringV2();
390  mCurves.append( line );
391  if ( lastCurve )
392  {
393  line->addVertex( lastCurve->endPoint() );
394  }
395  lastCurve = line;
396  }
397  else //create new QgsLineStringV2* with point in it
398  {
399  line = static_cast<QgsLineStringV2*>( lastCurve );
400  }
401  line->addVertex( pt );
402 }
403 
405 {
407  for ( ; it != mCurves.constEnd(); ++it )
408  {
409  ( *it )->draw( p );
410  }
411 }
412 
414 {
415  QList< QgsCurveV2* >::iterator it = mCurves.begin();
416  for ( ; it != mCurves.end(); ++it )
417  {
418  ( *it )->transform( ct );
419  }
420 }
421 
423 {
424  QList< QgsCurveV2* >::iterator it = mCurves.begin();
425  for ( ; it != mCurves.end(); ++it )
426  {
427  ( *it )->transform( t );
428  }
429 }
430 
432 {
433  QPainterPath pp;
435  for ( ; it != mCurves.constEnd(); ++it )
436  {
437  ( *it )->addToPainterPath( pp );
438  }
439  path.addPath( pp );
440 }
441 
443 {
444  QPainterPath pp;
446  for ( ; it != mCurves.constEnd(); ++it )
447  {
448  ( *it )->addToPainterPath( pp );
449  }
450  p.drawPath( pp );
451 }
452 
453 bool QgsCompoundCurveV2::insertVertex( const QgsVertexId& position, const QgsPointV2& vertex )
454 {
455  QList< QPair<int, QgsVertexId> > curveIds = curveVertexId( position );
456  if ( curveIds.size() < 1 )
457  {
458  return false;
459  }
460  int curveId = curveIds.at( 0 ).first;
461  if ( curveId >= mCurves.size() )
462  {
463  return false;
464  }
465  return mCurves[curveId]->insertVertex( curveIds.at( 0 ).second, vertex );
466 }
467 
468 bool QgsCompoundCurveV2::moveVertex( const QgsVertexId& position, const QgsPointV2& newPos )
469 {
470  QList< QPair<int, QgsVertexId> > curveIds = curveVertexId( position );
471  QList< QPair<int, QgsVertexId> >::const_iterator idIt = curveIds.constBegin();
472  for ( ; idIt != curveIds.constEnd(); ++idIt )
473  {
474  mCurves[idIt->first]->moveVertex( idIt->second, newPos );
475  }
476  mBoundingBox = QgsRectangle(); //bbox changed
477  return curveIds.size() > 0;
478 }
479 
481 {
482  QList< QPair<int, QgsVertexId> > curveIds = curveVertexId( position );
483  QList< QPair<int, QgsVertexId> >::const_iterator idIt = curveIds.constBegin();
484  for ( ; idIt != curveIds.constEnd(); ++idIt )
485  {
486  mCurves[idIt->first]->deleteVertex( idIt->second );
487  }
488  return curveIds.size() > 0;
489 }
490 
491 QList< QPair<int, QgsVertexId> > QgsCompoundCurveV2::curveVertexId( const QgsVertexId& id ) const
492 {
494 
495  int currentVertexIndex = 0;
496  for ( int i = 0; i < mCurves.size(); ++i )
497  {
498  int increment = mCurves.at( i )->numPoints() - 1;
499  if ( id.vertex >= currentVertexIndex && id.vertex <= currentVertexIndex + increment )
500  {
501  int curveVertexId = id.vertex - currentVertexIndex;
502  QgsVertexId vid; vid.part = 0; vid.ring = 0; vid.vertex = curveVertexId;
503  curveIds.append( qMakePair( i, vid ) );
504  if ( curveVertexId == increment && i < ( mCurves.size() - 1 ) ) //add first vertex of next curve
505  {
506  vid.vertex = 0;
507  curveIds.append( qMakePair( i + 1, vid ) );
508  }
509  }
510  currentVertexIndex += increment;
511  }
512 
513  return curveIds;
514 }
515 
516 double QgsCompoundCurveV2::closestSegment( const QgsPointV2& pt, QgsPointV2& segmentPt, QgsVertexId& vertexAfter, bool* leftOf, double epsilon ) const
517 {
518  return QgsGeometryUtils::closestSegmentFromComponents( mCurves, QgsGeometryUtils::VERTEX, pt, segmentPt, vertexAfter, leftOf, epsilon );
519 }
520 
522 {
523  int currentVertexId = 0;
524  for ( int j = 0; j < mCurves.size(); ++j )
525  {
526  int nCurvePoints = mCurves.at( j )->numPoints();
527  if (( i - currentVertexId ) < nCurvePoints )
528  {
529  return ( mCurves.at( j )->pointAt( i - currentVertexId, vertex, type ) );
530  }
531  currentVertexId += ( nCurvePoints - 1 );
532  }
533  return false;
534 }
535 
536 void QgsCompoundCurveV2::sumUpArea( double& sum ) const
537 {
539  for ( ; curveIt != mCurves.constEnd(); ++curveIt )
540  {
541  ( *curveIt )->sumUpArea( sum );
542  }
543 }
544 
546 {
547  if ( numPoints() < 1 || isClosed() )
548  {
549  return;
550  }
551  addVertex( startPoint() );
552 }
553 
555 {
557  for ( ; curveIt != mCurves.constEnd(); ++curveIt )
558  {
559  if (( *curveIt )->hasCurvedSegments() )
560  {
561  return true;
562  }
563  }
564  return false;
565 }
566 
void addPath(const QPainterPath &path)
void clear()
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
QgsWKBTypes::Type wkbType() const
Returns the WKB type of the geometry.
A rectangle specified with double values.
Definition: qgsrectangle.h:35
QDomElement asGML2(QDomDocument &doc, int precision=17, const QString &ns="gml") const override
Returns a GML2 representation of the geometry.
void transform(const QgsCoordinateTransform &ct) override
Transforms the geometry using a coordinate transform.
virtual QgsLineStringV2 * curveToLine() const override
Returns a new line string geometry corresponding to a segmentized approximation of the curve...
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 (...
void close()
Appends first point if not already closed.
virtual QgsAbstractGeometryV2 & operator=(const QgsAbstractGeometryV2 &geom)
QDomNode appendChild(const QDomNode &newChild)
bool pointAt(int i, QgsPointV2 &vertex, QgsVertexId::VertexType &type) const override
Returns the point and vertex id of a point within the curve.
bool hasCurvedSegments() const override
Returns true if the geometry contains curved segments.
Circular string geometry type.
virtual void points(QList< QgsPointV2 > &pt) const =0
Returns a list of points within the curve.
virtual QgsPointV2 endPoint() const override
Returns the end point of the curve.
virtual bool deleteVertex(const QgsVertexId &position) override
Deletes a vertex within the geometry.
virtual QgsPointV2 startPoint() const override
Returns the starting point of the curve.
void removeFirst()
const T & at(int i) const
void removeAt(int i)
QDomElement asGML2(QDomDocument &doc, int precision=17, const QString &ns="gml") const override
Returns a GML2 representation of the geometry.
virtual bool insertVertex(const QgsVertexId &position, const QgsPointV2 &vertex) override
Inserts a vertex into the geometry.
Abstract base class for all geometries.
static QStringList wktGetChildBlocks(const QString &wkt, const QString &defaultType="")
Parses a WKT string and returns of list of blocks contained in the WKT.
unsigned char * asWkb(int &binarySize) const override
Returns a WKB representation of the geometry.
static double closestSegmentFromComponents(T &container, componentType ctype, const QgsPointV2 &pt, QgsPointV2 &segmentPt, QgsVertexId &vertexAfter, bool *leftOf, double epsilon)
virtual QgsRectangle calculateBoundingBox() const override
Calculates the minimal bounding box for the geometry.
void append(const QgsLineStringV2 *line)
void sumUpArea(double &sum) const override
Calculates the area of the curve.
QDomElement createElementNS(const QString &nsURI, const QString &qName)
void chop(int n)
void addToPainterPath(QPainterPath &path) const override
Adds a curve to a painter path.
static endian_t endian()
Returns whether this machine uses big or little endian.
QString wktTypeStr() const
Returns the WKT type string of the geometry.
virtual int wkbSize() const =0
Returns the size of the WKB representation of the geometry.
QgsCompoundCurveV2 & operator=(const QgsCompoundCurveV2 &curve)
void removeCurve(int i)
Removes a curve from the geometry.
int size() const
virtual QgsLineStringV2 * curveToLine() const override
Returns a new line string geometry corresponding to a segmentized approximation of the curve...
QgsWKBTypes::Type readHeader() const
Definition: qgswkbptr.cpp:8
static Type flatType(Type type)
Definition: qgswkbtypes.cpp:46
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
void combineExtentWith(QgsRectangle *rect)
expand the rectangle so that covers both the original rectangle and the given rectangle ...
void append(const T &value)
Utility class for identifying a unique vertex within a geometry.
bool isMeasure() const
Returns true if the geometry contains m values.
void drawAsPolygon(QPainter &p) const override
Draws the curve as a polygon on the specified QPainter.
Line string geometry type.
void draw(QPainter &p) const override
Draws the geometry using the specified QPainter.
virtual QString geometryType() const override
Returns a unique string representing the geometry type.
void addVertex(const QgsPointV2 &pt)
Adds a vertex to the end of the geometry.
virtual bool fromWkb(const unsigned char *wkb)=0
Sets the geometry from a WKB string.
Point geometry type.
Definition: qgspointv2.h:29
QString asJSON(int precision=17) const override
Returns a GeoJSON representation of the geometry.
QString asWkt(int precision=17) const override
Returns a WKT representation of the geometry.
virtual unsigned char * asWkb(int &binarySize) const =0
Returns a WKB representation of the geometry.
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const
const QgsCurveV2 * curveAt(int i) const
Returns the curve at the specified index.
void setZMTypeFromSubGeometry(const QgsAbstractGeometryV2 *subggeom, QgsWKBTypes::Type baseGeomType)
Updates the geometry type based on whether sub geometries contain z or m values.
T & first()
QString asJSON(int precision=17) const override
Returns a GeoJSON representation of the geometry.
Compound curve geometry type.
iterator end()
static QDomElement pointsToGML3(const QList< QgsPointV2 > &points, QDomDocument &doc, int precision, const QString &ns, bool is3D)
Returns a gml::posList DOM element.
virtual QString geometryType() const =0
Returns a unique string representing the geometry type.
void addCurve(QgsCurveV2 *c)
Adds a curve to the geometr (takes ownership)
void addVertex(const QgsPointV2 &pt)
virtual QgsPointV2 endPoint() const =0
Returns the end point of the curve.
QString mid(int position, int n) const
void drawPath(const QPainterPath &path)
virtual bool fromWkt(const QString &wkt) override
Sets the geometry from a WKT string.
virtual bool moveVertex(const QgsVertexId &position, const QgsPointV2 &newPos) override
Moves a vertex within the geometry.
virtual bool isClosed() const
Returns true if the curve is closed.
Definition: qgscurvev2.cpp:27
int wkbSize() const override
Returns the size of the WKB representation of the geometry.
virtual void points(QList< QgsPointV2 > &pts) const override
Returns a list of points within the curve.
Class for doing transforms between two map coordinate systems.
virtual QString asWkt(int precision=17) const =0
Returns a WKT representation of the geometry.
virtual 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 parseType(const QString &wktStr)
Definition: qgswkbtypes.cpp:56
double ANALYSIS_EXPORT leftOf(Point3D *thepoint, Point3D *p1, Point3D *p2)
Returns whether 'thepoint' is left or right of the line from 'p1' to 'p2'.
virtual QgsAbstractGeometryV2 * clone() const override
Clones the geometry by performing a deep copy.
const_iterator constEnd() const
const_iterator constBegin() const
virtual QgsAbstractGeometryV2 * clone() const =0
Clones the geometry by performing a deep copy.
Abstract base class for curved geometry type.
Definition: qgscurvev2.h:32
virtual bool fromWkb(const unsigned char *wkb) override
Sets the geometry from a WKB string.
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
virtual int numPoints() const override
Returns the number of points in the curve.
QDomElement asGML3(QDomDocument &doc, int precision=17, const QString &ns="gml") const override
Returns a GML3 representation of the geometry.
virtual double length() const override
Returns the length (or perimeter for area geometries) of the geometry.
T & back()
int nCurves() const
Returns the number of curves in the geometry.
iterator begin()
virtual void clear() override
Clears the geometry, ie reset it to a null geometry.