|
|
|
@ -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 ) |
|
|
|
tags[aNodes[*it]] = srcTag; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
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; |
|
|
|
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( target->GetNoLine() ) |
|
|
|
{ |
|
|
|
valid = false; |
|
|
|
std::list<RN_NODE_PTR> closest = GetClosestNodes( target, LINE_TARGET() ); |
|
|
|
|
|
|
|
for( RN_NODE_PTR& node : closest ) |
|
|
|
if( changed || target->GetNoLine() ) |
|
|
|
{ |
|
|
|
if( node && node != source ) |
|
|
|
changed = false; |
|
|
|
std::list<RN_NODE_PTR> closest = GetClosestNodes( source, |
|
|
|
LINE_TARGET_SAME_TAG( target->GetTag() ) ); |
|
|
|
|
|
|
|
if( !closest.empty() ) |
|
|
|
{ |
|
|
|
target = node; |
|
|
|
break; |
|
|
|
RN_NODE_PTR& node = closest.front(); |
|
|
|
|
|
|
|
if( node != target ) |
|
|
|
{ |
|
|
|
changed = true; |
|
|
|
update = true; |
|
|
|
target = node; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
while( changed ); |
|
|
|
|
|
|
|
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() ) ); |
|
|
|
|