QGIS API Documentation  2.12.0-Lyon
qgspallabeling.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgspallabeling.cpp
3  Smart labeling for vector layers
4  -------------------
5  begin : June 2009
6  copyright : (C) Martin Dobias
7  email : wonder dot sk at gmail dot com
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 "qgspallabeling.h"
19 #include "qgspalgeometry.h"
20 
21 #include <list>
22 
23 #include <pal/pal.h>
24 #include <pal/feature.h>
25 #include <pal/layer.h>
26 #include <pal/palexception.h>
27 #include <pal/problem.h>
28 #include <pal/labelposition.h>
29 
30 #include <cmath>
31 
32 #include <QApplication>
33 #include <QByteArray>
34 #include <QString>
35 #include <QFontMetrics>
36 #include <QTime>
37 #include <QPainter>
38 
39 #include "diagram/qgsdiagram.h"
40 #include "qgsdiagramrendererv2.h"
41 #include "qgsfontutils.h"
42 #include "qgslabelsearchtree.h"
43 #include "qgsexpression.h"
44 #include "qgsdatadefined.h"
45 #include "qgslabelingenginev2.h"
46 #include "qgsvectorlayerlabeling.h"
47 
48 #include <qgslogger.h>
49 #include <qgsvectorlayer.h>
50 #include <qgsmaplayerregistry.h>
51 #include <qgsvectordataprovider.h>
54 #include <qgsgeometry.h>
55 #include <qgsmaprenderer.h>
56 #include <qgsmarkersymbollayerv2.h>
57 #include <qgsproject.h>
58 #include "qgssymbolv2.h"
59 #include "qgssymbollayerv2utils.h"
60 #include <QMessageBox>
61 
62 
63 Q_GUI_EXPORT extern int qt_defaultDpiX();
64 Q_GUI_EXPORT extern int qt_defaultDpiY();
65 
66 static void _fixQPictureDPI( QPainter* p )
67 {
68  // QPicture makes an assumption that we drawing to it with system DPI.
69  // Then when being drawn, it scales the painter. The following call
70  // negates the effect. There is no way of setting QPicture's DPI.
71  // See QTBUG-20361
72  p->scale(( double )qt_defaultDpiX() / p->device()->logicalDpiX(),
73  ( double )qt_defaultDpiY() / p->device()->logicalDpiY() );
74 }
75 
76 
77 using namespace pal;
78 
79 // -------------
80 
82  : upsidedownLabels( Upright )
83  , mCurFeat( 0 )
84  , xform( NULL )
85  , ct( NULL )
86  , extentGeom( NULL )
87  , mFeaturesToLabel( 0 )
88  , mFeatsSendingToPal( 0 )
89  , mFeatsRegPal( 0 )
90  , expression( 0 )
91 {
92  enabled = false;
93  drawLabels = true;
94  isExpression = false;
95  fieldIndex = 0;
96 
97  // text style
99  fontSizeInMapUnits = false;
100  textColor = Qt::black;
101  textTransp = 0;
102  blendMode = QPainter::CompositionMode_SourceOver;
103  previewBkgrdColor = Qt::white;
104  // font processing info
105  mTextFontFound = true;
107 
108  // text formatting
109  wrapChar = "";
110  multilineHeight = 1.0;
112  addDirectionSymbol = false;
113  leftDirectionSymbol = QString( "<" );
114  rightDirectionSymbol = QString( ">" );
115  reverseDirectionSymbol = false;
117  formatNumbers = false;
118  decimals = 3;
119  plusSign = false;
120 
121  // text buffer
122  bufferDraw = false;
123  bufferSize = 1.0;
124  bufferSizeInMapUnits = false;
125  bufferColor = Qt::white;
126  bufferTransp = 0;
127  bufferNoFill = false;
128  bufferJoinStyle = Qt::BevelJoin;
129  bufferBlendMode = QPainter::CompositionMode_SourceOver;
130 
131  // shape background
132  shapeDraw = false;
134  shapeSVGFile = QString();
136  shapeSize = QPointF( 0.0, 0.0 );
137  shapeSizeUnits = MM;
139  shapeRotation = 0.0;
140  shapeOffset = QPointF( 0.0, 0.0 );
142  shapeRadii = QPointF( 0.0, 0.0 );
144  shapeFillColor = Qt::white;
145  shapeBorderColor = Qt::darkGray;
146  shapeBorderWidth = 0.0;
148  shapeJoinStyle = Qt::BevelJoin;
149  shapeTransparency = 0;
150  shapeBlendMode = QPainter::CompositionMode_SourceOver;
151 
152  // drop shadow
153  shadowDraw = false;
155  shadowOffsetAngle = 135;
156  shadowOffsetDist = 1.0;
158  shadowOffsetGlobal = true;
159  shadowRadius = 1.5;
161  shadowRadiusAlphaOnly = false;
162  shadowTransparency = 30;
163  shadowScale = 100;
164  shadowColor = Qt::black;
165  shadowBlendMode = QPainter::CompositionMode_Multiply;
166 
167  // placement
170  centroidWhole = false;
171  centroidInside = false;
172  fitInPolygonOnly = false;
174  xOffset = 0;
175  yOffset = 0;
176  labelOffsetInMapUnits = true;
177  dist = 0;
178  distInMapUnits = false;
179  angleOffset = 0;
180  preserveRotation = true;
181  maxCurvedCharAngleIn = 20.0;
182  maxCurvedCharAngleOut = -20.0;
183  priority = 5;
184  repeatDistance = 0;
186 
187  // rendering
188  scaleVisibility = false;
189  scaleMin = 1;
190  scaleMax = 10000000;
191  fontLimitPixelSize = false;
192  fontMinPixelSize = 0; //trigger to turn it on by default for map unit labels
193  fontMaxPixelSize = 10000;
194  displayAll = false;
196 
197  labelPerPart = false;
198  mergeLines = false;
199  minFeatureSize = 0.0;
200  limitNumLabels = false;
201  maxNumLabels = 2000;
202  obstacle = true;
203  obstacleFactor = 1.0;
205 
206  // scale factors
207  vectorScaleFactor = 1.0;
208  rasterCompressFactor = 1.0;
209 
210  // data defined string and old-style index values
211  // NOTE: in QPair use -1 for second value (other values are for old-style layer properties migration)
212 
213  // text style
214  mDataDefinedNames.insert( Size, QPair<QString, int>( "Size", 0 ) );
215  mDataDefinedNames.insert( Bold, QPair<QString, int>( "Bold", 1 ) );
216  mDataDefinedNames.insert( Italic, QPair<QString, int>( "Italic", 2 ) );
217  mDataDefinedNames.insert( Underline, QPair<QString, int>( "Underline", 3 ) );
218  mDataDefinedNames.insert( Color, QPair<QString, int>( "Color", 4 ) );
219  mDataDefinedNames.insert( Strikeout, QPair<QString, int>( "Strikeout", 5 ) );
220  mDataDefinedNames.insert( Family, QPair<QString, int>( "Family", 6 ) );
221  mDataDefinedNames.insert( FontStyle, QPair<QString, int>( "FontStyle", -1 ) );
222  mDataDefinedNames.insert( FontSizeUnit, QPair<QString, int>( "FontSizeUnit", -1 ) );
223  mDataDefinedNames.insert( FontTransp, QPair<QString, int>( "FontTransp", 18 ) );
224  mDataDefinedNames.insert( FontCase, QPair<QString, int>( "FontCase", -1 ) );
225  mDataDefinedNames.insert( FontLetterSpacing, QPair<QString, int>( "FontLetterSpacing", -1 ) );
226  mDataDefinedNames.insert( FontWordSpacing, QPair<QString, int>( "FontWordSpacing", -1 ) );
227  mDataDefinedNames.insert( FontBlendMode, QPair<QString, int>( "FontBlendMode", -1 ) );
228 
229  // text formatting
230  mDataDefinedNames.insert( MultiLineWrapChar, QPair<QString, int>( "MultiLineWrapChar", -1 ) );
231  mDataDefinedNames.insert( MultiLineHeight, QPair<QString, int>( "MultiLineHeight", -1 ) );
232  mDataDefinedNames.insert( MultiLineAlignment, QPair<QString, int>( "MultiLineAlignment", -1 ) );
233  mDataDefinedNames.insert( DirSymbDraw, QPair<QString, int>( "DirSymbDraw", -1 ) );
234  mDataDefinedNames.insert( DirSymbLeft, QPair<QString, int>( "DirSymbLeft", -1 ) );
235  mDataDefinedNames.insert( DirSymbRight, QPair<QString, int>( "DirSymbRight", -1 ) );
236  mDataDefinedNames.insert( DirSymbPlacement, QPair<QString, int>( "DirSymbPlacement", -1 ) );
237  mDataDefinedNames.insert( DirSymbReverse, QPair<QString, int>( "DirSymbReverse", -1 ) );
238  mDataDefinedNames.insert( NumFormat, QPair<QString, int>( "NumFormat", -1 ) );
239  mDataDefinedNames.insert( NumDecimals, QPair<QString, int>( "NumDecimals", -1 ) );
240  mDataDefinedNames.insert( NumPlusSign, QPair<QString, int>( "NumPlusSign", -1 ) );
241 
242  // text buffer
243  mDataDefinedNames.insert( BufferDraw, QPair<QString, int>( "BufferDraw", -1 ) );
244  mDataDefinedNames.insert( BufferSize, QPair<QString, int>( "BufferSize", 7 ) );
245  mDataDefinedNames.insert( BufferUnit, QPair<QString, int>( "BufferUnit", -1 ) );
246  mDataDefinedNames.insert( BufferColor, QPair<QString, int>( "BufferColor", 8 ) );
247  mDataDefinedNames.insert( BufferTransp, QPair<QString, int>( "BufferTransp", 19 ) );
248  mDataDefinedNames.insert( BufferJoinStyle, QPair<QString, int>( "BufferJoinStyle", -1 ) );
249  mDataDefinedNames.insert( BufferBlendMode, QPair<QString, int>( "BufferBlendMode", -1 ) );
250 
251  // background
252  mDataDefinedNames.insert( ShapeDraw, QPair<QString, int>( "ShapeDraw", -1 ) );
253  mDataDefinedNames.insert( ShapeKind, QPair<QString, int>( "ShapeKind", -1 ) );
254  mDataDefinedNames.insert( ShapeSVGFile, QPair<QString, int>( "ShapeSVGFile", -1 ) );
255  mDataDefinedNames.insert( ShapeSizeType, QPair<QString, int>( "ShapeSizeType", -1 ) );
256  mDataDefinedNames.insert( ShapeSizeX, QPair<QString, int>( "ShapeSizeX", -1 ) );
257  mDataDefinedNames.insert( ShapeSizeY, QPair<QString, int>( "ShapeSizeY", -1 ) );
258  mDataDefinedNames.insert( ShapeSizeUnits, QPair<QString, int>( "ShapeSizeUnits", -1 ) );
259  mDataDefinedNames.insert( ShapeRotationType, QPair<QString, int>( "ShapeRotationType", -1 ) );
260  mDataDefinedNames.insert( ShapeRotation, QPair<QString, int>( "ShapeRotation", -1 ) );
261  mDataDefinedNames.insert( ShapeOffset, QPair<QString, int>( "ShapeOffset", -1 ) );
262  mDataDefinedNames.insert( ShapeOffsetUnits, QPair<QString, int>( "ShapeOffsetUnits", -1 ) );
263  mDataDefinedNames.insert( ShapeRadii, QPair<QString, int>( "ShapeRadii", -1 ) );
264  mDataDefinedNames.insert( ShapeRadiiUnits, QPair<QString, int>( "ShapeRadiiUnits", -1 ) );
265  mDataDefinedNames.insert( ShapeTransparency, QPair<QString, int>( "ShapeTransparency", -1 ) );
266  mDataDefinedNames.insert( ShapeBlendMode, QPair<QString, int>( "ShapeBlendMode", -1 ) );
267  mDataDefinedNames.insert( ShapeFillColor, QPair<QString, int>( "ShapeFillColor", -1 ) );
268  mDataDefinedNames.insert( ShapeBorderColor, QPair<QString, int>( "ShapeBorderColor", -1 ) );
269  mDataDefinedNames.insert( ShapeBorderWidth, QPair<QString, int>( "ShapeBorderWidth", -1 ) );
270  mDataDefinedNames.insert( ShapeBorderWidthUnits, QPair<QString, int>( "ShapeBorderWidthUnits", -1 ) );
271  mDataDefinedNames.insert( ShapeJoinStyle, QPair<QString, int>( "ShapeJoinStyle", -1 ) );
272 
273  // drop shadow
274  mDataDefinedNames.insert( ShadowDraw, QPair<QString, int>( "ShadowDraw", -1 ) );
275  mDataDefinedNames.insert( ShadowUnder, QPair<QString, int>( "ShadowUnder", -1 ) );
276  mDataDefinedNames.insert( ShadowOffsetAngle, QPair<QString, int>( "ShadowOffsetAngle", -1 ) );
277  mDataDefinedNames.insert( ShadowOffsetDist, QPair<QString, int>( "ShadowOffsetDist", -1 ) );
278  mDataDefinedNames.insert( ShadowOffsetUnits, QPair<QString, int>( "ShadowOffsetUnits", -1 ) );
279  mDataDefinedNames.insert( ShadowRadius, QPair<QString, int>( "ShadowRadius", -1 ) );
280  mDataDefinedNames.insert( ShadowRadiusUnits, QPair<QString, int>( "ShadowRadiusUnits", -1 ) );
281  mDataDefinedNames.insert( ShadowTransparency, QPair<QString, int>( "ShadowTransparency", -1 ) );
282  mDataDefinedNames.insert( ShadowScale, QPair<QString, int>( "ShadowScale", -1 ) );
283  mDataDefinedNames.insert( ShadowColor, QPair<QString, int>( "ShadowColor", -1 ) );
284  mDataDefinedNames.insert( ShadowBlendMode, QPair<QString, int>( "ShadowBlendMode", -1 ) );
285 
286  // placement
287  mDataDefinedNames.insert( CentroidWhole, QPair<QString, int>( "CentroidWhole", -1 ) );
288  mDataDefinedNames.insert( OffsetQuad, QPair<QString, int>( "OffsetQuad", -1 ) );
289  mDataDefinedNames.insert( OffsetXY, QPair<QString, int>( "OffsetXY", -1 ) );
290  mDataDefinedNames.insert( OffsetUnits, QPair<QString, int>( "OffsetUnits", -1 ) );
291  mDataDefinedNames.insert( LabelDistance, QPair<QString, int>( "LabelDistance", 13 ) );
292  mDataDefinedNames.insert( DistanceUnits, QPair<QString, int>( "DistanceUnits", -1 ) );
293  mDataDefinedNames.insert( OffsetRotation, QPair<QString, int>( "OffsetRotation", -1 ) );
294  mDataDefinedNames.insert( CurvedCharAngleInOut, QPair<QString, int>( "CurvedCharAngleInOut", -1 ) );
295  mDataDefinedNames.insert( RepeatDistance, QPair<QString, int>( "RepeatDistance", -1 ) );
296  mDataDefinedNames.insert( RepeatDistanceUnit, QPair<QString, int>( "RepeatDistanceUnit", -1 ) );
297  mDataDefinedNames.insert( Priority, QPair<QString, int>( "Priority", -1 ) );
298  mDataDefinedNames.insert( IsObstacle, QPair<QString, int>( "IsObstacle", -1 ) );
299  mDataDefinedNames.insert( ObstacleFactor, QPair<QString, int>( "ObstacleFactor", -1 ) );
300 
301  // (data defined only)
302  mDataDefinedNames.insert( PositionX, QPair<QString, int>( "PositionX", 9 ) );
303  mDataDefinedNames.insert( PositionY, QPair<QString, int>( "PositionY", 10 ) );
304  mDataDefinedNames.insert( Hali, QPair<QString, int>( "Hali", 11 ) );
305  mDataDefinedNames.insert( Vali, QPair<QString, int>( "Vali", 12 ) );
306  mDataDefinedNames.insert( Rotation, QPair<QString, int>( "Rotation", 14 ) );
307 
308  //rendering
309  mDataDefinedNames.insert( ScaleVisibility, QPair<QString, int>( "ScaleVisibility", -1 ) );
310  mDataDefinedNames.insert( MinScale, QPair<QString, int>( "MinScale", 16 ) );
311  mDataDefinedNames.insert( MaxScale, QPair<QString, int>( "MaxScale", 17 ) );
312  mDataDefinedNames.insert( FontLimitPixel, QPair<QString, int>( "FontLimitPixel", -1 ) );
313  mDataDefinedNames.insert( FontMinPixel, QPair<QString, int>( "FontMinPixel", -1 ) );
314  mDataDefinedNames.insert( FontMaxPixel, QPair<QString, int>( "FontMaxPixel", -1 ) );
315  // (data defined only)
316  mDataDefinedNames.insert( Show, QPair<QString, int>( "Show", 15 ) );
317  mDataDefinedNames.insert( AlwaysShow, QPair<QString, int>( "AlwaysShow", 20 ) );
318 
319  // temp stuff for when drawing label components (don't copy)
320  showingShadowRects = false;
321 }
322 
324  : mCurFeat( NULL )
325  , fieldIndex( 0 )
326  , xform( NULL )
327  , ct( NULL )
328  , extentGeom( NULL )
329  , mFeaturesToLabel( 0 )
330  , mFeatsSendingToPal( 0 )
331  , mFeatsRegPal( 0 )
332  , showingShadowRects( false )
333  , expression( NULL )
334 {
335  *this = s;
336 }
337 
339 {
340  if ( this == &s )
341  return *this;
342 
343  // copy only permanent stuff
344 
345  enabled = s.enabled;
347 
348  // text style
349  fieldName = s.fieldName;
351  textFont = s.textFont;
355  textColor = s.textColor;
357  blendMode = s.blendMode;
359  // font processing info
362 
363  // text formatting
364  wrapChar = s.wrapChar;
373  decimals = s.decimals;
374  plusSign = s.plusSign;
375 
376  // text buffer
386 
387  // placement
388  placement = s.placement;
394  xOffset = s.xOffset;
395  yOffset = s.yOffset;
398  dist = s.dist;
405  priority = s.priority;
409 
410  // rendering
412  scaleMin = s.scaleMin;
413  scaleMax = s.scaleMax;
419 
425  obstacle = s.obstacle;
428 
429  // shape background
430  shapeDraw = s.shapeDraw;
431  shapeType = s.shapeType;
434  shapeSize = s.shapeSize;
453 
454  // drop shadow
470 
471  // data defined
474  for ( ; it != s.dataDefinedProperties.constEnd(); ++it )
475  {
476  dataDefinedProperties.insert( it.key(), it.value() ? new QgsDataDefined( *it.value() ) : 0 );
477  }
478  mDataDefinedNames = s.mDataDefinedNames;
479 
480  // scale factors
483  return *this;
484 }
485 
486 
488 {
489  // pal layer is deleted internally in PAL
490 
491  delete ct;
492  delete expression;
493  delete extentGeom;
494 
495  // delete all QgsDataDefined objects (which also deletes their QgsExpression object)
497 }
498 
499 
501 {
502  QgsPalLayerSettings settings;
503  settings.readFromLayer( layer );
504  return settings;
505 }
506 
507 
509 {
510  if ( expression == NULL )
511  {
512  expression = new QgsExpression( fieldName );
513  }
514  return expression;
515 }
516 
517 static QColor _readColor( QgsVectorLayer* layer, const QString& property, const QColor& defaultColor = Qt::black, bool withAlpha = true )
518 {
519  int r = layer->customProperty( property + "R", QVariant( defaultColor.red() ) ).toInt();
520  int g = layer->customProperty( property + "G", QVariant( defaultColor.green() ) ).toInt();
521  int b = layer->customProperty( property + "B", QVariant( defaultColor.blue() ) ).toInt();
522  int a = withAlpha ? layer->customProperty( property + "A", QVariant( defaultColor.alpha() ) ).toInt() : 255;
523  return QColor( r, g, b, a );
524 }
525 
526 static void _writeColor( QgsVectorLayer* layer, const QString& property, const QColor& color, bool withAlpha = true )
527 {
528  layer->setCustomProperty( property + "R", color.red() );
529  layer->setCustomProperty( property + "G", color.green() );
530  layer->setCustomProperty( property + "B", color.blue() );
531  if ( withAlpha )
532  layer->setCustomProperty( property + "A", color.alpha() );
533 }
534 
536 {
537  if ( str.compare( "Point", Qt::CaseInsensitive ) == 0
538  || str.compare( "Points", Qt::CaseInsensitive ) == 0 ) return QgsPalLayerSettings::Points;
539  if ( str.compare( "MapUnit", Qt::CaseInsensitive ) == 0
540  || str.compare( "MapUnits", Qt::CaseInsensitive ) == 0 ) return QgsPalLayerSettings::MapUnits;
541  if ( str.compare( "Percent", Qt::CaseInsensitive ) == 0 ) return QgsPalLayerSettings::Percent;
542  return QgsPalLayerSettings::MM; // "MM"
543 }
544 
545 static Qt::PenJoinStyle _decodePenJoinStyle( const QString& str )
546 {
547  if ( str.compare( "Miter", Qt::CaseInsensitive ) == 0 ) return Qt::MiterJoin;
548  if ( str.compare( "Round", Qt::CaseInsensitive ) == 0 ) return Qt::RoundJoin;
549  return Qt::BevelJoin; // "Bevel"
550 }
551 
552 void QgsPalLayerSettings::readDataDefinedPropertyMap( QgsVectorLayer* layer, QDomElement* parentElem,
554 {
555  if ( !layer && !parentElem )
556  {
557  return;
558  }
559 
561  while ( i.hasNext() )
562  {
563  i.next();
564  if ( layer )
565  {
566  // reading from layer's custom properties (old way)
567  readDataDefinedProperty( layer, i.key(), propertyMap );
568  }
569  else if ( parentElem )
570  {
571  // reading from XML (new way)
572  QDomElement e = parentElem->firstChildElement( i.value().first );
573  if ( !e.isNull() )
574  {
575  QgsDataDefined* dd = new QgsDataDefined();
576  if ( dd->setFromXmlElement( e ) )
577  propertyMap.insert( i.key(), dd );
578  else
579  delete dd;
580  }
581  }
582  }
583 }
584 
585 void QgsPalLayerSettings::writeDataDefinedPropertyMap( QgsVectorLayer* layer, QDomElement* parentElem,
587 {
588  if ( !layer && !parentElem )
589  {
590  return;
591  }
592 
594  while ( i.hasNext() )
595  {
596  i.next();
597  QString newPropertyName = "labeling/dataDefined/" + i.value().first;
598  QVariant propertyValue = QVariant();
599 
601  if ( it != propertyMap.constEnd() )
602  {
603  QgsDataDefined* dd = it.value();
604  if ( dd )
605  {
606  bool active = dd->isActive();
607  bool useExpr = dd->useExpression();
608  QString expr = dd->expressionString();
609  QString field = dd->field();
610 
611  bool defaultVals = ( !active && !useExpr && expr.isEmpty() && field.isEmpty() );
612 
613  if ( !defaultVals )
614  {
615  // TODO: update this when project settings for labeling are migrated to better XML layout
616  QStringList values;
617  values << ( active ? "1" : "0" );
618  values << ( useExpr ? "1" : "0" );
619  values << expr;
620  values << field;
621  if ( !values.isEmpty() )
622  {
623  propertyValue = QVariant( values.join( "~~" ) );
624  }
625  }
626 
627  if ( parentElem )
628  {
629  // writing to XML document (instead of writing to layer)
630  QDomDocument doc = parentElem->ownerDocument();
631  QDomElement e = dd->toXmlElement( doc, i.value().first );
632  parentElem->appendChild( e );
633  }
634  }
635  }
636 
637  if ( layer )
638  {
639  // writing to layer's custom properties (old method)
640 
641  if ( propertyValue.isValid() )
642  {
643  layer->setCustomProperty( newPropertyName, propertyValue );
644  }
645  else
646  {
647  // remove unused properties
648  layer->removeCustomProperty( newPropertyName );
649  }
650 
651  if ( layer->customProperty( newPropertyName, QVariant() ).isValid() && i.value().second > -1 )
652  {
653  // remove old-style field index-based property, if still present
654  layer->removeCustomProperty( QString( "labeling/dataDefinedProperty" ) + QString::number( i.value().second ) );
655  }
656  }
657  }
658 }
659 
660 void QgsPalLayerSettings::readDataDefinedProperty( QgsVectorLayer* layer,
663 {
664  QString newPropertyName = "labeling/dataDefined/" + mDataDefinedNames.value( p ).first;
665  QVariant newPropertyField = layer->customProperty( newPropertyName, QVariant() );
666 
667  QString ddString = QString();
668  if ( newPropertyField.isValid() )
669  {
670  ddString = newPropertyField.toString();
671  }
672  else // maybe working with old-style field index-based property (< QGIS 2.0)
673  {
674  int oldIndx = mDataDefinedNames.value( p ).second;
675 
676  if ( oldIndx < 0 ) // something went wrong and we are working with new-style
677  {
678  return;
679  }
680 
681  QString oldPropertyName = "labeling/dataDefinedProperty" + QString::number( oldIndx );
682  QVariant oldPropertyField = layer->customProperty( oldPropertyName, QVariant() );
683 
684  if ( !oldPropertyField.isValid() )
685  {
686  return;
687  }
688 
689  // switch from old-style field index- to name-based properties
690  bool conversionOk;
691  int indx = oldPropertyField.toInt( &conversionOk );
692 
693  if ( conversionOk )
694  {
695  // Fix to migrate from old-style vector api, where returned QMap keys possibly
696  // had 'holes' in sequence of field indices, e.g. 0,2,3
697  // QgsAttrPalIndexNameHash provides a means of access field name in sequences from
698  // providers that procuded holes (e.g. PostGIS skipped geom column), otherwise it is empty
699  QgsAttrPalIndexNameHash oldIndicesToNames = layer->dataProvider()->palAttributeIndexNames();
700 
701  if ( !oldIndicesToNames.isEmpty() )
702  {
703  ddString = oldIndicesToNames.value( indx );
704  }
705  else
706  {
707  QgsFields fields = layer->dataProvider()->fields();
708  if ( indx < fields.size() ) // in case field count has changed
709  {
710  ddString = fields.at( indx ).name();
711  }
712  }
713  }
714 
715  if ( !ddString.isEmpty() )
716  {
717  //upgrade any existing property to field name-based
718  layer->setCustomProperty( newPropertyName, QVariant( updateDataDefinedString( ddString ) ) );
719 
720  // fix for buffer drawing triggered off of just its data defined size in the past (<2.0)
721  if ( oldIndx == 7 ) // old bufferSize enum
722  {
723  bufferDraw = true;
724  layer->setCustomProperty( "labeling/bufferDraw", true );
725  }
726 
727  // fix for scale visibility limits triggered off of just its data defined values in the past (<2.0)
728  if ( oldIndx == 16 || oldIndx == 17 ) // old minScale and maxScale enums
729  {
730  scaleVisibility = true;
731  layer->setCustomProperty( "labeling/scaleVisibility", true );
732  }
733  }
734 
735  // remove old-style field index-based property
736  layer->removeCustomProperty( oldPropertyName );
737  }
738 
739  if ( !ddString.isEmpty() && ddString != QLatin1String( "0~~0~~~~" ) )
740  {
741  // TODO: update this when project settings for labeling are migrated to better XML layout
742  QString newStyleString = updateDataDefinedString( ddString );
743  QStringList ddv = newStyleString.split( "~~" );
744 
745  QgsDataDefined* dd = new QgsDataDefined( ddv.at( 0 ).toInt(), ddv.at( 1 ).toInt(), ddv.at( 2 ), ddv.at( 3 ) );
746  propertyMap.insert( p, dd );
747  }
748  else
749  {
750  // remove unused properties
751  layer->removeCustomProperty( newPropertyName );
752  }
753 }
754 
756 {
757  if ( layer->customProperty( "labeling" ).toString() != QLatin1String( "pal" ) )
758  {
759  // for polygons the "over point" (over centroid) placement is better than the default
760  // "around point" (around centroid) which is more suitable for points
761  if ( layer->geometryType() == QGis::Polygon )
763 
764  return; // there's no information available
765  }
766 
767  // NOTE: set defaults for newly added properties, for backwards compatibility
768 
769  enabled = layer->labelsEnabled();
770  drawLabels = layer->customProperty( "labeling/drawLabels", true ).toBool();
771 
772  // text style
773  fieldName = layer->customProperty( "labeling/fieldName" ).toString();
774  isExpression = layer->customProperty( "labeling/isExpression" ).toBool();
775  QFont appFont = QApplication::font();
776  mTextFontFamily = layer->customProperty( "labeling/fontFamily", QVariant( appFont.family() ) ).toString();
777  QString fontFamily = mTextFontFamily;
779  {
780  // trigger to notify user about font family substitution (signal emitted in QgsVectorLayer::prepareLabelingAndDiagrams)
781  mTextFontFound = false;
782 
783  // TODO: update when pref for how to resolve missing family (use matching algorithm or just default font) is implemented
784  // currently only defaults to matching algorithm for resolving [foundry], if a font of similar family is found (default for QFont)
785 
786  // for now, do not use matching algorithm for substitution if family not found, substitute default instead
787  fontFamily = appFont.family();
788  }
789 
790  double fontSize = layer->customProperty( "labeling/fontSize" ).toDouble();
791  fontSizeInMapUnits = layer->customProperty( "labeling/fontSizeInMapUnits" ).toBool();
792  fontSizeMapUnitScale.minScale = layer->customProperty( "labeling/fontSizeMapUnitMinScale", 0.0 ).toDouble();
793  fontSizeMapUnitScale.maxScale = layer->customProperty( "labeling/fontSizeMapUnitMaxScale", 0.0 ).toDouble();
794  int fontWeight = layer->customProperty( "labeling/fontWeight" ).toInt();
795  bool fontItalic = layer->customProperty( "labeling/fontItalic" ).toBool();
796  textFont = QFont( fontFamily, fontSize, fontWeight, fontItalic );
797  textFont.setPointSizeF( fontSize ); //double precision needed because of map units
798  textNamedStyle = QgsFontUtils::translateNamedStyle( layer->customProperty( "labeling/namedStyle", QVariant( "" ) ).toString() );
799  QgsFontUtils::updateFontViaStyle( textFont, textNamedStyle ); // must come after textFont.setPointSizeF()
800  textFont.setCapitalization(( QFont::Capitalization )layer->customProperty( "labeling/fontCapitals", QVariant( 0 ) ).toUInt() );
801  textFont.setUnderline( layer->customProperty( "labeling/fontUnderline" ).toBool() );
802  textFont.setStrikeOut( layer->customProperty( "labeling/fontStrikeout" ).toBool() );
803  textFont.setLetterSpacing( QFont::AbsoluteSpacing, layer->customProperty( "labeling/fontLetterSpacing", QVariant( 0.0 ) ).toDouble() );
804  textFont.setWordSpacing( layer->customProperty( "labeling/fontWordSpacing", QVariant( 0.0 ) ).toDouble() );
805  textColor = _readColor( layer, "labeling/textColor", Qt::black, false );
806  textTransp = layer->customProperty( "labeling/textTransp" ).toInt();
808  ( QgsMapRenderer::BlendMode )layer->customProperty( "labeling/blendMode", QVariant( QgsMapRenderer::BlendNormal ) ).toUInt() );
809  previewBkgrdColor = QColor( layer->customProperty( "labeling/previewBkgrdColor", QVariant( "#ffffff" ) ).toString() );
810 
811 
812  // text formatting
813  wrapChar = layer->customProperty( "labeling/wrapChar" ).toString();
814  multilineHeight = layer->customProperty( "labeling/multilineHeight", QVariant( 1.0 ) ).toDouble();
815  multilineAlign = ( MultiLineAlign )layer->customProperty( "labeling/multilineAlign", QVariant( MultiLeft ) ).toUInt();
816  addDirectionSymbol = layer->customProperty( "labeling/addDirectionSymbol" ).toBool();
817  leftDirectionSymbol = layer->customProperty( "labeling/leftDirectionSymbol", QVariant( "<" ) ).toString();
818  rightDirectionSymbol = layer->customProperty( "labeling/rightDirectionSymbol", QVariant( ">" ) ).toString();
819  reverseDirectionSymbol = layer->customProperty( "labeling/reverseDirectionSymbol" ).toBool();
820  placeDirectionSymbol = ( DirectionSymbols )layer->customProperty( "labeling/placeDirectionSymbol", QVariant( SymbolLeftRight ) ).toUInt();
821  formatNumbers = layer->customProperty( "labeling/formatNumbers" ).toBool();
822  decimals = layer->customProperty( "labeling/decimals" ).toInt();
823  plusSign = layer->customProperty( "labeling/plussign" ).toInt();
824 
825  // text buffer
826  double bufSize = layer->customProperty( "labeling/bufferSize", QVariant( 0.0 ) ).toDouble();
827 
828  // fix for buffer being keyed off of just its size in the past (<2.0)
829  QVariant drawBuffer = layer->customProperty( "labeling/bufferDraw", QVariant() );
830  if ( drawBuffer.isValid() )
831  {
832  bufferDraw = drawBuffer.toBool();
833  bufferSize = bufSize;
834  }
835  else if ( bufSize != 0.0 )
836  {
837  bufferDraw = true;
838  bufferSize = bufSize;
839  }
840  else
841  {
842  // keep bufferSize at new 1.0 default
843  bufferDraw = false;
844  }
845 
846  bufferSizeInMapUnits = layer->customProperty( "labeling/bufferSizeInMapUnits" ).toBool();
847  bufferSizeMapUnitScale.minScale = layer->customProperty( "labeling/bufferSizeMapUnitMinScale", 0.0 ).toDouble();
848  bufferSizeMapUnitScale.maxScale = layer->customProperty( "labeling/bufferSizeMapUnitMaxScale", 0.0 ).toDouble();
849  bufferColor = _readColor( layer, "labeling/bufferColor", Qt::white, false );
850  bufferTransp = layer->customProperty( "labeling/bufferTransp" ).toInt();
852  ( QgsMapRenderer::BlendMode )layer->customProperty( "labeling/bufferBlendMode", QVariant( QgsMapRenderer::BlendNormal ) ).toUInt() );
853  bufferJoinStyle = ( Qt::PenJoinStyle )layer->customProperty( "labeling/bufferJoinStyle", QVariant( Qt::BevelJoin ) ).toUInt();
854  bufferNoFill = layer->customProperty( "labeling/bufferNoFill", QVariant( false ) ).toBool();
855 
856  // background
857  shapeDraw = layer->customProperty( "labeling/shapeDraw", QVariant( false ) ).toBool();
858  shapeType = ( ShapeType )layer->customProperty( "labeling/shapeType", QVariant( ShapeRectangle ) ).toUInt();
859  shapeSVGFile = layer->customProperty( "labeling/shapeSVGFile", QVariant( "" ) ).toString();
860  shapeSizeType = ( SizeType )layer->customProperty( "labeling/shapeSizeType", QVariant( SizeBuffer ) ).toUInt();
861  shapeSize = QPointF( layer->customProperty( "labeling/shapeSizeX", QVariant( 0.0 ) ).toDouble(),
862  layer->customProperty( "labeling/shapeSizeY", QVariant( 0.0 ) ).toDouble() );
863  shapeSizeUnits = ( SizeUnit )layer->customProperty( "labeling/shapeSizeUnits", QVariant( MM ) ).toUInt();
864  shapeSizeMapUnitScale.minScale = layer->customProperty( "labeling/shapeSizeMapUnitMinScale", 0.0 ).toDouble();
865  shapeSizeMapUnitScale.maxScale = layer->customProperty( "labeling/shapeSizeMapUnitMaxScale", 0.0 ).toDouble();
866  shapeRotationType = ( RotationType )layer->customProperty( "labeling/shapeRotationType", QVariant( RotationSync ) ).toUInt();
867  shapeRotation = layer->customProperty( "labeling/shapeRotation", QVariant( 0.0 ) ).toDouble();
868  shapeOffset = QPointF( layer->customProperty( "labeling/shapeOffsetX", QVariant( 0.0 ) ).toDouble(),
869  layer->customProperty( "labeling/shapeOffsetY", QVariant( 0.0 ) ).toDouble() );
870  shapeOffsetUnits = ( SizeUnit )layer->customProperty( "labeling/shapeOffsetUnits", QVariant( MM ) ).toUInt();
871  shapeOffsetMapUnitScale.minScale = layer->customProperty( "labeling/shapeOffsetMapUnitMinScale", 0.0 ).toDouble();
872  shapeOffsetMapUnitScale.maxScale = layer->customProperty( "labeling/shapeOffsetMapUnitMaxScale", 0.0 ).toDouble();
873  shapeRadii = QPointF( layer->customProperty( "labeling/shapeRadiiX", QVariant( 0.0 ) ).toDouble(),
874  layer->customProperty( "labeling/shapeRadiiY", QVariant( 0.0 ) ).toDouble() );
875  shapeRadiiUnits = ( SizeUnit )layer->customProperty( "labeling/shapeRadiiUnits", QVariant( MM ) ).toUInt();
876  shapeRadiiMapUnitScale.minScale = layer->customProperty( "labeling/shapeRaddiMapUnitMinScale", 0.0 ).toDouble();
877  shapeRadiiMapUnitScale.maxScale = layer->customProperty( "labeling/shapeRaddiMapUnitMaxScale", 0.0 ).toDouble();
878  shapeFillColor = _readColor( layer, "labeling/shapeFillColor", Qt::white, true );
879  shapeBorderColor = _readColor( layer, "labeling/shapeBorderColor", Qt::darkGray, true );
880  shapeBorderWidth = layer->customProperty( "labeling/shapeBorderWidth", QVariant( .0 ) ).toDouble();
881  shapeBorderWidthUnits = ( SizeUnit )layer->customProperty( "labeling/shapeBorderWidthUnits", QVariant( MM ) ).toUInt();
882  shapeBorderWidthMapUnitScale.minScale = layer->customProperty( "labeling/shapeBorderWidthMapUnitMinScale", 0.0 ).toDouble();
883  shapeBorderWidthMapUnitScale.maxScale = layer->customProperty( "labeling/shapeBorderWidthMapUnitMaxScale", 0.0 ).toDouble();
884  shapeJoinStyle = ( Qt::PenJoinStyle )layer->customProperty( "labeling/shapeJoinStyle", QVariant( Qt::BevelJoin ) ).toUInt();
885  shapeTransparency = layer->customProperty( "labeling/shapeTransparency", QVariant( 0 ) ).toInt();
887  ( QgsMapRenderer::BlendMode )layer->customProperty( "labeling/shapeBlendMode", QVariant( QgsMapRenderer::BlendNormal ) ).toUInt() );
888 
889  // drop shadow
890  shadowDraw = layer->customProperty( "labeling/shadowDraw", QVariant( false ) ).toBool();
891  shadowUnder = ( ShadowType )layer->customProperty( "labeling/shadowUnder", QVariant( ShadowLowest ) ).toUInt();//ShadowLowest;
892  shadowOffsetAngle = layer->customProperty( "labeling/shadowOffsetAngle", QVariant( 135 ) ).toInt();
893  shadowOffsetDist = layer->customProperty( "labeling/shadowOffsetDist", QVariant( 1.0 ) ).toDouble();
894  shadowOffsetUnits = ( SizeUnit )layer->customProperty( "labeling/shadowOffsetUnits", QVariant( MM ) ).toUInt();
895  shadowOffsetMapUnitScale.minScale = layer->customProperty( "labeling/shadowOffsetMapUnitMinScale", 0.0 ).toDouble();
896  shadowOffsetMapUnitScale.maxScale = layer->customProperty( "labeling/shadowOffsetMapUnitMaxScale", 0.0 ).toDouble();
897  shadowOffsetGlobal = layer->customProperty( "labeling/shadowOffsetGlobal", QVariant( true ) ).toBool();
898  shadowRadius = layer->customProperty( "labeling/shadowRadius", QVariant( 1.5 ) ).toDouble();
899  shadowRadiusUnits = ( SizeUnit )layer->customProperty( "labeling/shadowRadiusUnits", QVariant( MM ) ).toUInt();
900  shadowRadiusMapUnitScale.minScale = layer->customProperty( "labeling/shadowRadiusMapUnitMinScale", 0.0 ).toDouble();
901  shadowRadiusMapUnitScale.maxScale = layer->customProperty( "labeling/shadowRadiusMapUnitMaxScale", 0.0 ).toDouble();
902  shadowRadiusAlphaOnly = layer->customProperty( "labeling/shadowRadiusAlphaOnly", QVariant( false ) ).toBool();
903  shadowTransparency = layer->customProperty( "labeling/shadowTransparency", QVariant( 30 ) ).toInt();
904  shadowScale = layer->customProperty( "labeling/shadowScale", QVariant( 100 ) ).toInt();
905  shadowColor = _readColor( layer, "labeling/shadowColor", Qt::black, false );
907  ( QgsMapRenderer::BlendMode )layer->customProperty( "labeling/shadowBlendMode", QVariant( QgsMapRenderer::BlendMultiply ) ).toUInt() );
908 
909  // placement
910  placement = ( Placement )layer->customProperty( "labeling/placement" ).toInt();
911  placementFlags = layer->customProperty( "labeling/placementFlags" ).toUInt();
912  centroidWhole = layer->customProperty( "labeling/centroidWhole", QVariant( false ) ).toBool();
913  centroidInside = layer->customProperty( "labeling/centroidInside", QVariant( false ) ).toBool();
914  fitInPolygonOnly = layer->customProperty( "labeling/fitInPolygonOnly", QVariant( false ) ).toBool();
915  dist = layer->customProperty( "labeling/dist" ).toDouble();
916  distInMapUnits = layer->customProperty( "labeling/distInMapUnits" ).toBool();
917  distMapUnitScale.minScale = layer->customProperty( "labeling/distMapUnitMinScale", 0.0 ).toDouble();
918  distMapUnitScale.maxScale = layer->customProperty( "labeling/distMapUnitMaxScale", 0.0 ).toDouble();
919  quadOffset = ( QuadrantPosition )layer->customProperty( "labeling/quadOffset", QVariant( QuadrantOver ) ).toUInt();
920  xOffset = layer->customProperty( "labeling/xOffset", QVariant( 0.0 ) ).toDouble();
921  yOffset = layer->customProperty( "labeling/yOffset", QVariant( 0.0 ) ).toDouble();
922  labelOffsetInMapUnits = layer->customProperty( "labeling/labelOffsetInMapUnits", QVariant( true ) ).toBool();
923  labelOffsetMapUnitScale.minScale = layer->customProperty( "labeling/labelOffsetMapUnitMinScale", 0.0 ).toDouble();
924  labelOffsetMapUnitScale.maxScale = layer->customProperty( "labeling/labelOffsetMapUnitMaxScale", 0.0 ).toDouble();
925  angleOffset = layer->customProperty( "labeling/angleOffset", QVariant( 0.0 ) ).toDouble();
926  preserveRotation = layer->customProperty( "labeling/preserveRotation", QVariant( true ) ).toBool();
927  maxCurvedCharAngleIn = layer->customProperty( "labeling/maxCurvedCharAngleIn", QVariant( 20.0 ) ).toDouble();
928  maxCurvedCharAngleOut = layer->customProperty( "labeling/maxCurvedCharAngleOut", QVariant( -20.0 ) ).toDouble();
929  priority = layer->customProperty( "labeling/priority" ).toInt();
930  repeatDistance = layer->customProperty( "labeling/repeatDistance", 0.0 ).toDouble();
931  repeatDistanceUnit = ( SizeUnit ) layer->customProperty( "labeling/repeatDistanceUnit", QVariant( MM ) ).toUInt();
932  repeatDistanceMapUnitScale.minScale = layer->customProperty( "labeling/repeatDistanceMapUnitMinScale", 0.0 ).toDouble();
933  repeatDistanceMapUnitScale.maxScale = layer->customProperty( "labeling/repeatDistanceMapUnitMaxScale", 0.0 ).toDouble();
934 
935  // rendering
936  int scalemn = layer->customProperty( "labeling/scaleMin", QVariant( 0 ) ).toInt();
937  int scalemx = layer->customProperty( "labeling/scaleMax", QVariant( 0 ) ).toInt();
938 
939  // fix for scale visibility limits being keyed off of just its values in the past (<2.0)
940  QVariant scalevis = layer->customProperty( "labeling/scaleVisibility", QVariant() );
941  if ( scalevis.isValid() )
942  {
943  scaleVisibility = scalevis.toBool();
944  scaleMin = scalemn;
945  scaleMax = scalemx;
946  }
947  else if ( scalemn > 0 || scalemx > 0 )
948  {
949  scaleVisibility = true;
950  scaleMin = scalemn;
951  scaleMax = scalemx;
952  }
953  else
954  {
955  // keep scaleMin and scaleMax at new 1.0 defaults (1 and 10000000, were 0 and 0)
956  scaleVisibility = false;
957  }
958 
959 
960  fontLimitPixelSize = layer->customProperty( "labeling/fontLimitPixelSize", QVariant( false ) ).toBool();
961  fontMinPixelSize = layer->customProperty( "labeling/fontMinPixelSize", QVariant( 0 ) ).toInt();
962  fontMaxPixelSize = layer->customProperty( "labeling/fontMaxPixelSize", QVariant( 10000 ) ).toInt();
963  displayAll = layer->customProperty( "labeling/displayAll", QVariant( false ) ).toBool();
964  upsidedownLabels = ( UpsideDownLabels )layer->customProperty( "labeling/upsidedownLabels", QVariant( Upright ) ).toUInt();
965 
966  labelPerPart = layer->customProperty( "labeling/labelPerPart" ).toBool();
967  mergeLines = layer->customProperty( "labeling/mergeLines" ).toBool();
968  minFeatureSize = layer->customProperty( "labeling/minFeatureSize" ).toDouble();
969  limitNumLabels = layer->customProperty( "labeling/limitNumLabels", QVariant( false ) ).toBool();
970  maxNumLabels = layer->customProperty( "labeling/maxNumLabels", QVariant( 2000 ) ).toInt();
971  obstacle = layer->customProperty( "labeling/obstacle", QVariant( true ) ).toBool();
972  obstacleFactor = layer->customProperty( "labeling/obstacleFactor", QVariant( 1.0 ) ).toDouble();
973  obstacleType = ( ObstacleType )layer->customProperty( "labeling/obstacleType", QVariant( PolygonInterior ) ).toUInt();
974 
975  readDataDefinedPropertyMap( layer, 0, dataDefinedProperties );
976 }
977 
979 {
980  // this is a mark that labeling information is present
981  layer->setCustomProperty( "labeling", "pal" );
982 
983  layer->setCustomProperty( "labeling/enabled", enabled );
984  layer->setCustomProperty( "labeling/drawLabels", drawLabels );
985 
986  // text style
987  layer->setCustomProperty( "labeling/fieldName", fieldName );
988  layer->setCustomProperty( "labeling/isExpression", isExpression );
989  layer->setCustomProperty( "labeling/fontFamily", textFont.family() );
990  layer->setCustomProperty( "labeling/namedStyle", QgsFontUtils::untranslateNamedStyle( textNamedStyle ) );
991  layer->setCustomProperty( "labeling/fontSize", textFont.pointSizeF() );
992  layer->setCustomProperty( "labeling/fontSizeInMapUnits", fontSizeInMapUnits );
993  layer->setCustomProperty( "labeling/fontSizeMapUnitMinScale", fontSizeMapUnitScale.minScale );
994  layer->setCustomProperty( "labeling/fontSizeMapUnitMaxScale", fontSizeMapUnitScale.maxScale );
995  layer->setCustomProperty( "labeling/fontWeight", textFont.weight() );
996  layer->setCustomProperty( "labeling/fontItalic", textFont.italic() );
997  layer->setCustomProperty( "labeling/fontStrikeout", textFont.strikeOut() );
998  layer->setCustomProperty( "labeling/fontUnderline", textFont.underline() );
999  _writeColor( layer, "labeling/textColor", textColor );
1000  layer->setCustomProperty( "labeling/fontCapitals", ( unsigned int )textFont.capitalization() );
1001  layer->setCustomProperty( "labeling/fontLetterSpacing", textFont.letterSpacing() );
1002  layer->setCustomProperty( "labeling/fontWordSpacing", textFont.wordSpacing() );
1003  layer->setCustomProperty( "labeling/textTransp", textTransp );
1004  layer->setCustomProperty( "labeling/blendMode", QgsMapRenderer::getBlendModeEnum( blendMode ) );
1005  layer->setCustomProperty( "labeling/previewBkgrdColor", previewBkgrdColor.name() );
1006 
1007  // text formatting
1008  layer->setCustomProperty( "labeling/wrapChar", wrapChar );
1009  layer->setCustomProperty( "labeling/multilineHeight", multilineHeight );
1010  layer->setCustomProperty( "labeling/multilineAlign", ( unsigned int )multilineAlign );
1011  layer->setCustomProperty( "labeling/addDirectionSymbol", addDirectionSymbol );
1012  layer->setCustomProperty( "labeling/leftDirectionSymbol", leftDirectionSymbol );
1013  layer->setCustomProperty( "labeling/rightDirectionSymbol", rightDirectionSymbol );
1014  layer->setCustomProperty( "labeling/reverseDirectionSymbol", reverseDirectionSymbol );
1015  layer->setCustomProperty( "labeling/placeDirectionSymbol", ( unsigned int )placeDirectionSymbol );
1016  layer->setCustomProperty( "labeling/formatNumbers", formatNumbers );
1017  layer->setCustomProperty( "labeling/decimals", decimals );
1018  layer->setCustomProperty( "labeling/plussign", plusSign );
1019 
1020  // text buffer
1021  layer->setCustomProperty( "labeling/bufferDraw", bufferDraw );
1022  layer->setCustomProperty( "labeling/bufferSize", bufferSize );
1023  layer->setCustomProperty( "labeling/bufferSizeInMapUnits", bufferSizeInMapUnits );
1024  layer->setCustomProperty( "labeling/bufferSizeMapUnitMinScale", bufferSizeMapUnitScale.minScale );
1025  layer->setCustomProperty( "labeling/bufferSizeMapUnitMaxScale", bufferSizeMapUnitScale.maxScale );
1026  _writeColor( layer, "labeling/bufferColor", bufferColor );
1027  layer->setCustomProperty( "labeling/bufferNoFill", bufferNoFill );
1028  layer->setCustomProperty( "labeling/bufferTransp", bufferTransp );
1029  layer->setCustomProperty( "labeling/bufferJoinStyle", ( unsigned int )bufferJoinStyle );
1030  layer->setCustomProperty( "labeling/bufferBlendMode", QgsMapRenderer::getBlendModeEnum( bufferBlendMode ) );
1031 
1032  // background
1033  layer->setCustomProperty( "labeling/shapeDraw", shapeDraw );
1034  layer->setCustomProperty( "labeling/shapeType", ( unsigned int )shapeType );
1035  layer->setCustomProperty( "labeling/shapeSVGFile", shapeSVGFile );
1036  layer->setCustomProperty( "labeling/shapeSizeType", ( unsigned int )shapeSizeType );
1037  layer->setCustomProperty( "labeling/shapeSizeX", shapeSize.x() );
1038  layer->setCustomProperty( "labeling/shapeSizeY", shapeSize.y() );
1039  layer->setCustomProperty( "labeling/shapeSizeUnits", ( unsigned int )shapeSizeUnits );
1040  layer->setCustomProperty( "labeling/shapeSizeMapUnitMinScale", shapeSizeMapUnitScale.minScale );
1041  layer->setCustomProperty( "labeling/shapeSizeMapUnitMaxScale", shapeSizeMapUnitScale.maxScale );
1042  layer->setCustomProperty( "labeling/shapeRotationType", ( unsigned int )shapeRotationType );
1043  layer->setCustomProperty( "labeling/shapeRotation", shapeRotation );
1044  layer->setCustomProperty( "labeling/shapeOffsetX", shapeOffset.x() );
1045  layer->setCustomProperty( "labeling/shapeOffsetY", shapeOffset.y() );
1046  layer->setCustomProperty( "labeling/shapeOffsetUnits", ( unsigned int )shapeOffsetUnits );
1047  layer->setCustomProperty( "labeling/shapeOffsetMapUnitMinScale", shapeOffsetMapUnitScale.minScale );
1048  layer->setCustomProperty( "labeling/shapeOffsetMapUnitMaxScale", shapeOffsetMapUnitScale.maxScale );
1049  layer->setCustomProperty( "labeling/shapeRadiiX", shapeRadii.x() );
1050  layer->setCustomProperty( "labeling/shapeRadiiY", shapeRadii.y() );
1051  layer->setCustomProperty( "labeling/shapeRadiiUnits", ( unsigned int )shapeRadiiUnits );
1052  layer->setCustomProperty( "labeling/shapeRadiiMapUnitMinScale", shapeRadiiMapUnitScale.minScale );
1053  layer->setCustomProperty( "labeling/shapeRadiiMapUnitMaxScale", shapeRadiiMapUnitScale.maxScale );
1054  _writeColor( layer, "labeling/shapeFillColor", shapeFillColor, true );
1055  _writeColor( layer, "labeling/shapeBorderColor", shapeBorderColor, true );
1056  layer->setCustomProperty( "labeling/shapeBorderWidth", shapeBorderWidth );
1057  layer->setCustomProperty( "labeling/shapeBorderWidthUnits", ( unsigned int )shapeBorderWidthUnits );
1058  layer->setCustomProperty( "labeling/shapeBorderWidthMapUnitMinScale", shapeBorderWidthMapUnitScale.minScale );
1059  layer->setCustomProperty( "labeling/shapeBorderWidthMapUnitMaxScale", shapeBorderWidthMapUnitScale.maxScale );
1060  layer->setCustomProperty( "labeling/shapeJoinStyle", ( unsigned int )shapeJoinStyle );
1061  layer->setCustomProperty( "labeling/shapeTransparency", shapeTransparency );
1062  layer->setCustomProperty( "labeling/shapeBlendMode", QgsMapRenderer::getBlendModeEnum( shapeBlendMode ) );
1063 
1064  // drop shadow
1065  layer->setCustomProperty( "labeling/shadowDraw", shadowDraw );
1066  layer->setCustomProperty( "labeling/shadowUnder", ( unsigned int )shadowUnder );
1067  layer->setCustomProperty( "labeling/shadowOffsetAngle", shadowOffsetAngle );
1068  layer->setCustomProperty( "labeling/shadowOffsetDist", shadowOffsetDist );
1069  layer->setCustomProperty( "labeling/shadowOffsetUnits", ( unsigned int )shadowOffsetUnits );
1070  layer->setCustomProperty( "labeling/shadowOffsetMapUnitMinScale", shadowOffsetMapUnitScale.minScale );
1071  layer->setCustomProperty( "labeling/shadowOffsetMapUnitMaxScale", shadowOffsetMapUnitScale.maxScale );
1072  layer->setCustomProperty( "labeling/shadowOffsetGlobal", shadowOffsetGlobal );
1073  layer->setCustomProperty( "labeling/shadowRadius", shadowRadius );
1074  layer->setCustomProperty( "labeling/shadowRadiusUnits", ( unsigned int )shadowRadiusUnits );
1075  layer->setCustomProperty( "labeling/shadowRadiusMapUnitMinScale", shadowRadiusMapUnitScale.minScale );
1076  layer->setCustomProperty( "labeling/shadowRadiusMapUnitMaxScale", shadowRadiusMapUnitScale.maxScale );
1077  layer->setCustomProperty( "labeling/shadowRadiusAlphaOnly", shadowRadiusAlphaOnly );
1078  layer->setCustomProperty( "labeling/shadowTransparency", shadowTransparency );
1079  layer->setCustomProperty( "labeling/shadowScale", shadowScale );
1080  _writeColor( layer, "labeling/shadowColor", shadowColor, false );
1081  layer->setCustomProperty( "labeling/shadowBlendMode", QgsMapRenderer::getBlendModeEnum( shadowBlendMode ) );
1082 
1083  // placement
1084  layer->setCustomProperty( "labeling/placement", placement );
1085  layer->setCustomProperty( "labeling/placementFlags", ( unsigned int )placementFlags );
1086  layer->setCustomProperty( "labeling/centroidWhole", centroidWhole );
1087  layer->setCustomProperty( "labeling/centroidInside", centroidInside );
1088  layer->setCustomProperty( "labeling/fitInPolygonOnly", fitInPolygonOnly );
1089  layer->setCustomProperty( "labeling/dist", dist );
1090  layer->setCustomProperty( "labeling/distInMapUnits", distInMapUnits );
1091  layer->setCustomProperty( "labeling/distMapUnitMinScale", distMapUnitScale.minScale );
1092  layer->setCustomProperty( "labeling/distMapUnitMaxScale", distMapUnitScale.maxScale );
1093  layer->setCustomProperty( "labeling/quadOffset", ( unsigned int )quadOffset );
1094  layer->setCustomProperty( "labeling/xOffset", xOffset );
1095  layer->setCustomProperty( "labeling/yOffset", yOffset );
1096  layer->setCustomProperty( "labeling/labelOffsetInMapUnits", labelOffsetInMapUnits );
1097  layer->setCustomProperty( "labeling/labelOffsetMapUnitMinScale", labelOffsetMapUnitScale.minScale );
1098  layer->setCustomProperty( "labeling/labelOffsetMapUnitMaxScale", labelOffsetMapUnitScale.maxScale );
1099  layer->setCustomProperty( "labeling/angleOffset", angleOffset );
1100  layer->setCustomProperty( "labeling/preserveRotation", preserveRotation );
1101  layer->setCustomProperty( "labeling/maxCurvedCharAngleIn", maxCurvedCharAngleIn );
1102  layer->setCustomProperty( "labeling/maxCurvedCharAngleOut", maxCurvedCharAngleOut );
1103  layer->setCustomProperty( "labeling/priority", priority );
1104  layer->setCustomProperty( "labeling/repeatDistance", repeatDistance );
1105  layer->setCustomProperty( "labeling/repeatDistanceUnit", repeatDistanceUnit );
1106  layer->setCustomProperty( "labeling/repeatDistanceMapUnitMinScale", repeatDistanceMapUnitScale.minScale );
1107  layer->setCustomProperty( "labeling/repeatDistanceMapUnitMaxScale", repeatDistanceMapUnitScale.maxScale );
1108 
1109  // rendering
1110  layer->setCustomProperty( "labeling/scaleVisibility", scaleVisibility );
1111  layer->setCustomProperty( "labeling/scaleMin", scaleMin );
1112  layer->setCustomProperty( "labeling/scaleMax", scaleMax );
1113  layer->setCustomProperty( "labeling/fontLimitPixelSize", fontLimitPixelSize );
1114  layer->setCustomProperty( "labeling/fontMinPixelSize", fontMinPixelSize );
1115  layer->setCustomProperty( "labeling/fontMaxPixelSize", fontMaxPixelSize );
1116  layer->setCustomProperty( "labeling/displayAll", displayAll );
1117  layer->setCustomProperty( "labeling/upsidedownLabels", ( unsigned int )upsidedownLabels );
1118 
1119  layer->setCustomProperty( "labeling/labelPerPart", labelPerPart );
1120  layer->setCustomProperty( "labeling/mergeLines", mergeLines );
1121  layer->setCustomProperty( "labeling/minFeatureSize", minFeatureSize );
1122  layer->setCustomProperty( "labeling/limitNumLabels", limitNumLabels );
1123  layer->setCustomProperty( "labeling/maxNumLabels", maxNumLabels );
1124  layer->setCustomProperty( "labeling/obstacle", obstacle );
1125  layer->setCustomProperty( "labeling/obstacleFactor", obstacleFactor );
1126  layer->setCustomProperty( "labeling/obstacleType", ( unsigned int )obstacleType );
1127 
1128  writeDataDefinedPropertyMap( layer, 0, dataDefinedProperties );
1129 }
1130 
1131 
1132 
1134 {
1135  enabled = true;
1136  drawLabels = true;
1137 
1138  // text style
1139  QDomElement textStyleElem = elem.firstChildElement( "text-style" );
1140  fieldName = textStyleElem.attribute( "fieldName" );
1141  isExpression = textStyleElem.attribute( "isExpression" ).toInt();
1142  QFont appFont = QApplication::font();
1143  mTextFontFamily = textStyleElem.attribute( "fontFamily", appFont.family() );
1144  QString fontFamily = mTextFontFamily;
1146  {
1147  // trigger to notify user about font family substitution (signal emitted in QgsVectorLayer::prepareLabelingAndDiagrams)
1148  mTextFontFound = false;
1149 
1150  // TODO: update when pref for how to resolve missing family (use matching algorithm or just default font) is implemented
1151  // currently only defaults to matching algorithm for resolving [foundry], if a font of similar family is found (default for QFont)
1152 
1153  // for now, do not use matching algorithm for substitution if family not found, substitute default instead
1154  fontFamily = appFont.family();
1155  }
1156 
1157  double fontSize = textStyleElem.attribute( "fontSize" ).toDouble();
1158  fontSizeInMapUnits = textStyleElem.attribute( "fontSizeInMapUnits" ).toInt();
1159  fontSizeMapUnitScale.minScale = textStyleElem.attribute( "fontSizeMapUnitMinScale", "0" ).toDouble();
1160  fontSizeMapUnitScale.maxScale = textStyleElem.attribute( "fontSizeMapUnitMaxScale", "0" ).toDouble();
1161  int fontWeight = textStyleElem.attribute( "fontWeight" ).toInt();
1162  bool fontItalic = textStyleElem.attribute( "fontItalic" ).toInt();
1163  textFont = QFont( fontFamily, fontSize, fontWeight, fontItalic );
1164  textFont.setPointSizeF( fontSize ); //double precision needed because of map units
1165  textNamedStyle = QgsFontUtils::translateNamedStyle( textStyleElem.attribute( "namedStyle" ) );
1166  QgsFontUtils::updateFontViaStyle( textFont, textNamedStyle ); // must come after textFont.setPointSizeF()
1167  textFont.setCapitalization(( QFont::Capitalization )textStyleElem.attribute( "fontCapitals", "0" ).toUInt() );
1168  textFont.setUnderline( textStyleElem.attribute( "fontUnderline" ).toInt() );
1169  textFont.setStrikeOut( textStyleElem.attribute( "fontStrikeout" ).toInt() );
1170  textFont.setLetterSpacing( QFont::AbsoluteSpacing, textStyleElem.attribute( "fontLetterSpacing", "0" ).toDouble() );
1171  textFont.setWordSpacing( textStyleElem.attribute( "fontWordSpacing", "0" ).toDouble() );
1172  textColor = QgsSymbolLayerV2Utils::decodeColor( textStyleElem.attribute( "textColor", QgsSymbolLayerV2Utils::encodeColor( Qt::black ) ) );
1173  textTransp = textStyleElem.attribute( "textTransp" ).toInt();
1176  previewBkgrdColor = QColor( textStyleElem.attribute( "previewBkgrdColor", "#ffffff" ) );
1177 
1178 
1179  // text formatting
1180  QDomElement textFormatElem = elem.firstChildElement( "text-format" );
1181  wrapChar = textFormatElem.attribute( "wrapChar" );
1182  multilineHeight = textFormatElem.attribute( "multilineHeight", "1" ).toDouble();
1183  multilineAlign = ( MultiLineAlign )textFormatElem.attribute( "multilineAlign", QString::number( MultiLeft ) ).toUInt();
1184  addDirectionSymbol = textFormatElem.attribute( "addDirectionSymbol" ).toInt();
1185  leftDirectionSymbol = textFormatElem.attribute( "leftDirectionSymbol", "<" );
1186  rightDirectionSymbol = textFormatElem.attribute( "rightDirectionSymbol", ">" );
1187  reverseDirectionSymbol = textFormatElem.attribute( "reverseDirectionSymbol" ).toInt();
1188  placeDirectionSymbol = ( DirectionSymbols )textFormatElem.attribute( "placeDirectionSymbol", QString::number( SymbolLeftRight ) ).toUInt();
1189  formatNumbers = textFormatElem.attribute( "formatNumbers" ).toInt();
1190  decimals = textFormatElem.attribute( "decimals" ).toInt();
1191  plusSign = textFormatElem.attribute( "plussign" ).toInt();
1192 
1193  // text buffer
1194  QDomElement textBufferElem = elem.firstChildElement( "text-buffer" );
1195  double bufSize = textBufferElem.attribute( "bufferSize", "0" ).toDouble();
1196 
1197  // fix for buffer being keyed off of just its size in the past (<2.0)
1198  QVariant drawBuffer = textBufferElem.attribute( "bufferDraw" );
1199  if ( drawBuffer.isValid() )
1200  {
1201  bufferDraw = drawBuffer.toBool();
1202  bufferSize = bufSize;
1203  }
1204  else if ( bufSize != 0.0 )
1205  {
1206  bufferDraw = true;
1207  bufferSize = bufSize;
1208  }
1209  else
1210  {
1211  // keep bufferSize at new 1.0 default
1212  bufferDraw = false;
1213  }
1214 
1215  bufferSizeInMapUnits = textBufferElem.attribute( "bufferSizeInMapUnits" ).toInt();
1216  bufferSizeMapUnitScale.minScale = textBufferElem.attribute( "bufferSizeMapUnitMinScale", "0" ).toDouble();
1217  bufferSizeMapUnitScale.maxScale = textBufferElem.attribute( "bufferSizeMapUnitMaxScale", "0" ).toDouble();
1218  bufferColor = QgsSymbolLayerV2Utils::decodeColor( textBufferElem.attribute( "bufferColor", QgsSymbolLayerV2Utils::encodeColor( Qt::white ) ) );
1219  bufferTransp = textBufferElem.attribute( "bufferTransp" ).toInt();
1221  ( QgsMapRenderer::BlendMode )textBufferElem.attribute( "bufferBlendMode", QString::number( QgsMapRenderer::BlendNormal ) ).toUInt() );
1222  bufferJoinStyle = ( Qt::PenJoinStyle )textBufferElem.attribute( "bufferJoinStyle", QString::number( Qt::BevelJoin ) ).toUInt();
1223  bufferNoFill = textBufferElem.attribute( "bufferNoFill", "0" ).toInt();
1224 
1225  // background
1226  QDomElement backgroundElem = elem.firstChildElement( "background" );
1227  shapeDraw = backgroundElem.attribute( "shapeDraw", "0" ).toInt();
1228  shapeType = ( ShapeType )backgroundElem.attribute( "shapeType", QString::number( ShapeRectangle ) ).toUInt();
1229  shapeSVGFile = backgroundElem.attribute( "shapeSVGFile" );
1230  shapeSizeType = ( SizeType )backgroundElem.attribute( "shapeSizeType", QString::number( SizeBuffer ) ).toUInt();
1231  shapeSize = QPointF( backgroundElem.attribute( "shapeSizeX", "0" ).toDouble(),
1232  backgroundElem.attribute( "shapeSizeY", "0" ).toDouble() );
1233  shapeSizeUnits = ( SizeUnit )backgroundElem.attribute( "shapeSizeUnits", QString::number( MM ) ).toUInt();
1234  shapeSizeMapUnitScale.minScale = backgroundElem.attribute( "shapeSizeMapUnitMinScale", "0" ).toDouble();
1235  shapeSizeMapUnitScale.maxScale = backgroundElem.attribute( "shapeSizeMapUnitMaxScale", "0" ).toDouble();
1236  shapeRotationType = ( RotationType )backgroundElem.attribute( "shapeRotationType", QString::number( RotationSync ) ).toUInt();
1237  shapeRotation = backgroundElem.attribute( "shapeRotation", "0" ).toDouble();
1238  shapeOffset = QPointF( backgroundElem.attribute( "shapeOffsetX", "0" ).toDouble(),
1239  backgroundElem.attribute( "shapeOffsetY", "0" ).toDouble() );
1240  shapeOffsetUnits = ( SizeUnit )backgroundElem.attribute( "shapeOffsetUnits", QString::number( MM ) ).toUInt();
1241  shapeOffsetMapUnitScale.minScale = backgroundElem.attribute( "shapeOffsetMapUnitMinScale", "0" ).toDouble();
1242  shapeOffsetMapUnitScale.maxScale = backgroundElem.attribute( "shapeOffsetMapUnitMaxScale", "0" ).toDouble();
1243  shapeRadii = QPointF( backgroundElem.attribute( "shapeRadiiX", "0" ).toDouble(),
1244  backgroundElem.attribute( "shapeRadiiY", "0" ).toDouble() );
1245  shapeRadiiUnits = ( SizeUnit )backgroundElem.attribute( "shapeRadiiUnits", QString::number( MM ) ).toUInt();
1246  shapeRadiiMapUnitScale.minScale = backgroundElem.attribute( "shapeRaddiMapUnitMinScale", "0" ).toDouble();
1247  shapeRadiiMapUnitScale.maxScale = backgroundElem.attribute( "shapeRaddiMapUnitMaxScale", "0" ).toDouble();
1248  shapeFillColor = QgsSymbolLayerV2Utils::decodeColor( backgroundElem.attribute( "shapeFillColor", QgsSymbolLayerV2Utils::encodeColor( Qt::white ) ) );
1249  shapeBorderColor = QgsSymbolLayerV2Utils::decodeColor( backgroundElem.attribute( "shapeBorderColor", QgsSymbolLayerV2Utils::encodeColor( Qt::darkGray ) ) );
1250  shapeBorderWidth = backgroundElem.attribute( "shapeBorderWidth", "0" ).toDouble();
1251  shapeBorderWidthUnits = ( SizeUnit )backgroundElem.attribute( "shapeBorderWidthUnits", QString::number( MM ) ).toUInt();
1252  shapeBorderWidthMapUnitScale.minScale = backgroundElem.attribute( "shapeBorderWidthMapUnitMinScale", "0" ).toDouble();
1253  shapeBorderWidthMapUnitScale.maxScale = backgroundElem.attribute( "shapeBorderWidthMapUnitMaxScale", "0" ).toDouble();
1254  shapeJoinStyle = ( Qt::PenJoinStyle )backgroundElem.attribute( "shapeJoinStyle", QString::number( Qt::BevelJoin ) ).toUInt();
1255  shapeTransparency = backgroundElem.attribute( "shapeTransparency", "0" ).toInt();
1257  ( QgsMapRenderer::BlendMode )backgroundElem.attribute( "shapeBlendMode", QString::number( QgsMapRenderer::BlendNormal ) ).toUInt() );
1258 
1259  // drop shadow
1260  QDomElement shadowElem = elem.firstChildElement( "shadow" );
1261  shadowDraw = shadowElem.attribute( "shadowDraw", "0" ).toInt();
1262  shadowUnder = ( ShadowType )shadowElem.attribute( "shadowUnder", QString::number( ShadowLowest ) ).toUInt();//ShadowLowest;
1263  shadowOffsetAngle = shadowElem.attribute( "shadowOffsetAngle", "135" ).toInt();
1264  shadowOffsetDist = shadowElem.attribute( "shadowOffsetDist", "1" ).toDouble();
1265  shadowOffsetUnits = ( SizeUnit )shadowElem.attribute( "shadowOffsetUnits", QString::number( MM ) ).toUInt();
1266  shadowOffsetMapUnitScale.minScale = shadowElem.attribute( "shadowOffsetMapUnitMinScale", "0" ).toDouble();
1267  shadowOffsetMapUnitScale.maxScale = shadowElem.attribute( "shadowOffsetMapUnitMaxScale", "0" ).toDouble();
1268  shadowOffsetGlobal = shadowElem.attribute( "shadowOffsetGlobal", "1" ).toInt();
1269  shadowRadius = shadowElem.attribute( "shadowRadius", "1.5" ).toDouble();
1270  shadowRadiusUnits = ( SizeUnit )shadowElem.attribute( "shadowRadiusUnits", QString::number( MM ) ).toUInt();
1271  shadowRadiusMapUnitScale.minScale = shadowElem.attribute( "shadowRadiusMapUnitMinScale", "0" ).toDouble();
1272  shadowRadiusMapUnitScale.maxScale = shadowElem.attribute( "shadowRadiusMapUnitMaxScale", "0" ).toDouble();
1273  shadowRadiusAlphaOnly = shadowElem.attribute( "shadowRadiusAlphaOnly", "0" ).toInt();
1274  shadowTransparency = shadowElem.attribute( "shadowTransparency", "30" ).toInt();
1275  shadowScale = shadowElem.attribute( "shadowScale", "100" ).toInt();
1276  shadowColor = QgsSymbolLayerV2Utils::decodeColor( shadowElem.attribute( "shadowColor", QgsSymbolLayerV2Utils::encodeColor( Qt::black ) ) );
1278  ( QgsMapRenderer::BlendMode )shadowElem.attribute( "shadowBlendMode", QString::number( QgsMapRenderer::BlendMultiply ) ).toUInt() );
1279 
1280  // placement
1281  QDomElement placementElem = elem.firstChildElement( "placement" );
1282  placement = ( Placement )placementElem.attribute( "placement" ).toInt();
1283  placementFlags = placementElem.attribute( "placementFlags" ).toUInt();
1284  centroidWhole = placementElem.attribute( "centroidWhole", "0" ).toInt();
1285  centroidInside = placementElem.attribute( "centroidInside", "0" ).toInt();
1286  fitInPolygonOnly = placementElem.attribute( "fitInPolygonOnly", "0" ).toInt();
1287  dist = placementElem.attribute( "dist" ).toDouble();
1288  distInMapUnits = placementElem.attribute( "distInMapUnits" ).toInt();
1289  distMapUnitScale.minScale = placementElem.attribute( "distMapUnitMinScale", "0" ).toDouble();
1290  distMapUnitScale.maxScale = placementElem.attribute( "distMapUnitMaxScale", "0" ).toDouble();
1291  quadOffset = ( QuadrantPosition )placementElem.attribute( "quadOffset", QString::number( QuadrantOver ) ).toUInt();
1292  xOffset = placementElem.attribute( "xOffset", "0" ).toDouble();
1293  yOffset = placementElem.attribute( "yOffset", "0" ).toDouble();
1294  labelOffsetInMapUnits = placementElem.attribute( "labelOffsetInMapUnits", "1" ).toInt();
1295  labelOffsetMapUnitScale.minScale = placementElem.attribute( "labelOffsetMapUnitMinScale", "0" ).toDouble();
1296  labelOffsetMapUnitScale.maxScale = placementElem.attribute( "labelOffsetMapUnitMaxScale", "0" ).toDouble();
1297  angleOffset = placementElem.attribute( "angleOffset", "0" ).toDouble();
1298  preserveRotation = placementElem.attribute( "preserveRotation", "1" ).toInt();
1299  maxCurvedCharAngleIn = placementElem.attribute( "maxCurvedCharAngleIn", "20" ).toDouble();
1300  maxCurvedCharAngleOut = placementElem.attribute( "maxCurvedCharAngleOut", "-20" ).toDouble();
1301  priority = placementElem.attribute( "priority" ).toInt();
1302  repeatDistance = placementElem.attribute( "repeatDistance", "0" ).toDouble();
1303  repeatDistanceUnit = ( SizeUnit ) placementElem.attribute( "repeatDistanceUnit", QString::number( MM ) ).toUInt();
1304  repeatDistanceMapUnitScale.minScale = placementElem.attribute( "repeatDistanceMapUnitMinScale", "0" ).toDouble();
1305  repeatDistanceMapUnitScale.maxScale = placementElem.attribute( "repeatDistanceMapUnitMaxScale", "0" ).toDouble();
1306 
1307  // rendering
1308  QDomElement renderingElem = elem.firstChildElement( "rendering" );
1309  scaleMin = renderingElem.attribute( "scaleMin", "0" ).toInt();
1310  scaleMax = renderingElem.attribute( "scaleMax", "0" ).toInt();
1311  scaleVisibility = renderingElem.attribute( "scaleVisibility" ).toInt();
1312 
1313  fontLimitPixelSize = renderingElem.attribute( "fontLimitPixelSize", "0" ).toInt();
1314  fontMinPixelSize = renderingElem.attribute( "fontMinPixelSize", "0" ).toInt();
1315  fontMaxPixelSize = renderingElem.attribute( "fontMaxPixelSize", "10000" ).toInt();
1316  displayAll = renderingElem.attribute( "displayAll", "0" ).toInt();
1317  upsidedownLabels = ( UpsideDownLabels )renderingElem.attribute( "upsidedownLabels", QString::number( Upright ) ).toUInt();
1318 
1319  labelPerPart = renderingElem.attribute( "labelPerPart" ).toInt();
1320  mergeLines = renderingElem.attribute( "mergeLines" ).toInt();
1321  minFeatureSize = renderingElem.attribute( "minFeatureSize" ).toDouble();
1322  limitNumLabels = renderingElem.attribute( "limitNumLabels", "0" ).toInt();
1323  maxNumLabels = renderingElem.attribute( "maxNumLabels", "2000" ).toInt();
1324  obstacle = renderingElem.attribute( "obstacle", "1" ).toInt();
1325  obstacleFactor = renderingElem.attribute( "obstacleFactor", "1" ).toDouble();
1326  obstacleType = ( ObstacleType )renderingElem.attribute( "obstacleType", QString::number( PolygonInterior ) ).toUInt();
1327 
1328  QDomElement ddElem = elem.firstChildElement( "data-defined" );
1329  readDataDefinedPropertyMap( 0, &ddElem, dataDefinedProperties );
1330 }
1331 
1332 
1333 
1335 {
1336  // we assume (enabled == true && drawLabels == true) so those are not saved
1337 
1338  // text style
1339  QDomElement textStyleElem = doc.createElement( "text-style" );
1340  textStyleElem.setAttribute( "fieldName", fieldName );
1341  textStyleElem.setAttribute( "isExpression", isExpression );
1342  textStyleElem.setAttribute( "fontFamily", textFont.family() );
1343  textStyleElem.setAttribute( "namedStyle", QgsFontUtils::untranslateNamedStyle( textNamedStyle ) );
1344  textStyleElem.setAttribute( "fontSize", textFont.pointSizeF() );
1345  textStyleElem.setAttribute( "fontSizeInMapUnits", fontSizeInMapUnits );
1346  textStyleElem.setAttribute( "fontSizeMapUnitMinScale", fontSizeMapUnitScale.minScale );
1347  textStyleElem.setAttribute( "fontSizeMapUnitMaxScale", fontSizeMapUnitScale.maxScale );
1348  textStyleElem.setAttribute( "fontWeight", textFont.weight() );
1349  textStyleElem.setAttribute( "fontItalic", textFont.italic() );
1350  textStyleElem.setAttribute( "fontStrikeout", textFont.strikeOut() );
1351  textStyleElem.setAttribute( "fontUnderline", textFont.underline() );
1352  textStyleElem.setAttribute( "textColor", QgsSymbolLayerV2Utils::encodeColor( textColor ) );
1353  textStyleElem.setAttribute( "fontCapitals", ( unsigned int )textFont.capitalization() );
1354  textStyleElem.setAttribute( "fontLetterSpacing", textFont.letterSpacing() );
1355  textStyleElem.setAttribute( "fontWordSpacing", textFont.wordSpacing() );
1356  textStyleElem.setAttribute( "textTransp", textTransp );
1357  textStyleElem.setAttribute( "blendMode", QgsMapRenderer::getBlendModeEnum( blendMode ) );
1358  textStyleElem.setAttribute( "previewBkgrdColor", previewBkgrdColor.name() );
1359 
1360  // text formatting
1361  QDomElement textFormatElem = doc.createElement( "text-format" );
1362  textFormatElem.setAttribute( "wrapChar", wrapChar );
1363  textFormatElem.setAttribute( "multilineHeight", multilineHeight );
1364  textFormatElem.setAttribute( "multilineAlign", ( unsigned int )multilineAlign );
1365  textFormatElem.setAttribute( "addDirectionSymbol", addDirectionSymbol );
1366  textFormatElem.setAttribute( "leftDirectionSymbol", leftDirectionSymbol );
1367  textFormatElem.setAttribute( "rightDirectionSymbol", rightDirectionSymbol );
1368  textFormatElem.setAttribute( "reverseDirectionSymbol", reverseDirectionSymbol );
1369  textFormatElem.setAttribute( "placeDirectionSymbol", ( unsigned int )placeDirectionSymbol );
1370  textFormatElem.setAttribute( "formatNumbers", formatNumbers );
1371  textFormatElem.setAttribute( "decimals", decimals );
1372  textFormatElem.setAttribute( "plussign", plusSign );
1373 
1374  // text buffer
1375  QDomElement textBufferElem = doc.createElement( "text-buffer" );
1376  textBufferElem.setAttribute( "bufferDraw", bufferDraw );
1377  textBufferElem.setAttribute( "bufferSize", bufferSize );
1378  textBufferElem.setAttribute( "bufferSizeInMapUnits", bufferSizeInMapUnits );
1379  textBufferElem.setAttribute( "bufferSizeMapUnitMinScale", bufferSizeMapUnitScale.minScale );
1380  textBufferElem.setAttribute( "bufferSizeMapUnitMaxScale", bufferSizeMapUnitScale.maxScale );
1381  textBufferElem.setAttribute( "bufferColor", QgsSymbolLayerV2Utils::encodeColor( bufferColor ) );
1382  textBufferElem.setAttribute( "bufferNoFill", bufferNoFill );
1383  textBufferElem.setAttribute( "bufferTransp", bufferTransp );
1384  textBufferElem.setAttribute( "bufferJoinStyle", ( unsigned int )bufferJoinStyle );
1385  textBufferElem.setAttribute( "bufferBlendMode", QgsMapRenderer::getBlendModeEnum( bufferBlendMode ) );
1386 
1387  // background
1388  QDomElement backgroundElem = doc.createElement( "background" );
1389  backgroundElem.setAttribute( "shapeDraw", shapeDraw );
1390  backgroundElem.setAttribute( "shapeType", ( unsigned int )shapeType );
1391  backgroundElem.setAttribute( "shapeSVGFile", shapeSVGFile );
1392  backgroundElem.setAttribute( "shapeSizeType", ( unsigned int )shapeSizeType );
1393  backgroundElem.setAttribute( "shapeSizeX", shapeSize.x() );
1394  backgroundElem.setAttribute( "shapeSizeY", shapeSize.y() );
1395  backgroundElem.setAttribute( "shapeSizeUnits", ( unsigned int )shapeSizeUnits );
1396  backgroundElem.setAttribute( "shapeSizeMapUnitMinScale", shapeSizeMapUnitScale.minScale );
1397  backgroundElem.setAttribute( "shapeSizeMapUnitMaxScale", shapeSizeMapUnitScale.maxScale );
1398  backgroundElem.setAttribute( "shapeRotationType", ( unsigned int )shapeRotationType );
1399  backgroundElem.setAttribute( "shapeRotation", shapeRotation );
1400  backgroundElem.setAttribute( "shapeOffsetX", shapeOffset.x() );
1401  backgroundElem.setAttribute( "shapeOffsetY", shapeOffset.y() );
1402  backgroundElem.setAttribute( "shapeOffsetUnits", ( unsigned int )shapeOffsetUnits );
1403  backgroundElem.setAttribute( "shapeOffsetMapUnitMinScale", shapeOffsetMapUnitScale.minScale );
1404  backgroundElem.setAttribute( "shapeOffsetMapUnitMaxScale", shapeOffsetMapUnitScale.maxScale );
1405  backgroundElem.setAttribute( "shapeRadiiX", shapeRadii.x() );
1406  backgroundElem.setAttribute( "shapeRadiiY", shapeRadii.y() );
1407  backgroundElem.setAttribute( "shapeRadiiUnits", ( unsigned int )shapeRadiiUnits );
1408  backgroundElem.setAttribute( "shapeRadiiMapUnitMinScale", shapeRadiiMapUnitScale.minScale );
1409  backgroundElem.setAttribute( "shapeRadiiMapUnitMaxScale", shapeRadiiMapUnitScale.maxScale );
1410  backgroundElem.setAttribute( "shapeFillColor", QgsSymbolLayerV2Utils::encodeColor( shapeFillColor ) );
1411  backgroundElem.setAttribute( "shapeBorderColor", QgsSymbolLayerV2Utils::encodeColor( shapeBorderColor ) );
1412  backgroundElem.setAttribute( "shapeBorderWidth", shapeBorderWidth );
1413  backgroundElem.setAttribute( "shapeBorderWidthUnits", ( unsigned int )shapeBorderWidthUnits );
1414  backgroundElem.setAttribute( "shapeBorderWidthMapUnitMinScale", shapeBorderWidthMapUnitScale.minScale );
1415  backgroundElem.setAttribute( "shapeBorderWidthMapUnitMaxScale", shapeBorderWidthMapUnitScale.maxScale );
1416  backgroundElem.setAttribute( "shapeJoinStyle", ( unsigned int )shapeJoinStyle );
1417  backgroundElem.setAttribute( "shapeTransparency", shapeTransparency );
1418  backgroundElem.setAttribute( "shapeBlendMode", QgsMapRenderer::getBlendModeEnum( shapeBlendMode ) );
1419 
1420  // drop shadow
1421  QDomElement shadowElem = doc.createElement( "shadow" );
1422  shadowElem.setAttribute( "shadowDraw", shadowDraw );
1423  shadowElem.setAttribute( "shadowUnder", ( unsigned int )shadowUnder );
1424  shadowElem.setAttribute( "shadowOffsetAngle", shadowOffsetAngle );
1425  shadowElem.setAttribute( "shadowOffsetDist", shadowOffsetDist );
1426  shadowElem.setAttribute( "shadowOffsetUnits", ( unsigned int )shadowOffsetUnits );
1427  shadowElem.setAttribute( "shadowOffsetMapUnitMinScale", shadowOffsetMapUnitScale.minScale );
1428  shadowElem.setAttribute( "shadowOffsetMapUnitMaxScale", shadowOffsetMapUnitScale.maxScale );
1429  shadowElem.setAttribute( "shadowOffsetGlobal", shadowOffsetGlobal );
1430  shadowElem.setAttribute( "shadowRadius", shadowRadius );
1431  shadowElem.setAttribute( "shadowRadiusUnits", ( unsigned int )shadowRadiusUnits );
1432  shadowElem.setAttribute( "shadowRadiusMapUnitMinScale", shadowRadiusMapUnitScale.minScale );
1433  shadowElem.setAttribute( "shadowRadiusMapUnitMaxScale", shadowRadiusMapUnitScale.maxScale );
1434  shadowElem.setAttribute( "shadowRadiusAlphaOnly", shadowRadiusAlphaOnly );
1435  shadowElem.setAttribute( "shadowTransparency", shadowTransparency );
1436  shadowElem.setAttribute( "shadowScale", shadowScale );
1437  shadowElem.setAttribute( "shadowColor", QgsSymbolLayerV2Utils::encodeColor( shadowColor ) );
1438  shadowElem.setAttribute( "shadowBlendMode", QgsMapRenderer::getBlendModeEnum( shadowBlendMode ) );
1439 
1440  // placement
1441  QDomElement placementElem = doc.createElement( "placement" );
1442  placementElem.setAttribute( "placement", placement );
1443  placementElem.setAttribute( "placementFlags", ( unsigned int )placementFlags );
1444  placementElem.setAttribute( "centroidWhole", centroidWhole );
1445  placementElem.setAttribute( "centroidInside", centroidInside );
1446  placementElem.setAttribute( "fitInPolygonOnly", fitInPolygonOnly );
1447  placementElem.setAttribute( "dist", dist );
1448  placementElem.setAttribute( "distInMapUnits", distInMapUnits );
1449  placementElem.setAttribute( "distMapUnitMinScale", distMapUnitScale.minScale );
1450  placementElem.setAttribute( "distMapUnitMaxScale", distMapUnitScale.maxScale );
1451  placementElem.setAttribute( "quadOffset", ( unsigned int )quadOffset );
1452  placementElem.setAttribute( "xOffset", xOffset );
1453  placementElem.setAttribute( "yOffset", yOffset );
1454  placementElem.setAttribute( "labelOffsetInMapUnits", labelOffsetInMapUnits );
1455  placementElem.setAttribute( "labelOffsetMapUnitMinScale", labelOffsetMapUnitScale.minScale );
1456  placementElem.setAttribute( "labelOffsetMapUnitMaxScale", labelOffsetMapUnitScale.maxScale );
1457  placementElem.setAttribute( "angleOffset", angleOffset );
1458  placementElem.setAttribute( "preserveRotation", preserveRotation );
1459  placementElem.setAttribute( "maxCurvedCharAngleIn", maxCurvedCharAngleIn );
1460  placementElem.setAttribute( "maxCurvedCharAngleOut", maxCurvedCharAngleOut );
1461  placementElem.setAttribute( "priority", priority );
1462  placementElem.setAttribute( "repeatDistance", repeatDistance );
1463  placementElem.setAttribute( "repeatDistanceUnit", repeatDistanceUnit );
1464  placementElem.setAttribute( "repeatDistanceMapUnitMinScale", repeatDistanceMapUnitScale.minScale );
1465  placementElem.setAttribute( "repeatDistanceMapUnitMaxScale", repeatDistanceMapUnitScale.maxScale );
1466 
1467  // rendering
1468  QDomElement renderingElem = doc.createElement( "rendering" );
1469  renderingElem.setAttribute( "scaleVisibility", scaleVisibility );
1470  renderingElem.setAttribute( "scaleMin", scaleMin );
1471  renderingElem.setAttribute( "scaleMax", scaleMax );
1472  renderingElem.setAttribute( "fontLimitPixelSize", fontLimitPixelSize );
1473  renderingElem.setAttribute( "fontMinPixelSize", fontMinPixelSize );
1474  renderingElem.setAttribute( "fontMaxPixelSize", fontMaxPixelSize );
1475  renderingElem.setAttribute( "displayAll", displayAll );
1476  renderingElem.setAttribute( "upsidedownLabels", ( unsigned int )upsidedownLabels );
1477 
1478  renderingElem.setAttribute( "labelPerPart", labelPerPart );
1479  renderingElem.setAttribute( "mergeLines", mergeLines );
1480  renderingElem.setAttribute( "minFeatureSize", minFeatureSize );
1481  renderingElem.setAttribute( "limitNumLabels", limitNumLabels );
1482  renderingElem.setAttribute( "maxNumLabels", maxNumLabels );
1483  renderingElem.setAttribute( "obstacle", obstacle );
1484  renderingElem.setAttribute( "obstacleFactor", obstacleFactor );
1485  renderingElem.setAttribute( "obstacleType", ( unsigned int )obstacleType );
1486 
1487  QDomElement ddElem = doc.createElement( "data-defined" );
1488  writeDataDefinedPropertyMap( 0, &ddElem, dataDefinedProperties );
1489 
1490  QDomElement elem = doc.createElement( "settings" );
1491  elem.appendChild( textStyleElem );
1492  elem.appendChild( textFormatElem );
1493  elem.appendChild( textBufferElem );
1494  elem.appendChild( backgroundElem );
1495  elem.appendChild( shadowElem );
1496  elem.appendChild( placementElem );
1497  elem.appendChild( renderingElem );
1498  elem.appendChild( ddElem );
1499  return elem;
1500 }
1501 
1503  bool active, bool useExpr, const QString& expr, const QString& field )
1504 {
1505  bool defaultVals = ( !active && !useExpr && expr.isEmpty() && field.isEmpty() );
1506 
1507  if ( dataDefinedProperties.contains( p ) )
1508  {
1510  if ( it != dataDefinedProperties.constEnd() )
1511  {
1512  QgsDataDefined* dd = it.value();
1513  dd->setActive( active );
1514  dd->setExpressionString( expr );
1515  dd->setField( field );
1516  dd->setUseExpression( useExpr );
1517  }
1518  }
1519  else if ( !defaultVals )
1520  {
1521  QgsDataDefined* dd = new QgsDataDefined( active, useExpr, expr, field );
1522  dataDefinedProperties.insert( p, dd );
1523  }
1524 }
1525 
1527 {
1529  if ( it != dataDefinedProperties.end() )
1530  {
1531  delete( it.value() );
1533  }
1534 }
1535 
1537 {
1539  for ( ; it != dataDefinedProperties.constEnd(); ++it )
1540  {
1541  delete( it.value() );
1542  it.value() = 0;
1543  }
1545 }
1546 
1548 {
1549  // TODO: update or remove this when project settings for labeling are migrated to better XML layout
1550  QString newValue = value;
1551  if ( !value.isEmpty() && !value.contains( "~~" ) )
1552  {
1553  QStringList values;
1554  values << "1"; // all old-style values are active if not empty
1555  values << "0";
1556  values << "";
1557  values << value; // all old-style values are only field names
1558  newValue = values.join( "~~" );
1559  }
1560 
1561  return newValue;
1562 }
1563 
1565 {
1567  return 0;
1568 
1570  if ( it != dataDefinedProperties.constEnd() )
1571  {
1572  return it.value();
1573  }
1574  return 0;
1575 }
1576 
1578 {
1581  if ( it != dataDefinedProperties.constEnd() )
1582  {
1583  return it.value()->toMap();
1584  }
1585  return map;
1586 }
1587 
1589 {
1591  {
1592  return QVariant();
1593  }
1594 
1595  //try to keep < 2.12 API - handle no passed expression context
1597  if ( !context )
1598  {
1599  scopedEc.reset( new QgsExpressionContext() );
1600  scopedEc->setFeature( f );
1601  scopedEc->setFields( fields );
1602  }
1603  const QgsExpressionContext* ec = context ? context : scopedEc.data();
1604 
1605  QgsDataDefined* dd = 0;
1607  if ( it != dataDefinedProperties.constEnd() )
1608  {
1609  dd = it.value();
1610  }
1611 
1612  if ( !dd )
1613  {
1614  return QVariant();
1615  }
1616 
1617  if ( !dd->isActive() )
1618  {
1619  return QVariant();
1620  }
1621 
1622  QVariant result = QVariant();
1623  bool useExpression = dd->useExpression();
1624  QString field = dd->field();
1625 
1626  //QgsDebugMsgLevel( QString( "isActive:" ) + isActive ? "1" : "0", 4 );
1627  //QgsDebugMsgLevel( QString( "useExpression:" ) + useExpression ? "1" : "0", 4 );
1628  //QgsDebugMsgLevel( QString( "expression:" ) + dd->expressionString(), 4 );
1629  //QgsDebugMsgLevel( QString( "field:" ) + field, 4 );
1630 
1631  if ( useExpression && dd->expressionIsPrepared() )
1632  {
1633  QgsExpression* expr = dd->expression();
1634  //QgsDebugMsgLevel( QString( "expr columns:" ) + expr->referencedColumns().join( "," ), 4 );
1635 
1636  result = expr->evaluate( ec );
1637  if ( expr->hasEvalError() )
1638  {
1639  QgsDebugMsgLevel( QString( "Evaluate error:" ) + expr->evalErrorString(), 4 );
1640  return QVariant();
1641  }
1642  }
1643  else if ( !useExpression && !field.isEmpty() )
1644  {
1645  // use direct attribute access instead of evaluating "field" expression (much faster)
1646  int indx = fields.indexFromName( field );
1647  if ( indx != -1 )
1648  {
1649  result = f.attribute( indx );
1650  }
1651  }
1652  return result;
1653 }
1654 
1656 {
1657  // null passed-around QVariant
1658  exprVal.clear();
1660  return false;
1661 
1662  //try to keep < 2.12 API - handle no passed expression context
1664  if ( !context )
1665  {
1666  scopedEc.reset( new QgsExpressionContext() );
1667  scopedEc->setFeature( *mCurFeat );
1668  scopedEc->setFields( mCurFields );
1669  }
1670  QgsExpressionContext* ec = context ? context : scopedEc.data();
1671 
1672  ec->setOriginalValueVariable( originalValue );
1673  QVariant result = dataDefinedValue( p, *mCurFeat, mCurFields, ec );
1674 
1675  if ( result.isValid() && !result.isNull() )
1676  {
1677  //QgsDebugMsgLevel( QString( "result type:" ) + QString( result.typeName() ), 4 );
1678  //QgsDebugMsgLevel( QString( "result string:" ) + result.toString(), 4 );
1679  exprVal = result;
1680  return true;
1681  }
1682 
1683  return false;
1684 }
1685 
1687 {
1689  return false;
1690 
1691  bool isActive = false;
1692 
1694  if ( it != dataDefinedProperties.constEnd() )
1695  {
1696  isActive = it.value()->isActive();
1697  }
1698 
1699  return isActive;
1700 }
1701 
1703 {
1705  return false;
1706 
1707  bool useExpression = false;
1709  if ( it != dataDefinedProperties.constEnd() )
1710  {
1711  useExpression = it.value()->useExpression();
1712  }
1713 
1714  return useExpression;
1715 }
1716 
1717 bool QgsPalLayerSettings::checkMinimumSizeMM( const QgsRenderContext& ct, const QgsGeometry* geom, double minSize ) const
1718 {
1719  return QgsPalLabeling::checkMinimumSizeMM( ct, geom, minSize );
1720 }
1721 
1722 void QgsPalLayerSettings::calculateLabelSize( const QFontMetricsF* fm, QString text, double& labelX, double& labelY, QgsFeature* f, QgsRenderContext *context )
1723 {
1724  if ( !fm || !f )
1725  {
1726  return;
1727  }
1728 
1729  //try to keep < 2.12 API - handle no passed render context
1731  if ( !context )
1732  {
1733  scopedRc.reset( new QgsRenderContext() );
1734  if ( f )
1735  scopedRc->expressionContext().setFeature( *f );
1736  }
1737  QgsRenderContext* rc = context ? context : scopedRc.data();
1738 
1739  QString wrapchr = wrapChar;
1740  double multilineH = multilineHeight;
1741 
1742  bool addDirSymb = addDirectionSymbol;
1743  QString leftDirSymb = leftDirectionSymbol;
1744  QString rightDirSymb = rightDirectionSymbol;
1746 
1747  if ( f == mCurFeat ) // called internally, use any stored data defined values
1748  {
1749  if ( dataDefinedValues.contains( QgsPalLayerSettings::MultiLineWrapChar ) )
1750  {
1751  wrapchr = dataDefinedValues.value( QgsPalLayerSettings::MultiLineWrapChar ).toString();
1752  }
1753 
1754  if ( dataDefinedValues.contains( QgsPalLayerSettings::MultiLineHeight ) )
1755  {
1756  multilineH = dataDefinedValues.value( QgsPalLayerSettings::MultiLineHeight ).toDouble();
1757  }
1758 
1759  if ( dataDefinedValues.contains( QgsPalLayerSettings::DirSymbDraw ) )
1760  {
1761  addDirSymb = dataDefinedValues.value( QgsPalLayerSettings::DirSymbDraw ).toBool();
1762  }
1763 
1764  if ( addDirSymb )
1765  {
1766 
1767  if ( dataDefinedValues.contains( QgsPalLayerSettings::DirSymbLeft ) )
1768  {
1769  leftDirSymb = dataDefinedValues.value( QgsPalLayerSettings::DirSymbLeft ).toString();
1770  }
1771  if ( dataDefinedValues.contains( QgsPalLayerSettings::DirSymbRight ) )
1772  {
1773  rightDirSymb = dataDefinedValues.value( QgsPalLayerSettings::DirSymbRight ).toString();
1774  }
1775 
1776  if ( dataDefinedValues.contains( QgsPalLayerSettings::DirSymbPlacement ) )
1777  {
1778  placeDirSymb = ( QgsPalLayerSettings::DirectionSymbols )dataDefinedValues.value( QgsPalLayerSettings::DirSymbPlacement ).toInt();
1779  }
1780 
1781  }
1782 
1783  }
1784  else // called externally with passed-in feature, evaluate data defined
1785  {
1788  if ( exprVal.isValid() )
1789  {
1790  wrapchr = exprVal.toString();
1791  }
1792  exprVal.clear();
1793  rc->expressionContext().setOriginalValueVariable( multilineH );
1795  if ( exprVal.isValid() )
1796  {
1797  bool ok;
1798  double size = exprVal.toDouble( &ok );
1799  if ( ok )
1800  {
1801  multilineH = size;
1802  }
1803  }
1804 
1805  exprVal.clear();
1806  rc->expressionContext().setOriginalValueVariable( addDirSymb );
1808  if ( exprVal.isValid() )
1809  {
1810  addDirSymb = exprVal.toBool();
1811  }
1812 
1813  if ( addDirSymb ) // don't do extra evaluations if not adding a direction symbol
1814  {
1815  exprVal.clear();
1816  rc->expressionContext().setOriginalValueVariable( leftDirSymb );
1818  if ( exprVal.isValid() )
1819  {
1820  leftDirSymb = exprVal.toString();
1821  }
1822  exprVal.clear();
1823  rc->expressionContext().setOriginalValueVariable( rightDirSymb );
1825  if ( exprVal.isValid() )
1826  {
1827  rightDirSymb = exprVal.toString();
1828  }
1829  exprVal.clear();
1830  rc->expressionContext().setOriginalValueVariable(( int )placeDirSymb );
1832  if ( exprVal.isValid() )
1833  {
1834  bool ok;
1835  int enmint = exprVal.toInt( &ok );
1836  if ( ok )
1837  {
1838  placeDirSymb = ( QgsPalLayerSettings::DirectionSymbols )enmint;
1839  }
1840  }
1841  }
1842 
1843  }
1844 
1845  if ( wrapchr.isEmpty() )
1846  {
1847  wrapchr = QLatin1String( "\n" ); // default to new line delimiter
1848  }
1849 
1850  //consider the space needed for the direction symbol
1851  if ( addDirSymb && placement == QgsPalLayerSettings::Line
1852  && ( !leftDirSymb.isEmpty() || !rightDirSymb.isEmpty() ) )
1853  {
1854  QString dirSym = leftDirSymb;
1855 
1856  if ( fm->width( rightDirSymb ) > fm->width( dirSym ) )
1857  dirSym = rightDirSymb;
1858 
1859  if ( placeDirSymb == QgsPalLayerSettings::SymbolLeftRight )
1860  {
1861  text.append( dirSym );
1862  }
1863  else
1864  {
1865  text.prepend( dirSym + QLatin1String( "\n" ) ); // SymbolAbove or SymbolBelow
1866  }
1867  }
1868 
1869  double w = 0.0, h = 0.0;
1870  QStringList multiLineSplit = QgsPalLabeling::splitToLines( text, wrapchr );
1871  int lines = multiLineSplit.size();
1872 
1873  double labelHeight = fm->ascent() + fm->descent(); // ignore +1 for baseline
1874 
1875  h += fm->height() + ( double )(( lines - 1 ) * labelHeight * multilineH );
1876  h /= rasterCompressFactor;
1877 
1878  for ( int i = 0; i < lines; ++i )
1879  {
1880  double width = fm->width( multiLineSplit.at( i ) );
1881  if ( width > w )
1882  {
1883  w = width;
1884  }
1885  }
1886  w /= rasterCompressFactor;
1887 
1888 #if 0 // XXX strk
1889  QgsPoint ptSize = xform->toMapCoordinatesF( w, h );
1890  labelX = qAbs( ptSize.x() - ptZero.x() );
1891  labelY = qAbs( ptSize.y() - ptZero.y() );
1892 #else
1893  double uPP = xform->mapUnitsPerPixel();
1894  labelX = w * uPP;
1895  labelY = h * uPP;
1896 #endif
1897 }
1898 
1899 
1900 void QgsPalLayerSettings::registerFeature( QgsFeature& f, QgsRenderContext &context, const QString& dxfLayer, QgsLabelFeature** labelFeature )
1901 {
1902  // either used in QgsPalLabeling (palLayer is set) or in QgsLabelingEngineV2 (labelFeature is set)
1903  Q_ASSERT( labelFeature );
1904 
1905  Q_UNUSED( dxfLayer ); // now handled in QgsDxfLabelProvider
1906 
1907  if ( !drawLabels )
1908  {
1909  if ( obstacle )
1910  {
1911  registerObstacleFeature( f, context, QString(), labelFeature );
1912  }
1913  return;
1914  }
1915 
1916  QVariant exprVal; // value() is repeatedly nulled on data defined evaluation and replaced when successful
1917  mCurFeat = &f;
1918 // mCurFields = &layer->pendingFields();
1919 
1920  // store data defined-derived values for later adding to label feature for use during rendering
1921  dataDefinedValues.clear();
1922 
1923  // data defined show label? defaults to show label if not 0
1925  {
1926  bool showLabel = dataDefinedEvaluate( QgsPalLayerSettings::Show, exprVal, &context.expressionContext(), true );
1927  showLabel &= exprVal.toBool();
1928  QgsDebugMsgLevel( QString( "exprVal Show:%1" ).arg( showLabel ? "true" : "false" ), 4 );
1929  if ( !showLabel )
1930  {
1931  return;
1932  }
1933  }
1934 
1935  // data defined scale visibility?
1936  bool useScaleVisibility = scaleVisibility;
1938  {
1939  QgsDebugMsgLevel( QString( "exprVal ScaleVisibility:%1" ).arg( exprVal.toBool() ? "true" : "false" ), 4 );
1940  useScaleVisibility = exprVal.toBool();
1941  }
1942 
1943  if ( useScaleVisibility )
1944  {
1945  // data defined min scale?
1946  double minScale = scaleMin;
1948  {
1949  QgsDebugMsgLevel( QString( "exprVal MinScale:%1" ).arg( exprVal.toDouble() ), 4 );
1950  bool conversionOk;
1951  double mins = exprVal.toDouble( &conversionOk );
1952  if ( conversionOk )
1953  {
1954  minScale = mins;
1955  }
1956  }
1957 
1958  // scales closer than 1:1
1959  if ( minScale < 0 )
1960  {
1961  minScale = 1 / qAbs( minScale );
1962  }
1963 
1964  if ( minScale != 0 && context.rendererScale() < minScale )
1965  {
1966  return;
1967  }
1968 
1969  // data defined max scale?
1970  double maxScale = scaleMax;
1972  {
1973  QgsDebugMsgLevel( QString( "exprVal MaxScale:%1" ).arg( exprVal.toDouble() ), 4 );
1974  bool conversionOk;
1975  double maxs = exprVal.toDouble( &conversionOk );
1976  if ( conversionOk )
1977  {
1978  maxScale = maxs;
1979  }
1980  }
1981 
1982  // scales closer than 1:1
1983  if ( maxScale < 0 )
1984  {
1985  maxScale = 1 / qAbs( maxScale );
1986  }
1987 
1988  if ( maxScale != 0 && context.rendererScale() > maxScale )
1989  {
1990  return;
1991  }
1992  }
1993 
1994  QFont labelFont = textFont;
1995  // labelFont will be added to label feature for use during label painting
1996 
1997  // data defined font units?
2000  {
2001  QString units = exprVal.toString().trimmed();
2002  QgsDebugMsgLevel( QString( "exprVal Font units:%1" ).arg( units ), 4 );
2003  if ( !units.isEmpty() )
2004  {
2005  fontunits = _decodeUnits( units );
2006  }
2007  }
2008 
2009  //data defined label size?
2010  double fontSize = labelFont.pointSizeF(); // font size doesn't have its own class data member
2011  if ( dataDefinedEvaluate( QgsPalLayerSettings::Size, exprVal, &context.expressionContext(), fontSize ) )
2012  {
2013  QgsDebugMsgLevel( QString( "exprVal Size:%1" ).arg( exprVal.toDouble() ), 4 );
2014  bool ok;
2015  double size = exprVal.toDouble( &ok );
2016  if ( ok )
2017  {
2018  fontSize = size;
2019  }
2020  }
2021  if ( fontSize <= 0.0 )
2022  {
2023  return;
2024  }
2025 
2026  int fontPixelSize = sizeToPixel( fontSize, context, fontunits, true, fontSizeMapUnitScale );
2027  // don't try to show font sizes less than 1 pixel (Qt complains)
2028  if ( fontPixelSize < 1 )
2029  {
2030  return;
2031  }
2032  labelFont.setPixelSize( fontPixelSize );
2033 
2034  // NOTE: labelFont now always has pixelSize set, so pointSize or pointSizeF might return -1
2035 
2036  // defined 'minimum/maximum pixel font size'?
2037  if ( fontunits == QgsPalLayerSettings::MapUnits )
2038  {
2039  bool useFontLimitPixelSize = fontLimitPixelSize;
2041  {
2042  QgsDebugMsgLevel( QString( "exprVal FontLimitPixel:%1" ).arg( exprVal.toBool() ? "true" : "false" ), 4 );
2043  useFontLimitPixelSize = exprVal.toBool();
2044  }
2045 
2046  if ( useFontLimitPixelSize )
2047  {
2048  int fontMinPixel = fontMinPixelSize;
2050  {
2051  bool ok;
2052  int sizeInt = exprVal.toInt( &ok );
2053  QgsDebugMsgLevel( QString( "exprVal FontMinPixel:%1" ).arg( sizeInt ), 4 );
2054  if ( ok )
2055  {
2056  fontMinPixel = sizeInt;
2057  }
2058  }
2059 
2060  int fontMaxPixel = fontMaxPixelSize;
2062  {
2063  bool ok;
2064  int sizeInt = exprVal.toInt( &ok );
2065  QgsDebugMsgLevel( QString( "exprVal FontMaxPixel:%1" ).arg( sizeInt ), 4 );
2066  if ( ok )
2067  {
2068  fontMaxPixel = sizeInt;
2069  }
2070  }
2071 
2072  if ( fontMinPixel > labelFont.pixelSize() || labelFont.pixelSize() > fontMaxPixel )
2073  {
2074  return;
2075  }
2076  }
2077  }
2078 
2079  // NOTE: the following parsing functions calculate and store any data defined values for later use in QgsPalLabeling::drawLabeling
2080  // this is done to provide clarity, and because such parsing is not directly related to PAL feature registration calculations
2081 
2082  // calculate rest of font attributes and store any data defined values
2083  // this is done here for later use in making label backgrounds part of collision management (when implemented)
2084  parseTextStyle( labelFont, fontunits, context );
2085  parseTextFormatting( context );
2086  parseTextBuffer( context );
2087  parseShapeBackground( context );
2088  parseDropShadow( context );
2089 
2090  QString labelText;
2091 
2092  // Check to see if we are a expression string.
2093  if ( isExpression )
2094  {
2096  if ( exp->hasParserError() )
2097  {
2098  QgsDebugMsgLevel( QString( "Expression parser error:%1" ).arg( exp->parserErrorString() ), 4 );
2099  return;
2100  }
2101  exp->setScale( context.rendererScale() );
2102 // QVariant result = exp->evaluate( &f, layer->pendingFields() );
2103  QVariant result = exp->evaluate( &context.expressionContext() ); // expression prepared in QgsPalLabeling::prepareLayer()
2104  if ( exp->hasEvalError() )
2105  {
2106  QgsDebugMsgLevel( QString( "Expression parser eval error:%1" ).arg( exp->evalErrorString() ), 4 );
2107  return;
2108  }
2109  labelText = result.isNull() ? "" : result.toString();
2110  }
2111  else
2112  {
2113  const QVariant &v = f.attribute( fieldIndex );
2114  labelText = v.isNull() ? "" : v.toString();
2115  }
2116 
2117  // data defined format numbers?
2118  bool formatnum = formatNumbers;
2120  {
2121  formatnum = exprVal.toBool();
2122  QgsDebugMsgLevel( QString( "exprVal NumFormat:%1" ).arg( formatnum ? "true" : "false" ), 4 );
2123  }
2124 
2125  // format number if label text is coercible to a number
2126  if ( formatnum )
2127  {
2128  // data defined decimal places?
2129  int decimalPlaces = decimals;
2131  {
2132  bool ok;
2133  int dInt = exprVal.toInt( &ok );
2134  QgsDebugMsgLevel( QString( "exprVal NumDecimals:%1" ).arg( dInt ), 4 );
2135  if ( ok && dInt > 0 ) // needs to be positive
2136  {
2137  decimalPlaces = dInt;
2138  }
2139  }
2140 
2141  // data defined plus sign?
2142  bool signPlus = plusSign;
2144  {
2145  signPlus = exprVal.toBool();
2146  QgsDebugMsgLevel( QString( "exprVal NumPlusSign:%1" ).arg( signPlus ? "true" : "false" ), 4 );
2147  }
2148 
2149  QVariant textV( labelText );
2150  bool ok;
2151  double d = textV.toDouble( &ok );
2152  if ( ok )
2153  {
2154  QString numberFormat;
2155  if ( d > 0 && signPlus )
2156  {
2157  numberFormat.append( "+" );
2158  }
2159  numberFormat.append( "%1" );
2160  labelText = numberFormat.arg( d, 0, 'f', decimalPlaces );
2161  }
2162  }
2163 
2164 
2165  // NOTE: this should come AFTER any option that affects font metrics
2166  QScopedPointer<QFontMetricsF> labelFontMetrics( new QFontMetricsF( labelFont ) );
2167  double labelX, labelY; // will receive label size
2168  calculateLabelSize( labelFontMetrics.data(), labelText, labelX, labelY, mCurFeat, &context );
2169 
2170 
2171  // maximum angle between curved label characters (hardcoded defaults used in QGIS <2.0)
2172  //
2173  double maxcharanglein = 20.0; // range 20.0-60.0
2174  double maxcharangleout = -20.0; // range 20.0-95.0
2175 
2177  {
2178  maxcharanglein = maxCurvedCharAngleIn;
2179  maxcharangleout = maxCurvedCharAngleOut;
2180 
2181  //data defined maximum angle between curved label characters?
2183  {
2184  QString ptstr = exprVal.toString().trimmed();
2185  QgsDebugMsgLevel( QString( "exprVal CurvedCharAngleInOut:%1" ).arg( ptstr ), 4 );
2186 
2187  if ( !ptstr.isEmpty() )
2188  {
2189  QPointF maxcharanglePt = QgsSymbolLayerV2Utils::decodePoint( ptstr );
2190  maxcharanglein = qBound( 20.0, ( double )maxcharanglePt.x(), 60.0 );
2191  maxcharangleout = qBound( 20.0, ( double )maxcharanglePt.y(), 95.0 );
2192  }
2193  }
2194  // make sure maxcharangleout is always negative
2195  maxcharangleout = -( qAbs( maxcharangleout ) );
2196  }
2197 
2198  // data defined centroid whole or clipped?
2199  bool wholeCentroid = centroidWhole;
2201  {
2202  QString str = exprVal.toString().trimmed();
2203  QgsDebugMsgLevel( QString( "exprVal CentroidWhole:%1" ).arg( str ), 4 );
2204 
2205  if ( !str.isEmpty() )
2206  {
2207  if ( str.compare( "Visible", Qt::CaseInsensitive ) == 0 )
2208  {
2209  wholeCentroid = false;
2210  }
2211  else if ( str.compare( "Whole", Qt::CaseInsensitive ) == 0 )
2212  {
2213  wholeCentroid = true;
2214  }
2215  }
2216  }
2217 
2218  const QgsGeometry* geom = f.constGeometry();
2219  if ( !geom )
2220  {
2221  return;
2222  }
2223 
2224  // whether we're going to create a centroid for polygon
2225  bool centroidPoly = (( placement == QgsPalLayerSettings::AroundPoint
2227  && geom->type() == QGis::Polygon );
2228 
2229  // CLIP the geometry if it is bigger than the extent
2230  // don't clip if centroid is requested for whole feature
2231  bool doClip = false;
2232  if ( !centroidPoly || !wholeCentroid )
2233  {
2234  doClip = true;
2235  }
2236 
2237  const GEOSGeometry* geos_geom = 0;
2238  const QgsGeometry* preparedGeom = geom;
2239  QScopedPointer<QgsGeometry> scopedPreparedGeom;
2240 
2241  if ( QgsPalLabeling::geometryRequiresPreparation( geom, context, ct, doClip ? extentGeom : 0 ) )
2242  {
2243  scopedPreparedGeom.reset( QgsPalLabeling::prepareGeometry( geom, context, ct, doClip ? extentGeom : 0 ) );
2244  if ( !scopedPreparedGeom.data() )
2245  return;
2246  preparedGeom = scopedPreparedGeom.data();
2247  geos_geom = scopedPreparedGeom.data()->asGeos();
2248  }
2249  else
2250  {
2251  geos_geom = geom->asGeos();
2252  }
2253 
2254  if ( minFeatureSize > 0 && !checkMinimumSizeMM( context, preparedGeom, minFeatureSize ) )
2255  return;
2256 
2257  if ( geos_geom == NULL )
2258  return; // invalid geometry
2259 
2260  // likelihood exists label will be registered with PAL and may be drawn
2261  // check if max number of features to label (already registered with PAL) has been reached
2262  // Debug output at end of QgsPalLabeling::drawLabeling(), when deleting temp geometries
2263  if ( limitNumLabels )
2264  {
2265  if ( !maxNumLabels )
2266  {
2267  return;
2268  }
2269  if ( mFeatsRegPal >= maxNumLabels )
2270  {
2271  return;
2272  }
2273 
2274  int divNum = ( int )((( double )mFeaturesToLabel / maxNumLabels ) + 0.5 );
2275  if ( divNum && ( mFeatsRegPal == ( int )( mFeatsSendingToPal / divNum ) ) )
2276  {
2277  mFeatsSendingToPal += 1;
2278  if ( divNum && mFeatsSendingToPal % divNum )
2279  {
2280  return;
2281  }
2282  }
2283  }
2284 
2285  GEOSGeometry* geos_geom_clone;
2286  if ( GEOSGeomTypeId_r( QgsGeometry::getGEOSHandler(), geos_geom ) == GEOS_POLYGON && repeatDistance > 0 && placement == Line )
2287  {
2288  geos_geom_clone = GEOSBoundary_r( QgsGeometry::getGEOSHandler(), geos_geom );
2289  }
2290  else
2291  {
2292  geos_geom_clone = GEOSGeom_clone_r( QgsGeometry::getGEOSHandler(), geos_geom );
2293  }
2294 
2295  //data defined position / alignment / rotation?
2296  bool dataDefinedPosition = false;
2297  bool layerDefinedRotation = false;
2298  bool dataDefinedRotation = false;
2299  double xPos = 0.0, yPos = 0.0, angle = 0.0;
2300  bool ddXPos = false, ddYPos = false;
2301  double quadOffsetX = 0.0, quadOffsetY = 0.0;
2302  double offsetX = 0.0, offsetY = 0.0;
2303 
2304  //data defined quadrant offset?
2305  bool ddFixedQuad = false;
2306  QuadrantPosition quadOff = quadOffset;
2307  if ( dataDefinedEvaluate( QgsPalLayerSettings::OffsetQuad, exprVal, &context.expressionContext(), ( int )quadOff ) )
2308  {
2309  bool ok;
2310  int quadInt = exprVal.toInt( &ok );
2311  QgsDebugMsgLevel( QString( "exprVal OffsetQuad:%1" ).arg( quadInt ), 4 );
2312  if ( ok && 0 <= quadInt && quadInt <= 8 )
2313  {
2314  quadOff = ( QuadrantPosition )quadInt;
2315  ddFixedQuad = true;
2316  }
2317  }
2318 
2319  // adjust quadrant offset of labels
2320  switch ( quadOff )
2321  {
2322  case QuadrantAboveLeft:
2323  quadOffsetX = -1.0;
2324  quadOffsetY = 1.0;
2325  break;
2326  case QuadrantAbove:
2327  quadOffsetX = 0.0;
2328  quadOffsetY = 1.0;
2329  break;
2330  case QuadrantAboveRight:
2331  quadOffsetX = 1.0;
2332  quadOffsetY = 1.0;
2333  break;
2334  case QuadrantLeft:
2335  quadOffsetX = -1.0;
2336  quadOffsetY = 0.0;
2337  break;
2338  case QuadrantRight:
2339  quadOffsetX = 1.0;
2340  quadOffsetY = 0.0;
2341  break;
2342  case QuadrantBelowLeft:
2343  quadOffsetX = -1.0;
2344  quadOffsetY = -1.0;
2345  break;
2346  case QuadrantBelow:
2347  quadOffsetX = 0.0;
2348  quadOffsetY = -1.0;
2349  break;
2350  case QuadrantBelowRight:
2351  quadOffsetX = 1.0;
2352  quadOffsetY = -1.0;
2353  break;
2354  case QuadrantOver:
2355  default:
2356  break;
2357  }
2358 
2359  //data defined label offset?
2360  double xOff = xOffset;
2361  double yOff = yOffset;
2363  {
2364  QString ptstr = exprVal.toString().trimmed();
2365  QgsDebugMsgLevel( QString( "exprVal OffsetXY:%1" ).arg( ptstr ), 4 );
2366 
2367  if ( !ptstr.isEmpty() )
2368  {
2369  QPointF ddOffPt = QgsSymbolLayerV2Utils::decodePoint( ptstr );
2370  xOff = ddOffPt.x();
2371  yOff = ddOffPt.y();
2372  }
2373  }
2374 
2375  // data defined label offset units?
2376  bool offinmapunits = labelOffsetInMapUnits;
2378  {
2379  QString units = exprVal.toString().trimmed();
2380  QgsDebugMsgLevel( QString( "exprVal OffsetUnits:%1" ).arg( units ), 4 );
2381  if ( !units.isEmpty() )
2382  {
2383  offinmapunits = ( _decodeUnits( units ) == QgsPalLayerSettings::MapUnits );
2384  }
2385  }
2386 
2387  // adjust offset of labels to match chosen unit and map scale
2388  // offsets match those of symbology: -x = left, -y = up
2389  double mapUntsPerMM = labelOffsetMapUnitScale.computeMapUnitsPerPixel( context ) * context.scaleFactor();
2390  if ( xOff != 0 )
2391  {
2392  offsetX = xOff; // must be positive to match symbology offset direction
2393  if ( !offinmapunits )
2394  {
2395  offsetX *= mapUntsPerMM; //convert offset from mm to map units
2396  }
2397  }
2398  if ( yOff != 0 )
2399  {
2400  offsetY = -yOff; // must be negative to match symbology offset direction
2401  if ( !offinmapunits )
2402  {
2403  offsetY *= mapUntsPerMM; //convert offset from mm to map units
2404  }
2405  }
2406 
2407  // layer defined rotation?
2408  // only rotate non-pinned OverPoint placements until other placements are supported in pal::Feature
2409  if ( placement == QgsPalLayerSettings::OverPoint && angleOffset != 0 )
2410  {
2411  layerDefinedRotation = true;
2412  angle = angleOffset * M_PI / 180; // convert to radians
2413  }
2414 
2415  const QgsMapToPixel& m2p = context.mapToPixel();
2416  //data defined rotation?
2418  {
2419  bool ok;
2420  double rotD = exprVal.toDouble( &ok );
2421  QgsDebugMsgLevel( QString( "exprVal Rotation:%1" ).arg( rotD ), 4 );
2422  if ( ok )
2423  {
2424  dataDefinedRotation = true;
2425  // TODO: add setting to disable having data defined rotation follow
2426  // map rotation ?
2427  rotD -= m2p.mapRotation();
2428  angle = rotD * M_PI / 180.0;
2429  }
2430  }
2431 
2433  {
2434  if ( !exprVal.isNull() )
2435  xPos = exprVal.toDouble( &ddXPos );
2436  QgsDebugMsgLevel( QString( "exprVal PositionX:%1" ).arg( xPos ), 4 );
2437 
2439  {
2440  //data defined position. But field values could be NULL -> positions will be generated by PAL
2441  if ( !exprVal.isNull() )
2442  yPos = exprVal.toDouble( &ddYPos );
2443  QgsDebugMsgLevel( QString( "exprVal PositionY:%1" ).arg( yPos ), 4 );
2444 
2445  if ( ddXPos && ddYPos )
2446  {
2447  dataDefinedPosition = true;
2448  // layer rotation set, but don't rotate pinned labels unless data defined
2449  if ( layerDefinedRotation && !dataDefinedRotation )
2450  {
2451  angle = 0.0;
2452  }
2453 
2454  //x/y shift in case of alignment
2455  double xdiff = 0.0;
2456  double ydiff = 0.0;
2457 
2458  //horizontal alignment
2459  if ( dataDefinedEvaluate( QgsPalLayerSettings::Hali, exprVal, &context.expressionContext() ) )
2460  {
2461  QString haliString = exprVal.toString();
2462  QgsDebugMsgLevel( QString( "exprVal Hali:%1" ).arg( haliString ), 4 );
2463  if ( haliString.compare( "Center", Qt::CaseInsensitive ) == 0 )
2464  {
2465  xdiff -= labelX / 2.0;
2466  }
2467  else if ( haliString.compare( "Right", Qt::CaseInsensitive ) == 0 )
2468  {
2469  xdiff -= labelX;
2470  }
2471  }
2472 
2473  //vertical alignment
2474  if ( dataDefinedEvaluate( QgsPalLayerSettings::Vali, exprVal, &context.expressionContext() ) )
2475  {
2476  QString valiString = exprVal.toString();
2477  QgsDebugMsgLevel( QString( "exprVal Vali:%1" ).arg( valiString ), 4 );
2478 
2479  if ( valiString.compare( "Bottom", Qt::CaseInsensitive ) != 0 )
2480  {
2481  if ( valiString.compare( "Top", Qt::CaseInsensitive ) == 0 )
2482  {
2483  ydiff -= labelY;
2484  }
2485  else
2486  {
2487  double descentRatio = labelFontMetrics->descent() / labelFontMetrics->height();
2488  if ( valiString.compare( "Base", Qt::CaseInsensitive ) == 0 )
2489  {
2490  ydiff -= labelY * descentRatio;
2491  }
2492  else //'Cap' or 'Half'
2493  {
2494  double capHeightRatio = ( labelFontMetrics->boundingRect( 'H' ).height() + 1 + labelFontMetrics->descent() ) / labelFontMetrics->height();
2495  ydiff -= labelY * capHeightRatio;
2496  if ( valiString.compare( "Half", Qt::CaseInsensitive ) == 0 )
2497  {
2498  ydiff += labelY * ( capHeightRatio - descentRatio ) / 2.0;
2499  }
2500  }
2501  }
2502  }
2503  }
2504 
2505  if ( dataDefinedRotation )
2506  {
2507  //adjust xdiff and ydiff because the hali/vali point needs to be the rotation center
2508  double xd = xdiff * cos( angle ) - ydiff * sin( angle );
2509  double yd = xdiff * sin( angle ) + ydiff * cos( angle );
2510  xdiff = xd;
2511  ydiff = yd;
2512  }
2513 
2514  //project xPos and yPos from layer to map CRS
2515  double z = 0;
2516  if ( ct )
2517  {
2518  try
2519  {
2520  ct->transformInPlace( xPos, yPos, z );
2521  }
2522  catch ( QgsCsException &e )
2523  {
2524  Q_UNUSED( e );
2525  QgsDebugMsgLevel( QString( "Ignoring feature %1 due transformation exception on data-defined position" ).arg( f.id() ), 4 );
2526  return;
2527  }
2528  }
2529 
2530  //rotate position with map if data-defined
2531  if ( dataDefinedPosition && m2p.mapRotation() )
2532  {
2533  const QgsPoint& center = context.extent().center();
2534  QTransform t = QTransform::fromTranslate( center.x(), center.y() );
2535  t.rotate( -m2p.mapRotation() );
2536  t.translate( -center.x(), -center.y() );
2537  qreal xPosR, yPosR;
2538  qreal xPos_qreal = xPos, yPos_qreal = yPos;
2539  t.map( xPos_qreal, yPos_qreal, &xPosR, &yPosR );
2540  xPos = xPosR; yPos = yPosR;
2541 
2542  }
2543 
2544  xPos += xdiff;
2545  yPos += ydiff;
2546  }
2547  else
2548  {
2549  // only rotate non-pinned OverPoint placements until other placements are supported in pal::Feature
2550  if ( dataDefinedRotation && placement != QgsPalLayerSettings::OverPoint )
2551  {
2552  angle = 0.0;
2553  }
2554  }
2555  }
2556  }
2557 
2558  // data defined always show?
2559  bool alwaysShow = false;
2561  {
2562  alwaysShow = exprVal.toBool();
2563  }
2564 
2565  // set repeat distance
2566  // data defined repeat distance?
2567  double repeatDist = repeatDistance;
2569  {
2570  bool ok;
2571  double distD = exprVal.toDouble( &ok );
2572  if ( ok )
2573  {
2574  repeatDist = distD;
2575  }
2576  }
2577 
2578  // data defined label-repeat distance units?
2579  bool repeatdistinmapunit = repeatDistanceUnit == QgsPalLayerSettings::MapUnits;
2581  {
2582  QString units = exprVal.toString().trimmed();
2583  QgsDebugMsgLevel( QString( "exprVal RepeatDistanceUnits:%1" ).arg( units ), 4 );
2584  if ( !units.isEmpty() )
2585  {
2586  repeatdistinmapunit = ( _decodeUnits( units ) == QgsPalLayerSettings::MapUnits );
2587  }
2588  }
2589 
2590  if ( !qgsDoubleNear( repeatDist, 0.0 ) )
2591  {
2592  if ( !repeatdistinmapunit )
2593  {
2594  repeatDist *= mapUntsPerMM; //convert repeat distance from mm to map units
2595  }
2596  }
2597 
2598  // feature to the layer
2599  QgsTextLabelFeature* lf = new QgsTextLabelFeature( f.id(), geos_geom_clone, QSizeF( labelX, labelY ) );
2600  mFeatsRegPal++;
2601 
2602  *labelFeature = lf;
2603  ( *labelFeature )->setHasFixedPosition( dataDefinedPosition );
2604  ( *labelFeature )->setFixedPosition( QgsPoint( xPos, yPos ) );
2605  // use layer-level defined rotation, but not if position fixed
2606  ( *labelFeature )->setHasFixedAngle( dataDefinedRotation || ( !dataDefinedPosition && angle != 0 ) );
2607  ( *labelFeature )->setFixedAngle( angle );
2608  ( *labelFeature )->setQuadOffset( QPointF( quadOffsetX, quadOffsetY ) );
2609  ( *labelFeature )->setPositionOffset( QgsPoint( offsetX, offsetY ) );
2610  ( *labelFeature )->setAlwaysShow( alwaysShow );
2611  ( *labelFeature )->setRepeatDistance( repeatDist );
2612  ( *labelFeature )->setLabelText( labelText );
2613 
2614  // store the label's calculated font for later use during painting
2615  QgsDebugMsgLevel( QString( "PAL font stored definedFont: %1, Style: %2" ).arg( labelFont.toString(), labelFont.styleName() ), 4 );
2616  lf->setDefinedFont( labelFont );
2617 
2618  // TODO: only for placement which needs character info
2619  // account for any data defined font metrics adjustments
2620  lf->calculateInfo( placement == QgsPalLayerSettings::Curved, labelFontMetrics.data(), xform, rasterCompressFactor, maxcharanglein, maxcharangleout );
2621  // for labelFeature the LabelInfo is passed to feat when it is registered
2622 
2623  // TODO: allow layer-wide feature dist in PAL...?
2624 
2625  // data defined label-feature distance?
2626  double distance = dist;
2628  {
2629  bool ok;
2630  double distD = exprVal.toDouble( &ok );
2631  if ( ok )
2632  {
2633  distance = distD;
2634  }
2635  }
2636 
2637  // data defined label-feature distance units?
2638  bool distinmapunit = distInMapUnits;
2640  {
2641  QString units = exprVal.toString().trimmed();
2642  QgsDebugMsgLevel( QString( "exprVal DistanceUnits:%1" ).arg( units ), 4 );
2643  if ( !units.isEmpty() )
2644  {
2645  distinmapunit = ( _decodeUnits( units ) == QgsPalLayerSettings::MapUnits );
2646  }
2647  }
2648 
2649  if ( distance != 0 )
2650  {
2651  if ( distinmapunit ) //convert distance from mm/map units to pixels
2652  {
2653  distance /= distMapUnitScale.computeMapUnitsPerPixel( context );
2654  }
2655  else //mm
2656  {
2657  distance *= vectorScaleFactor;
2658  }
2659  double d = qAbs( ptOne.x() - ptZero.x() ) * distance;
2660  ( *labelFeature )->setDistLabel( d );
2661  }
2662 
2663  if ( ddFixedQuad )
2664  {
2665  ( *labelFeature )->setHasFixedQuadrant( true );
2666  }
2667 
2668  // data defined priority?
2670  {
2671  bool ok;
2672  double priorityD = exprVal.toDouble( &ok );
2673  if ( ok )
2674  {
2675  priorityD = qBound( 0.0, priorityD, 10.0 );
2676  priorityD = 1 - priorityD / 10.0; // convert 0..10 --> 1..0
2677  ( *labelFeature )->setPriority( priorityD );
2678  }
2679  }
2680 
2681  // data defined is obstacle?
2682  bool isObstacle = obstacle; // start with layer default
2684  {
2685  isObstacle = exprVal.toBool();
2686  }
2687 
2688  ( *labelFeature )->setIsObstacle( isObstacle );
2689 
2690  double featObstacleFactor = obstacleFactor;
2692  {
2693  bool ok;
2694  double factorD = exprVal.toDouble( &ok );
2695  if ( ok )
2696  {
2697  factorD = qBound( 0.0, factorD, 10.0 );
2698  factorD = factorD / 5.0 + 0.0001; // convert 0 -> 10 to 0.0001 -> 2.0
2699  featObstacleFactor = factorD;
2700  }
2701  }
2702  ( *labelFeature )->setObstacleFactor( featObstacleFactor );
2703 
2704  // add parameters for data defined labeling to label feature
2705  lf->setDataDefinedValues( dataDefinedValues );
2706 }
2707 
2708 
2709 void QgsPalLayerSettings::registerObstacleFeature( QgsFeature& f, QgsRenderContext &context, const QString& dxfLayer, QgsLabelFeature** obstacleFeature )
2710 {
2711  Q_UNUSED( dxfLayer ); // now handled in QgsDxfLabelProvider
2712 
2713  mCurFeat = &f;
2714 
2715  const QgsGeometry* geom = f.constGeometry();
2716  if ( !geom )
2717  {
2718  return;
2719  }
2720 
2721  const GEOSGeometry* geos_geom = 0;
2722  QScopedPointer<QgsGeometry> scopedPreparedGeom;
2723 
2725  {
2726  scopedPreparedGeom.reset( QgsPalLabeling::prepareGeometry( geom, context, ct, extentGeom ) );
2727  if ( !scopedPreparedGeom.data() )
2728  return;
2729  geos_geom = scopedPreparedGeom.data()->asGeos();
2730  }
2731  else
2732  {
2733  geos_geom = geom->asGeos();
2734  }
2735 
2736  if ( geos_geom == NULL )
2737  return; // invalid geometry
2738 
2739  GEOSGeometry* geos_geom_clone;
2740  geos_geom_clone = GEOSGeom_clone_r( QgsGeometry::getGEOSHandler(), geos_geom );
2741 
2742  // feature to the layer
2743  *obstacleFeature = new QgsLabelFeature( f.id(), geos_geom_clone, QSizeF( 0, 0 ) );
2744  ( *obstacleFeature )->setIsObstacle( true );
2745  mFeatsRegPal++;
2746 }
2747 
2748 bool QgsPalLayerSettings::dataDefinedValEval( DataDefinedValueType valType,
2750  QVariant& exprVal, QgsExpressionContext& context, const QVariant& originalValue )
2751 {
2752  if ( dataDefinedEvaluate( p, exprVal, &context, originalValue ) )
2753  {
2754  QString dbgStr = QString( "exprVal %1:" ).arg( mDataDefinedNames.value( p ).first ) + "%1";
2755 
2756  switch ( valType )
2757  {
2758  case DDBool:
2759  {
2760  bool bol = exprVal.toBool();
2761  QgsDebugMsgLevel( dbgStr.arg( bol ? "true" : "false" ), 4 );
2762  dataDefinedValues.insert( p, QVariant( bol ) );
2763  return true;
2764  }
2765  case DDInt:
2766  {
2767  bool ok;
2768  int size = exprVal.toInt( &ok );
2769  QgsDebugMsgLevel( dbgStr.arg( size ), 4 );
2770 
2771  if ( ok )
2772  {
2773  dataDefinedValues.insert( p, QVariant( size ) );
2774  return true;
2775  }
2776  return false;
2777  }
2778  case DDIntPos:
2779  {
2780  bool ok;
2781  int size = exprVal.toInt( &ok );
2782  QgsDebugMsgLevel( dbgStr.arg( size ), 4 );
2783 
2784  if ( ok && size > 0 )
2785  {
2786  dataDefinedValues.insert( p, QVariant( size ) );
2787  return true;
2788  }
2789  return false;
2790  }
2791  case DDDouble:
2792  {
2793  bool ok;
2794  double size = exprVal.toDouble( &ok );
2795  QgsDebugMsgLevel( dbgStr.arg( size ), 4 );
2796 
2797  if ( ok )
2798  {
2799  dataDefinedValues.insert( p, QVariant( size ) );
2800  return true;
2801  }
2802  return false;
2803  }
2804  case DDDoublePos:
2805  {
2806  bool ok;
2807  double size = exprVal.toDouble( &ok );
2808  QgsDebugMsgLevel( dbgStr.arg( size ), 4 );
2809 
2810  if ( ok && size > 0.0 )
2811  {
2812  dataDefinedValues.insert( p, QVariant( size ) );
2813  return true;
2814  }
2815  return false;
2816  }
2817  case DDRotation180:
2818  {
2819  bool ok;
2820  double rot = exprVal.toDouble( &ok );
2821  QgsDebugMsgLevel( dbgStr.arg( rot ), 4 );
2822  if ( ok )
2823  {
2824  if ( rot < -180.0 && rot >= -360 )
2825  {
2826  rot += 360;
2827  }
2828  if ( rot > 180.0 && rot <= 360 )
2829  {
2830  rot -= 360;
2831  }
2832  if ( rot >= -180 && rot <= 180 )
2833  {
2834  dataDefinedValues.insert( p, QVariant( rot ) );
2835  return true;
2836  }
2837  }
2838  return false;
2839  }
2840  case DDTransparency:
2841  {
2842  bool ok;
2843  int size = exprVal.toInt( &ok );
2844  QgsDebugMsgLevel( dbgStr.arg( size ), 4 );
2845  if ( ok && size >= 0 && size <= 100 )
2846  {
2847  dataDefinedValues.insert( p, QVariant( size ) );
2848  return true;
2849  }
2850  return false;
2851  }
2852  case DDString:
2853  {
2854  QString str = exprVal.toString(); // don't trim whitespace
2855  QgsDebugMsgLevel( dbgStr.arg( str ), 4 );
2856 
2857  dataDefinedValues.insert( p, QVariant( str ) ); // let it stay empty if it is
2858  return true;
2859  }
2860  case DDUnits:
2861  {
2862  QString unitstr = exprVal.toString().trimmed();
2863  QgsDebugMsgLevel( dbgStr.arg( unitstr ), 4 );
2864 
2865  if ( !unitstr.isEmpty() )
2866  {
2867  dataDefinedValues.insert( p, QVariant(( int )_decodeUnits( unitstr ) ) );
2868  return true;
2869  }
2870  return false;
2871  }
2872  case DDColor:
2873  {
2874  QString colorstr = exprVal.toString().trimmed();
2875  QgsDebugMsgLevel( dbgStr.arg( colorstr ), 4 );
2876  QColor color = QgsSymbolLayerV2Utils::decodeColor( colorstr );
2877 
2878  if ( color.isValid() )
2879  {
2880  dataDefinedValues.insert( p, QVariant( color ) );
2881  return true;
2882  }
2883  return false;
2884  }
2885  case DDJoinStyle:
2886  {
2887  QString joinstr = exprVal.toString().trimmed();
2888  QgsDebugMsgLevel( dbgStr.arg( joinstr ), 4 );
2889 
2890  if ( !joinstr.isEmpty() )
2891  {
2892  dataDefinedValues.insert( p, QVariant(( int )_decodePenJoinStyle( joinstr ) ) );
2893  return true;
2894  }
2895  return false;
2896  }
2897  case DDBlendMode:
2898  {
2899  QString blendstr = exprVal.toString().trimmed();
2900  QgsDebugMsgLevel( dbgStr.arg( blendstr ), 4 );
2901 
2902  if ( !blendstr.isEmpty() )
2903  {
2904  dataDefinedValues.insert( p, QVariant(( int )QgsSymbolLayerV2Utils::decodeBlendMode( blendstr ) ) );
2905  return true;
2906  }
2907  return false;
2908  }
2909  case DDPointF:
2910  {
2911  QString ptstr = exprVal.toString().trimmed();
2912  QgsDebugMsgLevel( dbgStr.arg( ptstr ), 4 );
2913 
2914  if ( !ptstr.isEmpty() )
2915  {
2916  dataDefinedValues.insert( p, QVariant( QgsSymbolLayerV2Utils::decodePoint( ptstr ) ) );
2917  return true;
2918  }
2919  return false;
2920  }
2921  }
2922  }
2923  return false;
2924 }
2925 
2926 void QgsPalLayerSettings::parseTextStyle( QFont& labelFont,
2928  QgsRenderContext &context )
2929 {
2930  // NOTE: labelFont already has pixelSize set, so pointSize or pointSizeF might return -1
2931 
2932  QVariant exprVal; // value() is repeatedly nulled on data defined evaluation and replaced when successful
2933 
2934  // Two ways to generate new data defined font:
2935  // 1) Family + [bold] + [italic] (named style is ignored and font is built off of base family)
2936  // 2) Family + named style (bold or italic is ignored)
2937 
2938  // data defined font family?
2939  QString ddFontFamily( "" );
2940  if ( dataDefinedEvaluate( QgsPalLayerSettings::Family, exprVal, &context.expressionContext(), labelFont.family() ) )
2941  {
2942  QString family = exprVal.toString().trimmed();
2943  QgsDebugMsgLevel( QString( "exprVal Font family:%1" ).arg( family ), 4 );
2944 
2945  if ( labelFont.family() != family )
2946  {
2947  // testing for ddFontFamily in QFontDatabase.families() may be slow to do for every feature
2948  // (i.e. don't use QgsFontUtils::fontFamilyMatchOnSystem( family ) here)
2949  if ( QgsFontUtils::fontFamilyOnSystem( family ) )
2950  {
2951  ddFontFamily = family;
2952  }
2953  }
2954  }
2955 
2956  // data defined named font style?
2957  QString ddFontStyle( "" );
2959  {
2960  QString fontstyle = exprVal.toString().trimmed();
2961  QgsDebugMsgLevel( QString( "exprVal Font style:%1" ).arg( fontstyle ), 4 );
2962  ddFontStyle = fontstyle;
2963  }
2964 
2965  // data defined bold font style?
2966  bool ddBold = false;
2967  if ( dataDefinedEvaluate( QgsPalLayerSettings::Bold, exprVal, &context.expressionContext(), labelFont.bold() ) )
2968  {
2969  bool bold = exprVal.toBool();
2970  QgsDebugMsgLevel( QString( "exprVal Font bold:%1" ).arg( bold ? "true" : "false" ), 4 );
2971  ddBold = bold;
2972  }
2973 
2974  // data defined italic font style?
2975  bool ddItalic = false;
2976  if ( dataDefinedEvaluate( QgsPalLayerSettings::Italic, exprVal, &context.expressionContext(), labelFont.italic() ) )
2977  {
2978  bool italic = exprVal.toBool();
2979  QgsDebugMsgLevel( QString( "exprVal Font italic:%1" ).arg( italic ? "true" : "false" ), 4 );
2980  ddItalic = italic;
2981  }
2982 
2983  // TODO: update when pref for how to resolve missing family (use matching algorithm or just default font) is implemented
2984  // (currently defaults to what has been read in from layer settings)
2985  QFont newFont;
2986  QFont appFont = QApplication::font();
2987  bool newFontBuilt = false;
2988  if ( ddBold || ddItalic )
2989  {
2990  // new font needs built, since existing style needs removed
2991  newFont = QFont( !ddFontFamily.isEmpty() ? ddFontFamily : labelFont.family() );
2992  newFontBuilt = true;
2993  newFont.setBold( ddBold );
2994  newFont.setItalic( ddItalic );
2995  }
2996  else if ( !ddFontStyle.isEmpty()
2997  && ddFontStyle.compare( "Ignore", Qt::CaseInsensitive ) != 0 )
2998  {
2999  if ( !ddFontFamily.isEmpty() )
3000  {
3001  // both family and style are different, build font from database
3002  QFont styledfont = mFontDB.font( ddFontFamily, ddFontStyle, appFont.pointSize() );
3003  if ( appFont != styledfont )
3004  {
3005  newFont = styledfont;
3006  newFontBuilt = true;
3007  }
3008  }
3009 
3010  // update the font face style
3011  QgsFontUtils::updateFontViaStyle( newFontBuilt ? newFont : labelFont, ddFontStyle );
3012  }
3013  else if ( !ddFontFamily.isEmpty() )
3014  {
3015  if ( ddFontStyle.compare( "Ignore", Qt::CaseInsensitive ) != 0 )
3016  {
3017  // just family is different, build font from database
3018  QFont styledfont = mFontDB.font( ddFontFamily, textNamedStyle, appFont.pointSize() );
3019  if ( appFont != styledfont )
3020  {
3021  newFont = styledfont;
3022  newFontBuilt = true;
3023  }
3024  }
3025  else
3026  {
3027  newFont = QFont( ddFontFamily );
3028  newFontBuilt = true;
3029  }
3030  }
3031 
3032  if ( newFontBuilt )
3033  {
3034  // copy over existing font settings
3035  //newFont = newFont.resolve( labelFont ); // should work, but let's be sure what's being copied
3036  newFont.setPixelSize( labelFont.pixelSize() );
3037  newFont.setCapitalization( labelFont.capitalization() );
3038  newFont.setUnderline( labelFont.underline() );
3039  newFont.setStrikeOut( labelFont.strikeOut() );
3040  newFont.setWordSpacing( labelFont.wordSpacing() );
3041  newFont.setLetterSpacing( QFont::AbsoluteSpacing, labelFont.letterSpacing() );
3042 
3043  labelFont = newFont;
3044  }
3045 
3046  // data defined word spacing?
3047  double wordspace = labelFont.wordSpacing();
3048  if ( dataDefinedEvaluate( QgsPalLayerSettings::FontWordSpacing, exprVal, &context.expressionContext(), wordspace ) )
3049  {
3050  bool ok;
3051  double wspacing = exprVal.toDouble( &ok );
3052  QgsDebugMsgLevel( QString( "exprVal FontWordSpacing:%1" ).arg( wspacing ), 4 );
3053  if ( ok )
3054  {
3055  wordspace = wspacing;
3056  }
3057  }
3058  labelFont.setWordSpacing( sizeToPixel( wordspace, context, fontunits, false, fontSizeMapUnitScale ) );
3059 
3060  // data defined letter spacing?
3061  double letterspace = labelFont.letterSpacing();
3062  if ( dataDefinedEvaluate( QgsPalLayerSettings::FontLetterSpacing, exprVal, &context.expressionContext(), letterspace ) )
3063  {
3064  bool ok;
3065  double lspacing = exprVal.toDouble( &ok );
3066  QgsDebugMsgLevel( QString( "exprVal FontLetterSpacing:%1" ).arg( lspacing ), 4 );
3067  if ( ok )
3068  {
3069  letterspace = lspacing;
3070  }
3071  }
3072  labelFont.setLetterSpacing( QFont::AbsoluteSpacing, sizeToPixel( letterspace, context, fontunits, false, fontSizeMapUnitScale ) );
3073 
3074  // data defined font capitalization?
3075  QFont::Capitalization fontcaps = labelFont.capitalization();
3077  {
3078  QString fcase = exprVal.toString().trimmed();
3079  QgsDebugMsgLevel( QString( "exprVal FontCase:%1" ).arg( fcase ), 4 );
3080 
3081  if ( !fcase.isEmpty() )
3082  {
3083  if ( fcase.compare( "NoChange", Qt::CaseInsensitive ) == 0 )
3084  {
3085  fontcaps = QFont::MixedCase;
3086  }
3087  else if ( fcase.compare( "Upper", Qt::CaseInsensitive ) == 0 )
3088  {
3089  fontcaps = QFont::AllUppercase;
3090  }
3091  else if ( fcase.compare( "Lower", Qt::CaseInsensitive ) == 0 )
3092  {
3093  fontcaps = QFont::AllLowercase;
3094  }
3095  else if ( fcase.compare( "Capitalize", Qt::CaseInsensitive ) == 0 )
3096  {
3097  fontcaps = QFont::Capitalize;
3098  }
3099 
3100  if ( fontcaps != labelFont.capitalization() )
3101  {
3102  labelFont.setCapitalization( fontcaps );
3103  }
3104  }
3105  }
3106 
3107  // data defined strikeout font style?
3108  if ( dataDefinedEvaluate( QgsPalLayerSettings::Strikeout, exprVal, &context.expressionContext(), labelFont.strikeOut() ) )
3109  {
3110  bool strikeout = exprVal.toBool();
3111  QgsDebugMsgLevel( QString( "exprVal Font strikeout:%1" ).arg( strikeout ? "true" : "false" ), 4 );
3112  labelFont.setStrikeOut( strikeout );
3113  }
3114 
3115  // data defined underline font style?
3116  if ( dataDefinedEvaluate( QgsPalLayerSettings::Underline, exprVal, &context.expressionContext(), labelFont.underline() ) )
3117  {
3118  bool underline = exprVal.toBool();
3119  QgsDebugMsgLevel( QString( "exprVal Font underline:%1" ).arg( underline ? "true" : "false" ), 4 );
3120  labelFont.setUnderline( underline );
3121  }
3122 
3123  // pass the rest on to QgsPalLabeling::drawLabeling
3124 
3125  // data defined font color?
3126  dataDefinedValEval( DDColor, QgsPalLayerSettings::Color, exprVal, context.expressionContext(), QgsSymbolLayerV2Utils::encodeColor( textColor ) );
3127 
3128  // data defined font transparency?
3129  dataDefinedValEval( DDTransparency, QgsPalLayerSettings::FontTransp, exprVal, context.expressionContext(), textTransp );
3130 
3131  // data defined font blend mode?
3132  dataDefinedValEval( DDBlendMode, QgsPalLayerSettings::FontBlendMode, exprVal, context.expressionContext() );
3133 
3134 }
3135 
3136 void QgsPalLayerSettings::parseTextBuffer( QgsRenderContext &context )
3137 {
3138  QVariant exprVal; // value() is repeatedly nulled on data defined evaluation and replaced when successful
3139 
3140  // data defined draw buffer?
3141  bool drawBuffer = bufferDraw;
3142  if ( dataDefinedValEval( DDBool, QgsPalLayerSettings::BufferDraw, exprVal, context.expressionContext(), bufferDraw ) )
3143  {
3144  drawBuffer = exprVal.toBool();
3145  }
3146 
3147  if ( !drawBuffer )
3148  {
3149  return;
3150  }
3151 
3152  // data defined buffer size?
3153  double bufrSize = bufferSize;
3154  if ( dataDefinedValEval( DDDoublePos, QgsPalLayerSettings::BufferSize, exprVal, context.expressionContext(), bufferSize ) )
3155  {
3156  bufrSize = exprVal.toDouble();
3157  }
3158 
3159  // data defined buffer transparency?
3160  int bufTransp = bufferTransp;
3161  if ( dataDefinedValEval( DDTransparency, QgsPalLayerSettings::BufferTransp, exprVal, context.expressionContext(), bufferTransp ) )
3162  {
3163  bufTransp = exprVal.toInt();
3164  }
3165 
3166  drawBuffer = ( drawBuffer && bufrSize > 0.0 && bufTransp < 100 );
3167 
3168  if ( !drawBuffer )
3169  {
3170  dataDefinedValues.insert( QgsPalLayerSettings::BufferDraw, QVariant( false ) ); // trigger value
3171  dataDefinedValues.remove( QgsPalLayerSettings::BufferSize );
3172  dataDefinedValues.remove( QgsPalLayerSettings::BufferTransp );
3173  return; // don't bother evaluating values that won't be used
3174  }
3175 
3176  // data defined buffer units?
3177  dataDefinedValEval( DDUnits, QgsPalLayerSettings::BufferUnit, exprVal, context.expressionContext() );
3178 
3179  // data defined buffer color?
3180  dataDefinedValEval( DDColor, QgsPalLayerSettings::BufferColor, exprVal, context.expressionContext(), QgsSymbolLayerV2Utils::encodeColor( bufferColor ) );
3181 
3182  // data defined buffer pen join style?
3184 
3185  // data defined buffer blend mode?
3186  dataDefinedValEval( DDBlendMode, QgsPalLayerSettings::BufferBlendMode, exprVal, context.expressionContext() );
3187 }
3188 
3189 void QgsPalLayerSettings::parseTextFormatting( QgsRenderContext &context )
3190 {
3191  QVariant exprVal; // value() is repeatedly nulled on data defined evaluation and replaced when successful
3192 
3193  // data defined multiline wrap character?
3194  QString wrapchr = wrapChar;
3195  if ( dataDefinedValEval( DDString, QgsPalLayerSettings::MultiLineWrapChar, exprVal, context.expressionContext(), wrapChar ) )
3196  {
3197  wrapchr = exprVal.toString();
3198  }
3199 
3200  // data defined multiline height?
3201  dataDefinedValEval( DDDouble, QgsPalLayerSettings::MultiLineHeight, exprVal, context.expressionContext() );
3202 
3203  // data defined multiline text align?
3205  {
3206  QString str = exprVal.toString().trimmed();
3207  QgsDebugMsgLevel( QString( "exprVal MultiLineAlignment:%1" ).arg( str ), 4 );
3208 
3209  if ( !str.isEmpty() )
3210  {
3211  // "Left"
3213 
3214  if ( str.compare( "Center", Qt::CaseInsensitive ) == 0 )
3215  {
3217  }
3218  else if ( str.compare( "Right", Qt::CaseInsensitive ) == 0 )
3219  {
3220  aligntype = QgsPalLayerSettings::MultiRight;
3221  }
3222  else if ( str.compare( "Follow", Qt::CaseInsensitive ) == 0 )
3223  {
3225  }
3226  dataDefinedValues.insert( QgsPalLayerSettings::MultiLineAlignment, QVariant(( int )aligntype ) );
3227  }
3228  }
3229 
3230  // data defined direction symbol?
3231  bool drawDirSymb = addDirectionSymbol;
3232  if ( dataDefinedValEval( DDBool, QgsPalLayerSettings::DirSymbDraw, exprVal, context.expressionContext(), addDirectionSymbol ) )
3233  {
3234  drawDirSymb = exprVal.toBool();
3235  }
3236 
3237  if ( drawDirSymb )
3238  {
3239  // data defined direction left symbol?
3240  dataDefinedValEval( DDString, QgsPalLayerSettings::DirSymbLeft, exprVal, context.expressionContext(), leftDirectionSymbol );
3241 
3242  // data defined direction right symbol?
3243  dataDefinedValEval( DDString, QgsPalLayerSettings::DirSymbRight, exprVal, context.expressionContext(), rightDirectionSymbol );
3244 
3245  // data defined direction symbol placement?
3247  {
3248  QString str = exprVal.toString().trimmed();
3249  QgsDebugMsgLevel( QString( "exprVal DirSymbPlacement:%1" ).arg( str ), 4 );
3250 
3251  if ( !str.isEmpty() )
3252  {
3253  // "LeftRight"
3255 
3256  if ( str.compare( "Above", Qt::CaseInsensitive ) == 0 )
3257  {
3259  }
3260  else if ( str.compare( "Below", Qt::CaseInsensitive ) == 0 )
3261  {
3263  }
3264  dataDefinedValues.insert( QgsPalLayerSettings::DirSymbPlacement, QVariant(( int )placetype ) );
3265  }
3266  }
3267 
3268  // data defined direction symbol reversed?
3269  dataDefinedValEval( DDBool, QgsPalLayerSettings::DirSymbReverse, exprVal, context.expressionContext(), reverseDirectionSymbol );
3270  }
3271 
3272  // formatting for numbers is inline with generation of base label text and not passed to label painting
3273 }
3274 
3275 void QgsPalLayerSettings::parseShapeBackground( QgsRenderContext &context )
3276 {
3277  QVariant exprVal; // value() is repeatedly nulled on data defined evaluation and replaced when successful
3278 
3279  // data defined draw shape?
3280  bool drawShape = shapeDraw;
3281  if ( dataDefinedValEval( DDBool, QgsPalLayerSettings::ShapeDraw, exprVal, context.expressionContext(), shapeDraw ) )
3282  {
3283  drawShape = exprVal.toBool();
3284  }
3285 
3286  if ( !drawShape )
3287  {
3288  return;
3289  }
3290 
3291  // data defined shape transparency?
3292  int shapeTransp = shapeTransparency;
3293  if ( dataDefinedValEval( DDTransparency, QgsPalLayerSettings::ShapeTransparency, exprVal, context.expressionContext(), shapeTransparency ) )
3294  {
3295  shapeTransp = exprVal.toInt();
3296  }
3297 
3298  drawShape = ( drawShape && shapeTransp < 100 ); // size is not taken into account (could be)
3299 
3300  if ( !drawShape )
3301  {
3302  dataDefinedValues.insert( QgsPalLayerSettings::ShapeDraw, QVariant( false ) ); // trigger value
3303  dataDefinedValues.remove( QgsPalLayerSettings::ShapeTransparency );
3304  return; // don't bother evaluating values that won't be used
3305  }
3306 
3307  // data defined shape kind?
3310  {
3311  QString skind = exprVal.toString().trimmed();
3312  QgsDebugMsgLevel( QString( "exprVal ShapeKind:%1" ).arg( skind ), 4 );
3313 
3314  if ( !skind.isEmpty() )
3315  {
3316  // "Rectangle"
3318 
3319  if ( skind.compare( "Square", Qt::CaseInsensitive ) == 0 )
3320  {
3322  }
3323  else if ( skind.compare( "Ellipse", Qt::CaseInsensitive ) == 0 )
3324  {
3326  }
3327  else if ( skind.compare( "Circle", Qt::CaseInsensitive ) == 0 )
3328  {
3330  }
3331  else if ( skind.compare( "SVG", Qt::CaseInsensitive ) == 0 )
3332  {
3334  }
3335  shapeKind = shpkind;
3336  dataDefinedValues.insert( QgsPalLayerSettings::ShapeKind, QVariant(( int )shpkind ) );
3337  }
3338  }
3339 
3340  // data defined shape SVG path?
3341  QString svgPath = shapeSVGFile;
3343  {
3344  QString svgfile = exprVal.toString().trimmed();
3345  QgsDebugMsgLevel( QString( "exprVal ShapeSVGFile:%1" ).arg( svgfile ), 4 );
3346 
3347  // '' empty paths are allowed
3348  svgPath = svgfile;
3349  dataDefinedValues.insert( QgsPalLayerSettings::ShapeSVGFile, QVariant( svgfile ) );
3350  }
3351 
3352  // data defined shape size type?
3355  {
3356  QString stype = exprVal.toString().trimmed();
3357  QgsDebugMsgLevel( QString( "exprVal ShapeSizeType:%1" ).arg( stype ), 4 );
3358 
3359  if ( !stype.isEmpty() )
3360  {
3361  // "Buffer"
3363 
3364  if ( stype.compare( "Fixed", Qt::CaseInsensitive ) == 0 )
3365  {
3367  }
3368  shpSizeType = sizType;
3369  dataDefinedValues.insert( QgsPalLayerSettings::ShapeSizeType, QVariant(( int )sizType ) );
3370  }
3371  }
3372 
3373  // data defined shape size X? (SVGs only use X for sizing)
3374  double ddShpSizeX = shapeSize.x();
3375  if ( dataDefinedValEval( DDDouble, QgsPalLayerSettings::ShapeSizeX, exprVal, context.expressionContext(), ddShpSizeX ) )
3376  {
3377  ddShpSizeX = exprVal.toDouble();
3378  }
3379 
3380  // data defined shape size Y?
3381  double ddShpSizeY = shapeSize.y();
3382  if ( dataDefinedValEval( DDDouble, QgsPalLayerSettings::ShapeSizeY, exprVal, context.expressionContext(), ddShpSizeY ) )
3383  {
3384  ddShpSizeY = exprVal.toDouble();
3385  }
3386 
3387  // don't continue under certain circumstances (e.g. size is fixed)
3388  bool skip = false;
3389  if ( shapeKind == QgsPalLayerSettings::ShapeSVG
3390  && ( svgPath.isEmpty()
3391  || ( !svgPath.isEmpty()
3392  && shpSizeType == QgsPalLayerSettings::SizeFixed
3393  && ddShpSizeX == 0.0 ) ) )
3394  {
3395  skip = true;
3396  }
3397  if ( shapeKind != QgsPalLayerSettings::ShapeSVG
3398  && shpSizeType == QgsPalLayerSettings::SizeFixed
3399  && ( ddShpSizeX == 0.0 || ddShpSizeY == 0.0 ) )
3400  {
3401  skip = true;
3402  }
3403 
3404  if ( skip )
3405  {
3406  dataDefinedValues.insert( QgsPalLayerSettings::ShapeDraw, QVariant( false ) ); // trigger value
3407  dataDefinedValues.remove( QgsPalLayerSettings::ShapeTransparency );
3408  dataDefinedValues.remove( QgsPalLayerSettings::ShapeKind );
3409  dataDefinedValues.remove( QgsPalLayerSettings::ShapeSVGFile );
3410  dataDefinedValues.remove( QgsPalLayerSettings::ShapeSizeX );
3411  dataDefinedValues.remove( QgsPalLayerSettings::ShapeSizeY );
3412  return; // don't bother evaluating values that won't be used
3413  }
3414 
3415  // data defined shape size units?
3416  dataDefinedValEval( DDUnits, QgsPalLayerSettings::ShapeSizeUnits, exprVal, context.expressionContext() );
3417 
3418  // data defined shape rotation type?
3420  {
3421  QString rotstr = exprVal.toString().trimmed();
3422  QgsDebugMsgLevel( QString( "exprVal ShapeRotationType:%1" ).arg( rotstr ), 4 );
3423 
3424  if ( !rotstr.isEmpty() )
3425  {
3426  // "Sync"
3428 
3429  if ( rotstr.compare( "Offset", Qt::CaseInsensitive ) == 0 )
3430  {
3432  }
3433  else if ( rotstr.compare( "Fixed", Qt::CaseInsensitive ) == 0 )
3434  {
3436  }
3437  dataDefinedValues.insert( QgsPalLayerSettings::ShapeRotationType, QVariant(( int )rottype ) );
3438  }
3439  }
3440 
3441  // data defined shape rotation?
3442  dataDefinedValEval( DDRotation180, QgsPalLayerSettings::ShapeRotation, exprVal, context.expressionContext(), shapeRotation );
3443 
3444  // data defined shape offset?
3445  dataDefinedValEval( DDPointF, QgsPalLayerSettings::ShapeOffset, exprVal, context.expressionContext(), QgsSymbolLayerV2Utils::encodePoint( shapeOffset ) );
3446 
3447  // data defined shape offset units?
3448  dataDefinedValEval( DDUnits, QgsPalLayerSettings::ShapeOffsetUnits, exprVal, context.expressionContext() );
3449 
3450  // data defined shape radii?
3451  dataDefinedValEval( DDPointF, QgsPalLayerSettings::ShapeRadii, exprVal, context.expressionContext(), QgsSymbolLayerV2Utils::encodePoint( shapeRadii ) );
3452 
3453  // data defined shape radii units?
3454  dataDefinedValEval( DDUnits, QgsPalLayerSettings::ShapeRadiiUnits, exprVal, context.expressionContext() );
3455 
3456  // data defined shape blend mode?
3457  dataDefinedValEval( DDBlendMode, QgsPalLayerSettings::ShapeBlendMode, exprVal, context.expressionContext() );
3458 
3459  // data defined shape fill color?
3460  dataDefinedValEval( DDColor, QgsPalLayerSettings::ShapeFillColor, exprVal, context.expressionContext(), QgsSymbolLayerV2Utils::encodeColor( shapeFillColor ) );
3461 
3462  // data defined shape border color?
3464 
3465  // data defined shape border width?
3466  dataDefinedValEval( DDDoublePos, QgsPalLayerSettings::ShapeBorderWidth, exprVal, context.expressionContext(), shapeBorderWidth );
3467 
3468  // data defined shape border width units?
3469  dataDefinedValEval( DDUnits, QgsPalLayerSettings::ShapeBorderWidthUnits, exprVal, context.expressionContext() );
3470 
3471  // data defined shape join style?
3473 
3474 }
3475 
3476 void QgsPalLayerSettings::parseDropShadow( QgsRenderContext &context )
3477 {
3478  QVariant exprVal; // value() is repeatedly nulled on data defined evaluation and replaced when successful
3479 
3480  // data defined draw shadow?
3481  bool drawShadow = shadowDraw;
3482  if ( dataDefinedValEval( DDBool, QgsPalLayerSettings::ShadowDraw, exprVal, context.expressionContext(), shadowDraw ) )
3483  {
3484  drawShadow = exprVal.toBool();
3485  }
3486 
3487  if ( !drawShadow )
3488  {
3489  return;
3490  }
3491 
3492  // data defined shadow transparency?
3493  int shadowTransp = shadowTransparency;
3494  if ( dataDefinedValEval( DDTransparency, QgsPalLayerSettings::ShadowTransparency, exprVal, context.expressionContext(), shadowTransparency ) )
3495  {
3496  shadowTransp = exprVal.toInt();
3497  }
3498 
3499  // data defined shadow offset distance?
3500  double shadowOffDist = shadowOffsetDist;
3501  if ( dataDefinedValEval( DDDoublePos, QgsPalLayerSettings::ShadowOffsetDist, exprVal, context.expressionContext(), shadowOffsetDist ) )
3502  {
3503  shadowOffDist = exprVal.toDouble();
3504  }
3505 
3506  // data defined shadow offset distance?
3507  double shadowRad = shadowRadius;
3508  if ( dataDefinedValEval( DDDoublePos, QgsPalLayerSettings::ShadowRadius, exprVal, context.expressionContext(), shadowRadius ) )
3509  {
3510  shadowRad = exprVal.toDouble();
3511  }
3512 
3513  drawShadow = ( drawShadow && shadowTransp < 100 && !( shadowOffDist == 0.0 && shadowRad == 0.0 ) );
3514 
3515  if ( !drawShadow )
3516  {
3517  dataDefinedValues.insert( QgsPalLayerSettings::ShadowDraw, QVariant( false ) ); // trigger value
3518  dataDefinedValues.remove( QgsPalLayerSettings::ShadowTransparency );
3519  dataDefinedValues.remove( QgsPalLayerSettings::ShadowOffsetDist );
3520  dataDefinedValues.remove( QgsPalLayerSettings::ShadowRadius );
3521  return; // don't bother evaluating values that won't be used
3522  }
3523 
3524  // data defined shadow under type?
3526  {
3527  QString str = exprVal.toString().trimmed();
3528  QgsDebugMsgLevel( QString( "exprVal ShadowUnder:%1" ).arg( str ), 4 );
3529 
3530  if ( !str.isEmpty() )
3531  {
3532  // "Lowest"
3534 
3535  if ( str.compare( "Text", Qt::CaseInsensitive ) == 0 )
3536  {
3538  }
3539  else if ( str.compare( "Buffer", Qt::CaseInsensitive ) == 0 )
3540  {
3542  }
3543  else if ( str.compare( "Background", Qt::CaseInsensitive ) == 0 )
3544  {
3546  }
3547  dataDefinedValues.insert( QgsPalLayerSettings::ShadowUnder, QVariant(( int )shdwtype ) );
3548  }
3549  }
3550 
3551  // data defined shadow offset angle?
3552  dataDefinedValEval( DDRotation180, QgsPalLayerSettings::ShadowOffsetAngle, exprVal, context.expressionContext(), shadowOffsetAngle );
3553 
3554  // data defined shadow offset units?
3555  dataDefinedValEval( DDUnits, QgsPalLayerSettings::ShadowOffsetUnits, exprVal, context.expressionContext() );
3556 
3557  // data defined shadow radius?
3558  dataDefinedValEval( DDDouble, QgsPalLayerSettings::ShadowRadius, exprVal, context.expressionContext(), shadowRadius );
3559 
3560  // data defined shadow radius units?
3561  dataDefinedValEval( DDUnits, QgsPalLayerSettings::ShadowRadiusUnits, exprVal, context.expressionContext() );
3562 
3563  // data defined shadow scale? ( gui bounds to 0-2000, no upper bound here )
3564  dataDefinedValEval( DDIntPos, QgsPalLayerSettings::ShadowScale, exprVal, context.expressionContext(), shadowScale );
3565 
3566  // data defined shadow color?
3567  dataDefinedValEval( DDColor, QgsPalLayerSettings::ShadowColor, exprVal, context.expressionContext(), QgsSymbolLayerV2Utils::encodeColor( shadowColor ) );
3568 
3569  // data defined shadow blend mode?
3570  dataDefinedValEval( DDBlendMode, QgsPalLayerSettings::ShadowBlendMode, exprVal, context.expressionContext() );
3571 }
3572 
3573 int QgsPalLayerSettings::sizeToPixel( double size, const QgsRenderContext& c, SizeUnit unit, bool rasterfactor, const QgsMapUnitScale& mapUnitScale ) const
3574 {
3575  return ( int )( scaleToPixelContext( size, c, unit, rasterfactor, mapUnitScale ) + 0.5 );
3576 }
3577 
3578 double QgsPalLayerSettings::scaleToPixelContext( double size, const QgsRenderContext& c, SizeUnit unit, bool rasterfactor, const QgsMapUnitScale& mapUnitScale ) const
3579 {
3580  // if render context is that of device (i.e. not a scaled map), just return size
3581  double mapUnitsPerPixel = mapUnitScale.computeMapUnitsPerPixel( c );
3582 
3583  if ( unit == MapUnits && mapUnitsPerPixel > 0.0 )
3584  {
3585  size = size / mapUnitsPerPixel * ( rasterfactor ? c.rasterScaleFactor() : 1 );
3586  }
3587  else // e.g. in points or mm
3588  {
3589  double ptsTomm = ( unit == Points ? 0.352778 : 1 );
3590  size *= ptsTomm * c.scaleFactor() * ( rasterfactor ? c.rasterScaleFactor() : 1 );
3591  }
3592  return size;
3593 }
3594 
3595 // -------------
3596 
3598  : mEngine( new QgsLabelingEngineV2() )
3599 {
3600 }
3601 
3603 {
3604  delete mEngine;
3605  mEngine = 0;
3606 }
3607 
3609 {
3610  return staticWillUseLayer( layer );
3611 }
3612 
3614 {
3615  QgsVectorLayer* layer = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( layerID ) );
3616  if ( !layer )
3617  return false;
3618  return staticWillUseLayer( layer );
3619 }
3620 
3621 
3623 {
3624  // don't do QgsPalLayerSettings::readFromLayer( layer ) if not needed
3625  bool enabled = false;
3626  if ( layer->customProperty( "labeling" ).toString() == "pal" )
3627  enabled = layer->labelsEnabled() || layer->diagramsEnabled();
3628  else if ( layer->labeling()->type() == "rule-based" )
3629  return true;
3630 
3631  return enabled;
3632 }
3633 
3634 
3636 {
3637 }
3638 
3640 {
3641  Q_UNUSED( layerID );
3642 }
3643 
3644 
3646 {
3647  if ( !willUseLayer( layer ) )
3648  {
3649  return 0;
3650  }
3651 
3652  if ( !layer->labeling() )
3653  return 0;
3654 
3655  QgsVectorLayerLabelProvider* lp = layer->labeling()->provider( layer );
3656  if ( !lp )
3657  return 0;
3658 
3659  //QgsVectorLayerLabelProvider* lp = new QgsVectorLayerLabelProvider( layer, false );
3660  // need to be added before calling prepare() - uses map settings from engine
3661  mEngine->addProvider( lp );
3662  mLabelProviders[layer->id()] = lp; // fast lookup table by layer ID
3663 
3664  if ( !lp->prepare( ctx, attrNames ) )
3665  {
3666  mEngine->removeProvider( lp );
3667  return 0;
3668  }
3669 
3670  return 1; // init successful
3671 }
3672 
3674 {
3676  // need to be added before calling prepare() - uses map settings from engine
3677  mEngine->addProvider( dp );
3678  mDiagramProviders[layer->id()] = dp; // fast lookup table by layer ID
3679 
3680  if ( !dp->prepare( ctx, attrNames ) )
3681  {
3682  mEngine->removeProvider( dp );
3683  return 0;
3684  }
3685 
3686  return 1;
3687 }
3688 
3690 {
3691  QgsDebugMsg( "Called addDiagramLayer()... need to use prepareDiagramLayer() instead!" );
3692  Q_UNUSED( layer );
3693  Q_UNUSED( s );
3694  return 0;
3695 }
3696 
3697 void QgsPalLabeling::registerFeature( const QString& layerID, QgsFeature& f, QgsRenderContext &context, const QString& dxfLayer )
3698 {
3699  Q_UNUSED( dxfLayer ); // now handled by QgsDxfLabelProvider
3700  if ( QgsVectorLayerLabelProvider* provider = mLabelProviders.value( layerID, 0 ) )
3701  provider->registerFeature( f, context );
3702 }
3703 
3705 {
3706  if ( !geometry )
3707  {
3708  return false;
3709  }
3710 
3711  //requires reprojection
3712  if ( ct )
3713  return true;
3714 
3715  //requires fixing
3716  if ( geometry->type() == QGis::Polygon && !geometry->isGeosValid() )
3717  return true;
3718 
3719  //requires rotation
3720  const QgsMapToPixel& m2p = context.mapToPixel();
3721  if ( !qgsDoubleNear( m2p.mapRotation(), 0 ) )
3722  return true;
3723 
3724  //requires clip
3725  if ( clipGeometry && !clipGeometry->contains( geometry ) )
3726  return true;
3727 
3728  return false;
3729 }
3730 
3731 QStringList QgsPalLabeling::splitToLines( const QString &text, const QString &wrapCharacter )
3732 {
3733  QStringList multiLineSplit;
3734  if ( !wrapCharacter.isEmpty() && wrapCharacter != QLatin1String( "\n" ) )
3735  {
3736  //wrap on both the wrapchr and new line characters
3737  Q_FOREACH ( const QString& line, text.split( wrapCharacter ) )
3738  {
3739  multiLineSplit.append( line.split( QString( "\n" ) ) );
3740  }
3741  }
3742  else
3743  {
3744  multiLineSplit = text.split( "\n" );
3745  }
3746 
3747  return multiLineSplit;
3748 }
3749 
3751 {
3752  QStringList graphemes;
3753  QTextBoundaryFinder boundaryFinder( QTextBoundaryFinder::Grapheme, text );
3754  int currentBoundary = -1;
3755  int previousBoundary = 0;
3756  while (( currentBoundary = boundaryFinder.toNextBoundary() ) > 0 )
3757  {
3758  graphemes << text.mid( previousBoundary, currentBoundary - previousBoundary );
3759  previousBoundary = currentBoundary;
3760  }
3761  return graphemes;
3762 }
3763 
3765 {
3766  if ( !geometry )
3767  {
3768  return 0;
3769  }
3770 
3771  //don't modify the feature's geometry so that geometry based expressions keep working
3772  QgsGeometry* geom = new QgsGeometry( *geometry );
3773  QScopedPointer<QgsGeometry> clonedGeometry( geom );
3774 
3775  //reproject the geometry if necessary
3776  if ( ct )
3777  {
3778  try
3779  {
3780  geom->transform( *ct );
3781  }
3782  catch ( QgsCsException &cse )
3783  {
3784  Q_UNUSED( cse );
3785  QgsDebugMsgLevel( QString( "Ignoring feature due to transformation exception" ), 4 );
3786  return 0;
3787  }
3788  }
3789 
3790  // Rotate the geometry if needed, before clipping
3791  const QgsMapToPixel& m2p = context.mapToPixel();
3792  if ( !qgsDoubleNear( m2p.mapRotation(), 0 ) )
3793  {
3794  QgsPoint center = context.extent().center();
3795 
3796  if ( ct )
3797  {
3798  try
3799  {
3800  center = ct->transform( center );
3801  }
3802  catch ( QgsCsException &cse )
3803  {
3804  Q_UNUSED( cse );
3805  QgsDebugMsgLevel( QString( "Ignoring feature due to transformation exception" ), 4 );
3806  return 0;
3807  }
3808  }
3809 
3810  if ( geom->rotate( m2p.mapRotation(), center ) )
3811  {
3812  QgsDebugMsg( QString( "Error rotating geometry" ).arg( geom->exportToWkt() ) );
3813  return 0;
3814  }
3815  }
3816 
3817  if ( !geom->asGeos() )
3818  return 0; // there is something really wrong with the geometry
3819 
3820  // fix invalid polygons
3821  if ( geom->type() == QGis::Polygon && !geom->isGeosValid() )
3822  {
3823  QgsGeometry* bufferGeom = geom->buffer( 0, 0 );
3824  if ( !bufferGeom )
3825  {
3826  return 0;
3827  }
3828  geom = bufferGeom;
3829  clonedGeometry.reset( geom );
3830  }
3831 
3832  if ( clipGeometry && !clipGeometry->contains( geom ) )
3833  {
3834  QgsGeometry* clipGeom = geom->intersection( clipGeometry ); // creates new geometry
3835  if ( !clipGeom )
3836  {
3837  return 0;
3838  }
3839  geom = clipGeom;
3840  clonedGeometry.reset( geom );
3841  }
3842 
3843  return clonedGeometry.take();
3844 }
3845 
3846 bool QgsPalLabeling::checkMinimumSizeMM( const QgsRenderContext& context, const QgsGeometry* geom, double minSize )
3847 {
3848  if ( minSize <= 0 )
3849  {
3850  return true;
3851  }
3852 
3853  if ( !geom )
3854  {
3855  return false;
3856  }
3857 
3858  QGis::GeometryType featureType = geom->type();
3859  if ( featureType == QGis::Point ) //minimum size does not apply to point features
3860  {
3861  return true;
3862  }
3863 
3864  double mapUnitsPerMM = context.mapToPixel().mapUnitsPerPixel() * context.scaleFactor();
3865  if ( featureType == QGis::Line )
3866  {
3867  double length = geom->length();
3868  if ( length >= 0.0 )
3869  {
3870  return ( length >= ( minSize * mapUnitsPerMM ) );
3871  }
3872  }
3873  else if ( featureType == QGis::Polygon )
3874  {
3875  double area = geom->area();
3876  if ( area >= 0.0 )
3877  {
3878  return ( sqrt( area ) >= ( minSize * mapUnitsPerMM ) );
3879  }
3880  }
3881  return true; //should never be reached. Return true in this case to label such geometries anyway.
3882 }
3883 
3885 {
3886  if ( QgsVectorLayerDiagramProvider* provider = mDiagramProviders.value( layerID, 0 ) )
3887  provider->registerFeature( feat, context );
3888 }
3889 
3890 
3892 {
3893  init( mr->mapSettings() );
3894 }
3895 
3896 
3897 void QgsPalLabeling::init( const QgsMapSettings& mapSettings )
3898 {
3899  mEngine->setMapSettings( mapSettings );
3900 }
3901 
3903 {
3904  delete mEngine;
3905  mEngine = new QgsLabelingEngineV2();
3906 }
3907 
3909 {
3910  Q_UNUSED( layerName );
3911  return mInvalidLayerSettings;
3912 }
3913 
3916 {
3917  //font color
3918  if ( ddValues.contains( QgsPalLayerSettings::Color ) )
3919  {
3920  QVariant ddColor = ddValues.value( QgsPalLayerSettings::Color );
3921  tmpLyr.textColor = ddColor.value<QColor>();
3922  }
3923 
3924  //font transparency
3925  if ( ddValues.contains( QgsPalLayerSettings::FontTransp ) )
3926  {
3927  tmpLyr.textTransp = ddValues.value( QgsPalLayerSettings::FontTransp ).toInt();
3928  }
3929 
3930  tmpLyr.textColor.setAlphaF(( 100.0 - ( double )( tmpLyr.textTransp ) ) / 100.0 );
3931 
3932  //font blend mode
3933  if ( ddValues.contains( QgsPalLayerSettings::FontBlendMode ) )
3934  {
3935  tmpLyr.blendMode = ( QPainter::CompositionMode )ddValues.value( QgsPalLayerSettings::FontBlendMode ).toInt();
3936  }
3937 }
3938 
3941 {
3943  {
3944  tmpLyr.wrapChar = ddValues.value( QgsPalLayerSettings::MultiLineWrapChar ).toString();
3945  }
3946 
3947  if ( !tmpLyr.wrapChar.isEmpty() || tmpLyr.getLabelExpression()->expression().contains( "wordwrap" ) )
3948  {
3949 
3951  {
3952  tmpLyr.multilineHeight = ddValues.value( QgsPalLayerSettings::MultiLineHeight ).toDouble();
3953  }
3954 
3956  {
3958  }
3959 
3960  }
3961 
3962  if ( ddValues.contains( QgsPalLayerSettings::DirSymbDraw ) )
3963  {
3964  tmpLyr.addDirectionSymbol = ddValues.value( QgsPalLayerSettings::DirSymbDraw ).toBool();
3965  }
3966 
3967  if ( tmpLyr.addDirectionSymbol )
3968  {
3969 
3970  if ( ddValues.contains( QgsPalLayerSettings::DirSymbLeft ) )
3971  {
3972  tmpLyr.leftDirectionSymbol = ddValues.value( QgsPalLayerSettings::DirSymbLeft ).toString();
3973  }
3974  if ( ddValues.contains( QgsPalLayerSettings::DirSymbRight ) )
3975  {
3976  tmpLyr.rightDirectionSymbol = ddValues.value( QgsPalLayerSettings::DirSymbRight ).toString();
3977  }
3978 
3980  {
3982  }
3983 
3985  {
3987  }
3988 
3989  }
3990 }
3991 
3994 {
3995  //buffer draw
3996  if ( ddValues.contains( QgsPalLayerSettings::BufferDraw ) )
3997  {
3998  tmpLyr.bufferDraw = ddValues.value( QgsPalLayerSettings::BufferDraw ).toBool();
3999  }
4000 
4001  if ( !tmpLyr.bufferDraw )
4002  {
4003  // tmpLyr.bufferSize > 0.0 && tmpLyr.bufferTransp < 100 figured in during evaluation
4004  return; // don't continue looking for unused values
4005  }
4006 
4007  //buffer size
4008  if ( ddValues.contains( QgsPalLayerSettings::BufferSize ) )
4009  {
4010  tmpLyr.bufferSize = ddValues.value( QgsPalLayerSettings::BufferSize ).toDouble();
4011  }
4012 
4013  //buffer transparency
4014  if ( ddValues.contains( QgsPalLayerSettings::BufferTransp ) )
4015  {
4016  tmpLyr.bufferTransp = ddValues.value( QgsPalLayerSettings::BufferTransp ).toInt();
4017  }
4018 
4019  //buffer size units
4020  if ( ddValues.contains( QgsPalLayerSettings::BufferUnit ) )
4021  {
4023  tmpLyr.bufferSizeInMapUnits = ( bufunit == QgsPalLayerSettings::MapUnits );
4024  }
4025 
4026  //buffer color
4027  if ( ddValues.contains( QgsPalLayerSettings::BufferColor ) )
4028  {
4029  QVariant ddColor = ddValues.value( QgsPalLayerSettings::BufferColor );
4030  tmpLyr.bufferColor = ddColor.value<QColor>();
4031  }
4032 
4033  // apply any transparency
4034  tmpLyr.bufferColor.setAlphaF(( 100.0 - ( double )( tmpLyr.bufferTransp ) ) / 100.0 );
4035 
4036  //buffer pen join style
4038  {
4039  tmpLyr.bufferJoinStyle = ( Qt::PenJoinStyle )ddValues.value( QgsPalLayerSettings::BufferJoinStyle ).toInt();
4040  }
4041 
4042  //buffer blend mode
4044  {
4045  tmpLyr.bufferBlendMode = ( QPainter::CompositionMode )ddValues.value( QgsPalLayerSettings::BufferBlendMode ).toInt();
4046  }
4047 }
4048 
4051 {
4052  //shape draw
4053  if ( ddValues.contains( QgsPalLayerSettings::ShapeDraw ) )
4054  {
4055  tmpLyr.shapeDraw = ddValues.value( QgsPalLayerSettings::ShapeDraw ).toBool();
4056  }
4057 
4058  if ( !tmpLyr.shapeDraw )
4059  {
4060  return; // don't continue looking for unused values
4061  }
4062 
4063  if ( ddValues.contains( QgsPalLayerSettings::ShapeKind ) )
4064  {
4066  }
4067 
4068  if ( ddValues.contains( QgsPalLayerSettings::ShapeSVGFile ) )
4069  {
4070  tmpLyr.shapeSVGFile = ddValues.value( QgsPalLayerSettings::ShapeSVGFile ).toString();
4071  }
4072 
4073  if ( ddValues.contains( QgsPalLayerSettings::ShapeSizeType ) )
4074  {
4076  }
4077 
4078  if ( ddValues.contains( QgsPalLayerSettings::ShapeSizeX ) )
4079  {
4080  tmpLyr.shapeSize.setX( ddValues.value( QgsPalLayerSettings::ShapeSizeX ).toDouble() );
4081  }
4082  if ( ddValues.contains( QgsPalLayerSettings::ShapeSizeY ) )
4083  {
4084  tmpLyr.shapeSize.setY( ddValues.value( QgsPalLayerSettings::ShapeSizeY ).toDouble() );
4085  }
4086 
4088  {
4090  }
4091 
4093  {
4095  }
4096 
4097  if ( ddValues.contains( QgsPalLayerSettings::ShapeRotation ) )
4098  {
4099  tmpLyr.shapeRotation = ddValues.value( QgsPalLayerSettings::ShapeRotation ).toDouble();
4100  }
4101 
4102  if ( ddValues.contains( QgsPalLayerSettings::ShapeOffset ) )
4103  {
4104  tmpLyr.shapeOffset = ddValues.value( QgsPalLayerSettings::ShapeOffset ).toPointF();
4105  }
4106 
4108  {
4110  }
4111 
4112  if ( ddValues.contains( QgsPalLayerSettings::ShapeRadii ) )
4113  {
4114  tmpLyr.shapeRadii = ddValues.value( QgsPalLayerSettings::ShapeRadii ).toPointF();
4115  }
4116 
4118  {
4120  }
4121 
4123  {
4124  tmpLyr.shapeTransparency = ddValues.value( QgsPalLayerSettings::ShapeTransparency ).toInt();
4125  }
4126 
4128  {
4129  tmpLyr.shapeBlendMode = ( QPainter::CompositionMode )ddValues.value( QgsPalLayerSettings::ShapeBlendMode ).toInt();
4130  }
4131 
4133  {
4134  QVariant ddColor = ddValues.value( QgsPalLayerSettings::ShapeFillColor );
4135  tmpLyr.shapeFillColor = ddColor.value<QColor>();
4136  }
4137 
4139  {
4141  tmpLyr.shapeBorderColor = ddColor.value<QColor>();
4142  }
4143 
4145  {
4146  tmpLyr.shapeBorderWidth = ddValues.value( QgsPalLayerSettings::ShapeBorderWidth ).toDouble();
4147  }
4148 
4150  {
4152  }
4153 
4155  {
4156  tmpLyr.shapeJoinStyle = ( Qt::PenJoinStyle )ddValues.value( QgsPalLayerSettings::ShapeJoinStyle ).toInt();
4157  }
4158 }
4159 
4162 {
4163  //shadow draw
4164  if ( ddValues.contains( QgsPalLayerSettings::ShadowDraw ) )
4165  {
4166  tmpLyr.shadowDraw = ddValues.value( QgsPalLayerSettings::ShadowDraw ).toBool();
4167  }
4168 
4169  if ( !tmpLyr.shadowDraw )
4170  {
4171  return; // don't continue looking for unused values
4172  }
4173 
4174  if ( ddValues.contains( QgsPalLayerSettings::ShadowUnder ) )
4175  {
4177  }
4178 
4180  {
4181  tmpLyr.shadowOffsetAngle = ddValues.value( QgsPalLayerSettings::ShadowOffsetAngle ).toInt();
4182  }
4183 
4185  {
4186  tmpLyr.shadowOffsetDist = ddValues.value( QgsPalLayerSettings::ShadowOffsetDist ).toDouble();
4187  }
4188 
4190  {
4192  }
4193 
4194  if ( ddValues.contains( QgsPalLayerSettings::ShadowRadius ) )
4195  {
4196  tmpLyr.shadowRadius = ddValues.value( QgsPalLayerSettings::ShadowRadius ).toDouble();
4197  }
4198 
4200  {
4202  }
4203 
4205  {
4207  }
4208 
4209  if ( ddValues.contains( QgsPalLayerSettings::ShadowScale ) )
4210  {
4211  tmpLyr.shadowScale = ddValues.value( QgsPalLayerSettings::ShadowScale ).toInt();
4212  }
4213 
4214  if ( ddValues.contains( QgsPalLayerSettings::ShadowColor ) )
4215  {
4216  QVariant ddColor = ddValues.value( QgsPalLayerSettings::ShadowColor );
4217  tmpLyr.shadowColor = ddColor.value<QColor>();
4218  }
4219 
4221  {
4222  tmpLyr.shadowBlendMode = ( QPainter::CompositionMode )ddValues.value( QgsPalLayerSettings::ShadowBlendMode ).toInt();
4223  }
4224 }
4225 
4226 
4227 
4229 {
4230  mEngine->run( context );
4231 }
4232 
4234 {
4235 }
4236 
4238 {
4240 }
4241 
4243 {
4245 }
4246 
4248 {
4249  return mEngine->takeResults();
4250 }
4251 
4252 void QgsPalLabeling::numCandidatePositions( int& candPoint, int& candLine, int& candPolygon )
4253 {
4254  mEngine->numCandidatePositions( candPoint, candLine, candPolygon );
4255 }
4256 
4257 void QgsPalLabeling::setNumCandidatePositions( int candPoint, int candLine, int candPolygon )
4258 {
4259  mEngine->setNumCandidatePositions( candPoint, candLine, candPolygon );
4260 }
4261 
4263 {
4264  mEngine->setSearchMethod( s );
4265 }
4266 
4268 {
4269  return mEngine->searchMethod();
4270 }
4271 
4273 {
4275 }
4276 
4278 {
4280 }
4281 
4283 {
4285 }
4286 
4288 {
4290 }
4291 
4293 {
4295 }
4296 
4298 {
4300 }
4301 
4303 {
4305 }
4306 
4308 {
4310 }
4311 
4313 {
4315 }
4316 
4318 {
4320 }
4321 
4323 {
4325 }
4326 
4328 {
4330 }
4331 
4333 {
4334  QgsPoint outPt = xform->transform( lp->getX(), lp->getY() );
4335 
4336  painter->save();
4337 
4338 #if 0 // TODO: generalize some of this
4339  double w = lp->getWidth();
4340  double h = lp->getHeight();
4341  double cx = lp->getX() + w / 2.0;
4342  double cy = lp->getY() + h / 2.0;
4343  double scale = 1.0 / xform->mapUnitsPerPixel();
4344  double rotation = xform->mapRotation();
4345  double sw = w * scale;
4346  double sh = h * scale;
4347  QRectF rect( -sw / 2, -sh / 2, sw, sh );
4348 
4349  painter->translate( xform->transform( QPointF( cx, cy ) ).toQPointF() );
4350  if ( rotation )
4351  {
4352  // Only if not horizontal
4353  if ( lp->getFeaturePart()->getLayer()->getArrangement() != P_POINT &&
4354  lp->getFeaturePart()->getLayer()->getArrangement() != P_POINT_OVER &&
4355  lp->getFeaturePart()->getLayer()->getArrangement() != P_HORIZ )
4356  {
4357  painter->rotate( rotation );
4358  }
4359  }
4360  painter->translate( rect.bottomLeft() );
4361  painter->rotate( -lp->getAlpha() * 180 / M_PI );
4362  painter->translate( -rect.bottomLeft() );
4363 #else
4364  QgsPoint outPt2 = xform->transform( lp->getX() + lp->getWidth(), lp->getY() + lp->getHeight() );
4365  QRectF rect( 0, 0, outPt2.x() - outPt.x(), outPt2.y() - outPt.y() );
4366  painter->translate( QPointF( outPt.x(), outPt.y() ) );
4367  painter->rotate( -lp->getAlpha() * 180 / M_PI );
4368 #endif
4369 
4370  if ( lp->conflictsWithObstacle() )
4371  {
4372  painter->setPen( QColor( 255, 0, 0, 64 ) );
4373  }
4374  else
4375  {
4376  painter->setPen( QColor( 0, 0, 0, 64 ) );
4377  }
4378  painter->drawRect( rect );
4379  painter->restore();
4380 
4381  // save the rect
4382  rect.moveTo( outPt.x(), outPt.y() );
4383  if ( candidates )
4384  candidates->append( QgsLabelCandidate( rect, lp->cost() * 1000 ) );
4385 
4386  // show all parts of the multipart label
4387  if ( lp->getNextPart() )
4388  drawLabelCandidateRect( lp->getNextPart(), painter, xform, candidates );
4389 }
4390 
4391 
4393  const QgsLabelComponent& component,
4394  const QgsPalLayerSettings& tmpLyr )
4395 {
4396  QPainter* p = context.painter();
4397 
4398  double penSize = tmpLyr.scaleToPixelContext( tmpLyr.bufferSize, context,
4400 
4401  QPainterPath path;
4402  path.setFillRule( Qt::WindingFill );
4403  path.addText( 0, 0, tmpLyr.textFont, component.text() );
4404  QPen pen( tmpLyr.bufferColor );
4405  pen.setWidthF( penSize );
4406  pen.setJoinStyle( tmpLyr.bufferJoinStyle );
4407  QColor tmpColor( tmpLyr.bufferColor );
4408  // honor pref for whether to fill buffer interior
4409  if ( tmpLyr.bufferNoFill )
4410  {
4411  tmpColor.setAlpha( 0 );
4412  }
4413 
4414  // store buffer's drawing in QPicture for drop shadow call
4415  QPicture buffPict;
4416  QPainter buffp;
4417  buffp.begin( &buffPict );
4418  buffp.setPen( pen );
4419  buffp.setBrush( tmpColor );
4420  buffp.drawPath( path );
4421  buffp.end();
4422 
4423  if ( tmpLyr.shadowDraw && tmpLyr.shadowUnder == QgsPalLayerSettings::ShadowBuffer )
4424  {
4425  QgsLabelComponent bufferComponent = component;
4426  bufferComponent.setOrigin( QgsPoint( 0.0, 0.0 ) );
4427  bufferComponent.setPicture( &buffPict );
4428  bufferComponent.setPictureBuffer( penSize / 2.0 );
4429  drawLabelShadow( context, bufferComponent, tmpLyr );
4430  }
4431 
4432  p->save();
4433  if ( context.useAdvancedEffects() )
4434  {
4435  p->setCompositionMode( tmpLyr.bufferBlendMode );
4436  }
4437 // p->setPen( pen );
4438 // p->setBrush( tmpColor );
4439 // p->drawPath( path );
4440 
4441  // scale for any print output or image saving @ specific dpi
4442  p->scale( component.dpiRatio(), component.dpiRatio() );
4443  _fixQPictureDPI( p );
4444  p->drawPicture( 0, 0, buffPict );
4445  p->restore();
4446 }
4447 
4449  QgsLabelComponent component,
4450  const QgsPalLayerSettings& tmpLyr )
4451 {
4452  QPainter* p = context.painter();
4453  double labelWidth = component.size().x(), labelHeight = component.size().y();
4454  //QgsDebugMsgLevel( QString( "Background label rotation: %1" ).arg( component.rotation() ), 4 );
4455 
4456  // shared calculations between shapes and SVG
4457 
4458  // configure angles, set component rotation and rotationOffset
4460  {
4461  component.setRotation( -( component.rotation() * 180 / M_PI ) ); // RotationSync
4462  component.setRotationOffset(
4464  }
4465  else // RotationFixed
4466  {
4467  component.setRotation( 0.0 ); // don't use label's rotation
4468  component.setRotationOffset( tmpLyr.shapeRotation );
4469  }
4470 
4471  // mm to map units conversion factor
4472  double mmToMapUnits = tmpLyr.shapeSizeMapUnitScale.computeMapUnitsPerPixel( context ) * context.scaleFactor();
4473 
4474  // TODO: the following label-buffered generated shapes and SVG symbols should be moved into marker symbology classes
4475 
4476  if ( tmpLyr.shapeType == QgsPalLayerSettings::ShapeSVG )
4477  {
4478  // all calculations done in shapeSizeUnits, which are then passed to symbology class for painting
4479 
4480  if ( tmpLyr.shapeSVGFile.isEmpty() )
4481  return;
4482 
4483  double sizeOut = 0.0;
4484  // only one size used for SVG sizing/scaling (no use of shapeSize.y() or Y field in gui)
4486  {
4487  sizeOut = tmpLyr.shapeSize.x();
4488  }
4489  else if ( tmpLyr.shapeSizeType == QgsPalLayerSettings::SizeBuffer )
4490  {
4491  // add buffer to greatest dimension of label
4492  if ( labelWidth >= labelHeight )
4493  sizeOut = labelWidth;
4494  else if ( labelHeight > labelWidth )
4495  sizeOut = labelHeight;
4496 
4497  // label size in map units, convert to shapeSizeUnits, if different
4498  if ( tmpLyr.shapeSizeUnits == QgsPalLayerSettings::MM )
4499  {
4500  sizeOut /= mmToMapUnits;
4501  }
4502 
4503  // add buffer
4504  sizeOut += tmpLyr.shapeSize.x() * 2;
4505  }
4506 
4507  // don't bother rendering symbols smaller than 1x1 pixels in size
4508  // TODO: add option to not show any svgs under/over a certian size
4509  if ( tmpLyr.scaleToPixelContext( sizeOut, context, tmpLyr.shapeSizeUnits, false, tmpLyr.shapeSizeMapUnitScale ) < 1.0 )
4510  return;
4511 
4512  QgsStringMap map; // for SVG symbology marker
4514  map["size"] = QString::number( sizeOut );
4515  map["size_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit(
4517  map["angle"] = QString::number( 0.0 ); // angle is handled by this local painter
4518 
4519  // offset is handled by this local painter
4520  // TODO: see why the marker renderer doesn't seem to translate offset *after* applying rotation
4521  //map["offset"] = QgsSymbolLayerV2Utils::encodePoint( tmpLyr.shapeOffset );
4522  //map["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit(
4523  // tmpLyr.shapeOffsetUnits == QgsPalLayerSettings::MapUnits ? QgsSymbolV2::MapUnit : QgsSymbolV2::MM );
4524 
4525  map["fill"] = tmpLyr.shapeFillColor.name();
4526  map["outline"] = tmpLyr.shapeBorderColor.name();
4527  map["outline-width"] = QString::number( tmpLyr.shapeBorderWidth );
4528 
4529  // TODO: fix overriding SVG symbol's border width/units in QgsSvgCache
4530  // currently broken, fall back to symbol's
4531  //map["outline_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit(
4532  // tmpLyr.shapeBorderWidthUnits == QgsPalLayerSettings::MapUnits ? QgsSymbolV2::MapUnit : QgsSymbolV2::MM );
4533 
4534  if ( tmpLyr.shadowDraw && tmpLyr.shadowUnder == QgsPalLayerSettings::ShadowShape )
4535  {
4536  // configure SVG shadow specs
4537  QgsStringMap shdwmap( map );
4538  shdwmap["fill"] = tmpLyr.shadowColor.name();
4539  shdwmap["outline"] = tmpLyr.shadowColor.name();
4540  shdwmap["size"] = QString::number( sizeOut * tmpLyr.rasterCompressFactor );
4541 
4542  // store SVG's drawing in QPicture for drop shadow call
4543  QPicture svgPict;
4544  QPainter svgp;
4545  svgp.begin( &svgPict );
4546 
4547  // draw shadow symbol
4548 
4549  // clone current render context map unit/mm conversion factors, but not
4550  // other map canvas parameters, then substitute this painter for use in symbology painting
4551  // NOTE: this is because the shadow needs to be scaled correctly for output to map canvas,
4552  // but will be created relative to the SVG's computed size, not the current map canvas
4553  QgsRenderContext shdwContext;
4554  shdwContext.setMapToPixel( context.mapToPixel() );
4555  shdwContext.setScaleFactor( context.scaleFactor() );
4556  shdwContext.setPainter( &svgp );
4557 
4558  QgsSymbolLayerV2* symShdwL = QgsSvgMarkerSymbolLayerV2::create( shdwmap );
4559  QgsSvgMarkerSymbolLayerV2* svgShdwM = static_cast<QgsSvgMarkerSymbolLayerV2*>( symShdwL );
4560  QgsSymbolV2RenderContext svgShdwContext( shdwContext, QgsSymbolV2::Mixed,
4561  ( 100.0 - ( double )( tmpLyr.shapeTransparency ) ) / 100.0 );
4562 
4563  double svgSize = tmpLyr.scaleToPixelContext( sizeOut, context, tmpLyr.shapeSizeUnits, true, tmpLyr.shapeSizeMapUnitScale );
4564  svgShdwM->renderPoint( QPointF( svgSize / 2, -svgSize / 2 ), svgShdwContext );
4565  svgp.end();
4566 
4567  component.setPicture( &svgPict );
4568  // TODO: when SVG symbol's border width/units is fixed in QgsSvgCache, adjust for it here
4569  component.setPictureBuffer( 0.0 );
4570 
4571  component.setSize( QgsPoint( svgSize, svgSize ) );
4572  component.setOffset( QgsPoint( 0.0, 0.0 ) );
4573 
4574  // rotate about origin center of SVG
4575  p->save();
4576  p->translate( component.center().x(), component.center().y() );
4577  p->rotate( component.rotation() );
4578  p->scale( 1.0 / tmpLyr.rasterCompressFactor, 1.0 / tmpLyr.rasterCompressFactor );
4579  double xoff = tmpLyr.scaleToPixelContext( tmpLyr.shapeOffset.x(), context, tmpLyr.shapeOffsetUnits, true, tmpLyr.shapeOffsetMapUnitScale );
4580  double yoff = tmpLyr.scaleToPixelContext( tmpLyr.shapeOffset.y(), context, tmpLyr.shapeOffsetUnits, true, tmpLyr.shapeOffsetMapUnitScale );
4581  p->translate( QPointF( xoff, yoff ) );
4582  p->rotate( component.rotationOffset() );
4583  p->translate( -svgSize / 2, svgSize / 2 );
4584 
4585  drawLabelShadow( context, component, tmpLyr );
4586  p->restore();
4587 
4588  delete svgShdwM;
4589  svgShdwM = 0;
4590  }
4591 
4592  // draw the actual symbol
4594  QgsSvgMarkerSymbolLayerV2* svgM = static_cast<QgsSvgMarkerSymbolLayerV2*>( symL );
4595  QgsSymbolV2RenderContext svgContext( context, QgsSymbolV2::Mixed,
4596  ( 100.0 - ( double )( tmpLyr.shapeTransparency ) ) / 100.0 );
4597 
4598  p->save();
4599  if ( context.useAdvancedEffects() )
4600  {
4601  p->setCompositionMode( tmpLyr.shapeBlendMode );
4602  }
4603  p->translate( component.center().x(), component.center().y() );
4604  p->rotate( component.rotation() );
4605  double xoff = tmpLyr.scaleToPixelContext( tmpLyr.shapeOffset.x(), context, tmpLyr.shapeOffsetUnits, false, tmpLyr.shapeOffsetMapUnitScale );
4606  double yoff = tmpLyr.scaleToPixelContext( tmpLyr.shapeOffset.y(), context, tmpLyr.shapeOffsetUnits, false, tmpLyr.shapeOffsetMapUnitScale );
4607  p->translate( QPointF( xoff, yoff ) );
4608  p->rotate( component.rotationOffset() );
4609  svgM->renderPoint( QPointF( 0, 0 ), svgContext );
4610  p->setCompositionMode( QPainter::CompositionMode_SourceOver ); // just to be sure
4611  p->restore();
4612 
4613  delete svgM;
4614  svgM = 0;
4615 
4616  }
4617  else // Generated Shapes
4618  {
4619  // all calculations done in shapeSizeUnits
4620 
4621  double w = labelWidth / ( tmpLyr.shapeSizeUnits == QgsPalLayerSettings::MM ? mmToMapUnits : 1 );
4622  double h = labelHeight / ( tmpLyr.shapeSizeUnits == QgsPalLayerSettings::MM ? mmToMapUnits : 1 );
4623 
4624  double xsize = tmpLyr.shapeSize.x();
4625  double ysize = tmpLyr.shapeSize.y();
4626 
4628  {
4629  w = xsize;
4630  h = ysize;
4631  }
4632  else if ( tmpLyr.shapeSizeType == QgsPalLayerSettings::SizeBuffer )
4633  {
4635  {
4636  if ( w > h )
4637  h = w;
4638  else if ( h > w )
4639  w = h;
4640  }
4641  else if ( tmpLyr.shapeType == QgsPalLayerSettings::ShapeCircle )
4642  {
4643  // start with label bound by circle
4644  h = sqrt( pow( w, 2 ) + pow( h, 2 ) );
4645  w = h;
4646  }
4647  else if ( tmpLyr.shapeType == QgsPalLayerSettings::ShapeEllipse )
4648  {
4649  // start with label bound by ellipse
4650  h = h / sqrt( 2.0 ) * 2;
4651  w = w / sqrt( 2.0 ) * 2;
4652  }
4653 
4654  w += xsize * 2;
4655  h += ysize * 2;
4656  }
4657 
4658  // convert everything over to map pixels from here on
4659  w = tmpLyr.scaleToPixelContext( w, context, tmpLyr.shapeSizeUnits, true, tmpLyr.shapeSizeMapUnitScale );
4660  h = tmpLyr.scaleToPixelContext( h, context, tmpLyr.shapeSizeUnits, true, tmpLyr.shapeSizeMapUnitScale );
4661 
4662  // offsets match those of symbology: -x = left, -y = up
4663  QRectF rect( -w / 2.0, - h / 2.0, w, h );
4664 
4665  if ( rect.isNull() )
4666  return;
4667 
4668  p->save();
4669  p->translate( QPointF( component.center().x(), component.center().y() ) );
4670  p->rotate( component.rotation() );
4671  double xoff = tmpLyr.scaleToPixelContext( tmpLyr.shapeOffset.x(), context, tmpLyr.shapeOffsetUnits, false, tmpLyr.shapeOffsetMapUnitScale );
4672  double yoff = tmpLyr.scaleToPixelContext( tmpLyr.shapeOffset.y(), context, tmpLyr.shapeOffsetUnits, false, tmpLyr.shapeOffsetMapUnitScale );
4673  p->translate( QPointF( xoff, yoff ) );
4674  p->rotate( component.rotationOffset() );
4675 
4676  double penSize = tmpLyr.scaleToPixelContext( tmpLyr.shapeBorderWidth, context, tmpLyr.shapeBorderWidthUnits, true, tmpLyr.shapeBorderWidthMapUnitScale );
4677 
4678  QPen pen;
4679  if ( tmpLyr.shapeBorderWidth > 0 )
4680  {
4681  pen.setColor( tmpLyr.shapeBorderColor );
4682  pen.setWidthF( penSize );
4684  pen.setJoinStyle( tmpLyr.shapeJoinStyle );
4685  }
4686  else
4687  {
4688  pen = Qt::NoPen;
4689  }
4690 
4691  // store painting in QPicture for shadow drawing
4692  QPicture shapePict;
4693  QPainter shapep;
4694  shapep.begin( &shapePict );
4695  shapep.setPen( pen );
4696  shapep.setBrush( tmpLyr.shapeFillColor );
4697 
4700  {
4702  {
4703  shapep.drawRoundedRect( rect, tmpLyr.shapeRadii.x(), tmpLyr.shapeRadii.y(), Qt::RelativeSize );
4704  }
4705  else
4706  {
4707  double xRadius = tmpLyr.scaleToPixelContext( tmpLyr.shapeRadii.x(), context, tmpLyr.shapeRadiiUnits, true, tmpLyr.shapeRadiiMapUnitScale );
4708  double yRadius = tmpLyr.scaleToPixelContext( tmpLyr.shapeRadii.y(), context, tmpLyr.shapeRadiiUnits, true, tmpLyr.shapeRadiiMapUnitScale );
4709  shapep.drawRoundedRect( rect, xRadius, yRadius );
4710  }
4711  }
4712  else if ( tmpLyr.shapeType == QgsPalLayerSettings::ShapeEllipse
4714  {
4715  shapep.drawEllipse( rect );
4716  }
4717  shapep.end();
4718 
4719  p->scale( 1.0 / tmpLyr.rasterCompressFactor, 1.0 / tmpLyr.rasterCompressFactor );
4720 
4721  if ( tmpLyr.shadowDraw && tmpLyr.shadowUnder == QgsPalLayerSettings::ShadowShape )
4722  {
4723  component.setPicture( &shapePict );
4724  component.setPictureBuffer( penSize / 2.0 );
4725 
4726  component.setSize( QgsPoint( rect.width(), rect.height() ) );
4727  component.setOffset( QgsPoint( rect.width() / 2, -rect.height() / 2 ) );
4728  drawLabelShadow( context, component, tmpLyr );
4729  }
4730 
4731  p->setOpacity(( 100.0 - ( double )( tmpLyr.shapeTransparency ) ) / 100.0 );
4732  if ( context.useAdvancedEffects() )
4733  {
4734  p->setCompositionMode( tmpLyr.shapeBlendMode );
4735  }
4736 
4737  // scale for any print output or image saving @ specific dpi
4738  p->scale( component.dpiRatio(), component.dpiRatio() );
4739  _fixQPictureDPI( p );
4740  p->drawPicture( 0, 0, shapePict );
4741  p->restore();
4742  }
4743 }
4744 
4746  const QgsLabelComponent& component,
4747  const QgsPalLayerSettings& tmpLyr )
4748 {
4749  // incoming component sizes should be multiplied by rasterCompressFactor, as
4750  // this allows shadows to be created at paint device dpi (e.g. high resolution),
4751  // then scale device painter by 1.0 / rasterCompressFactor for output
4752 
4753  QPainter* p = context.painter();
4754  double componentWidth = component.size().x(), componentHeight = component.size().y();
4755  double xOffset = component.offset().x(), yOffset = component.offset().y();
4756  double pictbuffer = component.pictureBuffer();
4757 
4758  // generate pixmap representation of label component drawing
4759  bool mapUnits = ( tmpLyr.shadowRadiusUnits == QgsPalLayerSettings::MapUnits );
4760  double radius = tmpLyr.scaleToPixelContext( tmpLyr.shadowRadius, context, tmpLyr.shadowRadiusUnits, !mapUnits, tmpLyr.shadowRadiusMapUnitScale );
4761  radius /= ( mapUnits ? tmpLyr.vectorScaleFactor / component.dpiRatio() : 1 );
4762  radius = ( int )( radius + 0.5 );
4763 
4764  // TODO: add labeling gui option to adjust blurBufferClippingScale to minimize pixels, or
4765  // to ensure shadow isn't clipped too tight. (Or, find a better method of buffering)
4766  double blurBufferClippingScale = 3.75;
4767  int blurbuffer = ( radius > 17 ? 16 : radius ) * blurBufferClippingScale;
4768 
4769  QImage blurImg( componentWidth + ( pictbuffer * 2.0 ) + ( blurbuffer * 2.0 ),
4770  componentHeight + ( pictbuffer * 2.0 ) + ( blurbuffer * 2.0 ),
4771  QImage::Format_ARGB32_Premultiplied );
4772 
4773  // TODO: add labeling gui option to not show any shadows under/over a certian size
4774  // keep very small QImages from causing paint device issues, i.e. must be at least > 1
4775  int minBlurImgSize = 1;
4776  // max limitation on QgsSvgCache is 10,000 for screen, which will probably be reasonable for future caching here, too
4777  // 4 x QgsSvgCache limit for output to print/image at higher dpi
4778  // TODO: should it be higher, scale with dpi, or have no limit? Needs testing with very large labels rendered at high dpi output
4779  int maxBlurImgSize = 40000;
4780  if ( blurImg.isNull()
4781  || ( blurImg.width() < minBlurImgSize || blurImg.height() < minBlurImgSize )
4782  || ( blurImg.width() > maxBlurImgSize || blurImg.height() > maxBlurImgSize ) )
4783  return;
4784 
4785  blurImg.fill( QColor( Qt::transparent ).rgba() );
4786  QPainter pictp;
4787  if ( !pictp.begin( &blurImg ) )
4788  return;
4789  pictp.setRenderHints( QPainter::Antialiasing | QPainter::SmoothPixmapTransform );
4790  QPointF imgOffset( blurbuffer + pictbuffer + xOffset,
4791  blurbuffer + pictbuffer + componentHeight + yOffset );
4792 
4793  pictp.drawPicture( imgOffset,
4794  *component.picture() );
4795 
4796  // overlay shadow color
4797  pictp.setCompositionMode( QPainter::CompositionMode_SourceIn );
4798  pictp.fillRect( blurImg.rect(), tmpLyr.shadowColor );
4799  pictp.end();
4800 
4801  // blur the QImage in-place
4802  if ( tmpLyr.shadowRadius > 0.0 && radius > 0 )
4803  {
4804  QgsSymbolLayerV2Utils::blurImageInPlace( blurImg, blurImg.rect(), radius, tmpLyr.shadowRadiusAlphaOnly );
4805  }
4806 
4807  if ( tmpLyr.showingShadowRects ) // engine setting, not per layer
4808  {
4809  // debug rect for QImage shadow registration and clipping visualization
4810  QPainter picti;
4811  picti.begin( &blurImg );
4812  picti.setBrush( Qt::Dense7Pattern );
4813  QPen imgPen( QColor( 0, 0, 255, 255 ) );
4814  imgPen.setWidth( 1 );
4815  picti.setPen( imgPen );
4816  picti.setOpacity( 0.1 );
4817  picti.drawRect( 0, 0, blurImg.width(), blurImg.height() );
4818  picti.end();
4819  }
4820 
4821  double offsetDist = tmpLyr.scaleToPixelContext( tmpLyr.shadowOffsetDist, context, tmpLyr.shadowOffsetUnits, true, tmpLyr.shadowOffsetMapUnitScale );
4822  double angleRad = tmpLyr.shadowOffsetAngle * M_PI / 180; // to radians
4823  if ( tmpLyr.shadowOffsetGlobal )
4824  {
4825  // TODO: check for differences in rotation origin and cw/ccw direction,
4826  // when this shadow function is used for something other than labels
4827 
4828  // it's 0-->cw-->360 for labels
4829  //QgsDebugMsgLevel( QString( "Shadow aggregated label rotation (degrees): %1" ).arg( component.rotation() + component.rotationOffset() ), 4 );
4830  angleRad -= ( component.rotation() * M_PI / 180 + component.rotationOffset() * M_PI / 180 );
4831  }
4832 
4833  QPointF transPt( -offsetDist * cos( angleRad + M_PI / 2 ),
4834  -offsetDist * sin( angleRad + M_PI / 2 ) );
4835 
4836  p->save();
4837  p->setRenderHints( QPainter::Antialiasing | QPainter::SmoothPixmapTransform );
4838  if ( context.useAdvancedEffects() )
4839  {
4840  p->setCompositionMode( tmpLyr.shadowBlendMode );
4841  }
4842  p->setOpacity(( 100.0 - ( double )( tmpLyr.shadowTransparency ) ) / 100.0 );
4843 
4844  double scale = ( double )tmpLyr.shadowScale / 100.0;
4845  // TODO: scale from center/center, left/center or left/top, instead of default left/bottom?
4846  p->scale( scale, scale );
4847  if ( component.useOrigin() )
4848  {
4849  p->translate( component.origin().x(), component.origin().y() );
4850  }
4851  p->translate( transPt );
4852  p->translate( -imgOffset.x(),
4853  -imgOffset.y() );
4854  p->drawImage( 0, 0, blurImg );
4855  p->restore();
4856 
4857  // debug rects
4858  if ( tmpLyr.showingShadowRects ) // engine setting, not per layer
4859  {
4860  // draw debug rect for QImage painting registration
4861  p->save();
4862  p->setBrush( Qt::NoBrush );
4863  QPen imgPen( QColor( 255, 0, 0, 10 ) );
4864  imgPen.setWidth( 2 );
4865  imgPen.setStyle( Qt::DashLine );
4866  p->setPen( imgPen );
4867  p->scale( scale, scale );
4868  if ( component.useOrigin() )
4869  {
4870  p->translate( component.origin().x(), component.origin().y() );
4871  }
4872  p->translate( transPt );
4873  p->translate( -imgOffset.x(),
4874  -imgOffset.y() );
4875  p->drawRect( 0, 0, blurImg.width(), blurImg.height() );
4876  p->restore();
4877 
4878  // draw debug rect for passed in component dimensions
4879  p->save();
4880  p->setBrush( Qt::NoBrush );
4881  QPen componentRectPen( QColor( 0, 255, 0, 70 ) );
4882  componentRectPen.setWidth( 1 );
4883  if ( component.useOrigin() )
4884  {
4885  p->translate( component.origin().x(), component.origin().y() );
4886  }
4887  p->setPen( componentRectPen );
4888  p->drawRect( QRect( -xOffset, -componentHeight - yOffset, componentWidth, componentHeight ) );
4889  p->restore();
4890  }
4891 }
4892 
4894 {
4896 }
4897 
4899 {
4901 }
4902 
4904 {
4905  QgsProject::instance()->removeEntry( "PAL", "/SearchMethod" );
4906  QgsProject::instance()->removeEntry( "PAL", "/CandidatesPoint" );
4907  QgsProject::instance()->removeEntry( "PAL", "/CandidatesLine" );
4908  QgsProject::instance()->removeEntry( "PAL", "/CandidatesPolygon" );
4909  QgsProject::instance()->removeEntry( "PAL", "/ShowingCandidates" );
4910  QgsProject::instance()->removeEntry( "PAL", "/ShowingShadowRects" );
4911  QgsProject::instance()->removeEntry( "PAL", "/ShowingAllLabels" );
4912  QgsProject::instance()->removeEntry( "PAL", "/ShowingPartialsLabels" );
4913  QgsProject::instance()->removeEntry( "PAL", "/DrawOutlineLabels" );
4914 }
4915 
4917 {
4918  QgsPalLabeling* lbl = new QgsPalLabeling();
4925  return lbl;
4926 }
4927 
4928 
4930 {
4931  mLabelSearchTree = new QgsLabelSearchTree();
4932 }
4933 
4935 {
4936  delete mLabelSearchTree;
4937  mLabelSearchTree = NULL;
4938 }
4939 
4941 {
4942  QList<QgsLabelPosition> positions;
4943 
4944  QList<QgsLabelPosition*> positionPointers;
4945  if ( mLabelSearchTree )
4946  {
4947  mLabelSearchTree->label( p, positionPointers );
4948  QList<QgsLabelPosition*>::const_iterator pointerIt = positionPointers.constBegin();
4949  for ( ; pointerIt != positionPointers.constEnd(); ++pointerIt )
4950  {
4951  positions.push_back( QgsLabelPosition( **pointerIt ) );
4952  }
4953  }
4954 
4955  return positions;
4956 }
4957 
4959 {
4960  QList<QgsLabelPosition> positions;
4961 
4962  QList<QgsLabelPosition*> positionPointers;
4963  if ( mLabelSearchTree )
4964  {
4965  mLabelSearchTree->labelsInRect( r, positionPointers );
4966  QList<QgsLabelPosition*>::const_iterator pointerIt = positionPointers.constBegin();
4967  for ( ; pointerIt != positionPointers.constEnd(); ++pointerIt )
4968  {
4969  positions.push_back( QgsLabelPosition( **pointerIt ) );
4970  }
4971  }
4972 
4973  return positions;
4974 }
const QgsMapSettings & mapSettings()
bridge to QgsMapSettings
virtual void registerDiagramFeature(const QString &layerID, QgsFeature &feat, QgsRenderContext &context) override
called for every diagram feature
QgsFeatureId id() const
Get the feature ID for this feature.
Definition: qgsfeature.cpp:53
QTransform fromTranslate(qreal dx, qreal dy)
static QString encodeOutputUnit(QgsSymbolV2::OutputUnit unit)
static void _fixQPictureDPI(QPainter *p)
Class for parsing and evaluation of expressions (formerly called "search strings").
Definition: qgsexpression.h:92
void setShowingCandidates(bool showing)
const QString & name() const
Gets the name of the field.
Definition: qgsfield.cpp:72
bool hasEvalError() const
Returns true if an error occurred when evaluating last input.
void setActive(bool active)
void setOpacity(qreal opacity)
FeaturePart * getFeaturePart()
return the feature corresponding to this labelposition
A rectangle specified with double values.
Definition: qgsrectangle.h:35
void setStyle(Qt::PenStyle style)
QHash< QString, QgsVectorLayerLabelProvider * > mLabelProviders
hashtable of label providers, being filled during labeling (key = layer ID)
QString & append(QChar ch)
void label(const QgsPoint &p, QList< QgsLabelPosition * > &posList) const
Returns label position(s) at a given point.
bool hasParserError() const
Returns true if an error occurred when parsing the input expression.
static void dataDefinedShapeBackground(QgsPalLayerSettings &tmpLyr, const QMap< QgsPalLayerSettings::DataDefinedProperties, QVariant > &ddValues)
bool dataDefinedIsActive(QgsPalLayerSettings::DataDefinedProperties p) const
Whether data definition is active.
iterator erase(iterator pos)
QgsMapUnitScale shapeSizeMapUnitScale
bool diagramsEnabled() const
Returns whether the layer contains diagrams which are enabled and should be drawn.
static void dataDefinedTextStyle(QgsPalLayerSettings &tmpLyr, const QMap< QgsPalLayerSettings::DataDefinedProperties, QVariant > &ddValues)
A container class for data source field mapping or expression.
QgsMapUnitScale shadowRadiusMapUnitScale
bool end()
bool contains(const Key &key) const
Q_DECL_DEPRECATED QVariant evaluate(const QgsFeature *f)
Evaluate the feature and return the result.
int pixelSize() const
void setOrigin(const QgsPoint &point)
void fillRect(const QRectF &rectangle, const QBrush &brush)
void setCompositionMode(CompositionMode mode)
virtual bool willUseLayer(QgsVectorLayer *layer) override
called to find out whether the layer is used for labeling
virtual bool prepare(const QgsRenderContext &context, QStringList &attributeNames)
Prepare for registration of features.
void setNumCandidatePositions(int candPoint, int candLine, int candPolygon)
arranges candidates around a point (centroid for polygon)
Definition: pal.h:79
QDomNode appendChild(const QDomNode &newChild)
const QString expression() const
Alias for dump()
void push_back(const T &value)
const QString & text() const
QString name() const
double getWidth() const
QgsLabelingResults * takeResults()
Return pointer to recently computed results (in drawLabeling()) and pass the ownership of results to ...
QString attribute(const QString &name, const QString &defValue) const
QString field() const
Get the field which this QgsDataDefined represents.
A class to query the labeling structure at a given point (small wraper around pal RTree class) ...
UpsideDownLabels upsidedownLabels
double obstacleFactor
Obstacle factor, where 1.0 = default, < 1.0 more likely to be covered by labels, 1.0 less likely to be covered
qreal pointSizeF() const
void setShowingPartialsLabels(bool showing)
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
void setSearchMethod(Search s)
int weight() const
QPoint map(const QPoint &point) const
void loadEngineSettings()
load/save engine settings to project file
Whether to show debugging rectangles for drop shadows.
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const
static QString encodeColor(const QColor &color)
QPainter::CompositionMode bufferBlendMode
QString & prepend(QChar ch)
double rendererScale() const
double rotationOffset() const
QgsMapUnitScale shadowOffsetMapUnitScale
const QgsPoint & size() const
void scale(qreal sx, qreal sy)
double computeMapUnitsPerPixel(const QgsRenderContext &c) const
Computes a map units per pixel scaling factor, respecting the minimum and maximum scales set for the ...
void addProvider(QgsAbstractLabelProvider *provider)
Add provider of label features. Takes ownership of the provider.
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
void setCustomProperty(const QString &key, const QVariant &value)
Set a custom property for layer.
double cost() const
Returns the candidate label position's geographical cost.
QuadrantPosition quadOffset
void setUnderline(bool enable)
static void drawLabelBuffer(QgsRenderContext &context, const QgsLabelComponent &component, const QgsPalLayerSettings &tmpLyr)
QGis::GeometryType type() const
Returns type of the geometry as a QGis::GeometryType.
virtual Q_DECL_DEPRECATED int addDiagramLayer(QgsVectorLayer *layer, const QgsDiagramLayerSettings *s) override
adds a diagram layer to the labeling engine
Class that adds extra information to QgsLabelFeature for text labels.
void save()
void numCandidatePositions(int &candPoint, int &candLine, int &candPolygon)
The QgsLabelingEngineV2 class provides map labeling functionality.
void setDefinedFont(const QFont &f)
Set font to be used for rendering.
QgsExpression * expression()
T value() const
Container of fields for a vector layer.
Definition: qgsfield.h:177
static QgsPalLayerSettings fromLayer(QgsVectorLayer *layer)
The QgsVectorLayerLabelProvider class implements a label provider for vector layers.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:76
void setJoinStyle(Qt::PenJoinStyle style)
void setAlpha(int alpha)
bool drawLabels
Whether to draw labels for this layer.
QHash< QString, QgsVectorLayerDiagramProvider * > mDiagramProviders
hashtable of diagram providers (key = layer ID)
void readFromLayer(QgsVectorLayer *layer)
static QPointF decodePoint(const QString &str)
QString expressionString() const
Returns the expression string of this QgsDataDefined.
GeometryType
Definition: qgis.h:104
const QgsRectangle & extent() const
static void dataDefinedDropShadow(QgsPalLayerSettings &tmpLyr, const QMap< QgsPalLayerSettings::DataDefinedProperties, QVariant > &ddValues)
Capitalization capitalization() const
QgsMapUnitScale repeatDistanceMapUnitScale
MultiLineAlign multilineAlign
QgsPoint transform(const QgsPoint &p, TransformDirection direction=ForwardTransform) const
Transform the point from Source Coordinate System to Destination Coordinate System If the direction i...
void removeDataDefinedProperty(QgsPalLayerSettings::DataDefinedProperties p)
Set a property to static instead data defined.
double scaleFactor() const
QString join(const QString &separator) const
bool isNull() const
void readSettingsFromProject()
Read configuration of the labeling engine from the current project file.
void rotate(qreal angle)
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:176
void addText(const QPointF &point, const QFont &font, const QString &text)
const QgsPoint & origin() const
double dpiRatio() const
A non GUI class for rendering a map layer set onto a QPainter.
void setNumCandidatePositions(int candPoint, int candLine, int candPolygon)
Set number of candidate positions that will be generated for each label feature.
void clear()
static QString translateNamedStyle(const QString &namedStyle)
Returns the localized named style of a font, if such a translation is available.
double toDouble(bool *ok) 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.
const QgsPoint & center() const
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:268
double maxScale
The maximum scale, or 0.0 if unset.
void setRotationOffset(const double rotation)
double x() const
Get the x value of the point.
Definition: qgspoint.h:126
bool bold() const
static void drawLabelBackground(QgsRenderContext &context, QgsLabelComponent component, const QgsPalLayerSettings &tmpLyr)
Qt::PenJoinStyle bufferJoinStyle
int size() const
QgsMapLayer * mapLayer(const QString &theLayerId)
Retrieve a pointer to a loaded layer by id.
void setHasFixedPosition(bool enabled)
Set whether the label should use a fixed position instead of being automatically placed.
bool italic() const
void reset(T *other)
QgsMapUnitScale fontSizeMapUnitScale
const QgsPoint & offset() const
The QgsMapSettings class contains configuration for rendering of the map.
QgsMapUnitScale shapeBorderWidthMapUnitScale
QString styleName() const
virtual Q_DECL_DEPRECATED void init(QgsMapRenderer *mr) override
called when we're going to start with rendering
QgsLabelingResults * results() const
For internal use by the providers.
bool useAdvancedEffects() const
Returns true if advanced effects such as blend modes such be used.
bool dataDefinedUseExpression(QgsPalLayerSettings::DataDefinedProperties p) const
Whether data definition is set to use an expression.
void removeProvider(QgsAbstractLabelProvider *provider)
Remove provider if the provider's initialization failed. Provider instance is deleted.
static bool staticWillUseLayer(QgsVectorLayer *layer)
called to find out whether the layer is used for labeling
void setBold(bool enable)
virtual void clearActiveLayer(const QString &layerID) override
clears data defined objects from PAL layer settings for a registered layer
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
QList< QgsLabelPosition > labelsWithinRect(const QgsRectangle &r) const
return infos about labels within a given (map) rectangle
void setPixelSize(int pixelSize)
void setUseExpression(bool use)
Controls if the field or the expression part is active.
void setSearchMethod(QgsPalLabeling::Search s)
Set which search method to use for removal collisions between labels.
Mixed units in symbol layers.
Definition: qgssymbolv2.h:59
double rotation() const
void transformInPlace(double &x, double &y, double &z, TransformDirection direction=ForwardTransform) const
bool contains(const QgsPoint *p) const
Test for containment of a point (uses GEOS)
QTransform & translate(qreal dx, qreal dy)
The output shall be in millimeters.
Definition: qgssymbolv2.h:57
static QPainter::CompositionMode decodeBlendMode(const QString &s)
ObstacleType obstacleType
Controls how features act as obstacles for labels.
void setRotation(const double rotation)
QFont font()
QString number(int n, int base)
qreal x() const
qreal y() const
static bool geometryRequiresPreparation(const QgsGeometry *geometry, QgsRenderContext &context, const QgsCoordinateTransform *ct, QgsGeometry *clipGeometry=0)
Checks whether a geometry requires preparation before registration with PAL.
void append(const T &value)
static void dataDefinedTextBuffer(QgsPalLayerSettings &tmpLyr, const QMap< QgsPalLayerSettings::DataDefinedProperties, QVariant > &ddValues)
void setIsObstacle(bool enabled)
Sets whether the feature will act as an obstacle for labels.
bool setFromXmlElement(const QDomElement &element)
Sets the properties of the data defined container from an XML element.
void setScaleFactor(double factor)
uint toUInt(bool *ok) const
QDomDocument ownerDocument() const
const QgsCoordinateTransform * ct
int toInt(bool *ok) const
bool isNull() const
bool useOrigin() const
QgsMapUnitScale shapeRadiiMapUnitScale
const QgsAbstractVectorLayerLabeling * labeling() const
Access to labeling configuration.
const QPicture * picture() const
void fill(uint pixelValue)
void setFillRule(Qt::FillRule fillRule)
double getY(int i=0) const
get the down-left y coordinate
static QString encodePoint(QPointF point)
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:34
double getAlpha() const
get alpha
QgsPalLayerSettings mInvalidLayerSettings
SizeUnit shapeBorderWidthUnits
QPainter::CompositionMode blendMode
Whether to draw rectangles of generated candidates (good for debugging)
int red() const
static bool fontFamilyOnSystem(const QString &family)
Check whether font family is on system in a quick manner, which does not compare [foundry].
void setPen(const QColor &color)
QList< QgsLabelPosition > labelsAtPosition(const QgsPoint &p) const
return infos about labels at a given (map) position
int width() const
void drawEllipse(const QRectF &rectangle)
qreal letterSpacing() const
void setAttribute(const QString &name, const QString &value)
bool dataDefinedEvaluate(QgsPalLayerSettings::DataDefinedProperties p, QVariant &exprVal, QgsExpressionContext *context=0, const QVariant &originalValue=QVariant()) const
Get data defined property value from expression string or attribute field name.
void setField(const QString &field)
Set the field name which this QgsDataDefined represents.
The QgsVectorLayerDiagramProvider class implements support for diagrams within the labeling engine...
QString updateDataDefinedString(const QString &value)
Convert old property value to new one as delimited values.
void drawRoundedRect(const QRectF &rect, qreal xRadius, qreal yRadius, Qt::SizeMode mode)
virtual QgsLabelingEngineInterface * clone() override
called when passing engine among map renderers
int toInt(bool *ok, int base) const
bool isEmpty() const
void setDataDefinedValues(const QMap< QgsPalLayerSettings::DataDefinedProperties, QVariant > &values)
Set data-defined values.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
virtual void drawLabeling(QgsRenderContext &context) override
called when the map is drawn and labels should be placed
virtual QgsAttrPalIndexNameHash palAttributeIndexNames() const
Return list of indexes to names for QgsPalLabeling fix.
Q_DECL_DEPRECATED QgsPalLayerSettings & layer(const QString &layerName) override
bool isEmpty() const
QRect rect() const
QString trimmed() const
static QString encodePenJoinStyle(Qt::PenJoinStyle style)
const_iterator constEnd() const
QDomElement toXmlElement(QDomDocument &document, const QString &elementName) const
Returns a DOM element containing the properties of the data defined container.
static QString symbolNameToPath(QString name)
Get symbol's path from its name.
The output shall be in map unitx.
Definition: qgssymbolv2.h:58
#define M_PI
const QgsMapToPixel * xform
void calculateInfo(bool curvedLabeling, QFontMetricsF *fm, const QgsMapToPixel *xform, double fontScale, double maxinangle, double maxoutangle)
calculate data for info(). setDefinedFont() must have been called already.
QMap< QgsPalLayerSettings::DataDefinedProperties, QgsDataDefined * > dataDefinedProperties
Map of current data defined properties.
QPaintDevice * device() const
void setWidthF(qreal width)
void readXml(QDomElement &elem)
Read settings from a DOM element.
void setBrush(const QBrush &brush)
void setPainter(QPainter *p)
bool isShowingPartialsLabels() const
double rasterScaleFactor() const
QString id() const
Get this layer's unique ID, this ID is used to access this layer from map layer registry.
bool removeEntry(const QString &scope, const QString &key)
Remove the given key.
const T & value() const
bool underline() const
QgsMapUnitScale bufferSizeMapUnitScale
double mapUnitsPerPixel() const
Return current map units per pixel.
QGis::GeometryType geometryType() const
Returns point, line or polygon.
QgsFeature * mCurFeat
LabelPosition * getNextPart() const
void removeCustomProperty(const QString &key)
Remove a custom property from layer.
QPainter::CompositionMode shapeBlendMode
iterator end()
double scaleToPixelContext(double size, const QgsRenderContext &c, SizeUnit unit, bool rasterfactor=false, const QgsMapUnitScale &mapUnitScale=QgsMapUnitScale()) const
Calculates size (considering output size should be in pixel or map units, scale factors and optionall...
QVariant customProperty(const QString &value, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer.
QVariant dataDefinedValue(QgsPalLayerSettings::DataDefinedProperties p, QgsFeature &f, const QgsFields &fields, const QgsExpressionContext *context=0) const
Get data defined property value from expression string or attribute field name.
void setColor(const QColor &color)
const GEOSGeometry * asGeos(double precision=0) const
Returns a geos geometry.
T & value() const
QgsDataDefined * dataDefinedProperty(QgsPalLayerSettings::DataDefinedProperties p)
Get a data defined property pointer.
const QgsField & at(int i) const
Get field at particular index (must be in range 0..N-1)
Definition: qgsfield.cpp:331
SizeUnit
Units used for option sizes, before being converted to rendered sizes.
Search searchMethod() const
int alpha() const
QMap< QString, QString > dataDefinedMap(QgsPalLayerSettings::DataDefinedProperties p) const
Get property value as separate values split into Qmap.
QgsGeometry * buffer(double distance, int segments) const
Returns a buffer region around this geometry having the given width and with a specified number of se...
A class to represent a point.
Definition: qgspoint.h:63
iterator begin()
static Qt::PenJoinStyle _decodePenJoinStyle(const QString &str)
Qt::PenJoinStyle shapeJoinStyle
void writeSettingsToProject()
Write configuration of the labeling engine to the current project file.
BlendMode
Blending modes enum defining the available composition modes that can be used when rendering a layer...
bool useExpression() const
Returns if the field or the expression part is active.
int indexFromName(const QString &name) const
Look up field's index from name. Returns -1 on error.
Definition: qgsfield.cpp:364
int logicalDpiX() const
int logicalDpiY() const
bool drawLabelRectOnly() const
Returns whether the engine will only draw the outline rectangles of labels, not the label contents th...
T * data() const
int green() 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)
const T value(const Key &key) const
void setWordSpacing(qreal spacing)
bool testFlag(Flag f) const
Test whether a particular flag is enabled.
bool isNull() const
bool contains(QChar ch, Qt::CaseSensitivity cs) const
void clear()
void setMapSettings(const QgsMapSettings &mapSettings)
Associate map settings instance.
Only for lines, labels along the line.
Definition: pal.h:83
QgsExpressionContext & expressionContext()
Gets the expression context.
double length() const
Returns the length of geometry using GEOS.
void run(QgsRenderContext &context)
compute the labeling with given map settings and providers
void setItalic(bool enable)
void setPointSizeF(qreal pointSize)
Q_GUI_EXPORT int qt_defaultDpiX()
QgsPoint toMapCoordinatesF(double x, double y) const
Transform device coordinates to map (world) coordinates.
bool isNull() const
static QPainter::CompositionMode getCompositionMode(const QgsMapRenderer::BlendMode &blendMode)
Returns a QPainter::CompositionMode corresponding to a BlendMode.
unsigned int placementFlags
Whether to draw all labels even if there would be collisions.
QgsPalLayerSettings & operator=(const QgsPalLayerSettings &s)
copy operator - only copies the permanent members
Whether to use also label candidates that are partially outside of the map view.
void setRenderHints(QFlags< QPainter::RenderHint > hints, bool on)
void restore()
const Key key(const T &value) const
QTransform & rotate(qreal angle, Qt::Axis axis)
QgsGeometry * intersection(const QgsGeometry *geometry) const
Returns a geometry representing the points shared by this geometry and other.
static QString untranslateNamedStyle(const QString &namedStyle)
Returns the english named style of a font, if possible.
bool isShowingCandidates() const
static QColor _readColor(QgsVectorLayer *layer, const QString &property, const QColor &defaultColor=Qt::black, bool withAlpha=true)
Q_GUI_EXPORT int qt_defaultDpiY()
int blue() const
QgsExpression * getLabelExpression()
Returns the QgsExpression for this label settings.
void setDrawingOutlineLabels(bool outline)
Contains information about the context of a rendering operation.
void setShowingShadowRectangles(bool showing)
void setPicture(QPicture *picture)
virtual int prepareDiagramLayer(QgsVectorLayer *layer, QStringList &attrNames, QgsRenderContext &ctx) override
adds a diagram layer to the labeling engine
virtual const QgsFields & fields() const =0
Return a map of indexes with field names for this layer.
void setDataDefinedProperty(QgsPalLayerSettings::DataDefinedProperties p, bool active, bool useExpr, const QString &expr, const QString &field)
Set a property as data defined.
static QgsMapLayerRegistry * instance()
Returns the instance pointer, creating the object on the first call.
void drawImage(const QRectF &target, const QImage &image, const QRectF &source, QFlags< Qt::ImageConversionFlag > flags)
QPainter * painter()
The QgsLabelFeature class describes a feature that should be used within the labeling engine...
qreal width() const
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:238
QString mid(int position, int n) const
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)
static QgsPalLayerSettings::SizeUnit _decodeUnits(const QString &str)
static GEOSContextHandle_t getGEOSHandler()
Return GEOS context handle.
void setWidth(int width)
double getHeight() const
QgsMapUnitScale distMapUnitScale
QString toString() const
Struct for storing maximum and minimum scales for measurements in map units.
qreal ascent() const
bool fitInPolygonOnly
True if only labels which completely fit within a polygon are allowed.
virtual Q_DECL_DEPRECATED QList< QgsLabelPosition > labelsWithinRect(const QgsRectangle &r) override
return infos about labels within a given (map) rectangle
bool isEmpty() const
bool expressionIsPrepared() const
Returns whether the data defined object's expression is prepared.
QString family() const
int rotate(double rotation, const QgsPoint &center)
Rotate this geometry around the Z axis.
static bool updateFontViaStyle(QFont &f, const QString &fontstyle, bool fallback=false)
Updates font with named style and retain all font properties.
void setX(qreal x)
void setY(qreal y)
int sizeToPixel(double size, const QgsRenderContext &c, SizeUnit unit, bool rasterfactor=false, const QgsMapUnitScale &mapUnitScale=QgsMapUnitScale()) const
Calculates pixel size (considering output size should be in pixel or map units, scale factors and opt...
static QgsProject * instance()
access to canonical QgsProject instance
Definition: qgsproject.cpp:353
QDomElement firstChildElement(const QString &tagName) const
virtual void clearActiveLayers() override
clears all PAL layer settings for registered layers
QPointF bottomLeft() const
void setMapToPixel(const QgsMapToPixel &mtp)
static QStringList splitToGraphemes(const QString &text)
Splits a text string to a list of graphemes, which are the smallest allowable character divisions in ...
int size() const
Return number of items.
Definition: qgsfield.cpp:316
const QgsGeometry * constGeometry() const
Gets a const pointer to the geometry object associated with this feature.
Definition: qgsfeature.cpp:70
QgsPalLabeling::Search searchMethod() const
Which search method to use for removal collisions between labels.
qreal descent() const
Class for doing transforms between two map coordinate systems.
void setStrikeOut(bool enable)
static void _writeColor(QgsVectorLayer *layer, const QString &property, const QColor &color, bool withAlpha=true)
LabelPosition is a candidate feature label position.
Definition: labelposition.h:48
bool toBool() const
void translate(const QPointF &offset)
int transform(const QgsCoordinateTransform &ct)
Transform this geometry as described by CoordinateTransform ct.
void registerFeature(QgsFeature &f, QgsRenderContext &context, const QString &dxfLayer, QgsLabelFeature **labelFeature=0)
Register a feature for labelling.
void setCapitalization(Capitalization caps)
QDomElement writeXml(QDomDocument &doc)
Write settings into a DOM element.
const QgsMapToPixel & mapToPixel() const
static QgsGeometry * prepareGeometry(const QgsGeometry *geometry, QgsRenderContext &context, const QgsCoordinateTransform *ct, QgsGeometry *clipGeometry=0)
Prepares a geometry for registration with PAL.
void writeToLayer(QgsVectorLayer *layer)
double y() const
Get the y value of the point.
Definition: qgspoint.h:134
void removeAllDataDefinedProperties()
Clear all data-defined properties.
void setAlphaF(qreal alpha)
bool isValid() const
virtual int prepareLayer(QgsVectorLayer *layer, QStringList &attrNames, QgsRenderContext &ctx) override
hook called when drawing layer before issuing select()
qreal height() const
int height() const
double toDouble(bool *ok) const
static QColor decodeColor(const QString &str)
double getX(int i=0) const
get the down-left x coordinate
double pictureBuffer() const
iterator insert(const Key &key, const T &value)
QPainter::CompositionMode shadowBlendMode
static void drawLabelCandidateRect(pal::LabelPosition *lp, QPainter *painter, const QgsMapToPixel *xform, QList< QgsLabelCandidate > *candidates=0)
bool isExpression
Is this label made from a expression string eg FieldName || 'mm'.
virtual Q_DECL_DEPRECATED QList< QgsLabelPosition > labelsAtPosition(const QgsPoint &p) override
return infos about labels at a given (map) position
void setSize(const QgsPoint &point)
Class that stores computed placement from labeling engine.
bool isShowingAllLabels() const
void setShowingAllLabels(bool showing)
static QgsMapRenderer::BlendMode getBlendModeEnum(const QPainter::CompositionMode &blendMode)
Returns a BlendMode corresponding to a QPainter::CompositionMode.
virtual QString type() const =0
Unique type string of the labeling configuration implementation.
bool isEmpty() const
Custom exception class for Coordinate Reference System related exceptions.
void drawPicture(const QPointF &point, const QPicture &picture)
bool isShowingShadowRectangles() const
QgsMapUnitScale shapeOffsetMapUnitScale
Labeling engine interface.
QgsVectorDataProvider * dataProvider()
Returns the data provider.
void setPictureBuffer(const double buffer)
const_iterator constEnd() const
QDomElement createElement(const QString &tagName)
Q_DECL_DEPRECATED const QList< QgsLabelCandidate > & candidates()
bool strikeOut() const
const_iterator constBegin() const
bool labelsEnabled() const
Returns whether the layer contains labels which are enabled and should be drawn.
void labelsInRect(const QgsRectangle &r, QList< QgsLabelPosition * > &posList) const
Returns label position(s) in given rectangle.
bool isDrawingOutlineLabels() const
void setScale(double scale)
static bool checkMinimumSizeMM(const QgsRenderContext &context, const QgsGeometry *geom, double minSize)
Checks whether a geometry exceeds the minimum required size for a geometry to be labeled.
Represents a vector layer which manages a vector based data sets.
bool begin(QPaintDevice *device)
double minScale
The minimum scale, or 0.0 if unset.
int compare(const QString &other) const
void setDrawLabelRectOnly(bool drawRect)
Sets whether the engine should only draw the outline rectangles of labels, not the label contents the...
bool isGeosValid() const
Checks validity of the geometry using GEOS.
QFont font(const QString &family, const QString &style, int pointSize) const
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for the context.
QString parserErrorString() const
Returns parser error.
void setLetterSpacing(SpacingType type, qreal spacing)
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
void setFlag(Flag f, bool enabled=true)
Set whether a particual flag is enabled.
QString toString() const
Whether to render labels as text or outlines.
QgsPoint center() const
Center point of the rectangle.
Definition: qgsrectangle.h:216
QString evalErrorString() const
Returns evaluation error.
void setExpressionString(const QString &expr)
Sets the expression for this QgsDataDefined.
QString exportToWkt(const int &precision=17) const
Exports the geometry to WKT.
bool isActive() const
iterator find(const Key &key)
QgsLabelingResults * takeResults()
Return pointer to recently computed results and pass the ownership of results to the caller...
void calculateLabelSize(const QFontMetricsF *fm, QString text, double &labelX, double &labelY, QgsFeature *f=0, QgsRenderContext *context=0)
static void blurImageInPlace(QImage &image, const QRect &rect, int radius, bool alphaOnly)
Blurs an image in place, e.g.
Maintains current state of more grainular and temporal values when creating/painting component parts ...
static bool fontFamilyMatchOnSystem(const QString &family, QString *chosen=0, bool *match=0)
Check whether font family is on system.
virtual void registerFeature(const QString &layerID, QgsFeature &feat, QgsRenderContext &context, const QString &dxfLayer=QString::null) override
Register a feature for labelling.
RotationType shapeRotationType
double area() const
Returns the area of the geometry using GEOS.
virtual QgsVectorLayerLabelProvider * provider(QgsVectorLayer *layer) const =0
Factory for label provider implementation.
int pointSize() const
QgsMapUnitScale labelOffsetMapUnitScale
void renderPoint(const QPointF &point, QgsSymbolV2RenderContext &context) override
void numCandidatePositions(int &candPoint, int &candLine, int &candPolygon)
Get number of candidate positions that will be generated for each label feature (default to 8) ...
virtual void exit() override
called when we're done with rendering
qreal height() const
qreal wordSpacing() const
void moveTo(qreal x, qreal y)
const T value(const Key &key) const
uint toUInt(bool *ok, int base) const
int remove(const Key &key)
ObstacleType
Valid obstacle types, which affect how features within the layer will act as obstacles for labels...
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)
QgsLabelingEngineV2 * mEngine
New labeling engine to interface with PAL.