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 <iostream>
41 : : #include <fstream>
42 : : #include <cmath>
43 : : #include <QString>
44 : :
45 : : /**
46 : : * \ingroup core
47 : : * \brief pal labeling engine
48 : : * \class pal::LabelInfo
49 : : * \note not available in Python bindings
50 : : */
51 : :
52 : : namespace pal
53 : : {
54 : : //! Optional additional info about label (for curved labels)
55 : : class CORE_EXPORT LabelInfo
56 : : {
57 : : public:
58 : : struct CharacterInfo
59 : : {
60 : : double width;
61 : : };
62 : :
63 : 0 : LabelInfo( int num, double height, double maxinangle = 20.0, double maxoutangle = -20.0 )
64 : : {
65 : 0 : max_char_angle_inside = maxinangle;
66 : : // outside angle should be negative
67 : 0 : max_char_angle_outside = maxoutangle > 0 ? -maxoutangle : maxoutangle;
68 : 0 : label_height = height;
69 : 0 : char_num = num;
70 : 0 : char_info = new CharacterInfo[num];
71 : 0 : }
72 : 0 : ~LabelInfo() { delete [] char_info; }
73 : :
74 : : //! LabelInfo cannot be copied
75 : : LabelInfo( const LabelInfo &rh ) = delete;
76 : : //! LabelInfo cannot be copied
77 : : LabelInfo &operator=( const LabelInfo &rh ) = delete;
78 : :
79 : : double max_char_angle_inside;
80 : : double max_char_angle_outside;
81 : : double label_height;
82 : : int char_num;
83 : 0 : CharacterInfo *char_info = nullptr;
84 : :
85 : : };
86 : :
87 : : class LabelPosition;
88 : : class FeaturePart;
89 : :
90 : : /**
91 : : * \ingroup core
92 : : * \brief Main class to handle feature
93 : : * \class pal::FeaturePart
94 : : * \note not available in Python bindings
95 : : */
96 : : class CORE_EXPORT FeaturePart : public PointSet
97 : : {
98 : :
99 : : public:
100 : :
101 : : /**
102 : : * Creates a new generic feature.
103 : : * \param lf a pointer for a feature which contains the spatial entites
104 : : * \param geom a pointer to a GEOS geometry
105 : : */
106 : : FeaturePart( QgsLabelFeature *lf, const GEOSGeometry *geom );
107 : :
108 : : FeaturePart( const FeaturePart &other );
109 : :
110 : : /**
111 : : * Delete the feature
112 : : */
113 : : ~FeaturePart() override;
114 : :
115 : : /**
116 : : * Returns the parent feature.
117 : : */
118 : 0 : QgsLabelFeature *feature() { return mLF; }
119 : :
120 : : /**
121 : : * Returns the layer that feature belongs to.
122 : : */
123 : : Layer *layer();
124 : :
125 : : /**
126 : : * Returns the unique ID of the feature.
127 : : */
128 : : QgsFeatureId featureId() const;
129 : :
130 : : /**
131 : : * Returns the maximum number of point candidates to generate for this feature.
132 : : */
133 : : std::size_t maximumPointCandidates() const;
134 : :
135 : : /**
136 : : * Returns the maximum number of line candidates to generate for this feature.
137 : : */
138 : : std::size_t maximumLineCandidates() const;
139 : :
140 : : /**
141 : : * Returns the maximum number of polygon candidates to generate for this feature.
142 : : */
143 : : std::size_t maximumPolygonCandidates() const;
144 : :
145 : : /**
146 : : * Generates a list of candidate positions for labels for this feature.
147 : : */
148 : : std::vector<std::unique_ptr<LabelPosition> > createCandidates( Pal *pal );
149 : :
150 : : /**
151 : : * Generate candidates for point feature, located around a specified point.
152 : : * \param x x coordinate of the point
153 : : * \param y y coordinate of the point
154 : : * \param lPos pointer to an array of candidates, will be filled by generated candidates
155 : : * \param angle orientation of the label
156 : : * \returns the number of generated candidates
157 : : */
158 : : std::size_t createCandidatesAroundPoint( double x, double y, std::vector<std::unique_ptr<LabelPosition> > &lPos, double angle );
159 : :
160 : : /**
161 : : * Generate one candidate over or offset the specified point.
162 : : * \param x x coordinate of the point
163 : : * \param y y coordinate of the point
164 : : * \param lPos pointer to an array of candidates, will be filled by generated candidate
165 : : * \param angle orientation of the label
166 : : * \returns the number of generated candidates (always 1)
167 : : */
168 : : std::size_t createCandidatesOverPoint( double x, double y, std::vector<std::unique_ptr<LabelPosition> > &lPos, double angle );
169 : :
170 : : /**
171 : : * Generate one candidate centered over the specified point.
172 : : * \param x x coordinate of the point
173 : : * \param y y coordinate of the point
174 : : * \param lPos pointer to an array of candidates, will be filled by generated candidate
175 : : * \param angle orientation of the label
176 : : * \returns the number of generated candidates (always 1)
177 : : */
178 : : std::size_t createCandidateCenteredOverPoint( double x, double y, std::vector<std::unique_ptr<LabelPosition> > &lPos, double angle );
179 : :
180 : : /**
181 : : * Creates a single candidate using the "point on sruface" algorithm.
182 : : *
183 : : * \note Unlike the other create candidates methods, this method
184 : : * bypasses the usual candidate filtering steps and ALWAYS returns a single candidate.
185 : : */
186 : : std::unique_ptr< LabelPosition > createCandidatePointOnSurface( PointSet *mapShape );
187 : :
188 : : /**
189 : : * Generates candidates following a prioritized list of predefined positions around a point.
190 : : * \param x x coordinate of the point
191 : : * \param y y coordinate of the point
192 : : * \param lPos pointer to an array of candidates, will be filled by generated candidate
193 : : * \param angle orientation of the label
194 : : * \returns the number of generated candidates
195 : : */
196 : : std::size_t createCandidatesAtOrderedPositionsOverPoint( double x, double y, std::vector<std::unique_ptr<LabelPosition> > &lPos, double angle );
197 : :
198 : : /**
199 : : * Generate candidates for line feature.
200 : : * \param lPos pointer to an array of candidates, will be filled by generated candidates
201 : : * \param mapShape a pointer to the line
202 : : * \param allowOverrun set to TRUE to allow labels to overrun features
203 : : * \param pal point to pal settings object, for cancellation support
204 : : * \returns the number of generated candidates
205 : : */
206 : : std::size_t createCandidatesAlongLine( std::vector<std::unique_ptr<LabelPosition> > &lPos, PointSet *mapShape, bool allowOverrun, Pal *pal );
207 : :
208 : : /**
209 : : * Generate horizontal candidates for line feature.
210 : : * \param lPos pointer to an array of candidates, will be filled by generated candidates
211 : : * \param mapShape a pointer to the line
212 : : * \param pal point to pal settings object, for cancellation support
213 : : * \returns the number of generated candidates
214 : : */
215 : : std::size_t createHorizontalCandidatesAlongLine( std::vector<std::unique_ptr<LabelPosition> > &lPos, PointSet *mapShape, Pal *pal );
216 : :
217 : : /**
218 : : * Generate candidates for line feature, by trying to place candidates towards the middle of the longest
219 : : * straightish segments of the line. Segments closer to horizontal are preferred over vertical segments.
220 : : * \param lPos pointer to an array of candidates, will be filled by generated candidates
221 : : * \param mapShape a pointer to the line
222 : : * \param pal point to pal settings object, for cancellation support
223 : : * \returns the number of generated candidates
224 : : */
225 : : std::size_t createCandidatesAlongLineNearStraightSegments( std::vector<std::unique_ptr<LabelPosition> > &lPos, PointSet *mapShape, Pal *pal );
226 : :
227 : : /**
228 : : * Generate candidates for line feature, by trying to place candidates as close as possible to the line's midpoint.
229 : : * Candidates can "cut corners" if it helps them place near this mid point.
230 : : * \param lPos pointer to an array of candidates, will be filled by generated candidates
231 : : * \param mapShape a pointer to the line
232 : : * \param initialCost initial cost for candidates generated using this method. If set, cost can be increased
233 : : * by a preset amount.
234 : : * \param pal point to pal settings object, for cancellation support
235 : : * \returns the number of generated candidates
236 : : */
237 : : std::size_t createCandidatesAlongLineNearMidpoint( std::vector<std::unique_ptr<LabelPosition> > &lPos, PointSet *mapShape, double initialCost = 0.0, Pal *pal = nullptr );
238 : :
239 : : /**
240 : : * Returns the label position for a curved label at a specific offset along a path.
241 : : * \param path_positions line path to place label on
242 : : * \param path_distances array of distances to each segment on path
243 : : * \param orientation can be 0 for automatic calculation of orientation, or -1/+1 for a specific label orientation
244 : : * \param distance distance to offset label along curve by
245 : : * \param reversed if TRUE label is reversed from lefttoright to righttoleft
246 : : * \param flip if TRUE label is placed on the other side of the line
247 : : * \param applyAngleConstraints TRUE if label feature character angle constraints should be applied
248 : : * \returns calculated label position
249 : : */
250 : : std::unique_ptr< LabelPosition > curvedPlacementAtOffset( PointSet *path_positions, double *path_distances,
251 : : int &orientation, double distance, bool &reversed, bool &flip, bool applyAngleConstraints );
252 : :
253 : : /**
254 : : * Generate curved candidates for line features.
255 : : * \param lPos pointer to an array of candidates, will be filled by generated candidates
256 : : * \param mapShape a pointer to the line
257 : : * \param allowOverrun set to TRUE to allow labels to overrun features
258 : : * \param pal point to pal settings object, for cancellation support
259 : : * \returns the number of generated candidates
260 : : */
261 : : std::size_t createCurvedCandidatesAlongLine( std::vector<std::unique_ptr<LabelPosition> > &lPos, PointSet *mapShape, bool allowOverrun, Pal *pal );
262 : :
263 : : /**
264 : : * Generate candidates for polygon features.
265 : : * \param lPos pointer to an array of candidates, will be filled by generated candidates
266 : : * \param mapShape a pointer to the polygon
267 : : * \param pal point to pal settings object, for cancellation support
268 : : * \returns the number of generated candidates
269 : : */
270 : : std::size_t createCandidatesForPolygon( std::vector<std::unique_ptr<LabelPosition> > &lPos, PointSet *mapShape, Pal *pal );
271 : :
272 : : /**
273 : : * Generate candidates outside of polygon features.
274 : : * \param lPos pointer to an array of candidates, will be filled by generated candidates
275 : : * \param pal point to pal settings object, for cancellation support
276 : : * \returns the number of generated candidates
277 : : */
278 : : std::size_t createCandidatesOutsidePolygon( std::vector<std::unique_ptr<LabelPosition> > &lPos, Pal *pal );
279 : :
280 : : /**
281 : : * Tests whether this feature part belongs to the same QgsLabelFeature as another
282 : : * feature part.
283 : : * \param part part to compare to
284 : : * \returns TRUE if both parts belong to same QgsLabelFeature
285 : : */
286 : : bool hasSameLabelFeatureAs( FeaturePart *part ) const;
287 : :
288 : : /**
289 : : * Returns the width of the label, optionally taking an \a angle into account.
290 : : * \returns the width of the label
291 : : */
292 : 0 : double getLabelWidth( double angle = 0.0 ) const { return mLF->size( angle ).width(); }
293 : :
294 : : /**
295 : : * Returns the height of the label, optionally taking an \a angle into account.
296 : : * \returns the hieght of the label
297 : : */
298 : 0 : double getLabelHeight( double angle = 0.0 ) const { return mLF->size( angle ).height(); }
299 : :
300 : : /**
301 : : * Returns the distance from the anchor point to the label
302 : : * \returns the distance to the label
303 : : */
304 : 0 : double getLabelDistance() const { return mLF->distLabel(); }
305 : :
306 : : //! Returns TRUE if the feature's label has a fixed rotation
307 : 0 : bool hasFixedRotation() const { return mLF->hasFixedAngle(); }
308 : :
309 : : //! Returns the fixed angle for the feature's label
310 : 0 : double fixedAngle() const { return mLF->fixedAngle(); }
311 : :
312 : : //! Returns TRUE if the feature's label has a fixed position
313 : 0 : bool hasFixedPosition() const { return mLF->hasFixedPosition(); }
314 : :
315 : : /**
316 : : * Returns TRUE if the feature's label should always been shown,
317 : : * even when it collides with other labels
318 : : */
319 : 0 : bool alwaysShow() const { return mLF->alwaysShow(); }
320 : :
321 : : /**
322 : : * Returns the feature's obstacle settings.
323 : : */
324 : 0 : const QgsLabelObstacleSettings &obstacleSettings() const { return mLF->obstacleSettings(); }
325 : :
326 : : //! Returns the distance between repeating labels for this feature
327 : 0 : double repeatDistance() const { return mLF->repeatDistance(); }
328 : :
329 : : //! Gets number of holes (inner rings) - they are considered as obstacles
330 : 0 : int getNumSelfObstacles() const { return mHoles.count(); }
331 : : //! Gets hole (inner ring) - considered as obstacle
332 : 0 : FeaturePart *getSelfObstacle( int i ) { return mHoles.at( i ); }
333 : :
334 : : //! Check whether this part is connected with some other part
335 : : bool isConnected( FeaturePart *p2 );
336 : :
337 : : /**
338 : : * Merge other (connected) part with this one and save the result in this part (other is unchanged).
339 : : * Returns TRUE on success, FALSE if the feature wasn't modified.
340 : : */
341 : : bool mergeWithFeaturePart( FeaturePart *other );
342 : :
343 : : /**
344 : : * Increases the cost of the label candidates for this feature, based on the size of the feature.
345 : : *
346 : : * E.g. small lines or polygons get higher cost so that larger features are more likely to be labeled.
347 : : */
348 : : void addSizePenalty( std::vector<std::unique_ptr<LabelPosition> > &lPos, double bbx[4], double bby[4] );
349 : :
350 : : /**
351 : : * Calculates the priority for the feature. This will be the feature's priority if set,
352 : : * otherwise the layer's default priority.
353 : : */
354 : : double calculatePriority() const;
355 : :
356 : : //! Returns TRUE if feature's label must be displayed upright
357 : : bool showUprightLabels() const;
358 : :
359 : : //! Returns TRUE if the next char position is found. The referenced parameters are updated.
360 : : bool nextCharPosition( double charWidth, double segmentLength, PointSet *path_positions, int &index, double ¤tDistanceAlongSegment,
361 : : double &characterStartX, double &characterStartY, double &characterEndX, double &characterEndY ) const;
362 : :
363 : : /**
364 : : * Returns the total number of repeating labels associated with this label.
365 : : * \see setTotalRepeats()
366 : : */
367 : : int totalRepeats() const;
368 : :
369 : : /**
370 : : * Returns the total number of repeating labels associated with this label.
371 : : * \see totalRepeats()
372 : : */
373 : : void setTotalRepeats( int repeats );
374 : :
375 : : protected:
376 : :
377 : : QgsLabelFeature *mLF = nullptr;
378 : : QList<FeaturePart *> mHoles;
379 : :
380 : : //! \brief read coordinates from a GEOS geom
381 : : void extractCoords( const GEOSGeometry *geom );
382 : :
383 : : private:
384 : :
385 : : LabelPosition::Quadrant quadrantFromOffset() const;
386 : :
387 : : int mTotalRepeats = 0;
388 : :
389 : : mutable std::size_t mCachedMaxLineCandidates = 0;
390 : : mutable std::size_t mCachedMaxPolygonCandidates = 0;
391 : :
392 : : FeaturePart &operator= ( const FeaturePart & ) = delete;
393 : : };
394 : :
395 : : } // end namespace pal
396 : :
397 : : #endif
|