diff --git a/src/core/pal/costcalculator.cpp b/src/core/pal/costcalculator.cpp index 29a13d78342..5117850891a 100644 --- a/src/core/pal/costcalculator.cpp +++ b/src/core/pal/costcalculator.cpp @@ -35,7 +35,7 @@ bool CostCalculator::candidateSortShrink( const std::unique_ptr< LabelPosition > return c1->cost() > c2->cost(); } -void CostCalculator::addObstacleCostPenalty( LabelPosition *lp, FeaturePart *obstacle ) +void CostCalculator::addObstacleCostPenalty( LabelPosition *lp, FeaturePart *obstacle, Pal *pal ) { int n = 0; double dist; @@ -83,11 +83,30 @@ void CostCalculator::addObstacleCostPenalty( LabelPosition *lp, FeaturePart *obs break; } + //scale cost by obstacle's factor + double obstacleCost = obstacle->obstacleFactor() * double( n ); if ( n > 0 ) lp->setConflictsWithObstacle( true ); - //scale cost by obstacle's factor - double obstacleCost = obstacle->obstacleFactor() * double( n ); + switch ( pal->placementVersion() ) + { + case QgsLabelingEngineSettings::PlacementEngineVersion1: + break; + + case QgsLabelingEngineSettings::PlacementEngineVersion2: + { + // obstacle factor is from 0 -> 2, label priority is from 1 -> 0. argh! + const double priority = 2 * ( 1 - lp->feature->calculatePriority() ); + const double obstaclePriority = obstacle->obstacleFactor(); + + // if feature priority is < obstaclePriorty, there's a hard conflict... + if ( n > 0 && ( priority < obstaclePriority && !qgsDoubleNear( priority, obstaclePriority, 0.001 ) ) ) + { + lp->setHasHardObstacleConflict( true ); + } + break; + } + } // label cost is penalized lp->setCost( lp->cost() + obstacleCost ); @@ -185,6 +204,7 @@ std::size_t CostCalculator::finalizeCandidatesCosts( Feats *feat, std::size_t ma } while ( stop == 0 && discrim < feat->candidates.back()->cost() + 2.0 ); + // THIS LOOKS SUSPICIOUS -- it clamps all costs to a fixed value?? if ( discrim > 1.5 ) { for ( std::size_t k = 0; k < stop; k++ ) diff --git a/src/core/pal/costcalculator.h b/src/core/pal/costcalculator.h index 307b1290576..0918e5eec8e 100644 --- a/src/core/pal/costcalculator.h +++ b/src/core/pal/costcalculator.h @@ -29,6 +29,7 @@ namespace pal { class Feats; class LabelPosition; + class Pal; /** * \ingroup core @@ -37,7 +38,7 @@ namespace pal { public: //! Increase candidate's cost according to its collision with passed feature - static void addObstacleCostPenalty( LabelPosition *lp, pal::FeaturePart *obstacle ); + static void addObstacleCostPenalty( LabelPosition *lp, pal::FeaturePart *obstacle, Pal *pal ); //! Calculates the costs for polygon label candidates static void setPolygonCandidatesCost( std::size_t nblp, std::vector > &lPos, RTree *obstacles, double bbx[4], double bby[4] ); diff --git a/src/core/pal/labelposition.cpp b/src/core/pal/labelposition.cpp index 6bc7bbfc7e9..9c3aa809cd1 100644 --- a/src/core/pal/labelposition.cpp +++ b/src/core/pal/labelposition.cpp @@ -407,6 +407,13 @@ void LabelPosition::setConflictsWithObstacle( bool conflicts ) nextPart->setConflictsWithObstacle( conflicts ); } +void LabelPosition::setHasHardObstacleConflict( bool conflicts ) +{ + mHasHardConflict = conflicts; + if ( nextPart ) + nextPart->setHasHardObstacleConflict( conflicts ); +} + bool LabelPosition::polygonObstacleCallback( FeaturePart *obstacle, void *ctx ) { PolygonCostCalculator *pCost = reinterpret_cast< PolygonCostCalculator * >( ctx ); @@ -453,7 +460,7 @@ bool LabelPosition::pruneCallback( LabelPosition *candidatePosition, void *ctx ) return true; } - CostCalculator::addObstacleCostPenalty( candidatePosition, obstaclePart ); + CostCalculator::addObstacleCostPenalty( candidatePosition, obstaclePart, ( reinterpret_cast< PruneCtx * >( ctx ) )->pal ); return true; } diff --git a/src/core/pal/labelposition.h b/src/core/pal/labelposition.h index 291a054e536..e6fb99f6b95 100644 --- a/src/core/pal/labelposition.h +++ b/src/core/pal/labelposition.h @@ -217,6 +217,22 @@ namespace pal */ bool conflictsWithObstacle() const { return mHasObstacleConflict; } + /** + * Sets whether the position is marked as having a hard conflict with an obstacle feature. + * A hard conflict means that the placement should (usually) not be considered, because the candidate + * conflicts with a obstacle of sufficient weight. + * \see hasHardObstacleConflict() + */ + void setHasHardObstacleConflict( bool conflicts ); + + /** + * Returns whether the position is marked as having a hard conflict with an obstacle feature. + * A hard conflict means that the placement should (usually) not be considered, because the candidate + * conflicts with a obstacle of sufficient weight. + * \see setHasHardObstacleConflict() + */ + bool hasHardObstacleConflict() const { return mHasHardConflict; } + //! Make sure the cost is less than 1 void validateCost(); @@ -329,6 +345,7 @@ namespace pal private: double mCost; bool mHasObstacleConflict; + bool mHasHardConflict = false; int mUpsideDownCharCount; /** diff --git a/src/core/pal/pal.cpp b/src/core/pal/pal.cpp index 520e3c71b23..4ee512a1344 100644 --- a/src/core/pal/pal.cpp +++ b/src/core/pal/pal.cpp @@ -380,6 +380,27 @@ std::unique_ptr Pal::extract( const QgsRectangle &extent, const QgsGeom feat->candidates.pop_back(); } + switch ( mPlacementVersion ) + { + case QgsLabelingEngineSettings::PlacementEngineVersion1: + break; + + case QgsLabelingEngineSettings::PlacementEngineVersion2: + { + // v2 placement rips out candidates where the candidate cost is too high when compared to + // their inactive cost + feat->candidates.erase( std::remove_if( feat->candidates.begin(), feat->candidates.end(), [ & ]( std::unique_ptr< LabelPosition > &candidate ) + { + if ( candidate->hasHardObstacleConflict() ) + { + feat->candidates.back()->removeFromIndex( prob->mAllCandidatesIndex ); + return true; + } + return false; + } ), feat->candidates.end() ); + } + } + if ( isCanceled() ) return nullptr;