1 /***************************************************************************
2                         qgsmultipolygon.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 
16 #include "qgsmultipolygon.h"
17 #include "qgsapplication.h"
18 #include "qgsgeometryutils.h"
19 #include "qgssurface.h"
20 #include "qgslinestring.h"
21 #include "qgspolygon.h"
22 #include "qgscurvepolygon.h"
23 #include "qgsmultilinestring.h"
24 
25 #include <QJsonObject>
26 #include <nlohmann/json.hpp>
27 
QgsMultiPolygon()28 QgsMultiPolygon::QgsMultiPolygon()
29 {
30   mWkbType = QgsWkbTypes::MultiPolygon;
31 }
32 
polygonN(int index)33 QgsPolygon *QgsMultiPolygon::polygonN( int index )
34 {
35   return qgsgeometry_cast< QgsPolygon * >( geometryN( index ) );
36 }
37 
polygonN(int index) const38 const QgsPolygon *QgsMultiPolygon::polygonN( int index ) const
39 {
40   return qgsgeometry_cast< const QgsPolygon * >( geometryN( index ) );
41 }
42 
geometryType() const43 QString QgsMultiPolygon::geometryType() const
44 {
45   return QStringLiteral( "MultiPolygon" );
46 }
47 
clear()48 void QgsMultiPolygon::clear()
49 {
50   QgsMultiSurface::clear();
51   mWkbType = QgsWkbTypes::MultiPolygon;
52 }
53 
createEmptyWithSameType() const54 QgsMultiPolygon *QgsMultiPolygon::createEmptyWithSameType() const
55 {
56   auto result = std::make_unique< QgsMultiPolygon >();
57   result->mWkbType = mWkbType;
58   return result.release();
59 }
60 
clone() const61 QgsMultiPolygon *QgsMultiPolygon::clone() const
62 {
63   return new QgsMultiPolygon( *this );
64 }
65 
fromWkt(const QString & wkt)66 bool QgsMultiPolygon::fromWkt( const QString &wkt )
67 {
68   return fromCollectionWkt( wkt, QVector<QgsAbstractGeometry *>() << new QgsPolygon, QStringLiteral( "Polygon" ) );
69 }
70 
asGml2(QDomDocument & doc,int precision,const QString & ns,const AxisOrder axisOrder) const71 QDomElement QgsMultiPolygon::asGml2( QDomDocument &doc, int precision, const QString &ns, const AxisOrder axisOrder ) const
72 {
73   // GML2 does not support curves
74   QDomElement elemMultiPolygon = doc.createElementNS( ns, QStringLiteral( "MultiPolygon" ) );
75 
76   if ( isEmpty() )
77     return elemMultiPolygon;
78 
79   for ( const QgsAbstractGeometry *geom : mGeometries )
80   {
81     if ( qgsgeometry_cast<const QgsPolygon *>( geom ) )
82     {
83       QDomElement elemPolygonMember = doc.createElementNS( ns, QStringLiteral( "polygonMember" ) );
84       elemPolygonMember.appendChild( geom->asGml2( doc, precision, ns, axisOrder ) );
85       elemMultiPolygon.appendChild( elemPolygonMember );
86     }
87   }
88 
89   return elemMultiPolygon;
90 }
91 
asGml3(QDomDocument & doc,int precision,const QString & ns,const QgsAbstractGeometry::AxisOrder axisOrder) const92 QDomElement QgsMultiPolygon::asGml3( QDomDocument &doc, int precision, const QString &ns, const QgsAbstractGeometry::AxisOrder axisOrder ) const
93 {
94   QDomElement elemMultiSurface = doc.createElementNS( ns, QStringLiteral( "MultiPolygon" ) );
95 
96   if ( isEmpty() )
97     return elemMultiSurface;
98 
99   for ( const QgsAbstractGeometry *geom : mGeometries )
100   {
101     if ( qgsgeometry_cast<const QgsPolygon *>( geom ) )
102     {
103       QDomElement elemSurfaceMember = doc.createElementNS( ns, QStringLiteral( "polygonMember" ) );
104       elemSurfaceMember.appendChild( geom->asGml3( doc, precision, ns, axisOrder ) );
105       elemMultiSurface.appendChild( elemSurfaceMember );
106     }
107   }
108 
109   return elemMultiSurface;
110 }
111 
asJsonObject(int precision) const112 json QgsMultiPolygon::asJsonObject( int precision ) const
113 {
114   json polygons( json::array( ) );
115   for ( const QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
116   {
117     if ( qgsgeometry_cast<const QgsPolygon *>( geom ) )
118     {
119       json coordinates( json::array( ) );
120       const QgsPolygon *polygon = static_cast<const QgsPolygon *>( geom );
121 
122       std::unique_ptr< QgsLineString > exteriorLineString( polygon->exteriorRing()->curveToLine() );
123       QgsPointSequence exteriorPts;
124       exteriorLineString->points( exteriorPts );
125       coordinates.push_back( QgsGeometryUtils::pointsToJson( exteriorPts, precision ) );
126 
127       std::unique_ptr< QgsLineString > interiorLineString;
128       for ( int i = 0, n = polygon->numInteriorRings(); i < n; ++i )
129       {
130         interiorLineString.reset( polygon->interiorRing( i )->curveToLine() );
131         QgsPointSequence interiorPts;
132         interiorLineString->points( interiorPts );
133         coordinates.push_back( QgsGeometryUtils::pointsToJson( interiorPts, precision ) );
134       }
135       polygons.push_back( coordinates );
136     }
137   }
138   return
139   {
140     { "type", "MultiPolygon" },
141     { "coordinates", polygons }
142   };
143 }
144 
addGeometry(QgsAbstractGeometry * g)145 bool QgsMultiPolygon::addGeometry( QgsAbstractGeometry *g )
146 {
147   if ( !qgsgeometry_cast<QgsPolygon *>( g ) )
148   {
149     delete g;
150     return false;
151   }
152 
153   if ( mGeometries.empty() )
154   {
155     setZMTypeFromSubGeometry( g, QgsWkbTypes::MultiPolygon );
156   }
157   if ( is3D() && !g->is3D() )
158     g->addZValue();
159   else if ( !is3D() && g->is3D() )
160     g->dropZValue();
161   if ( isMeasure() && !g->isMeasure() )
162     g->addMValue();
163   else if ( !isMeasure() && g->isMeasure() )
164     g->dropMValue();
165 
166   return QgsGeometryCollection::addGeometry( g ); // clazy:exclude=skipped-base-method
167 }
168 
insertGeometry(QgsAbstractGeometry * g,int index)169 bool QgsMultiPolygon::insertGeometry( QgsAbstractGeometry *g, int index )
170 {
171   if ( !g || !qgsgeometry_cast< QgsPolygon * >( g ) )
172   {
173     delete g;
174     return false;
175   }
176 
177   return QgsMultiSurface::insertGeometry( g, index );
178 }
179 
toCurveType() const180 QgsMultiSurface *QgsMultiPolygon::toCurveType() const
181 {
182   QgsMultiSurface *multiSurface = new QgsMultiSurface();
183   multiSurface->reserve( mGeometries.size() );
184   for ( int i = 0; i < mGeometries.size(); ++i )
185   {
186     multiSurface->addGeometry( mGeometries.at( i )->clone() );
187   }
188   return multiSurface;
189 }
190 
boundary() const191 QgsAbstractGeometry *QgsMultiPolygon::boundary() const
192 {
193   std::unique_ptr< QgsMultiLineString > multiLine( new QgsMultiLineString() );
194   multiLine->reserve( mGeometries.size() );
195   for ( int i = 0; i < mGeometries.size(); ++i )
196   {
197     if ( QgsPolygon *polygon = qgsgeometry_cast<QgsPolygon *>( mGeometries.at( i ) ) )
198     {
199       QgsAbstractGeometry *polygonBoundary = polygon->boundary();
200 
201       if ( QgsLineString *lineStringBoundary = qgsgeometry_cast< QgsLineString * >( polygonBoundary ) )
202       {
203         multiLine->addGeometry( lineStringBoundary );
204       }
205       else if ( QgsMultiLineString *multiLineStringBoundary = qgsgeometry_cast< QgsMultiLineString * >( polygonBoundary ) )
206       {
207         for ( int j = 0; j < multiLineStringBoundary->numGeometries(); ++j )
208         {
209           multiLine->addGeometry( multiLineStringBoundary->geometryN( j )->clone() );
210         }
211         delete multiLineStringBoundary;
212       }
213       else
214       {
215         delete polygonBoundary;
216       }
217     }
218   }
219   if ( multiLine->numGeometries() == 0 )
220   {
221     return nullptr;
222   }
223   return multiLine.release();
224 }
225 
wktOmitChildType() const226 bool QgsMultiPolygon::wktOmitChildType() const
227 {
228   return true;
229 }
230