Fixed ratsnest for nodes surrounded with zones
This commit is contained in:
parent
b00ca19f41
commit
516510774c
|
@ -101,7 +101,7 @@ protected:
|
|||
#endif
|
||||
|
||||
/// Node coordinates
|
||||
int m_x, m_y;
|
||||
const int m_x, m_y;
|
||||
|
||||
/// Tag for quick connection resolution
|
||||
int m_tag;
|
||||
|
|
|
@ -127,6 +127,7 @@ static std::vector<RN_EDGE_MST_PTR>* kruskalMST( RN_LINKS::RN_EDGE_LIST& aEdges,
|
|||
// Set tags for marking cycles
|
||||
boost::unordered_map<RN_NODE_PTR, int> tags;
|
||||
unsigned int tag = 0;
|
||||
|
||||
for( RN_NODE_PTR& node : aNodes )
|
||||
{
|
||||
node->SetTag( tag );
|
||||
|
@ -158,40 +159,41 @@ static std::vector<RN_EDGE_MST_PTR>* kruskalMST( RN_LINKS::RN_EDGE_LIST& aEdges,
|
|||
ratsnestLines = true;
|
||||
|
||||
// Update tags
|
||||
std::list<int>::iterator it, itEnd;
|
||||
|
||||
if( ratsnestLines )
|
||||
{
|
||||
for( it = cycles[trgTag].begin(), itEnd = cycles[trgTag].end(); it != itEnd; ++it )
|
||||
for( auto it = cycles[trgTag].begin(); it != cycles[trgTag].end(); ++it )
|
||||
{
|
||||
tags[aNodes[*it]] = srcTag;
|
||||
}
|
||||
else
|
||||
{
|
||||
for( it = cycles[trgTag].begin(), itEnd = cycles[trgTag].end(); it != itEnd; ++it ) {
|
||||
tags[aNodes[*it]] = srcTag;
|
||||
aNodes[*it]->SetTag( srcTag );
|
||||
}
|
||||
}
|
||||
|
||||
// Move nodes that were marked with old tag to the list marked with the new tag
|
||||
cycles[srcTag].splice( cycles[srcTag].end(), cycles[trgTag] );
|
||||
|
||||
if( ratsnestLines )
|
||||
{
|
||||
// Do a copy of edge, but make it RN_EDGE_MST. In contrary to RN_EDGE,
|
||||
// RN_EDGE_MST saves both source and target node and does not require any other
|
||||
// edges to exist for getting source/target nodes
|
||||
RN_EDGE_MST_PTR newEdge = std::make_shared<RN_EDGE_MST>( dt->GetSourceNode(),
|
||||
dt->GetTargetNode(),
|
||||
dt->GetWeight() );
|
||||
|
||||
assert( newEdge->GetSourceNode()->GetTag() != newEdge->GetTargetNode()->GetTag() );
|
||||
assert( newEdge->GetWeight() > 0 );
|
||||
|
||||
mst->push_back( newEdge );
|
||||
++mstSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
//for( it = cycles[trgTag].begin(), itEnd = cycles[trgTag].end(); it != itEnd; ++it )
|
||||
//for( auto it : cycles[trgTag] )
|
||||
for( auto it = cycles[trgTag].begin(); it != cycles[trgTag].end(); ++it )
|
||||
{
|
||||
tags[aNodes[*it]] = srcTag;
|
||||
aNodes[*it]->SetTag( srcTag );
|
||||
}
|
||||
|
||||
// Processing a connection, decrease the expected size of the ratsnest MST
|
||||
--mstExpectedSize;
|
||||
}
|
||||
|
||||
// Move nodes that were marked with old tag to the list marked with the new tag
|
||||
cycles[srcTag].splice( cycles[srcTag].end(), cycles[trgTag] );
|
||||
}
|
||||
|
||||
// Remove the edge that was just processed
|
||||
|
@ -209,42 +211,60 @@ void RN_NET::validateEdge( RN_EDGE_MST_PTR& aEdge )
|
|||
{
|
||||
RN_NODE_PTR source = aEdge->GetSourceNode();
|
||||
RN_NODE_PTR target = aEdge->GetTargetNode();
|
||||
bool valid = true;
|
||||
bool update = false, changed = false;
|
||||
|
||||
// If any of nodes belonging to the edge has the flag set,
|
||||
// change it to the closest node that has flag cleared
|
||||
if( source->GetNoLine() )
|
||||
// note: finding the right nodes can be done iteratively to get the best results,
|
||||
// but it is not likely to be worth the time cost
|
||||
do
|
||||
{
|
||||
valid = false;
|
||||
std::list<RN_NODE_PTR> closest = GetClosestNodes( source, LINE_TARGET() );
|
||||
|
||||
for( RN_NODE_PTR& node : closest )
|
||||
if( changed || source->GetNoLine() )
|
||||
{
|
||||
if( node && node != target )
|
||||
changed = false;
|
||||
std::list<RN_NODE_PTR> closest = GetClosestNodes( target,
|
||||
LINE_TARGET_SAME_TAG( source->GetTag() ) );
|
||||
|
||||
if( !closest.empty() )
|
||||
{
|
||||
source = node;
|
||||
break;
|
||||
RN_NODE_PTR& node = closest.front();
|
||||
|
||||
if( node != source )
|
||||
{
|
||||
changed = true;
|
||||
update = true;
|
||||
source = node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( changed || target->GetNoLine() )
|
||||
{
|
||||
changed = false;
|
||||
std::list<RN_NODE_PTR> closest = GetClosestNodes( source,
|
||||
LINE_TARGET_SAME_TAG( target->GetTag() ) );
|
||||
|
||||
if( !closest.empty() )
|
||||
{
|
||||
RN_NODE_PTR& node = closest.front();
|
||||
|
||||
if( node != target )
|
||||
{
|
||||
changed = true;
|
||||
update = true;
|
||||
target = node;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
while( changed );
|
||||
|
||||
if( target->GetNoLine() )
|
||||
{
|
||||
valid = false;
|
||||
std::list<RN_NODE_PTR> closest = GetClosestNodes( target, LINE_TARGET() );
|
||||
|
||||
for( RN_NODE_PTR& node : closest )
|
||||
{
|
||||
if( node && node != source )
|
||||
{
|
||||
target = node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
assert( source->GetTag() >= 0 && target->GetTag() >= 0 );
|
||||
assert( source->GetTag() != target->GetTag() );
|
||||
assert( source != target );
|
||||
|
||||
// Replace an invalid edge with new, valid one
|
||||
if( !valid )
|
||||
if( update )
|
||||
aEdge.reset( new RN_EDGE_MST( source, target ) );
|
||||
}
|
||||
|
||||
|
@ -326,7 +346,8 @@ void RN_NET::compute()
|
|||
const RN_LINKS::RN_NODE_SET& boardNodes = m_links.GetNodes();
|
||||
const RN_LINKS::RN_EDGE_LIST& boardEdges = m_links.GetConnections();
|
||||
|
||||
// Special cases do not need complicated algorithms
|
||||
// Special cases do not need complicated algorithms (actually, it does not work well with
|
||||
// the Delaunay triangulator)
|
||||
if( boardNodes.size() <= 2 )
|
||||
{
|
||||
m_rnEdges.reset( new std::vector<RN_EDGE_MST_PTR>( 0 ) );
|
||||
|
@ -337,12 +358,18 @@ void RN_NET::compute()
|
|||
RN_LINKS::RN_NODE_SET::iterator last = ++boardNodes.begin();
|
||||
|
||||
// There can be only one possible connection, but it is missing
|
||||
m_rnEdges->push_back( std::make_shared<RN_EDGE_MST>( *boardNodes.begin(), *last ) );
|
||||
RN_EDGE_MST_PTR edge = std::make_shared<RN_EDGE_MST>( *boardNodes.begin(), *last );
|
||||
edge->GetSourceNode()->SetTag( 0 );
|
||||
edge->GetTargetNode()->SetTag( 1 );
|
||||
m_rnEdges->push_back( edge );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set tags to nodes as connected
|
||||
for( RN_NODE_PTR node : boardNodes )
|
||||
node->SetTag( 0 );
|
||||
}
|
||||
|
||||
// Set tags to nodes as connected
|
||||
for( RN_NODE_PTR node : boardNodes )
|
||||
node->SetTag( 0 );
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -612,8 +639,7 @@ std::list<RN_NODE_PTR> RN_NET::GetClosestNodes( const RN_NODE_PTR& aNode, int aN
|
|||
const RN_LINKS::RN_NODE_SET& nodes = m_links.GetNodes();
|
||||
|
||||
// Copy nodes
|
||||
for( const RN_NODE_PTR& node : nodes )
|
||||
closest.push_back( node );
|
||||
std::copy( nodes.begin(), nodes.end(), std::back_inserter( closest ) );
|
||||
|
||||
// Sort by the distance from aNode
|
||||
closest.sort( std::bind( sortDistance, std::cref( aNode ), _1, _2 ) );
|
||||
|
@ -635,9 +661,8 @@ std::list<RN_NODE_PTR> RN_NET::GetClosestNodes( const RN_NODE_PTR& aNode,
|
|||
std::list<RN_NODE_PTR> closest;
|
||||
const RN_LINKS::RN_NODE_SET& nodes = m_links.GetNodes();
|
||||
|
||||
// Copy nodes
|
||||
for( const RN_NODE_PTR& node : nodes )
|
||||
closest.push_back( node );
|
||||
// Copy filtered nodes
|
||||
std::copy_if( nodes.begin(), nodes.end(), std::back_inserter( closest ), std::cref( aFilter ) );
|
||||
|
||||
// Sort by the distance from aNode
|
||||
closest.sort( std::bind( sortDistance, std::cref( aNode ), _1, _2 ) );
|
||||
|
@ -645,9 +670,6 @@ std::list<RN_NODE_PTR> RN_NET::GetClosestNodes( const RN_NODE_PTR& aNode,
|
|||
// aNode should not be returned in the results
|
||||
closest.remove( aNode );
|
||||
|
||||
// Filter out by condition
|
||||
std::remove_if( closest.begin(), closest.end(), aFilter );
|
||||
|
||||
// Trim the result to the asked size
|
||||
if( aNumber > 0 )
|
||||
closest.resize( std::min( static_cast<size_t>( aNumber ), nodes.size() ) );
|
||||
|
|
|
@ -92,7 +92,7 @@ struct RN_NODE_FILTER : public std::unary_function<const RN_NODE_PTR&, bool>
|
|||
RN_NODE_AND_FILTER operator&&( const RN_NODE_FILTER& aFilter1, const RN_NODE_FILTER& aFilter2 );
|
||||
RN_NODE_OR_FILTER operator||( const RN_NODE_FILTER& aFilter1, const RN_NODE_FILTER& aFilter2 );
|
||||
|
||||
///> Filters out nodes that cannot be a ratsnest line target
|
||||
///> Leaves nodes that can be a ratsnest line target
|
||||
struct LINE_TARGET : public RN_NODE_FILTER
|
||||
{
|
||||
bool operator()( const RN_NODE_PTR& aNode ) const
|
||||
|
@ -101,20 +101,35 @@ struct LINE_TARGET : public RN_NODE_FILTER
|
|||
}
|
||||
};
|
||||
|
||||
///> Filters out nodes with a specific tag
|
||||
struct DIFF_TAG : public RN_NODE_FILTER
|
||||
///> Leaves nodes that can be a ratsnest line target and have a specific tag
|
||||
struct LINE_TARGET_SAME_TAG : public RN_NODE_FILTER
|
||||
{
|
||||
DIFF_TAG( int aTag ) :
|
||||
LINE_TARGET_SAME_TAG( int aTag ) :
|
||||
m_tag( aTag )
|
||||
{}
|
||||
|
||||
bool operator()( const RN_NODE_PTR& aNode ) const
|
||||
{
|
||||
return aNode->GetTag() != m_tag;
|
||||
return !aNode->GetNoLine() && aNode->GetTag() == m_tag;
|
||||
}
|
||||
|
||||
private:
|
||||
int m_tag;
|
||||
private:
|
||||
int m_tag;
|
||||
};
|
||||
|
||||
struct LINE_TARGET_DIFF_TAG : public RN_NODE_FILTER
|
||||
{
|
||||
LINE_TARGET_DIFF_TAG( int aTag ) :
|
||||
m_tag( aTag )
|
||||
{}
|
||||
|
||||
bool operator()( const RN_NODE_PTR& aNode ) const
|
||||
{
|
||||
return !aNode->GetNoLine() && aNode->GetTag() == m_tag;
|
||||
}
|
||||
|
||||
private:
|
||||
int m_tag;
|
||||
};
|
||||
|
||||
struct RN_NODE_AND_FILTER : public RN_NODE_FILTER
|
||||
|
|
Loading…
Reference in New Issue