KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcb_io_kicad_sexpr.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 The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25#include <wx/dir.h>
26#include <wx/ffile.h>
27#include <wx/log.h>
28#include <wx/msgdlg.h>
29#include <wx/mstream.h>
30
31#include <board.h>
33#include <callback_gal.h>
34#include <confirm.h>
35#include <convert_basic_shapes_to_polygon.h> // for enum RECT_CHAMFER_POSITIONS definition
36#include <fmt/core.h>
37#include <font/fontconfig.h>
38#include <footprint.h>
40#include <kiface_base.h>
41#include <layer_range.h>
42#include <locale_io.h>
43#include <macros.h>
44#include <pad.h>
45#include <pcb_dimension.h>
46#include <pcb_generator.h>
47#include <pcb_group.h>
50#include <pcb_reference_image.h>
51#include <pcb_shape.h>
52#include <pcb_table.h>
53#include <pcb_tablecell.h>
54#include <pcb_target.h>
55#include <pcb_text.h>
56#include <pcb_textbox.h>
57#include <pcb_track.h>
58#include <pcbnew_settings.h>
59#include <pgm_base.h>
60#include <progress_reporter.h>
61#include <reporter.h>
62#include <string_utils.h>
63#include <trace_helpers.h>
65#include <zone.h>
66
67#include <build_version.h>
68#include <filter_reader.h>
69#include <ctl_flags.h>
70
71
72using namespace PCB_KEYS_T;
73
74
75FP_CACHE_ENTRY::FP_CACHE_ENTRY( FOOTPRINT* aFootprint, const WX_FILENAME& aFileName ) :
76 m_filename( aFileName ),
77 m_footprint( aFootprint )
78{ }
79
80
81FP_CACHE::FP_CACHE( PCB_IO_KICAD_SEXPR* aOwner, const wxString& aLibraryPath )
82{
83 m_owner = aOwner;
84 m_lib_raw_path = aLibraryPath;
85 m_lib_path.SetPath( aLibraryPath );
87 m_cache_dirty = true;
88}
89
90
91void FP_CACHE::Save( FOOTPRINT* aFootprintFilter )
92{
94
95 if( !m_lib_path.DirExists() && !m_lib_path.Mkdir() )
96 {
97 THROW_IO_ERROR( wxString::Format( _( "Cannot create footprint library '%s'." ),
99 }
100
101 if( !m_lib_path.IsDirWritable() )
102 {
103 THROW_IO_ERROR( wxString::Format( _( "Footprint library '%s' is read only." ),
104 m_lib_raw_path ) );
105 }
106
107 for( auto it = m_footprints.begin(); it != m_footprints.end(); ++it )
108 {
109 FP_CACHE_ENTRY* fpCacheEntry = it->second;
110 std::unique_ptr<FOOTPRINT>& footprint = fpCacheEntry->GetFootprint();
111
112 if( aFootprintFilter && footprint.get() != aFootprintFilter )
113 continue;
114
115 // If we've requested to embed the fonts in the footprint, do so. Otherwise, clear the
116 // embedded fonts from the footprint. Embedded fonts will be used if available.
117 if( footprint->GetAreFontsEmbedded() )
118 footprint->EmbedFonts();
119 else
120 footprint->GetEmbeddedFiles()->ClearEmbeddedFonts();
121
122 WX_FILENAME fn = fpCacheEntry->GetFileName();
123 wxString fileName = fn.GetFullPath();
124
125 // Allow file output stream to go out of scope to close the file stream before
126 // renaming the file.
127 {
128#ifdef USE_TMP_FILE
129 fileName = wxFileName::CreateTempFileName( fn.GetPath() );
130
131 wxLogTrace( traceKicadPcbPlugin, wxT( "Creating temporary library file '%s'." ),
132 fileName );
133#else
134 wxLogTrace( traceKicadPcbPlugin, wxT( "Writing library file '%s'." ),
135 fileName );
136#endif
137
138 PRETTIFIED_FILE_OUTPUTFORMATTER formatter( fileName );
139
140 m_owner->SetOutputFormatter( &formatter );
141 m_owner->Format( footprint.get() );
142 }
143
144#ifdef USE_TMP_FILE
145 wxRemove( fn.GetFullPath() ); // it is not an error if this does not exist
146
147 // Even on Linux you can see an _intermittent_ error when calling wxRename(),
148 // and it is fully inexplicable. See if this dodges the error.
149 wxMilliSleep( 250L );
150
151 // Preserve the permissions of the current file
153
154 if( !wxRenameFile( fileName, fn.GetFullPath() ) )
155 {
156 wxString msg = wxString::Format( _( "Cannot rename temporary file '%s' to '%s'" ),
157 fileName,
158 fn.GetFullPath() );
159 THROW_IO_ERROR( msg );
160 }
161#endif
163 }
164
165 m_cache_timestamp += m_lib_path.GetModificationTime().GetValue().GetValue();
166
167 // If we've saved the full cache, we clear the dirty flag.
168 if( !aFootprintFilter )
169 m_cache_dirty = false;
170}
171
172
174{
175 m_cache_dirty = false;
177
178 wxDir dir( m_lib_raw_path );
179
180 if( !dir.IsOpened() )
181 {
182 wxString msg = wxString::Format( _( "Footprint library '%s' not found." ),
184 THROW_IO_ERROR( msg );
185 }
186
187 wxString fullName;
188 wxString fileSpec = wxT( "*." ) + wxString( FILEEXT::KiCadFootprintFileExtension );
189
190 // wxFileName construction is egregiously slow. Construct it once and just swap out
191 // the filename thereafter.
192 WX_FILENAME fn( m_lib_raw_path, wxT( "dummyName" ) );
193
194 if( dir.GetFirst( &fullName, fileSpec ) )
195 {
196 wxString cacheError;
197
198 do
199 {
200 fn.SetFullName( fullName );
201
202 // Queue I/O errors so only files that fail to parse don't get loaded.
203 try
204 {
205 FILE_LINE_READER reader( fn.GetFullPath() );
206 PCB_IO_KICAD_SEXPR_PARSER parser( &reader, nullptr, nullptr );
207
208 FOOTPRINT* footprint = dynamic_cast<FOOTPRINT*>( parser.Parse() );
209 wxString fpName = fn.GetName();
210
211 if( !footprint )
212 THROW_IO_ERROR( wxEmptyString ); // caught locally, just below...
213
214 footprint->SetFPID( LIB_ID( wxEmptyString, fpName ) );
215 m_footprints.insert( fpName, new FP_CACHE_ENTRY( footprint, fn ) );
216 }
217 catch( const IO_ERROR& ioe )
218 {
219 if( !cacheError.IsEmpty() )
220 cacheError += wxT( "\n\n" );
221
222 cacheError += wxString::Format( _( "Unable to read file '%s'" ) + '\n',
223 fn.GetFullPath() );
224 cacheError += ioe.What();
225 }
226 } while( dir.GetNext( &fullName ) );
227
229
230 if( !cacheError.IsEmpty() )
231 THROW_IO_ERROR( cacheError );
232 }
233}
234
235
236void FP_CACHE::Remove( const wxString& aFootprintName )
237{
238 auto it = m_footprints.find( aFootprintName );
239
240 if( it == m_footprints.end() )
241 {
242 wxString msg = wxString::Format( _( "Library '%s' has no footprint '%s'." ),
244 aFootprintName );
245 THROW_IO_ERROR( msg );
246 }
247
248 // Remove the footprint from the cache and delete the footprint file from the library.
249 wxString fullPath = it->second->GetFileName().GetFullPath();
250 m_footprints.erase( aFootprintName );
251 wxRemoveFile( fullPath );
252}
253
254
255bool FP_CACHE::IsPath( const wxString& aPath ) const
256{
257 return aPath == m_lib_raw_path;
258}
259
260
261void FP_CACHE::SetPath( const wxString& aPath )
262{
263 m_lib_raw_path = aPath;
264 m_lib_path.SetPath( aPath );
265
266
267 for( const auto& footprint : GetFootprints() )
268 footprint.second->SetFilePath( aPath );
269}
270
271
273{
275
276 return m_cache_dirty;
277}
278
279
280long long FP_CACHE::GetTimestamp( const wxString& aLibPath )
281{
282 wxString fileSpec = wxT( "*." ) + wxString( FILEEXT::KiCadFootprintFileExtension );
283
284 return TimestampDir( aLibPath, fileSpec );
285}
286
287
288bool PCB_IO_KICAD_SEXPR::CanReadBoard( const wxString& aFileName ) const
289{
290 if( !PCB_IO::CanReadBoard( aFileName ) )
291 return false;
292
293 try
294 {
295 FILE_LINE_READER reader( aFileName );
296 PCB_IO_KICAD_SEXPR_PARSER parser( &reader, nullptr, m_queryUserCallback );
297
298 return parser.IsValidBoardHeader();
299 }
300 catch( const IO_ERROR& )
301 {
302 }
303
304 return false;
305}
306
307
308void PCB_IO_KICAD_SEXPR::SaveBoard( const wxString& aFileName, BOARD* aBoard,
309 const std::map<std::string, UTF8>* aProperties )
310{
311 LOCALE_IO toggle; // toggles on, then off, the C locale.
312
313 wxString sanityResult = aBoard->GroupsSanityCheck();
314
315 if( sanityResult != wxEmptyString && m_queryUserCallback )
316 {
318 _( "Internal Group Data Error" ), wxICON_ERROR,
319 wxString::Format( _( "Please report this bug. Error validating group "
320 "structure: %s\n\nSave anyway?" ), sanityResult ),
321 _( "Save Anyway" ) ) )
322 {
323 return;
324 }
325 }
326
327 init( aProperties );
328
329 m_board = aBoard; // after init()
330
331 // If the user wants fonts embedded, make sure that they are added to the board. Otherwise,
332 // remove any fonts that were previously embedded.
335 else
337
338 // Prepare net mapping that assures that net codes saved in a file are consecutive integers
339 m_mapping->SetBoard( aBoard );
340
341 PRETTIFIED_FILE_OUTPUTFORMATTER formatter( aFileName );
342
343 m_out = &formatter; // no ownership
344
345 m_out->Print( "(kicad_pcb (version %d) (generator \"pcbnew\") (generator_version %s)",
347 m_out->Quotew( GetMajorMinorVersion() ).c_str() );
348
349 Format( aBoard );
350
351 m_out->Print( ")" );
352 m_out->Finish();
353
354 m_out = nullptr;
355}
356
357
358BOARD_ITEM* PCB_IO_KICAD_SEXPR::Parse( const wxString& aClipboardSourceInput )
359{
360 std::string input = TO_UTF8( aClipboardSourceInput );
361
362 STRING_LINE_READER reader( input, wxT( "clipboard" ) );
363 PCB_IO_KICAD_SEXPR_PARSER parser( &reader, nullptr, m_queryUserCallback );
364
365 try
366 {
367 return parser.Parse();
368 }
369 catch( const PARSE_ERROR& parse_error )
370 {
371 if( parser.IsTooRecent() )
372 throw FUTURE_FORMAT_ERROR( parse_error, parser.GetRequiredVersion() );
373 else
374 throw;
375 }
376}
377
378
379void PCB_IO_KICAD_SEXPR::Format( const BOARD_ITEM* aItem ) const
380{
381 LOCALE_IO toggle; // public API function, perform anything convenient for caller
382
383 switch( aItem->Type() )
384 {
385 case PCB_T:
386 format( static_cast<const BOARD*>( aItem ) );
387 break;
388
390 case PCB_DIM_CENTER_T:
391 case PCB_DIM_RADIAL_T:
393 case PCB_DIM_LEADER_T:
394 format( static_cast<const PCB_DIMENSION_BASE*>( aItem ) );
395 break;
396
397 case PCB_SHAPE_T:
398 format( static_cast<const PCB_SHAPE*>( aItem ) );
399 break;
400
402 format( static_cast<const PCB_REFERENCE_IMAGE*>( aItem ) );
403 break;
404
405 case PCB_TARGET_T:
406 format( static_cast<const PCB_TARGET*>( aItem ) );
407 break;
408
409 case PCB_FOOTPRINT_T:
410 format( static_cast<const FOOTPRINT*>( aItem ) );
411 break;
412
413 case PCB_PAD_T:
414 format( static_cast<const PAD*>( aItem ) );
415 break;
416
417 case PCB_FIELD_T:
418 // Handled in the footprint formatter when properties are formatted
419 break;
420
421 case PCB_TEXT_T:
422 format( static_cast<const PCB_TEXT*>( aItem ) );
423 break;
424
425 case PCB_TEXTBOX_T:
426 format( static_cast<const PCB_TEXTBOX*>( aItem ) );
427 break;
428
429 case PCB_TABLE_T:
430 format( static_cast<const PCB_TABLE*>( aItem ) );
431 break;
432
433 case PCB_GROUP_T:
434 format( static_cast<const PCB_GROUP*>( aItem ) );
435 break;
436
437 case PCB_GENERATOR_T:
438 format( static_cast<const PCB_GENERATOR*>( aItem ) );
439 break;
440
441 case PCB_TRACE_T:
442 case PCB_ARC_T:
443 case PCB_VIA_T:
444 format( static_cast<const PCB_TRACK*>( aItem ) );
445 break;
446
447 case PCB_ZONE_T:
448 format( static_cast<const ZONE*>( aItem ) );
449 break;
450
451 default:
452 wxFAIL_MSG( wxT( "Cannot format item " ) + aItem->GetClass() );
453 }
454}
455
456
457std::string formatInternalUnits( int aValue )
458{
460}
461
462
463std::string formatInternalUnits( const VECTOR2I& aCoord )
464{
466}
467
468
469std::string formatInternalUnits( const VECTOR2I& aCoord, const FOOTPRINT* aParentFP )
470{
471 if( aParentFP )
472 {
473 VECTOR2I coord = aCoord - aParentFP->GetPosition();
474 RotatePoint( coord, -aParentFP->GetOrientation() );
475 return formatInternalUnits( coord );
476 }
477
478 return formatInternalUnits( aCoord );
479}
480
481
482void PCB_IO_KICAD_SEXPR::formatLayer( PCB_LAYER_ID aLayer, bool aIsKnockout ) const
483{
484 m_out->Print( "(layer %s %s)",
485 m_out->Quotew( LSET::Name( aLayer ) ).c_str(),
486 aIsKnockout ? "knockout" : "" );
487}
488
489
491 const FOOTPRINT* aParentFP ) const
492{
493 m_out->Print( "(pts" );
494
495 for( int ii = 0; ii < outline.PointCount(); ++ii )
496 {
497 int ind = outline.ArcIndex( ii );
498
499 if( ind < 0 )
500 {
501 m_out->Print( "(xy %s)",
502 formatInternalUnits( outline.CPoint( ii ), aParentFP ).c_str() );
503 }
504 else
505 {
506 const SHAPE_ARC& arc = outline.Arc( ind );
507 m_out->Print( "(arc (start %s) (mid %s) (end %s))",
508 formatInternalUnits( arc.GetP0(), aParentFP ).c_str(),
509 formatInternalUnits( arc.GetArcMid(), aParentFP ).c_str(),
510 formatInternalUnits( arc.GetP1(), aParentFP ).c_str() );
511
512 do
513 {
514 ++ii;
515 } while( ii < outline.PointCount() && outline.ArcIndex( ii ) == ind );
516
517 --ii;
518 }
519 }
520
521 m_out->Print( ")" );
522}
523
524
526{
527 wxString resolvedText( aText->GetShownText( true ) );
528 std::vector<std::unique_ptr<KIFONT::GLYPH>>* cache = aText->GetRenderCache( aText->GetFont(),
529 resolvedText );
530
531 m_out->Print( "(render_cache %s %s",
532 m_out->Quotew( resolvedText ).c_str(),
533 EDA_UNIT_UTILS::FormatAngle( aText->GetDrawRotation() ).c_str() );
534
536
537 CALLBACK_GAL callback_gal( empty_opts,
538 // Polygon callback
539 [&]( const SHAPE_LINE_CHAIN& aPoly )
540 {
541 m_out->Print( "(polygon" );
542 formatPolyPts( aPoly );
543 m_out->Print( ")" );
544 } );
545
546 callback_gal.SetLineWidth( aText->GetTextThickness() );
547 callback_gal.DrawGlyphs( *cache );
548
549 m_out->Print( ")" );
550}
551
552
553void PCB_IO_KICAD_SEXPR::formatSetup( const BOARD* aBoard ) const
554{
555 // Setup
556 m_out->Print( "(setup" );
557
558 // Save the board physical stackup structure
559 const BOARD_STACKUP& stackup = aBoard->GetDesignSettings().GetStackupDescriptor();
560
561 if( aBoard->GetDesignSettings().m_HasStackup )
562 stackup.FormatBoardStackup( m_out, aBoard );
563
564 BOARD_DESIGN_SETTINGS& dsnSettings = aBoard->GetDesignSettings();
565
566 m_out->Print( "(pad_to_mask_clearance %s)",
567 formatInternalUnits( dsnSettings.m_SolderMaskExpansion ).c_str() );
568
569 if( dsnSettings.m_SolderMaskMinWidth )
570 {
571 m_out->Print( "(solder_mask_min_width %s)",
572 formatInternalUnits( dsnSettings.m_SolderMaskMinWidth ).c_str() );
573 }
574
575 if( dsnSettings.m_SolderPasteMargin != 0 )
576 {
577 m_out->Print( "(pad_to_paste_clearance %s)",
578 formatInternalUnits( dsnSettings.m_SolderPasteMargin ).c_str() );
579 }
580
581 if( dsnSettings.m_SolderPasteMarginRatio != 0 )
582 {
583 m_out->Print( "(pad_to_paste_clearance_ratio %s)",
584 FormatDouble2Str( dsnSettings.m_SolderPasteMarginRatio ).c_str() );
585 }
586
587 KICAD_FORMAT::FormatBool( m_out, "allow_soldermask_bridges_in_footprints",
588 dsnSettings.m_AllowSoldermaskBridgesInFPs );
589
590 if( dsnSettings.m_TentViasFront || dsnSettings.m_TentViasBack )
591 {
592 m_out->Print( "(tenting %s %s)",
593 dsnSettings.m_TentViasFront ? "front" : "",
594 dsnSettings.m_TentViasBack ? "back" : "" );
595 }
596 else
597 {
598 m_out->Print( "(tenting none)" );
599 }
600
601 VECTOR2I origin = dsnSettings.GetAuxOrigin();
602
603 if( origin != VECTOR2I( 0, 0 ) )
604 {
605 m_out->Print( "(aux_axis_origin %s %s)",
606 formatInternalUnits( origin.x ).c_str(),
607 formatInternalUnits( origin.y ).c_str() );
608 }
609
610 origin = dsnSettings.GetGridOrigin();
611
612 if( origin != VECTOR2I( 0, 0 ) )
613 {
614 m_out->Print( "(grid_origin %s %s)",
615 formatInternalUnits( origin.x ).c_str(),
616 formatInternalUnits( origin.y ).c_str() );
617 }
618
619 aBoard->GetPlotOptions().Format( m_out );
620
621 m_out->Print( ")" );
622}
623
624
625void PCB_IO_KICAD_SEXPR::formatGeneral( const BOARD* aBoard ) const
626{
627 const BOARD_DESIGN_SETTINGS& dsnSettings = aBoard->GetDesignSettings();
628
629 m_out->Print( "(general" );
630
631 m_out->Print( "(thickness %s)",
632 formatInternalUnits( dsnSettings.GetBoardThickness() ).c_str() );
633
634 KICAD_FORMAT::FormatBool( m_out, "legacy_teardrops", aBoard->LegacyTeardrops() );
635
636 m_out->Print( ")" );
637
638 aBoard->GetPageSettings().Format( m_out );
639 aBoard->GetTitleBlock().Format( m_out );
640}
641
642
644{
645 m_out->Print( "(layers" );
646
647 // Save only the used copper layers from front to back.
648
649 for( PCB_LAYER_ID layer : aBoard->GetEnabledLayers().CuStack() )
650 {
651 m_out->Print( "(%d %s %s %s)",
652 layer,
653 m_out->Quotew( LSET::Name( layer ) ).c_str(),
654 LAYER::ShowType( aBoard->GetLayerType( layer ) ),
655 LSET::Name( layer ) == m_board->GetLayerName( layer )
656 ? ""
657 : m_out->Quotew( m_board->GetLayerName( layer ) ).c_str() );
658
659 }
660
661 // Save used non-copper layers in the order they are defined.
662 LSEQ seq = aBoard->GetEnabledLayers().TechAndUserUIOrder();
663
664 for( PCB_LAYER_ID layer : seq )
665 {
666 m_out->Print( "(%d %s %s %s)",
667 layer,
668 m_out->Quotew( LSET::Name( layer ) ).c_str(),
669 layer >= User_1 && IsCopperLayer( layer )
670 ? LAYER::ShowType( aBoard->GetLayerType( layer ) )
671 : "user",
672 m_board->GetLayerName( layer ) == LSET::Name( layer )
673 ? ""
674 : m_out->Quotew( m_board->GetLayerName( layer ) ).c_str() );
675 }
676
677 m_out->Print( ")" );
678}
679
680
682{
683 for( NETINFO_ITEM* net : *m_mapping )
684 {
685 if( net == nullptr ) // Skip not actually existing nets (orphan nets)
686 continue;
687
688 m_out->Print( "(net %d %s)",
689 m_mapping->Translate( net->GetNetCode() ),
690 m_out->Quotew( net->GetNetname() ).c_str() );
691 }
692}
693
694
696{
697 for( const std::pair<const wxString, wxString>& prop : aBoard->GetProperties() )
698 {
699 m_out->Print( "(property %s %s)",
700 m_out->Quotew( prop.first ).c_str(),
701 m_out->Quotew( prop.second ).c_str() );
702 }
703}
704
705
706void PCB_IO_KICAD_SEXPR::formatHeader( const BOARD* aBoard ) const
707{
708 formatGeneral( aBoard );
709
710 // Layers list.
711 formatBoardLayers( aBoard );
712
713 // Setup
714 formatSetup( aBoard );
715
716 // Properties
717 formatProperties( aBoard );
718
719 // Save net codes and names
720 formatNetInformation( aBoard );
721}
722
723
725{
726 static const TEARDROP_PARAMETERS defaults;
727
728 return tdParams.m_Enabled == defaults.m_Enabled
729 && tdParams.m_BestLengthRatio == defaults.m_BestLengthRatio
730 && tdParams.m_TdMaxLen == defaults.m_TdMaxLen
731 && tdParams.m_BestWidthRatio == defaults.m_BestWidthRatio
732 && tdParams.m_TdMaxWidth == defaults.m_TdMaxWidth
733 && tdParams.m_CurvedEdges == defaults.m_CurvedEdges
735 && tdParams.m_AllowUseTwoTracks == defaults.m_AllowUseTwoTracks
736 && tdParams.m_TdOnPadsInZones == defaults.m_TdOnPadsInZones;
737}
738
739
741{
742 m_out->Print( "(teardrops (best_length_ratio %s) (max_length %s) (best_width_ratio %s) "
743 "(max_width %s)",
744 FormatDouble2Str( tdParams.m_BestLengthRatio ).c_str(),
745 formatInternalUnits( tdParams.m_TdMaxLen ).c_str(),
746 FormatDouble2Str( tdParams.m_BestWidthRatio ).c_str(),
747 formatInternalUnits( tdParams.m_TdMaxWidth ).c_str() );
748
749 KICAD_FORMAT::FormatBool( m_out, "curved_edges", tdParams.m_CurvedEdges );
750
751 m_out->Print( "(filter_ratio %s)",
752 FormatDouble2Str( tdParams.m_WidthtoSizeFilterRatio ).c_str() );
753
754 KICAD_FORMAT::FormatBool( m_out, "enabled", tdParams.m_Enabled );
755 KICAD_FORMAT::FormatBool( m_out, "allow_two_segments", tdParams.m_AllowUseTwoTracks );
756 KICAD_FORMAT::FormatBool( m_out, "prefer_zone_connections", !tdParams.m_TdOnPadsInZones );
757 m_out->Print( ")" );
758}
759
760
761void PCB_IO_KICAD_SEXPR::format( const BOARD* aBoard ) const
762{
763 std::set<BOARD_ITEM*, BOARD_ITEM::ptr_cmp> sorted_footprints( aBoard->Footprints().begin(),
764 aBoard->Footprints().end() );
765 std::set<BOARD_ITEM*, BOARD_ITEM::ptr_cmp> sorted_drawings( aBoard->Drawings().begin(),
766 aBoard->Drawings().end() );
767 std::set<PCB_TRACK*, PCB_TRACK::cmp_tracks> sorted_tracks( aBoard->Tracks().begin(),
768 aBoard->Tracks().end() );
769 std::set<BOARD_ITEM*, BOARD_ITEM::ptr_cmp> sorted_zones( aBoard->Zones().begin(),
770 aBoard->Zones().end() );
771 std::set<BOARD_ITEM*, BOARD_ITEM::ptr_cmp> sorted_groups( aBoard->Groups().begin(),
772 aBoard->Groups().end() );
773 std::set<BOARD_ITEM*, BOARD_ITEM::ptr_cmp> sorted_generators( aBoard->Generators().begin(),
774 aBoard->Generators().end() );
775 formatHeader( aBoard );
776
777 // Save the footprints.
778 for( BOARD_ITEM* footprint : sorted_footprints )
779 Format( footprint );
780
781 // Save the graphical items on the board (not owned by a footprint)
782 for( BOARD_ITEM* item : sorted_drawings )
783 Format( item );
784
785 // Do not save PCB_MARKERs, they can be regenerated easily.
786
787 // Save the tracks and vias.
788 for( PCB_TRACK* track : sorted_tracks )
789 Format( track );
790
791 // Save the polygon (which are the newer technology) zones.
792 for( auto zone : sorted_zones )
793 Format( zone );
794
795 // Save the groups
796 for( BOARD_ITEM* group : sorted_groups )
797 Format( group );
798
799 // Save the generators
800 for( BOARD_ITEM* gen : sorted_generators )
801 Format( gen );
802
803 // Save any embedded files
804 // Consolidate the embedded models in footprints into a single map
805 // to avoid duplicating the same model in the board file.
806 EMBEDDED_FILES files_to_write;
807
808 for( auto& file : aBoard->GetEmbeddedFiles()->EmbeddedFileMap() )
809 files_to_write.AddFile( file.second );
810
811 for( BOARD_ITEM* item : sorted_footprints )
812 {
813 FOOTPRINT* fp = static_cast<FOOTPRINT*>( item );
814
815 for( auto& file : fp->GetEmbeddedFiles()->EmbeddedFileMap() )
816 files_to_write.AddFile( file.second );
817 }
818
819 m_out->Print( "(embedded_fonts %s)",
820 aBoard->GetEmbeddedFiles()->GetAreFontsEmbedded() ? "yes" : "no" );
821
822 if( !files_to_write.IsEmpty() )
823 files_to_write.WriteEmbeddedFiles( *m_out, ( m_ctl & CTL_FOR_BOARD ) );
824
825 // Remove the files so that they are not freed in the DTOR
826 files_to_write.ClearEmbeddedFiles( false );
827}
828
829
830void PCB_IO_KICAD_SEXPR::format( const PCB_DIMENSION_BASE* aDimension ) const
831{
832 const PCB_DIM_ALIGNED* aligned = dynamic_cast<const PCB_DIM_ALIGNED*>( aDimension );
833 const PCB_DIM_ORTHOGONAL* ortho = dynamic_cast<const PCB_DIM_ORTHOGONAL*>( aDimension );
834 const PCB_DIM_CENTER* center = dynamic_cast<const PCB_DIM_CENTER*>( aDimension );
835 const PCB_DIM_RADIAL* radial = dynamic_cast<const PCB_DIM_RADIAL*>( aDimension );
836 const PCB_DIM_LEADER* leader = dynamic_cast<const PCB_DIM_LEADER*>( aDimension );
837
838 m_out->Print( "(dimension" );
839
840 if( ortho ) // must be tested before aligned, because ortho is derived from aligned
841 // and aligned is not null
842 m_out->Print( "(type orthogonal)" );
843 else if( aligned )
844 m_out->Print( "(type aligned)" );
845 else if( leader )
846 m_out->Print( "(type leader)" );
847 else if( center )
848 m_out->Print( "(type center)" );
849 else if( radial )
850 m_out->Print( "(type radial)" );
851 else
852 wxFAIL_MSG( wxT( "Cannot format unknown dimension type!" ) );
853
854 if( aDimension->IsLocked() )
855 KICAD_FORMAT::FormatBool( m_out, "locked", aDimension->IsLocked() );
856
857 formatLayer( aDimension->GetLayer() );
858
859 KICAD_FORMAT::FormatUuid( m_out, aDimension->m_Uuid );
860
861 m_out->Print( "(pts (xy %s %s) (xy %s %s))",
862 formatInternalUnits( aDimension->GetStart().x ).c_str(),
863 formatInternalUnits( aDimension->GetStart().y ).c_str(),
864 formatInternalUnits( aDimension->GetEnd().x ).c_str(),
865 formatInternalUnits( aDimension->GetEnd().y ).c_str() );
866
867 if( aligned )
868 m_out->Print( "(height %s)", formatInternalUnits( aligned->GetHeight() ).c_str() );
869
870 if( radial )
871 {
872 m_out->Print( "(leader_length %s)",
873 formatInternalUnits( radial->GetLeaderLength() ).c_str() );
874 }
875
876 if( ortho )
877 m_out->Print( "(orientation %d)", static_cast<int>( ortho->GetOrientation() ) );
878
879 if( !center )
880 {
881 m_out->Print( "(format (prefix %s) (suffix %s) (units %d) (units_format %d) (precision %d)",
882 m_out->Quotew( aDimension->GetPrefix() ).c_str(),
883 m_out->Quotew( aDimension->GetSuffix() ).c_str(),
884 static_cast<int>( aDimension->GetUnitsMode() ),
885 static_cast<int>( aDimension->GetUnitsFormat() ),
886 static_cast<int>( aDimension->GetPrecision() ) );
887
888 if( aDimension->GetOverrideTextEnabled() )
889 {
890 m_out->Print( "(override_value %s)",
891 m_out->Quotew( aDimension->GetOverrideText() ).c_str() );
892 }
893
894 if( aDimension->GetSuppressZeroes() )
895 KICAD_FORMAT::FormatBool( m_out, "suppress_zeroes", true );
896
897 m_out->Print( ")" );
898 }
899
900 m_out->Print( "(style (thickness %s) (arrow_length %s) (text_position_mode %d)",
901 formatInternalUnits( aDimension->GetLineThickness() ).c_str(),
902 formatInternalUnits( aDimension->GetArrowLength() ).c_str(),
903 static_cast<int>( aDimension->GetTextPositionMode() ) );
904
905 if( ortho || aligned )
906 {
907 switch( aDimension->GetArrowDirection() )
908 {
909 case DIM_ARROW_DIRECTION::OUTWARD:
910 m_out->Print( "(arrow_direction outward)" );
911 break;
912 case DIM_ARROW_DIRECTION::INWARD:
913 m_out->Print( "(arrow_direction inward)" );
914 break;
915 // No default, handle all cases
916 }
917 }
918
919 if( aligned )
920 {
921 m_out->Print( "(extension_height %s)",
922 formatInternalUnits( aligned->GetExtensionHeight() ).c_str() );
923 }
924
925 if( leader )
926 m_out->Print( "(text_frame %d)", static_cast<int>( leader->GetTextBorder() ) );
927
928 m_out->Print( "(extension_offset %s)",
929 formatInternalUnits( aDimension->GetExtensionOffset() ).c_str() );
930
931 if( aDimension->GetKeepTextAligned() )
932 KICAD_FORMAT::FormatBool( m_out, "keep_text_aligned", true );
933
934 m_out->Print( ")" );
935
936 // Write dimension text after all other options to be sure the
937 // text options are known when reading the file
938 if( !center )
939 format( static_cast<const PCB_TEXT*>( aDimension ) );
940
941 m_out->Print( ")" );
942}
943
944
945void PCB_IO_KICAD_SEXPR::format( const PCB_SHAPE* aShape ) const
946{
947 FOOTPRINT* parentFP = aShape->GetParentFootprint();
948 std::string prefix = parentFP ? "fp" : "gr";
949
950 switch( aShape->GetShape() )
951 {
952 case SHAPE_T::SEGMENT:
953 m_out->Print( "(%s_line (start %s) (end %s)",
954 prefix.c_str(),
955 formatInternalUnits( aShape->GetStart(), parentFP ).c_str(),
956 formatInternalUnits( aShape->GetEnd(), parentFP ).c_str() );
957 break;
958
959 case SHAPE_T::RECTANGLE:
960 m_out->Print( "(%s_rect (start %s) (end %s)",
961 prefix.c_str(),
962 formatInternalUnits( aShape->GetStart(), parentFP ).c_str(),
963 formatInternalUnits( aShape->GetEnd(), parentFP ).c_str() );
964 break;
965
966 case SHAPE_T::CIRCLE:
967 m_out->Print( "(%s_circle (center %s) (end %s)",
968 prefix.c_str(),
969 formatInternalUnits( aShape->GetStart(), parentFP ).c_str(),
970 formatInternalUnits( aShape->GetEnd(), parentFP ).c_str() );
971 break;
972
973 case SHAPE_T::ARC:
974 m_out->Print( "(%s_arc (start %s) (mid %s) (end %s)",
975 prefix.c_str(),
976 formatInternalUnits( aShape->GetStart(), parentFP ).c_str(),
977 formatInternalUnits( aShape->GetArcMid(), parentFP ).c_str(),
978 formatInternalUnits( aShape->GetEnd(), parentFP ).c_str() );
979 break;
980
981 case SHAPE_T::POLY:
982 if( aShape->IsPolyShapeValid() )
983 {
984 const SHAPE_POLY_SET& poly = aShape->GetPolyShape();
985 const SHAPE_LINE_CHAIN& outline = poly.Outline( 0 );
986
987 m_out->Print( "(%s_poly", prefix.c_str() );
988 formatPolyPts( outline, parentFP );
989 }
990 else
991 {
992 wxFAIL_MSG( wxT( "Cannot format invalid polygon." ) );
993 return;
994 }
995
996 break;
997
998 case SHAPE_T::BEZIER:
999 m_out->Print( "(%s_curve (pts (xy %s) (xy %s) (xy %s) (xy %s))",
1000 prefix.c_str(),
1001 formatInternalUnits( aShape->GetStart(), parentFP ).c_str(),
1002 formatInternalUnits( aShape->GetBezierC1(), parentFP ).c_str(),
1003 formatInternalUnits( aShape->GetBezierC2(), parentFP ).c_str(),
1004 formatInternalUnits( aShape->GetEnd(), parentFP ).c_str() );
1005 break;
1006
1007 default:
1009 return;
1010 };
1011
1012 aShape->GetStroke().Format( m_out, pcbIUScale );
1013
1014 // The filled flag represents if a solid fill is present on circles, rectangles and polygons
1015 if( ( aShape->GetShape() == SHAPE_T::POLY )
1016 || ( aShape->GetShape() == SHAPE_T::RECTANGLE )
1017 || ( aShape->GetShape() == SHAPE_T::CIRCLE ) )
1018 {
1019 KICAD_FORMAT::FormatBool( m_out, "fill", aShape->IsFilled() );
1020 }
1021
1022 if( aShape->IsLocked() )
1023 KICAD_FORMAT::FormatBool( m_out, "locked", true );
1024
1025 if( aShape->GetLayerSet().count() > 1 )
1026 formatLayers( aShape->GetLayerSet(), false /* enumerate layers */ );
1027 else
1028 formatLayer( aShape->GetLayer() );
1029
1030 if( aShape->HasSolderMask()
1031 && aShape->GetLocalSolderMaskMargin().has_value()
1032 && IsExternalCopperLayer( aShape->GetLayer() ) )
1033 {
1034 m_out->Print( "(solder_mask_margin %s)",
1035 formatInternalUnits( aShape->GetLocalSolderMaskMargin().value() ).c_str() );
1036 }
1037
1038 if( aShape->GetNetCode() > 0 )
1039 m_out->Print( "(net %d)", m_mapping->Translate( aShape->GetNetCode() ) );
1040
1042 m_out->Print( ")" );
1043}
1044
1045
1047{
1048 wxCHECK_RET( aBitmap != nullptr && m_out != nullptr, "" );
1049
1050 const REFERENCE_IMAGE& refImage = aBitmap->GetReferenceImage();
1051
1052 const wxImage* image = refImage.GetImage().GetImageData();
1053
1054 wxCHECK_RET( image != nullptr, "wxImage* is NULL" );
1055
1056 m_out->Print( "(image (at %s %s)",
1057 formatInternalUnits( aBitmap->GetPosition().x ).c_str(),
1058 formatInternalUnits( aBitmap->GetPosition().y ).c_str() );
1059
1060 formatLayer( aBitmap->GetLayer() );
1061
1062 if( refImage.GetImageScale() != 1.0 )
1063 m_out->Print( "(scale %g)", refImage.GetImageScale() );
1064
1065 if( aBitmap->IsLocked() )
1066 KICAD_FORMAT::FormatBool( m_out, "locked", true );
1067
1068 wxMemoryOutputStream ostream;
1069 refImage.GetImage().SaveImageData( ostream );
1070
1071 KICAD_FORMAT::FormatStreamData( *m_out, *ostream.GetOutputStreamBuffer() );
1072
1074 m_out->Print( ")" ); // Closes image token.
1075}
1076
1077
1078void PCB_IO_KICAD_SEXPR::format( const PCB_TARGET* aTarget ) const
1079{
1080 m_out->Print( "(target %s (at %s) (size %s)",
1081 ( aTarget->GetShape() ) ? "x" : "plus",
1082 formatInternalUnits( aTarget->GetPosition() ).c_str(),
1083 formatInternalUnits( aTarget->GetSize() ).c_str() );
1084
1085 if( aTarget->GetWidth() != 0 )
1086 m_out->Print( "(width %s)", formatInternalUnits( aTarget->GetWidth() ).c_str() );
1087
1088 formatLayer( aTarget->GetLayer() );
1090 m_out->Print( ")" );
1091}
1092
1093
1094void PCB_IO_KICAD_SEXPR::format( const FOOTPRINT* aFootprint ) const
1095{
1096 if( !( m_ctl & CTL_OMIT_INITIAL_COMMENTS ) )
1097 {
1098 const wxArrayString* initial_comments = aFootprint->GetInitialComments();
1099
1100 if( initial_comments )
1101 {
1102 for( unsigned i = 0; i < initial_comments->GetCount(); ++i )
1103 m_out->Print( "%s\n", TO_UTF8( (*initial_comments)[i] ) );
1104 }
1105 }
1106
1107 if( m_ctl & CTL_OMIT_LIBNAME )
1108 {
1109 m_out->Print( "(footprint %s",
1110 m_out->Quotes( aFootprint->GetFPID().GetLibItemName() ).c_str() );
1111 }
1112 else
1113 {
1114 m_out->Print( "(footprint %s",
1115 m_out->Quotes( aFootprint->GetFPID().Format() ).c_str() );
1116 }
1117
1119 {
1120 m_out->Print( "(version %d) (generator \"pcbnew\") (generator_version %s)",
1122 m_out->Quotew( GetMajorMinorVersion() ).c_str() );
1123 }
1124
1125 if( aFootprint->IsLocked() )
1126 KICAD_FORMAT::FormatBool( m_out, "locked", true );
1127
1128 if( aFootprint->IsPlaced() )
1129 KICAD_FORMAT::FormatBool( m_out, "placed", true );
1130
1131 formatLayer( aFootprint->GetLayer() );
1132
1133 if( !( m_ctl & CTL_OMIT_UUIDS ) )
1134 KICAD_FORMAT::FormatUuid( m_out, aFootprint->m_Uuid );
1135
1136 if( !( m_ctl & CTL_OMIT_AT ) )
1137 {
1138 m_out->Print( "(at %s %s)",
1139 formatInternalUnits( aFootprint->GetPosition() ).c_str(),
1140 aFootprint->GetOrientation().IsZero()
1141 ? ""
1142 : EDA_UNIT_UTILS::FormatAngle( aFootprint->GetOrientation() ).c_str() );
1143 }
1144
1145 if( !aFootprint->GetLibDescription().IsEmpty() )
1146 m_out->Print( "(descr %s)", m_out->Quotew( aFootprint->GetLibDescription() ).c_str() );
1147
1148 if( !aFootprint->GetKeywords().IsEmpty() )
1149 m_out->Print( "(tags %s)", m_out->Quotew( aFootprint->GetKeywords() ).c_str() );
1150
1151 for( const PCB_FIELD* field : aFootprint->GetFields() )
1152 {
1153 m_out->Print( "(property %s %s",
1154 m_out->Quotew( field->GetCanonicalName() ).c_str(),
1155 m_out->Quotew( field->GetText() ).c_str() );
1156
1157 format( field );
1158
1159 m_out->Print( ")" );
1160 }
1161
1162 if( const COMPONENT_CLASS* compClass = aFootprint->GetComponentClass() )
1163 {
1164 if( !compClass->IsEmpty() )
1165 {
1166 m_out->Print( "(component_classes" );
1167
1168 for( const COMPONENT_CLASS* constituent : compClass->GetConstituentClasses() )
1169 m_out->Print( "(class %s)", m_out->Quotew( constituent->GetFullName() ).c_str() );
1170
1171 m_out->Print( ")" );
1172 }
1173 }
1174
1175 if( !aFootprint->GetFilters().empty() )
1176 {
1177 m_out->Print( "(property ki_fp_filters %s)",
1178 m_out->Quotew( aFootprint->GetFilters() ).c_str() );
1179 }
1180
1181 if( !( m_ctl & CTL_OMIT_PATH ) && !aFootprint->GetPath().empty() )
1182 m_out->Print( "(path %s)", m_out->Quotew( aFootprint->GetPath().AsString() ).c_str() );
1183
1184 if( !aFootprint->GetSheetname().empty() )
1185 m_out->Print( "(sheetname %s)", m_out->Quotew( aFootprint->GetSheetname() ).c_str() );
1186
1187 if( !aFootprint->GetSheetfile().empty() )
1188 m_out->Print( "(sheetfile %s)", m_out->Quotew( aFootprint->GetSheetfile() ).c_str() );
1189
1190 if( aFootprint->GetLocalSolderMaskMargin().has_value() )
1191 {
1192 m_out->Print( "(solder_mask_margin %s)",
1193 formatInternalUnits( aFootprint->GetLocalSolderMaskMargin().value() ).c_str() );
1194 }
1195
1196 if( aFootprint->GetLocalSolderPasteMargin().has_value() )
1197 {
1198 m_out->Print( "(solder_paste_margin %s)",
1199 formatInternalUnits( aFootprint->GetLocalSolderPasteMargin().value() ).c_str() );
1200 }
1201
1202 if( aFootprint->GetLocalSolderPasteMarginRatio().has_value() )
1203 {
1204 m_out->Print( "(solder_paste_margin_ratio %s)",
1205 FormatDouble2Str( aFootprint->GetLocalSolderPasteMarginRatio().value() ).c_str() );
1206 }
1207
1208 if( aFootprint->GetLocalClearance().has_value() )
1209 {
1210 m_out->Print( "(clearance %s)",
1211 formatInternalUnits( aFootprint->GetLocalClearance().value() ).c_str() );
1212 }
1213
1214 if( aFootprint->GetLocalZoneConnection() != ZONE_CONNECTION::INHERITED )
1215 {
1216 m_out->Print( "(zone_connect %d)",
1217 static_cast<int>( aFootprint->GetLocalZoneConnection() ) );
1218 }
1219
1220 // Attributes
1221 if( aFootprint->GetAttributes() )
1222 {
1223 m_out->Print( "(attr" );
1224
1225 if( aFootprint->GetAttributes() & FP_SMD )
1226 m_out->Print( " smd" );
1227
1228 if( aFootprint->GetAttributes() & FP_THROUGH_HOLE )
1229 m_out->Print( " through_hole" );
1230
1231 if( aFootprint->GetAttributes() & FP_BOARD_ONLY )
1232 m_out->Print( " board_only" );
1233
1234 if( aFootprint->GetAttributes() & FP_EXCLUDE_FROM_POS_FILES )
1235 m_out->Print( " exclude_from_pos_files" );
1236
1237 if( aFootprint->GetAttributes() & FP_EXCLUDE_FROM_BOM )
1238 m_out->Print( " exclude_from_bom" );
1239
1240 if( aFootprint->GetAttributes() & FP_ALLOW_MISSING_COURTYARD )
1241 m_out->Print( " allow_missing_courtyard" );
1242
1243 if( aFootprint->GetAttributes() & FP_DNP )
1244 m_out->Print( " dnp" );
1245
1246 if( aFootprint->GetAttributes() & FP_ALLOW_SOLDERMASK_BRIDGES )
1247 m_out->Print( " allow_soldermask_bridges" );
1248
1249 m_out->Print( ")" );
1250 }
1251
1252 if( aFootprint->GetPrivateLayers().any() )
1253 {
1254 m_out->Print( "(private_layers" );
1255
1256 for( PCB_LAYER_ID layer : aFootprint->GetPrivateLayers().Seq() )
1257 {
1258 wxString canonicalName( LSET::Name( layer ) );
1259 m_out->Print( " %s", m_out->Quotew( canonicalName ).c_str() );
1260 }
1261
1262 m_out->Print( ")" );
1263 }
1264
1265 if( aFootprint->IsNetTie() )
1266 {
1267 m_out->Print( "(net_tie_pad_groups" );
1268
1269 for( const wxString& group : aFootprint->GetNetTiePadGroups() )
1270 m_out->Print( " %s", m_out->Quotew( group ).c_str() );
1271
1272 m_out->Print( ")" );
1273 }
1274
1275 Format( (BOARD_ITEM*) &aFootprint->Reference() );
1276 Format( (BOARD_ITEM*) &aFootprint->Value() );
1277
1278 std::set<PAD*, FOOTPRINT::cmp_pads> sorted_pads( aFootprint->Pads().begin(),
1279 aFootprint->Pads().end() );
1280 std::set<BOARD_ITEM*, FOOTPRINT::cmp_drawings> sorted_drawings(
1281 aFootprint->GraphicalItems().begin(),
1282 aFootprint->GraphicalItems().end() );
1283 std::set<ZONE*, FOOTPRINT::cmp_zones> sorted_zones( aFootprint->Zones().begin(),
1284 aFootprint->Zones().end() );
1285 std::set<BOARD_ITEM*, PCB_GROUP::ptr_cmp> sorted_groups( aFootprint->Groups().begin(),
1286 aFootprint->Groups().end() );
1287
1288 // Save drawing elements.
1289
1290 for( BOARD_ITEM* gr : sorted_drawings )
1291 Format( gr );
1292
1293 // Save pads.
1294 for( PAD* pad : sorted_pads )
1295 Format( pad );
1296
1297 // Save zones.
1298 for( BOARD_ITEM* zone : sorted_zones )
1299 Format( zone );
1300
1301 // Save groups.
1302 for( BOARD_ITEM* group : sorted_groups )
1303 Format( group );
1304
1305 KICAD_FORMAT::FormatBool( m_out, "embedded_fonts",
1306 aFootprint->GetEmbeddedFiles()->GetAreFontsEmbedded() );
1307
1308 if( !aFootprint->GetEmbeddedFiles()->IsEmpty() )
1309 aFootprint->WriteEmbeddedFiles( *m_out, !( m_ctl & CTL_FOR_BOARD ) );
1310
1311 // Save 3D info.
1312 auto bs3D = aFootprint->Models().begin();
1313 auto es3D = aFootprint->Models().end();
1314
1315 while( bs3D != es3D )
1316 {
1317 if( !bs3D->m_Filename.IsEmpty() )
1318 {
1319 m_out->Print( "(model %s", m_out->Quotew( bs3D->m_Filename ).c_str() );
1320
1321 if( !bs3D->m_Show )
1322 KICAD_FORMAT::FormatBool( m_out, "hide", !bs3D->m_Show );
1323
1324 if( bs3D->m_Opacity != 1.0 )
1325 m_out->Print( "(opacity %0.4f)", bs3D->m_Opacity );
1326
1327 m_out->Print( "(offset (xyz %s %s %s))",
1328 FormatDouble2Str( bs3D->m_Offset.x ).c_str(),
1329 FormatDouble2Str( bs3D->m_Offset.y ).c_str(),
1330 FormatDouble2Str( bs3D->m_Offset.z ).c_str() );
1331
1332 m_out->Print( "(scale (xyz %s %s %s))",
1333 FormatDouble2Str( bs3D->m_Scale.x ).c_str(),
1334 FormatDouble2Str( bs3D->m_Scale.y ).c_str(),
1335 FormatDouble2Str( bs3D->m_Scale.z ).c_str() );
1336
1337 m_out->Print( "(rotate (xyz %s %s %s))",
1338 FormatDouble2Str( bs3D->m_Rotation.x ).c_str(),
1339 FormatDouble2Str( bs3D->m_Rotation.y ).c_str(),
1340 FormatDouble2Str( bs3D->m_Rotation.z ).c_str() );
1341
1342 m_out->Print( ")" );
1343 }
1344
1345 ++bs3D;
1346 }
1347
1348 m_out->Print( ")" );
1349}
1350
1351
1352void PCB_IO_KICAD_SEXPR::formatLayers( LSET aLayerMask, bool aEnumerateLayers ) const
1353{
1354 static const LSET cu_all( LSET::AllCuMask() );
1355 static const LSET fr_bk( { B_Cu, F_Cu } );
1356 static const LSET adhes( { B_Adhes, F_Adhes } );
1357 static const LSET paste( { B_Paste, F_Paste } );
1358 static const LSET silks( { B_SilkS, F_SilkS } );
1359 static const LSET mask( { B_Mask, F_Mask } );
1360 static const LSET crt_yd( { B_CrtYd, F_CrtYd } );
1361 static const LSET fab( { B_Fab, F_Fab } );
1362
1363 LSET cu_board_mask = LSET::AllCuMask( m_board
1365 : MAX_CU_LAYERS );
1366
1367 std::string output;
1368
1369 if( !aEnumerateLayers )
1370 {
1371 // If all copper layers present on the board are enabled, then output the wildcard
1372 if( ( aLayerMask & cu_board_mask ) == cu_board_mask )
1373 {
1374 output += ' ' + m_out->Quotew( "*.Cu" );
1375
1376 // Clear all copper bits because pads might have internal layers that aren't part of the
1377 // board enabled, and we don't want to output those in the layers listing if we already
1378 // output the wildcard.
1379 aLayerMask &= ~cu_all;
1380 }
1381 else if( ( aLayerMask & cu_board_mask ) == fr_bk )
1382 {
1383 output += ' ' + m_out->Quotew( "F&B.Cu" );
1384 aLayerMask &= ~fr_bk;
1385 }
1386
1387 if( ( aLayerMask & adhes ) == adhes )
1388 {
1389 output += ' ' + m_out->Quotew( "*.Adhes" );
1390 aLayerMask &= ~adhes;
1391 }
1392
1393 if( ( aLayerMask & paste ) == paste )
1394 {
1395 output += ' ' + m_out->Quotew( "*.Paste" );
1396 aLayerMask &= ~paste;
1397 }
1398
1399 if( ( aLayerMask & silks ) == silks )
1400 {
1401 output += ' ' + m_out->Quotew( "*.SilkS" );
1402 aLayerMask &= ~silks;
1403 }
1404
1405 if( ( aLayerMask & mask ) == mask )
1406 {
1407 output += ' ' + m_out->Quotew( "*.Mask" );
1408 aLayerMask &= ~mask;
1409 }
1410
1411 if( ( aLayerMask & crt_yd ) == crt_yd )
1412 {
1413 output += ' ' + m_out->Quotew( "*.CrtYd" );
1414 aLayerMask &= ~crt_yd;
1415 }
1416
1417 if( ( aLayerMask & fab ) == fab )
1418 {
1419 output += ' ' + m_out->Quotew( "*.Fab" );
1420 aLayerMask &= ~fab;
1421 }
1422 }
1423
1424 // output any individual layers not handled in wildcard combos above
1425 wxString layerName;
1426
1427 for( int layer = 0; layer < PCB_LAYER_ID_COUNT; ++layer )
1428 {
1429 if( aLayerMask[layer] )
1430 output += ' ' + m_out->Quotew( LSET::Name( PCB_LAYER_ID( layer ) ) );
1431 }
1432
1433 m_out->Print( "(layers %s)", output.c_str() );
1434}
1435
1436
1437void PCB_IO_KICAD_SEXPR::format( const PAD* aPad ) const
1438{
1439 const BOARD* board = aPad->GetBoard();
1440
1441 auto shapeName =
1442 [&]( PCB_LAYER_ID aLayer )
1443 {
1444 switch( aPad->GetShape( aLayer ) )
1445 {
1446 case PAD_SHAPE::CIRCLE: return "circle";
1447 case PAD_SHAPE::RECTANGLE: return "rect";
1448 case PAD_SHAPE::OVAL: return "oval";
1449 case PAD_SHAPE::TRAPEZOID: return "trapezoid";
1450 case PAD_SHAPE::CHAMFERED_RECT:
1451 case PAD_SHAPE::ROUNDRECT: return "roundrect";
1452 case PAD_SHAPE::CUSTOM: return "custom";
1453
1454 default:
1455 THROW_IO_ERROR( wxString::Format( _( "unknown pad type: %d"),
1456 aPad->GetShape( aLayer ) ) );
1457 }
1458 };
1459
1460 const char* type;
1461
1462 switch( aPad->GetAttribute() )
1463 {
1464 case PAD_ATTRIB::PTH: type = "thru_hole"; break;
1465 case PAD_ATTRIB::SMD: type = "smd"; break;
1466 case PAD_ATTRIB::CONN: type = "connect"; break;
1467 case PAD_ATTRIB::NPTH: type = "np_thru_hole"; break;
1468
1469 default:
1470 THROW_IO_ERROR( wxString::Format( wxT( "unknown pad attribute: %d" ),
1471 aPad->GetAttribute() ) );
1472 }
1473
1474 const char* property = nullptr;
1475
1476 switch( aPad->GetProperty() )
1477 {
1478 case PAD_PROP::NONE: break; // could be "none"
1479 case PAD_PROP::BGA: property = "pad_prop_bga"; break;
1480 case PAD_PROP::FIDUCIAL_GLBL: property = "pad_prop_fiducial_glob"; break;
1481 case PAD_PROP::FIDUCIAL_LOCAL: property = "pad_prop_fiducial_loc"; break;
1482 case PAD_PROP::TESTPOINT: property = "pad_prop_testpoint"; break;
1483 case PAD_PROP::HEATSINK: property = "pad_prop_heatsink"; break;
1484 case PAD_PROP::CASTELLATED: property = "pad_prop_castellated"; break;
1485 case PAD_PROP::MECHANICAL: property = "pad_prop_mechanical"; break;
1486
1487 default:
1488 THROW_IO_ERROR( wxString::Format( wxT( "unknown pad property: %d" ),
1489 aPad->GetProperty() ) );
1490 }
1491
1492 m_out->Print( "(pad %s %s %s",
1493 m_out->Quotew( aPad->GetNumber() ).c_str(),
1494 type,
1495 shapeName( PADSTACK::ALL_LAYERS ) );
1496
1497 m_out->Print( "(at %s %s)",
1498 formatInternalUnits( aPad->GetFPRelativePosition() ).c_str(),
1499 aPad->GetOrientation().IsZero()
1500 ? ""
1501 : EDA_UNIT_UTILS::FormatAngle( aPad->GetOrientation() ).c_str() );
1502
1503 m_out->Print( "(size %s)", formatInternalUnits( aPad->GetSize( PADSTACK::ALL_LAYERS ) ).c_str() );
1504
1505 if( aPad->GetDelta( PADSTACK::ALL_LAYERS ).x != 0
1506 || aPad->GetDelta( PADSTACK::ALL_LAYERS ).y != 0 )
1507 {
1508 m_out->Print( "(rect_delta %s)",
1510 }
1511
1512 VECTOR2I sz = aPad->GetDrillSize();
1513 VECTOR2I shapeoffset = aPad->GetOffset( PADSTACK::ALL_LAYERS );
1514
1515 if( (sz.x > 0) || (sz.y > 0) ||
1516 (shapeoffset.x != 0) || (shapeoffset.y != 0) )
1517 {
1518 m_out->Print( "(drill" );
1519
1520 if( aPad->GetDrillShape() == PAD_DRILL_SHAPE::OBLONG )
1521 m_out->Print( " oval" );
1522
1523 if( sz.x > 0 )
1524 m_out->Print( " %s", formatInternalUnits( sz.x ).c_str() );
1525
1526 if( sz.y > 0 && sz.x != sz.y )
1527 m_out->Print( " %s", formatInternalUnits( sz.y ).c_str() );
1528
1529 // NOTE: Shape offest is a property of the copper shape, not of the drill, but this was put
1530 // in the file format under the drill section. So, it is left here to minimize file format
1531 // changes, but note that the other padstack layers (if present) will have an offset stored
1532 // separately.
1533 if( shapeoffset.x != 0 || shapeoffset.y != 0 )
1534 {
1535 m_out->Print( "(offset %s)",
1537 }
1538
1539 m_out->Print( ")" );
1540 }
1541
1542 // Add pad property, if exists.
1543 if( property )
1544 m_out->Print( "(property %s)", property );
1545
1546 formatLayers( aPad->GetLayerSet(), false /* enumerate layers */ );
1547
1548 if( aPad->GetAttribute() == PAD_ATTRIB::PTH )
1549 {
1550 KICAD_FORMAT::FormatBool( m_out, "remove_unused_layers", aPad->GetRemoveUnconnected() );
1551
1552 if( aPad->GetRemoveUnconnected() )
1553 {
1554 KICAD_FORMAT::FormatBool( m_out, "keep_end_layers", aPad->GetKeepTopBottom() );
1555
1556 if( board ) // Will be nullptr in footprint library
1557 {
1558 m_out->Print( "(zone_layer_connections" );
1559
1560 for( PCB_LAYER_ID layer : board->GetEnabledLayers().CuStack() )
1561 {
1562 if( aPad->GetZoneLayerOverride( layer ) == ZLO_FORCE_FLASHED )
1563 m_out->Print( " %s", m_out->Quotew( LSET::Name( layer ) ).c_str() );
1564 }
1565
1566 m_out->Print( ")" );
1567 }
1568 }
1569 }
1570
1571 auto formatCornerProperties =
1572 [&]( PCB_LAYER_ID aLayer )
1573 {
1574 // Output the radius ratio for rounded and chamfered rect pads
1575 if( aPad->GetShape( aLayer ) == PAD_SHAPE::ROUNDRECT
1576 || aPad->GetShape( aLayer ) == PAD_SHAPE::CHAMFERED_RECT)
1577 {
1578 m_out->Print( "(roundrect_rratio %s)",
1579 FormatDouble2Str( aPad->GetRoundRectRadiusRatio( aLayer ) ).c_str() );
1580 }
1581
1582 // Output the chamfer corners for chamfered rect pads
1583 if( aPad->GetShape( aLayer ) == PAD_SHAPE::CHAMFERED_RECT)
1584 {
1585 m_out->Print( "(chamfer_ratio %s)",
1586 FormatDouble2Str( aPad->GetChamferRectRatio( aLayer ) ).c_str() );
1587
1588 m_out->Print( "(chamfer" );
1589
1590 if( ( aPad->GetChamferPositions( aLayer ) & RECT_CHAMFER_TOP_LEFT ) )
1591 m_out->Print( " top_left" );
1592
1593 if( ( aPad->GetChamferPositions( aLayer ) & RECT_CHAMFER_TOP_RIGHT ) )
1594 m_out->Print( " top_right" );
1595
1596 if( ( aPad->GetChamferPositions( aLayer ) & RECT_CHAMFER_BOTTOM_LEFT ) )
1597 m_out->Print( " bottom_left" );
1598
1599 if( ( aPad->GetChamferPositions( aLayer ) & RECT_CHAMFER_BOTTOM_RIGHT ) )
1600 m_out->Print( " bottom_right" );
1601
1602 m_out->Print( ")" );
1603 }
1604
1605 };
1606
1607 // For normal padstacks, this is the one and only set of properties. For complex ones, this
1608 // will represent the front layer properties, and other layers will be formatted below
1609 formatCornerProperties( PADSTACK::ALL_LAYERS );
1610
1611 // Unconnected pad is default net so don't save it.
1613 {
1614 m_out->Print( "(net %d %s)", m_mapping->Translate( aPad->GetNetCode() ),
1615 m_out->Quotew( aPad->GetNetname() ).c_str() );
1616 }
1617
1618 // Pin functions and types are closely related to nets, so if CTL_OMIT_NETS is set, omit
1619 // them as well (for instance when saved from library editor).
1620 if( !( m_ctl & CTL_OMIT_PAD_NETS ) )
1621 {
1622 if( !aPad->GetPinFunction().IsEmpty() )
1623 m_out->Print( "(pinfunction %s)", m_out->Quotew( aPad->GetPinFunction() ).c_str() );
1624
1625 if( !aPad->GetPinType().IsEmpty() )
1626 m_out->Print( "(pintype %s)", m_out->Quotew( aPad->GetPinType() ).c_str() );
1627 }
1628
1629 if( aPad->GetPadToDieLength() != 0 )
1630 {
1631 m_out->Print( "(die_length %s)",
1632 formatInternalUnits( aPad->GetPadToDieLength() ).c_str() );
1633 }
1634
1635 if( aPad->GetLocalSolderMaskMargin().has_value() )
1636 {
1637 m_out->Print( "(solder_mask_margin %s)",
1638 formatInternalUnits( aPad->GetLocalSolderMaskMargin().value() ).c_str() );
1639 }
1640
1641 if( aPad->GetLocalSolderPasteMargin().has_value() )
1642 {
1643 m_out->Print( "(solder_paste_margin %s)",
1644 formatInternalUnits( aPad->GetLocalSolderPasteMargin().value() ).c_str() );
1645 }
1646
1647 if( aPad->GetLocalSolderPasteMarginRatio().has_value() )
1648 {
1649 m_out->Print( "(solder_paste_margin_ratio %s)",
1650 FormatDouble2Str( aPad->GetLocalSolderPasteMarginRatio().value() ).c_str() );
1651 }
1652
1653 if( aPad->GetLocalClearance().has_value() )
1654 {
1655 m_out->Print( "(clearance %s)",
1656 formatInternalUnits( aPad->GetLocalClearance().value() ).c_str() );
1657 }
1658
1659 if( aPad->GetLocalZoneConnection() != ZONE_CONNECTION::INHERITED )
1660 {
1661 m_out->Print( "(zone_connect %d)",
1662 static_cast<int>( aPad->GetLocalZoneConnection() ) );
1663 }
1664
1665 if( aPad->GetLocalThermalSpokeWidthOverride().has_value() )
1666 {
1667 m_out->Print( "(thermal_bridge_width %s)",
1668 formatInternalUnits( aPad->GetLocalThermalSpokeWidthOverride().value() ).c_str() );
1669 }
1670
1671 EDA_ANGLE defaultThermalSpokeAngle = ANGLE_90;
1672
1673 if( aPad->GetShape( PADSTACK::ALL_LAYERS ) == PAD_SHAPE::CIRCLE ||
1674 ( aPad->GetShape( PADSTACK::ALL_LAYERS ) == PAD_SHAPE::CUSTOM
1675 && aPad->GetAnchorPadShape( PADSTACK::ALL_LAYERS ) == PAD_SHAPE::CIRCLE ) )
1676 {
1677 defaultThermalSpokeAngle = ANGLE_45;
1678 }
1679
1680 if( aPad->GetThermalSpokeAngle() != defaultThermalSpokeAngle )
1681 {
1682 m_out->Print( "(thermal_bridge_angle %s)",
1684 }
1685
1686 if( aPad->GetLocalThermalGapOverride().has_value() )
1687 {
1688 m_out->Print( "(thermal_gap %s)",
1689 formatInternalUnits( aPad->GetLocalThermalGapOverride().value() ).c_str() );
1690 }
1691
1692 auto anchorShape =
1693 [&]( PCB_LAYER_ID aLayer )
1694 {
1695 switch( aPad->GetAnchorPadShape( aLayer ) )
1696 {
1697 case PAD_SHAPE::RECTANGLE: return "rect";
1698 default:
1699 case PAD_SHAPE::CIRCLE: return "circle";
1700 }
1701 };
1702
1703 auto formatPrimitives =
1704 [&]( PCB_LAYER_ID aLayer )
1705 {
1706 m_out->Print( "(primitives" );
1707
1708 // Output all basic shapes
1709 for( const std::shared_ptr<PCB_SHAPE>& primitive : aPad->GetPrimitives( aLayer ) )
1710 {
1711 switch( primitive->GetShape() )
1712 {
1713 case SHAPE_T::SEGMENT:
1714 if( primitive->IsProxyItem() )
1715 {
1716 m_out->Print( "(gr_vector (start %s) (end %s)",
1717 formatInternalUnits( primitive->GetStart() ).c_str(),
1718 formatInternalUnits( primitive->GetEnd() ).c_str() );
1719 }
1720 else
1721 {
1722 m_out->Print( "(gr_line (start %s) (end %s)",
1723 formatInternalUnits( primitive->GetStart() ).c_str(),
1724 formatInternalUnits( primitive->GetEnd() ).c_str() );
1725 }
1726 break;
1727
1728 case SHAPE_T::RECTANGLE:
1729 if( primitive->IsProxyItem() )
1730 {
1731 m_out->Print( "(gr_bbox (start %s) (end %s)",
1732 formatInternalUnits( primitive->GetStart() ).c_str(),
1733 formatInternalUnits( primitive->GetEnd() ).c_str() );
1734 }
1735 else
1736 {
1737 m_out->Print( "(gr_rect (start %s) (end %s)",
1738 formatInternalUnits( primitive->GetStart() ).c_str(),
1739 formatInternalUnits( primitive->GetEnd() ).c_str() );
1740 }
1741 break;
1742
1743 case SHAPE_T::ARC:
1744 m_out->Print( "(gr_arc (start %s) (mid %s) (end %s)",
1745 formatInternalUnits( primitive->GetStart() ).c_str(),
1746 formatInternalUnits( primitive->GetArcMid() ).c_str(),
1747 formatInternalUnits( primitive->GetEnd() ).c_str() );
1748 break;
1749
1750 case SHAPE_T::CIRCLE:
1751 m_out->Print( "(gr_circle (center %s) (end %s)",
1752 formatInternalUnits( primitive->GetStart() ).c_str(),
1753 formatInternalUnits( primitive->GetEnd() ).c_str() );
1754 break;
1755
1756 case SHAPE_T::BEZIER:
1757 m_out->Print( "(gr_curve (pts (xy %s) (xy %s) (xy %s) (xy %s))",
1758 formatInternalUnits( primitive->GetStart() ).c_str(),
1759 formatInternalUnits( primitive->GetBezierC1() ).c_str(),
1760 formatInternalUnits( primitive->GetBezierC2() ).c_str(),
1761 formatInternalUnits( primitive->GetEnd() ).c_str() );
1762 break;
1763
1764 case SHAPE_T::POLY:
1765 if( primitive->IsPolyShapeValid() )
1766 {
1767 const SHAPE_POLY_SET& poly = primitive->GetPolyShape();
1768 const SHAPE_LINE_CHAIN& outline = poly.Outline( 0 );
1769
1770 m_out->Print( "(gr_poly" );
1771 formatPolyPts( outline );
1772 }
1773 break;
1774
1775 default:
1776 break;
1777 }
1778
1779 if( !primitive->IsProxyItem() )
1780 m_out->Print( "(width %s)", formatInternalUnits( primitive->GetWidth() ).c_str() );
1781
1782 // The filled flag represents if a solid fill is present on circles,
1783 // rectangles and polygons
1784 if( ( primitive->GetShape() == SHAPE_T::POLY )
1785 || ( primitive->GetShape() == SHAPE_T::RECTANGLE )
1786 || ( primitive->GetShape() == SHAPE_T::CIRCLE ) )
1787 {
1788 KICAD_FORMAT::FormatBool( m_out, "fill", primitive->IsFilled() );
1789 }
1790
1791 m_out->Print( ")" );
1792 }
1793
1794 m_out->Print( ")" ); // end of (primitives
1795 };
1796
1797 if( aPad->GetShape( PADSTACK::ALL_LAYERS ) == PAD_SHAPE::CUSTOM )
1798 {
1799 m_out->Print( "(options" );
1800
1802 m_out->Print( "(clearance convexhull)" );
1803 else
1804 m_out->Print( "(clearance outline)" );
1805
1806 // Output the anchor pad shape (circle/rect)
1807 m_out->Print( "(anchor %s)", anchorShape( PADSTACK::ALL_LAYERS ) );
1808
1809 m_out->Print( ")"); // end of (options ...
1810
1811 // Output graphic primitive of the pad shape
1812 formatPrimitives( PADSTACK::ALL_LAYERS );
1813 }
1814
1817
1818 formatTenting( aPad->Padstack() );
1819
1821
1822 // TODO: Refactor so that we call formatPadLayer( ALL_LAYERS ) above instead of redundant code
1823 auto formatPadLayer =
1824 [&]( PCB_LAYER_ID aLayer )
1825 {
1826 const PADSTACK& padstack = aPad->Padstack();
1827
1828 m_out->Print( "(shape %s)", shapeName( aLayer ) );
1829 m_out->Print( "(size %s)", formatInternalUnits( aPad->GetSize( aLayer ) ).c_str() );
1830
1831 const VECTOR2I& delta = aPad->GetDelta( aLayer );
1832
1833 if( delta.x != 0 || delta.y != 0 )
1834 m_out->Print( "(rect_delta %s)", formatInternalUnits( delta ).c_str() );
1835
1836 shapeoffset = aPad->GetOffset( aLayer );
1837
1838 if( shapeoffset.x != 0 || shapeoffset.y != 0 )
1839 m_out->Print( "(offset %s)", formatInternalUnits( shapeoffset ).c_str() );
1840
1841 formatCornerProperties( aLayer );
1842
1843 if( aPad->GetShape( aLayer ) == PAD_SHAPE::CUSTOM )
1844 {
1845 m_out->Print( "(options" );
1846
1847 // Output the anchor pad shape (circle/rect)
1848 m_out->Print( "(anchor %s)", anchorShape( aLayer ) );
1849
1850 m_out->Print( ")" ); // end of (options ...
1851
1852 // Output graphic primitive of the pad shape
1853 formatPrimitives( aLayer );
1854 }
1855
1856 EDA_ANGLE defaultLayerAngle = ANGLE_90;
1857
1858 if( aPad->GetShape( aLayer ) == PAD_SHAPE::CIRCLE ||
1859 ( aPad->GetShape( aLayer ) == PAD_SHAPE::CUSTOM
1860 && aPad->GetAnchorPadShape( aLayer ) == PAD_SHAPE::CIRCLE ) )
1861 {
1862 defaultLayerAngle = ANGLE_45;
1863 }
1864
1865 EDA_ANGLE layerSpokeAngle = padstack.ThermalSpokeAngle( aLayer );
1866
1867 if( layerSpokeAngle != defaultLayerAngle )
1868 {
1869 m_out->Print( "(thermal_bridge_angle %s)",
1870 EDA_UNIT_UTILS::FormatAngle( layerSpokeAngle ).c_str() );
1871 }
1872
1873 if( padstack.ThermalGap( aLayer ).has_value() )
1874 {
1875 m_out->Print( "(thermal_gap %s)",
1876 formatInternalUnits( *padstack.ThermalGap( aLayer ) ).c_str() );
1877 }
1878
1879 if( padstack.ThermalSpokeWidth( aLayer ).has_value() )
1880 {
1881 m_out->Print( "(thermal_bridge_width %s)",
1882 formatInternalUnits( *padstack.ThermalSpokeWidth( aLayer ) ).c_str() );
1883 }
1884
1885 if( padstack.Clearance( aLayer ).has_value() )
1886 {
1887 m_out->Print( "(clearance %s)",
1888 formatInternalUnits( *padstack.Clearance( aLayer ) ).c_str() );
1889 }
1890
1891 if( padstack.ZoneConnection( aLayer ).has_value() )
1892 {
1893 m_out->Print( "(zone_connect %d)",
1894 static_cast<int>( *padstack.ZoneConnection( aLayer ) ) );
1895 }
1896 };
1897
1898
1899 if( aPad->Padstack().Mode() != PADSTACK::MODE::NORMAL )
1900 {
1902 {
1903 m_out->Print( "(padstack (mode front_inner_back)" );
1904
1905 m_out->Print( "(layer \"Inner\"" );
1906 formatPadLayer( PADSTACK::INNER_LAYERS );
1907 m_out->Print( ")" );
1908 m_out->Print( "(layer \"B.Cu\"" );
1909 formatPadLayer( B_Cu );
1910 m_out->Print( ")" );
1911 }
1912 else
1913 {
1914 m_out->Print( "(padstack (mode custom)" );
1915
1916 int layerCount = board ? board->GetCopperLayerCount() : MAX_CU_LAYERS;
1917
1918 for( PCB_LAYER_ID layer : LAYER_RANGE( F_Cu, B_Cu, layerCount ) )
1919 {
1920 if( layer == F_Cu )
1921 continue;
1922
1923 m_out->Print( "(layer %s", m_out->Quotew( LSET::Name( layer ) ).c_str() );
1924 formatPadLayer( layer );
1925 m_out->Print( ")" );
1926 }
1927 }
1928
1929 m_out->Print( ")" );
1930 }
1931
1932 m_out->Print( ")" );
1933}
1934
1935
1936void PCB_IO_KICAD_SEXPR::formatTenting( const PADSTACK& aPadstack ) const
1937{
1938 std::optional<bool> front = aPadstack.FrontOuterLayers().has_solder_mask;
1939 std::optional<bool> back = aPadstack.BackOuterLayers().has_solder_mask;
1940
1941 if( front.has_value() || back.has_value() )
1942 {
1943 if( front.value_or( false ) || back.value_or( false ) )
1944 {
1945 m_out->Print( "(tenting %s %s)",
1946 front.value_or( false ) ? "front" : "",
1947 back.value_or( false ) ? "back" : "" );
1948 }
1949 else
1950 {
1951 m_out->Print( "(tenting none)" );
1952 }
1953 }
1954}
1955
1956
1957void PCB_IO_KICAD_SEXPR::format( const PCB_TEXT* aText ) const
1958{
1959 FOOTPRINT* parentFP = aText->GetParentFootprint();
1960 std::string prefix;
1961 std::string type;
1962 VECTOR2I pos = aText->GetTextPos();
1963 const PCB_FIELD* field = dynamic_cast<const PCB_FIELD*>( aText );
1964
1965 // Always format dimension text as gr_text
1966 if( dynamic_cast<const PCB_DIMENSION_BASE*>( aText ) )
1967 parentFP = nullptr;
1968
1969 if( parentFP )
1970 {
1971 prefix = "fp";
1972 type = "user";
1973
1974 pos -= parentFP->GetPosition();
1975 RotatePoint( pos, -parentFP->GetOrientation() );
1976 }
1977 else
1978 {
1979 prefix = "gr";
1980 }
1981
1982 if( !field )
1983 {
1984 m_out->Print( "(%s_text %s %s",
1985 prefix.c_str(),
1986 type.c_str(),
1987 m_out->Quotew( aText->GetText() ).c_str() );
1988
1989 if( aText->IsLocked() )
1990 KICAD_FORMAT::FormatBool( m_out, "locked", true );
1991 }
1992
1993 m_out->Print( "(at %s %s)",
1994 formatInternalUnits( pos ).c_str(),
1995 EDA_UNIT_UTILS::FormatAngle( aText->GetTextAngle() ).c_str() );
1996
1997 if( parentFP && !aText->IsKeepUpright() )
1998 KICAD_FORMAT::FormatBool( m_out, "unlocked", true );
1999
2000 formatLayer( aText->GetLayer(), aText->IsKnockout() );
2001
2002 if( field && !field->IsVisible() )
2003 KICAD_FORMAT::FormatBool( m_out, "hide", true );
2004
2006
2007 // Currently, texts have no specific color and no hyperlink.
2008 // so ensure they are never written in kicad_pcb file
2009 int ctl_flags = CTL_OMIT_COLOR | CTL_OMIT_HYPERLINK;
2010
2011 aText->EDA_TEXT::Format( m_out, ctl_flags );
2012
2013 if( aText->GetFont() && aText->GetFont()->IsOutline() )
2014 formatRenderCache( aText );
2015
2016 if( !field )
2017 m_out->Print( ")" );
2018}
2019
2020
2021void PCB_IO_KICAD_SEXPR::format( const PCB_TEXTBOX* aTextBox ) const
2022{
2023 FOOTPRINT* parentFP = aTextBox->GetParentFootprint();
2024
2025 m_out->Print( "(%s %s",
2026 aTextBox->Type() == PCB_TABLECELL_T ? "table_cell"
2027 : parentFP ? "fp_text_box"
2028 : "gr_text_box",
2029 m_out->Quotew( aTextBox->GetText() ).c_str() );
2030
2031 if( aTextBox->IsLocked() )
2032 KICAD_FORMAT::FormatBool( m_out, "locked", true );
2033
2034 if( aTextBox->GetShape() == SHAPE_T::RECTANGLE )
2035 {
2036 m_out->Print( "(start %s) (end %s)",
2037 formatInternalUnits( aTextBox->GetStart(), parentFP ).c_str(),
2038 formatInternalUnits( aTextBox->GetEnd(), parentFP ).c_str() );
2039 }
2040 else if( aTextBox->GetShape() == SHAPE_T::POLY )
2041 {
2042 const SHAPE_POLY_SET& poly = aTextBox->GetPolyShape();
2043 const SHAPE_LINE_CHAIN& outline = poly.Outline( 0 );
2044
2045 formatPolyPts( outline, parentFP );
2046 }
2047 else
2048 {
2049 UNIMPLEMENTED_FOR( aTextBox->SHAPE_T_asString() );
2050 }
2051
2052 m_out->Print( "(margins %s %s %s %s)",
2053 formatInternalUnits( aTextBox->GetMarginLeft() ).c_str(),
2054 formatInternalUnits( aTextBox->GetMarginTop() ).c_str(),
2055 formatInternalUnits( aTextBox->GetMarginRight() ).c_str(),
2056 formatInternalUnits( aTextBox->GetMarginBottom() ).c_str() );
2057
2058 if( const PCB_TABLECELL* cell = dynamic_cast<const PCB_TABLECELL*>( aTextBox ) )
2059 m_out->Print( "(span %d %d)", cell->GetColSpan(), cell->GetRowSpan() );
2060
2061 EDA_ANGLE angle = aTextBox->GetTextAngle();
2062
2063 if( parentFP )
2064 {
2065 angle -= parentFP->GetOrientation();
2066 angle.Normalize720();
2067 }
2068
2069 if( !angle.IsZero() )
2070 m_out->Print( "(angle %s)", EDA_UNIT_UTILS::FormatAngle( angle ).c_str() );
2071
2072 formatLayer( aTextBox->GetLayer() );
2073
2075
2076 aTextBox->EDA_TEXT::Format( m_out, 0 );
2077
2078 if( aTextBox->Type() != PCB_TABLECELL_T )
2079 {
2080 KICAD_FORMAT::FormatBool( m_out, "border", aTextBox->IsBorderEnabled() );
2081 aTextBox->GetStroke().Format( m_out, pcbIUScale );
2082 }
2083
2084 if( aTextBox->GetFont() && aTextBox->GetFont()->IsOutline() )
2085 formatRenderCache( aTextBox );
2086
2087 m_out->Print( ")" );
2088}
2089
2090
2091void PCB_IO_KICAD_SEXPR::format( const PCB_TABLE* aTable ) const
2092{
2093 wxCHECK_RET( aTable != nullptr && m_out != nullptr, "" );
2094
2095 m_out->Print( "(table (column_count %d)", aTable->GetColCount() );
2096
2097 if( aTable->IsLocked() )
2098 KICAD_FORMAT::FormatBool( m_out, "locked", true );
2099
2100 formatLayer( aTable->GetLayer() );
2101
2102 m_out->Print( "(border" );
2103 KICAD_FORMAT::FormatBool( m_out, "external", aTable->StrokeExternal() );
2104 KICAD_FORMAT::FormatBool( m_out, "header", aTable->StrokeHeader() );
2105
2106 if( aTable->StrokeExternal() || aTable->StrokeHeader() )
2107 aTable->GetBorderStroke().Format( m_out, pcbIUScale );
2108
2109 m_out->Print( ")" ); // Close `border` token.
2110
2111 m_out->Print( "(separators" );
2112 KICAD_FORMAT::FormatBool( m_out, "rows", aTable->StrokeRows() );
2113 KICAD_FORMAT::FormatBool( m_out, "cols", aTable->StrokeColumns() );
2114
2115 if( aTable->StrokeRows() || aTable->StrokeColumns() )
2117
2118 m_out->Print( ")" ); // Close `separators` token.
2119
2120 m_out->Print( "(column_widths" );
2121
2122 for( int col = 0; col < aTable->GetColCount(); ++col )
2123 m_out->Print( " %s", formatInternalUnits( aTable->GetColWidth( col ) ).c_str() );
2124
2125 m_out->Print( ")" );
2126
2127 m_out->Print( "(row_heights" );
2128
2129 for( int row = 0; row < aTable->GetRowCount(); ++row )
2130 m_out->Print( " %s", formatInternalUnits( aTable->GetRowHeight( row ) ).c_str() );
2131
2132 m_out->Print( ")" );
2133
2134 m_out->Print( "(cells" );
2135
2136 for( PCB_TABLECELL* cell : aTable->GetCells() )
2137 format( static_cast<PCB_TEXTBOX*>( cell ) );
2138
2139 m_out->Print( ")" ); // Close `cells` token.
2140 m_out->Print( ")" ); // Close `table` token.
2141}
2142
2143
2144void PCB_IO_KICAD_SEXPR::format( const PCB_GROUP* aGroup ) const
2145{
2146 // Don't write empty groups
2147 if( aGroup->GetItems().empty() )
2148 return;
2149
2150 m_out->Print( "(group %s", m_out->Quotew( aGroup->GetName() ).c_str() );
2151
2153
2154 if( aGroup->IsLocked() )
2155 KICAD_FORMAT::FormatBool( m_out, "locked", true );
2156
2157 wxArrayString memberIds;
2158
2159 for( BOARD_ITEM* member : aGroup->GetItems() )
2160 memberIds.Add( member->m_Uuid.AsString() );
2161
2162 memberIds.Sort();
2163
2164 m_out->Print( "(members" );
2165
2166 for( const wxString& memberId : memberIds )
2167 m_out->Print( " %s", m_out->Quotew( memberId ).c_str() );
2168
2169 m_out->Print( ")" ); // Close `members` token.
2170 m_out->Print( ")" ); // Close `group` token.
2171}
2172
2173
2174void PCB_IO_KICAD_SEXPR::format( const PCB_GENERATOR* aGenerator ) const
2175{
2176 // Some conditions appear to still be creating ghost tuning patterns. Don't save them.
2177 if( aGenerator->GetGeneratorType() == wxT( "tuning_pattern" )
2178 && aGenerator->GetItems().empty() )
2179 {
2180 return;
2181 }
2182
2183 m_out->Print( "(generated" );
2184
2185 KICAD_FORMAT::FormatUuid( m_out, aGenerator->m_Uuid );
2186
2187 m_out->Print( "(type %s) (name %s) (layer %s)",
2188 TO_UTF8( aGenerator->GetGeneratorType() ),
2189 m_out->Quotew( aGenerator->GetName() ).c_str(),
2190 m_out->Quotew( LSET::Name( aGenerator->GetLayer() ) ).c_str() );
2191
2192 if( aGenerator->IsLocked() )
2193 KICAD_FORMAT::FormatBool( m_out, "locked", true );
2194
2195 for( const auto& [key, value] : aGenerator->GetProperties() )
2196 {
2197 if( value.CheckType<double>() || value.CheckType<int>() || value.CheckType<long>()
2198 || value.CheckType<long long>() )
2199 {
2200 double val;
2201
2202 if( !value.GetAs( &val ) )
2203 continue;
2204
2205 std::string buf = fmt::format( "{:.10g}", val );
2206
2207 // Don't quote numbers
2208 m_out->Print( "(%s %s)", key.c_str(), buf.c_str() );
2209 }
2210 else if( value.CheckType<bool>() )
2211 {
2212 bool val;
2213 value.GetAs( &val );
2214
2215 KICAD_FORMAT::FormatBool( m_out, key, val );
2216 }
2217 else if( value.CheckType<VECTOR2I>() )
2218 {
2219 VECTOR2I val;
2220 value.GetAs( &val );
2221
2222 m_out->Print( "(%s (xy %s))",
2223 key.c_str(),
2224 formatInternalUnits( val ).c_str() );
2225 }
2226 else if( value.CheckType<SHAPE_LINE_CHAIN>() )
2227 {
2228 SHAPE_LINE_CHAIN val;
2229 value.GetAs( &val );
2230
2231 m_out->Print( "(%s ", key.c_str() );
2232 formatPolyPts( val );
2233 m_out->Print( ")" );
2234 }
2235 else
2236 {
2237 wxString val;
2238
2239 if( value.CheckType<wxString>() )
2240 {
2241 value.GetAs( &val );
2242 }
2243 else if( value.CheckType<std::string>() )
2244 {
2245 std::string str;
2246 value.GetAs( &str );
2247
2248 val = wxString::FromUTF8( str );
2249 }
2250
2251 m_out->Print( "(%s %s)", key.c_str(), m_out->Quotew( val ).c_str() );
2252 }
2253 }
2254
2255 wxArrayString memberIds;
2256
2257 for( BOARD_ITEM* member : aGenerator->GetItems() )
2258 memberIds.Add( member->m_Uuid.AsString() );
2259
2260 memberIds.Sort();
2261
2262 m_out->Print( "(members" );
2263
2264 for( const wxString& memberId : memberIds )
2265 m_out->Print( " %s", m_out->Quotew( memberId ).c_str() );
2266
2267 m_out->Print( ")" ); // Close `members` token.
2268 m_out->Print( ")" ); // Close `generated` token.
2269}
2270
2271
2272void PCB_IO_KICAD_SEXPR::format( const PCB_TRACK* aTrack ) const
2273{
2274 if( aTrack->Type() == PCB_VIA_T )
2275 {
2276 PCB_LAYER_ID layer1, layer2;
2277
2278 const PCB_VIA* via = static_cast<const PCB_VIA*>( aTrack );
2279 const BOARD* board = via->GetBoard();
2280
2281 wxCHECK_RET( board != nullptr, wxT( "Via has no parent." ) );
2282
2283 m_out->Print( "(via" );
2284
2285 via->LayerPair( &layer1, &layer2 );
2286
2287 switch( via->GetViaType() )
2288 {
2289 case VIATYPE::THROUGH: // Default shape not saved.
2290 break;
2291
2292 case VIATYPE::BLIND_BURIED:
2293 m_out->Print( " blind " );
2294 break;
2295
2296 case VIATYPE::MICROVIA:
2297 m_out->Print( " micro " );
2298 break;
2299
2300 default:
2301 THROW_IO_ERROR( wxString::Format( _( "unknown via type %d" ), via->GetViaType() ) );
2302 }
2303
2304 m_out->Print( "(at %s) (size %s)",
2305 formatInternalUnits( aTrack->GetStart() ).c_str(),
2306 formatInternalUnits( via->GetWidth( F_Cu ) ).c_str() );
2307
2308 // Old boards were using UNDEFINED_DRILL_DIAMETER value in file for via drill when
2309 // via drill was the netclass value.
2310 // recent boards always set the via drill to the actual value, but now we need to
2311 // always store the drill value, because netclass value is not stored in the board file.
2312 // Otherwise the drill value of some (old) vias can be unknown
2313 if( via->GetDrill() != UNDEFINED_DRILL_DIAMETER )
2314 m_out->Print( "(drill %s)", formatInternalUnits( via->GetDrill() ).c_str() );
2315 else
2316 m_out->Print( "(drill %s)", formatInternalUnits( via->GetDrillValue() ).c_str() );
2317
2318 m_out->Print( "(layers %s %s)",
2319 m_out->Quotew( LSET::Name( layer1 ) ).c_str(),
2320 m_out->Quotew( LSET::Name( layer2 ) ).c_str() );
2321
2322 switch( via->Padstack().UnconnectedLayerMode() )
2323 {
2325 KICAD_FORMAT::FormatBool( m_out, "remove_unused_layers", true );
2326 KICAD_FORMAT::FormatBool( m_out, "keep_end_layers", false );
2327 break;
2328
2330 KICAD_FORMAT::FormatBool( m_out, "remove_unused_layers", true );
2331 KICAD_FORMAT::FormatBool( m_out, "keep_end_layers", true );
2332 break;
2333
2335 break;
2336 }
2337
2338 if( via->IsLocked() )
2339 KICAD_FORMAT::FormatBool( m_out, "locked", true );
2340
2341 if( via->GetIsFree() )
2342 KICAD_FORMAT::FormatBool( m_out, "free", true );
2343
2344 if( via->GetRemoveUnconnected() )
2345 {
2346 m_out->Print( "(zone_layer_connections" );
2347
2348 for( PCB_LAYER_ID layer : board->GetEnabledLayers().CuStack() )
2349 {
2350 if( via->GetZoneLayerOverride( layer ) == ZLO_FORCE_FLASHED )
2351 m_out->Print( " %s", m_out->Quotew( LSET::Name( layer ) ).c_str() );
2352 }
2353
2354 m_out->Print( ")" );
2355 }
2356
2357 const PADSTACK& padstack = via->Padstack();
2358
2359 formatTenting( padstack );
2360
2361 if( padstack.Mode() != PADSTACK::MODE::NORMAL )
2362 {
2363 m_out->Print( "(padstack" );
2364
2365 if( padstack.Mode() == PADSTACK::MODE::FRONT_INNER_BACK )
2366 {
2367 m_out->Print( "(mode front_inner_back)" );
2368
2369 m_out->Print( "(layer \"Inner\"" );
2370 m_out->Print( "(size %s)",
2371 formatInternalUnits( padstack.Size( PADSTACK::INNER_LAYERS ).x ).c_str() );
2372 m_out->Print( ")" );
2373 m_out->Print( "(layer \"B.Cu\"" );
2374 m_out->Print( "(size %s)",
2375 formatInternalUnits( padstack.Size( B_Cu ).x ).c_str() );
2376 m_out->Print( ")" );
2377 }
2378 else
2379 {
2380 m_out->Print( "(mode custom)" );
2381
2382 for( PCB_LAYER_ID layer : LAYER_RANGE( F_Cu, B_Cu, board->GetCopperLayerCount() ) )
2383 {
2384 if( layer == F_Cu )
2385 continue;
2386
2387 m_out->Print( "(layer %s", m_out->Quotew( LSET::Name( layer ) ).c_str() );
2388 m_out->Print( "(size %s)",
2389 formatInternalUnits( padstack.Size( layer ).x ).c_str() );
2390 m_out->Print( ")" );
2391 }
2392 }
2393
2394 m_out->Print( ")" );
2395 }
2396
2397 if( !isDefaultTeardropParameters( via->GetTeardropParams() ) )
2398 formatTeardropParameters( via->GetTeardropParams() );
2399 }
2400 else
2401 {
2402 if( aTrack->Type() == PCB_ARC_T )
2403 {
2404 const PCB_ARC* arc = static_cast<const PCB_ARC*>( aTrack );
2405
2406 m_out->Print( "(arc (start %s) (mid %s) (end %s) (width %s)",
2407 formatInternalUnits( arc->GetStart() ).c_str(),
2408 formatInternalUnits( arc->GetMid() ).c_str(),
2409 formatInternalUnits( arc->GetEnd() ).c_str(),
2410 formatInternalUnits( arc->GetWidth() ).c_str() );
2411 }
2412 else
2413 {
2414 m_out->Print( "(segment (start %s) (end %s) (width %s)",
2415 formatInternalUnits( aTrack->GetStart() ).c_str(),
2416 formatInternalUnits( aTrack->GetEnd() ).c_str(),
2417 formatInternalUnits( aTrack->GetWidth() ).c_str() );
2418 }
2419
2420 if( aTrack->IsLocked() )
2421 KICAD_FORMAT::FormatBool( m_out, "locked", true );
2422
2423 if( aTrack->GetLayerSet().count() > 1 )
2424 formatLayers( aTrack->GetLayerSet(), false /* enumerate layers */ );
2425 else
2426 formatLayer( aTrack->GetLayer() );
2427
2428 if( aTrack->HasSolderMask()
2429 && aTrack->GetLocalSolderMaskMargin().has_value()
2430 && ( aTrack->IsOnLayer( F_Cu ) || aTrack->IsOnLayer( B_Cu ) ) )
2431 {
2432 m_out->Print( "(solder_mask_margin %s)",
2433 formatInternalUnits( aTrack->GetLocalSolderMaskMargin().value() ).c_str() );
2434 }
2435 }
2436
2437 m_out->Print( "(net %d)", m_mapping->Translate( aTrack->GetNetCode() ) );
2438
2440 m_out->Print( ")" );
2441}
2442
2443
2444void PCB_IO_KICAD_SEXPR::format( const ZONE* aZone ) const
2445{
2446 // Save the NET info.
2447 // For keepout and non copper zones, net code and net name are irrelevant
2448 // so be sure a dummy value is stored, just for ZONE compatibility
2449 // (perhaps netcode and netname should be not stored)
2450
2451 bool has_no_net = aZone->GetIsRuleArea() || !aZone->IsOnCopperLayer();
2452
2453 m_out->Print( "(zone (net %d) (net_name %s)",
2454 has_no_net ? 0 : m_mapping->Translate( aZone->GetNetCode() ),
2455 m_out->Quotew( has_no_net ? wxString( wxT("") ) : aZone->GetNetname() ).c_str() );
2456
2457 if( aZone->IsLocked() )
2458 KICAD_FORMAT::FormatBool( m_out, "locked", true );
2459
2460 // If a zone exists on multiple layers, format accordingly
2461 LSET layers = aZone->GetLayerSet();
2462
2463 if( aZone->GetBoard() )
2464 layers &= aZone->GetBoard()->GetEnabledLayers();
2465
2466 // Always enumerate every layer for a zone on a copper layer
2467 if( layers.count() > 1 )
2468 formatLayers( layers, aZone->IsOnCopperLayer() );
2469 else
2470 formatLayer( aZone->GetFirstLayer() );
2471
2473
2474 if( !aZone->GetZoneName().empty() )
2475 m_out->Print( "(name %s)", m_out->Quotew( aZone->GetZoneName() ).c_str() );
2476
2477 // Save the outline aux info
2478 std::string hatch;
2479
2480 switch( aZone->GetHatchStyle() )
2481 {
2482 default:
2483 case ZONE_BORDER_DISPLAY_STYLE::NO_HATCH: hatch = "none"; break;
2484 case ZONE_BORDER_DISPLAY_STYLE::DIAGONAL_EDGE: hatch = "edge"; break;
2485 case ZONE_BORDER_DISPLAY_STYLE::DIAGONAL_FULL: hatch = "full"; break;
2486 }
2487
2488 m_out->Print( "(hatch %s %s)", hatch.c_str(),
2489 formatInternalUnits( aZone->GetBorderHatchPitch() ).c_str() );
2490
2491
2492
2493 if( aZone->GetAssignedPriority() > 0 )
2494 m_out->Print( "(priority %d)", aZone->GetAssignedPriority() );
2495
2496 // Add teardrop keywords in file: (attr (teardrop (type xxx)))where xxx is the teardrop type
2497 if( aZone->IsTeardropArea() )
2498 {
2499 m_out->Print( "(attr (teardrop (type %s)))",
2500 aZone->GetTeardropAreaType() == TEARDROP_TYPE::TD_VIAPAD
2501 ? "padvia"
2502 : "track_end" );
2503 }
2504
2505 m_out->Print( "(connect_pads" );
2506
2507 switch( aZone->GetPadConnection() )
2508 {
2509 default:
2510 case ZONE_CONNECTION::THERMAL: // Default option not saved or loaded.
2511 break;
2512
2513 case ZONE_CONNECTION::THT_THERMAL:
2514 m_out->Print( " thru_hole_only" );
2515 break;
2516
2517 case ZONE_CONNECTION::FULL:
2518 m_out->Print( " yes" );
2519 break;
2520
2521 case ZONE_CONNECTION::NONE:
2522 m_out->Print( " no" );
2523 break;
2524 }
2525
2526 m_out->Print( "(clearance %s)",
2527 formatInternalUnits( aZone->GetLocalClearance().value() ).c_str() );
2528
2529 m_out->Print( ")" );
2530
2531 m_out->Print( "(min_thickness %s)",
2532 formatInternalUnits( aZone->GetMinThickness() ).c_str() );
2533
2534 // We continue to write this for 3rd-party parsers, but we no longer read it (as of V7).
2535 m_out->Print( "(filled_areas_thickness no)" );
2536
2537 if( aZone->GetIsRuleArea() )
2538 {
2539 // Keepout settings
2540 m_out->Print( "(keepout (tracks %s) (vias %s) (pads %s) (copperpour %s) (footprints %s))",
2541 aZone->GetDoNotAllowTracks() ? "not_allowed" : "allowed",
2542 aZone->GetDoNotAllowVias() ? "not_allowed" : "allowed",
2543 aZone->GetDoNotAllowPads() ? "not_allowed" : "allowed",
2544 aZone->GetDoNotAllowCopperPour() ? "not_allowed" : "allowed",
2545 aZone->GetDoNotAllowFootprints() ? "not_allowed" : "allowed" );
2546
2547 // Multichannel settings
2548 m_out->Print( "(placement" );
2550
2551 switch( aZone->GetRuleAreaPlacementSourceType() )
2552 {
2553 case RULE_AREA_PLACEMENT_SOURCE_TYPE::SHEETNAME:
2554 m_out->Print( "(sheetname %s)",
2555 m_out->Quotew( aZone->GetRuleAreaPlacementSource() ).c_str() );
2556 break;
2557 case RULE_AREA_PLACEMENT_SOURCE_TYPE::COMPONENT_CLASS:
2558 m_out->Print( "(component_class %s)",
2559 m_out->Quotew( aZone->GetRuleAreaPlacementSource() ).c_str() );
2560 break;
2561 }
2562
2563 m_out->Print( ")" );
2564 }
2565
2566 m_out->Print( "(fill" );
2567
2568 // Default is not filled.
2569 if( aZone->IsFilled() )
2570 m_out->Print( " yes" );
2571
2572 // Default is polygon filled.
2573 if( aZone->GetFillMode() == ZONE_FILL_MODE::HATCH_PATTERN )
2574 m_out->Print( "(mode hatch)" );
2575
2576 m_out->Print( "(thermal_gap %s) (thermal_bridge_width %s)",
2577 formatInternalUnits( aZone->GetThermalReliefGap() ).c_str(),
2578 formatInternalUnits( aZone->GetThermalReliefSpokeWidth() ).c_str() );
2579
2581 {
2582 switch( aZone->GetCornerSmoothingType() )
2583 {
2585 m_out->Print( "(smoothing chamfer)" );
2586 break;
2587
2589 m_out->Print( "(smoothing fillet)" );
2590 break;
2591
2592 default:
2593 THROW_IO_ERROR( wxString::Format( _( "unknown zone corner smoothing type %d" ),
2594 aZone->GetCornerSmoothingType() ) );
2595 }
2596
2597 if( aZone->GetCornerRadius() != 0 )
2598 m_out->Print( "(radius %s)", formatInternalUnits( aZone->GetCornerRadius() ).c_str() );
2599 }
2600
2601 if( aZone->GetIslandRemovalMode() != ISLAND_REMOVAL_MODE::ALWAYS )
2602 {
2603 m_out->Print( "(island_removal_mode %d) (island_area_min %s)",
2604 static_cast<int>( aZone->GetIslandRemovalMode() ),
2606 }
2607
2608 if( aZone->GetFillMode() == ZONE_FILL_MODE::HATCH_PATTERN )
2609 {
2610 m_out->Print( "(hatch_thickness %s) (hatch_gap %s) (hatch_orientation %s)",
2611 formatInternalUnits( aZone->GetHatchThickness() ).c_str(),
2612 formatInternalUnits( aZone->GetHatchGap() ).c_str(),
2613 FormatDouble2Str( aZone->GetHatchOrientation().AsDegrees() ).c_str() );
2614
2615 if( aZone->GetHatchSmoothingLevel() > 0 )
2616 {
2617 m_out->Print( "(hatch_smoothing_level %d) (hatch_smoothing_value %s)",
2618 aZone->GetHatchSmoothingLevel(),
2619 FormatDouble2Str( aZone->GetHatchSmoothingValue() ).c_str() );
2620 }
2621
2622 m_out->Print( "(hatch_border_algorithm %s) (hatch_min_hole_area %s)",
2623 aZone->GetHatchBorderAlgorithm() ? "hatch_thickness" : "min_thickness",
2624 FormatDouble2Str( aZone->GetHatchHoleMinArea() ).c_str() );
2625 }
2626
2627 m_out->Print( ")" );
2628
2629 if( aZone->GetNumCorners() )
2630 {
2631 SHAPE_POLY_SET::POLYGON poly = aZone->Outline()->Polygon(0);
2632
2633 for( const SHAPE_LINE_CHAIN& chain : poly )
2634 {
2635 m_out->Print( "(polygon" );
2637 m_out->Print( ")" );
2638 }
2639 }
2640
2641 // Save the PolysList (filled areas)
2642 for( PCB_LAYER_ID layer : aZone->GetLayerSet().Seq() )
2643 {
2644 const std::shared_ptr<SHAPE_POLY_SET>& fv = aZone->GetFilledPolysList( layer );
2645
2646 for( int ii = 0; ii < fv->OutlineCount(); ++ii )
2647 {
2648 m_out->Print( "(filled_polygon" );
2649 m_out->Print( "(layer %s)", m_out->Quotew( LSET::Name( layer ) ).c_str() );
2650
2651 if( aZone->IsIsland( layer, ii ) )
2652 m_out->Print( "(island)" );
2653
2654 const SHAPE_LINE_CHAIN& chain = fv->COutline( ii );
2655
2657 m_out->Print( ")" );
2658 }
2659 }
2660
2661 m_out->Print( ")" );
2662}
2663
2664
2665PCB_IO_KICAD_SEXPR::PCB_IO_KICAD_SEXPR( int aControlFlags ) : PCB_IO( wxS( "KiCad" ) ),
2666 m_cache( nullptr ),
2667 m_ctl( aControlFlags ),
2668 m_mapping( new NETINFO_MAPPING() )
2669{
2670 init( nullptr );
2671 m_out = &m_sf;
2672}
2673
2674
2676{
2677 delete m_cache;
2678 delete m_mapping;
2679}
2680
2681
2682BOARD* PCB_IO_KICAD_SEXPR::LoadBoard( const wxString& aFileName, BOARD* aAppendToMe,
2683 const std::map<std::string, UTF8>* aProperties, PROJECT* aProject )
2684{
2685 FILE_LINE_READER reader( aFileName );
2686
2687 unsigned lineCount = 0;
2688
2690
2691 if( m_progressReporter )
2692 {
2693 m_progressReporter->Report( wxString::Format( _( "Loading %s..." ), aFileName ) );
2694
2696 THROW_IO_ERROR( _( "Open cancelled by user." ) );
2697
2698 while( reader.ReadLine() )
2699 lineCount++;
2700
2701 reader.Rewind();
2702 }
2703
2704 BOARD* board = DoLoad( reader, aAppendToMe, aProperties, m_progressReporter, lineCount );
2705
2706 // Give the filename to the board if it's new
2707 if( !aAppendToMe )
2708 board->SetFileName( aFileName );
2709
2710 return board;
2711}
2712
2713
2714BOARD* PCB_IO_KICAD_SEXPR::DoLoad( LINE_READER& aReader, BOARD* aAppendToMe, const std::map<std::string, UTF8>* aProperties,
2715 PROGRESS_REPORTER* aProgressReporter, unsigned aLineCount)
2716{
2717 init( aProperties );
2718
2719 PCB_IO_KICAD_SEXPR_PARSER parser( &aReader, aAppendToMe, m_queryUserCallback, aProgressReporter, aLineCount );
2720 BOARD* board;
2721
2722 try
2723 {
2724 board = dynamic_cast<BOARD*>( parser.Parse() );
2725 }
2726 catch( const FUTURE_FORMAT_ERROR& )
2727 {
2728 // Don't wrap a FUTURE_FORMAT_ERROR in another
2729 throw;
2730 }
2731 catch( const PARSE_ERROR& parse_error )
2732 {
2733 if( parser.IsTooRecent() )
2734 throw FUTURE_FORMAT_ERROR( parse_error, parser.GetRequiredVersion() );
2735 else
2736 throw;
2737 }
2738
2739 if( !board )
2740 {
2741 // The parser loaded something that was valid, but wasn't a board.
2742 THROW_PARSE_ERROR( _( "This file does not contain a PCB." ), parser.CurSource(),
2743 parser.CurLine(), parser.CurLineNumber(), parser.CurOffset() );
2744 }
2745
2746 return board;
2747}
2748
2749
2750void PCB_IO_KICAD_SEXPR::init( const std::map<std::string, UTF8>* aProperties )
2751{
2752 m_board = nullptr;
2753 m_reader = nullptr;
2754 m_props = aProperties;
2755}
2756
2757
2758void PCB_IO_KICAD_SEXPR::validateCache( const wxString& aLibraryPath, bool checkModified )
2759{
2761
2762 if( !m_cache || !m_cache->IsPath( aLibraryPath ) || ( checkModified && m_cache->IsModified() ) )
2763 {
2764 // a spectacular episode in memory management:
2765 delete m_cache;
2766 m_cache = new FP_CACHE( this, aLibraryPath );
2767 m_cache->Load();
2768 }
2769}
2770
2771
2772void PCB_IO_KICAD_SEXPR::FootprintEnumerate( wxArrayString& aFootprintNames, const wxString& aLibPath,
2773 bool aBestEfforts, const std::map<std::string, UTF8>* aProperties )
2774{
2775 LOCALE_IO toggle; // toggles on, then off, the C locale.
2776 wxDir dir( aLibPath );
2777 wxString errorMsg;
2778
2779 init( aProperties );
2780
2781 try
2782 {
2783 validateCache( aLibPath );
2784 }
2785 catch( const IO_ERROR& ioe )
2786 {
2787 errorMsg = ioe.What();
2788 }
2789
2790 // Some of the files may have been parsed correctly so we want to add the valid files to
2791 // the library.
2792
2793 for( const auto& footprint : m_cache->GetFootprints() )
2794 aFootprintNames.Add( footprint.first );
2795
2796 if( !errorMsg.IsEmpty() && !aBestEfforts )
2797 THROW_IO_ERROR( errorMsg );
2798}
2799
2800
2801const FOOTPRINT* PCB_IO_KICAD_SEXPR::getFootprint( const wxString& aLibraryPath,
2802 const wxString& aFootprintName,
2803 const std::map<std::string, UTF8>* aProperties,
2804 bool checkModified )
2805{
2806 LOCALE_IO toggle; // toggles on, then off, the C locale.
2807
2808 init( aProperties );
2809
2810 try
2811 {
2812 validateCache( aLibraryPath, checkModified );
2813 }
2814 catch( const IO_ERROR& )
2815 {
2816 // do nothing with the error
2817 }
2818
2819 auto it = m_cache->GetFootprints().find( aFootprintName );
2820
2821 if( it == m_cache->GetFootprints().end() )
2822 return nullptr;
2823
2824 return it->second->GetFootprint().get();
2825}
2826
2827
2828const FOOTPRINT* PCB_IO_KICAD_SEXPR::GetEnumeratedFootprint( const wxString& aLibraryPath,
2829 const wxString& aFootprintName,
2830 const std::map<std::string, UTF8>* aProperties )
2831{
2832 return getFootprint( aLibraryPath, aFootprintName, aProperties, false );
2833}
2834
2835
2836bool PCB_IO_KICAD_SEXPR::FootprintExists( const wxString& aLibraryPath, const wxString& aFootprintName,
2837 const std::map<std::string, UTF8>* aProperties )
2838{
2839 // Note: checking the cache sounds like a good idea, but won't catch files which differ
2840 // only in case.
2841 //
2842 // Since this goes out to the native filesystem, we get platform differences (ie: MSW's
2843 // case-insensitive filesystem) handled "for free".
2844 // Warning: footprint names frequently contain a point. So be careful when initializing
2845 // wxFileName, and use a CTOR with extension specified
2846 wxFileName footprintFile( aLibraryPath, aFootprintName, FILEEXT::KiCadFootprintFileExtension );
2847
2848 return footprintFile.Exists();
2849}
2850
2851
2852FOOTPRINT* PCB_IO_KICAD_SEXPR::ImportFootprint( const wxString& aFootprintPath, wxString& aFootprintNameOut,
2853 const std::map<std::string, UTF8>* aProperties )
2854{
2855 wxString fcontents;
2856 wxFFile f( aFootprintPath );
2857
2859
2860 if( !f.IsOpened() )
2861 return nullptr;
2862
2863 f.ReadAll( &fcontents );
2864
2865 aFootprintNameOut = wxFileName( aFootprintPath ).GetName();
2866
2867 return dynamic_cast<FOOTPRINT*>( Parse( fcontents ) );
2868}
2869
2870
2871FOOTPRINT* PCB_IO_KICAD_SEXPR::FootprintLoad( const wxString& aLibraryPath,
2872 const wxString& aFootprintName,
2873 bool aKeepUUID,
2874 const std::map<std::string, UTF8>* aProperties )
2875{
2877
2878 const FOOTPRINT* footprint = getFootprint( aLibraryPath, aFootprintName, aProperties, true );
2879
2880 if( footprint )
2881 {
2882 FOOTPRINT* copy;
2883
2884 if( aKeepUUID )
2885 copy = static_cast<FOOTPRINT*>( footprint->Clone() );
2886 else
2887 copy = static_cast<FOOTPRINT*>( footprint->Duplicate() );
2888
2889 copy->SetParent( nullptr );
2890 return copy;
2891 }
2892
2893 return nullptr;
2894}
2895
2896
2897void PCB_IO_KICAD_SEXPR::FootprintSave( const wxString& aLibraryPath, const FOOTPRINT* aFootprint,
2898 const std::map<std::string, UTF8>* aProperties )
2899{
2900 LOCALE_IO toggle; // toggles on, then off, the C locale.
2901
2902 init( aProperties );
2903
2904 // In this public PLUGIN API function, we can safely assume it was
2905 // called for saving into a library path.
2907
2908 validateCache( aLibraryPath, !aProperties || !aProperties->contains( "skip_cache_validation" ) );
2909
2910 if( !m_cache->IsWritable() )
2911 {
2912 if( !m_cache->Exists() )
2913 {
2914 const wxString msg = wxString::Format( _( "Library '%s' does not exist.\n"
2915 "Would you like to create it?"),
2916 aLibraryPath );
2917
2918 if( !Pgm().IsGUI()
2919 || wxMessageBox( msg, _( "Library Not Found" ), wxYES_NO | wxICON_QUESTION )
2920 != wxYES )
2921 return;
2922
2923 // Save throws its own IO_ERROR on failure, so no need to recreate here
2924 m_cache->Save( nullptr );
2925 }
2926 else
2927 {
2928 wxString msg = wxString::Format( _( "Library '%s' is read only." ), aLibraryPath );
2929 THROW_IO_ERROR( msg );
2930 }
2931 }
2932
2933 wxString footprintName = aFootprint->GetFPID().GetLibItemName();
2934
2935 wxString fpName = aFootprint->GetFPID().GetLibItemName().wx_str();
2936 ReplaceIllegalFileNameChars( fpName, '_' );
2937
2938 // Quietly overwrite footprint and delete footprint file from path for any by same name.
2939 wxFileName fn( aLibraryPath, fpName, FILEEXT::KiCadFootprintFileExtension );
2940
2941 // Write through symlinks, don't replace them
2943
2944 if( !fn.IsOk() )
2945 {
2946 THROW_IO_ERROR( wxString::Format( _( "Footprint file name '%s' is not valid." ),
2947 fn.GetFullPath() ) );
2948 }
2949
2950 if( fn.FileExists() && !fn.IsFileWritable() )
2951 {
2952 THROW_IO_ERROR( wxString::Format( _( "Insufficient permissions to delete '%s'." ),
2953 fn.GetFullPath() ) );
2954 }
2955
2956 wxString fullPath = fn.GetFullPath();
2957 wxString fullName = fn.GetFullName();
2958 auto it = m_cache->GetFootprints().find( footprintName );
2959
2960 if( it != m_cache->GetFootprints().end() )
2961 {
2962 wxLogTrace( traceKicadPcbPlugin, wxT( "Removing footprint file '%s'." ), fullPath );
2963 m_cache->GetFootprints().erase( footprintName );
2964 wxRemoveFile( fullPath );
2965 }
2966
2967 // I need my own copy for the cache
2968 FOOTPRINT* footprint = static_cast<FOOTPRINT*>( aFootprint->Clone() );
2969
2970 // It's orientation should be zero and it should be on the front layer.
2971 footprint->SetOrientation( ANGLE_0 );
2972
2973 if( footprint->GetLayer() != F_Cu )
2974 {
2975 PCBNEW_SETTINGS* cfg = dynamic_cast<PCBNEW_SETTINGS*>( Kiface().KifaceSettings() );
2976
2977 if( cfg )
2978 footprint->Flip( footprint->GetPosition(), cfg->m_FlipDirection );
2979 else
2980 footprint->Flip( footprint->GetPosition(), FLIP_DIRECTION::TOP_BOTTOM );
2981 }
2982
2983 // Detach it from the board and its group
2984 footprint->SetParent( nullptr );
2985 footprint->SetParentGroup( nullptr );
2986
2987 wxLogTrace( traceKicadPcbPlugin, wxT( "Creating s-expr footprint file '%s'." ), fullPath );
2988 m_cache->GetFootprints().insert( footprintName,
2989 new FP_CACHE_ENTRY( footprint,
2990 WX_FILENAME( fn.GetPath(), fullName ) ) );
2991 m_cache->Save( footprint );
2992}
2993
2994
2995void PCB_IO_KICAD_SEXPR::FootprintDelete( const wxString& aLibraryPath, const wxString& aFootprintName,
2996 const std::map<std::string, UTF8>* aProperties )
2997{
2998 LOCALE_IO toggle; // toggles on, then off, the C locale.
2999
3000 init( aProperties );
3001
3002 validateCache( aLibraryPath );
3003
3004 if( !m_cache->IsWritable() )
3005 {
3006 THROW_IO_ERROR( wxString::Format( _( "Library '%s' is read only." ),
3007 aLibraryPath.GetData() ) );
3008 }
3009
3010 m_cache->Remove( aFootprintName );
3011}
3012
3013
3014
3015long long PCB_IO_KICAD_SEXPR::GetLibraryTimestamp( const wxString& aLibraryPath ) const
3016{
3017 return FP_CACHE::GetTimestamp( aLibraryPath );
3018}
3019
3020
3021void PCB_IO_KICAD_SEXPR::CreateLibrary( const wxString& aLibraryPath, const std::map<std::string, UTF8>* aProperties )
3022{
3023 if( wxDir::Exists( aLibraryPath ) )
3024 {
3025 THROW_IO_ERROR( wxString::Format( _( "Cannot overwrite library path '%s'." ),
3026 aLibraryPath.GetData() ) );
3027 }
3028
3029 LOCALE_IO toggle;
3030
3031 init( aProperties );
3032
3033 delete m_cache;
3034 m_cache = new FP_CACHE( this, aLibraryPath );
3035 m_cache->Save();
3036}
3037
3038
3039bool PCB_IO_KICAD_SEXPR::DeleteLibrary( const wxString& aLibraryPath, const std::map<std::string, UTF8>* aProperties )
3040{
3041 wxFileName fn;
3042 fn.SetPath( aLibraryPath );
3043
3044 // Return if there is no library path to delete.
3045 if( !fn.DirExists() )
3046 return false;
3047
3048 if( !fn.IsDirWritable() )
3049 {
3050 THROW_IO_ERROR( wxString::Format( _( "Insufficient permissions to delete folder '%s'." ),
3051 aLibraryPath.GetData() ) );
3052 }
3053
3054 wxDir dir( aLibraryPath );
3055
3056 if( dir.HasSubDirs() )
3057 {
3058 THROW_IO_ERROR( wxString::Format( _( "Library folder '%s' has unexpected sub-folders." ),
3059 aLibraryPath.GetData() ) );
3060 }
3061
3062 // All the footprint files must be deleted before the directory can be deleted.
3063 if( dir.HasFiles() )
3064 {
3065 unsigned i;
3066 wxFileName tmp;
3067 wxArrayString files;
3068
3069 wxDir::GetAllFiles( aLibraryPath, &files );
3070
3071 for( i = 0; i < files.GetCount(); i++ )
3072 {
3073 tmp = files[i];
3074
3075 if( tmp.GetExt() != FILEEXT::KiCadFootprintFileExtension )
3076 {
3077 THROW_IO_ERROR( wxString::Format( _( "Unexpected file '%s' found in library "
3078 "path '%s'." ),
3079 files[i].GetData(),
3080 aLibraryPath.GetData() ) );
3081 }
3082 }
3083
3084 for( i = 0; i < files.GetCount(); i++ )
3085 wxRemoveFile( files[i] );
3086 }
3087
3088 wxLogTrace( traceKicadPcbPlugin, wxT( "Removing footprint library '%s'." ),
3089 aLibraryPath.GetData() );
3090
3091 // Some of the more elaborate wxRemoveFile() crap puts up its own wxLog dialog
3092 // we don't want that. we want bare metal portability with no UI here.
3093 if( !wxRmdir( aLibraryPath ) )
3094 {
3095 THROW_IO_ERROR( wxString::Format( _( "Footprint library '%s' cannot be deleted." ),
3096 aLibraryPath.GetData() ) );
3097 }
3098
3099 // For some reason removing a directory in Windows is not immediately updated. This delay
3100 // prevents an error when attempting to immediately recreate the same directory when over
3101 // writing an existing library.
3102#ifdef __WINDOWS__
3103 wxMilliSleep( 250L );
3104#endif
3105
3106 if( m_cache && !m_cache->IsPath( aLibraryPath ) )
3107 {
3108 delete m_cache;
3109 m_cache = nullptr;
3110 }
3111
3112 return true;
3113}
3114
3115
3116bool PCB_IO_KICAD_SEXPR::IsLibraryWritable( const wxString& aLibraryPath )
3117{
3118 LOCALE_IO toggle;
3119
3120 init( nullptr );
3121
3122 validateCache( aLibraryPath );
3123
3124 return m_cache->IsWritable();
3125}
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:108
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
@ ZLO_FORCE_FLASHED
Definition: board_item.h:68
wxString GetMajorMinorVersion()
Get only the major and minor version in a string major.minor.
bool SaveImageData(wxOutputStream &aOutStream) const
Write the bitmap data to aOutStream.
wxImage * GetImageData()
Definition: bitmap_base.h:68
TEARDROP_PARAMETERS & GetTeardropParams()
Container for design settings for a BOARD object.
int GetBoardThickness() const
The full thickness of the board including copper and masks.
const VECTOR2I & GetGridOrigin()
const VECTOR2I & GetAuxOrigin()
BOARD_STACKUP & GetStackupDescriptor()
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:79
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:239
void SetParentGroup(PCB_GROUP *aGroup)
Definition: board_item.h:89
virtual bool IsKnockout() const
Definition: board_item.h:326
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
Definition: board_item.cpp:47
FOOTPRINT * GetParentFootprint() const
Definition: board_item.cpp:298
VECTOR2I GetFPRelativePosition() const
Definition: board_item.cpp:327
virtual bool IsLocked() const
Definition: board_item.cpp:75
Manage layers needed to make a physical board.
void FormatBoardStackup(OUTPUTFORMATTER *aFormatter, const BOARD *aBoard) const
Write the stackup info on board file.
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:295
LSET GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition: board.cpp:831
EMBEDDED_FILES * GetEmbeddedFiles() override
Definition: board.cpp:2620
const GENERATORS & Generators() const
Definition: board.h:342
void SetFileName(const wxString &aFileName)
Definition: board.h:330
const PAGE_INFO & GetPageSettings() const
Definition: board.h:706
const ZONES & Zones() const
Definition: board.h:340
const GROUPS & Groups() const
The groups must maintain the following invariants.
Definition: board.h:363
LAYER_T GetLayerType(PCB_LAYER_ID aLayer) const
Return the type of the copper layer given by aLayer.
Definition: board.cpp:654
TITLE_BLOCK & GetTitleBlock()
Definition: board.h:712
int GetCopperLayerCount() const
Definition: board.cpp:783
const std::map< wxString, wxString > & GetProperties() const
Definition: board.h:367
const FOOTPRINTS & Footprints() const
Definition: board.h:336
const TRACKS & Tracks() const
Definition: board.h:334
const PCB_PLOT_PARAMS & GetPlotOptions() const
Definition: board.h:709
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition: board.cpp:616
bool LegacyTeardrops() const
Definition: board.h:1278
wxString GroupsSanityCheck(bool repair=false)
Consistency check of internal m_groups structure.
Definition: board.cpp:2831
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:948
void EmbedFonts() override
Finds all fonts used in the board and embeds them in the file if permissions allow.
Definition: board.cpp:2666
const DRAWINGS & Drawings() const
Definition: board.h:338
const std::vector< COMPONENT_CLASS * > & GetConstituentClasses() const
Fetches a vector of the constituent classes for this (effective) class.
double AsDegrees() const
Definition: eda_angle.h:113
bool IsZero() const
Definition: eda_angle.h:133
EDA_ANGLE Normalize720()
Definition: eda_angle.h:271
const KIID m_Uuid
Definition: eda_item.h:488
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:101
virtual void SetParent(EDA_ITEM *aParent)
Definition: eda_item.h:104
virtual wxString GetClass() const =0
Return the class name.
const VECTOR2I & GetBezierC2() const
Definition: eda_shape.h:213
SHAPE_POLY_SET & GetPolyShape()
Definition: eda_shape.h:291
bool IsFilled() const
Definition: eda_shape.h:98
SHAPE_T GetShape() const
Definition: eda_shape.h:132
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition: eda_shape.h:174
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition: eda_shape.h:137
wxString SHAPE_T_asString() const
Definition: eda_shape.cpp:340
const VECTOR2I & GetBezierC1() const
Definition: eda_shape.h:210
bool IsPolyShapeValid() const
Definition: eda_shape.cpp:1590
VECTOR2I GetArcMid() const
Definition: eda_shape.cpp:810
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition: eda_text.h:80
const VECTOR2I & GetTextPos() const
Definition: eda_text.h:260
const EDA_ANGLE & GetTextAngle() const
Definition: eda_text.h:134
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:98
bool IsKeepUpright() const
Definition: eda_text.h:193
virtual bool IsVisible() const
Definition: eda_text.h:174
KIFONT::FONT * GetFont() const
Definition: eda_text.h:234
std::vector< std::unique_ptr< KIFONT::GLYPH > > * GetRenderCache(const KIFONT::FONT *aFont, const wxString &forResolvedText, const VECTOR2I &aOffset={ 0, 0 }) const
Definition: eda_text.cpp:664
virtual EDA_ANGLE GetDrawRotation() const
Definition: eda_text.h:365
virtual wxString GetShownText(bool aAllowExtraText, int aDepth=0) const
Return the string actually shown after processing of the base text.
Definition: eda_text.h:109
int GetTextThickness() const
Definition: eda_text.h:126
bool IsEmpty() const
void WriteEmbeddedFiles(OUTPUTFORMATTER &aOut, bool aWriteData) const
Output formatter for the embedded files.
void ClearEmbeddedFiles(bool aDeleteFiles=true)
void ClearEmbeddedFonts()
Remove all embedded fonts from the collection.
EMBEDDED_FILE * AddFile(const wxFileName &aName, bool aOverwrite)
Load a file from disk and adds it to the collection.
const std::map< wxString, EMBEDDED_FILE * > & EmbeddedFileMap() const
bool GetAreFontsEmbedded() const
A LINE_READER that reads from an open file.
Definition: richio.h:185
void Rewind()
Rewind the file and resets the line number back to zero.
Definition: richio.h:234
char * ReadLine() override
Read a line of text into the buffer and increments the line number counter.
Definition: richio.cpp:246
void SetFPID(const LIB_ID &aFPID)
Definition: footprint.h:247
wxString GetLibDescription() const
Definition: footprint.h:255
ZONE_CONNECTION GetLocalZoneConnection() const
Definition: footprint.h:286
EDA_ANGLE GetOrientation() const
Definition: footprint.h:225
ZONES & Zones()
Definition: footprint.h:210
void SetOrientation(const EDA_ANGLE &aNewAngle)
Definition: footprint.cpp:2588
wxString GetSheetname() const
Definition: footprint.h:264
std::optional< int > GetLocalSolderPasteMargin() const
Definition: footprint.h:279
EDA_ITEM * Clone() const override
Invoke a function on all children.
Definition: footprint.cpp:2178
PCB_FIELD & Value()
read/write accessors:
Definition: footprint.h:656
std::optional< int > GetLocalClearance() const
Definition: footprint.h:273
BOARD_ITEM * Duplicate() const override
Create a copy of this BOARD_ITEM.
Definition: footprint.cpp:2619
std::deque< PAD * > & Pads()
Definition: footprint.h:204
int GetAttributes() const
Definition: footprint.h:288
const COMPONENT_CLASS * GetComponentClass() const
Returns the component class for this footprint.
Definition: footprint.h:1052
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition: footprint.h:234
LSET GetPrivateLayers() const
Definition: footprint.h:145
wxString GetSheetfile() const
Definition: footprint.h:267
const std::vector< wxString > & GetNetTiePadGroups() const
Definition: footprint.h:337
const LIB_ID & GetFPID() const
Definition: footprint.h:246
bool IsLocked() const override
Definition: footprint.h:409
PCB_FIELD & Reference()
Definition: footprint.h:657
bool IsNetTie() const
Definition: footprint.h:295
std::optional< double > GetLocalSolderPasteMarginRatio() const
Definition: footprint.h:282
void Flip(const VECTOR2I &aCentre, FLIP_DIRECTION aFlipDirection) override
Flip this object, i.e.
Definition: footprint.cpp:2438
GROUPS & Groups()
Definition: footprint.h:213
wxString GetFilters() const
Definition: footprint.h:270
const wxArrayString * GetInitialComments() const
Return the initial comments block or NULL if none, without transfer of ownership.
Definition: footprint.h:977
void GetFields(std::vector< PCB_FIELD * > &aVector, bool aVisibleOnly) const
Populate a std::vector with PCB_TEXTs.
Definition: footprint.cpp:680
std::vector< FP_3DMODEL > & Models()
Definition: footprint.h:218
const KIID_PATH & GetPath() const
Definition: footprint.h:261
std::optional< int > GetLocalSolderMaskMargin() const
Definition: footprint.h:276
wxString GetKeywords() const
Definition: footprint.h:258
EMBEDDED_FILES * GetEmbeddedFiles() override
Definition: footprint.h:1005
bool IsPlaced() const
Definition: footprint.h:432
VECTOR2I GetPosition() const override
Definition: footprint.h:222
DRAWINGS & GraphicalItems()
Definition: footprint.h:207
Helper class for creating a footprint library cache.
FP_CACHE_ENTRY(FOOTPRINT *aFootprint, const WX_FILENAME &aFileName)
const WX_FILENAME & GetFileName() const
std::unique_ptr< FOOTPRINT > & GetFootprint()
static long long GetTimestamp(const wxString &aLibPath)
Generate a timestamp representing all source files in the cache (including the parent directory).
bool Exists() const
boost::ptr_map< wxString, FP_CACHE_ENTRY > m_footprints
PCB_IO_KICAD_SEXPR * m_owner
bool IsModified()
Return true if the cache is not up-to-date.
long long m_cache_timestamp
wxString m_lib_raw_path
void SetPath(const wxString &aPath)
wxFileName m_lib_path
bool IsPath(const wxString &aPath) const
Check if aPath is the same as the current cache path.
void Save(FOOTPRINT *aFootprintFilter=nullptr)
Save the footprint cache or a single footprint from it to disk.
FP_CACHE(PCB_IO_KICAD_SEXPR *aOwner, const wxString &aLibraryPath)
bool IsWritable() const
boost::ptr_map< wxString, FP_CACHE_ENTRY > & GetFootprints()
void Remove(const wxString &aFootprintName)
PROGRESS_REPORTER * m_progressReporter
Progress reporter to track the progress of the operation, may be nullptr.
Definition: io_base.h:223
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
Definition: ki_exception.h:77
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:30
APP_SETTINGS_BASE * KifaceSettings() const
Definition: kiface_base.h:95
virtual bool IsOutline() const
Definition: font.h:139
virtual void SetLineWidth(float aLineWidth)
Set the line width.
wxString AsString() const
Definition: kiid.cpp:356
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:49
UTF8 Format() const
Definition: lib_id.cpp:118
const UTF8 & GetLibItemName() const
Definition: lib_id.h:102
An abstract class from which implementation specific LINE_READERs may be derived to read single lines...
Definition: richio.h:93
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: locale_io.h:49
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
Definition: lseq.h:47
LSET is a set of PCB_LAYER_IDs.
Definition: lset.h:37
LSEQ CuStack() const
Return a sequence of copper layers in starting from the front/top and extending to the back/bottom.
Definition: lset.cpp:247
LSEQ TechAndUserUIOrder() const
Return the technical and user layers in the order shown in layer widget.
Definition: lset.cpp:260
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:564
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:297
static wxString Name(PCB_LAYER_ID aLayerId)
Return the fixed name association with aLayerId.
Definition: lset.cpp:188
Handle the data for a net.
Definition: netinfo.h:56
static const int UNCONNECTED
Constant that holds the "unconnected net" number (typically 0) all items "connected" to this net are ...
Definition: netinfo.h:381
void SetBoard(const BOARD *aBoard)
Set a BOARD object that is used to prepare the net code map.
Definition: netinfo.h:223
int Translate(int aNetCode) const
Translate net number according to the map prepared by Update() function.
virtual bool Finish()
Performs any cleanup needed at the end of a write.
Definition: richio.h:431
std::string Quotew(const wxString &aWrapee) const
Definition: richio.cpp:545
int PRINTF_FUNC_N Print(int nestLevel, const char *fmt,...)
Format and write text to the output stream.
Definition: richio.cpp:460
virtual std::string Quotes(const std::string &aWrapee) const
Check aWrapee input string for a need to be quoted (e.g.
Definition: richio.cpp:506
A PADSTACK defines the characteristics of a single or multi-layer pad, in the IPC sense of the word.
Definition: padstack.h:124
std::optional< int > & Clearance(PCB_LAYER_ID aLayer=F_Cu)
Definition: padstack.cpp:1181
MASK_LAYER_PROPS & FrontOuterLayers()
Definition: padstack.h:312
std::optional< int > & ThermalSpokeWidth(PCB_LAYER_ID aLayer=F_Cu)
Definition: padstack.cpp:1246
EDA_ANGLE ThermalSpokeAngle(PCB_LAYER_ID aLayer=F_Cu) const
Definition: padstack.cpp:1281
std::optional< int > & ThermalGap(PCB_LAYER_ID aLayer=F_Cu)
Definition: padstack.cpp:1258
const VECTOR2I & Size(PCB_LAYER_ID aLayer) const
Definition: padstack.cpp:1068
@ NORMAL
Shape is the same on all layers.
@ FRONT_INNER_BACK
Up to three shapes can be defined (F_Cu, inner copper layers, B_Cu)
MODE Mode() const
Definition: padstack.h:287
MASK_LAYER_PROPS & BackOuterLayers()
Definition: padstack.h:315
static constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
Definition: padstack.h:144
static constexpr PCB_LAYER_ID INNER_LAYERS
! The layer identifier to use for "inner layers" on top/inner/bottom padstacks
Definition: padstack.h:147
std::optional< ZONE_CONNECTION > & ZoneConnection(PCB_LAYER_ID aLayer=F_Cu)
Definition: padstack.cpp:1234
Definition: pad.h:54
PAD_PROP GetProperty() const
Definition: pad.h:441
bool GetRemoveUnconnected() const
Definition: pad.h:726
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: pad.h:435
const std::vector< std::shared_ptr< PCB_SHAPE > > & GetPrimitives(PCB_LAYER_ID aLayer) const
Accessor to the basic shape list for custom-shaped pads.
Definition: pad.h:363
const ZONE_LAYER_OVERRIDE & GetZoneLayerOverride(PCB_LAYER_ID aLayer) const
Definition: pad.cpp:202
std::optional< double > GetLocalSolderPasteMarginRatio() const
Definition: pad.h:468
const wxString & GetPinType() const
Definition: pad.h:151
const VECTOR2I & GetDrillSize() const
Definition: pad.h:303
PAD_ATTRIB GetAttribute() const
Definition: pad.h:438
const wxString & GetPinFunction() const
Definition: pad.h:145
const wxString & GetNumber() const
Definition: pad.h:134
const VECTOR2I & GetDelta(PCB_LAYER_ID aLayer) const
Definition: pad.h:297
EDA_ANGLE GetThermalSpokeAngle() const
Definition: pad.h:617
double GetRoundRectRadiusRatio(PCB_LAYER_ID aLayer) const
Definition: pad.h:663
PAD_SHAPE GetShape(PCB_LAYER_ID aLayer) const
Definition: pad.h:193
bool GetKeepTopBottom() const
Definition: pad.h:742
std::optional< int > GetLocalClearance() const override
Return any local clearances set in the "classic" (ie: pre-rule) system.
Definition: pad.h:453
const PADSTACK & Padstack() const
Definition: pad.h:319
const VECTOR2I & GetOffset(PCB_LAYER_ID aLayer) const
Definition: pad.h:315
EDA_ANGLE GetOrientation() const
Return the rotation angle of the pad.
Definition: pad.h:406
PADSTACK::CUSTOM_SHAPE_ZONE_MODE GetCustomShapeInZoneOpt() const
Definition: pad.h:219
PAD_DRILL_SHAPE GetDrillShape() const
Definition: pad.h:420
int GetChamferPositions(PCB_LAYER_ID aLayer) const
Definition: pad.h:703
std::optional< int > GetLocalSolderPasteMargin() const
Definition: pad.h:462
std::optional< int > GetLocalSolderMaskMargin() const
Definition: pad.h:456
double GetChamferRectRatio(PCB_LAYER_ID aLayer) const
Definition: pad.h:686
std::optional< int > GetLocalThermalSpokeWidthOverride() const
Definition: pad.h:601
ZONE_CONNECTION GetLocalZoneConnection() const
Definition: pad.h:478
int GetLocalThermalGapOverride(wxString *aSource) const
Definition: pad.cpp:1262
PAD_SHAPE GetAnchorPadShape(PCB_LAYER_ID aLayer) const
Definition: pad.h:211
int GetPadToDieLength() const
Definition: pad.h:451
const VECTOR2I & GetSize(PCB_LAYER_ID aLayer) const
Definition: pad.h:262
void Format(OUTPUTFORMATTER *aFormatter) const
Output the page class to aFormatter in s-expression form.
Definition: page_info.cpp:275
FLIP_DIRECTION m_FlipDirection
const VECTOR2I & GetMid() const
Definition: pcb_track.h:305
Abstract dimension API.
wxString GetOverrideText() const
wxString GetSuffix() const
int GetLineThickness() const
DIM_TEXT_POSITION GetTextPositionMode() const
bool GetKeepTextAligned() const
DIM_PRECISION GetPrecision() const
wxString GetPrefix() const
DIM_UNITS_MODE GetUnitsMode() const
DIM_UNITS_FORMAT GetUnitsFormat() const
virtual const VECTOR2I & GetStart() const
The dimension's origin is the first feature point for the dimension.
DIM_ARROW_DIRECTION GetArrowDirection() const
bool GetSuppressZeroes() const
int GetExtensionOffset() const
int GetArrowLength() const
bool GetOverrideTextEnabled() const
virtual const VECTOR2I & GetEnd() const
For better understanding of the points that make a dimension:
int GetHeight() const
int GetExtensionHeight() const
Mark the center of a circle or arc with a cross shape.
A leader is a dimension-like object pointing to a specific point.
DIM_TEXT_BORDER GetTextBorder() const
An orthogonal dimension is like an aligned dimension, but the extension lines are locked to the X or ...
A radial dimension indicates either the radius or diameter of an arc or circle.
int GetLeaderLength() const
virtual const STRING_ANY_MAP GetProperties() const
virtual wxString GetGeneratorType() const
A set of BOARD_ITEMs (i.e., without duplicates).
Definition: pcb_group.h:52
std::unordered_set< BOARD_ITEM * > & GetItems()
Definition: pcb_group.h:69
wxString GetName() const
Definition: pcb_group.h:66
Read a Pcbnew s-expression formatted LINE_READER object and returns the appropriate BOARD_ITEM object...
bool IsTooRecent()
Return whether a version number, if any was parsed, was too recent.
bool IsValidBoardHeader()
Partially parse the input and check if it matches expected header.
wxString GetRequiredVersion()
Return a string representing the version of KiCad required to open this file.
A #PLUGIN derivation for saving and loading Pcbnew s-expression formatted files.
BOARD * DoLoad(LINE_READER &aReader, BOARD *aAppendToMe, const std::map< std::string, UTF8 > *aProperties, PROGRESS_REPORTER *aProgressReporter, unsigned aLineCount)
bool CanReadBoard(const wxString &aFileName) const override
Checks if this PCB_IO can read the specified board file.
void formatProperties(const BOARD *aBoard) const
formats the Nets and Netclasses
FOOTPRINT * ImportFootprint(const wxString &aFootprintPath, wxString &aFootprintNameOut, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Load a single footprint from aFootprintPath and put its name in aFootprintNameOut.
void FootprintDelete(const wxString &aLibraryPath, const wxString &aFootprintName, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Delete aFootprintName from the library at aLibraryPath.
long long GetLibraryTimestamp(const wxString &aLibraryPath) const override
Generate a timestamp representing all the files in the library (including the library directory).
bool IsLibraryWritable(const wxString &aLibraryPath) override
Return true if the library at aLibraryPath is writable.
void formatTeardropParameters(const TEARDROP_PARAMETERS &tdParams) const
bool DeleteLibrary(const wxString &aLibraryPath, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Delete an existing library and returns true, or if library does not exist returns false,...
NETINFO_MAPPING * m_mapping
mapping for net codes, so only not empty net codes are stored with consecutive integers as net codes
void formatNetInformation(const BOARD *aBoard) const
formats the Nets and Netclasses
const FOOTPRINT * GetEnumeratedFootprint(const wxString &aLibraryPath, const wxString &aFootprintName, const std::map< std::string, UTF8 > *aProperties=nullptr) override
A version of FootprintLoad() for use after FootprintEnumerate() for more efficient cache management.
void CreateLibrary(const wxString &aLibraryPath, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Create a new empty library at aLibraryPath empty.
void FootprintEnumerate(wxArrayString &aFootprintNames, const wxString &aLibraryPath, bool aBestEfforts, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Return a list of footprint names contained within the library at aLibraryPath.
void formatPolyPts(const SHAPE_LINE_CHAIN &outline, const FOOTPRINT *aParentFP=nullptr) const
FP_CACHE * m_cache
Footprint library cache.
void formatBoardLayers(const BOARD *aBoard) const
formats the board layer information
FOOTPRINT * FootprintLoad(const wxString &aLibraryPath, const wxString &aFootprintName, bool aKeepUUID=false, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Load a footprint having aFootprintName from the aLibraryPath containing a library format that this PC...
BOARD * LoadBoard(const wxString &aFileName, BOARD *aAppendToMe, const std::map< std::string, UTF8 > *aProperties=nullptr, PROJECT *aProject=nullptr) override
Load information from some input file format that this PCB_IO implementation knows about into either ...
bool FootprintExists(const wxString &aLibraryPath, const wxString &aFootprintName, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Check for the existence of a footprint.
void FootprintSave(const wxString &aLibraryPath, const FOOTPRINT *aFootprint, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Write aFootprint to an existing library located at aLibraryPath.
void format(const BOARD *aBoard) const
void SaveBoard(const wxString &aFileName, BOARD *aBoard, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Write aBoard to a storage file in a format that this PCB_IO implementation knows about or it can be u...
void formatTenting(const PADSTACK &aPadstack) const
void formatGeneral(const BOARD *aBoard) const
formats the General section of the file
void formatSetup(const BOARD *aBoard) const
formats the board setup information
void formatLayers(LSET aLayerMask, bool aEnumerateLayers) const
std::function< bool(wxString aTitle, int aIcon, wxString aMsg, wxString aAction)> m_queryUserCallback
BOARD_ITEM * Parse(const wxString &aClipboardSourceInput)
void init(const std::map< std::string, UTF8 > *aProperties)
STRING_FORMATTER m_sf
void Format(const BOARD_ITEM *aItem) const
Output aItem to aFormatter in s-expression format.
void formatLayer(PCB_LAYER_ID aLayer, bool aIsKnockout=false) const
void formatHeader(const BOARD *aBoard) const
writes everything that comes before the board_items, like settings and layers etc
const FOOTPRINT * getFootprint(const wxString &aLibraryPath, const wxString &aFootprintName, const std::map< std::string, UTF8 > *aProperties, bool checkModified)
void SetOutputFormatter(OUTPUTFORMATTER *aFormatter)
PCB_IO_KICAD_SEXPR(int aControlFlags=CTL_FOR_BOARD)
OUTPUTFORMATTER * m_out
output any Format()s to this, no ownership
void validateCache(const wxString &aLibraryPath, bool checkModified=true)
void formatRenderCache(const EDA_TEXT *aText) const
LINE_READER * m_reader
no ownership
A base class that BOARD loading and saving plugins should derive from.
Definition: pcb_io.h:71
BOARD * m_board
The board BOARD being worked on, no ownership here.
Definition: pcb_io.h:324
virtual bool CanReadBoard(const wxString &aFileName) const
Checks if this PCB_IO can read the specified board file.
Definition: pcb_io.cpp:42
const std::map< std::string, UTF8 > * m_props
Properties passed via Save() or Load(), no ownership, may be NULL.
Definition: pcb_io.h:327
void Format(OUTPUTFORMATTER *aFormatter) const
Object to handle a bitmap image that can be inserted in a PCB.
VECTOR2I GetPosition() const override
Get the position of the image (this is the center of the image).
REFERENCE_IMAGE & GetReferenceImage()
std::optional< int > GetLocalSolderMaskMargin() const
Definition: pcb_shape.h:186
bool HasSolderMask() const
Definition: pcb_shape.h:183
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: pcb_shape.cpp:218
STROKE_PARAMS GetStroke() const override
Definition: pcb_shape.h:89
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition: pcb_shape.h:69
bool StrokeRows() const
Definition: pcb_table.h:98
int GetRowCount() const
Definition: pcb_table.h:115
bool StrokeColumns() const
Definition: pcb_table.h:95
bool StrokeExternal() const
Definition: pcb_table.h:53
bool StrokeHeader() const
Definition: pcb_table.h:56
std::vector< PCB_TABLECELL * > GetCells() const
Definition: pcb_table.h:150
int GetColCount() const
Definition: pcb_table.h:113
const STROKE_PARAMS & GetSeparatorsStroke() const
Definition: pcb_table.h:77
const STROKE_PARAMS & GetBorderStroke() const
Definition: pcb_table.h:59
int GetColWidth(int aCol) const
Definition: pcb_table.h:122
int GetRowHeight(int aRow) const
Definition: pcb_table.h:132
int GetShape() const
Definition: pcb_target.h:58
int GetWidth() const
Definition: pcb_target.h:64
int GetSize() const
Definition: pcb_target.h:61
VECTOR2I GetPosition() const override
Definition: pcb_target.h:55
bool IsBorderEnabled() const
Disables the border, this is done by changing the stroke internally.
int GetMarginBottom() const
Definition: pcb_textbox.h:90
int GetMarginLeft() const
Definition: pcb_textbox.h:87
int GetMarginRight() const
Definition: pcb_textbox.h:89
int GetMarginTop() const
Definition: pcb_textbox.h:88
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: pcb_track.cpp:1046
bool HasSolderMask() const
Definition: pcb_track.h:146
std::optional< int > GetLocalSolderMaskMargin() const
Definition: pcb_track.h:149
const VECTOR2I & GetStart() const
Definition: pcb_track.h:122
const VECTOR2I & GetEnd() const
Definition: pcb_track.h:119
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Test to see if this object is on the given layer.
Definition: pcb_track.cpp:958
virtual int GetWidth() const
Definition: pcb_track.h:116
A progress reporter interface for use in multi-threaded environments.
virtual bool KeepRefreshing(bool aWait=false)=0
Update the UI (if any).
virtual void Report(const wxString &aMessage)=0
Display aMessage in the progress bar dialog.
Container for project specific data.
Definition: project.h:64
A REFERENCE_IMAGE is a wrapper around a BITMAP_IMAGE that is displayed in an editor as a reference fo...
const BITMAP_BASE & GetImage() const
Get the underlying image.
double GetImageScale() const
const VECTOR2I & GetArcMid() const
Definition: shape_arc.h:118
const VECTOR2I & GetP1() const
Definition: shape_arc.h:117
const VECTOR2I & GetP0() const
Definition: shape_arc.h:116
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
const SHAPE_ARC & Arc(size_t aArc) const
int PointCount() const
Return the number of points (vertices) in this line chain.
ssize_t ArcIndex(size_t aSegment) const
Return the arc index for the given segment index.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
Represent a set of closed polygons.
POLYGON & Polygon(int aIndex)
Return the aIndex-th subpolygon in the set.
std::vector< SHAPE_LINE_CHAIN > POLYGON
represents a single polygon outline with holes.
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
Is a LINE_READER that reads from a multiline 8 bit wide std::string.
Definition: richio.h:253
void Format(OUTPUTFORMATTER *out, const EDA_IU_SCALE &aIuScale) const
TEARDROP_PARAMETARS is a helper class to handle parameters needed to build teardrops for a board thes...
double m_BestWidthRatio
The height of a teardrop as ratio between height and size of pad/via.
int m_TdMaxLen
max allowed length for teardrops in IU. <= 0 to disable
bool m_AllowUseTwoTracks
True to create teardrops using 2 track segments if the first in too small.
int m_TdMaxWidth
max allowed height for teardrops in IU. <= 0 to disable
double m_BestLengthRatio
The length of a teardrop as ratio between length and size of pad/via.
double m_WidthtoSizeFilterRatio
The ratio (H/D) between the via/pad size and the track width max value to create a teardrop 1....
bool m_TdOnPadsInZones
A filter to exclude pads inside zone fills.
bool m_Enabled
Flag to enable teardrops.
bool m_CurvedEdges
True if the teardrop should be curved.
virtual void Format(OUTPUTFORMATTER *aFormatter) const
Output the object to aFormatter in s-expression form.
Definition: title_block.cpp:31
wxString wx_str() const
Definition: utf8.cpp:45
static REPORTER & GetInstance()
Definition: reporter.cpp:202
A wrapper around a wxFileName which is much more performant with a subset of the API.
Definition: wx_filename.h:50
void SetFullName(const wxString &aFileNameAndExtension)
Definition: wx_filename.cpp:34
static void ResolvePossibleSymlinks(wxFileName &aFilename)
Definition: wx_filename.cpp:91
wxString GetPath() const
Definition: wx_filename.cpp:60
wxString GetName() const
Definition: wx_filename.cpp:47
wxString GetFullPath() const
Definition: wx_filename.cpp:66
long long GetTimestamp()
Definition: wx_filename.cpp:80
Handle a list of polygons defining a copper zone.
Definition: zone.h:73
int GetHatchBorderAlgorithm() const
Definition: zone.h:313
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
Definition: zone.h:731
std::optional< int > GetLocalClearance() const override
Definition: zone.cpp:717
wxString GetRuleAreaPlacementSource() const
Definition: zone.h:737
bool GetDoNotAllowVias() const
Definition: zone.h:739
const std::shared_ptr< SHAPE_POLY_SET > & GetFilledPolysList(PCB_LAYER_ID aLayer) const
Definition: zone.h:627
bool GetDoNotAllowPads() const
Definition: zone.h:741
bool GetDoNotAllowTracks() const
Definition: zone.h:740
bool GetRuleAreaPlacementEnabled() const
Definition: zone.h:732
bool IsFilled() const
Definition: zone.h:271
ISLAND_REMOVAL_MODE GetIslandRemovalMode() const
Definition: zone.h:760
SHAPE_POLY_SET * Outline()
Definition: zone.h:347
bool IsIsland(PCB_LAYER_ID aLayer, int aPolyIdx) const
Check if a given filled polygon is an insulated island.
Definition: zone.cpp:1323
long long int GetMinIslandArea() const
Definition: zone.h:763
const wxString & GetZoneName() const
Definition: zone.h:142
int GetMinThickness() const
Definition: zone.h:280
ZONE_CONNECTION GetPadConnection() const
Definition: zone.h:277
int GetHatchThickness() const
Definition: zone.h:295
double GetHatchHoleMinArea() const
Definition: zone.h:310
bool IsTeardropArea() const
Definition: zone.h:706
int GetThermalReliefSpokeWidth() const
Definition: zone.h:224
int GetBorderHatchPitch() const
HatchBorder related methods.
Definition: zone.cpp:1104
ZONE_BORDER_DISPLAY_STYLE GetHatchStyle() const
Definition: zone.h:616
EDA_ANGLE GetHatchOrientation() const
Definition: zone.h:301
bool GetDoNotAllowFootprints() const
Definition: zone.h:742
ZONE_FILL_MODE GetFillMode() const
Definition: zone.h:203
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: zone.h:133
bool GetDoNotAllowCopperPour() const
Definition: zone.h:738
int GetHatchGap() const
Definition: zone.h:298
RULE_AREA_PLACEMENT_SOURCE_TYPE GetRuleAreaPlacementSourceType() const
Definition: zone.h:733
TEARDROP_TYPE GetTeardropAreaType() const
Definition: zone.h:717
double GetHatchSmoothingValue() const
Definition: zone.h:307
int GetHatchSmoothingLevel() const
Definition: zone.h:304
unsigned int GetCornerRadius() const
Definition: zone.h:677
int GetCornerSmoothingType() const
Definition: zone.h:673
bool IsOnCopperLayer() const override
Definition: zone.cpp:480
PCB_LAYER_ID GetFirstLayer() const
Definition: zone.cpp:458
int GetThermalReliefGap() const
Definition: zone.h:213
unsigned GetAssignedPriority() const
Definition: zone.h:123
int GetNumCorners(void) const
Access to m_Poly parameters.
Definition: zone.h:526
static void SetReporter(REPORTER *aReporter)
Set the reporter to use for reporting font substitution warnings.
Definition: fontconfig.cpp:65
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:600
This file is part of the common library.
#define CTL_OMIT_HYPERLINK
Omit the hyperlink attribute in .kicad_xxx files.
Definition: ctl_flags.h:46
#define CTL_OMIT_UUIDS
Omit component unique ids (useless in library)
Definition: ctl_flags.h:30
#define CTL_OMIT_FOOTPRINT_VERSION
Omit the version string from the (footprint) sexpr group.
Definition: ctl_flags.h:39
#define CTL_OMIT_INITIAL_COMMENTS
Omit FOOTPRINT initial comments.
Definition: ctl_flags.h:43
#define CTL_OMIT_LIBNAME
Omit lib alias when saving (used for board/not library).
Definition: ctl_flags.h:37
#define CTL_OMIT_PATH
Omit component sheet time stamp (useless in library).
Definition: ctl_flags.h:33
#define CTL_OMIT_AT
Omit position and rotation.
Definition: ctl_flags.h:35
#define CTL_OMIT_PAD_NETS
Omit pads net names (useless in library).
Definition: ctl_flags.h:29
#define CTL_OMIT_COLOR
Omit the color attribute in .kicad_xxx files.
Definition: ctl_flags.h:45
#define _(s)
static constexpr EDA_ANGLE ANGLE_0
Definition: eda_angle.h:401
static constexpr EDA_ANGLE ANGLE_90
Definition: eda_angle.h:403
static constexpr EDA_ANGLE ANGLE_45
Definition: eda_angle.h:402
@ FP_SMD
Definition: footprint.h:80
@ FP_DNP
Definition: footprint.h:87
@ FP_ALLOW_MISSING_COURTYARD
Definition: footprint.h:86
@ FP_EXCLUDE_FROM_POS_FILES
Definition: footprint.h:81
@ FP_BOARD_ONLY
Definition: footprint.h:83
@ FP_EXCLUDE_FROM_BOM
Definition: footprint.h:82
@ FP_THROUGH_HOLE
Definition: footprint.h:79
@ FP_ALLOW_SOLDERMASK_BRIDGES
Definition: footprint.h:85
static const std::string KiCadFootprintFileExtension
const wxChar *const traceKicadPcbPlugin
Flag to enable GEDA PCB plugin debug output.
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:39
#define THROW_PARSE_ERROR(aProblem, aSource, aInputLine, aLineNumber, aByteIndex)
Definition: ki_exception.h:165
#define MAX_CU_LAYERS
Definition: layer_ids.h:176
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition: layer_ids.h:618
bool IsExternalCopperLayer(int aLayerId)
Test whether a layer is an external (F_Cu or B_Cu) copper layer.
Definition: layer_ids.h:629
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ F_CrtYd
Definition: layer_ids.h:116
@ B_Adhes
Definition: layer_ids.h:103
@ F_Paste
Definition: layer_ids.h:104
@ F_Adhes
Definition: layer_ids.h:102
@ B_Mask
Definition: layer_ids.h:98
@ B_Cu
Definition: layer_ids.h:65
@ F_Mask
Definition: layer_ids.h:97
@ B_Paste
Definition: layer_ids.h:105
@ F_Fab
Definition: layer_ids.h:119
@ F_SilkS
Definition: layer_ids.h:100
@ B_CrtYd
Definition: layer_ids.h:115
@ User_1
Definition: layer_ids.h:124
@ B_SilkS
Definition: layer_ids.h:101
@ PCB_LAYER_ID_COUNT
Definition: layer_ids.h:171
@ F_Cu
Definition: layer_ids.h:64
@ B_Fab
Definition: layer_ids.h:118
This file contains miscellaneous commonly used macros and functions.
#define UNIMPLEMENTED_FOR(type)
Definition: macros.h:96
KICOMMON_API std::string FormatInternalUnits(const EDA_IU_SCALE &aIuScale, int aValue)
Converts aValue from internal units to a string appropriate for writing to file.
Definition: eda_units.cpp:170
KICOMMON_API std::string FormatAngle(const EDA_ANGLE &aAngle)
Convert aAngle from board units to a string appropriate for writing to file.
Definition: eda_units.cpp:162
void FormatUuid(OUTPUTFORMATTER *aOut, const KIID &aUuid)
void FormatStreamData(OUTPUTFORMATTER &aOut, const wxStreamBuffer &aStream)
Write binary data to the formatter as base 64 encoded string.
void FormatBool(OUTPUTFORMATTER *aOut, const wxString &aKey, bool aValue)
Writes a boolean to the formatter, in the style (aKey [yes|no])
bool DuplicatePermissions(const wxString &aSrc, const wxString &aDest)
Duplicates the file security data from one file to another ensuring that they are the same between bo...
Definition: unix/io.cpp:47
Class to handle a set of BOARD_ITEMs.
bool isDefaultTeardropParameters(const TEARDROP_PARAMETERS &tdParams)
std::string formatInternalUnits(int aValue)
#define SEXPR_BOARD_FILE_VERSION
Current s-expression file format version. 2 was the last legacy format version.
#define CTL_FOR_BOARD
The zero arg constructor when PCB_PLUGIN is used for PLUGIN::Load() and PLUGIN::Save()ing a BOARD fil...
#define CTL_FOR_LIBRARY
Format output for a footprint library instead of clipboard or BOARD.
Pcbnew s-expression file format parser definition.
#define UNDEFINED_DRILL_DIAMETER
Definition: pcb_track.h:81
PGM_BASE & Pgm()
The global program "get" accessor.
Definition: pgm_base.cpp:1073
see class PGM_BASE
bool ReplaceIllegalFileNameChars(std::string *aName, int aReplaceChar)
Checks aName for illegal file name characters.
std::string FormatDouble2Str(double aValue)
Print a float number without using scientific notation and no trailing 0 This function is intended in...
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: string_utils.h:403
const double IU_PER_MM
Definition: base_units.h:76
Variant of PARSE_ERROR indicating that a syntax or related error was likely caused by a file generate...
Definition: ki_exception.h:176
static const char * ShowType(LAYER_T aType)
Convert a LAYER_T enum to a string representation of the layer type.
Definition: board.cpp:686
std::optional< bool > has_solder_mask
True if this outer layer has mask (is not tented)
Definition: padstack.h:231
A filename or source description, a problem input line, a line number, a byte offset,...
Definition: ki_exception.h:120
VECTOR2I center
const SHAPE_LINE_CHAIN chain
constexpr int delta
wxLogTrace helper definitions.
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition: trigo.cpp:229
@ PCB_T
Definition: typeinfo.h:82
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition: typeinfo.h:88
@ PCB_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition: typeinfo.h:105
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition: typeinfo.h:102
@ PCB_GENERATOR_T
class PCB_GENERATOR, generator on a layer
Definition: typeinfo.h:91
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:97
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition: typeinfo.h:103
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
Definition: typeinfo.h:110
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition: typeinfo.h:93
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition: typeinfo.h:107
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition: typeinfo.h:92
@ PCB_REFERENCE_IMAGE_T
class PCB_REFERENCE_IMAGE, bitmap on a layer
Definition: typeinfo.h:89
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
Definition: typeinfo.h:90
@ PCB_TARGET_T
class PCB_TARGET, a target (graphic item)
Definition: typeinfo.h:106
@ PCB_TABLECELL_T
class PCB_TABLECELL, PCB_TEXTBOX for use in tables
Definition: typeinfo.h:95
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
Definition: typeinfo.h:86
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition: typeinfo.h:101
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition: typeinfo.h:87
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition: typeinfo.h:98
@ PCB_TABLE_T
class PCB_TABLE, table of PCB_TABLECELLs
Definition: typeinfo.h:94
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:96
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition: typeinfo.h:104
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:695
Definition of file extensions used in Kicad.