mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
[FEATURE][labeling] Add option to control how polygon layers
act as obstacles Options are either avoid placing labels over polygon interior or avoid placing over polygon boundaries. (Previous behaviour was always avoid placing over interior). Avoiding placing over boundaries is useful for regional boundary layers, where the features cover an entire area. In this case it's impossible to avoid placing labels within these features, and it looks much better to avoid placing them over the boundaries between features. End result is better cartographic placement of labels in this situation.
This commit is contained in:
parent
cc1a34fcea
commit
3a44e294de
@ -145,6 +145,17 @@ class QgsPalLayerSettings
|
||||
will be drawn with right alignment*/
|
||||
};
|
||||
|
||||
/** Valid obstacle types, which affect how features within the layer will act as obstacles
|
||||
* for labels.
|
||||
*/
|
||||
enum ObstacleType
|
||||
{
|
||||
PolygonInterior, /*!< avoid placing labels over interior of polygon (prefer placing labels totally
|
||||
outside or just slightly inside polygon) */
|
||||
PolygonBoundary /*!< avoid placing labels over boundary of polygon (prefer placing outside or
|
||||
completely inside polygon) */
|
||||
};
|
||||
|
||||
enum ShapeType
|
||||
{
|
||||
ShapeRectangle,
|
||||
@ -453,6 +464,10 @@ class QgsPalLayerSettings
|
||||
double minFeatureSize; // minimum feature size to be labelled (in mm)
|
||||
bool obstacle; // whether features for layer are obstacles to labels of other layers
|
||||
|
||||
/** Controls how features act as obstacles for labels
|
||||
*/
|
||||
ObstacleType obstacleType;
|
||||
|
||||
//-- scale factors
|
||||
double vectorScaleFactor; //scale factor painter units->pixels
|
||||
double rasterCompressFactor; //pixel resolution scale factor
|
||||
|
@ -80,6 +80,9 @@ QgsLabelingGui::QgsLabelingGui( QgsVectorLayer* layer, QgsMapCanvas* mapCanvas,
|
||||
mFontLetterSpacingSpinBox->setClearValue( 0.0 );
|
||||
mFontWordSpacingSpinBox->setClearValue( 0.0 );
|
||||
|
||||
mObstacleTypeComboBox->addItem( tr( "Over the feature's interior" ), QgsPalLayerSettings::PolygonInterior );
|
||||
mObstacleTypeComboBox->addItem( tr( "Over the feature's boundary" ), QgsPalLayerSettings::PolygonBoundary );
|
||||
|
||||
mCharDlg = new QgsCharacterSelectorDialog( this );
|
||||
|
||||
mRefFont = lblFontPreview->font();
|
||||
@ -152,6 +155,7 @@ QgsLabelingGui::QgsLabelingGui( QgsVectorLayer* layer, QgsMapCanvas* mapCanvas,
|
||||
chkMergeLines->setVisible( layer->geometryType() == QGis::Line );
|
||||
mDirectSymbolsFrame->setVisible( layer->geometryType() == QGis::Line );
|
||||
mMinSizeFrame->setVisible( layer->geometryType() != QGis::Point );
|
||||
mPolygonObstacleTypeFrame->setVisible( layer->geometryType() == QGis::Polygon );
|
||||
|
||||
// field combo and expression button
|
||||
mFieldExpressionWidget->setLayer( mLayer );
|
||||
@ -354,7 +358,8 @@ void QgsLabelingGui::init()
|
||||
mRepeatDistanceUnitWidget->setMapUnitScale( lyr.repeatDistanceMapUnitScale );
|
||||
|
||||
mPrioritySlider->setValue( lyr.priority );
|
||||
chkNoObstacle->setChecked( lyr.obstacle );
|
||||
mChkNoObstacle->setChecked( lyr.obstacle );
|
||||
mObstacleTypeComboBox->setCurrentIndex( mObstacleTypeComboBox->findData( lyr.obstacleType ) );
|
||||
chkLabelPerFeaturePart->setChecked( lyr.labelPerPart );
|
||||
mPalShowAllLabelsForLayerChkBx->setChecked( lyr.displayAll );
|
||||
chkMergeLines->setChecked( lyr.mergeLines );
|
||||
@ -648,7 +653,8 @@ QgsPalLayerSettings QgsLabelingGui::layerSettings()
|
||||
lyr.previewBkgrdColor = mPreviewBackgroundBtn->color();
|
||||
|
||||
lyr.priority = mPrioritySlider->value();
|
||||
lyr.obstacle = chkNoObstacle->isChecked();
|
||||
lyr.obstacle = mChkNoObstacle->isChecked();
|
||||
lyr.obstacleType = ( QgsPalLayerSettings::ObstacleType )mObstacleTypeComboBox->itemData( mObstacleTypeComboBox->currentIndex() ).toInt();
|
||||
lyr.labelPerPart = chkLabelPerFeaturePart->isChecked();
|
||||
lyr.displayAll = mPalShowAllLabelsForLayerChkBx->isChecked();
|
||||
lyr.mergeLines = chkMergeLines->isChecked();
|
||||
@ -1698,6 +1704,11 @@ void QgsLabelingGui::on_mDirectSymbRightToolBtn_clicked()
|
||||
mDirectSymbRightLineEdit->setText( QString( dirSymb ) );
|
||||
}
|
||||
|
||||
void QgsLabelingGui::on_mChkNoObstacle_toggled( bool active )
|
||||
{
|
||||
mPolygonObstacleTypeFrame->setEnabled( active );
|
||||
}
|
||||
|
||||
void QgsLabelingGui::showBackgroundRadius( bool show )
|
||||
{
|
||||
mShapeRadiusLabel->setVisible( show );
|
||||
|
@ -80,6 +80,7 @@ class APP_EXPORT QgsLabelingGui : public QWidget, private Ui::QgsLabelingGuiBase
|
||||
void on_mPreviewBackgroundBtn_colorChanged( const QColor &color );
|
||||
void on_mDirectSymbLeftToolBtn_clicked();
|
||||
void on_mDirectSymbRightToolBtn_clicked();
|
||||
void on_mChkNoObstacle_toggled( bool active );
|
||||
|
||||
protected:
|
||||
void blockInitSignals( bool block );
|
||||
|
@ -30,17 +30,17 @@
|
||||
namespace pal
|
||||
{
|
||||
|
||||
void CostCalculator::addObstacleCostPenalty( LabelPosition* lp, PointSet* feat )
|
||||
void CostCalculator::addObstacleCostPenalty( LabelPosition* lp, FeaturePart* obstacle )
|
||||
{
|
||||
int n = 0;
|
||||
double dist;
|
||||
double distlabel = lp->feature->getLabelDistance();
|
||||
|
||||
switch ( feat->getGeosType() )
|
||||
switch ( obstacle->getGeosType() )
|
||||
{
|
||||
case GEOS_POINT:
|
||||
|
||||
dist = lp->getDistanceToPoint( feat->x[0], feat->y[0] );
|
||||
dist = lp->getDistanceToPoint( obstacle->x[0], obstacle->y[0] );
|
||||
if ( dist < 0 )
|
||||
n = 2;
|
||||
else if ( dist < distlabel )
|
||||
@ -52,11 +52,23 @@ namespace pal
|
||||
case GEOS_LINESTRING:
|
||||
|
||||
// Is one of label's borders crossing the line ?
|
||||
n = ( lp->isBorderCrossingLine( feat ) ? 1 : 0 );
|
||||
n = ( lp->isBorderCrossingLine( obstacle ) ? 1 : 0 );
|
||||
break;
|
||||
|
||||
case GEOS_POLYGON:
|
||||
n = lp->getNumPointsInPolygon( feat->getNumPoints(), feat->x, feat->y );
|
||||
// behaviour depends on obstacle avoid type
|
||||
switch ( obstacle->layer()->obstacleType() )
|
||||
{
|
||||
case PolygonInterior:
|
||||
// n ranges from 0 -> 12
|
||||
n = lp->getNumPointsInPolygon( obstacle->getNumPoints(), obstacle->x, obstacle->y );
|
||||
break;
|
||||
case PolygonBoundary:
|
||||
// penalty may need tweaking, given that interior mode ranges up to 12
|
||||
n = ( lp->isBorderCrossingLine( obstacle ) ? 6 : 0 );
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@ -67,7 +79,7 @@ namespace pal
|
||||
|
||||
////////
|
||||
|
||||
void CostCalculator::setPolygonCandidatesCost( int nblp, LabelPosition **lPos, int max_p, RTree<PointSet*, double, 2, double> *obstacles, double bbx[4], double bby[4] )
|
||||
void CostCalculator::setPolygonCandidatesCost( int nblp, LabelPosition **lPos, int max_p, RTree<FeaturePart*, double, 2, double> *obstacles, double bbx[4], double bby[4] )
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -125,7 +137,7 @@ namespace pal
|
||||
}
|
||||
|
||||
|
||||
void CostCalculator::setCandidateCostFromPolygon( LabelPosition* lp, RTree <PointSet*, double, 2, double> *obstacles, double bbx[4], double bby[4] )
|
||||
void CostCalculator::setCandidateCostFromPolygon( LabelPosition* lp, RTree <FeaturePart*, double, 2, double> *obstacles, double bbx[4], double bby[4] )
|
||||
{
|
||||
|
||||
double amin[2];
|
||||
@ -153,7 +165,7 @@ namespace pal
|
||||
delete pCost;
|
||||
}
|
||||
|
||||
int CostCalculator::finalizeCandidatesCosts( Feats* feat, int max_p, RTree <PointSet*, double, 2, double> *obstacles, double bbx[4], double bby[4] )
|
||||
int CostCalculator::finalizeCandidatesCosts( Feats* feat, int max_p, RTree <FeaturePart*, double, 2, double> *obstacles, double bbx[4], double bby[4] )
|
||||
{
|
||||
// If candidates list is smaller than expected
|
||||
if ( max_p > feat->nblp )
|
||||
@ -191,7 +203,7 @@ namespace pal
|
||||
|
||||
if ( feat->feature->getGeosType() == GEOS_POLYGON )
|
||||
{
|
||||
int arrangement = feat->feature->getLayer()->arrangement();
|
||||
int arrangement = feat->feature->layer()->arrangement();
|
||||
if ( arrangement == P_FREE || arrangement == P_HORIZ )
|
||||
setPolygonCandidatesCost( stop, ( LabelPosition** ) feat->lPos, max_p, obstacles, bbx, bby );
|
||||
}
|
||||
|
@ -25,18 +25,18 @@ namespace pal
|
||||
{
|
||||
public:
|
||||
/** Increase candidate's cost according to its collision with passed feature */
|
||||
static void addObstacleCostPenalty( LabelPosition* lp, PointSet* feat );
|
||||
static void addObstacleCostPenalty( LabelPosition* lp, pal::FeaturePart *obstacle );
|
||||
|
||||
static void setPolygonCandidatesCost( int nblp, LabelPosition **lPos, int max_p, RTree<PointSet*, double, 2, double> *obstacles, double bbx[4], double bby[4] );
|
||||
static void setPolygonCandidatesCost( int nblp, LabelPosition **lPos, int max_p, RTree<pal::FeaturePart*, double, 2, double> *obstacles, double bbx[4], double bby[4] );
|
||||
|
||||
/** Set cost to the smallest distance between lPos's centroid and a polygon stored in geoetry field */
|
||||
static void setCandidateCostFromPolygon( LabelPosition* lp, RTree <PointSet*, double, 2, double> *obstacles, double bbx[4], double bby[4] );
|
||||
static void setCandidateCostFromPolygon( LabelPosition* lp, RTree<pal::FeaturePart *, double, 2, double> *obstacles, double bbx[4], double bby[4] );
|
||||
|
||||
/** Sort candidates by costs, skip the worse ones, evaluate polygon candidates */
|
||||
static int finalizeCandidatesCosts( Feats* feat, int max_p, RTree <PointSet*, double, 2, double> *obstacles, double bbx[4], double bby[4] );
|
||||
static int finalizeCandidatesCosts( Feats* feat, int max_p, RTree<pal::FeaturePart *, double, 2, double> *obstacles, double bbx[4], double bby[4] );
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* \brief Data structure to compute polygon's candidates costs
|
||||
*
|
||||
* eight segment from center of candidat to (rpx,rpy) points (0°, 45°, 90°, ..., 315°)
|
||||
@ -49,7 +49,7 @@ namespace pal
|
||||
public:
|
||||
PolygonCostCalculator( LabelPosition *lp );
|
||||
|
||||
void update( PointSet *pset );
|
||||
void update( pal::PointSet *pset );
|
||||
|
||||
double getCost();
|
||||
|
||||
|
@ -132,8 +132,6 @@ namespace pal
|
||||
|
||||
void FeaturePart::extractCoords( const GEOSGeometry* geom )
|
||||
{
|
||||
int i, j;
|
||||
|
||||
const GEOSCoordSequence *coordSeq;
|
||||
GEOSContextHandle_t geosctxt = geosContext();
|
||||
|
||||
@ -145,35 +143,15 @@ namespace pal
|
||||
{
|
||||
// set nbHoles, holes member variables
|
||||
nbHoles = GEOSGetNumInteriorRings_r( geosctxt, geom );
|
||||
holes = new PointSet*[nbHoles];
|
||||
holes = new FeaturePart*[nbHoles];
|
||||
|
||||
for ( i = 0; i < nbHoles; i++ )
|
||||
for ( int i = 0; i < nbHoles; ++i )
|
||||
{
|
||||
holes[i] = new PointSet();
|
||||
holes[i]->holeOf = NULL;
|
||||
|
||||
const GEOSGeometry* interior = GEOSGetInteriorRingN_r( geosctxt, geom, i );
|
||||
holes[i]->nbPoints = GEOSGetNumCoordinates_r( geosctxt, interior );
|
||||
holes[i]->x = new double[holes[i]->nbPoints];
|
||||
holes[i]->y = new double[holes[i]->nbPoints];
|
||||
|
||||
holes[i]->xmin = holes[i]->ymin = DBL_MAX;
|
||||
holes[i]->xmax = holes[i]->ymax = -DBL_MAX;
|
||||
|
||||
coordSeq = GEOSGeom_getCoordSeq_r( geosctxt, interior );
|
||||
|
||||
for ( j = 0; j < holes[i]->nbPoints; j++ )
|
||||
{
|
||||
GEOSCoordSeq_getX_r( geosctxt, coordSeq, j, &holes[i]->x[j] );
|
||||
GEOSCoordSeq_getY_r( geosctxt, coordSeq, j, &holes[i]->y[j] );
|
||||
|
||||
holes[i]->xmax = holes[i]->x[j] > holes[i]->xmax ? holes[i]->x[j] : holes[i]->xmax;
|
||||
holes[i]->xmin = holes[i]->x[j] < holes[i]->xmin ? holes[i]->x[j] : holes[i]->xmin;
|
||||
|
||||
holes[i]->ymax = holes[i]->y[j] > holes[i]->ymax ? holes[i]->y[j] : holes[i]->ymax;
|
||||
holes[i]->ymin = holes[i]->y[j] < holes[i]->ymin ? holes[i]->y[j] : holes[i]->ymin;
|
||||
}
|
||||
|
||||
holes[i] = new FeaturePart( f, interior );
|
||||
holes[i]->holeOf = NULL;
|
||||
// possibly not needed. it's not done for the exterior ring, so I'm not sure
|
||||
// why it's just done here...
|
||||
reorderPolygon( holes[i]->nbPoints, holes[i]->x, holes[i]->y );
|
||||
}
|
||||
}
|
||||
@ -199,7 +177,7 @@ namespace pal
|
||||
x = new double[nbPoints];
|
||||
y = new double[nbPoints];
|
||||
|
||||
for ( i = 0; i < nbPoints; i++ )
|
||||
for ( int i = 0; i < nbPoints; ++i )
|
||||
{
|
||||
GEOSCoordSeq_getX_r( geosctxt, coordSeq, i, &x[i] );
|
||||
GEOSCoordSeq_getY_r( geosctxt, coordSeq, i, &y[i] );
|
||||
@ -259,7 +237,7 @@ namespace pal
|
||||
|
||||
|
||||
|
||||
Layer *FeaturePart::getLayer()
|
||||
Layer* FeaturePart::layer()
|
||||
{
|
||||
return f->layer;
|
||||
}
|
||||
|
@ -247,11 +247,9 @@ namespace pal
|
||||
*/
|
||||
const GEOSGeometry* getGeometry() const { return the_geom; }
|
||||
|
||||
/**
|
||||
* \brief return the layer that feature belongs to
|
||||
* \return the layer of the feature
|
||||
/** Returns the layer that feature belongs to.
|
||||
*/
|
||||
Layer * getLayer();
|
||||
Layer* layer();
|
||||
|
||||
/**
|
||||
* \brief generic method to generate candidates
|
||||
@ -295,7 +293,7 @@ namespace pal
|
||||
bool getAlwaysShow() { return f->alwaysShow; }
|
||||
|
||||
int getNumSelfObstacles() const { return nbHoles; }
|
||||
PointSet* getSelfObstacle( int i ) { return holes[i]; }
|
||||
FeaturePart* getSelfObstacle( int i ) { return holes[i]; }
|
||||
|
||||
/** Check whether this part is connected with some other part */
|
||||
bool isConnected( FeaturePart* p2 );
|
||||
@ -310,7 +308,7 @@ namespace pal
|
||||
Feature* f;
|
||||
|
||||
int nbHoles;
|
||||
PointSet **holes;
|
||||
FeaturePart **holes;
|
||||
|
||||
GEOSGeometry *the_geom;
|
||||
bool ownsGeom;
|
||||
|
@ -97,12 +97,12 @@ namespace pal
|
||||
y[3] = y1 + dy2;
|
||||
|
||||
// upside down ? (curved labels are always correct)
|
||||
if ( feature->getLayer()->arrangement() != P_CURVED &&
|
||||
if ( feature->layer()->arrangement() != P_CURVED &&
|
||||
this->alpha > M_PI / 2 && this->alpha <= 3*M_PI / 2 )
|
||||
{
|
||||
bool uprightLabel = false;
|
||||
|
||||
switch ( feature->getLayer()->upsidedownLabels() )
|
||||
switch ( feature->layer()->upsidedownLabels() )
|
||||
{
|
||||
case Layer::Upright:
|
||||
uprightLabel = true;
|
||||
@ -388,7 +388,7 @@ namespace pal
|
||||
|
||||
QString LabelPosition::getLayerName() const
|
||||
{
|
||||
return feature->getLayer()->name();
|
||||
return feature->layer()->name();
|
||||
}
|
||||
|
||||
bool LabelPosition::costShrink( void *l, void *r )
|
||||
@ -402,17 +402,17 @@ namespace pal
|
||||
}
|
||||
|
||||
|
||||
bool LabelPosition::polygonObstacleCallback( PointSet *feat, void *ctx )
|
||||
bool LabelPosition::polygonObstacleCallback( FeaturePart *obstacle, void *ctx )
|
||||
{
|
||||
PolygonCostCalculator *pCost = ( PolygonCostCalculator* ) ctx;
|
||||
|
||||
LabelPosition *lp = pCost->getLabel();
|
||||
if (( feat == lp->feature ) || ( feat->getHoleOf() && feat->getHoleOf() != lp->feature ) )
|
||||
if (( obstacle == lp->feature ) || ( obstacle->getHoleOf() && obstacle->getHoleOf() != lp->feature ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
pCost->update( feat );
|
||||
pCost->update( obstacle );
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -440,7 +440,7 @@ namespace pal
|
||||
|
||||
bool LabelPosition::pruneCallback( LabelPosition *lp, void *ctx )
|
||||
{
|
||||
PointSet *feat = (( PruneCtx* ) ctx )->obstacle;
|
||||
FeaturePart *feat = (( PruneCtx* ) ctx )->obstacle;
|
||||
|
||||
if (( feat == lp->feature ) || ( feat->getHoleOf() && feat->getHoleOf() != lp->feature ) )
|
||||
{
|
||||
|
@ -217,7 +217,7 @@ namespace pal
|
||||
typedef struct
|
||||
{
|
||||
Pal* pal;
|
||||
PointSet *obstacle;
|
||||
FeaturePart *obstacle;
|
||||
} PruneCtx;
|
||||
|
||||
/** Check whether the candidate in ctx overlap with obstacle feat */
|
||||
@ -247,7 +247,7 @@ namespace pal
|
||||
static bool removeOverlapCallback( LabelPosition *lp, void *ctx );
|
||||
|
||||
// for polygon cost calculation
|
||||
static bool polygonObstacleCallback( PointSet *feat, void *ctx );
|
||||
static bool polygonObstacleCallback( pal::FeaturePart *obstacle, void *ctx );
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -52,6 +52,7 @@ namespace pal
|
||||
: mName( lyrName )
|
||||
, pal( pal )
|
||||
, mObstacle( obstacle )
|
||||
, mObstacleType( PolygonInterior )
|
||||
, mActive( active )
|
||||
, mLabelLayer( toLabel )
|
||||
, mDisplayAll( displayAll )
|
||||
|
@ -149,6 +149,19 @@ namespace pal
|
||||
*/
|
||||
bool obstacle() const { return mObstacle; }
|
||||
|
||||
/** Returns the obstacle type, which controls how features within the layer
|
||||
* act as obstacles for labels.
|
||||
* @see setObstacleType
|
||||
*/
|
||||
ObstacleType obstacleType() const { return mObstacleType; }
|
||||
|
||||
/** Sets the obstacle type, which controls how features within the layer
|
||||
* act as obstacles for labels.
|
||||
* @param obstacleType new obstacle type
|
||||
* @see obstacleType
|
||||
*/
|
||||
void setObstacleType( ObstacleType obstacleType ) { mObstacleType = obstacleType; }
|
||||
|
||||
/** Sets the layer's priority.
|
||||
* @param priority layer priority, between 0 and 1. 0 corresponds to highest priority,
|
||||
* 1 to lowest priority.
|
||||
@ -260,6 +273,7 @@ namespace pal
|
||||
double mDefaultPriority;
|
||||
|
||||
bool mObstacle;
|
||||
ObstacleType mObstacleType;
|
||||
bool mActive;
|
||||
bool mLabelLayer;
|
||||
bool mDisplayAll;
|
||||
|
@ -200,7 +200,7 @@ namespace pal
|
||||
{
|
||||
Layer *layer;
|
||||
QLinkedList<Feats*>* fFeats;
|
||||
RTree<PointSet*, double, 2, double> *obstacles;
|
||||
RTree<FeaturePart*, double, 2, double> *obstacles;
|
||||
RTree<LabelPosition*, double, 2, double> *candidates;
|
||||
double bbox_min[2];
|
||||
double bbox_max[2];
|
||||
@ -287,7 +287,7 @@ namespace pal
|
||||
Pal* pal;
|
||||
} FilterContext;
|
||||
|
||||
bool filteringCallback( PointSet *pset, void *ctx )
|
||||
bool filteringCallback( FeaturePart *featurePart, void *ctx )
|
||||
{
|
||||
|
||||
RTree<LabelPosition*, double, 2, double> *cdtsIndex = (( FilterContext* ) ctx )->cdtsIndex;
|
||||
@ -297,10 +297,10 @@ namespace pal
|
||||
return false; // do not continue searching
|
||||
|
||||
double amin[2], amax[2];
|
||||
pset->getBoundingBox( amin, amax );
|
||||
featurePart->getBoundingBox( amin, amax );
|
||||
|
||||
LabelPosition::PruneCtx pruneContext;
|
||||
pruneContext.obstacle = pset;
|
||||
pruneContext.obstacle = featurePart;
|
||||
pruneContext.pal = pal;
|
||||
cdtsIndex->Search( amin, amax, LabelPosition::pruneCallback, ( void* ) &pruneContext );
|
||||
|
||||
@ -310,7 +310,7 @@ namespace pal
|
||||
Problem* Pal::extract( int nbLayers, const QStringList& layersName, double lambda_min, double phi_min, double lambda_max, double phi_max )
|
||||
{
|
||||
// to store obstacles
|
||||
RTree<PointSet*, double, 2, double> *obstacles = new RTree<PointSet*, double, 2, double>();
|
||||
RTree<FeaturePart*, double, 2, double> *obstacles = new RTree<FeaturePart*, double, 2, double>();
|
||||
|
||||
Problem *prob = new Problem();
|
||||
|
||||
|
@ -92,6 +92,12 @@ namespace pal
|
||||
};
|
||||
Q_DECLARE_FLAGS( LineArrangementFlags, LineArrangementFlag )
|
||||
|
||||
enum ObstacleType
|
||||
{
|
||||
PolygonInterior,
|
||||
PolygonBoundary
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Pal main class.
|
||||
*
|
||||
|
@ -2626,7 +2626,7 @@ namespace pal
|
||||
solList->push_back( labelpositions[sol->s[i]] ); // active labels
|
||||
}
|
||||
else if ( returnInactive
|
||||
|| labelpositions[featStartId[i]]->getFeaturePart()->getLayer()->displayAll()
|
||||
|| labelpositions[featStartId[i]]->getFeaturePart()->layer()->displayAll()
|
||||
|| labelpositions[featStartId[i]]->getFeaturePart()->getAlwaysShow() )
|
||||
{
|
||||
solList->push_back( labelpositions[featStartId[i]] ); // unplaced label
|
||||
|
@ -201,6 +201,7 @@ QgsPalLayerSettings::QgsPalLayerSettings()
|
||||
limitNumLabels = false;
|
||||
maxNumLabels = 2000;
|
||||
obstacle = true;
|
||||
obstacleType = PolygonInterior;
|
||||
|
||||
// scale factors
|
||||
vectorScaleFactor = 1.0;
|
||||
@ -413,6 +414,7 @@ QgsPalLayerSettings::QgsPalLayerSettings( const QgsPalLayerSettings& s )
|
||||
limitNumLabels = s.limitNumLabels;
|
||||
maxNumLabels = s.maxNumLabels;
|
||||
obstacle = s.obstacle;
|
||||
obstacleType = s.obstacleType;
|
||||
|
||||
// shape background
|
||||
shapeDraw = s.shapeDraw;
|
||||
@ -920,6 +922,7 @@ void QgsPalLayerSettings::readFromLayer( QgsVectorLayer* layer )
|
||||
limitNumLabels = layer->customProperty( "labeling/limitNumLabels", QVariant( false ) ).toBool();
|
||||
maxNumLabels = layer->customProperty( "labeling/maxNumLabels", QVariant( 2000 ) ).toInt();
|
||||
obstacle = layer->customProperty( "labeling/obstacle", QVariant( true ) ).toBool();
|
||||
obstacleType = ( ObstacleType )layer->customProperty( "labeling/obstacleType", QVariant( PolygonInterior ) ).toUInt();
|
||||
|
||||
readDataDefinedPropertyMap( layer, dataDefinedProperties );
|
||||
}
|
||||
@ -1071,6 +1074,7 @@ void QgsPalLayerSettings::writeToLayer( QgsVectorLayer* layer )
|
||||
layer->setCustomProperty( "labeling/limitNumLabels", limitNumLabels );
|
||||
layer->setCustomProperty( "labeling/maxNumLabels", maxNumLabels );
|
||||
layer->setCustomProperty( "labeling/obstacle", obstacle );
|
||||
layer->setCustomProperty( "labeling/obstacleType", ( unsigned int )obstacleType );
|
||||
|
||||
writeDataDefinedPropertyMap( layer, dataDefinedProperties );
|
||||
}
|
||||
@ -3316,6 +3320,16 @@ int QgsPalLabeling::prepareLayer( QgsVectorLayer* layer, QStringList& attrNames,
|
||||
// set whether adjacent lines should be merged
|
||||
l->setMergeConnectedLines( lyr.mergeLines );
|
||||
|
||||
// set obstacle type
|
||||
switch ( lyr.obstacleType )
|
||||
{
|
||||
case PolygonInterior:
|
||||
l->setObstacleType( pal::PolygonInterior );
|
||||
break;
|
||||
case PolygonBoundary:
|
||||
l->setObstacleType( pal::PolygonBoundary );
|
||||
break;
|
||||
}
|
||||
|
||||
// set whether location of centroid must be inside of polygons
|
||||
l->setCentroidInside( lyr.centroidInside );
|
||||
|
@ -120,6 +120,17 @@ class CORE_EXPORT QgsPalLayerSettings
|
||||
will be drawn with right alignment*/
|
||||
};
|
||||
|
||||
/** Valid obstacle types, which affect how features within the layer will act as obstacles
|
||||
* for labels.
|
||||
*/
|
||||
enum ObstacleType
|
||||
{
|
||||
PolygonInterior, /*!< avoid placing labels over interior of polygon (prefer placing labels totally
|
||||
outside or just slightly inside polygon) */
|
||||
PolygonBoundary /*!< avoid placing labels over boundary of polygon (prefer placing outside or
|
||||
completely inside polygon) */
|
||||
};
|
||||
|
||||
enum ShapeType
|
||||
{
|
||||
ShapeRectangle = 0,
|
||||
@ -428,6 +439,10 @@ class CORE_EXPORT QgsPalLayerSettings
|
||||
double minFeatureSize; // minimum feature size to be labelled (in mm)
|
||||
bool obstacle; // whether features for layer are obstacles to labels of other layers
|
||||
|
||||
/** Controls how features act as obstacles for labels
|
||||
*/
|
||||
ObstacleType obstacleType;
|
||||
|
||||
//-- scale factors
|
||||
double vectorScaleFactor; //scale factor painter units->pixels
|
||||
double rasterCompressFactor; //pixel resolution scale factor
|
||||
|
@ -494,7 +494,7 @@
|
||||
<item>
|
||||
<widget class="QStackedWidget" name="mLabelStackedWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
<number>6</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="mLabelPage_Text">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
@ -1244,7 +1244,7 @@ font-style: italic;</string>
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>566</width>
|
||||
<width>383</width>
|
||||
<height>389</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -1844,8 +1844,8 @@ font-style: italic;</string>
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>582</width>
|
||||
<height>379</height>
|
||||
<width>298</width>
|
||||
<height>257</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_12">
|
||||
@ -2205,7 +2205,7 @@ font-style: italic;</string>
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>566</width>
|
||||
<width>362</width>
|
||||
<height>697</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -3008,7 +3008,7 @@ font-style: italic;</string>
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>566</width>
|
||||
<width>325</width>
|
||||
<height>424</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -3489,7 +3489,7 @@ font-style: italic;</string>
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>566</width>
|
||||
<width>427</width>
|
||||
<height>829</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -4818,9 +4818,9 @@ font-style: italic;</string>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>566</width>
|
||||
<height>622</height>
|
||||
<y>-292</y>
|
||||
<width>578</width>
|
||||
<height>655</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_8">
|
||||
@ -5440,7 +5440,7 @@ font-style: italic;</string>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="chkNoObstacle">
|
||||
<widget class="QCheckBox" name="mChkNoObstacle">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
@ -5449,6 +5449,44 @@ font-style: italic;</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="mPolygonObstacleTypeFrame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_11">
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_14">
|
||||
<property name="text">
|
||||
<string>Minimise placing labels</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="mObstacleTypeComboBox"/>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_15">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
@ -5875,7 +5913,7 @@ font-style: italic;</string>
|
||||
<tabstop>mLimitLabelChkBox</tabstop>
|
||||
<tabstop>mLimitLabelSpinBox</tabstop>
|
||||
<tabstop>mMinSizeSpinBox</tabstop>
|
||||
<tabstop>chkNoObstacle</tabstop>
|
||||
<tabstop>mChkNoObstacle</tabstop>
|
||||
<tabstop>mRenderingLabelGrpBx</tabstop>
|
||||
</tabstops>
|
||||
<resources>
|
||||
|
Loading…
x
Reference in New Issue
Block a user