Skip to content
Permalink
Browse files
1. Use real builder-director pattern.
2. Replase QMap container to QVector, sort and bynary search. RAM saving at the same perfomance.
  • Loading branch information
stopa85milk committed May 31, 2011
1 parent fc3104f commit 6e0435a
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 71 deletions.
@@ -33,40 +33,14 @@ QgsGraphBuilder::~QgsGraphBuilder()
delete mGraph;
}

QgsPoint QgsGraphBuilder::addVertex( const QgsPoint& pt )
void QgsGraphBuilder::addVertex( int, const QgsPoint& pt )
{
int id = pointId( pt );
if ( id != -1 )
return mGraph->vertex( id ).point();

QgsPoint newPoint = pt;
if ( topologyTolerance() > 0 )
{
newPoint = QgsPoint( ceil( pt.x() / topologyTolerance() ),
ceil( pt.y() / topologyTolerance() ) );
}
int newId = mGraph->addVertex( pt );

mPointMap[ newPoint ] = newId;
return pt;
mGraph->addVertex( pt );
}

void QgsGraphBuilder::addArc( const QgsPoint& pt1, const QgsPoint& pt2, const QVector< QVariant >& prop )
void QgsGraphBuilder::addArc( int pt1id, const QgsPoint&, int pt2id, const QgsPoint&, const QVector< QVariant >& prop )
{
int pt1_id = pointId( pt1 );
int pt2_id = pointId( pt2 );
if ( pt1_id == -1 )
{
// FIXME to QgsDebug
std::cerr << "haven't vertex at (" << pt1.x() << ";" << pt1.y() << ")\n";
return;
}
if ( pt2_id == -1 )
{
std::cerr << "haven't vertex at (" << pt2.x() << ";" << pt2.y() << ")\n";
return;
}
mGraph->addEdge( pt1_id, pt2_id, prop );
mGraph->addEdge( pt1id, pt2id, prop );
}

QgsGraph* QgsGraphBuilder::graph()
@@ -75,21 +49,3 @@ QgsGraph* QgsGraphBuilder::graph()
mGraph = NULL;
return res;
}

int QgsGraphBuilder::pointId( const QgsPoint& pt )
{
QgsPoint findPoint = pt;
if ( topologyTolerance() > 0.0 )
{
findPoint = QgsPoint( ceil( pt.x() / topologyTolerance() ),
ceil( pt.y() / topologyTolerance() ) ) ;
}

std::map< QgsPoint, int, QgsPointCompare >::iterator it = mPointMap.find( findPoint );
if ( it != mPointMap.end() )
{
return it->second;
}

return -1;
}
@@ -60,22 +60,16 @@ class ANALYSIS_EXPORT QgsGraphBuilder : public QgsGraphBuilderInterface
/*
* MANDATORY BUILDER PROPERTY DECLARATION
*/
virtual QgsPoint addVertex( const QgsPoint& pt );
virtual void addVertex( int id, const QgsPoint& pt );

virtual void addArc( const QgsPoint& pt1, const QgsPoint& pt2, const QVector< QVariant >& prop );
virtual void addArc( int pt1id, const QgsPoint& pt1, int pt2id, const QgsPoint& pt2, const QVector< QVariant >& prop );

/**
* return QgsGraph result;
*/
QgsGraph* graph();

private:
// return -1 if pt not found
int pointId( const QgsPoint& pt );

QgsSpatialIndex mPointIndex;

std::map< QgsPoint, int, QgsPointCompare > mPointMap;

QgsGraph *mGraph;
};
@@ -77,12 +77,25 @@ class ANALYSIS_EXPORT QgsGraphBuilderInterface
return &mDa;
}

//! add vertex
virtual QgsPoint addVertex( const QgsPoint& pt )
{ return pt; }
/**
* add vertex
* @param id vertex identyficator
* @param pt vertex coordinate
* @note id and pt is a redundant interface. You can use coordinates or id for vertex identyfy
*/
virtual void addVertex( int id, const QgsPoint& pt )
{ }

//! add arc
virtual void addArc( const QgsPoint& pt1, const QgsPoint& pt2, const QVector< QVariant >& properties )
/**
* add arc
* @param pt1id first vertex identificator
* @param pt1 first vertex coordinate
* @param pt2id second vertex identificator
* @param pt2 second vertex coordinate
* @param properties arc properties
* @note pt1id, pt1 and pt2id, pt2 is a redundant interface. You can use vertex coordinates or their identificators.
*/
virtual void addArc( int pt1id, const QgsPoint& pt1, int pt2id, const QgsPoint& pt2, const QVector< QVariant >& properties )
{ }

private:
@@ -31,6 +31,58 @@

//standard includes
#include <limits>
#include <algorithm>

class QgsPointCompare
{
public:
QgsPointCompare( double tolerance ) :
mTolerance( tolerance )
{ }

bool operator()( const QgsPoint& p1, const QgsPoint& p2 ) const
{
if ( mTolerance <= 0 )
return p1.x() == p2.x() ? p1.y() < p2.y() : p1.x() < p2.x();

double tx1 = ceil( p1.x()/mTolerance );
double tx2 = ceil( p2.x()/mTolerance );
if ( tx1 == tx2 )
return ceil( p1.y()/mTolerance ) < ceil( p2.y()/mTolerance );
return tx1 < tx2;
}

private:
double mTolerance;
};

template <typename RandIter, typename Type, typename CompareOp > RandIter my_binary_search( RandIter begin, RandIter end, Type val, CompareOp comp)
{
// result if not found
RandIter not_found = end;

while ( true )
{
RandIter avg = begin + (end-begin)/2;
if ( begin == avg || end == avg )
{
if ( !comp( *begin, val ) && !comp( val, *begin ) )
return begin;
if ( !comp( *end, val ) && !comp( val, *end ) )
return end;

return not_found;
}
if ( comp( val, *avg ) )
end = avg;
else if ( comp( *avg, val ) )
begin = avg;
else
return avg;
}

return not_found;
}

QgsLineVectorLayerDirector::QgsLineVectorLayerDirector( const QString& layerId,
int directionFieldId,
@@ -80,12 +132,16 @@ void QgsLineVectorLayerDirector::makeGraph( QgsGraphBuilderInterface *builder, c
}

tiedPoint = QVector< QgsPoint >( additionalPoints.size(), QgsPoint( 0.0, 0.0 ) );

TiePointInfo tmpInfo;
tmpInfo.mLength = std::numeric_limits<double>::infinity();

QVector< TiePointInfo > pointLengthMap( additionalPoints.size(), tmpInfo );
QVector< TiePointInfo >::iterator pointLengthIt;

//Graph's points;
QVector< QgsPoint > points;

// begin: tie points to the graph
QgsAttributeList la;
vl->select( la );
@@ -98,7 +154,9 @@ void QgsLineVectorLayerDirector::makeGraph( QgsGraphBuilderInterface *builder, c
QgsPolyline::iterator pointIt;
for ( pointIt = pl.begin(); pointIt != pl.end(); ++pointIt )
{
pt2 = builder->addVertex( ct.transform( *pointIt ) );
pt2 = ct.transform( *pointIt );
points.push_back( pt2 );

if ( !isFirstPoint )
{
int i = 0;
@@ -131,7 +189,6 @@ void QgsLineVectorLayerDirector::makeGraph( QgsGraphBuilderInterface *builder, c
}
emit buildProgress( ++step, featureCount );
}

// end: tie points to graph

// add tied point to graph
@@ -140,10 +197,21 @@ void QgsLineVectorLayerDirector::makeGraph( QgsGraphBuilderInterface *builder, c
{
if ( tiedPoint[ i ] != QgsPoint( 0.0, 0.0 ) )
{
tiedPoint[ i ] = builder->addVertex( tiedPoint[ i ] );
pointLengthMap[ i ].mTiedPoint = tiedPoint[ i ];
points.push_back( tiedPoint [ i ] );
}
}

QgsPointCompare pointCompare( builder->topologyTolerance() );

qSort( points.begin(), points.end(), pointCompare );
QVector< QgsPoint >::iterator tmp = std::unique( points.begin(), points.end() );
points.resize( tmp - points.begin() );

for (i=0;i<points.size();++i)
builder->addVertex( i, points[ i ] );

for ( i = 0; i < tiedPoint.size() ; ++i)
tiedPoint[ i ] = *(my_binary_search( points.begin(), points.end(), tiedPoint[ i ], pointCompare ) );

{ // fill attribute list 'la'
QgsAttributeList tmpAttr;
@@ -216,10 +284,10 @@ void QgsLineVectorLayerDirector::makeGraph( QgsGraphBuilderInterface *builder, c
QgsPolyline::iterator pointIt;
for ( pointIt = pl.begin(); pointIt != pl.end(); ++pointIt )
{
pt2 = builder->addVertex( ct.transform( *pointIt ) );
pt2 = ct.transform( *pointIt );

if ( !isFirstPoint )
{

std::map< double, QgsPoint > pointsOnArc;
pointsOnArc[ 0.0 ] = pt1;
pointsOnArc[ pt1.sqrDist( pt2 )] = pt2;
@@ -236,11 +304,16 @@ void QgsLineVectorLayerDirector::makeGraph( QgsGraphBuilderInterface *builder, c
std::map< double, QgsPoint >::iterator pointsIt;
QgsPoint pt1;
QgsPoint pt2;
int pt1idx = -1, pt2idx = -1;
bool isFirstPoint = true;
for ( pointsIt = pointsOnArc.begin(); pointsIt != pointsOnArc.end(); ++pointsIt )
{
pt2 = pointsIt->second;
if ( !isFirstPoint )
tmp = my_binary_search( points.begin(), points.end(), pt2, pointCompare );
pt2 = *tmp;
pt2idx = tmp - points.begin();

if ( !isFirstPoint && pt1 != pt2 )
{
double distance = builder->distanceArea()->measureLine( pt1, pt2 );
QVector< QVariant > prop;
@@ -253,14 +326,15 @@ void QgsLineVectorLayerDirector::makeGraph( QgsGraphBuilderInterface *builder, c
if ( directionType == 1 ||
directionType == 3 )
{
builder->addArc( pt1, pt2, prop );
builder->addArc( pt1idx, pt1, pt2idx, pt2, prop );
}
if ( directionType == 2 ||
directionType == 3 )
{
builder->addArc( pt2, pt1, prop );
builder->addArc( pt2idx, pt2, pt1idx, pt1, prop );
}
}
pt1idx = pt2idx;
pt1 = pt2;
isFirstPoint = false;
}
@@ -282,7 +282,7 @@ bool RgShortestPathWidget::getPath( QgsGraph* shortestTree, QgsPoint& p1, QgsPoi
QVector< double > pointCost(0,0.0);

int startVertexIdx = graph->findVertex( p1 );
std::cout << " startVertexIdx " << startVertexIdx << "\n";

int criterionNum = 0;
if ( mCriterionName->currentIndex() > 0 )
criterionNum = 1;

0 comments on commit 6e0435a

Please sign in to comment.