Skip to content

Commit b1774d6

Browse files
committedJun 10, 2019
Fix labeling ignores "label per part" setting when geometry parts
are adjacent Fixes #26763 (cherry picked from commit 4cb1213)
1 parent 25c8cb7 commit b1774d6

File tree

3 files changed

+81
-6
lines changed

3 files changed

+81
-6
lines changed
 

‎src/core/qgspallabeling.cpp

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
#include "qgssymbollayerutils.h"
6060
#include "qgsmaptopixelgeometrysimplifier.h"
6161
#include "qgscurvepolygon.h"
62+
#include "qgsgeometrycollection.h"
6263
#include <QMessageBox>
6364

6465

@@ -2974,15 +2975,37 @@ QgsGeometry QgsPalLabeling::prepareGeometry( const QgsGeometry &geometry, QgsRen
29742975
}
29752976

29762977
// fix invalid polygons
2977-
if ( geom.type() == QgsWkbTypes::PolygonGeometry && !geom.isGeosValid() )
2978+
if ( geom.type() == QgsWkbTypes::PolygonGeometry )
29782979
{
2979-
QgsGeometry bufferGeom = geom.buffer( 0, 0 );
2980-
if ( bufferGeom.isNull() )
2980+
if ( geom.isMultipart() )
29812981
{
2982-
QgsDebugMsg( QStringLiteral( "Could not repair geometry: %1" ).arg( bufferGeom.lastError() ) );
2983-
return QgsGeometry();
2982+
// important -- we need to treat ever part in isolation here. We can't test the validity of the whole geometry
2983+
// at once, because touching parts would result in an invalid geometry, and buffering this "dissolves" the parts.
2984+
// because the actual label engine treats parts as separate entities, we aren't bound by the usual "touching parts are invalid" rule
2985+
// see https://github.com/qgis/QGIS/issues/26763
2986+
QVector< QgsGeometry> parts;
2987+
parts.reserve( qgsgeometry_cast< const QgsGeometryCollection * >( geom.constGet() )->numGeometries() );
2988+
for ( auto it = geom.const_parts_begin(); it != geom.const_parts_end(); ++it )
2989+
{
2990+
QgsGeometry partGeom( ( *it )->clone() );
2991+
if ( !partGeom.isGeosValid() )
2992+
{
2993+
partGeom = partGeom.buffer( 0, 0 );
2994+
}
2995+
parts.append( partGeom );
2996+
}
2997+
geom = QgsGeometry::collectGeometry( parts );
2998+
}
2999+
else if ( !geom.isGeosValid() )
3000+
{
3001+
QgsGeometry bufferGeom = geom.buffer( 0, 0 );
3002+
if ( bufferGeom.isNull() )
3003+
{
3004+
QgsDebugMsg( QStringLiteral( "Could not repair geometry: %1" ).arg( bufferGeom.lastError() ) );
3005+
return QgsGeometry();
3006+
}
3007+
geom = bufferGeom;
29843008
}
2985-
geom = bufferGeom;
29863009
}
29873010

29883011
if ( !clipGeometry.isNull() &&

‎tests/src/core/testqgslabelingengine.cpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ class TestQgsLabelingEngine : public QObject
5252
void testRegisterFeatureUnprojectible();
5353
void testRotateHidePartial();
5454
void testParallelLabelSmallFeature();
55+
void testAdjacentParts();
5556

5657
private:
5758
QgsVectorLayer *vl = nullptr;
@@ -805,5 +806,56 @@ void TestQgsLabelingEngine::testParallelLabelSmallFeature()
805806
// QVERIFY( imageCheck( "label_rotate_hide_partial", img, 20 ) );
806807
}
807808

809+
void TestQgsLabelingEngine::testAdjacentParts()
810+
{
811+
// test combination of map rotation with reprojected layer
812+
QgsPalLayerSettings settings;
813+
setDefaultLabelParams( settings );
814+
815+
QgsTextFormat format = settings.format();
816+
format.setSize( 20 );
817+
format.setColor( QColor( 0, 0, 0 ) );
818+
settings.setFormat( format );
819+
820+
settings.fieldName = QStringLiteral( "'X'" );
821+
settings.isExpression = true;
822+
settings.placement = QgsPalLayerSettings::OverPoint;
823+
settings.labelPerPart = true;
824+
825+
std::unique_ptr< QgsVectorLayer> vl2( new QgsVectorLayer( QStringLiteral( "Polygon?crs=epsg:3946&field=id:integer" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) ) );
826+
vl2->setRenderer( new QgsNullSymbolRenderer() );
827+
828+
QgsFeature f;
829+
f.setAttributes( QgsAttributes() << 1 );
830+
f.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "MultiPolygon (((1967901.6872910603415221 5162590.11975561361759901, 1967905.31832842249423265 5162591.80023225769400597, 1967907.63076798897236586 5162586.43503414187580347, 1967903.84105980419553816 5162584.57283254805952311, 1967901.6872910603415221 5162590.11975561361759901)),((1967901.64785283687524498 5162598.3270823871716857, 1967904.82891705213114619 5162601.06552503909915686, 1967910.82140435534529388 5162587.99774718284606934, 1967907.63076798897236586 5162586.43503414187580347, 1967905.31832842249423265 5162591.80023225769400597, 1967901.6872910603415221 5162590.11975561361759901, 1967899.27472299290820956 5162596.28855143301188946, 1967901.64785283687524498 5162598.3270823871716857)),((1967904.82891705213114619 5162601.06552503909915686, 1967901.64785283687524498 5162598.3270823871716857, 1967884.28552994946949184 5162626.09785370342433453, 1967895.81538487318903208 5162633.84423183929175138, 1967901.64141261484473944 5162624.63927845563739538, 1967906.47453573765233159 5162616.87410452589392662, 1967913.7844126324634999 5162604.47178338281810284, 1967909.58057221467606723 5162602.89022256527096033, 1967904.82891705213114619 5162601.06552503909915686)))" ) ) );
831+
QVERIFY( vl2->dataProvider()->addFeature( f ) );
832+
833+
vl2->setLabeling( new QgsVectorLayerSimpleLabeling( settings ) ); // TODO: this should not be necessary!
834+
vl2->setLabelsEnabled( true );
835+
836+
// make a fake render context
837+
QSize size( 640, 480 );
838+
QgsMapSettings mapSettings;
839+
mapSettings.setDestinationCrs( vl2->crs() );
840+
841+
mapSettings.setOutputSize( size );
842+
mapSettings.setExtent( f.geometry().boundingBox() );
843+
mapSettings.setLayers( QList<QgsMapLayer *>() << vl2.get() );
844+
mapSettings.setOutputDpi( 96 );
845+
846+
QgsLabelingEngineSettings engineSettings = mapSettings.labelingEngineSettings();
847+
engineSettings.setFlag( QgsLabelingEngineSettings::UsePartialCandidates, false );
848+
engineSettings.setFlag( QgsLabelingEngineSettings::DrawLabelRectOnly, true );
849+
//engineSettings.setFlag( QgsLabelingEngineSettings::DrawCandidates, true );
850+
mapSettings.setLabelingEngineSettings( engineSettings );
851+
852+
QgsMapRendererSequentialJob job( mapSettings );
853+
job.start();
854+
job.waitForFinished();
855+
856+
QImage img = job.renderedImage();
857+
QVERIFY( imageCheck( QStringLiteral( "label_adjacent_parts" ), img, 20 ) );
858+
}
859+
808860
QGSTEST_MAIN( TestQgsLabelingEngine )
809861
#include "testqgslabelingengine.moc"

0 commit comments

Comments
 (0)
Please sign in to comment.