More pal::rtree swaps

This commit is contained in:
Nyall Dawson 2019-12-09 11:33:52 +10:00
parent 94306655b7
commit 727a4da01f
9 changed files with 213 additions and 251 deletions

View File

@ -38,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, Pal *pal );
static void addObstacleCostPenalty( pal::LabelPosition *lp, pal::FeaturePart *obstacle, Pal *pal );
//! Calculates the costs for polygon label candidates
static void setPolygonCandidatesCost( std::size_t nblp, std::vector<std::unique_ptr<pal::LabelPosition> > &lPos, QgsGenericSpatialIndex< FeaturePart > *obstacles, double bbx[4], double bby[4] );

View File

@ -265,7 +265,7 @@ bool LabelPosition::isInside( double *bbox )
return true;
}
bool LabelPosition::isInConflict( LabelPosition *lp )
bool LabelPosition::isInConflict( const LabelPosition *lp ) const
{
if ( this->probFeat == lp->probFeat ) // bugfix #1
return false; // always overlaping itself !
@ -276,7 +276,7 @@ bool LabelPosition::isInConflict( LabelPosition *lp )
return isInConflictMultiPart( lp );
}
bool LabelPosition::isInConflictSinglePart( LabelPosition *lp )
bool LabelPosition::isInConflictSinglePart( const LabelPosition *lp ) const
{
if ( qgsDoubleNear( alpha, 0 ) && qgsDoubleNear( lp->alpha, 0 ) )
{
@ -303,14 +303,14 @@ bool LabelPosition::isInConflictSinglePart( LabelPosition *lp )
}
}
bool LabelPosition::isInConflictMultiPart( LabelPosition *lp )
bool LabelPosition::isInConflictMultiPart( const LabelPosition *lp ) const
{
// check all parts against all parts of other one
LabelPosition *tmp1 = this;
const LabelPosition *tmp1 = this;
while ( tmp1 )
{
// check tmp1 against parts of other label
LabelPosition *tmp2 = lp;
const LabelPosition *tmp2 = lp;
while ( tmp2 )
{
if ( tmp1->isInConflictSinglePart( tmp2 ) )
@ -383,7 +383,7 @@ void LabelPosition::validateCost()
}
}
FeaturePart *LabelPosition::getFeaturePart()
FeaturePart *LabelPosition::getFeaturePart() const
{
return feature;
}
@ -428,81 +428,20 @@ void LabelPosition::setHasHardObstacleConflict( bool conflicts )
nextPart->setHasHardObstacleConflict( conflicts );
}
void LabelPosition::removeFromIndex( RTree<LabelPosition *, double, 2, double> &index )
void LabelPosition::removeFromIndex( QgsGenericSpatialIndex<LabelPosition> &index )
{
double amin[2];
double amax[2];
getBoundingBox( amin, amax );
index.Remove( amin, amax, this );
index.deleteData( this, QgsRectangle( amin[0], amin[1], amax[0], amax[1] ) );
}
void LabelPosition::insertIntoIndex( RTree<LabelPosition *, double, 2, double> &index )
void LabelPosition::insertIntoIndex( QgsGenericSpatialIndex<LabelPosition> &index )
{
double amin[2];
double amax[2];
getBoundingBox( amin, amax );
index.Insert( amin, amax, this );
}
bool LabelPosition::pruneCallback( LabelPosition *candidatePosition, void *ctx )
{
FeaturePart *obstaclePart = ( reinterpret_cast< PruneCtx * >( ctx ) )->obstacle;
// test whether we should ignore this obstacle for the candidate. We do this if:
// 1. it's not a hole, and the obstacle belongs to the same label feature as the candidate (e.g.,
// features aren't obstacles for their own labels)
// 2. it IS a hole, and the hole belongs to a different label feature to the candidate (e.g., holes
// are ONLY obstacles for the labels of the feature they belong to)
if ( ( !obstaclePart->getHoleOf() && candidatePosition->feature->hasSameLabelFeatureAs( obstaclePart ) )
|| ( obstaclePart->getHoleOf() && !candidatePosition->feature->hasSameLabelFeatureAs( dynamic_cast< FeaturePart * >( obstaclePart->getHoleOf() ) ) ) )
{
return true;
}
CostCalculator::addObstacleCostPenalty( candidatePosition, obstaclePart, ( reinterpret_cast< PruneCtx * >( ctx ) )->pal );
return true;
}
bool LabelPosition::countOverlapCallback( LabelPosition *lp, void *ctx )
{
LabelPosition *lp2 = reinterpret_cast< LabelPosition * >( ctx );
if ( lp2->isInConflict( lp ) )
{
lp2->nbOverlap++;
}
return true;
}
bool LabelPosition::countFullOverlapCallback( LabelPosition *lp, void *ctx )
{
CountContext *context = reinterpret_cast< CountContext * >( ctx );
LabelPosition *lp2 = context->lp;
double *cost = context->cost;
int *nbOv = context->nbOv;
std::vector< double > &inactiveCost = *context->inactiveCost;
if ( lp2->isInConflict( lp ) )
{
( *nbOv ) ++;
*cost += inactiveCost[lp->probFeat] + lp->cost();
}
return true;
}
bool LabelPosition::removeOverlapCallback( LabelPosition *lp, void *ctx )
{
LabelPosition *lp2 = reinterpret_cast< LabelPosition * >( ctx );
if ( lp2->isInConflict( lp ) )
{
lp->nbOverlap--;
lp2->nbOverlap--;
}
return true;
index.insertData( this, QgsRectangle( amin[0], amin[1], amax[0], amax[1] ) );
}
double LabelPosition::getDistanceToPoint( double xp, double yp ) const

View File

@ -36,6 +36,7 @@
#include "qgis_core.h"
#include "pointset.h"
#include "rtree.hpp"
#include "qgsgenericspatialindex.h"
#include <fstream>
namespace pal
@ -139,7 +140,7 @@ namespace pal
* \param ls other labelposition
* \returns TRUE or FALSE
*/
bool isInConflict( LabelPosition *ls );
bool isInConflict( const LabelPosition *ls ) const;
//! Returns bounding box - amin: xmin,ymin - amax: xmax,ymax
void getBoundingBox( double amin[2], double amax[2] ) const;
@ -176,11 +177,21 @@ namespace pal
/**
* Returns the feature corresponding to this labelposition
*/
FeaturePart *getFeaturePart();
FeaturePart *getFeaturePart() const;
int getNumOverlaps() const { return nbOverlap; }
void resetNumOverlaps() { nbOverlap = 0; } // called from problem.cpp, pal.cpp
/**
* Increases the number of overlaps recorded against this position by 1.
*/
void incrementNumOverlaps() { nbOverlap++; }
/**
* Decreases the number of overlaps recorded against this position by 1.
*/
void decrementNumOverlaps() { nbOverlap++; }
int getProblemFeatureId() const { return probFeat; }
/**
@ -278,12 +289,12 @@ namespace pal
/**
* Removes the label position from the specified \a index.
*/
void removeFromIndex( RTree<LabelPosition *, double, 2, double> &index );
void removeFromIndex( QgsGenericSpatialIndex<LabelPosition> &index );
/**
* Inserts the label position into the specified \a index.
*/
void insertIntoIndex( RTree<LabelPosition *, double, 2, double> &index );
void insertIntoIndex( QgsGenericSpatialIndex<LabelPosition> &index );
struct PruneCtx
{
@ -356,8 +367,8 @@ namespace pal
LabelPosition::Quadrant quadrant;
bool isInConflictSinglePart( LabelPosition *lp );
bool isInConflictMultiPart( LabelPosition *lp );
bool isInConflictSinglePart( const LabelPosition *lp ) const;
bool isInConflictMultiPart( const LabelPosition *lp ) const;
private:
double mCost;

View File

@ -256,15 +256,11 @@ bool Layer::registerFeature( QgsLabelFeature *lf )
void Layer::addFeaturePart( FeaturePart *fpart, const QString &labelText )
{
double bmin[2];
double bmax[2];
fpart->getBoundingBox( bmin, bmax );
// add to list of layer's feature parts
mFeatureParts << fpart;
// add to r-tree for fast spatial access
mFeatureIndex.insertData( fpart, QgsRectangle( bmin[0], bmin[1], bmax[0], bmax[1] ) );
mFeatureIndex.insertData( fpart, fpart->boundingBox() );
// add to hashtable with equally named feature parts
if ( mMergeLines && !labelText.isEmpty() )
@ -275,15 +271,11 @@ void Layer::addFeaturePart( FeaturePart *fpart, const QString &labelText )
void Layer::addObstaclePart( FeaturePart *fpart )
{
double bmin[2];
double bmax[2];
fpart->getBoundingBox( bmin, bmax );
// add to list of layer's feature parts
mObstacleParts.append( fpart );
// add to obstacle r-tree
mObstacleIndex.insertData( fpart, QgsRectangle( bmin[0], bmin[1], bmax[0], bmax[1] ) );
mObstacleIndex.insertData( fpart, fpart->boundingBox() );
}
static FeaturePart *_findConnectedPart( FeaturePart *partCheck, const QVector<FeaturePart *> &otherParts )
@ -329,22 +321,18 @@ void Layer::joinConnectedFeatures()
if ( otherPart )
{
// remove partCheck from r-tree
double checkpartBMin[2], checkpartBMax[2];
partCheck->getBoundingBox( checkpartBMin, checkpartBMax );
double otherPartBMin[2], otherPartBMax[2];
otherPart->getBoundingBox( otherPartBMin, otherPartBMax );
const QgsRectangle checkPartBoundsBefore = partCheck->boundingBox();
const QgsRectangle otherPartBoundsBefore = otherPart->boundingBox();
// merge points from partCheck to p->item
if ( otherPart->mergeWithFeaturePart( partCheck ) )
{
// remove the parts we are joining from the index
mFeatureIndex.deleteData( partCheck, QgsRectangle( checkpartBMin[0], checkpartBMin[1], checkpartBMax[0], checkpartBMax[1] ) );
mFeatureIndex.deleteData( otherPart, QgsRectangle( otherPartBMin[0], otherPartBMin[1], otherPartBMax[0], otherPartBMax[1] ) ) ;
mFeatureIndex.deleteData( partCheck, checkPartBoundsBefore );
mFeatureIndex.deleteData( otherPart, otherPartBoundsBefore ) ;
// reinsert merged line to r-tree (probably not needed)
otherPart->getBoundingBox( otherPartBMin, otherPartBMax );
mFeatureIndex.insertData( otherPart, QgsRectangle( otherPartBMin[0], otherPartBMin[1], otherPartBMax[0], otherPartBMax[1] ) );
mFeatureIndex.insertData( otherPart, otherPart->boundingBox() );
mConnectedFeaturesIds.insert( partCheck->featureId(), connectedFeaturesId );
mConnectedFeaturesIds.insert( otherPart->featureId(), connectedFeaturesId );
@ -411,9 +399,7 @@ void Layer::chopFeaturesAtRepeatDistance()
if ( shouldChop )
{
double bmin[2], bmax[2];
fpart->getBoundingBox( bmin, bmax );
mFeatureIndex.deleteData( fpart.get(), QgsRectangle( bmin[0], bmin[1], bmax[0], bmax[1] ) );
mFeatureIndex.deleteData( fpart.get(), fpart->boundingBox() );
const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( geosctxt, geom );
@ -473,8 +459,7 @@ void Layer::chopFeaturesAtRepeatDistance()
GEOSGeometry *newgeom = GEOSGeom_createLineString_r( geosctxt, cooSeq );
FeaturePart *newfpart = new FeaturePart( fpart->feature(), newgeom );
newFeatureParts.append( newfpart );
newfpart->getBoundingBox( bmin, bmax );
mFeatureIndex.insertData( newfpart, QgsRectangle( bmin[0], bmin[1], bmax[0], bmax[1] ) );
mFeatureIndex.insertData( newfpart, newfpart->boundingBox() );
repeatParts.push_back( newfpart );
break;
@ -498,8 +483,7 @@ void Layer::chopFeaturesAtRepeatDistance()
GEOSGeometry *newgeom = GEOSGeom_createLineString_r( geosctxt, cooSeq );
FeaturePart *newfpart = new FeaturePart( fpart->feature(), newgeom );
newFeatureParts.append( newfpart );
newfpart->getBoundingBox( bmin, bmax );
mFeatureIndex.insertData( newfpart, QgsRectangle( bmin[0], bmin[1], bmax[0], bmax[1] ) );
mFeatureIndex.insertData( newfpart, newfpart->boundingBox() );
part.clear();
part.push_back( p );
repeatParts.push_back( newfpart );

View File

@ -89,7 +89,7 @@ struct FeatCallBackCtx
std::list< std::unique_ptr< Feats > > *features = nullptr;
QgsGenericSpatialIndex< FeaturePart > *obstacleIndex = nullptr;
RTree<LabelPosition *, double, 2, double> *allCandidateIndex = nullptr;
QgsGenericSpatialIndex<LabelPosition> *allCandidateIndex = nullptr;
std::vector< std::unique_ptr< LabelPosition > > *positionsWithNoCandidates = nullptr;
const GEOSPreparedGeometry *mapBoundary = nullptr;
Pal *pal = nullptr;
@ -105,7 +105,7 @@ struct ObstacleCallBackCtx
struct FilterContext
{
RTree<LabelPosition *, double, 2, double> *allCandidatesIndex = nullptr;
QgsGenericSpatialIndex<LabelPosition> *allCandidatesIndex = nullptr;
Pal *pal = nullptr;
};
@ -189,7 +189,6 @@ std::unique_ptr<Problem> Pal::extract( const QgsRectangle &extent, const QgsGeom
context.layer = layer;
layer->mFeatureIndex.intersects( QgsRectangle( amin[ 0], amin[1], amax[0], amax[1] ), [&context]( const FeaturePart * constFeaturePart )->bool
{
double amin[2], amax[2];
FeaturePart *featurePart = const_cast< FeaturePart * >( constFeaturePart );
if ( context.pal->isCanceled() )
@ -198,8 +197,7 @@ std::unique_ptr<Problem> Pal::extract( const QgsRectangle &extent, const QgsGeom
// Holes of the feature are obstacles
for ( int i = 0; i < featurePart->getNumSelfObstacles(); i++ )
{
featurePart->getSelfObstacle( i )->getBoundingBox( amin, amax );
context.obstacleIndex->insertData( featurePart->getSelfObstacle( i ), QgsRectangle( amin[0], amin[1], amax[0], amax[1] ) );
context.obstacleIndex->insertData( featurePart->getSelfObstacle( i ), featurePart->getSelfObstacle( i )->boundingBox() );
if ( !featurePart->getSelfObstacle( i )->getHoleOf() )
{
@ -305,13 +303,27 @@ std::unique_ptr<Problem> Pal::extract( const QgsRectangle &extent, const QgsGeom
if ( filterCtx.pal->isCanceled() )
return false; // do not continue searching
double amin[2], amax[2];
part->getBoundingBox( amin, amax );
LabelPosition::PruneCtx pruneContext;
pruneContext.obstacle = const_cast< FeaturePart * >( part );
pruneContext.pal = filterCtx.pal;
filterCtx.allCandidatesIndex->Search( amin, amax, LabelPosition::pruneCallback, static_cast< void * >( &pruneContext ) );
filterCtx.allCandidatesIndex->intersects( part->boundingBox(), [&pruneContext]( const LabelPosition * candidatePosition ) -> bool{
FeaturePart *obstaclePart = pruneContext.obstacle;
// test whether we should ignore this obstacle for the candidate. We do this if:
// 1. it's not a hole, and the obstacle belongs to the same label feature as the candidate (e.g.,
// features aren't obstacles for their own labels)
// 2. it IS a hole, and the hole belongs to a different label feature to the candidate (e.g., holes
// are ONLY obstacles for the labels of the feature they belong to)
if ( ( !obstaclePart->getHoleOf() && candidatePosition->getFeaturePart()->hasSameLabelFeatureAs( obstaclePart ) )
|| ( obstaclePart->getHoleOf() && !candidatePosition->getFeaturePart()->hasSameLabelFeatureAs( dynamic_cast< FeaturePart * >( obstaclePart->getHoleOf() ) ) ) )
{
return true;
}
CostCalculator::addObstacleCostPenalty( const_cast< LabelPosition * >( candidatePosition ), obstaclePart, pruneContext.pal );
return true;
} );
return true;
} );
@ -407,6 +419,8 @@ std::unique_ptr<Problem> Pal::extract( const QgsRectangle &extent, const QgsGeom
int nbOverlaps = 0;
double amin[2];
double amax[2];
while ( !features.empty() ) // foreach feature
{
if ( isCanceled() )
@ -426,10 +440,18 @@ std::unique_ptr<Problem> Pal::extract( const QgsRectangle &extent, const QgsGeom
//prob->feat[idlp] = j;
lp->getBoundingBox( amin, amax );
// lookup for overlapping candidate
prob->mAllCandidatesIndex.Search( amin, amax, LabelPosition::countOverlapCallback, static_cast< void * >( lp.get() ) );
lp->getBoundingBox( amin, amax );
prob->mAllCandidatesIndex.intersects( QgsRectangle( amin[0], amin[1], amax[0], amax[1] ), [&lp]( const LabelPosition * lp2 )->bool
{
if ( lp->isInConflict( lp2 ) )
{
lp->incrementNumOverlaps();
}
return true;
} );
nbOverlaps += lp->getNumOverlaps();

View File

@ -148,14 +148,6 @@ namespace pal
int getGeosType() const { return type; }
void getBoundingBox( double min[2], double max[2] ) const
{
min[0] = xmin;
min[1] = ymin;
max[0] = xmax;
max[1] = ymax;
}
/**
* Returns the point set bounding box.
*/

View File

@ -108,7 +108,16 @@ void Problem::reduce()
lp2->getBoundingBox( amin, amax );
mNbOverlap -= lp2->getNumOverlaps();
mAllCandidatesIndex.Search( amin, amax, LabelPosition::removeOverlapCallback, reinterpret_cast< void * >( lp2 ) );
mAllCandidatesIndex.intersects( QgsRectangle( amin[0], amin[1], amax[0], amax[1] ), [&lp2]( const LabelPosition * lp ) -> bool
{
if ( lp2->isInConflict( lp ) )
{
const_cast< LabelPosition * >( lp )->decrementNumOverlaps();
lp2->decrementNumOverlaps();
}
return true;
} );
lp2->removeFromIndex( mAllCandidatesIndex );
}
@ -127,59 +136,39 @@ void Problem::reduce()
struct FalpContext
{
PriorityQueue *list = nullptr;
LabelPosition *lp = nullptr;
RTree <LabelPosition *, double, 2, double> *candidatesIndex = nullptr;
const LabelPosition *lp = nullptr;
QgsGenericSpatialIndex< LabelPosition > *candidatesIndex = nullptr;
};
bool falpCallback2( LabelPosition *lp, void *ctx )
{
FalpContext *context = reinterpret_cast< FalpContext * >( ctx );
LabelPosition *lp2 = context->lp;
PriorityQueue *list = context->list;
if ( lp->getId() != lp2->getId() && list->isIn( lp->getId() ) && lp->isInConflict( lp2 ) )
{
list->decreaseKey( lp->getId() );
}
return true;
}
void ignoreLabel( LabelPosition *lp, PriorityQueue &list, RTree <LabelPosition *, double, 2, double> &candidatesIndex )
void ignoreLabel( const LabelPosition *lp, PriorityQueue &list, QgsGenericSpatialIndex< LabelPosition > &candidatesIndex )
{
FalpContext context;
context.candidatesIndex = nullptr;
context.list = &list;
double amin[2];
double amax[2];
if ( list.isIn( lp->getId() ) )
{
list.remove( lp->getId() );
lp->getBoundingBox( amin, amax );
context.lp = lp;
candidatesIndex.Search( amin, amax, falpCallback2, &context );
double amin[2];
double amax[2];
lp->getBoundingBox( amin, amax );
candidatesIndex.intersects( QgsRectangle( amin[0], amin[1], amax[0], amax[1] ), [&context]( const LabelPosition * lp )->bool
{
const LabelPosition *lp2 = context.lp;
PriorityQueue *list = context.list;
if ( lp->getId() != lp2->getId() && list->isIn( lp->getId() ) && lp->isInConflict( lp2 ) )
{
list->decreaseKey( lp->getId() );
}
return true;
} );
}
}
bool falpCallback1( LabelPosition *lp, void *ctx )
{
FalpContext *context = reinterpret_cast< FalpContext * >( ctx );
LabelPosition *lp2 = context->lp;
PriorityQueue *list = context->list;
if ( lp2->isInConflict( lp ) )
{
ignoreLabel( lp, *list, *context->candidatesIndex );
}
return true;
}
/* Better initial solution
* Step one FALP (Yamamoto, Camara, Lorena 2005)
*/
@ -243,8 +232,18 @@ void Problem::init_sol_falp()
lp->getBoundingBox( amin, amax );
context.lp = lp;
mAllCandidatesIndex.Search( amin, amax, falpCallback1, reinterpret_cast< void * >( &context ) );
mActiveCandidatesIndex.Insert( amin, amax, lp );
mAllCandidatesIndex.intersects( QgsRectangle( amin[0], amin[1], amax[0], amax[1] ), [&context]( const LabelPosition * lp ) ->bool
{
const LabelPosition *lp2 = context.lp;
PriorityQueue *list = context.list;
if ( lp2->isInConflict( lp ) )
{
ignoreLabel( lp, *list, *context.candidatesIndex );
}
return true;
} );
mActiveCandidatesIndex.insertData( lp, QgsRectangle( amin[0], amin[1], amax[0], amax[1] ) );
}
if ( mDisplayAll )
@ -268,7 +267,14 @@ void Problem::init_sol_falp()
lp->getBoundingBox( amin, amax );
mActiveCandidatesIndex.Search( amin, amax, LabelPosition::countOverlapCallback, lp );
mActiveCandidatesIndex.intersects( QgsRectangle( amin[0], amin[1], amax[0], amax[1] ), [&lp]( const LabelPosition * lp2 )->bool
{
if ( lp->isInConflict( lp2 ) )
{
lp->incrementNumOverlaps();
}
return true;
} );
if ( lp->getNumOverlaps() < nbOverlap )
{
@ -300,52 +306,6 @@ struct ChainContext
} ;
bool chainCallback( LabelPosition *lp, void *context )
{
ChainContext *ctx = reinterpret_cast< ChainContext * >( context );
if ( lp->isInConflict( ctx->lp ) )
{
int feat, rfeat;
bool sub = nullptr != ctx->featWrap;
feat = lp->getProblemFeatureId();
if ( sub )
{
rfeat = feat;
feat = ctx->featWrap[feat];
}
else
rfeat = feat;
if ( feat >= 0 && ( *ctx->tmpsol )[feat] == lp->getId() )
{
if ( sub && feat < ctx->borderSize )
{
throw - 2;
}
}
// is there any cycles ?
QLinkedList< ElemTrans * >::iterator cur;
for ( cur = ctx->currentChain->begin(); cur != ctx->currentChain->end(); ++cur )
{
if ( ( *cur )->feat == feat )
{
throw - 1;
}
}
if ( !ctx->conflicts->contains( feat ) )
{
ctx->conflicts->append( feat );
*ctx->delta_tmp += lp->cost() + ( * ctx->inactiveCost )[rfeat];
}
}
return true;
}
inline Chain *Problem::chain( int seed )
{
@ -373,8 +333,6 @@ inline Chain *Problem::chain( int seed )
std::vector< int > tmpsol( mSol.activeLabelIds );
LabelPosition *lp = nullptr;
double amin[2];
double amax[2];
ChainContext context;
context.featWrap = nullptr;
@ -386,6 +344,9 @@ inline Chain *Problem::chain( int seed )
context.conflicts = &conflicts;
context.delta_tmp = &delta_tmp;
double amin[2];
double amax[2];
delta = 0;
while ( seed != -1 )
{
@ -416,11 +377,52 @@ inline Chain *Problem::chain( int seed )
lp = mLabelPositions[ lid ].get();
// evaluate conflicts graph in solution after moving seed's label
lp->getBoundingBox( amin, amax );
context.lp = lp;
mActiveCandidatesIndex.Search( amin, amax, chainCallback, reinterpret_cast< void * >( &context ) );
lp->getBoundingBox( amin, amax );
mActiveCandidatesIndex.intersects( QgsRectangle( amin[0], amin[1], amax[0], amax[1] ), [&context]( const LabelPosition * lp ) -> bool
{
if ( lp->isInConflict( context.lp ) )
{
int feat, rfeat;
bool sub = nullptr != context.featWrap;
feat = lp->getProblemFeatureId();
if ( sub )
{
rfeat = feat;
feat = context.featWrap[feat];
}
else
rfeat = feat;
if ( feat >= 0 && ( *context.tmpsol )[feat] == lp->getId() )
{
if ( sub && feat < context.borderSize )
{
throw - 2;
}
}
// is there any cycles ?
QLinkedList< ElemTrans * >::iterator cur;
for ( cur = context.currentChain->begin(); cur != context.currentChain->end(); ++cur )
{
if ( ( *cur )->feat == feat )
{
throw - 1;
}
}
if ( !context.conflicts->contains( feat ) )
{
context.conflicts->append( feat );
*context.delta_tmp += lp->cost() + ( * context.inactiveCost )[rfeat];
}
}
return true;
} );
// no conflict -> end of chain
if ( conflicts.isEmpty() )
@ -626,28 +628,6 @@ struct NokContext
int *wrap = nullptr;
};
bool nokCallback( LabelPosition *lp, void *context )
{
NokContext *ctx = reinterpret_cast< NokContext *>( context );
LabelPosition *lp2 = ctx->lp;
bool *ok = ctx->ok;
int *wrap = ctx->wrap;
if ( lp2->isInConflict( lp ) )
{
if ( wrap )
{
ok[wrap[lp->getProblemFeatureId()]] = false;
}
else
{
ok[lp->getProblemFeatureId()] = false;
}
}
return true;
}
void Problem::chain_search()
{
if ( mFeatureCount == 0 )
@ -659,8 +639,6 @@ void Problem::chain_search()
int fid;
int lid;
int popit = 0;
double amin[2];
double amax[2];
NokContext context;
context.ok = ok;
@ -678,6 +656,9 @@ void Problem::chain_search()
int iter = 0;
double amin[2];
double amax[2];
while ( true )
{
@ -709,11 +690,28 @@ void Problem::chain_search()
{
LabelPosition *old = mLabelPositions[ mSol.activeLabelIds[fid] ].get();
old->removeFromIndex( mActiveCandidatesIndex );
old->getBoundingBox( amin, amax );
context.lp = old;
mAllCandidatesIndex.Search( amin, amax, nokCallback, &context );
old->getBoundingBox( amin, amax );
mAllCandidatesIndex.intersects( QgsRectangle( amin[0], amin[1], amax[0], amax[1] ), [&context]( const LabelPosition * lp ) ->bool
{
LabelPosition *lp2 = context.lp;
bool *ok = context.ok;
int *wrap = context.wrap;
if ( lp2->isInConflict( lp ) )
{
if ( wrap )
{
ok[wrap[lp->getProblemFeatureId()]] = false;
}
else
{
ok[lp->getProblemFeatureId()] = false;
}
}
return true;
} );
}
mSol.activeLabelIds[fid] = lid;
@ -785,12 +783,13 @@ void Problem::solution_cost()
context.inactiveCost = &mInactiveCost;
context.nbOv = &nbOv;
context.cost = &mSol.totalCost;
double amin[2];
double amax[2];
LabelPosition *lp = nullptr;
int nbHidden = 0;
double amin[2];
double amax[2];
for ( std::size_t i = 0; i < mFeatureCount; i++ )
{
if ( mSol.activeLabelIds[i] == -1 )
@ -803,10 +802,22 @@ void Problem::solution_cost()
nbOv = 0;
lp = mLabelPositions[ mSol.activeLabelIds[i] ].get();
lp->getBoundingBox( amin, amax );
context.lp = lp;
mActiveCandidatesIndex.Search( amin, amax, LabelPosition::countFullOverlapCallback, &context );
lp->getBoundingBox( amin, amax );
mActiveCandidatesIndex.intersects( QgsRectangle( amin[0], amin[1], amax[0], amax[1] ), [&context]( const LabelPosition * lp )->bool
{
LabelPosition *lp2 = context.lp;
double *cost = context.cost;
int *nbOv = context.nbOv;
std::vector< double > &inactiveCost = *context.inactiveCost;
if ( lp2->isInConflict( lp ) )
{
( *nbOv ) ++;
*cost += inactiveCost[lp->getProblemFeatureId()] + lp->cost();
}
return true;
} );
mSol.totalCost += lp->cost();
}

View File

@ -36,7 +36,7 @@
#include "qgis_core.h"
#include <list>
#include <QList>
#include "rtree.hpp"
#include "qgsgenericspatialindex.h"
namespace pal
{
@ -178,8 +178,8 @@ namespace pal
std::vector< std::unique_ptr< LabelPosition > > mLabelPositions;
RTree<LabelPosition *, double, 2, double> mAllCandidatesIndex;
RTree<LabelPosition *, double, 2, double> mActiveCandidatesIndex;
QgsGenericSpatialIndex<LabelPosition> mAllCandidatesIndex;
QgsGenericSpatialIndex<LabelPosition> mActiveCandidatesIndex;
std::vector< std::unique_ptr< LabelPosition > > mPositionsWithNoCandidates;

View File

@ -69,6 +69,7 @@ class GenericIndexVisitor : public SpatialIndex::IVisitor
template <class T>
QgsGenericSpatialIndex< T >::QgsGenericSpatialIndex()
: mMutex( QMutex::Recursive )
{
mStorageManager.reset( SpatialIndex::StorageManager::createNewMemoryStorageManager() );
mRTree = createSpatialIndex( *mStorageManager );
@ -142,6 +143,8 @@ bool QgsGenericSpatialIndex<T>::intersects( const QgsRectangle &rectangle, const
namespace pal
{
class FeaturePart;
class LabelPosition;
}
template class QgsGenericSpatialIndex<pal::FeaturePart>;
template class QgsGenericSpatialIndex<pal::LabelPosition>;