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-2020 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 <common.h>
27 #include <build_version.h> // LEGACY_BOARD_FILE_VERSION
28 #include <macros.h>
30 #include <base_units.h>
31 #include <trace_helpers.h>
32 #include <class_board.h>
33 #include <class_module.h>
34 #include <class_pcb_text.h>
35 #include <class_dimension.h>
36 #include <class_track.h>
37 #include <class_zone.h>
38 #include <class_drawsegment.h>
39 #include <class_pcb_target.h>
40 #include <class_edge_mod.h>
41 #include <zones.h>
42 #include <kicad_plugin.h>
43 #include <pcb_parser.h>
44 #include <pcbnew_settings.h>
45 #include <wx/dir.h>
46 #include <wx/filename.h>
47 #include <wx/wfstream.h>
48 #include <boost/ptr_container/ptr_map.hpp>
49 #include <memory.h>
51 #include <convert_basic_shapes_to_polygon.h> // for enum RECT_CHAMFER_POSITIONS definition
52 #include <kiface_i.h>
53 
54 #include <advanced_config.h> // for pad pin function and pad property feature management
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  "(or is not a directory)." ),
264  m_lib_raw_path );
265  THROW_IO_ERROR( msg );
266  }
267 
268  wxString fullName;
269  wxString fileSpec = wxT( "*." ) + KiCadFootprintFileExtension;
270 
271  // wxFileName construction is egregiously slow. Construct it once and just swap out
272  // the filename thereafter.
273  WX_FILENAME fn( m_lib_raw_path, wxT( "dummyName" ) );
274 
275  if( dir.GetFirst( &fullName, fileSpec ) )
276  {
277  wxString cacheError;
278 
279  do
280  {
281  fn.SetFullName( fullName );
282 
283  // Queue I/O errors so only files that fail to parse don't get loaded.
284  try
285  {
286  FILE_LINE_READER reader( fn.GetFullPath() );
287 
288  m_owner->m_parser->SetLineReader( &reader );
289 
290  MODULE* footprint = (MODULE*) m_owner->m_parser->Parse();
291  wxString fpName = fn.GetName();
292 
293  footprint->SetFPID( LIB_ID( wxEmptyString, fpName ) );
294  m_modules.insert( fpName, new FP_CACHE_ITEM( footprint, fn ) );
295 
297  }
298  catch( const IO_ERROR& ioe )
299  {
300  if( !cacheError.IsEmpty() )
301  cacheError += "\n\n";
302 
303  cacheError += ioe.What();
304  }
305  } while( dir.GetNext( &fullName ) );
306 
307  if( !cacheError.IsEmpty() )
308  THROW_IO_ERROR( cacheError );
309  }
310 }
311 
312 
313 void FP_CACHE::Remove( const wxString& aFootprintName )
314 {
315  MODULE_CITER it = m_modules.find( aFootprintName );
316 
317  if( it == m_modules.end() )
318  {
319  wxString msg = wxString::Format( _( "library \"%s\" has no footprint \"%s\" to delete" ),
321  aFootprintName );
322  THROW_IO_ERROR( msg );
323  }
324 
325  // Remove the module from the cache and delete the module file from the library.
326  wxString fullPath = it->second->GetFileName().GetFullPath();
327  m_modules.erase( aFootprintName );
328  wxRemoveFile( fullPath );
329 }
330 
331 
332 bool FP_CACHE::IsPath( const wxString& aPath ) const
333 {
334  return aPath == m_lib_raw_path;
335 }
336 
337 
339 {
341 
342  return m_cache_dirty;
343 }
344 
345 
346 long long FP_CACHE::GetTimestamp( const wxString& aLibPath )
347 {
348  wxString fileSpec = wxT( "*." ) + KiCadFootprintFileExtension;
349 
350  return TimestampDir( aLibPath, fileSpec );
351 }
352 
353 
354 void PCB_IO::Save( const wxString& aFileName, BOARD* aBoard, const PROPERTIES* aProperties )
355 {
356  LOCALE_IO toggle; // toggles on, then off, the C locale.
357 
358  init( aProperties );
359 
360  m_board = aBoard; // after init()
361 
362  // Prepare net mapping that assures that net codes saved in a file are consecutive integers
363  m_mapping->SetBoard( aBoard );
364 
365  FILE_OUTPUTFORMATTER formatter( aFileName );
366 
367  m_out = &formatter; // no ownership
368 
369  m_out->Print( 0, "(kicad_pcb (version %d) (host pcbnew %s)\n", SEXPR_BOARD_FILE_VERSION,
370  formatter.Quotew( GetBuildVersion() ).c_str() );
371 
372  Format( aBoard, 1 );
373 
374  m_out->Print( 0, ")\n" );
375 }
376 
377 
378 BOARD_ITEM* PCB_IO::Parse( const wxString& aClipboardSourceInput )
379 {
380  std::string input = TO_UTF8( aClipboardSourceInput );
381 
382  STRING_LINE_READER reader( input, wxT( "clipboard" ) );
383 
384  m_parser->SetLineReader( &reader );
385 
386  try
387  {
388  return m_parser->Parse();
389  }
390  catch( const PARSE_ERROR& parse_error )
391  {
392  if( m_parser->IsTooRecent() )
393  throw FUTURE_FORMAT_ERROR( parse_error, m_parser->GetRequiredVersion() );
394  else
395  throw;
396  }
397 }
398 
399 
400 void PCB_IO::Format( BOARD_ITEM* aItem, int aNestLevel ) const
401 {
402  LOCALE_IO toggle; // public API function, perform anything convenient for caller
403 
404  switch( aItem->Type() )
405  {
406  case PCB_T:
407  format( static_cast<BOARD*>( aItem ), aNestLevel );
408  break;
409 
410  case PCB_DIMENSION_T:
411  format( static_cast<DIMENSION*>( aItem ), aNestLevel );
412  break;
413 
414  case PCB_LINE_T:
415  format( static_cast<DRAWSEGMENT*>( aItem ), aNestLevel );
416  break;
417 
418  case PCB_MODULE_EDGE_T:
419  format( static_cast<EDGE_MODULE*>( aItem ), aNestLevel );
420  break;
421 
422  case PCB_TARGET_T:
423  format( static_cast<PCB_TARGET*>( aItem ), aNestLevel );
424  break;
425 
426  case PCB_MODULE_T:
427  format( static_cast<MODULE*>( aItem ), aNestLevel );
428  break;
429 
430  case PCB_PAD_T:
431  format( static_cast<D_PAD*>( aItem ), aNestLevel );
432  break;
433 
434  case PCB_TEXT_T:
435  format( static_cast<TEXTE_PCB*>( aItem ), aNestLevel );
436  break;
437 
438  case PCB_MODULE_TEXT_T:
439  format( static_cast<TEXTE_MODULE*>( aItem ), aNestLevel );
440  break;
441 
442  case PCB_TRACE_T:
443  case PCB_ARC_T:
444  case PCB_VIA_T:
445  format( static_cast<TRACK*>( aItem ), aNestLevel );
446  break;
447 
449  case PCB_ZONE_AREA_T:
450  format( static_cast<ZONE_CONTAINER*>( aItem ), aNestLevel );
451  break;
452 
453  default:
454  wxFAIL_MSG( wxT( "Cannot format item " ) + aItem->GetClass() );
455  }
456 }
457 
458 
459 void PCB_IO::formatLayer( const BOARD_ITEM* aItem ) const
460 {
461  if( m_ctl & CTL_STD_LAYER_NAMES )
462  {
463  PCB_LAYER_ID layer = aItem->GetLayer();
464 
465  // English layer names should never need quoting.
466  m_out->Print( 0, " (layer %s)", TO_UTF8( BOARD::GetStandardLayerName( layer ) ) );
467  }
468  else
469  m_out->Print( 0, " (layer %s)", m_out->Quotew( aItem->GetLayerName() ).c_str() );
470 }
471 
472 
473 void PCB_IO::formatSetup( BOARD* aBoard, int aNestLevel ) const
474 {
475  // Setup
476  m_out->Print( aNestLevel, "(setup\n" );
477 
478  // Save the board physical stackup structure
480 
481  if( aBoard->GetDesignSettings().m_HasStackup )
482  stackup.FormatBoardStackup( m_out,aBoard, aNestLevel+1 );
483 
484  BOARD_DESIGN_SETTINGS& dsnSettings = aBoard->GetDesignSettings();
485 
486  if( dsnSettings.m_AuxOrigin != wxPoint( 0, 0 ) )
487  m_out->Print( aNestLevel+1, "(aux_axis_origin %s %s)\n",
488  FormatInternalUnits( dsnSettings.m_AuxOrigin.x ).c_str(),
489  FormatInternalUnits( dsnSettings.m_AuxOrigin.y ).c_str() );
490 
491  if( dsnSettings.m_GridOrigin != wxPoint( 0, 0 ) )
492  m_out->Print( aNestLevel+1, "(grid_origin %s %s)\n",
493  FormatInternalUnits( dsnSettings.m_GridOrigin.x ).c_str(),
494  FormatInternalUnits( dsnSettings.m_GridOrigin.y ).c_str() );
495 
496  aBoard->GetPlotOptions().Format( m_out, aNestLevel+1 );
497 
498  m_out->Print( aNestLevel, ")\n\n" );
499 }
500 
501 
502 void PCB_IO::formatGeneral( BOARD* aBoard, int aNestLevel ) const
503 {
504  const BOARD_DESIGN_SETTINGS& dsnSettings = aBoard->GetDesignSettings();
505 
506  m_out->Print( 0, "\n" );
507  m_out->Print( aNestLevel, "(general\n" );
508  // Write Bounding box info
509  m_out->Print( aNestLevel+1, "(thickness %s)\n",
510  FormatInternalUnits( dsnSettings.GetBoardThickness() ).c_str() );
511 
512  m_out->Print( aNestLevel+1, "(drawings %u)\n", (unsigned)aBoard->Drawings().size() );
513  m_out->Print( aNestLevel + 1, "(tracks %u)\n", (unsigned)aBoard->Tracks().size() );
514  m_out->Print( aNestLevel + 1, "(modules %u)\n", (unsigned)aBoard->Modules().size() );
515  m_out->Print( aNestLevel+1, "(nets %d)\n", m_mapping->GetSize() );
516  m_out->Print( aNestLevel, ")\n\n" );
517 
518  aBoard->GetPageSettings().Format( m_out, aNestLevel, m_ctl );
519  aBoard->GetTitleBlock().Format( m_out, aNestLevel, m_ctl );
520 }
521 
522 
523 void PCB_IO::formatBoardLayers( BOARD* aBoard, int aNestLevel ) const
524 {
525  m_out->Print( aNestLevel, "(layers\n" );
526 
527  // Save only the used copper layers from front to back.
528 
529  for( LSEQ cu = aBoard->GetEnabledLayers().CuStack(); cu; ++cu )
530  {
531  PCB_LAYER_ID layer = *cu;
532 
533  m_out->Print( aNestLevel+1, "(%d %s %s", layer,
534  m_out->Quotew( aBoard->GetLayerName( layer ) ).c_str(),
535  LAYER::ShowType( aBoard->GetLayerType( layer ) ) );
536 
537  m_out->Print( 0, ")\n" );
538  }
539 
540  // Save used non-copper layers in the order they are defined.
541  // desired sequence for non Cu BOARD layers.
542  static const PCB_LAYER_ID non_cu[] =
543  {
544  B_Adhes, // 32
545  F_Adhes,
546  B_Paste,
547  F_Paste,
548  B_SilkS,
549  F_SilkS,
550  B_Mask,
551  F_Mask,
552  Dwgs_User,
553  Cmts_User,
554  Eco1_User,
555  Eco2_User,
556  Edge_Cuts,
557  Margin,
558  B_CrtYd,
559  F_CrtYd,
560  B_Fab,
561  F_Fab
562  };
563 
564  for( LSEQ seq = aBoard->GetEnabledLayers().Seq( non_cu, arrayDim( non_cu ) ); seq; ++seq )
565  {
566  PCB_LAYER_ID layer = *seq;
567 
568  m_out->Print( aNestLevel+1, "(%d %s user", layer,
569  m_out->Quotew( aBoard->GetLayerName( layer ) ).c_str() );
570 
571  m_out->Print( 0, ")\n" );
572  }
573 
574  m_out->Print( aNestLevel, ")\n\n" );
575 }
576 
577 
578 void PCB_IO::formatNetInformation( BOARD* aBoard, int aNestLevel ) const
579 {
580  for( NETINFO_ITEM* net : *m_mapping )
581  {
582  m_out->Print( aNestLevel, "(net %d %s)\n",
583  m_mapping->Translate( net->GetNet() ),
584  m_out->Quotew( net->GetNetname() ).c_str() );
585  }
586 
587  m_out->Print( 0, "\n" );
588 }
589 
590 
591 void PCB_IO::formatHeader( BOARD* aBoard, int aNestLevel ) const
592 {
593  formatGeneral( aBoard, aNestLevel );
594  // Layers list.
595  formatBoardLayers( aBoard, aNestLevel );
596 
597  // Setup
598  formatSetup( aBoard, aNestLevel );
599 
600  // Save net codes and names
601  formatNetInformation( aBoard, aNestLevel );
602 }
603 
604 void PCB_IO::format( BOARD* aBoard, int aNestLevel ) const
605 {
606  formatHeader( aBoard, aNestLevel );
607 
608  // Save the modules.
609  for( auto module : aBoard->Modules() )
610  {
611  Format( module, aNestLevel );
612  m_out->Print( 0, "\n" );
613  }
614 
615  // Save the graphical items on the board (not owned by a module)
616  for( auto item : aBoard->Drawings() )
617  Format( item, aNestLevel );
618 
619  if( aBoard->Drawings().size() )
620  m_out->Print( 0, "\n" );
621 
622  // Do not save MARKER_PCBs, they can be regenerated easily.
623 
624  // Save the tracks and vias.
625  for( auto track : aBoard->Tracks() )
626  Format( track, aNestLevel );
627 
628  if( aBoard->Tracks().size() )
629  m_out->Print( 0, "\n" );
630 
631  // Save the polygon (which are the newer technology) zones.
632  for( int i = 0; i < aBoard->GetAreaCount(); ++i )
633  Format( aBoard->GetArea( i ), aNestLevel );
634 }
635 
636 
637 void PCB_IO::format( DIMENSION* aDimension, int aNestLevel ) const
638 {
639  m_out->Print( aNestLevel, "(dimension %s (width %s)",
640  FormatInternalUnits( aDimension->GetValue() ).c_str(),
641  FormatInternalUnits( aDimension->GetWidth() ).c_str() );
642 
643  formatLayer( aDimension );
644 
645  m_out->Print( 0, " (tstamp %s)", TO_UTF8( aDimension->m_Uuid.AsString() ) );
646 
647  m_out->Print( 0, "\n" );
648 
649  Format( &aDimension->Text(), aNestLevel+1 );
650 
651  m_out->Print( aNestLevel+1, "(feature1 (pts (xy %s %s) (xy %s %s)))\n",
652  FormatInternalUnits( aDimension->m_featureLineDO.x ).c_str(),
653  FormatInternalUnits( aDimension->m_featureLineDO.y ).c_str(),
654  FormatInternalUnits( aDimension->m_featureLineDF.x ).c_str(),
655  FormatInternalUnits( aDimension->m_featureLineDF.y ).c_str() );
656 
657  m_out->Print( aNestLevel+1, "(feature2 (pts (xy %s %s) (xy %s %s)))\n",
658  FormatInternalUnits( aDimension->m_featureLineGO.x ).c_str(),
659  FormatInternalUnits( aDimension->m_featureLineGO.y ).c_str(),
660  FormatInternalUnits( aDimension->m_featureLineGF.x ).c_str(),
661  FormatInternalUnits( aDimension->m_featureLineGF.y ).c_str() );
662 
663  m_out->Print( aNestLevel+1, "(crossbar (pts (xy %s %s) (xy %s %s)))\n",
664  FormatInternalUnits( aDimension->m_crossBarO.x ).c_str(),
665  FormatInternalUnits( aDimension->m_crossBarO.y ).c_str(),
666  FormatInternalUnits( aDimension->m_crossBarF.x ).c_str(),
667  FormatInternalUnits( aDimension->m_crossBarF.y ).c_str() );
668 
669  m_out->Print( aNestLevel+1, "(arrow1a (pts (xy %s %s) (xy %s %s)))\n",
670  FormatInternalUnits( aDimension->m_crossBarF.x ).c_str(),
671  FormatInternalUnits( aDimension->m_crossBarF.y ).c_str(),
672  FormatInternalUnits( aDimension->m_arrowD1F.x ).c_str(),
673  FormatInternalUnits( aDimension->m_arrowD1F.y ).c_str() );
674 
675  m_out->Print( aNestLevel+1, "(arrow1b (pts (xy %s %s) (xy %s %s)))\n",
676  FormatInternalUnits( aDimension->m_crossBarF.x ).c_str(),
677  FormatInternalUnits( aDimension->m_crossBarF.y ).c_str(),
678  FormatInternalUnits( aDimension->m_arrowD2F.x ).c_str(),
679  FormatInternalUnits( aDimension->m_arrowD2F.y ).c_str() );
680 
681  m_out->Print( aNestLevel+1, "(arrow2a (pts (xy %s %s) (xy %s %s)))\n",
682  FormatInternalUnits( aDimension->m_crossBarO.x ).c_str(),
683  FormatInternalUnits( aDimension->m_crossBarO.y ).c_str(),
684  FormatInternalUnits( aDimension->m_arrowG1F.x ).c_str(),
685  FormatInternalUnits( aDimension->m_arrowG1F.y ).c_str() );
686 
687  m_out->Print( aNestLevel+1, "(arrow2b (pts (xy %s %s) (xy %s %s)))\n",
688  FormatInternalUnits( aDimension->m_crossBarO.x ).c_str(),
689  FormatInternalUnits( aDimension->m_crossBarO.y ).c_str(),
690  FormatInternalUnits( aDimension->m_arrowG2F.x ).c_str(),
691  FormatInternalUnits( aDimension->m_arrowG2F.y ).c_str() );
692 
693  m_out->Print( aNestLevel, ")\n" );
694 }
695 
696 
697 void PCB_IO::format( DRAWSEGMENT* aSegment, int aNestLevel ) const
698 {
699  switch( aSegment->GetShape() )
700  {
701  case S_SEGMENT: // Line
702  m_out->Print( aNestLevel, "(gr_line (start %s) (end %s)",
703  FormatInternalUnits( aSegment->GetStart() ).c_str(),
704  FormatInternalUnits( aSegment->GetEnd() ).c_str() );
705 
706  if( aSegment->GetAngle() != 0.0 )
707  m_out->Print( 0, " (angle %s)", FormatAngle( aSegment->GetAngle() ).c_str() );
708 
709  break;
710 
711  case S_RECT: // Rectangle
712  m_out->Print( aNestLevel, "(gr_rect (start %s) (end %s)",
713  FormatInternalUnits( aSegment->GetStart() ).c_str(),
714  FormatInternalUnits( aSegment->GetEnd() ).c_str() );
715  break;
716 
717  case S_CIRCLE: // Circle
718  m_out->Print( aNestLevel, "(gr_circle (center %s) (end %s)",
719  FormatInternalUnits( aSegment->GetStart() ).c_str(),
720  FormatInternalUnits( aSegment->GetEnd() ).c_str() );
721  break;
722 
723  case S_ARC: // Arc
724  m_out->Print( aNestLevel, "(gr_arc (start %s) (end %s) (angle %s)",
725  FormatInternalUnits( aSegment->GetStart() ).c_str(),
726  FormatInternalUnits( aSegment->GetEnd() ).c_str(),
727  FormatAngle( aSegment->GetAngle() ).c_str() );
728  break;
729 
730  case S_POLYGON: // Polygon
731  if( aSegment->IsPolyShapeValid() )
732  {
733  SHAPE_POLY_SET& poly = aSegment->GetPolyShape();
734  SHAPE_LINE_CHAIN& outline = poly.Outline( 0 );
735  int pointsCount = outline.PointCount();
736 
737  m_out->Print( aNestLevel, "(gr_poly (pts" );
738 
739  for( int ii = 0; ii < pointsCount; ++ii )
740  {
741  m_out->Print( 0, " (xy %s)", FormatInternalUnits( outline.CPoint( ii ) ).c_str() );
742  }
743 
744  m_out->Print( 0, ")" );
745  }
746  else
747  {
748  wxFAIL_MSG( wxT( "Cannot format invalid polygon." ) );
749  return;
750  }
751 
752  break;
753 
754  case S_CURVE: // Bezier curve
755  m_out->Print( aNestLevel, "(gr_curve (pts (xy %s) (xy %s) (xy %s) (xy %s))",
756  FormatInternalUnits( aSegment->GetStart() ).c_str(),
757  FormatInternalUnits( aSegment->GetBezControl1() ).c_str(),
758  FormatInternalUnits( aSegment->GetBezControl2() ).c_str(),
759  FormatInternalUnits( aSegment->GetEnd() ).c_str() );
760  break;
761 
762  default:
763  wxFAIL_MSG( "PCB_IO::format cannot format unknown DRAWSEGMENT shape:"
764  + STROKE_T_asString( aSegment->GetShape() ) );
765  return;
766  };
767 
768  formatLayer( aSegment );
769 
770  m_out->Print( 0, " (width %s)", FormatInternalUnits( aSegment->GetWidth() ).c_str() );
771 
772  m_out->Print( 0, " (tstamp %s)", TO_UTF8( aSegment->m_Uuid.AsString() ) );
773 
774  if( aSegment->GetStatus() )
775  m_out->Print( 0, " (status %X)", aSegment->GetStatus() );
776 
777  m_out->Print( 0, ")\n" );
778 }
779 
780 
781 void PCB_IO::format( EDGE_MODULE* aModuleDrawing, int aNestLevel ) const
782 {
783  switch( aModuleDrawing->GetShape() )
784  {
785  case S_SEGMENT: // Line
786  m_out->Print( aNestLevel, "(fp_line (start %s) (end %s)",
787  FormatInternalUnits( aModuleDrawing->GetStart0() ).c_str(),
788  FormatInternalUnits( aModuleDrawing->GetEnd0() ).c_str() );
789  break;
790 
791  case S_RECT: // Rectangle
792  m_out->Print( aNestLevel, "(fp_rect (start %s) (end %s)",
793  FormatInternalUnits( aModuleDrawing->GetStart0() ).c_str(),
794  FormatInternalUnits( aModuleDrawing->GetEnd0() ).c_str() );
795  break;
796 
797  case S_CIRCLE: // Circle
798  m_out->Print( aNestLevel, "(fp_circle (center %s) (end %s)",
799  FormatInternalUnits( aModuleDrawing->GetStart0() ).c_str(),
800  FormatInternalUnits( aModuleDrawing->GetEnd0() ).c_str() );
801  break;
802 
803  case S_ARC: // Arc
804  m_out->Print( aNestLevel, "(fp_arc (start %s) (end %s) (angle %s)",
805  FormatInternalUnits( aModuleDrawing->GetStart0() ).c_str(),
806  FormatInternalUnits( aModuleDrawing->GetEnd0() ).c_str(),
807  FormatAngle( aModuleDrawing->GetAngle() ).c_str() );
808  break;
809 
810  case S_POLYGON: // Polygonal segment
811  if( aModuleDrawing->IsPolyShapeValid() )
812  {
813  SHAPE_POLY_SET& poly = aModuleDrawing->GetPolyShape();
814  SHAPE_LINE_CHAIN& outline = poly.Outline( 0 );
815  int pointsCount = outline.PointCount();
816 
817  m_out->Print( aNestLevel, "(fp_poly (pts" );
818 
819  for( int ii = 0; ii < pointsCount; ++ii )
820  {
821  int nestLevel = 0;
822 
823  if( ii && !( ii%4 ) ) // newline every 4 pts
824  {
825  nestLevel = aNestLevel + 1;
826  m_out->Print( 0, "\n" );
827  }
828 
829  m_out->Print( nestLevel, "%s(xy %s)",
830  nestLevel ? "" : " ", FormatInternalUnits( outline.CPoint( ii ) ).c_str() );
831  }
832 
833  m_out->Print( 0, ")" );
834  }
835  else
836  {
837  wxFAIL_MSG( wxT( "Cannot format invalid polygon." ) );
838  return;
839  }
840  break;
841 
842  case S_CURVE: // Bezier curve
843  m_out->Print( aNestLevel, "(fp_curve (pts (xy %s) (xy %s) (xy %s) (xy %s))",
844  FormatInternalUnits( aModuleDrawing->GetStart0() ).c_str(),
845  FormatInternalUnits( aModuleDrawing->GetBezier0_C1() ).c_str(),
846  FormatInternalUnits( aModuleDrawing->GetBezier0_C2() ).c_str(),
847  FormatInternalUnits( aModuleDrawing->GetEnd0() ).c_str() );
848  break;
849 
850  default:
851  wxFAIL_MSG( "PCB_IO::format cannot format unknown EDGE_MODULE shape:"
852  + STROKE_T_asString( aModuleDrawing->GetShape() ) );
853  return;
854  };
855 
856  formatLayer( aModuleDrawing );
857 
858  m_out->Print( 0, " (width %s)", FormatInternalUnits( aModuleDrawing->GetWidth() ).c_str() );
859 
860  m_out->Print( 0, ")\n" );
861 }
862 
863 
864 void PCB_IO::format( PCB_TARGET* aTarget, int aNestLevel ) const
865 {
866  m_out->Print( aNestLevel, "(target %s (at %s) (size %s)",
867  ( aTarget->GetShape() ) ? "x" : "plus",
868  FormatInternalUnits( aTarget->GetPosition() ).c_str(),
869  FormatInternalUnits( aTarget->GetSize() ).c_str() );
870 
871  if( aTarget->GetWidth() != 0 )
872  m_out->Print( 0, " (width %s)", FormatInternalUnits( aTarget->GetWidth() ).c_str() );
873 
874  formatLayer( aTarget );
875 
876  m_out->Print( 0, " (tstamp %s)", TO_UTF8( aTarget->m_Uuid.AsString() ) );
877 
878  m_out->Print( 0, ")\n" );
879 }
880 
881 
882 void PCB_IO::format( MODULE* aModule, int aNestLevel ) const
883 {
884  if( !( m_ctl & CTL_OMIT_INITIAL_COMMENTS ) )
885  {
886  const wxArrayString* initial_comments = aModule->GetInitialComments();
887 
888  if( initial_comments )
889  {
890  for( unsigned i=0; i<initial_comments->GetCount(); ++i )
891  m_out->Print( aNestLevel, "%s\n", TO_UTF8( (*initial_comments)[i] ) );
892 
893  m_out->Print( 0, "\n" ); // improve readability?
894  }
895  }
896 
897  m_out->Print( aNestLevel, "(module %s",
898  m_out->Quotes( aModule->GetFPID().Format() ).c_str() );
899 
900  if( aModule->IsLocked() )
901  m_out->Print( 0, " locked" );
902 
903  if( aModule->IsPlaced() )
904  m_out->Print( 0, " placed" );
905 
906  formatLayer( aModule );
907 
908  m_out->Print( 0, " (tedit %lX)", (unsigned long)aModule->GetLastEditTime() );
909 
910  if( !( m_ctl & CTL_OMIT_TSTAMPS ) )
911  m_out->Print( 0, " (tstamp %s)", TO_UTF8( aModule->m_Uuid.AsString() ) );
912 
913  m_out->Print( 0, "\n" );
914 
915  if( !( m_ctl & CTL_OMIT_AT ) )
916  {
917  m_out->Print( aNestLevel+1, "(at %s", FormatInternalUnits( aModule->GetPosition() ).c_str() );
918 
919  if( aModule->GetOrientation() != 0.0 )
920  m_out->Print( 0, " %s", FormatAngle( aModule->GetOrientation() ).c_str() );
921 
922  m_out->Print( 0, ")\n" );
923  }
924 
925  if( !aModule->GetDescription().IsEmpty() )
926  m_out->Print( aNestLevel+1, "(descr %s)\n",
927  m_out->Quotew( aModule->GetDescription() ).c_str() );
928 
929  if( !aModule->GetKeywords().IsEmpty() )
930  m_out->Print( aNestLevel+1, "(tags %s)\n",
931  m_out->Quotew( aModule->GetKeywords() ).c_str() );
932 
933  if( !( m_ctl & CTL_OMIT_PATH ) && !aModule->GetPath().empty() )
934  m_out->Print( aNestLevel+1, "(path %s)\n",
935  m_out->Quotew( aModule->GetPath().AsString() ).c_str() );
936 
937  if( aModule->GetPlacementCost90() != 0 )
938  m_out->Print( aNestLevel+1, "(autoplace_cost90 %d)\n", aModule->GetPlacementCost90() );
939 
940  if( aModule->GetPlacementCost180() != 0 )
941  m_out->Print( aNestLevel+1, "(autoplace_cost180 %d)\n", aModule->GetPlacementCost180() );
942 
943  if( aModule->GetLocalSolderMaskMargin() != 0 )
944  m_out->Print( aNestLevel+1, "(solder_mask_margin %s)\n",
945  FormatInternalUnits( aModule->GetLocalSolderMaskMargin() ).c_str() );
946 
947  if( aModule->GetLocalSolderPasteMargin() != 0 )
948  m_out->Print( aNestLevel+1, "(solder_paste_margin %s)\n",
949  FormatInternalUnits( aModule->GetLocalSolderPasteMargin() ).c_str() );
950 
951  if( aModule->GetLocalSolderPasteMarginRatio() != 0 )
952  m_out->Print( aNestLevel+1, "(solder_paste_ratio %s)\n",
953  Double2Str( aModule->GetLocalSolderPasteMarginRatio() ).c_str() );
954 
955  if( aModule->GetLocalClearance() != 0 )
956  m_out->Print( aNestLevel+1, "(clearance %s)\n",
957  FormatInternalUnits( aModule->GetLocalClearance() ).c_str() );
958 
960  m_out->Print( aNestLevel+1, "(zone_connect %d)\n",
961  static_cast<int>( aModule->GetZoneConnection() ) );
962 
963  if( aModule->GetThermalWidth() != 0 )
964  m_out->Print( aNestLevel+1, "(thermal_width %s)\n",
965  FormatInternalUnits( aModule->GetThermalWidth() ).c_str() );
966 
967  if( aModule->GetThermalGap() != 0 )
968  m_out->Print( aNestLevel+1, "(thermal_gap %s)\n",
969  FormatInternalUnits( aModule->GetThermalGap() ).c_str() );
970 
971  // Attributes
972  if( aModule->GetAttributes() != MOD_DEFAULT )
973  {
974  m_out->Print( aNestLevel+1, "(attr" );
975 
976  if( aModule->GetAttributes() & MOD_CMS )
977  m_out->Print( 0, " smd" );
978 
979  if( aModule->GetAttributes() & MOD_VIRTUAL )
980  m_out->Print( 0, " virtual" );
981 
982  m_out->Print( 0, ")\n" );
983  }
984 
985  Format( (BOARD_ITEM*) &aModule->Reference(), aNestLevel+1 );
986  Format( (BOARD_ITEM*) &aModule->Value(), aNestLevel+1 );
987 
988  // Save drawing elements.
989  for( auto gr : aModule->GraphicalItems() )
990  Format( gr, aNestLevel+1 );
991 
992  // Save pads.
993  for( auto pad : aModule->Pads() )
994  format( pad, aNestLevel+1 );
995 
996  // Save zones.
997  for( auto zone : aModule->Zones() )
998  format( zone, aNestLevel + 1 );
999 
1000  // Save 3D info.
1001  auto bs3D = aModule->Models().begin();
1002  auto es3D = aModule->Models().end();
1003 
1004  while( bs3D != es3D )
1005  {
1006  if( !bs3D->m_Filename.IsEmpty() )
1007  {
1008  m_out->Print( aNestLevel+1, "(model %s%s\n",
1009  m_out->Quotew( bs3D->m_Filename ).c_str(),
1010  bs3D->m_Show ? "" : " hide" );
1011 
1012  if( bs3D->m_Opacity != 1.0 )
1013  m_out->Print( aNestLevel+2, "(opacity %0.4f)", bs3D->m_Opacity );
1014 
1015  /* Write 3D model offset in mm
1016  * 4.0.x wrote "at" which was actually in inches
1017  * 5.0.x onwards, 3D model offset is written using "offset"
1018  *
1019  * If the offset is all zero, write "at" (fewer file changes)
1020  * Otherwise, write "offset"
1021  */
1022 
1023  wxString offsetTag = "offset";
1024 
1025  if( bs3D->m_Offset.x == 0 &&
1026  bs3D->m_Offset.y == 0 &&
1027  bs3D->m_Offset.z == 0 )
1028  {
1029  offsetTag = "at";
1030  }
1031 
1032  m_out->Print( aNestLevel+2, "(%s (xyz %s %s %s))\n",
1033  offsetTag.ToStdString().c_str(),
1034  Double2Str( bs3D->m_Offset.x ).c_str(),
1035  Double2Str( bs3D->m_Offset.y ).c_str(),
1036  Double2Str( bs3D->m_Offset.z ).c_str() );
1037 
1038  m_out->Print( aNestLevel+2, "(scale (xyz %s %s %s))\n",
1039  Double2Str( bs3D->m_Scale.x ).c_str(),
1040  Double2Str( bs3D->m_Scale.y ).c_str(),
1041  Double2Str( bs3D->m_Scale.z ).c_str() );
1042 
1043  m_out->Print( aNestLevel+2, "(rotate (xyz %s %s %s))\n",
1044  Double2Str( bs3D->m_Rotation.x ).c_str(),
1045  Double2Str( bs3D->m_Rotation.y ).c_str(),
1046  Double2Str( bs3D->m_Rotation.z ).c_str() );
1047 
1048  m_out->Print( aNestLevel+1, ")\n" );
1049  }
1050  ++bs3D;
1051  }
1052 
1053  m_out->Print( aNestLevel, ")\n" );
1054 }
1055 
1056 
1057 void PCB_IO::formatLayers( LSET aLayerMask, int aNestLevel ) const
1058 {
1059  std::string output;
1060 
1061  if( aNestLevel == 0 )
1062  output += ' ';
1063 
1064  output += "(layers";
1065 
1066  static const LSET cu_all( LSET::AllCuMask() );
1067  static const LSET fr_bk( 2, B_Cu, F_Cu );
1068  static const LSET adhes( 2, B_Adhes, F_Adhes );
1069  static const LSET paste( 2, B_Paste, F_Paste );
1070  static const LSET silks( 2, B_SilkS, F_SilkS );
1071  static const LSET mask( 2, B_Mask, F_Mask );
1072  static const LSET crt_yd(2, B_CrtYd, F_CrtYd );
1073  static const LSET fab( 2, B_Fab, F_Fab );
1074 
1075  LSET cu_mask = cu_all;
1076 
1077  // output copper layers first, then non copper
1078 
1079  if( ( aLayerMask & cu_mask ) == cu_mask )
1080  {
1081  output += " *.Cu";
1082  aLayerMask &= ~cu_all; // clear bits, so they are not output again below
1083  }
1084  else if( ( aLayerMask & cu_mask ) == fr_bk )
1085  {
1086  output += " F&B.Cu";
1087  aLayerMask &= ~fr_bk;
1088  }
1089 
1090  if( ( aLayerMask & adhes ) == adhes )
1091  {
1092  output += " *.Adhes";
1093  aLayerMask &= ~adhes;
1094  }
1095 
1096  if( ( aLayerMask & paste ) == paste )
1097  {
1098  output += " *.Paste";
1099  aLayerMask &= ~paste;
1100  }
1101 
1102  if( ( aLayerMask & silks ) == silks )
1103  {
1104  output += " *.SilkS";
1105  aLayerMask &= ~silks;
1106  }
1107 
1108  if( ( aLayerMask & mask ) == mask )
1109  {
1110  output += " *.Mask";
1111  aLayerMask &= ~mask;
1112  }
1113 
1114  if( ( aLayerMask & crt_yd ) == crt_yd )
1115  {
1116  output += " *.CrtYd";
1117  aLayerMask &= ~crt_yd;
1118  }
1119 
1120  if( ( aLayerMask & fab ) == fab )
1121  {
1122  output += " *.Fab";
1123  aLayerMask &= ~fab;
1124  }
1125 
1126  // output any individual layers not handled in wildcard combos above
1127 
1128  wxString layerName;
1129 
1130  for( LAYER_NUM layer = 0; layer < PCB_LAYER_ID_COUNT; ++layer )
1131  {
1132  if( aLayerMask[layer] )
1133  {
1134  if( m_board && !( m_ctl & CTL_STD_LAYER_NAMES ) )
1135  layerName = m_board->GetLayerName( PCB_LAYER_ID( layer ) );
1136 
1137  else // I am being called from FootprintSave()
1138  layerName = BOARD::GetStandardLayerName( PCB_LAYER_ID( layer ) );
1139 
1140  output += ' ';
1141  output += m_out->Quotew( layerName );
1142  }
1143  }
1144 
1145  m_out->Print( aNestLevel, "%s)", output.c_str() );
1146 }
1147 
1148 
1149 void PCB_IO::format( D_PAD* aPad, int aNestLevel ) const
1150 {
1151  const char* shape;
1152 
1153  switch( aPad->GetShape() )
1154  {
1155  case PAD_SHAPE_CIRCLE: shape = "circle"; break;
1156  case PAD_SHAPE_RECT: shape = "rect"; break;
1157  case PAD_SHAPE_OVAL: shape = "oval"; break;
1158  case PAD_SHAPE_TRAPEZOID: shape = "trapezoid"; break;
1160  case PAD_SHAPE_ROUNDRECT: shape = "roundrect"; break;
1161  case PAD_SHAPE_CUSTOM: shape = "custom"; break;
1162 
1163  default:
1164  THROW_IO_ERROR( wxString::Format( _( "unknown pad type: %d"), aPad->GetShape() ) );
1165  }
1166 
1167  const char* type;
1168 
1169  switch( aPad->GetAttribute() )
1170  {
1171  case PAD_ATTRIB_STANDARD: type = "thru_hole"; break;
1172  case PAD_ATTRIB_SMD: type = "smd"; break;
1173  case PAD_ATTRIB_CONN: type = "connect"; break;
1174  case PAD_ATTRIB_HOLE_NOT_PLATED: type = "np_thru_hole"; break;
1175 
1176  default:
1177  THROW_IO_ERROR( wxString::Format( "unknown pad attribute: %d", aPad->GetAttribute() ) );
1178  }
1179 
1180  const char* property = nullptr;
1181 
1182  switch( aPad->GetProperty() )
1183  {
1184  case PAD_PROP_NONE: break;
1185  case PAD_PROP_BGA: property = "pad_prop_bga"; break;
1186  case PAD_PROP_FIDUCIAL_GLBL: property = "pad_prop_fiducial_glob"; break;
1187  case PAD_PROP_FIDUCIAL_LOCAL: property = "pad_prop_fiducial_loc"; break;
1188  case PAD_PROP_TESTPOINT: property = "pad_prop_testpoint"; break;
1189  case PAD_PROP_HEATSINK: property = "pad_prop_heatsink"; break;
1190  case PAD_PROP_CASTELLATED: property = "pad_prop_castellated"; break;
1191 
1192  default:
1193  THROW_IO_ERROR( wxString::Format( "unknown pad property: %d", aPad->GetProperty() ) );
1194  }
1195 
1196  m_out->Print( aNestLevel, "(pad %s %s %s",
1197  m_out->Quotew( aPad->GetName() ).c_str(),
1198  type, shape );
1199  m_out->Print( 0, " (at %s", FormatInternalUnits( aPad->GetPos0() ).c_str() );
1200 
1201  if( aPad->GetOrientation() != 0.0 )
1202  m_out->Print( 0, " %s", FormatAngle( aPad->GetOrientation() ).c_str() );
1203 
1204  m_out->Print( 0, ")" );
1205  m_out->Print( 0, " (size %s)", FormatInternalUnits( aPad->GetSize() ).c_str() );
1206 
1207  if( (aPad->GetDelta().GetWidth()) != 0 || (aPad->GetDelta().GetHeight() != 0 ) )
1208  m_out->Print( 0, " (rect_delta %s )", FormatInternalUnits( aPad->GetDelta() ).c_str() );
1209 
1210  wxSize sz = aPad->GetDrillSize();
1211  wxPoint shapeoffset = aPad->GetOffset();
1212 
1213  if( (sz.GetWidth() > 0) || (sz.GetHeight() > 0) ||
1214  (shapeoffset.x != 0) || (shapeoffset.y != 0) )
1215  {
1216  m_out->Print( 0, " (drill" );
1217 
1218  if( aPad->GetDrillShape() == PAD_DRILL_SHAPE_OBLONG )
1219  m_out->Print( 0, " oval" );
1220 
1221  if( sz.GetWidth() > 0 )
1222  m_out->Print( 0, " %s", FormatInternalUnits( sz.GetWidth() ).c_str() );
1223 
1224  if( sz.GetHeight() > 0 && sz.GetWidth() != sz.GetHeight() )
1225  m_out->Print( 0, " %s", FormatInternalUnits( sz.GetHeight() ).c_str() );
1226 
1227  if( (shapeoffset.x != 0) || (shapeoffset.y != 0) )
1228  m_out->Print( 0, " (offset %s)", FormatInternalUnits( aPad->GetOffset() ).c_str() );
1229 
1230  m_out->Print( 0, ")" );
1231  }
1232 
1233  if( property && ADVANCED_CFG::GetCfg().m_EnableUsePadProperty )
1234  {
1235  // Add pad property, if exists.
1236  m_out->Print( 0, " (property %s)", property );
1237  }
1238 
1239  formatLayers( aPad->GetLayerSet() );
1240 
1241  // Output the radius ratio for rounded and chamfered rect pads
1242  if( aPad->GetShape() == PAD_SHAPE_ROUNDRECT || aPad->GetShape() == PAD_SHAPE_CHAMFERED_RECT)
1243  {
1244  m_out->Print( 0, " (roundrect_rratio %s)",
1245  Double2Str( aPad->GetRoundRectRadiusRatio() ).c_str() );
1246  }
1247 
1248  // Output the chamfer corners for chamfered rect pads
1249  if( aPad->GetShape() == PAD_SHAPE_CHAMFERED_RECT)
1250  {
1251  m_out->Print( 0, "\n" );
1252 
1253  m_out->Print( aNestLevel+1, "(chamfer_ratio %s)",
1254  Double2Str( aPad->GetChamferRectRatio() ).c_str() );
1255 
1256  m_out->Print( 0, " (chamfer" );
1257 
1258  if( ( aPad->GetChamferPositions() & RECT_CHAMFER_TOP_LEFT ) )
1259  m_out->Print( 0, " top_left" );
1260 
1261  if( ( aPad->GetChamferPositions() & RECT_CHAMFER_TOP_RIGHT ) )
1262  m_out->Print( 0, " top_right" );
1263 
1264  if( ( aPad->GetChamferPositions() & RECT_CHAMFER_BOTTOM_LEFT ) )
1265  m_out->Print( 0, " bottom_left" );
1266 
1268  m_out->Print( 0, " bottom_right" );
1269 
1270  m_out->Print( 0, ")" );
1271  }
1272 
1273  std::string output;
1274 
1275  // Unconnected pad is default net so don't save it.
1276  if( !( m_ctl & CTL_OMIT_NETS ) && aPad->GetNetCode() != NETINFO_LIST::UNCONNECTED )
1277  StrPrintf( &output, " (net %d %s)", m_mapping->Translate( aPad->GetNetCode() ),
1278  m_out->Quotew( aPad->GetNetname() ).c_str() );
1279 
1280  // Add pinfunction, if exists.
1281  // Pin function is closely related to nets, so if CTL_OMIT_NETS is set,
1282  // omit also pin function (for instance when saved from library editor)
1283  if( !(m_ctl & CTL_OMIT_NETS) && !aPad->GetPinFunction().IsEmpty() )
1284  StrPrintf( &output, " (pinfunction %s)",
1285  m_out->Quotew( aPad->GetPinFunction() ).c_str() );
1286 
1287  if( aPad->GetPadToDieLength() != 0 )
1288  StrPrintf( &output, " (die_length %s)",
1289  FormatInternalUnits( aPad->GetPadToDieLength() ).c_str() );
1290 
1291  if( aPad->GetLocalSolderMaskMargin() != 0 )
1292  StrPrintf( &output, " (solder_mask_margin %s)",
1293  FormatInternalUnits( aPad->GetLocalSolderMaskMargin() ).c_str() );
1294 
1295  if( aPad->GetLocalSolderPasteMargin() != 0 )
1296  StrPrintf( &output, " (solder_paste_margin %s)",
1297  FormatInternalUnits( aPad->GetLocalSolderPasteMargin() ).c_str() );
1298 
1299  if( aPad->GetLocalSolderPasteMarginRatio() != 0 )
1300  StrPrintf( &output, " (solder_paste_margin_ratio %s)",
1301  Double2Str( aPad->GetLocalSolderPasteMarginRatio() ).c_str() );
1302 
1303  if( aPad->GetLocalClearance() != 0 )
1304  StrPrintf( &output, " (clearance %s)", FormatInternalUnits( aPad->GetLocalClearance() ).c_str() );
1305 
1307  StrPrintf( &output, " (zone_connect %d)", static_cast<int>( aPad->GetEffectiveZoneConnection() ) );
1308 
1309  if( aPad->GetThermalWidth() != 0 )
1310  StrPrintf( &output, " (thermal_width %s)", FormatInternalUnits( aPad->GetThermalWidth() ).c_str() );
1311 
1312  if( aPad->GetThermalGap() != 0 )
1313  StrPrintf( &output, " (thermal_gap %s)", FormatInternalUnits( aPad->GetThermalGap() ).c_str() );
1314 
1315  if( output.size() )
1316  {
1317  m_out->Print( 0, "\n" );
1318  m_out->Print( aNestLevel+1, "%s", output.c_str()+1 ); // +1 skips 1st space on 1st element
1319  }
1320 
1321  if( aPad->GetShape() == PAD_SHAPE_CUSTOM )
1322  {
1323  m_out->Print( 0, "\n");
1324  m_out->Print( aNestLevel+1, "(options" );
1325 
1327  m_out->Print( 0, " (clearance convexhull)" );
1328  #if 1 // Set to 1 to output the default option
1329  else
1330  m_out->Print( 0, " (clearance outline)" );
1331  #endif
1332 
1333  // Output the anchor pad shape (circle/rect)
1334  if( aPad->GetAnchorPadShape() == PAD_SHAPE_RECT )
1335  shape = "rect";
1336  else
1337  shape = "circle";
1338 
1339  m_out->Print( 0, " (anchor %s)", shape );
1340 
1341  m_out->Print( 0, ")"); // end of (options ...
1342 
1343  // Output graphic primitive of the pad shape
1344  m_out->Print( 0, "\n");
1345  m_out->Print( aNestLevel+1, "(primitives" );
1346 
1347  int nested_level = aNestLevel+2;
1348 
1349  // Output all basic shapes
1350  for( const std::shared_ptr<DRAWSEGMENT> primitive : aPad->GetPrimitives() )
1351  {
1352  m_out->Print( 0, "\n");
1353 
1354  switch( primitive->GetShape() )
1355  {
1356  case S_SEGMENT: // usual segment : line with rounded ends
1357  m_out->Print( nested_level, "(gr_line (start %s) (end %s) (width %s))",
1358  FormatInternalUnits( primitive->GetStart() ).c_str(),
1359  FormatInternalUnits( primitive->GetEnd() ).c_str(),
1360  FormatInternalUnits( primitive->GetWidth() ).c_str() );
1361  break;
1362 
1363  case S_RECT:
1364  m_out->Print( nested_level, "(gr_rect (start %s) (end %s) (width %s))",
1365  FormatInternalUnits( primitive->GetStart() ).c_str(),
1366  FormatInternalUnits( primitive->GetEnd() ).c_str(),
1367  FormatInternalUnits( primitive->GetWidth() ).c_str() );
1368  break;
1369 
1370  case S_ARC: // Arc with rounded ends
1371  m_out->Print( nested_level, "(gr_arc (start %s) (end %s) (angle %s) (width %s))",
1372  FormatInternalUnits( primitive->GetStart() ).c_str(),
1373  FormatInternalUnits( primitive->GetEnd() ).c_str(),
1374  FormatAngle( primitive->GetAngle() ).c_str(),
1375  FormatInternalUnits( primitive->GetWidth() ).c_str() );
1376  break;
1377 
1378  case S_CIRCLE: // ring or circle (circle if width == 0
1379  m_out->Print( nested_level, "(gr_circle (center %s) (end %s) (width %s))",
1380  FormatInternalUnits( primitive->GetStart() ).c_str(),
1381  FormatInternalUnits( primitive->GetEnd() ).c_str(),
1382  FormatInternalUnits( primitive->GetWidth() ).c_str() );
1383  break;
1384 
1385  case S_CURVE: // Bezier Curve
1386  m_out->Print( aNestLevel, "(gr_curve (pts (xy %s) (xy %s) (xy %s) (xy %s)) (width %s))",
1387  FormatInternalUnits( primitive->GetStart() ).c_str(),
1388  FormatInternalUnits( primitive->GetBezControl1() ).c_str(),
1389  FormatInternalUnits( primitive->GetBezControl2() ).c_str(),
1390  FormatInternalUnits( primitive->GetEnd() ).c_str(),
1391  FormatInternalUnits( primitive->GetWidth() ).c_str() );
1392  break;
1393 
1394  case S_POLYGON: // polygon
1395  if( primitive->GetPolyShape().COutline( 0 ).CPoints().size() < 2 )
1396  break; // Malformed polygon.
1397 
1398  {
1399  m_out->Print( nested_level, "(gr_poly (pts\n");
1400 
1401  // Write the polygon corners coordinates:
1402  int newLine = 0;
1403 
1404  for( const VECTOR2I &pt : primitive->GetPolyShape().COutline( 0 ).CPoints() )
1405  {
1406  if( newLine == 0 )
1407  m_out->Print( nested_level+1, " (xy %s)",
1408  FormatInternalUnits( (wxPoint) pt ).c_str() );
1409  else
1410  m_out->Print( 0, " (xy %s)",
1411  FormatInternalUnits( (wxPoint) pt ).c_str() );
1412 
1413  if( ++newLine > 4 )
1414  {
1415  newLine = 0;
1416  m_out->Print( 0, "\n" );
1417  }
1418  }
1419 
1420  m_out->Print( 0, ") (width %s))", FormatInternalUnits( primitive->GetWidth() ).c_str() );
1421  }
1422  break;
1423 
1424  default:
1425  break;
1426  }
1427  }
1428 
1429  m_out->Print( 0, "\n");
1430  m_out->Print( aNestLevel+1, ")" ); // end of (basic_shapes
1431  }
1432 
1433  m_out->Print( 0, " (tstamp %s)", TO_UTF8( aPad->m_Uuid.AsString() ) );
1434 
1435  m_out->Print( 0, ")\n" );
1436 }
1437 
1438 
1439 void PCB_IO::format( TEXTE_PCB* aText, int aNestLevel ) const
1440 {
1441  m_out->Print( aNestLevel, "(gr_text %s (at %s",
1442  m_out->Quotew( aText->GetText() ).c_str(),
1443  FormatInternalUnits( aText->GetTextPos() ).c_str() );
1444 
1445  if( aText->GetTextAngle() != 0.0 )
1446  m_out->Print( 0, " %s", FormatAngle( aText->GetTextAngle() ).c_str() );
1447 
1448  m_out->Print( 0, ")" );
1449 
1450  formatLayer( aText );
1451 
1452  m_out->Print( 0, " (tstamp %s)", TO_UTF8( aText->m_Uuid.AsString() ) );
1453 
1454  m_out->Print( 0, "\n" );
1455 
1456  aText->EDA_TEXT::Format( m_out, aNestLevel, m_ctl );
1457 
1458  m_out->Print( aNestLevel, ")\n" );
1459 }
1460 
1461 
1462 void PCB_IO::format( TEXTE_MODULE* aText, int aNestLevel ) const
1463 {
1464  std::string type;
1465 
1466  switch( aText->GetType() )
1467  {
1468  case TEXTE_MODULE::TEXT_is_REFERENCE: type = "reference"; break;
1469  case TEXTE_MODULE::TEXT_is_VALUE: type = "value"; break;
1470  case TEXTE_MODULE::TEXT_is_DIVERS: type = "user";
1471  }
1472 
1473  m_out->Print( aNestLevel, "(fp_text %s %s (at %s",
1474  type.c_str(),
1475  m_out->Quotew( aText->GetText() ).c_str(),
1476  FormatInternalUnits( aText->GetPos0() ).c_str() );
1477 
1478  // Due to Pcbnew history, fp_text angle is saved as an absolute on screen angle,
1479  // but internally the angle is held relative to its parent footprint. parent
1480  // may be NULL when saving a footprint outside a BOARD.
1481  double orient = aText->GetTextAngle();
1482  MODULE* parent = (MODULE*) aText->GetParent();
1483 
1484  if( parent )
1485  {
1486  // GetTextAngle() is always in -360..+360 range because of
1487  // TEXTE_MODULE::SetTextAngle(), but summing that angle with an
1488  // additional board angle could kick sum up >= 360 or <= -360, so to have
1489  // consistent results, normalize again for the BOARD save. A footprint
1490  // save does not use this code path since parent is NULL.
1491 #if 0
1492  // This one could be considered reasonable if you like positive angles
1493  // in your board text.
1494  orient = NormalizeAnglePos( orient + parent->GetOrientation() );
1495 #else
1496  // Choose compatibility for now, even though this is only a 720 degree clamp
1497  // with two possible values for every angle.
1498  orient = NormalizeAngle360Min( orient + parent->GetOrientation() );
1499 #endif
1500  }
1501 
1502  if( orient != 0.0 )
1503  m_out->Print( 0, " %s", FormatAngle( orient ).c_str() );
1504 
1505  if( !aText->IsKeepUpright() )
1506  m_out->Print( 0, " unlocked" );
1507 
1508  m_out->Print( 0, ")" );
1509  formatLayer( aText );
1510 
1511  if( !aText->IsVisible() )
1512  m_out->Print( 0, " hide" );
1513 
1514  m_out->Print( 0, "\n" );
1515 
1516  aText->EDA_TEXT::Format( m_out, aNestLevel, m_ctl | CTL_OMIT_HIDE );
1517 
1518  m_out->Print( aNestLevel, ")\n" );
1519 }
1520 
1521 
1522 void PCB_IO::format( TRACK* aTrack, int aNestLevel ) const
1523 {
1524  if( aTrack->Type() == PCB_VIA_T )
1525  {
1526  PCB_LAYER_ID layer1, layer2;
1527 
1528  const VIA* via = static_cast<const VIA*>( aTrack );
1529  BOARD* board = (BOARD*) via->GetParent();
1530 
1531  wxCHECK_RET( board != 0, wxT( "Via " ) + via->GetSelectMenuText( EDA_UNITS::MILLIMETRES )
1532  + wxT( " has no parent." ) );
1533 
1534  m_out->Print( aNestLevel, "(via" );
1535 
1536  via->LayerPair( &layer1, &layer2 );
1537 
1538  switch( via->GetViaType() )
1539  {
1540  case VIATYPE::THROUGH: // Default shape not saved.
1541  break;
1542 
1543  case VIATYPE::BLIND_BURIED:
1544  m_out->Print( 0, " blind" );
1545  break;
1546 
1547  case VIATYPE::MICROVIA:
1548  m_out->Print( 0, " micro" );
1549  break;
1550 
1551  default:
1552  THROW_IO_ERROR( wxString::Format( _( "unknown via type %d" ), via->GetViaType() ) );
1553  }
1554 
1555  m_out->Print( 0, " (at %s) (size %s)",
1556  FormatInternalUnits( aTrack->GetStart() ).c_str(),
1557  FormatInternalUnits( aTrack->GetWidth() ).c_str() );
1558 
1559  if( via->GetDrill() != UNDEFINED_DRILL_DIAMETER )
1560  m_out->Print( 0, " (drill %s)", FormatInternalUnits( via->GetDrill() ).c_str() );
1561 
1562  m_out->Print( 0, " (layers %s %s)",
1563  m_out->Quotew( m_board->GetLayerName( layer1 ) ).c_str(),
1564  m_out->Quotew( m_board->GetLayerName( layer2 ) ).c_str() );
1565  }
1566  else if( aTrack->Type() == PCB_ARC_T )
1567  {
1568  const ARC* arc = static_cast<const ARC*>( aTrack );
1569 
1570  m_out->Print( aNestLevel, "(arc (start %s) (mid %s) (end %s) (width %s)",
1571  FormatInternalUnits( arc->GetStart() ).c_str(),
1572  FormatInternalUnits( arc->GetMid() ).c_str(),
1573  FormatInternalUnits( arc->GetEnd() ).c_str(),
1574  FormatInternalUnits( arc->GetWidth() ).c_str() );
1575 
1576  m_out->Print( 0, " (layer %s)", m_out->Quotew( aTrack->GetLayerName() ).c_str() );
1577  }
1578  else
1579  {
1580  m_out->Print( aNestLevel, "(segment (start %s) (end %s) (width %s)",
1581  FormatInternalUnits( aTrack->GetStart() ).c_str(), FormatInternalUnits( aTrack->GetEnd() ).c_str(),
1582  FormatInternalUnits( aTrack->GetWidth() ).c_str() );
1583 
1584  m_out->Print( 0, " (layer %s)", m_out->Quotew( aTrack->GetLayerName() ).c_str() );
1585  }
1586 
1587  m_out->Print( 0, " (net %d)", m_mapping->Translate( aTrack->GetNetCode() ) );
1588 
1589  m_out->Print( 0, " (tstamp %s)", TO_UTF8( aTrack->m_Uuid.AsString() ) );
1590 
1591  if( aTrack->GetStatus() != 0 )
1592  m_out->Print( 0, " (status %X)", aTrack->GetStatus() );
1593 
1594  m_out->Print( 0, ")\n" );
1595 }
1596 
1597 
1598 void PCB_IO::format( ZONE_CONTAINER* aZone, int aNestLevel ) const
1599 {
1600  // Save the NET info; For keepout zones, net code and net name are irrelevant
1601  // so be sure a dummy value is stored, just for ZONE_CONTAINER compatibility
1602  // (perhaps netcode and netname should be not stored)
1603  m_out->Print( aNestLevel, "(zone (net %d) (net_name %s)",
1604  aZone->GetIsKeepout() ? 0 : m_mapping->Translate( aZone->GetNetCode() ),
1605  m_out->Quotew( aZone->GetIsKeepout() ? wxT("") : aZone->GetNetname() ).c_str() );
1606 
1607  // If a zone exists on multiple layers, format accordingly
1608  if( aZone->GetLayerSet().count() > 1 )
1609  {
1610  formatLayers( aZone->GetLayerSet() );
1611  }
1612  else
1613  {
1614  formatLayer( aZone );
1615  }
1616 
1617  m_out->Print( 0, " (tstamp %s)", TO_UTF8( aZone->m_Uuid.AsString() ) );
1618 
1619  if( !aZone->GetZoneName().empty() )
1620  m_out->Print( 0, " (name %s)", m_out->Quotew( aZone->GetZoneName() ).c_str() );
1621 
1622  // Save the outline aux info
1623  std::string hatch;
1624 
1625  switch( aZone->GetHatchStyle() )
1626  {
1627  default:
1629  hatch = "none";
1630  break;
1632  hatch = "edge";
1633  break;
1635  hatch = "full";
1636  break;
1637  }
1638 
1639  m_out->Print( 0, " (hatch %s %s)\n", hatch.c_str(),
1640  FormatInternalUnits( aZone->GetHatchPitch() ).c_str() );
1641 
1642  if( aZone->GetPriority() > 0 )
1643  m_out->Print( aNestLevel+1, "(priority %d)\n", aZone->GetPriority() );
1644 
1645  m_out->Print( aNestLevel+1, "(connect_pads" );
1646 
1647  switch( aZone->GetPadConnection() )
1648  {
1649  default:
1650  case ZONE_CONNECTION::THERMAL: // Default option not saved or loaded.
1651  break;
1652 
1654  m_out->Print( 0, " thru_hole_only" );
1655  break;
1656 
1657  case ZONE_CONNECTION::FULL:
1658  m_out->Print( 0, " yes" );
1659  break;
1660 
1661  case ZONE_CONNECTION::NONE:
1662  m_out->Print( 0, " no" );
1663  break;
1664  }
1665 
1666  m_out->Print( 0, " (clearance %s))\n",
1667  FormatInternalUnits( aZone->GetZoneClearance() ).c_str() );
1668 
1669  m_out->Print( aNestLevel+1, "(min_thickness %s)",
1670  FormatInternalUnits( aZone->GetMinThickness() ).c_str() );
1671 
1672  // write it only if V 6.O version option is not used (i.e. do not write if the
1673  // "legacy" algorithm is used)
1674  if( !aZone->GetFilledPolysUseThickness() )
1675  m_out->Print( 0, " (filled_areas_thickness no)" );
1676 
1677  m_out->Print( 0, "\n" );
1678 
1679  if( aZone->GetIsKeepout() )
1680  {
1681  m_out->Print( aNestLevel+1, "(keepout (tracks %s) (vias %s) (pads %s ) (copperpour %s) (footprints %s))\n",
1682  aZone->GetDoNotAllowTracks() ? "not_allowed" : "allowed",
1683  aZone->GetDoNotAllowVias() ? "not_allowed" : "allowed",
1684  aZone->GetDoNotAllowPads() ? "not_allowed" : "allowed",
1685  aZone->GetDoNotAllowCopperPour() ? "not_allowed" : "allowed",
1686  aZone->GetDoNotAllowFootprints() ? "not_allowed" : "allowed" );
1687  }
1688 
1689  m_out->Print( aNestLevel+1, "(fill" );
1690 
1691  // Default is not filled.
1692  if( aZone->IsFilled() )
1693  m_out->Print( 0, " yes" );
1694 
1695  // Default is polygon filled.
1696  if( aZone->GetFillMode() == ZONE_FILL_MODE::HATCH_PATTERN )
1697  m_out->Print( 0, " (mode hatch)" );
1698 
1699  m_out->Print( 0, " (thermal_gap %s) (thermal_bridge_width %s)",
1700  FormatInternalUnits( aZone->GetThermalReliefGap() ).c_str(),
1701  FormatInternalUnits( aZone->GetThermalReliefCopperBridge() ).c_str() );
1702 
1704  {
1705  m_out->Print( 0, " (smoothing" );
1706 
1707  switch( aZone->GetCornerSmoothingType() )
1708  {
1710  m_out->Print( 0, " chamfer" );
1711  break;
1712 
1714  m_out->Print( 0, " fillet" );
1715  break;
1716 
1717  default:
1718  THROW_IO_ERROR( wxString::Format( _( "unknown zone corner smoothing type %d" ),
1719  aZone->GetCornerSmoothingType() ) );
1720  }
1721  m_out->Print( 0, ")" );
1722 
1723  if( aZone->GetCornerRadius() != 0 )
1724  m_out->Print( 0, " (radius %s)",
1725  FormatInternalUnits( aZone->GetCornerRadius() ).c_str() );
1726  }
1727 
1729  {
1730  m_out->Print( 0, " (island_removal_mode %d) (island_area_min %s)",
1731  static_cast<int>( aZone->GetIslandRemovalMode() ),
1732  FormatInternalUnits( aZone->GetMinIslandArea() / IU_PER_MM ).c_str() );
1733  }
1734 
1735  if( aZone->GetFillMode() == ZONE_FILL_MODE::HATCH_PATTERN )
1736  {
1737  m_out->Print( 0, "\n" );
1738  m_out->Print( aNestLevel+2, "(hatch_thickness %s) (hatch_gap %s) (hatch_orientation %s)",
1739  FormatInternalUnits( aZone->GetHatchFillTypeThickness() ).c_str(),
1740  FormatInternalUnits( aZone->GetHatchFillTypeGap() ).c_str(),
1741  Double2Str( aZone->GetHatchFillTypeOrientation() ).c_str() );
1742 
1743  if( aZone->GetHatchFillTypeSmoothingLevel() > 0 )
1744  {
1745  m_out->Print( 0, "\n" );
1746  m_out->Print( aNestLevel+2, "(hatch_smoothing_level %d) (hatch_smoothing_value %s)",
1748  Double2Str( aZone->GetHatchFillTypeSmoothingValue() ).c_str() );
1749  }
1750  }
1751 
1752  m_out->Print( 0, ")\n" );
1753 
1754  int newLine = 0;
1755 
1756  if( aZone->GetNumCorners() )
1757  {
1758  bool new_polygon = true;
1759  bool is_closed = false;
1760 
1761  for( auto iterator = aZone->IterateWithHoles(); iterator; iterator++ )
1762  {
1763  if( new_polygon )
1764  {
1765  newLine = 0;
1766  m_out->Print( aNestLevel+1, "(polygon\n" );
1767  m_out->Print( aNestLevel+2, "(pts\n" );
1768  new_polygon = false;
1769  is_closed = false;
1770  }
1771 
1772  if( newLine == 0 )
1773  m_out->Print( aNestLevel+3, "(xy %s %s)",
1774  FormatInternalUnits( iterator->x ).c_str(),
1775  FormatInternalUnits( iterator->y ).c_str() );
1776  else
1777  m_out->Print( 0, " (xy %s %s)",
1778  FormatInternalUnits( iterator->x ).c_str(),
1779  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  {
1806  if( newLine != 0 )
1807  m_out->Print( 0, "\n" );
1808 
1809  m_out->Print( aNestLevel+2, ")\n" );
1810  m_out->Print( aNestLevel+1, ")\n" );
1811  }
1812  }
1813 
1814  // Save the PolysList (filled areas)
1815  for( PCB_LAYER_ID layer : aZone->GetLayerSet().Seq() )
1816  {
1817  const SHAPE_POLY_SET& fv = aZone->GetFilledPolysList( layer );
1818  newLine = 0;
1819 
1820  if( !fv.IsEmpty() )
1821  {
1822  int poly_index = 0;
1823  bool new_polygon = true;
1824  bool is_closed = false;
1825 
1826  for( auto it = fv.CIterate(); it; ++it )
1827  {
1828  if( new_polygon )
1829  {
1830  newLine = 0;
1831  m_out->Print( aNestLevel + 1, "(filled_polygon\n" );
1832  m_out->Print( aNestLevel + 2, "(layer %s)\n",
1833  TO_UTF8( BOARD::GetStandardLayerName( layer ) ) );
1834 
1835  if( aZone->IsIsland( layer, poly_index ) )
1836  m_out->Print( aNestLevel + 2, "(island)\n" );
1837 
1838  m_out->Print( aNestLevel + 2, "(pts\n" );
1839  new_polygon = false;
1840  is_closed = false;
1841  poly_index++;
1842  }
1843 
1844  if( newLine == 0 )
1845  m_out->Print( aNestLevel + 3, "(xy %s %s)",
1846  FormatInternalUnits( it->x ).c_str(),
1847  FormatInternalUnits( it->y ).c_str() );
1848  else
1849  m_out->Print( 0, " (xy %s %s)", FormatInternalUnits( it->x ).c_str(),
1850  FormatInternalUnits( it->y ).c_str() );
1851 
1852  if( newLine < 4 )
1853  {
1854  newLine += 1;
1855  }
1856  else
1857  {
1858  newLine = 0;
1859  m_out->Print( 0, "\n" );
1860  }
1861 
1862  if( it.IsEndContour() )
1863  {
1864  is_closed = true;
1865 
1866  if( newLine != 0 )
1867  m_out->Print( 0, "\n" );
1868 
1869  m_out->Print( aNestLevel + 2, ")\n" );
1870  m_out->Print( aNestLevel + 1, ")\n" );
1871  new_polygon = true;
1872  }
1873  }
1874 
1875  if( !is_closed ) // Should not happen, but...
1876  m_out->Print( aNestLevel + 1, ")\n" );
1877  }
1878 
1879  // Save the filling segments list
1880  const auto& segs = aZone->FillSegments( layer );
1881 
1882  if( segs.size() )
1883  {
1884  m_out->Print( aNestLevel + 1, "(fill_segments\n" );
1885  m_out->Print( aNestLevel + 2, "(layer %s)\n",
1886  TO_UTF8( BOARD::GetStandardLayerName( layer ) ) );
1887 
1888  for( ZONE_SEGMENT_FILL::const_iterator it = segs.begin(); it != segs.end(); ++it )
1889  {
1890  m_out->Print( aNestLevel + 2, "(pts (xy %s) (xy %s))\n",
1891  FormatInternalUnits( wxPoint( it->A ) ).c_str(),
1892  FormatInternalUnits( wxPoint( it->B ) ).c_str() );
1893  }
1894 
1895  m_out->Print( aNestLevel + 1, ")\n" );
1896  }
1897  }
1898 
1899  m_out->Print( aNestLevel, ")\n" );
1900 }
1901 
1902 
1903 PCB_IO::PCB_IO( int aControlFlags ) :
1904  m_cache( 0 ),
1905  m_ctl( aControlFlags ),
1906  m_parser( new PCB_PARSER() ),
1907  m_mapping( new NETINFO_MAPPING() )
1908 {
1909  init( 0 );
1910  m_out = &m_sf;
1911 }
1912 
1913 
1915 {
1916  delete m_cache;
1917  delete m_parser;
1918  delete m_mapping;
1919 }
1920 
1921 
1922 BOARD* PCB_IO::Load( const wxString& aFileName, BOARD* aAppendToMe, const PROPERTIES* aProperties )
1923 {
1924  FILE_LINE_READER reader( aFileName );
1925 
1926  init( aProperties );
1927 
1928  m_parser->SetLineReader( &reader );
1929  m_parser->SetBoard( aAppendToMe );
1930 
1931  BOARD* board;
1932 
1933  try
1934  {
1935  board = dynamic_cast<BOARD*>( m_parser->Parse() );
1936  }
1937  catch( const FUTURE_FORMAT_ERROR& )
1938  {
1939  // Don't wrap a FUTURE_FORMAT_ERROR in another
1940  throw;
1941  }
1942  catch( const PARSE_ERROR& parse_error )
1943  {
1944  if( m_parser->IsTooRecent() )
1945  throw FUTURE_FORMAT_ERROR( parse_error, m_parser->GetRequiredVersion() );
1946  else
1947  throw;
1948  }
1949 
1950  if( !board )
1951  {
1952  // The parser loaded something that was valid, but wasn't a board.
1953  THROW_PARSE_ERROR( _( "this file does not contain a PCB" ),
1954  m_parser->CurSource(), m_parser->CurLine(),
1955  m_parser->CurLineNumber(), m_parser->CurOffset() );
1956  }
1957 
1958  // Give the filename to the board if it's new
1959  if( !aAppendToMe )
1960  board->SetFileName( aFileName );
1961 
1962  return board;
1963 }
1964 
1965 
1966 void PCB_IO::init( const PROPERTIES* aProperties )
1967 {
1968  m_board = NULL;
1969  m_reader = NULL;
1971  m_props = aProperties;
1972 }
1973 
1974 
1975 void PCB_IO::validateCache( const wxString& aLibraryPath, bool checkModified )
1976 {
1977  if( !m_cache || !m_cache->IsPath( aLibraryPath ) || ( checkModified && m_cache->IsModified() ) )
1978  {
1979  // a spectacular episode in memory management:
1980  delete m_cache;
1981  m_cache = new FP_CACHE( this, aLibraryPath );
1982  m_cache->Load();
1983  }
1984 }
1985 
1986 
1987 void PCB_IO::FootprintEnumerate( wxArrayString& aFootprintNames, const wxString& aLibPath,
1988  bool aBestEfforts, const PROPERTIES* aProperties )
1989 {
1990  LOCALE_IO toggle; // toggles on, then off, the C locale.
1991  wxDir dir( aLibPath );
1992  wxString errorMsg;
1993 
1994  init( aProperties );
1995 
1996  try
1997  {
1998  validateCache( aLibPath );
1999  }
2000  catch( const IO_ERROR& ioe )
2001  {
2002  errorMsg = ioe.What();
2003  }
2004 
2005  // Some of the files may have been parsed correctly so we want to add the valid files to
2006  // the library.
2007 
2008  for( MODULE_CITER it = m_cache->GetModules().begin(); it != m_cache->GetModules().end(); ++it )
2009  aFootprintNames.Add( it->first );
2010 
2011  if( !errorMsg.IsEmpty() && !aBestEfforts )
2012  THROW_IO_ERROR( errorMsg );
2013 }
2014 
2015 
2016 const MODULE* PCB_IO::getFootprint( const wxString& aLibraryPath,
2017  const wxString& aFootprintName,
2018  const PROPERTIES* aProperties,
2019  bool checkModified )
2020 {
2021  LOCALE_IO toggle; // toggles on, then off, the C locale.
2022 
2023  init( aProperties );
2024 
2025  try
2026  {
2027  validateCache( aLibraryPath, checkModified );
2028  }
2029  catch( const IO_ERROR& )
2030  {
2031  // do nothing with the error
2032  }
2033 
2034  const MODULE_MAP& mods = m_cache->GetModules();
2035 
2036  MODULE_CITER it = mods.find( aFootprintName );
2037 
2038  if( it == mods.end() )
2039  return nullptr;
2040 
2041  return it->second->GetModule();
2042 }
2043 
2044 
2045 const MODULE* PCB_IO::GetEnumeratedFootprint( const wxString& aLibraryPath,
2046  const wxString& aFootprintName,
2047  const PROPERTIES* aProperties )
2048 {
2049  return getFootprint( aLibraryPath, aFootprintName, aProperties, false );
2050 }
2051 
2052 
2053 bool PCB_IO::FootprintExists( const wxString& aLibraryPath, const wxString& aFootprintName,
2054  const PROPERTIES* aProperties )
2055 {
2056  // Note: checking the cache sounds like a good idea, but won't catch files which differ
2057  // only in case.
2058  //
2059  // Since this goes out to the native filesystem, we get platform differences (ie: MSW's
2060  // case-insensitive filesystem) handled "for free".
2061  // Warning: footprint names frequently contain a point. So be careful when initializing
2062  // wxFileName, and use a CTOR with extension specified
2063  wxFileName footprintFile( aLibraryPath, aFootprintName, KiCadFootprintFileExtension );
2064 
2065  return footprintFile.Exists();
2066 }
2067 
2068 
2069 MODULE* PCB_IO::FootprintLoad( const wxString& aLibraryPath, const wxString& aFootprintName,
2070  const PROPERTIES* aProperties )
2071 {
2072  const MODULE* footprint = getFootprint( aLibraryPath, aFootprintName, aProperties, true );
2073  return footprint ? (MODULE*) footprint->Duplicate() : nullptr;
2074 }
2075 
2076 
2077 void PCB_IO::FootprintSave( const wxString& aLibraryPath, const MODULE* aFootprint,
2078  const PROPERTIES* aProperties )
2079 {
2080  LOCALE_IO toggle; // toggles on, then off, the C locale.
2081 
2082  init( aProperties );
2083 
2084  // In this public PLUGIN API function, we can safely assume it was
2085  // called for saving into a library path.
2087 
2088  validateCache( aLibraryPath );
2089 
2090  if( !m_cache->IsWritable() )
2091  {
2092  if( !m_cache->Exists() )
2093  {
2094  const wxString msg = wxString::Format( _( "Library \"%s\" does not exist.\n"
2095  "Would you like to create it?"),
2096  GetChars( aLibraryPath ) );
2097 
2098  if( wxMessageBox( msg, _( "Library Not Found"), wxYES_NO | wxICON_QUESTION ) != wxYES )
2099  return;
2100 
2101  // Save throws its own IO_ERROR on failure, so no need to recreate here
2102  m_cache->Save( NULL );
2103  }
2104  else
2105  {
2106  wxString msg = wxString::Format( _( "Library \"%s\" is read only" ), aLibraryPath );
2107  THROW_IO_ERROR( msg );
2108  }
2109  }
2110 
2111  wxString footprintName = aFootprint->GetFPID().GetLibItemName();
2112 
2113  MODULE_MAP& mods = m_cache->GetModules();
2114 
2115  // Quietly overwrite module and delete module file from path for any by same name.
2116  wxFileName fn( aLibraryPath, aFootprint->GetFPID().GetLibItemName(),
2118 
2119 #ifndef __WINDOWS__
2120  // Write through symlinks, don't replace them
2121  if( fn.Exists( wxFILE_EXISTS_SYMLINK ) )
2122  {
2123  char buffer[ PATH_MAX + 1 ];
2124  ssize_t pathLen = readlink( TO_UTF8( fn.GetFullPath() ), buffer, PATH_MAX );
2125 
2126  if( pathLen > 0 )
2127  {
2128  buffer[ pathLen ] = '\0';
2129  fn.Assign( fn.GetPath() + wxT( "/" ) + wxString::FromUTF8( buffer ) );
2130  fn.Normalize();
2131  }
2132  }
2133 #endif
2134 
2135  if( !fn.IsOk() )
2136  {
2137  THROW_IO_ERROR( wxString::Format( _( "Footprint file name \"%s\" is not valid." ),
2138  fn.GetFullPath() ) );
2139  }
2140 
2141  if( fn.FileExists() && !fn.IsFileWritable() )
2142  {
2143  THROW_IO_ERROR( wxString::Format( _( "No write permissions to delete file \"%s\"" ),
2144  fn.GetFullPath() ) );
2145  }
2146 
2147  wxString fullPath = fn.GetFullPath();
2148  wxString fullName = fn.GetFullName();
2149  MODULE_CITER it = mods.find( footprintName );
2150 
2151  if( it != mods.end() )
2152  {
2153  wxLogTrace( traceKicadPcbPlugin, wxT( "Removing footprint file '%s'." ), fullPath );
2154  mods.erase( footprintName );
2155  wxRemoveFile( fullPath );
2156  }
2157 
2158  // I need my own copy for the cache
2159  MODULE* module = static_cast<MODULE*>( aFootprint->Duplicate() );
2160 
2161  // It should have no parent, orientation should be zero, and it should be on the front layer.
2162  module->SetParent( nullptr );
2163  module->SetOrientation( 0 );
2164 
2165  if( module->GetLayer() != F_Cu )
2166  {
2167  auto cfg = dynamic_cast<PCBNEW_SETTINGS*>( Kiface().KifaceSettings() );
2168 
2169  if( cfg )
2170  module->Flip( module->GetPosition(), cfg->m_FlipLeftRight );
2171  else
2172  module->Flip( module->GetPosition(), false );
2173  }
2174 
2175  wxLogTrace( traceKicadPcbPlugin, wxT( "Creating s-expr footprint file '%s'." ), fullPath );
2176  mods.insert( footprintName, new FP_CACHE_ITEM( module, WX_FILENAME( fn.GetPath(), fullName ) ) );
2177  m_cache->Save( module );
2178 }
2179 
2180 
2181 void PCB_IO::FootprintDelete( const wxString& aLibraryPath, const wxString& aFootprintName,
2182  const PROPERTIES* aProperties )
2183 {
2184  LOCALE_IO toggle; // toggles on, then off, the C locale.
2185 
2186  init( aProperties );
2187 
2188  validateCache( aLibraryPath );
2189 
2190  if( !m_cache->IsWritable() )
2191  {
2192  THROW_IO_ERROR( wxString::Format( _( "Library \"%s\" is read only." ),
2193  aLibraryPath.GetData() ) );
2194  }
2195 
2196  m_cache->Remove( aFootprintName );
2197 }
2198 
2199 
2200 
2201 long long PCB_IO::GetLibraryTimestamp( const wxString& aLibraryPath ) const
2202 {
2203  return FP_CACHE::GetTimestamp( aLibraryPath );
2204 }
2205 
2206 
2207 void PCB_IO::FootprintLibCreate( const wxString& aLibraryPath, const PROPERTIES* aProperties )
2208 {
2209  if( wxDir::Exists( aLibraryPath ) )
2210  {
2211  THROW_IO_ERROR( wxString::Format( _( "Cannot overwrite library path \"%s\"." ),
2212  aLibraryPath.GetData() ) );
2213  }
2214 
2215  LOCALE_IO toggle;
2216 
2217  init( aProperties );
2218 
2219  delete m_cache;
2220  m_cache = new FP_CACHE( this, aLibraryPath );
2221  m_cache->Save();
2222 }
2223 
2224 
2225 bool PCB_IO::FootprintLibDelete( const wxString& aLibraryPath, const PROPERTIES* aProperties )
2226 {
2227  wxFileName fn;
2228  fn.SetPath( aLibraryPath );
2229 
2230  // Return if there is no library path to delete.
2231  if( !fn.DirExists() )
2232  return false;
2233 
2234  if( !fn.IsDirWritable() )
2235  {
2236  THROW_IO_ERROR( wxString::Format( _( "User does not have permission to delete directory \"%s\"." ),
2237  aLibraryPath.GetData() ) );
2238  }
2239 
2240  wxDir dir( aLibraryPath );
2241 
2242  if( dir.HasSubDirs() )
2243  {
2244  THROW_IO_ERROR( wxString::Format( _( "Library directory \"%s\" has unexpected sub-directories." ),
2245  aLibraryPath.GetData() ) );
2246  }
2247 
2248  // All the footprint files must be deleted before the directory can be deleted.
2249  if( dir.HasFiles() )
2250  {
2251  unsigned i;
2252  wxFileName tmp;
2253  wxArrayString files;
2254 
2255  wxDir::GetAllFiles( aLibraryPath, &files );
2256 
2257  for( i = 0; i < files.GetCount(); i++ )
2258  {
2259  tmp = files[i];
2260 
2261  if( tmp.GetExt() != KiCadFootprintFileExtension )
2262  {
2263  THROW_IO_ERROR( wxString::Format( _( "Unexpected file \"%s\" was found in library path \"%s\"." ),
2264  files[i].GetData(), aLibraryPath.GetData() ) );
2265  }
2266  }
2267 
2268  for( i = 0; i < files.GetCount(); i++ )
2269  wxRemoveFile( files[i] );
2270  }
2271 
2272  wxLogTrace( traceKicadPcbPlugin, wxT( "Removing footprint library \"%s\"." ),
2273  aLibraryPath.GetData() );
2274 
2275  // Some of the more elaborate wxRemoveFile() crap puts up its own wxLog dialog
2276  // we don't want that. we want bare metal portability with no UI here.
2277  if( !wxRmdir( aLibraryPath ) )
2278  {
2279  THROW_IO_ERROR( wxString::Format( _( "Footprint library \"%s\" cannot be deleted." ),
2280  aLibraryPath.GetData() ) );
2281  }
2282 
2283  // For some reason removing a directory in Windows is not immediately updated. This delay
2284  // prevents an error when attempting to immediately recreate the same directory when over
2285  // writing an existing library.
2286 #ifdef __WINDOWS__
2287  wxMilliSleep( 250L );
2288 #endif
2289 
2290  if( m_cache && !m_cache->IsPath( aLibraryPath ) )
2291  {
2292  delete m_cache;
2293  m_cache = NULL;
2294  }
2295 
2296  return true;
2297 }
2298 
2299 
2300 bool PCB_IO::IsFootprintLibWritable( const wxString& aLibraryPath )
2301 {
2302  LOCALE_IO toggle;
2303 
2304  init( NULL );
2305 
2306  validateCache( aLibraryPath );
2307 
2308  return m_cache->IsWritable();
2309 }
void FormatBoardStackup(OUTPUTFORMATTER *aFormatter, BOARD *aBoard, int aNestLevel) const
Writes the stackup info on board file.
timestamp_t GetLastEditTime() const
Definition: class_module.h:345
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:712
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.
bool GetDoNotAllowPads() const
Definition: class_zone.h:706
int GetAttributes() const
Definition: class_module.h:255
ZONE_CONTAINER handles a list of polygons defining a copper zone.
Definition: class_zone.h:61
int GetLocalSolderMaskMargin() const
Definition: class_pad.h:344
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:211
bool IsFilled() const
Definition: class_zone.h:185
STATUS_FLAGS GetStatus() const
Definition: base_struct.h:229
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:155
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:552
const UTF8 & GetLibItemName() const
Definition: lib_id.h:114
const PAGE_INFO & GetPageSettings() const
Definition: class_board.h:572
bool IsModified()
Function IsModified Return true if the cache is not up-to-date.
TEXTE_MODULE & Reference()
Definition: class_module.h:474
std::unique_ptr< MODULE > m_module
int GetNetCode() const
Function GetNetCode.
const PCB_PLOT_PARAMS & GetPlotOptions() const
Definition: class_board.h:575
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:214
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
wxPoint m_GridOrigin
origin for grid offsets
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Function GetLayerName returns the name of a layer.
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:354
no special fabrication property
Definition: pad_shapes.h:97
like PAD_STANDARD, but not plated mechanical use only, no connection allowed
Definition: pad_shapes.h:85
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: common.h:216
wxFileName m_lib_path
this class manage the layers needed to make a physical board they are solder mask,...
Implementation of conversion functions that require both schematic and board internal units.
wxPoint m_crossBarF
BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class,...
const std::string KiCadFootprintFileExtension
wxPoint m_arrowD1F
PAD_SHAPE_T GetAnchorPadShape() const
Function GetAnchorPadShape.
Definition: class_pad.h:167
FP_CACHE * m_cache
Footprint library cache.
const wxPoint & GetStart() const
Definition: class_track.h:118
STROKE_T GetShape() const
PCB_PARSER reads a Pcbnew s-expression formatted LINE_READER object and returns the appropriate BOARD...
Definition: pcb_parser.h:69
int GetLocalClearance(wxString *aSource=nullptr) const override
Function GetLocalClearance returns any local clearances set in the "classic" (ie: pre-rule) system.
Definition: class_pad.cpp:520
int GetSize() const
int GetHatchFillTypeThickness() const
Definition: class_zone.h:210
const PROPERTIES * m_props
passed via Save() or Load(), no ownership, may be NULL.
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:185
bool IsPlaced() const
Definition: class_module.h:315
void init(const PROPERTIES *aProperties)
a fiducial (usually a smd) for the full board
Definition: pad_shapes.h:99
polygon (not yet used for tracks, but could be in microwave apps)
ZONE_CONNECTION GetZoneConnection() const
Definition: class_module.h:247
bool IsEmpty() const
Returns true if the set is empty (no polygons at all)
int GetLocalClearance(wxString *aSource=nullptr) const
Definition: class_module.h:230
int GetPadToDieLength() const
Definition: class_pad.h:342
Smd pad, appears on the solder paste layer (default)
Definition: pad_shapes.h:81
class ZONE_CONTAINER, a zone area
Definition: typeinfo.h:102
const WX_FILENAME & GetFileName() const
wxString m_lib_raw_path
PADS & Pads()
Definition: class_module.h:169
Set for modules listed in the automatic insertion list (usually SMD footprints)
Definition: class_module.h:68
#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:173
bool GetFilledPolysUseThickness() const
Definition: class_zone.h:661
class TEXTE_PCB, text on a layer
Definition: typeinfo.h:92
double GetHatchFillTypeOrientation() const
Definition: class_zone.h:216
wxString GetName() const
Definition: common.cpp:773
const SHAPE_POLY_SET & GetFilledPolysList(PCB_LAYER_ID aLayer) const
Function GetFilledPolysList returns a reference to the list of filled polygons.
Definition: class_zone.h:602
class ARC, an arc track segment on a copper layer
Definition: typeinfo.h:98
void formatNetInformation(BOARD *aBoard, int aNestLevel=0) const
formats the Nets and Netclasses
Smd pad, used in BGA footprints.
Definition: pad_shapes.h:98
wxString AsString() const
Definition: common.cpp:165
double GetHatchFillTypeSmoothingValue() const
Definition: class_zone.h:222
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Function GetDesignSettings.
Definition: class_board.h:551
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
std::string Double2Str(double aValue)
Helper function Double2Str to print a float number without using scientific notation and no trailing ...
Definition: base_units.cpp:62
const LIB_ID & GetFPID() const
Definition: class_module.h:215
LSET GetEnabledLayers() const
Function GetEnabledLayers is a proxy function that calls the corresponding function in m_BoardSetting...
wxPoint m_featureLineDF
const KIID_PATH & GetPath() const
Definition: class_module.h:224
DRAWINGS & GraphicalItems()
Definition: class_module.h:179
a pad used as heat sink, usually in SMD footprints
Definition: pad_shapes.h:102
int GetThermalReliefGap(D_PAD *aPad=NULL) const
Definition: class_zone.cpp:345
const wxString & GetPinFunction() const
Definition: class_pad.h:134
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:767
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).
const wxPoint & GetEnd() const
Function GetEnd returns the ending point of the graphic.
int GetThermalGap() const
Definition: class_pad.cpp:650
int GetLocalSolderMaskMargin() const
Definition: class_module.h:227
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:377
class EDGE_MODULE, a footprint edge
Definition: typeinfo.h:94
std::map< wxString, MODULE * > MODULE_MAP
Definition: eagle_parser.h:51
iterator begin()
Definition: netclass.h:132
PAD_ATTR_T GetAttribute() const
Definition: class_pad.h:332
virtual void SetParent(EDA_ITEM *aParent)
Definition: base_struct.h:196
A single base class (TRACK) represents both tracks and vias, with subclasses for curved tracks (ARC) ...
class TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:96
This file contains miscellaneous commonly used macros and functions.
int GetChamferPositions() const
Definition: class_pad.h:488
a pad with a castellated through hole
Definition: pad_shapes.h:103
bool GetDoNotAllowVias() const
Definition: class_zone.h:704
static const char * ShowType(LAYER_T aType)
Function ShowType converts a LAYER_T enum to a const char*.
long long int GetMinIslandArea() const
Definition: class_zone.h:729
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:281
long long m_cache_timestamp
wxPoint m_featureLineGO
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:312
bool IsKeepUpright()
wxString GetZoneName() const
Definition: class_zone.h:109
DIMENSION class definition.
const VECTOR2I & CPoint(int aIndex) const
Function Point()
MODULE_MAP m_modules
segment with non rounded ends
class MODULE, a footprint
Definition: typeinfo.h:89
long long GetTimestamp()
Definition: common.cpp:807
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:589
BOARD_STACKUP & GetStackupDescriptor()
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:
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:208
int GetAreaCount() const
Function GetAreaCount.
Definition: class_board.h:919
void FootprintLibCreate(const wxString &aLibraryPath, const PROPERTIES *aProperties=NULL) override
Function FootprintLibCreate creates a new empty footprint library at aLibraryPath empty.
LSET is a set of PCB_LAYER_IDs.
pads are covered by copper
const wxPoint & GetMid() const
Definition: class_track.h:288
void SetBoard(BOARD *aBoard)
Definition: pcb_parser.h:342
unsigned int GetCornerRadius() const
Definition: class_zone.h:659
int GetSize() const
Function GetSize.
Definition: netinfo.h:375
#define NULL
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.
MODULES & Modules()
Definition: class_board.h:266
iterator end()
Definition: netclass.h:133
wxString GetBuildVersion()
Get the full KiCad version string.
bool IsPath(const wxString &aPath) const
Function IsPath checks if aPath is the same as the current cache path.
SHAPE_POLY_SET.
TEXTE_MODULE & Value()
read/write accessors:
Definition: class_module.h:473
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:148
int GetValue() const
int GetDrill() const
Function GetDrill returns the local drill setting for this VIA.
Definition: class_track.h:449
Arcs (with rounded ends)
void Flip(const wxPoint &aCentre, bool aFlipLeftRight) override
Function Flip Flip this object, i.e.
KIFACE_I & Kiface()
Global KIFACE_I "get" accessor.
const wxPoint & GetOffset() const
Definition: class_pad.h:229
int m_loading_format_version
which SEXPR_BOARD_FILE_VERSION should be Load()ed?
PAD_DRILL_SHAPE_T GetDrillShape() const
Definition: class_pad.h:318
double GetChamferRectRatio() const
Definition: class_pad.h:479
int GetThermalWidth() const
Definition: class_pad.cpp:639
NETCLASS handles a collection of nets and the parameters used to route or test these nets.
Definition: netclass.h:55
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:329
wxPoint m_arrowG1F
bool GetDoNotAllowCopperPour() const
Definition: class_zone.h:703
const ISLAND_REMOVAL_MODE GetIslandRemovalMode() const
Definition: class_zone.h:725
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Function GetConnectivity() returns list of missing connections between components/tracks.
Definition: class_board.h:355
wxPoint m_arrowD2F
wxPoint m_arrowG2F
Definition of file extensions used in Kicad.
wxString GetSelectMenuText(EDA_UNITS aUnits) const override
Function GetSelectMenuText returns the text to display to be used in the selection clarification cont...
Definition: class_track.cpp:72
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:477
const wxString & GetName() const
Definition: class_pad.h:128
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:966
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: ws_painter.cpp:217
#define THROW_IO_ERROR(msg)
std::string Quotew(const wxString &aWrapee)
Definition: richio.cpp:472
const wxPoint & GetBezier0_C2() const
SHAPE_POLY_SET & GetPolyShape()
void formatSetup(BOARD *aBoard, int aNestLevel=0) const
formats the board setup information
PAD_PROP_T GetProperty() const
Definition: class_pad.h:335
WX_FILENAME m_filename
void SetFileName(const wxString &aFileName)
Definition: class_board.h:253
Bezier Curve.
#define UNDEFINED_DRILL_DIAMETER
Definition: class_track.h:77
PCB_PARSER * m_parser
ZONE_CONNECTION GetPadConnection(D_PAD *aPad=NULL) const
Definition: class_zone.cpp:839
#define THROW_PARSE_ERROR(aProblem, aSource, aInputLine, aLineNumber, aByteIndex)
const wxSize & GetDelta() const
Definition: class_pad.h:223
const wxString & GetNetname() const
Function GetNetname.
#define CTL_OMIT_NETS
Omit pads net names (useless in library)
BOARD_ITEM * Parse()
Definition: pcb_parser.cpp:481
#define CTL_OMIT_PATH
Omit component sheet time stamp (useless in library)
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:655
Like smd, does not appear on the solder paste layer (default) note also has a special attribute in Ge...
Definition: pad_shapes.h:82
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:297
const wxString & GetKeywords() const
Definition: class_module.h:221
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
ZONE_HATCH_STYLE GetHatchStyle() const
Definition: class_zone.h:565
int GetCornerSmoothingType() const
Definition: class_zone.h:655
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
const MODULE_ZONE_CONTAINERS & Zones() const
Definition: class_module.h:184
UTF8 Format() const
Definition: lib_id.cpp:237
int GetLocalSolderPasteMargin() const
Definition: class_module.h:240
int GetWidth() const
bool GetIsKeepout() const
Accessors to parameters used in Keepout zones:
Definition: class_zone.h:702
LINE_READER * SetLineReader(LINE_READER *aReader)
Function SetLineReader sets aLineReader into the parser, and returns the previous one,...
Definition: pcb_parser.h:335
Thermal relief only for THT pads.
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:67
constexpr std::size_t arrayDim(T const (&)[N]) noexcept
Definition: macros.h:160
ZONE_CONNECTION GetEffectiveZoneConnection() const
Return the zone connection in effect (either locally overridden or overridden in the parent module).
Definition: class_pad.cpp:628
wxString GetPath() const
Definition: common.cpp:786
const KIID m_Uuid
Definition: base_struct.h:162
const wxPoint & GetPos0() const
CUST_PAD_SHAPE_IN_ZONE GetCustomShapeInZoneOpt() const
Definition: class_pad.h:173
class TEXTE_MODULE, text in a footprint
Definition: typeinfo.h:93
int GetPlacementCost180() const
Definition: class_module.h:549
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()
Use thermal relief for pads.
void formatBoardLayers(BOARD *aBoard, int aNestLevel=0) const
formats the board layer information
static wxString STROKE_T_asString(STROKE_T a)
wxString GetFullPath() const
Definition: common.cpp:792
const wxString & GetDescription() const
Definition: class_module.h:218
double GetAngle() const
NETINFO_ITEM handles the data for a net.
Definition: netinfo.h:65
bool IsWritable() const
bool IsTooRecent()
Return whether a version number, if any was parsed, was too recent.
Definition: pcb_parser.h:360
double GetLocalSolderPasteMarginRatio() const
Definition: class_module.h:243
MODULE_MAP::const_iterator MODULE_CITER
std::list< MODULE_3D_SETTINGS > & Models()
Definition: class_module.h:201
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:101
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:153
a fiducial (usually a smd) local to the parent footprint
Definition: pad_shapes.h:100
virtual wxString GetClass() const =0
Function GetClass returns the class name.
TITLE_BLOCK & GetTitleBlock()
Definition: class_board.h:578
A wrapper around a wxFileName which is much more performant with a subset of the API.
Definition: common.h:414
int GetWidth() const
Definition: class_track.h:112
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
int GetNet() const
Function GetNet.
Definition: netinfo.h:223
BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:180
#define _(s)
Definition: 3d_actions.cpp:33
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:497
double GetOrientation() const
Function GetOrientation returns the rotation angle of the pad in tenths of degrees,...
Definition: class_pad.h:313
Virtual component: when created by copper shapes on board (Like edge card connectors,...
Definition: class_module.h:70
#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:248
TEXTE_PCB & Text()
wxString AsString() const
Definition: common.h:137
#define CTL_STD_LAYER_NAMES
Use English Standard layer names.
const wxSize & GetDrillSize() const
Definition: class_pad.h:226
void FootprintEnumerate(wxArrayString &aFootprintNames, const wxString &aLibraryPath, bool aBestEfforts, const PROPERTIES *aProperties=NULL) override
Return a list of footprint names contained within the library at aLibraryPath.
BOARD * m_board
which BOARD, no ownership here
bool FootprintExists(const wxString &aLibraryPath, const wxString &aFootprintName, const PROPERTIES *aProperties=NULL) override
Function FootprintExists check for the existence of a footprint.
int GetShape() const
VIATYPE GetViaType() const
Definition: class_track.h:368
void format(BOARD *aBoard, int aNestLevel=0) const
int GetHatchPitch() const
Hatch related methods.
Definition: class_zone.cpp:945
const wxPoint & GetBezControl2() const
#define TO_UTF8(wxstring)
The common library.
int GetMinThickness() const
Definition: class_zone.h:201
Pads are not covered.
bool IsPolyShapeValid() const
const wxPoint & GetEnd() const
Definition: class_track.h:115
FILE_OUTPUTFORMATTER may be used for text file output.
Definition: richio.h:492
bool GetDoNotAllowTracks() const
Definition: class_zone.h:705
FP_CACHE_ITEM(MODULE *aModule, const WX_FILENAME &aFileName)
double GetRoundRectRadiusRatio() const
Definition: class_pad.h:470
bool GetDoNotAllowFootprints() const
Definition: class_zone.h:707
const wxPoint & GetTextPos() const
Definition: eda_text.h:247
const wxPoint & GetBezier0_C1() const
wxPoint m_crossBarO
const wxPoint & GetEnd0() const
int GetHatchFillTypeSmoothingLevel() const
Definition: class_zone.h:219
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers of advanced config.
PCB_TARGET class definition.
ZONE_SEGMENT_FILL & FillSegments(PCB_LAYER_ID aLayer)
Definition: class_zone.h:259
class VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:97
const wxPoint & GetBezControl1() const
const wxPoint & GetStart() const
Function GetStart returns the starting point of the graphic.
Pcbnew s-expression file format parser definition.
void filterNetClass(const BOARD &aBoard, NETCLASS &aNetClass)
Removes empty nets (i.e. with node count equal zero) from net classes
Struct FUTURE_FORMAT_ERROR variant of PARSE_ERROR indicating that a syntax or related error was likel...
Definition: ki_exception.h:172
PAD_SHAPE_T GetShape() const
Definition: class_pad.h:153
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
ZONE_CONTAINER * GetArea(int index) const
Function GetArea returns the Area (Zone Container) at a given index.
Definition: class_board.h:884
bool m_cache_dirty
void formatLayers(LSET aLayerMask, int aNestLevel=0) const
int GetZoneClearance() const
Definition: class_zone.h:191
class ZONE_CONTAINER, managed by a footprint
Definition: typeinfo.h:95
bool m_HasStackup
Set to true if the board has a stackup management.
const std::vector< std::shared_ptr< DRAWSEGMENT > > & GetPrimitives() const
Accessor to the basic shape list.
Definition: class_pad.h:268
int PRINTF_FUNC Print(int nestLevel, const char *fmt,...)
Function Print formats and writes text to the output stream.
Definition: richio.cpp:404
#define CTL_OMIT_INITIAL_COMMENTS
omit MODULE initial comments
MODULE_MAP::iterator MODULE_ITER
const wxSize & GetSize() const
Definition: class_pad.h:220
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:250
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:237
int GetLocalSolderPasteMargin() const
Definition: class_pad.h:350
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
STRING_LINE_READER is a LINE_READER that reads from a multiline 8 bit wide std::string.
Definition: richio.h:254
#define CTL_OMIT_HIDE
Definition: eda_text.h:42
wxString GetLayerName() const
Function GetLayerName returns the name of the PCB layer on which the item resides.
a test point pad
Definition: pad_shapes.h:101
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:461
Struct IO_ERROR is a class used to hold an error message and may be used when throwing exceptions con...
Definition: ki_exception.h:76
int GetHatchFillTypeGap() const
Definition: class_zone.h:213
const wxPoint GetPosition() const override
Definition: class_module.h:206
int GetThermalGap() const
Definition: class_module.h:253
DRAWINGS & Drawings()
Definition: class_board.h:275
void SetFPID(const LIB_ID &aFPID)
Definition: class_module.h:216
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:126
wxPoint m_AuxOrigin
origin for plot exports
bool IsIsland(PCB_LAYER_ID aLayer, int aPolyIdx)
Checks if a given filled polygon is an insulated island.
wxString GetPath() const
DIMENSION.
TRACKS & Tracks()
Definition: class_board.h:257
std::string FormatInternalUnits(int aValue)
Function FormatInternalUnits converts aValue from internal units to a string appropriate for writing ...
Definition: base_units.cpp:560
double GetLocalSolderPasteMarginRatio() const
Definition: class_pad.h:353
MODULE_MAP & GetModules()
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.
BOARD_ITEM * Duplicate() const
Function Duplicate creates a copy of a BOARD_ITEM.
KICAD_T Type() const
Function Type()
Definition: base_struct.h:193
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:648
BOARD_DESIGN_SETTINGS contains design settings for a BOARD object.
wxPoint m_featureLineGF