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