1 
2 /***************************************************************************
3                         qgsmultisurface.cpp
4   -------------------------------------------------------------------
5 Date                 : 28 Oct 2014
6 Copyright            : (C) 2014 by Marco Hugentobler
7 email                : marco.hugentobler at sourcepole dot com
8  ***************************************************************************
9  *                                                                         *
10  *   This program is free software; you can redistribute it and/or modify  *
11  *   it under the terms of the GNU General Public License as published by  *
12  *   the Free Software Foundation; either version 2 of the License, or     *
13  *   (at your option) any later version.                                   *
14  *                                                                         *
15  ***************************************************************************/
16 
17 #include "qgsmultisurface.h"
18 #include "qgsapplication.h"
19 #include "qgsgeometryutils.h"
20 #include "qgssurface.h"
21 #include "qgslinestring.h"
22 #include "qgspolygon.h"
23 #include "qgscurvepolygon.h"
24 #include "qgsmulticurve.h"
25 
26 #include <QJsonObject>
27 #include <nlohmann/json.hpp>
28 
QgsMultiSurface()29 QgsMultiSurface::QgsMultiSurface()
30 {
31   mWkbType = QgsWkbTypes::MultiSurface;
32 }
33 
surfaceN(int index)34 QgsSurface *QgsMultiSurface::surfaceN( int index )
35 {
36   return qgsgeometry_cast< QgsSurface * >( geometryN( index ) );
37 }
38 
surfaceN(int index) const39 const QgsSurface *QgsMultiSurface::surfaceN( int index ) const
40 {
41   return qgsgeometry_cast< const QgsSurface * >( geometryN( index ) );
42 }
43 
geometryType() const44 QString QgsMultiSurface::geometryType() const
45 {
46   return QStringLiteral( "MultiSurface" );
47 }
48 
clear()49 void QgsMultiSurface::clear()
50 {
51   QgsGeometryCollection::clear();
52   mWkbType = QgsWkbTypes::MultiSurface;
53 }
54 
createEmptyWithSameType() const55 QgsMultiSurface *QgsMultiSurface::createEmptyWithSameType() const
56 {
57   auto result = std::make_unique< QgsMultiSurface >();
58   result->mWkbType = mWkbType;
59   return result.release();
60 }
61 
clone() const62 QgsMultiSurface *QgsMultiSurface::clone() const
63 {
64   return new QgsMultiSurface( *this );
65 }
66 
toCurveType() const67 QgsMultiSurface *QgsMultiSurface::toCurveType() const
68 {
69   return clone();
70 }
71 
fromWkt(const QString & wkt)72 bool QgsMultiSurface::fromWkt( const QString &wkt )
73 {
74   return fromCollectionWkt( wkt,
75                             QVector<QgsAbstractGeometry *>() << new QgsPolygon << new QgsCurvePolygon,
76                             QStringLiteral( "Polygon" ) );
77 }
78 
asGml2(QDomDocument & doc,int precision,const QString & ns,const AxisOrder axisOrder) const79 QDomElement QgsMultiSurface::asGml2( QDomDocument &doc, int precision, const QString &ns, const AxisOrder axisOrder ) const
80 {
81   // GML2 does not support curves
82   QDomElement elemMultiPolygon = doc.createElementNS( ns, QStringLiteral( "MultiPolygon" ) );
83 
84   if ( isEmpty() )
85     return elemMultiPolygon;
86 
87   for ( const QgsAbstractGeometry *geom : mGeometries )
88   {
89     if ( qgsgeometry_cast<const QgsSurface *>( geom ) )
90     {
91       std::unique_ptr< QgsPolygon > polygon( static_cast<const QgsSurface *>( geom )->surfaceToPolygon() );
92 
93       QDomElement elemPolygonMember = doc.createElementNS( ns, QStringLiteral( "polygonMember" ) );
94       elemPolygonMember.appendChild( polygon->asGml2( doc, precision, ns, axisOrder ) );
95       elemMultiPolygon.appendChild( elemPolygonMember );
96     }
97   }
98 
99   return elemMultiPolygon;
100 }
101 
asGml3(QDomDocument & doc,int precision,const QString & ns,const AxisOrder axisOrder) const102 QDomElement QgsMultiSurface::asGml3( QDomDocument &doc, int precision, const QString &ns, const AxisOrder axisOrder ) const
103 {
104   QDomElement elemMultiSurface = doc.createElementNS( ns, QStringLiteral( "MultiSurface" ) );
105 
106   if ( isEmpty() )
107     return elemMultiSurface;
108 
109   for ( const QgsAbstractGeometry *geom : mGeometries )
110   {
111     if ( qgsgeometry_cast<const QgsSurface *>( geom ) )
112     {
113       QDomElement elemSurfaceMember = doc.createElementNS( ns, QStringLiteral( "surfaceMember" ) );
114       elemSurfaceMember.appendChild( geom->asGml3( doc, precision, ns, axisOrder ) );
115       elemMultiSurface.appendChild( elemSurfaceMember );
116     }
117   }
118 
119   return elemMultiSurface;
120 }
121 
122 
asJsonObject(int precision) const123 json QgsMultiSurface::asJsonObject( int precision ) const
124 {
125   json polygons( json::array( ) );
126   for ( const QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
127   {
128     if ( qgsgeometry_cast<const QgsSurface *>( geom ) )
129     {
130       json coordinates( json::array( ) );
131       std::unique_ptr< QgsPolygon >polygon( static_cast<const QgsSurface *>( geom )->surfaceToPolygon() );
132       std::unique_ptr< QgsLineString > exteriorLineString( polygon->exteriorRing()->curveToLine() );
133       QgsPointSequence exteriorPts;
134       exteriorLineString->points( exteriorPts );
135       coordinates.push_back( QgsGeometryUtils::pointsToJson( exteriorPts, precision ) );
136 
137       std::unique_ptr< QgsLineString > interiorLineString;
138       for ( int i = 0, n = polygon->numInteriorRings(); i < n; ++i )
139       {
140         interiorLineString.reset( polygon->interiorRing( i )->curveToLine() );
141         QgsPointSequence interiorPts;
142         interiorLineString->points( interiorPts );
143         coordinates.push_back( QgsGeometryUtils::pointsToJson( interiorPts, precision ) );
144       }
145       polygons.push_back( coordinates );
146     }
147   }
148   return
149   {
150     {  "type",  "MultiPolygon" },
151     {  "coordinates", polygons }
152   };
153 }
154 
addGeometry(QgsAbstractGeometry * g)155 bool QgsMultiSurface::addGeometry( QgsAbstractGeometry *g )
156 {
157   if ( !qgsgeometry_cast<QgsSurface *>( g ) )
158   {
159     delete g;
160     return false;
161   }
162 
163   if ( mGeometries.empty() )
164   {
165     setZMTypeFromSubGeometry( g, QgsWkbTypes::MultiSurface );
166   }
167   if ( is3D() && !g->is3D() )
168     g->addZValue();
169   else if ( !is3D() && g->is3D() )
170     g->dropZValue();
171   if ( isMeasure() && !g->isMeasure() )
172     g->addMValue();
173   else if ( !isMeasure() && g->isMeasure() )
174     g->dropMValue();
175 
176   return QgsGeometryCollection::addGeometry( g );
177 }
178 
insertGeometry(QgsAbstractGeometry * g,int index)179 bool QgsMultiSurface::insertGeometry( QgsAbstractGeometry *g, int index )
180 {
181   if ( !g || !qgsgeometry_cast< QgsSurface * >( g ) )
182   {
183     delete g;
184     return false;
185   }
186 
187   return QgsGeometryCollection::insertGeometry( g, index );
188 }
189 
boundary() const190 QgsAbstractGeometry *QgsMultiSurface::boundary() const
191 {
192   std::unique_ptr< QgsMultiCurve > multiCurve( new QgsMultiCurve() );
193   multiCurve->reserve( mGeometries.size() );
194   for ( int i = 0; i < mGeometries.size(); ++i )
195   {
196     if ( QgsSurface *surface = qgsgeometry_cast<QgsSurface *>( mGeometries.at( i ) ) )
197     {
198       multiCurve->addGeometry( surface->boundary() );
199     }
200   }
201   if ( multiCurve->numGeometries() == 0 )
202   {
203     return nullptr;
204   }
205   return multiCurve.release();
206 }
207