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