mirror of
https://github.com/qgis/QGIS.git
synced 2025-02-22 00:06:12 -05:00
pal cleanups - better variable names, comments
This commit is contained in:
parent
e002547f50
commit
5e1059946f
@ -328,9 +328,9 @@ std::unique_ptr<Problem> Pal::extractProblem( const QgsRectangle &extent, const
|
||||
|
||||
prob->mFeatureCount = features.size();
|
||||
prob->mTotalCandidates = 0;
|
||||
prob->mFeatNbLp.resize( prob->mFeatureCount );
|
||||
prob->mFeatStartId.resize( prob->mFeatureCount );
|
||||
prob->mInactiveCost.resize( prob->mFeatureCount );
|
||||
prob->mCandidateCountForFeature.resize( prob->mFeatureCount );
|
||||
prob->mFirstCandidateIndexForFeature.resize( prob->mFeatureCount );
|
||||
prob->mUnlabeledCostForFeature.resize( prob->mFeatureCount );
|
||||
|
||||
if ( !features.empty() )
|
||||
{
|
||||
@ -396,17 +396,18 @@ std::unique_ptr<Problem> Pal::extractProblem( const QgsRectangle &extent, const
|
||||
conflictProfile = std::make_unique< QgsScopedRuntimeProfile >( QObject::tr( "Calculating conflicts" ), QStringLiteral( "rendering" ) );
|
||||
}
|
||||
|
||||
int idlp = 0;
|
||||
for ( std::size_t i = 0; i < prob->mFeatureCount; i++ ) /* for each feature into prob */
|
||||
int currentLabelPositionIndex = 0;
|
||||
// loop through all the features registered in the problem
|
||||
for ( std::size_t featureIndex = 0; featureIndex < prob->mFeatureCount; featureIndex++ )
|
||||
{
|
||||
if ( feedback )
|
||||
feedback->setProgress( i * step );
|
||||
feedback->setProgress( featureIndex * step );
|
||||
|
||||
std::unique_ptr< Feats > feat = std::move( features.front() );
|
||||
features.pop_front();
|
||||
|
||||
prob->mFeatStartId[i] = idlp;
|
||||
prob->mInactiveCost[i] = std::pow( 2, 10 - 10 * feat->priority );
|
||||
prob->mFirstCandidateIndexForFeature[featureIndex] = currentLabelPositionIndex;
|
||||
prob->mUnlabeledCostForFeature[featureIndex] = std::pow( 2, 10 - 10 * feat->priority );
|
||||
|
||||
std::size_t maxCandidates = 0;
|
||||
switch ( feat->feature->getGeosType() )
|
||||
@ -520,14 +521,14 @@ std::unique_ptr<Problem> Pal::extractProblem( const QgsRectangle &extent, const
|
||||
return nullptr;
|
||||
|
||||
// update problem's # candidate
|
||||
prob->mFeatNbLp[i] = static_cast< int >( feat->candidates.size() );
|
||||
prob->mCandidateCountForFeature[featureIndex] = static_cast< int >( feat->candidates.size() );
|
||||
prob->mTotalCandidates += static_cast< int >( feat->candidates.size() );
|
||||
|
||||
// add all candidates into a rtree (to speed up conflicts searching)
|
||||
for ( std::unique_ptr< LabelPosition > &candidate : feat->candidates )
|
||||
{
|
||||
candidate->insertIntoIndex( prob->allCandidatesIndex() );
|
||||
candidate->setProblemIds( static_cast< int >( i ), idlp++ );
|
||||
candidate->setProblemIds( static_cast< int >( featureIndex ), currentLabelPositionIndex++ );
|
||||
}
|
||||
features.emplace_back( std::move( feat ) );
|
||||
}
|
||||
|
@ -133,6 +133,17 @@ namespace pal
|
||||
* boundary, which will be used to detect whether a label is visible (or partially visible) in
|
||||
* the rendered map. This may differ from \a extent in the case of rotated or non-rectangular
|
||||
* maps.
|
||||
*
|
||||
* This method:
|
||||
*
|
||||
* - preprocesses features, eg merging connected lines, chopping features at repeat distances
|
||||
* - creates label candidates for every feature
|
||||
* - purges candidates outside the map extent (respecting whether partial labels should be shown at the map boundary)
|
||||
* - creates default fallback candidates for features with no valid candidates
|
||||
* - collects obstacles
|
||||
* - calculates candidate costs
|
||||
* - calculates overlaps/conflicts
|
||||
* - eliminates hard conflicts (forbidden placement)
|
||||
*/
|
||||
std::unique_ptr< Problem > extractProblem( const QgsRectangle &extent, const QgsGeometry &mapBoundary, QgsRenderContext &context );
|
||||
|
||||
|
@ -70,53 +70,47 @@ Problem::~Problem() = default;
|
||||
|
||||
void Problem::reduce()
|
||||
{
|
||||
int i;
|
||||
int j;
|
||||
int k;
|
||||
|
||||
int counter = 0;
|
||||
|
||||
int lpid;
|
||||
|
||||
bool *ok = new bool[mTotalCandidates];
|
||||
bool run = true;
|
||||
|
||||
for ( i = 0; i < mTotalCandidates; i++ )
|
||||
ok[i] = false;
|
||||
|
||||
std::vector<bool> ok( mTotalCandidates, false );
|
||||
|
||||
double amin[2];
|
||||
double amax[2];
|
||||
LabelPosition *lp2 = nullptr;
|
||||
|
||||
while ( run )
|
||||
while ( true )
|
||||
{
|
||||
if ( pal->isCanceled() )
|
||||
break;
|
||||
|
||||
run = false;
|
||||
for ( i = 0; i < static_cast< int >( mFeatureCount ); i++ )
|
||||
bool finished = true;
|
||||
for ( std::size_t feature = 0; feature < mFeatureCount; feature++ )
|
||||
{
|
||||
if ( pal->isCanceled() )
|
||||
break;
|
||||
|
||||
// ok[i] = true;
|
||||
for ( j = 0; j < mFeatNbLp[i]; j++ ) // for each candidate
|
||||
// for each candidate
|
||||
const int totalCandidatesForFeature = mCandidateCountForFeature[feature];
|
||||
for ( int candidateIndex = 0; candidateIndex < totalCandidatesForFeature; candidateIndex++ )
|
||||
{
|
||||
if ( !ok[mFeatStartId[i] + j] )
|
||||
if ( !ok[mFirstCandidateIndexForFeature[feature] + candidateIndex] )
|
||||
{
|
||||
if ( mLabelPositions.at( mFeatStartId[i] + j )->getNumOverlaps() == 0 ) // if candidate has no overlap
|
||||
if ( mLabelPositions.at( mFirstCandidateIndexForFeature[feature] + candidateIndex )->getNumOverlaps() == 0 ) // if candidate has no overlap
|
||||
{
|
||||
run = true;
|
||||
ok[mFeatStartId[i] + j] = true;
|
||||
finished = false;
|
||||
ok[mFirstCandidateIndexForFeature[feature] + candidateIndex] = true;
|
||||
// 1) remove worse candidates from candidates
|
||||
// 2) update nb_overlaps
|
||||
counter += mFeatNbLp[i] - j - 1;
|
||||
counter += totalCandidatesForFeature - candidateIndex - 1;
|
||||
|
||||
for ( k = j + 1; k < mFeatNbLp[i]; k++ )
|
||||
for ( k = candidateIndex + 1; k < totalCandidatesForFeature; k++ )
|
||||
{
|
||||
|
||||
lpid = mFeatStartId[i] + k;
|
||||
lpid = mFirstCandidateIndexForFeature[feature] + k;
|
||||
ok[lpid] = true;
|
||||
lp2 = mLabelPositions[lpid ].get();
|
||||
|
||||
@ -136,16 +130,18 @@ void Problem::reduce()
|
||||
lp2->removeFromIndex( mAllCandidatesIndex );
|
||||
}
|
||||
|
||||
mFeatNbLp[i] = j + 1;
|
||||
mCandidateCountForFeature[feature] = candidateIndex + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( finished )
|
||||
break;
|
||||
}
|
||||
|
||||
this->mTotalCandidates -= counter;
|
||||
delete[] ok;
|
||||
}
|
||||
|
||||
void Problem::ignoreLabel( const LabelPosition *lp, PriorityQueue &list, PalRtree< LabelPosition > &candidatesIndex )
|
||||
@ -184,10 +180,12 @@ void Problem::init_sol_falp()
|
||||
|
||||
LabelPosition *lp = nullptr;
|
||||
|
||||
for ( int i = 0; i < static_cast< int >( mFeatureCount ); i++ )
|
||||
for ( int j = 0; j < mFeatNbLp[i]; j++ )
|
||||
for ( int feature = 0; feature < static_cast< int >( mFeatureCount ); feature++ )
|
||||
{
|
||||
const int totalCandidatesForFeature = mCandidateCountForFeature[feature];
|
||||
for ( int candidateIndex = 0; candidateIndex < totalCandidatesForFeature; candidateIndex++ )
|
||||
{
|
||||
label = mFeatStartId[i] + j;
|
||||
label = mFirstCandidateIndexForFeature[feature] + candidateIndex;
|
||||
try
|
||||
{
|
||||
list.insert( label, mLabelPositions.at( label )->getNumOverlaps() );
|
||||
@ -197,6 +195,7 @@ void Problem::init_sol_falp()
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while ( list.getSize() > 0 ) // O (log size)
|
||||
{
|
||||
@ -217,9 +216,9 @@ void Problem::init_sol_falp()
|
||||
const int probFeatId = lp->getProblemFeatureId();
|
||||
mSol.activeLabelIds[probFeatId] = label;
|
||||
|
||||
for ( int i = mFeatStartId[probFeatId]; i < mFeatStartId[probFeatId] + mFeatNbLp[probFeatId]; i++ )
|
||||
for ( int candidateIndex = mFirstCandidateIndexForFeature[probFeatId]; candidateIndex < mFirstCandidateIndexForFeature[probFeatId] + mCandidateCountForFeature[probFeatId]; candidateIndex++ )
|
||||
{
|
||||
ignoreLabel( mLabelPositions[ i ].get(), list, mAllCandidatesIndex );
|
||||
ignoreLabel( mLabelPositions[ candidateIndex ].get(), list, mAllCandidatesIndex );
|
||||
}
|
||||
|
||||
|
||||
@ -245,20 +244,18 @@ void Problem::init_sol_falp()
|
||||
|
||||
if ( mDisplayAll )
|
||||
{
|
||||
int nbOverlap;
|
||||
int start_p;
|
||||
LabelPosition *retainedLabel = nullptr;
|
||||
int p;
|
||||
|
||||
for ( std::size_t i = 0; i < mFeatureCount; i++ ) // forearch hidden feature
|
||||
{
|
||||
if ( mSol.activeLabelIds[i] == -1 )
|
||||
{
|
||||
nbOverlap = std::numeric_limits<int>::max();
|
||||
start_p = mFeatStartId[i];
|
||||
for ( p = 0; p < mFeatNbLp[i]; p++ )
|
||||
int nbOverlap = std::numeric_limits<int>::max();
|
||||
const int firstCandidateIdForFeature = mFirstCandidateIndexForFeature[i];
|
||||
const int totalCandidatesForFeature = mCandidateCountForFeature[i];
|
||||
for ( int candidateIndexForFeature = 0; candidateIndexForFeature < totalCandidatesForFeature; candidateIndexForFeature++ )
|
||||
{
|
||||
lp = mLabelPositions[ start_p + p ].get();
|
||||
lp = mLabelPositions[ firstCandidateIdForFeature + candidateIndexForFeature ].get();
|
||||
lp->resetNumOverlaps();
|
||||
|
||||
lp->getBoundingBox( amin, amax );
|
||||
@ -308,8 +305,6 @@ inline Chain *Problem::chain( int seed )
|
||||
|
||||
const int max_degree = pal->mEjChainDeg;
|
||||
|
||||
int seedNbLp;
|
||||
|
||||
QLinkedList<ElemTrans *> currentChain;
|
||||
QLinkedList<int> conflicts;
|
||||
|
||||
@ -320,10 +315,12 @@ inline Chain *Problem::chain( int seed )
|
||||
double amin[2];
|
||||
double amax[2];
|
||||
|
||||
// delta is actually related to the cost?
|
||||
delta = 0;
|
||||
// seed is actually the feature number!
|
||||
while ( seed != -1 )
|
||||
{
|
||||
seedNbLp = mFeatNbLp[seed];
|
||||
const int totalCandidatesForThisFeature = mCandidateCountForFeature[seed];
|
||||
delta_min = std::numeric_limits<double>::max();
|
||||
|
||||
next_seed = -1;
|
||||
@ -331,20 +328,20 @@ inline Chain *Problem::chain( int seed )
|
||||
|
||||
// sol[seed] is ejected
|
||||
if ( tmpsol[seed] == -1 )
|
||||
delta -= mInactiveCost[seed];
|
||||
delta -= mUnlabeledCostForFeature[seed];
|
||||
else
|
||||
delta -= mLabelPositions.at( tmpsol[seed] )->cost();
|
||||
|
||||
for ( int i = -1; i < seedNbLp; i++ )
|
||||
for ( int i = -1; i < totalCandidatesForThisFeature ; i++ )
|
||||
{
|
||||
try
|
||||
{
|
||||
// Skip active label !
|
||||
if ( !( tmpsol[seed] == -1 && i == -1 ) && i + mFeatStartId[seed] != tmpsol[seed] )
|
||||
if ( !( tmpsol[seed] == -1 && i == -1 ) && i + mFirstCandidateIndexForFeature[seed] != tmpsol[seed] )
|
||||
{
|
||||
if ( i != -1 ) // new_label
|
||||
{
|
||||
lid = mFeatStartId[seed] + i;
|
||||
lid = mFirstCandidateIndexForFeature[seed] + i;
|
||||
delta_tmp = delta;
|
||||
|
||||
lp = mLabelPositions[ lid ].get();
|
||||
@ -371,7 +368,7 @@ inline Chain *Problem::chain( int seed )
|
||||
if ( !conflicts.contains( feat ) )
|
||||
{
|
||||
conflicts.append( feat );
|
||||
delta_tmp += lp2->cost() + mInactiveCost[feat];
|
||||
delta_tmp += lp2->cost() + mUnlabeledCostForFeature[feat];
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@ -461,7 +458,7 @@ inline Chain *Problem::chain( int seed )
|
||||
const int ftid = conflicts.takeFirst();
|
||||
newChain->feat[j] = ftid;
|
||||
newChain->label[j] = -1;
|
||||
newChain->delta += mInactiveCost[ftid];
|
||||
newChain->delta += mUnlabeledCostForFeature[ftid];
|
||||
j++;
|
||||
}
|
||||
|
||||
@ -482,7 +479,7 @@ inline Chain *Problem::chain( int seed )
|
||||
}
|
||||
else // Current label == -1 end of chain ...
|
||||
{
|
||||
if ( !retainedChain || delta + mInactiveCost[seed] < delta_best )
|
||||
if ( !retainedChain || delta + mUnlabeledCostForFeature[seed] < delta_best )
|
||||
{
|
||||
if ( retainedChain )
|
||||
{
|
||||
@ -492,7 +489,7 @@ inline Chain *Problem::chain( int seed )
|
||||
else
|
||||
retainedChain = new Chain();
|
||||
|
||||
delta_best = delta + mInactiveCost[seed];
|
||||
delta_best = delta + mUnlabeledCostForFeature[seed];
|
||||
|
||||
retainedChain->degree = currentChain.size() + 1;
|
||||
retainedChain->feat = new int[retainedChain->degree];
|
||||
@ -510,7 +507,7 @@ inline Chain *Problem::chain( int seed )
|
||||
}
|
||||
retainedChain->feat[j] = seed;
|
||||
retainedChain->label[j] = -1;
|
||||
retainedChain->delta = delta + mInactiveCost[seed];
|
||||
retainedChain->delta = delta + mUnlabeledCostForFeature[seed];
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -581,7 +578,6 @@ void Problem::chainSearch( QgsRenderContext & )
|
||||
return;
|
||||
|
||||
int i;
|
||||
int seed;
|
||||
bool *ok = new bool[mFeatureCount];
|
||||
int fid;
|
||||
int lid;
|
||||
@ -597,6 +593,8 @@ void Problem::chainSearch( QgsRenderContext & )
|
||||
double amin[2];
|
||||
double amax[2];
|
||||
|
||||
// seed is actually the feature ID, maybe should be renamed?
|
||||
int seed;
|
||||
while ( true )
|
||||
{
|
||||
for ( seed = ( iter + 1 ) % mFeatureCount;
|
||||
@ -669,7 +667,7 @@ QList<LabelPosition *> Problem::getSolution( bool returnInactive, QList<LabelPos
|
||||
{
|
||||
const int labelId = mSol.activeLabelIds[i];
|
||||
const bool foundNonOverlappingPlacement = labelId != -1;
|
||||
const int startIndexForLabelPlacements = mFeatStartId[i];
|
||||
const int startIndexForLabelPlacements = mFirstCandidateIndexForFeature[i];
|
||||
const bool foundCandidatesForFeature = startIndexForLabelPlacements < static_cast< int >( mLabelPositions.size() );
|
||||
|
||||
if ( foundNonOverlappingPlacement )
|
||||
@ -686,7 +684,7 @@ QList<LabelPosition *> Problem::getSolution( bool returnInactive, QList<LabelPos
|
||||
else if ( unlabeled )
|
||||
{
|
||||
// need to be careful here -- if the next feature's start id is the same as this one, then this feature had no candidates!
|
||||
if ( foundCandidatesForFeature && ( i == mFeatureCount - 1 || startIndexForLabelPlacements != mFeatStartId[i + 1] ) )
|
||||
if ( foundCandidatesForFeature && ( i == mFeatureCount - 1 || startIndexForLabelPlacements != mFirstCandidateIndexForFeature[i + 1] ) )
|
||||
unlabeled->push_back( mLabelPositions[ startIndexForLabelPlacements ].get() );
|
||||
}
|
||||
}
|
||||
|
@ -103,13 +103,16 @@ namespace pal
|
||||
/**
|
||||
* Returns the number of candidates generated for the \a feature at the specified index.
|
||||
*/
|
||||
int featureCandidateCount( int feature ) const { return mFeatNbLp[feature]; }
|
||||
int featureCandidateCount( int feature ) const { return mCandidateCountForFeature[feature]; }
|
||||
|
||||
/**
|
||||
* Returns the candidate corresponding to the specified \a feature and \a candidate index.
|
||||
*/
|
||||
LabelPosition *featureCandidate( int feature, int candidate ) const { return mLabelPositions[ mFeatStartId[feature] + candidate ].get(); }
|
||||
LabelPosition *featureCandidate( int feature, int candidate ) const { return mLabelPositions[ mFirstCandidateIndexForFeature[feature] + candidate ].get(); }
|
||||
|
||||
/**
|
||||
* Gets called AFTER extractProblem.
|
||||
*/
|
||||
void reduce();
|
||||
|
||||
/**
|
||||
@ -201,9 +204,12 @@ namespace pal
|
||||
|
||||
std::vector< std::unique_ptr< LabelPosition > > mPositionsWithNoCandidates;
|
||||
|
||||
std::vector< int > mFeatStartId;
|
||||
std::vector< int > mFeatNbLp;
|
||||
std::vector< double > mInactiveCost;
|
||||
//! Index of the position in mLabelPositions which corresponds to the first candidate for a feature, array index corresponds to label feature index
|
||||
std::vector< int > mFirstCandidateIndexForFeature;
|
||||
//! Total number of registered candidates for each feature, array index corresponds to label feature index
|
||||
std::vector< int > mCandidateCountForFeature;
|
||||
//! Cost for excluding (ie not labeling) a feature, array index corresponds to label feature index
|
||||
std::vector< double > mUnlabeledCostForFeature;
|
||||
|
||||
class Sol
|
||||
{
|
||||
@ -221,6 +227,7 @@ namespace pal
|
||||
Sol mSol;
|
||||
double mNbOverlap = 0.0;
|
||||
|
||||
// seed is actually a feature ID, maybe it should be renamed?
|
||||
Chain *chain( int seed );
|
||||
|
||||
Pal *pal = nullptr;
|
||||
|
Loading…
x
Reference in New Issue
Block a user