More pal modernization of memory management, finally ownership is starting to become clear...

This commit is contained in:
Nyall Dawson 2019-11-28 09:54:20 +10:00
parent b0f4cb45cc
commit 077c507207
6 changed files with 117 additions and 161 deletions

View File

@ -25,12 +25,12 @@
using namespace pal;
bool CostCalculator::candidateSortGrow( const LabelPosition *c1, const LabelPosition *c2 )
bool CostCalculator::candidateSortGrow( const std::unique_ptr< LabelPosition > &c1, const std::unique_ptr< LabelPosition > &c2 )
{
return c1->cost() < c2->cost();
}
bool CostCalculator::candidateSortShrink( const LabelPosition *c1, const LabelPosition *c2 )
bool CostCalculator::candidateSortShrink( const std::unique_ptr< LabelPosition > &c1, const std::unique_ptr< LabelPosition > &c2 )
{
return c1->cost() > c2->cost();
}
@ -93,31 +93,21 @@ void CostCalculator::addObstacleCostPenalty( LabelPosition *lp, FeaturePart *obs
lp->setCost( lp->cost() + obstacleCost );
}
void CostCalculator::setPolygonCandidatesCost( int nblp, QList< LabelPosition * > &lPos, RTree<FeaturePart *, double, 2, double> *obstacles, double bbx[4], double bby[4] )
void CostCalculator::setPolygonCandidatesCost( std::size_t nblp, std::vector< std::unique_ptr< LabelPosition > > &lPos, RTree<FeaturePart *, double, 2, double> *obstacles, double bbx[4], double bby[4] )
{
double normalizer;
// compute raw cost
for ( int i = 0; i < nblp; ++i )
setCandidateCostFromPolygon( lPos.at( i ), obstacles, bbx, bby );
for ( std::size_t i = 0; i < nblp; ++i )
setCandidateCostFromPolygon( lPos[ i ].get(), obstacles, bbx, bby );
// lPos with big values came first (value = min distance from label to Polygon's Perimeter)
// IMPORTANT - only want to sort first nblp positions. The rest have not had the cost
// calculated so will have nonsense values
QList< LabelPosition * > toSort;
toSort.reserve( nblp );
for ( int i = 0; i < nblp; ++i )
{
toSort << lPos.at( i );
}
std::sort( toSort.begin(), toSort.end(), candidateSortShrink );
for ( int i = 0; i < nblp; ++i )
{
lPos[i] = toSort.at( i );
}
std::sort( lPos.begin(), lPos.begin() + nblp, candidateSortShrink );
// define the value's range
double cost_max = lPos.at( 0 )->cost();
double cost_min = lPos.at( nblp - 1 )->cost();
double cost_max = lPos.front()->cost();
double cost_min = lPos.back()->cost();
cost_max -= cost_min;
@ -132,17 +122,18 @@ void CostCalculator::setPolygonCandidatesCost( int nblp, QList< LabelPosition *
// adjust cost => the best is 0.0001, the worst is 0.0021
// others are set proportionally between best and worst
for ( int i = 0; i < nblp; ++i )
for ( std::size_t i = 0; i < nblp; ++i )
{
LabelPosition *pos = lPos[ i ].get();
//if (cost_max - cost_min < EPSILON)
if ( cost_max > EPSILON )
{
lPos.at( i )->setCost( 0.0021 - ( lPos.at( i )->cost() - cost_min ) * normalizer );
pos->setCost( 0.0021 - ( pos->cost() - cost_min ) * normalizer );
}
else
{
//lPos[i]->cost = 0.0001 + (lPos[i]->cost - cost_min) * normalizer;
lPos.at( i )->setCost( 0.0001 );
//pos->cost = 0.0001 + (pos->cost - cost_min) * normalizer;
pos->setCost( 0.0001 );
}
}
}
@ -174,31 +165,30 @@ void CostCalculator::setCandidateCostFromPolygon( LabelPosition *lp, RTree <Feat
delete pCost;
}
int CostCalculator::finalizeCandidatesCosts( Feats *feat, int max_p, RTree <FeaturePart *, double, 2, double> *obstacles, double bbx[4], double bby[4] )
std::size_t CostCalculator::finalizeCandidatesCosts( Feats *feat, std::size_t max_p, RTree <FeaturePart *, double, 2, double> *obstacles, double bbx[4], double bby[4] )
{
// If candidates list is smaller than expected
if ( max_p > feat->candidates.count() )
max_p = feat->candidates.count();
if ( max_p > feat->candidates.size() )
max_p = feat->candidates.size();
//
// sort candidates list, best label to worst
std::sort( feat->candidates.begin(), feat->candidates.end(), candidateSortGrow );
// try to exclude all conflitual labels (good ones have cost < 1 by pruning)
double discrim = 0.0;
int stop;
std::size_t stop = 0;
do
{
discrim += 1.0;
for ( stop = 0; stop < feat->candidates.count() && feat->candidates.at( stop )->cost() < discrim; stop++ )
for ( stop = 0; stop < feat->candidates.size() && feat->candidates[ stop ]->cost() < discrim; stop++ )
;
}
while ( stop == 0 && discrim < feat->candidates.last()->cost() + 2.0 );
while ( stop == 0 && discrim < feat->candidates.back()->cost() + 2.0 );
if ( discrim > 1.5 )
{
int k;
for ( k = 0; k < stop; k++ )
feat->candidates.at( k )->setCost( 0.0021 );
for ( std::size_t k = 0; k < stop; k++ )
feat->candidates[ k ]->setCost( 0.0021 );
}
if ( max_p > stop )

View File

@ -28,6 +28,7 @@
namespace pal
{
class Feats;
class LabelPosition;
/**
* \ingroup core
@ -38,23 +39,23 @@ namespace pal
//! Increase candidate's cost according to its collision with passed feature
static void addObstacleCostPenalty( LabelPosition *lp, pal::FeaturePart *obstacle );
static void setPolygonCandidatesCost( int nblp, QList< LabelPosition * > &lPos, RTree<pal::FeaturePart *, double, 2, double> *obstacles, double bbx[4], double bby[4] );
static void setPolygonCandidatesCost( std::size_t nblp, std::vector<std::unique_ptr<pal::LabelPosition> > &lPos, RTree<pal::FeaturePart *, double, 2, double> *obstacles, double bbx[4], double bby[4] );
//! Sets cost to the smallest distance between lPos's centroid and a polygon stored in geoetry field
static void setCandidateCostFromPolygon( LabelPosition *lp, RTree<pal::FeaturePart *, double, 2, double> *obstacles, double bbx[4], double bby[4] );
//! Sort candidates by costs, skip the worse ones, evaluate polygon candidates
static int finalizeCandidatesCosts( Feats *feat, int max_p, RTree<pal::FeaturePart *, double, 2, double> *obstacles, double bbx[4], double bby[4] );
static std::size_t finalizeCandidatesCosts( Feats *feat, std::size_t max_p, RTree<pal::FeaturePart *, double, 2, double> *obstacles, double bbx[4], double bby[4] );
/**
* Sorts label candidates in ascending order of cost
*/
static bool candidateSortGrow( const LabelPosition *c1, const LabelPosition *c2 );
static bool candidateSortGrow( const std::unique_ptr<pal::LabelPosition> &c1, const std::unique_ptr<pal::LabelPosition> &c2 );
/**
* Sorts label candidates in descending order of cost
*/
static bool candidateSortShrink( const LabelPosition *c1, const LabelPosition *c2 );
static bool candidateSortShrink( const std::unique_ptr<pal::LabelPosition> &c1, const std::unique_ptr<pal::LabelPosition> &c2 );
};
/**

View File

@ -235,9 +235,9 @@ void FeaturePart::setTotalRepeats( int totalRepeats )
mTotalRepeats = totalRepeats;
}
int FeaturePart::createCandidatesOverPoint( double x, double y, QList< LabelPosition *> &lPos, double angle )
std::size_t FeaturePart::createCandidatesOverPoint( double x, double y, std::vector< std::unique_ptr< LabelPosition > > &lPos, double angle )
{
int nbp = 1;
std::size_t nbp = 1;
// get from feature
double labelW = getLabelWidth( angle );
@ -310,7 +310,7 @@ int FeaturePart::createCandidatesOverPoint( double x, double y, QList< LabelPosi
}
}
lPos << new LabelPosition( id, lx, ly, labelW, labelH, angle, cost, this, false, quadrantFromOffset() );
lPos.emplace_back( qgis::make_unique< LabelPosition >( id, lx, ly, labelW, labelH, angle, cost, this, false, quadrantFromOffset() ) );
return nbp;
}
@ -341,7 +341,7 @@ std::unique_ptr<LabelPosition> FeaturePart::createCandidatePointOnSurface( Point
return qgis::make_unique< LabelPosition >( 0, px, py, getLabelWidth(), getLabelHeight(), 0.0, 0.0, this );
}
int FeaturePart::createCandidatesAtOrderedPositionsOverPoint( double x, double y, QList<LabelPosition *> &lPos, double angle )
std::size_t FeaturePart::createCandidatesAtOrderedPositionsOverPoint( double x, double y, std::vector< std::unique_ptr< LabelPosition > > &lPos, double angle )
{
QVector< QgsPalLayerSettings::PredefinedPointPosition > positions = mLF->predefinedPositionOrder();
double labelWidth = getLabelWidth( angle );
@ -356,7 +356,7 @@ int FeaturePart::createCandidatesAtOrderedPositionsOverPoint( double x, double y
int i = 0;
const auto constPositions = positions;
const int maxNumberCandidates = mLF->layer()->maximumPointLabelCandidates();
const std::size_t maxNumberCandidates = mLF->layer()->maximumPointLabelCandidates();
for ( QgsPalLayerSettings::PredefinedPointPosition position : constPositions )
{
double alpha = 0.0;
@ -459,7 +459,7 @@ int FeaturePart::createCandidatesAtOrderedPositionsOverPoint( double x, double y
if ( ! mLF->permissibleZonePrepared() || GeomFunction::containsCandidate( mLF->permissibleZonePrepared(), labelX, labelY, labelWidth, labelHeight, angle ) )
{
lPos << new LabelPosition( i, labelX, labelY, labelWidth, labelHeight, angle, cost, this, false, quadrant );
lPos.emplace_back( qgis::make_unique< LabelPosition >( i, labelX, labelY, labelWidth, labelHeight, angle, cost, this, false, quadrant ) );
//TODO - tweak
cost += 0.001;
if ( lPos.size() >= maxNumberCandidates )
@ -468,16 +468,16 @@ int FeaturePart::createCandidatesAtOrderedPositionsOverPoint( double x, double y
++i;
}
return lPos.count();
return lPos.size();
}
int FeaturePart::createCandidatesAroundPoint( double x, double y, QList< LabelPosition * > &lPos, double angle )
std::size_t FeaturePart::createCandidatesAroundPoint( double x, double y, std::vector< std::unique_ptr< LabelPosition > > &lPos, double angle )
{
double labelWidth = getLabelWidth( angle );
double labelHeight = getLabelHeight( angle );
double distanceToLabel = getLabelDistance();
const int maxNumberCandidates = mLF->layer()->maximumPointLabelCandidates();
const std::size_t maxNumberCandidates = mLF->layer()->maximumPointLabelCandidates();
int icost = 0;
int inc = 2;
@ -508,9 +508,9 @@ int FeaturePart::createCandidatesAroundPoint( double x, double y, QList< LabelPo
if ( gamma2 > a90 / 3.0 )
gamma2 = a90 / 3.0;
QList< LabelPosition * > candidates;
std::size_t numberCandidatesGenerated = 0;
int i;
std::size_t i;
double angleToCandidate;
for ( i = 0, angleToCandidate = M_PI_4; i < maxNumberCandidates; i++, angleToCandidate += candidateAngleIncrement )
{
@ -596,35 +596,28 @@ int FeaturePart::createCandidatesAroundPoint( double x, double y, QList< LabelPo
}
}
candidates << new LabelPosition( i, labelX, labelY, labelWidth, labelHeight, angle, cost, this, false, quadrant );
lPos.emplace_back( qgis::make_unique< LabelPosition >( i, labelX, labelY, labelWidth, labelHeight, angle, cost, this, false, quadrant ) );
numberCandidatesGenerated++;
icost += inc;
if ( icost == maxNumberCandidates )
if ( icost == static_cast< int >( maxNumberCandidates ) )
{
icost = maxNumberCandidates - 1;
icost = static_cast< int >( maxNumberCandidates ) - 1;
inc = -2;
}
else if ( icost > maxNumberCandidates )
else if ( icost > static_cast< int >( maxNumberCandidates ) )
{
icost = maxNumberCandidates - 2;
icost = static_cast< int >( maxNumberCandidates ) - 2;
inc = -2;
}
}
if ( !candidates.isEmpty() )
{
for ( int i = 0; i < candidates.count(); ++i )
{
lPos << candidates.at( i );
}
}
return candidates.count();
return numberCandidatesGenerated;
}
int FeaturePart::createCandidatesAlongLine( QList< LabelPosition * > &lPos, PointSet *mapShape, bool allowOverrun )
std::size_t FeaturePart::createCandidatesAlongLine( std::vector< std::unique_ptr< LabelPosition > > &lPos, PointSet *mapShape, bool allowOverrun )
{
if ( allowOverrun )
{
@ -639,9 +632,9 @@ int FeaturePart::createCandidatesAlongLine( QList< LabelPosition * > &lPos, Poin
}
//prefer to label along straightish segments:
int candidates = createCandidatesAlongLineNearStraightSegments( lPos, mapShape );
std::size_t candidates = createCandidatesAlongLineNearStraightSegments( lPos, mapShape );
if ( candidates < mLF->layer()->maximumLineLabelCandidates() )
if ( static_cast< int >( candidates ) < mLF->layer()->maximumLineLabelCandidates() )
{
// but not enough candidates yet, so fallback to labeling near whole line's midpoint
candidates = createCandidatesAlongLineNearMidpoint( lPos, mapShape, candidates > 0 ? 0.01 : 0.0 );
@ -649,7 +642,7 @@ int FeaturePart::createCandidatesAlongLine( QList< LabelPosition * > &lPos, Poin
return candidates;
}
int FeaturePart::createCandidatesAlongLineNearStraightSegments( QList<LabelPosition *> &lPos, PointSet *mapShape )
std::size_t FeaturePart::createCandidatesAlongLineNearStraightSegments( std::vector< std::unique_ptr< LabelPosition > > &lPos, PointSet *mapShape )
{
double labelWidth = getLabelWidth();
double labelHeight = getLabelHeight();
@ -835,7 +828,7 @@ int FeaturePart::createCandidatesAlongLineNearStraightSegments( QList<LabelPosit
if ( !mLF->permissibleZonePrepared() || GeomFunction::containsCandidate( mLF->permissibleZonePrepared(), candidateStartX - std::cos( beta ) * ( distanceLineToLabel + labelHeight ), candidateStartY - std::sin( beta ) * ( distanceLineToLabel + labelHeight ), labelWidth, labelHeight, angle ) )
{
const double candidateCost = cost + ( reversed ? 0 : 0.001 );
lPos.append( new LabelPosition( i, candidateStartX - std::cos( beta ) * ( distanceLineToLabel + labelHeight ), candidateStartY - std::sin( beta ) * ( distanceLineToLabel + labelHeight ), labelWidth, labelHeight, angle, candidateCost, this, isRightToLeft ) ); // Line
lPos.emplace_back( qgis::make_unique< LabelPosition >( i, candidateStartX - std::cos( beta ) * ( distanceLineToLabel + labelHeight ), candidateStartY - std::sin( beta ) * ( distanceLineToLabel + labelHeight ), labelWidth, labelHeight, angle, candidateCost, this, isRightToLeft ) ); // Line
}
}
if ( aboveLine )
@ -843,7 +836,7 @@ int FeaturePart::createCandidatesAlongLineNearStraightSegments( QList<LabelPosit
if ( !mLF->permissibleZonePrepared() || GeomFunction::containsCandidate( mLF->permissibleZonePrepared(), candidateStartX + std::cos( beta ) *distanceLineToLabel, candidateStartY + std::sin( beta ) *distanceLineToLabel, labelWidth, labelHeight, angle ) )
{
const double candidateCost = cost + ( !reversed ? 0 : 0.001 ); // no extra cost for above line placements
lPos.append( new LabelPosition( i, candidateStartX + std::cos( beta ) *distanceLineToLabel, candidateStartY + std::sin( beta ) *distanceLineToLabel, labelWidth, labelHeight, angle, candidateCost, this, isRightToLeft ) ); // Line
lPos.emplace_back( qgis::make_unique< LabelPosition >( i, candidateStartX + std::cos( beta ) *distanceLineToLabel, candidateStartY + std::sin( beta ) *distanceLineToLabel, labelWidth, labelHeight, angle, candidateCost, this, isRightToLeft ) ); // Line
}
}
if ( flags & FLAG_ON_LINE )
@ -851,13 +844,13 @@ int FeaturePart::createCandidatesAlongLineNearStraightSegments( QList<LabelPosit
if ( !mLF->permissibleZonePrepared() || GeomFunction::containsCandidate( mLF->permissibleZonePrepared(), candidateStartX - labelHeight * std::cos( beta ) / 2, candidateStartY - labelHeight * std::sin( beta ) / 2, labelWidth, labelHeight, angle ) )
{
const double candidateCost = cost + 0.002;
lPos.append( new LabelPosition( i, candidateStartX - labelHeight * std::cos( beta ) / 2, candidateStartY - labelHeight * std::sin( beta ) / 2, labelWidth, labelHeight, angle, candidateCost, this, isRightToLeft ) ); // Line
lPos.emplace_back( qgis::make_unique< LabelPosition >( i, candidateStartX - labelHeight * std::cos( beta ) / 2, candidateStartY - labelHeight * std::sin( beta ) / 2, labelWidth, labelHeight, angle, candidateCost, this, isRightToLeft ) ); // Line
}
}
}
else if ( mLF->layer()->arrangement() == QgsPalLayerSettings::Horizontal )
{
lPos.append( new LabelPosition( i, candidateStartX - labelWidth / 2, candidateStartY - labelHeight / 2, labelWidth, labelHeight, 0, cost, this ) ); // Line
lPos.emplace_back( qgis::make_unique< LabelPosition >( i, candidateStartX - labelWidth / 2, candidateStartY - labelHeight / 2, labelWidth, labelHeight, 0, cost, this ) ); // Line
}
else
{
@ -873,7 +866,7 @@ int FeaturePart::createCandidatesAlongLineNearStraightSegments( QList<LabelPosit
return lPos.size();
}
int FeaturePart::createCandidatesAlongLineNearMidpoint( QList<LabelPosition *> &lPos, PointSet *mapShape, double initialCost )
std::size_t FeaturePart::createCandidatesAlongLineNearMidpoint( std::vector< std::unique_ptr< LabelPosition > > &lPos, PointSet *mapShape, double initialCost )
{
double distanceLineToLabel = getLabelDistance();
@ -887,8 +880,6 @@ int FeaturePart::createCandidatesAlongLineNearMidpoint( QList<LabelPosition *> &
if ( flags == 0 )
flags = FLAG_ON_LINE; // default flag
QList<LabelPosition *> positions;
PointSet *line = mapShape;
int nbPoints = line->nbPoints;
std::vector< double > &x = line->x;
@ -989,7 +980,7 @@ int FeaturePart::createCandidatesAlongLineNearMidpoint( QList<LabelPosition *> &
if ( !mLF->permissibleZonePrepared() || GeomFunction::containsCandidate( mLF->permissibleZonePrepared(), candidateStartX + std::cos( beta ) *distanceLineToLabel, candidateStartY + std::sin( beta ) *distanceLineToLabel, labelWidth, labelHeight, angle ) )
{
const double candidateCost = cost + ( !reversed ? 0 : 0.001 ); // no extra cost for above line placements
positions.append( new LabelPosition( i, candidateStartX + std::cos( beta ) *distanceLineToLabel, candidateStartY + std::sin( beta ) *distanceLineToLabel, labelWidth, labelHeight, angle, candidateCost, this, isRightToLeft ) ); // Line
lPos.emplace_back( qgis::make_unique< LabelPosition >( i, candidateStartX + std::cos( beta ) *distanceLineToLabel, candidateStartY + std::sin( beta ) *distanceLineToLabel, labelWidth, labelHeight, angle, candidateCost, this, isRightToLeft ) ); // Line
}
}
if ( belowLine )
@ -997,7 +988,7 @@ int FeaturePart::createCandidatesAlongLineNearMidpoint( QList<LabelPosition *> &
if ( !mLF->permissibleZonePrepared() || GeomFunction::containsCandidate( mLF->permissibleZonePrepared(), candidateStartX - std::cos( beta ) * ( distanceLineToLabel + labelHeight ), candidateStartY - std::sin( beta ) * ( distanceLineToLabel + labelHeight ), labelWidth, labelHeight, angle ) )
{
const double candidateCost = cost + ( !reversed ? 0.001 : 0 );
positions.append( new LabelPosition( i, candidateStartX - std::cos( beta ) * ( distanceLineToLabel + labelHeight ), candidateStartY - std::sin( beta ) * ( distanceLineToLabel + labelHeight ), labelWidth, labelHeight, angle, candidateCost, this, isRightToLeft ) ); // Line
lPos.emplace_back( qgis::make_unique< LabelPosition >( i, candidateStartX - std::cos( beta ) * ( distanceLineToLabel + labelHeight ), candidateStartY - std::sin( beta ) * ( distanceLineToLabel + labelHeight ), labelWidth, labelHeight, angle, candidateCost, this, isRightToLeft ) ); // Line
}
}
if ( flags & FLAG_ON_LINE )
@ -1005,13 +996,13 @@ int FeaturePart::createCandidatesAlongLineNearMidpoint( QList<LabelPosition *> &
if ( !mLF->permissibleZonePrepared() || GeomFunction::containsCandidate( mLF->permissibleZonePrepared(), candidateStartX - labelHeight * std::cos( beta ) / 2, candidateStartY - labelHeight * std::sin( beta ) / 2, labelWidth, labelHeight, angle ) )
{
const double candidateCost = cost + 0.002;
positions.append( new LabelPosition( i, candidateStartX - labelHeight * std::cos( beta ) / 2, candidateStartY - labelHeight * std::sin( beta ) / 2, labelWidth, labelHeight, angle, candidateCost, this, isRightToLeft ) ); // Line
lPos.emplace_back( qgis::make_unique< LabelPosition >( i, candidateStartX - labelHeight * std::cos( beta ) / 2, candidateStartY - labelHeight * std::sin( beta ) / 2, labelWidth, labelHeight, angle, candidateCost, this, isRightToLeft ) ); // Line
}
}
}
else if ( mLF->layer()->arrangement() == QgsPalLayerSettings::Horizontal )
{
positions.append( new LabelPosition( i, candidateStartX - labelWidth / 2, candidateStartY - labelHeight / 2, labelWidth, labelHeight, 0, cost, this ) ); // Line
lPos.emplace_back( qgis::make_unique< LabelPosition >( i, candidateStartX - labelWidth / 2, candidateStartY - labelHeight / 2, labelWidth, labelHeight, 0, cost, this ) ); // Line
}
else
{
@ -1031,7 +1022,6 @@ int FeaturePart::createCandidatesAlongLineNearMidpoint( QList<LabelPosition *> &
delete[] segmentLengths;
delete[] distanceToSegment;
lPos.append( positions );
return lPos.size();
}
@ -1212,7 +1202,7 @@ static LabelPosition *_createCurvedCandidate( LabelPosition *lp, double angle, d
return newLp;
}
int FeaturePart::createCurvedCandidatesAlongLine( QList< LabelPosition * > &lPos, PointSet *mapShape, bool allowOverrun )
std::size_t FeaturePart::createCurvedCandidatesAlongLine( std::vector< std::unique_ptr< LabelPosition > > &lPos, PointSet *mapShape, bool allowOverrun )
{
LabelInfo *li = mLF->curvedLabelInfo();
@ -1391,10 +1381,10 @@ int FeaturePart::createCurvedCandidatesAlongLine( QList< LabelPosition * > &lPos
delete slp;
}
int nbp = positions.size();
for ( int i = 0; i < nbp; i++ )
std::size_t nbp = positions.size();
for ( std::size_t i = 0; i < nbp; i++ )
{
lPos << positions.takeFirst();
lPos.emplace_back( std::unique_ptr< LabelPosition >( positions.takeFirst() ) );
}
return nbp;
@ -1412,9 +1402,8 @@ int FeaturePart::createCurvedCandidatesAlongLine( QList< LabelPosition * > &lPos
*
*/
int FeaturePart::createCandidatesForPolygon( QList< LabelPosition *> &lPos, PointSet *mapShape )
std::size_t FeaturePart::createCandidatesForPolygon( std::vector< std::unique_ptr< LabelPosition > > &lPos, PointSet *mapShape )
{
int i;
int j;
double labelWidth = getLabelWidth();
@ -1429,12 +1418,10 @@ int FeaturePart::createCandidatesForPolygon( QList< LabelPosition *> &lPos, Poin
splitPolygons( shapes_toProcess, shapes_final, labelWidth, labelHeight );
int nbp;
std::size_t nbp = 0;
if ( !shapes_final.isEmpty() )
{
QLinkedList<LabelPosition *> positions;
int id = 0; // ids for candidates
double dlx, dly; // delta from label center and bottom-left corner
double alpha = 0.0; // rotation for the label
@ -1470,6 +1457,8 @@ int FeaturePart::createCandidatesForPolygon( QList< LabelPosition *> &lPos, Poin
//then use a smaller limit for number of iterations
int maxTry = mLF->permissibleZonePrepared() ? 7 : 10;
std::size_t numberCandidatesGenerated = 0;
do
{
for ( bbid = 0; bbid < j; bbid++ )
@ -1580,13 +1569,14 @@ int FeaturePart::createCandidatesForPolygon( QList< LabelPosition *> &lPos, Poin
if ( candidateAcceptable )
{
// cost is set to minimal value, evaluated later
positions.append( new LabelPosition( id++, rx - dlx, ry - dly, labelWidth, labelHeight, alpha, 0.0001, this ) ); // Polygon
lPos.emplace_back( qgis::make_unique< LabelPosition >( id++, rx - dlx, ry - dly, labelWidth, labelHeight, alpha, 0.0001, this ) ); // Polygon
numberCandidatesGenerated++;
}
}
}
} // forall box
nbp = positions.size();
nbp = numberCandidatesGenerated;
if ( nbp == 0 )
{
dx /= 2;
@ -1596,12 +1586,7 @@ int FeaturePart::createCandidatesForPolygon( QList< LabelPosition *> &lPos, Poin
}
while ( nbp == 0 && numTry < maxTry );
nbp = positions.size();
for ( i = 0; i < nbp; i++ )
{
lPos << positions.takeFirst();
}
nbp = numberCandidatesGenerated;
for ( bbid = 0; bbid < j; bbid++ )
{
@ -1618,14 +1603,14 @@ int FeaturePart::createCandidatesForPolygon( QList< LabelPosition *> &lPos, Poin
return nbp;
}
QList<LabelPosition *> FeaturePart::createCandidates()
std::vector< std::unique_ptr< LabelPosition > > FeaturePart::createCandidates()
{
QList<LabelPosition *> lPos;
std::vector< std::unique_ptr< LabelPosition > > lPos;
double angle = mLF->hasFixedAngle() ? mLF->fixedAngle() : 0.0;
if ( mLF->hasFixedPosition() )
{
lPos << new LabelPosition( 0, mLF->fixedPosition().x(), mLF->fixedPosition().y(), getLabelWidth( angle ), getLabelHeight( angle ), angle, 0.0, this );
lPos.emplace_back( qgis::make_unique< LabelPosition> ( 0, mLF->fixedPosition().x(), mLF->fixedPosition().y(), getLabelWidth( angle ), getLabelHeight( angle ), angle, 0.0, this ) );
}
else
{
@ -1674,7 +1659,7 @@ QList<LabelPosition *> FeaturePart::createCandidates()
return lPos;
}
void FeaturePart::addSizePenalty( int nbp, QList< LabelPosition * > &lPos, double bbx[4], double bby[4] )
void FeaturePart::addSizePenalty( std::size_t nbp, std::vector< std::unique_ptr< LabelPosition > > &lPos, double bbx[4], double bby[4] )
{
if ( !mGeos )
createGeosGeom();
@ -1725,9 +1710,10 @@ void FeaturePart::addSizePenalty( int nbp, QList< LabelPosition * > &lPos, doubl
return; // no size penalty for points
// apply the penalty
for ( int i = 0; i < nbp; i++ )
for ( std::size_t i = 0; i < nbp; i++ )
{
lPos.at( i )->setCost( lPos.at( i )->cost() + sizeCost / 100 );
LabelPosition *pos = lPos[ i ].get();
pos->setCost( pos->cost() + sizeCost / 100 );
}
}

View File

@ -130,7 +130,7 @@ namespace pal
/**
* Generates a list of candidate positions for labels for this feature.
*/
QList<LabelPosition *> createCandidates();
std::vector<std::unique_ptr<LabelPosition> > createCandidates();
/**
* Generate candidates for point feature, located around a specified point.
@ -140,7 +140,7 @@ namespace pal
* \param angle orientation of the label
* \returns the number of generated candidates
*/
int createCandidatesAroundPoint( double x, double y, QList<LabelPosition *> &lPos, double angle );
std::size_t createCandidatesAroundPoint( double x, double y, std::vector<std::unique_ptr<LabelPosition> > &lPos, double angle );
/**
* Generate one candidate over or offset the specified point.
@ -150,7 +150,7 @@ namespace pal
* \param angle orientation of the label
* \returns the number of generated candidates (always 1)
*/
int createCandidatesOverPoint( double x, double y, QList<LabelPosition *> &lPos, double angle );
std::size_t createCandidatesOverPoint( double x, double y, std::vector<std::unique_ptr<LabelPosition> > &lPos, double angle );
/**
* Creates a single candidate using the "point on sruface" algorithm.
@ -168,7 +168,7 @@ namespace pal
* \param angle orientation of the label
* \returns the number of generated candidates
*/
int createCandidatesAtOrderedPositionsOverPoint( double x, double y, QList<LabelPosition *> &lPos, double angle );
std::size_t createCandidatesAtOrderedPositionsOverPoint( double x, double y, std::vector<std::unique_ptr<LabelPosition> > &lPos, double angle );
/**
* Generate candidates for line feature.
@ -177,7 +177,7 @@ namespace pal
* \param allowOverrun set to TRUE to allow labels to overrun features
* \returns the number of generated candidates
*/
int createCandidatesAlongLine( QList<LabelPosition *> &lPos, PointSet *mapShape, bool allowOverrun = false );
std::size_t createCandidatesAlongLine( std::vector<std::unique_ptr<LabelPosition> > &lPos, PointSet *mapShape, bool allowOverrun = false );
/**
* Generate candidates for line feature, by trying to place candidates towards the middle of the longest
@ -186,7 +186,7 @@ namespace pal
* \param mapShape a pointer to the line
* \returns the number of generated candidates
*/
int createCandidatesAlongLineNearStraightSegments( QList<LabelPosition *> &lPos, PointSet *mapShape );
std::size_t createCandidatesAlongLineNearStraightSegments( std::vector<std::unique_ptr<LabelPosition> > &lPos, PointSet *mapShape );
/**
* Generate candidates for line feature, by trying to place candidates as close as possible to the line's midpoint.
@ -197,7 +197,7 @@ namespace pal
* by a preset amount.
* \returns the number of generated candidates
*/
int createCandidatesAlongLineNearMidpoint( QList<LabelPosition *> &lPos, PointSet *mapShape, double initialCost = 0.0 );
std::size_t createCandidatesAlongLineNearMidpoint( std::vector<std::unique_ptr<LabelPosition> > &lPos, PointSet *mapShape, double initialCost = 0.0 );
/**
* Returns the label position for a curved label at a specific offset along a path.
@ -219,7 +219,7 @@ namespace pal
* \param allowOverrun set to TRUE to allow labels to overrun features
* \returns the number of generated candidates
*/
int createCurvedCandidatesAlongLine( QList<LabelPosition *> &lPos, PointSet *mapShape, bool allowOverrun = false );
std::size_t createCurvedCandidatesAlongLine( std::vector<std::unique_ptr<LabelPosition> > &lPos, PointSet *mapShape, bool allowOverrun = false );
/**
* Generate candidates for polygon features.
@ -227,7 +227,7 @@ namespace pal
* \param mapShape a pointer to the polygon
* \returns the number of generated candidates
*/
int createCandidatesForPolygon( QList<LabelPosition *> &lPos, PointSet *mapShape );
std::size_t createCandidatesForPolygon( std::vector<std::unique_ptr<LabelPosition> > &lPos, PointSet *mapShape );
/**
* Tests whether this feature part belongs to the same QgsLabelFeature as another
@ -304,7 +304,7 @@ namespace pal
* Returns TRUE on success, FALSE if the feature wasn't modified */
bool mergeWithFeaturePart( FeaturePart *other );
void addSizePenalty( int nbp, QList<LabelPosition *> &lPos, double bbx[4], double bby[4] );
void addSizePenalty( std::size_t nbp, std::vector<std::unique_ptr<LabelPosition> > &lPos, double bbx[4], double bby[4] );
/**
* Calculates the priority for the feature. This will be the feature's priority if set,

View File

@ -92,7 +92,7 @@ Layer *Pal::addLayer( QgsAbstractLabelProvider *provider, const QString &layerNa
return layer;
}
typedef struct _featCbackCtx
struct FeatCallBackCtx
{
Layer *layer = nullptr;
@ -103,7 +103,7 @@ typedef struct _featCbackCtx
QList<LabelPosition *> *positionsWithNoCandidates;
const GEOSPreparedGeometry *mapBoundary = nullptr;
Pal *pal = nullptr;
} FeatCallBackCtx;
};
@ -130,40 +130,31 @@ bool extractFeatCallback( FeaturePart *featurePart, void *ctx )
}
// generate candidates for the feature part
QList< LabelPosition * > candidates = featurePart->createCandidates();
std::vector< std::unique_ptr< LabelPosition > > candidates = featurePart->createCandidates();
// purge candidates that are outside the bbox
QMutableListIterator< LabelPosition *> i( candidates );
while ( i.hasNext() )
candidates.erase( std::remove_if( candidates.begin(), candidates.end(), [&context]( std::unique_ptr< LabelPosition > &candidate )
{
LabelPosition *pos = i.next();
bool outside = false;
if ( context->pal->getShowPartial() )
outside = !pos->intersects( context->mapBoundary );
return !candidate->intersects( context->mapBoundary );
else
outside = !pos->within( context->mapBoundary );
if ( outside )
{
i.remove();
delete pos;
}
else // this one is OK
{
pos->insertIntoIndex( context->candidates );
}
}
return !candidate->within( context->mapBoundary );
} ), candidates.end() );
if ( !candidates.empty() )
{
for ( std::unique_ptr< LabelPosition > &candidate : candidates )
{
candidate->insertIntoIndex( context->candidates );
}
std::sort( candidates.begin(), candidates.end(), CostCalculator::candidateSortGrow );
// valid features are added to fFeats
std::unique_ptr< Feats > ft = qgis::make_unique< Feats >();
ft->feature = featurePart;
ft->shape = nullptr;
ft->candidates = candidates;
ft->candidates = std::move( candidates );
ft->priority = featurePart->calculatePriority();
context->fFeats->emplace_back( std::move( ft ) );
}
@ -233,17 +224,13 @@ std::unique_ptr<Problem> Pal::extract( const QgsRectangle &extent, const QgsGeom
RTree<FeaturePart *, double, 2, double> obstacles;
std::unique_ptr< Problem > prob = qgis::make_unique< Problem >();
int j;
double bbx[4];
double bby[4];
double amin[2];
double amax[2];
int max_p = 0;
LabelPosition *lp = nullptr;
std::size_t max_p = 0;
bbx[0] = bbx[3] = amin[0] = prob->bbox[0] = extent.xMinimum();
bby[0] = bby[1] = amin[1] = prob->bbox[1] = extent.yMinimum();
@ -338,12 +325,6 @@ std::unique_ptr<Problem> Pal::extract( const QgsRectangle &extent, const QgsGeom
if ( isCanceled() )
{
for ( const std::unique_ptr< Feats > &feat : qgis::as_const( fFeats ) )
{
qDeleteAll( feat->candidates );
feat->candidates.clear();
}
return nullptr;
}
@ -373,23 +354,22 @@ std::unique_ptr<Problem> Pal::extract( const QgsRectangle &extent, const QgsGeom
max_p = CostCalculator::finalizeCandidatesCosts( feat.get(), max_p, &obstacles, bbx, bby );
// only keep the 'max_p' best candidates
while ( feat->candidates.count() > max_p )
while ( feat->candidates.size() > max_p )
{
// TODO remove from index
feat->candidates.constLast()->removeFromIndex( prob->candidates );
delete feat->candidates.takeLast();
feat->candidates.back()->removeFromIndex( prob->candidates );
feat->candidates.pop_back();
}
// update problem's # candidate
prob->featNbLp[i] = feat->candidates.count();
prob->mTotalCandidates += feat->candidates.count();
prob->featNbLp[i] = 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 ( j = 0; j < feat->candidates.count(); j++, idlp++ )
for ( std::size_t j = 0; j < feat->candidates.size(); j++, idlp++ )
{
lp = feat->candidates.at( j );
//lp->insertIntoIndex(prob->candidates);
lp->setProblemIds( i, idlp ); // bugfix #1 (maxence 10/23/2008)
feat->candidates[ j ]->setProblemIds( static_cast< int >( i ), idlp ); // bugfix #1 (maxence 10/23/2008)
}
fFeats.emplace_back( std::move( feat ) );
}
@ -400,35 +380,31 @@ std::unique_ptr<Problem> Pal::extract( const QgsRectangle &extent, const QgsGeom
{
if ( isCanceled() )
{
for ( const std::unique_ptr< Feats > &feat : qgis::as_const( fFeats ) )
{
qDeleteAll( feat->candidates );
feat->candidates.clear();
}
return nullptr;
}
std::unique_ptr< Feats > feat = std::move( fFeats.front() );
fFeats.pop_front();
while ( !feat->candidates.isEmpty() ) // foreach label candidate
for ( std::unique_ptr< LabelPosition > &candidate : feat->candidates )
{
lp = feat->candidates.takeFirst();
std::unique_ptr< LabelPosition > lp = std::move( candidate );
lp->resetNumOverlaps();
// make sure that candidate's cost is less than 1
lp->validateCost();
prob->addCandidatePosition( lp );
//prob->feat[idlp] = j;
lp->getBoundingBox( amin, amax );
// lookup for overlapping candidate
prob->candidates->Search( amin, amax, LabelPosition::countOverlapCallback, static_cast< void * >( lp ) );
prob->candidates->Search( amin, amax, LabelPosition::countOverlapCallback, static_cast< void * >( lp.get() ) );
nbOverlaps += lp->getNumOverlaps();
prob->addCandidatePosition( lp.release() );
}
}
nbOverlaps /= 2;

View File

@ -34,6 +34,8 @@
#include <QList>
#include <vector>
#include <memory>
namespace pal
{
@ -41,6 +43,7 @@ namespace pal
class LabelPosition;
class Layer;
class FeaturePart;
class PointSet;
/**
* \ingroup core
@ -56,7 +59,7 @@ namespace pal
FeaturePart *feature = nullptr;
PointSet *shape = nullptr;
double priority = 0;
QList< LabelPosition *> candidates;
std::vector< std::unique_ptr< LabelPosition > > candidates;
};