KiCad PCB EDA Suite
board_netlist_updater.cpp
Go to the documentation of this file.
1 
6 /*
7  * This program source code file is part of KiCad, a free EDA CAD application.
8  *
9  * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
10  * Copyright (C) 2015 CERN
11  * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
12  * Copyright (C) 2011 Wayne Stambaugh <stambaughw@verizon.net>
13  *
14  * Copyright (C) 1992-2019 KiCad Developers, see AUTHORS.txt for contributors.
15  *
16  * This program is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU General Public License
18  * as published by the Free Software Foundation; either version 2
19  * of the License, or (at your option) any later version.
20  *
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24  * GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License
27  * along with this program; if not, you may find one here:
28  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
29  * or you may search the http://www.gnu.org website for the version 2 license,
30  * or you may write to the Free Software Foundation, Inc.,
31  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
32  */
33 
34 
35 #include <common.h> // for PAGE_INFO
36 
37 #include <board.h>
38 #include <netinfo.h>
39 #include <footprint.h>
40 #include <pad.h>
41 #include <track.h>
42 #include <zone.h>
43 #include <kicad_string.h>
44 #include <pcbnew_settings.h>
45 #include <pcb_edit_frame.h>
48 #include <reporter.h>
49 
50 #include "board_netlist_updater.h"
51 
52 
54  m_frame( aFrame ),
55  m_commit( aFrame ),
56  m_board( aBoard )
57 {
59 
60  m_deleteSinglePadNets = true;
62  m_isDryRun = false;
63  m_replaceFootprints = true;
64  m_lookupByTimestamp = false;
65  m_warnForNoNetPads = false;
66 
67  m_warningCount = 0;
68  m_errorCount = 0;
70 }
71 
72 
74 {
75 }
76 
77 
78 // These functions allow inspection of pad nets during dry runs by keeping a cache of
79 // current pad netnames indexed by pad.
80 
81 void BOARD_NETLIST_UPDATER::cacheNetname( PAD* aPad, const wxString& aNetname )
82 {
83  m_padNets[ aPad ] = aNetname;
84 }
85 
86 
88 {
89  if( m_isDryRun && m_padNets.count( aPad ) )
90  return m_padNets[ aPad ];
91  else
92  return aPad->GetNetname();
93 }
94 
95 
96 void BOARD_NETLIST_UPDATER::cachePinFunction( PAD* aPad, const wxString& aPinFunction )
97 {
98  m_padPinFunctions[ aPad ] = aPinFunction;
99 }
100 
101 
103 {
104  if( m_isDryRun && m_padPinFunctions.count( aPad ) )
105  return m_padPinFunctions[ aPad ];
106  else
107  return aPad->GetPinFunction();
108 }
109 
110 
112 {
113  wxPoint bestPosition;
114 
115  if( !m_board->IsEmpty() )
116  {
117  // Position new components below any existing board features.
119 
120  if( bbox.GetWidth() || bbox.GetHeight() )
121  {
122  bestPosition.x = bbox.Centre().x;
123  bestPosition.y = bbox.GetBottom() + Millimeter2iu( 10 );
124  }
125  }
126  else
127  {
128  // Position new components in the center of the page when the board is empty.
129  wxSize pageSize = m_board->GetPageSettings().GetSizeIU();
130 
131  bestPosition.x = pageSize.GetWidth() / 2;
132  bestPosition.y = pageSize.GetHeight() / 2;
133  }
134 
135  return bestPosition;
136 }
137 
138 
140 {
141  wxString msg;
142 
143  if( aComponent->GetFPID().empty() )
144  {
145  msg.Printf( _( "Cannot add %s (no footprint assigned)." ),
146  aComponent->GetReference(),
147  aComponent->GetFPID().Format().wx_str() );
149  ++m_errorCount;
150  return nullptr;
151  }
152 
153  FOOTPRINT* footprint = m_frame->LoadFootprint( aComponent->GetFPID() );
154 
155  if( footprint == nullptr )
156  {
157  msg.Printf( _( "Cannot add %s (footprint \"%s\" not found)." ),
158  aComponent->GetReference(),
159  aComponent->GetFPID().Format().wx_str() );
161  ++m_errorCount;
162  return nullptr;
163  }
164 
165  msg.Printf( _( "Add %s (footprint \"%s\")." ),
166  aComponent->GetReference(),
167  aComponent->GetFPID().Format().wx_str() );
169 
170  for( PAD* pad : footprint->Pads() )
171  {
172  // Set the pads ratsnest settings to the global settings
173  pad->SetLocalRatsnestVisible( m_frame->GetDisplayOptions().m_ShowGlobalRatsnest );
174  pad->SetLocked( !m_frame->Settings().m_AddUnlockedPads );
175 
176  // Pads in the library all have orphaned nets. Replace with Default.
177  pad->SetNetCode( 0 );
178  }
179 
181 
182  if( !m_isDryRun )
183  {
184  footprint->SetParent( m_board );
186 
187  m_addedComponents.push_back( footprint );
188  m_commit.Add( footprint );
189 
190  return footprint;
191  }
192  else
193  {
194  delete footprint;
195  }
196 
197  return NULL;
198 }
199 
200 
202  COMPONENT* aNewComponent )
203 {
204  wxString msg;
205 
206  if( aNewComponent->GetFPID().empty() )
207  {
208  msg.Printf( _( "Cannot update %s (no footprint assigned)." ),
209  aNewComponent->GetReference(),
210  aNewComponent->GetFPID().Format().wx_str() );
212  ++m_errorCount;
213  return nullptr;
214  }
215 
216  FOOTPRINT* newFootprint = m_frame->LoadFootprint( aNewComponent->GetFPID() );
217 
218  if( newFootprint == nullptr )
219  {
220  msg.Printf( _( "Cannot update %s (footprint \"%s\" not found)." ),
221  aNewComponent->GetReference(),
222  aNewComponent->GetFPID().Format().wx_str() );
224  ++m_errorCount;
225  return nullptr;
226  }
227 
228  msg.Printf( _( "Change %s footprint from \"%s\" to \"%s\"."),
229  aPcbComponent->GetReference(),
230  aPcbComponent->GetFPID().Format().wx_str(),
231  aNewComponent->GetFPID().Format().wx_str() );
233 
235 
236  if( !m_isDryRun )
237  {
238  m_frame->ExchangeFootprint( aPcbComponent, newFootprint, m_commit );
239  return newFootprint;
240  }
241  else
242  {
243  delete newFootprint;
244  }
245 
246  return nullptr;
247 }
248 
249 
251  COMPONENT* aNetlistComponent )
252 {
253  wxString msg;
254 
255  // Create a copy only if the footprint has not been added during this update
256  FOOTPRINT* copy = m_commit.GetStatus( aPcbFootprint ) ? nullptr
257  : (FOOTPRINT*) aPcbFootprint->Clone();
258  bool changed = false;
259 
260  // Test for reference designator field change.
261  if( aPcbFootprint->GetReference() != aNetlistComponent->GetReference() )
262  {
263  msg.Printf( _( "Change %s reference designator to %s." ),
264  aPcbFootprint->GetReference(),
265  aNetlistComponent->GetReference() );
267 
268  if ( !m_isDryRun )
269  {
270  changed = true;
271  aPcbFootprint->SetReference( aNetlistComponent->GetReference() );
272  }
273  }
274 
275  // Test for value field change.
276  if( aPcbFootprint->GetValue() != aNetlistComponent->GetValue() )
277  {
278  msg.Printf( _( "Change %s value from %s to %s." ),
279  aPcbFootprint->GetReference(),
280  aPcbFootprint->GetValue(),
281  aNetlistComponent->GetValue() );
283 
284  if( !m_isDryRun )
285  {
286  changed = true;
287  aPcbFootprint->SetValue( aNetlistComponent->GetValue() );
288  }
289  }
290 
291  // Test for time stamp change.
292  KIID_PATH new_path = aNetlistComponent->GetPath();
293  new_path.push_back( aNetlistComponent->GetKIIDs().front() );
294 
295  if( aPcbFootprint->GetPath() != new_path )
296  {
297  msg.Printf( _( "Update %s symbol association from %s to %s." ),
298  aPcbFootprint->GetReference(),
299  aPcbFootprint->GetPath().AsString(),
300  new_path.AsString() );
302 
303  if( !m_isDryRun )
304  {
305  changed = true;
306  aPcbFootprint->SetPath( new_path );
307  }
308  }
309 
310  if( aPcbFootprint->GetProperties() != aNetlistComponent->GetProperties() )
311  {
312  msg.Printf( _( "Update %s properties." ),
313  aPcbFootprint->GetReference() );
315 
316  if( !m_isDryRun )
317  {
318  changed = true;
319  aPcbFootprint->SetProperties( aNetlistComponent->GetProperties() );
320  }
321  }
322 
323  if( ( aNetlistComponent->GetProperties().count( "exclude_from_bom" ) > 0 )
324  != ( ( aPcbFootprint->GetAttributes() & FP_EXCLUDE_FROM_BOM ) > 0 ) )
325  {
326  int attributes = aPcbFootprint->GetAttributes();
327 
328  if( aNetlistComponent->GetProperties().count( "exclude_from_bom" ) )
329  {
330  attributes |= FP_EXCLUDE_FROM_BOM;
331  msg.Printf( _( "Setting %s 'exclude from BOM' fabrication attribute." ),
332  aPcbFootprint->GetReference() );
333  }
334  else
335  {
336  attributes &= ~FP_EXCLUDE_FROM_BOM;
337  msg.Printf( _( "Removing %s 'exclude from BOM' fabrication attribute." ),
338  aPcbFootprint->GetReference() );
339  }
340 
342 
343  if( !m_isDryRun )
344  {
345  changed = true;
346  aPcbFootprint->SetAttributes( attributes );
347  }
348  }
349 
350  if( changed && copy )
351  m_commit.Modified( aPcbFootprint, copy );
352  else
353  delete copy;
354 
355  return true;
356 }
357 
358 
360  COMPONENT* aNewComponent )
361 {
362  wxString msg;
363 
364  // Create a copy only if the footprint has not been added during this update
365  FOOTPRINT* copy = m_commit.GetStatus( aFootprint ) ? nullptr : (FOOTPRINT*) aFootprint->Clone();
366  bool changed = false;
367 
368  // At this point, the component footprint is updated. Now update the nets.
369  for( PAD* pad : aFootprint->Pads() )
370  {
371  const COMPONENT_NET& net = aNewComponent->GetNet( pad->GetName() );
372 
373  wxString pinFunction;
374  wxString pinType;
375 
376  if( net.IsValid() ) // i.e. the pad has a name
377  {
378  pinFunction = net.GetPinFunction();
379  pinType = net.GetPinType();
380  }
381 
382  if( !m_isDryRun )
383  {
384  if( pad->GetPinFunction() != pinFunction )
385  {
386  changed = true;
387  pad->SetPinFunction( pinFunction );
388  }
389 
390  if( pad->GetPinType() != pinType )
391  {
392  changed = true;
393  pad->SetPinType( pinType );
394  }
395  }
396  else
397  cachePinFunction( pad, pinFunction );
398 
399  // Test if new footprint pad has no net (pads not on copper layers have no net).
400  if( !net.IsValid() || !pad->IsOnCopperLayer() )
401  {
402  if( !pad->GetNetname().IsEmpty() )
403  {
404  msg.Printf( _( "Disconnect %s pin %s." ),
405  aFootprint->GetReference(),
406  pad->GetName() );
408  }
409  else if( m_warnForNoNetPads && pad->IsOnCopperLayer() && !pad->GetName().IsEmpty() )
410  {
411  // pad is connectable but has no net found in netlist
412  msg.Printf( _( "No net for symbol %s pin %s." ),
413  aFootprint->GetReference(),
414  pad->GetName() );
416  }
417 
418  if( !m_isDryRun )
419  {
420  changed = true;
421  pad->SetNetCode( NETINFO_LIST::UNCONNECTED );
422 
423  // If the pad has no net from netlist (i.e. not in netlist
424  // it cannot have a pin function
425  if( pad->GetNetname().IsEmpty() )
426  pad->SetPinFunction( wxEmptyString );
427 
428  }
429  else
430  cacheNetname( pad, wxEmptyString );
431  }
432  else // New footprint pad has a net.
433  {
434  const wxString& netName = net.GetNetName();
435  NETINFO_ITEM* netinfo = m_board->FindNet( netName );
436 
437  if( netinfo && !m_isDryRun )
438  netinfo->SetIsCurrent( true );
439 
440  if( pad->GetNetname() != netName )
441  {
442 
443  if( netinfo == nullptr )
444  {
445  // It might be a new net that has not been added to the board yet
446  if( m_addedNets.count( netName ) )
447  netinfo = m_addedNets[ netName ];
448  }
449 
450  if( netinfo == nullptr )
451  {
452  netinfo = new NETINFO_ITEM( m_board, netName );
453 
454  // It is a new net, we have to add it
455  if( !m_isDryRun )
456  {
457  changed = true;
458  m_commit.Add( netinfo );
459  }
460 
461  m_addedNets[netName] = netinfo;
462  msg.Printf( _( "Add net %s." ), UnescapeString( netName ) );
464  }
465 
466  if( !pad->GetNetname().IsEmpty() )
467  {
468  m_oldToNewNets[ pad->GetNetname() ] = netName;
469 
470  msg.Printf( _( "Reconnect %s pin %s from %s to %s."),
471  aFootprint->GetReference(),
472  pad->GetName(),
473  UnescapeString( pad->GetNetname() ),
474  UnescapeString( netName ) );
475  }
476  else
477  {
478  msg.Printf( _( "Connect %s pin %s to %s."),
479  aFootprint->GetReference(),
480  pad->GetName(),
481  UnescapeString( netName ) );
482  }
484 
485  if( !m_isDryRun )
486  {
487  changed = true;
488  pad->SetNet( netinfo );
489  }
490  else
491  cacheNetname( pad, netName );
492  }
493  }
494  }
495 
496  if( changed && copy )
497  m_commit.Modified( aFootprint, copy );
498  else
499  delete copy;
500 
501  return true;
502 }
503 
504 
506 {
507  for( ZONE* zone : m_board->Zones() )
508  {
509  if( !zone->IsOnCopperLayer() || zone->GetIsRuleArea() )
510  continue;
511 
512  m_zoneConnectionsCache[ zone ] = m_board->GetConnectivity()->GetConnectedPads( zone );
513  }
514 }
515 
516 
518 {
519  wxString msg;
520  std::set<wxString> netlistNetnames;
521 
522  for( int ii = 0; ii < (int) aNetlist.GetCount(); ii++ )
523  {
524  const COMPONENT* component = aNetlist.GetComponent( ii );
525  for( unsigned jj = 0; jj < component->GetNetCount(); jj++ )
526  {
527  const COMPONENT_NET& net = component->GetNet( jj );
528  netlistNetnames.insert( net.GetNetName() );
529  }
530  }
531 
532  for( TRACK* via : m_board->Tracks() )
533  {
534  if( via->Type() != PCB_VIA_T )
535  continue;
536 
537  if( netlistNetnames.count( via->GetNetname() ) == 0 )
538  {
539  wxString updatedNetname = wxEmptyString;
540 
541  // Take via name from name change map if it didn't match to a new pad
542  // (this is useful for stitching vias that don't connect to tracks)
543  if( m_oldToNewNets.count( via->GetNetname() ) )
544  {
545  updatedNetname = m_oldToNewNets[via->GetNetname()];
546  }
547 
548  if( !updatedNetname.IsEmpty() )
549  {
550  msg.Printf( _( "Reconnect via from %s to %s." ),
551  UnescapeString( via->GetNetname() ),
552  UnescapeString( updatedNetname ) );
554 
555  if( !m_isDryRun )
556  {
557  NETINFO_ITEM* netinfo = m_board->FindNet( updatedNetname );
558 
559  if( !netinfo )
560  netinfo = m_addedNets[updatedNetname];
561 
562  if( netinfo )
563  {
564  m_commit.Modify( via );
565  via->SetNet( netinfo );
566  }
567  }
568  }
569  else
570  {
571  msg.Printf( _( "Via connected to unknown net (%s)." ),
572  UnescapeString( via->GetNetname() ) );
574  ++m_warningCount;
575  }
576  }
577  }
578 
579  // Test copper zones to detect "dead" nets (nets without any pad):
580  for( ZONE* zone : m_board->Zones() )
581  {
582  if( !zone->IsOnCopperLayer() || zone->GetIsRuleArea() )
583  continue;
584 
585  if( netlistNetnames.count( zone->GetNetname() ) == 0 )
586  {
587  // Look for a pad in the zone's connected-pad-cache which has been updated to
588  // a new net and use that. While this won't always be the right net, the dead
589  // net is guaranteed to be wrong.
590  wxString updatedNetname = wxEmptyString;
591 
592  for( PAD* pad : m_zoneConnectionsCache[ zone ] )
593  {
594  if( getNetname( pad ) != zone->GetNetname() )
595  {
596  updatedNetname = getNetname( pad );
597  break;
598  }
599  }
600 
601  // Take zone name from name change map if it didn't match to a new pad
602  // (this is useful for zones on internal layers)
603  if( updatedNetname.IsEmpty() && m_oldToNewNets.count( zone->GetNetname() ) )
604  {
605  updatedNetname = m_oldToNewNets[ zone->GetNetname() ];
606  }
607 
608  if( !updatedNetname.IsEmpty() )
609  {
610  msg.Printf( _( "Reconnect copper zone from %s to %s." ),
611  UnescapeString( zone->GetNetname() ),
612  UnescapeString( updatedNetname ) );
614 
615  if( !m_isDryRun )
616  {
617  NETINFO_ITEM* netinfo = m_board->FindNet( updatedNetname );
618 
619  if( !netinfo )
620  netinfo = m_addedNets[ updatedNetname ];
621 
622  if( netinfo )
623  {
624  m_commit.Modify( zone );
625  zone->SetNet( netinfo );
626  }
627  }
628  }
629  else
630  {
631  msg.Printf( _( "Copper zone (%s) has no pads connected." ),
632  UnescapeString( zone->GetNetname() ) );
634  ++m_warningCount;
635  }
636  }
637  }
638 
639  return true;
640 }
641 
642 
644 {
645  int count = 0;
646  wxString netname;
647  wxString msg;
648  PAD* previouspad = NULL;
649 
650  // We need the pad list for next tests.
651 
653 
654  std::vector<PAD*> padlist = m_board->GetPads();
655 
656  // Sort pads by netlist name
657  std::sort( padlist.begin(), padlist.end(), [ this ]( PAD* a, PAD* b ) -> bool
658  {
659  return getNetname( a ) < getNetname( b );
660  } );
661 
662  for( PAD* pad : padlist )
663  {
664  if( getNetname( pad ).IsEmpty() )
665  continue;
666 
667  if( netname != getNetname( pad ) ) // End of net
668  {
669  if( previouspad && count == 1 )
670  {
671  // First, see if we have a copper zone attached to this pad.
672  // If so, this is not really a single pad net
673 
674  for( ZONE* zone : m_board->Zones() )
675  {
676  if( !zone->IsOnCopperLayer() )
677  continue;
678 
679  if( zone->GetIsRuleArea() )
680  continue;
681 
682  if( zone->GetNetname() == getNetname( previouspad ) )
683  {
684  count++;
685  break;
686  }
687  }
688 
689  if( count == 1 ) // Really one pad, and nothing else
690  {
691  msg.Printf( _( "Remove single pad net %s." ),
692  UnescapeString( getNetname( previouspad ) ) );
694 
695  if( !m_isDryRun )
696  previouspad->SetNetCode( NETINFO_LIST::UNCONNECTED );
697  else
698  cacheNetname( previouspad, wxEmptyString );
699  }
700  }
701 
702  netname = getNetname( pad );
703  count = 1;
704  }
705  else
706  {
707  count++;
708  }
709 
710  previouspad = pad;
711  }
712 
713  // Examine last pad
714  if( count == 1 )
715  {
716  if( !m_isDryRun )
717  previouspad->SetNetCode( NETINFO_LIST::UNCONNECTED );
718  else
719  cacheNetname( previouspad, wxEmptyString );
720  }
721 
722  return true;
723 }
724 
725 
727  std::map<COMPONENT*, FOOTPRINT*>& aFootprintMap )
728 {
729  // Verify that board contains all pads in netlist: if it doesn't then footprints are
730  // wrong or missing.
731 
732  wxString msg;
733  wxString padname;
734 
735  for( int i = 0; i < (int) aNetlist.GetCount(); i++ )
736  {
737  COMPONENT* component = aNetlist.GetComponent( i );
738  FOOTPRINT* footprint = aFootprintMap[component];
739 
740  if( !footprint ) // It can be missing in partial designs
741  continue;
742 
743  // Explore all pins/pads in component
744  for( unsigned jj = 0; jj < component->GetNetCount(); jj++ )
745  {
746  const COMPONENT_NET& net = component->GetNet( jj );
747  padname = net.GetPinName();
748 
749  if( footprint->FindPadByName( padname ) )
750  continue; // OK, pad found
751 
752  // not found: bad footprint, report error
753  msg.Printf( _( "%s pad %s not found in %s." ),
754  component->GetReference(),
755  padname,
756  footprint->GetFPID().Format().wx_str() );
758  ++m_errorCount;
759  }
760  }
761 
762  return true;
763 }
764 
765 
767 {
768  FOOTPRINT* lastPreexistingFootprint = nullptr;
769  COMPONENT* component = nullptr;
770  wxString msg;
771 
772  m_errorCount = 0;
773  m_warningCount = 0;
775 
776  std::map<COMPONENT*, FOOTPRINT*> footprintMap;
777 
778  if( !m_board->Footprints().empty() )
779  lastPreexistingFootprint = m_board->Footprints().back();
780 
782 
783  // First mark all nets (except <no net>) as stale; we'll update those which are current
784  // in the following two loops.
785  //
786  if( !m_isDryRun )
787  {
788  m_board->SetStatus( 0 );
789 
790  for( NETINFO_ITEM* net : m_board->GetNetInfo() )
791  net->SetIsCurrent( net->GetNetCode() == 0 );
792  }
793 
794  // Next go through the netlist updating all board footprints which have matching component
795  // entries and adding new footprints for those that don't.
796  //
797  for( unsigned i = 0; i < aNetlist.GetCount(); i++ )
798  {
799  component = aNetlist.GetComponent( i );
800 
801  if( component->GetProperties().count( "exclude_from_board" ) )
802  continue;
803 
804  msg.Printf( _( "Processing symbol '%s:%s'." ),
805  component->GetReference(),
806  component->GetFPID().Format().wx_str() );
808 
809  int matchCount = 0;
810 
811  for( FOOTPRINT* footprint : m_board->Footprints() )
812  {
813  bool match = false;
814 
815  if( m_lookupByTimestamp )
816  {
817  for( auto& uuid : component->GetKIIDs() )
818  {
819  KIID_PATH base = component->GetPath();
820  base.push_back( uuid );
821 
822  if( footprint->GetPath() == base )
823  {
824  match = true;
825  break;
826  }
827  }
828  }
829  else
830  match = footprint->GetReference().CmpNoCase( component->GetReference() ) == 0;
831 
832  if( match )
833  {
834  FOOTPRINT* tmp = footprint;
835 
836  if( m_replaceFootprints && component->GetFPID() != footprint->GetFPID() )
837  tmp = replaceComponent( aNetlist, footprint, component );
838 
839  if( tmp )
840  {
841  footprintMap[ component ] = tmp;
842 
843  updateFootprintParameters( tmp, component );
844  updateComponentPadConnections( tmp, component );
845  }
846 
847  matchCount++;
848  }
849 
850  if( footprint == lastPreexistingFootprint )
851  {
852  // No sense going through the newly-created footprints: end of loop
853  break;
854  }
855  }
856 
857  if( matchCount == 0 )
858  {
859  FOOTPRINT* footprint = addNewComponent( component );
860 
861  if( footprint )
862  {
863  footprintMap[ component ] = footprint;
864 
865  updateFootprintParameters( footprint, component );
866  updateComponentPadConnections( footprint, component );
867  }
868  }
869  else if( matchCount > 1 )
870  {
871  msg.Printf( _( "Multiple footprints found for \"%s\"." ),
872  component->GetReference() );
874  }
875  }
876 
877  updateCopperZoneNets( aNetlist );
878 
879  // Finally go through the board footprints and update all those that *don't* have matching
880  // component entries.
881  //
882  for( FOOTPRINT* footprint : m_board->Footprints() )
883  {
884  bool doDelete = m_deleteUnusedComponents;
885 
886  if( ( footprint->GetAttributes() & FP_BOARD_ONLY ) > 0 )
887  doDelete = false;
888 
889  if( doDelete )
890  {
891  if( m_lookupByTimestamp )
892  component = aNetlist.GetComponentByPath( footprint->GetPath() );
893  else
894  component = aNetlist.GetComponentByReference( footprint->GetReference() );
895 
896  if( component && component->GetProperties().count( "exclude_from_board" ) == 0 )
897  doDelete = false;
898  }
899 
900  if( doDelete && footprint->IsLocked() )
901  {
902  msg.Printf( _( "Cannot remove unused footprint %s (locked)." ),
903  footprint->GetReference() );
905  doDelete = false;
906  }
907 
908  if( doDelete )
909  {
910  msg.Printf( _( "Remove unused footprint %s." ), footprint->GetReference() );
912 
913  if( !m_isDryRun )
914  m_commit.Remove( footprint );
915  }
916  else if( !m_isDryRun )
917  {
918  for( PAD* pad : footprint->Pads() )
919  {
920  if( pad->GetNet() )
921  pad->GetNet()->SetIsCurrent( true );
922  }
923  }
924  }
925 
926  if( !m_isDryRun )
927  {
928  m_board->GetConnectivity()->Build( m_board );
929  testConnectivity( aNetlist, footprintMap );
930 
931  // Now the connectivity data is rebuilt, we can delete single pads nets
934 
935  for( NETINFO_ITEM* net : m_board->GetNetInfo() )
936  {
937  if( !net->IsCurrent() )
938  {
939  msg.Printf( _( "Remove unused net \"%s\"." ), net->GetNetname() );
941  m_commit.Removed( net );
942  }
943  }
944 
946  m_commit.Push( _( "Update netlist" ) );
947  }
949  {
950  // We can delete single net pads in dry run mode only if no new footprints
951  // are added, because these new footprints are not actually added to the board
952  // and the current pad list is wrong in this case.
954  }
955 
956  if( m_isDryRun )
957  {
958  for( const std::pair<const wxString, NETINFO_ITEM*>& addedNet : m_addedNets )
959  delete addedNet.second;
960 
961  m_addedNets.clear();
962  }
963 
964  // Update the ratsnest
967 
968  msg.Printf( _( "Total warnings: %d, errors: %d." ), m_warningCount, m_errorCount );
970 
971  return true;
972 }
void SetReference(const wxString &aReference)
Definition: footprint.h:432
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
Definition: board.cpp:1268
void BuildListOfNets()
Definition: board.h:726
COMMIT & Modify(EDA_ITEM *aItem)
Create an undo entry for an item that has been already modified.
Definition: commit.h:103
const PAGE_INFO & GetPageSettings() const
Definition: board.h:599
COMPONENT * GetComponentByPath(const KIID_PATH &aPath)
Function GetComponentByPath returns a COMPONENT by aPath.
ZONES & Zones()
Definition: board.h:302
const wxString & GetValue() const
Definition: footprint.h:445
const KIID_PATH & GetPath() const
Definition: footprint.h:199
wxString getNetname(PAD *aPad)
void SetPath(const KIID_PATH &aPath)
Definition: footprint.h:200
COMMIT & Add(EDA_ITEM *aItem)
Notify observers that aItem has been added.
Definition: commit.h:78
const EDA_RECT GetBoardEdgesBoundingBox() const
Returns the board bounding box calculated using exclusively the board edges (graphics on Edge....
Definition: board.h:803
void SetIsCurrent(bool isCurrent)
Definition: netinfo.h:141
const wxString & GetPinType() const
Definition: pcb_netlist.h:66
virtual REPORTER & ReportTail(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
Places the report at the end of the list, for objects that support report ordering.
Definition: reporter.h:93
int GetWidth() const
Definition: eda_rect.h:114
bool SetNetCode(int aNetCode, bool aNoAssert)
Set net using a net code.
wxString GetNetname() const
BOARD_NETLIST_UPDATER class definition.
unsigned GetCount() const
Function GetCount.
Definition: pcb_netlist.h:237
int GetStatus(EDA_ITEM *aItem)
Definition: commit.cpp:129
const NETINFO_LIST & GetNetInfo() const
Definition: board.h:745
std::map< wxString, wxString > m_oldToNewNets
bool updateCopperZoneNets(NETLIST &aNetlist)
void cachePinFunction(PAD *aPad, const wxString &aPinFunction)
void RemoveUnusedNets()
const PCB_DISPLAY_OPTIONS & GetDisplayOptions() const
Display options control the way tracks, vias, outlines and other things are shown (for instance solid...
bool UpdateNetlist(NETLIST &aNetlist)
Update the board's components according to the new netlist.
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)=0
Report a string with a given severity.
bool empty() const
Definition: lib_id.h:189
virtual void SetParent(EDA_ITEM *aParent)
Definition: eda_item.h:165
void SetAttributes(int aAttributes)
Definition: footprint.h:232
PADS & Pads()
Definition: footprint.h:164
int GetBottom() const
Definition: eda_rect.h:119
std::map< wxString, NETINFO_ITEM * > m_addedNets
const LIB_ID & GetFPID() const
Definition: pcb_netlist.h:168
COMPONENT_NET is used to store the component pin name to net name (and pin function) associations sto...
Definition: pcb_netlist.h:44
bool updateComponentPadConnections(FOOTPRINT *aFootprint, COMPONENT *aNewComponent)
COMMIT & Removed(EDA_ITEM *aItem)
Modify a given item in the model.
Definition: commit.h:96
wxString getPinFunction(PAD *aPad)
FOOTPRINT * addNewComponent(COMPONENT *aComponent)
void ExchangeFootprint(FOOTPRINT *aExisting, FOOTPRINT *aNew, BOARD_COMMIT &aCommit, bool deleteExtraTexts=true, bool resetTextLayers=true, bool resetTextEffects=true, bool resetFabricationAttrs=true, bool reset3DModels=true)
Replace aExisting footprint by aNew footprint using the Existing footprint settings (position,...
const wxString & GetNetName() const
Definition: pcb_netlist.h:64
NETLIST stores all of information read from a netlist along with the flags used to update the NETLIST...
Definition: pcb_netlist.h:207
#define NULL
std::vector< FOOTPRINT * > m_addedComponents
std::map< ZONE *, std::vector< PAD * > > m_zoneConnectionsCache
unsigned GetNetCount() const
Definition: pcb_netlist.h:144
const std::vector< PAD * > GetPads() const
Return a reference to a list of all the pads.
Definition: board.cpp:1877
FOOTPRINTS & Footprints()
Definition: board.h:296
const wxString & GetReference() const
Definition: pcb_netlist.h:158
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
Definition: board.h:407
const wxString & GetReference() const
Definition: footprint.h:423
FOOTPRINT * replaceComponent(NETLIST &aNetlist, FOOTPRINT *aPcbComponent, COMPONENT *aNewComponent)
FOOTPRINT * LoadFootprint(const LIB_ID &aFootprintId)
Attempt to load aFootprintId from the footprint library table.
const LIB_ID & GetFPID() const
Definition: footprint.h:190
ZONE handles a list of polygons defining a copper zone.
Definition: zone.h:57
COMMIT & Remove(EDA_ITEM *aItem)
Notify observers that aItem has been removed.
Definition: commit.h:90
PAD * FindPadByName(const wxString &aPadName) const
Return a PAD with a matching name.
Definition: footprint.cpp:956
void SetValue(const wxString &aValue)
Definition: footprint.h:453
const COMPONENT_NET & GetNet(unsigned aIndex) const
Definition: pcb_netlist.h:146
int GetHeight() const
Definition: eda_rect.h:115
UTF8 Format() const
Definition: lib_id.cpp:233
COMPONENT is used to store components and all of their related information found in a netlist.
Definition: pcb_netlist.h:85
const wxString & GetPinFunction() const
Definition: pcb_netlist.h:65
bool IsValid() const
Definition: pcb_netlist.h:68
COMPONENT * GetComponent(unsigned aIndex)
Function GetComponent returns the COMPONENT at aIndex.
Definition: pcb_netlist.h:246
COMMIT & Modified(EDA_ITEM *aItem, EDA_ITEM *aCopy)
Definition: commit.h:110
Handle the data for a net.
Definition: netinfo.h:64
bool updateFootprintParameters(FOOTPRINT *aPcbFootprint, COMPONENT *aNetlistComponent)
int GetAttributes() const
Definition: footprint.h:231
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:189
#define _(s)
Definition: 3d_actions.cpp:33
wxString UnescapeString(const wxString &aSource)
Definition: string.cpp:150
wxString AsString() const
Definition: kiid.cpp:245
wxString wx_str() const
Definition: utf8.cpp:51
Handle the component boundary box.
Definition: eda_rect.h:42
The main frame for Pcbnew.
PCBNEW_SETTINGS & Settings()
The common library.
virtual void Push(const wxString &aMessage=wxT("A commit"), bool aCreateUndoEntry=true, bool aSetDirtyBit=true) override
Revert the commit by restoring the modified items state.
void SetStatus(STATUS_FLAGS aStatus)
Definition: eda_item.h:200
wxPoint Centre() const
Definition: eda_rect.h:60
const wxString & GetPinName() const
Definition: pcb_netlist.h:63
const std::map< wxString, wxString > & GetProperties() const
Definition: footprint.h:466
std::map< PAD *, wxString > m_padNets
const std::map< wxString, wxString > & GetProperties() const
Definition: pcb_netlist.h:165
const wxString & GetValue() const
Definition: pcb_netlist.h:159
COMPONENT * GetComponentByReference(const wxString &aReference)
Function GetComponentByReference returns a COMPONENT by aReference.
class VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:96
static REPORTER & GetInstance()
Definition: reporter.cpp:105
void SetProperties(const std::map< wxString, wxString > &aProps)
Definition: footprint.h:467
Definition: pad.h:60
void SetPosition(const wxPoint &aPos) override
Definition: footprint.cpp:1437
bool testConnectivity(NETLIST &aNetlist, std::map< COMPONENT *, FOOTPRINT * > &aFootprintMap)
BOARD_NETLIST_UPDATER(PCB_EDIT_FRAME *aFrame, BOARD *aBoard)
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: footprint.cpp:1168
void cacheNetname(PAD *aPad, const wxString &aNetname)
const KIID_PATH & GetPath() const
Definition: pcb_netlist.h:173
std::map< PAD *, wxString > m_padPinFunctions
static constexpr int Millimeter2iu(double mm)
static const int UNCONNECTED
Constant that forces initialization of a netinfo item to the NETINFO_ITEM ORPHANED (typically -1) whe...
Definition: netinfo.h:365
const wxString & GetPinFunction() const
Definition: pad.h:139
bool IsEmpty() const
Definition: board.h:344
TRACKS & Tracks()
Definition: board.h:293
Definition: track.h:83
const std::vector< KIID > & GetKIIDs() const
Definition: pcb_netlist.h:175