56#include <QRegularExpression>
60#include "moc_qgsarcgisrestutils.cpp"
62using namespace Qt::StringLiterals;
66 if ( esriFieldType ==
"esriFieldTypeInteger"_L1 )
67 return QMetaType::Type::LongLong;
68 if ( esriFieldType ==
"esriFieldTypeSmallInteger"_L1 )
69 return QMetaType::Type::Int;
70 if ( esriFieldType ==
"esriFieldTypeDouble"_L1 )
71 return QMetaType::Type::Double;
72 if ( esriFieldType ==
"esriFieldTypeSingle"_L1 )
73 return QMetaType::Type::Double;
74 if ( esriFieldType ==
"esriFieldTypeString"_L1 )
75 return QMetaType::Type::QString;
76 if ( esriFieldType ==
"esriFieldTypeDate"_L1 )
77 return QMetaType::Type::QDateTime;
78 if ( esriFieldType ==
"esriFieldTypeGeometry"_L1 )
79 return QMetaType::Type::UnknownType;
80 if ( esriFieldType ==
"esriFieldTypeOID"_L1 )
81 return QMetaType::Type::LongLong;
82 if ( esriFieldType ==
"esriFieldTypeBlob"_L1 )
83 return QMetaType::Type::QByteArray;
84 if ( esriFieldType ==
"esriFieldTypeGlobalID"_L1 )
85 return QMetaType::Type::QString;
86 if ( esriFieldType ==
"esriFieldTypeRaster"_L1 )
87 return QMetaType::Type::QByteArray;
88 if ( esriFieldType ==
"esriFieldTypeGUID"_L1 )
89 return QMetaType::Type::QString;
90 if ( esriFieldType ==
"esriFieldTypeXML"_L1 )
91 return QMetaType::Type::QString;
92 return QMetaType::Type::UnknownType;
98 if ( esriGeometryType ==
"esriGeometryNull"_L1 )
100 else if ( esriGeometryType ==
"esriGeometryPoint"_L1 )
102 else if ( esriGeometryType ==
"esriGeometryMultipoint"_L1 )
104 else if ( esriGeometryType ==
"esriGeometryPolyline"_L1 )
106 else if ( esriGeometryType ==
"esriGeometryPolygon"_L1 )
108 else if ( esriGeometryType ==
"esriGeometryEnvelope"_L1 )
128std::unique_ptr< QgsPoint > QgsArcGisRestUtils::convertPoint(
const QVariantList &coordList,
Qgis::WkbType pointType )
130 int nCoords = coordList.size();
133 bool xok =
false, yok =
false;
134 const double x = coordList[0].toDouble( &xok );
135 const double y = coordList[1].toDouble( &yok );
139 const double z = hasZ && nCoords >= 3 ? coordList[2].toDouble() : std::numeric_limits< double >::quiet_NaN();
142 const double m =
QgsWkbTypes::hasM( pointType ) && ( ( hasZ && nCoords >= 4 ) || ( !hasZ && nCoords >= 3 ) ) ? coordList[ hasZ ? 3 : 2].toDouble() : std::numeric_limits< double >::quiet_NaN();
143 return std::make_unique< QgsPoint >( pointType, x, y, z, m );
146std::unique_ptr< QgsCircularString > QgsArcGisRestUtils::convertCircularString(
const QVariantMap &curveData,
Qgis::WkbType pointType,
const QgsPoint &startPoint )
148 const QVariantList coordsList = curveData[u
"c"_s].toList();
149 if ( coordsList.isEmpty() )
151 const int coordsListSize = coordsList.size();
153 QVector<QgsPoint> points;
154 points.reserve( coordsListSize + 1 );
155 points.append( startPoint );
157 for (
int i = 0; i < coordsListSize - 1; )
161 std::unique_ptr< QgsPoint > endPoint( convertPoint( coordsList.at( i ).toList(), pointType ) );
165 std::unique_ptr< QgsPoint > interiorPoint( convertPoint( coordsList.at( i ).toList(), pointType ) );
166 if ( !interiorPoint )
169 points << *interiorPoint;
172 auto curve = std::make_unique< QgsCircularString> ();
173 curve->setPoints( points );
177std::unique_ptr< QgsCompoundCurve > QgsArcGisRestUtils::convertCompoundCurve(
const QVariantList &curvesList,
Qgis::WkbType pointType )
180 auto compoundCurve = std::make_unique< QgsCompoundCurve >();
182 QVector< double > lineX;
183 QVector< double > lineY;
184 QVector< double > lineZ;
185 QVector< double > lineM;
186 int maxCurveListSize = curvesList.size();
187 lineX.resize( maxCurveListSize );
188 lineY.resize( maxCurveListSize );
192 lineZ.resize( maxCurveListSize );
195 lineM.resize( maxCurveListSize );
197 double *outLineX = lineX.data();
198 double *outLineY = lineY.data();
199 double *outLineZ = lineZ.data();
200 double *outLineM = lineM.data();
201 int actualLineSize = 0;
206 int curveListIndex = 0;
207 for (
const QVariant &curveData : curvesList )
209 if ( curveData.userType() == QMetaType::Type::QVariantList )
211 const QVariantList coordList = curveData.toList();
212 const int nCoords = coordList.size();
216 const double x = coordList[0].toDouble( &xok );
217 const double y = coordList[1].toDouble( &yok );
226 *outLineZ++ = nCoords >= 3 ? coordList[2].toDouble() : std::numeric_limits< double >::quiet_NaN();
232 *outLineM++ = ( ( hasZ && nCoords >= 4 ) || ( !hasZ && nCoords >= 3 ) ) ? coordList[ hasZ ? 3 : 2].toDouble() : std::numeric_limits< double >::quiet_NaN();
235 else if ( curveData.userType() == QMetaType::Type::QVariantMap )
238 QgsPoint lastLineStringPoint;
239 if ( actualLineSize > 0 )
241 lastLineStringPoint = QgsPoint( lineX.at( actualLineSize - 1 ),
242 lineY.at( actualLineSize - 1 ),
243 hasZ ? lineZ.at( actualLineSize - 1 ) : std::numeric_limits< double >::quiet_NaN(),
244 hasM ? lineM.at( actualLineSize - 1 ) : std::numeric_limits< double >::quiet_NaN() );
246 std::unique_ptr< QgsCircularString > circularString( convertCircularString( curveData.toMap(), pointType, lastLineStringPoint ) );
247 if ( !circularString )
252 if ( actualLineSize > 0 )
254 lineX.resize( actualLineSize );
255 lineY.resize( actualLineSize );
257 lineZ.resize( actualLineSize );
259 lineM.resize( actualLineSize );
261 compoundCurve->addCurve(
new QgsLineString( lineX, lineY, lineZ, lineM ) );
262 lineX.resize( maxCurveListSize - curveListIndex );
263 lineY.resize( maxCurveListSize - curveListIndex );
265 lineZ.resize( maxCurveListSize - curveListIndex );
267 lineM.resize( maxCurveListSize - curveListIndex );
268 outLineX = lineX.data();
269 outLineY = lineY.data();
270 outLineZ = lineZ.data();
271 outLineM = lineM.data();
275 if ( compoundCurve->curveAt( compoundCurve->nCurves() - 1 )->nCoordinates() < 2 )
276 compoundCurve->removeCurve( compoundCurve->nCurves() - 1 );
278 const QgsPoint endPointCircularString = circularString->endPoint();
279 compoundCurve->addCurve( circularString.release() );
283 *outLineX++ = endPointCircularString.
x();
284 *outLineY++ = endPointCircularString.
y();
286 *outLineZ++ = endPointCircularString.
z();
288 *outLineM++ = endPointCircularString.
m();
293 if ( actualLineSize == 1 && compoundCurve->nCurves() > 0 )
295 const QgsCurve *finalCurve = compoundCurve->curveAt( compoundCurve->nCurves() - 1 );
296 const QgsPoint finalCurveEndPoint = finalCurve->
endPoint();
299 && ( !hasZ ||
qgsDoubleNear( finalCurveEndPoint.
z(), lineZ.at( 0 ) ) )
300 && ( !hasM ||
qgsDoubleNear( finalCurveEndPoint.
m(), lineM.at( 0 ) ) ) )
306 if ( actualLineSize > 0 )
308 lineX.resize( actualLineSize );
309 lineY.resize( actualLineSize );
311 lineZ.resize( actualLineSize );
313 lineM.resize( actualLineSize );
314 compoundCurve->addCurve(
new QgsLineString( lineX, lineY, lineZ, lineM ) );
317 return compoundCurve;
320std::unique_ptr< QgsPoint > QgsArcGisRestUtils::convertGeometryPoint(
const QVariantMap &geometryData,
Qgis::WkbType pointType )
323 bool xok =
false, yok =
false;
324 double x = geometryData[u
"x"_s].toDouble( &xok );
325 double y = geometryData[u
"y"_s].toDouble( &yok );
328 double z = geometryData[u
"z"_s].toDouble();
329 double m = geometryData[u
"m"_s].toDouble();
330 return std::make_unique< QgsPoint >( pointType, x, y, z, m );
333std::unique_ptr< QgsMultiPoint > QgsArcGisRestUtils::convertMultiPoint(
const QVariantMap &geometryData,
Qgis::WkbType pointType )
336 const QVariantList coordsList = geometryData[u
"points"_s].toList();
338 auto multiPoint = std::make_unique< QgsMultiPoint >();
339 multiPoint->reserve( coordsList.size() );
340 for (
const QVariant &coordData : coordsList )
342 const QVariantList coordList = coordData.toList();
343 std::unique_ptr< QgsPoint > p = convertPoint( coordList, pointType );
348 multiPoint->addGeometry( p.release() );
353 std::unique_ptr< QgsPoint > p = convertGeometryPoint( geometryData, pointType );
355 multiPoint->addGeometry( p.release() );
357 if ( multiPoint->numGeometries() == 0 )
365std::unique_ptr< QgsMultiCurve > QgsArcGisRestUtils::convertGeometryPolyline(
const QVariantMap &geometryData,
Qgis::WkbType pointType )
368 QVariantList pathsList;
369 if ( geometryData[u
"paths"_s].isValid() )
370 pathsList = geometryData[u
"paths"_s].toList();
371 else if ( geometryData[u
"curvePaths"_s].isValid() )
372 pathsList = geometryData[u
"curvePaths"_s].toList();
373 if ( pathsList.isEmpty() )
375 auto multiCurve = std::make_unique< QgsMultiCurve >();
376 multiCurve->reserve( pathsList.size() );
377 for (
const QVariant &pathData : std::as_const( pathsList ) )
379 std::unique_ptr< QgsCompoundCurve > curve = convertCompoundCurve( pathData.toList(), pointType );
384 multiCurve->addGeometry( curve.release() );
389std::unique_ptr< QgsMultiSurface > QgsArcGisRestUtils::convertGeometryPolygon(
const QVariantMap &geometryData,
Qgis::WkbType pointType )
392 QVariantList ringsList;
393 if ( geometryData[u
"rings"_s].isValid() )
394 ringsList = geometryData[u
"rings"_s].toList();
395 else if ( geometryData[u
"ringPaths"_s].isValid() )
396 ringsList = geometryData[u
"ringPaths"_s].toList();
397 if ( ringsList.isEmpty() )
400 QList< QgsCompoundCurve * > curves;
401 for (
int i = 0, n = ringsList.size(); i < n; ++i )
403 std::unique_ptr< QgsCompoundCurve > curve = convertCompoundCurve( ringsList[i].toList(), pointType );
408 curves.append( curve.release() );
410 if ( curves.count() == 0 )
413 auto result = std::make_unique< QgsMultiSurface >();
414 if ( curves.count() == 1 )
417 auto newPolygon = std::make_unique< QgsCurvePolygon >();
418 newPolygon->setExteriorRing( curves.takeAt( 0 ) );
419 result->addGeometry( newPolygon.release() );
423 std::sort( curves.begin(), curves.end(), [](
const QgsCompoundCurve * a,
const QgsCompoundCurve * b )->bool{ double a_area = 0.0; double b_area = 0.0; a->sumUpArea( a_area ); b->sumUpArea( b_area ); return std::abs( a_area ) > std::abs( b_area ); } );
424 result->reserve( curves.size() );
425 while ( !curves.isEmpty() )
427 QgsCompoundCurve *exterior = curves.takeFirst();
428 QgsCurvePolygon *newPolygon =
new QgsCurvePolygon();
431 engine->prepareGeometry();
433 QMutableListIterator< QgsCompoundCurve * > it( curves );
434 while ( it.hasNext() )
436 QgsCompoundCurve *curve = it.next();
437 QgsRectangle boundingBox = newPolygon->
boundingBox();
441 if ( engine->contains( &point ) )
446 engine->prepareGeometry();
450 result->addGeometry( newPolygon );
452 if ( result->numGeometries() == 0 )
458std::unique_ptr< QgsPolygon > QgsArcGisRestUtils::convertEnvelope(
const QVariantMap &geometryData )
461 bool xminOk =
false, yminOk =
false, xmaxOk =
false, ymaxOk =
false;
462 double xmin = geometryData[u
"xmin"_s].toDouble( &xminOk );
463 double ymin = geometryData[u
"ymin"_s].toDouble( &yminOk );
464 double xmax = geometryData[u
"xmax"_s].toDouble( &xmaxOk );
465 double ymax = geometryData[u
"ymax"_s].toDouble( &ymaxOk );
466 if ( !xminOk || !yminOk || !xmaxOk || !ymaxOk )
468 auto ext = std::make_unique< QgsLineString> ();
469 ext->addVertex( QgsPoint( xmin, ymin ) );
470 ext->addVertex( QgsPoint( xmax, ymin ) );
471 ext->addVertex( QgsPoint( xmax, ymax ) );
472 ext->addVertex( QgsPoint( xmin, ymax ) );
473 ext->addVertex( QgsPoint( xmin, ymin ) );
474 auto poly = std::make_unique< QgsPolygon >();
475 poly->setExteriorRing( ext.release() );
488 if ( esriGeometryType ==
"esriGeometryNull"_L1 )
490 else if ( esriGeometryType ==
"esriGeometryPoint"_L1 )
491 return convertGeometryPoint( geometryData, pointType ).release();
492 else if ( esriGeometryType ==
"esriGeometryMultipoint"_L1 )
493 return convertMultiPoint( geometryData, pointType ).release();
494 else if ( esriGeometryType ==
"esriGeometryPolyline"_L1 )
495 return convertGeometryPolyline( geometryData, pointType ).release();
496 else if ( esriGeometryType ==
"esriGeometryPolygon"_L1 )
497 return convertGeometryPolygon( geometryData, pointType ).release();
498 else if ( esriGeometryType ==
"esriGeometryEnvelope"_L1 )
499 return convertEnvelope( geometryData ).release();
522 QString spatialReference = spatialReferenceMap[u
"latestWkid"_s].toString();
523 if ( spatialReference.isEmpty() )
524 spatialReference = spatialReferenceMap[u
"wkid"_s].toString();
527 if ( !spatialReference.isEmpty() )
536 else if ( !spatialReferenceMap[u
"wkt"_s].toString().isEmpty() )
539 crs.
createFromWkt( spatialReferenceMap[u
"wkt"_s].toString() );
554 const QString type = symbolData.value( u
"type"_s ).toString();
555 if ( type ==
"esriSMS"_L1 )
558 return parseEsriMarkerSymbolJson( symbolData ).release();
560 else if ( type ==
"esriSLS"_L1 )
563 return parseEsriLineSymbolJson( symbolData ).release();
565 else if ( type ==
"esriSFS"_L1 )
568 return parseEsriFillSymbolJson( symbolData ).release();
570 else if ( type ==
"esriPFS"_L1 )
572 return parseEsriPictureFillSymbolJson( symbolData ).release();
574 else if ( type ==
"esriPMS"_L1 )
577 return parseEsriPictureMarkerSymbolJson( symbolData ).release();
579 else if ( type ==
"esriTS"_L1 )
581 return parseEsriTextMarkerSymbolJson( symbolData ).release();
586std::unique_ptr<QgsLineSymbol> QgsArcGisRestUtils::parseEsriLineSymbolJson(
const QVariantMap &symbolData )
588 QColor lineColor =
convertColor( symbolData.value( u
"color"_s ) );
589 if ( !lineColor.isValid() )
593 double widthInPoints = symbolData.value( u
"width"_s ).toDouble( &ok );
598 Qt::PenStyle penStyle =
convertLineStyle( symbolData.value( u
"style"_s ).toString() );
599 auto lineLayer = std::make_unique< QgsSimpleLineSymbolLayer >( lineColor, widthInPoints, penStyle );
601 layers.append( lineLayer.release() );
603 auto symbol = std::make_unique< QgsLineSymbol >( layers );
607std::unique_ptr<QgsFillSymbol> QgsArcGisRestUtils::parseEsriFillSymbolJson(
const QVariantMap &symbolData )
609 QColor fillColor =
convertColor( symbolData.value( u
"color"_s ) );
610 Qt::BrushStyle brushStyle =
convertFillStyle( symbolData.value( u
"style"_s ).toString() );
612 const QVariantMap outlineData = symbolData.value( u
"outline"_s ).toMap();
613 QColor lineColor =
convertColor( outlineData.value( u
"color"_s ) );
614 Qt::PenStyle penStyle =
convertLineStyle( outlineData.value( u
"style"_s ).toString() );
616 double penWidthInPoints = outlineData.value( u
"width"_s ).toDouble( &ok );
619 auto fillLayer = std::make_unique< QgsSimpleFillSymbolLayer >( fillColor, brushStyle, lineColor, penStyle, penWidthInPoints );
621 layers.append( fillLayer.release() );
623 auto symbol = std::make_unique< QgsFillSymbol >( layers );
627std::unique_ptr<QgsFillSymbol> QgsArcGisRestUtils::parseEsriPictureFillSymbolJson(
const QVariantMap &symbolData )
631 double widthInPixels = symbolData.value( u
"width"_s ).toInt( &ok );
635 const double xScale = symbolData.value( u
"xscale"_s ).toDouble( &ok );
637 widthInPixels *= xScale;
639 const double angleCCW = symbolData.value( u
"angle"_s ).toDouble( &ok );
644 const double xOffset = symbolData.value( u
"xoffset"_s ).toDouble();
645 const double yOffset = symbolData.value( u
"yoffset"_s ).toDouble();
647 QString symbolPath( symbolData.value( u
"imageData"_s ).toString() );
648 symbolPath.prepend(
"base64:"_L1 );
651 auto fillLayer = std::make_unique< QgsRasterFillSymbolLayer >( symbolPath );
652 fillLayer->setWidth( widthInPixels );
653 fillLayer->setAngle( angleCW );
655 fillLayer->setOffset( QPointF( xOffset, yOffset ) );
657 layers.append( fillLayer.release() );
659 const QVariantMap outlineData = symbolData.value( u
"outline"_s ).toMap();
660 QColor lineColor =
convertColor( outlineData.value( u
"color"_s ) );
661 Qt::PenStyle penStyle =
convertLineStyle( outlineData.value( u
"style"_s ).toString() );
662 double penWidthInPoints = outlineData.value( u
"width"_s ).toDouble( &ok );
664 auto lineLayer = std::make_unique< QgsSimpleLineSymbolLayer >( lineColor, penWidthInPoints, penStyle );
666 layers.append( lineLayer.release() );
668 auto symbol = std::make_unique< QgsFillSymbol >( layers );
672Qgis::MarkerShape QgsArcGisRestUtils::parseEsriMarkerShape(
const QString &style )
674 if ( style ==
"esriSMSCircle"_L1 )
676 else if ( style ==
"esriSMSCross"_L1 )
678 else if ( style ==
"esriSMSDiamond"_L1 )
680 else if ( style ==
"esriSMSSquare"_L1 )
682 else if ( style ==
"esriSMSX"_L1 )
684 else if ( style ==
"esriSMSTriangle"_L1 )
690std::unique_ptr<QgsMarkerSymbol> QgsArcGisRestUtils::parseEsriMarkerSymbolJson(
const QVariantMap &symbolData )
692 QColor fillColor =
convertColor( symbolData.value( u
"color"_s ) );
694 const double sizeInPoints = symbolData.value( u
"size"_s ).toDouble( &ok );
697 const double angleCCW = symbolData.value( u
"angle"_s ).toDouble( &ok );
702 Qgis::MarkerShape shape = parseEsriMarkerShape( symbolData.value( u
"style"_s ).toString() );
704 const double xOffset = symbolData.value( u
"xoffset"_s ).toDouble();
705 const double yOffset = symbolData.value( u
"yoffset"_s ).toDouble();
707 const QVariantMap outlineData = symbolData.value( u
"outline"_s ).toMap();
708 QColor lineColor =
convertColor( outlineData.value( u
"color"_s ) );
709 Qt::PenStyle penStyle =
convertLineStyle( outlineData.value( u
"style"_s ).toString() );
710 double penWidthInPoints = outlineData.value( u
"width"_s ).toDouble( &ok );
713 auto markerLayer = std::make_unique< QgsSimpleMarkerSymbolLayer >( shape, sizeInPoints, angleCW,
Qgis::ScaleMethod::ScaleArea, fillColor, lineColor );
716 markerLayer->setStrokeStyle( penStyle );
717 markerLayer->setStrokeWidth( penWidthInPoints );
718 markerLayer->setOffset( QPointF( xOffset, yOffset ) );
720 layers.append( markerLayer.release() );
722 auto symbol = std::make_unique< QgsMarkerSymbol >( layers );
726std::unique_ptr<QgsMarkerSymbol> QgsArcGisRestUtils::parseEsriPictureMarkerSymbolJson(
const QVariantMap &symbolData )
729 const double widthInPixels = symbolData.value( u
"width"_s ).toInt( &ok );
732 const double heightInPixels = symbolData.value( u
"height"_s ).toInt( &ok );
736 const double angleCCW = symbolData.value( u
"angle"_s ).toDouble( &ok );
741 const double xOffset = symbolData.value( u
"xoffset"_s ).toDouble();
742 const double yOffset = symbolData.value( u
"yoffset"_s ).toDouble();
746 QString symbolPath( symbolData.value( u
"imageData"_s ).toString() );
747 symbolPath.prepend(
"base64:"_L1 );
754 if ( !
qgsDoubleNear(
static_cast< double >( heightInPixels ) / widthInPixels, markerLayer->defaultAspectRatio() ) )
755 markerLayer->setFixedAspectRatio(
static_cast< double >( heightInPixels ) / widthInPixels );
757 markerLayer->setOffset( QPointF( xOffset, yOffset ) );
759 layers.append( markerLayer.release() );
761 auto symbol = std::make_unique< QgsMarkerSymbol >( layers );
765std::unique_ptr<QgsMarkerSymbol> QgsArcGisRestUtils::parseEsriTextMarkerSymbolJson(
const QVariantMap &symbolData )
769 const QString fontFamily = symbolData.value( u
"font"_s ).toMap().value( u
"family"_s ).toString();
771 const QString chr = symbolData.value( u
"text"_s ).toString();
773 const double pointSize = symbolData.value( u
"font"_s ).toMap().value( u
"size"_s ).toDouble();
775 const QColor color =
convertColor( symbolData.value( u
"color"_s ) );
777 const double esriAngle = symbolData.value( u
"angle"_s ).toDouble();
779 const double angle = 90.0 - esriAngle;
781 auto markerLayer = std::make_unique< QgsFontMarkerSymbolLayer >( fontFamily, chr, pointSize, color, angle );
783 QColor strokeColor =
convertColor( symbolData.value( u
"borderLineColor"_s ) );
784 markerLayer->setStrokeColor( strokeColor );
786 double borderLineSize = symbolData.value( u
"borderLineSize"_s ).toDouble();
787 markerLayer->setStrokeWidth( borderLineSize );
789 const QString fontStyle = symbolData.value( u
"font"_s ).toMap().value( u
"style"_s ).toString();
790 markerLayer->setFontStyle( fontStyle );
792 double xOffset = symbolData.value( u
"xoffset"_s ).toDouble();
793 double yOffset = symbolData.value( u
"yoffset"_s ).toDouble();
795 markerLayer->setOffset( QPointF( xOffset, yOffset ) );
804 QString horizontalAnchorPoint = symbolData.value( u
"horizontalAlignment"_s ).toString();
805 QString verticalAnchorPoint = symbolData.value( u
"verticalAlignment"_s ).toString();
807 if ( horizontalAnchorPoint == QString(
"center" ) )
811 else if ( horizontalAnchorPoint == QString(
"left" ) )
815 else if ( horizontalAnchorPoint == QString(
"right" ) )
820 if ( verticalAnchorPoint == QString(
"center" ) )
824 else if ( verticalAnchorPoint == QString(
"top" ) )
828 else if ( verticalAnchorPoint == QString(
"bottom" ) )
833 markerLayer->setHorizontalAnchorPoint( hAlign );
834 markerLayer->setVerticalAnchorPoint( vAlign );
836 layers.append( markerLayer.release() );
838 auto symbol = std::make_unique< QgsMarkerSymbol >( layers );
844 if ( labelingData.empty() )
851 for (
const QVariant &lbl : labelingData )
853 const QVariantMap labeling = lbl.toMap();
858 const QString placement = labeling.value( u
"labelPlacement"_s ).toString();
859 if ( placement ==
"esriServerPointLabelPlacementAboveCenter"_L1 )
864 else if ( placement ==
"esriServerPointLabelPlacementBelowCenter"_L1 )
869 else if ( placement ==
"esriServerPointLabelPlacementCenterCenter"_L1 )
874 else if ( placement ==
"esriServerPointLabelPlacementAboveLeft"_L1 )
879 else if ( placement ==
"esriServerPointLabelPlacementBelowLeft"_L1 )
884 else if ( placement ==
"esriServerPointLabelPlacementCenterLeft"_L1 )
889 else if ( placement ==
"esriServerPointLabelPlacementAboveRight"_L1 )
894 else if ( placement ==
"esriServerPointLabelPlacementBelowRight"_L1 )
899 else if ( placement ==
"esriServerPointLabelPlacementCenterRight"_L1 )
904 else if ( placement ==
"esriServerLinePlacementAboveAfter"_L1 ||
905 placement ==
"esriServerLinePlacementAboveStart"_L1 ||
906 placement ==
"esriServerLinePlacementAboveAlong"_L1 )
911 else if ( placement ==
"esriServerLinePlacementBelowAfter"_L1 ||
912 placement ==
"esriServerLinePlacementBelowStart"_L1 ||
913 placement ==
"esriServerLinePlacementBelowAlong"_L1 )
918 else if ( placement ==
"esriServerLinePlacementCenterAfter"_L1 ||
919 placement ==
"esriServerLinePlacementCenterStart"_L1 ||
920 placement ==
"esriServerLinePlacementCenterAlong"_L1 )
925 else if ( placement ==
"esriServerPolygonPlacementAlwaysHorizontal"_L1 )
930 const double minScale = labeling.value( u
"minScale"_s ).toDouble();
931 const double maxScale = labeling.value( u
"maxScale"_s ).toDouble();
933 QVariantMap symbol = labeling.value( u
"symbol"_s ).toMap();
935 const double haloSize = symbol.value( u
"haloSize"_s ).toDouble();
946 const QString fontFamily = symbol.value( u
"font"_s ).toMap().value( u
"family"_s ).toString();
947 const QString fontStyle = symbol.value( u
"font"_s ).toMap().value( u
"style"_s ).toString();
948 const QString fontWeight = symbol.value( u
"font"_s ).toMap().value( u
"weight"_s ).toString();
949 const int fontSize = symbol.value( u
"font"_s ).toMap().value( u
"size"_s ).toInt();
950 QFont font( fontFamily, fontSize );
951 font.setStyleName( fontStyle );
952 font.setWeight( fontWeight ==
"bold"_L1 ? QFont::Bold : QFont::Normal );
960 QString where = labeling.value( u
"where"_s ).toString();
979 const QString type = rendererData.value( u
"type"_s ).toString();
980 if ( type ==
"simple"_L1 )
982 const QVariantMap symbolProps = rendererData.value( u
"symbol"_s ).toMap();
983 std::unique_ptr< QgsSymbol > symbol(
convertSymbol( symbolProps ) );
989 else if ( type ==
"uniqueValue"_L1 )
991 const QString field1 = rendererData.value( u
"field1"_s ).toString();
992 const QString field2 = rendererData.value( u
"field2"_s ).toString();
993 const QString field3 = rendererData.value( u
"field3"_s ).toString();
995 if ( !field2.isEmpty() || !field3.isEmpty() )
997 const QString delimiter = rendererData.value( u
"fieldDelimiter"_s ).toString();
998 if ( !field3.isEmpty() )
1000 attribute = u
"concat(\"%1\",'%2',\"%3\",'%4',\"%5\")"_s.arg( field1, delimiter, field2, delimiter, field3 );
1004 attribute = u
"concat(\"%1\",'%2',\"%3\")"_s.arg( field1, delimiter, field2 );
1012 const QVariantList categories = rendererData.value( u
"uniqueValueInfos"_s ).toList();
1014 for (
const QVariant &category : categories )
1016 const QVariantMap categoryData = category.toMap();
1017 const QString value = categoryData.value( u
"value"_s ).toString();
1018 const QString label = categoryData.value( u
"label"_s ).toString();
1026 std::unique_ptr< QgsSymbol > defaultSymbol(
convertSymbol( rendererData.value( u
"defaultSymbol"_s ).toMap() ) );
1027 if ( defaultSymbol )
1029 categoryList.append(
QgsRendererCategory( QVariant(), defaultSymbol.release(), rendererData.value( u
"defaultLabel"_s ).toString() ) );
1032 if ( categoryList.empty() )
1037 else if ( type ==
"classBreaks"_L1 )
1039 const QString attrName = rendererData.value( u
"field"_s ).toString();
1041 const QVariantList classBreakInfos = rendererData.value( u
"classBreakInfos"_s ).toList();
1042 const QVariantMap authoringInfo = rendererData.value( u
"authoringInfo"_s ).toMap();
1043 QVariantMap symbolData;
1045 QString esriMode = authoringInfo.value( u
"classificationMethod"_s ).toString();
1046 if ( esriMode.isEmpty() )
1048 esriMode = rendererData.value( u
"classificationMethod"_s ).toString();
1051 if ( !classBreakInfos.isEmpty() )
1053 symbolData = classBreakInfos.at( 0 ).toMap().value( u
"symbol"_s ).toMap();
1059 const double transparency = rendererData.value( u
"transparency"_s ).toDouble();
1060 const double opacity = ( 100.0 - transparency ) / 100.0;
1061 symbol->setOpacity( opacity );
1063 const QVariantList visualVariablesData = rendererData.value( u
"visualVariables"_s ).toList();
1065 for (
const QVariant &visualVariable : visualVariablesData )
1067 const QVariantMap visualVariableData = visualVariable.toMap();
1068 const QString variableType = visualVariableData.value( u
"type"_s ).toString();
1069 if ( variableType ==
"sizeInfo"_L1 )
1073 else if ( variableType ==
"colorInfo"_L1 )
1075 const QVariantList stops = visualVariableData.value( u
"stops"_s ).toList();
1076 if ( stops.size() < 2 )
1081 const double minValue = stops.front().toMap().value( u
"value"_s ).toDouble( &ok );
1084 const QColor minColor =
convertColor( stops.front().toMap().value( u
"color"_s ) );
1086 const double maxValue = stops.back().toMap().value( u
"value"_s ).toDouble( &ok );
1089 const QColor maxColor =
convertColor( stops.back().toMap().value( u
"color"_s ) );
1092 for (
int i = 1; i < stops.size() - 1; ++i )
1094 const QVariantMap stopData = stops.at( i ).toMap();
1095 const double breakpoint = stopData.value( u
"value"_s ).toDouble();
1096 const double scaledBreakpoint = ( breakpoint - minValue ) / ( maxValue - minValue );
1097 const QColor fillColor =
convertColor( stopData.value( u
"color"_s ) );
1099 gradientStops.append(
QgsGradientStop( scaledBreakpoint, fillColor ) );
1102 auto colorRamp = std::make_unique< QgsGradientColorRamp >(
1103 minColor, maxColor,
false, gradientStops
1110 for (
int layer = 0; layer < symbol->symbolLayerCount(); ++layer )
1115 auto singleSymbolRenderer = std::make_unique< QgsSingleSymbolRenderer >( symbol.release() );
1117 return singleSymbolRenderer.release();
1121 QgsDebugError( u
"ESRI visualVariable type %1 is not currently supported"_s.arg( variableType ) );
1125 double lastValue = rendererData.value( u
"minValue"_s ).toDouble();
1127 auto graduatedRenderer = std::make_unique< QgsGraduatedSymbolRenderer >( attrName );
1129 graduatedRenderer->setSourceSymbol( symbol.release() );
1131 if ( esriMode ==
"esriClassifyDefinedInterval"_L1 )
1134 graduatedRenderer->setClassificationMethod( method );
1136 else if ( esriMode ==
"esriClassifyEqualInterval"_L1 )
1139 graduatedRenderer->setClassificationMethod( method );
1141 else if ( esriMode ==
"esriClassifyGeometricalInterval"_L1 )
1144 graduatedRenderer->setClassificationMethod( method );
1146 else if ( esriMode ==
"esriClassifyManual"_L1 )
1149 graduatedRenderer->setClassificationMethod( method );
1151 else if ( esriMode ==
"esriClassifyNaturalBreaks"_L1 )
1154 graduatedRenderer->setClassificationMethod( method );
1156 else if ( esriMode ==
"esriClassifyQuantile"_L1 )
1159 graduatedRenderer->setClassificationMethod( method );
1161 else if ( esriMode ==
"esriClassifyStandardDeviation"_L1 )
1164 graduatedRenderer->setClassificationMethod( method );
1166 else if ( !esriMode.isEmpty() )
1168 QgsDebugError( u
"ESRI classification mode %1 is not currently supported"_s.arg( esriMode ) );
1171 for (
const QVariant &classBreakInfo : classBreakInfos )
1173 const QVariantMap symbolData = classBreakInfo.toMap().value( u
"symbol"_s ).toMap();
1175 double classMaxValue = classBreakInfo.toMap().value( u
"classMaxValue"_s ).toDouble();
1176 const QString label = classBreakInfo.toMap().value( u
"label"_s ).toString();
1185 lastValue = classMaxValue;
1186 graduatedRenderer->addClass( range );
1189 return graduatedRenderer.release();
1191 else if ( type ==
"heatmap"_L1 )
1196 else if ( type ==
"vectorField"_L1 )
1206 QString expression = string;
1209 const thread_local QRegularExpression rx1 = QRegularExpression( u
"(?=([^\"\\\\]*(\\\\.|\"([^\"\\\\]*\\\\.)*[^\"\\\\]*\"))*[^\"]*$)(\\s|^)CONCAT(\\s|$)"_s );
1210 expression = expression.replace( rx1, u
"\\4||\\5"_s );
1212 const thread_local QRegularExpression rx2 = QRegularExpression( u
"(?=([^\"\\\\]*(\\\\.|\"([^\"\\\\]*\\\\.)*[^\"\\\\]*\"))*[^\"]*$)(\\s|^)NEWLINE(\\s|$)"_s );
1213 expression = expression.replace( rx2, u
"\\4'\\n'\\5"_s );
1216 const thread_local QRegularExpression rx3 = QRegularExpression( u
"\"(.*?(?<!\\\\))\""_s );
1217 expression = expression.replace( rx3, u
"'\\1'"_s );
1218 const thread_local QRegularExpression rx4 = QRegularExpression( u
"\\\\\""_s );
1219 expression = expression.replace( rx4, u
"\""_s );
1222 const thread_local QRegularExpression rx5 = QRegularExpression( u
"\\[([^]]*)\\]"_s );
1223 expression = expression.replace( rx5, u
"\"\\1\""_s );
1230 const QVariantList colorParts = colorData.toList();
1231 if ( colorParts.count() < 4 )
1234 int red = colorParts.at( 0 ).toInt();
1235 int green = colorParts.at( 1 ).toInt();
1236 int blue = colorParts.at( 2 ).toInt();
1237 int alpha = colorParts.at( 3 ).toInt();
1238 return QColor( red, green, blue, alpha );
1243 if ( style ==
"esriSLSSolid"_L1 )
1244 return Qt::SolidLine;
1245 else if ( style ==
"esriSLSDash"_L1 )
1246 return Qt::DashLine;
1247 else if ( style ==
"esriSLSDashDot"_L1 )
1248 return Qt::DashDotLine;
1249 else if ( style ==
"esriSLSDashDotDot"_L1 )
1250 return Qt::DashDotDotLine;
1251 else if ( style ==
"esriSLSDot"_L1 )
1253 else if ( style ==
"esriSLSNull"_L1 )
1256 return Qt::SolidLine;
1261 if ( style ==
"esriSFSBackwardDiagonal"_L1 )
1262 return Qt::BDiagPattern;
1263 else if ( style ==
"esriSFSCross"_L1 )
1264 return Qt::CrossPattern;
1265 else if ( style ==
"esriSFSDiagonalCross"_L1 )
1266 return Qt::DiagCrossPattern;
1267 else if ( style ==
"esriSFSForwardDiagonal"_L1 )
1268 return Qt::FDiagPattern;
1269 else if ( style ==
"esriSFSHorizontal"_L1 )
1270 return Qt::HorPattern;
1271 else if ( style ==
"esriSFSNull"_L1 )
1273 else if ( style ==
"esriSFSSolid"_L1 )
1274 return Qt::SolidPattern;
1275 else if ( style ==
"esriSFSVertical"_L1 )
1276 return Qt::VerPattern;
1278 return Qt::SolidPattern;
1286 QDateTime dt = QDateTime::fromMSecsSinceEpoch( value.toLongLong( &ok ) );
1289 QgsDebugError( u
"Invalid value %1 for datetime"_s.arg( value.toString() ) );
1301 const QVariantMap coords = value.toMap();
1306 const double xmin = coords.value( u
"xmin"_s ).toDouble( &ok );
1309 const double ymin = coords.value( u
"ymin"_s ).toDouble( &ok );
1312 const double xmax = coords.value( u
"xmax"_s ).toDouble( &ok );
1315 const double ymax = coords.value( u
"ymax"_s ).toDouble( &ok );
1327 return QVariantMap();
1334 return QVariantMap();
1378 return QVariantMap();
1381 return QVariantMap();
1384 return QVariantMap();
1391 res.insert( u
"spatialReference"_s,
crsToJson( crs ) );
1397QVariantMap QgsArcGisRestUtils::pointToJson(
const QgsPoint *point )
1401 data[u
"x"_s] = u
"NaN"_s;
1404 data[u
"x"_s] = point->
x();
1405 data[u
"y"_s] = point->
y();
1407 if ( point->
is3D() )
1408 data[u
"z"_s] = !std::isnan( point->
z() ) ? QVariant( point->
z() ) : QVariant( u
"NaN"_s );
1411 data[u
"m"_s] = !std::isnan( point->
m() ) ? QVariant( point->
m() ) : QVariant( u
"NaN"_s );
1416QVariantMap QgsArcGisRestUtils::multiPointToJson(
const QgsMultiPoint *multiPoint )
1419 const bool hasZ = multiPoint->
is3D();
1420 const bool hasM = multiPoint->
isMeasure();
1421 data[u
"hasM"_s] = hasM;
1422 data[u
"hasZ"_s] = hasZ;
1424 QVariantList pointsList;
1426 pointsList.reserve( size );
1428 QVariantList pointList;
1429 for (
int i = 0; i < size; ++i )
1431 const QgsPoint *point = multiPoint->
pointN( i );
1434 pointList.append( point->
x() );
1435 pointList.append( point->
y() );
1437 pointList.append( point->
z() );
1438 if ( hasM && !std::isnan( point->
m() ) )
1439 pointList.append( point->
m() );
1441 pointsList.push_back( pointList );
1444 data[u
"points"_s] = pointsList;
1448QVariantList QgsArcGisRestUtils::lineStringToJsonPath(
const QgsLineString *line )
1450 const bool hasZ = line->
is3D();
1453 QVariantList pointsList;
1455 pointsList.reserve( size );
1457 QVariantList pointList;
1458 const double *xData = line->
xData();
1459 const double *yData = line->
yData();
1460 const double *zData = hasZ ? line->
zData() :
nullptr;
1461 const double *mData = hasM ? line->
mData() :
nullptr;
1463 for (
int i = 0; i < size; ++i )
1466 pointList.append( *xData++ );
1467 pointList.append( *yData++ );
1470 pointList.append( *zData++ );
1472 if ( hasM && !std::isnan( *mData ) )
1473 pointList.append( *mData );
1477 pointsList.push_back( pointList );
1482QVariantList QgsArcGisRestUtils::curveToJsonCurve(
const QgsCurve *curve,
bool includeStart )
1484 const bool hasZ = curve->
is3D();
1487 auto pointToList = [hasZ, hasM](
const QgsPoint & point ) -> QVariantList
1489 QVariantList pointList;
1491 pointList.append( point.
x() );
1492 pointList.append( point.
y() );
1495 pointList.append( point.
z() );
1497 if ( hasM && !std::isnan( point.
m() ) )
1498 pointList.append( point.
m() );
1509 if ( !part.isEmpty() && !includeStart )
1518 if ( includeStart && !circularString->
isEmpty() )
1520 res.push_back( pointToList( circularString->
startPoint() ) );
1523 const int size = circularString->
numPoints();
1524 for (
int i = 1; i + 1 < size; i += 2 )
1527 QVariantMap curvePart;
1528 QVariantList curveList;
1529 curveList.push_back( pointToList( circularString->
pointN( i + 1 ) ) );
1531 curveList.push_back( pointToList( circularString->
pointN( i ) ) );
1533 curvePart.insert( u
"c"_s, curveList );
1534 res.push_back( curvePart );
1543 const int size = compoundCurve->
nCurves();
1544 for (
int i = 0; i < size; ++i )
1546 const QgsCurve *subCurve = compoundCurve->
curveAt( i );
1547 res.append( curveToJsonCurve( subCurve, i == 0 ) );
1558QVariantMap QgsArcGisRestUtils::lineStringToJson(
const QgsLineString *line )
1561 const bool hasZ = line->
is3D();
1563 data[u
"hasM"_s] = hasM;
1564 data[u
"hasZ"_s] = hasZ;
1566 const QVariantList pointsList = lineStringToJsonPath( line );
1568 QVariantList pointsData = QVariantList();
1569 pointsData.push_back( pointsList );
1570 data[u
"paths"_s] = pointsData;
1575QVariantMap QgsArcGisRestUtils::curveToJson(
const QgsCurve *curve )
1578 const bool hasZ = curve->
is3D();
1580 data[u
"hasM"_s] = hasM;
1581 data[u
"hasZ"_s] = hasZ;
1583 const QVariantList curveList = curveToJsonCurve( curve,
true );
1585 QVariantList curveData = QVariantList();
1586 curveData.push_back( curveList );
1587 data[u
"curvePaths"_s] = curveData;
1592QVariantMap QgsArcGisRestUtils::multiLineStringToJson(
const QgsMultiLineString *multiLine )
1595 const bool hasZ = multiLine->
is3D();
1596 const bool hasM = multiLine->
isMeasure();
1597 data[u
"hasM"_s] = hasM;
1598 data[u
"hasZ"_s] = hasZ;
1602 paths.reserve( size );
1603 for (
int i = 0; i < size; ++i )
1605 const QgsLineString *line = multiLine->
lineStringN( i );
1606 paths.push_back( lineStringToJsonPath( line ) );
1609 data[u
"paths"_s] = paths;
1613QVariantMap QgsArcGisRestUtils::multiCurveToJson(
const QgsMultiCurve *multiCurve )
1616 const bool hasZ = multiCurve->
is3D();
1617 const bool hasM = multiCurve->
isMeasure();
1618 data[u
"hasM"_s] = hasM;
1619 data[u
"hasZ"_s] = hasZ;
1623 paths.reserve( size );
1624 for (
int i = 0; i < size; ++i )
1626 const QgsCurve *curve = multiCurve->
curveN( i );
1627 paths.push_back( curveToJsonCurve( curve,
true ) );
1630 data[u
"curvePaths"_s] = paths;
1634QVariantList QgsArcGisRestUtils::polygonToJsonRings(
const QgsPolygon *polygon )
1638 rings.reserve( numInteriorRings + 1 );
1646 rings.push_back( lineStringToJsonPath( exterior ) );
1651 std::unique_ptr< QgsLineString > reversed( exterior->
reversed() );
1652 rings.push_back( lineStringToJsonPath( reversed.get() ) );
1660 for (
int i = 0; i < numInteriorRings; ++i )
1667 rings.push_back( lineStringToJsonPath( ring ) );
1672 std::unique_ptr< QgsLineString > reversed( ring->
reversed() );
1673 rings.push_back( lineStringToJsonPath( reversed.get() ) );
1683QVariantList QgsArcGisRestUtils::curvePolygonToJsonRings(
const QgsCurvePolygon *polygon )
1687 rings.reserve( numInteriorRings + 1 );
1695 rings.push_back( curveToJsonCurve( exterior,
true ) );
1700 std::unique_ptr< QgsCurve > reversed( exterior->
reversed() );
1701 rings.push_back( curveToJsonCurve( reversed.get(),
true ) );
1709 for (
int i = 0; i < numInteriorRings; ++i )
1716 rings.push_back( curveToJsonCurve( ring,
true ) );
1721 std::unique_ptr< QgsCurve > reversed( ring->
reversed() );
1722 rings.push_back( curveToJsonCurve( reversed.get(),
true ) );
1732QVariantMap QgsArcGisRestUtils::polygonToJson(
const QgsPolygon *polygon )
1735 const bool hasZ = polygon->
is3D();
1737 data[u
"hasM"_s] = hasM;
1738 data[u
"hasZ"_s] = hasZ;
1739 data[u
"rings"_s] = polygonToJsonRings( polygon );
1743QVariantMap QgsArcGisRestUtils::curvePolygonToJson(
const QgsCurvePolygon *polygon )
1746 const bool hasZ = polygon->
is3D();
1748 data[u
"hasM"_s] = hasM;
1749 data[u
"hasZ"_s] = hasZ;
1750 data[u
"curveRings"_s] = curvePolygonToJsonRings( polygon );
1754QVariantMap QgsArcGisRestUtils::multiPolygonToJson(
const QgsMultiPolygon *multiPolygon )
1757 const bool hasZ = multiPolygon->
is3D();
1758 const bool hasM = multiPolygon->
isMeasure();
1759 data[u
"hasM"_s] = hasM;
1760 data[u
"hasZ"_s] = hasZ;
1764 for (
int i = 0; i < size; ++i )
1766 const QgsPolygon *polygon = multiPolygon->
polygonN( i );
1767 rings.append( polygonToJsonRings( polygon ) );
1770 data[u
"rings"_s] = rings;
1774QVariantMap QgsArcGisRestUtils::multiSurfaceToJson(
const QgsMultiSurface *multiSurface )
1777 const bool hasZ = multiSurface->
is3D();
1778 const bool hasM = multiSurface->
isMeasure();
1779 data[u
"hasM"_s] = hasM;
1780 data[u
"hasZ"_s] = hasZ;
1784 for (
int i = 0; i < size; ++i )
1790 rings.append( curvePolygonToJsonRings( polygon ) );
1793 data[u
"curveRings"_s] = rings;
1803 const QString authid = crs.
authid();
1804 if ( !authid.isEmpty() )
1806 const thread_local QRegularExpression rxAuthid( u
"(\\w+):(\\d+)"_s );
1807 const QRegularExpressionMatch match = rxAuthid.match( authid );
1808 if ( match.hasMatch()
1810 ( match.captured( 1 ).compare(
"EPSG"_L1, Qt::CaseInsensitive ) == 0 )
1811 || ( match.captured( 1 ).compare(
"ESRI"_L1, Qt::CaseInsensitive ) == 0 )
1815 const QString wkid = match.captured( 2 );
1816 res.insert( u
"wkid"_s, wkid );
1835 QVariantMap attributes;
1837 for (
const QgsField &field : fields )
1839 QVariant value = feature.
attribute( field.name() );
1840 if ( value.userType() == qMetaTypeId< QgsUnsetAttributeValue >() )
1851 if ( !attributes.isEmpty() )
1853 res.insert( u
"attributes"_s, attributes );
1863 switch ( expectedType )
1865 case QMetaType::Type::QString:
1867 const QString escaped = variant.toString().replace(
'\\',
"\\\\"_L1 ).replace(
'"',
"\\\""_L1 );
1868 return QString( QUrl::toPercentEncoding( escaped,
"'" ) );
1871 case QMetaType::Type::QDateTime:
1872 case QMetaType::Type::QDate:
1874 switch ( variant.userType() )
1876 case QMetaType::Type::QDateTime:
1877 return variant.toDateTime().toMSecsSinceEpoch();
1879 case QMetaType::Type::QDate:
1881 if ( context.
timeZone().isValid() )
1882 return QDateTime( variant.toDate(), QTime( 0, 0, 0 ), context.
timeZone() ).toMSecsSinceEpoch();
1884 return QDateTime( variant.toDate(), QTime( 0, 0, 0 ) ).toMSecsSinceEpoch();
1899 res.insert( u
"name"_s, field.
name() );
1902 switch ( field.
type() )
1904 case QMetaType::Type::LongLong:
1905 fieldType = u
"esriFieldTypeInteger"_s;
1908 case QMetaType::Type::Int:
1909 fieldType = u
"esriFieldTypeSmallInteger"_s;
1912 case QMetaType::Type::Double:
1913 fieldType = u
"esriFieldTypeDouble"_s;
1916 case QMetaType::Type::QString:
1917 fieldType = u
"esriFieldTypeString"_s;
1920 case QMetaType::Type::QDateTime:
1921 case QMetaType::Type::QDate:
1922 fieldType = u
"esriFieldTypeDate"_s;
1925 case QMetaType::Type::QByteArray:
1926 fieldType = u
"esriFieldTypeBlob"_s;
1931 fieldType = u
"esriFieldTypeString"_s;
1934 res.insert( u
"type"_s, fieldType );
1936 if ( !field.
alias().isEmpty() )
1937 res.insert( u
"alias"_s, field.
alias() );
1941 res.insert( u
"nullable"_s, !notNullable );
1944 res.insert( u
"editable"_s,
true );
1951 if ( type.compare(
"FeatureServer"_L1, Qt::CaseInsensitive ) == 0 )
1953 else if ( type.compare(
"MapServer"_L1, Qt::CaseInsensitive ) == 0 )
1955 else if ( type.compare(
"ImageServer"_L1, Qt::CaseInsensitive ) == 0 )
1957 else if ( type.compare(
"GlobeServer"_L1, Qt::CaseInsensitive ) == 0 )
1959 else if ( type.compare(
"GPServer"_L1, Qt::CaseInsensitive ) == 0 )
1961 else if ( type.compare(
"GeocodeServer"_L1, Qt::CaseInsensitive ) == 0 )
1963 else if ( type.compare(
"SceneServer"_L1, Qt::CaseInsensitive ) == 0 )
@ 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. Applies to polygon layers only...
@ ScaleArea
Calculate scale by the area.
ArcGisRestServiceType
Available ArcGIS REST service types.
@ GeocodeServer
GeocodeServer.
@ SceneServer
SceneServer.
@ Unknown
Other unknown/unsupported type.
@ GlobeServer
GlobeServer.
@ ImageServer
ImageServer.
@ FeatureServer
FeatureServer.
MarkerShape
Marker shapes.
@ Cross2
Rotated cross (lines only), 'x' shape.
@ Cross
Cross (lines only).
VerticalAnchorPoint
Marker symbol vertical anchor points.
@ Bottom
Align to bottom of symbol.
@ Center
Align to vertical center of symbol.
@ Top
Align to top of symbol.
@ Points
Points (e.g., for font sizes).
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.
HorizontalAnchorPoint
Marker symbol horizontal anchor points.
@ Center
Align to horizontal center of symbol.
@ Right
Align to right side of symbol.
@ Left
Align to left side of symbol.
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.
virtual QgsRectangle boundingBox() const
Returns the minimal bounding box for the geometry.
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.
Abstract base class - its implementations define different approaches to the labeling of a vector lay...
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 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 QgsSymbol * convertSymbol(const QVariantMap &definition)
Converts a symbol JSON definition to a QgsSymbol.
static QVariantMap geometryToJson(const QgsGeometry &geometry, const QgsArcGisRestContext &context, const QgsCoordinateReferenceSystem &crs=QgsCoordinateReferenceSystem())
Converts a geometry to an ArcGIS REST JSON representation.
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 QgsAbstractGeometry * convertGeometry(const QVariantMap &geometry, const QString &esriGeometryType, bool hasM, bool hasZ, QgsCoordinateReferenceSystem *crs=nullptr)
Converts an ESRI REST geometry JSON definition to a QgsAbstractGeometry.
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 QgsFeatureRenderer * convertRenderer(const QVariantMap &rendererData)
Converts renderer JSON data to an equivalent QgsFeatureRenderer.
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 QVariantMap crsToJson(const QgsCoordinateReferenceSystem &crs)
Converts a crs to an ArcGIS REST JSON representation.
QFlags< FeatureToJsonFlag > FeatureToJsonFlags
Flags which control the behavior of converting features to JSON.
static QgsAbstractVectorLayerLabeling * convertLabeling(const QVariantList &data)
Converts labeling JSON data to an equivalent QGIS vector labeling.
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 feature renderer which represents features using a list of renderer categories.
QgsPoint startPoint() const override
Returns the starting point of the curve.
bool isEmpty() const override
Returns true if the geometry is empty.
int numPoints() const override
Returns the number of points in the curve.
QgsPoint pointN(int i) const
Returns the point at index i within the circular string.
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.
QgsCompoundCurve * reversed() const override
Returns a reversed copy of the curve, where the direction of the curve has been flipped.
int nCurves() const
Returns the number of curves in the geometry.
const QgsCurve * curveAt(int i) const
Returns the curve at the specified index.
QgsPoint startPoint() const override
Returns the starting point of the curve.
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.
virtual void setExteriorRing(QgsCurve *ring)
Sets the exterior ring of the polygon.
virtual void addInteriorRing(QgsCurve *ring)
Adds an interior ring to the geometry (takes ownership).
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").
bool isValid() const
Checks if this expression is valid.
Abstract base class for all 2D vector feature renderers.
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.
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometry *geometry, double precision=0.0, Qgis::GeosCreationFlags flags=Qgis::GeosCreationFlag::SkipEmptyInteriorRings)
Creates and returns a new geometry engine representing the specified geometry using precision on a gr...
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.
const double * yData() const
Returns a const pointer to the y vertex data.
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 linestring does not have z values.
int numPoints() const override
Returns the number of points in the curve.
QgsLineString * reversed() const override
Returns a reversed copy of the curve, where the direction of the curve has been flipped.
const double * mData() const
Returns a const pointer to the m vertex data, or nullptr if the linestring does not have m values.
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.
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...
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 fromField(const QString &fieldName, bool isActive=true)
Returns a new FieldBasedProperty created from the specified field name.
A rectangle specified with double values.
bool intersects(const QgsRectangle &rect) const
Returns true when rectangle intersects with other rectangle.
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
Rule based labeling for a vector layer.
A feature renderer which renders all features with the same symbol.
Abstract base class for all rendered symbols.
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.
double ANALYSIS_EXPORT angle(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored).
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)
QList< QgsSymbolLayer * > QgsSymbolLayerList