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  PCB_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  PCB_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 PCB_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  PCB_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 < PCB_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( PCB_LAYER_ID( layer ) );
1220 
1221  else // I am being called from FootprintSave()
1222  layerName = BOARD::GetStandardLayerName( PCB_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  PCB_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  bool new_polygon = true;
1614  bool is_closed = false;
1615 
1616  for( auto iterator = aZone->IterateWithHoles(); iterator; iterator++ )
1617  {
1618  if( new_polygon )
1619  {
1620  newLine = 0;
1621  m_out->Print( aNestLevel+1, "(polygon\n" );
1622  m_out->Print( aNestLevel+2, "(pts\n" );
1623  new_polygon = false;
1624  is_closed = false;
1625  }
1626 
1627  if( newLine == 0 )
1628  m_out->Print( aNestLevel+3, "(xy %s %s)",
1629  FMT_IU( iterator->x ).c_str(), FMT_IU( iterator->y ).c_str() );
1630  else
1631  m_out->Print( 0, " (xy %s %s)",
1632  FMT_IU( iterator->x ).c_str(), FMT_IU( iterator->y ).c_str() );
1633 
1634  if( newLine < 4 )
1635  {
1636  newLine += 1;
1637  }
1638  else
1639  {
1640  newLine = 0;
1641  m_out->Print( 0, "\n" );
1642  }
1643 
1644  if( iterator.IsEndContour() )
1645  {
1646  is_closed = true;
1647 
1648  if( newLine != 0 )
1649  m_out->Print( 0, "\n" );
1650 
1651  m_out->Print( aNestLevel+2, ")\n" );
1652  m_out->Print( aNestLevel+1, ")\n" );
1653  new_polygon = true;
1654  }
1655  }
1656 
1657  if( !is_closed ) // Should not happen, but...
1658  m_out->Print( aNestLevel+1, ")\n" );
1659 
1660  }
1661 
1662  // Save the PolysList (filled areas)
1663  const SHAPE_POLY_SET& fv = aZone->GetFilledPolysList();
1664  newLine = 0;
1665 
1666  if( !fv.IsEmpty() )
1667  {
1668  bool new_polygon = true;
1669  bool is_closed = false;
1670 
1671  for( auto it = fv.CIterate(); it; ++it )
1672  {
1673  if( new_polygon )
1674  {
1675  newLine = 0;
1676  m_out->Print( aNestLevel+1, "(filled_polygon\n" );
1677  m_out->Print( aNestLevel+2, "(pts\n" );
1678  new_polygon = false;
1679  is_closed = false;
1680  }
1681 
1682  if( newLine == 0 )
1683  m_out->Print( aNestLevel+3, "(xy %s %s)",
1684  FMT_IU( it->x ).c_str(), FMT_IU( it->y ).c_str() );
1685  else
1686  m_out->Print( 0, " (xy %s %s)",
1687  FMT_IU( it->x ) .c_str(), FMT_IU( it->y ).c_str() );
1688 
1689  if( newLine < 4 )
1690  {
1691  newLine += 1;
1692  }
1693  else
1694  {
1695  newLine = 0;
1696  m_out->Print( 0, "\n" );
1697  }
1698 
1699  if( it.IsEndContour() )
1700  {
1701  is_closed = true;
1702 
1703  if( newLine != 0 )
1704  m_out->Print( 0, "\n" );
1705 
1706  m_out->Print( aNestLevel+2, ")\n" );
1707  m_out->Print( aNestLevel+1, ")\n" );
1708  new_polygon = true;
1709  }
1710  }
1711 
1712  if( !is_closed ) // Should not happen, but...
1713  m_out->Print( aNestLevel+1, ")\n" );
1714  }
1715 
1716  // Save the filling segments list
1717  const std::vector< SEGMENT >& segs = aZone->FillSegments();
1718 
1719  if( segs.size() )
1720  {
1721  m_out->Print( aNestLevel+1, "(fill_segments\n" );
1722 
1723  for( std::vector< SEGMENT >::const_iterator it = segs.begin(); it != segs.end(); ++it )
1724  {
1725  m_out->Print( aNestLevel+2, "(pts (xy %s) (xy %s))\n",
1726  FMT_IU( it->m_Start ).c_str(),
1727  FMT_IU( it->m_End ).c_str() );
1728  }
1729 
1730  m_out->Print( aNestLevel+1, ")\n" );
1731  }
1732 
1733  m_out->Print( aNestLevel, ")\n" );
1734 }
1735 
1736 
1737 PCB_IO::PCB_IO( int aControlFlags ) :
1738  m_cache( 0 ),
1739  m_ctl( aControlFlags ),
1740  m_parser( new PCB_PARSER() ),
1741  m_mapping( new NETINFO_MAPPING() )
1742 {
1743  init( 0 );
1744  m_out = &m_sf;
1745 }
1746 
1747 
1749 {
1750  delete m_cache;
1751  delete m_parser;
1752  delete m_mapping;
1753 }
1754 
1755 
1756 BOARD* PCB_IO::Load( const wxString& aFileName, BOARD* aAppendToMe, const PROPERTIES* aProperties )
1757 {
1758  FILE_LINE_READER reader( aFileName );
1759 
1760  init( aProperties );
1761 
1762  m_parser->SetLineReader( &reader );
1763  m_parser->SetBoard( aAppendToMe );
1764 
1765  BOARD* board;
1766 
1767  try
1768  {
1769  board = dynamic_cast<BOARD*>( m_parser->Parse() );
1770  }
1771  catch( const FUTURE_FORMAT_ERROR& )
1772  {
1773  // Don't wrap a FUTURE_FORMAT_ERROR in another
1774  throw;
1775  }
1776  catch( const PARSE_ERROR& parse_error )
1777  {
1778  if( m_parser->IsTooRecent() )
1779  throw FUTURE_FORMAT_ERROR( parse_error, m_parser->GetRequiredVersion() );
1780  else
1781  throw;
1782  }
1783 
1784  if( !board )
1785  {
1786  // The parser loaded something that was valid, but wasn't a board.
1787  THROW_PARSE_ERROR( _( "this file does not contain a PCB" ),
1790  }
1791 
1792  // Give the filename to the board if it's new
1793  if( !aAppendToMe )
1794  board->SetFileName( aFileName );
1795 
1796  return board;
1797 }
1798 
1799 
1800 void PCB_IO::init( const PROPERTIES* aProperties )
1801 {
1802  m_board = NULL;
1803  m_reader = NULL;
1805  m_props = aProperties;
1806 }
1807 
1808 
1809 void PCB_IO::cacheLib( const wxString& aLibraryPath, const wxString& aFootprintName )
1810 {
1811  if( !m_cache || m_cache->IsModified( aLibraryPath, aFootprintName ) )
1812  {
1813  // a spectacular episode in memory management:
1814  delete m_cache;
1815  m_cache = new FP_CACHE( this, aLibraryPath );
1816  m_cache->Load();
1817  }
1818 }
1819 
1820 
1821 wxArrayString PCB_IO::FootprintEnumerate( const wxString& aLibraryPath,
1822  const PROPERTIES* aProperties )
1823 {
1824  LOCALE_IO toggle; // toggles on, then off, the C locale.
1825  wxArrayString ret;
1826  wxDir dir( aLibraryPath );
1827 
1828  if( !dir.IsOpened() )
1829  {
1830  THROW_IO_ERROR( wxString::Format( _( "footprint library path '%s' does not exist" ),
1831  GetChars( aLibraryPath ) ) );
1832  }
1833 
1834  init( aProperties );
1835 
1836 #if 1 // Set to 0 to only read directory contents, not load cache.
1837  cacheLib( aLibraryPath );
1838 
1839  const MODULE_MAP& mods = m_cache->GetModules();
1840 
1841 
1842  for( MODULE_CITER it = mods.begin(); it != mods.end(); ++it )
1843  {
1844  ret.Add( FROM_UTF8( it->first.c_str() ) );
1845  }
1846 #else
1847  wxString fpFileName;
1848  wxString wildcard = wxT( "*." ) + KiCadFootprintFileExtension;
1849 
1850  if( dir.GetFirst( &fpFileName, wildcard, wxDIR_FILES ) )
1851  {
1852  do
1853  {
1854  wxFileName fn( aLibraryPath, fpFileName );
1855  ret.Add( fn.GetName() );
1856  } while( dir.GetNext( &fpFileName ) );
1857  }
1858 #endif
1859 
1860  return ret;
1861 }
1862 
1863 
1864 MODULE* PCB_IO::FootprintLoad( const wxString& aLibraryPath, const wxString& aFootprintName,
1865  const PROPERTIES* aProperties )
1866 {
1867  LOCALE_IO toggle; // toggles on, then off, the C locale.
1868 
1869  init( aProperties );
1870 
1871  cacheLib( aLibraryPath, aFootprintName );
1872 
1873  const MODULE_MAP& mods = m_cache->GetModules();
1874 
1875  MODULE_CITER it = mods.find( TO_UTF8( aFootprintName ) );
1876 
1877  if( it == mods.end() )
1878  {
1879  return NULL;
1880  }
1881 
1882  // copy constructor to clone the already loaded MODULE
1883  return new MODULE( *it->second->GetModule() );
1884 }
1885 
1886 
1887 void PCB_IO::FootprintSave( const wxString& aLibraryPath, const MODULE* aFootprint,
1888  const PROPERTIES* aProperties )
1889 {
1890  LOCALE_IO toggle; // toggles on, then off, the C locale.
1891 
1892  init( aProperties );
1893 
1894  // In this public PLUGIN API function, we can safely assume it was
1895  // called for saving into a library path.
1897 
1898  cacheLib( aLibraryPath );
1899 
1900  if( !m_cache->IsWritable() )
1901  {
1902  wxString msg = wxString::Format(
1903  _( "Library '%s' is read only" ),
1904  GetChars( aLibraryPath )
1905  );
1906 
1907  THROW_IO_ERROR( msg );
1908  }
1909 
1910  std::string footprintName = aFootprint->GetFPID().GetLibItemName();
1911 
1912  MODULE_MAP& mods = m_cache->GetModules();
1913 
1914  // Quietly overwrite module and delete module file from path for any by same name.
1915  wxFileName fn( aLibraryPath, FROM_UTF8( aFootprint->GetFPID().GetLibItemName() ),
1917 
1918  if( !fn.IsOk() )
1919  {
1920  THROW_IO_ERROR( wxString::Format( _( "Footprint file name '%s' is not valid." ),
1921  GetChars( fn.GetFullPath() ) ) );
1922  }
1923 
1924  if( fn.FileExists() && !fn.IsFileWritable() )
1925  {
1926  THROW_IO_ERROR( wxString::Format( _( "user does not have write permission to delete file '%s' " ),
1927  GetChars( fn.GetFullPath() ) ) );
1928  }
1929 
1930  MODULE_CITER it = mods.find( footprintName );
1931 
1932  if( it != mods.end() )
1933  {
1934  wxLogTrace( traceFootprintLibrary, wxT( "Removing footprint library file '%s'." ),
1935  fn.GetFullPath().GetData() );
1936  mods.erase( footprintName );
1937  wxRemoveFile( fn.GetFullPath() );
1938  }
1939 
1940  // I need my own copy for the cache
1941  MODULE* module = new MODULE( *aFootprint );
1942 
1943  // and it's time stamp must be 0, it should have no parent, orientation should
1944  // be zero, and it should be on the front layer.
1945  module->SetTimeStamp( 0 );
1946  module->SetParent( 0 );
1947  module->SetOrientation( 0 );
1948 
1949  if( module->GetLayer() != F_Cu )
1950  module->Flip( module->GetPosition() );
1951 
1952  wxLogTrace( traceFootprintLibrary, wxT( "Creating s-expression footprint file: %s." ),
1953  fn.GetFullPath().GetData() );
1954  mods.insert( footprintName, new FP_CACHE_ITEM( module, fn ) );
1955  m_cache->Save();
1956 }
1957 
1958 
1959 void PCB_IO::FootprintDelete( const wxString& aLibraryPath, const wxString& aFootprintName, const PROPERTIES* aProperties )
1960 {
1961  LOCALE_IO toggle; // toggles on, then off, the C locale.
1962 
1963  init( aProperties );
1964 
1965  cacheLib( aLibraryPath );
1966 
1967  if( !m_cache->IsWritable() )
1968  {
1969  THROW_IO_ERROR( wxString::Format( _( "Library '%s' is read only" ),
1970  aLibraryPath.GetData() ) );
1971  }
1972 
1973  m_cache->Remove( aFootprintName );
1974 }
1975 
1976 
1977 void PCB_IO::FootprintLibCreate( const wxString& aLibraryPath, const PROPERTIES* aProperties )
1978 {
1979  if( wxDir::Exists( aLibraryPath ) )
1980  {
1981  THROW_IO_ERROR( wxString::Format( _( "cannot overwrite library path '%s'" ),
1982  aLibraryPath.GetData() ) );
1983  }
1984 
1985  LOCALE_IO toggle;
1986 
1987  init( aProperties );
1988 
1989  delete m_cache;
1990  m_cache = new FP_CACHE( this, aLibraryPath );
1991  m_cache->Save();
1992 }
1993 
1994 
1995 bool PCB_IO::FootprintLibDelete( const wxString& aLibraryPath, const PROPERTIES* aProperties )
1996 {
1997  wxFileName fn;
1998  fn.SetPath( aLibraryPath );
1999 
2000  // Return if there is no library path to delete.
2001  if( !fn.DirExists() )
2002  return false;
2003 
2004  if( !fn.IsDirWritable() )
2005  {
2006  THROW_IO_ERROR( wxString::Format( _( "user does not have permission to delete directory '%s'" ),
2007  aLibraryPath.GetData() ) );
2008  }
2009 
2010  wxDir dir( aLibraryPath );
2011 
2012  if( dir.HasSubDirs() )
2013  {
2014  THROW_IO_ERROR( wxString::Format( _( "library directory '%s' has unexpected sub-directories" ),
2015  aLibraryPath.GetData() ) );
2016  }
2017 
2018  // All the footprint files must be deleted before the directory can be deleted.
2019  if( dir.HasFiles() )
2020  {
2021  unsigned i;
2022  wxFileName tmp;
2023  wxArrayString files;
2024 
2025  wxDir::GetAllFiles( aLibraryPath, &files );
2026 
2027  for( i = 0; i < files.GetCount(); i++ )
2028  {
2029  tmp = files[i];
2030 
2031  if( tmp.GetExt() != KiCadFootprintFileExtension )
2032  {
2033  THROW_IO_ERROR( wxString::Format( _( "unexpected file '%s' was found in library path '%s'" ),
2034  files[i].GetData(), aLibraryPath.GetData() ) );
2035  }
2036  }
2037 
2038  for( i = 0; i < files.GetCount(); i++ )
2039  {
2040  wxRemoveFile( files[i] );
2041  }
2042  }
2043 
2044  wxLogTrace( traceFootprintLibrary, wxT( "Removing footprint library '%s'" ),
2045  aLibraryPath.GetData() );
2046 
2047  // Some of the more elaborate wxRemoveFile() crap puts up its own wxLog dialog
2048  // we don't want that. we want bare metal portability with no UI here.
2049  if( !wxRmdir( aLibraryPath ) )
2050  {
2051  THROW_IO_ERROR( wxString::Format( _( "footprint library '%s' cannot be deleted" ),
2052  aLibraryPath.GetData() ) );
2053  }
2054 
2055  // For some reason removing a directory in Windows is not immediately updated. This delay
2056  // prevents an error when attempting to immediately recreate the same directory when over
2057  // writing an existing library.
2058 #ifdef __WINDOWS__
2059  wxMilliSleep( 250L );
2060 #endif
2061 
2062  if( m_cache && !m_cache->IsPath( aLibraryPath ) )
2063  {
2064  delete m_cache;
2065  m_cache = NULL;
2066  }
2067 
2068  return true;
2069 }
2070 
2071 
2072 bool PCB_IO::IsFootprintLibWritable( const wxString& aLibraryPath )
2073 {
2074  LOCALE_IO toggle;
2075 
2076  init( NULL );
2077 
2078  cacheLib( aLibraryPath );
2079 
2080  return m_cache->IsWritable();
2081 }
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
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:144
polygon (not yet used for tracks, but could be in microwave apps)
MODULE * Next() const
Definition: class_module.h:100
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
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
#define cu(a)
Definition: auxiliary.h:88
int GetDrill() const
Function GetDrill returns the local drill setting for this VIA.
Definition: class_track.h:461
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:152
#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
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
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 PCB_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:446
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:148
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:58
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 PCB_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
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.
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
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()
Class NETINFO_ITEM handles the data for a net.
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: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: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
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
void SetOrientation(double newangle)
Virtual component: when created by copper shapes on board (Like edge card connectors, mounting hole...)
Definition: class_module.h:79
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
#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.
const char * name
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
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:646
wxDateTime GetLibModificationTime() const
pads are covered by copper
Definition: zones.h:59
Class BOARD_DESIGN_SETTINGS contains design settings for a BOARD object.