47 : mAllCandidatesIndex( extent )
48 , mActiveCandidatesIndex( extent )
53 mLabelPositions.emplace_back( std::move( position ) );
66 std::vector<bool> ok( mTotalCandidates,
false );
72 if (
pal->isCanceled() )
76 for ( std::size_t feature = 0; feature < mFeatureCount; feature++ )
78 if (
pal->isCanceled() )
82 const int totalCandidatesForFeature = mCandidateCountForFeature[feature];
83 for (
int candidateIndex = 0; candidateIndex < totalCandidatesForFeature; candidateIndex++ )
85 if ( !ok[mFirstCandidateIndexForFeature[feature] + candidateIndex] )
87 if ( mLabelPositions.at( mFirstCandidateIndexForFeature[feature] + candidateIndex )->getNumOverlaps() == 0 )
90 ok[mFirstCandidateIndexForFeature[feature] + candidateIndex] =
true;
93 counter += totalCandidatesForFeature - candidateIndex - 1;
95 for ( k = candidateIndex + 1; k < totalCandidatesForFeature; k++ )
97 lpid = mFirstCandidateIndexForFeature[feature] + k;
99 lp2 = mLabelPositions[lpid].get();
105 if ( candidatesAreConflicting( lp2, lp ) )
116 mCandidateCountForFeature[feature] = candidateIndex + 1;
127 this->mTotalCandidates -= counter;
138 if ( lp2->
getId() != lp->
getId() && list.
isIn( lp2->
getId() ) && candidatesAreConflicting( lp2, lp ) )
154 mSol.init( mFeatureCount );
160 for (
int feature = 0; feature < static_cast< int >( mFeatureCount ); feature++ )
162 const int totalCandidatesForFeature = mCandidateCountForFeature[feature];
163 for (
int candidateIndex = 0; candidateIndex < totalCandidatesForFeature; candidateIndex++ )
165 label = mFirstCandidateIndexForFeature[feature] + candidateIndex;
168 list.
insert( label, mLabelPositions.at( label )->getNumOverlaps() );
179 if (
pal->isCanceled() )
186 lp = mLabelPositions[label].get();
188 if ( lp->
getId() != label )
194 mSol.activeLabelIds[probFeatId] = label;
196 for (
int candidateIndex = mFirstCandidateIndexForFeature[probFeatId]; candidateIndex < mFirstCandidateIndexForFeature[probFeatId] + mCandidateCountForFeature[probFeatId]; candidateIndex++ )
198 ignoreLabel( mLabelPositions[candidateIndex].get(), list, mAllCandidatesIndex );
203 std::vector< const LabelPosition * > conflictingPositions;
204 mAllCandidatesIndex.
intersects( searchBounds, [lp, &conflictingPositions,
this](
const LabelPosition *lp2 ) ->
bool {
205 if ( candidatesAreConflicting( lp, lp2 ) )
207 conflictingPositions.emplace_back( lp2 );
214 ignoreLabel( conflict, list, mAllCandidatesIndex );
224 for ( std::size_t i = 0; i < mFeatureCount; i++ )
226 if ( mSol.activeLabelIds[i] == -1 )
228 int nbOverlap = std::numeric_limits<int>::max();
229 const int firstCandidateIdForFeature = mFirstCandidateIndexForFeature[i];
230 const int totalCandidatesForFeature = mCandidateCountForFeature[i];
231 for (
int candidateIndexForFeature = 0; candidateIndexForFeature < totalCandidatesForFeature; candidateIndexForFeature++ )
233 lp = mLabelPositions[firstCandidateIdForFeature + candidateIndexForFeature].get();
238 if ( candidatesAreConflicting( lp, lp2 ) )
251 mSol.activeLabelIds[i] = retainedLabel->
getId();
261 return pal->candidatesAreConflicting( lp1, lp2 );
264inline std::unique_ptr<Chain> Problem::chain(
int seed )
270 double delta_best = std::numeric_limits<double>::max();
275 std::unique_ptr< Chain > retainedChain;
277 const int max_degree =
pal->mEjChainDeg;
279 QVector<ElemTrans *> currentChain;
280 QVector<int> conflicts;
282 std::vector< int > tmpsol( mSol.activeLabelIds );
291 const int totalCandidatesForThisFeature = mCandidateCountForFeature[seed];
292 delta_min = std::numeric_limits<double>::max();
298 if ( tmpsol[seed] == -1 )
299 delta -= mUnlabeledCostForFeature[seed];
301 delta -= mLabelPositions.at( tmpsol[seed] )->cost();
303 for (
int i = -1; i < totalCandidatesForThisFeature; i++ )
308 if ( !( tmpsol[seed] == -1 && i == -1 ) && i + mFirstCandidateIndexForFeature[seed] != tmpsol[seed] )
312 lid = mFirstCandidateIndexForFeature[seed] + i;
315 lp = mLabelPositions[lid].get();
319 mActiveCandidatesIndex.intersects( searchBounds, [lp, &delta_tmp, &conflicts, ¤tChain,
this](
const LabelPosition *lp2 ) ->
bool {
320 if ( candidatesAreConflicting( lp2, lp ) )
325 for (
auto cur = currentChain.begin(); cur != currentChain.end(); ++cur )
327 if ( ( *cur )->feat == feat )
333 if ( !conflicts.contains( feat ) )
335 conflicts.append( feat );
336 delta_tmp += lp2->
cost() + mUnlabeledCostForFeature[feat];
343 if ( conflicts.isEmpty() )
345 if ( !retainedChain || delta + lp->
cost() < delta_best )
349 retainedChain->label.clear();
350 retainedChain->feat.clear();
354 retainedChain = std::make_unique< Chain >();
357 delta_best = delta + lp->
cost();
359 retainedChain->degree = currentChain.size() + 1;
360 retainedChain->feat.resize( retainedChain->degree );
361 retainedChain->label.resize( retainedChain->degree );
362 QVector<ElemTrans *>::iterator current = currentChain.begin();
363 ElemTrans *move =
nullptr;
365 while ( current != currentChain.end() )
368 retainedChain->feat[j] = move->
feat;
369 retainedChain->label[j] = move->
new_label;
373 retainedChain->feat[j] = seed;
374 retainedChain->label[j] = lid;
375 retainedChain->delta = delta + lp->
cost();
380 else if ( conflicts.size() == 1 )
382 if ( delta_tmp < delta_min )
384 delta_min = delta_tmp;
386 next_seed = conflicts.takeFirst();
390 conflicts.takeFirst();
396 auto newChain = std::make_unique< Chain >();
397 newChain->degree = currentChain.size() + 1 + conflicts.size();
398 newChain->feat.resize( newChain->degree );
399 newChain->label.resize( newChain->degree );
400 QVector<ElemTrans *>::iterator current = currentChain.begin();
401 ElemTrans *move =
nullptr;
404 while ( current != currentChain.end() )
407 newChain->feat[j] = move->
feat;
414 newChain->
feat[j] = seed;
415 newChain->label[j] = lid;
416 newChain->delta = delta + mLabelPositions.at( newChain->label[j] )->cost();
420 while ( !conflicts.isEmpty() )
422 const int ftid = conflicts.takeFirst();
423 newChain->feat[j] = ftid;
424 newChain->label[j] = -1;
425 newChain->delta += mUnlabeledCostForFeature[ftid];
429 if ( newChain->delta < delta_best )
431 delta_best = newChain->delta;
432 retainedChain = std::move( newChain );
442 if ( !retainedChain || delta + mUnlabeledCostForFeature[seed] < delta_best )
446 retainedChain->label.clear();
447 retainedChain->feat.clear();
450 retainedChain = std::make_unique< Chain >();
452 delta_best = delta + mUnlabeledCostForFeature[seed];
454 retainedChain->degree = currentChain.size() + 1;
455 retainedChain->feat.resize( retainedChain->degree );
456 retainedChain->label.resize( retainedChain->degree );
457 QVector<ElemTrans *>::iterator current = currentChain.begin();
458 ElemTrans *move =
nullptr;
460 while ( current != currentChain.end() )
463 retainedChain->feat[j] = move->
feat;
464 retainedChain->label[j] = move->
new_label;
468 retainedChain->feat[j] = seed;
469 retainedChain->label[j] = -1;
470 retainedChain->delta = delta + mUnlabeledCostForFeature[seed];
481 if ( next_seed == -1 )
485 else if ( currentChain.size() > max_degree )
492 ElemTrans *et =
new ElemTrans();
496 currentChain.append( et );
500 mLabelPositions.at( et->
old_label )->removeFromIndex( mActiveCandidatesIndex, pal );
505 mLabelPositions.at( et->
new_label )->insertIntoIndex( mActiveCandidatesIndex, pal );
509 tmpsol[seed] = retainedLabel;
511 delta += mLabelPositions.at( retainedLabel )->cost();
516 while ( !currentChain.isEmpty() )
518 std::unique_ptr< ElemTrans > et( currentChain.takeFirst() );
522 mLabelPositions.at( et->
new_label )->removeFromIndex( mActiveCandidatesIndex, pal );
527 mLabelPositions.at( et->
old_label )->insertIntoIndex( mActiveCandidatesIndex, pal );
531 return retainedChain;
537 if ( mFeatureCount == 0 )
541 std::vector< bool > ok( mFeatureCount,
false );
545 std::unique_ptr< Chain > retainedChain;
555 for ( seed = ( iter + 1 ) % mFeatureCount; ok[seed] && seed != iter; seed = ( seed + 1 ) % mFeatureCount )
564 iter = ( iter + 1 ) % mFeatureCount;
565 retainedChain = chain( seed );
567 if ( retainedChain && retainedChain->delta < -
EPSILON )
570 for ( i = 0; i < retainedChain->degree; i++ )
572 fid = retainedChain->feat[i];
573 lid = retainedChain->label[i];
575 if ( mSol.activeLabelIds[fid] >= 0 )
577 LabelPosition *old = mLabelPositions[mSol.activeLabelIds[fid]].get();
582 if ( candidatesAreConflicting( old, lp ) )
591 mSol.activeLabelIds[fid] = lid;
593 if ( mSol.activeLabelIds[fid] >= 0 )
595 mLabelPositions.at( lid )->insertIntoIndex( mActiveCandidatesIndex,
pal );
611 QList<LabelPosition *> finalLabelPlacements;
612 finalLabelPlacements.reserve( mFeatureCount );
615 for ( std::size_t i = 0; i < mFeatureCount; i++ )
617 const int labelId = mSol.activeLabelIds[i];
618 const bool foundNonOverlappingPlacement = labelId != -1;
619 const int startIndexForLabelPlacements = mFirstCandidateIndexForFeature[i];
620 const bool foundCandidatesForFeature = startIndexForLabelPlacements < static_cast< int >( mLabelPositions.size() );
622 if ( foundNonOverlappingPlacement )
624 finalLabelPlacements.push_back( mLabelPositions[labelId].get() );
626 else if ( foundCandidatesForFeature &&
629 || mLabelPositions.at( startIndexForLabelPlacements )->getFeaturePart()->alwaysShow() ) )
631 finalLabelPlacements.push_back( mLabelPositions[startIndexForLabelPlacements].get() );
633 else if ( unlabeled )
636 if ( foundCandidatesForFeature && ( i == mFeatureCount - 1 || startIndexForLabelPlacements != mFirstCandidateIndexForFeature[i + 1] ) )
637 unlabeled->push_back( mLabelPositions[startIndexForLabelPlacements].get() );
644 unlabeled->reserve( mPositionsWithNoCandidates.size() );
645 for (
const std::unique_ptr< LabelPosition > &position : mPositionsWithNoCandidates )
646 unlabeled->append( position.get() );
649 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.