00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "qgspallabeling.h"
00019
00020 #include <list>
00021
00022 #include <pal/pal.h>
00023 #include <pal/feature.h>
00024 #include <pal/layer.h>
00025 #include <pal/palgeometry.h>
00026 #include <pal/palexception.h>
00027 #include <pal/problem.h>
00028 #include <pal/labelposition.h>
00029
00030 #include <geos_c.h>
00031
00032 #include <cmath>
00033
00034 #include <QByteArray>
00035 #include <QString>
00036 #include <QFontMetrics>
00037 #include <QTime>
00038 #include <QPainter>
00039
00040 #include "qgsdiagram.h"
00041 #include "qgsdiagramrendererv2.h"
00042 #include "qgslabelsearchtree.h"
00043 #include "qgsexpression.h"
00044
00045 #include <qgslogger.h>
00046 #include <qgsvectorlayer.h>
00047 #include <qgsmaplayerregistry.h>
00048 #include <qgsvectordataprovider.h>
00049 #include <qgsgeometry.h>
00050 #include <qgsmaprenderer.h>
00051 #include <QMessageBox>
00052
00053 using namespace pal;
00054
00055
00056 class QgsPalGeometry : public PalGeometry
00057 {
00058 public:
00059 QgsPalGeometry( QgsFeatureId id, QString text, GEOSGeometry* g )
00060 : mG( g )
00061 , mText( text )
00062 , mId( id )
00063 , mInfo( NULL )
00064 , mIsDiagram( false )
00065 {
00066 mStrId = FID_TO_STRING( id ).toAscii();
00067 }
00068
00069 ~QgsPalGeometry()
00070 {
00071 if ( mG )
00072 GEOSGeom_destroy( mG );
00073 delete mInfo;
00074 }
00075
00076
00077
00078 GEOSGeometry* getGeosGeometry()
00079 {
00080 return mG;
00081 }
00082 void releaseGeosGeometry( GEOSGeometry* )
00083 {
00084
00085 }
00086
00087 const char* strId() { return mStrId.data(); }
00088 QString text() { return mText; }
00089
00090 pal::LabelInfo* info( QFontMetricsF* fm, const QgsMapToPixel* xform, double fontScale )
00091 {
00092 if ( mInfo )
00093 return mInfo;
00094
00095
00096 QgsPoint ptZero = xform->toMapCoordinates( 0, 0 );
00097 QgsPoint ptSize = xform->toMapCoordinatesF( 0.0, -fm->height() / fontScale );
00098
00099 mInfo = new pal::LabelInfo( mText.count(), ptSize.y() - ptZero.y() );
00100 for ( int i = 0; i < mText.count(); i++ )
00101 {
00102 mInfo->char_info[i].chr = mText[i].unicode();
00103 ptSize = xform->toMapCoordinatesF( fm->width( mText[i] ) / fontScale , 0.0 );
00104 mInfo->char_info[i].width = ptSize.x() - ptZero.x();
00105 }
00106 return mInfo;
00107 }
00108
00109 const QMap< QgsPalLayerSettings::DataDefinedProperties, QVariant >& dataDefinedValues() const { return mDataDefinedValues; }
00110 void addDataDefinedValue( QgsPalLayerSettings::DataDefinedProperties p, QVariant v ) { mDataDefinedValues.insert( p, v ); }
00111
00112 void setIsDiagram( bool d ) { mIsDiagram = d; }
00113 bool isDiagram() const { return mIsDiagram; }
00114
00115 void addDiagramAttribute( int index, QVariant value ) { mDiagramAttributes.insert( index, value ); }
00116 const QgsAttributeMap& diagramAttributes() { return mDiagramAttributes; }
00117
00118 protected:
00119 GEOSGeometry* mG;
00120 QString mText;
00121 QByteArray mStrId;
00122 QgsFeatureId mId;
00123 LabelInfo* mInfo;
00124 bool mIsDiagram;
00126 QMap< QgsPalLayerSettings::DataDefinedProperties, QVariant > mDataDefinedValues;
00127
00129 QgsAttributeMap mDiagramAttributes;
00130 };
00131
00132
00133
00134 QgsPalLayerSettings::QgsPalLayerSettings()
00135 : palLayer( NULL ), fontMetrics( NULL ), ct( NULL ), extentGeom( NULL ), expression( NULL )
00136 {
00137 placement = AroundPoint;
00138 placementFlags = 0;
00139
00140 textColor = Qt::black;
00141 enabled = false;
00142 priority = 5;
00143 obstacle = true;
00144 dist = 0;
00145 scaleMin = 0;
00146 scaleMax = 0;
00147 bufferSize = 1;
00148 bufferColor = Qt::white;
00149 formatNumbers = false;
00150 decimals = 3;
00151 plusSign = false;
00152 labelPerPart = false;
00153 mergeLines = false;
00154 minFeatureSize = 0.0;
00155 vectorScaleFactor = 1.0;
00156 rasterCompressFactor = 1.0;
00157 addDirectionSymbol = false;
00158 fontSizeInMapUnits = false;
00159 distInMapUnits = false;
00160 wrapChar = "";
00161 }
00162
00163 QgsPalLayerSettings::QgsPalLayerSettings( const QgsPalLayerSettings& s )
00164 {
00165
00166 fieldName = s.fieldName;
00167 isExpression = s.isExpression;
00168 placement = s.placement;
00169 placementFlags = s.placementFlags;
00170 textFont = s.textFont;
00171 textColor = s.textColor;
00172 enabled = s.enabled;
00173 priority = s.priority;
00174 obstacle = s.obstacle;
00175 dist = s.dist;
00176 scaleMin = s.scaleMin;
00177 scaleMax = s.scaleMax;
00178 bufferSize = s.bufferSize;
00179 bufferColor = s.bufferColor;
00180 formatNumbers = s.formatNumbers;
00181 decimals = s.decimals;
00182 plusSign = s.plusSign;
00183 labelPerPart = s.labelPerPart;
00184 mergeLines = s.mergeLines;
00185 minFeatureSize = s.minFeatureSize;
00186 vectorScaleFactor = s.vectorScaleFactor;
00187 rasterCompressFactor = s.rasterCompressFactor;
00188 addDirectionSymbol = s.addDirectionSymbol;
00189 fontSizeInMapUnits = s.fontSizeInMapUnits;
00190 distInMapUnits = s.distInMapUnits;
00191 wrapChar = s.wrapChar;
00192
00193 dataDefinedProperties = s.dataDefinedProperties;
00194 fontMetrics = NULL;
00195 ct = NULL;
00196 extentGeom = NULL;
00197 expression = NULL;
00198 }
00199
00200
00201 QgsPalLayerSettings::~QgsPalLayerSettings()
00202 {
00203
00204
00205 delete fontMetrics;
00206 delete ct;
00207 delete expression;
00208 delete extentGeom;
00209 }
00210
00211 QgsExpression* QgsPalLayerSettings::getLabelExpression()
00212 {
00213 if ( expression == NULL )
00214 {
00215 expression = new QgsExpression( fieldName );
00216 }
00217 return expression;
00218 }
00219
00220 static QColor _readColor( QgsVectorLayer* layer, QString property )
00221 {
00222 int r = layer->customProperty( property + "R" ).toInt();
00223 int g = layer->customProperty( property + "G" ).toInt();
00224 int b = layer->customProperty( property + "B" ).toInt();
00225 return QColor( r, g, b );
00226 }
00227
00228 static void _writeColor( QgsVectorLayer* layer, QString property, QColor color )
00229 {
00230 layer->setCustomProperty( property + "R", color.red() );
00231 layer->setCustomProperty( property + "G", color.green() );
00232 layer->setCustomProperty( property + "B", color.blue() );
00233 }
00234
00235 static void _writeDataDefinedPropertyMap( QgsVectorLayer* layer, const QMap< QgsPalLayerSettings::DataDefinedProperties, int >& propertyMap )
00236 {
00237 if ( !layer )
00238 {
00239 return;
00240 }
00241
00242 for ( int i = 0; i < 15; ++i )
00243 {
00244 QMap< QgsPalLayerSettings::DataDefinedProperties, int >::const_iterator it = propertyMap.find(( QgsPalLayerSettings::DataDefinedProperties )i );
00245 QVariant propertyValue;
00246 if ( it == propertyMap.constEnd() )
00247 {
00248 propertyValue = QVariant();
00249 }
00250 else
00251 {
00252 propertyValue = *it;
00253 }
00254 layer->setCustomProperty( "labeling/dataDefinedProperty" + QString::number( i ), propertyValue );
00255 }
00256 }
00257
00258 static void _readDataDefinedProperty( QgsVectorLayer* layer, QgsPalLayerSettings::DataDefinedProperties p,
00259 QMap< QgsPalLayerSettings::DataDefinedProperties, int >& propertyMap )
00260 {
00261 QVariant propertyField = layer->customProperty( "labeling/dataDefinedProperty" + QString::number( p ) );
00262 bool conversionOk;
00263 int fieldIndex;
00264
00265 if ( propertyField.isValid() )
00266 {
00267 fieldIndex = propertyField.toInt( &conversionOk );
00268 if ( conversionOk )
00269 {
00270 propertyMap.insert( p, fieldIndex );
00271 }
00272 }
00273 }
00274
00275 static void _readDataDefinedPropertyMap( QgsVectorLayer* layer, QMap< QgsPalLayerSettings::DataDefinedProperties, int >& propertyMap )
00276 {
00277 if ( !layer )
00278 {
00279 return;
00280 }
00281
00282 _readDataDefinedProperty( layer, QgsPalLayerSettings::Size, propertyMap );
00283 _readDataDefinedProperty( layer, QgsPalLayerSettings::Color, propertyMap );
00284 _readDataDefinedProperty( layer, QgsPalLayerSettings::Bold, propertyMap );
00285 _readDataDefinedProperty( layer, QgsPalLayerSettings::Italic, propertyMap );
00286 _readDataDefinedProperty( layer, QgsPalLayerSettings::Underline, propertyMap );
00287 _readDataDefinedProperty( layer, QgsPalLayerSettings::Strikeout, propertyMap );
00288 _readDataDefinedProperty( layer, QgsPalLayerSettings::Family, propertyMap );
00289 _readDataDefinedProperty( layer, QgsPalLayerSettings::BufferSize, propertyMap );
00290 _readDataDefinedProperty( layer, QgsPalLayerSettings::BufferColor, propertyMap );
00291 _readDataDefinedProperty( layer, QgsPalLayerSettings::PositionX, propertyMap );
00292 _readDataDefinedProperty( layer, QgsPalLayerSettings::PositionY, propertyMap );
00293 _readDataDefinedProperty( layer, QgsPalLayerSettings::Hali, propertyMap );
00294 _readDataDefinedProperty( layer, QgsPalLayerSettings::Vali, propertyMap );
00295 _readDataDefinedProperty( layer, QgsPalLayerSettings::LabelDistance, propertyMap );
00296 _readDataDefinedProperty( layer, QgsPalLayerSettings::Rotation, propertyMap );
00297 }
00298
00299 void QgsPalLayerSettings::readFromLayer( QgsVectorLayer* layer )
00300 {
00301 if ( layer->customProperty( "labeling" ).toString() != QString( "pal" ) )
00302 return;
00303
00304 fieldName = layer->customProperty( "labeling/fieldName" ).toString();
00305 isExpression = layer->customProperty( "labeling/isExpression" ).toBool();
00306 placement = ( Placement ) layer->customProperty( "labeling/placement" ).toInt();
00307 placementFlags = layer->customProperty( "labeling/placementFlags" ).toUInt();
00308 QString fontFamily = layer->customProperty( "labeling/fontFamily" ).toString();
00309 double fontSize = layer->customProperty( "labeling/fontSize" ).toDouble();
00310 int fontWeight = layer->customProperty( "labeling/fontWeight" ).toInt();
00311 bool fontItalic = layer->customProperty( "labeling/fontItalic" ).toBool();
00312 textFont = QFont( fontFamily, fontSize, fontWeight, fontItalic );
00313 textFont.setUnderline( layer->customProperty( "labeling/fontUnderline" ).toBool() );
00314 textFont.setStrikeOut( layer->customProperty( "labeling/fontStrikeout" ).toBool() );
00315 textFont.setPointSizeF( fontSize );
00316 textColor = _readColor( layer, "labeling/textColor" );
00317 enabled = layer->customProperty( "labeling/enabled" ).toBool();
00318 priority = layer->customProperty( "labeling/priority" ).toInt();
00319 obstacle = layer->customProperty( "labeling/obstacle" ).toBool();
00320 dist = layer->customProperty( "labeling/dist" ).toDouble();
00321 scaleMin = layer->customProperty( "labeling/scaleMin" ).toInt();
00322 scaleMax = layer->customProperty( "labeling/scaleMax" ).toInt();
00323 bufferSize = layer->customProperty( "labeling/bufferSize" ).toDouble();
00324 bufferColor = _readColor( layer, "labeling/bufferColor" );
00325 formatNumbers = layer->customProperty( "labeling/formatNumbers" ).toBool();
00326 decimals = layer->customProperty( "labeling/decimals" ).toInt();
00327 plusSign = layer->customProperty( "labeling/plussign" ).toInt();
00328 labelPerPart = layer->customProperty( "labeling/labelPerPart" ).toBool();
00329 mergeLines = layer->customProperty( "labeling/mergeLines" ).toBool();
00330 addDirectionSymbol = layer->customProperty( "labeling/addDirectionSymbol" ).toBool();
00331 minFeatureSize = layer->customProperty( "labeling/minFeatureSize" ).toDouble();
00332 fontSizeInMapUnits = layer->customProperty( "labeling/fontSizeInMapUnits" ).toBool();
00333 distInMapUnits = layer->customProperty( "labeling/distInMapUnits" ).toBool();
00334 wrapChar = layer->customProperty( "labeling/wrapChar" ).toString();
00335 _readDataDefinedPropertyMap( layer, dataDefinedProperties );
00336 }
00337
00338 void QgsPalLayerSettings::writeToLayer( QgsVectorLayer* layer )
00339 {
00340
00341 layer->setCustomProperty( "labeling", "pal" );
00342
00343 layer->setCustomProperty( "labeling/fieldName", fieldName );
00344 layer->setCustomProperty( "labeling/isExpression", isExpression );
00345 layer->setCustomProperty( "labeling/placement", placement );
00346 layer->setCustomProperty( "labeling/placementFlags", ( unsigned int )placementFlags );
00347
00348 layer->setCustomProperty( "labeling/fontFamily", textFont.family() );
00349 layer->setCustomProperty( "labeling/fontSize", textFont.pointSizeF() );
00350 layer->setCustomProperty( "labeling/fontWeight", textFont.weight() );
00351 layer->setCustomProperty( "labeling/fontItalic", textFont.italic() );
00352 layer->setCustomProperty( "labeling/fontStrikeout", textFont.strikeOut() );
00353 layer->setCustomProperty( "labeling/fontUnderline", textFont.underline() );
00354
00355 _writeColor( layer, "labeling/textColor", textColor );
00356 layer->setCustomProperty( "labeling/enabled", enabled );
00357 layer->setCustomProperty( "labeling/priority", priority );
00358 layer->setCustomProperty( "labeling/obstacle", obstacle );
00359 layer->setCustomProperty( "labeling/dist", dist );
00360 layer->setCustomProperty( "labeling/scaleMin", scaleMin );
00361 layer->setCustomProperty( "labeling/scaleMax", scaleMax );
00362 layer->setCustomProperty( "labeling/bufferSize", bufferSize );
00363 _writeColor( layer, "labeling/bufferColor", bufferColor );
00364 layer->setCustomProperty( "labeling/formatNumbers", formatNumbers );
00365 layer->setCustomProperty( "labeling/decimals", decimals );
00366 layer->setCustomProperty( "labeling/plussign", plusSign );
00367 layer->setCustomProperty( "labeling/labelPerPart", labelPerPart );
00368 layer->setCustomProperty( "labeling/mergeLines", mergeLines );
00369 layer->setCustomProperty( "labeling/addDirectionSymbol", addDirectionSymbol );
00370 layer->setCustomProperty( "labeling/minFeatureSize", minFeatureSize );
00371 layer->setCustomProperty( "labeling/fontSizeInMapUnits", fontSizeInMapUnits );
00372 layer->setCustomProperty( "labeling/distInMapUnits", distInMapUnits );
00373 layer->setCustomProperty( "labeling/wrapChar", wrapChar );
00374 _writeDataDefinedPropertyMap( layer, dataDefinedProperties );
00375 }
00376
00377 void QgsPalLayerSettings::setDataDefinedProperty( DataDefinedProperties p, int attributeIndex )
00378 {
00379 dataDefinedProperties.insert( p, attributeIndex );
00380 }
00381
00382 void QgsPalLayerSettings::removeDataDefinedProperty( DataDefinedProperties p )
00383 {
00384 dataDefinedProperties.remove( p );
00385 }
00386
00387 bool QgsPalLayerSettings::checkMinimumSizeMM( const QgsRenderContext& ct, QgsGeometry* geom, double minSize ) const
00388 {
00389 if ( minSize <= 0 )
00390 {
00391 return true;
00392 }
00393
00394 if ( !geom )
00395 {
00396 return false;
00397 }
00398
00399 QGis::GeometryType featureType = geom->type();
00400 if ( featureType == QGis::Point )
00401 {
00402 return true;
00403 }
00404
00405 double mapUnitsPerMM = ct.mapToPixel().mapUnitsPerPixel() * ct.scaleFactor();
00406 if ( featureType == QGis::Line )
00407 {
00408 double length = geom->length();
00409 if ( length >= 0.0 )
00410 {
00411 return ( length >= ( minSize * mapUnitsPerMM ) );
00412 }
00413 }
00414 else if ( featureType == QGis::Polygon )
00415 {
00416 double area = geom->area();
00417 if ( area >= 0.0 )
00418 {
00419 return ( sqrt( area ) >= ( minSize * mapUnitsPerMM ) );
00420 }
00421 }
00422 return true;
00423 }
00424
00425 void QgsPalLayerSettings::calculateLabelSize( const QFontMetricsF* fm, QString text, double& labelX, double& labelY )
00426 {
00427 if ( !fm )
00428 {
00429 return;
00430 }
00431
00432
00433 if ( addDirectionSymbol && placement == QgsPalLayerSettings::Line )
00434 {
00435 text.append( ">" );
00436 }
00437
00438 double w, h;
00439 QStringList multiLineSplit;
00440 if ( !wrapChar.isEmpty() )
00441 multiLineSplit = text.split( wrapChar );
00442 else
00443 multiLineSplit = text.split( "\n" );
00444
00445 h = fm->height() * multiLineSplit.size() / rasterCompressFactor;
00446 w = 0;
00447 for ( int i = 0; i < multiLineSplit.size(); ++i )
00448 {
00449 double width = fm->width( multiLineSplit.at( i ) );
00450 if ( width > w )
00451 {
00452 w = width;
00453 }
00454 }
00455 w /= rasterCompressFactor;
00456 QgsPoint ptSize = xform->toMapCoordinatesF( w, h );
00457
00458 labelX = qAbs( ptSize.x() - ptZero.x() );
00459 labelY = qAbs( ptSize.y() - ptZero.y() );
00460 }
00461
00462 void QgsPalLayerSettings::registerFeature( QgsVectorLayer* layer, QgsFeature& f, const QgsRenderContext& context )
00463 {
00464 QString labelText;
00465
00466 if ( isExpression )
00467 {
00468 QgsExpression* exp = getLabelExpression();
00469 if ( exp->hasParserError() )
00470 {
00471 QgsDebugMsg( "Expression parser error:" + exp->parserErrorString() );
00472 return;
00473 }
00474 QVariant result = exp->evaluate( &f, layer->pendingFields() );
00475 if ( exp->hasEvalError() )
00476 {
00477 QgsDebugMsg( "Expression parser eval error:" + exp->evalErrorString() );
00478 return;
00479 }
00480 labelText = result.toString();
00481 }
00482 else if ( formatNumbers == true && ( f.attributeMap()[fieldIndex].type() == QVariant::Int ||
00483 f.attributeMap()[fieldIndex].type() == QVariant::Double ) )
00484 {
00485 QString numberFormat;
00486 double d = f.attributeMap()[fieldIndex].toDouble();
00487 if ( d > 0 && plusSign == true )
00488 {
00489 numberFormat.append( "+" );
00490 }
00491 numberFormat.append( "%1" );
00492 labelText = numberFormat.arg( d, 0, 'f', decimals );
00493 }
00494 else
00495 {
00496 labelText = f.attributeMap()[fieldIndex].toString();
00497 }
00498
00499 double labelX, labelY;
00500 QFont labelFont = textFont;
00501
00502
00503 QMap< DataDefinedProperties, int >::const_iterator it = dataDefinedProperties.find( QgsPalLayerSettings::Size );
00504 if ( it != dataDefinedProperties.constEnd() )
00505 {
00506
00507 QVariant size = f.attributeMap().value( *it );
00508 if ( size.isValid() )
00509 {
00510 double sizeDouble = size.toDouble();
00511 if ( sizeDouble <= 0 )
00512 {
00513 return;
00514 }
00515 labelFont.setPixelSize( sizeToPixel( sizeDouble, context ) );
00516 }
00517 QFontMetricsF labelFontMetrics( labelFont );
00518 calculateLabelSize( &labelFontMetrics, labelText, labelX, labelY );
00519 }
00520 else
00521 {
00522 calculateLabelSize( fontMetrics, labelText, labelX, labelY );
00523 }
00524
00525 QgsGeometry* geom = f.geometry();
00526 if ( !geom )
00527 {
00528 return;
00529 }
00530
00531 if ( ct )
00532 geom->transform( *ct );
00533
00534 if ( !checkMinimumSizeMM( context, geom, minFeatureSize ) )
00535 {
00536 return;
00537 }
00538
00539
00540 QgsGeometry* geomClipped = NULL;
00541 GEOSGeometry* geos_geom;
00542 bool do_clip = !extentGeom->contains( geom );
00543 if ( do_clip )
00544 {
00545 geomClipped = geom->intersection( extentGeom );
00546 if ( !geomClipped )
00547 {
00548 return;
00549 }
00550 geos_geom = geomClipped->asGeos();
00551 }
00552 else
00553 {
00554 geos_geom = geom->asGeos();
00555 }
00556
00557 if ( geos_geom == NULL )
00558 return;
00559 GEOSGeometry* geos_geom_clone = GEOSGeom_clone( geos_geom );
00560 if ( do_clip )
00561 delete geomClipped;
00562
00563
00564 bool dataDefinedPosition = false;
00565 bool dataDefinedRotation = false;
00566 double xPos = 0.0, yPos = 0.0, angle = 0.0;
00567 bool ddXPos, ddYPos;
00568
00569 QMap< DataDefinedProperties, int >::const_iterator dPosXIt = dataDefinedProperties.find( QgsPalLayerSettings::PositionX );
00570 if ( dPosXIt != dataDefinedProperties.constEnd() )
00571 {
00572 QMap< DataDefinedProperties, int >::const_iterator dPosYIt = dataDefinedProperties.find( QgsPalLayerSettings::PositionY );
00573 if ( dPosYIt != dataDefinedProperties.constEnd() )
00574 {
00575
00576 xPos = f.attributeMap().value( *dPosXIt ).toDouble( &ddXPos );
00577 yPos = f.attributeMap().value( *dPosYIt ).toDouble( &ddYPos );
00578
00579 if ( ddXPos && ddYPos )
00580 {
00581 dataDefinedPosition = true;
00582
00583 double xdiff = 0;
00584 double ydiff = 0;
00585
00586
00587 QMap< DataDefinedProperties, int >::const_iterator haliIt = dataDefinedProperties.find( QgsPalLayerSettings::Hali );
00588 if ( haliIt != dataDefinedProperties.end() )
00589 {
00590 QString haliString = f.attributeMap().value( *haliIt ).toString();
00591 if ( haliString.compare( "Center", Qt::CaseInsensitive ) == 0 )
00592 {
00593 xdiff -= labelX / 2.0;
00594 }
00595 else if ( haliString.compare( "Right", Qt::CaseInsensitive ) == 0 )
00596 {
00597 xdiff -= labelX;
00598 }
00599 }
00600
00601
00602 QMap< DataDefinedProperties, int >::const_iterator valiIt = dataDefinedProperties.find( QgsPalLayerSettings::Vali );
00603 if ( valiIt != dataDefinedProperties.constEnd() )
00604 {
00605 QString valiString = f.attributeMap().value( *valiIt ).toString();
00606 if ( valiString.compare( "Bottom", Qt::CaseInsensitive ) != 0 )
00607 {
00608 if ( valiString.compare( "Top", Qt::CaseInsensitive ) == 0 || valiString.compare( "Cap", Qt::CaseInsensitive ) == 0 )
00609 {
00610 ydiff -= labelY;
00611 }
00612 else
00613 {
00614 QFontMetrics labelFontMetrics( labelFont );
00615 double descentRatio = labelFontMetrics.descent() / labelFontMetrics.height();
00616
00617 if ( valiString.compare( "Base", Qt::CaseInsensitive ) == 0 )
00618 {
00619 ydiff -= labelY * descentRatio;
00620 }
00621 else if ( valiString.compare( "Half", Qt::CaseInsensitive ) == 0 )
00622 {
00623 ydiff -= labelY * descentRatio;
00624 ydiff -= labelY * 0.5 * ( 1 - descentRatio );
00625 }
00626 }
00627 }
00628 }
00629
00630
00631 QMap< DataDefinedProperties, int >::const_iterator rotIt = dataDefinedProperties.find( QgsPalLayerSettings::Rotation );
00632 if ( rotIt != dataDefinedProperties.constEnd() )
00633 {
00634 dataDefinedRotation = true;
00635 angle = f.attributeMap().value( *rotIt ).toDouble() * M_PI / 180;
00636
00637 double xd = xdiff * cos( angle ) - ydiff * sin( angle );
00638 double yd = xdiff * sin( angle ) + ydiff * cos( angle );
00639 xdiff = xd;
00640 ydiff = yd;
00641 }
00642
00643
00644 double z = 0;
00645 if ( ct )
00646 {
00647 ct->transformInPlace( xPos, yPos, z );
00648 }
00649
00650 yPos += ydiff;
00651 xPos += xdiff;
00652
00653 }
00654 }
00655 }
00656
00657 QgsPalGeometry* lbl = new QgsPalGeometry( f.id(), labelText, geos_geom_clone );
00658
00659
00660 geometries.append( lbl );
00661
00662
00663 try
00664 {
00665 if ( !palLayer->registerFeature( lbl->strId(), lbl, labelX, labelY, labelText.toUtf8().constData(),
00666 xPos, yPos, dataDefinedPosition, angle, dataDefinedRotation ) )
00667 return;
00668 }
00669 catch ( std::exception &e )
00670 {
00671 Q_UNUSED( e );
00672 QgsDebugMsg( QString( "Ignoring feature %1 due PAL exception: " ).arg( f.id() ) + QString::fromLatin1( e.what() ) );
00673 return;
00674 }
00675
00676
00677 pal::Feature* feat = palLayer->getFeature( lbl->strId() );
00678 feat->setLabelInfo( lbl->info( fontMetrics, xform, rasterCompressFactor ) );
00679
00680
00681
00682
00683 double distance = dist;
00684 QMap< DataDefinedProperties, int >::const_iterator dDistIt = dataDefinedProperties.find( QgsPalLayerSettings::LabelDistance );
00685 if ( dDistIt != dataDefinedProperties.constEnd() )
00686 {
00687 distance = f.attributeMap().value( *dDistIt ).toDouble();
00688 }
00689
00690 if ( distance != 0 )
00691 {
00692 if ( distInMapUnits )
00693 {
00694 distance /= context.mapToPixel().mapUnitsPerPixel();
00695 }
00696 else
00697 {
00698 distance *= vectorScaleFactor;
00699 }
00700 feat->setDistLabel( qAbs( ptOne.x() - ptZero.x() )* distance );
00701 }
00702
00703
00704 QMap< DataDefinedProperties, int >::const_iterator dIt = dataDefinedProperties.constBegin();
00705 for ( ; dIt != dataDefinedProperties.constEnd(); ++dIt )
00706 {
00707 lbl->addDataDefinedValue( dIt.key(), f.attributeMap()[dIt.value()] );
00708 }
00709 }
00710
00711 int QgsPalLayerSettings::sizeToPixel( double size, const QgsRenderContext& c ) const
00712 {
00713 double pixelSize;
00714 if ( fontSizeInMapUnits )
00715 {
00716 pixelSize = size / c.mapToPixel().mapUnitsPerPixel() * c.rasterScaleFactor();
00717 }
00718 else
00719 {
00720
00721 pixelSize = 0.3527 * size * c.scaleFactor() * c.rasterScaleFactor();
00722 }
00723 return ( int )( pixelSize + 0.5 );
00724 }
00725
00726
00727
00728
00729 QgsPalLabeling::QgsPalLabeling()
00730 : mMapRenderer( NULL ), mPal( NULL )
00731 {
00732
00733
00734 Pal p;
00735 mCandPoint = p.getPointP();
00736 mCandLine = p.getLineP();
00737 mCandPolygon = p.getPolyP();
00738
00739 switch ( p.getSearch() )
00740 {
00741 case CHAIN: mSearch = Chain; break;
00742 case POPMUSIC_TABU: mSearch = Popmusic_Tabu; break;
00743 case POPMUSIC_CHAIN: mSearch = Popmusic_Chain; break;
00744 case POPMUSIC_TABU_CHAIN: mSearch = Popmusic_Tabu_Chain; break;
00745 case FALP: mSearch = Falp; break;
00746 }
00747
00748 mShowingCandidates = false;
00749 mShowingAllLabels = false;
00750
00751 mLabelSearchTree = new QgsLabelSearchTree();
00752 }
00753
00754
00755 QgsPalLabeling::~QgsPalLabeling()
00756 {
00757
00758 exit();
00759 delete mLabelSearchTree;
00760 mLabelSearchTree = NULL;
00761 }
00762
00763
00764 bool QgsPalLabeling::willUseLayer( QgsVectorLayer* layer )
00765 {
00766 QgsPalLayerSettings lyrTmp;
00767 lyrTmp.readFromLayer( layer );
00768 return lyrTmp.enabled;
00769 }
00770
00771 int QgsPalLabeling::prepareLayer( QgsVectorLayer* layer, QSet<int>& attrIndices, QgsRenderContext& ctx )
00772 {
00773 QgsDebugMsg( "PREPARE LAYER" );
00774 Q_ASSERT( mMapRenderer != NULL );
00775
00776
00777 QgsPalLayerSettings lyrTmp;
00778 lyrTmp.readFromLayer( layer );
00779
00780 if ( !lyrTmp.enabled )
00781 return 0;
00782
00783
00784 int fldIndex = -1;
00785 if ( lyrTmp.isExpression )
00786 {
00787 if ( lyrTmp.fieldName.isEmpty() )
00788 return 0;
00789 QgsExpression exp( lyrTmp.fieldName );
00790 foreach( QString name, exp.referencedColumns() )
00791 {
00792 QgsDebugMsg( "REFERENCED COLUMN = " + name );
00793 fldIndex = layer->fieldNameIndex( name );
00794 attrIndices.insert( fldIndex );
00795 }
00796
00797 }
00798 else
00799 {
00800
00801 fldIndex = layer->fieldNameIndex( lyrTmp.fieldName );
00802 if ( fldIndex == -1 )
00803 return 0;
00804 attrIndices.insert( fldIndex );
00805 }
00806
00807
00808 QMap< QgsPalLayerSettings::DataDefinedProperties, int >::const_iterator dIt = lyrTmp.dataDefinedProperties.constBegin();
00809 for ( ; dIt != lyrTmp.dataDefinedProperties.constEnd(); ++dIt )
00810 {
00811 attrIndices.insert( dIt.value() );
00812 }
00813
00814
00815 mActiveLayers.insert( layer, lyrTmp );
00816
00817 QgsPalLayerSettings& lyr = mActiveLayers[layer];
00818
00819
00820 Arrangement arrangement;
00821 switch ( lyr.placement )
00822 {
00823 case QgsPalLayerSettings::AroundPoint: arrangement = P_POINT; break;
00824 case QgsPalLayerSettings::OverPoint: arrangement = P_POINT_OVER; break;
00825 case QgsPalLayerSettings::Line: arrangement = P_LINE; break;
00826 case QgsPalLayerSettings::Curved: arrangement = P_CURVED; break;
00827 case QgsPalLayerSettings::Horizontal: arrangement = P_HORIZ; break;
00828 case QgsPalLayerSettings::Free: arrangement = P_FREE; break;
00829 default: Q_ASSERT( "unsupported placement" && 0 ); return 0;
00830 }
00831
00832
00833 double priority = 1 - lyr.priority / 10.0;
00834 double min_scale = -1, max_scale = -1;
00835 if ( lyr.scaleMin != 0 && lyr.scaleMax != 0 )
00836 {
00837 min_scale = lyr.scaleMin;
00838 max_scale = lyr.scaleMax;
00839 }
00840
00841 Layer* l = mPal->addLayer( layer->id().toUtf8().data(),
00842 min_scale, max_scale, arrangement,
00843 METER, priority, lyr.obstacle, true, true );
00844
00845 if ( lyr.placementFlags )
00846 l->setArrangementFlags( lyr.placementFlags );
00847
00848
00849 l->setLabelMode( lyr.labelPerPart ? Layer::LabelPerFeaturePart : Layer::LabelPerFeature );
00850
00851
00852 l->setMergeConnectedLines( lyr.mergeLines );
00853
00854 lyr.textFont.setPixelSize( lyr.sizeToPixel( lyr.textFont.pointSizeF(), ctx ) );
00855
00856
00857 lyr.vectorScaleFactor = ctx.scaleFactor();
00858 lyr.rasterCompressFactor = ctx.rasterScaleFactor();
00859
00860
00861 lyr.palLayer = l;
00862 lyr.fieldIndex = fldIndex;
00863 lyr.fontMetrics = new QFontMetricsF( lyr.textFont );
00864
00865 lyr.xform = mMapRenderer->coordinateTransform();
00866 if ( mMapRenderer->hasCrsTransformEnabled() )
00867 lyr.ct = new QgsCoordinateTransform( layer->crs(), mMapRenderer->destinationCrs() );
00868 else
00869 lyr.ct = NULL;
00870 lyr.ptZero = lyr.xform->toMapCoordinates( 0, 0 );
00871 lyr.ptOne = lyr.xform->toMapCoordinates( 1, 0 );
00872
00873
00874 lyr.extentGeom = QgsGeometry::fromRect( mMapRenderer->extent() );
00875
00876 return 1;
00877 }
00878
00879 int QgsPalLabeling::addDiagramLayer( QgsVectorLayer* layer, QgsDiagramLayerSettings *s )
00880 {
00881 Layer* l = mPal->addLayer( layer->id().append( "d" ).toUtf8().data(), -1, -1, pal::Arrangement( s->placement ), METER, s->priority, s->obstacle, true, true );
00882 l->setArrangementFlags( s->placementFlags );
00883
00884 s->palLayer = l;
00885 if ( mMapRenderer->hasCrsTransformEnabled() )
00886 s->ct = new QgsCoordinateTransform( layer->crs(), mMapRenderer->destinationCrs() );
00887 else
00888 s->ct = NULL;
00889 s->xform = mMapRenderer->coordinateTransform();
00890 mActiveDiagramLayers.insert( layer, *s );
00891 return 1;
00892 }
00893
00894 void QgsPalLabeling::registerFeature( QgsVectorLayer* layer, QgsFeature& f, const QgsRenderContext& context )
00895 {
00896 QgsPalLayerSettings& lyr = mActiveLayers[layer];
00897 lyr.registerFeature( layer, f, context );
00898 }
00899
00900 void QgsPalLabeling::registerDiagramFeature( QgsVectorLayer* layer, QgsFeature& feat, const QgsRenderContext& context )
00901 {
00902
00903 QHash<QgsVectorLayer*, QgsDiagramLayerSettings>::iterator layerIt = mActiveDiagramLayers.find( layer );
00904 if ( layerIt == mActiveDiagramLayers.constEnd() )
00905 {
00906 return;
00907 }
00908
00909
00910 QgsGeometry* geom = feat.geometry();
00911
00912 if ( layerIt.value().ct && !willUseLayer( layer ) )
00913 {
00914 geom->transform( *( layerIt.value().ct ) );
00915 }
00916
00917 GEOSGeometry* geos_geom = geom->asGeos();
00918 if ( geos_geom == 0 )
00919 {
00920 return;
00921 }
00922
00923
00924 QgsPalGeometry* lbl = new QgsPalGeometry( feat.id(), "", GEOSGeom_clone( geos_geom ) );
00925 lbl->setIsDiagram( true );
00926
00927
00928 layerIt.value().geometries.append( lbl );
00929
00930 double diagramWidth = 0;
00931 double diagramHeight = 0;
00932 QgsDiagramRendererV2* dr = layerIt.value().renderer;
00933 if ( dr )
00934 {
00935 QSizeF diagSize = dr->sizeMapUnits( feat.attributeMap(), context );
00936 if ( diagSize.isValid() )
00937 {
00938 diagramWidth = diagSize.width();
00939 diagramHeight = diagSize.height();
00940 }
00941
00942
00943 QList<int> diagramAttrib = dr->diagramAttributes();
00944 QList<int>::const_iterator diagAttIt = diagramAttrib.constBegin();
00945 for ( ; diagAttIt != diagramAttrib.constEnd(); ++diagAttIt )
00946 {
00947 lbl->addDiagramAttribute( *diagAttIt, feat.attributeMap()[*diagAttIt] );
00948 }
00949 }
00950
00951
00952 int ddColX = layerIt.value().xPosColumn;
00953 int ddColY = layerIt.value().yPosColumn;
00954 double ddPosX = 0.0;
00955 double ddPosY = 0.0;
00956 bool ddPos = ( ddColX >= 0 && ddColY >= 0 );
00957 if ( ddPos )
00958 {
00959 bool posXOk, posYOk;
00960
00961 ddPosX = feat.attributeMap()[ddColX].toDouble( &posXOk ) - diagramWidth / 2.0;
00962 ddPosY = feat.attributeMap()[ddColY].toDouble( &posYOk ) - diagramHeight / 2.0;
00963 if ( !posXOk || !posYOk )
00964 {
00965 ddPos = false;
00966 }
00967 else
00968 {
00969 const QgsCoordinateTransform* ct = layerIt.value().ct;
00970 if ( ct )
00971 {
00972 double z = 0;
00973 ct->transformInPlace( ddPosX, ddPosY, z );
00974 }
00975 }
00976 }
00977
00978 try
00979 {
00980 if ( !layerIt.value().palLayer->registerFeature( lbl->strId(), lbl, diagramWidth, diagramHeight, "", ddPosX, ddPosY, ddPos ) )
00981 {
00982 return;
00983 }
00984 }
00985 catch ( std::exception &e )
00986 {
00987 Q_UNUSED( e );
00988 QgsDebugMsg( QString( "Ignoring feature %1 due PAL exception: " ).arg( feat.id() ) + QString::fromLatin1( e.what() ) );
00989 return;
00990 }
00991
00992 pal::Feature* palFeat = layerIt.value().palLayer->getFeature( lbl->strId() );
00993 QgsPoint ptZero = layerIt.value().xform->toMapCoordinates( 0, 0 );
00994 QgsPoint ptOne = layerIt.value().xform->toMapCoordinates( 1, 0 );
00995 palFeat->setDistLabel( qAbs( ptOne.x() - ptZero.x() ) * layerIt.value().dist );
00996 }
00997
00998
00999 void QgsPalLabeling::init( QgsMapRenderer* mr )
01000 {
01001 mMapRenderer = mr;
01002
01003
01004 if ( mPal )
01005 delete mPal;
01006
01007 mPal = new Pal;
01008
01009 SearchMethod s;
01010 switch ( mSearch )
01011 {
01012 default:
01013 case Chain: s = CHAIN; break;
01014 case Popmusic_Tabu: s = POPMUSIC_TABU; break;
01015 case Popmusic_Chain: s = POPMUSIC_CHAIN; break;
01016 case Popmusic_Tabu_Chain: s = POPMUSIC_TABU_CHAIN; break;
01017 case Falp: s = FALP; break;
01018 }
01019 mPal->setSearch( s );
01020
01021
01022 mPal->setPointP( mCandPoint );
01023 mPal->setLineP( mCandLine );
01024 mPal->setPolyP( mCandPolygon );
01025
01026 mActiveLayers.clear();
01027 mActiveDiagramLayers.clear();
01028 }
01029
01030 void QgsPalLabeling::exit()
01031 {
01032 delete mPal;
01033 mPal = NULL;
01034 mMapRenderer = NULL;
01035 }
01036
01037 QgsPalLayerSettings& QgsPalLabeling::layer( const QString& layerName )
01038 {
01039 QHash<QgsVectorLayer*, QgsPalLayerSettings>::iterator lit;
01040 for ( lit = mActiveLayers.begin(); lit != mActiveLayers.end(); ++lit )
01041 {
01042 if ( lit.key() && lit.key()->id() == layerName )
01043 {
01044 return lit.value();
01045 }
01046 }
01047 return mInvalidLayerSettings;
01048 }
01049
01050
01051 void QgsPalLabeling::drawLabeling( QgsRenderContext& context )
01052 {
01053 Q_ASSERT( mMapRenderer != NULL );
01054 QPainter* painter = context.painter();
01055 QgsRectangle extent = context.extent();
01056
01057 if ( mLabelSearchTree )
01058 {
01059 mLabelSearchTree->clear();
01060 }
01061
01062 QTime t;
01063 t.start();
01064
01065
01066 double scale = mMapRenderer->scale();
01067 QgsRectangle r = extent;
01068 double bbox[] = { r.xMinimum(), r.yMinimum(), r.xMaximum(), r.yMaximum() };
01069
01070 std::list<LabelPosition*>* labels;
01071 pal::Problem* problem;
01072 try
01073 {
01074 problem = mPal->extractProblem( scale, bbox );
01075 }
01076 catch ( std::exception& e )
01077 {
01078 Q_UNUSED( e );
01079 QgsDebugMsg( "PAL EXCEPTION :-( " + QString::fromLatin1( e.what() ) );
01080
01081 return;
01082 }
01083
01084 const QgsMapToPixel* xform = mMapRenderer->coordinateTransform();
01085
01086
01087
01088
01089 mCandidates.clear();
01090 if ( mShowingCandidates && problem )
01091 {
01092 painter->setPen( QColor( 0, 0, 0, 64 ) );
01093 painter->setBrush( Qt::NoBrush );
01094 for ( int i = 0; i < problem->getNumFeatures(); i++ )
01095 {
01096 for ( int j = 0; j < problem->getFeatureCandidateCount( i ); j++ )
01097 {
01098 pal::LabelPosition* lp = problem->getFeatureCandidate( i, j );
01099
01100 drawLabelCandidateRect( lp, painter, xform );
01101 }
01102 }
01103 }
01104
01105
01106 labels = mPal->solveProblem( problem, mShowingAllLabels );
01107
01108 QgsDebugMsg( QString( "LABELING work: %1 ms ... labels# %2" ).arg( t.elapsed() ).arg( labels->size() ) );
01109 t.restart();
01110
01111 painter->setRenderHint( QPainter::Antialiasing );
01112
01113
01114 std::list<LabelPosition*>::iterator it = labels->begin();
01115 for ( ; it != labels->end(); ++it )
01116 {
01117 QgsPalGeometry* palGeometry = dynamic_cast< QgsPalGeometry* >(( *it )->getFeaturePart()->getUserGeometry() );
01118 if ( !palGeometry )
01119 {
01120 continue;
01121 }
01122
01123
01124 QString layerNameUtf8 = QString::fromUtf8(( *it )->getLayerName() );
01125 if ( palGeometry->isDiagram() )
01126 {
01127
01128 QHash<QgsVectorLayer*, QgsDiagramLayerSettings>::iterator dit = mActiveDiagramLayers.begin();
01129 for ( dit = mActiveDiagramLayers.begin(); dit != mActiveDiagramLayers.end(); ++dit )
01130 {
01131 if ( dit.key() && dit.key()->id().append( "d" ) == layerNameUtf8 )
01132 {
01133 QgsPoint outPt = xform->transform(( *it )->getX(), ( *it )->getY() );
01134 dit.value().renderer->renderDiagram( palGeometry->diagramAttributes(), context, QPointF( outPt.x(), outPt.y() ) );
01135 }
01136 }
01137
01138
01139 if ( mLabelSearchTree )
01140 {
01141
01142 QString layerId = layerNameUtf8;
01143 layerId.chop( 1 );
01144 mLabelSearchTree->insertLabel( *it, QString( palGeometry->strId() ).toInt(), layerId, true );
01145 }
01146 continue;
01147 }
01148
01149 const QgsPalLayerSettings& lyr = layer( layerNameUtf8 );
01150 QFont fontForLabel = lyr.textFont;
01151 QColor fontColor = lyr.textColor;
01152 double bufferSize = lyr.bufferSize;
01153 QColor bufferColor = lyr.bufferColor;
01154
01155
01156
01157 QVariant dataDefinedSize = palGeometry->dataDefinedValues().value( QgsPalLayerSettings::Size );
01158 if ( dataDefinedSize.isValid() )
01159 {
01160 fontForLabel.setPixelSize( lyr.sizeToPixel( dataDefinedSize.toDouble(), context ) );
01161 }
01162
01163 QVariant dataDefinedColor = palGeometry->dataDefinedValues().value( QgsPalLayerSettings::Color );
01164 if ( dataDefinedColor.isValid() )
01165 {
01166 fontColor.setNamedColor( dataDefinedColor.toString() );
01167 if ( !fontColor.isValid() )
01168 {
01169 fontColor = lyr.textColor;
01170 }
01171 }
01172
01173 QVariant dataDefinedBold = palGeometry->dataDefinedValues().value( QgsPalLayerSettings::Bold );
01174 if ( dataDefinedBold.isValid() )
01175 {
01176 fontForLabel.setBold(( bool )dataDefinedBold.toInt() );
01177 }
01178
01179 QVariant dataDefinedItalic = palGeometry->dataDefinedValues().value( QgsPalLayerSettings::Italic );
01180 if ( dataDefinedItalic.isValid() )
01181 {
01182 fontForLabel.setItalic(( bool ) dataDefinedItalic.toInt() );
01183 }
01184
01185 QVariant dataDefinedUnderline = palGeometry->dataDefinedValues().value( QgsPalLayerSettings::Underline );
01186 if ( dataDefinedUnderline.isValid() )
01187 {
01188 fontForLabel.setUnderline(( bool ) dataDefinedUnderline.toInt() );
01189 }
01190
01191 QVariant dataDefinedStrikeout = palGeometry->dataDefinedValues().value( QgsPalLayerSettings::Strikeout );
01192 if ( dataDefinedStrikeout.isValid() )
01193 {
01194 fontForLabel.setStrikeOut(( bool ) dataDefinedStrikeout.toInt() );
01195 }
01196
01197 QVariant dataDefinedFontFamily = palGeometry->dataDefinedValues().value( QgsPalLayerSettings::Family );
01198 if ( dataDefinedFontFamily.isValid() )
01199 {
01200 fontForLabel.setFamily( dataDefinedFontFamily.toString() );
01201 }
01202
01203 QVariant dataDefinedBufferSize = palGeometry->dataDefinedValues().value( QgsPalLayerSettings::BufferSize );
01204 if ( dataDefinedBufferSize.isValid() )
01205 {
01206 bufferSize = dataDefinedBufferSize.toDouble();
01207 }
01208
01209
01210 QVariant dataDefinedBufferColor = palGeometry->dataDefinedValues().value( QgsPalLayerSettings::BufferColor );
01211 if ( dataDefinedBufferColor.isValid() )
01212 {
01213 bufferColor.setNamedColor( dataDefinedBufferColor.toString() );
01214 if ( !bufferColor.isValid() )
01215 {
01216 bufferColor = lyr.bufferColor;
01217 }
01218 }
01219
01220 if ( lyr.bufferSize != 0 )
01221 drawLabel( *it, painter, fontForLabel, fontColor, xform, bufferSize, bufferColor, true );
01222
01223 drawLabel( *it, painter, fontForLabel, fontColor, xform );
01224
01225 if ( mLabelSearchTree )
01226 {
01227 mLabelSearchTree->insertLabel( *it, QString( palGeometry->strId() ).toInt(), ( *it )->getLayerName() );
01228 }
01229 }
01230
01231 QgsDebugMsg( QString( "LABELING draw: %1 ms" ).arg( t.elapsed() ) );
01232
01233 delete problem;
01234 delete labels;
01235
01236
01237 QHash<QgsVectorLayer*, QgsPalLayerSettings>::iterator lit;
01238 for ( lit = mActiveLayers.begin(); lit != mActiveLayers.end(); ++lit )
01239 {
01240 QgsPalLayerSettings& lyr = lit.value();
01241 for ( QList<QgsPalGeometry*>::iterator git = lyr.geometries.begin(); git != lyr.geometries.end(); ++git )
01242 delete *git;
01243 lyr.geometries.clear();
01244 }
01245
01246
01247 QHash<QgsVectorLayer*, QgsDiagramLayerSettings>::iterator dIt = mActiveDiagramLayers.begin();
01248 for ( ; dIt != mActiveDiagramLayers.end(); ++dIt )
01249 {
01250 QgsDiagramLayerSettings& dls = dIt.value();
01251 for ( QList<QgsPalGeometry*>::iterator git = dls.geometries.begin(); git != dls.geometries.end(); ++git )
01252 {
01253 delete *git;
01254 }
01255 dls.geometries.clear();
01256 }
01257 }
01258
01259 QList<QgsLabelPosition> QgsPalLabeling::labelsAtPosition( const QgsPoint& p )
01260 {
01261 QList<QgsLabelPosition> positions;
01262
01263 QList<QgsLabelPosition*> positionPointers;
01264 if ( mLabelSearchTree )
01265 {
01266 mLabelSearchTree->label( p, positionPointers );
01267 QList<QgsLabelPosition*>::const_iterator pointerIt = positionPointers.constBegin();
01268 for ( ; pointerIt != positionPointers.constEnd(); ++pointerIt )
01269 {
01270 positions.push_back( QgsLabelPosition( **pointerIt ) );
01271 }
01272 }
01273
01274 return positions;
01275 }
01276
01277 void QgsPalLabeling::numCandidatePositions( int& candPoint, int& candLine, int& candPolygon )
01278 {
01279 candPoint = mCandPoint;
01280 candLine = mCandLine;
01281 candPolygon = mCandPolygon;
01282 }
01283
01284 void QgsPalLabeling::setNumCandidatePositions( int candPoint, int candLine, int candPolygon )
01285 {
01286 mCandPoint = candPoint;
01287 mCandLine = candLine;
01288 mCandPolygon = candPolygon;
01289 }
01290
01291 void QgsPalLabeling::setSearchMethod( QgsPalLabeling::Search s )
01292 {
01293 mSearch = s;
01294 }
01295
01296 QgsPalLabeling::Search QgsPalLabeling::searchMethod() const
01297 {
01298 return mSearch;
01299 }
01300
01301 void QgsPalLabeling::drawLabelCandidateRect( pal::LabelPosition* lp, QPainter* painter, const QgsMapToPixel* xform )
01302 {
01303 QgsPoint outPt = xform->transform( lp->getX(), lp->getY() );
01304 QgsPoint outPt2 = xform->transform( lp->getX() + lp->getWidth(), lp->getY() + lp->getHeight() );
01305
01306 painter->save();
01307 painter->translate( QPointF( outPt.x(), outPt.y() ) );
01308 painter->rotate( -lp->getAlpha() * 180 / M_PI );
01309 QRectF rect( 0, 0, outPt2.x() - outPt.x(), outPt2.y() - outPt.y() );
01310 painter->drawRect( rect );
01311 painter->restore();
01312
01313
01314 rect.moveTo( outPt.x(), outPt.y() );
01315 mCandidates.append( QgsLabelCandidate( rect, lp->getCost() * 1000 ) );
01316
01317
01318 if ( lp->getNextPart() )
01319 drawLabelCandidateRect( lp->getNextPart(), painter, xform );
01320 }
01321
01322 void QgsPalLabeling::drawLabel( pal::LabelPosition* label, QPainter* painter, const QFont& f, const QColor& c, const QgsMapToPixel* xform, double bufferSize,
01323 const QColor& bufferColor, bool drawBuffer )
01324 {
01325 QgsPoint outPt = xform->transform( label->getX(), label->getY() );
01326
01327
01328 const QgsPalLayerSettings& lyr = layer( QString::fromUtf8( label->getLayerName() ) );
01329 QString text = (( QgsPalGeometry* )label->getFeaturePart()->getUserGeometry() )->text();
01330 QString txt = ( label->getPartId() == -1 ? text : QString( text[label->getPartId()] ) );
01331
01332
01333 if ( !txt.isEmpty() && lyr.placement == QgsPalLayerSettings::Line &&
01334 lyr.addDirectionSymbol )
01335 {
01336 if ( label->getReversed() )
01337 {
01338 txt.prepend( "<" );
01339 }
01340 else
01341 {
01342 txt.append( ">" );
01343 }
01344 }
01345
01346
01347
01348 QStringList multiLineList;
01349 if ( !lyr.wrapChar.isEmpty() )
01350 multiLineList = txt.split( lyr.wrapChar );
01351 else
01352 multiLineList = txt.split( "\n" );
01353
01354 for ( int i = 0; i < multiLineList.size(); ++i )
01355 {
01356 painter->save();
01357 painter->translate( QPointF( outPt.x(), outPt.y() ) );
01358 painter->rotate( -label->getAlpha() * 180 / M_PI );
01359
01360
01361
01362 painter->scale( 1.0 / lyr.rasterCompressFactor, 1.0 / lyr.rasterCompressFactor );
01363
01364 double yMultiLineOffset = ( multiLineList.size() - 1 - i ) * lyr.fontMetrics->height();
01365 painter->translate( QPointF( 0, - lyr.fontMetrics->descent() - yMultiLineOffset ) );
01366
01367 if ( drawBuffer )
01368 {
01369
01370 drawLabelBuffer( painter, multiLineList.at( i ), f, bufferSize * lyr.vectorScaleFactor * lyr.rasterCompressFactor , bufferColor );
01371 }
01372 else
01373 {
01374
01375 QPainterPath path;
01376 path.addText( 0, 0, f, multiLineList.at( i ) );
01377 painter->setPen( Qt::NoPen );
01378 painter->setBrush( c );
01379 painter->drawPath( path );
01380 }
01381 painter->restore();
01382
01383 if ( label->getNextPart() )
01384 drawLabel( label->getNextPart(), painter, f, c, xform, bufferSize, bufferColor, drawBuffer );
01385 }
01386 }
01387
01388
01389 void QgsPalLabeling::drawLabelBuffer( QPainter* p, QString text, const QFont& font, double size, QColor color )
01390 {
01391 QPainterPath path;
01392 path.addText( 0, 0, font, text );
01393 QPen pen( color );
01394 pen.setWidthF( size );
01395 p->setPen( pen );
01396 p->setBrush( color );
01397 p->drawPath( path );
01398 }
01399
01400 QgsLabelingEngineInterface* QgsPalLabeling::clone()
01401 {
01402 QgsPalLabeling* lbl = new QgsPalLabeling();
01403 lbl->mShowingAllLabels = mShowingAllLabels;
01404 lbl->mShowingCandidates = mShowingCandidates;
01405 return lbl;
01406 }