Fixed ratsnest for nodes surrounded with zones
This commit is contained in:
parent
b00ca19f41
commit
516510774c
|
@ -101,7 +101,7 @@ protected:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// Node coordinates
|
/// Node coordinates
|
||||||
int m_x, m_y;
|
const int m_x, m_y;
|
||||||
|
|
||||||
/// Tag for quick connection resolution
|
/// Tag for quick connection resolution
|
||||||
int m_tag;
|
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
|
// Set tags for marking cycles
|
||||||
boost::unordered_map<RN_NODE_PTR, int> tags;
|
boost::unordered_map<RN_NODE_PTR, int> tags;
|
||||||
unsigned int tag = 0;
|
unsigned int tag = 0;
|
||||||
|
|
||||||
for( RN_NODE_PTR& node : aNodes )
|
for( RN_NODE_PTR& node : aNodes )
|
||||||
{
|
{
|
||||||
node->SetTag( tag );
|
node->SetTag( tag );
|
||||||
|
@ -158,40 +159,41 @@ static std::vector<RN_EDGE_MST_PTR>* kruskalMST( RN_LINKS::RN_EDGE_LIST& aEdges,
|
||||||
ratsnestLines = true;
|
ratsnestLines = true;
|
||||||
|
|
||||||
// Update tags
|
// Update tags
|
||||||
std::list<int>::iterator it, itEnd;
|
|
||||||
|
|
||||||
if( ratsnestLines )
|
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;
|
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,
|
// 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
|
// RN_EDGE_MST saves both source and target node and does not require any other
|
||||||
// edges to exist for getting source/target nodes
|
// edges to exist for getting source/target nodes
|
||||||
RN_EDGE_MST_PTR newEdge = std::make_shared<RN_EDGE_MST>( dt->GetSourceNode(),
|
RN_EDGE_MST_PTR newEdge = std::make_shared<RN_EDGE_MST>( dt->GetSourceNode(),
|
||||||
dt->GetTargetNode(),
|
dt->GetTargetNode(),
|
||||||
dt->GetWeight() );
|
dt->GetWeight() );
|
||||||
|
|
||||||
|
assert( newEdge->GetSourceNode()->GetTag() != newEdge->GetTargetNode()->GetTag() );
|
||||||
|
assert( newEdge->GetWeight() > 0 );
|
||||||
|
|
||||||
mst->push_back( newEdge );
|
mst->push_back( newEdge );
|
||||||
++mstSize;
|
++mstSize;
|
||||||
}
|
}
|
||||||
else
|
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
|
// Processing a connection, decrease the expected size of the ratsnest MST
|
||||||
--mstExpectedSize;
|
--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
|
// 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 source = aEdge->GetSourceNode();
|
||||||
RN_NODE_PTR target = aEdge->GetTargetNode();
|
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,
|
// If any of nodes belonging to the edge has the flag set,
|
||||||
// change it to the closest node that has flag cleared
|
// 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;
|
if( changed || source->GetNoLine() )
|
||||||
std::list<RN_NODE_PTR> closest = GetClosestNodes( source, LINE_TARGET() );
|
|
||||||
|
|
||||||
for( RN_NODE_PTR& node : closest )
|
|
||||||
{
|
{
|
||||||
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;
|
RN_NODE_PTR& node = closest.front();
|
||||||
break;
|
|
||||||
|
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() )
|
assert( source->GetTag() >= 0 && target->GetTag() >= 0 );
|
||||||
{
|
assert( source->GetTag() != target->GetTag() );
|
||||||
valid = false;
|
assert( source != target );
|
||||||
std::list<RN_NODE_PTR> closest = GetClosestNodes( target, LINE_TARGET() );
|
|
||||||
|
|
||||||
for( RN_NODE_PTR& node : closest )
|
|
||||||
{
|
|
||||||
if( node && node != source )
|
|
||||||
{
|
|
||||||
target = node;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Replace an invalid edge with new, valid one
|
// Replace an invalid edge with new, valid one
|
||||||
if( !valid )
|
if( update )
|
||||||
aEdge.reset( new RN_EDGE_MST( source, target ) );
|
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_NODE_SET& boardNodes = m_links.GetNodes();
|
||||||
const RN_LINKS::RN_EDGE_LIST& boardEdges = m_links.GetConnections();
|
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 )
|
if( boardNodes.size() <= 2 )
|
||||||
{
|
{
|
||||||
m_rnEdges.reset( new std::vector<RN_EDGE_MST_PTR>( 0 ) );
|
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();
|
RN_LINKS::RN_NODE_SET::iterator last = ++boardNodes.begin();
|
||||||
|
|
||||||
// There can be only one possible connection, but it is missing
|
// 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;
|
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();
|
const RN_LINKS::RN_NODE_SET& nodes = m_links.GetNodes();
|
||||||
|
|
||||||
// Copy nodes
|
// Copy nodes
|
||||||
for( const RN_NODE_PTR& node : nodes )
|
std::copy( nodes.begin(), nodes.end(), std::back_inserter( closest ) );
|
||||||
closest.push_back( node );
|
|
||||||
|
|
||||||
// Sort by the distance from aNode
|
// Sort by the distance from aNode
|
||||||
closest.sort( std::bind( sortDistance, std::cref( aNode ), _1, _2 ) );
|
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;
|
std::list<RN_NODE_PTR> closest;
|
||||||
const RN_LINKS::RN_NODE_SET& nodes = m_links.GetNodes();
|
const RN_LINKS::RN_NODE_SET& nodes = m_links.GetNodes();
|
||||||
|
|
||||||
// Copy nodes
|
// Copy filtered nodes
|
||||||
for( const RN_NODE_PTR& node : nodes )
|
std::copy_if( nodes.begin(), nodes.end(), std::back_inserter( closest ), std::cref( aFilter ) );
|
||||||
closest.push_back( node );
|
|
||||||
|
|
||||||
// Sort by the distance from aNode
|
// Sort by the distance from aNode
|
||||||
closest.sort( std::bind( sortDistance, std::cref( aNode ), _1, _2 ) );
|
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
|
// aNode should not be returned in the results
|
||||||
closest.remove( aNode );
|
closest.remove( aNode );
|
||||||
|
|
||||||
// Filter out by condition
|
|
||||||
std::remove_if( closest.begin(), closest.end(), aFilter );
|
|
||||||
|
|
||||||
// Trim the result to the asked size
|
// Trim the result to the asked size
|
||||||
if( aNumber > 0 )
|
if( aNumber > 0 )
|
||||||
closest.resize( std::min( static_cast<size_t>( aNumber ), nodes.size() ) );
|
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_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 );
|
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
|
struct LINE_TARGET : public RN_NODE_FILTER
|
||||||
{
|
{
|
||||||
bool operator()( const RN_NODE_PTR& aNode ) const
|
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
|
///> Leaves nodes that can be a ratsnest line target and have a specific tag
|
||||||
struct DIFF_TAG : public RN_NODE_FILTER
|
struct LINE_TARGET_SAME_TAG : public RN_NODE_FILTER
|
||||||
{
|
{
|
||||||
DIFF_TAG( int aTag ) :
|
LINE_TARGET_SAME_TAG( int aTag ) :
|
||||||
m_tag( aTag )
|
m_tag( aTag )
|
||||||
{}
|
{}
|
||||||
|
|
||||||
bool operator()( const RN_NODE_PTR& aNode ) const
|
bool operator()( const RN_NODE_PTR& aNode ) const
|
||||||
{
|
{
|
||||||
return aNode->GetTag() != m_tag;
|
return !aNode->GetNoLine() && aNode->GetTag() == m_tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_tag;
|
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
|
struct RN_NODE_AND_FILTER : public RN_NODE_FILTER
|
||||||
|
|
Loading…
Reference in New Issue