47 : mAllCandidatesIndex( extent )
48 , mActiveCandidatesIndex( extent )
55 mLabelPositions.emplace_back( std::move( position ) );
68 std::vector<bool> ok( mTotalCandidates,
false );
74 if (
pal->isCanceled() )
78 for ( std::size_t feature = 0; feature < mFeatureCount; feature++ )
80 if (
pal->isCanceled() )
84 const int totalCandidatesForFeature = mCandidateCountForFeature[feature];
85 for (
int candidateIndex = 0; candidateIndex < totalCandidatesForFeature; candidateIndex++ )
87 if ( !ok[mFirstCandidateIndexForFeature[feature] + candidateIndex] )
89 if ( mLabelPositions.at( mFirstCandidateIndexForFeature[feature] + candidateIndex )->getNumOverlaps() == 0 )
92 ok[mFirstCandidateIndexForFeature[feature] + candidateIndex] =
true;
95 counter += totalCandidatesForFeature - candidateIndex - 1;
97 for ( k = candidateIndex + 1; k < totalCandidatesForFeature; k++ )
100 lpid = mFirstCandidateIndexForFeature[feature] + k;
102 lp2 = mLabelPositions[lpid ].get();
109 if ( candidatesAreConflicting( lp2, lp ) )
120 mCandidateCountForFeature[feature] = candidateIndex + 1;
131 this->mTotalCandidates -= counter;
143 if ( lp2->
getId() != lp->
getId() && list.
isIn( lp2->
getId() ) && candidatesAreConflicting( lp2, lp ) )
159 mSol.init( mFeatureCount );
165 for (
int feature = 0; feature < static_cast< int >( mFeatureCount ); feature++ )
167 const int totalCandidatesForFeature = mCandidateCountForFeature[feature];
168 for (
int candidateIndex = 0; candidateIndex < totalCandidatesForFeature; candidateIndex++ )
170 label = mFirstCandidateIndexForFeature[feature] + candidateIndex;
173 list.
insert( label, mLabelPositions.at( label )->getNumOverlaps() );
184 if (
pal->isCanceled() )
191 lp = mLabelPositions[ label ].get();
193 if ( lp->
getId() != label )
199 mSol.activeLabelIds[probFeatId] = label;
201 for (
int candidateIndex = mFirstCandidateIndexForFeature[probFeatId]; candidateIndex < mFirstCandidateIndexForFeature[probFeatId] + mCandidateCountForFeature[probFeatId]; candidateIndex++ )
203 ignoreLabel( mLabelPositions[ candidateIndex ].get(), list, mAllCandidatesIndex );
208 std::vector< const LabelPosition * > conflictingPositions;
209 mAllCandidatesIndex.
intersects( searchBounds, [lp, &conflictingPositions,
this](
const LabelPosition * lp2 ) ->
bool
211 if ( candidatesAreConflicting( lp, lp2 ) )
213 conflictingPositions.emplace_back( lp2 );
220 ignoreLabel( conflict, list, mAllCandidatesIndex );
230 for ( std::size_t i = 0; i < mFeatureCount; i++ )
232 if ( mSol.activeLabelIds[i] == -1 )
234 int nbOverlap = std::numeric_limits<int>::max();
235 const int firstCandidateIdForFeature = mFirstCandidateIndexForFeature[i];
236 const int totalCandidatesForFeature = mCandidateCountForFeature[i];
237 for (
int candidateIndexForFeature = 0; candidateIndexForFeature < totalCandidatesForFeature; candidateIndexForFeature++ )
239 lp = mLabelPositions[ firstCandidateIdForFeature + candidateIndexForFeature ].get();
245 if ( candidatesAreConflicting( lp, lp2 ) )
258 mSol.activeLabelIds[i] = retainedLabel->
getId();
269 return pal->candidatesAreConflicting( lp1, lp2 );
272inline std::unique_ptr<Chain> Problem::chain(
int seed )
278 double delta_best = std::numeric_limits<double>::max();
283 std::unique_ptr< Chain > retainedChain;
285 const int max_degree =
pal->mEjChainDeg;
287 QLinkedList<ElemTrans *> currentChain;
288 QLinkedList<int> conflicts;
290 std::vector< int > tmpsol( mSol.activeLabelIds );
299 const int totalCandidatesForThisFeature = mCandidateCountForFeature[seed];
300 delta_min = std::numeric_limits<double>::max();
306 if ( tmpsol[seed] == -1 )
307 delta -= mUnlabeledCostForFeature[seed];
309 delta -= mLabelPositions.at( tmpsol[seed] )->cost();
311 for (
int i = -1; i < totalCandidatesForThisFeature ; i++ )
316 if ( !( tmpsol[seed] == -1 && i == -1 ) && i + mFirstCandidateIndexForFeature[seed] != tmpsol[seed] )
320 lid = mFirstCandidateIndexForFeature[seed] + i;
323 lp = mLabelPositions[ lid ].get();
327 mActiveCandidatesIndex.intersects( searchBounds, [lp, &delta_tmp, &conflicts, ¤tChain,
this](
const LabelPosition * lp2 ) ->
bool
329 if ( candidatesAreConflicting( lp2, lp ) )
334 QLinkedList< ElemTrans * >::iterator cur;
335 for ( cur = currentChain.begin(); cur != currentChain.end(); ++cur )
337 if ( ( *cur )->feat == feat )
343 if ( !conflicts.contains( feat ) )
345 conflicts.append( feat );
346 delta_tmp += lp2->
cost() + mUnlabeledCostForFeature[feat];
353 if ( conflicts.isEmpty() )
355 if ( !retainedChain || delta + lp->
cost() < delta_best )
359 retainedChain->label.clear();
360 retainedChain->feat.clear();
364 retainedChain = std::make_unique< Chain >();
367 delta_best = delta + lp->
cost();
369 retainedChain->degree = currentChain.size() + 1;
370 retainedChain->feat.resize( retainedChain->degree );
371 retainedChain->label.resize( retainedChain->degree );
372 QLinkedList<ElemTrans *>::iterator current = currentChain.begin();
373 ElemTrans *move =
nullptr;
375 while ( current != currentChain.end() )
378 retainedChain->feat[j] = move->
feat;
379 retainedChain->label[j] = move->
new_label;
383 retainedChain->feat[j] = seed;
384 retainedChain->label[j] = lid;
385 retainedChain->delta = delta + lp->
cost();
390 else if ( conflicts.size() == 1 )
392 if ( delta_tmp < delta_min )
394 delta_min = delta_tmp;
396 next_seed = conflicts.takeFirst();
400 conflicts.takeFirst();
407 auto newChain = std::make_unique< Chain >();
408 newChain->degree = currentChain.size() + 1 + conflicts.size();
409 newChain->feat.resize( newChain->degree );
410 newChain->label.resize( newChain->degree );
411 QLinkedList<ElemTrans *>::iterator current = currentChain.begin();
412 ElemTrans *move =
nullptr;
415 while ( current != currentChain.end() )
425 newChain->
feat[j] = seed;
426 newChain->label[j] = lid;
427 newChain->delta = delta + mLabelPositions.at( newChain->label[j] )->cost();
431 while ( !conflicts.isEmpty() )
433 const int ftid = conflicts.takeFirst();
434 newChain->feat[j] = ftid;
435 newChain->label[j] = -1;
436 newChain->delta += mUnlabeledCostForFeature[ftid];
440 if ( newChain->delta < delta_best )
442 delta_best = newChain->delta;
443 retainedChain = std::move( newChain );
454 if ( !retainedChain || delta + mUnlabeledCostForFeature[seed] < delta_best )
458 retainedChain->label.clear();
459 retainedChain->feat.clear();
462 retainedChain = std::make_unique< Chain >();
464 delta_best = delta + mUnlabeledCostForFeature[seed];
466 retainedChain->degree = currentChain.size() + 1;
467 retainedChain->feat.resize( retainedChain->degree );
468 retainedChain->label.resize( retainedChain->degree );
469 QLinkedList<ElemTrans *>::iterator current = currentChain.begin();
470 ElemTrans *move =
nullptr;
472 while ( current != currentChain.end() )
475 retainedChain->feat[j] = move->
feat;
476 retainedChain->label[j] = move->
new_label;
480 retainedChain->feat[j] = seed;
481 retainedChain->label[j] = -1;
482 retainedChain->delta = delta + mUnlabeledCostForFeature[seed];
493 if ( next_seed == -1 )
497 else if ( currentChain.size() > max_degree )
504 ElemTrans *et =
new ElemTrans();
508 currentChain.append( et );
512 mLabelPositions.at( et->
old_label )->removeFromIndex( mActiveCandidatesIndex, pal );
517 mLabelPositions.at( et->
new_label )->insertIntoIndex( mActiveCandidatesIndex, pal );
521 tmpsol[seed] = retainedLabel;
523 delta += mLabelPositions.at( retainedLabel )->cost();
528 while ( !currentChain.isEmpty() )
530 std::unique_ptr< ElemTrans > et( currentChain.takeFirst() );
534 mLabelPositions.at( et->
new_label )->removeFromIndex( mActiveCandidatesIndex, pal );
539 mLabelPositions.at( et->
old_label )->insertIntoIndex( mActiveCandidatesIndex, pal );
543 return retainedChain;
549 if ( mFeatureCount == 0 )
553 std::vector< bool > ok( mFeatureCount,
false );
557 std::unique_ptr< Chain > retainedChain;
567 for ( seed = ( iter + 1 ) % mFeatureCount;
568 ok[seed] && seed != iter;
569 seed = ( seed + 1 ) % mFeatureCount )
578 iter = ( iter + 1 ) % mFeatureCount;
579 retainedChain = chain( seed );
581 if ( retainedChain && retainedChain->delta < -
EPSILON )
584 for ( i = 0; i < retainedChain->degree; i++ )
586 fid = retainedChain->feat[i];
587 lid = retainedChain->label[i];
589 if ( mSol.activeLabelIds[fid] >= 0 )
591 LabelPosition *old = mLabelPositions[ mSol.activeLabelIds[fid] ].get();
597 if ( candidatesAreConflicting( old, lp ) )
606 mSol.activeLabelIds[fid] = lid;
608 if ( mSol.activeLabelIds[fid] >= 0 )
610 mLabelPositions.at( lid )->insertIntoIndex( mActiveCandidatesIndex,
pal );
626 QList<LabelPosition *> finalLabelPlacements;
627 finalLabelPlacements.reserve( mFeatureCount );
630 for ( std::size_t i = 0; i < mFeatureCount; i++ )
632 const int labelId = mSol.activeLabelIds[i];
633 const bool foundNonOverlappingPlacement = labelId != -1;
634 const int startIndexForLabelPlacements = mFirstCandidateIndexForFeature[i];
635 const bool foundCandidatesForFeature = startIndexForLabelPlacements < static_cast< int >( mLabelPositions.size() );
637 if ( foundNonOverlappingPlacement )
639 finalLabelPlacements.push_back( mLabelPositions[ labelId ].get() );
641 else if ( foundCandidatesForFeature &&
644 || mLabelPositions.at( startIndexForLabelPlacements )->getFeaturePart()->alwaysShow() ) )
646 finalLabelPlacements.push_back( mLabelPositions[ startIndexForLabelPlacements ].get() );
648 else if ( unlabeled )
651 if ( foundCandidatesForFeature && ( i == mFeatureCount - 1 || startIndexForLabelPlacements != mFirstCandidateIndexForFeature[i + 1] ) )
652 unlabeled->push_back( mLabelPositions[ startIndexForLabelPlacements ].get() );
659 unlabeled->reserve( mPositionsWithNoCandidates.size() );
660 for (
const std::unique_ptr< LabelPosition > &position : mPositionsWithNoCandidates )
661 unlabeled->append( position.get() );
664 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.
bool intersects(const QgsRectangle &rect) const
Returns true when rectangle intersects with other rectangle.
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 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.
void removeFromIndex(PalRtree< LabelPosition > &index, Pal *pal)
Removes the label position from the specified index.
double cost() const
Returns the candidate label position's geographical cost.
int getNumOverlaps() const
int getProblemFeatureId() const
void insertIntoIndex(PalRtree< LabelPosition > &index, Pal *pal)
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...
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.