KiCad PCB EDA Suite
Loading...
Searching...
No Matches
tracks_cleaner.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2004-2018 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 2011 Wayne Stambaugh <[email protected]>
6 * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26#include <reporter.h>
27#include <board_commit.h>
28#include <cleanup_item.h>
31#include <lset.h>
32#include <tool/tool_manager.h>
33#include <tools/pcb_actions.h>
35#include <drc/drc_rtree.h>
36#include <tracks_cleaner.h>
37
39 m_brd( aPcb ),
40 m_commit( aCommit ),
41 m_dryRun( true ),
42 m_itemsList( nullptr ),
43 m_reporter( nullptr )
44{
45}
46
47
48/* Main cleaning function.
49 * Delete
50 * - Redundant points on tracks (merge aligned segments)
51 * - vias on pad
52 * - null length segments
53 */
55 std::vector<std::shared_ptr<CLEANUP_ITEM> >* aItemsList,
56 bool aRemoveMisConnected, bool aCleanVias, bool aMergeSegments,
57 bool aDeleteUnconnected, bool aDeleteTracksinPad,
58 bool aDeleteDanglingVias, REPORTER* aReporter )
59{
60 m_reporter = aReporter;
61 bool has_deleted = false;
62
63 m_dryRun = aDryRun;
64 m_itemsList = aItemsList;
65
66 if( m_reporter )
67 {
68 if( aDryRun )
69 m_reporter->Report( _( "Checking null tracks and vias..." ) );
70 else
71 m_reporter->Report( _( "Removing null tracks and vias..." ) );
72
73 wxSafeYield(); // Timeslice to update UI
74 }
75
76 bool removeNullSegments = aMergeSegments || aRemoveMisConnected;
77 cleanup( aCleanVias, removeNullSegments, aMergeSegments /* dup segments*/, aMergeSegments );
78
79 if( m_reporter )
80 {
81 if( aDryRun )
82 m_reporter->Report( _( "Checking redundant tracks..." ) );
83 else
84 m_reporter->Report( _( "Removing redundant tracks..." ) );
85
86 wxSafeYield(); // Timeslice to update UI
87 }
88
89 // If we didn't remove duplicates above, do it now
90 if( !aMergeSegments )
91 cleanup( false, false, true, false );
92
93 if( aRemoveMisConnected )
94 {
95 if( m_reporter )
96 {
97 if( aDryRun )
98 m_reporter->Report( _( "Checking shorting tracks..." ) );
99 else
100 m_reporter->Report( _( "Removing shorting tracks..." ) );
101
102 wxSafeYield(); // Timeslice to update UI
103 }
104
106 }
107
108 if( aDeleteTracksinPad )
109 {
110 if( m_reporter )
111 {
112 if( aDryRun )
113 m_reporter->Report( _( "Checking tracks in pads..." ) );
114 else
115 m_reporter->Report( _( "Removing tracks in pads..." ) );
116
117 wxSafeYield(); // Timeslice to update UI
118 }
119
121 }
122
123 if( aDeleteUnconnected || aDeleteDanglingVias )
124 {
125 if( m_reporter )
126 {
127 if( aDryRun )
128 {
129 m_reporter->Report( _( "Checking dangling tracks and vias..." ) );
130 }
131 else
132 {
133 if( aDeleteUnconnected )
134 m_reporter->Report( _( "Removing dangling tracks..." ) );
135
136 if( aDeleteDanglingVias )
137 m_reporter->Report( _( "Removing dangling vias..." ) );
138 }
139
140 wxSafeYield(); // Timeslice to update UI
141 }
142
143 has_deleted = deleteDanglingTracks( aDeleteUnconnected, aDeleteDanglingVias );
144 }
145
146 if( has_deleted && aMergeSegments )
147 {
148 if( m_reporter )
149 {
150 if( aDryRun )
151 m_reporter->Report( _( "Checking collinear tracks..." ) );
152 else
153 m_reporter->Report( _( "Merging collinear tracks..." ) );
154
155 wxSafeYield(); // Timeslice to update UI
156 }
157
158 cleanup( false, false, false, true );
159 }
160}
161
162
164{
165 std::shared_ptr<CONNECTIVITY_DATA> connectivity = m_brd->GetConnectivity();
166
167 std::set<BOARD_ITEM *> toRemove;
168
169 for( PCB_TRACK* segment : m_brd->Tracks() )
170 {
171 // Assume that the user knows what they are doing
172 if( segment->IsLocked() )
173 continue;
174
175 for( PAD* testedPad : connectivity->GetConnectedPads( segment ) )
176 {
177 if( segment->GetNetCode() != testedPad->GetNetCode() )
178 {
179 std::shared_ptr<CLEANUP_ITEM> item;
180
181 if( segment->Type() == PCB_VIA_T )
182 item = std::make_shared<CLEANUP_ITEM>( CLEANUP_SHORTING_VIA );
183 else
184 item = std::make_shared<CLEANUP_ITEM>( CLEANUP_SHORTING_TRACK );
185
186 item->SetItems( segment );
187 m_itemsList->push_back( item );
188
189 toRemove.insert( segment );
190 }
191 }
192
193 for( PCB_TRACK* testedTrack : connectivity->GetConnectedTracks( segment ) )
194 {
195 if( segment->GetNetCode() != testedTrack->GetNetCode() )
196 {
197 std::shared_ptr<CLEANUP_ITEM> item;
198
199 if( segment->Type() == PCB_VIA_T )
200 item = std::make_shared<CLEANUP_ITEM>( CLEANUP_SHORTING_VIA );
201 else
202 item = std::make_shared<CLEANUP_ITEM>( CLEANUP_SHORTING_TRACK );
203
204 item->SetItems( segment );
205 m_itemsList->push_back( item );
206
207 toRemove.insert( segment );
208 }
209 }
210 }
211
212 if( !m_dryRun )
213 removeItems( toRemove );
214}
215
216
218{
219 // A node is a point where more than 2 items are connected.
220
221 const std::list<CN_ITEM*>& items =
222 m_brd->GetConnectivity()->GetConnectivityAlgo()->ItemEntry( aTrack ).GetItems();
223
224 if( items.empty() )
225 return false;
226
227 CN_ITEM* citem = items.front();
228
229 if( !citem->Valid() )
230 return false;
231
232 const std::vector<std::shared_ptr<CN_ANCHOR>>& anchors = citem->Anchors();
233
234 VECTOR2I refpoint = aTstStart ? aTrack->GetStart() : aTrack->GetEnd();
235
236 for( const std::shared_ptr<CN_ANCHOR>& anchor : anchors )
237 {
238 if( anchor->Pos() != refpoint )
239 continue;
240
241 // The right anchor point is found: if more than one other item
242 // (pad, via, track...) is connected, it is a node:
243 return anchor->ConnectedItemsCount() > 1;
244 }
245
246 return false;
247}
248
249
250bool TRACKS_CLEANER::deleteDanglingTracks( bool aTrack, bool aVia )
251{
252 bool item_erased = false;
253 bool modified = false;
254
255 if( !aTrack && !aVia )
256 return false;
257
258 do // Iterate when at least one track is deleted
259 {
260 item_erased = false;
261 // Ensure the connectivity is up to date, especially after removing a dangling segment
263
264 // Keep a duplicate deque to all deleting in the primary
265 std::deque<PCB_TRACK*> temp_tracks( m_brd->Tracks() );
266
267 for( PCB_TRACK* track : temp_tracks )
268 {
269 if( track->IsLocked() || ( track->GetFlags() & IS_DELETED ) > 0 )
270 continue;
271
272 if( !aVia && track->Type() == PCB_VIA_T )
273 continue;
274
275 if( !aTrack && ( track->Type() == PCB_TRACE_T || track->Type() == PCB_ARC_T ) )
276 continue;
277
278 // Test if a track (or a via) endpoint is not connected to another track or zone.
279 if( m_brd->GetConnectivity()->TestTrackEndpointDangling( track, false ) )
280 {
281 std::shared_ptr<CLEANUP_ITEM> item;
282
283 if( track->Type() == PCB_VIA_T )
284 item = std::make_shared<CLEANUP_ITEM>( CLEANUP_DANGLING_VIA );
285 else
286 item = std::make_shared<CLEANUP_ITEM>( CLEANUP_DANGLING_TRACK );
287
288 item->SetItems( track );
289 m_itemsList->push_back( item );
290 track->SetFlags( IS_DELETED );
291
292 // keep iterating, because a track connected to the deleted track
293 // now perhaps is not connected and should be deleted
294 item_erased = true;
295
296 if( !m_dryRun )
297 {
298 m_brd->Remove( track );
299 m_commit.Removed( track );
300 modified = true;
301 }
302 }
303 }
304 } while( item_erased ); // A segment was erased: test for some new dangling segments
305
306 return modified;
307}
308
309
311{
312 std::set<BOARD_ITEM*> toRemove;
313
314 // Delete tracks that start and end on the same pad
315 std::shared_ptr<CONNECTIVITY_DATA> connectivity = m_brd->GetConnectivity();
316
317 for( PCB_TRACK* track : m_brd->Tracks() )
318 {
319 if( track->IsLocked() )
320 continue;
321
322 if( track->Type() == PCB_VIA_T )
323 continue;
324
325 // Mark track if connected to pads
326 for( PAD* pad : connectivity->GetConnectedPads( track ) )
327 {
328 if( pad->HitTest( track->GetStart() ) && pad->HitTest( track->GetEnd() ) )
329 {
330 SHAPE_POLY_SET poly;
331 track->TransformShapeToPolygon( poly, track->GetLayer(), 0, ARC_HIGH_DEF,
332 ERROR_INSIDE );
333
334 poly.BooleanSubtract( *pad->GetEffectivePolygon( ERROR_INSIDE ),
336
337 if( poly.IsEmpty() )
338 {
339 auto item = std::make_shared<CLEANUP_ITEM>( CLEANUP_TRACK_IN_PAD );
340 item->SetItems( track );
341 m_itemsList->push_back( item );
342
343 toRemove.insert( track );
344 track->SetFlags( IS_DELETED );
345 }
346 }
347 }
348 }
349
350 if( !m_dryRun )
351 removeItems( toRemove );
352}
353
354
358void TRACKS_CLEANER::cleanup( bool aDeleteDuplicateVias, bool aDeleteNullSegments,
359 bool aDeleteDuplicateSegments, bool aMergeSegments )
360{
361 DRC_RTREE rtree;
362
363 for( PCB_TRACK* track : m_brd->Tracks() )
364 {
365 track->ClearFlags( IS_DELETED | SKIP_STRUCT );
366 rtree.Insert( track, track->GetLayer() );
367 }
368
369 std::set<BOARD_ITEM*> toRemove;
370
371 for( PCB_TRACK* track : m_brd->Tracks() )
372 {
373 if( track->HasFlag( IS_DELETED ) || track->IsLocked() )
374 continue;
375
376 if( aDeleteDuplicateVias && track->Type() == PCB_VIA_T )
377 {
378 PCB_VIA* via = static_cast<PCB_VIA*>( track );
379
380 if( via->GetStart() != via->GetEnd() )
381 via->SetEnd( via->GetStart() );
382
383 rtree.QueryColliding( via, via->GetLayer(), via->GetLayer(),
384 // Filter:
385 [&]( BOARD_ITEM* aItem ) -> bool
386 {
387 return aItem->Type() == PCB_VIA_T
388 && !aItem->HasFlag( SKIP_STRUCT )
389 && !aItem->HasFlag( IS_DELETED );
390 },
391 // Visitor:
392 [&]( BOARD_ITEM* aItem ) -> bool
393 {
394 PCB_VIA* other = static_cast<PCB_VIA*>( aItem );
395
396 if( via->GetPosition() == other->GetPosition()
397 && via->GetViaType() == other->GetViaType()
398 && via->GetLayerSet() == other->GetLayerSet() )
399 {
400 auto item = std::make_shared<CLEANUP_ITEM>( CLEANUP_REDUNDANT_VIA );
401 item->SetItems( via );
402 m_itemsList->push_back( item );
403
404 via->SetFlags( IS_DELETED );
405 toRemove.insert( via );
406 }
407
408 return true;
409 } );
410
411 // To delete through Via on THT pads at same location
412 // Examine the list of connected pads: if a through pad is found, the via is redundant
413 for( PAD* pad : m_brd->GetConnectivity()->GetConnectedPads( via ) )
414 {
415 const LSET all_cu = LSET::AllCuMask();
416
417 if( ( pad->GetLayerSet() & all_cu ) == all_cu )
418 {
419 auto item = std::make_shared<CLEANUP_ITEM>( CLEANUP_REDUNDANT_VIA );
420 item->SetItems( via, pad );
421 m_itemsList->push_back( item );
422
423 via->SetFlags( IS_DELETED );
424 toRemove.insert( via );
425 break;
426 }
427 }
428
429 via->SetFlags( SKIP_STRUCT );
430 }
431
432 if( aDeleteNullSegments && track->Type() != PCB_VIA_T )
433 {
434 if( track->IsNull() )
435 {
436 auto item = std::make_shared<CLEANUP_ITEM>( CLEANUP_ZERO_LENGTH_TRACK );
437 item->SetItems( track );
438 m_itemsList->push_back( item );
439
440 track->SetFlags( IS_DELETED );
441 toRemove.insert( track );
442 }
443 }
444
445 if( aDeleteDuplicateSegments && track->Type() == PCB_TRACE_T && !track->IsNull() )
446 {
447 rtree.QueryColliding( track, track->GetLayer(), track->GetLayer(),
448 // Filter:
449 [&]( BOARD_ITEM* aItem ) -> bool
450 {
451 return aItem->Type() == PCB_TRACE_T
452 && !aItem->HasFlag( SKIP_STRUCT )
453 && !aItem->HasFlag( IS_DELETED )
454 && !static_cast<PCB_TRACK*>( aItem )->IsNull();
455 },
456 // Visitor:
457 [&]( BOARD_ITEM* aItem ) -> bool
458 {
459 PCB_TRACK* other = static_cast<PCB_TRACK*>( aItem );
460
461 if( track->IsPointOnEnds( other->GetStart() )
462 && track->IsPointOnEnds( other->GetEnd() )
463 && track->GetWidth() == other->GetWidth()
464 && track->GetLayer() == other->GetLayer() )
465 {
466 auto item = std::make_shared<CLEANUP_ITEM>( CLEANUP_DUPLICATE_TRACK );
467 item->SetItems( track );
468 m_itemsList->push_back( item );
469
470 track->SetFlags( IS_DELETED );
471 toRemove.insert( track );
472 }
473
474 return true;
475 } );
476
477 track->SetFlags( SKIP_STRUCT );
478 }
479 }
480
481 if( !m_dryRun )
482 removeItems( toRemove );
483
484 auto mergeSegments =
485 [&]( std::shared_ptr<CN_CONNECTIVITY_ALGO> connectivity ) -> bool
486 {
487
488 for( PCB_TRACK* segment : m_brd->Tracks() )
489 {
490 // one can merge only collinear segments, not vias or arcs.
491 if( segment->Type() != PCB_TRACE_T )
492 continue;
493
494 if( segment->HasFlag( IS_DELETED ) ) // already taken into account
495 continue;
496
497 // for each end of the segment:
498 for( CN_ITEM* citem : connectivity->ItemEntry( segment ).GetItems() )
499 {
500 // Do not merge an end which has different width tracks attached -- it's a
501 // common use-case for necking-down a track between pads.
502 std::vector<PCB_TRACK*> sameWidthCandidates;
503 std::vector<PCB_TRACK*> differentWidthCandidates;
504
505 for( CN_ITEM* connected : citem->ConnectedItems() )
506 {
507 if( !connected->Valid() )
508 continue;
509
510 BOARD_CONNECTED_ITEM* candidate = connected->Parent();
511
512 if( candidate->Type() == PCB_TRACE_T
513 && !candidate->HasFlag( IS_DELETED ) )
514 {
515 PCB_TRACK* candidateSegment = static_cast<PCB_TRACK*>( candidate );
516
517 if( candidateSegment->GetWidth() == segment->GetWidth() )
518 {
519 sameWidthCandidates.push_back( candidateSegment );
520 }
521 else
522 {
523 differentWidthCandidates.push_back( candidateSegment );
524 break;
525 }
526 }
527 }
528
529 if( !differentWidthCandidates.empty() )
530 continue;
531
532 for( PCB_TRACK* candidate : sameWidthCandidates )
533 {
534 if( segment->ApproxCollinear( *candidate )
535 && mergeCollinearSegments( segment, candidate ) )
536 {
537 return true;
538 }
539 }
540 }
541 }
542
543 return false;
544 };
545
546 if( aMergeSegments )
547 {
548 do
549 {
550 while( !m_brd->BuildConnectivity() )
551 wxSafeYield();
552
553 m_connectedItemsCache.clear();
554 } while( mergeSegments( m_brd->GetConnectivity()->GetConnectivityAlgo() ) );
555 }
556
557 for( PCB_TRACK* track : m_brd->Tracks() )
559}
560
561
562const std::vector<BOARD_CONNECTED_ITEM*>& TRACKS_CLEANER::getConnectedItems( PCB_TRACK* aTrack )
563{
564 static const std::vector<KICAD_T> connectedTypes = { PCB_TRACE_T,
565 PCB_ARC_T,
566 PCB_VIA_T,
567 PCB_PAD_T,
568 PCB_ZONE_T };
569
570 const std::shared_ptr<CONNECTIVITY_DATA>& connectivity = m_brd->GetConnectivity();
571
572 if( m_connectedItemsCache.count( aTrack ) == 0 )
573 m_connectedItemsCache[ aTrack ] = connectivity->GetConnectedItems( aTrack, connectedTypes );
574
575 return m_connectedItemsCache[ aTrack ];
576}
577
578
580{
581 if( aSeg1->IsLocked() || aSeg2->IsLocked() )
582 return false;
583
584 // Collect the unique points where the two tracks are connected to other items
585 std::set<VECTOR2I> pts;
586
587 auto collectPts =
588 [&]( BOARD_CONNECTED_ITEM* citem )
589 {
590 if( citem->Type() == PCB_TRACE_T || citem->Type() == PCB_ARC_T
591 || citem->Type() == PCB_VIA_T )
592 {
593 PCB_TRACK* track = static_cast<PCB_TRACK*>( citem );
594
595 if( track->IsPointOnEnds( aSeg1->GetStart() ) )
596 pts.emplace( aSeg1->GetStart() );
597
598 if( track->IsPointOnEnds( aSeg1->GetEnd() ) )
599 pts.emplace( aSeg1->GetEnd() );
600
601 if( track->IsPointOnEnds( aSeg2->GetStart() ) )
602 pts.emplace( aSeg2->GetStart() );
603
604 if( track->IsPointOnEnds( aSeg2->GetEnd() ) )
605 pts.emplace( aSeg2->GetEnd() );
606 }
607 else
608 {
609 if( citem->HitTest( aSeg1->GetStart(), ( aSeg1->GetWidth() + 1 ) / 2 ) )
610 pts.emplace( aSeg1->GetStart() );
611
612 if( citem->HitTest( aSeg1->GetEnd(), ( aSeg1->GetWidth() + 1 ) / 2 ) )
613 pts.emplace( aSeg1->GetEnd() );
614
615 if( citem->HitTest( aSeg2->GetStart(), ( aSeg2->GetWidth() + 1 ) / 2 ) )
616 pts.emplace( aSeg2->GetStart() );
617
618 if( citem->HitTest( aSeg2->GetEnd(), ( aSeg2->GetWidth() + 1 ) / 2 ) )
619 pts.emplace( aSeg2->GetEnd() );
620 }
621 };
622
623 for( BOARD_CONNECTED_ITEM* item : getConnectedItems( aSeg1 ) )
624 {
625 if( item != aSeg1 && item != aSeg2 )
626 collectPts( item );
627 }
628
629 for( BOARD_CONNECTED_ITEM* item : getConnectedItems( aSeg2 ) )
630 {
631 if( item != aSeg1 && item != aSeg2 )
632 collectPts( item );
633 }
634
635 // This means there is a node in the center
636 if( pts.size() > 2 )
637 return false;
638
639 // Verify the removed point after merging is not a node.
640 // If it is a node (i.e. if more than one other item is connected, the segments cannot be merged
641 PCB_TRACK dummy_seg( *aSeg1 );
642
643 // Calculate the new ends of the segment to merge, and store them to dummy_seg:
644 int min_x = std::min( aSeg1->GetStart().x,
645 std::min( aSeg1->GetEnd().x, std::min( aSeg2->GetStart().x, aSeg2->GetEnd().x ) ) );
646 int min_y = std::min( aSeg1->GetStart().y,
647 std::min( aSeg1->GetEnd().y, std::min( aSeg2->GetStart().y, aSeg2->GetEnd().y ) ) );
648 int max_x = std::max( aSeg1->GetStart().x,
649 std::max( aSeg1->GetEnd().x, std::max( aSeg2->GetStart().x, aSeg2->GetEnd().x ) ) );
650 int max_y = std::max( aSeg1->GetStart().y,
651 std::max( aSeg1->GetEnd().y, std::max( aSeg2->GetStart().y, aSeg2->GetEnd().y ) ) );
652
653 if( ( aSeg1->GetStart().x > aSeg1->GetEnd().x )
654 == ( aSeg1->GetStart().y > aSeg1->GetEnd().y ) )
655 {
656 dummy_seg.SetStart( VECTOR2I( min_x, min_y ) );
657 dummy_seg.SetEnd( VECTOR2I( max_x, max_y ) );
658 }
659 else
660 {
661 dummy_seg.SetStart( VECTOR2I( min_x, max_y ) );
662 dummy_seg.SetEnd( VECTOR2I( max_x, min_y ) );
663 }
664
665 // The new ends of the segment must be connected to all of the same points as the original
666 // segments. If not, the segments cannot be merged.
667 for( auto& pt : pts )
668 {
669 if( !dummy_seg.IsPointOnEnds( pt ) )
670 {
671 dummy_seg.SetParentGroup( nullptr );
672 return false;
673 }
674 }
675
676 // Now find the removed end(s) and stop merging if it is a node:
677 if( aSeg1->GetStart() != dummy_seg.GetStart() && aSeg1->GetStart() != dummy_seg.GetEnd() )
678 {
679 if( testTrackEndpointIsNode( aSeg1, true ) )
680 {
681 dummy_seg.SetParentGroup( nullptr );
682 return false;
683 }
684 }
685
686 if( aSeg1->GetEnd() != dummy_seg.GetStart() && aSeg1->GetEnd() != dummy_seg.GetEnd() )
687 {
688 if( testTrackEndpointIsNode( aSeg1, false ) )
689 {
690 dummy_seg.SetParentGroup( nullptr );
691 return false;
692 }
693 }
694
695 std::shared_ptr<CLEANUP_ITEM> item = std::make_shared<CLEANUP_ITEM>( CLEANUP_MERGE_TRACKS );
696 item->SetItems( aSeg1, aSeg2 );
697 m_itemsList->push_back( item );
698
699 aSeg2->SetFlags( IS_DELETED );
700
701 if( !m_dryRun )
702 {
703 m_commit.Modify( aSeg1 );
704 *aSeg1 = dummy_seg;
705
706 m_brd->GetConnectivity()->Update( aSeg1 );
707
708 // Merge successful, seg2 has to go away
709 m_brd->Remove( aSeg2 );
710 m_commit.Removed( aSeg2 );
711 }
712
713 // Note that dummy_seg is used to replace aSeg1 after processing, so the group membership must
714 // be kept until all processing has finished, and cannot be removed right after creation of the
715 // dummy object
716 dummy_seg.SetParentGroup( nullptr );
717 return true;
718}
719
720
721void TRACKS_CLEANER::removeItems( std::set<BOARD_ITEM*>& aItems )
722{
723 for( BOARD_ITEM* item : aItems )
724 {
725 m_brd->Remove( item );
726 m_commit.Removed( item );
727 }
728}
constexpr int ARC_HIGH_DEF
Definition: base_units.h:120
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...
Definition: board_item.h:79
void SetParentGroup(PCB_GROUP *aGroup)
Definition: board_item.h:92
virtual bool IsLocked() const
Definition: board_item.cpp:75
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:289
bool BuildConnectivity(PROGRESS_REPORTER *aReporter=nullptr)
Build or rebuild the board connectivity database for the board, especially the list of connected item...
Definition: board.cpp:186
const TRACKS & Tracks() const
Definition: board.h:328
void Remove(BOARD_ITEM *aBoardItem, REMOVE_MODE aMode=REMOVE_MODE::NORMAL) override
Removes an item from the container.
Definition: board.cpp:1120
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
Definition: board.h:474
CN_ITEM represents a BOARD_CONNETED_ITEM in the connectivity system (ie: a pad, track/arc/via,...
const std::vector< CN_ITEM * > & ConnectedItems() const
bool Valid() 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.
Definition: commit.h:105
COMMIT & Removed(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Modify a given item in the model.
Definition: commit.h:98
Implement an R-tree for fast spatial and layer indexing of connectable items.
Definition: drc_rtree.h:48
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.
Definition: drc_rtree.h:104
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.
Definition: drc_rtree.h:213
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:127
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:101
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: eda_item.h:129
bool HasFlag(EDA_ITEM_FLAGS aFlag) const
Definition: eda_item.h:131
LSET is a set of PCB_LAYER_IDs.
Definition: lset.h:35
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:732
Definition: pad.h:54
int GetWidth() const
Definition: pcb_track.h:116
void SetEnd(const VECTOR2I &aEnd)
Definition: pcb_track.h:118
void SetStart(const VECTOR2I &aStart)
Definition: pcb_track.h:121
const VECTOR2I & GetStart() const
Definition: pcb_track.h:122
const VECTOR2I & GetEnd() const
Definition: pcb_track.h:119
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...
Definition: pcb_track.cpp:559
VECTOR2I GetPosition() const override
Definition: pcb_track.h:449
VIATYPE GetViaType() const
Definition: pcb_track.h:377
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: pcb_track.cpp:891
A pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:71
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)
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)
REPORTER * m_reporter
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::vector< std::shared_ptr< CLEANUP_ITEM > > * m_itemsList
TRACKS_CLEANER(BOARD *aPcb, BOARD_COMMIT &aCommit)
void removeShortingTrackSegments()
BOARD_COMMIT & m_commit
@ CLEANUP_TRACK_IN_PAD
Definition: cleanup_item.h:42
@ CLEANUP_DANGLING_VIA
Definition: cleanup_item.h:40
@ CLEANUP_MERGE_TRACKS
Definition: cleanup_item.h:38
@ CLEANUP_DANGLING_TRACK
Definition: cleanup_item.h:39
@ CLEANUP_ZERO_LENGTH_TRACK
Definition: cleanup_item.h:41
@ CLEANUP_SHORTING_VIA
Definition: cleanup_item.h:35
@ CLEANUP_REDUNDANT_VIA
Definition: cleanup_item.h:36
@ CLEANUP_SHORTING_TRACK
Definition: cleanup_item.h:34
#define _(s)
#define IS_DELETED
#define SKIP_STRUCT
flag indicating that the structure should be ignored
static std::vector< KICAD_T > connectedTypes
@ ERROR_INSIDE
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:97
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition: typeinfo.h:107
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition: typeinfo.h:87
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition: typeinfo.h:98
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:96
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:673