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 // Save the board physical stackup structure
326 if( aBoard->GetDesignSettings().m_HasStackup )
327 formatBoardStackupV10( m_out, aBoard );
328
329 BOARD_DESIGN_SETTINGS& dsnSettings = aBoard->GetDesignSettings();
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 if( m_board )
2113 {
2114 const auto& cache = m_board->GetItemByIdCache();
2115
2116 std::unordered_set<const EDA_ITEM*> validPtrs;
2117
2118 for( const auto& [uuid, item] : cache )
2119 validPtrs.insert( item );
2120
2121 for( EDA_ITEM* member : aGroup->GetItems() )
2122 {
2123 if( validPtrs.count( member ) )
2124 memberIds.Add( member->m_Uuid.AsString() );
2125 }
2126 }
2127 else
2128 {
2129 for( EDA_ITEM* member : aGroup->GetItems() )
2130 memberIds.Add( member->m_Uuid.AsString() );
2131 }
2132
2133 if( memberIds.empty() )
2134 return;
2135
2136 m_out->Print( "(group %s", m_out->Quotew( aGroup->GetName() ).c_str() );
2137
2139
2140 if( aGroup->IsLocked() )
2141 KICAD_FORMAT::LEGACY::FormatBool( m_out, "locked", true );
2142
2143 if( aGroup->HasDesignBlockLink() )
2144 m_out->Print( "(lib_id \"%s\")", KICAD_FORMAT::LEGACY::FormatLibId( aGroup->GetDesignBlockLibId() ).c_str() );
2145
2146 memberIds.Sort();
2147
2148 m_out->Print( "(members" );
2149
2150 for( const wxString& memberId : memberIds )
2151 m_out->Print( " %s", m_out->Quotew( memberId ).c_str() );
2152
2153 m_out->Print( ")" ); // Close `members` token.
2154 m_out->Print( ")" ); // Close `group` token.
2155}
2156
2157
2158void PCB_WRITER_V10::format( const PCB_GENERATOR* aGenerator ) const
2159{
2160 // Some conditions appear to still be creating ghost tuning patterns. Don't save them.
2161 if( aGenerator->GetGeneratorType() == wxT( "tuning_pattern" ) && aGenerator->GetItems().empty() )
2162 {
2163 return;
2164 }
2165
2166 m_out->Print( "(generated" );
2167
2169
2170 m_out->Print( "(type %s) (name %s) (layer %s)", TO_UTF8( aGenerator->GetGeneratorType() ),
2171 m_out->Quotew( aGenerator->GetName() ).c_str(),
2172 m_out->Quotew( LSET::Name( aGenerator->GetLayer() ) ).c_str() );
2173
2174 if( aGenerator->IsLocked() )
2175 KICAD_FORMAT::LEGACY::FormatBool( m_out, "locked", true );
2176
2177 for( const auto& [key, value] : KICAD_FORMAT::LEGACY::TuningPropertiesForEra( *aGenerator, false ) )
2178 {
2179 if( value.CheckType<double>() || value.CheckType<int>() || value.CheckType<long>()
2180 || value.CheckType<long long>() )
2181 {
2182 double val;
2183
2184 if( !value.GetAs( &val ) )
2185 continue;
2186
2187 std::string buf = fmt::format( "{:.10g}", val );
2188
2189 // Don't quote numbers
2190 m_out->Print( "(%s %s)", key.c_str(), buf.c_str() );
2191 }
2192 else if( value.CheckType<bool>() )
2193 {
2194 bool val;
2195 value.GetAs( &val );
2196
2198 }
2199 else if( value.CheckType<VECTOR2I>() )
2200 {
2201 VECTOR2I val;
2202 value.GetAs( &val );
2203
2204 m_out->Print( "(%s (xy %s))", key.c_str(), formatInternalUnits( val ).c_str() );
2205 }
2206 else if( value.CheckType<SHAPE_LINE_CHAIN>() )
2207 {
2208 SHAPE_LINE_CHAIN val;
2209 value.GetAs( &val );
2210
2211 m_out->Print( "(%s ", key.c_str() );
2212 formatPolyPts( val );
2213 m_out->Print( ")" );
2214 }
2215 else
2216 {
2217 wxString val;
2218
2219 if( value.CheckType<wxString>() )
2220 {
2221 value.GetAs( &val );
2222 }
2223 else if( value.CheckType<std::string>() )
2224 {
2225 std::string str;
2226 value.GetAs( &str );
2227
2228 val = wxString::FromUTF8( str );
2229 }
2230
2231 m_out->Print( "(%s %s)", key.c_str(), m_out->Quotew( val ).c_str() );
2232 }
2233 }
2234
2235 wxArrayString memberIds;
2236
2237 for( EDA_ITEM* member : aGenerator->GetItems() )
2238 memberIds.Add( member->m_Uuid.AsString() );
2239
2240 memberIds.Sort();
2241
2242 m_out->Print( "(members" );
2243
2244 for( const wxString& memberId : memberIds )
2245 m_out->Print( " %s", m_out->Quotew( memberId ).c_str() );
2246
2247 m_out->Print( ")" ); // Close `members` token.
2248 m_out->Print( ")" ); // Close `generated` token.
2249}
2250
2251
2252void PCB_WRITER_V10::format( const PCB_TRACK* aTrack ) const
2253{
2254 if( aTrack->Type() == PCB_VIA_T )
2255 {
2256 PCB_LAYER_ID layer1, layer2;
2257
2258 const PCB_VIA* via = static_cast<const PCB_VIA*>( aTrack );
2259 const BOARD* board = via->GetBoard();
2260
2261 wxCHECK_RET( board != nullptr, wxT( "Via has no parent." ) );
2262
2263 m_out->Print( "(via" );
2264
2265 via->LayerPair( &layer1, &layer2 );
2266
2267 switch( via->GetViaType() )
2268 {
2269 case VIATYPE::THROUGH: // Default shape not saved.
2270 break;
2271
2272 case VIATYPE::BLIND: m_out->Print( " blind " ); break;
2273
2274 case VIATYPE::BURIED: m_out->Print( " buried " ); break;
2275
2276 case VIATYPE::MICROVIA: m_out->Print( " micro " ); break;
2277
2278 default: THROW_IO_ERROR( wxString::Format( _( "unknown via type %d" ), via->GetViaType() ) );
2279 }
2280
2281 m_out->Print( "(at %s) (size %s)", formatInternalUnits( aTrack->GetStart() ).c_str(),
2282 formatInternalUnits( via->GetWidth( F_Cu ) ).c_str() );
2283
2284 // Old boards were using UNDEFINED_DRILL_DIAMETER value in file for via drill when
2285 // via drill was the netclass value.
2286 // recent boards always set the via drill to the actual value, but now we need to
2287 // always store the drill value, because netclass value is not stored in the board file.
2288 // Otherwise the drill value of some (old) vias can be unknown
2289 if( via->GetDrill() != UNDEFINED_DRILL_DIAMETER )
2290 m_out->Print( "(drill %s)", formatInternalUnits( via->GetDrill() ).c_str() );
2291 else
2292 m_out->Print( "(drill %s)", formatInternalUnits( via->GetDrillValue() ).c_str() );
2293
2294 if( via->Padstack().SecondaryDrill().size.x > 0 )
2295 {
2296 m_out->Print( "(backdrill (size %s) (layers %s %s))",
2297 formatInternalUnits( via->Padstack().SecondaryDrill().size.x ).c_str(),
2298 m_out->Quotew( LSET::Name( via->Padstack().SecondaryDrill().start ) ).c_str(),
2299 m_out->Quotew( LSET::Name( via->Padstack().SecondaryDrill().end ) ).c_str() );
2300 }
2301
2302 if( via->Padstack().TertiaryDrill().size.x > 0 )
2303 {
2304 m_out->Print( "(tertiary_drill (size %s) (layers %s %s))",
2305 formatInternalUnits( via->Padstack().TertiaryDrill().size.x ).c_str(),
2306 m_out->Quotew( LSET::Name( via->Padstack().TertiaryDrill().start ) ).c_str(),
2307 m_out->Quotew( LSET::Name( via->Padstack().TertiaryDrill().end ) ).c_str() );
2308 }
2309
2310 auto formatPostMachining = [&]( const char* aName, const PADSTACK::POST_MACHINING_PROPS& aProps )
2311 {
2312 if( !aProps.mode.has_value() || aProps.mode == PAD_DRILL_POST_MACHINING_MODE::NOT_POST_MACHINED )
2313 return;
2314
2315 m_out->Print( "(%s %s", aName,
2316 aProps.mode == PAD_DRILL_POST_MACHINING_MODE::COUNTERBORE ? "counterbore" : "countersink" );
2317
2318 if( aProps.size > 0 )
2319 m_out->Print( " (size %s)", formatInternalUnits( aProps.size ).c_str() );
2320
2321 if( aProps.depth > 0 )
2322 m_out->Print( " (depth %s)", formatInternalUnits( aProps.depth ).c_str() );
2323
2324 if( aProps.angle > 0 )
2325 m_out->Print( " (angle %s)", FormatDouble2Str( aProps.angle / 10.0 ).c_str() );
2326
2327 m_out->Print( ")" );
2328 };
2329
2330 formatPostMachining( "front_post_machining", via->Padstack().FrontPostMachining() );
2331 formatPostMachining( "back_post_machining", via->Padstack().BackPostMachining() );
2332
2333 m_out->Print( "(layers %s %s)", m_out->Quotew( LSET::Name( layer1 ) ).c_str(),
2334 m_out->Quotew( LSET::Name( layer2 ) ).c_str() );
2335
2336 switch( via->Padstack().UnconnectedLayerMode() )
2337 {
2339 KICAD_FORMAT::LEGACY::FormatBool( m_out, "remove_unused_layers", true );
2340 KICAD_FORMAT::LEGACY::FormatBool( m_out, "keep_end_layers", false );
2341 break;
2342
2344 KICAD_FORMAT::LEGACY::FormatBool( m_out, "remove_unused_layers", true );
2345 KICAD_FORMAT::LEGACY::FormatBool( m_out, "keep_end_layers", true );
2346 break;
2347
2349 KICAD_FORMAT::LEGACY::FormatBool( m_out, "start_end_only", true );
2350 break;
2351
2353 }
2354
2355 if( via->IsLocked() )
2356 KICAD_FORMAT::LEGACY::FormatBool( m_out, "locked", true );
2357
2358 if( via->GetIsFree() )
2359 KICAD_FORMAT::LEGACY::FormatBool( m_out, "free", true );
2360
2361 if( via->GetRemoveUnconnected() )
2362 {
2363 m_out->Print( "(zone_layer_connections" );
2364
2365 for( PCB_LAYER_ID layer : board->GetEnabledLayers().CuStack() )
2366 {
2367 if( via->GetZoneLayerOverride( layer ) == ZLO_FORCE_FLASHED )
2368 m_out->Print( " %s", m_out->Quotew( LSET::Name( layer ) ).c_str() );
2369 }
2370
2371 m_out->Print( ")" );
2372 }
2373
2374 const PADSTACK& padstack = via->Padstack();
2375
2376 if( padstack.FrontOuterLayers().has_solder_mask.has_value()
2377 || padstack.BackOuterLayers().has_solder_mask.has_value() )
2378 {
2379 m_out->Print( 0, " (tenting " );
2382 m_out->Print( 0, ")" );
2383 }
2384
2385 if( padstack.Drill().is_capped.has_value() )
2386 KICAD_FORMAT::LEGACY::FormatOptBool( m_out, "capping", padstack.Drill().is_capped );
2387
2388 if( padstack.FrontOuterLayers().has_covering.has_value()
2389 || padstack.BackOuterLayers().has_covering.has_value() )
2390 {
2391 m_out->Print( 0, " (covering " );
2394 m_out->Print( 0, ")" );
2395 }
2396
2397 if( padstack.FrontOuterLayers().has_plugging.has_value()
2398 || padstack.BackOuterLayers().has_plugging.has_value() )
2399 {
2400 m_out->Print( 0, " (plugging " );
2403 m_out->Print( 0, ")" );
2404 }
2405
2406 if( padstack.Drill().is_filled.has_value() )
2407 KICAD_FORMAT::LEGACY::FormatOptBool( m_out, "filling", padstack.Drill().is_filled );
2408
2409 if( padstack.Mode() != PADSTACK::MODE::NORMAL )
2410 {
2411 m_out->Print( "(padstack" );
2412
2413 if( padstack.Mode() == PADSTACK::MODE::FRONT_INNER_BACK )
2414 {
2415 m_out->Print( "(mode front_inner_back)" );
2416
2417 m_out->Print( "(layer \"Inner\"" );
2418 m_out->Print( "(size %s)", formatInternalUnits( padstack.Size( PADSTACK::INNER_LAYERS ).x ).c_str() );
2419 m_out->Print( ")" );
2420 m_out->Print( "(layer \"B.Cu\"" );
2421 m_out->Print( "(size %s)", formatInternalUnits( padstack.Size( B_Cu ).x ).c_str() );
2422 m_out->Print( ")" );
2423 }
2424 else
2425 {
2426 m_out->Print( "(mode custom)" );
2427
2428 for( PCB_LAYER_ID layer : LAYER_RANGE( F_Cu, B_Cu, board->GetCopperLayerCount() ) )
2429 {
2430 if( layer == F_Cu )
2431 continue;
2432
2433 m_out->Print( "(layer %s", m_out->Quotew( LSET::Name( layer ) ).c_str() );
2434 m_out->Print( "(size %s)", formatInternalUnits( padstack.Size( layer ).x ).c_str() );
2435 m_out->Print( ")" );
2436 }
2437 }
2438
2439 m_out->Print( ")" );
2440 }
2441
2442 if( !isDefaultTeardropParameters( via->GetTeardropParams() ) )
2443 formatTeardropParameters( via->GetTeardropParams() );
2444 }
2445 else
2446 {
2447 if( aTrack->Type() == PCB_ARC_T )
2448 {
2449 const PCB_ARC* arc = static_cast<const PCB_ARC*>( aTrack );
2450
2451 m_out->Print( "(arc (start %s) (mid %s) (end %s) (width %s)",
2452 formatInternalUnits( arc->GetStart() ).c_str(), formatInternalUnits( arc->GetMid() ).c_str(),
2453 formatInternalUnits( arc->GetEnd() ).c_str(),
2454 formatInternalUnits( arc->GetWidth() ).c_str() );
2455 }
2456 else
2457 {
2458 m_out->Print( "(segment (start %s) (end %s) (width %s)", formatInternalUnits( aTrack->GetStart() ).c_str(),
2459 formatInternalUnits( aTrack->GetEnd() ).c_str(),
2460 formatInternalUnits( aTrack->GetWidth() ).c_str() );
2461 }
2462
2463 if( aTrack->IsLocked() )
2464 KICAD_FORMAT::LEGACY::FormatBool( m_out, "locked", true );
2465
2466 if( aTrack->GetLayerSet().count() > 1 )
2467 formatLayers( aTrack->GetLayerSet(), false /* enumerate layers */ );
2468 else
2469 formatLayer( aTrack->GetLayer() );
2470
2471 if( aTrack->HasSolderMask() && aTrack->GetLocalSolderMaskMargin().has_value()
2472 && IsExternalCopperLayer( aTrack->GetLayer() ) )
2473 {
2474 m_out->Print( "(solder_mask_margin %s)",
2475 formatInternalUnits( aTrack->GetLocalSolderMaskMargin().value() ).c_str() );
2476 }
2477 }
2478
2479 m_out->Print( "(net %s)", m_out->Quotew( aTrack->GetNetname() ).c_str() );
2480
2482 m_out->Print( ")" );
2483}
2484
2485
2486void PCB_WRITER_V10::format( const ZONE* aZone ) const
2487{
2488 m_out->Print( "(zone" );
2489
2490 if( aZone->IsOnCopperLayer() && !aZone->GetIsRuleArea() && aZone->GetNetCode() > 0 )
2491 m_out->Print( "(net %s)", m_out->Quotew( aZone->GetNetname() ).c_str() );
2492
2493 if( aZone->IsLocked() )
2494 KICAD_FORMAT::LEGACY::FormatBool( m_out, "locked", true );
2495
2496 // If a zone exists on multiple layers, format accordingly
2497 LSET layers = aZone->GetLayerSet();
2498
2499 if( aZone->GetBoard() )
2500 layers &= aZone->GetBoard()->GetEnabledLayers();
2501
2502 // Always enumerate every layer for a zone on a copper layer
2503 if( layers.count() > 1 )
2504 formatLayers( layers, aZone->IsOnCopperLayer(), true );
2505 else
2506 formatLayer( aZone->GetFirstLayer() );
2507
2508 if( !aZone->IsTeardropArea() )
2510
2511 if( !aZone->GetZoneName().empty() && !aZone->IsTeardropArea() )
2512 m_out->Print( "(name %s)", m_out->Quotew( aZone->GetZoneName() ).c_str() );
2513
2514 // Save the outline aux info
2515 std::string hatch;
2516
2517 switch( aZone->GetHatchStyle() )
2518 {
2519 default:
2520 case ZONE_BORDER_DISPLAY_STYLE::NO_HATCH: hatch = "none"; break;
2521 case ZONE_BORDER_DISPLAY_STYLE::DIAGONAL_EDGE: hatch = "edge"; break;
2522 case ZONE_BORDER_DISPLAY_STYLE::DIAGONAL_FULL: hatch = "full"; break;
2523 }
2524
2525 m_out->Print( "(hatch %s %s)", hatch.c_str(), formatInternalUnits( aZone->GetBorderHatchPitch() ).c_str() );
2526
2527
2528 if( aZone->GetAssignedPriority() > 0 )
2529 m_out->Print( "(priority %d)", aZone->GetAssignedPriority() );
2530
2531 // Add teardrop keywords in file: (attr (teardrop (type xxx))) where xxx is the teardrop type
2532 if( aZone->IsTeardropArea() )
2533 {
2534 m_out->Print( "(attr (teardrop (type %s)))",
2535 aZone->GetTeardropAreaType() == TEARDROP_TYPE::TD_VIAPAD ? "padvia" : "track_end" );
2536 }
2537
2538 m_out->Print( "(connect_pads" );
2539
2540 switch( aZone->GetPadConnection() )
2541 {
2542 default:
2543 case ZONE_CONNECTION::THERMAL: // Default option not saved or loaded.
2544 break;
2545
2546 case ZONE_CONNECTION::THT_THERMAL: m_out->Print( " thru_hole_only" ); break;
2547
2548 case ZONE_CONNECTION::FULL: m_out->Print( " yes" ); break;
2549
2550 case ZONE_CONNECTION::NONE: m_out->Print( " no" ); break;
2551 }
2552
2553 m_out->Print( "(clearance %s)", formatInternalUnits( aZone->GetLocalClearance().value() ).c_str() );
2554
2555 m_out->Print( ")" );
2556
2557 m_out->Print( "(min_thickness %s)", formatInternalUnits( aZone->GetMinThickness() ).c_str() );
2558
2559 if( aZone->GetIsRuleArea() )
2560 {
2561 // Keepout settings
2562 m_out->Print( "(keepout (tracks %s) (vias %s) (pads %s) (copperpour %s) (footprints %s))",
2563 aZone->GetDoNotAllowTracks() ? "not_allowed" : "allowed",
2564 aZone->GetDoNotAllowVias() ? "not_allowed" : "allowed",
2565 aZone->GetDoNotAllowPads() ? "not_allowed" : "allowed",
2566 aZone->GetDoNotAllowZoneFills() ? "not_allowed" : "allowed",
2567 aZone->GetDoNotAllowFootprints() ? "not_allowed" : "allowed" );
2568
2569 // Multichannel settings
2570 m_out->Print( "(placement" );
2572
2573 switch( aZone->GetPlacementAreaSourceType() )
2574 {
2576 m_out->Print( "(sheetname %s)", m_out->Quotew( aZone->GetPlacementAreaSource() ).c_str() );
2577 break;
2579 m_out->Print( "(component_class %s)", m_out->Quotew( aZone->GetPlacementAreaSource() ).c_str() );
2580 break;
2582 m_out->Print( "(group %s)", m_out->Quotew( aZone->GetPlacementAreaSource() ).c_str() );
2583 break;
2584 // These are transitory and should not be saved
2586 }
2587
2588 m_out->Print( ")" );
2589 }
2590
2591 m_out->Print( "(fill" );
2592
2593 // Default is not filled.
2594 if( aZone->IsFilled() )
2595 m_out->Print( " yes" );
2596
2597 // Default is polygon filled.
2599 m_out->Print( "(mode hatch)" );
2600
2601 if( !aZone->IsTeardropArea() )
2602 {
2603 m_out->Print( "(thermal_gap %s) (thermal_bridge_width %s)",
2604 formatInternalUnits( aZone->GetThermalReliefGap() ).c_str(),
2605 formatInternalUnits( aZone->GetThermalReliefSpokeWidth() ).c_str() );
2606 }
2607
2609 {
2610 switch( aZone->GetCornerSmoothingType() )
2611 {
2612 case ZONE_SETTINGS::CORNER_SMOOTHING::CHAMFER: m_out->Print( "(smoothing chamfer)" ); break;
2613
2614 case ZONE_SETTINGS::CORNER_SMOOTHING::FILLET: m_out->Print( "(smoothing fillet)" ); break;
2615
2616 default:
2617 THROW_IO_ERROR( wxString::Format( _( "unknown zone corner smoothing type %d" ),
2618 static_cast<int>( aZone->GetCornerSmoothingType() ) ) );
2619 }
2620
2621 if( aZone->GetCornerRadius() != 0 )
2622 m_out->Print( "(radius %s)", formatInternalUnits( aZone->GetCornerRadius() ).c_str() );
2623 }
2624
2625 m_out->Print( "(island_removal_mode %d)", static_cast<int>( aZone->GetIslandRemovalMode() ) );
2626
2628 {
2629 m_out->Print( "(island_area_min %s)",
2630 formatInternalUnits( aZone->GetMinIslandArea() / pcbIUScale.IU_PER_MM ).c_str() );
2631 }
2632
2634 {
2635 m_out->Print( "(hatch_thickness %s) (hatch_gap %s) (hatch_orientation %s)",
2636 formatInternalUnits( aZone->GetHatchThickness() ).c_str(),
2637 formatInternalUnits( aZone->GetHatchGap() ).c_str(),
2638 FormatDouble2Str( aZone->GetHatchOrientation().AsDegrees() ).c_str() );
2639
2640 if( aZone->GetHatchSmoothingLevel() > 0 )
2641 {
2642 m_out->Print( "(hatch_smoothing_level %d) (hatch_smoothing_value %s)", aZone->GetHatchSmoothingLevel(),
2643 FormatDouble2Str( aZone->GetHatchSmoothingValue() ).c_str() );
2644 }
2645
2646 m_out->Print( "(hatch_border_algorithm %s) (hatch_min_hole_area %s)",
2647 aZone->GetHatchBorderAlgorithm() ? "hatch_thickness" : "min_thickness",
2648 FormatDouble2Str( aZone->GetHatchHoleMinArea() ).c_str() );
2649 }
2650
2651 m_out->Print( ")" );
2652
2653 for( const auto& [layer, properties] : aZone->LayerProperties() )
2654 {
2655 format( properties, 0, layer );
2656 }
2657
2658 if( aZone->GetNumCorners() )
2659 {
2660 // Footprint outlines are now stored in library coordinates. The legacy format
2661 // stores these in board coordinates, unlike the other footprint graphics.
2662 SHAPE_POLY_SET::POLYGON poly = aZone->GetBoardOutline().Polygon( 0 );
2663
2664 for( const SHAPE_LINE_CHAIN& chain : poly )
2665 {
2666 m_out->Print( "(polygon" );
2668 m_out->Print( ")" );
2669 }
2670 }
2671
2672 // Save the PolysList (filled areas)
2673 for( PCB_LAYER_ID layer : aZone->GetLayerSet().Seq() )
2674 {
2675 const std::shared_ptr<SHAPE_POLY_SET>& fv = aZone->GetFilledPolysList( layer );
2676
2677 for( int ii = 0; ii < fv->OutlineCount(); ++ii )
2678 {
2679 m_out->Print( "(filled_polygon" );
2680 m_out->Print( "(layer %s)", m_out->Quotew( LSET::Name( layer ) ).c_str() );
2681
2682 if( aZone->IsIsland( layer, ii ) )
2683 KICAD_FORMAT::LEGACY::FormatBool( m_out, "island", true );
2684
2685 const SHAPE_LINE_CHAIN& chain = fv->COutline( ii );
2686
2688 m_out->Print( ")" );
2689 }
2690 }
2691
2692 m_out->Print( ")" );
2693}
2694
2695
2696void PCB_WRITER_V10::format( const ZONE_LAYER_PROPERTIES& aZoneLayerProperties, int aNestLevel,
2697 PCB_LAYER_ID aLayer ) const
2698{
2699 // Do not store the layer properties if no value is actually set.
2700 if( !aZoneLayerProperties.hatching_offset.has_value() )
2701 return;
2702
2703 m_out->Print( aNestLevel, "(property\n" );
2704 m_out->Print( aNestLevel, "(layer %s)\n", m_out->Quotew( LSET::Name( aLayer ) ).c_str() );
2705
2706 if( aZoneLayerProperties.hatching_offset.has_value() )
2707 {
2708 m_out->Print( aNestLevel, "(hatch_position (xy %s))",
2709 formatInternalUnits( aZoneLayerProperties.hatching_offset.value() ).c_str() );
2710 }
2711
2712 m_out->Print( aNestLevel, ")\n" );
2713}
2714
2715
2716void PCB_WRITER_V10::SaveFootprintFile( const wxString& aFileName, FOOTPRINT* aFootprint )
2717{
2718 if( aFootprint->GetAreFontsEmbedded() )
2719 aFootprint->EmbedFonts();
2720 else
2721 aFootprint->GetEmbeddedFiles()->ClearEmbeddedFonts();
2722
2723 PRETTIFIED_FILE_OUTPUTFORMATTER formatter( aFileName );
2724
2725 m_out = &formatter;
2727 Format( aFootprint );
2728 formatter.Finish();
2729 m_out = nullptr;
2730}
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:128
@ LT_FRONT
Definition board.h:249
@ LT_BACK
Definition board.h:250
@ ZLO_FORCE_FLASHED
Definition board_item.h:74
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:64
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:84
virtual bool IsKnockout() const
Definition board_item.h:414
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:410
EMBEDDED_FILES * GetEmbeddedFiles() override
Definition board.cpp:3844
const std::vector< wxString > & GetVariantNames() const
Definition board.h:532
const GENERATORS & Generators() const
Definition board.h:484
const PCB_POINTS & Points() const
Definition board.h:498
const PAGE_INFO & GetPageSettings() const
Definition board.h:1018
const ZONES & Zones() const
Definition board.h:468
const GROUPS & Groups() const
The groups must maintain the following invariants.
Definition board.h:517
LAYER_T GetLayerType(PCB_LAYER_ID aLayer) const
Return the type of the copper layer given by aLayer.
Definition board.cpp:999
TITLE_BLOCK & GetTitleBlock()
Definition board.h:1024
int GetCopperLayerCount() const
Definition board.cpp:1135
const std::map< wxString, wxString > & GetProperties() const
Definition board.h:525
const FOOTPRINTS & Footprints() const
Definition board.h:464
const TRACKS & Tracks() const
Definition board.h:462
wxString GetVariantDescription(const wxString &aVariantName) const
Definition board.cpp:3324
const PCB_PLOT_PARAMS & GetPlotOptions() const
Definition board.h:1021
bool LegacyTeardrops() const
Definition board.h:1651
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition board.cpp:1298
const LSET & GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
Definition board.cpp:1182
const DRAWINGS & Drawings() const
Definition board.h:466
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:368
FILL_T GetFillMode() const
Definition eda_shape.h:148
SHAPE_POLY_SET & GetPolyShape()
SHAPE_T GetShape() const
Definition eda_shape.h:175
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition eda_shape.h:325
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition eda_shape.h:275
wxString SHAPE_T_asString() const
const VECTOR2I & GetBezierC1() const
Definition eda_shape.h:365
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:1243
const CASE_INSENSITIVE_MAP< FOOTPRINT_VARIANT > & GetVariants() const
Get all variants.
Definition footprint.h:1127
void EmbedFonts() override
bool AllowSolderMaskBridges() const
Definition footprint.h:560
wxString GetLibDescription() const
Definition footprint.h:491
ZONE_CONNECTION GetLocalZoneConnection() const
Definition footprint.h:533
bool IsDNP() const
Definition footprint.h:1063
EDA_ANGLE GetOrientation() const
Definition footprint.h:439
ZONES & Zones()
Definition footprint.h:411
PCB_POINTS & Points()
Definition footprint.h:420
bool IsExcludedFromBOM() const
Definition footprint.h:1045
wxString GetSheetname() const
Definition footprint.h:511
const std::vector< FP_UNIT_INFO > & GetUnitInfo() const
Definition footprint.h:1025
std::optional< int > GetLocalSolderPasteMargin() const
Definition footprint.h:526
PCB_FIELD & Value()
read/write accessors:
Definition footprint.h:947
std::optional< int > GetLocalClearance() const
Definition footprint.h:520
PCB_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this footprint.
std::deque< PAD * > & Pads()
Definition footprint.h:405
int GetAttributes() const
Definition footprint.h:551
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition footprint.h:450
LSET GetPrivateLayers() const
Definition footprint.h:345
bool AllowMissingCourtyard() const
Definition footprint.h:557
wxString GetSheetfile() const
Definition footprint.h:514
const std::vector< wxString > & GetNetTiePadGroups() const
Definition footprint.h:609
const LIB_ID & GetFPID() const
Definition footprint.h:474
bool IsLocked() const override
Definition footprint.h:682
bool IsExcludedFromPosFiles() const
Definition footprint.h:1036
const LSET & GetStackupLayers() const
Definition footprint.h:549
PCB_FIELD & Reference()
Definition footprint.h:948
JUMPER_GROUP_SET & JumperPadGroups()
Each jumper pad group is a set of pad numbers that should be treated as internally connected.
Definition footprint.h:1250
bool IsNetTie() const
Definition footprint.h:567
std::optional< double > GetLocalSolderPasteMarginRatio() const
Definition footprint.h:529
GROUPS & Groups()
Definition footprint.h:414
wxString GetFilters() const
Definition footprint.h:517
const wxArrayString * GetInitialComments() const
Return the initial comments block or NULL if none, without transfer of ownership.
Definition footprint.h:1368
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:425
const COMPONENT_CLASS * GetStaticComponentClass() const
Returns the component class for this footprint.
const KIID_PATH & GetPath() const
Definition footprint.h:497
std::optional< int > GetLocalSolderMaskMargin() const
Definition footprint.h:523
wxString GetKeywords() const
Definition footprint.h:494
EMBEDDED_FILES * GetEmbeddedFiles() override
Definition footprint.h:1397
FOOTPRINT_STACKUP GetStackupMode() const
Definition footprint.h:542
bool IsPlaced() const
Definition footprint.h:718
VECTOR2I GetPosition() const override
Definition footprint.h:436
DRAWINGS & GraphicalItems()
Definition footprint.h:408
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:156
std::optional< int > & Clearance(PCB_LAYER_ID aLayer=F_Cu)
Definition padstack.cpp:999
MASK_LAYER_PROPS & FrontOuterLayers()
Definition padstack.h:379
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:365
std::optional< int > & ThermalGap(PCB_LAYER_ID aLayer=F_Cu)
DRILL_PROPS & TertiaryDrill()
Definition padstack.h:362
DRILL_PROPS & Drill()
Definition padstack.h:356
const VECTOR2I & Size(PCB_LAYER_ID aLayer) const
Definition padstack.cpp:868
@ NORMAL
Shape is the same on all layers.
Definition padstack.h:170
@ FRONT_INNER_BACK
Up to three shapes can be defined (F_Cu, inner copper layers, B_Cu)
Definition padstack.h:171
DRILL_PROPS & SecondaryDrill()
Definition padstack.h:359
POST_MACHINING_PROPS & BackPostMachining()
Definition padstack.h:368
MODE Mode() const
Definition padstack.h:344
MASK_LAYER_PROPS & BackOuterLayers()
Definition padstack.h:382
static constexpr PCB_LAYER_ID INNER_LAYERS
! The layer identifier to use for "inner layers" on top/inner/bottom padstacks
Definition padstack.h:182
std::optional< ZONE_CONNECTION > & ZoneConnection(PCB_LAYER_ID aLayer=F_Cu)
Definition pad.h:61
PAD_PROP GetProperty() const
Definition pad.h:563
bool GetRemoveUnconnected() const
Definition pad.h:874
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition pad.h:557
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:517
std::optional< double > GetLocalSolderPasteMarginRatio() const
Definition pad.h:600
const wxString & GetPinType() const
Definition pad.h:160
PAD_ATTRIB GetAttribute() const
Definition pad.h:560
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:757
VECTOR2I GetOffset(PCB_LAYER_ID aLayer) const
Definition pad.cpp:838
VECTOR2I GetDrillSize() const
Definition pad.h:320
double GetRoundRectRadiusRatio(PCB_LAYER_ID aLayer) const
Definition pad.h:811
PAD_SHAPE GetShape(PCB_LAYER_ID aLayer) const
Definition pad.h:205
bool GetKeepTopBottom() const
Definition pad.h:889
VECTOR2I GetSize(PCB_LAYER_ID aLayer) const
Definition pad.cpp:298
int GetPadToDieDelay() const
Definition pad.h:581
std::optional< int > GetLocalClearance() const override
Return any local clearances set in the "classic" (ie: pre-rule) system.
Definition pad.h:583
const PADSTACK & Padstack() const
Definition pad.h:331
EDA_ANGLE GetOrientation() const
Return the rotation angle of the pad.
Definition pad.cpp:1757
PAD_DRILL_SHAPE GetDrillShape() const
Definition pad.h:434
int GetChamferPositions(PCB_LAYER_ID aLayer) const
Definition pad.h:852
std::optional< int > GetLocalSolderPasteMargin() const
Definition pad.h:593
std::optional< int > GetLocalSolderMaskMargin() const
Definition pad.h:586
double GetChamferRectRatio(PCB_LAYER_ID aLayer) const
Definition pad.h:834
std::optional< int > GetLocalThermalSpokeWidthOverride() const
Definition pad.h:741
ZONE_CONNECTION GetLocalZoneConnection() const
Definition pad.h:611
CUSTOM_SHAPE_ZONE_MODE GetCustomShapeInZoneOpt() const
Definition pad.h:227
int GetLocalThermalGapOverride(wxString *aSource) const
Definition pad.cpp:2195
PAD_SHAPE GetAnchorPadShape(PCB_LAYER_ID aLayer) const
Definition pad.h:219
int GetPadToDieLength() const
Definition pad.h:578
const VECTOR2I & GetMid() const
Definition pcb_track.h:295
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:347
bool HasSolderMask() const
Definition pcb_shape.h:344
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:68
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:1062
bool GetDoNotAllowVias() const
Definition zone.h:843
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:845
PLACEMENT_SOURCE_T GetPlacementAreaSourceType() const
Definition zone.h:839
bool GetDoNotAllowTracks() const
Definition zone.h:844
bool IsFilled() const
Definition zone.h:306
ISLAND_REMOVAL_MODE GetIslandRemovalMode() const
Definition zone.h:854
bool IsIsland(PCB_LAYER_ID aLayer, int aPolyIdx) const
Check if a given filled polygon is an insulated island.
Definition zone.cpp:1714
long long int GetMinIslandArea() const
Definition zone.h:857
const wxString & GetZoneName() const
Definition zone.h:160
int GetMinThickness() const
Definition zone.h:315
SHAPE_POLY_SET GetBoardOutline() const
Definition zone.cpp:916
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:867
ZONE_BORDER_DISPLAY_STYLE GetHatchStyle() const
Definition zone.h:687
EDA_ANGLE GetHatchOrientation() const
Definition zone.h:331
bool GetDoNotAllowFootprints() const
Definition zone.h:846
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:842
int GetHatchSmoothingLevel() const
Definition zone.h:334
unsigned int GetCornerRadius() const
Definition zone.h:775
bool IsOnCopperLayer() const override
Definition zone.cpp:615
PCB_LAYER_ID GetFirstLayer() const
Definition zone.cpp:595
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:90
#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:450
static constexpr EDA_ANGLE ANGLE_45
Definition eda_angle.h:449
@ 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:161
#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:703
bool IsExternalCopperLayer(int aLayerId)
Test whether a layer is an external (F_Cu or B_Cu) copper layer.
Definition layer_ids.h:714
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:102
@ SMD
Smd pad, appears on the solder paste layer (default)
Definition padstack.h:98
@ PTH
Plated through hole pad.
Definition padstack.h:97
@ CONN
Like smd, does not appear on the solder paste layer (default) Note: also has a special attribute in G...
Definition padstack.h:99
@ CHAMFERED_RECT
Definition padstack.h:59
@ ROUNDRECT
Definition padstack.h:56
@ TRAPEZOID
Definition padstack.h:55
@ RECTANGLE
Definition padstack.h:53
@ FIDUCIAL_LOCAL
a fiducial (usually a smd) local to the parent footprint
Definition padstack.h:117
@ FIDUCIAL_GLBL
a fiducial (usually a smd) for the full board
Definition padstack.h:116
@ MECHANICAL
a pad used for mechanical support
Definition padstack.h:121
@ PRESSFIT
a PTH with a hole diameter with tight tolerances for press fit pin
Definition padstack.h:122
@ HEATSINK
a pad used as heat sink, usually in SMD footprints
Definition padstack.h:119
@ NONE
no special fabrication property
Definition padstack.h:114
@ TESTPOINT
a test point pad
Definition padstack.h:118
@ CASTELLATED
a pad with a castellated through hole
Definition padstack.h:120
@ BGA
Smd pad, used in BGA footprints.
Definition padstack.h:115
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:275
PCB_LAYER_ID end
Definition padstack.h:276
VECTOR2I size
Drill diameter (x == y) or slot dimensions (x != y)
Definition padstack.h:273
std::optional< bool > is_capped
True if the drill hole should be capped.
Definition padstack.h:279
std::optional< bool > is_filled
True if the drill hole should be filled completely.
Definition padstack.h:278
std::optional< bool > has_covering
True if the pad on this side should have covering.
Definition padstack.h:261
std::optional< bool > has_solder_mask
True if this outer layer has mask (is not tented)
Definition padstack.h:259
std::optional< bool > has_plugging
True if the drill hole should be plugged on this side.
Definition padstack.h:262
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