QGIS API Documentation  2.99.0-Master (e077efd)
qgspaperitem.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgspaperitem.cpp
3  -------------------
4  begin : September 2008
5  copyright : (C) 2008 by Marco Hugentobler
6  email : marco dot hugentobler at karto dot baug dot ethz dot ch
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include "qgspaperitem.h"
19 #include "qgscomposition.h"
20 #include "qgsstyle.h"
21 #include "qgslogger.h"
22 #include "qgsmapsettings.h"
23 #include <QGraphicsRectItem>
24 #include <QGraphicsView>
25 #include <QPainter>
26 
27 //QgsPaperGrid
28 
29 QgsPaperGrid::QgsPaperGrid( double x, double y, double width, double height, QgsComposition* composition ): QGraphicsRectItem( 0, 0, width, height ), mComposition( composition )
30 {
31  setFlag( QGraphicsItem::ItemIsSelectable, false );
32  setFlag( QGraphicsItem::ItemIsMovable, false );
33  setZValue( 1000 );
34  setPos( x, y );
35 }
36 
38 {
39 }
40 
41 void QgsPaperGrid::paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget )
42 {
43  Q_UNUSED( itemStyle );
44  Q_UNUSED( pWidget );
45 
46  //draw grid
47  if ( mComposition )
48  {
49  if ( mComposition->gridVisible() && mComposition->plotStyle() == QgsComposition::Preview
50  && mComposition->snapGridResolution() > 0 )
51  {
52  int gridMultiplyX = static_cast< int >( mComposition->snapGridOffsetX() / mComposition->snapGridResolution() );
53  int gridMultiplyY = static_cast< int >( mComposition->snapGridOffsetY() / mComposition->snapGridResolution() );
54  double currentXCoord = mComposition->snapGridOffsetX() - gridMultiplyX * mComposition->snapGridResolution();
55  double currentYCoord;
56  double minYCoord = mComposition->snapGridOffsetY() - gridMultiplyY * mComposition->snapGridResolution();
57 
58  painter->save();
59  //turn of antialiasing so grid is nice and sharp
60  painter->setRenderHint( QPainter::Antialiasing, false );
61 
62  if ( mComposition->gridStyle() == QgsComposition::Solid )
63  {
64  painter->setPen( mComposition->gridPen() );
65 
66  //draw vertical lines
67  for ( ; currentXCoord <= rect().width(); currentXCoord += mComposition->snapGridResolution() )
68  {
69  painter->drawLine( QPointF( currentXCoord, 0 ), QPointF( currentXCoord, rect().height() ) );
70  }
71 
72  //draw horizontal lines
73  currentYCoord = minYCoord;
74  for ( ; currentYCoord <= rect().height(); currentYCoord += mComposition->snapGridResolution() )
75  {
76  painter->drawLine( QPointF( 0, currentYCoord ), QPointF( rect().width(), currentYCoord ) );
77  }
78  }
79  else //'Dots' or 'Crosses'
80  {
81  QPen gridPen = mComposition->gridPen();
82  painter->setPen( gridPen );
83  painter->setBrush( QBrush( gridPen.color() ) );
84  double halfCrossLength = 1;
85  if ( mComposition->gridStyle() == QgsComposition::Dots )
86  {
87  //dots are actually drawn as tiny crosses a few pixels across
88  //check QGraphicsView to get current transform
89  if ( scene() )
90  {
91  QList<QGraphicsView*> viewList = scene()->views();
92  if ( !viewList.isEmpty() )
93  {
94  QGraphicsView* currentView = viewList.at( 0 );
95  if ( currentView->isVisible() )
96  {
97  //set halfCrossLength to equivalent of 1 pixel
98  halfCrossLength = 1 / currentView->transform().m11();
99  }
100  }
101  }
102  }
103  else if ( mComposition->gridStyle() == QgsComposition::Crosses )
104  {
105  halfCrossLength = mComposition->snapGridResolution() / 6;
106  }
107 
108  for ( ; currentXCoord <= rect().width(); currentXCoord += mComposition->snapGridResolution() )
109  {
110  currentYCoord = minYCoord;
111  for ( ; currentYCoord <= rect().height(); currentYCoord += mComposition->snapGridResolution() )
112  {
113  painter->drawLine( QPointF( currentXCoord - halfCrossLength, currentYCoord ), QPointF( currentXCoord + halfCrossLength, currentYCoord ) );
114  painter->drawLine( QPointF( currentXCoord, currentYCoord - halfCrossLength ), QPointF( currentXCoord, currentYCoord + halfCrossLength ) );
115  }
116  }
117  }
118  painter->restore();
119  }
120  }
121 }
122 
123 
124 //QgsPaperItem
125 
127  mPageGrid( nullptr )
128 {
129  initialize();
130 }
131 
132 QgsPaperItem::QgsPaperItem( qreal x, qreal y, qreal width, qreal height, QgsComposition* composition ): QgsComposerItem( x, y, width, height, composition, false ),
133  mPageGrid( nullptr ), mPageMargin( 0 )
134 {
135  initialize();
136 }
137 
138 QgsPaperItem::QgsPaperItem(): QgsComposerItem( nullptr, false ),
139  mPageGrid( nullptr ), mPageMargin( 0 )
140 {
141  initialize();
142 }
143 
145 {
146  delete mPageGrid;
147 }
148 
149 void QgsPaperItem::paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget )
150 {
151  Q_UNUSED( itemStyle );
152  Q_UNUSED( pWidget );
153  if ( !painter || !mComposition || !mComposition->pagesVisible() )
154  {
155  return;
156  }
157 
158  //setup painter scaling to dots so that raster symbology is drawn to scale
159  double dotsPerMM = painter->device()->logicalDpiX() / 25.4;
160 
161  //setup render context
163  //context units should be in dots
164  ms.setOutputDpi( painter->device()->logicalDpiX() );
166  context.setPainter( painter );
167  context.setForceVectorOutput( true );
168  QgsExpressionContext expressionContext = createExpressionContext();
169  context.setExpressionContext( expressionContext );
170 
171  painter->save();
172 
174  {
175  //if in preview mode, draw page border and shadow so that it's
176  //still possible to tell where pages with a transparent style begin and end
177  painter->setRenderHint( QPainter::Antialiasing, false );
178 
179  //shadow
180  painter->setBrush( QBrush( QColor( 150, 150, 150 ) ) );
181  painter->setPen( Qt::NoPen );
182  painter->drawRect( QRectF( 1, 1, rect().width() + 1, rect().height() + 1 ) );
183 
184  //page area
185  painter->setBrush( QColor( 215, 215, 215 ) );
186  painter->setPen( QPen( QColor( 100, 100, 100 ) ) );
187  painter->drawRect( QRectF( 0, 0, rect().width(), rect().height() ) );
188  }
189 
190  painter->scale( 1 / dotsPerMM, 1 / dotsPerMM ); // scale painter from mm to dots
191 
192  painter->setRenderHint( QPainter::Antialiasing );
194 
195  calculatePageMargin();
196  QPolygonF pagePolygon = QPolygonF( QRectF( mPageMargin * dotsPerMM, mPageMargin * dotsPerMM,
197  ( rect().width() - 2 * mPageMargin ) * dotsPerMM, ( rect().height() - 2 * mPageMargin ) * dotsPerMM ) );
198  QList<QPolygonF> rings; //empty list
199 
200  mComposition->pageStyleSymbol()->renderPolygon( pagePolygon, &rings, nullptr, context );
201  mComposition->pageStyleSymbol()->stopRender( context );
202  painter->restore();
203 }
204 
205 void QgsPaperItem::calculatePageMargin()
206 {
207  //get max bleed from symbol
209 
210  //Now subtract 1 pixel to prevent semi-transparent borders at edge of solid page caused by
211  //anti-aliased painting. This may cause a pixel to be cropped from certain edge lines/symbols,
212  //but that can be counteracted by adding a dummy transparent line symbol layer with a wider line width
213  mPageMargin = maxBleed - ( 25.4 / mComposition->printResolution() );
214 }
215 
216 bool QgsPaperItem::writeXml( QDomElement& elem, QDomDocument & doc ) const
217 {
218  Q_UNUSED( elem );
219  Q_UNUSED( doc );
220  return true;
221 }
222 
223 bool QgsPaperItem::readXml( const QDomElement& itemElem, const QDomDocument& doc )
224 {
225  Q_UNUSED( itemElem );
226  Q_UNUSED( doc );
227  return true;
228 }
229 
230 void QgsPaperItem::setSceneRect( const QRectF& rectangle )
231 {
232  QgsComposerItem::setSceneRect( rectangle );
233  //update size and position of attached QgsPaperGrid to reflect new page size and position
234  mPageGrid->setRect( 0, 0, rect().width(), rect().height() );
235  mPageGrid->setPos( pos().x(), pos().y() );
236 }
237 
238 void QgsPaperItem::initialize()
239 {
240  setFlag( QGraphicsItem::ItemIsSelectable, false );
241  setFlag( QGraphicsItem::ItemIsMovable, false );
242  setZValue( 0 );
243 
244  //even though we aren't going to use it to draw the page, set the pen width as 4
245  //so that the page border and shadow is fully rendered within its scene rect
246  //(QGraphicsRectItem considers the pen width when calculating an item's scene rect)
247  setPen( QPen( QBrush( Qt::NoBrush ), 4 ) );
248 
249  if ( mComposition )
250  {
251  //create a new QgsPaperGrid for this page, and add it to the composition
252  mPageGrid = new QgsPaperGrid( pos().x(), pos().y(), rect().width(), rect().height(), mComposition );
253  mComposition->addItem( mPageGrid );
254 
255  //connect to atlas feature changes
256  //to update symbol style (in case of data-defined symbology)
257  connect( &mComposition->atlasComposition(), SIGNAL( featureChanged( QgsFeature* ) ), this, SLOT( repaint() ) );
258  }
259 }
void setForceVectorOutput(bool force)
const QPen & gridPen() const
double snapGridOffsetY() const
double snapGridOffsetX() const
int printResolution() const
A item that forms part of a map composition.
QgsPaperGrid(double x, double y, double width, double height, QgsComposition *composition)
void setOutputDpi(double dpi)
Set DPI used for conversion between real world units (e.g. mm) and pixels.
bool gridVisible() const
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:135
void startRender(QgsRenderContext &context, const QgsFields &fields=QgsFields())
Begins the rendering process for the symbol.
Definition: qgssymbol.cpp:387
QgsComposition::PlotStyle plotStyle() const
The QgsMapSettings class contains configuration for rendering of the map.
void renderPolygon(const QPolygonF &points, QList< QPolygonF > *rings, const QgsFeature *f, QgsRenderContext &context, int layer=-1, bool selected=false)
Definition: qgssymbol.cpp:1732
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
bool readXml(const QDomElement &itemElem, const QDomDocument &doc) override
Sets state from Dom document.
Item representing a grid.
Definition: qgspaperitem.h:27
void setPainter(QPainter *p)
void repaint() override
QgsPaperItem(QgsComposition *c)
Graphics scene for map printing.
const QgsMapSettings & mapSettings() const
Return setting of QGIS map canvas.
static double estimateMaxSymbolBleed(QgsSymbol *symbol)
Returns the maximum estimated bleed for the symbol.
virtual QgsExpressionContext createExpressionContext() const override
Creates an expression context relating to the item&#39;s current state.
QgsComposition * mComposition
void paint(QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget) override
Reimplementation of QCanvasItem::paint.
Contains information about the context of a rendering operation.
QgsFillSymbol * pageStyleSymbol()
Note: added in version 2.1.
const QgsComposition * composition() const
Returns the composition the item is attached to.
static QgsRenderContext fromMapSettings(const QgsMapSettings &mapSettings)
create initialized QgsRenderContext instance from given QgsMapSettings
GridStyle gridStyle() const
virtual void setSceneRect(const QRectF &rectangle)
Sets this items bound in scene coordinates such that 1 item size units corresponds to 1 scene size un...
virtual void setSceneRect(const QRectF &rectangle) override
Sets this items bound in scene coordinates such that 1 item size units corresponds to 1 scene size un...
double snapGridResolution() const
QgsAtlasComposition & atlasComposition()
void paint(QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget) override
Reimplementation of QCanvasItem::paint.
bool writeXml(QDomElement &elem, QDomDocument &doc) const override
Stores state in Dom element.
QgsComposerItem(QgsComposition *composition, bool manageZValue=true)
Constructor.
bool pagesVisible() const
Returns whether the page items are be visible in the composition.
void stopRender(QgsRenderContext &context)
Ends the rendering process.
Definition: qgssymbol.cpp:408
void setExpressionContext(const QgsExpressionContext &context)
Sets the expression context.