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() );
126 const QVariantMap outlineData = symbolData.value( u
"outline"_s ).toMap();
127 const QColor lineColor =
convertColor( outlineData.value( u
"color"_s ) );
128 const Qt::PenStyle penStyle =
convertLineStyle( outlineData.value( u
"style"_s ).toString() );
130 const double penWidthInPoints = outlineData.value( u
"width"_s ).toDouble( &ok );
133 auto fillLayer = std::make_unique< QgsSimpleFillSymbolLayer >( fillColor, brushStyle, lineColor, penStyle, penWidthInPoints );
135 layers.append( fillLayer.release() );
137 auto symbol = std::make_unique< QgsFillSymbol >( layers );
141std::unique_ptr<QgsFillSymbol> QgsSymbolConverterEsriRest::parseEsriPictureFillSymbolJson(
const QVariantMap &symbolData )
145 double widthInPixels = symbolData.value( u
"width"_s ).toInt( &ok );
149 const double xScale = symbolData.value( u
"xscale"_s ).toDouble( &ok );
151 widthInPixels *= xScale;
153 const double angleCCW = symbolData.value( u
"angle"_s ).toDouble( &ok );
158 const double xOffset = symbolData.value( u
"xoffset"_s ).toDouble();
159 const double yOffset = symbolData.value( u
"yoffset"_s ).toDouble();
161 QString symbolPath( symbolData.value( u
"imageData"_s ).toString() );
162 symbolPath.prepend(
"base64:"_L1 );
165 auto fillLayer = std::make_unique< QgsRasterFillSymbolLayer >( symbolPath );
166 fillLayer->setWidth( widthInPixels );
167 fillLayer->setAngle( angleCW );
169 fillLayer->setOffset( QPointF( xOffset, yOffset ) );
171 layers.append( fillLayer.release() );
173 const QVariantMap outlineData = symbolData.value( u
"outline"_s ).toMap();
174 const QColor lineColor =
convertColor( outlineData.value( u
"color"_s ) );
175 const Qt::PenStyle penStyle =
convertLineStyle( outlineData.value( u
"style"_s ).toString() );
176 const double penWidthInPoints = outlineData.value( u
"width"_s ).toDouble( &ok );
178 auto lineLayer = std::make_unique< QgsSimpleLineSymbolLayer >( lineColor, penWidthInPoints, penStyle );
180 layers.append( lineLayer.release() );
182 auto symbol = std::make_unique< QgsFillSymbol >( layers );
186Qgis::MarkerShape QgsSymbolConverterEsriRest::parseEsriMarkerShape(
const QString &style )
188 if ( style ==
"esriSMSCircle"_L1 )
190 else if ( style ==
"esriSMSCross"_L1 )
192 else if ( style ==
"esriSMSDiamond"_L1 )
194 else if ( style ==
"esriSMSSquare"_L1 )
196 else if ( style ==
"esriSMSX"_L1 )
198 else if ( style ==
"esriSMSTriangle"_L1 )
204std::unique_ptr<QgsMarkerSymbol> QgsSymbolConverterEsriRest::parseEsriMarkerSymbolJson(
const QVariantMap &symbolData )
206 QColor fillColor =
convertColor( symbolData.value( u
"color"_s ) );
208 const double sizeInPoints = symbolData.value( u
"size"_s ).toDouble( &ok );
211 const double angleCCW = symbolData.value( u
"angle"_s ).toDouble( &ok );
216 const Qgis::MarkerShape shape = parseEsriMarkerShape( symbolData.value( u
"style"_s ).toString() );
218 const double xOffset = symbolData.value( u
"xoffset"_s ).toDouble();
219 const double yOffset = symbolData.value( u
"yoffset"_s ).toDouble();
221 const QVariantMap outlineData = symbolData.value( u
"outline"_s ).toMap();
222 const QColor lineColor =
convertColor( outlineData.value( u
"color"_s ) );
223 const Qt::PenStyle penStyle =
convertLineStyle( outlineData.value( u
"style"_s ).toString() );
224 double penWidthInPoints = outlineData.value( u
"width"_s ).toDouble( &ok );
227 auto markerLayer = std::make_unique< QgsSimpleMarkerSymbolLayer >( shape, sizeInPoints, angleCW,
Qgis::ScaleMethod::ScaleArea, fillColor, lineColor );
230 markerLayer->setStrokeStyle( penStyle );
231 markerLayer->setStrokeWidth( penWidthInPoints );
232 markerLayer->setOffset( QPointF( xOffset, yOffset ) );
234 layers.append( markerLayer.release() );
236 auto symbol = std::make_unique< QgsMarkerSymbol >( layers );
240std::unique_ptr<QgsMarkerSymbol> QgsSymbolConverterEsriRest::parseEsriPictureMarkerSymbolJson(
const QVariantMap &symbolData )
243 const double widthInPixels = symbolData.value( u
"width"_s ).toInt( &ok );
246 const double heightInPixels = symbolData.value( u
"height"_s ).toInt( &ok );
250 const double angleCCW = symbolData.value( u
"angle"_s ).toDouble( &ok );
255 const double xOffset = symbolData.value( u
"xoffset"_s ).toDouble();
256 const double yOffset = symbolData.value( u
"yoffset"_s ).toDouble();
258 QString symbolPath( symbolData.value( u
"imageData"_s ).toString() );
259 symbolPath.prepend(
"base64:"_L1 );
266 if ( !
qgsDoubleNear(
static_cast< double >( heightInPixels ) / widthInPixels, markerLayer->defaultAspectRatio() ) )
267 markerLayer->setFixedAspectRatio(
static_cast< double >( heightInPixels ) / widthInPixels );
269 markerLayer->setOffset( QPointF( xOffset, yOffset ) );
271 layers.append( markerLayer.release() );
273 auto symbol = std::make_unique< QgsMarkerSymbol >( layers );
277std::unique_ptr<QgsMarkerSymbol> QgsSymbolConverterEsriRest::parseEsriTextMarkerSymbolJson(
const QVariantMap &symbolData )
281 const QString fontFamily = symbolData.value( u
"font"_s ).toMap().value( u
"family"_s ).toString();
282 const QString chr = symbolData.value( u
"text"_s ).toString();
283 const double pointSize = symbolData.value( u
"font"_s ).toMap().value( u
"size"_s ).toDouble();
284 const QColor color =
convertColor( symbolData.value( u
"color"_s ) );
285 const double esriAngle = symbolData.value( u
"angle"_s ).toDouble();
286 const double angle = 90.0 - esriAngle;
288 auto markerLayer = std::make_unique< QgsFontMarkerSymbolLayer >( fontFamily, chr, pointSize, color, angle );
290 QColor strokeColor =
convertColor( symbolData.value( u
"borderLineColor"_s ) );
291 markerLayer->setStrokeColor( strokeColor );
293 double borderLineSize = symbolData.value( u
"borderLineSize"_s ).toDouble();
294 markerLayer->setStrokeWidth( borderLineSize );
296 const QString fontStyle = symbolData.value( u
"font"_s ).toMap().value( u
"style"_s ).toString();
297 markerLayer->setFontStyle( fontStyle );
299 double xOffset = symbolData.value( u
"xoffset"_s ).toDouble();
300 double yOffset = symbolData.value( u
"yoffset"_s ).toDouble();
302 markerLayer->setOffset( QPointF( xOffset, yOffset ) );
311 QString horizontalAnchorPoint = symbolData.value( u
"horizontalAlignment"_s ).toString();
312 QString verticalAnchorPoint = symbolData.value( u
"verticalAlignment"_s ).toString();
314 if ( horizontalAnchorPoint == QString(
"center" ) )
318 else if ( horizontalAnchorPoint == QString(
"left" ) )
322 else if ( horizontalAnchorPoint == QString(
"right" ) )
327 if ( verticalAnchorPoint == QString(
"center" ) )
331 else if ( verticalAnchorPoint == QString(
"top" ) )
335 else if ( verticalAnchorPoint == QString(
"bottom" ) )
340 markerLayer->setHorizontalAnchorPoint( hAlign );
341 markerLayer->setVerticalAnchorPoint( vAlign );
343 layers.append( markerLayer.release() );
345 auto symbol = std::make_unique< QgsMarkerSymbol >( layers );
351 const QVariantList colorParts = colorData.toList();
352 if ( colorParts.count() < 4 )
355 const int red = colorParts.at( 0 ).toInt();
356 const int green = colorParts.at( 1 ).toInt();
357 const int blue = colorParts.at( 2 ).toInt();
358 const int alpha = colorParts.at( 3 ).toInt();
359 return QColor( red, green, blue, alpha );
364 if ( style ==
"esriSLSSolid"_L1 )
365 return Qt::SolidLine;
366 else if ( style ==
"esriSLSDash"_L1 )
368 else if ( style ==
"esriSLSDashDot"_L1 )
369 return Qt::DashDotLine;
370 else if ( style ==
"esriSLSDashDotDot"_L1 )
371 return Qt::DashDotDotLine;
372 else if ( style ==
"esriSLSDot"_L1 )
374 else if ( style ==
"esriSLSNull"_L1 )
377 return Qt::SolidLine;
382 if ( style ==
"esriSFSBackwardDiagonal"_L1 )
383 return Qt::BDiagPattern;
384 else if ( style ==
"esriSFSCross"_L1 )
385 return Qt::CrossPattern;
386 else if ( style ==
"esriSFSDiagonalCross"_L1 )
387 return Qt::DiagCrossPattern;
388 else if ( style ==
"esriSFSForwardDiagonal"_L1 )
389 return Qt::FDiagPattern;
390 else if ( style ==
"esriSFSHorizontal"_L1 )
391 return Qt::HorPattern;
392 else if ( style ==
"esriSFSNull"_L1 )
394 else if ( style ==
"esriSFSSolid"_L1 )
395 return Qt::SolidPattern;
396 else if ( style ==
"esriSFSVertical"_L1 )
397 return Qt::VerPattern;
399 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.
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