QGIS API Documentation 3.34.0-Prizren (ffbdd678812)
Loading...
Searching...
No Matches
qgsellipsesymbollayer.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsellipsesymbollayer.cpp
3 ---------------------
4 begin : June 2011
5 copyright : (C) 2011 by Marco Hugentobler
6 email : marco dot hugentobler at sourcepole dot ch
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
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 const bool useSelectedColor = shouldRenderUsingSelectionColor( context );
283 if ( shapeIsFilled( shape ) )
284 {
285 p->setPen( useSelectedColor ? mSelPen : mPen );
286 p->setBrush( useSelectedColor ? mSelBrush : mBrush );
287 }
288 else
289 {
290 p->setPen( useSelectedColor ? mSelPen : mPen );
291 p->setBrush( QBrush() );
292 }
293 p->drawPath( transform.map( mPainterPath ) );
294}
295
296
297void QgsEllipseSymbolLayer::calculateOffsetAndRotation( QgsSymbolRenderContext &context,
298 double scaledWidth,
299 double scaledHeight,
300 bool &hasDataDefinedRotation,
301 QPointF &offset,
302 double &angle ) const
303{
304 double offsetX = 0;
305 double offsetY = 0;
306 markerOffset( context, scaledWidth, scaledHeight, mSymbolWidthUnit, mSymbolHeightUnit, offsetX, offsetY, mSymbolWidthMapUnitScale, mSymbolHeightMapUnitScale );
307 offset = QPointF( offsetX, offsetY );
308
309//priority for rotation: 1. data defined symbol level, 2. symbol layer rotation (mAngle)
310 const bool ok = true;
312 bool usingDataDefinedRotation = false;
314 {
317 usingDataDefinedRotation = ok;
318 }
319
320 hasDataDefinedRotation = context.renderHints() & Qgis::SymbolRenderHint::DynamicRotation || usingDataDefinedRotation;
321 if ( hasDataDefinedRotation )
322 {
323 // For non-point markers, "dataDefinedRotation" means following the
324 // shape (shape-data defined). For them, "field-data defined" does
325 // not work at all. TODO: if "field-data defined" ever gets implemented
326 // we'll need a way to distinguish here between the two, possibly
327 // using another flag in renderHints()
328 const QgsFeature *f = context.feature();
329 if ( f )
330 {
331 const QgsGeometry g = f->geometry();
332 if ( !g.isNull() && g.type() == Qgis::GeometryType::Point )
333 {
334 const QgsMapToPixel &m2p = context.renderContext().mapToPixel();
335 angle += m2p.mapRotation();
336 }
337 }
338 }
339
340 if ( angle )
342}
343
345{
346 return QStringLiteral( "EllipseMarker" );
347}
348
350{
351 QgsMarkerSymbolLayer::startRender( context ); // get anchor point expressions
352 if ( !context.feature() || !dataDefinedProperties().hasActiveProperties() )
353 {
354 preparePath( mShape, context );
355 }
356 mPen.setColor( mStrokeColor );
357 mPen.setStyle( mStrokeStyle );
358 mPen.setJoinStyle( mPenJoinStyle );
359 mPen.setCapStyle( mPenCapStyle );
360 mPen.setWidthF( context.renderContext().convertToPainterUnits( mStrokeWidth, mStrokeWidthUnit, mStrokeWidthMapUnitScale ) );
361 mBrush.setColor( mColor );
362
363 QColor selBrushColor = context.renderContext().selectionColor();
364 QColor selPenColor = selBrushColor == mColor ? selBrushColor : mStrokeColor;
365 if ( context.opacity() < 1 && !SELECTION_IS_OPAQUE )
366 {
367 selBrushColor.setAlphaF( context.opacity() );
368 selPenColor.setAlphaF( context.opacity() );
369 }
370 mSelBrush = QBrush( selBrushColor );
371 mSelPen = QPen( !shapeIsFilled( mShape ) ? selBrushColor : selPenColor );
372 mSelPen.setStyle( mStrokeStyle );
373 mSelPen.setWidthF( context.renderContext().convertToPainterUnits( mStrokeWidth, mStrokeWidthUnit, mStrokeWidthMapUnitScale ) );
374}
375
379
381{
383 m->setShape( mShape );
384 m->setSymbolWidth( mSymbolWidth );
385 m->setSymbolHeight( mSymbolHeight );
386 m->setStrokeStyle( mStrokeStyle );
387 m->setOffset( mOffset );
390 m->setStrokeStyle( mStrokeStyle );
391 m->setPenJoinStyle( mPenJoinStyle );
392 m->setPenCapStyle( mPenCapStyle );
393 m->setStrokeWidth( mStrokeWidth );
394 m->setColor( color() );
395 m->setStrokeColor( mStrokeColor );
396 m->setSymbolWidthUnit( mSymbolWidthUnit );
397 m->setSymbolWidthMapUnitScale( mSymbolWidthMapUnitScale );
398 m->setSymbolHeightUnit( mSymbolHeightUnit );
399 m->setSymbolHeightMapUnitScale( mSymbolHeightMapUnitScale );
400 m->setStrokeWidthUnit( mStrokeWidthUnit );
401 m->setStrokeWidthMapUnitScale( mStrokeWidthMapUnitScale );
402 m->setAngle( mAngle );
405
407 copyPaintEffect( m );
408 return m;
409}
410
411void QgsEllipseSymbolLayer::toSld( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const
412{
413 QDomElement symbolizerElem = doc.createElement( QStringLiteral( "se:PointSymbolizer" ) );
414 if ( !props.value( QStringLiteral( "uom" ), QString() ).toString().isEmpty() )
415 symbolizerElem.setAttribute( QStringLiteral( "uom" ), props.value( QStringLiteral( "uom" ), QString() ).toString() );
416 element.appendChild( symbolizerElem );
417
418 // <Geometry>
419 QgsSymbolLayerUtils::createGeometryElement( doc, symbolizerElem, props.value( QStringLiteral( "geom" ), QString() ).toString() );
420
421 writeSldMarker( doc, symbolizerElem, props );
422}
423
424void QgsEllipseSymbolLayer::writeSldMarker( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const
425{
426 // <Graphic>
427 QDomElement graphicElem = doc.createElement( QStringLiteral( "se:Graphic" ) );
428 element.appendChild( graphicElem );
429
430 const double strokeWidth = QgsSymbolLayerUtils::rescaleUom( mStrokeWidth, mStrokeWidthUnit, props );
431 const double symbolWidth = QgsSymbolLayerUtils::rescaleUom( mSymbolWidth, mSymbolWidthUnit, props );
432 QgsSymbolLayerUtils::wellKnownMarkerToSld( doc, graphicElem, encodeShape( mShape ), mColor, mStrokeColor, mStrokeStyle, strokeWidth, symbolWidth );
433
434 // <Rotation>
436
437 QString angleFunc = props.value( QStringLiteral( "angle" ), QString() ).toString();
438 if ( angleFunc.isEmpty() ) // symbol has no angle set
439 {
440 if ( ddRotation && ddRotation.isActive() )
441 {
442 angleFunc = ddRotation.asExpression();
443 }
444 else if ( !qgsDoubleNear( mAngle, 0.0 ) )
445 angleFunc = QString::number( mAngle );
446 }
447 else if ( ddRotation && ddRotation.isActive() )
448 {
449 // the symbol has an angle and the symbol layer have a rotation
450 // property set
451 angleFunc = QStringLiteral( "%1 + %2" ).arg( angleFunc, ddRotation.asExpression() );
452 }
453 else if ( !qgsDoubleNear( mAngle, 0.0 ) )
454 {
455 // both the symbol and the symbol layer have angle value set
456 bool ok;
457 const double angle = angleFunc.toDouble( &ok );
458 if ( !ok )
459 {
460 // its a string (probably a property name or a function)
461 angleFunc = QStringLiteral( "%1 + %2" ).arg( angleFunc ).arg( mAngle );
462 }
463 else if ( !qgsDoubleNear( angle + mAngle, 0.0 ) )
464 {
465 // it's a double value
466 angleFunc = QString::number( angle + mAngle );
467 }
468 }
469 QgsSymbolLayerUtils::createRotationElement( doc, graphicElem, angleFunc );
470
471 // <Displacement>
474
475 // store w/h factor in a <VendorOption>
476 const double widthHeightFactor = mSymbolWidth / mSymbolHeight;
477 const QDomElement factorElem = QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "widthHeightFactor" ), QString::number( widthHeightFactor ) );
478 graphicElem.appendChild( factorElem );
479}
480
482{
483 QgsDebugMsgLevel( QStringLiteral( "Entered." ), 4 );
484
485 QDomElement graphicElem = element.firstChildElement( QStringLiteral( "Graphic" ) );
486 if ( graphicElem.isNull() )
487 return nullptr;
488
489 QString name = QStringLiteral( "circle" );
490 QColor fillColor, strokeColor;
491 double strokeWidth, size;
492 double widthHeightFactor = 1.0;
493 Qt::PenStyle strokeStyle;
494
495 QgsStringMap vendorOptions = QgsSymbolLayerUtils::getVendorOptionList( graphicElem );
496 for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
497 {
498 if ( it.key() == QLatin1String( "widthHeightFactor" ) )
499 {
500 bool ok;
501 const double v = it.value().toDouble( &ok );
502 if ( ok && !qgsDoubleNear( v, 0.0 ) && v > 0 )
503 widthHeightFactor = v;
504 }
505 }
506
508 return nullptr;
509
510 double scaleFactor = 1.0;
511 const QString uom = element.attribute( QStringLiteral( "uom" ) );
512 Qgis::RenderUnit sldUnitSize = QgsSymbolLayerUtils::decodeSldUom( uom, &scaleFactor );
513 size = size * scaleFactor;
514 strokeWidth = strokeWidth * scaleFactor;
515
516 double angle = 0.0;
517 QString angleFunc;
518 if ( QgsSymbolLayerUtils::rotationFromSldElement( graphicElem, angleFunc ) )
519 {
520 bool ok;
521 const double d = angleFunc.toDouble( &ok );
522 if ( ok )
523 angle = d;
524 }
525
527 m->setOutputUnit( sldUnitSize );
528 m->setShape( decodeShape( name ) );
533 m->setSymbolWidth( size );
534 m->setSymbolHeight( size / widthHeightFactor );
535 m->setAngle( angle );
536 return m;
537}
538
540{
541 QVariantMap map;
542 map[QStringLiteral( "symbol_name" )] = encodeShape( mShape );
543 map[QStringLiteral( "symbol_width" )] = QString::number( mSymbolWidth );
544 map[QStringLiteral( "symbol_width_unit" )] = QgsUnitTypes::encodeUnit( mSymbolWidthUnit );
545 map[QStringLiteral( "symbol_width_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mSymbolWidthMapUnitScale );
546 map[QStringLiteral( "symbol_height" )] = QString::number( mSymbolHeight );
547 map[QStringLiteral( "symbol_height_unit" )] = QgsUnitTypes::encodeUnit( mSymbolHeightUnit );
548 map[QStringLiteral( "symbol_height_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mSymbolHeightMapUnitScale );
549 map[QStringLiteral( "angle" )] = QString::number( mAngle );
550 map[QStringLiteral( "outline_style" )] = QgsSymbolLayerUtils::encodePenStyle( mStrokeStyle );
551 map[QStringLiteral( "outline_width" )] = QString::number( mStrokeWidth );
552 map[QStringLiteral( "outline_width_unit" )] = QgsUnitTypes::encodeUnit( mStrokeWidthUnit );
553 map[QStringLiteral( "outline_width_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mStrokeWidthMapUnitScale );
554 map[QStringLiteral( "joinstyle" )] = QgsSymbolLayerUtils::encodePenJoinStyle( mPenJoinStyle );
555 map[QStringLiteral( "cap_style" )] = QgsSymbolLayerUtils::encodePenCapStyle( mPenCapStyle );
556 map[QStringLiteral( "color" )] = QgsSymbolLayerUtils::encodeColor( mColor );
557 map[QStringLiteral( "outline_color" )] = QgsSymbolLayerUtils::encodeColor( mStrokeColor );
558 map[QStringLiteral( "offset" )] = QgsSymbolLayerUtils::encodePoint( mOffset );
559 map[QStringLiteral( "offset_unit" )] = QgsUnitTypes::encodeUnit( mOffsetUnit );
560 map[QStringLiteral( "offset_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mOffsetMapUnitScale );
561 map[QStringLiteral( "size" )] = QString::number( mSize );
562 map[QStringLiteral( "size_unit" )] = QgsUnitTypes::encodeUnit( mSizeUnit );
563 map[QStringLiteral( "size_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mSizeMapUnitScale );
564 map[QStringLiteral( "horizontal_anchor_point" )] = QString::number( mHorizontalAnchorPoint );
565 map[QStringLiteral( "vertical_anchor_point" )] = QString::number( mVerticalAnchorPoint );
566 return map;
567}
568
569QSizeF QgsEllipseSymbolLayer::calculateSize( QgsSymbolRenderContext &context, double *scaledWidth, double *scaledHeight )
570{
571 double width = 0;
572
573 if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyWidth ) ) //1. priority: data defined setting on symbol layer le
574 {
575 context.setOriginalValueVariable( mSymbolWidth );
577 }
578 else //2. priority: global width setting
579 {
580 width = mSymbolWidth;
581 }
582 if ( scaledWidth )
583 {
584 *scaledWidth = width;
585 }
586 width = context.renderContext().convertToPainterUnits( width, mSymbolWidthUnit, mSymbolHeightMapUnitScale );
587
588 double height = 0;
589 if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyHeight ) ) //1. priority: data defined setting on symbol layer level
590 {
591 context.setOriginalValueVariable( mSymbolHeight );
593 }
594 else //2. priority: global height setting
595 {
596 height = mSymbolHeight;
597 }
598 if ( scaledHeight )
599 {
600 *scaledHeight = height;
601 }
602 height = context.renderContext().convertToPainterUnits( height, mSymbolHeightUnit, mSymbolHeightMapUnitScale );
603 return QSizeF( width, height );
604}
605
606void QgsEllipseSymbolLayer::preparePath( const QgsEllipseSymbolLayer::Shape &shape, QgsSymbolRenderContext &context, double *scaledWidth, double *scaledHeight, const QgsFeature * )
607{
608 mPainterPath = QPainterPath();
609
610 const QSizeF size = calculateSize( context, scaledWidth, scaledHeight );
611
612 switch ( shape )
613 {
614 case Circle:
615 mPainterPath.addEllipse( QRectF( -size.width() / 2.0, -size.height() / 2.0, size.width(), size.height() ) );
616 return;
617
618 case SemiCircle:
619 mPainterPath.arcTo( -size.width() / 2.0, -size.height() / 2.0, size.width(), size.height(), 0, 180 );
620 mPainterPath.lineTo( 0, 0 );
621 return;
622
623 case ThirdCircle:
624 mPainterPath.arcTo( -size.width() / 2.0, -size.height() / 2.0, size.width(), size.height(), 90, 120 );
625 mPainterPath.lineTo( 0, 0 );
626 return;
627
628 case QuarterCircle:
629 mPainterPath.arcTo( -size.width() / 2.0, -size.height() / 2.0, size.width(), size.height(), 90, 90 );
630 mPainterPath.lineTo( 0, 0 );
631 return;
632
633 case Rectangle:
634 mPainterPath.addRect( QRectF( -size.width() / 2.0, -size.height() / 2.0, size.width(), size.height() ) );
635 return;
636
637 case Diamond:
638 mPainterPath.moveTo( -size.width() / 2.0, 0 );
639 mPainterPath.lineTo( 0, size.height() / 2.0 );
640 mPainterPath.lineTo( size.width() / 2.0, 0 );
641 mPainterPath.lineTo( 0, -size.height() / 2.0 );
642 mPainterPath.lineTo( -size.width() / 2.0, 0 );
643 return;
644
645 case Cross:
646 mPainterPath.moveTo( 0, -size.height() / 2.0 );
647 mPainterPath.lineTo( 0, size.height() / 2.0 );
648 mPainterPath.moveTo( -size.width() / 2.0, 0 );
649 mPainterPath.lineTo( size.width() / 2.0, 0 );
650 return;
651
652 case Arrow:
653 mPainterPath.moveTo( -size.width() / 2.0, size.height() / 2.0 );
654 mPainterPath.lineTo( 0, -size.height() / 2.0 );
655 mPainterPath.lineTo( size.width() / 2.0, size.height() / 2.0 );
656 return;
657
658 case HalfArc:
659 mPainterPath.moveTo( size.width() / 2.0, 0 );
660 mPainterPath.arcTo( -size.width() / 2.0, -size.height() / 2.0, size.width(), size.height(), 0, 180 );
661 return;
662
663 case Triangle:
664 mPainterPath.moveTo( 0, -size.height() / 2.0 );
665 mPainterPath.lineTo( -size.width() / 2.0, size.height() / 2.0 );
666 mPainterPath.lineTo( size.width() / 2.0, size.height() / 2.0 );
667 mPainterPath.lineTo( 0, -size.height() / 2.0 );
668 return;
669
670 case LeftHalfTriangle:
671 mPainterPath.moveTo( 0, size.height() / 2.0 );
672 mPainterPath.lineTo( size.width() / 2.0, size.height() / 2.0 );
673 mPainterPath.lineTo( 0, -size.height() / 2.0 );
674 mPainterPath.lineTo( 0, size.height() / 2.0 );
675 return;
676
678 mPainterPath.moveTo( -size.width() / 2.0, size.height() / 2.0 );
679 mPainterPath.lineTo( 0, size.height() / 2.0 );
680 mPainterPath.lineTo( 0, -size.height() / 2.0 );
681 mPainterPath.lineTo( -size.width() / 2.0, size.height() / 2.0 );
682 return;
683
684 case Pentagon:
685 mPainterPath.moveTo( ( size.width() * -0.9511 ) / 2.0, size.height() / ( 2 / -0.309 ) );
686 mPainterPath.lineTo( ( size.width() * -0.5878 ) / 2.0, size.height() / ( 2 / 0.8090 ) );
687 mPainterPath.lineTo( ( size.width() * 0.5878 ) / 2.0, size.height() / ( 2 / 0.8090 ) );
688 mPainterPath.lineTo( ( size.width() * 0.9511 ) / 2.0, size.height() / ( 2 / -0.309 ) );
689 mPainterPath.lineTo( 0, size.height() / -2.0 );
690 mPainterPath.lineTo( ( size.width() * -0.9511 ) / 2.0, size.height() / ( 2 / -0.309 ) );
691 return;
692
693 case Hexagon:
694 mPainterPath.moveTo( ( size.width() * 0.8660 ) / 2.0, size.height() / 4.0 );
695 mPainterPath.lineTo( ( size.width() * 0.8660 ) / 2.0, size.height() / -4.0 );
696 mPainterPath.lineTo( 0, size.height() / -2.0 );
697 mPainterPath.lineTo( ( size.width() * 0.8660 ) / -2.0, size.height() / -4.0 );
698 mPainterPath.lineTo( ( size.width() * 0.8660 ) / -2.0, size.height() / 4.0 );
699 mPainterPath.lineTo( 0, size.height() / 2.0 );
700 mPainterPath.lineTo( ( size.width() * 0.8660 ) / 2.0, size.height() / 4.0 );
701 return;
702
703 case Octagon:
704 {
705 static constexpr double VERTEX_OFFSET_FROM_ORIGIN = 1.0 / ( 1 + M_SQRT2 );
706 mPainterPath.moveTo( ( size.width() * VERTEX_OFFSET_FROM_ORIGIN ) / -2.0, size.height() / 2.0 );
707 mPainterPath.lineTo( ( size.width() * VERTEX_OFFSET_FROM_ORIGIN ) / 2.0, size.height() / 2.0 );
708 mPainterPath.lineTo( size.width() / 2.0, ( size.height() * VERTEX_OFFSET_FROM_ORIGIN ) / 2.0 );
709 mPainterPath.lineTo( size.width() / 2.0, ( size.height() * VERTEX_OFFSET_FROM_ORIGIN ) / -2.0 );
710 mPainterPath.lineTo( ( size.width() * VERTEX_OFFSET_FROM_ORIGIN ) / 2.0, size.height() / -2.0 );
711 mPainterPath.lineTo( ( size.width() * VERTEX_OFFSET_FROM_ORIGIN ) / -2.0, size.height() / -2.0 );
712 mPainterPath.lineTo( size.width() / -2.0, ( size.height() * VERTEX_OFFSET_FROM_ORIGIN ) / -2.0 );
713 mPainterPath.lineTo( size.width() / -2.0, ( size.height() * VERTEX_OFFSET_FROM_ORIGIN ) / 2.0 );
714 mPainterPath.lineTo( ( size.width() * VERTEX_OFFSET_FROM_ORIGIN ) / -2.0, size.height() / 2.0 );
715 return;
716 }
717
718 case Star:
719 {
720 const double inner_r = std::cos( DEG2RAD( 72.0 ) ) / std::cos( DEG2RAD( 36.0 ) );
721 mPainterPath.moveTo( ( size.width() * inner_r * std::sin( DEG2RAD( 324.0 ) ) ) / 2.0, ( size.height() * inner_r * std::cos( DEG2RAD( 324.0 ) ) ) / -2.0 );
722 mPainterPath.lineTo( ( size.width() * std::sin( DEG2RAD( 288.0 ) ) ) / 2.0, ( size.height() * std::cos( DEG2RAD( 288.0 ) ) ) / -2.0 );
723 mPainterPath.lineTo( ( size.width() * inner_r * std::sin( DEG2RAD( 252.0 ) ) ) / 2.0, ( size.height() * inner_r * std::cos( DEG2RAD( 252.0 ) ) ) / -2.0 );
724 mPainterPath.lineTo( ( size.width() * std::sin( DEG2RAD( 216.0 ) ) ) / 2.0, ( size.height() * std::cos( DEG2RAD( 216.0 ) ) ) / -2.0 );
725 mPainterPath.lineTo( 0, ( size.height() * inner_r ) / 2.0 );
726 mPainterPath.lineTo( ( size.width() * std::sin( DEG2RAD( 144.0 ) ) ) / 2.0, ( size.height() * std::cos( DEG2RAD( 144.0 ) ) ) / -2.0 );
727 mPainterPath.lineTo( ( size.width() * inner_r * std::sin( DEG2RAD( 108.0 ) ) ) / 2.0, ( size.height() * inner_r * std::cos( DEG2RAD( 108.0 ) ) ) / -2.0 );
728 mPainterPath.lineTo( ( size.width() * std::sin( DEG2RAD( 72.0 ) ) ) / 2.0, ( size.height() * std::cos( DEG2RAD( 72.0 ) ) ) / -2.0 );
729 mPainterPath.lineTo( ( size.width() * inner_r * std::sin( DEG2RAD( 36.0 ) ) ) / 2.0, ( size.height() * inner_r * std::cos( DEG2RAD( 36.0 ) ) ) / -2.0 );
730 mPainterPath.lineTo( 0, size.height() / -2.0 );
731 mPainterPath.lineTo( ( size.width() * inner_r * std::sin( DEG2RAD( 324.0 ) ) ) / 2.0, ( size.height() * inner_r * std::cos( DEG2RAD( 324.0 ) ) ) / -2.0 );
732 return;
733 }
734 }
735}
736
738{
739 switch ( shape )
740 {
741 case Circle:
742 case Rectangle:
743 case Diamond:
744 case Triangle:
746 case LeftHalfTriangle:
747 case SemiCircle:
748 case ThirdCircle:
749 case QuarterCircle:
750 case Pentagon:
751 case Hexagon:
752 case Octagon:
753 case Star:
754 return true;
755
756 case Cross:
757 case Arrow:
758 case HalfArc:
759 return false;
760 }
761
762 return true;
763}
764
766{
767 if ( mSymbolWidth >= mSymbolHeight )
768 {
769 mSymbolHeight = mSymbolHeight * size / mSymbolWidth;
770 mSymbolWidth = size;
771 }
772 else
773 {
774 mSymbolWidth = mSymbolWidth * size / mSymbolHeight;
775 mSymbolHeight = size;
776 }
778}
779
781{
782 mSymbolWidth = w;
783 QgsMarkerSymbolLayer::setSize( mSymbolWidth >= mSymbolHeight ? mSymbolWidth : mSymbolHeight );
784}
785
787{
788 mSymbolHeight = h;
789 QgsMarkerSymbolLayer::setSize( mSymbolWidth >= mSymbolHeight ? mSymbolWidth : mSymbolHeight );
790}
791
793{
795 mSymbolWidthUnit = unit;
796 mSymbolHeightUnit = unit;
797 mStrokeWidthUnit = unit;
798}
799
801{
803 if ( mSymbolWidthUnit != unit || mSymbolHeightUnit != unit || mStrokeWidthUnit != unit )
804 {
806 }
807 return unit;
808}
809
811{
812 return mSymbolWidthUnit == Qgis::RenderUnit::MapUnits || mSymbolWidthUnit == Qgis::RenderUnit::MetersInMapUnits
813 || mSymbolHeightUnit == Qgis::RenderUnit::MapUnits || mSymbolHeightUnit == Qgis::RenderUnit::MetersInMapUnits
814 || mStrokeWidthUnit == Qgis::RenderUnit::MapUnits || mStrokeWidthUnit == Qgis::RenderUnit::MetersInMapUnits
816}
817
819{
821 mSymbolWidthMapUnitScale = scale;
822 mSymbolHeightMapUnitScale = scale;
823 mStrokeWidthMapUnitScale = scale;
824}
825
827{
828 if ( QgsMarkerSymbolLayer::mapUnitScale() == mSymbolWidthMapUnitScale &&
829 mSymbolWidthMapUnitScale == mSymbolHeightMapUnitScale &&
830 mSymbolHeightMapUnitScale == mStrokeWidthMapUnitScale )
831 {
832 return mSymbolWidthMapUnitScale;
833 }
834 return QgsMapUnitScale();
835}
836
838{
839 const QSizeF size = calculateSize( context );
840
841 bool hasDataDefinedRotation = false;
842 QPointF offset;
843 double angle = 0;
844 calculateOffsetAndRotation( context, size.width(), size.height(), hasDataDefinedRotation, offset, angle );
845
846 QTransform transform;
847
848 // move to the desired position
849 transform.translate( point.x() + offset.x(), point.y() + offset.y() );
850
851 if ( !qgsDoubleNear( angle, 0.0 ) )
852 transform.rotate( angle );
853
854 double penWidth = mStrokeWidth;
856 {
857 context.setOriginalValueVariable( mStrokeWidth );
859
860 if ( !QgsVariantUtils::isNull( exprVal ) )
861 {
862 bool ok;
863 const double strokeWidth = exprVal.toDouble( &ok );
864 if ( ok )
865 {
866 penWidth = strokeWidth;
867 }
868 }
869 }
870 penWidth = context.renderContext().convertToPainterUnits( penWidth, mStrokeWidthUnit, mStrokeWidthMapUnitScale );
871
873 {
876 if ( !QgsVariantUtils::isNull( exprVal ) && exprVal.toString() == QLatin1String( "no" ) )
877 {
878 penWidth = 0.0;
879 }
880 }
881 else if ( mStrokeStyle == Qt::NoPen )
882 penWidth = 0;
883
884 //antialiasing, add 1 pixel
885 penWidth += 1;
886
887 QRectF symbolBounds = transform.mapRect( QRectF( -size.width() / 2.0,
888 -size.height() / 2.0,
889 size.width(),
890 size.height() ) );
891
892 //extend bounds by pen width / 2.0
893 symbolBounds.adjust( -penWidth / 2.0, -penWidth / 2.0,
894 penWidth / 2.0, penWidth / 2.0 );
895
896 return symbolBounds;
897}
898
899bool QgsEllipseSymbolLayer::writeDxf( QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, QgsSymbolRenderContext &context, QPointF shift ) const
900{
901 //width
902 double symbolWidth = mSymbolWidth;
903
904 if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyWidth ) ) //1. priority: data defined setting on symbol layer le
905 {
906 context.setOriginalValueVariable( mSymbolWidth );
908 }
909 if ( mSymbolWidthUnit == Qgis::RenderUnit::Millimeters )
910 {
911 symbolWidth *= mmMapUnitScaleFactor;
912 }
913
914 //height
915 double symbolHeight = mSymbolHeight;
916 if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyHeight ) ) //1. priority: data defined setting on symbol layer level
917 {
918 context.setOriginalValueVariable( mSymbolHeight );
920 }
921 if ( mSymbolHeightUnit == Qgis::RenderUnit::Millimeters )
922 {
923 symbolHeight *= mmMapUnitScaleFactor;
924 }
925
926 //stroke width
927 double strokeWidth = mStrokeWidth;
928
930 {
931 context.setOriginalValueVariable( mStrokeWidth );
933 }
934 if ( mStrokeWidthUnit == Qgis::RenderUnit::Millimeters )
935 {
937 }
938
939 //fill color
940 QColor fc = mColor;
942 {
945 }
946
947 //stroke color
948 QColor oc = mStrokeColor;
950 {
953 }
954
955 //symbol name
958 {
961 }
962
963 //offset
964 double offsetX = 0;
965 double offsetY = 0;
966 markerOffset( context, offsetX, offsetY );
967 QPointF off( offsetX, offsetY );
968
969 //priority for rotation: 1. data defined symbol level, 2. symbol layer rotation (mAngle)
970 double rotation = 0.0;
972 {
975 }
976 else if ( !qgsDoubleNear( mAngle + mLineAngle, 0.0 ) )
977 {
978 rotation = mAngle + mLineAngle;
979 }
980 rotation = -rotation; //rotation in Qt is counterclockwise
981 if ( rotation )
982 off = _rotatedOffset( off, rotation );
983
984 QTransform t;
985 t.translate( shift.x() + offsetX, shift.y() + offsetY );
986
987 if ( !qgsDoubleNear( rotation, 0.0 ) )
988 t.rotate( rotation );
989
990 const double halfWidth = symbolWidth / 2.0;
991 const double halfHeight = symbolHeight / 2.0;
992
993 switch ( shape )
994 {
995 case Circle:
996 {
997 if ( qgsDoubleNear( halfWidth, halfHeight ) )
998 {
999 const QgsPoint pt( t.map( QPointF( 0, 0 ) ) );
1000 e.writeFilledCircle( layerName, oc, pt, halfWidth );
1001 }
1002 else
1003 {
1004 QgsPointSequence line;
1005
1006 const double stepsize = 2 * M_PI / 40;
1007 for ( int i = 0; i < 39; ++i )
1008 {
1009 const double angle = stepsize * i;
1010 const double x = halfWidth * std::cos( angle );
1011 const double y = halfHeight * std::sin( angle );
1012 line << QgsPoint( t.map( QPointF( x, y ) ) );
1013 }
1014 //close ellipse with first point
1015 line << line.at( 0 );
1016
1017 if ( mBrush.style() != Qt::NoBrush )
1018 e.writePolygon( QgsRingSequence() << line, layerName, QStringLiteral( "SOLID" ), fc );
1019 if ( mPen.style() != Qt::NoPen )
1020 e.writePolyline( line, layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth );
1021 }
1022 return true;
1023 }
1024
1025 case Rectangle:
1026 {
1028 p << QgsPoint( t.map( QPointF( -halfWidth, -halfHeight ) ) )
1029 << QgsPoint( t.map( QPointF( halfWidth, -halfHeight ) ) )
1030 << QgsPoint( t.map( QPointF( halfWidth, halfHeight ) ) )
1031 << QgsPoint( t.map( QPointF( -halfWidth, halfHeight ) ) );
1032 p << p[0];
1033
1034 if ( mBrush.style() != Qt::NoBrush )
1035 e.writePolygon( QgsRingSequence() << p, layerName, QStringLiteral( "SOLID" ), fc );
1036 if ( mPen.style() != Qt::NoPen )
1037 e.writePolyline( p, layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth );
1038 return true;
1039 }
1040 case Cross:
1041 {
1042 if ( mPen.style() != Qt::NoPen )
1043 {
1045 << QgsPoint( t.map( QPointF( -halfWidth, 0 ) ) )
1046 << QgsPoint( t.map( QPointF( halfWidth, 0 ) ) ),
1047 layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth );
1049 << QgsPoint( t.map( QPointF( 0, halfHeight ) ) )
1050 << QgsPoint( t.map( QPointF( 0, -halfHeight ) ) ),
1051 layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth );
1052 return true;
1053 }
1054 break;
1055 }
1056
1057 case Triangle:
1058 {
1060 p << QgsPoint( t.map( QPointF( -halfWidth, -halfHeight ) ) )
1061 << QgsPoint( t.map( QPointF( halfWidth, -halfHeight ) ) )
1062 << QgsPoint( t.map( QPointF( 0, halfHeight ) ) );
1063 p << p[0];
1064 if ( mBrush.style() != Qt::NoBrush )
1065 e.writePolygon( QgsRingSequence() << p, layerName, QStringLiteral( "SOLID" ), fc );
1066 if ( mPen.style() != Qt::NoPen )
1067 e.writePolyline( p, layerName, QStringLiteral( "CONTINUOUS" ), oc, strokeWidth );
1068 return true;
1069 }
1070
1071 case Diamond:
1072 case Arrow:
1073 case HalfArc:
1074 case RightHalfTriangle:
1075 case LeftHalfTriangle:
1076 case SemiCircle:
1077 case ThirdCircle:
1078 case QuarterCircle:
1079 case Pentagon:
1080 case Hexagon:
1081 case Octagon:
1082 case Star:
1083 return false;
1084 }
1085
1086 return false;
1087}
1088
1090{
1091 if ( ok )
1092 *ok = true;
1093 const QString cleaned = name.toLower().trimmed();
1094
1095 if ( cleaned == QLatin1String( "circle" ) )
1096 return Circle;
1097 else if ( cleaned == QLatin1String( "square" ) || cleaned == QLatin1String( "rectangle" ) )
1098 return Rectangle;
1099 else if ( cleaned == QLatin1String( "diamond" ) )
1100 return Diamond;
1101 else if ( cleaned == QLatin1String( "cross" ) )
1102 return Cross;
1103 else if ( cleaned == QLatin1String( "arrow" ) )
1104 return Arrow;
1105 else if ( cleaned == QLatin1String( "half_arc" ) )
1106 return HalfArc;
1107 else if ( cleaned == QLatin1String( "triangle" ) )
1108 return Triangle;
1109 else if ( cleaned == QLatin1String( "right_half_triangle" ) )
1110 return RightHalfTriangle;
1111 else if ( cleaned == QLatin1String( "left_half_triangle" ) )
1112 return LeftHalfTriangle;
1113 else if ( cleaned == QLatin1String( "semi_circle" ) )
1114 return SemiCircle;
1115 else if ( cleaned == QLatin1String( "third_circle" ) )
1116 return ThirdCircle;
1117 else if ( cleaned == QLatin1String( "quarter_circle" ) )
1118 return QuarterCircle;
1119 else if ( cleaned == QLatin1String( "pentagon" ) )
1120 return Pentagon;
1121 else if ( cleaned == QLatin1String( "hexagon" ) )
1122 return Hexagon;
1123 else if ( cleaned == QLatin1String( "octagon" ) )
1124 return Octagon;
1125 else if ( cleaned == QLatin1String( "star" ) )
1126 return Star; if ( ok )
1127 *ok = false;
1128 return Circle;
1129}
1130
1132{
1133 switch ( shape )
1134 {
1135 case Circle:
1136 return QStringLiteral( "circle" );
1137 case Rectangle:
1138 return QStringLiteral( "rectangle" );
1139 case Diamond:
1140 return QStringLiteral( "diamond" );
1141 case Cross:
1142 return QStringLiteral( "cross" );
1143 case Arrow:
1144 return QStringLiteral( "arrow" );
1145 case HalfArc:
1146 return QStringLiteral( "half_arc" );
1147 case Triangle:
1148 return QStringLiteral( "triangle" );
1149 case RightHalfTriangle:
1150 return QStringLiteral( "right_half_triangle" );
1151 case LeftHalfTriangle:
1152 return QStringLiteral( "left_half_triangle" );
1153 case SemiCircle:
1154 return QStringLiteral( "semi_circle" );
1155 case ThirdCircle:
1156 return QStringLiteral( "third_circle" );
1157 case QuarterCircle:
1158 return QStringLiteral( "quarter_circle" );
1159 case Pentagon:
1160 return QStringLiteral( "pentagon" );
1161 case Hexagon:
1162 return QStringLiteral( "hexagon" );
1163 case Octagon:
1164 return QStringLiteral( "octagon" );
1165 case Star:
1166 return QStringLiteral( "star" );
1167 }
1168 return QString();
1169}
1170
1171QList<QgsEllipseSymbolLayer::Shape> QgsEllipseSymbolLayer::availableShapes()
1172{
1173 QList< Shape > shapes;
1174 shapes << Circle
1175 << Rectangle
1176 << Diamond
1177 << Cross
1178 << Arrow
1179 << HalfArc
1180 << Triangle
1183 << SemiCircle
1184 << ThirdCircle
1185 << QuarterCircle
1186 << Pentagon
1187 << Hexagon
1188 << Octagon
1189 << Star;
1190 return shapes;
1191}
@ DynamicRotation
Rotation of symbol may be changed during rendering and symbol should not be cached.
RenderUnit
Rendering size units.
Definition qgis.h:3627
@ Millimeters
Millimeters.
@ Unknown
Mixed or unknown units.
@ MapUnits
Map units.
@ MetersInMapUnits
Meters value as Map units.
QColor valueAsColor(int key, const QgsExpressionContext &context, const QColor &defaultColor=QColor(), bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a color.
double valueAsDouble(int key, const QgsExpressionContext &context, double defaultValue=0.0, bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a double.
QString valueAsString(int key, const QgsExpressionContext &context, const QString &defaultString=QString(), bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a string.
Exports QGIS layers to the DXF format.
void writeFilledCircle(const QString &layer, const QColor &color, const QgsPoint &pt, double radius)
Write filled circle (as hatch)
void writePolygon(const QgsRingSequence &polygon, const QString &layer, const QString &hatchPattern, const QColor &color)
Draw dxf filled polygon (HATCH)
void writePolyline(const QgsPointSequence &line, const QString &layer, const QString &lineStyleName, const QColor &color, double width=-1)
Draw dxf primitives (LWPOLYLINE)
A symbol layer for rendering objects with major and minor axis (e.g.
void setPenCapStyle(Qt::PenCapStyle style)
Sets the marker's stroke cap style (e.g., flat, round, etc).
bool writeDxf(QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, QgsSymbolRenderContext &context, QPointF shift=QPointF(0.0, 0.0)) const override
write as DXF
void setSymbolHeightMapUnitScale(const QgsMapUnitScale &scale)
void setSymbolWidthMapUnitScale(const QgsMapUnitScale &scale)
QVariantMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
QRectF bounds(QPointF point, QgsSymbolRenderContext &context) override
Returns the approximate bounding box of the marker symbol layer, taking into account any data defined...
Qgis::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
void renderPoint(QPointF point, QgsSymbolRenderContext &context) override
Renders a marker at the specified point.
void toSld(QDomDocument &doc, QDomElement &element, const QVariantMap &props) const override
Saves the symbol layer as SLD.
void setStrokeColor(const QColor &c) override
Sets the stroke color for the symbol layer.
void setStrokeStyle(Qt::PenStyle strokeStyle)
static QgsEllipseSymbolLayer::Shape decodeShape(const QString &name, bool *ok=nullptr)
Attempts to decode a string representation of a shape name to the corresponding shape.
void setStrokeWidthUnit(Qgis::RenderUnit unit)
Sets the units for the symbol's stroke width.
void setSize(double size) override
Sets the symbol size.
QgsMapUnitScale mapUnitScale() const override
Shape
Marker symbol shapes.
@ ThirdCircle
Third Circle (since QGIS 3.28)
@ Pentagon
Pentagon (since QGIS 3.28)
@ Hexagon
Hexagon (since QGIS 3.28)
@ Cross
Stroke-only cross.
@ QuarterCircle
Quarter Circle (since QGIS 3.28)
@ HalfArc
Stroke-only half arc (since QGIS 3.20)
@ Arrow
Stroke-only arrow (since QGIS 3.20)
@ RightHalfTriangle
Right half of a triangle.
@ Star
Star (since QGIS 3.28)
@ Octagon
Octagon (since QGIS 3.28)
@ LeftHalfTriangle
Left half of a triangle.
QColor fillColor() const override
Returns the fill color for the symbol layer.
QgsEllipseSymbolLayer::Shape shape() const
Returns the shape for the rendered ellipse marker symbol.
bool usesMapUnits() const override
Returns true if the symbol layer has any components which use map unit based sizes.
void setFillColor(const QColor &c) override
Sets the fill color for the symbol layer.
void setShape(QgsEllipseSymbolLayer::Shape shape)
Sets the rendered ellipse marker shape.
static QList< QgsEllipseSymbolLayer::Shape > availableShapes()
Returns a list of all available shape types.
Qt::PenStyle strokeStyle() const
static QgsSymbolLayer * create(const QVariantMap &properties=QVariantMap())
Creates the symbol layer.
static QgsSymbolLayer * createFromSld(QDomElement &element)
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.
Qgis::GeometryType type
Perform transforms between map coordinates and device coordinates.
double mapRotation() const
Returns the current map rotation in degrees (clockwise).
Struct for storing maximum and minimum scales for measurements in map units.
double mSize
Marker size.
virtual void setSize(double size)
Sets the symbol size.
Qgis::RenderUnit mOffsetUnit
Offset units.
QPointF offset() const
Returns the marker's offset, which is the horizontal and vertical displacement which the rendered mar...
double mLineAngle
Line rotation angle (see setLineAngle() for details)
HorizontalAnchorPoint
Symbol horizontal anchor points.
void setOffsetUnit(Qgis::RenderUnit unit)
Sets the units for the symbol's offset.
void setAngle(double angle)
Sets the rotation angle for the marker.
Qgis::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
void setVerticalAnchorPoint(VerticalAnchorPoint v)
Sets the vertical anchor point for positioning the symbol.
QPointF mOffset
Marker offset.
void setHorizontalAnchorPoint(HorizontalAnchorPoint h)
Sets the horizontal anchor point for positioning the symbol.
QgsMapUnitScale mapUnitScale() const override
void setOffset(QPointF offset)
Sets the marker's offset, which is the horizontal and vertical displacement which the rendered marker...
void setSizeMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the symbol's size.
double size() const
Returns the symbol size.
QgsMapUnitScale mOffsetMapUnitScale
Offset map unit scale.
HorizontalAnchorPoint mHorizontalAnchorPoint
Horizontal anchor point.
static QPointF _rotatedOffset(QPointF offset, double angle)
Adjusts a marker offset to account for rotation.
QgsMapUnitScale mSizeMapUnitScale
Marker size map unit scale.
Qgis::RenderUnit mSizeUnit
Marker size unit.
void setOutputUnit(Qgis::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
void setSizeUnit(Qgis::RenderUnit unit)
Sets the units for the symbol's size.
VerticalAnchorPoint
Symbol vertical anchor points.
void markerOffset(QgsSymbolRenderContext &context, double &offsetX, double &offsetY) const
Calculates the required marker offset, including both the symbol offset and any displacement required...
VerticalAnchorPoint mVerticalAnchorPoint
Vertical anchor point.
void setOffsetMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the symbol's offset.
double mAngle
Marker rotation angle, in degrees clockwise from north.
void startRender(QgsSymbolRenderContext &context) override
Called before a set of rendering operations commences on the supplied render context.
double angle() const
Returns the rotation angle for the marker, in degrees clockwise from north.
void setMapUnitScale(const QgsMapUnitScale &scale) override
Point geometry type, with support for z-dimension and m-values.
Definition qgspoint.h:49
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.
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.
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.
void restoreOldDataDefinedProperties(const QVariantMap &stringMap)
Restores older data defined properties from string map.
virtual void setColor(const QColor &color)
Sets the "representative" color for the symbol layer.
virtual QColor color() const
Returns the "representative" color of the symbol layer.
void copyPaintEffect(QgsSymbolLayer *destLayer) const
Copies paint effect of this layer to another symbol layer.
QgsPropertyCollection mDataDefinedProperties
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the symbol layer's property collection, used for data defined overrides.
const QgsFeature * feature() const
Returns the current feature being rendered.
Qgis::SymbolRenderHints renderHints() const
Returns the rendering hint flags for the symbol.
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for data defined symbology.
qreal opacity() const
Returns the opacity for the symbol.
QgsRenderContext & renderContext()
Returns a reference to the context's render context.
static Q_INVOKABLE Qgis::RenderUnit decodeRenderUnit(const QString &string, bool *ok=nullptr)
Decodes a render unit from a string.
static Q_INVOKABLE QString encodeUnit(Qgis::DistanceUnit unit)
Encodes a distance unit to a string.
static bool isNull(const QVariant &variant)
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:4332
QMap< QString, QString > QgsStringMap
Definition qgis.h:4877
QVector< QgsPointSequence > QgsRingSequence
QVector< QgsPoint > QgsPointSequence
#define DEG2RAD(x)
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:39