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