KiCad PCB EDA Suite
connectivity_algo.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) 2016-2018 CERN
5  * Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, you may find one here:
21  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
22  * or you may search the http://www.gnu.org website for the version 2 license,
23  * or you may write to the Free Software Foundation, Inc.,
24  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25  */
26 
30 #include <board_commit.h>
31 
32 #include <wx/log.h>
33 
34 #include <thread>
35 #include <mutex>
36 #include <algorithm>
37 #include <future>
38 
39 #ifdef PROFILE
40 #include <profile.h>
41 #endif
42 
43 
45 {
46  markItemNetAsDirty( aItem );
47 
48  switch( aItem->Type() )
49  {
50  case PCB_FOOTPRINT_T:
51  for( PAD* pad : static_cast<FOOTPRINT*>( aItem )->Pads() )
52  {
53  m_itemMap[pad].MarkItemsAsInvalid();
54  m_itemMap.erase( pad );
55  }
56 
57  m_itemList.SetDirty( true );
58  break;
59 
60  case PCB_PAD_T:
61  m_itemMap[aItem].MarkItemsAsInvalid();
62  m_itemMap.erase( aItem );
63  m_itemList.SetDirty( true );
64  break;
65 
66  case PCB_TRACE_T:
67  case PCB_ARC_T:
68  m_itemMap[aItem].MarkItemsAsInvalid();
69  m_itemMap.erase( aItem );
70  m_itemList.SetDirty( true );
71  break;
72 
73  case PCB_VIA_T:
74  m_itemMap[aItem].MarkItemsAsInvalid();
75  m_itemMap.erase( aItem );
76  m_itemList.SetDirty( true );
77  break;
78 
79  case PCB_ZONE_T:
80  m_itemMap[aItem].MarkItemsAsInvalid();
81  m_itemMap.erase ( aItem );
82  m_itemList.SetDirty( true );
83  break;
84 
85  default:
86  return false;
87  }
88 
89  // Once we delete an item, it may connect between lists, so mark both as potentially invalid
90  m_itemList.SetHasInvalid( true );
91 
92  return true;
93 }
94 
95 
97 {
98  if( aItem->IsConnected() )
99  {
100  auto citem = static_cast<const BOARD_CONNECTED_ITEM*>( aItem );
101  MarkNetAsDirty( citem->GetNetCode() );
102  }
103  else
104  {
105  if( aItem->Type() == PCB_FOOTPRINT_T )
106  {
107  const FOOTPRINT* footprint = static_cast<const FOOTPRINT*>( aItem );
108 
109  for( PAD* pad : footprint->Pads() )
110  MarkNetAsDirty( pad->GetNetCode() );
111  }
112  }
113 }
114 
115 
117 {
118  if( !aItem->IsOnCopperLayer() )
119  return false;
120 
121  markItemNetAsDirty ( aItem );
122 
123  switch( aItem->Type() )
124  {
125  case PCB_NETINFO_T:
126  MarkNetAsDirty( static_cast<NETINFO_ITEM*>( aItem )->GetNetCode() );
127  break;
128 
129  case PCB_FOOTPRINT_T:
130  for( PAD* pad : static_cast<FOOTPRINT*>( aItem )->Pads() )
131  {
132  if( m_itemMap.find( pad ) != m_itemMap.end() )
133  return false;
134 
135  add( m_itemList, pad );
136  }
137 
138  break;
139 
140  case PCB_PAD_T:
141  if( m_itemMap.find ( aItem ) != m_itemMap.end() )
142  return false;
143 
144  add( m_itemList, static_cast<PAD*>( aItem ) );
145  break;
146 
147  case PCB_TRACE_T:
148  if( m_itemMap.find( aItem ) != m_itemMap.end() )
149  return false;
150 
151  add( m_itemList, static_cast<PCB_TRACK*>( aItem ) );
152  break;
153 
154  case PCB_ARC_T:
155  if( m_itemMap.find( aItem ) != m_itemMap.end() )
156  return false;
157 
158  add( m_itemList, static_cast<PCB_ARC*>( aItem ) );
159  break;
160 
161  case PCB_VIA_T:
162  if( m_itemMap.find( aItem ) != m_itemMap.end() )
163  return false;
164 
165  add( m_itemList, static_cast<PCB_VIA*>( aItem ) );
166  break;
167 
168  case PCB_ZONE_T:
169  {
170  ZONE* zone = static_cast<ZONE*>( aItem );
171 
172  if( m_itemMap.find( aItem ) != m_itemMap.end() )
173  return false;
174 
175  m_itemMap[zone] = ITEM_MAP_ENTRY();
176 
177  for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
178  {
179  for( CN_ITEM* zitem : m_itemList.Add( zone, layer ) )
180  m_itemMap[zone].Link( zitem );
181  }
182  }
183  break;
184 
185  default:
186  return false;
187  }
188 
189  return true;
190 }
191 
192 
194 {
195 #ifdef PROFILE
196  PROF_COUNTER garbage_collection( "garbage-collection" );
197 #endif
198  std::vector<CN_ITEM*> garbage;
199  garbage.reserve( 1024 );
200 
201  m_itemList.RemoveInvalidItems( garbage );
202 
203  for( auto item : garbage )
204  delete item;
205 
206 #ifdef PROFILE
207  garbage_collection.Show();
208  PROF_COUNTER search_basic( "search-basic" );
209 #endif
210 
211  std::vector<CN_ITEM*> dirtyItems;
212  std::copy_if( m_itemList.begin(), m_itemList.end(), std::back_inserter( dirtyItems ),
213  [] ( CN_ITEM* aItem )
214  {
215  return aItem->Dirty();
216  } );
217 
218  if( m_progressReporter )
219  {
220  m_progressReporter->SetMaxProgress( dirtyItems.size() );
221 
223  return;
224  }
225 
226  if( m_itemList.IsDirty() )
227  {
228  size_t parallelThreadCount = std::min<size_t>( std::thread::hardware_concurrency(),
229  ( dirtyItems.size() + 7 ) / 8 );
230 
231  std::atomic<size_t> nextItem( 0 );
232  std::vector<std::future<size_t>> returns( parallelThreadCount );
233 
234  auto conn_lambda =
235  [&nextItem, &dirtyItems]( CN_LIST* aItemList,
236  PROGRESS_REPORTER* aReporter) -> size_t
237  {
238  for( size_t i = nextItem++; i < dirtyItems.size(); i = nextItem++ )
239  {
240  CN_VISITOR visitor( dirtyItems[i] );
241  aItemList->FindNearby( dirtyItems[i], visitor );
242 
243  if( aReporter )
244  {
245  if( aReporter->IsCancelled() )
246  break;
247  else
248  aReporter->AdvanceProgress();
249  }
250  }
251 
252  return 1;
253  };
254 
255  if( parallelThreadCount <= 1 )
256  conn_lambda( &m_itemList, m_progressReporter );
257  else
258  {
259  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
260  {
261  returns[ii] = std::async( std::launch::async, conn_lambda, &m_itemList,
263  }
264 
265  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
266  {
267  // Here we balance returns with a 100ms timeout to allow UI updating
268  std::future_status status;
269  do
270  {
271  if( m_progressReporter )
273 
274  status = returns[ii].wait_for( std::chrono::milliseconds( 100 ) );
275  } while( status != std::future_status::ready );
276  }
277  }
278 
279  if( m_progressReporter )
281  }
282 
283 #ifdef PROFILE
284  search_basic.Show();
285 #endif
286 
288 }
289 
290 
292 {
293  constexpr KICAD_T types[] = { PCB_TRACE_T, PCB_ARC_T, PCB_PAD_T, PCB_VIA_T, PCB_ZONE_T,
294  PCB_FOOTPRINT_T, EOT };
295  constexpr KICAD_T no_zones[] = { PCB_TRACE_T, PCB_ARC_T, PCB_PAD_T, PCB_VIA_T,
296  PCB_FOOTPRINT_T, EOT };
297 
298  if( aMode == CSM_PROPAGATE )
299  return SearchClusters( aMode, no_zones, -1 );
300  else
301  return SearchClusters( aMode, types, -1 );
302 }
303 
304 
306  const KICAD_T aTypes[],
307  int aSingleNet )
308 {
309  bool withinAnyNet = ( aMode != CSM_PROPAGATE );
310 
311  std::deque<CN_ITEM*> Q;
312  std::set<CN_ITEM*> item_set;
313 
314  CLUSTERS clusters;
315 
316  if( m_itemList.IsDirty() )
318 
319  auto addToSearchList =
320  [&item_set, withinAnyNet, aSingleNet, aTypes]( CN_ITEM *aItem )
321  {
322  if( withinAnyNet && aItem->Net() <= 0 )
323  return;
324 
325  if( !aItem->Valid() )
326  return;
327 
328  if( aSingleNet >=0 && aItem->Net() != aSingleNet )
329  return;
330 
331  bool found = false;
332 
333  for( int i = 0; aTypes[i] != EOT; i++ )
334  {
335  if( aItem->Parent()->Type() == aTypes[i] )
336  {
337  found = true;
338  break;
339  }
340  }
341 
342  if( !found )
343  return;
344 
345  aItem->SetVisited( false );
346 
347  item_set.insert( aItem );
348  };
349 
350  std::for_each( m_itemList.begin(), m_itemList.end(), addToSearchList );
351 
353  return CLUSTERS();
354 
355  while( !item_set.empty() )
356  {
357  CN_CLUSTER_PTR cluster = std::make_shared<CN_CLUSTER>();
358  CN_ITEM* root;
359  auto it = item_set.begin();
360 
361  while( it != item_set.end() && (*it)->Visited() )
362  it = item_set.erase( item_set.begin() );
363 
364  if( it == item_set.end() )
365  break;
366 
367  root = *it;
368  root->SetVisited( true );
369 
370  Q.clear();
371  Q.push_back( root );
372 
373  while( Q.size() )
374  {
375  CN_ITEM* current = Q.front();
376 
377  Q.pop_front();
378  cluster->Add( current );
379 
380  for( auto n : current->ConnectedItems() )
381  {
382  if( withinAnyNet && n->Net() != root->Net() )
383  continue;
384 
385  if( !n->Visited() && n->Valid() )
386  {
387  n->SetVisited( true );
388  Q.push_back( n );
389  }
390  }
391  }
392 
393  clusters.push_back( cluster );
394  }
395 
397  return CLUSTERS();
398 
399  std::sort( clusters.begin(), clusters.end(),
400  []( CN_CLUSTER_PTR a, CN_CLUSTER_PTR b )
401  {
402  return a->OriginNet() < b->OriginNet();
403  } );
404 
405  return clusters;
406 }
407 
408 
409 void reportProgress( PROGRESS_REPORTER* aReporter, int aCount, int aSize, int aDelta )
410 {
411  if( aReporter && ( ( aCount % aDelta ) == 0 || aCount == aSize - 1 ) )
412  {
413  aReporter->SetCurrentProgress( (double) aCount / (double) aSize );
414  aReporter->KeepRefreshing( false );
415  }
416 }
417 
418 
420 {
421  const int delta = 100; // Number of additions between 2 calls to the progress bar
422  int ii = 0;
423  int size = 0;
424 
425  size += aBoard->Zones().size();
426  size += aBoard->Tracks().size();
427 
428  for( FOOTPRINT* footprint : aBoard->Footprints() )
429  size += footprint->Pads().size();
430 
431  size *= 2; // Our caller us gets the other half of the progress bar
432 
433  for( ZONE* zone : aBoard->Zones() )
434  {
435  Add( zone );
436  reportProgress( aReporter, ii++, size, delta );
437  }
438 
439  for( PCB_TRACK* tv : aBoard->Tracks() )
440  {
441  Add( tv );
442  reportProgress( aReporter, ii++, size, delta );
443  }
444 
445  for( FOOTPRINT* footprint : aBoard->Footprints() )
446  {
447  for( PAD* pad : footprint->Pads() )
448  {
449  Add( pad );
450  reportProgress( aReporter, ii++, size, delta );
451  }
452  }
453 }
454 
455 
456 void CN_CONNECTIVITY_ALGO::Build( const std::vector<BOARD_ITEM*>& aItems )
457 {
458  for( auto item : aItems )
459  {
460  switch( item->Type() )
461  {
462  case PCB_TRACE_T:
463  case PCB_ARC_T:
464  case PCB_VIA_T:
465  case PCB_PAD_T:
466  Add( item );
467  break;
468 
469  case PCB_FOOTPRINT_T:
470  for( PAD* pad : static_cast<FOOTPRINT*>( item )->Pads() )
471  Add( pad );
472 
473  break;
474 
475  default:
476  break;
477  }
478  }
479 }
480 
481 
483 {
484  bool skipConflicts = ( aMode == PROPAGATE_MODE::SKIP_CONFLICTS );
485 
486  wxLogTrace( "CN", "propagateConnections: propagate skip conflicts? %d", skipConflicts );
487 
488  for( const auto& cluster : m_connClusters )
489  {
490  if( skipConflicts && cluster->IsConflicting() )
491  {
492  wxLogTrace( "CN", "Conflicting nets in cluster %p; skipping update", cluster.get() );
493  }
494  else if( cluster->IsOrphaned() )
495  {
496  wxLogTrace( "CN", "Skipping orphaned cluster %p [net: %s]", cluster.get(),
497  (const char*) cluster->OriginNetName().c_str() );
498  }
499  else if( cluster->HasValidNet() )
500  {
501  if( cluster->IsConflicting() )
502  {
503  wxLogTrace( "CN", "Conflicting nets in cluster %p; chose %d (%s)", cluster.get(),
504  cluster->OriginNet(), cluster->OriginNetName() );
505  }
506 
507  // normal cluster: just propagate from the pads
508  int n_changed = 0;
509 
510  for( auto item : *cluster )
511  {
512  if( item->CanChangeNet() )
513  {
514  if( item->Valid() && item->Parent()->GetNetCode() != cluster->OriginNet() )
515  {
516  MarkNetAsDirty( item->Parent()->GetNetCode() );
517  MarkNetAsDirty( cluster->OriginNet() );
518 
519  if( aCommit )
520  aCommit->Modify( item->Parent() );
521 
522  item->Parent()->SetNetCode( cluster->OriginNet() );
523  n_changed++;
524  }
525  }
526  }
527 
528  if( n_changed )
529  {
530  wxLogTrace( "CN", "Cluster %p : net : %d %s", cluster.get(),
531  cluster->OriginNet(), (const char*) cluster->OriginNetName().c_str() );
532  }
533  else
534  wxLogTrace( "CN", "Cluster %p : nothing to propagate", cluster.get() );
535  }
536  else
537  {
538  wxLogTrace( "CN", "Cluster %p : connected to unused net", cluster.get() );
539  }
540  }
541 }
542 
543 
545 {
547  propagateConnections( aCommit, aMode );
548 }
549 
550 
552  std::vector<int>& aIslands )
553 {
554  if( aZone->GetFilledPolysList( aLayer ).IsEmpty() )
555  return;
556 
557  aIslands.clear();
558 
559  Remove( aZone );
560  Add( aZone );
561 
563 
564  for( const auto& cluster : m_connClusters )
565  {
566  if( cluster->Contains( aZone ) && cluster->IsOrphaned() )
567  {
568  for( auto z : *cluster )
569  {
570  if( z->Parent() == aZone && z->Layer() == aLayer )
571  {
572  aIslands.push_back( static_cast<CN_ZONE_LAYER*>(z)->SubpolyIndex() );
573  }
574  }
575  }
576  }
577 
578  wxLogTrace( "CN", "Found %u isolated islands\n", (unsigned)aIslands.size() );
579 }
580 
581 void CN_CONNECTIVITY_ALGO::FindIsolatedCopperIslands( std::vector<CN_ZONE_ISOLATED_ISLAND_LIST>& aZones )
582 {
583  for( auto& z : aZones )
584  {
585  Remove( z.m_zone );
586  Add( z.m_zone );
587  }
588 
590 
591  for( CN_ZONE_ISOLATED_ISLAND_LIST& zone : aZones )
592  {
593  for( PCB_LAYER_ID layer : zone.m_zone->GetLayerSet().Seq() )
594  {
595  if( zone.m_zone->GetFilledPolysList( layer ).IsEmpty() )
596  continue;
597 
598  for( const CN_CLUSTER_PTR& cluster : m_connClusters )
599  {
600  if( cluster->Contains( zone.m_zone ) && cluster->IsOrphaned() )
601  {
602  for( CN_ITEM* z : *cluster )
603  {
604  if( z->Parent() == zone.m_zone && z->Layer() == layer )
605  {
606  zone.m_islands[layer].push_back(
607  static_cast<CN_ZONE_LAYER*>( z )->SubpolyIndex() );
608  }
609  }
610  }
611  }
612  }
613  }
614 }
615 
616 
618 {
620  return m_ratsnestClusters;
621 }
622 
623 
625 {
626  if( aNet < 0 )
627  return;
628 
629  if( (int) m_dirtyNets.size() <= aNet )
630  {
631  int lastNet = m_dirtyNets.size() - 1;
632 
633  if( lastNet < 0 )
634  lastNet = 0;
635 
636  m_dirtyNets.resize( aNet + 1 );
637 
638  for( int i = lastNet; i < aNet + 1; i++ )
639  m_dirtyNets[i] = true;
640  }
641 
642  m_dirtyNets[aNet] = true;
643 }
644 
645 
647 {
648  if( aZoneLayer->Net() != aItem->Net() && !aItem->CanChangeNet() )
649  return;
650 
651  if( !aZoneLayer->BBox().Intersects( aItem->BBox() ) )
652  return;
653 
654  int accuracy = 0;
655 
656  if( aItem->Parent()->Type() == PCB_VIA_T
657  || aItem->Parent()->Type() == PCB_TRACE_T
658  || aItem->Parent()->Type() == PCB_ARC_T )
659  {
660  accuracy = ( static_cast<PCB_TRACK*>( aItem->Parent() )->GetWidth() + 1 ) / 2;
661  }
662 
663  for( int i = 0; i < aItem->AnchorCount(); ++i )
664  {
665  if( aZoneLayer->ContainsPoint( aItem->GetAnchor( i ), accuracy ) )
666  {
667  aZoneLayer->Connect( aItem );
668  aItem->Connect( aZoneLayer );
669  return;
670  }
671  }
672 }
673 
675 {
676  const ZONE* zoneA = static_cast<const ZONE*>( aZoneLayerA->Parent() );
677  const ZONE* zoneB = static_cast<const ZONE*>( aZoneLayerB->Parent() );
678 
679  if( aZoneLayerA->Layer() != aZoneLayerB->Layer() )
680  return;
681 
682  if( aZoneLayerB->Net() != aZoneLayerA->Net() )
683  return; // we only test zones belonging to the same net
684 
685  const BOX2I& boxA = aZoneLayerA->BBox();
686  const BOX2I& boxB = aZoneLayerB->BBox();
687 
688  int radiusA = 0;
689  int radiusB = 0;
690 
691  if( zoneA->GetFilledPolysUseThickness() )
692  radiusA = ( zoneA->GetMinThickness() + 1 ) / 2;
693 
694  if( zoneB->GetFilledPolysUseThickness() )
695  radiusB = ( zoneB->GetMinThickness() + 1 ) / 2;
696 
697  PCB_LAYER_ID layer = static_cast<PCB_LAYER_ID>( aZoneLayerA->Layer() );
698 
699  const SHAPE_LINE_CHAIN& outline =
700  zoneA->GetFilledPolysList( layer ).COutline( aZoneLayerA->SubpolyIndex() );
701 
702  for( int i = 0; i < outline.PointCount(); i++ )
703  {
704  if( !boxB.Contains( outline.CPoint( i ) ) )
705  continue;
706 
707  if( aZoneLayerB->ContainsPoint( outline.CPoint( i ), radiusA ) )
708  {
709  aZoneLayerA->Connect( aZoneLayerB );
710  aZoneLayerB->Connect( aZoneLayerA );
711  return;
712  }
713  }
714 
715  const SHAPE_LINE_CHAIN& outline2 =
716  zoneB->GetFilledPolysList( layer ).COutline( aZoneLayerB->SubpolyIndex() );
717 
718  for( int i = 0; i < outline2.PointCount(); i++ )
719  {
720  if( !boxA.Contains( outline2.CPoint( i ) ) )
721  continue;
722 
723  if( aZoneLayerA->ContainsPoint( outline2.CPoint( i ), radiusB ) )
724  {
725  aZoneLayerA->Connect( aZoneLayerB );
726  aZoneLayerB->Connect( aZoneLayerA );
727  return;
728  }
729  }
730 }
731 
732 
733 bool CN_VISITOR::operator()( CN_ITEM* aCandidate )
734 {
735  const BOARD_CONNECTED_ITEM* parentA = aCandidate->Parent();
736  const BOARD_CONNECTED_ITEM* parentB = m_item->Parent();
737 
738  if( !aCandidate->Valid() || !m_item->Valid() )
739  return true;
740 
741  if( parentA == parentB )
742  return true;
743 
744  if( !( parentA->GetLayerSet() & parentB->GetLayerSet() ).any() )
745  return true;
746 
747  // If both m_item and aCandidate are marked dirty, they will both be searched
748  // Since we are reciprocal in our connection, we arbitrarily pick one of the connections
749  // to conduct the expensive search
750  if( aCandidate->Dirty() && aCandidate < m_item )
751  return true;
752 
753  // We should handle zone-zone connection separately
754  if ( parentA->Type() == PCB_ZONE_T && parentB->Type() == PCB_ZONE_T )
755  {
756  checkZoneZoneConnection( static_cast<CN_ZONE_LAYER*>( m_item ),
757  static_cast<CN_ZONE_LAYER*>( aCandidate ) );
758  return true;
759  }
760 
761  if( parentA->Type() == PCB_ZONE_T )
762  {
763  checkZoneItemConnection( static_cast<CN_ZONE_LAYER*>( aCandidate ), m_item );
764  return true;
765  }
766 
767  if( parentB->Type() == PCB_ZONE_T )
768  {
769  checkZoneItemConnection( static_cast<CN_ZONE_LAYER*>( m_item ), aCandidate );
770  return true;
771  }
772 
773  int accuracyA = 0;
774  int accuracyB = 0;
775 
776  if( parentA->Type() == PCB_VIA_T
777  || parentA->Type() == PCB_TRACE_T
778  || parentA->Type() == PCB_ARC_T)
779  accuracyA = ( static_cast<const PCB_TRACK*>( parentA )->GetWidth() + 1 ) / 2;
780 
781  if( parentB->Type() == PCB_VIA_T
782  || parentB->Type() == PCB_TRACE_T
783  || parentB->Type() == PCB_ARC_T )
784  accuracyB = ( static_cast<const PCB_TRACK*>( parentB )->GetWidth() + 1 ) / 2;
785 
786  // Items do not necessarily have reciprocity as we only check for anchors
787  // therefore, we check HitTest both directions A->B & B->A
788  for( int i = 0; i < aCandidate->AnchorCount(); ++i )
789  {
790  if( parentB->HitTest( wxPoint( aCandidate->GetAnchor( i ) ), accuracyA ) )
791  {
792  m_item->Connect( aCandidate );
793  aCandidate->Connect( m_item );
794  return true;
795  }
796  }
797 
798  for( int i = 0; i < m_item->AnchorCount(); ++i )
799  {
800  if( parentA->HitTest( wxPoint( m_item->GetAnchor( i ) ), accuracyB ) )
801  {
802  m_item->Connect( aCandidate );
803  aCandidate->Connect( m_item );
804  return true;
805  }
806  }
807 
808  return true;
809 };
810 
811 
813 {
814  m_ratsnestClusters.clear();
815  m_connClusters.clear();
816  m_itemMap.clear();
817  m_itemList.Clear();
818 
819 }
820 
822 {
823  m_progressReporter = aReporter;
824 }
void RemoveInvalidItems(std::vector< CN_ITEM * > &aGarbage)
const CONNECTED_ITEMS & ConnectedItems() const
COMMIT & Modify(EDA_ITEM *aItem)
Create an undo entry for an item that has been already modified.
Definition: commit.h:103
bool Remove(BOARD_ITEM *aItem)
void SetHasInvalid(bool aInvalid=true)
ZONES & Zones()
Definition: board.h:239
PROPAGATE_MODE
Controls how nets are propagated through clusters.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:80
void checkZoneItemConnection(CN_ZONE_LAYER *aZoneLayer, CN_ITEM *aItem)
A progress reporter for use in multi-threaded environments.
CN_ITEM * Add(PAD *pad)
const BOX2I & BBox()
bool IsEmpty() const
void ClearDirtyFlags()
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: zone.cpp:291
bool ContainsPoint(const VECTOR2I &p, int aAccuracy=0) const
void SetVisited(bool aVisited)
class PCB_ARC, an arc track segment on a copper layer
Definition: typeinfo.h:97
bool IsDirty() const
void MarkNetAsDirty(int aNet)
class PAD, a pad in a footprint
Definition: typeinfo.h:89
bool Add(BOARD_ITEM *aItem)
const SHAPE_POLY_SET & GetFilledPolysList(PCB_LAYER_ID aLayer) const
Definition: zone.h:636
bool Dirty() const
BOARD_CONNECTED_ITEM * Parent() const
void FindIsolatedCopperIslands(ZONE *aZone, PCB_LAYER_ID aLayer, std::vector< int > &aIslands)
void add(Container &c, BItem brditem)
int PointCount() const
Return the number of points (vertices) in this line chain.
LSEQ Seq(const PCB_LAYER_ID *aWishListSequence, unsigned aCount) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:411
A small class to help profiling.
Definition: profile.h:45
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
void SetDirty(bool aDirty=true)
int Net() const
allow parallel connection threads
search types array terminator (End Of Types)
Definition: typeinfo.h:81
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition: typeinfo.h:77
std::vector< bool > m_dirtyNets
class PCB_TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:95
PADS & Pads()
Definition: footprint.h:159
virtual int AnchorCount() const
void PropagateNets(BOARD_COMMIT *aCommit=nullptr, PROPAGATE_MODE aMode=PROPAGATE_MODE::SKIP_CONFLICTS)
Propagate nets from pads to other items in clusters.
const CLUSTERS SearchClusters(CLUSTER_SEARCH_MODE aMode, const KICAD_T aTypes[], int aSingleNet)
virtual bool HitTest(const wxPoint &aPosition, int aAccuracy=0) const
Test if aPosition is contained within or on the bounding box of an item.
Definition: eda_item.h:225
bool Intersects(const BOX2< Vec > &aRect) const
Definition: box2.h:217
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
virtual void SetCurrentProgress(double aProgress)
Set the progress value to aProgress (0..1).
PCB_LAYER_ID
A quick note on layer IDs:
void markItemNetAsDirty(const BOARD_ITEM *aItem)
bool IsCancelled() const
int GetMinThickness() const
Definition: zone.h:245
void propagateConnections(BOARD_COMMIT *aCommit=nullptr, PROPAGATE_MODE aMode=PROPAGATE_MODE::SKIP_CONFLICTS)
FOOTPRINTS & Footprints()
Definition: board.h:233
bool Contains(const Vec &aPoint) const
Definition: box2.h:134
a few functions useful in geometry calculations.
void checkZoneZoneConnection(CN_ZONE_LAYER *aZoneLayerA, CN_ZONE_LAYER *aZoneLayerB)
The item we are looking for connections to.
Handle a list of polygons defining a copper zone.
Definition: zone.h:57
class ZONE, a copper pour area
Definition: typeinfo.h:105
int SubpolyIndex() const
void reportProgress(PROGRESS_REPORTER *aReporter, int aCount, int aSize, int aDelta)
virtual const VECTOR2I GetAnchor(int n) const
class FOOTPRINT, a footprint
Definition: typeinfo.h:88
bool CanChangeNet() const
bool operator()(CN_ITEM *aCandidate)
const CLUSTERS & GetClusters()
void Build(BOARD *aBoard, PROGRESS_REPORTER *aReporter=nullptr)
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:190
Represent a polyline (an zero-thickness chain of connected line segments).
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
class NETINFO_ITEM, a description of a net
Definition: typeinfo.h:107
bool KeepRefreshing(bool aWait=false)
Update the UI dialog.
std::shared_ptr< CN_CLUSTER > CN_CLUSTER_PTR
virtual int Layer() const
Return the item's layer, for single-layered items only.
virtual bool IsConnected() const
Returns information if the object is derived from BOARD_CONNECTED_ITEM.
Definition: board_item.h:134
void Connect(CN_ITEM *b)
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:96
void Show(std::ostream &aStream=std::cerr)
Print the elapsed time (in a suitable unit) to a stream.
Definition: profile.h:102
Definition: pad.h:57
CN_ITEM * m_item
void SetMaxProgress(int aMaxProgress)
Fix the value that gives the 100 percent progress bar length (inside the current virtual zone).
std::vector< CN_CLUSTER_PTR > CLUSTERS
TRACKS & Tracks()
Definition: board.h:230
virtual bool IsOnCopperLayer() const
Definition: board_item.h:142
std::unordered_map< const BOARD_ITEM *, ITEM_MAP_ENTRY > m_itemMap
A structure used for calculating isolated islands on a given zone across all its layers.
const BOX2I & BBox()
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition: board_item.h:176
bool Valid() const
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:113
bool GetFilledPolysUseThickness() const
Definition: zone.h:690
void SetProgressReporter(PROGRESS_REPORTER *aReporter)
PROGRESS_REPORTER * m_progressReporter