QGIS API Documentation  2.14.0-Essen
qgsvectorlayerlabelprovider.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsvectorlayerlabelprovider.cpp
3  --------------------------------------
4  Date : September 2015
5  Copyright : (C) 2015 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 
17 
18 #include "qgsdatadefined.h"
19 #include "qgsgeometry.h"
20 #include "qgslabelsearchtree.h"
21 #include "qgspallabeling.h"
22 #include "qgstextlabelfeature.h"
23 #include "qgsvectorlayer.h"
25 #include "qgsrendererv2.h"
26 #include "qgspolygonv2.h"
27 #include "qgslinestringv2.h"
28 #include "qgsmultipolygonv2.h"
29 
30 #include "feature.h"
31 #include "labelposition.h"
32 
33 #include <QPicture>
34 
35 using namespace pal;
36 
37 Q_GUI_EXPORT extern int qt_defaultDpiX();
38 Q_GUI_EXPORT extern int qt_defaultDpiY();
39 
40 static void _fixQPictureDPI( QPainter* p )
41 {
42  // QPicture makes an assumption that we drawing to it with system DPI.
43  // Then when being drawn, it scales the painter. The following call
44  // negates the effect. There is no way of setting QPicture's DPI.
45  // See QTBUG-20361
46  p->scale( static_cast< double >( qt_defaultDpiX() ) / p->device()->logicalDpiX(),
47  static_cast< double >( qt_defaultDpiY() ) / p->device()->logicalDpiY() );
48 }
49 
50 
51 
52 QgsVectorLayerLabelProvider::QgsVectorLayerLabelProvider( QgsVectorLayer* layer, bool withFeatureLoop, const QgsPalLayerSettings* settings, const QString& layerName )
53  : QgsAbstractLabelProvider( layer->id() )
54  , mSettings( settings ? *settings : QgsPalLayerSettings::fromLayer( layer ) )
55  , mLayerGeometryType( layer->geometryType() )
56  , mRenderer( layer->rendererV2() )
57  , mFields( layer->fields() )
58  , mCrs( layer->crs() )
59 {
60  mName = layerName.isEmpty() ? layer->id() : layerName;
61 
62  if ( withFeatureLoop )
63  {
64  mSource = new QgsVectorLayerFeatureSource( layer );
65  mOwnsSource = true;
66  }
67  else
68  {
69  mSource = nullptr;
70  mOwnsSource = false;
71  }
72 
73  init();
74 }
75 
77  const QString& layerId,
78  const QgsFields& fields,
81  bool ownsSource, QgsFeatureRendererV2* renderer )
82  : QgsAbstractLabelProvider( layerId )
83  , mSettings( settings )
84  , mLayerGeometryType( QGis::UnknownGeometry )
85  , mRenderer( renderer )
86  , mFields( fields )
87  , mCrs( crs )
88  , mSource( source )
89  , mOwnsSource( ownsSource )
90 {
91  init();
92 }
93 
94 
96 {
99  mFlags = Flags();
106  mPriority = 1 - mSettings.priority / 10.0; // convert 0..10 --> 1..0
107 
109  {
110  //override obstacle type to treat any intersection of a label with the point symbol as a high cost conflict
112  }
113  else
114  {
116  }
117 
119 }
120 
121 
123 {
124  qDeleteAll( mLabels );
125 
126  if ( mOwnsSource )
127  delete mSource;
128 }
129 
130 
132 {
134  const QgsMapSettings& mapSettings = mEngine->mapSettings();
135 
136  QgsDebugMsgLevel( "PREPARE LAYER " + mLayerId, 4 );
137 
138  if ( lyr.drawLabels )
139  {
140  if ( lyr.fieldName.isEmpty() )
141  {
142  return false;
143  }
144 
145  if ( lyr.isExpression )
146  {
147  QgsExpression exp( lyr.fieldName );
148  if ( exp.hasEvalError() )
149  {
150  QgsDebugMsgLevel( "Prepare error:" + exp.evalErrorString(), 4 );
151  return false;
152  }
153  }
154  else
155  {
156  // If we aren't an expression, we check to see if we can find the column.
157  if ( mFields.fieldNameIndex( lyr.fieldName ) == -1 )
158  {
159  return false;
160  }
161  }
162  }
163 
164  lyr.mCurFields = mFields;
165 
166  if ( lyr.drawLabels )
167  {
168  // add field indices for label's text, from expression or field
169  if ( lyr.isExpression )
170  {
171  // prepare expression for use in QgsPalLayerSettings::registerFeature()
172  QgsExpression* exp = lyr.getLabelExpression();
173  exp->prepare( &context.expressionContext() );
174  if ( exp->hasEvalError() )
175  {
176  QgsDebugMsgLevel( "Prepare error:" + exp->evalErrorString(), 4 );
177  }
178  Q_FOREACH ( const QString& name, exp->referencedColumns() )
179  {
180  QgsDebugMsgLevel( "REFERENCED COLUMN = " + name, 4 );
181  attributeNames.append( name );
182  }
183  }
184  else
185  {
186  attributeNames.append( lyr.fieldName );
187  }
188 
189  // add field indices of data defined expression or field
191  for ( ; dIt != lyr.dataDefinedProperties.constEnd(); ++dIt )
192  {
193  QgsDataDefined* dd = dIt.value();
194  if ( !dd->isActive() )
195  {
196  continue;
197  }
198 
199  // NOTE: the following also prepares any expressions for later use
200 
201  // store parameters for data defined expressions
202  QMap<QString, QVariant> exprParams;
203  exprParams.insert( "scale", context.rendererScale() );
204 
205  dd->setExpressionParams( exprParams );
206 
207  // this will return columns for expressions or field name, depending upon what is set to be used
208  QStringList cols = dd->referencedColumns( context.expressionContext() ); // <-- prepares any expressions, too
209 
210  //QgsDebugMsgLevel( QString( "Data defined referenced columns:" ) + cols.join( "," ), 4 );
211  Q_FOREACH ( const QString& name, cols )
212  {
213  attributeNames.append( name );
214  }
215  }
216  }
217 
218  // NOW INITIALIZE QgsPalLayerSettings
219 
220  // TODO: ideally these (non-configuration) members should get out of QgsPalLayerSettings to here
221  // (together with registerFeature() & related methods) and QgsPalLayerSettings just stores config
222 
223  //raster and vector scale factors
224  lyr.vectorScaleFactor = context.scaleFactor();
225  lyr.rasterCompressFactor = context.rasterScaleFactor();
226 
227  // save the pal layer to our layer context (with some additional info)
229 
230  lyr.xform = &mapSettings.mapToPixel();
231  lyr.ct = nullptr;
232  if ( mapSettings.hasCrsTransformEnabled() )
233  {
234  if ( context.coordinateTransform() )
235  // this is context for layer rendering - use its CT as it includes correct datum transform
236  lyr.ct = context.coordinateTransform()->clone();
237  else
238  // otherwise fall back to creating our own CT - this one may not have the correct datum transform!
239  lyr.ct = new QgsCoordinateTransform( mCrs, mapSettings.destinationCrs() );
240  }
241  lyr.ptZero = lyr.xform->toMapCoordinates( 0, 0 );
242  lyr.ptOne = lyr.xform->toMapCoordinates( 1, 0 );
243 
244  // rect for clipping
245  lyr.extentGeom = QgsGeometry::fromRect( mapSettings.visibleExtent() );
246  if ( !qgsDoubleNear( mapSettings.rotation(), 0.0 ) )
247  {
248  //PAL features are prerotated, so extent also needs to be unrotated
249  lyr.extentGeom->rotate( -mapSettings.rotation(), mapSettings.visibleExtent().center() );
250  }
251 
252  lyr.mFeatsSendingToPal = 0;
253 
254  return true;
255 }
256 
257 
258 
260 {
261  if ( !mSource )
262  {
263  // we have created the provider with "own feature loop" == false
264  // so it is assumed that prepare() has been already called followed by registerFeature() calls
265  return mLabels;
266  }
267 
268  QStringList attrNames;
269  if ( !prepare( ctx, attrNames ) )
270  return QList<QgsLabelFeature*>();
271 
272  if ( mRenderer )
273  mRenderer->startRender( ctx, mFields );
274 
275  QgsRectangle layerExtent = ctx.extent();
276  if ( mSettings.ct )
278 
279  QgsFeatureRequest request;
280  request.setFilterRect( layerExtent );
281  request.setSubsetOfAttributes( attrNames, mFields );
282  QgsFeatureIterator fit = mSource->getFeatures( request );
283 
285  ctx.expressionContext().appendScope( symbolScope );
286  QgsFeature fet;
287  while ( fit.nextFeature( fet ) )
288  {
289  QScopedPointer<QgsGeometry> obstacleGeometry;
290  if ( mRenderer )
291  {
292  QgsSymbolV2List symbols = mRenderer->originalSymbolsForFeature( fet, ctx );
293  if ( !symbols.isEmpty() && fet.constGeometry()->type() == QGis::Point )
294  {
295  //point feature, use symbol bounds as obstacle
296  obstacleGeometry.reset( QgsVectorLayerLabelProvider::getPointObstacleGeometry( fet, ctx, symbols ) );
297  }
298  if ( !symbols.isEmpty() )
299  {
300  symbolScope = QgsExpressionContextUtils::updateSymbolScope( symbols.at( 0 ), symbolScope );
301  }
302  }
303  ctx.expressionContext().setFeature( fet );
304  registerFeature( fet, ctx, obstacleGeometry.data() );
305  }
306 
307  if ( ctx.expressionContext().lastScope() == symbolScope )
308  delete ctx.expressionContext().popScope();
309 
310  if ( mRenderer )
311  mRenderer->stopRender( ctx );
312 
313  return mLabels;
314 }
315 
317 {
318  QgsLabelFeature* label = nullptr;
319  mSettings.registerFeature( feature, context, QString(), &label, obstacleGeometry );
320  if ( label )
321  mLabels << label;
322 }
323 
325 {
326  if ( !fet.constGeometry() || fet.constGeometry()->isEmpty() || fet.constGeometry()->type() != QGis::Point )
327  return nullptr;
328 
329  bool isMultiPoint = fet.constGeometry()->geometry()->nCoordinates() > 1;
330  QgsAbstractGeometryV2* obstacleGeom = nullptr;
331  if ( isMultiPoint )
332  obstacleGeom = new QgsMultiPolygonV2();
333 
334  // for each point
335  for ( int i = 0; i < fet.constGeometry()->geometry()->nCoordinates(); ++i )
336  {
337  QRectF bounds;
338  QgsPointV2 p = fet.constGeometry()->geometry()->vertexAt( QgsVertexId( i, 0, 0 ) );
339  double x = p.x();
340  double y = p.y();
341  double z = 0; // dummy variable for coordinate transforms
342 
343  //transform point to pixels
344  if ( context.coordinateTransform() )
345  {
346  context.coordinateTransform()->transformInPlace( x, y, z );
347  }
348  context.mapToPixel().transformInPlace( x, y );
349 
350  QPointF pt( x, y );
351  Q_FOREACH ( QgsSymbolV2* symbol, symbols )
352  {
353  if ( symbol->type() == QgsSymbolV2::Marker )
354  {
355  if ( bounds.isValid() )
356  bounds = bounds.united( static_cast< QgsMarkerSymbolV2* >( symbol )->bounds( pt, context ) );
357  else
358  bounds = static_cast< QgsMarkerSymbolV2* >( symbol )->bounds( pt, context );
359  }
360  }
361 
362  //convert bounds to a geometry
363  QgsLineStringV2* boundLineString = new QgsLineStringV2();
364  boundLineString->addVertex( QgsPointV2( bounds.topLeft() ) );
365  boundLineString->addVertex( QgsPointV2( bounds.topRight() ) );
366  boundLineString->addVertex( QgsPointV2( bounds.bottomRight() ) );
367  boundLineString->addVertex( QgsPointV2( bounds.bottomLeft() ) );
368 
369  //then transform back to map units
370  //TODO - remove when labeling is refactored to use screen units
371  for ( int i = 0; i < boundLineString->numPoints(); ++i )
372  {
373  QgsPoint point = context.mapToPixel().toMapCoordinates( boundLineString->xAt( i ), boundLineString->yAt( i ) );
374  boundLineString->setXAt( i, point.x() );
375  boundLineString->setYAt( i, point.y() );
376  }
377  if ( context.coordinateTransform() )
378  {
380  }
381  boundLineString->close();
382 
383  QgsPolygonV2* obstaclePolygon = new QgsPolygonV2();
384  obstaclePolygon->setExteriorRing( boundLineString );
385 
386  if ( isMultiPoint )
387  {
388  static_cast<QgsMultiPolygonV2*>( obstacleGeom )->addGeometry( obstaclePolygon );
389  }
390  else
391  {
392  obstacleGeom = obstaclePolygon;
393  }
394  }
395 
396  return new QgsGeometry( obstacleGeom );
397 }
398 
400 {
401  if ( !mSettings.drawLabels )
402  return;
403 
404  QgsTextLabelFeature* lf = dynamic_cast<QgsTextLabelFeature*>( label->getFeaturePart()->feature() );
405 
406  // Copy to temp, editable layer settings
407  // these settings will be changed by any data defined values, then used for rendering label components
408  // settings may be adjusted during rendering of components
409  QgsPalLayerSettings tmpLyr( mSettings );
410 
411  // apply any previously applied data defined settings for the label
413 
414  //font
415  QFont dFont = lf->definedFont();
416  QgsDebugMsgLevel( QString( "PAL font tmpLyr: %1, Style: %2" ).arg( tmpLyr.textFont.toString(), tmpLyr.textFont.styleName() ), 4 );
417  QgsDebugMsgLevel( QString( "PAL font definedFont: %1, Style: %2" ).arg( dFont.toString(), dFont.styleName() ), 4 );
418  tmpLyr.textFont = dFont;
419 
421  {
422  //calculate font alignment based on label quadrant
423  switch ( label->getQuadrant() )
424  {
425  case LabelPosition::QuadrantAboveLeft:
426  case LabelPosition::QuadrantLeft:
427  case LabelPosition::QuadrantBelowLeft:
429  break;
430  case LabelPosition::QuadrantAbove:
431  case LabelPosition::QuadrantOver:
432  case LabelPosition::QuadrantBelow:
434  break;
435  case LabelPosition::QuadrantAboveRight:
436  case LabelPosition::QuadrantRight:
437  case LabelPosition::QuadrantBelowRight:
439  break;
440  }
441  }
442 
443  // update tmpLyr with any data defined text style values
444  QgsPalLabeling::dataDefinedTextStyle( tmpLyr, ddValues );
445 
446  // update tmpLyr with any data defined text buffer values
447  QgsPalLabeling::dataDefinedTextBuffer( tmpLyr, ddValues );
448 
449  // update tmpLyr with any data defined text formatting values
450  QgsPalLabeling::dataDefinedTextFormatting( tmpLyr, ddValues );
451 
452  // update tmpLyr with any data defined shape background values
453  QgsPalLabeling::dataDefinedShapeBackground( tmpLyr, ddValues );
454 
455  // update tmpLyr with any data defined drop shadow values
456  QgsPalLabeling::dataDefinedDropShadow( tmpLyr, ddValues );
457 
459 
460  // Render the components of a label in reverse order
461  // (backgrounds -> text)
462 
463  if ( tmpLyr.shadowDraw && tmpLyr.shadowUnder == QgsPalLayerSettings::ShadowLowest )
464  {
465  if ( tmpLyr.shapeDraw )
466  {
468  }
469  else if ( tmpLyr.bufferDraw )
470  {
472  }
473  else
474  {
476  }
477  }
478 
479  if ( tmpLyr.shapeDraw )
480  {
481  drawLabelPrivate( label, context, tmpLyr, QgsPalLabeling::LabelShape );
482  }
483 
484  if ( tmpLyr.bufferDraw )
485  {
486  drawLabelPrivate( label, context, tmpLyr, QgsPalLabeling::LabelBuffer );
487  }
488 
489  drawLabelPrivate( label, context, tmpLyr, QgsPalLabeling::LabelText );
490 
491  // add to the results
492  QString labeltext = label->getFeaturePart()->feature()->labelText();
493  mEngine->results()->mLabelSearchTree->insertLabel( label, label->getFeaturePart()->featureId(), mLayerId, labeltext, dFont, false, lf->hasFixedPosition() );
494 }
495 
496 
498 {
499  // NOTE: this is repeatedly called for multi-part labels
500  QPainter* painter = context.painter();
501 #if 1 // XXX strk
502  // features are pre-rotated but not scaled/translated,
503  // so we only disable rotation here. Ideally, they'd be
504  // also pre-scaled/translated, as suggested here:
505  // http://hub.qgis.org/issues/11856
506  QgsMapToPixel xform = context.mapToPixel();
507  xform.setMapRotation( 0, 0, 0 );
508 #else
509  const QgsMapToPixel& xform = context.mapToPixel();
510 #endif
511 
512  QgsLabelComponent component;
513  component.setDpiRatio( dpiRatio );
514 
515  QgsPoint outPt = xform.transform( label->getX(), label->getY() );
516 // QgsPoint outPt2 = xform->transform( label->getX() + label->getWidth(), label->getY() + label->getHeight() );
517 // QRectF labelRect( 0, 0, outPt2.x() - outPt.x(), outPt2.y() - outPt.y() );
518 
519  component.setOrigin( outPt );
520  component.setRotation( label->getAlpha() );
521 
522  if ( mEngine->testFlag( QgsLabelingEngineV2::DrawLabelRectOnly ) ) // TODO: this should get directly to labeling engine
523  {
524  //debugging rect
525  if ( drawType != QgsPalLabeling::LabelText )
526  return;
527 
528  QgsPoint outPt2 = xform.transform( label->getX() + label->getWidth(), label->getY() + label->getHeight() );
529  QRectF rect( 0, 0, outPt2.x() - outPt.x(), outPt2.y() - outPt.y() );
530  painter->save();
531  painter->setRenderHint( QPainter::Antialiasing, false );
532  painter->translate( QPointF( outPt.x(), outPt.y() ) );
533  painter->rotate( -label->getAlpha() * 180 / M_PI );
534 
535  if ( label->conflictsWithObstacle() )
536  {
537  painter->setBrush( QColor( 255, 0, 0, 100 ) );
538  painter->setPen( QColor( 255, 0, 0, 150 ) );
539  }
540  else
541  {
542  painter->setBrush( QColor( 0, 255, 0, 100 ) );
543  painter->setPen( QColor( 0, 255, 0, 150 ) );
544  }
545 
546  painter->drawRect( rect );
547  painter->restore();
548 
549  if ( label->getNextPart() )
550  drawLabelPrivate( label->getNextPart(), context, tmpLyr, drawType, dpiRatio );
551 
552  return;
553  }
554 
555  if ( drawType == QgsPalLabeling::LabelShape )
556  {
557  // get rotated label's center point
558  QgsPoint centerPt( outPt );
559  QgsPoint outPt2 = xform.transform( label->getX() + label->getWidth() / 2,
560  label->getY() + label->getHeight() / 2 );
561 
562  double xc = outPt2.x() - outPt.x();
563  double yc = outPt2.y() - outPt.y();
564 
565  double angle = -label->getAlpha();
566  double xd = xc * cos( angle ) - yc * sin( angle );
567  double yd = xc * sin( angle ) + yc * cos( angle );
568 
569  centerPt.setX( centerPt.x() + xd );
570  centerPt.setY( centerPt.y() + yd );
571 
572  component.setCenter( centerPt );
573  component.setSize( QgsPoint( label->getWidth(), label->getHeight() ) );
574 
575  QgsPalLabeling::drawLabelBackground( context, component, tmpLyr );
576  }
577 
578  else if ( drawType == QgsPalLabeling::LabelBuffer
579  || drawType == QgsPalLabeling::LabelText )
580  {
581 
582  // TODO: optimize access :)
583  QgsTextLabelFeature* lf = static_cast<QgsTextLabelFeature*>( label->getFeaturePart()->feature() );
584  QString txt = lf->text( label->getPartId() );
585  QFontMetricsF* labelfm = lf->labelFontMetrics();
586 
587  //add the direction symbol if needed
588  if ( !txt.isEmpty() && tmpLyr.placement == QgsPalLayerSettings::Line &&
589  tmpLyr.addDirectionSymbol )
590  {
591  bool prependSymb = false;
592  QString symb = tmpLyr.rightDirectionSymbol;
593 
594  if ( label->getReversed() )
595  {
596  prependSymb = true;
597  symb = tmpLyr.leftDirectionSymbol;
598  }
599 
600  if ( tmpLyr.reverseDirectionSymbol )
601  {
602  if ( symb == tmpLyr.rightDirectionSymbol )
603  {
604  prependSymb = true;
605  symb = tmpLyr.leftDirectionSymbol;
606  }
607  else
608  {
609  prependSymb = false;
610  symb = tmpLyr.rightDirectionSymbol;
611  }
612  }
613 
615  {
616  prependSymb = true;
617  symb = symb + QLatin1String( "\n" );
618  }
620  {
621  prependSymb = false;
622  symb = QLatin1String( "\n" ) + symb;
623  }
624 
625  if ( prependSymb )
626  {
627  txt.prepend( symb );
628  }
629  else
630  {
631  txt.append( symb );
632  }
633  }
634 
635  //QgsDebugMsgLevel( "drawLabel " + txt, 4 );
636  QStringList multiLineList = QgsPalLabeling::splitToLines( txt, tmpLyr.wrapChar );
637  int lines = multiLineList.size();
638 
639  double labelWidest = 0.0;
640  for ( int i = 0; i < lines; ++i )
641  {
642  double labelWidth = labelfm->width( multiLineList.at( i ) );
643  if ( labelWidth > labelWidest )
644  {
645  labelWidest = labelWidth;
646  }
647  }
648 
649  double labelHeight = labelfm->ascent() + labelfm->descent(); // ignore +1 for baseline
650  // double labelHighest = labelfm->height() + ( double )(( lines - 1 ) * labelHeight * tmpLyr.multilineHeight );
651 
652  // needed to move bottom of text's descender to within bottom edge of label
653  double ascentOffset = 0.25 * labelfm->ascent(); // labelfm->descent() is not enough
654 
655  for ( int i = 0; i < lines; ++i )
656  {
657  painter->save();
658 #if 0 // TODO: generalize some of this
659  LabelPosition* lp = label;
660  double w = lp->getWidth();
661  double h = lp->getHeight();
662  double cx = lp->getX() + w / 2.0;
663  double cy = lp->getY() + h / 2.0;
664  double scale = 1.0 / xform->mapUnitsPerPixel();
665  double rotation = xform->mapRotation();
666  double sw = w * scale;
667  double sh = h * scale;
668  QRectF rect( -sw / 2, -sh / 2, sw, sh );
669  painter->translate( xform->transform( QPointF( cx, cy ) ).toQPointF() );
670  if ( rotation )
671  {
672  // Only if not horizontal
673  if ( lp->getFeaturePart()->getLayer()->getArrangement() != P_POINT &&
674  lp->getFeaturePart()->getLayer()->getArrangement() != P_POINT_OVER &&
675  lp->getFeaturePart()->getLayer()->getArrangement() != P_HORIZ )
676  {
677  painter->rotate( rotation );
678  }
679  }
680  painter->translate( rect.bottomLeft() );
681  painter->rotate( -lp->getAlpha() * 180 / M_PI );
682 #else
683  painter->translate( QPointF( outPt.x(), outPt.y() ) );
684  painter->rotate( -label->getAlpha() * 180 / M_PI );
685 #endif
686 
687  // scale down painter: the font size has been multiplied by raster scale factor
688  // to workaround a Qt font scaling bug with small font sizes
689  painter->scale( 1.0 / tmpLyr.rasterCompressFactor, 1.0 / tmpLyr.rasterCompressFactor );
690 
691  // figure x offset for horizontal alignment of multiple lines
692  double xMultiLineOffset = 0.0;
693  double labelWidth = labelfm->width( multiLineList.at( i ) );
694  if ( lines > 1 && tmpLyr.multilineAlign != QgsPalLayerSettings::MultiLeft )
695  {
696  double labelWidthDiff = labelWidest - labelWidth;
698  {
699  labelWidthDiff /= 2;
700  }
701  xMultiLineOffset = labelWidthDiff;
702  //QgsDebugMsgLevel( QString( "xMultiLineOffset: %1" ).arg( xMultiLineOffset ), 4 );
703  }
704 
705  double yMultiLineOffset = ( lines - 1 - i ) * labelHeight * tmpLyr.multilineHeight;
706  painter->translate( QPointF( xMultiLineOffset, - ascentOffset - yMultiLineOffset ) );
707 
708  component.setText( multiLineList.at( i ) );
709  component.setSize( QgsPoint( labelWidth, labelHeight ) );
710  component.setOffset( QgsPoint( 0.0, -ascentOffset ) );
711  component.setRotation( -component.rotation() * 180 / M_PI );
712  component.setRotationOffset( 0.0 );
713 
714  if ( drawType == QgsPalLabeling::LabelBuffer )
715  {
716  // draw label's buffer
717  QgsPalLabeling::drawLabelBuffer( context, component, tmpLyr );
718  }
719  else
720  {
721  // draw label's text, QPainterPath method
722  QPainterPath path;
723  path.setFillRule( Qt::WindingFill );
724  path.addText( 0, 0, tmpLyr.textFont, component.text() );
725 
726  // store text's drawing in QPicture for drop shadow call
727  QPicture textPict;
728  QPainter textp;
729  textp.begin( &textPict );
730  textp.setPen( Qt::NoPen );
731  textp.setBrush( tmpLyr.textColor );
732  textp.drawPath( path );
733  // TODO: why are some font settings lost on drawPicture() when using drawText() inside QPicture?
734  // e.g. some capitalization options, but not others
735  //textp.setFont( tmpLyr.textFont );
736  //textp.setPen( tmpLyr.textColor );
737  //textp.drawText( 0, 0, component.text() );
738  textp.end();
739 
740  if ( tmpLyr.shadowDraw && tmpLyr.shadowUnder == QgsPalLayerSettings::ShadowText )
741  {
742  component.setPicture( &textPict );
743  component.setPictureBuffer( 0.0 ); // no pen width to deal with
744  component.setOrigin( QgsPoint( 0.0, 0.0 ) );
745 
746  QgsPalLabeling::drawLabelShadow( context, component, tmpLyr );
747  }
748 
749  // paint the text
750  if ( context.useAdvancedEffects() )
751  {
752  painter->setCompositionMode( tmpLyr.blendMode );
753  }
754 
755  // scale for any print output or image saving @ specific dpi
756  painter->scale( component.dpiRatio(), component.dpiRatio() );
757 
759  {
760  // draw outlined text
761  _fixQPictureDPI( painter );
762  painter->drawPicture( 0, 0, textPict );
763  }
764  else
765  {
766  // draw text as text (for SVG and PDF exports)
767  painter->setFont( tmpLyr.textFont );
768  painter->setPen( tmpLyr.textColor );
769  painter->setRenderHint( QPainter::TextAntialiasing );
770  painter->drawText( 0, 0, component.text() );
771  }
772  }
773  painter->restore();
774  }
775  }
776 
777  // NOTE: this used to be within above multi-line loop block, at end. (a mistake since 2010? [LS])
778  if ( label->getNextPart() )
779  drawLabelPrivate( label->getNextPart(), context, tmpLyr, drawType, dpiRatio );
780 }
Class for parsing and evaluation of expressions (formerly called "search strings").
void setExpressionParams(const QMap< QString, QVariant > &params)
bool hasEvalError() const
Returns true if an error occurred when evaluating last input.
Wrapper for iterator of features from vector data provider or vector layer.
QString name() const
Name of the layer (for statistics, debugging etc.) - does not need to be unique.
void close()
Closes the line string by appending the first point to the end of the line, if it is not already clos...
A rectangle specified with double values.
Definition: qgsrectangle.h:35
QString & append(QChar ch)
static void dataDefinedShapeBackground(QgsPalLayerSettings &tmpLyr, const QMap< QgsPalLayerSettings::DataDefinedProperties, QVariant > &ddValues)
void setMapRotation(double degrees, double cx, double cy)
Set map rotation in degrees (clockwise)
QStringList referencedColumns() const
Get list of columns referenced by the expression.
QgsPalLayerSettings::Placement mPlacement
Placement strategy.
static void dataDefinedTextStyle(QgsPalLayerSettings &tmpLyr, const QMap< QgsPalLayerSettings::DataDefinedProperties, QVariant > &ddValues)
A container class for data source field mapping or expression.
bool end()
void setOrigin(const QgsPoint &point)
void setCompositionMode(CompositionMode mode)
void setRenderHint(RenderHint hint, bool on)
QgsLabelFeature * feature()
Returns the parent feature.
Definition: feature.h:109
void registerFeature(QgsFeature &f, QgsRenderContext &context, const QString &dxfLayer, QgsLabelFeature **labelFeature=nullptr, QgsGeometry *obstacleGeometry=nullptr)
Register a feature for labelling.
double x() const
Returns the point&#39;s x-coordinate.
Definition: qgspointv2.h:68
SymbolType type() const
Definition: qgssymbolv2.h:104
double getWidth() const
Q_DECL_DEPRECATED bool prepare(const QgsFields &fields)
Get the expression ready for evaluation - find out column indexes.
UpsideDownLabels upsidedownLabels
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
double mPriority
Default priority of labels.
bool mOwnsSource
Whether layer&#39;s feature source is owned.
double xAt(int index) const
Returns the x-coordinate of the specified node in the line string.
QgsAbstractGeometryV2 * geometry() const
Returns the underlying geometry store.
Whether to show debugging rectangles for drop shadows.
int fieldNameIndex(const QString &fieldName) const
Look up field&#39;s index from name also looks up case-insensitive if there is no match otherwise...
Definition: qgsfield.cpp:503
QString & prepend(QChar ch)
double rendererScale() const
void scale(qreal sx, qreal sy)
const_iterator constBegin() const
QgsPoint transform(const QgsPoint &p) const
Transform the point from map (world) coordinates to device coordinates.
const T & at(int i) const
QgsVectorLayerLabelProvider(QgsVectorLayer *layer, bool withFeatureLoop=true, const QgsPalLayerSettings *settings=nullptr, const QString &layerName=QString())
Convenience constructor to initialize the provider from given vector layer.
static void drawLabelBuffer(QgsRenderContext &context, const QgsLabelComponent &component, const QgsPalLayerSettings &tmpLyr)
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
QgsRectangle visibleExtent() const
Return the actual extent derived from requested extent that takes takes output image size into accoun...
QGis::GeometryType type() const
Returns type of the geometry as a QGis::GeometryType.
Class that adds extra information to QgsLabelFeature for text labels.
void save()
Abstract base class for all geometries.
static QgsGeometry * getPointObstacleGeometry(QgsFeature &fet, QgsRenderContext &context, const QgsSymbolV2List &symbols)
Returns the geometry for a point feature which should be used as an obstacle for labels.
bool hasCrsTransformEnabled() const
returns true if projections are enabled for this layer set
Container of fields for a vector layer.
Definition: qgsfield.h:187
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:76
bool drawLabels
Whether to draw labels for this layer.
static void _fixQPictureDPI(QPainter *p)
const QgsRectangle & extent() const
const QgsMapToPixel & mapToPixel() const
static void dataDefinedDropShadow(QgsPalLayerSettings &tmpLyr, const QMap< QgsPalLayerSettings::DataDefinedProperties, QVariant > &ddValues)
MultiLineAlign multilineAlign
The QGis class provides global constants for use throughout the application.
Definition: qgis.h:36
double scaleFactor() const
whether to label each part of multi-part features separately
double rotation() const
Return the rotation of the resulting map image Units are clockwise degrees.
FeaturePart * getFeaturePart()
return the feature corresponding to this labelposition
void transform(const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection d=QgsCoordinateTransform::ForwardTransform) override
Transforms the geometry using a coordinate transform.
void rotate(qreal angle)
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:187
void addText(const QPointF &point, const QFont &font, const QString &text)
double dpiRatio() const
const QgsCoordinateTransform * coordinateTransform() const
static QStringList splitToLines(const QString &text, const QString &wrapCharacter)
Splits a text string to a list of separate lines, using a specified wrap character.
virtual bool prepare(const QgsRenderContext &context, QStringList &attributeNames)
Prepare for registration of features.
double mapRotation() const
Return current map rotation in degrees.
qreal width(const QString &text) const
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Definition: qgis.h:285
void setRotationOffset(const double rotation)
double x() const
Get the x value of the point.
Definition: qgspoint.h:128
int nCoordinates() const
Returns the number of nodes contained in the geometry.
static void drawLabelBackground(QgsRenderContext &context, QgsLabelComponent component, const QgsPalLayerSettings &tmpLyr)
Marker symbol.
Definition: qgssymbolv2.h:78
int size() const
virtual void startRender(QgsRenderContext &context, const QgsFields &fields)=0
Needs to be called when a new render cycle is started.
void reset(T *other)
QList< QgsLabelFeature * > mLabels
List of generated.
whether adjacent lines (with the same label text) should be merged
The QgsMapSettings class contains configuration for rendering of the map.
double y() const
Returns the point&#39;s y-coordinate.
Definition: qgspointv2.h:74
QString styleName() const
virtual void stopRender(QgsRenderContext &context)=0
Needs to be called when a render cycle has finished to clean up.
QgsLabelingResults * results() const
For internal use by the providers.
bool useAdvancedEffects() const
Returns true if advanced effects such as blend modes such be used.
virtual QList< QgsLabelFeature * > labelFeatures(QgsRenderContext &context) override
Return list of label features (they are owned by the provider and thus deleted on its destruction) ...
void init()
initialization method - called from constructors
virtual Q_DECL_DEPRECATED QgsSymbolV2List originalSymbolsForFeature(QgsFeature &feat)
Equivalent of originalSymbolsForFeature() call extended to support renderers that may use more symbol...
bool hasFixedPosition() const
Whether the label should use a fixed position instead of being automatically placed.
QgsGeometry * extentGeom
bool conflictsWithObstacle() const
Returns whether the position is marked as conflicting with an obstacle feature.
void drawRect(const QRectF &rectangle)
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:34
Polygon geometry type.
Definition: qgspolygonv2.h:29
double rotation() const
void transformInPlace(double &x, double &y, double &z, TransformDirection direction=ForwardTransform) const
void setFont(const QFont &font)
void transformInPlace(double &x, double &y) const
Transform device coordinates to map coordinates.
QgsExpressionContextScope * lastScope()
Returns the last scope added to the context.
ObstacleType obstacleType
Controls how features act as obstacles for labels.
void setRotation(const double rotation)
void append(const T &value)
static void dataDefinedTextBuffer(QgsPalLayerSettings &tmpLyr, const QMap< QgsPalLayerSettings::DataDefinedProperties, QVariant > &ddValues)
virtual void setExteriorRing(QgsCurveV2 *ring) override
Sets the exterior ring of the polygon.
const QgsCoordinateTransform * ct
void setFillRule(Qt::FillRule fillRule)
Utility class for identifying a unique vertex within a geometry.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:34
Line string geometry type, with support for z-dimension and m-values.
QPainter::CompositionMode blendMode
unsigned int mLinePlacementFlags
Extra placement flags for linestring geometries.
void setPen(const QColor &color)
const QgsMapSettings & mapSettings() const
Get associated map settings.
Quadrant getQuadrant() const
const QgsCoordinateReferenceSystem & destinationCrs() const
returns CRS of destination coordinate reference system
Point geometry type, with support for z-dimension and m-values.
Definition: qgspointv2.h:34
bool isEmpty() const
QPointF topLeft() const
QgsPalLayerSettings mSettings
Layer&#39;s labeling configuration.
bool isEmpty() const
const QMap< QgsPalLayerSettings::DataDefinedProperties, QVariant > & dataDefinedValues() const
Get data-defined values.
const_iterator constEnd() const
void setCenter(const QgsPoint &point)
double getY(int i=0) const
get the down-left y coordinate
#define M_PI
const QgsMapToPixel * xform
QMap< QgsPalLayerSettings::DataDefinedProperties, QgsDataDefined * > dataDefinedProperties
Map of current data defined properties.
QPaintDevice * device() const
This class wraps a request for features to a vector layer (or directly its vector data provider)...
Flags mFlags
Flags altering drawing and registration of features.
whether location of centroid must be inside of polygons
void setBrush(const QBrush &brush)
void drawText(const QPointF &position, const QString &text)
double rasterScaleFactor() const
void setText(const QString &text)
QString id() const
Get this layer&#39;s unique ID, this ID is used to access this layer from map layer registry.
const QgsLabelingEngineV2 * mEngine
Associated labeling engine.
QPointF topRight() const
double mapUnitsPerPixel() const
Return current map units per pixel.
LabelPosition * getNextPart() const
whether labels must fall completely within the polygon
QRectF united(const QRectF &rectangle) const
whether all features will be labelled even though overlaps occur
void setYAt(int index, double y)
Sets the y-coordinate of the specified node in the line string.
Single scope for storing variables and functions for use within a QgsExpressionContext.
Base class that can be used for any class that is capable of returning features.
double getX(int i=0) const
get the down-left x coordinate
double yAt(int index) const
Returns the y-coordinate of the specified node in the line string.
A class to represent a point.
Definition: qgspoint.h:65
The QgsAbstractLabelProvider class is an interface class.
bool getReversed() const
int logicalDpiX() const
int logicalDpiY() const
T * data() const
double ANALYSIS_EXPORT angle(Point3D *p1, Point3D *p2, Point3D *p3, Point3D *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
void setDpiRatio(const double ratio)
bool testFlag(Flag f) const
Test whether a particular flag is enabled.
QString layerId() const
Returns ID of associated layer, or empty string if no layer is associated with the provider...
virtual void registerFeature(QgsFeature &feature, QgsRenderContext &context, QgsGeometry *obstacleGeometry=nullptr)
Register a feature for labeling as one or more QgsLabelFeature objects stored into mLabels...
void setXAt(int index, double x)
Sets the x-coordinate of the specified node in the line string.
Partial snapshot of vector layer&#39;s state (only the members necessary for access to features) ...
void setX(double x)
Sets the x value of the point.
Definition: qgspoint.h:105
void setY(double y)
Sets the y value of the point.
Definition: qgspoint.h:113
QgsExpressionContext & expressionContext()
Gets the expression context.
double getAlpha() const
get alpha
unsigned int placementFlags
QgsPoint toMapCoordinates(int x, int y) const
void restore()
QgsFields mFields
Layer&#39;s fields.
bool isValid() const
QgsAbstractFeatureSource * mSource
Layer&#39;s feature source.
void addVertex(const QgsPointV2 &pt)
Adds a new vertex to the end of the line string.
QgsExpression * getLabelExpression()
Returns the QgsExpression for this label settings.
Arranges candidates over a point (or centroid of a polygon), or at a preset offset from the point...
Contains information about the context of a rendering operation.
QFont definedFont()
Font to be used for rendering.
void setPicture(QPicture *picture)
int getPartId() const
QString text(int partId) const
Returns the text component corresponding to a specified label part.
QPainter * painter()
The QgsLabelFeature class describes a feature that should be used within the labeling engine...
void drawPath(const QPainterPath &path)
Whether to only draw the label rect and not the actual label text (used for unit tests) ...
void setOffset(const QgsPoint &point)
QString mName
Name of the layer.
double getHeight() const
QString toString() const
qreal ascent() const
QgsCoordinateReferenceSystem mCrs
Layer&#39;s CRS.
bool fitInPolygonOnly
True if only labels which completely fit within a polygon are allowed.
int rotate(double rotation, const QgsPoint &center)
Rotate this geometry around the Z axis.
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
Class for storing a coordinate reference system (CRS)
QPointF bottomLeft() const
const QgsGeometry * constGeometry() const
Gets a const pointer to the geometry object associated with this feature.
Definition: qgsfeature.cpp:82
qreal descent() const
Class for doing transforms between two map coordinate systems.
static QgsGeometry * fromRect(const QgsRectangle &rect)
Creates a new geometry from a QgsRectangle.
LabelPosition is a candidate feature label position.
Definition: labelposition.h:50
void translate(const QPointF &offset)
QgsPalLayerSettings::ObstacleType mObstacleType
Type of the obstacle of feature geometries.
const QgsMapToPixel & mapToPixel() const
QgsPalLayerSettings::UpsideDownLabels mUpsidedownLabels
How to handle labels that would be upside down.
double y() const
Get the y value of the point.
Definition: qgspoint.h:136
Multi polygon geometry collection.
whether the labels should be rendered
iterator insert(const Key &key, const T &value)
bool isExpression
Is this label made from a expression string eg FieldName || &#39;mm&#39;.
bool isEmpty() const
Returns true if the geometry is empty (ie, contains no underlying geometry accessible via geometry)...
void setSize(const QgsPoint &point)
void drawPicture(const QPointF &point, const QPicture &picture)
QPointF bottomRight() const
virtual QgsFeatureIterator getFeatures(const QgsFeatureRequest &request)=0
Get an iterator for features matching the specified request.
void setPictureBuffer(const double buffer)
QgsExpressionContextScope * popScope()
Removes the last scope from the expression context and return it.
bool nextFeature(QgsFeature &f)
QFontMetricsF * labelFontMetrics()
Metrics of the font for rendering.
bool insertLabel(pal::LabelPosition *labelPos, int featureId, const QString &layerName, const QString &labeltext, const QFont &labelfont, bool diagram=false, bool pinned=false)
Inserts label position.
Represents a vector layer which manages a vector based data sets.
bool begin(QPaintDevice *device)
QString mLayerId
Associated layer&#39;s ID, if applicable.
static QgsExpressionContextScope * updateSymbolScope(const QgsSymbolV2 *symbol, QgsExpressionContextScope *symbolScope=nullptr)
Updates a symbol scope related to a QgsSymbolV2 to an expression context.
Q_GUI_EXPORT int qt_defaultDpiY()
QString text() const
Whether to render labels as text or outlines.
QgsPoint center() const
Center point of the rectangle.
Definition: qgsrectangle.h:217
QString labelText() const
Text of the label.
QString evalErrorString() const
Returns evaluation error.
bool isActive() const
Maintains current state of more grainular and temporal values when creating/painting component parts ...
virtual void drawLabel(QgsRenderContext &context, pal::LabelPosition *label) const override
draw this label at the position determined by the labeling engine
Q_DECL_DEPRECATED QStringList referencedColumns(QgsVectorLayer *layer)
Returns the columns referenced by the QgsDataDefined.
Q_GUI_EXPORT int qt_defaultDpiX()
QgsFeatureRequest & setFilterRect(const QgsRectangle &rect)
Set rectangle from which features will be taken.
virtual QgsPointV2 vertexAt(QgsVertexId id) const =0
Returns the point corresponding to a specified vertex id.
QgsRectangle transformBoundingBox(const QgsRectangle &theRect, TransformDirection direction=ForwardTransform, const bool handle180Crossover=false) const
Transform a QgsRectangle to the dest Coordinate system If the direction is ForwardTransform then coor...
QGis::GeometryType mLayerGeometryType
Geometry type of layer.
int numPoints() const override
Returns the number of points in the curve.
void drawLabelPrivate(pal::LabelPosition *label, QgsRenderContext &context, QgsPalLayerSettings &tmpLyr, QgsPalLabeling::DrawLabelType drawType, double dpiRatio=1.0) const
Internal label drawing method.
QgsCoordinateTransform * clone() const
const T value(const Key &key) const
QgsFeatureId featureId() const
Returns the unique ID of the feature.
Definition: feature.cpp:154
DirectionSymbols placeDirectionSymbol
QPointF toQPointF() const
Converts a point to a QPointF.
Definition: qgspoint.cpp:121
static void drawLabelShadow(QgsRenderContext &context, const QgsLabelComponent &component, const QgsPalLayerSettings &tmpLyr)
static void dataDefinedTextFormatting(QgsPalLayerSettings &tmpLyr, const QMap< QgsPalLayerSettings::DataDefinedProperties, QVariant > &ddValues)