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 PAL_LAYER_H_
31 : : #define PAL_LAYER_H_
32 : :
33 : : #define SIP_NO_FILE
34 : :
35 : :
36 : : #include "qgis_core.h"
37 : : #include "pal.h" // for LineArrangementFlags enum
38 : : #include "qgsgeos.h"
39 : : #include "qgsgenericspatialindex.h"
40 : : #include <QMutex>
41 : : #include <QLinkedList>
42 : : #include <QHash>
43 : : #include <fstream>
44 : :
45 : : class QgsLabelFeature;
46 : :
47 : : namespace pal
48 : : {
49 : :
50 : : class FeaturePart;
51 : :
52 : : class Pal;
53 : : class LabelInfo;
54 : :
55 : : /**
56 : : * \ingroup core
57 : : * \brief A set of features which influence the labeling process
58 : : * \class pal::Layer
59 : : * \note not available in Python bindings
60 : : */
61 : : class CORE_EXPORT Layer
62 : : {
63 : : friend class Pal;
64 : : friend class FeaturePart;
65 : :
66 : : friend class Problem;
67 : :
68 : : friend class LabelPosition;
69 : :
70 : : public:
71 : : enum UpsideDownLabels
72 : : {
73 : : Upright, // upside-down labels (90 <= angle < 270) are shown upright
74 : : ShowDefined, // show upside down when rotation is layer- or data-defined
75 : : ShowAll // show upside down for all labels, including dynamic ones
76 : : };
77 : :
78 : : /**
79 : : * \brief Create a new layer
80 : : *
81 : : * \param provider Associated provider
82 : : * \param name Name of the layer (for stats, debugging - does not need to be unique)
83 : : * \param arrangement Arrangement mode : how to place candidates
84 : : * \param defaultPriority layer's prioriry (0 is the best, 1 the worst)
85 : : * \param active is the layer is active (currently displayed)
86 : : * \param toLabel the layer will be labeled whether toLablel is TRUE
87 : : * \param pal pointer to the pal object
88 : : * \param displayAll if TRUE, all features will be labelled even though overlaps occur
89 : : *
90 : : */
91 : : Layer( QgsAbstractLabelProvider *provider, const QString &name, QgsPalLayerSettings::Placement arrangement, double defaultPriority, bool active, bool toLabel, Pal *pal, bool displayAll = false );
92 : :
93 : : virtual ~Layer();
94 : :
95 : 0 : bool displayAll() const { return mDisplayAll; }
96 : :
97 : : /**
98 : : * Returns the number of features in layer.
99 : : */
100 : : int featureCount() { return mHashtable.size(); }
101 : :
102 : : /**
103 : : * Returns the maximum number of point label candidates to generate for features
104 : : * in this layer.
105 : : */
106 : 0 : std::size_t maximumPointLabelCandidates() const
107 : : {
108 : : // when an extreme number of features exist in the layer, we limit the number of candidates
109 : : // to avoid the engine processing endlessly...
110 : 0 : const int size = mHashtable.size();
111 : 0 : if ( size > 1000 )
112 : 0 : return static_cast< std::size_t >( mPal->globalCandidatesLimitPoint() > 0 ? std::min( mPal->globalCandidatesLimitPoint(), 4 ) : 4 );
113 : 0 : else if ( size > 500 )
114 : 0 : return static_cast< std::size_t >( mPal->globalCandidatesLimitPoint() > 0 ? std::min( mPal->globalCandidatesLimitPoint(), 6 ) : 6 );
115 : 0 : else if ( size > 200 )
116 : 0 : return static_cast< std::size_t >( mPal->globalCandidatesLimitPoint() > 0 ? std::min( mPal->globalCandidatesLimitPoint(), 8 ) : 8 );
117 : 0 : else if ( size > 100 )
118 : 0 : return static_cast< std::size_t >( mPal->globalCandidatesLimitPoint() > 0 ? std::min( mPal->globalCandidatesLimitPoint(), 12 ) : 12 );
119 : : else
120 : 0 : return static_cast< std::size_t >( std::max( mPal->globalCandidatesLimitPoint(), 0 ) );
121 : 0 : }
122 : :
123 : : /**
124 : : * Returns the maximum number of line label candidates to generate for features
125 : : * in this layer.
126 : : */
127 : 0 : std::size_t maximumLineLabelCandidates() const
128 : : {
129 : : // when an extreme number of features exist in the layer, we limit the number of candidates
130 : : // to avoid the engine processing endlessly...
131 : 0 : const int size = mHashtable.size();
132 : 0 : if ( size > 1000 )
133 : 0 : return static_cast< std::size_t >( mPal->globalCandidatesLimitLine() > 0 ? std::min( mPal->globalCandidatesLimitLine(), 5 ) : 5 );
134 : 0 : else if ( size > 500 )
135 : 0 : return static_cast< std::size_t >( mPal->globalCandidatesLimitLine() > 0 ? std::min( mPal->globalCandidatesLimitLine(), 10 ) : 10 );
136 : 0 : else if ( size > 200 )
137 : 0 : return static_cast< std::size_t >( mPal->globalCandidatesLimitLine() > 0 ? std::min( mPal->globalCandidatesLimitLine(), 20 ) : 20 );
138 : 0 : else if ( size > 100 )
139 : 0 : return static_cast< std::size_t >( mPal->globalCandidatesLimitLine() > 0 ? std::min( mPal->globalCandidatesLimitLine(), 40 ) : 40 );
140 : : else
141 : 0 : return static_cast< std::size_t >( std::max( mPal->globalCandidatesLimitLine(), 0 ) );
142 : 0 : }
143 : :
144 : : /**
145 : : * Returns the maximum number of polygon label candidates to generate for features
146 : : * in this layer.
147 : : */
148 : 0 : std::size_t maximumPolygonLabelCandidates() const
149 : : {
150 : : // when an extreme number of features exist in the layer, we limit the number of candidates
151 : : // to avoid the engine processing endlessly...
152 : 0 : const int size = mHashtable.size();
153 : 0 : if ( size > 1000 )
154 : 0 : return static_cast< std::size_t >( mPal->globalCandidatesLimitPolygon() > 0 ? std::min( mPal->globalCandidatesLimitPolygon(), 5 ) : 5 );
155 : 0 : else if ( size > 500 )
156 : 0 : return static_cast< std::size_t >( mPal->globalCandidatesLimitPolygon() > 0 ? std::min( mPal->globalCandidatesLimitPolygon(), 15 ) : 15 );
157 : 0 : else if ( size > 200 )
158 : 0 : return static_cast< std::size_t >( mPal->globalCandidatesLimitPolygon() > 0 ? std::min( mPal->globalCandidatesLimitPolygon(), 20 ) : 20 );
159 : 0 : else if ( size > 100 )
160 : 0 : return static_cast< std::size_t >( mPal->globalCandidatesLimitPolygon() > 0 ? std::min( mPal->globalCandidatesLimitPolygon(), 25 ) : 25 );
161 : : else
162 : 0 : return static_cast< std::size_t >( std::max( mPal->globalCandidatesLimitPolygon(), 0 ) );
163 : 0 : }
164 : :
165 : : //! Returns pointer to the associated provider
166 : 0 : QgsAbstractLabelProvider *provider() const { return mProvider; }
167 : :
168 : : /**
169 : : * Returns the layer's name.
170 : : */
171 : 0 : QString name() const { return mName; }
172 : :
173 : : /**
174 : : * Returns the layer's arrangement policy.
175 : : * \see setArrangement
176 : : */
177 : 0 : QgsPalLayerSettings::Placement arrangement() const { return mArrangement; }
178 : :
179 : : /**
180 : : * Returns TRUE if the layer has curved labels
181 : : */
182 : 0 : bool isCurved() const { return mArrangement == QgsPalLayerSettings::Curved || mArrangement == QgsPalLayerSettings::PerimeterCurved; }
183 : :
184 : : /**
185 : : * Sets the layer's arrangement policy.
186 : : * \param arrangement arrangement policy
187 : : * \see arrangement
188 : : */
189 : : void setArrangement( QgsPalLayerSettings::Placement arrangement ) { mArrangement = arrangement; }
190 : :
191 : : /**
192 : : * \brief Sets whether the layer is currently active.
193 : : *
194 : : * Active means "is currently displayed or used as obstacles". When a layer is
195 : : * deactivated then feature of this layer will not be used for either
196 : : * labeling or as obstacles.
197 : : *
198 : : * \param active set to TRUE to make the layer active, or FALSE to deactivate the layer
199 : : * \see active
200 : : */
201 : : void setActive( bool active ) { mActive = active; }
202 : :
203 : : /**
204 : : * Returns whether the layer is currently active.
205 : : * \see setActive
206 : : */
207 : 0 : bool active() const { return mActive; }
208 : :
209 : : /**
210 : : * Sets whether the layer will be labeled.
211 : : * \note Layers are labelled if and only if labelLayer and active are TRUE
212 : : * \param toLabel set to FALSE disable labeling this layer
213 : : * \see labelLayer
214 : : * \see setActive
215 : : */
216 : : void setLabelLayer( bool toLabel ) { mLabelLayer = toLabel; }
217 : :
218 : : /**
219 : : * Returns whether the layer will be labeled or not.
220 : : * \see setLabelLayer
221 : : */
222 : : bool labelLayer() const { return mLabelLayer; }
223 : :
224 : : /**
225 : : * Returns the obstacle type, which controls how features within the layer
226 : : * act as obstacles for labels.
227 : : * \see setObstacleType
228 : : */
229 : 0 : QgsLabelObstacleSettings::ObstacleType obstacleType() const { return mObstacleType; }
230 : :
231 : : /**
232 : : * Sets the obstacle type, which controls how features within the layer
233 : : * act as obstacles for labels.
234 : : * \param obstacleType new obstacle type
235 : : * \see obstacleType
236 : : */
237 : 0 : void setObstacleType( QgsLabelObstacleSettings::ObstacleType obstacleType ) { mObstacleType = obstacleType; }
238 : :
239 : : /**
240 : : * Sets the layer's priority.
241 : : * \param priority layer priority, between 0 and 1. 0 corresponds to highest priority,
242 : : * 1 to lowest priority.
243 : : * \see priority
244 : : */
245 : : void setPriority( double priority );
246 : :
247 : : /**
248 : : * Returns the layer's priority, between 0 and 1. 0 corresponds to highest priority,
249 : : * 1 to lowest priority.
250 : : * \see setPriority
251 : : */
252 : 0 : double priority() const { return mDefaultPriority; }
253 : :
254 : : /**
255 : : * Sets whether connected lines should be merged before labeling
256 : : * \param merge set to TRUE to merge connected lines
257 : : * \see mergeConnectedLines
258 : : */
259 : 0 : void setMergeConnectedLines( bool merge ) { mMergeLines = merge; }
260 : :
261 : : /**
262 : : * Returns whether connected lines will be merged before labeling.
263 : : * \see setMergeConnectedLines
264 : : */
265 : 0 : bool mergeConnectedLines() const { return mMergeLines; }
266 : :
267 : : /**
268 : : * Sets how upside down labels will be handled within the layer.
269 : : * \param ud upside down label handling mode
270 : : * \see upsidedownLabels
271 : : */
272 : 0 : void setUpsidedownLabels( UpsideDownLabels ud ) { mUpsidedownLabels = ud; }
273 : :
274 : : /**
275 : : * Returns how upside down labels are handled within the layer.
276 : : * \see setUpsidedownLabels
277 : : */
278 : 0 : UpsideDownLabels upsidedownLabels() const { return mUpsidedownLabels; }
279 : :
280 : : /**
281 : : * Sets whether labels placed at the centroid of features within the layer
282 : : * are forced to be placed inside the feature's geometry.
283 : : * \param forceInside set to TRUE to force centroid labels to be within the
284 : : * feature. If set to FALSE then the centroid may fall outside the feature.
285 : : * \see centroidInside
286 : : */
287 : 0 : void setCentroidInside( bool forceInside ) { mCentroidInside = forceInside; }
288 : :
289 : : /**
290 : : * Returns whether labels placed at the centroid of features within the layer
291 : : * are forced to be placed inside the feature's geometry.
292 : : * \see setCentroidInside
293 : : */
294 : 0 : bool centroidInside() const { return mCentroidInside; }
295 : :
296 : : /**
297 : : * Register a feature in the layer.
298 : : *
299 : : * Does not take ownership of the label feature (it is owned by its provider).
300 : : *
301 : : * \throws PalException::FeatureExists
302 : : *
303 : : * \returns TRUE on success (i.e. valid geometry)
304 : : */
305 : : bool registerFeature( QgsLabelFeature *label );
306 : :
307 : : //! Join connected features with the same label text
308 : : void joinConnectedFeatures();
309 : :
310 : : /**
311 : : * Returns the connected feature ID for a label feature ID, which is unique for all features
312 : : * which have been joined as a result of joinConnectedFeatures()
313 : : * \returns connected feature ID, or -1 if feature was not joined
314 : : */
315 : : int connectedFeatureId( QgsFeatureId featureId ) const;
316 : :
317 : : //! Chop layer features at the repeat distance
318 : : void chopFeaturesAtRepeatDistance();
319 : :
320 : : protected:
321 : : QgsAbstractLabelProvider *mProvider; // not owned
322 : : QString mName;
323 : :
324 : : //! List of feature parts
325 : : QLinkedList<FeaturePart *> mFeatureParts;
326 : :
327 : : //! List of obstacle parts
328 : : QList<FeaturePart *> mObstacleParts;
329 : :
330 : : std::vector< geos::unique_ptr > mGeosObstacleGeometries;
331 : :
332 : : Pal *mPal = nullptr;
333 : :
334 : : double mDefaultPriority;
335 : :
336 : : QgsLabelObstacleSettings::ObstacleType mObstacleType = QgsLabelObstacleSettings::PolygonBoundary;
337 : : bool mActive;
338 : : bool mLabelLayer;
339 : : bool mDisplayAll;
340 : : bool mCentroidInside;
341 : :
342 : : //! Optional flags used for some placement methods
343 : : QgsPalLayerSettings::Placement mArrangement;
344 : :
345 : : bool mMergeLines;
346 : :
347 : : UpsideDownLabels mUpsidedownLabels;
348 : :
349 : : //! Lookup table of label features (owned by the label feature provider that created them)
350 : : QHash< QgsFeatureId, QgsLabelFeature *> mHashtable;
351 : :
352 : : QHash< QString, QVector<FeaturePart *> > mConnectedHashtable;
353 : : QHash< QgsFeatureId, int > mConnectedFeaturesIds;
354 : :
355 : : QMutex mMutex;
356 : :
357 : : //! Add newly created feature part into r tree and to the list
358 : : void addFeaturePart( FeaturePart *fpart, const QString &labelText = QString() );
359 : :
360 : : //! Add newly created obstacle part into r tree and to the list
361 : : void addObstaclePart( FeaturePart *fpart );
362 : :
363 : : };
364 : :
365 : : } // end namespace pal
366 : :
367 : :
368 : : #endif
|