QGIS API Documentation  2.12.0-Lyon
qgsgeometrycollectionv2.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsgeometrycollectionv2.cpp
3  -------------------------------------------------------------------
4 Date : 28 Oct 2014
5 Copyright : (C) 2014 by Marco Hugentobler
6 email : marco.hugentobler at sourcepole dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
17 #include "qgsapplication.h"
18 #include "qgsgeometryfactory.h"
19 #include "qgsgeometryutils.h"
20 #include "qgscircularstringv2.h"
21 #include "qgscompoundcurvev2.h"
22 #include "qgslinestringv2.h"
23 #include "qgsmultilinestringv2.h"
24 #include "qgspointv2.h"
25 #include "qgsmultipointv2.h"
26 #include "qgspolygonv2.h"
27 #include "qgsmultipolygonv2.h"
28 #include "qgswkbptr.h"
29 
31 {
33 }
34 
36 {
37  int nGeoms = c.mGeometries.size();
38  mGeometries.resize( nGeoms );
39  for ( int i = 0; i < nGeoms; ++i )
40  {
41  mGeometries[i] = c.mGeometries.at( i )->clone();
42  }
43 }
44 
46 {
47  if ( &c != this )
48  {
50  int nGeoms = c.mGeometries.size();
51  mGeometries.resize( nGeoms );
52  for ( int i = 0; i < nGeoms; ++i )
53  {
54  mGeometries[i] = c.mGeometries.at( i )->clone();
55  }
56  }
57  return *this;
58 }
59 
61 {
62  clear();
63 }
64 
66 {
67  return new QgsGeometryCollectionV2( *this );
68 }
69 
71 {
72  qDeleteAll( mGeometries );
75 }
76 
78 {
79  return mGeometries.size();
80 }
81 
83 {
84  if ( n >= mGeometries.size() )
85  {
86  return 0;
87  }
88  return mGeometries.at( n );
89 }
90 
92 {
93  if ( n >= mGeometries.size() )
94  {
95  return 0;
96  }
97  return mGeometries.at( n );
98 }
99 
101 {
102  if ( !g )
103  {
104  return false;
105  }
106 
107  mGeometries.append( g );
108  return true;
109 }
110 
112 {
113  if ( !g )
114  {
115  return false;
116  }
117 
118  mGeometries.insert( index, g );
119  return true;
120 }
121 
123 {
124  if ( nr >= mGeometries.size() || nr < 0 )
125  {
126  return false;
127  }
128  delete mGeometries[nr];
129  mGeometries.remove( nr );
130  return true;
131 }
132 
134 {
135  int maxDim = 0;
137  for ( ; it != mGeometries.constEnd(); ++it )
138  {
139  int dim = ( *it )->dimension();
140  if ( dim > maxDim )
141  {
142  maxDim = dim;
143  }
144  }
145  return maxDim;
146 }
147 
149 {
151  for ( ; it != mGeometries.end(); ++it )
152  {
153  ( *it )->transform( ct, d );
154  }
155 }
156 
158 {
160  for ( ; it != mGeometries.end(); ++it )
161  {
162  ( *it )->transform( t );
163  }
164 }
165 
166 #if 0
167 void QgsGeometryCollectionV2::clip( const QgsRectangle& rect )
168 {
170  for ( ; it != mGeometries.end(); ++it )
171  {
172  ( *it )->clip( rect );
173  }
174 }
175 #endif
176 
178 {
180  for ( ; it != mGeometries.constEnd(); ++it )
181  {
182  ( *it )->draw( p );
183  }
184 }
185 
186 bool QgsGeometryCollectionV2::fromWkb( const unsigned char * wkb )
187 {
188  if ( !wkb )
189  {
190  return false;
191  }
192  QgsConstWkbPtr wkbPtr( wkb + 1 );
193  //type
194  wkbPtr >> mWkbType;
195  int nGeometries = 0;
196  wkbPtr >> nGeometries;
197 
198  QList<QgsAbstractGeometryV2*> geometryList;
199  for ( int i = 0; i < nGeometries; ++i )
200  {
202  if ( geom )
203  {
204  geometryList.append( geom );
205  wkbPtr += geom->wkbSize();
206  }
207  }
208 
209  mGeometries.resize( geometryList.size() );
210  for ( int i = 0; i < geometryList.size(); ++i )
211  {
212  mGeometries[i] = geometryList.at( i );
213  }
214 
215  return true;
216 }
217 
219 {
223  << new QgsMultiPolygonV2 << new QgsGeometryCollectionV2, "GeometryCollection" );
224 }
225 
227 {
228  int size = sizeof( char ) + sizeof( quint32 ) + sizeof( quint32 );
229  Q_FOREACH ( const QgsAbstractGeometryV2 *geom, mGeometries )
230  {
231  if ( geom )
232  {
233  size += geom->wkbSize();
234  }
235  }
236  return size;
237 }
238 
239 unsigned char* QgsGeometryCollectionV2::asWkb( int& binarySize ) const
240 {
241  binarySize = wkbSize();
242  unsigned char* geomPtr = new unsigned char[binarySize];
243  QgsWkbPtr wkb( geomPtr );
244  wkb << static_cast<char>( QgsApplication::endian() );
245  wkb << static_cast<quint32>( wkbType() );
246  wkb << static_cast<quint32>( mGeometries.size() );
247  Q_FOREACH ( const QgsAbstractGeometryV2 *geom, mGeometries )
248  {
249  int geomWkbLen = 0;
250  if ( geom )
251  {
252  unsigned char* geomWkb = geom->asWkb( geomWkbLen );
253  memcpy( wkb, geomWkb, geomWkbLen );
254  wkb += geomWkbLen;
255  delete[] geomWkb;
256  }
257  }
258  return geomPtr;
259 }
260 
262 {
263  QString wkt = wktTypeStr() + " (";
264  Q_FOREACH ( const QgsAbstractGeometryV2 *geom, mGeometries )
265  {
266  QString childWkt = geom->asWkt( precision );
267  if ( wktOmitChildType() )
268  {
269  childWkt = childWkt.mid( childWkt.indexOf( "(" ) );
270  }
271  wkt += childWkt + ",";
272  }
273  if ( wkt.endsWith( "," ) )
274  {
275  wkt.chop( 1 ); // Remove last ","
276  }
277  wkt += ")";
278  return wkt;
279 }
280 
281 QDomElement QgsGeometryCollectionV2::asGML2( QDomDocument& doc, int precision, const QString& ns ) const
282 {
283  QDomElement elemMultiGeometry = doc.createElementNS( ns, "MultiGeometry" );
284  Q_FOREACH ( const QgsAbstractGeometryV2 *geom, mGeometries )
285  {
286  QDomElement elemGeometryMember = doc.createElementNS( ns, "geometryMember" );
287  elemGeometryMember.appendChild( geom->asGML2( doc, precision, ns ) );
288  elemMultiGeometry.appendChild( elemGeometryMember );
289  }
290  return elemMultiGeometry;
291 }
292 
293 QDomElement QgsGeometryCollectionV2::asGML3( QDomDocument& doc, int precision, const QString& ns ) const
294 {
295  QDomElement elemMultiGeometry = doc.createElementNS( ns, "MultiGeometry" );
296  Q_FOREACH ( const QgsAbstractGeometryV2 *geom, mGeometries )
297  {
298  QDomElement elemGeometryMember = doc.createElementNS( ns, "geometryMember" );
299  elemGeometryMember.appendChild( geom->asGML3( doc, precision, ns ) );
300  elemMultiGeometry.appendChild( elemGeometryMember );
301  }
302  return elemMultiGeometry;
303 }
304 
306 {
307  QString json = "{\"type\": \"GeometryCollection\", \"geometries\": [";
308  Q_FOREACH ( const QgsAbstractGeometryV2 *geom, mGeometries )
309  {
310  json += geom->asJSON( precision ) + ", ";
311  }
312  if ( json.endsWith( ", " ) )
313  {
314  json.chop( 2 ); // Remove last ", "
315  }
316  json += "] }";
317  return json;
318 }
319 
321 {
322  if ( mGeometries.size() < 1 )
323  {
324  return QgsRectangle();
325  }
326 
327  QgsRectangle bbox = mGeometries.at( 0 )->calculateBoundingBox();
328  for ( int i = 1; i < mGeometries.size(); ++i )
329  {
330  QgsRectangle geomBox = mGeometries.at( i )->calculateBoundingBox();
331  bbox.combineExtentWith( &geomBox );
332  }
333  return bbox;
334 }
335 
337 {
338  coord.clear();
340  for ( ; geomIt != mGeometries.constEnd(); ++geomIt )
341  {
342  QList< QList< QList< QgsPointV2 > > > geomCoords;
343  ( *geomIt )->coordinateSequence( geomCoords );
344  QList< QList< QList< QgsPointV2 > > >::const_iterator cIt = geomCoords.constBegin();
345  for ( ; cIt != geomCoords.constEnd(); ++cIt )
346  {
347  coord.push_back( *cIt );
348  }
349  }
350 }
351 
352 double QgsGeometryCollectionV2::closestSegment( const QgsPointV2& pt, QgsPointV2& segmentPt, QgsVertexId& vertexAfter, bool* leftOf, double epsilon ) const
353 {
354  return QgsGeometryUtils::closestSegmentFromComponents( mGeometries, QgsGeometryUtils::PART, pt, segmentPt, vertexAfter, leftOf, epsilon );
355 }
356 
358 {
359  if ( id.part < 0 )
360  {
361  id.part = 0; id.ring = -1; id.vertex = -1;
362  }
363 
364  QgsAbstractGeometryV2* geom = mGeometries.at( id.part );
365  if ( geom->nextVertex( id, vertex ) )
366  {
367  return true;
368  }
369  if (( id.part + 1 ) >= numGeometries() )
370  {
371  return false;
372  }
373  ++id.part; id.ring = -1; id.vertex = -1;
374  return mGeometries.at( id.part )->nextVertex( id, vertex );
375 }
376 
377 bool QgsGeometryCollectionV2::insertVertex( const QgsVertexId& position, const QgsPointV2& vertex )
378 {
379  if ( position.part >= mGeometries.size() )
380  {
381  return false;
382  }
383 
384  bool success = mGeometries[position.part]->insertVertex( position, vertex );
385  if ( success )
386  {
387  mBoundingBox = QgsRectangle(); //set bounding box invalid
388  }
389  return success;
390 }
391 
392 bool QgsGeometryCollectionV2::moveVertex( const QgsVertexId& position, const QgsPointV2& newPos )
393 {
394  if ( position.part >= mGeometries.size() )
395  {
396  return false;
397  }
398 
399  bool success = mGeometries[position.part]->moveVertex( position, newPos );
400  if ( success )
401  {
402  mBoundingBox = QgsRectangle(); //set bounding box invalid
403  }
404  return success;
405 }
406 
408 {
409  if ( position.part >= mGeometries.size() )
410  {
411  return false;
412  }
413 
414  QgsAbstractGeometryV2* geom = mGeometries[position.part];
415  if ( !geom )
416  {
417  return false;
418  }
419 
420  bool success = geom->deleteVertex( position );
421 
422  //remove geometry if no vertices left
423  if ( geom->isEmpty() )
424  {
425  removeGeometry( position.part );
426  }
427 
428  if ( success )
429  {
430  mBoundingBox = QgsRectangle(); //set bounding box invalid
431  }
432  return success;
433 }
434 
436 {
437  double length = 0.0;
439  for ( ; geomIt != mGeometries.constEnd(); ++geomIt )
440  {
441  length += ( *geomIt )->length();
442  }
443  return length;
444 }
445 
447 {
448  double area = 0.0;
450  for ( ; geomIt != mGeometries.constEnd(); ++geomIt )
451  {
452  area += ( *geomIt )->area();
453  }
454  return area;
455 }
456 
458 {
459  double perimeter = 0.0;
461  for ( ; geomIt != mGeometries.constEnd(); ++geomIt )
462  {
463  perimeter += ( *geomIt )->perimeter();
464  }
465  return perimeter;
466 }
467 
468 bool QgsGeometryCollectionV2::fromCollectionWkt( const QString &wkt, const QList<QgsAbstractGeometryV2*>& subtypes, const QString& defaultChildWkbType )
469 {
470  clear();
471 
473 
474  if ( QgsWKBTypes::flatType( parts.first ) != QgsWKBTypes::parseType( geometryType() ) )
475  return false;
476  mWkbType = parts.first;
477 
478  QString defChildWkbType = QString( "%1%2%3 " ).arg( defaultChildWkbType, is3D() ? "Z" : "", isMeasure() ? "M" : "" );
479 
480  Q_FOREACH ( const QString& childWkt, QgsGeometryUtils::wktGetChildBlocks( parts.second, defChildWkbType ) )
481  {
483 
484  bool success = false;
485  Q_FOREACH ( const QgsAbstractGeometryV2* geom, subtypes )
486  {
487  if ( QgsWKBTypes::flatType( childParts.first ) == QgsWKBTypes::parseType( geom->geometryType() ) )
488  {
489  mGeometries.append( geom->clone() );
490  if ( mGeometries.back()->fromWkt( childWkt ) )
491  {
492  success = true;
493  break;
494  }
495  }
496  }
497  if ( !success )
498  {
499  clear();
500  qDeleteAll( subtypes );
501  return false;
502  }
503  }
504  qDeleteAll( subtypes );
505 
506  //scan through geometries and check if dimensionality of geometries is different to collection.
507  //if so, update the type dimensionality of the collection to match
508  bool hasZ = false;
509  bool hasM = false;
510  Q_FOREACH ( QgsAbstractGeometryV2* geom, mGeometries )
511  {
512  hasZ = hasZ || geom->is3D();
513  hasM = hasM || geom->isMeasure();
514  if ( hasZ && hasM )
515  break;
516  }
517  if ( hasZ )
518  addZValue( 0 );
519  if ( hasM )
520  addMValue( 0 );
521 
522  return true;
523 }
524 
526 {
528  for ( ; it != mGeometries.constEnd(); ++it )
529  {
530  if (( *it )->hasCurvedSegments() )
531  {
532  return true;
533  }
534  }
535  return false;
536 }
537 
539 {
541  QgsGeometryCollectionV2* geomCollection = dynamic_cast<QgsGeometryCollectionV2*>( geom );
542  if ( !geomCollection )
543  {
544  delete geom; return clone();
545  }
546 
548  for ( ; geomIt != mGeometries.constEnd(); ++geomIt )
549  {
550  geomCollection->addGeometry(( *geomIt )->segmentize() );
551  }
552  return geomCollection;
553 }
554 
556 {
557  if ( vertex.part >= mGeometries.size() )
558  {
559  return 0.0;
560  }
561 
562  QgsAbstractGeometryV2* geom = mGeometries[vertex.part];
563  if ( !geom )
564  {
565  return 0.0;
566  }
567 
568  return geom->vertexAngle( vertex );
569 }
570 
572 {
573  if ( QgsWKBTypes::hasZ( mWkbType ) )
574  return false;
575 
577 
578  Q_FOREACH ( QgsAbstractGeometryV2* geom, mGeometries )
579  {
580  geom->addZValue( zValue );
581  }
582  return true;
583 }
584 
586 {
587  if ( QgsWKBTypes::hasM( mWkbType ) )
588  return false;
589 
591 
592  Q_FOREACH ( QgsAbstractGeometryV2* geom, mGeometries )
593  {
594  geom->addMValue( mValue );
595  }
596  return true;
597 }
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
bool fromWkb(const unsigned char *wkb) override
Sets the geometry from a WKB string.
static unsigned index
QgsWKBTypes::Type wkbType() const
Returns the WKB type of the geometry.
A rectangle specified with double values.
Definition: qgsrectangle.h:35
virtual double vertexAngle(const QgsVertexId &vertex) const =0
Returns approximate rotation angle for a vertex.
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 (...
virtual void coordinateSequence(QList< QList< QList< QgsPointV2 > > > &coord) const override
Retrieves the sequence of geometries, rings and nodes.
virtual bool insertGeometry(QgsAbstractGeometryV2 *g, int index)
Inserts a geometry before a specified index and takes ownership.
QgsGeometryCollectionV2 & operator=(const QgsGeometryCollectionV2 &c)
virtual QgsAbstractGeometryV2 & operator=(const QgsAbstractGeometryV2 &geom)
QDomNode appendChild(const QDomNode &newChild)
void append(const T &value)
iterator begin()
Circular string geometry type.
const_iterator constEnd() const
const T & at(int i) const
virtual QString asJSON(int precision=17) const =0
Returns a GeoJSON representation of the geometry.
void insert(int i, const T &value)
Abstract base class for all geometries.
virtual void transform(const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection d=QgsCoordinateTransform::ForwardTransform) override
Transforms the geometry using a coordinate transform.
static QStringList wktGetChildBlocks(const QString &wkt, const QString &defaultType="")
Parses a WKT string and returns of list of blocks contained in the WKT.
virtual bool wktOmitChildType() const
Returns whether child type names are omitted from Wkt representations of the collection.
TransformDirection
Enum used to indicate the direction (forward or inverse) of the transform.
static double closestSegmentFromComponents(T &container, componentType ctype, const QgsPointV2 &pt, QgsPointV2 &segmentPt, QgsVertexId &vertexAfter, bool *leftOf, double epsilon)
virtual bool insertVertex(const QgsVertexId &position, const QgsPointV2 &vertex) override
Inserts a vertex into the geometry.
Multi point geometry collection.
QDomElement createElementNS(const QString &nsURI, const QString &qName)
QString asWkt(int precision=17) const override
Returns a WKT representation of the geometry.
virtual void clear() override
Clears the geometry, ie reset it to a null geometry.
void chop(int n)
static endian_t endian()
Returns whether this machine uses big or little endian.
Multi line string geometry collection.
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.
QDomElement asGML2(QDomDocument &doc, int precision=17, const QString &ns="gml") const override
Returns a GML2 representation of the geometry.
reference back()
int size() const
virtual bool addMValue(double mValue=0)=0
Adds a measure to the geometry, initialized to a preset value.
bool nextVertex(QgsVertexId &id, QgsPointV2 &vertex) const override
Returns next vertex id and coordinates.
Polygon geometry type.
Definition: qgspolygonv2.h:29
void clear()
static Type flatType(Type type)
Definition: qgswkbtypes.cpp:46
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
unsigned char * asWkb(int &binarySize) const override
Returns a WKB representation of the geometry.
bool hasCurvedSegments() const override
Returns true if the geometry contains curved segments.
void combineExtentWith(QgsRectangle *rect)
expand the rectangle so that covers both the original rectangle and the given rectangle ...
void append(const T &value)
QDomElement asGML3(QDomDocument &doc, int precision=17, const QString &ns="gml") const override
Returns a GML3 representation of the geometry.
double vertexAngle(const QgsVertexId &vertex) const override
Returns approximate rotation angle for a vertex.
static bool hasM(Type type)
Tests whether a WKB type contains m values.
void resize(int size)
int wkbSize() const override
Returns the size of the WKB representation of the geometry.
Utility class for identifying a unique vertex within a geometry.
bool isMeasure() const
Returns true if the geometry contains m values.
Line string geometry type.
bool isEmpty() const
Returns true if the geometry is empty.
static Type addZ(Type type)
Adds the z dimension to a WKB type and returns the new type.
Point geometry type.
Definition: qgspointv2.h:29
void remove(int i)
static bool hasZ(Type type)
Tests whether a WKB type contains the z-dimension.
virtual unsigned char * asWkb(int &binarySize) const =0
Returns a WKB representation of the geometry.
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const
virtual bool addZValue(double zValue=0)=0
Adds a z-dimension to the geometry, initialized to a preset value.
virtual QDomElement asGML3(QDomDocument &doc, int precision=17, const QString &ns="gml") const =0
Returns a GML3 representation of the geometry.
virtual bool nextVertex(QgsVertexId &id, QgsPointV2 &vertex) const =0
Returns next vertex id and coordinates.
static QgsAbstractGeometryV2 * geomFromWkbType(QgsWKBTypes::Type t)
Return empty geometry from wkb type.
virtual double length() const override
Returns the length of the geometry.
QString asJSON(int precision=17) const override
Returns a GeoJSON representation of the geometry.
Compound curve geometry type.
bool fromCollectionWkt(const QString &wkt, const QList< QgsAbstractGeometryV2 * > &subtypes, const QString &defaultChildWkbType=QString())
Reads a collection from a WKT string.
virtual double area() const override
Returns the area of the geometry.
virtual QString geometryType() const =0
Returns a unique string representing the geometry type.
static QgsAbstractGeometryV2 * geomFromWkb(const unsigned char *wkb)
Construct geometry from a WKB string.
virtual bool fromWkt(const QString &wkt) override
Sets the geometry from a WKT string.
virtual bool deleteVertex(const QgsVertexId &position) override
Deletes a vertex within the geometry.
QVector< QgsAbstractGeometryV2 * > mGeometries
virtual bool deleteVertex(const QgsVertexId &position)=0
Deletes a vertex within the geometry.
int numGeometries() const
Returns the number of geometries within the collection.
const T & at(int i) const
const_iterator constBegin() const
virtual bool addMValue(double mValue=0) override
Adds a measure to the geometry, initialized to a preset value.
QString mid(int position, int n) const
virtual QgsGeometryCollectionV2 * clone() const override
Clones the geometry by performing a deep copy.
virtual bool addGeometry(QgsAbstractGeometryV2 *g)
Adds a geometry and takes ownership.
virtual void draw(QPainter &p) const override
Draws the geometry using the specified QPainter.
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.
Class for doing transforms between two map coordinate systems.
virtual QString asWkt(int precision=17) const =0
Returns a WKT representation of the geometry.
const QgsAbstractGeometryV2 * geometryN(int n) const
Returns a const reference to a geometry from within the collection.
virtual QString geometryType() const override
Returns a unique string representing the geometry type.
virtual bool removeGeometry(int nr)
Removes a geometry from the collection.
Multi polygon geometry collection.
virtual bool addZValue(double zValue=0) override
Adds a z-dimension to the geometry, initialized to a preset value.
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 QDomElement asGML2(QDomDocument &doc, int precision=17, const QString &ns="gml") const =0
Returns a GML2 representation of the geometry.
const_iterator constEnd() const
QgsAbstractGeometryV2 * segmentize() const override
Returns a geometry without curves.
const_iterator constBegin() const
virtual QgsAbstractGeometryV2 * clone() const =0
Clones the geometry by performing a deep copy.
virtual bool moveVertex(const QgsVertexId &position, const QgsPointV2 &newPos) override
Moves a vertex within the geometry.
int size() const
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
iterator end()
static Type addM(Type type)
Adds the m dimension to a WKB type and returns the new type.
virtual double perimeter() const override
Returns the perimeter of the geometry.
virtual QgsRectangle calculateBoundingBox() const override
Calculates the minimal bounding box for the geometry.
virtual int dimension() const override
Returns the inherent dimension of the geometry.