1 /***************************************************************************
2                            qgsgeometryfactory.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 "qgsgeometryfactory.h"
19 #include "qgscircularstring.h"
20 #include "qgscompoundcurve.h"
21 #include "qgscurvepolygon.h"
22 #include "qgspoint.h"
23 #include "qgspolygon.h"
24 #include "qgslinestring.h"
25 #include "qgsmulticurve.h"
26 #include "qgsmultilinestring.h"
27 #include "qgsmultipoint.h"
28 #include "qgsmultipolygon.h"
29 #include "qgsmultisurface.h"
30 #include "qgstriangle.h"
31 #include "qgswkbtypes.h"
32 #include "qgslogger.h"
33 
geomFromWkb(QgsConstWkbPtr & wkbPtr)34 std::unique_ptr<QgsAbstractGeometry> QgsGeometryFactory::geomFromWkb( QgsConstWkbPtr &wkbPtr )
35 {
36   if ( !wkbPtr )
37     return nullptr;
38 
39   //find out type (bytes 2-5)
40   QgsWkbTypes::Type type = QgsWkbTypes::Unknown;
41   try
42   {
43     type = wkbPtr.readHeader();
44   }
45   catch ( const QgsWkbException &e )
46   {
47     Q_UNUSED( e )
48     QgsDebugMsg( "WKB exception while reading header: " + e.what() );
49     return nullptr;
50   }
51   wkbPtr -= 1 + sizeof( int );
52 
53   std::unique_ptr< QgsAbstractGeometry > geom = geomFromWkbType( type );
54 
55   if ( geom )
56   {
57     try
58     {
59       geom->fromWkb( wkbPtr );  // also updates wkbPtr
60     }
61     catch ( const QgsWkbException &e )
62     {
63       Q_UNUSED( e )
64       QgsDebugMsg( "WKB exception: " + e.what() );
65       geom.reset();
66     }
67   }
68 
69   return geom;
70 }
71 
geomFromWkt(const QString & text)72 std::unique_ptr<QgsAbstractGeometry> QgsGeometryFactory::geomFromWkt( const QString &text )
73 {
74   const QString trimmed = text.trimmed();
75   std::unique_ptr< QgsAbstractGeometry> geom;
76   if ( trimmed.startsWith( QLatin1String( "Point" ), Qt::CaseInsensitive ) )
77   {
78     geom = std::make_unique< QgsPoint >();
79   }
80   else if ( trimmed.startsWith( QLatin1String( "LineString" ), Qt::CaseInsensitive ) )
81   {
82     geom = std::make_unique< QgsLineString >();
83   }
84   else if ( trimmed.startsWith( QLatin1String( "CircularString" ), Qt::CaseInsensitive ) )
85   {
86     geom = std::make_unique< QgsCircularString >();
87   }
88   else if ( trimmed.startsWith( QLatin1String( "CompoundCurve" ), Qt::CaseInsensitive ) )
89   {
90     geom = std::make_unique< QgsCompoundCurve>();
91   }
92   else if ( trimmed.startsWith( QLatin1String( "Polygon" ), Qt::CaseInsensitive ) )
93   {
94     geom = std::make_unique< QgsPolygon >();
95   }
96   else if ( trimmed.startsWith( QLatin1String( "Triangle" ), Qt::CaseInsensitive ) )
97   {
98     geom = std::make_unique< QgsTriangle >();
99   }
100   else if ( trimmed.startsWith( QLatin1String( "CurvePolygon" ), Qt::CaseInsensitive ) )
101   {
102     geom = std::make_unique< QgsCurvePolygon >();
103   }
104   else if ( trimmed.startsWith( QLatin1String( "MultiPoint" ), Qt::CaseInsensitive ) )
105   {
106     geom = std::make_unique< QgsMultiPoint >();
107   }
108   else if ( trimmed.startsWith( QLatin1String( "MultiCurve" ), Qt::CaseInsensitive ) )
109   {
110     geom = std::make_unique< QgsMultiCurve >();
111   }
112   else if ( trimmed.startsWith( QLatin1String( "MultiLineString" ), Qt::CaseInsensitive ) )
113   {
114     geom = std::make_unique< QgsMultiLineString >();
115   }
116   else if ( trimmed.startsWith( QLatin1String( "MultiSurface" ), Qt::CaseInsensitive ) )
117   {
118     geom = std::make_unique< QgsMultiSurface >();
119   }
120   else if ( trimmed.startsWith( QLatin1String( "MultiPolygon" ), Qt::CaseInsensitive ) )
121   {
122     geom = std::make_unique< QgsMultiPolygon >();
123   }
124   else if ( trimmed.startsWith( QLatin1String( "GeometryCollection" ), Qt::CaseInsensitive ) )
125   {
126     geom = std::make_unique< QgsGeometryCollection >();
127   }
128 
129   if ( geom )
130   {
131     if ( !geom->fromWkt( text ) )
132     {
133       return nullptr;
134     }
135   }
136   return geom;
137 }
138 
fromPointXY(const QgsPointXY & point)139 std::unique_ptr< QgsAbstractGeometry > QgsGeometryFactory::fromPointXY( const QgsPointXY &point )
140 {
141   return std::make_unique< QgsPoint >( point.x(), point.y() );
142 }
143 
fromMultiPointXY(const QgsMultiPointXY & multipoint)144 std::unique_ptr<QgsMultiPoint> QgsGeometryFactory::fromMultiPointXY( const QgsMultiPointXY &multipoint )
145 {
146   std::unique_ptr< QgsMultiPoint > mp = std::make_unique< QgsMultiPoint >();
147   QgsMultiPointXY::const_iterator ptIt = multipoint.constBegin();
148   mp->reserve( multipoint.size() );
149   for ( ; ptIt != multipoint.constEnd(); ++ptIt )
150   {
151     QgsPoint *pt = new QgsPoint( ptIt->x(), ptIt->y() );
152     mp->addGeometry( pt );
153   }
154   return mp;
155 }
156 
fromPolylineXY(const QgsPolylineXY & polyline)157 std::unique_ptr<QgsAbstractGeometry> QgsGeometryFactory::fromPolylineXY( const QgsPolylineXY &polyline )
158 {
159   return linestringFromPolyline( polyline );
160 }
161 
fromMultiPolylineXY(const QgsMultiPolylineXY & multiline)162 std::unique_ptr<QgsMultiLineString> QgsGeometryFactory::fromMultiPolylineXY( const QgsMultiPolylineXY &multiline )
163 {
164   std::unique_ptr< QgsMultiLineString > mLine = std::make_unique< QgsMultiLineString >();
165   mLine->reserve( multiline.size() );
166   for ( int i = 0; i < multiline.size(); ++i )
167   {
168     mLine->addGeometry( fromPolylineXY( multiline.at( i ) ).release() );
169   }
170   return mLine;
171 }
172 
fromPolygonXY(const QgsPolygonXY & polygon)173 std::unique_ptr<QgsPolygon> QgsGeometryFactory::fromPolygonXY( const QgsPolygonXY &polygon )
174 {
175   std::unique_ptr< QgsPolygon > poly = std::make_unique< QgsPolygon >();
176 
177   QVector<QgsCurve *> holes;
178   holes.reserve( polygon.size() );
179   for ( int i = 0; i < polygon.size(); ++i )
180   {
181     std::unique_ptr< QgsLineString > l = linestringFromPolyline( polygon.at( i ) );
182     l->close();
183 
184     if ( i == 0 )
185     {
186       poly->setExteriorRing( l.release() );
187     }
188     else
189     {
190       holes.push_back( l.release() );
191     }
192   }
193   poly->setInteriorRings( holes );
194   return poly;
195 }
196 
fromMultiPolygonXY(const QgsMultiPolygonXY & multipoly)197 std::unique_ptr< QgsMultiPolygon > QgsGeometryFactory::fromMultiPolygonXY( const QgsMultiPolygonXY &multipoly )
198 {
199   std::unique_ptr< QgsMultiPolygon > mp = std::make_unique< QgsMultiPolygon >();
200   mp->reserve( multipoly.size() );
201   for ( int i = 0; i < multipoly.size(); ++i )
202   {
203     mp->addGeometry( fromPolygonXY( multipoly.at( i ) ).release() );
204   }
205   return mp;
206 }
207 
linestringFromPolyline(const QgsPolylineXY & polyline)208 std::unique_ptr<QgsLineString> QgsGeometryFactory::linestringFromPolyline( const QgsPolylineXY &polyline )
209 {
210   const int size = polyline.size();
211   QVector< double > x;
212   x.resize( size );
213   QVector< double > y;
214   y.resize( size );
215   double *destX = x.data();
216   double *destY = y.data();
217   const QgsPointXY *src = polyline.data();
218   for ( int i = 0; i < size; ++i )
219   {
220     *destX++ = src->x();
221     *destY++ = src->y();
222     src++;
223   }
224   std::unique_ptr< QgsLineString > line = std::make_unique< QgsLineString >( x, y );
225   return line;
226 }
227 
geomFromWkbType(QgsWkbTypes::Type t)228 std::unique_ptr<QgsAbstractGeometry> QgsGeometryFactory::geomFromWkbType( QgsWkbTypes::Type t )
229 {
230   const QgsWkbTypes::Type type = QgsWkbTypes::flatType( t );
231   switch ( type )
232   {
233     case QgsWkbTypes::Point:
234       return std::make_unique< QgsPoint >();
235     case QgsWkbTypes::LineString:
236       return std::make_unique< QgsLineString >();
237     case QgsWkbTypes::CircularString:
238       return std::make_unique< QgsCircularString >();
239     case QgsWkbTypes::CompoundCurve:
240       return std::make_unique< QgsCompoundCurve >();
241     case QgsWkbTypes::Polygon:
242       return std::make_unique< QgsPolygon >();
243     case QgsWkbTypes::CurvePolygon:
244       return std::make_unique< QgsCurvePolygon >();
245     case QgsWkbTypes::MultiLineString:
246       return std::make_unique< QgsMultiLineString >();
247     case QgsWkbTypes::MultiPolygon:
248       return std::make_unique< QgsMultiPolygon >();
249     case QgsWkbTypes::MultiPoint:
250       return std::make_unique< QgsMultiPoint >();
251     case QgsWkbTypes::MultiCurve:
252       return std::make_unique< QgsMultiCurve >();
253     case QgsWkbTypes::MultiSurface:
254       return std::make_unique< QgsMultiSurface >();
255     case QgsWkbTypes::GeometryCollection:
256       return std::make_unique< QgsGeometryCollection >();
257     case QgsWkbTypes::Triangle:
258       return std::make_unique< QgsTriangle >();
259     default:
260       return nullptr;
261   }
262 }
263 
createCollectionOfType(QgsWkbTypes::Type t)264 std::unique_ptr<QgsGeometryCollection> QgsGeometryFactory::createCollectionOfType( QgsWkbTypes::Type t )
265 {
266   const QgsWkbTypes::Type type = QgsWkbTypes::flatType( QgsWkbTypes::multiType( t ) );
267   std::unique_ptr< QgsGeometryCollection > collect;
268   switch ( type )
269   {
270     case QgsWkbTypes::MultiPoint:
271       collect = std::make_unique< QgsMultiPoint >();
272       break;
273     case QgsWkbTypes::MultiLineString:
274       collect = std::make_unique< QgsMultiLineString >();
275       break;
276     case QgsWkbTypes::MultiCurve:
277       collect = std::make_unique< QgsMultiCurve >();
278       break;
279     case QgsWkbTypes::MultiPolygon:
280       collect = std::make_unique< QgsMultiPolygon >();
281       break;
282     case QgsWkbTypes::MultiSurface:
283       collect = std::make_unique< QgsMultiSurface >();
284       break;
285     case QgsWkbTypes::GeometryCollection:
286       collect = std::make_unique< QgsGeometryCollection >();
287       break;
288     default:
289       // should not be possible
290       return nullptr;
291   }
292   if ( QgsWkbTypes::hasM( t ) )
293     collect->addMValue();
294   if ( QgsWkbTypes::hasZ( t ) )
295     collect->addZValue();
296 
297   return collect;
298 }
299