Skip to content

Commit

Permalink
Move merge line settings to QgsLabelLineSettings
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Aug 17, 2020
1 parent 23848e0 commit d93d881
Show file tree
Hide file tree
Showing 12 changed files with 77 additions and 34 deletions.
16 changes: 16 additions & 0 deletions python/core/auto_generated/labeling/qgslabellinesettings.sip.in
Expand Up @@ -39,6 +39,22 @@ Returns the line placement ``flags``, which dictate how line labels can be place
above or below the lines.

.. seealso:: :py:func:`placementFlags`
%End

bool mergeLines() const;
%Docstring
Returns ``True`` if connected line features with identical label text should be merged
prior to generating label positions.

.. seealso:: :py:func:`setMergeLines`
%End

void setMergeLines( bool merge );
%Docstring
Sets whether connected line features with identical label text should be merged
prior to generating label positions.

.. seealso:: :py:func:`mergeLines`
%End

void updateDataDefinedProperties( const QgsPropertyCollection &properties, QgsExpressionContext &context );
Expand Down
9 changes: 5 additions & 4 deletions python/core/auto_generated/labeling/qgspallabeling.sip.in
Expand Up @@ -133,9 +133,9 @@ class QgsPalLayerSettings
AboveLine,
BelowLine,
MapOrientation,
} /Deprecated/;
};

enum
enum QuadrantPosition
{
QuadrantAboveLeft,
QuadrantAbove,
Expand Down Expand Up @@ -487,8 +487,6 @@ Sets the polygon placement ``flags``, which dictate how polygon labels can be pl

bool labelPerPart;

bool mergeLines;


%Property( name = limitNumLabels, get = _limitNumLabels, set = _setLimitNumLabels )
%Property( name = maxNumLabels, get = _maxNumLabels, set = _setMaxNumLabels )
Expand All @@ -497,6 +495,7 @@ Sets the polygon placement ``flags``, which dictate how polygon labels can be pl
%Property( name = obstacleFactor, get = _getObstacleFactor, set = _setObstacleFactor )
%Property( name = obstacleType, get = _getObstacleType, set = _setObstacleType )
%Property( name = placementFlags, get = _getLinePlacementFlags, set = _setLinePlacementFlags )
%Property( name = mergeLines, get = _getMergeLines, set = _setMergeLines )

bool _limitNumLabels() const;
void _setLimitNumLabels( bool limit );
Expand All @@ -512,6 +511,8 @@ Sets the polygon placement ``flags``, which dictate how polygon labels can be pl
void _setObstacleType( ObstacleType type );
unsigned int _getLinePlacementFlags() const;
void _setLinePlacementFlags( unsigned int flags );
bool _getMergeLines() const;
void _setMergeLines( bool merge );

double zIndex;

Expand Down
1 change: 1 addition & 0 deletions src/core/labeling/qgslabellinesettings.cpp
Expand Up @@ -32,3 +32,4 @@ void QgsLabelLineSettings::updateDataDefinedProperties( const QgsPropertyCollect
}
}
}

18 changes: 17 additions & 1 deletion src/core/labeling/qgslabellinesettings.h
Expand Up @@ -53,6 +53,22 @@ class CORE_EXPORT QgsLabelLineSettings
*/
void setPlacementFlags( QgsLabeling::LinePlacementFlags flags ) { mPlacementFlags = flags; }

/**
* Returns TRUE if connected line features with identical label text should be merged
* prior to generating label positions.
*
* \see setMergeLines()
*/
bool mergeLines() const { return mMergeLines; }

/**
* Sets whether connected line features with identical label text should be merged
* prior to generating label positions.
*
* \see mergeLines()
*/
void setMergeLines( bool merge ) { mMergeLines = merge; }

/**
* Updates the thinning settings to respect any data defined properties
* set within the specified \a properties collection.
Expand All @@ -61,7 +77,7 @@ class CORE_EXPORT QgsLabelLineSettings

private:
QgsLabeling::LinePlacementFlags mPlacementFlags = QgsLabeling::LinePlacementFlag::AboveLine | QgsLabeling::LinePlacementFlag::MapOrientation;

bool mMergeLines = false;
};

#endif // QGSLABELLINESETTINGS_H
28 changes: 14 additions & 14 deletions src/core/labeling/qgspallabeling.cpp
Expand Up @@ -346,7 +346,6 @@ QgsPalLayerSettings &QgsPalLayerSettings::operator=( const QgsPalLayerSettings &
upsidedownLabels = s.upsidedownLabels;

labelPerPart = s.labelPerPart;
mergeLines = s.mergeLines && !s.addDirectionSymbol;
zIndex = s.zIndex;

mFormat = s.mFormat;
Expand Down Expand Up @@ -846,7 +845,7 @@ void QgsPalLayerSettings::readFromLayerCustomProperties( QgsVectorLayer *layer )
upsidedownLabels = static_cast< UpsideDownLabels >( layer->customProperty( QStringLiteral( "labeling/upsidedownLabels" ), QVariant( Upright ) ).toUInt() );

labelPerPart = layer->customProperty( QStringLiteral( "labeling/labelPerPart" ) ).toBool();
mergeLines = layer->customProperty( QStringLiteral( "labeling/mergeLines" ) ).toBool();
mLineSettings.setMergeLines( layer->customProperty( QStringLiteral( "labeling/mergeLines" ) ).toBool() );
mThinningSettings.setMinimumFeatureSize( layer->customProperty( QStringLiteral( "labeling/minFeatureSize" ) ).toDouble() );
mThinningSettings.setLimitNumberLabelsEnabled( layer->customProperty( QStringLiteral( "labeling/limitNumLabels" ), QVariant( false ) ).toBool() );
mThinningSettings.setMaximumNumberLabels( layer->customProperty( QStringLiteral( "labeling/maxNumLabels" ), QVariant( 2000 ) ).toInt() );
Expand Down Expand Up @@ -1074,7 +1073,7 @@ void QgsPalLayerSettings::readXml( const QDomElement &elem, const QgsReadWriteCo
upsidedownLabels = static_cast< UpsideDownLabels >( renderingElem.attribute( QStringLiteral( "upsidedownLabels" ), QString::number( Upright ) ).toUInt() );

labelPerPart = renderingElem.attribute( QStringLiteral( "labelPerPart" ) ).toInt();
mergeLines = renderingElem.attribute( QStringLiteral( "mergeLines" ) ).toInt();
mLineSettings.setMergeLines( renderingElem.attribute( QStringLiteral( "mergeLines" ) ).toInt() );
mThinningSettings.setMinimumFeatureSize( renderingElem.attribute( QStringLiteral( "minFeatureSize" ) ).toDouble() );
mThinningSettings.setLimitNumberLabelsEnabled( renderingElem.attribute( QStringLiteral( "limitNumLabels" ), QStringLiteral( "0" ) ).toInt() );
mThinningSettings.setMaximumNumberLabels( renderingElem.attribute( QStringLiteral( "maxNumLabels" ), QStringLiteral( "2000" ) ).toInt() );
Expand Down Expand Up @@ -1222,7 +1221,7 @@ QDomElement QgsPalLayerSettings::writeXml( QDomDocument &doc, const QgsReadWrite
renderingElem.setAttribute( QStringLiteral( "upsidedownLabels" ), static_cast< unsigned int >( upsidedownLabels ) );

renderingElem.setAttribute( QStringLiteral( "labelPerPart" ), labelPerPart );
renderingElem.setAttribute( QStringLiteral( "mergeLines" ), mergeLines );
renderingElem.setAttribute( QStringLiteral( "mergeLines" ), mLineSettings.mergeLines() );
renderingElem.setAttribute( QStringLiteral( "minFeatureSize" ), mThinningSettings.minimumFeatureSize() );
renderingElem.setAttribute( QStringLiteral( "limitNumLabels" ), mThinningSettings.limitNumberOfLabelsEnabled() );
renderingElem.setAttribute( QStringLiteral( "maxNumLabels" ), mThinningSettings.maximumNumberLabels() );
Expand Down Expand Up @@ -2043,16 +2042,19 @@ void QgsPalLayerSettings::registerFeature( const QgsFeature &f, QgsRenderContext
}
}

QgsLabelLineSettings lineSettings = mLineSettings;
lineSettings.updateDataDefinedProperties( mDataDefinedProperties, context.expressionContext() );

// if using fitInPolygonOnly option, generate the permissible zone (must happen before geometry is modified - e.g.,
// as a result of using perimeter based labeling and the geometry is converted to a boundary)
// note that we also force this if we are permitting labels to be placed outside of polygons too!
QgsGeometry permissibleZone;
if ( geom.type() == QgsWkbTypes::PolygonGeometry && ( fitInPolygonOnly || polygonPlacement & QgsLabeling::PolygonPlacementFlag::AllowPlacementOutsideOfPolygon ) )
{
permissibleZone = geom;
if ( QgsPalLabeling::geometryRequiresPreparation( permissibleZone, context, ct, doClip ? extentGeom : QgsGeometry(), mergeLines ) )
if ( QgsPalLabeling::geometryRequiresPreparation( permissibleZone, context, ct, doClip ? extentGeom : QgsGeometry(), lineSettings.mergeLines() ) )
{
permissibleZone = QgsPalLabeling::prepareGeometry( permissibleZone, context, ct, doClip ? extentGeom : QgsGeometry(), mergeLines );
permissibleZone = QgsPalLabeling::prepareGeometry( permissibleZone, context, ct, doClip ? extentGeom : QgsGeometry(), lineSettings.mergeLines() );
}
}

Expand All @@ -2065,9 +2067,9 @@ void QgsPalLayerSettings::registerFeature( const QgsFeature &f, QgsRenderContext
}

geos::unique_ptr geos_geom_clone;
if ( QgsPalLabeling::geometryRequiresPreparation( geom, context, ct, doClip ? extentGeom : QgsGeometry(), mergeLines ) )
if ( QgsPalLabeling::geometryRequiresPreparation( geom, context, ct, doClip ? extentGeom : QgsGeometry(), lineSettings.mergeLines() ) )
{
geom = QgsPalLabeling::prepareGeometry( geom, context, ct, doClip ? extentGeom : QgsGeometry(), mergeLines );
geom = QgsPalLabeling::prepareGeometry( geom, context, ct, doClip ? extentGeom : QgsGeometry(), lineSettings.mergeLines() );

if ( geom.isEmpty() )
return;
Expand All @@ -2076,9 +2078,9 @@ void QgsPalLayerSettings::registerFeature( const QgsFeature &f, QgsRenderContext

if ( isObstacle || ( geom.type() == QgsWkbTypes::PointGeometry && offsetType == FromSymbolBounds ) )
{
if ( !obstacleGeometry.isNull() && QgsPalLabeling::geometryRequiresPreparation( obstacleGeometry, context, ct, doClip ? extentGeom : QgsGeometry(), mergeLines ) )
if ( !obstacleGeometry.isNull() && QgsPalLabeling::geometryRequiresPreparation( obstacleGeometry, context, ct, doClip ? extentGeom : QgsGeometry(), lineSettings.mergeLines() ) )
{
obstacleGeometry = QgsGeometry( QgsPalLabeling::prepareGeometry( obstacleGeometry, context, ct, doClip ? extentGeom : QgsGeometry(), mergeLines ) );
obstacleGeometry = QgsGeometry( QgsPalLabeling::prepareGeometry( obstacleGeometry, context, ct, doClip ? extentGeom : QgsGeometry(), lineSettings.mergeLines() ) );
}
}

Expand Down Expand Up @@ -2561,8 +2563,6 @@ void QgsPalLayerSettings::registerFeature( const QgsFeature &f, QgsRenderContext
( *labelFeature )->setHasFixedQuadrant( true );
}

QgsLabelLineSettings lineSettings = mLineSettings;
lineSettings.updateDataDefinedProperties( mDataDefinedProperties, context.expressionContext() );
( *labelFeature )->setArrangementFlags( lineSettings.placementFlags() );

( *labelFeature )->setPolygonPlacementFlags( polygonPlacement );
Expand Down Expand Up @@ -2652,9 +2652,9 @@ void QgsPalLayerSettings::registerObstacleFeature( const QgsFeature &f, QgsRende
geos::unique_ptr geos_geom_clone;
std::unique_ptr<QgsGeometry> scopedPreparedGeom;

if ( QgsPalLabeling::geometryRequiresPreparation( geom, context, ct, extentGeom, mergeLines ) )
if ( QgsPalLabeling::geometryRequiresPreparation( geom, context, ct, extentGeom, mLineSettings.mergeLines() ) )
{
geom = QgsPalLabeling::prepareGeometry( geom, context, ct, extentGeom, mergeLines );
geom = QgsPalLabeling::prepareGeometry( geom, context, ct, extentGeom, mLineSettings.mergeLines() );
}
geos_geom_clone = QgsGeos::asGeos( geom );

Expand Down
11 changes: 4 additions & 7 deletions src/core/labeling/qgspallabeling.h
Expand Up @@ -280,7 +280,7 @@ class CORE_EXPORT QgsPalLayerSettings
MapOrientation = 8, /**< Signifies that the AboveLine and BelowLine flags should respect the map's orientation rather
than the feature's orientation. For example, AboveLine will always result in label's being placed
above a line, regardless of the line's direction. */
} SIP_DEPRECATED;
};

enum QuadrantPosition
{
Expand Down Expand Up @@ -886,12 +886,6 @@ class CORE_EXPORT QgsPalLayerSettings
*/
bool labelPerPart = false;

/**
* TRUE if connected line features with identical label text should be merged
* prior to generating label positions.
*/
bool mergeLines = false;

// TODO QGIS 4.0 - remove this junk

#ifdef SIP_RUN
Expand All @@ -902,6 +896,7 @@ class CORE_EXPORT QgsPalLayerSettings
SIP_PROPERTY( name = obstacleFactor, get = _getObstacleFactor, set = _setObstacleFactor )
SIP_PROPERTY( name = obstacleType, get = _getObstacleType, set = _setObstacleType )
SIP_PROPERTY( name = placementFlags, get = _getLinePlacementFlags, set = _setLinePlacementFlags )
SIP_PROPERTY( name = mergeLines, get = _getMergeLines, set = _setMergeLines )
#endif

///@cond PRIVATE
Expand All @@ -919,6 +914,8 @@ class CORE_EXPORT QgsPalLayerSettings
void _setObstacleType( ObstacleType type ) { mObstacleSettings.setType( static_cast< QgsLabelObstacleSettings::ObstacleType>( type ) ); }
unsigned int _getLinePlacementFlags() const { return static_cast< unsigned int >( mLineSettings.placementFlags() ); }
void _setLinePlacementFlags( unsigned int flags ) { mLineSettings.setPlacementFlags( static_cast< QgsLabeling::LinePlacementFlags >( flags ) ); }
bool _getMergeLines() const { return mLineSettings.mergeLines(); }
void _setMergeLines( bool merge ) { mLineSettings.setMergeLines( merge ); }
///@endcond

//! Z-Index of label, where labels with a higher z-index are rendered on top of labels with a lower z-index
Expand Down
2 changes: 1 addition & 1 deletion src/core/labeling/qgsvectorlayerlabeling.cpp
Expand Up @@ -500,7 +500,7 @@ void QgsAbstractVectorLayerLabeling::writeTextSymbolizer( QDomNode &parent, QgsP
QDomElement vo = QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "forceLeftToRight" ), QStringLiteral( "false" ) );
textSymbolizerElement.appendChild( vo );
}
if ( settings.mergeLines )
if ( settings.lineSettings().mergeLines() )
{
QDomElement vo = QgsSymbolLayerUtils::createVendorOptionElement( doc, QStringLiteral( "group" ), QStringLiteral( "yes" ) );
textSymbolizerElement.appendChild( vo );
Expand Down
2 changes: 1 addition & 1 deletion src/core/labeling/qgsvectorlayerlabelprovider.cpp
Expand Up @@ -82,7 +82,7 @@ void QgsVectorLayerLabelProvider::init()
mFlags |= DrawLabels;
if ( mSettings.displayAll )
mFlags |= DrawAllLabels;
if ( mSettings.mergeLines && !mSettings.addDirectionSymbol )
if ( mSettings.lineSettings().mergeLines() && !mSettings.addDirectionSymbol )
mFlags |= MergeConnectedLines;
if ( mSettings.centroidInside )
mFlags |= CentroidMustBeInside;
Expand Down
4 changes: 2 additions & 2 deletions src/core/qgsvectorlayer.cpp
Expand Up @@ -4888,11 +4888,11 @@ bool QgsVectorLayer::readSldTextSymbolizer( const QDomNode &node, QgsPalLayerSet
}
else if ( it.key() == QLatin1String( "group" ) && it.value() == QLatin1String( "yes" ) )
{
settings.mergeLines = true;
settings.lineSettings().setMergeLines( true );
}
else if ( it.key() == QLatin1String( "labelAllGroup" ) && it.value() == QLatin1String( "true" ) )
{
settings.mergeLines = true;
settings.lineSettings().setMergeLines( true );
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/gui/labeling/qgslabelinggui.cpp
Expand Up @@ -356,7 +356,7 @@ void QgsLabelingGui::setLayer( QgsMapLayer *mapLayer )

chkLabelPerFeaturePart->setChecked( mSettings.labelPerPart );
mPalShowAllLabelsForLayerChkBx->setChecked( mSettings.displayAll );
chkMergeLines->setChecked( mSettings.mergeLines );
chkMergeLines->setChecked( mSettings.lineSettings().mergeLines() );
mMinSizeSpinBox->setValue( mSettings.thinningSettings().minimumFeatureSize() );
mLimitLabelChkBox->setChecked( mSettings.thinningSettings().limitNumberOfLabelsEnabled() );
mLimitLabelSpinBox->setValue( mSettings.thinningSettings().maximumNumberLabels() );
Expand Down Expand Up @@ -568,7 +568,7 @@ QgsPalLayerSettings QgsLabelingGui::layerSettings()

lyr.labelPerPart = chkLabelPerFeaturePart->isChecked();
lyr.displayAll = mPalShowAllLabelsForLayerChkBx->isChecked();
lyr.mergeLines = chkMergeLines->isChecked();
lyr.lineSettings().setMergeLines( chkMergeLines->isChecked() );

lyr.scaleVisibility = mScaleBasedVisibilityChkBx->isChecked();
lyr.minimumScale = mMinScaleWidget->scale();
Expand Down
4 changes: 2 additions & 2 deletions tests/src/core/testqgslabelingengine.cpp
Expand Up @@ -1040,7 +1040,7 @@ void TestQgsLabelingEngine::testTouchingParts()
settings.isExpression = true;
settings.placement = QgsPalLayerSettings::Curved;
settings.labelPerPart = false;
settings.mergeLines = true;
settings.lineSettings().setMergeLines( true );

// if treated individually, none of these parts are long enough for the label to fit -- but the label should be rendered if the mergeLines setting is true,
// because the parts should be merged into a single linestring
Expand Down Expand Up @@ -1096,7 +1096,7 @@ void TestQgsLabelingEngine::testMergingLinesWithForks()
settings.isExpression = true;
settings.placement = QgsPalLayerSettings::Curved;
settings.labelPerPart = false;
settings.mergeLines = true;
settings.lineSettings().setMergeLines( true );

// if treated individually, none of these parts are long enough for the label to fit -- but the label should be rendered if the mergeLines setting is true
std::unique_ptr< QgsVectorLayer> vl2( new QgsVectorLayer( QStringLiteral( "LineString?crs=epsg:3946&field=id:integer" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) ) );
Expand Down
12 changes: 12 additions & 0 deletions tests/src/python/test_qgslabellinesettings.py
Expand Up @@ -38,12 +38,24 @@ def test_line_settings(self):
settings.setPlacementFlags(QgsLabeling.LinePlacementFlag.OnLine | QgsLabeling.LinePlacementFlag.MapOrientation)
self.assertEqual(settings.placementFlags(), QgsLabeling.LinePlacementFlag.OnLine | QgsLabeling.LinePlacementFlag.MapOrientation)

settings.setMergeLines(True)
self.assertTrue(settings.mergeLines())
settings.setMergeLines(False)
self.assertFalse(settings.mergeLines())

# check that compatibility code works
pal_settings = QgsPalLayerSettings()
pal_settings.placementFlags = QgsPalLayerSettings.OnLine | QgsPalLayerSettings.MapOrientation
self.assertEqual(pal_settings.placementFlags, 9)
self.assertTrue(pal_settings.lineSettings().placementFlags(), QgsLabeling.LinePlacementFlag.OnLine | QgsLabeling.LinePlacementFlag.MapOrientation)

pal_settings.mergeLines = True
self.assertTrue(pal_settings.mergeLines)
self.assertTrue(pal_settings.lineSettings().mergeLines())
pal_settings.mergeLines = False
self.assertFalse(pal_settings.mergeLines)
self.assertFalse(pal_settings.lineSettings().mergeLines())

def testUpdateDataDefinedProps(self):
settings = QgsLabelLineSettings()
settings.setPlacementFlags(QgsLabeling.LinePlacementFlag.OnLine)
Expand Down

0 comments on commit d93d881

Please sign in to comment.