QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
problem.cpp
Go to the documentation of this file.
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 #include "pal.h"
31 #include "palstat.h"
32 #include "layer.h"
33 #include "feature.h"
34 #include "geomfunction.h"
35 #include "labelposition.h"
36 #include "problem.h"
37 #include "util.h"
38 #include "priorityqueue.h"
39 #include "internalexception.h"
40 #include <cfloat>
41 #include <limits> //for std::numeric_limits<int>::max()
42 
43 #include "qgslabelingengine.h"
44 
45 using namespace pal;
46 
47 inline void delete_chain( Chain *chain )
48 {
49  if ( chain )
50  {
51  delete[] chain->feat;
52  delete[] chain->label;
53  delete chain;
54  }
55 }
56 
58  : mAllCandidatesIndex( extent )
59  , mActiveCandidatesIndex( extent )
60 {
61 
62 }
63 
64 Problem::~Problem() = default;
65 
67 {
68  int i;
69  int j;
70  int k;
71 
72  int counter = 0;
73 
74  int lpid;
75 
76  bool *ok = new bool[mTotalCandidates];
77  bool run = true;
78 
79  for ( i = 0; i < mTotalCandidates; i++ )
80  ok[i] = false;
81 
82 
83  double amin[2];
84  double amax[2];
85  LabelPosition *lp2 = nullptr;
86 
87  while ( run )
88  {
89  run = false;
90  for ( i = 0; i < static_cast< int >( mFeatureCount ); i++ )
91  {
92  // ok[i] = true;
93  for ( j = 0; j < mFeatNbLp[i]; j++ ) // foreach candidate
94  {
95  if ( !ok[mFeatStartId[i] + j] )
96  {
97  if ( mLabelPositions.at( mFeatStartId[i] + j )->getNumOverlaps() == 0 ) // if candidate has no overlap
98  {
99  run = true;
100  ok[mFeatStartId[i] + j] = true;
101  // 1) remove worse candidates from candidates
102  // 2) update nb_overlaps
103  counter += mFeatNbLp[i] - j - 1;
104 
105  for ( k = j + 1; k < mFeatNbLp[i]; k++ )
106  {
107 
108  lpid = mFeatStartId[i] + k;
109  ok[lpid] = true;
110  lp2 = mLabelPositions[lpid ].get();
111 
112  lp2->getBoundingBox( amin, amax );
113 
114  mNbOverlap -= lp2->getNumOverlaps();
115  mAllCandidatesIndex.intersects( QgsRectangle( amin[0], amin[1], amax[0], amax[1] ), [&lp2]( const LabelPosition * lp ) -> bool
116  {
117  if ( lp2->isInConflict( lp ) )
118  {
119  const_cast< LabelPosition * >( lp )->decrementNumOverlaps();
120  lp2->decrementNumOverlaps();
121  }
122 
123  return true;
124  } );
125  lp2->removeFromIndex( mAllCandidatesIndex );
126  }
127 
128  mFeatNbLp[i] = j + 1;
129  break;
130  }
131  }
132  }
133  }
134  }
135 
136  this->mTotalCandidates -= counter;
137  delete[] ok;
138 }
139 
140 void ignoreLabel( const LabelPosition *lp, PriorityQueue &list, PalRtree< LabelPosition > &candidatesIndex )
141 {
142  if ( list.isIn( lp->getId() ) )
143  {
144  list.remove( lp->getId() );
145 
146  double amin[2];
147  double amax[2];
148  lp->getBoundingBox( amin, amax );
149  candidatesIndex.intersects( QgsRectangle( amin[0], amin[1], amax[0], amax[1] ), [lp, &list]( const LabelPosition * lp2 )->bool
150  {
151  if ( lp2->getId() != lp->getId() && list.isIn( lp2->getId() ) && lp2->isInConflict( lp ) )
152  {
153  list.decreaseKey( lp2->getId() );
154  }
155  return true;
156  } );
157  }
158 }
159 
160 /* Better initial solution
161  * Step one FALP (Yamamoto, Camara, Lorena 2005)
162  */
164 {
165  int label;
166 
167  mSol.init( mFeatureCount );
168 
169  PriorityQueue list( mTotalCandidates, mAllNblp, true );
170 
171  double amin[2];
172  double amax[2];
173 
174  LabelPosition *lp = nullptr;
175 
176  for ( int i = 0; i < static_cast< int >( mFeatureCount ); i++ )
177  for ( int j = 0; j < mFeatNbLp[i]; j++ )
178  {
179  label = mFeatStartId[i] + j;
180  try
181  {
182  list.insert( label, mLabelPositions.at( label )->getNumOverlaps() );
183  }
184  catch ( pal::InternalException::Full & )
185  {
186  continue;
187  }
188  }
189 
190  while ( list.getSize() > 0 ) // O (log size)
191  {
192  if ( pal->isCanceled() )
193  {
194  return;
195  }
196 
197  label = list.getBest(); // O (log size)
198 
199  lp = mLabelPositions[ label ].get();
200 
201  if ( lp->getId() != label )
202  {
203  //error
204  }
205 
206  int probFeatId = lp->getProblemFeatureId();
207  mSol.activeLabelIds[probFeatId] = label;
208 
209  for ( int i = mFeatStartId[probFeatId]; i < mFeatStartId[probFeatId] + mFeatNbLp[probFeatId]; i++ )
210  {
211  ignoreLabel( mLabelPositions[ i ].get(), list, mAllCandidatesIndex );
212  }
213 
214 
215  lp->getBoundingBox( amin, amax );
216 
217  std::vector< const LabelPosition * > conflictingPositions;
218  mAllCandidatesIndex.intersects( QgsRectangle( amin[0], amin[1], amax[0], amax[1] ), [lp, &conflictingPositions]( const LabelPosition * lp2 ) ->bool
219  {
220  if ( lp->isInConflict( lp2 ) )
221  {
222  conflictingPositions.emplace_back( lp2 );
223  }
224  return true;
225  } );
226 
227  for ( const LabelPosition *conflict : conflictingPositions )
228  {
229  ignoreLabel( conflict, list, mAllCandidatesIndex );
230  }
231 
232  mActiveCandidatesIndex.insert( lp, QgsRectangle( amin[0], amin[1], amax[0], amax[1] ) );
233  }
234 
235  if ( mDisplayAll )
236  {
237  int nbOverlap;
238  int start_p;
239  LabelPosition *retainedLabel = nullptr;
240  int p;
241 
242  for ( std::size_t i = 0; i < mFeatureCount; i++ ) // forearch hidden feature
243  {
244  if ( mSol.activeLabelIds[i] == -1 )
245  {
246  nbOverlap = std::numeric_limits<int>::max();
247  start_p = mFeatStartId[i];
248  for ( p = 0; p < mFeatNbLp[i]; p++ )
249  {
250  lp = mLabelPositions[ start_p + p ].get();
251  lp->resetNumOverlaps();
252 
253  lp->getBoundingBox( amin, amax );
254 
255 
256  mActiveCandidatesIndex.intersects( QgsRectangle( amin[0], amin[1], amax[0], amax[1] ), [&lp]( const LabelPosition * lp2 )->bool
257  {
258  if ( lp->isInConflict( lp2 ) )
259  {
260  lp->incrementNumOverlaps();
261  }
262  return true;
263  } );
264 
265  if ( lp->getNumOverlaps() < nbOverlap )
266  {
267  retainedLabel = lp;
268  nbOverlap = lp->getNumOverlaps();
269  }
270  }
271  mSol.activeLabelIds[i] = retainedLabel->getId();
272 
273  retainedLabel->insertIntoIndex( mActiveCandidatesIndex );
274 
275  }
276  }
277  }
278 }
279 
280 inline Chain *Problem::chain( int seed )
281 {
282  int lid;
283 
284  double delta;
285  double delta_min;
286  double delta_best = std::numeric_limits<double>::max();
287  double delta_tmp;
288 
289  int next_seed;
290  int retainedLabel;
291  Chain *retainedChain = nullptr;
292 
293  int max_degree = pal->mEjChainDeg;
294 
295  int seedNbLp;
296 
297  QLinkedList<ElemTrans *> currentChain;
298  QLinkedList<int> conflicts;
299 
300  std::vector< int > tmpsol( mSol.activeLabelIds );
301 
302  LabelPosition *lp = nullptr;
303 
304  double amin[2];
305  double amax[2];
306 
307  delta = 0;
308  while ( seed != -1 )
309  {
310  seedNbLp = mFeatNbLp[seed];
311  delta_min = std::numeric_limits<double>::max();
312 
313  next_seed = -1;
314  retainedLabel = -2;
315 
316  // sol[seed] is ejected
317  if ( tmpsol[seed] == -1 )
318  delta -= mInactiveCost[seed];
319  else
320  delta -= mLabelPositions.at( tmpsol[seed] )->cost();
321 
322  for ( int i = -1; i < seedNbLp; i++ )
323  {
324  try
325  {
326  // Skip active label !
327  if ( !( tmpsol[seed] == -1 && i == -1 ) && i + mFeatStartId[seed] != tmpsol[seed] )
328  {
329  if ( i != -1 ) // new_label
330  {
331  lid = mFeatStartId[seed] + i;
332  delta_tmp = delta;
333 
334  lp = mLabelPositions[ lid ].get();
335 
336  // evaluate conflicts graph in solution after moving seed's label
337 
338  lp->getBoundingBox( amin, amax );
339  mActiveCandidatesIndex.intersects( QgsRectangle( amin[0], amin[1], amax[0], amax[1] ), [lp, &delta_tmp, &conflicts, &currentChain, this]( const LabelPosition * lp2 ) -> bool
340  {
341  if ( lp2->isInConflict( lp ) )
342  {
343  const int feat = lp2->getProblemFeatureId();
344 
345  // is there any cycles ?
346  QLinkedList< ElemTrans * >::iterator cur;
347  for ( cur = currentChain.begin(); cur != currentChain.end(); ++cur )
348  {
349  if ( ( *cur )->feat == feat )
350  {
351  throw - 1;
352  }
353  }
354 
355  if ( !conflicts.contains( feat ) )
356  {
357  conflicts.append( feat );
358  delta_tmp += lp2->cost() + mInactiveCost[feat];
359  }
360  }
361  return true;
362  } );
363 
364  // no conflict -> end of chain
365  if ( conflicts.isEmpty() )
366  {
367  if ( !retainedChain || delta + lp->cost() < delta_best )
368  {
369  if ( retainedChain )
370  {
371  delete[] retainedChain->label;
372  delete[] retainedChain->feat;
373  }
374  else
375  {
376  retainedChain = new Chain();
377  }
378 
379  delta_best = delta + lp->cost();
380 
381  retainedChain->degree = currentChain.size() + 1;
382  retainedChain->feat = new int[retainedChain->degree];
383  retainedChain->label = new int[retainedChain->degree];
384  QLinkedList<ElemTrans *>::iterator current = currentChain.begin();
385  ElemTrans *move = nullptr;
386  int j = 0;
387  while ( current != currentChain.end() )
388  {
389  move = *current;
390  retainedChain->feat[j] = move->feat;
391  retainedChain->label[j] = move->new_label;
392  ++current;
393  ++j;
394  }
395  retainedChain->feat[j] = seed;
396  retainedChain->label[j] = lid;
397  retainedChain->delta = delta + lp->cost();
398  }
399  }
400 
401  // another feature can be ejected
402  else if ( conflicts.size() == 1 )
403  {
404  if ( delta_tmp < delta_min )
405  {
406  delta_min = delta_tmp;
407  retainedLabel = lid;
408  next_seed = conflicts.takeFirst();
409  }
410  else
411  {
412  conflicts.takeFirst();
413  }
414  }
415  else
416  {
417 
418  // A lot of conflict : make them inactive and store chain
419  Chain *newChain = new Chain();
420  newChain->degree = currentChain.size() + 1 + conflicts.size();
421  newChain->feat = new int[newChain->degree];
422  newChain->label = new int[newChain->degree];
423  QLinkedList<ElemTrans *>::iterator current = currentChain.begin();
424  ElemTrans *move = nullptr;
425  int j = 0;
426 
427  while ( current != currentChain.end() )
428  {
429  move = *current;
430  newChain->feat[j] = move->feat;
431  newChain->label[j] = move->new_label;
432  ++current;
433  ++j;
434  }
435 
436  // add the current candidates into the chain
437  newChain->feat[j] = seed;
438  newChain->label[j] = lid;
439  newChain->delta = delta + mLabelPositions.at( newChain->label[j] )->cost();
440  j++;
441 
442  // hide all conflictual candidates
443  while ( !conflicts.isEmpty() )
444  {
445  int ftid = conflicts.takeFirst();
446  newChain->feat[j] = ftid;
447  newChain->label[j] = -1;
448  newChain->delta += mInactiveCost[ftid];
449  j++;
450  }
451 
452  if ( newChain->delta < delta_best )
453  {
454  if ( retainedChain )
455  delete_chain( retainedChain );
456 
457  delta_best = newChain->delta;
458  retainedChain = newChain;
459  }
460  else
461  {
462  delete_chain( newChain );
463  }
464  }
465 
466  }
467  else // Current label == -1 end of chain ...
468  {
469  if ( !retainedChain || delta + mInactiveCost[seed] < delta_best )
470  {
471  if ( retainedChain )
472  {
473  delete[] retainedChain->label;
474  delete[] retainedChain->feat;
475  }
476  else
477  retainedChain = new Chain();
478 
479  delta_best = delta + mInactiveCost[seed];
480 
481  retainedChain->degree = currentChain.size() + 1;
482  retainedChain->feat = new int[retainedChain->degree];
483  retainedChain->label = new int[retainedChain->degree];
484  QLinkedList<ElemTrans *>::iterator current = currentChain.begin();
485  ElemTrans *move = nullptr;
486  int j = 0;
487  while ( current != currentChain.end() )
488  {
489  move = *current;
490  retainedChain->feat[j] = move->feat;
491  retainedChain->label[j] = move->new_label;
492  ++current;
493  ++j;
494  }
495  retainedChain->feat[j] = seed;
496  retainedChain->label[j] = -1;
497  retainedChain->delta = delta + mInactiveCost[seed];
498  }
499  }
500  }
501  }
502  catch ( int )
503  {
504  conflicts.clear();
505  }
506  } // end foreach labelposition
507 
508  if ( next_seed == -1 )
509  {
510  seed = -1;
511  }
512  else if ( currentChain.size() > max_degree )
513  {
514  // Max degree reached
515  seed = -1;
516  }
517  else
518  {
519  ElemTrans *et = new ElemTrans();
520  et->feat = seed;
521  et->old_label = tmpsol[seed];
522  et->new_label = retainedLabel;
523  currentChain.append( et );
524 
525  if ( et->old_label != -1 )
526  {
527  mLabelPositions.at( et->old_label )->removeFromIndex( mActiveCandidatesIndex );
528  }
529 
530  if ( et->new_label != -1 )
531  {
532  mLabelPositions.at( et->new_label )->insertIntoIndex( mActiveCandidatesIndex );
533  }
534 
535 
536  tmpsol[seed] = retainedLabel;
537  // cppcheck-suppress invalidFunctionArg
538  delta += mLabelPositions.at( retainedLabel )->cost();
539  seed = next_seed;
540  }
541  }
542 
543  while ( !currentChain.isEmpty() )
544  {
545  std::unique_ptr< ElemTrans > et( currentChain.takeFirst() );
546 
547  if ( et->new_label != -1 )
548  {
549  mLabelPositions.at( et->new_label )->removeFromIndex( mActiveCandidatesIndex );
550  }
551 
552  if ( et->old_label != -1 )
553  {
554  mLabelPositions.at( et->old_label )->insertIntoIndex( mActiveCandidatesIndex );
555  }
556  }
557 
558  return retainedChain;
559 }
560 
561 
562 void Problem::chain_search()
563 {
564  if ( mFeatureCount == 0 )
565  return;
566 
567  int i;
568  int seed;
569  bool *ok = new bool[mFeatureCount];
570  int fid;
571  int lid;
572  int popit = 0;
573 
574  Chain *retainedChain = nullptr;
575 
576  std::fill( ok, ok + mFeatureCount, false );
577 
578  //initialization();
579  init_sol_falp();
580 
581  //check_solution();
582  solution_cost();
583 
584  int iter = 0;
585 
586  double amin[2];
587  double amax[2];
588 
589  while ( true )
590  {
591 
592  //check_solution();
593 
594  for ( seed = ( iter + 1 ) % mFeatureCount;
595  ok[seed] && seed != iter;
596  seed = ( seed + 1 ) % mFeatureCount )
597  ;
598 
599  // All seeds are OK
600  if ( seed == iter )
601  {
602  break;
603  }
604 
605  iter = ( iter + 1 ) % mFeatureCount;
606  retainedChain = chain( seed );
607 
608  if ( retainedChain && retainedChain->delta < - EPSILON )
609  {
610  // apply modification
611  for ( i = 0; i < retainedChain->degree; i++ )
612  {
613  fid = retainedChain->feat[i];
614  lid = retainedChain->label[i];
615 
616  if ( mSol.activeLabelIds[fid] >= 0 )
617  {
618  LabelPosition *old = mLabelPositions[ mSol.activeLabelIds[fid] ].get();
619  old->removeFromIndex( mActiveCandidatesIndex );
620  old->getBoundingBox( amin, amax );
621  mAllCandidatesIndex.intersects( QgsRectangle( amin[0], amin[1], amax[0], amax[1] ), [&ok, old]( const LabelPosition * lp ) ->bool
622  {
623  if ( old->isInConflict( lp ) )
624  {
625  ok[lp->getProblemFeatureId()] = false;
626  }
627 
628  return true;
629  } );
630  }
631 
632  mSol.activeLabelIds[fid] = lid;
633 
634  if ( mSol.activeLabelIds[fid] >= 0 )
635  {
636  mLabelPositions.at( lid )->insertIntoIndex( mActiveCandidatesIndex );
637  }
638 
639  ok[fid] = false;
640  }
641  mSol.totalCost += retainedChain->delta;
642  }
643  else
644  {
645  // no chain or the one is not god enough
646  ok[seed] = true;
647  }
648 
649  delete_chain( retainedChain );
650  popit++;
651  }
652 
653  solution_cost();
654  delete[] ok;
655 }
656 
657 QList<LabelPosition *> Problem::getSolution( bool returnInactive, QList<LabelPosition *> *unlabeled )
658 {
659  QList<LabelPosition *> finalLabelPlacements;
660 
661  // loop through all features to be labeled
662  for ( std::size_t i = 0; i < mFeatureCount; i++ )
663  {
664  const int labelId = mSol.activeLabelIds[i];
665  const bool foundNonOverlappingPlacement = labelId != -1;
666  const int startIndexForLabelPlacements = mFeatStartId[i];
667  const bool foundCandidatesForFeature = startIndexForLabelPlacements < static_cast< int >( mLabelPositions.size() );
668 
669  if ( foundNonOverlappingPlacement )
670  {
671  finalLabelPlacements.push_back( mLabelPositions[ labelId ].get() ); // active labels
672  }
673  else if ( foundCandidatesForFeature &&
674  ( returnInactive // allowing any overlapping labels regardless of where they are from
675  || mLabelPositions.at( startIndexForLabelPlacements )->getFeaturePart()->layer()->displayAll() // allowing overlapping labels for the layer
676  || mLabelPositions.at( startIndexForLabelPlacements )->getFeaturePart()->alwaysShow() ) ) // allowing overlapping labels for the feature
677  {
678  finalLabelPlacements.push_back( mLabelPositions[ startIndexForLabelPlacements ].get() ); // unplaced label
679  }
680  else if ( unlabeled )
681  {
682  // need to be careful here -- if the next feature's start id is the same as this one, then this feature had no candidates!
683  if ( foundCandidatesForFeature && ( i == mFeatureCount - 1 || startIndexForLabelPlacements != mFeatStartId[i + 1] ) )
684  unlabeled->push_back( mLabelPositions[ startIndexForLabelPlacements ].get() );
685  }
686  }
687 
688  // unlabeled features also include those with no candidates
689  if ( unlabeled )
690  {
691  for ( const std::unique_ptr< LabelPosition > &position : mPositionsWithNoCandidates )
692  unlabeled->append( position.get() );
693  }
694 
695  return finalLabelPlacements;
696 }
697 
698 void Problem::solution_cost()
699 {
700  mSol.totalCost = 0.0;
701 
702  LabelPosition *lp = nullptr;
703 
704  double amin[2];
705  double amax[2];
706 
707  for ( std::size_t i = 0; i < mFeatureCount; i++ )
708  {
709  if ( mSol.activeLabelIds[i] == -1 )
710  {
711  mSol.totalCost += mInactiveCost[i];
712  }
713  else
714  {
715  lp = mLabelPositions[ mSol.activeLabelIds[i] ].get();
716 
717  lp->getBoundingBox( amin, amax );
718  mActiveCandidatesIndex.intersects( QgsRectangle( amin[0], amin[1], amax[0], amax[1] ), [&lp, this]( const LabelPosition * lp2 )->bool
719  {
720  if ( lp->isInConflict( lp2 ) )
721  {
722  mSol.totalCost += mInactiveCost[lp2->getProblemFeatureId()] + lp2->cost();
723  }
724 
725  return true;
726  } );
727 
728  mSol.totalCost += lp->cost();
729  }
730  }
731 }
pal::ElemTrans
Definition: util.h:67
pal::PriorityQueue::getSize
int getSize()
Definition: priorityqueue.cpp:76
PalRtree::intersects
bool intersects(const QgsRectangle &bounds, const std::function< bool(T *data)> &callback) const
Performs an intersection check against the index, for data intersecting the specified bounds.
Definition: palrtree.h:96
pal::LabelPosition::isInConflict
bool isInConflict(const LabelPosition *ls) const
Check whether or not this overlap with another labelPosition.
Definition: labelposition.cpp:265
pal::LabelPosition::getProblemFeatureId
int getProblemFeatureId() const
Definition: labelposition.h:189
pal::Chain::label
int * label
Definition: problem.h:60
pal::ElemTrans::feat
int feat
Definition: util.h:68
labelposition.h
pal::LabelPosition::cost
double cost() const
Returns the candidate label position's geographical cost.
Definition: labelposition.h:206
pal::LabelPosition
LabelPosition is a candidate feature label position.
Definition: labelposition.h:56
EPSILON
#define EPSILON
Definition: util.h:78
pal::PriorityQueue
Definition: priorityqueue.h:52
pal::ElemTrans::old_label
int old_label
Definition: util.h:69
pal::Problem::Problem
Problem(const QgsRectangle &extent)
Constructor for Problem.
Definition: problem.cpp:57
layer.h
pal::PriorityQueue::isIn
bool isIn(int key)
Definition: priorityqueue.cpp:106
QgsRectangle
A rectangle specified with double values.
Definition: qgsrectangle.h:42
pal
Definition: qgsdiagramrenderer.h:49
pal::PriorityQueue::remove
void remove(int key)
Definition: priorityqueue.cpp:134
problem.h
palstat.h
priorityqueue.h
pal::LabelPosition::getBoundingBox
void getBoundingBox(double amin[2], double amax[2]) const
Returns bounding box - amin: xmin,ymin - amax: xmax,ymax.
Definition: labelposition.cpp:379
feature.h
ignoreLabel
void ignoreLabel(const LabelPosition *lp, PriorityQueue &list, PalRtree< LabelPosition > &candidatesIndex)
Definition: problem.cpp:140
pal::LabelPosition::getId
int getId() const
Returns the id.
Definition: labelposition.cpp:346
pal::Problem::reduce
void reduce()
Definition: problem.cpp:66
geomfunction.h
delete_chain
void delete_chain(Chain *chain)
Definition: problem.cpp:47
pal::Problem::init_sol_falp
void init_sol_falp()
Definition: problem.cpp:163
pal::Chain
Definition: problem.h:56
pal::LabelPosition::decrementNumOverlaps
void decrementNumOverlaps()
Decreases the number of overlaps recorded against this position by 1.
Definition: labelposition.h:187
pal::Chain::feat
int * feat
Definition: problem.h:59
pal::LabelPosition::getNumOverlaps
int getNumOverlaps() const
Definition: labelposition.h:176
pal::Problem::~Problem
~Problem()
pal::InternalException::Full
Thrown when something is added in a Full set.
Definition: internalexception.h:51
pal::Problem::getSolution
QList< LabelPosition * > getSolution(bool returnInactive, QList< LabelPosition * > *unlabeled=nullptr)
Solves the labeling problem, selecting the best candidate locations for all labels and returns a list...
Definition: problem.cpp:657
pal::Chain::degree
int degree
Definition: problem.h:57
pal::PriorityQueue::getBest
int getBest()
Definition: priorityqueue.cpp:82
pal::Chain::delta
double delta
Definition: problem.h:58
PalRtree
A rtree spatial index for use in the pal labeling engine.
Definition: palrtree.h:36
internalexception.h
pal::ElemTrans::new_label
int new_label
Definition: util.h:70
pal::LabelPosition::removeFromIndex
void removeFromIndex(PalRtree< LabelPosition > &index)
Removes the label position from the specified index.
Definition: labelposition.cpp:419
pal::LabelPosition::insertIntoIndex
void insertIntoIndex(PalRtree< LabelPosition > &index)
Inserts the label position into the specified index.
Definition: labelposition.cpp:427
pal.h
pal::LabelPosition::resetNumOverlaps
void resetNumOverlaps()
Definition: labelposition.h:177
pal::PriorityQueue::insert
void insert(int key, double p)
Definition: priorityqueue.cpp:116
util.h
qgslabelingengine.h