Skip to content

Commit

Permalink
[needs-docs] Add optional global settings allowing for hard limits
Browse files Browse the repository at this point in the history
to be placed on the maximum number of point, line and polygon candidates
which are generated for label features

These settings are set via the core\rendering\label_candidates_limit_*
settings, and allow for global limits to be set on the maximum number
of candidates allowed for label features. Placing these limits can
improve map rendering time, at the expense of worse label placement or
potentially missing map labels. (By default no global limit is set, which
means the labeling engine auto calculates the limit or uses the project
level settings)

The intended use case is for server administrators who are seeking for
maximum rendering speed to globally set these limits, causing them to
apply to all projects without the need for project-specific tweaks.
  • Loading branch information
nyalldawson committed Dec 26, 2019
1 parent 7e3de3a commit c5e0ada
Show file tree
Hide file tree
Showing 7 changed files with 98 additions and 22 deletions.
18 changes: 18 additions & 0 deletions resources/qgis_global_settings.ini
Expand Up @@ -98,6 +98,24 @@ NewsFeed\http00008000\long=
# When new projects are created, default to planimetric measurement.
measure\planimetric=false

# When set to a non-zero value, places a global limit on the maximum number of label candidates which
# are generated for point features. Setting this limit to a low (non-zero) value can improve map rendering
# time, at the expense of worse label placement or potentially missing map labels. A value of 0 indicates
# that no limit is present.
rendering\label_candidates_limit_points=0

# When set to a non-zero value, places a global limit on the maximum number of label candidates which
# are generated for line features. Setting this limit to a low (non-zero) value can improve map rendering
# time, at the expense of worse label placement or potentially missing map labels. A value of 0 indicates
# that no limit is present.
rendering\label_candidates_limit_lines=0

# When set to a non-zero value, places a global limit on the maximum number of label candidates which
# are generated for polygon features. Setting this limit to a low (non-zero) value can improve map rendering
# time, at the expense of worse label placement or potentially missing map labels. A value of 0 indicates
# that no limit is present.
rendering\label_candidates_limit_polygons=0

[colors]
# These colors are used in logs.
default=
Expand Down
9 changes: 7 additions & 2 deletions src/core/pal/feature.cpp
Expand Up @@ -157,6 +157,11 @@ QgsFeatureId FeaturePart::featureId() const
return mLF->id();
}

std::size_t FeaturePart::maximumPointCandidates() const
{
return mLF->layer()->maximumPointLabelCandidates();
}

std::size_t FeaturePart::maximumLineCandidates() const
{
if ( mCachedMaxLineCandidates > 0 )
Expand All @@ -168,7 +173,7 @@ std::size_t FeaturePart::maximumLineCandidates() const
double length = 0;
if ( GEOSLength_r( geosctxt, geos(), &length ) == 1 )
{
const std::size_t candidatesForLineLength = static_cast< std::size_t >( std::ceil( mLF->layer()->pal->maximumLineCandidatesPerMapUnit() * length ) );
const std::size_t candidatesForLineLength = static_cast< std::size_t >( std::ceil( mLF->layer()->mPal->maximumLineCandidatesPerMapUnit() * length ) );
const std::size_t maxForLayer = mLF->layer()->maximumLineLabelCandidates();
if ( maxForLayer == 0 )
mCachedMaxLineCandidates = candidatesForLineLength;
Expand All @@ -195,7 +200,7 @@ std::size_t FeaturePart::maximumPolygonCandidates() const
double area = 0;
if ( GEOSArea_r( geosctxt, geos(), &area ) == 1 )
{
const std::size_t candidatesForArea = static_cast< std::size_t >( std::ceil( mLF->layer()->pal->maximumPolygonCandidatesPerMapUnitSquared() * area ) );
const std::size_t candidatesForArea = static_cast< std::size_t >( std::ceil( mLF->layer()->mPal->maximumPolygonCandidatesPerMapUnitSquared() * area ) );
const std::size_t maxForLayer = mLF->layer()->maximumPolygonLabelCandidates();
if ( maxForLayer == 0 )
mCachedMaxPolygonCandidates = candidatesForArea;
Expand Down
5 changes: 5 additions & 0 deletions src/core/pal/feature.h
Expand Up @@ -126,6 +126,11 @@ namespace pal
*/
QgsFeatureId featureId() const;

/**
* Returns the maximum number of point candidates to generate for this feature.
*/
std::size_t maximumPointCandidates() const;

/**
* Returns the maximum number of line candidates to generate for this feature.
*/
Expand Down
2 changes: 1 addition & 1 deletion src/core/pal/layer.cpp
Expand Up @@ -44,7 +44,7 @@ using namespace pal;
Layer::Layer( QgsAbstractLabelProvider *provider, const QString &name, QgsPalLayerSettings::Placement arrangement, double defaultPriority, bool active, bool toLabel, Pal *pal, bool displayAll )
: mProvider( provider )
, mName( name )
, pal( pal )
, mPal( pal )
, mActive( active )
, mLabelLayer( toLabel )
, mDisplayAll( displayAll )
Expand Down
34 changes: 17 additions & 17 deletions src/core/pal/layer.h
Expand Up @@ -88,7 +88,7 @@ namespace pal
* \param displayAll if TRUE, all features will be labelled even though overlaps occur
*
*/
Layer( QgsAbstractLabelProvider *provider, const QString &name, QgsPalLayerSettings::Placement arrangement, double defaultPriority, bool active, bool toLabel, Pal *pal, bool displayAll = false );
Layer( QgsAbstractLabelProvider *provider, const QString &name, QgsPalLayerSettings::Placement arrangement, double defaultPriority, bool active, bool toLabel, Pal *mPal, bool displayAll = false );

virtual ~Layer();

Expand All @@ -109,15 +109,15 @@ namespace pal
// to avoid the engine processing endlessly...
const int size = mHashtable.size();
if ( size > 1000 )
return 4;
return static_cast< std::size_t >( mPal->globalCandidatesLimitPoint() > 0 ? std::min( mPal->globalCandidatesLimitPoint(), 4 ) : 4 );
else if ( size > 500 )
return 6;
return static_cast< std::size_t >( mPal->globalCandidatesLimitPoint() > 0 ? std::min( mPal->globalCandidatesLimitPoint(), 6 ) : 6 );
else if ( size > 200 )
return 8;
return static_cast< std::size_t >( mPal->globalCandidatesLimitPoint() > 0 ? std::min( mPal->globalCandidatesLimitPoint(), 8 ) : 8 );
else if ( size > 100 )
return 12;
return static_cast< std::size_t >( mPal->globalCandidatesLimitPoint() > 0 ? std::min( mPal->globalCandidatesLimitPoint(), 12 ) : 12 );
else
return 0;
return static_cast< std::size_t >( std::max( mPal->globalCandidatesLimitPoint(), 0 ) );
}

/**
Expand All @@ -130,15 +130,15 @@ namespace pal
// to avoid the engine processing endlessly...
const int size = mHashtable.size();
if ( size > 1000 )
return static_cast< std::size_t >( 5 );
return static_cast< std::size_t >( mPal->globalCandidatesLimitLine() > 0 ? std::min( mPal->globalCandidatesLimitLine(), 5 ) : 5 );
else if ( size > 500 )
return static_cast< std::size_t >( 10 );
return static_cast< std::size_t >( mPal->globalCandidatesLimitLine() > 0 ? std::min( mPal->globalCandidatesLimitLine(), 10 ) : 10 );
else if ( size > 200 )
return static_cast< std::size_t >( 20 );
return static_cast< std::size_t >( mPal->globalCandidatesLimitLine() > 0 ? std::min( mPal->globalCandidatesLimitLine(), 20 ) : 20 );
else if ( size > 100 )
return static_cast< std::size_t >( 40 );
return static_cast< std::size_t >( mPal->globalCandidatesLimitLine() > 0 ? std::min( mPal->globalCandidatesLimitLine(), 40 ) : 40 );
else
return static_cast< std::size_t >( 0 );
return static_cast< std::size_t >( std::max( mPal->globalCandidatesLimitLine(), 0 ) );
}

/**
Expand All @@ -151,15 +151,15 @@ namespace pal
// to avoid the engine processing endlessly...
const int size = mHashtable.size();
if ( size > 1000 )
return static_cast< std::size_t >( 5 );
return static_cast< std::size_t >( mPal->globalCandidatesLimitPolygon() > 0 ? std::min( mPal->globalCandidatesLimitPolygon(), 5 ) : 5 );
else if ( size > 500 )
return static_cast< std::size_t >( 15 );
return static_cast< std::size_t >( mPal->globalCandidatesLimitPolygon() > 0 ? std::min( mPal->globalCandidatesLimitPolygon(), 15 ) : 15 );
else if ( size > 200 )
return static_cast< std::size_t >( 20 );
return static_cast< std::size_t >( mPal->globalCandidatesLimitPolygon() > 0 ? std::min( mPal->globalCandidatesLimitPolygon(), 20 ) : 20 );
else if ( size > 100 )
return static_cast< std::size_t >( 25 );
return static_cast< std::size_t >( mPal->globalCandidatesLimitPolygon() > 0 ? std::min( mPal->globalCandidatesLimitPolygon(), 25 ) : 25 );
else
return static_cast< std::size_t >( 0 );
return static_cast< std::size_t >( std::max( mPal->globalCandidatesLimitPolygon(), 0 ) );
}

//! Returns pointer to the associated provider
Expand Down Expand Up @@ -329,7 +329,7 @@ namespace pal

std::vector< geos::unique_ptr > mGeosObstacleGeometries;

Pal *pal = nullptr;
Pal *mPal = nullptr;

double mDefaultPriority;

Expand Down
12 changes: 10 additions & 2 deletions src/core/pal/pal.cpp
Expand Up @@ -41,12 +41,19 @@
#include "internalexception.h"
#include "util.h"
#include "palrtree.h"
#include "qgssettings.h"
#include <cfloat>
#include <list>

using namespace pal;

Pal::Pal() = default;
Pal::Pal()
{
QgsSettings settings;
mGlobalCandidatesLimitPoint = settings.value( QStringLiteral( "rendering/label_candidates_limit_points" ), 0, QgsSettings::Core ).toInt();
mGlobalCandidatesLimitLine = settings.value( QStringLiteral( "rendering/label_candidates_limit_lines" ), 0, QgsSettings::Core ).toInt();
mGlobalCandidatesLimitPolygon = settings.value( QStringLiteral( "rendering/label_candidates_limit_polygons" ), 0, QgsSettings::Core ).toInt();
}

Pal::~Pal() = default;

Expand Down Expand Up @@ -291,7 +298,8 @@ std::unique_ptr<Problem> Pal::extract( const QgsRectangle &extent, const QgsGeom
switch ( feat->feature->getGeosType() )
{
case GEOS_POINT:
// no max at this stage, use all the candidates generated
// this is usually 0, i.e. no maximum
max_p = feat->feature->maximumPointCandidates();
break;

case GEOS_LINESTRING:
Expand Down
40 changes: 40 additions & 0 deletions src/core/pal/pal.h
Expand Up @@ -215,6 +215,42 @@ namespace pal
*/
void setPlacementVersion( QgsLabelingEngineSettings::PlacementEngineVersion placementVersion );

/**
* Returns the global candidates limit for point features, or 0 if no global limit is in effect.
*
* This is an installation-wide setting which applies to all projects, and is set via QSettings. It can
* be used to place global limits on the number of candidates generated for point features in order
* to optimise map rendering speeds.
*
* \see globalCandidatesLimitLine()
* \see globalCandidatesLimitPolygon()
*/
int globalCandidatesLimitPoint() const { return mGlobalCandidatesLimitPoint; }

/**
* Returns the global candidates limit for line features, or 0 if no global limit is in effect.
*
* This is an installation-wide setting which applies to all projects, and is set via QSettings. It can
* be used to place global limits on the number of candidates generated for line features in order
* to optimise map rendering speeds.
*
* \see globalCandidatesLimitPolygon()
* \see globalCandidatesLimitPoint()
*/
int globalCandidatesLimitLine() const { return mGlobalCandidatesLimitLine; }

/**
* Returns the global candidates limit for polygon features, or 0 if no global limit is in effect.
*
* This is an installation-wide setting which applies to all projects, and is set via QSettings. It can
* be used to place global limits on the number of candidates generated for polygon features in order
* to optimise map rendering speeds.
*
* \see globalCandidatesLimitLine()
* \see globalCandidatesLimitPoint()
*/
int globalCandidatesLimitPolygon() const { return mGlobalCandidatesLimitPolygon; }

private:

std::unordered_map< QgsAbstractLabelProvider *, std::unique_ptr< Layer > > mLayers;
Expand All @@ -241,6 +277,10 @@ namespace pal
double mMaxLineCandidatesPerMapUnit = 0;
double mMaxPolygonCandidatesPerMapUnitSquared = 0;

int mGlobalCandidatesLimitPoint = 0;
int mGlobalCandidatesLimitLine = 0;
int mGlobalCandidatesLimitPolygon = 0;

QgsLabelingEngineSettings::PlacementEngineVersion mPlacementVersion = QgsLabelingEngineSettings::PlacementEngineVersion2;

//! Callback that may be called from PAL to check whether the job has not been canceled in meanwhile
Expand Down

0 comments on commit c5e0ada

Please sign in to comment.