[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:
Nyall Dawson 2015-07-17 15:26:57 +10:00
parent cc1a34fcea
commit 3a44e294de
17 changed files with 183 additions and 80 deletions

View File

@ -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

View File

@ -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 );

View File

@ -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 );

View File

@ -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 );
}

View File

@ -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();

View File

@ -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;
}

View File

@ -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;

View File

@ -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 ) )
{

View File

@ -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:

View File

@ -52,6 +52,7 @@ namespace pal
: mName( lyrName )
, pal( pal )
, mObstacle( obstacle )
, mObstacleType( PolygonInterior )
, mActive( active )
, mLabelLayer( toLabel )
, mDisplayAll( displayAll )

View File

@ -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;

View File

@ -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();

View File

@ -92,6 +92,12 @@ namespace pal
};
Q_DECLARE_FLAGS( LineArrangementFlags, LineArrangementFlag )
enum ObstacleType
{
PolygonInterior,
PolygonBoundary
};
/**
* \brief Pal main class.
*

View File

@ -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

View File

@ -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 );

View File

@ -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

View File

@ -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>