QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
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
352{
353 QgsMarkerSymbolLayer::startRender( context ); // get anchor point expressions
354 if ( !context.feature() || !dataDefinedProperties().hasActiveProperties() )
355 {
356 preparePath( mShape, context );
357 }
358 mPen.setColor( mStrokeColor );
359 mPen.setStyle( mStrokeStyle );
360 mPen.setJoinStyle( mPenJoinStyle );
361 mPen.setCapStyle( mPenCapStyle );
362 mPen.setWidthF( context.renderContext().convertToPainterUnits( mStrokeWidth, mStrokeWidthUnit, mStrokeWidthMapUnitScale ) );
363 mBrush.setColor( mColor );
364
365 QColor selBrushColor = context.renderContext().selectionColor();
366 QColor selPenColor = selBrushColor == mColor ? selBrushColor : mStrokeColor;
367 if ( context.opacity() < 1 && !SELECTION_IS_OPAQUE )
368 {
369 selBrushColor.setAlphaF( context.opacity() );
370 selPenColor.setAlphaF( context.opacity() );
371 }
372 mSelBrush = QBrush( selBrushColor );
373 mSelPen = QPen( !shapeIsFilled( mShape ) ? selBrushColor : selPenColor );
374 mSelPen.setStyle( mStrokeStyle );
375 mSelPen.setWidthF( context.renderContext().convertToPainterUnits( mStrokeWidth, mStrokeWidthUnit, mStrokeWidthMapUnitScale ) );
376}
377
379{
380}
381
383{
389 m->setShape( mShape );
390 m->setSymbolWidth( mSymbolWidth );
391 m->setSymbolHeight( mSymbolHeight );
392 m->setStrokeStyle( mStrokeStyle );
393 m->setOffset( mOffset );
394 m->setStrokeStyle( mStrokeStyle );
395 m->setPenJoinStyle( mPenJoinStyle );
396 m->setPenCapStyle( mPenCapStyle );
397 m->setStrokeWidth( mStrokeWidth );
398 m->setColor( color() );
399 m->setStrokeColor( mStrokeColor );
400 m->setSymbolWidthUnit( mSymbolWidthUnit );
401 m->setSymbolWidthMapUnitScale( mSymbolWidthMapUnitScale );
402 m->setSymbolHeightUnit( mSymbolHeightUnit );
403 m->setSymbolHeightMapUnitScale( mSymbolHeightMapUnitScale );
404 m->setStrokeWidthUnit( mStrokeWidthUnit );
405 m->setStrokeWidthMapUnitScale( mStrokeWidthMapUnitScale );
406 m->setAngle( mAngle );
409
411 copyPaintEffect( m );
412 return m;
413}
414
415void QgsEllipseSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const
416{
417 QDomElement symbolizerElem = doc.createElement( QStringLiteral( "se:PointSymbolizer" ) );
418 if ( !props.value( QStringLiteral( "uom" ), QString() ).toString().isEmpty() )
419 symbolizerElem.setAttribute( QStringLiteral( "uom" ), props.value( QStringLiteral( "uom" ), QString() ).toString() );
420 element.appendChild( symbolizerElem );
421
422 // <Geometry>
423 QgsSymbolLayerUtils::createGeometryElement( doc, symbolizerElem, props.value( QStringLiteral( "geom" ), QString() ).toString() );
424
425 writeSldMarker( doc, symbolizerElem, props );
426}
427
428void QgsEllipseSymbolLayer::writeSldMarker( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const
429{
430 // <Graphic>
431 QDomElement graphicElem = doc.createElement( QStringLiteral( "se:Graphic" ) );
432 element.appendChild( graphicElem );
433
434 const double strokeWidth = QgsSymbolLayerUtils::rescaleUom( mStrokeWidth, mStrokeWidthUnit, props );
435 const double symbolWidth = QgsSymbolLayerUtils::rescaleUom( mSymbolWidth, mSymbolWidthUnit, props );
436 QgsSymbolLayerUtils::wellKnownMarkerToSld( doc, graphicElem, encodeShape( mShape ), mColor, mStrokeColor, mStrokeStyle, strokeWidth, symbolWidth );
437
438 // <Rotation>
440
441 QString angleFunc = props.value( QStringLiteral( "angle" ), QString() ).toString();
442 if ( angleFunc.isEmpty() ) // symbol has no angle set
443 {
444 if ( ddRotation && ddRotation.isActive() )
445 {
446 angleFunc = ddRotation.asExpression();
447 }
448 else if ( !qgsDoubleNear( mAngle, 0.0 ) )
449 angleFunc = QString::number( mAngle );
450 }
451 else if ( ddRotation && ddRotation.isActive() )
452 {
453 // the symbol has an angle and the symbol layer have a rotation
454 // property set
455 angleFunc = QStringLiteral( "%1 + %2" ).arg( angleFunc, ddRotation.asExpression() );
456 }
457 else if ( !qgsDoubleNear( mAngle, 0.0 ) )
458 {
459 // both the symbol and the symbol layer have angle value set
460 bool ok;
461 const double angle = angleFunc.toDouble( &ok );
462 if ( !ok )
463 {
464 // its a string (probably a property name or a function)
465 angleFunc = QStringLiteral( "%1 + %2" ).arg( angleFunc ).arg( mAngle );
466 }
467 else if ( !qgsDoubleNear( angle + mAngle, 0.0 ) )
468 {
469 // it's a double value
470 angleFunc = QString::number( angle + mAngle );
471 }
472 }
473 QgsSymbolLayerUtils::createRotationElement( doc, graphicElem, angleFunc );
474
475 // <Displacement>
478
479 // store w/h factor in a <VendorOption>
480 const double widthHeightFactor = mSymbolWidth / mSymbolHeight;
481 const QDomElement factorElem = QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "widthHeightFactor" ), QString::number( widthHeightFactor ) );
482 graphicElem.appendChild( factorElem );
483}
484
486{
487 QgsDebugMsgLevel( QStringLiteral( "Entered." ), 4 );
488
489 QDomElement graphicElem = element.firstChildElement( QStringLiteral( "Graphic" ) );
490 if ( graphicElem.isNull() )
491 return nullptr;
492
493 QString name = QStringLiteral( "circle" );
494 QColor fillColor, strokeColor;
495 double strokeWidth, size;
496 double widthHeightFactor = 1.0;
497 Qt::PenStyle strokeStyle;
498
499 QgsStringMap vendorOptions = QgsSymbolLayerUtils::getVendorOptionList( graphicElem );
500 for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
501 {
502 if ( it.key() == QLatin1String( "widthHeightFactor" ) )
503 {
504 bool ok;
505 const double v = it.value().toDouble( &ok );
506 if ( ok && !qgsDoubleNear( v, 0.0 ) && v > 0 )
507 widthHeightFactor = v;
508 }
509 }
510
512 return nullptr;
513
514 double scaleFactor = 1.0;
515 const QString uom = element.attribute( QStringLiteral( "uom" ) );
516 Qgis::RenderUnit sldUnitSize = QgsSymbolLayerUtils::decodeSldUom( uom, &scaleFactor );
517 size = size * scaleFactor;
518 strokeWidth = strokeWidth * scaleFactor;
519
520 double angle = 0.0;
521 QString angleFunc;
522 if ( QgsSymbolLayerUtils::rotationFromSldElement( graphicElem, angleFunc ) )
523 {
524 bool ok;
525 const double d = angleFunc.toDouble( &ok );
526 if ( ok )
527 angle = d;
528 }
529
531 m->setOutputUnit( sldUnitSize );
532 m->setShape( decodeShape( name ) );
537 m->setSymbolWidth( size );
538 m->setSymbolHeight( size / widthHeightFactor );
539 m->setAngle( angle );
540 return m;
541}
542
544{
545 QVariantMap map;
546 map[QStringLiteral( "symbol_name" )] = encodeShape( mShape );
547 map[QStringLiteral( "symbol_width" )] = QString::number( mSymbolWidth );
548 map[QStringLiteral( "symbol_width_unit" )] = QgsUnitTypes::encodeUnit( mSymbolWidthUnit );
549 map[QStringLiteral( "symbol_width_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mSymbolWidthMapUnitScale );
550 map[QStringLiteral( "symbol_height" )] = QString::number( mSymbolHeight );
551 map[QStringLiteral( "symbol_height_unit" )] = QgsUnitTypes::encodeUnit( mSymbolHeightUnit );
552 map[QStringLiteral( "symbol_height_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mSymbolHeightMapUnitScale );
553 map[QStringLiteral( "angle" )] = QString::number( mAngle );
554 map[QStringLiteral( "outline_style" )] = QgsSymbolLayerUtils::encodePenStyle( mStrokeStyle );
555 map[QStringLiteral( "outline_width" )] = QString::number( mStrokeWidth );
556 map[QStringLiteral( "outline_width_unit" )] = QgsUnitTypes::encodeUnit( mStrokeWidthUnit );
557 map[QStringLiteral( "outline_width_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mStrokeWidthMapUnitScale );
558 map[QStringLiteral( "joinstyle" )] = QgsSymbolLayerUtils::encodePenJoinStyle( mPenJoinStyle );
559 map[QStringLiteral( "cap_style" )] = QgsSymbolLayerUtils::encodePenCapStyle( mPenCapStyle );
560 map[QStringLiteral( "color" )] = QgsColorUtils::colorToString( mColor );
561 map[QStringLiteral( "outline_color" )] = QgsColorUtils::colorToString( mStrokeColor );
562 map[QStringLiteral( "offset" )] = QgsSymbolLayerUtils::encodePoint( mOffset );
563 map[QStringLiteral( "offset_unit" )] = QgsUnitTypes::encodeUnit( mOffsetUnit );
564 map[QStringLiteral( "offset_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mOffsetMapUnitScale );
565 map[QStringLiteral( "size" )] = QString::number( mSize );
566 map[QStringLiteral( "size_unit" )] = QgsUnitTypes::encodeUnit( mSizeUnit );
567 map[QStringLiteral( "size_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mSizeMapUnitScale );
568 map[QStringLiteral( "horizontal_anchor_point" )] = QString::number( mHorizontalAnchorPoint );
569 map[QStringLiteral( "vertical_anchor_point" )] = QString::number( mVerticalAnchorPoint );
570 return map;
571}
572
573QSizeF QgsEllipseSymbolLayer::calculateSize( QgsSymbolRenderContext &context, double *scaledWidth, double *scaledHeight )
574{
575 double width = 0;
576
577 if ( mDataDefinedProperties.isActive( QgsSymbolLayer::Property::Width ) ) //1. priority: data defined setting on symbol layer le
578 {
579 context.setOriginalValueVariable( mSymbolWidth );
581 }
582 else //2. priority: global width setting
583 {
584 width = mSymbolWidth;
585 }
586 if ( scaledWidth )
587 {
588 *scaledWidth = width;
589 }
590 width = context.renderContext().convertToPainterUnits( width, mSymbolWidthUnit, mSymbolHeightMapUnitScale );
591
592 double height = 0;
593 if ( mDataDefinedProperties.isActive( QgsSymbolLayer::Property::Height ) ) //1. priority: data defined setting on symbol layer level
594 {
595 context.setOriginalValueVariable( mSymbolHeight );
597 }
598 else //2. priority: global height setting
599 {
600 height = mSymbolHeight;
601 }
602 if ( scaledHeight )
603 {
604 *scaledHeight = height;
605 }
606 height = context.renderContext().convertToPainterUnits( height, mSymbolHeightUnit, mSymbolHeightMapUnitScale );
607 return QSizeF( width, height );
608}
609
610void QgsEllipseSymbolLayer::preparePath( const QgsEllipseSymbolLayer::Shape &shape, QgsSymbolRenderContext &context, double *scaledWidth, double *scaledHeight, const QgsFeature * )
611{
612 mPainterPath = QPainterPath();
613
614 const QSizeF size = calculateSize( context, scaledWidth, scaledHeight );
615
616 switch ( shape )
617 {
618 case Circle:
619 mPainterPath.addEllipse( QRectF( -size.width() / 2.0, -size.height() / 2.0, size.width(), size.height() ) );
620 return;
621
622 case SemiCircle:
623 mPainterPath.arcTo( -size.width() / 2.0, -size.height() / 2.0, size.width(), size.height(), 0, 180 );
624 mPainterPath.lineTo( 0, 0 );
625 return;
626
627 case ThirdCircle:
628 mPainterPath.arcTo( -size.width() / 2.0, -size.height() / 2.0, size.width(), size.height(), 90, 120 );
629 mPainterPath.lineTo( 0, 0 );
630 return;
631
632 case QuarterCircle:
633 mPainterPath.arcTo( -size.width() / 2.0, -size.height() / 2.0, size.width(), size.height(), 90, 90 );
634 mPainterPath.lineTo( 0, 0 );
635 return;
636
637 case Rectangle:
638 mPainterPath.addRect( QRectF( -size.width() / 2.0, -size.height() / 2.0, size.width(), size.height() ) );
639 return;
640
641 case Diamond:
642 mPainterPath.moveTo( -size.width() / 2.0, 0 );
643 mPainterPath.lineTo( 0, size.height() / 2.0 );
644 mPainterPath.lineTo( size.width() / 2.0, 0 );
645 mPainterPath.lineTo( 0, -size.height() / 2.0 );
646 mPainterPath.lineTo( -size.width() / 2.0, 0 );
647 return;
648
649 case Cross:
650 mPainterPath.moveTo( 0, -size.height() / 2.0 );
651 mPainterPath.lineTo( 0, size.height() / 2.0 );
652 mPainterPath.moveTo( -size.width() / 2.0, 0 );
653 mPainterPath.lineTo( size.width() / 2.0, 0 );
654 return;
655
656 case Arrow:
657 mPainterPath.moveTo( -size.width() / 2.0, size.height() / 2.0 );
658 mPainterPath.lineTo( 0, -size.height() / 2.0 );
659 mPainterPath.lineTo( size.width() / 2.0, size.height() / 2.0 );
660 return;
661
662 case HalfArc:
663 mPainterPath.moveTo( size.width() / 2.0, 0 );
664 mPainterPath.arcTo( -size.width() / 2.0, -size.height() / 2.0, size.width(), size.height(), 0, 180 );
665 return;
666
667 case Triangle:
668 mPainterPath.moveTo( 0, -size.height() / 2.0 );
669 mPainterPath.lineTo( -size.width() / 2.0, size.height() / 2.0 );
670 mPainterPath.lineTo( size.width() / 2.0, size.height() / 2.0 );
671 mPainterPath.lineTo( 0, -size.height() / 2.0 );
672 return;
673
674 case LeftHalfTriangle:
675 mPainterPath.moveTo( 0, size.height() / 2.0 );
676 mPainterPath.lineTo( size.width() / 2.0, size.height() / 2.0 );
677 mPainterPath.lineTo( 0, -size.height() / 2.0 );
678 mPainterPath.lineTo( 0, size.height() / 2.0 );
679 return;
680
682 mPainterPath.moveTo( -size.width() / 2.0, size.height() / 2.0 );
683 mPainterPath.lineTo( 0, size.height() / 2.0 );
684 mPainterPath.lineTo( 0, -size.height() / 2.0 );
685 mPainterPath.lineTo( -size.width() / 2.0, size.height() / 2.0 );
686 return;
687
688 case Pentagon:
689 mPainterPath.moveTo( ( size.width() * -0.9511 ) / 2.0, size.height() / ( 2 / -0.309 ) );
690 mPainterPath.lineTo( ( size.width() * -0.5878 ) / 2.0, size.height() / ( 2 / 0.8090 ) );
691 mPainterPath.lineTo( ( size.width() * 0.5878 ) / 2.0, size.height() / ( 2 / 0.8090 ) );
692 mPainterPath.lineTo( ( size.width() * 0.9511 ) / 2.0, size.height() / ( 2 / -0.309 ) );
693 mPainterPath.lineTo( 0, size.height() / -2.0 );
694 mPainterPath.lineTo( ( size.width() * -0.9511 ) / 2.0, size.height() / ( 2 / -0.309 ) );
695 return;
696
697 case Hexagon:
698 mPainterPath.moveTo( ( size.width() * 0.8660 ) / 2.0, size.height() / 4.0 );
699 mPainterPath.lineTo( ( size.width() * 0.8660 ) / 2.0, size.height() / -4.0 );
700 mPainterPath.lineTo( 0, size.height() / -2.0 );
701 mPainterPath.lineTo( ( size.width() * 0.8660 ) / -2.0, size.height() / -4.0 );
702 mPainterPath.lineTo( ( size.width() * 0.8660 ) / -2.0, size.height() / 4.0 );
703 mPainterPath.lineTo( 0, size.height() / 2.0 );
704 mPainterPath.lineTo( ( size.width() * 0.8660 ) / 2.0, size.height() / 4.0 );
705 return;
706
707 case Octagon:
708 {
709 static constexpr double VERTEX_OFFSET_FROM_ORIGIN = 1.0 / ( 1 + M_SQRT2 );
710 mPainterPath.moveTo( ( size.width() * VERTEX_OFFSET_FROM_ORIGIN ) / -2.0, size.height() / 2.0 );
711 mPainterPath.lineTo( ( size.width() * VERTEX_OFFSET_FROM_ORIGIN ) / 2.0, size.height() / 2.0 );
712 mPainterPath.lineTo( size.width() / 2.0, ( size.height() * VERTEX_OFFSET_FROM_ORIGIN ) / 2.0 );
713 mPainterPath.lineTo( size.width() / 2.0, ( size.height() * VERTEX_OFFSET_FROM_ORIGIN ) / -2.0 );
714 mPainterPath.lineTo( ( size.width() * VERTEX_OFFSET_FROM_ORIGIN ) / 2.0, size.height() / -2.0 );
715 mPainterPath.lineTo( ( size.width() * VERTEX_OFFSET_FROM_ORIGIN ) / -2.0, size.height() / -2.0 );
716 mPainterPath.lineTo( size.width() / -2.0, ( size.height() * VERTEX_OFFSET_FROM_ORIGIN ) / -2.0 );
717 mPainterPath.lineTo( size.width() / -2.0, ( size.height() * VERTEX_OFFSET_FROM_ORIGIN ) / 2.0 );
718 mPainterPath.lineTo( ( size.width() * VERTEX_OFFSET_FROM_ORIGIN ) / -2.0, size.height() / 2.0 );
719 return;
720 }
721
722 case Star:
723 {
724 const double inner_r = std::cos( DEG2RAD( 72.0 ) ) / std::cos( DEG2RAD( 36.0 ) );
725 mPainterPath.moveTo( ( size.width() * inner_r * std::sin( DEG2RAD( 324.0 ) ) ) / 2.0, ( size.height() * inner_r * std::cos( DEG2RAD( 324.0 ) ) ) / -2.0 );
726 mPainterPath.lineTo( ( size.width() * std::sin( DEG2RAD( 288.0 ) ) ) / 2.0, ( size.height() * std::cos( DEG2RAD( 288.0 ) ) ) / -2.0 );
727 mPainterPath.lineTo( ( size.width() * inner_r * std::sin( DEG2RAD( 252.0 ) ) ) / 2.0, ( size.height() * inner_r * std::cos( DEG2RAD( 252.0 ) ) ) / -2.0 );
728 mPainterPath.lineTo( ( size.width() * std::sin( DEG2RAD( 216.0 ) ) ) / 2.0, ( size.height() * std::cos( DEG2RAD( 216.0 ) ) ) / -2.0 );
729 mPainterPath.lineTo( 0, ( size.height() * inner_r ) / 2.0 );
730 mPainterPath.lineTo( ( size.width() * std::sin( DEG2RAD( 144.0 ) ) ) / 2.0, ( size.height() * std::cos( DEG2RAD( 144.0 ) ) ) / -2.0 );
731 mPainterPath.lineTo( ( size.width() * inner_r * std::sin( DEG2RAD( 108.0 ) ) ) / 2.0, ( size.height() * inner_r * std::cos( DEG2RAD( 108.0 ) ) ) / -2.0 );
732 mPainterPath.lineTo( ( size.width() * std::sin( DEG2RAD( 72.0 ) ) ) / 2.0, ( size.height() * std::cos( DEG2RAD( 72.0 ) ) ) / -2.0 );
733 mPainterPath.lineTo( ( size.width() * inner_r * std::sin( DEG2RAD( 36.0 ) ) ) / 2.0, ( size.height() * inner_r * std::cos( DEG2RAD( 36.0 ) ) ) / -2.0 );
734 mPainterPath.lineTo( 0, size.height() / -2.0 );
735 mPainterPath.lineTo( ( size.width() * inner_r * std::sin( DEG2RAD( 324.0 ) ) ) / 2.0, ( size.height() * inner_r * std::cos( DEG2RAD( 324.0 ) ) ) / -2.0 );
736 return;
737 }
738 }
739}
740
742{
743 switch ( shape )
744 {
745 case Circle:
746 case Rectangle:
747 case Diamond:
748 case Triangle:
750 case LeftHalfTriangle:
751 case SemiCircle:
752 case ThirdCircle:
753 case QuarterCircle:
754 case Pentagon:
755 case Hexagon:
756 case Octagon:
757 case Star:
758 return true;
759
760 case Cross:
761 case Arrow:
762 case HalfArc:
763 return false;
764 }
765
766 return true;
767}
768
770{
771 if ( mSymbolWidth >= mSymbolHeight )
772 {
773 mSymbolHeight = mSymbolHeight * size / mSymbolWidth;
774 mSymbolWidth = size;
775 }
776 else
777 {
778 mSymbolWidth = mSymbolWidth * size / mSymbolHeight;
779 mSymbolHeight = size;
780 }
782}
783
785{
786 mSymbolWidth = w;
787 QgsMarkerSymbolLayer::setSize( mSymbolWidth >= mSymbolHeight ? mSymbolWidth : mSymbolHeight );
788}
789
791{
792 mSymbolHeight = h;
793 QgsMarkerSymbolLayer::setSize( mSymbolWidth >= mSymbolHeight ? mSymbolWidth : mSymbolHeight );
794}
795
797{
799 mSymbolWidthUnit = unit;
800 mSymbolHeightUnit = unit;
801 mStrokeWidthUnit = unit;
802}
803
805{
807 if ( mSymbolWidthUnit != unit || mSymbolHeightUnit != unit || mStrokeWidthUnit != unit )
808 {
810 }
811 return unit;
812}
813
815{
816 return mSymbolWidthUnit == Qgis::RenderUnit::MapUnits || mSymbolWidthUnit == Qgis::RenderUnit::MetersInMapUnits
817 || mSymbolHeightUnit == Qgis::RenderUnit::MapUnits || mSymbolHeightUnit == Qgis::RenderUnit::MetersInMapUnits
818 || mStrokeWidthUnit == Qgis::RenderUnit::MapUnits || mStrokeWidthUnit == Qgis::RenderUnit::MetersInMapUnits
820}
821
823{
825 mSymbolWidthMapUnitScale = scale;
826 mSymbolHeightMapUnitScale = scale;
827 mStrokeWidthMapUnitScale = scale;
828}
829
831{
832 if ( QgsMarkerSymbolLayer::mapUnitScale() == mSymbolWidthMapUnitScale &&
833 mSymbolWidthMapUnitScale == mSymbolHeightMapUnitScale &&
834 mSymbolHeightMapUnitScale == mStrokeWidthMapUnitScale )
835 {
836 return mSymbolWidthMapUnitScale;
837 }
838 return QgsMapUnitScale();
839}
840
842{
843 const QSizeF size = calculateSize( context );
844
845 bool hasDataDefinedRotation = false;
846 QPointF offset;
847 double angle = 0;
848 calculateOffsetAndRotation( context, size.width(), size.height(), hasDataDefinedRotation, offset, angle );
849
850 QTransform transform;
851
852 // move to the desired position
853 transform.translate( point.x() + offset.x(), point.y() + offset.y() );
854
855 if ( !qgsDoubleNear( angle, 0.0 ) )
856 transform.rotate( angle );
857
858 double penWidth = mStrokeWidth;
860 {
861 context.setOriginalValueVariable( mStrokeWidth );
863
864 if ( !QgsVariantUtils::isNull( exprVal ) )
865 {
866 bool ok;
867 const double strokeWidth = exprVal.toDouble( &ok );
868 if ( ok )
869 {
870 penWidth = strokeWidth;
871 }
872 }
873 }
874 penWidth = context.renderContext().convertToPainterUnits( penWidth, mStrokeWidthUnit, mStrokeWidthMapUnitScale );
875
877 {
880 if ( !QgsVariantUtils::isNull( exprVal ) && exprVal.toString() == QLatin1String( "no" ) )
881 {
882 penWidth = 0.0;
883 }
884 }
885 else if ( mStrokeStyle == Qt::NoPen )
886 penWidth = 0;
887
888 //antialiasing, add 1 pixel
889 penWidth += 1;
890
891 QRectF symbolBounds = transform.mapRect( QRectF( -size.width() / 2.0,
892 -size.height() / 2.0,
893 size.width(),
894 size.height() ) );
895
896 //extend bounds by pen width / 2.0
897 symbolBounds.adjust( -penWidth / 2.0, -penWidth / 2.0,
898 penWidth / 2.0, penWidth / 2.0 );
899
900 return symbolBounds;
901}
902
903bool QgsEllipseSymbolLayer::writeDxf( QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, QgsSymbolRenderContext &context, QPointF shift ) const
904{
905 //width
906 double symbolWidth = mSymbolWidth;
907
908 if ( mDataDefinedProperties.isActive( QgsSymbolLayer::Property::Width ) ) //1. priority: data defined setting on symbol layer le
909 {
910 context.setOriginalValueVariable( mSymbolWidth );
912 }
913 if ( mSymbolWidthUnit == Qgis::RenderUnit::Millimeters )
914 {
915 symbolWidth *= mmMapUnitScaleFactor;
916 }
917
918 //height
919 double symbolHeight = mSymbolHeight;
920 if ( mDataDefinedProperties.isActive( QgsSymbolLayer::Property::Height ) ) //1. priority: data defined setting on symbol layer level
921 {
922 context.setOriginalValueVariable( mSymbolHeight );
924 }
925 if ( mSymbolHeightUnit == Qgis::RenderUnit::Millimeters )
926 {
927 symbolHeight *= mmMapUnitScaleFactor;
928 }
929
930 //stroke width
931 double strokeWidth = mStrokeWidth;
932
934 {
935 context.setOriginalValueVariable( mStrokeWidth );
937 }
938 if ( mStrokeWidthUnit == Qgis::RenderUnit::Millimeters )
939 {
941 }
942
943 //fill color
944 QColor fc = mColor;
946 {
949 }
950
951 //stroke color
952 QColor oc = mStrokeColor;
954 {
957 }
958
959 //symbol name
962 {
965 }
966
967 //offset
968 double offsetX = 0;
969 double offsetY = 0;
970 markerOffset( context, offsetX, offsetY );
971 QPointF off( offsetX, offsetY );
972
973 //priority for rotation: 1. data defined symbol level, 2. symbol layer rotation (mAngle)
974 double rotation = 0.0;
976 {
979 }
980 else if ( !qgsDoubleNear( mAngle + mLineAngle, 0.0 ) )
981 {
982 rotation = mAngle + mLineAngle;
983 }
984 rotation = -rotation; //rotation in Qt is counterclockwise
985 if ( rotation )
986 off = _rotatedOffset( off, rotation );
987
988 QTransform t;
989 t.translate( shift.x() + offsetX, shift.y() + offsetY );
990
991 if ( !qgsDoubleNear( rotation, 0.0 ) )
992 t.rotate( rotation );
993
994 const double halfWidth = symbolWidth / 2.0;
995 const double halfHeight = symbolHeight / 2.0;
996
997 switch ( shape )
998 {
999 case Circle:
1000 {
1001 if ( qgsDoubleNear( halfWidth, halfHeight ) )
1002 {
1003 const QgsPoint pt( t.map( QPointF( 0, 0 ) ) );
1004 e.writeFilledCircle( layerName, oc, pt, halfWidth );
1005 }
1006 else
1007 {
1008 QgsPointSequence line;
1009
1010 const double stepsize = 2 * M_PI / 40;
1011 for ( int i = 0; i < 39; ++i )
1012 {
1013 const double angle = stepsize * i;
1014 const double x = halfWidth * std::cos( angle );
1015 const double y = halfHeight * std::sin( angle );
1016 line << QgsPoint( t.map( QPointF( x, y ) ) );
1017 }
1018 //close ellipse with first point
1019 line << line.at( 0 );
1020
1021 if ( mBrush.style() != Qt::NoBrush )
1022 e.writePolygon( QgsRingSequence() << line, layerName, QStringLiteral( "SOLID" ), fc );
1023 if ( mPen.style() != Qt::NoPen )
1024 e.writePolyline( line, layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth );
1025 }
1026 return true;
1027 }
1028
1029 case Rectangle:
1030 {
1032 p << QgsPoint( t.map( QPointF( -halfWidth, -halfHeight ) ) )
1033 << QgsPoint( t.map( QPointF( halfWidth, -halfHeight ) ) )
1034 << QgsPoint( t.map( QPointF( halfWidth, halfHeight ) ) )
1035 << QgsPoint( t.map( QPointF( -halfWidth, halfHeight ) ) );
1036 p << p[0];
1037
1038 if ( mBrush.style() != Qt::NoBrush )
1039 e.writePolygon( QgsRingSequence() << p, layerName, QStringLiteral( "SOLID" ), fc );
1040 if ( mPen.style() != Qt::NoPen )
1041 e.writePolyline( p, layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth );
1042 return true;
1043 }
1044 case Cross:
1045 {
1046 if ( mPen.style() != Qt::NoPen )
1047 {
1049 << QgsPoint( t.map( QPointF( -halfWidth, 0 ) ) )
1050 << QgsPoint( t.map( QPointF( halfWidth, 0 ) ) ),
1051 layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth );
1053 << QgsPoint( t.map( QPointF( 0, halfHeight ) ) )
1054 << QgsPoint( t.map( QPointF( 0, -halfHeight ) ) ),
1055 layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth );
1056 return true;
1057 }
1058 break;
1059 }
1060
1061 case Triangle:
1062 {
1064 p << QgsPoint( t.map( QPointF( -halfWidth, -halfHeight ) ) )
1065 << QgsPoint( t.map( QPointF( halfWidth, -halfHeight ) ) )
1066 << QgsPoint( t.map( QPointF( 0, halfHeight ) ) );
1067 p << p[0];
1068 if ( mBrush.style() != Qt::NoBrush )
1069 e.writePolygon( QgsRingSequence() << p, layerName, QStringLiteral( "SOLID" ), fc );
1070 if ( mPen.style() != Qt::NoPen )
1071 e.writePolyline( p, layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth );
1072 return true;
1073 }
1074
1075 case Diamond:
1076 case Arrow:
1077 case HalfArc:
1078 case RightHalfTriangle:
1079 case LeftHalfTriangle:
1080 case SemiCircle:
1081 case ThirdCircle:
1082 case QuarterCircle:
1083 case Pentagon:
1084 case Hexagon:
1085 case Octagon:
1086 case Star:
1087 return false;
1088 }
1089
1090 return false;
1091}
1092
1094{
1095 if ( ok )
1096 *ok = true;
1097 const QString cleaned = name.toLower().trimmed();
1098
1099 if ( cleaned == QLatin1String( "circle" ) )
1100 return Circle;
1101 else if ( cleaned == QLatin1String( "square" ) || cleaned == QLatin1String( "rectangle" ) )
1102 return Rectangle;
1103 else if ( cleaned == QLatin1String( "diamond" ) )
1104 return Diamond;
1105 else if ( cleaned == QLatin1String( "cross" ) )
1106 return Cross;
1107 else if ( cleaned == QLatin1String( "arrow" ) )
1108 return Arrow;
1109 else if ( cleaned == QLatin1String( "half_arc" ) )
1110 return HalfArc;
1111 else if ( cleaned == QLatin1String( "triangle" ) )
1112 return Triangle;
1113 else if ( cleaned == QLatin1String( "right_half_triangle" ) )
1114 return RightHalfTriangle;
1115 else if ( cleaned == QLatin1String( "left_half_triangle" ) )
1116 return LeftHalfTriangle;
1117 else if ( cleaned == QLatin1String( "semi_circle" ) )
1118 return SemiCircle;
1119 else if ( cleaned == QLatin1String( "third_circle" ) )
1120 return ThirdCircle;
1121 else if ( cleaned == QLatin1String( "quarter_circle" ) )
1122 return QuarterCircle;
1123 else if ( cleaned == QLatin1String( "pentagon" ) )
1124 return Pentagon;
1125 else if ( cleaned == QLatin1String( "hexagon" ) )
1126 return Hexagon;
1127 else if ( cleaned == QLatin1String( "octagon" ) )
1128 return Octagon;
1129 else if ( cleaned == QLatin1String( "star" ) )
1130 return Star; if ( ok )
1131 *ok = false;
1132 return Circle;
1133}
1134
1136{
1137 switch ( shape )
1138 {
1139 case Circle:
1140 return QStringLiteral( "circle" );
1141 case Rectangle:
1142 return QStringLiteral( "rectangle" );
1143 case Diamond:
1144 return QStringLiteral( "diamond" );
1145 case Cross:
1146 return QStringLiteral( "cross" );
1147 case Arrow:
1148 return QStringLiteral( "arrow" );
1149 case HalfArc:
1150 return QStringLiteral( "half_arc" );
1151 case Triangle:
1152 return QStringLiteral( "triangle" );
1153 case RightHalfTriangle:
1154 return QStringLiteral( "right_half_triangle" );
1155 case LeftHalfTriangle:
1156 return QStringLiteral( "left_half_triangle" );
1157 case SemiCircle:
1158 return QStringLiteral( "semi_circle" );
1159 case ThirdCircle:
1160 return QStringLiteral( "third_circle" );
1161 case QuarterCircle:
1162 return QStringLiteral( "quarter_circle" );
1163 case Pentagon:
1164 return QStringLiteral( "pentagon" );
1165 case Hexagon:
1166 return QStringLiteral( "hexagon" );
1167 case Octagon:
1168 return QStringLiteral( "octagon" );
1169 case Star:
1170 return QStringLiteral( "star" );
1171 }
1172 return QString();
1173}
1174
1175QList<QgsEllipseSymbolLayer::Shape> QgsEllipseSymbolLayer::availableShapes()
1176{
1177 QList< Shape > shapes;
1178 shapes << Circle
1179 << Rectangle
1180 << Diamond
1181 << Cross
1182 << Arrow
1183 << HalfArc
1184 << Triangle
1187 << SemiCircle
1188 << ThirdCircle
1189 << QuarterCircle
1190 << Pentagon
1191 << Hexagon
1192 << Octagon
1193 << Star;
1194 return shapes;
1195}
@ DynamicRotation
Rotation of symbol may be changed during rendering and symbol should not be cached.
RenderUnit
Rendering size units.
Definition: qgis.h:4255
@ 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.
Definition: qgsdxfexport.h:66
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)
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:56
QgsGeometry geometry
Definition: qgsfeature.h:67
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:162
Q_GADGET bool isNull
Definition: qgsgeometry.h:164
Qgis::GeometryType type
Definition: qgsgeometry.h:165
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:39
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.
Definition: qgsproperty.h:228
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.
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.
double ANALYSIS_EXPORT angle(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
Definition: MathUtils.cpp:716
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:5207
QMap< QString, QString > QgsStringMap
Definition: qgis.h:5737
QVector< QgsPointSequence > QgsRingSequence
QVector< QgsPoint > QgsPointSequence
#define DEG2RAD(x)
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39