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