52#include <QRegularExpression>
56#include "moc_qgsarcgisrestutils.cpp"
58using namespace Qt::StringLiterals;
62 if ( esriFieldType ==
"esriFieldTypeInteger"_L1 )
63 return QMetaType::Type::LongLong;
64 if ( esriFieldType ==
"esriFieldTypeSmallInteger"_L1 )
65 return QMetaType::Type::Int;
66 if ( esriFieldType ==
"esriFieldTypeDouble"_L1 )
67 return QMetaType::Type::Double;
68 if ( esriFieldType ==
"esriFieldTypeSingle"_L1 )
69 return QMetaType::Type::Double;
70 if ( esriFieldType ==
"esriFieldTypeString"_L1 )
71 return QMetaType::Type::QString;
72 if ( esriFieldType ==
"esriFieldTypeDate"_L1 )
73 return QMetaType::Type::QDateTime;
74 if ( esriFieldType ==
"esriFieldTypeGeometry"_L1 )
75 return QMetaType::Type::UnknownType;
76 if ( esriFieldType ==
"esriFieldTypeOID"_L1 )
77 return QMetaType::Type::LongLong;
78 if ( esriFieldType ==
"esriFieldTypeBlob"_L1 )
79 return QMetaType::Type::QByteArray;
80 if ( esriFieldType ==
"esriFieldTypeGlobalID"_L1 )
81 return QMetaType::Type::QString;
82 if ( esriFieldType ==
"esriFieldTypeRaster"_L1 )
83 return QMetaType::Type::QByteArray;
84 if ( esriFieldType ==
"esriFieldTypeGUID"_L1 )
85 return QMetaType::Type::QString;
86 if ( esriFieldType ==
"esriFieldTypeXML"_L1 )
87 return QMetaType::Type::QString;
88 return QMetaType::Type::UnknownType;
94 if ( esriGeometryType ==
"esriGeometryNull"_L1 )
96 else if ( esriGeometryType ==
"esriGeometryPoint"_L1 )
98 else if ( esriGeometryType ==
"esriGeometryMultipoint"_L1 )
100 else if ( esriGeometryType ==
"esriGeometryPolyline"_L1 )
102 else if ( esriGeometryType ==
"esriGeometryPolygon"_L1 )
104 else if ( esriGeometryType ==
"esriGeometryEnvelope"_L1 )
124std::unique_ptr< QgsPoint > QgsArcGisRestUtils::convertPoint(
const QVariantList &coordList,
Qgis::WkbType pointType )
126 const int nCoords =
static_cast< int >( coordList.size() );
129 bool xok =
false, yok =
false;
130 const double x = coordList[0].toDouble( &xok );
131 const double y = coordList[1].toDouble( &yok );
135 const double z = hasZ && nCoords >= 3 ? coordList[2].toDouble() : std::numeric_limits< double >::quiet_NaN();
138 const double m =
QgsWkbTypes::hasM( pointType ) && ( ( hasZ && nCoords >= 4 ) || ( !hasZ && nCoords >= 3 ) ) ? coordList[hasZ ? 3 : 2].toDouble() : std::numeric_limits< double >::quiet_NaN();
139 return std::make_unique< QgsPoint >( pointType, x, y, z, m );
142std::unique_ptr< QgsCircularString > QgsArcGisRestUtils::convertCircularString(
const QVariantMap &curveData,
Qgis::WkbType pointType,
const QgsPoint &startPoint )
144 const QVariantList coordsList = curveData[u
"c"_s].toList();
145 if ( coordsList.isEmpty() )
147 const int coordsListSize =
static_cast< int >( coordsList.size() );
149 QVector<QgsPoint> points;
150 points.reserve( coordsListSize + 1 );
151 points.append( startPoint );
153 for (
int i = 0; i < coordsListSize - 1; )
157 std::unique_ptr< QgsPoint > endPoint( convertPoint( coordsList.at( i ).toList(), pointType ) );
161 std::unique_ptr< QgsPoint > interiorPoint( convertPoint( coordsList.at( i ).toList(), pointType ) );
162 if ( !interiorPoint )
165 points << *interiorPoint;
168 auto curve = std::make_unique< QgsCircularString>();
169 curve->setPoints( points );
173std::unique_ptr< QgsCurve > QgsArcGisRestUtils::convertCompoundCurve(
const QVariantList &curvesList,
Qgis::WkbType pointType )
176 auto compoundCurve = std::make_unique< QgsCompoundCurve >();
178 QVector< double > lineX;
179 QVector< double > lineY;
180 QVector< double > lineZ;
181 QVector< double > lineM;
182 const int maxCurveListSize =
static_cast< int >( curvesList.size() );
183 lineX.resize( maxCurveListSize );
184 lineY.resize( maxCurveListSize );
188 lineZ.resize( maxCurveListSize );
191 lineM.resize( maxCurveListSize );
193 double *outLineX = lineX.data();
194 double *outLineY = lineY.data();
195 double *outLineZ = lineZ.data();
196 double *outLineM = lineM.data();
197 int actualLineSize = 0;
202 int curveListIndex = 0;
203 for (
const QVariant &curveData : curvesList )
205 if ( curveData.userType() == QMetaType::Type::QVariantList )
207 const QVariantList coordList = curveData.toList();
208 const int nCoords =
static_cast< int >( coordList.size() );
212 const double x = coordList[0].toDouble( &xok );
213 const double y = coordList[1].toDouble( &yok );
222 *outLineZ++ = nCoords >= 3 ? coordList[2].toDouble() : std::numeric_limits< double >::quiet_NaN();
228 *outLineM++ = ( ( hasZ && nCoords >= 4 ) || ( !hasZ && nCoords >= 3 ) ) ? coordList[hasZ ? 3 : 2].toDouble() : std::numeric_limits< double >::quiet_NaN();
231 else if ( curveData.userType() == QMetaType::Type::QVariantMap )
234 QgsPoint lastLineStringPoint;
235 if ( actualLineSize > 0 )
238 = QgsPoint( lineX.at( actualLineSize - 1 ), lineY.at( actualLineSize - 1 ), hasZ ? lineZ.at( actualLineSize - 1 ) : std::numeric_limits< double >::quiet_NaN(), hasM ? lineM.at( actualLineSize - 1 ) : std::numeric_limits< double >::quiet_NaN() );
240 std::unique_ptr< QgsCircularString > circularString( convertCircularString( curveData.toMap(), pointType, lastLineStringPoint ) );
241 if ( !circularString )
246 if ( actualLineSize > 0 )
248 lineX.resize( actualLineSize );
249 lineY.resize( actualLineSize );
251 lineZ.resize( actualLineSize );
253 lineM.resize( actualLineSize );
255 compoundCurve->addCurve(
new QgsLineString( lineX, lineY, lineZ, lineM ) );
256 lineX.resize( maxCurveListSize - curveListIndex );
257 lineY.resize( maxCurveListSize - curveListIndex );
259 lineZ.resize( maxCurveListSize - curveListIndex );
261 lineM.resize( maxCurveListSize - curveListIndex );
262 outLineX = lineX.data();
263 outLineY = lineY.data();
264 outLineZ = lineZ.data();
265 outLineM = lineM.data();
269 if ( compoundCurve->curveAt( compoundCurve->nCurves() - 1 )->nCoordinates() < 2 )
270 compoundCurve->removeCurve( compoundCurve->nCurves() - 1 );
272 const QgsPoint endPointCircularString = circularString->endPoint();
273 compoundCurve->addCurve( circularString.release() );
277 *outLineX++ = endPointCircularString.
x();
278 *outLineY++ = endPointCircularString.
y();
280 *outLineZ++ = endPointCircularString.
z();
282 *outLineM++ = endPointCircularString.
m();
287 if ( actualLineSize == 1 && compoundCurve->nCurves() > 0 )
289 const QgsCurve *finalCurve = compoundCurve->curveAt( compoundCurve->nCurves() - 1 );
290 const QgsPoint finalCurveEndPoint = finalCurve->
endPoint();
293 && ( !hasZ ||
qgsDoubleNear( finalCurveEndPoint.
z(), lineZ.at( 0 ) ) )
294 && ( !hasM ||
qgsDoubleNear( finalCurveEndPoint.
m(), lineM.at( 0 ) ) ) )
300 if ( actualLineSize > 0 )
302 lineX.resize( actualLineSize );
303 lineY.resize( actualLineSize );
305 lineZ.resize( actualLineSize );
307 lineM.resize( actualLineSize );
308 compoundCurve->addCurve(
new QgsLineString( lineX, lineY, lineZ, lineM ) );
311 return compoundCurve;
314std::unique_ptr<QgsLineString> QgsArcGisRestUtils::convertLineString(
const QVariantList &curvesList,
Qgis::WkbType pointType )
316 auto linestring = std::make_unique< QgsLineString >();
318 QVector< double > lineX;
319 QVector< double > lineY;
320 QVector< double > lineZ;
321 QVector< double > lineM;
322 const int maxCurveListSize =
static_cast< int >( curvesList.size() );
323 lineX.resize( maxCurveListSize );
324 lineY.resize( maxCurveListSize );
328 lineZ.resize( maxCurveListSize );
331 lineM.resize( maxCurveListSize );
333 double *outLineX = lineX.data();
334 double *outLineY = lineY.data();
335 double *outLineZ = lineZ.data();
336 double *outLineM = lineM.data();
341 int actualLineSize = 0;
342 for (
const QVariant &curveData : curvesList )
344 if ( curveData.userType() == QMetaType::Type::QVariantList )
346 const QVariantList coordList = curveData.toList();
347 const int nCoords =
static_cast< int >( coordList.size() );
351 const double x = coordList[0].toDouble( &xok );
352 const double y = coordList[1].toDouble( &yok );
361 *outLineZ++ = nCoords >= 3 ? coordList[2].toDouble() : std::numeric_limits< double >::quiet_NaN();
367 *outLineM++ = ( ( hasZ && nCoords >= 4 ) || ( !hasZ && nCoords >= 3 ) ) ? coordList[hasZ ? 3 : 2].toDouble() : std::numeric_limits< double >::quiet_NaN();
372 QgsDebugError( u
"Found unexpected value when parsing ESRI json line string. Expected list, got %1"_s.arg( curveData.metaType().name() ) );
377 if ( actualLineSize == 0 )
380 lineX.resize( actualLineSize );
381 lineY.resize( actualLineSize );
383 lineZ.resize( actualLineSize );
385 lineM.resize( actualLineSize );
386 return std::make_unique< QgsLineString>( lineX, lineY, lineZ, lineM );
389std::unique_ptr< QgsPoint > QgsArcGisRestUtils::convertGeometryPoint(
const QVariantMap &geometryData,
Qgis::WkbType pointType )
392 bool xok =
false, yok =
false;
393 double x = geometryData[u
"x"_s].toDouble( &xok );
394 double y = geometryData[u
"y"_s].toDouble( &yok );
397 double z = geometryData[u
"z"_s].toDouble();
398 double m = geometryData[u
"m"_s].toDouble();
399 return std::make_unique< QgsPoint >( pointType, x, y, z, m );
402std::unique_ptr< QgsMultiPoint > QgsArcGisRestUtils::convertMultiPoint(
const QVariantMap &geometryData,
Qgis::WkbType pointType )
405 const QVariantList coordsList = geometryData[u
"points"_s].toList();
407 auto multiPoint = std::make_unique< QgsMultiPoint >();
408 multiPoint->reserve(
static_cast< int >( coordsList.size() ) );
409 for (
const QVariant &coordData : coordsList )
411 const QVariantList coordList = coordData.toList();
412 std::unique_ptr< QgsPoint > p = convertPoint( coordList, pointType );
417 multiPoint->addGeometry( p.release() );
422 std::unique_ptr< QgsPoint > p = convertGeometryPoint( geometryData, pointType );
424 multiPoint->addGeometry( p.release() );
426 if ( multiPoint->numGeometries() == 0 )
434std::unique_ptr< QgsMultiCurve > QgsArcGisRestUtils::convertGeometryPolyline(
const QVariantMap &geometryData,
Qgis::WkbType pointType,
bool allowCurves )
437 QVariantList pathsList;
438 if ( geometryData[u
"paths"_s].isValid() )
439 pathsList = geometryData[u
"paths"_s].toList();
440 else if ( geometryData[u
"curvePaths"_s].isValid() )
441 pathsList = geometryData[u
"curvePaths"_s].toList();
442 if ( pathsList.isEmpty() )
444 std::unique_ptr< QgsMultiCurve > multiCurve = allowCurves ? std::make_unique< QgsMultiCurve >() : std::make_unique< QgsMultiLineString >();
445 multiCurve->reserve(
static_cast< int >( pathsList.size() ) );
446 for (
const QVariant &pathData : std::as_const( pathsList ) )
448 std::unique_ptr< QgsCurve > curve = allowCurves ? convertCompoundCurve( pathData.toList(), pointType ) : convertLineString( pathData.toList(), pointType );
453 multiCurve->addGeometry( curve.release() );
458std::unique_ptr< QgsMultiSurface > QgsArcGisRestUtils::convertGeometryPolygon(
const QVariantMap &geometryData,
Qgis::WkbType pointType,
bool allowCurves )
461 QVariantList ringsList;
462 if ( geometryData[u
"rings"_s].isValid() )
463 ringsList = geometryData[u
"rings"_s].toList();
464 else if ( geometryData[u
"ringPaths"_s].isValid() )
465 ringsList = geometryData[u
"ringPaths"_s].toList();
466 if ( ringsList.isEmpty() )
469 QList< QgsCurve * > curves;
470 for (
int i = 0, n =
static_cast< int >( ringsList.size() ); i < n; ++i )
472 std::unique_ptr< QgsCurve > curve = allowCurves ? convertCompoundCurve( ringsList[i].toList(), pointType ) : convertLineString( ringsList[i].toList(), pointType );
477 curves.append( curve.release() );
479 if ( curves.count() == 0 )
482 std::unique_ptr< QgsMultiSurface > result = allowCurves ? std::make_unique< QgsMultiSurface >() : std::make_unique< QgsMultiPolygon >();
483 if ( curves.count() == 1 )
486 std::unique_ptr< QgsCurvePolygon > newPolygon = allowCurves ? std::make_unique< QgsCurvePolygon >() : std::make_unique< QgsPolygon >();
487 newPolygon->setExteriorRing( curves.takeAt( 0 ) );
488 result->addGeometry( newPolygon.release() );
492 std::sort( curves.begin(), curves.end(), [](
const QgsCurve *a,
const QgsCurve *b ) ->
bool {
495 a->sumUpArea( a_area );
496 b->sumUpArea( b_area );
497 return std::abs( a_area ) > std::abs( b_area );
499 result->reserve(
static_cast< int >( curves.size() ) );
500 while ( !curves.isEmpty() )
502 QgsCurve *exterior = curves.takeFirst();
503 QgsCurvePolygon *newPolygon = allowCurves ? new QgsCurvePolygon() : new QgsPolygon();
504 newPolygon->setExteriorRing( exterior );
505 std::unique_ptr<QgsGeometryEngine> engine( QgsGeometry::createGeometryEngine( newPolygon ) );
506 engine->prepareGeometry();
508 QMutableListIterator< QgsCurve * > it( curves );
509 while ( it.hasNext() )
511 QgsCurve *curve = it.next();
512 QgsRectangle boundingBox = newPolygon->boundingBox();
513 if ( boundingBox.intersects( curve->boundingBox() ) )
515 QgsPoint point = curve->startPoint();
516 if ( engine->contains( &point ) )
518 newPolygon->addInteriorRing( curve );
520 engine.reset( QgsGeometry::createGeometryEngine( newPolygon ) );
521 engine->prepareGeometry();
525 result->addGeometry( newPolygon );
527 if ( result->numGeometries() == 0 )
533std::unique_ptr< QgsPolygon > QgsArcGisRestUtils::convertEnvelope(
const QVariantMap &geometryData )
536 bool xminOk =
false, yminOk =
false, xmaxOk =
false, ymaxOk =
false;
537 double xmin = geometryData[u
"xmin"_s].toDouble( &xminOk );
538 double ymin = geometryData[u
"ymin"_s].toDouble( &yminOk );
539 double xmax = geometryData[u
"xmax"_s].toDouble( &xmaxOk );
540 double ymax = geometryData[u
"ymax"_s].toDouble( &ymaxOk );
541 if ( !xminOk || !yminOk || !xmaxOk || !ymaxOk )
543 auto ext = std::make_unique< QgsLineString>();
544 ext->addVertex( QgsPoint( xmin, ymin ) );
545 ext->addVertex( QgsPoint( xmax, ymin ) );
546 ext->addVertex( QgsPoint( xmax, ymax ) );
547 ext->addVertex( QgsPoint( xmin, ymax ) );
548 ext->addVertex( QgsPoint( xmin, ymin ) );
549 auto poly = std::make_unique< QgsPolygon >();
550 poly->setExteriorRing( ext.release() );
555 const QVariantMap &geometryData,
const QString &esriGeometryType,
bool readM,
bool readZ,
bool allowCurves,
QgsCoordinateReferenceSystem *crs
565 if ( esriGeometryType ==
"esriGeometryNull"_L1 )
567 else if ( esriGeometryType ==
"esriGeometryPoint"_L1 )
568 return convertGeometryPoint( geometryData, pointType );
569 else if ( esriGeometryType ==
"esriGeometryMultipoint"_L1 )
570 return convertMultiPoint( geometryData, pointType );
571 else if ( esriGeometryType ==
"esriGeometryPolyline"_L1 )
572 return convertGeometryPolyline( geometryData, pointType, allowCurves );
573 else if ( esriGeometryType ==
"esriGeometryPolygon"_L1 )
574 return convertGeometryPolygon( geometryData, pointType, allowCurves );
575 else if ( esriGeometryType ==
"esriGeometryEnvelope"_L1 )
576 return convertEnvelope( geometryData );
599 QString spatialReference = spatialReferenceMap[u
"latestWkid"_s].toString();
600 if ( spatialReference.isEmpty() )
601 spatialReference = spatialReferenceMap[u
"wkid"_s].toString();
604 if ( !spatialReference.isEmpty() )
613 else if ( !spatialReferenceMap[u
"wkt"_s].toString().isEmpty() )
616 crs.
createFromWkt( spatialReferenceMap[u
"wkt"_s].toString() );
643 if ( labelingData.empty() )
650 for (
const QVariant &lbl : labelingData )
652 const QVariantMap labeling = lbl.toMap();
657 const QString placement = labeling.value( u
"labelPlacement"_s ).toString();
658 if ( placement ==
"esriServerPointLabelPlacementAboveCenter"_L1 )
663 else if ( placement ==
"esriServerPointLabelPlacementBelowCenter"_L1 )
668 else if ( placement ==
"esriServerPointLabelPlacementCenterCenter"_L1 )
673 else if ( placement ==
"esriServerPointLabelPlacementAboveLeft"_L1 )
678 else if ( placement ==
"esriServerPointLabelPlacementBelowLeft"_L1 )
683 else if ( placement ==
"esriServerPointLabelPlacementCenterLeft"_L1 )
688 else if ( placement ==
"esriServerPointLabelPlacementAboveRight"_L1 )
693 else if ( placement ==
"esriServerPointLabelPlacementBelowRight"_L1 )
698 else if ( placement ==
"esriServerPointLabelPlacementCenterRight"_L1 )
703 else if ( placement ==
"esriServerLinePlacementAboveAfter"_L1 || placement ==
"esriServerLinePlacementAboveStart"_L1 || placement ==
"esriServerLinePlacementAboveAlong"_L1 )
708 else if ( placement ==
"esriServerLinePlacementBelowAfter"_L1 || placement ==
"esriServerLinePlacementBelowStart"_L1 || placement ==
"esriServerLinePlacementBelowAlong"_L1 )
713 else if ( placement ==
"esriServerLinePlacementCenterAfter"_L1 || placement ==
"esriServerLinePlacementCenterStart"_L1 || placement ==
"esriServerLinePlacementCenterAlong"_L1 )
718 else if ( placement ==
"esriServerPolygonPlacementAlwaysHorizontal"_L1 )
723 const bool repeatLabel = labeling.value( u
"repeatLabel"_s ).toBool();
726 const double repeatLabelDistance = labeling.value( u
"repeatLabelDistance"_s ).toDouble();
727 if ( repeatLabelDistance > 0.0 )
734 const double minScale = labeling.value( u
"minScale"_s ).toDouble();
735 const double maxScale = labeling.value( u
"maxScale"_s ).toDouble();
737 QVariantMap symbol = labeling.value( u
"symbol"_s ).toMap();
739 const double haloSize = symbol.value( u
"haloSize"_s ).toDouble();
750 const QString fontFamily = symbol.value( u
"font"_s ).toMap().value( u
"family"_s ).toString();
751 const QString fontStyle = symbol.value( u
"font"_s ).toMap().value( u
"style"_s ).toString();
752 const QString fontWeight = symbol.value( u
"font"_s ).toMap().value( u
"weight"_s ).toString();
753 const int fontSize = symbol.value( u
"font"_s ).toMap().value( u
"size"_s ).toInt();
754 QFont font( fontFamily, fontSize );
755 font.setStyleName( fontStyle );
756 font.setWeight( fontWeight ==
"bold"_L1 ? QFont::Bold : QFont::Normal );
764 QString where = labeling.value( u
"where"_s ).toString();
778 return std::make_unique< QgsRuleBasedLabeling >( root );
786 const QVariantList visualVariablesData = rendererData.value( u
"visualVariables"_s ).toList();
787 for (
const QVariant &visualVariable : visualVariablesData )
789 const QVariantMap visualVariableData = visualVariable.toMap();
790 const QString variableType = visualVariableData.value( u
"type"_s ).toString();
792 if ( variableType ==
"rotationInfo"_L1 )
794 const QString field = visualVariableData.value( u
"field"_s ).toString();
795 if ( field.isEmpty() )
798 if ( !visualVariableData.value( u
"valueExpression"_s ).toString().isEmpty() )
799 context.
pushWarning( QObject::tr(
"ESRI rotationInfo valueExpression is not yet supported" ) );
803 const QString rotationType = visualVariableData.value( u
"rotationType"_s ).toString();
805 QgsProperty angleProperty;
806 if ( rotationType ==
"arithmetic"_L1 )
813 else if ( rotationType ==
"geographic"_L1 )
820 context.
pushWarning( QObject::tr(
"ESRI rotationInfo rotationType '%1' is not supported" ).arg( rotationType ) );
832 context.
pushWarning( QObject::tr(
"ESRI visualVariable type '%1' is not currently supported" ).arg( variableType ) );
839 const QString type = rendererData.value( u
"type"_s ).toString();
841 if ( type ==
"simple"_L1 )
843 const QVariantMap symbolProps = rendererData.value( u
"symbol"_s ).toMap();
844 std::unique_ptr< QgsSymbol > symbol(
convertSymbol( symbolProps, context ) );
848 applyVisualVariables( rendererData, symbol.get(), context );
849 return std::make_unique< QgsSingleSymbolRenderer >( symbol.release() );
854 else if ( type ==
"uniqueValue"_L1 )
856 const QString field1 = rendererData.value( u
"field1"_s ).toString();
857 const QString field2 = rendererData.value( u
"field2"_s ).toString();
858 const QString field3 = rendererData.value( u
"field3"_s ).toString();
860 if ( !field2.isEmpty() || !field3.isEmpty() )
862 const QString delimiter = rendererData.value( u
"fieldDelimiter"_s ).toString();
863 if ( !field3.isEmpty() )
865 attribute = u
"concat(\"%1\",'%2',\"%3\",'%4',\"%5\")"_s.arg( field1, delimiter, field2, delimiter, field3 );
869 attribute = u
"concat(\"%1\",'%2',\"%3\")"_s.arg( field1, delimiter, field2 );
877 const QVariantList categories = rendererData.value( u
"uniqueValueInfos"_s ).toList();
879 for (
const QVariant &category : categories )
881 const QVariantMap categoryData = category.toMap();
882 const QString valueString = categoryData.value( u
"value"_s ).toString();
884 const QVariant value = valueString ==
"<Null>"_L1 ? QVariant() : QVariant( valueString );
885 const QString label = categoryData.value( u
"label"_s ).toString();
890 applyVisualVariables( rendererData, symbol.get(), context );
896 std::unique_ptr< QgsSymbol > defaultSymbol(
convertSymbol( rendererData.value( u
"defaultSymbol"_s ).toMap(), context ) );
900 applyVisualVariables( rendererData, defaultSymbol.get(), context );
901 categoryList.append(
QgsRendererCategory( QVariant(), defaultSymbol.release(), rendererData.value( u
"defaultLabel"_s ).toString() ) );
904 if ( categoryList.empty() )
907 auto renderer = std::make_unique< QgsCategorizedSymbolRenderer >( attribute, categoryList );
910 else if ( type ==
"classBreaks"_L1 )
912 const QString attrName = rendererData.value( u
"field"_s ).toString();
914 const QVariantList classBreakInfos = rendererData.value( u
"classBreakInfos"_s ).toList();
915 const QVariantMap authoringInfo = rendererData.value( u
"authoringInfo"_s ).toMap();
916 QVariantMap symbolData;
918 QString esriMode = authoringInfo.value( u
"classificationMethod"_s ).toString();
919 if ( esriMode.isEmpty() )
921 esriMode = rendererData.value( u
"classificationMethod"_s ).toString();
924 if ( !classBreakInfos.isEmpty() )
926 symbolData = classBreakInfos.at( 0 ).toMap().value( u
"symbol"_s ).toMap();
932 const QVariantList visualVariablesData = rendererData.value( u
"visualVariables"_s ).toList();
934 for (
const QVariant &visualVariable : visualVariablesData )
936 const QVariantMap visualVariableData = visualVariable.toMap();
937 const QString variableType = visualVariableData.value( u
"type"_s ).toString();
938 if ( variableType ==
"sizeInfo"_L1 )
942 else if ( variableType ==
"colorInfo"_L1 )
944 const QVariantList stops = visualVariableData.value( u
"stops"_s ).toList();
945 if ( stops.size() < 2 )
950 const double minValue = stops.front().toMap().value( u
"value"_s ).toDouble( &ok );
953 const QColor minColor =
convertColor( stops.front().toMap().value( u
"color"_s ) );
955 const double maxValue = stops.back().toMap().value( u
"value"_s ).toDouble( &ok );
958 const QColor maxColor =
convertColor( stops.back().toMap().value( u
"color"_s ) );
961 for (
int i = 1; i < stops.size() - 1; ++i )
963 const QVariantMap stopData = stops.at( i ).toMap();
964 const double breakpoint = stopData.value( u
"value"_s ).toDouble();
965 const double scaledBreakpoint = ( breakpoint - minValue ) / ( maxValue - minValue );
966 const QColor fillColor =
convertColor( stopData.value( u
"color"_s ) );
968 gradientStops.append(
QgsGradientStop( scaledBreakpoint, fillColor ) );
971 auto colorRamp = std::make_unique< QgsGradientColorRamp >( minColor, maxColor,
false, gradientStops );
975 for (
int layer = 0; layer < symbol->symbolLayerCount(); ++layer )
980 return std::make_unique< QgsSingleSymbolRenderer >( symbol.release() );
982 else if ( variableType ==
"rotationInfo"_L1 )
989 context.
pushWarning( QObject::tr(
"ESRI visualVariable type '%1' is not currently supported" ).arg( variableType ) );
993 double lastValue = rendererData.value( u
"minValue"_s ).toDouble();
995 auto graduatedRenderer = std::make_unique< QgsGraduatedSymbolRenderer >( attrName );
997 graduatedRenderer->setSourceSymbol( symbol.release() );
999 if ( esriMode ==
"esriClassifyDefinedInterval"_L1 )
1002 graduatedRenderer->setClassificationMethod( method );
1004 else if ( esriMode ==
"esriClassifyEqualInterval"_L1 )
1007 graduatedRenderer->setClassificationMethod( method );
1009 else if ( esriMode ==
"esriClassifyGeometricalInterval"_L1 )
1012 graduatedRenderer->setClassificationMethod( method );
1014 else if ( esriMode ==
"esriClassifyManual"_L1 )
1017 graduatedRenderer->setClassificationMethod( method );
1019 else if ( esriMode ==
"esriClassifyNaturalBreaks"_L1 )
1022 graduatedRenderer->setClassificationMethod( method );
1024 else if ( esriMode ==
"esriClassifyQuantile"_L1 )
1027 graduatedRenderer->setClassificationMethod( method );
1029 else if ( esriMode ==
"esriClassifyStandardDeviation"_L1 )
1032 graduatedRenderer->setClassificationMethod( method );
1034 else if ( !esriMode.isEmpty() )
1036 context.
pushWarning( QObject::tr(
"ESRI classification mode '%1' is not currently supported" ).arg( esriMode ) );
1039 for (
const QVariant &classBreakInfo : classBreakInfos )
1041 const QVariantMap symbolData = classBreakInfo.toMap().value( u
"symbol"_s ).toMap();
1043 double classMaxValue = classBreakInfo.toMap().value( u
"classMaxValue"_s ).toDouble();
1044 const QString label = classBreakInfo.toMap().value( u
"label"_s ).toString();
1047 applyVisualVariables( rendererData, symbol.get(), context );
1056 lastValue = classMaxValue;
1057 graduatedRenderer->addClass( range );
1060 return graduatedRenderer;
1062 else if ( type ==
"heatmap"_L1 )
1067 else if ( type ==
"vectorField"_L1 )
1084 QString expression = string;
1087 const thread_local QRegularExpression rx1 = QRegularExpression( u
"(?=([^\"\\\\]*(\\\\.|\"([^\"\\\\]*\\\\.)*[^\"\\\\]*\"))*[^\"]*$)(\\s|^)CONCAT(\\s|$)"_s );
1088 expression = expression.replace( rx1, u
"\\4||\\5"_s );
1090 const thread_local QRegularExpression rx2 = QRegularExpression( u
"(?=([^\"\\\\]*(\\\\.|\"([^\"\\\\]*\\\\.)*[^\"\\\\]*\"))*[^\"]*$)(\\s|^)NEWLINE(\\s|$)"_s );
1091 expression = expression.replace( rx2, u
"\\4'\\n'\\5"_s );
1094 const thread_local QRegularExpression rx3 = QRegularExpression( u
"\"(.*?(?<!\\\\))\""_s );
1095 expression = expression.replace( rx3, u
"'\\1'"_s );
1096 const thread_local QRegularExpression rx4 = QRegularExpression( u
"\\\\\""_s );
1097 expression = expression.replace( rx4, u
"\""_s );
1100 const thread_local QRegularExpression rx5 = QRegularExpression( u
"\\[([^]]*)\\]"_s );
1101 expression = expression.replace( rx5, u
"\"\\1\""_s );
1126 QDateTime dt = QDateTime::fromMSecsSinceEpoch( value.toLongLong( &ok ) );
1129 QgsDebugError( u
"Invalid value %1 for datetime"_s.arg( value.toString() ) );
1141 const QVariantMap coords = value.toMap();
1142 if ( coords.isEmpty() )
1147 const double xmin = coords.value( u
"xmin"_s ).toDouble( &ok );
1151 const double ymin = coords.value( u
"ymin"_s ).toDouble( &ok );
1155 const double xmax = coords.value( u
"xmax"_s ).toDouble( &ok );
1159 const double ymax = coords.value( u
"ymax"_s ).toDouble( &ok );
1171 return QVariantMap();
1178 return QVariantMap();
1222 return QVariantMap();
1225 return QVariantMap();
1228 return QVariantMap();
1234 res.insert( u
"spatialReference"_s,
crsToJson( crs ) );
1240QVariantMap QgsArcGisRestUtils::pointToJson(
const QgsPoint *point )
1244 data[u
"x"_s] = u
"NaN"_s;
1247 data[u
"x"_s] = point->
x();
1248 data[u
"y"_s] = point->
y();
1250 if ( point->
is3D() )
1251 data[u
"z"_s] = !std::isnan( point->
z() ) ? QVariant( point->
z() ) : QVariant( u
"NaN"_s );
1254 data[u
"m"_s] = !std::isnan( point->
m() ) ? QVariant( point->
m() ) : QVariant( u
"NaN"_s );
1259QVariantMap QgsArcGisRestUtils::multiPointToJson(
const QgsMultiPoint *multiPoint )
1262 const bool hasZ = multiPoint->
is3D();
1263 const bool hasM = multiPoint->
isMeasure();
1264 data[u
"hasM"_s] = hasM;
1265 data[u
"hasZ"_s] = hasZ;
1267 QVariantList pointsList;
1269 pointsList.reserve( size );
1271 QVariantList pointList;
1272 for (
int i = 0; i < size; ++i )
1274 const QgsPoint *point = multiPoint->
pointN( i );
1277 pointList.append( point->
x() );
1278 pointList.append( point->
y() );
1280 pointList.append( point->
z() );
1281 if ( hasM && !std::isnan( point->
m() ) )
1282 pointList.append( point->
m() );
1284 pointsList.push_back( pointList );
1287 data[u
"points"_s] = pointsList;
1291QVariantList QgsArcGisRestUtils::lineStringToJsonPath(
const QgsLineString *line )
1293 const bool hasZ = line->
is3D();
1296 QVariantList pointsList;
1298 pointsList.reserve( size );
1300 QVariantList pointList;
1301 const double *xData = line->
xData();
1302 const double *yData = line->
yData();
1303 const double *zData = hasZ ? line->
zData() :
nullptr;
1304 const double *mData = hasM ? line->
mData() :
nullptr;
1306 for (
int i = 0; i < size; ++i )
1309 pointList.append( *xData++ );
1310 pointList.append( *yData++ );
1313 pointList.append( *zData++ );
1315 if ( hasM && !std::isnan( *mData ) )
1316 pointList.append( *mData );
1320 pointsList.push_back( pointList );
1325QVariantList QgsArcGisRestUtils::curveToJsonCurve(
const QgsCurve *curve,
bool includeStart )
1327 const bool hasZ = curve->
is3D();
1330 auto pointToList = [hasZ, hasM](
const QgsPoint &point ) -> QVariantList {
1331 QVariantList pointList;
1333 pointList.append( point.
x() );
1334 pointList.append( point.
y() );
1337 pointList.append( point.
z() );
1339 if ( hasM && !std::isnan( point.
m() ) )
1340 pointList.append( point.
m() );
1351 if ( !part.isEmpty() && !includeStart )
1360 if ( includeStart && !circularString->
isEmpty() )
1362 res.push_back( pointToList( circularString->
startPoint() ) );
1365 const int size = circularString->
numPoints();
1366 for (
int i = 1; i + 1 < size; i += 2 )
1369 QVariantMap curvePart;
1370 QVariantList curveList;
1371 curveList.push_back( pointToList( circularString->
pointN( i + 1 ) ) );
1373 curveList.push_back( pointToList( circularString->
pointN( i ) ) );
1375 curvePart.insert( u
"c"_s, curveList );
1376 res.push_back( curvePart );
1385 const int size = compoundCurve->
nCurves();
1386 for (
int i = 0; i < size; ++i )
1388 const QgsCurve *subCurve = compoundCurve->
curveAt( i );
1389 res.append( curveToJsonCurve( subCurve, i == 0 ) );
1400QVariantMap QgsArcGisRestUtils::lineStringToJson(
const QgsLineString *line )
1403 const bool hasZ = line->
is3D();
1405 data[u
"hasM"_s] = hasM;
1406 data[u
"hasZ"_s] = hasZ;
1408 const QVariantList pointsList = lineStringToJsonPath( line );
1410 QVariantList pointsData = QVariantList();
1411 pointsData.push_back( pointsList );
1412 data[u
"paths"_s] = pointsData;
1417QVariantMap QgsArcGisRestUtils::curveToJson(
const QgsCurve *curve )
1420 const bool hasZ = curve->
is3D();
1422 data[u
"hasM"_s] = hasM;
1423 data[u
"hasZ"_s] = hasZ;
1425 const QVariantList curveList = curveToJsonCurve( curve,
true );
1427 QVariantList curveData = QVariantList();
1428 curveData.push_back( curveList );
1429 data[u
"curvePaths"_s] = curveData;
1434QVariantMap QgsArcGisRestUtils::multiLineStringToJson(
const QgsMultiLineString *multiLine )
1437 const bool hasZ = multiLine->
is3D();
1438 const bool hasM = multiLine->
isMeasure();
1439 data[u
"hasM"_s] = hasM;
1440 data[u
"hasZ"_s] = hasZ;
1444 paths.reserve( size );
1445 for (
int i = 0; i < size; ++i )
1447 const QgsLineString *line = multiLine->
lineStringN( i );
1448 paths.push_back( lineStringToJsonPath( line ) );
1451 data[u
"paths"_s] = paths;
1455QVariantMap QgsArcGisRestUtils::multiCurveToJson(
const QgsMultiCurve *multiCurve )
1458 const bool hasZ = multiCurve->
is3D();
1459 const bool hasM = multiCurve->
isMeasure();
1460 data[u
"hasM"_s] = hasM;
1461 data[u
"hasZ"_s] = hasZ;
1465 paths.reserve( size );
1466 for (
int i = 0; i < size; ++i )
1468 const QgsCurve *curve = multiCurve->
curveN( i );
1469 paths.push_back( curveToJsonCurve( curve,
true ) );
1472 data[u
"curvePaths"_s] = paths;
1476QVariantList QgsArcGisRestUtils::polygonToJsonRings(
const QgsPolygon *polygon )
1480 rings.reserve( numInteriorRings + 1 );
1485 switch ( exterior->orientation() )
1488 rings.push_back( lineStringToJsonPath( exterior ) );
1493 std::unique_ptr< QgsLineString > reversed( exterior->reversed() );
1494 rings.push_back( lineStringToJsonPath( reversed.get() ) );
1502 for (
int i = 0; i < numInteriorRings; ++i )
1509 rings.push_back( lineStringToJsonPath( ring ) );
1514 std::unique_ptr< QgsLineString > reversed( ring->
reversed() );
1515 rings.push_back( lineStringToJsonPath( reversed.get() ) );
1525QVariantList QgsArcGisRestUtils::curvePolygonToJsonRings(
const QgsCurvePolygon *polygon )
1529 rings.reserve( numInteriorRings + 1 );
1534 switch ( exterior->orientation() )
1537 rings.push_back( curveToJsonCurve( exterior,
true ) );
1542 std::unique_ptr< QgsCurve > reversed( exterior->reversed() );
1543 rings.push_back( curveToJsonCurve( reversed.get(),
true ) );
1551 for (
int i = 0; i < numInteriorRings; ++i )
1558 rings.push_back( curveToJsonCurve( ring,
true ) );
1563 std::unique_ptr< QgsCurve > reversed( ring->
reversed() );
1564 rings.push_back( curveToJsonCurve( reversed.get(),
true ) );
1574QVariantMap QgsArcGisRestUtils::polygonToJson(
const QgsPolygon *polygon )
1577 const bool hasZ = polygon->
is3D();
1579 data[u
"hasM"_s] = hasM;
1580 data[u
"hasZ"_s] = hasZ;
1581 data[u
"rings"_s] = polygonToJsonRings( polygon );
1585QVariantMap QgsArcGisRestUtils::curvePolygonToJson(
const QgsCurvePolygon *polygon )
1588 const bool hasZ = polygon->
is3D();
1590 data[u
"hasM"_s] = hasM;
1591 data[u
"hasZ"_s] = hasZ;
1592 data[u
"curveRings"_s] = curvePolygonToJsonRings( polygon );
1596QVariantMap QgsArcGisRestUtils::multiPolygonToJson(
const QgsMultiPolygon *multiPolygon )
1599 const bool hasZ = multiPolygon->
is3D();
1600 const bool hasM = multiPolygon->
isMeasure();
1601 data[u
"hasM"_s] = hasM;
1602 data[u
"hasZ"_s] = hasZ;
1606 for (
int i = 0; i < size; ++i )
1608 const QgsPolygon *polygon = multiPolygon->
polygonN( i );
1609 rings.append( polygonToJsonRings( polygon ) );
1612 data[u
"rings"_s] = rings;
1616QVariantMap QgsArcGisRestUtils::multiSurfaceToJson(
const QgsMultiSurface *multiSurface )
1619 const bool hasZ = multiSurface->
is3D();
1620 const bool hasM = multiSurface->
isMeasure();
1621 data[u
"hasM"_s] = hasM;
1622 data[u
"hasZ"_s] = hasZ;
1626 for (
int i = 0; i < size; ++i )
1632 rings.append( curvePolygonToJsonRings( polygon ) );
1635 data[u
"curveRings"_s] = rings;
1645 const QString authid = crs.
authid();
1646 if ( !authid.isEmpty() )
1648 const thread_local QRegularExpression rxAuthid( u
"(\\w+):(\\d+)"_s );
1649 const QRegularExpressionMatch match = rxAuthid.match( authid );
1650 if ( match.hasMatch() && ( ( match.captured( 1 ).compare(
"EPSG"_L1, Qt::CaseInsensitive ) == 0 ) || ( match.captured( 1 ).compare(
"ESRI"_L1, Qt::CaseInsensitive ) == 0 ) ) )
1652 const QString wkid = match.captured( 2 );
1653 res.insert( u
"wkid"_s, wkid );
1672 QVariantMap attributes;
1674 for (
const QgsField &field : fields )
1676 QVariant value = feature.
attribute( field.name() );
1677 if ( value.userType() == qMetaTypeId< QgsUnsetAttributeValue >() )
1688 if ( !attributes.isEmpty() )
1690 res.insert( u
"attributes"_s, attributes );
1700 switch ( expectedType )
1702 case QMetaType::Type::QString:
1704 const QString escaped = variant.toString().replace(
'\\',
"\\\\"_L1 ).replace(
'"',
"\\\""_L1 );
1705 return QString( QUrl::toPercentEncoding( escaped,
"'" ) );
1708 case QMetaType::Type::QDateTime:
1709 case QMetaType::Type::QDate:
1711 switch ( variant.userType() )
1713 case QMetaType::Type::QDateTime:
1714 return variant.toDateTime().toMSecsSinceEpoch();
1716 case QMetaType::Type::QDate:
1718 if ( context.
timeZone().isValid() )
1719 return QDateTime( variant.toDate(), QTime( 0, 0, 0 ), context.
timeZone() ).toMSecsSinceEpoch();
1721 return QDateTime( variant.toDate(), QTime( 0, 0, 0 ) ).toMSecsSinceEpoch();
1736 res.insert( u
"name"_s, field.
name() );
1739 switch ( field.
type() )
1741 case QMetaType::Type::LongLong:
1742 fieldType = u
"esriFieldTypeInteger"_s;
1745 case QMetaType::Type::Int:
1746 fieldType = u
"esriFieldTypeSmallInteger"_s;
1749 case QMetaType::Type::Double:
1750 fieldType = u
"esriFieldTypeDouble"_s;
1753 case QMetaType::Type::QString:
1754 fieldType = u
"esriFieldTypeString"_s;
1757 case QMetaType::Type::QDateTime:
1758 case QMetaType::Type::QDate:
1759 fieldType = u
"esriFieldTypeDate"_s;
1762 case QMetaType::Type::QByteArray:
1763 fieldType = u
"esriFieldTypeBlob"_s;
1768 fieldType = u
"esriFieldTypeString"_s;
1771 res.insert( u
"type"_s, fieldType );
1773 if ( !field.
alias().isEmpty() )
1774 res.insert( u
"alias"_s, field.
alias() );
1778 res.insert( u
"nullable"_s, !notNullable );
1781 res.insert( u
"editable"_s,
true );
1788 if ( type.compare(
"FeatureServer"_L1, Qt::CaseInsensitive ) == 0 )
1790 else if ( type.compare(
"MapServer"_L1, Qt::CaseInsensitive ) == 0 )
1792 else if ( type.compare(
"ImageServer"_L1, Qt::CaseInsensitive ) == 0 )
1794 else if ( type.compare(
"GlobeServer"_L1, Qt::CaseInsensitive ) == 0 )
1796 else if ( type.compare(
"GPServer"_L1, Qt::CaseInsensitive ) == 0 )
1798 else if ( type.compare(
"GeocodeServer"_L1, Qt::CaseInsensitive ) == 0 )
1800 else if ( type.compare(
"SceneServer"_L1, Qt::CaseInsensitive ) == 0 )
1808 const QStringList parts = capabilities.split(
',' );
1824 if ( pixelType.compare(
"U8"_L1, Qt::CaseInsensitive ) == 0
1825 || pixelType.compare(
"U4"_L1, Qt::CaseInsensitive ) == 0
1826 || pixelType.compare(
"U2"_L1, Qt::CaseInsensitive ) == 0
1827 || pixelType.compare(
"U1"_L1, Qt::CaseInsensitive ) == 0 )
1831 else if ( pixelType.compare(
"S8"_L1, Qt::CaseInsensitive ) == 0 )
1835 else if ( pixelType.compare(
"U16"_L1, Qt::CaseInsensitive ) == 0 )
1839 else if ( pixelType.compare(
"S16"_L1, Qt::CaseInsensitive ) == 0 )
1843 else if ( pixelType.compare(
"U32"_L1, Qt::CaseInsensitive ) == 0 )
1847 else if ( pixelType.compare(
"S32"_L1, Qt::CaseInsensitive ) == 0 )
1851 else if ( pixelType.compare(
"F32"_L1, Qt::CaseInsensitive ) == 0 )
1855 else if ( pixelType.compare(
"F64"_L1, Qt::CaseInsensitive ) == 0 )
1859 else if ( pixelType.compare(
"C64"_L1, Qt::CaseInsensitive ) == 0 )
1864 else if ( pixelType.compare(
"C128"_L1, Qt::CaseInsensitive ) == 0 )
1871 QgsDebugError( u
"Unknown pixelType: %1"_s.arg( pixelType ) );
1879 if ( pixelType.compare(
"U8"_L1, Qt::CaseInsensitive ) == 0
1880 || pixelType.compare(
"U4"_L1, Qt::CaseInsensitive ) == 0
1881 || pixelType.compare(
"U2"_L1, Qt::CaseInsensitive ) == 0
1882 || pixelType.compare(
"U1"_L1, Qt::CaseInsensitive ) == 0
1883 || pixelType.compare(
"S8"_L1, Qt::CaseInsensitive ) == 0
1884 || pixelType.compare(
"U16"_L1, Qt::CaseInsensitive ) == 0
1885 || pixelType.compare(
"S16"_L1, Qt::CaseInsensitive ) == 0 )
1889 else if ( pixelType.compare(
"U32"_L1, Qt::CaseInsensitive ) == 0 )
1893 else if ( pixelType.compare(
"S32"_L1, Qt::CaseInsensitive ) == 0
1894 || pixelType.compare(
"F32"_L1, Qt::CaseInsensitive ) == 0
1895 || pixelType.compare(
"F64"_L1, Qt::CaseInsensitive ) == 0
1896 || pixelType.compare(
"C64"_L1, Qt::CaseInsensitive ) == 0
1897 || pixelType.compare(
"C128"_L1, Qt::CaseInsensitive ) == 0 )
1903 QgsDebugError( u
"Unknown pixelType: %1"_s.arg( pixelType ) );
1911 if ( pixelType.compare(
"U8"_L1, Qt::CaseInsensitive ) == 0 )
1913 return std::make_pair( 0.0, 255.0 );
1915 else if ( pixelType.compare(
"U4"_L1, Qt::CaseInsensitive ) == 0 )
1917 return std::make_pair( 0.0, 15.0 );
1919 else if ( pixelType.compare(
"U2"_L1, Qt::CaseInsensitive ) == 0 )
1921 return std::make_pair( 0.0, 3.0 );
1923 else if ( pixelType.compare(
"U1"_L1, Qt::CaseInsensitive ) == 0 )
1925 return std::make_pair( 0.0, 1.0 );
1927 else if ( pixelType.compare(
"S8"_L1, Qt::CaseInsensitive ) == 0 )
1929 return std::make_pair( -128.0, 127.0 );
1931 else if ( pixelType.compare(
"U16"_L1, Qt::CaseInsensitive ) == 0 )
1933 return std::make_pair( 0.0, 65535.0 );
1935 else if ( pixelType.compare(
"S16"_L1, Qt::CaseInsensitive ) == 0 )
1937 return std::make_pair( -32768.0, 32767.0 );
1939 else if ( pixelType.compare(
"U32"_L1, Qt::CaseInsensitive ) == 0 )
1941 return std::make_pair( 0.0,
static_cast<double>( std::numeric_limits<uint32_t>::max() ) );
1943 else if ( pixelType.compare(
"S32"_L1, Qt::CaseInsensitive ) == 0 )
1945 return std::make_pair(
static_cast<double>( std::numeric_limits<int32_t>::lowest() ),
static_cast<double>( std::numeric_limits<int32_t>::max() ) );
1947 else if ( pixelType.compare(
"F32"_L1, Qt::CaseInsensitive ) == 0 )
1949 return std::make_pair(
static_cast<double>( std::numeric_limits<float>::lowest() ),
static_cast<double>( std::numeric_limits<float>::max() ) );
1951 else if ( pixelType.compare(
"F64"_L1, Qt::CaseInsensitive ) == 0 )
1953 return std::make_pair( std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max() );
1955 else if ( pixelType.compare(
"C64"_L1, Qt::CaseInsensitive ) == 0 )
1958 return std::make_pair(
static_cast<double>( std::numeric_limits<float>::lowest() ),
static_cast<double>( std::numeric_limits<float>::max() ) );
1960 else if ( pixelType.compare(
"C128"_L1, Qt::CaseInsensitive ) == 0 )
1963 return std::make_pair( std::numeric_limits<double>::lowest(), std::numeric_limits<double>::max() );
1967 QgsDebugError( u
"Unknown pixelType: %1"_s.arg( pixelType ) );
1970 return std::nullopt;
1975 if ( bandName.isEmpty() )
1980 if ( bandName.compare(
"Red"_L1, Qt::CaseInsensitive ) == 0 )
1982 else if ( bandName.compare(
"Green"_L1, Qt::CaseInsensitive ) == 0 )
1984 else if ( bandName.compare(
"Blue"_L1, Qt::CaseInsensitive ) == 0 )
1986 else if ( bandName.compare(
"Alpha"_L1, Qt::CaseInsensitive ) == 0 )
1988 else if ( bandName.compare(
"NIR"_L1, Qt::CaseInsensitive ) == 0
1989 || bandName.compare(
"NearInfrared"_L1, Qt::CaseInsensitive ) == 0
1990 || bandName.compare(
"NearIR"_L1, Qt::CaseInsensitive ) == 0
1991 || bandName.compare(
"NarrowNIR"_L1, Qt::CaseInsensitive ) == 0 )
1993 else if ( bandName.startsWith(
"SWIR"_L1, Qt::CaseInsensitive ) )
1995 else if ( bandName.startsWith(
"VRE"_L1, Qt::CaseInsensitive ) || bandName.compare(
"RedEdge"_L1, Qt::CaseInsensitive ) == 0 )
1997 else if ( bandName.startsWith(
"Coastal"_L1, Qt::CaseInsensitive ) )
1999 else if ( bandName.startsWith(
"Pan"_L1, Qt::CaseInsensitive ) )
2001 else if ( bandName.startsWith(
"Thermal"_L1, Qt::CaseInsensitive ) || bandName.startsWith(
"TIR"_L1, Qt::CaseInsensitive ) )
2003 else if ( bandName.compare(
"Gray"_L1, Qt::CaseInsensitive ) == 0 || bandName.compare(
"Grey"_L1, Qt::CaseInsensitive ) == 0 )
2005 else if ( bandName.compare(
"Cyan"_L1, Qt::CaseInsensitive ) == 0 )
2007 else if ( bandName.compare(
"Magenta"_L1, Qt::CaseInsensitive ) == 0 )
2009 else if ( bandName.compare(
"Yellow"_L1, Qt::CaseInsensitive ) == 0 )
2011 else if ( bandName.compare(
"Black"_L1, Qt::CaseInsensitive ) == 0 )
2013 else if ( bandName.compare(
"Hue"_L1, Qt::CaseInsensitive ) == 0 )
2015 else if ( bandName.compare(
"Saturation"_L1, Qt::CaseInsensitive ) == 0 )
2017 else if ( bandName.compare(
"Lightness"_L1, Qt::CaseInsensitive ) == 0 )
2035 return std::numeric_limits<quint8>::max();
2039 return std::numeric_limits<qint8>::lowest();
2043 return std::numeric_limits<quint16>::max();
2047 return std::numeric_limits<qint16>::lowest();
2051 return std::numeric_limits<quint32>::max();
2055 return std::numeric_limits<qint32>::lowest();
2059 return std::numeric_limits<float>::quiet_NaN();
2063 return std::numeric_limits<double>::quiet_NaN();
@ BelowLine
Labels can be placed below a line feature. Unless MapOrientation is also specified this mode respects...
@ MapOrientation
Signifies that the AboveLine and BelowLine flags should respect the map's orientation rather than the...
@ OnLine
Labels can be placed directly over a line feature.
@ AboveLine
Labels can be placed above a line feature. Unless MapOrientation is also specified this mode respects...
@ NoOrientation
Unknown orientation or sentinel value.
@ CounterClockwise
Counter-clockwise direction.
@ Clockwise
Clockwise direction.
@ OverPoint
Arranges candidates over a point (or centroid of a polygon), or at a preset offset from the point....
@ Line
Arranges candidates parallel to a generalised line representing the feature or parallel to a polygon'...
@ Horizontal
Arranges horizontal candidates scattered throughout a polygon feature or along a line feature....
ArcGisRestServiceType
Available ArcGIS REST service types.
@ GeocodeServer
GeocodeServer.
@ SceneServer
SceneServer.
@ Unknown
Other unknown/unsupported type.
@ GlobeServer
GlobeServer.
@ ImageServer
ImageServer.
@ FeatureServer
FeatureServer.
DataType
Raster data types.
@ Float32
Thirty two bit floating point (float).
@ CFloat64
Complex Float64.
@ Int16
Sixteen bit signed integer (qint16).
@ ARGB32_Premultiplied
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
@ Int8
Eight bit signed integer (qint8) (added in QGIS 3.30).
@ UInt16
Sixteen bit unsigned integer (quint16).
@ Byte
Eight bit unsigned integer (quint8).
@ UnknownDataType
Unknown or unspecified type.
@ ARGB32
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32.
@ Int32
Thirty two bit signed integer (qint32).
@ Float64
Sixty four bit floating point (double).
@ CFloat32
Complex Float32.
@ UInt32
Thirty two bit unsigned integer (quint32).
@ Points
Points (e.g., for font sizes).
QFlags< ArcGisRestServiceCapability > ArcGisRestServiceCapabilities
Available ArcGIS REST service capabilities.
@ TilesOnly
Service supports tiled image requests only.
@ Image
Image capabilities.
RasterColorInterpretation
Raster color interpretation.
@ NIRBand
Near-InfraRed (NIR) band [0.75 - 1.40 um].
@ GreenBand
Green band of RGBA image, or green spectral band [0.51 - 0.60 um].
@ SaturationBand
Saturation band of HLS image.
@ MagentaBand
Magenta band of CMYK image.
@ BlackBand
Black band of CMLY image.
@ AlphaBand
Alpha (0=transparent, 255=opaque).
@ SWIRBand
Short-Wavelength InfraRed (SWIR) band [1.40 - 3.00 um].
@ BlueBand
Blue band of RGBA image, or blue spectral band [0.45 - 0.53 um].
@ RedEdgeBand
Red-edge band [0.69 - 0.79 um].
@ YellowBand
Yellow band of CMYK image, or yellow spectral band [0.58 - 0.62 um].
@ CyanBand
Cyan band of CMYK image.
@ LightnessBand
Lightness band of HLS image.
@ CoastalBand
Coastal band [0.40 - 0.45 um].
@ HueBand
Hue band of HLS image.
@ TIRBand
Thermal InfraRed (TIR) band (MWIR or LWIR) [3 - 15 um].
@ RedBand
Red band of RGBA image, or red spectral band [0.62 - 0.69 um].
@ PanBand
Panchromatic band [0.40 - 1.00 um].
WkbType
The WKB type describes the number of dimensions a geometry has.
@ CompoundCurve
CompoundCurve.
@ MultiPolygon
MultiPolygon.
@ MultiLineString
MultiLineString.
@ CircularString
CircularString.
@ GeometryCollection
GeometryCollection.
@ CurvePolygon
CurvePolygon.
@ MultiSurface
MultiSurface.
@ Wkt2_2019Simplified
WKT2_2019 with the simplification rule of WKT2_SIMPLIFIED.
Abstract base class for all geometries.
virtual const QgsAbstractGeometry * simplifiedTypeRef() const
Returns a reference to the simplest lossless representation of this geometry, e.g.
bool isMeasure() const
Returns true if the geometry contains m values.
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
Qgis::WkbType wkbType() const
Returns the WKB type of the geometry.
Contains the context of a ArcGIS REST service operation.
QTimeZone timeZone() const
Returns the time zone for datetime values.
QString objectIdFieldName() const
Returns the name of the objectId field.
static std::unique_ptr< QgsAbstractGeometry > convertGeometry(const QVariantMap &geometry, const QString &esriGeometryType, bool hasM, bool hasZ, bool allowCurves=true, QgsCoordinateReferenceSystem *crs=nullptr)
Converts an ESRI REST geometry JSON definition to a QgsAbstractGeometry.
static QVariantMap fieldDefinitionToJson(const QgsField &field)
Converts a field's definition to an ArcGIS REST JSON representation.
static QgsCoordinateReferenceSystem convertSpatialReference(const QVariantMap &spatialReferenceMap)
Converts a spatial reference JSON definition to a QgsCoordinateReferenceSystem value.
static QDateTime convertDateTime(const QVariant &value)
Converts a date time value to a QDateTime.
static Qgis::WkbType convertGeometryType(const QString &type)
Converts an ESRI REST geometry type to a WKB type.
static QString convertLabelingExpression(const QString &string)
Converts an ESRI labeling expression to a QGIS expression string.
static QVariantMap geometryToJson(const QgsGeometry &geometry, const QgsArcGisRestContext &context, const QgsCoordinateReferenceSystem &crs=QgsCoordinateReferenceSystem())
Converts a geometry to an ArcGIS REST JSON representation.
static double defaultNoDataForDataType(Qgis::DataType type, bool &ok)
Returns a sensible no-data value to use for the specified data type.
static PixelTypeLimitUsefulness pixelTypeLimitUsefulness(const QString &pixelType)
Returns whether the theoretical minimum and maximum values for a given ESRI pixelType are practically...
static Qgis::ArcGisRestServiceType serviceTypeFromString(const QString &type)
Converts a string value to a REST service type.
static QVariant variantToAttributeValue(const QVariant &variant, QMetaType::Type expectedType, const QgsArcGisRestContext &context)
Converts a variant to a REST attribute value.
static QVariantMap featureToJson(const QgsFeature &feature, const QgsArcGisRestContext &context, const QgsCoordinateReferenceSystem &crs=QgsCoordinateReferenceSystem(), QgsArcGisRestUtils::FeatureToJsonFlags flags=QgsArcGisRestUtils::FeatureToJsonFlags(static_cast< int >(QgsArcGisRestUtils::FeatureToJsonFlag::IncludeGeometry)|static_cast< int >(QgsArcGisRestUtils::FeatureToJsonFlag::IncludeNonObjectIdAttributes)))
Converts a feature to an ArcGIS REST JSON representation.
static Qt::PenStyle convertLineStyle(const QString &style)
Converts an ESRI line style to a Qt pen style.
@ IncludeGeometry
Whether to include the geometry definition.
@ IncludeNonObjectIdAttributes
Whether to include any non-objectId attributes.
@ SkipUnsetAttributes
Skip unset attributes.
static Qgis::ArcGisRestServiceCapabilities serviceCapabilitiesFromString(const QString &capabilities)
Parses a capabilities string to known values.
static std::optional< std::pair< double, double > > rangeForPixelType(const QString &pixelType)
Returns the valid data range given an ESRI pixelType string.
static QMetaType::Type convertFieldType(const QString &type)
Converts an ESRI REST field type to a QVariant type.
static Qt::BrushStyle convertFillStyle(const QString &style)
Converts an ESRI fill style to a Qt brush style.
static std::unique_ptr< QgsFeatureRenderer > convertRenderer(const QVariantMap &rendererData, QgsSymbolConverterContext &context)
Converts renderer JSON data to an equivalent QgsFeatureRenderer.
static Qgis::RasterColorInterpretation colorInterpretationFromBandName(const QString &bandName)
Attempts to match arbitrary band name strings to a QGIS raster color interpretation.
static QVariantMap crsToJson(const QgsCoordinateReferenceSystem &crs)
Converts a crs to an ArcGIS REST JSON representation.
static std::unique_ptr< QgsAbstractVectorLayerLabeling > convertLabeling(const QVariantList &data)
Converts labeling JSON data to an equivalent QGIS vector labeling.
QFlags< FeatureToJsonFlag > FeatureToJsonFlags
Flags which control the behavior of converting features to JSON.
static Qgis::DataType dataTypeFromString(const QString &pixelType)
Returns the raster data type corresponding to an ESRI pixelType string.
static std::unique_ptr< QgsSymbol > convertSymbol(const QVariantMap &definition, QgsSymbolConverterContext &context)
Converts a symbol JSON definition to a QgsSymbol.
static QColor convertColor(const QVariant &data)
Converts ESRI JSON color data to a QColor object.
static QgsRectangle convertRectangle(const QVariant &value)
Converts a rectangle value to a QgsRectangle.
A dummy implementation class method which does not compute any breaks.
A classification method which uses equal width intervals.
Implementation of a fixed interval classification.
A classification method for natural breaks, based on Jenks method.
A classification method which creates classes based on quantiles.
A classification method which classifies based on standard deviation of values.
int nCurves() const
Returns the number of curves in the geometry.
const QgsCurve * curveAt(int i) const
Returns the curve at the specified index.
Represents a coordinate reference system (CRS).
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
bool createFromWkt(const QString &wkt)
Sets this CRS using a WKT definition.
bool createFromString(const QString &definition)
Set up this CRS from a string definition.
QString toWkt(Qgis::CrsWktVariant variant=Qgis::CrsWktVariant::Wkt1Gdal, bool multiline=false, int indentationWidth=4) const
Returns a WKT representation of this CRS.
Curve polygon geometry type.
int numInteriorRings() const
Returns the number of interior rings contained with the curve polygon.
const QgsCurve * exteriorRing() const
Returns the curve polygon's exterior ring.
const QgsCurve * interiorRing(int i) const
Retrieves an interior ring from the curve polygon.
Abstract base class for curved geometry type.
Qgis::AngularDirection orientation() const
Returns the curve's orientation, e.g.
virtual QgsCurve * reversed() const =0
Returns a reversed copy of the curve, where the direction of the curve has been flipped.
virtual QgsPoint endPoint() const =0
Returns the end point of the curve.
Handles parsing and evaluation of expressions (formerly called "search strings").
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes).
bool isValid() const
Checks if this expression is valid.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Q_INVOKABLE QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
@ ConstraintNotNull
Field may not be null.
Encapsulate a field in an attribute table or data source.
QgsFieldConstraints constraints
Container of fields for a vector layer.
int numGeometries() const
Returns the number of geometries within the collection.
const QgsAbstractGeometry * geometryN(int n) const
Returns a const reference to a geometry from within the collection.
A geometry is the spatial representation of a feature.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
Represents a color stop within a QgsGradientColorRamp color ramp.
void setPlacementFlags(Qgis::LabelLinePlacementFlags flags)
Returns the line placement flags, which dictate how line labels can be placed above or below the line...
void setQuadrant(Qgis::LabelQuadrantPosition quadrant)
Sets the quadrant in which to offset labels from the point.
Line string geometry type, with support for z-dimension and m-values.
QgsLineString * reversed() const override
Returns a reversed copy of the curve, where the direction of the curve has been flipped.
Multi curve geometry collection.
QgsCurve * curveN(int index)
Returns the curve with the specified index.
Multi line string geometry collection.
QgsLineString * lineStringN(int index)
Returns the line string with the specified index.
Multi point geometry collection.
QgsPoint * pointN(int index)
Returns the point with the specified index.
Multi polygon geometry collection.
QgsPolygon * polygonN(int index)
Returns the polygon with the specified index.
Multi surface geometry collection.
Contains settings for how a map layer will be labeled.
void setFormat(const QgsTextFormat &format)
Sets the label text formatting settings, e.g., font settings, buffer settings, etc.
Qgis::LabelPlacement placement
Label placement mode.
double repeatDistance
Distance for repeating labels for a single feature.
bool isExpression
true if this label is made from a expression string, e.g., FieldName || 'mm'
const QgsLabelLineSettings & lineSettings() const
Returns the label line settings, which contain settings related to how the label engine places and fo...
Qgis::RenderUnit repeatDistanceUnit
Units for repeating labels for a single feature.
QString fieldName
Name of field (or an expression) to use for label text.
const QgsLabelPointSettings & pointSettings() const
Returns the label point settings, which contain settings related to how the label engine places and f...
Point geometry type, with support for z-dimension and m-values.
void clear() override
Clears the geometry, ie reset it to a null geometry.
bool isEmpty() const override
Returns true if the geometry is empty.
A store for object properties.
void setTransformer(QgsPropertyTransformer *transformer)
Sets an optional transformer to use for manipulating the calculated values for the property.
static QgsProperty fromExpression(const QString &expression, bool isActive=true)
Returns a new ExpressionBasedProperty created from the specified expression.
static QgsProperty fromField(const QString &fieldName, bool isActive=true)
Returns a new FieldBasedProperty created from the specified field name.
A container for the context for various read/write operations on objects.
A rectangle specified with double values.
Represents an individual category (class) from a QgsCategorizedSymbolRenderer.
Represents a value range for a QgsGraduatedSymbolRenderer.
void setUpperValue(double upperValue)
Sets the upper bound of the range.
void setSymbol(QgsSymbol *s)
Sets the symbol used for the range.
void setLabel(const QString &label)
Sets the label used for the range.
void setLowerValue(double lowerValue)
Sets the lower bound of the range.
A child rule for QgsRuleBasedLabeling.
void setActive(bool state)
Sets if this rule is active.
void appendChild(QgsRuleBasedLabeling::Rule *rule)
add child rule, take ownership, sets this as parent
int numPoints() const override
Returns the number of points in the curve.
bool isEmpty() const override
Returns true if the geometry is empty.
const double * mData() const
Returns a const pointer to the m vertex data, or nullptr if the simple curve does not have m values.
const double * yData() const
Returns a const pointer to the y vertex data.
QgsPoint startPoint() const override
Returns the starting point of the curve.
QgsPoint pointN(int i) const
Returns the specified point from inside the simple curve.
const double * xData() const
Returns a const pointer to the x vertex data.
const double * zData() const
Returns a const pointer to the z vertex data, or nullptr if the simple curve does not have z values.
Represents the context in which a QgsSymbolConverter conversion occurs.
void pushWarning(const QString &warning)
Pushes a warning message generated during the conversion.
A symbol converter for converting ESRI REST JSON symbols.
static Qt::PenStyle convertLineStyle(const QString &style)
Converts an ESRI line style to a Qt pen style.
std::unique_ptr< QgsSymbol > createSymbol(const QVariant &variant, QgsSymbolConverterContext &context) const override
Creates a new QgsSymbol from a QVariant representation.
static Qt::BrushStyle convertFillStyle(const QString &style)
Converts an ESRI fill style to a Qt brush style.
static QColor convertColor(const QVariant &data)
Converts ESRI JSON color data to a QColor object.
virtual void setDataDefinedProperty(Property key, const QgsProperty &property)
Sets a data defined property for the layer.
Abstract base class for all rendered symbols.
QgsSymbolLayer * symbolLayer(int layer)
Returns the symbol layer at the specified index.
int symbolLayerCount() const
Returns the total number of symbol layers contained in the symbol.
Container for settings relating to a text buffer.
void setColor(const QColor &color)
Sets the color for the buffer.
void setSizeUnit(Qgis::RenderUnit unit)
Sets the units used for the buffer size.
void setEnabled(bool enabled)
Sets whether the text buffer will be drawn.
void setSize(double size)
Sets the size of the buffer.
Container for all settings relating to text rendering.
void setColor(const QColor &color)
Sets the color that text will be rendered in.
void setSize(double size)
Sets the size for rendered text.
void setFont(const QFont &font)
Sets the font used for rendering text.
void setSizeUnit(Qgis::RenderUnit unit)
Sets the units for the size of rendered text.
void setBuffer(const QgsTextBufferSettings &bufferSettings)
Sets the text's buffer settings.
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
static Qgis::WkbType zmType(Qgis::WkbType type, bool hasZ, bool hasM)
Returns the modified input geometry type according to hasZ / hasM.
static Q_INVOKABLE bool hasZ(Qgis::WkbType type)
Tests whether a WKB type contains the z-dimension.
static Q_INVOKABLE bool hasM(Qgis::WkbType type)
Tests whether a WKB type contains m values.
static Qgis::WkbType flatType(Qgis::WkbType type)
Returns the flat type for a WKB type.
#define BUILTIN_UNREACHABLE
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
T qgsgeometry_cast(QgsAbstractGeometry *geom)
QList< QgsRendererCategory > QgsCategoryList
QList< QgsGradientStop > QgsGradientStopsList
List of gradient stops.
#define QgsDebugError(str)
Struct representing whether the theoretical limits of a pixel type are useful for describing actual d...