1 /*************************************************************************** 2 qgssymbollayer.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 #ifndef QGSSYMBOLLAYER_H 16 #define QGSSYMBOLLAYER_H 17 18 #define DEG2RAD(x) ((x)*M_PI/180) 19 #define DEFAULT_SCALE_METHOD Qgis::ScaleMethod::ScaleDiameter 20 21 #include "qgis_core.h" 22 #include "qgis.h" 23 #include "qgsfields.h" 24 #include "qgspropertycollection.h" 25 #include "qgssymbolrendercontext.h" 26 27 #include <QColor> 28 #include <QMap> 29 #include <QPointF> 30 #include <QSet> 31 #include <QDomDocument> 32 #include <QDomElement> 33 #include <QPainterPath> 34 35 class QPainter; 36 class QSize; 37 class QPolygonF; 38 39 class QgsDxfExport; 40 class QgsExpression; 41 class QgsRenderContext; 42 class QgsPaintEffect; 43 class QgsSymbolLayerReference; 44 45 #ifndef SIP_RUN 46 typedef QMap<QString, QString> QgsStringMap; 47 #endif 48 49 /** 50 * \ingroup core 51 * \class QgsSymbolLayer 52 */ 53 class CORE_EXPORT QgsSymbolLayer 54 { 55 #ifdef SIP_RUN 56 #include <qgslinesymbollayer.h> 57 #endif 58 59 60 #ifdef SIP_RUN 61 SIP_CONVERT_TO_SUBCLASS_CODE 62 switch ( sipCpp->type() ) 63 { 64 case Qgis::SymbolType::Marker: 65 if ( sipCpp->layerType() == "EllipseMarker" ) 66 sipType = sipType_QgsEllipseSymbolLayer; 67 else if ( sipCpp->layerType() == "FontMarker" ) 68 sipType = sipType_QgsFontMarkerSymbolLayer; 69 else if ( sipCpp->layerType() == "SimpleMarker" ) 70 sipType = sipType_QgsSimpleMarkerSymbolLayer; 71 else if ( sipCpp->layerType() == "FilledMarker" ) 72 sipType = sipType_QgsFilledMarkerSymbolLayer; 73 else if ( sipCpp->layerType() == "SvgMarker" ) 74 sipType = sipType_QgsSvgMarkerSymbolLayer; 75 else if ( sipCpp->layerType() == "RasterMarker" ) 76 sipType = sipType_QgsRasterMarkerSymbolLayer; 77 else if ( sipCpp->layerType() == "VectorField" ) 78 sipType = sipType_QgsVectorFieldSymbolLayer; 79 else if ( sipCpp->layerType() == "MaskMarker" ) 80 sipType = sipType_QgsMaskMarkerSymbolLayer; 81 else 82 sipType = sipType_QgsMarkerSymbolLayer; 83 break; 84 85 case Qgis::SymbolType::Line: 86 if ( sipCpp->layerType() == "MarkerLine" ) 87 sipType = sipType_QgsMarkerLineSymbolLayer; 88 else if ( sipCpp->layerType() == "SimpleLine" ) 89 sipType = sipType_QgsSimpleLineSymbolLayer; 90 else if ( sipCpp->layerType() == "HashLine" ) 91 sipType = sipType_QgsHashedLineSymbolLayer; 92 else if ( sipCpp->layerType() == "ArrowLine" ) 93 sipType = sipType_QgsArrowSymbolLayer; 94 else if ( sipCpp->layerType() == "InterpolatedLine" ) 95 sipType = sipType_QgsInterpolatedLineSymbolLayer; 96 else 97 sipType = sipType_QgsLineSymbolLayer; 98 break; 99 100 case Qgis::SymbolType::Fill: 101 if ( sipCpp->layerType() == "SimpleFill" ) 102 sipType = sipType_QgsSimpleFillSymbolLayer; 103 else if ( sipCpp->layerType() == "LinePatternFill" ) 104 sipType = sipType_QgsLinePatternFillSymbolLayer; 105 else if ( sipCpp->layerType() == "PointPatternFill" ) 106 sipType = sipType_QgsPointPatternFillSymbolLayer; 107 else if ( sipCpp->layerType() == "SVGFill" ) 108 sipType = sipType_QgsSVGFillSymbolLayer; 109 else if ( sipCpp->layerType() == "RasterFill" ) 110 sipType = sipType_QgsRasterFillSymbolLayer; 111 else if ( sipCpp->layerType() == "CentroidFill" ) 112 sipType = sipType_QgsCentroidFillSymbolLayer; 113 else if ( sipCpp->layerType() == "GradientFill" ) 114 sipType = sipType_QgsGradientFillSymbolLayer; 115 else if ( sipCpp->layerType() == "ShapeburstFill" ) 116 sipType = sipType_QgsShapeburstFillSymbolLayer; 117 else if ( sipCpp->layerType() == "RandomMarkerFill" ) 118 sipType = sipType_QgsRandomMarkerFillSymbolLayer; 119 else 120 sipType = sipType_QgsFillSymbolLayer; 121 break; 122 123 case Qgis::SymbolType::Hybrid: 124 sipType = sipType_QgsGeometryGeneratorSymbolLayer; 125 break; 126 } 127 SIP_END 128 #endif 129 public: 130 131 /** 132 * Data definable properties. 133 * \since QGIS 3.0 134 */ 135 enum Property 136 { 137 PropertySize = 0, //!< Symbol size 138 PropertyAngle, //!< Symbol angle 139 PropertyName, //!< Name, eg shape name for simple markers 140 PropertyFillColor, //!< Fill color 141 PropertyStrokeColor, //!< Stroke color 142 PropertyStrokeWidth, //!< Stroke width 143 PropertyStrokeStyle, //!< Stroke style (eg solid, dashed) 144 PropertyOffset, //!< Symbol offset 145 PropertyCharacter, //!< Character, eg for font marker symbol layers 146 PropertyWidth, //!< Symbol width 147 PropertyHeight, //!< Symbol height 148 PropertyPreserveAspectRatio, //!< Preserve aspect ratio between width and height 149 PropertyFillStyle, //!< Fill style (eg solid, dots) 150 PropertyJoinStyle, //!< Line join style 151 PropertySecondaryColor, //!< Secondary color (eg for gradient fills) 152 PropertyLineAngle, //!< Line angle, or angle of hash lines for hash line symbols 153 PropertyLineDistance, //!< Distance between lines, or length of lines for hash line symbols 154 PropertyGradientType, //!< Gradient fill type 155 PropertyCoordinateMode, //!< Gradient coordinate mode 156 PropertyGradientSpread, //!< Gradient spread mode 157 PropertyGradientReference1X, //!< Gradient reference point 1 x 158 PropertyGradientReference1Y, //!< Gradient reference point 1 y 159 PropertyGradientReference2X, //!< Gradient reference point 2 x 160 PropertyGradientReference2Y, //!< Gradient reference point 2 y 161 PropertyGradientReference1IsCentroid, //!< Gradient reference point 1 is centroid 162 PropertyGradientReference2IsCentroid, //!< Gradient reference point 2 is centroid 163 PropertyBlurRadius, //!< Shapeburst blur radius 164 PropertyShapeburstUseWholeShape, //!< Shapeburst use whole shape 165 PropertyShapeburstMaxDistance, //!< Shapeburst fill from edge distance 166 PropertyShapeburstIgnoreRings, //!< Shapeburst ignore rings 167 PropertyFile, //!< Filename, eg for svg files 168 PropertyDistanceX, //!< Horizontal distance between points 169 PropertyDistanceY, //!< Vertical distance between points 170 PropertyDisplacementX, //!< Horizontal displacement 171 PropertyDisplacementY, //!< Vertical displacement 172 PropertyOpacity, //!< Opacity 173 PropertyCustomDash, //!< Custom dash pattern 174 PropertyCapStyle, //!< Line cap style 175 PropertyPlacement, //!< Line marker placement 176 PropertyInterval, //!< Line marker interval 177 PropertyOffsetAlongLine, //!< Offset along line 178 PropertyAverageAngleLength, //!< Length to average symbol angles over 179 PropertyHorizontalAnchor, //!< Horizontal anchor point 180 PropertyVerticalAnchor, //!< Vertical anchor point 181 PropertyLayerEnabled, //!< Whether symbol layer is enabled 182 PropertyArrowWidth, //!< Arrow tail width 183 PropertyArrowStartWidth, //!< Arrow tail start width 184 PropertyArrowHeadLength, //!< Arrow head length 185 PropertyArrowHeadThickness, //!< Arrow head thickness 186 PropertyArrowHeadType, //!< Arrow head type 187 PropertyArrowType, //!< Arrow type 188 PropertyOffsetX, //!< Horizontal offset 189 PropertyOffsetY, //!< Vertical offset 190 PropertyPointCount, //!< Point count 191 PropertyRandomSeed, //!< Random number seed 192 PropertyClipPoints, //!< Whether markers should be clipped to polygon boundaries 193 PropertyDensityArea, //!< Density area 194 PropertyFontFamily, //!< Font family 195 PropertyFontStyle, //!< Font style 196 PropertyDashPatternOffset, //!< Dash pattern offset, 197 PropertyTrimStart, //!< Trim distance from start of line (since QGIS 3.20) 198 PropertyTrimEnd, //!< Trim distance from end of line (since QGIS 3.20) 199 PropertyLineStartWidthValue, //!< Start line width for interpolated line renderer (since QGIS 3.22) 200 PropertyLineEndWidthValue, //!< End line width for interpolated line renderer (since QGIS 3.22) 201 PropertyLineStartColorValue, //!< Start line color for interpolated line renderer (since QGIS 3.22) 202 PropertyLineEndColorValue, //!< End line color for interpolated line renderer (since QGIS 3.22) 203 }; 204 205 /** 206 * Returns the symbol layer property definitions. 207 * \since QGIS 3.0 208 */ 209 static const QgsPropertiesDefinition &propertyDefinitions(); 210 211 virtual ~QgsSymbolLayer(); 212 213 //! QgsSymbolLayer cannot be copied 214 QgsSymbolLayer( const QgsSymbolLayer &other ) = delete; 215 216 //! QgsSymbolLayer cannot be copied 217 QgsSymbolLayer &operator=( const QgsSymbolLayer &other ) = delete; 218 219 /** 220 * Returns flags which control the symbol layer's behavior. 221 * 222 * \since QGIS 3.22 223 */ 224 virtual Qgis::SymbolLayerFlags flags() const; 225 226 /** 227 * Returns TRUE if symbol layer is enabled and will be drawn. 228 * \see setEnabled() 229 * \since QGIS 3.0 230 */ enabled()231 bool enabled() const { return mEnabled; } 232 233 /** 234 * Sets whether symbol layer is enabled and should be drawn. Disabled 235 * layers are not drawn, but remain part of the symbol and can be re-enabled 236 * when desired. 237 * \see enabled() 238 * \since QGIS 3.0 239 */ setEnabled(bool enabled)240 void setEnabled( bool enabled ) { mEnabled = enabled; } 241 242 /** 243 * The fill color. 244 */ color()245 virtual QColor color() const { return mColor; } 246 247 /** 248 * The fill color. 249 */ setColor(const QColor & color)250 virtual void setColor( const QColor &color ) { mColor = color; } 251 252 /** 253 * Set stroke color. Supported by marker and fill layers. 254 * \since QGIS 2.1 255 */ setStrokeColor(const QColor & color)256 virtual void setStrokeColor( const QColor &color ) { Q_UNUSED( color ) } 257 258 /** 259 * Gets stroke color. Supported by marker and fill layers. 260 * \since QGIS 2.1 261 */ strokeColor()262 virtual QColor strokeColor() const { return QColor(); } 263 264 /** 265 * Set fill color. Supported by marker and fill layers. 266 * \since QGIS 2.1 267 */ setFillColor(const QColor & color)268 virtual void setFillColor( const QColor &color ) { Q_UNUSED( color ) } 269 270 /** 271 * Gets fill color. Supported by marker and fill layers. 272 * \since QGIS 2.1 273 */ fillColor()274 virtual QColor fillColor() const { return QColor(); } 275 276 /** 277 * Returns a string that represents this layer type. Used for serialization. 278 * Should match with the string used to register this symbol layer in the registry. 279 */ 280 virtual QString layerType() const = 0; 281 282 /** 283 * Called before a set of rendering operations commences on the supplied render \a context. 284 * 285 * This is always followed by a call to stopRender() after all rendering operations 286 * have been completed. 287 * 288 * Subclasses can use this method to prepare for a set of rendering operations, e.g. by 289 * pre-evaluating paths or images to render, and performing other one-time optimisations. 290 * 291 * \see startFeatureRender() 292 * \see stopRender() 293 */ 294 virtual void startRender( QgsSymbolRenderContext &context ) = 0; 295 296 /** 297 * Called after a set of rendering operations has finished on the supplied render \a context. 298 * 299 * This is always preceded by a call to startRender() before all rendering operations 300 * are commenced. 301 * 302 * Subclasses can use this method to cleanup after a set of rendering operations. 303 * 304 * \see startRender() 305 * \see stopFeatureRender() 306 */ 307 virtual void stopRender( QgsSymbolRenderContext &context ) = 0; 308 309 /** 310 * Called before the layer will be rendered for a particular \a feature. 311 * 312 * This is always followed by a call to stopFeatureRender() after the feature 313 * has been completely rendered (i.e. all parts have been rendered). 314 * 315 * The default implementation does nothing. 316 * 317 * \note In some circumstances, startFeatureRender() and stopFeatureRender() may not be called 318 * before a symbol layer is rendered. E.g., when a symbol layer is being rendered in isolation 319 * and not as a result of rendering a feature (for instance, when rendering a legend patch or other 320 * non-feature based shape). 321 * 322 * \see stopFeatureRender() 323 * \see startRender() 324 * 325 * \since QGIS 3.12 326 */ 327 virtual void startFeatureRender( const QgsFeature &feature, QgsRenderContext &context ); 328 329 /** 330 * Called after the layer has been rendered for a particular \a feature. 331 * 332 * This is always preceded by a call to startFeatureRender() just before the feature 333 * will be rendered. 334 * 335 * The default implementation does nothing. 336 * 337 * \note In some circumstances, startFeatureRender() and stopFeatureRender() may not be called 338 * before a symbol layer is rendered. E.g., when a symbol layer is being rendered in isolation 339 * and not as a result of rendering a feature (for instance, when rendering a legend patch or other 340 * non-feature based shape). 341 * 342 * \see startFeatureRender() 343 * \see stopRender() 344 * 345 * \since QGIS 3.12 346 */ 347 virtual void stopFeatureRender( const QgsFeature &feature, QgsRenderContext &context ); 348 349 /** 350 * Shall be reimplemented by subclasses to create a deep copy of the instance. 351 */ 352 virtual QgsSymbolLayer *clone() const = 0 SIP_FACTORY; 353 354 //! Saves the symbol layer as SLD toSld(QDomDocument & doc,QDomElement & element,const QVariantMap & props)355 virtual void toSld( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const 356 { Q_UNUSED( props ) element.appendChild( doc.createComment( QStringLiteral( "SymbolLayerV2 %1 not implemented yet" ).arg( layerType() ) ) ); } 357 ogrFeatureStyle(double mmScaleFactor,double mapUnitScaleFactor)358 virtual QString ogrFeatureStyle( double mmScaleFactor, double mapUnitScaleFactor ) const { Q_UNUSED( mmScaleFactor ) Q_UNUSED( mapUnitScaleFactor ); return QString(); } 359 360 /** 361 * Should be reimplemented by subclasses to return a string map that 362 * contains the configuration information for the symbol layer. This 363 * is used to serialize a symbol layer perstistently. 364 */ 365 virtual QVariantMap properties() const = 0; 366 367 virtual void drawPreviewIcon( QgsSymbolRenderContext &context, QSize size ) = 0; 368 369 /** 370 * Returns the symbol's sub symbol, if present. 371 */ 372 virtual QgsSymbol *subSymbol(); 373 374 //! Sets layer's subsymbol. takes ownership of the passed symbol 375 virtual bool setSubSymbol( QgsSymbol *symbol SIP_TRANSFER ); 376 type()377 Qgis::SymbolType type() const { return mType; } 378 379 //! Returns if the layer can be used below the specified symbol 380 virtual bool isCompatibleWithSymbol( QgsSymbol *symbol ) const; 381 382 /** 383 * Returns TRUE if the symbol layer rendering can cause visible artifacts across a single feature 384 * when the feature is rendered as a series of adjacent map tiles each containing a portion of the feature's geometry. 385 * 386 * The default implementation returns FALSE. 387 * 388 * \since QGIS 3.18 389 */ 390 virtual bool canCauseArtifactsBetweenAdjacentTiles() const; 391 392 /** 393 * Sets whether the layer's colors are locked. 394 * 395 * If \a locked is TRUE then the symbol layer colors are locked and the layer will ignore any symbol-level color changes. 396 * 397 * \see isLocked() 398 */ setLocked(bool locked)399 void setLocked( bool locked ) { mLocked = locked; } 400 401 /** 402 * Returns TRUE if the symbol layer colors are locked and the layer will ignore any symbol-level color changes. 403 * 404 * \see setLocked() 405 */ isLocked()406 bool isLocked() const { return mLocked; } 407 408 /** 409 * Returns the estimated maximum distance which the layer style will bleed outside 410 * the drawn shape when drawn in the specified /a context. For example, polygons 411 * drawn with an stroke will draw half the width 412 * of the stroke outside of the polygon. This amount is estimated, since it may 413 * be affected by data defined symbology rules. 414 */ estimateMaxBleed(const QgsRenderContext & context)415 virtual double estimateMaxBleed( const QgsRenderContext &context ) const { Q_UNUSED( context ) return 0; } 416 417 /** 418 * Sets the units to use for sizes and widths within the symbol layer. Individual 419 * symbol layer subclasses will interpret this in different ways, e.g., a marker symbol 420 * layer may use it to specify the units for the marker size, while a line symbol 421 * layer may use it to specify the units for the line width. 422 * \param unit output units 423 * \see outputUnit() 424 */ setOutputUnit(QgsUnitTypes::RenderUnit unit)425 virtual void setOutputUnit( QgsUnitTypes::RenderUnit unit ) { Q_UNUSED( unit ) } 426 427 /** 428 * Returns the units to use for sizes and widths within the symbol layer. Individual 429 * symbol layer subclasses will interpret this in different ways, e.g., a marker symbol 430 * layer may use it to specify the units for the marker size, while a line symbol 431 * layer may use it to specify the units for the line width. 432 * \returns output unit, or QgsUnitTypes::RenderUnknownUnit if the symbol layer contains mixed units 433 * \see setOutputUnit() 434 */ outputUnit()435 virtual QgsUnitTypes::RenderUnit outputUnit() const { return QgsUnitTypes::RenderUnknownUnit; } 436 437 /** 438 * Returns TRUE if the symbol layer has any components which use map unit based sizes. 439 * 440 * \since QGIS 3.18 441 */ 442 virtual bool usesMapUnits() const; 443 setMapUnitScale(const QgsMapUnitScale & scale)444 virtual void setMapUnitScale( const QgsMapUnitScale &scale ) { Q_UNUSED( scale ) } mapUnitScale()445 virtual QgsMapUnitScale mapUnitScale() const { return QgsMapUnitScale(); } 446 447 /** 448 * Specifies the rendering pass in which this symbol layer should be rendered. 449 * The lower the number, the lower the symbol will be rendered. 450 * 0: first pass, 1: second pass, ... 451 * Defaults to 0 452 */ 453 void setRenderingPass( int renderingPass ); 454 455 /** 456 * Specifies the rendering pass in which this symbol layer should be rendered. 457 * The lower the number, the lower the symbol will be rendered. 458 * 0: first pass, 1: second pass, ... 459 * Defaults to 0 460 */ 461 int renderingPass() const; 462 463 /** 464 * Returns the set of attributes referenced by the layer. This includes attributes 465 * required by any data defined properties associated with the layer. 466 */ 467 virtual QSet<QString> usedAttributes( const QgsRenderContext &context ) const; 468 469 /** 470 * Sets a data defined property for the layer. Any existing property with the same key 471 * will be overwritten. 472 * \see dataDefinedProperties() 473 * \see Property 474 * \since QGIS 3.0 475 */ 476 virtual void setDataDefinedProperty( Property key, const QgsProperty &property ); 477 478 //! write as DXF 479 virtual bool writeDxf( QgsDxfExport &e, double mmMapUnitScaleFactor, const QString &layerName, QgsSymbolRenderContext &context, QPointF shift = QPointF( 0.0, 0.0 ) ) const; 480 481 //! Gets line width 482 virtual double dxfWidth( const QgsDxfExport &e, QgsSymbolRenderContext &context ) const; 483 484 //! Gets offset 485 virtual double dxfOffset( const QgsDxfExport &e, QgsSymbolRenderContext &context ) const; 486 487 //! Gets color 488 virtual QColor dxfColor( QgsSymbolRenderContext &context ) const; 489 490 //! Gets angle 491 virtual double dxfAngle( QgsSymbolRenderContext &context ) const; 492 493 //! Gets dash pattern 494 virtual QVector<qreal> dxfCustomDashPattern( QgsUnitTypes::RenderUnit &unit ) const; 495 496 //! Gets pen style 497 virtual Qt::PenStyle dxfPenStyle() const; 498 499 //! Gets brush/fill color 500 virtual QColor dxfBrushColor( QgsSymbolRenderContext &context ) const; 501 502 //! Gets brush/fill style 503 virtual Qt::BrushStyle dxfBrushStyle() const; 504 505 /** 506 * Returns the current paint effect for the layer. 507 * \returns paint effect 508 * \see setPaintEffect 509 * \since QGIS 2.9 510 */ 511 QgsPaintEffect *paintEffect() const; 512 513 /** 514 * Sets the current paint effect for the layer. 515 * \param effect paint effect. Ownership is transferred to the layer. 516 * \see paintEffect 517 * \since QGIS 2.9 518 */ 519 void setPaintEffect( QgsPaintEffect *effect SIP_TRANSFER ); 520 521 /** 522 * Prepares all data defined property expressions for evaluation. This should 523 * be called prior to evaluating data defined properties. 524 * \param context symbol render context 525 * \since QGIS 2.12 526 */ 527 virtual void prepareExpressions( const QgsSymbolRenderContext &context ); 528 529 /** 530 * Returns a reference to the symbol layer's property collection, used for data defined overrides. 531 * \see setDataDefinedProperties() 532 * \see Property 533 * \since QGIS 3.0 534 */ dataDefinedProperties()535 QgsPropertyCollection &dataDefinedProperties() { return mDataDefinedProperties; } 536 537 /** 538 * Returns a reference to the symbol layer's property collection, used for data defined overrides. 539 * \see setDataDefinedProperties() 540 * \since QGIS 3.0 541 */ dataDefinedProperties()542 const QgsPropertyCollection &dataDefinedProperties() const { return mDataDefinedProperties; } SIP_SKIP 543 544 /** 545 * Sets the symbol layer's property collection, used for data defined overrides. 546 * \param collection property collection. Existing properties will be replaced. 547 * \see dataDefinedProperties() 548 * \since QGIS 3.0 549 */ setDataDefinedProperties(const QgsPropertyCollection & collection)550 void setDataDefinedProperties( const QgsPropertyCollection &collection ) { mDataDefinedProperties = collection; } 551 552 /** 553 * Returns TRUE if the symbol layer (or any of its sub-symbols) contains data defined properties. 554 * 555 * \since QGIS 3.4.5 556 */ 557 virtual bool hasDataDefinedProperties() const; 558 559 /** 560 * Returns masks defined by this symbol layer. 561 * This is a list of symbol layers of other layers that should be occluded. 562 * \since QGIS 3.12 563 */ 564 virtual QList<QgsSymbolLayerReference> masks() const; 565 566 protected: 567 568 /** 569 * Constructor for QgsSymbolLayer. 570 * \param type specifies the associated symbol type 571 * \param locked if TRUE, then symbol layer colors will be locked and will ignore any symbol-level color changes. 572 */ 573 QgsSymbolLayer( Qgis::SymbolType type, bool locked = false ); 574 575 Qgis::SymbolType mType; 576 577 //! True if layer is enabled and should be drawn 578 bool mEnabled = true; 579 580 bool mLocked = false; 581 QColor mColor; 582 int mRenderingPass = 0; 583 584 QgsPropertyCollection mDataDefinedProperties; 585 586 std::unique_ptr< QgsPaintEffect > mPaintEffect; 587 QgsFields mFields; 588 589 // Configuration of selected symbology implementation 590 //! Whether styles for selected features ignore symbol alpha 591 static const bool SELECTION_IS_OPAQUE = true; 592 //! Whether fill styles for selected features also highlight symbol stroke 593 static const bool SELECT_FILL_BORDER = false; 594 //! Whether fill styles for selected features uses symbol layer style 595 static const bool SELECT_FILL_STYLE = false; 596 597 /** 598 * Restores older data defined properties from string map. 599 * \since QGIS 3.0 600 */ 601 void restoreOldDataDefinedProperties( const QVariantMap &stringMap ); 602 603 /** 604 * Copies all data defined properties of this layer to another symbol layer. 605 * \param destLayer destination layer 606 */ 607 void copyDataDefinedProperties( QgsSymbolLayer *destLayer ) const; 608 609 /** 610 * Copies paint effect of this layer to another symbol layer 611 * \param destLayer destination layer 612 * \since QGIS 2.9 613 */ 614 void copyPaintEffect( QgsSymbolLayer *destLayer ) const; 615 616 private: 617 static void initPropertyDefinitions(); 618 619 //! Property definitions 620 static QgsPropertiesDefinition sPropertyDefinitions; 621 622 #ifdef SIP_RUN 623 QgsSymbolLayer( const QgsSymbolLayer &other ); 624 #endif 625 626 }; 627 628 ////////////////////// 629 630 /** 631 * \ingroup core 632 * \class QgsMarkerSymbolLayer 633 * \brief Abstract base class for marker symbol layers. 634 */ 635 class CORE_EXPORT QgsMarkerSymbolLayer : public QgsSymbolLayer 636 { 637 public: 638 639 //! Symbol horizontal anchor points 640 enum HorizontalAnchorPoint 641 { 642 Left, //!< Align to left side of symbol 643 HCenter, //!< Align to horizontal center of symbol 644 Right, //!< Align to right side of symbol 645 }; 646 647 //! Symbol vertical anchor points 648 enum VerticalAnchorPoint 649 { 650 Top, //!< Align to top of symbol 651 VCenter, //!< Align to vertical center of symbol 652 Bottom, //!< Align to bottom of symbol 653 }; 654 655 //! QgsMarkerSymbolLayer cannot be copied 656 QgsMarkerSymbolLayer( const QgsMarkerSymbolLayer &other ) = delete; 657 658 //! QgsMarkerSymbolLayer cannot be copied 659 QgsMarkerSymbolLayer &operator=( const QgsMarkerSymbolLayer &other ) = delete; 660 661 void startRender( QgsSymbolRenderContext &context ) override; 662 663 void stopRender( QgsSymbolRenderContext &context ) override; 664 665 /** 666 * Renders a marker at the specified point. Derived classes must implement this to 667 * handle drawing the point. 668 * \param point position at which to render point, in painter units 669 * \param context symbol render context 670 */ 671 virtual void renderPoint( QPointF point, QgsSymbolRenderContext &context ) = 0; 672 673 void drawPreviewIcon( QgsSymbolRenderContext &context, QSize size ) override; 674 675 /** 676 * Sets the rotation angle for the marker. 677 * \param angle angle in degrees clockwise from north. 678 * \see angle() 679 * \see setLineAngle() 680 */ setAngle(double angle)681 void setAngle( double angle ) { mAngle = angle; } 682 683 /** 684 * Returns the rotation angle for the marker, in degrees clockwise from north. 685 * \see setAngle() 686 */ angle()687 double angle() const { return mAngle; } 688 689 /** 690 * Sets the line angle modification for the symbol's angle. This angle is added to 691 * the marker's rotation and data defined rotation before rendering the symbol, and 692 * is usually used for orienting symbols to match a line's angle. 693 * \param lineAngle Angle in degrees clockwise from north, valid values are between 0 and 360 694 * \see setAngle() 695 * \see angle() 696 * \since QGIS 2.9 697 */ setLineAngle(double lineAngle)698 void setLineAngle( double lineAngle ) { mLineAngle = lineAngle; } 699 700 /** 701 * Sets the symbol size. 702 * \param size symbol size. Units are specified by sizeUnit(). 703 * \see size() 704 * \see setSizeUnit() 705 * \see setSizeMapUnitScale() 706 */ setSize(double size)707 virtual void setSize( double size ) { mSize = size; } 708 709 /** 710 * Returns the symbol size. Units are specified by sizeUnit(). 711 * \see setSize() 712 * \see sizeUnit() 713 * \see sizeMapUnitScale() 714 */ size()715 double size() const { return mSize; } 716 717 /** 718 * Sets the units for the symbol's size. 719 * \param unit size units 720 * \see sizeUnit() 721 * \see setSize() 722 * \see setSizeMapUnitScale() 723 */ setSizeUnit(QgsUnitTypes::RenderUnit unit)724 void setSizeUnit( QgsUnitTypes::RenderUnit unit ) { mSizeUnit = unit; } 725 726 /** 727 * Returns the units for the symbol's size. 728 * \see setSizeUnit() 729 * \see size() 730 * \see sizeMapUnitScale() 731 */ sizeUnit()732 QgsUnitTypes::RenderUnit sizeUnit() const { return mSizeUnit; } 733 734 /** 735 * Sets the map unit scale for the symbol's size. 736 * \param scale size map unit scale 737 * \see sizeMapUnitScale() 738 * \see setSize() 739 * \see setSizeUnit() 740 */ setSizeMapUnitScale(const QgsMapUnitScale & scale)741 void setSizeMapUnitScale( const QgsMapUnitScale &scale ) { mSizeMapUnitScale = scale; } 742 743 /** 744 * Returns the map unit scale for the symbol's size. 745 * \see setSizeMapUnitScale() 746 * \see size() 747 * \see sizeUnit() 748 */ sizeMapUnitScale()749 const QgsMapUnitScale &sizeMapUnitScale() const { return mSizeMapUnitScale; } 750 751 /** 752 * Sets the method to use for scaling the marker's size. 753 * \param scaleMethod scale method 754 * \see scaleMethod() 755 */ setScaleMethod(Qgis::ScaleMethod scaleMethod)756 void setScaleMethod( Qgis::ScaleMethod scaleMethod ) { mScaleMethod = scaleMethod; } 757 758 /** 759 * Returns the method to use for scaling the marker's size. 760 * \see setScaleMethod() 761 */ scaleMethod()762 Qgis::ScaleMethod scaleMethod() const { return mScaleMethod; } 763 764 /** 765 * Sets the marker's offset, which is the horizontal and vertical displacement which the rendered marker 766 * should have from the original feature's geometry. 767 * \param offset marker offset. Units are specified by offsetUnit() 768 * \see offset() 769 * \see setOffsetUnit() 770 * \see setOffsetMapUnitScale() 771 */ setOffset(QPointF offset)772 void setOffset( QPointF offset ) { mOffset = offset; } 773 774 /** 775 * Returns the marker's offset, which is the horizontal and vertical displacement which the rendered marker 776 * will have from the original feature's geometry. Units are specified by offsetUnit(). 777 * \see setOffset() 778 * \see offsetUnit() 779 * \see offsetMapUnitScale() 780 */ offset()781 QPointF offset() const { return mOffset; } 782 783 /** 784 * Sets the units for the symbol's offset. 785 * \param unit offset units 786 * \see offsetUnit() 787 * \see setOffset() 788 * \see setOffsetMapUnitScale() 789 */ setOffsetUnit(QgsUnitTypes::RenderUnit unit)790 void setOffsetUnit( QgsUnitTypes::RenderUnit unit ) { mOffsetUnit = unit; } 791 792 /** 793 * Returns the units for the symbol's offset. 794 * \see setOffsetUnit() 795 * \see offset() 796 * \see offsetMapUnitScale() 797 */ offsetUnit()798 QgsUnitTypes::RenderUnit offsetUnit() const { return mOffsetUnit; } 799 800 /** 801 * Sets the map unit scale for the symbol's offset. 802 * \param scale offset map unit scale 803 * \see offsetMapUnitScale() 804 * \see setOffset() 805 * \see setOffsetUnit() 806 */ setOffsetMapUnitScale(const QgsMapUnitScale & scale)807 void setOffsetMapUnitScale( const QgsMapUnitScale &scale ) { mOffsetMapUnitScale = scale; } 808 809 /** 810 * Returns the map unit scale for the symbol's offset. 811 * \see setOffsetMapUnitScale() 812 * \see offset() 813 * \see offsetUnit() 814 */ offsetMapUnitScale()815 const QgsMapUnitScale &offsetMapUnitScale() const { return mOffsetMapUnitScale; } 816 817 /** 818 * Sets the horizontal anchor point for positioning the symbol. 819 * \param h anchor point. Symbol will be drawn so that the horizontal anchor point is aligned with 820 * the marker's desired location. 821 * \see horizontalAnchorPoint() 822 * \see setVerticalAnchorPoint() 823 */ setHorizontalAnchorPoint(HorizontalAnchorPoint h)824 void setHorizontalAnchorPoint( HorizontalAnchorPoint h ) { mHorizontalAnchorPoint = h; } 825 826 /** 827 * Returns the horizontal anchor point for positioning the symbol. The symbol will be drawn so that 828 * the horizontal anchor point is aligned with the marker's desired location. 829 * \see setHorizontalAnchorPoint() 830 * \see verticalAnchorPoint() 831 */ horizontalAnchorPoint()832 HorizontalAnchorPoint horizontalAnchorPoint() const { return mHorizontalAnchorPoint; } 833 834 /** 835 * Sets the vertical anchor point for positioning the symbol. 836 * \param v anchor point. Symbol will be drawn so that the vertical anchor point is aligned with 837 * the marker's desired location. 838 * \see verticalAnchorPoint() 839 * \see setHorizontalAnchorPoint() 840 */ setVerticalAnchorPoint(VerticalAnchorPoint v)841 void setVerticalAnchorPoint( VerticalAnchorPoint v ) { mVerticalAnchorPoint = v; } 842 843 /** 844 * Returns the vertical anchor point for positioning the symbol. The symbol will be drawn so that 845 * the vertical anchor point is aligned with the marker's desired location. 846 * \see setVerticalAnchorPoint() 847 * \see horizontalAnchorPoint() 848 */ verticalAnchorPoint()849 VerticalAnchorPoint verticalAnchorPoint() const { return mVerticalAnchorPoint; } 850 851 void toSld( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const override; 852 853 /** 854 * Writes the symbol layer definition as a SLD XML element. 855 * \param doc XML document 856 * \param element parent XML element 857 * \param props symbol layer definition (see properties()) 858 */ writeSldMarker(QDomDocument & doc,QDomElement & element,const QVariantMap & props)859 virtual void writeSldMarker( QDomDocument &doc, QDomElement &element, const QVariantMap &props ) const 860 { Q_UNUSED( props ) element.appendChild( doc.createComment( QStringLiteral( "QgsMarkerSymbolLayer %1 not implemented yet" ).arg( layerType() ) ) ); } 861 862 void setOutputUnit( QgsUnitTypes::RenderUnit unit ) override; 863 QgsUnitTypes::RenderUnit outputUnit() const override; 864 void setMapUnitScale( const QgsMapUnitScale &scale ) override; 865 QgsMapUnitScale mapUnitScale() const override; 866 867 /** 868 * Returns the approximate bounding box of the marker symbol layer, taking into account 869 * any data defined overrides and offsets which are set for the marker layer. 870 * \returns approximate symbol bounds, in painter units 871 * \since QGIS 2.14 872 */ 873 virtual QRectF bounds( QPointF point, QgsSymbolRenderContext &context ) = 0; 874 875 protected: 876 877 /** 878 * Constructor for QgsMarkerSymbolLayer. 879 * \param locked set to TRUE to lock symbol color 880 */ 881 QgsMarkerSymbolLayer( bool locked = false ); 882 883 /** 884 * Calculates the required marker offset, including both the symbol offset 885 * and any displacement required to align with the marker's anchor point. 886 * \param context symbol render context 887 * \param offsetX will be set to required horizontal offset (in painter units) 888 * \param offsetY will be set to required vertical offset (in painter units) 889 */ 890 void markerOffset( QgsSymbolRenderContext &context, double &offsetX, double &offsetY ) const; 891 892 /** 893 * Calculates the required marker offset, including both the symbol offset 894 * and any displacement required to align with the marker's anchor point. 895 * \param context symbol render context 896 * \param width marker width 897 * \param height marker height 898 * \param offsetX will be set to required horizontal offset (in painter units) 899 * \param offsetY will be set to required vertical offset (in painter units) 900 * \note available in Python as markerOffsetWithWidthAndHeight 901 */ 902 void markerOffset( QgsSymbolRenderContext &context, double width, double height, double &offsetX, double &offsetY ) const SIP_PYNAME( markerOffsetWithWidthAndHeight ); 903 904 //! \note available in Python bindings as markerOffset2 905 void markerOffset( QgsSymbolRenderContext &context, double width, double height, 906 QgsUnitTypes::RenderUnit widthUnit, QgsUnitTypes::RenderUnit heightUnit, 907 double &offsetX, double &offsetY, 908 const QgsMapUnitScale &widthMapUnitScale, const QgsMapUnitScale &heightMapUnitScale ) const SIP_PYNAME( markerOffset2 ); 909 910 /** 911 * Adjusts a marker offset to account for rotation. 912 * \param offset offset prior to rotation 913 * \param angle rotation angle in degrees clockwise from north 914 * \returns adjusted offset 915 */ 916 static QPointF _rotatedOffset( QPointF offset, double angle ); 917 918 //! Marker rotation angle, in degrees clockwise from north 919 double mAngle = 0; 920 //! Line rotation angle (see setLineAngle() for details) 921 double mLineAngle = 0; 922 //! Marker size 923 double mSize = 2.0; 924 //! Marker size unit 925 QgsUnitTypes::RenderUnit mSizeUnit = QgsUnitTypes::RenderMillimeters; 926 //! Marker size map unit scale 927 QgsMapUnitScale mSizeMapUnitScale; 928 //! Marker offset 929 QPointF mOffset; 930 //! Offset units 931 QgsUnitTypes::RenderUnit mOffsetUnit = QgsUnitTypes::RenderMillimeters; 932 //! Offset map unit scale 933 QgsMapUnitScale mOffsetMapUnitScale; 934 //! Marker size scaling method 935 Qgis::ScaleMethod mScaleMethod = Qgis::ScaleMethod::ScaleDiameter; 936 //! Horizontal anchor point 937 HorizontalAnchorPoint mHorizontalAnchorPoint = HCenter; 938 //! Vertical anchor point 939 VerticalAnchorPoint mVerticalAnchorPoint = VCenter; 940 941 private: 942 static QgsMarkerSymbolLayer::HorizontalAnchorPoint decodeHorizontalAnchorPoint( const QString &str ); 943 static QgsMarkerSymbolLayer::VerticalAnchorPoint decodeVerticalAnchorPoint( const QString &str ); 944 945 #ifdef SIP_RUN 946 QgsMarkerSymbolLayer( const QgsMarkerSymbolLayer &other ); 947 #endif 948 }; 949 950 /** 951 * \ingroup core 952 * \class QgsLineSymbolLayer 953 */ 954 class CORE_EXPORT QgsLineSymbolLayer : public QgsSymbolLayer 955 { 956 public: 957 958 //! Options for filtering rings when the line symbol layer is being used to render a polygon's rings. 959 enum RenderRingFilter 960 { 961 AllRings, //!< Render both exterior and interior rings 962 ExteriorRingOnly, //!< Render the exterior ring only 963 InteriorRingsOnly, //!< Render the interior rings only 964 }; 965 966 //! QgsLineSymbolLayer cannot be copied 967 QgsLineSymbolLayer( const QgsLineSymbolLayer &other ) = delete; 968 969 //! QgsLineSymbolLayer cannot be copied 970 QgsLineSymbolLayer &operator=( const QgsLineSymbolLayer &other ) = delete; 971 972 void setOutputUnit( QgsUnitTypes::RenderUnit unit ) override; 973 QgsUnitTypes::RenderUnit outputUnit() const override; 974 void setMapUnitScale( const QgsMapUnitScale &scale ) override; 975 QgsMapUnitScale mapUnitScale() const override; 976 void drawPreviewIcon( QgsSymbolRenderContext &context, QSize size ) override; 977 double dxfWidth( const QgsDxfExport &e, QgsSymbolRenderContext &context ) const override; 978 979 /** 980 * Renders the line symbol layer along the line joining \a points, using the given render \a context. 981 * \see renderPolygonStroke() 982 */ 983 virtual void renderPolyline( const QPolygonF &points, QgsSymbolRenderContext &context ) = 0; 984 985 /** 986 * Renders the line symbol layer along the outline of polygon, using the given render \a context. 987 * 988 * The exterior ring of the polygon is specified in \a points. Optionally, interior 989 * rings are set via the \a rings argument. 990 * 991 * \see renderPolyline() 992 */ 993 virtual void renderPolygonStroke( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context ); 994 995 /** 996 * Sets the \a width of the line symbol layer. 997 * 998 * Calling this method updates the width of the line symbol layer, without 999 * changing the existing width units. It has different effects depending 1000 * on the line symbol layer subclass, e.g. for a simple line layer it 1001 * changes the stroke width of the line, for a marker line layer it 1002 * changes the size of the markers used to draw the line. 1003 * 1004 * \see width() 1005 * \warning Since the width units vary, this method is useful for changing the 1006 * relative width of a line symbol layer only. 1007 */ setWidth(double width)1008 virtual void setWidth( double width ) { mWidth = width; } 1009 1010 /** 1011 * Returns the estimated width for the line symbol layer. 1012 * 1013 * \warning This returned value is inaccurate if the symbol layer has sub-symbols with 1014 * different width units. Use the overload accepting a QgsRenderContext 1015 * argument instead for accurate sizes in this case. 1016 * 1017 * \see setWidth() 1018 */ width()1019 virtual double width() const { return mWidth; } 1020 1021 /** 1022 * Returns the line symbol layer width, in painter units. 1023 * 1024 * This method returns an accurate width by calculating the actual rendered 1025 * width of the symbol layer using the provided render \a context. 1026 * 1027 * \see setWidth() 1028 * 1029 * \since QGIS 3.4.5 1030 */ 1031 virtual double width( const QgsRenderContext &context ) const; 1032 1033 /** 1034 * Returns the line's offset. 1035 * 1036 * Offset units can be retrieved by calling offsetUnit(). 1037 * 1038 * \see setOffset() 1039 * \see offsetUnit() 1040 * \see offsetMapUnitScale() 1041 */ offset()1042 double offset() const { return mOffset; } 1043 1044 /** 1045 * Sets the line's \a offset. 1046 * 1047 * Offset units are set via setOffsetUnit(). 1048 * 1049 * \see offset() 1050 * \see setOffsetUnit() 1051 * \see setOffsetMapUnitScale() 1052 */ setOffset(double offset)1053 void setOffset( double offset ) { mOffset = offset; } 1054 1055 /** 1056 * Sets the \a unit for the line's offset. 1057 * \see offsetUnit() 1058 * \see setOffset() 1059 * \see setOffsetMapUnitScale() 1060 */ setOffsetUnit(QgsUnitTypes::RenderUnit unit)1061 void setOffsetUnit( QgsUnitTypes::RenderUnit unit ) { mOffsetUnit = unit; } 1062 1063 /** 1064 * Returns the units for the line's offset. 1065 * \see setOffsetUnit() 1066 * \see offset() 1067 * \see offsetMapUnitScale() 1068 */ offsetUnit()1069 QgsUnitTypes::RenderUnit offsetUnit() const { return mOffsetUnit; } 1070 1071 /** 1072 * Sets the map unit \a scale for the line's offset. 1073 * \see offsetMapUnitScale() 1074 * \see setOffset() 1075 * \see setOffsetUnit() 1076 */ setOffsetMapUnitScale(const QgsMapUnitScale & scale)1077 void setOffsetMapUnitScale( const QgsMapUnitScale &scale ) { mOffsetMapUnitScale = scale; } 1078 1079 /** 1080 * Returns the map unit scale for the line's offset. 1081 * \see setOffsetMapUnitScale() 1082 * \see offset() 1083 * \see offsetUnit() 1084 */ offsetMapUnitScale()1085 const QgsMapUnitScale &offsetMapUnitScale() const { return mOffsetMapUnitScale; } 1086 1087 // TODO QGIS 4.0 - setWidthUnit(), widthUnit(), setWidthUnitScale(), widthUnitScale() 1088 // only apply to simple line symbol layers and do not belong here. 1089 1090 /** 1091 * Sets the units for the line's width. 1092 * \param unit width units 1093 * \see widthUnit() 1094 */ setWidthUnit(QgsUnitTypes::RenderUnit unit)1095 void setWidthUnit( QgsUnitTypes::RenderUnit unit ) { mWidthUnit = unit; } 1096 1097 /** 1098 * Returns the units for the line's width. 1099 * \see setWidthUnit() 1100 */ widthUnit()1101 QgsUnitTypes::RenderUnit widthUnit() const { return mWidthUnit; } 1102 setWidthMapUnitScale(const QgsMapUnitScale & scale)1103 void setWidthMapUnitScale( const QgsMapUnitScale &scale ) { mWidthMapUnitScale = scale; } widthMapUnitScale()1104 const QgsMapUnitScale &widthMapUnitScale() const { return mWidthMapUnitScale; } 1105 1106 /** 1107 * Returns the line symbol layer's ring filter, which controls which rings are 1108 * rendered when the line symbol is being used to draw a polygon's rings. 1109 * 1110 * This setting has no effect when the line symbol is not being rendered 1111 * for a polygon. 1112 * 1113 * \see setRingFilter() 1114 * \since QGIS 3.6 1115 */ 1116 RenderRingFilter ringFilter() const; 1117 1118 /** 1119 * Sets the line symbol layer's ring \a filter, which controls which rings are 1120 * rendered when the line symbol is being used to draw a polygon's rings. 1121 * 1122 * This setting has no effect when the line symbol is not being rendered 1123 * for a polygon. 1124 * 1125 * \see ringFilter() 1126 * \since QGIS 3.6 1127 */ 1128 void setRingFilter( QgsLineSymbolLayer::RenderRingFilter filter ); 1129 1130 protected: 1131 QgsLineSymbolLayer( bool locked = false ); 1132 1133 double mWidth = 0; 1134 QgsUnitTypes::RenderUnit mWidthUnit = QgsUnitTypes::RenderMillimeters; 1135 QgsMapUnitScale mWidthMapUnitScale; 1136 double mOffset = 0; 1137 QgsUnitTypes::RenderUnit mOffsetUnit = QgsUnitTypes::RenderMillimeters; 1138 QgsMapUnitScale mOffsetMapUnitScale; 1139 1140 RenderRingFilter mRingFilter = AllRings; 1141 1142 private: 1143 #ifdef SIP_RUN 1144 QgsLineSymbolLayer( const QgsLineSymbolLayer &other ); 1145 #endif 1146 }; 1147 1148 /** 1149 * \ingroup core 1150 * \class QgsFillSymbolLayer 1151 */ 1152 class CORE_EXPORT QgsFillSymbolLayer : public QgsSymbolLayer 1153 { 1154 public: 1155 1156 //! QgsFillSymbolLayer cannot be copied 1157 QgsFillSymbolLayer( const QgsFillSymbolLayer &other ) = delete; 1158 1159 //! QgsFillSymbolLayer cannot be copied 1160 QgsFillSymbolLayer &operator=( const QgsFillSymbolLayer &other ) = delete; 1161 1162 /** 1163 * Renders the fill symbol layer for the polygon whose outer ring is defined by \a points, using the given render \a context. 1164 * 1165 * The \a rings argument optionally specifies a list of polygon rings to render as holes. 1166 */ 1167 virtual void renderPolygon( const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context ) = 0; 1168 1169 void drawPreviewIcon( QgsSymbolRenderContext &context, QSize size ) override; 1170 setAngle(double angle)1171 void setAngle( double angle ) { mAngle = angle; } angle()1172 double angle() const { return mAngle; } 1173 1174 protected: 1175 QgsFillSymbolLayer( bool locked = false ); 1176 //! Default method to render polygon 1177 void _renderPolygon( QPainter *p, const QPolygonF &points, const QVector<QPolygonF> *rings, QgsSymbolRenderContext &context ); 1178 1179 double mAngle = 0.0; 1180 1181 private: 1182 #ifdef SIP_RUN 1183 QgsFillSymbolLayer( const QgsFillSymbolLayer &other ); 1184 #endif 1185 }; 1186 1187 class QgsSymbolLayerWidget; // why does SIP fail, when this isn't here 1188 1189 #endif 1190 1191 1192