26#include <QCryptographicHash> 
   28#include <nlohmann/json.hpp> 
   32QgsSensorThingsSharedData::QgsSensorThingsSharedData( 
const QString &uri )
 
   34  const QVariantMap uriParts = QgsSensorThingsProviderMetadata().decodeUri( uri );
 
   37  const QVariantList expandTo = uriParts.value( QStringLiteral( 
"expandTo" ) ).toList();
 
   38  QList< Qgis::SensorThingsEntity > expandedEntities;
 
   39  for ( 
const QVariant &expansionVariant : expandTo )
 
   44      mExpansions.append( expansion );
 
   55  mMaximumPageSize = uriParts.value( QStringLiteral( 
"pageSize" ), mMaximumPageSize ).toInt();
 
   57  mFeatureLimit = uriParts.value( QStringLiteral( 
"featureLimit" ) ).toInt();
 
   58  mFilterExtent = uriParts.value( QStringLiteral( 
"bounds" ) ).value< 
QgsRectangle >();
 
   59  mSubsetString = uriParts.value( QStringLiteral( 
"sql" ) ).toString();
 
   63    if ( uriParts.contains( QStringLiteral( 
"geometryType" ) ) )
 
   65      const QString geometryType = uriParts.value( QStringLiteral( 
"geometryType" ) ).toString();
 
   66      if ( geometryType.compare( QLatin1String( 
"point" ), Qt::CaseInsensitive ) == 0 )
 
   70      else if ( geometryType.compare( QLatin1String( 
"multipoint" ), Qt::CaseInsensitive ) == 0 )
 
   74      else if ( geometryType.compare( QLatin1String( 
"line" ), Qt::CaseInsensitive ) == 0 )
 
   78      else if ( geometryType.compare( QLatin1String( 
"polygon" ), Qt::CaseInsensitive ) == 0 )
 
  100  mAuthCfg = dsUri.authConfigId();
 
  101  mHeaders = dsUri.httpHeaders();
 
  103  mRootUri = uriParts.value( QStringLiteral( 
"url" ) ).toString();
 
  106QUrl QgsSensorThingsSharedData::parseUrl( 
const QUrl &url, 
bool *isTestEndpoint )
 
  108  if ( isTestEndpoint )
 
  109    *isTestEndpoint = 
false;
 
  111  QUrl modifiedUrl( url );
 
  112  if ( modifiedUrl.toString().contains( QLatin1String( 
"fake_qgis_http_endpoint" ) ) )
 
  114    if ( isTestEndpoint )
 
  115      *isTestEndpoint = 
true;
 
  118    QString modifiedUrlString = modifiedUrl.toString();
 
  120    modifiedUrlString = QUrl::fromPercentEncoding( modifiedUrlString.toUtf8() );
 
  121    modifiedUrlString.replace( QLatin1String( 
"fake_qgis_http_endpoint/" ), QLatin1String( 
"fake_qgis_http_endpoint_" ) );
 
  123    modifiedUrlString = modifiedUrlString.mid( QStringLiteral( 
"http://" ).size() );
 
  124    QString args = modifiedUrlString.indexOf( 
'?' ) >= 0 ? modifiedUrlString.mid( modifiedUrlString.indexOf( 
'?' ) ) : QString();
 
  125    if ( modifiedUrlString.size() > 150 )
 
  127      args = QCryptographicHash::hash( args.toUtf8(), QCryptographicHash::Md5 ).toHex();
 
  131      args.replace( QLatin1String( 
"?" ), QLatin1String( 
"_" ) );
 
  132      args.replace( QLatin1String( 
"&" ), QLatin1String( 
"_" ) );
 
  133      args.replace( QLatin1String( 
"$" ), QLatin1String( 
"_" ) );
 
  134      args.replace( QLatin1String( 
"<" ), QLatin1String( 
"_" ) );
 
  135      args.replace( QLatin1String( 
">" ), QLatin1String( 
"_" ) );
 
  136      args.replace( QLatin1String( 
"'" ), QLatin1String( 
"_" ) );
 
  137      args.replace( QLatin1String( 
"\"" ), QLatin1String( 
"_" ) );
 
  138      args.replace( QLatin1String( 
" " ), QLatin1String( 
"_" ) );
 
  139      args.replace( QLatin1String( 
":" ), QLatin1String( 
"_" ) );
 
  140      args.replace( QLatin1String( 
"/" ), QLatin1String( 
"_" ) );
 
  141      args.replace( QLatin1String( 
"\n" ), QLatin1String( 
"_" ) );
 
  146    if ( modifiedUrlString[1] == 
'/' )
 
  148      modifiedUrlString = modifiedUrlString[0] + 
":/" + modifiedUrlString.mid( 2 );
 
  151    modifiedUrlString = modifiedUrlString.mid( 0, modifiedUrlString.indexOf( 
'?' ) ) + args;
 
  152    QgsDebugMsgLevel( QStringLiteral( 
"Get %1 (after laundering)" ).arg( modifiedUrlString ), 2 );
 
  153    modifiedUrl = QUrl::fromLocalFile( modifiedUrlString );
 
  154    if ( !QFile::exists( modifiedUrlString ) )
 
  156      QgsDebugError( QStringLiteral( 
"Local test file %1 for URL %2 does not exist!!!" ).arg( modifiedUrlString, url.toString() ) );
 
  169  return hasCachedAllFeatures() ? mFetchedFeatureExtent
 
  170         : ( !mFilterExtent.isNull() ? mFilterExtent : 
QgsRectangle( -180, -90, 180, 90 ) );
 
  173long long QgsSensorThingsSharedData::featureCount( 
QgsFeedback *feedback )
 const 
  176  if ( mFeatureCount >= 0 )
 
  177    return mFeatureCount;
 
  185  if ( !mExpansions.isEmpty() )
 
  191  QString countUri = QStringLiteral( 
"%1?$top=0&$count=true" ).arg( mEntityBaseUri );
 
  195  if ( !filterString.isEmpty() )
 
  196    filterString = QStringLiteral( 
"&$filter=" ) + filterString;
 
  197  if ( !filterString.isEmpty() )
 
  198    countUri += filterString;
 
  200  const QUrl url = parseUrl( QUrl( countUri ) );
 
  202  QNetworkRequest request( url );
 
  204  mHeaders.updateNetworkRequest( request );
 
  211    return mFeatureCount;
 
  224      auto rootContent = json::parse( content.
content().toStdString() );
 
  225      if ( !rootContent.contains( 
"@iot.count" ) )
 
  227        mError = QObject::tr( 
"No '@iot.count' value in response" );
 
  228        return mFeatureCount;
 
  231      mFeatureCount = rootContent[
"@iot.count"].get<
long long>();
 
  232      if ( mFeatureLimit > 0 && mFeatureCount > mFeatureLimit )
 
  233        mFeatureCount = mFeatureLimit;
 
  235    catch ( 
const json::parse_error &ex )
 
  237      mError = QObject::tr( 
"Error parsing response: %1" ).arg( ex.what() );
 
  241  return mFeatureCount;
 
  244QString QgsSensorThingsSharedData::subsetString()
 const 
  246  return mSubsetString;
 
  249bool QgsSensorThingsSharedData::hasCachedAllFeatures()
 const 
  252  return mHasCachedAllFeatures
 
  253         || ( mFeatureCount > 0 && mCachedFeatures.size() == mFeatureCount )
 
  254         || ( mFeatureLimit > 0 && mRetrievedBaseFeatureCount >= mFeatureLimit );
 
  262  QMap<QgsFeatureId, QgsFeature>::const_iterator it = mCachedFeatures.constFind( 
id );
 
  263  if ( it != mCachedFeatures.constEnd() )
 
  269  if ( hasCachedAllFeatures() )
 
  272  bool featureFetched = 
false;
 
  274  if ( mNextPage.isEmpty() )
 
  278    int thisPageSize = mMaximumPageSize;
 
  279    if ( mFeatureLimit > 0 && ( mCachedFeatures.size() + thisPageSize ) > mFeatureLimit )
 
  280      thisPageSize = mFeatureLimit - mCachedFeatures.size();
 
  282    mNextPage = QStringLiteral( 
"%1?$top=%2&$count=false%3" ).arg( mEntityBaseUri ).arg( thisPageSize ).arg( !mExpandQueryString.isEmpty() ? ( QStringLiteral( 
"&" ) + mExpandQueryString ) : QString() );
 
  286    if ( !filterString.isEmpty() )
 
  287      mNextPage += QStringLiteral( 
"&$filter=" ) + filterString;
 
  292  processFeatureRequest( mNextPage, feedback, [
id, &f, &featureFetched]( 
const QgsFeature & feature )
 
  294    if ( feature.
id() == 
id )
 
  297      featureFetched = true;
 
  300  }, [&featureFetched, 
this]
 
  302    return !featureFetched && !hasCachedAllFeatures();
 
  306    mHasCachedAllFeatures = 
true;
 
  309  return featureFetched;
 
  318  if ( hasCachedAllFeatures() || mCachedExtent.contains( extentGeom ) )
 
  322    return qgis::listToSet( mSpatialIndex.intersects( requestExtent ) );
 
  328  if ( !filterString.isEmpty() )
 
  329    filterString = QStringLiteral( 
"&$filter=" ) + filterString;
 
  330  int thisPageSize = mMaximumPageSize;
 
  332  if ( !thisPage.isEmpty() )
 
  335    const thread_local QRegularExpression topRe( QStringLiteral( 
"\\$top=\\d+" ) );
 
  336    const QRegularExpressionMatch match = topRe.match( queryUrl );
 
  337    if ( match.hasMatch() )
 
  339      if ( mFeatureLimit > 0 && ( mCachedFeatures.size() + thisPageSize ) > mFeatureLimit )
 
  340        thisPageSize = mFeatureLimit - mCachedFeatures.size();
 
  341      queryUrl = queryUrl.left( match.capturedStart( 0 ) ) + QStringLiteral( 
"$top=%1" ).arg( thisPageSize ) + queryUrl.mid( match.capturedEnd( 0 ) );
 
  346    queryUrl = QStringLiteral( 
"%1?$top=%2&$count=false%3%4" ).arg( mEntityBaseUri ).arg( thisPageSize ).arg( filterString, !mExpandQueryString.isEmpty() ? ( QStringLiteral( 
"&" ) + mExpandQueryString ) : QString() );
 
  349  if ( thisPage.isEmpty() && mCachedExtent.intersects( extentGeom ) )
 
  355    return qgis::listToSet( mSpatialIndex.intersects( requestExtent ) );
 
  362  bool noMoreFeatures = 
false;
 
  363  bool hasFirstPage = 
false;
 
  364  const bool res = processFeatureRequest( queryUrl, feedback, [&ids, &alreadyFetchedIds]( 
const QgsFeature & feature )
 
  366    if ( !alreadyFetchedIds.contains( feature.
id() ) )
 
  367      ids.insert( feature.
id() );
 
  379    noMoreFeatures = 
true;
 
  381  if ( noMoreFeatures && res && ( !feedback || !feedback->
isCanceled() ) )
 
  386  nextPage = noMoreFeatures || !res ? QString() : queryUrl;
 
  391void QgsSensorThingsSharedData::clearCache()
 
  396  mCachedFeatures.clear();
 
  397  mIotIdToFeatureId.clear();
 
  402bool QgsSensorThingsSharedData::processFeatureRequest( QString &nextPage, 
QgsFeedback *feedback, 
const std::function< 
void( 
const QgsFeature & ) > &fetchedFeatureCallback, 
const std::function<
bool ()> &continueFetchingCallback, 
const std::function<
void ()> &onNoMoreFeaturesCallback )
 
  407  const QString authcfg = mAuthCfg;
 
  410  const QList< QgsSensorThingsExpansionDefinition > expansions = mExpansions;
 
  412  while ( continueFetchingCallback() )
 
  421    const QUrl url = parseUrl( nextPage );
 
  423    QNetworkRequest request( url );
 
  448        const auto rootContent = json::parse( content.
content().toStdString() );
 
  449        if ( !rootContent.contains( 
"value" ) )
 
  452          mError = QObject::tr( 
"No 'value' in response" );
 
  459          const auto &values = rootContent[
"value"];
 
  460          if ( values.empty() )
 
  464            onNoMoreFeaturesCallback();
 
  471            for ( 
const auto &featureData : values )
 
  473              auto getString = []( 
const basic_json<> &json, 
const char *tag ) -> QVariant
 
  475                if ( !json.contains( tag ) )
 
  478                std::function< QString( 
const basic_json<> &obj, 
bool &ok ) > objToString;
 
  479                objToString = [&objToString]( 
const basic_json<> &obj, 
bool & ok ) -> QString
 
  482                  if ( obj.is_number_integer() )
 
  484                    return QString::number( obj.get<
int>() );
 
  486                  else if ( obj.is_number_unsigned() )
 
  488                    return QString::number( obj.get<
unsigned>() );
 
  490                  else if ( obj.is_boolean() )
 
  492                    return QString::number( obj.get<
bool>() );
 
  494                  else if ( obj.is_number_float() )
 
  496                    return QString::number( obj.get<
double>() );
 
  498                  else if ( obj.is_array() )
 
  501                    results.reserve( obj.size() );
 
  502                    for ( 
const auto &item : obj )
 
  505                      const QString itemString = objToString( item, itemOk );
 
  507                        results.push_back( itemString );
 
  509                    return results.join( 
',' );
 
  511                  else if ( obj.is_string() )
 
  513                    return QString::fromStdString( obj.get<std::string >() );
 
  520                const auto &jObj = json[tag];
 
  522                const QString r = objToString( jObj, ok );
 
  528              auto getDateTime = []( 
const basic_json<> &json, 
const char *tag ) -> QVariant
 
  530                if ( !json.contains( tag ) )
 
  533                const auto &jObj = json[tag];
 
  534                if ( jObj.is_string() )
 
  536                  const QString dateTimeString = QString::fromStdString( json[tag].get<std::string >() );
 
  537                  return QDateTime::fromString( dateTimeString, Qt::ISODateWithMs );
 
  543              auto getVariantMap = []( 
const basic_json<> &json, 
const char *tag ) -> QVariant
 
  545                if ( !json.contains( tag ) )
 
  551              auto getVariantList = []( 
const basic_json<> &json, 
const char *tag ) -> QVariant
 
  553                if ( !json.contains( tag ) )
 
  559              auto getStringList = []( 
const basic_json<> &json, 
const char *tag ) -> QVariant
 
  561                if ( !json.contains( tag ) )
 
  564                const auto &jObj = json[tag];
 
  565                if ( jObj.is_string() )
 
  567                  return QStringList{ QString::fromStdString( json[tag].get<std::string >() ) };
 
  569                else if ( jObj.is_array() )
 
  572                  for ( 
const auto &element : jObj )
 
  574                    if ( element.is_string() )
 
  575                      res.append( QString::fromStdString( element.get<std::string >() ) );
 
  583              auto getDateTimeRange = []( 
const basic_json<> &json, 
const char *tag ) -> std::pair< QVariant, QVariant >
 
  585                if ( !json.contains( tag ) )
 
  586                  return { QVariant(), QVariant() };
 
  588                const auto &jObj = json[tag];
 
  589                if ( jObj.is_string() )
 
  591                  const QString rangeString = QString::fromStdString( json[tag].get<std::string >() );
 
  592                  const QStringList rangeParts = rangeString.split( 
'/' );
 
  593                  if ( rangeParts.size() == 2 )
 
  597                      QDateTime::fromString( rangeParts.at( 0 ), Qt::ISODateWithMs ),
 
  598                      QDateTime::fromString( rangeParts.at( 1 ), Qt::ISODateWithMs )
 
  603                    const QDateTime instant = QDateTime::fromString( rangeString, Qt::ISODateWithMs );
 
  604                    if ( instant.isValid() )
 
  605                      return { instant, instant };
 
  609                return { QVariant(), QVariant() };
 
  612              const QString iotId = getString( featureData, 
"@iot.id" ).toString();
 
  613              if ( expansions.isEmpty() )
 
  615                auto existingFeatureIdIt = mIotIdToFeatureId.constFind( iotId );
 
  616                if ( existingFeatureIdIt != mIotIdToFeatureId.constEnd() )
 
  619                  fetchedFeatureCallback( *mCachedFeatures.find( *existingFeatureIdIt ) );
 
  629                if ( featureData.contains( mGeometryField.toLocal8Bit().constData() ) )
 
  631                  const auto &geometryPart = featureData[mGeometryField.toLocal8Bit().constData()];
 
  632                  if ( geometryPart.contains( 
"geometry" ) )
 
  639              auto extendAttributes = [&getString, &getVariantMap, &getDateTimeRange, &getDateTime, &getStringList, &getVariantList]( 
Qgis::SensorThingsEntity entityType, 
const auto & entityData, 
QgsAttributes & attributes )
 
  641                const QString iotId = getString( entityData, 
"@iot.id" ).toString();
 
  642                const QString selfLink = getString( entityData, 
"@iot.selfLink" ).toString();
 
  644                const QVariant properties = getVariantMap( entityData, 
"properties" );
 
  647                switch ( entityType )
 
  656                        << getString( entityData, 
"name" )
 
  657                        << getString( entityData, 
"description" )
 
  665                        << getString( entityData, 
"name" )
 
  666                        << getString( entityData, 
"description" )
 
  674                        << getDateTime( entityData, 
"time" );
 
  679                    std::pair< QVariant, QVariant > phenomenonTime = getDateTimeRange( entityData, 
"phenomenonTime" );
 
  680                    std::pair< QVariant, QVariant > resultTime = getDateTimeRange( entityData, 
"resultTime" );
 
  684                        << getString( entityData, 
"name" )
 
  685                        << getString( entityData, 
"description" )
 
  686                        << getVariantMap( entityData, 
"unitOfMeasurement" )
 
  687                        << getString( entityData, 
"observationType" )
 
  689                        << phenomenonTime.first
 
  690                        << phenomenonTime.second
 
  692                        << resultTime.second;
 
  700                        << getString( entityData, 
"name" )
 
  701                        << getString( entityData, 
"description" )
 
  702                        << getString( entityData, 
"metadata" )
 
  710                        << getString( entityData, 
"name" )
 
  711                        << getString( entityData, 
"definition" )
 
  712                        << getString( entityData, 
"description" )
 
  718                    std::pair< QVariant, QVariant > phenomenonTime = getDateTimeRange( entityData, 
"phenomenonTime" );
 
  719                    std::pair< QVariant, QVariant > validTime = getDateTimeRange( entityData, 
"validTime" );
 
  723                        << phenomenonTime.first
 
  724                        << phenomenonTime.second
 
  725                        << getString( entityData, 
"result" ) 
 
  726                        << getDateTime( entityData, 
"resultTime" )
 
  727                        << getStringList( entityData, 
"resultQuality" )
 
  730                        << getVariantMap( entityData, 
"parameters" );
 
  738                        << getString( entityData, 
"name" )
 
  739                        << getString( entityData, 
"description" )
 
  745                    std::pair< QVariant, QVariant > phenomenonTime = getDateTimeRange( entityData, 
"phenomenonTime" );
 
  746                    std::pair< QVariant, QVariant > resultTime = getDateTimeRange( entityData, 
"resultTime" );
 
  750                        << getString( entityData, 
"name" )
 
  751                        << getString( entityData, 
"description" )
 
  752                        << getVariantList( entityData, 
"unitOfMeasurements" )
 
  753                        << getString( entityData, 
"observationType" )
 
  754                        << getStringList( entityData, 
"multiObservationDataTypes" )
 
  756                        << phenomenonTime.first
 
  757                        << phenomenonTime.second
 
  759                        << resultTime.second;
 
  767              attributes.reserve( fields.
size() );
 
  768              extendAttributes( mEntityType, featureData, attributes );
 
  770              auto processFeature = [
this, &fetchedFeatureCallback]( 
QgsFeature & feature, 
const QString & rawFeatureId )
 
  772                feature.
setId( mNextFeatureId++ );
 
  774                mCachedFeatures.insert( feature.
id(), feature );
 
  775                mIotIdToFeatureId.insert( rawFeatureId, feature.
id() );
 
  776                mSpatialIndex.addFeature( feature );
 
  779                fetchedFeatureCallback( feature );
 
  782              const QString baseFeatureId = getString( featureData, 
"@iot.id" ).toString();
 
  783              if ( !expansions.empty() )
 
  785                mRetrievedBaseFeatureCount++;
 
  787                std::function< void( 
const nlohmann::json &, 
Qgis::SensorThingsEntity, 
const QList<QgsSensorThingsExpansionDefinition > &, 
const QString &, 
const QgsAttributes & ) > traverseExpansion;
 
  788                traverseExpansion = [
this, &feature, &getString, &traverseExpansion, &fetchedFeatureCallback, &extendAttributes, &processFeature]( 
const nlohmann::json & currentLevelData, 
Qgis::SensorThingsEntity parentEntityType, 
const QList<QgsSensorThingsExpansionDefinition > &expansionTargets, 
const QString & lowerLevelId, 
const QgsAttributes & lowerLevelAttributes )
 
  791                  const QList< QgsSensorThingsExpansionDefinition > remainingExpansionTargets = expansionTargets.mid( 1 );
 
  795                  QString currentExpansionPropertyString;
 
  796                  switch ( cardinality )
 
  809                  if ( currentLevelData.contains( currentExpansionPropertyString.toLocal8Bit().constData() ) )
 
  811                    auto parseExpandedEntity = [lowerLevelAttributes, &feature, &processFeature, &lowerLevelId, &getString, &remainingExpansionTargets, &fetchedFeatureCallback, &extendAttributes, &traverseExpansion, ¤tExpansionTarget, 
this]( 
const json & expandedEntityElement )
 
  814                      const QString expandedEntityIotId = getString( expandedEntityElement, 
"@iot.id" ).toString();
 
  815                      const QString expandedFeatureId = lowerLevelId + 
'_' + expandedEntityIotId;
 
  817                      if ( remainingExpansionTargets.empty() )
 
  819                        auto existingFeatureIdIt = mIotIdToFeatureId.constFind( expandedFeatureId );
 
  820                        if ( existingFeatureIdIt != mIotIdToFeatureId.constEnd() )
 
  823                          fetchedFeatureCallback( *mCachedFeatures.find( *existingFeatureIdIt ) );
 
  828                      extendAttributes( currentExpansionTarget.childEntity(), expandedEntityElement, expandedAttributes );
 
  829                      if ( !remainingExpansionTargets.empty() )
 
  832                        traverseExpansion( expandedEntityElement, currentExpansionTarget.childEntity(), remainingExpansionTargets, expandedFeatureId, expandedAttributes );
 
  836                        feature.setAttributes( expandedAttributes );
 
  837                        processFeature( feature, expandedFeatureId );
 
  840                    const auto &expandedEntity = currentLevelData[currentExpansionPropertyString.toLocal8Bit().constData()];
 
  841                    if ( expandedEntity.is_array() )
 
  843                      for ( 
const auto &expandedEntityElement : expandedEntity )
 
  845                        parseExpandedEntity( expandedEntityElement );
 
  851                    else if ( expandedEntity.is_object() )
 
  853                      parseExpandedEntity( expandedEntity );
 
  864                traverseExpansion( featureData, mEntityType, expansions, baseFeatureId, attributes );
 
  866                if ( mFeatureLimit > 0 && mFeatureLimit <= mRetrievedBaseFeatureCount )
 
  871                feature.setAttributes( attributes );
 
  872                processFeature( feature, baseFeatureId );
 
  873                mRetrievedBaseFeatureCount++;
 
  874                if ( mFeatureLimit > 0 && mFeatureLimit <= mRetrievedBaseFeatureCount )
 
  881          if ( rootContent.contains( 
"@iot.nextLink" ) && ( mFeatureLimit == 0 || mFeatureLimit > mCachedFeatures.size() ) )
 
  883            nextPage = QString::fromStdString( rootContent[
"@iot.nextLink"].get<std::string>() );
 
  887            onNoMoreFeaturesCallback();
 
  891          if ( !continueFetchingCallback() )
 
  897      catch ( 
const json::parse_error &ex )
 
  900        mError = QObject::tr( 
"Error parsing response: %1" ).arg( ex.what() );
 
  901        QgsDebugMsgLevel( QStringLiteral( 
"Error parsing response: %1" ).arg( ex.what() ), 2 );
 
SensorThingsEntity
OGC SensorThings API entity types.
 
@ Sensor
A Sensor is an instrument that observes a property or phenomenon with the goal of producing an estima...
 
@ MultiDatastream
A MultiDatastream groups a collection of Observations and the Observations in a MultiDatastream have ...
 
@ ObservedProperty
An ObservedProperty specifies the phenomenon of an Observation.
 
@ Invalid
An invalid/unknown entity.
 
@ FeatureOfInterest
In the context of the Internet of Things, many Observations’ FeatureOfInterest can be the Location of...
 
@ Datastream
A Datastream groups a collection of Observations measuring the same ObservedProperty and produced by ...
 
@ Observation
An Observation is the act of measuring or otherwise determining the value of a property.
 
@ Location
A Location entity locates the Thing or the Things it associated with. A Thing’s Location entity is de...
 
@ Thing
A Thing is an object of the physical world (physical things) or the information world (virtual things...
 
@ HistoricalLocation
A Thing’s HistoricalLocation entity set provides the times of the current (i.e., last known) and prev...
 
RelationshipCardinality
Relationship cardinality.
 
@ ManyToMany
Many to many relationship.
 
@ ManyToOne
Many to one relationship.
 
@ OneToOne
One to one relationship.
 
@ OneToMany
One to many relationship.
 
@ MultiPointZ
MultiPointZ.
 
@ MultiLineStringZ
MultiLineStringZ.
 
@ MultiPolygonZ
MultiPolygonZ.
 
A thread safe class for performing blocking (sync) network requests, with full support for QGIS proxy...
 
void setAuthCfg(const QString &authCfg)
Sets the authentication config id which should be used during the request.
 
QString errorMessage() const
Returns the error message string, after a get(), post(), head() or put() request has been made.
 
ErrorCode get(QNetworkRequest &request, bool forceRefresh=false, QgsFeedback *feedback=nullptr, RequestFlags requestFlags=QgsBlockingNetworkRequest::RequestFlags())
Performs a "get" operation on the specified request.
 
@ NoError
No error was encountered.
 
QgsNetworkReplyContent reply() const
Returns the content of the network reply, after a get(), post(), head() or put() request has been mad...
 
Represents a coordinate reference system (CRS).
 
Stores the component parts of a data source URI (e.g.
 
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
 
void setId(QgsFeatureId id)
Sets the feature id for this feature.
 
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
 
Base class for feedback objects to be used for cancellation of something running in a worker thread.
 
bool isCanceled() const
Tells whether the operation has been canceled already.
 
Container of fields for a vector layer.
 
int size() const
Returns number of items.
 
A geometry is the spatial representation of a feature.
 
static QgsGeometry fromRect(const QgsRectangle &rect)
Creates a new geometry from a QgsRectangle.
 
static QgsGeometry unaryUnion(const QVector< QgsGeometry > &geometries, const QgsGeometryParameters ¶meters=QgsGeometryParameters())
Compute the unary union on a list of geometries.
 
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
 
static QgsGeometry geometryFromGeoJson(const json &geometry)
Parses a GeoJSON "geometry" value to a QgsGeometry object.
 
static QVariant jsonToVariant(const json &value)
Converts a JSON value to a QVariant, in case of parsing error an invalid QVariant is returned.
 
Encapsulates a network reply within a container which is inexpensive to copy and safe to pass between...
 
QByteArray content() const
Returns the reply content.
 
A convenience class that simplifies locking and unlocking QReadWriteLocks.
 
A rectangle specified with double values.
 
QgsRectangle intersect(const QgsRectangle &rect) const
Returns the intersection with the given rectangle.
 
Encapsulates information about how relationships in a SensorThings API service should be expanded.
 
Qgis::SensorThingsEntity childEntity() const
Returns the target child entity which should be expanded.
 
bool isValid() const
Returns true if the definition is valid.
 
static QString entityToSetString(Qgis::SensorThingsEntity type)
Converts a SensorThings entity set to a SensorThings entity set string.
 
static QString asQueryString(Qgis::SensorThingsEntity baseType, const QList< QgsSensorThingsExpansionDefinition > &expansions)
Returns a list of expansions as a valid SensorThings API query string, eg "$expand=Locations($orderby...
 
static QString combineFilters(const QStringList &filters)
Combines a set of SensorThings API filter operators.
 
static QString filterForWkbType(Qgis::SensorThingsEntity entityType, Qgis::WkbType wkbType)
Returns a filter string which restricts results to those matching the specified entityType and wkbTyp...
 
static Qgis::RelationshipCardinality relationshipCardinality(Qgis::SensorThingsEntity baseType, Qgis::SensorThingsEntity relatedType, bool &valid)
Returns the cardinality of the relationship between a base entity type and a related entity type.
 
static bool entityTypeHasGeometry(Qgis::SensorThingsEntity type)
Returns true if the specified entity type can have geometry attached.
 
static QgsFields fieldsForExpandedEntityType(Qgis::SensorThingsEntity baseType, const QList< Qgis::SensorThingsEntity > &expandedTypes)
Returns the fields which correspond to a specified entity baseType, expanded using the specified list...
 
static QString geometryFieldForEntityType(Qgis::SensorThingsEntity type)
Returns the geometry field for a specified entity type.
 
static QString filterForExtent(const QString &geometryField, const QgsRectangle &extent)
Returns a filter string which restricts results to those within the specified extent.
 
A spatial index for QgsFeature objects.
 
@ Uncounted
Feature count not yet computed.
 
@ UnknownCount
Provider returned an unknown feature count.
 
T qgsEnumKeyToValue(const QString &key, const T &defaultValue, bool tryValueAsKey=true, bool *returnOk=nullptr)
Returns the value corresponding to the given key of an enum.
 
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
 
QSet< QgsFeatureId > QgsFeatureIds
 
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
 
#define QgsDebugMsgLevel(str, level)
 
#define QgsDebugError(str)
 
#define QgsSetRequestInitiatorClass(request, _class)