18#include <nlohmann/json.hpp>
29#include <QCryptographicHash>
33using namespace Qt::StringLiterals;
37QgsSensorThingsSharedData::QgsSensorThingsSharedData(
const QString &uri )
39 const QVariantMap uriParts = QgsSensorThingsProviderMetadata().decodeUri( uri );
42 const QVariantList expandTo = uriParts.value( u
"expandTo"_s ).toList();
43 QList< Qgis::SensorThingsEntity > expandedEntities;
44 for (
const QVariant &expansionVariant : expandTo )
49 mExpansions.append( expansion );
60 mMaximumPageSize = uriParts.value( u
"pageSize"_s, mMaximumPageSize ).toInt();
62 mFeatureLimit = uriParts.value( u
"featureLimit"_s ).toInt();
63 mFilterExtent = uriParts.value( u
"bounds"_s ).value<
QgsRectangle >();
64 mSubsetString = uriParts.value( u
"sql"_s ).
toString();
68 if ( uriParts.contains( u
"geometryType"_s ) )
70 const QString geometryType = uriParts.value( u
"geometryType"_s ).toString();
71 if ( geometryType.compare(
"point"_L1, Qt::CaseInsensitive ) == 0 )
75 else if ( geometryType.compare(
"multipoint"_L1, Qt::CaseInsensitive ) == 0 )
79 else if ( geometryType.compare(
"line"_L1, Qt::CaseInsensitive ) == 0 )
83 else if ( geometryType.compare(
"polygon"_L1, Qt::CaseInsensitive ) == 0 )
105 mAuthCfg = dsUri.authConfigId();
106 mHeaders = dsUri.httpHeaders();
108 mRootUri = uriParts.value( u
"url"_s ).toString();
111QUrl QgsSensorThingsSharedData::parseUrl(
const QUrl &url,
bool *isTestEndpoint )
113 if ( isTestEndpoint )
114 *isTestEndpoint =
false;
116 QUrl modifiedUrl( url );
117 if ( modifiedUrl.toString().contains(
"fake_qgis_http_endpoint"_L1 ) )
119 if ( isTestEndpoint )
120 *isTestEndpoint =
true;
123 QString modifiedUrlString = modifiedUrl.toString();
125 modifiedUrlString = QUrl::fromPercentEncoding( modifiedUrlString.toUtf8() );
126 modifiedUrlString.replace(
"fake_qgis_http_endpoint/"_L1,
"fake_qgis_http_endpoint_"_L1 );
128 modifiedUrlString = modifiedUrlString.mid( u
"http://"_s.size() );
129 QString args = modifiedUrlString.indexOf(
'?' ) >= 0 ? modifiedUrlString.mid( modifiedUrlString.indexOf(
'?' ) ) : QString();
130 if ( modifiedUrlString.size() > 150 )
132 args = QCryptographicHash::hash( args.toUtf8(), QCryptographicHash::Md5 ).toHex();
136 args.replace(
"?"_L1,
"_"_L1 );
137 args.replace(
"&"_L1,
"_"_L1 );
138 args.replace(
"$"_L1,
"_"_L1 );
139 args.replace(
"<"_L1,
"_"_L1 );
140 args.replace(
">"_L1,
"_"_L1 );
141 args.replace(
"'"_L1,
"_"_L1 );
142 args.replace(
"\""_L1,
"_"_L1 );
143 args.replace(
" "_L1,
"_"_L1 );
144 args.replace(
":"_L1,
"_"_L1 );
145 args.replace(
"/"_L1,
"_"_L1 );
146 args.replace(
"\n"_L1,
"_"_L1 );
151 if ( modifiedUrlString[1] ==
'/' )
153 modifiedUrlString = modifiedUrlString[0] +
":/" + modifiedUrlString.mid( 2 );
156 modifiedUrlString = modifiedUrlString.mid( 0, modifiedUrlString.indexOf(
'?' ) ) + args;
157 QgsDebugMsgLevel( u
"Get %1 (after laundering)"_s.arg( modifiedUrlString ), 2 );
158 modifiedUrl = QUrl::fromLocalFile( modifiedUrlString );
159 if ( !QFile::exists( modifiedUrlString ) )
161 QgsDebugError( u
"Local test file %1 for URL %2 does not exist!!!"_s.arg( modifiedUrlString, url.toString() ) );
174 return hasCachedAllFeatures() ? mFetchedFeatureExtent : ( !mFilterExtent.isNull() ? mFilterExtent :
QgsRectangle( -180, -90, 180, 90 ) );
177long long QgsSensorThingsSharedData::featureCount(
QgsFeedback *feedback )
const
180 if ( mFeatureCount >= 0 )
181 return mFeatureCount;
189 if ( !mExpansions.isEmpty() )
195 QString countUri = u
"%1?$top=0&$count=true"_s.arg( mEntityBaseUri );
199 if ( !filterString.isEmpty() )
200 filterString = u
"&$filter="_s + filterString;
201 if ( !filterString.isEmpty() )
202 countUri += filterString;
204 const QUrl url = parseUrl( QUrl( countUri ) );
206 QNetworkRequest request( url );
208 mHeaders.updateNetworkRequest( request );
215 return mFeatureCount;
227 const std::string countKey = mVersion >= QVersionNumber( 2, 0 ) ?
"@count" :
"@iot.count";
231 auto rootContent = json::parse( content.
content().toStdString() );
232 if ( !rootContent.contains( countKey ) )
234 mError = QObject::tr(
"No '%1' value in response" ).arg( QString::fromStdString( countKey ) );
235 return mFeatureCount;
238 mFeatureCount = rootContent[countKey].get<
long long>();
239 if ( mFeatureLimit > 0 && mFeatureCount > mFeatureLimit )
240 mFeatureCount = mFeatureLimit;
242 catch (
const json::parse_error &ex )
244 mError = QObject::tr(
"Error parsing response: %1" ).arg( ex.what() );
248 return mFeatureCount;
251QString QgsSensorThingsSharedData::subsetString()
const
253 return mSubsetString;
256bool QgsSensorThingsSharedData::hasCachedAllFeatures()
const
259 return mHasCachedAllFeatures || ( mFeatureCount > 0 && mCachedFeatures.size() == mFeatureCount ) || ( mFeatureLimit > 0 && mRetrievedBaseFeatureCount >= mFeatureLimit );
267 QMap<QgsFeatureId, QgsFeature>::const_iterator it = mCachedFeatures.constFind(
id );
268 if ( it != mCachedFeatures.constEnd() )
274 if ( hasCachedAllFeatures() )
277 bool featureFetched =
false;
279 if ( mNextPage.isEmpty() )
283 std::size_t thisPageSize = mMaximumPageSize;
284 if ( mFeatureLimit > 0 && ( mCachedFeatures.size() + thisPageSize ) >
static_cast< std::size_t
>( mFeatureLimit ) )
285 thisPageSize =
static_cast< std::size_t
>( mFeatureLimit ) - mCachedFeatures.size();
287 mNextPage = u
"%1?$top=%2&$count=false%3"_s.arg( mEntityBaseUri ).arg( thisPageSize ).arg( !mExpandQueryString.isEmpty() ? ( u
"&"_s + mExpandQueryString ) : QString() );
291 if ( !filterString.isEmpty() )
292 mNextPage += u
"&$filter="_s + filterString;
297 processFeatureRequest(
300 [
id, &f, &featureFetched](
const QgsFeature &feature ) {
301 if ( feature.
id() ==
id )
304 featureFetched =
true;
308 [&featureFetched,
this] {
return !featureFetched && !hasCachedAllFeatures(); },
311 mHasCachedAllFeatures =
true;
315 return featureFetched;
324 if ( hasCachedAllFeatures() || mCachedExtent.contains( extentGeom ) )
328 return qgis::listToSet( mSpatialIndex.intersects( requestExtent ) );
334 if ( !filterString.isEmpty() )
335 filterString = u
"&$filter="_s + filterString;
336 std::size_t thisPageSize = mMaximumPageSize;
338 if ( !thisPage.isEmpty() )
341 const thread_local QRegularExpression topRe( u
"\\$top=\\d+"_s );
342 const QRegularExpressionMatch match = topRe.match( queryUrl );
343 if ( match.hasMatch() )
345 if ( mFeatureLimit > 0 && ( mCachedFeatures.size() + thisPageSize ) >
static_cast< std::size_t
>( mFeatureLimit ) )
346 thisPageSize =
static_cast< std::size_t
>( mFeatureLimit ) - mCachedFeatures.size();
347 queryUrl = queryUrl.left( match.capturedStart( 0 ) ) + u
"$top=%1"_s.arg( thisPageSize ) + queryUrl.mid( match.capturedEnd( 0 ) );
352 queryUrl = u
"%1?$top=%2&$count=false%3%4"_s.arg( mEntityBaseUri ).arg( thisPageSize ).arg( filterString, !mExpandQueryString.isEmpty() ? ( u
"&"_s + mExpandQueryString ) : QString() );
355 if ( thisPage.isEmpty() && mCachedExtent.intersects( extentGeom ) )
361 return qgis::listToSet( mSpatialIndex.intersects( requestExtent ) );
368 bool noMoreFeatures =
false;
369 bool hasFirstPage =
false;
370 const bool res = processFeatureRequest(
373 [&ids, &alreadyFetchedIds](
const QgsFeature &feature ) {
374 if ( !alreadyFetchedIds.contains( feature.
id() ) )
375 ids.insert( feature.
id() );
386 [&noMoreFeatures] { noMoreFeatures =
true; }
388 if ( noMoreFeatures && res && ( !feedback || !feedback->
isCanceled() ) )
393 nextPage = noMoreFeatures || !res ? QString() : queryUrl;
398void QgsSensorThingsSharedData::clearCache()
403 mCachedFeatures.clear();
404 mIotIdToFeatureId.clear();
409bool QgsSensorThingsSharedData::processFeatureRequest(
412 const std::function<
void(
const QgsFeature & ) > &fetchedFeatureCallback,
413 const std::function<
bool()> &continueFetchingCallback,
414 const std::function<
void()> &onNoMoreFeaturesCallback
420 const QString authcfg = mAuthCfg;
423 const QList< QgsSensorThingsExpansionDefinition > expansions = mExpansions;
425 const bool isVersion2OrLater = mVersion >= QVersionNumber( 2, 0 );
426 const std::string idKey = isVersion2OrLater ?
"id" :
"@iot.id";
427 const std::string selfLinkKey = isVersion2OrLater ?
"@id" :
"@iot.selfLink";
428 const std::string nextLinkKey = isVersion2OrLater ?
"@nextLink" :
"@iot.nextLink";
430 while ( continueFetchingCallback() )
439 const QUrl url = parseUrl( nextPage );
441 QNetworkRequest request( url );
466 const auto rootContent = json::parse( content.
content().toStdString() );
467 if ( !rootContent.contains(
"value" ) )
470 mError = QObject::tr(
"No 'value' in response" );
477 const auto &values = rootContent[
"value"];
478 if ( values.empty() )
482 onNoMoreFeaturesCallback();
489 for (
const auto &featureData : values )
491 auto getString = [](
const basic_json<> &json,
const char *tag ) -> QVariant {
492 if ( !json.contains( tag ) )
495 std::function< QString(
const basic_json<> &obj,
bool &ok ) > objToString;
496 objToString = [&objToString](
const basic_json<> &obj,
bool &ok ) -> QString {
498 if ( obj.is_number_integer() )
500 return QString::number( obj.get<
int>() );
502 else if ( obj.is_number_unsigned() )
504 return QString::number( obj.get<
unsigned>() );
506 else if ( obj.is_boolean() )
508 return QString::number( obj.get<
bool>() );
510 else if ( obj.is_number_float() )
512 return QString::number( obj.get<
double>() );
514 else if ( obj.is_array() )
517 results.reserve(
static_cast< qsizetype
>( obj.size() ) );
518 for (
const auto &item : obj )
521 const QString itemString = objToString( item, itemOk );
523 results.push_back( itemString );
525 return results.join(
',' );
527 else if ( obj.is_string() )
529 return QString::fromStdString( obj.get<std::string >() );
536 const auto &jObj = json[tag];
538 const QString r = objToString( jObj, ok );
544 auto getDateTime = [](
const basic_json<> &json,
const char *tag ) -> QVariant {
545 if ( !json.contains( tag ) )
548 const auto &jObj = json[tag];
549 if ( jObj.is_string() )
551 const QString dateTimeString = QString::fromStdString( json[tag].get<std::string >() );
552 return QDateTime::fromString( dateTimeString, Qt::ISODateWithMs );
558 auto getVariantMap = [](
const basic_json<> &json,
const char *tag ) -> QVariant {
559 if ( !json.contains( tag ) )
565 auto getVariantList = [](
const basic_json<> &json,
const char *tag ) -> QVariant {
566 if ( !json.contains( tag ) )
572 auto getStringList = [](
const basic_json<> &json,
const char *tag ) -> QVariant {
573 if ( !json.contains( tag ) )
576 const auto &jObj = json[tag];
577 if ( jObj.is_string() )
579 return QStringList { QString::fromStdString( json[tag].get<std::string >() ) };
581 else if ( jObj.is_array() )
584 for (
const auto &element : jObj )
586 if ( element.is_string() )
587 res.append( QString::fromStdString( element.get<std::string >() ) );
595 auto getDateTimeRange = [](
const basic_json<> &json,
const char *tag ) -> std::pair< QVariant, QVariant > {
596 if ( !json.contains( tag ) )
597 return { QVariant(), QVariant() };
599 const auto &jObj = json[tag];
600 if ( jObj.is_string() )
602 const QString rangeString = QString::fromStdString( json[tag].get<std::string >() );
603 const QStringList rangeParts = rangeString.split(
'/' );
604 if ( rangeParts.size() == 2 )
606 return { QDateTime::fromString( rangeParts.at( 0 ), Qt::ISODateWithMs ), QDateTime::fromString( rangeParts.at( 1 ), Qt::ISODateWithMs ) };
610 const QDateTime instant = QDateTime::fromString( rangeString, Qt::ISODateWithMs );
611 if ( instant.isValid() )
612 return { instant, instant };
616 return { QVariant(), QVariant() };
619 const QString iotId = getString( featureData, idKey.data() ).toString();
620 if ( expansions.isEmpty() )
622 auto existingFeatureIdIt = mIotIdToFeatureId.constFind( iotId );
623 if ( existingFeatureIdIt != mIotIdToFeatureId.constEnd() )
626 fetchedFeatureCallback( *mCachedFeatures.find( *existingFeatureIdIt ) );
636 if ( featureData.contains( mGeometryField.toLocal8Bit().constData() ) )
638 const auto &geometryPart = featureData[mGeometryField.toLocal8Bit().constData()];
639 if ( geometryPart.contains(
"geometry" ) )
646 auto extendAttributes = [&getString,
654 const QString iotId = getString( entityData, idKey.data() ).toString();
655 const QString selfLink = getString( entityData, selfLinkKey.data() ).toString();
657 const QVariant properties = getVariantMap( entityData,
"properties" );
660 switch ( entityType )
666 attributes << iotId << selfLink << getString( entityData,
"name" ) << getString( entityData,
"description" ) << properties;
670 attributes << iotId << selfLink << getString( entityData,
"name" ) << getString( entityData,
"description" ) << properties;
674 attributes << iotId << selfLink << 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;
697 attributes << iotId << selfLink << getString( entityData,
"name" ) << getString( entityData,
"description" ) << getString( entityData,
"metadata" ) << properties;
701 attributes << iotId << selfLink << getString( entityData,
"name" ) << getString( entityData,
"definition" ) << getString( entityData,
"description" ) << properties;
706 std::pair< QVariant, QVariant > phenomenonTime = getDateTimeRange( entityData,
"phenomenonTime" );
707 std::pair< QVariant, QVariant > validTime = getDateTimeRange( entityData,
"validTime" );
711 << phenomenonTime.first
712 << phenomenonTime.second
713 << getString( entityData,
"result" )
714 << getDateTime( entityData,
"resultTime" )
715 << getStringList( entityData,
"resultQuality" )
718 << getVariantMap( entityData,
"parameters" );
723 attributes << iotId << selfLink << getString( entityData,
"name" ) << getString( entityData,
"description" ) << properties;
727 attributes << iotId << selfLink << getString( entityData,
"name" ) << getString( entityData,
"description" ) << properties;
731 attributes << iotId << selfLink << getString( entityData,
"name" ) << getString( entityData,
"description" ) << properties;
736 std::pair< QVariant, QVariant > phenomenonTime = getDateTimeRange( entityData,
"phenomenonTime" );
737 std::pair< QVariant, QVariant > resultTime = getDateTimeRange( entityData,
"resultTime" );
741 << getString( entityData,
"name" )
742 << getString( entityData,
"description" )
743 << getVariantList( entityData,
"unitOfMeasurements" )
744 << getString( entityData,
"observationType" )
745 << getStringList( entityData,
"multiObservationDataTypes" )
747 << phenomenonTime.first
748 << phenomenonTime.second
750 << resultTime.second;
756 std::pair< QVariant, QVariant > time = getDateTimeRange( entityData,
"time" );
757 attributes << iotId << selfLink << getString( entityData,
"name" ) << getString( entityData,
"description" ) << properties << time.first << time.second;
763 attributes << iotId << selfLink << getString( entityData,
"name" ) << getString( entityData,
"definition" ) << getString( entityData,
"description" ) << properties;
769 std::pair< QVariant, QVariant > time = getDateTimeRange( entityData,
"time" );
773 << getString( entityData,
"name" )
774 << getString( entityData,
"definition" )
775 << getString( entityData,
"description" )
784 attributes << iotId << selfLink << getString( entityData,
"name" ) << getString( entityData,
"definition" ) << getString( entityData,
"description" ) << properties;
793 << getString( entityData,
"name" )
794 << getString( entityData,
"definition" )
795 << getString( entityData,
"description" )
797 << getString( entityData,
"samplerType" );
803 std::pair< QVariant, QVariant > time = getDateTimeRange( entityData,
"time" );
807 << getString( entityData,
"name" )
808 << getString( entityData,
"definition" )
809 << getString( entityData,
"description" )
818 attributes << iotId << selfLink << getString( entityData,
"name" ) << getString( entityData,
"definition" ) << getString( entityData,
"description" ) << properties;
827 << getString( entityData,
"name" )
828 << getString( entityData,
"definition" )
829 << getString( entityData,
"inverseName" )
830 << getString( entityData,
"inverseDefinition" )
831 << getString( entityData,
"description" )
841 attributes << iotId << selfLink << getString( entityData,
"externalTarget" );
849 attributes.reserve( fields.
size() );
850 extendAttributes( mEntityType, featureData, attributes );
852 auto processFeature = [
this, &fetchedFeatureCallback](
QgsFeature &feature,
const QString &rawFeatureId ) {
853 feature.
setId( mNextFeatureId++ );
855 mCachedFeatures.insert( feature.
id(), feature );
856 mIotIdToFeatureId.insert( rawFeatureId, feature.
id() );
857 mSpatialIndex.addFeature( feature );
860 fetchedFeatureCallback( feature );
863 const QString baseFeatureId = getString( featureData, idKey.data() ).toString();
864 if ( !expansions.empty() )
866 mRetrievedBaseFeatureCount++;
868 std::function< void(
const nlohmann::json &,
Qgis::SensorThingsEntity,
const QList<QgsSensorThingsExpansionDefinition > &,
const QString &,
const QgsAttributes & ) > traverseExpansion;
874 &fetchedFeatureCallback,
877 &processFeature](
const nlohmann::json ¤tLevelData,
Qgis::SensorThingsEntity parentEntityType,
const QList<QgsSensorThingsExpansionDefinition > &expansionTargets,
const QString &lowerLevelId,
const QgsAttributes &lowerLevelAttributes ) {
879 const QList< QgsSensorThingsExpansionDefinition > remainingExpansionTargets = expansionTargets.mid( 1 );
883 QString currentExpansionPropertyString;
884 switch ( cardinality )
897 if ( currentLevelData.contains( currentExpansionPropertyString.toLocal8Bit().constData() ) )
899 auto parseExpandedEntity = [lowerLevelAttributes,
904 &remainingExpansionTargets,
905 &fetchedFeatureCallback,
908 ¤tExpansionTarget,
910 this](
const json &expandedEntityElement ) {
912 const QString expandedEntityIotId = getString( expandedEntityElement, idKey.data() ).toString();
913 const QString expandedFeatureId = lowerLevelId +
'_' + expandedEntityIotId;
915 if ( remainingExpansionTargets.empty() )
917 auto existingFeatureIdIt = mIotIdToFeatureId.constFind( expandedFeatureId );
918 if ( existingFeatureIdIt != mIotIdToFeatureId.constEnd() )
921 fetchedFeatureCallback( *mCachedFeatures.find( *existingFeatureIdIt ) );
926 extendAttributes( currentExpansionTarget.childEntity(), expandedEntityElement, expandedAttributes );
927 if ( !remainingExpansionTargets.empty() )
930 traverseExpansion( expandedEntityElement, currentExpansionTarget.childEntity(), remainingExpansionTargets, expandedFeatureId, expandedAttributes );
934 feature.setAttributes( expandedAttributes );
935 processFeature( feature, expandedFeatureId );
938 const auto &expandedEntity = currentLevelData[currentExpansionPropertyString.toLocal8Bit().constData()];
939 if ( expandedEntity.is_array() )
941 for (
const auto &expandedEntityElement : expandedEntity )
943 parseExpandedEntity( expandedEntityElement );
949 else if ( expandedEntity.is_object() )
951 parseExpandedEntity( expandedEntity );
962 traverseExpansion( featureData, mEntityType, expansions, baseFeatureId, attributes );
964 if ( mFeatureLimit > 0 && mFeatureLimit <= mRetrievedBaseFeatureCount )
969 feature.setAttributes( attributes );
970 processFeature( feature, baseFeatureId );
971 mRetrievedBaseFeatureCount++;
972 if ( mFeatureLimit > 0 && mFeatureLimit <= mRetrievedBaseFeatureCount )
979 if ( rootContent.contains( nextLinkKey.data() ) && ( mFeatureLimit == 0 || mFeatureLimit > mCachedFeatures.size() ) )
981 nextPage = QString::fromStdString( rootContent[nextLinkKey.data()].get<std::string>() );
985 onNoMoreFeaturesCallback();
989 if ( !continueFetchingCallback() )
995 catch (
const json::parse_error &ex )
998 mError = QObject::tr(
"Error parsing response: %1" ).arg( ex.what() );
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 ...
@ Sampling
The Sampling is the act of taking one or more Samples. The Sampling takes Samples from a SampledFeatu...
@ DatastreamRelation
A DatastreamRelation Entity relates a source Datastream to a target Datastream, or to an external res...
@ Feature
A Feature is an abstraction of real-world phenomena. It acts as an independent entity that can repres...
@ FeatureRelation
A FeatureRelation Entity relates a source Feature to a target Feature, or to an external resource,...
@ ObservedProperty
An ObservedProperty specifies the phenomenon of an Observation.
@ Invalid
An invalid/unknown entity.
@ Sampler
The Sampler describes the machine, device, human or other entity that executed the sampling procedure...
@ PreparationStep
When applying a PreparationProcdedure to a Sample, the process is recorded in individual PreparationS...
@ RelationRole
The RelationRole Entity holds a name and definition for both directions of the relation....
@ SamplingProcedure
The SamplingProcedure describes the method, or procedure, that the Sampler uses to create Samples....
@ ObservationRelation
A ObservationRelation Entity relates a source Observation to a target Observation,...
@ 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 ...
@ PreparationProcedure
After a sample is taken, a preparation procedure can be applied to it. The difference with the sampli...
@ Observation
An Observation is the act of measuring or otherwise determining the value of a property.
@ ObservingProcedure
An Observing Procedure. Implemented in the "Sensing Extension (Observations & Measurements)".
@ Location
A Location entity locates the Thing or the Things it associated with. A Thing’s Location entity is de...
@ ThingRelation
A ThingRelation Entity relates a source Thing to a target Thing, or to an external resource,...
@ FeatureType
A FeatureType provides the classification and schema definition for a Feature, describing the common ...
@ Thing
A Thing is an object of the physical world (physical things) or the information world (virtual things...
@ Deployment
A Deployment is the association of a Sensor to a Thing that hosts this Sensor, and to the Datastreams...
@ 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.
Encapsulates parameters under which a geometry operation is performed.
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(), QgsFeedback *feedback=nullptr)
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.
Q_INVOKABLE QString toString(int precision=16) const
Returns a string representation of form xmin,ymin : xmax,ymax Coordinates will be rounded to the spec...
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)