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