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