Support arcs in Break Track.
Fixes https://gitlab.com/kicad/code/kicad/-/issues/16712
This commit is contained in:
parent
a46d409ec6
commit
ed00cb3304
|
@ -2,7 +2,7 @@
|
||||||
* KiRouter - a push-and-(sometimes-)shove PCB router
|
* KiRouter - a push-and-(sometimes-)shove PCB router
|
||||||
*
|
*
|
||||||
* Copyright (C) 2013-2017 CERN
|
* Copyright (C) 2013-2017 CERN
|
||||||
* Copyright (C) 2016-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
* Copyright (C) 2016-2024 KiCad Developers, see AUTHORS.txt for contributors.
|
||||||
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify it
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
|
@ -767,7 +767,7 @@ bool LINE_PLACER::rhWalkOnly( const VECTOR2I& aP, LINE& aNewHead, LINE& aNewTail
|
||||||
// (now a hull or a walk/shove line cannot collide with the 'owner' of the hull under any circumstances).
|
// (now a hull or a walk/shove line cannot collide with the 'owner' of the hull under any circumstances).
|
||||||
// This, however, introduced a subtle bug. For a row/column/any other 'regular' arrangement
|
// This, however, introduced a subtle bug. For a row/column/any other 'regular' arrangement
|
||||||
// of overlapping hulls (think of pads of a SOP/SOIC chip or a regular via grid), walking around may
|
// of overlapping hulls (think of pads of a SOP/SOIC chip or a regular via grid), walking around may
|
||||||
// produce a new 'head' that is not considered colliding (due to the clearance epsilon), but with
|
// produce a new 'head' that is not considered colliding (due to the clearance epsilon), but with
|
||||||
// its start point inside one of the subsequent hulls to process.
|
// its start point inside one of the subsequent hulls to process.
|
||||||
// We can't have head[0] inside any hull for the algorithm to work - therefore, we now consider the entire
|
// We can't have head[0] inside any hull for the algorithm to work - therefore, we now consider the entire
|
||||||
// 'tail+head' trace when walking around and in case of success, reconstruct the
|
// 'tail+head' trace when walking around and in case of success, reconstruct the
|
||||||
|
@ -932,7 +932,7 @@ bool LINE_PLACER::rhShoveOnly( const VECTOR2I& aP, LINE& aNewHead, LINE& aNewTai
|
||||||
{
|
{
|
||||||
newHead.AppendVia( makeVia( newHead.CPoint( -1 ) ) );
|
newHead.AppendVia( makeVia( newHead.CPoint( -1 ) ) );
|
||||||
PNS_DBG( Dbg(), AddPoint, newHead.Via().Pos(), GREEN, 1000000, "shove-new-via" );
|
PNS_DBG( Dbg(), AddPoint, newHead.Via().Pos(), GREEN, 1000000, "shove-new-via" );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SHOVE::SHOVE_STATUS status = m_shove->ShoveLines( newHead );
|
SHOVE::SHOVE_STATUS status = m_shove->ShoveLines( newHead );
|
||||||
|
@ -1292,6 +1292,38 @@ bool LINE_PLACER::SplitAdjacentSegments( NODE* aNode, ITEM* aSeg, const VECTOR2I
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool LINE_PLACER::SplitAdjacentArcs( NODE* aNode, ITEM* aArc, const VECTOR2I& aP )
|
||||||
|
{
|
||||||
|
if( !aArc )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if( !aArc->OfKind( ITEM::ARC_T ) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const JOINT* jt = aNode->FindJoint( aP, aArc );
|
||||||
|
|
||||||
|
if( jt && jt->LinkCount() >= 1 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ARC* a_old = static_cast<ARC*>( aArc );
|
||||||
|
const SHAPE_ARC& o_arc = a_old->Arc();
|
||||||
|
|
||||||
|
std::unique_ptr<ARC> a_new[2] = { Clone( *a_old ), Clone( *a_old ) };
|
||||||
|
|
||||||
|
a_new[0]->Arc().ConstructFromStartEndCenter( o_arc.GetP0(), aP, o_arc.GetCenter(),
|
||||||
|
o_arc.IsClockwise(), o_arc.GetWidth() );
|
||||||
|
|
||||||
|
a_new[1]->Arc().ConstructFromStartEndCenter( aP, o_arc.GetP1(), o_arc.GetCenter(),
|
||||||
|
o_arc.IsClockwise(), o_arc.GetWidth() );
|
||||||
|
|
||||||
|
aNode->Remove( a_old );
|
||||||
|
aNode->Add( std::move( a_new[0] ), true );
|
||||||
|
aNode->Add( std::move( a_new[1] ), true );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool LINE_PLACER::SetLayer( int aLayer )
|
bool LINE_PLACER::SetLayer( int aLayer )
|
||||||
{
|
{
|
||||||
if( m_idle )
|
if( m_idle )
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* KiRouter - a push-and-(sometimes-)shove PCB router
|
* KiRouter - a push-and-(sometimes-)shove PCB router
|
||||||
*
|
*
|
||||||
* Copyright (C) 2013-2017 CERN
|
* Copyright (C) 2013-2017 CERN
|
||||||
* Copyright (C) 2016-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
* Copyright (C) 2016-2024 KiCad Developers, see AUTHORS.txt for contributors.
|
||||||
*
|
*
|
||||||
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
||||||
*
|
*
|
||||||
|
@ -206,11 +206,17 @@ public:
|
||||||
void GetModifiedNets( std::vector<NET_HANDLE>& aNets ) const override;
|
void GetModifiedNets( std::vector<NET_HANDLE>& aNets ) const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if point \a aP lies on segment \a aSeg. If so, splits the segment in two, forming a
|
* Snaps the point \a aP to segment \a aSeg. Splits the segment in two, forming a
|
||||||
* joint at \a aP and stores updated topology in node \a aNode.
|
* joint at \a aP and stores updated topology in node \a aNode.
|
||||||
*/
|
*/
|
||||||
bool SplitAdjacentSegments( NODE* aNode, ITEM* aSeg, const VECTOR2I& aP );
|
bool SplitAdjacentSegments( NODE* aNode, ITEM* aSeg, const VECTOR2I& aP );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Snaps the point \a aP to arc \a aArc. Splits the arc in two, forming a
|
||||||
|
* joint at \a aP and stores updated topology in node \a aNode.
|
||||||
|
*/
|
||||||
|
bool SplitAdjacentArcs( NODE* aNode, ITEM* aArc, const VECTOR2I& aP );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* Re-route the current track to point aP. Returns true, when routing has completed
|
* Re-route the current track to point aP. Returns true, when routing has completed
|
||||||
|
|
|
@ -1039,13 +1039,20 @@ void ROUTER::SetInterface( ROUTER_IFACE *aIface )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ROUTER::BreakSegment( ITEM *aItem, const VECTOR2I& aP )
|
void ROUTER::BreakSegmentOrArc( ITEM *aItem, const VECTOR2I& aP )
|
||||||
{
|
{
|
||||||
NODE *node = m_world->Branch();
|
NODE *node = m_world->Branch();
|
||||||
|
|
||||||
LINE_PLACER placer( this );
|
LINE_PLACER placer( this );
|
||||||
|
|
||||||
if( placer.SplitAdjacentSegments( node, aItem, aP ) )
|
bool ret = false;
|
||||||
|
|
||||||
|
if( aItem->OfKind( ITEM::SEGMENT_T ) )
|
||||||
|
ret = placer.SplitAdjacentSegments( node, aItem, aP );
|
||||||
|
else if( aItem->OfKind( ITEM::ARC_T ) )
|
||||||
|
ret = placer.SplitAdjacentArcs( node, aItem, aP );
|
||||||
|
|
||||||
|
if( ret )
|
||||||
{
|
{
|
||||||
CommitRouting( node );
|
CommitRouting( node );
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,7 +150,7 @@ public:
|
||||||
bool Finish();
|
bool Finish();
|
||||||
bool ContinueFromEnd( ITEM** aNewStartItem );
|
bool ContinueFromEnd( ITEM** aNewStartItem );
|
||||||
bool FixRoute( const VECTOR2I& aP, ITEM* aItem, bool aForceFinish, bool aForceCommit );
|
bool FixRoute( const VECTOR2I& aP, ITEM* aItem, bool aForceFinish, bool aForceCommit );
|
||||||
void BreakSegment( ITEM *aItem, const VECTOR2I& aP );
|
void BreakSegmentOrArc( ITEM *aItem, const VECTOR2I& aP );
|
||||||
|
|
||||||
std::optional<VECTOR2I> UndoLastSegment();
|
std::optional<VECTOR2I> UndoLastSegment();
|
||||||
void CommitRouting();
|
void CommitRouting();
|
||||||
|
|
|
@ -1563,8 +1563,11 @@ bool ROUTER_TOOL::RoutingInProgress()
|
||||||
|
|
||||||
void ROUTER_TOOL::breakTrack()
|
void ROUTER_TOOL::breakTrack()
|
||||||
{
|
{
|
||||||
if( m_startItem && m_startItem->OfKind( PNS::ITEM::SEGMENT_T ) )
|
if( !m_startItem )
|
||||||
m_router->BreakSegment( m_startItem, m_startSnapPoint );
|
return;
|
||||||
|
|
||||||
|
if( m_startItem->OfKind( PNS::ITEM::SEGMENT_T | PNS::ITEM::ARC_T ) )
|
||||||
|
m_router->BreakSegmentOrArc( m_startItem, m_startSnapPoint );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2501,7 +2504,7 @@ int ROUTER_TOOL::InlineBreakTrack( const TOOL_EVENT& aEvent )
|
||||||
const BOARD_CONNECTED_ITEM* item =
|
const BOARD_CONNECTED_ITEM* item =
|
||||||
static_cast<const BOARD_CONNECTED_ITEM*>( selection.Front() );
|
static_cast<const BOARD_CONNECTED_ITEM*>( selection.Front() );
|
||||||
|
|
||||||
if( item->Type() != PCB_TRACE_T )
|
if( item->Type() != PCB_TRACE_T && item->Type() != PCB_ARC_T )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear );
|
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear );
|
||||||
|
@ -2516,6 +2519,8 @@ int ROUTER_TOOL::InlineBreakTrack( const TOOL_EVENT& aEvent )
|
||||||
m_gridHelper->SetUseGrid( gal->GetGridSnapping() && !aEvent.DisableGridSnapping() );
|
m_gridHelper->SetUseGrid( gal->GetGridSnapping() && !aEvent.DisableGridSnapping() );
|
||||||
m_gridHelper->SetSnap( !aEvent.Modifier( MD_SHIFT ) );
|
m_gridHelper->SetSnap( !aEvent.Modifier( MD_SHIFT ) );
|
||||||
|
|
||||||
|
controls()->ForceCursorPosition( false );
|
||||||
|
|
||||||
if( toolManager->IsContextMenuActive() )
|
if( toolManager->IsContextMenuActive() )
|
||||||
{
|
{
|
||||||
// If we're here from a context menu then we need to get the position of the
|
// If we're here from a context menu then we need to get the position of the
|
||||||
|
|
Loading…
Reference in New Issue