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