QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgslayoutitemmarker.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgslayoutitemmarker.cpp
3  ---------------------
4  begin : April 2020
5  copyright : (C) 2020 by Nyall Dawson
6  email : nyall dot dawson at gmail dot com
7  ***************************************************************************/
8 /***************************************************************************
9  * *
10  * This program is free software; you can redistribute it and/or modify *
11  * it under the terms of the GNU General Public License as published by *
12  * the Free Software Foundation; either version 2 of the License, or *
13  * (at your option) any later version. *
14  * *
15  ***************************************************************************/
16 
17 #include "qgslayoutitemmarker.h"
18 #include "qgslayout.h"
19 #include "qgslayoututils.h"
20 #include "qgssymbollayerutils.h"
21 #include "qgslayoutmodel.h"
22 #include "qgsstyleentityvisitor.h"
23 #include "qgslayoutitemmap.h"
24 #include "qgsmarkersymbol.h"
25 
26 #include <QPainter>
27 
29  : QgsLayoutItem( layout )
30  , mNorthArrowHandler( new QgsLayoutNorthArrowHandler( this ) )
31 {
32  setBackgroundEnabled( false );
33  setFrameEnabled( false );
35  QVariantMap properties;
36  properties.insert( QStringLiteral( "size" ), QStringLiteral( "4" ) );
37  mShapeStyleSymbol.reset( QgsMarkerSymbol::createSimple( properties ) );
38  refreshSymbol();
39 
40  connect( this, &QgsLayoutItemMarker::sizePositionChanged, this, [ = ]
41  {
42  updateBoundingRect();
43  update();
44  } );
45 
46  connect( mNorthArrowHandler, &QgsLayoutNorthArrowHandler::arrowRotationChanged, this, &QgsLayoutItemMarker::northArrowRotationChanged );
47 }
48 
50 
52 {
53  return new QgsLayoutItemMarker( layout );
54 }
55 
57 {
59 }
60 
62 {
63  return QgsApplication::getThemeIcon( QStringLiteral( "/mLayoutItemMarker.svg" ) );
64 }
65 
66 void QgsLayoutItemMarker::refreshSymbol()
67 {
68  if ( auto *lLayout = layout() )
69  {
70  QgsRenderContext rc = QgsLayoutUtils::createRenderContextForLayout( lLayout, nullptr, lLayout->renderContext().dpi() );
71 
72  std::unique_ptr< QgsMarkerSymbol > sym( mShapeStyleSymbol->clone() );
73  sym->setAngle( sym->angle() + mNorthArrowRotation );
74  sym->startRender( rc );
75  QRectF bounds = sym->bounds( QPointF( 0, 0 ), rc );
76  sym->stopRender( rc );
77  mPoint = QPointF( -bounds.left() * 25.4 / lLayout->renderContext().dpi(),
78  -bounds.top() * 25.4 / lLayout->renderContext().dpi() );
79  bounds.translate( mPoint );
80 
81  const QgsLayoutSize newSizeMm = QgsLayoutSize( bounds.size() * 25.4 / lLayout->renderContext().dpi(), QgsUnitTypes::LayoutMillimeters );
82  mFixedSize = mLayout->renderContext().measurementConverter().convert( newSizeMm, sizeWithUnits().units() );
83 
84  attemptResize( mFixedSize );
85  }
86 
87  updateBoundingRect();
88 
89  update();
90  emit frameChanged();
91 }
92 
93 void QgsLayoutItemMarker::updateBoundingRect()
94 {
95  QRectF rectangle = rect();
96 
97  // add a bit, to account for antialiasing on stroke and miter effects on stroke
98  rectangle.adjust( -5, -5, 5, 5 );
99  if ( rectangle != mCurrentRectangle )
100  {
101  prepareGeometryChange();
102  mCurrentRectangle = rectangle;
103  }
104 }
105 
106 void QgsLayoutItemMarker::northArrowRotationChanged( double rotation )
107 {
108  mNorthArrowRotation = rotation;
109  refreshSymbol();
110 }
111 
113 {
114  if ( !symbol )
115  return;
116 
117  mShapeStyleSymbol.reset( symbol );
118  refreshSymbol();
119 }
120 
122 {
123  return mShapeStyleSymbol.get();
124 }
125 
127 {
128  mNorthArrowHandler->setLinkedMap( map );
129 }
130 
132 {
133  return mNorthArrowHandler->linkedMap();
134 }
135 
137 {
138  return mNorthArrowHandler->northMode();
139 
140 }
141 
143 {
144  mNorthArrowHandler->setNorthMode( mode );
145 
146 }
147 
149 {
150  return mNorthArrowHandler->northOffset();
151 }
152 
154 {
155  mNorthArrowHandler->setNorthOffset( offset );
156 }
157 
159 {
160  return mCurrentRectangle;
161 }
162 
164 {
165  return mFixedSize;
166 }
167 
169 {
170  if ( mShapeStyleSymbol )
171  {
172  QgsStyleSymbolEntity entity( mShapeStyleSymbol.get() );
173  if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity, uuid(), displayName() ) ) )
174  return false;
175  }
176 
177  return true;
178 }
179 
181 {
182  QPainter *painter = context.renderContext().painter();
183  painter->setPen( Qt::NoPen );
184  painter->setBrush( Qt::NoBrush );
185 
186  const double scale = context.renderContext().convertToPainterUnits( 1, QgsUnitTypes::RenderMillimeters );
187 
188  const QPointF shapePoint = mPoint * scale;
189 
190  std::unique_ptr< QgsMarkerSymbol > sym( mShapeStyleSymbol->clone() );
191  sym->setAngle( sym->angle() + mNorthArrowRotation );
192  sym->startRender( context.renderContext() );
193  sym->renderPoint( shapePoint, nullptr, context.renderContext() );
194  sym->stopRender( context.renderContext() );
195 }
196 
197 bool QgsLayoutItemMarker::writePropertiesToElement( QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context ) const
198 {
199  const QDomElement shapeStyleElem = QgsSymbolLayerUtils::saveSymbol( QString(), mShapeStyleSymbol.get(), document, context );
200  element.appendChild( shapeStyleElem );
201 
202  //rotation
203  element.setAttribute( QStringLiteral( "arrowRotation" ), QString::number( mNorthArrowRotation ) );
204  if ( !mNorthArrowHandler->linkedMap() )
205  {
206  element.setAttribute( QStringLiteral( "mapUuid" ), QString() );
207  }
208  else
209  {
210  element.setAttribute( QStringLiteral( "mapUuid" ), mNorthArrowHandler->linkedMap()->uuid() );
211  }
212  element.setAttribute( QStringLiteral( "northMode" ), mNorthArrowHandler->northMode() );
213  element.setAttribute( QStringLiteral( "northOffset" ), mNorthArrowHandler->northOffset() );
214 
215  return true;
216 }
217 
218 bool QgsLayoutItemMarker::readPropertiesFromElement( const QDomElement &element, const QDomDocument &, const QgsReadWriteContext &context )
219 {
220  const QDomElement shapeStyleSymbolElem = element.firstChildElement( QStringLiteral( "symbol" ) );
221  if ( !shapeStyleSymbolElem.isNull() )
222  {
223  mShapeStyleSymbol.reset( QgsSymbolLayerUtils::loadSymbol<QgsMarkerSymbol>( shapeStyleSymbolElem, context ) );
224  }
225 
226  //picture rotation
227  if ( !qgsDoubleNear( element.attribute( QStringLiteral( "arrowRotation" ), QStringLiteral( "0" ) ).toDouble(), 0.0 ) )
228  {
229  mNorthArrowRotation = element.attribute( QStringLiteral( "arrowRotation" ), QStringLiteral( "0" ) ).toDouble();
230  }
231 
232  //rotation map
233  mNorthArrowHandler->setNorthMode( static_cast< QgsLayoutNorthArrowHandler::NorthMode >( element.attribute( QStringLiteral( "northMode" ), QStringLiteral( "0" ) ).toInt() ) );
234  mNorthArrowHandler->setNorthOffset( element.attribute( QStringLiteral( "northOffset" ), QStringLiteral( "0" ) ).toDouble() );
235 
236  mNorthArrowHandler->setLinkedMap( nullptr );
237  mRotationMapUuid = element.attribute( QStringLiteral( "mapUuid" ) );
238 
239  refreshSymbol();
240 
241  return true;
242 }
243 
245 {
246  if ( !mLayout || mRotationMapUuid.isEmpty() )
247  {
248  mNorthArrowHandler->setLinkedMap( nullptr );
249  }
250  else
251  {
252  mNorthArrowHandler->setLinkedMap( qobject_cast< QgsLayoutItemMap * >( mLayout->itemByUuid( mRotationMapUuid, true ) ) );
253  }
254  emit changed();
255 }
QgsLayoutObject::layout
const QgsLayout * layout() const
Returns the layout the object is attached to.
Definition: qgslayoutobject.cpp:216
QgsLayoutItemMarker
A layout item for showing marker symbols.
Definition: qgslayoutitemmarker.h:33
QgsLayoutItem::sizePositionChanged
void sizePositionChanged()
Emitted when the item's size or position changes.
QgsLayoutItem::setFrameEnabled
virtual void setFrameEnabled(bool drawFrame)
Sets whether this item has a frame drawn around it or not.
Definition: qgslayoutitem.cpp:834
QgsReadWriteContext
The class is used as a container of context for various read/write operations on other objects.
Definition: qgsreadwritecontext.h:34
QgsLayoutItemMarker::readPropertiesFromElement
bool readPropertiesFromElement(const QDomElement &element, const QDomDocument &document, const QgsReadWriteContext &context) override
Sets item state from a DOM element.
Definition: qgslayoutitemmarker.cpp:218
QgsLayoutItem::Middle
@ Middle
Center of item.
Definition: qgslayoutitem.h:207
QgsStyleSymbolEntity
A symbol entity for QgsStyle databases.
Definition: qgsstyle.h:1341
QgsLayoutNorthArrowHandler::linkedMap
QgsLayoutItemMap * linkedMap() const
Returns the linked rotation map, if set.
Definition: qgslayoutnortharrowhandler.cpp:107
qgssymbollayerutils.h
QgsLayoutItemMarker::~QgsLayoutItemMarker
~QgsLayoutItemMarker() override
QgsLayoutItemRenderContext
Contains settings and helpers relating to a render of a QgsLayoutItem.
Definition: qgslayoutitem.h:44
QgsRenderContext
Contains information about the context of a rendering operation.
Definition: qgsrendercontext.h:59
QgsStyleEntityVisitorInterface
An interface for classes which can visit style entity (e.g. symbol) nodes (using the visitor pattern)...
Definition: qgsstyleentityvisitor.h:33
QgsLayoutItemMarker::setNorthOffset
void setNorthOffset(double offset)
Sets the offset added to the marker's rotation from a map's North.
Definition: qgslayoutitemmarker.cpp:153
QgsUnitTypes::RenderMillimeters
@ RenderMillimeters
Millimeters.
Definition: qgsunittypes.h:169
QgsLayoutItemMarker::northMode
QgsLayoutNorthArrowHandler::NorthMode northMode() const
Returns the mode used to align the marker to a map's North.
Definition: qgslayoutitemmarker.cpp:136
QgsLayoutObject::changed
void changed()
Emitted when the object's properties change.
QgsLayoutItem::sizeWithUnits
QgsLayoutSize sizeWithUnits() const
Returns the item's current size, including units.
Definition: qgslayoutitem.h:673
QgsStyleEntityVisitorInterface::StyleLeaf
Contains information relating to the style entity currently being visited.
Definition: qgsstyleentityvisitor.h:60
QgsLayoutItemMarker::linkedMap
QgsLayoutItemMap * linkedMap() const
Returns the linked rotation map, if set.
Definition: qgslayoutitemmarker.cpp:131
QgsLayoutItemMarker::northOffset
double northOffset() const
Returns the offset added to the marker's rotation from a map's North.
Definition: qgslayoutitemmarker.cpp:148
QgsLayoutItemMarker::writePropertiesToElement
bool writePropertiesToElement(QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context) const override
Stores item state within an XML DOM element.
Definition: qgslayoutitemmarker.cpp:197
QgsLayoutItemMarker::accept
bool accept(QgsStyleEntityVisitorInterface *visitor) const override
Accepts the specified style entity visitor, causing it to visit all style entities associated with th...
Definition: qgslayoutitemmarker.cpp:168
qgslayoututils.h
QgsLayoutNorthArrowHandler::northMode
NorthMode northMode() const
Returns the mode used to calculate the arrow rotation.
Definition: qgslayoutnortharrowhandler.h:74
QgsLayoutUtils::createRenderContextForLayout
static QgsRenderContext createRenderContextForLayout(QgsLayout *layout, QPainter *painter, double dpi=-1)
Creates a render context suitable for the specified layout and painter destination.
Definition: qgslayoututils.cpp:141
QgsLayoutItemMarker::create
static QgsLayoutItemMarker * create(QgsLayout *layout)
Returns a new marker item for the specified layout.
Definition: qgslayoutitemmarker.cpp:51
QgsLayoutItemMarker::boundingRect
QRectF boundingRect() const override
Definition: qgslayoutitemmarker.cpp:158
QgsLayoutItemMarker::setLinkedMap
void setLinkedMap(QgsLayoutItemMap *map)
Sets the map object for rotation.
Definition: qgslayoutitemmarker.cpp:126
QgsMarkerSymbol
A marker symbol type, for rendering Point and MultiPoint geometries.
Definition: qgsmarkersymbol.h:30
qgsDoubleNear
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:2265
QgsLayoutItem::frameChanged
void frameChanged()
Emitted if the item's frame style changes.
QgsLayoutNorthArrowHandler::setNorthOffset
void setNorthOffset(double offset)
Sets the offset added to the arrows's rotation from a map's North.
Definition: qgslayoutnortharrowhandler.cpp:118
QgsLayoutItem::setBackgroundEnabled
void setBackgroundEnabled(bool drawBackground)
Sets whether this item has a background drawn under it or not.
Definition: qgslayoutitem.cpp:887
QgsLayoutItemMarker::symbol
QgsMarkerSymbol * symbol()
Returns the marker symbol used to draw the shape.
Definition: qgslayoutitemmarker.cpp:121
QgsLayoutItemMarker::fixedSize
QgsLayoutSize fixedSize() const override
Returns the fixed size of the item, if applicable, or an empty size if item can be freely resized.
Definition: qgslayoutitemmarker.cpp:163
QgsLayoutNorthArrowHandler::setLinkedMap
void setLinkedMap(QgsLayoutItemMap *map)
Sets the linked map item.
Definition: qgslayoutnortharrowhandler.cpp:81
QgsLayoutNorthArrowHandler::arrowRotationChanged
void arrowRotationChanged(double newRotation)
Emitted on arrow rotation change.
QgsLayoutItem
Base class for graphical items within a QgsLayout.
Definition: qgslayoutitem.h:112
QgsLayoutNorthArrowHandler::setNorthMode
void setNorthMode(NorthMode mode)
Sets the mode used to calculate the arrow rotation.
Definition: qgslayoutnortharrowhandler.cpp:112
qgslayoutitemmarker.h
qgslayout.h
QgsLayoutNorthArrowHandler
An object which handles north-arrow type behavior for layout items.
Definition: qgslayoutnortharrowhandler.h:32
QgsLayoutNorthArrowHandler::NorthMode
NorthMode
Method for syncing rotation to a map's North direction.
Definition: qgslayoutnortharrowhandler.h:38
QgsRenderContext::convertToPainterUnits
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).
Definition: qgsrendercontext.cpp:367
QgsLayoutItemMap
Layout graphical items for displaying a map.
Definition: qgslayoutitemmap.h:317
QgsLayoutItemMarker::type
int type() const override
Definition: qgslayoutitemmarker.cpp:56
QgsLayoutItemMarker::setNorthMode
void setNorthMode(QgsLayoutNorthArrowHandler::NorthMode mode)
Sets the mode used to align the marker to a map's North.
Definition: qgslayoutitemmarker.cpp:142
QgsLayoutItem::setReferencePoint
void setReferencePoint(ReferencePoint point)
Sets the reference point for positioning of the layout item.
Definition: qgslayoutitem.cpp:415
QgsLayoutItemRenderContext::renderContext
QgsRenderContext & renderContext()
Returns a reference to the context's render context.
Definition: qgslayoutitem.h:72
QgsLayoutItem::uuid
virtual QString uuid() const
Returns the item identification string.
Definition: qgslayoutitem.h:345
QgsLayoutObject::mLayout
QPointer< QgsLayout > mLayout
Definition: qgslayoutobject.h:363
QgsLayoutItemMarker::QgsLayoutItemMarker
QgsLayoutItemMarker(QgsLayout *layout)
Constructor for QgsLayoutItemMarker, with the specified parent layout.
Definition: qgslayoutitemmarker.cpp:28
QgsLayout
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
Definition: qgslayout.h:50
QgsLayoutItem::displayName
virtual QString displayName() const
Gets item display name.
Definition: qgslayoutitem.cpp:107
qgsmarkersymbol.h
QgsLayoutItemRegistry::LayoutMarker
@ LayoutMarker
Marker item.
Definition: qgslayoutitemregistry.h:369
QgsLayoutItemMarker::draw
void draw(QgsLayoutItemRenderContext &context) override
Draws the item's contents using the specified item render context.
Definition: qgslayoutitemmarker.cpp:180
QgsLayoutItemMarker::setSymbol
void setSymbol(QgsMarkerSymbol *symbol)
Sets the marker symbol used to draw the shape.
Definition: qgslayoutitemmarker.cpp:112
QgsLayoutItem::attemptResize
virtual void attemptResize(const QgsLayoutSize &size, bool includesFrame=false)
Attempts to resize the item to a specified target size.
Definition: qgslayoutitem.cpp:429
QgsStyleEntityVisitorInterface::visit
virtual bool visit(const QgsStyleEntityVisitorInterface::StyleLeaf &entity)
Called when the visitor will visit a style entity.
Definition: qgsstyleentityvisitor.h:153
QgsLayoutNorthArrowHandler::northOffset
double northOffset() const
Returns the offset added to the arrows's rotation from a map's North.
Definition: qgslayoutnortharrowhandler.h:88
QgsLayoutSize
This class provides a method of storing sizes, consisting of a width and height, for use in QGIS layo...
Definition: qgslayoutsize.h:40
QgsApplication::getThemeIcon
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
Definition: qgsapplication.cpp:693
QgsUnitTypes::LayoutMillimeters
@ LayoutMillimeters
Millimeters.
Definition: qgsunittypes.h:183
QgsLayoutItemMarker::finalizeRestoreFromXml
void finalizeRestoreFromXml() override
Called after all pending items have been restored from XML.
Definition: qgslayoutitemmarker.cpp:244
QgsRenderContext::painter
QPainter * painter()
Returns the destination QPainter for the render operation.
Definition: qgsrendercontext.h:112
QgsLayoutItemMarker::icon
QIcon icon() const override
Returns the item's icon.
Definition: qgslayoutitemmarker.cpp:61
QgsMarkerSymbol::createSimple
static QgsMarkerSymbol * createSimple(const QVariantMap &properties)
Create a marker symbol with one symbol layer: SimpleMarker with specified properties.
Definition: qgsmarkersymbol.cpp:22
qgslayoutmodel.h
QgsSymbolLayerUtils::saveSymbol
static QDomElement saveSymbol(const QString &symbolName, const QgsSymbol *symbol, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a symbol definition to XML.
Definition: qgssymbollayerutils.cpp:1397
qgsstyleentityvisitor.h
qgslayoutitemmap.h