Skip to content

Commit 9f63f49

Browse files
committedDec 3, 2019
Move label obstacle settings out to their own class, and monkey patch around
to maintain current API QgsPalLayerSettings is way too heavy, and we need to start refactoring this into smaller atomic components
1 parent f145fa9 commit 9f63f49

18 files changed

+391
-66
lines changed
 
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/************************************************************************
2+
* This file has been generated automatically from *
3+
* *
4+
* src/core/qgslabelobstaclesettings.h *
5+
* *
6+
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
7+
************************************************************************/
8+
9+
10+
11+
class QgsLabelObstacleSettings
12+
{
13+
%Docstring
14+
15+
Contains settings related to how the label engine treats features as obstacles
16+
17+
.. versionadded:: 3.10.2
18+
%End
19+
20+
%TypeHeaderCode
21+
#include "qgslabelobstaclesettings.h"
22+
%End
23+
public:
24+
25+
enum ObstacleType
26+
{
27+
PolygonInterior,
28+
PolygonBoundary,
29+
PolygonWhole
30+
};
31+
32+
bool isObstacle() const;
33+
%Docstring
34+
Returns ``True`` if the features are obstacles to labels of other layers.
35+
36+
.. seealso:: :py:func:`setIsObstacle`
37+
38+
.. seealso:: :py:func:`factor`
39+
40+
.. seealso:: :py:func:`type`
41+
%End
42+
43+
void setIsObstacle( bool isObstacle );
44+
%Docstring
45+
Sets whether features are obstacles to labels of other layers.
46+
47+
.. seealso:: :py:func:`isObstacle`
48+
49+
.. seealso:: :py:func:`factor`
50+
51+
.. seealso:: :py:func:`type`
52+
%End
53+
54+
double factor() const;
55+
%Docstring
56+
Returns the obstacle factor, where 1.0 = default, < 1.0 more likely to be covered by labels,
57+
> 1.0 less likely to be covered
58+
59+
.. seealso:: :py:func:`setFactor`
60+
61+
.. seealso:: :py:func:`isObstacle`
62+
63+
.. seealso:: :py:func:`type`
64+
%End
65+
66+
void setFactor( double factor );
67+
%Docstring
68+
Sets the obstacle ``factor``, where 1.0 = default, < 1.0 more likely to be covered by labels,
69+
> 1.0 less likely to be covered
70+
71+
.. seealso:: :py:func:`factor`
72+
73+
.. seealso:: :py:func:`isObstacle`
74+
75+
.. seealso:: :py:func:`type`
76+
%End
77+
78+
ObstacleType type() const;
79+
%Docstring
80+
Returns how features act as obstacles for labels.
81+
82+
.. seealso:: :py:func:`setType`
83+
84+
.. seealso:: :py:func:`isObstacle`
85+
86+
.. seealso:: :py:func:`factor`
87+
%End
88+
89+
void setType( ObstacleType type );
90+
%Docstring
91+
Controls how features act as obstacles for labels.
92+
93+
.. seealso:: :py:func:`type`
94+
95+
.. seealso:: :py:func:`isObstacle`
96+
97+
.. seealso:: :py:func:`factor`
98+
%End
99+
100+
};
101+
102+
/************************************************************************
103+
* This file has been generated automatically from *
104+
* *
105+
* src/core/qgslabelobstaclesettings.h *
106+
* *
107+
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
108+
************************************************************************/

‎python/core/auto_generated/qgspallabeling.sip.in

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@ Constructor for QgsLabelPosition
7676
bool isUnplaced;
7777
};
7878

79-
8079
class QgsPalLayerSettings
8180
{
8281

@@ -469,11 +468,18 @@ Returns the QgsExpression for this label settings. May be ``None`` if isExpressi
469468

470469
double minFeatureSize;
471470

472-
bool obstacle;
473471

474-
double obstacleFactor;
472+
%Property( name = obstacle, get = _getIsObstacle, set = _setIsObstacle )
473+
%Property( name = obstacleFactor, get = _getObstacleFactor, set = _setObstacleFactor )
474+
%Property( name = obstacleType, get = _getObstacleType, set = _setObstacleType )
475+
476+
bool _getIsObstacle() const;
477+
void _setIsObstacle( bool obstacle );
478+
double _getObstacleFactor() const;
479+
void _setObstacleFactor( double factor );
480+
ObstacleType _getObstacleType() const;
481+
void _setObstacleType( ObstacleType type );
475482

476-
ObstacleType obstacleType;
477483

478484
double zIndex;
479485

@@ -585,6 +591,25 @@ Ownership of ``callout`` is transferred to the settings.
585591
.. versionadded:: 3.10
586592
%End
587593

594+
595+
QgsLabelObstacleSettings &obstacleSettings();
596+
%Docstring
597+
Returns the label obstacle settings.
598+
599+
.. seealso:: :py:func:`setObstacleSettings`
600+
601+
.. versionadded:: 3.10.2
602+
%End
603+
604+
void setObstacleSettings( const QgsLabelObstacleSettings &settings );
605+
%Docstring
606+
Sets the label obstacle ``settings``.
607+
608+
.. seealso:: :py:func:`obstacleSettings`
609+
610+
.. versionadded:: 3.10.2
611+
%End
612+
588613
static QPixmap labelSettingsPreviewPixmap( const QgsPalLayerSettings &settings, QSize size, const QString &previewText = QString(), int padding = 0 );
589614
%Docstring
590615
Returns a pixmap preview for label ``settings``.
@@ -738,6 +763,7 @@ allowed to be split apart (e.g., Arabic and Indic based scripts)
738763

739764
};
740765

766+
741767
/************************************************************************
742768
* This file has been generated automatically from *
743769
* *

‎python/core/core_auto.sip

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@
8888
%Include auto_generated/qgsinterval.sip
8989
%Include auto_generated/qgsjsonutils.sip
9090
%Include auto_generated/qgslabelingenginesettings.sip
91+
%Include auto_generated/qgslabelobstaclesettings.sip
9192
%Include auto_generated/qgslabelsearchtree.sip
9293
%Include auto_generated/qgslayerdefinition.sip
9394
%Include auto_generated/qgslegendrenderer.sip

‎scripts/sipify.pl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,10 @@ sub detect_non_method_member{
530530
write_output("SF1", "%Feature $1$2\n");
531531
next;
532532
}
533+
if ($LINE =~ m/^\s*SIP_PROPERTY\((.*)\)$/){
534+
write_output("SF1", "%Property($1)\n");
535+
next;
536+
}
533537
if ($LINE =~ m/^\s*SIP_IF_FEATURE\( (\!?\w+) \)(.*)$/){
534538
write_output("SF2", "%If ($1)$2\n");
535539
next;

‎src/core/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -754,6 +754,7 @@ SET(QGIS_CORE_HDRS
754754
qgslabelfeature.h
755755
qgslabelingengine.h
756756
qgslabelingenginesettings.h
757+
qgslabelobstaclesettings.h
757758
qgslabelsearchtree.h
758759
qgslayerdefinition.h
759760
qgslegendrenderer.h

‎src/core/pal/layer.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ Layer::Layer( QgsAbstractLabelProvider *provider, const QString &name, QgsPalLay
4545
: mProvider( provider )
4646
, mName( name )
4747
, pal( pal )
48-
, mObstacleType( QgsPalLayerSettings::PolygonInterior )
4948
, mActive( active )
5049
, mLabelLayer( toLabel )
5150
, mDisplayAll( displayAll )

‎src/core/pal/layer.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -228,15 +228,15 @@ namespace pal
228228
* act as obstacles for labels.
229229
* \see setObstacleType
230230
*/
231-
QgsPalLayerSettings::ObstacleType obstacleType() const { return mObstacleType; }
231+
QgsLabelObstacleSettings::ObstacleType obstacleType() const { return mObstacleType; }
232232

233233
/**
234234
* Sets the obstacle type, which controls how features within the layer
235235
* act as obstacles for labels.
236236
* \param obstacleType new obstacle type
237237
* \see obstacleType
238238
*/
239-
void setObstacleType( QgsPalLayerSettings::ObstacleType obstacleType ) { mObstacleType = obstacleType; }
239+
void setObstacleType( QgsLabelObstacleSettings::ObstacleType obstacleType ) { mObstacleType = obstacleType; }
240240

241241
/**
242242
* Sets the layer's priority.
@@ -333,7 +333,7 @@ namespace pal
333333

334334
double mDefaultPriority;
335335

336-
QgsPalLayerSettings::ObstacleType mObstacleType;
336+
QgsLabelObstacleSettings::ObstacleType mObstacleType = QgsLabelObstacleSettings::PolygonBoundary;
337337
bool mActive;
338338
bool mLabelLayer;
339339
bool mDisplayAll;

‎src/core/qgis_sip.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,5 +251,9 @@
251251
#define SIP_MONKEYPATCH_SCOPEENUM
252252
#define SIP_MONKEYPATCH_SCOPEENUM_UNNEST(OUTSIDE_CLASS,FORMERNAME)
253253

254+
/*
255+
* Directive to define a Python property;
256+
*/
257+
#define SIP_PROPERTY(name,getter,setter)
254258

255259
#endif // QGIS_SIP_H

‎src/core/qgslabelingengine.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -620,7 +620,6 @@ QgsAbstractLabelProvider::QgsAbstractLabelProvider( QgsMapLayer *layer, const QS
620620
, mFlags( DrawLabels )
621621
, mPlacement( QgsPalLayerSettings::AroundPoint )
622622
, mPriority( 0.5 )
623-
, mObstacleType( QgsPalLayerSettings::PolygonInterior )
624623
, mUpsidedownLabels( QgsPalLayerSettings::Upright )
625624
{
626625
}

‎src/core/qgslabelingengine.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ class CORE_EXPORT QgsAbstractLabelProvider
142142
double priority() const { return mPriority; }
143143

144144
//! How the feature geometries will work as obstacles
145-
QgsPalLayerSettings::ObstacleType obstacleType() const { return mObstacleType; }
145+
QgsLabelObstacleSettings::ObstacleType obstacleType() const { return mObstacleType; }
146146

147147
//! How to handle labels that would be upside down
148148
QgsPalLayerSettings::UpsideDownLabels upsidedownLabels() const { return mUpsidedownLabels; }
@@ -166,7 +166,7 @@ class CORE_EXPORT QgsAbstractLabelProvider
166166
//! Default priority of labels
167167
double mPriority;
168168
//! Type of the obstacle of feature geometries
169-
QgsPalLayerSettings::ObstacleType mObstacleType;
169+
QgsLabelObstacleSettings::ObstacleType mObstacleType = QgsLabelObstacleSettings::PolygonBoundary;
170170
//! How to handle labels that would be upside down
171171
QgsPalLayerSettings::UpsideDownLabels mUpsidedownLabels;
172172
};

‎src/core/qgslabelobstaclesettings.h

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/***************************************************************************
2+
qgslabelobstaclesettings.h
3+
--------------------------
4+
Date : December 2019
5+
Copyright : (C) 2019 by Nyall Dawson
6+
Email : nyall dot dawson 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+
16+
#ifndef QGSLABELOBSTACLESETTINGS_H
17+
#define QGSLABELOBSTACLESETTINGS_H
18+
19+
#include "qgis_core.h"
20+
#include "qgis_sip.h"
21+
22+
/**
23+
* \ingroup core
24+
* \class QgsLabelObstacleSettings
25+
*
26+
* Contains settings related to how the label engine treats features as obstacles
27+
*
28+
* \since QGIS 3.10.2
29+
*/
30+
class CORE_EXPORT QgsLabelObstacleSettings
31+
{
32+
public:
33+
34+
/**
35+
* Valid obstacle types, which affect how features within the layer will act as obstacles
36+
* for labels.
37+
*/
38+
enum ObstacleType
39+
{
40+
PolygonInterior, /*!< avoid placing labels over interior of polygon (prefer placing labels totally
41+
outside or just slightly inside polygon) */
42+
PolygonBoundary, /*!< avoid placing labels over boundary of polygon (prefer placing outside or
43+
completely inside polygon) */
44+
PolygonWhole /*!< avoid placing labels over ANY part of polygon. Where PolygonInterior will prefer
45+
to place labels with the smallest area of intersection between the label and the polygon,
46+
PolygonWhole will penalise any label which intersects with the polygon by an equal amount, so that
47+
placing labels over any part of the polygon is avoided.*/
48+
};
49+
50+
/**
51+
* Returns TRUE if the features are obstacles to labels of other layers.
52+
* \see setIsObstacle()
53+
* \see factor()
54+
* \see type()
55+
*/
56+
bool isObstacle() const
57+
{
58+
return mIsObstacle;
59+
}
60+
61+
/**
62+
* Sets whether features are obstacles to labels of other layers.
63+
* \see isObstacle()
64+
* \see factor()
65+
* \see type()
66+
*/
67+
void setIsObstacle( bool isObstacle )
68+
{
69+
mIsObstacle = isObstacle;
70+
}
71+
72+
/**
73+
* Returns the obstacle factor, where 1.0 = default, < 1.0 more likely to be covered by labels,
74+
* > 1.0 less likely to be covered
75+
*
76+
* \see setFactor()
77+
* \see isObstacle()
78+
* \see type()
79+
*/
80+
double factor() const
81+
{
82+
return mObstacleFactor;
83+
}
84+
85+
/**
86+
* Sets the obstacle \a factor, where 1.0 = default, < 1.0 more likely to be covered by labels,
87+
* > 1.0 less likely to be covered
88+
*
89+
* \see factor()
90+
* \see isObstacle()
91+
* \see type()
92+
*/
93+
void setFactor( double factor )
94+
{
95+
mObstacleFactor = factor;
96+
}
97+
98+
/**
99+
* Returns how features act as obstacles for labels.
100+
* \see setType()
101+
* \see isObstacle()
102+
* \see factor()
103+
*/
104+
ObstacleType type() const
105+
{
106+
return mObstacleType;
107+
}
108+
109+
/**
110+
* Controls how features act as obstacles for labels.
111+
* \see type()
112+
* \see isObstacle()
113+
* \see factor()
114+
*/
115+
void setType( ObstacleType type )
116+
{
117+
mObstacleType = type;
118+
}
119+
120+
private:
121+
122+
bool mIsObstacle = true;
123+
double mObstacleFactor = 1.0;
124+
ObstacleType mObstacleType = PolygonBoundary;
125+
126+
};
127+
128+
#endif // QGSLABELOBSTACLESETTINGS_H

‎src/core/qgspallabeling.cpp

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -347,16 +347,15 @@ QgsPalLayerSettings &QgsPalLayerSettings::operator=( const QgsPalLayerSettings &
347347
minFeatureSize = s.minFeatureSize;
348348
limitNumLabels = s.limitNumLabels;
349349
maxNumLabels = s.maxNumLabels;
350-
obstacle = s.obstacle;
351-
obstacleFactor = s.obstacleFactor;
352-
obstacleType = s.obstacleType;
353350
zIndex = s.zIndex;
354351

355352
mFormat = s.mFormat;
356353
mDataDefinedProperties = s.mDataDefinedProperties;
357354

358355
mCallout.reset( s.mCallout ? s.mCallout->clone() : nullptr );
359356

357+
mObstacleSettings = s.mObstacleSettings;
358+
360359
geometryGenerator = s.geometryGenerator;
361360
geometryGeneratorEnabled = s.geometryGeneratorEnabled;
362361
geometryGeneratorType = s.geometryGeneratorType;
@@ -395,7 +394,7 @@ bool QgsPalLayerSettings::prepare( QgsRenderContext &context, QSet<QString> &att
395394

396395
mCurFields = fields;
397396

398-
if ( drawLabels || obstacle )
397+
if ( drawLabels || mObstacleSettings.isObstacle() )
399398
{
400399
if ( drawLabels )
401400
{
@@ -812,9 +811,9 @@ void QgsPalLayerSettings::readFromLayerCustomProperties( QgsVectorLayer *layer )
812811
minFeatureSize = layer->customProperty( QStringLiteral( "labeling/minFeatureSize" ) ).toDouble();
813812
limitNumLabels = layer->customProperty( QStringLiteral( "labeling/limitNumLabels" ), QVariant( false ) ).toBool();
814813
maxNumLabels = layer->customProperty( QStringLiteral( "labeling/maxNumLabels" ), QVariant( 2000 ) ).toInt();
815-
obstacle = layer->customProperty( QStringLiteral( "labeling/obstacle" ), QVariant( true ) ).toBool();
816-
obstacleFactor = layer->customProperty( QStringLiteral( "labeling/obstacleFactor" ), QVariant( 1.0 ) ).toDouble();
817-
obstacleType = static_cast< ObstacleType >( layer->customProperty( QStringLiteral( "labeling/obstacleType" ), QVariant( PolygonInterior ) ).toUInt() );
814+
mObstacleSettings.setIsObstacle( layer->customProperty( QStringLiteral( "labeling/obstacle" ), QVariant( true ) ).toBool() );
815+
mObstacleSettings.setFactor( layer->customProperty( QStringLiteral( "labeling/obstacleFactor" ), QVariant( 1.0 ) ).toDouble() );
816+
mObstacleSettings.setType( static_cast< QgsLabelObstacleSettings::ObstacleType >( layer->customProperty( QStringLiteral( "labeling/obstacleType" ), QVariant( PolygonInterior ) ).toUInt() ) );
818817
zIndex = layer->customProperty( QStringLiteral( "labeling/zIndex" ), QVariant( 0.0 ) ).toDouble();
819818

820819
mDataDefinedProperties.clear();
@@ -1038,9 +1037,9 @@ void QgsPalLayerSettings::readXml( const QDomElement &elem, const QgsReadWriteCo
10381037
minFeatureSize = renderingElem.attribute( QStringLiteral( "minFeatureSize" ) ).toDouble();
10391038
limitNumLabels = renderingElem.attribute( QStringLiteral( "limitNumLabels" ), QStringLiteral( "0" ) ).toInt();
10401039
maxNumLabels = renderingElem.attribute( QStringLiteral( "maxNumLabels" ), QStringLiteral( "2000" ) ).toInt();
1041-
obstacle = renderingElem.attribute( QStringLiteral( "obstacle" ), QStringLiteral( "1" ) ).toInt();
1042-
obstacleFactor = renderingElem.attribute( QStringLiteral( "obstacleFactor" ), QStringLiteral( "1" ) ).toDouble();
1043-
obstacleType = static_cast< ObstacleType >( renderingElem.attribute( QStringLiteral( "obstacleType" ), QString::number( PolygonInterior ) ).toUInt() );
1040+
mObstacleSettings.setIsObstacle( renderingElem.attribute( QStringLiteral( "obstacle" ), QStringLiteral( "1" ) ).toInt() );
1041+
mObstacleSettings.setFactor( renderingElem.attribute( QStringLiteral( "obstacleFactor" ), QStringLiteral( "1" ) ).toDouble() );
1042+
mObstacleSettings.setType( static_cast< QgsLabelObstacleSettings::ObstacleType >( renderingElem.attribute( QStringLiteral( "obstacleType" ), QString::number( PolygonInterior ) ).toUInt() ) );
10441043
zIndex = renderingElem.attribute( QStringLiteral( "zIndex" ), QStringLiteral( "0.0" ) ).toDouble();
10451044

10461045
QDomElement ddElem = elem.firstChildElement( QStringLiteral( "dd_properties" ) );
@@ -1185,9 +1184,9 @@ QDomElement QgsPalLayerSettings::writeXml( QDomDocument &doc, const QgsReadWrite
11851184
renderingElem.setAttribute( QStringLiteral( "minFeatureSize" ), minFeatureSize );
11861185
renderingElem.setAttribute( QStringLiteral( "limitNumLabels" ), limitNumLabels );
11871186
renderingElem.setAttribute( QStringLiteral( "maxNumLabels" ), maxNumLabels );
1188-
renderingElem.setAttribute( QStringLiteral( "obstacle" ), obstacle );
1189-
renderingElem.setAttribute( QStringLiteral( "obstacleFactor" ), obstacleFactor );
1190-
renderingElem.setAttribute( QStringLiteral( "obstacleType" ), static_cast< unsigned int >( obstacleType ) );
1187+
renderingElem.setAttribute( QStringLiteral( "obstacle" ), mObstacleSettings.isObstacle() );
1188+
renderingElem.setAttribute( QStringLiteral( "obstacleFactor" ), mObstacleSettings.factor() );
1189+
renderingElem.setAttribute( QStringLiteral( "obstacleType" ), static_cast< unsigned int >( mObstacleSettings.type() ) );
11911190
renderingElem.setAttribute( QStringLiteral( "zIndex" ), zIndex );
11921191

11931192
QDomElement ddElem = doc.createElement( QStringLiteral( "dd_properties" ) );
@@ -1583,9 +1582,9 @@ void QgsPalLayerSettings::registerFeature( const QgsFeature &f, QgsRenderContext
15831582
mCurFeat = &f;
15841583

15851584
// data defined is obstacle? calculate this first, to avoid wasting time working with obstacles we don't require
1586-
bool isObstacle = obstacle;
1585+
bool isObstacle = mObstacleSettings.isObstacle();
15871586
if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::IsObstacle ) )
1588-
isObstacle = mDataDefinedProperties.valueAsBool( QgsPalLayerSettings::IsObstacle, context.expressionContext(), obstacle ); // default to layer default
1587+
isObstacle = mDataDefinedProperties.valueAsBool( QgsPalLayerSettings::IsObstacle, context.expressionContext(), isObstacle ); // default to layer default
15891588

15901589
if ( !drawLabels )
15911590
{
@@ -2481,7 +2480,7 @@ void QgsPalLayerSettings::registerFeature( const QgsFeature &f, QgsRenderContext
24812480

24822481
( *labelFeature )->setIsObstacle( isObstacle );
24832482

2484-
double featObstacleFactor = obstacleFactor;
2483+
double featObstacleFactor = mObstacleSettings.factor();
24852484
if ( isObstacle && mDataDefinedProperties.isActive( QgsPalLayerSettings::ObstacleFactor ) )
24862485
{
24872486
context.expressionContext().setOriginalValueVariable( featObstacleFactor );
@@ -2566,7 +2565,7 @@ void QgsPalLayerSettings::registerObstacleFeature( const QgsFeature &f, QgsRende
25662565
( *obstacleFeature )->setIsObstacle( true );
25672566
( *obstacleFeature )->setFeature( f );
25682567

2569-
double featObstacleFactor = obstacleFactor;
2568+
double featObstacleFactor = mObstacleSettings.factor();
25702569
if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::ObstacleFactor ) )
25712570
{
25722571
context.expressionContext().setOriginalValueVariable( featObstacleFactor );

‎src/core/qgspallabeling.h

Lines changed: 42 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#include "qgssymbol.h"
4343
#include "qgstextrenderer.h"
4444
#include "qgspropertycollection.h"
45+
#include "qgslabelobstaclesettings.h"
4546

4647
namespace pal SIP_SKIP
4748
{
@@ -193,7 +194,6 @@ class CORE_EXPORT QgsLabelPosition
193194
bool isUnplaced = false;
194195
};
195196

196-
197197
/**
198198
* \ingroup core
199199
* \class QgsPalLayerSettings
@@ -311,7 +311,7 @@ class CORE_EXPORT QgsPalLayerSettings
311311
will be drawn with right alignment*/
312312
};
313313

314-
//TODO QGIS 4.0 - Move to QgsLabelingEngine
314+
//TODO QGIS 4.0 - Remove -- moved to QgsLabelEngineObstacleSettings
315315

316316
/**
317317
* Valid obstacle types, which affect how features within the layer will act as obstacles
@@ -885,27 +885,23 @@ class CORE_EXPORT QgsPalLayerSettings
885885
*/
886886
double minFeatureSize = 0;
887887

888-
/**
889-
* TRUE if features for layer are obstacles to labels of other layers.
890-
* \see obstacleFactor
891-
* \see obstacleType
892-
*/
893-
bool obstacle = true;
888+
// TODO QGIS 4.0 - remove this junk
894889

895-
/**
896-
* Obstacle factor, where 1.0 = default, < 1.0 more likely to be covered by labels,
897-
* > 1.0 less likely to be covered
898-
* \see obstacle
899-
* \see obstacleType
900-
*/
901-
double obstacleFactor = 1.0;
890+
#ifdef SIP_RUN
891+
SIP_PROPERTY( name = obstacle, get = _getIsObstacle, set = _setIsObstacle )
892+
SIP_PROPERTY( name = obstacleFactor, get = _getObstacleFactor, set = _setObstacleFactor )
893+
SIP_PROPERTY( name = obstacleType, get = _getObstacleType, set = _setObstacleType )
894+
#endif
902895

903-
/**
904-
* Controls how features act as obstacles for labels.
905-
* \see obstacle
906-
* \see obstacleFactor
907-
*/
908-
ObstacleType obstacleType = PolygonBoundary;
896+
///@cond PRIVATE
897+
bool _getIsObstacle() const { return mObstacleSettings.isObstacle(); }
898+
void _setIsObstacle( bool obstacle ) { mObstacleSettings.setIsObstacle( obstacle ); }
899+
double _getObstacleFactor() const { return mObstacleSettings.factor(); }
900+
void _setObstacleFactor( double factor ) { mObstacleSettings.setFactor( factor ); }
901+
ObstacleType _getObstacleType() const { return static_cast< ObstacleType>( mObstacleSettings.type() ); }
902+
void _setObstacleType( ObstacleType type ) { mObstacleSettings.setType( static_cast< QgsLabelObstacleSettings::ObstacleType>( type ) ); }
903+
904+
///@endcond
909905

910906
//! Z-Index of label, where labels with a higher z-index are rendered on top of labels with a lower z-index
911907
double zIndex = 0;
@@ -1023,6 +1019,28 @@ class CORE_EXPORT QgsPalLayerSettings
10231019
*/
10241020
void setCallout( QgsCallout *callout SIP_TRANSFER );
10251021

1022+
/**
1023+
* Returns the label obstacle settings.
1024+
* \see setObstacleSettings()
1025+
* \note Not available in Python bindings
1026+
* \since QGIS 3.10.2
1027+
*/
1028+
const QgsLabelObstacleSettings &obstacleSettings() const { return mObstacleSettings; } SIP_SKIP
1029+
1030+
/**
1031+
* Returns the label obstacle settings.
1032+
* \see setObstacleSettings()
1033+
* \since QGIS 3.10.2
1034+
*/
1035+
QgsLabelObstacleSettings &obstacleSettings() { return mObstacleSettings; }
1036+
1037+
/**
1038+
* Sets the label obstacle \a settings.
1039+
* \see obstacleSettings()
1040+
* \since QGIS 3.10.2
1041+
*/
1042+
void setObstacleSettings( const QgsLabelObstacleSettings &settings ) { mObstacleSettings = settings; }
1043+
10261044
/**
10271045
* Returns a pixmap preview for label \a settings.
10281046
* \param settings label settings
@@ -1126,6 +1144,8 @@ class CORE_EXPORT QgsPalLayerSettings
11261144

11271145
std::unique_ptr< QgsCallout > mCallout;
11281146

1147+
QgsLabelObstacleSettings mObstacleSettings;
1148+
11291149
QgsExpression mGeometryGeneratorExpression;
11301150

11311151
bool mRenderStarted = false;
@@ -1293,4 +1313,5 @@ class CORE_EXPORT QgsPalLabeling
12931313
friend class QgsPalLayerSettings;
12941314
};
12951315

1316+
12961317
#endif // QGSPALLABELING_H

‎src/core/qgsvectorlayerlabelprovider.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,11 +75,11 @@ void QgsVectorLayerLabelProvider::init()
7575
if ( mLayerGeometryType == QgsWkbTypes::PointGeometry && mRenderer )
7676
{
7777
//override obstacle type to treat any intersection of a label with the point symbol as a high cost conflict
78-
mObstacleType = QgsPalLayerSettings::PolygonWhole;
78+
mObstacleType = QgsLabelObstacleSettings::PolygonWhole;
7979
}
8080
else
8181
{
82-
mObstacleType = mSettings.obstacleType;
82+
mObstacleType = mSettings.obstacleSettings().type();
8383
}
8484

8585
mUpsidedownLabels = mSettings.upsidedownLabels;

‎src/gui/qgslabelinggui.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -287,11 +287,11 @@ void QgsLabelingGui::setLayer( QgsMapLayer *mapLayer )
287287
mOverrunDistanceUnitWidget->setMapUnitScale( mSettings.overrunDistanceMapUnitScale );
288288

289289
mPrioritySlider->setValue( mSettings.priority );
290-
mChkNoObstacle->setChecked( mSettings.obstacle );
291-
mObstacleFactorSlider->setValue( mSettings.obstacleFactor * 5 );
292-
mObstacleTypeComboBox->setCurrentIndex( mObstacleTypeComboBox->findData( mSettings.obstacleType ) );
293-
mPolygonObstacleTypeFrame->setEnabled( mSettings.obstacle );
294-
mObstaclePriorityFrame->setEnabled( mSettings.obstacle );
290+
mChkNoObstacle->setChecked( mSettings.obstacleSettings().isObstacle() );
291+
mObstacleFactorSlider->setValue( mSettings.obstacleSettings().factor() * 5 );
292+
mObstacleTypeComboBox->setCurrentIndex( mObstacleTypeComboBox->findData( mSettings.obstacleSettings().type() ) );
293+
mPolygonObstacleTypeFrame->setEnabled( mSettings.obstacleSettings().isObstacle() );
294+
mObstaclePriorityFrame->setEnabled( mSettings.obstacleSettings().isObstacle() );
295295
chkLabelPerFeaturePart->setChecked( mSettings.labelPerPart );
296296
mPalShowAllLabelsForLayerChkBx->setChecked( mSettings.displayAll );
297297
chkMergeLines->setChecked( mSettings.mergeLines );
@@ -488,9 +488,9 @@ QgsPalLayerSettings QgsLabelingGui::layerSettings()
488488
lyr.overrunDistanceMapUnitScale = mOverrunDistanceUnitWidget->getMapUnitScale();
489489

490490
lyr.priority = mPrioritySlider->value();
491-
lyr.obstacle = mChkNoObstacle->isChecked() || mMode == ObstaclesOnly;
492-
lyr.obstacleFactor = mObstacleFactorSlider->value() / 5.0;
493-
lyr.obstacleType = ( QgsPalLayerSettings::ObstacleType )mObstacleTypeComboBox->currentData().toInt();
491+
lyr.obstacleSettings().setIsObstacle( mChkNoObstacle->isChecked() || mMode == ObstaclesOnly );
492+
lyr.obstacleSettings().setFactor( mObstacleFactorSlider->value() / 5.0 );
493+
lyr.obstacleSettings().setType( static_cast< QgsLabelObstacleSettings::ObstacleType >( mObstacleTypeComboBox->currentData().toInt() ) );
494494
lyr.labelPerPart = chkLabelPerFeaturePart->isChecked();
495495
lyr.displayAll = mPalShowAllLabelsForLayerChkBx->isChecked();
496496
lyr.mergeLines = chkMergeLines->isChecked();

‎src/gui/qgstextformatwidget.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,8 +169,8 @@ void QgsTextFormatWidget::initWidget()
169169
mZIndexSpinBox->setClearValue( 0.0 );
170170
mLineDistanceSpnBx->setClearValue( 0.0 );
171171

172-
mObstacleTypeComboBox->addItem( tr( "Over the Feature's Interior" ), QgsPalLayerSettings::PolygonInterior );
173-
mObstacleTypeComboBox->addItem( tr( "Over the Feature's Boundary" ), QgsPalLayerSettings::PolygonBoundary );
172+
mObstacleTypeComboBox->addItem( tr( "Over the Feature's Interior" ), QgsLabelObstacleSettings::PolygonInterior );
173+
mObstacleTypeComboBox->addItem( tr( "Over the Feature's Boundary" ), QgsLabelObstacleSettings::PolygonBoundary );
174174

175175
mOffsetTypeComboBox->addItem( tr( "From Point" ), QgsPalLayerSettings::FromPoint );
176176
mOffsetTypeComboBox->addItem( tr( "From Symbol Bounds" ), QgsPalLayerSettings::FromSymbolBounds );

‎tests/src/core/testqgslabelingengine.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ void TestQgsLabelingEngine::testRuleBased()
321321

322322
QgsPalLayerSettings s1;
323323
s1.fieldName = QStringLiteral( "Class" );
324-
s1.obstacle = false;
324+
s1.obstacleSettings().setIsObstacle( false );
325325
s1.dist = 2;
326326
QgsTextFormat format = s1.format();
327327
format.setColor( QColor( 200, 0, 200 ) );
@@ -336,7 +336,7 @@ void TestQgsLabelingEngine::testRuleBased()
336336

337337
QgsPalLayerSettings s2;
338338
s2.fieldName = QStringLiteral( "Class" );
339-
s2.obstacle = false;
339+
s2.obstacleSettings().setIsObstacle( false );
340340
s2.dist = 2;
341341
format = s2.format();
342342
format.setColor( Qt::red );
@@ -1707,7 +1707,7 @@ void TestQgsLabelingEngine::drawUnplaced()
17071707
settings.isExpression = true;
17081708
settings.placement = QgsPalLayerSettings::OverPoint;
17091709
settings.priority = 3;
1710-
settings.obstacleFactor = 0;
1710+
settings.obstacleSettings().setFactor( 0 );
17111711

17121712
std::unique_ptr< QgsVectorLayer> vl1( new QgsVectorLayer( QStringLiteral( "Point?crs=epsg:4326&field=id:integer" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) ) );
17131713
vl1->setRenderer( new QgsNullSymbolRenderer() );
@@ -1725,7 +1725,7 @@ void TestQgsLabelingEngine::drawUnplaced()
17251725
settings.isExpression = true;
17261726
settings.placement = QgsPalLayerSettings::OverPoint;
17271727
settings.priority = 5; // higher priority - YY should be placed, not XX
1728-
settings.obstacleFactor = 0;
1728+
settings.obstacleSettings().setFactor( 0 );
17291729
format.setSize( 90 );
17301730
settings.setFormat( format );
17311731

‎tests/src/python/test_qgspallabeling_placement.py

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
QgsSingleSymbolRenderer,
2727
QgsMarkerSymbol,
2828
QgsProperty,
29-
QgsVectorLayerSimpleLabeling)
29+
QgsVectorLayerSimpleLabeling,
30+
QgsLabelObstacleSettings)
3031
from utilities import getTempfilePath, renderMapToImage, mapSettingsString
3132

3233
from test_qgspallabeling_base import TestQgsPalLabeling, runSuite
@@ -108,6 +109,40 @@ def setUpClass(cls):
108109
TestPlacementBase.setUpClass()
109110
cls.layer = None
110111

112+
def test_obstacle_settings(self):
113+
"""
114+
Test obstacle settings
115+
"""
116+
117+
settings = QgsLabelObstacleSettings()
118+
settings.setIsObstacle(True)
119+
self.assertTrue(settings.isObstacle())
120+
settings.setIsObstacle(False)
121+
self.assertFalse(settings.isObstacle())
122+
123+
settings.setFactor(0.1)
124+
self.assertEqual(settings.factor(), 0.1)
125+
126+
settings.setType(QgsLabelObstacleSettings.PolygonWhole)
127+
self.assertEqual(settings.type(), QgsLabelObstacleSettings.PolygonWhole)
128+
129+
# check that compatibility code works
130+
pal_settings = QgsPalLayerSettings()
131+
pal_settings.obstacle = True
132+
self.assertTrue(pal_settings.obstacle)
133+
self.assertTrue(pal_settings.obstacleSettings().isObstacle())
134+
pal_settings.obstacle = False
135+
self.assertFalse(pal_settings.obstacle)
136+
self.assertFalse(pal_settings.obstacleSettings().isObstacle())
137+
138+
pal_settings.obstacleFactor = 0.2
139+
self.assertEqual(pal_settings.obstacleFactor, 0.2)
140+
self.assertEqual(pal_settings.obstacleSettings().factor(), 0.2)
141+
142+
pal_settings.obstacleType = QgsPalLayerSettings.PolygonWhole
143+
self.assertEqual(pal_settings.obstacleType, QgsPalLayerSettings.PolygonWhole)
144+
self.assertEqual(pal_settings.obstacleSettings().type(), QgsLabelObstacleSettings.PolygonWhole)
145+
111146
def test_point_placement_around(self):
112147
# Default point label placement
113148
self.layer = TestQgsPalLabeling.loadFeatureLayer('point')

0 commit comments

Comments
 (0)
Please sign in to comment.