QGIS API Documentation 3.99.0-Master (2fe06baccd8)
Loading...
Searching...
No Matches
qgsellipsesymbollayer.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsellipsesymbollayer.cpp
3 ---------------------
4 begin : June 2011
5 copyright : (C) 2011 by Marco Hugentobler
6 email : marco dot hugentobler at sourcepole dot ch
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
17
18#include "qgscolorutils.h"
19#include "qgsdxfexport.h"
20#include "qgsfeature.h"
21#include "qgslogger.h"
22#include "qgsproperty.h"
23#include "qgsrendercontext.h"
24#include "qgssldexportcontext.h"
25#include "qgssymbollayerutils.h"
26#include "qgsunittypes.h"
27
28#include <QDomDocument>
29#include <QDomElement>
30#include <QPainter>
31#include <QSet>
32
34 : mStrokeColor( QColor( 35, 35, 35 ) )
35{
36 mColor = Qt::white;
37 mPen.setColor( mStrokeColor );
38 mPen.setStyle( mStrokeStyle );
39 mPen.setJoinStyle( mPenJoinStyle );
40 mPen.setWidth( 1.0 );
41 mBrush.setColor( mColor );
42 mBrush.setStyle( Qt::SolidPattern );
43 mOffset = QPointF( 0, 0 );
44 mAngle = 0;
45}
46
48
50{
52 if ( properties.contains( QStringLiteral( "symbol_name" ) ) )
53 {
54 layer->setShape( decodeShape( properties[ QStringLiteral( "symbol_name" )].toString() ) );
55 }
56 if ( properties.contains( QStringLiteral( "size" ) ) )
57 {
58 layer->setSize( properties[QStringLiteral( "size" )].toDouble() );
59 }
60 if ( properties.contains( QStringLiteral( "size_unit" ) ) )
61 {
62 layer->setSizeUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "size_unit" )].toString() ) );
63 }
64 if ( properties.contains( QStringLiteral( "size_map_unit_scale" ) ) )
65 {
66 layer->setSizeMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "size_map_unit_scale" )].toString() ) );
67 }
68 if ( properties.contains( QStringLiteral( "symbol_width" ) ) )
69 {
70 layer->setSymbolWidth( properties[QStringLiteral( "symbol_width" )].toDouble() );
71 }
72 if ( properties.contains( QStringLiteral( "symbol_width_unit" ) ) )
73 {
74 layer->setSymbolWidthUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "symbol_width_unit" )].toString() ) );
75 }
76 if ( properties.contains( QStringLiteral( "symbol_width_map_unit_scale" ) ) )
77 {
78 layer->setSymbolWidthMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "symbol_width_map_unit_scale" )].toString() ) );
79 }
80 if ( properties.contains( QStringLiteral( "symbol_height" ) ) )
81 {
82 layer->setSymbolHeight( properties[QStringLiteral( "symbol_height" )].toDouble() );
83 }
84 if ( properties.contains( QStringLiteral( "symbol_height_unit" ) ) )
85 {
86 layer->setSymbolHeightUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "symbol_height_unit" )].toString() ) );
87 }
88 if ( properties.contains( QStringLiteral( "symbol_height_map_unit_scale" ) ) )
89 {
90 layer->setSymbolHeightMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "symbol_height_map_unit_scale" )].toString() ) );
91 }
92 if ( properties.contains( QStringLiteral( "angle" ) ) )
93 {
94 layer->setAngle( properties[QStringLiteral( "angle" )].toDouble() );
95 }
96 if ( properties.contains( QStringLiteral( "outline_style" ) ) )
97 {
98 layer->setStrokeStyle( QgsSymbolLayerUtils::decodePenStyle( properties[QStringLiteral( "outline_style" )].toString() ) );
99 }
100 else if ( properties.contains( QStringLiteral( "line_style" ) ) )
101 {
102 layer->setStrokeStyle( QgsSymbolLayerUtils::decodePenStyle( properties[QStringLiteral( "line_style" )].toString() ) );
103 }
104 if ( properties.contains( QStringLiteral( "joinstyle" ) ) )
105 {
106 layer->setPenJoinStyle( QgsSymbolLayerUtils::decodePenJoinStyle( properties[QStringLiteral( "joinstyle" )].toString() ) );
107 }
108 if ( properties.contains( QStringLiteral( "cap_style" ) ) )
109 {
110 layer->setPenCapStyle( QgsSymbolLayerUtils::decodePenCapStyle( properties[QStringLiteral( "cap_style" )].toString() ) );
111 }
112 if ( properties.contains( QStringLiteral( "outline_width" ) ) )
113 {
114 layer->setStrokeWidth( properties[QStringLiteral( "outline_width" )].toDouble() );
115 }
116 else if ( properties.contains( QStringLiteral( "line_width" ) ) )
117 {
118 layer->setStrokeWidth( properties[QStringLiteral( "line_width" )].toDouble() );
119 }
120 if ( properties.contains( QStringLiteral( "outline_width_unit" ) ) )
121 {
122 layer->setStrokeWidthUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "outline_width_unit" )].toString() ) );
123 }
124 else if ( properties.contains( QStringLiteral( "line_width_unit" ) ) )
125 {
126 layer->setStrokeWidthUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "line_width_unit" )].toString() ) );
127 }
128 if ( properties.contains( QStringLiteral( "outline_width_map_unit_scale" ) ) )
129 {
130 layer->setStrokeWidthMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "outline_width_map_unit_scale" )].toString() ) );
131 }
132 if ( properties.contains( QStringLiteral( "fill_color" ) ) )
133 {
134 //pre 2.5 projects used "fill_color"
135 layer->setFillColor( QgsColorUtils::colorFromString( properties[QStringLiteral( "fill_color" )].toString() ) );
136 }
137 else if ( properties.contains( QStringLiteral( "color" ) ) )
138 {
139 layer->setFillColor( QgsColorUtils::colorFromString( properties[QStringLiteral( "color" )].toString() ) );
140 }
141 if ( properties.contains( QStringLiteral( "outline_color" ) ) )
142 {
143 layer->setStrokeColor( QgsColorUtils::colorFromString( properties[QStringLiteral( "outline_color" )].toString() ) );
144 }
145 else if ( properties.contains( QStringLiteral( "line_color" ) ) )
146 {
147 layer->setStrokeColor( QgsColorUtils::colorFromString( properties[QStringLiteral( "line_color" )].toString() ) );
148 }
149 if ( properties.contains( QStringLiteral( "offset" ) ) )
150 {
151 layer->setOffset( QgsSymbolLayerUtils::decodePoint( properties[QStringLiteral( "offset" )].toString() ) );
152 }
153 if ( properties.contains( QStringLiteral( "offset_unit" ) ) )
154 {
155 layer->setOffsetUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "offset_unit" )].toString() ) );
156 }
157 if ( properties.contains( QStringLiteral( "offset_map_unit_scale" ) ) )
158 {
159 layer->setOffsetMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "offset_map_unit_scale" )].toString() ) );
160 }
161 if ( properties.contains( QStringLiteral( "horizontal_anchor_point" ) ) )
162 {
163 layer->setHorizontalAnchorPoint( static_cast< Qgis::HorizontalAnchorPoint >( properties[ QStringLiteral( "horizontal_anchor_point" )].toInt() ) );
164 }
165 if ( properties.contains( QStringLiteral( "vertical_anchor_point" ) ) )
166 {
167 layer->setVerticalAnchorPoint( static_cast< Qgis::VerticalAnchorPoint >( properties[ QStringLiteral( "vertical_anchor_point" )].toInt() ) );
168 }
169
170 //data defined properties
172
173 return layer;
174}
175
177{
178 double scaledWidth = mSymbolWidth;
179 double scaledHeight = mSymbolHeight;
180
181 QColor brushColor = mColor;
182 brushColor.setAlphaF( brushColor.alphaF() * context.opacity() );
183 mBrush.setColor( brushColor );
184
185 QColor penColor = mStrokeColor;
186 penColor.setAlphaF( penColor.alphaF() * context.opacity() );
187 mPen.setColor( penColor );
188
189 bool ok;
191 {
192 context.setOriginalValueVariable( mStrokeWidth );
194 if ( !QgsVariantUtils::isNull( exprVal ) )
195 {
196 double width = exprVal.toDouble( &ok );
197 if ( ok )
198 {
199 width = context.renderContext().convertToPainterUnits( width, mStrokeWidthUnit, mStrokeWidthMapUnitScale );
200 mPen.setWidthF( width );
201 mSelPen.setWidthF( width );
202 }
203 }
204 }
205
207 {
210 if ( !QgsVariantUtils::isNull( exprVal ) )
211 {
212 mPen.setStyle( QgsSymbolLayerUtils::decodePenStyle( exprVal.toString() ) );
213 mSelPen.setStyle( mPen.style() );
214 }
215 }
216
218 {
221 if ( !QgsVariantUtils::isNull( exprVal ) )
222 {
223 mPen.setJoinStyle( QgsSymbolLayerUtils::decodePenJoinStyle( exprVal.toString() ) );
224 mSelPen.setJoinStyle( mPen.joinStyle() );
225 }
226 }
227
229 {
231 const QString style = mDataDefinedProperties.valueAsString( QgsSymbolLayer::Property::CapStyle, context.renderContext().expressionContext(), QString(), &ok );
232 if ( ok )
233 {
234 mPen.setCapStyle( QgsSymbolLayerUtils::decodePenCapStyle( style ) );
235 mSelPen.setCapStyle( QgsSymbolLayerUtils::decodePenCapStyle( style ) );
236 }
237 }
238
240 {
243 brushColor.setAlphaF( brushColor.alphaF() * context.opacity() );
244 mBrush.setColor( brushColor );
245 }
246
248 {
250 QColor penColor = mDataDefinedProperties.valueAsColor( QgsSymbolLayer::Property::StrokeColor, context.renderContext().expressionContext(), mStrokeColor );
251 penColor.setAlphaF( penColor.alphaF() * context.opacity() );
252 mPen.setColor( penColor );
253 }
254
257 {
259 const QVariant exprVal = mDataDefinedProperties.value( QgsSymbolLayer::Property::Name, context.renderContext().expressionContext() );
260 if ( !QgsVariantUtils::isNull( exprVal ) )
261 {
262 shape = decodeShape( exprVal.toString() );
263 }
264 preparePath( shape, context, &scaledWidth, &scaledHeight, context.feature() );
265 }
266
267 //offset and rotation
268 bool hasDataDefinedRotation = false;
269 QPointF offset;
270 double angle = 0;
271 calculateOffsetAndRotation( context, scaledWidth, scaledHeight, hasDataDefinedRotation, offset, angle );
272
273 QPainter *p = context.renderContext().painter();
274 if ( !p )
275 {
276 return;
277 }
278
279 QTransform transform;
280 transform.translate( point.x() + offset.x(), point.y() + offset.y() );
281 if ( !qgsDoubleNear( angle, 0.0 ) )
282 {
283 transform.rotate( angle );
284 }
285
286 const bool useSelectedColor = shouldRenderUsingSelectionColor( context );
287 if ( shapeIsFilled( shape ) )
288 {
289 p->setPen( useSelectedColor ? mSelPen : mPen );
290 p->setBrush( useSelectedColor ? mSelBrush : mBrush );
291 }
292 else
293 {
294 p->setPen( useSelectedColor ? mSelPen : mPen );
295 p->setBrush( QBrush() );
296 }
297 p->drawPath( transform.map( mPainterPath ) );
298}
299
300
301void QgsEllipseSymbolLayer::calculateOffsetAndRotation( QgsSymbolRenderContext &context,
302 double scaledWidth,
303 double scaledHeight,
304 bool &hasDataDefinedRotation,
305 QPointF &offset,
306 double &angle ) const
307{
308 double offsetX = 0;
309 double offsetY = 0;
310 markerOffset( context, scaledWidth, scaledHeight, mSymbolWidthUnit, mSymbolHeightUnit, offsetX, offsetY, mSymbolWidthMapUnitScale, mSymbolHeightMapUnitScale );
311 offset = QPointF( offsetX, offsetY );
312
313//priority for rotation: 1. data defined symbol level, 2. symbol layer rotation (mAngle)
314 const bool ok = true;
316 bool usingDataDefinedRotation = false;
318 {
321 usingDataDefinedRotation = ok;
322 }
323
324 hasDataDefinedRotation = context.renderHints() & Qgis::SymbolRenderHint::DynamicRotation || usingDataDefinedRotation;
325 if ( hasDataDefinedRotation )
326 {
327 // For non-point markers, "dataDefinedRotation" means following the
328 // shape (shape-data defined). For them, "field-data defined" does
329 // not work at all. TODO: if "field-data defined" ever gets implemented
330 // we'll need a way to distinguish here between the two, possibly
331 // using another flag in renderHints()
332 const QgsFeature *f = context.feature();
333 if ( f )
334 {
335 const QgsGeometry g = f->geometry();
336 if ( !g.isNull() && g.type() == Qgis::GeometryType::Point )
337 {
338 const QgsMapToPixel &m2p = context.renderContext().mapToPixel();
339 angle += m2p.mapRotation();
340 }
341 }
342 }
343
344 if ( angle )
346}
347
349{
350 return QStringLiteral( "EllipseMarker" );
351}
352
357
359{
360 QgsMarkerSymbolLayer::startRender( context ); // get anchor point expressions
361 if ( !context.feature() || !dataDefinedProperties().hasActiveProperties() )
362 {
363 preparePath( mShape, context );
364 }
365 mPen.setColor( mStrokeColor );
366 mPen.setStyle( mStrokeStyle );
367 mPen.setJoinStyle( mPenJoinStyle );
368 mPen.setCapStyle( mPenCapStyle );
369 mPen.setWidthF( context.renderContext().convertToPainterUnits( mStrokeWidth, mStrokeWidthUnit, mStrokeWidthMapUnitScale ) );
370 mBrush.setColor( mColor );
371
372 QColor selBrushColor = context.renderContext().selectionColor();
373 QColor selPenColor = selBrushColor == mColor ? selBrushColor : mStrokeColor;
374 if ( context.opacity() < 1 && !SELECTION_IS_OPAQUE )
375 {
376 selBrushColor.setAlphaF( context.opacity() );
377 selPenColor.setAlphaF( context.opacity() );
378 }
379 mSelBrush = QBrush( selBrushColor );
380 mSelPen = QPen( !shapeIsFilled( mShape ) ? selBrushColor : selPenColor );
381 mSelPen.setStyle( mStrokeStyle );
382 mSelPen.setWidthF( context.renderContext().convertToPainterUnits( mStrokeWidth, mStrokeWidthUnit, mStrokeWidthMapUnitScale ) );
383}
384
388
390{
396 m->setShape( mShape );
397 m->setSymbolWidth( mSymbolWidth );
398 m->setSymbolHeight( mSymbolHeight );
399 m->setStrokeStyle( mStrokeStyle );
400 m->setOffset( mOffset );
401 m->setStrokeStyle( mStrokeStyle );
402 m->setPenJoinStyle( mPenJoinStyle );
403 m->setPenCapStyle( mPenCapStyle );
404 m->setStrokeWidth( mStrokeWidth );
405 m->setColor( color() );
406 m->setStrokeColor( mStrokeColor );
407 m->setSymbolWidthUnit( mSymbolWidthUnit );
408 m->setSymbolWidthMapUnitScale( mSymbolWidthMapUnitScale );
409 m->setSymbolHeightUnit( mSymbolHeightUnit );
410 m->setSymbolHeightMapUnitScale( mSymbolHeightMapUnitScale );
411 m->setStrokeWidthUnit( mStrokeWidthUnit );
412 m->setStrokeWidthMapUnitScale( mStrokeWidthMapUnitScale );
413 m->setAngle( mAngle );
416
418 copyPaintEffect( m );
419 return m;
420}
421
422void QgsEllipseSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const
423{
424 QgsSldExportContext context;
425 context.setExtraProperties( props );
426 toSld( doc, element, context );
427}
428
429bool QgsEllipseSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, QgsSldExportContext &context ) const
430{
431 QDomElement symbolizerElem = doc.createElement( QStringLiteral( "se:PointSymbolizer" ) );
432 const QVariantMap props = context.extraProperties();
433 if ( !props.value( QStringLiteral( "uom" ), QString() ).toString().isEmpty() )
434 symbolizerElem.setAttribute( QStringLiteral( "uom" ), props.value( QStringLiteral( "uom" ), QString() ).toString() );
435 element.appendChild( symbolizerElem );
436
437 // <Geometry>
438 QgsSymbolLayerUtils::createGeometryElement( doc, symbolizerElem, props.value( QStringLiteral( "geom" ), QString() ).toString(), context );
439
440 return writeSldMarker( doc, symbolizerElem, context );
441}
442
443void QgsEllipseSymbolLayer::writeSldMarker( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const
444{
445 QgsSldExportContext context;
446 context.setExtraProperties( props );
447 writeSldMarker( doc, element, context );
448}
449
450bool QgsEllipseSymbolLayer::writeSldMarker( QDomDocument &doc, QDomElement &element, QgsSldExportContext &context ) const
451{
452 // <Graphic>
453 QDomElement graphicElem = doc.createElement( QStringLiteral( "se:Graphic" ) );
454 element.appendChild( graphicElem );
455
456 const QVariantMap props = context.extraProperties();
457 const double strokeWidth = QgsSymbolLayerUtils::rescaleUom( mStrokeWidth, mStrokeWidthUnit, props );
458 const double symbolWidth = QgsSymbolLayerUtils::rescaleUom( mSymbolWidth, mSymbolWidthUnit, props );
459 QgsSymbolLayerUtils::wellKnownMarkerToSld( doc, graphicElem, encodeShape( mShape ), mColor, mStrokeColor, mStrokeStyle, context, strokeWidth, symbolWidth );
460
461 // <Rotation>
463
464 QString angleFunc = props.value( QStringLiteral( "angle" ), QString() ).toString();
465 if ( angleFunc.isEmpty() ) // symbol has no angle set
466 {
467 if ( ddRotation && ddRotation.isActive() )
468 {
469 angleFunc = ddRotation.asExpression();
470 }
471 else if ( !qgsDoubleNear( mAngle, 0.0 ) )
472 angleFunc = QString::number( mAngle );
473 }
474 else if ( ddRotation && ddRotation.isActive() )
475 {
476 // the symbol has an angle and the symbol layer have a rotation
477 // property set
478 angleFunc = QStringLiteral( "%1 + %2" ).arg( angleFunc, ddRotation.asExpression() );
479 }
480 else if ( !qgsDoubleNear( mAngle, 0.0 ) )
481 {
482 // both the symbol and the symbol layer have angle value set
483 bool ok;
484 const double angle = angleFunc.toDouble( &ok );
485 if ( !ok )
486 {
487 // its a string (probably a property name or a function)
488 angleFunc = QStringLiteral( "%1 + %2" ).arg( angleFunc ).arg( mAngle );
489 }
490 else if ( !qgsDoubleNear( angle + mAngle, 0.0 ) )
491 {
492 // it's a double value
493 angleFunc = QString::number( angle + mAngle );
494 }
495 }
496 QgsSymbolLayerUtils::createRotationElement( doc, graphicElem, angleFunc, context );
497
498 // <Displacement>
501
502 // store w/h factor in a <VendorOption>
503 const double widthHeightFactor = mSymbolWidth / mSymbolHeight;
504 const QDomElement factorElem = QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "widthHeightFactor" ), QString::number( widthHeightFactor ) );
505 graphicElem.appendChild( factorElem );
506 return true;
507}
508
510{
511 QgsDebugMsgLevel( QStringLiteral( "Entered." ), 4 );
512
513 QDomElement graphicElem = element.firstChildElement( QStringLiteral( "Graphic" ) );
514 if ( graphicElem.isNull() )
515 return nullptr;
516
517 QString name = QStringLiteral( "circle" );
518 QColor fillColor, strokeColor;
519 double strokeWidth, size;
520 double widthHeightFactor = 1.0;
521 Qt::PenStyle strokeStyle;
522
523 QgsStringMap vendorOptions = QgsSymbolLayerUtils::getVendorOptionList( graphicElem );
524 for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
525 {
526 if ( it.key() == QLatin1String( "widthHeightFactor" ) )
527 {
528 bool ok;
529 const double v = it.value().toDouble( &ok );
530 if ( ok && !qgsDoubleNear( v, 0.0 ) && v > 0 )
531 widthHeightFactor = v;
532 }
533 }
534
536 return nullptr;
537
538 double scaleFactor = 1.0;
539 const QString uom = element.attribute( QStringLiteral( "uom" ) );
540 Qgis::RenderUnit sldUnitSize = QgsSymbolLayerUtils::decodeSldUom( uom, &scaleFactor );
541 size = size * scaleFactor;
542 strokeWidth = strokeWidth * scaleFactor;
543
544 double angle = 0.0;
545 QString angleFunc;
546 if ( QgsSymbolLayerUtils::rotationFromSldElement( graphicElem, angleFunc ) )
547 {
548 bool ok;
549 const double d = angleFunc.toDouble( &ok );
550 if ( ok )
551 angle = d;
552 }
553
555 m->setOutputUnit( sldUnitSize );
556 m->setShape( decodeShape( name ) );
561 m->setSymbolWidth( size );
562 m->setSymbolHeight( size / widthHeightFactor );
563 m->setAngle( angle );
564 return m;
565}
566
568{
569 QVariantMap map;
570 map[QStringLiteral( "symbol_name" )] = encodeShape( mShape );
571 map[QStringLiteral( "symbol_width" )] = QString::number( mSymbolWidth );
572 map[QStringLiteral( "symbol_width_unit" )] = QgsUnitTypes::encodeUnit( mSymbolWidthUnit );
573 map[QStringLiteral( "symbol_width_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mSymbolWidthMapUnitScale );
574 map[QStringLiteral( "symbol_height" )] = QString::number( mSymbolHeight );
575 map[QStringLiteral( "symbol_height_unit" )] = QgsUnitTypes::encodeUnit( mSymbolHeightUnit );
576 map[QStringLiteral( "symbol_height_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mSymbolHeightMapUnitScale );
577 map[QStringLiteral( "angle" )] = QString::number( mAngle );
578 map[QStringLiteral( "outline_style" )] = QgsSymbolLayerUtils::encodePenStyle( mStrokeStyle );
579 map[QStringLiteral( "outline_width" )] = QString::number( mStrokeWidth );
580 map[QStringLiteral( "outline_width_unit" )] = QgsUnitTypes::encodeUnit( mStrokeWidthUnit );
581 map[QStringLiteral( "outline_width_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mStrokeWidthMapUnitScale );
582 map[QStringLiteral( "joinstyle" )] = QgsSymbolLayerUtils::encodePenJoinStyle( mPenJoinStyle );
583 map[QStringLiteral( "cap_style" )] = QgsSymbolLayerUtils::encodePenCapStyle( mPenCapStyle );
584 map[QStringLiteral( "color" )] = QgsColorUtils::colorToString( mColor );
585 map[QStringLiteral( "outline_color" )] = QgsColorUtils::colorToString( mStrokeColor );
586 map[QStringLiteral( "offset" )] = QgsSymbolLayerUtils::encodePoint( mOffset );
587 map[QStringLiteral( "offset_unit" )] = QgsUnitTypes::encodeUnit( mOffsetUnit );
588 map[QStringLiteral( "offset_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mOffsetMapUnitScale );
589 map[QStringLiteral( "size" )] = QString::number( mSize );
590 map[QStringLiteral( "size_unit" )] = QgsUnitTypes::encodeUnit( mSizeUnit );
591 map[QStringLiteral( "size_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mSizeMapUnitScale );
592 map[QStringLiteral( "horizontal_anchor_point" )] = QString::number( static_cast< int >( mHorizontalAnchorPoint ) );
593 map[QStringLiteral( "vertical_anchor_point" )] = QString::number( static_cast< int >( mVerticalAnchorPoint ) );
594 return map;
595}
596
597QSizeF QgsEllipseSymbolLayer::calculateSize( QgsSymbolRenderContext &context, double *scaledWidth, double *scaledHeight )
598{
599 double width = 0;
600
601 if ( mDataDefinedProperties.isActive( QgsSymbolLayer::Property::Width ) ) //1. priority: data defined setting on symbol layer le
602 {
603 context.setOriginalValueVariable( mSymbolWidth );
605 }
606 else //2. priority: global width setting
607 {
608 width = mSymbolWidth;
609 }
610 if ( scaledWidth )
611 {
612 *scaledWidth = width;
613 }
614 width = context.renderContext().convertToPainterUnits( width, mSymbolWidthUnit, mSymbolHeightMapUnitScale );
615
616 double height = 0;
617 if ( mDataDefinedProperties.isActive( QgsSymbolLayer::Property::Height ) ) //1. priority: data defined setting on symbol layer level
618 {
619 context.setOriginalValueVariable( mSymbolHeight );
620 height = mDataDefinedProperties.valueAsDouble( QgsSymbolLayer::Property::Height, context.renderContext().expressionContext(), mSymbolHeight );
621 }
622 else //2. priority: global height setting
623 {
624 height = mSymbolHeight;
625 }
626 if ( scaledHeight )
627 {
628 *scaledHeight = height;
629 }
630 height = context.renderContext().convertToPainterUnits( height, mSymbolHeightUnit, mSymbolHeightMapUnitScale );
631 return QSizeF( width, height );
632}
633
634void QgsEllipseSymbolLayer::preparePath( const QgsEllipseSymbolLayer::Shape &shape, QgsSymbolRenderContext &context, double *scaledWidth, double *scaledHeight, const QgsFeature * )
635{
636 mPainterPath = QPainterPath();
637
638 const QSizeF size = calculateSize( context, scaledWidth, scaledHeight );
639
640 switch ( shape )
641 {
642 case Circle:
643 mPainterPath.addEllipse( QRectF( -size.width() / 2.0, -size.height() / 2.0, size.width(), size.height() ) );
644 return;
645
646 case SemiCircle:
647 mPainterPath.arcTo( -size.width() / 2.0, -size.height() / 2.0, size.width(), size.height(), 0, 180 );
648 mPainterPath.lineTo( 0, 0 );
649 return;
650
651 case ThirdCircle:
652 mPainterPath.arcTo( -size.width() / 2.0, -size.height() / 2.0, size.width(), size.height(), 90, 120 );
653 mPainterPath.lineTo( 0, 0 );
654 return;
655
656 case QuarterCircle:
657 mPainterPath.arcTo( -size.width() / 2.0, -size.height() / 2.0, size.width(), size.height(), 90, 90 );
658 mPainterPath.lineTo( 0, 0 );
659 return;
660
661 case Rectangle:
662 mPainterPath.addRect( QRectF( -size.width() / 2.0, -size.height() / 2.0, size.width(), size.height() ) );
663 return;
664
665 case Diamond:
666 mPainterPath.moveTo( -size.width() / 2.0, 0 );
667 mPainterPath.lineTo( 0, size.height() / 2.0 );
668 mPainterPath.lineTo( size.width() / 2.0, 0 );
669 mPainterPath.lineTo( 0, -size.height() / 2.0 );
670 mPainterPath.lineTo( -size.width() / 2.0, 0 );
671 return;
672
673 case Cross:
674 mPainterPath.moveTo( 0, -size.height() / 2.0 );
675 mPainterPath.lineTo( 0, size.height() / 2.0 );
676 mPainterPath.moveTo( -size.width() / 2.0, 0 );
677 mPainterPath.lineTo( size.width() / 2.0, 0 );
678 return;
679
680 case Arrow:
681 mPainterPath.moveTo( -size.width() / 2.0, size.height() / 2.0 );
682 mPainterPath.lineTo( 0, -size.height() / 2.0 );
683 mPainterPath.lineTo( size.width() / 2.0, size.height() / 2.0 );
684 return;
685
686 case HalfArc:
687 mPainterPath.moveTo( size.width() / 2.0, 0 );
688 mPainterPath.arcTo( -size.width() / 2.0, -size.height() / 2.0, size.width(), size.height(), 0, 180 );
689 return;
690
691 case Triangle:
692 mPainterPath.moveTo( 0, -size.height() / 2.0 );
693 mPainterPath.lineTo( -size.width() / 2.0, size.height() / 2.0 );
694 mPainterPath.lineTo( size.width() / 2.0, size.height() / 2.0 );
695 mPainterPath.lineTo( 0, -size.height() / 2.0 );
696 return;
697
698 case LeftHalfTriangle:
699 mPainterPath.moveTo( 0, size.height() / 2.0 );
700 mPainterPath.lineTo( size.width() / 2.0, size.height() / 2.0 );
701 mPainterPath.lineTo( 0, -size.height() / 2.0 );
702 mPainterPath.lineTo( 0, size.height() / 2.0 );
703 return;
704
706 mPainterPath.moveTo( -size.width() / 2.0, size.height() / 2.0 );
707 mPainterPath.lineTo( 0, size.height() / 2.0 );
708 mPainterPath.lineTo( 0, -size.height() / 2.0 );
709 mPainterPath.lineTo( -size.width() / 2.0, size.height() / 2.0 );
710 return;
711
712 case Pentagon:
713 mPainterPath.moveTo( ( size.width() * -0.9511 ) / 2.0, size.height() / ( 2 / -0.309 ) );
714 mPainterPath.lineTo( ( size.width() * -0.5878 ) / 2.0, size.height() / ( 2 / 0.8090 ) );
715 mPainterPath.lineTo( ( size.width() * 0.5878 ) / 2.0, size.height() / ( 2 / 0.8090 ) );
716 mPainterPath.lineTo( ( size.width() * 0.9511 ) / 2.0, size.height() / ( 2 / -0.309 ) );
717 mPainterPath.lineTo( 0, size.height() / -2.0 );
718 mPainterPath.lineTo( ( size.width() * -0.9511 ) / 2.0, size.height() / ( 2 / -0.309 ) );
719 return;
720
721 case Hexagon:
722 mPainterPath.moveTo( ( size.width() * 0.8660 ) / 2.0, size.height() / 4.0 );
723 mPainterPath.lineTo( ( size.width() * 0.8660 ) / 2.0, size.height() / -4.0 );
724 mPainterPath.lineTo( 0, size.height() / -2.0 );
725 mPainterPath.lineTo( ( size.width() * 0.8660 ) / -2.0, size.height() / -4.0 );
726 mPainterPath.lineTo( ( size.width() * 0.8660 ) / -2.0, size.height() / 4.0 );
727 mPainterPath.lineTo( 0, size.height() / 2.0 );
728 mPainterPath.lineTo( ( size.width() * 0.8660 ) / 2.0, size.height() / 4.0 );
729 return;
730
731 case Octagon:
732 {
733 static constexpr double VERTEX_OFFSET_FROM_ORIGIN = 1.0 / ( 1 + M_SQRT2 );
734 mPainterPath.moveTo( ( size.width() * VERTEX_OFFSET_FROM_ORIGIN ) / -2.0, size.height() / 2.0 );
735 mPainterPath.lineTo( ( size.width() * VERTEX_OFFSET_FROM_ORIGIN ) / 2.0, size.height() / 2.0 );
736 mPainterPath.lineTo( size.width() / 2.0, ( size.height() * VERTEX_OFFSET_FROM_ORIGIN ) / 2.0 );
737 mPainterPath.lineTo( size.width() / 2.0, ( size.height() * VERTEX_OFFSET_FROM_ORIGIN ) / -2.0 );
738 mPainterPath.lineTo( ( size.width() * VERTEX_OFFSET_FROM_ORIGIN ) / 2.0, size.height() / -2.0 );
739 mPainterPath.lineTo( ( size.width() * VERTEX_OFFSET_FROM_ORIGIN ) / -2.0, size.height() / -2.0 );
740 mPainterPath.lineTo( size.width() / -2.0, ( size.height() * VERTEX_OFFSET_FROM_ORIGIN ) / -2.0 );
741 mPainterPath.lineTo( size.width() / -2.0, ( size.height() * VERTEX_OFFSET_FROM_ORIGIN ) / 2.0 );
742 mPainterPath.lineTo( ( size.width() * VERTEX_OFFSET_FROM_ORIGIN ) / -2.0, size.height() / 2.0 );
743 return;
744 }
745
746 case Star:
747 {
748 const double inner_r = std::cos( DEG2RAD( 72.0 ) ) / std::cos( DEG2RAD( 36.0 ) );
749 mPainterPath.moveTo( ( size.width() * inner_r * std::sin( DEG2RAD( 324.0 ) ) ) / 2.0, ( size.height() * inner_r * std::cos( DEG2RAD( 324.0 ) ) ) / -2.0 );
750 mPainterPath.lineTo( ( size.width() * std::sin( DEG2RAD( 288.0 ) ) ) / 2.0, ( size.height() * std::cos( DEG2RAD( 288.0 ) ) ) / -2.0 );
751 mPainterPath.lineTo( ( size.width() * inner_r * std::sin( DEG2RAD( 252.0 ) ) ) / 2.0, ( size.height() * inner_r * std::cos( DEG2RAD( 252.0 ) ) ) / -2.0 );
752 mPainterPath.lineTo( ( size.width() * std::sin( DEG2RAD( 216.0 ) ) ) / 2.0, ( size.height() * std::cos( DEG2RAD( 216.0 ) ) ) / -2.0 );
753 mPainterPath.lineTo( 0, ( size.height() * inner_r ) / 2.0 );
754 mPainterPath.lineTo( ( size.width() * std::sin( DEG2RAD( 144.0 ) ) ) / 2.0, ( size.height() * std::cos( DEG2RAD( 144.0 ) ) ) / -2.0 );
755 mPainterPath.lineTo( ( size.width() * inner_r * std::sin( DEG2RAD( 108.0 ) ) ) / 2.0, ( size.height() * inner_r * std::cos( DEG2RAD( 108.0 ) ) ) / -2.0 );
756 mPainterPath.lineTo( ( size.width() * std::sin( DEG2RAD( 72.0 ) ) ) / 2.0, ( size.height() * std::cos( DEG2RAD( 72.0 ) ) ) / -2.0 );
757 mPainterPath.lineTo( ( size.width() * inner_r * std::sin( DEG2RAD( 36.0 ) ) ) / 2.0, ( size.height() * inner_r * std::cos( DEG2RAD( 36.0 ) ) ) / -2.0 );
758 mPainterPath.lineTo( 0, size.height() / -2.0 );
759 mPainterPath.lineTo( ( size.width() * inner_r * std::sin( DEG2RAD( 324.0 ) ) ) / 2.0, ( size.height() * inner_r * std::cos( DEG2RAD( 324.0 ) ) ) / -2.0 );
760 return;
761 }
762 }
763}
764
766{
767 switch ( shape )
768 {
769 case Circle:
770 case Rectangle:
771 case Diamond:
772 case Triangle:
774 case LeftHalfTriangle:
775 case SemiCircle:
776 case ThirdCircle:
777 case QuarterCircle:
778 case Pentagon:
779 case Hexagon:
780 case Octagon:
781 case Star:
782 return true;
783
784 case Cross:
785 case Arrow:
786 case HalfArc:
787 return false;
788 }
789
790 return true;
791}
792
794{
795 if ( mSymbolWidth >= mSymbolHeight )
796 {
797 mSymbolHeight = mSymbolHeight * size / mSymbolWidth;
798 mSymbolWidth = size;
799 }
800 else
801 {
802 mSymbolWidth = mSymbolWidth * size / mSymbolHeight;
803 mSymbolHeight = size;
804 }
806}
807
809{
810 mSymbolWidth = w;
811 QgsMarkerSymbolLayer::setSize( mSymbolWidth >= mSymbolHeight ? mSymbolWidth : mSymbolHeight );
812}
813
815{
816 mSymbolHeight = h;
817 QgsMarkerSymbolLayer::setSize( mSymbolWidth >= mSymbolHeight ? mSymbolWidth : mSymbolHeight );
818}
819
821{
823 mSymbolWidthUnit = unit;
824 mSymbolHeightUnit = unit;
825 mStrokeWidthUnit = unit;
826}
827
829{
831 if ( mSymbolWidthUnit != unit || mSymbolHeightUnit != unit || mStrokeWidthUnit != unit )
832 {
834 }
835 return unit;
836}
837
839{
840 return mSymbolWidthUnit == Qgis::RenderUnit::MapUnits || mSymbolWidthUnit == Qgis::RenderUnit::MetersInMapUnits
841 || mSymbolHeightUnit == Qgis::RenderUnit::MapUnits || mSymbolHeightUnit == Qgis::RenderUnit::MetersInMapUnits
842 || mStrokeWidthUnit == Qgis::RenderUnit::MapUnits || mStrokeWidthUnit == Qgis::RenderUnit::MetersInMapUnits
844}
845
847{
849 mSymbolWidthMapUnitScale = scale;
850 mSymbolHeightMapUnitScale = scale;
851 mStrokeWidthMapUnitScale = scale;
852}
853
855{
856 if ( QgsMarkerSymbolLayer::mapUnitScale() == mSymbolWidthMapUnitScale &&
857 mSymbolWidthMapUnitScale == mSymbolHeightMapUnitScale &&
858 mSymbolHeightMapUnitScale == mStrokeWidthMapUnitScale )
859 {
860 return mSymbolWidthMapUnitScale;
861 }
862 return QgsMapUnitScale();
863}
864
866{
867 const QSizeF size = calculateSize( context );
868
869 bool hasDataDefinedRotation = false;
870 QPointF offset;
871 double angle = 0;
872 calculateOffsetAndRotation( context, size.width(), size.height(), hasDataDefinedRotation, offset, angle );
873
874 QTransform transform;
875
876 // move to the desired position
877 transform.translate( point.x() + offset.x(), point.y() + offset.y() );
878
879 if ( !qgsDoubleNear( angle, 0.0 ) )
880 transform.rotate( angle );
881
882 double penWidth = mStrokeWidth;
884 {
885 context.setOriginalValueVariable( mStrokeWidth );
887
888 if ( !QgsVariantUtils::isNull( exprVal ) )
889 {
890 bool ok;
891 const double strokeWidth = exprVal.toDouble( &ok );
892 if ( ok )
893 {
894 penWidth = strokeWidth;
895 }
896 }
897 }
898 penWidth = context.renderContext().convertToPainterUnits( penWidth, mStrokeWidthUnit, mStrokeWidthMapUnitScale );
899
901 {
904 if ( !QgsVariantUtils::isNull( exprVal ) && exprVal.toString() == QLatin1String( "no" ) )
905 {
906 penWidth = 0.0;
907 }
908 }
909 else if ( mStrokeStyle == Qt::NoPen )
910 penWidth = 0;
911
912 //antialiasing, add 1 pixel
913 penWidth += 1;
914
915 QRectF symbolBounds = transform.mapRect( QRectF( -size.width() / 2.0,
916 -size.height() / 2.0,
917 size.width(),
918 size.height() ) );
919
920 //extend bounds by pen width / 2.0
921 symbolBounds.adjust( -penWidth / 2.0, -penWidth / 2.0,
922 penWidth / 2.0, penWidth / 2.0 );
923
924 return symbolBounds;
925}
926
927bool QgsEllipseSymbolLayer::writeDxf( QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, QgsSymbolRenderContext &context, QPointF shift ) const
928{
929 //width
930 double symbolWidth = mSymbolWidth;
931
932 if ( mDataDefinedProperties.isActive( QgsSymbolLayer::Property::Width ) ) //1. priority: data defined setting on symbol layer le
933 {
934 context.setOriginalValueVariable( mSymbolWidth );
936 }
937 if ( mSymbolWidthUnit == Qgis::RenderUnit::Millimeters )
938 {
939 symbolWidth *= mmMapUnitScaleFactor;
940 }
941
942 //height
943 double symbolHeight = mSymbolHeight;
944 if ( mDataDefinedProperties.isActive( QgsSymbolLayer::Property::Height ) ) //1. priority: data defined setting on symbol layer level
945 {
946 context.setOriginalValueVariable( mSymbolHeight );
948 }
949 if ( mSymbolHeightUnit == Qgis::RenderUnit::Millimeters )
950 {
951 symbolHeight *= mmMapUnitScaleFactor;
952 }
953
954 //stroke width
955 double strokeWidth = mStrokeWidth;
956
958 {
959 context.setOriginalValueVariable( mStrokeWidth );
961 }
962 if ( mStrokeWidthUnit == Qgis::RenderUnit::Millimeters )
963 {
965 }
966
967 //fill color
968 QColor fc = mColor;
970 {
973 }
974
975 //stroke color
976 QColor oc = mStrokeColor;
978 {
981 }
982
983 //symbol name
986 {
989 }
990
991 //offset
992 double offsetX = 0;
993 double offsetY = 0;
994 markerOffset( context, offsetX, offsetY );
995 QPointF off( offsetX, offsetY );
996
997 //priority for rotation: 1. data defined symbol level, 2. symbol layer rotation (mAngle)
998 double rotation = 0.0;
1000 {
1003 }
1004 else if ( !qgsDoubleNear( mAngle + mLineAngle, 0.0 ) )
1005 {
1006 rotation = mAngle + mLineAngle;
1007 }
1008 rotation = -rotation; //rotation in Qt is counterclockwise
1009 if ( rotation )
1010 off = _rotatedOffset( off, rotation );
1011
1012 QTransform t;
1013 t.translate( shift.x() + offsetX, shift.y() + offsetY );
1014
1015 if ( !qgsDoubleNear( rotation, 0.0 ) )
1016 t.rotate( rotation );
1017
1018 const double halfWidth = symbolWidth / 2.0;
1019 const double halfHeight = symbolHeight / 2.0;
1020
1021 switch ( shape )
1022 {
1023 case Circle:
1024 {
1025 if ( qgsDoubleNear( halfWidth, halfHeight ) )
1026 {
1027 const QgsPoint pt( t.map( QPointF( 0, 0 ) ) );
1028 e.writeFilledCircle( layerName, oc, pt, halfWidth );
1029 }
1030 else
1031 {
1032 QgsPointSequence line;
1033
1034 const double stepsize = 2 * M_PI / 40;
1035 for ( int i = 0; i < 39; ++i )
1036 {
1037 const double angle = stepsize * i;
1038 const double x = halfWidth * std::cos( angle );
1039 const double y = halfHeight * std::sin( angle );
1040 line << QgsPoint( t.map( QPointF( x, y ) ) );
1041 }
1042 //close ellipse with first point
1043 line << line.at( 0 );
1044
1045 if ( mBrush.style() != Qt::NoBrush )
1046 e.writePolygon( QgsRingSequence() << line, layerName, QStringLiteral( "SOLID" ), fc );
1047 if ( mPen.style() != Qt::NoPen )
1048 e.writePolyline( line, layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth );
1049 }
1050 return true;
1051 }
1052
1053 case Rectangle:
1054 {
1056 p << QgsPoint( t.map( QPointF( -halfWidth, -halfHeight ) ) )
1057 << QgsPoint( t.map( QPointF( halfWidth, -halfHeight ) ) )
1058 << QgsPoint( t.map( QPointF( halfWidth, halfHeight ) ) )
1059 << QgsPoint( t.map( QPointF( -halfWidth, halfHeight ) ) );
1060 p << p[0];
1061
1062 if ( mBrush.style() != Qt::NoBrush )
1063 e.writePolygon( QgsRingSequence() << p, layerName, QStringLiteral( "SOLID" ), fc );
1064 if ( mPen.style() != Qt::NoPen )
1065 e.writePolyline( p, layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth );
1066 return true;
1067 }
1068 case Cross:
1069 {
1070 if ( mPen.style() != Qt::NoPen )
1071 {
1073 << QgsPoint( t.map( QPointF( -halfWidth, 0 ) ) )
1074 << QgsPoint( t.map( QPointF( halfWidth, 0 ) ) ),
1075 layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth );
1077 << QgsPoint( t.map( QPointF( 0, halfHeight ) ) )
1078 << QgsPoint( t.map( QPointF( 0, -halfHeight ) ) ),
1079 layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth );
1080 return true;
1081 }
1082 break;
1083 }
1084
1085 case Triangle:
1086 {
1088 p << QgsPoint( t.map( QPointF( -halfWidth, -halfHeight ) ) )
1089 << QgsPoint( t.map( QPointF( halfWidth, -halfHeight ) ) )
1090 << QgsPoint( t.map( QPointF( 0, halfHeight ) ) );
1091 p << p[0];
1092 if ( mBrush.style() != Qt::NoBrush )
1093 e.writePolygon( QgsRingSequence() << p, layerName, QStringLiteral( "SOLID" ), fc );
1094 if ( mPen.style() != Qt::NoPen )
1095 e.writePolyline( p, layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth );
1096 return true;
1097 }
1098
1099 case Diamond:
1100 case Arrow:
1101 case HalfArc:
1102 case RightHalfTriangle:
1103 case LeftHalfTriangle:
1104 case SemiCircle:
1105 case ThirdCircle:
1106 case QuarterCircle:
1107 case Pentagon:
1108 case Hexagon:
1109 case Octagon:
1110 case Star:
1111 return false;
1112 }
1113
1114 return false;
1115}
1116
1118{
1119 if ( ok )
1120 *ok = true;
1121 const QString cleaned = name.toLower().trimmed();
1122
1123 if ( cleaned == QLatin1String( "circle" ) )
1124 return Circle;
1125 else if ( cleaned == QLatin1String( "square" ) || cleaned == QLatin1String( "rectangle" ) )
1126 return Rectangle;
1127 else if ( cleaned == QLatin1String( "diamond" ) )
1128 return Diamond;
1129 else if ( cleaned == QLatin1String( "cross" ) )
1130 return Cross;
1131 else if ( cleaned == QLatin1String( "arrow" ) )
1132 return Arrow;
1133 else if ( cleaned == QLatin1String( "half_arc" ) )
1134 return HalfArc;
1135 else if ( cleaned == QLatin1String( "triangle" ) )
1136 return Triangle;
1137 else if ( cleaned == QLatin1String( "right_half_triangle" ) )
1138 return RightHalfTriangle;
1139 else if ( cleaned == QLatin1String( "left_half_triangle" ) )
1140 return LeftHalfTriangle;
1141 else if ( cleaned == QLatin1String( "semi_circle" ) )
1142 return SemiCircle;
1143 else if ( cleaned == QLatin1String( "third_circle" ) )
1144 return ThirdCircle;
1145 else if ( cleaned == QLatin1String( "quarter_circle" ) )
1146 return QuarterCircle;
1147 else if ( cleaned == QLatin1String( "pentagon" ) )
1148 return Pentagon;
1149 else if ( cleaned == QLatin1String( "hexagon" ) )
1150 return Hexagon;
1151 else if ( cleaned == QLatin1String( "octagon" ) )
1152 return Octagon;
1153 else if ( cleaned == QLatin1String( "star" ) )
1154 return Star; if ( ok )
1155 *ok = false;
1156 return Circle;
1157}
1158
1160{
1161 switch ( shape )
1162 {
1163 case Circle:
1164 return QStringLiteral( "circle" );
1165 case Rectangle:
1166 return QStringLiteral( "rectangle" );
1167 case Diamond:
1168 return QStringLiteral( "diamond" );
1169 case Cross:
1170 return QStringLiteral( "cross" );
1171 case Arrow:
1172 return QStringLiteral( "arrow" );
1173 case HalfArc:
1174 return QStringLiteral( "half_arc" );
1175 case Triangle:
1176 return QStringLiteral( "triangle" );
1177 case RightHalfTriangle:
1178 return QStringLiteral( "right_half_triangle" );
1179 case LeftHalfTriangle:
1180 return QStringLiteral( "left_half_triangle" );
1181 case SemiCircle:
1182 return QStringLiteral( "semi_circle" );
1183 case ThirdCircle:
1184 return QStringLiteral( "third_circle" );
1185 case QuarterCircle:
1186 return QStringLiteral( "quarter_circle" );
1187 case Pentagon:
1188 return QStringLiteral( "pentagon" );
1189 case Hexagon:
1190 return QStringLiteral( "hexagon" );
1191 case Octagon:
1192 return QStringLiteral( "octagon" );
1193 case Star:
1194 return QStringLiteral( "star" );
1195 }
1196 return QString();
1197}
1198
1199QList<QgsEllipseSymbolLayer::Shape> QgsEllipseSymbolLayer::availableShapes()
1200{
1201 QList< Shape > shapes;
1202 shapes << Circle
1203 << Rectangle
1204 << Diamond
1205 << Cross
1206 << Arrow
1207 << HalfArc
1208 << Triangle
1211 << SemiCircle
1212 << ThirdCircle
1213 << QuarterCircle
1214 << Pentagon
1215 << Hexagon
1216 << Octagon
1217 << Star;
1218 return shapes;
1219}
@ DynamicRotation
Rotation of symbol may be changed during rendering and symbol should not be cached.
Definition qgis.h:770
@ CanCalculateMaskGeometryPerFeature
If present, indicates that mask geometry can safely be calculated per feature for the symbol layer....
Definition qgis.h:882
QFlags< SymbolLayerFlag > SymbolLayerFlags
Symbol layer flags.
Definition qgis.h:887
VerticalAnchorPoint
Marker symbol vertical anchor points.
Definition qgis.h:814
@ Point
Points.
Definition qgis.h:359
RenderUnit
Rendering size units.
Definition qgis.h:5183
@ Millimeters
Millimeters.
Definition qgis.h:5184
@ Unknown
Mixed or unknown units.
Definition qgis.h:5190
@ MapUnits
Map units.
Definition qgis.h:5185
@ MetersInMapUnits
Meters value as Map units.
Definition qgis.h:5191
HorizontalAnchorPoint
Marker symbol horizontal anchor points.
Definition qgis.h:800
double valueAsDouble(int key, const QgsExpressionContext &context, double defaultValue=0.0, bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a double.
static QColor colorFromString(const QString &string)
Decodes a string into a color value.
static QString colorToString(const QColor &color)
Encodes a color into a string value.
Exports QGIS layers to the DXF format.
void writeFilledCircle(const QString &layer, const QColor &color, const QgsPoint &pt, double radius)
Write filled circle (as hatch).
void writePolygon(const QgsRingSequence &polygon, const QString &layer, const QString &hatchPattern, const QColor &color)
Draw dxf filled polygon (HATCH).
void writePolyline(const QgsPointSequence &line, const QString &layer, const QString &lineStyleName, const QColor &color, double width=-1)
Draw dxf primitives (LWPOLYLINE).
void setPenCapStyle(Qt::PenCapStyle style)
Sets the marker's stroke cap style (e.g., flat, round, etc).
bool writeDxf(QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, QgsSymbolRenderContext &context, QPointF shift=QPointF(0.0, 0.0)) const override
write as DXF
void setSymbolHeightMapUnitScale(const QgsMapUnitScale &scale)
void setSymbolWidthMapUnitScale(const QgsMapUnitScale &scale)
QVariantMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
QRectF bounds(QPointF point, QgsSymbolRenderContext &context) override
Returns the approximate bounding box of the marker symbol layer, taking into account any data defined...
Qgis::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
void renderPoint(QPointF point, QgsSymbolRenderContext &context) override
Renders a marker at the specified point.
void setStrokeColor(const QColor &c) override
Sets the stroke color for the symbol layer.
void setStrokeStyle(Qt::PenStyle strokeStyle)
static QgsEllipseSymbolLayer::Shape decodeShape(const QString &name, bool *ok=nullptr)
Attempts to decode a string representation of a shape name to the corresponding shape.
void setStrokeWidthUnit(Qgis::RenderUnit unit)
Sets the units for the symbol's stroke width.
void setSize(double size) override
Sets the symbol size.
QgsMapUnitScale mapUnitScale() const override
Shape
Marker symbol shapes.
@ Cross
Stroke-only cross.
@ HalfArc
Stroke-only half arc.
@ Arrow
Stroke-only arrow.
@ RightHalfTriangle
Right half of a triangle.
@ LeftHalfTriangle
Left half of a triangle.
QColor fillColor() const override
Returns the fill color for the symbol layer.
QgsEllipseSymbolLayer::Shape shape() const
Returns the shape for the rendered ellipse marker symbol.
bool usesMapUnits() const override
Returns true if the symbol layer has any components which use map unit based sizes.
void setFillColor(const QColor &c) override
Sets the fill color for the symbol layer.
void setShape(QgsEllipseSymbolLayer::Shape shape)
Sets the rendered ellipse marker shape.
static QList< QgsEllipseSymbolLayer::Shape > availableShapes()
Returns a list of all available shape types.
Qt::PenStyle strokeStyle() const
static QgsSymbolLayer * create(const QVariantMap &properties=QVariantMap())
Creates the symbol layer.
static QgsSymbolLayer * createFromSld(QDomElement &element)
Qgis::SymbolLayerFlags flags() const override
Returns flags which control the symbol layer's behavior.
void setOutputUnit(Qgis::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
Q_DECL_DEPRECATED void toSld(QDomDocument &doc, QDomElement &element, const QVariantMap &props=QVariantMap()) const override
Saves the symbol layer as SLD.
static QString encodeShape(QgsEllipseSymbolLayer::Shape shape)
Encodes a shape to its string representation.
void setStrokeWidthMapUnitScale(const QgsMapUnitScale &scale)
void setSymbolHeightUnit(Qgis::RenderUnit unit)
Sets the units for the symbol's height.
void stopRender(QgsSymbolRenderContext &context) override
Called after a set of rendering operations has finished on the supplied render context.
QString layerType() const override
Returns a string that represents this layer type.
QColor strokeColor() const override
Returns the stroke color for the symbol layer.
void setPenJoinStyle(Qt::PenJoinStyle style)
Set stroke join style.
static bool shapeIsFilled(const QgsEllipseSymbolLayer::Shape &shape)
Returns true if a shape has a fill.
void setSymbolWidthUnit(Qgis::RenderUnit unit)
Sets the units for the symbol's width.
void startRender(QgsSymbolRenderContext &context) override
Called before a set of rendering operations commences on the supplied render context.
~QgsEllipseSymbolLayer() override
void setMapUnitScale(const QgsMapUnitScale &scale) override
Q_DECL_DEPRECATED void writeSldMarker(QDomDocument &doc, QDomElement &element, const QVariantMap &props) const override
Writes the symbol layer definition as a SLD XML element.
QgsEllipseSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:58
QgsGeometry geometry
Definition qgsfeature.h:69
Qgis::GeometryType type
double mapRotation() const
Returns the current map rotation in degrees (clockwise).
Struct for storing maximum and minimum scales for measurements in map units.
double mSize
Marker size.
virtual void setSize(double size)
Sets the symbol size.
void setVerticalAnchorPoint(Qgis::VerticalAnchorPoint v)
Sets the vertical anchor point for positioning the symbol.
Qgis::RenderUnit mOffsetUnit
Offset units.
QPointF offset() const
Returns the marker's offset, which is the horizontal and vertical displacement which the rendered mar...
double mLineAngle
Line rotation angle (see setLineAngle() for details).
void setOffsetUnit(Qgis::RenderUnit unit)
Sets the units for the symbol's offset.
void setAngle(double angle)
Sets the rotation angle for the marker.
Qgis::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
QPointF mOffset
Marker offset.
QgsMapUnitScale mapUnitScale() const override
void setOffset(QPointF offset)
Sets the marker's offset, which is the horizontal and vertical displacement which the rendered marker...
void setSizeMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the symbol's size.
double size() const
Returns the symbol size.
QgsMapUnitScale mOffsetMapUnitScale
Offset map unit scale.
Qgis::VerticalAnchorPoint mVerticalAnchorPoint
Vertical anchor point.
static QPointF _rotatedOffset(QPointF offset, double angle)
Adjusts a marker offset to account for rotation.
void setHorizontalAnchorPoint(Qgis::HorizontalAnchorPoint h)
Sets the horizontal anchor point for positioning the symbol.
QgsMapUnitScale mSizeMapUnitScale
Marker size map unit scale.
Qgis::RenderUnit mSizeUnit
Marker size unit.
void setOutputUnit(Qgis::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
void setSizeUnit(Qgis::RenderUnit unit)
Sets the units for the symbol's size.
void markerOffset(QgsSymbolRenderContext &context, double &offsetX, double &offsetY) const
Calculates the required marker offset, including both the symbol offset and any displacement required...
Qgis::HorizontalAnchorPoint mHorizontalAnchorPoint
Horizontal anchor point.
void setOffsetMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the symbol's offset.
double mAngle
Marker rotation angle, in degrees clockwise from north.
void startRender(QgsSymbolRenderContext &context) override
Called before a set of rendering operations commences on the supplied render context.
double angle() const
Returns the rotation angle for the marker, in degrees clockwise from north.
void setMapUnitScale(const QgsMapUnitScale &scale) override
Point geometry type, with support for z-dimension and m-values.
Definition qgspoint.h:49
bool isActive(int key) const final
Returns true if the collection contains an active property with the specified key.
A store for object properties.
QString asExpression() const
Returns an expression string representing the state of the property, or an empty string if the proper...
bool isActive() const
Returns whether the property is currently active.
double convertToPainterUnits(double size, Qgis::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale(), Qgis::RenderSubcomponentProperty property=Qgis::RenderSubcomponentProperty::Generic) const
Converts a size from the specified units to painter units (pixels).
QPainter * painter()
Returns the destination QPainter for the render operation.
QgsExpressionContext & expressionContext()
Gets the expression context.
const QgsMapToPixel & mapToPixel() const
Returns the context's map to pixel transform, which transforms between map coordinates and device coo...
QColor selectionColor() const
Returns the color to use when rendering selected features.
Holds SLD export options and other information related to SLD export of a QGIS layer style.
void setExtraProperties(const QVariantMap &properties)
Sets the open ended set of properties that can drive/inform the SLD encoding.
QVariantMap extraProperties() const
Returns the open ended set of properties that can drive/inform the SLD encoding.
static bool rotationFromSldElement(QDomElement &element, QString &rotationFunc)
static QString encodePenStyle(Qt::PenStyle style)
static Qt::PenJoinStyle decodePenJoinStyle(const QString &str)
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
static double rescaleUom(double size, Qgis::RenderUnit unit, const QVariantMap &props)
Rescales the given size based on the uomScale found in the props, if any is found,...
static Qt::PenCapStyle decodePenCapStyle(const QString &str)
static QString encodePenCapStyle(Qt::PenCapStyle style)
static QDomElement createVendorOptionElement(QDomDocument &doc, const QString &name, const QString &value)
static bool wellKnownMarkerFromSld(QDomElement &element, QString &name, QColor &color, QColor &strokeColor, Qt::PenStyle &strokeStyle, double &strokeWidth, double &size)
Extracts properties from an SLD marker definition.
static void createDisplacementElement(QDomDocument &doc, QDomElement &element, QPointF offset)
static QString encodeColor(const QColor &color)
static Qgis::RenderUnit decodeSldUom(const QString &str, double *scaleFactor=nullptr)
Decodes a SLD unit of measure string to a render unit.
static Q_DECL_DEPRECATED void createGeometryElement(QDomDocument &doc, QDomElement &element, const QString &geomFunc)
Creates an SLD geometry element.
static Q_DECL_DEPRECATED void wellKnownMarkerToSld(QDomDocument &doc, QDomElement &element, const QString &name, const QColor &color, const QColor &strokeColor, Qt::PenStyle strokeStyle, double strokeWidth=-1, double size=-1)
Exports a marker to SLD.
static Qt::PenStyle decodePenStyle(const QString &str)
static Q_DECL_DEPRECATED void createRotationElement(QDomDocument &doc, QDomElement &element, const QString &rotationFunc)
Creates SLD rotation element.
static QString encodePoint(QPointF point)
Encodes a QPointF to a string.
static QString encodePenJoinStyle(Qt::PenJoinStyle style)
static QgsStringMap getVendorOptionList(QDomElement &element)
static QPointF decodePoint(const QString &string)
Decodes a QSizeF from a string.
bool shouldRenderUsingSelectionColor(const QgsSymbolRenderContext &context) const
Returns true if the symbol layer should be rendered using the selection color from the render context...
static const bool SELECTION_IS_OPAQUE
Whether styles for selected features ignore symbol alpha.
void copyDataDefinedProperties(QgsSymbolLayer *destLayer) const
Copies all data defined properties of this layer to another symbol layer.
@ StrokeStyle
Stroke style (eg solid, dashed).
@ Name
Name, eg shape name for simple markers.
@ CapStyle
Line cap style.
@ JoinStyle
Line join style.
void restoreOldDataDefinedProperties(const QVariantMap &stringMap)
Restores older data defined properties from string map.
virtual void setColor(const QColor &color)
Sets the "representative" color for the symbol layer.
virtual QColor color() const
Returns the "representative" color of the symbol layer.
void copyPaintEffect(QgsSymbolLayer *destLayer) const
Copies paint effect of this layer to another symbol layer.
virtual Qgis::SymbolLayerFlags flags() const
Returns flags which control the symbol layer's behavior.
QgsPropertyCollection mDataDefinedProperties
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the symbol layer's property collection, used for data defined overrides.
QgsSymbolLayer(const QgsSymbolLayer &other)
Encapsulates the context in which a symbol is being rendered.
const QgsFeature * feature() const
Returns the current feature being rendered.
Qgis::SymbolRenderHints renderHints() const
Returns the rendering hint flags for the symbol.
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for data defined symbology.
qreal opacity() const
Returns the opacity for the symbol.
QgsRenderContext & renderContext()
Returns a reference to the context's render context.
static Q_INVOKABLE Qgis::RenderUnit decodeRenderUnit(const QString &string, bool *ok=nullptr)
Decodes a render unit from a string.
static Q_INVOKABLE QString encodeUnit(Qgis::DistanceUnit unit)
Encodes a distance unit to a string.
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:6607
QMap< QString, QString > QgsStringMap
Definition qgis.h:7132
QVector< QgsPointSequence > QgsRingSequence
QVector< QgsPoint > QgsPointSequence
#define DEG2RAD(x)
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:61