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