Skip to content

Commit

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

Fixes #26763
  • Loading branch information
nyalldawson committed May 28, 2019
1 parent 76d9a26 commit 4cb1213
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 @@ -60,6 +60,7 @@
#include "qgsmaptopixelgeometrysimplifier.h"
#include "qgscurvepolygon.h"
#include "qgsmessagelog.h"
#include "qgsgeometrycollection.h"
#include <QMessageBox>

using namespace pal;
Expand Down Expand Up @@ -3115,15 +3116,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();
void testLabelBoundary();
void testLabelBlockingRegion();

Expand Down Expand Up @@ -807,6 +808,57 @@ 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 ) );
}

void TestQgsLabelingEngine::testLabelBoundary()
{
// test that no labels are drawn outside of the specified label boundary
Expand Down
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 4cb1213

Please sign in to comment.