52     delete[] chain->
label;
 
   58   : mAllCandidatesIndex( extent )
 
   59   , mActiveCandidatesIndex( extent )
 
   76   bool *ok = 
new bool[mTotalCandidates];
 
   79   for ( i = 0; i < mTotalCandidates; i++ )
 
   90     for ( i = 0; i < static_cast< int >( mFeatureCount ); i++ )
 
   93       for ( j = 0; j < mFeatNbLp[i]; j++ )  
 
   95         if ( !ok[mFeatStartId[i] + j] )
 
   97           if ( mLabelPositions.at( mFeatStartId[i] + j )->getNumOverlaps() == 0 ) 
 
  100             ok[mFeatStartId[i] + j] = 
true;
 
  103             counter += mFeatNbLp[i] - j - 1;
 
  105             for ( k = j + 1; k < mFeatNbLp[i]; k++ )
 
  108               lpid = mFeatStartId[i] + k;
 
  110               lp2 = mLabelPositions[lpid ].get();
 
  115               mAllCandidatesIndex.intersects( 
QgsRectangle( amin[0], amin[1], amax[0], amax[1] ), [&lp2, 
this]( 
const LabelPosition * lp ) -> 
bool 
  117                 if ( candidatesAreConflicting( lp2, lp ) )
 
  128             mFeatNbLp[i] = j + 1;
 
  136   this->mTotalCandidates -= counter;
 
  151       if ( lp2->
getId() != lp->
getId() && list.
isIn( lp2->
getId() ) && candidatesAreConflicting( lp2, lp ) )
 
  167   mSol.init( mFeatureCount );
 
  176   for ( 
int i = 0; i < static_cast< int >( mFeatureCount ); i++ )
 
  177     for ( 
int j = 0; j < mFeatNbLp[i]; j++ )
 
  179       label = mFeatStartId[i] + j;
 
  182         list.
insert( label, mLabelPositions.at( label )->getNumOverlaps() );
 
  192     if ( 
pal->isCanceled() )
 
  199     lp = mLabelPositions[ label ].get();
 
  201     if ( lp->
getId() != label )
 
  207     mSol.activeLabelIds[probFeatId] = label;
 
  209     for ( 
int i = mFeatStartId[probFeatId]; i < mFeatStartId[probFeatId] + mFeatNbLp[probFeatId]; i++ )
 
  211       ignoreLabel( mLabelPositions[ i ].get(), list, mAllCandidatesIndex );
 
  217     std::vector< const LabelPosition * > conflictingPositions;
 
  218     mAllCandidatesIndex.intersects( 
QgsRectangle( amin[0], amin[1], amax[0], amax[1] ), [lp, &conflictingPositions, 
this]( 
const LabelPosition * lp2 ) ->
bool 
  220       if ( candidatesAreConflicting( lp, lp2 ) )
 
  222         conflictingPositions.emplace_back( lp2 );
 
  229       ignoreLabel( conflict, list, mAllCandidatesIndex );
 
  232     mActiveCandidatesIndex.insert( lp, 
QgsRectangle( amin[0], amin[1], amax[0], amax[1] ) );
 
  242     for ( std::size_t i = 0; i < mFeatureCount; i++ ) 
 
  244       if ( mSol.activeLabelIds[i] == -1 )
 
  246         nbOverlap = std::numeric_limits<int>::max();
 
  247         start_p = mFeatStartId[i];
 
  248         for ( p = 0; p < mFeatNbLp[i]; p++ )
 
  250           lp = mLabelPositions[ start_p + p ].get();
 
  256           mActiveCandidatesIndex.intersects( 
QgsRectangle( amin[0], amin[1], amax[0], amax[1] ), [&lp, 
this]( 
const LabelPosition * lp2 )->
bool 
  258             if ( candidatesAreConflicting( lp, lp2 ) )
 
  271         mSol.activeLabelIds[i] = retainedLabel->
getId();
 
  282   return  pal->candidatesAreConflicting( lp1, lp2 );
 
  285 inline Chain *Problem::chain( 
int seed )
 
  291   double delta_best = std::numeric_limits<double>::max();
 
  296   Chain *retainedChain = 
nullptr;
 
  298   int max_degree = 
pal->mEjChainDeg;
 
  302   QLinkedList<ElemTrans *> currentChain;
 
  303   QLinkedList<int> conflicts;
 
  305   std::vector< int > tmpsol( mSol.activeLabelIds );
 
  315     seedNbLp = mFeatNbLp[seed];
 
  316     delta_min = std::numeric_limits<double>::max();
 
  322     if ( tmpsol[seed] == -1 )
 
  323       delta -= mInactiveCost[seed];
 
  325       delta -= mLabelPositions.at( tmpsol[seed] )->cost();
 
  327     for ( 
int i = -1; i < seedNbLp; i++ )
 
  332         if ( !( tmpsol[seed] == -1 && i == -1 ) && i + mFeatStartId[seed] != tmpsol[seed] )
 
  336             lid = mFeatStartId[seed] + i;
 
  339             lp = mLabelPositions[ lid ].get();
 
  344             mActiveCandidatesIndex.intersects( 
QgsRectangle( amin[0], amin[1], amax[0], amax[1] ), [lp, &delta_tmp, &conflicts, ¤tChain, 
this]( 
const LabelPosition * lp2 ) -> 
bool 
  346               if ( candidatesAreConflicting( lp2, lp ) )
 
  351                 QLinkedList< ElemTrans * >::iterator cur;
 
  352                 for ( cur = currentChain.begin(); cur != currentChain.end(); ++cur )
 
  354                   if ( ( *cur )->feat == feat )
 
  360                 if ( !conflicts.contains( feat ) )
 
  362                   conflicts.append( feat );
 
  363                   delta_tmp += lp2->cost() + mInactiveCost[feat];
 
  370             if ( conflicts.isEmpty() )
 
  372               if ( !retainedChain || delta + lp->
cost() < delta_best )
 
  376                   delete[] retainedChain->
label;
 
  377                   delete[] retainedChain->
feat;
 
  381                   retainedChain = 
new Chain();
 
  384                 delta_best = delta + lp->
cost();
 
  386                 retainedChain->
degree = currentChain.size() + 1;
 
  387                 retainedChain->
feat  = 
new int[retainedChain->
degree];
 
  388                 retainedChain->
label = 
new int[retainedChain->
degree];
 
  389                 QLinkedList<ElemTrans *>::iterator current = currentChain.begin();
 
  392                 while ( current != currentChain.end() )
 
  395                   retainedChain->
feat[j]  = move->
feat;
 
  400                 retainedChain->
feat[j] = seed;
 
  401                 retainedChain->
label[j] = lid;
 
  402                 retainedChain->
delta = delta + lp->
cost();
 
  407             else if ( conflicts.size() == 1 )
 
  409               if ( delta_tmp < delta_min )
 
  411                 delta_min = delta_tmp;
 
  413                 next_seed = conflicts.takeFirst();
 
  417                 conflicts.takeFirst();
 
  425               newChain->
degree = currentChain.size() + 1 + conflicts.size();
 
  428               QLinkedList<ElemTrans *>::iterator current = currentChain.begin();
 
  432               while ( current != currentChain.end() )
 
  442               newChain->
feat[j] = seed;
 
  443               newChain->
label[j] = lid;
 
  444               newChain->
delta = delta + mLabelPositions.at( newChain->
label[j] )->cost();
 
  448               while ( !conflicts.isEmpty() )
 
  450                 int ftid = conflicts.takeFirst();
 
  451                 newChain->
feat[j] = ftid;
 
  452                 newChain->
label[j] = -1;
 
  453                 newChain->
delta += mInactiveCost[ftid];
 
  457               if ( newChain->
delta < delta_best )
 
  462                 delta_best = newChain->
delta;
 
  463                 retainedChain = newChain;
 
  474             if ( !retainedChain || delta + mInactiveCost[seed] < delta_best )
 
  478                 delete[] retainedChain->
label;
 
  479                 delete[] retainedChain->
feat;
 
  482                 retainedChain = 
new Chain();
 
  484               delta_best = delta + mInactiveCost[seed];
 
  486               retainedChain->
degree = currentChain.size() + 1;
 
  487               retainedChain->
feat  = 
new int[retainedChain->
degree];
 
  488               retainedChain->
label = 
new int[retainedChain->
degree];
 
  489               QLinkedList<ElemTrans *>::iterator current = currentChain.begin();
 
  492               while ( current != currentChain.end() )
 
  495                 retainedChain->
feat[j]  = move->
feat;
 
  500               retainedChain->
feat[j] = seed;
 
  501               retainedChain->
label[j] = -1;
 
  502               retainedChain->
delta = delta + mInactiveCost[seed];
 
  513     if ( next_seed == -1 )
 
  517     else if ( currentChain.size() > max_degree )
 
  528       currentChain.append( et );
 
  532         mLabelPositions.at( et->
old_label )->removeFromIndex( mActiveCandidatesIndex );
 
  537         mLabelPositions.at( et->
new_label )->insertIntoIndex( mActiveCandidatesIndex );
 
  541       tmpsol[seed] = retainedLabel;
 
  543       delta += mLabelPositions.at( retainedLabel )->cost();
 
  548   while ( !currentChain.isEmpty() )
 
  550     std::unique_ptr< ElemTrans > et( currentChain.takeFirst() );
 
  554       mLabelPositions.at( et->
new_label )->removeFromIndex( mActiveCandidatesIndex );
 
  559       mLabelPositions.at( et->
old_label )->insertIntoIndex( mActiveCandidatesIndex );
 
  563   return retainedChain;
 
  567 void Problem::chain_search()
 
  569   if ( mFeatureCount == 0 )
 
  574   bool *ok = 
new bool[mFeatureCount];
 
  579   Chain *retainedChain = 
nullptr;
 
  581   std::fill( ok, ok + mFeatureCount, 
false );
 
  599     for ( seed = ( iter + 1 ) % mFeatureCount;
 
  600           ok[seed] && seed != iter;
 
  601           seed = ( seed + 1 ) % mFeatureCount )
 
  610     iter = ( iter + 1 ) % mFeatureCount;
 
  611     retainedChain = chain( seed );
 
  613     if ( retainedChain && retainedChain->
delta < - 
EPSILON )
 
  616       for ( i = 0; i < retainedChain->
degree; i++ )
 
  618         fid = retainedChain->
feat[i];
 
  619         lid = retainedChain->
label[i];
 
  621         if ( mSol.activeLabelIds[fid] >= 0 )
 
  623           LabelPosition *old = mLabelPositions[ mSol.activeLabelIds[fid] ].get();
 
  626           mAllCandidatesIndex.intersects( 
QgsRectangle( amin[0], amin[1], amax[0], amax[1] ), [&ok, old, 
this]( 
const LabelPosition * lp ) ->
bool 
  628             if ( candidatesAreConflicting( old, lp ) )
 
  637         mSol.activeLabelIds[fid] = lid;
 
  639         if ( mSol.activeLabelIds[fid] >= 0 )
 
  641           mLabelPositions.at( lid )->insertIntoIndex( mActiveCandidatesIndex );
 
  646       mSol.totalCost += retainedChain->
delta;
 
  664   QList<LabelPosition *> finalLabelPlacements;
 
  667   for ( std::size_t i = 0; i < mFeatureCount; i++ )
 
  669     const int labelId = mSol.activeLabelIds[i];
 
  670     const bool foundNonOverlappingPlacement = labelId != -1;
 
  671     const int startIndexForLabelPlacements = mFeatStartId[i];
 
  672     const bool foundCandidatesForFeature = startIndexForLabelPlacements < static_cast< int >( mLabelPositions.size() );
 
  674     if ( foundNonOverlappingPlacement )
 
  676       finalLabelPlacements.push_back( mLabelPositions[ labelId ].get() ); 
 
  678     else if ( foundCandidatesForFeature &&
 
  680                 || mLabelPositions.at( startIndexForLabelPlacements )->getFeaturePart()->layer()->displayAll() 
 
  681                 || mLabelPositions.at( startIndexForLabelPlacements )->getFeaturePart()->alwaysShow() ) ) 
 
  683       finalLabelPlacements.push_back( mLabelPositions[ startIndexForLabelPlacements ].get() ); 
 
  685     else if ( unlabeled )
 
  688       if ( foundCandidatesForFeature && ( i == mFeatureCount - 1 || startIndexForLabelPlacements != mFeatStartId[i + 1] ) )
 
  689         unlabeled->push_back( mLabelPositions[ startIndexForLabelPlacements ].get() );
 
  696     for ( 
const std::unique_ptr< LabelPosition > &position : mPositionsWithNoCandidates )
 
  697       unlabeled->append( position.get() );
 
  700   return finalLabelPlacements;
 
  703 void Problem::solution_cost()
 
  705   mSol.totalCost = 0.0;
 
  712   for ( std::size_t i = 0; i < mFeatureCount; i++ )
 
  714     if ( mSol.activeLabelIds[i] == -1 )
 
  716       mSol.totalCost += mInactiveCost[i];
 
  720       lp = mLabelPositions[ mSol.activeLabelIds[i] ].get();
 
  723       mActiveCandidatesIndex.intersects( 
QgsRectangle( amin[0], amin[1], amax[0], amax[1] ), [&lp, 
this]( 
const LabelPosition * lp2 )->
bool 
  725         if ( candidatesAreConflicting( lp, lp2 ) )
 
  733       mSol.totalCost += lp->
cost();
 
A rtree spatial index for use in the pal labeling engine.
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.
A rectangle specified with double values.
Thrown when something is added in a Full set.
LabelPosition is a candidate feature label position.
void incrementNumOverlaps()
Increases the number of overlaps recorded against this position by 1.
void removeFromIndex(PalRtree< LabelPosition > &index)
Removes the label position from the specified index.
void decrementNumOverlaps()
Decreases the number of overlaps recorded against this position by 1.
int getId() const
Returns the id.
double cost() const
Returns the candidate label position's geographical cost.
int getNumOverlaps() const
int getProblemFeatureId() const
void getBoundingBox(double amin[2], double amax[2]) const
Returns bounding box - amin: xmin,ymin - amax: xmax,ymax.
void insertIntoIndex(PalRtree< LabelPosition > &index)
Inserts the label position into the specified index.
Custom priority queue for use in pal labeling engine.
void decreaseKey(int key)
void insert(int key, double p)
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...
Problem(const QgsRectangle &extent)
Constructor for Problem.
void delete_chain(Chain *chain)