Allow shoving and springback when dragging vias (either connected or free).

Fixes: lp:1833216
* https://bugs.launchpad.net/kicad/+bug/1833216
This commit is contained in:
Jeff Young 2019-07-22 17:46:20 -06:00
parent 8c77d31d4d
commit c1fcb1d895
3 changed files with 61 additions and 20 deletions

View File

@ -89,6 +89,22 @@ public:
m_hasVia = false; m_hasVia = false;
} }
/**
* Constructor
* Constructs a LINE for a lone VIA (ie a stitching via).
* @param aVia
*/
LINE( const VIA& aVia ) :
ITEM( LINE_T )
{
m_hasVia = true;
m_via = aVia;
m_width = aVia.Diameter();
m_net = aVia.Net();
m_layers = aVia.Layers();
m_rank = aVia.Rank();
}
~LINE(); ~LINE();
static inline bool ClassOf( const ITEM* aItem ) static inline bool ClassOf( const ITEM* aItem )

View File

@ -530,17 +530,20 @@ SHOVE::SHOVE_STATUS SHOVE::onCollidingSolid( LINE& aCurrent, ITEM* aObstacle )
} }
bool SHOVE::reduceSpringback( const ITEM_SET& aHeadSet ) /*
* Pops NODE stackframes which no longer collide with aHeadSet. Optionally sets aDraggedVia
* to the dragged via of the last unpopped state.
*/
NODE* SHOVE::reduceSpringback( const ITEM_SET& aHeadSet, VIA** aDraggedVia )
{ {
bool rv = false;
while( !m_nodeStack.empty() ) while( !m_nodeStack.empty() )
{ {
SPRINGBACK_TAG spTag = m_nodeStack.back(); SPRINGBACK_TAG spTag = m_nodeStack.back();
if( !spTag.m_node->CheckColliding( aHeadSet ) ) if( !spTag.m_node->CheckColliding( aHeadSet ) )
{ {
rv = true; if( aDraggedVia )
*aDraggedVia = spTag.m_draggedVia;
delete spTag.m_node; delete spTag.m_node;
m_nodeStack.pop_back(); m_nodeStack.pop_back();
@ -549,11 +552,15 @@ bool SHOVE::reduceSpringback( const ITEM_SET& aHeadSet )
break; break;
} }
return rv; return m_nodeStack.empty() ? m_root : m_nodeStack.back().m_node;
} }
bool SHOVE::pushSpringback( NODE* aNode, const OPT_BOX2I& aAffectedArea ) /*
* Push the current NODE on to the stack. aDraggedVia is the dragged via *before* the push
* (which will be restored in the event the stackframe is popped).
*/
bool SHOVE::pushSpringback( NODE* aNode, const OPT_BOX2I& aAffectedArea, VIA* aDraggedVia )
{ {
SPRINGBACK_TAG st; SPRINGBACK_TAG st;
OPT_BOX2I prev_area; OPT_BOX2I prev_area;
@ -561,6 +568,7 @@ bool SHOVE::pushSpringback( NODE* aNode, const OPT_BOX2I& aAffectedArea )
if( !m_nodeStack.empty() ) if( !m_nodeStack.empty() )
prev_area = m_nodeStack.back().m_affectedArea; prev_area = m_nodeStack.back().m_affectedArea;
st.m_draggedVia = aDraggedVia;
st.m_node = aNode; st.m_node = aNode;
if( aAffectedArea ) if( aAffectedArea )
@ -1026,6 +1034,13 @@ SHOVE::SHOVE_STATUS SHOVE::shoveMainLoop()
timeLimit.Restart(); timeLimit.Restart();
if( m_lineStack.empty() && m_draggedVia )
{
// If we're shoving a free via then push a proxy LINE (with the via on the end) onto
// the stack.
pushLine( LINE( *m_draggedVia ) );
}
while( !m_lineStack.empty() ) while( !m_lineStack.empty() )
{ {
st = shoveIteration( m_iter ); st = shoveIteration( m_iter );
@ -1081,9 +1096,7 @@ SHOVE::SHOVE_STATUS SHOVE::ShoveLines( const LINE& aCurrentHead )
ITEM_SET headSet; ITEM_SET headSet;
headSet.Add( aCurrentHead ); headSet.Add( aCurrentHead );
reduceSpringback( headSet ); NODE* parent = reduceSpringback( headSet, nullptr );
NODE* parent = m_nodeStack.empty() ? m_root : m_nodeStack.back().m_node;
m_currentNode = parent->Branch(); m_currentNode = parent->Branch();
m_currentNode->ClearRanks(); m_currentNode->ClearRanks();
@ -1136,7 +1149,7 @@ SHOVE::SHOVE_STATUS SHOVE::ShoveLines( const LINE& aCurrentHead )
if( st == SH_OK || st == SH_HEAD_MODIFIED ) if( st == SH_OK || st == SH_HEAD_MODIFIED )
{ {
pushSpringback( m_currentNode, m_affectedArea ); pushSpringback( m_currentNode, m_affectedArea, nullptr );
} }
else else
{ {
@ -1183,9 +1196,7 @@ SHOVE::SHOVE_STATUS SHOVE::ShoveMultiLines( const ITEM_SET& aHeadSet )
m_optimizerQueue.clear(); m_optimizerQueue.clear();
m_logger.Clear(); m_logger.Clear();
reduceSpringback( headSet ); NODE* parent = reduceSpringback( headSet, nullptr );
NODE* parent = m_nodeStack.empty() ? m_root : m_nodeStack.back().m_node;
m_currentNode = parent->Branch(); m_currentNode = parent->Branch();
m_currentNode->ClearRanks(); m_currentNode->ClearRanks();
@ -1231,7 +1242,7 @@ SHOVE::SHOVE_STATUS SHOVE::ShoveMultiLines( const ITEM_SET& aHeadSet )
if( st == SH_OK ) if( st == SH_OK )
{ {
pushSpringback( m_currentNode, m_affectedArea ); pushSpringback( m_currentNode, m_affectedArea, nullptr );
} }
else else
{ {
@ -1252,15 +1263,29 @@ SHOVE::SHOVE_STATUS SHOVE::ShoveDraggingVia( VIA* aVia, const VECTOR2I& aWhere,
m_newHead = OPT_LINE(); m_newHead = OPT_LINE();
m_draggedVia = NULL; m_draggedVia = NULL;
NODE* parent = m_nodeStack.empty() ? m_root : m_nodeStack.back().m_node; ITEM_SET headSet;
headSet.Add( *aVia );
// Pop NODEs containing previous shoves which are no longer necessary
//
NODE* parent = reduceSpringback( headSet, &aVia );
// Create a new NODE
//
m_currentNode = parent->Branch(); m_currentNode = parent->Branch();
m_currentNode->ClearRanks(); m_currentNode->ClearRanks();
aVia->Mark( MK_HEAD ); aVia->Mark( MK_HEAD );
aVia->SetRank( 100000 );
// Push the via to its new location
//
st = pushVia( aVia, ( aWhere - aVia->Pos() ), 0 ); st = pushVia( aVia, ( aWhere - aVia->Pos() ), 0 );
st = shoveMainLoop();
// Shove any colliding objects out of the way
//
if( st == SH_OK )
st = shoveMainLoop();
if( st == SH_OK ) if( st == SH_OK )
runOptimizer( m_currentNode ); runOptimizer( m_currentNode );
@ -1270,7 +1295,7 @@ SHOVE::SHOVE_STATUS SHOVE::ShoveDraggingVia( VIA* aVia, const VECTOR2I& aWhere,
wxLogTrace( "PNS","setNewV %p", m_draggedVia ); wxLogTrace( "PNS","setNewV %p", m_draggedVia );
*aNewVia = m_draggedVia; *aNewVia = m_draggedVia;
pushSpringback( m_currentNode, m_affectedArea ); pushSpringback( m_currentNode, m_affectedArea, aVia );
} }
else else
{ {

View File

@ -93,7 +93,7 @@ private:
struct SPRINGBACK_TAG struct SPRINGBACK_TAG
{ {
int64_t m_length; int64_t m_length;
int m_segments; VIA* m_draggedVia;
VECTOR2I m_p; VECTOR2I m_p;
NODE* m_node; NODE* m_node;
OPT_BOX2I m_affectedArea; OPT_BOX2I m_affectedArea;
@ -102,8 +102,8 @@ private:
SHOVE_STATUS processHullSet( LINE& aCurrent, LINE& aObstacle, SHOVE_STATUS processHullSet( LINE& aCurrent, LINE& aObstacle,
LINE& aShoved, const HULL_SET& hulls ); LINE& aShoved, const HULL_SET& hulls );
bool reduceSpringback( const ITEM_SET& aHeadItems ); NODE* reduceSpringback( const ITEM_SET& aHeadItems, VIA** aDraggedVia );
bool pushSpringback( NODE* aNode, const OPT_BOX2I& aAffectedArea ); bool pushSpringback( NODE* aNode, const OPT_BOX2I& aAffectedArea, VIA* aDraggedVia );
SHOVE_STATUS walkaroundLoneVia( LINE& aCurrent, LINE& aObstacle, LINE& aShoved ); SHOVE_STATUS walkaroundLoneVia( LINE& aCurrent, LINE& aObstacle, LINE& aShoved );
bool checkBumpDirection( const LINE& aCurrent, const LINE& aShoved ) const; bool checkBumpDirection( const LINE& aCurrent, const LINE& aShoved ) const;