KiCad PCB EDA Suite
connectivity_data.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) 2017 CERN
5  * Copyright (C) 2018-2020 KiCad Developers, see AUTHORS.txt for contributors.
6  * @author Tomasz Wlostowski <[email protected]>
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 #ifdef PROFILE
27 #include <profile.h>
28 #endif
29 
30 #include <thread>
31 #include <algorithm>
32 #include <future>
33 
37 
38 #include <geometry/shape_segment.h>
39 #include <geometry/shape_circle.h>
40 #include <ratsnest/ratsnest_data.h>
41 #include <progress_reporter.h>
42 #include <trigo.h>
43 
45 {
46  m_connAlgo.reset( new CN_CONNECTIVITY_ALGO );
47  m_progressReporter = nullptr;
48  m_fromToCache.reset( new FROM_TO_CACHE );
49 }
50 
51 
52 CONNECTIVITY_DATA::CONNECTIVITY_DATA( const std::vector<BOARD_ITEM*>& aItems, bool aSkipRatsnest )
53  : m_skipRatsnest( aSkipRatsnest )
54 {
55  Build( aItems );
56  m_progressReporter = nullptr;
57  m_fromToCache.reset( new FROM_TO_CACHE );
58 }
59 
60 
62 {
63  Clear();
64 }
65 
66 
68 {
69  m_connAlgo->Add( aItem );
70  return true;
71 }
72 
73 
75 {
76  m_connAlgo->Remove( aItem );
77  return true;
78 }
79 
80 
82 {
83  m_connAlgo->Remove( aItem );
84  m_connAlgo->Add( aItem );
85  return true;
86 }
87 
88 
90 {
91  std::unique_lock<KISPINLOCK> lock( m_lock, std::try_to_lock );
92 
93  if( !lock )
94  return;
95 
96  m_connAlgo.reset( new CN_CONNECTIVITY_ALGO );
97  m_connAlgo->Build( aBoard, aReporter );
98 
99  m_netclassMap.clear();
100 
101  for( NETINFO_ITEM* net : aBoard->GetNetInfo() )
102  if( net->GetNetClass()->GetName() != NETCLASS::Default )
103  m_netclassMap[ net->GetNetCode() ] = net->GetNetClass()->GetName();
104 
105  if( aReporter )
106  {
107  aReporter->SetCurrentProgress( 0.75 );
108  aReporter->KeepRefreshing( false );
109  }
110 
112 
113  if( aReporter )
114  {
115  aReporter->SetCurrentProgress( 1.0 );
116  aReporter->KeepRefreshing( false );
117  }
118 }
119 
120 
121 void CONNECTIVITY_DATA::Build( const std::vector<BOARD_ITEM*>& aItems )
122 {
123  std::unique_lock<KISPINLOCK> lock( m_lock, std::try_to_lock );
124 
125  if( !lock )
126  return;
127 
128  m_connAlgo.reset( new CN_CONNECTIVITY_ALGO );
129  m_connAlgo->Build( aItems );
130 
132 }
133 
134 
135 void CONNECTIVITY_DATA::Move( const VECTOR2I& aDelta )
136 {
137  m_connAlgo->ForEachAnchor( [&aDelta]( CN_ANCHOR& anchor )
138  {
139  anchor.Move( aDelta );
140  } );
141 }
142 
143 
145 {
146 #ifdef PROFILE
147  PROF_COUNTER rnUpdate( "update-ratsnest" );
148 #endif
149 
150  std::vector<RN_NET*> dirty_nets;
151 
152  // Start with net 1 as net 0 is reserved for not-connected
153  // Nets without nodes are also ignored
154  std::copy_if( m_nets.begin() + 1, m_nets.end(), std::back_inserter( dirty_nets ),
155  [] ( RN_NET* aNet )
156  {
157  return aNet->IsDirty() && aNet->GetNodeCount() > 0;
158  } );
159 
160  // We don't want to spin up a new thread for fewer than 8 nets (overhead costs)
161  size_t parallelThreadCount = std::min<size_t>( std::thread::hardware_concurrency(),
162  ( dirty_nets.size() + 7 ) / 8 );
163 
164  std::atomic<size_t> nextNet( 0 );
165  std::vector<std::future<size_t>> returns( parallelThreadCount );
166 
167  auto update_lambda =
168  [&nextNet, &dirty_nets]() -> size_t
169  {
170  for( size_t i = nextNet++; i < dirty_nets.size(); i = nextNet++ )
171  dirty_nets[i]->Update();
172 
173  return 1;
174  };
175 
176  if( parallelThreadCount <= 1 )
177  {
178  update_lambda();
179  }
180  else
181  {
182  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
183  returns[ii] = std::async( std::launch::async, update_lambda );
184 
185  // Finalize the ratsnest threads
186  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
187  returns[ii].wait();
188  }
189 
190 #ifdef PROFILE
191  rnUpdate.Show();
192 #endif
193 }
194 
195 
196 void CONNECTIVITY_DATA::addRatsnestCluster( const std::shared_ptr<CN_CLUSTER>& aCluster )
197 {
198  RN_NET* rnNet = m_nets[ aCluster->OriginNet() ];
199 
200  rnNet->AddCluster( aCluster );
201 }
202 
203 
205 {
206  m_connAlgo->PropagateNets( aCommit );
207 
208  int lastNet = m_connAlgo->NetCount();
209 
210  if( lastNet >= (int) m_nets.size() )
211  {
212  unsigned int prevSize = m_nets.size();
213  m_nets.resize( lastNet + 1 );
214 
215  for( unsigned int i = prevSize; i < m_nets.size(); i++ )
216  m_nets[i] = new RN_NET;
217  }
218 
219  const std::vector<CN_CLUSTER_PTR>& clusters = m_connAlgo->GetClusters();
220 
221  int dirtyNets = 0;
222 
223  for( int net = 0; net < lastNet; net++ )
224  {
225  if( m_connAlgo->IsNetDirty( net ) )
226  {
227  m_nets[net]->Clear();
228  dirtyNets++;
229  }
230  }
231 
232  for( const CN_CLUSTER_PTR& c : clusters )
233  {
234  int net = c->OriginNet();
235 
236  // Don't add intentionally-kept zone islands to the ratsnest
237  if( c->IsOrphaned() && c->Size() == 1 )
238  {
239  if( dynamic_cast<CN_ZONE_LAYER*>( *c->begin() ) )
240  continue;
241  }
242 
243  if( m_connAlgo->IsNetDirty( net ) )
244  {
245  addRatsnestCluster( c );
246  }
247  }
248 
249  m_connAlgo->ClearDirtyFlags();
250 
251  if( !m_skipRatsnest )
252  updateRatsnest();
253 }
254 
255 
256 void CONNECTIVITY_DATA::BlockRatsnestItems( const std::vector<BOARD_ITEM*>& aItems )
257 {
258  std::vector<BOARD_CONNECTED_ITEM*> citems;
259 
260  for( BOARD_ITEM* item : aItems )
261  {
262  if( item->Type() == PCB_FOOTPRINT_T )
263  {
264  for( PAD* pad : static_cast<FOOTPRINT*>(item)->Pads() )
265  citems.push_back( pad );
266  }
267  else
268  {
269  if( BOARD_CONNECTED_ITEM* citem = dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) )
270  citems.push_back( citem );
271  }
272  }
273 
274  for( const BOARD_CONNECTED_ITEM* item : citems )
275  {
276  if ( m_connAlgo->ItemExists( item ) )
277  {
278  CN_CONNECTIVITY_ALGO::ITEM_MAP_ENTRY& entry = m_connAlgo->ItemEntry( item );
279 
280  for( CN_ITEM* cnItem : entry.GetItems() )
281  {
282  for( const std::shared_ptr<CN_ANCHOR>& anchor : cnItem->Anchors() )
283  anchor->SetNoLine( true );
284  }
285  }
286  }
287 }
288 
289 
291 {
292  return m_connAlgo->NetCount();
293 }
294 
295 
296 void CONNECTIVITY_DATA::FindIsolatedCopperIslands( ZONE* aZone, std::vector<int>& aIslands )
297 {
298  // TODO(JE) ZONES
299 #if 0
300  m_connAlgo->FindIsolatedCopperIslands( aZone, aIslands );
301 #endif
302 }
303 
304 void CONNECTIVITY_DATA::FindIsolatedCopperIslands( std::vector<CN_ZONE_ISOLATED_ISLAND_LIST>& aZones )
305 {
306  m_connAlgo->FindIsolatedCopperIslands( aZones );
307 }
308 
309 
310 void CONNECTIVITY_DATA::ComputeDynamicRatsnest( const std::vector<BOARD_ITEM*>& aItems,
311  const CONNECTIVITY_DATA* aDynamicData,
312  VECTOR2I aInternalOffset )
313 {
314  if( !aDynamicData )
315  return;
316 
317  m_dynamicRatsnest.clear();
318 
319  // This gets connections between the stationary board and the
320  // moving selection
321  for( unsigned int nc = 1; nc < aDynamicData->m_nets.size(); nc++ )
322  {
323  auto dynNet = aDynamicData->m_nets[nc];
324 
325  if( dynNet->GetNodeCount() != 0 )
326  {
327  RN_NET* ourNet = m_nets[nc];
328  CN_ANCHOR_PTR nodeA, nodeB;
329 
330  if( ourNet->NearestBicoloredPair( *dynNet, nodeA, nodeB ) )
331  {
332  RN_DYNAMIC_LINE l;
333  l.a = nodeA->Pos();
334  l.b = nodeB->Pos();
335  l.netCode = nc;
336 
337  m_dynamicRatsnest.push_back( l );
338  }
339  }
340  }
341 
342  // This gets the ratsnest for internal connections in the moving set
343  const std::vector<CN_EDGE>& edges = GetRatsnestForItems( aItems );
344 
345  for( const CN_EDGE& edge : edges )
346  {
347  const CN_ANCHOR_PTR& nodeA = edge.GetSourceNode();
348  const CN_ANCHOR_PTR& nodeB = edge.GetTargetNode();
349  RN_DYNAMIC_LINE l;
350 
351  // Use the parents' positions
352  l.a = nodeA->Parent()->GetPosition() + (wxPoint) aInternalOffset;
353  l.b = nodeB->Parent()->GetPosition() + (wxPoint) aInternalOffset;
354  l.netCode = 0;
355  m_dynamicRatsnest.push_back( l );
356  }
357 }
358 
359 
361 {
362  m_connAlgo->ForEachAnchor( []( CN_ANCHOR& anchor )
363  {
364  anchor.SetNoLine( false );
365  } );
367 }
368 
369 
371 {
372  m_dynamicRatsnest.clear();
373 }
374 
375 
377 {
378  m_connAlgo->PropagateNets( aCommit, aMode );
379 }
380 
381 
383  std::vector<KICAD_T> aTypes,
384  bool aCheckOptionalFlashing ) const
385 {
386  CN_CONNECTIVITY_ALGO::ITEM_MAP_ENTRY &entry = m_connAlgo->ItemEntry( aItem );
387 
388  auto matchType =
389  [&]( KICAD_T aItemType )
390  {
391  if( aTypes.empty() )
392  return true;
393 
394  return std::count( aTypes.begin(), aTypes.end(), aItemType ) > 0;
395  };
396 
397  for( CN_ITEM* citem : entry.GetItems() )
398  {
399  for( CN_ITEM* connected : citem->ConnectedItems() )
400  {
401  if( connected->Valid()
402  && connected->Layers().Overlaps( aLayer )
403  && matchType( connected->Parent()->Type() ) )
404  {
405  if( aCheckOptionalFlashing && aItem->Type() == PCB_PAD_T )
406  {
407  const PAD* pad = static_cast<const PAD*>( aItem );
408  SHAPE_SEGMENT hole( *pad->GetEffectiveHoleShape() );
409  PCB_LAYER_ID layer = ToLAYER_ID( aLayer );
410 
411  if( connected->Net() != aItem->GetNetCode() )
412  {
413  // Even if the nets aren't the same, we need to check for a physical
414  // connection with the unflashed pad's hole (as its walls are plated).
415  return connected->Parent()->GetEffectiveShape( layer )->Collide( &hole );
416  }
417  else if( CN_ZONE_LAYER* zoneLayer = dynamic_cast<CN_ZONE_LAYER*>( connected ) )
418  {
419  ZONE* zone = static_cast<ZONE*>( zoneLayer->Parent() );
420  int islandIdx = zoneLayer->SubpolyIndex();
421 
422  if( zone->IsFilled() )
423  {
424  const auto& fill = zone->GetFilledPolysList( layer );
425  const auto& padOutline = pad->GetEffectivePolygon()->Outline( 0 );
426 
427  for( const VECTOR2I& pt : fill.COutline( islandIdx ).CPoints() )
428  {
429  if( !padOutline.PointInside( pt ) )
430  return true;
431  }
432  }
433 
434  // If the zone isn't filled, or the entire island is inside the pad's
435  // flashing then the pad won't _actually_ connect to anything else.
436  return false;
437  }
438  }
439  else if( aCheckOptionalFlashing && aItem->Type() == PCB_VIA_T )
440  {
441  const PCB_VIA* via = static_cast<const PCB_VIA*>( aItem );
442  SHAPE_CIRCLE hole( via->GetCenter(), via->GetDrillValue() / 2 );
443  PCB_LAYER_ID layer = ToLAYER_ID( aLayer );
444 
445  if( connected->Net() != aItem->GetNetCode() )
446  {
447  // Even if the nets aren't the same, we need to check for a physical
448  // connection with the unflashed via's hole (as its walls are plated).
449  return connected->Parent()->GetEffectiveShape( layer )->Collide( &hole );
450  }
451  else if( CN_ZONE_LAYER* zoneLayer = dynamic_cast<CN_ZONE_LAYER*>( connected ) )
452  {
453  ZONE* zone = static_cast<ZONE*>( zoneLayer->Parent() );
454  int islandIdx = zoneLayer->SubpolyIndex();
455 
456  if( zone->IsFilled() )
457  {
458  const auto& fill = zone->GetFilledPolysList( layer );
459  SHAPE_CIRCLE viaCircle( via->GetCenter(), via->GetWidth() / 2 );
460 
461  for( const VECTOR2I& pt : fill.COutline( islandIdx ).CPoints() )
462  {
463  if( !viaCircle.SHAPE::Collide( pt ) )
464  return true;
465  }
466  }
467 
468  // If the zone isn't filled, or the entire island is inside the pad's
469  // flashing then the pad won't _actually_ connect to anything else.
470  return false;
471  }
472  }
473 
474  return connected->Net() == aItem->GetNetCode();
475  }
476  }
477  }
478 
479  return false;
480 }
481 
482 
484 {
485  unsigned int unconnected = 0;
486 
487  for( RN_NET* net : m_nets )
488  {
489  if( !net )
490  continue;
491 
492  const std::vector<CN_EDGE>& edges = net->GetUnconnected();
493 
494  if( edges.empty() )
495  continue;
496 
497  unconnected += edges.size();
498  }
499 
500  return unconnected;
501 }
502 
503 
505 {
506  for( RN_NET* net : m_nets )
507  delete net;
508 
509  m_nets.clear();
510 }
511 
512 
513 const std::vector<BOARD_CONNECTED_ITEM*> CONNECTIVITY_DATA::GetConnectedItems(
514  const BOARD_CONNECTED_ITEM* aItem,
515  const KICAD_T aTypes[],
516  bool aIgnoreNetcodes ) const
517 {
518  std::vector<BOARD_CONNECTED_ITEM*> rv;
519  const auto clusters = m_connAlgo->SearchClusters(
520  aIgnoreNetcodes ?
523  aIgnoreNetcodes ? -1 : aItem->GetNetCode() );
524 
525  for( auto cl : clusters )
526  {
527  if( cl->Contains( aItem ) )
528  {
529  for( const auto item : *cl )
530  {
531  if( item->Valid() )
532  rv.push_back( item->Parent() );
533  }
534  }
535  }
536 
537  return rv;
538 }
539 
540 
541 const std::vector<BOARD_CONNECTED_ITEM*> CONNECTIVITY_DATA::GetNetItems( int aNetCode,
542  const KICAD_T aTypes[] ) const
543 {
544  std::vector<BOARD_CONNECTED_ITEM*> items;
545  items.reserve( 32 );
546 
547  std::bitset<MAX_STRUCT_TYPE_ID> type_bits;
548 
549  for( unsigned int i = 0; aTypes[i] != EOT; ++i )
550  {
551  wxASSERT( aTypes[i] < MAX_STRUCT_TYPE_ID );
552  type_bits.set( aTypes[i] );
553  }
554 
555  m_connAlgo->ForEachItem( [&]( CN_ITEM& aItem ) {
556  if( aItem.Valid() && ( aItem.Net() == aNetCode ) && type_bits[aItem.Parent()->Type()] )
557  items.push_back( aItem.Parent() );
558  } );
559 
560  std::sort( items.begin(), items.end() );
561  items.erase( std::unique( items.begin(), items.end() ), items.end() );
562  return items;
563 }
564 
565 
566 bool CONNECTIVITY_DATA::CheckConnectivity( std::vector<CN_DISJOINT_NET_ENTRY>& aReport )
567 {
569 
570  for( auto net : m_nets )
571  {
572  if( net )
573  {
574  for( const auto& edge : net->GetEdges() )
575  {
577  ent.net = edge.GetSourceNode()->Parent()->GetNetCode();
578  ent.a = edge.GetSourceNode()->Parent();
579  ent.b = edge.GetTargetNode()->Parent();
580  ent.anchorA = edge.GetSourceNode()->Pos();
581  ent.anchorB = edge.GetTargetNode()->Pos();
582  aReport.push_back( ent );
583  }
584  }
585  }
586 
587  return aReport.empty();
588 }
589 
590 
591 const std::vector<PCB_TRACK*> CONNECTIVITY_DATA::GetConnectedTracks(
592  const BOARD_CONNECTED_ITEM* aItem ) const
593 {
594  auto& entry = m_connAlgo->ItemEntry( aItem );
595 
596  std::set<PCB_TRACK*> tracks;
597  std::vector<PCB_TRACK*> rv;
598 
599  for( CN_ITEM* citem : entry.GetItems() )
600  {
601  for( CN_ITEM* connected : citem->ConnectedItems() )
602  {
603  if( connected->Valid() &&
604  ( connected->Parent()->Type() == PCB_TRACE_T ||
605  connected->Parent()->Type() == PCB_VIA_T ||
606  connected->Parent()->Type() == PCB_ARC_T ) )
607  tracks.insert( static_cast<PCB_TRACK*> ( connected->Parent() ) );
608  }
609  }
610 
611  std::copy( tracks.begin(), tracks.end(), std::back_inserter( rv ) );
612  return rv;
613 }
614 
615 
617  std::set<PAD*>* pads ) const
618 {
619  for( CN_ITEM* citem : m_connAlgo->ItemEntry( aItem ).GetItems() )
620  {
621  for( CN_ITEM* connected : citem->ConnectedItems() )
622  {
623  if( connected->Valid() && connected->Parent()->Type() == PCB_PAD_T )
624  pads->insert( static_cast<PAD*> ( connected->Parent() ) );
625  }
626  }
627 }
628 
629 
630 const std::vector<PAD*> CONNECTIVITY_DATA::GetConnectedPads( const BOARD_CONNECTED_ITEM* aItem )
631 const
632 {
633  std::set<PAD*> pads;
634  std::vector<PAD*> rv;
635 
636  GetConnectedPads( aItem, &pads );
637 
638  std::copy( pads.begin(), pads.end(), std::back_inserter( rv ) );
639  return rv;
640 }
641 
642 
643 unsigned int CONNECTIVITY_DATA::GetNodeCount( int aNet ) const
644 {
645  int sum = 0;
646 
647  if( aNet < 0 ) // Node count for all nets
648  {
649  for( const RN_NET* net : m_nets )
650  sum += net->GetNodeCount();
651  }
652  else if( aNet < (int) m_nets.size() )
653  {
654  sum = m_nets[aNet]->GetNodeCount();
655  }
656 
657  return sum;
658 }
659 
660 
661 unsigned int CONNECTIVITY_DATA::GetPadCount( int aNet ) const
662 {
663  int n = 0;
664 
665  for( CN_ITEM* pad : m_connAlgo->ItemList() )
666  {
667  if( !pad->Valid() || pad->Parent()->Type() != PCB_PAD_T)
668  continue;
669 
670  PAD* dpad = static_cast<PAD*>( pad->Parent() );
671 
672  if( aNet < 0 || aNet == dpad->GetNetCode() )
673  n++;
674  }
675 
676  return n;
677 }
678 
679 
680 void CONNECTIVITY_DATA::GetUnconnectedEdges( std::vector<CN_EDGE>& aEdges) const
681 {
682  for( const RN_NET* rnNet : m_nets )
683  {
684  if( rnNet )
685  {
686  for( const CN_EDGE& edge : rnNet->GetEdges() )
687  aEdges.push_back( edge );
688  }
689  }
690 }
691 
692 
693 static int getMinDist( BOARD_CONNECTED_ITEM* aItem, const wxPoint& aPoint )
694 {
695  switch( aItem->Type() )
696  {
697  case PCB_TRACE_T:
698  case PCB_ARC_T:
699  {
700  PCB_TRACK* track = static_cast<PCB_TRACK*>( aItem );
701 
702  return std::min( GetLineLength( track->GetStart(), aPoint ),
703  GetLineLength( track->GetEnd(), aPoint ) );
704  }
705 
706  default:
707  return GetLineLength( aItem->GetPosition(), aPoint );
708  }
709 }
710 
711 
713 {
714  std::list<CN_ITEM*> items = GetConnectivityAlgo()->ItemEntry( aTrack ).GetItems();
715 
716  // Not in the connectivity system. This is a bug!
717  if( items.empty() )
718  {
719  wxFAIL_MSG( wxT( "track not in connectivity system" ) );
720  return false;
721  }
722 
723  CN_ITEM* citem = items.front();
724 
725  if( !citem->Valid() )
726  return false;
727 
728  if( aTrack->Type() == PCB_TRACE_T || aTrack->Type() == PCB_ARC_T )
729  {
730  // Test if a segment is connected on each end.
731  //
732  // NB: be wary of short segments which can be connected to the *same* other item on
733  // each end. If that's their only connection then they're still dangling.
734 
735  PCB_LAYER_ID layer = aTrack->GetLayer();
736  int accuracy = KiROUND( aTrack->GetWidth() / 2 );
737  int start_count = 0;
738  int end_count = 0;
739 
740  for( CN_ITEM* connected : citem->ConnectedItems() )
741  {
742  BOARD_CONNECTED_ITEM* item = connected->Parent();
743 
744  if( item->GetFlags() & IS_DELETED )
745  continue;
746 
747  std::shared_ptr<SHAPE> shape = item->GetEffectiveShape( layer );
748 
749  bool hitStart = shape->Collide( aTrack->GetStart(), accuracy );
750  bool hitEnd = shape->Collide( aTrack->GetEnd(), accuracy );
751 
752  if( hitStart && hitEnd )
753  {
754  if( getMinDist( item, aTrack->GetStart() ) < getMinDist( item, aTrack->GetEnd() ) )
755  start_count++;
756  else
757  end_count++;
758  }
759  else if( hitStart )
760  {
761  start_count++;
762  }
763  else if( hitEnd )
764  {
765  end_count++;
766  }
767 
768  if( start_count > 0 && end_count > 0 )
769  return false;
770  }
771 
772  if( aPos )
773  *aPos = (start_count == 0 ) ? aTrack->GetStart() : aTrack->GetEnd();
774 
775  return true;
776  }
777  else if( aTrack->Type() == PCB_VIA_T )
778  {
779  // Test if a via is only connected on one layer
780 
781  const std::vector<CN_ITEM*>& connected = citem->ConnectedItems();
782 
783  if( connected.empty() )
784  {
785  if( aPos )
786  *aPos = aTrack->GetPosition();
787 
788  return true;
789  }
790 
791  // Here, we check if the via is connected only to items on a single layer
792  int first_layer = UNDEFINED_LAYER;
793 
794  for( CN_ITEM* item : connected )
795  {
796  if( item->Parent()->GetFlags() & IS_DELETED )
797  continue;
798 
799  if( first_layer == UNDEFINED_LAYER )
800  first_layer = item->Layer();
801  else if( item->Layer() != first_layer )
802  return false;
803  }
804 
805  if( aPos )
806  *aPos = aTrack->GetPosition();
807 
808  return true;
809  }
810  else
811  {
812  wxFAIL_MSG( wxT( "CONNECTIVITY_DATA::TestTrackEndpointDangling: unknown track type" ) );
813  }
814 
815  return false;
816 }
817 
818 
819 const std::vector<BOARD_CONNECTED_ITEM*> CONNECTIVITY_DATA::GetConnectedItemsAtAnchor(
820  const BOARD_CONNECTED_ITEM* aItem,
821  const VECTOR2I& aAnchor,
822  const KICAD_T aTypes[],
823  const int& aMaxError ) const
824 {
825  auto& entry = m_connAlgo->ItemEntry( aItem );
826  std::vector<BOARD_CONNECTED_ITEM*> rv;
827  SEG::ecoord maxErrorSq = (SEG::ecoord) aMaxError * aMaxError;
828 
829  for( auto cnItem : entry.GetItems() )
830  {
831  for( auto connected : cnItem->ConnectedItems() )
832  {
833  for( auto anchor : connected->Anchors() )
834  {
835  if( ( anchor->Pos() - aAnchor ).SquaredEuclideanNorm() <= maxErrorSq )
836  {
837  for( int i = 0; aTypes[i] > 0; i++ )
838  {
839  if( connected->Valid() && connected->Parent()->Type() == aTypes[i] )
840  {
841  rv.push_back( connected->Parent() );
842  break;
843  }
844  }
845 
846  break;
847  }
848  }
849  }
850  }
851 
852  return rv;
853 }
854 
855 
857 {
858  if ( aNet < 0 || aNet >= (int) m_nets.size() )
859  {
860  return nullptr;
861  }
862 
863  return m_nets[ aNet ];
864 }
865 
866 
868 {
869  if ( aItem->Type() == PCB_FOOTPRINT_T)
870  {
871  for( PAD* pad : static_cast<FOOTPRINT*>( aItem )->Pads() )
872  m_connAlgo->MarkNetAsDirty( pad->GetNetCode() );
873  }
874  if (aItem->IsConnected() )
875  {
876  m_connAlgo->MarkNetAsDirty( static_cast<BOARD_CONNECTED_ITEM*>( aItem )->GetNetCode() );
877  }
878 }
879 
880 
882 {
883  m_progressReporter = aReporter;
884  m_connAlgo->SetProgressReporter( m_progressReporter );
885 }
886 
887 
888 const std::vector<CN_EDGE> CONNECTIVITY_DATA::GetRatsnestForItems( std::vector<BOARD_ITEM*> aItems )
889 {
890  std::set<int> nets;
891  std::vector<CN_EDGE> edges;
892  std::set<BOARD_CONNECTED_ITEM*> item_set;
893 
894  for( BOARD_ITEM* item : aItems )
895  {
896  if( item->Type() == PCB_FOOTPRINT_T )
897  {
898  FOOTPRINT* footprint = static_cast<FOOTPRINT*>( item );
899 
900  for( PAD* pad : footprint->Pads() )
901  {
902  nets.insert( pad->GetNetCode() );
903  item_set.insert( pad );
904  }
905  }
906  else if( auto conn_item = dyn_cast<BOARD_CONNECTED_ITEM*>( item ) )
907  {
908  item_set.insert( conn_item );
909  nets.insert( conn_item->GetNetCode() );
910  }
911  }
912 
913  for( int netcode : nets )
914  {
915  RN_NET* net = GetRatsnestForNet( netcode );
916 
917  for( const CN_EDGE& edge : net->GetEdges() )
918  {
919  std::shared_ptr<CN_ANCHOR> srcNode = edge.GetSourceNode();
920  std::shared_ptr<CN_ANCHOR> dstNode = edge.GetTargetNode();
921 
922  BOARD_CONNECTED_ITEM* srcParent = srcNode->Parent();
923  BOARD_CONNECTED_ITEM* dstParent = dstNode->Parent();
924 
925  bool srcFound = ( item_set.find( srcParent ) != item_set.end() );
926  bool dstFound = ( item_set.find( dstParent ) != item_set.end() );
927 
928  if ( srcFound && dstFound )
929  edges.push_back( edge );
930  }
931  }
932 
933  return edges;
934 }
935 
936 
937 const std::vector<CN_EDGE> CONNECTIVITY_DATA::GetRatsnestForPad( const PAD* aPad )
938 {
939  std::vector<CN_EDGE> edges;
940  RN_NET* net = GetRatsnestForNet( aPad->GetNetCode() );
941 
942  for( const CN_EDGE& edge : net->GetEdges() )
943  {
944  if( edge.GetSourceNode()->Parent() == aPad || edge.GetTargetNode()->Parent() == aPad )
945  edges.push_back( edge );
946  }
947 
948  return edges;
949 }
950 
951 
952 const std::vector<CN_EDGE> CONNECTIVITY_DATA::GetRatsnestForComponent( FOOTPRINT* aComponent, bool aSkipInternalConnections )
953 {
954  std::set<int> nets;
955  std::set<const PAD*> pads;
956  std::vector<CN_EDGE> edges;
957 
958  for( auto pad : aComponent->Pads() )
959  {
960  nets.insert( pad->GetNetCode() );
961  pads.insert( pad );
962  }
963 
964  for( const auto& netcode : nets )
965  {
966  const auto& net = GetRatsnestForNet( netcode );
967 
968  for( const auto& edge : net->GetEdges() )
969  {
970  auto srcNode = edge.GetSourceNode();
971  auto dstNode = edge.GetTargetNode();
972 
973  const PAD* srcParent = static_cast<const PAD*>( srcNode->Parent() );
974  const PAD* dstParent = static_cast<const PAD*>( dstNode->Parent() );
975 
976  bool srcFound = ( pads.find(srcParent) != pads.end() );
977  bool dstFound = ( pads.find(dstParent) != pads.end() );
978 
979  if ( srcFound && dstFound && !aSkipInternalConnections )
980  {
981  edges.push_back( edge );
982  }
983  else if ( srcFound || dstFound )
984  {
985  edges.push_back( edge );
986  }
987  }
988  }
989 
990  return edges;
991 }
992 
993 
bool IsConnectedOnLayer(const BOARD_CONNECTED_ITEM *aItem, int aLayer, std::vector< KICAD_T > aTypes={}, bool aCheckOptionalFlashing=false) const
const CONNECTED_ITEMS & ConnectedItems() const
void Clear()
Function Clear() Erases the connectivity database.
const std::vector< CN_EDGE > GetRatsnestForComponent(FOOTPRINT *aComponent, bool aSkipInternalConnections=false)
unsigned int GetNodeCount(int aNet=-1) const
double GetLineLength(const wxPoint &aPointA, const wxPoint &aPointB)
Return the length of a line segment defined by aPointA and aPointB.
Definition: trigo.h:222
PROPAGATE_MODE
Controls how nets are propagated through clusters.
const std::vector< PCB_TRACK * > GetConnectedTracks(const BOARD_CONNECTED_ITEM *aItem) const
wxPoint GetPosition() const override
Definition: pcb_track.h:98
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
A progress reporter interface for use in multi-threaded environments.
std::shared_ptr< CN_CONNECTIVITY_ALGO > m_connAlgo
Class that computes missing connections on a PCB.
PROGRESS_REPORTER * m_progressReporter
const std::list< CN_ITEM * > GetItems() const
VECTOR2I::extended_type ecoord
Definition: seg.h:43
std::shared_ptr< CN_CONNECTIVITY_ALGO > GetConnectivityAlgo() const
bool Update(BOARD_ITEM *aItem)
Function Update() Updates the connectivity data for an item.
const std::vector< BOARD_CONNECTED_ITEM * > GetNetItems(int aNetCode, const KICAD_T aTypes[]) const
Function GetNetItems() Returns the list of items that belong to a certain net.
void RecalculateRatsnest(BOARD_COMMIT *aCommit=nullptr)
Function RecalculateRatsnest() Updates the ratsnest for the board.
std::shared_ptr< FROM_TO_CACHE > m_fromToCache
class PCB_ARC, an arc track segment on a copper layer
Definition: typeinfo.h:97
void PropagateNets(BOARD_COMMIT *aCommit=nullptr, PROPAGATE_MODE aMode=PROPAGATE_MODE::SKIP_CONFLICTS)
Propagates the net codes from the source pads to the tracks/vias.
const NETINFO_LIST & GetNetInfo() const
Definition: board.h:680
class PAD, a pad in a footprint
Definition: typeinfo.h:89
const SHAPE_POLY_SET & GetFilledPolysList(PCB_LAYER_ID aLayer) const
Definition: zone.h:637
int GetWidth() const
Definition: pcb_track.h:102
bool IsFilled() const
Definition: zone.h:234
BOARD_CONNECTED_ITEM * Parent() const
virtual wxPoint GetPosition() const
Definition: eda_item.h:251
CN_ANCHOR represents a physical location that can be connected: a pad or a track/arc/via endpoint.
A thread-safe event counter.
Definition: profile.h:225
BOARD_CONNECTED_ITEM * b
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
std::vector< RN_DYNAMIC_LINE > m_dynamicRatsnest
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
void ComputeDynamicRatsnest(const std::vector< BOARD_ITEM * > &aItems, const CONNECTIVITY_DATA *aDynamicData, VECTOR2I aInternalOffset={ 0, 0 })
Function ComputeDynamicRatsnest() Calculates the temporary dynamic ratsnest (i.e.
VECTOR2I anchorB
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
class PCB_TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:95
PADS & Pads()
Definition: footprint.h:169
unsigned int GetPadCount(int aNet=-1) const
void Build(BOARD *aBoard, PROGRESS_REPORTER *aReporter=nullptr)
Function Build() Builds the connectivity database for the board aBoard.
#define IS_DELETED
VECTOR2I anchorA
const std::vector< BOARD_CONNECTED_ITEM * > GetConnectedItemsAtAnchor(const BOARD_CONNECTED_ITEM *aItem, const VECTOR2I &aAnchor, const KICAD_T aTypes[], const int &aMaxError=0) const
Function GetConnectedItemsAtAnchor() Returns a list of items connected to a source item aItem at posi...
static const char Default[]
the name of the default NETCLASS
Definition: netclass.h:49
const std::vector< BOARD_CONNECTED_ITEM * > GetConnectedItems(const BOARD_CONNECTED_ITEM *aItem, const KICAD_T aTypes[], bool aIgnoreNetcodes=false) const
Function GetConnectedItems() Returns a list of items connected to a source item aItem.
std::map< int, wxString > m_netclassMap
Map of netcode -> netclass the net is a member of; used for ratsnest painting.
unsigned int GetUnconnectedCount() const
Function GetUnconnectedCount() Returns the number of remaining edges in the ratsnest.
Handle a list of polygons defining a copper zone.
Definition: zone.h:56
void ClearDynamicRatsnest()
Function ClearDynamicRatsnest() Erases the temporary dynamic ratsnest (i.e.
void SetProgressReporter(PROGRESS_REPORTER *aReporter)
bool Remove(BOARD_ITEM *aItem)
Function Remove() Removes an item from the connectivity data.
void MarkItemNetAsDirty(BOARD_ITEM *aItem)
const std::vector< CN_EDGE > & GetEdges() const
static int getMinDist(BOARD_CONNECTED_ITEM *aItem, const wxPoint &aPoint)
std::vector< RN_NET * > m_nets
EDA_ITEM_FLAGS GetFlags() const
Definition: eda_item.h:154
bool NearestBicoloredPair(const RN_NET &aOtherNet, CN_ANCHOR_PTR &aNode1, CN_ANCHOR_PTR &aNode2) const
class FOOTPRINT, a footprint
Definition: typeinfo.h:88
void GetUnconnectedEdges(std::vector< CN_EDGE > &aEdges) const
bool Add(BOARD_ITEM *aItem)
Function Add() Adds an item to the connectivity data.
void BlockRatsnestItems(const std::vector< BOARD_ITEM * > &aItems)
void AddCluster(std::shared_ptr< CN_CLUSTER > aCluster)
RN_NET * GetRatsnestForNet(int aNet)
Function GetRatsnestForNet() Returns the ratsnest, expressed as a set of graph edges for a given net.
BOARD_CONNECTED_ITEM * a
Handle the data for a net.
Definition: netinfo.h:66
const std::vector< CN_EDGE > GetRatsnestForPad(const PAD *aPad)
bool CheckConnectivity(std::vector< CN_DISJOINT_NET_ENTRY > &aReport)
CN_EDGE represents a point-to-point connection, whether realized or unrealized (ie: tracks etc.
void FindIsolatedCopperIslands(ZONE *aZone, std::vector< int > &aIslands)
Function FindIsolatedCopperIslands() Searches for copper islands in zone aZone that are not connected...
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:191
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:65
CN_ITEM represents a BOARD_CONNETED_ITEM in the connectivity system (ie: a pad, track/arc/via,...
std::shared_ptr< CN_CLUSTER > CN_CLUSTER_PTR
std::shared_ptr< CN_ANCHOR > CN_ANCHOR_PTR
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:73
int net
int GetNetCount() const
Function GetNetCount() Returns the total number of nets in the connectivity database.
bool TestTrackEndpointDangling(PCB_TRACK *aTrack, wxPoint *aPos=nullptr)
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).
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:96
Describe ratsnest for a single net.
Definition: ratsnest_data.h:61
void Show(std::ostream &aStream=std::cerr)
Definition: profile.h:255
const std::vector< PAD * > GetConnectedPads(const BOARD_CONNECTED_ITEM *aItem) const
Definition: pad.h:57
void HideDynamicRatsnest()
Hides the temporary dynamic ratsnest lines.
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:143
void addRatsnestCluster(const std::shared_ptr< CN_CLUSTER > &aCluster)
PCB_LAYER_ID ToLAYER_ID(int aLayer)
Definition: lset.cpp:914
void Move(const VECTOR2I &aDelta)
Moves the connectivity list anchors.
const wxPoint & GetStart() const
Definition: pcb_track.h:108
const std::vector< CN_EDGE > GetRatsnestForItems(const std::vector< BOARD_ITEM * > aItems)
bool Valid() const
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:112
virtual void SetCurrentProgress(double aProgress)=0
Set the progress value to aProgress (0..1).
bool m_skipRatsnest
Used to suppress ratsnest calculations on dynamic ratsnests.