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 )
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<QgsLineString> QgsArcGisRestUtils::convertLineString(
const QVariantList &curvesList,
Qgis::WkbType pointType )
322 auto linestring = std::make_unique< QgsLineString >();
324 QVector< double > lineX;
325 QVector< double > lineY;
326 QVector< double > lineZ;
327 QVector< double > lineM;
328 const int maxCurveListSize =
static_cast< int >( curvesList.size() );
329 lineX.resize( maxCurveListSize );
330 lineY.resize( maxCurveListSize );
334 lineZ.resize( maxCurveListSize );
337 lineM.resize( maxCurveListSize );
339 double *outLineX = lineX.data();
340 double *outLineY = lineY.data();
341 double *outLineZ = lineZ.data();
342 double *outLineM = lineM.data();
347 int actualLineSize = 0;
348 for (
const QVariant &curveData : curvesList )
350 if ( curveData.userType() == QMetaType::Type::QVariantList )
352 const QVariantList coordList = curveData.toList();
353 const int nCoords =
static_cast< int >( coordList.size() );
357 const double x = coordList[0].toDouble( &xok );
358 const double y = coordList[1].toDouble( &yok );
367 *outLineZ++ = nCoords >= 3 ? coordList[2].toDouble() : std::numeric_limits< double >::quiet_NaN();
373 *outLineM++ = ( ( hasZ && nCoords >= 4 ) || ( !hasZ && nCoords >= 3 ) ) ? coordList[ hasZ ? 3 : 2].toDouble() : std::numeric_limits< double >::quiet_NaN();
378 QgsDebugError( u
"Found unexpected value when parsing ESRI json line string. Expected list, got %1"_s.arg( curveData.metaType().name() ) );
383 if ( actualLineSize == 0 )
386 lineX.resize( actualLineSize );
387 lineY.resize( actualLineSize );
389 lineZ.resize( actualLineSize );
391 lineM.resize( actualLineSize );
392 return std::make_unique< QgsLineString>( lineX, lineY, lineZ, lineM );
395std::unique_ptr< QgsPoint > QgsArcGisRestUtils::convertGeometryPoint(
const QVariantMap &geometryData,
Qgis::WkbType pointType )
398 bool xok =
false, yok =
false;
399 double x = geometryData[u
"x"_s].toDouble( &xok );
400 double y = geometryData[u
"y"_s].toDouble( &yok );
403 double z = geometryData[u
"z"_s].toDouble();
404 double m = geometryData[u
"m"_s].toDouble();
405 return std::make_unique< QgsPoint >( pointType, x, y, z, m );
408std::unique_ptr< QgsMultiPoint > QgsArcGisRestUtils::convertMultiPoint(
const QVariantMap &geometryData,
Qgis::WkbType pointType )
411 const QVariantList coordsList = geometryData[u
"points"_s].toList();
413 auto multiPoint = std::make_unique< QgsMultiPoint >();
414 multiPoint->reserve(
static_cast< int >( coordsList.size() ) );
415 for (
const QVariant &coordData : coordsList )
417 const QVariantList coordList = coordData.toList();
418 std::unique_ptr< QgsPoint > p = convertPoint( coordList, pointType );
423 multiPoint->addGeometry( p.release() );
428 std::unique_ptr< QgsPoint > p = convertGeometryPoint( geometryData, pointType );
430 multiPoint->addGeometry( p.release() );
432 if ( multiPoint->numGeometries() == 0 )
440std::unique_ptr< QgsMultiCurve > QgsArcGisRestUtils::convertGeometryPolyline(
const QVariantMap &geometryData,
Qgis::WkbType pointType,
bool allowCurves )
443 QVariantList pathsList;
444 if ( geometryData[u
"paths"_s].isValid() )
445 pathsList = geometryData[u
"paths"_s].toList();
446 else if ( geometryData[u
"curvePaths"_s].isValid() )
447 pathsList = geometryData[u
"curvePaths"_s].toList();
448 if ( pathsList.isEmpty() )
450 std::unique_ptr< QgsMultiCurve > multiCurve = allowCurves ? std::make_unique< QgsMultiCurve >() : std::make_unique< QgsMultiLineString >();
451 multiCurve->reserve(
static_cast< int >( pathsList.size() ) );
452 for (
const QVariant &pathData : std::as_const( pathsList ) )
454 std::unique_ptr< QgsCurve > curve = allowCurves ? convertCompoundCurve( pathData.toList(), pointType ) : convertLineString( pathData.toList(), pointType );
459 multiCurve->addGeometry( curve.release() );
464std::unique_ptr< QgsMultiSurface > QgsArcGisRestUtils::convertGeometryPolygon(
const QVariantMap &geometryData,
Qgis::WkbType pointType,
bool allowCurves )
467 QVariantList ringsList;
468 if ( geometryData[u
"rings"_s].isValid() )
469 ringsList = geometryData[u
"rings"_s].toList();
470 else if ( geometryData[u
"ringPaths"_s].isValid() )
471 ringsList = geometryData[u
"ringPaths"_s].toList();
472 if ( ringsList.isEmpty() )
475 QList< QgsCurve * > curves;
476 for (
int i = 0, n =
static_cast< int >( ringsList.size() ); i < n; ++i )
478 std::unique_ptr< QgsCurve > curve = allowCurves ? convertCompoundCurve( ringsList[i].toList(), pointType ) : convertLineString( ringsList[i].toList(), pointType );
483 curves.append( curve.release() );
485 if ( curves.count() == 0 )
488 std::unique_ptr< QgsMultiSurface > result = allowCurves ? std::make_unique< QgsMultiSurface >() : std::make_unique< QgsMultiPolygon >();
489 if ( curves.count() == 1 )
492 std::unique_ptr< QgsCurvePolygon > newPolygon = allowCurves ? std::make_unique< QgsCurvePolygon >() : std::make_unique< QgsPolygon >();
493 newPolygon->setExteriorRing( curves.takeAt( 0 ) );
494 result->addGeometry( newPolygon.release() );
498 std::sort( curves.begin(), curves.end(), [](
const QgsCurve * a,
const QgsCurve * 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 ); } );
499 result->reserve(
static_cast< int >( curves.size() ) );
500 while ( !curves.isEmpty() )
502 QgsCurve *exterior = curves.takeFirst();
503 QgsCurvePolygon *newPolygon = allowCurves ? new QgsCurvePolygon() : new QgsPolygon();
504 newPolygon->setExteriorRing( exterior );
505 std::unique_ptr<QgsGeometryEngine> engine( QgsGeometry::createGeometryEngine( newPolygon ) );
506 engine->prepareGeometry();
508 QMutableListIterator< QgsCurve * > it( curves );
509 while ( it.hasNext() )
511 QgsCurve *curve = it.next();
512 QgsRectangle boundingBox = newPolygon->boundingBox();
513 if ( boundingBox.intersects( curve->boundingBox() ) )
515 QgsPoint point = curve->startPoint();
516 if ( engine->contains( &point ) )
518 newPolygon->addInteriorRing( curve );
520 engine.reset( QgsGeometry::createGeometryEngine( newPolygon ) );
521 engine->prepareGeometry();
525 result->addGeometry( newPolygon );
527 if ( result->numGeometries() == 0 )
533std::unique_ptr< QgsPolygon > QgsArcGisRestUtils::convertEnvelope(
const QVariantMap &geometryData )
536 bool xminOk =
false, yminOk =
false, xmaxOk =
false, ymaxOk =
false;
537 double xmin = geometryData[u
"xmin"_s].toDouble( &xminOk );
538 double ymin = geometryData[u
"ymin"_s].toDouble( &yminOk );
539 double xmax = geometryData[u
"xmax"_s].toDouble( &xmaxOk );
540 double ymax = geometryData[u
"ymax"_s].toDouble( &ymaxOk );
541 if ( !xminOk || !yminOk || !xmaxOk || !ymaxOk )
543 auto ext = std::make_unique< QgsLineString> ();
544 ext->addVertex( QgsPoint( xmin, ymin ) );
545 ext->addVertex( QgsPoint( xmax, ymin ) );
546 ext->addVertex( QgsPoint( xmax, ymax ) );
547 ext->addVertex( QgsPoint( xmin, ymax ) );
548 ext->addVertex( QgsPoint( xmin, ymin ) );
549 auto poly = std::make_unique< QgsPolygon >();
550 poly->setExteriorRing( ext.release() );
563 if ( esriGeometryType ==
"esriGeometryNull"_L1 )
565 else if ( esriGeometryType ==
"esriGeometryPoint"_L1 )
566 return convertGeometryPoint( geometryData, pointType );
567 else if ( esriGeometryType ==
"esriGeometryMultipoint"_L1 )
568 return convertMultiPoint( geometryData, pointType );
569 else if ( esriGeometryType ==
"esriGeometryPolyline"_L1 )
570 return convertGeometryPolyline( geometryData, pointType, allowCurves );
571 else if ( esriGeometryType ==
"esriGeometryPolygon"_L1 )
572 return convertGeometryPolygon( geometryData, pointType, allowCurves );
573 else if ( esriGeometryType ==
"esriGeometryEnvelope"_L1 )
574 return convertEnvelope( geometryData );
597 QString spatialReference = spatialReferenceMap[u
"latestWkid"_s].toString();
598 if ( spatialReference.isEmpty() )
599 spatialReference = spatialReferenceMap[u
"wkid"_s].toString();
602 if ( !spatialReference.isEmpty() )
611 else if ( !spatialReferenceMap[u
"wkt"_s].toString().isEmpty() )
614 crs.
createFromWkt( spatialReferenceMap[u
"wkt"_s].toString() );
629 const QString type = symbolData.value( u
"type"_s ).toString();
630 if ( type ==
"esriSMS"_L1 )
633 return parseEsriMarkerSymbolJson( symbolData );
635 else if ( type ==
"esriSLS"_L1 )
638 return parseEsriLineSymbolJson( symbolData );
640 else if ( type ==
"esriSFS"_L1 )
643 return parseEsriFillSymbolJson( symbolData );
645 else if ( type ==
"esriPFS"_L1 )
647 return parseEsriPictureFillSymbolJson( symbolData );
649 else if ( type ==
"esriPMS"_L1 )
652 return parseEsriPictureMarkerSymbolJson( symbolData );
654 else if ( type ==
"esriTS"_L1 )
656 return parseEsriTextMarkerSymbolJson( symbolData );
661std::unique_ptr<QgsLineSymbol> QgsArcGisRestUtils::parseEsriLineSymbolJson(
const QVariantMap &symbolData )
663 QColor lineColor =
convertColor( symbolData.value( u
"color"_s ) );
664 if ( !lineColor.isValid() )
668 double widthInPoints = symbolData.value( u
"width"_s ).toDouble( &ok );
673 Qt::PenStyle penStyle =
convertLineStyle( symbolData.value( u
"style"_s ).toString() );
674 auto lineLayer = std::make_unique< QgsSimpleLineSymbolLayer >( lineColor, widthInPoints, penStyle );
676 layers.append( lineLayer.release() );
678 auto symbol = std::make_unique< QgsLineSymbol >( layers );
682std::unique_ptr<QgsFillSymbol> QgsArcGisRestUtils::parseEsriFillSymbolJson(
const QVariantMap &symbolData )
684 QColor fillColor =
convertColor( symbolData.value( u
"color"_s ) );
685 Qt::BrushStyle brushStyle =
convertFillStyle( symbolData.value( u
"style"_s ).toString() );
687 const QVariantMap outlineData = symbolData.value( u
"outline"_s ).toMap();
688 QColor lineColor =
convertColor( outlineData.value( u
"color"_s ) );
689 Qt::PenStyle penStyle =
convertLineStyle( outlineData.value( u
"style"_s ).toString() );
691 double penWidthInPoints = outlineData.value( u
"width"_s ).toDouble( &ok );
694 auto fillLayer = std::make_unique< QgsSimpleFillSymbolLayer >( fillColor, brushStyle, lineColor, penStyle, penWidthInPoints );
696 layers.append( fillLayer.release() );
698 auto symbol = std::make_unique< QgsFillSymbol >( layers );
702std::unique_ptr<QgsFillSymbol> QgsArcGisRestUtils::parseEsriPictureFillSymbolJson(
const QVariantMap &symbolData )
706 double widthInPixels = symbolData.value( u
"width"_s ).toInt( &ok );
710 const double xScale = symbolData.value( u
"xscale"_s ).toDouble( &ok );
712 widthInPixels *= xScale;
714 const double angleCCW = symbolData.value( u
"angle"_s ).toDouble( &ok );
719 const double xOffset = symbolData.value( u
"xoffset"_s ).toDouble();
720 const double yOffset = symbolData.value( u
"yoffset"_s ).toDouble();
722 QString symbolPath( symbolData.value( u
"imageData"_s ).toString() );
723 symbolPath.prepend(
"base64:"_L1 );
726 auto fillLayer = std::make_unique< QgsRasterFillSymbolLayer >( symbolPath );
727 fillLayer->setWidth( widthInPixels );
728 fillLayer->setAngle( angleCW );
730 fillLayer->setOffset( QPointF( xOffset, yOffset ) );
732 layers.append( fillLayer.release() );
734 const QVariantMap outlineData = symbolData.value( u
"outline"_s ).toMap();
735 QColor lineColor =
convertColor( outlineData.value( u
"color"_s ) );
736 Qt::PenStyle penStyle =
convertLineStyle( outlineData.value( u
"style"_s ).toString() );
737 double penWidthInPoints = outlineData.value( u
"width"_s ).toDouble( &ok );
739 auto lineLayer = std::make_unique< QgsSimpleLineSymbolLayer >( lineColor, penWidthInPoints, penStyle );
741 layers.append( lineLayer.release() );
743 auto symbol = std::make_unique< QgsFillSymbol >( layers );
747Qgis::MarkerShape QgsArcGisRestUtils::parseEsriMarkerShape(
const QString &style )
749 if ( style ==
"esriSMSCircle"_L1 )
751 else if ( style ==
"esriSMSCross"_L1 )
753 else if ( style ==
"esriSMSDiamond"_L1 )
755 else if ( style ==
"esriSMSSquare"_L1 )
757 else if ( style ==
"esriSMSX"_L1 )
759 else if ( style ==
"esriSMSTriangle"_L1 )
765std::unique_ptr<QgsMarkerSymbol> QgsArcGisRestUtils::parseEsriMarkerSymbolJson(
const QVariantMap &symbolData )
767 QColor fillColor =
convertColor( symbolData.value( u
"color"_s ) );
769 const double sizeInPoints = symbolData.value( u
"size"_s ).toDouble( &ok );
772 const double angleCCW = symbolData.value( u
"angle"_s ).toDouble( &ok );
777 Qgis::MarkerShape shape = parseEsriMarkerShape( symbolData.value( u
"style"_s ).toString() );
779 const double xOffset = symbolData.value( u
"xoffset"_s ).toDouble();
780 const double yOffset = symbolData.value( u
"yoffset"_s ).toDouble();
782 const QVariantMap outlineData = symbolData.value( u
"outline"_s ).toMap();
783 QColor lineColor =
convertColor( outlineData.value( u
"color"_s ) );
784 Qt::PenStyle penStyle =
convertLineStyle( outlineData.value( u
"style"_s ).toString() );
785 double penWidthInPoints = outlineData.value( u
"width"_s ).toDouble( &ok );
788 auto markerLayer = std::make_unique< QgsSimpleMarkerSymbolLayer >( shape, sizeInPoints, angleCW,
Qgis::ScaleMethod::ScaleArea, fillColor, lineColor );
791 markerLayer->setStrokeStyle( penStyle );
792 markerLayer->setStrokeWidth( penWidthInPoints );
793 markerLayer->setOffset( QPointF( xOffset, yOffset ) );
795 layers.append( markerLayer.release() );
797 auto symbol = std::make_unique< QgsMarkerSymbol >( layers );
801std::unique_ptr<QgsMarkerSymbol> QgsArcGisRestUtils::parseEsriPictureMarkerSymbolJson(
const QVariantMap &symbolData )
804 const double widthInPixels = symbolData.value( u
"width"_s ).toInt( &ok );
807 const double heightInPixels = symbolData.value( u
"height"_s ).toInt( &ok );
811 const double angleCCW = symbolData.value( u
"angle"_s ).toDouble( &ok );
816 const double xOffset = symbolData.value( u
"xoffset"_s ).toDouble();
817 const double yOffset = symbolData.value( u
"yoffset"_s ).toDouble();
821 QString symbolPath( symbolData.value( u
"imageData"_s ).toString() );
822 symbolPath.prepend(
"base64:"_L1 );
829 if ( !
qgsDoubleNear(
static_cast< double >( heightInPixels ) / widthInPixels, markerLayer->defaultAspectRatio() ) )
830 markerLayer->setFixedAspectRatio(
static_cast< double >( heightInPixels ) / widthInPixels );
832 markerLayer->setOffset( QPointF( xOffset, yOffset ) );
834 layers.append( markerLayer.release() );
836 auto symbol = std::make_unique< QgsMarkerSymbol >( layers );
840std::unique_ptr<QgsMarkerSymbol> QgsArcGisRestUtils::parseEsriTextMarkerSymbolJson(
const QVariantMap &symbolData )
844 const QString fontFamily = symbolData.value( u
"font"_s ).toMap().value( u
"family"_s ).toString();
846 const QString chr = symbolData.value( u
"text"_s ).toString();
848 const double pointSize = symbolData.value( u
"font"_s ).toMap().value( u
"size"_s ).toDouble();
850 const QColor color =
convertColor( symbolData.value( u
"color"_s ) );
852 const double esriAngle = symbolData.value( u
"angle"_s ).toDouble();
854 const double angle = 90.0 - esriAngle;
856 auto markerLayer = std::make_unique< QgsFontMarkerSymbolLayer >( fontFamily, chr, pointSize, color, angle );
858 QColor strokeColor =
convertColor( symbolData.value( u
"borderLineColor"_s ) );
859 markerLayer->setStrokeColor( strokeColor );
861 double borderLineSize = symbolData.value( u
"borderLineSize"_s ).toDouble();
862 markerLayer->setStrokeWidth( borderLineSize );
864 const QString fontStyle = symbolData.value( u
"font"_s ).toMap().value( u
"style"_s ).toString();
865 markerLayer->setFontStyle( fontStyle );
867 double xOffset = symbolData.value( u
"xoffset"_s ).toDouble();
868 double yOffset = symbolData.value( u
"yoffset"_s ).toDouble();
870 markerLayer->setOffset( QPointF( xOffset, yOffset ) );
879 QString horizontalAnchorPoint = symbolData.value( u
"horizontalAlignment"_s ).toString();
880 QString verticalAnchorPoint = symbolData.value( u
"verticalAlignment"_s ).toString();
882 if ( horizontalAnchorPoint == QString(
"center" ) )
886 else if ( horizontalAnchorPoint == QString(
"left" ) )
890 else if ( horizontalAnchorPoint == QString(
"right" ) )
895 if ( verticalAnchorPoint == QString(
"center" ) )
899 else if ( verticalAnchorPoint == QString(
"top" ) )
903 else if ( verticalAnchorPoint == QString(
"bottom" ) )
908 markerLayer->setHorizontalAnchorPoint( hAlign );
909 markerLayer->setVerticalAnchorPoint( vAlign );
911 layers.append( markerLayer.release() );
913 auto symbol = std::make_unique< QgsMarkerSymbol >( layers );
919 if ( labelingData.empty() )
926 for (
const QVariant &lbl : labelingData )
928 const QVariantMap labeling = lbl.toMap();
933 const QString placement = labeling.value( u
"labelPlacement"_s ).toString();
934 if ( placement ==
"esriServerPointLabelPlacementAboveCenter"_L1 )
939 else if ( placement ==
"esriServerPointLabelPlacementBelowCenter"_L1 )
944 else if ( placement ==
"esriServerPointLabelPlacementCenterCenter"_L1 )
949 else if ( placement ==
"esriServerPointLabelPlacementAboveLeft"_L1 )
954 else if ( placement ==
"esriServerPointLabelPlacementBelowLeft"_L1 )
959 else if ( placement ==
"esriServerPointLabelPlacementCenterLeft"_L1 )
964 else if ( placement ==
"esriServerPointLabelPlacementAboveRight"_L1 )
969 else if ( placement ==
"esriServerPointLabelPlacementBelowRight"_L1 )
974 else if ( placement ==
"esriServerPointLabelPlacementCenterRight"_L1 )
979 else if ( placement ==
"esriServerLinePlacementAboveAfter"_L1 ||
980 placement ==
"esriServerLinePlacementAboveStart"_L1 ||
981 placement ==
"esriServerLinePlacementAboveAlong"_L1 )
986 else if ( placement ==
"esriServerLinePlacementBelowAfter"_L1 ||
987 placement ==
"esriServerLinePlacementBelowStart"_L1 ||
988 placement ==
"esriServerLinePlacementBelowAlong"_L1 )
993 else if ( placement ==
"esriServerLinePlacementCenterAfter"_L1 ||
994 placement ==
"esriServerLinePlacementCenterStart"_L1 ||
995 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 >(
1178 minColor, maxColor,
false, gradientStops
1185 for (
int layer = 0; layer < symbol->symbolLayerCount(); ++layer )
1190 return std::make_unique< QgsSingleSymbolRenderer >( symbol.release() );
1194 QgsDebugError( u
"ESRI visualVariable type %1 is not currently supported"_s.arg( variableType ) );
1198 double lastValue = rendererData.value( u
"minValue"_s ).toDouble();
1200 auto graduatedRenderer = std::make_unique< QgsGraduatedSymbolRenderer >( attrName );
1202 graduatedRenderer->setSourceSymbol( symbol.release() );
1204 if ( esriMode ==
"esriClassifyDefinedInterval"_L1 )
1207 graduatedRenderer->setClassificationMethod( method );
1209 else if ( esriMode ==
"esriClassifyEqualInterval"_L1 )
1212 graduatedRenderer->setClassificationMethod( method );
1214 else if ( esriMode ==
"esriClassifyGeometricalInterval"_L1 )
1217 graduatedRenderer->setClassificationMethod( method );
1219 else if ( esriMode ==
"esriClassifyManual"_L1 )
1222 graduatedRenderer->setClassificationMethod( method );
1224 else if ( esriMode ==
"esriClassifyNaturalBreaks"_L1 )
1227 graduatedRenderer->setClassificationMethod( method );
1229 else if ( esriMode ==
"esriClassifyQuantile"_L1 )
1232 graduatedRenderer->setClassificationMethod( method );
1234 else if ( esriMode ==
"esriClassifyStandardDeviation"_L1 )
1237 graduatedRenderer->setClassificationMethod( method );
1239 else if ( !esriMode.isEmpty() )
1241 QgsDebugError( u
"ESRI classification mode %1 is not currently supported"_s.arg( esriMode ) );
1244 for (
const QVariant &classBreakInfo : classBreakInfos )
1246 const QVariantMap symbolData = classBreakInfo.toMap().value( u
"symbol"_s ).toMap();
1248 double classMaxValue = classBreakInfo.toMap().value( u
"classMaxValue"_s ).toDouble();
1249 const QString label = classBreakInfo.toMap().value( u
"label"_s ).toString();
1258 lastValue = classMaxValue;
1259 graduatedRenderer->addClass( range );
1262 return graduatedRenderer;
1264 else if ( type ==
"heatmap"_L1 )
1269 else if ( type ==
"vectorField"_L1 )
1279 QString expression = string;
1282 const thread_local QRegularExpression rx1 = QRegularExpression( u
"(?=([^\"\\\\]*(\\\\.|\"([^\"\\\\]*\\\\.)*[^\"\\\\]*\"))*[^\"]*$)(\\s|^)CONCAT(\\s|$)"_s );
1283 expression = expression.replace( rx1, u
"\\4||\\5"_s );
1285 const thread_local QRegularExpression rx2 = QRegularExpression( u
"(?=([^\"\\\\]*(\\\\.|\"([^\"\\\\]*\\\\.)*[^\"\\\\]*\"))*[^\"]*$)(\\s|^)NEWLINE(\\s|$)"_s );
1286 expression = expression.replace( rx2, u
"\\4'\\n'\\5"_s );
1289 const thread_local QRegularExpression rx3 = QRegularExpression( u
"\"(.*?(?<!\\\\))\""_s );
1290 expression = expression.replace( rx3, u
"'\\1'"_s );
1291 const thread_local QRegularExpression rx4 = QRegularExpression( u
"\\\\\""_s );
1292 expression = expression.replace( rx4, u
"\""_s );
1295 const thread_local QRegularExpression rx5 = QRegularExpression( u
"\\[([^]]*)\\]"_s );
1296 expression = expression.replace( rx5, u
"\"\\1\""_s );
1303 const QVariantList colorParts = colorData.toList();
1304 if ( colorParts.count() < 4 )
1307 int red = colorParts.at( 0 ).toInt();
1308 int green = colorParts.at( 1 ).toInt();
1309 int blue = colorParts.at( 2 ).toInt();
1310 int alpha = colorParts.at( 3 ).toInt();
1311 return QColor( red, green, blue, alpha );
1316 if ( style ==
"esriSLSSolid"_L1 )
1317 return Qt::SolidLine;
1318 else if ( style ==
"esriSLSDash"_L1 )
1319 return Qt::DashLine;
1320 else if ( style ==
"esriSLSDashDot"_L1 )
1321 return Qt::DashDotLine;
1322 else if ( style ==
"esriSLSDashDotDot"_L1 )
1323 return Qt::DashDotDotLine;
1324 else if ( style ==
"esriSLSDot"_L1 )
1326 else if ( style ==
"esriSLSNull"_L1 )
1329 return Qt::SolidLine;
1334 if ( style ==
"esriSFSBackwardDiagonal"_L1 )
1335 return Qt::BDiagPattern;
1336 else if ( style ==
"esriSFSCross"_L1 )
1337 return Qt::CrossPattern;
1338 else if ( style ==
"esriSFSDiagonalCross"_L1 )
1339 return Qt::DiagCrossPattern;
1340 else if ( style ==
"esriSFSForwardDiagonal"_L1 )
1341 return Qt::FDiagPattern;
1342 else if ( style ==
"esriSFSHorizontal"_L1 )
1343 return Qt::HorPattern;
1344 else if ( style ==
"esriSFSNull"_L1 )
1346 else if ( style ==
"esriSFSSolid"_L1 )
1347 return Qt::SolidPattern;
1348 else if ( style ==
"esriSFSVertical"_L1 )
1349 return Qt::VerPattern;
1351 return Qt::SolidPattern;
1359 QDateTime dt = QDateTime::fromMSecsSinceEpoch( value.toLongLong( &ok ) );
1362 QgsDebugError( u
"Invalid value %1 for datetime"_s.arg( value.toString() ) );
1374 const QVariantMap coords = value.toMap();
1379 const double xmin = coords.value( u
"xmin"_s ).toDouble( &ok );
1382 const double ymin = coords.value( u
"ymin"_s ).toDouble( &ok );
1385 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();
1464 res.insert( u
"spatialReference"_s,
crsToJson( crs ) );
1470QVariantMap QgsArcGisRestUtils::pointToJson(
const QgsPoint *point )
1474 data[u
"x"_s] = u
"NaN"_s;
1477 data[u
"x"_s] = point->
x();
1478 data[u
"y"_s] = point->
y();
1480 if ( point->
is3D() )
1481 data[u
"z"_s] = !std::isnan( point->
z() ) ? QVariant( point->
z() ) : QVariant( u
"NaN"_s );
1484 data[u
"m"_s] = !std::isnan( point->
m() ) ? QVariant( point->
m() ) : QVariant( u
"NaN"_s );
1489QVariantMap QgsArcGisRestUtils::multiPointToJson(
const QgsMultiPoint *multiPoint )
1492 const bool hasZ = multiPoint->
is3D();
1493 const bool hasM = multiPoint->
isMeasure();
1494 data[u
"hasM"_s] = hasM;
1495 data[u
"hasZ"_s] = hasZ;
1497 QVariantList pointsList;
1499 pointsList.reserve( size );
1501 QVariantList pointList;
1502 for (
int i = 0; i < size; ++i )
1504 const QgsPoint *point = multiPoint->
pointN( i );
1507 pointList.append( point->
x() );
1508 pointList.append( point->
y() );
1510 pointList.append( point->
z() );
1511 if ( hasM && !std::isnan( point->
m() ) )
1512 pointList.append( point->
m() );
1514 pointsList.push_back( pointList );
1517 data[u
"points"_s] = pointsList;
1521QVariantList QgsArcGisRestUtils::lineStringToJsonPath(
const QgsLineString *line )
1523 const bool hasZ = line->
is3D();
1526 QVariantList pointsList;
1528 pointsList.reserve( size );
1530 QVariantList pointList;
1531 const double *xData = line->
xData();
1532 const double *yData = line->
yData();
1533 const double *zData = hasZ ? line->
zData() :
nullptr;
1534 const double *mData = hasM ? line->
mData() :
nullptr;
1536 for (
int i = 0; i < size; ++i )
1539 pointList.append( *xData++ );
1540 pointList.append( *yData++ );
1543 pointList.append( *zData++ );
1545 if ( hasM && !std::isnan( *mData ) )
1546 pointList.append( *mData );
1550 pointsList.push_back( pointList );
1555QVariantList QgsArcGisRestUtils::curveToJsonCurve(
const QgsCurve *curve,
bool includeStart )
1557 const bool hasZ = curve->
is3D();
1560 auto pointToList = [hasZ, hasM](
const QgsPoint & point ) -> QVariantList
1562 QVariantList pointList;
1564 pointList.append( point.
x() );
1565 pointList.append( point.
y() );
1568 pointList.append( point.
z() );
1570 if ( hasM && !std::isnan( point.
m() ) )
1571 pointList.append( point.
m() );
1582 if ( !part.isEmpty() && !includeStart )
1591 if ( includeStart && !circularString->
isEmpty() )
1593 res.push_back( pointToList( circularString->
startPoint() ) );
1596 const int size = circularString->
numPoints();
1597 for (
int i = 1; i + 1 < size; i += 2 )
1600 QVariantMap curvePart;
1601 QVariantList curveList;
1602 curveList.push_back( pointToList( circularString->
pointN( i + 1 ) ) );
1604 curveList.push_back( pointToList( circularString->
pointN( i ) ) );
1606 curvePart.insert( u
"c"_s, curveList );
1607 res.push_back( curvePart );
1616 const int size = compoundCurve->
nCurves();
1617 for (
int i = 0; i < size; ++i )
1619 const QgsCurve *subCurve = compoundCurve->
curveAt( i );
1620 res.append( curveToJsonCurve( subCurve, i == 0 ) );
1631QVariantMap QgsArcGisRestUtils::lineStringToJson(
const QgsLineString *line )
1634 const bool hasZ = line->
is3D();
1636 data[u
"hasM"_s] = hasM;
1637 data[u
"hasZ"_s] = hasZ;
1639 const QVariantList pointsList = lineStringToJsonPath( line );
1641 QVariantList pointsData = QVariantList();
1642 pointsData.push_back( pointsList );
1643 data[u
"paths"_s] = pointsData;
1648QVariantMap QgsArcGisRestUtils::curveToJson(
const QgsCurve *curve )
1651 const bool hasZ = curve->
is3D();
1653 data[u
"hasM"_s] = hasM;
1654 data[u
"hasZ"_s] = hasZ;
1656 const QVariantList curveList = curveToJsonCurve( curve,
true );
1658 QVariantList curveData = QVariantList();
1659 curveData.push_back( curveList );
1660 data[u
"curvePaths"_s] = curveData;
1665QVariantMap QgsArcGisRestUtils::multiLineStringToJson(
const QgsMultiLineString *multiLine )
1668 const bool hasZ = multiLine->
is3D();
1669 const bool hasM = multiLine->
isMeasure();
1670 data[u
"hasM"_s] = hasM;
1671 data[u
"hasZ"_s] = hasZ;
1675 paths.reserve( size );
1676 for (
int i = 0; i < size; ++i )
1678 const QgsLineString *line = multiLine->
lineStringN( i );
1679 paths.push_back( lineStringToJsonPath( line ) );
1682 data[u
"paths"_s] = paths;
1686QVariantMap QgsArcGisRestUtils::multiCurveToJson(
const QgsMultiCurve *multiCurve )
1689 const bool hasZ = multiCurve->
is3D();
1690 const bool hasM = multiCurve->
isMeasure();
1691 data[u
"hasM"_s] = hasM;
1692 data[u
"hasZ"_s] = hasZ;
1696 paths.reserve( size );
1697 for (
int i = 0; i < size; ++i )
1699 const QgsCurve *curve = multiCurve->
curveN( i );
1700 paths.push_back( curveToJsonCurve( curve,
true ) );
1703 data[u
"curvePaths"_s] = paths;
1707QVariantList QgsArcGisRestUtils::polygonToJsonRings(
const QgsPolygon *polygon )
1711 rings.reserve( numInteriorRings + 1 );
1716 switch ( exterior->orientation() )
1719 rings.push_back( lineStringToJsonPath( exterior ) );
1724 std::unique_ptr< QgsLineString > reversed( exterior->reversed() );
1725 rings.push_back( lineStringToJsonPath( reversed.get() ) );
1733 for (
int i = 0; i < numInteriorRings; ++i )
1740 rings.push_back( lineStringToJsonPath( ring ) );
1745 std::unique_ptr< QgsLineString > reversed( ring->
reversed() );
1746 rings.push_back( lineStringToJsonPath( reversed.get() ) );
1756QVariantList QgsArcGisRestUtils::curvePolygonToJsonRings(
const QgsCurvePolygon *polygon )
1760 rings.reserve( numInteriorRings + 1 );
1765 switch ( exterior->orientation() )
1768 rings.push_back( curveToJsonCurve( exterior,
true ) );
1773 std::unique_ptr< QgsCurve > reversed( exterior->reversed() );
1774 rings.push_back( curveToJsonCurve( reversed.get(),
true ) );
1782 for (
int i = 0; i < numInteriorRings; ++i )
1789 rings.push_back( curveToJsonCurve( ring,
true ) );
1794 std::unique_ptr< QgsCurve > reversed( ring->
reversed() );
1795 rings.push_back( curveToJsonCurve( reversed.get(),
true ) );
1805QVariantMap QgsArcGisRestUtils::polygonToJson(
const QgsPolygon *polygon )
1808 const bool hasZ = polygon->
is3D();
1810 data[u
"hasM"_s] = hasM;
1811 data[u
"hasZ"_s] = hasZ;
1812 data[u
"rings"_s] = polygonToJsonRings( polygon );
1816QVariantMap QgsArcGisRestUtils::curvePolygonToJson(
const QgsCurvePolygon *polygon )
1819 const bool hasZ = polygon->
is3D();
1821 data[u
"hasM"_s] = hasM;
1822 data[u
"hasZ"_s] = hasZ;
1823 data[u
"curveRings"_s] = curvePolygonToJsonRings( polygon );
1827QVariantMap QgsArcGisRestUtils::multiPolygonToJson(
const QgsMultiPolygon *multiPolygon )
1830 const bool hasZ = multiPolygon->
is3D();
1831 const bool hasM = multiPolygon->
isMeasure();
1832 data[u
"hasM"_s] = hasM;
1833 data[u
"hasZ"_s] = hasZ;
1837 for (
int i = 0; i < size; ++i )
1839 const QgsPolygon *polygon = multiPolygon->
polygonN( i );
1840 rings.append( polygonToJsonRings( polygon ) );
1843 data[u
"rings"_s] = rings;
1847QVariantMap QgsArcGisRestUtils::multiSurfaceToJson(
const QgsMultiSurface *multiSurface )
1850 const bool hasZ = multiSurface->
is3D();
1851 const bool hasM = multiSurface->
isMeasure();
1852 data[u
"hasM"_s] = hasM;
1853 data[u
"hasZ"_s] = hasZ;
1857 for (
int i = 0; i < size; ++i )
1863 rings.append( curvePolygonToJsonRings( polygon ) );
1866 data[u
"curveRings"_s] = rings;
1876 const QString authid = crs.
authid();
1877 if ( !authid.isEmpty() )
1879 const thread_local QRegularExpression rxAuthid( u
"(\\w+):(\\d+)"_s );
1880 const QRegularExpressionMatch match = rxAuthid.match( authid );
1881 if ( match.hasMatch()
1883 ( match.captured( 1 ).compare(
"EPSG"_L1, Qt::CaseInsensitive ) == 0 )
1884 || ( match.captured( 1 ).compare(
"ESRI"_L1, Qt::CaseInsensitive ) == 0 )
1888 const QString wkid = match.captured( 2 );
1889 res.insert( u
"wkid"_s, wkid );
1908 QVariantMap attributes;
1910 for (
const QgsField &field : fields )
1912 QVariant value = feature.
attribute( field.name() );
1913 if ( value.userType() == qMetaTypeId< QgsUnsetAttributeValue >() )
1924 if ( !attributes.isEmpty() )
1926 res.insert( u
"attributes"_s, attributes );
1936 switch ( expectedType )
1938 case QMetaType::Type::QString:
1940 const QString escaped = variant.toString().replace(
'\\',
"\\\\"_L1 ).replace(
'"',
"\\\""_L1 );
1941 return QString( QUrl::toPercentEncoding( escaped,
"'" ) );
1944 case QMetaType::Type::QDateTime:
1945 case QMetaType::Type::QDate:
1947 switch ( variant.userType() )
1949 case QMetaType::Type::QDateTime:
1950 return variant.toDateTime().toMSecsSinceEpoch();
1952 case QMetaType::Type::QDate:
1954 if ( context.
timeZone().isValid() )
1955 return QDateTime( variant.toDate(), QTime( 0, 0, 0 ), context.
timeZone() ).toMSecsSinceEpoch();
1957 return QDateTime( variant.toDate(), QTime( 0, 0, 0 ) ).toMSecsSinceEpoch();
1972 res.insert( u
"name"_s, field.
name() );
1975 switch ( field.
type() )
1977 case QMetaType::Type::LongLong:
1978 fieldType = u
"esriFieldTypeInteger"_s;
1981 case QMetaType::Type::Int:
1982 fieldType = u
"esriFieldTypeSmallInteger"_s;
1985 case QMetaType::Type::Double:
1986 fieldType = u
"esriFieldTypeDouble"_s;
1989 case QMetaType::Type::QString:
1990 fieldType = u
"esriFieldTypeString"_s;
1993 case QMetaType::Type::QDateTime:
1994 case QMetaType::Type::QDate:
1995 fieldType = u
"esriFieldTypeDate"_s;
1998 case QMetaType::Type::QByteArray:
1999 fieldType = u
"esriFieldTypeBlob"_s;
2004 fieldType = u
"esriFieldTypeString"_s;
2007 res.insert( u
"type"_s, fieldType );
2009 if ( !field.
alias().isEmpty() )
2010 res.insert( u
"alias"_s, field.
alias() );
2014 res.insert( u
"nullable"_s, !notNullable );
2017 res.insert( u
"editable"_s,
true );
2024 if ( type.compare(
"FeatureServer"_L1, Qt::CaseInsensitive ) == 0 )
2026 else if ( type.compare(
"MapServer"_L1, Qt::CaseInsensitive ) == 0 )
2028 else if ( type.compare(
"ImageServer"_L1, Qt::CaseInsensitive ) == 0 )
2030 else if ( type.compare(
"GlobeServer"_L1, Qt::CaseInsensitive ) == 0 )
2032 else if ( type.compare(
"GPServer"_L1, Qt::CaseInsensitive ) == 0 )
2034 else if ( type.compare(
"GeocodeServer"_L1, Qt::CaseInsensitive ) == 0 )
2036 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