[FEATURE][labeling] Add option to only draw labels which fit

completely within polygon features (fix #12136)
This commit is contained in:
Nyall Dawson 2015-07-20 13:48:49 +10:00
parent 42bef4e02e
commit dc4049ddff
11 changed files with 208 additions and 56 deletions

View File

@ -418,6 +418,10 @@ class QgsPalLayerSettings
bool centroidWhole; // whether centroid calculated from whole or visible polygon
bool centroidInside; // whether centroid-point calculated must be inside polygon
/** True if only labels which completely fit within a polygon are allowed.
*/
bool fitInPolygonOnly;
double dist; // distance from the feature (in mm)
bool distInMapUnits; //true if distance is in map units (otherwise in mm)
QgsMapUnitScale distMapUnitScale;

View File

@ -156,6 +156,7 @@ QgsLabelingGui::QgsLabelingGui( QgsVectorLayer* layer, QgsMapCanvas* mapCanvas,
mDirectSymbolsFrame->setVisible( layer->geometryType() == QGis::Line );
mMinSizeFrame->setVisible( layer->geometryType() != QGis::Point );
mPolygonObstacleTypeFrame->setVisible( layer->geometryType() == QGis::Polygon );
mPolygonFeatureOptionsFrame->setVisible( layer->geometryType() == QGis::Polygon );
// field combo and expression button
mFieldExpressionWidget->setLayer( mLayer );
@ -310,6 +311,7 @@ void QgsLabelingGui::init()
// populate placement options
mCentroidRadioWhole->setChecked( lyr.centroidWhole );
mCentroidInsideCheckBox->setChecked( lyr.centroidInside );
mFitInsidePolygonCheckBox->setChecked( lyr.fitInPolygonOnly );
mLineDistanceSpnBx->setValue( lyr.dist );
mLineDistanceUnitWidget->setUnit( lyr.distInMapUnits ? QgsSymbolV2::MapUnit : QgsSymbolV2::MM );
mLineDistanceUnitWidget->setMapUnitScale( lyr.distMapUnitScale );
@ -593,6 +595,7 @@ QgsPalLayerSettings QgsLabelingGui::layerSettings()
QWidget* curPlacementWdgt = stackedPlacement->currentWidget();
lyr.centroidWhole = mCentroidRadioWhole->isChecked();
lyr.centroidInside = mCentroidInsideCheckBox->isChecked();
lyr.fitInPolygonOnly = mFitInsidePolygonCheckBox->isChecked();
lyr.dist = mLineDistanceSpnBx->value();
lyr.distInMapUnits = ( mLineDistanceUnitWidget->unit() == QgsSymbolV2::MapUnit );
lyr.distMapUnitScale = mLineDistanceUnitWidget->getMapUnitScale();

View File

@ -237,7 +237,7 @@ namespace pal
}
}
int FeaturePart::setPositionOverPoint( double x, double y, LabelPosition ***lPos, double angle )
int FeaturePart::setPositionOverPoint( double x, double y, LabelPosition ***lPos, double angle, PointSet *mapShape )
{
int nbp = 1;
*lPos = new LabelPosition *[nbp];
@ -308,20 +308,30 @@ namespace pal
double lx = x + xdiff;
double ly = y + ydiff;
if ( mapShape && type == GEOS_POLYGON && mFeature->layer->fitInPolygonOnly() )
{
if ( !mapShape->containsLabelCandidate( lx, ly, labelW, labelH, angle ) )
{
delete[] *lPos;
*lPos = 0;
return 0;
}
}
( *lPos )[0] = new LabelPosition( id, lx, ly, labelW, labelH, angle, cost, this, false, quadrantFromOffset() );
return nbp;
}
int FeaturePart::setPositionForPoint( double x, double y, LabelPosition ***lPos, double angle )
int FeaturePart::setPositionForPoint( double x, double y, LabelPosition ***lPos, double angle, PointSet *mapShape )
{
#ifdef _DEBUG_
std::cout << "SetPosition (point) : " << layer->name << "/" << uid << std::endl;
#endif
double xrm = mFeature->label_x;
double yrm = mFeature->label_y;
double distlabel = mFeature->distlabel;
double labelWidth = mFeature->label_x;
double labelHeight = mFeature->label_y;
double distanceToLabel = mFeature->distlabel;
int numberCandidates = mFeature->layer->pal->point_p;
@ -339,10 +349,10 @@ namespace pal
double gamma1, gamma2;
if ( distlabel > 0 )
if ( distanceToLabel > 0 )
{
gamma1 = atan2( yrm / 2, distlabel + xrm / 2 );
gamma2 = atan2( xrm / 2, distlabel + yrm / 2 );
gamma1 = atan2( labelHeight / 2, distanceToLabel + labelWidth / 2 );
gamma2 = atan2( labelWidth / 2, distanceToLabel + labelHeight / 2 );
}
else
{
@ -361,7 +371,7 @@ namespace pal
std::cout << "Oups... label size error..." << std::endl;
}
*lPos = new LabelPosition *[numberCandidates];
QList< LabelPosition* > candidates;
int i;
double angleToCandidate;
@ -377,59 +387,59 @@ namespace pal
if ( angleToCandidate < gamma1 || angleToCandidate > a360 - gamma1 ) // on the right
{
labelX += distlabel;
labelX += distanceToLabel;
double iota = ( angleToCandidate + gamma1 );
if ( iota > a360 - gamma1 )
iota -= a360;
//ly += -yrm/2.0 + tan(alpha)*(distlabel + xrm/2);
labelY += -yrm + yrm * iota / ( 2 * gamma1 );
labelY += -labelHeight + labelHeight * iota / ( 2 * gamma1 );
quadrant = LabelPosition::QuadrantRight;
}
else if ( angleToCandidate < a90 - gamma2 ) // top-right
{
labelX += distlabel * cos( angleToCandidate );
labelY += distlabel * sin( angleToCandidate );
labelX += distanceToLabel * cos( angleToCandidate );
labelY += distanceToLabel * sin( angleToCandidate );
quadrant = LabelPosition::QuadrantAboveRight;
}
else if ( angleToCandidate < a90 + gamma2 ) // top
{
//lx += -xrm/2.0 - tan(alpha+a90)*(distlabel + yrm/2);
labelX += -xrm * ( angleToCandidate - a90 + gamma2 ) / ( 2 * gamma2 );
labelY += distlabel;
labelX += -labelWidth * ( angleToCandidate - a90 + gamma2 ) / ( 2 * gamma2 );
labelY += distanceToLabel;
quadrant = LabelPosition::QuadrantAbove;
}
else if ( angleToCandidate < a180 - gamma1 ) // top left
{
labelX += distlabel * cos( angleToCandidate ) - xrm;
labelY += distlabel * sin( angleToCandidate );
labelX += distanceToLabel * cos( angleToCandidate ) - labelWidth;
labelY += distanceToLabel * sin( angleToCandidate );
quadrant = LabelPosition::QuadrantAboveLeft;
}
else if ( angleToCandidate < a180 + gamma1 ) // left
{
labelX += -distlabel - xrm;
labelX += -distanceToLabel - labelWidth;
//ly += -yrm/2.0 - tan(alpha)*(distlabel + xrm/2);
labelY += - ( angleToCandidate - a180 + gamma1 ) * yrm / ( 2 * gamma1 );
labelY += - ( angleToCandidate - a180 + gamma1 ) * labelHeight / ( 2 * gamma1 );
quadrant = LabelPosition::QuadrantLeft;
}
else if ( angleToCandidate < a270 - gamma2 ) // down - left
{
labelX += distlabel * cos( angleToCandidate ) - xrm;
labelY += distlabel * sin( angleToCandidate ) - yrm;
labelX += distanceToLabel * cos( angleToCandidate ) - labelWidth;
labelY += distanceToLabel * sin( angleToCandidate ) - labelHeight;
quadrant = LabelPosition::QuadrantBelowLeft;
}
else if ( angleToCandidate < a270 + gamma2 ) // down
{
labelY += -distlabel - yrm;
labelY += -distanceToLabel - labelHeight;
//lx += -xrm/2.0 + tan(alpha+a90)*(distlabel + yrm/2);
labelX += -xrm + ( angleToCandidate - a270 + gamma2 ) * xrm / ( 2 * gamma2 );
labelX += -labelWidth + ( angleToCandidate - a270 + gamma2 ) * labelWidth / ( 2 * gamma2 );
quadrant = LabelPosition::QuadrantBelow;
}
else if ( angleToCandidate < a360 ) // down - right
{
labelX += distlabel * cos( angleToCandidate );
labelY += distlabel * sin( angleToCandidate ) - yrm;
labelX += distanceToLabel * cos( angleToCandidate );
labelY += distanceToLabel * sin( angleToCandidate ) - labelHeight;
quadrant = LabelPosition::QuadrantBelowRight;
}
@ -440,7 +450,16 @@ namespace pal
else
cost = 0.0001 + 0.0020 * double( icost ) / double( numberCandidates - 1 );
( *lPos )[i] = new LabelPosition( i, labelX, labelY, xrm, yrm, angle, cost, this, false, quadrant );
if ( mapShape && type == GEOS_POLYGON && mFeature->layer->fitInPolygonOnly() )
{
if ( !mapShape->containsLabelCandidate( labelX, labelY, labelWidth, labelHeight, angle ) )
{
continue;
}
}
candidates << new LabelPosition( i, labelX, labelY, labelWidth, labelHeight, angle, cost, this, false, quadrant );
icost += inc;
@ -457,10 +476,19 @@ namespace pal
}
return numberCandidates;
if ( !candidates.isEmpty() )
{
*lPos = new LabelPosition *[candidates.count()];
for ( int i = 0; i < candidates.count(); ++i )
{
( *lPos )[i] = candidates.at( i );
}
}
return candidates.count();
}
// TODO work with squared distance by remonving call to sqrt or dist_euc2d
// TODO work with squared distance by removing call to sqrt or dist_euc2d
int FeaturePart::setPositionForLine( LabelPosition ***lPos, PointSet *mapShape )
{
#ifdef _DEBUG_
@ -969,8 +997,8 @@ namespace pal
int i;
int j;
double xrm = mFeature->label_x;
double yrm = mFeature->label_y;
double labelWidth = mFeature->label_x;
double labelHeight = mFeature->label_y;
//print();
@ -981,7 +1009,7 @@ namespace pal
shapes_toProcess.append( mapShape );
splitPolygons( shapes_toProcess, shapes_final, xrm, yrm, mFeature->uid );
splitPolygons( shapes_toProcess, shapes_final, labelWidth, labelHeight, mFeature->uid );
int nbp;
@ -997,7 +1025,7 @@ namespace pal
double dy;
int bbid;
double beta;
double diago = sqrt( xrm * xrm / 4.0 + yrm * yrm / 4 );
double diago = sqrt( labelWidth * labelWidth / 4.0 + labelHeight * labelHeight / 4 );
double rx, ry;
CHullBox **boxes = new CHullBox*[shapes_final.size()];
j = 0;
@ -1015,12 +1043,16 @@ namespace pal
}
//dx = dy = min( yrm, xrm ) / 2;
dx = xrm / 2.0;
dy = yrm / 2.0;
dx = labelWidth / 2.0;
dy = labelHeight / 2.0;
int num_try = 0;
int max_try = 10;
int numTry = 0;
//fit in polygon only mode slows down calculation a lot, so if it's enabled
//then use a smaller limit for number of iterations
int maxTry = mFeature->layer->fitInPolygonOnly() ? 7 : 10;
do
{
for ( bbid = 0; bbid < j; bbid++ )
@ -1033,11 +1065,21 @@ namespace pal
std::cout << " Box size: " << box->length << "/" << box->width << std::endl;
std::cout << " Alpha: " << alpha << " " << alpha * 180 / M_PI << std::endl;
std::cout << " Dx;Dy: " << dx << " " << dy << std::endl;
std::cout << " LabelSizerm: " << xrm << " " << yrm << std::endl;
std::cout << " LabelSizerm: " << labelWidth << " " << labelHeight << std::endl;
std::cout << " LabelSizeUn: " << mFeature->label_x << " " << mFeature->label_y << std::endl;
continue;
}
if ( mFeature->layer->arrangement() == P_HORIZ && mFeature->layer->fitInPolygonOnly() )
{
//check width/height of bbox is sufficient for label
if ( box->length < labelWidth || box->width < labelHeight )
{
//no way label can fit in this box, skip it
continue;
}
}
#ifdef _DEBUG_FULL_
std::cout << "New BBox : " << bbid << std::endl;
for ( i = 0; i < 4; i++ )
@ -1050,16 +1092,16 @@ namespace pal
if ( mFeature->layer->arrangement() == P_FREE )
{
enoughPlace = true;
px = ( box->x[0] + box->x[2] ) / 2 - xrm;
py = ( box->y[0] + box->y[2] ) / 2 - yrm;
px = ( box->x[0] + box->x[2] ) / 2 - labelWidth;
py = ( box->y[0] + box->y[2] ) / 2 - labelHeight;
int i, j;
// Virtual label: center on bbox center, label size = 2x original size
// alpha = 0.
// If all corner are in bbox then place candidates horizontaly
for ( rx = px, i = 0; i < 2; rx = rx + 2 * xrm, i++ )
for ( rx = px, i = 0; i < 2; rx = rx + 2 * labelWidth, i++ )
{
for ( ry = py, j = 0; j < 2; ry = ry + 2 * yrm, j++ )
for ( ry = py, j = 0; j < 2; ry = ry + 2 * labelHeight, j++ )
{
if ( !mapShape->containsPoint( rx, ry ) )
{
@ -1079,7 +1121,7 @@ namespace pal
{
alpha = 0.0; // HORIZ
}
else if ( box->length > 1.5*xrm && box->width > 1.5*xrm )
else if ( box->length > 1.5*labelWidth && box->width > 1.5*labelWidth )
{
if ( box->alpha <= M_PI / 4 )
{
@ -1099,7 +1141,7 @@ namespace pal
alpha = box->alpha;
}
beta = atan2( yrm, xrm ) + alpha;
beta = atan2( labelHeight, labelWidth ) + alpha;
//alpha = box->alpha;
@ -1108,7 +1150,6 @@ namespace pal
dlx = cos( beta ) * diago;
dly = sin( beta ) * diago;
double px0, py0;
px0 = box->width / 2.0;
@ -1128,11 +1169,13 @@ namespace pal
rx += box->x[0];
ry += box->y[0];
// Only accept candidate that center is in the polygon
if ( mapShape->containsPoint( rx, ry ) )
bool candidateAcceptable = ( mFeature->layer->fitInPolygonOnly()
? mapShape->containsLabelCandidate( rx - dlx, ry - dly, labelWidth, labelHeight, alpha )
: mapShape->containsPoint( rx, ry ) );
if ( candidateAcceptable )
{
// cost is set to minimal value, evaluated later
positions.append( new LabelPosition( id++, rx - dlx, ry - dly, xrm, yrm, alpha, 0.0001, this ) ); // Polygon
positions.append( new LabelPosition( id++, rx - dlx, ry - dly, labelWidth, labelHeight, alpha, 0.0001, this ) ); // Polygon
}
}
}
@ -1143,10 +1186,10 @@ namespace pal
{
dx /= 2;
dy /= 2;
num_try++;
numTry++;
}
}
while ( nbp == 0 && num_try < max_try );
while ( nbp == 0 && numTry < maxTry );
nbp = positions.size();
@ -1245,9 +1288,9 @@ namespace pal
double cx, cy;
mapShape->getCentroid( cx, cy, mFeature->layer->centroidInside() );
if ( mFeature->layer->arrangement() == P_POINT_OVER )
nbp = setPositionOverPoint( cx, cy, lPos, angle );
nbp = setPositionOverPoint( cx, cy, lPos, angle, mapShape );
else
nbp = setPositionForPoint( cx, cy, lPos, angle );
nbp = setPositionForPoint( cx, cy, lPos, angle, mapShape );
break;
case P_LINE:
nbp = setPositionForLine( lPos, mapShape );

View File

@ -189,18 +189,20 @@ namespace pal
* @param y y coordinate of the point
* @param lPos pointer to an array of candidates, will be filled by generated candidates
* @param angle orientation of the label
* @param mapShape optional geometry of source polygon
* @returns the number of generated candidates
*/
int setPositionForPoint( double x, double y, LabelPosition ***lPos, double angle );
int setPositionForPoint( double x, double y, LabelPosition ***lPos, double angle, PointSet *mapShape = 0 );
/** Generate one candidate over or offset the specified point.
* @param x x coordinate of the point
* @param y y coordinate of the point
* @param lPos pointer to an array of candidates, will be filled by generated candidate
* @param angle orientation of the label
* @param mapShape optional geometry of source polygon
* @returns the number of generated candidates (always 1)
*/
int setPositionOverPoint( double x, double y, LabelPosition ***lPos, double angle );
int setPositionOverPoint( double x, double y, LabelPosition ***lPos, double angle, PointSet *mapShape = 0 );
/** Generate candidates for line feature.
* @param lPos pointer to an array of candidates, will be filled by generated candidates

View File

@ -52,6 +52,7 @@ namespace pal
, mLabelLayer( toLabel )
, mDisplayAll( displayAll )
, mCentroidInside( false )
, mFitInPolygon( false )
, mArrangement( arrangement )
, mArrangementFlags( 0 )
, mMode( LabelPerFeature )

View File

@ -221,6 +221,21 @@ namespace pal
*/
bool centroidInside() const { return mCentroidInside; }
/** Sets whether labels which do not fit completely within a polygon feature
* are discarded.
* @param fitInPolygon set to true to discard labels which do not fit within
* polygon features. Set to false to allow labels which partially fall outside
* the polygon.
* @see fitInPolygonOnly
*/
void setFitInPolygonOnly( bool fitInPolygon ) { mFitInPolygon = fitInPolygon; }
/** Returns whether labels which do not fit completely within a polygon feature
* are discarded.
* @see setFitInPolygonOnly
*/
bool fitInPolygonOnly() const { return mFitInPolygon; }
/** Register a feature in the layer.
* @param geom_id unique identifier
* @param userGeom user's geometry that implements the PalGeometry interface
@ -277,6 +292,7 @@ namespace pal
bool mLabelLayer;
bool mDisplayAll;
bool mCentroidInside;
bool mFitInPolygon;
/** Optional flags used for some placement methods */
Arrangement mArrangement;

View File

@ -277,6 +277,46 @@ namespace pal
return result;
}
bool PointSet::containsLabelCandidate( double x, double y, double width, double height, double alpha ) const
{
GEOSContextHandle_t geosctxt = geosContext();
GEOSCoordSequence *coord = GEOSCoordSeq_create_r( geosctxt, 5, 2 );
GEOSCoordSeq_setX_r( geosctxt, coord, 0, x );
GEOSCoordSeq_setY_r( geosctxt, coord, 0, y );
if ( !qgsDoubleNear( alpha, 0.0 ) )
{
double beta = alpha + ( M_PI / 2 );
double dx1 = cos( alpha ) * width;
double dy1 = sin( alpha ) * width;
double dx2 = cos( beta ) * height;
double dy2 = sin( beta ) * height;
GEOSCoordSeq_setX_r( geosctxt, coord, 1, x + dx1 );
GEOSCoordSeq_setY_r( geosctxt, coord, 1, y + dy1 );
GEOSCoordSeq_setX_r( geosctxt, coord, 2, x + dx1 + dx2 );
GEOSCoordSeq_setY_r( geosctxt, coord, 2, y + dy1 + dy2 );
GEOSCoordSeq_setX_r( geosctxt, coord, 3, x + dx2 );
GEOSCoordSeq_setY_r( geosctxt, coord, 3, y + dy2 );
}
else
{
GEOSCoordSeq_setX_r( geosctxt, coord, 1, x + width );
GEOSCoordSeq_setY_r( geosctxt, coord, 1, y );
GEOSCoordSeq_setX_r( geosctxt, coord, 2, x + width );
GEOSCoordSeq_setY_r( geosctxt, coord, 2, y + height );
GEOSCoordSeq_setX_r( geosctxt, coord, 3, x );
GEOSCoordSeq_setY_r( geosctxt, coord, 3, y + height );
}
//close ring
GEOSCoordSeq_setX_r( geosctxt, coord, 4, x );
GEOSCoordSeq_setY_r( geosctxt, coord, 4, y );
GEOSGeometry* bboxGeos = GEOSGeom_createLinearRing_r( geosctxt, coord );
bool result = ( GEOSPreparedContains_r( geosctxt, preparedGeom(), bboxGeos ) == 1 );
GEOSGeom_destroy_r( geosctxt, bboxGeos );
return result;
}
void PointSet::splitPolygons( QLinkedList<PointSet*> &shapes_toProcess,
QLinkedList<PointSet*> &shapes_final,
double xrm, double yrm, const QString& uid )

View File

@ -80,6 +80,16 @@ namespace pal
*/
bool containsPoint( double x, double y ) const;
/** Tests whether a possible label candidate will fit completely within the shape.
* @param x x-coordinate of label candidate
* @param y y-coordinate of label candidate
* @param width label width
* @param height label height
* @param alpha label angle
* @returns true if point set completely contains candidate label
*/
bool containsLabelCandidate( double x, double y, double width, double height, double alpha = 0 ) const;
CHullBox * compute_chull_bbox();
/** Split a concave shape into several convex shapes.

View File

@ -169,6 +169,7 @@ QgsPalLayerSettings::QgsPalLayerSettings()
placementFlags = AboveLine | MapOrientation;
centroidWhole = false;
centroidInside = false;
fitInPolygonOnly = false;
quadOffset = QuadrantOver;
xOffset = 0;
yOffset = 0;
@ -379,6 +380,7 @@ QgsPalLayerSettings::QgsPalLayerSettings( const QgsPalLayerSettings& s )
placementFlags = s.placementFlags;
centroidWhole = s.centroidWhole;
centroidInside = s.centroidInside;
fitInPolygonOnly = s.fitInPolygonOnly;
quadOffset = s.quadOffset;
xOffset = s.xOffset;
yOffset = s.yOffset;
@ -863,6 +865,7 @@ void QgsPalLayerSettings::readFromLayer( QgsVectorLayer* layer )
placementFlags = layer->customProperty( "labeling/placementFlags" ).toUInt();
centroidWhole = layer->customProperty( "labeling/centroidWhole", QVariant( false ) ).toBool();
centroidInside = layer->customProperty( "labeling/centroidInside", QVariant( false ) ).toBool();
fitInPolygonOnly = layer->customProperty( "labeling/fitInPolygonOnly", QVariant( false ) ).toBool();
dist = layer->customProperty( "labeling/dist" ).toDouble();
distInMapUnits = layer->customProperty( "labeling/distInMapUnits" ).toBool();
distMapUnitScale.minScale = layer->customProperty( "labeling/distMapUnitMinScale", 0.0 ).toDouble();
@ -1036,6 +1039,7 @@ void QgsPalLayerSettings::writeToLayer( QgsVectorLayer* layer )
layer->setCustomProperty( "labeling/placementFlags", ( unsigned int )placementFlags );
layer->setCustomProperty( "labeling/centroidWhole", centroidWhole );
layer->setCustomProperty( "labeling/centroidInside", centroidInside );
layer->setCustomProperty( "labeling/fitInPolygonOnly", fitInPolygonOnly );
layer->setCustomProperty( "labeling/dist", dist );
layer->setCustomProperty( "labeling/distInMapUnits", distInMapUnits );
layer->setCustomProperty( "labeling/distMapUnitMinScale", distMapUnitScale.minScale );
@ -3332,6 +3336,9 @@ int QgsPalLabeling::prepareLayer( QgsVectorLayer* layer, QStringList& attrNames,
// set whether location of centroid must be inside of polygons
l->setCentroidInside( lyr.centroidInside );
// set whether labels must fall completely within the polygon
l->setFitInPolygonOnly( lyr.fitInPolygonOnly );
// set how to show upside-down labels
Layer::UpsideDownLabels upsdnlabels;
switch ( lyr.upsidedownLabels )

View File

@ -393,6 +393,10 @@ class CORE_EXPORT QgsPalLayerSettings
bool centroidWhole; // whether centroid calculated from whole or visible polygon
bool centroidInside; // whether centroid-point calculated must be inside polygon
/** True if only labels which completely fit within a polygon are allowed.
*/
bool fitInPolygonOnly;
double dist; // distance from the feature (in mm)
bool distInMapUnits; //true if distance is in map units (otherwise in mm)
QgsMapUnitScale distMapUnitScale;

View File

@ -524,7 +524,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>578</width>
<width>341</width>
<height>388</height>
</rect>
</property>
@ -4818,9 +4818,9 @@ font-style: italic;</string>
<property name="geometry">
<rect>
<x>0</x>
<y>-292</y>
<y>-298</y>
<width>578</width>
<height>655</height>
<height>683</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_8">
@ -5439,6 +5439,28 @@ font-style: italic;</string>
</layout>
</widget>
</item>
<item>
<widget class="QFrame" name="mPolygonFeatureOptionsFrame">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_12">
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QCheckBox" name="mFitInsidePolygonCheckBox">
<property name="text">
<string>Only draw labels which fit completely within feature</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QCheckBox" name="mChkNoObstacle">
<property name="enabled">