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_PROBLEM_H
31 #define PAL_PROBLEM_H
32 
33 #define SIP_NO_FILE
34 
35 
36 #include "qgis_core.h"
37 #include <list>
38 #include <QList>
39 #include "palrtree.h"
40 #include <memory>
41 #include <vector>
42 
43 namespace pal
44 {
45 
46   class LabelPosition;
47   class Label;
48 
49   /**
50    * \class pal::Sol
51    * \ingroup core
52    * \brief Chain solution parameters.
53    * \note not available in Python bindings
54    */
55 
56   struct Chain
57   {
58     int degree;
59     double delta;
60     int *feat = nullptr;
61     int *label = nullptr;
62   };
63 
64   /**
65    * \ingroup core
66    * \brief Representation of a labeling problem
67    * \class pal::Problem
68    * \note not available in Python bindings
69    */
70   class CORE_EXPORT Problem
71   {
72       friend class Pal;
73 
74     public:
75 
76       /**
77        * Constructor for Problem.
78        *
79        * The \a extent argument specifies the bounds of the incoming coordinates.
80        */
81       Problem( const QgsRectangle &extent );
82 
83       //Problem(char *lorena_file, bool displayAll);
84 
85       ~Problem();
86 
87       //! Problem cannot be copied
88       Problem( const Problem &other ) = delete;
89       //! Problem cannot be copied
90       Problem &operator=( const Problem &other ) = delete;
91 
92       /**
93        * Adds a candidate label position to the problem.
94        * \param position label candidate position. Ownership is transferred to Problem.
95        * \since QGIS 2.12
96        */
addCandidatePosition(std::unique_ptr<LabelPosition> position)97       void addCandidatePosition( std::unique_ptr< LabelPosition > position ) { mLabelPositions.emplace_back( std::move( position ) ); }
98 
99       /**
100        * Returns the total number of features considered during the labeling problem.
101        */
featureCount()102       std::size_t featureCount() const { return mFeatureCount; }
103 
104       /**
105        * Returns the number of candidates generated for the \a feature at the specified index.
106        */
featureCandidateCount(int feature)107       int featureCandidateCount( int feature ) const { return mFeatNbLp[feature]; }
108 
109       /**
110        * Returns the candidate corresponding to the specified \a feature and \a candidate index.
111        */
featureCandidate(int feature,int candidate)112       LabelPosition *featureCandidate( int feature, int candidate ) const { return mLabelPositions[ mFeatStartId[feature] + candidate ].get(); }
113 
114       void reduce();
115 
116       /**
117        * \brief Test with very-large scale neighborhood
118        */
119       void chain_search();
120 
121       /**
122        * Solves the labeling problem, selecting the best candidate locations for all labels and returns a list of these
123        * calculated label positions.
124        *
125        * If \a returnInactive is TRUE, then the best positions for ALL labels will be returned, regardless of whether these
126        * labels overlap other labels.
127        *
128        * If the optional \a unlabeled list is specified, it will be filled with a list of all feature labels which could
129        * not be placed in the returned solution (e.g. due to overlaps or other constraints).
130        *
131        * Ownership of the returned labels is not transferred - it resides with the pal object.
132        */
133       QList<LabelPosition *> getSolution( bool returnInactive, QList<LabelPosition *> *unlabeled = nullptr );
134 
135       /* useful only for postscript post-conversion*/
136       //void toFile(char *label_file);
137 
138       void init_sol_falp();
139 
140       /**
141        * Returns a reference to the list of label positions which correspond to
142        * features with no candidates.
143        *
144        * Ownership of positions added to this list is transferred to the problem.
145        */
positionsWithNoCandidates()146       std::vector< std::unique_ptr< LabelPosition > > *positionsWithNoCandidates()
147       {
148         return &mPositionsWithNoCandidates;
149       }
150 
151       /**
152        * Returns the index containing all label candidates.
153        */
allCandidatesIndex()154       PalRtree< LabelPosition > &allCandidatesIndex() { return mAllCandidatesIndex; }
155 
156     private:
157 
158       /**
159        * Total number of layers containing labels
160        */
161       int mLayerCount = 0;
162 
163       /**
164        * Names of the labelled layers
165        */
166       QStringList labelledLayersName;
167 
168       /**
169        * Total number of active candidates (remaining after reduce())
170        */
171       int mTotalCandidates = 0;
172 
173       /**
174        * Number of candidates (all, including)
175        */
176       int mAllNblp = 0;
177 
178       /**
179        * Total number of features to label.
180        */
181       std::size_t mFeatureCount = 0;
182 
183       /**
184        * if TRUE, special value -1 is prohibited
185        */
186       bool mDisplayAll = false;
187 
188       /**
189        * Map extent (xmin, ymin, xmax, ymax)
190        */
191       double mMapExtentBounds[4] = {0, 0, 0, 0};
192 
193       std::vector< std::unique_ptr< LabelPosition > > mLabelPositions;
194 
195       PalRtree<LabelPosition> mAllCandidatesIndex;
196       PalRtree<LabelPosition> mActiveCandidatesIndex;
197 
198       std::vector< std::unique_ptr< LabelPosition > > mPositionsWithNoCandidates;
199 
200       std::vector< int > mFeatStartId;
201       std::vector< int > mFeatNbLp;
202       std::vector< double > mInactiveCost;
203 
204       class Sol
205       {
206         public:
207 
208           //! Placeholder list for active labels. Will contain label id for active labels, or -1 for empty positions in list
209           std::vector< int > activeLabelIds;
210 
211           double totalCost = 0;
212 
init(std::size_t featureCount)213           void init( std::size_t featureCount )
214           {
215             activeLabelIds.resize( featureCount, -1 );
216             totalCost = 0;
217           }
218       };
219 
220       Sol mSol;
221       double mNbOverlap = 0.0;
222 
223       Chain *chain( int seed );
224 
225       Pal *pal = nullptr;
226 
227       void solution_cost();
228   };
229 
230 } // namespace
231 
232 #endif
233