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