Skip to content
Permalink
Browse files

[FEATURE][labeling] Add priority control for obstacles

Allows you to make labels prefer to overlap features from certain
layers rather than others. Can also be data defined, so that certain
features are more likely to be covered than others.
  • Loading branch information
nyalldawson committed Jul 23, 2015
1 parent c97733e commit b4311877f72bdb6516080011c7aa0c3c0d108307
@@ -299,6 +299,7 @@ class QgsPalLayerSettings
FontMinPixel,
FontMaxPixel,
IsObstacle,
ObstacleFactor,

// (data defined only)
Show,
@@ -469,6 +470,11 @@ class QgsPalLayerSettings

double minFeatureSize; // minimum feature size to be labelled (in mm)
bool obstacle; // whether features for layer are obstacles to labels of other layers

/** Obstacle factor, where 1.0 = default, < 1.0 more likely to be covered by labels,
* > 1.0 less likely to be covered
*/
double obstacleFactor;

/** Controls how features act as obstacles for labels
*/
@@ -361,7 +361,10 @@ void QgsLabelingGui::init()

mPrioritySlider->setValue( lyr.priority );
mChkNoObstacle->setChecked( lyr.obstacle );
mObstacleFactorSlider->setValue( lyr.obstacleFactor * 50 );
mObstacleTypeComboBox->setCurrentIndex( mObstacleTypeComboBox->findData( lyr.obstacleType ) );
mPolygonObstacleTypeFrame->setEnabled( lyr.obstacle );
mObstaclePriorityFrame->setEnabled( lyr.obstacle );
chkLabelPerFeaturePart->setChecked( lyr.labelPerPart );
mPalShowAllLabelsForLayerChkBx->setChecked( lyr.displayAll );
chkMergeLines->setChecked( lyr.mergeLines );
@@ -657,6 +660,7 @@ QgsPalLayerSettings QgsLabelingGui::layerSettings()

lyr.priority = mPrioritySlider->value();
lyr.obstacle = mChkNoObstacle->isChecked() || mLabelModeComboBox->currentIndex() == 2;
lyr.obstacleFactor = mObstacleFactorSlider->value() / 50.0;
lyr.obstacleType = ( QgsPalLayerSettings::ObstacleType )mObstacleTypeComboBox->itemData( mObstacleTypeComboBox->currentIndex() ).toInt();
lyr.labelPerPart = chkLabelPerFeaturePart->isChecked();
lyr.displayAll = mPalShowAllLabelsForLayerChkBx->isChecked();
@@ -857,6 +861,7 @@ QgsPalLayerSettings QgsLabelingGui::layerSettings()
setDataDefinedProperty( mShowLabelDDBtn, QgsPalLayerSettings::Show, lyr );
setDataDefinedProperty( mAlwaysShowDDBtn, QgsPalLayerSettings::AlwaysShow, lyr );
setDataDefinedProperty( mIsObstacleDDBtn, QgsPalLayerSettings::IsObstacle, lyr );
setDataDefinedProperty( mObstacleFactorDDBtn, QgsPalLayerSettings::ObstacleFactor, lyr );

return lyr;
}
@@ -1125,6 +1130,8 @@ void QgsLabelingGui::populateDataDefinedButtons( QgsPalLayerSettings& s )

mIsObstacleDDBtn->init( mLayer, s.dataDefinedProperty( QgsPalLayerSettings::IsObstacle ),
QgsDataDefinedButton::AnyType, QgsDataDefinedButton::boolDesc() );
mObstacleFactorDDBtn->init( mLayer, s.dataDefinedProperty( QgsPalLayerSettings::ObstacleFactor ),
QgsDataDefinedButton::AnyType, tr( "double [0.0-10.0]" ) );
}

void QgsLabelingGui::changeTextColor( const QColor &color )
@@ -1714,6 +1721,7 @@ void QgsLabelingGui::on_mDirectSymbRightToolBtn_clicked()
void QgsLabelingGui::on_mChkNoObstacle_toggled( bool active )
{
mPolygonObstacleTypeFrame->setEnabled( active );
mObstaclePriorityFrame->setEnabled( active );
}

void QgsLabelingGui::showBackgroundRadius( bool show )
@@ -72,8 +72,11 @@ namespace pal
break;
}

//scale cost by obstacle's factor
double obstacleCost = obstacle->getFeature()->obstacleFactor() * double( n );

// label cost is penalized
lp->setCost( lp->getCost() + double( n ) );
lp->setCost( lp->getCost() + obstacleCost );
}


@@ -76,6 +76,7 @@ namespace pal
, alwaysShow( false )
, mFixedQuadrant( false )
, mIsObstacle( true )
, mObstacleFactor( 1.0 )
, mPriority( -1.0 )
{
assert( finite( lx ) && finite( ly ) );
@@ -120,6 +120,21 @@ namespace pal
*/
double isObstacle() const { return mIsObstacle; }

/** Sets the obstacle factor for the feature. The factor controls the penalty
* for labels overlapping this feature.
* @param factor larger factors ( > 1.0 ) will result in labels
* which are less likely to cover this feature, smaller factors ( < 1.0 ) mean labels
* are more likely to cover this feature (where required)
* @see obstacleFactor
*/
void setObstacleFactor( double factor ) { mObstacleFactor = factor; }

/** Returns the obstacle factor for the feature. The factor controls the penalty
* for labels overlapping this feature.
* @see setObstacleFactor
*/
double obstacleFactor() const { return mObstacleFactor; }

/** Sets the priority for labeling the feature.
* @param priority feature's priority, as a value between 0 (highest priority)
* and 1 (lowest priority). Set to -1.0 to use the layer's default priority
@@ -174,6 +189,7 @@ namespace pal

bool mFixedQuadrant;
bool mIsObstacle;
double mObstacleFactor;

//-1 if layer priority should be used
double mPriority;
@@ -200,6 +200,7 @@ QgsPalLayerSettings::QgsPalLayerSettings()
limitNumLabels = false;
maxNumLabels = 2000;
obstacle = true;
obstacleFactor = 1.0;
obstacleType = PolygonInterior;

// scale factors
@@ -295,6 +296,7 @@ QgsPalLayerSettings::QgsPalLayerSettings()
mDataDefinedNames.insert( RepeatDistanceUnit, QPair<QString, int>( "RepeatDistanceUnit", -1 ) );
mDataDefinedNames.insert( Priority, QPair<QString, int>( "Priority", -1 ) );
mDataDefinedNames.insert( IsObstacle, QPair<QString, int>( "IsObstacle", -1 ) );
mDataDefinedNames.insert( ObstacleFactor, QPair<QString, int>( "ObstacleFactor", -1 ) );

// (data defined only)
mDataDefinedNames.insert( PositionX, QPair<QString, int>( "PositionX", 9 ) );
@@ -415,6 +417,7 @@ QgsPalLayerSettings::QgsPalLayerSettings( const QgsPalLayerSettings& s )
limitNumLabels = s.limitNumLabels;
maxNumLabels = s.maxNumLabels;
obstacle = s.obstacle;
obstacleFactor = s.obstacleFactor;
obstacleType = s.obstacleType;

// shape background
@@ -924,6 +927,7 @@ void QgsPalLayerSettings::readFromLayer( QgsVectorLayer* layer )
limitNumLabels = layer->customProperty( "labeling/limitNumLabels", QVariant( false ) ).toBool();
maxNumLabels = layer->customProperty( "labeling/maxNumLabels", QVariant( 2000 ) ).toInt();
obstacle = layer->customProperty( "labeling/obstacle", QVariant( true ) ).toBool();
obstacleFactor = layer->customProperty( "labeling/obstacleFactor", QVariant( 1.0 ) ).toDouble();
obstacleType = ( ObstacleType )layer->customProperty( "labeling/obstacleType", QVariant( PolygonInterior ) ).toUInt();

readDataDefinedPropertyMap( layer, dataDefinedProperties );
@@ -1077,6 +1081,7 @@ void QgsPalLayerSettings::writeToLayer( QgsVectorLayer* layer )
layer->setCustomProperty( "labeling/limitNumLabels", limitNumLabels );
layer->setCustomProperty( "labeling/maxNumLabels", maxNumLabels );
layer->setCustomProperty( "labeling/obstacle", obstacle );
layer->setCustomProperty( "labeling/obstacleFactor", obstacleFactor );
layer->setCustomProperty( "labeling/obstacleType", ( unsigned int )obstacleType );

writeDataDefinedPropertyMap( layer, dataDefinedProperties );
@@ -2214,6 +2219,20 @@ void QgsPalLayerSettings::registerFeature( QgsFeature& f, const QgsRenderContext
feat->setIsObstacle( exprVal.toBool() );
}

double featObstacleFactor = obstacleFactor;
if ( dataDefinedEvaluate( QgsPalLayerSettings::ObstacleFactor, exprVal ) )
{
bool ok;
double factorD = exprVal.toDouble( &ok );
if ( ok )
{
factorD = qBound( 0.0, factorD, 10.0 );
factorD = factorD / 5.0 + 0.0001; // convert 0 -> 10 to 0.0001 -> 2.0
featObstacleFactor = factorD;
}
}
feat->setObstacleFactor( featObstacleFactor );

//add parameters for data defined labeling to QgsPalGeometry
QMap< DataDefinedProperties, QVariant >::const_iterator dIt = dataDefinedValues.constBegin();
for ( ; dIt != dataDefinedValues.constEnd(); ++dIt )
@@ -274,6 +274,7 @@ class CORE_EXPORT QgsPalLayerSettings
FontMinPixel = 25,
FontMaxPixel = 26,
IsObstacle = 88,
ObstacleFactor = 89,

// (data defined only)
Show = 15,
@@ -445,6 +446,11 @@ class CORE_EXPORT QgsPalLayerSettings
double minFeatureSize; // minimum feature size to be labelled (in mm)
bool obstacle; // whether features for layer are obstacles to labels of other layers

/** Obstacle factor, where 1.0 = default, < 1.0 more likely to be covered by labels,
* > 1.0 less likely to be covered
*/
double obstacleFactor;

/** Controls how features act as obstacles for labels
*/
ObstacleType obstacleType;
@@ -3488,8 +3488,8 @@ font-style: italic;</string>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>427</width>
<y>-466</y>
<width>578</width>
<height>829</height>
</rect>
</property>
@@ -4818,9 +4818,9 @@ font-style: italic;</string>
<property name="geometry">
<rect>
<x>0</x>
<y>-361</y>
<y>-401</y>
<width>578</width>
<height>724</height>
<height>764</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_8">
@@ -5517,6 +5517,58 @@ font-style: italic;</string>
</item>
</layout>
</item>
<item>
<widget class="QFrame" name="mObstaclePriorityFrame">
<layout class="QHBoxLayout" name="horizontalLayout_18">
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_40">
<property name="text">
<string>Low priority</string>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="mObstacleFactorSlider">
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>100</number>
</property>
<property name="value">
<number>50</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tickPosition">
<enum>QSlider::TicksBelow</enum>
</property>
<property name="tickInterval">
<number>10</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_41">
<property name="text">
<string>High priority</string>
</property>
</widget>
</item>
<item>
<widget class="QgsDataDefinedButton" name="mObstacleFactorDDBtn">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QFrame" name="mPolygonObstacleTypeFrame">
<property name="frameShape">
@@ -5981,8 +6033,8 @@ font-style: italic;</string>
<slot>setCurrentIndex(int)</slot>
<hints>
<hint type="sourcelabel">
<x>47</x>
<y>524</y>
<x>34</x>
<y>599</y>
</hint>
<hint type="destinationlabel">
<x>633</x>

0 comments on commit b431187

Please sign in to comment.
You can’t perform that action at this time.