52 delete[] chain->
label;
58 : mAllCandidatesIndex( extent )
59 , mActiveCandidatesIndex( extent )
66 mLabelPositions.emplace_back( std::move( position ) );
81 bool *ok =
new bool[mTotalCandidates];
84 for ( i = 0; i < mTotalCandidates; i++ )
94 if (
pal->isCanceled() )
98 for ( i = 0; i < static_cast< int >( mFeatureCount ); i++ )
100 if (
pal->isCanceled() )
104 for ( j = 0; j < mFeatNbLp[i]; j++ )
106 if ( !ok[mFeatStartId[i] + j] )
108 if ( mLabelPositions.at( mFeatStartId[i] + j )->getNumOverlaps() == 0 )
111 ok[mFeatStartId[i] + j] =
true;
114 counter += mFeatNbLp[i] - j - 1;
116 for ( k = j + 1; k < mFeatNbLp[i]; k++ )
119 lpid = mFeatStartId[i] + k;
121 lp2 = mLabelPositions[lpid ].get();
126 mAllCandidatesIndex.intersects(
QgsRectangle( amin[0], amin[1], amax[0], amax[1] ), [&lp2,
this](
const LabelPosition * lp ) ->
bool
128 if ( candidatesAreConflicting( lp2, lp ) )
139 mFeatNbLp[i] = j + 1;
147 this->mTotalCandidates -= counter;
162 if ( lp2->
getId() != lp->
getId() && list.
isIn( lp2->
getId() ) && candidatesAreConflicting( lp2, lp ) )
178 mSol.init( mFeatureCount );
187 for (
int i = 0; i < static_cast< int >( mFeatureCount ); i++ )
188 for (
int j = 0; j < mFeatNbLp[i]; j++ )
190 label = mFeatStartId[i] + j;
193 list.
insert( label, mLabelPositions.at( label )->getNumOverlaps() );
203 if (
pal->isCanceled() )
210 lp = mLabelPositions[ label ].get();
212 if ( lp->
getId() != label )
218 mSol.activeLabelIds[probFeatId] = label;
220 for (
int i = mFeatStartId[probFeatId]; i < mFeatStartId[probFeatId] + mFeatNbLp[probFeatId]; i++ )
222 ignoreLabel( mLabelPositions[ i ].get(), list, mAllCandidatesIndex );
228 std::vector< const LabelPosition * > conflictingPositions;
229 mAllCandidatesIndex.intersects(
QgsRectangle( amin[0], amin[1], amax[0], amax[1] ), [lp, &conflictingPositions,
this](
const LabelPosition * lp2 ) ->
bool
231 if ( candidatesAreConflicting( lp, lp2 ) )
233 conflictingPositions.emplace_back( lp2 );
240 ignoreLabel( conflict, list, mAllCandidatesIndex );
243 mActiveCandidatesIndex.insert( lp,
QgsRectangle( amin[0], amin[1], amax[0], amax[1] ) );
253 for ( std::size_t i = 0; i < mFeatureCount; i++ )
255 if ( mSol.activeLabelIds[i] == -1 )
257 nbOverlap = std::numeric_limits<int>::max();
258 start_p = mFeatStartId[i];
259 for ( p = 0; p < mFeatNbLp[i]; p++ )
261 lp = mLabelPositions[ start_p + p ].get();
267 mActiveCandidatesIndex.intersects(
QgsRectangle( amin[0], amin[1], amax[0], amax[1] ), [&lp,
this](
const LabelPosition * lp2 )->
bool
269 if ( candidatesAreConflicting( lp, lp2 ) )
282 mSol.activeLabelIds[i] = retainedLabel->
getId();
293 return pal->candidatesAreConflicting( lp1, lp2 );
296inline Chain *Problem::chain(
int seed )
302 double delta_best = std::numeric_limits<double>::max();
307 Chain *retainedChain =
nullptr;
309 const int max_degree =
pal->mEjChainDeg;
313 QLinkedList<ElemTrans *> currentChain;
314 QLinkedList<int> conflicts;
316 std::vector< int > tmpsol( mSol.activeLabelIds );
326 seedNbLp = mFeatNbLp[seed];
327 delta_min = std::numeric_limits<double>::max();
333 if ( tmpsol[seed] == -1 )
334 delta -= mInactiveCost[seed];
336 delta -= mLabelPositions.at( tmpsol[seed] )->cost();
338 for (
int i = -1; i < seedNbLp; i++ )
343 if ( !( tmpsol[seed] == -1 && i == -1 ) && i + mFeatStartId[seed] != tmpsol[seed] )
347 lid = mFeatStartId[seed] + i;
350 lp = mLabelPositions[ lid ].get();
355 mActiveCandidatesIndex.intersects(
QgsRectangle( amin[0], amin[1], amax[0], amax[1] ), [lp, &delta_tmp, &conflicts, ¤tChain,
this](
const LabelPosition * lp2 ) ->
bool
357 if ( candidatesAreConflicting( lp2, lp ) )
362 QLinkedList< ElemTrans * >::iterator cur;
363 for ( cur = currentChain.begin(); cur != currentChain.end(); ++cur )
365 if ( ( *cur )->feat == feat )
371 if ( !conflicts.contains( feat ) )
373 conflicts.append( feat );
374 delta_tmp += lp2->cost() + mInactiveCost[feat];
381 if ( conflicts.isEmpty() )
383 if ( !retainedChain || delta + lp->
cost() < delta_best )
387 delete[] retainedChain->
label;
388 delete[] retainedChain->
feat;
392 retainedChain =
new Chain();
395 delta_best = delta + lp->
cost();
397 retainedChain->
degree = currentChain.size() + 1;
398 retainedChain->
feat =
new int[retainedChain->
degree];
399 retainedChain->
label =
new int[retainedChain->
degree];
400 QLinkedList<ElemTrans *>::iterator current = currentChain.begin();
403 while ( current != currentChain.end() )
406 retainedChain->
feat[j] = move->
feat;
411 retainedChain->
feat[j] = seed;
412 retainedChain->
label[j] = lid;
413 retainedChain->
delta = delta + lp->
cost();
418 else if ( conflicts.size() == 1 )
420 if ( delta_tmp < delta_min )
422 delta_min = delta_tmp;
424 next_seed = conflicts.takeFirst();
428 conflicts.takeFirst();
436 newChain->
degree = currentChain.size() + 1 + conflicts.size();
439 QLinkedList<ElemTrans *>::iterator current = currentChain.begin();
443 while ( current != currentChain.end() )
453 newChain->
feat[j] = seed;
454 newChain->
label[j] = lid;
455 newChain->
delta = delta + mLabelPositions.at( newChain->
label[j] )->cost();
459 while ( !conflicts.isEmpty() )
461 const int ftid = conflicts.takeFirst();
462 newChain->
feat[j] = ftid;
463 newChain->
label[j] = -1;
464 newChain->
delta += mInactiveCost[ftid];
468 if ( newChain->
delta < delta_best )
473 delta_best = newChain->
delta;
474 retainedChain = newChain;
485 if ( !retainedChain || delta + mInactiveCost[seed] < delta_best )
489 delete[] retainedChain->
label;
490 delete[] retainedChain->
feat;
493 retainedChain =
new Chain();
495 delta_best = delta + mInactiveCost[seed];
497 retainedChain->
degree = currentChain.size() + 1;
498 retainedChain->
feat =
new int[retainedChain->
degree];
499 retainedChain->
label =
new int[retainedChain->
degree];
500 QLinkedList<ElemTrans *>::iterator current = currentChain.begin();
503 while ( current != currentChain.end() )
506 retainedChain->
feat[j] = move->
feat;
511 retainedChain->
feat[j] = seed;
512 retainedChain->
label[j] = -1;
513 retainedChain->
delta = delta + mInactiveCost[seed];
524 if ( next_seed == -1 )
528 else if ( currentChain.size() > max_degree )
539 currentChain.append( et );
543 mLabelPositions.at( et->
old_label )->removeFromIndex( mActiveCandidatesIndex );
548 mLabelPositions.at( et->
new_label )->insertIntoIndex( mActiveCandidatesIndex );
552 tmpsol[seed] = retainedLabel;
554 delta += mLabelPositions.at( retainedLabel )->cost();
559 while ( !currentChain.isEmpty() )
561 std::unique_ptr< ElemTrans > et( currentChain.takeFirst() );
565 mLabelPositions.at( et->
new_label )->removeFromIndex( mActiveCandidatesIndex );
570 mLabelPositions.at( et->
old_label )->insertIntoIndex( mActiveCandidatesIndex );
574 return retainedChain;
580 if ( mFeatureCount == 0 )
585 bool *ok =
new bool[mFeatureCount];
589 Chain *retainedChain =
nullptr;
591 std::fill( ok, ok + mFeatureCount,
false );
602 for ( seed = ( iter + 1 ) % mFeatureCount;
603 ok[seed] && seed != iter;
604 seed = ( seed + 1 ) % mFeatureCount )
613 iter = ( iter + 1 ) % mFeatureCount;
614 retainedChain = chain( seed );
616 if ( retainedChain && retainedChain->
delta < -
EPSILON )
619 for ( i = 0; i < retainedChain->
degree; i++ )
621 fid = retainedChain->
feat[i];
622 lid = retainedChain->
label[i];
624 if ( mSol.activeLabelIds[fid] >= 0 )
626 LabelPosition *old = mLabelPositions[ mSol.activeLabelIds[fid] ].get();
629 mAllCandidatesIndex.intersects(
QgsRectangle( amin[0], amin[1], amax[0], amax[1] ), [&ok, old,
this](
const LabelPosition * lp ) ->
bool
631 if ( candidatesAreConflicting( old, lp ) )
640 mSol.activeLabelIds[fid] = lid;
642 if ( mSol.activeLabelIds[fid] >= 0 )
644 mLabelPositions.at( lid )->insertIntoIndex( mActiveCandidatesIndex );
664 QList<LabelPosition *> finalLabelPlacements;
665 finalLabelPlacements.reserve( mFeatureCount );
668 for ( std::size_t i = 0; i < mFeatureCount; i++ )
670 const int labelId = mSol.activeLabelIds[i];
671 const bool foundNonOverlappingPlacement = labelId != -1;
672 const int startIndexForLabelPlacements = mFeatStartId[i];
673 const bool foundCandidatesForFeature = startIndexForLabelPlacements < static_cast< int >( mLabelPositions.size() );
675 if ( foundNonOverlappingPlacement )
677 finalLabelPlacements.push_back( mLabelPositions[ labelId ].get() );
679 else if ( foundCandidatesForFeature &&
682 || mLabelPositions.at( startIndexForLabelPlacements )->getFeaturePart()->alwaysShow() ) )
684 finalLabelPlacements.push_back( mLabelPositions[ startIndexForLabelPlacements ].get() );
686 else if ( unlabeled )
689 if ( foundCandidatesForFeature && ( i == mFeatureCount - 1 || startIndexForLabelPlacements != mFeatStartId[i + 1] ) )
690 unlabeled->push_back( mLabelPositions[ startIndexForLabelPlacements ].get() );
697 unlabeled->reserve( mPositionsWithNoCandidates.size() );
698 for (
const std::unique_ptr< LabelPosition > &position : mPositionsWithNoCandidates )
699 unlabeled->append( position.get() );
702 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.
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...
void addCandidatePosition(std::unique_ptr< LabelPosition > position)
Adds a candidate label position to the problem.
void chainSearch(QgsRenderContext &context)
Test with very-large scale neighborhood.
void delete_chain(Chain *chain)