From 44905e1b0a47769b703eac8faf3606f398333d0d Mon Sep 17 00:00:00 2001 From: Tomasz Wlostowski Date: Fri, 28 Feb 2020 23:13:25 +0100 Subject: [PATCH] router: initial support for dragging components with traces attached --- pcbnew/router/CMakeLists.txt | 1 + pcbnew/router/pns_component_dragger.cpp | 166 ++++++++++++++++++++++++ pcbnew/router/pns_component_dragger.h | 109 ++++++++++++++++ pcbnew/router/pns_router.cpp | 38 ++++-- pcbnew/router/pns_router.h | 7 +- 5 files changed, 306 insertions(+), 15 deletions(-) create mode 100644 pcbnew/router/pns_component_dragger.cpp create mode 100644 pcbnew/router/pns_component_dragger.h diff --git a/pcbnew/router/CMakeLists.txt b/pcbnew/router/CMakeLists.txt index 37d4132503..7334b0035d 100644 --- a/pcbnew/router/CMakeLists.txt +++ b/pcbnew/router/CMakeLists.txt @@ -14,6 +14,7 @@ set( PCBNEW_PNS_SRCS pns_kicad_iface.cpp pns_algo_base.cpp pns_arc.cpp + pns_component_dragger.cpp pns_diff_pair.cpp pns_diff_pair_placer.cpp pns_dp_meander_placer.cpp diff --git a/pcbnew/router/pns_component_dragger.cpp b/pcbnew/router/pns_component_dragger.cpp new file mode 100644 index 0000000000..f70b25503b --- /dev/null +++ b/pcbnew/router/pns_component_dragger.cpp @@ -0,0 +1,166 @@ +/* + * KiRouter - a push-and-(sometimes-)shove PCB router + * + * Copyright (C) 2013-2020 CERN + * Author: Tomasz Wlostowski + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include + +#include "pns_line.h" +#include "pns_solid.h" +#include "pns_via.h" +#include "pns_router.h" + +#include "pns_component_dragger.h" +#include "pns_debug_decorator.h" + +namespace PNS +{ + +COMPONENT_DRAGGER::COMPONENT_DRAGGER( ROUTER* aRouter ) : DRAG_ALGO( aRouter ) +{ +} + + +COMPONENT_DRAGGER::~COMPONENT_DRAGGER() +{ +} + + +bool COMPONENT_DRAGGER::Start( const VECTOR2I& aP, ITEM_SET& aPrimitives ) +{ + m_currentNode = nullptr; + m_initialDraggedItems = aPrimitives; + m_p0 = aP; + + for( auto item : aPrimitives.Items() ) + { + if( item.item->Kind() != ITEM::SOLID_T ) + continue; + + auto solid = static_cast( item.item ); + auto jt = m_world->FindJoint( solid->Pos(), solid ); + + m_solids.insert( solid ); + + for( auto link : jt->LinkList() ) + { + if( link.item->OfKind( ITEM::SEGMENT_T | ITEM::ARC_T ) ) + { + LINKED_ITEM* li = static_cast( link.item ); + int segIndex; + + auto l0 = m_world->AssembleLine( li, &segIndex ); + +// printf( "solid %p jt %p fanout %d segs %d\n", solid, jt, jt->LinkCount(), +/// l0.SegmentCount() ); + + DRAGGED_CONNECTION cn; + + cn.origLine = l0; + cn.attachedPad = solid; + m_conns.push_back( cn ); + } + } + } + +// printf( "Total: %d conns to drag\n", m_conns.size() ); + + return true; +} + +bool COMPONENT_DRAGGER::Drag( const VECTOR2I& aP ) +{ + m_world->KillChildren(); + m_currentNode = m_world->Branch(); + + for( auto item : m_initialDraggedItems.Items() ) + m_currentNode->Remove( item ); + + m_draggedItems.Clear(); + + for( auto item : m_solids ) + { + SOLID* s = static_cast( item ); + auto p_next = aP - m_p0 + s->Pos(); + std::unique_ptr snew( static_cast( s->Clone() ) ); + snew->SetPos( p_next ); + + m_draggedItems.Add( snew.get() ); + m_currentNode->Add( std::move( snew ) ); + + for( auto& l : m_conns ) + { + if( l.attachedPad == s ) + { + l.p_orig = s->Pos(); + l.p_next = p_next; + } + } + } + + for( auto& cn : m_conns ) + { + auto l_new( cn.origLine ); + l_new.Unmark(); + l_new.ClearSegmentLinks(); + l_new.DragCorner( cn.p_next, cn.origLine.CLine().Find( cn.p_orig ) ); + + Dbg()->AddLine( l_new.CLine(), 4, 100000 ); + m_draggedItems.Add( l_new ); + + auto l_orig( cn.origLine ); + m_currentNode->Remove( l_orig ); + m_currentNode->Add( l_new ); + } + + return true; +} + +bool COMPONENT_DRAGGER::FixRoute() +{ + NODE* node = CurrentNode(); + + if( node ) + { + bool ok; + if( Settings().CanViolateDRC() ) + ok = true; + else + ok = !node->CheckColliding( m_draggedItems ); + + if( !ok ) + return false; + + Router()->CommitRouting( node ); + return true; + } + + return false; +} + +NODE* COMPONENT_DRAGGER::CurrentNode() const +{ + return m_currentNode ? m_currentNode : m_world; +} + +const ITEM_SET COMPONENT_DRAGGER::Traces() +{ + return m_draggedItems; +} + +}; // namespace PNS diff --git a/pcbnew/router/pns_component_dragger.h b/pcbnew/router/pns_component_dragger.h new file mode 100644 index 0000000000..5253e86ce9 --- /dev/null +++ b/pcbnew/router/pns_component_dragger.h @@ -0,0 +1,109 @@ +/* + * KiRouter - a push-and-(sometimes-)shove PCB router + * + * Copyright (C) 2013-2020 CERN + * Author: Tomasz Wlostowski + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef __PNS_COMPONENT_DRAGGER_H +#define __PNS_COMPONENT_DRAGGER_H + +#include + +#include "pns_drag_algo.h" +#include "pns_itemset.h" +#include "pns_line.h" +#include "pns_node.h" +#include "pns_via.h" + +namespace PNS +{ +class ROUTER; +class OPTIMIZER; + +/** + * COMPONENT_DRAGGER + * + * Implements component dragging algorithm. + */ +class COMPONENT_DRAGGER : public DRAG_ALGO +{ +public: + COMPONENT_DRAGGER( ROUTER* aRouter ); + ~COMPONENT_DRAGGER(); + + + /** + * Function Start() + * + * Starts routing a single track at point aP, taking item aStartItem as anchor + * (unless NULL). Returns true if a dragging operation has started. + */ + bool Start( const VECTOR2I& aP, ITEM_SET& aPrimitives ) override; + + /** + * Function Drag() + * + * Drags the current segment/corner/via to the point aP. + * @return true, if dragging finished with success. + */ + bool Drag( const VECTOR2I& aP ) override; + + /** + * Function FixRoute() + * + * Checks if the result of current dragging operation is correct + * and eventually commits it to the world. + * @return true, if dragging finished with success. + */ + bool FixRoute() override; + + /** + * Function CurrentNode() + * + * Returns the most recent world state, including all + * items changed due to dragging operation. + */ + NODE* CurrentNode() const override; + + /** + * Function Traces() + * + * Returns the set of dragged items. + */ + const ITEM_SET Traces() override; + +private: + struct DRAGGED_CONNECTION + { + LINE origLine; + SOLID* attachedPad; + VECTOR2I p_orig, p_next; + }; + + std::set m_solids; + std::vector m_conns; + + bool m_dragStatus; + ITEM_SET m_draggedItems; + ITEM_SET m_initialDraggedItems; + NODE* m_currentNode; + VECTOR2I m_p0; +}; + +}; // namespace PNS + +#endif diff --git a/pcbnew/router/pns_router.cpp b/pcbnew/router/pns_router.cpp index 18b4b68902..c1b8fa45c5 100644 --- a/pcbnew/router/pns_router.cpp +++ b/pcbnew/router/pns_router.cpp @@ -49,6 +49,7 @@ #include "pns_router.h" #include "pns_shove.h" #include "pns_dragger.h" +#include "pns_component_dragger.h" #include "pns_topology.h" #include "pns_diff_pair_placer.h" #include "pns_meander_placer.h" @@ -127,27 +128,37 @@ const ITEM_SET ROUTER::QueryHoverItems( const VECTOR2I& aP ) return m_placer->CurrentNode()->HitTest( aP ); } - -bool ROUTER::StartDragging( const VECTOR2I& aP, ITEM* aStartItem, int aDragMode ) +bool ROUTER::StartDragging( const VECTOR2I& aP, ITEM* aItem, int aDragMode ) { + return StartDragging( aP, ITEM_SET( aItem ), aDragMode ); +} - if( aDragMode & DM_FREE_ANGLE ) - m_forceMarkObstaclesMode = true; - else - m_forceMarkObstaclesMode = false; - if( !aStartItem || aStartItem->OfKind( ITEM::SOLID_T ) ) +bool ROUTER::StartDragging( const VECTOR2I& aP, ITEM_SET aStartItems, int aDragMode ) +{ + if( aStartItems.Empty() ) return false; - m_placer = std::make_unique( this ); - m_placer->Start( aP, aStartItem ); + if( aStartItems.Count( ITEM::SOLID_T ) == aStartItems.Size() ) + { + m_dragger = std::make_unique( this ); + m_forceMarkObstaclesMode = true; + } + else + { + if( aDragMode & DM_FREE_ANGLE ) + m_forceMarkObstaclesMode = true; + else + m_forceMarkObstaclesMode = false; + + m_dragger = std::make_unique( this ); + } - m_dragger = std::make_unique( this ); m_dragger->SetMode( aDragMode ); m_dragger->SetWorld( m_world.get() ); m_dragger->SetDebugDecorator ( m_iface->GetDebugDecorator () ); - if( m_dragger->Start ( aP, aStartItem ) ) + if( m_dragger->Start ( aP, aStartItems ) ) m_state = DRAG_SEGMENT; else { @@ -310,7 +321,6 @@ void ROUTER::updateView( NODE* aNode, ITEM_SET& aCurrent, bool aDragging ) for( auto item : added ) { int clearance = GetRuleResolver()->Clearance( item->Net() ); - m_iface->DisplayItem( item, -1, clearance, aDragging ); } @@ -411,7 +421,9 @@ void ROUTER::UndoLastSegment() void ROUTER::CommitRouting() { - m_placer->CommitPlacement(); + if( m_state == ROUTE_TRACK ) + m_placer->CommitPlacement(); + StopRouting(); } diff --git a/pcbnew/router/pns_router.h b/pcbnew/router/pns_router.h index d4916ca078..7996e9f2c4 100644 --- a/pcbnew/router/pns_router.h +++ b/pcbnew/router/pns_router.h @@ -62,6 +62,7 @@ class VIA; class RULE_RESOLVER; class SHOVE; class DRAGGER; +class DRAG_ALGO; enum ROUTER_MODE { PNS_MODE_ROUTE_SINGLE = 1, @@ -78,7 +79,8 @@ enum DRAG_MODE DM_VIA = 0x4, DM_FREE_ANGLE = 0x8, DM_ARC = 0x10, - DM_ANY = 0x17 + DM_ANY = 0x17, + DM_COMPONENT = 0x20 }; /** * ROUTER @@ -180,6 +182,7 @@ public: const VECTOR2I SnapToItem( ITEM* aItem, VECTOR2I aP, bool& aSplitsSegment ); bool StartDragging( const VECTOR2I& aP, ITEM* aItem, int aDragMode = DM_ANY ); + bool StartDragging( const VECTOR2I& aP, ITEM_SET aItems, int aDragMode = DM_COMPONENT ); void SetIterLimit( int aX ) { m_iterLimit = aX; } int GetIterLimit() const { return m_iterLimit; }; @@ -263,7 +266,7 @@ private: NODE* m_lastNode; std::unique_ptr< PLACEMENT_ALGO > m_placer; - std::unique_ptr< DRAGGER > m_dragger; + std::unique_ptr< DRAG_ALGO > m_dragger; std::unique_ptr< SHOVE > m_shove; ROUTER_IFACE* m_iface;