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