46 m_itemsList( nullptr ),
47 m_reporter( nullptr ),
60 std::vector<std::shared_ptr<CLEANUP_ITEM> >* aItemsList,
61 bool aRemoveMisConnected,
bool aCleanVias,
bool aMergeSegments,
62 bool aDeleteUnconnected,
bool aDeleteTracksinPad,
63 bool aDeleteDanglingVias,
REPORTER* aReporter )
66 bool has_deleted =
false;
81 bool removeNullSegments = aMergeSegments || aRemoveMisConnected;
82 cleanup( aCleanVias, removeNullSegments, aMergeSegments , aMergeSegments );
96 cleanup(
false,
false,
true,
false );
98 if( aRemoveMisConnected )
113 if( aDeleteTracksinPad )
128 if( aDeleteUnconnected || aDeleteDanglingVias )
138 if( aDeleteUnconnected )
141 if( aDeleteDanglingVias )
151 if( has_deleted && aMergeSegments )
163 cleanup(
false,
false,
false,
true );
181 std::set<BOARD_ITEM *> toRemove;
185 if( segment->IsLocked() ||
filterItem( segment ) )
188 for(
PAD* testedPad : connectivity->GetConnectedPads( segment ) )
190 if( segment->GetNetCode() != testedPad->GetNetCode() )
192 std::shared_ptr<CLEANUP_ITEM> item;
199 item->SetItems( segment );
202 toRemove.insert( segment );
206 for(
PCB_TRACK* testedTrack : connectivity->GetConnectedTracks( segment ) )
208 if( segment->GetNetCode() != testedTrack->GetNetCode() )
210 std::shared_ptr<CLEANUP_ITEM> item;
217 item->SetItems( segment );
220 toRemove.insert( segment );
234 const std::list<CN_ITEM*>& items =
240 CN_ITEM* citem = items.front();
242 if( !citem->
Valid() )
245 const std::vector<std::shared_ptr<CN_ANCHOR>>& anchors = citem->
Anchors();
249 for(
const std::shared_ptr<CN_ANCHOR>&
anchor : anchors )
251 if(
anchor->Pos() != refpoint )
256 return anchor->ConnectedItemsCount() > 1;
265 bool item_erased =
false;
266 bool modified =
false;
268 if( !aTrack && !aVia )
278 std::deque<PCB_TRACK*> temp_tracks(
m_brd->
Tracks() );
285 if( !aVia && track->Type() ==
PCB_VIA_T )
294 std::shared_ptr<CLEANUP_ITEM> item;
301 item->SetItems( track );
317 }
while( item_erased );
325 std::set<BOARD_ITEM*> toRemove;
332 if( track->IsLocked() ||
filterItem( track ) )
339 for(
PAD*
pad : connectivity->GetConnectedPads( track ) )
341 if(
pad->HitTest( track->GetStart() ) &&
pad->HitTest( track->GetEnd() ) )
344 track->TransformShapeToPolygon( poly, track->GetLayer(), 0,
ARC_HIGH_DEF,
353 item->SetItems( track );
356 toRemove.insert( track );
372 bool aDeleteDuplicateSegments,
bool aMergeSegments )
379 rtree.
Insert( track, track->GetLayer() );
382 std::set<BOARD_ITEM*> toRemove;
389 if( aDeleteDuplicateVias && track->Type() ==
PCB_VIA_T )
393 if(
via->GetStart() !=
via->GetEnd() )
394 via->SetEnd(
via->GetStart() );
414 item->SetItems(
via );
418 toRemove.insert(
via );
430 if( (
pad->GetLayerSet() & all_cu ) == all_cu )
433 item->SetItems(
via,
pad );
437 toRemove.insert(
via );
445 if( aDeleteNullSegments && track->Type() !=
PCB_VIA_T )
447 if( track->IsNull() )
450 item->SetItems( track );
454 toRemove.insert( track );
458 if( aDeleteDuplicateSegments && track->Type() ==
PCB_TRACE_T && !track->IsNull() )
460 rtree.
QueryColliding( track, track->GetLayer(), track->GetLayer(),
464 return aItem->Type() == PCB_TRACE_T
465 && !aItem->HasFlag( SKIP_STRUCT )
466 && !aItem->HasFlag( IS_DELETED )
467 && !static_cast<PCB_TRACK*>( aItem )->IsNull();
472 PCB_TRACK* other = static_cast<PCB_TRACK*>( aItem );
474 if( track->IsPointOnEnds( other->GetStart() )
475 && track->IsPointOnEnds( other->GetEnd() )
476 && track->GetWidth() == other->GetWidth()
477 && track->GetLayer() == other->GetLayer() )
479 auto item = std::make_shared<CLEANUP_ITEM>( CLEANUP_DUPLICATE_TRACK );
480 item->SetItems( track );
481 m_itemsList->push_back( item );
483 track->SetFlags( IS_DELETED );
484 toRemove.insert( track );
495 removeItems( toRemove );
500 auto mergeSegments = [&]( std::shared_ptr<CN_CONNECTIVITY_ALGO> connectivity ) ->
bool
502 auto track_loop = [&](
int aStart,
int aEnd ) -> std::vector<std::pair<PCB_TRACK*, PCB_TRACK*>>
504 std::vector<std::pair<PCB_TRACK*, PCB_TRACK*>> tracks;
506 for(
int ii = aStart; ii < aEnd; ++ii )
508 PCB_TRACK* segment = m_brd->Tracks()[ii];
517 if( filterItem( segment ) )
521 for(
CN_ITEM* citem : connectivity->ItemEntry( segment ).GetItems() )
525 std::vector<PCB_TRACK*> sameWidthCandidates;
526 std::vector<PCB_TRACK*> differentWidthCandidates;
530 if( !connected->Valid() )
536 && !filterItem( candidate ) )
542 sameWidthCandidates.push_back( candidateSegment );
546 differentWidthCandidates.push_back( candidateSegment );
552 if( !differentWidthCandidates.empty() )
555 for(
PCB_TRACK* candidate : sameWidthCandidates )
557 if( candidate < segment )
561 && testMergeCollinearSegments( segment, candidate ) )
563 tracks.emplace_back( segment, candidate );
574 auto merge_returns =
tp.parallelize_loop( 0, m_brd->Tracks().size(), track_loop );
576 for(
size_t ii = 0; ii < merge_returns.size(); ++ii )
578 std::future<std::vector<std::pair<PCB_TRACK*, PCB_TRACK*>>>& ret = merge_returns[ii];
582 for(
auto& [seg1, seg2] : ret.get() )
587 mergeCollinearSegments( seg1, seg2 );
599 while( !m_brd->BuildConnectivity() )
602 m_connectedItemsCache.clear();
603 }
while( mergeSegments( m_brd->GetConnectivity()->GetConnectivityAlgo() ) );
606 for(
PCB_TRACK* track : m_brd->Tracks() )
634 const unsigned p1s = 1 << 0;
635 const unsigned p1e = 1 << 1;
636 const unsigned p2s = 1 << 2;
637 const unsigned p2e = 1 << 3;
639 std::atomic<unsigned> flags = 0;
644 if( std::popcount( flags.load() ) > 2 )
666 if( !( flags & p1s ) && citem->HitTest( aSeg1->
GetStart(), ( aSeg1->
GetWidth() + 1 ) / 2 ) )
669 if( !( flags & p1e ) && citem->HitTest( aSeg1->
GetEnd(), ( aSeg1->
GetWidth() + 1 ) / 2 ) )
672 if( !( flags & p2s ) && citem->HitTest( aSeg2->
GetStart(), ( aSeg2->
GetWidth() + 1 ) / 2 ) )
675 if( !( flags & p2e ) && citem->HitTest( aSeg2->
GetEnd(), ( aSeg2->
GetWidth() + 1 ) / 2 ) )
682 if( item != aSeg1 && item != aSeg2 )
688 if( item != aSeg1 && item != aSeg2 )
693 if( std::popcount( flags.load() ) > 2 )
702 aDummySeg = &dummy_seg;
708 int min_x = std::min( aSeg1->
GetStart().
x,
710 int min_y = std::min( aSeg1->
GetStart().
y,
712 int max_x = std::max( aSeg1->
GetStart().
x,
714 int max_y = std::max( aSeg1->
GetStart().
y,
731 for(
unsigned i = 0; i < 4; ++i )
733 if( ( flags & ( 1 << i ) ) && !aDummySeg->
IsPointOnEnds( pts[i] ) )
763 item->SetItems( aSeg1, aSeg2 );
constexpr int ARC_HIGH_DEF
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
void SetParentGroup(PCB_GROUP *aGroup)
PCB_GROUP * GetParentGroup() const
virtual bool IsLocked() const
Information pertinent to a Pcbnew printed circuit board.
bool BuildConnectivity(PROGRESS_REPORTER *aReporter=nullptr)
Build or rebuild the board connectivity database for the board, especially the list of connected item...
const TRACKS & Tracks() const
void Remove(BOARD_ITEM *aBoardItem, REMOVE_MODE aMode=REMOVE_MODE::NORMAL) override
Removes an item from the container.
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
CN_ITEM represents a BOARD_CONNETED_ITEM in the connectivity system (ie: a pad, track/arc/via,...
const std::vector< CN_ITEM * > & ConnectedItems() const
std::vector< std::shared_ptr< CN_ANCHOR > > & Anchors()
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Create an undo entry for an item that has been already modified.
COMMIT & Removed(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Modify a given item in the model.
Implement an R-tree for fast spatial and layer indexing of connectable items.
void Insert(BOARD_ITEM *aItem, PCB_LAYER_ID aLayer, int aWorstClearance=0)
Insert an item into the tree on a particular layer with an optional worst clearance.
int QueryColliding(BOARD_ITEM *aRefItem, PCB_LAYER_ID aRefLayer, PCB_LAYER_ID aTargetLayer, std::function< bool(BOARD_ITEM *)> aFilter=nullptr, std::function< bool(BOARD_ITEM *)> aVisitor=nullptr, int aClearance=0) const
This is a fast test which essentially does bounding-box overlap given a worst-case clearance.
void SetFlags(EDA_ITEM_FLAGS aMask)
KICAD_T Type() const
Returns the type of object.
bool HasFlag(EDA_ITEM_FLAGS aFlag) const
LSET is a set of PCB_LAYER_IDs.
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
A set of BOARD_ITEMs (i.e., without duplicates).
void SetEnd(const VECTOR2I &aEnd)
void SetStart(const VECTOR2I &aStart)
bool ApproxCollinear(const PCB_TRACK &aTrack)
const VECTOR2I & GetStart() const
const VECTOR2I & GetEnd() const
EDA_ITEM_FLAGS IsPointOnEnds(const VECTOR2I &point, int min_dist=0) const
Return STARTPOINT if point if near (dist = min_dist) start point, ENDPOINT if point if near (dist = m...
virtual int GetWidth() const
VECTOR2I GetPosition() const override
VIATYPE GetViaType() const
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
A pure virtual class used to derive REPORTER objects from.
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)=0
Report a string with a given severity.
Represent a set of closed polygons.
void BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset difference For aFastMode meaning, see function booleanOp.
bool IsEmpty() const
Return true if the set is empty (no polygons at all)
const std::vector< BOARD_CONNECTED_ITEM * > & getConnectedItems(PCB_TRACK *aTrack)
bool testMergeCollinearSegments(PCB_TRACK *aSeg1, PCB_TRACK *aSeg2, PCB_TRACK *aDummySeg=nullptr)
helper function test if 2 segments are colinear.
bool filterItem(BOARD_CONNECTED_ITEM *aItem)
void deleteTracksInPads()
void removeItems(std::set< BOARD_ITEM * > &aItems)
void cleanup(bool aDeleteDuplicateVias, bool aDeleteNullSegments, bool aDeleteDuplicateSegments, bool aMergeSegments)
Geometry-based cleanup: duplicate items, null items, colinear items.
void CleanupBoard(bool aDryRun, std::vector< std::shared_ptr< CLEANUP_ITEM > > *aItemsList, bool aCleanVias, bool aRemoveMisConnected, bool aMergeSegments, bool aDeleteUnconnected, bool aDeleteTracksinPad, bool aDeleteDanglingVias, REPORTER *aReporter=nullptr)
the cleanup function.
bool testTrackEndpointIsNode(PCB_TRACK *aTrack, bool aTstStart)
bool mergeCollinearSegments(PCB_TRACK *aSeg1, PCB_TRACK *aSeg2)
helper function merge aTrackRef and aCandidate, when possible, i.e.
bool deleteDanglingTracks(bool aTrack, bool aVia)
Removes tracks or vias only connected on one end.
std::map< PCB_TRACK *, std::vector< BOARD_CONNECTED_ITEM * > > m_connectedItemsCache
std::function< bool(BOARD_CONNECTED_ITEM *aItem)> m_filter
std::vector< std::shared_ptr< CLEANUP_ITEM > > * m_itemsList
TRACKS_CLEANER(BOARD *aPcb, BOARD_COMMIT &aCommit)
void removeShortingTrackSegments()
@ CLEANUP_ZERO_LENGTH_TRACK
#define SKIP_STRUCT
flag indicating that the structure should be ignored
BS::thread_pool thread_pool
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
@ PCB_ZONE_T
class ZONE, a copper pour area
@ PCB_PAD_T
class PAD, a pad in a footprint
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
VECTOR2< int32_t > VECTOR2I