mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-18 00:03:05 -04:00
[FEATURE] Rule-based labeling
Work in progress This code has been funded by Tuscany Region (Italy) - SITA (CIG: 63526840AE) and commissioned to Gis3W s.a.s.
This commit is contained in:
parent
287590eea2
commit
1782d1a505
@ -163,6 +163,7 @@ SET(QGIS_CORE_SRCS
|
|||||||
qgsrenderchecker.cpp
|
qgsrenderchecker.cpp
|
||||||
qgsrendercontext.cpp
|
qgsrendercontext.cpp
|
||||||
qgsrectangle.cpp
|
qgsrectangle.cpp
|
||||||
|
qgsrulebasedlabeling.cpp
|
||||||
qgsrunprocess.cpp
|
qgsrunprocess.cpp
|
||||||
qgsscalecalculator.cpp
|
qgsscalecalculator.cpp
|
||||||
qgsscaleexpression.cpp
|
qgsscaleexpression.cpp
|
||||||
@ -186,6 +187,7 @@ SET(QGIS_CORE_SRCS
|
|||||||
qgsvectorlayerfeatureiterator.cpp
|
qgsvectorlayerfeatureiterator.cpp
|
||||||
qgsvectorlayerimport.cpp
|
qgsvectorlayerimport.cpp
|
||||||
qgsvectorlayerjoinbuffer.cpp
|
qgsvectorlayerjoinbuffer.cpp
|
||||||
|
qgsvectorlayerlabeling.cpp
|
||||||
qgsvectorlayerlabelprovider.cpp
|
qgsvectorlayerlabelprovider.cpp
|
||||||
qgsvectorlayerrenderer.cpp
|
qgsvectorlayerrenderer.cpp
|
||||||
qgsvectorlayerundocommand.cpp
|
qgsvectorlayerundocommand.cpp
|
||||||
|
@ -388,11 +388,6 @@ namespace pal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString LabelPosition::getLayerName() const
|
|
||||||
{
|
|
||||||
return feature->layer()->name();
|
|
||||||
}
|
|
||||||
|
|
||||||
void LabelPosition::setConflictsWithObstacle( bool conflicts )
|
void LabelPosition::setConflictsWithObstacle( bool conflicts )
|
||||||
{
|
{
|
||||||
mHasObstacleConflict = conflicts;
|
mHasObstacleConflict = conflicts;
|
||||||
|
@ -164,9 +164,6 @@ namespace pal
|
|||||||
if ( nextPart ) nextPart->setProblemIds( probFid, lpId );
|
if ( nextPart ) nextPart->setProblemIds( probFid, lpId );
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Return pointer to layer's name. used for stats */
|
|
||||||
QString getLayerName() const;
|
|
||||||
|
|
||||||
/** Returns the candidate label position's geographical cost.
|
/** Returns the candidate label position's geographical cost.
|
||||||
* @see setCost
|
* @see setCost
|
||||||
*/
|
*/
|
||||||
|
@ -45,8 +45,9 @@
|
|||||||
namespace pal
|
namespace pal
|
||||||
{
|
{
|
||||||
|
|
||||||
Layer::Layer( const QString &lyrName, Arrangement arrangement, double defaultPriority, bool active, bool toLabel, Pal *pal, bool displayAll )
|
Layer::Layer( QgsAbstractLabelProvider* provider, const QString& name, Arrangement arrangement, double defaultPriority, bool active, bool toLabel, Pal *pal, bool displayAll )
|
||||||
: mName( lyrName )
|
: mProvider( provider )
|
||||||
|
, mName( name )
|
||||||
, pal( pal )
|
, pal( pal )
|
||||||
, mObstacleType( PolygonInterior )
|
, mObstacleType( PolygonInterior )
|
||||||
, mActive( active )
|
, mActive( active )
|
||||||
|
@ -81,6 +81,9 @@ namespace pal
|
|||||||
*/
|
*/
|
||||||
int featureCount() { return mHashtable.size(); }
|
int featureCount() { return mHashtable.size(); }
|
||||||
|
|
||||||
|
/** Returns pointer to the associated provider */
|
||||||
|
QgsAbstractLabelProvider* provider() const { return mProvider; }
|
||||||
|
|
||||||
/** Returns the layer's name.
|
/** Returns the layer's name.
|
||||||
*/
|
*/
|
||||||
QString name() const { return mName; }
|
QString name() const { return mName; }
|
||||||
@ -242,7 +245,8 @@ namespace pal
|
|||||||
void chopFeaturesAtRepeatDistance();
|
void chopFeaturesAtRepeatDistance();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QString mName; /* unique */
|
QgsAbstractLabelProvider* mProvider; // not owned
|
||||||
|
QString mName;
|
||||||
|
|
||||||
/** List of feature parts */
|
/** List of feature parts */
|
||||||
QLinkedList<FeaturePart*> mFeatureParts;
|
QLinkedList<FeaturePart*> mFeatureParts;
|
||||||
@ -279,7 +283,8 @@ namespace pal
|
|||||||
/**
|
/**
|
||||||
* \brief Create a new layer
|
* \brief Create a new layer
|
||||||
*
|
*
|
||||||
* @param lyrName layer's name
|
* @param provider Associated provider
|
||||||
|
* @param name Name of the layer (for stats, debugging - does not need to be unique)
|
||||||
* @param arrangement Arrangement mode : how to place candidates
|
* @param arrangement Arrangement mode : how to place candidates
|
||||||
* @param defaultPriority layer's prioriry (0 is the best, 1 the worst)
|
* @param defaultPriority layer's prioriry (0 is the best, 1 the worst)
|
||||||
* @param active is the layer is active (currently displayed)
|
* @param active is the layer is active (currently displayed)
|
||||||
@ -288,7 +293,7 @@ namespace pal
|
|||||||
* @param displayAll if true, all features will be labelled even though overlaps occur
|
* @param displayAll if true, all features will be labelled even though overlaps occur
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
Layer( const QString& lyrName, Arrangement arrangement, double defaultPriority, bool active, bool toLabel, Pal *pal, bool displayAll = false );
|
Layer( QgsAbstractLabelProvider* provider, const QString& name, Arrangement arrangement, double defaultPriority, bool active, bool toLabel, Pal *pal, bool displayAll = false );
|
||||||
|
|
||||||
/** Add newly created feature part into r tree and to the list */
|
/** Add newly created feature part into r tree and to the list */
|
||||||
void addFeaturePart( FeaturePart* fpart, const QString &labelText = QString() );
|
void addFeaturePart( FeaturePart* fpart, const QString &labelText = QString() );
|
||||||
|
@ -90,38 +90,17 @@ namespace pal
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<Layer*> Pal::getLayers()
|
|
||||||
{
|
|
||||||
// TODO make const ! or whatever else
|
|
||||||
return mLayers.values();
|
|
||||||
}
|
|
||||||
|
|
||||||
Layer *Pal::getLayer( const QString& layerName )
|
|
||||||
{
|
|
||||||
mMutex.lock();
|
|
||||||
if ( !mLayers.contains( layerName ) )
|
|
||||||
{
|
|
||||||
mMutex.unlock();
|
|
||||||
throw new PalException::UnknownLayer();
|
|
||||||
}
|
|
||||||
|
|
||||||
Layer* result = mLayers.value( layerName );
|
|
||||||
mMutex.unlock();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Pal::removeLayer( Layer *layer )
|
void Pal::removeLayer( Layer *layer )
|
||||||
{
|
{
|
||||||
if ( !layer )
|
if ( !layer )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
mMutex.lock();
|
mMutex.lock();
|
||||||
QString key = mLayers.key( layer, QString() );
|
if ( QgsAbstractLabelProvider* key = mLayers.key( layer, 0 ) )
|
||||||
if ( !key.isEmpty() )
|
|
||||||
{
|
{
|
||||||
mLayers.remove( key );
|
mLayers.remove( key );
|
||||||
|
delete layer;
|
||||||
}
|
}
|
||||||
delete layer;
|
|
||||||
mMutex.unlock();
|
mMutex.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,21 +117,14 @@ namespace pal
|
|||||||
//finishGEOS();
|
//finishGEOS();
|
||||||
}
|
}
|
||||||
|
|
||||||
Layer* Pal::addLayer( const QString &layerName, Arrangement arrangement, double defaultPriority, bool active, bool toLabel, bool displayAll )
|
Layer* Pal::addLayer( QgsAbstractLabelProvider* provider, const QString& layerName, Arrangement arrangement, double defaultPriority, bool active, bool toLabel, bool displayAll )
|
||||||
{
|
{
|
||||||
mMutex.lock();
|
mMutex.lock();
|
||||||
|
|
||||||
//check if layer is already known
|
Q_ASSERT( !mLayers.contains( provider ) );
|
||||||
if ( mLayers.contains( layerName ) )
|
|
||||||
{
|
|
||||||
mMutex.unlock();
|
|
||||||
//There is already a layer with this name, so we just return the existing one.
|
|
||||||
//Sometimes the same layer is added twice (e.g. datetime split with otf-reprojection)
|
|
||||||
return mLayers.value( layerName );
|
|
||||||
}
|
|
||||||
|
|
||||||
Layer* layer = new Layer( layerName, arrangement, defaultPriority, active, toLabel, this, displayAll );
|
Layer* layer = new Layer( provider, layerName, arrangement, defaultPriority, active, toLabel, this, displayAll );
|
||||||
mLayers.insert( layerName, layer );
|
mLayers.insert( provider, layer );
|
||||||
mMutex.unlock();
|
mMutex.unlock();
|
||||||
|
|
||||||
return layer;
|
return layer;
|
||||||
@ -266,7 +238,7 @@ namespace pal
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Problem* Pal::extract( const QStringList& layerNames, double lambda_min, double phi_min, double lambda_max, double phi_max )
|
Problem* Pal::extract( double lambda_min, double phi_min, double lambda_max, double phi_max )
|
||||||
{
|
{
|
||||||
// to store obstacles
|
// to store obstacles
|
||||||
RTree<FeaturePart*, double, 2, double> *obstacles = new RTree<FeaturePart*, double, 2, double>();
|
RTree<FeaturePart*, double, 2, double> *obstacles = new RTree<FeaturePart*, double, 2, double>();
|
||||||
@ -308,14 +280,12 @@ namespace pal
|
|||||||
// first step : extract features from layers
|
// first step : extract features from layers
|
||||||
|
|
||||||
int previousFeatureCount = 0;
|
int previousFeatureCount = 0;
|
||||||
Layer *layer;
|
|
||||||
|
|
||||||
QStringList layersWithFeaturesInBBox;
|
QStringList layersWithFeaturesInBBox;
|
||||||
|
|
||||||
mMutex.lock();
|
mMutex.lock();
|
||||||
Q_FOREACH ( const QString& layerName, layerNames )
|
Q_FOREACH ( Layer* layer, mLayers.values() )
|
||||||
{
|
{
|
||||||
layer = mLayers.value( layerName, 0 );
|
|
||||||
if ( !layer )
|
if ( !layer )
|
||||||
{
|
{
|
||||||
// invalid layer name
|
// invalid layer name
|
||||||
@ -503,15 +473,10 @@ namespace pal
|
|||||||
return prob;
|
return prob;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::list<LabelPosition*>* Pal::labeller( double bbox[4], PalStat **stats, bool displayAll )
|
|
||||||
{
|
|
||||||
return labeller( mLayers.keys(), bbox, stats, displayAll );
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* BIG MACHINE
|
* BIG MACHINE
|
||||||
*/
|
*/
|
||||||
std::list<LabelPosition*>* Pal::labeller( const QStringList& layerNames, double bbox[4], PalStat **stats, bool displayAll )
|
std::list<LabelPosition*>* Pal::labeller( double bbox[4], PalStat **stats, bool displayAll )
|
||||||
{
|
{
|
||||||
#ifdef _DEBUG_
|
#ifdef _DEBUG_
|
||||||
std::cout << "LABELLER (selection)" << std::endl;
|
std::cout << "LABELLER (selection)" << std::endl;
|
||||||
@ -536,7 +501,7 @@ namespace pal
|
|||||||
t.start();
|
t.start();
|
||||||
|
|
||||||
// First, extract the problem
|
// First, extract the problem
|
||||||
if (( prob = extract( layerNames, bbox[0], bbox[1], bbox[2], bbox[3] ) ) == NULL )
|
if (( prob = extract( bbox[0], bbox[1], bbox[2], bbox[3] ) ) == NULL )
|
||||||
{
|
{
|
||||||
// nothing to be done => return an empty result set
|
// nothing to be done => return an empty result set
|
||||||
if ( stats )
|
if ( stats )
|
||||||
@ -611,7 +576,7 @@ namespace pal
|
|||||||
|
|
||||||
Problem* Pal::extractProblem( double bbox[4] )
|
Problem* Pal::extractProblem( double bbox[4] )
|
||||||
{
|
{
|
||||||
return extract( mLayers.keys(), bbox[0], bbox[1], bbox[2], bbox[3] );
|
return extract( bbox[0], bbox[1], bbox[2], bbox[3] );
|
||||||
}
|
}
|
||||||
|
|
||||||
std::list<LabelPosition*>* Pal::solveProblem( Problem* prob, bool displayAll )
|
std::list<LabelPosition*>* Pal::solveProblem( Problem* prob, bool displayAll )
|
||||||
|
@ -39,6 +39,8 @@
|
|||||||
|
|
||||||
// TODO ${MAJOR} ${MINOR} etc instead of 0.2
|
// TODO ${MAJOR} ${MINOR} etc instead of 0.2
|
||||||
|
|
||||||
|
class QgsAbstractLabelProvider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* \section intro_sec Introduction
|
* \section intro_sec Introduction
|
||||||
@ -127,6 +129,7 @@ namespace pal
|
|||||||
/**
|
/**
|
||||||
* \brief add a new layer
|
* \brief add a new layer
|
||||||
*
|
*
|
||||||
|
* @param provider Provider associated with the layer
|
||||||
* @param layerName layer's name
|
* @param layerName layer's name
|
||||||
* @param arrangement Howto place candidates
|
* @param arrangement Howto place candidates
|
||||||
* @param defaultPriority layer's prioriry (0 is the best, 1 the worst)
|
* @param defaultPriority layer's prioriry (0 is the best, 1 the worst)
|
||||||
@ -138,25 +141,7 @@ namespace pal
|
|||||||
*
|
*
|
||||||
* @todo add symbolUnit
|
* @todo add symbolUnit
|
||||||
*/
|
*/
|
||||||
Layer* addLayer( const QString& layerName, Arrangement arrangement, double defaultPriority, bool active, bool toLabel, bool displayAll = false );
|
Layer* addLayer( QgsAbstractLabelProvider* provider, const QString& layerName, Arrangement arrangement, double defaultPriority, bool active, bool toLabel, bool displayAll = false );
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Look for a layer
|
|
||||||
*
|
|
||||||
* @param layerName name of layer to search
|
|
||||||
*
|
|
||||||
* @throws PalException::UnkownLayer
|
|
||||||
*
|
|
||||||
* @return a pointer on layer or NULL if layer not exist
|
|
||||||
*/
|
|
||||||
Layer *getLayer( const QString &layerName );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief get all layers
|
|
||||||
*
|
|
||||||
* @return a list of all layers
|
|
||||||
*/
|
|
||||||
QList<Layer*> getLayers();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief remove a layer
|
* \brief remove a layer
|
||||||
@ -177,24 +162,6 @@ namespace pal
|
|||||||
*/
|
*/
|
||||||
std::list<LabelPosition*> *labeller( double bbox[4], PalStat **stats, bool displayAll );
|
std::list<LabelPosition*> *labeller( double bbox[4], PalStat **stats, bool displayAll );
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief the labeling machine
|
|
||||||
* Active layers are specifiend through layersName array
|
|
||||||
* @todo add obstacles and tolabel arrays
|
|
||||||
* @param layerNames names of layers to label
|
|
||||||
* @param bbox map extent
|
|
||||||
* @param stat will be filled with labelling process statistics, can be NULL
|
|
||||||
* @param displayAll if true, all feature will be labelled even though overlaps occur
|
|
||||||
*
|
|
||||||
* @todo UnknownLayer will be ignored ? should throw exception or not ???
|
|
||||||
*
|
|
||||||
* @return A list of label to display on map
|
|
||||||
*/
|
|
||||||
std::list<LabelPosition*> *labeller( const QStringList& layerNames,
|
|
||||||
double bbox[4],
|
|
||||||
PalStat **stat,
|
|
||||||
bool displayAll );
|
|
||||||
|
|
||||||
typedef bool ( *FnIsCancelled )( void* ctx );
|
typedef bool ( *FnIsCancelled )( void* ctx );
|
||||||
|
|
||||||
/** Register a function that returns whether this job has been cancelled - PAL calls it during the computation */
|
/** Register a function that returns whether this job has been cancelled - PAL calls it during the computation */
|
||||||
@ -279,7 +246,7 @@ namespace pal
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
QHash< QString, Layer* > mLayers;
|
QHash< QgsAbstractLabelProvider*, Layer* > mLayers;
|
||||||
|
|
||||||
QMutex mMutex;
|
QMutex mMutex;
|
||||||
|
|
||||||
@ -326,14 +293,12 @@ namespace pal
|
|||||||
* \brief Problem factory
|
* \brief Problem factory
|
||||||
* Extract features to label and generates candidates for them,
|
* Extract features to label and generates candidates for them,
|
||||||
* respects to a bounding box
|
* respects to a bounding box
|
||||||
* @param layersName layers name to be extracted
|
|
||||||
* @param lambda_min xMin bounding-box
|
* @param lambda_min xMin bounding-box
|
||||||
* @param phi_min yMin bounding-box
|
* @param phi_min yMin bounding-box
|
||||||
* @param lambda_max xMax bounding-box
|
* @param lambda_max xMax bounding-box
|
||||||
* @param phi_max yMax bounding-box
|
* @param phi_max yMax bounding-box
|
||||||
*/
|
*/
|
||||||
Problem* extract( const QStringList& layersName,
|
Problem* extract( double lambda_min, double phi_min,
|
||||||
double lambda_min, double phi_min,
|
|
||||||
double lambda_max, double phi_max );
|
double lambda_max, double phi_max );
|
||||||
|
|
||||||
|
|
||||||
|
@ -2674,7 +2674,7 @@ namespace pal
|
|||||||
int k;
|
int k;
|
||||||
for ( i = 0; i < nbft; i++ )
|
for ( i = 0; i < nbft; i++ )
|
||||||
{
|
{
|
||||||
lyrName = mLabelPositions.at( featStartId[i] )->getLayerName();
|
lyrName = mLabelPositions.at( featStartId[i] )->getFeaturePart()->feature()->provider()->name();
|
||||||
k = -1;
|
k = -1;
|
||||||
for ( j = 0; j < stats->nbLayers; j++ )
|
for ( j = 0; j < stats->nbLayers; j++ )
|
||||||
{
|
{
|
||||||
|
@ -48,6 +48,7 @@ QgsLabelingEngineV2::~QgsLabelingEngineV2()
|
|||||||
{
|
{
|
||||||
delete mResults;
|
delete mResults;
|
||||||
qDeleteAll( mProviders );
|
qDeleteAll( mProviders );
|
||||||
|
qDeleteAll( mSubProviders );
|
||||||
}
|
}
|
||||||
|
|
||||||
void QgsLabelingEngineV2::addProvider( QgsAbstractLabelProvider* provider )
|
void QgsLabelingEngineV2::addProvider( QgsAbstractLabelProvider* provider )
|
||||||
@ -65,6 +66,95 @@ void QgsLabelingEngineV2::removeProvider( QgsAbstractLabelProvider* provider )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QgsLabelingEngineV2::processProvider( QgsAbstractLabelProvider* provider, QgsRenderContext& context, pal::Pal& p )
|
||||||
|
{
|
||||||
|
// how to place the labels
|
||||||
|
pal::Arrangement arrangement;
|
||||||
|
switch ( provider->placement() )
|
||||||
|
{
|
||||||
|
case QgsPalLayerSettings::AroundPoint: arrangement = pal::P_POINT; break;
|
||||||
|
case QgsPalLayerSettings::OverPoint: arrangement = pal::P_POINT_OVER; break;
|
||||||
|
case QgsPalLayerSettings::Line: arrangement = pal::P_LINE; break;
|
||||||
|
case QgsPalLayerSettings::Curved: arrangement = pal::P_CURVED; break;
|
||||||
|
case QgsPalLayerSettings::Horizontal: arrangement = pal::P_HORIZ; break;
|
||||||
|
case QgsPalLayerSettings::Free: arrangement = pal::P_FREE; break;
|
||||||
|
default: Q_ASSERT( "unsupported placement" && 0 ); return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QgsAbstractLabelProvider::Flags flags = provider->flags();
|
||||||
|
|
||||||
|
// create the pal layer
|
||||||
|
pal::Layer* l = p.addLayer( provider,
|
||||||
|
provider->name(),
|
||||||
|
arrangement,
|
||||||
|
provider->priority(),
|
||||||
|
true,
|
||||||
|
flags.testFlag( QgsAbstractLabelProvider::DrawLabels ),
|
||||||
|
flags.testFlag( QgsAbstractLabelProvider::DrawAllLabels ) );
|
||||||
|
|
||||||
|
// extra flags for placement of labels for linestrings
|
||||||
|
l->setArrangementFlags(( pal::LineArrangementFlags ) provider->linePlacementFlags() );
|
||||||
|
|
||||||
|
// set label mode (label per feature is the default)
|
||||||
|
l->setLabelMode( flags.testFlag( QgsAbstractLabelProvider::LabelPerFeaturePart ) ? pal::Layer::LabelPerFeaturePart : pal::Layer::LabelPerFeature );
|
||||||
|
|
||||||
|
// set whether adjacent lines should be merged
|
||||||
|
l->setMergeConnectedLines( flags.testFlag( QgsAbstractLabelProvider::MergeConnectedLines ) );
|
||||||
|
|
||||||
|
// set obstacle type
|
||||||
|
switch ( provider->obstacleType() )
|
||||||
|
{
|
||||||
|
case QgsPalLayerSettings::PolygonInterior:
|
||||||
|
l->setObstacleType( pal::PolygonInterior );
|
||||||
|
break;
|
||||||
|
case QgsPalLayerSettings::PolygonBoundary:
|
||||||
|
l->setObstacleType( pal::PolygonBoundary );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set whether location of centroid must be inside of polygons
|
||||||
|
l->setCentroidInside( flags.testFlag( QgsAbstractLabelProvider::CentroidMustBeInside ) );
|
||||||
|
|
||||||
|
// set whether labels must fall completely within the polygon
|
||||||
|
l->setFitInPolygonOnly( flags.testFlag( QgsAbstractLabelProvider::FitInPolygonOnly ) );
|
||||||
|
|
||||||
|
// set how to show upside-down labels
|
||||||
|
pal::Layer::UpsideDownLabels upsdnlabels;
|
||||||
|
switch ( provider->upsidedownLabels() )
|
||||||
|
{
|
||||||
|
case QgsPalLayerSettings::Upright: upsdnlabels = pal::Layer::Upright; break;
|
||||||
|
case QgsPalLayerSettings::ShowDefined: upsdnlabels = pal::Layer::ShowDefined; break;
|
||||||
|
case QgsPalLayerSettings::ShowAll: upsdnlabels = pal::Layer::ShowAll; break;
|
||||||
|
default: Q_ASSERT( "unsupported upside-down label setting" && 0 ); return;
|
||||||
|
}
|
||||||
|
l->setUpsidedownLabels( upsdnlabels );
|
||||||
|
|
||||||
|
|
||||||
|
QList<QgsLabelFeature*> features = provider->labelFeatures( context );
|
||||||
|
|
||||||
|
foreach ( QgsLabelFeature* feature, features )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
l->registerFeature( feature );
|
||||||
|
}
|
||||||
|
catch ( std::exception &e )
|
||||||
|
{
|
||||||
|
Q_UNUSED( e );
|
||||||
|
QgsDebugMsgLevel( QString( "Ignoring feature %1 due PAL exception:" ).arg( feature->id() ) + QString::fromLatin1( e.what() ), 4 );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// any sub-providers?
|
||||||
|
Q_FOREACH ( QgsAbstractLabelProvider* subProvider, provider->subProviders() )
|
||||||
|
{
|
||||||
|
mSubProviders << subProvider;
|
||||||
|
processProvider( subProvider, context, p );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void QgsLabelingEngineV2::run( QgsRenderContext& context )
|
void QgsLabelingEngineV2::run( QgsRenderContext& context )
|
||||||
{
|
{
|
||||||
pal::Pal p;
|
pal::Pal p;
|
||||||
@ -92,82 +182,7 @@ void QgsLabelingEngineV2::run( QgsRenderContext& context )
|
|||||||
// for each provider: get labels and register them in PAL
|
// for each provider: get labels and register them in PAL
|
||||||
foreach ( QgsAbstractLabelProvider* provider, mProviders )
|
foreach ( QgsAbstractLabelProvider* provider, mProviders )
|
||||||
{
|
{
|
||||||
// how to place the labels
|
processProvider( provider, context, p );
|
||||||
pal::Arrangement arrangement;
|
|
||||||
switch ( provider->placement() )
|
|
||||||
{
|
|
||||||
case QgsPalLayerSettings::AroundPoint: arrangement = pal::P_POINT; break;
|
|
||||||
case QgsPalLayerSettings::OverPoint: arrangement = pal::P_POINT_OVER; break;
|
|
||||||
case QgsPalLayerSettings::Line: arrangement = pal::P_LINE; break;
|
|
||||||
case QgsPalLayerSettings::Curved: arrangement = pal::P_CURVED; break;
|
|
||||||
case QgsPalLayerSettings::Horizontal: arrangement = pal::P_HORIZ; break;
|
|
||||||
case QgsPalLayerSettings::Free: arrangement = pal::P_FREE; break;
|
|
||||||
default: Q_ASSERT( "unsupported placement" && 0 ); return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QgsAbstractLabelProvider::Flags flags = provider->flags();
|
|
||||||
|
|
||||||
// create the pal layer
|
|
||||||
pal::Layer* l = p.addLayer( provider->id(),
|
|
||||||
arrangement,
|
|
||||||
provider->priority(),
|
|
||||||
true,
|
|
||||||
flags.testFlag( QgsAbstractLabelProvider::DrawLabels ),
|
|
||||||
flags.testFlag( QgsAbstractLabelProvider::DrawAllLabels ) );
|
|
||||||
|
|
||||||
// extra flags for placement of labels for linestrings
|
|
||||||
l->setArrangementFlags(( pal::LineArrangementFlags ) provider->linePlacementFlags() );
|
|
||||||
|
|
||||||
// set label mode (label per feature is the default)
|
|
||||||
l->setLabelMode( flags.testFlag( QgsAbstractLabelProvider::LabelPerFeaturePart ) ? pal::Layer::LabelPerFeaturePart : pal::Layer::LabelPerFeature );
|
|
||||||
|
|
||||||
// set whether adjacent lines should be merged
|
|
||||||
l->setMergeConnectedLines( flags.testFlag( QgsAbstractLabelProvider::MergeConnectedLines ) );
|
|
||||||
|
|
||||||
// set obstacle type
|
|
||||||
switch ( provider->obstacleType() )
|
|
||||||
{
|
|
||||||
case QgsPalLayerSettings::PolygonInterior:
|
|
||||||
l->setObstacleType( pal::PolygonInterior );
|
|
||||||
break;
|
|
||||||
case QgsPalLayerSettings::PolygonBoundary:
|
|
||||||
l->setObstacleType( pal::PolygonBoundary );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set whether location of centroid must be inside of polygons
|
|
||||||
l->setCentroidInside( flags.testFlag( QgsAbstractLabelProvider::CentroidMustBeInside ) );
|
|
||||||
|
|
||||||
// set whether labels must fall completely within the polygon
|
|
||||||
l->setFitInPolygonOnly( flags.testFlag( QgsAbstractLabelProvider::FitInPolygonOnly ) );
|
|
||||||
|
|
||||||
// set how to show upside-down labels
|
|
||||||
pal::Layer::UpsideDownLabels upsdnlabels;
|
|
||||||
switch ( provider->upsidedownLabels() )
|
|
||||||
{
|
|
||||||
case QgsPalLayerSettings::Upright: upsdnlabels = pal::Layer::Upright; break;
|
|
||||||
case QgsPalLayerSettings::ShowDefined: upsdnlabels = pal::Layer::ShowDefined; break;
|
|
||||||
case QgsPalLayerSettings::ShowAll: upsdnlabels = pal::Layer::ShowAll; break;
|
|
||||||
default: Q_ASSERT( "unsupported upside-down label setting" && 0 ); return;
|
|
||||||
}
|
|
||||||
l->setUpsidedownLabels( upsdnlabels );
|
|
||||||
|
|
||||||
|
|
||||||
QList<QgsLabelFeature*> features = provider->labelFeatures( context );
|
|
||||||
|
|
||||||
foreach ( QgsLabelFeature* feature, features )
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
l->registerFeature( feature );
|
|
||||||
}
|
|
||||||
catch ( std::exception &e )
|
|
||||||
{
|
|
||||||
Q_UNUSED( e );
|
|
||||||
QgsDebugMsgLevel( QString( "Ignoring feature %1 due PAL exception:" ).arg( feature->id() ) + QString::fromLatin1( e.what() ), 4 );
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -269,10 +284,7 @@ void QgsLabelingEngineV2::run( QgsRenderContext& context )
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
//layer names
|
lf->provider()->drawLabel( context, *it );
|
||||||
QString layerName = ( *it )->getLayerName();
|
|
||||||
|
|
||||||
providerById( layerName )->drawLabel( context, *it );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset composition mode for further drawing operations
|
// Reset composition mode for further drawing operations
|
||||||
@ -327,16 +339,6 @@ void QgsLabelingEngineV2::writeSettingsToProject()
|
|||||||
QgsProject::instance()->writeEntry( "PAL", "/DrawOutlineLabels", mFlags.testFlag( RenderOutlineLabels ) );
|
QgsProject::instance()->writeEntry( "PAL", "/DrawOutlineLabels", mFlags.testFlag( RenderOutlineLabels ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
QgsAbstractLabelProvider* QgsLabelingEngineV2::providerById( const QString& id )
|
|
||||||
{
|
|
||||||
Q_FOREACH ( QgsAbstractLabelProvider* provider, mProviders )
|
|
||||||
{
|
|
||||||
if ( provider->id() == id )
|
|
||||||
return provider;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////
|
////
|
||||||
@ -369,6 +371,12 @@ QgsLabelFeature::~QgsLabelFeature()
|
|||||||
delete mInfo;
|
delete mInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QgsAbstractLabelProvider*QgsLabelFeature::provider() const
|
||||||
|
{
|
||||||
|
return mLayer ? mLayer->provider() : 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
QgsAbstractLabelProvider::QgsAbstractLabelProvider()
|
QgsAbstractLabelProvider::QgsAbstractLabelProvider()
|
||||||
: mEngine( 0 )
|
: mEngine( 0 )
|
||||||
, mFlags( DrawLabels )
|
, mFlags( DrawLabels )
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
|
|
||||||
#include <QFlags>
|
#include <QFlags>
|
||||||
|
|
||||||
|
class QgsAbstractLabelProvider;
|
||||||
class QgsRenderContext;
|
class QgsRenderContext;
|
||||||
class QgsGeometry;
|
class QgsGeometry;
|
||||||
|
|
||||||
@ -183,6 +184,9 @@ class CORE_EXPORT QgsLabelFeature
|
|||||||
//! Assign PAL layer to the label feature. Should be only used internally in PAL
|
//! Assign PAL layer to the label feature. Should be only used internally in PAL
|
||||||
void setLayer( pal::Layer* layer ) { mLayer = layer; }
|
void setLayer( pal::Layer* layer ) { mLayer = layer; }
|
||||||
|
|
||||||
|
//! Return provider of this instance
|
||||||
|
QgsAbstractLabelProvider* provider() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
//! Pointer to PAL layer (assigned when registered to PAL)
|
//! Pointer to PAL layer (assigned when registered to PAL)
|
||||||
pal::Layer* mLayer;
|
pal::Layer* mLayer;
|
||||||
@ -262,15 +266,18 @@ class CORE_EXPORT QgsAbstractLabelProvider
|
|||||||
};
|
};
|
||||||
Q_DECLARE_FLAGS( Flags, Flag )
|
Q_DECLARE_FLAGS( Flags, Flag )
|
||||||
|
|
||||||
//! Return unique identifier of the provider
|
|
||||||
virtual QString id() const = 0;
|
|
||||||
|
|
||||||
//! Return list of label features (they are owned by the provider and thus deleted on its destruction)
|
//! Return list of label features (they are owned by the provider and thus deleted on its destruction)
|
||||||
virtual QList<QgsLabelFeature*> labelFeatures( const QgsRenderContext& context ) = 0;
|
virtual QList<QgsLabelFeature*> labelFeatures( const QgsRenderContext& context ) = 0;
|
||||||
|
|
||||||
//! draw this label at the position determined by the labeling engine
|
//! draw this label at the position determined by the labeling engine
|
||||||
virtual void drawLabel( QgsRenderContext& context, pal::LabelPosition* label ) const = 0;
|
virtual void drawLabel( QgsRenderContext& context, pal::LabelPosition* label ) const = 0;
|
||||||
|
|
||||||
|
//! Return list of child providers - useful if the provider needs to put labels into more layers with different configuration
|
||||||
|
virtual QList<QgsAbstractLabelProvider*> subProviders() { return QList<QgsAbstractLabelProvider*>(); }
|
||||||
|
|
||||||
|
//! Name of the layer (for statistics, debugging etc.) - does not need to be unique
|
||||||
|
QString name() const { return mName; }
|
||||||
|
|
||||||
//! Flags associated with the provider
|
//! Flags associated with the provider
|
||||||
Flags flags() const { return mFlags; }
|
Flags flags() const { return mFlags; }
|
||||||
|
|
||||||
@ -289,11 +296,12 @@ class CORE_EXPORT QgsAbstractLabelProvider
|
|||||||
//! How to handle labels that would be upside down
|
//! How to handle labels that would be upside down
|
||||||
QgsPalLayerSettings::UpsideDownLabels upsidedownLabels() const { return mUpsidedownLabels; }
|
QgsPalLayerSettings::UpsideDownLabels upsidedownLabels() const { return mUpsidedownLabels; }
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
//! Associated labeling engine
|
//! Associated labeling engine
|
||||||
const QgsLabelingEngineV2* mEngine;
|
const QgsLabelingEngineV2* mEngine;
|
||||||
|
|
||||||
|
//! Name of the layer
|
||||||
|
QString mName;
|
||||||
//! Flags altering drawing and registration of features
|
//! Flags altering drawing and registration of features
|
||||||
Flags mFlags;
|
Flags mFlags;
|
||||||
//! Placement strategy
|
//! Placement strategy
|
||||||
@ -366,9 +374,6 @@ class CORE_EXPORT QgsLabelingEngineV2
|
|||||||
//! Remove provider if the provider's initialization failed. Provider instance is deleted.
|
//! Remove provider if the provider's initialization failed. Provider instance is deleted.
|
||||||
void removeProvider( QgsAbstractLabelProvider* provider );
|
void removeProvider( QgsAbstractLabelProvider* provider );
|
||||||
|
|
||||||
//! Lookup provider by its ID
|
|
||||||
QgsAbstractLabelProvider* providerById( const QString& id );
|
|
||||||
|
|
||||||
//! compute the labeling with given map settings and providers
|
//! compute the labeling with given map settings and providers
|
||||||
void run( QgsRenderContext& context );
|
void run( QgsRenderContext& context );
|
||||||
|
|
||||||
@ -402,11 +407,15 @@ class CORE_EXPORT QgsLabelingEngineV2
|
|||||||
//! Write configuration of the labeling engine to the current project file
|
//! Write configuration of the labeling engine to the current project file
|
||||||
void writeSettingsToProject();
|
void writeSettingsToProject();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void processProvider( QgsAbstractLabelProvider* provider, QgsRenderContext& context, pal::Pal& p );
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
//! Associated map settings instance
|
//! Associated map settings instance
|
||||||
QgsMapSettings mMapSettings;
|
QgsMapSettings mMapSettings;
|
||||||
//! List of providers (the are owned by the labeling engine)
|
//! List of providers (the are owned by the labeling engine)
|
||||||
QList<QgsAbstractLabelProvider*> mProviders;
|
QList<QgsAbstractLabelProvider*> mProviders;
|
||||||
|
QList<QgsAbstractLabelProvider*> mSubProviders;
|
||||||
//! Flags
|
//! Flags
|
||||||
Flags mFlags;
|
Flags mFlags;
|
||||||
//! search method to use for removal collisions between labels
|
//! search method to use for removal collisions between labels
|
||||||
|
@ -3207,14 +3207,20 @@ void QgsPalLabeling::clearActiveLayer( const QString &layerID )
|
|||||||
Q_UNUSED( layerID );
|
Q_UNUSED( layerID );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "qgsvectorlayerlabeling.h"
|
||||||
|
|
||||||
int QgsPalLabeling::prepareLayer( QgsVectorLayer* layer, QStringList& attrNames, QgsRenderContext& ctx )
|
int QgsPalLabeling::prepareLayer( QgsVectorLayer* layer, QStringList& attrNames, QgsRenderContext& ctx )
|
||||||
{
|
{
|
||||||
if ( !willUseLayer( layer ) || !layer->labelsEnabled() )
|
if ( !willUseLayer( layer ) )
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
QgsVectorLayerLabelProvider* lp = new QgsVectorLayerLabelProvider( layer, false );
|
QgsVectorLayerLabelProvider* lp = layer->labeling().provider( layer );
|
||||||
|
if ( !lp )
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
//QgsVectorLayerLabelProvider* lp = new QgsVectorLayerLabelProvider( layer, false );
|
||||||
// need to be added before calling prepare() - uses map settings from engine
|
// need to be added before calling prepare() - uses map settings from engine
|
||||||
mEngine->addProvider( lp );
|
mEngine->addProvider( lp );
|
||||||
mLabelProviders[layer->id()] = lp; // fast lookup table by layer ID
|
mLabelProviders[layer->id()] = lp; // fast lookup table by layer ID
|
||||||
|
183
src/core/qgsrulebasedlabeling.cpp
Normal file
183
src/core/qgsrulebasedlabeling.cpp
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
#include "qgsrulebasedlabeling.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
QgsRuleBasedLabelProvider::QgsRuleBasedLabelProvider( const QgsRuleBasedLabeling& rules, QgsVectorLayer* layer, bool withFeatureLoop )
|
||||||
|
: QgsVectorLayerLabelProvider( layer, withFeatureLoop )
|
||||||
|
, mRules( rules )
|
||||||
|
{
|
||||||
|
mRules.rootRule()->createSubProviders( layer, mSubProviders );
|
||||||
|
}
|
||||||
|
|
||||||
|
QgsRuleBasedLabelProvider::~QgsRuleBasedLabelProvider()
|
||||||
|
{
|
||||||
|
// sub-providers owned by labeling engine
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool QgsRuleBasedLabelProvider::prepare( const QgsRenderContext& context, QStringList& attributeNames )
|
||||||
|
{
|
||||||
|
Q_FOREACH ( QgsVectorLayerLabelProvider* provider, mSubProviders.values() )
|
||||||
|
provider->setEngine( mEngine );
|
||||||
|
|
||||||
|
// populate sub-providers
|
||||||
|
mRules.rootRule()->prepare( context, attributeNames, mSubProviders );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QgsRuleBasedLabelProvider::registerFeature( QgsFeature& feature, const QgsRenderContext& context )
|
||||||
|
{
|
||||||
|
// will register the feature to relevant sub-providers
|
||||||
|
mRules.rootRule()->registerFeature( feature, context, mSubProviders );
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QgsAbstractLabelProvider*> QgsRuleBasedLabelProvider::subProviders()
|
||||||
|
{
|
||||||
|
QList<QgsAbstractLabelProvider*> lst;
|
||||||
|
Q_FOREACH ( QgsVectorLayerLabelProvider* subprovider, mSubProviders.values() )
|
||||||
|
lst << subprovider;
|
||||||
|
return lst;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////
|
||||||
|
|
||||||
|
QgsRuleBasedLabeling::Rule::Rule( QgsPalLayerSettings* settings, int scaleMinDenom, int scaleMaxDenom, const QString& filterExp, const QString& label, const QString& description, bool elseRule )
|
||||||
|
: mParent( 0 ), mSettings( settings )
|
||||||
|
, mScaleMinDenom( scaleMinDenom ), mScaleMaxDenom( scaleMaxDenom )
|
||||||
|
, mFilterExp( filterExp ), mLabel( label ), mDescription( description )
|
||||||
|
, mElseRule( elseRule )
|
||||||
|
//, mIsActive( true )
|
||||||
|
, mFilter( 0 )
|
||||||
|
{
|
||||||
|
initFilter();
|
||||||
|
}
|
||||||
|
|
||||||
|
QgsRuleBasedLabeling::Rule::~Rule()
|
||||||
|
{
|
||||||
|
delete mSettings;
|
||||||
|
delete mFilter;
|
||||||
|
qDeleteAll( mChildren );
|
||||||
|
// do NOT delete parent
|
||||||
|
}
|
||||||
|
|
||||||
|
void QgsRuleBasedLabeling::Rule::initFilter()
|
||||||
|
{
|
||||||
|
if ( mElseRule || mFilterExp.compare( "ELSE", Qt::CaseInsensitive ) == 0 )
|
||||||
|
{
|
||||||
|
mElseRule = true;
|
||||||
|
mFilter = 0;
|
||||||
|
}
|
||||||
|
else if ( !mFilterExp.isEmpty() )
|
||||||
|
{
|
||||||
|
delete mFilter;
|
||||||
|
mFilter = new QgsExpression( mFilterExp );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mFilter = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void QgsRuleBasedLabeling::Rule::appendChild( QgsRuleBasedLabeling::Rule* rule )
|
||||||
|
{
|
||||||
|
mChildren.append( rule );
|
||||||
|
rule->mParent = this;
|
||||||
|
// TODO updateElseRules();
|
||||||
|
}
|
||||||
|
|
||||||
|
QgsRuleBasedLabeling::Rule*QgsRuleBasedLabeling::Rule::clone() const
|
||||||
|
{
|
||||||
|
QgsPalLayerSettings* s = mSettings ? new QgsPalLayerSettings( *mSettings ) : 0;
|
||||||
|
Rule* newrule = new Rule( s, mScaleMinDenom, mScaleMaxDenom, mFilterExp, mLabel, mDescription );
|
||||||
|
// TODO newrule->setCheckState( mIsActive );
|
||||||
|
// clone children
|
||||||
|
Q_FOREACH ( Rule* rule, mChildren )
|
||||||
|
newrule->appendChild( rule->clone() );
|
||||||
|
return newrule;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QgsRuleBasedLabeling::Rule::createSubProviders( QgsVectorLayer* layer, QgsRuleBasedLabeling::RuleToProviderMap& subProviders )
|
||||||
|
{
|
||||||
|
if ( mSettings )
|
||||||
|
{
|
||||||
|
// add provider!
|
||||||
|
QgsVectorLayerLabelProvider* p = new QgsVectorLayerLabelProvider( layer, false, mSettings );
|
||||||
|
subProviders[this] = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
// call recursively
|
||||||
|
Q_FOREACH ( Rule* rule, mChildren )
|
||||||
|
{
|
||||||
|
rule->createSubProviders( layer, subProviders );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QgsRuleBasedLabeling::Rule::prepare( const QgsRenderContext& context, QStringList& attributeNames, QgsRuleBasedLabeling::RuleToProviderMap& subProviders )
|
||||||
|
{
|
||||||
|
if ( mSettings )
|
||||||
|
{
|
||||||
|
QgsVectorLayerLabelProvider* p = subProviders[this];
|
||||||
|
if ( !p->prepare( context, attributeNames ) )
|
||||||
|
{
|
||||||
|
subProviders.remove( this );
|
||||||
|
delete p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( mFilter )
|
||||||
|
mFilter->prepare( &context.expressionContext() );
|
||||||
|
|
||||||
|
// call recursively
|
||||||
|
Q_FOREACH ( Rule* rule, mChildren )
|
||||||
|
{
|
||||||
|
rule->prepare( context, attributeNames, subProviders );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QgsRuleBasedLabeling::Rule::registerFeature( QgsFeature& feature, const QgsRenderContext& context, QgsRuleBasedLabeling::RuleToProviderMap& subProviders )
|
||||||
|
{
|
||||||
|
bool isOK = isFilterOK( feature, const_cast<QgsRenderContext&>( context ) ); // TODO: remove const_cast
|
||||||
|
|
||||||
|
if ( !isOK )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// do we have active subprovider for the rule?
|
||||||
|
if ( subProviders.contains( this ) )
|
||||||
|
subProviders[this]->registerFeature( feature, context );
|
||||||
|
|
||||||
|
// call recursively
|
||||||
|
Q_FOREACH ( Rule* rule, mChildren )
|
||||||
|
{
|
||||||
|
rule->registerFeature( feature, context, subProviders );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QgsRuleBasedLabeling::Rule::isFilterOK( QgsFeature& f, QgsRenderContext& context ) const
|
||||||
|
{
|
||||||
|
if ( ! mFilter || mElseRule )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
context.expressionContext().setFeature( f );
|
||||||
|
QVariant res = mFilter->evaluate( &context.expressionContext() );
|
||||||
|
return res.toInt() != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////
|
||||||
|
|
||||||
|
QgsRuleBasedLabeling::QgsRuleBasedLabeling( QgsRuleBasedLabeling::Rule* root )
|
||||||
|
: mRootRule( root )
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QgsRuleBasedLabeling::QgsRuleBasedLabeling( const QgsRuleBasedLabeling& other )
|
||||||
|
{
|
||||||
|
mRootRule = other.mRootRule->clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
QgsRuleBasedLabeling::~QgsRuleBasedLabeling()
|
||||||
|
{
|
||||||
|
delete mRootRule;
|
||||||
|
}
|
189
src/core/qgsrulebasedlabeling.h
Normal file
189
src/core/qgsrulebasedlabeling.h
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
#ifndef QGSRULEBASEDLABELING_H
|
||||||
|
#define QGSRULEBASEDLABELING_H
|
||||||
|
|
||||||
|
#include <QStringList>
|
||||||
|
|
||||||
|
class QgsExpression;
|
||||||
|
class QgsFeature;
|
||||||
|
class QgsPalLayerSettings;
|
||||||
|
class QgsRenderContext;
|
||||||
|
class QgsVectorLayer;
|
||||||
|
class QgsVectorLayerLabelProvider;
|
||||||
|
|
||||||
|
|
||||||
|
class CORE_EXPORT QgsRuleBasedLabeling
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
class Rule;
|
||||||
|
typedef QList<Rule*> RuleList;
|
||||||
|
typedef QMap<Rule*, QgsVectorLayerLabelProvider*> RuleToProviderMap;
|
||||||
|
|
||||||
|
class Rule
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//! takes ownership of settings
|
||||||
|
Rule( QgsPalLayerSettings* settings, int scaleMinDenom = 0, int scaleMaxDenom = 0, const QString& filterExp = QString(), const QString& label = QString(), const QString& description = QString(), bool elseRule = false );
|
||||||
|
~Rule();
|
||||||
|
|
||||||
|
QgsPalLayerSettings* settings() const { return mSettings; }
|
||||||
|
QString label() const { return mLabel; }
|
||||||
|
bool dependsOnScale() const { return mScaleMinDenom != 0 || mScaleMaxDenom != 0; }
|
||||||
|
int scaleMinDenom() const { return mScaleMinDenom; }
|
||||||
|
int scaleMaxDenom() const { return mScaleMaxDenom; }
|
||||||
|
/**
|
||||||
|
* A filter that will check if this rule applies
|
||||||
|
* @return An expression
|
||||||
|
*/
|
||||||
|
QString filterExpression() const { return mFilterExp; }
|
||||||
|
/**
|
||||||
|
* A human readable description for this rule
|
||||||
|
*
|
||||||
|
* @return Description
|
||||||
|
*/
|
||||||
|
QString description() const { return mDescription; }
|
||||||
|
/**
|
||||||
|
* Check if this rule is an ELSE rule
|
||||||
|
*
|
||||||
|
* @return True if this rule is an else rule
|
||||||
|
*/
|
||||||
|
bool isElse() { return mElseRule; }
|
||||||
|
|
||||||
|
void setLabel( QString label ) { mLabel = label; }
|
||||||
|
/**
|
||||||
|
* Set the minimum denominator for which this rule shall apply.
|
||||||
|
* E.g. 1000 if it shall be evaluated between 1:1000 and 1:100'000
|
||||||
|
* Set to 0 to disable the minimum check
|
||||||
|
* @param scaleMinDenom The minimum scale denominator for this rule
|
||||||
|
*/
|
||||||
|
void setScaleMinDenom( int scaleMinDenom ) { mScaleMinDenom = scaleMinDenom; }
|
||||||
|
/**
|
||||||
|
* Set the maximum denominator for which this rule shall apply.
|
||||||
|
* E.g. 100'000 if it shall be evaluated between 1:1000 and 1:100'000
|
||||||
|
* Set to 0 to disable the maximum check
|
||||||
|
* @param scaleMaxDenom maximum scale denominator for this rule
|
||||||
|
*/
|
||||||
|
void setScaleMaxDenom( int scaleMaxDenom ) { mScaleMaxDenom = scaleMaxDenom; }
|
||||||
|
/**
|
||||||
|
* Set the expression used to check if a given feature shall be rendered with this rule
|
||||||
|
*
|
||||||
|
* @param filterExp An expression
|
||||||
|
*/
|
||||||
|
void setFilterExpression( QString filterExp ) { mFilterExp = filterExp; initFilter(); }
|
||||||
|
/**
|
||||||
|
* Set a human readable description for this rule
|
||||||
|
*
|
||||||
|
* @param description Description
|
||||||
|
*/
|
||||||
|
void setDescription( QString description ) { mDescription = description; }
|
||||||
|
/**
|
||||||
|
* Sets if this rule is an ELSE rule
|
||||||
|
*
|
||||||
|
* @param iselse If true, this rule is an ELSE rule
|
||||||
|
*/
|
||||||
|
void setIsElse( bool iselse ) { mElseRule = iselse; }
|
||||||
|
|
||||||
|
|
||||||
|
// parent / child operations
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return all children rules of this rule
|
||||||
|
*
|
||||||
|
* @return A list of rules
|
||||||
|
*/
|
||||||
|
RuleList& children() { return mChildren; }
|
||||||
|
/**
|
||||||
|
* The parent rule
|
||||||
|
*
|
||||||
|
* @return Parent rule
|
||||||
|
*/
|
||||||
|
Rule* parent() { return mParent; }
|
||||||
|
|
||||||
|
//! add child rule, take ownership, sets this as parent
|
||||||
|
void appendChild( Rule* rule );
|
||||||
|
|
||||||
|
//! clone this rule, return new instance
|
||||||
|
Rule* clone() const;
|
||||||
|
|
||||||
|
// TODO: load / save
|
||||||
|
|
||||||
|
// evaluation
|
||||||
|
|
||||||
|
//! add providers
|
||||||
|
void createSubProviders( QgsVectorLayer* layer, RuleToProviderMap& subProviders );
|
||||||
|
|
||||||
|
//! call prepare() on sub-providers and populate attributeNames
|
||||||
|
void prepare( const QgsRenderContext& context, QStringList& attributeNames, RuleToProviderMap& subProviders );
|
||||||
|
|
||||||
|
//! register individual features
|
||||||
|
void registerFeature( QgsFeature& feature, const QgsRenderContext& context, RuleToProviderMap& subProviders );
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* Check if a given feature shall be labelled by this rule
|
||||||
|
*
|
||||||
|
* @param f The feature to test
|
||||||
|
* @param context The context in which the rendering happens
|
||||||
|
* @return True if the feature shall be rendered
|
||||||
|
*/
|
||||||
|
bool isFilterOK( QgsFeature& f, QgsRenderContext& context ) const;
|
||||||
|
|
||||||
|
void initFilter();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Rule* mParent; // parent rule (NULL only for root rule)
|
||||||
|
QgsPalLayerSettings* mSettings;
|
||||||
|
int mScaleMinDenom, mScaleMaxDenom;
|
||||||
|
QString mFilterExp, mLabel, mDescription;
|
||||||
|
bool mElseRule;
|
||||||
|
RuleList mChildren;
|
||||||
|
|
||||||
|
// temporary
|
||||||
|
QgsExpression* mFilter;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//! Constructs the labeling from given tree of rules (takes ownership)
|
||||||
|
explicit QgsRuleBasedLabeling( QgsRuleBasedLabeling::Rule* root );
|
||||||
|
//! Copy constructor
|
||||||
|
QgsRuleBasedLabeling( const QgsRuleBasedLabeling& other );
|
||||||
|
~QgsRuleBasedLabeling();
|
||||||
|
|
||||||
|
Rule* rootRule() { return mRootRule; }
|
||||||
|
|
||||||
|
// TODO: static create() from DOM
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Rule* mRootRule;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#include "qgsvectorlayerlabelprovider.h"
|
||||||
|
|
||||||
|
|
||||||
|
class CORE_EXPORT QgsRuleBasedLabelProvider : public QgsVectorLayerLabelProvider
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QgsRuleBasedLabelProvider( const QgsRuleBasedLabeling& rules, QgsVectorLayer* layer, bool withFeatureLoop = true );
|
||||||
|
~QgsRuleBasedLabelProvider();
|
||||||
|
|
||||||
|
// reimplemented
|
||||||
|
|
||||||
|
virtual bool prepare( const QgsRenderContext& context, QStringList& attributeNames ) override;
|
||||||
|
|
||||||
|
virtual void registerFeature( QgsFeature& feature, const QgsRenderContext& context ) override;
|
||||||
|
|
||||||
|
// new methods
|
||||||
|
|
||||||
|
virtual QList<QgsAbstractLabelProvider*> subProviders() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
//! owned copy
|
||||||
|
QgsRuleBasedLabeling mRules;
|
||||||
|
//! label providers are owned by labeling engine
|
||||||
|
QgsRuleBasedLabeling::RuleToProviderMap mSubProviders;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // QGSRULEBASEDLABELING_H
|
@ -69,6 +69,7 @@
|
|||||||
#include "qgsvectorlayereditutils.h"
|
#include "qgsvectorlayereditutils.h"
|
||||||
#include "qgsvectorlayerfeatureiterator.h"
|
#include "qgsvectorlayerfeatureiterator.h"
|
||||||
#include "qgsvectorlayerjoinbuffer.h"
|
#include "qgsvectorlayerjoinbuffer.h"
|
||||||
|
#include "qgsvectorlayerlabeling.h"
|
||||||
#include "qgsvectorlayerrenderer.h"
|
#include "qgsvectorlayerrenderer.h"
|
||||||
#include "qgsvectorlayerundocommand.h"
|
#include "qgsvectorlayerundocommand.h"
|
||||||
#include "qgspointv2.h"
|
#include "qgspointv2.h"
|
||||||
@ -131,6 +132,7 @@ QgsVectorLayer::QgsVectorLayer( QString vectorLayerPath,
|
|||||||
, mRendererV2( NULL )
|
, mRendererV2( NULL )
|
||||||
, mLabel( 0 )
|
, mLabel( 0 )
|
||||||
, mLabelOn( false )
|
, mLabelOn( false )
|
||||||
|
, mLabeling( new QgsVectorLayerLabeling )
|
||||||
, mLabelFontNotFoundNotified( false )
|
, mLabelFontNotFoundNotified( false )
|
||||||
, mFeatureBlendMode( QPainter::CompositionMode_SourceOver ) // Default to normal feature blending
|
, mFeatureBlendMode( QPainter::CompositionMode_SourceOver ) // Default to normal feature blending
|
||||||
, mLayerTransparency( 0 )
|
, mLayerTransparency( 0 )
|
||||||
@ -184,7 +186,8 @@ QgsVectorLayer::~QgsVectorLayer()
|
|||||||
delete mJoinBuffer;
|
delete mJoinBuffer;
|
||||||
delete mExpressionFieldBuffer;
|
delete mExpressionFieldBuffer;
|
||||||
delete mCache;
|
delete mCache;
|
||||||
delete mLabel;
|
delete mLabel; // old deprecated implementation
|
||||||
|
delete mLabeling;
|
||||||
delete mDiagramLayerSettings;
|
delete mDiagramLayerSettings;
|
||||||
delete mDiagramRenderer;
|
delete mDiagramRenderer;
|
||||||
|
|
||||||
|
@ -63,6 +63,7 @@ class QgsSymbolV2;
|
|||||||
class QgsVectorDataProvider;
|
class QgsVectorDataProvider;
|
||||||
class QgsVectorLayerEditBuffer;
|
class QgsVectorLayerEditBuffer;
|
||||||
class QgsVectorLayerJoinBuffer;
|
class QgsVectorLayerJoinBuffer;
|
||||||
|
class QgsVectorLayerLabeling;
|
||||||
class QgsPointV2;
|
class QgsPointV2;
|
||||||
|
|
||||||
typedef QList<int> QgsAttributeList;
|
typedef QList<int> QgsAttributeList;
|
||||||
@ -1261,6 +1262,11 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
|
|||||||
*/
|
*/
|
||||||
Q_DECL_DEPRECATED bool hasLabelsEnabled() const;
|
Q_DECL_DEPRECATED bool hasLabelsEnabled() const;
|
||||||
|
|
||||||
|
/** Access to labeling configuration
|
||||||
|
* @note added in 2.12
|
||||||
|
*/
|
||||||
|
QgsVectorLayerLabeling& labeling() { return *mLabeling; }
|
||||||
|
|
||||||
/** Returns true if the provider is in editing mode */
|
/** Returns true if the provider is in editing mode */
|
||||||
virtual bool isEditable() const override;
|
virtual bool isEditable() const override;
|
||||||
|
|
||||||
@ -2079,12 +2085,15 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
|
|||||||
/** Simplification object which holds the information about how to simplify the features for fast rendering */
|
/** Simplification object which holds the information about how to simplify the features for fast rendering */
|
||||||
QgsVectorSimplifyMethod mSimplifyMethod;
|
QgsVectorSimplifyMethod mSimplifyMethod;
|
||||||
|
|
||||||
/** Label */
|
/** Label [old deprecated implementation] */
|
||||||
QgsLabel *mLabel;
|
QgsLabel *mLabel;
|
||||||
|
|
||||||
/** Display labels */
|
/** Display labels [old deprecated implementation] */
|
||||||
bool mLabelOn;
|
bool mLabelOn;
|
||||||
|
|
||||||
|
/** Labeling configuration */
|
||||||
|
QgsVectorLayerLabeling* mLabeling;
|
||||||
|
|
||||||
/** Whether 'labeling font not found' has be shown for this layer (only show once in QgsMessageBar, on first rendering) */
|
/** Whether 'labeling font not found' has be shown for this layer (only show once in QgsMessageBar, on first rendering) */
|
||||||
bool mLabelFontNotFoundNotified;
|
bool mLabelFontNotFoundNotified;
|
||||||
|
|
||||||
|
@ -59,6 +59,7 @@ QgsVectorLayerDiagramProvider::QgsVectorLayerDiagramProvider( QgsVectorLayer* la
|
|||||||
|
|
||||||
void QgsVectorLayerDiagramProvider::init()
|
void QgsVectorLayerDiagramProvider::init()
|
||||||
{
|
{
|
||||||
|
mName = mLayerId;
|
||||||
mPriority = 1 - mSettings.priority / 10.0; // convert 0..10 --> 1..0
|
mPriority = 1 - mSettings.priority / 10.0; // convert 0..10 --> 1..0
|
||||||
mPlacement = QgsPalLayerSettings::Placement( mSettings.placement );
|
mPlacement = QgsPalLayerSettings::Placement( mSettings.placement );
|
||||||
mLinePlacementFlags = mSettings.placementFlags;
|
mLinePlacementFlags = mSettings.placementFlags;
|
||||||
@ -77,11 +78,6 @@ QgsVectorLayerDiagramProvider::~QgsVectorLayerDiagramProvider()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
QString QgsVectorLayerDiagramProvider::id() const
|
|
||||||
{
|
|
||||||
return mLayerId + "d";
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<QgsLabelFeature*> QgsVectorLayerDiagramProvider::labelFeatures( const QgsRenderContext& context )
|
QList<QgsLabelFeature*> QgsVectorLayerDiagramProvider::labelFeatures( const QgsRenderContext& context )
|
||||||
{
|
{
|
||||||
if ( !mSource )
|
if ( !mSource )
|
||||||
@ -154,10 +150,7 @@ void QgsVectorLayerDiagramProvider::drawLabel( QgsRenderContext& context, pal::L
|
|||||||
mSettings.renderer->renderDiagram( feature, context, centerPt.toQPointF() );
|
mSettings.renderer->renderDiagram( feature, context, centerPt.toQPointF() );
|
||||||
|
|
||||||
//insert into label search tree to manipulate position interactively
|
//insert into label search tree to manipulate position interactively
|
||||||
//for diagrams, remove the additional 'd' at the end of the layer id
|
mEngine->results()->mLabelSearchTree->insertLabel( label, label->getFeaturePart()->featureId(), mLayerId, QString(), QFont(), true, false );
|
||||||
QString layerId = id();
|
|
||||||
layerId.chop( 1 );
|
|
||||||
mEngine->results()->mLabelSearchTree->insertLabel( label, label->getFeaturePart()->featureId(), layerId, QString(), QFont(), true, false );
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,8 +70,6 @@ class CORE_EXPORT QgsVectorLayerDiagramProvider : public QgsAbstractLabelProvide
|
|||||||
//! Clean up
|
//! Clean up
|
||||||
~QgsVectorLayerDiagramProvider();
|
~QgsVectorLayerDiagramProvider();
|
||||||
|
|
||||||
virtual QString id() const override;
|
|
||||||
|
|
||||||
virtual QList<QgsLabelFeature*> labelFeatures( const QgsRenderContext& context ) override;
|
virtual QList<QgsLabelFeature*> labelFeatures( const QgsRenderContext& context ) override;
|
||||||
|
|
||||||
virtual void drawLabel( QgsRenderContext& context, pal::LabelPosition* label ) const override;
|
virtual void drawLabel( QgsRenderContext& context, pal::LabelPosition* label ) const override;
|
||||||
|
75
src/core/qgsvectorlayerlabeling.cpp
Normal file
75
src/core/qgsvectorlayerlabeling.cpp
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
#include "qgsvectorlayerlabeling.h"
|
||||||
|
|
||||||
|
#include "qgspallabeling.h"
|
||||||
|
#include "qgsrulebasedlabeling.h"
|
||||||
|
#include "qgsvectorlayer.h"
|
||||||
|
|
||||||
|
QgsVectorLayerLabeling::QgsVectorLayerLabeling()
|
||||||
|
: mMode( SimpleLabels )
|
||||||
|
//, mSimpleLabeling( 0 )
|
||||||
|
, mRuleBasedLabeling( 0 )
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QgsVectorLayerLabeling::~QgsVectorLayerLabeling()
|
||||||
|
{
|
||||||
|
//delete mSimpleLabeling;
|
||||||
|
delete mRuleBasedLabeling;
|
||||||
|
}
|
||||||
|
|
||||||
|
//QgsPalLayerSettings QgsVectorLayerLabeling::simpleLabeling()
|
||||||
|
//{
|
||||||
|
//}
|
||||||
|
|
||||||
|
//void QgsVectorLayerLabeling::setSimpleLabeling(QgsPalLayerSettings* settings)
|
||||||
|
//{
|
||||||
|
// delete mSimpleLabeling;
|
||||||
|
// mSimpleLabeling = settings;
|
||||||
|
//}
|
||||||
|
|
||||||
|
void QgsVectorLayerLabeling::setRuleBasedLabeling( QgsRuleBasedLabeling* settings )
|
||||||
|
{
|
||||||
|
delete mRuleBasedLabeling;
|
||||||
|
mRuleBasedLabeling = settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
QgsVectorLayerLabelProvider* QgsVectorLayerLabeling::provider( QgsVectorLayer* layer )
|
||||||
|
{
|
||||||
|
if ( mMode == SimpleLabels )
|
||||||
|
{
|
||||||
|
if ( layer->customProperty( "labeling" ).toString() == QString( "pal" ) && layer->labelsEnabled() )
|
||||||
|
return new QgsVectorLayerLabelProvider( layer, false );
|
||||||
|
}
|
||||||
|
else // rule-based
|
||||||
|
{
|
||||||
|
if ( mRuleBasedLabeling )
|
||||||
|
return new QgsRuleBasedLabelProvider( *mRuleBasedLabeling, layer, false );
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
QgsAbstractLabelProvider* QgsVectorLayerLabeling::addProviderToEngine( QgsVectorLayer* layer, QgsLabelingEngineV2* engine, QgsRenderContext& context )
|
||||||
|
{
|
||||||
|
if ( mMode == SimpleLabels )
|
||||||
|
{
|
||||||
|
QgsVectorLayerLabelProvider* provider = 0;
|
||||||
|
if ( layer->labelsEnabled() )
|
||||||
|
{
|
||||||
|
provider = new QgsVectorLayerLabelProvider( layer, false );
|
||||||
|
engine->addProvider( provider );
|
||||||
|
if ( !provider->prepare( context, attributeNames ) )
|
||||||
|
{
|
||||||
|
engine->removeProvider( provider );
|
||||||
|
provider = 0; // deleted by engine
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // rule-based
|
||||||
|
{
|
||||||
|
return 0; // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
49
src/core/qgsvectorlayerlabeling.h
Normal file
49
src/core/qgsvectorlayerlabeling.h
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#ifndef QGSVECTORLAYERLABELING_H
|
||||||
|
#define QGSVECTORLAYERLABELING_H
|
||||||
|
|
||||||
|
|
||||||
|
class QgsPalLayerSettings;
|
||||||
|
class QgsRuleBasedLabeling;
|
||||||
|
class QgsVectorLayer;
|
||||||
|
class QgsVectorLayerLabelProvider;
|
||||||
|
|
||||||
|
class CORE_EXPORT QgsVectorLayerLabeling
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum Mode
|
||||||
|
{
|
||||||
|
//NoLabels, //!< the layer does not participate in labeling
|
||||||
|
//Obstacles, //!< no labels are shown, but layer's features act as obstacles for other labels
|
||||||
|
SimpleLabels, //!< the layer is labelled with one style
|
||||||
|
RuleBasedLabels //!< the layer is labelled with multiple styles defined with rules
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Defaults to no labels
|
||||||
|
QgsVectorLayerLabeling();
|
||||||
|
~QgsVectorLayerLabeling();
|
||||||
|
|
||||||
|
Mode mode() const { return mMode; }
|
||||||
|
void setMode( Mode m ) { mMode = m; }
|
||||||
|
|
||||||
|
//QgsPalLayerSettings simpleLabeling();
|
||||||
|
|
||||||
|
//QgsPalLayerSettings* simpleLabeling() const { return mSimpleLabeling; }
|
||||||
|
//! Assign simple labeling configuration (takes ownership)
|
||||||
|
//void setSimpleLabeling( QgsPalLayerSettings* settings );
|
||||||
|
|
||||||
|
QgsRuleBasedLabeling* ruleBasedLabeling() const { return mRuleBasedLabeling; }
|
||||||
|
//! Assign rule-based labeling configuration (takes ownership)
|
||||||
|
void setRuleBasedLabeling( QgsRuleBasedLabeling* settings );
|
||||||
|
|
||||||
|
//! Factory for label provider implementation - according to the current mode
|
||||||
|
QgsVectorLayerLabelProvider* provider( QgsVectorLayer* layer );
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Mode mMode;
|
||||||
|
//QgsPalLayerSettings* mSimpleLabeling;
|
||||||
|
QgsRuleBasedLabeling* mRuleBasedLabeling;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // QGSVECTORLAYERLABELING_H
|
@ -43,14 +43,11 @@ static void _fixQPictureDPI( QPainter* p )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
typedef QgsPalLayerSettings QgsVectorLayerLabelSettings;
|
|
||||||
|
|
||||||
QgsVectorLayerLabelProvider::QgsVectorLayerLabelProvider( QgsVectorLayer* layer, bool withFeatureLoop )
|
QgsVectorLayerLabelProvider::QgsVectorLayerLabelProvider( QgsVectorLayer* layer, bool withFeatureLoop, const QgsPalLayerSettings* settings, const QString& layerName )
|
||||||
{
|
{
|
||||||
if ( layer->customProperty( "labeling" ).toString() != QString( "pal" ) || !layer->labelsEnabled() )
|
mSettings = settings ? *settings : QgsPalLayerSettings::fromLayer( layer );
|
||||||
return;
|
mName = layerName.isEmpty() ? layer->id() : layerName;
|
||||||
|
|
||||||
mSettings = QgsVectorLayerLabelSettings::fromLayer( layer );
|
|
||||||
mLayerId = layer->id();
|
mLayerId = layer->id();
|
||||||
mFields = layer->fields();
|
mFields = layer->fields();
|
||||||
mCrs = layer->crs();
|
mCrs = layer->crs();
|
||||||
@ -120,14 +117,10 @@ QgsVectorLayerLabelProvider::~QgsVectorLayerLabelProvider()
|
|||||||
delete mSource;
|
delete mSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString QgsVectorLayerLabelProvider::id() const
|
|
||||||
{
|
|
||||||
return mLayerId;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool QgsVectorLayerLabelProvider::prepare( const QgsRenderContext& context, QStringList& attributeNames )
|
bool QgsVectorLayerLabelProvider::prepare( const QgsRenderContext& context, QStringList& attributeNames )
|
||||||
{
|
{
|
||||||
QgsVectorLayerLabelSettings& lyr = mSettings;
|
QgsPalLayerSettings& lyr = mSettings;
|
||||||
const QgsMapSettings& mapSettings = mEngine->mapSettings();
|
const QgsMapSettings& mapSettings = mEngine->mapSettings();
|
||||||
|
|
||||||
QgsDebugMsgLevel( "PREPARE LAYER " + mLayerId, 4 );
|
QgsDebugMsgLevel( "PREPARE LAYER " + mLayerId, 4 );
|
||||||
@ -389,7 +382,7 @@ void QgsVectorLayerLabelProvider::drawLabel( QgsRenderContext& context, pal::Lab
|
|||||||
|
|
||||||
// add to the results
|
// add to the results
|
||||||
QString labeltext = label->getFeaturePart()->feature()->labelText();
|
QString labeltext = label->getFeaturePart()->feature()->labelText();
|
||||||
mEngine->results()->mLabelSearchTree->insertLabel( label, label->getFeaturePart()->featureId(), id(), labeltext, dFont, false, lf->hasFixedPosition() );
|
mEngine->results()->mLabelSearchTree->insertLabel( label, label->getFeaturePart()->featureId(), mLayerId, labeltext, dFont, false, lf->hasFixedPosition() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ class CORE_EXPORT QgsVectorLayerLabelProvider : public QgsAbstractLabelProvider
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
//! Convenience constructor to initialize the provider from given vector layer
|
//! Convenience constructor to initialize the provider from given vector layer
|
||||||
explicit QgsVectorLayerLabelProvider( QgsVectorLayer* layer, bool withFeatureLoop = true );
|
explicit QgsVectorLayerLabelProvider( QgsVectorLayer* layer, bool withFeatureLoop = true, const QgsPalLayerSettings* settings = 0, const QString& layerName = QString() );
|
||||||
|
|
||||||
//! Construct diagram provider with all the necessary configuration parameters
|
//! Construct diagram provider with all the necessary configuration parameters
|
||||||
QgsVectorLayerLabelProvider( const QgsPalLayerSettings& settings,
|
QgsVectorLayerLabelProvider( const QgsPalLayerSettings& settings,
|
||||||
@ -44,8 +44,6 @@ class CORE_EXPORT QgsVectorLayerLabelProvider : public QgsAbstractLabelProvider
|
|||||||
|
|
||||||
~QgsVectorLayerLabelProvider();
|
~QgsVectorLayerLabelProvider();
|
||||||
|
|
||||||
virtual QString id() const override;
|
|
||||||
|
|
||||||
virtual QList<QgsLabelFeature*> labelFeatures( const QgsRenderContext& context ) override;
|
virtual QList<QgsLabelFeature*> labelFeatures( const QgsRenderContext& context ) override;
|
||||||
|
|
||||||
virtual void drawLabel( QgsRenderContext& context, pal::LabelPosition* label ) const override;
|
virtual void drawLabel( QgsRenderContext& context, pal::LabelPosition* label ) const override;
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#include "qgsvectorlayer.h"
|
#include "qgsvectorlayer.h"
|
||||||
#include "qgsvectorlayerdiagramprovider.h"
|
#include "qgsvectorlayerdiagramprovider.h"
|
||||||
#include "qgsvectorlayerfeatureiterator.h"
|
#include "qgsvectorlayerfeatureiterator.h"
|
||||||
|
#include "qgsvectorlayerlabeling.h"
|
||||||
#include "qgsvectorlayerlabelprovider.h"
|
#include "qgsvectorlayerlabelprovider.h"
|
||||||
#include "qgspainteffect.h"
|
#include "qgspainteffect.h"
|
||||||
|
|
||||||
@ -494,7 +495,19 @@ void QgsVectorLayerRenderer::prepareLabeling( QgsVectorLayer* layer, QStringList
|
|||||||
{
|
{
|
||||||
if ( QgsLabelingEngineV2* engine2 = mContext.labelingEngineV2() )
|
if ( QgsLabelingEngineV2* engine2 = mContext.labelingEngineV2() )
|
||||||
{
|
{
|
||||||
if ( layer->labelsEnabled() )
|
mLabelProvider = layer->labeling().provider( layer );
|
||||||
|
if ( mLabelProvider )
|
||||||
|
{
|
||||||
|
engine2->addProvider( mLabelProvider );
|
||||||
|
if ( !mLabelProvider->prepare( mContext, attributeNames ) )
|
||||||
|
{
|
||||||
|
engine2->removeProvider( mLabelProvider );
|
||||||
|
mLabelProvider = 0; // deleted by engine
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//mLabelProvider = layer->labeling().addProviderToEngine( layer, engine2, mContext );
|
||||||
|
/*if ( layer->labelsEnabled() )
|
||||||
{
|
{
|
||||||
mLabelProvider = new QgsVectorLayerLabelProvider( layer, false );
|
mLabelProvider = new QgsVectorLayerLabelProvider( layer, false );
|
||||||
engine2->addProvider( mLabelProvider );
|
engine2->addProvider( mLabelProvider );
|
||||||
@ -503,7 +516,7 @@ void QgsVectorLayerRenderer::prepareLabeling( QgsVectorLayer* layer, QStringList
|
|||||||
engine2->removeProvider( mLabelProvider );
|
engine2->removeProvider( mLabelProvider );
|
||||||
mLabelProvider = 0; // deleted by engine
|
mLabelProvider = 0; // deleted by engine
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,7 @@ class TestQgsLabelingEngineV2 : public QObject
|
|||||||
void cleanupTestCase();
|
void cleanupTestCase();
|
||||||
void testBasic();
|
void testBasic();
|
||||||
void testDiagrams();
|
void testDiagrams();
|
||||||
|
void testRuleBased();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QgsVectorLayer* vl;
|
QgsVectorLayer* vl;
|
||||||
@ -135,6 +136,62 @@ void TestQgsLabelingEngineV2::testDiagrams()
|
|||||||
QImage img2 = job.renderedImage();
|
QImage img2 = job.renderedImage();
|
||||||
|
|
||||||
QCOMPARE( img, img2 );
|
QCOMPARE( img, img2 );
|
||||||
|
|
||||||
|
vl->loadDefaultStyle( res );
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "qgsvectorlayerlabeling.h"
|
||||||
|
#include "qgsrulebasedlabeling.h"
|
||||||
|
|
||||||
|
void TestQgsLabelingEngineV2::testRuleBased()
|
||||||
|
{
|
||||||
|
QSize size( 640, 480 );
|
||||||
|
QgsMapSettings mapSettings;
|
||||||
|
mapSettings.setOutputSize( size );
|
||||||
|
mapSettings.setExtent( vl->extent() );
|
||||||
|
mapSettings.setLayers( QStringList() << vl->id() );
|
||||||
|
|
||||||
|
// set up most basic rule-based labeling for layer
|
||||||
|
QgsRuleBasedLabeling::Rule* root = new QgsRuleBasedLabeling::Rule( 0 );
|
||||||
|
|
||||||
|
QgsPalLayerSettings s1;
|
||||||
|
s1.enabled = true;
|
||||||
|
s1.fieldName = "Class";
|
||||||
|
s1.obstacle = false;
|
||||||
|
s1.dist = 2;
|
||||||
|
s1.distInMapUnits = false;
|
||||||
|
root->appendChild( new QgsRuleBasedLabeling::Rule( new QgsPalLayerSettings( s1 ) ) );
|
||||||
|
|
||||||
|
QgsPalLayerSettings s2;
|
||||||
|
s2.enabled = true;
|
||||||
|
s2.fieldName = "Class";
|
||||||
|
s2.obstacle = false;
|
||||||
|
s2.dist = 2;
|
||||||
|
s2.textColor = Qt::red;
|
||||||
|
root->appendChild( new QgsRuleBasedLabeling::Rule( new QgsPalLayerSettings( s2 ), 0, 0, "Class = 'Jet'" ) );
|
||||||
|
|
||||||
|
vl->labeling().setMode( QgsVectorLayerLabeling::RuleBasedLabels );
|
||||||
|
vl->labeling().setRuleBasedLabeling( new QgsRuleBasedLabeling( root ) );
|
||||||
|
|
||||||
|
QgsMapRendererSequentialJob job( mapSettings );
|
||||||
|
job.start();
|
||||||
|
job.waitForFinished();
|
||||||
|
QImage img = job.renderedImage();
|
||||||
|
|
||||||
|
img.save( "/tmp/rules.png" );
|
||||||
|
|
||||||
|
vl->labeling().setMode( QgsVectorLayerLabeling::SimpleLabels );
|
||||||
|
|
||||||
|
/*
|
||||||
|
QPainter p( &img );
|
||||||
|
QgsRenderContext context = QgsRenderContext::fromMapSettings( mapSettings );
|
||||||
|
context.setPainter( &p );
|
||||||
|
|
||||||
|
QgsLabelingEngineV2 engine;
|
||||||
|
engine.setMapSettings( mapSettings );
|
||||||
|
engine.addProvider( new QgsRuleBasedLabelProvider( , vl ) );
|
||||||
|
engine.run( context );*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QTEST_MAIN( TestQgsLabelingEngineV2 )
|
QTEST_MAIN( TestQgsLabelingEngineV2 )
|
||||||
|
Loading…
x
Reference in New Issue
Block a user