53 delete[] chain->
label;
59 : mAllCandidatesIndex( extent )
60 , mActiveCandidatesIndex( extent )
67 mLabelPositions.emplace_back( std::move( position ) );
80 std::vector<bool> ok( mTotalCandidates,
false );
86 if (
pal->isCanceled() )
90 for ( std::size_t feature = 0; feature < mFeatureCount; feature++ )
92 if (
pal->isCanceled() )
96 const int totalCandidatesForFeature = mCandidateCountForFeature[feature];
97 for (
int candidateIndex = 0; candidateIndex < totalCandidatesForFeature; candidateIndex++ )
99 if ( !ok[mFirstCandidateIndexForFeature[feature] + candidateIndex] )
101 if ( mLabelPositions.at( mFirstCandidateIndexForFeature[feature] + candidateIndex )->getNumOverlaps() == 0 )
104 ok[mFirstCandidateIndexForFeature[feature] + candidateIndex] =
true;
107 counter += totalCandidatesForFeature - candidateIndex - 1;
109 for ( k = candidateIndex + 1; k < totalCandidatesForFeature; k++ )
112 lpid = mFirstCandidateIndexForFeature[feature] + k;
114 lp2 = mLabelPositions[lpid ].get();
119 mAllCandidatesIndex.intersects( searchBounds, [&lp2,
this](
const LabelPosition * lp ) ->
bool
121 if ( candidatesAreConflicting( lp2, lp ) )
132 mCandidateCountForFeature[feature] = candidateIndex + 1;
143 this->mTotalCandidates -= counter;
155 if ( lp2->
getId() != lp->
getId() && list.
isIn( lp2->
getId() ) && candidatesAreConflicting( lp2, lp ) )
171 mSol.init( mFeatureCount );
177 for (
int feature = 0; feature < static_cast< int >( mFeatureCount ); feature++ )
179 const int totalCandidatesForFeature = mCandidateCountForFeature[feature];
180 for (
int candidateIndex = 0; candidateIndex < totalCandidatesForFeature; candidateIndex++ )
182 label = mFirstCandidateIndexForFeature[feature] + candidateIndex;
185 list.
insert( label, mLabelPositions.at( label )->getNumOverlaps() );
196 if (
pal->isCanceled() )
203 lp = mLabelPositions[ label ].get();
205 if ( lp->
getId() != label )
211 mSol.activeLabelIds[probFeatId] = label;
213 for (
int candidateIndex = mFirstCandidateIndexForFeature[probFeatId]; candidateIndex < mFirstCandidateIndexForFeature[probFeatId] + mCandidateCountForFeature[probFeatId]; candidateIndex++ )
215 ignoreLabel( mLabelPositions[ candidateIndex ].get(), list, mAllCandidatesIndex );
220 std::vector< const LabelPosition * > conflictingPositions;
221 mAllCandidatesIndex.intersects( searchBounds, [lp, &conflictingPositions,
this](
const LabelPosition * lp2 ) ->
bool
223 if ( candidatesAreConflicting( lp, lp2 ) )
225 conflictingPositions.emplace_back( lp2 );
232 ignoreLabel( conflict, list, mAllCandidatesIndex );
235 mActiveCandidatesIndex.insert( lp, lp->
boundingBox() );
242 for ( std::size_t i = 0; i < mFeatureCount; i++ )
244 if ( mSol.activeLabelIds[i] == -1 )
246 int nbOverlap = std::numeric_limits<int>::max();
247 const int firstCandidateIdForFeature = mFirstCandidateIndexForFeature[i];
248 const int totalCandidatesForFeature = mCandidateCountForFeature[i];
249 for (
int candidateIndexForFeature = 0; candidateIndexForFeature < totalCandidatesForFeature; candidateIndexForFeature++ )
251 lp = mLabelPositions[ firstCandidateIdForFeature + candidateIndexForFeature ].get();
255 mActiveCandidatesIndex.intersects( searchBounds, [&lp,
this](
const LabelPosition * lp2 )->
bool
257 if ( candidatesAreConflicting( lp, lp2 ) )
270 mSol.activeLabelIds[i] = retainedLabel->
getId();
281 return pal->candidatesAreConflicting( lp1, lp2 );
284inline Chain *Problem::chain(
int seed )
290 double delta_best = std::numeric_limits<double>::max();
295 Chain *retainedChain =
nullptr;
297 const int max_degree =
pal->mEjChainDeg;
299 QLinkedList<ElemTrans *> currentChain;
300 QLinkedList<int> conflicts;
302 std::vector< int > tmpsol( mSol.activeLabelIds );
311 const int totalCandidatesForThisFeature = mCandidateCountForFeature[seed];
312 delta_min = std::numeric_limits<double>::max();
318 if ( tmpsol[seed] == -1 )
319 delta -= mUnlabeledCostForFeature[seed];
321 delta -= mLabelPositions.at( tmpsol[seed] )->cost();
323 for (
int i = -1; i < totalCandidatesForThisFeature ; i++ )
328 if ( !( tmpsol[seed] == -1 && i == -1 ) && i + mFirstCandidateIndexForFeature[seed] != tmpsol[seed] )
332 lid = mFirstCandidateIndexForFeature[seed] + i;
335 lp = mLabelPositions[ lid ].get();
339 mActiveCandidatesIndex.intersects( searchBounds, [lp, &delta_tmp, &conflicts, ¤tChain,
this](
const LabelPosition * lp2 ) ->
bool
341 if ( candidatesAreConflicting( lp2, lp ) )
346 QLinkedList< ElemTrans * >::iterator cur;
347 for ( cur = currentChain.begin(); cur != currentChain.end(); ++cur )
349 if ( ( *cur )->feat == feat )
355 if ( !conflicts.contains( feat ) )
357 conflicts.append( feat );
358 delta_tmp += lp2->
cost() + mUnlabeledCostForFeature[feat];
365 if ( conflicts.isEmpty() )
367 if ( !retainedChain || delta + lp->
cost() < delta_best )
371 delete[] retainedChain->
label;
372 delete[] retainedChain->
feat;
376 retainedChain =
new Chain();
379 delta_best = delta + lp->
cost();
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();
387 while ( current != currentChain.end() )
390 retainedChain->
feat[j] = move->
feat;
395 retainedChain->
feat[j] = seed;
396 retainedChain->
label[j] = lid;
397 retainedChain->
delta = delta + lp->
cost();
402 else if ( conflicts.size() == 1 )
404 if ( delta_tmp < delta_min )
406 delta_min = delta_tmp;
408 next_seed = conflicts.takeFirst();
412 conflicts.takeFirst();
420 newChain->
degree = currentChain.size() + 1 + conflicts.size();
423 QLinkedList<ElemTrans *>::iterator current = currentChain.begin();
427 while ( current != currentChain.end() )
437 newChain->
feat[j] = seed;
438 newChain->
label[j] = lid;
439 newChain->
delta = delta + mLabelPositions.at( newChain->
label[j] )->cost();
443 while ( !conflicts.isEmpty() )
445 const int ftid = conflicts.takeFirst();
446 newChain->
feat[j] = ftid;
447 newChain->
label[j] = -1;
448 newChain->
delta += mUnlabeledCostForFeature[ftid];
452 if ( newChain->
delta < delta_best )
457 delta_best = newChain->
delta;
458 retainedChain = newChain;
469 if ( !retainedChain || delta + mUnlabeledCostForFeature[seed] < delta_best )
473 delete[] retainedChain->
label;
474 delete[] retainedChain->
feat;
477 retainedChain =
new Chain();
479 delta_best = delta + mUnlabeledCostForFeature[seed];
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();
487 while ( current != currentChain.end() )
490 retainedChain->
feat[j] = move->
feat;
495 retainedChain->
feat[j] = seed;
496 retainedChain->
label[j] = -1;
497 retainedChain->
delta = delta + mUnlabeledCostForFeature[seed];
508 if ( next_seed == -1 )
512 else if ( currentChain.size() > max_degree )
523 currentChain.append( et );
527 mLabelPositions.at( et->
old_label )->removeFromIndex( mActiveCandidatesIndex );
532 mLabelPositions.at( et->
new_label )->insertIntoIndex( mActiveCandidatesIndex );
536 tmpsol[seed] = retainedLabel;
538 delta += mLabelPositions.at( retainedLabel )->cost();
543 while ( !currentChain.isEmpty() )
545 std::unique_ptr< ElemTrans > et( currentChain.takeFirst() );
549 mLabelPositions.at( et->
new_label )->removeFromIndex( mActiveCandidatesIndex );
554 mLabelPositions.at( et->
old_label )->insertIntoIndex( mActiveCandidatesIndex );
558 return retainedChain;
564 if ( mFeatureCount == 0 )
568 bool *ok =
new bool[mFeatureCount];
572 Chain *retainedChain =
nullptr;
574 std::fill( ok, ok + mFeatureCount,
false );
584 for ( seed = ( iter + 1 ) % mFeatureCount;
585 ok[seed] && seed != iter;
586 seed = ( seed + 1 ) % mFeatureCount )
595 iter = ( iter + 1 ) % mFeatureCount;
596 retainedChain = chain( seed );
598 if ( retainedChain && retainedChain->
delta < -
EPSILON )
601 for ( i = 0; i < retainedChain->
degree; i++ )
603 fid = retainedChain->
feat[i];
604 lid = retainedChain->
label[i];
606 if ( mSol.activeLabelIds[fid] >= 0 )
608 LabelPosition *old = mLabelPositions[ mSol.activeLabelIds[fid] ].get();
612 mAllCandidatesIndex.intersects( searchBounds, [&ok, old,
this](
const LabelPosition * lp ) ->
bool
614 if ( candidatesAreConflicting( old, lp ) )
623 mSol.activeLabelIds[fid] = lid;
625 if ( mSol.activeLabelIds[fid] >= 0 )
627 mLabelPositions.at( lid )->insertIntoIndex( mActiveCandidatesIndex );
647 QList<LabelPosition *> finalLabelPlacements;
648 finalLabelPlacements.reserve( mFeatureCount );
651 for ( std::size_t i = 0; i < mFeatureCount; i++ )
653 const int labelId = mSol.activeLabelIds[i];
654 const bool foundNonOverlappingPlacement = labelId != -1;
655 const int startIndexForLabelPlacements = mFirstCandidateIndexForFeature[i];
656 const bool foundCandidatesForFeature = startIndexForLabelPlacements < static_cast< int >( mLabelPositions.size() );
658 if ( foundNonOverlappingPlacement )
660 finalLabelPlacements.push_back( mLabelPositions[ labelId ].get() );
662 else if ( foundCandidatesForFeature &&
665 || mLabelPositions.at( startIndexForLabelPlacements )->getFeaturePart()->alwaysShow() ) )
667 finalLabelPlacements.push_back( mLabelPositions[ startIndexForLabelPlacements ].get() );
669 else if ( unlabeled )
672 if ( foundCandidatesForFeature && ( i == mFeatureCount - 1 || startIndexForLabelPlacements != mFirstCandidateIndexForFeature[i + 1] ) )
673 unlabeled->push_back( mLabelPositions[ startIndexForLabelPlacements ].get() );
680 unlabeled->reserve( mPositionsWithNoCandidates.size() );
681 for (
const std::unique_ptr< LabelPosition > &position : mPositionsWithNoCandidates )
682 unlabeled->append( position.get() );
685 return finalLabelPlacements;
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.
@ AllowOverlapIfRequired
Avoids overlapping labels when possible, but permit overlaps if labels for features cannot otherwise ...
A rectangle specified with double values.
Contains information about the context of a rendering operation.
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.
QgsRectangle boundingBoxForCandidateConflicts(Pal *pal) const
Returns the bounding box to use for candidate conflicts.
double cost() const
Returns the candidate label position's geographical cost.
int getNumOverlaps() const
int getProblemFeatureId() const
void insertIntoIndex(PalRtree< LabelPosition > &index)
Inserts the label position into the specified index.
QgsRectangle boundingBox() const
Returns bounding box.
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...
void addCandidatePosition(std::unique_ptr< LabelPosition > position)
Adds a candidate label position to the problem.
Problem(const QgsRectangle &extent)
Constructor for Problem.
void chainSearch(QgsRenderContext &context)
Test with very-large scale neighborhood.
void reduce()
Gets called AFTER extractProblem.
void delete_chain(Chain *chain)