KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcb_writer_v10.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 The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20// Board writer for the KiCad 10.0 file format, extracted from the 10.0.0 release. It can only
21// emit what 10.0 knew, so its output always opens there. Do not add new-format features here.
22
24
25#include <wx/ffile.h>
26#include <wx/mstream.h>
27#include <board.h>
31#include <callback_gal.h>
34#include <fmt/format.h>
35#include <footprint.h>
38#include "legacy_item_order.h"
41#include <layer_range.h>
42#include <macros.h>
43#include <pad.h>
44#include <pcb_dimension.h>
45#include <pcb_generator.h>
46#include <pcb_group.h>
48#include <pcb_point.h>
49#include <pcb_reference_image.h>
50#include <pcb_barcode.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 <richio.h>
59#include <string_utils.h>
60#include <zone.h>
61#include <build_version.h>
62
63
64static void formatBoardStackupV10( OUTPUTFORMATTER* aFormatter, const BOARD* aBoard )
65{
66 const BOARD_STACKUP& stackup = aBoard->GetDesignSettings().GetStackupDescriptor();
67
68 // Board stackup is the ordered list from top to bottom of
69 // physical layers and substrate used to build the board.
70 if( stackup.GetList().empty() )
71 return;
72
73 aFormatter->Print( "(stackup" );
74
75 // Note:
76 // Unspecified parameters are not stored in file.
77 for( BOARD_STACKUP_ITEM* item : stackup.GetList() )
78 {
79 wxString layer_name;
80
81 if( item->GetBrdLayerId() == UNDEFINED_LAYER )
82 layer_name.Printf( wxT( "dielectric %d" ), item->GetDielectricLayerId() );
83 else
84 layer_name = LSET::Name( item->GetBrdLayerId() );
85
86 aFormatter->Print( "(layer %s (type %s)", aFormatter->Quotew( layer_name ).c_str(),
87 aFormatter->Quotew( item->GetTypeName() ).c_str() );
88
89 // Output other parameters (in sub layer list there is at least one item)
90 for( int idx = 0; idx < item->GetSublayersCount(); idx++ )
91 {
92 if( idx ) // not for the main (first) layer.
93 aFormatter->Print( " addsublayer" );
94
95 if( item->IsColorEditable() && IsPrmSpecified( item->GetColor( idx ) ) )
96 {
97 aFormatter->Print( "(color %s)", aFormatter->Quotew( item->GetColor( idx ) ).c_str() );
98 }
99
100 if( item->IsThicknessEditable() )
101 {
102 aFormatter->Print(
103 "(thickness %s",
104 EDA_UNIT_UTILS::FormatInternalUnits( pcbIUScale, item->GetThickness( idx ) ).c_str() );
105
106 if( item->GetType() == BS_ITEM_TYPE_DIELECTRIC && item->IsThicknessLocked( idx ) )
107 aFormatter->Print( " locked" );
108
109 aFormatter->Print( ")" );
110 }
111
112 if( item->HasMaterialValue( idx ) )
113 {
114 aFormatter->Print( "(material %s)", aFormatter->Quotew( item->GetMaterial( idx ) ).c_str() );
115 }
116
117 if( item->HasEpsilonRValue() && item->HasMaterialValue( idx ) )
118 aFormatter->Print( "(epsilon_r %s)", FormatDouble2Str( item->GetEpsilonR( idx ) ).c_str() );
119
120 if( item->HasLossTangentValue() && item->HasMaterialValue( idx ) )
121 {
122 aFormatter->Print( "(loss_tangent %s)", FormatDouble2Str( item->GetLossTangent( idx ) ).c_str() );
123 }
124 }
125
126 aFormatter->Print( ")" );
127 }
128
129 // Other infos about board, related to layers and other fabrication specifications
130 if( IsPrmSpecified( stackup.m_FinishType ) )
131 aFormatter->Print( "(copper_finish %s)", aFormatter->Quotew( stackup.m_FinishType ).c_str() );
132
133 KICAD_FORMAT::LEGACY::FormatBool( aFormatter, "dielectric_constraints", stackup.m_HasDielectricConstrains );
134
135 if( stackup.m_EdgeConnectorConstraints > 0 )
136 {
137 aFormatter->Print( "(edge_connector %s)", stackup.m_EdgeConnectorConstraints > 1 ? "bevelled" : "yes" );
138 }
139
140 if( stackup.m_EdgePlating )
141 KICAD_FORMAT::LEGACY::FormatBool( aFormatter, "edge_plating", true );
142
143 aFormatter->Print( ")" );
144}
145
146
147void PCB_WRITER_V10::SaveBoard( const wxString& aFileName, BOARD* aBoard )
148{
149 PRETTIFIED_FILE_OUTPUTFORMATTER formatter( aFileName );
150 FormatBoardToFormatter( &formatter, aBoard );
151 formatter.Finish();
152}
153
154
156{
158 m_board = aBoard;
159
160 // If the user wants fonts embedded, make sure that they are added to the board. Otherwise,
161 // remove any fonts that were previously embedded.
162 if( m_board->GetAreFontsEmbedded() )
163 m_board->EmbedFonts();
164 else
165 m_board->GetEmbeddedFiles()->ClearEmbeddedFonts();
166
167 m_out = aOut;
168
169 m_out->Print( "(kicad_pcb (version %d) (generator \"pcbnew\") (generator_version %s)",
171
172 Format( aBoard );
173
174 m_out->Print( ")" );
175
176 m_out = nullptr;
177}
178
179
180void PCB_WRITER_V10::Format( const BOARD_ITEM* aItem ) const
181{
182 switch( aItem->Type() )
183 {
184 case PCB_T: format( static_cast<const BOARD*>( aItem ) ); break;
185
187 case PCB_DIM_CENTER_T:
188 case PCB_DIM_RADIAL_T:
190 case PCB_DIM_LEADER_T: format( static_cast<const PCB_DIMENSION_BASE*>( aItem ) ); break;
191
192 case PCB_SHAPE_T: format( static_cast<const PCB_SHAPE*>( aItem ) ); break;
193
194 case PCB_REFERENCE_IMAGE_T: format( static_cast<const PCB_REFERENCE_IMAGE*>( aItem ) ); break;
195
196 case PCB_POINT_T: format( static_cast<const PCB_POINT*>( aItem ) ); break;
197
198 case PCB_TARGET_T: format( static_cast<const PCB_TARGET*>( aItem ) ); break;
199
200 case PCB_FOOTPRINT_T: format( static_cast<const FOOTPRINT*>( aItem ) ); break;
201
202 case PCB_PAD_T: format( static_cast<const PAD*>( aItem ) ); break;
203
204 case PCB_FIELD_T:
205 // Handled in the footprint formatter when properties are formatted
206 break;
207
208 case PCB_TEXT_T: format( static_cast<const PCB_TEXT*>( aItem ) ); break;
209
210 case PCB_TEXTBOX_T: format( static_cast<const PCB_TEXTBOX*>( aItem ) ); break;
211
212 case PCB_BARCODE_T: format( static_cast<const PCB_BARCODE*>( aItem ) ); break;
213
214 case PCB_TABLE_T: format( static_cast<const PCB_TABLE*>( aItem ) ); break;
215
216 case PCB_GROUP_T: format( static_cast<const PCB_GROUP*>( aItem ) ); break;
217
218 case PCB_GENERATOR_T: format( static_cast<const PCB_GENERATOR*>( aItem ) ); break;
219
220 case PCB_TRACE_T:
221 case PCB_ARC_T:
222 case PCB_VIA_T: format( static_cast<const PCB_TRACK*>( aItem ) ); break;
223
224 case PCB_ZONE_T: format( static_cast<const ZONE*>( aItem ) ); break;
225
226 default: wxFAIL_MSG( wxT( "Cannot format item " ) + aItem->GetClass() );
227 }
228}
229
230
231static std::string formatInternalUnits( const int aValue, const EDA_DATA_TYPE aDataType = EDA_DATA_TYPE::DISTANCE )
232{
233 return EDA_UNIT_UTILS::FormatInternalUnits( pcbIUScale, aValue, aDataType );
234}
235
236
237static std::string formatInternalUnits( const VECTOR2I& aCoord )
238{
240}
241
242
243static std::string formatInternalUnits( const VECTOR2I& aCoord, const FOOTPRINT* aParentFP )
244{
245 if( aParentFP )
246 {
247 VECTOR2I coord = aCoord - aParentFP->GetPosition();
248 RotatePoint( coord, -aParentFP->GetOrientation() );
249 return formatInternalUnits( coord );
250 }
251
252 return formatInternalUnits( aCoord );
253}
254
255
256void PCB_WRITER_V10::formatLayer( PCB_LAYER_ID aLayer, bool aIsKnockout ) const
257{
258 m_out->Print( "(layer %s %s)", m_out->Quotew( LSET::Name( aLayer ) ).c_str(), aIsKnockout ? "knockout" : "" );
259}
260
261
262void PCB_WRITER_V10::formatPolyPts( const SHAPE_LINE_CHAIN& aOutline, const FOOTPRINT* aParentFP ) const
263{
264 m_out->Print( "(pts" );
265
266 for( int ii = 0; ii < aOutline.PointCount(); ++ii )
267 {
268 int ind = aOutline.ArcIndex( ii );
269
270 if( ind < 0 )
271 {
272 m_out->Print( "(xy %s)", formatInternalUnits( aOutline.CPoint( ii ), aParentFP ).c_str() );
273 }
274 else
275 {
276 const SHAPE_ARC& arc = aOutline.Arc( ind );
277 m_out->Print( "(arc (start %s) (mid %s) (end %s))", formatInternalUnits( arc.GetP0(), aParentFP ).c_str(),
278 formatInternalUnits( arc.GetArcMid(), aParentFP ).c_str(),
279 formatInternalUnits( arc.GetP1(), aParentFP ).c_str() );
280
281 do
282 {
283 ++ii;
284 } while( ii < aOutline.PointCount() && aOutline.ArcIndex( ii ) == ind );
285
286 --ii;
287 }
288 }
289
290 m_out->Print( ")" );
291}
292
293
295{
296 wxString resolvedText( aText->GetShownText( FOR_CANVAS ) );
297 std::vector<std::unique_ptr<KIFONT::GLYPH>>* cache = aText->GetRenderCache( aText->GetFont(), resolvedText );
298
299 m_out->Print( "(render_cache %s %s", m_out->Quotew( resolvedText ).c_str(),
300 EDA_UNIT_UTILS::FormatAngle( aText->GetDrawRotation() ).c_str() );
301
303
304 CALLBACK_GAL callback_gal( empty_opts,
305 // Polygon callback
306 [&]( const SHAPE_LINE_CHAIN& aPoly )
307 {
308 m_out->Print( "(polygon" );
309 formatPolyPts( aPoly );
310 m_out->Print( ")" );
311 } );
312
313 callback_gal.SetLineWidth( aText->GetTextThickness() );
314 callback_gal.DrawGlyphs( *cache );
315
316 m_out->Print( ")" );
317}
318
319
320void PCB_WRITER_V10::formatSetup( const BOARD* aBoard ) const
321{
322 // Setup
323 m_out->Print( "(setup" );
324
325 const BOARD_DESIGN_SETTINGS& dsnSettings = aBoard->GetDesignSettings();
326
327 // Save the board physical stackup structure
328 if( dsnSettings.m_HasStackup )
329 formatBoardStackupV10( m_out, aBoard );
330
331 m_out->Print( "(pad_to_mask_clearance %s)", formatInternalUnits( dsnSettings.m_SolderMaskExpansion ).c_str() );
332
333 if( dsnSettings.m_SolderMaskMinWidth )
334 {
335 m_out->Print( "(solder_mask_min_width %s)", formatInternalUnits( dsnSettings.m_SolderMaskMinWidth ).c_str() );
336 }
337
338 if( dsnSettings.m_SolderPasteMargin != 0 )
339 {
340 m_out->Print( "(pad_to_paste_clearance %s)", formatInternalUnits( dsnSettings.m_SolderPasteMargin ).c_str() );
341 }
342
343 if( dsnSettings.m_SolderPasteMarginRatio != 0 )
344 {
345 m_out->Print( "(pad_to_paste_clearance_ratio %s)",
346 FormatDouble2Str( dsnSettings.m_SolderPasteMarginRatio ).c_str() );
347 }
348
349 KICAD_FORMAT::LEGACY::FormatBool( m_out, "allow_soldermask_bridges_in_footprints",
350 dsnSettings.m_AllowSoldermaskBridgesInFPs );
351
352 m_out->Print( 0, " (tenting " );
355 m_out->Print( 0, ")" );
356
357 m_out->Print( 0, " (covering " );
360 m_out->Print( 0, ")" );
361
362 m_out->Print( 0, " (plugging " );
365 m_out->Print( 0, ")" );
366
367 KICAD_FORMAT::LEGACY::FormatBool( m_out, "capping", dsnSettings.m_CapVias );
368
369 KICAD_FORMAT::LEGACY::FormatBool( m_out, "filling", dsnSettings.m_FillVias );
370
371 if( !dsnSettings.m_ZoneLayerProperties.empty() )
372 {
373 m_out->Print( 0, " (zone_defaults" );
374
375 for( const auto& [layer, properties] : dsnSettings.m_ZoneLayerProperties )
376 format( properties, 0, layer );
377
378 m_out->Print( 0, ")\n" );
379 }
380
381 VECTOR2I origin = dsnSettings.GetAuxOrigin();
382
383 if( origin != VECTOR2I( 0, 0 ) )
384 {
385 m_out->Print( "(aux_axis_origin %s %s)", formatInternalUnits( origin.x ).c_str(),
386 formatInternalUnits( origin.y ).c_str() );
387 }
388
389 origin = dsnSettings.GetGridOrigin();
390
391 if( origin != VECTOR2I( 0, 0 ) )
392 {
393 m_out->Print( "(grid_origin %s %s)", formatInternalUnits( origin.x ).c_str(),
394 formatInternalUnits( origin.y ).c_str() );
395 }
396
398
399 m_out->Print( ")" );
400}
401
402
403void PCB_WRITER_V10::formatGeneral( const BOARD* aBoard ) const
404{
405 const BOARD_DESIGN_SETTINGS& dsnSettings = aBoard->GetDesignSettings();
406
407 m_out->Print( "(general" );
408
409 m_out->Print( "(thickness %s)", formatInternalUnits( dsnSettings.GetBoardThickness() ).c_str() );
410
411 KICAD_FORMAT::LEGACY::FormatBool( m_out, "legacy_teardrops", aBoard->LegacyTeardrops() );
412
413 m_out->Print( ")" );
414
417}
418
419
420void PCB_WRITER_V10::formatBoardLayers( const BOARD* aBoard ) const
421{
422 m_out->Print( "(layers" );
423
424 // Save only the used copper layers from front to back.
425
426 for( PCB_LAYER_ID layer : aBoard->GetEnabledLayers().CuStack() )
427 {
428 m_out->Print( "(%d %s %s %s)", layer, m_out->Quotew( LSET::Name( layer ) ).c_str(),
429 LAYER::ShowType( aBoard->GetLayerType( layer ) ),
430 LSET::Name( layer ) == m_board->GetLayerName( layer )
431 ? ""
432 : m_out->Quotew( m_board->GetLayerName( layer ) ).c_str() );
433 }
434
435 // Save used non-copper layers in the order they are defined.
436 LSEQ seq = aBoard->GetEnabledLayers().TechAndUserUIOrder();
437
438 for( PCB_LAYER_ID layer : seq )
439 {
440 bool print_type = false;
441
442 // User layers (layer id >= User_1) have a qualifier
443 // default is "user", but other qualifiers exist
444 if( layer >= User_1 )
445 {
446 if( IsCopperLayer( layer ) )
447 print_type = true;
448
449 if( aBoard->GetLayerType( layer ) == LT_FRONT || aBoard->GetLayerType( layer ) == LT_BACK )
450 print_type = true;
451 }
452
453 m_out->Print( "(%d %s %s %s)", layer, m_out->Quotew( LSET::Name( layer ) ).c_str(),
454 print_type ? LAYER::ShowType( aBoard->GetLayerType( layer ) ) : "user",
455 m_board->GetLayerName( layer ) == LSET::Name( layer )
456 ? ""
457 : m_out->Quotew( m_board->GetLayerName( layer ) ).c_str() );
458 }
459
460 m_out->Print( ")" );
461}
462
463
464void PCB_WRITER_V10::formatProperties( const BOARD* aBoard ) const
465{
466 for( const std::pair<const wxString, wxString>& prop : aBoard->GetProperties() )
467 {
468 m_out->Print( "(property %s %s)", m_out->Quotew( prop.first ).c_str(), m_out->Quotew( prop.second ).c_str() );
469 }
470}
471
472
473void PCB_WRITER_V10::formatVariants( const BOARD* aBoard ) const
474{
475 const std::vector<wxString>& variantNames = aBoard->GetVariantNames();
476
477 if( variantNames.empty() )
478 return;
479
480 m_out->Print( "(variants" );
481
482 for( const wxString& variantName : variantNames )
483 {
484 m_out->Print( "(variant (name %s)", m_out->Quotew( variantName ).c_str() );
485
486 wxString description = aBoard->GetVariantDescription( variantName );
487
488 if( !description.IsEmpty() )
489 m_out->Print( "(description %s)", m_out->Quotew( description ).c_str() );
490
491 m_out->Print( ")" );
492 }
493
494 m_out->Print( ")" );
495}
496
497
498void PCB_WRITER_V10::formatHeader( const BOARD* aBoard ) const
499{
500 formatGeneral( aBoard );
501
502 // Layers list.
503 formatBoardLayers( aBoard );
504
505 // Setup
506 formatSetup( aBoard );
507
508 // Properties
509 formatProperties( aBoard );
510
511 // Variants
512 formatVariants( aBoard );
513}
514
515
517{
518 static const TEARDROP_PARAMETERS defaults;
519
520 return tdParams.m_Enabled == defaults.m_Enabled && tdParams.m_BestLengthRatio == defaults.m_BestLengthRatio
521 && tdParams.m_TdMaxLen == defaults.m_TdMaxLen && tdParams.m_BestWidthRatio == defaults.m_BestWidthRatio
522 && tdParams.m_TdMaxWidth == defaults.m_TdMaxWidth && tdParams.m_CurvedEdges == defaults.m_CurvedEdges
524 && tdParams.m_AllowUseTwoTracks == defaults.m_AllowUseTwoTracks
525 && tdParams.m_TdOnPadsInZones == defaults.m_TdOnPadsInZones;
526}
527
528
530{
531 m_out->Print( "(teardrops (best_length_ratio %s) (max_length %s) (best_width_ratio %s) "
532 "(max_width %s)",
533 FormatDouble2Str( tdParams.m_BestLengthRatio ).c_str(),
534 formatInternalUnits( tdParams.m_TdMaxLen ).c_str(),
535 FormatDouble2Str( tdParams.m_BestWidthRatio ).c_str(),
536 formatInternalUnits( tdParams.m_TdMaxWidth ).c_str() );
537
538 KICAD_FORMAT::LEGACY::FormatBool( m_out, "curved_edges", tdParams.m_CurvedEdges );
539
540 m_out->Print( "(filter_ratio %s)", FormatDouble2Str( tdParams.m_WidthtoSizeFilterRatio ).c_str() );
541
542 KICAD_FORMAT::LEGACY::FormatBool( m_out, "enabled", tdParams.m_Enabled );
543 KICAD_FORMAT::LEGACY::FormatBool( m_out, "allow_two_segments", tdParams.m_AllowUseTwoTracks );
544 KICAD_FORMAT::LEGACY::FormatBool( m_out, "prefer_zone_connections", !tdParams.m_TdOnPadsInZones );
545 m_out->Print( ")" );
546}
547
548
549void PCB_WRITER_V10::format( const BOARD* aBoard ) const
550{
551 std::set<BOARD_ITEM*, BOARD_ITEM::ptr_cmp> sorted_footprints( aBoard->Footprints().begin(),
552 aBoard->Footprints().end() );
553 std::set<BOARD_ITEM*, BOARD::cmp_drawings> sorted_drawings( aBoard->Drawings().begin(), aBoard->Drawings().end() );
554 std::set<PCB_TRACK*, PCB_TRACK::cmp_tracks> sorted_tracks( aBoard->Tracks().begin(), aBoard->Tracks().end() );
555 std::set<PCB_POINT*, PCB_POINT::cmp_points> sorted_points( aBoard->Points().begin(), aBoard->Points().end() );
556 std::set<BOARD_ITEM*, BOARD_ITEM::ptr_cmp> sorted_zones( aBoard->Zones().begin(), aBoard->Zones().end() );
557 std::set<BOARD_ITEM*, BOARD_ITEM::ptr_cmp> sorted_groups( aBoard->Groups().begin(), aBoard->Groups().end() );
558 std::set<BOARD_ITEM*, BOARD_ITEM::ptr_cmp> sorted_generators( aBoard->Generators().begin(),
559 aBoard->Generators().end() );
560 formatHeader( aBoard );
561
562 // Save the footprints.
563 for( BOARD_ITEM* footprint : sorted_footprints )
564 Format( footprint );
565
566 // Save the graphical items on the board (not owned by a footprint)
567 for( BOARD_ITEM* item : sorted_drawings )
568 Format( item );
569
570 // Save the points
571 for( PCB_POINT* point : sorted_points )
572 Format( point );
573
574 // Do not save PCB_MARKERs, they can be regenerated easily.
575
576 // Save the tracks and vias.
577 for( PCB_TRACK* track : sorted_tracks )
578 Format( track );
579
580 // Save the polygon (which are the newer technology) zones.
581 for( auto zone : sorted_zones )
582 Format( zone );
583
584 // Save the groups
585 for( BOARD_ITEM* group : sorted_groups )
586 Format( group );
587
588 // Save the generators
589 for( BOARD_ITEM* gen : sorted_generators )
590 Format( gen );
591
592 // Save any embedded files
593 // Consolidate the embedded models in footprints into a single map
594 // to avoid duplicating the same model in the board file.
595 EMBEDDED_FILES files_to_write;
596
597 for( auto& file : aBoard->GetEmbeddedFiles()->EmbeddedFileMap() )
598 files_to_write.AddFile( file.second );
599
600 for( BOARD_ITEM* item : sorted_footprints )
601 {
602 FOOTPRINT* fp = static_cast<FOOTPRINT*>( item );
603
604 for( auto& file : fp->GetEmbeddedFiles()->EmbeddedFileMap() )
605 files_to_write.AddFile( file.second );
606 }
607
608 m_out->Print( "(embedded_fonts %s)", aBoard->GetEmbeddedFiles()->GetAreFontsEmbedded() ? "yes" : "no" );
609
610 if( !files_to_write.IsEmpty() )
612
613 // Remove the files so that they are not freed in the DTOR
614 files_to_write.ClearEmbeddedFiles( false );
615}
616
617
618void PCB_WRITER_V10::format( const PCB_DIMENSION_BASE* aDimension ) const
619{
620 const PCB_DIM_ALIGNED* aligned = dynamic_cast<const PCB_DIM_ALIGNED*>( aDimension );
621 const PCB_DIM_ORTHOGONAL* ortho = dynamic_cast<const PCB_DIM_ORTHOGONAL*>( aDimension );
622 const PCB_DIM_CENTER* center = dynamic_cast<const PCB_DIM_CENTER*>( aDimension );
623 const PCB_DIM_RADIAL* radial = dynamic_cast<const PCB_DIM_RADIAL*>( aDimension );
624 const PCB_DIM_LEADER* leader = dynamic_cast<const PCB_DIM_LEADER*>( aDimension );
625
626 m_out->Print( "(dimension" );
627
628 if( ortho ) // must be tested before aligned, because ortho is derived from aligned
629 // and aligned is not null
630 m_out->Print( "(type orthogonal)" );
631 else if( aligned )
632 m_out->Print( "(type aligned)" );
633 else if( leader )
634 m_out->Print( "(type leader)" );
635 else if( center )
636 m_out->Print( "(type center)" );
637 else if( radial )
638 m_out->Print( "(type radial)" );
639 else
640 wxFAIL_MSG( wxT( "Cannot format unknown dimension type!" ) );
641
642 if( aDimension->IsLocked() )
643 KICAD_FORMAT::LEGACY::FormatBool( m_out, "locked", aDimension->IsLocked() );
644
645 formatLayer( aDimension->GetLayer() );
646
648
649 m_out->Print( "(pts (xy %s %s) (xy %s %s))", formatInternalUnits( aDimension->GetStart().x ).c_str(),
650 formatInternalUnits( aDimension->GetStart().y ).c_str(),
651 formatInternalUnits( aDimension->GetEnd().x ).c_str(),
652 formatInternalUnits( aDimension->GetEnd().y ).c_str() );
653
654 if( aligned )
655 m_out->Print( "(height %s)", formatInternalUnits( aligned->GetHeight() ).c_str() );
656
657 if( radial )
658 {
659 m_out->Print( "(leader_length %s)", formatInternalUnits( radial->GetLeaderLength() ).c_str() );
660 }
661
662 if( ortho )
663 m_out->Print( "(orientation %d)", static_cast<int>( ortho->GetOrientation() ) );
664
665 if( !center )
666 {
667 m_out->Print( "(format (prefix %s) (suffix %s) (units %d) (units_format %d) (precision %d)",
668 m_out->Quotew( aDimension->GetPrefix() ).c_str(),
669 m_out->Quotew( aDimension->GetSuffix() ).c_str(), static_cast<int>( aDimension->GetUnitsMode() ),
670 static_cast<int>( aDimension->GetUnitsFormat() ),
671 static_cast<int>( aDimension->GetPrecision() ) );
672
673 if( aDimension->GetOverrideTextEnabled() )
674 {
675 m_out->Print( "(override_value %s)", m_out->Quotew( aDimension->GetOverrideText() ).c_str() );
676 }
677
678 if( aDimension->GetSuppressZeroes() )
679 KICAD_FORMAT::LEGACY::FormatBool( m_out, "suppress_zeroes", true );
680
681 m_out->Print( ")" );
682 }
683
684 m_out->Print( "(style (thickness %s) (arrow_length %s) (text_position_mode %d)",
685 formatInternalUnits( aDimension->GetLineThickness() ).c_str(),
686 formatInternalUnits( aDimension->GetArrowLength() ).c_str(),
687 static_cast<int>( aDimension->GetTextPositionMode() ) );
688
689 if( ortho || aligned )
690 {
691 switch( aDimension->GetArrowDirection() )
692 {
693 case DIM_ARROW_DIRECTION::OUTWARD: m_out->Print( "(arrow_direction outward)" ); break;
695 m_out->Print( "(arrow_direction inward)" );
696 break;
697 // No default, handle all cases
698 }
699 }
700
701 if( aligned )
702 {
703 m_out->Print( "(extension_height %s)", formatInternalUnits( aligned->GetExtensionHeight() ).c_str() );
704 }
705
706 if( leader )
707 m_out->Print( "(text_frame %d)", static_cast<int>( leader->GetTextBorder() ) );
708
709 m_out->Print( "(extension_offset %s)", formatInternalUnits( aDimension->GetExtensionOffset() ).c_str() );
710
711 if( aDimension->GetKeepTextAligned() )
712 KICAD_FORMAT::LEGACY::FormatBool( m_out, "keep_text_aligned", true );
713
714 m_out->Print( ")" );
715
716 // Write dimension text after all other options to be sure the
717 // text options are known when reading the file
718 if( !center )
719 format( static_cast<const PCB_TEXT*>( aDimension ) );
720
721 m_out->Print( ")" );
722}
723
724
725void PCB_WRITER_V10::format( const PCB_SHAPE* aShape ) const
726{
727 FOOTPRINT* parentFP = aShape->GetParentFootprint();
728 std::string prefix = parentFP ? "fp" : "gr";
729
730 switch( aShape->GetShape() )
731 {
732 case SHAPE_T::SEGMENT:
733 m_out->Print( "(%s_line (start %s) (end %s)", prefix.c_str(),
734 formatInternalUnits( aShape->GetStart(), parentFP ).c_str(),
735 formatInternalUnits( aShape->GetEnd(), parentFP ).c_str() );
736 break;
737
739 m_out->Print( "(%s_rect (start %s) (end %s)", prefix.c_str(),
740 formatInternalUnits( aShape->GetStart(), parentFP ).c_str(),
741 formatInternalUnits( aShape->GetEnd(), parentFP ).c_str() );
742
743 if( aShape->GetCornerRadius() > 0 )
744 m_out->Print( " (radius %s)", formatInternalUnits( aShape->GetCornerRadius() ).c_str() );
745 break;
746
747 case SHAPE_T::CIRCLE:
748 m_out->Print( "(%s_circle (center %s) (end %s)", prefix.c_str(),
749 formatInternalUnits( aShape->GetStart(), parentFP ).c_str(),
750 formatInternalUnits( aShape->GetEnd(), parentFP ).c_str() );
751 break;
752
753 case SHAPE_T::ARC:
754 m_out->Print( "(%s_arc (start %s) (mid %s) (end %s)", prefix.c_str(),
755 formatInternalUnits( aShape->GetStart(), parentFP ).c_str(),
756 formatInternalUnits( aShape->GetArcMid(), parentFP ).c_str(),
757 formatInternalUnits( aShape->GetEnd(), parentFP ).c_str() );
758 break;
759
760 case SHAPE_T::POLY:
761 if( aShape->IsPolyShapeValid() )
762 {
763 const SHAPE_POLY_SET& poly = aShape->GetPolyShape();
764 const SHAPE_LINE_CHAIN& outline = poly.Outline( 0 );
765
766 m_out->Print( "(%s_poly", prefix.c_str() );
767 formatPolyPts( outline, parentFP );
768 }
769 else
770 {
771 return;
772 }
773
774 break;
775
776 case SHAPE_T::BEZIER:
777 m_out->Print( "(%s_curve (pts (xy %s) (xy %s) (xy %s) (xy %s))", prefix.c_str(),
778 formatInternalUnits( aShape->GetStart(), parentFP ).c_str(),
779 formatInternalUnits( aShape->GetBezierC1(), parentFP ).c_str(),
780 formatInternalUnits( aShape->GetBezierC2(), parentFP ).c_str(),
781 formatInternalUnits( aShape->GetEnd(), parentFP ).c_str() );
782 break;
783
784 default: UNIMPLEMENTED_FOR( aShape->SHAPE_T_asString() ); return;
785 };
786
788
789 // The filled flag represents if a solid fill is present on circles, rectangles and polygons
790 if( ( aShape->GetShape() == SHAPE_T::POLY ) || ( aShape->GetShape() == SHAPE_T::RECTANGLE )
791 || ( aShape->GetShape() == SHAPE_T::CIRCLE ) )
792 {
793 switch( aShape->GetFillMode() )
794 {
795 case FILL_T::HATCH: m_out->Print( "(fill hatch)" ); break;
796
797 case FILL_T::REVERSE_HATCH: m_out->Print( "(fill reverse_hatch)" ); break;
798
799 case FILL_T::CROSS_HATCH: m_out->Print( "(fill cross_hatch)" ); break;
800
801 case FILL_T::FILLED_SHAPE: KICAD_FORMAT::LEGACY::FormatBool( m_out, "fill", true ); break;
802
803 default: KICAD_FORMAT::LEGACY::FormatBool( m_out, "fill", false ); break;
804 }
805 }
806
807 if( aShape->IsLocked() )
808 KICAD_FORMAT::LEGACY::FormatBool( m_out, "locked", true );
809
810 if( aShape->GetLayerSet().count() > 1 )
811 formatLayers( aShape->GetLayerSet(), false /* enumerate layers */ );
812 else
813 formatLayer( aShape->GetLayer() );
814
815 if( aShape->HasSolderMask() && aShape->GetLocalSolderMaskMargin().has_value()
816 && IsExternalCopperLayer( aShape->GetLayer() ) )
817 {
818 m_out->Print( "(solder_mask_margin %s)",
819 formatInternalUnits( aShape->GetLocalSolderMaskMargin().value() ).c_str() );
820 }
821
822 if( aShape->GetNetCode() > 0 )
823 m_out->Print( "(net %s)", m_out->Quotew( aShape->GetNetname() ).c_str() );
824
826 m_out->Print( ")" );
827}
828
829
830void PCB_WRITER_V10::format( const PCB_REFERENCE_IMAGE* aBitmap ) const
831{
832 wxCHECK_RET( aBitmap != nullptr && m_out != nullptr, "" );
833
834 const REFERENCE_IMAGE& refImage = aBitmap->GetReferenceImage();
835
836 const wxImage* image = refImage.GetImage().GetImageData();
837
838 wxCHECK_RET( image != nullptr, "wxImage* is NULL" );
839
840 m_out->Print( "(image (at %s %s)", formatInternalUnits( aBitmap->GetPosition().x ).c_str(),
841 formatInternalUnits( aBitmap->GetPosition().y ).c_str() );
842
843 formatLayer( aBitmap->GetLayer() );
844
845 if( refImage.GetImageScale() != 1.0 )
846 m_out->Print( "%s", fmt::format( "(scale {:g})", refImage.GetImageScale() ).c_str() );
847
848 if( aBitmap->IsLocked() )
849 KICAD_FORMAT::LEGACY::FormatBool( m_out, "locked", true );
850
851 wxMemoryOutputStream ostream;
852 refImage.GetImage().SaveImageData( ostream );
853
854 KICAD_FORMAT::LEGACY::FormatStreamData( *m_out, *ostream.GetOutputStreamBuffer() );
855
857 m_out->Print( ")" ); // Closes image token.
858}
859
860
861void PCB_WRITER_V10::format( const PCB_POINT* aPoint ) const
862{
863 m_out->Print( "(point (at %s) (size %s)", formatInternalUnits( aPoint->GetPosition() ).c_str(),
864 formatInternalUnits( aPoint->GetSize() ).c_str() );
865
866 formatLayer( aPoint->GetLayer() );
867
869 m_out->Print( ")" );
870}
871
872
873void PCB_WRITER_V10::format( const PCB_TARGET* aTarget ) const
874{
875 m_out->Print( "(target %s (at %s) (size %s)", ( aTarget->GetShape() ) ? "x" : "plus",
876 formatInternalUnits( aTarget->GetPosition() ).c_str(),
877 formatInternalUnits( aTarget->GetSize() ).c_str() );
878
879 if( aTarget->GetWidth() != 0 )
880 m_out->Print( "(width %s)", formatInternalUnits( aTarget->GetWidth() ).c_str() );
881
882 formatLayer( aTarget->GetLayer() );
884 m_out->Print( ")" );
885}
886
887
888void PCB_WRITER_V10::format( const FOOTPRINT* aFootprint ) const
889{
891 {
892 const wxArrayString* initial_comments = aFootprint->GetInitialComments();
893
894 if( initial_comments )
895 {
896 for( unsigned i = 0; i < initial_comments->GetCount(); ++i )
897 m_out->Print( "%s\n", TO_UTF8( ( *initial_comments )[i] ) );
898 }
899 }
900
901 if( m_ctl & CTL_OMIT_LIBNAME )
902 {
903 m_out->Print( "(footprint %s", m_out->Quotes( aFootprint->GetFPID().GetLibItemName() ).c_str() );
904 }
905 else
906 {
907 m_out->Print( "(footprint %s",
908 m_out->Quotes( KICAD_FORMAT::LEGACY::FormatLibId( aFootprint->GetFPID() ) ).c_str() );
909 }
910
912 {
913 m_out->Print( "(version %d) (generator \"pcbnew\") (generator_version %s)", PCB_WRITER_V10::FORMAT_VERSION,
914 m_out->Quotew( GetMajorMinorVersion() ).c_str() );
915 }
916
917 if( aFootprint->IsLocked() )
918 KICAD_FORMAT::LEGACY::FormatBool( m_out, "locked", true );
919
920 if( aFootprint->IsPlaced() )
921 KICAD_FORMAT::LEGACY::FormatBool( m_out, "placed", true );
922
923 formatLayer( aFootprint->GetLayer() );
924
925 if( !( m_ctl & CTL_OMIT_UUIDS ) )
927
928 if( !( m_ctl & CTL_OMIT_AT ) )
929 {
930 m_out->Print( "(at %s %s)", formatInternalUnits( aFootprint->GetPosition() ).c_str(),
931 aFootprint->GetOrientation().IsZero()
932 ? ""
933 : EDA_UNIT_UTILS::FormatAngle( aFootprint->GetOrientation() ).c_str() );
934 }
935
936 if( !aFootprint->GetLibDescription().IsEmpty() )
937 m_out->Print( "(descr %s)", m_out->Quotew( aFootprint->GetLibDescription() ).c_str() );
938
939 if( !aFootprint->GetKeywords().IsEmpty() )
940 m_out->Print( "(tags %s)", m_out->Quotew( aFootprint->GetKeywords() ).c_str() );
941
942 for( const PCB_FIELD* field : aFootprint->GetFields() )
943 {
944 if( !field )
945 continue;
946
947 m_out->Print( "(property %s %s", m_out->Quotew( field->GetUntranslatedName() ).c_str(),
948 m_out->Quotew( field->GetText() ).c_str() );
949
950 format( field );
951
952 m_out->Print( ")" );
953 }
954
955 if( const COMPONENT_CLASS* compClass = aFootprint->GetStaticComponentClass() )
956 {
957 if( !compClass->IsEmpty() )
958 {
959 m_out->Print( "(component_classes" );
960
961 for( const COMPONENT_CLASS* constituent : compClass->GetConstituentClasses() )
962 m_out->Print( "(class %s)", m_out->Quotew( constituent->GetName() ).c_str() );
963
964 m_out->Print( ")" );
965 }
966 }
967
968 if( !aFootprint->GetFilters().empty() )
969 {
970 m_out->Print( "(property ki_fp_filters %s)", m_out->Quotew( aFootprint->GetFilters() ).c_str() );
971 }
972
973 if( !( m_ctl & CTL_OMIT_PATH ) && !aFootprint->GetPath().empty() )
974 m_out->Print( "(path %s)", m_out->Quotew( aFootprint->GetPath().AsString() ).c_str() );
975
976 if( !aFootprint->GetSheetname().empty() )
977 m_out->Print( "(sheetname %s)", m_out->Quotew( aFootprint->GetSheetname() ).c_str() );
978
979 if( !aFootprint->GetSheetfile().empty() )
980 m_out->Print( "(sheetfile %s)", m_out->Quotew( aFootprint->GetSheetfile() ).c_str() );
981
982 // Emit unit info for gate swapping metadata (flat pin list form)
983 if( !aFootprint->GetUnitInfo().empty() )
984 {
985 m_out->Print( "(units" );
986
987 for( const FOOTPRINT::FP_UNIT_INFO& u : aFootprint->GetUnitInfo() )
988 {
989 m_out->Print( "(unit (name %s)", m_out->Quotew( u.m_unitName ).c_str() );
990 m_out->Print( "(pins" );
991
992 for( const wxString& n : u.m_pins )
993 m_out->Print( " %s", m_out->Quotew( n ).c_str() );
994
995 m_out->Print( ")" ); // </pins>
996 m_out->Print( ")" ); // </unit>
997 }
998
999 m_out->Print( ")" ); // </units>
1000 }
1001
1002 if( aFootprint->GetLocalSolderMaskMargin().has_value() )
1003 {
1004 m_out->Print( "(solder_mask_margin %s)",
1005 formatInternalUnits( aFootprint->GetLocalSolderMaskMargin().value() ).c_str() );
1006 }
1007
1008 if( aFootprint->GetLocalSolderPasteMargin().has_value() )
1009 {
1010 m_out->Print( "(solder_paste_margin %s)",
1011 formatInternalUnits( aFootprint->GetLocalSolderPasteMargin().value() ).c_str() );
1012 }
1013
1014 if( aFootprint->GetLocalSolderPasteMarginRatio().has_value() )
1015 {
1016 m_out->Print( "(solder_paste_margin_ratio %s)",
1017 FormatDouble2Str( aFootprint->GetLocalSolderPasteMarginRatio().value() ).c_str() );
1018 }
1019
1020 if( aFootprint->GetLocalClearance().has_value() )
1021 {
1022 m_out->Print( "(clearance %s)", formatInternalUnits( aFootprint->GetLocalClearance().value() ).c_str() );
1023 }
1024
1026 {
1027 m_out->Print( "(zone_connect %d)", static_cast<int>( aFootprint->GetLocalZoneConnection() ) );
1028 }
1029
1030 // Attributes
1031 if( aFootprint->GetAttributes() || aFootprint->AllowMissingCourtyard() || aFootprint->AllowSolderMaskBridges() )
1032 {
1033 m_out->Print( "(attr" );
1034
1035 if( aFootprint->GetAttributes() & FP_SMD )
1036 m_out->Print( " smd" );
1037
1038 if( aFootprint->GetAttributes() & FP_THROUGH_HOLE )
1039 m_out->Print( " through_hole" );
1040
1041 if( aFootprint->GetAttributes() & FP_BOARD_ONLY )
1042 m_out->Print( " board_only" );
1043
1044 if( aFootprint->GetAttributes() & FP_EXCLUDE_FROM_POS_FILES )
1045 m_out->Print( " exclude_from_pos_files" );
1046
1047 if( aFootprint->GetAttributes() & FP_EXCLUDE_FROM_BOM )
1048 m_out->Print( " exclude_from_bom" );
1049
1050 if( aFootprint->AllowMissingCourtyard() )
1051 m_out->Print( " allow_missing_courtyard" );
1052
1053 if( aFootprint->GetAttributes() & FP_DNP )
1054 m_out->Print( " dnp" );
1055
1056 if( aFootprint->AllowSolderMaskBridges() )
1057 m_out->Print( " allow_soldermask_bridges" );
1058
1059 m_out->Print( ")" );
1060 }
1061
1062 // Expand inner layers is the default stackup mode
1064 {
1065 m_out->Print( "(stackup" );
1066
1067 const LSET& fpLset = aFootprint->GetStackupLayers();
1068 for( PCB_LAYER_ID layer : fpLset.Seq() )
1069 {
1070 wxString canonicalName( LSET::Name( layer ) );
1071 m_out->Print( "(layer %s)", m_out->Quotew( canonicalName ).c_str() );
1072 }
1073
1074 m_out->Print( ")" );
1075 }
1076
1077 if( aFootprint->GetPrivateLayers().any() )
1078 {
1079 m_out->Print( "(private_layers" );
1080
1081 for( PCB_LAYER_ID layer : aFootprint->GetPrivateLayers().Seq() )
1082 {
1083 wxString canonicalName( LSET::Name( layer ) );
1084 m_out->Print( " %s", m_out->Quotew( canonicalName ).c_str() );
1085 }
1086
1087 m_out->Print( ")" );
1088 }
1089
1090 if( aFootprint->IsNetTie() )
1091 {
1092 m_out->Print( "(net_tie_pad_groups" );
1093
1094 for( const wxString& group : aFootprint->GetNetTiePadGroups() )
1095 m_out->Print( " %s", m_out->Quotew( group ).c_str() );
1096
1097 m_out->Print( ")" );
1098 }
1099
1100 KICAD_FORMAT::LEGACY::FormatBool( m_out, "duplicate_pad_numbers_are_jumpers",
1101 aFootprint->GetDuplicatePadNumbersAreJumpers() );
1102
1103 const JUMPER_GROUP_SET& jumperGroups = aFootprint->JumperPadGroups();
1104
1105 if( !jumperGroups.IsEmpty() )
1106 {
1107 m_out->Print( "(jumper_pad_groups" );
1108
1109 for( const JUMPER_GROUP& group : jumperGroups.GetAll() )
1110 {
1111 m_out->Print( "(" );
1112
1113 for( const wxString& padName : group.GetNames() )
1114 m_out->Print( "%s ", m_out->Quotew( padName ).c_str() );
1115
1116 m_out->Print( ")" );
1117 }
1118
1119 m_out->Print( ")" );
1120 }
1121
1122 Format( &aFootprint->Reference() );
1123 Format( &aFootprint->Value() );
1124
1125 std::set<PAD*, FOOTPRINT::cmp_pads> sorted_pads( aFootprint->Pads().begin(), aFootprint->Pads().end() );
1126 std::set<BOARD_ITEM*, KICAD_FORMAT::LEGACY::FP_DRAWING_ORDER_V10> sorted_drawings(
1127 aFootprint->GraphicalItems().begin(), aFootprint->GraphicalItems().end() );
1128 std::set<PCB_POINT*, PCB_POINT::cmp_points> sorted_points( aFootprint->Points().begin(),
1129 aFootprint->Points().end() );
1130 std::set<ZONE*, FOOTPRINT::cmp_zones> sorted_zones( aFootprint->Zones().begin(), aFootprint->Zones().end() );
1131 std::set<BOARD_ITEM*, PCB_GROUP::ptr_cmp> sorted_groups( aFootprint->Groups().begin(), aFootprint->Groups().end() );
1132
1133 // Save drawing elements.
1134
1135 for( BOARD_ITEM* gr : sorted_drawings )
1136 Format( gr );
1137
1138 for( PCB_POINT* point : sorted_points )
1139 Format( point );
1140
1141 // Save pads.
1142 for( PAD* pad : sorted_pads )
1143 Format( pad );
1144
1145 // Save zones.
1146 for( BOARD_ITEM* zone : sorted_zones )
1147 Format( zone );
1148
1149 // Save groups.
1150 for( BOARD_ITEM* group : sorted_groups )
1151 Format( group );
1152
1153 // Save variants.
1154 const bool baseDnp = aFootprint->IsDNP();
1155 const bool baseExcludedFromBOM = aFootprint->IsExcludedFromBOM();
1156 const bool baseExcludedFromPosFiles = aFootprint->IsExcludedFromPosFiles();
1157
1158 for( const auto& [variantName, variant] : aFootprint->GetVariants() )
1159 {
1160 m_out->Print( "(variant (name %s)", m_out->Quotew( variantName ).c_str() );
1161
1162 if( variant.GetDNP() != baseDnp )
1163 KICAD_FORMAT::LEGACY::FormatBool( m_out, "dnp", variant.GetDNP() );
1164
1165 if( variant.GetExcludedFromBOM() != baseExcludedFromBOM )
1166 KICAD_FORMAT::LEGACY::FormatBool( m_out, "exclude_from_bom", variant.GetExcludedFromBOM() );
1167
1168 if( variant.GetExcludedFromPosFiles() != baseExcludedFromPosFiles )
1169 {
1170 KICAD_FORMAT::LEGACY::FormatBool( m_out, "exclude_from_pos_files", variant.GetExcludedFromPosFiles() );
1171 }
1172
1173 for( const auto& [fieldName, fieldValue] : variant.GetFields() )
1174 {
1175 const PCB_FIELD* baseField = aFootprint->GetField( fieldName );
1176 const wxString baseValue = baseField ? baseField->GetText() : wxString();
1177
1178 if( fieldValue == baseValue )
1179 continue;
1180
1181 m_out->Print( "(field (name %s) (value %s))", m_out->Quotew( fieldName ).c_str(),
1182 m_out->Quotew( fieldValue ).c_str() );
1183 }
1184
1185 m_out->Print( ")" );
1186 }
1187
1188 KICAD_FORMAT::LEGACY::FormatBool( m_out, "embedded_fonts", aFootprint->GetEmbeddedFiles()->GetAreFontsEmbedded() );
1189
1190 if( !aFootprint->GetEmbeddedFiles()->IsEmpty() )
1192
1193 // Save 3D info.
1194 auto bs3D = aFootprint->Models().begin();
1195 auto es3D = aFootprint->Models().end();
1196
1197 while( bs3D != es3D )
1198 {
1199 if( !bs3D->m_Filename.IsEmpty() )
1200 {
1201 m_out->Print( "(model %s", m_out->Quotew( bs3D->m_Filename ).c_str() );
1202
1203 if( !bs3D->m_Show )
1204 KICAD_FORMAT::LEGACY::FormatBool( m_out, "hide", !bs3D->m_Show );
1205
1206 if( bs3D->m_Opacity != 1.0 )
1207 m_out->Print( "%s", fmt::format( "(opacity {:.4f})", bs3D->m_Opacity ).c_str() );
1208
1209 m_out->Print( "(offset (xyz %s %s %s))", FormatDouble2Str( bs3D->m_Offset.x ).c_str(),
1210 FormatDouble2Str( bs3D->m_Offset.y ).c_str(), FormatDouble2Str( bs3D->m_Offset.z ).c_str() );
1211
1212 m_out->Print( "(scale (xyz %s %s %s))", FormatDouble2Str( bs3D->m_Scale.x ).c_str(),
1213 FormatDouble2Str( bs3D->m_Scale.y ).c_str(), FormatDouble2Str( bs3D->m_Scale.z ).c_str() );
1214
1215 m_out->Print( "(rotate (xyz %s %s %s))", FormatDouble2Str( bs3D->m_Rotation.x ).c_str(),
1216 FormatDouble2Str( bs3D->m_Rotation.y ).c_str(),
1217 FormatDouble2Str( bs3D->m_Rotation.z ).c_str() );
1218
1219 m_out->Print( ")" );
1220 }
1221
1222 ++bs3D;
1223 }
1224
1225 m_out->Print( ")" );
1226}
1227
1228
1229void PCB_WRITER_V10::formatLayers( LSET aLayerMask, bool aEnumerateLayers, bool aIsZone ) const
1230{
1231 static const LSET cu_all( LSET::AllCuMask() );
1232 static const LSET fr_bk( { B_Cu, F_Cu } );
1233 static const LSET adhes( { B_Adhes, F_Adhes } );
1234 static const LSET paste( { B_Paste, F_Paste } );
1235 static const LSET silks( { B_SilkS, F_SilkS } );
1236 static const LSET mask( { B_Mask, F_Mask } );
1237 static const LSET crt_yd( { B_CrtYd, F_CrtYd } );
1238 static const LSET fab( { B_Fab, F_Fab } );
1239
1240 LSET cu_board_mask = LSET::AllCuMask( m_board ? m_board->GetCopperLayerCount() : MAX_CU_LAYERS );
1241
1242 std::string output;
1243
1244 if( !aEnumerateLayers )
1245 {
1246 // If all copper layers present on the board are enabled, then output the wildcard
1247 if( ( aLayerMask & cu_board_mask ) == cu_board_mask )
1248 {
1249 output += ' ' + m_out->Quotew( "*.Cu" );
1250
1251 // Clear all copper bits because pads might have internal layers that aren't part of the
1252 // board enabled, and we don't want to output those in the layers listing if we already
1253 // output the wildcard.
1254 aLayerMask &= ~cu_all;
1255 }
1256 else if( ( aLayerMask & cu_board_mask ) == fr_bk )
1257 {
1258 if( aIsZone )
1259 output += ' ' + m_out->Quotew( "F&B.Cu" );
1260 else
1261 output += ' ' + m_out->Quotew( "*.Cu" );
1262
1263 aLayerMask &= ~fr_bk;
1264 }
1265
1266 if( ( aLayerMask & adhes ) == adhes )
1267 {
1268 output += ' ' + m_out->Quotew( "*.Adhes" );
1269 aLayerMask &= ~adhes;
1270 }
1271
1272 if( ( aLayerMask & paste ) == paste )
1273 {
1274 output += ' ' + m_out->Quotew( "*.Paste" );
1275 aLayerMask &= ~paste;
1276 }
1277
1278 if( ( aLayerMask & silks ) == silks )
1279 {
1280 output += ' ' + m_out->Quotew( "*.SilkS" );
1281 aLayerMask &= ~silks;
1282 }
1283
1284 if( ( aLayerMask & mask ) == mask )
1285 {
1286 output += ' ' + m_out->Quotew( "*.Mask" );
1287 aLayerMask &= ~mask;
1288 }
1289
1290 if( ( aLayerMask & crt_yd ) == crt_yd )
1291 {
1292 output += ' ' + m_out->Quotew( "*.CrtYd" );
1293 aLayerMask &= ~crt_yd;
1294 }
1295
1296 if( ( aLayerMask & fab ) == fab )
1297 {
1298 output += ' ' + m_out->Quotew( "*.Fab" );
1299 aLayerMask &= ~fab;
1300 }
1301 }
1302
1303 // output any individual layers not handled in wildcard combos above
1304 for( int layer = 0; layer < PCB_LAYER_ID_COUNT; ++layer )
1305 {
1306 if( aLayerMask[layer] )
1307 output += ' ' + m_out->Quotew( LSET::Name( PCB_LAYER_ID( layer ) ) );
1308 }
1309
1310 m_out->Print( "(layers %s)", output.c_str() );
1311}
1312
1313
1314void PCB_WRITER_V10::format( const PAD* aPad ) const
1315{
1316 const BOARD* board = aPad->GetBoard();
1317
1318 auto shapeName = [&]( PCB_LAYER_ID aLayer )
1319 {
1320 switch( aPad->GetShape( aLayer ) )
1321 {
1322 case PAD_SHAPE::CIRCLE: return "circle";
1323 case PAD_SHAPE::RECTANGLE: return "rect";
1324 case PAD_SHAPE::OVAL: return "oval";
1325 case PAD_SHAPE::TRAPEZOID: return "trapezoid";
1327 case PAD_SHAPE::ROUNDRECT: return "roundrect";
1328 case PAD_SHAPE::CUSTOM: return "custom";
1329
1330 default: THROW_IO_ERROR( wxString::Format( _( "unknown pad type: %d" ), aPad->GetShape( aLayer ) ) );
1331 }
1332 };
1333
1334 const char* type;
1335
1336 switch( aPad->GetAttribute() )
1337 {
1338 case PAD_ATTRIB::PTH: type = "thru_hole"; break;
1339 case PAD_ATTRIB::SMD: type = "smd"; break;
1340 case PAD_ATTRIB::CONN: type = "connect"; break;
1341 case PAD_ATTRIB::NPTH: type = "np_thru_hole"; break;
1342
1343 default: THROW_IO_ERROR( wxString::Format( wxT( "unknown pad attribute: %d" ), aPad->GetAttribute() ) );
1344 }
1345
1346 const char* property = nullptr;
1347
1348 switch( aPad->GetProperty() )
1349 {
1350 case PAD_PROP::NONE: break; // could be "none"
1351 case PAD_PROP::BGA: property = "pad_prop_bga"; break;
1352 case PAD_PROP::FIDUCIAL_GLBL: property = "pad_prop_fiducial_glob"; break;
1353 case PAD_PROP::FIDUCIAL_LOCAL: property = "pad_prop_fiducial_loc"; break;
1354 case PAD_PROP::TESTPOINT: property = "pad_prop_testpoint"; break;
1355 case PAD_PROP::HEATSINK: property = "pad_prop_heatsink"; break;
1356 case PAD_PROP::CASTELLATED: property = "pad_prop_castellated"; break;
1357 case PAD_PROP::MECHANICAL: property = "pad_prop_mechanical"; break;
1358 case PAD_PROP::PRESSFIT: property = "pad_prop_pressfit"; break;
1359
1360 default: THROW_IO_ERROR( wxString::Format( wxT( "unknown pad property: %d" ), aPad->GetProperty() ) );
1361 }
1362
1363 m_out->Print( "(pad %s %s %s", m_out->Quotew( aPad->GetNumber() ).c_str(), type, shapeName( F_Cu ) );
1364
1365 m_out->Print( "(at %s %s)", formatInternalUnits( aPad->GetFPRelativePosition() ).c_str(),
1366 aPad->GetOrientation().IsZero() ? ""
1367 : EDA_UNIT_UTILS::FormatAngle( aPad->GetOrientation() ).c_str() );
1368
1369 m_out->Print( "(size %s)", formatInternalUnits( aPad->GetSize( F_Cu ) ).c_str() );
1370
1371 if( aPad->GetDelta( F_Cu ).x != 0 || aPad->GetDelta( F_Cu ).y != 0 )
1372 {
1373 m_out->Print( "(rect_delta %s)", formatInternalUnits( aPad->GetDelta( F_Cu ) ).c_str() );
1374 }
1375
1376 const VECTOR2I& drill = aPad->GetDrillSize();
1377 VECTOR2I shapeoffset = aPad->GetOffset( F_Cu );
1378 bool forceShapeOffsetOutput = false;
1379
1381 [&]( PCB_LAYER_ID layer )
1382 {
1383 if( aPad->GetOffset( layer ) != shapeoffset )
1384 forceShapeOffsetOutput = true;
1385 } );
1386
1387 if( drill.x > 0 || drill.y > 0 || shapeoffset.x != 0 || shapeoffset.y != 0 || forceShapeOffsetOutput )
1388 {
1389 m_out->Print( "(drill" );
1390
1391 if( aPad->GetDrillShape() == PAD_DRILL_SHAPE::OBLONG )
1392 m_out->Print( " oval" );
1393
1394 if( drill.x > 0 )
1395 m_out->Print( " %s", formatInternalUnits( drill.x ).c_str() );
1396
1397 if( drill.y > 0 && drill.x != drill.y )
1398 m_out->Print( " %s", formatInternalUnits( drill.y ).c_str() );
1399
1400 // NOTE: Shape offest is a property of the copper shape, not of the drill, but this was put
1401 // in the file format under the drill section. So, it is left here to minimize file format
1402 // changes, but note that the other padstack layers (if present) will have an offset stored
1403 // separately.
1404 if( shapeoffset.x != 0 || shapeoffset.y != 0 || forceShapeOffsetOutput )
1405 m_out->Print( "(offset %s)", formatInternalUnits( aPad->GetOffset( F_Cu ) ).c_str() );
1406
1407 m_out->Print( ")" );
1408 }
1409
1410 if( aPad->Padstack().SecondaryDrill().size.x > 0 )
1411 {
1412 m_out->Print( "(backdrill (size %s) (layers %s %s))",
1413 formatInternalUnits( aPad->Padstack().SecondaryDrill().size.x ).c_str(),
1414 m_out->Quotew( LSET::Name( aPad->Padstack().SecondaryDrill().start ) ).c_str(),
1415 m_out->Quotew( LSET::Name( aPad->Padstack().SecondaryDrill().end ) ).c_str() );
1416 }
1417
1418 if( aPad->Padstack().TertiaryDrill().size.x > 0 )
1419 {
1420 m_out->Print( "(tertiary_drill (size %s) (layers %s %s))",
1421 formatInternalUnits( aPad->Padstack().TertiaryDrill().size.x ).c_str(),
1422 m_out->Quotew( LSET::Name( aPad->Padstack().TertiaryDrill().start ) ).c_str(),
1423 m_out->Quotew( LSET::Name( aPad->Padstack().TertiaryDrill().end ) ).c_str() );
1424 }
1425
1426 auto formatPostMachining = [&]( const char* aName, const PADSTACK::POST_MACHINING_PROPS& aProps )
1427 {
1428 if( !aProps.mode.has_value() || aProps.mode == PAD_DRILL_POST_MACHINING_MODE::NOT_POST_MACHINED )
1429 return;
1430
1431 m_out->Print( "(%s %s", aName,
1432 aProps.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE ? "counterbore" : "countersink" );
1433
1434 if( aProps.size > 0 )
1435 m_out->Print( " (size %s)", formatInternalUnits( aProps.size ).c_str() );
1436
1437 if( aProps.depth > 0 )
1438 m_out->Print( " (depth %s)", formatInternalUnits( aProps.depth ).c_str() );
1439
1440 if( aProps.angle > 0 )
1441 m_out->Print( " (angle %s)", FormatDouble2Str( aProps.angle / 10.0 ).c_str() );
1442
1443 m_out->Print( ")" );
1444 };
1445
1446 formatPostMachining( "front_post_machining", aPad->Padstack().FrontPostMachining() );
1447 formatPostMachining( "back_post_machining", aPad->Padstack().BackPostMachining() );
1448
1449 // Add pad property, if exists.
1450 if( property )
1451 m_out->Print( "(property %s)", property );
1452
1453 formatLayers( aPad->GetLayerSet(), false /* enumerate layers */ );
1454
1455 if( aPad->GetAttribute() == PAD_ATTRIB::PTH )
1456 {
1457 KICAD_FORMAT::LEGACY::FormatBool( m_out, "remove_unused_layers", aPad->GetRemoveUnconnected() );
1458
1459 if( aPad->GetRemoveUnconnected() )
1460 {
1461 KICAD_FORMAT::LEGACY::FormatBool( m_out, "keep_end_layers", aPad->GetKeepTopBottom() );
1462
1463 if( board ) // Will be nullptr in footprint library
1464 {
1465 m_out->Print( "(zone_layer_connections" );
1466
1467 for( PCB_LAYER_ID layer : board->GetEnabledLayers().CuStack() )
1468 {
1469 if( aPad->GetZoneLayerOverride( layer ) == ZLO_FORCE_FLASHED )
1470 m_out->Print( " %s", m_out->Quotew( LSET::Name( layer ) ).c_str() );
1471 }
1472
1473 m_out->Print( ")" );
1474 }
1475 }
1476 }
1477
1478 auto formatCornerProperties = [&]( PCB_LAYER_ID aLayer )
1479 {
1480 // Output the radius ratio for rounded and chamfered rect pads
1481 if( aPad->GetShape( aLayer ) == PAD_SHAPE::ROUNDRECT || aPad->GetShape( aLayer ) == PAD_SHAPE::CHAMFERED_RECT )
1482 {
1483 m_out->Print( "(roundrect_rratio %s)",
1484 FormatDouble2Str( aPad->GetRoundRectRadiusRatio( aLayer ) ).c_str() );
1485 }
1486
1487 // Output the chamfer corners for chamfered rect pads
1488 if( aPad->GetShape( aLayer ) == PAD_SHAPE::CHAMFERED_RECT )
1489 {
1490 m_out->Print( "(chamfer_ratio %s)", FormatDouble2Str( aPad->GetChamferRectRatio( aLayer ) ).c_str() );
1491
1492 m_out->Print( "(chamfer" );
1493
1494 if( ( aPad->GetChamferPositions( aLayer ) & RECT_CHAMFER_TOP_LEFT ) )
1495 m_out->Print( " top_left" );
1496
1497 if( ( aPad->GetChamferPositions( aLayer ) & RECT_CHAMFER_TOP_RIGHT ) )
1498 m_out->Print( " top_right" );
1499
1500 if( ( aPad->GetChamferPositions( aLayer ) & RECT_CHAMFER_BOTTOM_LEFT ) )
1501 m_out->Print( " bottom_left" );
1502
1503 if( ( aPad->GetChamferPositions( aLayer ) & RECT_CHAMFER_BOTTOM_RIGHT ) )
1504 m_out->Print( " bottom_right" );
1505
1506 m_out->Print( ")" );
1507 }
1508 };
1509
1510 // For normal padstacks, this is the one and only set of properties. For complex ones, this
1511 // will represent the front layer properties, and other layers will be formatted below
1512 formatCornerProperties( F_Cu );
1513
1514 // Unconnected pad is default net so don't save it.
1515 if( !( m_ctl & CTL_OMIT_PAD_NETS ) && aPad->GetNetCode() > 0 )
1516 m_out->Print( "(net %s)", m_out->Quotew( aPad->GetNetname() ).c_str() );
1517
1518 // Pin functions and types are closely related to nets, so if CTL_OMIT_NETS is set, omit
1519 // them as well (for instance when saved from library editor).
1520 if( !( m_ctl & CTL_OMIT_PAD_NETS ) )
1521 {
1522 if( !aPad->GetPinFunction().IsEmpty() )
1523 m_out->Print( "(pinfunction %s)", m_out->Quotew( aPad->GetPinFunction() ).c_str() );
1524
1525 if( !aPad->GetPinType().IsEmpty() )
1526 m_out->Print( "(pintype %s)", m_out->Quotew( aPad->GetPinType() ).c_str() );
1527 }
1528
1529 if( aPad->GetPadToDieLength() != 0 )
1530 {
1531 m_out->Print( "(die_length %s)", formatInternalUnits( aPad->GetPadToDieLength() ).c_str() );
1532 }
1533
1534 if( aPad->GetPadToDieDelay() != 0 )
1535 {
1536 m_out->Print( "(die_delay %s)", formatInternalUnits( aPad->GetPadToDieDelay(), EDA_DATA_TYPE::TIME ).c_str() );
1537 }
1538
1539 if( aPad->GetLocalSolderMaskMargin().has_value() )
1540 {
1541 m_out->Print( "(solder_mask_margin %s)",
1542 formatInternalUnits( aPad->GetLocalSolderMaskMargin().value() ).c_str() );
1543 }
1544
1545 if( aPad->GetLocalSolderPasteMargin().has_value() )
1546 {
1547 m_out->Print( "(solder_paste_margin %s)",
1548 formatInternalUnits( aPad->GetLocalSolderPasteMargin().value() ).c_str() );
1549 }
1550
1551 if( aPad->GetLocalSolderPasteMarginRatio().has_value() )
1552 {
1553 m_out->Print( "(solder_paste_margin_ratio %s)",
1554 FormatDouble2Str( aPad->GetLocalSolderPasteMarginRatio().value() ).c_str() );
1555 }
1556
1557 if( aPad->GetLocalClearance().has_value() )
1558 {
1559 m_out->Print( "(clearance %s)", formatInternalUnits( aPad->GetLocalClearance().value() ).c_str() );
1560 }
1561
1563 {
1564 m_out->Print( "(zone_connect %d)", static_cast<int>( aPad->GetLocalZoneConnection() ) );
1565 }
1566
1567 if( aPad->GetLocalThermalSpokeWidthOverride().has_value() )
1568 {
1569 m_out->Print( "(thermal_bridge_width %s)",
1570 formatInternalUnits( aPad->GetLocalThermalSpokeWidthOverride().value() ).c_str() );
1571 }
1572
1573 EDA_ANGLE defaultThermalSpokeAngle = ANGLE_90;
1574
1575 if( aPad->GetShape( F_Cu ) == PAD_SHAPE::CIRCLE
1576 || ( aPad->GetShape( F_Cu ) == PAD_SHAPE::CUSTOM && aPad->GetAnchorPadShape( F_Cu ) == PAD_SHAPE::CIRCLE ) )
1577 {
1578 defaultThermalSpokeAngle = ANGLE_45;
1579 }
1580
1581 if( aPad->GetThermalSpokeAngle() != defaultThermalSpokeAngle )
1582 {
1583 m_out->Print( "(thermal_bridge_angle %s)",
1585 }
1586
1587 if( aPad->GetLocalThermalGapOverride().has_value() )
1588 {
1589 m_out->Print( "(thermal_gap %s)", formatInternalUnits( aPad->GetLocalThermalGapOverride().value() ).c_str() );
1590 }
1591
1592 auto anchorShape = [&]( PCB_LAYER_ID aLayer )
1593 {
1594 switch( aPad->GetAnchorPadShape( aLayer ) )
1595 {
1596 case PAD_SHAPE::RECTANGLE: return "rect";
1597 default:
1598 case PAD_SHAPE::CIRCLE: return "circle";
1599 }
1600 };
1601
1602 auto formatPrimitives = [&]( PCB_LAYER_ID aLayer )
1603 {
1604 m_out->Print( "(primitives" );
1605
1606 // Output all basic shapes
1607 for( const std::shared_ptr<PCB_SHAPE>& primitive : aPad->GetPrimitives( aLayer ) )
1608 {
1609 // Set false by any branch that opens no node. The width, the fill and the closing
1610 // paren below belong to that node, so emitting them without it corrupts the file.
1611 bool emitted = true;
1612
1613 switch( primitive->GetShape() )
1614 {
1615 case SHAPE_T::SEGMENT:
1616 if( primitive->IsProxyItem() )
1617 {
1618 m_out->Print( "(gr_vector (start %s) (end %s)",
1619 formatInternalUnits( primitive->GetStart() ).c_str(),
1620 formatInternalUnits( primitive->GetEnd() ).c_str() );
1621 }
1622 else
1623 {
1624 m_out->Print( "(gr_line (start %s) (end %s)", formatInternalUnits( primitive->GetStart() ).c_str(),
1625 formatInternalUnits( primitive->GetEnd() ).c_str() );
1626 }
1627 break;
1628
1629 case SHAPE_T::RECTANGLE:
1630 if( primitive->IsProxyItem() )
1631 {
1632 m_out->Print( "(gr_bbox (start %s) (end %s)", formatInternalUnits( primitive->GetStart() ).c_str(),
1633 formatInternalUnits( primitive->GetEnd() ).c_str() );
1634 }
1635 else
1636 {
1637 m_out->Print( "(gr_rect (start %s) (end %s)", formatInternalUnits( primitive->GetStart() ).c_str(),
1638 formatInternalUnits( primitive->GetEnd() ).c_str() );
1639
1640 if( primitive->GetCornerRadius() > 0 )
1641 {
1642 m_out->Print( " (radius %s)", formatInternalUnits( primitive->GetCornerRadius() ).c_str() );
1643 }
1644 }
1645 break;
1646
1647 case SHAPE_T::ARC:
1648 m_out->Print( "(gr_arc (start %s) (mid %s) (end %s)",
1649 formatInternalUnits( primitive->GetStart() ).c_str(),
1650 formatInternalUnits( primitive->GetArcMid() ).c_str(),
1651 formatInternalUnits( primitive->GetEnd() ).c_str() );
1652 break;
1653
1654 case SHAPE_T::CIRCLE:
1655 m_out->Print( "(gr_circle (center %s) (end %s)", formatInternalUnits( primitive->GetStart() ).c_str(),
1656 formatInternalUnits( primitive->GetEnd() ).c_str() );
1657 break;
1658
1659 case SHAPE_T::BEZIER:
1660 m_out->Print( "(gr_curve (pts (xy %s) (xy %s) (xy %s) (xy %s))",
1661 formatInternalUnits( primitive->GetStart() ).c_str(),
1662 formatInternalUnits( primitive->GetBezierC1() ).c_str(),
1663 formatInternalUnits( primitive->GetBezierC2() ).c_str(),
1664 formatInternalUnits( primitive->GetEnd() ).c_str() );
1665 break;
1666
1667 case SHAPE_T::POLY:
1668 if( !primitive->IsPolyShapeValid() )
1669 {
1670 emitted = false;
1671 }
1672 else
1673 {
1674 const SHAPE_POLY_SET& poly = primitive->GetPolyShape();
1675 const SHAPE_LINE_CHAIN& outline = poly.Outline( 0 );
1676
1677 m_out->Print( "(gr_poly" );
1678 formatPolyPts( outline );
1679 }
1680 break;
1681
1682 default: emitted = false; break;
1683 }
1684
1685 if( !emitted )
1686 continue;
1687
1688 if( !primitive->IsProxyItem() )
1689 m_out->Print( "(width %s)", formatInternalUnits( primitive->GetWidth() ).c_str() );
1690
1691 // The filled flag represents if a solid fill is present on circles,
1692 // rectangles and polygons
1693 if( ( primitive->GetShape() == SHAPE_T::POLY ) || ( primitive->GetShape() == SHAPE_T::RECTANGLE )
1694 || ( primitive->GetShape() == SHAPE_T::CIRCLE ) )
1695 {
1696 KICAD_FORMAT::LEGACY::FormatBool( m_out, "fill", primitive->IsSolidFill() );
1697 }
1698
1699 m_out->Print( ")" );
1700 }
1701
1702 m_out->Print( ")" ); // end of (primitives
1703 };
1704
1705 bool hasCustomLayer = false;
1706
1708 [&]( PCB_LAYER_ID aLayer )
1709 {
1710 hasCustomLayer |= aPad->GetShape( aLayer ) == PAD_SHAPE::CUSTOM;
1711 } );
1712
1713 if( aPad->GetShape( F_Cu ) == PAD_SHAPE::CUSTOM
1714 || ( hasCustomLayer && aPad->GetCustomShapeInZoneOpt() == CUSTOM_SHAPE_ZONE_MODE::CONVEXHULL ) )
1715 {
1716 m_out->Print( "(options" );
1717
1719 m_out->Print( "(clearance convexhull)" );
1720 else
1721 m_out->Print( "(clearance outline)" );
1722
1723 // Output the anchor pad shape (circle/rect)
1724 m_out->Print( "(anchor %s)", anchorShape( F_Cu ) );
1725
1726 m_out->Print( ")" ); // end of (options ...
1727
1728 // Output graphic primitive of the pad shape
1729 if( aPad->GetShape( F_Cu ) == PAD_SHAPE::CUSTOM )
1730 formatPrimitives( F_Cu );
1731 }
1732
1735
1736 if( aPad->Padstack().FrontOuterLayers().has_solder_mask.has_value()
1737 || aPad->Padstack().BackOuterLayers().has_solder_mask.has_value() )
1738 {
1739 m_out->Print( 0, " (tenting " );
1742 m_out->Print( 0, ")" );
1743 }
1744
1746
1747 auto formatPadLayer = [&]( PCB_LAYER_ID aLayer )
1748 {
1749 const PADSTACK& padstack = aPad->Padstack();
1750
1751 m_out->Print( "(shape %s)", shapeName( aLayer ) );
1752 m_out->Print( "(size %s)", formatInternalUnits( aPad->GetSize( aLayer ) ).c_str() );
1753
1754 const VECTOR2I& delta = aPad->GetDelta( aLayer );
1755
1756 if( delta.x != 0 || delta.y != 0 )
1757 m_out->Print( "(rect_delta %s)", formatInternalUnits( delta ).c_str() );
1758
1759 shapeoffset = aPad->GetOffset( aLayer );
1760
1761 if( shapeoffset.x != 0 || shapeoffset.y != 0 )
1762 m_out->Print( "(offset %s)", formatInternalUnits( shapeoffset ).c_str() );
1763
1764 formatCornerProperties( aLayer );
1765
1766 if( aPad->GetShape( aLayer ) == PAD_SHAPE::CUSTOM )
1767 {
1768 m_out->Print( "(options" );
1769
1771 m_out->Print( "(clearance convexhull)" );
1772 else
1773 m_out->Print( "(clearance outline)" );
1774
1775 // Output the anchor pad shape (circle/rect)
1776 m_out->Print( "(anchor %s)", anchorShape( aLayer ) );
1777
1778 m_out->Print( ")" ); // end of (options ...
1779
1780 // Output graphic primitive of the pad shape
1781 formatPrimitives( aLayer );
1782 }
1783
1784 EDA_ANGLE defaultLayerAngle = ANGLE_90;
1785
1786 if( aPad->GetShape( aLayer ) == PAD_SHAPE::CIRCLE
1787 || ( aPad->GetShape( aLayer ) == PAD_SHAPE::CUSTOM
1788 && aPad->GetAnchorPadShape( aLayer ) == PAD_SHAPE::CIRCLE ) )
1789 {
1790 defaultLayerAngle = ANGLE_45;
1791 }
1792
1793 EDA_ANGLE layerSpokeAngle = padstack.ThermalSpokeAngle( aLayer );
1794
1795 if( layerSpokeAngle != defaultLayerAngle )
1796 {
1797 m_out->Print( "(thermal_bridge_angle %s)", EDA_UNIT_UTILS::FormatAngle( layerSpokeAngle ).c_str() );
1798 }
1799
1800 if( padstack.ThermalGap( aLayer ).has_value() )
1801 {
1802 m_out->Print( "(thermal_gap %s)", formatInternalUnits( *padstack.ThermalGap( aLayer ) ).c_str() );
1803 }
1804
1805 if( padstack.ThermalSpokeWidth( aLayer ).has_value() )
1806 {
1807 m_out->Print( "(thermal_bridge_width %s)",
1808 formatInternalUnits( *padstack.ThermalSpokeWidth( aLayer ) ).c_str() );
1809 }
1810
1811 if( padstack.Clearance( aLayer ).has_value() )
1812 {
1813 m_out->Print( "(clearance %s)", formatInternalUnits( *padstack.Clearance( aLayer ) ).c_str() );
1814 }
1815
1816 if( padstack.ZoneConnection( aLayer ).has_value() )
1817 {
1818 m_out->Print( "(zone_connect %d)", static_cast<int>( *padstack.ZoneConnection( aLayer ) ) );
1819 }
1820 };
1821
1822
1823 if( aPad->Padstack().Mode() != PADSTACK::MODE::NORMAL )
1824 {
1826 {
1827 m_out->Print( "(padstack (mode front_inner_back)" );
1828
1829 m_out->Print( "(layer \"Inner\"" );
1830 formatPadLayer( PADSTACK::INNER_LAYERS );
1831 m_out->Print( ")" );
1832 m_out->Print( "(layer \"B.Cu\"" );
1833 formatPadLayer( B_Cu );
1834 m_out->Print( ")" );
1835 }
1836 else
1837 {
1838 m_out->Print( "(padstack (mode custom)" );
1839
1840 int layerCount = board ? board->GetCopperLayerCount() : MAX_CU_LAYERS;
1841
1842 for( PCB_LAYER_ID layer : LAYER_RANGE( F_Cu, B_Cu, layerCount ) )
1843 {
1844 if( layer == F_Cu )
1845 continue;
1846
1847 m_out->Print( "(layer %s", m_out->Quotew( LSET::Name( layer ) ).c_str() );
1848 formatPadLayer( layer );
1849 m_out->Print( ")" );
1850 }
1851 }
1852
1853 m_out->Print( ")" );
1854 }
1855
1856 m_out->Print( ")" );
1857}
1858
1859
1860void PCB_WRITER_V10::format( const PCB_BARCODE* aBarcode ) const
1861{
1862 wxCHECK_RET( aBarcode != nullptr && m_out != nullptr, "" );
1863
1864 m_out->Print( "(barcode" );
1865
1866 if( aBarcode->IsLocked() )
1867 KICAD_FORMAT::LEGACY::FormatBool( m_out, "locked", true );
1868
1869 m_out->Print( "(at %s %s)", formatInternalUnits( aBarcode->GetPosition() ).c_str(),
1870 EDA_UNIT_UTILS::FormatAngle( aBarcode->GetAngle() ).c_str() );
1871
1872 formatLayer( aBarcode->GetLayer() );
1873
1874 m_out->Print( "(size %s %s)", formatInternalUnits( aBarcode->GetWidth() ).c_str(),
1875 formatInternalUnits( aBarcode->GetHeight() ).c_str() );
1876
1877 m_out->Print( "(text %s)", m_out->Quotew( aBarcode->GetText() ).c_str() );
1878
1879 m_out->Print( "(text_height %s)", formatInternalUnits( aBarcode->GetTextSize() ).c_str() );
1880
1881 const char* typeStr = "code39";
1882
1883 switch( aBarcode->GetKind() )
1884 {
1885 case BARCODE_T::CODE_39: typeStr = "code39"; break;
1886 case BARCODE_T::CODE_128: typeStr = "code128"; break;
1887 case BARCODE_T::DATA_MATRIX: typeStr = "datamatrix"; break;
1888 case BARCODE_T::QR_CODE: typeStr = "qr"; break;
1889 case BARCODE_T::MICRO_QR_CODE: typeStr = "microqr"; break;
1890 }
1891
1892 m_out->Print( "(type %s)", typeStr );
1893
1894 if( aBarcode->GetKind() == BARCODE_T::QR_CODE || aBarcode->GetKind() == BARCODE_T::MICRO_QR_CODE )
1895 {
1896 const char* eccStr = "L";
1897 switch( aBarcode->GetErrorCorrection() )
1898 {
1899 case BARCODE_ECC_T::L: eccStr = "L"; break;
1900 case BARCODE_ECC_T::M: eccStr = "M"; break;
1901 case BARCODE_ECC_T::Q: eccStr = "Q"; break;
1902 case BARCODE_ECC_T::H: eccStr = "H"; break;
1903 }
1904
1905 m_out->Print( "(ecc_level %s)", eccStr );
1906 }
1907
1908 KICAD_FORMAT::LEGACY::FormatBool( m_out, "hide", !aBarcode->GetShowText() );
1909 KICAD_FORMAT::LEGACY::FormatBool( m_out, "knockout", aBarcode->IsKnockout() );
1910
1911 if( aBarcode->GetMargin().x != 0 || aBarcode->GetMargin().y != 0 )
1912 {
1913 m_out->Print( "(margins %s %s)", formatInternalUnits( aBarcode->GetMargin().x ).c_str(),
1914 formatInternalUnits( aBarcode->GetMargin().y ).c_str() );
1915 }
1916
1918
1919 m_out->Print( ")" );
1920}
1921
1922
1923void PCB_WRITER_V10::format( const PCB_TEXT* aText ) const
1924{
1925 FOOTPRINT* parentFP = aText->GetParentFootprint();
1926 std::string prefix;
1927 std::string type;
1928 VECTOR2I pos = aText->GetTextPos();
1929 const PCB_FIELD* field = aText->Type() == PCB_FIELD_T ? static_cast<const PCB_FIELD*>( aText ) : nullptr;
1930
1931 // Always format dimension text as gr_text
1932 if( dynamic_cast<const PCB_DIMENSION_BASE*>( aText ) )
1933 parentFP = nullptr;
1934
1935 if( parentFP )
1936 {
1937 prefix = "fp";
1938 type = "user";
1939
1940 pos -= parentFP->GetPosition();
1941 RotatePoint( pos, -parentFP->GetOrientation() );
1942 }
1943 else
1944 {
1945 prefix = "gr";
1946 }
1947
1948 if( !field )
1949 {
1950 m_out->Print( "(%s_text %s %s", prefix.c_str(), type.c_str(), m_out->Quotew( aText->GetText() ).c_str() );
1951
1952 if( aText->IsLocked() )
1953 KICAD_FORMAT::LEGACY::FormatBool( m_out, "locked", true );
1954 }
1955
1956 m_out->Print( "(at %s %s)", formatInternalUnits( pos ).c_str(),
1957 EDA_UNIT_UTILS::FormatAngle( aText->GetTextAngle() ).c_str() );
1958
1959 if( parentFP && !aText->IsKeepUpright() )
1960 KICAD_FORMAT::LEGACY::FormatBool( m_out, "unlocked", true );
1961
1962 formatLayer( aText->GetLayer(), aText->IsKnockout() );
1963
1964 if( field && !field->IsVisible() )
1965 KICAD_FORMAT::LEGACY::FormatBool( m_out, "hide", true );
1966
1968
1969 // Currently, texts have no specific color and no hyperlink.
1970 // so ensure they are never written in kicad_pcb file
1971 int ctl_flags = CTL_OMIT_COLOR | CTL_OMIT_HYPERLINK;
1972
1974
1975 if( aText->GetFont() && aText->GetFont()->IsOutline() )
1976 formatRenderCache( aText );
1977
1978 if( !field )
1979 m_out->Print( ")" );
1980}
1981
1982
1983void PCB_WRITER_V10::format( const PCB_TEXTBOX* aTextBox ) const
1984{
1985 FOOTPRINT* parentFP = aTextBox->GetParentFootprint();
1986
1987 m_out->Print( "(%s %s",
1988 aTextBox->Type() == PCB_TABLECELL_T ? "table_cell"
1989 : parentFP ? "fp_text_box"
1990 : "gr_text_box",
1991 m_out->Quotew( aTextBox->GetText() ).c_str() );
1992
1993 if( aTextBox->IsLocked() )
1994 KICAD_FORMAT::LEGACY::FormatBool( m_out, "locked", true );
1995
1996 if( aTextBox->GetShape() == SHAPE_T::RECTANGLE )
1997 {
1998 m_out->Print( "(start %s) (end %s)", formatInternalUnits( aTextBox->GetStart(), parentFP ).c_str(),
1999 formatInternalUnits( aTextBox->GetEnd(), parentFP ).c_str() );
2000 }
2001 else if( aTextBox->GetShape() == SHAPE_T::POLY )
2002 {
2003 const SHAPE_POLY_SET& poly = aTextBox->GetPolyShape();
2004 const SHAPE_LINE_CHAIN& outline = poly.Outline( 0 );
2005
2006 formatPolyPts( outline, parentFP );
2007 }
2008 else
2009 {
2010 UNIMPLEMENTED_FOR( aTextBox->SHAPE_T_asString() );
2011 }
2012
2013 m_out->Print( "(margins %s %s %s %s)", formatInternalUnits( aTextBox->GetMarginLeft() ).c_str(),
2014 formatInternalUnits( aTextBox->GetMarginTop() ).c_str(),
2015 formatInternalUnits( aTextBox->GetMarginRight() ).c_str(),
2016 formatInternalUnits( aTextBox->GetMarginBottom() ).c_str() );
2017
2018 if( const PCB_TABLECELL* cell = dynamic_cast<const PCB_TABLECELL*>( aTextBox ) )
2019 m_out->Print( "(span %d %d)", cell->GetColSpan(), cell->GetRowSpan() );
2020
2021 EDA_ANGLE angle = aTextBox->GetTextAngle();
2022
2023 if( parentFP )
2024 {
2025 angle -= parentFP->GetOrientation();
2026 angle.Normalize720();
2027 }
2028
2029 if( !angle.IsZero() )
2030 m_out->Print( "(angle %s)", EDA_UNIT_UTILS::FormatAngle( angle ).c_str() );
2031
2032 formatLayer( aTextBox->GetLayer() );
2033
2035
2037
2038 if( aTextBox->Type() != PCB_TABLECELL_T )
2039 {
2040 KICAD_FORMAT::LEGACY::FormatBool( m_out, "border", aTextBox->IsBorderEnabled() );
2042
2043 KICAD_FORMAT::LEGACY::FormatBool( m_out, "knockout", aTextBox->IsKnockout() );
2044 }
2045
2046 if( aTextBox->GetFont() && aTextBox->GetFont()->IsOutline() )
2047 formatRenderCache( aTextBox );
2048
2049 m_out->Print( ")" );
2050}
2051
2052
2053void PCB_WRITER_V10::format( const PCB_TABLE* aTable ) const
2054{
2055 wxCHECK_RET( aTable != nullptr && m_out != nullptr, "" );
2056
2057 m_out->Print( "(table (column_count %d)", aTable->GetColCount() );
2058
2060
2061 if( aTable->IsLocked() )
2062 KICAD_FORMAT::LEGACY::FormatBool( m_out, "locked", true );
2063
2064 formatLayer( aTable->GetLayer() );
2065
2066 m_out->Print( "(border" );
2067 KICAD_FORMAT::LEGACY::FormatBool( m_out, "external", aTable->StrokeExternal() );
2069
2070 if( aTable->StrokeExternal() || aTable->StrokeHeaderSeparator() )
2072
2073 m_out->Print( ")" ); // Close `border` token.
2074
2075 m_out->Print( "(separators" );
2078
2079 if( aTable->StrokeRows() || aTable->StrokeColumns() )
2081
2082 m_out->Print( ")" ); // Close `separators` token.
2083
2084 m_out->Print( "(column_widths" );
2085
2086 for( int col = 0; col < aTable->GetColCount(); ++col )
2087 m_out->Print( " %s", formatInternalUnits( aTable->GetColWidth( col ) ).c_str() );
2088
2089 m_out->Print( ")" );
2090
2091 m_out->Print( "(row_heights" );
2092
2093 for( int row = 0; row < aTable->GetRowCount(); ++row )
2094 m_out->Print( " %s", formatInternalUnits( aTable->GetRowHeight( row ) ).c_str() );
2095
2096 m_out->Print( ")" );
2097
2098 m_out->Print( "(cells" );
2099
2100 for( PCB_TABLECELL* cell : aTable->GetCells() )
2101 format( static_cast<PCB_TEXTBOX*>( cell ) );
2102
2103 m_out->Print( ")" ); // Close `cells` token.
2104 m_out->Print( ")" ); // Close `table` token.
2105}
2106
2107
2108void PCB_WRITER_V10::format( const PCB_GROUP* aGroup ) const
2109{
2110 wxArrayString memberIds;
2111
2112 // Validate member pointers against the board cache to avoid use-after-free on dangling
2113 // pointers (e.g. when a group held a reference to a deleted item). This validation only
2114 // applies when the group itself is part of m_board; for groups created off-board (e.g. a
2115 // DeepClone() used by the clipboard) the cache contains the originals, not our clones, so
2116 // skip the validation in that case and trust the member pointers.
2117 //
2118 // IsItemIndexedById() is explicitly safe to call on possibly-dangling pointers.
2119 bool validateAgainstBoard = m_board && m_board->IsItemIndexedById( aGroup );
2120
2121 for( EDA_ITEM* member : aGroup->GetItems() )
2122 {
2123 if( !validateAgainstBoard
2124 || m_board->IsItemIndexedById( static_cast<const BOARD_ITEM*>( member ) ) )
2125 {
2126 memberIds.Add( member->m_Uuid.AsString() );
2127 }
2128 }
2129
2130 if( memberIds.empty() )
2131 return;
2132
2133 m_out->Print( "(group %s", m_out->Quotew( aGroup->GetName() ).c_str() );
2134
2136
2137 if( aGroup->IsLocked() )
2138 KICAD_FORMAT::LEGACY::FormatBool( m_out, "locked", true );
2139
2140 if( aGroup->HasDesignBlockLink() )
2141 m_out->Print( "(lib_id \"%s\")", KICAD_FORMAT::LEGACY::FormatLibId( aGroup->GetDesignBlockLibId() ).c_str() );
2142
2143 memberIds.Sort();
2144
2145 m_out->Print( "(members" );
2146
2147 for( const wxString& memberId : memberIds )
2148 m_out->Print( " %s", m_out->Quotew( memberId ).c_str() );
2149
2150 m_out->Print( ")" ); // Close `members` token.
2151 m_out->Print( ")" ); // Close `group` token.
2152}
2153
2154
2155void PCB_WRITER_V10::format( const PCB_GENERATOR* aGenerator ) const
2156{
2157 // Some conditions appear to still be creating ghost tuning patterns. Don't save them.
2158 if( aGenerator->GetGeneratorType() == wxT( "tuning_pattern" ) && aGenerator->GetItems().empty() )
2159 {
2160 return;
2161 }
2162
2163 m_out->Print( "(generated" );
2164
2166
2167 m_out->Print( "(type %s) (name %s) (layer %s)", TO_UTF8( aGenerator->GetGeneratorType() ),
2168 m_out->Quotew( aGenerator->GetName() ).c_str(),
2169 m_out->Quotew( LSET::Name( aGenerator->GetLayer() ) ).c_str() );
2170
2171 if( aGenerator->IsLocked() )
2172 KICAD_FORMAT::LEGACY::FormatBool( m_out, "locked", true );
2173
2174 for( const auto& [key, value] : KICAD_FORMAT::LEGACY::TuningPropertiesForEra( *aGenerator, false ) )
2175 {
2176 if( value.CheckType<double>() || value.CheckType<int>() || value.CheckType<long>()
2177 || value.CheckType<long long>() )
2178 {
2179 double val;
2180
2181 if( !value.GetAs( &val ) )
2182 continue;
2183
2184 std::string buf = fmt::format( "{:.10g}", val );
2185
2186 // Don't quote numbers
2187 m_out->Print( "(%s %s)", key.c_str(), buf.c_str() );
2188 }
2189 else if( value.CheckType<bool>() )
2190 {
2191 bool val;
2192 value.GetAs( &val );
2193
2195 }
2196 else if( value.CheckType<VECTOR2I>() )
2197 {
2198 VECTOR2I val;
2199 value.GetAs( &val );
2200
2201 m_out->Print( "(%s (xy %s))", key.c_str(), formatInternalUnits( val ).c_str() );
2202 }
2203 else if( value.CheckType<SHAPE_LINE_CHAIN>() )
2204 {
2205 SHAPE_LINE_CHAIN val;
2206 value.GetAs( &val );
2207
2208 m_out->Print( "(%s ", key.c_str() );
2209 formatPolyPts( val );
2210 m_out->Print( ")" );
2211 }
2212 else
2213 {
2214 wxString val;
2215
2216 if( value.CheckType<wxString>() )
2217 {
2218 value.GetAs( &val );
2219 }
2220 else if( value.CheckType<std::string>() )
2221 {
2222 std::string str;
2223 value.GetAs( &str );
2224
2225 val = wxString::FromUTF8( str );
2226 }
2227
2228 m_out->Print( "(%s %s)", key.c_str(), m_out->Quotew( val ).c_str() );
2229 }
2230 }
2231
2232 wxArrayString memberIds;
2233
2234 for( EDA_ITEM* member : aGenerator->GetItems() )
2235 memberIds.Add( member->m_Uuid.AsString() );
2236
2237 memberIds.Sort();
2238
2239 m_out->Print( "(members" );
2240
2241 for( const wxString& memberId : memberIds )
2242 m_out->Print( " %s", m_out->Quotew( memberId ).c_str() );
2243
2244 m_out->Print( ")" ); // Close `members` token.
2245 m_out->Print( ")" ); // Close `generated` token.
2246}
2247
2248
2249void PCB_WRITER_V10::format( const PCB_TRACK* aTrack ) const
2250{
2251 if( aTrack->Type() == PCB_VIA_T )
2252 {
2253 PCB_LAYER_ID layer1, layer2;
2254
2255 const PCB_VIA* via = static_cast<const PCB_VIA*>( aTrack );
2256 const BOARD* board = via->GetBoard();
2257
2258 wxCHECK_RET( board != nullptr, wxT( "Via has no parent." ) );
2259
2260 m_out->Print( "(via" );
2261
2262 via->LayerPair( &layer1, &layer2 );
2263
2264 switch( via->GetViaType() )
2265 {
2266 case VIATYPE::THROUGH: // Default shape not saved.
2267 break;
2268
2269 case VIATYPE::BLIND: m_out->Print( " blind " ); break;
2270
2271 case VIATYPE::BURIED: m_out->Print( " buried " ); break;
2272
2273 case VIATYPE::MICROVIA: m_out->Print( " micro " ); break;
2274
2275 default: THROW_IO_ERROR( wxString::Format( _( "unknown via type %d" ), via->GetViaType() ) );
2276 }
2277
2278 m_out->Print( "(at %s) (size %s)", formatInternalUnits( aTrack->GetStart() ).c_str(),
2279 formatInternalUnits( via->GetWidth( F_Cu ) ).c_str() );
2280
2281 // Old boards were using UNDEFINED_DRILL_DIAMETER value in file for via drill when
2282 // via drill was the netclass value.
2283 // recent boards always set the via drill to the actual value, but now we need to
2284 // always store the drill value, because netclass value is not stored in the board file.
2285 // Otherwise the drill value of some (old) vias can be unknown
2286 if( via->GetDrill() != UNDEFINED_DRILL_DIAMETER )
2287 m_out->Print( "(drill %s)", formatInternalUnits( via->GetDrill() ).c_str() );
2288 else
2289 m_out->Print( "(drill %s)", formatInternalUnits( via->GetDrillValue() ).c_str() );
2290
2291 if( via->Padstack().SecondaryDrill().size.x > 0 )
2292 {
2293 m_out->Print( "(backdrill (size %s) (layers %s %s))",
2294 formatInternalUnits( via->Padstack().SecondaryDrill().size.x ).c_str(),
2295 m_out->Quotew( LSET::Name( via->Padstack().SecondaryDrill().start ) ).c_str(),
2296 m_out->Quotew( LSET::Name( via->Padstack().SecondaryDrill().end ) ).c_str() );
2297 }
2298
2299 if( via->Padstack().TertiaryDrill().size.x > 0 )
2300 {
2301 m_out->Print( "(tertiary_drill (size %s) (layers %s %s))",
2302 formatInternalUnits( via->Padstack().TertiaryDrill().size.x ).c_str(),
2303 m_out->Quotew( LSET::Name( via->Padstack().TertiaryDrill().start ) ).c_str(),
2304 m_out->Quotew( LSET::Name( via->Padstack().TertiaryDrill().end ) ).c_str() );
2305 }
2306
2307 auto formatPostMachining = [&]( const char* aName, const PADSTACK::POST_MACHINING_PROPS& aProps )
2308 {
2309 if( !aProps.mode.has_value() || aProps.mode == PAD_DRILL_POST_MACHINING_MODE::NOT_POST_MACHINED )
2310 return;
2311
2312 m_out->Print( "(%s %s", aName,
2313 aProps.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE ? "counterbore" : "countersink" );
2314
2315 if( aProps.size > 0 )
2316 m_out->Print( " (size %s)", formatInternalUnits( aProps.size ).c_str() );
2317
2318 if( aProps.depth > 0 )
2319 m_out->Print( " (depth %s)", formatInternalUnits( aProps.depth ).c_str() );
2320
2321 if( aProps.angle > 0 )
2322 m_out->Print( " (angle %s)", FormatDouble2Str( aProps.angle / 10.0 ).c_str() );
2323
2324 m_out->Print( ")" );
2325 };
2326
2327 formatPostMachining( "front_post_machining", via->Padstack().FrontPostMachining() );
2328 formatPostMachining( "back_post_machining", via->Padstack().BackPostMachining() );
2329
2330 m_out->Print( "(layers %s %s)", m_out->Quotew( LSET::Name( layer1 ) ).c_str(),
2331 m_out->Quotew( LSET::Name( layer2 ) ).c_str() );
2332
2333 switch( via->Padstack().UnconnectedLayerMode() )
2334 {
2336 KICAD_FORMAT::LEGACY::FormatBool( m_out, "remove_unused_layers", true );
2337 KICAD_FORMAT::LEGACY::FormatBool( m_out, "keep_end_layers", false );
2338 break;
2339
2341 KICAD_FORMAT::LEGACY::FormatBool( m_out, "remove_unused_layers", true );
2342 KICAD_FORMAT::LEGACY::FormatBool( m_out, "keep_end_layers", true );
2343 break;
2344
2346 KICAD_FORMAT::LEGACY::FormatBool( m_out, "start_end_only", true );
2347 break;
2348
2350 }
2351
2352 if( via->IsLocked() )
2353 KICAD_FORMAT::LEGACY::FormatBool( m_out, "locked", true );
2354
2355 if( via->GetIsFree() )
2356 KICAD_FORMAT::LEGACY::FormatBool( m_out, "free", true );
2357
2358 if( via->GetRemoveUnconnected() )
2359 {
2360 m_out->Print( "(zone_layer_connections" );
2361
2362 for( PCB_LAYER_ID layer : board->GetEnabledLayers().CuStack() )
2363 {
2364 if( via->GetZoneLayerOverride( layer ) == ZLO_FORCE_FLASHED )
2365 m_out->Print( " %s", m_out->Quotew( LSET::Name( layer ) ).c_str() );
2366 }
2367
2368 m_out->Print( ")" );
2369 }
2370
2371 const PADSTACK& padstack = via->Padstack();
2372
2373 if( padstack.FrontOuterLayers().has_solder_mask.has_value()
2374 || padstack.BackOuterLayers().has_solder_mask.has_value() )
2375 {
2376 m_out->Print( 0, " (tenting " );
2379 m_out->Print( 0, ")" );
2380 }
2381
2382 if( padstack.Drill().is_capped.has_value() )
2383 KICAD_FORMAT::LEGACY::FormatOptBool( m_out, "capping", padstack.Drill().is_capped );
2384
2385 if( padstack.FrontOuterLayers().has_covering.has_value()
2386 || padstack.BackOuterLayers().has_covering.has_value() )
2387 {
2388 m_out->Print( 0, " (covering " );
2391 m_out->Print( 0, ")" );
2392 }
2393
2394 if( padstack.FrontOuterLayers().has_plugging.has_value()
2395 || padstack.BackOuterLayers().has_plugging.has_value() )
2396 {
2397 m_out->Print( 0, " (plugging " );
2400 m_out->Print( 0, ")" );
2401 }
2402
2403 if( padstack.Drill().is_filled.has_value() )
2404 KICAD_FORMAT::LEGACY::FormatOptBool( m_out, "filling", padstack.Drill().is_filled );
2405
2406 if( padstack.Mode() != PADSTACK::MODE::NORMAL )
2407 {
2408 m_out->Print( "(padstack" );
2409
2410 if( padstack.Mode() == PADSTACK::MODE::FRONT_INNER_BACK )
2411 {
2412 m_out->Print( "(mode front_inner_back)" );
2413
2414 m_out->Print( "(layer \"Inner\"" );
2415 m_out->Print( "(size %s)", formatInternalUnits( padstack.Size( PADSTACK::INNER_LAYERS ).x ).c_str() );
2416 m_out->Print( ")" );
2417 m_out->Print( "(layer \"B.Cu\"" );
2418 m_out->Print( "(size %s)", formatInternalUnits( padstack.Size( B_Cu ).x ).c_str() );
2419 m_out->Print( ")" );
2420 }
2421 else
2422 {
2423 m_out->Print( "(mode custom)" );
2424
2425 for( PCB_LAYER_ID layer : LAYER_RANGE( F_Cu, B_Cu, board->GetCopperLayerCount() ) )
2426 {
2427 if( layer == F_Cu )
2428 continue;
2429
2430 m_out->Print( "(layer %s", m_out->Quotew( LSET::Name( layer ) ).c_str() );
2431 m_out->Print( "(size %s)", formatInternalUnits( padstack.Size( layer ).x ).c_str() );
2432 m_out->Print( ")" );
2433 }
2434 }
2435
2436 m_out->Print( ")" );
2437 }
2438
2439 if( !isDefaultTeardropParameters( via->GetTeardropParams() ) )
2440 formatTeardropParameters( via->GetTeardropParams() );
2441 }
2442 else
2443 {
2444 if( aTrack->Type() == PCB_ARC_T )
2445 {
2446 const PCB_ARC* arc = static_cast<const PCB_ARC*>( aTrack );
2447
2448 m_out->Print( "(arc (start %s) (mid %s) (end %s) (width %s)",
2449 formatInternalUnits( arc->GetStart() ).c_str(), formatInternalUnits( arc->GetMid() ).c_str(),
2450 formatInternalUnits( arc->GetEnd() ).c_str(),
2451 formatInternalUnits( arc->GetWidth() ).c_str() );
2452 }
2453 else
2454 {
2455 m_out->Print( "(segment (start %s) (end %s) (width %s)", formatInternalUnits( aTrack->GetStart() ).c_str(),
2456 formatInternalUnits( aTrack->GetEnd() ).c_str(),
2457 formatInternalUnits( aTrack->GetWidth() ).c_str() );
2458 }
2459
2460 if( aTrack->IsLocked() )
2461 KICAD_FORMAT::LEGACY::FormatBool( m_out, "locked", true );
2462
2463 if( aTrack->GetLayerSet().count() > 1 )
2464 formatLayers( aTrack->GetLayerSet(), false /* enumerate layers */ );
2465 else
2466 formatLayer( aTrack->GetLayer() );
2467
2468 if( aTrack->HasSolderMask() && aTrack->GetLocalSolderMaskMargin().has_value()
2469 && IsExternalCopperLayer( aTrack->GetLayer() ) )
2470 {
2471 m_out->Print( "(solder_mask_margin %s)",
2472 formatInternalUnits( aTrack->GetLocalSolderMaskMargin().value() ).c_str() );
2473 }
2474 }
2475
2476 m_out->Print( "(net %s)", m_out->Quotew( aTrack->GetNetname() ).c_str() );
2477
2479 m_out->Print( ")" );
2480}
2481
2482
2483void PCB_WRITER_V10::format( const ZONE* aZone ) const
2484{
2485 m_out->Print( "(zone" );
2486
2487 if( aZone->IsOnCopperLayer() && !aZone->GetIsRuleArea() && aZone->GetNetCode() > 0 )
2488 m_out->Print( "(net %s)", m_out->Quotew( aZone->GetNetname() ).c_str() );
2489
2490 if( aZone->IsLocked() )
2491 KICAD_FORMAT::LEGACY::FormatBool( m_out, "locked", true );
2492
2493 // If a zone exists on multiple layers, format accordingly
2494 LSET layers = aZone->GetLayerSet();
2495
2496 if( aZone->GetBoard() )
2497 layers &= aZone->GetBoard()->GetEnabledLayers();
2498
2499 // Always enumerate every layer for a zone on a copper layer
2500 if( layers.count() > 1 )
2501 formatLayers( layers, aZone->IsOnCopperLayer(), true );
2502 else
2503 formatLayer( aZone->GetFirstLayer() );
2504
2505 if( !aZone->IsTeardropArea() )
2507
2508 if( !aZone->GetZoneName().empty() && !aZone->IsTeardropArea() )
2509 m_out->Print( "(name %s)", m_out->Quotew( aZone->GetZoneName() ).c_str() );
2510
2511 // Save the outline aux info
2512 std::string hatch;
2513
2514 switch( aZone->GetHatchStyle() )
2515 {
2516 default:
2517 case ZONE_BORDER_DISPLAY_STYLE::NO_HATCH: hatch = "none"; break;
2518 case ZONE_BORDER_DISPLAY_STYLE::DIAGONAL_EDGE: hatch = "edge"; break;
2519 case ZONE_BORDER_DISPLAY_STYLE::DIAGONAL_FULL: hatch = "full"; break;
2520 }
2521
2522 m_out->Print( "(hatch %s %s)", hatch.c_str(), formatInternalUnits( aZone->GetBorderHatchPitch() ).c_str() );
2523
2524
2525 if( aZone->GetAssignedPriority() > 0 )
2526 m_out->Print( "(priority %d)", aZone->GetAssignedPriority() );
2527
2528 // Add teardrop keywords in file: (attr (teardrop (type xxx))) where xxx is the teardrop type
2529 if( aZone->IsTeardropArea() )
2530 {
2531 m_out->Print( "(attr (teardrop (type %s)))",
2532 aZone->GetTeardropAreaType() == TEARDROP_TYPE::TD_VIAPAD ? "padvia" : "track_end" );
2533 }
2534
2535 m_out->Print( "(connect_pads" );
2536
2537 switch( aZone->GetPadConnection() )
2538 {
2539 default:
2540 case ZONE_CONNECTION::THERMAL: // Default option not saved or loaded.
2541 break;
2542
2543 case ZONE_CONNECTION::THT_THERMAL: m_out->Print( " thru_hole_only" ); break;
2544
2545 case ZONE_CONNECTION::FULL: m_out->Print( " yes" ); break;
2546
2547 case ZONE_CONNECTION::NONE: m_out->Print( " no" ); break;
2548 }
2549
2550 m_out->Print( "(clearance %s)", formatInternalUnits( aZone->GetLocalClearance().value() ).c_str() );
2551
2552 m_out->Print( ")" );
2553
2554 m_out->Print( "(min_thickness %s)", formatInternalUnits( aZone->GetMinThickness() ).c_str() );
2555
2556 if( aZone->GetIsRuleArea() )
2557 {
2558 // Keepout settings
2559 m_out->Print( "(keepout (tracks %s) (vias %s) (pads %s) (copperpour %s) (footprints %s))",
2560 aZone->GetDoNotAllowTracks() ? "not_allowed" : "allowed",
2561 aZone->GetDoNotAllowVias() ? "not_allowed" : "allowed",
2562 aZone->GetDoNotAllowPads() ? "not_allowed" : "allowed",
2563 aZone->GetDoNotAllowZoneFills() ? "not_allowed" : "allowed",
2564 aZone->GetDoNotAllowFootprints() ? "not_allowed" : "allowed" );
2565
2566 // Multichannel settings
2567 m_out->Print( "(placement" );
2569
2570 switch( aZone->GetPlacementAreaSourceType() )
2571 {
2573 m_out->Print( "(sheetname %s)", m_out->Quotew( aZone->GetPlacementAreaSource() ).c_str() );
2574 break;
2576 m_out->Print( "(component_class %s)", m_out->Quotew( aZone->GetPlacementAreaSource() ).c_str() );
2577 break;
2579 m_out->Print( "(group %s)", m_out->Quotew( aZone->GetPlacementAreaSource() ).c_str() );
2580 break;
2581 // These are transitory and should not be saved
2583 }
2584
2585 m_out->Print( ")" );
2586 }
2587
2588 m_out->Print( "(fill" );
2589
2590 // Default is not filled.
2591 if( aZone->IsFilled() )
2592 m_out->Print( " yes" );
2593
2594 // Default is polygon filled.
2596 m_out->Print( "(mode hatch)" );
2597
2598 if( !aZone->IsTeardropArea() )
2599 {
2600 m_out->Print( "(thermal_gap %s) (thermal_bridge_width %s)",
2601 formatInternalUnits( aZone->GetThermalReliefGap() ).c_str(),
2602 formatInternalUnits( aZone->GetThermalReliefSpokeWidth() ).c_str() );
2603 }
2604
2606 {
2607 switch( aZone->GetCornerSmoothingType() )
2608 {
2609 case ZONE_SETTINGS::CORNER_SMOOTHING::CHAMFER: m_out->Print( "(smoothing chamfer)" ); break;
2610
2611 case ZONE_SETTINGS::CORNER_SMOOTHING::FILLET: m_out->Print( "(smoothing fillet)" ); break;
2612
2613 default:
2614 THROW_IO_ERROR( wxString::Format( _( "unknown zone corner smoothing type %d" ),
2615 static_cast<int>( aZone->GetCornerSmoothingType() ) ) );
2616 }
2617
2618 if( aZone->GetCornerRadius() != 0 )
2619 m_out->Print( "(radius %s)", formatInternalUnits( aZone->GetCornerRadius() ).c_str() );
2620 }
2621
2622 m_out->Print( "(island_removal_mode %d)", static_cast<int>( aZone->GetIslandRemovalMode() ) );
2623
2625 {
2626 m_out->Print( "(island_area_min %s)",
2627 formatInternalUnits( aZone->GetMinIslandArea() / pcbIUScale.IU_PER_MM ).c_str() );
2628 }
2629
2631 {
2632 m_out->Print( "(hatch_thickness %s) (hatch_gap %s) (hatch_orientation %s)",
2633 formatInternalUnits( aZone->GetHatchThickness() ).c_str(),
2634 formatInternalUnits( aZone->GetHatchGap() ).c_str(),
2635 FormatDouble2Str( aZone->GetHatchOrientation().AsDegrees() ).c_str() );
2636
2637 if( aZone->GetHatchSmoothingLevel() > 0 )
2638 {
2639 m_out->Print( "(hatch_smoothing_level %d) (hatch_smoothing_value %s)", aZone->GetHatchSmoothingLevel(),
2640 FormatDouble2Str( aZone->GetHatchSmoothingValue() ).c_str() );
2641 }
2642
2643 m_out->Print( "(hatch_border_algorithm %s) (hatch_min_hole_area %s)",
2644 aZone->GetHatchBorderAlgorithm() ? "hatch_thickness" : "min_thickness",
2645 FormatDouble2Str( aZone->GetHatchHoleMinArea() ).c_str() );
2646 }
2647
2648 m_out->Print( ")" );
2649
2650 for( const auto& [layer, properties] : aZone->LayerProperties() )
2651 {
2652 format( properties, 0, layer );
2653 }
2654
2655 if( aZone->GetNumCorners() )
2656 {
2657 // Footprint outlines are now stored in library coordinates. The legacy format
2658 // stores these in board coordinates, unlike the other footprint graphics.
2659 SHAPE_POLY_SET::POLYGON poly = aZone->GetBoardOutline().Polygon( 0 );
2660
2661 for( const SHAPE_LINE_CHAIN& chain : poly )
2662 {
2663 m_out->Print( "(polygon" );
2665 m_out->Print( ")" );
2666 }
2667 }
2668
2669 // Save the PolysList (filled areas)
2670 for( PCB_LAYER_ID layer : aZone->GetLayerSet().Seq() )
2671 {
2672 const std::shared_ptr<SHAPE_POLY_SET>& fv = aZone->GetFilledPolysList( layer );
2673
2674 for( int ii = 0; ii < fv->OutlineCount(); ++ii )
2675 {
2676 m_out->Print( "(filled_polygon" );
2677 m_out->Print( "(layer %s)", m_out->Quotew( LSET::Name( layer ) ).c_str() );
2678
2679 if( aZone->IsIsland( layer, ii ) )
2680 KICAD_FORMAT::LEGACY::FormatBool( m_out, "island", true );
2681
2682 const SHAPE_LINE_CHAIN& chain = fv->COutline( ii );
2683
2685 m_out->Print( ")" );
2686 }
2687 }
2688
2689 m_out->Print( ")" );
2690}
2691
2692
2693void PCB_WRITER_V10::format( const ZONE_LAYER_PROPERTIES& aZoneLayerProperties, int aNestLevel,
2694 PCB_LAYER_ID aLayer ) const
2695{
2696 // Do not store the layer properties if no value is actually set.
2697 if( !aZoneLayerProperties.hatching_offset.has_value() )
2698 return;
2699
2700 m_out->Print( aNestLevel, "(property\n" );
2701 m_out->Print( aNestLevel, "(layer %s)\n", m_out->Quotew( LSET::Name( aLayer ) ).c_str() );
2702
2703 if( aZoneLayerProperties.hatching_offset.has_value() )
2704 {
2705 m_out->Print( aNestLevel, "(hatch_position (xy %s))",
2706 formatInternalUnits( aZoneLayerProperties.hatching_offset.value() ).c_str() );
2707 }
2708
2709 m_out->Print( aNestLevel, ")\n" );
2710}
2711
2712
2713void PCB_WRITER_V10::SaveFootprintFile( const wxString& aFileName, FOOTPRINT* aFootprint )
2714{
2715 if( aFootprint->GetAreFontsEmbedded() )
2716 aFootprint->EmbedFonts();
2717 else
2718 aFootprint->GetEmbeddedFiles()->ClearEmbeddedFonts();
2719
2720 PRETTIFIED_FILE_OUTPUTFORMATTER formatter( aFileName );
2721
2722 m_out = &formatter;
2724 Format( aFootprint );
2725 formatter.Finish();
2726 m_out = nullptr;
2727}
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:128
@ LT_FRONT
Definition board.h:250
@ LT_BACK
Definition board.h:251
@ ZLO_FORCE_FLASHED
Definition board_item.h:75
bool IsPrmSpecified(const wxString &aPrmValue)
@ BS_ITEM_TYPE_DIELECTRIC
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:66
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
TEARDROP_PARAMETERS & GetTeardropParams()
Container for design settings for a BOARD object.
std::map< PCB_LAYER_ID, ZONE_LAYER_PROPERTIES > m_ZoneLayerProperties
const VECTOR2I & GetGridOrigin() const
int GetBoardThickness() const
The full thickness of the board including copper and masks.
const VECTOR2I & GetAuxOrigin() const
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:85
virtual bool IsKnockout() const
Definition board_item.h:423
bool IsLocked() const override
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
FOOTPRINT * GetParentFootprint() const
VECTOR2I GetFPRelativePosition() const
Manage one layer needed to make a physical board.
Manage layers needed to make a physical board.
const std::vector< BOARD_STACKUP_ITEM * > & GetList() const
bool m_HasDielectricConstrains
True if some layers have impedance controlled tracks or have specific constrains for micro-wave appli...
bool m_EdgePlating
True if the edge board is plated.
BS_EDGE_CONNECTOR_CONSTRAINTS m_EdgeConnectorConstraints
If the board has edge connector cards, some constrains can be specified in job file: BS_EDGE_CONNECTO...
wxString m_FinishType
The name of external copper finish.
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:411
EMBEDDED_FILES * GetEmbeddedFiles() override
Definition board.cpp:3662
const std::vector< wxString > & GetVariantNames() const
Definition board.h:533
const GENERATORS & Generators() const
Definition board.h:485
const PCB_POINTS & Points() const
Definition board.h:499
const PAGE_INFO & GetPageSettings() const
Definition board.h:1020
const ZONES & Zones() const
Definition board.h:469
const GROUPS & Groups() const
The groups must maintain the following invariants.
Definition board.h:518
LAYER_T GetLayerType(PCB_LAYER_ID aLayer) const
Return the type of the copper layer given by aLayer.
Definition board.cpp:991
TITLE_BLOCK & GetTitleBlock()
Definition board.h:1026
int GetCopperLayerCount() const
Definition board.cpp:1127
const std::map< wxString, wxString > & GetProperties() const
Definition board.h:526
const FOOTPRINTS & Footprints() const
Definition board.h:465
const TRACKS & Tracks() const
Definition board.h:463
wxString GetVariantDescription(const wxString &aVariantName) const
Definition board.cpp:3125
const PCB_PLOT_PARAMS & GetPlotOptions() const
Definition board.h:1023
bool LegacyTeardrops() const
Definition board.h:1658
const LSET & GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition board.cpp:1174
BOARD_DESIGN_SETTINGS & GetDesignSettings()
Definition board.cpp:1290
const DRAWINGS & Drawings() const
Definition board.h:467
A lightweight representation of a component class.
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:115
bool IsZero() const
Definition eda_angle.h:135
EDA_ANGLE Normalize720()
Definition eda_angle.h:286
const LIB_ID & GetDesignBlockLibId() const
Definition eda_group.h:102
std::unordered_set< EDA_ITEM * > & GetItems()
Definition eda_group.h:78
wxString GetName() const
Definition eda_group.h:75
bool HasDesignBlockLink() const
Definition eda_group.h:99
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:98
const KIID m_Uuid
Definition eda_item.h:599
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
const VECTOR2I & GetBezierC2() const
Definition eda_shape.h:376
FILL_T GetFillMode() const
Definition eda_shape.h:150
SHAPE_POLY_SET & GetPolyShape()
SHAPE_T GetShape() const
Definition eda_shape.h:177
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition eda_shape.h:333
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition eda_shape.h:283
wxString SHAPE_T_asString() const
const VECTOR2I & GetBezierC1() const
Definition eda_shape.h:373
int GetCornerRadius() const
bool IsPolyShapeValid() const
VECTOR2I GetArcMid() const
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition eda_text.h:94
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition eda_text.h:118
bool IsKeepUpright() const
Definition eda_text.h:245
virtual bool IsVisible() const
Definition eda_text.h:226
KIFONT::FONT * GetFont() const
Definition eda_text.h:286
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:683
virtual EDA_ANGLE GetDrawRotation() const
Definition eda_text.h:425
virtual wxString GetShownText(RESOLUTION_CONTEXT aContext, int aDepth=0) const
Return the string actually shown after processing of the base text.
Definition eda_text.h:128
virtual int GetTextThickness() const
Definition eda_text.h:159
bool IsEmpty() const
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, std::shared_ptr< EMBEDDED_FILE > > & EmbeddedFileMap() const
Provide an iterable view of the file collection.
bool GetAreFontsEmbedded() const
bool GetDuplicatePadNumbersAreJumpers() const
Definition footprint.h:1133
const CASE_INSENSITIVE_MAP< FOOTPRINT_VARIANT > & GetVariants() const
Get all variants.
Definition footprint.h:1011
void EmbedFonts() override
bool AllowSolderMaskBridges() const
Definition footprint.h:518
wxString GetLibDescription() const
Definition footprint.h:449
ZONE_CONNECTION GetLocalZoneConnection() const
Definition footprint.h:491
bool IsDNP() const
Definition footprint.h:947
EDA_ANGLE GetOrientation() const
Definition footprint.h:382
ZONES & Zones()
Definition footprint.h:361
PCB_POINTS & Points()
Definition footprint.h:370
bool IsExcludedFromBOM() const
Definition footprint.h:929
wxString GetSheetname() const
Definition footprint.h:469
const std::vector< FP_UNIT_INFO > & GetUnitInfo() const
Definition footprint.h:909
std::optional< int > GetLocalSolderPasteMargin() const
Definition footprint.h:484
PCB_FIELD & Value()
read/write accessors:
Definition footprint.h:831
std::optional< int > GetLocalClearance() const
Definition footprint.h:478
PCB_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this footprint.
std::deque< PAD * > & Pads()
Definition footprint.h:355
int GetAttributes() const
Definition footprint.h:509
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition footprint.h:393
LSET GetPrivateLayers() const
Definition footprint.h:295
bool AllowMissingCourtyard() const
Definition footprint.h:515
wxString GetSheetfile() const
Definition footprint.h:472
const std::vector< wxString > & GetNetTiePadGroups() const
Definition footprint.h:567
const LIB_ID & GetFPID() const
Definition footprint.h:417
bool IsExcludedFromPosFiles() const
Definition footprint.h:920
const LSET & GetStackupLayers() const
Definition footprint.h:507
PCB_FIELD & Reference()
Definition footprint.h:832
JUMPER_GROUP_SET & JumperPadGroups()
Each jumper pad group is a set of pad numbers that should be treated as internally connected.
Definition footprint.h:1140
bool IsNetTie() const
Definition footprint.h:525
std::optional< double > GetLocalSolderPasteMarginRatio() const
Definition footprint.h:487
GROUPS & Groups()
Definition footprint.h:364
wxString GetFilters() const
Definition footprint.h:475
const wxArrayString * GetInitialComments() const
Return the initial comments block or NULL if none, without transfer of ownership.
Definition footprint.h:1257
void GetFields(std::vector< PCB_FIELD * > &aVector, bool aVisibleOnly) const
Populate a std::vector with PCB_TEXTs.
std::vector< FP_3DMODEL > & Models()
Definition footprint.h:375
const COMPONENT_CLASS * GetStaticComponentClass() const
Returns the component class for this footprint.
const KIID_PATH & GetPath() const
Definition footprint.h:455
std::optional< int > GetLocalSolderMaskMargin() const
Definition footprint.h:481
wxString GetKeywords() const
Definition footprint.h:452
EMBEDDED_FILES * GetEmbeddedFiles() override
Definition footprint.h:1286
FOOTPRINT_STACKUP GetStackupMode() const
Definition footprint.h:500
bool IsPlaced() const
Definition footprint.h:656
VECTOR2I GetPosition() const override
Definition footprint.h:379
DRAWINGS & GraphicalItems()
Definition footprint.h:358
Represents an (ordered) list of JUMPER_GROUP objects.
const std::vector< JUMPER_GROUP > & GetAll() const
bool IsEmpty() const
Represents a group of jumper pins or pads, keyed by name.
virtual bool IsOutline() const
Definition font.h:102
virtual void SetLineWidth(float aLineWidth)
Set the line width.
virtual wxString GetClass() const =0
Return the class name.
wxString AsString() const
Definition kiid.cpp:423
const UTF8 & GetLibItemName() const
Definition lib_id.h:98
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
static const LSET & AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
Definition lset.cpp:604
LSEQ CuStack() const
Return a sequence of copper layers in starting from the front/top and extending to the back/bottom.
Definition lset.cpp:259
LSEQ TechAndUserUIOrder() const
Return the technical and user layers in the order shown in layer widget.
Definition lset.cpp:272
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition lset.cpp:309
static LSET AllCuMask(int aCuLayerCount)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition lset.cpp:595
static wxString Name(PCB_LAYER_ID aLayerId)
Return the fixed name association with aLayerId.
Definition lset.cpp:184
An interface used to output 8 bit text in a convenient way.
Definition richio.h:294
std::string Quotew(const wxString &aWrapee) const
Definition richio.cpp:505
int PRINTF_FUNC_N Print(int nestLevel, const char *fmt,...)
Format and write text to the output stream.
Definition richio.cpp:432
A PADSTACK defines the characteristics of a single or multi-layer pad, in the IPC sense of the word.
Definition padstack.h:158
std::optional< int > & Clearance(PCB_LAYER_ID aLayer=F_Cu)
MASK_LAYER_PROPS & FrontOuterLayers()
Definition padstack.h:407
void ForEachUniqueLayer(const std::function< void(PCB_LAYER_ID)> &aMethod) const
Runs the given callable for each active unique copper layer in this padstack, meaning F_Cu for MODE::...
std::optional< int > & ThermalSpokeWidth(PCB_LAYER_ID aLayer=F_Cu)
EDA_ANGLE ThermalSpokeAngle(PCB_LAYER_ID aLayer=F_Cu) const
POST_MACHINING_PROPS & FrontPostMachining()
Definition padstack.h:369
std::optional< int > & ThermalGap(PCB_LAYER_ID aLayer=F_Cu)
DRILL_PROPS & TertiaryDrill()
Definition padstack.h:366
DRILL_PROPS & Drill()
Definition padstack.h:360
const VECTOR2I & Size(PCB_LAYER_ID aLayer) const
Definition padstack.cpp:879
@ NORMAL
Shape is the same on all layers.
Definition padstack.h:172
@ FRONT_INNER_BACK
Up to three shapes can be defined (F_Cu, inner copper layers, B_Cu)
Definition padstack.h:173
DRILL_PROPS & SecondaryDrill()
Definition padstack.h:363
POST_MACHINING_PROPS & BackPostMachining()
Definition padstack.h:372
MODE Mode() const
Definition padstack.h:348
MASK_LAYER_PROPS & BackOuterLayers()
Definition padstack.h:410
static constexpr PCB_LAYER_ID INNER_LAYERS
! The layer identifier to use for "inner layers" on top/inner/bottom padstacks
Definition padstack.h:184
std::optional< ZONE_CONNECTION > & ZoneConnection(PCB_LAYER_ID aLayer=F_Cu)
Definition pad.h:61
PAD_PROP GetProperty() const
Definition pad.h:581
bool GetRemoveUnconnected() const
Definition pad.h:896
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition pad.h:575
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:375
const ZONE_LAYER_OVERRIDE & GetZoneLayerOverride(PCB_LAYER_ID aLayer) const
Definition pad.cpp:516
std::optional< double > GetLocalSolderPasteMarginRatio() const
Definition pad.h:618
const wxString & GetPinType() const
Definition pad.h:160
PAD_ATTRIB GetAttribute() const
Definition pad.h:578
const wxString & GetPinFunction() const
Definition pad.h:154
const wxString & GetNumber() const
Definition pad.h:143
const VECTOR2I & GetDelta(PCB_LAYER_ID aLayer) const
Definition pad.h:307
EDA_ANGLE GetThermalSpokeAngle() const
Definition pad.h:775
VECTOR2I GetOffset(PCB_LAYER_ID aLayer) const
Definition pad.cpp:837
VECTOR2I GetDrillSize() const
Definition pad.h:320
double GetRoundRectRadiusRatio(PCB_LAYER_ID aLayer) const
Definition pad.h:833
PAD_SHAPE GetShape(PCB_LAYER_ID aLayer) const
Definition pad.h:205
bool GetKeepTopBottom() const
Definition pad.h:911
VECTOR2I GetSize(PCB_LAYER_ID aLayer) const
Definition pad.cpp:297
int GetPadToDieDelay() const
Definition pad.h:599
std::optional< int > GetLocalClearance() const override
Return any local clearances set in the "classic" (ie: pre-rule) system.
Definition pad.h:601
const PADSTACK & Padstack() const
Definition pad.h:331
EDA_ANGLE GetOrientation() const
Return the rotation angle of the pad.
Definition pad.cpp:1658
PAD_DRILL_SHAPE GetDrillShape() const
Definition pad.h:434
int GetChamferPositions(PCB_LAYER_ID aLayer) const
Definition pad.h:874
std::optional< int > GetLocalSolderPasteMargin() const
Definition pad.h:611
std::optional< int > GetLocalSolderMaskMargin() const
Definition pad.h:604
double GetChamferRectRatio(PCB_LAYER_ID aLayer) const
Definition pad.h:856
std::optional< int > GetLocalThermalSpokeWidthOverride() const
Definition pad.h:759
ZONE_CONNECTION GetLocalZoneConnection() const
Definition pad.h:629
CUSTOM_SHAPE_ZONE_MODE GetCustomShapeInZoneOpt() const
Definition pad.h:227
int GetLocalThermalGapOverride(wxString *aSource) const
Definition pad.cpp:2101
PAD_SHAPE GetAnchorPadShape(PCB_LAYER_ID aLayer) const
Definition pad.h:219
int GetPadToDieLength() const
Definition pad.h:596
const VECTOR2I & GetMid() const
Definition pcb_track.h:300
const VECTOR2I & GetMargin() const
Get the barcode margin (in internal units).
VECTOR2I GetPosition() const override
Get the position (center) of the barcode in internal units.
wxString GetText() const
int GetTextSize() const
bool IsKnockout() const override
int GetHeight() const
Get the barcode height (in internal units).
BARCODE_ECC_T GetErrorCorrection() const
bool GetShowText() const
EDA_ANGLE GetAngle() const
BARCODE_T GetKind() const
Returns the type of the barcode (QR, CODE_39, etc.).
int GetWidth() const
Get the barcode width (in internal units).
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
DIM_ARROW_DIRECTION GetArrowDirection() const
virtual VECTOR2I GetEnd() const
bool GetSuppressZeroes() const
int GetExtensionOffset() const
virtual VECTOR2I GetStart() const
The dimension's origin is the first feature point for the dimension.
int GetArrowLength() const
bool GetOverrideTextEnabled() 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
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
virtual wxString GetGeneratorType() const
A set of BOARD_ITEMs (i.e., without duplicates).
Definition pcb_group.h:51
A PCB_POINT is a 0-dimensional point that is used to mark a position on a PCB, or more usually a foot...
Definition pcb_point.h:39
int GetSize() const
Definition pcb_point.h:69
VECTOR2I GetPosition() const override
Definition pcb_point.h:60
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:350
bool HasSolderMask() const
Definition pcb_shape.h:347
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
STROKE_PARAMS GetStroke() const override
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition pcb_shape.h:70
bool StrokeRows() const
Definition pcb_table.h:110
int GetRowCount() const
Definition pcb_table.h:128
bool StrokeHeaderSeparator() const
Definition pcb_table.h:68
bool StrokeColumns() const
Definition pcb_table.h:107
bool StrokeExternal() const
Definition pcb_table.h:65
std::vector< PCB_TABLECELL * > GetCells() const
Definition pcb_table.h:165
int GetColCount() const
Definition pcb_table.h:126
const STROKE_PARAMS & GetSeparatorsStroke() const
Definition pcb_table.h:89
const STROKE_PARAMS & GetBorderStroke() const
Definition pcb_table.h:71
int GetColWidth(int aCol) const
Definition pcb_table.h:137
int GetRowHeight(int aRow) const
Definition pcb_table.h:147
int GetShape() const
Definition pcb_target.h:54
int GetWidth() const
Definition pcb_target.h:60
int GetSize() const
Definition pcb_target.h:57
VECTOR2I GetPosition() const override
Definition pcb_target.h:51
bool IsBorderEnabled() const
Tests whether the border is disabled, as configured by the stroke.
int GetMarginBottom() const
EDA_ANGLE GetTextAngle() const override
int GetMarginLeft() const
int GetMarginRight() const
int GetMarginTop() const
EDA_ANGLE GetTextAngle() const override
Definition pcb_text.cpp:560
VECTOR2I GetTextPos() const override
Definition pcb_text.cpp:461
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
bool HasSolderMask() const
Definition pcb_track.h:122
std::optional< int > GetLocalSolderMaskMargin() const
Definition pcb_track.h:125
const VECTOR2I & GetStart() const
Definition pcb_track.h:98
const VECTOR2I & GetEnd() const
Definition pcb_track.h:95
virtual int GetWidth() const
Definition pcb_track.h:92
static constexpr int FORMAT_VERSION
void formatGeneral(const BOARD *aBoard) const
void FormatBoardToFormatter(OUTPUTFORMATTER *aOut, BOARD *aBoard)
OUTPUTFORMATTER * m_out
void formatProperties(const BOARD *aBoard) const
void formatLayer(PCB_LAYER_ID aLayer, bool aIsKnockout=false) const
void formatLayers(LSET aLayerMask, bool aEnumerateLayers, bool aIsZone=false) const
void formatPolyPts(const SHAPE_LINE_CHAIN &aOutline, const FOOTPRINT *aParentFP=nullptr) const
void formatHeader(const BOARD *aBoard) const
void formatTeardropParameters(const TEARDROP_PARAMETERS &tdParams) const
void formatVariants(const BOARD *aBoard) const
void formatBoardLayers(const BOARD *aBoard) const
void Format(const BOARD_ITEM *aItem) const
void SaveFootprintFile(const wxString &aFileName, FOOTPRINT *aFootprint)
void format(const BOARD *aBoard) const
void SaveBoard(const wxString &aFileName, BOARD *aBoard)
void formatSetup(const BOARD *aBoard) const
void formatRenderCache(const EDA_TEXT *aText) const
bool Finish() override
Runs prettification over the buffered bytes, writes them to the sibling temp file,...
Definition richio.cpp:710
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:116
const VECTOR2I & GetP1() const
Definition shape_arc.h:115
const VECTOR2I & GetP0() const
Definition shape_arc.h:114
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.
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.
Handle a list of polygons defining a copper zone.
Definition zone.h:70
int GetHatchBorderAlgorithm() const
Definition zone.h:343
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
Definition zone.h:832
std::optional< int > GetLocalClearance() const override
Definition zone.cpp:1097
bool GetDoNotAllowVias() const
Definition zone.h:850
ZONE_LAYER_PROPERTIES & LayerProperties(PCB_LAYER_ID aLayer)
Definition zone.h:146
wxString GetPlacementAreaSource() const
Definition zone.h:837
std::shared_ptr< SHAPE_POLY_SET > GetFilledPolysList(PCB_LAYER_ID aLayer) const
Definition zone.h:699
bool GetDoNotAllowPads() const
Definition zone.h:852
PLACEMENT_SOURCE_T GetPlacementAreaSourceType() const
Definition zone.h:839
bool GetDoNotAllowTracks() const
Definition zone.h:851
bool IsFilled() const
Definition zone.h:306
ISLAND_REMOVAL_MODE GetIslandRemovalMode() const
Definition zone.h:861
bool IsIsland(PCB_LAYER_ID aLayer, int aPolyIdx) const
Check if a given filled polygon is an insulated island.
Definition zone.cpp:1746
long long int GetMinIslandArea() const
Definition zone.h:864
const wxString & GetZoneName() const
Definition zone.h:160
int GetMinThickness() const
Definition zone.h:315
SHAPE_POLY_SET GetBoardOutline() const
Definition zone.cpp:951
ZONE_SETTINGS::CORNER_SMOOTHING GetCornerSmoothingType() const
Definition zone.h:771
ZONE_CONNECTION GetPadConnection() const
Definition zone.h:312
int GetHatchThickness() const
Definition zone.h:325
double GetHatchHoleMinArea() const
Definition zone.h:340
bool GetPlacementAreaEnabled() const
Definition zone.h:834
bool IsTeardropArea() const
Definition zone.h:807
int GetThermalReliefSpokeWidth() const
Definition zone.h:259
int GetBorderHatchPitch() const
HatchBorder related methods.
Definition zone.h:874
ZONE_BORDER_DISPLAY_STYLE GetHatchStyle() const
Definition zone.h:687
EDA_ANGLE GetHatchOrientation() const
Definition zone.h:331
bool GetDoNotAllowFootprints() const
Definition zone.h:853
ZONE_FILL_MODE GetFillMode() const
Definition zone.h:238
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition zone.h:133
int GetHatchGap() const
Definition zone.h:328
TEARDROP_TYPE GetTeardropAreaType() const
Definition zone.h:818
double GetHatchSmoothingValue() const
Definition zone.h:337
bool GetDoNotAllowZoneFills() const
Definition zone.h:849
int GetHatchSmoothingLevel() const
Definition zone.h:334
unsigned int GetCornerRadius() const
Definition zone.h:775
bool IsOnCopperLayer() const override
Definition zone.cpp:650
PCB_LAYER_ID GetFirstLayer() const
Definition zone.cpp:630
int GetThermalReliefGap() const
Definition zone.h:248
unsigned GetAssignedPriority() const
Definition zone.h:122
int GetNumCorners(void) const
Access to m_Poly parameters.
Definition zone.h:617
@ FOR_CANVAS
Definition common.h:92
#define CTL_OMIT_HYPERLINK
Omit the hyperlink attribute in .kicad_xxx files.
Definition ctl_flags.h:46
#define CTL_OMIT_UUIDS
Omit component unique ids (useless in library)
Definition ctl_flags.h:30
#define CTL_OMIT_FOOTPRINT_VERSION
Omit the version string from the (footprint) sexpr group.
Definition ctl_flags.h:39
#define CTL_OMIT_INITIAL_COMMENTS
Omit FOOTPRINT initial comments.
Definition ctl_flags.h:43
#define CTL_OMIT_LIBNAME
Omit lib alias when saving (used for board/not library).
Definition ctl_flags.h:37
#define CTL_OMIT_PATH
Omit component sheet time stamp (useless in library).
Definition ctl_flags.h:33
#define CTL_OMIT_AT
Omit position and rotation.
Definition ctl_flags.h:35
#define CTL_OMIT_PAD_NETS
Omit pads net names (useless in library).
Definition ctl_flags.h:29
#define CTL_OMIT_COLOR
Omit the color attribute in .kicad_xxx files.
Definition ctl_flags.h:45
#define _(s)
static constexpr EDA_ANGLE ANGLE_90
Definition eda_angle.h:474
static constexpr EDA_ANGLE ANGLE_45
Definition eda_angle.h:473
@ REVERSE_HATCH
Definition eda_fill.h:35
@ HATCH
Definition eda_fill.h:34
@ FILLED_SHAPE
Fill with object color.
Definition eda_fill.h:31
@ CROSS_HATCH
Definition eda_fill.h:36
@ SEGMENT
Definition eda_shape.h:56
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
Definition eda_shape.h:57
EDA_DATA_TYPE
The type of unit.
Definition eda_units.h:34
@ FP_SMD
Definition footprint.h:87
@ FP_DNP
Definition footprint.h:92
@ FP_EXCLUDE_FROM_POS_FILES
Definition footprint.h:88
@ FP_BOARD_ONLY
Definition footprint.h:90
@ FP_EXCLUDE_FROM_BOM
Definition footprint.h:89
@ FP_THROUGH_HOLE
Definition footprint.h:86
@ EXPAND_INNER_LAYERS
The 'normal' stackup handling, where there is a single inner layer (In1) and rule areas using it expa...
Definition footprint.h:111
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition idf_helpers.h:37
#define MAX_CU_LAYERS
Definition layer_ids.h:172
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition layer_ids.h:744
bool IsExternalCopperLayer(int aLayerId)
Test whether a layer is an external (F_Cu or B_Cu) copper layer.
Definition layer_ids.h:755
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
@ F_CrtYd
Definition layer_ids.h:112
@ B_Adhes
Definition layer_ids.h:99
@ F_Paste
Definition layer_ids.h:100
@ F_Adhes
Definition layer_ids.h:98
@ B_Mask
Definition layer_ids.h:94
@ B_Cu
Definition layer_ids.h:61
@ F_Mask
Definition layer_ids.h:93
@ B_Paste
Definition layer_ids.h:101
@ F_Fab
Definition layer_ids.h:115
@ F_SilkS
Definition layer_ids.h:96
@ B_CrtYd
Definition layer_ids.h:111
@ UNDEFINED_LAYER
Definition layer_ids.h:57
@ User_1
Definition layer_ids.h:120
@ B_SilkS
Definition layer_ids.h:97
@ PCB_LAYER_ID_COUNT
Definition layer_ids.h:167
@ F_Cu
Definition layer_ids.h:60
@ B_Fab
Definition layer_ids.h:114
This file contains miscellaneous commonly used macros and functions.
#define UNIMPLEMENTED_FOR(type)
Definition macros.h:92
KICOMMON_API std::string FormatAngle(const EDA_ANGLE &aAngle)
Convert aAngle from board units to a string appropriate for writing to file.
KICOMMON_API std::string FormatInternalUnits(const EDA_IU_SCALE &aIuScale, int aValue, EDA_DATA_TYPE aDataType=EDA_DATA_TYPE::DISTANCE)
Converts aValue from internal units to a string appropriate for writing to file.
void FormatBool(OUTPUTFORMATTER *aOut, const wxString &aKey, bool aValue)
void FormatTitle(OUTPUTFORMATTER *aOut, const TITLE_BLOCK &aTitle)
void FormatOptBool(OUTPUTFORMATTER *aOut, const wxString &aKey, std::optional< bool > aValue)
void FormatPlotV10(OUTPUTFORMATTER *aOut, const PCB_PLOT_PARAMS &aPlot)
void FormatStreamData(OUTPUTFORMATTER &aOut, const wxStreamBuffer &aStream)
void FormatUuid(OUTPUTFORMATTER *aOut, const KIID &aUuid)
STRING_ANY_MAP TuningPropertiesForEra(const PCB_GENERATOR &aGenerator, bool aV9)
void FormatTextV10(OUTPUTFORMATTER *aOut, const EDA_TEXT &aText, const EDA_IU_SCALE &aScale, int aControlBits)
void FormatStroke(OUTPUTFORMATTER *aOut, const STROKE_PARAMS &aStroke, const EDA_IU_SCALE &aScale)
UTF8 FormatLibId(const LIB_ID &aId)
void FormatPageV10(OUTPUTFORMATTER *aOut, const PAGE_INFO &aPage)
void FormatEmbeddedFilesV10(OUTPUTFORMATTER &aOut, const EMBEDDED_FILES &aFiles, bool aWriteData)
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
Definition padstack.h:104
@ SMD
Smd pad, appears on the solder paste layer (default)
Definition padstack.h:100
@ PTH
Plated through hole pad.
Definition padstack.h:99
@ CONN
Like smd, does not appear on the solder paste layer (default) Note: also has a special attribute in G...
Definition padstack.h:101
@ CHAMFERED_RECT
Definition padstack.h:61
@ ROUNDRECT
Definition padstack.h:58
@ TRAPEZOID
Definition padstack.h:57
@ RECTANGLE
Definition padstack.h:55
@ FIDUCIAL_LOCAL
a fiducial (usually a smd) local to the parent footprint
Definition padstack.h:119
@ FIDUCIAL_GLBL
a fiducial (usually a smd) for the full board
Definition padstack.h:118
@ MECHANICAL
a pad used for mechanical support
Definition padstack.h:123
@ PRESSFIT
a PTH with a hole diameter with tight tolerances for press fit pin
Definition padstack.h:124
@ HEATSINK
a pad used as heat sink, usually in SMD footprints
Definition padstack.h:121
@ NONE
no special fabrication property
Definition padstack.h:116
@ TESTPOINT
a test point pad
Definition padstack.h:120
@ CASTELLATED
a pad with a castellated through hole
Definition padstack.h:122
@ BGA
Smd pad, used in BGA footprints.
Definition padstack.h:117
BARCODE class definition.
Class to handle a set of BOARD_ITEMs.
bool isDefaultTeardropParameters(const TEARDROP_PARAMETERS &tdParams)
std::string formatInternalUnits(const int aValue, const EDA_DATA_TYPE aDataType=EDA_DATA_TYPE::DISTANCE)
#define CTL_FOR_BOARD
The zero arg constructor when PCB_PLUGIN is used for PLUGIN::Load() and PLUGIN::Save()ing a BOARD fil...
#define CTL_FOR_LIBRARY
Format output for a footprint library instead of clipboard or BOARD.
#define UNDEFINED_DRILL_DIAMETER
static bool isDefaultTeardropParameters(const TEARDROP_PARAMETERS &tdParams)
static void formatBoardStackupV10(OUTPUTFORMATTER *aFormatter, const BOARD *aBoard)
static std::string formatInternalUnits(const int aValue, const EDA_DATA_TYPE aDataType=EDA_DATA_TYPE::DISTANCE)
std::string FormatDouble2Str(double aValue)
Print a float number without using scientific notation and no trailing 0 This function is intended in...
PCB_LAYER_ID start
Definition padstack.h:277
PCB_LAYER_ID end
Definition padstack.h:278
VECTOR2I size
Drill diameter (x == y) or slot dimensions (x != y)
Definition padstack.h:275
std::optional< bool > is_capped
True if the drill hole should be capped.
Definition padstack.h:281
std::optional< bool > is_filled
True if the drill hole should be filled completely.
Definition padstack.h:280
std::optional< bool > has_covering
True if the pad on this side should have covering.
Definition padstack.h:263
std::optional< bool > has_solder_mask
True if this outer layer has mask (is not tented)
Definition padstack.h:261
std::optional< bool > has_plugging
True if the drill hole should be plugged on this side.
Definition padstack.h:264
std::optional< VECTOR2I > hatching_offset
VECTOR2I center
const SHAPE_LINE_CHAIN chain
int delta
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:227
@ PCB_T
Definition typeinfo.h:74
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition typeinfo.h:80
@ PCB_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
Definition typeinfo.h:98
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
Definition typeinfo.h:95
@ PCB_GENERATOR_T
class PCB_GENERATOR, generator on a layer
Definition typeinfo.h:83
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:89
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
Definition typeinfo.h:96
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
Definition typeinfo.h:103
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition typeinfo.h:85
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition typeinfo.h:100
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition typeinfo.h:84
@ PCB_REFERENCE_IMAGE_T
class PCB_REFERENCE_IMAGE, bitmap on a layer
Definition typeinfo.h:81
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
Definition typeinfo.h:82
@ PCB_BARCODE_T
class PCB_BARCODE, a barcode (graphic item)
Definition typeinfo.h:93
@ PCB_TARGET_T
class PCB_TARGET, a target (graphic item)
Definition typeinfo.h:99
@ PCB_TABLECELL_T
class PCB_TABLECELL, PCB_TEXTBOX for use in tables
Definition typeinfo.h:87
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
Definition typeinfo.h:78
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
Definition typeinfo.h:94
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition typeinfo.h:79
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition typeinfo.h:90
@ PCB_TABLE_T
class PCB_TABLE, table of PCB_TABLECELLs
Definition typeinfo.h:86
@ PCB_POINT_T
class PCB_POINT, a 0-dimensional point
Definition typeinfo.h:105
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition typeinfo.h:88
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
Definition typeinfo.h:97
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708
@ THERMAL
Use thermal relief for pads.
Definition zones.h:46
@ THT_THERMAL
Thermal relief only for THT pads.
Definition zones.h:48
@ NONE
Pads are not covered.
Definition zones.h:45
@ FULL
pads are covered by copper
Definition zones.h:47