24 #include <pal/feature.h>
25 #include <pal/layer.h>
26 #include <pal/palgeometry.h>
27 #include <pal/palexception.h>
28 #include <pal/problem.h>
29 #include <pal/labelposition.h>
37 #include <QFontMetrics>
58 QgsPalGeometry(
int id, QString text, GEOSGeometry* g ): mG( g ), mText( text ), mId( id ), mInfo( NULL ), mIsDiagram( false )
60 mStrId = QByteArray::number(
id );
65 if ( mG ) GEOSGeom_destroy( mG );
71 GEOSGeometry* getGeosGeometry()
75 void releaseGeosGeometry( GEOSGeometry* )
80 const char*
strId() {
return mStrId.data(); }
81 QString
text() {
return mText; }
83 pal::LabelInfo* info( QFontMetricsF* fm,
const QgsMapToPixel* xform,
double fontScale )
85 if ( mInfo )
return mInfo;
91 mInfo =
new pal::LabelInfo( mText.count(), ptSize.
y() - ptZero.
y() );
92 for (
int i = 0; i < mText.count(); i++ )
94 mInfo->char_info[i].chr = mText[i].unicode();
96 mInfo->char_info[i].width = ptSize.
x() - ptZero.
x();
101 const QMap< QgsPalLayerSettings::DataDefinedProperties, QVariant >&
dataDefinedValues()
const {
return mDataDefinedValues; }
127 : palLayer( NULL ), fontMetrics( NULL ), ct( NULL )
197 return QColor( r, g, b );
214 for (
int i = 0; i < 15; ++i )
217 QVariant propertyValue;
218 if ( it == propertyMap.constEnd() )
220 propertyValue = QVariant();
226 layer->
setCustomProperty(
"labeling/dataDefinedProperty" + QString::number( i ), propertyValue );
231 QMap< QgsPalLayerSettings::DataDefinedProperties, int >& propertyMap )
233 QVariant propertyField = layer->
customProperty(
"labeling/dataDefinedProperty" + QString::number( p ) );
237 if ( propertyField.isValid() )
239 fieldIndex = propertyField.toInt( &conversionOk );
242 propertyMap.insert( p, fieldIndex );
273 if ( layer->
customProperty(
"labeling" ).toString() != QString(
"pal" ) )
279 QString fontFamily = layer->
customProperty(
"labeling/fontFamily" ).toString();
280 double fontSize = layer->
customProperty(
"labeling/fontSize" ).toDouble();
281 int fontWeight = layer->
customProperty(
"labeling/fontWeight" ).toInt();
282 bool fontItalic = layer->
customProperty(
"labeling/fontItalic" ).toBool();
283 textFont = QFont( fontFamily, fontSize, fontWeight, fontItalic );
372 double length = geom->
length();
375 return ( length >= ( minSize * mapUnitsPerMM ) );
380 double area = geom->
area();
383 return ( sqrt( area ) >= ( minSize * mapUnitsPerMM ) );
400 QRectF labelRect = fm->boundingRect( text );
409 QStringList multiLineSplit = text.split(
"\n" );
412 for (
int i = 0; i < multiLineSplit.size(); ++i )
414 double width = fm->width( multiLineSplit.at( i ) );
424 labelX = qAbs( ptSize.
x() -
ptZero.
x() );
425 labelY = qAbs( ptSize.
y() -
ptZero.
y() );
431 double labelX, labelY;
440 if ( size.isValid() )
442 double sizeDouble = size.toDouble();
443 if ( sizeDouble <= 0 )
447 labelFont.setPixelSize(
sizeToPixel( sizeDouble, context ) );
449 QFontMetricsF labelFontMetrics( labelFont );
462 GEOSGeometry* geos_geom = geom->
asGeos();
463 if ( geos_geom == NULL )
472 bool dataDefinedPosition =
false;
473 bool dataDefinedRotation =
false;
474 double xPos = 0.0, yPos = 0.0,
angle = 0.0;
484 xPos = f.
attributeMap().value( *dPosXIt ).toDouble( &ddXPos );
485 yPos = f.
attributeMap().value( *dPosYIt ).toDouble( &ddYPos );
487 if ( ddXPos && ddYPos )
489 dataDefinedPosition =
true;
498 QString haliString = f.
attributeMap().value( *haliIt ).toString();
499 if ( haliString.compare(
"Center", Qt::CaseInsensitive ) == 0 )
501 xdiff -= labelX / 2.0;
503 else if ( haliString.compare(
"Right", Qt::CaseInsensitive ) == 0 )
513 QString valiString = f.
attributeMap().value( *valiIt ).toString();
514 if ( valiString.compare(
"Bottom", Qt::CaseInsensitive ) != 0 )
516 if ( valiString.compare(
"Top", Qt::CaseInsensitive ) == 0 || valiString.compare(
"Cap", Qt::CaseInsensitive ) == 0 )
522 QFontMetrics labelFontMetrics( labelFont );
523 double descentRatio = labelFontMetrics.descent() / labelFontMetrics.height();
525 if ( valiString.compare(
"Base", Qt::CaseInsensitive ) == 0 )
527 ydiff -= labelY * descentRatio;
529 else if ( valiString.compare(
"Half", Qt::CaseInsensitive ) == 0 )
531 ydiff -= labelY * descentRatio;
532 ydiff -= labelY * 0.5 * ( 1 - descentRatio );
542 dataDefinedRotation =
true;
545 double xd = xdiff * cos(
angle ) - ydiff * sin(
angle );
546 double yd = xdiff * sin(
angle ) + ydiff * cos(
angle );
573 if ( !
palLayer->registerFeature( lbl->
strId(), lbl, labelX, labelY, labelText.toUtf8().constData(),
574 xPos, yPos, dataDefinedPosition,
angle, dataDefinedRotation ) )
577 catch ( std::exception* e )
579 QgsDebugMsg( QString(
"Ignoring feature %1 due PAL exception: " ).arg( f.
id() ) + QString::fromLatin1( e->what() ) );
590 double distance =
dist;
594 distance = f.
attributeMap().value( *dDistIt ).toDouble();
607 feat->setDistLabel( qAbs(
ptOne.
x() -
ptZero.
x() )* distance );
630 return (
int )( pixelSize + 0.5 );
637 : mMapRenderer( NULL ), mPal( NULL )
646 switch ( p.getSearch() )
691 if ( fldIndex == -1 )
693 attrIndices.insert( fldIndex );
696 QMap< QgsPalLayerSettings::DataDefinedProperties, int >::const_iterator dIt = lyrTmp.
dataDefinedProperties.constBegin();
699 attrIndices.insert( dIt.value() );
708 Arrangement arrangement;
717 default: Q_ASSERT(
"unsupported placement" && 0 );
return 0;
break;
721 double priority = 1 - lyr.
priority / 10.0;
722 double min_scale = -1, max_scale = -1;
729 Layer* l =
mPal->addLayer( layer->
id().toUtf8().data(),
730 min_scale, max_scale, arrangement,
731 METER, priority, lyr.
obstacle,
true, true );
737 l->setLabelMode( lyr.
labelPerPart ? Layer::LabelPerFeaturePart : Layer::LabelPerFeature );
766 Layer* l =
mPal->addLayer( layer->
id().append(
"d" ).toUtf8().data(), -1, -1, pal::Arrangement( s->
placement ), METER, s->
priority, s->
obstacle,
true, true );
788 QHash<QgsVectorLayer*, QgsDiagramLayerSettings>::iterator layerIt =
mActiveDiagramLayers.find( layer );
799 geom->
transform( *( layerIt.value().ct ) );
802 GEOSGeometry* geos_geom = geom->
asGeos();
803 if ( geos_geom == 0 )
813 layerIt.value().geometries.append( lbl );
815 double diagramWidth = 0;
816 double diagramHeight = 0;
821 if ( diagSize.isValid() )
823 diagramWidth = diagSize.width();
824 diagramHeight = diagSize.height();
829 QList<int>::const_iterator diagAttIt = diagramAttrib.constBegin();
830 for ( ; diagAttIt != diagramAttrib.constEnd(); ++diagAttIt )
837 int ddColX = layerIt.value().xPosColumn;
838 int ddColY = layerIt.value().yPosColumn;
841 bool ddPos = ( ddColX >= 0 && ddColY >= 0 );
846 ddPosX = feat.
attributeMap()[ddColX].toDouble( &posXOk ) - diagramWidth / 2.0;
847 ddPosY = feat.
attributeMap()[ddColY].toDouble( &posYOk ) - diagramHeight / 2.0;
848 if ( !posXOk || !posYOk )
865 if ( !layerIt.value().palLayer->registerFeature( lbl->
strId(), lbl, diagramWidth, diagramHeight,
"", ddPosX, ddPosY, ddPos ) )
870 catch ( std::exception* e )
872 QgsDebugMsg( QString(
"Ignoring feature %1 due PAL exception: " ).arg( feat.
id() ) + QString::fromLatin1( e->what() ) );
876 pal::Feature* palFeat = layerIt.value().palLayer->getFeature( lbl->
strId() );
877 QgsPoint ptZero = layerIt.value().xform->toMapCoordinates( 0, 0 );
878 QgsPoint ptOne = layerIt.value().xform->toMapCoordinates( 1, 0 );
879 palFeat->setDistLabel( qAbs( ptOne.
x() - ptZero.
x() ) * layerIt.value().dist );
897 case Chain: s = CHAIN;
break;
901 case Falp: s = FALP;
break;
903 mPal->setSearch( s );
923 QHash<QgsVectorLayer*, QgsPalLayerSettings>::iterator lit;
926 if ( lit.key() && lit.key()->id() == layerName )
938 QPainter* painter = context.
painter();
954 std::list<LabelPosition*>* labels;
955 pal::Problem* problem;
958 problem =
mPal->extractProblem( scale, bbox );
960 catch ( std::exception& e )
962 QgsDebugMsg(
"PAL EXCEPTION :-( " + QString::fromLatin1( e.what() ) );
975 painter->setPen( QColor( 0, 0, 0, 64 ) );
976 painter->setBrush( Qt::NoBrush );
977 for (
int i = 0; i < problem->getNumFeatures(); i++ )
979 for (
int j = 0; j < problem->getFeatureCandidateCount( i ); j++ )
981 pal::LabelPosition* lp = problem->getFeatureCandidate( i, j );
991 QgsDebugMsg( QString(
"LABELING work: %1 ms ... labels# %2" ).arg( t.elapsed() ).arg( labels->size() ) );
994 painter->setRenderHint( QPainter::Antialiasing );
997 std::list<LabelPosition*>::iterator it = labels->begin();
998 for ( ; it != labels->end(); ++it )
1007 QString layerNameUtf8 = QString::fromUtf8(( *it )->getLayerName() );
1014 if ( dit.key() && dit.key()->id().append(
"d" ) == layerNameUtf8 )
1017 dit.value().renderer->renderDiagram( palGeometry->
diagramAttributes(), context, QPointF( outPt.
x(), outPt.
y() ) );
1025 QString layerId = layerNameUtf8;
1041 if ( dataDefinedSize.isValid() )
1043 fontForLabel.setPixelSize( lyr.
sizeToPixel( dataDefinedSize.toDouble(), context ) );
1047 if ( dataDefinedColor.isValid() )
1049 fontColor.setNamedColor( dataDefinedColor.toString() );
1050 if ( !fontColor.isValid() )
1057 if ( dataDefinedBold.isValid() )
1059 fontForLabel.setBold((
bool )dataDefinedBold.toInt() );
1063 if ( dataDefinedItalic.isValid() )
1065 fontForLabel.setItalic((
bool ) dataDefinedItalic.toInt() );
1069 if ( dataDefinedUnderline.isValid() )
1071 fontForLabel.setUnderline((
bool ) dataDefinedUnderline.toInt() );
1075 if ( dataDefinedStrikeout.isValid() )
1077 fontForLabel.setStrikeOut((
bool ) dataDefinedStrikeout.toInt() );
1081 if ( dataDefinedFontFamily.isValid() )
1083 fontForLabel.setFamily( dataDefinedFontFamily.toString() );
1087 if ( dataDefinedBufferSize.isValid() )
1089 bufferSize = dataDefinedBufferSize.toDouble();
1094 if ( dataDefinedBufferColor.isValid() )
1096 bufferColor.setNamedColor( dataDefinedBufferColor.toString() );
1097 if ( !bufferColor.isValid() )
1104 drawLabel( *it, painter, fontForLabel, fontColor, xform, bufferSize, bufferColor,
true );
1106 drawLabel( *it, painter, fontForLabel, fontColor, xform );
1114 QgsDebugMsg( QString(
"LABELING draw: %1 ms" ).arg( t.elapsed() ) );
1120 QHash<QgsVectorLayer*, QgsPalLayerSettings>::iterator lit;
1124 for ( QList<QgsPalGeometry*>::iterator git = lyr.
geometries.begin(); git != lyr.
geometries.end(); ++git )
1134 for ( QList<QgsPalGeometry*>::iterator git = dls.
geometries.begin(); git != dls.
geometries.end(); ++git )
1144 QList<QgsLabelPosition> positions;
1146 QList<QgsLabelPosition*> positionPointers;
1150 QList<QgsLabelPosition*>::const_iterator pointerIt = positionPointers.constBegin();
1151 for ( ; pointerIt != positionPointers.constEnd(); ++pointerIt )
1187 QgsPoint outPt2 = xform->
transform( lp->getX() + lp->getWidth(), lp->getY() + lp->getHeight() );
1190 painter->translate( QPointF( outPt.
x(), outPt.
y() ) );
1191 painter->rotate( -lp->getAlpha() * 180 /
M_PI );
1192 QRectF rect( 0, 0, outPt2.
x() - outPt.
x(), outPt2.
y() - outPt.
y() );
1193 painter->drawRect( rect );
1197 rect.moveTo( outPt.
x(), outPt.
y() );
1201 if ( lp->getNextPart() )
1206 const QColor& bufferColor,
bool drawBuffer )
1213 QString text = ((
QgsPalGeometry* )label->getFeaturePart()->getUserGeometry() )->text();
1214 QString txt = ( label->getPartId() == -1 ? text : QString( text[label->getPartId()] ) );
1220 if ( label->getReversed() )
1232 QStringList multiLineList;
1235 multiLineList = txt.split(
"\n" );
1239 multiLineList << txt;
1242 for (
int i = 0; i < multiLineList.size(); ++i )
1245 painter->translate( QPointF( outPt.
x(), outPt.
y() ) );
1246 painter->rotate( -label->getAlpha() * 180 /
M_PI );
1252 double yMultiLineOffset = ( multiLineList.size() - 1 - i ) * lyr.
fontMetrics->height();
1253 painter->translate( QPointF( 0, - lyr.
fontMetrics->descent() - yMultiLineOffset ) );
1264 path.addText( 0, 0, f, multiLineList.at( i ) );
1265 painter->setPen( Qt::NoPen );
1266 painter->setBrush( c );
1267 painter->drawPath( path );
1271 if ( label->getNextPart() )
1272 drawLabel( label->getNextPart(), painter, f, c, xform, bufferSize, bufferColor, drawBuffer );
1280 path.addText( 0, 0, font, text );
1282 pen.setWidthF( size );
1284 p->setBrush( color );
1285 p->drawPath( path );