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