1 /*************************************************************************** 2 qgsmarkersymbollayer.h 3 --------------------- 4 begin : November 2009 5 copyright : (C) 2009 by Martin Dobias 6 email : wonder dot sk at gmail dot com 7 *************************************************************************** 8 * * 9 * This program is free software; you can redistribute it and/or modify * 10 * it under the terms of the GNU General Public License as published by * 11 * the Free Software Foundation; either version 2 of the License, or * 12 * (at your option) any later version. * 13 * * 14 ***************************************************************************/ 15 16 #ifndef QGSMARKERSYMBOLLAYER_H 17 #define QGSMARKERSYMBOLLAYER_H 18 19 #include "qgis_core.h" 20 #include "qgis_sip.h" 21 #include "qgssymbollayer.h" 22 23 #define DEFAULT_SIMPLEMARKER_NAME "circle" 24 #define DEFAULT_SIMPLEMARKER_COLOR QColor(255,0,0) 25 #define DEFAULT_SIMPLEMARKER_BORDERCOLOR QColor( 35, 35, 35 ) 26 #define DEFAULT_SIMPLEMARKER_JOINSTYLE Qt::BevelJoin 27 #define DEFAULT_SIMPLEMARKER_SIZE DEFAULT_POINT_SIZE 28 #define DEFAULT_SIMPLEMARKER_ANGLE 0 29 30 #include <QPen> 31 #include <QBrush> 32 #include <QPicture> 33 #include <QPolygonF> 34 #include <QFont> 35 36 /** 37 * \ingroup core 38 * \class QgsSimpleMarkerSymbolLayerBase 39 * \brief Abstract base class for simple marker symbol layers. Handles creation of the symbol shapes but 40 * leaves the actual drawing of the symbols to subclasses. 41 * \since QGIS 2.16 42 */ 43 class CORE_EXPORT QgsSimpleMarkerSymbolLayerBase : public QgsMarkerSymbolLayer 44 { 45 46 public: 47 48 //! Marker symbol shapes 49 enum Shape 50 { 51 Square, //!< Square 52 Diamond, //!< Diamond 53 Pentagon, //!< Pentagon 54 Hexagon, //!< Hexagon 55 Triangle, //!< Triangle 56 EquilateralTriangle, //!< Equilateral triangle 57 Star, //!< Star 58 Arrow, //!< Arrow 59 Circle, //!< Circle 60 Cross, //!< Cross (lines only) 61 CrossFill, //!< Solid filled cross 62 Cross2, //!< Rotated cross (lines only), "x" shape 63 Line, //!< Vertical line 64 ArrowHead, //!< Right facing arrow head (unfilled, lines only) 65 ArrowHeadFilled, //!< Right facing filled arrow head 66 SemiCircle, //!< Semi circle (top half) 67 ThirdCircle, //!< One third circle (top left third) 68 QuarterCircle, //!< Quarter circle (top left quarter) 69 QuarterSquare, //!< Quarter square (top left quarter) 70 HalfSquare, //!< Half square (left half) 71 DiagonalHalfSquare, //!< Diagonal half square (bottom left half) 72 RightHalfTriangle, //!< Right half of triangle 73 LeftHalfTriangle, //!< Left half of triangle 74 Octagon, //!< Octagon (since QGIS 3.18) 75 SquareWithCorners, //!< A square with diagonal corners (since QGIS 3.18) 76 AsteriskFill, //!< A filled asterisk shape (since QGIS 3.18) 77 }; 78 79 //! Returns a list of all available shape types. 80 static QList< QgsSimpleMarkerSymbolLayerBase::Shape > availableShapes(); 81 82 /** 83 * Returns TRUE if a symbol shape has a fill. 84 * \param shape shape to test 85 * \returns TRUE if shape uses a fill, or FALSE if shape uses lines only 86 */ 87 static bool shapeIsFilled( QgsSimpleMarkerSymbolLayerBase::Shape shape ); 88 89 /** 90 * Constructor for QgsSimpleMarkerSymbolLayerBase. 91 * \param shape symbol shape for markers 92 * \param size symbol size (in mm) 93 * \param angle symbol rotation angle 94 * \param scaleMethod scaling method for data defined scaling 95 */ 96 QgsSimpleMarkerSymbolLayerBase( QgsSimpleMarkerSymbolLayerBase::Shape shape = Circle, 97 double size = DEFAULT_SIMPLEMARKER_SIZE, 98 double angle = DEFAULT_SIMPLEMARKER_ANGLE, 99 QgsSymbol::ScaleMethod scaleMethod = DEFAULT_SCALE_METHOD ); 100 101 /** 102 * Returns the shape for the rendered marker symbol. 103 * \see setShape() 104 */ shape()105 QgsSimpleMarkerSymbolLayerBase::Shape shape() const { return mShape; } 106 107 /** 108 * Sets the rendered marker shape. 109 * \param shape new marker shape 110 * \see shape() 111 */ setShape(QgsSimpleMarkerSymbolLayerBase::Shape shape)112 void setShape( QgsSimpleMarkerSymbolLayerBase::Shape shape ) { mShape = shape; } 113 114 /** 115 * Attempts to decode a string representation of a shape name to the corresponding 116 * shape. 117 * \param name encoded shape name 118 * \param ok if specified, will be set to TRUE if shape was successfully decoded 119 * \returns decoded name 120 * \see encodeShape() 121 */ 122 static QgsSimpleMarkerSymbolLayerBase::Shape decodeShape( const QString &name, bool *ok = nullptr ); 123 124 /** 125 * Encodes a shape to its string representation. 126 * \param shape shape to encode 127 * \returns encoded string 128 * \see decodeShape() 129 */ 130 static QString encodeShape( QgsSimpleMarkerSymbolLayerBase::Shape shape ); 131 132 void startRender( QgsSymbolRenderContext &context ) override; 133 void stopRender( QgsSymbolRenderContext &context ) override; 134 void renderPoint( QPointF point, QgsSymbolRenderContext &context ) override; 135 QRectF bounds( QPointF point, QgsSymbolRenderContext &context ) override; 136 137 protected: 138 139 /** 140 * Prepares the layer for drawing the specified shape (QPolygonF version) 141 */ 142 bool prepareMarkerShape( Shape shape ); 143 144 /** 145 * Prepares the layer for drawing the specified shape (QPainterPath version) 146 */ 147 bool prepareMarkerPath( Shape symbol ); 148 149 /** 150 * Creates a polygon representing the specified shape. 151 * \param shape shape to create 152 * \param polygon destination polygon for shape 153 * \returns TRUE if shape was successfully stored in polygon 154 */ 155 bool shapeToPolygon( Shape shape, QPolygonF &polygon ) const; 156 157 /** 158 * Calculates the desired size of the marker, considering data defined size overrides. 159 * \param context symbol render context 160 * \param hasDataDefinedSize will be set to TRUE if marker uses data defined sizes 161 * \returns marker size, in original size units 162 */ 163 double calculateSize( QgsSymbolRenderContext &context, bool &hasDataDefinedSize ) const; 164 165 /** 166 * Calculates the marker offset and rotation. 167 * \param context symbol render context 168 * \param scaledSize size of symbol to render 169 * \param hasDataDefinedRotation will be set to TRUE if marker has data defined rotation 170 * \param offset will be set to calculated marker offset (in painter units) 171 * \param angle will be set to calculated marker angle 172 */ 173 void calculateOffsetAndRotation( QgsSymbolRenderContext &context, double scaledSize, bool &hasDataDefinedRotation, QPointF &offset, double &angle ) const; 174 175 //! Polygon of points in shape. If polygon is empty then shape is using mPath. 176 QPolygonF mPolygon; 177 178 //! Painter path representing shape. If mPolygon is empty then the shape is stored in mPath. 179 QPainterPath mPath; 180 181 //! Symbol shape 182 Shape mShape; 183 184 private: 185 186 /** 187 * Derived classes must implement draw() to handle drawing the generated shape onto the painter surface. 188 * \param context symbol render context 189 * \param shape shape to draw 190 * \param polygon polygon representing transformed marker shape. May be empty, in which case the shape will be specified 191 * in the path argument. 192 * \param path transformed painter path representing shape to draw 193 */ 194 virtual void draw( QgsSymbolRenderContext &context, QgsSimpleMarkerSymbolLayerBase::Shape shape, const QPolygonF &polygon, const QPainterPath &path ) = 0 SIP_FORCE; 195 }; 196 197 /** 198 * \ingroup core 199 * \class QgsSimpleMarkerSymbolLayer 200 * \brief Simple marker symbol layer, consisting of a rendered shape with solid fill color and an stroke. 201 */ 202 class CORE_EXPORT QgsSimpleMarkerSymbolLayer : public QgsSimpleMarkerSymbolLayerBase 203 { 204 public: 205 206 /** 207 * Constructor for QgsSimpleMarkerSymbolLayer. 208 * \param shape symbol shape 209 * \param size symbol size (in mm) 210 * \param angle symbol rotation angle 211 * \param scaleMethod scaling method for data defined scaling 212 * \param color fill color for symbol 213 * \param strokeColor stroke color for symbol 214 * \param penJoinStyle join style for stroke pen 215 */ 216 QgsSimpleMarkerSymbolLayer( QgsSimpleMarkerSymbolLayerBase::Shape shape = Circle, 217 double size = DEFAULT_SIMPLEMARKER_SIZE, 218 double angle = DEFAULT_SIMPLEMARKER_ANGLE, 219 QgsSymbol::ScaleMethod scaleMethod = DEFAULT_SCALE_METHOD, 220 const QColor &color = DEFAULT_SIMPLEMARKER_COLOR, 221 const QColor &strokeColor = DEFAULT_SIMPLEMARKER_BORDERCOLOR, 222 Qt::PenJoinStyle penJoinStyle = DEFAULT_SIMPLEMARKER_JOINSTYLE ); 223 224 // static methods 225 226 /** 227 * Creates a new QgsSimpleMarkerSymbolLayer. 228 * \param properties a property map containing symbol properties (see properties()) 229 * \returns new QgsSimpleMarkerSymbolLayer 230 */ 231 static QgsSymbolLayer *create( const QgsStringMap &properties = QgsStringMap() ) SIP_FACTORY; 232 233 /** 234 * Creates a new QgsSimpleMarkerSymbolLayer from an SLD XML element. 235 * \param element XML element containing SLD definition of symbol 236 * \returns new QgsSimpleMarkerSymbolLayer 237 */ 238 static QgsSymbolLayer *createFromSld( QDomElement &element ) SIP_FACTORY; 239 240 // reimplemented from base classes 241 242 QString layerType() const override; 243 void startRender( QgsSymbolRenderContext &context ) override; 244 void renderPoint( QPointF point, QgsSymbolRenderContext &context ) override; 245 QgsStringMap properties() const override; 246 QgsSimpleMarkerSymbolLayer *clone() const override SIP_FACTORY; 247 void writeSldMarker( QDomDocument &doc, QDomElement &element, const QgsStringMap &props ) const override; 248 QString ogrFeatureStyle( double mmScaleFactor, double mapUnitScaleFactor ) const override; 249 bool writeDxf( QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, QgsSymbolRenderContext &context, QPointF shift = QPointF( 0.0, 0.0 ) ) const override; 250 void setOutputUnit( QgsUnitTypes::RenderUnit unit ) override; 251 QgsUnitTypes::RenderUnit outputUnit() const override; 252 void setMapUnitScale( const QgsMapUnitScale &scale ) override; 253 QgsMapUnitScale mapUnitScale() const override; 254 bool usesMapUnits() const override; 255 QRectF bounds( QPointF point, QgsSymbolRenderContext &context ) override; fillColor()256 QColor fillColor() const override { return mColor; } setFillColor(const QColor & color)257 void setFillColor( const QColor &color ) override { mColor = color; } 258 void setColor( const QColor &color ) override; 259 QColor color() const override; 260 261 // new methods 262 263 /** 264 * Returns the marker's stroke color. 265 * \see setStrokeColor() 266 * \see strokeStyle() 267 * \see penJoinStyle() 268 */ strokeColor()269 QColor strokeColor() const override { return mStrokeColor; } 270 271 /** 272 * Sets the marker's stroke color. 273 * \param color stroke color 274 * \see strokeColor() 275 * \see setStrokeStyle() 276 * \see setPenJoinStyle() 277 */ setStrokeColor(const QColor & color)278 void setStrokeColor( const QColor &color ) override { mStrokeColor = color; } 279 280 /** 281 * Returns the marker's stroke style (e.g., solid, dashed, etc) 282 * \see setStrokeStyle() 283 * \see strokeColor() 284 * \see penJoinStyle() 285 * \since QGIS 2.4 286 */ strokeStyle()287 Qt::PenStyle strokeStyle() const { return mStrokeStyle; } 288 289 /** 290 * Sets the marker's stroke style (e.g., solid, dashed, etc) 291 * \param strokeStyle style 292 * \see strokeStyle() 293 * \see setStrokeColor() 294 * \see setPenJoinStyle() 295 * \since QGIS 2.4 296 */ setStrokeStyle(Qt::PenStyle strokeStyle)297 void setStrokeStyle( Qt::PenStyle strokeStyle ) { mStrokeStyle = strokeStyle; } 298 299 /** 300 * Returns the marker's stroke join style (e.g., miter, bevel, etc). 301 * \see setPenJoinStyle() 302 * \see strokeColor() 303 * \see strokeStyle() 304 * \since QGIS 2.16 305 */ penJoinStyle()306 Qt::PenJoinStyle penJoinStyle() const { return mPenJoinStyle; } 307 308 /** 309 * Sets the marker's stroke join style (e.g., miter, bevel, etc). 310 * \param style join style 311 * \see penJoinStyle() 312 * \see setStrokeColor() 313 * \see setStrokeStyle() 314 * \since QGIS 2.16 315 */ setPenJoinStyle(Qt::PenJoinStyle style)316 void setPenJoinStyle( Qt::PenJoinStyle style ) { mPenJoinStyle = style; } 317 318 /** 319 * Returns the width of the marker's stroke. 320 * \see setStrokeWidth() 321 * \see strokeWidthUnit() 322 * \see strokeWidthMapUnitScale() 323 */ strokeWidth()324 double strokeWidth() const { return mStrokeWidth; } 325 326 /** 327 * Sets the width of the marker's stroke. 328 * \param w stroke width. See strokeWidthUnit() for units. 329 * \see strokeWidth() 330 * \see setStrokeWidthUnit() 331 * \see setStrokeWidthMapUnitScale() 332 */ setStrokeWidth(double w)333 void setStrokeWidth( double w ) { mStrokeWidth = w; } 334 335 /** 336 * Sets the unit for the width of the marker's stroke. 337 * \param u stroke width unit 338 * \see strokeWidthUnit() 339 * \see setStrokeWidth() 340 * \see setStrokeWidthMapUnitScale() 341 */ setStrokeWidthUnit(QgsUnitTypes::RenderUnit u)342 void setStrokeWidthUnit( QgsUnitTypes::RenderUnit u ) { mStrokeWidthUnit = u; } 343 344 /** 345 * Returns the unit for the width of the marker's stroke. 346 * \see setStrokeWidthUnit() 347 * \see strokeWidth() 348 * \see strokeWidthMapUnitScale() 349 */ strokeWidthUnit()350 QgsUnitTypes::RenderUnit strokeWidthUnit() const { return mStrokeWidthUnit; } 351 352 /** 353 * Sets the map scale for the width of the marker's stroke. 354 * \param scale stroke width map unit scale 355 * \see strokeWidthMapUnitScale() 356 * \see setStrokeWidth() 357 * \see setStrokeWidthUnit() 358 */ setStrokeWidthMapUnitScale(const QgsMapUnitScale & scale)359 void setStrokeWidthMapUnitScale( const QgsMapUnitScale &scale ) { mStrokeWidthMapUnitScale = scale; } 360 361 /** 362 * Returns the map scale for the width of the marker's stroke. 363 * \see setStrokeWidthMapUnitScale() 364 * \see strokeWidth() 365 * \see strokeWidthUnit() 366 */ strokeWidthMapUnitScale()367 const QgsMapUnitScale &strokeWidthMapUnitScale() const { return mStrokeWidthMapUnitScale; } 368 369 protected: 370 371 /** 372 * Draws the marker shape in the specified painter. 373 * \param p destination QPainter 374 * \param context symbol context 375 * \note this method does not handle setting the painter pen or brush to match the symbol's fill or stroke 376 */ 377 void drawMarker( QPainter *p, QgsSymbolRenderContext &context ); 378 379 /** 380 * Prepares cache image 381 * \returns TRUE in case of success, FALSE if cache image size too large 382 */ 383 bool prepareCache( QgsSymbolRenderContext &context ); 384 385 //! Stroke color 386 QColor mStrokeColor; 387 //! Stroke style 388 Qt::PenStyle mStrokeStyle = Qt::SolidLine; 389 //! Stroke width 390 double mStrokeWidth = 0; 391 //! Stroke width units 392 QgsUnitTypes::RenderUnit mStrokeWidthUnit = QgsUnitTypes::RenderMillimeters; 393 //! Stroke width map unit scale 394 QgsMapUnitScale mStrokeWidthMapUnitScale; 395 //! Stroke pen join style 396 Qt::PenJoinStyle mPenJoinStyle; 397 //! QPen corresponding to marker's stroke style 398 QPen mPen; 399 //! QBrush corresponding to marker's fill style 400 QBrush mBrush; 401 402 //! Cached image of marker, if using cached version 403 QImage mCache; 404 //! QPen to use as stroke of selected symbols 405 QPen mSelPen; 406 //! QBrush to use as fill of selected symbols 407 QBrush mSelBrush; 408 //! Cached image of selected marker, if using cached version 409 QImage mSelCache; 410 411 /** 412 * TRUE if using cached images of markers for drawing. This is faster, but cannot 413 * be used when data defined properties are present 414 */ 415 bool mUsingCache = false; 416 417 //! Maximum width/height of cache image 418 static const int MAXIMUM_CACHE_WIDTH = 3000; 419 420 private: 421 422 void draw( QgsSymbolRenderContext &context, QgsSimpleMarkerSymbolLayerBase::Shape shape, const QPolygonF &polygon, const QPainterPath &path ) override SIP_FORCE; 423 424 double mCachedOpacity = 1.0; 425 426 }; 427 428 /** 429 * \ingroup core 430 * \class QgsFilledMarkerSymbolLayer 431 * \brief Filled marker symbol layer, consisting of a shape which is rendered using a QgsFillSymbol. This allows 432 * the symbol to support advanced styling of the interior and stroke of the shape. 433 * \since QGIS 2.16 434 */ 435 class CORE_EXPORT QgsFilledMarkerSymbolLayer : public QgsSimpleMarkerSymbolLayerBase 436 { 437 public: 438 439 /** 440 * Constructor for QgsFilledMarkerSymbolLayer. 441 * \param shape symbol shape 442 * \param size symbol size (in mm) 443 * \param angle symbol rotation angle 444 * \param scaleMethod size scaling method 445 */ 446 QgsFilledMarkerSymbolLayer( QgsSimpleMarkerSymbolLayerBase::Shape shape = Circle, 447 double size = DEFAULT_SIMPLEMARKER_SIZE, 448 double angle = DEFAULT_SIMPLEMARKER_ANGLE, 449 QgsSymbol::ScaleMethod scaleMethod = DEFAULT_SCALE_METHOD ); 450 451 /** 452 * Creates a new QgsFilledMarkerSymbolLayer. 453 * \param properties a property map containing symbol properties (see properties()) 454 * \returns new QgsFilledMarkerSymbolLayer 455 */ 456 static QgsSymbolLayer *create( const QgsStringMap &properties = QgsStringMap() ) SIP_FACTORY; 457 458 QString layerType() const override; 459 void startRender( QgsSymbolRenderContext &context ) override; 460 void stopRender( QgsSymbolRenderContext &context ) override; 461 QgsStringMap properties() const override; 462 QgsFilledMarkerSymbolLayer *clone() const override SIP_FACTORY; 463 QgsSymbol *subSymbol() override; 464 bool setSubSymbol( QgsSymbol *symbol SIP_TRANSFER ) override; 465 double estimateMaxBleed( const QgsRenderContext &context ) const override; 466 QSet<QString> usedAttributes( const QgsRenderContext &context ) const override; 467 bool hasDataDefinedProperties() const override; 468 void setColor( const QColor &c ) override; 469 QColor color() const override; 470 bool usesMapUnits() const override; 471 472 private: 473 #ifdef SIP_RUN 474 QgsFilledMarkerSymbolLayer( const QgsFilledMarkerSymbolLayer & ); 475 #endif 476 477 void draw( QgsSymbolRenderContext &context, QgsSimpleMarkerSymbolLayerBase::Shape shape, const QPolygonF &polygon, const QPainterPath &path ) override SIP_FORCE; 478 479 //! Fill subsymbol 480 std::unique_ptr< QgsFillSymbol > mFill; 481 }; 482 483 ////////// 484 485 #define DEFAULT_SVGMARKER_SIZE 2*DEFAULT_POINT_SIZE 486 #define DEFAULT_SVGMARKER_ANGLE 0 487 488 /** 489 * \ingroup core 490 * \class QgsSvgMarkerSymbolLayer 491 */ 492 class CORE_EXPORT QgsSvgMarkerSymbolLayer : public QgsMarkerSymbolLayer 493 { 494 public: 495 //! Constructs SVG marker symbol layer with picture from given absolute path to a SVG file 496 QgsSvgMarkerSymbolLayer( const QString &path, 497 double size = DEFAULT_SVGMARKER_SIZE, 498 double angle = DEFAULT_SVGMARKER_ANGLE, 499 QgsSymbol::ScaleMethod scaleMethod = DEFAULT_SCALE_METHOD ); 500 501 // static stuff 502 503 static QgsSymbolLayer *create( const QgsStringMap &properties = QgsStringMap() ) SIP_FACTORY; 504 static QgsSymbolLayer *createFromSld( QDomElement &element ) SIP_FACTORY; 505 506 /** 507 * Turns relative paths in properties map to absolute when reading and vice versa when writing. 508 * Used internally when reading/writing symbols. 509 * \since QGIS 3.0 510 */ 511 static void resolvePaths( QgsStringMap &properties, const QgsPathResolver &pathResolver, bool saving ); 512 513 // implemented from base classes 514 515 QString layerType() const override; 516 517 void startRender( QgsSymbolRenderContext &context ) override; 518 519 void stopRender( QgsSymbolRenderContext &context ) override; 520 521 void renderPoint( QPointF point, QgsSymbolRenderContext &context ) override; 522 523 QgsStringMap properties() const override; 524 bool usesMapUnits() const override; 525 526 QgsSvgMarkerSymbolLayer *clone() const override SIP_FACTORY; 527 528 void writeSldMarker( QDomDocument &doc, QDomElement &element, const QgsStringMap &props ) const override; 529 530 /** 531 * Returns the marker SVG path. 532 * \see setPath() 533 */ path()534 QString path() const { return mPath; } 535 536 /** 537 * Set the marker SVG path. 538 * \param path SVG path 539 * \see path() 540 */ 541 void setPath( const QString &path ); 542 543 /** 544 * Returns the default marker aspect ratio between width and height, 0 if not yet calculated. 545 * \see updateDefaultAspectRatio() 546 */ defaultAspectRatio()547 double defaultAspectRatio() const { return mDefaultAspectRatio; } 548 549 /** 550 * Calculates the default marker aspect ratio between width and height. 551 * \returns the default aspect ratio value 552 * \see defaultAspectRatio() 553 */ 554 double updateDefaultAspectRatio(); 555 556 /** 557 * Returns the preserved aspect ratio value, TRUE if fixed aspect ratio has been lower or equal to 0. 558 * \see setPreservedAspectRatio() 559 */ preservedAspectRatio()560 bool preservedAspectRatio() const { return mFixedAspectRatio <= 0.0; } 561 562 /** 563 * Set preserved the marker aspect ratio between width and height. 564 * \param par Preserved Aspect Ratio 565 * \returns the preserved aspect ratio value, TRUE if fixed aspect ratio has been lower or equal to 0 566 * \see preservedAspectRatio() 567 */ 568 bool setPreservedAspectRatio( bool par ); 569 570 /** 571 * Returns the marker aspect ratio between width and height to be used in rendering, 572 * if the value set is lower or equal to 0 the aspect ratio will be preserved in rendering 573 * \see setFixedAspectRatio() QgsSvgCache 574 */ fixedAspectRatio()575 double fixedAspectRatio() const { return mFixedAspectRatio; } 576 577 /** 578 * Set the marker aspect ratio between width and height to be used in rendering, 579 * if the value set is lower or equal to 0 the aspect ratio will be preserved in rendering 580 * \param ratio Fixed Aspect Ratio 581 * \see fixedAspectRatio() QgsSvgCache 582 */ setFixedAspectRatio(double ratio)583 void setFixedAspectRatio( double ratio ) { mFixedAspectRatio = ratio; } 584 fillColor()585 QColor fillColor() const override { return color(); } setFillColor(const QColor & color)586 void setFillColor( const QColor &color ) override { setColor( color ); } 587 strokeColor()588 QColor strokeColor() const override { return mStrokeColor; } setStrokeColor(const QColor & c)589 void setStrokeColor( const QColor &c ) override { mStrokeColor = c; } 590 strokeWidth()591 double strokeWidth() const { return mStrokeWidth; } setStrokeWidth(double w)592 void setStrokeWidth( double w ) { mStrokeWidth = w; } 593 594 /** 595 * Sets the units for the stroke width. 596 * \param unit width units 597 * \see strokeWidthUnit() 598 */ setStrokeWidthUnit(QgsUnitTypes::RenderUnit unit)599 void setStrokeWidthUnit( QgsUnitTypes::RenderUnit unit ) { mStrokeWidthUnit = unit; } 600 601 /** 602 * Returns the units for the stroke width. 603 * \see strokeWidthUnit() 604 */ strokeWidthUnit()605 QgsUnitTypes::RenderUnit strokeWidthUnit() const { return mStrokeWidthUnit; } 606 setStrokeWidthMapUnitScale(const QgsMapUnitScale & scale)607 void setStrokeWidthMapUnitScale( const QgsMapUnitScale &scale ) { mStrokeWidthMapUnitScale = scale; } strokeWidthMapUnitScale()608 const QgsMapUnitScale &strokeWidthMapUnitScale() const { return mStrokeWidthMapUnitScale; } 609 610 void setOutputUnit( QgsUnitTypes::RenderUnit unit ) override; 611 QgsUnitTypes::RenderUnit outputUnit() const override; 612 613 void setMapUnitScale( const QgsMapUnitScale &scale ) override; 614 QgsMapUnitScale mapUnitScale() const override; 615 616 bool writeDxf( QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, QgsSymbolRenderContext &context, QPointF shift = QPointF( 0.0, 0.0 ) ) const override; 617 618 QRectF bounds( QPointF point, QgsSymbolRenderContext &context ) override; 619 620 protected: 621 622 /** 623 * Calculates the marker aspect ratio between width and height. 624 * \param context symbol render context 625 * \param scaledSize size of symbol to render 626 * \param hasDataDefinedAspectRatio will be set to TRUE if marker has data defined aspectRatio 627 */ 628 double calculateAspectRatio( QgsSymbolRenderContext &context, double scaledSize, bool &hasDataDefinedAspectRatio ) const; 629 630 QString mPath; 631 632 //! The marker default aspect ratio 633 double mDefaultAspectRatio = 0.0; 634 //! The marker fixed aspect ratio 635 double mFixedAspectRatio = 0.0; 636 //param(fill), param(stroke), param(stroke-width) are going 637 //to be replaced in memory 638 bool mHasFillParam = false; 639 QColor mStrokeColor; 640 double mStrokeWidth; 641 642 QgsUnitTypes::RenderUnit mStrokeWidthUnit; 643 QgsMapUnitScale mStrokeWidthMapUnitScale; 644 645 private: 646 double calculateSize( QgsSymbolRenderContext &context, bool &hasDataDefinedSize ) const; 647 void calculateOffsetAndRotation( QgsSymbolRenderContext &context, double scaledWidth, double scaledHeight, QPointF &offset, double &angle ) const; 648 649 }; 650 651 652 ////////// 653 654 #define DEFAULT_RASTERMARKER_SIZE 2*DEFAULT_POINT_SIZE 655 #define DEFAULT_RASTERMARKER_ANGLE 0 656 657 /** 658 * \ingroup core 659 * \class QgsRasterMarkerSymbolLayer 660 * \brief Raster marker symbol layer class. 661 * \since QGIS 3.6 662 */ 663 class CORE_EXPORT QgsRasterMarkerSymbolLayer : public QgsMarkerSymbolLayer 664 { 665 public: 666 //! Constructs raster marker symbol layer with picture from given absolute path to a raster image file 667 QgsRasterMarkerSymbolLayer( const QString &path = QString(), 668 double size = DEFAULT_SVGMARKER_SIZE, 669 double angle = DEFAULT_SVGMARKER_ANGLE, 670 QgsSymbol::ScaleMethod scaleMethod = DEFAULT_SCALE_METHOD ); 671 672 // static stuff 673 674 /** 675 * Creates a raster marker symbol layer from a string map of properties. 676 * \param properties QgsStringMap properties object 677 */ 678 static QgsSymbolLayer *create( const QgsStringMap &properties = QgsStringMap() ) SIP_FACTORY; 679 680 /** 681 * Turns relative paths in properties map to absolute when reading and vice versa when writing. 682 * Used internally when reading/writing symbols. 683 * \since QGIS 3.0 684 */ 685 static void resolvePaths( QgsStringMap &properties, const QgsPathResolver &pathResolver, bool saving ); 686 687 // implemented from base classes 688 689 QString layerType() const override; 690 691 void renderPoint( QPointF point, QgsSymbolRenderContext &context ) override; 692 693 QgsStringMap properties() const override; 694 695 QgsRasterMarkerSymbolLayer *clone() const override SIP_FACTORY; 696 bool usesMapUnits() const override; 697 698 /** 699 * Calculates the marker aspect ratio between width and height. 700 * \param context symbol render context 701 * \param scaledSize size of symbol to render 702 * \param hasDataDefinedAspectRatio will be set to TRUE if marker has data defined aspectRatio 703 */ 704 double calculateAspectRatio( QgsSymbolRenderContext &context, double scaledSize, bool &hasDataDefinedAspectRatio ) const; 705 706 /** 707 * Returns the marker raster image path. 708 * \see setPath() 709 */ path()710 QString path() const { return mPath; } 711 712 /** 713 * Set the marker raster image path. 714 * \param path raster image path 715 * \see path() 716 */ 717 void setPath( const QString &path ); 718 719 /** 720 * Returns the marker opacity. 721 * \returns opacity value between 0 (fully transparent) and 1 (fully opaque) 722 * \see setOpacity() 723 */ opacity()724 double opacity() const { return mOpacity; } 725 726 /** 727 * Set the marker opacity. 728 * \param opacity opacity value between 0 (fully transparent) and 1 (fully opaque) 729 * \see opacity() 730 */ setOpacity(double opacity)731 void setOpacity( double opacity ) { mOpacity = opacity; } 732 733 /** 734 * Returns the default marker aspect ratio between width and height, 0 if not yet calculated. 735 * \see updateDefaultAspectRatio() 736 */ defaultAspectRatio()737 double defaultAspectRatio() const { return mDefaultAspectRatio; } 738 739 /** 740 * Calculates the default marker aspect ratio between width and height. 741 * \returns the default aspect ratio value 742 * \see defaultAspectRatio() 743 */ 744 double updateDefaultAspectRatio(); 745 746 /** 747 * Returns the preserved aspect ratio value, TRUE if fixed aspect ratio has been lower or equal to 0. 748 * \see setPreservedAspectRatio() 749 */ preservedAspectRatio()750 bool preservedAspectRatio() const { return mFixedAspectRatio <= 0.0; } 751 752 /** 753 * Set preserved the marker aspect ratio between width and height. 754 * \param par Preserved Aspect Ratio 755 * \returns the preserved aspect ratio value, TRUE if fixed aspect ratio has been lower or equal to 0 756 * \see preservedAspectRatio() 757 */ 758 bool setPreservedAspectRatio( bool par ); 759 760 /** 761 * Returns the marker aspect ratio between width and height to be used in rendering, 762 * if the value set is lower or equal to 0 the aspect ratio will be preserved in rendering 763 * \see setFixedAspectRatio() QgsSvgCache 764 */ fixedAspectRatio()765 double fixedAspectRatio() const { return mFixedAspectRatio; } 766 767 /** 768 * Set the marker aspect ratio between width and height to be used in rendering, 769 * if the value set is lower or equal to 0 the aspect ratio will be preserved in rendering 770 * \param ratio Fixed Aspect Ratio 771 * \see fixedAspectRatio() QgsSvgCache 772 */ setFixedAspectRatio(double ratio)773 void setFixedAspectRatio( double ratio ) { mFixedAspectRatio = ratio; } 774 775 void setMapUnitScale( const QgsMapUnitScale &scale ) override; 776 QgsMapUnitScale mapUnitScale() const override; 777 778 QRectF bounds( QPointF point, QgsSymbolRenderContext &context ) override; 779 780 protected: 781 782 QString mPath; 783 //! The marker default opacity 784 double mOpacity = 1.0; 785 //! The marker default aspect ratio 786 double mDefaultAspectRatio = 0.0; 787 //! The marker fixed aspect ratio 788 double mFixedAspectRatio = 0.0; 789 790 private: 791 double calculateSize( QgsSymbolRenderContext &context, bool &hasDataDefinedSize ) const; 792 void calculateOffsetAndRotation( QgsSymbolRenderContext &context, double scaledWidth, double scaledHeight, QPointF &offset, double &angle ) const; 793 794 }; 795 796 797 ////////// 798 799 #define POINT2MM(x) ( (x) * 25.4 / 72 ) // point is 1/72 of inch 800 #define MM2POINT(x) ( (x) * 72 / 25.4 ) 801 802 #define DEFAULT_FONTMARKER_FONT "Dingbats" 803 #define DEFAULT_FONTMARKER_CHR QChar('A') 804 #define DEFAULT_FONTMARKER_SIZE POINT2MM(12) 805 #define DEFAULT_FONTMARKER_COLOR QColor( 35, 35, 35 ) 806 #define DEFAULT_FONTMARKER_BORDERCOLOR QColor(Qt::white) 807 #define DEFAULT_FONTMARKER_JOINSTYLE Qt::MiterJoin 808 #define DEFAULT_FONTMARKER_ANGLE 0 809 810 /** 811 * \ingroup core 812 * \class QgsFontMarkerSymbolLayer 813 */ 814 class CORE_EXPORT QgsFontMarkerSymbolLayer : public QgsMarkerSymbolLayer 815 { 816 public: 817 818 //! Constructs a font marker symbol layer. 819 QgsFontMarkerSymbolLayer( const QString &fontFamily = DEFAULT_FONTMARKER_FONT, 820 QString chr = DEFAULT_FONTMARKER_CHR, 821 double pointSize = DEFAULT_FONTMARKER_SIZE, 822 const QColor &color = DEFAULT_FONTMARKER_COLOR, 823 double angle = DEFAULT_FONTMARKER_ANGLE ); 824 825 // static stuff 826 827 /** 828 * Creates a new QgsFontMarkerSymbolLayer from a property map (see properties()) 829 */ 830 static QgsSymbolLayer *create( const QgsStringMap &properties = QgsStringMap() ) SIP_FACTORY; 831 832 /** 833 * Creates a new QgsFontMarkerSymbolLayer from an SLD XML \a element. 834 */ 835 static QgsSymbolLayer *createFromSld( QDomElement &element ) SIP_FACTORY; 836 837 // implemented from base classes 838 839 QString layerType() const override; 840 841 void startRender( QgsSymbolRenderContext &context ) override; 842 843 void stopRender( QgsSymbolRenderContext &context ) override; 844 845 void renderPoint( QPointF point, QgsSymbolRenderContext &context ) override; 846 847 QgsStringMap properties() const override; 848 849 QgsFontMarkerSymbolLayer *clone() const override SIP_FACTORY; 850 851 void writeSldMarker( QDomDocument &doc, QDomElement &element, const QgsStringMap &props ) const override; 852 bool usesMapUnits() const override; 853 854 // new methods 855 856 /** 857 * Returns the font family name for the associated font which will be used to render the point. 858 * 859 * \see setFontFamily() 860 */ fontFamily()861 QString fontFamily() const { return mFontFamily; } 862 863 /** 864 * Sets the font \a family for the font which will be used to render the point. 865 * 866 * \see fontFamily() 867 */ setFontFamily(const QString & family)868 void setFontFamily( const QString &family ) { mFontFamily = family; } 869 870 /** 871 * Returns the font style for the associated font which will be used to render the point. 872 * 873 * \see setFontStyle() 874 * \since QGIS 3.14 875 */ fontStyle()876 QString fontStyle() const { return mFontStyle; } 877 878 /** 879 * Sets the font \a style for the font which will be used to render the point. 880 * 881 * \see fontStyle() 882 * \since QGIS 3.14 883 */ setFontStyle(const QString & style)884 void setFontStyle( const QString &style ) { mFontStyle = style; } 885 886 /** 887 * Returns the character(s) used when rendering points. 888 * 889 * \see setCharacter() 890 */ character()891 QString character() const { return mString; } 892 893 /** 894 * Sets the character(s) used when rendering points. 895 * 896 * \see character() 897 */ setCharacter(QString chr)898 void setCharacter( QString chr ) { mString = chr; } 899 strokeColor()900 QColor strokeColor() const override { return mStrokeColor; } setStrokeColor(const QColor & color)901 void setStrokeColor( const QColor &color ) override { mStrokeColor = color; } 902 903 /** 904 * Returns the marker's stroke width. Units are retrieved by strokeWidthUnit() 905 * 906 * \see setStrokeWidth() 907 * \see strokeWidthUnit() 908 * \see strokeWidthMapUnitScale() 909 * 910 * \since QGIS 2.16 911 */ strokeWidth()912 double strokeWidth() const { return mStrokeWidth; } 913 914 /** 915 * Set's the marker's stroke \a width. Units are set by setStrokeWidthUnit(). 916 * 917 * \see strokeWidth() 918 * \see setStrokeWidthUnit() 919 * \see setStrokeWidthMapUnitScale() 920 * 921 * \since QGIS 2.16 922 */ setStrokeWidth(double width)923 void setStrokeWidth( double width ) { mStrokeWidth = width; } 924 925 /** 926 * Returns the stroke width unit. 927 * 928 * \see setStrokeWidthUnit() 929 * \see strokeWidth() 930 * \see strokeWidthMapUnitScale() 931 * 932 * \since QGIS 2.16 933 */ strokeWidthUnit()934 QgsUnitTypes::RenderUnit strokeWidthUnit() const { return mStrokeWidthUnit; } 935 936 /** 937 * Sets the stroke width \a unit. 938 * 939 * \see strokeWidthUnit() 940 * \see setStrokeWidth() 941 * \see setStrokeWidthMapUnitScale() 942 * \since QGIS 2.16 943 */ setStrokeWidthUnit(QgsUnitTypes::RenderUnit unit)944 void setStrokeWidthUnit( QgsUnitTypes::RenderUnit unit ) { mStrokeWidthUnit = unit; } 945 946 /** 947 * Returns the stroke width map unit scale. 948 * 949 * \see setStrokeWidthMapUnitScale() 950 * \see strokeWidth() 951 * \see strokeWidthUnit() 952 * 953 * \since QGIS 2.16 954 */ strokeWidthMapUnitScale()955 const QgsMapUnitScale &strokeWidthMapUnitScale() const { return mStrokeWidthMapUnitScale; } 956 957 /** 958 * Sets the stroke width map unit \a scale. 959 * 960 * \see strokeWidthMapUnitScale() 961 * \see setStrokeWidth() 962 * \see setStrokeWidthUnit() 963 * 964 * \since QGIS 2.16 965 */ setStrokeWidthMapUnitScale(const QgsMapUnitScale & scale)966 void setStrokeWidthMapUnitScale( const QgsMapUnitScale &scale ) { mStrokeWidthMapUnitScale = scale; } 967 968 /** 969 * Returns the stroke join style. 970 * 971 * \see setPenJoinStyle() 972 * 973 * \since QGIS 2.16 974 */ penJoinStyle()975 Qt::PenJoinStyle penJoinStyle() const { return mPenJoinStyle; } 976 977 /** 978 * Sets the stroke join \a style. 979 * 980 * \see penJoinStyle() 981 * 982 * \since QGIS 2.16 983 */ setPenJoinStyle(Qt::PenJoinStyle style)984 void setPenJoinStyle( Qt::PenJoinStyle style ) { mPenJoinStyle = style; } 985 986 QRectF bounds( QPointF point, QgsSymbolRenderContext &context ) override; 987 988 private: 989 990 QString mFontFamily; 991 QString mFontStyle; 992 QFont mFont; 993 std::unique_ptr< QFontMetrics >mFontMetrics; 994 995 QString mString; 996 997 double mChrWidth = 0; 998 QPointF mChrOffset; 999 //! Scaling for font sizes, used if font size grows too large 1000 double mFontSizeScale = 1.0; 1001 double mOrigSize; 1002 1003 QColor mStrokeColor; 1004 double mStrokeWidth; 1005 QgsUnitTypes::RenderUnit mStrokeWidthUnit; 1006 QgsMapUnitScale mStrokeWidthMapUnitScale; 1007 Qt::PenJoinStyle mPenJoinStyle; 1008 1009 QPen mPen; 1010 QBrush mBrush; 1011 1012 bool mUseCachedPath = false; 1013 QPainterPath mCachedPath; 1014 1015 // If font has a zero (or nearly zero) size, we skip rendering altogether.. 1016 bool mNonZeroFontSize = true; 1017 1018 QString characterToRender( QgsSymbolRenderContext &context, QPointF &charOffset, double &charWidth ); 1019 void calculateOffsetAndRotation( QgsSymbolRenderContext &context, double scaledSize, bool &hasDataDefinedRotation, QPointF &offset, double &angle ) const; 1020 double calculateSize( QgsSymbolRenderContext &context ); 1021 }; 1022 1023 // clazy:excludeall=qstring-allocations 1024 1025 #endif 1026 1027 1028