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