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