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_H
31 : : #define PAL_H
32 : :
33 : : #define SIP_NO_FILE
34 : :
35 : :
36 : : #include "qgis_core.h"
37 : : #include "qgsgeometry.h"
38 : : #include "qgsgeos.h"
39 : : #include "qgspallabeling.h"
40 : : #include "qgslabelingenginesettings.h"
41 : : #include <QList>
42 : : #include <iostream>
43 : : #include <ctime>
44 : : #include <QMutex>
45 : : #include <QStringList>
46 : : #include <unordered_map>
47 : :
48 : : // TODO ${MAJOR} ${MINOR} etc instead of 0.2
49 : :
50 : : class QgsAbstractLabelProvider;
51 : :
52 : : namespace pal
53 : : {
54 : : class Layer;
55 : : class LabelPosition;
56 : : class PalStat;
57 : : class Problem;
58 : : class PointSet;
59 : :
60 : : //! Search method to use
61 : : enum SearchMethod
62 : : {
63 : : CHAIN = 0, //!< Is the worst but fastest method
64 : : POPMUSIC_TABU_CHAIN = 1, //!< Is the best but slowest
65 : : POPMUSIC_TABU = 2, //!< Is a little bit better than CHAIN but slower
66 : : POPMUSIC_CHAIN = 3, //!< Is slower and best than TABU, worse and faster than TABU_CHAIN
67 : : FALP = 4 //!< Only initial solution
68 : : };
69 : :
70 : : /**
71 : : * \ingroup core
72 : : * \brief Main Pal labeling class
73 : : *
74 : : * A pal object will contains layers and global information such as which search method
75 : : * will be used.
76 : : * \class pal::Pal
77 : : * \note not available in Python bindings
78 : : */
79 : : class CORE_EXPORT Pal
80 : : {
81 : : friend class Problem;
82 : : friend class FeaturePart;
83 : : friend class Layer;
84 : :
85 : : public:
86 : :
87 : : /**
88 : : * \brief Create an new pal instance
89 : : */
90 : : Pal();
91 : :
92 : : ~Pal();
93 : :
94 : : //! Pal cannot be copied.
95 : : Pal( const Pal &other ) = delete;
96 : : //! Pal cannot be copied.
97 : : Pal &operator=( const Pal &other ) = delete;
98 : :
99 : : /**
100 : : * \brief add a new layer
101 : : *
102 : : * \param provider Provider associated with the layer
103 : : * \param layerName layer's name
104 : : * \param arrangement Howto place candidates
105 : : * \param defaultPriority layer's prioriry (0 is the best, 1 the worst)
106 : : * \param active is the layer is active (currently displayed)
107 : : * \param toLabel the layer will be labeled only if toLablel is TRUE
108 : : * \param displayAll if TRUE, all features will be labelled even though overlaps occur
109 : : *
110 : : * \throws PalException::LayerExists
111 : : */
112 : : Layer *addLayer( QgsAbstractLabelProvider *provider, const QString &layerName, QgsPalLayerSettings::Placement arrangement, double defaultPriority, bool active, bool toLabel, bool displayAll = false );
113 : :
114 : : /**
115 : : * \brief remove a layer
116 : : *
117 : : * \param layer layer to remove
118 : : */
119 : : void removeLayer( Layer *layer );
120 : :
121 : : typedef bool ( *FnIsCanceled )( void *ctx );
122 : :
123 : : //! Register a function that returns whether this job has been canceled - PAL calls it during the computation
124 : : void registerCancellationCallback( FnIsCanceled fnCanceled, void *context );
125 : :
126 : : //! Check whether the job has been canceled
127 : 0 : inline bool isCanceled() { return fnIsCanceled ? fnIsCanceled( fnIsCanceledContext ) : false; }
128 : :
129 : : /**
130 : : * Extracts the labeling problem for the specified map \a extent - only features within this
131 : : * extent will be considered. The \a mapBoundary argument specifies the actual geometry of the map
132 : : * boundary, which will be used to detect whether a label is visible (or partially visible) in
133 : : * the rendered map. This may differ from \a extent in the case of rotated or non-rectangular
134 : : * maps.
135 : : */
136 : : std::unique_ptr< Problem > extractProblem( const QgsRectangle &extent, const QgsGeometry &mapBoundary );
137 : :
138 : : /**
139 : : * Solves the labeling problem, selecting the best candidate locations for all labels and returns a list of these
140 : : * calculated label positions.
141 : : *
142 : : * If \a displayAll is TRUE, then the best positions for ALL labels will be returned, regardless of whether these
143 : : * labels overlap other labels.
144 : : *
145 : : * If the optional \a unlabeled list is specified, it will be filled with a list of all feature labels which could
146 : : * not be placed in the returned solution (e.g. due to overlaps or other constraints).
147 : : *
148 : : * Ownership of the returned labels is not transferred - it resides with the pal object.
149 : : */
150 : : QList<LabelPosition *> solveProblem( Problem *prob, bool displayAll, QList<pal::LabelPosition *> *unlabeled = nullptr );
151 : :
152 : : /**
153 : : * Sets whether partial labels show be allowed.
154 : : *
155 : : * \see showPartialLabels()
156 : : */
157 : : void setShowPartialLabels( bool show );
158 : :
159 : : /**
160 : : * Returns whether partial labels should be allowed.
161 : : *
162 : : * \see setShowPartialLabels()
163 : : */
164 : : bool showPartialLabels() const;
165 : :
166 : : /**
167 : : * Returns the maximum number of line label candidate positions per map unit.
168 : : *
169 : : * \see setMaximumLineCandidatesPerMapUnit()
170 : : */
171 : 0 : double maximumLineCandidatesPerMapUnit() const { return mMaxLineCandidatesPerMapUnit; }
172 : :
173 : : /**
174 : : * Sets the maximum number of line label \a candidates per map unit.
175 : : *
176 : : * \see maximumLineCandidatesPerMapUnit()
177 : : */
178 : 0 : void setMaximumLineCandidatesPerMapUnit( double candidates ) { mMaxLineCandidatesPerMapUnit = candidates; }
179 : :
180 : : /**
181 : : * Returns the maximum number of polygon label candidate positions per map unit squared.
182 : : *
183 : : * \see setMaximumPolygonCandidatesPerMapUnitSquared()
184 : : */
185 : 0 : double maximumPolygonCandidatesPerMapUnitSquared() const { return mMaxPolygonCandidatesPerMapUnitSquared; }
186 : :
187 : : /**
188 : : * Sets the maximum number of polygon label \a candidates per map unit squared.
189 : : *
190 : : * \see maximumPolygonCandidatesPerMapUnitSquared()
191 : : */
192 : 0 : void setMaximumPolygonCandidatesPerMapUnitSquared( double candidates ) { mMaxPolygonCandidatesPerMapUnitSquared = candidates; }
193 : :
194 : : /**
195 : : * Returns the placement engine version, which dictates how the label placement problem is solved.
196 : : *
197 : : * \see setPlacementVersion()
198 : : */
199 : : QgsLabelingEngineSettings::PlacementEngineVersion placementVersion() const;
200 : :
201 : : /**
202 : : * Sets the placement engine \a version, which dictates how the label placement problem is solved.
203 : : *
204 : : * \see placementVersion()
205 : : */
206 : : void setPlacementVersion( QgsLabelingEngineSettings::PlacementEngineVersion placementVersion );
207 : :
208 : : /**
209 : : * Returns the global candidates limit for point features, or 0 if no global limit is in effect.
210 : : *
211 : : * This is an installation-wide setting which applies to all projects, and is set via QSettings. It can
212 : : * be used to place global limits on the number of candidates generated for point features in order
213 : : * to optimise map rendering speeds.
214 : : *
215 : : * \see globalCandidatesLimitLine()
216 : : * \see globalCandidatesLimitPolygon()
217 : : */
218 : 0 : int globalCandidatesLimitPoint() const { return mGlobalCandidatesLimitPoint; }
219 : :
220 : : /**
221 : : * Returns the global candidates limit for line features, or 0 if no global limit is in effect.
222 : : *
223 : : * This is an installation-wide setting which applies to all projects, and is set via QSettings. It can
224 : : * be used to place global limits on the number of candidates generated for line features in order
225 : : * to optimise map rendering speeds.
226 : : *
227 : : * \see globalCandidatesLimitPolygon()
228 : : * \see globalCandidatesLimitPoint()
229 : : */
230 : 0 : int globalCandidatesLimitLine() const { return mGlobalCandidatesLimitLine; }
231 : :
232 : : /**
233 : : * Returns the global candidates limit for polygon features, or 0 if no global limit is in effect.
234 : : *
235 : : * This is an installation-wide setting which applies to all projects, and is set via QSettings. It can
236 : : * be used to place global limits on the number of candidates generated for polygon features in order
237 : : * to optimise map rendering speeds.
238 : : *
239 : : * \see globalCandidatesLimitLine()
240 : : * \see globalCandidatesLimitPoint()
241 : : */
242 : 0 : int globalCandidatesLimitPolygon() const { return mGlobalCandidatesLimitPolygon; }
243 : :
244 : : /**
245 : : * Returns TRUE if a labelling candidate \a lp1 conflicts with \a lp2.
246 : : */
247 : : bool candidatesAreConflicting( const LabelPosition *lp1, const LabelPosition *lp2 ) const;
248 : :
249 : : private:
250 : :
251 : : std::unordered_map< QgsAbstractLabelProvider *, std::unique_ptr< Layer > > mLayers;
252 : :
253 : : QMutex mMutex;
254 : :
255 : : /*
256 : : * POPMUSIC Tuning
257 : : */
258 : : int mPopmusicR = 30;
259 : :
260 : : int mTabuMaxIt = 4;
261 : : int mTabuMinIt = 2;
262 : :
263 : : int mEjChainDeg = 50;
264 : : int mTenure = 10;
265 : : double mCandListSize = 0.2;
266 : :
267 : : unsigned int mNextCandidateId = 1;
268 : : mutable QHash< QPair< unsigned int, unsigned int >, bool > mCandidateConflicts;
269 : :
270 : : /**
271 : : * \brief show partial labels (cut-off by the map canvas) or not
272 : : */
273 : : bool mShowPartialLabels = true;
274 : :
275 : : double mMaxLineCandidatesPerMapUnit = 0;
276 : : double mMaxPolygonCandidatesPerMapUnitSquared = 0;
277 : :
278 : : int mGlobalCandidatesLimitPoint = 0;
279 : : int mGlobalCandidatesLimitLine = 0;
280 : : int mGlobalCandidatesLimitPolygon = 0;
281 : :
282 : : QgsLabelingEngineSettings::PlacementEngineVersion mPlacementVersion = QgsLabelingEngineSettings::PlacementEngineVersion2;
283 : :
284 : : //! Callback that may be called from PAL to check whether the job has not been canceled in meanwhile
285 : : FnIsCanceled fnIsCanceled = nullptr;
286 : : //! Application-specific context for the cancellation check function
287 : : void *fnIsCanceledContext = nullptr;
288 : :
289 : : /**
290 : : * Creates a Problem, by extracting labels and generating candidates from the given \a extent.
291 : : * The \a mapBoundary geometry specifies the actual visible region of the map, and is used
292 : : * for pruning candidates which fall outside the visible region.
293 : : */
294 : : std::unique_ptr< Problem > extract( const QgsRectangle &extent, const QgsGeometry &mapBoundary );
295 : :
296 : : /**
297 : : * \brief Choose the size of popmusic subpart's
298 : : * \param r subpart size
299 : : */
300 : : void setPopmusicR( int r );
301 : :
302 : : /**
303 : : * \brief minimum # of iteration for search method POPMUSIC_TABU, POPMUSIC_CHAIN and POPMUSIC_TABU_CHAIN
304 : : * \param min_it Sub part optimization min # of iteration
305 : : */
306 : : void setMinIt( int min_it );
307 : :
308 : : /**
309 : : * \brief maximum \# of iteration for search method POPMUSIC_TABU, POPMUSIC_CHAIN and POPMUSIC_TABU_CHAIN
310 : : * \param max_it Sub part optimization max # of iteration
311 : : */
312 : : void setMaxIt( int max_it );
313 : :
314 : : /**
315 : : * \brief For tabu search : how many iteration a feature will be tabu
316 : : * \param tenure consiser a feature as tabu for tenure iteration after updating feature in solution
317 : : */
318 : : void setTenure( int tenure );
319 : :
320 : : /**
321 : : * \brief For *CHAIN, select the max size of a transformation chain
322 : : * \param degree maximum soze of a transformation chain
323 : : */
324 : : void setEjChainDeg( int degree );
325 : :
326 : : /**
327 : : * \brief How many candidates will be tested by a tabu iteration
328 : : * \param fact the ration (0..1) of candidates to test
329 : : */
330 : : void setCandListSize( double fact );
331 : :
332 : :
333 : : /**
334 : : * Returns the minimum number of iterations used for POPMUSIC_TABU, POPMUSIC_CHAIN and POPMUSIC_TABU_CHAIN.
335 : : * \see getMaxIt()
336 : : */
337 : : int getMinIt();
338 : :
339 : : /**
340 : : * Returns the maximum number of iterations allowed for POPMUSIC_TABU, POPMUSIC_CHAIN and POPMUSIC_TABU_CHAIN.
341 : : * \see getMinIt()
342 : : */
343 : : int getMaxIt();
344 : :
345 : : };
346 : :
347 : : } // end namespace pal
348 : :
349 : : #endif
|