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 <[email protected]>
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 
28 #include <progress_reporter.h>
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  switch( aItem->Type() )
122  {
123  case PCB_NETINFO_T:
124  MarkNetAsDirty( static_cast<NETINFO_ITEM*>( aItem )->GetNetCode() );
125  break;
126 
127  case PCB_FOOTPRINT_T:
128  {
129  if( static_cast<FOOTPRINT*>( aItem )->GetAttributes() & FP_JUST_ADDED )
130  return false;
131 
132  for( PAD* pad : static_cast<FOOTPRINT*>( aItem )->Pads() )
133  {
134  if( m_itemMap.find( pad ) != m_itemMap.end() )
135  return false;
136 
137  add( m_itemList, pad );
138  }
139 
140  break;
141  }
142 
143  case PCB_PAD_T:
144  {
145  if( FOOTPRINT* fp = dynamic_cast<FOOTPRINT*>( aItem->GetParentFootprint() ) )
146  {
147  if( fp->GetAttributes() & FP_JUST_ADDED )
148  return false;
149  }
150 
151  if( m_itemMap.find( aItem ) != m_itemMap.end() )
152  return false;
153 
154  add( m_itemList, static_cast<PAD*>( aItem ) );
155  break;
156  }
157 
158  case PCB_TRACE_T:
159  if( m_itemMap.find( aItem ) != m_itemMap.end() )
160  return false;
161 
162  add( m_itemList, static_cast<PCB_TRACK*>( aItem ) );
163  break;
164 
165  case PCB_ARC_T:
166  if( m_itemMap.find( aItem ) != m_itemMap.end() )
167  return false;
168 
169  add( m_itemList, static_cast<PCB_ARC*>( aItem ) );
170  break;
171 
172  case PCB_VIA_T:
173  if( m_itemMap.find( aItem ) != m_itemMap.end() )
174  return false;
175 
176  add( m_itemList, static_cast<PCB_VIA*>( aItem ) );
177  break;
178 
179  case PCB_ZONE_T:
180  {
181  ZONE* zone = static_cast<ZONE*>( aItem );
182 
183  if( m_itemMap.find( aItem ) != m_itemMap.end() )
184  return false;
185 
186  m_itemMap[zone] = ITEM_MAP_ENTRY();
187 
188  for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
189  {
190  for( CN_ITEM* zitem : m_itemList.Add( zone, layer ) )
191  m_itemMap[zone].Link( zitem );
192  }
193  }
194  break;
195 
196  default:
197  return false;
198  }
199 
200  markItemNetAsDirty( aItem );
201 
202  return true;
203 }
204 
205 
207 {
208 #ifdef PROFILE
209  PROF_COUNTER garbage_collection( "garbage-collection" );
210 #endif
211  std::vector<CN_ITEM*> garbage;
212  garbage.reserve( 1024 );
213 
214  m_itemList.RemoveInvalidItems( garbage );
215 
216  for( auto item : garbage )
217  delete item;
218 
219 #ifdef PROFILE
220  garbage_collection.Show();
221  PROF_COUNTER search_basic( "search-basic" );
222 #endif
223 
224  std::vector<CN_ITEM*> dirtyItems;
225  std::copy_if( m_itemList.begin(), m_itemList.end(), std::back_inserter( dirtyItems ),
226  [] ( CN_ITEM* aItem )
227  {
228  return aItem->Dirty();
229  } );
230 
231  if( m_progressReporter )
232  {
233  m_progressReporter->SetMaxProgress( dirtyItems.size() );
234 
236  return;
237  }
238 
239  if( m_itemList.IsDirty() )
240  {
241  size_t parallelThreadCount = std::min<size_t>( std::thread::hardware_concurrency(),
242  ( dirtyItems.size() + 7 ) / 8 );
243 
244  std::atomic<size_t> nextItem( 0 );
245  std::vector<std::future<size_t>> returns( parallelThreadCount );
246 
247  auto conn_lambda =
248  [&nextItem, &dirtyItems]( CN_LIST* aItemList,
249  PROGRESS_REPORTER* aReporter) -> size_t
250  {
251  for( size_t i = nextItem++; i < dirtyItems.size(); i = nextItem++ )
252  {
253  CN_VISITOR visitor( dirtyItems[i] );
254  aItemList->FindNearby( dirtyItems[i], visitor );
255 
256  if( aReporter )
257  {
258  if( aReporter->IsCancelled() )
259  break;
260  else
261  aReporter->AdvanceProgress();
262  }
263  }
264 
265  return 1;
266  };
267 
268  if( parallelThreadCount <= 1 )
269  conn_lambda( &m_itemList, m_progressReporter );
270  else
271  {
272  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
273  {
274  returns[ii] = std::async( std::launch::async, conn_lambda, &m_itemList,
276  }
277 
278  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
279  {
280  // Here we balance returns with a 100ms timeout to allow UI updating
281  std::future_status status;
282  do
283  {
284  if( m_progressReporter )
286 
287  status = returns[ii].wait_for( std::chrono::milliseconds( 100 ) );
288  } while( status != std::future_status::ready );
289  }
290  }
291 
292  if( m_progressReporter )
294  }
295 
296 #ifdef PROFILE
297  search_basic.Show();
298 #endif
299 
301 }
302 
303 
305 {
306  constexpr KICAD_T types[] = { PCB_TRACE_T, PCB_ARC_T, PCB_PAD_T, PCB_VIA_T, PCB_ZONE_T,
307  PCB_FOOTPRINT_T, EOT };
308  constexpr KICAD_T no_zones[] = { PCB_TRACE_T, PCB_ARC_T, PCB_PAD_T, PCB_VIA_T,
309  PCB_FOOTPRINT_T, EOT };
310 
311  if( aMode == CSM_PROPAGATE )
312  return SearchClusters( aMode, no_zones, -1 );
313  else
314  return SearchClusters( aMode, types, -1 );
315 }
316 
317 
319  const KICAD_T aTypes[],
320  int aSingleNet )
321 {
322  bool withinAnyNet = ( aMode != CSM_PROPAGATE );
323 
324  std::deque<CN_ITEM*> Q;
325  std::set<CN_ITEM*> item_set;
326 
327  CLUSTERS clusters;
328 
329  if( m_itemList.IsDirty() )
331 
332  auto addToSearchList =
333  [&item_set, withinAnyNet, aSingleNet, aTypes]( CN_ITEM *aItem )
334  {
335  if( withinAnyNet && aItem->Net() <= 0 )
336  return;
337 
338  if( !aItem->Valid() )
339  return;
340 
341  if( aSingleNet >=0 && aItem->Net() != aSingleNet )
342  return;
343 
344  bool found = false;
345 
346  for( int i = 0; aTypes[i] != EOT; i++ )
347  {
348  if( aItem->Parent()->Type() == aTypes[i] )
349  {
350  found = true;
351  break;
352  }
353  }
354 
355  if( !found )
356  return;
357 
358  aItem->SetVisited( false );
359 
360  item_set.insert( aItem );
361  };
362 
363  std::for_each( m_itemList.begin(), m_itemList.end(), addToSearchList );
364 
366  return CLUSTERS();
367 
368  while( !item_set.empty() )
369  {
370  CN_CLUSTER_PTR cluster = std::make_shared<CN_CLUSTER>();
371  CN_ITEM* root;
372  auto it = item_set.begin();
373 
374  while( it != item_set.end() && (*it)->Visited() )
375  it = item_set.erase( item_set.begin() );
376 
377  if( it == item_set.end() )
378  break;
379 
380  root = *it;
381  root->SetVisited( true );
382 
383  Q.clear();
384  Q.push_back( root );
385 
386  while( Q.size() )
387  {
388  CN_ITEM* current = Q.front();
389 
390  Q.pop_front();
391  cluster->Add( current );
392 
393  for( auto n : current->ConnectedItems() )
394  {
395  if( withinAnyNet && n->Net() != root->Net() )
396  continue;
397 
398  if( !n->Visited() && n->Valid() )
399  {
400  n->SetVisited( true );
401  Q.push_back( n );
402  }
403  }
404  }
405 
406  clusters.push_back( cluster );
407  }
408 
410  return CLUSTERS();
411 
412  std::sort( clusters.begin(), clusters.end(),
413  []( CN_CLUSTER_PTR a, CN_CLUSTER_PTR b )
414  {
415  return a->OriginNet() < b->OriginNet();
416  } );
417 
418  return clusters;
419 }
420 
421 
422 void reportProgress( PROGRESS_REPORTER* aReporter, int aCount, int aSize, int aDelta )
423 {
424  if( aReporter && ( ( aCount % aDelta ) == 0 || aCount == aSize - 1 ) )
425  {
426  aReporter->SetCurrentProgress( (double) aCount / (double) aSize );
427  aReporter->KeepRefreshing( false );
428  }
429 }
430 
431 
433 {
434  int delta = 200; // Number of additions between 2 calls to the progress bar
435  int ii = 0;
436  int size = 0;
437 
438  size += aBoard->Zones().size();
439  size += aBoard->Tracks().size();
440 
441  for( FOOTPRINT* footprint : aBoard->Footprints() )
442  size += footprint->Pads().size();
443 
444  size *= 2; // Our caller us gets the other half of the progress bar
445 
446  delta = std::max( delta, size / 10 );
447 
448  for( ZONE* zone : aBoard->Zones() )
449  {
450  Add( zone );
451  reportProgress( aReporter, ii++, size, delta );
452  }
453 
454  for( PCB_TRACK* tv : aBoard->Tracks() )
455  {
456  Add( tv );
457  reportProgress( aReporter, ii++, size, delta );
458  }
459 
460  for( FOOTPRINT* footprint : aBoard->Footprints() )
461  {
462  for( PAD* pad : footprint->Pads() )
463  {
464  Add( pad );
465  reportProgress( aReporter, ii++, size, delta );
466  }
467  }
468 }
469 
470 
471 void CN_CONNECTIVITY_ALGO::Build( const std::vector<BOARD_ITEM*>& aItems )
472 {
473  for( auto item : aItems )
474  {
475  switch( item->Type() )
476  {
477  case PCB_TRACE_T:
478  case PCB_ARC_T:
479  case PCB_VIA_T:
480  case PCB_PAD_T:
481  Add( item );
482  break;
483 
484  case PCB_FOOTPRINT_T:
485  for( PAD* pad : static_cast<FOOTPRINT*>( item )->Pads() )
486  Add( pad );
487 
488  break;
489 
490  default:
491  break;
492  }
493  }
494 }
495 
496 
498 {
499  bool skipConflicts = ( aMode == PROPAGATE_MODE::SKIP_CONFLICTS );
500 
501  wxLogTrace( wxT( "CN" ), wxT( "propagateConnections: propagate skip conflicts? %d" ),
502  skipConflicts );
503 
504  for( const auto& cluster : m_connClusters )
505  {
506  if( skipConflicts && cluster->IsConflicting() )
507  {
508  wxLogTrace( wxT( "CN" ), wxT( "Conflicting nets in cluster %p; skipping update" ),
509  cluster.get() );
510  }
511  else if( cluster->IsOrphaned() )
512  {
513  wxLogTrace( wxT( "CN" ), wxT( "Skipping orphaned cluster %p [net: %s]" ),
514  cluster.get(),
515  (const char*) cluster->OriginNetName().c_str() );
516  }
517  else if( cluster->HasValidNet() )
518  {
519  if( cluster->IsConflicting() )
520  {
521  wxLogTrace( wxT( "CN" ), wxT( "Conflicting nets in cluster %p; chose %d (%s)" ),
522  cluster.get(),
523  cluster->OriginNet(),
524  cluster->OriginNetName() );
525  }
526 
527  // normal cluster: just propagate from the pads
528  int n_changed = 0;
529 
530  for( auto item : *cluster )
531  {
532  if( item->CanChangeNet() )
533  {
534  if( item->Valid() && item->Parent()->GetNetCode() != cluster->OriginNet() )
535  {
536  MarkNetAsDirty( item->Parent()->GetNetCode() );
537  MarkNetAsDirty( cluster->OriginNet() );
538 
539  if( aCommit )
540  aCommit->Modify( item->Parent() );
541 
542  item->Parent()->SetNetCode( cluster->OriginNet() );
543  n_changed++;
544  }
545  }
546  }
547 
548  if( n_changed )
549  {
550  wxLogTrace( wxT( "CN" ), wxT( "Cluster %p : net : %d %s" ),
551  cluster.get(),
552  cluster->OriginNet(),
553  (const char*) cluster->OriginNetName().c_str() );
554  }
555  else
556  wxLogTrace( wxT( "CN" ), wxT( "Cluster %p : nothing to propagate" ),
557  cluster.get() );
558  }
559  else
560  {
561  wxLogTrace( wxT( "CN" ), wxT( "Cluster %p : connected to unused net" ),
562  cluster.get() );
563  }
564  }
565 }
566 
567 
569 {
571  propagateConnections( aCommit, aMode );
572 }
573 
574 
576  std::vector<int>& aIslands )
577 {
578  if( aZone->GetFilledPolysList( aLayer ).IsEmpty() )
579  return;
580 
581  aIslands.clear();
582 
583  Remove( aZone );
584  Add( aZone );
585 
587 
588  for( const auto& cluster : m_connClusters )
589  {
590  if( cluster->Contains( aZone ) && cluster->IsOrphaned() )
591  {
592  for( auto z : *cluster )
593  {
594  if( z->Parent() == aZone && z->Layer() == aLayer )
595  {
596  aIslands.push_back( static_cast<CN_ZONE_LAYER*>(z)->SubpolyIndex() );
597  }
598  }
599  }
600  }
601 
602  wxLogTrace( wxT( "CN" ), wxT( "Found %u isolated islands\n" ), (unsigned) aIslands.size() );
603 }
604 
605 void CN_CONNECTIVITY_ALGO::FindIsolatedCopperIslands( std::vector<CN_ZONE_ISOLATED_ISLAND_LIST>& aZones )
606 {
607  for( auto& z : aZones )
608  {
609  Remove( z.m_zone );
610  Add( z.m_zone );
611  }
612 
614 
615  for( CN_ZONE_ISOLATED_ISLAND_LIST& zone : aZones )
616  {
617  for( PCB_LAYER_ID layer : zone.m_zone->GetLayerSet().Seq() )
618  {
619  if( zone.m_zone->GetFilledPolysList( layer ).IsEmpty() )
620  continue;
621 
622  for( const CN_CLUSTER_PTR& cluster : m_connClusters )
623  {
624  if( cluster->Contains( zone.m_zone ) && cluster->IsOrphaned() )
625  {
626  for( CN_ITEM* z : *cluster )
627  {
628  if( z->Parent() == zone.m_zone && z->Layer() == layer )
629  {
630  zone.m_islands[layer].push_back(
631  static_cast<CN_ZONE_LAYER*>( z )->SubpolyIndex() );
632  }
633  }
634  }
635  }
636  }
637  }
638 }
639 
640 
642 {
644  return m_ratsnestClusters;
645 }
646 
647 
649 {
650  if( aNet < 0 )
651  return;
652 
653  if( (int) m_dirtyNets.size() <= aNet )
654  {
655  int lastNet = m_dirtyNets.size() - 1;
656 
657  if( lastNet < 0 )
658  lastNet = 0;
659 
660  m_dirtyNets.resize( aNet + 1 );
661 
662  for( int i = lastNet; i < aNet + 1; i++ )
663  m_dirtyNets[i] = true;
664  }
665 
666  m_dirtyNets[aNet] = true;
667 }
668 
669 
671 {
672  if( aZoneLayer->Net() != aItem->Net() && !aItem->CanChangeNet() )
673  return;
674 
675  if( !aZoneLayer->BBox().Intersects( aItem->BBox() ) )
676  return;
677 
678  int accuracy = 0;
679 
680  if( aItem->Parent()->Type() == PCB_VIA_T
681  || aItem->Parent()->Type() == PCB_TRACE_T
682  || aItem->Parent()->Type() == PCB_ARC_T )
683  {
684  accuracy = ( static_cast<PCB_TRACK*>( aItem->Parent() )->GetWidth() + 1 ) / 2;
685  }
686 
687  for( int i = 0; i < aItem->AnchorCount(); ++i )
688  {
689  if( aZoneLayer->ContainsPoint( aItem->GetAnchor( i ), accuracy ) )
690  {
691  aZoneLayer->Connect( aItem );
692  aItem->Connect( aZoneLayer );
693  return;
694  }
695  }
696 }
697 
699 {
700  const ZONE* zoneA = static_cast<const ZONE*>( aZoneLayerA->Parent() );
701  const ZONE* zoneB = static_cast<const ZONE*>( aZoneLayerB->Parent() );
702 
703  if( aZoneLayerA->Layer() != aZoneLayerB->Layer() )
704  return;
705 
706  if( aZoneLayerB->Net() != aZoneLayerA->Net() )
707  return; // we only test zones belonging to the same net
708 
709  const BOX2I& boxA = aZoneLayerA->BBox();
710  const BOX2I& boxB = aZoneLayerB->BBox();
711 
712  int radiusA = 0;
713  int radiusB = 0;
714 
715  if( zoneA->GetFilledPolysUseThickness() )
716  radiusA = ( zoneA->GetMinThickness() + 1 ) / 2;
717 
718  if( zoneB->GetFilledPolysUseThickness() )
719  radiusB = ( zoneB->GetMinThickness() + 1 ) / 2;
720 
721  PCB_LAYER_ID layer = static_cast<PCB_LAYER_ID>( aZoneLayerA->Layer() );
722 
723  const SHAPE_LINE_CHAIN& outline =
724  zoneA->GetFilledPolysList( layer ).COutline( aZoneLayerA->SubpolyIndex() );
725 
726  for( int i = 0; i < outline.PointCount(); i++ )
727  {
728  if( !boxB.Contains( outline.CPoint( i ) ) )
729  continue;
730 
731  if( aZoneLayerB->ContainsPoint( outline.CPoint( i ), radiusA ) )
732  {
733  aZoneLayerA->Connect( aZoneLayerB );
734  aZoneLayerB->Connect( aZoneLayerA );
735  return;
736  }
737  }
738 
739  const SHAPE_LINE_CHAIN& outline2 =
740  zoneB->GetFilledPolysList( layer ).COutline( aZoneLayerB->SubpolyIndex() );
741 
742  for( int i = 0; i < outline2.PointCount(); i++ )
743  {
744  if( !boxA.Contains( outline2.CPoint( i ) ) )
745  continue;
746 
747  if( aZoneLayerA->ContainsPoint( outline2.CPoint( i ), radiusB ) )
748  {
749  aZoneLayerA->Connect( aZoneLayerB );
750  aZoneLayerB->Connect( aZoneLayerA );
751  return;
752  }
753  }
754 }
755 
756 
757 bool CN_VISITOR::operator()( CN_ITEM* aCandidate )
758 {
759  const BOARD_CONNECTED_ITEM* parentA = aCandidate->Parent();
760  const BOARD_CONNECTED_ITEM* parentB = m_item->Parent();
761 
762  if( !aCandidate->Valid() || !m_item->Valid() )
763  return true;
764 
765  if( parentA == parentB )
766  return true;
767 
768  LSET commonLayers = parentA->GetLayerSet() & parentB->GetLayerSet();
769 
770  if( !commonLayers.any() )
771  return true;
772 
773  // If both m_item and aCandidate are marked dirty, they will both be searched
774  // Since we are reciprocal in our connection, we arbitrarily pick one of the connections
775  // to conduct the expensive search
776  if( aCandidate->Dirty() && aCandidate < m_item )
777  return true;
778 
779  // We should handle zone-zone connection separately
780  if ( parentA->Type() == PCB_ZONE_T && parentB->Type() == PCB_ZONE_T )
781  {
782  checkZoneZoneConnection( static_cast<CN_ZONE_LAYER*>( m_item ),
783  static_cast<CN_ZONE_LAYER*>( aCandidate ) );
784  return true;
785  }
786 
787  if( parentA->Type() == PCB_ZONE_T )
788  {
789  checkZoneItemConnection( static_cast<CN_ZONE_LAYER*>( aCandidate ), m_item );
790  return true;
791  }
792 
793  if( parentB->Type() == PCB_ZONE_T )
794  {
795  checkZoneItemConnection( static_cast<CN_ZONE_LAYER*>( m_item ), aCandidate );
796  return true;
797  }
798 
799  for( PCB_LAYER_ID layer : commonLayers.Seq() )
800  {
801  FLASHING flashingA = FLASHING::NEVER_FLASHED;
802  FLASHING flashingB = FLASHING::NEVER_FLASHED;
803 
804  if( const PAD* pad = dyn_cast<const PAD*>( parentA ) )
805  {
806  if( !pad->GetRemoveUnconnected() || ( ( layer == F_Cu || layer == B_Cu ) && pad->GetKeepTopBottom() ) )
807  flashingA = FLASHING::ALWAYS_FLASHED;
808  }
809  else if( const PCB_VIA* via = dyn_cast<const PCB_VIA*>( parentA ) )
810  {
811  if( !via->GetRemoveUnconnected() || ( ( layer == F_Cu || layer == B_Cu ) && via->GetKeepTopBottom() ) )
812  flashingA = FLASHING::ALWAYS_FLASHED;
813  }
814 
815  if( const PAD* pad = dyn_cast<const PAD*>( parentB ) )
816  {
817  if( !pad->GetRemoveUnconnected() || ( ( layer == F_Cu || layer == B_Cu ) && pad->GetKeepTopBottom() ) )
818  flashingB = FLASHING::ALWAYS_FLASHED;
819  }
820  else if( const PCB_VIA* via = dyn_cast<const PCB_VIA*>( parentB ) )
821  {
822  if( !via->GetRemoveUnconnected() || ( ( layer == F_Cu || layer == B_Cu ) && via->GetKeepTopBottom() ) )
823  flashingB = FLASHING::ALWAYS_FLASHED;
824  }
825 
826  if( parentA->GetEffectiveShape( layer, flashingA )->Collide(
827  parentB->GetEffectiveShape( layer, flashingB ).get() ) )
828  {
829  m_item->Connect( aCandidate );
830  aCandidate->Connect( m_item );
831  return true;
832  }
833  }
834 
835  return true;
836 };
837 
838 
840 {
841  m_ratsnestClusters.clear();
842  m_connClusters.clear();
843  m_itemMap.clear();
844  m_itemList.Clear();
845 
846 }
847 
849 {
850  m_progressReporter = aReporter;
851 }
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
virtual void SetMaxProgress(int aMaxProgress)=0
Fix the value that gives the 100 percent progress bar length (inside the current virtual zone).
bool Remove(BOARD_ITEM *aItem)
void SetHasInvalid(bool aInvalid=true)
ZONES & Zones()
Definition: board.h:240
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:49
void checkZoneItemConnection(CN_ZONE_LAYER *aZoneLayer, CN_ITEM *aItem)
A progress reporter interface 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:289
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:637
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 thread-safe event counter.
Definition: profile.h:225
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
void SetDirty(bool aDirty=true)
virtual std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT) const
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
Definition: board_item.cpp:181
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:169
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)
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.
void markItemNetAsDirty(const BOARD_ITEM *aItem)
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:516
int GetMinThickness() const
Definition: zone.h:244
void propagateConnections(BOARD_COMMIT *aCommit=nullptr, PROPAGATE_MODE aMode=PROPAGATE_MODE::SKIP_CONFLICTS)
FOOTPRINTS & Footprints()
Definition: board.h:234
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)
Handle a list of polygons defining a copper zone.
Definition: zone.h:56
class ZONE, a copper pour area
Definition: typeinfo.h:105
int SubpolyIndex() const
void reportProgress(PROGRESS_REPORTER *aReporter, int aCount, int aSize, int aDelta)
FLASHING
Enum used during connectivity building to ensure we do not query connectivity while building the data...
Definition: layer_ids.h:153
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:191
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:65
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
CN_ITEM represents a BOARD_CONNETED_ITEM in the connectivity system (ie: a pad, track/arc/via,...
Definition: layer_ids.h:71
class NETINFO_ITEM, a description of a net
Definition: typeinfo.h:107
std::shared_ptr< CN_CLUSTER > CN_CLUSTER_PTR
virtual int Layer() const
Return the item's layer, for single-layered items only.
constexpr int delta
virtual bool IsConnected() const
Returns information if the object is derived from BOARD_CONNECTED_ITEM.
Definition: board_item.h:103
virtual bool KeepRefreshing(bool aWait=false)=0
Update the UI (if any).
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)
Definition: profile.h:255
virtual bool IsCancelled() const =0
Definition: pad.h:57
CN_ITEM * m_item
The item we are looking for connections to.
std::vector< CN_CLUSTER_PTR > CLUSTERS
TRACKS & Tracks()
Definition: board.h:231
virtual bool IsOnCopperLayer() const
Definition: board_item.h:111
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:148
bool Valid() const
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:112
BOARD_ITEM_CONTAINER * GetParentFootprint() const
Definition: board_item.cpp:191
bool GetFilledPolysUseThickness() const
Definition: zone.h:691
void SetProgressReporter(PROGRESS_REPORTER *aReporter)
PROGRESS_REPORTER * m_progressReporter
virtual void SetCurrentProgress(double aProgress)=0
Set the progress value to aProgress (0..1).