17#include "moc_qgsjsonutils.cpp" 
   37#include <QJsonDocument> 
   40#include <nlohmann/json.hpp> 
   44  , mLayer( vectorLayer )
 
 
   84                                        const QVariant &
id, 
int indent )
 const 
 
   93    {  
"type",  
"Feature" },
 
   98    auto intId = 
id.toLongLong( &ok );
 
  101      featureJson[
"id"] = intId;
 
  105      featureJson[
"id"] = 
id.toString().toStdString();
 
  110    featureJson[
"id"] = 
nullptr;
 
  114    featureJson[
"id"] = feature.
id();
 
  118  if ( !geom.
isNull() && mIncludeGeometry )
 
  137      featureJson[ 
"bbox" ] =
 
  145    featureJson[ 
"geometry" ] = geom.
asJsonObject( mPrecision );
 
  149    featureJson[ 
"geometry"  ] = 
nullptr;
 
  154  if ( mIncludeAttributes || !extraProperties.isEmpty() )
 
  157    if ( mIncludeAttributes )
 
  161      QStringList formattersAllowList;
 
  162      formattersAllowList << QStringLiteral( 
"KeyValue" )
 
  163                          << QStringLiteral( 
"List" )
 
  164                          << QStringLiteral( 
"ValueRelation" )
 
  165                          << QStringLiteral( 
"ValueMap" );
 
  167      for ( 
int i = 0; i < fields.
count(); ++i )
 
  169        if ( ( !mAttributeIndexes.isEmpty() && !mAttributeIndexes.contains( i ) ) || mExcludedAttributeIndexes.contains( i ) )
 
  174        if ( mUseFieldFormatters && mLayer )
 
  178          if ( formattersAllowList.contains( fieldFormatter->
id() ) )
 
  182        QString name = fields.
at( i ).
name();
 
  183        if ( mAttributeDisplayName )
 
  185          name = mLayer->attributeDisplayName( i );
 
  191    if ( !extraProperties.isEmpty() )
 
  193      QVariantMap::const_iterator it = extraProperties.constBegin();
 
  194      for ( ; it != extraProperties.constEnd(); ++it )
 
  201    if ( mLayer && mIncludeRelatedAttributes )
 
  204      for ( 
const auto &relation : std::as_const( relations ) )
 
  209        json relatedFeatureAttributes;
 
  213          QVector<QVariant> attributeWidgetCaches;
 
  216          for ( 
const QgsField &field : fields )
 
  220            attributeWidgetCaches.append( fieldFormatter->
createCache( childLayer, fieldIndex, setup.
config() ) );
 
  229        properties[ relation.name().toStdString() ] = relatedFeatureAttributes;
 
  233  featureJson[ 
"properties" ] = properties;
 
 
  246    { 
"type", 
"FeatureCollection" },
 
  247    { 
"features", json::array() }
 
  252  for ( 
const QgsFeature &feature : std::as_const( features ) )
 
 
  261  mDestinationCrs = destinationCrs;
 
 
  272    encoding = QTextCodec::codecForName( 
"UTF-8" );
 
 
  280    encoding = QTextCodec::codecForName( 
"UTF-8" );
 
 
  288    return QStringLiteral( 
"null" );
 
  290  switch ( value.userType() )
 
  292    case QMetaType::Type::Int:
 
  293    case QMetaType::Type::UInt:
 
  294    case QMetaType::Type::LongLong:
 
  295    case QMetaType::Type::ULongLong:
 
  296    case QMetaType::Type::Double:
 
  297      return value.toString();
 
  299    case QMetaType::Type::Bool:
 
  300      return value.toBool() ? 
"true" : 
"false";
 
  302    case QMetaType::Type::QStringList:
 
  303    case QMetaType::Type::QVariantList:
 
  304    case QMetaType::Type::QVariantMap:
 
  305      return QString::fromUtf8( QJsonDocument::fromVariant( value ).toJson( QJsonDocument::Compact ) );
 
  308    case QMetaType::Type::QString:
 
  309      QString v = value.toString()
 
  310                  .replace( 
'\\', QLatin1String( 
"\\\\" ) )
 
  311                  .replace( 
'"', QLatin1String( 
"\\\"" ) )
 
  312                  .replace( 
'\r', QLatin1String( 
"\\r" ) )
 
  313                  .replace( 
'\b', QLatin1String( 
"\\b" ) )
 
  314                  .replace( 
'\t', QLatin1String( 
"\\t" ) )
 
  315                  .replace( 
'/', QLatin1String( 
"\\/" ) )
 
  316                  .replace( 
'\n', QLatin1String( 
"\\n" ) );
 
  318      return v.prepend( 
'"' ).append( 
'"' );
 
 
  326  for ( 
int i = 0; i < fields.
count(); ++i )
 
  329      attrs += QLatin1String( 
",\n" );
 
  338        val = fieldFormatter->
representValue( layer, i, setup.
config(), attributeWidgetCaches.count() >= i ? attributeWidgetCaches.at( i ) : QVariant(), val );
 
  343  return attrs.prepend( 
'{' ).append( 
'}' );
 
 
  348  QString errorMessage;
 
  352    const auto jObj( json::parse( json.toStdString() ) );
 
  353    if ( ! jObj.is_array() )
 
  355      throw json::parse_error::create( 0, 0, QStringLiteral( 
"JSON value must be an array" ).toStdString(), &jObj );
 
  357    for ( 
const auto &item : jObj )
 
  361      if ( item.is_number_integer() )
 
  365      else if ( item.is_number_unsigned() )
 
  367        v = item.get<
unsigned>();
 
  369      else if ( item.is_number_float() )
 
  372        v = item.get<
double>();
 
  374      else if ( item.is_string() )
 
  376        v = QString::fromStdString( item.get<std::string>() );
 
  378      else if ( item.is_boolean() )
 
  380        v = item.get<
bool>();
 
  382      else if ( item.is_null() )
 
  389      if ( type != QMetaType::Type::UnknownType )
 
  391        if ( ! v.convert( 
static_cast<int>( type ) ) )
 
  393          QgsLogger::warning( QStringLiteral( 
"Cannot convert json array element to specified type, ignoring: %1" ).arg( v.toString() ) );
 
  397          result.push_back( v );
 
  402        result.push_back( v );
 
  406  catch ( json::parse_error &ex )
 
  408    errorMessage = ex.what();
 
  409    QgsLogger::warning( QStringLiteral( 
"Cannot parse json (%1): %2" ).arg( ex.what(), json ) );
 
 
  422  if ( !coords.is_array() || coords.size() < 2 || coords.size() > 3 )
 
  424    QgsDebugError( QStringLiteral( 
"JSON Point geometry coordinates must be an array of two or three numbers" ) );
 
  428  const double x = coords[0].get< 
double >();
 
  429  const double y = coords[1].get< 
double >();
 
  430  if ( coords.size() == 2 )
 
  432    return std::make_unique< QgsPoint >( x, y );
 
  436    const double z = coords[2].get< 
double >();
 
  437    return std::make_unique< QgsPoint >( x, y, z );
 
 
  443  if ( !coords.is_array() || coords.size() < 2 )
 
  445    QgsDebugError( QStringLiteral( 
"JSON LineString geometry coordinates must be an array of at least two points" ) );
 
  449  const std::size_t coordsSize = coords.size();
 
  454#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 
  455  x.resize( 
static_cast< int >( coordsSize ) );
 
  456  y.resize( 
static_cast< int >( coordsSize ) );
 
  457  z.resize( 
static_cast< int >( coordsSize ) );
 
  459  x.resize( coordsSize );
 
  460  y.resize( coordsSize );
 
  461  z.resize( coordsSize );
 
  463  double *xOut = x.data();
 
  464  double *yOut = y.data();
 
  465  double *zOut = z.data();
 
  467  for ( 
const auto &coord : coords )
 
  469    if ( !coord.is_array() || coord.size() < 2 || coord.size() > 3 )
 
  471      QgsDebugError( QStringLiteral( 
"JSON LineString geometry coordinates must be an array of two or three numbers" ) );
 
  475    *xOut++ = coord[0].get< 
double >();
 
  476    *yOut++ = coord[1].get< 
double >();
 
  477    if ( coord.size() == 3 )
 
  479      *zOut++ = coord[2].get< 
double >();
 
  484      *zOut++ = std::numeric_limits< double >::quiet_NaN();
 
  488  return std::make_unique< QgsLineString >( x, y, hasZ ? z : QVector<double>() );
 
 
  493  if ( !coords.is_array() || coords.size() < 1 )
 
  495    QgsDebugError( QStringLiteral( 
"JSON Polygon geometry coordinates must be an array" ) );
 
  499  const std::size_t coordsSize = coords.size();
 
  506  auto polygon = std::make_unique< QgsPolygon >( exterior.release() );
 
  507  for ( std::size_t i = 1; i < coordsSize; ++i )
 
  514    polygon->addInteriorRing( ring.release() );
 
 
  521  if ( !geometry.is_object() )
 
  523    QgsDebugError( QStringLiteral( 
"JSON geometry value must be an object" ) );
 
  527  if ( !geometry.contains( 
"type" ) )
 
  529    QgsDebugError( QStringLiteral( 
"JSON geometry must contain 'type'" ) );
 
  533  const QString type = QString::fromStdString( geometry[
"type"].get< std::string >() );
 
  534  if ( type.compare( QLatin1String( 
"Point" ), Qt::CaseInsensitive ) == 0 )
 
  536    if ( !geometry.contains( 
"coordinates" ) )
 
  538      QgsDebugError( QStringLiteral( 
"JSON Point geometry must contain 'coordinates'" ) );
 
  542    const json &coords = geometry[
"coordinates"];
 
  545  else if ( type.compare( QLatin1String( 
"MultiPoint" ), Qt::CaseInsensitive ) == 0 )
 
  547    if ( !geometry.contains( 
"coordinates" ) )
 
  549      QgsDebugError( QStringLiteral( 
"JSON MultiPoint geometry must contain 'coordinates'" ) );
 
  553    const json &coords = geometry[
"coordinates"];
 
  555    if ( !coords.is_array() )
 
  557      QgsDebugError( QStringLiteral( 
"JSON MultiPoint geometry coordinates must be an array" ) );
 
  561    auto multiPoint = std::make_unique< QgsMultiPoint >();
 
  562    multiPoint->reserve( 
static_cast< int >( coords.size() ) );
 
  563    for ( 
const auto &pointCoords : coords )
 
  570      multiPoint->addGeometry( point.release() );
 
  575  else if ( type.compare( QLatin1String( 
"LineString" ), Qt::CaseInsensitive ) == 0 )
 
  577    if ( !geometry.contains( 
"coordinates" ) )
 
  579      QgsDebugError( QStringLiteral( 
"JSON LineString geometry must contain 'coordinates'" ) );
 
  583    const json &coords = geometry[
"coordinates"];
 
  586  else if ( type.compare( QLatin1String( 
"MultiLineString" ), Qt::CaseInsensitive ) == 0 )
 
  588    if ( !geometry.contains( 
"coordinates" ) )
 
  590      QgsDebugError( QStringLiteral( 
"JSON MultiLineString geometry must contain 'coordinates'" ) );
 
  594    const json &coords = geometry[
"coordinates"];
 
  596    if ( !coords.is_array() )
 
  598      QgsDebugError( QStringLiteral( 
"JSON MultiLineString geometry coordinates must be an array" ) );
 
  602    auto multiLineString = std::make_unique< QgsMultiLineString >();
 
  603    multiLineString->reserve( 
static_cast< int >( coords.size() ) );
 
  604    for ( 
const auto &lineCoords : coords )
 
  611      multiLineString->addGeometry( line.release() );
 
  614    return multiLineString;
 
  616  else if ( type.compare( QLatin1String( 
"Polygon" ), Qt::CaseInsensitive ) == 0 )
 
  618    if ( !geometry.contains( 
"coordinates" ) )
 
  620      QgsDebugError( QStringLiteral( 
"JSON Polygon geometry must contain 'coordinates'" ) );
 
  624    const json &coords = geometry[
"coordinates"];
 
  625    if ( !coords.is_array() || coords.size() < 1 )
 
  627      QgsDebugError( QStringLiteral( 
"JSON Polygon geometry coordinates must be an array of at least one ring" ) );
 
  633  else if ( type.compare( QLatin1String( 
"MultiPolygon" ), Qt::CaseInsensitive ) == 0 )
 
  635    if ( !geometry.contains( 
"coordinates" ) )
 
  637      QgsDebugError( QStringLiteral( 
"JSON MultiPolygon geometry must contain 'coordinates'" ) );
 
  641    const json &coords = geometry[
"coordinates"];
 
  643    if ( !coords.is_array() )
 
  645      QgsDebugError( QStringLiteral( 
"JSON MultiPolygon geometry coordinates must be an array" ) );
 
  649    auto multiPolygon = std::make_unique< QgsMultiPolygon >();
 
  650    multiPolygon->reserve( 
static_cast< int >( coords.size() ) );
 
  651    for ( 
const auto &polygonCoords : coords )
 
  658      multiPolygon->addGeometry( polygon.release() );
 
  663  else if ( type.compare( QLatin1String( 
"GeometryCollection" ), Qt::CaseInsensitive ) == 0 )
 
  665    if ( !geometry.contains( 
"geometries" ) )
 
  667      QgsDebugError( QStringLiteral( 
"JSON GeometryCollection geometry must contain 'geometries'" ) );
 
  671    const json &geometries = geometry[
"geometries"];
 
  673    if ( !geometries.is_array() )
 
  675      QgsDebugError( QStringLiteral( 
"JSON GeometryCollection geometries must be an array" ) );
 
  679    auto collection = std::make_unique< QgsGeometryCollection >();
 
  680    collection->reserve( 
static_cast< int >( geometries.size() ) );
 
  681    for ( 
const auto &geometry : geometries )
 
  688      collection->addGeometry( 
object.release() );
 
  694  QgsDebugError( QStringLiteral( 
"Unhandled GeoJSON geometry type: %1" ).arg( type ) );
 
 
  700  if ( !geometry.is_object() )
 
  702    QgsDebugError( QStringLiteral( 
"JSON geometry value must be an object" ) );
 
 
  713    const auto jObj( json::parse( geometry.toStdString() ) );
 
  716  catch ( json::parse_error &ex )
 
  718    QgsDebugError( QStringLiteral( 
"Cannot parse json (%1): %2" ).arg( geometry, ex.what() ) );
 
 
  730  if ( val.userType() == QMetaType::Type::QVariantMap )
 
  732    const QVariantMap &vMap = val.toMap();
 
  733    json jMap = json::object();
 
  734    for ( 
auto it = vMap.constBegin(); it != vMap.constEnd(); it++ )
 
  740  else if ( val.userType() == QMetaType::Type::QVariantList || val.userType() == QMetaType::Type::QStringList )
 
  742    const QVariantList &vList = val.toList();
 
  743    json jList = json::array();
 
  744    for ( 
const auto &v : vList )
 
  752    switch ( val.userType() )
 
  755      case QMetaType::UInt:
 
  756      case QMetaType::LongLong:
 
  757      case QMetaType::ULongLong:
 
  758        j = val.toLongLong();
 
  760      case QMetaType::Double:
 
  761      case QMetaType::Float:
 
  764      case QMetaType::Bool:
 
  767      case QMetaType::QByteArray:
 
  768        j = val.toByteArray().toBase64().toStdString();
 
  771        j = val.toString().toStdString();
 
 
  781  const QVariant res = 
parseJson( jsonString, error );
 
  783  if ( !error.isEmpty() )
 
  786                        QString::fromStdString( jsonString ) ) );
 
 
  796    const json j = json::parse( jsonString );
 
  799  catch ( json::parse_error &ex )
 
  801    error = QString::fromStdString( ex.what() );
 
 
  809  bool isPrimitive = 
true;
 
  811  std::function<QVariant( json )> _parser { [ & ]( json jObj ) -> QVariant {
 
  813      if ( jObj.is_array() )
 
  816        QVariantList results;
 
  817        results.reserve( jObj.size() );
 
  818        for ( 
const auto &item : jObj )
 
  820          results.push_back( _parser( item ) );
 
  824      else if ( jObj.is_object() )
 
  828        for ( 
const auto  &item : jObj.items() )
 
  830          const auto key { QString::fromStdString( item.key() ) };
 
  831          const auto value {  _parser( item.value() ) };
 
  832          results[ key ] = value;
 
  838        if ( jObj.is_number_unsigned() )
 
  842          const qulonglong num { jObj.get<qulonglong>() };
 
  843          if ( num <= std::numeric_limits<int>::max() )
 
  845            result = 
static_cast<int>( num );
 
  847          else if ( num <= std::numeric_limits<qlonglong>::max() )
 
  849            result = 
static_cast<qlonglong
>( num );
 
  856        else if ( jObj.is_number_integer() )
 
  858          const qlonglong num { jObj.get<qlonglong>() };
 
  859          if ( num <= std::numeric_limits<int>::max() && num >= std::numeric_limits<int>::lowest() )
 
  861            result = 
static_cast<int>( num );
 
  868        else if ( jObj.is_boolean() )
 
  870          result = jObj.get<
bool>();
 
  872        else if ( jObj.is_number_float() )
 
  875          result = jObj.get<
double>();
 
  877        else if ( jObj.is_string() )
 
  879          if ( isPrimitive && jObj.get<std::string>().length() == 0 )
 
  881            result = QString::fromStdString( jObj.get<std::string>() ).append( 
"\"" ).insert( 0, 
"\"" );
 
  885            result = QString::fromStdString( jObj.get<std::string>() );
 
  888        else if ( jObj.is_null() )
 
  897  return _parser( value );
 
 
  902  return jsonString.isEmpty() ? QVariant() : 
parseJson( jsonString.toStdString() );
 
 
  909  for ( 
int i = 0; i < fields.
count(); ++i )
 
  913    if ( layer && useFieldFormatters )
 
  918        val = fieldFormatter->
representValue( layer, i, setup.
config(), attributeWidgetCaches.count() >= i ? attributeWidgetCaches.at( i ) : QVariant(), val );
 
 
  932  value[
"crs"][
"type"] = 
"name";
 
  933  value[
"crs"][
"properties"][
"name"] = 
crs.
toOgcUrn().toStdString();
 
 
@ Success
Operation succeeded.
 
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
 
static QgsFieldFormatterRegistry * fieldFormatterRegistry()
Gets the registry of available field formatters.
 
Represents a coordinate reference system (CRS).
 
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
 
QString toOgcUrn() const
Returns the crs as OGC URN (format: urn:ogc:def:crs:OGC:1.3:CRS84) Returns an empty string on failure...
 
Custom exception class for Coordinate Reference System related exceptions.
 
Wrapper for iterator of features from vector data provider or vector layer.
 
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
 
Wraps a request for features to a vector layer (or directly its vector data provider).
 
QgsFeatureRequest & setFlags(Qgis::FeatureRequestFlags flags)
Sets flags that affect how features will be fetched.
 
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
 
Encapsulate a field in an attribute table or data source.
 
QgsEditorWidgetSetup editorWidgetSetup() const
Gets the editor widget setup for the field.
 
Container of fields for a vector layer.
 
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
 
A geometry is the spatial representation of a feature.
 
Qgis::GeometryOperationResult transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool transformZ=false)
Transforms this geometry as described by the coordinate transform ct.
 
virtual json asJsonObject(int precision=17) const
Exports the geometry to a json object.
 
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
 
Qgis::WkbType wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
 
json exportFeatureToJsonObject(const QgsFeature &feature, const QVariantMap &extraProperties=QVariantMap(), const QVariant &id=QVariant()) const
Returns a QJsonObject representation of a feature.
 
json exportFeaturesToJsonObject(const QgsFeatureList &features) const
Returns a JSON object representation of a list of features (feature collection).
 
void setSourceCrs(const QgsCoordinateReferenceSystem &crs)
Sets the source CRS for feature geometries.
 
void setDestinationCrs(const QgsCoordinateReferenceSystem &destinationCrs)
Set the destination CRS for feature geometry transformation to destinationCrs, this defaults to EPSG:...
 
QgsVectorLayer * vectorLayer() const
Returns the associated vector layer, if set.
 
QString exportFeature(const QgsFeature &feature, const QVariantMap &extraProperties=QVariantMap(), const QVariant &id=QVariant(), int indent=-1) const
Returns a GeoJSON string representation of a feature.
 
QString exportFeatures(const QgsFeatureList &features, int indent=-1) const
Returns a GeoJSON string representation of a list of features (feature collection).
 
void setVectorLayer(QgsVectorLayer *vectorLayer)
Sets the associated vector layer (required for related attribute export).
 
QgsCoordinateReferenceSystem sourceCrs() const
Returns the source CRS for feature geometries.
 
QgsJsonExporter(QgsVectorLayer *vectorLayer=nullptr, int precision=6)
Constructor for QgsJsonExporter.
 
static QgsGeometry geometryFromGeoJson(const json &geometry)
Parses a GeoJSON "geometry" value to a QgsGeometry object.
 
static QString exportAttributes(const QgsFeature &feature, QgsVectorLayer *layer=nullptr, const QVector< QVariant > &attributeWidgetCaches=QVector< QVariant >())
Exports all attributes from a QgsFeature as a JSON map type.
 
static QgsFeatureList stringToFeatureList(const QString &string, const QgsFields &fields=QgsFields(), QTextCodec *encoding SIP_PYARGREMOVE6=nullptr)
Attempts to parse a GeoJSON string to a collection of features.
 
static Q_INVOKABLE QString encodeValue(const QVariant &value)
Encodes a value to a JSON string representation, adding appropriate quotations and escaping where req...
 
static QVariant parseJson(const std::string &jsonString)
Converts JSON jsonString to a QVariant, in case of parsing error an invalid QVariant is returned and ...
 
static void addCrsInfo(json &value, const QgsCoordinateReferenceSystem &crs)
Add crs information entry in json object regarding old GeoJSON specification format if it differs fro...
 
static Q_INVOKABLE QVariantList parseArray(const QString &json, QMetaType::Type type=QMetaType::Type::UnknownType)
Parse a simple array (depth=1)
 
static json exportAttributesToJsonObject(const QgsFeature &feature, QgsVectorLayer *layer=nullptr, const QVector< QVariant > &attributeWidgetCaches=QVector< QVariant >(), bool useFieldFormatters=true)
Exports all attributes from a QgsFeature as a json object.
 
static QVariant jsonToVariant(const json &value)
Converts a JSON value to a QVariant, in case of parsing error an invalid QVariant is returned.
 
static QgsFields stringToFields(const QString &string, QTextCodec *encoding SIP_PYARGREMOVE6=nullptr)
Attempts to retrieve the fields from a GeoJSON string representing a collection of features.
 
static json jsonFromVariant(const QVariant &v)
Converts a QVariant v to a json object.
 
static void warning(const QString &msg)
Goes to qWarning.
 
QgsCoordinateReferenceSystem crs
 
static QgsFeatureList stringToFeatureList(const QString &string, const QgsFields &fields, QTextCodec *encoding)
Attempts to parse a string representing a collection of features using OGR.
 
static QgsFields stringToFields(const QString &string, QTextCodec *encoding)
Attempts to retrieve the fields from a string representing a collection of features using OGR.
 
QgsRelationManager * relationManager
 
static QgsProject * instance()
Returns the QgsProject singleton instance.
 
A rectangle specified with double values.
 
QList< QgsRelation > referencedRelations(const QgsVectorLayer *layer=nullptr) const
Gets all relations where this layer is the referenced part (i.e.
 
static QMetaType::Type variantTypeToMetaType(QVariant::Type variantType)
Converts a QVariant::Type to a QMetaType::Type.
 
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
 
static QVariant createNullVariant(QMetaType::Type metaType)
Helper method to properly create a null QVariant from a metaType Returns the created QVariant.
 
Represents a vector layer which manages a vector based dataset.
 
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
 
static Qgis::WkbType flatType(Qgis::WkbType type)
Returns the flat type for a WKB type.
 
double qgsRound(double number, int places)
Returns a double number, rounded (as close as possible) to the specified number of places.
 
QList< QgsFeature > QgsFeatureList
 
std::unique_ptr< QgsPoint > parsePointFromGeoJson(const json &coords)
 
std::unique_ptr< QgsPolygon > parsePolygonFromGeoJson(const json &coords)
 
std::unique_ptr< QgsAbstractGeometry > parseGeometryFromGeoJson(const json &geometry)
 
std::unique_ptr< QgsLineString > parseLineStringFromGeoJson(const json &coords)
 
#define QgsDebugError(str)
 
const QgsCoordinateReferenceSystem & crs