QGIS API Documentation  2.7.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
qgslabel.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgslabel.cpp - render vector labels
3  -------------------
4  begin : August 2004
5  copyright : (C) 2004 by Radim Blazek
6  email : blazek@itc.it
7  ***************************************************************************/
8 /***************************************************************************
9  * *
10  * This program is free software; you can redistribute it and/or modify *
11  * it under the terms of the GNU General Public License as published by *
12  * the Free Software Foundation; either version 2 of the License, or *
13  * (at your option) any later version. *
14  * *
15  ***************************************************************************/
16 
17 #include <cmath>
18 #include <limits>
19 
20 #include <QString>
21 #include <QFont>
22 #include <QFontMetrics>
23 
24 #include <QPainter>
25 #include <QDomNode>
26 #include <QDomElement>
27 
28 #include "qgis.h"
29 #include "qgsfeature.h"
30 #include "qgsgeometry.h"
31 #include "qgsfield.h"
32 #include "qgslogger.h"
33 #include "qgsrectangle.h"
34 #include "qgsmaptopixel.h"
35 #include "qgscoordinatetransform.h"
36 #include "qgsrendercontext.h"
37 
38 #include "qgslabelattributes.h"
39 #include "qgslabel.h"
40 
41 // use M_PI define PI 3.141592654
42 #ifdef WIN32
43 #undef M_PI
44 #define M_PI 4*atan(1.0)
45 #endif
46 
47 QgsLabel::QgsLabel( const QgsFields & fields )
48  : mMinScale( 0 ),
49  mMaxScale( 100000000 ),
50  mScaleBasedVisibility( false )
51 {
52  mFields = fields;
53  mLabelFieldIdx.resize( LabelFieldCount );
54  for ( int i = 0; i < LabelFieldCount; i++ )
55  {
56  mLabelFieldIdx[i] = -1;
57  }
58  mLabelAttributes = new QgsLabelAttributes( true );
59 }
60 
62 {
63  delete mLabelAttributes;
64 }
65 
66 QString QgsLabel::fieldValue( int attr, QgsFeature &feature )
67 {
68  int idx = mLabelFieldIdx[attr];
69  return idx < 0 ? QString() : feature.attribute( idx ).toString();
70 }
71 
73  QgsFeature &feature, bool selected,
74  QgsLabelAttributes *classAttributes )
75 {
76  Q_UNUSED( classAttributes );
77 
78  if ( mLabelAttributes->selectedOnly() && !selected )
79  return;
80 
81  QPen pen;
82  QFont font;
83  QString value;
84  QString text;
85 
86  /* Calc scale (not nice) */
87  QgsPoint point;
88  point = renderContext.mapToPixel().transform( 0, 0 );
89  double x1 = point.x();
90  point = renderContext.mapToPixel().transform( 1000, 0 );
91  double x2 = point.x();
92  double scale = ( x2 - x1 ) * 0.001;
93 
94  /* Text */
95  value = fieldValue( Text, feature );
96  if ( value.isEmpty() )
97  {
98  text = mLabelAttributes->text();
99  }
100  else
101  {
102  text = value;
103  }
104 
105  /* Font */
106  value = fieldValue( Family, feature );
107  if ( value.isEmpty() )
108  {
109  font.setFamily( mLabelAttributes->family() );
110  }
111  else
112  {
113  font.setFamily( value );
114  }
115 
116  double size;
117  value = fieldValue( Size, feature );
118  if ( value.isEmpty() )
119  {
120  size = mLabelAttributes->size();
121  }
122  else
123  {
124  size = value.toDouble();
125  }
126  int sizeType;
127  value = fieldValue( SizeType, feature );
128  if ( value.isEmpty() )
129  sizeType = mLabelAttributes->sizeType();
130  else
131  {
132  value = value.toLower();
133  if ( value.compare( "mapunits" ) == 0 )
134  sizeType = QgsLabelAttributes::MapUnits;
135  else
137  }
138  if ( sizeType == QgsLabelAttributes::MapUnits )
139  {
140  size *= scale;
141  }
142  else //point units
143  {
144  double sizeMM = size * 0.3527;
145  size = sizeMM * renderContext.scaleFactor();
146  }
147 
148  //Request font larger (multiplied by rasterScaleFactor) as a workaround for the Qt font bug
149  //and scale the painter down by rasterScaleFactor when drawing the label
150  size *= renderContext.rasterScaleFactor();
151 
152  if (( int )size <= 0 )
153  // skip too small labels
154  return;
155 
156  font.setPixelSize( size );
157 
158  value = fieldValue( Color, feature );
159  if ( value.isEmpty() )
160  {
161  pen.setColor( mLabelAttributes->color() );
162  }
163  else
164  {
165  pen.setColor( QColor( value ) );
166  }
167 
168  value = fieldValue( Bold, feature );
169  if ( value.isEmpty() )
170  {
171  font.setBold( mLabelAttributes->bold() );
172  }
173  else
174  {
175  font.setBold(( bool ) value.toInt() );
176  }
177 
178  value = fieldValue( Italic, feature );
179  if ( value.isEmpty() )
180  {
181  font.setItalic( mLabelAttributes->italic() );
182  }
183  else
184  {
185  font.setItalic(( bool ) value.toInt() );
186  }
187 
188  value = fieldValue( Underline, feature );
189  if ( value.isEmpty() )
190  {
191  font.setUnderline( mLabelAttributes->underline() );
192  }
193  else
194  {
195  font.setUnderline(( bool ) value.toInt() );
196  }
197 
198  value = fieldValue( StrikeOut, feature );
199  if ( value.isEmpty() )
200  {
201  font.setStrikeOut( mLabelAttributes->strikeOut() );
202  }
203  else
204  {
205  font.setStrikeOut(( bool ) value.toInt() );
206  }
207 
208  //
209  QgsPoint overridePoint;
210  bool useOverridePoint = false;
211  value = fieldValue( XCoordinate, feature );
212  if ( !value.isEmpty() )
213  {
214  overridePoint.setX( value.toDouble() );
215  useOverridePoint = true;
216  }
217  value = fieldValue( YCoordinate, feature );
218  if ( !value.isEmpty() )
219  {
220  overridePoint.setY( value.toDouble() );
221  useOverridePoint = true;
222  }
223 
224  /* Alignment */
225  int alignment;
226  QFontMetrics fm( font );
227  int width, height;
228 
229  if ( mLabelAttributes->multilineEnabled() )
230  {
231  QStringList texts = text.split( "\n" );
232 
233  width = 0;
234  for ( int i = 0; i < texts.size(); i++ )
235  {
236  int w = fm.width( texts[i] );
237  if ( w > width )
238  width = w;
239  }
240 
241  height = fm.height() * texts.size();
242  }
243  else
244  {
245  width = fm.width( text );
246  height = fm.height();
247  }
248 
249  int dx = 0;
250  int dy = 0;
251 
252  value = fieldValue( Alignment, feature );
253  if ( value.isEmpty() )
254  {
255  alignment = mLabelAttributes->alignment();
256  }
257  else
258  {
259  value = value.toLower();
260 
261  alignment = 0;
262 
263  if ( value.contains( "left" ) )
264  alignment |= Qt::AlignLeft;
265  else if ( value.contains( "right" ) )
266  alignment |= Qt::AlignRight;
267  else
268  alignment |= Qt::AlignHCenter;
269 
270  if ( value.contains( "bottom" ) )
271  alignment |= Qt::AlignBottom;
272  else if ( value.contains( "top" ) )
273  alignment |= Qt::AlignTop;
274  else
275  alignment |= Qt::AlignVCenter;
276  }
277 
278  if ( alignment & Qt::AlignLeft )
279  {
280  dx = 0;
281  }
282  else if ( alignment & Qt::AlignHCenter )
283  {
284  dx = -width / 2;
285  }
286  else if ( alignment & Qt::AlignRight )
287  {
288  dx = -width;
289  }
290 
291  if ( alignment & Qt::AlignBottom )
292  {
293  dy = 0;
294  }
295  else if ( alignment & Qt::AlignVCenter )
296  {
297  dy = height / 2;
298  }
299  else if ( alignment & Qt::AlignTop )
300  {
301  dy = height;
302  }
303 
304  // Offset
305  double xoffset, yoffset;
306  value = fieldValue( XOffset, feature );
307  if ( value.isEmpty() )
308  {
309  xoffset = mLabelAttributes->xOffset();
310  }
311  else
312  {
313  xoffset = value.toDouble();
314  }
315  value = fieldValue( YOffset, feature );
316  if ( value.isEmpty() )
317  {
318  yoffset = mLabelAttributes->yOffset();
319  }
320  else
321  {
322  yoffset = value.toDouble();
323  }
324 
325  // recalc offset to pixels
326  if ( mLabelAttributes->offsetType() == QgsLabelAttributes::MapUnits )
327  {
328  xoffset *= scale;
329  yoffset *= scale;
330  }
331  else
332  {
333  xoffset = xoffset * 0.3527 * renderContext.scaleFactor();
334  yoffset = yoffset * 0.3527 * renderContext.scaleFactor();
335  }
336 
337  // Angle
338  double ang;
339  value = fieldValue( Angle, feature );
340  if ( value.isEmpty() )
341  {
342  ang = mLabelAttributes->angle();
343  }
344  else
345  {
346  ang = value.toDouble();
347  }
348 
349 
350  // Work out a suitable position to put the label for the
351  // feature. For multi-geometries, put the same label on each
352  // part.
353  if ( useOverridePoint )
354  {
355  renderLabel( renderContext, overridePoint, text, font, pen, dx, dy,
356  xoffset, yoffset, ang, width, height, alignment );
357  }
358  else
359  {
360  std::vector<labelpoint> points;
361  labelPoint( points, feature );
362  for ( uint i = 0; i < points.size(); ++i )
363  {
364  renderLabel( renderContext, points[i].p, text, font, pen, dx, dy,
365  xoffset, yoffset, mLabelAttributes->angleIsAuto() ? points[i].angle : ang, width, height, alignment );
366  }
367  }
368 }
369 
370 void QgsLabel::renderLabel( QgsRenderContext &renderContext,
371  QgsPoint point,
372  QString text, QFont font, QPen pen,
373  int dx, int dy,
374  double xoffset, double yoffset,
375  double ang,
376  int width, int height, int alignment )
377 {
378  QPainter *painter = renderContext.painter();
379 
380  // Convert point to projected units
381  if ( renderContext.coordinateTransform() )
382  {
383  try
384  {
385  point = renderContext.coordinateTransform()->transform( point );
386  }
387  catch ( QgsCsException &cse )
388  {
389  Q_UNUSED( cse ); // unused otherwise
390  QgsDebugMsg( "Caught transform error. Skipping rendering this label" );
391  return;
392  }
393  }
394 
395  // and then to canvas units
396  renderContext.mapToPixel().transform( &point );
397  double x = point.x();
398  double y = point.y();
399 
400  double rad = ang * M_PI / 180;
401 
402  x = x + xoffset * cos( rad ) - yoffset * sin( rad );
403  y = y - xoffset * sin( rad ) - yoffset * cos( rad );
404 
405  painter->save();
406  painter->setFont( font );
407  painter->translate( x, y );
408  //correct oversampled font size back by scaling painter down
409  painter->scale( 1.0 / renderContext.rasterScaleFactor(), 1.0 / renderContext.rasterScaleFactor() );
410  painter->rotate( -ang );
411 
412  //
413  // Draw a buffer behind the text if one is desired
414  //
415  if ( mLabelAttributes->bufferSizeIsSet() && mLabelAttributes->bufferEnabled() )
416  {
417  double myBufferSize = mLabelAttributes->bufferSize() * 0.3527 * renderContext.scaleFactor() * renderContext.rasterScaleFactor();
418  QPen bufferPen;
419  if ( mLabelAttributes->bufferColorIsSet() )
420  {
421  bufferPen.setColor( mLabelAttributes->bufferColor() );
422  }
423  else //default to a white buffer
424  {
425  bufferPen.setColor( Qt::white );
426  }
427  painter->setPen( bufferPen );
428 
429  double bufferStepSize; //hack to distinguish pixel devices from logical devices
430  if (( renderContext.scaleFactor() - 1 ) > 1.5 )
431  {
432  bufferStepSize = 1;
433  }
434  else //draw more dense in case of logical devices
435  {
436  bufferStepSize = 1 / renderContext.rasterScaleFactor();
437  }
438 
439  for ( double i = dx - myBufferSize; i <= dx + myBufferSize; i += bufferStepSize )
440  {
441  for ( double j = dy - myBufferSize; j <= dy + myBufferSize; j += bufferStepSize )
442  {
443  if ( mLabelAttributes->multilineEnabled() )
444  painter->drawText( QRectF( i, j - height, width, height ), alignment, text );
445  else
446  painter->drawText( QPointF( i, j ), text );
447  }
448  }
449  }
450 
451  painter->setPen( pen );
452  if ( mLabelAttributes->multilineEnabled() )
453  painter->drawText( dx, dy - height, width, height, alignment, text );
454  else
455  painter->drawText( dx, dy, text );
456  painter->restore();
457 }
458 
460 {
461  for ( uint i = 0; i < LabelFieldCount; i++ )
462  {
463  if ( mLabelFieldIdx[i] == -1 )
464  continue;
465  bool found = false;
466  for ( QgsAttributeList::iterator it = fields.begin(); it != fields.end(); ++it )
467  {
468  if ( *it == mLabelFieldIdx[i] )
469  {
470  found = true;
471  break;
472  }
473  }
474  if ( !found )
475  {
476  fields.append( mLabelFieldIdx[i] );
477  }
478  }
479 }
480 
481 void QgsLabel::setFields( const QgsFields & fields )
482 {
483  mFields = fields;
484 }
485 
487 {
488  return mFields;
489 }
490 
491 void QgsLabel::setLabelField( int attr, int fieldIndex )
492 {
493  if ( attr >= LabelFieldCount )
494  return;
495 
496  mLabelFieldIdx[attr] = fieldIndex;
497 }
498 
499 QString QgsLabel::labelField( int attr ) const
500 {
501  if ( attr >= LabelFieldCount )
502  return QString();
503 
504  int fieldIndex = mLabelFieldIdx[attr];
505  if ( fieldIndex < 0 || fieldIndex >= mFields.count() )
506  return QString();
507  return mFields[fieldIndex].name();
508 }
509 
511 {
512  return mLabelAttributes;
513 }
514 
515 void QgsLabel::labelPoint( std::vector<labelpoint>& points, QgsFeature & feature )
516 {
517  QgsGeometry *geometry = feature.geometry();
518  const unsigned char *geom = geometry->asWkb();
519  size_t geomlen = geometry->wkbSize();
520  QGis::WkbType wkbType = geometry->wkbType();
521  labelpoint point;
522 
523  switch ( wkbType )
524  {
525  case QGis::WKBPoint25D:
526  case QGis::WKBPoint:
528  case QGis::WKBLineString:
529  case QGis::WKBPolygon25D:
530  case QGis::WKBPolygon:
531  {
532  labelPoint( point, geom, geomlen );
533  points.push_back( point );
534  }
535  break;
536 
538  case QGis::WKBMultiPoint:
543  // Return a position for each individual in the multi-feature
544  {
545  Q_ASSERT( 1 + sizeof( wkbType ) + sizeof( int ) <= geomlen );
546  geom += 1 + sizeof( wkbType );
547  int nFeatures = *( unsigned int * )geom;
548  geom += sizeof( int );
549 
550  const unsigned char *feature = geom;
551  for ( int i = 0; i < nFeatures && feature; ++i )
552  {
553  feature = labelPoint( point, feature, geom + geomlen - feature );
554  points.push_back( point );
555  }
556  }
557  break;
558  default:
559  QgsDebugMsg( "Unknown geometry type of " + QString::number( wkbType ) );
560  }
561 }
562 
563 const unsigned char* QgsLabel::labelPoint( labelpoint& point, const unsigned char *geom, size_t geomlen )
564 {
565  // verify that local types match sizes as WKB spec
566  Q_ASSERT( sizeof( int ) == 4 );
567  Q_ASSERT( sizeof( QGis::WkbType ) == 4 );
568  Q_ASSERT( sizeof( double ) == 8 );
569 
570  if ( geom == NULL )
571  {
572  QgsDebugMsg( "empty wkb" );
573  return NULL;
574  }
575 
576  QGis::WkbType wkbType;
577 #ifndef QT_NO_DEBUG
578  const unsigned char *geomend = geom + geomlen;
579 #else
580  Q_UNUSED( geomlen );
581 #endif
582  Q_ASSERT( geom + 1 + sizeof( wkbType ) <= geomend );
583 
584  geom++; // skip endianness
585  memcpy( &wkbType, geom, sizeof( wkbType ) );
586  geom += sizeof( wkbType );
587 
588  int dims = 2;
589 
590  switch ( wkbType )
591  {
592  case QGis::WKBPoint25D:
593  case QGis::WKBPoint:
594  {
595  Q_ASSERT( geom + 2*sizeof( double ) <= geomend );
596  double *pts = ( double * )geom;
597  point.p.set( pts[0], pts[1] );
598  point.angle = 0.0;
599  geom += 2 * sizeof( double );
600  }
601  break;
602 
604  dims = 3;
605  case QGis::WKBLineString: // Line center
606  {
607  Q_ASSERT( geom + sizeof( int ) <= geomend );
608  int nPoints = *( unsigned int * )geom;
609  geom += sizeof( int );
610 
611  Q_ASSERT( geom + nPoints*sizeof( double )*dims <= geomend );
612 
613  // get line center
614  double *pts = ( double * )geom;
615  double tl = 0.0;
616  for ( int i = 1; i < nPoints; i++ )
617  {
618  double dx = pts[dims*i] - pts[dims*( i-1 )];
619  double dy = pts[dims*i+1] - pts[dims*( i-1 )+1];
620  tl += sqrt( dx * dx + dy * dy );
621  }
622  tl /= 2.0;
623 
624  // find line center
625  double l = 0.0;
626  for ( int i = 1; i < nPoints; i++ )
627  {
628  double dx = pts[dims*i] - pts[dims*( i-1 )];
629  double dy = pts[dims*i+1] - pts[dims*( i-1 )+1];
630  double dl = sqrt( dx * dx + dy * dy );
631 
632  if ( l + dl > tl )
633  {
634  double k = ( tl - l ) / dl;
635 
636  point.p.set( pts[dims*( i-1 )] + k * dx,
637  pts[dims*( i-1 )+1] + k * dy );
638  point.angle = atan2( dy, dx ) * 180.0 * M_1_PI;
639  break;
640  }
641 
642  l += dl;
643  }
644 
645  geom += nPoints * sizeof( double ) * dims;
646  }
647  break;
648 
649  case QGis::WKBPolygon25D:
650  dims = 3;
651  case QGis::WKBPolygon: // centroid of outer ring
652  {
653  Q_ASSERT( geom + sizeof( int ) <= geomend );
654  int nRings = *( unsigned int * )geom;
655  geom += sizeof( int );
656 
657  for ( int i = 0; i < nRings; ++i )
658  {
659  Q_ASSERT( geom + sizeof( int ) <= geomend );
660  int nPoints = *( unsigned int * )geom;
661  geom += sizeof( int );
662 
663  Q_ASSERT( geom + nPoints*sizeof( double )*dims <= geomend );
664 
665  if ( i == 0 )
666  {
667  double sx = 0.0, sy = 0.0;
668  double *pts = ( double* ) geom;
669  for ( int j = 0; j < nPoints - 1; j++ )
670  {
671  sx += pts[dims*j];
672  sy += pts[dims*j+1];
673  }
674  point.p.set( sx / ( nPoints - 1 ),
675  sy / ( nPoints - 1 ) );
676  point.angle = 0.0;
677  }
678 
679  geom += nPoints * sizeof( double ) * dims;
680  }
681  }
682  break;
683 
684  default:
685  // To get here is a bug because our caller should be filtering
686  // on wkb type.
687  QgsDebugMsg( "unsupported wkb type" );
688  return NULL;
689  }
690 
691  return geom;
692 }
693 
694 bool QgsLabel::readLabelField( QDomElement &el, int attr, QString prefix = "field" )
695 {
696  QString name = prefix + "name";
697 
698  if ( el.hasAttribute( name ) )
699  {
700  name = el.attribute( name );
701 
702  int idx = 0;
703  for ( ; idx < mFields.count(); ++idx )
704  {
705  if ( mFields[idx].name() == name )
706  {
707  break;
708  }
709  }
710 
711  if ( idx != mFields.count() )
712  {
713  mLabelFieldIdx[attr] = idx;
714  return true;
715  }
716  }
717  else if ( el.hasAttribute( prefix ) )
718  {
719  QString value = el.attribute( prefix );
720  mLabelFieldIdx[attr] = value.isEmpty() ? -1 : value.toInt();
721  return true;
722  }
723 
724  mLabelFieldIdx[attr] = -1;
725  return false;
726 }
727 
728 
729 void QgsLabel::readXML( const QDomNode& node )
730 {
731  QgsDebugMsg( " called for layer label properties, got node " + node.nodeName() );
732 
733  QDomNode scratchNode; // Dom node re-used to get current QgsLabel attribute
734  QDomElement el;
735 
736  int red, green, blue;
737  int type;
738 
739  /* Text */
740  scratchNode = node.namedItem( "label" );
741 
742  if ( scratchNode.isNull() )
743  {
744  QgsDebugMsg( "couldn't find QgsLabel ``label'' attribute" );
745  }
746  else
747  {
748  el = scratchNode.toElement();
749  mLabelAttributes->setText( el.attribute( "text", "" ) );
750  readLabelField( el, Text );
751  }
752 
753  /* Family */
754  scratchNode = node.namedItem( "family" );
755 
756  if ( scratchNode.isNull() )
757  {
758  QgsDebugMsg( "couldn't find QgsLabel ``family'' attribute" );
759  }
760  else
761  {
762  el = scratchNode.toElement();
763  mLabelAttributes->setFamily( el.attribute( "name", "" ) );
764  readLabelField( el, Family );
765  }
766 
767  /* Size */
768  scratchNode = node.namedItem( "size" );
769 
770  if ( scratchNode.isNull() )
771  {
772  QgsDebugMsg( "couldn't find QgsLabel ``size'' attribute" );
773  }
774  else
775  {
776  el = scratchNode.toElement();
777  if ( !el.hasAttribute( "unitfield" ) && !el.hasAttribute( "unitfieldname" ) )
778  {
779  type = QgsLabelAttributes::unitsCode( el.attribute( "units", "" ) );
780  mLabelAttributes->setSize( el.attribute( "value", "0.0" ).toDouble(), type );
781  }
782  else
783  {
784  readLabelField( el, SizeType, "unitfield" );
785  }
786  readLabelField( el, Size );
787  }
788 
789  /* Bold */
790  scratchNode = node.namedItem( "bold" );
791 
792  if ( scratchNode.isNull() )
793  {
794  QgsDebugMsg( "couldn't find QgsLabel ``bold'' attribute" );
795  }
796  else
797  {
798  el = scratchNode.toElement();
799  mLabelAttributes->setBold(( bool )el.attribute( "on", "0" ).toInt() );
800  readLabelField( el, Bold );
801  }
802 
803  /* Italic */
804  scratchNode = node.namedItem( "italic" );
805 
806  if ( scratchNode.isNull() )
807  {
808  QgsDebugMsg( "couldn't find QgsLabel ``italic'' attribute" );
809  }
810  else
811  {
812  el = scratchNode.toElement();
813  mLabelAttributes->setItalic(( bool )el.attribute( "on", "0" ).toInt() );
814  readLabelField( el, Italic );
815  }
816 
817  /* Underline */
818  scratchNode = node.namedItem( "underline" );
819 
820  if ( scratchNode.isNull() )
821  {
822  QgsDebugMsg( "couldn't find QgsLabel ``underline'' attribute" );
823  }
824  else
825  {
826  el = scratchNode.toElement();
827  mLabelAttributes->setUnderline(( bool )el.attribute( "on", "0" ).toInt() );
828  readLabelField( el, Underline );
829  }
830 
831  /* Strikeout */
832  scratchNode = node.namedItem( "strikeout" );
833 
834  if ( scratchNode.isNull() )
835  {
836  QgsDebugMsg( "couldn't find QgsLabel ``strikeout'' attribute" );
837  }
838  else
839  {
840  el = scratchNode.toElement();
841  mLabelAttributes->setStrikeOut(( bool )el.attribute( "on", "0" ).toInt() );
842  readLabelField( el, StrikeOut );
843  }
844 
845  /* Color */
846  scratchNode = node.namedItem( "color" );
847 
848  if ( scratchNode.isNull() )
849  {
850  QgsDebugMsg( "couldn't find QgsLabel ``color'' attribute" );
851  }
852  else
853  {
854  el = scratchNode.toElement();
855 
856  red = el.attribute( "red", "0" ).toInt();
857  green = el.attribute( "green", "0" ).toInt();
858  blue = el.attribute( "blue", "0" ).toInt();
859 
860  mLabelAttributes->setColor( QColor( red, green, blue ) );
861 
862  readLabelField( el, Color );
863  }
864 
865  /* X */
866  scratchNode = node.namedItem( "x" );
867 
868  if ( scratchNode.isNull() )
869  {
870  QgsDebugMsg( "couldn't find QgsLabel ``x'' attribute" );
871  }
872  else
873  {
874  el = scratchNode.toElement();
875  readLabelField( el, XCoordinate );
876  }
877 
878  /* Y */
879  scratchNode = node.namedItem( "y" );
880 
881  if ( scratchNode.isNull() )
882  {
883  QgsDebugMsg( "couldn't find QgsLabel ``y'' attribute" );
884  }
885  else
886  {
887  el = scratchNode.toElement();
888  readLabelField( el, YCoordinate );
889  }
890 
891 
892  /* X,Y offset */
893  scratchNode = node.namedItem( "offset" );
894 
895  if ( scratchNode.isNull() )
896  {
897  QgsDebugMsg( "couldn't find QgsLabel ``offset'' attribute" );
898  }
899  else
900  {
901  double xoffset, yoffset;
902 
903  el = scratchNode.toElement();
904 
905  type = QgsLabelAttributes::unitsCode( el.attribute( "units", "" ) );
906  xoffset = el.attribute( "x", "0.0" ).toDouble();
907  yoffset = el.attribute( "y", "0.0" ).toDouble();
908 
909  mLabelAttributes->setOffset( xoffset, yoffset, type );
910  readLabelField( el, XOffset, "xfield" );
911  readLabelField( el, YOffset, "yfield" );
912  }
913 
914  /* Angle */
915  scratchNode = node.namedItem( "angle" );
916 
917  if ( scratchNode.isNull() )
918  {
919  QgsDebugMsg( "couldn't find QgsLabel ``angle'' attribute" );
920  }
921  else
922  {
923  el = scratchNode.toElement();
924  mLabelAttributes->setAngle( el.attribute( "value", "0.0" ).toDouble() );
925  readLabelField( el, Angle );
926  mLabelAttributes->setAutoAngle( el.attribute( "auto", "0" ) == "1" );
927  }
928 
929  /* Alignment */
930  scratchNode = node.namedItem( "alignment" );
931 
932  if ( scratchNode.isNull() )
933  {
934  QgsDebugMsg( "couldn't find QgsLabel ``alignment'' attribute" );
935  }
936  else
937  {
938  el = scratchNode.toElement();
939  mLabelAttributes->setAlignment( QgsLabelAttributes::alignmentCode( el.attribute( "value", "" ) ) );
940  readLabelField( el, Alignment );
941  }
942 
943 
944  // Buffer
945  scratchNode = node.namedItem( "buffercolor" );
946 
947  if ( scratchNode.isNull() )
948  {
949  QgsDebugMsg( "couldn't find QgsLabel ``buffercolor'' attribute" );
950  }
951  else
952  {
953  el = scratchNode.toElement();
954 
955  red = el.attribute( "red", "0" ).toInt();
956  green = el.attribute( "green", "0" ).toInt();
957  blue = el.attribute( "blue", "0" ).toInt();
958 
959  mLabelAttributes->setBufferColor( QColor( red, green, blue ) );
960  readLabelField( el, BufferColor );
961  }
962 
963  scratchNode = node.namedItem( "buffersize" );
964 
965  if ( scratchNode.isNull() )
966  {
967  QgsDebugMsg( "couldn't find QgsLabel ``bffersize'' attribute" );
968  }
969  else
970  {
971  el = scratchNode.toElement();
972 
973  type = QgsLabelAttributes::unitsCode( el.attribute( "units", "" ) );
974  mLabelAttributes->setBufferSize( el.attribute( "value", "0.0" ).toDouble(), type );
975  readLabelField( el, BufferSize );
976  }
977 
978  scratchNode = node.namedItem( "bufferenabled" );
979 
980  if ( scratchNode.isNull() )
981  {
982  QgsDebugMsg( "couldn't find QgsLabel ``bufferenabled'' attribute" );
983  }
984  else
985  {
986  el = scratchNode.toElement();
987 
988  mLabelAttributes->setBufferEnabled(( bool )el.attribute( "on", "0" ).toInt() );
989  readLabelField( el, BufferEnabled );
990  }
991 
992  scratchNode = node.namedItem( "multilineenabled" );
993 
994  if ( scratchNode.isNull() )
995  {
996  QgsDebugMsg( "couldn't find QgsLabel ``multilineenabled'' attribute" );
997  }
998  else
999  {
1000  el = scratchNode.toElement();
1001 
1002  mLabelAttributes->setMultilineEnabled(( bool )el.attribute( "on", "0" ).toInt() );
1003  readLabelField( el, MultilineEnabled );
1004  }
1005 
1006  scratchNode = node.namedItem( "selectedonly" );
1007 
1008  if ( scratchNode.isNull() )
1009  {
1010  QgsDebugMsg( "couldn't find QgsLabel ``selectedonly'' attribute" );
1011  }
1012  else
1013  {
1014  el = scratchNode.toElement();
1015  mLabelAttributes->setSelectedOnly(( bool )el.attribute( "on", "0" ).toInt() );
1016  }
1017 
1018 } // QgsLabel::readXML()
1019 
1020 
1021 
1022 void QgsLabel::writeXML( QDomNode & layer_node, QDomDocument & document ) const
1023 {
1024  QDomElement labelattributes = document.createElement( "labelattributes" );
1025 
1026  // Text
1027  QDomElement label = document.createElement( "label" );
1028  label.setAttribute( "text", mLabelAttributes->text() );
1029  if ( mLabelAttributes->textIsSet() && mLabelFieldIdx[Text] != -1 )
1030  {
1031  label.setAttribute( "fieldname", labelField( Text ) );
1032  }
1033  else
1034  {
1035  label.setAttribute( "fieldname", "" );
1036  }
1037  labelattributes.appendChild( label );
1038 
1039  // Family
1040  QDomElement family = document.createElement( "family" );
1041  if ( mLabelAttributes->familyIsSet() && !mLabelAttributes->family().isNull() )
1042  {
1043  if ( mLabelFieldIdx[Family] != -1 )
1044  {
1045  family.setAttribute( "name", mLabelAttributes->family() );
1046  family.setAttribute( "fieldname", labelField( Family ) );
1047  }
1048  else
1049  {
1050  family.setAttribute( "name", mLabelAttributes->family() );
1051  family.setAttribute( "fieldname", "" );
1052  }
1053  }
1054  else
1055  {
1056  family.setAttribute( "name", "Arial" );
1057  family.setAttribute( "fieldname", "" );
1058  }
1059  labelattributes.appendChild( family );
1060 
1061  // size and units
1062  QDomElement size = document.createElement( "size" );
1063  size.setAttribute( "value", QString::number( mLabelAttributes->size() ) );
1064  if ( mLabelAttributes->sizeIsSet() )
1065  {
1066  if ( mLabelFieldIdx[Size] != -1 )
1067  {
1068  if ( mLabelFieldIdx[SizeType] != -1 )
1069  {
1070  size.setAttribute( "unitfieldname", labelField( SizeType ) );
1071  }
1072  else
1073  {
1074  size.setAttribute( "units", QgsLabelAttributes::unitsName( mLabelAttributes->sizeType() ) );
1075  }
1076  size.setAttribute( "fieldname", labelField( Size ) );
1077  }
1078  else
1079  {
1080  size.setAttribute( "units", QgsLabelAttributes::unitsName( mLabelAttributes->sizeType() ) );
1081  size.setAttribute( "fieldname", "" );
1082  }
1083  }
1084  else
1085  {
1086  size.setAttribute( "value", "12" );
1087  size.setAttribute( "units", "Points" );
1088  size.setAttribute( "fieldname", "" );
1089  }
1090  labelattributes.appendChild( size );
1091 
1092  // bold
1093  QDomElement bold = document.createElement( "bold" );
1094  if ( mLabelAttributes->boldIsSet() )
1095  {
1096  bold.setAttribute( "on", mLabelAttributes->bold() );
1097  if ( mLabelFieldIdx[Bold] != -1 )
1098  {
1099  bold.setAttribute( "fieldname", labelField( Bold ) );
1100  }
1101  else
1102  {
1103  bold.setAttribute( "fieldname", "" );
1104  }
1105  }
1106  else
1107  {
1108  bold.setAttribute( "on", 0 );
1109  bold.setAttribute( "fieldname", 0 );
1110  }
1111  labelattributes.appendChild( bold );
1112 
1113  // italics
1114  QDomElement italic = document.createElement( "italic" );
1115  if ( mLabelAttributes->italicIsSet() )
1116  {
1117  italic.setAttribute( "on", mLabelAttributes->italic() );
1118  if ( mLabelFieldIdx[Italic] != -1 )
1119  {
1120  italic.setAttribute( "fieldname", labelField( Italic ) );
1121  }
1122  else
1123  {
1124  italic.setAttribute( "fieldname", "" );
1125  }
1126  }
1127  else
1128  {
1129  italic.setAttribute( "on", "0" );
1130  italic.setAttribute( "fieldname", "" );
1131  }
1132  labelattributes.appendChild( italic );
1133 
1134  // underline
1135  QDomElement underline = document.createElement( "underline" );
1136  if ( mLabelAttributes->underlineIsSet() )
1137  {
1138  underline.setAttribute( "on", mLabelAttributes->underline() );
1139  if ( mLabelFieldIdx[Underline] != -1 )
1140  {
1141  underline.setAttribute( "fieldname", labelField( Underline ) );
1142  }
1143  else
1144  {
1145  underline.setAttribute( "fieldname", "" );
1146  }
1147  }
1148  else
1149  {
1150  underline.setAttribute( "on", 0 );
1151  underline.setAttribute( "fieldname", "" );
1152  }
1153  labelattributes.appendChild( underline );
1154 
1155  // strikeout
1156  QDomElement strikeOut = document.createElement( "strikeout" );
1157  if ( mLabelAttributes->strikeOutIsSet() )
1158  {
1159  strikeOut.setAttribute( "on", mLabelAttributes->strikeOut() );
1160  if ( mLabelFieldIdx[StrikeOut] != -1 )
1161  {
1162  strikeOut.setAttribute( "fieldname", labelField( StrikeOut ) );
1163  }
1164  else
1165  {
1166  strikeOut.setAttribute( "fieldname", "" );
1167  }
1168  }
1169  else
1170  {
1171  strikeOut.setAttribute( "on", 0 );
1172  strikeOut.setAttribute( "fieldname", "" );
1173  }
1174  labelattributes.appendChild( strikeOut );
1175 
1176  // color
1177  QDomElement color = document.createElement( "color" );
1178  if ( mLabelAttributes->colorIsSet() )
1179  {
1180  color.setAttribute( "red", mLabelAttributes->color().red() );
1181  color.setAttribute( "green", mLabelAttributes->color().green() );
1182  color.setAttribute( "blue", mLabelAttributes->color().blue() );
1183  if ( mLabelFieldIdx[Color] != -1 )
1184  {
1185  color.setAttribute( "fieldname", labelField( Color ) );
1186  }
1187  else
1188  {
1189  color.setAttribute( "fieldname", "" );
1190  }
1191  }
1192  else
1193  {
1194  color.setAttribute( "red", 0 );
1195  color.setAttribute( "green", 0 );
1196  color.setAttribute( "blue", 0 );
1197  color.setAttribute( "fieldname", "" );
1198  }
1199  labelattributes.appendChild( color );
1200 
1201  /* X */
1202  QDomElement x = document.createElement( "x" );
1203  if ( mLabelFieldIdx[XCoordinate] != -1 )
1204  {
1205  x.setAttribute( "fieldname", labelField( XCoordinate ) );
1206  }
1207  else
1208  {
1209  x.setAttribute( "fieldname", "" );
1210  }
1211  labelattributes.appendChild( x );
1212 
1213  /* Y */
1214  QDomElement y = document.createElement( "y" );
1215  if ( mLabelFieldIdx[YCoordinate] != -1 )
1216  {
1217  y.setAttribute( "fieldname", labelField( YCoordinate ) );
1218  }
1219  else
1220  {
1221  y.setAttribute( "fieldname", "" );
1222  }
1223  labelattributes.appendChild( y );
1224 
1225  // offset
1226  if ( mLabelAttributes->offsetIsSet() )
1227  {
1228  QDomElement offset = document.createElement( "offset" );
1229  offset.setAttribute( "units", QgsLabelAttributes::unitsName( mLabelAttributes->offsetType() ) );
1230  offset.setAttribute( "x", QString::number( mLabelAttributes->xOffset() ) );
1231  offset.setAttribute( "xfieldname", labelField( XOffset ) );
1232  offset.setAttribute( "y", QString::number( mLabelAttributes->yOffset() ) );
1233  offset.setAttribute( "yfieldname", labelField( YOffset ) );
1234  labelattributes.appendChild( offset );
1235  }
1236 
1237  // Angle
1238  QDomElement angle = document.createElement( "angle" );
1239  if ( mLabelAttributes->angleIsSet() )
1240  {
1241  angle.setAttribute( "value", QString::number( mLabelAttributes->angle() ) );
1242  if ( mLabelFieldIdx[Angle] != -1 )
1243  {
1244  angle.setAttribute( "fieldname", labelField( Angle ) );
1245  }
1246  else
1247  {
1248  angle.setAttribute( "fieldname", "" );
1249  }
1250  }
1251  else
1252  {
1253  angle.setAttribute( "value", "" );
1254  angle.setAttribute( "fieldname", "" );
1255  }
1256  angle.setAttribute( "auto", mLabelAttributes->angleIsAuto() ? "1" : "0" );
1257  labelattributes.appendChild( angle );
1258 
1259  // alignment
1260  if ( mLabelAttributes->alignmentIsSet() )
1261  {
1262  QDomElement alignment = document.createElement( "alignment" );
1263  alignment.setAttribute( "value", QgsLabelAttributes::alignmentName( mLabelAttributes->alignment() ) );
1264  alignment.setAttribute( "fieldname", labelField( Alignment ) );
1265  labelattributes.appendChild( alignment );
1266  }
1267 
1268  // buffer color
1269  QDomElement buffercolor = document.createElement( "buffercolor" );
1270  if ( mLabelAttributes->bufferColorIsSet() )
1271  {
1272  buffercolor.setAttribute( "red", mLabelAttributes->bufferColor().red() );
1273  buffercolor.setAttribute( "green", mLabelAttributes->bufferColor().green() );
1274  buffercolor.setAttribute( "blue", mLabelAttributes->bufferColor().blue() );
1275  if ( mLabelFieldIdx[BufferColor] != -1 )
1276  {
1277  buffercolor.setAttribute( "fieldname", labelField( BufferColor ) );
1278  }
1279  else
1280  {
1281  buffercolor.setAttribute( "fieldname", "" );
1282  }
1283  }
1284  else
1285  {
1286  buffercolor.setAttribute( "red", "" );
1287  buffercolor.setAttribute( "green", "" );
1288  buffercolor.setAttribute( "blue", "" );
1289  buffercolor.setAttribute( "fieldname", "" );
1290  }
1291  labelattributes.appendChild( buffercolor );
1292 
1293  // buffer size
1294  QDomElement buffersize = document.createElement( "buffersize" );
1295  if ( mLabelAttributes->bufferSizeIsSet() )
1296  {
1297  buffersize.setAttribute( "value", QString::number( mLabelAttributes->bufferSize() ) );
1298  buffersize.setAttribute( "units", QgsLabelAttributes::unitsName( mLabelAttributes->bufferSizeType() ) );
1299  if ( mLabelFieldIdx[BufferSize] != -1 )
1300  {
1301  buffersize.setAttribute( "fieldname", labelField( BufferSize ) );
1302  }
1303  else
1304  {
1305  buffersize.setAttribute( "fieldname", "" );
1306  }
1307  }
1308  else
1309  {
1310  buffersize.setAttribute( "value", "" );
1311  buffersize.setAttribute( "units", "" );
1312  buffersize.setAttribute( "fieldname", "" );
1313  }
1314  labelattributes.appendChild( buffersize );
1315 
1316  // buffer enabled
1317  QDomElement bufferenabled = document.createElement( "bufferenabled" );
1318  if ( mLabelAttributes->bufferEnabled() )
1319  {
1320  bufferenabled.setAttribute( "on", mLabelAttributes->bufferEnabled() );
1321  if ( mLabelFieldIdx[BufferEnabled] != -1 )
1322  {
1323  bufferenabled.setAttribute( "fieldname", labelField( BufferEnabled ) );
1324  }
1325  else
1326  {
1327  bufferenabled.setAttribute( "fieldname", "" );
1328  }
1329  }
1330  else
1331  {
1332  bufferenabled.setAttribute( "on", "" );
1333  bufferenabled.setAttribute( "fieldname", "" );
1334  }
1335  labelattributes.appendChild( bufferenabled );
1336 
1337  // multiline enabled
1338  QDomElement multilineenabled = document.createElement( "multilineenabled" );
1339  if ( mLabelAttributes->multilineEnabled() )
1340  {
1341  multilineenabled.setAttribute( "on", mLabelAttributes->multilineEnabled() );
1342  if ( mLabelFieldIdx[MultilineEnabled] != -1 )
1343  {
1344  multilineenabled.setAttribute( "fieldname", labelField( MultilineEnabled ) );
1345  }
1346  else
1347  {
1348  multilineenabled.setAttribute( "fieldname", "" );
1349  }
1350  }
1351  else
1352  {
1353  multilineenabled.setAttribute( "on", "" );
1354  multilineenabled.setAttribute( "fieldname", "" );
1355  }
1356  labelattributes.appendChild( multilineenabled );
1357 
1358  QDomElement selectedonly = document.createElement( "selectedonly" );
1359  if ( mLabelAttributes->selectedOnly() )
1360  {
1361  selectedonly.setAttribute( "on", mLabelAttributes->selectedOnly() );
1362  }
1363  else
1364  {
1365  selectedonly.setAttribute( "on", "" );
1366  }
1367  labelattributes.appendChild( selectedonly );
1368 
1369  layer_node.appendChild( labelattributes );
1370 }
1371 
1372 void QgsLabel::setScaleBasedVisibility( bool theVisibilityFlag )
1373 {
1374  mScaleBasedVisibility = theVisibilityFlag;
1375 }
1376 
1378 {
1379  return mScaleBasedVisibility;
1380 }
1381 
1382 void QgsLabel::setMinScale( float theMinScale )
1383 {
1384  mMinScale = theMinScale;
1385 }
1386 
1387 float QgsLabel::minScale() const
1388 {
1389  return mMinScale;
1390 }
1391 
1392 void QgsLabel::setMaxScale( float theMaxScale )
1393 {
1394  mMaxScale = theMaxScale;
1395 }
1396 
1397 float QgsLabel::maxScale() const
1398 {
1399  return mMaxScale;
1400 }
void setBufferColor(const QColor &color)
double bufferSize() const
void setMultilineEnabled(bool useMultiline)
void setBold(bool enable)
void setLabelField(int attr, int fieldIndex)
Set label field.
Definition: qgslabel.cpp:491
void setSize(double size, int type)
void setUnderline(bool enable)
void setSelectedOnly(bool selectedonly)
static int unitsCode(const QString &name)
void setFamily(const QString &family)
bool alignmentIsSet() const
size_t wkbSize() const
Returns the size of the WKB in asWkb().
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
float maxScale() const
Definition: qgslabel.cpp:1397
static QString alignmentName(int alignment)
QgsGeometry * geometry() const
Get the geometry object associated with this feature.
Definition: qgsfeature.cpp:112
QgsPoint transform(const QgsPoint &p) const
void renderLabel(QgsRenderContext &renderContext, QgsFeature &feature, bool selected, QgsLabelAttributes *classAttributes=0)
render label
Definition: qgslabel.cpp:72
Container of fields for a vector layer.
Definition: qgsfield.h:172
void setFields(const QgsFields &fields)
Set available fields.
Definition: qgslabel.cpp:481
QgsPoint transform(const QgsPoint &p, TransformDirection direction=ForwardTransform) const
double scaleFactor() const
WkbType
Used for symbology operations.
Definition: qgis.h:53
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:113
const QgsCoordinateTransform * coordinateTransform() const
float minScale() const
Definition: qgslabel.cpp:1387
double x() const
Definition: qgspoint.h:126
QgsLabelAttributes * labelAttributes()
Pointer to default attributes.
Definition: qgslabel.cpp:510
void setAutoAngle(bool state)
static QString unitsName(int units)
QColor bufferColor() const
static int alignmentCode(const QString &name)
const QColor & color() const
void setBufferSize(double size, int type)
void setScaleBasedVisibility(bool theVisibilityFlag)
Accessor and mutator for the scale based visilibility flag.
Definition: qgslabel.cpp:1372
#define M_PI
QList< int > QgsAttributeList
bool scaleBasedVisibility() const
Definition: qgslabel.cpp:1377
double rasterScaleFactor() const
int count() const
Return number of items.
Definition: qgsfield.h:214
QGis::WkbType wkbType() const
Returns type of wkb (point / linestring / polygon etc.)
QString labelField(int attr) const
label field
Definition: qgslabel.cpp:499
QgsFields & fields()
Available vector fields.
Definition: qgslabel.cpp:486
void setText(const QString &text)
void readXML(const QDomNode &node)
Reads the renderer configuration from an XML file.
Definition: qgslabel.cpp:729
bool multilineEnabled() const
void setAngle(double angle)
A class to represent a point.
Definition: qgspoint.h:63
void writeXML(QDomNode &label_node, QDomDocument &document) const
Writes the contents of the renderer to a configuration file.
Definition: qgslabel.cpp:1022
QString fieldValue(int attr, QgsFeature &feature)
Get field value if : 1) field name is not empty 2) field exists 3) value is defined otherwise returns...
Definition: qgslabel.cpp:66
bool bufferSizeIsSet() const
double ANALYSIS_EXPORT angle(Point3D *p1, Point3D *p2, Point3D *p3, Point3D *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
void setX(double x)
Definition: qgspoint.h:103
void setY(double y)
Definition: qgspoint.h:111
const QString family() const
void setStrikeOut(bool enable)
void addRequiredFields(QgsAttributeList &fields) const
add vector of required fields to existing list of fields
Definition: qgslabel.cpp:459
Contains information about the context of a rendering operation.
void setMaxScale(float theMaxScale)
Accessor and mutator for the maximum scale member.
Definition: qgslabel.cpp:1392
void setAlignment(int alignment)
QPainter * painter()
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:230
void setOffset(double x, double y, int type)
QgsLabel(const QgsFields &fields)
Definition: qgslabel.cpp:47
bool strikeOutIsSet() const
const QgsMapToPixel & mapToPixel() const
double y() const
Definition: qgspoint.h:134
~QgsLabel()
Definition: qgslabel.cpp:61
bool underlineIsSet() const
void setMinScale(float theMinScale)
Accessor and mutator for the minimum scale member.
Definition: qgslabel.cpp:1382
Custom exception class for Coordinate Reference System related exceptions.
A class to store attributes needed for label rendering.
void setColor(const QColor &color)
double size
Definition: qgssvgcache.cpp:77
void setBufferEnabled(bool useBufferFlag)
const unsigned char * asWkb() const
Returns the buffer containing this geometry in WKB format.
bool bufferColorIsSet() const
void setItalic(bool enable)
const QString text() const