QGIS API Documentation  2.11.0-Master
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 "qgsstylev2.h"
21 #include "qgslogger.h"
22 #include <QGraphicsRectItem>
23 #include <QGraphicsView>
24 #include <QPainter>
25 
26 //QgsPaperGrid
27 
28 QgsPaperGrid::QgsPaperGrid( double x, double y, double width, double height, QgsComposition* composition ): QGraphicsRectItem( 0, 0, width, height ), mComposition( composition )
29 {
30  setFlag( QGraphicsItem::ItemIsSelectable, false );
31  setFlag( QGraphicsItem::ItemIsMovable, false );
32  setZValue( 1000 );
33  setPos( x, y );
34 }
35 
37 {
38 }
39 
40 void QgsPaperGrid::paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget )
41 {
42  Q_UNUSED( itemStyle );
43  Q_UNUSED( pWidget );
44 
45  //draw grid
46  if ( mComposition )
47  {
48  if ( mComposition->gridVisible() && mComposition->plotStyle() == QgsComposition::Preview
49  && mComposition->snapGridResolution() > 0 )
50  {
51  int gridMultiplyX = ( int )( mComposition->snapGridOffsetX() / mComposition->snapGridResolution() );
52  int gridMultiplyY = ( int )( mComposition->snapGridOffsetY() / mComposition->snapGridResolution() );
53  double currentXCoord = mComposition->snapGridOffsetX() - gridMultiplyX * mComposition->snapGridResolution();
54  double currentYCoord;
55  double minYCoord = mComposition->snapGridOffsetY() - gridMultiplyY * mComposition->snapGridResolution();
56 
57  painter->save();
58  //turn of antialiasing so grid is nice and sharp
59  painter->setRenderHint( QPainter::Antialiasing, false );
60 
61  if ( mComposition->gridStyle() == QgsComposition::Solid )
62  {
63  painter->setPen( mComposition->gridPen() );
64 
65  //draw vertical lines
66  for ( ; currentXCoord <= rect().width(); currentXCoord += mComposition->snapGridResolution() )
67  {
68  painter->drawLine( QPointF( currentXCoord, 0 ), QPointF( currentXCoord, rect().height() ) );
69  }
70 
71  //draw horizontal lines
72  currentYCoord = minYCoord;
73  for ( ; currentYCoord <= rect().height(); currentYCoord += mComposition->snapGridResolution() )
74  {
75  painter->drawLine( QPointF( 0, currentYCoord ), QPointF( rect().width(), currentYCoord ) );
76  }
77  }
78  else //'Dots' or 'Crosses'
79  {
80  QPen gridPen = mComposition->gridPen();
81  painter->setPen( gridPen );
82  painter->setBrush( QBrush( gridPen.color() ) );
83  double halfCrossLength = 1;
84  if ( mComposition->gridStyle() == QgsComposition::Dots )
85  {
86  //dots are actually drawn as tiny crosses a few pixels across
87  //check QGraphicsView to get current transform
88  if ( scene() )
89  {
90  QList<QGraphicsView*> viewList = scene()->views();
91  if ( viewList.size() > 0 )
92  {
93  QGraphicsView* currentView = viewList.at( 0 );
94  if ( currentView->isVisible() )
95  {
96  //set halfCrossLength to equivalent of 1 pixel
97  halfCrossLength = 1 / currentView->transform().m11();
98  }
99  }
100  }
101  }
102  else if ( mComposition->gridStyle() == QgsComposition::Crosses )
103  {
104  halfCrossLength = mComposition->snapGridResolution() / 6;
105  }
106 
107  for ( ; currentXCoord <= rect().width(); currentXCoord += mComposition->snapGridResolution() )
108  {
109  currentYCoord = minYCoord;
110  for ( ; currentYCoord <= rect().height(); currentYCoord += mComposition->snapGridResolution() )
111  {
112  painter->drawLine( QPointF( currentXCoord - halfCrossLength, currentYCoord ), QPointF( currentXCoord + halfCrossLength, currentYCoord ) );
113  painter->drawLine( QPointF( currentXCoord, currentYCoord - halfCrossLength ), QPointF( currentXCoord, currentYCoord + halfCrossLength ) );
114  }
115  }
116  }
117  painter->restore();
118  }
119  }
120 }
121 
122 
123 //QgsPaperItem
124 
126  mPageGrid( 0 )
127 {
128  initialize();
129 }
130 
131 QgsPaperItem::QgsPaperItem( qreal x, qreal y, qreal width, qreal height, QgsComposition* composition ): QgsComposerItem( x, y, width, height, composition, false ),
132  mPageGrid( 0 ), mPageMargin( 0 )
133 {
134  initialize();
135 }
136 
137 QgsPaperItem::QgsPaperItem(): QgsComposerItem( 0, false ),
138  mPageGrid( 0 ), mPageMargin( 0 )
139 {
140  initialize();
141 }
142 
144 {
145  delete mPageGrid;
146 }
147 
148 void QgsPaperItem::paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget )
149 {
150  Q_UNUSED( itemStyle );
151  Q_UNUSED( pWidget );
152  if ( !painter )
153  {
154  return;
155  }
156 
157  //setup painter scaling to dots so that raster symbology is drawn to scale
158  double dotsPerMM = painter->device()->logicalDpiX() / 25.4;
159 
160  //setup render context
162  //context units should be in dots
163  ms.setOutputDpi( painter->device()->logicalDpiX() );
165  context.setPainter( painter );
166  context.setForceVectorOutput( true );
167 
168  painter->save();
169 
171  {
172  //if in preview mode, draw page border and shadow so that it's
173  //still possible to tell where pages with a transparent style begin and end
174  painter->setRenderHint( QPainter::Antialiasing, false );
175 
176  //shadow
177  painter->setBrush( QBrush( QColor( 150, 150, 150 ) ) );
178  painter->setPen( Qt::NoPen );
179  painter->drawRect( QRectF( 1, 1, rect().width() + 1, rect().height() + 1 ) );
180 
181  //page area
182  painter->setBrush( QColor( 215, 215, 215 ) );
183  painter->setPen( QPen( QColor( 100, 100, 100 ) ) );
184  painter->drawRect( QRectF( 0, 0, rect().width(), rect().height() ) );
185  }
186 
187  painter->scale( 1 / dotsPerMM, 1 / dotsPerMM ); // scale painter from mm to dots
188 
189  painter->setRenderHint( QPainter::Antialiasing );
191 
192  calculatePageMargin();
193  QPolygonF pagePolygon = QPolygonF( QRectF( mPageMargin * dotsPerMM, mPageMargin * dotsPerMM,
194  ( rect().width() - 2 * mPageMargin ) * dotsPerMM, ( rect().height() - 2 * mPageMargin ) * dotsPerMM ) );
195  QList<QPolygonF> rings; //empty list
196 
197  //need to render using atlas feature properties?
199  {
200  //using an atlas, so render using current atlas feature
201  //since there may be data defined symbols using atlas feature properties
202  mComposition->pageStyleSymbol()->renderPolygon( pagePolygon, &rings, mComposition->atlasComposition().currentFeature(), context );
203  }
204  else
205  {
206  mComposition->pageStyleSymbol()->renderPolygon( pagePolygon, &rings, 0, context );
207  }
208 
209  mComposition->pageStyleSymbol()->stopRender( context );
210  painter->restore();
211 }
212 
213 void QgsPaperItem::calculatePageMargin()
214 {
215  //get max bleed from symbol
217 
218  //Now subtract 1 pixel to prevent semi-transparent borders at edge of solid page caused by
219  //anti-aliased painting. This may cause a pixel to be cropped from certain edge lines/symbols,
220  //but that can be counteracted by adding a dummy transparent line symbol layer with a wider line width
221  mPageMargin = maxBleed - ( 25.4 / mComposition->printResolution() );
222 }
223 
225 {
226  Q_UNUSED( elem );
227  Q_UNUSED( doc );
228  return true;
229 }
230 
231 bool QgsPaperItem::readXML( const QDomElement& itemElem, const QDomDocument& doc )
232 {
233  Q_UNUSED( itemElem );
234  Q_UNUSED( doc );
235  return true;
236 }
237 
238 void QgsPaperItem::setSceneRect( const QRectF& rectangle )
239 {
240  QgsComposerItem::setSceneRect( rectangle );
241  //update size and position of attached QgsPaperGrid to reflect new page size and position
242  mPageGrid->setRect( 0, 0, rect().width(), rect().height() );
243  mPageGrid->setPos( pos().x(), pos().y() );
244 }
245 
246 void QgsPaperItem::initialize()
247 {
248  setFlag( QGraphicsItem::ItemIsSelectable, false );
249  setFlag( QGraphicsItem::ItemIsMovable, false );
250  setZValue( 0 );
251 
252  //even though we aren't going to use it to draw the page, set the pen width as 4
253  //so that the page border and shadow is fully rendered within its scene rect
254  //(QGraphicsRectItem considers the pen width when calculating an item's scene rect)
255  setPen( QPen( QBrush( Qt::NoBrush ), 4 ) );
256 
257  if ( mComposition )
258  {
259  //create a new QgsPaperGrid for this page, and add it to the composition
260  mPageGrid = new QgsPaperGrid( pos().x(), pos().y(), rect().width(), rect().height(), mComposition );
261  mComposition->addItem( mPageGrid );
262 
263  //connect to atlas feature changes
264  //to update symbol style (in case of data-defined symbology)
265  connect( &mComposition->atlasComposition(), SIGNAL( featureChanged( QgsFeature* ) ), this, SLOT( repaint() ) );
266  }
267 }
void setForceVectorOutput(bool force)
QgsComposition::AtlasMode atlasMode() const
Returns the current atlas mode of the composition.
qreal x() const
qreal y() const
void renderPolygon(const QPolygonF &points, QList< QPolygonF > *rings, const QgsFeature *f, QgsRenderContext &context, int layer=-1, bool selected=false)
QgsFillSymbolV2 * pageStyleSymbol()
Note: added in version 2.1.
bool writeXML(QDomElement &elem, QDomDocument &doc) const override
Stores state in Dom element.
void setRenderHint(RenderHint hint, bool on)
void setFlag(GraphicsItemFlag flag, bool enabled)
void setOutputDpi(int dpi)
Set DPI used for conversion between real world units (e.g. mm) and pixels.
const QgsMapSettings & mapSettings() const
Return setting of QGIS map canvas.
const QPen & gridPen() const
void scale(qreal sx, qreal sy)
const T & at(int i) const
A item that forms part of a map composition.
QgsPaperGrid(double x, double y, double width, double height, QgsComposition *composition)
bool isVisible() const
void save()
bool enabled() const
Returns whether the atlas generation is enabled.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:162
void drawLine(const QLineF &line)
QGraphicsScene * scene() const
int size() const
void setRect(const QRectF &rectangle)
The QgsMapSettings class contains configuration for rendering of the map.
void drawRect(const QRectF &rectangle)
QColor color() const
QTransform transform() const
QPointF pos() const
void startRender(QgsRenderContext &context, const QgsFields *fields=0)
int printResolution() const
void setPen(const QColor &color)
void setPos(const QPointF &pos)
QList< QGraphicsView * > views() const
qreal m11() const
bool readXML(const QDomElement &itemElem, const QDomDocument &doc) override
Sets state from Dom document.
QPaintDevice * device() const
Item representing a grid.
Definition: qgspaperitem.h:26
void setBrush(const QBrush &brush)
void setPainter(QPainter *p)
void repaint() override
QgsPaperItem(QgsComposition *c)
static double estimateMaxSymbolBleed(QgsSymbolV2 *symbol)
Returns the maximum estimated bleed for the symbol.
Graphics scene for map printing.
QgsFeature * currentFeature()
Returns the current atlas feature.
int logicalDpiX() const
GridStyle gridStyle() const
void restore()
QgsComposition * mComposition
void paint(QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget) override
Reimplementation of QCanvasItem::paint.
double snapGridOffsetY() const
Contains information about the context of a rendering operation.
double snapGridOffsetX() const
qreal width() const
void stopRender(QgsRenderContext &context)
void setPen(const QPen &pen)
static QgsRenderContext fromMapSettings(const QgsMapSettings &mapSettings)
create initialized QgsRenderContext instance from given QgsMapSettings
double snapGridResolution() 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...
bool gridVisible() const
qreal height() const
QgsAtlasComposition & atlasComposition()
void paint(QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget) override
Reimplementation of QCanvasItem::paint.
void addItem(QGraphicsItem *item)
QgsComposition::PlotStyle plotStyle() const
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void setZValue(qreal z)
QRectF rect() const