KiCad PCB EDA Suite
kicad_plugin.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) 2012 CERN
5  * Copyright (C) 1992-2017 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
25 #include <fctsys.h>
26 #include <kicad_string.h>
27 #include <common.h>
28 #include <build_version.h> // LEGACY_BOARD_FILE_VERSION
29 #include <macros.h>
31 #include <base_units.h>
32 
33 #include <class_board.h>
34 #include <class_module.h>
35 #include <class_pcb_text.h>
36 #include <class_dimension.h>
37 #include <class_track.h>
38 #include <class_zone.h>
39 #include <class_drawsegment.h>
40 #include <class_mire.h>
41 #include <class_edge_mod.h>
42 #include <pcb_plot_params.h>
43 #include <zones.h>
44 #include <kicad_plugin.h>
45 #include <pcb_parser.h>
46 
47 #include <wx/dir.h>
48 #include <wx/filename.h>
49 #include <wx/wfstream.h>
50 #include <boost/ptr_container/ptr_map.hpp>
51 #include <memory.h>
52 #include <connectivity.h>
53 
54 using namespace PCB_KEYS_T;
55 
56 #define FMTIU BOARD_ITEM::FormatInternalUnits
57 
62 static const wxString traceFootprintLibrary( wxT( "KicadFootprintLib" ) );
63 
65 void filterNetClass( const BOARD& aBoard, NETCLASS& aNetClass )
66 {
67  auto connectivity = aBoard.GetConnectivity();
68 
69  for( NETCLASS::iterator it = aNetClass.begin(); it != aNetClass.end(); )
70  {
71  NETINFO_ITEM* netinfo = aBoard.FindNet( *it );
72 
73  if( netinfo && connectivity->GetNodeCount( netinfo->GetNet() ) <= 0 ) // hopefully there are no nets with negative
74  aNetClass.Remove( it++ ); // node count, but you never know..
75  else
76  ++it;
77  }
78 }
79 
90 {
91  wxFileName m_file_name;
92  wxDateTime m_mod_time;
93  std::unique_ptr<MODULE> m_module;
94 
95 public:
96  FP_CACHE_ITEM( MODULE* aModule, const wxFileName& aFileName );
97 
98  wxString GetName() const { return m_file_name.GetDirs().Last(); }
99  wxFileName GetFileName() const { return m_file_name; }
100 
102  bool IsModified() const;
103 
104  MODULE* GetModule() const { return m_module.get(); }
105  void UpdateModificationTime() { m_mod_time = m_file_name.GetModificationTime(); }
106 };
107 
108 
109 FP_CACHE_ITEM::FP_CACHE_ITEM( MODULE* aModule, const wxFileName& aFileName ) :
110  m_module( aModule )
111 {
112  m_file_name = aFileName;
113 
114  if( m_file_name.FileExists() )
115  m_mod_time = m_file_name.GetModificationTime();
116  else
117  m_mod_time.Now();
118 }
119 
120 
122 {
123  if( !m_file_name.FileExists() )
124  return false;
125 
126  wxLogTrace( traceFootprintLibrary, wxT( "File '%s', m_mod_time %s-%s, file mod time: %s-%s." ),
127  GetChars( m_file_name.GetFullPath() ),
128  GetChars( m_mod_time.FormatDate() ), GetChars( m_mod_time.FormatTime() ),
129  GetChars( m_file_name.GetModificationTime().FormatDate() ),
130  GetChars( m_file_name.GetModificationTime().FormatTime() ) );
131 
132  return m_file_name.GetModificationTime() != m_mod_time;
133 }
134 
135 
136 typedef boost::ptr_map< std::string, FP_CACHE_ITEM > MODULE_MAP;
137 typedef MODULE_MAP::iterator MODULE_ITER;
138 typedef MODULE_MAP::const_iterator MODULE_CITER;
139 
140 
141 class FP_CACHE
142 {
144  wxFileName m_lib_path;
145  wxDateTime m_mod_time;
146  MODULE_MAP m_modules;
147 
148 public:
149  FP_CACHE( PCB_IO* aOwner, const wxString& aLibraryPath );
150 
151  wxString GetPath() const { return m_lib_path.GetPath(); }
152  wxDateTime GetLastModificationTime() const { return m_mod_time; }
153  bool IsWritable() const { return m_lib_path.IsOk() && m_lib_path.IsDirWritable(); }
154  MODULE_MAP& GetModules() { return m_modules; }
155 
156  // Most all functions in this class throw IO_ERROR exceptions. There are no
157  // error codes nor user interface calls from here, nor in any PLUGIN.
158  // Catch these exceptions higher up please.
159 
161  void Save();
162 
163  void Load();
164 
165  void Remove( const wxString& aFootprintName );
166 
167  wxDateTime GetLibModificationTime() const;
168 
180  bool IsModified( const wxString& aLibPath,
181  const wxString& aFootprintName = wxEmptyString ) const;
182 
195  bool IsPath( const wxString& aPath ) const;
196 };
197 
198 
199 FP_CACHE::FP_CACHE( PCB_IO* aOwner, const wxString& aLibraryPath )
200 {
201  m_owner = aOwner;
202  m_lib_path.SetPath( aLibraryPath );
203 }
204 
205 
207 {
208  return m_lib_path.GetModificationTime();
209 }
210 
211 
213 {
214  if( !m_lib_path.DirExists() && !m_lib_path.Mkdir() )
215  {
216  THROW_IO_ERROR( wxString::Format( _( "Cannot create footprint library path '%s'" ),
217  m_lib_path.GetPath().GetData() ) );
218  }
219 
220  if( !m_lib_path.IsDirWritable() )
221  {
222  THROW_IO_ERROR( wxString::Format( _( "Footprint library path '%s' is read only" ),
223  GetChars( m_lib_path.GetPath() ) ) );
224  }
225 
226  for( MODULE_ITER it = m_modules.begin(); it != m_modules.end(); ++it )
227  {
228  wxFileName fn = it->second->GetFileName();
229 
230  if( fn.FileExists() && !it->second->IsModified() )
231  continue;
232 
233  wxString tempFileName =
234 #ifdef USE_TMP_FILE
235  fn.CreateTempFileName( fn.GetPath() );
236 #else
237  fn.GetFullPath();
238 #endif
239  // Allow file output stream to go out of scope to close the file stream before
240  // renaming the file.
241  {
242  wxLogTrace( traceFootprintLibrary, wxT( "Creating temporary library file %s" ),
243  GetChars( tempFileName ) );
244 
245  FILE_OUTPUTFORMATTER formatter( tempFileName );
246 
247  m_owner->SetOutputFormatter( &formatter );
248  m_owner->Format( (BOARD_ITEM*) it->second->GetModule() );
249  }
250 
251 #ifdef USE_TMP_FILE
252  wxRemove( fn.GetFullPath() ); // it is not an error if this does not exist
253 
254  // Even on linux you can see an _intermittent_ error when calling wxRename(),
255  // and it is fully inexplicable. See if this dodges the error.
256  wxMilliSleep( 250L );
257 
258  if( !wxRenameFile( tempFileName, fn.GetFullPath() ) )
259  {
260  wxString msg = wxString::Format(
261  _( "Cannot rename temporary file '%s' to footprint library file '%s'" ),
262  GetChars( tempFileName ),
263  GetChars( fn.GetFullPath() )
264  );
265  THROW_IO_ERROR( msg );
266  }
267 #endif
268  it->second->UpdateModificationTime();
270  }
271 }
272 
273 
275 {
276  wxDir dir( m_lib_path.GetPath() );
277 
278  if( !dir.IsOpened() )
279  {
280  wxString msg = wxString::Format(
281  _( "Footprint library path '%s' does not exist" ),
282  GetChars( m_lib_path.GetPath() )
283  );
284 
285  THROW_IO_ERROR( msg );
286  }
287 
288  wxString fpFileName;
289  wxString wildcard = wxT( "*." ) + KiCadFootprintFileExtension;
290 
291  if( dir.GetFirst( &fpFileName, wildcard, wxDIR_FILES ) )
292  {
293  wxString cacheError;
294 
295  do
296  {
297  // prepend the libpath into fullPath
298  wxFileName fullPath( m_lib_path.GetPath(), fpFileName );
299 
300  // Queue I/O errors so only files that fail to parse don't get loaded.
301  try
302  {
303  FILE_LINE_READER reader( fullPath.GetFullPath() );
304 
305  m_owner->m_parser->SetLineReader( &reader );
306 
307  std::string name = TO_UTF8( fullPath.GetName() );
308  MODULE* footprint = (MODULE*) m_owner->m_parser->Parse();
309 
310  // The footprint name is the file name without the extension.
311  footprint->SetFPID( LIB_ID( fullPath.GetName() ) );
312  m_modules.insert( name, new FP_CACHE_ITEM( footprint, fullPath ) );
313  }
314  catch( const IO_ERROR& ioe )
315  {
316  if( !cacheError.IsEmpty() )
317  cacheError += "\n\n";
318 
319  cacheError += ioe.What();
320  }
321  } while( dir.GetNext( &fpFileName ) );
322 
323  // Remember the file modification time of library file when the
324  // cache snapshot was made, so that in a networked environment we will
325  // reload the cache as needed.
327 
328  if( !cacheError.IsEmpty() )
329  THROW_IO_ERROR( cacheError );
330  }
331 }
332 
333 
334 void FP_CACHE::Remove( const wxString& aFootprintName )
335 {
336  std::string footprintName = TO_UTF8( aFootprintName );
337 
338  MODULE_CITER it = m_modules.find( footprintName );
339 
340  if( it == m_modules.end() )
341  {
342  wxString msg = wxString::Format(
343  _( "library '%s' has no footprint '%s' to delete" ),
344  GetChars( m_lib_path.GetPath() ),
345  GetChars( aFootprintName )
346  );
347  THROW_IO_ERROR( msg );
348  }
349 
350  // Remove the module from the cache and delete the module file from the library.
351  wxString fullPath = it->second->GetFileName().GetFullPath();
352  m_modules.erase( footprintName );
353  wxRemoveFile( fullPath );
354 }
355 
356 
357 bool FP_CACHE::IsPath( const wxString& aPath ) const
358 {
359  // Converts path separators to native path separators
360  wxFileName newPath;
361  newPath.AssignDir( aPath );
362 
363  return m_lib_path == newPath;
364 }
365 
366 
367 bool FP_CACHE::IsModified( const wxString& aLibPath, const wxString& aFootprintName ) const
368 {
369  // The library is modified if the library path got deleted or changed.
370  if( !m_lib_path.DirExists() || !IsPath( aLibPath ) )
371  return true;
372 
373  // If no footprint was specified, check every file modification time against the time
374  // it was loaded.
375  if( aFootprintName.IsEmpty() )
376  {
377  for( MODULE_CITER it = m_modules.begin(); it != m_modules.end(); ++it )
378  {
379  wxFileName fn = m_lib_path;
380 
381  fn.SetName( it->second->GetFileName().GetName() );
382  fn.SetExt( KiCadFootprintFileExtension );
383 
384  if( !fn.FileExists() )
385  {
386  wxLogTrace( traceFootprintLibrary,
387  wxT( "Footprint cache file '%s' does not exist." ),
388  fn.GetFullPath().GetData() );
389  return true;
390  }
391 
392  if( it->second->IsModified() )
393  {
394  wxLogTrace( traceFootprintLibrary,
395  wxT( "Footprint cache file '%s' has been modified." ),
396  fn.GetFullPath().GetData() );
397  return true;
398  }
399  }
400  }
401  else
402  {
403  MODULE_CITER it = m_modules.find( TO_UTF8( aFootprintName ) );
404 
405  if( it == m_modules.end() || it->second->IsModified() )
406  return true;
407  }
408 
409  return false;
410 }
411 
412 
413 void PCB_IO::Save( const wxString& aFileName, BOARD* aBoard, const PROPERTIES* aProperties )
414 {
415  LOCALE_IO toggle; // toggles on, then off, the C locale.
416 
417  init( aProperties );
418 
419  m_board = aBoard; // after init()
420 
421  // Prepare net mapping that assures that net codes saved in a file are consecutive integers
422  m_mapping->SetBoard( aBoard );
423 
424  FILE_OUTPUTFORMATTER formatter( aFileName );
425 
426  m_out = &formatter; // no ownership
427 
428  m_out->Print( 0, "(kicad_pcb (version %d) (host pcbnew %s)\n", SEXPR_BOARD_FILE_VERSION,
429  formatter.Quotew( GetBuildVersion() ).c_str() );
430 
431  Format( aBoard, 1 );
432 
433  m_out->Print( 0, ")\n" );
434 }
435 
436 
437 BOARD_ITEM* PCB_IO::Parse( const wxString& aClipboardSourceInput )
438 {
439  std::string input = TO_UTF8( aClipboardSourceInput );
440 
441  STRING_LINE_READER reader( input, wxT( "clipboard" ) );
442 
443  m_parser->SetLineReader( &reader );
444 
445  try
446  {
447  return m_parser->Parse();
448  }
449  catch( const PARSE_ERROR& parse_error )
450  {
451  if( m_parser->IsTooRecent() )
452  throw FUTURE_FORMAT_ERROR( parse_error, m_parser->GetRequiredVersion() );
453  else
454  throw;
455  }
456 }
457 
458 
459 void PCB_IO::Format( BOARD_ITEM* aItem, int aNestLevel ) const
460 {
461  LOCALE_IO toggle; // public API function, perform anything convenient for caller
462 
463  switch( aItem->Type() )
464  {
465  case PCB_T:
466  format( static_cast<BOARD*>( aItem ), aNestLevel );
467  break;
468 
469  case PCB_DIMENSION_T:
470  format( static_cast<DIMENSION*>( aItem ), aNestLevel );
471  break;
472 
473  case PCB_LINE_T:
474  format( static_cast<DRAWSEGMENT*>( aItem ), aNestLevel );
475  break;
476 
477  case PCB_MODULE_EDGE_T:
478  format( static_cast<EDGE_MODULE*>( aItem ), aNestLevel );
479  break;
480 
481  case PCB_TARGET_T:
482  format( static_cast<PCB_TARGET*>( aItem ), aNestLevel );
483  break;
484 
485  case PCB_MODULE_T:
486  format( static_cast<MODULE*>( aItem ), aNestLevel );
487  break;
488 
489  case PCB_PAD_T:
490  format( static_cast<D_PAD*>( aItem ), aNestLevel );
491  break;
492 
493  case PCB_TEXT_T:
494  format( static_cast<TEXTE_PCB*>( aItem ), aNestLevel );
495  break;
496 
497  case PCB_MODULE_TEXT_T:
498  format( static_cast<TEXTE_MODULE*>( aItem ), aNestLevel );
499  break;
500 
501  case PCB_TRACE_T:
502  case PCB_VIA_T:
503  format( static_cast<TRACK*>( aItem ), aNestLevel );
504  break;
505 
506  case PCB_ZONE_AREA_T:
507  format( static_cast<ZONE_CONTAINER*>( aItem ), aNestLevel );
508  break;
509 
510  default:
511  wxFAIL_MSG( wxT( "Cannot format item " ) + aItem->GetClass() );
512  }
513 }
514 
515 
516 void PCB_IO::formatLayer( const BOARD_ITEM* aItem ) const
517 {
518  if( m_ctl & CTL_STD_LAYER_NAMES )
519  {
520  PCB_LAYER_ID layer = aItem->GetLayer();
521 
522  // English layer names should never need quoting.
523  m_out->Print( 0, " (layer %s)", TO_UTF8( BOARD::GetStandardLayerName( layer ) ) );
524  }
525  else
526  m_out->Print( 0, " (layer %s)", m_out->Quotew( aItem->GetLayerName() ).c_str() );
527 }
528 
529 
530 void PCB_IO::format( BOARD* aBoard, int aNestLevel ) const
531 {
532  const BOARD_DESIGN_SETTINGS& dsnSettings = aBoard->GetDesignSettings();
533 
534  m_out->Print( 0, "\n" );
535 
536  m_out->Print( aNestLevel, "(general\n" );
537 
538  // Write Bounding box info
539  m_out->Print( aNestLevel+1, "(thickness %s)\n",
540  FMTIU( dsnSettings.GetBoardThickness() ).c_str() );
541 
542  m_out->Print( aNestLevel+1, "(drawings %d)\n", aBoard->Drawings().Size() );
543  m_out->Print( aNestLevel+1, "(tracks %d)\n", aBoard->GetNumSegmTrack() );
544  m_out->Print( aNestLevel+1, "(zones %d)\n", aBoard->GetNumSegmZone() );
545  m_out->Print( aNestLevel+1, "(modules %d)\n", aBoard->m_Modules.GetCount() );
546  m_out->Print( aNestLevel+1, "(nets %d)\n", m_mapping->GetSize() );
547  m_out->Print( aNestLevel, ")\n\n" );
548 
549  aBoard->GetPageSettings().Format( m_out, aNestLevel, m_ctl );
550  aBoard->GetTitleBlock().Format( m_out, aNestLevel, m_ctl );
551 
552  // Layers.
553  m_out->Print( aNestLevel, "(layers\n" );
554 
555  // Save only the used copper layers from front to back.
556  LSET visible_layers = aBoard->GetVisibleLayers();
557 
558  for( LSEQ cu = aBoard->GetEnabledLayers().CuStack(); cu; ++cu )
559  {
560  PCB_LAYER_ID layer = *cu;
561 
562  m_out->Print( aNestLevel+1, "(%d %s %s", layer,
563  m_out->Quotew( aBoard->GetLayerName( layer ) ).c_str(),
564  LAYER::ShowType( aBoard->GetLayerType( layer ) ) );
565 
566  if( !visible_layers[layer] )
567  m_out->Print( 0, " hide" );
568 
569  m_out->Print( 0, ")\n" );
570  }
571 
572  // Save used non-copper layers in the order they are defined.
573  // desired sequence for non Cu BOARD layers.
574  static const PCB_LAYER_ID non_cu[] = {
575  B_Adhes, // 32
576  F_Adhes,
577  B_Paste,
578  F_Paste,
579  B_SilkS,
580  F_SilkS,
581  B_Mask,
582  F_Mask,
583  Dwgs_User,
584  Cmts_User,
585  Eco1_User,
586  Eco2_User,
587  Edge_Cuts,
588  Margin,
589  B_CrtYd,
590  F_CrtYd,
591  B_Fab,
592  F_Fab
593  };
594 
595  for( LSEQ seq = aBoard->GetEnabledLayers().Seq( non_cu, DIM( non_cu ) ); seq; ++seq )
596  {
597  PCB_LAYER_ID layer = *seq;
598 
599  m_out->Print( aNestLevel+1, "(%d %s user", layer,
600  m_out->Quotew( aBoard->GetLayerName( layer ) ).c_str() );
601 
602  if( !visible_layers[layer] )
603  m_out->Print( 0, " hide" );
604 
605  m_out->Print( 0, ")\n" );
606  }
607 
608  m_out->Print( aNestLevel, ")\n\n" );
609 
610  // Setup
611  m_out->Print( aNestLevel, "(setup\n" );
612 
613  // Save current default track width, for compatibility with older Pcbnew version;
614  m_out->Print( aNestLevel+1, "(last_trace_width %s)\n",
615  FMTIU( dsnSettings.GetCurrentTrackWidth() ).c_str() );
616 
617  // Save custom tracks width list (the first is not saved here: this is the netclass value
618  for( unsigned ii = 1; ii < dsnSettings.m_TrackWidthList.size(); ii++ )
619  m_out->Print( aNestLevel+1, "(user_trace_width %s)\n",
620  FMTIU( dsnSettings.m_TrackWidthList[ii] ).c_str() );
621 
622  m_out->Print( aNestLevel+1, "(trace_clearance %s)\n",
623  FMTIU( dsnSettings.GetDefault()->GetClearance() ).c_str() );
624 
625  // ZONE_SETTINGS
626  m_out->Print( aNestLevel+1, "(zone_clearance %s)\n",
627  FMTIU( aBoard->GetZoneSettings().m_ZoneClearance ).c_str() );
628  m_out->Print( aNestLevel+1, "(zone_45_only %s)\n",
629  aBoard->GetZoneSettings().m_Zone_45_Only ? "yes" : "no" );
630 
631  m_out->Print( aNestLevel+1, "(trace_min %s)\n",
632  FMTIU( dsnSettings.m_TrackMinWidth ).c_str() );
633 
634  m_out->Print( aNestLevel+1, "(segment_width %s)\n",
635  FMTIU( dsnSettings.m_DrawSegmentWidth ).c_str() );
636  m_out->Print( aNestLevel+1, "(edge_width %s)\n",
637  FMTIU( dsnSettings.m_EdgeSegmentWidth ).c_str() );
638 
639  // Save current default via size, for compatibility with older Pcbnew version;
640  m_out->Print( aNestLevel+1, "(via_size %s)\n",
641  FMTIU( dsnSettings.GetDefault()->GetViaDiameter() ).c_str() );
642  m_out->Print( aNestLevel+1, "(via_drill %s)\n",
643  FMTIU( dsnSettings.GetDefault()->GetViaDrill() ).c_str() );
644  m_out->Print( aNestLevel+1, "(via_min_size %s)\n",
645  FMTIU( dsnSettings.m_ViasMinSize ).c_str() );
646  m_out->Print( aNestLevel+1, "(via_min_drill %s)\n",
647  FMTIU( dsnSettings.m_ViasMinDrill ).c_str() );
648 
649  // Save custom vias diameters list (the first is not saved here: this is
650  // the netclass value
651  for( unsigned ii = 1; ii < dsnSettings.m_ViasDimensionsList.size(); ii++ )
652  m_out->Print( aNestLevel+1, "(user_via %s %s)\n",
653  FMTIU( dsnSettings.m_ViasDimensionsList[ii].m_Diameter ).c_str(),
654  FMTIU( dsnSettings.m_ViasDimensionsList[ii].m_Drill ).c_str() );
655 
656  // for old versions compatibility:
657  if( dsnSettings.m_BlindBuriedViaAllowed )
658  m_out->Print( aNestLevel+1, "(blind_buried_vias_allowed yes)\n" );
659 
660  m_out->Print( aNestLevel+1, "(uvia_size %s)\n",
661  FMTIU( dsnSettings.GetDefault()->GetuViaDiameter() ).c_str() );
662  m_out->Print( aNestLevel+1, "(uvia_drill %s)\n",
663  FMTIU( dsnSettings.GetDefault()->GetuViaDrill() ).c_str() );
664  m_out->Print( aNestLevel+1, "(uvias_allowed %s)\n",
665  ( dsnSettings.m_MicroViasAllowed ) ? "yes" : "no" );
666  m_out->Print( aNestLevel+1, "(uvia_min_size %s)\n",
667  FMTIU( dsnSettings.m_MicroViasMinSize ).c_str() );
668  m_out->Print( aNestLevel+1, "(uvia_min_drill %s)\n",
669  FMTIU( dsnSettings.m_MicroViasMinDrill ).c_str() );
670 
671  m_out->Print( aNestLevel+1, "(pcb_text_width %s)\n",
672  FMTIU( dsnSettings.m_PcbTextWidth ).c_str() );
673  m_out->Print( aNestLevel+1, "(pcb_text_size %s %s)\n",
674  FMTIU( dsnSettings.m_PcbTextSize.x ).c_str(),
675  FMTIU( dsnSettings.m_PcbTextSize.y ).c_str() );
676 
677  m_out->Print( aNestLevel+1, "(mod_edge_width %s)\n",
678  FMTIU( dsnSettings.m_ModuleSegmentWidth ).c_str() );
679  m_out->Print( aNestLevel+1, "(mod_text_size %s %s)\n",
680  FMTIU( dsnSettings.m_ModuleTextSize.x ).c_str(),
681  FMTIU( dsnSettings.m_ModuleTextSize.y ).c_str() );
682  m_out->Print( aNestLevel+1, "(mod_text_width %s)\n",
683  FMTIU( dsnSettings.m_ModuleTextWidth ).c_str() );
684 
685  m_out->Print( aNestLevel+1, "(pad_size %s %s)\n",
686  FMTIU( dsnSettings.m_Pad_Master.GetSize().x ).c_str(),
687  FMTIU( dsnSettings.m_Pad_Master.GetSize().y ).c_str() );
688  m_out->Print( aNestLevel+1, "(pad_drill %s)\n",
689  FMTIU( dsnSettings.m_Pad_Master.GetDrillSize().x ).c_str() );
690 
691  m_out->Print( aNestLevel+1, "(pad_to_mask_clearance %s)\n",
692  FMTIU( dsnSettings.m_SolderMaskMargin ).c_str() );
693 
694  if( dsnSettings.m_SolderMaskMinWidth )
695  m_out->Print( aNestLevel+1, "(solder_mask_min_width %s)\n",
696  FMTIU( dsnSettings.m_SolderMaskMinWidth ).c_str() );
697 
698  if( dsnSettings.m_SolderPasteMargin != 0 )
699  m_out->Print( aNestLevel+1, "(pad_to_paste_clearance %s)\n",
700  FMTIU( dsnSettings.m_SolderPasteMargin ).c_str() );
701 
702  if( dsnSettings.m_SolderPasteMarginRatio != 0 )
703  m_out->Print( aNestLevel+1, "(pad_to_paste_clearance_ratio %s)\n",
704  Double2Str( dsnSettings.m_SolderPasteMarginRatio ).c_str() );
705 
706  m_out->Print( aNestLevel+1, "(aux_axis_origin %s %s)\n",
707  FMTIU( aBoard->GetAuxOrigin().x ).c_str(),
708  FMTIU( aBoard->GetAuxOrigin().y ).c_str() );
709 
710  if( aBoard->GetGridOrigin().x || aBoard->GetGridOrigin().y )
711  m_out->Print( aNestLevel+1, "(grid_origin %s %s)\n",
712  FMTIU( aBoard->GetGridOrigin().x ).c_str(),
713  FMTIU( aBoard->GetGridOrigin().y ).c_str() );
714 
715  m_out->Print( aNestLevel+1, "(visible_elements %X)\n",
716  dsnSettings.GetVisibleElements() );
717 
718  aBoard->GetPlotOptions().Format( m_out, aNestLevel+1 );
719 
720  m_out->Print( aNestLevel, ")\n\n" );
721 
722  // Save net codes and names
723  for( NETINFO_MAPPING::iterator net = m_mapping->begin(), netEnd = m_mapping->end();
724  net != netEnd; ++net )
725  {
726  m_out->Print( aNestLevel, "(net %d %s)\n",
727  m_mapping->Translate( net->GetNet() ),
728  m_out->Quotew( net->GetNetname() ).c_str() );
729  }
730 
731  m_out->Print( 0, "\n" );
732 
733  // Save the default net class first.
734  NETCLASS defaultNC = *dsnSettings.GetDefault();
735  filterNetClass( *aBoard, defaultNC ); // Remove empty nets (from a copy of a netclass)
736  defaultNC.Format( m_out, aNestLevel, m_ctl );
737 
738  // Save the rest of the net classes alphabetically.
739  for( NETCLASSES::const_iterator it = dsnSettings.m_NetClasses.begin();
740  it != dsnSettings.m_NetClasses.end();
741  ++it )
742  {
743  NETCLASS netclass = *it->second;
744  filterNetClass( *aBoard, netclass ); // Remove empty nets (from a copy of a netclass)
745  netclass.Format( m_out, aNestLevel, m_ctl );
746  }
747 
748  // Save the modules.
749  for( MODULE* module = aBoard->m_Modules; module; module = module->Next() )
750  {
751  Format( module, aNestLevel );
752  m_out->Print( 0, "\n" );
753  }
754 
755  // Save the graphical items on the board (not owned by a module)
756  for( auto item : aBoard->Drawings() )
757  Format( item, aNestLevel );
758 
759  if( aBoard->Drawings().Size() )
760  m_out->Print( 0, "\n" );
761 
762  // Do not save MARKER_PCBs, they can be regenerated easily.
763 
764  // Save the tracks and vias.
765  for( TRACK* track = aBoard->m_Track; track; track = track->Next() )
766  Format( track, aNestLevel );
767 
768  if( aBoard->m_Track.GetCount() )
769  m_out->Print( 0, "\n" );
770 
773 
774  // Save the polygon (which are the newer technology) zones.
775  for( int i = 0; i < aBoard->GetAreaCount(); ++i )
776  Format( aBoard->GetArea( i ), aNestLevel );
777 }
778 
779 
780 void PCB_IO::format( DIMENSION* aDimension, int aNestLevel ) const
781 {
782  m_out->Print( aNestLevel, "(dimension %s (width %s)",
783  FMT_IU( aDimension->GetValue() ).c_str(),
784  FMT_IU( aDimension->GetWidth() ).c_str() );
785 
786  formatLayer( aDimension );
787 
788  if( aDimension->GetTimeStamp() )
789  m_out->Print( 0, " (tstamp %lX)", (unsigned long)aDimension->GetTimeStamp() );
790 
791  m_out->Print( 0, "\n" );
792 
793  Format( &aDimension->Text(), aNestLevel+1 );
794 
795  m_out->Print( aNestLevel+1, "(feature1 (pts (xy %s %s) (xy %s %s)))\n",
796  FMT_IU( aDimension->m_featureLineDO.x ).c_str(),
797  FMT_IU( aDimension->m_featureLineDO.y ).c_str(),
798  FMT_IU( aDimension->m_featureLineDF.x ).c_str(),
799  FMT_IU( aDimension->m_featureLineDF.y ).c_str() );
800 
801  m_out->Print( aNestLevel+1, "(feature2 (pts (xy %s %s) (xy %s %s)))\n",
802  FMT_IU( aDimension->m_featureLineGO.x ).c_str(),
803  FMT_IU( aDimension->m_featureLineGO.y ).c_str(),
804  FMT_IU( aDimension->m_featureLineGF.x ).c_str(),
805  FMT_IU( aDimension->m_featureLineGF.y ).c_str() );
806 
807  m_out->Print( aNestLevel+1, "(crossbar (pts (xy %s %s) (xy %s %s)))\n",
808  FMT_IU( aDimension->m_crossBarO.x ).c_str(),
809  FMT_IU( aDimension->m_crossBarO.y ).c_str(),
810  FMT_IU( aDimension->m_crossBarF.x ).c_str(),
811  FMT_IU( aDimension->m_crossBarF.y ).c_str() );
812 
813  m_out->Print( aNestLevel+1, "(arrow1a (pts (xy %s %s) (xy %s %s)))\n",
814  FMT_IU( aDimension->m_crossBarF.x ).c_str(),
815  FMT_IU( aDimension->m_crossBarF.y ).c_str(),
816  FMT_IU( aDimension->m_arrowD1F.x ).c_str(),
817  FMT_IU( aDimension->m_arrowD1F.y ).c_str() );
818 
819  m_out->Print( aNestLevel+1, "(arrow1b (pts (xy %s %s) (xy %s %s)))\n",
820  FMT_IU( aDimension->m_crossBarF.x ).c_str(),
821  FMT_IU( aDimension->m_crossBarF.y ).c_str(),
822  FMT_IU( aDimension->m_arrowD2F.x ).c_str(),
823  FMT_IU( aDimension->m_arrowD2F.y ).c_str() );
824 
825  m_out->Print( aNestLevel+1, "(arrow2a (pts (xy %s %s) (xy %s %s)))\n",
826  FMT_IU( aDimension->m_crossBarO.x ).c_str(),
827  FMT_IU( aDimension->m_crossBarO.y ).c_str(),
828  FMT_IU( aDimension->m_arrowG1F.x ).c_str(),
829  FMT_IU( aDimension->m_arrowG1F.y ).c_str() );
830 
831  m_out->Print( aNestLevel+1, "(arrow2b (pts (xy %s %s) (xy %s %s)))\n",
832  FMT_IU( aDimension->m_crossBarO.x ).c_str(),
833  FMT_IU( aDimension->m_crossBarO.y ).c_str(),
834  FMT_IU( aDimension->m_arrowG2F.x ).c_str(),
835  FMT_IU( aDimension->m_arrowG2F.y ).c_str() );
836 
837  m_out->Print( aNestLevel, ")\n" );
838 }
839 
840 
841 void PCB_IO::format( DRAWSEGMENT* aSegment, int aNestLevel ) const
842 {
843  unsigned i;
844 
845  switch( aSegment->GetShape() )
846  {
847  case S_SEGMENT: // Line
848  m_out->Print( aNestLevel, "(gr_line (start %s) (end %s)",
849  FMT_IU( aSegment->GetStart() ).c_str(),
850  FMT_IU( aSegment->GetEnd() ).c_str() );
851 
852  if( aSegment->GetAngle() != 0.0 )
853  m_out->Print( 0, " (angle %s)", FMT_ANGLE( aSegment->GetAngle() ).c_str() );
854 
855  break;
856 
857  case S_CIRCLE: // Circle
858  m_out->Print( aNestLevel, "(gr_circle (center %s) (end %s)",
859  FMT_IU( aSegment->GetStart() ).c_str(),
860  FMT_IU( aSegment->GetEnd() ).c_str() );
861  break;
862 
863  case S_ARC: // Arc
864  m_out->Print( aNestLevel, "(gr_arc (start %s) (end %s) (angle %s)",
865  FMT_IU( aSegment->GetStart() ).c_str(),
866  FMT_IU( aSegment->GetEnd() ).c_str(),
867  FMT_ANGLE( aSegment->GetAngle() ).c_str() );
868  break;
869 
870  case S_POLYGON: // Polygon
871  m_out->Print( aNestLevel, "(gr_poly (pts" );
872 
873  for( i = 0; i < aSegment->GetPolyPoints().size(); ++i )
874  m_out->Print( 0, " (xy %s)", FMT_IU( aSegment->GetPolyPoints()[i] ).c_str() );
875 
876  m_out->Print( 0, ")" );
877  break;
878 
879  case S_CURVE: // Bezier curve
880  m_out->Print( aNestLevel, "(gr_curve (pts (xy %s) (xy %s) (xy %s) (xy %s))",
881  FMT_IU( aSegment->GetStart() ).c_str(),
882  FMT_IU( aSegment->GetBezControl1() ).c_str(),
883  FMT_IU( aSegment->GetBezControl2() ).c_str(),
884  FMT_IU( aSegment->GetEnd() ).c_str() );
885  break;
886 
887  default:
888  wxFAIL_MSG( wxT( "Cannot format invalid DRAWSEGMENT type." ) );
889  };
890 
891  formatLayer( aSegment );
892 
893  if( aSegment->GetWidth() != 0 )
894  m_out->Print( 0, " (width %s)", FMT_IU( aSegment->GetWidth() ).c_str() );
895 
896  if( aSegment->GetTimeStamp() )
897  m_out->Print( 0, " (tstamp %lX)", (unsigned long)aSegment->GetTimeStamp() );
898 
899  if( aSegment->GetStatus() )
900  m_out->Print( 0, " (status %X)", aSegment->GetStatus() );
901 
902  m_out->Print( 0, ")\n" );
903 }
904 
905 
906 void PCB_IO::format( EDGE_MODULE* aModuleDrawing, int aNestLevel ) const
907 {
908  switch( aModuleDrawing->GetShape() )
909  {
910  case S_SEGMENT: // Line
911  m_out->Print( aNestLevel, "(fp_line (start %s) (end %s)",
912  FMT_IU( aModuleDrawing->GetStart0() ).c_str(),
913  FMT_IU( aModuleDrawing->GetEnd0() ).c_str() );
914  break;
915 
916  case S_CIRCLE: // Circle
917  m_out->Print( aNestLevel, "(fp_circle (center %s) (end %s)",
918  FMT_IU( aModuleDrawing->GetStart0() ).c_str(),
919  FMT_IU( aModuleDrawing->GetEnd0() ).c_str() );
920  break;
921 
922  case S_ARC: // Arc
923  m_out->Print( aNestLevel, "(fp_arc (start %s) (end %s) (angle %s)",
924  FMT_IU( aModuleDrawing->GetStart0() ).c_str(),
925  FMT_IU( aModuleDrawing->GetEnd0() ).c_str(),
926  FMT_ANGLE( aModuleDrawing->GetAngle() ).c_str() );
927  break;
928 
929  case S_POLYGON: // Polygon
930  m_out->Print( aNestLevel, "(fp_poly (pts" );
931 
932  for( unsigned i = 0; i < aModuleDrawing->GetPolyPoints().size(); ++i )
933  {
934  int nestLevel = 0;
935 
936  if( i && !(i%4) ) // newline every 4(pts)
937  {
938  nestLevel = aNestLevel + 1;
939  m_out->Print( 0, "\n" );
940  }
941 
942  m_out->Print( nestLevel, "%s(xy %s)",
943  nestLevel ? "" : " ",
944  FMT_IU( aModuleDrawing->GetPolyPoints()[i] ).c_str() );
945  }
946  m_out->Print( 0, ")" );
947  break;
948 
949  case S_CURVE: // Bezier curve
950  m_out->Print( aNestLevel, "(fp_curve (pts (xy %s) (xy %s) (xy %s) (xy %s))",
951  FMT_IU( aModuleDrawing->GetStart0() ).c_str(),
952  FMT_IU( aModuleDrawing->GetBezControl1() ).c_str(),
953  FMT_IU( aModuleDrawing->GetBezControl2() ).c_str(),
954  FMT_IU( aModuleDrawing->GetEnd0() ).c_str() );
955  break;
956 
957  default:
958  wxFAIL_MSG( wxT( "Cannot format invalid DRAWSEGMENT type." ) );
959  };
960 
961  formatLayer( aModuleDrawing );
962 
963  m_out->Print( 0, " (width %s)", FMT_IU( aModuleDrawing->GetWidth() ).c_str() );
964 
965  m_out->Print( 0, ")\n" );
966 }
967 
968 
969 void PCB_IO::format( PCB_TARGET* aTarget, int aNestLevel ) const
970 {
971  m_out->Print( aNestLevel, "(target %s (at %s) (size %s)",
972  ( aTarget->GetShape() ) ? "x" : "plus",
973  FMT_IU( aTarget->GetPosition() ).c_str(),
974  FMT_IU( aTarget->GetSize() ).c_str() );
975 
976  if( aTarget->GetWidth() != 0 )
977  m_out->Print( 0, " (width %s)", FMT_IU( aTarget->GetWidth() ).c_str() );
978 
979  formatLayer( aTarget );
980 
981  if( aTarget->GetTimeStamp() )
982  m_out->Print( 0, " (tstamp %lX)", (unsigned long)aTarget->GetTimeStamp() );
983 
984  m_out->Print( 0, ")\n" );
985 }
986 
987 
988 void PCB_IO::format( MODULE* aModule, int aNestLevel ) const
989 {
990  if( !( m_ctl & CTL_OMIT_INITIAL_COMMENTS ) )
991  {
992  const wxArrayString* initial_comments = aModule->GetInitialComments();
993 
994  if( initial_comments )
995  {
996  for( unsigned i=0; i<initial_comments->GetCount(); ++i )
997  m_out->Print( aNestLevel, "%s\n", TO_UTF8( (*initial_comments)[i] ) );
998 
999  m_out->Print( 0, "\n" ); // improve readability?
1000  }
1001  }
1002 
1003  m_out->Print( aNestLevel, "(module %s",
1004  m_out->Quotes( aModule->GetFPID().Format() ).c_str() );
1005 
1006  if( aModule->IsLocked() )
1007  m_out->Print( 0, " locked" );
1008 
1009  if( aModule->IsPlaced() )
1010  m_out->Print( 0, " placed" );
1011 
1012  formatLayer( aModule );
1013 
1014  m_out->Print( 0, " (tedit %lX)", (unsigned long)aModule->GetLastEditTime() );
1015 
1016  if( !( m_ctl & CTL_OMIT_TSTAMPS ) )
1017  {
1018  m_out->Print( 0, " (tstamp %lX)\n", (unsigned long)aModule->GetTimeStamp() );
1019  }
1020  else
1021  m_out->Print( 0, "\n" );
1022 
1023  if( !( m_ctl & CTL_OMIT_AT ) )
1024  {
1025  m_out->Print( aNestLevel+1, "(at %s", FMT_IU( aModule->GetPosition() ).c_str() );
1026 
1027  if( aModule->GetOrientation() != 0.0 )
1028  m_out->Print( 0, " %s", FMT_ANGLE( aModule->GetOrientation() ).c_str() );
1029 
1030  m_out->Print( 0, ")\n" );
1031  }
1032 
1033  if( !aModule->GetDescription().IsEmpty() )
1034  m_out->Print( aNestLevel+1, "(descr %s)\n",
1035  m_out->Quotew( aModule->GetDescription() ).c_str() );
1036 
1037  if( !aModule->GetKeywords().IsEmpty() )
1038  m_out->Print( aNestLevel+1, "(tags %s)\n",
1039  m_out->Quotew( aModule->GetKeywords() ).c_str() );
1040 
1041  if( !( m_ctl & CTL_OMIT_PATH ) && !!aModule->GetPath() )
1042  m_out->Print( aNestLevel+1, "(path %s)\n",
1043  m_out->Quotew( aModule->GetPath() ).c_str() );
1044 
1045  if( aModule->GetPlacementCost90() != 0 )
1046  m_out->Print( aNestLevel+1, "(autoplace_cost90 %d)\n", aModule->GetPlacementCost90() );
1047 
1048  if( aModule->GetPlacementCost180() != 0 )
1049  m_out->Print( aNestLevel+1, "(autoplace_cost180 %d)\n", aModule->GetPlacementCost180() );
1050 
1051  if( aModule->GetLocalSolderMaskMargin() != 0 )
1052  m_out->Print( aNestLevel+1, "(solder_mask_margin %s)\n",
1053  FMT_IU( aModule->GetLocalSolderMaskMargin() ).c_str() );
1054 
1055  if( aModule->GetLocalSolderPasteMargin() != 0 )
1056  m_out->Print( aNestLevel+1, "(solder_paste_margin %s)\n",
1057  FMT_IU( aModule->GetLocalSolderPasteMargin() ).c_str() );
1058 
1059  if( aModule->GetLocalSolderPasteMarginRatio() != 0 )
1060  m_out->Print( aNestLevel+1, "(solder_paste_ratio %s)\n",
1061  Double2Str( aModule->GetLocalSolderPasteMarginRatio() ).c_str() );
1062 
1063  if( aModule->GetLocalClearance() != 0 )
1064  m_out->Print( aNestLevel+1, "(clearance %s)\n",
1065  FMT_IU( aModule->GetLocalClearance() ).c_str() );
1066 
1067  if( aModule->GetZoneConnection() != PAD_ZONE_CONN_INHERITED )
1068  m_out->Print( aNestLevel+1, "(zone_connect %d)\n", aModule->GetZoneConnection() );
1069 
1070  if( aModule->GetThermalWidth() != 0 )
1071  m_out->Print( aNestLevel+1, "(thermal_width %s)\n",
1072  FMT_IU( aModule->GetThermalWidth() ).c_str() );
1073 
1074  if( aModule->GetThermalGap() != 0 )
1075  m_out->Print( aNestLevel+1, "(thermal_gap %s)\n",
1076  FMT_IU( aModule->GetThermalGap() ).c_str() );
1077 
1078  // Attributes
1079  if( aModule->GetAttributes() != MOD_DEFAULT )
1080  {
1081  m_out->Print( aNestLevel+1, "(attr" );
1082 
1083  if( aModule->GetAttributes() & MOD_CMS )
1084  m_out->Print( 0, " smd" );
1085 
1086  if( aModule->GetAttributes() & MOD_VIRTUAL )
1087  m_out->Print( 0, " virtual" );
1088 
1089  m_out->Print( 0, ")\n" );
1090  }
1091 
1092  Format( (BOARD_ITEM*) &aModule->Reference(), aNestLevel+1 );
1093  Format( (BOARD_ITEM*) &aModule->Value(), aNestLevel+1 );
1094 
1095  // Save drawing elements.
1096  for( BOARD_ITEM* gr = aModule->GraphicalItemsList(); gr; gr = gr->Next() )
1097  Format( gr, aNestLevel+1 );
1098 
1099  // Save pads.
1100  for( D_PAD* pad = aModule->PadsList(); pad; pad = pad->Next() )
1101  format( pad, aNestLevel+1 );
1102 
1103  // Save 3D info.
1104  std::list<S3D_INFO>::const_iterator bs3D = aModule->Models().begin();
1105  std::list<S3D_INFO>::const_iterator es3D = aModule->Models().end();
1106 
1107  while( bs3D != es3D )
1108  {
1109  if( !bs3D->m_Filename.IsEmpty() )
1110  {
1111  m_out->Print( aNestLevel+1, "(model %s\n",
1112  m_out->Quotew( bs3D->m_Filename ).c_str() );
1113 
1114  m_out->Print( aNestLevel+2, "(at (xyz %s %s %s))\n",
1115  Double2Str( bs3D->m_Offset.x ).c_str(),
1116  Double2Str( bs3D->m_Offset.y ).c_str(),
1117  Double2Str( bs3D->m_Offset.z ).c_str() );
1118 
1119  m_out->Print( aNestLevel+2, "(scale (xyz %s %s %s))\n",
1120  Double2Str( bs3D->m_Scale.x ).c_str(),
1121  Double2Str( bs3D->m_Scale.y ).c_str(),
1122  Double2Str( bs3D->m_Scale.z ).c_str() );
1123 
1124  m_out->Print( aNestLevel+2, "(rotate (xyz %s %s %s))\n",
1125  Double2Str( bs3D->m_Rotation.x ).c_str(),
1126  Double2Str( bs3D->m_Rotation.y ).c_str(),
1127  Double2Str( bs3D->m_Rotation.z ).c_str() );
1128 
1129  m_out->Print( aNestLevel+1, ")\n" );
1130  }
1131  ++bs3D;
1132  }
1133 
1134  m_out->Print( aNestLevel, ")\n" );
1135 }
1136 
1137 
1138 void PCB_IO::formatLayers( LSET aLayerMask, int aNestLevel ) const
1139 {
1140  std::string output;
1141 
1142  if( aNestLevel == 0 )
1143  output += ' ';
1144 
1145  output += "(layers";
1146 
1147  static const LSET cu_all( LSET::AllCuMask() );
1148  static const LSET fr_bk( 2, B_Cu, F_Cu );
1149  static const LSET adhes( 2, B_Adhes, F_Adhes );
1150  static const LSET paste( 2, B_Paste, F_Paste );
1151  static const LSET silks( 2, B_SilkS, F_SilkS );
1152  static const LSET mask( 2, B_Mask, F_Mask );
1153  static const LSET crt_yd(2, B_CrtYd, F_CrtYd );
1154  static const LSET fab( 2, B_Fab, F_Fab );
1155 
1156  LSET cu_mask = cu_all;
1157 
1158  if( m_board )
1159  cu_mask &= m_board->GetEnabledLayers();
1160 
1161  // output copper layers first, then non copper
1162 
1163  if( ( aLayerMask & cu_mask ) == cu_mask )
1164  {
1165  output += " *.Cu";
1166  aLayerMask &= ~cu_all; // clear bits, so they are not output again below
1167  }
1168  else if( ( aLayerMask & cu_mask ) == fr_bk )
1169  {
1170  output += " F&B.Cu";
1171  aLayerMask &= ~fr_bk;
1172  }
1173 
1174  if( ( aLayerMask & adhes ) == adhes )
1175  {
1176  output += " *.Adhes";
1177  aLayerMask &= ~adhes;
1178  }
1179 
1180  if( ( aLayerMask & paste ) == paste )
1181  {
1182  output += " *.Paste";
1183  aLayerMask &= ~paste;
1184  }
1185 
1186  if( ( aLayerMask & silks ) == silks )
1187  {
1188  output += " *.SilkS";
1189  aLayerMask &= ~silks;
1190  }
1191 
1192  if( ( aLayerMask & mask ) == mask )
1193  {
1194  output += " *.Mask";
1195  aLayerMask &= ~mask;
1196  }
1197 
1198  if( ( aLayerMask & crt_yd ) == crt_yd )
1199  {
1200  output += " *.CrtYd";
1201  aLayerMask &= ~crt_yd;
1202  }
1203 
1204  if( ( aLayerMask & fab ) == fab )
1205  {
1206  output += " *.Fab";
1207  aLayerMask &= ~fab;
1208  }
1209 
1210  // output any individual layers not handled in wildcard combos above
1211 
1212  if( m_board )
1213  aLayerMask &= m_board->GetEnabledLayers();
1214 
1215  wxString layerName;
1216 
1217  for( LAYER_NUM layer = 0; layer < PCB_LAYER_ID_COUNT; ++layer )
1218  {
1219  if( aLayerMask[layer] )
1220  {
1221  if( m_board && !( m_ctl & CTL_STD_LAYER_NAMES ) )
1222  layerName = m_board->GetLayerName( PCB_LAYER_ID( layer ) );
1223 
1224  else // I am being called from FootprintSave()
1225  layerName = BOARD::GetStandardLayerName( PCB_LAYER_ID( layer ) );
1226 
1227  output += ' ';
1228  output += m_out->Quotew( layerName );
1229  }
1230  }
1231 
1232  m_out->Print( aNestLevel, "%s)", output.c_str() );
1233 }
1234 
1235 
1236 void PCB_IO::format( D_PAD* aPad, int aNestLevel ) const
1237 {
1238  const char* shape;
1239 
1240  switch( aPad->GetShape() )
1241  {
1242  case PAD_SHAPE_CIRCLE: shape = "circle"; break;
1243  case PAD_SHAPE_RECT: shape = "rect"; break;
1244  case PAD_SHAPE_OVAL: shape = "oval"; break;
1245  case PAD_SHAPE_TRAPEZOID: shape = "trapezoid"; break;
1246  case PAD_SHAPE_ROUNDRECT: shape = "roundrect"; break;
1247 
1248  default:
1249  THROW_IO_ERROR( wxString::Format( _( "unknown pad type: %d"), aPad->GetShape() ) );
1250  }
1251 
1252  const char* type;
1253 
1254  switch( aPad->GetAttribute() )
1255  {
1256  case PAD_ATTRIB_STANDARD: type = "thru_hole"; break;
1257  case PAD_ATTRIB_SMD: type = "smd"; break;
1258  case PAD_ATTRIB_CONN: type = "connect"; break;
1259  case PAD_ATTRIB_HOLE_NOT_PLATED: type = "np_thru_hole"; break;
1260 
1261  default:
1262  THROW_IO_ERROR( wxString::Format( _( "unknown pad attribute: %d" ),
1263  aPad->GetAttribute() ) );
1264  }
1265 
1266  m_out->Print( aNestLevel, "(pad %s %s %s",
1267  m_out->Quotew( aPad->GetPadName() ).c_str(),
1268  type, shape );
1269  m_out->Print( 0, " (at %s", FMT_IU( aPad->GetPos0() ).c_str() );
1270 
1271  if( aPad->GetOrientation() != 0.0 )
1272  m_out->Print( 0, " %s", FMT_ANGLE( aPad->GetOrientation() ).c_str() );
1273 
1274  m_out->Print( 0, ")" );
1275  m_out->Print( 0, " (size %s)", FMT_IU( aPad->GetSize() ).c_str() );
1276 
1277  if( (aPad->GetDelta().GetWidth()) != 0 || (aPad->GetDelta().GetHeight() != 0 ) )
1278  m_out->Print( 0, " (rect_delta %s )", FMT_IU( aPad->GetDelta() ).c_str() );
1279 
1280  wxSize sz = aPad->GetDrillSize();
1281  wxPoint shapeoffset = aPad->GetOffset();
1282 
1283  if( (sz.GetWidth() > 0) || (sz.GetHeight() > 0) ||
1284  (shapeoffset.x != 0) || (shapeoffset.y != 0) )
1285  {
1286  m_out->Print( 0, " (drill" );
1287 
1288  if( aPad->GetDrillShape() == PAD_DRILL_SHAPE_OBLONG )
1289  m_out->Print( 0, " oval" );
1290 
1291  if( sz.GetWidth() > 0 )
1292  m_out->Print( 0, " %s", FMT_IU( sz.GetWidth() ).c_str() );
1293 
1294  if( sz.GetHeight() > 0 && sz.GetWidth() != sz.GetHeight() )
1295  m_out->Print( 0, " %s", FMT_IU( sz.GetHeight() ).c_str() );
1296 
1297  if( (shapeoffset.x != 0) || (shapeoffset.y != 0) )
1298  m_out->Print( 0, " (offset %s)", FMT_IU( aPad->GetOffset() ).c_str() );
1299 
1300  m_out->Print( 0, ")" );
1301  }
1302 
1303  formatLayers( aPad->GetLayerSet(), 0 );
1304 
1305  // Output the radius ratio for rounded rect pads
1306  if( aPad->GetShape() == PAD_SHAPE_ROUNDRECT )
1307  {
1308  m_out->Print( 0, "(roundrect_rratio %s)",
1309  Double2Str( aPad->GetRoundRectRadiusRatio() ).c_str() );
1310  }
1311 
1312  std::string output;
1313 
1314  // Unconnected pad is default net so don't save it.
1315  if( !( m_ctl & CTL_OMIT_NETS ) && aPad->GetNetCode() != NETINFO_LIST::UNCONNECTED )
1316  StrPrintf( &output, " (net %d %s)", m_mapping->Translate( aPad->GetNetCode() ),
1317  m_out->Quotew( aPad->GetNetname() ).c_str() );
1318 
1319  if( aPad->GetPadToDieLength() != 0 )
1320  StrPrintf( &output, " (die_length %s)", FMT_IU( aPad->GetPadToDieLength() ).c_str() );
1321 
1322  if( aPad->GetLocalSolderMaskMargin() != 0 )
1323  StrPrintf( &output, " (solder_mask_margin %s)", FMT_IU( aPad->GetLocalSolderMaskMargin() ).c_str() );
1324 
1325  if( aPad->GetLocalSolderPasteMargin() != 0 )
1326  StrPrintf( &output, " (solder_paste_margin %s)", FMT_IU( aPad->GetLocalSolderPasteMargin() ).c_str() );
1327 
1328  if( aPad->GetLocalSolderPasteMarginRatio() != 0 )
1329  StrPrintf( &output, " (solder_paste_margin_ratio %s)",
1330  Double2Str( aPad->GetLocalSolderPasteMarginRatio() ).c_str() );
1331 
1332  if( aPad->GetLocalClearance() != 0 )
1333  StrPrintf( &output, " (clearance %s)", FMT_IU( aPad->GetLocalClearance() ).c_str() );
1334 
1336  StrPrintf( &output, " (zone_connect %d)", aPad->GetZoneConnection() );
1337 
1338  if( aPad->GetThermalWidth() != 0 )
1339  StrPrintf( &output, " (thermal_width %s)", FMT_IU( aPad->GetThermalWidth() ).c_str() );
1340 
1341  if( aPad->GetThermalGap() != 0 )
1342  StrPrintf( &output, " (thermal_gap %s)", FMT_IU( aPad->GetThermalGap() ).c_str() );
1343 
1344  if( output.size() )
1345  {
1346  m_out->Print( 0, "\n" );
1347  m_out->Print( aNestLevel+1, "%s", output.c_str()+1 ); // +1 skips 1st space on 1st element
1348  }
1349 
1350  m_out->Print( 0, ")\n" );
1351 }
1352 
1353 
1354 void PCB_IO::format( TEXTE_PCB* aText, int aNestLevel ) const
1355 {
1356  m_out->Print( aNestLevel, "(gr_text %s (at %s",
1357  m_out->Quotew( aText->GetText() ).c_str(),
1358  FMT_IU( aText->GetTextPos() ).c_str() );
1359 
1360  if( aText->GetTextAngle() != 0.0 )
1361  m_out->Print( 0, " %s", FMT_ANGLE( aText->GetTextAngle() ).c_str() );
1362 
1363  m_out->Print( 0, ")" );
1364 
1365  formatLayer( aText );
1366 
1367  if( aText->GetTimeStamp() )
1368  m_out->Print( 0, " (tstamp %lX)", (unsigned long)aText->GetTimeStamp() );
1369 
1370  m_out->Print( 0, "\n" );
1371 
1372  aText->EDA_TEXT::Format( m_out, aNestLevel, m_ctl );
1373 
1374  m_out->Print( aNestLevel, ")\n" );
1375 }
1376 
1377 
1378 void PCB_IO::format( TEXTE_MODULE* aText, int aNestLevel ) const
1379 {
1380  wxString type;
1381 
1382  switch( aText->GetType() )
1383  {
1384  case TEXTE_MODULE::TEXT_is_REFERENCE: type = "reference"; break;
1385  case TEXTE_MODULE::TEXT_is_VALUE: type = "value"; break;
1386  case TEXTE_MODULE::TEXT_is_DIVERS: type = "user";
1387  }
1388 
1389  m_out->Print( aNestLevel, "(fp_text %s %s (at %s",
1390  m_out->Quotew( type ).c_str(),
1391  m_out->Quotew( aText->GetText() ).c_str(),
1392  FMT_IU( aText->GetPos0() ).c_str() );
1393 
1394  // Due to Pcbnew history, fp_text angle is saved as an absolute on screen angle,
1395  // but internally the angle is held relative to its parent footprint. parent
1396  // may be NULL when saving a footprint outside a BOARD.
1397  double orient = aText->GetTextAngle();
1398  MODULE* parent = (MODULE*) aText->GetParent();
1399 
1400  if( parent )
1401  {
1402  // GetTextAngle() is always in -360..+360 range because of
1403  // TEXTE_MODULE::SetTextAngle(), but summing that angle with an
1404  // additional board angle could kick sum up >= 360 or <= -360, so to have
1405  // consistent results, normalize again for the BOARD save. A footprint
1406  // save does not use this code path since parent is NULL.
1407 #if 0
1408  // This one could be considered reasonable if you like positive angles
1409  // in your board text.
1410  orient = NormalizeAnglePos( orient + parent->GetOrientation() );
1411 #else
1412  // Choose compatibility for now, even though this is only a 720 degree clamp
1413  // with two possible values for every angle.
1414  orient = NormalizeAngle360( orient + parent->GetOrientation() );
1415 #endif
1416  }
1417 
1418  if( orient != 0.0 )
1419  m_out->Print( 0, " %s", FMT_ANGLE( orient ).c_str() );
1420 
1421  m_out->Print( 0, ")" );
1422  formatLayer( aText );
1423 
1424  if( !aText->IsVisible() )
1425  m_out->Print( 0, " hide" );
1426 
1427  m_out->Print( 0, "\n" );
1428 
1429  aText->EDA_TEXT::Format( m_out, aNestLevel, m_ctl | CTL_OMIT_HIDE );
1430 
1431  m_out->Print( aNestLevel, ")\n" );
1432 }
1433 
1434 
1435 void PCB_IO::format( TRACK* aTrack, int aNestLevel ) const
1436 {
1437  if( aTrack->Type() == PCB_VIA_T )
1438  {
1439  PCB_LAYER_ID layer1, layer2;
1440 
1441  const VIA* via = static_cast<const VIA*>(aTrack);
1442  BOARD* board = (BOARD*) via->GetParent();
1443 
1444  wxCHECK_RET( board != 0, wxT( "Via " ) + via->GetSelectMenuText() +
1445  wxT( " has no parent." ) );
1446 
1447  m_out->Print( aNestLevel, "(via" );
1448 
1449  via->LayerPair( &layer1, &layer2 );
1450 
1451  switch( via->GetViaType() )
1452  {
1453  case VIA_THROUGH: // Default shape not saved.
1454  break;
1455 
1456  case VIA_BLIND_BURIED:
1457  m_out->Print( 0, " blind" );
1458  break;
1459 
1460  case VIA_MICROVIA:
1461  m_out->Print( 0, " micro" );
1462  break;
1463 
1464  default:
1465  THROW_IO_ERROR( wxString::Format( _( "unknown via type %d" ), via->GetViaType() ) );
1466  }
1467 
1468  m_out->Print( 0, " (at %s) (size %s)",
1469  FMT_IU( aTrack->GetStart() ).c_str(),
1470  FMT_IU( aTrack->GetWidth() ).c_str() );
1471 
1472  if( via->GetDrill() != UNDEFINED_DRILL_DIAMETER )
1473  m_out->Print( 0, " (drill %s)", FMT_IU( via->GetDrill() ).c_str() );
1474 
1475  m_out->Print( 0, " (layers %s %s)",
1476  m_out->Quotew( m_board->GetLayerName( layer1 ) ).c_str(),
1477  m_out->Quotew( m_board->GetLayerName( layer2 ) ).c_str() );
1478  }
1479  else
1480  {
1481  m_out->Print( aNestLevel, "(segment (start %s) (end %s) (width %s)",
1482  FMT_IU( aTrack->GetStart() ).c_str(), FMT_IU( aTrack->GetEnd() ).c_str(),
1483  FMT_IU( aTrack->GetWidth() ).c_str() );
1484 
1485  m_out->Print( 0, " (layer %s)", m_out->Quotew( aTrack->GetLayerName() ).c_str() );
1486  }
1487 
1488  m_out->Print( 0, " (net %d)", m_mapping->Translate( aTrack->GetNetCode() ) );
1489 
1490  if( aTrack->GetTimeStamp() != 0 )
1491  m_out->Print( 0, " (tstamp %lX)", (unsigned long)aTrack->GetTimeStamp() );
1492 
1493  if( aTrack->GetStatus() != 0 )
1494  m_out->Print( 0, " (status %X)", aTrack->GetStatus() );
1495 
1496  m_out->Print( 0, ")\n" );
1497 }
1498 
1499 
1500 void PCB_IO::format( ZONE_CONTAINER* aZone, int aNestLevel ) const
1501 {
1502  // Save the NET info; For keepout zones, net code and net name are irrelevant
1503  // so be sure a dummy value is stored, just for ZONE_CONTAINER compatibility
1504  // (perhaps netcode and netname should be not stored)
1505  m_out->Print( aNestLevel, "(zone (net %d) (net_name %s)",
1506  aZone->GetIsKeepout() ? 0 : m_mapping->Translate( aZone->GetNetCode() ),
1507  m_out->Quotew( aZone->GetIsKeepout() ? wxT("") : aZone->GetNetname() ).c_str() );
1508 
1509  formatLayer( aZone );
1510 
1511  m_out->Print( 0, " (tstamp %lX)", (unsigned long) aZone->GetTimeStamp() );
1512 
1513  // Save the outline aux info
1514  std::string hatch;
1515 
1516  switch( aZone->GetHatchStyle() )
1517  {
1518  default:
1519  case ZONE_CONTAINER::NO_HATCH: hatch = "none"; break;
1520  case ZONE_CONTAINER::DIAGONAL_EDGE: hatch = "edge"; break;
1521  case ZONE_CONTAINER::DIAGONAL_FULL: hatch = "full"; break;
1522  }
1523 
1524  m_out->Print( 0, " (hatch %s %s)\n", hatch.c_str(),
1525  FMT_IU( aZone->GetHatchPitch() ).c_str() );
1526 
1527  if( aZone->GetPriority() > 0 )
1528  m_out->Print( aNestLevel+1, "(priority %d)\n", aZone->GetPriority() );
1529 
1530  m_out->Print( aNestLevel+1, "(connect_pads" );
1531 
1532  switch( aZone->GetPadConnection() )
1533  {
1534  default:
1535  case PAD_ZONE_CONN_THERMAL: // Default option not saved or loaded.
1536  break;
1537 
1539  m_out->Print( 0, " thru_hole_only" );
1540  break;
1541 
1542  case PAD_ZONE_CONN_FULL:
1543  m_out->Print( 0, " yes" );
1544  break;
1545 
1546  case PAD_ZONE_CONN_NONE:
1547  m_out->Print( 0, " no" );
1548  break;
1549  }
1550 
1551  m_out->Print( 0, " (clearance %s))\n",
1552  FMT_IU( aZone->GetZoneClearance() ).c_str() );
1553 
1554  m_out->Print( aNestLevel+1, "(min_thickness %s)\n",
1555  FMT_IU( aZone->GetMinThickness() ).c_str() );
1556 
1557  if( aZone->GetIsKeepout() )
1558  {
1559  m_out->Print( aNestLevel+1, "(keepout (tracks %s) (vias %s) (copperpour %s))\n",
1560  aZone->GetDoNotAllowTracks() ? "not_allowed" : "allowed",
1561  aZone->GetDoNotAllowVias() ? "not_allowed" : "allowed",
1562  aZone->GetDoNotAllowCopperPour() ? "not_allowed" : "allowed" );
1563  }
1564 
1565  m_out->Print( aNestLevel+1, "(fill" );
1566 
1567  // Default is not filled.
1568  if( aZone->IsFilled() )
1569  m_out->Print( 0, " yes" );
1570 
1571  // Default is polygon filled.
1572  if( aZone->GetFillMode() )
1573  m_out->Print( 0, " (mode segment)" );
1574 
1575  m_out->Print( 0, " (arc_segments %d) (thermal_gap %s) (thermal_bridge_width %s)",
1576  aZone->GetArcSegmentCount(),
1577  FMT_IU( aZone->GetThermalReliefGap() ).c_str(),
1578  FMT_IU( aZone->GetThermalReliefCopperBridge() ).c_str() );
1579 
1581  {
1582  m_out->Print( 0, " (smoothing" );
1583 
1584  switch( aZone->GetCornerSmoothingType() )
1585  {
1587  m_out->Print( 0, " chamfer" );
1588  break;
1589 
1591  m_out->Print( 0, " fillet" );
1592  break;
1593 
1594  default:
1595  THROW_IO_ERROR( wxString::Format( _( "unknown zone corner smoothing type %d" ),
1596  aZone->GetCornerSmoothingType() ) );
1597  }
1598  m_out->Print( 0, ")" );
1599 
1600  if( aZone->GetCornerRadius() != 0 )
1601  m_out->Print( 0, " (radius %s)",
1602  FMT_IU( aZone->GetCornerRadius() ).c_str() );
1603  }
1604 
1605  m_out->Print( 0, ")\n" );
1606 
1607  int newLine = 0;
1608 
1609  if( aZone->GetNumCorners() )
1610  {
1611  bool new_polygon = true;
1612  bool is_closed = false;
1613 
1614  for( auto iterator = aZone->IterateWithHoles(); iterator; iterator++ )
1615  {
1616  if( new_polygon )
1617  {
1618  newLine = 0;
1619  m_out->Print( aNestLevel+1, "(polygon\n" );
1620  m_out->Print( aNestLevel+2, "(pts\n" );
1621  new_polygon = false;
1622  is_closed = false;
1623  }
1624 
1625  if( newLine == 0 )
1626  m_out->Print( aNestLevel+3, "(xy %s %s)",
1627  FMT_IU( iterator->x ).c_str(), FMT_IU( iterator->y ).c_str() );
1628  else
1629  m_out->Print( 0, " (xy %s %s)",
1630  FMT_IU( iterator->x ).c_str(), FMT_IU( iterator->y ).c_str() );
1631 
1632  if( newLine < 4 )
1633  {
1634  newLine += 1;
1635  }
1636  else
1637  {
1638  newLine = 0;
1639  m_out->Print( 0, "\n" );
1640  }
1641 
1642  if( iterator.IsEndContour() )
1643  {
1644  is_closed = true;
1645 
1646  if( newLine != 0 )
1647  m_out->Print( 0, "\n" );
1648 
1649  m_out->Print( aNestLevel+2, ")\n" );
1650  m_out->Print( aNestLevel+1, ")\n" );
1651  new_polygon = true;
1652  }
1653  }
1654 
1655  if( !is_closed ) // Should not happen, but...
1656  m_out->Print( aNestLevel+1, ")\n" );
1657 
1658  }
1659 
1660  // Save the PolysList (filled areas)
1661  const SHAPE_POLY_SET& fv = aZone->GetFilledPolysList();
1662  newLine = 0;
1663 
1664  if( !fv.IsEmpty() )
1665  {
1666  bool new_polygon = true;
1667  bool is_closed = false;
1668 
1669  for( auto it = fv.CIterate(); it; ++it )
1670  {
1671  if( new_polygon )
1672  {
1673  newLine = 0;
1674  m_out->Print( aNestLevel+1, "(filled_polygon\n" );
1675  m_out->Print( aNestLevel+2, "(pts\n" );
1676  new_polygon = false;
1677  is_closed = false;
1678  }
1679 
1680  if( newLine == 0 )
1681  m_out->Print( aNestLevel+3, "(xy %s %s)",
1682  FMT_IU( it->x ).c_str(), FMT_IU( it->y ).c_str() );
1683  else
1684  m_out->Print( 0, " (xy %s %s)",
1685  FMT_IU( it->x ) .c_str(), FMT_IU( it->y ).c_str() );
1686 
1687  if( newLine < 4 )
1688  {
1689  newLine += 1;
1690  }
1691  else
1692  {
1693  newLine = 0;
1694  m_out->Print( 0, "\n" );
1695  }
1696 
1697  if( it.IsEndContour() )
1698  {
1699  is_closed = true;
1700 
1701  if( newLine != 0 )
1702  m_out->Print( 0, "\n" );
1703 
1704  m_out->Print( aNestLevel+2, ")\n" );
1705  m_out->Print( aNestLevel+1, ")\n" );
1706  new_polygon = true;
1707  }
1708  }
1709 
1710  if( !is_closed ) // Should not happen, but...
1711  m_out->Print( aNestLevel+1, ")\n" );
1712  }
1713 
1714  // Save the filling segments list
1715  const std::vector< SEGMENT >& segs = aZone->FillSegments();
1716 
1717  if( segs.size() )
1718  {
1719  m_out->Print( aNestLevel+1, "(fill_segments\n" );
1720 
1721  for( std::vector< SEGMENT >::const_iterator it = segs.begin(); it != segs.end(); ++it )
1722  {
1723  m_out->Print( aNestLevel+2, "(pts (xy %s) (xy %s))\n",
1724  FMT_IU( it->m_Start ).c_str(),
1725  FMT_IU( it->m_End ).c_str() );
1726  }
1727 
1728  m_out->Print( aNestLevel+1, ")\n" );
1729  }
1730 
1731  m_out->Print( aNestLevel, ")\n" );
1732 }
1733 
1734 
1735 PCB_IO::PCB_IO( int aControlFlags ) :
1736  m_cache( 0 ),
1737  m_ctl( aControlFlags ),
1738  m_parser( new PCB_PARSER() ),
1739  m_mapping( new NETINFO_MAPPING() )
1740 {
1741  init( 0 );
1742  m_out = &m_sf;
1743 }
1744 
1745 
1747 {
1748  delete m_cache;
1749  delete m_parser;
1750  delete m_mapping;
1751 }
1752 
1753 
1754 BOARD* PCB_IO::Load( const wxString& aFileName, BOARD* aAppendToMe, const PROPERTIES* aProperties )
1755 {
1756  FILE_LINE_READER reader( aFileName );
1757 
1758  init( aProperties );
1759 
1760  m_parser->SetLineReader( &reader );
1761  m_parser->SetBoard( aAppendToMe );
1762 
1763  BOARD* board;
1764 
1765  try
1766  {
1767  board = dynamic_cast<BOARD*>( m_parser->Parse() );
1768  }
1769  catch( const FUTURE_FORMAT_ERROR& )
1770  {
1771  // Don't wrap a FUTURE_FORMAT_ERROR in another
1772  throw;
1773  }
1774  catch( const PARSE_ERROR& parse_error )
1775  {
1776  if( m_parser->IsTooRecent() )
1777  throw FUTURE_FORMAT_ERROR( parse_error, m_parser->GetRequiredVersion() );
1778  else
1779  throw;
1780  }
1781 
1782  if( !board )
1783  {
1784  // The parser loaded something that was valid, but wasn't a board.
1785  THROW_PARSE_ERROR( _( "this file does not contain a PCB" ),
1788  }
1789 
1790  // Give the filename to the board if it's new
1791  if( !aAppendToMe )
1792  board->SetFileName( aFileName );
1793 
1794  return board;
1795 }
1796 
1797 
1798 void PCB_IO::init( const PROPERTIES* aProperties )
1799 {
1800  m_board = NULL;
1801  m_reader = NULL;
1803  m_props = aProperties;
1804 }
1805 
1806 
1807 void PCB_IO::cacheLib( const wxString& aLibraryPath, const wxString& aFootprintName )
1808 {
1809  if( !m_cache || m_cache->IsModified( aLibraryPath, aFootprintName ) )
1810  {
1811  // a spectacular episode in memory management:
1812  delete m_cache;
1813  m_cache = new FP_CACHE( this, aLibraryPath );
1814  m_cache->Load();
1815  }
1816 }
1817 
1818 
1819 void PCB_IO::FootprintEnumerate( wxArrayString& aFootprintNames,
1820  const wxString& aLibraryPath,
1821  const PROPERTIES* aProperties )
1822 {
1823  LOCALE_IO toggle; // toggles on, then off, the C locale.
1824  wxDir dir( aLibraryPath );
1825 
1826  if( !dir.IsOpened() )
1827  {
1828  THROW_IO_ERROR( wxString::Format( _( "footprint library path '%s' does not exist" ),
1829  GetChars( aLibraryPath ) ) );
1830  }
1831 
1832  init( aProperties );
1833 
1834  wxString errorMsg;
1835 
1836  // Some of the files may have been parsed correctly so we want to add the valid files to
1837  // the library.
1838  try
1839  {
1840  cacheLib( aLibraryPath );
1841  }
1842  catch( const IO_ERROR& ioe )
1843  {
1844  errorMsg = ioe.What();
1845  }
1846 
1847  const MODULE_MAP& mods = m_cache->GetModules();
1848 
1849  for( MODULE_CITER it = mods.begin(); it != mods.end(); ++it )
1850  {
1851  aFootprintNames.Add( FROM_UTF8( it->first.c_str() ) );
1852  }
1853 
1854  if( !errorMsg.IsEmpty() )
1855  THROW_IO_ERROR( errorMsg );
1856 }
1857 
1858 
1859 MODULE* PCB_IO::FootprintLoad( const wxString& aLibraryPath, const wxString& aFootprintName,
1860  const PROPERTIES* aProperties )
1861 {
1862  LOCALE_IO toggle; // toggles on, then off, the C locale.
1863 
1864  init( aProperties );
1865 
1866  cacheLib( aLibraryPath, aFootprintName );
1867 
1868  const MODULE_MAP& mods = m_cache->GetModules();
1869 
1870  MODULE_CITER it = mods.find( TO_UTF8( aFootprintName ) );
1871 
1872  if( it == mods.end() )
1873  {
1874  return NULL;
1875  }
1876 
1877  // copy constructor to clone the already loaded MODULE
1878  return new MODULE( *it->second->GetModule() );
1879 }
1880 
1881 
1882 void PCB_IO::FootprintSave( const wxString& aLibraryPath, const MODULE* aFootprint,
1883  const PROPERTIES* aProperties )
1884 {
1885  LOCALE_IO toggle; // toggles on, then off, the C locale.
1886 
1887  init( aProperties );
1888 
1889  // In this public PLUGIN API function, we can safely assume it was
1890  // called for saving into a library path.
1892 
1893  cacheLib( aLibraryPath );
1894 
1895  if( !m_cache->IsWritable() )
1896  {
1897  wxString msg = wxString::Format(
1898  _( "Library '%s' is read only" ),
1899  GetChars( aLibraryPath )
1900  );
1901 
1902  THROW_IO_ERROR( msg );
1903  }
1904 
1905  std::string footprintName = aFootprint->GetFPID().GetLibItemName();
1906 
1907  MODULE_MAP& mods = m_cache->GetModules();
1908 
1909  // Quietly overwrite module and delete module file from path for any by same name.
1910  wxFileName fn( aLibraryPath, FROM_UTF8( aFootprint->GetFPID().GetLibItemName() ),
1912 
1913  if( !fn.IsOk() )
1914  {
1915  THROW_IO_ERROR( wxString::Format( _( "Footprint file name '%s' is not valid." ),
1916  GetChars( fn.GetFullPath() ) ) );
1917  }
1918 
1919  if( fn.FileExists() && !fn.IsFileWritable() )
1920  {
1921  THROW_IO_ERROR( wxString::Format( _( "user does not have write permission to delete file '%s' " ),
1922  GetChars( fn.GetFullPath() ) ) );
1923  }
1924 
1925  MODULE_CITER it = mods.find( footprintName );
1926 
1927  if( it != mods.end() )
1928  {
1929  wxLogTrace( traceFootprintLibrary, wxT( "Removing footprint library file '%s'." ),
1930  fn.GetFullPath().GetData() );
1931  mods.erase( footprintName );
1932  wxRemoveFile( fn.GetFullPath() );
1933  }
1934 
1935  // I need my own copy for the cache
1936  MODULE* module = new MODULE( *aFootprint );
1937 
1938  // and it's time stamp must be 0, it should have no parent, orientation should
1939  // be zero, and it should be on the front layer.
1940  module->SetTimeStamp( 0 );
1941  module->SetParent( 0 );
1942  module->SetOrientation( 0 );
1943 
1944  if( module->GetLayer() != F_Cu )
1945  module->Flip( module->GetPosition() );
1946 
1947  wxLogTrace( traceFootprintLibrary, wxT( "Creating s-expression footprint file: %s." ),
1948  fn.GetFullPath().GetData() );
1949  mods.insert( footprintName, new FP_CACHE_ITEM( module, fn ) );
1950  m_cache->Save();
1951 }
1952 
1953 
1954 void PCB_IO::FootprintDelete( const wxString& aLibraryPath, const wxString& aFootprintName, const PROPERTIES* aProperties )
1955 {
1956  LOCALE_IO toggle; // toggles on, then off, the C locale.
1957 
1958  init( aProperties );
1959 
1960  cacheLib( aLibraryPath );
1961 
1962  if( !m_cache->IsWritable() )
1963  {
1964  THROW_IO_ERROR( wxString::Format( _( "Library '%s' is read only" ),
1965  aLibraryPath.GetData() ) );
1966  }
1967 
1968  m_cache->Remove( aFootprintName );
1969 }
1970 
1971 
1972 void PCB_IO::FootprintLibCreate( const wxString& aLibraryPath, const PROPERTIES* aProperties )
1973 {
1974  if( wxDir::Exists( aLibraryPath ) )
1975  {
1976  THROW_IO_ERROR( wxString::Format( _( "cannot overwrite library path '%s'" ),
1977  aLibraryPath.GetData() ) );
1978  }
1979 
1980  LOCALE_IO toggle;
1981 
1982  init( aProperties );
1983 
1984  delete m_cache;
1985  m_cache = new FP_CACHE( this, aLibraryPath );
1986  m_cache->Save();
1987 }
1988 
1989 
1990 bool PCB_IO::FootprintLibDelete( const wxString& aLibraryPath, const PROPERTIES* aProperties )
1991 {
1992  wxFileName fn;
1993  fn.SetPath( aLibraryPath );
1994 
1995  // Return if there is no library path to delete.
1996  if( !fn.DirExists() )
1997  return false;
1998 
1999  if( !fn.IsDirWritable() )
2000  {
2001  THROW_IO_ERROR( wxString::Format( _( "user does not have permission to delete directory '%s'" ),
2002  aLibraryPath.GetData() ) );
2003  }
2004 
2005  wxDir dir( aLibraryPath );
2006 
2007  if( dir.HasSubDirs() )
2008  {
2009  THROW_IO_ERROR( wxString::Format( _( "library directory '%s' has unexpected sub-directories" ),
2010  aLibraryPath.GetData() ) );
2011  }
2012 
2013  // All the footprint files must be deleted before the directory can be deleted.
2014  if( dir.HasFiles() )
2015  {
2016  unsigned i;
2017  wxFileName tmp;
2018  wxArrayString files;
2019 
2020  wxDir::GetAllFiles( aLibraryPath, &files );
2021 
2022  for( i = 0; i < files.GetCount(); i++ )
2023  {
2024  tmp = files[i];
2025 
2026  if( tmp.GetExt() != KiCadFootprintFileExtension )
2027  {
2028  THROW_IO_ERROR( wxString::Format( _( "unexpected file '%s' was found in library path '%s'" ),
2029  files[i].GetData(), aLibraryPath.GetData() ) );
2030  }
2031  }
2032 
2033  for( i = 0; i < files.GetCount(); i++ )
2034  {
2035  wxRemoveFile( files[i] );
2036  }
2037  }
2038 
2039  wxLogTrace( traceFootprintLibrary, wxT( "Removing footprint library '%s'" ),
2040  aLibraryPath.GetData() );
2041 
2042  // Some of the more elaborate wxRemoveFile() crap puts up its own wxLog dialog
2043  // we don't want that. we want bare metal portability with no UI here.
2044  if( !wxRmdir( aLibraryPath ) )
2045  {
2046  THROW_IO_ERROR( wxString::Format( _( "footprint library '%s' cannot be deleted" ),
2047  aLibraryPath.GetData() ) );
2048  }
2049 
2050  // For some reason removing a directory in Windows is not immediately updated. This delay
2051  // prevents an error when attempting to immediately recreate the same directory when over
2052  // writing an existing library.
2053 #ifdef __WINDOWS__
2054  wxMilliSleep( 250L );
2055 #endif
2056 
2057  if( m_cache && !m_cache->IsPath( aLibraryPath ) )
2058  {
2059  delete m_cache;
2060  m_cache = NULL;
2061  }
2062 
2063  return true;
2064 }
2065 
2066 
2067 bool PCB_IO::IsFootprintLibWritable( const wxString& aLibraryPath )
2068 {
2069  LOCALE_IO toggle;
2070 
2071  init( NULL );
2072 
2073  cacheLib( aLibraryPath );
2074 
2075  return m_cache->IsWritable();
2076 }
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Function AllCuMask returns a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:639
friend class FP_CACHE
KICAD_T Type() const
Function Type()
Definition: base_struct.h:198
wxString GetPath() const
#define DIM(x)
of elements in an array
Definition: macros.h:98
int m_SolderMaskMargin
Solder mask margin.
BOARD_ITEM_CONTAINER * GetParent() const
const wxString KiCadFootprintFileExtension
Class ZONE_CONTAINER handles a list of polygons defining a copper zone.
Definition: class_zone.h:78
iterator begin() const
Function begin() Returns iterator to the first entry in the mapping.
OUTPUTFORMATTER * m_out
output any Format()s to this, no ownership
LINE_READER * m_reader
no ownership here.
TEXTE_MODULE & Reference()
Definition: class_module.h:463
std::unique_ptr< MODULE > m_module
const ZONE_SETTINGS & GetZoneSettings() const
Definition: class_board.h:557
int GetVisibleElements() const
Function GetVisibleElements returns a bit-mask of all the element categories that are visible...
Definition: typeinfo.h:97
#define CTL_OMIT_AT
Omit position and rotation.
int GetThermalGap() const
Definition: class_module.h:195
BOARD_ITEM * Parse(const wxString &aClipboardSourceInput)
const wxPoint & GetBezControl2() const
PCB_TARGET class definition.
Class PCB_IO is a PLUGIN derivation for saving and loading Pcbnew s-expression formatted files...
BOARD * Load(const wxString &aFileName, BOARD *aAppendToMe, const PROPERTIES *aProperties=NULL) override
Function Load loads information from some input file format that this PLUGIN implementation knows abo...
NETCLASSPTR GetDefault() const
Function GetDefault.
int GetNumCorners(void) const
Access to m_Poly parameters.
Definition: class_zone.h:465
time_t GetLastEditTime() const
Definition: class_module.h:284
static wxString FROM_UTF8(const char *cstring)
function FROM_UTF8 converts a UTF8 encoded C string to a wxString for all wxWidgets build modes...
Definition: macros.h:53
PAD_ATTR_T GetAttribute() const
Definition: class_pad.h:238
TEXTE_PCB class definition.
const wxPoint & GetTextPos() const
Definition: eda_text.h:224
const wxPoint & GetGridOrigin() const
Definition: class_board.h:342
like PAD_STANDARD, but not plated mechanical use only, no connection allowed
Definition: pad_shapes.h:63
int m_SolderPasteMargin
Solder paste margin absolute value.
Class LOCALE_IO is a class that can be instantiated within a scope in which you are expecting excepti...
Definition: common.h:166
wxFileName m_lib_path
Plugin object that owns the cache.
Implementation of conversion functions that require both schematic and board internal units...
int GetMinThickness() const
Definition: class_zone.h:209
wxPoint m_crossBarF
int GetWidth() const
Definition: class_mire.h:72
int m_ModuleTextWidth
Default footprint texts thickness.
Class BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class...
bool GetDoNotAllowCopperPour() const
Definition: class_zone.h:655
int GetLocalClearance() const
Definition: class_module.h:179
std::vector< int > m_TrackWidthList
Track width list.
int m_ModuleSegmentWidth
Default width for all graphic lines.
wxPoint m_arrowD1F
TEXT_TYPE GetType() const
FP_CACHE * m_cache
Footprint library cache.
int GetArcSegmentCount() const
Definition: class_zone.h:198
const wxPoint & GetPos0() const
Class PCB_PARSER reads a Pcbnew s-expression formatted LINE_READER object and returns the appropriate...
Definition: pcb_parser.h:66
int m_PcbTextWidth
current Pcb (not module) Text width
const PROPERTIES * m_props
passed via Save() or Load(), no ownership, may be NULL.
void Flip(const wxPoint &aCentre) override
Function Flip Flip this object, i.e.
int GetWidth() const
LSEQ CuStack() const
Function CuStack returns a sequence of copper layers in starting from the front/top and extending to ...
Definition: lset.cpp:147
int GetPadToDieLength() const
Definition: class_pad.h:241
Class BOARD to handle a board.
void init(const PROPERTIES *aProperties)
const wxPoint & GetPosition() const override
Definition: class_module.h:155
bool IsFilled() const
Definition: class_zone.h:200
polygon (not yet used for tracks, but could be in microwave apps)
int GetLocalSolderMaskMargin() const
Definition: class_pad.h:243
MODULE * Next() const
Definition: class_module.h:100
const wxPoint & GetEnd0() const
Smd pad, appears on the solder paste layer (default)
Definition: pad_shapes.h:59
CONST_ITERATOR CIterate(int aFirst, int aLast, bool aIterateHoles=false) const
class ZONE_CONTAINER, a zone area
Definition: typeinfo.h:114
boost::ptr_map< std::string, FP_CACHE_ITEM > MODULE_MAP
void formatLayer(const BOARD_ITEM *aItem) const
Set for modules listed in the automatic insertion list (usually SMD footprints)
Definition: class_module.h:77
#define SEXPR_BOARD_FILE_VERSION
Current s-expression file format version. 2 was the last legacy format version.
class TEXTE_PCB, text on a layer
Definition: typeinfo.h:104
void FootprintEnumerate(wxArrayString &aFootprintNames, const wxString &aLibraryPath, const PROPERTIES *aProperties=NULL) override
Return a list of footprint names contained within the library at aLibraryPath.
wxString GetName() const
Classes to handle copper zones.
const wxPoint & GetPos0() const
Definition: class_pad.h:176
int GetCornerSmoothingType() const
Definition: class_zone.h:612
PAD_DRILL_SHAPE_T GetDrillShape() const
Definition: class_pad.h:221
bool IsFootprintLibWritable(const wxString &aLibraryPath) override
Function IsFootprintLibWritable returns true iff the library at aLibraryPath is writable.
usual segment : line with rounded ends
class D_PAD, a pad in a footprint
Definition: typeinfo.h:102
iterator end()
std::string Double2Str(double aValue)
Helper function Double2Str to print a float number without using scientific notation and no trailing ...
Definition: base_units.cpp:60
const std::vector< wxPoint > & GetPolyPoints() const
bool IsModified(const wxString &aLibPath, const wxString &aFootprintName=wxEmptyString) const
Function IsModified check if the footprint cache has been modified relative to aLibPath and aFootprin...
wxPoint m_featureLineDF
ZoneConnection GetZoneConnection() const
Definition: class_module.h:189
wxFileName GetFileName() const
std::list< S3D_INFO > & Models()
Definition: class_module.h:150
const wxSize & GetDrillSize() const
Definition: class_pad.h:188
int GetPlacementCost90() const
Definition: class_module.h:533
Class LIB_ID.
Definition: lib_id.h:56
STATUS_FLAGS GetStatus() const
Definition: base_struct.h:250
wxSize m_ModuleTextSize
Default footprint texts size.
Class PROPERTIES is a name/value tuple with unique names and optional values.
Definition: properties.h:34
#define cu(a)
Definition: auxiliary.h:88
int GetThermalReliefCopperBridge(D_PAD *aPad=NULL) const
Definition: class_zone.cpp:466
PAD_SHAPE_T GetShape() const
Function GetShape.
Definition: class_pad.h:166
int GetDrill() const
Function GetDrill returns the local drill setting for this VIA.
Definition: class_track.h:454
LSET GetEnabledLayers() const
Function GetEnabledLayers is a proxy function that calls the corresponding function in m_BoardSetting...
unsigned int GetCornerRadius() const
Definition: class_zone.h:616
wxString GetLayerName() const
Function GetLayerName returns the name of the PCB layer on which the item resides.
class EDGE_MODULE, a footprint edge
Definition: typeinfo.h:106
double GetLocalSolderPasteMarginRatio() const
Definition: class_module.h:185
NETCLASS_MAP::const_iterator const_iterator
FP_CACHE_ITEM(MODULE *aModule, const wxFileName &aFileName)
const wxPoint & GetEnd() const
Definition: class_track.h:118
iterator begin()
void SetTimeStamp(time_t aNewTimeStamp)
Definition: base_struct.h:203
double GetTextAngle() const
Definition: eda_text.h:164
Functions relatives to tracks, vias and segments used to fill zones.
iterator end() const
Function end() Returns iterator to the last entry in the mapping.
class TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:107
void Format(OUTPUTFORMATTER *aFormatter, int aNestLevel, int aControlBits) const
Function Format outputs the net class to aFormatter in s-expression form.
This file contains miscellaneous commonly used macros and functions.
static const char * ShowType(LAYER_T aType)
Function ShowType converts a LAYER_T enum to a const char*.
const wxString & CurSource()
Function CurFilename returns the current LINE_READER source.
Definition: dsnlexer.h:528
void UpdateModificationTime()
void SetOutputFormatter(OUTPUTFORMATTER *aFormatter)
void SetBoard(const BOARD *aBoard)
Function SetBoard Sets a BOARD object that is used to prepare the net code map.
Pads are not covered.
Definition: zones.h:57
wxPoint m_featureLineGO
bool GetIsKeepout() const
Accessors to parameters used in Keepout zones:
Definition: class_zone.h:654
LSEQ Seq(const PCB_LAYER_ID *aWishListSequence, unsigned aCount) const
Function Seq returns an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:337
int StrPrintf(std::string *result, const char *format,...)
Function StrPrintf is like sprintf() but the output is appended to a std::string instead of to a char...
Definition: richio.cpp:75
BOARD_ITEM * Next() const
MODULE * GetModule() const
const LIB_ID & GetFPID() const
Definition: class_module.h:164
#define TO_UTF8(wxstring)
Macro TO_UTF8 converts a wxString to a UTF8 encoded C string for all wxWidgets build modes...
Definition: macros.h:47
std::vector< SEGMENT > & FillSegments()
Definition: class_zone.h:244
DIMENSION class definition.
MODULE_MAP m_modules
Footprint library path modified time stamp.
class MODULE, a footprint
Definition: typeinfo.h:101
void Remove(const wxString &aFootprintName)
MODULE_MAP::const_iterator MODULE_CITER
PCB_IO(int aControlFlags=CTL_FOR_BOARD)
STRINGSET::iterator iterator
PCB_LAYER_ID
A quick note on layer IDs:
Class FILE_LINE_READER is a LINE_READER that reads from an open file.
Definition: richio.h:180
STROKE_T GetShape() const
wxString GetRequiredVersion()
Return a string representing the version of kicad required to open this file.
Definition: pcb_parser.cpp:182
int GetShape() const
Definition: class_mire.h:66
void FootprintLibCreate(const wxString &aLibraryPath, const PROPERTIES *aProperties=NULL) override
Function FootprintLibCreate creates a new empty footprint library at aLibraryPath empty...
Class LSET is a set of PCB_LAYER_IDs.
iterator begin()
#define THROW_PARSE_ERROR(aProblem, aSource, aInputLine, aLineNumber, aByteIndex)
Definition: ki_exception.h:133
ZoneConnection GetPadConnection(D_PAD *aPad=NULL) const
Definition: class_zone.cpp:814
void SetBoard(BOARD *aBoard)
Definition: pcb_parser.h:303
const wxPoint & GetEnd() const
Function GetEnd returns the ending point of the graphic.
int GetSize() const
Function GetSize.
VIATYPE_T GetViaType() const
Definition: class_track.h:439
void FootprintSave(const wxString &aLibraryPath, const MODULE *aFootprint, const PROPERTIES *aProperties=NULL) override
Function FootprintSave will write aModule to an existing library located at aLibraryPath.
iterator end()
wxString GetBuildVersion()
Function GetBuildVersion Return the build version string.
bool IsPath(const wxString &aPath) const
Function IsPath checks if aPath is the same as the current cache path.
void SetParent(EDA_ITEM *aParent)
Definition: base_struct.h:213
wxFileName m_file_name
The the full file name and path of the footprint to cache.
int Translate(int aNetCode) const
Function Translate Translates net number according to the map prepared by Update() function...
double GetOrientation() const
Definition: class_module.h:160
Class SHAPE_POLY_SET.
TEXTE_MODULE & Value()
read/write accessors:
Definition: class_module.h:462
wxSize m_PcbTextSize
current Pcb (not module) Text size
MODULE * FootprintLoad(const wxString &aLibraryPath, const wxString &aFootprintName, const PROPERTIES *aProperties=NULL) override
Function FootprintLoad loads a footprint having aFootprintName from the aLibraryPath containing a lib...
C++ does not put enum values in separate namespaces unless the enum itself is in a separate namespace...
Definition: pcb_lexer.h:23
const UTF8 & GetLibItemName() const
Function GetLibItemName.
Definition: lib_id.h:129
const wxPoint & GetStart() const
Definition: class_track.h:121
int m_TrackMinWidth
track min value for width ((min copper size value
const wxString & GetText() const
Function GetText returns the string associated with the text object.
Definition: eda_text.h:130
Arcs (with rounded ends)
wxDateTime m_mod_time
The path of the library.
static const wxString traceFootprintLibrary(wxT("KicadFootprintLib"))
Definition for enabling and disabling footprint library trace output.
int m_ViasMinSize
vias (not micro vias) min diameter
int m_loading_format_version
which SEXPR_BOARD_FILE_VERSION should be Load()ed?
Class NETCLASS handles a collection of nets and the parameters used to route or test these nets...
ZoneConnection GetZoneConnection() const
Definition: class_pad.cpp:610
LSET GetLayerSet() const override
Function GetLayerSet returns a "layer mask", which is a bitmap of all layers on which the TRACK segme...
Definition: class_pad.h:235
wxPoint m_arrowG1F
int GetThermalReliefGap(D_PAD *aPad=NULL) const
Definition: class_zone.cpp:457
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Function GetLayerName returns the name of a layer given by aLayer.
int m_DrawSegmentWidth
current graphic line width (not EDGE layer)
wxPoint m_arrowD2F
wxPoint m_arrowG2F
int GetThermalWidth() const
Definition: class_pad.cpp:621
bool IsModified() const
Tell if the disk content or the lib_path has changed.
int m_ViasMinDrill
vias (not micro vias) min drill diameter
D_PAD * Next() const
Definition: class_pad.h:106
int CurOffset()
Function CurOffset returns the byte offset within the current line, using a 1 based index...
Definition: dsnlexer.h:538
int GetThermalGap() const
Definition: class_pad.cpp:632
The common library.
const PCB_PLOT_PARAMS & GetPlotOptions() const
Definition: class_board.h:551
const wxSize & GetSize() const
Definition: class_pad.h:182
#define FMT_IU
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Function GetDesignSettings.
Definition: class_board.h:533
int m_ZoneClearance
Clearance value.
int GetAttributes() const
Definition: class_module.h:197
virtual void Format(OUTPUTFORMATTER *aFormatter, int aNestLevel, int aControlBits) const
Function Format outputs the object to aFormatter in s-expression form.
Definition: worksheet.cpp:245
PCB_IO * m_owner
const wxString & GetKeywords() const
Definition: class_module.h:170
const wxPoint & GetBezControl1() const
bool m_BlindBuriedViaAllowed
true to allow blind/buried vias
int GetLocalSolderPasteMargin() const
Definition: class_pad.h:249
std::string Quotew(const wxString &aWrapee)
Definition: richio.cpp:486
int GetAreaCount() const
Function GetAreaCount.
Definition: class_board.h:1025
#define THROW_IO_ERROR(x)
Definition: utf8.cpp:60
void SetFileName(const wxString &aFileName)
Definition: class_board.h:232
Bezier Curve.
#define UNDEFINED_DRILL_DIAMETER
Definition: class_track.h:58
PCB_PARSER * m_parser
int GetNet() const
Function GetNet.
int GetLocalSolderMaskMargin() const
Definition: class_module.h:176
#define CTL_OMIT_NETS
Omit pads net names (useless in library)
Wrapper class, so you can iterate through NETINFO_ITEM*s, not std::pair
BOARD_ITEM * Parse()
Definition: pcb_parser.cpp:405
#define CTL_OMIT_PATH
Omit component sheet time stamp (useless in library)
Class FP_CACHE_ITEM is helper class for creating a footprint library cache.
int m_MicroViasMinSize
micro vias (not vias) min diameter
void Format(BOARD_ITEM *aItem, int aNestLevel=0) const
Function Format outputs aItem to aFormatter in s-expression format.
Like smd, does not appear on the solder paste layer (default) note also has a special attribute in Ge...
Definition: pad_shapes.h:60
class DIMENSION, a dimension (graphic item)
Definition: typeinfo.h:112
bool IsLocked() const override
Function IsLocked.
Definition: class_module.h:236
NETINFO_MAPPING * m_mapping
mapping for net codes, so only not empty net codes are stored with consecutive integers as net codes ...
bool IsWritable() const
const SHAPE_POLY_SET & GetFilledPolysList() const
Function GetFilledPolysList returns a reference to the list of filled polygons.
Definition: class_zone.h:582
int GetNumSegmTrack() const
Functions to get some items count.
Thermal relief only for THT pads.
Definition: zones.h:60
Class LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
const PAGE_INFO & GetPageSettings() const
Definition: class_board.h:548
int GetLocalClearance() const
Definition: class_pad.h:246
LINE_READER * SetLineReader(LINE_READER *aReader)
Function SetLineReader sets aLineReader into the parser, and returns the previous one...
Definition: pcb_parser.h:296
class PCB_TARGET, a target (graphic item)
Definition: typeinfo.h:113
void LayerPair(PCB_LAYER_ID *top_layer, PCB_LAYER_ID *bottom_layer) const
Function LayerPair Return the 2 layers used by the via (the via actually uses all layers between thes...
int LAYER_NUM
Type LAYER_NUM can be replaced with int and removed.
int GetLocalSolderPasteMargin() const
Definition: class_module.h:182
time_t GetTimeStamp() const
Definition: base_struct.h:204
double GetLocalSolderPasteMarginRatio() const
Definition: class_pad.h:252
void FootprintDelete(const wxString &aLibraryPath, const wxString &aFootprintName, const PROPERTIES *aProperties=NULL) override
Function FootprintDelete deletes aFootprintName from the library at aLibraryPath. ...
default
Definition: class_module.h:76
int GetNetCode() const
Function GetNetCode.
const char * CurLine()
Function CurLine returns the current line of text, from which the CurText() would return its token...
Definition: dsnlexer.h:517
class TEXTE_MODULE, text in a footprint
Definition: typeinfo.h:105
const wxPoint & GetAuxOrigin() const
Definition: class_board.h:335
wxDateTime m_mod_time
The last file modified time stamp.
virtual std::string Quotes(const std::string &aWrapee)
Function Quotes checks aWrapee input string for a need to be quoted (e.g.
Definition: richio.cpp:437
wxString GetSelectMenuText() const override
Function GetSelectMenuText returns the text to display to be used in the selection clarification cont...
void Load()
Class NETINFO_ITEM handles the data for a net.
Definition: class_netinfo.h:69
PCB_LAYER_ID GetLayer() const
Function GetLayer returns the primary layer this item is on.
bool IsTooRecent()
Return whether a version number, if any was parsed, was too recent.
Definition: pcb_parser.h:314
void Format(OUTPUTFORMATTER *aFormatter, int aNestLevel, int aControlBits) const
Function GetStandardSizes returns the standard page types, such as "A4", "A3", etc.
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:33
void Remove(iterator aName)
Function Remove will remove NET name aName from the collection of members.
Struct PARSE_ERROR contains a filename or source description, a problem input line, a line number, a byte offset, and an error message which contains the the caller's report and his call site information: CPP source file, function, and line number.
Definition: ki_exception.h:94
bool GetDoNotAllowTracks() const
Definition: class_zone.h:657
STRING_FORMATTER m_sf
#define CTL_FOR_LIBRARY
Format output for a footprint library instead of clipboard or BOARD.
const wxPoint & GetPosition() const override
Definition: class_mire.h:63
TRACK * Next() const
Definition: class_track.h:98
void Save()
save the entire legacy library to m_lib_name;
static const wxChar * GetChars(const wxString &s)
Function GetChars returns a wxChar* to the actual wxChar* data within a wxString, and is helpful for ...
Definition: macros.h:92
double GetAngle() const
virtual wxString GetClass() const =0
Function GetClass returns the class name.
TITLE_BLOCK & GetTitleBlock()
Definition: class_board.h:554
const wxString & GetNetname() const
Function GetNetname.
ZONE_CONTAINER * GetArea(int index) const
Function GetArea returns the Area (Zone Container) at a given index.
Definition: class_board.h:996
int GetFillMode() const
Definition: class_zone.h:186
double GetRoundRectRadiusRatio() const
has meaning only for rounded rect pads
Definition: class_pad.h:450
Class to handle a graphic segment.
const wxPoint & GetStart0() const
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
const wxString & GetDescription() const
Definition: class_module.h:167
bool GetDoNotAllowVias() const
Definition: class_zone.h:656
Class BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:169
DLIST< MODULE > m_Modules
Definition: class_board.h:245
bool IsVisible() const
Definition: eda_text.h:176
int GetWidth() const
Definition: class_track.h:115
void SetOrientation(double newangle)
SHAPE_POLY_SET::ITERATOR IterateWithHoles()
Function IterateWithHoles returns an iterator to visit all points of the zone's main outline with hol...
Definition: class_zone.h:485
Virtual component: when created by copper shapes on board (Like edge card connectors, mounting hole...)
Definition: class_module.h:79
#define CTL_OMIT_TSTAMPS
Omit component time stamp (useless in library)
T NormalizeAnglePos(T Angle)
Normalize angle to be in the 0.0 .
Definition: trigo.h:214
TEXTE_PCB & Text()
LSET GetVisibleLayers() const
Function GetVisibleLayers is a proxy function that calls the correspondent function in m_BoardSetting...
#define CTL_STD_LAYER_NAMES
Use English Standard layer names.
double GetOrientation() const
Function GetOrientation returns the rotation angle of the pad in tenths of degrees, but soon degrees.
Definition: class_pad.h:214
D_PAD m_Pad_Master
A dummy pad to store all default parameters.
int GetNumSegmZone() const
Calculate the zone segment count.
void format(BOARD *aBoard, int aNestLevel=0) const
BOARD * m_board
which BOARD, no ownership here
const wxSize & GetDelta() const
Definition: class_pad.h:185
Usual pad.
Definition: pad_shapes.h:58
HATCH_STYLE GetHatchStyle() const
Definition: class_zone.h:549
int CurLineNumber()
Function CurLineNumber returns the current line number within my LINE_READER.
Definition: dsnlexer.h:507
NETINFO_ITEM * FindNet(int aNetcode) const
Function FindNet searches for a net with the given netcode.
The common library.
int GetWidth() const
std::vector< VIA_DIMENSION > m_ViasDimensionsList
Vias size and drill list.
UTF8 Format() const
Function Format.
Definition: lib_id.cpp:263
const char * name
Class FILE_OUTPUTFORMATTER may be used for text file output.
Definition: richio.h:492
int GetSize() const
Definition: class_mire.h:69
unsigned GetCount() const
Function GetCount returns the number of elements in the list.
Definition: dlist.h:126
void formatLayers(LSET aLayerMask, int aNestLevel=0) const
wxPoint m_crossBarO
wxDateTime GetLastModificationTime() const
DLIST< BOARD_ITEM > & GraphicalItemsList()
Definition: class_module.h:137
class VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:108
wxString GetPadName() const
Definition: class_pad.cpp:433
Pcbnew s-expression file format parser definition.
DLIST< D_PAD > & PadsList()
Definition: class_module.h:134
DLIST< TRACK > m_Track
Definition: class_board.h:246
int GetHatchPitch() const
Hatch related methods.
Definition: class_zone.cpp:914
void filterNetClass(const BOARD &aBoard, NETCLASS &aNetClass)
Removes empty nets (i.e. with node count equal zero) from net classes
Struct FUTURE_FORMAT_ERROR variant of PARSE_ERROR indicating that a syntax or related error was likel...
Definition: ki_exception.h:143
FP_CACHE(PCB_IO *aOwner, const wxString &aLibraryPath)
Map of footprint file name per MODULE*.
Module description (excepted pads)
bool IsEmpty() const
Returns true if the set is empty (no polygons at all)
bool m_MicroViasAllowed
true to allow micro vias
int GetValue() const
int m_MicroViasMinDrill
micro vias (not vias) min drill diameter
void Format(OUTPUTFORMATTER *aFormatter, int aNestLevel, int aControl=0) const
int PRINTF_FUNC Print(int nestLevel, const char *fmt,...)
Function Print formats and writes text to the output stream.
Definition: richio.cpp:408
#define CTL_OMIT_INITIAL_COMMENTS
omit MODULE initial comments
MODULE_MAP::iterator MODULE_ITER
const wxString & GetPath() const
Definition: class_module.h:173
int m_EdgeSegmentWidth
current graphic line width (EDGE layer only)
double m_SolderPasteMarginRatio
Solder pask margin ratio value of pad size The final margin is the sum of these 2 values...
unsigned GetPriority() const
Function GetPriority.
Definition: class_zone.h:119
int GetCurrentTrackWidth() const
Function GetCurrentTrackWidth.
EDGE_MODULE class definition.
class DRAWSEGMENT, a segment not on copper layers
Definition: typeinfo.h:103
bool FootprintLibDelete(const wxString &aLibraryPath, const PROPERTIES *aProperties=NULL) override
Function FootprintLibDelete deletes an existing footprint library and returns true, or if library does not exist returns false, or throws an exception if library exists but is read only or cannot be deleted for some other reason.
const wxArrayString * GetInitialComments() const
Return the initial comments block or NULL if none, without transfer of ownership. ...
Definition: class_module.h:648
const wxPoint & GetStart() const
Function GetStart returns the starting point of the graphic.
#define FMT_ANGLE
Class STRING_LINE_READER is a LINE_READER that reads from a multiline 8 bit wide std::string.
Definition: richio.h:254
#define CTL_OMIT_HIDE
Definition: eda_text.h:42
bool IsPlaced() const
Definition: class_module.h:254
wxPoint m_featureLineDO
#define FMTIU
static const int UNCONNECTED
Constant that holds the "unconnected net" number (typically 0) all items "connected" to this net are ...
Struct IO_ERROR is a class used to hold an error message and may be used when throwing exceptions con...
Definition: ki_exception.h:47
int GetPlacementCost180() const
Definition: class_module.h:530
LAYER_T GetLayerType(PCB_LAYER_ID aLayer) const
Function GetLayerType returns the type of the copper layer given by aLayer.
Use thermal relief for pads.
Definition: zones.h:58
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Function GetConnectivity() returns list of missing connections between components/tracks.
Definition: class_board.h:290
void cacheLib(const wxString &aLibraryPath, const wxString &aFootprintName=wxEmptyString)
we only cache one footprint library, this determines which one.
Class DIMENSION.
int GetZoneClearance() const
Definition: class_zone.h:203
const wxPoint & GetOffset() const
Definition: class_pad.h:191
int GetThermalWidth() const
Definition: class_module.h:192
MODULE_MAP & GetModules()
DLIST_ITERATOR_WRAPPER< BOARD_ITEM > Drawings()
Definition: class_board.h:251
void Save(const wxString &aFileName, BOARD *aBoard, const PROPERTIES *aProperties=NULL) override
Function Save will write aBoard to a storage file in a format that this PLUGIN implementation knows a...
NETCLASSES m_NetClasses
List of current netclasses. There is always the default netclass.
int m_SolderMaskMinWidth
Solder mask min width.
T NormalizeAngle360(T Angle)
Normalize angle to be in the -360.0 .. 360.0:
Definition: trigo.h:202
static wxString GetStandardLayerName(PCB_LAYER_ID aLayerId)
Function GetStandardLayerName returns an "English Standard" name of a PCB layer when given aLayerNumb...
Definition: class_board.h:649
wxDateTime GetLibModificationTime() const
pads are covered by copper
Definition: zones.h:59
Class BOARD_DESIGN_SETTINGS contains design settings for a BOARD object.
wxPoint m_featureLineGF