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
This commit is contained in:
Nyall Dawson 2019-12-03 15:49:13 +10:00
parent f145fa96c8
commit 9f63f49230
18 changed files with 391 additions and 66 deletions

View File

@ -0,0 +1,108 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/qgslabelobstaclesettings.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
class QgsLabelObstacleSettings
{
%Docstring
Contains settings related to how the label engine treats features as obstacles
.. versionadded:: 3.10.2
%End
%TypeHeaderCode
#include "qgslabelobstaclesettings.h"
%End
public:
enum ObstacleType
{
PolygonInterior,
PolygonBoundary,
PolygonWhole
};
bool isObstacle() const;
%Docstring
Returns ``True`` if the features are obstacles to labels of other layers.
.. seealso:: :py:func:`setIsObstacle`
.. seealso:: :py:func:`factor`
.. seealso:: :py:func:`type`
%End
void setIsObstacle( bool isObstacle );
%Docstring
Sets whether features are obstacles to labels of other layers.
.. seealso:: :py:func:`isObstacle`
.. seealso:: :py:func:`factor`
.. seealso:: :py:func:`type`
%End
double factor() const;
%Docstring
Returns the obstacle factor, where 1.0 = default, < 1.0 more likely to be covered by labels,
> 1.0 less likely to be covered
.. seealso:: :py:func:`setFactor`
.. seealso:: :py:func:`isObstacle`
.. seealso:: :py:func:`type`
%End
void setFactor( double factor );
%Docstring
Sets the obstacle ``factor``, where 1.0 = default, < 1.0 more likely to be covered by labels,
> 1.0 less likely to be covered
.. seealso:: :py:func:`factor`
.. seealso:: :py:func:`isObstacle`
.. seealso:: :py:func:`type`
%End
ObstacleType type() const;
%Docstring
Returns how features act as obstacles for labels.
.. seealso:: :py:func:`setType`
.. seealso:: :py:func:`isObstacle`
.. seealso:: :py:func:`factor`
%End
void setType( ObstacleType type );
%Docstring
Controls how features act as obstacles for labels.
.. seealso:: :py:func:`type`
.. seealso:: :py:func:`isObstacle`
.. seealso:: :py:func:`factor`
%End
};
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/qgslabelobstaclesettings.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/

View File

@ -76,7 +76,6 @@ Constructor for QgsLabelPosition
bool isUnplaced;
};
class QgsPalLayerSettings
{
@ -469,11 +468,18 @@ Returns the QgsExpression for this label settings. May be ``None`` if isExpressi
double minFeatureSize;
bool obstacle;
double obstacleFactor;
%Property( name = obstacle, get = _getIsObstacle, set = _setIsObstacle )
%Property( name = obstacleFactor, get = _getObstacleFactor, set = _setObstacleFactor )
%Property( name = obstacleType, get = _getObstacleType, set = _setObstacleType )
bool _getIsObstacle() const;
void _setIsObstacle( bool obstacle );
double _getObstacleFactor() const;
void _setObstacleFactor( double factor );
ObstacleType _getObstacleType() const;
void _setObstacleType( ObstacleType type );
ObstacleType obstacleType;
double zIndex;
@ -585,6 +591,25 @@ Ownership of ``callout`` is transferred to the settings.
.. versionadded:: 3.10
%End
QgsLabelObstacleSettings &obstacleSettings();
%Docstring
Returns the label obstacle settings.
.. seealso:: :py:func:`setObstacleSettings`
.. versionadded:: 3.10.2
%End
void setObstacleSettings( const QgsLabelObstacleSettings &settings );
%Docstring
Sets the label obstacle ``settings``.
.. seealso:: :py:func:`obstacleSettings`
.. versionadded:: 3.10.2
%End
static QPixmap labelSettingsPreviewPixmap( const QgsPalLayerSettings &settings, QSize size, const QString &previewText = QString(), int padding = 0 );
%Docstring
Returns a pixmap preview for label ``settings``.
@ -738,6 +763,7 @@ allowed to be split apart (e.g., Arabic and Indic based scripts)
};
/************************************************************************
* This file has been generated automatically from *
* *

View File

@ -88,6 +88,7 @@
%Include auto_generated/qgsinterval.sip
%Include auto_generated/qgsjsonutils.sip
%Include auto_generated/qgslabelingenginesettings.sip
%Include auto_generated/qgslabelobstaclesettings.sip
%Include auto_generated/qgslabelsearchtree.sip
%Include auto_generated/qgslayerdefinition.sip
%Include auto_generated/qgslegendrenderer.sip

View File

@ -530,6 +530,10 @@ while ($LINE_IDX < $LINE_COUNT){
write_output("SF1", "%Feature $1$2\n");
next;
}
if ($LINE =~ m/^\s*SIP_PROPERTY\((.*)\)$/){
write_output("SF1", "%Property($1)\n");
next;
}
if ($LINE =~ m/^\s*SIP_IF_FEATURE\( (\!?\w+) \)(.*)$/){
write_output("SF2", "%If ($1)$2\n");
next;

View File

@ -754,6 +754,7 @@ SET(QGIS_CORE_HDRS
qgslabelfeature.h
qgslabelingengine.h
qgslabelingenginesettings.h
qgslabelobstaclesettings.h
qgslabelsearchtree.h
qgslayerdefinition.h
qgslegendrenderer.h

View File

@ -45,7 +45,6 @@ Layer::Layer( QgsAbstractLabelProvider *provider, const QString &name, QgsPalLay
: mProvider( provider )
, mName( name )
, pal( pal )
, mObstacleType( QgsPalLayerSettings::PolygonInterior )
, mActive( active )
, mLabelLayer( toLabel )
, mDisplayAll( displayAll )

View File

@ -228,7 +228,7 @@ namespace pal
* act as obstacles for labels.
* \see setObstacleType
*/
QgsPalLayerSettings::ObstacleType obstacleType() const { return mObstacleType; }
QgsLabelObstacleSettings::ObstacleType obstacleType() const { return mObstacleType; }
/**
* Sets the obstacle type, which controls how features within the layer
@ -236,7 +236,7 @@ namespace pal
* \param obstacleType new obstacle type
* \see obstacleType
*/
void setObstacleType( QgsPalLayerSettings::ObstacleType obstacleType ) { mObstacleType = obstacleType; }
void setObstacleType( QgsLabelObstacleSettings::ObstacleType obstacleType ) { mObstacleType = obstacleType; }
/**
* Sets the layer's priority.
@ -333,7 +333,7 @@ namespace pal
double mDefaultPriority;
QgsPalLayerSettings::ObstacleType mObstacleType;
QgsLabelObstacleSettings::ObstacleType mObstacleType = QgsLabelObstacleSettings::PolygonBoundary;
bool mActive;
bool mLabelLayer;
bool mDisplayAll;

View File

@ -251,5 +251,9 @@
#define SIP_MONKEYPATCH_SCOPEENUM
#define SIP_MONKEYPATCH_SCOPEENUM_UNNEST(OUTSIDE_CLASS,FORMERNAME)
/*
* Directive to define a Python property;
*/
#define SIP_PROPERTY(name,getter,setter)
#endif // QGIS_SIP_H

View File

@ -620,7 +620,6 @@ QgsAbstractLabelProvider::QgsAbstractLabelProvider( QgsMapLayer *layer, const QS
, mFlags( DrawLabels )
, mPlacement( QgsPalLayerSettings::AroundPoint )
, mPriority( 0.5 )
, mObstacleType( QgsPalLayerSettings::PolygonInterior )
, mUpsidedownLabels( QgsPalLayerSettings::Upright )
{
}

View File

@ -142,7 +142,7 @@ class CORE_EXPORT QgsAbstractLabelProvider
double priority() const { return mPriority; }
//! How the feature geometries will work as obstacles
QgsPalLayerSettings::ObstacleType obstacleType() const { return mObstacleType; }
QgsLabelObstacleSettings::ObstacleType obstacleType() const { return mObstacleType; }
//! How to handle labels that would be upside down
QgsPalLayerSettings::UpsideDownLabels upsidedownLabels() const { return mUpsidedownLabels; }
@ -166,7 +166,7 @@ class CORE_EXPORT QgsAbstractLabelProvider
//! Default priority of labels
double mPriority;
//! Type of the obstacle of feature geometries
QgsPalLayerSettings::ObstacleType mObstacleType;
QgsLabelObstacleSettings::ObstacleType mObstacleType = QgsLabelObstacleSettings::PolygonBoundary;
//! How to handle labels that would be upside down
QgsPalLayerSettings::UpsideDownLabels mUpsidedownLabels;
};

View File

@ -0,0 +1,128 @@
/***************************************************************************
qgslabelobstaclesettings.h
--------------------------
Date : December 2019
Copyright : (C) 2019 by Nyall Dawson
Email : nyall dot dawson at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSLABELOBSTACLESETTINGS_H
#define QGSLABELOBSTACLESETTINGS_H
#include "qgis_core.h"
#include "qgis_sip.h"
/**
* \ingroup core
* \class QgsLabelObstacleSettings
*
* Contains settings related to how the label engine treats features as obstacles
*
* \since QGIS 3.10.2
*/
class CORE_EXPORT QgsLabelObstacleSettings
{
public:
/**
* Valid obstacle types, which affect how features within the layer will act as obstacles
* for labels.
*/
enum ObstacleType
{
PolygonInterior, /*!< avoid placing labels over interior of polygon (prefer placing labels totally
outside or just slightly inside polygon) */
PolygonBoundary, /*!< avoid placing labels over boundary of polygon (prefer placing outside or
completely inside polygon) */
PolygonWhole /*!< avoid placing labels over ANY part of polygon. Where PolygonInterior will prefer
to place labels with the smallest area of intersection between the label and the polygon,
PolygonWhole will penalise any label which intersects with the polygon by an equal amount, so that
placing labels over any part of the polygon is avoided.*/
};
/**
* Returns TRUE if the features are obstacles to labels of other layers.
* \see setIsObstacle()
* \see factor()
* \see type()
*/
bool isObstacle() const
{
return mIsObstacle;
}
/**
* Sets whether features are obstacles to labels of other layers.
* \see isObstacle()
* \see factor()
* \see type()
*/
void setIsObstacle( bool isObstacle )
{
mIsObstacle = isObstacle;
}
/**
* Returns the obstacle factor, where 1.0 = default, < 1.0 more likely to be covered by labels,
* > 1.0 less likely to be covered
*
* \see setFactor()
* \see isObstacle()
* \see type()
*/
double factor() const
{
return mObstacleFactor;
}
/**
* Sets the obstacle \a factor, where 1.0 = default, < 1.0 more likely to be covered by labels,
* > 1.0 less likely to be covered
*
* \see factor()
* \see isObstacle()
* \see type()
*/
void setFactor( double factor )
{
mObstacleFactor = factor;
}
/**
* Returns how features act as obstacles for labels.
* \see setType()
* \see isObstacle()
* \see factor()
*/
ObstacleType type() const
{
return mObstacleType;
}
/**
* Controls how features act as obstacles for labels.
* \see type()
* \see isObstacle()
* \see factor()
*/
void setType( ObstacleType type )
{
mObstacleType = type;
}
private:
bool mIsObstacle = true;
double mObstacleFactor = 1.0;
ObstacleType mObstacleType = PolygonBoundary;
};
#endif // QGSLABELOBSTACLESETTINGS_H

View File

@ -347,9 +347,6 @@ QgsPalLayerSettings &QgsPalLayerSettings::operator=( const QgsPalLayerSettings &
minFeatureSize = s.minFeatureSize;
limitNumLabels = s.limitNumLabels;
maxNumLabels = s.maxNumLabels;
obstacle = s.obstacle;
obstacleFactor = s.obstacleFactor;
obstacleType = s.obstacleType;
zIndex = s.zIndex;
mFormat = s.mFormat;
@ -357,6 +354,8 @@ QgsPalLayerSettings &QgsPalLayerSettings::operator=( const QgsPalLayerSettings &
mCallout.reset( s.mCallout ? s.mCallout->clone() : nullptr );
mObstacleSettings = s.mObstacleSettings;
geometryGenerator = s.geometryGenerator;
geometryGeneratorEnabled = s.geometryGeneratorEnabled;
geometryGeneratorType = s.geometryGeneratorType;
@ -395,7 +394,7 @@ bool QgsPalLayerSettings::prepare( QgsRenderContext &context, QSet<QString> &att
mCurFields = fields;
if ( drawLabels || obstacle )
if ( drawLabels || mObstacleSettings.isObstacle() )
{
if ( drawLabels )
{
@ -812,9 +811,9 @@ void QgsPalLayerSettings::readFromLayerCustomProperties( QgsVectorLayer *layer )
minFeatureSize = layer->customProperty( QStringLiteral( "labeling/minFeatureSize" ) ).toDouble();
limitNumLabels = layer->customProperty( QStringLiteral( "labeling/limitNumLabels" ), QVariant( false ) ).toBool();
maxNumLabels = layer->customProperty( QStringLiteral( "labeling/maxNumLabels" ), QVariant( 2000 ) ).toInt();
obstacle = layer->customProperty( QStringLiteral( "labeling/obstacle" ), QVariant( true ) ).toBool();
obstacleFactor = layer->customProperty( QStringLiteral( "labeling/obstacleFactor" ), QVariant( 1.0 ) ).toDouble();
obstacleType = static_cast< ObstacleType >( layer->customProperty( QStringLiteral( "labeling/obstacleType" ), QVariant( PolygonInterior ) ).toUInt() );
mObstacleSettings.setIsObstacle( layer->customProperty( QStringLiteral( "labeling/obstacle" ), QVariant( true ) ).toBool() );
mObstacleSettings.setFactor( layer->customProperty( QStringLiteral( "labeling/obstacleFactor" ), QVariant( 1.0 ) ).toDouble() );
mObstacleSettings.setType( static_cast< QgsLabelObstacleSettings::ObstacleType >( layer->customProperty( QStringLiteral( "labeling/obstacleType" ), QVariant( PolygonInterior ) ).toUInt() ) );
zIndex = layer->customProperty( QStringLiteral( "labeling/zIndex" ), QVariant( 0.0 ) ).toDouble();
mDataDefinedProperties.clear();
@ -1038,9 +1037,9 @@ void QgsPalLayerSettings::readXml( const QDomElement &elem, const QgsReadWriteCo
minFeatureSize = renderingElem.attribute( QStringLiteral( "minFeatureSize" ) ).toDouble();
limitNumLabels = renderingElem.attribute( QStringLiteral( "limitNumLabels" ), QStringLiteral( "0" ) ).toInt();
maxNumLabels = renderingElem.attribute( QStringLiteral( "maxNumLabels" ), QStringLiteral( "2000" ) ).toInt();
obstacle = renderingElem.attribute( QStringLiteral( "obstacle" ), QStringLiteral( "1" ) ).toInt();
obstacleFactor = renderingElem.attribute( QStringLiteral( "obstacleFactor" ), QStringLiteral( "1" ) ).toDouble();
obstacleType = static_cast< ObstacleType >( renderingElem.attribute( QStringLiteral( "obstacleType" ), QString::number( PolygonInterior ) ).toUInt() );
mObstacleSettings.setIsObstacle( renderingElem.attribute( QStringLiteral( "obstacle" ), QStringLiteral( "1" ) ).toInt() );
mObstacleSettings.setFactor( renderingElem.attribute( QStringLiteral( "obstacleFactor" ), QStringLiteral( "1" ) ).toDouble() );
mObstacleSettings.setType( static_cast< QgsLabelObstacleSettings::ObstacleType >( renderingElem.attribute( QStringLiteral( "obstacleType" ), QString::number( PolygonInterior ) ).toUInt() ) );
zIndex = renderingElem.attribute( QStringLiteral( "zIndex" ), QStringLiteral( "0.0" ) ).toDouble();
QDomElement ddElem = elem.firstChildElement( QStringLiteral( "dd_properties" ) );
@ -1185,9 +1184,9 @@ QDomElement QgsPalLayerSettings::writeXml( QDomDocument &doc, const QgsReadWrite
renderingElem.setAttribute( QStringLiteral( "minFeatureSize" ), minFeatureSize );
renderingElem.setAttribute( QStringLiteral( "limitNumLabels" ), limitNumLabels );
renderingElem.setAttribute( QStringLiteral( "maxNumLabels" ), maxNumLabels );
renderingElem.setAttribute( QStringLiteral( "obstacle" ), obstacle );
renderingElem.setAttribute( QStringLiteral( "obstacleFactor" ), obstacleFactor );
renderingElem.setAttribute( QStringLiteral( "obstacleType" ), static_cast< unsigned int >( obstacleType ) );
renderingElem.setAttribute( QStringLiteral( "obstacle" ), mObstacleSettings.isObstacle() );
renderingElem.setAttribute( QStringLiteral( "obstacleFactor" ), mObstacleSettings.factor() );
renderingElem.setAttribute( QStringLiteral( "obstacleType" ), static_cast< unsigned int >( mObstacleSettings.type() ) );
renderingElem.setAttribute( QStringLiteral( "zIndex" ), zIndex );
QDomElement ddElem = doc.createElement( QStringLiteral( "dd_properties" ) );
@ -1583,9 +1582,9 @@ void QgsPalLayerSettings::registerFeature( const QgsFeature &f, QgsRenderContext
mCurFeat = &f;
// data defined is obstacle? calculate this first, to avoid wasting time working with obstacles we don't require
bool isObstacle = obstacle;
bool isObstacle = mObstacleSettings.isObstacle();
if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::IsObstacle ) )
isObstacle = mDataDefinedProperties.valueAsBool( QgsPalLayerSettings::IsObstacle, context.expressionContext(), obstacle ); // default to layer default
isObstacle = mDataDefinedProperties.valueAsBool( QgsPalLayerSettings::IsObstacle, context.expressionContext(), isObstacle ); // default to layer default
if ( !drawLabels )
{
@ -2481,7 +2480,7 @@ void QgsPalLayerSettings::registerFeature( const QgsFeature &f, QgsRenderContext
( *labelFeature )->setIsObstacle( isObstacle );
double featObstacleFactor = obstacleFactor;
double featObstacleFactor = mObstacleSettings.factor();
if ( isObstacle && mDataDefinedProperties.isActive( QgsPalLayerSettings::ObstacleFactor ) )
{
context.expressionContext().setOriginalValueVariable( featObstacleFactor );
@ -2566,7 +2565,7 @@ void QgsPalLayerSettings::registerObstacleFeature( const QgsFeature &f, QgsRende
( *obstacleFeature )->setIsObstacle( true );
( *obstacleFeature )->setFeature( f );
double featObstacleFactor = obstacleFactor;
double featObstacleFactor = mObstacleSettings.factor();
if ( mDataDefinedProperties.isActive( QgsPalLayerSettings::ObstacleFactor ) )
{
context.expressionContext().setOriginalValueVariable( featObstacleFactor );

View File

@ -42,6 +42,7 @@
#include "qgssymbol.h"
#include "qgstextrenderer.h"
#include "qgspropertycollection.h"
#include "qgslabelobstaclesettings.h"
namespace pal SIP_SKIP
{
@ -193,7 +194,6 @@ class CORE_EXPORT QgsLabelPosition
bool isUnplaced = false;
};
/**
* \ingroup core
* \class QgsPalLayerSettings
@ -311,7 +311,7 @@ class CORE_EXPORT QgsPalLayerSettings
will be drawn with right alignment*/
};
//TODO QGIS 4.0 - Move to QgsLabelingEngine
//TODO QGIS 4.0 - Remove -- moved to QgsLabelEngineObstacleSettings
/**
* Valid obstacle types, which affect how features within the layer will act as obstacles
@ -885,27 +885,23 @@ class CORE_EXPORT QgsPalLayerSettings
*/
double minFeatureSize = 0;
/**
* TRUE if features for layer are obstacles to labels of other layers.
* \see obstacleFactor
* \see obstacleType
*/
bool obstacle = true;
// TODO QGIS 4.0 - remove this junk
/**
* Obstacle factor, where 1.0 = default, < 1.0 more likely to be covered by labels,
* > 1.0 less likely to be covered
* \see obstacle
* \see obstacleType
*/
double obstacleFactor = 1.0;
#ifdef SIP_RUN
SIP_PROPERTY( name = obstacle, get = _getIsObstacle, set = _setIsObstacle )
SIP_PROPERTY( name = obstacleFactor, get = _getObstacleFactor, set = _setObstacleFactor )
SIP_PROPERTY( name = obstacleType, get = _getObstacleType, set = _setObstacleType )
#endif
/**
* Controls how features act as obstacles for labels.
* \see obstacle
* \see obstacleFactor
*/
ObstacleType obstacleType = PolygonBoundary;
///@cond PRIVATE
bool _getIsObstacle() const { return mObstacleSettings.isObstacle(); }
void _setIsObstacle( bool obstacle ) { mObstacleSettings.setIsObstacle( obstacle ); }
double _getObstacleFactor() const { return mObstacleSettings.factor(); }
void _setObstacleFactor( double factor ) { mObstacleSettings.setFactor( factor ); }
ObstacleType _getObstacleType() const { return static_cast< ObstacleType>( mObstacleSettings.type() ); }
void _setObstacleType( ObstacleType type ) { mObstacleSettings.setType( static_cast< QgsLabelObstacleSettings::ObstacleType>( type ) ); }
///@endcond
//! Z-Index of label, where labels with a higher z-index are rendered on top of labels with a lower z-index
double zIndex = 0;
@ -1023,6 +1019,28 @@ class CORE_EXPORT QgsPalLayerSettings
*/
void setCallout( QgsCallout *callout SIP_TRANSFER );
/**
* Returns the label obstacle settings.
* \see setObstacleSettings()
* \note Not available in Python bindings
* \since QGIS 3.10.2
*/
const QgsLabelObstacleSettings &obstacleSettings() const { return mObstacleSettings; } SIP_SKIP
/**
* Returns the label obstacle settings.
* \see setObstacleSettings()
* \since QGIS 3.10.2
*/
QgsLabelObstacleSettings &obstacleSettings() { return mObstacleSettings; }
/**
* Sets the label obstacle \a settings.
* \see obstacleSettings()
* \since QGIS 3.10.2
*/
void setObstacleSettings( const QgsLabelObstacleSettings &settings ) { mObstacleSettings = settings; }
/**
* Returns a pixmap preview for label \a settings.
* \param settings label settings
@ -1126,6 +1144,8 @@ class CORE_EXPORT QgsPalLayerSettings
std::unique_ptr< QgsCallout > mCallout;
QgsLabelObstacleSettings mObstacleSettings;
QgsExpression mGeometryGeneratorExpression;
bool mRenderStarted = false;
@ -1293,4 +1313,5 @@ class CORE_EXPORT QgsPalLabeling
friend class QgsPalLayerSettings;
};
#endif // QGSPALLABELING_H

View File

@ -75,11 +75,11 @@ void QgsVectorLayerLabelProvider::init()
if ( mLayerGeometryType == QgsWkbTypes::PointGeometry && mRenderer )
{
//override obstacle type to treat any intersection of a label with the point symbol as a high cost conflict
mObstacleType = QgsPalLayerSettings::PolygonWhole;
mObstacleType = QgsLabelObstacleSettings::PolygonWhole;
}
else
{
mObstacleType = mSettings.obstacleType;
mObstacleType = mSettings.obstacleSettings().type();
}
mUpsidedownLabels = mSettings.upsidedownLabels;

View File

@ -287,11 +287,11 @@ void QgsLabelingGui::setLayer( QgsMapLayer *mapLayer )
mOverrunDistanceUnitWidget->setMapUnitScale( mSettings.overrunDistanceMapUnitScale );
mPrioritySlider->setValue( mSettings.priority );
mChkNoObstacle->setChecked( mSettings.obstacle );
mObstacleFactorSlider->setValue( mSettings.obstacleFactor * 5 );
mObstacleTypeComboBox->setCurrentIndex( mObstacleTypeComboBox->findData( mSettings.obstacleType ) );
mPolygonObstacleTypeFrame->setEnabled( mSettings.obstacle );
mObstaclePriorityFrame->setEnabled( mSettings.obstacle );
mChkNoObstacle->setChecked( mSettings.obstacleSettings().isObstacle() );
mObstacleFactorSlider->setValue( mSettings.obstacleSettings().factor() * 5 );
mObstacleTypeComboBox->setCurrentIndex( mObstacleTypeComboBox->findData( mSettings.obstacleSettings().type() ) );
mPolygonObstacleTypeFrame->setEnabled( mSettings.obstacleSettings().isObstacle() );
mObstaclePriorityFrame->setEnabled( mSettings.obstacleSettings().isObstacle() );
chkLabelPerFeaturePart->setChecked( mSettings.labelPerPart );
mPalShowAllLabelsForLayerChkBx->setChecked( mSettings.displayAll );
chkMergeLines->setChecked( mSettings.mergeLines );
@ -488,9 +488,9 @@ QgsPalLayerSettings QgsLabelingGui::layerSettings()
lyr.overrunDistanceMapUnitScale = mOverrunDistanceUnitWidget->getMapUnitScale();
lyr.priority = mPrioritySlider->value();
lyr.obstacle = mChkNoObstacle->isChecked() || mMode == ObstaclesOnly;
lyr.obstacleFactor = mObstacleFactorSlider->value() / 5.0;
lyr.obstacleType = ( QgsPalLayerSettings::ObstacleType )mObstacleTypeComboBox->currentData().toInt();
lyr.obstacleSettings().setIsObstacle( mChkNoObstacle->isChecked() || mMode == ObstaclesOnly );
lyr.obstacleSettings().setFactor( mObstacleFactorSlider->value() / 5.0 );
lyr.obstacleSettings().setType( static_cast< QgsLabelObstacleSettings::ObstacleType >( mObstacleTypeComboBox->currentData().toInt() ) );
lyr.labelPerPart = chkLabelPerFeaturePart->isChecked();
lyr.displayAll = mPalShowAllLabelsForLayerChkBx->isChecked();
lyr.mergeLines = chkMergeLines->isChecked();

View File

@ -169,8 +169,8 @@ void QgsTextFormatWidget::initWidget()
mZIndexSpinBox->setClearValue( 0.0 );
mLineDistanceSpnBx->setClearValue( 0.0 );
mObstacleTypeComboBox->addItem( tr( "Over the Feature's Interior" ), QgsPalLayerSettings::PolygonInterior );
mObstacleTypeComboBox->addItem( tr( "Over the Feature's Boundary" ), QgsPalLayerSettings::PolygonBoundary );
mObstacleTypeComboBox->addItem( tr( "Over the Feature's Interior" ), QgsLabelObstacleSettings::PolygonInterior );
mObstacleTypeComboBox->addItem( tr( "Over the Feature's Boundary" ), QgsLabelObstacleSettings::PolygonBoundary );
mOffsetTypeComboBox->addItem( tr( "From Point" ), QgsPalLayerSettings::FromPoint );
mOffsetTypeComboBox->addItem( tr( "From Symbol Bounds" ), QgsPalLayerSettings::FromSymbolBounds );

View File

@ -321,7 +321,7 @@ void TestQgsLabelingEngine::testRuleBased()
QgsPalLayerSettings s1;
s1.fieldName = QStringLiteral( "Class" );
s1.obstacle = false;
s1.obstacleSettings().setIsObstacle( false );
s1.dist = 2;
QgsTextFormat format = s1.format();
format.setColor( QColor( 200, 0, 200 ) );
@ -336,7 +336,7 @@ void TestQgsLabelingEngine::testRuleBased()
QgsPalLayerSettings s2;
s2.fieldName = QStringLiteral( "Class" );
s2.obstacle = false;
s2.obstacleSettings().setIsObstacle( false );
s2.dist = 2;
format = s2.format();
format.setColor( Qt::red );
@ -1707,7 +1707,7 @@ void TestQgsLabelingEngine::drawUnplaced()
settings.isExpression = true;
settings.placement = QgsPalLayerSettings::OverPoint;
settings.priority = 3;
settings.obstacleFactor = 0;
settings.obstacleSettings().setFactor( 0 );
std::unique_ptr< QgsVectorLayer> vl1( new QgsVectorLayer( QStringLiteral( "Point?crs=epsg:4326&field=id:integer" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) ) );
vl1->setRenderer( new QgsNullSymbolRenderer() );
@ -1725,7 +1725,7 @@ void TestQgsLabelingEngine::drawUnplaced()
settings.isExpression = true;
settings.placement = QgsPalLayerSettings::OverPoint;
settings.priority = 5; // higher priority - YY should be placed, not XX
settings.obstacleFactor = 0;
settings.obstacleSettings().setFactor( 0 );
format.setSize( 90 );
settings.setFormat( format );

View File

@ -26,7 +26,8 @@ from qgis.core import (QgsLabelingEngineSettings,
QgsSingleSymbolRenderer,
QgsMarkerSymbol,
QgsProperty,
QgsVectorLayerSimpleLabeling)
QgsVectorLayerSimpleLabeling,
QgsLabelObstacleSettings)
from utilities import getTempfilePath, renderMapToImage, mapSettingsString
from test_qgspallabeling_base import TestQgsPalLabeling, runSuite
@ -108,6 +109,40 @@ class TestPointPlacement(TestPlacementBase):
TestPlacementBase.setUpClass()
cls.layer = None
def test_obstacle_settings(self):
"""
Test obstacle settings
"""
settings = QgsLabelObstacleSettings()
settings.setIsObstacle(True)
self.assertTrue(settings.isObstacle())
settings.setIsObstacle(False)
self.assertFalse(settings.isObstacle())
settings.setFactor(0.1)
self.assertEqual(settings.factor(), 0.1)
settings.setType(QgsLabelObstacleSettings.PolygonWhole)
self.assertEqual(settings.type(), QgsLabelObstacleSettings.PolygonWhole)
# check that compatibility code works
pal_settings = QgsPalLayerSettings()
pal_settings.obstacle = True
self.assertTrue(pal_settings.obstacle)
self.assertTrue(pal_settings.obstacleSettings().isObstacle())
pal_settings.obstacle = False
self.assertFalse(pal_settings.obstacle)
self.assertFalse(pal_settings.obstacleSettings().isObstacle())
pal_settings.obstacleFactor = 0.2
self.assertEqual(pal_settings.obstacleFactor, 0.2)
self.assertEqual(pal_settings.obstacleSettings().factor(), 0.2)
pal_settings.obstacleType = QgsPalLayerSettings.PolygonWhole
self.assertEqual(pal_settings.obstacleType, QgsPalLayerSettings.PolygonWhole)
self.assertEqual(pal_settings.obstacleSettings().type(), QgsLabelObstacleSettings.PolygonWhole)
def test_point_placement_around(self):
# Default point label placement
self.layer = TestQgsPalLabeling.loadFeatureLayer('point')