6 changes: 4 additions & 2 deletions src/core/pal/feature.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions src/core/pal/layer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ namespace pal
, mLabelLayer( toLabel )
, mDisplayAll( displayAll )
, mCentroidInside( false )
, mFitInPolygon( false )
, mArrangement( arrangement )
, mArrangementFlags( 0 )
, mMode( LabelPerFeature )
Expand Down
16 changes: 16 additions & 0 deletions src/core/pal/layer.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -277,6 +292,7 @@ namespace pal
bool mLabelLayer;
bool mDisplayAll;
bool mCentroidInside;
bool mFitInPolygon;

/** Optional flags used for some placement methods */
Arrangement mArrangement;
Expand Down
40 changes: 40 additions & 0 deletions src/core/pal/pointset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 )
Expand Down
10 changes: 10 additions & 0 deletions src/core/pal/pointset.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
7 changes: 7 additions & 0 deletions src/core/qgspallabeling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ QgsPalLayerSettings::QgsPalLayerSettings()
placementFlags = AboveLine | MapOrientation;
centroidWhole = false;
centroidInside = false;
fitInPolygonOnly = false;
quadOffset = QuadrantOver;
xOffset = 0;
yOffset = 0;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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 );
Expand Down Expand Up @@ -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 )
Expand Down
4 changes: 4 additions & 0 deletions src/core/qgspallabeling.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
28 changes: 25 additions & 3 deletions src/ui/qgslabelingguibase.ui
Original file line number Diff line number Diff line change
Expand Up @@ -524,7 +524,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>578</width>
<width>341</width>
<height>388</height>
</rect>
</property>
Expand Down Expand Up @@ -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">
Expand Down Expand Up @@ -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">
Expand Down