Skip to content
Permalink
Browse files
Merge pull request #46657 from nirvn/label_alg
[feature][processing] A brand new Extract labels algorithm
  • Loading branch information
nirvn committed Jan 6, 2022
2 parents 34458c4 + e2bb0bb commit 3c001deed8bb7bbaecc07550373c527bcb3bb10b
@@ -90,6 +90,7 @@ set(QGIS_ANALYSIS_SRCS
processing/qgsalgorithmextractbyexpression.cpp
processing/qgsalgorithmextractbyextent.cpp
processing/qgsalgorithmextractbylocation.cpp
processing/qgsalgorithmextractlabels.cpp
processing/qgsalgorithmextractlayoutmapextent.cpp
processing/qgsalgorithmextractzmvalues.cpp
processing/qgsalgorithmextractvertices.cpp

Large diffs are not rendered by default.

@@ -0,0 +1,62 @@
/***************************************************************************
qgsalgorithmextractlabels.h - QgsExtractLabelsAlgorithm
---------------------
begin : 30.12.2021
copyright : (C) 2021 by Mathieu Pellerin
email : nirvn dot asia at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#ifndef QGSALGORITHMEXTRACTLABELS_H
#define QGSALGORITHMEXTRACTLABELS_H

#define SIP_NO_FILE

#include "qgis_sip.h"
#include "qgsprocessingalgorithm.h"
#include "qgslabelingenginesettings.h"

///@cond PRIVATE

class QgsExtractLabelsAlgorithm : public QgsProcessingAlgorithm
{
public:
QgsExtractLabelsAlgorithm() = default;

void initAlgorithm( const QVariantMap &configuration = QVariantMap() ) override;
QString name() const override;
QString displayName() const override;
QStringList tags() const override;
Flags flags() const override;
QString group() const override;
QString groupId() const override;
QString shortHelpString() const override;
QString shortDescription() const override;
QgsExtractLabelsAlgorithm *createInstance() const override SIP_FACTORY;

protected:

QVariantMap processAlgorithm( const QVariantMap &parameters,
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;

bool prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;

private:

QList<QgsMapLayer *> mMapLayers;
QMap<QString, QString> mMapLayerNames;
QMap<QString, QString> mMapThemeStyleOverrides;
QgsLabelingEngineSettings mLabelSettings;
QgsCoordinateReferenceSystem mCrs;

};

///@endcond PRIVATE

#endif // QGSALGORITHMEXTRACTLABELS_H
@@ -73,6 +73,7 @@
#include "qgsalgorithmextractbyexpression.h"
#include "qgsalgorithmextractbyextent.h"
#include "qgsalgorithmextractbylocation.h"
#include "qgsalgorithmextractlabels.h"
#include "qgsalgorithmextractlayoutmapextent.h"
#include "qgsalgorithmextractvertices.h"
#include "qgsalgorithmextractspecificvertices.h"
@@ -321,6 +322,7 @@ void QgsNativeAlgorithms::loadAlgorithms()
addAlgorithm( new QgsExtractByExpressionAlgorithm() );
addAlgorithm( new QgsExtractByExtentAlgorithm() );
addAlgorithm( new QgsExtractByLocationAlgorithm() );
addAlgorithm( new QgsExtractLabelsAlgorithm() );
addAlgorithm( new QgsExtractMValuesAlgorithm() );
addAlgorithm( new QgsExtractVerticesAlgorithm() );
addAlgorithm( new QgsExtractSpecificVerticesAlgorithm() );
@@ -32,6 +32,12 @@ void QgsLabelSinkProvider::drawLabel( QgsRenderContext &context, pal::LabelPosit
mLabelSink->drawLabel( layerId(), context, label, mSettings );
}

void QgsLabelSinkProvider::drawUnplacedLabel( QgsRenderContext &context, pal::LabelPosition *label ) const
{
Q_ASSERT( mLabelSink );
mLabelSink->drawUnplacedLabel( layerId(), context, label, mSettings );
}

QgsRuleBasedLabelSinkProvider::QgsRuleBasedLabelSinkProvider( const QgsRuleBasedLabeling &rules, QgsVectorLayer *layer, QgsLabelSink *sink )
: QgsRuleBasedLabelProvider( rules, layer, false )
, mLabelSink( sink )
@@ -55,3 +61,9 @@ void QgsRuleBasedLabelSinkProvider::drawLabel( QgsRenderContext &context, pal::L
Q_ASSERT( mLabelSink );
mLabelSink->drawLabel( layerId(), context, label, mSettings );
}

void QgsRuleBasedLabelSinkProvider::drawUnplacedLabel( QgsRenderContext &context, pal::LabelPosition *label ) const
{
Q_ASSERT( mLabelSink );
mLabelSink->drawUnplacedLabel( layerId(), context, label, mSettings );
}
@@ -45,6 +45,23 @@ class QgsLabelSink
* to another desired location.
*/
virtual void drawLabel( const QString &layerId, QgsRenderContext &context, pal::LabelPosition *label, const QgsPalLayerSettings &settings ) = 0;

/**
* The drawLabel method is called for each unplaced label.
* \param layerId The layer ID associated to the label
* \param context The render context object
* \param label The label object
* \param settings The layer labeling settings
* \since QGIS 3.24
*/
virtual void drawUnplacedLabel( const QString &layerId, QgsRenderContext &context, pal::LabelPosition *label, const QgsPalLayerSettings &settings )
{
Q_UNUSED( layerId );
Q_UNUSED( context )
Q_UNUSED( label );
Q_UNUSED( settings );
return;
}
};

/**
@@ -61,6 +78,7 @@ class QgsLabelSinkProvider : public QgsVectorLayerLabelProvider
explicit QgsLabelSinkProvider( QgsVectorLayer *layer, const QString &providerId, QgsLabelSink *sink, const QgsPalLayerSettings *settings );

void drawLabel( QgsRenderContext &context, pal::LabelPosition *label ) const override;
void drawUnplacedLabel( QgsRenderContext &context, pal::LabelPosition *label ) const override;

private:
QgsLabelSink *mLabelSink = nullptr;
@@ -86,6 +104,7 @@ class QgsRuleBasedLabelSinkProvider : public QgsRuleBasedLabelProvider
Q_DECL_DEPRECATED void reinit( QgsVectorLayer *layer );

void drawLabel( QgsRenderContext &context, pal::LabelPosition *label ) const override;
void drawUnplacedLabel( QgsRenderContext &context, pal::LabelPosition *label ) const override;

//! Creates a QgsRuleBasedLabelSinkProvider
QgsVectorLayerLabelProvider *createProvider( QgsVectorLayer *layer, const QString &providerId, bool withFeatureLoop, const QgsPalLayerSettings *settings ) override;
@@ -30,7 +30,7 @@ class QgsTextCharacterFormat;
*
* \note not part of public API
*/
class QgsTextLabelFeature : public QgsLabelFeature
class CORE_EXPORT QgsTextLabelFeature : public QgsLabelFeature
{
public:
//! Construct text label feature
@@ -331,6 +331,7 @@ void QgsMapRendererCustomPainterJob::doRender()
emit layerRendered( job.layerId );
}

emit renderingLayersFinished();
QgsDebugMsgLevel( QStringLiteral( "Done rendering map layers" ), 5 );

if ( mSettings.testFlag( Qgis::MapSettingsFlag::DrawLabeling ) && !mLabelJob.context.renderingStopped() )
@@ -64,6 +64,7 @@
#include "qgsannotationlayer.h"
#include "qgsannotationmarkeritem.h"
#include "qgscolorrampimpl.h"
#include "qgstextformat.h"

class TestQgsProcessingAlgs: public QObject
{
@@ -198,6 +199,8 @@ class TestQgsProcessingAlgs: public QObject
void uploadGpsData();
void transferMainAnnotationLayer();

void extractLabels();

private:

bool imageCheck( const QString &testName, const QString &renderedImage );
@@ -7173,6 +7176,62 @@ void TestQgsProcessingAlgs::exportMeshTimeSeries()
outputFile.close();
}

void TestQgsProcessingAlgs::extractLabels()
{
QgsProject project;
QgsVectorLayer *pointsLayer = new QgsVectorLayer( mPointLayerPath,
QStringLiteral( "points" ), QStringLiteral( "ogr" ) );
QVERIFY( mPointsLayer->isValid() );
project.addMapLayer( pointsLayer );

QgsTextFormat format = QgsTextFormat::fromQFont( QgsFontUtils::getStandardTestFont() );
format.setSize( 10 );
QgsPalLayerSettings settings;
settings.fieldName = QStringLiteral( "Class" );
settings.setFormat( format );
pointsLayer->setLabeling( new QgsVectorLayerSimpleLabeling( settings ) );

std::unique_ptr< QgsProcessingAlgorithm > alg( QgsApplication::processingRegistry()->createAlgorithmById( QStringLiteral( "native:extractlabels" ) ) );
QVERIFY( alg != nullptr );

QgsReferencedRectangle extent( QgsRectangle( -120, 20, -80, 50 ), QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4326" ) ) );

QVariantMap parameters;
parameters.insert( QStringLiteral( "EXTENT" ), extent );
parameters.insert( QStringLiteral( "SCALE" ), 9000000.00 );
parameters.insert( QStringLiteral( "DPI" ), 96.00 );
parameters.insert( QStringLiteral( "OUTPUT" ), QgsProcessing::TEMPORARY_OUTPUT );

bool ok = false;
std::unique_ptr< QgsProcessingContext > context = std::make_unique< QgsProcessingContext >();
context->setProject( &project );
QgsProcessingFeedback feedback;

QVariantMap results;
results = alg->run( parameters, *context, &feedback, &ok );
QVERIFY( ok );

QgsVectorLayer *resultLayer = qobject_cast< QgsVectorLayer * >( context->getMapLayer( results.value( QStringLiteral( "OUTPUT" ) ).toString() ) );
QVERIFY( resultLayer );
QCOMPARE( resultLayer->wkbType(), QgsWkbTypes::Point );
QCOMPARE( resultLayer->featureCount(), 17 );

QgsFeature feature = resultLayer->getFeature( 1 );
QVariantMap attributes = feature.attributeMap();
QCOMPARE( attributes[QStringLiteral( "Layer" )], QStringLiteral( "points" ) );
QCOMPARE( attributes[QStringLiteral( "FeatureID" )], 1 );
QCOMPARE( attributes[QStringLiteral( "LabelText" )], QStringLiteral( "Biplane" ) );
QCOMPARE( attributes[QStringLiteral( "LabelRotation" )], 0.0 );
QCOMPARE( attributes[QStringLiteral( "Family" )], QStringLiteral( "QGIS Vera Sans" ) );
QCOMPARE( attributes[QStringLiteral( "Size" )], 9.75 );
QCOMPARE( attributes[QStringLiteral( "Italic" )], false );
QCOMPARE( attributes[QStringLiteral( "Bold" )], false );
QCOMPARE( attributes[QStringLiteral( "FontStyle" )], QStringLiteral( "Roman" ) );
QCOMPARE( attributes[QStringLiteral( "FontLetterSpacing" )], 0.0 );
QCOMPARE( attributes[QStringLiteral( "FontWordSpacing" )], 0.0 );
QCOMPARE( attributes[QStringLiteral( "MultiLineAlignment" )], QStringLiteral( "left" ) );
QCOMPARE( attributes[QStringLiteral( "MultiLineHeight" )], 1.0 );
}

bool TestQgsProcessingAlgs::imageCheck( const QString &testName, const QString &renderedImage )
{

0 comments on commit 3c001de

Please sign in to comment.