LCOV - code coverage report
Current view: top level - core/labeling - qgsvectorlayerlabeling.cpp (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 0 354 0.0 %
Date: 2021-03-26 12:19:53 Functions: 0 0 -
Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /***************************************************************************
       2                 :            :     qgsvectorlayerlabeling.cpp
       3                 :            :     ---------------------
       4                 :            :     begin                : September 2015
       5                 :            :     copyright            : (C) 2015 by Martin Dobias
       6                 :            :     email                : wonder dot sk at gmail dot com
       7                 :            :  ***************************************************************************
       8                 :            :  *                                                                         *
       9                 :            :  *   This program is free software; you can redistribute it and/or modify  *
      10                 :            :  *   it under the terms of the GNU General Public License as published by  *
      11                 :            :  *   the Free Software Foundation; either version 2 of the License, or     *
      12                 :            :  *   (at your option) any later version.                                   *
      13                 :            :  *                                                                         *
      14                 :            :  ***************************************************************************/
      15                 :            : #include "qgsvectorlayerlabeling.h"
      16                 :            : 
      17                 :            : #include "qgspallabeling.h"
      18                 :            : #include "qgsrulebasedlabeling.h"
      19                 :            : #include "qgsvectorlayer.h"
      20                 :            : #include "qgssymbollayerutils.h"
      21                 :            : #include "qgssymbollayer.h"
      22                 :            : #include "qgsmarkersymbollayer.h"
      23                 :            : #include "qgis.h"
      24                 :            : #include "qgsstyleentityvisitor.h"
      25                 :            : 
      26                 :            : 
      27                 :          0 : QgsAbstractVectorLayerLabeling *QgsAbstractVectorLayerLabeling::create( const QDomElement &element, const QgsReadWriteContext &context )
      28                 :            : {
      29                 :          0 :   QString type = element.attribute( QStringLiteral( "type" ) );
      30                 :          0 :   if ( type == QLatin1String( "rule-based" ) )
      31                 :            :   {
      32                 :          0 :     return QgsRuleBasedLabeling::create( element, context );
      33                 :            :   }
      34                 :          0 :   else if ( type == QLatin1String( "simple" ) )
      35                 :            :   {
      36                 :          0 :     return QgsVectorLayerSimpleLabeling::create( element, context );
      37                 :            :   }
      38                 :            :   else
      39                 :            :   {
      40                 :          0 :     return nullptr;
      41                 :            :   }
      42                 :          0 : }
      43                 :            : 
      44                 :          0 : bool QgsAbstractVectorLayerLabeling::accept( QgsStyleEntityVisitorInterface * ) const
      45                 :            : {
      46                 :          0 :   return true;
      47                 :            : }
      48                 :            : 
      49                 :          0 : QgsVectorLayerLabelProvider *QgsVectorLayerSimpleLabeling::provider( QgsVectorLayer *layer ) const
      50                 :            : {
      51                 :          0 :   return new QgsVectorLayerLabelProvider( layer, QString(), false, mSettings.get() );
      52                 :          0 : }
      53                 :            : 
      54                 :          0 : QgsVectorLayerSimpleLabeling::QgsVectorLayerSimpleLabeling( const QgsPalLayerSettings &settings )
      55                 :          0 :   : mSettings( new QgsPalLayerSettings( settings ) )
      56                 :          0 : {
      57                 :            : 
      58                 :          0 : }
      59                 :            : 
      60                 :          0 : QString QgsVectorLayerSimpleLabeling::type() const
      61                 :            : {
      62                 :          0 :   return QStringLiteral( "simple" );
      63                 :            : }
      64                 :            : 
      65                 :          0 : QgsAbstractVectorLayerLabeling *QgsVectorLayerSimpleLabeling::clone() const
      66                 :            : {
      67                 :          0 :   return new QgsVectorLayerSimpleLabeling( *mSettings );
      68                 :          0 : }
      69                 :            : 
      70                 :          0 : QDomElement QgsVectorLayerSimpleLabeling::save( QDomDocument &doc, const QgsReadWriteContext &context ) const
      71                 :            : {
      72                 :          0 :   QDomElement elem = doc.createElement( QStringLiteral( "labeling" ) );
      73                 :          0 :   elem.setAttribute( QStringLiteral( "type" ), QStringLiteral( "simple" ) );
      74                 :          0 :   elem.appendChild( mSettings->writeXml( doc, context ) );
      75                 :          0 :   return elem;
      76                 :          0 : }
      77                 :            : 
      78                 :          0 : QgsPalLayerSettings QgsVectorLayerSimpleLabeling::settings( const QString &providerId ) const
      79                 :            : {
      80                 :          0 :   Q_UNUSED( providerId )
      81                 :          0 :   return *mSettings;
      82                 :            : }
      83                 :            : 
      84                 :          0 : bool QgsVectorLayerSimpleLabeling::accept( QgsStyleEntityVisitorInterface *visitor ) const
      85                 :            : {
      86                 :          0 :   if ( mSettings )
      87                 :            :   {
      88                 :          0 :     QgsStyleLabelSettingsEntity entity( *mSettings );
      89                 :          0 :     if ( !visitor->visit( &entity ) )
      90                 :          0 :       return false;
      91                 :          0 :   }
      92                 :          0 :   return true;
      93                 :          0 : }
      94                 :            : 
      95                 :          0 : bool QgsVectorLayerSimpleLabeling::requiresAdvancedEffects() const
      96                 :            : {
      97                 :          0 :   return mSettings->format().containsAdvancedEffects();
      98                 :            : }
      99                 :            : 
     100                 :          0 : QgsVectorLayerSimpleLabeling *QgsVectorLayerSimpleLabeling::create( const QDomElement &element, const QgsReadWriteContext &context )
     101                 :            : {
     102                 :          0 :   QDomElement settingsElem = element.firstChildElement( QStringLiteral( "settings" ) );
     103                 :          0 :   if ( !settingsElem.isNull() )
     104                 :            :   {
     105                 :          0 :     QgsPalLayerSettings settings;
     106                 :          0 :     settings.readXml( settingsElem, context );
     107                 :          0 :     return new QgsVectorLayerSimpleLabeling( settings );
     108                 :          0 :   }
     109                 :            : 
     110                 :          0 :   return new QgsVectorLayerSimpleLabeling( QgsPalLayerSettings() );
     111                 :          0 : }
     112                 :            : 
     113                 :          0 : QPointF quadOffsetToSldAnchor( QgsPalLayerSettings::QuadrantPosition quadrantPosition )
     114                 :            : {
     115                 :          0 :   double quadOffsetX = 0.5, quadOffsetY = 0.5;
     116                 :            : 
     117                 :            :   // adjust quadrant offset of labels
     118                 :          0 :   switch ( quadrantPosition )
     119                 :            :   {
     120                 :            :     case QgsPalLayerSettings::QuadrantAboveLeft:
     121                 :          0 :       quadOffsetX = 1;
     122                 :          0 :       quadOffsetY = 0;
     123                 :          0 :       break;
     124                 :            :     case QgsPalLayerSettings::QuadrantAbove:
     125                 :          0 :       quadOffsetX = 0.5;
     126                 :          0 :       quadOffsetY = 0;
     127                 :          0 :       break;
     128                 :            :     case QgsPalLayerSettings::QuadrantAboveRight:
     129                 :          0 :       quadOffsetX = 0;
     130                 :          0 :       quadOffsetY = 0;
     131                 :          0 :       break;
     132                 :            :     case QgsPalLayerSettings::QuadrantLeft:
     133                 :          0 :       quadOffsetX = 1;
     134                 :          0 :       quadOffsetY = 0.5;
     135                 :          0 :       break;
     136                 :            :     case QgsPalLayerSettings::QuadrantRight:
     137                 :          0 :       quadOffsetX = 0;
     138                 :          0 :       quadOffsetY = 0.5;
     139                 :          0 :       break;
     140                 :            :     case QgsPalLayerSettings::QuadrantBelowLeft:
     141                 :          0 :       quadOffsetX = 1;
     142                 :          0 :       quadOffsetY = 1;
     143                 :          0 :       break;
     144                 :            :     case QgsPalLayerSettings::QuadrantBelow:
     145                 :          0 :       quadOffsetX = 0.5;
     146                 :          0 :       quadOffsetY = 1;
     147                 :          0 :       break;
     148                 :            :     case QgsPalLayerSettings::QuadrantBelowRight:
     149                 :          0 :       quadOffsetX = 0;
     150                 :          0 :       quadOffsetY = 1.0;
     151                 :          0 :       break;
     152                 :            :     case QgsPalLayerSettings::QuadrantOver:
     153                 :          0 :       break;
     154                 :            :   }
     155                 :            : 
     156                 :          0 :   return QPointF( quadOffsetX, quadOffsetY );
     157                 :            : }
     158                 :            : 
     159                 :            : /*
     160                 :            :  * This is not a generic function encoder, just enough to encode the label case control functions
     161                 :            :  */
     162                 :          0 : void appendSimpleFunction( QDomDocument &doc, QDomElement &parent, const QString &name, const QString &attribute )
     163                 :            : {
     164                 :          0 :   QDomElement function = doc.createElement( QStringLiteral( "ogc:Function" ) );
     165                 :          0 :   function.setAttribute( QStringLiteral( "name" ), name );
     166                 :          0 :   parent.appendChild( function );
     167                 :          0 :   QDomElement property = doc.createElement( QStringLiteral( "ogc:PropertyName" ) );
     168                 :          0 :   property.appendChild( doc.createTextNode( attribute ) );
     169                 :          0 :   function.appendChild( property );
     170                 :          0 : }
     171                 :            : 
     172                 :          0 : std::unique_ptr<QgsMarkerSymbolLayer> backgroundToMarkerLayer( const QgsTextBackgroundSettings &settings )
     173                 :            : {
     174                 :          0 :   std::unique_ptr<QgsMarkerSymbolLayer> layer;
     175                 :          0 :   switch ( settings.type() )
     176                 :            :   {
     177                 :            :     case QgsTextBackgroundSettings::ShapeSVG:
     178                 :            :     {
     179                 :          0 :       QgsSvgMarkerSymbolLayer *svg = new QgsSvgMarkerSymbolLayer( settings.svgFile() );
     180                 :          0 :       svg->setStrokeWidth( settings.strokeWidth() );
     181                 :          0 :       svg->setStrokeWidthUnit( settings.strokeWidthUnit() );
     182                 :          0 :       layer.reset( svg );
     183                 :          0 :       break;
     184                 :            :     }
     185                 :            :     case QgsTextBackgroundSettings::ShapeMarkerSymbol:
     186                 :            :     {
     187                 :            :       // just grab the first layer and hope for the best
     188                 :          0 :       if ( settings.markerSymbol() && settings.markerSymbol()->symbolLayerCount() > 0 )
     189                 :            :       {
     190                 :          0 :         layer.reset( static_cast< QgsMarkerSymbolLayer * >( settings.markerSymbol()->symbolLayer( 0 )->clone() ) );
     191                 :          0 :         break;
     192                 :            :       }
     193                 :            :       FALLTHROUGH // not set, just go with the default
     194                 :          0 :     }
     195                 :            :     case QgsTextBackgroundSettings::ShapeCircle:
     196                 :            :     case QgsTextBackgroundSettings::ShapeEllipse:
     197                 :            :     case QgsTextBackgroundSettings::ShapeRectangle:
     198                 :            :     case QgsTextBackgroundSettings::ShapeSquare:
     199                 :            :     {
     200                 :          0 :       QgsSimpleMarkerSymbolLayer *marker = new QgsSimpleMarkerSymbolLayer();
     201                 :            :       // default value
     202                 :          0 :       QgsSimpleMarkerSymbolLayerBase::Shape shape = QgsSimpleMarkerSymbolLayerBase::Diamond;
     203                 :          0 :       switch ( settings.type() )
     204                 :            :       {
     205                 :            :         case QgsTextBackgroundSettings::ShapeCircle:
     206                 :            :         case QgsTextBackgroundSettings::ShapeEllipse:
     207                 :          0 :           shape = QgsSimpleMarkerSymbolLayerBase::Circle;
     208                 :          0 :           break;
     209                 :            :         case QgsTextBackgroundSettings::ShapeRectangle:
     210                 :            :         case QgsTextBackgroundSettings::ShapeSquare:
     211                 :          0 :           shape = QgsSimpleMarkerSymbolLayerBase::Square;
     212                 :          0 :           break;
     213                 :            :         case QgsTextBackgroundSettings::ShapeSVG:
     214                 :            :         case QgsTextBackgroundSettings::ShapeMarkerSymbol:
     215                 :          0 :           break;
     216                 :            :       }
     217                 :            : 
     218                 :          0 :       marker->setShape( shape );
     219                 :          0 :       marker->setStrokeWidth( settings.strokeWidth() );
     220                 :          0 :       marker->setStrokeWidthUnit( settings.strokeWidthUnit() );
     221                 :          0 :       layer.reset( marker );
     222                 :            :     }
     223                 :          0 :   }
     224                 :          0 :   layer->setEnabled( true );
     225                 :            :   // a marker does not have a size x and y, just a size (and it should be at least one)
     226                 :          0 :   QSizeF size = settings.size();
     227                 :          0 :   layer->setSize( std::max( 1., std::max( size.width(), size.height() ) ) );
     228                 :          0 :   layer->setSizeUnit( settings.sizeUnit() );
     229                 :            :   // fill and stroke
     230                 :          0 :   QColor fillColor = settings.fillColor();
     231                 :          0 :   QColor strokeColor = settings.strokeColor();
     232                 :          0 :   if ( settings.opacity() < 1 )
     233                 :            :   {
     234                 :          0 :     int alpha = std::round( settings.opacity() * 255 );
     235                 :          0 :     fillColor.setAlpha( alpha );
     236                 :          0 :     strokeColor.setAlpha( alpha );
     237                 :          0 :   }
     238                 :          0 :   layer->setFillColor( fillColor );
     239                 :          0 :   layer->setStrokeColor( strokeColor );
     240                 :            :   // rotation
     241                 :          0 :   if ( settings.rotationType() == QgsTextBackgroundSettings::RotationFixed )
     242                 :            :   {
     243                 :          0 :     layer->setAngle( settings.rotation() );
     244                 :          0 :   }
     245                 :            :   // offset
     246                 :          0 :   layer->setOffset( settings.offset() );
     247                 :          0 :   layer->setOffsetUnit( settings.offsetUnit() );
     248                 :            : 
     249                 :          0 :   return layer;
     250                 :          0 : }
     251                 :            : 
     252                 :          0 : void QgsAbstractVectorLayerLabeling::writeTextSymbolizer( QDomNode &parent, QgsPalLayerSettings &settings, const QVariantMap &props ) const
     253                 :            : {
     254                 :          0 :   QDomDocument doc = parent.ownerDocument();
     255                 :            : 
     256                 :            :   // text symbolizer
     257                 :          0 :   QDomElement textSymbolizerElement = doc.createElement( QStringLiteral( "se:TextSymbolizer" ) );
     258                 :          0 :   parent.appendChild( textSymbolizerElement );
     259                 :            : 
     260                 :            :   // label
     261                 :          0 :   QgsTextFormat format = settings.format();
     262                 :          0 :   QFont font = format.font();
     263                 :          0 :   QDomElement labelElement = doc.createElement( QStringLiteral( "se:Label" ) );
     264                 :          0 :   textSymbolizerElement.appendChild( labelElement );
     265                 :          0 :   if ( settings.isExpression )
     266                 :            :   {
     267                 :          0 :     labelElement.appendChild( doc.createComment( QStringLiteral( "SE Export for %1 not implemented yet" ).arg( settings.getLabelExpression()->dump() ) ) );
     268                 :          0 :     labelElement.appendChild( doc.createTextNode( "Placeholder" ) );
     269                 :          0 :   }
     270                 :            :   else
     271                 :            :   {
     272                 :          0 :     QgsStringUtils::Capitalization capitalization = format.capitalization();
     273                 :          0 :     if ( capitalization == QgsStringUtils::MixedCase && font.capitalization() != QFont::MixedCase )
     274                 :          0 :       capitalization = static_cast< QgsStringUtils::Capitalization >( font.capitalization() );
     275                 :          0 :     if ( capitalization == QgsStringUtils::AllUppercase )
     276                 :            :     {
     277                 :          0 :       appendSimpleFunction( doc, labelElement, QStringLiteral( "strToUpperCase" ), settings.fieldName );
     278                 :          0 :     }
     279                 :          0 :     else if ( capitalization == QgsStringUtils::AllLowercase )
     280                 :            :     {
     281                 :          0 :       appendSimpleFunction( doc, labelElement, QStringLiteral( "strToLowerCase" ), settings.fieldName );
     282                 :          0 :     }
     283                 :          0 :     else if ( capitalization == QgsStringUtils::ForceFirstLetterToCapital )
     284                 :            :     {
     285                 :          0 :       appendSimpleFunction( doc, labelElement, QStringLiteral( "strCapitalize" ), settings.fieldName );
     286                 :          0 :     }
     287                 :            :     else
     288                 :            :     {
     289                 :          0 :       QDomElement propertyNameElement = doc.createElement( QStringLiteral( "ogc:PropertyName" ) );
     290                 :          0 :       propertyNameElement.appendChild( doc.createTextNode( settings.fieldName ) );
     291                 :          0 :       labelElement.appendChild( propertyNameElement );
     292                 :          0 :     }
     293                 :            :   }
     294                 :            : 
     295                 :            :   // font
     296                 :          0 :   QDomElement fontElement = doc.createElement( QStringLiteral( "se:Font" ) );
     297                 :          0 :   textSymbolizerElement.appendChild( fontElement );
     298                 :          0 :   fontElement.appendChild( QgsSymbolLayerUtils::createSvgParameterElement( doc, QStringLiteral( "font-family" ), font.family() ) );
     299                 :          0 :   double fontSize = QgsSymbolLayerUtils::rescaleUom( format.size(), format.sizeUnit(), props );
     300                 :          0 :   fontElement.appendChild( QgsSymbolLayerUtils::createSvgParameterElement( doc, QStringLiteral( "font-size" ), QString::number( fontSize ) ) );
     301                 :          0 :   if ( format.font().italic() )
     302                 :            :   {
     303                 :          0 :     fontElement.appendChild( QgsSymbolLayerUtils::createSvgParameterElement( doc, QStringLiteral( "font-style" ), QStringLiteral( "italic" ) ) );
     304                 :          0 :   }
     305                 :          0 :   if ( format.font().bold() )
     306                 :            :   {
     307                 :          0 :     fontElement.appendChild( QgsSymbolLayerUtils::createSvgParameterElement( doc, QStringLiteral( "font-weight" ), QStringLiteral( "bold" ) ) );
     308                 :          0 :   }
     309                 :            : 
     310                 :            :   // label placement
     311                 :          0 :   QDomElement labelPlacement = doc.createElement( QStringLiteral( "se:LabelPlacement" ) );
     312                 :          0 :   textSymbolizerElement.appendChild( labelPlacement );
     313                 :          0 :   double maxDisplacement = 0;
     314                 :          0 :   double repeatDistance = 0;
     315                 :          0 :   switch ( settings.placement )
     316                 :            :   {
     317                 :            :     case QgsPalLayerSettings::OverPoint:
     318                 :            :     {
     319                 :          0 :       QDomElement pointPlacement = doc.createElement( "se:PointPlacement" );
     320                 :          0 :       labelPlacement.appendChild( pointPlacement );
     321                 :            :       // anchor point
     322                 :          0 :       QPointF anchor = quadOffsetToSldAnchor( settings.quadOffset );
     323                 :          0 :       QgsSymbolLayerUtils::createAnchorPointElement( doc, pointPlacement, anchor );
     324                 :            :       // displacement
     325                 :          0 :       if ( settings.xOffset > 0 || settings.yOffset > 0 )
     326                 :            :       {
     327                 :          0 :         QgsUnitTypes::RenderUnit offsetUnit =  settings.offsetUnits;
     328                 :          0 :         double dx = QgsSymbolLayerUtils::rescaleUom( settings.xOffset, offsetUnit, props );
     329                 :          0 :         double dy = QgsSymbolLayerUtils::rescaleUom( settings.yOffset, offsetUnit, props );
     330                 :          0 :         QgsSymbolLayerUtils::createDisplacementElement( doc, pointPlacement, QPointF( dx, dy ) );
     331                 :          0 :       }
     332                 :            :       // rotation
     333                 :          0 :       if ( settings.angleOffset != 0 )
     334                 :            :       {
     335                 :          0 :         QDomElement rotation = doc.createElement( "se:Rotation" );
     336                 :          0 :         pointPlacement.appendChild( rotation );
     337                 :          0 :         rotation.appendChild( doc.createTextNode( QString::number( settings.angleOffset ) ) );
     338                 :          0 :       }
     339                 :          0 :     }
     340                 :          0 :     break;
     341                 :            :     case QgsPalLayerSettings::AroundPoint:
     342                 :            :     case QgsPalLayerSettings::OrderedPositionsAroundPoint:
     343                 :            :     {
     344                 :          0 :       QDomElement pointPlacement = doc.createElement( "se:PointPlacement" );
     345                 :          0 :       labelPlacement.appendChild( pointPlacement );
     346                 :            : 
     347                 :            :       // SLD cannot do either, but let's do a best effort setting the distance using
     348                 :            :       // anchor point and displacement
     349                 :          0 :       QgsSymbolLayerUtils::createAnchorPointElement( doc, pointPlacement, QPointF( 0, 0.5 ) );
     350                 :          0 :       QgsUnitTypes::RenderUnit distUnit = settings.distUnits;
     351                 :          0 :       double radius = QgsSymbolLayerUtils::rescaleUom( settings.dist, distUnit, props );
     352                 :          0 :       double offset = std::sqrt( radius * radius / 2 ); // make it start top/right
     353                 :          0 :       maxDisplacement = radius + 1; // lock the distance
     354                 :          0 :       QgsSymbolLayerUtils::createDisplacementElement( doc, pointPlacement, QPointF( offset, offset ) );
     355                 :          0 :     }
     356                 :          0 :     break;
     357                 :            :     case QgsPalLayerSettings::Horizontal:
     358                 :            :     case QgsPalLayerSettings::Free:
     359                 :            :     case QgsPalLayerSettings::OutsidePolygons:
     360                 :            :     {
     361                 :            :       // still a point placement (for "free" it's a fallback, there is no SLD equivalent)
     362                 :          0 :       QDomElement pointPlacement = doc.createElement( "se:PointPlacement" );
     363                 :          0 :       labelPlacement.appendChild( pointPlacement );
     364                 :          0 :       QgsSymbolLayerUtils::createAnchorPointElement( doc, pointPlacement, QPointF( 0.5, 0.5 ) );
     365                 :          0 :       QgsUnitTypes::RenderUnit distUnit = settings.distUnits;
     366                 :          0 :       double dist = QgsSymbolLayerUtils::rescaleUom( settings.dist, distUnit, props );
     367                 :          0 :       QgsSymbolLayerUtils::createDisplacementElement( doc, pointPlacement, QPointF( 0, dist ) );
     368                 :            :       break;
     369                 :          0 :     }
     370                 :            :     case QgsPalLayerSettings::Line:
     371                 :            :     case QgsPalLayerSettings::Curved:
     372                 :            :     case QgsPalLayerSettings::PerimeterCurved:
     373                 :            :     {
     374                 :          0 :       QDomElement linePlacement = doc.createElement( "se:LinePlacement" );
     375                 :          0 :       labelPlacement.appendChild( linePlacement );
     376                 :            : 
     377                 :            :       // perpendicular distance if required
     378                 :          0 :       if ( settings.dist > 0 )
     379                 :            :       {
     380                 :          0 :         QgsUnitTypes::RenderUnit distUnit = settings.distUnits;
     381                 :          0 :         double dist = QgsSymbolLayerUtils::rescaleUom( settings.dist, distUnit, props );
     382                 :          0 :         QDomElement perpendicular = doc.createElement( "se:PerpendicularOffset" );
     383                 :          0 :         linePlacement.appendChild( perpendicular );
     384                 :          0 :         perpendicular.appendChild( doc.createTextNode( qgsDoubleToString( dist, 2 ) ) );
     385                 :          0 :       }
     386                 :            : 
     387                 :            :       // repeat distance if required
     388                 :          0 :       if ( settings.repeatDistance > 0 )
     389                 :            :       {
     390                 :          0 :         QDomElement repeat = doc.createElement( "se:Repeat" );
     391                 :          0 :         linePlacement.appendChild( repeat );
     392                 :          0 :         repeat.appendChild( doc.createTextNode( QStringLiteral( "true" ) ) );
     393                 :          0 :         QDomElement gap = doc.createElement( "se:Gap" );
     394                 :          0 :         linePlacement.appendChild( gap );
     395                 :          0 :         repeatDistance = QgsSymbolLayerUtils::rescaleUom( settings.repeatDistance, settings.repeatDistanceUnit, props );
     396                 :          0 :         gap.appendChild( doc.createTextNode( qgsDoubleToString( repeatDistance, 2 ) ) );
     397                 :          0 :       }
     398                 :            : 
     399                 :            :       // always generalized
     400                 :          0 :       QDomElement generalize = doc.createElement( "se:GeneralizeLine" );
     401                 :          0 :       linePlacement.appendChild( generalize );
     402                 :          0 :       generalize.appendChild( doc.createTextNode( QStringLiteral( "true" ) ) );
     403                 :          0 :     }
     404                 :          0 :     break;
     405                 :            :   }
     406                 :            : 
     407                 :            :   // halo
     408                 :          0 :   QgsTextBufferSettings buffer = format.buffer();
     409                 :          0 :   if ( buffer.enabled() )
     410                 :            :   {
     411                 :          0 :     QDomElement haloElement = doc.createElement( QStringLiteral( "se:Halo" ) );
     412                 :          0 :     textSymbolizerElement.appendChild( haloElement );
     413                 :            : 
     414                 :          0 :     QDomElement radiusElement = doc.createElement( QStringLiteral( "se:Radius" ) );
     415                 :          0 :     haloElement.appendChild( radiusElement );
     416                 :            :     // the SLD uses a radius, which is actually half of the link thickness the buffer size specifies
     417                 :          0 :     double radius = QgsSymbolLayerUtils::rescaleUom( buffer.size(), buffer.sizeUnit(), props ) / 2;
     418                 :          0 :     radiusElement.appendChild( doc.createTextNode( qgsDoubleToString( radius ) ) );
     419                 :            : 
     420                 :          0 :     QDomElement fillElement = doc.createElement( QStringLiteral( "se:Fill" ) );
     421                 :          0 :     haloElement.appendChild( fillElement );
     422                 :          0 :     fillElement.appendChild( QgsSymbolLayerUtils::createSvgParameterElement( doc, QStringLiteral( "fill" ), buffer.color().name() ) );
     423                 :          0 :     if ( buffer.opacity() != 1 )
     424                 :            :     {
     425                 :          0 :       fillElement.appendChild( QgsSymbolLayerUtils::createSvgParameterElement( doc, QStringLiteral( "fill-opacity" ), QString::number( buffer.opacity() ) ) );
     426                 :          0 :     }
     427                 :          0 :   }
     428                 :            : 
     429                 :            :   // fill
     430                 :          0 :   QDomElement fillElement = doc.createElement( QStringLiteral( "se:Fill" ) );
     431                 :          0 :   textSymbolizerElement.appendChild( fillElement );
     432                 :          0 :   fillElement.appendChild( QgsSymbolLayerUtils::createSvgParameterElement( doc, QStringLiteral( "fill" ), format.color().name() ) );
     433                 :          0 :   if ( format.opacity() != 1 )
     434                 :            :   {
     435                 :          0 :     fillElement.appendChild( QgsSymbolLayerUtils::createSvgParameterElement( doc, QStringLiteral( "fill-opacity" ), QString::number( format.opacity() ) ) );
     436                 :          0 :   }
     437                 :            : 
     438                 :            :   // background graphic (not supported by SE 1.1, but supported by the GeoTools ecosystem as an extension)
     439                 :          0 :   QgsTextBackgroundSettings background = format.background();
     440                 :          0 :   if ( background.enabled() )
     441                 :            :   {
     442                 :          0 :     std::unique_ptr<QgsMarkerSymbolLayer> layer = backgroundToMarkerLayer( background );
     443                 :          0 :     layer->writeSldMarker( doc, textSymbolizerElement, props );
     444                 :          0 :   }
     445                 :            : 
     446                 :            :   // priority and zIndex, the default values are 0 and 5 in qgis (and between 0 and 10),
     447                 :            :   // in the GeoTools ecosystem there is a single priority value set at 1000 by default
     448                 :          0 :   if ( settings.priority != 5 || settings.zIndex > 0 )
     449                 :            :   {
     450                 :          0 :     QDomElement priorityElement = doc.createElement( QStringLiteral( "se:Priority" ) );
     451                 :          0 :     textSymbolizerElement.appendChild( priorityElement );
     452                 :          0 :     int priority = 500 + 1000 * settings.zIndex + ( settings.priority - 5 ) * 100;
     453                 :          0 :     if ( settings.priority == 0 && settings.zIndex > 0 )
     454                 :            :     {
     455                 :            :       // small adjustment to make sure labels in z index n+1 are all above level n despite the priority value
     456                 :          0 :       priority += 1;
     457                 :          0 :     }
     458                 :          0 :     priorityElement.appendChild( doc.createTextNode( QString::number( priority ) ) );
     459                 :          0 :   }
     460                 :            : 
     461                 :            :   // vendor options for text appearance
     462                 :          0 :   if ( font.underline() )
     463                 :            :   {
     464                 :          0 :     QDomElement vo = QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "underlineText" ), QStringLiteral( "true" ) );
     465                 :          0 :     textSymbolizerElement.appendChild( vo );
     466                 :          0 :   }
     467                 :          0 :   if ( font.strikeOut() )
     468                 :            :   {
     469                 :          0 :     QDomElement vo =  QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "strikethroughText" ), QStringLiteral( "true" ) );
     470                 :          0 :     textSymbolizerElement.appendChild( vo );
     471                 :          0 :   }
     472                 :            :   // vendor options for text positioning
     473                 :          0 :   if ( maxDisplacement > 0 )
     474                 :            :   {
     475                 :          0 :     QDomElement vo =  QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "maxDisplacement" ), qgsDoubleToString( maxDisplacement, 2 ) );
     476                 :          0 :     textSymbolizerElement.appendChild( vo );
     477                 :          0 :   }
     478                 :          0 :   if ( settings.placement == QgsPalLayerSettings::Curved || settings.placement == QgsPalLayerSettings::PerimeterCurved )
     479                 :            :   {
     480                 :          0 :     QDomElement vo =  QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "followLine" ), QStringLiteral( "true" ) );
     481                 :          0 :     textSymbolizerElement.appendChild( vo );
     482                 :          0 :     if ( settings.maxCurvedCharAngleIn > 0 || settings.maxCurvedCharAngleOut > 0 )
     483                 :            :     {
     484                 :            :       // SLD has no notion for this, the GeoTools ecosystem can only do a single angle
     485                 :          0 :       double angle = std::min( std::fabs( settings.maxCurvedCharAngleIn ), std::fabs( settings.maxCurvedCharAngleOut ) );
     486                 :          0 :       QDomElement vo =  QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "maxAngleDelta" ), qgsDoubleToString( angle ) );
     487                 :          0 :       textSymbolizerElement.appendChild( vo );
     488                 :          0 :     }
     489                 :          0 :   }
     490                 :          0 :   if ( repeatDistance > 0 )
     491                 :            :   {
     492                 :          0 :     QDomElement vo =  QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "repeat" ), qgsDoubleToString( repeatDistance, 2 ) );
     493                 :          0 :     textSymbolizerElement.appendChild( vo );
     494                 :          0 :   }
     495                 :            :   // miscellaneous options
     496                 :          0 :   if ( settings.displayAll )
     497                 :            :   {
     498                 :          0 :     QDomElement vo =  QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "conflictResolution" ), QStringLiteral( "false" ) );
     499                 :          0 :     textSymbolizerElement.appendChild( vo );
     500                 :          0 :   }
     501                 :          0 :   if ( settings.upsidedownLabels == QgsPalLayerSettings::ShowAll )
     502                 :            :   {
     503                 :          0 :     QDomElement vo =  QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "forceLeftToRight" ), QStringLiteral( "false" ) );
     504                 :          0 :     textSymbolizerElement.appendChild( vo );
     505                 :          0 :   }
     506                 :          0 :   if ( settings.lineSettings().mergeLines() )
     507                 :            :   {
     508                 :          0 :     QDomElement vo =  QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "group" ), QStringLiteral( "yes" ) );
     509                 :          0 :     textSymbolizerElement.appendChild( vo );
     510                 :          0 :     if ( settings.labelPerPart )
     511                 :            :     {
     512                 :          0 :       QDomElement vo =  QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "labelAllGroup" ), QStringLiteral( "true" ) );
     513                 :          0 :       textSymbolizerElement.appendChild( vo );
     514                 :          0 :     }
     515                 :          0 :   }
     516                 :            :   // background symbol resize handling
     517                 :          0 :   if ( background.enabled() )
     518                 :            :   {
     519                 :            :     // enable resizing if needed
     520                 :          0 :     switch ( background.sizeType() )
     521                 :            :     {
     522                 :            :       case QgsTextBackgroundSettings::SizeBuffer:
     523                 :            :       {
     524                 :          0 :         QString resizeType;
     525                 :          0 :         if ( background.type() == QgsTextBackgroundSettings::ShapeRectangle || background.type() == QgsTextBackgroundSettings::ShapeEllipse )
     526                 :            :         {
     527                 :          0 :           resizeType = QStringLiteral( "stretch" );
     528                 :          0 :         }
     529                 :            :         else
     530                 :            :         {
     531                 :          0 :           resizeType = QStringLiteral( "proportional" );
     532                 :            :         }
     533                 :          0 :         QDomElement voResize =  QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "graphic-resize" ), resizeType );
     534                 :          0 :         textSymbolizerElement.appendChild( voResize );
     535                 :            : 
     536                 :            :         // now hadle margin
     537                 :          0 :         QSizeF size = background.size();
     538                 :          0 :         if ( size.width() > 0 || size.height() > 0 )
     539                 :            :         {
     540                 :          0 :           double x = QgsSymbolLayerUtils::rescaleUom( size.width(), background.sizeUnit(), props );
     541                 :          0 :           double y = QgsSymbolLayerUtils::rescaleUom( size.height(), background.sizeUnit(), props );
     542                 :            :           // in case of ellipse qgis pads the size generously to make sure the text is inside the ellipse
     543                 :            :           // the following seems to do the trick and keep visual output similar
     544                 :          0 :           if ( background.type() == QgsTextBackgroundSettings::ShapeEllipse )
     545                 :            :           {
     546                 :          0 :             x += fontSize / 2;
     547                 :          0 :             y += fontSize;
     548                 :          0 :           }
     549                 :          0 :           QString resizeSpec = QString( "%1 %2" ).arg( qgsDoubleToString( x, 2 ), qgsDoubleToString( y, 2 ) );
     550                 :          0 :           QDomElement voMargin =  QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "graphic-margin" ), resizeSpec );
     551                 :          0 :           textSymbolizerElement.appendChild( voMargin );
     552                 :          0 :         }
     553                 :            :         break;
     554                 :          0 :       }
     555                 :            :       case QgsTextBackgroundSettings::SizeFixed:
     556                 :            :       case QgsTextBackgroundSettings::SizePercent:
     557                 :            :         // nothing to do here
     558                 :          0 :         break;
     559                 :            :     }
     560                 :          0 :   }
     561                 :          0 : }
     562                 :            : 
     563                 :            : 
     564                 :          0 : void QgsVectorLayerSimpleLabeling::toSld( QDomNode &parent, const QVariantMap &props ) const
     565                 :            : {
     566                 :            : 
     567                 :          0 :   if ( mSettings->drawLabels )
     568                 :            :   {
     569                 :          0 :     QDomDocument doc = parent.ownerDocument();
     570                 :            : 
     571                 :          0 :     QDomElement ruleElement = doc.createElement( QStringLiteral( "se:Rule" ) );
     572                 :          0 :     parent.appendChild( ruleElement );
     573                 :            : 
     574                 :            :     // scale dependencies
     575                 :          0 :     if ( mSettings->scaleVisibility )
     576                 :            :     {
     577                 :          0 :       QVariantMap scaleProps = QVariantMap();
     578                 :            :       // tricky here, the max scale is expressed as its denominator, but it's still the max scale
     579                 :            :       // in other words, the smallest scale denominator....
     580                 :          0 :       scaleProps.insert( "scaleMinDenom", qgsDoubleToString( mSettings->maximumScale ) );
     581                 :          0 :       scaleProps.insert( "scaleMaxDenom", qgsDoubleToString( mSettings->minimumScale ) );
     582                 :          0 :       QgsSymbolLayerUtils::applyScaleDependency( doc, ruleElement, scaleProps );
     583                 :          0 :     }
     584                 :            : 
     585                 :          0 :     writeTextSymbolizer( ruleElement, *mSettings, props );
     586                 :          0 :   }
     587                 :            : 
     588                 :            : 
     589                 :          0 : }
     590                 :            : 
     591                 :          0 : void QgsVectorLayerSimpleLabeling::setSettings( QgsPalLayerSettings *settings, const QString &providerId )
     592                 :            : {
     593                 :          0 :   Q_UNUSED( providerId )
     594                 :            : 
     595                 :          0 :   if ( mSettings.get() == settings )
     596                 :          0 :     return;
     597                 :            : 
     598                 :          0 :   mSettings.reset( settings );
     599                 :          0 : }

Generated by: LCOV version 1.14