QGIS API Documentation 3.39.0-Master (47f7b3a4989)
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#include "qgsdxfexport.h"
18#include "qgsfeature.h"
19#include "qgsrendercontext.h"
20#include "qgslogger.h"
21#include "qgsunittypes.h"
22#include "qgsproperty.h"
23#include "qgssymbollayerutils.h"
24#include "qgscolorutils.h"
25
26#include <QPainter>
27#include <QSet>
28#include <QDomDocument>
29#include <QDomElement>
30
32 : mStrokeColor( QColor( 35, 35, 35 ) )
33{
34 mColor = Qt::white;
35 mPen.setColor( mStrokeColor );
36 mPen.setStyle( mStrokeStyle );
37 mPen.setJoinStyle( mPenJoinStyle );
38 mPen.setWidth( 1.0 );
39 mBrush.setColor( mColor );
40 mBrush.setStyle( Qt::SolidPattern );
41 mOffset = QPointF( 0, 0 );
42 mAngle = 0;
43}
44
46
47QgsSymbolLayer *QgsEllipseSymbolLayer::create( const QVariantMap &properties )
48{
50 if ( properties.contains( QStringLiteral( "symbol_name" ) ) )
51 {
52 layer->setShape( decodeShape( properties[ QStringLiteral( "symbol_name" )].toString() ) );
53 }
54 if ( properties.contains( QStringLiteral( "size" ) ) )
55 {
56 layer->setSize( properties[QStringLiteral( "size" )].toDouble() );
57 }
58 if ( properties.contains( QStringLiteral( "size_unit" ) ) )
59 {
60 layer->setSizeUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "size_unit" )].toString() ) );
61 }
62 if ( properties.contains( QStringLiteral( "size_map_unit_scale" ) ) )
63 {
64 layer->setSizeMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "size_map_unit_scale" )].toString() ) );
65 }
66 if ( properties.contains( QStringLiteral( "symbol_width" ) ) )
67 {
68 layer->setSymbolWidth( properties[QStringLiteral( "symbol_width" )].toDouble() );
69 }
70 if ( properties.contains( QStringLiteral( "symbol_width_unit" ) ) )
71 {
72 layer->setSymbolWidthUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "symbol_width_unit" )].toString() ) );
73 }
74 if ( properties.contains( QStringLiteral( "symbol_width_map_unit_scale" ) ) )
75 {
76 layer->setSymbolWidthMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "symbol_width_map_unit_scale" )].toString() ) );
77 }
78 if ( properties.contains( QStringLiteral( "symbol_height" ) ) )
79 {
80 layer->setSymbolHeight( properties[QStringLiteral( "symbol_height" )].toDouble() );
81 }
82 if ( properties.contains( QStringLiteral( "symbol_height_unit" ) ) )
83 {
84 layer->setSymbolHeightUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "symbol_height_unit" )].toString() ) );
85 }
86 if ( properties.contains( QStringLiteral( "symbol_height_map_unit_scale" ) ) )
87 {
88 layer->setSymbolHeightMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "symbol_height_map_unit_scale" )].toString() ) );
89 }
90 if ( properties.contains( QStringLiteral( "angle" ) ) )
91 {
92 layer->setAngle( properties[QStringLiteral( "angle" )].toDouble() );
93 }
94 if ( properties.contains( QStringLiteral( "outline_style" ) ) )
95 {
96 layer->setStrokeStyle( QgsSymbolLayerUtils::decodePenStyle( properties[QStringLiteral( "outline_style" )].toString() ) );
97 }
98 else if ( properties.contains( QStringLiteral( "line_style" ) ) )
99 {
100 layer->setStrokeStyle( QgsSymbolLayerUtils::decodePenStyle( properties[QStringLiteral( "line_style" )].toString() ) );
101 }
102 if ( properties.contains( QStringLiteral( "joinstyle" ) ) )
103 {
104 layer->setPenJoinStyle( QgsSymbolLayerUtils::decodePenJoinStyle( properties[QStringLiteral( "joinstyle" )].toString() ) );
105 }
106 if ( properties.contains( QStringLiteral( "cap_style" ) ) )
107 {
108 layer->setPenCapStyle( QgsSymbolLayerUtils::decodePenCapStyle( properties[QStringLiteral( "cap_style" )].toString() ) );
109 }
110 if ( properties.contains( QStringLiteral( "outline_width" ) ) )
111 {
112 layer->setStrokeWidth( properties[QStringLiteral( "outline_width" )].toDouble() );
113 }
114 else if ( properties.contains( QStringLiteral( "line_width" ) ) )
115 {
116 layer->setStrokeWidth( properties[QStringLiteral( "line_width" )].toDouble() );
117 }
118 if ( properties.contains( QStringLiteral( "outline_width_unit" ) ) )
119 {
120 layer->setStrokeWidthUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "outline_width_unit" )].toString() ) );
121 }
122 else if ( properties.contains( QStringLiteral( "line_width_unit" ) ) )
123 {
124 layer->setStrokeWidthUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "line_width_unit" )].toString() ) );
125 }
126 if ( properties.contains( QStringLiteral( "outline_width_map_unit_scale" ) ) )
127 {
128 layer->setStrokeWidthMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "outline_width_map_unit_scale" )].toString() ) );
129 }
130 if ( properties.contains( QStringLiteral( "fill_color" ) ) )
131 {
132 //pre 2.5 projects used "fill_color"
133 layer->setFillColor( QgsColorUtils::colorFromString( properties[QStringLiteral( "fill_color" )].toString() ) );
134 }
135 else if ( properties.contains( QStringLiteral( "color" ) ) )
136 {
137 layer->setFillColor( QgsColorUtils::colorFromString( properties[QStringLiteral( "color" )].toString() ) );
138 }
139 if ( properties.contains( QStringLiteral( "outline_color" ) ) )
140 {
141 layer->setStrokeColor( QgsColorUtils::colorFromString( properties[QStringLiteral( "outline_color" )].toString() ) );
142 }
143 else if ( properties.contains( QStringLiteral( "line_color" ) ) )
144 {
145 layer->setStrokeColor( QgsColorUtils::colorFromString( properties[QStringLiteral( "line_color" )].toString() ) );
146 }
147 if ( properties.contains( QStringLiteral( "offset" ) ) )
148 {
149 layer->setOffset( QgsSymbolLayerUtils::decodePoint( properties[QStringLiteral( "offset" )].toString() ) );
150 }
151 if ( properties.contains( QStringLiteral( "offset_unit" ) ) )
152 {
153 layer->setOffsetUnit( QgsUnitTypes::decodeRenderUnit( properties[QStringLiteral( "offset_unit" )].toString() ) );
154 }
155 if ( properties.contains( QStringLiteral( "offset_map_unit_scale" ) ) )
156 {
157 layer->setOffsetMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( properties[QStringLiteral( "offset_map_unit_scale" )].toString() ) );
158 }
159 if ( properties.contains( QStringLiteral( "horizontal_anchor_point" ) ) )
160 {
161 layer->setHorizontalAnchorPoint( QgsMarkerSymbolLayer::HorizontalAnchorPoint( properties[ QStringLiteral( "horizontal_anchor_point" )].toInt() ) );
162 }
163 if ( properties.contains( QStringLiteral( "vertical_anchor_point" ) ) )
164 {
165 layer->setVerticalAnchorPoint( QgsMarkerSymbolLayer::VerticalAnchorPoint( properties[ QStringLiteral( "vertical_anchor_point" )].toInt() ) );
166 }
167
168 //data defined properties
170
171 return layer;
172}
173
175{
176 double scaledWidth = mSymbolWidth;
177 double scaledHeight = mSymbolHeight;
178
179 QColor brushColor = mColor;
180 brushColor.setAlphaF( brushColor.alphaF() * context.opacity() );
181 mBrush.setColor( brushColor );
182
183 QColor penColor = mStrokeColor;
184 penColor.setAlphaF( penColor.alphaF() * context.opacity() );
185 mPen.setColor( penColor );
186
187 bool ok;
189 {
190 context.setOriginalValueVariable( mStrokeWidth );
192 if ( !QgsVariantUtils::isNull( exprVal ) )
193 {
194 double width = exprVal.toDouble( &ok );
195 if ( ok )
196 {
197 width = context.renderContext().convertToPainterUnits( width, mStrokeWidthUnit, mStrokeWidthMapUnitScale );
198 mPen.setWidthF( width );
199 mSelPen.setWidthF( width );
200 }
201 }
202 }
203
205 {
208 if ( !QgsVariantUtils::isNull( exprVal ) )
209 {
210 mPen.setStyle( QgsSymbolLayerUtils::decodePenStyle( exprVal.toString() ) );
211 mSelPen.setStyle( mPen.style() );
212 }
213 }
214
216 {
219 if ( !QgsVariantUtils::isNull( exprVal ) )
220 {
221 mPen.setJoinStyle( QgsSymbolLayerUtils::decodePenJoinStyle( exprVal.toString() ) );
222 mSelPen.setJoinStyle( mPen.joinStyle() );
223 }
224 }
225
227 {
230 if ( ok )
231 {
232 mPen.setCapStyle( QgsSymbolLayerUtils::decodePenCapStyle( style ) );
233 mSelPen.setCapStyle( QgsSymbolLayerUtils::decodePenCapStyle( style ) );
234 }
235 }
236
238 {
241 brushColor.setAlphaF( brushColor.alphaF() * context.opacity() );
242 mBrush.setColor( brushColor );
243 }
244
246 {
249 penColor.setAlphaF( penColor.alphaF() * context.opacity() );
250 mPen.setColor( penColor );
251 }
252
255 {
258 if ( !QgsVariantUtils::isNull( exprVal ) )
259 {
260 shape = decodeShape( exprVal.toString() );
261 }
262 preparePath( shape, context, &scaledWidth, &scaledHeight, context.feature() );
263 }
264
265 //offset and rotation
266 bool hasDataDefinedRotation = false;
267 QPointF offset;
268 double angle = 0;
269 calculateOffsetAndRotation( context, scaledWidth, scaledHeight, hasDataDefinedRotation, offset, angle );
270
271 QPainter *p = context.renderContext().painter();
272 if ( !p )
273 {
274 return;
275 }
276
277 QTransform transform;
278 transform.translate( point.x() + offset.x(), point.y() + offset.y() );
279 if ( !qgsDoubleNear( angle, 0.0 ) )
280 {
281 transform.rotate( angle );
282 }
283
284 const bool useSelectedColor = shouldRenderUsingSelectionColor( context );
285 if ( shapeIsFilled( shape ) )
286 {
287 p->setPen( useSelectedColor ? mSelPen : mPen );
288 p->setBrush( useSelectedColor ? mSelBrush : mBrush );
289 }
290 else
291 {
292 p->setPen( useSelectedColor ? mSelPen : mPen );
293 p->setBrush( QBrush() );
294 }
295 p->drawPath( transform.map( mPainterPath ) );
296}
297
298
299void QgsEllipseSymbolLayer::calculateOffsetAndRotation( QgsSymbolRenderContext &context,
300 double scaledWidth,
301 double scaledHeight,
302 bool &hasDataDefinedRotation,
303 QPointF &offset,
304 double &angle ) const
305{
306 double offsetX = 0;
307 double offsetY = 0;
308 markerOffset( context, scaledWidth, scaledHeight, mSymbolWidthUnit, mSymbolHeightUnit, offsetX, offsetY, mSymbolWidthMapUnitScale, mSymbolHeightMapUnitScale );
309 offset = QPointF( offsetX, offsetY );
310
311//priority for rotation: 1. data defined symbol level, 2. symbol layer rotation (mAngle)
312 const bool ok = true;
314 bool usingDataDefinedRotation = false;
316 {
319 usingDataDefinedRotation = ok;
320 }
321
322 hasDataDefinedRotation = context.renderHints() & Qgis::SymbolRenderHint::DynamicRotation || usingDataDefinedRotation;
323 if ( hasDataDefinedRotation )
324 {
325 // For non-point markers, "dataDefinedRotation" means following the
326 // shape (shape-data defined). For them, "field-data defined" does
327 // not work at all. TODO: if "field-data defined" ever gets implemented
328 // we'll need a way to distinguish here between the two, possibly
329 // using another flag in renderHints()
330 const QgsFeature *f = context.feature();
331 if ( f )
332 {
333 const QgsGeometry g = f->geometry();
334 if ( !g.isNull() && g.type() == Qgis::GeometryType::Point )
335 {
336 const QgsMapToPixel &m2p = context.renderContext().mapToPixel();
337 angle += m2p.mapRotation();
338 }
339 }
340 }
341
342 if ( angle )
344}
345
347{
348 return QStringLiteral( "EllipseMarker" );
349}
350
355
357{
358 QgsMarkerSymbolLayer::startRender( context ); // get anchor point expressions
359 if ( !context.feature() || !dataDefinedProperties().hasActiveProperties() )
360 {
361 preparePath( mShape, context );
362 }
363 mPen.setColor( mStrokeColor );
364 mPen.setStyle( mStrokeStyle );
365 mPen.setJoinStyle( mPenJoinStyle );
366 mPen.setCapStyle( mPenCapStyle );
367 mPen.setWidthF( context.renderContext().convertToPainterUnits( mStrokeWidth, mStrokeWidthUnit, mStrokeWidthMapUnitScale ) );
368 mBrush.setColor( mColor );
369
370 QColor selBrushColor = context.renderContext().selectionColor();
371 QColor selPenColor = selBrushColor == mColor ? selBrushColor : mStrokeColor;
372 if ( context.opacity() < 1 && !SELECTION_IS_OPAQUE )
373 {
374 selBrushColor.setAlphaF( context.opacity() );
375 selPenColor.setAlphaF( context.opacity() );
376 }
377 mSelBrush = QBrush( selBrushColor );
378 mSelPen = QPen( !shapeIsFilled( mShape ) ? selBrushColor : selPenColor );
379 mSelPen.setStyle( mStrokeStyle );
380 mSelPen.setWidthF( context.renderContext().convertToPainterUnits( mStrokeWidth, mStrokeWidthUnit, mStrokeWidthMapUnitScale ) );
381}
382
386
388{
394 m->setShape( mShape );
395 m->setSymbolWidth( mSymbolWidth );
396 m->setSymbolHeight( mSymbolHeight );
397 m->setStrokeStyle( mStrokeStyle );
398 m->setOffset( mOffset );
399 m->setStrokeStyle( mStrokeStyle );
400 m->setPenJoinStyle( mPenJoinStyle );
401 m->setPenCapStyle( mPenCapStyle );
402 m->setStrokeWidth( mStrokeWidth );
403 m->setColor( color() );
404 m->setStrokeColor( mStrokeColor );
405 m->setSymbolWidthUnit( mSymbolWidthUnit );
406 m->setSymbolWidthMapUnitScale( mSymbolWidthMapUnitScale );
407 m->setSymbolHeightUnit( mSymbolHeightUnit );
408 m->setSymbolHeightMapUnitScale( mSymbolHeightMapUnitScale );
409 m->setStrokeWidthUnit( mStrokeWidthUnit );
410 m->setStrokeWidthMapUnitScale( mStrokeWidthMapUnitScale );
411 m->setAngle( mAngle );
414
416 copyPaintEffect( m );
417 return m;
418}
419
420void QgsEllipseSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const
421{
422 QDomElement symbolizerElem = doc.createElement( QStringLiteral( "se:PointSymbolizer" ) );
423 if ( !props.value( QStringLiteral( "uom" ), QString() ).toString().isEmpty() )
424 symbolizerElem.setAttribute( QStringLiteral( "uom" ), props.value( QStringLiteral( "uom" ), QString() ).toString() );
425 element.appendChild( symbolizerElem );
426
427 // <Geometry>
428 QgsSymbolLayerUtils::createGeometryElement( doc, symbolizerElem, props.value( QStringLiteral( "geom" ), QString() ).toString() );
429
430 writeSldMarker( doc, symbolizerElem, props );
431}
432
433void QgsEllipseSymbolLayer::writeSldMarker( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const
434{
435 // <Graphic>
436 QDomElement graphicElem = doc.createElement( QStringLiteral( "se:Graphic" ) );
437 element.appendChild( graphicElem );
438
439 const double strokeWidth = QgsSymbolLayerUtils::rescaleUom( mStrokeWidth, mStrokeWidthUnit, props );
440 const double symbolWidth = QgsSymbolLayerUtils::rescaleUom( mSymbolWidth, mSymbolWidthUnit, props );
441 QgsSymbolLayerUtils::wellKnownMarkerToSld( doc, graphicElem, encodeShape( mShape ), mColor, mStrokeColor, mStrokeStyle, strokeWidth, symbolWidth );
442
443 // <Rotation>
445
446 QString angleFunc = props.value( QStringLiteral( "angle" ), QString() ).toString();
447 if ( angleFunc.isEmpty() ) // symbol has no angle set
448 {
449 if ( ddRotation && ddRotation.isActive() )
450 {
451 angleFunc = ddRotation.asExpression();
452 }
453 else if ( !qgsDoubleNear( mAngle, 0.0 ) )
454 angleFunc = QString::number( mAngle );
455 }
456 else if ( ddRotation && ddRotation.isActive() )
457 {
458 // the symbol has an angle and the symbol layer have a rotation
459 // property set
460 angleFunc = QStringLiteral( "%1 + %2" ).arg( angleFunc, ddRotation.asExpression() );
461 }
462 else if ( !qgsDoubleNear( mAngle, 0.0 ) )
463 {
464 // both the symbol and the symbol layer have angle value set
465 bool ok;
466 const double angle = angleFunc.toDouble( &ok );
467 if ( !ok )
468 {
469 // its a string (probably a property name or a function)
470 angleFunc = QStringLiteral( "%1 + %2" ).arg( angleFunc ).arg( mAngle );
471 }
472 else if ( !qgsDoubleNear( angle + mAngle, 0.0 ) )
473 {
474 // it's a double value
475 angleFunc = QString::number( angle + mAngle );
476 }
477 }
478 QgsSymbolLayerUtils::createRotationElement( doc, graphicElem, angleFunc );
479
480 // <Displacement>
483
484 // store w/h factor in a <VendorOption>
485 const double widthHeightFactor = mSymbolWidth / mSymbolHeight;
486 const QDomElement factorElem = QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "widthHeightFactor" ), QString::number( widthHeightFactor ) );
487 graphicElem.appendChild( factorElem );
488}
489
491{
492 QgsDebugMsgLevel( QStringLiteral( "Entered." ), 4 );
493
494 QDomElement graphicElem = element.firstChildElement( QStringLiteral( "Graphic" ) );
495 if ( graphicElem.isNull() )
496 return nullptr;
497
498 QString name = QStringLiteral( "circle" );
499 QColor fillColor, strokeColor;
500 double strokeWidth, size;
501 double widthHeightFactor = 1.0;
502 Qt::PenStyle strokeStyle;
503
504 QgsStringMap vendorOptions = QgsSymbolLayerUtils::getVendorOptionList( graphicElem );
505 for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
506 {
507 if ( it.key() == QLatin1String( "widthHeightFactor" ) )
508 {
509 bool ok;
510 const double v = it.value().toDouble( &ok );
511 if ( ok && !qgsDoubleNear( v, 0.0 ) && v > 0 )
512 widthHeightFactor = v;
513 }
514 }
515
517 return nullptr;
518
519 double scaleFactor = 1.0;
520 const QString uom = element.attribute( QStringLiteral( "uom" ) );
521 Qgis::RenderUnit sldUnitSize = QgsSymbolLayerUtils::decodeSldUom( uom, &scaleFactor );
522 size = size * scaleFactor;
523 strokeWidth = strokeWidth * scaleFactor;
524
525 double angle = 0.0;
526 QString angleFunc;
527 if ( QgsSymbolLayerUtils::rotationFromSldElement( graphicElem, angleFunc ) )
528 {
529 bool ok;
530 const double d = angleFunc.toDouble( &ok );
531 if ( ok )
532 angle = d;
533 }
534
536 m->setOutputUnit( sldUnitSize );
537 m->setShape( decodeShape( name ) );
542 m->setSymbolWidth( size );
543 m->setSymbolHeight( size / widthHeightFactor );
544 m->setAngle( angle );
545 return m;
546}
547
549{
550 QVariantMap map;
551 map[QStringLiteral( "symbol_name" )] = encodeShape( mShape );
552 map[QStringLiteral( "symbol_width" )] = QString::number( mSymbolWidth );
553 map[QStringLiteral( "symbol_width_unit" )] = QgsUnitTypes::encodeUnit( mSymbolWidthUnit );
554 map[QStringLiteral( "symbol_width_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mSymbolWidthMapUnitScale );
555 map[QStringLiteral( "symbol_height" )] = QString::number( mSymbolHeight );
556 map[QStringLiteral( "symbol_height_unit" )] = QgsUnitTypes::encodeUnit( mSymbolHeightUnit );
557 map[QStringLiteral( "symbol_height_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mSymbolHeightMapUnitScale );
558 map[QStringLiteral( "angle" )] = QString::number( mAngle );
559 map[QStringLiteral( "outline_style" )] = QgsSymbolLayerUtils::encodePenStyle( mStrokeStyle );
560 map[QStringLiteral( "outline_width" )] = QString::number( mStrokeWidth );
561 map[QStringLiteral( "outline_width_unit" )] = QgsUnitTypes::encodeUnit( mStrokeWidthUnit );
562 map[QStringLiteral( "outline_width_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mStrokeWidthMapUnitScale );
563 map[QStringLiteral( "joinstyle" )] = QgsSymbolLayerUtils::encodePenJoinStyle( mPenJoinStyle );
564 map[QStringLiteral( "cap_style" )] = QgsSymbolLayerUtils::encodePenCapStyle( mPenCapStyle );
565 map[QStringLiteral( "color" )] = QgsColorUtils::colorToString( mColor );
566 map[QStringLiteral( "outline_color" )] = QgsColorUtils::colorToString( mStrokeColor );
567 map[QStringLiteral( "offset" )] = QgsSymbolLayerUtils::encodePoint( mOffset );
568 map[QStringLiteral( "offset_unit" )] = QgsUnitTypes::encodeUnit( mOffsetUnit );
569 map[QStringLiteral( "offset_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mOffsetMapUnitScale );
570 map[QStringLiteral( "size" )] = QString::number( mSize );
571 map[QStringLiteral( "size_unit" )] = QgsUnitTypes::encodeUnit( mSizeUnit );
572 map[QStringLiteral( "size_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mSizeMapUnitScale );
573 map[QStringLiteral( "horizontal_anchor_point" )] = QString::number( mHorizontalAnchorPoint );
574 map[QStringLiteral( "vertical_anchor_point" )] = QString::number( mVerticalAnchorPoint );
575 return map;
576}
577
578QSizeF QgsEllipseSymbolLayer::calculateSize( QgsSymbolRenderContext &context, double *scaledWidth, double *scaledHeight )
579{
580 double width = 0;
581
582 if ( mDataDefinedProperties.isActive( QgsSymbolLayer::Property::Width ) ) //1. priority: data defined setting on symbol layer le
583 {
584 context.setOriginalValueVariable( mSymbolWidth );
586 }
587 else //2. priority: global width setting
588 {
589 width = mSymbolWidth;
590 }
591 if ( scaledWidth )
592 {
593 *scaledWidth = width;
594 }
595 width = context.renderContext().convertToPainterUnits( width, mSymbolWidthUnit, mSymbolHeightMapUnitScale );
596
597 double height = 0;
598 if ( mDataDefinedProperties.isActive( QgsSymbolLayer::Property::Height ) ) //1. priority: data defined setting on symbol layer level
599 {
600 context.setOriginalValueVariable( mSymbolHeight );
602 }
603 else //2. priority: global height setting
604 {
605 height = mSymbolHeight;
606 }
607 if ( scaledHeight )
608 {
609 *scaledHeight = height;
610 }
611 height = context.renderContext().convertToPainterUnits( height, mSymbolHeightUnit, mSymbolHeightMapUnitScale );
612 return QSizeF( width, height );
613}
614
615void QgsEllipseSymbolLayer::preparePath( const QgsEllipseSymbolLayer::Shape &shape, QgsSymbolRenderContext &context, double *scaledWidth, double *scaledHeight, const QgsFeature * )
616{
617 mPainterPath = QPainterPath();
618
619 const QSizeF size = calculateSize( context, scaledWidth, scaledHeight );
620
621 switch ( shape )
622 {
623 case Circle:
624 mPainterPath.addEllipse( QRectF( -size.width() / 2.0, -size.height() / 2.0, size.width(), size.height() ) );
625 return;
626
627 case SemiCircle:
628 mPainterPath.arcTo( -size.width() / 2.0, -size.height() / 2.0, size.width(), size.height(), 0, 180 );
629 mPainterPath.lineTo( 0, 0 );
630 return;
631
632 case ThirdCircle:
633 mPainterPath.arcTo( -size.width() / 2.0, -size.height() / 2.0, size.width(), size.height(), 90, 120 );
634 mPainterPath.lineTo( 0, 0 );
635 return;
636
637 case QuarterCircle:
638 mPainterPath.arcTo( -size.width() / 2.0, -size.height() / 2.0, size.width(), size.height(), 90, 90 );
639 mPainterPath.lineTo( 0, 0 );
640 return;
641
642 case Rectangle:
643 mPainterPath.addRect( QRectF( -size.width() / 2.0, -size.height() / 2.0, size.width(), size.height() ) );
644 return;
645
646 case Diamond:
647 mPainterPath.moveTo( -size.width() / 2.0, 0 );
648 mPainterPath.lineTo( 0, size.height() / 2.0 );
649 mPainterPath.lineTo( size.width() / 2.0, 0 );
650 mPainterPath.lineTo( 0, -size.height() / 2.0 );
651 mPainterPath.lineTo( -size.width() / 2.0, 0 );
652 return;
653
654 case Cross:
655 mPainterPath.moveTo( 0, -size.height() / 2.0 );
656 mPainterPath.lineTo( 0, size.height() / 2.0 );
657 mPainterPath.moveTo( -size.width() / 2.0, 0 );
658 mPainterPath.lineTo( size.width() / 2.0, 0 );
659 return;
660
661 case Arrow:
662 mPainterPath.moveTo( -size.width() / 2.0, size.height() / 2.0 );
663 mPainterPath.lineTo( 0, -size.height() / 2.0 );
664 mPainterPath.lineTo( size.width() / 2.0, size.height() / 2.0 );
665 return;
666
667 case HalfArc:
668 mPainterPath.moveTo( size.width() / 2.0, 0 );
669 mPainterPath.arcTo( -size.width() / 2.0, -size.height() / 2.0, size.width(), size.height(), 0, 180 );
670 return;
671
672 case Triangle:
673 mPainterPath.moveTo( 0, -size.height() / 2.0 );
674 mPainterPath.lineTo( -size.width() / 2.0, size.height() / 2.0 );
675 mPainterPath.lineTo( size.width() / 2.0, size.height() / 2.0 );
676 mPainterPath.lineTo( 0, -size.height() / 2.0 );
677 return;
678
679 case LeftHalfTriangle:
680 mPainterPath.moveTo( 0, size.height() / 2.0 );
681 mPainterPath.lineTo( size.width() / 2.0, size.height() / 2.0 );
682 mPainterPath.lineTo( 0, -size.height() / 2.0 );
683 mPainterPath.lineTo( 0, size.height() / 2.0 );
684 return;
685
687 mPainterPath.moveTo( -size.width() / 2.0, size.height() / 2.0 );
688 mPainterPath.lineTo( 0, size.height() / 2.0 );
689 mPainterPath.lineTo( 0, -size.height() / 2.0 );
690 mPainterPath.lineTo( -size.width() / 2.0, size.height() / 2.0 );
691 return;
692
693 case Pentagon:
694 mPainterPath.moveTo( ( size.width() * -0.9511 ) / 2.0, size.height() / ( 2 / -0.309 ) );
695 mPainterPath.lineTo( ( size.width() * -0.5878 ) / 2.0, size.height() / ( 2 / 0.8090 ) );
696 mPainterPath.lineTo( ( size.width() * 0.5878 ) / 2.0, size.height() / ( 2 / 0.8090 ) );
697 mPainterPath.lineTo( ( size.width() * 0.9511 ) / 2.0, size.height() / ( 2 / -0.309 ) );
698 mPainterPath.lineTo( 0, size.height() / -2.0 );
699 mPainterPath.lineTo( ( size.width() * -0.9511 ) / 2.0, size.height() / ( 2 / -0.309 ) );
700 return;
701
702 case Hexagon:
703 mPainterPath.moveTo( ( size.width() * 0.8660 ) / 2.0, size.height() / 4.0 );
704 mPainterPath.lineTo( ( size.width() * 0.8660 ) / 2.0, size.height() / -4.0 );
705 mPainterPath.lineTo( 0, size.height() / -2.0 );
706 mPainterPath.lineTo( ( size.width() * 0.8660 ) / -2.0, size.height() / -4.0 );
707 mPainterPath.lineTo( ( size.width() * 0.8660 ) / -2.0, size.height() / 4.0 );
708 mPainterPath.lineTo( 0, size.height() / 2.0 );
709 mPainterPath.lineTo( ( size.width() * 0.8660 ) / 2.0, size.height() / 4.0 );
710 return;
711
712 case Octagon:
713 {
714 static constexpr double VERTEX_OFFSET_FROM_ORIGIN = 1.0 / ( 1 + M_SQRT2 );
715 mPainterPath.moveTo( ( size.width() * VERTEX_OFFSET_FROM_ORIGIN ) / -2.0, size.height() / 2.0 );
716 mPainterPath.lineTo( ( size.width() * VERTEX_OFFSET_FROM_ORIGIN ) / 2.0, size.height() / 2.0 );
717 mPainterPath.lineTo( size.width() / 2.0, ( size.height() * VERTEX_OFFSET_FROM_ORIGIN ) / 2.0 );
718 mPainterPath.lineTo( size.width() / 2.0, ( size.height() * VERTEX_OFFSET_FROM_ORIGIN ) / -2.0 );
719 mPainterPath.lineTo( ( size.width() * VERTEX_OFFSET_FROM_ORIGIN ) / 2.0, size.height() / -2.0 );
720 mPainterPath.lineTo( ( size.width() * VERTEX_OFFSET_FROM_ORIGIN ) / -2.0, size.height() / -2.0 );
721 mPainterPath.lineTo( size.width() / -2.0, ( size.height() * VERTEX_OFFSET_FROM_ORIGIN ) / -2.0 );
722 mPainterPath.lineTo( size.width() / -2.0, ( size.height() * VERTEX_OFFSET_FROM_ORIGIN ) / 2.0 );
723 mPainterPath.lineTo( ( size.width() * VERTEX_OFFSET_FROM_ORIGIN ) / -2.0, size.height() / 2.0 );
724 return;
725 }
726
727 case Star:
728 {
729 const double inner_r = std::cos( DEG2RAD( 72.0 ) ) / std::cos( DEG2RAD( 36.0 ) );
730 mPainterPath.moveTo( ( size.width() * inner_r * std::sin( DEG2RAD( 324.0 ) ) ) / 2.0, ( size.height() * inner_r * std::cos( DEG2RAD( 324.0 ) ) ) / -2.0 );
731 mPainterPath.lineTo( ( size.width() * std::sin( DEG2RAD( 288.0 ) ) ) / 2.0, ( size.height() * std::cos( DEG2RAD( 288.0 ) ) ) / -2.0 );
732 mPainterPath.lineTo( ( size.width() * inner_r * std::sin( DEG2RAD( 252.0 ) ) ) / 2.0, ( size.height() * inner_r * std::cos( DEG2RAD( 252.0 ) ) ) / -2.0 );
733 mPainterPath.lineTo( ( size.width() * std::sin( DEG2RAD( 216.0 ) ) ) / 2.0, ( size.height() * std::cos( DEG2RAD( 216.0 ) ) ) / -2.0 );
734 mPainterPath.lineTo( 0, ( size.height() * inner_r ) / 2.0 );
735 mPainterPath.lineTo( ( size.width() * std::sin( DEG2RAD( 144.0 ) ) ) / 2.0, ( size.height() * std::cos( DEG2RAD( 144.0 ) ) ) / -2.0 );
736 mPainterPath.lineTo( ( size.width() * inner_r * std::sin( DEG2RAD( 108.0 ) ) ) / 2.0, ( size.height() * inner_r * std::cos( DEG2RAD( 108.0 ) ) ) / -2.0 );
737 mPainterPath.lineTo( ( size.width() * std::sin( DEG2RAD( 72.0 ) ) ) / 2.0, ( size.height() * std::cos( DEG2RAD( 72.0 ) ) ) / -2.0 );
738 mPainterPath.lineTo( ( size.width() * inner_r * std::sin( DEG2RAD( 36.0 ) ) ) / 2.0, ( size.height() * inner_r * std::cos( DEG2RAD( 36.0 ) ) ) / -2.0 );
739 mPainterPath.lineTo( 0, size.height() / -2.0 );
740 mPainterPath.lineTo( ( size.width() * inner_r * std::sin( DEG2RAD( 324.0 ) ) ) / 2.0, ( size.height() * inner_r * std::cos( DEG2RAD( 324.0 ) ) ) / -2.0 );
741 return;
742 }
743 }
744}
745
747{
748 switch ( shape )
749 {
750 case Circle:
751 case Rectangle:
752 case Diamond:
753 case Triangle:
755 case LeftHalfTriangle:
756 case SemiCircle:
757 case ThirdCircle:
758 case QuarterCircle:
759 case Pentagon:
760 case Hexagon:
761 case Octagon:
762 case Star:
763 return true;
764
765 case Cross:
766 case Arrow:
767 case HalfArc:
768 return false;
769 }
770
771 return true;
772}
773
775{
776 if ( mSymbolWidth >= mSymbolHeight )
777 {
778 mSymbolHeight = mSymbolHeight * size / mSymbolWidth;
779 mSymbolWidth = size;
780 }
781 else
782 {
783 mSymbolWidth = mSymbolWidth * size / mSymbolHeight;
784 mSymbolHeight = size;
785 }
787}
788
790{
791 mSymbolWidth = w;
792 QgsMarkerSymbolLayer::setSize( mSymbolWidth >= mSymbolHeight ? mSymbolWidth : mSymbolHeight );
793}
794
796{
797 mSymbolHeight = h;
798 QgsMarkerSymbolLayer::setSize( mSymbolWidth >= mSymbolHeight ? mSymbolWidth : mSymbolHeight );
799}
800
802{
804 mSymbolWidthUnit = unit;
805 mSymbolHeightUnit = unit;
806 mStrokeWidthUnit = unit;
807}
808
810{
812 if ( mSymbolWidthUnit != unit || mSymbolHeightUnit != unit || mStrokeWidthUnit != unit )
813 {
815 }
816 return unit;
817}
818
820{
821 return mSymbolWidthUnit == Qgis::RenderUnit::MapUnits || mSymbolWidthUnit == Qgis::RenderUnit::MetersInMapUnits
822 || mSymbolHeightUnit == Qgis::RenderUnit::MapUnits || mSymbolHeightUnit == Qgis::RenderUnit::MetersInMapUnits
823 || mStrokeWidthUnit == Qgis::RenderUnit::MapUnits || mStrokeWidthUnit == Qgis::RenderUnit::MetersInMapUnits
825}
826
828{
830 mSymbolWidthMapUnitScale = scale;
831 mSymbolHeightMapUnitScale = scale;
832 mStrokeWidthMapUnitScale = scale;
833}
834
836{
837 if ( QgsMarkerSymbolLayer::mapUnitScale() == mSymbolWidthMapUnitScale &&
838 mSymbolWidthMapUnitScale == mSymbolHeightMapUnitScale &&
839 mSymbolHeightMapUnitScale == mStrokeWidthMapUnitScale )
840 {
841 return mSymbolWidthMapUnitScale;
842 }
843 return QgsMapUnitScale();
844}
845
847{
848 const QSizeF size = calculateSize( context );
849
850 bool hasDataDefinedRotation = false;
851 QPointF offset;
852 double angle = 0;
853 calculateOffsetAndRotation( context, size.width(), size.height(), hasDataDefinedRotation, offset, angle );
854
855 QTransform transform;
856
857 // move to the desired position
858 transform.translate( point.x() + offset.x(), point.y() + offset.y() );
859
860 if ( !qgsDoubleNear( angle, 0.0 ) )
861 transform.rotate( angle );
862
863 double penWidth = mStrokeWidth;
865 {
866 context.setOriginalValueVariable( mStrokeWidth );
868
869 if ( !QgsVariantUtils::isNull( exprVal ) )
870 {
871 bool ok;
872 const double strokeWidth = exprVal.toDouble( &ok );
873 if ( ok )
874 {
875 penWidth = strokeWidth;
876 }
877 }
878 }
879 penWidth = context.renderContext().convertToPainterUnits( penWidth, mStrokeWidthUnit, mStrokeWidthMapUnitScale );
880
882 {
885 if ( !QgsVariantUtils::isNull( exprVal ) && exprVal.toString() == QLatin1String( "no" ) )
886 {
887 penWidth = 0.0;
888 }
889 }
890 else if ( mStrokeStyle == Qt::NoPen )
891 penWidth = 0;
892
893 //antialiasing, add 1 pixel
894 penWidth += 1;
895
896 QRectF symbolBounds = transform.mapRect( QRectF( -size.width() / 2.0,
897 -size.height() / 2.0,
898 size.width(),
899 size.height() ) );
900
901 //extend bounds by pen width / 2.0
902 symbolBounds.adjust( -penWidth / 2.0, -penWidth / 2.0,
903 penWidth / 2.0, penWidth / 2.0 );
904
905 return symbolBounds;
906}
907
908bool QgsEllipseSymbolLayer::writeDxf( QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, QgsSymbolRenderContext &context, QPointF shift ) const
909{
910 //width
911 double symbolWidth = mSymbolWidth;
912
913 if ( mDataDefinedProperties.isActive( QgsSymbolLayer::Property::Width ) ) //1. priority: data defined setting on symbol layer le
914 {
915 context.setOriginalValueVariable( mSymbolWidth );
917 }
918 if ( mSymbolWidthUnit == Qgis::RenderUnit::Millimeters )
919 {
920 symbolWidth *= mmMapUnitScaleFactor;
921 }
922
923 //height
924 double symbolHeight = mSymbolHeight;
925 if ( mDataDefinedProperties.isActive( QgsSymbolLayer::Property::Height ) ) //1. priority: data defined setting on symbol layer level
926 {
927 context.setOriginalValueVariable( mSymbolHeight );
929 }
930 if ( mSymbolHeightUnit == Qgis::RenderUnit::Millimeters )
931 {
932 symbolHeight *= mmMapUnitScaleFactor;
933 }
934
935 //stroke width
936 double strokeWidth = mStrokeWidth;
937
939 {
940 context.setOriginalValueVariable( mStrokeWidth );
942 }
943 if ( mStrokeWidthUnit == Qgis::RenderUnit::Millimeters )
944 {
946 }
947
948 //fill color
949 QColor fc = mColor;
951 {
954 }
955
956 //stroke color
957 QColor oc = mStrokeColor;
959 {
962 }
963
964 //symbol name
967 {
970 }
971
972 //offset
973 double offsetX = 0;
974 double offsetY = 0;
975 markerOffset( context, offsetX, offsetY );
976 QPointF off( offsetX, offsetY );
977
978 //priority for rotation: 1. data defined symbol level, 2. symbol layer rotation (mAngle)
979 double rotation = 0.0;
981 {
984 }
985 else if ( !qgsDoubleNear( mAngle + mLineAngle, 0.0 ) )
986 {
987 rotation = mAngle + mLineAngle;
988 }
989 rotation = -rotation; //rotation in Qt is counterclockwise
990 if ( rotation )
991 off = _rotatedOffset( off, rotation );
992
993 QTransform t;
994 t.translate( shift.x() + offsetX, shift.y() + offsetY );
995
996 if ( !qgsDoubleNear( rotation, 0.0 ) )
997 t.rotate( rotation );
998
999 const double halfWidth = symbolWidth / 2.0;
1000 const double halfHeight = symbolHeight / 2.0;
1001
1002 switch ( shape )
1003 {
1004 case Circle:
1005 {
1006 if ( qgsDoubleNear( halfWidth, halfHeight ) )
1007 {
1008 const QgsPoint pt( t.map( QPointF( 0, 0 ) ) );
1009 e.writeFilledCircle( layerName, oc, pt, halfWidth );
1010 }
1011 else
1012 {
1013 QgsPointSequence line;
1014
1015 const double stepsize = 2 * M_PI / 40;
1016 for ( int i = 0; i < 39; ++i )
1017 {
1018 const double angle = stepsize * i;
1019 const double x = halfWidth * std::cos( angle );
1020 const double y = halfHeight * std::sin( angle );
1021 line << QgsPoint( t.map( QPointF( x, y ) ) );
1022 }
1023 //close ellipse with first point
1024 line << line.at( 0 );
1025
1026 if ( mBrush.style() != Qt::NoBrush )
1027 e.writePolygon( QgsRingSequence() << line, layerName, QStringLiteral( "SOLID" ), fc );
1028 if ( mPen.style() != Qt::NoPen )
1029 e.writePolyline( line, layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth );
1030 }
1031 return true;
1032 }
1033
1034 case Rectangle:
1035 {
1037 p << QgsPoint( t.map( QPointF( -halfWidth, -halfHeight ) ) )
1038 << QgsPoint( t.map( QPointF( halfWidth, -halfHeight ) ) )
1039 << QgsPoint( t.map( QPointF( halfWidth, halfHeight ) ) )
1040 << QgsPoint( t.map( QPointF( -halfWidth, halfHeight ) ) );
1041 p << p[0];
1042
1043 if ( mBrush.style() != Qt::NoBrush )
1044 e.writePolygon( QgsRingSequence() << p, layerName, QStringLiteral( "SOLID" ), fc );
1045 if ( mPen.style() != Qt::NoPen )
1046 e.writePolyline( p, layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth );
1047 return true;
1048 }
1049 case Cross:
1050 {
1051 if ( mPen.style() != Qt::NoPen )
1052 {
1054 << QgsPoint( t.map( QPointF( -halfWidth, 0 ) ) )
1055 << QgsPoint( t.map( QPointF( halfWidth, 0 ) ) ),
1056 layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth );
1058 << QgsPoint( t.map( QPointF( 0, halfHeight ) ) )
1059 << QgsPoint( t.map( QPointF( 0, -halfHeight ) ) ),
1060 layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth );
1061 return true;
1062 }
1063 break;
1064 }
1065
1066 case Triangle:
1067 {
1069 p << QgsPoint( t.map( QPointF( -halfWidth, -halfHeight ) ) )
1070 << QgsPoint( t.map( QPointF( halfWidth, -halfHeight ) ) )
1071 << QgsPoint( t.map( QPointF( 0, halfHeight ) ) );
1072 p << p[0];
1073 if ( mBrush.style() != Qt::NoBrush )
1074 e.writePolygon( QgsRingSequence() << p, layerName, QStringLiteral( "SOLID" ), fc );
1075 if ( mPen.style() != Qt::NoPen )
1076 e.writePolyline( p, layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth );
1077 return true;
1078 }
1079
1080 case Diamond:
1081 case Arrow:
1082 case HalfArc:
1083 case RightHalfTriangle:
1084 case LeftHalfTriangle:
1085 case SemiCircle:
1086 case ThirdCircle:
1087 case QuarterCircle:
1088 case Pentagon:
1089 case Hexagon:
1090 case Octagon:
1091 case Star:
1092 return false;
1093 }
1094
1095 return false;
1096}
1097
1099{
1100 if ( ok )
1101 *ok = true;
1102 const QString cleaned = name.toLower().trimmed();
1103
1104 if ( cleaned == QLatin1String( "circle" ) )
1105 return Circle;
1106 else if ( cleaned == QLatin1String( "square" ) || cleaned == QLatin1String( "rectangle" ) )
1107 return Rectangle;
1108 else if ( cleaned == QLatin1String( "diamond" ) )
1109 return Diamond;
1110 else if ( cleaned == QLatin1String( "cross" ) )
1111 return Cross;
1112 else if ( cleaned == QLatin1String( "arrow" ) )
1113 return Arrow;
1114 else if ( cleaned == QLatin1String( "half_arc" ) )
1115 return HalfArc;
1116 else if ( cleaned == QLatin1String( "triangle" ) )
1117 return Triangle;
1118 else if ( cleaned == QLatin1String( "right_half_triangle" ) )
1119 return RightHalfTriangle;
1120 else if ( cleaned == QLatin1String( "left_half_triangle" ) )
1121 return LeftHalfTriangle;
1122 else if ( cleaned == QLatin1String( "semi_circle" ) )
1123 return SemiCircle;
1124 else if ( cleaned == QLatin1String( "third_circle" ) )
1125 return ThirdCircle;
1126 else if ( cleaned == QLatin1String( "quarter_circle" ) )
1127 return QuarterCircle;
1128 else if ( cleaned == QLatin1String( "pentagon" ) )
1129 return Pentagon;
1130 else if ( cleaned == QLatin1String( "hexagon" ) )
1131 return Hexagon;
1132 else if ( cleaned == QLatin1String( "octagon" ) )
1133 return Octagon;
1134 else if ( cleaned == QLatin1String( "star" ) )
1135 return Star; if ( ok )
1136 *ok = false;
1137 return Circle;
1138}
1139
1141{
1142 switch ( shape )
1143 {
1144 case Circle:
1145 return QStringLiteral( "circle" );
1146 case Rectangle:
1147 return QStringLiteral( "rectangle" );
1148 case Diamond:
1149 return QStringLiteral( "diamond" );
1150 case Cross:
1151 return QStringLiteral( "cross" );
1152 case Arrow:
1153 return QStringLiteral( "arrow" );
1154 case HalfArc:
1155 return QStringLiteral( "half_arc" );
1156 case Triangle:
1157 return QStringLiteral( "triangle" );
1158 case RightHalfTriangle:
1159 return QStringLiteral( "right_half_triangle" );
1160 case LeftHalfTriangle:
1161 return QStringLiteral( "left_half_triangle" );
1162 case SemiCircle:
1163 return QStringLiteral( "semi_circle" );
1164 case ThirdCircle:
1165 return QStringLiteral( "third_circle" );
1166 case QuarterCircle:
1167 return QStringLiteral( "quarter_circle" );
1168 case Pentagon:
1169 return QStringLiteral( "pentagon" );
1170 case Hexagon:
1171 return QStringLiteral( "hexagon" );
1172 case Octagon:
1173 return QStringLiteral( "octagon" );
1174 case Star:
1175 return QStringLiteral( "star" );
1176 }
1177 return QString();
1178}
1179
1180QList<QgsEllipseSymbolLayer::Shape> QgsEllipseSymbolLayer::availableShapes()
1181{
1182 QList< Shape > shapes;
1183 shapes << Circle
1184 << Rectangle
1185 << Diamond
1186 << Cross
1187 << Arrow
1188 << HalfArc
1189 << Triangle
1192 << SemiCircle
1193 << ThirdCircle
1194 << QuarterCircle
1195 << Pentagon
1196 << Hexagon
1197 << Octagon
1198 << Star;
1199 return shapes;
1200}
@ DynamicRotation
Rotation of symbol may be changed during rendering and symbol should not be cached.
@ CanCalculateMaskGeometryPerFeature
If present, indicates that mask geometry can safely be calculated per feature for the symbol layer....
QFlags< SymbolLayerFlag > SymbolLayerFlags
Symbol layer flags.
Definition qgis.h:644
RenderUnit
Rendering size units.
Definition qgis.h:4494
@ Millimeters
Millimeters.
@ Unknown
Mixed or unknown units.
@ MapUnits
Map units.
@ MetersInMapUnits
Meters value as Map units.
QColor valueAsColor(int key, const QgsExpressionContext &context, const QColor &defaultColor=QColor(), bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a color.
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.
QString valueAsString(int key, const QgsExpressionContext &context, const QString &defaultString=QString(), bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a string.
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)
A symbol layer for rendering objects with major and minor axis (e.g.
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 toSld(QDomDocument &doc, QDomElement &element, const QVariantMap &props) const override
Saves the symbol layer as SLD.
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.
@ ThirdCircle
Third Circle (since QGIS 3.28)
@ Pentagon
Pentagon (since QGIS 3.28)
@ Hexagon
Hexagon (since QGIS 3.28)
@ Cross
Stroke-only cross.
@ QuarterCircle
Quarter Circle (since QGIS 3.28)
@ HalfArc
Stroke-only half arc (since QGIS 3.20)
@ Arrow
Stroke-only arrow (since QGIS 3.20)
@ RightHalfTriangle
Right half of a triangle.
@ Star
Star (since QGIS 3.28)
@ Octagon
Octagon (since QGIS 3.28)
@ 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.
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
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
A geometry is the spatial representation of a feature.
Qgis::GeometryType type
Perform transforms between map coordinates and device coordinates.
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.
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)
HorizontalAnchorPoint
Symbol horizontal anchor points.
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.
void setVerticalAnchorPoint(VerticalAnchorPoint v)
Sets the vertical anchor point for positioning the symbol.
QPointF mOffset
Marker offset.
void setHorizontalAnchorPoint(HorizontalAnchorPoint h)
Sets the horizontal anchor point for positioning the symbol.
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.
HorizontalAnchorPoint mHorizontalAnchorPoint
Horizontal anchor point.
static QPointF _rotatedOffset(QPointF offset, double angle)
Adjusts a marker offset to account for rotation.
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.
VerticalAnchorPoint
Symbol vertical anchor points.
void markerOffset(QgsSymbolRenderContext &context, double &offsetX, double &offsetY) const
Calculates the required marker offset, including both the symbol offset and any displacement required...
VerticalAnchorPoint mVerticalAnchorPoint
Vertical 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
QVariant value(int key, const QgsExpressionContext &context, const QVariant &defaultValue=QVariant()) const final
Returns the calculated value of the property with the specified key from within the collection.
bool isActive(int key) const final
Returns true if the collection contains an active property with the specified key.
QgsProperty property(int key) const final
Returns a matching property from the collection, if one exists.
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...
QVariant value(const QgsExpressionContext &context, const QVariant &defaultValue=QVariant(), bool *ok=nullptr) const
Calculates the current value of the property, including any transforms which are set for the property...
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.
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)
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 void createGeometryElement(QDomDocument &doc, QDomElement &element, const QString &geomFunc)
static void wellKnownMarkerToSld(QDomDocument &doc, QDomElement &element, const QString &name, const QColor &color, const QColor &strokeColor, Qt::PenStyle strokeStyle, double strokeWidth=-1, double size=-1)
static Qt::PenStyle decodePenStyle(const QString &str)
static void createRotationElement(QDomDocument &doc, QDomElement &element, const QString &rotationFunc)
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.
@ StrokeColor
Stroke color.
@ CapStyle
Line cap style.
@ JoinStyle
Line join style.
@ StrokeWidth
Stroke width.
@ Height
Symbol height.
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.
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:5465
QMap< QString, QString > QgsStringMap
Definition qgis.h:6003
QVector< QgsPointSequence > QgsRingSequence
QVector< QgsPoint > QgsPointSequence
#define DEG2RAD(x)
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:39