KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcb_writer_v9.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 9.0 file format, extracted from the 9.0.0 release. It can only emit
21// what 9.0 knew, so its output always opens there. Do not add new-format features here.
22
24
25#include <set>
26#include <wx/ffile.h>
27#include <wx/log.h>
28#include <wx/mstream.h>
29#include <board.h>
31#include <callback_gal.h>
32#include <convert_basic_shapes_to_polygon.h> // for enum RECT_CHAMFER_POSITIONS definition
33#include <fmt/format.h>
34#include <font/fontconfig.h>
35#include <footprint.h>
39#include "legacy_item_order.h"
42#include <layer_range.h>
43#include <locale_io.h>
44#include <macros.h>
45#include <pad.h>
46#include <pcb_dimension.h>
47#include <pcb_generator.h>
48#include <pcb_group.h>
50#include <pcb_reference_image.h>
51#include <pcb_shape.h>
52#include <pcb_table.h>
53#include <pcb_tablecell.h>
54#include <pcb_target.h>
55#include <pcb_text.h>
56#include <pcb_textbox.h>
57#include <pcb_track.h>
58#include <string_utils.h>
59#include <zone.h>
60#include <build_version.h>
61#include <ctl_flags.h>
64#include <richio.h>
65
66
67void NET_MAPPING_V9::SetBoard( const BOARD* aBoard )
68{
69 m_map.clear();
70 m_nets.clear();
71
72 // Collect all the used nets, as the era mapping did. The set keeps netcode order.
73 std::set<int> nets;
74
75 // Be sure that the unconnected gets 0 and is mapped as 0
76 nets.insert( 0 );
77
78 for( ZONE* zone : aBoard->Zones() )
79 nets.insert( zone->GetNetCode() );
80
81 for( PCB_TRACK* track : aBoard->Tracks() )
82 nets.insert( track->GetNetCode() );
83
84 for( BOARD_ITEM* item : aBoard->Drawings() )
85 {
86 if( item->Type() != PCB_SHAPE_T )
87 continue;
88
89 PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( item );
90
91 if( shape->GetNetCode() > 0 )
92 nets.insert( shape->GetNetCode() );
93 }
94
95 for( FOOTPRINT* footprint : aBoard->Footprints() )
96 {
97 for( PAD* pad : footprint->Pads() )
98 nets.insert( pad->GetNetCode() );
99 }
100
101 int next = 0;
102
103 for( int netCode : nets )
104 {
105 m_map[netCode] = next++;
106
107 // May be null for orphan netcodes. The declaration loop skips those, as the era did.
108 m_nets.push_back( aBoard->FindNet( netCode ) );
109 }
110}
111
112
113static void formatBoardStackupV9( OUTPUTFORMATTER* aFormatter, const BOARD* aBoard )
114{
115 const BOARD_STACKUP& stackup = aBoard->GetDesignSettings().GetStackupDescriptor();
116
117 // Board stackup is the ordered list from top to bottom of
118 // physical layers and substrate used to build the board.
119 if( stackup.GetList().empty() )
120 return;
121
122 aFormatter->Print( "(stackup" );
123
124 // Note:
125 // Unspecified parameters are not stored in file.
126 for( BOARD_STACKUP_ITEM* item : stackup.GetList() )
127 {
128 wxString layer_name;
129
130 if( item->GetBrdLayerId() == UNDEFINED_LAYER )
131 layer_name.Printf( wxT( "dielectric %d" ), item->GetDielectricLayerId() );
132 else
133 layer_name = LSET::Name( item->GetBrdLayerId() );
134
135 aFormatter->Print( "(layer %s (type %s)", aFormatter->Quotew( layer_name ).c_str(),
136 aFormatter->Quotew( item->GetTypeName() ).c_str() );
137
138 // Output other parameters (in sub layer list there is at least one item)
139 for( int idx = 0; idx < item->GetSublayersCount(); idx++ )
140 {
141 if( idx ) // not for the main (first) layer.
142 aFormatter->Print( " addsublayer" );
143
144 if( item->IsColorEditable() && IsPrmSpecified( item->GetColor( idx ) ) )
145 {
146 aFormatter->Print( "(color %s)", aFormatter->Quotew( item->GetColor( idx ) ).c_str() );
147 }
148
149 if( item->IsThicknessEditable() )
150 {
151 aFormatter->Print(
152 "(thickness %s",
153 EDA_UNIT_UTILS::FormatInternalUnits( pcbIUScale, item->GetThickness( idx ) ).c_str() );
154
155 if( item->GetType() == BS_ITEM_TYPE_DIELECTRIC && item->IsThicknessLocked( idx ) )
156 aFormatter->Print( " locked" );
157
158 aFormatter->Print( ")" );
159 }
160
161 if( item->HasMaterialValue( idx ) )
162 {
163 aFormatter->Print( "(material %s)", aFormatter->Quotew( item->GetMaterial( idx ) ).c_str() );
164 }
165
166 if( item->HasEpsilonRValue() && item->HasMaterialValue( idx ) )
167 aFormatter->Print( "(epsilon_r %g)", item->GetEpsilonR( idx ) ); //format:allow
168
169 if( item->HasLossTangentValue() && item->HasMaterialValue( idx ) )
170 {
171 aFormatter->Print( "(loss_tangent %s)", FormatDouble2Str( item->GetLossTangent( idx ) ).c_str() );
172 }
173 }
174
175 aFormatter->Print( ")" );
176 }
177
178 // Other infos about board, related to layers and other fabrication specifications
179 if( IsPrmSpecified( stackup.m_FinishType ) )
180 aFormatter->Print( "(copper_finish %s)", aFormatter->Quotew( stackup.m_FinishType ).c_str() );
181
182 KICAD_FORMAT::LEGACY::FormatBool( aFormatter, "dielectric_constraints", stackup.m_HasDielectricConstrains );
183
184 if( stackup.m_EdgeConnectorConstraints > 0 )
185 {
186 aFormatter->Print( "(edge_connector %s)", stackup.m_EdgeConnectorConstraints > 1 ? "bevelled" : "yes" );
187 }
188
189 // The era flag m_CastellatedPads is gone. Reconstruct it from the pads themselves.
190 bool castellatedPads = false;
191
192 for( FOOTPRINT* footprint : aBoard->Footprints() )
193 {
194 for( PAD* pad : footprint->Pads() )
195 {
196 if( pad->GetProperty() == PAD_PROP::CASTELLATED )
197 {
198 castellatedPads = true;
199 break;
200 }
201 }
202
203 if( castellatedPads )
204 break;
205 }
206
207 if( castellatedPads )
208 KICAD_FORMAT::LEGACY::FormatBool( aFormatter, "castellated_pads", true );
209
210 if( stackup.m_EdgePlating )
211 KICAD_FORMAT::LEGACY::FormatBool( aFormatter, "edge_plating", true );
212
213 aFormatter->Print( ")" );
214}
215
216
217void PCB_WRITER_V9::SaveBoard( const wxString& aFileName, BOARD* aBoard )
218{
219 LOCALE_IO toggle;
220
222 m_board = aBoard;
223
224 if( m_board->GetAreFontsEmbedded() )
225 m_board->EmbedFonts();
226 else
227 m_board->GetEmbeddedFiles()->ClearEmbeddedFonts();
228
229 m_mapping.SetBoard( aBoard );
230
231 PRETTIFIED_FILE_OUTPUTFORMATTER formatter( aFileName );
232
233 m_out = &formatter;
234
235 m_out->Print( "(kicad_pcb (version %d) (generator \"pcbnew\") (generator_version %s)",
237
238 Format( aBoard );
239
240 m_out->Print( ")" );
241 formatter.Finish();
242
243 m_out = nullptr;
244}
245
246
247void PCB_WRITER_V9::Format( const BOARD_ITEM* aItem ) const
248{
249 LOCALE_IO toggle;
250
251 switch( aItem->Type() )
252 {
253 case PCB_T: format( static_cast<const BOARD*>( aItem ) ); break;
254
256 case PCB_DIM_CENTER_T:
257 case PCB_DIM_RADIAL_T:
259 case PCB_DIM_LEADER_T: format( static_cast<const PCB_DIMENSION_BASE*>( aItem ) ); break;
260
261 case PCB_SHAPE_T: format( static_cast<const PCB_SHAPE*>( aItem ) ); break;
262
263 case PCB_REFERENCE_IMAGE_T: format( static_cast<const PCB_REFERENCE_IMAGE*>( aItem ) ); break;
264
265 case PCB_TARGET_T: format( static_cast<const PCB_TARGET*>( aItem ) ); break;
266
267 case PCB_FOOTPRINT_T: format( static_cast<const FOOTPRINT*>( aItem ) ); break;
268
269 case PCB_PAD_T: format( static_cast<const PAD*>( aItem ) ); break;
270
271 case PCB_FIELD_T:
272 // Handled in the footprint formatter when properties are formatted
273 break;
274
275 case PCB_TEXT_T: format( static_cast<const PCB_TEXT*>( aItem ) ); break;
276
277 case PCB_TEXTBOX_T: format( static_cast<const PCB_TEXTBOX*>( aItem ) ); break;
278
279 case PCB_TABLE_T: format( static_cast<const PCB_TABLE*>( aItem ) ); break;
280
281 case PCB_GROUP_T: format( static_cast<const PCB_GROUP*>( aItem ) ); break;
282
283 case PCB_GENERATOR_T: format( static_cast<const PCB_GENERATOR*>( aItem ) ); break;
284
285 case PCB_TRACE_T:
286 case PCB_ARC_T:
287 case PCB_VIA_T: format( static_cast<const PCB_TRACK*>( aItem ) ); break;
288
289 case PCB_ZONE_T: format( static_cast<const ZONE*>( aItem ) ); break;
290
291 default: wxFAIL_MSG( wxT( "Cannot format item " ) + aItem->GetClass() );
292 }
293}
294
295
296static std::string formatInternalUnits( int aValue )
297{
299}
300
301
302static std::string formatInternalUnits( const VECTOR2I& aCoord )
303{
305}
306
307
308static std::string formatInternalUnits( const VECTOR2I& aCoord, const FOOTPRINT* aParentFP )
309{
310 if( aParentFP )
311 {
312 VECTOR2I coord = aCoord - aParentFP->GetPosition();
313 RotatePoint( coord, -aParentFP->GetOrientation() );
314 return formatInternalUnits( coord );
315 }
316
317 return formatInternalUnits( aCoord );
318}
319
320
321void PCB_WRITER_V9::formatLayer( PCB_LAYER_ID aLayer, bool aIsKnockout ) const
322{
323 m_out->Print( "(layer %s %s)", m_out->Quotew( LSET::Name( aLayer ) ).c_str(), aIsKnockout ? "knockout" : "" );
324}
325
326
327void PCB_WRITER_V9::formatPolyPts( const SHAPE_LINE_CHAIN& aOutline, const FOOTPRINT* aParentFP ) const
328{
329 m_out->Print( "(pts" );
330
331 for( int ii = 0; ii < aOutline.PointCount(); ++ii )
332 {
333 int ind = aOutline.ArcIndex( ii );
334
335 if( ind < 0 )
336 {
337 m_out->Print( "(xy %s)", formatInternalUnits( aOutline.CPoint( ii ), aParentFP ).c_str() );
338 }
339 else
340 {
341 const SHAPE_ARC& arc = aOutline.Arc( ind );
342 m_out->Print( "(arc (start %s) (mid %s) (end %s))", formatInternalUnits( arc.GetP0(), aParentFP ).c_str(),
343 formatInternalUnits( arc.GetArcMid(), aParentFP ).c_str(),
344 formatInternalUnits( arc.GetP1(), aParentFP ).c_str() );
345
346 do
347 {
348 ++ii;
349 } while( ii < aOutline.PointCount() && aOutline.ArcIndex( ii ) == ind );
350
351 --ii;
352 }
353 }
354
355 m_out->Print( ")" );
356}
357
358
360{
361 wxString resolvedText( aText->GetShownText( FOR_CANVAS ) );
362 std::vector<std::unique_ptr<KIFONT::GLYPH>>* cache = aText->GetRenderCache( aText->GetFont(), resolvedText );
363
364 m_out->Print( "(render_cache %s %s", m_out->Quotew( resolvedText ).c_str(),
365 EDA_UNIT_UTILS::FormatAngle( aText->GetDrawRotation() ).c_str() );
366
368
369 CALLBACK_GAL callback_gal( empty_opts,
370 // Polygon callback
371 [&]( const SHAPE_LINE_CHAIN& aPoly )
372 {
373 m_out->Print( "(polygon" );
374 formatPolyPts( aPoly );
375 m_out->Print( ")" );
376 } );
377
378 callback_gal.SetLineWidth( aText->GetTextThickness() );
379 callback_gal.DrawGlyphs( *cache );
380
381 m_out->Print( ")" );
382}
383
384
385void PCB_WRITER_V9::formatSetup( const BOARD* aBoard ) const
386{
387 // Setup
388 m_out->Print( "(setup" );
389
390 // Save the board physical stackup structure
391 if( aBoard->GetDesignSettings().m_HasStackup )
392 formatBoardStackupV9( m_out, aBoard );
393
394 BOARD_DESIGN_SETTINGS& dsnSettings = aBoard->GetDesignSettings();
395
396 m_out->Print( "(pad_to_mask_clearance %s)", formatInternalUnits( dsnSettings.m_SolderMaskExpansion ).c_str() );
397
398 if( dsnSettings.m_SolderMaskMinWidth )
399 {
400 m_out->Print( "(solder_mask_min_width %s)", formatInternalUnits( dsnSettings.m_SolderMaskMinWidth ).c_str() );
401 }
402
403 if( dsnSettings.m_SolderPasteMargin != 0 )
404 {
405 m_out->Print( "(pad_to_paste_clearance %s)", formatInternalUnits( dsnSettings.m_SolderPasteMargin ).c_str() );
406 }
407
408 if( dsnSettings.m_SolderPasteMarginRatio != 0 )
409 {
410 m_out->Print( "(pad_to_paste_clearance_ratio %s)",
411 FormatDouble2Str( dsnSettings.m_SolderPasteMarginRatio ).c_str() );
412 }
413
414 KICAD_FORMAT::LEGACY::FormatBool( m_out, "allow_soldermask_bridges_in_footprints",
415 dsnSettings.m_AllowSoldermaskBridgesInFPs );
416
417 if( dsnSettings.m_TentViasFront || dsnSettings.m_TentViasBack )
418 {
419 m_out->Print( "(tenting %s %s)", dsnSettings.m_TentViasFront ? "front" : "",
420 dsnSettings.m_TentViasBack ? "back" : "" );
421 }
422 else
423 {
424 m_out->Print( "(tenting none)" );
425 }
426
427 VECTOR2I origin = dsnSettings.GetAuxOrigin();
428
429 if( origin != VECTOR2I( 0, 0 ) )
430 {
431 m_out->Print( "(aux_axis_origin %s %s)", formatInternalUnits( origin.x ).c_str(),
432 formatInternalUnits( origin.y ).c_str() );
433 }
434
435 origin = dsnSettings.GetGridOrigin();
436
437 if( origin != VECTOR2I( 0, 0 ) )
438 {
439 m_out->Print( "(grid_origin %s %s)", formatInternalUnits( origin.x ).c_str(),
440 formatInternalUnits( origin.y ).c_str() );
441 }
442
444
445 m_out->Print( ")" );
446}
447
448
449void PCB_WRITER_V9::formatGeneral( const BOARD* aBoard ) const
450{
451 const BOARD_DESIGN_SETTINGS& dsnSettings = aBoard->GetDesignSettings();
452
453 m_out->Print( "(general" );
454
455 m_out->Print( "(thickness %s)", formatInternalUnits( dsnSettings.GetBoardThickness() ).c_str() );
456
457 KICAD_FORMAT::LEGACY::FormatBool( m_out, "legacy_teardrops", aBoard->LegacyTeardrops() );
458
459 m_out->Print( ")" );
460
463}
464
465
466void PCB_WRITER_V9::formatBoardLayers( const BOARD* aBoard ) const
467{
468 m_out->Print( "(layers" );
469
470 // Save only the used copper layers from front to back.
471
472 for( PCB_LAYER_ID layer : aBoard->GetEnabledLayers().CuStack() )
473 {
474 m_out->Print( "(%d %s %s %s)", layer, m_out->Quotew( LSET::Name( layer ) ).c_str(),
475 LAYER::ShowType( aBoard->GetLayerType( layer ) ),
476 LSET::Name( layer ) == m_board->GetLayerName( layer )
477 ? ""
478 : m_out->Quotew( m_board->GetLayerName( layer ) ).c_str() );
479 }
480
481 // Save used non-copper layers in the order they are defined.
482 LSEQ seq = aBoard->GetEnabledLayers().TechAndUserUIOrder();
483
484 for( PCB_LAYER_ID layer : seq )
485 {
486 m_out->Print( "(%d %s %s %s)", layer, m_out->Quotew( LSET::Name( layer ) ).c_str(),
487 layer >= User_1 && IsCopperLayer( layer ) ? LAYER::ShowType( aBoard->GetLayerType( layer ) )
488 : "user",
489 m_board->GetLayerName( layer ) == LSET::Name( layer )
490 ? ""
491 : m_out->Quotew( m_board->GetLayerName( layer ) ).c_str() );
492 }
493
494 m_out->Print( ")" );
495}
496
497
499{
500 for( NETINFO_ITEM* net : m_mapping.Nets() )
501 {
502 if( net == nullptr ) // Skip not actually existing nets (orphan nets)
503 continue;
504
505 m_out->Print( "(net %d %s)", m_mapping.Translate( net->GetNetCode() ),
506 m_out->Quotew( net->GetNetname() ).c_str() );
507 }
508}
509
510
511void PCB_WRITER_V9::formatProperties( const BOARD* aBoard ) const
512{
513 for( const std::pair<const wxString, wxString>& prop : aBoard->GetProperties() )
514 {
515 m_out->Print( "(property %s %s)", m_out->Quotew( prop.first ).c_str(), m_out->Quotew( prop.second ).c_str() );
516 }
517}
518
519
520void PCB_WRITER_V9::formatHeader( const BOARD* aBoard ) const
521{
522 formatGeneral( aBoard );
523
524 // Layers list.
525 formatBoardLayers( aBoard );
526
527 // Setup
528 formatSetup( aBoard );
529
530 // Properties
531 formatProperties( aBoard );
532
533 // Save net codes and names
534 formatNetInformation( aBoard );
535}
536
537
539{
540 static const TEARDROP_PARAMETERS defaults;
541
542 return tdParams.m_Enabled == defaults.m_Enabled && tdParams.m_BestLengthRatio == defaults.m_BestLengthRatio
543 && tdParams.m_TdMaxLen == defaults.m_TdMaxLen && tdParams.m_BestWidthRatio == defaults.m_BestWidthRatio
544 && tdParams.m_TdMaxWidth == defaults.m_TdMaxWidth && tdParams.m_CurvedEdges == defaults.m_CurvedEdges
546 && tdParams.m_AllowUseTwoTracks == defaults.m_AllowUseTwoTracks
547 && tdParams.m_TdOnPadsInZones == defaults.m_TdOnPadsInZones;
548}
549
550
552{
553 m_out->Print( "(teardrops (best_length_ratio %s) (max_length %s) (best_width_ratio %s) "
554 "(max_width %s)",
555 FormatDouble2Str( tdParams.m_BestLengthRatio ).c_str(),
556 formatInternalUnits( tdParams.m_TdMaxLen ).c_str(),
557 FormatDouble2Str( tdParams.m_BestWidthRatio ).c_str(),
558 formatInternalUnits( tdParams.m_TdMaxWidth ).c_str() );
559
560 KICAD_FORMAT::LEGACY::FormatBool( m_out, "curved_edges", tdParams.m_CurvedEdges );
561
562 m_out->Print( "(filter_ratio %s)", FormatDouble2Str( tdParams.m_WidthtoSizeFilterRatio ).c_str() );
563
564 KICAD_FORMAT::LEGACY::FormatBool( m_out, "enabled", tdParams.m_Enabled );
565 KICAD_FORMAT::LEGACY::FormatBool( m_out, "allow_two_segments", tdParams.m_AllowUseTwoTracks );
566 KICAD_FORMAT::LEGACY::FormatBool( m_out, "prefer_zone_connections", !tdParams.m_TdOnPadsInZones );
567 m_out->Print( ")" );
568}
569
570
571void PCB_WRITER_V9::format( const BOARD* aBoard ) const
572{
573 std::set<BOARD_ITEM*, BOARD_ITEM::ptr_cmp> sorted_footprints( aBoard->Footprints().begin(),
574 aBoard->Footprints().end() );
575 std::set<BOARD_ITEM*, BOARD_ITEM::ptr_cmp> sorted_drawings( aBoard->Drawings().begin(), aBoard->Drawings().end() );
576 std::set<PCB_TRACK*, PCB_TRACK::cmp_tracks> sorted_tracks( aBoard->Tracks().begin(), aBoard->Tracks().end() );
577 std::set<BOARD_ITEM*, BOARD_ITEM::ptr_cmp> sorted_zones( aBoard->Zones().begin(), aBoard->Zones().end() );
578 std::set<BOARD_ITEM*, BOARD_ITEM::ptr_cmp> sorted_groups( aBoard->Groups().begin(), aBoard->Groups().end() );
579 std::set<BOARD_ITEM*, BOARD_ITEM::ptr_cmp> sorted_generators( aBoard->Generators().begin(),
580 aBoard->Generators().end() );
581 formatHeader( aBoard );
582
583 // Save the footprints.
584 for( BOARD_ITEM* footprint : sorted_footprints )
585 Format( footprint );
586
587 // Save the graphical items on the board (not owned by a footprint)
588 for( BOARD_ITEM* item : sorted_drawings )
589 Format( item );
590
591 // Do not save PCB_MARKERs, they can be regenerated easily.
592
593 // Save the tracks and vias.
594 for( PCB_TRACK* track : sorted_tracks )
595 Format( track );
596
597 // Save the polygon (which are the newer technology) zones.
598 for( auto zone : sorted_zones )
599 Format( zone );
600
601 // Save the groups
602 for( BOARD_ITEM* group : sorted_groups )
603 Format( group );
604
605 // Save the generators
606 for( BOARD_ITEM* gen : sorted_generators )
607 Format( gen );
608
609 // Save any embedded files
610 // Consolidate the embedded models in footprints into a single map
611 // to avoid duplicating the same model in the board file.
612 EMBEDDED_FILES files_to_write;
613
614 for( auto& file : aBoard->GetEmbeddedFiles()->EmbeddedFileMap() )
615 files_to_write.AddFile( file.second );
616
617 for( BOARD_ITEM* item : sorted_footprints )
618 {
619 FOOTPRINT* fp = static_cast<FOOTPRINT*>( item );
620
621 for( auto& file : fp->GetEmbeddedFiles()->EmbeddedFileMap() )
622 files_to_write.AddFile( file.second );
623 }
624
625 m_out->Print( "(embedded_fonts %s)", aBoard->GetEmbeddedFiles()->GetAreFontsEmbedded() ? "yes" : "no" );
626
627 if( !files_to_write.IsEmpty() )
629
630 // Remove the files so that they are not freed in the DTOR
631 files_to_write.ClearEmbeddedFiles( false );
632}
633
634
635void PCB_WRITER_V9::format( const PCB_DIMENSION_BASE* aDimension ) const
636{
637 const PCB_DIM_ALIGNED* aligned = dynamic_cast<const PCB_DIM_ALIGNED*>( aDimension );
638 const PCB_DIM_ORTHOGONAL* ortho = dynamic_cast<const PCB_DIM_ORTHOGONAL*>( aDimension );
639 const PCB_DIM_CENTER* center = dynamic_cast<const PCB_DIM_CENTER*>( aDimension );
640 const PCB_DIM_RADIAL* radial = dynamic_cast<const PCB_DIM_RADIAL*>( aDimension );
641 const PCB_DIM_LEADER* leader = dynamic_cast<const PCB_DIM_LEADER*>( aDimension );
642
643 m_out->Print( "(dimension" );
644
645 if( ortho ) // must be tested before aligned, because ortho is derived from aligned
646 // and aligned is not null
647 m_out->Print( "(type orthogonal)" );
648 else if( aligned )
649 m_out->Print( "(type aligned)" );
650 else if( leader )
651 m_out->Print( "(type leader)" );
652 else if( center )
653 m_out->Print( "(type center)" );
654 else if( radial )
655 m_out->Print( "(type radial)" );
656 else
657 wxFAIL_MSG( wxT( "Cannot format unknown dimension type!" ) );
658
659 if( aDimension->IsLocked() )
660 KICAD_FORMAT::LEGACY::FormatBool( m_out, "locked", aDimension->IsLocked() );
661
662 formatLayer( aDimension->GetLayer() );
663
665
666 m_out->Print( "(pts (xy %s %s) (xy %s %s))", formatInternalUnits( aDimension->GetStart().x ).c_str(),
667 formatInternalUnits( aDimension->GetStart().y ).c_str(),
668 formatInternalUnits( aDimension->GetEnd().x ).c_str(),
669 formatInternalUnits( aDimension->GetEnd().y ).c_str() );
670
671 if( aligned )
672 m_out->Print( "(height %s)", formatInternalUnits( aligned->GetHeight() ).c_str() );
673
674 if( radial )
675 {
676 m_out->Print( "(leader_length %s)", formatInternalUnits( radial->GetLeaderLength() ).c_str() );
677 }
678
679 if( ortho )
680 m_out->Print( "(orientation %d)", static_cast<int>( ortho->GetOrientation() ) );
681
682 if( !center )
683 {
684 m_out->Print( "(format (prefix %s) (suffix %s) (units %d) (units_format %d) (precision %d)",
685 m_out->Quotew( aDimension->GetPrefix() ).c_str(),
686 m_out->Quotew( aDimension->GetSuffix() ).c_str(), static_cast<int>( aDimension->GetUnitsMode() ),
687 static_cast<int>( aDimension->GetUnitsFormat() ),
688 static_cast<int>( aDimension->GetPrecision() ) );
689
690 if( aDimension->GetOverrideTextEnabled() )
691 {
692 m_out->Print( "(override_value %s)", m_out->Quotew( aDimension->GetOverrideText() ).c_str() );
693 }
694
695 if( aDimension->GetSuppressZeroes() )
696 KICAD_FORMAT::LEGACY::FormatBool( m_out, "suppress_zeroes", true );
697
698 m_out->Print( ")" );
699 }
700
701 m_out->Print( "(style (thickness %s) (arrow_length %s) (text_position_mode %d)",
702 formatInternalUnits( aDimension->GetLineThickness() ).c_str(),
703 formatInternalUnits( aDimension->GetArrowLength() ).c_str(),
704 static_cast<int>( aDimension->GetTextPositionMode() ) );
705
706 if( ortho || aligned )
707 {
708 switch( aDimension->GetArrowDirection() )
709 {
710 case DIM_ARROW_DIRECTION::OUTWARD: m_out->Print( "(arrow_direction outward)" ); break;
712 m_out->Print( "(arrow_direction inward)" );
713 break;
714 // No default, handle all cases
715 }
716 }
717
718 if( aligned )
719 {
720 m_out->Print( "(extension_height %s)", formatInternalUnits( aligned->GetExtensionHeight() ).c_str() );
721 }
722
723 if( leader )
724 m_out->Print( "(text_frame %d)", static_cast<int>( leader->GetTextBorder() ) );
725
726 m_out->Print( "(extension_offset %s)", formatInternalUnits( aDimension->GetExtensionOffset() ).c_str() );
727
728 if( aDimension->GetKeepTextAligned() )
729 KICAD_FORMAT::LEGACY::FormatBool( m_out, "keep_text_aligned", true );
730
731 m_out->Print( ")" );
732
733 // Write dimension text after all other options to be sure the
734 // text options are known when reading the file
735 if( !center )
736 format( static_cast<const PCB_TEXT*>( aDimension ) );
737
738 m_out->Print( ")" );
739}
740
741
742void PCB_WRITER_V9::format( const PCB_SHAPE* aShape ) const
743{
744 FOOTPRINT* parentFP = aShape->GetParentFootprint();
745 std::string prefix = parentFP ? "fp" : "gr";
746
747 switch( aShape->GetShape() )
748 {
749 case SHAPE_T::SEGMENT:
750 m_out->Print( "(%s_line (start %s) (end %s)", prefix.c_str(),
751 formatInternalUnits( aShape->GetStart(), parentFP ).c_str(),
752 formatInternalUnits( aShape->GetEnd(), parentFP ).c_str() );
753 break;
754
756 m_out->Print( "(%s_rect (start %s) (end %s)", prefix.c_str(),
757 formatInternalUnits( aShape->GetStart(), parentFP ).c_str(),
758 formatInternalUnits( aShape->GetEnd(), parentFP ).c_str() );
759 break;
760
761 case SHAPE_T::CIRCLE:
762 m_out->Print( "(%s_circle (center %s) (end %s)", prefix.c_str(),
763 formatInternalUnits( aShape->GetStart(), parentFP ).c_str(),
764 formatInternalUnits( aShape->GetEnd(), parentFP ).c_str() );
765 break;
766
767 case SHAPE_T::ARC:
768 m_out->Print( "(%s_arc (start %s) (mid %s) (end %s)", prefix.c_str(),
769 formatInternalUnits( aShape->GetStart(), parentFP ).c_str(),
770 formatInternalUnits( aShape->GetArcMid(), parentFP ).c_str(),
771 formatInternalUnits( aShape->GetEnd(), parentFP ).c_str() );
772 break;
773
774 case SHAPE_T::POLY:
775 if( aShape->IsPolyShapeValid() )
776 {
777 const SHAPE_POLY_SET& poly = aShape->GetPolyShape();
778 const SHAPE_LINE_CHAIN& outline = poly.Outline( 0 );
779
780 m_out->Print( "(%s_poly", prefix.c_str() );
781 formatPolyPts( outline, parentFP );
782 }
783 else
784 {
785 wxFAIL_MSG( wxT( "Cannot format invalid polygon." ) );
786 return;
787 }
788
789 break;
790
791 case SHAPE_T::BEZIER:
792 m_out->Print( "(%s_curve (pts (xy %s) (xy %s) (xy %s) (xy %s))", prefix.c_str(),
793 formatInternalUnits( aShape->GetStart(), parentFP ).c_str(),
794 formatInternalUnits( aShape->GetBezierC1(), parentFP ).c_str(),
795 formatInternalUnits( aShape->GetBezierC2(), parentFP ).c_str(),
796 formatInternalUnits( aShape->GetEnd(), parentFP ).c_str() );
797 break;
798
799 default: UNIMPLEMENTED_FOR( aShape->SHAPE_T_asString() ); return;
800 };
801
803
804 // The filled flag represents if a solid fill is present on circles, rectangles and polygons
805 if( ( aShape->GetShape() == SHAPE_T::POLY ) || ( aShape->GetShape() == SHAPE_T::RECTANGLE )
806 || ( aShape->GetShape() == SHAPE_T::CIRCLE ) )
807 {
809 }
810
811 if( aShape->IsLocked() )
812 KICAD_FORMAT::LEGACY::FormatBool( m_out, "locked", true );
813
814 if( aShape->GetLayerSet().count() > 1 )
815 formatLayers( aShape->GetLayerSet(), false /* enumerate layers */ );
816 else
817 formatLayer( aShape->GetLayer() );
818
819 if( aShape->HasSolderMask() && aShape->GetLocalSolderMaskMargin().has_value()
820 && IsExternalCopperLayer( aShape->GetLayer() ) )
821 {
822 m_out->Print( "(solder_mask_margin %s)",
823 formatInternalUnits( aShape->GetLocalSolderMaskMargin().value() ).c_str() );
824 }
825
826 if( aShape->GetNetCode() > 0 )
827 m_out->Print( "(net %d)", m_mapping.Translate( aShape->GetNetCode() ) );
828
830 m_out->Print( ")" );
831}
832
833
834void PCB_WRITER_V9::format( const PCB_REFERENCE_IMAGE* aBitmap ) const
835{
836 wxCHECK_RET( aBitmap != nullptr && m_out != nullptr, "" );
837
838 const REFERENCE_IMAGE& refImage = aBitmap->GetReferenceImage();
839
840 const wxImage* image = refImage.GetImage().GetImageData();
841
842 wxCHECK_RET( image != nullptr, "wxImage* is NULL" );
843
844 m_out->Print( "(image (at %s %s)", formatInternalUnits( aBitmap->GetPosition().x ).c_str(),
845 formatInternalUnits( aBitmap->GetPosition().y ).c_str() );
846
847 formatLayer( aBitmap->GetLayer() );
848
849 if( refImage.GetImageScale() != 1.0 )
850 m_out->Print( "(scale %g)", refImage.GetImageScale() ); //format:allow
851
852 if( aBitmap->IsLocked() )
853 KICAD_FORMAT::LEGACY::FormatBool( m_out, "locked", true );
854
855 wxMemoryOutputStream ostream;
856 refImage.GetImage().SaveImageData( ostream );
857
858 KICAD_FORMAT::LEGACY::FormatStreamData( *m_out, *ostream.GetOutputStreamBuffer() );
859
861 m_out->Print( ")" ); // Closes image token.
862}
863
864
865void PCB_WRITER_V9::format( const PCB_TARGET* aTarget ) const
866{
867 m_out->Print( "(target %s (at %s) (size %s)", ( aTarget->GetShape() ) ? "x" : "plus",
868 formatInternalUnits( aTarget->GetPosition() ).c_str(),
869 formatInternalUnits( aTarget->GetSize() ).c_str() );
870
871 if( aTarget->GetWidth() != 0 )
872 m_out->Print( "(width %s)", formatInternalUnits( aTarget->GetWidth() ).c_str() );
873
874 formatLayer( aTarget->GetLayer() );
876 m_out->Print( ")" );
877}
878
879
880void PCB_WRITER_V9::format( const FOOTPRINT* aFootprint ) const
881{
883 {
884 const wxArrayString* initial_comments = aFootprint->GetInitialComments();
885
886 if( initial_comments )
887 {
888 for( unsigned i = 0; i < initial_comments->GetCount(); ++i )
889 m_out->Print( "%s\n", TO_UTF8( ( *initial_comments )[i] ) );
890 }
891 }
892
893 if( m_ctl & CTL_OMIT_LIBNAME )
894 {
895 m_out->Print( "(footprint %s", m_out->Quotes( aFootprint->GetFPID().GetLibItemName() ).c_str() );
896 }
897 else
898 {
899 m_out->Print( "(footprint %s",
900 m_out->Quotes( KICAD_FORMAT::LEGACY::FormatLibId( aFootprint->GetFPID() ) ).c_str() );
901 }
902
904 {
905 m_out->Print( "(version %d) (generator \"pcbnew\") (generator_version %s)", PCB_WRITER_V9::FORMAT_VERSION,
906 m_out->Quotew( GetMajorMinorVersion() ).c_str() );
907 }
908
909 if( aFootprint->IsLocked() )
910 KICAD_FORMAT::LEGACY::FormatBool( m_out, "locked", true );
911
912 if( aFootprint->IsPlaced() )
913 KICAD_FORMAT::LEGACY::FormatBool( m_out, "placed", true );
914
915 formatLayer( aFootprint->GetLayer() );
916
917 if( !( m_ctl & CTL_OMIT_UUIDS ) )
919
920 if( !( m_ctl & CTL_OMIT_AT ) )
921 {
922 m_out->Print( "(at %s %s)", formatInternalUnits( aFootprint->GetPosition() ).c_str(),
923 aFootprint->GetOrientation().IsZero()
924 ? ""
925 : EDA_UNIT_UTILS::FormatAngle( aFootprint->GetOrientation() ).c_str() );
926 }
927
928 if( !aFootprint->GetLibDescription().IsEmpty() )
929 m_out->Print( "(descr %s)", m_out->Quotew( aFootprint->GetLibDescription() ).c_str() );
930
931 if( !aFootprint->GetKeywords().IsEmpty() )
932 m_out->Print( "(tags %s)", m_out->Quotew( aFootprint->GetKeywords() ).c_str() );
933
934 for( const PCB_FIELD* field : aFootprint->GetFields() )
935 {
936 if( !field )
937 continue;
938
939 m_out->Print( "(property %s %s", m_out->Quotew( field->GetUntranslatedName() ).c_str(),
940 m_out->Quotew( field->GetText() ).c_str() );
941
942 format( field );
943
944 m_out->Print( ")" );
945 }
946
947 if( const COMPONENT_CLASS* compClass = aFootprint->GetStaticComponentClass() )
948 {
949 if( !compClass->IsEmpty() )
950 {
951 m_out->Print( "(component_classes" );
952
953 for( const COMPONENT_CLASS* constituent : compClass->GetConstituentClasses() )
954 m_out->Print( "(class %s)", m_out->Quotew( constituent->GetName() ).c_str() );
955
956 m_out->Print( ")" );
957 }
958 }
959
960 if( !aFootprint->GetFilters().empty() )
961 {
962 m_out->Print( "(property ki_fp_filters %s)", m_out->Quotew( aFootprint->GetFilters() ).c_str() );
963 }
964
965 if( !( m_ctl & CTL_OMIT_PATH ) && !aFootprint->GetPath().empty() )
966 m_out->Print( "(path %s)", m_out->Quotew( aFootprint->GetPath().AsString() ).c_str() );
967
968 if( !aFootprint->GetSheetname().empty() )
969 m_out->Print( "(sheetname %s)", m_out->Quotew( aFootprint->GetSheetname() ).c_str() );
970
971 if( !aFootprint->GetSheetfile().empty() )
972 m_out->Print( "(sheetfile %s)", m_out->Quotew( aFootprint->GetSheetfile() ).c_str() );
973
974 if( aFootprint->GetLocalSolderMaskMargin().has_value() )
975 {
976 m_out->Print( "(solder_mask_margin %s)",
977 formatInternalUnits( aFootprint->GetLocalSolderMaskMargin().value() ).c_str() );
978 }
979
980 if( aFootprint->GetLocalSolderPasteMargin().has_value() )
981 {
982 m_out->Print( "(solder_paste_margin %s)",
983 formatInternalUnits( aFootprint->GetLocalSolderPasteMargin().value() ).c_str() );
984 }
985
986 if( aFootprint->GetLocalSolderPasteMarginRatio().has_value() )
987 {
988 m_out->Print( "(solder_paste_margin_ratio %s)",
989 FormatDouble2Str( aFootprint->GetLocalSolderPasteMarginRatio().value() ).c_str() );
990 }
991
992 if( aFootprint->GetLocalClearance().has_value() )
993 {
994 m_out->Print( "(clearance %s)", formatInternalUnits( aFootprint->GetLocalClearance().value() ).c_str() );
995 }
996
998 {
999 m_out->Print( "(zone_connect %d)", static_cast<int>( aFootprint->GetLocalZoneConnection() ) );
1000 }
1001
1002 // Attributes
1003 if( aFootprint->GetAttributes() )
1004 {
1005 m_out->Print( "(attr" );
1006
1007 if( aFootprint->GetAttributes() & FP_SMD )
1008 m_out->Print( " smd" );
1009
1010 if( aFootprint->GetAttributes() & FP_THROUGH_HOLE )
1011 m_out->Print( " through_hole" );
1012
1013 if( aFootprint->GetAttributes() & FP_BOARD_ONLY )
1014 m_out->Print( " board_only" );
1015
1016 if( aFootprint->GetAttributes() & FP_EXCLUDE_FROM_POS_FILES )
1017 m_out->Print( " exclude_from_pos_files" );
1018
1019 if( aFootprint->GetAttributes() & FP_EXCLUDE_FROM_BOM )
1020 m_out->Print( " exclude_from_bom" );
1021
1022 if( aFootprint->AllowMissingCourtyard() )
1023 m_out->Print( " allow_missing_courtyard" );
1024
1025 if( aFootprint->GetAttributes() & FP_DNP )
1026 m_out->Print( " dnp" );
1027
1028 if( aFootprint->AllowSolderMaskBridges() )
1029 m_out->Print( " allow_soldermask_bridges" );
1030
1031 m_out->Print( ")" );
1032 }
1033
1034 if( aFootprint->GetPrivateLayers().any() )
1035 {
1036 m_out->Print( "(private_layers" );
1037
1038 for( PCB_LAYER_ID layer : aFootprint->GetPrivateLayers().Seq() )
1039 {
1040 wxString canonicalName( LSET::Name( layer ) );
1041 m_out->Print( " %s", m_out->Quotew( canonicalName ).c_str() );
1042 }
1043
1044 m_out->Print( ")" );
1045 }
1046
1047 if( aFootprint->IsNetTie() )
1048 {
1049 m_out->Print( "(net_tie_pad_groups" );
1050
1051 for( const wxString& group : aFootprint->GetNetTiePadGroups() )
1052 m_out->Print( " %s", m_out->Quotew( group ).c_str() );
1053
1054 m_out->Print( ")" );
1055 }
1056
1057 Format( (BOARD_ITEM*) &aFootprint->Reference() );
1058 Format( (BOARD_ITEM*) &aFootprint->Value() );
1059
1060 std::set<PAD*, FOOTPRINT::cmp_pads> sorted_pads( aFootprint->Pads().begin(), aFootprint->Pads().end() );
1061 std::set<BOARD_ITEM*, KICAD_FORMAT::LEGACY::FP_DRAWING_ORDER_V9> sorted_drawings(
1062 aFootprint->GraphicalItems().begin(), aFootprint->GraphicalItems().end() );
1063 std::set<ZONE*, FOOTPRINT::cmp_zones> sorted_zones( aFootprint->Zones().begin(), aFootprint->Zones().end() );
1064 std::set<BOARD_ITEM*, PCB_GROUP::ptr_cmp> sorted_groups( aFootprint->Groups().begin(), aFootprint->Groups().end() );
1065
1066 // Save drawing elements.
1067
1068 for( BOARD_ITEM* gr : sorted_drawings )
1069 Format( gr );
1070
1071 // Save pads.
1072 for( PAD* pad : sorted_pads )
1073 Format( pad );
1074
1075 // Save zones.
1076 for( BOARD_ITEM* zone : sorted_zones )
1077 Format( zone );
1078
1079 // Save groups.
1080 for( BOARD_ITEM* group : sorted_groups )
1081 Format( group );
1082
1083 KICAD_FORMAT::LEGACY::FormatBool( m_out, "embedded_fonts", aFootprint->GetEmbeddedFiles()->GetAreFontsEmbedded() );
1084
1085 if( !aFootprint->GetEmbeddedFiles()->IsEmpty() )
1087
1088 // Save 3D info.
1089 auto bs3D = aFootprint->Models().begin();
1090 auto es3D = aFootprint->Models().end();
1091
1092 while( bs3D != es3D )
1093 {
1094 if( !bs3D->m_Filename.IsEmpty() )
1095 {
1096 m_out->Print( "(model %s", m_out->Quotew( bs3D->m_Filename ).c_str() );
1097
1098 if( !bs3D->m_Show )
1099 KICAD_FORMAT::LEGACY::FormatBool( m_out, "hide", !bs3D->m_Show );
1100
1101 if( bs3D->m_Opacity != 1.0 )
1102 m_out->Print( "(opacity %0.4f)", bs3D->m_Opacity ); //format:allow
1103
1104 m_out->Print( "(offset (xyz %s %s %s))", FormatDouble2Str( bs3D->m_Offset.x ).c_str(),
1105 FormatDouble2Str( bs3D->m_Offset.y ).c_str(), FormatDouble2Str( bs3D->m_Offset.z ).c_str() );
1106
1107 m_out->Print( "(scale (xyz %s %s %s))", FormatDouble2Str( bs3D->m_Scale.x ).c_str(),
1108 FormatDouble2Str( bs3D->m_Scale.y ).c_str(), FormatDouble2Str( bs3D->m_Scale.z ).c_str() );
1109
1110 m_out->Print( "(rotate (xyz %s %s %s))", FormatDouble2Str( bs3D->m_Rotation.x ).c_str(),
1111 FormatDouble2Str( bs3D->m_Rotation.y ).c_str(),
1112 FormatDouble2Str( bs3D->m_Rotation.z ).c_str() );
1113
1114 m_out->Print( ")" );
1115 }
1116
1117 ++bs3D;
1118 }
1119
1120 m_out->Print( ")" );
1121}
1122
1123
1124void PCB_WRITER_V9::formatLayers( LSET aLayerMask, bool aEnumerateLayers ) const
1125{
1126 static const LSET cu_all( LSET::AllCuMask() );
1127 static const LSET fr_bk( { B_Cu, F_Cu } );
1128 static const LSET adhes( { B_Adhes, F_Adhes } );
1129 static const LSET paste( { B_Paste, F_Paste } );
1130 static const LSET silks( { B_SilkS, F_SilkS } );
1131 static const LSET mask( { B_Mask, F_Mask } );
1132 static const LSET crt_yd( { B_CrtYd, F_CrtYd } );
1133 static const LSET fab( { B_Fab, F_Fab } );
1134
1135 LSET cu_board_mask = LSET::AllCuMask( m_board ? m_board->GetCopperLayerCount() : MAX_CU_LAYERS );
1136
1137 std::string output;
1138
1139 if( !aEnumerateLayers )
1140 {
1141 // If all copper layers present on the board are enabled, then output the wildcard
1142 if( ( aLayerMask & cu_board_mask ) == cu_board_mask )
1143 {
1144 output += ' ' + m_out->Quotew( "*.Cu" );
1145
1146 // Clear all copper bits because pads might have internal layers that aren't part of the
1147 // board enabled, and we don't want to output those in the layers listing if we already
1148 // output the wildcard.
1149 aLayerMask &= ~cu_all;
1150 }
1151 else if( ( aLayerMask & cu_board_mask ) == fr_bk )
1152 {
1153 output += ' ' + m_out->Quotew( "F&B.Cu" );
1154 aLayerMask &= ~fr_bk;
1155 }
1156
1157 if( ( aLayerMask & adhes ) == adhes )
1158 {
1159 output += ' ' + m_out->Quotew( "*.Adhes" );
1160 aLayerMask &= ~adhes;
1161 }
1162
1163 if( ( aLayerMask & paste ) == paste )
1164 {
1165 output += ' ' + m_out->Quotew( "*.Paste" );
1166 aLayerMask &= ~paste;
1167 }
1168
1169 if( ( aLayerMask & silks ) == silks )
1170 {
1171 output += ' ' + m_out->Quotew( "*.SilkS" );
1172 aLayerMask &= ~silks;
1173 }
1174
1175 if( ( aLayerMask & mask ) == mask )
1176 {
1177 output += ' ' + m_out->Quotew( "*.Mask" );
1178 aLayerMask &= ~mask;
1179 }
1180
1181 if( ( aLayerMask & crt_yd ) == crt_yd )
1182 {
1183 output += ' ' + m_out->Quotew( "*.CrtYd" );
1184 aLayerMask &= ~crt_yd;
1185 }
1186
1187 if( ( aLayerMask & fab ) == fab )
1188 {
1189 output += ' ' + m_out->Quotew( "*.Fab" );
1190 aLayerMask &= ~fab;
1191 }
1192 }
1193
1194 // output any individual layers not handled in wildcard combos above
1195 for( int layer = 0; layer < PCB_LAYER_ID_COUNT; ++layer )
1196 {
1197 if( aLayerMask[layer] )
1198 output += ' ' + m_out->Quotew( LSET::Name( PCB_LAYER_ID( layer ) ) );
1199 }
1200
1201 m_out->Print( "(layers %s)", output.c_str() );
1202}
1203
1204
1205void PCB_WRITER_V9::format( const PAD* aPad ) const
1206{
1207 const BOARD* board = aPad->GetBoard();
1208
1209 auto shapeName = [&]( PCB_LAYER_ID aLayer )
1210 {
1211 switch( aPad->GetShape( aLayer ) )
1212 {
1213 case PAD_SHAPE::CIRCLE: return "circle";
1214 case PAD_SHAPE::RECTANGLE: return "rect";
1215 case PAD_SHAPE::OVAL: return "oval";
1216 case PAD_SHAPE::TRAPEZOID: return "trapezoid";
1218 case PAD_SHAPE::ROUNDRECT: return "roundrect";
1219 case PAD_SHAPE::CUSTOM: return "custom";
1220
1221 default: THROW_IO_ERROR( wxString::Format( _( "unknown pad type: %d" ), aPad->GetShape( aLayer ) ) );
1222 }
1223 };
1224
1225 const char* type;
1226
1227 switch( aPad->GetAttribute() )
1228 {
1229 case PAD_ATTRIB::PTH: type = "thru_hole"; break;
1230 case PAD_ATTRIB::SMD: type = "smd"; break;
1231 case PAD_ATTRIB::CONN: type = "connect"; break;
1232 case PAD_ATTRIB::NPTH: type = "np_thru_hole"; break;
1233
1234 default: THROW_IO_ERROR( wxString::Format( wxT( "unknown pad attribute: %d" ), aPad->GetAttribute() ) );
1235 }
1236
1237 const char* property = nullptr;
1238
1239 switch( aPad->GetProperty() )
1240 {
1241 case PAD_PROP::NONE: break; // could be "none"
1242 case PAD_PROP::BGA: property = "pad_prop_bga"; break;
1243 case PAD_PROP::FIDUCIAL_GLBL: property = "pad_prop_fiducial_glob"; break;
1244 case PAD_PROP::FIDUCIAL_LOCAL: property = "pad_prop_fiducial_loc"; break;
1245 case PAD_PROP::TESTPOINT: property = "pad_prop_testpoint"; break;
1246 case PAD_PROP::HEATSINK: property = "pad_prop_heatsink"; break;
1247 case PAD_PROP::CASTELLATED: property = "pad_prop_castellated"; break;
1248 case PAD_PROP::MECHANICAL: property = "pad_prop_mechanical"; break;
1249
1250 default: THROW_IO_ERROR( wxString::Format( wxT( "unknown pad property: %d" ), aPad->GetProperty() ) );
1251 }
1252
1253 m_out->Print( "(pad %s %s %s", m_out->Quotew( aPad->GetNumber() ).c_str(), type, shapeName( F_Cu ) );
1254
1255 m_out->Print( "(at %s %s)", formatInternalUnits( aPad->GetFPRelativePosition() ).c_str(),
1256 aPad->GetOrientation().IsZero() ? ""
1257 : EDA_UNIT_UTILS::FormatAngle( aPad->GetOrientation() ).c_str() );
1258
1259 m_out->Print( "(size %s)", formatInternalUnits( aPad->GetSize( F_Cu ) ).c_str() );
1260
1261 if( aPad->GetDelta( F_Cu ).x != 0 || aPad->GetDelta( F_Cu ).y != 0 )
1262 {
1263 m_out->Print( "(rect_delta %s)", formatInternalUnits( aPad->GetDelta( F_Cu ) ).c_str() );
1264 }
1265
1266 VECTOR2I sz = aPad->GetDrillSize();
1267 VECTOR2I shapeoffset = aPad->GetOffset( F_Cu );
1268
1269 if( ( sz.x > 0 ) || ( sz.y > 0 ) || ( shapeoffset.x != 0 ) || ( shapeoffset.y != 0 ) )
1270 {
1271 m_out->Print( "(drill" );
1272
1273 if( aPad->GetDrillShape() == PAD_DRILL_SHAPE::OBLONG )
1274 m_out->Print( " oval" );
1275
1276 if( sz.x > 0 )
1277 m_out->Print( " %s", formatInternalUnits( sz.x ).c_str() );
1278
1279 if( sz.y > 0 && sz.x != sz.y )
1280 m_out->Print( " %s", formatInternalUnits( sz.y ).c_str() );
1281
1282 // NOTE: Shape offest is a property of the copper shape, not of the drill, but this was put
1283 // in the file format under the drill section. So, it is left here to minimize file format
1284 // changes, but note that the other padstack layers (if present) will have an offset stored
1285 // separately.
1286 if( shapeoffset.x != 0 || shapeoffset.y != 0 )
1287 {
1288 m_out->Print( "(offset %s)", formatInternalUnits( aPad->GetOffset( F_Cu ) ).c_str() );
1289 }
1290
1291 m_out->Print( ")" );
1292 }
1293
1294 // Add pad property, if exists.
1295 if( property )
1296 m_out->Print( "(property %s)", property );
1297
1298 formatLayers( aPad->GetLayerSet(), false /* enumerate layers */ );
1299
1300 if( aPad->GetAttribute() == PAD_ATTRIB::PTH )
1301 {
1302 KICAD_FORMAT::LEGACY::FormatBool( m_out, "remove_unused_layers", aPad->GetRemoveUnconnected() );
1303
1304 if( aPad->GetRemoveUnconnected() )
1305 {
1306 KICAD_FORMAT::LEGACY::FormatBool( m_out, "keep_end_layers", aPad->GetKeepTopBottom() );
1307
1308 if( board ) // Will be nullptr in footprint library
1309 {
1310 m_out->Print( "(zone_layer_connections" );
1311
1312 for( PCB_LAYER_ID layer : board->GetEnabledLayers().CuStack() )
1313 {
1314 if( aPad->GetZoneLayerOverride( layer ) == ZLO_FORCE_FLASHED )
1315 m_out->Print( " %s", m_out->Quotew( LSET::Name( layer ) ).c_str() );
1316 }
1317
1318 m_out->Print( ")" );
1319 }
1320 }
1321 }
1322
1323 auto formatCornerProperties = [&]( PCB_LAYER_ID aLayer )
1324 {
1325 // Output the radius ratio for rounded and chamfered rect pads
1326 if( aPad->GetShape( aLayer ) == PAD_SHAPE::ROUNDRECT || aPad->GetShape( aLayer ) == PAD_SHAPE::CHAMFERED_RECT )
1327 {
1328 m_out->Print( "(roundrect_rratio %s)",
1329 FormatDouble2Str( aPad->GetRoundRectRadiusRatio( aLayer ) ).c_str() );
1330 }
1331
1332 // Output the chamfer corners for chamfered rect pads
1333 if( aPad->GetShape( aLayer ) == PAD_SHAPE::CHAMFERED_RECT )
1334 {
1335 m_out->Print( "(chamfer_ratio %s)", FormatDouble2Str( aPad->GetChamferRectRatio( aLayer ) ).c_str() );
1336
1337 m_out->Print( "(chamfer" );
1338
1339 if( ( aPad->GetChamferPositions( aLayer ) & RECT_CHAMFER_TOP_LEFT ) )
1340 m_out->Print( " top_left" );
1341
1342 if( ( aPad->GetChamferPositions( aLayer ) & RECT_CHAMFER_TOP_RIGHT ) )
1343 m_out->Print( " top_right" );
1344
1345 if( ( aPad->GetChamferPositions( aLayer ) & RECT_CHAMFER_BOTTOM_LEFT ) )
1346 m_out->Print( " bottom_left" );
1347
1348 if( ( aPad->GetChamferPositions( aLayer ) & RECT_CHAMFER_BOTTOM_RIGHT ) )
1349 m_out->Print( " bottom_right" );
1350
1351 m_out->Print( ")" );
1352 }
1353 };
1354
1355 // For normal padstacks, this is the one and only set of properties. For complex ones, this
1356 // will represent the front layer properties, and other layers will be formatted below
1357 formatCornerProperties( F_Cu );
1358
1359 // Unconnected pad is default net so don't save it.
1361 {
1362 m_out->Print( "(net %d %s)", m_mapping.Translate( aPad->GetNetCode() ),
1363 m_out->Quotew( aPad->GetNetname() ).c_str() );
1364 }
1365
1366 // Pin functions and types are closely related to nets, so if CTL_OMIT_NETS is set, omit
1367 // them as well (for instance when saved from library editor).
1368 if( !( m_ctl & CTL_OMIT_PAD_NETS ) )
1369 {
1370 if( !aPad->GetPinFunction().IsEmpty() )
1371 m_out->Print( "(pinfunction %s)", m_out->Quotew( aPad->GetPinFunction() ).c_str() );
1372
1373 if( !aPad->GetPinType().IsEmpty() )
1374 m_out->Print( "(pintype %s)", m_out->Quotew( aPad->GetPinType() ).c_str() );
1375 }
1376
1377 if( aPad->GetPadToDieLength() != 0 )
1378 {
1379 m_out->Print( "(die_length %s)", formatInternalUnits( aPad->GetPadToDieLength() ).c_str() );
1380 }
1381
1382 if( aPad->GetLocalSolderMaskMargin().has_value() )
1383 {
1384 m_out->Print( "(solder_mask_margin %s)",
1385 formatInternalUnits( aPad->GetLocalSolderMaskMargin().value() ).c_str() );
1386 }
1387
1388 if( aPad->GetLocalSolderPasteMargin().has_value() )
1389 {
1390 m_out->Print( "(solder_paste_margin %s)",
1391 formatInternalUnits( aPad->GetLocalSolderPasteMargin().value() ).c_str() );
1392 }
1393
1394 if( aPad->GetLocalSolderPasteMarginRatio().has_value() )
1395 {
1396 m_out->Print( "(solder_paste_margin_ratio %s)",
1397 FormatDouble2Str( aPad->GetLocalSolderPasteMarginRatio().value() ).c_str() );
1398 }
1399
1400 if( aPad->GetLocalClearance().has_value() )
1401 {
1402 m_out->Print( "(clearance %s)", formatInternalUnits( aPad->GetLocalClearance().value() ).c_str() );
1403 }
1404
1406 {
1407 m_out->Print( "(zone_connect %d)", static_cast<int>( aPad->GetLocalZoneConnection() ) );
1408 }
1409
1410 if( aPad->GetLocalThermalSpokeWidthOverride().has_value() )
1411 {
1412 m_out->Print( "(thermal_bridge_width %s)",
1413 formatInternalUnits( aPad->GetLocalThermalSpokeWidthOverride().value() ).c_str() );
1414 }
1415
1416 EDA_ANGLE defaultThermalSpokeAngle = ANGLE_90;
1417
1418 if( aPad->GetShape( F_Cu ) == PAD_SHAPE::CIRCLE
1419 || ( aPad->GetShape( F_Cu ) == PAD_SHAPE::CUSTOM && aPad->GetAnchorPadShape( F_Cu ) == PAD_SHAPE::CIRCLE ) )
1420 {
1421 defaultThermalSpokeAngle = ANGLE_45;
1422 }
1423
1424 if( aPad->GetThermalSpokeAngle() != defaultThermalSpokeAngle )
1425 {
1426 m_out->Print( "(thermal_bridge_angle %s)",
1428 }
1429
1430 if( aPad->GetLocalThermalGapOverride().has_value() )
1431 {
1432 m_out->Print( "(thermal_gap %s)", formatInternalUnits( aPad->GetLocalThermalGapOverride().value() ).c_str() );
1433 }
1434
1435 auto anchorShape = [&]( PCB_LAYER_ID aLayer )
1436 {
1437 switch( aPad->GetAnchorPadShape( aLayer ) )
1438 {
1439 case PAD_SHAPE::RECTANGLE: return "rect";
1440 default:
1441 case PAD_SHAPE::CIRCLE: return "circle";
1442 }
1443 };
1444
1445 auto formatPrimitives = [&]( PCB_LAYER_ID aLayer )
1446 {
1447 m_out->Print( "(primitives" );
1448
1449 // Output all basic shapes
1450 for( const std::shared_ptr<PCB_SHAPE>& primitive : aPad->GetPrimitives( aLayer ) )
1451 {
1452 // Set false by any branch that opens no node. The width, the fill and the closing
1453 // paren below belong to that node, so emitting them without it corrupts the file.
1454 bool emitted = true;
1455
1456 switch( primitive->GetShape() )
1457 {
1458 case SHAPE_T::SEGMENT:
1459 if( primitive->IsProxyItem() )
1460 {
1461 m_out->Print( "(gr_vector (start %s) (end %s)",
1462 formatInternalUnits( primitive->GetStart() ).c_str(),
1463 formatInternalUnits( primitive->GetEnd() ).c_str() );
1464 }
1465 else
1466 {
1467 m_out->Print( "(gr_line (start %s) (end %s)", formatInternalUnits( primitive->GetStart() ).c_str(),
1468 formatInternalUnits( primitive->GetEnd() ).c_str() );
1469 }
1470 break;
1471
1472 case SHAPE_T::RECTANGLE:
1473 if( primitive->IsProxyItem() )
1474 {
1475 m_out->Print( "(gr_bbox (start %s) (end %s)", formatInternalUnits( primitive->GetStart() ).c_str(),
1476 formatInternalUnits( primitive->GetEnd() ).c_str() );
1477 }
1478 else
1479 {
1480 m_out->Print( "(gr_rect (start %s) (end %s)", formatInternalUnits( primitive->GetStart() ).c_str(),
1481 formatInternalUnits( primitive->GetEnd() ).c_str() );
1482 }
1483 break;
1484
1485 case SHAPE_T::ARC:
1486 m_out->Print( "(gr_arc (start %s) (mid %s) (end %s)",
1487 formatInternalUnits( primitive->GetStart() ).c_str(),
1488 formatInternalUnits( primitive->GetArcMid() ).c_str(),
1489 formatInternalUnits( primitive->GetEnd() ).c_str() );
1490 break;
1491
1492 case SHAPE_T::CIRCLE:
1493 m_out->Print( "(gr_circle (center %s) (end %s)", formatInternalUnits( primitive->GetStart() ).c_str(),
1494 formatInternalUnits( primitive->GetEnd() ).c_str() );
1495 break;
1496
1497 case SHAPE_T::BEZIER:
1498 m_out->Print( "(gr_curve (pts (xy %s) (xy %s) (xy %s) (xy %s))",
1499 formatInternalUnits( primitive->GetStart() ).c_str(),
1500 formatInternalUnits( primitive->GetBezierC1() ).c_str(),
1501 formatInternalUnits( primitive->GetBezierC2() ).c_str(),
1502 formatInternalUnits( primitive->GetEnd() ).c_str() );
1503 break;
1504
1505 case SHAPE_T::POLY:
1506 if( !primitive->IsPolyShapeValid() )
1507 {
1508 emitted = false;
1509 }
1510 else
1511 {
1512 const SHAPE_POLY_SET& poly = primitive->GetPolyShape();
1513 const SHAPE_LINE_CHAIN& outline = poly.Outline( 0 );
1514
1515 m_out->Print( "(gr_poly" );
1516 formatPolyPts( outline );
1517 }
1518 break;
1519
1520 default: emitted = false; break;
1521 }
1522
1523 if( !emitted )
1524 continue;
1525
1526 if( !primitive->IsProxyItem() )
1527 m_out->Print( "(width %s)", formatInternalUnits( primitive->GetWidth() ).c_str() );
1528
1529 // The filled flag represents if a solid fill is present on circles,
1530 // rectangles and polygons
1531 if( ( primitive->GetShape() == SHAPE_T::POLY ) || ( primitive->GetShape() == SHAPE_T::RECTANGLE )
1532 || ( primitive->GetShape() == SHAPE_T::CIRCLE ) )
1533 {
1534 KICAD_FORMAT::LEGACY::FormatBool( m_out, "fill", primitive->IsAnyFill() );
1535 }
1536
1537 m_out->Print( ")" );
1538 }
1539
1540 m_out->Print( ")" ); // end of (primitives
1541 };
1542
1543 if( aPad->GetShape( F_Cu ) == PAD_SHAPE::CUSTOM )
1544 {
1545 m_out->Print( "(options" );
1546
1548 m_out->Print( "(clearance convexhull)" );
1549 else
1550 m_out->Print( "(clearance outline)" );
1551
1552 // Output the anchor pad shape (circle/rect)
1553 m_out->Print( "(anchor %s)", anchorShape( F_Cu ) );
1554
1555 m_out->Print( ")" ); // end of (options ...
1556
1557 // Output graphic primitive of the pad shape
1558 formatPrimitives( F_Cu );
1559 }
1560
1563
1564 formatTenting( aPad->Padstack() );
1565
1567
1568 auto formatPadLayer = [&]( PCB_LAYER_ID aLayer )
1569 {
1570 const PADSTACK& padstack = aPad->Padstack();
1571
1572 m_out->Print( "(shape %s)", shapeName( aLayer ) );
1573 m_out->Print( "(size %s)", formatInternalUnits( aPad->GetSize( aLayer ) ).c_str() );
1574
1575 const VECTOR2I& delta = aPad->GetDelta( aLayer );
1576
1577 if( delta.x != 0 || delta.y != 0 )
1578 m_out->Print( "(rect_delta %s)", formatInternalUnits( delta ).c_str() );
1579
1580 shapeoffset = aPad->GetOffset( aLayer );
1581
1582 if( shapeoffset.x != 0 || shapeoffset.y != 0 )
1583 m_out->Print( "(offset %s)", formatInternalUnits( shapeoffset ).c_str() );
1584
1585 formatCornerProperties( aLayer );
1586
1587 if( aPad->GetShape( aLayer ) == PAD_SHAPE::CUSTOM )
1588 {
1589 m_out->Print( "(options" );
1590
1591 // Output the anchor pad shape (circle/rect)
1592 m_out->Print( "(anchor %s)", anchorShape( aLayer ) );
1593
1594 m_out->Print( ")" ); // end of (options ...
1595
1596 // Output graphic primitive of the pad shape
1597 formatPrimitives( aLayer );
1598 }
1599
1600 EDA_ANGLE defaultLayerAngle = ANGLE_90;
1601
1602 if( aPad->GetShape( aLayer ) == PAD_SHAPE::CIRCLE
1603 || ( aPad->GetShape( aLayer ) == PAD_SHAPE::CUSTOM
1604 && aPad->GetAnchorPadShape( aLayer ) == PAD_SHAPE::CIRCLE ) )
1605 {
1606 defaultLayerAngle = ANGLE_45;
1607 }
1608
1609 EDA_ANGLE layerSpokeAngle = padstack.ThermalSpokeAngle( aLayer );
1610
1611 if( layerSpokeAngle != defaultLayerAngle )
1612 {
1613 m_out->Print( "(thermal_bridge_angle %s)", EDA_UNIT_UTILS::FormatAngle( layerSpokeAngle ).c_str() );
1614 }
1615
1616 if( padstack.ThermalGap( aLayer ).has_value() )
1617 {
1618 m_out->Print( "(thermal_gap %s)", formatInternalUnits( *padstack.ThermalGap( aLayer ) ).c_str() );
1619 }
1620
1621 if( padstack.ThermalSpokeWidth( aLayer ).has_value() )
1622 {
1623 m_out->Print( "(thermal_bridge_width %s)",
1624 formatInternalUnits( *padstack.ThermalSpokeWidth( aLayer ) ).c_str() );
1625 }
1626
1627 if( padstack.Clearance( aLayer ).has_value() )
1628 {
1629 m_out->Print( "(clearance %s)", formatInternalUnits( *padstack.Clearance( aLayer ) ).c_str() );
1630 }
1631
1632 if( padstack.ZoneConnection( aLayer ).has_value() )
1633 {
1634 m_out->Print( "(zone_connect %d)", static_cast<int>( *padstack.ZoneConnection( aLayer ) ) );
1635 }
1636 };
1637
1638
1639 if( aPad->Padstack().Mode() != PADSTACK::MODE::NORMAL )
1640 {
1642 {
1643 m_out->Print( "(padstack (mode front_inner_back)" );
1644
1645 m_out->Print( "(layer \"Inner\"" );
1646 formatPadLayer( PADSTACK::INNER_LAYERS );
1647 m_out->Print( ")" );
1648 m_out->Print( "(layer \"B.Cu\"" );
1649 formatPadLayer( B_Cu );
1650 m_out->Print( ")" );
1651 }
1652 else
1653 {
1654 m_out->Print( "(padstack (mode custom)" );
1655
1656 int layerCount = board ? board->GetCopperLayerCount() : MAX_CU_LAYERS;
1657
1658 for( PCB_LAYER_ID layer : LAYER_RANGE( F_Cu, B_Cu, layerCount ) )
1659 {
1660 if( layer == F_Cu )
1661 continue;
1662
1663 m_out->Print( "(layer %s", m_out->Quotew( LSET::Name( layer ) ).c_str() );
1664 formatPadLayer( layer );
1665 m_out->Print( ")" );
1666 }
1667 }
1668
1669 m_out->Print( ")" );
1670 }
1671
1672 m_out->Print( ")" );
1673}
1674
1675
1676void PCB_WRITER_V9::formatTenting( const PADSTACK& aPadstack ) const
1677{
1678 std::optional<bool> front = aPadstack.FrontOuterLayers().has_solder_mask;
1679 std::optional<bool> back = aPadstack.BackOuterLayers().has_solder_mask;
1680
1681 if( front.has_value() || back.has_value() )
1682 {
1683 if( front.value_or( false ) || back.value_or( false ) )
1684 {
1685 m_out->Print( "(tenting %s %s)", front.value_or( false ) ? "front" : "",
1686 back.value_or( false ) ? "back" : "" );
1687 }
1688 else
1689 {
1690 m_out->Print( "(tenting none)" );
1691 }
1692 }
1693}
1694
1695
1696void PCB_WRITER_V9::format( const PCB_TEXT* aText ) const
1697{
1698 FOOTPRINT* parentFP = aText->GetParentFootprint();
1699 std::string prefix;
1700 std::string type;
1701 VECTOR2I pos = aText->GetTextPos();
1702 bool isField = aText->Type() == PCB_FIELD_T;
1703
1704 // Always format dimension text as gr_text
1705 if( dynamic_cast<const PCB_DIMENSION_BASE*>( aText ) )
1706 parentFP = nullptr;
1707
1708 if( parentFP )
1709 {
1710 prefix = "fp";
1711 type = "user";
1712
1713 pos -= parentFP->GetPosition();
1714 RotatePoint( pos, -parentFP->GetOrientation() );
1715 }
1716 else
1717 {
1718 prefix = "gr";
1719 }
1720
1721 if( !isField )
1722 {
1723 m_out->Print( "(%s_text %s %s", prefix.c_str(), type.c_str(), m_out->Quotew( aText->GetText() ).c_str() );
1724
1725 if( aText->IsLocked() )
1726 KICAD_FORMAT::LEGACY::FormatBool( m_out, "locked", true );
1727 }
1728
1729 m_out->Print( "(at %s %s)", formatInternalUnits( pos ).c_str(),
1730 EDA_UNIT_UTILS::FormatAngle( aText->GetTextAngle() ).c_str() );
1731
1732 if( parentFP && !aText->IsKeepUpright() )
1733 KICAD_FORMAT::LEGACY::FormatBool( m_out, "unlocked", true );
1734
1735 formatLayer( aText->GetLayer(), aText->IsKnockout() );
1736
1737 if( parentFP && !aText->IsVisible() )
1738 KICAD_FORMAT::LEGACY::FormatBool( m_out, "hide", true );
1739
1741
1742 int ctl_flags = m_ctl | KICAD_FORMAT::LEGACY::OMIT_HIDE;
1743
1744 // Currently, texts have no specific color and no hyperlink.
1745 // so ensure they are never written in kicad_pcb file
1746 ctl_flags |= CTL_OMIT_COLOR | CTL_OMIT_HYPERLINK;
1747
1749
1750 if( aText->GetFont() && aText->GetFont()->IsOutline() )
1751 formatRenderCache( aText );
1752
1753 if( !isField )
1754 m_out->Print( ")" );
1755}
1756
1757
1758void PCB_WRITER_V9::format( const PCB_TEXTBOX* aTextBox ) const
1759{
1760 FOOTPRINT* parentFP = aTextBox->GetParentFootprint();
1761
1762 m_out->Print( "(%s %s",
1763 aTextBox->Type() == PCB_TABLECELL_T ? "table_cell"
1764 : parentFP ? "fp_text_box"
1765 : "gr_text_box",
1766 m_out->Quotew( aTextBox->GetText() ).c_str() );
1767
1768 if( aTextBox->IsLocked() )
1769 KICAD_FORMAT::LEGACY::FormatBool( m_out, "locked", true );
1770
1771 if( aTextBox->GetShape() == SHAPE_T::RECTANGLE )
1772 {
1773 m_out->Print( "(start %s) (end %s)", formatInternalUnits( aTextBox->GetStart(), parentFP ).c_str(),
1774 formatInternalUnits( aTextBox->GetEnd(), parentFP ).c_str() );
1775 }
1776 else if( aTextBox->GetShape() == SHAPE_T::POLY )
1777 {
1778 const SHAPE_POLY_SET& poly = aTextBox->GetPolyShape();
1779 const SHAPE_LINE_CHAIN& outline = poly.Outline( 0 );
1780
1781 formatPolyPts( outline, parentFP );
1782 }
1783 else
1784 {
1785 UNIMPLEMENTED_FOR( aTextBox->SHAPE_T_asString() );
1786 }
1787
1788 m_out->Print( "(margins %s %s %s %s)", formatInternalUnits( aTextBox->GetMarginLeft() ).c_str(),
1789 formatInternalUnits( aTextBox->GetMarginTop() ).c_str(),
1790 formatInternalUnits( aTextBox->GetMarginRight() ).c_str(),
1791 formatInternalUnits( aTextBox->GetMarginBottom() ).c_str() );
1792
1793 if( const PCB_TABLECELL* cell = dynamic_cast<const PCB_TABLECELL*>( aTextBox ) )
1794 m_out->Print( "(span %d %d)", cell->GetColSpan(), cell->GetRowSpan() );
1795
1796 EDA_ANGLE angle = aTextBox->GetTextAngle();
1797
1798 if( parentFP )
1799 {
1800 angle -= parentFP->GetOrientation();
1801 angle.Normalize720();
1802 }
1803
1804 if( !angle.IsZero() )
1805 m_out->Print( "(angle %s)", EDA_UNIT_UTILS::FormatAngle( angle ).c_str() );
1806
1807 formatLayer( aTextBox->GetLayer() );
1808
1810
1811 // PCB_TEXTBOXes are never hidden, so always omit "hide" attribute
1813
1814 if( aTextBox->Type() != PCB_TABLECELL_T )
1815 {
1816 KICAD_FORMAT::LEGACY::FormatBool( m_out, "border", aTextBox->IsBorderEnabled() );
1818 }
1819
1820 if( aTextBox->GetFont() && aTextBox->GetFont()->IsOutline() )
1821 formatRenderCache( aTextBox );
1822
1823 m_out->Print( ")" );
1824}
1825
1826
1827void PCB_WRITER_V9::format( const PCB_TABLE* aTable ) const
1828{
1829 wxCHECK_RET( aTable != nullptr && m_out != nullptr, "" );
1830
1831 m_out->Print( "(table (column_count %d)", aTable->GetColCount() );
1832
1833 if( aTable->IsLocked() )
1834 KICAD_FORMAT::LEGACY::FormatBool( m_out, "locked", true );
1835
1836 formatLayer( aTable->GetLayer() );
1837
1838 m_out->Print( "(border" );
1839 KICAD_FORMAT::LEGACY::FormatBool( m_out, "external", aTable->StrokeExternal() );
1841
1842 if( aTable->StrokeExternal() || aTable->StrokeHeaderSeparator() )
1844
1845 m_out->Print( ")" ); // Close `border` token.
1846
1847 m_out->Print( "(separators" );
1850
1851 if( aTable->StrokeRows() || aTable->StrokeColumns() )
1853
1854 m_out->Print( ")" ); // Close `separators` token.
1855
1856 m_out->Print( "(column_widths" );
1857
1858 for( int col = 0; col < aTable->GetColCount(); ++col )
1859 m_out->Print( " %s", formatInternalUnits( aTable->GetColWidth( col ) ).c_str() );
1860
1861 m_out->Print( ")" );
1862
1863 m_out->Print( "(row_heights" );
1864
1865 for( int row = 0; row < aTable->GetRowCount(); ++row )
1866 m_out->Print( " %s", formatInternalUnits( aTable->GetRowHeight( row ) ).c_str() );
1867
1868 m_out->Print( ")" );
1869
1870 m_out->Print( "(cells" );
1871
1872 for( PCB_TABLECELL* cell : aTable->GetCells() )
1873 format( static_cast<PCB_TEXTBOX*>( cell ) );
1874
1875 m_out->Print( ")" ); // Close `cells` token.
1876 m_out->Print( ")" ); // Close `table` token.
1877}
1878
1879
1880void PCB_WRITER_V9::format( const PCB_GROUP* aGroup ) const
1881{
1882 // Don't write empty groups
1883 if( aGroup->GetItems().empty() )
1884 return;
1885
1886 m_out->Print( "(group %s", m_out->Quotew( aGroup->GetName() ).c_str() );
1887
1889
1890 if( aGroup->IsLocked() )
1891 KICAD_FORMAT::LEGACY::FormatBool( m_out, "locked", true );
1892
1893 wxArrayString memberIds;
1894
1895 for( EDA_ITEM* member : aGroup->GetItems() )
1896 memberIds.Add( member->m_Uuid.AsString() );
1897
1898 memberIds.Sort();
1899
1900 m_out->Print( "(members" );
1901
1902 for( const wxString& memberId : memberIds )
1903 m_out->Print( " %s", m_out->Quotew( memberId ).c_str() );
1904
1905 m_out->Print( ")" ); // Close `members` token.
1906 m_out->Print( ")" ); // Close `group` token.
1907}
1908
1909
1910void PCB_WRITER_V9::format( const PCB_GENERATOR* aGenerator ) const
1911{
1912 // Some conditions appear to still be creating ghost tuning patterns. Don't save them.
1913 if( aGenerator->GetGeneratorType() == wxT( "tuning_pattern" ) && aGenerator->GetItems().empty() )
1914 {
1915 return;
1916 }
1917
1918 m_out->Print( "(generated" );
1919
1921
1922 m_out->Print( "(type %s) (name %s) (layer %s)", TO_UTF8( aGenerator->GetGeneratorType() ),
1923 m_out->Quotew( aGenerator->GetName() ).c_str(),
1924 m_out->Quotew( LSET::Name( aGenerator->GetLayer() ) ).c_str() );
1925
1926 if( aGenerator->IsLocked() )
1927 KICAD_FORMAT::LEGACY::FormatBool( m_out, "locked", true );
1928
1929 for( const auto& [key, value] : KICAD_FORMAT::LEGACY::TuningPropertiesForEra( *aGenerator, true ) )
1930 {
1931 if( value.CheckType<double>() || value.CheckType<int>() || value.CheckType<long>()
1932 || value.CheckType<long long>() )
1933 {
1934 double val;
1935
1936 if( !value.GetAs( &val ) )
1937 continue;
1938
1939 std::string buf = fmt::format( "{:.10g}", val );
1940
1941 // Don't quote numbers
1942 m_out->Print( "(%s %s)", key.c_str(), buf.c_str() );
1943 }
1944 else if( value.CheckType<bool>() )
1945 {
1946 bool val;
1947 value.GetAs( &val );
1948
1950 }
1951 else if( value.CheckType<VECTOR2I>() )
1952 {
1953 VECTOR2I val;
1954 value.GetAs( &val );
1955
1956 m_out->Print( "(%s (xy %s))", key.c_str(), formatInternalUnits( val ).c_str() );
1957 }
1958 else if( value.CheckType<SHAPE_LINE_CHAIN>() )
1959 {
1960 SHAPE_LINE_CHAIN val;
1961 value.GetAs( &val );
1962
1963 m_out->Print( "(%s ", key.c_str() );
1964 formatPolyPts( val );
1965 m_out->Print( ")" );
1966 }
1967 else
1968 {
1969 wxString val;
1970
1971 if( value.CheckType<wxString>() )
1972 {
1973 value.GetAs( &val );
1974 }
1975 else if( value.CheckType<std::string>() )
1976 {
1977 std::string str;
1978 value.GetAs( &str );
1979
1980 val = wxString::FromUTF8( str );
1981 }
1982
1983 m_out->Print( "(%s %s)", key.c_str(), m_out->Quotew( val ).c_str() );
1984 }
1985 }
1986
1987 wxArrayString memberIds;
1988
1989 for( EDA_ITEM* member : aGenerator->GetItems() )
1990 memberIds.Add( member->m_Uuid.AsString() );
1991
1992 memberIds.Sort();
1993
1994 m_out->Print( "(members" );
1995
1996 for( const wxString& memberId : memberIds )
1997 m_out->Print( " %s", m_out->Quotew( memberId ).c_str() );
1998
1999 m_out->Print( ")" ); // Close `members` token.
2000 m_out->Print( ")" ); // Close `generated` token.
2001}
2002
2003
2004void PCB_WRITER_V9::format( const PCB_TRACK* aTrack ) const
2005{
2006 if( aTrack->Type() == PCB_VIA_T )
2007 {
2008 PCB_LAYER_ID layer1, layer2;
2009
2010 const PCB_VIA* via = static_cast<const PCB_VIA*>( aTrack );
2011 const BOARD* board = via->GetBoard();
2012
2013 wxCHECK_RET( board != nullptr, wxT( "Via has no parent." ) );
2014
2015 m_out->Print( "(via" );
2016
2017 via->LayerPair( &layer1, &layer2 );
2018
2019 switch( via->GetViaType() )
2020 {
2021 case VIATYPE::THROUGH: // Default shape not saved.
2022 break;
2023
2024 case VIATYPE::BLIND:
2025 case VIATYPE::BURIED: m_out->Print( " blind " ); break;
2026
2027 case VIATYPE::MICROVIA: m_out->Print( " micro " ); break;
2028
2029 default: THROW_IO_ERROR( wxString::Format( _( "unknown via type %d" ), via->GetViaType() ) );
2030 }
2031
2032 m_out->Print( "(at %s) (size %s)", formatInternalUnits( aTrack->GetStart() ).c_str(),
2033 formatInternalUnits( via->GetWidth( F_Cu ) ).c_str() );
2034
2035 // Old boards were using UNDEFINED_DRILL_DIAMETER value in file for via drill when
2036 // via drill was the netclass value.
2037 // recent boards always set the via drill to the actual value, but now we need to
2038 // always store the drill value, because netclass value is not stored in the board file.
2039 // Otherwise the drill value of some (old) vias can be unknown
2040 if( via->GetDrill() != UNDEFINED_DRILL_DIAMETER )
2041 m_out->Print( "(drill %s)", formatInternalUnits( via->GetDrill() ).c_str() );
2042 else
2043 m_out->Print( "(drill %s)", formatInternalUnits( via->GetDrillValue() ).c_str() );
2044
2045 m_out->Print( "(layers %s %s)", m_out->Quotew( LSET::Name( layer1 ) ).c_str(),
2046 m_out->Quotew( LSET::Name( layer2 ) ).c_str() );
2047
2048 switch( via->Padstack().UnconnectedLayerMode() )
2049 {
2051 KICAD_FORMAT::LEGACY::FormatBool( m_out, "remove_unused_layers", true );
2052 KICAD_FORMAT::LEGACY::FormatBool( m_out, "keep_end_layers", false );
2053 break;
2054
2055 // Skip vias postdate this format. The nearest era mode keeps the end layers.
2058 KICAD_FORMAT::LEGACY::FormatBool( m_out, "remove_unused_layers", true );
2059 KICAD_FORMAT::LEGACY::FormatBool( m_out, "keep_end_layers", true );
2060 break;
2061
2063 }
2064
2065 if( via->IsLocked() )
2066 KICAD_FORMAT::LEGACY::FormatBool( m_out, "locked", true );
2067
2068 if( via->GetIsFree() )
2069 KICAD_FORMAT::LEGACY::FormatBool( m_out, "free", true );
2070
2071 if( via->GetRemoveUnconnected() )
2072 {
2073 m_out->Print( "(zone_layer_connections" );
2074
2075 for( PCB_LAYER_ID layer : board->GetEnabledLayers().CuStack() )
2076 {
2077 if( via->GetZoneLayerOverride( layer ) == ZLO_FORCE_FLASHED )
2078 m_out->Print( " %s", m_out->Quotew( LSET::Name( layer ) ).c_str() );
2079 }
2080
2081 m_out->Print( ")" );
2082 }
2083
2084 const PADSTACK& padstack = via->Padstack();
2085
2086 formatTenting( padstack );
2087
2088 if( padstack.Mode() != PADSTACK::MODE::NORMAL )
2089 {
2090 m_out->Print( "(padstack" );
2091
2092 if( padstack.Mode() == PADSTACK::MODE::FRONT_INNER_BACK )
2093 {
2094 m_out->Print( "(mode front_inner_back)" );
2095
2096 m_out->Print( "(layer \"Inner\"" );
2097 m_out->Print( "(size %s)", formatInternalUnits( padstack.Size( PADSTACK::INNER_LAYERS ).x ).c_str() );
2098 m_out->Print( ")" );
2099 m_out->Print( "(layer \"B.Cu\"" );
2100 m_out->Print( "(size %s)", formatInternalUnits( padstack.Size( B_Cu ).x ).c_str() );
2101 m_out->Print( ")" );
2102 }
2103 else
2104 {
2105 m_out->Print( "(mode custom)" );
2106
2107 for( PCB_LAYER_ID layer : LAYER_RANGE( F_Cu, B_Cu, board->GetCopperLayerCount() ) )
2108 {
2109 if( layer == F_Cu )
2110 continue;
2111
2112 m_out->Print( "(layer %s", m_out->Quotew( LSET::Name( layer ) ).c_str() );
2113 m_out->Print( "(size %s)", formatInternalUnits( padstack.Size( layer ).x ).c_str() );
2114 m_out->Print( ")" );
2115 }
2116 }
2117
2118 m_out->Print( ")" );
2119 }
2120
2121 if( !isDefaultTeardropParameters( via->GetTeardropParams() ) )
2122 formatTeardropParameters( via->GetTeardropParams() );
2123 }
2124 else
2125 {
2126 if( aTrack->Type() == PCB_ARC_T )
2127 {
2128 const PCB_ARC* arc = static_cast<const PCB_ARC*>( aTrack );
2129
2130 m_out->Print( "(arc (start %s) (mid %s) (end %s) (width %s)",
2131 formatInternalUnits( arc->GetStart() ).c_str(), formatInternalUnits( arc->GetMid() ).c_str(),
2132 formatInternalUnits( arc->GetEnd() ).c_str(),
2133 formatInternalUnits( arc->GetWidth() ).c_str() );
2134 }
2135 else
2136 {
2137 m_out->Print( "(segment (start %s) (end %s) (width %s)", formatInternalUnits( aTrack->GetStart() ).c_str(),
2138 formatInternalUnits( aTrack->GetEnd() ).c_str(),
2139 formatInternalUnits( aTrack->GetWidth() ).c_str() );
2140 }
2141
2142 if( aTrack->IsLocked() )
2143 KICAD_FORMAT::LEGACY::FormatBool( m_out, "locked", true );
2144
2145 if( aTrack->GetLayerSet().count() > 1 )
2146 formatLayers( aTrack->GetLayerSet(), false /* enumerate layers */ );
2147 else
2148 formatLayer( aTrack->GetLayer() );
2149
2150 if( aTrack->HasSolderMask() && aTrack->GetLocalSolderMaskMargin().has_value()
2151 && ( aTrack->IsOnLayer( F_Cu ) || aTrack->IsOnLayer( B_Cu ) ) )
2152 {
2153 m_out->Print( "(solder_mask_margin %s)",
2154 formatInternalUnits( aTrack->GetLocalSolderMaskMargin().value() ).c_str() );
2155 }
2156 }
2157
2158 m_out->Print( "(net %d)", m_mapping.Translate( aTrack->GetNetCode() ) );
2159
2161 m_out->Print( ")" );
2162}
2163
2164
2165void PCB_WRITER_V9::format( const ZONE* aZone ) const
2166{
2167 // Save the NET info.
2168 // For keepout and non copper zones, net code and net name are irrelevant
2169 // so be sure a dummy value is stored, just for ZONE compatibility
2170 // (perhaps netcode and netname should be not stored)
2171
2172 bool has_no_net = aZone->GetIsRuleArea() || !aZone->IsOnCopperLayer();
2173
2174 m_out->Print( "(zone (net %d) (net_name %s)", has_no_net ? 0 : m_mapping.Translate( aZone->GetNetCode() ),
2175 m_out->Quotew( has_no_net ? wxString( wxT( "" ) ) : aZone->GetNetname() ).c_str() );
2176
2177 if( aZone->IsLocked() )
2178 KICAD_FORMAT::LEGACY::FormatBool( m_out, "locked", true );
2179
2180 // If a zone exists on multiple layers, format accordingly
2181 LSET layers = aZone->GetLayerSet();
2182
2183 if( aZone->GetBoard() )
2184 layers &= aZone->GetBoard()->GetEnabledLayers();
2185
2186 // Always enumerate every layer for a zone on a copper layer
2187 if( layers.count() > 1 )
2188 formatLayers( layers, aZone->IsOnCopperLayer() );
2189 else
2190 formatLayer( aZone->GetFirstLayer() );
2191
2193
2194 if( !aZone->GetZoneName().empty() )
2195 m_out->Print( "(name %s)", m_out->Quotew( aZone->GetZoneName() ).c_str() );
2196
2197 // Save the outline aux info
2198 std::string hatch;
2199
2200 switch( aZone->GetHatchStyle() )
2201 {
2202 default:
2203 case ZONE_BORDER_DISPLAY_STYLE::NO_HATCH: hatch = "none"; break;
2204 case ZONE_BORDER_DISPLAY_STYLE::DIAGONAL_EDGE: hatch = "edge"; break;
2205 case ZONE_BORDER_DISPLAY_STYLE::DIAGONAL_FULL: hatch = "full"; break;
2206 }
2207
2208 m_out->Print( "(hatch %s %s)", hatch.c_str(), formatInternalUnits( aZone->GetBorderHatchPitch() ).c_str() );
2209
2210
2211 if( aZone->GetAssignedPriority() > 0 )
2212 m_out->Print( "(priority %d)", aZone->GetAssignedPriority() );
2213
2214 // Add teardrop keywords in file: (attr (teardrop (type xxx)))where xxx is the teardrop type
2215 if( aZone->IsTeardropArea() )
2216 {
2217 m_out->Print( "(attr (teardrop (type %s)))",
2218 aZone->GetTeardropAreaType() == TEARDROP_TYPE::TD_VIAPAD ? "padvia" : "track_end" );
2219 }
2220
2221 m_out->Print( "(connect_pads" );
2222
2223 switch( aZone->GetPadConnection() )
2224 {
2225 default:
2226 case ZONE_CONNECTION::THERMAL: // Default option not saved or loaded.
2227 break;
2228
2229 case ZONE_CONNECTION::THT_THERMAL: m_out->Print( " thru_hole_only" ); break;
2230
2231 case ZONE_CONNECTION::FULL: m_out->Print( " yes" ); break;
2232
2233 case ZONE_CONNECTION::NONE: m_out->Print( " no" ); break;
2234 }
2235
2236 m_out->Print( "(clearance %s)", formatInternalUnits( aZone->GetLocalClearance().value() ).c_str() );
2237
2238 m_out->Print( ")" );
2239
2240 m_out->Print( "(min_thickness %s)", formatInternalUnits( aZone->GetMinThickness() ).c_str() );
2241
2242 // We continue to write this for 3rd-party parsers, but we no longer read it (as of V7).
2243 m_out->Print( "(filled_areas_thickness no)" );
2244
2245 if( aZone->GetIsRuleArea() )
2246 {
2247 // Keepout settings
2248 m_out->Print( "(keepout (tracks %s) (vias %s) (pads %s) (copperpour %s) (footprints %s))",
2249 aZone->GetDoNotAllowTracks() ? "not_allowed" : "allowed",
2250 aZone->GetDoNotAllowVias() ? "not_allowed" : "allowed",
2251 aZone->GetDoNotAllowPads() ? "not_allowed" : "allowed",
2252 aZone->GetDoNotAllowZoneFills() ? "not_allowed" : "allowed",
2253 aZone->GetDoNotAllowFootprints() ? "not_allowed" : "allowed" );
2254
2255 // Multichannel settings
2256 m_out->Print( "(placement" );
2258
2259 switch( aZone->GetPlacementAreaSourceType() )
2260 {
2262 m_out->Print( "(sheetname %s)", m_out->Quotew( aZone->GetPlacementAreaSource() ).c_str() );
2263 break;
2265 m_out->Print( "(component_class %s)", m_out->Quotew( aZone->GetPlacementAreaSource() ).c_str() );
2266 break;
2267
2269 if( aZone->GetPlacementAreaEnabled() || !aZone->GetPlacementAreaSource().IsEmpty() )
2270 THROW_IO_ERROR( wxT( "Group placement linkage must be removed before writing KiCad 9." ) );
2271
2272 break;
2273
2274 default: break;
2275 }
2276
2277 m_out->Print( ")" );
2278 }
2279
2280 m_out->Print( "(fill" );
2281
2282 // Default is not filled.
2283 if( aZone->IsFilled() )
2284 m_out->Print( " yes" );
2285
2286 // Default is polygon filled.
2288 m_out->Print( "(mode hatch)" );
2289
2290 m_out->Print( "(thermal_gap %s) (thermal_bridge_width %s)",
2291 formatInternalUnits( aZone->GetThermalReliefGap() ).c_str(),
2292 formatInternalUnits( aZone->GetThermalReliefSpokeWidth() ).c_str() );
2293
2295 {
2296 switch( aZone->GetCornerSmoothingType() )
2297 {
2298 case ZONE_SETTINGS::CORNER_SMOOTHING::CHAMFER: m_out->Print( "(smoothing chamfer)" ); break;
2299
2300 case ZONE_SETTINGS::CORNER_SMOOTHING::FILLET: m_out->Print( "(smoothing fillet)" ); break;
2301
2302 default:
2303 THROW_IO_ERROR( wxString::Format( _( "unknown zone corner smoothing type %d" ),
2304 static_cast<int>( aZone->GetCornerSmoothingType() ) ) );
2305 }
2306
2307 if( aZone->GetCornerRadius() != 0 )
2308 m_out->Print( "(radius %s)", formatInternalUnits( aZone->GetCornerRadius() ).c_str() );
2309 }
2310
2312 {
2313 m_out->Print( "(island_removal_mode %d) (island_area_min %s)",
2314 static_cast<int>( aZone->GetIslandRemovalMode() ),
2315 formatInternalUnits( aZone->GetMinIslandArea() / pcbIUScale.IU_PER_MM ).c_str() );
2316 }
2317
2319 {
2320 m_out->Print( "(hatch_thickness %s) (hatch_gap %s) (hatch_orientation %s)",
2321 formatInternalUnits( aZone->GetHatchThickness() ).c_str(),
2322 formatInternalUnits( aZone->GetHatchGap() ).c_str(),
2323 FormatDouble2Str( aZone->GetHatchOrientation().AsDegrees() ).c_str() );
2324
2325 if( aZone->GetHatchSmoothingLevel() > 0 )
2326 {
2327 m_out->Print( "(hatch_smoothing_level %d) (hatch_smoothing_value %s)", aZone->GetHatchSmoothingLevel(),
2328 FormatDouble2Str( aZone->GetHatchSmoothingValue() ).c_str() );
2329 }
2330
2331 m_out->Print( "(hatch_border_algorithm %s) (hatch_min_hole_area %s)",
2332 aZone->GetHatchBorderAlgorithm() ? "hatch_thickness" : "min_thickness",
2333 FormatDouble2Str( aZone->GetHatchHoleMinArea() ).c_str() );
2334 }
2335
2336 m_out->Print( ")" );
2337
2338 if( aZone->GetNumCorners() )
2339 {
2340 // Footprint outlines are now stored in library coordinates. The legacy format
2341 // stores these in board coordinates, unlike the other footprint graphics.
2342 SHAPE_POLY_SET::POLYGON poly = aZone->GetBoardOutline().Polygon( 0 );
2343
2344 for( const SHAPE_LINE_CHAIN& chain : poly )
2345 {
2346 m_out->Print( "(polygon" );
2348 m_out->Print( ")" );
2349 }
2350 }
2351
2352 // Save the PolysList (filled areas)
2353 for( PCB_LAYER_ID layer : aZone->GetLayerSet().Seq() )
2354 {
2355 const std::shared_ptr<SHAPE_POLY_SET>& fv = aZone->GetFilledPolysList( layer );
2356
2357 for( int ii = 0; ii < fv->OutlineCount(); ++ii )
2358 {
2359 m_out->Print( "(filled_polygon" );
2360 m_out->Print( "(layer %s)", m_out->Quotew( LSET::Name( layer ) ).c_str() );
2361
2362 if( aZone->IsIsland( layer, ii ) )
2363 m_out->Print( "(island)" );
2364
2365 const SHAPE_LINE_CHAIN& chain = fv->COutline( ii );
2366
2368 m_out->Print( ")" );
2369 }
2370 }
2371
2372 m_out->Print( ")" );
2373}
2374
2375
2376void PCB_WRITER_V9::SaveFootprintFile( const wxString& aFileName, FOOTPRINT* aFootprint )
2377{
2378 LOCALE_IO toggle;
2379
2380 if( aFootprint->GetAreFontsEmbedded() )
2381 aFootprint->EmbedFonts();
2382 else
2383 aFootprint->GetEmbeddedFiles()->ClearEmbeddedFonts();
2384
2385 PRETTIFIED_FILE_OUTPUTFORMATTER formatter( aFileName );
2386
2387 m_out = &formatter;
2389 Format( aFootprint );
2390 formatter.Finish();
2391 m_out = nullptr;
2392}
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:128
@ 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.
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 GENERATORS & Generators() const
Definition board.h:484
const PAGE_INFO & GetPageSettings() const
Definition board.h:1018
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
Definition board.cpp:2998
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
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
std::unordered_set< EDA_ITEM * > & GetItems()
Definition eda_group.h:78
wxString GetName() const
Definition eda_group.h:75
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
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
bool IsAnyFill() const
Definition eda_shape.h:118
wxString SHAPE_T_asString() const
const VECTOR2I & GetBezierC1() const
Definition eda_shape.h:365
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
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
EDA_ANGLE GetOrientation() const
Definition footprint.h:439
ZONES & Zones()
Definition footprint.h:411
wxString GetSheetname() const
Definition footprint.h:511
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
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
PCB_FIELD & Reference()
Definition footprint.h:948
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
bool IsPlaced() const
Definition footprint.h:718
VECTOR2I GetPosition() const override
Definition footprint.h:436
DRAWINGS & GraphicalItems()
Definition footprint.h:408
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
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition locale_io.h:37
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
Handle the data for a net.
Definition netinfo.h:50
static const int UNCONNECTED
Constant that holds the "unconnected net" number (typically 0) all items "connected" to this net are ...
Definition netinfo.h:281
void SetBoard(const BOARD *aBoard)
std::map< int, int > m_map
std::vector< NETINFO_ITEM * > m_nets
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
std::optional< int > & ThermalSpokeWidth(PCB_LAYER_ID aLayer=F_Cu)
EDA_ANGLE ThermalSpokeAngle(PCB_LAYER_ID aLayer=F_Cu) const
std::optional< int > & ThermalGap(PCB_LAYER_ID aLayer=F_Cu)
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
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
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
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
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
bool IsOnLayer(PCB_LAYER_ID aLayer) const override
Test to see if this object is on the given layer.
virtual int GetWidth() const
Definition pcb_track.h:92
void formatHeader(const BOARD *aBoard) const
static constexpr int FORMAT_VERSION
void formatRenderCache(const EDA_TEXT *aText) const
NET_MAPPING_V9 m_mapping
void formatTenting(const PADSTACK &aPadstack) const
void Format(const BOARD_ITEM *aItem) const
void SaveFootprintFile(const wxString &aFileName, FOOTPRINT *aFootprint)
void formatLayer(PCB_LAYER_ID aLayer, bool aIsKnockout=false) const
void formatSetup(const BOARD *aBoard) const
void formatTeardropParameters(const TEARDROP_PARAMETERS &tdParams) const
void formatBoardLayers(const BOARD *aBoard) const
void formatProperties(const BOARD *aBoard) const
void SaveBoard(const wxString &aFileName, BOARD *aBoard)
void formatLayers(LSET aLayerMask, bool aEnumerateLayers) const
void formatNetInformation(const BOARD *aBoard) const
void format(const BOARD *aBoard) const
void formatPolyPts(const SHAPE_LINE_CHAIN &aOutline, const FOOTPRINT *aParentFP=nullptr) const
void formatGeneral(const BOARD *aBoard) const
OUTPUTFORMATTER * m_out
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
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
@ SEGMENT
Definition eda_shape.h:56
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
Definition eda_shape.h:57
@ 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
#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 FormatPlotV9(OUTPUTFORMATTER *aOut, const PCB_PLOT_PARAMS &aPlot)
void FormatStreamData(OUTPUTFORMATTER &aOut, const wxStreamBuffer &aStream)
void FormatEmbeddedFilesV9(OUTPUTFORMATTER &aOut, const EMBEDDED_FILES &aFiles, bool aWriteData)
void FormatUuid(OUTPUTFORMATTER *aOut, const KIID &aUuid)
STRING_ANY_MAP TuningPropertiesForEra(const PCB_GENERATOR &aGenerator, bool aV9)
void FormatTextV9(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)
constexpr int OMIT_HIDE
UTF8 FormatLibId(const LIB_ID &aId)
void FormatPageV9(OUTPUTFORMATTER *aOut, const PAGE_INFO &aPage)
@ 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
@ 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
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 void formatBoardStackupV9(OUTPUTFORMATTER *aFormatter, const BOARD *aBoard)
static bool isDefaultTeardropParameters(const TEARDROP_PARAMETERS &tdParams)
static std::string formatInternalUnits(int aValue)
CITER next(CITER it)
Definition ptree.cpp:120
std::string FormatDouble2Str(double aValue)
Print a float number without using scientific notation and no trailing 0 This function is intended in...
std::optional< bool > has_solder_mask
True if this outer layer has mask (is not tented)
Definition padstack.h:259
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_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_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