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