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