Skip to content

Commit

Permalink
Fix labeling ignores "label per part" setting when geometry parts
Browse files Browse the repository at this point in the history
are adjacent

Fixes #26763

(cherry picked from commit 4cb1213)
  • Loading branch information
nyalldawson committed Jun 10, 2019
1 parent 25c8cb7 commit b1774d6
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 6 deletions.
35 changes: 29 additions & 6 deletions src/core/qgspallabeling.cpp
Expand Up @@ -59,6 +59,7 @@
#include "qgssymbollayerutils.h"
#include "qgsmaptopixelgeometrysimplifier.h"
#include "qgscurvepolygon.h"
#include "qgsgeometrycollection.h"
#include <QMessageBox>


Expand Down Expand Up @@ -2974,15 +2975,37 @@ QgsGeometry QgsPalLabeling::prepareGeometry( const QgsGeometry &geometry, QgsRen
}

// fix invalid polygons
if ( geom.type() == QgsWkbTypes::PolygonGeometry && !geom.isGeosValid() )
if ( geom.type() == QgsWkbTypes::PolygonGeometry )
{
QgsGeometry bufferGeom = geom.buffer( 0, 0 );
if ( bufferGeom.isNull() )
if ( geom.isMultipart() )
{
QgsDebugMsg( QStringLiteral( "Could not repair geometry: %1" ).arg( bufferGeom.lastError() ) );
return QgsGeometry();
// important -- we need to treat ever part in isolation here. We can't test the validity of the whole geometry
// at once, because touching parts would result in an invalid geometry, and buffering this "dissolves" the parts.
// because the actual label engine treats parts as separate entities, we aren't bound by the usual "touching parts are invalid" rule
// see https://github.com/qgis/QGIS/issues/26763
QVector< QgsGeometry> parts;
parts.reserve( qgsgeometry_cast< const QgsGeometryCollection * >( geom.constGet() )->numGeometries() );
for ( auto it = geom.const_parts_begin(); it != geom.const_parts_end(); ++it )
{
QgsGeometry partGeom( ( *it )->clone() );
if ( !partGeom.isGeosValid() )
{
partGeom = partGeom.buffer( 0, 0 );
}
parts.append( partGeom );
}
geom = QgsGeometry::collectGeometry( parts );
}
else if ( !geom.isGeosValid() )
{
QgsGeometry bufferGeom = geom.buffer( 0, 0 );
if ( bufferGeom.isNull() )
{
QgsDebugMsg( QStringLiteral( "Could not repair geometry: %1" ).arg( bufferGeom.lastError() ) );
return QgsGeometry();
}
geom = bufferGeom;
}
geom = bufferGeom;
}

if ( !clipGeometry.isNull() &&
Expand Down
52 changes: 52 additions & 0 deletions tests/src/core/testqgslabelingengine.cpp
Expand Up @@ -52,6 +52,7 @@ class TestQgsLabelingEngine : public QObject
void testRegisterFeatureUnprojectible();
void testRotateHidePartial();
void testParallelLabelSmallFeature();
void testAdjacentParts();

private:
QgsVectorLayer *vl = nullptr;
Expand Down Expand Up @@ -805,5 +806,56 @@ void TestQgsLabelingEngine::testParallelLabelSmallFeature()
// QVERIFY( imageCheck( "label_rotate_hide_partial", img, 20 ) );
}

void TestQgsLabelingEngine::testAdjacentParts()
{
// test combination of map rotation with reprojected layer
QgsPalLayerSettings settings;
setDefaultLabelParams( settings );

QgsTextFormat format = settings.format();
format.setSize( 20 );
format.setColor( QColor( 0, 0, 0 ) );
settings.setFormat( format );

settings.fieldName = QStringLiteral( "'X'" );
settings.isExpression = true;
settings.placement = QgsPalLayerSettings::OverPoint;
settings.labelPerPart = true;

std::unique_ptr< QgsVectorLayer> vl2( new QgsVectorLayer( QStringLiteral( "Polygon?crs=epsg:3946&field=id:integer" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) ) );
vl2->setRenderer( new QgsNullSymbolRenderer() );

QgsFeature f;
f.setAttributes( QgsAttributes() << 1 );
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)))" ) ) );
QVERIFY( vl2->dataProvider()->addFeature( f ) );

vl2->setLabeling( new QgsVectorLayerSimpleLabeling( settings ) ); // TODO: this should not be necessary!
vl2->setLabelsEnabled( true );

// make a fake render context
QSize size( 640, 480 );
QgsMapSettings mapSettings;
mapSettings.setDestinationCrs( vl2->crs() );

mapSettings.setOutputSize( size );
mapSettings.setExtent( f.geometry().boundingBox() );
mapSettings.setLayers( QList<QgsMapLayer *>() << vl2.get() );
mapSettings.setOutputDpi( 96 );

QgsLabelingEngineSettings engineSettings = mapSettings.labelingEngineSettings();
engineSettings.setFlag( QgsLabelingEngineSettings::UsePartialCandidates, false );
engineSettings.setFlag( QgsLabelingEngineSettings::DrawLabelRectOnly, true );
//engineSettings.setFlag( QgsLabelingEngineSettings::DrawCandidates, true );
mapSettings.setLabelingEngineSettings( engineSettings );

QgsMapRendererSequentialJob job( mapSettings );
job.start();
job.waitForFinished();

QImage img = job.renderedImage();
QVERIFY( imageCheck( QStringLiteral( "label_adjacent_parts" ), img, 20 ) );
}

QGSTEST_MAIN( TestQgsLabelingEngine )
#include "testqgslabelingengine.moc"
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit b1774d6

Please sign in to comment.