Branch data Line data Source code
1 : : /*
2 : : * libpal - Automated Placement of Labels Library
3 : : *
4 : : * Copyright (C) 2008 Maxence Laurent, MIS-TIC, HEIG-VD
5 : : * University of Applied Sciences, Western Switzerland
6 : : * http://www.hes-so.ch
7 : : *
8 : : * Contact:
9 : : * maxence.laurent <at> heig-vd <dot> ch
10 : : * or
11 : : * eric.taillard <at> heig-vd <dot> ch
12 : : *
13 : : * This file is part of libpal.
14 : : *
15 : : * libpal is free software: you can redistribute it and/or modify
16 : : * it under the terms of the GNU General Public License as published by
17 : : * the Free Software Foundation, either version 3 of the License, or
18 : : * (at your option) any later version.
19 : : *
20 : : * libpal is distributed in the hope that it will be useful,
21 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 : : * GNU General Public License for more details.
24 : : *
25 : : * You should have received a copy of the GNU General Public License
26 : : * along with libpal. If not, see <http://www.gnu.org/licenses/>.
27 : : *
28 : : */
29 : :
30 : : #ifndef FEATURE_H
31 : : #define FEATURE_H
32 : :
33 : : #define SIP_NO_FILE
34 : :
35 : :
36 : : #include "qgis_core.h"
37 : : #include "pointset.h"
38 : : #include "labelposition.h" // for LabelPosition enum
39 : : #include "qgslabelfeature.h"
40 : : #include "qgstextrendererutils.h"
41 : : #include <iostream>
42 : : #include <fstream>
43 : : #include <cmath>
44 : : #include <QString>
45 : :
46 : : /**
47 : : * \ingroup core
48 : : * \brief pal labeling engine
49 : : * \class pal::LabelInfo
50 : : * \note not available in Python bindings
51 : : */
52 : :
53 : : namespace pal
54 : : {
55 : : class LabelPosition;
56 : : class FeaturePart;
57 : :
58 : : /**
59 : : * \ingroup core
60 : : * \brief Main class to handle feature
61 : : * \class pal::FeaturePart
62 : : * \note not available in Python bindings
63 : : */
64 : : class CORE_EXPORT FeaturePart : public PointSet
65 : : {
66 : :
67 : : public:
68 : :
69 : : /**
70 : : * Creates a new generic feature.
71 : : * \param lf a pointer for a feature which contains the spatial entites
72 : : * \param geom a pointer to a GEOS geometry
73 : : */
74 : : FeaturePart( QgsLabelFeature *lf, const GEOSGeometry *geom );
75 : :
76 : : FeaturePart( const FeaturePart &other );
77 : :
78 : : /**
79 : : * Delete the feature
80 : : */
81 : : ~FeaturePart() override;
82 : :
83 : : /**
84 : : * Returns the parent feature.
85 : : */
86 : 0 : QgsLabelFeature *feature() { return mLF; }
87 : :
88 : : /**
89 : : * Returns the layer that feature belongs to.
90 : : */
91 : : Layer *layer();
92 : :
93 : : /**
94 : : * Returns the unique ID of the feature.
95 : : */
96 : : QgsFeatureId featureId() const;
97 : :
98 : : /**
99 : : * Returns the maximum number of point candidates to generate for this feature.
100 : : */
101 : : std::size_t maximumPointCandidates() const;
102 : :
103 : : /**
104 : : * Returns the maximum number of line candidates to generate for this feature.
105 : : */
106 : : std::size_t maximumLineCandidates() const;
107 : :
108 : : /**
109 : : * Returns the maximum number of polygon candidates to generate for this feature.
110 : : */
111 : : std::size_t maximumPolygonCandidates() const;
112 : :
113 : : /**
114 : : * Generates a list of candidate positions for labels for this feature.
115 : : */
116 : : std::vector<std::unique_ptr<LabelPosition> > createCandidates( Pal *pal );
117 : :
118 : : /**
119 : : * Generate candidates for point feature, located around a specified point.
120 : : * \param x x coordinate of the point
121 : : * \param y y coordinate of the point
122 : : * \param lPos pointer to an array of candidates, will be filled by generated candidates
123 : : * \param angle orientation of the label
124 : : * \returns the number of generated candidates
125 : : */
126 : : std::size_t createCandidatesAroundPoint( double x, double y, std::vector<std::unique_ptr<LabelPosition> > &lPos, double angle );
127 : :
128 : : /**
129 : : * Generate one candidate over or offset the specified point.
130 : : * \param x x coordinate of the point
131 : : * \param y y coordinate of the point
132 : : * \param lPos pointer to an array of candidates, will be filled by generated candidate
133 : : * \param angle orientation of the label
134 : : * \returns the number of generated candidates (always 1)
135 : : */
136 : : std::size_t createCandidatesOverPoint( double x, double y, std::vector<std::unique_ptr<LabelPosition> > &lPos, double angle );
137 : :
138 : : /**
139 : : * Generate one candidate centered over the specified point.
140 : : * \param x x coordinate of the point
141 : : * \param y y coordinate of the point
142 : : * \param lPos pointer to an array of candidates, will be filled by generated candidate
143 : : * \param angle orientation of the label
144 : : * \returns the number of generated candidates (always 1)
145 : : */
146 : : std::size_t createCandidateCenteredOverPoint( double x, double y, std::vector<std::unique_ptr<LabelPosition> > &lPos, double angle );
147 : :
148 : : /**
149 : : * Creates a single candidate using the "point on sruface" algorithm.
150 : : *
151 : : * \note Unlike the other create candidates methods, this method
152 : : * bypasses the usual candidate filtering steps and ALWAYS returns a single candidate.
153 : : */
154 : : std::unique_ptr< LabelPosition > createCandidatePointOnSurface( PointSet *mapShape );
155 : :
156 : : /**
157 : : * Generates candidates following a prioritized list of predefined positions around a point.
158 : : * \param x x coordinate of the point
159 : : * \param y y coordinate of the point
160 : : * \param lPos pointer to an array of candidates, will be filled by generated candidate
161 : : * \param angle orientation of the label
162 : : * \returns the number of generated candidates
163 : : */
164 : : std::size_t createCandidatesAtOrderedPositionsOverPoint( double x, double y, std::vector<std::unique_ptr<LabelPosition> > &lPos, double angle );
165 : :
166 : : /**
167 : : * Generate candidates for line feature.
168 : : * \param lPos pointer to an array of candidates, will be filled by generated candidates
169 : : * \param mapShape a pointer to the line
170 : : * \param allowOverrun set to TRUE to allow labels to overrun features
171 : : * \param pal point to pal settings object, for cancellation support
172 : : * \returns the number of generated candidates
173 : : */
174 : : std::size_t createCandidatesAlongLine( std::vector<std::unique_ptr<LabelPosition> > &lPos, PointSet *mapShape, bool allowOverrun, Pal *pal );
175 : :
176 : : /**
177 : : * Generate horizontal candidates for line feature.
178 : : * \param lPos pointer to an array of candidates, will be filled by generated candidates
179 : : * \param mapShape a pointer to the line
180 : : * \param pal point to pal settings object, for cancellation support
181 : : * \returns the number of generated candidates
182 : : */
183 : : std::size_t createHorizontalCandidatesAlongLine( std::vector<std::unique_ptr<LabelPosition> > &lPos, PointSet *mapShape, Pal *pal );
184 : :
185 : : /**
186 : : * Generate candidates for line feature, by trying to place candidates towards the middle of the longest
187 : : * straightish segments of the line. Segments closer to horizontal are preferred over vertical segments.
188 : : * \param lPos pointer to an array of candidates, will be filled by generated candidates
189 : : * \param mapShape a pointer to the line
190 : : * \param pal point to pal settings object, for cancellation support
191 : : * \returns the number of generated candidates
192 : : */
193 : : std::size_t createCandidatesAlongLineNearStraightSegments( std::vector<std::unique_ptr<LabelPosition> > &lPos, PointSet *mapShape, Pal *pal );
194 : :
195 : : /**
196 : : * Generate candidates for line feature, by trying to place candidates as close as possible to the line's midpoint.
197 : : * Candidates can "cut corners" if it helps them place near this mid point.
198 : : * \param lPos pointer to an array of candidates, will be filled by generated candidates
199 : : * \param mapShape a pointer to the line
200 : : * \param initialCost initial cost for candidates generated using this method. If set, cost can be increased
201 : : * by a preset amount.
202 : : * \param pal point to pal settings object, for cancellation support
203 : : * \returns the number of generated candidates
204 : : */
205 : : std::size_t createCandidatesAlongLineNearMidpoint( std::vector<std::unique_ptr<LabelPosition> > &lPos, PointSet *mapShape, double initialCost = 0.0, Pal *pal = nullptr );
206 : :
207 : : /**
208 : : * Returns the label position for a curved label at a specific offset along a path.
209 : : * \param mapShape line path to place label on
210 : : * \param pathDistances array of distances to each segment on path
211 : : * \param direction either RespectPainterOrientation or FollowLineDirection
212 : : * \param distance distance to offset label along curve by
213 : : * \param labeledLineSegmentIsRightToLeft if TRUE label is reversed from lefttoright to righttoleft
214 : : * \param applyAngleConstraints TRUE if label feature character angle constraints should be applied
215 : : * \returns calculated label position
216 : : */
217 : : std::unique_ptr< LabelPosition > curvedPlacementAtOffset( PointSet *mapShape, const std::vector<double> &pathDistances,
218 : : QgsTextRendererUtils::LabelLineDirection direction, double distance, bool &labeledLineSegmentIsRightToLeft, bool applyAngleConstraints );
219 : :
220 : : /**
221 : : * Generate curved candidates for line features.
222 : : * \param lPos pointer to an array of candidates, will be filled by generated candidates
223 : : * \param mapShape a pointer to the line
224 : : * \param allowOverrun set to TRUE to allow labels to overrun features
225 : : * \param pal point to pal settings object, for cancellation support
226 : : * \returns the number of generated candidates
227 : : */
228 : : std::size_t createCurvedCandidatesAlongLine( std::vector<std::unique_ptr<LabelPosition> > &lPos, PointSet *mapShape, bool allowOverrun, Pal *pal );
229 : :
230 : : /**
231 : : * Generate candidates for polygon features.
232 : : * \param lPos pointer to an array of candidates, will be filled by generated candidates
233 : : * \param mapShape a pointer to the polygon
234 : : * \param pal point to pal settings object, for cancellation support
235 : : * \returns the number of generated candidates
236 : : */
237 : : std::size_t createCandidatesForPolygon( std::vector<std::unique_ptr<LabelPosition> > &lPos, PointSet *mapShape, Pal *pal );
238 : :
239 : : /**
240 : : * Generate candidates outside of polygon features.
241 : : * \param lPos pointer to an array of candidates, will be filled by generated candidates
242 : : * \param pal point to pal settings object, for cancellation support
243 : : * \returns the number of generated candidates
244 : : */
245 : : std::size_t createCandidatesOutsidePolygon( std::vector<std::unique_ptr<LabelPosition> > &lPos, Pal *pal );
246 : :
247 : : /**
248 : : * Tests whether this feature part belongs to the same QgsLabelFeature as another
249 : : * feature part.
250 : : * \param part part to compare to
251 : : * \returns TRUE if both parts belong to same QgsLabelFeature
252 : : */
253 : : bool hasSameLabelFeatureAs( FeaturePart *part ) const;
254 : :
255 : : /**
256 : : * Returns the width of the label, optionally taking an \a angle into account.
257 : : * \returns the width of the label
258 : : */
259 : 0 : double getLabelWidth( double angle = 0.0 ) const { return mLF->size( angle ).width(); }
260 : :
261 : : /**
262 : : * Returns the height of the label, optionally taking an \a angle into account.
263 : : * \returns the hieght of the label
264 : : */
265 : 0 : double getLabelHeight( double angle = 0.0 ) const { return mLF->size( angle ).height(); }
266 : :
267 : : /**
268 : : * Returns the distance from the anchor point to the label
269 : : * \returns the distance to the label
270 : : */
271 : 0 : double getLabelDistance() const { return mLF->distLabel(); }
272 : :
273 : : //! Returns TRUE if the feature's label has a fixed rotation
274 : 0 : bool hasFixedRotation() const { return mLF->hasFixedAngle(); }
275 : :
276 : : //! Returns the fixed angle for the feature's label
277 : 0 : double fixedAngle() const { return mLF->fixedAngle(); }
278 : :
279 : : //! Returns TRUE if the feature's label has a fixed position
280 : 0 : bool hasFixedPosition() const { return mLF->hasFixedPosition(); }
281 : :
282 : : /**
283 : : * Returns TRUE if the feature's label should always been shown,
284 : : * even when it collides with other labels
285 : : */
286 : 0 : bool alwaysShow() const { return mLF->alwaysShow(); }
287 : :
288 : : /**
289 : : * Returns the feature's obstacle settings.
290 : : */
291 : 0 : const QgsLabelObstacleSettings &obstacleSettings() const { return mLF->obstacleSettings(); }
292 : :
293 : : //! Returns the distance between repeating labels for this feature
294 : 0 : double repeatDistance() const { return mLF->repeatDistance(); }
295 : :
296 : : //! Gets number of holes (inner rings) - they are considered as obstacles
297 : 0 : int getNumSelfObstacles() const { return mHoles.count(); }
298 : : //! Gets hole (inner ring) - considered as obstacle
299 : 0 : FeaturePart *getSelfObstacle( int i ) { return mHoles.at( i ); }
300 : :
301 : : //! Check whether this part is connected with some other part
302 : : bool isConnected( FeaturePart *p2 );
303 : :
304 : : /**
305 : : * Merge other (connected) part with this one and save the result in this part (other is unchanged).
306 : : * Returns TRUE on success, FALSE if the feature wasn't modified.
307 : : */
308 : : bool mergeWithFeaturePart( FeaturePart *other );
309 : :
310 : : /**
311 : : * Increases the cost of the label candidates for this feature, based on the size of the feature.
312 : : *
313 : : * E.g. small lines or polygons get higher cost so that larger features are more likely to be labeled.
314 : : */
315 : : void addSizePenalty( std::vector<std::unique_ptr<LabelPosition> > &lPos, double bbx[4], double bby[4] );
316 : :
317 : : /**
318 : : * Calculates the priority for the feature. This will be the feature's priority if set,
319 : : * otherwise the layer's default priority.
320 : : */
321 : : double calculatePriority() const;
322 : :
323 : : //! Returns TRUE if feature's label must be displayed upright
324 : : bool onlyShowUprightLabels() const;
325 : :
326 : : /**
327 : : * Returns the total number of repeating labels associated with this label.
328 : : * \see setTotalRepeats()
329 : : */
330 : : int totalRepeats() const;
331 : :
332 : : /**
333 : : * Returns the total number of repeating labels associated with this label.
334 : : * \see totalRepeats()
335 : : */
336 : : void setTotalRepeats( int repeats );
337 : :
338 : : protected:
339 : :
340 : : QgsLabelFeature *mLF = nullptr;
341 : : QList<FeaturePart *> mHoles;
342 : :
343 : : //! \brief read coordinates from a GEOS geom
344 : : void extractCoords( const GEOSGeometry *geom );
345 : :
346 : : private:
347 : :
348 : : LabelPosition::Quadrant quadrantFromOffset() const;
349 : :
350 : : int mTotalRepeats = 0;
351 : :
352 : : mutable std::size_t mCachedMaxLineCandidates = 0;
353 : : mutable std::size_t mCachedMaxPolygonCandidates = 0;
354 : :
355 : : FeaturePart &operator= ( const FeaturePart & ) = delete;
356 : : };
357 : :
358 : : } // end namespace pal
359 : :
360 : : #endif
|