28using namespace Qt::StringLiterals;
37 return u
"esri_rest"_s;
42 return QObject::tr(
"ESRI REST JSON" );
52 QVariantMap symbolData;
53 if ( variant.type() == QVariant::Map )
55 symbolData = variant.toMap();
57 else if ( variant.type() == QVariant::String )
60 if ( v.type() == QVariant::Map )
62 symbolData = v.toMap();
65 if ( symbolData.isEmpty() )
68 const QString type = symbolData.value( u
"type"_s ).toString();
69 if ( type ==
"esriSMS"_L1 )
72 return parseEsriMarkerSymbolJson( symbolData );
74 else if ( type ==
"esriSLS"_L1 )
77 return parseEsriLineSymbolJson( symbolData );
79 else if ( type ==
"esriSFS"_L1 )
82 return parseEsriFillSymbolJson( symbolData );
84 else if ( type ==
"esriPFS"_L1 )
86 return parseEsriPictureFillSymbolJson( symbolData );
88 else if ( type ==
"esriPMS"_L1 )
91 return parseEsriPictureMarkerSymbolJson( symbolData );
93 else if ( type ==
"esriTS"_L1 )
95 return parseEsriTextMarkerSymbolJson( symbolData );
100std::unique_ptr<QgsLineSymbol> QgsSymbolConverterEsriRest::parseEsriLineSymbolJson(
const QVariantMap &symbolData )
102 const QColor lineColor =
convertColor( symbolData.value( u
"color"_s ) );
103 if ( !lineColor.isValid() )
107 const double widthInPoints = symbolData.value( u
"width"_s ).toDouble( &ok );
112 const Qt::PenStyle penStyle =
convertLineStyle( symbolData.value( u
"style"_s ).toString() );
113 auto lineLayer = std::make_unique< QgsSimpleLineSymbolLayer >( lineColor, widthInPoints, penStyle );
115 layers.append( lineLayer.release() );
117 auto symbol = std::make_unique< QgsLineSymbol >( layers );
121std::unique_ptr<QgsFillSymbol> QgsSymbolConverterEsriRest::parseEsriFillSymbolJson(
const QVariantMap &symbolData )
123 const QColor fillColor =
convertColor( symbolData.value( u
"color"_s ) );
124 const Qt::BrushStyle brushStyle =
convertFillStyle( symbolData.value( u
"style"_s ).toString() );
127 Qt::PenStyle penStyle = Qt::NoPen;
128 double penWidthInPoints = 0;
131 const QVariant outlineVariant = symbolData.value( u
"outline"_s );
134 const QVariantMap outlineData = outlineVariant.toMap();
135 lineColor =
convertColor( outlineData.value( u
"color"_s ) );
138 penWidthInPoints = outlineData.value( u
"width"_s ).toDouble( &ok );
142 auto fillLayer = std::make_unique< QgsSimpleFillSymbolLayer >( fillColor, brushStyle, lineColor, penStyle, penWidthInPoints );
144 layers.append( fillLayer.release() );
146 auto symbol = std::make_unique< QgsFillSymbol >( layers );
150std::unique_ptr<QgsFillSymbol> QgsSymbolConverterEsriRest::parseEsriPictureFillSymbolJson(
const QVariantMap &symbolData )
154 double widthInPixels = symbolData.value( u
"width"_s ).toInt( &ok );
158 const double xScale = symbolData.value( u
"xscale"_s ).toDouble( &ok );
160 widthInPixels *= xScale;
162 const double angleCCW = symbolData.value( u
"angle"_s ).toDouble( &ok );
167 const double xOffset = symbolData.value( u
"xoffset"_s ).toDouble();
168 const double yOffset = symbolData.value( u
"yoffset"_s ).toDouble();
170 QString symbolPath( symbolData.value( u
"imageData"_s ).toString() );
171 symbolPath.prepend(
"base64:"_L1 );
174 auto fillLayer = std::make_unique< QgsRasterFillSymbolLayer >( symbolPath );
175 fillLayer->setWidth( widthInPixels );
176 fillLayer->setAngle( angleCW );
178 fillLayer->setOffset( QPointF( xOffset, yOffset ) );
180 layers.append( fillLayer.release() );
183 const QVariant outlineVariant = symbolData.value( u
"outline"_s );
186 const QVariantMap outlineData = outlineVariant.toMap();
187 const QColor lineColor =
convertColor( outlineData.value( u
"color"_s ) );
188 const Qt::PenStyle penStyle =
convertLineStyle( outlineData.value( u
"style"_s ).toString() );
189 const double penWidthInPoints = outlineData.value( u
"width"_s ).toDouble( &ok );
191 auto lineLayer = std::make_unique< QgsSimpleLineSymbolLayer >( lineColor, penWidthInPoints, penStyle );
193 layers.append( lineLayer.release() );
196 auto symbol = std::make_unique< QgsFillSymbol >( layers );
200Qgis::MarkerShape QgsSymbolConverterEsriRest::parseEsriMarkerShape(
const QString &style )
202 if ( style ==
"esriSMSCircle"_L1 )
204 else if ( style ==
"esriSMSCross"_L1 )
206 else if ( style ==
"esriSMSDiamond"_L1 )
208 else if ( style ==
"esriSMSSquare"_L1 )
210 else if ( style ==
"esriSMSX"_L1 )
212 else if ( style ==
"esriSMSTriangle"_L1 )
218std::unique_ptr<QgsMarkerSymbol> QgsSymbolConverterEsriRest::parseEsriMarkerSymbolJson(
const QVariantMap &symbolData )
220 QColor fillColor =
convertColor( symbolData.value( u
"color"_s ) );
222 const double sizeInPoints = symbolData.value( u
"size"_s ).toDouble( &ok );
225 const double angleCCW = symbolData.value( u
"angle"_s ).toDouble( &ok );
230 const Qgis::MarkerShape shape = parseEsriMarkerShape( symbolData.value( u
"style"_s ).toString() );
232 const double xOffset = symbolData.value( u
"xoffset"_s ).toDouble();
233 const double yOffset = symbolData.value( u
"yoffset"_s ).toDouble();
236 Qt::PenStyle penStyle = Qt::NoPen;
237 double penWidthInPoints = 0;
240 const QVariant outlineVariant = symbolData.value( u
"outline"_s );
243 const QVariantMap outlineData = outlineVariant.toMap();
244 lineColor =
convertColor( outlineData.value( u
"color"_s ) );
246 penWidthInPoints = outlineData.value( u
"width"_s ).toDouble( &ok );
250 auto markerLayer = std::make_unique< QgsSimpleMarkerSymbolLayer >( shape, sizeInPoints, angleCW,
Qgis::ScaleMethod::ScaleArea, fillColor, lineColor );
253 markerLayer->setStrokeStyle( penStyle );
254 markerLayer->setStrokeWidth( penWidthInPoints );
255 markerLayer->setOffset( QPointF( xOffset, yOffset ) );
257 layers.append( markerLayer.release() );
259 auto symbol = std::make_unique< QgsMarkerSymbol >( layers );
263std::unique_ptr<QgsMarkerSymbol> QgsSymbolConverterEsriRest::parseEsriPictureMarkerSymbolJson(
const QVariantMap &symbolData )
266 const double widthInPixels = symbolData.value( u
"width"_s ).toInt( &ok );
269 const double heightInPixels = symbolData.value( u
"height"_s ).toInt( &ok );
273 const double angleCCW = symbolData.value( u
"angle"_s ).toDouble( &ok );
278 const double xOffset = symbolData.value( u
"xoffset"_s ).toDouble();
279 const double yOffset = symbolData.value( u
"yoffset"_s ).toDouble();
281 QString symbolPath( symbolData.value( u
"imageData"_s ).toString() );
282 symbolPath.prepend(
"base64:"_L1 );
289 if ( !
qgsDoubleNear(
static_cast< double >( heightInPixels ) / widthInPixels, markerLayer->defaultAspectRatio() ) )
290 markerLayer->setFixedAspectRatio(
static_cast< double >( heightInPixels ) / widthInPixels );
292 markerLayer->setOffset( QPointF( xOffset, yOffset ) );
294 layers.append( markerLayer.release() );
296 auto symbol = std::make_unique< QgsMarkerSymbol >( layers );
300std::unique_ptr<QgsMarkerSymbol> QgsSymbolConverterEsriRest::parseEsriTextMarkerSymbolJson(
const QVariantMap &symbolData )
304 const QString fontFamily = symbolData.value( u
"font"_s ).toMap().value( u
"family"_s ).toString();
305 const QString chr = symbolData.value( u
"text"_s ).toString();
306 const double pointSize = symbolData.value( u
"font"_s ).toMap().value( u
"size"_s ).toDouble();
307 const QColor color =
convertColor( symbolData.value( u
"color"_s ) );
308 const double esriAngle = symbolData.value( u
"angle"_s ).toDouble();
309 const double angle = 90.0 - esriAngle;
311 auto markerLayer = std::make_unique< QgsFontMarkerSymbolLayer >( fontFamily, chr, pointSize, color, angle );
313 QColor strokeColor =
convertColor( symbolData.value( u
"borderLineColor"_s ) );
314 markerLayer->setStrokeColor( strokeColor );
316 double borderLineSize = symbolData.value( u
"borderLineSize"_s ).toDouble();
317 markerLayer->setStrokeWidth( borderLineSize );
319 const QString fontStyle = symbolData.value( u
"font"_s ).toMap().value( u
"style"_s ).toString();
320 markerLayer->setFontStyle( fontStyle );
322 double xOffset = symbolData.value( u
"xoffset"_s ).toDouble();
323 double yOffset = symbolData.value( u
"yoffset"_s ).toDouble();
325 markerLayer->setOffset( QPointF( xOffset, yOffset ) );
334 QString horizontalAnchorPoint = symbolData.value( u
"horizontalAlignment"_s ).toString();
335 QString verticalAnchorPoint = symbolData.value( u
"verticalAlignment"_s ).toString();
337 if ( horizontalAnchorPoint == QString(
"center" ) )
341 else if ( horizontalAnchorPoint == QString(
"left" ) )
345 else if ( horizontalAnchorPoint == QString(
"right" ) )
350 if ( verticalAnchorPoint == QString(
"center" ) )
354 else if ( verticalAnchorPoint == QString(
"top" ) )
358 else if ( verticalAnchorPoint == QString(
"bottom" ) )
363 markerLayer->setHorizontalAnchorPoint( hAlign );
364 markerLayer->setVerticalAnchorPoint( vAlign );
366 layers.append( markerLayer.release() );
368 auto symbol = std::make_unique< QgsMarkerSymbol >( layers );
374 const QVariantList colorParts = colorData.toList();
375 if ( colorParts.count() < 4 )
378 const int red = colorParts.at( 0 ).toInt();
379 const int green = colorParts.at( 1 ).toInt();
380 const int blue = colorParts.at( 2 ).toInt();
381 const int alpha = colorParts.at( 3 ).toInt();
382 return QColor( red, green, blue, alpha );
387 if ( style ==
"esriSLSSolid"_L1 )
388 return Qt::SolidLine;
389 else if ( style ==
"esriSLSDash"_L1 )
391 else if ( style ==
"esriSLSDashDot"_L1 )
392 return Qt::DashDotLine;
393 else if ( style ==
"esriSLSDashDotDot"_L1 )
394 return Qt::DashDotDotLine;
395 else if ( style ==
"esriSLSDot"_L1 )
397 else if ( style ==
"esriSLSNull"_L1 )
400 return Qt::SolidLine;
405 if ( style ==
"esriSFSBackwardDiagonal"_L1 )
406 return Qt::BDiagPattern;
407 else if ( style ==
"esriSFSCross"_L1 )
408 return Qt::CrossPattern;
409 else if ( style ==
"esriSFSDiagonalCross"_L1 )
410 return Qt::DiagCrossPattern;
411 else if ( style ==
"esriSFSForwardDiagonal"_L1 )
412 return Qt::FDiagPattern;
413 else if ( style ==
"esriSFSHorizontal"_L1 )
414 return Qt::HorPattern;
415 else if ( style ==
"esriSFSNull"_L1 )
417 else if ( style ==
"esriSFSSolid"_L1 )
418 return Qt::SolidPattern;
419 else if ( style ==
"esriSFSVertical"_L1 )
420 return Qt::VerPattern;
422 return Qt::SolidPattern;
@ ScaleArea
Calculate scale by the area.
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.
QFlags< SymbolConverterCapability > SymbolConverterCapabilities
Symbol converter capabilities.
@ Points
Points (e.g., for font sizes).
@ ReadSymbol
Allows reading symbols from variants.
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.
static QVariant parseJson(const std::string &jsonString)
Converts JSON jsonString to a QVariant, in case of parsing error an invalid QVariant is returned and ...
Custom exception class which is raised when an operation is not supported.
Represents the context in which a QgsSymbolConverter conversion occurs.
QString formatName() const override
Returns a translated, user-friendly name for the converter's data format.
static Qt::PenStyle convertLineStyle(const QString &style)
Converts an ESRI line style to a Qt pen style.
std::unique_ptr< QgsSymbol > createSymbol(const QVariant &variant, QgsSymbolConverterContext &context) const override
Creates a new QgsSymbol from a QVariant representation.
QString name() const override
Returns the unique name for the converter.
static Qt::BrushStyle convertFillStyle(const QString &style)
Converts an ESRI fill style to a Qt brush style.
QVariant toVariant(const QgsSymbol *symbol, QgsSymbolConverterContext &context) const override
Converts a symbol into a QVariant representation.
static QColor convertColor(const QVariant &data)
Converts ESRI JSON color data to a QColor object.
Qgis::SymbolConverterCapabilities capabilities() const override
Returns the capabilities of the converter.
Abstract base class for all rendered symbols.
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
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).
QList< QgsSymbolLayer * > QgsSymbolLayerList