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