[needs-docs] Rework label engine "maximum line candidates" and "maximum polygon candidates"

settings and logic

The previous approach of a single fixed value which applied to ALL line and ALL polygon
features was... not ideal. It meant that all line features would be assigned the same
number of candidates, regardless of length. So a road of length 1 cm on the rendered
map would have an identical number of candidates as a 30cm road covering the length of the
whole map!! This resulted in both a lot of wasted calculations (generating a ridiculous
number of candidates for small lines at barely discernable distances from each other)
AND an insufficient number of candidates for lengthy features (resulting in worse label
placement for these features).

(The situation was similar, but even worse for polygons)

Now, the setting is reworked to "Number of line candidates per cm" and "number of
polygon candidates per cm2". This means that small features get much less candidates,
and large features get much more features! Both a win for map rendering speed in many
circumstances AND good cartography... now that's a nice Christmas gift for QGIS :)
This commit is contained in:
Nyall Dawson 2019-12-21 07:28:02 +10:00
parent df102a98da
commit 1899f90a04
12 changed files with 254 additions and 130 deletions

View File

@ -73,23 +73,60 @@ Test whether a particular flag is enabled
Sets whether a particual flag is enabled Sets whether a particual flag is enabled
%End %End
void numCandidatePositions( int &candPoint, int &candLine, int &candPolygon ) const; double maximumLineCandidatesPerCm() const;
%Docstring
Returns the maximum number of line label candidate positions per centimeter.
.. seealso:: :py:func:`setMaximumLineCandidatesPerCm`
.. versionadded:: 3.12
%End
void setMaximumLineCandidatesPerCm( double candidates );
%Docstring
Sets the maximum number of line label ``candidates`` per centimeter.
.. seealso:: :py:func:`maximumLineCandidatesPerCm`
.. versionadded:: 3.12
%End
double maximumPolygonCandidatesPerCmSquared() const;
%Docstring
Returns the maximum number of polygon label candidate positions per centimeter squared.
.. seealso:: :py:func:`setMaximumPolygonCandidatesPerCmSquared`
.. versionadded:: 3.12
%End
void setMaximumPolygonCandidatesPerCmSquared( double candidates );
%Docstring
Sets the maximum number of polygon label ``candidates`` per centimeter squared.
.. seealso:: :py:func:`maximumPolygonCandidatesPerCmSquared`
.. versionadded:: 3.12
%End
void numCandidatePositions( int &candPoint, int &candLine, int &candPolygon ) const /Deprecated/;
%Docstring %Docstring
Gets number of candidate positions that will be generated for each label feature. Gets number of candidate positions that will be generated for each label feature.
.. deprecated:: QGIS 3.12 .. deprecated:: QGIS 3.12
the ``candPoint`` argument is ignored. use maximumPolygonCandidatesPerCmSquared() and
maximumLineCandidatesPerCm() instead.
%End %End
void setNumCandidatePositions( int candPoint, int candLine, int candPolygon ); void setNumCandidatePositions( int candPoint, int candLine, int candPolygon ) /Deprecated/;
%Docstring %Docstring
Sets the number of candidate positions that will be generated for each label feature. Sets the number of candidate positions that will be generated for each label feature.
.. deprecated:: QGIS 3.12 .. deprecated:: QGIS 3.12
the ``candPoint`` argument is ignored. use setMaximumPolygonCandidatesPerCmSquared() and
setMaximumLineCandidatesPerCm() instead.
%End %End
void setSearchMethod( Search s ) /Deprecated/; void setSearchMethod( Search s ) /Deprecated/;
%Docstring %Docstring
Used to set which search method to use for removal collisions between labels Used to set which search method to use for removal collisions between labels

View File

@ -55,11 +55,12 @@ QgsLabelEngineConfigWidget::QgsLabelEngineConfigWidget( QWidget *parent )
} }
} ); } );
spinCandLine->setClearValue( 5 );
spinCandPolygon->setClearValue( 10 );
// candidate numbers // candidate numbers
int candPoint, candLine, candPolygon; spinCandLine->setValue( engineSettings.maximumLineCandidatesPerCm() );
engineSettings.numCandidatePositions( candPoint, candLine, candPolygon ); spinCandPolygon->setValue( engineSettings.maximumPolygonCandidatesPerCmSquared() );
spinCandLine->setValue( candLine );
spinCandPolygon->setValue( candPolygon );
chkShowCandidates->setChecked( engineSettings.testFlag( QgsLabelingEngineSettings::DrawCandidates ) ); chkShowCandidates->setChecked( engineSettings.testFlag( QgsLabelingEngineSettings::DrawCandidates ) );
chkShowAllLabels->setChecked( engineSettings.testFlag( QgsLabelingEngineSettings::UseAllLabels ) ); chkShowAllLabels->setChecked( engineSettings.testFlag( QgsLabelingEngineSettings::UseAllLabels ) );
@ -108,7 +109,8 @@ void QgsLabelEngineConfigWidget::apply()
QgsLabelingEngineSettings engineSettings; QgsLabelingEngineSettings engineSettings;
// save // save
engineSettings.setNumCandidatePositions( 0, spinCandLine->value(), spinCandPolygon->value() ); engineSettings.setMaximumLineCandidatesPerCm( spinCandLine->value() );
engineSettings.setMaximumPolygonCandidatesPerCmSquared( spinCandPolygon->value() );
engineSettings.setFlag( QgsLabelingEngineSettings::DrawCandidates, chkShowCandidates->isChecked() ); engineSettings.setFlag( QgsLabelingEngineSettings::DrawCandidates, chkShowCandidates->isChecked() );
engineSettings.setFlag( QgsLabelingEngineSettings::UseAllLabels, chkShowAllLabels->isChecked() ); engineSettings.setFlag( QgsLabelingEngineSettings::UseAllLabels, chkShowAllLabels->isChecked() );
@ -128,8 +130,8 @@ void QgsLabelEngineConfigWidget::apply()
void QgsLabelEngineConfigWidget::setDefaults() void QgsLabelEngineConfigWidget::setDefaults()
{ {
pal::Pal p; pal::Pal p;
spinCandLine->setValue( p.maximumNumberOfLineCandidates() ); spinCandLine->setValue( 5 );
spinCandPolygon->setValue( p.maximumNumberOfPolygonCandidates() ); spinCandPolygon->setValue( 10 );
chkShowCandidates->setChecked( false ); chkShowCandidates->setChecked( false );
chkShowAllLabels->setChecked( false ); chkShowAllLabels->setChecked( false );
chkShowPartialsLabels->setChecked( p.showPartialLabels() ); chkShowPartialsLabels->setChecked( p.showPartialLabels() );

View File

@ -270,11 +270,8 @@ void QgsLabelingEngine::registerLabels( QgsRenderContext &context )
mPal = qgis::make_unique< pal::Pal >(); mPal = qgis::make_unique< pal::Pal >();
// set number of candidates generated per feature mPal->setMaximumLineCandidatesPerMapUnit( context.labelingEngine()->engineSettings().maximumLineCandidatesPerCm() / context.convertToMapUnits( 10, QgsUnitTypes::RenderMillimeters ) );
int candPoint, candLine, candPolygon; mPal->setMaximumPolygonCandidatesPerMapUnitSquared( context.labelingEngine()->engineSettings().maximumPolygonCandidatesPerCmSquared() / std::pow( context.convertToMapUnits( 10, QgsUnitTypes::RenderMillimeters ), 2 ) );
settings.numCandidatePositions( candPoint, candLine, candPolygon );
mPal->setMaximumNumberOfLineCandidates( candLine );
mPal->setMaximumNumberOfPolygonCandidates( candPolygon );
mPal->setShowPartialLabels( settings.testFlag( QgsLabelingEngineSettings::UsePartialCandidates ) ); mPal->setShowPartialLabels( settings.testFlag( QgsLabelingEngineSettings::UsePartialCandidates ) );
mPal->setPlacementVersion( settings.placementVersion() ); mPal->setPlacementVersion( settings.placementVersion() );

View File

@ -32,8 +32,8 @@ void QgsLabelingEngineSettings::readSettingsFromProject( QgsProject *prj )
{ {
bool saved = false; bool saved = false;
mSearchMethod = static_cast< Search >( prj->readNumEntry( QStringLiteral( "PAL" ), QStringLiteral( "/SearchMethod" ), static_cast< int >( Chain ), &saved ) ); mSearchMethod = static_cast< Search >( prj->readNumEntry( QStringLiteral( "PAL" ), QStringLiteral( "/SearchMethod" ), static_cast< int >( Chain ), &saved ) );
mCandLine = prj->readNumEntry( QStringLiteral( "PAL" ), QStringLiteral( "/CandidatesLine" ), 50, &saved ); mMaxLineCandidatesPerCm = prj->readDoubleEntry( QStringLiteral( "PAL" ), QStringLiteral( "/CandidatesLinePerCM" ), 5, &saved );
mCandPolygon = prj->readNumEntry( QStringLiteral( "PAL" ), QStringLiteral( "/CandidatesPolygon" ), 30, &saved ); mMaxPolygonCandidatesPerCmSquared = prj->readDoubleEntry( QStringLiteral( "PAL" ), QStringLiteral( "/CandidatesPolygonPerCM" ), 10, &saved );
mFlags = nullptr; mFlags = nullptr;
if ( prj->readBoolEntry( QStringLiteral( "PAL" ), QStringLiteral( "/ShowingCandidates" ), false, &saved ) ) mFlags |= DrawCandidates; if ( prj->readBoolEntry( QStringLiteral( "PAL" ), QStringLiteral( "/ShowingCandidates" ), false, &saved ) ) mFlags |= DrawCandidates;
@ -59,8 +59,8 @@ void QgsLabelingEngineSettings::readSettingsFromProject( QgsProject *prj )
void QgsLabelingEngineSettings::writeSettingsToProject( QgsProject *project ) void QgsLabelingEngineSettings::writeSettingsToProject( QgsProject *project )
{ {
project->writeEntry( QStringLiteral( "PAL" ), QStringLiteral( "/SearchMethod" ), static_cast< int >( mSearchMethod ) ); project->writeEntry( QStringLiteral( "PAL" ), QStringLiteral( "/SearchMethod" ), static_cast< int >( mSearchMethod ) );
project->writeEntry( QStringLiteral( "PAL" ), QStringLiteral( "/CandidatesLine" ), mCandLine ); project->writeEntry( QStringLiteral( "PAL" ), QStringLiteral( "/CandidatesLinePerCM" ), mMaxLineCandidatesPerCm );
project->writeEntry( QStringLiteral( "PAL" ), QStringLiteral( "/CandidatesPolygon" ), mCandPolygon ); project->writeEntry( QStringLiteral( "PAL" ), QStringLiteral( "/CandidatesPolygonPerCM" ), mMaxPolygonCandidatesPerCmSquared );
project->writeEntry( QStringLiteral( "PAL" ), QStringLiteral( "/ShowingCandidates" ), mFlags.testFlag( DrawCandidates ) ); project->writeEntry( QStringLiteral( "PAL" ), QStringLiteral( "/ShowingCandidates" ), mFlags.testFlag( DrawCandidates ) );
project->writeEntry( QStringLiteral( "PAL" ), QStringLiteral( "/DrawRectOnly" ), mFlags.testFlag( DrawLabelRectOnly ) ); project->writeEntry( QStringLiteral( "PAL" ), QStringLiteral( "/DrawRectOnly" ), mFlags.testFlag( DrawLabelRectOnly ) );

View File

@ -84,28 +84,61 @@ class CORE_EXPORT QgsLabelingEngineSettings
void setFlag( Flag f, bool enabled = true ) { if ( enabled ) mFlags |= f; else mFlags &= ~f; } void setFlag( Flag f, bool enabled = true ) { if ( enabled ) mFlags |= f; else mFlags &= ~f; }
/** /**
* Gets number of candidate positions that will be generated for each label feature. * Returns the maximum number of line label candidate positions per centimeter.
* \deprecated Since QGIS 3.12 the \a candPoint argument is ignored. *
* \see setMaximumLineCandidatesPerCm()
* \since QGIS 3.12
*/ */
void numCandidatePositions( int &candPoint, int &candLine, int &candPolygon ) const double maximumLineCandidatesPerCm() const { return mMaxLineCandidatesPerCm; }
/**
* Sets the maximum number of line label \a candidates per centimeter.
*
* \see maximumLineCandidatesPerCm()
* \since QGIS 3.12
*/
void setMaximumLineCandidatesPerCm( double candidates ) { mMaxLineCandidatesPerCm = candidates; }
/**
* Returns the maximum number of polygon label candidate positions per centimeter squared.
*
* \see setMaximumPolygonCandidatesPerCmSquared()
* \since QGIS 3.12
*/
double maximumPolygonCandidatesPerCmSquared() const { return mMaxPolygonCandidatesPerCmSquared; }
/**
* Sets the maximum number of polygon label \a candidates per centimeter squared.
*
* \see maximumPolygonCandidatesPerCmSquared()
* \since QGIS 3.12
*/
void setMaximumPolygonCandidatesPerCmSquared( double candidates ) { mMaxPolygonCandidatesPerCmSquared = candidates; }
/**
* Gets number of candidate positions that will be generated for each label feature.
* \deprecated Since QGIS 3.12 use maximumPolygonCandidatesPerCmSquared() and
* maximumLineCandidatesPerCm() instead.
*/
Q_DECL_DEPRECATED void numCandidatePositions( int &candPoint, int &candLine, int &candPolygon ) const SIP_DEPRECATED
{ {
Q_UNUSED( candPoint ) Q_UNUSED( candPoint )
candLine = mCandLine; Q_UNUSED( candLine )
candPolygon = mCandPolygon; Q_UNUSED( candPolygon )
} }
/** /**
* Sets the number of candidate positions that will be generated for each label feature. * Sets the number of candidate positions that will be generated for each label feature.
* \deprecated Since QGIS 3.12 the \a candPoint argument is ignored. * \deprecated Since QGIS 3.12 use setMaximumPolygonCandidatesPerCmSquared() and
* setMaximumLineCandidatesPerCm() instead.
*/ */
void setNumCandidatePositions( int candPoint, int candLine, int candPolygon ) Q_DECL_DEPRECATED void setNumCandidatePositions( int candPoint, int candLine, int candPolygon ) SIP_DEPRECATED
{ {
Q_UNUSED( candPoint ) Q_UNUSED( candPoint )
mCandLine = candLine; Q_UNUSED( candLine )
mCandPolygon = candPolygon; Q_UNUSED( candPolygon )
} }
/** /**
* Used to set which search method to use for removal collisions between labels * Used to set which search method to use for removal collisions between labels
* \deprecated since QGIS 3.10 - Chain is always used. * \deprecated since QGIS 3.10 - Chain is always used.
@ -186,10 +219,10 @@ class CORE_EXPORT QgsLabelingEngineSettings
Flags mFlags; Flags mFlags;
//! search method to use for removal collisions between labels //! search method to use for removal collisions between labels
Search mSearchMethod = Chain; Search mSearchMethod = Chain;
//! Number of candedate positions that will be generated for features
int mCandLine = 50, mCandPolygon = 30;
// maximum density of line/polygon candidates per mm
double mMaxLineCandidatesPerCm = 5;
double mMaxPolygonCandidatesPerCmSquared = 10;
QColor mUnplacedLabelColor = QColor( 255, 0, 0 ); QColor mUnplacedLabelColor = QColor( 255, 0, 0 );

View File

@ -157,6 +157,60 @@ QgsFeatureId FeaturePart::featureId() const
return mLF->id(); return mLF->id();
} }
std::size_t FeaturePart::maximumLineCandidates() const
{
if ( mCachedMaxLineCandidates > 0 )
return mCachedMaxLineCandidates;
GEOSContextHandle_t geosctxt = QgsGeos::getGEOSHandler();
try
{
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 maxForLayer = mLF->layer()->maximumLineLabelCandidates();
if ( maxForLayer == 0 )
mCachedMaxLineCandidates = candidatesForLineLength;
else
mCachedMaxLineCandidates = std::min( candidatesForLineLength, maxForLayer );
return mCachedMaxLineCandidates;
}
}
catch ( GEOSException & )
{
}
mCachedMaxLineCandidates = 1;
return mCachedMaxLineCandidates;
}
std::size_t FeaturePart::maximumPolygonCandidates() const
{
if ( mCachedMaxPolygonCandidates > 0 )
return mCachedMaxPolygonCandidates;
GEOSContextHandle_t geosctxt = QgsGeos::getGEOSHandler();
try
{
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 maxForLayer = mLF->layer()->maximumPolygonLabelCandidates();
if ( maxForLayer == 0 )
mCachedMaxPolygonCandidates = candidatesForArea;
else
mCachedMaxPolygonCandidates = std::min( candidatesForArea, maxForLayer );
return mCachedMaxPolygonCandidates;
}
}
catch ( GEOSException & )
{
}
mCachedMaxPolygonCandidates = 1;
return mCachedMaxPolygonCandidates;
}
bool FeaturePart::hasSameLabelFeatureAs( FeaturePart *part ) const bool FeaturePart::hasSameLabelFeatureAs( FeaturePart *part ) const
{ {
if ( !part ) if ( !part )
@ -635,7 +689,8 @@ std::size_t FeaturePart::createCandidatesAlongLine( std::vector< std::unique_ptr
//prefer to label along straightish segments: //prefer to label along straightish segments:
std::size_t candidates = createCandidatesAlongLineNearStraightSegments( lPos, mapShape, pal ); std::size_t candidates = createCandidatesAlongLineNearStraightSegments( lPos, mapShape, pal );
if ( static_cast< int >( candidates ) < mLF->layer()->maximumLineLabelCandidates() ) const std::size_t candidateTargetCount = maximumLineCandidates();
if ( candidates < candidateTargetCount )
{ {
// but not enough candidates yet, so fallback to labeling near whole line's midpoint // but not enough candidates yet, so fallback to labeling near whole line's midpoint
candidates = createCandidatesAlongLineNearMidpoint( lPos, mapShape, candidates > 0 ? 0.01 : 0.0, pal ); candidates = createCandidatesAlongLineNearMidpoint( lPos, mapShape, candidates > 0 ? 0.01 : 0.0, pal );
@ -734,8 +789,9 @@ std::size_t FeaturePart::createCandidatesAlongLineNearStraightSegments( std::vec
return 0; //createCandidatesAlongLineNearMidpoint will be more appropriate return 0; //createCandidatesAlongLineNearMidpoint will be more appropriate
} }
const std::size_t candidateTargetCount = maximumLineCandidates();
double lineStepDistance = ( totalLineLength - labelWidth ); // distance to move along line with each candidate double lineStepDistance = ( totalLineLength - labelWidth ); // distance to move along line with each candidate
lineStepDistance = std::min( std::min( labelHeight, labelWidth ), lineStepDistance / mLF->layer()->maximumLineLabelCandidates() ); lineStepDistance = std::min( std::min( labelHeight, labelWidth ), lineStepDistance / candidateTargetCount );
double distanceToEndOfSegment = 0.0; double distanceToEndOfSegment = 0.0;
int lastNodeInSegment = 0; int lastNodeInSegment = 0;
@ -906,9 +962,11 @@ std::size_t FeaturePart::createCandidatesAlongLineNearMidpoint( std::vector< std
double lineStepDistance = ( totalLineLength - labelWidth ); // distance to move along line with each candidate double lineStepDistance = ( totalLineLength - labelWidth ); // distance to move along line with each candidate
double currentDistanceAlongLine = 0; double currentDistanceAlongLine = 0;
const std::size_t candidateTargetCount = maximumLineCandidates();
if ( totalLineLength > labelWidth ) if ( totalLineLength > labelWidth )
{ {
lineStepDistance = std::min( std::min( labelHeight, labelWidth ), lineStepDistance / mLF->layer()->maximumLineLabelCandidates() ); lineStepDistance = std::min( std::min( labelHeight, labelWidth ), lineStepDistance / candidateTargetCount );
} }
else if ( !line->isClosed() ) // line length < label width => centering label position else if ( !line->isClosed() ) // line length < label width => centering label position
{ {
@ -1272,7 +1330,8 @@ std::size_t FeaturePart::createCurvedCandidatesAlongLine( std::vector< std::uniq
return 0; return 0;
QLinkedList<LabelPosition *> positions; QLinkedList<LabelPosition *> positions;
double delta = std::max( li->label_height / 6, total_distance / mLF->layer()->maximumLineLabelCandidates() ); const std::size_t candidateTargetCount = maximumLineCandidates();
double delta = std::max( li->label_height / 6, total_distance / candidateTargetCount );
pal::LineArrangementFlags flags = mLF->arrangementFlags(); pal::LineArrangementFlags flags = mLF->arrangementFlags();
if ( flags == 0 ) if ( flags == 0 )

View File

@ -126,6 +126,16 @@ namespace pal
*/ */
QgsFeatureId featureId() const; QgsFeatureId featureId() const;
/**
* Returns the maximum number of line candidates to generate for this feature.
*/
std::size_t maximumLineCandidates() const;
/**
* Returns the maximum number of polygon candidates to generate for this feature.
*/
std::size_t maximumPolygonCandidates() const;
/** /**
* Generates a list of candidate positions for labels for this feature. * Generates a list of candidate positions for labels for this feature.
*/ */
@ -349,6 +359,9 @@ namespace pal
LabelPosition::Quadrant quadrantFromOffset() const; LabelPosition::Quadrant quadrantFromOffset() const;
int mTotalRepeats = 0; int mTotalRepeats = 0;
mutable std::size_t mCachedMaxLineCandidates = 0;
mutable std::size_t mCachedMaxPolygonCandidates = 0;
}; };
} // end namespace pal } // end namespace pal

View File

@ -103,7 +103,7 @@ namespace pal
* Returns the maximum number of point label candidates to generate for features * Returns the maximum number of point label candidates to generate for features
* in this layer. * in this layer.
*/ */
int maximumPointLabelCandidates() const std::size_t maximumPointLabelCandidates() const
{ {
// when an extreme number of features exist in the layer, we limit the number of candidates // when an extreme number of features exist in the layer, we limit the number of candidates
// to avoid the engine processing endlessly... // to avoid the engine processing endlessly...
@ -124,42 +124,42 @@ namespace pal
* Returns the maximum number of line label candidates to generate for features * Returns the maximum number of line label candidates to generate for features
* in this layer. * in this layer.
*/ */
int maximumLineLabelCandidates() const std::size_t maximumLineLabelCandidates() const
{ {
// when an extreme number of features exist in the layer, we limit the number of candidates // when an extreme number of features exist in the layer, we limit the number of candidates
// to avoid the engine processing endlessly... // to avoid the engine processing endlessly...
const int size = mHashtable.size(); const int size = mHashtable.size();
if ( size > 1000 ) if ( size > 1000 )
return std::min( pal->mMaxLineCandidates, 5 ); return static_cast< std::size_t >( 5 );
else if ( size > 500 ) else if ( size > 500 )
return std::min( pal->mMaxLineCandidates, 10 ); return static_cast< std::size_t >( 10 );
else if ( size > 200 ) else if ( size > 200 )
return std::min( pal->mMaxLineCandidates, 20 ); return static_cast< std::size_t >( 20 );
else if ( size > 100 ) else if ( size > 100 )
return std::min( pal->mMaxLineCandidates, 40 ); return static_cast< std::size_t >( 40 );
else else
return pal->mMaxLineCandidates; return static_cast< std::size_t >( 0 );
} }
/** /**
* Returns the maximum number of polygon label candidates to generate for features * Returns the maximum number of polygon label candidates to generate for features
* in this layer. * in this layer.
*/ */
int maximumPolygonLabelCandidates() const std::size_t maximumPolygonLabelCandidates() const
{ {
// when an extreme number of features exist in the layer, we limit the number of candidates // when an extreme number of features exist in the layer, we limit the number of candidates
// to avoid the engine processing endlessly... // to avoid the engine processing endlessly...
const int size = mHashtable.size(); const int size = mHashtable.size();
if ( size > 1000 ) if ( size > 1000 )
return std::min( pal->mMaxPolyCandidates, 5 ); return static_cast< std::size_t >( 5 );
else if ( size > 500 ) else if ( size > 500 )
return std::min( pal->mMaxPolyCandidates, 15 ); return static_cast< std::size_t >( 15 );
else if ( size > 200 ) else if ( size > 200 )
return std::min( pal->mMaxPolyCandidates, 20 ); return static_cast< std::size_t >( 20 );
else if ( size > 100 ) else if ( size > 100 )
return std::min( pal->mMaxPolyCandidates, 25 ); return static_cast< std::size_t >( 25 );
else else
return pal->mMaxPolyCandidates; return static_cast< std::size_t >( 0 );
} }
//! Returns pointer to the associated provider //! Returns pointer to the associated provider

View File

@ -295,11 +295,11 @@ std::unique_ptr<Problem> Pal::extract( const QgsRectangle &extent, const QgsGeom
break; break;
case GEOS_LINESTRING: case GEOS_LINESTRING:
max_p = feat->feature->layer()->maximumLineLabelCandidates(); max_p = feat->feature->maximumLineCandidates();
break; break;
case GEOS_POLYGON: case GEOS_POLYGON:
max_p = feat->feature->layer()->maximumPolygonLabelCandidates(); max_p = feat->feature->maximumPolygonCandidates();
break; break;
} }
@ -443,19 +443,6 @@ QList<LabelPosition *> Pal::solveProblem( Problem *prob, bool displayAll, QList<
return prob->getSolution( displayAll, unlabeled ); return prob->getSolution( displayAll, unlabeled );
} }
void Pal::setMaximumNumberOfLineCandidates( int line_p )
{
if ( line_p > 0 )
this->mMaxLineCandidates = line_p;
}
void Pal::setMaximumNumberOfPolygonCandidates( int poly_p )
{
if ( poly_p > 0 )
this->mMaxPolyCandidates = poly_p;
}
void Pal::setMinIt( int min_it ) void Pal::setMinIt( int min_it )
{ {
if ( min_it >= 0 ) if ( min_it >= 0 )
@ -494,16 +481,6 @@ void Pal::setShowPartialLabels( bool show )
this->mShowPartialLabels = show; this->mShowPartialLabels = show;
} }
int Pal::maximumNumberOfLineCandidates() const
{
return mMaxLineCandidates;
}
int Pal::maximumNumberOfPolygonCandidates() const
{
return mMaxPolyCandidates;
}
QgsLabelingEngineSettings::PlacementEngineVersion Pal::placementVersion() const QgsLabelingEngineSettings::PlacementEngineVersion Pal::placementVersion() const
{ {
return mPlacementVersion; return mPlacementVersion;

View File

@ -174,28 +174,32 @@ namespace pal
bool showPartialLabels() const; bool showPartialLabels() const;
/** /**
* Sets the maximum number of candidates to generate for line features. * Returns the maximum number of line label candidate positions per map unit.
* *
* The larger the value, the longer the labeling solution will take to calculate. * \see setMaximumLineCandidatesPerCm()
*/ */
void setMaximumNumberOfLineCandidates( int candidates ); double maximumLineCandidatesPerMapUnit() const { return mMaxLineCandidatesPerMapUnit; }
/** /**
* Sets the maximum number of candidates to generate for polygon features. * Sets the maximum number of line label \a candidates per map unit.
* *
* The larger the value, the longer the labeling solution will take to calculate. * \see maximumLineCandidatesPerMapUnit()
*/ */
void setMaximumNumberOfPolygonCandidates( int candidates ); void setMaximumLineCandidatesPerMapUnit( double candidates ) { mMaxLineCandidatesPerMapUnit = candidates; }
/** /**
* Returns the number of candidates to generate for line features. * Returns the maximum number of polygon label candidate positions per map unit squared.
*
* \see setMaximumPolygonCandidatesPerMapUnitSquared()
*/ */
int maximumNumberOfLineCandidates() const; double maximumPolygonCandidatesPerMapUnitSquared() const { return mMaxPolygonCandidatesPerMapUnitSquared; }
/** /**
* Returns the number of candidates to generate for polygon features. * Sets the maximum number of polygon label \a candidates per map unit squared.
*
* \see maximumPolygonCandidatesPerMapUnitSquared()
*/ */
int maximumNumberOfPolygonCandidates() const; void setMaximumPolygonCandidatesPerMapUnitSquared( double candidates ) { mMaxPolygonCandidatesPerMapUnitSquared = candidates; }
/** /**
* Returns the placement engine version, which dictates how the label placement problem is solved. * Returns the placement engine version, which dictates how the label placement problem is solved.
@ -217,16 +221,6 @@ namespace pal
QMutex mMutex; QMutex mMutex;
/**
* Maximum number of candidates for a line.
*/
int mMaxLineCandidates = 50;
/**
* Maximum number of candidates for a polygon.
*/
int mMaxPolyCandidates = 30;
/* /*
* POPMUSIC Tuning * POPMUSIC Tuning
*/ */
@ -244,6 +238,9 @@ namespace pal
*/ */
bool mShowPartialLabels = true; bool mShowPartialLabels = true;
double mMaxLineCandidatesPerMapUnit = 0;
double mMaxPolygonCandidatesPerMapUnitSquared = 0;
QgsLabelingEngineSettings::PlacementEngineVersion mPlacementVersion = QgsLabelingEngineSettings::PlacementEngineVersion2; QgsLabelingEngineSettings::PlacementEngineVersion mPlacementVersion = QgsLabelingEngineSettings::PlacementEngineVersion2;
//! Callback that may be called from PAL to check whether the job has not been canceled in meanwhile //! Callback that may be called from PAL to check whether the job has not been canceled in meanwhile

View File

@ -50,32 +50,6 @@
<string>Number of Candidates</string> <string>Number of Candidates</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<widget class="QSpinBox" name="spinCandLine">
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>999</number>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="spinCandPolygon">
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>999</number>
</property>
</widget>
</item>
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="label_3"> <widget class="QLabel" name="label_3">
<property name="sizePolicy"> <property name="sizePolicy">
@ -85,7 +59,7 @@
</sizepolicy> </sizepolicy>
</property> </property>
<property name="text"> <property name="text">
<string>Line</string> <string>Line (per cm)</string>
</property> </property>
<property name="alignment"> <property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
@ -101,13 +75,45 @@
</sizepolicy> </sizepolicy>
</property> </property>
<property name="text"> <property name="text">
<string>Polygon</string> <string>Polygon (per cm²)</string>
</property> </property>
<property name="alignment"> <property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="1">
<widget class="QgsDoubleSpinBox" name="spinCandLine">
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="maximum">
<double>1000.000000000000000</double>
</property>
<property name="singleStep">
<double>1.000000000000000</double>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QgsDoubleSpinBox" name="spinCandPolygon">
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="maximum">
<double>1000.000000000000000</double>
</property>
<property name="singleStep">
<double>1.000000000000000</double>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>
@ -257,6 +263,11 @@
<header>qgspanelwidget.h</header> <header>qgspanelwidget.h</header>
<container>1</container> <container>1</container>
</customwidget> </customwidget>
<customwidget>
<class>QgsDoubleSpinBox</class>
<extends>QDoubleSpinBox</extends>
<header>qgsdoublespinbox.h</header>
</customwidget>
</customwidgets> </customwidgets>
<tabstops> <tabstops>
<tabstop>spinCandLine</tabstop> <tabstop>spinCandLine</tabstop>

View File

@ -122,13 +122,11 @@ void TestQgsMapSettings::testLabelingEngineSettings()
// test that setting labeling engine settings for QgsMapSettings works // test that setting labeling engine settings for QgsMapSettings works
QgsMapSettings ms; QgsMapSettings ms;
QgsLabelingEngineSettings les; QgsLabelingEngineSettings les;
les.setNumCandidatePositions( 4, 8, 15 ); // 23, 42... ;) les.setMaximumLineCandidatesPerCm( 4 );
les.setMaximumPolygonCandidatesPerCmSquared( 8.0 );
ms.setLabelingEngineSettings( les ); ms.setLabelingEngineSettings( les );
int c1, c2, c3; QCOMPARE( ms.labelingEngineSettings().maximumLineCandidatesPerCm(), 4.0 );
ms.labelingEngineSettings().numCandidatePositions( c1, c2, c3 ); QCOMPARE( ms.labelingEngineSettings().maximumPolygonCandidatesPerCmSquared(), 8.0 );
QCOMPARE( c1, 4 );
QCOMPARE( c2, 8 );
QCOMPARE( c3, 15 );
// ensure that setting labeling engine settings also sets text format // ensure that setting labeling engine settings also sets text format
les.setDefaultTextRenderFormat( QgsRenderContext::TextFormatAlwaysText ); les.setDefaultTextRenderFormat( QgsRenderContext::TextFormatAlwaysText );