52 delete[] chain->
label;
58 : mAllCandidatesIndex( extent )
59 , mActiveCandidatesIndex( extent )
76 bool *ok =
new bool[mTotalCandidates];
79 for ( i = 0; i < mTotalCandidates; i++ )
90 for ( i = 0; i < static_cast< int >( mFeatureCount ); i++ )
93 for ( j = 0; j < mFeatNbLp[i]; j++ )
95 if ( !ok[mFeatStartId[i] + j] )
97 if ( mLabelPositions.at( mFeatStartId[i] + j )->getNumOverlaps() == 0 )
100 ok[mFeatStartId[i] + j] =
true;
103 counter += mFeatNbLp[i] - j - 1;
105 for ( k = j + 1; k < mFeatNbLp[i]; k++ )
108 lpid = mFeatStartId[i] + k;
110 lp2 = mLabelPositions[lpid ].get();
115 mAllCandidatesIndex.intersects(
QgsRectangle( amin[0], amin[1], amax[0], amax[1] ), [&lp2,
this](
const LabelPosition * lp ) ->
bool
117 if ( candidatesAreConflicting( lp2, lp ) )
128 mFeatNbLp[i] = j + 1;
136 this->mTotalCandidates -= counter;
151 if ( lp2->
getId() != lp->
getId() && list.
isIn( lp2->
getId() ) && candidatesAreConflicting( lp2, lp ) )
167 mSol.init( mFeatureCount );
176 for (
int i = 0; i < static_cast< int >( mFeatureCount ); i++ )
177 for (
int j = 0; j < mFeatNbLp[i]; j++ )
179 label = mFeatStartId[i] + j;
182 list.
insert( label, mLabelPositions.at( label )->getNumOverlaps() );
192 if (
pal->isCanceled() )
199 lp = mLabelPositions[ label ].get();
201 if ( lp->
getId() != label )
207 mSol.activeLabelIds[probFeatId] = label;
209 for (
int i = mFeatStartId[probFeatId]; i < mFeatStartId[probFeatId] + mFeatNbLp[probFeatId]; i++ )
211 ignoreLabel( mLabelPositions[ i ].get(), list, mAllCandidatesIndex );
217 std::vector< const LabelPosition * > conflictingPositions;
218 mAllCandidatesIndex.intersects(
QgsRectangle( amin[0], amin[1], amax[0], amax[1] ), [lp, &conflictingPositions,
this](
const LabelPosition * lp2 ) ->
bool
220 if ( candidatesAreConflicting( lp, lp2 ) )
222 conflictingPositions.emplace_back( lp2 );
229 ignoreLabel( conflict, list, mAllCandidatesIndex );
232 mActiveCandidatesIndex.insert( lp,
QgsRectangle( amin[0], amin[1], amax[0], amax[1] ) );
242 for ( std::size_t i = 0; i < mFeatureCount; i++ )
244 if ( mSol.activeLabelIds[i] == -1 )
246 nbOverlap = std::numeric_limits<int>::max();
247 start_p = mFeatStartId[i];
248 for ( p = 0; p < mFeatNbLp[i]; p++ )
250 lp = mLabelPositions[ start_p + p ].get();
256 mActiveCandidatesIndex.intersects(
QgsRectangle( amin[0], amin[1], amax[0], amax[1] ), [&lp,
this](
const LabelPosition * lp2 )->
bool
258 if ( candidatesAreConflicting( lp, lp2 ) )
271 mSol.activeLabelIds[i] = retainedLabel->
getId();
282 return pal->candidatesAreConflicting( lp1, lp2 );
285 inline Chain *Problem::chain(
int seed )
291 double delta_best = std::numeric_limits<double>::max();
296 Chain *retainedChain =
nullptr;
298 const int max_degree =
pal->mEjChainDeg;
302 QLinkedList<ElemTrans *> currentChain;
303 QLinkedList<int> conflicts;
305 std::vector< int > tmpsol( mSol.activeLabelIds );
315 seedNbLp = mFeatNbLp[seed];
316 delta_min = std::numeric_limits<double>::max();
322 if ( tmpsol[seed] == -1 )
323 delta -= mInactiveCost[seed];
325 delta -= mLabelPositions.at( tmpsol[seed] )->cost();
327 for (
int i = -1; i < seedNbLp; i++ )
332 if ( !( tmpsol[seed] == -1 && i == -1 ) && i + mFeatStartId[seed] != tmpsol[seed] )
336 lid = mFeatStartId[seed] + i;
339 lp = mLabelPositions[ lid ].get();
344 mActiveCandidatesIndex.intersects(
QgsRectangle( amin[0], amin[1], amax[0], amax[1] ), [lp, &delta_tmp, &conflicts, ¤tChain,
this](
const LabelPosition * lp2 ) ->
bool
346 if ( candidatesAreConflicting( lp2, lp ) )
351 QLinkedList< ElemTrans * >::iterator cur;
352 for ( cur = currentChain.begin(); cur != currentChain.end(); ++cur )
354 if ( ( *cur )->feat == feat )
360 if ( !conflicts.contains( feat ) )
362 conflicts.append( feat );
363 delta_tmp += lp2->cost() + mInactiveCost[feat];
370 if ( conflicts.isEmpty() )
372 if ( !retainedChain || delta + lp->
cost() < delta_best )
376 delete[] retainedChain->
label;
377 delete[] retainedChain->
feat;
381 retainedChain =
new Chain();
384 delta_best = delta + lp->
cost();
386 retainedChain->
degree = currentChain.size() + 1;
387 retainedChain->
feat =
new int[retainedChain->
degree];
388 retainedChain->
label =
new int[retainedChain->
degree];
389 QLinkedList<ElemTrans *>::iterator current = currentChain.begin();
392 while ( current != currentChain.end() )
395 retainedChain->
feat[j] = move->
feat;
400 retainedChain->
feat[j] = seed;
401 retainedChain->
label[j] = lid;
402 retainedChain->
delta = delta + lp->
cost();
407 else if ( conflicts.size() == 1 )
409 if ( delta_tmp < delta_min )
411 delta_min = delta_tmp;
413 next_seed = conflicts.takeFirst();
417 conflicts.takeFirst();
425 newChain->
degree = currentChain.size() + 1 + conflicts.size();
428 QLinkedList<ElemTrans *>::iterator current = currentChain.begin();
432 while ( current != currentChain.end() )
442 newChain->
feat[j] = seed;
443 newChain->
label[j] = lid;
444 newChain->
delta = delta + mLabelPositions.at( newChain->
label[j] )->cost();
448 while ( !conflicts.isEmpty() )
450 const int ftid = conflicts.takeFirst();
451 newChain->
feat[j] = ftid;
452 newChain->
label[j] = -1;
453 newChain->
delta += mInactiveCost[ftid];
457 if ( newChain->
delta < delta_best )
462 delta_best = newChain->
delta;
463 retainedChain = newChain;
474 if ( !retainedChain || delta + mInactiveCost[seed] < delta_best )
478 delete[] retainedChain->
label;
479 delete[] retainedChain->
feat;
482 retainedChain =
new Chain();
484 delta_best = delta + mInactiveCost[seed];
486 retainedChain->
degree = currentChain.size() + 1;
487 retainedChain->
feat =
new int[retainedChain->
degree];
488 retainedChain->
label =
new int[retainedChain->
degree];
489 QLinkedList<ElemTrans *>::iterator current = currentChain.begin();
492 while ( current != currentChain.end() )
495 retainedChain->
feat[j] = move->
feat;
500 retainedChain->
feat[j] = seed;
501 retainedChain->
label[j] = -1;
502 retainedChain->
delta = delta + mInactiveCost[seed];
513 if ( next_seed == -1 )
517 else if ( currentChain.size() > max_degree )
528 currentChain.append( et );
532 mLabelPositions.at( et->
old_label )->removeFromIndex( mActiveCandidatesIndex );
537 mLabelPositions.at( et->
new_label )->insertIntoIndex( mActiveCandidatesIndex );
541 tmpsol[seed] = retainedLabel;
543 delta += mLabelPositions.at( retainedLabel )->cost();
548 while ( !currentChain.isEmpty() )
550 std::unique_ptr< ElemTrans > et( currentChain.takeFirst() );
554 mLabelPositions.at( et->
new_label )->removeFromIndex( mActiveCandidatesIndex );
559 mLabelPositions.at( et->
old_label )->insertIntoIndex( mActiveCandidatesIndex );
563 return retainedChain;
567 void Problem::chain_search()
569 if ( mFeatureCount == 0 )
574 bool *ok =
new bool[mFeatureCount];
579 Chain *retainedChain =
nullptr;
581 std::fill( ok, ok + mFeatureCount,
false );
592 for ( seed = ( iter + 1 ) % mFeatureCount;
593 ok[seed] && seed != iter;
594 seed = ( seed + 1 ) % mFeatureCount )
603 iter = ( iter + 1 ) % mFeatureCount;
604 retainedChain = chain( seed );
606 if ( retainedChain && retainedChain->
delta < -
EPSILON )
609 for ( i = 0; i < retainedChain->
degree; i++ )
611 fid = retainedChain->
feat[i];
612 lid = retainedChain->
label[i];
614 if ( mSol.activeLabelIds[fid] >= 0 )
616 LabelPosition *old = mLabelPositions[ mSol.activeLabelIds[fid] ].get();
619 mAllCandidatesIndex.intersects(
QgsRectangle( amin[0], amin[1], amax[0], amax[1] ), [&ok, old,
this](
const LabelPosition * lp ) ->
bool
621 if ( candidatesAreConflicting( old, lp ) )
630 mSol.activeLabelIds[fid] = lid;
632 if ( mSol.activeLabelIds[fid] >= 0 )
634 mLabelPositions.at( lid )->insertIntoIndex( mActiveCandidatesIndex );
655 QList<LabelPosition *> finalLabelPlacements;
658 for ( std::size_t i = 0; i < mFeatureCount; i++ )
660 const int labelId = mSol.activeLabelIds[i];
661 const bool foundNonOverlappingPlacement = labelId != -1;
662 const int startIndexForLabelPlacements = mFeatStartId[i];
663 const bool foundCandidatesForFeature = startIndexForLabelPlacements < static_cast< int >( mLabelPositions.size() );
665 if ( foundNonOverlappingPlacement )
667 finalLabelPlacements.push_back( mLabelPositions[ labelId ].get() );
669 else if ( foundCandidatesForFeature &&
671 || mLabelPositions.at( startIndexForLabelPlacements )->getFeaturePart()->layer()->displayAll()
672 || mLabelPositions.at( startIndexForLabelPlacements )->getFeaturePart()->alwaysShow() ) )
674 finalLabelPlacements.push_back( mLabelPositions[ startIndexForLabelPlacements ].get() );
676 else if ( unlabeled )
679 if ( foundCandidatesForFeature && ( i == mFeatureCount - 1 || startIndexForLabelPlacements != mFeatStartId[i + 1] ) )
680 unlabeled->push_back( mLabelPositions[ startIndexForLabelPlacements ].get() );
687 for (
const std::unique_ptr< LabelPosition > &position : mPositionsWithNoCandidates )
688 unlabeled->append( position.get() );
691 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.
A rectangle specified with double values.
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...
Problem(const QgsRectangle &extent)
Constructor for Problem.
void delete_chain(Chain *chain)