diff --git a/python/core/qgspallabeling.sip b/python/core/qgspallabeling.sip index 1c7b6a093e1f..b230361d8e3d 100644 --- a/python/core/qgspallabeling.sip +++ b/python/core/qgspallabeling.sip @@ -100,7 +100,25 @@ class QgsPalLayerSettings Line, /**< Arranges candidates parallel to a generalised line representing the feature or parallel to a polygon's perimeter. Applies to line or polygon layers only. */ Curved, /** Arranges candidates following the curvature of a line feature. Applies to line layers only.*/ Horizontal, /**< Arranges horizontal candidates scattered throughout a polygon feature. Applies to polygon layers only.*/ - Free /**< Arranges candidates scattered throughout a polygon feature. Candidates are rotated to respect the polygon's orientation. Applies to polygon layers only.*/ + Free, /**< Arranges candidates scattered throughout a polygon feature. Candidates are rotated to respect the polygon's orientation. Applies to polygon layers only.*/ + OrderedPositionsAroundPoint, /**< Candidates are placed in predefined positions around a point. Peference is given to positions with greatest cartographic appeal, eg top right, bottom right, etc. Applies to point layers only.*/ + }; + + //! Positions for labels when using the QgsPalLabeling::OrderedPositionsAroundPoint placement mode + enum PredefinedPointPosition + { + TopLeft, //!< Label on top-left of point + TopSlightlyLeft, //! Label on top of point, slightly left of center + TopMiddle, //!< Label directly above point + TopSlightlyRight, //! Label on top of point, slightly right of center + TopRight, //!< Label on top-right of point + MiddleLeft, //!< Label on left of point + MiddleRight, //!< Label on right of point + BottomLeft, //!< Label on bottom-left of point + BottomSlightlyLeft, //! Label below point, slightly left of center + BottomMiddle, //!< Label directly below point + BottomSlightlyRight, //! Label below point, slightly right of center + BottomRight, //!< Label on bottom right of point }; /** Line placement flags, which control how candidates are generated for a linear feature. @@ -304,6 +322,7 @@ class QgsPalLayerSettings RepeatDistance, RepeatDistanceUnit, Priority, + PredefinedPositionOrder, // rendering ScaleVisibility, @@ -437,6 +456,12 @@ class QgsPalLayerSettings bool centroidWhole; // whether centroid calculated from whole or visible polygon bool centroidInside; // whether centroid-point calculated must be inside polygon + /** Ordered list of predefined label positions for points. Positions earlier + * in the list will be prioritised over later positions. Only used when the placement + * is set to QgsPalLayerSettings::OrderedPositionsAroundPoint. + */ + QVector< QgsPalLayerSettings::PredefinedPointPosition > predefinedPositionOrder; + /** True if only labels which completely fit within a polygon are allowed. */ bool fitInPolygonOnly; diff --git a/src/core/pal/feature.h b/src/core/pal/feature.h index e84147fc6916..b7db33afe376 100644 --- a/src/core/pal/feature.h +++ b/src/core/pal/feature.h @@ -147,7 +147,6 @@ namespace pal * @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 */ int createCandidatesAtOrderedPositionsOverPoint( double x, double y, QList &lPos, double angle ); diff --git a/tests/src/python/test_qgspallabeling_placement.py b/tests/src/python/test_qgspallabeling_placement.py index a114abfe8eab..82005c61483b 100644 --- a/tests/src/python/test_qgspallabeling_placement.py +++ b/tests/src/python/test_qgspallabeling_placement.py @@ -185,6 +185,78 @@ def test_multipolygon_obstacle(self): self.removeMapLayer(polyLayer) self.layer = None + def test_point_ordered_placement1(self): + # Test ordered placements for point + self.layer = TestQgsPalLabeling.loadFeatureLayer('point_ordered_placement') + self._TestMapSettings = self.cloneMapSettings(self._MapSettings) + self.lyr.placement = QgsPalLayerSettings.OrderedPositionsAroundPoint + self.lyr.dist = 2 + self.checkTest() + self.removeMapLayer(self.layer) + self.layer = None + + def test_point_ordered_placement2(self): + # Test ordered placements for point (1 obstacle) + self.layer = TestQgsPalLabeling.loadFeatureLayer('point_ordered_placement') + obstacleLayer = TestQgsPalLabeling.loadFeatureLayer('point_ordered_obstacle1') + self._TestMapSettings = self.cloneMapSettings(self._MapSettings) + self.lyr.placement = QgsPalLayerSettings.OrderedPositionsAroundPoint + self.lyr.dist = 2 + self.checkTest() + self.removeMapLayer(obstacleLayer) + self.removeMapLayer(self.layer) + self.layer = None + + def test_point_ordered_placement3(self): + # Test ordered placements for point (2 obstacle) + self.layer = TestQgsPalLabeling.loadFeatureLayer('point_ordered_placement') + obstacleLayer = TestQgsPalLabeling.loadFeatureLayer('point_ordered_obstacle2') + self._TestMapSettings = self.cloneMapSettings(self._MapSettings) + self.lyr.placement = QgsPalLayerSettings.OrderedPositionsAroundPoint + self.lyr.dist = 2 + self.checkTest() + self.removeMapLayer(obstacleLayer) + self.removeMapLayer(self.layer) + self.layer = None + + def test_point_ordered_placement4(self): + # Test ordered placements for point (3 obstacle) + self.layer = TestQgsPalLabeling.loadFeatureLayer('point_ordered_placement') + obstacleLayer = TestQgsPalLabeling.loadFeatureLayer('point_ordered_obstacle3') + self._TestMapSettings = self.cloneMapSettings(self._MapSettings) + self.lyr.placement = QgsPalLayerSettings.OrderedPositionsAroundPoint + self.lyr.dist = 2 + self.checkTest() + self.removeMapLayer(obstacleLayer) + self.removeMapLayer(self.layer) + self.layer = None + + def test_point_dd_ordered_placement(self): + # Test ordered placements for point with data defined order + self.layer = TestQgsPalLabeling.loadFeatureLayer('point_ordered_placement') + self._TestMapSettings = self.cloneMapSettings(self._MapSettings) + self.lyr.placement = QgsPalLayerSettings.OrderedPositionsAroundPoint + self.lyr.dist = 2 + self.lyr.setDataDefinedProperty(QgsPalLayerSettings.PredefinedPositionOrder, True, True, "'T,B'", None) + self.checkTest() + self.removeMapLayer(self.layer) + self.lyr.removeDataDefinedProperty(QgsPalLayerSettings.PredefinedPositionOrder) + self.layer = None + + def test_point_dd_ordered_placement1(self): + # Test ordered placements for point with data defined order and obstacle + self.layer = TestQgsPalLabeling.loadFeatureLayer('point_ordered_placement') + obstacleLayer = TestQgsPalLabeling.loadFeatureLayer('point_ordered_obstacle_top') + self._TestMapSettings = self.cloneMapSettings(self._MapSettings) + self.lyr.placement = QgsPalLayerSettings.OrderedPositionsAroundPoint + self.lyr.dist = 2 + self.lyr.setDataDefinedProperty(QgsPalLayerSettings.PredefinedPositionOrder, True, True, "'T,B'", None) + self.checkTest() + self.removeMapLayer(obstacleLayer) + self.removeMapLayer(self.layer) + self.lyr.removeDataDefinedProperty(QgsPalLayerSettings.PredefinedPositionOrder) + self.layer = None + if __name__ == '__main__': # NOTE: unless PAL_SUITE env var is set all test class methods will be run # SEE: test_qgspallabeling_tests.suiteTests() to define suite diff --git a/tests/testdata/control_images/expected_pal_placement/sp_point_dd_ordered_placement/sp_point_dd_ordered_placement.png b/tests/testdata/control_images/expected_pal_placement/sp_point_dd_ordered_placement/sp_point_dd_ordered_placement.png new file mode 100644 index 000000000000..f2b0f3fb855d Binary files /dev/null and b/tests/testdata/control_images/expected_pal_placement/sp_point_dd_ordered_placement/sp_point_dd_ordered_placement.png differ diff --git a/tests/testdata/control_images/expected_pal_placement/sp_point_dd_ordered_placement/sp_point_dd_ordered_placement_mask.png b/tests/testdata/control_images/expected_pal_placement/sp_point_dd_ordered_placement/sp_point_dd_ordered_placement_mask.png new file mode 100644 index 000000000000..36c796b357bf Binary files /dev/null and b/tests/testdata/control_images/expected_pal_placement/sp_point_dd_ordered_placement/sp_point_dd_ordered_placement_mask.png differ diff --git a/tests/testdata/control_images/expected_pal_placement/sp_point_dd_ordered_placement1/sp_point_dd_ordered_placement1.png b/tests/testdata/control_images/expected_pal_placement/sp_point_dd_ordered_placement1/sp_point_dd_ordered_placement1.png new file mode 100644 index 000000000000..d6eae8a07a04 Binary files /dev/null and b/tests/testdata/control_images/expected_pal_placement/sp_point_dd_ordered_placement1/sp_point_dd_ordered_placement1.png differ diff --git a/tests/testdata/control_images/expected_pal_placement/sp_point_dd_ordered_placement1/sp_point_dd_ordered_placement1_mask.png b/tests/testdata/control_images/expected_pal_placement/sp_point_dd_ordered_placement1/sp_point_dd_ordered_placement1_mask.png new file mode 100644 index 000000000000..1839d8962e06 Binary files /dev/null and b/tests/testdata/control_images/expected_pal_placement/sp_point_dd_ordered_placement1/sp_point_dd_ordered_placement1_mask.png differ diff --git a/tests/testdata/control_images/expected_pal_placement/sp_point_ordered_placement1/sp_point_ordered_placement1.png b/tests/testdata/control_images/expected_pal_placement/sp_point_ordered_placement1/sp_point_ordered_placement1.png new file mode 100644 index 000000000000..1ae9e0f15f04 Binary files /dev/null and b/tests/testdata/control_images/expected_pal_placement/sp_point_ordered_placement1/sp_point_ordered_placement1.png differ diff --git a/tests/testdata/control_images/expected_pal_placement/sp_point_ordered_placement1/sp_point_ordered_placement1_mask.png b/tests/testdata/control_images/expected_pal_placement/sp_point_ordered_placement1/sp_point_ordered_placement1_mask.png new file mode 100644 index 000000000000..b2c56971fbdb Binary files /dev/null and b/tests/testdata/control_images/expected_pal_placement/sp_point_ordered_placement1/sp_point_ordered_placement1_mask.png differ diff --git a/tests/testdata/control_images/expected_pal_placement/sp_point_ordered_placement2/sp_point_ordered_placement2.png b/tests/testdata/control_images/expected_pal_placement/sp_point_ordered_placement2/sp_point_ordered_placement2.png new file mode 100644 index 000000000000..662fc2fb5ddc Binary files /dev/null and b/tests/testdata/control_images/expected_pal_placement/sp_point_ordered_placement2/sp_point_ordered_placement2.png differ diff --git a/tests/testdata/control_images/expected_pal_placement/sp_point_ordered_placement2/sp_point_ordered_placement2_mask.png b/tests/testdata/control_images/expected_pal_placement/sp_point_ordered_placement2/sp_point_ordered_placement2_mask.png new file mode 100644 index 000000000000..2049ffffe00b Binary files /dev/null and b/tests/testdata/control_images/expected_pal_placement/sp_point_ordered_placement2/sp_point_ordered_placement2_mask.png differ diff --git a/tests/testdata/control_images/expected_pal_placement/sp_point_ordered_placement3/sp_point_ordered_placement3.png b/tests/testdata/control_images/expected_pal_placement/sp_point_ordered_placement3/sp_point_ordered_placement3.png new file mode 100644 index 000000000000..216144746d38 Binary files /dev/null and b/tests/testdata/control_images/expected_pal_placement/sp_point_ordered_placement3/sp_point_ordered_placement3.png differ diff --git a/tests/testdata/control_images/expected_pal_placement/sp_point_ordered_placement3/sp_point_ordered_placement3_mask.png b/tests/testdata/control_images/expected_pal_placement/sp_point_ordered_placement3/sp_point_ordered_placement3_mask.png new file mode 100644 index 000000000000..bce256d4facf Binary files /dev/null and b/tests/testdata/control_images/expected_pal_placement/sp_point_ordered_placement3/sp_point_ordered_placement3_mask.png differ diff --git a/tests/testdata/control_images/expected_pal_placement/sp_point_ordered_placement4/sp_point_ordered_placement4.png b/tests/testdata/control_images/expected_pal_placement/sp_point_ordered_placement4/sp_point_ordered_placement4.png new file mode 100644 index 000000000000..515128e18a47 Binary files /dev/null and b/tests/testdata/control_images/expected_pal_placement/sp_point_ordered_placement4/sp_point_ordered_placement4.png differ diff --git a/tests/testdata/control_images/expected_pal_placement/sp_point_ordered_placement4/sp_point_ordered_placement4_mask.png b/tests/testdata/control_images/expected_pal_placement/sp_point_ordered_placement4/sp_point_ordered_placement4_mask.png new file mode 100644 index 000000000000..fce37f2a3c4d Binary files /dev/null and b/tests/testdata/control_images/expected_pal_placement/sp_point_ordered_placement4/sp_point_ordered_placement4_mask.png differ diff --git a/tests/testdata/labeling/pal_features_v3.sqlite b/tests/testdata/labeling/pal_features_v3.sqlite index eae71b2a82e9..bf55ef588518 100644 Binary files a/tests/testdata/labeling/pal_features_v3.sqlite and b/tests/testdata/labeling/pal_features_v3.sqlite differ diff --git a/tests/testdata/labeling/point_ordered_obstacle1.qml b/tests/testdata/labeling/point_ordered_obstacle1.qml new file mode 100644 index 000000000000..7310a3b7cb52 --- /dev/null +++ b/tests/testdata/labeling/point_ordered_obstacle1.qml @@ -0,0 +1,252 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 0 + 0 + pkuid + + + + + + + + + + + + + + + + 0 + + + 0 + generatedlayout + + + + + + diff --git a/tests/testdata/labeling/point_ordered_obstacle2.qml b/tests/testdata/labeling/point_ordered_obstacle2.qml new file mode 100644 index 000000000000..7310a3b7cb52 --- /dev/null +++ b/tests/testdata/labeling/point_ordered_obstacle2.qml @@ -0,0 +1,252 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 0 + 0 + pkuid + + + + + + + + + + + + + + + + 0 + + + 0 + generatedlayout + + + + + + diff --git a/tests/testdata/labeling/point_ordered_obstacle3.qml b/tests/testdata/labeling/point_ordered_obstacle3.qml new file mode 100644 index 000000000000..b673be303c72 --- /dev/null +++ b/tests/testdata/labeling/point_ordered_obstacle3.qml @@ -0,0 +1,252 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 0 + 0 + pkuid + + + + + + + + + + + + + + + + 0 + + + 0 + generatedlayout + + + + + + diff --git a/tests/testdata/labeling/point_ordered_obstacle_top.qml b/tests/testdata/labeling/point_ordered_obstacle_top.qml new file mode 100644 index 000000000000..59248aea60ab --- /dev/null +++ b/tests/testdata/labeling/point_ordered_obstacle_top.qml @@ -0,0 +1,252 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 0 + 0 + pkuid + + + + + + + + + + + + + + + + 0 + + + 0 + generatedlayout + + + + + + diff --git a/tests/testdata/labeling/point_ordered_placement.qml b/tests/testdata/labeling/point_ordered_placement.qml new file mode 100644 index 000000000000..a8095ebc94bc --- /dev/null +++ b/tests/testdata/labeling/point_ordered_placement.qml @@ -0,0 +1,254 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 0 + 0 + pkuid + + + + + + + + + + + + + + + + 0 + + + 0 + generatedlayout + + + + + +