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 const int nCoords =
static_cast< int >( 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 =
static_cast< int >( 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< QgsCurve > 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 const int maxCurveListSize =
static_cast< int >( 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 =
static_cast< int >( 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 )
242 = 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() );
244 std::unique_ptr< QgsCircularString > circularString( convertCircularString( curveData.toMap(), pointType, lastLineStringPoint ) );
245 if ( !circularString )
250 if ( actualLineSize > 0 )
252 lineX.resize( actualLineSize );
253 lineY.resize( actualLineSize );
255 lineZ.resize( actualLineSize );
257 lineM.resize( actualLineSize );
259 compoundCurve->addCurve(
new QgsLineString( lineX, lineY, lineZ, lineM ) );
260 lineX.resize( maxCurveListSize - curveListIndex );
261 lineY.resize( maxCurveListSize - curveListIndex );
263 lineZ.resize( maxCurveListSize - curveListIndex );
265 lineM.resize( maxCurveListSize - curveListIndex );
266 outLineX = lineX.data();
267 outLineY = lineY.data();
268 outLineZ = lineZ.data();
269 outLineM = lineM.data();
273 if ( compoundCurve->curveAt( compoundCurve->nCurves() - 1 )->nCoordinates() < 2 )
274 compoundCurve->removeCurve( compoundCurve->nCurves() - 1 );
276 const QgsPoint endPointCircularString = circularString->endPoint();
277 compoundCurve->addCurve( circularString.release() );
281 *outLineX++ = endPointCircularString.
x();
282 *outLineY++ = endPointCircularString.
y();
284 *outLineZ++ = endPointCircularString.
z();
286 *outLineM++ = endPointCircularString.
m();
291 if ( actualLineSize == 1 && compoundCurve->nCurves() > 0 )
293 const QgsCurve *finalCurve = compoundCurve->curveAt( compoundCurve->nCurves() - 1 );
294 const QgsPoint finalCurveEndPoint = finalCurve->
endPoint();
297 && ( !hasZ ||
qgsDoubleNear( finalCurveEndPoint.
z(), lineZ.at( 0 ) ) )
298 && ( !hasM ||
qgsDoubleNear( finalCurveEndPoint.
m(), lineM.at( 0 ) ) ) )
304 if ( actualLineSize > 0 )
306 lineX.resize( actualLineSize );
307 lineY.resize( actualLineSize );
309 lineZ.resize( actualLineSize );
311 lineM.resize( actualLineSize );
312 compoundCurve->addCurve(
new QgsLineString( lineX, lineY, lineZ, lineM ) );
315 return compoundCurve;
318std::unique_ptr<QgsLineString> QgsArcGisRestUtils::convertLineString(
const QVariantList &curvesList,
Qgis::WkbType pointType )
320 auto linestring = std::make_unique< QgsLineString >();
322 QVector< double > lineX;
323 QVector< double > lineY;
324 QVector< double > lineZ;
325 QVector< double > lineM;
326 const int maxCurveListSize =
static_cast< int >( curvesList.size() );
327 lineX.resize( maxCurveListSize );
328 lineY.resize( maxCurveListSize );
332 lineZ.resize( maxCurveListSize );
335 lineM.resize( maxCurveListSize );
337 double *outLineX = lineX.data();
338 double *outLineY = lineY.data();
339 double *outLineZ = lineZ.data();
340 double *outLineM = lineM.data();
345 int actualLineSize = 0;
346 for (
const QVariant &curveData : curvesList )
348 if ( curveData.userType() == QMetaType::Type::QVariantList )
350 const QVariantList coordList = curveData.toList();
351 const int nCoords =
static_cast< int >( coordList.size() );
355 const double x = coordList[0].toDouble( &xok );
356 const double y = coordList[1].toDouble( &yok );
365 *outLineZ++ = nCoords >= 3 ? coordList[2].toDouble() : std::numeric_limits< double >::quiet_NaN();
371 *outLineM++ = ( ( hasZ && nCoords >= 4 ) || ( !hasZ && nCoords >= 3 ) ) ? coordList[hasZ ? 3 : 2].toDouble() : std::numeric_limits< double >::quiet_NaN();
376 QgsDebugError( u
"Found unexpected value when parsing ESRI json line string. Expected list, got %1"_s.arg( curveData.metaType().name() ) );
381 if ( actualLineSize == 0 )
384 lineX.resize( actualLineSize );
385 lineY.resize( actualLineSize );
387 lineZ.resize( actualLineSize );
389 lineM.resize( actualLineSize );
390 return std::make_unique< QgsLineString>( lineX, lineY, lineZ, lineM );
393std::unique_ptr< QgsPoint > QgsArcGisRestUtils::convertGeometryPoint(
const QVariantMap &geometryData,
Qgis::WkbType pointType )
396 bool xok =
false, yok =
false;
397 double x = geometryData[u
"x"_s].toDouble( &xok );
398 double y = geometryData[u
"y"_s].toDouble( &yok );
401 double z = geometryData[u
"z"_s].toDouble();
402 double m = geometryData[u
"m"_s].toDouble();
403 return std::make_unique< QgsPoint >( pointType, x, y, z, m );
406std::unique_ptr< QgsMultiPoint > QgsArcGisRestUtils::convertMultiPoint(
const QVariantMap &geometryData,
Qgis::WkbType pointType )
409 const QVariantList coordsList = geometryData[u
"points"_s].toList();
411 auto multiPoint = std::make_unique< QgsMultiPoint >();
412 multiPoint->reserve(
static_cast< int >( coordsList.size() ) );
413 for (
const QVariant &coordData : coordsList )
415 const QVariantList coordList = coordData.toList();
416 std::unique_ptr< QgsPoint > p = convertPoint( coordList, pointType );
421 multiPoint->addGeometry( p.release() );
426 std::unique_ptr< QgsPoint > p = convertGeometryPoint( geometryData, pointType );
428 multiPoint->addGeometry( p.release() );
430 if ( multiPoint->numGeometries() == 0 )
438std::unique_ptr< QgsMultiCurve > QgsArcGisRestUtils::convertGeometryPolyline(
const QVariantMap &geometryData,
Qgis::WkbType pointType,
bool allowCurves )
441 QVariantList pathsList;
442 if ( geometryData[u
"paths"_s].isValid() )
443 pathsList = geometryData[u
"paths"_s].toList();
444 else if ( geometryData[u
"curvePaths"_s].isValid() )
445 pathsList = geometryData[u
"curvePaths"_s].toList();
446 if ( pathsList.isEmpty() )
448 std::unique_ptr< QgsMultiCurve > multiCurve = allowCurves ? std::make_unique< QgsMultiCurve >() : std::make_unique< QgsMultiLineString >();
449 multiCurve->reserve(
static_cast< int >( pathsList.size() ) );
450 for (
const QVariant &pathData : std::as_const( pathsList ) )
452 std::unique_ptr< QgsCurve > curve = allowCurves ? convertCompoundCurve( pathData.toList(), pointType ) : convertLineString( pathData.toList(), pointType );
457 multiCurve->addGeometry( curve.release() );
462std::unique_ptr< QgsMultiSurface > QgsArcGisRestUtils::convertGeometryPolygon(
const QVariantMap &geometryData,
Qgis::WkbType pointType,
bool allowCurves )
465 QVariantList ringsList;
466 if ( geometryData[u
"rings"_s].isValid() )
467 ringsList = geometryData[u
"rings"_s].toList();
468 else if ( geometryData[u
"ringPaths"_s].isValid() )
469 ringsList = geometryData[u
"ringPaths"_s].toList();
470 if ( ringsList.isEmpty() )
473 QList< QgsCurve * > curves;
474 for (
int i = 0, n =
static_cast< int >( ringsList.size() ); i < n; ++i )
476 std::unique_ptr< QgsCurve > curve = allowCurves ? convertCompoundCurve( ringsList[i].toList(), pointType ) : convertLineString( ringsList[i].toList(), pointType );
481 curves.append( curve.release() );
483 if ( curves.count() == 0 )
486 std::unique_ptr< QgsMultiSurface > result = allowCurves ? std::make_unique< QgsMultiSurface >() : std::make_unique< QgsMultiPolygon >();
487 if ( curves.count() == 1 )
490 std::unique_ptr< QgsCurvePolygon > newPolygon = allowCurves ? std::make_unique< QgsCurvePolygon >() : std::make_unique< QgsPolygon >();
491 newPolygon->setExteriorRing( curves.takeAt( 0 ) );
492 result->addGeometry( newPolygon.release() );
496 std::sort( curves.begin(), curves.end(), [](
const QgsCurve *a,
const QgsCurve *b ) ->
bool {
499 a->sumUpArea( a_area );
500 b->sumUpArea( b_area );
501 return std::abs( a_area ) > std::abs( b_area );
503 result->reserve(
static_cast< int >( curves.size() ) );
504 while ( !curves.isEmpty() )
506 QgsCurve *exterior = curves.takeFirst();
507 QgsCurvePolygon *newPolygon = allowCurves ? new QgsCurvePolygon() : new QgsPolygon();
508 newPolygon->setExteriorRing( exterior );
509 std::unique_ptr<QgsGeometryEngine> engine( QgsGeometry::createGeometryEngine( newPolygon ) );
510 engine->prepareGeometry();
512 QMutableListIterator< QgsCurve * > it( curves );
513 while ( it.hasNext() )
515 QgsCurve *curve = it.next();
516 QgsRectangle boundingBox = newPolygon->boundingBox();
517 if ( boundingBox.intersects( curve->boundingBox() ) )
519 QgsPoint point = curve->startPoint();
520 if ( engine->contains( &point ) )
522 newPolygon->addInteriorRing( curve );
524 engine.reset( QgsGeometry::createGeometryEngine( newPolygon ) );
525 engine->prepareGeometry();
529 result->addGeometry( newPolygon );
531 if ( result->numGeometries() == 0 )
537std::unique_ptr< QgsPolygon > QgsArcGisRestUtils::convertEnvelope(
const QVariantMap &geometryData )
540 bool xminOk =
false, yminOk =
false, xmaxOk =
false, ymaxOk =
false;
541 double xmin = geometryData[u
"xmin"_s].toDouble( &xminOk );
542 double ymin = geometryData[u
"ymin"_s].toDouble( &yminOk );
543 double xmax = geometryData[u
"xmax"_s].toDouble( &xmaxOk );
544 double ymax = geometryData[u
"ymax"_s].toDouble( &ymaxOk );
545 if ( !xminOk || !yminOk || !xmaxOk || !ymaxOk )
547 auto ext = std::make_unique< QgsLineString>();
548 ext->addVertex( QgsPoint( xmin, ymin ) );
549 ext->addVertex( QgsPoint( xmax, ymin ) );
550 ext->addVertex( QgsPoint( xmax, ymax ) );
551 ext->addVertex( QgsPoint( xmin, ymax ) );
552 ext->addVertex( QgsPoint( xmin, ymin ) );
553 auto poly = std::make_unique< QgsPolygon >();
554 poly->setExteriorRing( ext.release() );
559 const QVariantMap &geometryData,
const QString &esriGeometryType,
bool readM,
bool readZ,
bool allowCurves,
QgsCoordinateReferenceSystem *crs
569 if ( esriGeometryType ==
"esriGeometryNull"_L1 )
571 else if ( esriGeometryType ==
"esriGeometryPoint"_L1 )
572 return convertGeometryPoint( geometryData, pointType );
573 else if ( esriGeometryType ==
"esriGeometryMultipoint"_L1 )
574 return convertMultiPoint( geometryData, pointType );
575 else if ( esriGeometryType ==
"esriGeometryPolyline"_L1 )
576 return convertGeometryPolyline( geometryData, pointType, allowCurves );
577 else if ( esriGeometryType ==
"esriGeometryPolygon"_L1 )
578 return convertGeometryPolygon( geometryData, pointType, allowCurves );
579 else if ( esriGeometryType ==
"esriGeometryEnvelope"_L1 )
580 return convertEnvelope( geometryData );
603 QString spatialReference = spatialReferenceMap[u
"latestWkid"_s].toString();
604 if ( spatialReference.isEmpty() )
605 spatialReference = spatialReferenceMap[u
"wkid"_s].toString();
608 if ( !spatialReference.isEmpty() )
617 else if ( !spatialReferenceMap[u
"wkt"_s].toString().isEmpty() )
620 crs.
createFromWkt( spatialReferenceMap[u
"wkt"_s].toString() );
635 const QString type = symbolData.value( u
"type"_s ).toString();
636 if ( type ==
"esriSMS"_L1 )
639 return parseEsriMarkerSymbolJson( symbolData );
641 else if ( type ==
"esriSLS"_L1 )
644 return parseEsriLineSymbolJson( symbolData );
646 else if ( type ==
"esriSFS"_L1 )
649 return parseEsriFillSymbolJson( symbolData );
651 else if ( type ==
"esriPFS"_L1 )
653 return parseEsriPictureFillSymbolJson( symbolData );
655 else if ( type ==
"esriPMS"_L1 )
658 return parseEsriPictureMarkerSymbolJson( symbolData );
660 else if ( type ==
"esriTS"_L1 )
662 return parseEsriTextMarkerSymbolJson( symbolData );
667std::unique_ptr<QgsLineSymbol> QgsArcGisRestUtils::parseEsriLineSymbolJson(
const QVariantMap &symbolData )
669 QColor lineColor =
convertColor( symbolData.value( u
"color"_s ) );
670 if ( !lineColor.isValid() )
674 double widthInPoints = symbolData.value( u
"width"_s ).toDouble( &ok );
679 Qt::PenStyle penStyle =
convertLineStyle( symbolData.value( u
"style"_s ).toString() );
680 auto lineLayer = std::make_unique< QgsSimpleLineSymbolLayer >( lineColor, widthInPoints, penStyle );
682 layers.append( lineLayer.release() );
684 auto symbol = std::make_unique< QgsLineSymbol >( layers );
688std::unique_ptr<QgsFillSymbol> QgsArcGisRestUtils::parseEsriFillSymbolJson(
const QVariantMap &symbolData )
690 QColor fillColor =
convertColor( symbolData.value( u
"color"_s ) );
691 Qt::BrushStyle brushStyle =
convertFillStyle( symbolData.value( u
"style"_s ).toString() );
693 const QVariantMap outlineData = symbolData.value( u
"outline"_s ).toMap();
694 QColor lineColor =
convertColor( outlineData.value( u
"color"_s ) );
695 Qt::PenStyle penStyle =
convertLineStyle( outlineData.value( u
"style"_s ).toString() );
697 double penWidthInPoints = outlineData.value( u
"width"_s ).toDouble( &ok );
700 auto fillLayer = std::make_unique< QgsSimpleFillSymbolLayer >( fillColor, brushStyle, lineColor, penStyle, penWidthInPoints );
702 layers.append( fillLayer.release() );
704 auto symbol = std::make_unique< QgsFillSymbol >( layers );
708std::unique_ptr<QgsFillSymbol> QgsArcGisRestUtils::parseEsriPictureFillSymbolJson(
const QVariantMap &symbolData )
712 double widthInPixels = symbolData.value( u
"width"_s ).toInt( &ok );
716 const double xScale = symbolData.value( u
"xscale"_s ).toDouble( &ok );
718 widthInPixels *= xScale;
720 const double angleCCW = symbolData.value( u
"angle"_s ).toDouble( &ok );
725 const double xOffset = symbolData.value( u
"xoffset"_s ).toDouble();
726 const double yOffset = symbolData.value( u
"yoffset"_s ).toDouble();
728 QString symbolPath( symbolData.value( u
"imageData"_s ).toString() );
729 symbolPath.prepend(
"base64:"_L1 );
732 auto fillLayer = std::make_unique< QgsRasterFillSymbolLayer >( symbolPath );
733 fillLayer->setWidth( widthInPixels );
734 fillLayer->setAngle( angleCW );
736 fillLayer->setOffset( QPointF( xOffset, yOffset ) );
738 layers.append( fillLayer.release() );
740 const QVariantMap outlineData = symbolData.value( u
"outline"_s ).toMap();
741 QColor lineColor =
convertColor( outlineData.value( u
"color"_s ) );
742 Qt::PenStyle penStyle =
convertLineStyle( outlineData.value( u
"style"_s ).toString() );
743 double penWidthInPoints = outlineData.value( u
"width"_s ).toDouble( &ok );
745 auto lineLayer = std::make_unique< QgsSimpleLineSymbolLayer >( lineColor, penWidthInPoints, penStyle );
747 layers.append( lineLayer.release() );
749 auto symbol = std::make_unique< QgsFillSymbol >( layers );
753Qgis::MarkerShape QgsArcGisRestUtils::parseEsriMarkerShape(
const QString &style )
755 if ( style ==
"esriSMSCircle"_L1 )
757 else if ( style ==
"esriSMSCross"_L1 )
759 else if ( style ==
"esriSMSDiamond"_L1 )
761 else if ( style ==
"esriSMSSquare"_L1 )
763 else if ( style ==
"esriSMSX"_L1 )
765 else if ( style ==
"esriSMSTriangle"_L1 )
771std::unique_ptr<QgsMarkerSymbol> QgsArcGisRestUtils::parseEsriMarkerSymbolJson(
const QVariantMap &symbolData )
773 QColor fillColor =
convertColor( symbolData.value( u
"color"_s ) );
775 const double sizeInPoints = symbolData.value( u
"size"_s ).toDouble( &ok );
778 const double angleCCW = symbolData.value( u
"angle"_s ).toDouble( &ok );
783 Qgis::MarkerShape shape = parseEsriMarkerShape( symbolData.value( u
"style"_s ).toString() );
785 const double xOffset = symbolData.value( u
"xoffset"_s ).toDouble();
786 const double yOffset = symbolData.value( u
"yoffset"_s ).toDouble();
788 const QVariantMap outlineData = symbolData.value( u
"outline"_s ).toMap();
789 QColor lineColor =
convertColor( outlineData.value( u
"color"_s ) );
790 Qt::PenStyle penStyle =
convertLineStyle( outlineData.value( u
"style"_s ).toString() );
791 double penWidthInPoints = outlineData.value( u
"width"_s ).toDouble( &ok );
794 auto markerLayer = std::make_unique< QgsSimpleMarkerSymbolLayer >( shape, sizeInPoints, angleCW,
Qgis::ScaleMethod::ScaleArea, fillColor, lineColor );
797 markerLayer->setStrokeStyle( penStyle );
798 markerLayer->setStrokeWidth( penWidthInPoints );
799 markerLayer->setOffset( QPointF( xOffset, yOffset ) );
801 layers.append( markerLayer.release() );
803 auto symbol = std::make_unique< QgsMarkerSymbol >( layers );
807std::unique_ptr<QgsMarkerSymbol> QgsArcGisRestUtils::parseEsriPictureMarkerSymbolJson(
const QVariantMap &symbolData )
810 const double widthInPixels = symbolData.value( u
"width"_s ).toInt( &ok );
813 const double heightInPixels = symbolData.value( u
"height"_s ).toInt( &ok );
817 const double angleCCW = symbolData.value( u
"angle"_s ).toDouble( &ok );
822 const double xOffset = symbolData.value( u
"xoffset"_s ).toDouble();
823 const double yOffset = symbolData.value( u
"yoffset"_s ).toDouble();
827 QString symbolPath( symbolData.value( u
"imageData"_s ).toString() );
828 symbolPath.prepend(
"base64:"_L1 );
835 if ( !
qgsDoubleNear(
static_cast< double >( heightInPixels ) / widthInPixels, markerLayer->defaultAspectRatio() ) )
836 markerLayer->setFixedAspectRatio(
static_cast< double >( heightInPixels ) / widthInPixels );
838 markerLayer->setOffset( QPointF( xOffset, yOffset ) );
840 layers.append( markerLayer.release() );
842 auto symbol = std::make_unique< QgsMarkerSymbol >( layers );
846std::unique_ptr<QgsMarkerSymbol> QgsArcGisRestUtils::parseEsriTextMarkerSymbolJson(
const QVariantMap &symbolData )
850 const QString fontFamily = symbolData.value( u
"font"_s ).toMap().value( u
"family"_s ).toString();
852 const QString chr = symbolData.value( u
"text"_s ).toString();
854 const double pointSize = symbolData.value( u
"font"_s ).toMap().value( u
"size"_s ).toDouble();
856 const QColor color =
convertColor( symbolData.value( u
"color"_s ) );
858 const double esriAngle = symbolData.value( u
"angle"_s ).toDouble();
860 const double angle = 90.0 - esriAngle;
862 auto markerLayer = std::make_unique< QgsFontMarkerSymbolLayer >( fontFamily, chr, pointSize, color, angle );
864 QColor strokeColor =
convertColor( symbolData.value( u
"borderLineColor"_s ) );
865 markerLayer->setStrokeColor( strokeColor );
867 double borderLineSize = symbolData.value( u
"borderLineSize"_s ).toDouble();
868 markerLayer->setStrokeWidth( borderLineSize );
870 const QString fontStyle = symbolData.value( u
"font"_s ).toMap().value( u
"style"_s ).toString();
871 markerLayer->setFontStyle( fontStyle );
873 double xOffset = symbolData.value( u
"xoffset"_s ).toDouble();
874 double yOffset = symbolData.value( u
"yoffset"_s ).toDouble();
876 markerLayer->setOffset( QPointF( xOffset, yOffset ) );
885 QString horizontalAnchorPoint = symbolData.value( u
"horizontalAlignment"_s ).toString();
886 QString verticalAnchorPoint = symbolData.value( u
"verticalAlignment"_s ).toString();
888 if ( horizontalAnchorPoint == QString(
"center" ) )
892 else if ( horizontalAnchorPoint == QString(
"left" ) )
896 else if ( horizontalAnchorPoint == QString(
"right" ) )
901 if ( verticalAnchorPoint == QString(
"center" ) )
905 else if ( verticalAnchorPoint == QString(
"top" ) )
909 else if ( verticalAnchorPoint == QString(
"bottom" ) )
914 markerLayer->setHorizontalAnchorPoint( hAlign );
915 markerLayer->setVerticalAnchorPoint( vAlign );
917 layers.append( markerLayer.release() );
919 auto symbol = std::make_unique< QgsMarkerSymbol >( layers );
925 if ( labelingData.empty() )
932 for (
const QVariant &lbl : labelingData )
934 const QVariantMap labeling = lbl.toMap();
939 const QString placement = labeling.value( u
"labelPlacement"_s ).toString();
940 if ( placement ==
"esriServerPointLabelPlacementAboveCenter"_L1 )
945 else if ( placement ==
"esriServerPointLabelPlacementBelowCenter"_L1 )
950 else if ( placement ==
"esriServerPointLabelPlacementCenterCenter"_L1 )
955 else if ( placement ==
"esriServerPointLabelPlacementAboveLeft"_L1 )
960 else if ( placement ==
"esriServerPointLabelPlacementBelowLeft"_L1 )
965 else if ( placement ==
"esriServerPointLabelPlacementCenterLeft"_L1 )
970 else if ( placement ==
"esriServerPointLabelPlacementAboveRight"_L1 )
975 else if ( placement ==
"esriServerPointLabelPlacementBelowRight"_L1 )
980 else if ( placement ==
"esriServerPointLabelPlacementCenterRight"_L1 )
985 else if ( placement ==
"esriServerLinePlacementAboveAfter"_L1 || placement ==
"esriServerLinePlacementAboveStart"_L1 || placement ==
"esriServerLinePlacementAboveAlong"_L1 )
990 else if ( placement ==
"esriServerLinePlacementBelowAfter"_L1 || placement ==
"esriServerLinePlacementBelowStart"_L1 || placement ==
"esriServerLinePlacementBelowAlong"_L1 )
995 else if ( placement ==
"esriServerLinePlacementCenterAfter"_L1 || placement ==
"esriServerLinePlacementCenterStart"_L1 || placement ==
"esriServerLinePlacementCenterAlong"_L1 )
1000 else if ( placement ==
"esriServerPolygonPlacementAlwaysHorizontal"_L1 )
1005 const double minScale = labeling.value( u
"minScale"_s ).toDouble();
1006 const double maxScale = labeling.value( u
"maxScale"_s ).toDouble();
1008 QVariantMap symbol = labeling.value( u
"symbol"_s ).toMap();
1010 const double haloSize = symbol.value( u
"haloSize"_s ).toDouble();
1021 const QString fontFamily = symbol.value( u
"font"_s ).toMap().value( u
"family"_s ).toString();
1022 const QString fontStyle = symbol.value( u
"font"_s ).toMap().value( u
"style"_s ).toString();
1023 const QString fontWeight = symbol.value( u
"font"_s ).toMap().value( u
"weight"_s ).toString();
1024 const int fontSize = symbol.value( u
"font"_s ).toMap().value( u
"size"_s ).toInt();
1025 QFont font( fontFamily, fontSize );
1026 font.setStyleName( fontStyle );
1027 font.setWeight( fontWeight ==
"bold"_L1 ? QFont::Bold : QFont::Normal );
1035 QString where = labeling.value( u
"where"_s ).toString();
1049 return std::make_unique< QgsRuleBasedLabeling >( root );
1054 const QString type = rendererData.value( u
"type"_s ).toString();
1055 if ( type ==
"simple"_L1 )
1057 const QVariantMap symbolProps = rendererData.value( u
"symbol"_s ).toMap();
1058 std::unique_ptr< QgsSymbol > symbol(
convertSymbol( symbolProps ) );
1060 return std::make_unique< QgsSingleSymbolRenderer >( symbol.release() );
1064 else if ( type ==
"uniqueValue"_L1 )
1066 const QString field1 = rendererData.value( u
"field1"_s ).toString();
1067 const QString field2 = rendererData.value( u
"field2"_s ).toString();
1068 const QString field3 = rendererData.value( u
"field3"_s ).toString();
1070 if ( !field2.isEmpty() || !field3.isEmpty() )
1072 const QString delimiter = rendererData.value( u
"fieldDelimiter"_s ).toString();
1073 if ( !field3.isEmpty() )
1075 attribute = u
"concat(\"%1\",'%2',\"%3\",'%4',\"%5\")"_s.arg( field1, delimiter, field2, delimiter, field3 );
1079 attribute = u
"concat(\"%1\",'%2',\"%3\")"_s.arg( field1, delimiter, field2 );
1087 const QVariantList categories = rendererData.value( u
"uniqueValueInfos"_s ).toList();
1089 for (
const QVariant &category : categories )
1091 const QVariantMap categoryData = category.toMap();
1092 const QString value = categoryData.value( u
"value"_s ).toString();
1093 const QString label = categoryData.value( u
"label"_s ).toString();
1101 std::unique_ptr< QgsSymbol > defaultSymbol(
convertSymbol( rendererData.value( u
"defaultSymbol"_s ).toMap() ) );
1102 if ( defaultSymbol )
1104 categoryList.append(
QgsRendererCategory( QVariant(), defaultSymbol.release(), rendererData.value( u
"defaultLabel"_s ).toString() ) );
1107 if ( categoryList.empty() )
1110 return std::make_unique< QgsCategorizedSymbolRenderer >( attribute, categoryList );
1112 else if ( type ==
"classBreaks"_L1 )
1114 const QString attrName = rendererData.value( u
"field"_s ).toString();
1116 const QVariantList classBreakInfos = rendererData.value( u
"classBreakInfos"_s ).toList();
1117 const QVariantMap authoringInfo = rendererData.value( u
"authoringInfo"_s ).toMap();
1118 QVariantMap symbolData;
1120 QString esriMode = authoringInfo.value( u
"classificationMethod"_s ).toString();
1121 if ( esriMode.isEmpty() )
1123 esriMode = rendererData.value( u
"classificationMethod"_s ).toString();
1126 if ( !classBreakInfos.isEmpty() )
1128 symbolData = classBreakInfos.at( 0 ).toMap().value( u
"symbol"_s ).toMap();
1134 const double transparency = rendererData.value( u
"transparency"_s ).toDouble();
1135 const double opacity = ( 100.0 - transparency ) / 100.0;
1136 symbol->setOpacity( opacity );
1138 const QVariantList visualVariablesData = rendererData.value( u
"visualVariables"_s ).toList();
1140 for (
const QVariant &visualVariable : visualVariablesData )
1142 const QVariantMap visualVariableData = visualVariable.toMap();
1143 const QString variableType = visualVariableData.value( u
"type"_s ).toString();
1144 if ( variableType ==
"sizeInfo"_L1 )
1148 else if ( variableType ==
"colorInfo"_L1 )
1150 const QVariantList stops = visualVariableData.value( u
"stops"_s ).toList();
1151 if ( stops.size() < 2 )
1156 const double minValue = stops.front().toMap().value( u
"value"_s ).toDouble( &ok );
1159 const QColor minColor =
convertColor( stops.front().toMap().value( u
"color"_s ) );
1161 const double maxValue = stops.back().toMap().value( u
"value"_s ).toDouble( &ok );
1164 const QColor maxColor =
convertColor( stops.back().toMap().value( u
"color"_s ) );
1167 for (
int i = 1; i < stops.size() - 1; ++i )
1169 const QVariantMap stopData = stops.at( i ).toMap();
1170 const double breakpoint = stopData.value( u
"value"_s ).toDouble();
1171 const double scaledBreakpoint = ( breakpoint - minValue ) / ( maxValue - minValue );
1172 const QColor fillColor =
convertColor( stopData.value( u
"color"_s ) );
1174 gradientStops.append(
QgsGradientStop( scaledBreakpoint, fillColor ) );
1177 auto colorRamp = std::make_unique< QgsGradientColorRamp >( minColor, maxColor,
false, gradientStops );
1181 for (
int layer = 0; layer < symbol->symbolLayerCount(); ++layer )
1186 return std::make_unique< QgsSingleSymbolRenderer >( symbol.release() );
1190 QgsDebugError( u
"ESRI visualVariable type %1 is not currently supported"_s.arg( variableType ) );
1194 double lastValue = rendererData.value( u
"minValue"_s ).toDouble();
1196 auto graduatedRenderer = std::make_unique< QgsGraduatedSymbolRenderer >( attrName );
1198 graduatedRenderer->setSourceSymbol( symbol.release() );
1200 if ( esriMode ==
"esriClassifyDefinedInterval"_L1 )
1203 graduatedRenderer->setClassificationMethod( method );
1205 else if ( esriMode ==
"esriClassifyEqualInterval"_L1 )
1208 graduatedRenderer->setClassificationMethod( method );
1210 else if ( esriMode ==
"esriClassifyGeometricalInterval"_L1 )
1213 graduatedRenderer->setClassificationMethod( method );
1215 else if ( esriMode ==
"esriClassifyManual"_L1 )
1218 graduatedRenderer->setClassificationMethod( method );
1220 else if ( esriMode ==
"esriClassifyNaturalBreaks"_L1 )
1223 graduatedRenderer->setClassificationMethod( method );
1225 else if ( esriMode ==
"esriClassifyQuantile"_L1 )
1228 graduatedRenderer->setClassificationMethod( method );
1230 else if ( esriMode ==
"esriClassifyStandardDeviation"_L1 )
1233 graduatedRenderer->setClassificationMethod( method );
1235 else if ( !esriMode.isEmpty() )
1237 QgsDebugError( u
"ESRI classification mode %1 is not currently supported"_s.arg( esriMode ) );
1240 for (
const QVariant &classBreakInfo : classBreakInfos )
1242 const QVariantMap symbolData = classBreakInfo.toMap().value( u
"symbol"_s ).toMap();
1244 double classMaxValue = classBreakInfo.toMap().value( u
"classMaxValue"_s ).toDouble();
1245 const QString label = classBreakInfo.toMap().value( u
"label"_s ).toString();
1254 lastValue = classMaxValue;
1255 graduatedRenderer->addClass( range );
1258 return graduatedRenderer;
1260 else if ( type ==
"heatmap"_L1 )
1265 else if ( type ==
"vectorField"_L1 )
1275 QString expression = string;
1278 const thread_local QRegularExpression rx1 = QRegularExpression( u
"(?=([^\"\\\\]*(\\\\.|\"([^\"\\\\]*\\\\.)*[^\"\\\\]*\"))*[^\"]*$)(\\s|^)CONCAT(\\s|$)"_s );
1279 expression = expression.replace( rx1, u
"\\4||\\5"_s );
1281 const thread_local QRegularExpression rx2 = QRegularExpression( u
"(?=([^\"\\\\]*(\\\\.|\"([^\"\\\\]*\\\\.)*[^\"\\\\]*\"))*[^\"]*$)(\\s|^)NEWLINE(\\s|$)"_s );
1282 expression = expression.replace( rx2, u
"\\4'\\n'\\5"_s );
1285 const thread_local QRegularExpression rx3 = QRegularExpression( u
"\"(.*?(?<!\\\\))\""_s );
1286 expression = expression.replace( rx3, u
"'\\1'"_s );
1287 const thread_local QRegularExpression rx4 = QRegularExpression( u
"\\\\\""_s );
1288 expression = expression.replace( rx4, u
"\""_s );
1291 const thread_local QRegularExpression rx5 = QRegularExpression( u
"\\[([^]]*)\\]"_s );
1292 expression = expression.replace( rx5, u
"\"\\1\""_s );
1299 const QVariantList colorParts = colorData.toList();
1300 if ( colorParts.count() < 4 )
1303 int red = colorParts.at( 0 ).toInt();
1304 int green = colorParts.at( 1 ).toInt();
1305 int blue = colorParts.at( 2 ).toInt();
1306 int alpha = colorParts.at( 3 ).toInt();
1307 return QColor( red, green, blue, alpha );
1312 if ( style ==
"esriSLSSolid"_L1 )
1313 return Qt::SolidLine;
1314 else if ( style ==
"esriSLSDash"_L1 )
1315 return Qt::DashLine;
1316 else if ( style ==
"esriSLSDashDot"_L1 )
1317 return Qt::DashDotLine;
1318 else if ( style ==
"esriSLSDashDotDot"_L1 )
1319 return Qt::DashDotDotLine;
1320 else if ( style ==
"esriSLSDot"_L1 )
1322 else if ( style ==
"esriSLSNull"_L1 )
1325 return Qt::SolidLine;
1330 if ( style ==
"esriSFSBackwardDiagonal"_L1 )
1331 return Qt::BDiagPattern;
1332 else if ( style ==
"esriSFSCross"_L1 )
1333 return Qt::CrossPattern;
1334 else if ( style ==
"esriSFSDiagonalCross"_L1 )
1335 return Qt::DiagCrossPattern;
1336 else if ( style ==
"esriSFSForwardDiagonal"_L1 )
1337 return Qt::FDiagPattern;
1338 else if ( style ==
"esriSFSHorizontal"_L1 )
1339 return Qt::HorPattern;
1340 else if ( style ==
"esriSFSNull"_L1 )
1342 else if ( style ==
"esriSFSSolid"_L1 )
1343 return Qt::SolidPattern;
1344 else if ( style ==
"esriSFSVertical"_L1 )
1345 return Qt::VerPattern;
1347 return Qt::SolidPattern;
1355 QDateTime dt = QDateTime::fromMSecsSinceEpoch( value.toLongLong( &ok ) );
1358 QgsDebugError( u
"Invalid value %1 for datetime"_s.arg( value.toString() ) );
1370 const QVariantMap coords = value.toMap();
1371 if ( coords.isEmpty() )
1376 const double xmin = coords.value( u
"xmin"_s ).toDouble( &ok );
1380 const double ymin = coords.value( u
"ymin"_s ).toDouble( &ok );
1384 const double xmax = coords.value( u
"xmax"_s ).toDouble( &ok );
1388 const double ymax = coords.value( u
"ymax"_s ).toDouble( &ok );
1400 return QVariantMap();
1407 return QVariantMap();
1451 return QVariantMap();
1454 return QVariantMap();
1457 return QVariantMap();
1463 res.insert( u
"spatialReference"_s,
crsToJson( crs ) );
1469QVariantMap QgsArcGisRestUtils::pointToJson(
const QgsPoint *point )
1473 data[u
"x"_s] = u
"NaN"_s;
1476 data[u
"x"_s] = point->
x();
1477 data[u
"y"_s] = point->
y();
1479 if ( point->
is3D() )
1480 data[u
"z"_s] = !std::isnan( point->
z() ) ? QVariant( point->
z() ) : QVariant( u
"NaN"_s );
1483 data[u
"m"_s] = !std::isnan( point->
m() ) ? QVariant( point->
m() ) : QVariant( u
"NaN"_s );
1488QVariantMap QgsArcGisRestUtils::multiPointToJson(
const QgsMultiPoint *multiPoint )
1491 const bool hasZ = multiPoint->
is3D();
1492 const bool hasM = multiPoint->
isMeasure();
1493 data[u
"hasM"_s] = hasM;
1494 data[u
"hasZ"_s] = hasZ;
1496 QVariantList pointsList;
1498 pointsList.reserve( size );
1500 QVariantList pointList;
1501 for (
int i = 0; i < size; ++i )
1503 const QgsPoint *point = multiPoint->
pointN( i );
1506 pointList.append( point->
x() );
1507 pointList.append( point->
y() );
1509 pointList.append( point->
z() );
1510 if ( hasM && !std::isnan( point->
m() ) )
1511 pointList.append( point->
m() );
1513 pointsList.push_back( pointList );
1516 data[u
"points"_s] = pointsList;
1520QVariantList QgsArcGisRestUtils::lineStringToJsonPath(
const QgsLineString *line )
1522 const bool hasZ = line->
is3D();
1525 QVariantList pointsList;
1527 pointsList.reserve( size );
1529 QVariantList pointList;
1530 const double *xData = line->
xData();
1531 const double *yData = line->
yData();
1532 const double *zData = hasZ ? line->
zData() :
nullptr;
1533 const double *mData = hasM ? line->
mData() :
nullptr;
1535 for (
int i = 0; i < size; ++i )
1538 pointList.append( *xData++ );
1539 pointList.append( *yData++ );
1542 pointList.append( *zData++ );
1544 if ( hasM && !std::isnan( *mData ) )
1545 pointList.append( *mData );
1549 pointsList.push_back( pointList );
1554QVariantList QgsArcGisRestUtils::curveToJsonCurve(
const QgsCurve *curve,
bool includeStart )
1556 const bool hasZ = curve->
is3D();
1559 auto pointToList = [hasZ, hasM](
const QgsPoint &point ) -> QVariantList {
1560 QVariantList pointList;
1562 pointList.append( point.
x() );
1563 pointList.append( point.
y() );
1566 pointList.append( point.
z() );
1568 if ( hasM && !std::isnan( point.
m() ) )
1569 pointList.append( point.
m() );
1580 if ( !part.isEmpty() && !includeStart )
1589 if ( includeStart && !circularString->
isEmpty() )
1591 res.push_back( pointToList( circularString->
startPoint() ) );
1594 const int size = circularString->
numPoints();
1595 for (
int i = 1; i + 1 < size; i += 2 )
1598 QVariantMap curvePart;
1599 QVariantList curveList;
1600 curveList.push_back( pointToList( circularString->
pointN( i + 1 ) ) );
1602 curveList.push_back( pointToList( circularString->
pointN( i ) ) );
1604 curvePart.insert( u
"c"_s, curveList );
1605 res.push_back( curvePart );
1614 const int size = compoundCurve->
nCurves();
1615 for (
int i = 0; i < size; ++i )
1617 const QgsCurve *subCurve = compoundCurve->
curveAt( i );
1618 res.append( curveToJsonCurve( subCurve, i == 0 ) );
1629QVariantMap QgsArcGisRestUtils::lineStringToJson(
const QgsLineString *line )
1632 const bool hasZ = line->
is3D();
1634 data[u
"hasM"_s] = hasM;
1635 data[u
"hasZ"_s] = hasZ;
1637 const QVariantList pointsList = lineStringToJsonPath( line );
1639 QVariantList pointsData = QVariantList();
1640 pointsData.push_back( pointsList );
1641 data[u
"paths"_s] = pointsData;
1646QVariantMap QgsArcGisRestUtils::curveToJson(
const QgsCurve *curve )
1649 const bool hasZ = curve->
is3D();
1651 data[u
"hasM"_s] = hasM;
1652 data[u
"hasZ"_s] = hasZ;
1654 const QVariantList curveList = curveToJsonCurve( curve,
true );
1656 QVariantList curveData = QVariantList();
1657 curveData.push_back( curveList );
1658 data[u
"curvePaths"_s] = curveData;
1663QVariantMap QgsArcGisRestUtils::multiLineStringToJson(
const QgsMultiLineString *multiLine )
1666 const bool hasZ = multiLine->
is3D();
1667 const bool hasM = multiLine->
isMeasure();
1668 data[u
"hasM"_s] = hasM;
1669 data[u
"hasZ"_s] = hasZ;
1673 paths.reserve( size );
1674 for (
int i = 0; i < size; ++i )
1676 const QgsLineString *line = multiLine->
lineStringN( i );
1677 paths.push_back( lineStringToJsonPath( line ) );
1680 data[u
"paths"_s] = paths;
1684QVariantMap QgsArcGisRestUtils::multiCurveToJson(
const QgsMultiCurve *multiCurve )
1687 const bool hasZ = multiCurve->
is3D();
1688 const bool hasM = multiCurve->
isMeasure();
1689 data[u
"hasM"_s] = hasM;
1690 data[u
"hasZ"_s] = hasZ;
1694 paths.reserve( size );
1695 for (
int i = 0; i < size; ++i )
1697 const QgsCurve *curve = multiCurve->
curveN( i );
1698 paths.push_back( curveToJsonCurve( curve,
true ) );
1701 data[u
"curvePaths"_s] = paths;
1705QVariantList QgsArcGisRestUtils::polygonToJsonRings(
const QgsPolygon *polygon )
1709 rings.reserve( numInteriorRings + 1 );
1714 switch ( exterior->orientation() )
1717 rings.push_back( lineStringToJsonPath( exterior ) );
1722 std::unique_ptr< QgsLineString > reversed( exterior->reversed() );
1723 rings.push_back( lineStringToJsonPath( reversed.get() ) );
1731 for (
int i = 0; i < numInteriorRings; ++i )
1738 rings.push_back( lineStringToJsonPath( ring ) );
1743 std::unique_ptr< QgsLineString > reversed( ring->
reversed() );
1744 rings.push_back( lineStringToJsonPath( reversed.get() ) );
1754QVariantList QgsArcGisRestUtils::curvePolygonToJsonRings(
const QgsCurvePolygon *polygon )
1758 rings.reserve( numInteriorRings + 1 );
1763 switch ( exterior->orientation() )
1766 rings.push_back( curveToJsonCurve( exterior,
true ) );
1771 std::unique_ptr< QgsCurve > reversed( exterior->reversed() );
1772 rings.push_back( curveToJsonCurve( reversed.get(),
true ) );
1780 for (
int i = 0; i < numInteriorRings; ++i )
1787 rings.push_back( curveToJsonCurve( ring,
true ) );
1792 std::unique_ptr< QgsCurve > reversed( ring->
reversed() );
1793 rings.push_back( curveToJsonCurve( reversed.get(),
true ) );
1803QVariantMap QgsArcGisRestUtils::polygonToJson(
const QgsPolygon *polygon )
1806 const bool hasZ = polygon->
is3D();
1808 data[u
"hasM"_s] = hasM;
1809 data[u
"hasZ"_s] = hasZ;
1810 data[u
"rings"_s] = polygonToJsonRings( polygon );
1814QVariantMap QgsArcGisRestUtils::curvePolygonToJson(
const QgsCurvePolygon *polygon )
1817 const bool hasZ = polygon->
is3D();
1819 data[u
"hasM"_s] = hasM;
1820 data[u
"hasZ"_s] = hasZ;
1821 data[u
"curveRings"_s] = curvePolygonToJsonRings( polygon );
1825QVariantMap QgsArcGisRestUtils::multiPolygonToJson(
const QgsMultiPolygon *multiPolygon )
1828 const bool hasZ = multiPolygon->
is3D();
1829 const bool hasM = multiPolygon->
isMeasure();
1830 data[u
"hasM"_s] = hasM;
1831 data[u
"hasZ"_s] = hasZ;
1835 for (
int i = 0; i < size; ++i )
1837 const QgsPolygon *polygon = multiPolygon->
polygonN( i );
1838 rings.append( polygonToJsonRings( polygon ) );
1841 data[u
"rings"_s] = rings;
1845QVariantMap QgsArcGisRestUtils::multiSurfaceToJson(
const QgsMultiSurface *multiSurface )
1848 const bool hasZ = multiSurface->
is3D();
1849 const bool hasM = multiSurface->
isMeasure();
1850 data[u
"hasM"_s] = hasM;
1851 data[u
"hasZ"_s] = hasZ;
1855 for (
int i = 0; i < size; ++i )
1861 rings.append( curvePolygonToJsonRings( polygon ) );
1864 data[u
"curveRings"_s] = rings;
1874 const QString authid = crs.
authid();
1875 if ( !authid.isEmpty() )
1877 const thread_local QRegularExpression rxAuthid( u
"(\\w+):(\\d+)"_s );
1878 const QRegularExpressionMatch match = rxAuthid.match( authid );
1879 if ( match.hasMatch() && ( ( match.captured( 1 ).compare(
"EPSG"_L1, Qt::CaseInsensitive ) == 0 ) || ( match.captured( 1 ).compare(
"ESRI"_L1, Qt::CaseInsensitive ) == 0 ) ) )
1881 const QString wkid = match.captured( 2 );
1882 res.insert( u
"wkid"_s, wkid );
1901 QVariantMap attributes;
1903 for (
const QgsField &field : fields )
1905 QVariant value = feature.
attribute( field.name() );
1906 if ( value.userType() == qMetaTypeId< QgsUnsetAttributeValue >() )
1917 if ( !attributes.isEmpty() )
1919 res.insert( u
"attributes"_s, attributes );
1929 switch ( expectedType )
1931 case QMetaType::Type::QString:
1933 const QString escaped = variant.toString().replace(
'\\',
"\\\\"_L1 ).replace(
'"',
"\\\""_L1 );
1934 return QString( QUrl::toPercentEncoding( escaped,
"'" ) );
1937 case QMetaType::Type::QDateTime:
1938 case QMetaType::Type::QDate:
1940 switch ( variant.userType() )
1942 case QMetaType::Type::QDateTime:
1943 return variant.toDateTime().toMSecsSinceEpoch();
1945 case QMetaType::Type::QDate:
1947 if ( context.
timeZone().isValid() )
1948 return QDateTime( variant.toDate(), QTime( 0, 0, 0 ), context.
timeZone() ).toMSecsSinceEpoch();
1950 return QDateTime( variant.toDate(), QTime( 0, 0, 0 ) ).toMSecsSinceEpoch();
1965 res.insert( u
"name"_s, field.
name() );
1968 switch ( field.
type() )
1970 case QMetaType::Type::LongLong:
1971 fieldType = u
"esriFieldTypeInteger"_s;
1974 case QMetaType::Type::Int:
1975 fieldType = u
"esriFieldTypeSmallInteger"_s;
1978 case QMetaType::Type::Double:
1979 fieldType = u
"esriFieldTypeDouble"_s;
1982 case QMetaType::Type::QString:
1983 fieldType = u
"esriFieldTypeString"_s;
1986 case QMetaType::Type::QDateTime:
1987 case QMetaType::Type::QDate:
1988 fieldType = u
"esriFieldTypeDate"_s;
1991 case QMetaType::Type::QByteArray:
1992 fieldType = u
"esriFieldTypeBlob"_s;
1997 fieldType = u
"esriFieldTypeString"_s;
2000 res.insert( u
"type"_s, fieldType );
2002 if ( !field.
alias().isEmpty() )
2003 res.insert( u
"alias"_s, field.
alias() );
2007 res.insert( u
"nullable"_s, !notNullable );
2010 res.insert( u
"editable"_s,
true );
2017 if ( type.compare(
"FeatureServer"_L1, Qt::CaseInsensitive ) == 0 )
2019 else if ( type.compare(
"MapServer"_L1, Qt::CaseInsensitive ) == 0 )
2021 else if ( type.compare(
"ImageServer"_L1, Qt::CaseInsensitive ) == 0 )
2023 else if ( type.compare(
"GlobeServer"_L1, Qt::CaseInsensitive ) == 0 )
2025 else if ( type.compare(
"GPServer"_L1, Qt::CaseInsensitive ) == 0 )
2027 else if ( type.compare(
"GeocodeServer"_L1, Qt::CaseInsensitive ) == 0 )
2029 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.
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 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 std::unique_ptr< QgsSymbol > convertSymbol(const QVariantMap &definition)
Converts a symbol JSON definition to a QgsSymbol.
static std::unique_ptr< 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.
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 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.
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.
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").
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.
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.
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
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