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 QVector<ElemTrans *> currentChain;
288 QVector<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 for (
auto cur = currentChain.begin(); cur != currentChain.end(); ++cur )
336 if ( ( *cur )->feat == feat )
342 if ( !conflicts.contains( feat ) )
344 conflicts.append( feat );
345 delta_tmp += lp2->
cost() + mUnlabeledCostForFeature[feat];
352 if ( conflicts.isEmpty() )
354 if ( !retainedChain || delta + lp->
cost() < delta_best )
358 retainedChain->label.clear();
359 retainedChain->feat.clear();
363 retainedChain = std::make_unique< Chain >();
366 delta_best = delta + lp->
cost();
368 retainedChain->degree = currentChain.size() + 1;
369 retainedChain->feat.resize( retainedChain->degree );
370 retainedChain->label.resize( retainedChain->degree );
371 QVector<ElemTrans *>::iterator current = currentChain.begin();
372 ElemTrans *move =
nullptr;
374 while ( current != currentChain.end() )
377 retainedChain->feat[j] = move->
feat;
378 retainedChain->label[j] = move->
new_label;
382 retainedChain->feat[j] = seed;
383 retainedChain->label[j] = lid;
384 retainedChain->delta = delta + lp->
cost();
389 else if ( conflicts.size() == 1 )
391 if ( delta_tmp < delta_min )
393 delta_min = delta_tmp;
395 next_seed = conflicts.takeFirst();
399 conflicts.takeFirst();
406 auto newChain = std::make_unique< Chain >();
407 newChain->degree = currentChain.size() + 1 + conflicts.size();
408 newChain->feat.resize( newChain->degree );
409 newChain->label.resize( newChain->degree );
410 QVector<ElemTrans *>::iterator current = currentChain.begin();
411 ElemTrans *move =
nullptr;
414 while ( current != currentChain.end() )
417 newChain->feat[j] = move->
feat;
424 newChain->
feat[j] = seed;
425 newChain->label[j] = lid;
426 newChain->delta = delta + mLabelPositions.at( newChain->label[j] )->cost();
430 while ( !conflicts.isEmpty() )
432 const int ftid = conflicts.takeFirst();
433 newChain->feat[j] = ftid;
434 newChain->label[j] = -1;
435 newChain->delta += mUnlabeledCostForFeature[ftid];
439 if ( newChain->delta < delta_best )
441 delta_best = newChain->delta;
442 retainedChain = std::move( newChain );
453 if ( !retainedChain || delta + mUnlabeledCostForFeature[seed] < delta_best )
457 retainedChain->label.clear();
458 retainedChain->feat.clear();
461 retainedChain = std::make_unique< Chain >();
463 delta_best = delta + mUnlabeledCostForFeature[seed];
465 retainedChain->degree = currentChain.size() + 1;
466 retainedChain->feat.resize( retainedChain->degree );
467 retainedChain->label.resize( retainedChain->degree );
468 QVector<ElemTrans *>::iterator current = currentChain.begin();
469 ElemTrans *move =
nullptr;
471 while ( current != currentChain.end() )
474 retainedChain->feat[j] = move->
feat;
475 retainedChain->label[j] = move->
new_label;
479 retainedChain->feat[j] = seed;
480 retainedChain->label[j] = -1;
481 retainedChain->delta = delta + mUnlabeledCostForFeature[seed];
492 if ( next_seed == -1 )
496 else if ( currentChain.size() > max_degree )
503 ElemTrans *et =
new ElemTrans();
507 currentChain.append( et );
511 mLabelPositions.at( et->
old_label )->removeFromIndex( mActiveCandidatesIndex, pal );
516 mLabelPositions.at( et->
new_label )->insertIntoIndex( mActiveCandidatesIndex, pal );
520 tmpsol[seed] = retainedLabel;
522 delta += mLabelPositions.at( retainedLabel )->cost();
527 while ( !currentChain.isEmpty() )
529 std::unique_ptr< ElemTrans > et( currentChain.takeFirst() );
533 mLabelPositions.at( et->
new_label )->removeFromIndex( mActiveCandidatesIndex, pal );
538 mLabelPositions.at( et->
old_label )->insertIntoIndex( mActiveCandidatesIndex, pal );
542 return retainedChain;
548 if ( mFeatureCount == 0 )
552 std::vector< bool > ok( mFeatureCount,
false );
556 std::unique_ptr< Chain > retainedChain;
566 for ( seed = ( iter + 1 ) % mFeatureCount;
567 ok[seed] && seed != iter;
568 seed = ( seed + 1 ) % mFeatureCount )
577 iter = ( iter + 1 ) % mFeatureCount;
578 retainedChain = chain( seed );
580 if ( retainedChain && retainedChain->delta < -
EPSILON )
583 for ( i = 0; i < retainedChain->degree; i++ )
585 fid = retainedChain->feat[i];
586 lid = retainedChain->label[i];
588 if ( mSol.activeLabelIds[fid] >= 0 )
590 LabelPosition *old = mLabelPositions[ mSol.activeLabelIds[fid] ].get();
596 if ( candidatesAreConflicting( old, lp ) )
605 mSol.activeLabelIds[fid] = lid;
607 if ( mSol.activeLabelIds[fid] >= 0 )
609 mLabelPositions.at( lid )->insertIntoIndex( mActiveCandidatesIndex,
pal );
625 QList<LabelPosition *> finalLabelPlacements;
626 finalLabelPlacements.reserve( mFeatureCount );
629 for ( std::size_t i = 0; i < mFeatureCount; i++ )
631 const int labelId = mSol.activeLabelIds[i];
632 const bool foundNonOverlappingPlacement = labelId != -1;
633 const int startIndexForLabelPlacements = mFirstCandidateIndexForFeature[i];
634 const bool foundCandidatesForFeature = startIndexForLabelPlacements < static_cast< int >( mLabelPositions.size() );
636 if ( foundNonOverlappingPlacement )
638 finalLabelPlacements.push_back( mLabelPositions[ labelId ].get() );
640 else if ( foundCandidatesForFeature &&
643 || mLabelPositions.at( startIndexForLabelPlacements )->getFeaturePart()->alwaysShow() ) )
645 finalLabelPlacements.push_back( mLabelPositions[ startIndexForLabelPlacements ].get() );
647 else if ( unlabeled )
650 if ( foundCandidatesForFeature && ( i == mFeatureCount - 1 || startIndexForLabelPlacements != mFirstCandidateIndexForFeature[i + 1] ) )
651 unlabeled->push_back( mLabelPositions[ startIndexForLabelPlacements ].get() );
658 unlabeled->reserve( mPositionsWithNoCandidates.size() );
659 for (
const std::unique_ptr< LabelPosition > &position : mPositionsWithNoCandidates )
660 unlabeled->append( position.get() );
663 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.