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