QGIS API Documentation  3.24.2-Tisler (13c1a02865)
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 }
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
Layout graphical items for displaying a map.
A layout item for showing marker symbols.
~QgsLayoutItemMarker() override
double northOffset() const
Returns the offset added to the marker's rotation from a map's North.
void draw(QgsLayoutItemRenderContext &context) override
Draws the item's contents using the specified item render context.
bool readPropertiesFromElement(const QDomElement &element, const QDomDocument &document, const QgsReadWriteContext &context) override
Sets item state from a DOM element.
bool writePropertiesToElement(QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context) const override
Stores item state within an XML DOM element.
QIcon icon() const override
Returns the item's icon.
void setLinkedMap(QgsLayoutItemMap *map)
Sets the map object for rotation.
QgsLayoutNorthArrowHandler::NorthMode northMode() const
Returns the mode used to align the marker to a map's North.
QgsLayoutItemMarker(QgsLayout *layout)
Constructor for QgsLayoutItemMarker, with the specified parent layout.
QgsLayoutSize fixedSize() const override
Returns the fixed size of the item, if applicable, or an empty size if item can be freely resized.
void setNorthOffset(double offset)
Sets the offset added to the marker's rotation from a map's North.
int type() const override
void setNorthMode(QgsLayoutNorthArrowHandler::NorthMode mode)
Sets the mode used to align the marker to a map's North.
static QgsLayoutItemMarker * create(QgsLayout *layout)
Returns a new marker item for the specified layout.
QgsLayoutItemMap * linkedMap() const
Returns the linked rotation map, if set.
void setSymbol(QgsMarkerSymbol *symbol)
Sets the marker symbol used to draw the shape.
void finalizeRestoreFromXml() override
Called after all pending items have been restored from XML.
QRectF boundingRect() const override
QgsMarkerSymbol * symbol()
Returns the marker symbol used to draw the shape.
bool accept(QgsStyleEntityVisitorInterface *visitor) const override
Accepts the specified style entity visitor, causing it to visit all style entities associated with th...
Contains settings and helpers relating to a render of a QgsLayoutItem.
Definition: qgslayoutitem.h:45
QgsRenderContext & renderContext()
Returns a reference to the context's render context.
Definition: qgslayoutitem.h:72
Base class for graphical items within a QgsLayout.
QgsLayoutSize sizeWithUnits() const
Returns the item's current size, including units.
@ Middle
Center of item.
virtual void setFrameEnabled(bool drawFrame)
Sets whether this item has a frame drawn around it or not.
virtual QString displayName() const
Gets item display name.
virtual void attemptResize(const QgsLayoutSize &size, bool includesFrame=false)
Attempts to resize the item to a specified target size.
void sizePositionChanged()
Emitted when the item's size or position changes.
virtual QString uuid() const
Returns the item identification string.
void frameChanged()
Emitted if the item's frame style changes.
void setReferencePoint(ReferencePoint point)
Sets the reference point for positioning of the layout item.
void setBackgroundEnabled(bool drawBackground)
Sets whether this item has a background drawn under it or not.
An object which handles north-arrow type behavior for layout items.
void setNorthOffset(double offset)
Sets the offset added to the arrows's rotation from a map's North.
NorthMode northMode() const
Returns the mode used to calculate the arrow rotation.
QgsLayoutItemMap * linkedMap() const
Returns the linked rotation map, if set.
void arrowRotationChanged(double newRotation)
Emitted on arrow rotation change.
NorthMode
Method for syncing rotation to a map's North direction.
void setNorthMode(NorthMode mode)
Sets the mode used to calculate the arrow rotation.
void setLinkedMap(QgsLayoutItemMap *map)
Sets the linked map item.
double northOffset() const
Returns the offset added to the arrows's rotation from a map's North.
const QgsLayout * layout() const
Returns the layout the object is attached to.
void changed()
Emitted when the object's properties change.
QPointer< QgsLayout > mLayout
This class provides a method of storing sizes, consisting of a width and height, for use in QGIS layo...
Definition: qgslayoutsize.h:41
static QgsRenderContext createRenderContextForLayout(QgsLayout *layout, QPainter *painter, double dpi=-1)
Creates a render context suitable for the specified layout and painter destination.
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
Definition: qgslayout.h:51
A marker symbol type, for rendering Point and MultiPoint geometries.
static QgsMarkerSymbol * createSimple(const QVariantMap &properties)
Create a marker symbol with one symbol layer: SimpleMarker with specified properties.
The class is used as a container of context for various read/write operations on other objects.
Contains information about the context of a rendering operation.
QPainter * painter()
Returns the destination QPainter for the render operation.
double convertToPainterUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale(), Qgis::RenderSubcomponentProperty property=Qgis::RenderSubcomponentProperty::Generic) const
Converts a size from the specified units to painter units (pixels).
An interface for classes which can visit style entity (e.g.
virtual bool visit(const QgsStyleEntityVisitorInterface::StyleLeaf &entity)
Called when the visitor will visit a style entity.
A symbol entity for QgsStyle databases.
Definition: qgsstyle.h:1222
static QDomElement saveSymbol(const QString &symbolName, const QgsSymbol *symbol, QDomDocument &doc, const QgsReadWriteContext &context)
Writes a symbol definition to XML.
@ LayoutMillimeters
Millimeters.
Definition: qgsunittypes.h:183
@ RenderMillimeters
Millimeters.
Definition: qgsunittypes.h:169
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:1578
Contains information relating to the style entity currently being visited.