KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pcb_io_pads_binary.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2026 KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU 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#include "pcb_io_pads_binary.h"
21#include "pads_binary_parser.h"
22#include "pads_layer_mapper.h"
23#include "pads_pcb_shapes.h"
24
25#include <algorithm>
26#include <memory>
27#include <cmath>
28#include <functional>
29#include <set>
30
31#include <board.h>
32#include <pcb_track.h>
33#include <footprint.h>
34#include <pcb_group.h>
35#include <zone.h>
36
38#include <io/pads/pads_common.h>
39
40#include <netinfo.h>
41#include <wx/log.h>
42#include <pad.h>
43#include <pcb_shape.h>
45#include <netclass.h>
47#include <geometry/eda_angle.h>
48#include <string_utils.h>
49#include <progress_reporter.h>
50#include <reporter.h>
51#include <locale_io.h>
52#include <advanced_config.h>
53#include <geometry/shape_arc.h>
54
55
64
65
67
68
70{
71 IO_FILE_DESC desc;
72 desc.m_FileExtensions.emplace_back( "pcb" );
73 desc.m_Description = "PADS Binary";
74 return desc;
75}
76
77
79{
80 return IO_FILE_DESC( "PADS Binary Library", { "pcb" } );
81}
82
83
84long long PCB_IO_PADS_BINARY::GetLibraryTimestamp( const wxString& aLibraryPath ) const
85{
86 return 0;
87}
88
89
90bool PCB_IO_PADS_BINARY::CanReadBoard( const wxString& aFileName ) const
91{
92 if( !PCB_IO::CanReadBoard( aFileName ) )
93 return false;
94
96}
97
98
99bool PCB_IO_PADS_BINARY::CanReadLibrary( const wxString& aFileName ) const
100{
101 // The .pcb extension is shared with other tools, so a non-PADS .pcb must not be
102 // mis-identified; content-check the magic rather than trusting the extension.
103 if( !PCB_IO::CanReadLibrary( aFileName ) )
104 return false;
105
107}
108
109
110void PCB_IO_PADS_BINARY::loadBoard( const wxString& aFileName, BOARD& aBoard, bool aIsNewLoad,
111 const std::map<std::string, UTF8>* aProperties, PROJECT* aProject )
112{
113 LOCALE_IO setlocale;
114
115 if( m_reporter )
116 m_reporter->Report( _( "Starting PADS binary PCB import" ), RPT_SEVERITY_INFO );
117
119 m_progressReporter->SetNumPhases( 3 );
120
122
123 try
124 {
125 parser.Parse( aFileName );
126 }
127 catch( const std::exception& e )
128 {
129 THROW_IO_ERROR( wxString::Format( "Error parsing PADS binary file: %s", e.what() ) );
130 }
131
132 m_loadBoard = &aBoard;
133 m_parser = &parser;
134 m_converter = std::make_unique<PADS_PCB_CONVERTER>( m_loadBoard, m_reporter );
135
136 try
137 {
139 m_progressReporter->BeginPhase( 1 );
140
142
143 // Nets are created before the geometry that references them; loadTracksAndVias resolves
144 // each track and via net against this table.
145 loadNets();
146
148 m_progressReporter->BeginPhase( 2 );
149
151
152 // Cluster groups reference the footprints loadFootprints just added, so they follow it.
157 m_converter->LoadTexts( m_parser->GetTexts() );
159 loadZones();
160 m_converter->LoadKeepouts( m_parser->GetKeepouts() );
161 m_converter->LoadDimensions( m_parser->GetDimensions() );
162
163 // Appending merges into a board that already has its own rule file, so nothing would
164 // ever load rules written beside the PADS source
165 if( aIsNewLoad )
166 m_converter->WriteDiffPairRules( aFileName, m_parser->GetDiffPairs() );
167
168 m_converter->ReportStatistics();
169 }
170 catch( ... )
171 {
173 throw;
174 }
175
177}
178
179
181{
182 std::vector<PADS_IO::LAYER_INFO> padsLayerInfos = m_parser->GetLayerInfos();
183
184 // Binary layer records often carry no function code, so the layer name is the only
185 // remaining clue to what the layer is for.
186 m_converter->SetupLayers( padsLayerInfos, m_parser->GetParameters().layer_count, m_layer_mapping_handler, true );
187
188 // Binary files always use BASIC units, and the stackup thicknesses are BASIC too, so the
189 // units have to be settled before anything is scaled.
190 m_converter->UnitConverter().SetBasicUnitsMode( true );
192
193 m_converter->BuildStackup( padsLayerInfos );
194
195 const PADS_IO::POINT& origin = m_parser->GetParameters().origin;
196
197 m_converter->SetOrigin( origin.x, origin.y );
198
199 // Fall back to the board-outline center only when there is no DFT origin; the DFT origin
200 // gives exact coordinates and overriding it would shift all parts.
201 if( origin.x == 0.0 && origin.y == 0.0 )
202 m_converter->SetOriginFromOutlines( m_parser->GetBoardOutlines() );
203}
204
205
207{
208 const auto& nets = m_parser->GetNets();
209
210 for( const auto& padsNet : nets )
211 m_converter->EnsureNet( padsNet.name );
212
213 // Key on the decoded text so buildPad() can match against the reference it already built.
214 // ToStdString() would re-encode through the locale, which LOCALE_IO has pinned to "C"
215 for( const auto& padsNet : nets )
216 {
217 for( const PADS_IO::NET_PIN& pin : padsNet.pins )
218 {
219 wxString key = PADS_COMMON::ConvertText( pin.ref_des ) + wxT( "." )
220 + PADS_COMMON::ConvertText( pin.pin_name );
221 m_pinToNetMap[key] = padsNet.name;
222 }
223 }
224
225 // One KiCad NETCLASS per PADS net class, with its member nets. Empty on boards with no
226 // net classes (such as the v0x2021 dialect), where this is a no-op.
227 const std::vector<PADS_IO::BIN_NET_CLASS_DEF>& netClasses = m_parser->GetNetClasses();
228 const std::vector<PADS_IO::DIFF_PAIR_DEF>& diffPairs = m_parser->GetDiffPairs();
229
230 if( netClasses.empty() && diffPairs.empty() )
231 return;
232
233 std::shared_ptr<NET_SETTINGS> netSettings = m_loadBoard->GetDesignSettings().m_NetSettings;
234
235 for( const PADS_IO::BIN_NET_CLASS_DEF& nc : netClasses )
236 {
237 if( nc.name.empty() || nc.nets.empty() )
238 continue;
239
240 wxString className = PADS_COMMON::ConvertText( nc.name );
241
242 if( !netSettings->HasNetclass( className ) )
243 {
244 std::shared_ptr<NETCLASS> kicadClass = std::make_shared<NETCLASS>( className );
245
246 // KiCad's netclass carries one clearance and one track width; the PADS min/max
247 // values are advisory and dropped.
248 if( nc.hasRuleValues )
249 {
250 if( nc.clearance > 0 )
251 kicadClass->SetClearance( scaleSize( nc.clearance ) );
252
253 if( nc.trackWidth > 0 )
254 kicadClass->SetTrackWidth( scaleSize( nc.trackWidth ) );
255 }
256
257 netSettings->SetNetclass( className, kicadClass );
258 }
259
260 // Label assignments are rebuilt from schematic labels on every connectivity pass, so a
261 // board-side membership has to be a pattern assignment to survive
262 for( const std::string& netname : nc.nets )
263 {
264 wxString kicadNetname = PADS_COMMON::ConvertInvertedNetName( netname );
265 wxString literalNetnamePattern = EscapeString( kicadNetname, CTX_REGEX );
266 netSettings->SetNetclassPatternAssignment( literalNetnamePattern, className );
267 }
268 }
269
270 // Each differential pair becomes one DiffPair_<name> net class.
271 for( const PADS_IO::DIFF_PAIR_DEF& dp : diffPairs )
272 {
273 if( dp.name.empty() )
274 continue;
275
276 wxString dpClassName = wxString::Format( wxT( "DiffPair_%s" ), PADS_COMMON::ConvertText( dp.name ) );
277 std::shared_ptr<NETCLASS> dpNetclass = std::make_shared<NETCLASS>( dpClassName );
278
279 if( dp.gap > 0 )
280 dpNetclass->SetDiffPairGap( scaleSize( dp.gap ) );
281
282 if( dp.width > 0 )
283 {
284 dpNetclass->SetDiffPairWidth( scaleSize( dp.width ) );
285 dpNetclass->SetTrackWidth( scaleSize( dp.width ) );
286 }
287
288 netSettings->SetNetclass( dpClassName, dpNetclass );
289
290 if( !dp.positive_net.empty() )
291 netSettings->SetNetclassPatternAssignment( PADS_COMMON::ConvertInvertedNetName( dp.positive_net ),
292 dpClassName );
293
294 if( !dp.negative_net.empty() )
295 netSettings->SetNetclassPatternAssignment( PADS_COMMON::ConvertInvertedNetName( dp.negative_net ),
296 dpClassName );
297 }
298}
299
300
302{
303 const auto& decals = m_parser->GetPartDecals();
304 const auto& parts = m_parser->GetParts();
305
306 for( const auto& padsPart : parts )
307 {
308 FOOTPRINT* footprint = new FOOTPRINT( m_loadBoard );
309 footprint->SetReference( PADS_COMMON::ConvertText( padsPart.name ) );
310
311 KIID symbolUuid = PADS_COMMON::GenerateDeterministicUuid( padsPart.name );
313 path.push_back( symbolUuid );
314 footprint->SetPath( path );
315
316 std::string decalName = padsPart.decal;
317
318 LIB_ID fpid;
319
320 if( !decalName.empty() )
321 fpid.SetLibItemName( PADS_COMMON::ConvertText( decalName ) );
322 else
323 fpid.SetLibItemName( PADS_COMMON::ConvertText( padsPart.name ) );
324
325 footprint->SetFPID( fpid );
326
327 // A part referencing a *PARTTYPE alias (often a manufacturer part number) shows that
328 // alias as its value, not the physical decal it resolves to; see linkPartsToDecals().
329 footprint->SetValue( PADS_COMMON::ConvertText( padsPart.value.empty() ? padsPart.decal
330 : padsPart.value ) );
331
332 footprint->SetPosition( scalePoint( padsPart.location.x, padsPart.location.y ) );
333 footprint->SetOrientation( EDA_ANGLE( padsPart.rotation, DEGREES_T ) );
334 footprint->SetLayer( F_Cu );
335 footprint->Reference().SetLayer( F_Fab );
336 footprint->Reference().SetVisible( false );
337 footprint->Value().SetLayer( F_Fab );
338 footprint->Value().SetVisible( false );
339
340 auto decalIt = decals.find( decalName );
341
342 if( decalIt == decals.end() )
343 {
344 if( m_reporter )
345 {
346 m_reporter->Report( wxString::Format( _( "Part '%s': decal '%s' not found, no pads created" ),
347 padsPart.name, decalName ),
349 }
350 }
351
352 if( decalIt != decals.end() )
353 {
354 const PADS_IO::PART_DECAL& decal = decalIt->second;
355 EDA_ANGLE partOrient( padsPart.rotation, DEGREES_T );
356
357 for( size_t termIdx = 0; termIdx < decal.terminals.size(); ++termIdx )
358 buildPad( footprint, decal, termIdx, partOrient );
359 }
360
361 for( const PADS_IO::ATTRIBUTE& attribute : padsPart.attributes )
362 {
363 PCB_FIELD* field = nullptr;
364
365 if( attribute.name == "Ref.Des." )
366 field = &footprint->Reference();
367 else if( attribute.name == "Part Type" )
368 field = &footprint->Value();
369
370 if( !field )
371 continue;
372
373 int scaledSize = scaleSize( attribute.height );
374 int charHeight = static_cast<int>( scaledSize * ADVANCED_CFG::GetCfg().m_PadsPcbTextHeightScale );
375 int charWidth = static_cast<int>( scaledSize * ADVANCED_CFG::GetCfg().m_PadsPcbTextWidthScale );
376 field->SetTextSize( VECTOR2I( charWidth, charHeight ) );
377
378 if( attribute.width > 0 )
379 field->SetTextThickness( scaleSize( attribute.width ) );
380
381 VECTOR2I offset( scaleSize( attribute.x ), -scaleSize( attribute.y ) );
382 EDA_ANGLE partAngle( padsPart.rotation, DEGREES_T );
383 RotatePoint( offset, partAngle );
384
385 EDA_ANGLE textAngle( attribute.orientation + padsPart.rotation, DEGREES_T );
386 VECTOR2I textShift( -ADVANCED_CFG::GetCfg().m_PadsTextAnchorOffsetNm, 0 );
387 RotatePoint( textShift, textAngle );
388
389 field->SetPosition( footprint->GetPosition() + offset + textShift );
390 field->SetTextAngle( textAngle );
391 field->SetKeepUpright( false );
392 field->SetVisible( attribute.visible );
393 field->SetLayer( F_Fab );
394
395 if( attribute.hjust == "LEFT" )
397 else if( attribute.hjust == "RIGHT" )
399 else
401
402 if( attribute.vjust == "UP" )
404 else if( attribute.vjust == "DOWN" )
406 else
408 }
409
410 m_loadBoard->Add( footprint );
411
412 if( padsPart.bottom_layer )
413 {
414 footprint->Flip( footprint->GetPosition(), FLIP_DIRECTION::LEFT_RIGHT );
415
416 for( PAD* pad : footprint->Pads() )
417 {
418 if( pad->GetAttribute() == PAD_ATTRIB::PTH && pad->Padstack().Mode() == PADSTACK::MODE::NORMAL )
419 {
420 pad->SetLayerSet( PAD::PTHMask() | ( pad->GetLayerSet() & LSET( { F_Paste, B_Paste } ) ) );
421 }
422 }
423 }
424
425 m_partFootprints.push_back( footprint );
426 }
427}
428
429
430void PCB_IO_PADS_BINARY::buildPad( FOOTPRINT* aFootprint, const PADS_IO::PART_DECAL& aDecal, size_t aTermIdx,
431 const EDA_ANGLE& aPartOrient )
432{
433 const auto& term = aDecal.terminals[aTermIdx];
434 PAD* pad = new PAD( aFootprint );
435 aFootprint->Add( pad );
436
437 pad->SetNumber( PADS_COMMON::ConvertText( term.name ) );
438
439 VECTOR2I padPos( scaleSize( term.x ), -scaleSize( term.y ) );
440 RotatePoint( padPos, aPartOrient );
441 pad->SetPosition( aFootprint->GetPosition() + padPos );
442
443 int pinNum = static_cast<int>( aTermIdx + 1 );
444 auto stackIt = aDecal.pad_stacks.find( pinNum );
445
446 if( stackIt == aDecal.pad_stacks.end() )
447 stackIt = aDecal.pad_stacks.find( 0 );
448
449 if( stackIt != aDecal.pad_stacks.end() && !stackIt->second.empty() )
450 {
451 const std::vector<PADS_IO::PAD_STACK_LAYER>& stack = stackIt->second;
452 const PADS_IO::PAD_STACK_LAYER& layerDef = stack[0];
453
454 std::set<int> serializedLayers;
455 bool ambiguousLayers = false;
456
457 // A relief or anti-pad row repeats the layer ordinal of the copper row it qualifies, so
458 // counting it here would read every plane-relief padstack as ambiguous
459 for( auto it = std::next( stack.begin() ); it != stack.end(); ++it )
460 {
461 if( PADS_IO::IsCopperPadRow( *it ) )
462 ambiguousLayers |= !serializedLayers.insert( it->layer ).second;
463 }
464
465 bool modernZeroDefaultSmd = m_parser->GetVersion() == 0x2024 && layerDef.drill == 0 && layerDef.sizeA <= 0;
466 bool legacyZeroDefaultSmd = m_parser->GetVersion() == 0x2022 && layerDef.drill == 0
467 && layerDef.sizeA <= 0;
468 bool zeroDefaultSmd = modernZeroDefaultSmd || legacyZeroDefaultSmd;
469 bool hasExplicitLayers = stack.size() > 1 && ( layerDef.drill > 0 || zeroDefaultSmd ) && !ambiguousLayers;
470 LSET layerSet;
471
472 if( hasExplicitLayers )
473 {
474 pad->Padstack().SetMode( PADSTACK::MODE::FRONT_INNER_BACK );
475 bool appliedExplicitLayer = false;
476 const PADS_IO::PAD_STACK_LAYER* inheritedLegacyShape = nullptr;
477
478 if( legacyZeroDefaultSmd )
479 {
480 auto inherited = std::find_if( stack.begin(), stack.end(),
481 []( const PADS_IO::PAD_STACK_LAYER& aLayer )
482 {
483 return aLayer.layer == 0 && aLayer.sizeA > 0;
484 } );
485
486 if( inherited != stack.end() )
487 inheritedLegacyShape = &*inherited;
488 }
489
490 for( const PADS_IO::PAD_STACK_LAYER& stackLayer : stack )
491 {
492 if( stackLayer.sizeA <= 0 )
493 continue;
494
495 // RT/ST are plane thermal-relief spoke patterns and RA/SA are anti-pad
496 // clearances. Neither is pad copper, so they must not reach the shape below.
497 // KiCad derives the relief geometry from the zone, so an RT/ST row only says
498 // that this pad connects through spokes rather than solid copper.
499 if( PADS_IO::IsThermalReliefPadRow( stackLayer ) )
500 {
501 pad->SetLocalZoneConnection( ZONE_CONNECTION::THERMAL );
502 continue;
503 }
504
505 if( PADS_IO::IsAntiPadRow( stackLayer ) )
506 continue;
507
508 if( modernZeroDefaultSmd && stackLayer.layer == 0 )
509 continue;
510
511 if( legacyZeroDefaultSmd && stackLayer.layer <= 0 )
512 continue;
513
514 PCB_LAYER_ID kicadLayer = UNDEFINED_LAYER;
515
516 if( modernZeroDefaultSmd && stackLayer.layer == -1 )
517 {
518 kicadLayer = B_Paste;
519 layerSet.set( B_Paste );
520 }
521 else if( stackLayer.layer == -2 )
522 {
523 kicadLayer = F_Cu;
524 layerSet.set( F_Cu );
525 }
526 else if( stackLayer.layer == -1 )
527 {
528 kicadLayer = B_Cu;
529 layerSet.set( B_Cu );
530 }
531 else if( stackLayer.layer == 0 )
532 {
533 if( m_loadBoard->GetCopperLayerCount() > 2 )
534 {
535 kicadLayer = In1_Cu;
536
537 for( int layer = 2; layer < m_parser->GetParameters().layer_count; ++layer )
538 {
539 PCB_LAYER_ID inner = getMappedLayer( layer );
540
541 if( IsCopperLayer( inner ) )
542 layerSet.set( inner );
543 }
544 }
545 }
546 else
547 {
548 int padsLayer = stackLayer.layer;
549 kicadLayer = getMappedLayer( padsLayer );
550
551 if( kicadLayer != UNDEFINED_LAYER )
552 layerSet.set( kicadLayer );
553 }
554
555 if( kicadLayer != UNDEFINED_LAYER )
556 {
557 PADS_IO::PAD_STACK_LAYER appliedLayer = stackLayer;
558
559 if( modernZeroDefaultSmd )
560 {
561 appliedLayer.sizeA *= 1.5;
562 appliedLayer.sizeB *= 1.5;
563 appliedLayer.corner_radius *= 1.5;
564 }
565 else if( inheritedLegacyShape )
566 {
567 appliedLayer.shape = inheritedLegacyShape->shape;
568 appliedLayer.sizeA = inheritedLegacyShape->sizeA * 1.5;
569 appliedLayer.sizeB = inheritedLegacyShape->sizeB * 1.5;
570 }
571
572 applyPadShape( pad, appliedLayer, kicadLayer );
573 appliedExplicitLayer = true;
574
575 if( zeroDefaultSmd && appliedLayer.shape == "R" )
576 pad->SetRoundRectRadiusRatio( kicadLayer, 0.25 );
577 }
578 }
579
580 if( zeroDefaultSmd && !appliedExplicitLayer )
581 {
582 applyPadShape( pad, layerDef, F_Cu );
583 applyPadShape( pad, layerDef, F_Mask );
584 applyPadShape( pad, layerDef, F_Paste );
585 layerSet = LSET( { F_Cu, F_Mask, F_Paste } );
586 }
587 }
588 else
589 {
590 applyPadShape( pad, layerDef, F_Cu );
591 }
592
593 pad->SetOrientation( aPartOrient + EDA_ANGLE( layerDef.rotation, DEGREES_T ) );
594
595 int drill = scaleSize( layerDef.drill );
596
597 if( layerDef.slot_length > 0 && layerDef.slot_length != layerDef.drill )
598 {
599 pad->SetDrillShape( PAD_DRILL_SHAPE::OBLONG );
600
601 int drillMajor = scaleSize( layerDef.slot_length );
602 double relativeAngle = std::fmod( layerDef.slot_orientation - layerDef.rotation, 360.0 );
603
604 if( relativeAngle < 0 )
605 relativeAngle += 360.0;
606
607 bool vertical = ( relativeAngle > 45.0 && relativeAngle < 135.0 )
608 || ( relativeAngle > 225.0 && relativeAngle < 315.0 );
609 pad->SetDrillSize( vertical ? VECTOR2I( drill, drillMajor ) : VECTOR2I( drillMajor, drill ) );
610 }
611 else
612 {
613 pad->SetDrillSize( VECTOR2I( drill, drill ) );
614 }
615
616 if( drill == 0 )
617 {
618 pad->SetAttribute( PAD_ATTRIB::SMD );
619
620 if( hasExplicitLayers )
621 {
622 if( !zeroDefaultSmd )
623 {
624 if( layerSet.test( F_Cu ) )
625 layerSet |= LSET( { F_Mask, F_Paste } );
626
627 if( layerSet.test( B_Cu ) )
628 layerSet |= LSET( { B_Mask, B_Paste } );
629 }
630
631 pad->SetLayerSet( layerSet );
632 }
633 else
634 {
635 pad->SetLayerSet( LSET( { F_Cu, F_Mask, F_Paste } ) );
636 }
637 }
638 else
639 {
640 // Keep whatever mask and paste rows the stack carried, the way the ASCII path does
641 LSET maskPasteBits = layerSet & LSET( { F_Mask, B_Mask, F_Paste, B_Paste } );
642
643 pad->Padstack().SetMode( PADSTACK::MODE::NORMAL );
644 applyPadShape( pad, layerDef, F_Cu );
645
646 if( layerDef.plated )
647 {
648 pad->SetAttribute( PAD_ATTRIB::PTH );
649 pad->SetLayerSet( PAD::PTHMask() | maskPasteBits );
650 }
651 else
652 {
653 pad->SetAttribute( PAD_ATTRIB::NPTH );
654 pad->SetNumber( wxString() );
655 pad->SetLayerSet( PAD::UnplatedHoleMask() | maskPasteBits );
656 }
657 }
658 }
659 else
660 {
661 // 38100 basic units = 1 mil; default 60 mil pad.
662 int defaultPad = scaleSize( 60.0 * PADS_IO::SDB_BASIC_PER_MIL );
663 pad->SetSize( F_Cu, VECTOR2I( defaultPad, defaultPad ) );
664 pad->SetShape( F_Cu, PAD_SHAPE::CIRCLE );
665 pad->SetAttribute( PAD_ATTRIB::PTH );
666 pad->SetLayerSet( PAD::PTHMask() );
667 }
668
669 // An unplated hole is mechanical; joining it to a net pulls ratsnest to a mounting hole
670 if( pad->GetAttribute() == PAD_ATTRIB::NPTH )
671 return;
672
673 auto netIt = m_pinToNetMap.find( aFootprint->GetReference() + wxT( "." )
674 + PADS_COMMON::ConvertText( term.name ) );
675
676 if( netIt != m_pinToNetMap.end() )
677 {
678 NETINFO_ITEM* net = m_loadBoard->FindNet( PADS_COMMON::ConvertInvertedNetName( netIt->second ) );
679
680 if( net )
681 pad->SetNet( net );
682 }
683}
684
685
687 PCB_LAYER_ID aKiCadLayer )
688{
689 auto scaledPadSize = [&]( double aValue )
690 {
691 return std::max( m_minObjectSize, scaleSize( aValue ) );
692 };
693
694 VECTOR2I size( scaledPadSize( aLayer.sizeA ), scaledPadSize( aLayer.sizeA ) );
695
696 auto applyCornerRadius = [&]( const VECTOR2I& aSize, bool aDefaultRound )
697 {
698 if( aLayer.corner_radius > 0 )
699 {
700 int radius = scaledPadSize( aLayer.corner_radius );
701 int minimumDimension = std::min( aSize.x, aSize.y );
702 double ratio = minimumDimension > 0
703 ? std::min( static_cast<double>( radius ) / minimumDimension, 0.5 )
704 : 0.25;
705
706 aPad->SetShape( aKiCadLayer, PAD_SHAPE::ROUNDRECT );
707 aPad->SetRoundRectRadiusRatio( aKiCadLayer, ratio );
708 }
709 else if( aDefaultRound )
710 {
711 aPad->SetShape( aKiCadLayer, PAD_SHAPE::ROUNDRECT );
712 aPad->SetRoundRectRadiusRatio( aKiCadLayer, 0.25 );
713 }
714 };
715
716 aPad->SetShape( aKiCadLayer, PADS_PCB::PadsShapeToKiCad( aLayer.shape ) );
717
718 if( aLayer.shape == "O" || aLayer.shape == "OF" )
719 {
720 VECTOR2I ovalSize( scaledPadSize( aLayer.sizeB ), scaledPadSize( aLayer.sizeA ) );
721 aPad->SetSize( aKiCadLayer, ovalSize );
722 }
723 else if( aLayer.shape == "RF" )
724 {
725 VECTOR2I rectSize( scaledPadSize( aLayer.sizeB ), scaledPadSize( aLayer.sizeA ) );
726 aPad->SetSize( aKiCadLayer, rectSize );
727 applyCornerRadius( rectSize, false );
728
729 if( aLayer.finger_offset != 0 )
730 {
731 int offset = scaleSize( aLayer.finger_offset );
732 VECTOR2I padOffset( offset, 0 );
733 RotatePoint( padOffset, EDA_ANGLE( aLayer.rotation, DEGREES_T ) );
734 aPad->SetOffset( aKiCadLayer, padOffset );
735 }
736 }
737 else if( aLayer.shape == "RC" || aLayer.shape == "OC" )
738 {
739 VECTOR2I rrSize( scaledPadSize( aLayer.sizeB ), scaledPadSize( aLayer.sizeA ) );
740 aPad->SetSize( aKiCadLayer, rrSize );
741 applyCornerRadius( rrSize, true );
742 }
743 else
744 {
745 aPad->SetSize( aKiCadLayer, size );
746
747 if( aLayer.shape == "S" || aLayer.shape == "ST" )
748 applyCornerRadius( size, false );
749 }
750}
751
752
754{
755 const std::vector<PADS_IO::PART_CLUSTER>& clusters = m_parser->GetClusters();
756
757 if( clusters.empty() )
758 return;
759
760 // One PCB_GROUP per cluster, keyed by the 1-based CLSTID the membership field references.
761 std::map<int, PCB_GROUP*> clusterGroups;
762
763 for( const PADS_IO::PART_CLUSTER& cluster : clusters )
764 {
766 group->SetName( PADS_COMMON::ConvertText( cluster.name ) );
767 m_loadBoard->Add( group );
768 clusterGroups[cluster.id] = group;
769 }
770
771 // m_partFootprints is indexed by part index, so the part-index-keyed membership map
772 // resolves directly to a footprint.
773 const std::map<size_t, int>& partClusterIds = m_parser->GetPartClusterIds();
774
775 for( size_t i = 0; i < m_partFootprints.size(); ++i )
776 {
777 auto idIt = partClusterIds.find( i );
778
779 if( idIt == partClusterIds.end() || idIt->second <= 0 )
780 continue;
781
782 auto groupIt = clusterGroups.find( idIt->second );
783
784 if( groupIt != clusterGroups.end() )
785 groupIt->second->AddItem( m_partFootprints[i] );
786 }
787}
788
789
791 const PADS_IO::ARC_POINT& aCurr )
792{
793 aShape->SetShape( SHAPE_T::ARC );
794
795 // A start/end/center triple is ambiguous (minor vs major arc) for shallow arcs, so
796 // sample a midpoint at the sweep midpoint and pass start/mid/end; scaleCoord applies the
797 // Y-axis flip uniformly.
798 double midAngle = ( aCurr.arc.start_angle + aCurr.arc.delta_angle / 2.0 ) * M_PI / 180.0;
799 double midX = aCurr.arc.cx + aCurr.arc.radius * std::cos( midAngle );
800 double midY = aCurr.arc.cy + aCurr.arc.radius * std::sin( midAngle );
801
802 VECTOR2I start = scalePoint( aPrev.x, aPrev.y );
803 VECTOR2I mid = scalePoint( midX, midY );
804 VECTOR2I end = scalePoint( aCurr.x, aCurr.y );
805
806 aShape->SetArcGeometry( start, mid, end );
807}
808
809
811{
812 for( const PADS_IO::POLYLINE& polyline : m_parser->GetBoardOutlines() )
813 {
814 const auto& pts = polyline.points;
815
816 if( pts.size() < 2 )
817 continue;
818
819 for( size_t i = 0; i < pts.size() - 1; ++i )
820 {
821 const PADS_IO::ARC_POINT& p1 = pts[i];
822 const PADS_IO::ARC_POINT& p2 = pts[i + 1];
823
824 if( std::abs( p1.x - p2.x ) < 0.001 && std::abs( p1.y - p2.y ) < 0.001 )
825 continue;
826
827 PCB_SHAPE* shape = new PCB_SHAPE( m_loadBoard );
828
829 if( p2.is_arc )
830 {
831 setBoardOutlineArc( shape, p1, p2 );
832 }
833 else
834 {
835 shape->SetShape( SHAPE_T::SEGMENT );
836 shape->SetStart( scalePoint( p1.x, p1.y ) );
837 shape->SetEnd( scalePoint( p2.x, p2.y ) );
838 }
839
840 shape->SetWidth( scaleSize( polyline.width ) );
841 shape->SetLayer( Edge_Cuts );
842 m_loadBoard->Add( shape );
843 }
844
845 if( polyline.closed && pts.size() > 2 )
846 {
847 const PADS_IO::ARC_POINT& pLast = pts.back();
848 const PADS_IO::ARC_POINT& pFirst = pts.front();
849
850 bool needsClosing = ( std::abs( pLast.x - pFirst.x ) > 0.001 || std::abs( pLast.y - pFirst.y ) > 0.001 );
851
852 if( needsClosing )
853 {
854 PCB_SHAPE* shape = new PCB_SHAPE( m_loadBoard );
855
856 if( pFirst.is_arc )
857 {
858 setBoardOutlineArc( shape, pLast, pFirst );
859 }
860 else
861 {
862 shape->SetShape( SHAPE_T::SEGMENT );
863 shape->SetStart( scalePoint( pLast.x, pLast.y ) );
864 shape->SetEnd( scalePoint( pFirst.x, pFirst.y ) );
865 }
866
867 shape->SetWidth( scaleSize( polyline.width ) );
868 shape->SetLayer( Edge_Cuts );
869 m_loadBoard->Add( shape );
870 }
871 }
872 }
873}
874
875
877{
878 for( const PADS_IO::GRAPHIC_LINE& graphic : m_parser->GetGraphicLines() )
879 {
880 PCB_LAYER_ID layer = getMappedLayer( graphic.layer );
881
882 if( layer == UNDEFINED_LAYER )
883 continue;
884
885 const std::vector<PADS_IO::ARC_POINT>& points = graphic.points;
886
887 if( points.size() == 1 && points[0].is_arc && std::abs( points[0].arc.delta_angle - 360.0 ) < 0.1 )
888 {
889 PCB_SHAPE* shape = new PCB_SHAPE( m_loadBoard );
890 VECTOR2I center = scalePoint( points[0].arc.cx, points[0].arc.cy );
891 int radius = std::max( scaleSize( points[0].arc.radius ), m_minObjectSize );
892 shape->SetShape( SHAPE_T::CIRCLE );
893 shape->SetCenter( center );
894 shape->SetEnd( VECTOR2I( center.x + radius, center.y ) );
895 shape->SetWidth( scaleSize( graphic.width ) );
896 shape->SetLayer( layer );
897 m_loadBoard->Add( shape );
898 continue;
899 }
900
901 if( points.size() < 2 )
902 continue;
903
904 for( size_t index = 1; index < points.size(); ++index )
905 {
906 const PADS_IO::ARC_POINT& previous = points[index - 1];
907 const PADS_IO::ARC_POINT& current = points[index];
908
909 if( std::abs( previous.x - current.x ) < 0.001 && std::abs( previous.y - current.y ) < 0.001 )
910 continue;
911
912 PCB_SHAPE* shape = new PCB_SHAPE( m_loadBoard );
913
914 if( current.is_arc )
915 {
916 setBoardOutlineArc( shape, previous, current );
917 }
918 else
919 {
920 shape->SetShape( SHAPE_T::SEGMENT );
921 shape->SetStart( scalePoint( previous.x, previous.y ) );
922 shape->SetEnd( scalePoint( current.x, current.y ) );
923 }
924
925 shape->SetWidth( scaleSize( graphic.width ) );
926 shape->SetLayer( layer );
927 m_loadBoard->Add( shape );
928 }
929 }
930}
931
932
934{
935 const auto& routes = m_parser->GetRoutes();
936 for( const auto& route : routes )
937 {
938 NETINFO_ITEM* net = nullptr;
939
940 if( !route.net_name.empty() )
941 {
942 net = m_loadBoard->FindNet( PADS_COMMON::ConvertInvertedNetName( route.net_name ) );
943
944 if( !net )
945 {
946 if( m_reporter )
947 {
948 m_reporter->Report( wxString::Format( _( "Route net '%s' not found, skipping" ), route.net_name ),
950 }
951
952 continue;
953 }
954 }
955
956 for( const auto& track_def : route.tracks )
957 {
958 if( track_def.points.size() < 2 )
959 continue;
960
961 PCB_LAYER_ID track_layer = getMappedLayer( track_def.layer );
962
963 // An importer is best effort, and a route layer the user mapped to a non-copper
964 // layer is ordinary input, so drop the track rather than the whole board
965 if( !IsCopperLayer( track_layer ) )
966 {
967 if( m_reporter )
968 {
969 m_reporter->Report( wxString::Format( _( "Skipped a route on non-copper or unmapped "
970 "PADS layer %d." ),
971 track_def.layer ),
973 }
974
975 continue;
976 }
977
978 int track_width = scaleSize( track_def.width );
979
980 if( track_width <= 0 )
981 {
982 if( m_reporter )
983 {
984 m_reporter->Report( wxString::Format( _( "Skipped a non-positive-width route on PADS layer %d." ),
985 track_def.layer ),
987 }
988
989 continue;
990 }
991
992 for( size_t i = 0; i < track_def.points.size() - 1; ++i )
993 {
994 const PADS_IO::ARC_POINT& p1 = track_def.points[i];
995 const PADS_IO::ARC_POINT& p2 = track_def.points[i + 1];
996
997 VECTOR2I start = scalePoint( p1.x, p1.y );
998 VECTOR2I end = scalePoint( p2.x, p2.y );
999
1000 // Route-cell endpoints retain quantization residue that the PADS writer
1001 // collapses when exporting the same route to ASCII.
1002 constexpr int MIN_ROUTE_LENGTH = 500;
1003 int64_t deltaX = static_cast<int64_t>( end.x ) - start.x;
1004 int64_t deltaY = static_cast<int64_t>( end.y ) - start.y;
1005
1006 if( deltaX * deltaX + deltaY * deltaY < MIN_ROUTE_LENGTH * MIN_ROUTE_LENGTH )
1007 continue;
1008
1009 if( p2.is_arc )
1010 {
1011 VECTOR2I center = scalePoint( p2.arc.cx, p2.arc.cy );
1012
1013 bool clockwise = ( p2.arc.delta_angle < 0 );
1014
1015 SHAPE_ARC shapeArc;
1016 shapeArc.ConstructFromStartEndCenter( start, end, center, clockwise, track_width );
1017
1018 PCB_ARC* arc = new PCB_ARC( m_loadBoard, &shapeArc );
1019
1020 if( net )
1021 arc->SetNet( net );
1022
1023 arc->SetWidth( track_width );
1024 arc->SetLayer( track_layer );
1025 m_loadBoard->Add( arc );
1026 }
1027 else
1028 {
1029 PCB_TRACK* track = new PCB_TRACK( m_loadBoard );
1030
1031 if( net )
1032 track->SetNet( net );
1033
1034 track->SetWidth( track_width );
1035 track->SetLayer( track_layer );
1036 track->SetStart( start );
1037 track->SetEnd( end );
1038 m_loadBoard->Add( track );
1039 }
1040 }
1041 }
1042
1043 for( const auto& via_def : route.vias )
1044 {
1045 VECTOR2I pos = scalePoint( via_def.location.x, via_def.location.y );
1046
1047 std::unique_ptr<PCB_VIA> via = std::make_unique<PCB_VIA>( m_loadBoard );
1048
1049 if( net )
1050 via->SetNet( net );
1051
1052 via->SetPosition( pos );
1053
1054 const double viaDrill = via_def.stack.front().drill;
1055 via->Padstack().SetMode( PADSTACK::MODE::FRONT_INNER_BACK );
1056
1057 for( const PADS_IO::PAD_STACK_LAYER& layer : via_def.stack )
1058 {
1059 if( layer.sizeA <= 0 || !PADS_IO::IsCopperPadRow( layer ) )
1060 continue;
1061
1062 int width = scaleSize( layer.sizeA );
1063
1064 if( layer.layer == -2 )
1065 via->SetWidth( F_Cu, width );
1066 else if( layer.layer == 0 )
1067 via->SetWidth( PADSTACK::INNER_LAYERS, width );
1068 else if( layer.layer == -1 )
1069 via->SetWidth( B_Cu, width );
1070 }
1071
1072 via->SetDrill( scaleSize( viaDrill ) );
1073 PCB_LAYER_ID startLayer = getMappedLayer( via_def.start_layer );
1074 PCB_LAYER_ID endLayer = getMappedLayer( via_def.end_layer );
1075
1076 // A one-layer file defaults every via to the same span, so a whole board must not be
1077 // lost to a via the layer table cannot place
1078 if( !IsCopperLayer( startLayer ) || !IsCopperLayer( endLayer ) || startLayer == endLayer )
1079 {
1080 if( m_reporter )
1081 {
1082 m_reporter->Report( wxString::Format( _( "Skipped a via on net '%s' with an unusable "
1083 "PADS layer span %d,%d." ),
1084 PADS_COMMON::ConvertText( route.net_name ),
1085 via_def.start_layer, via_def.end_layer ),
1087 }
1088
1089 continue;
1090 }
1091
1092 // SetLayerPair sanitizes the span against the current via type and PCB_VIA is
1093 // constructed as THROUGH, so the type has to be set first or the decoded span is
1094 // overwritten with F_Cu/B_Cu and every blind or buried via becomes full stack
1095 if( ( startLayer == F_Cu && endLayer == B_Cu )
1096 || ( startLayer == B_Cu && endLayer == F_Cu ) )
1097 via->SetViaType( VIATYPE::THROUGH );
1098 else if( std::abs( via_def.start_layer - via_def.end_layer ) == 1
1099 && ( startLayer == F_Cu || startLayer == B_Cu || endLayer == F_Cu || endLayer == B_Cu ) )
1100 via->SetViaType( VIATYPE::MICROVIA );
1101 else if( startLayer == F_Cu || startLayer == B_Cu || endLayer == F_Cu || endLayer == B_Cu )
1102 via->SetViaType( VIATYPE::BLIND );
1103 else
1104 via->SetViaType( VIATYPE::BURIED );
1105
1106 via->SetLayerPair( startLayer, endLayer );
1107
1108 m_loadBoard->Add( via.release() );
1109 }
1110 }
1111}
1112
1113
1115{
1116 const auto& copperShapes = m_parser->GetCopperShapes();
1117
1118 for( const PADS_IO::COPPER_SHAPE& copper : copperShapes )
1119 {
1120 if( !copper.filled || copper.is_cutout || copper.outline.size() < 3 )
1121 continue;
1122
1123 PCB_LAYER_ID layer = getMappedLayer( copper.layer );
1124
1125 if( layer == UNDEFINED_LAYER )
1126 {
1127 if( m_reporter )
1128 {
1129 m_reporter->Report( wxString::Format( _( "COPPER item on unmapped layer %d" ), copper.layer ),
1131 }
1132
1133 continue;
1134 }
1135
1136 SHAPE_LINE_CHAIN outline;
1137
1138 for( const PADS_IO::ARC_POINT& pt : copper.outline )
1139 outline.Append( scalePoint( pt.x, pt.y ) );
1140
1141 outline.SetClosed( true );
1142
1143 if( !IsCopperLayer( layer ) )
1144 {
1146 shape->SetLayer( layer );
1147 shape->SetFilled( true );
1148 shape->SetPolyShape( SHAPE_POLY_SET( outline ) );
1149 m_loadBoard->Add( shape );
1150 continue;
1151 }
1152
1153 ZONE* zone = new ZONE( m_loadBoard );
1154 zone->SetLayer( layer );
1155 zone->SetIsRuleArea( false );
1156 zone->Outline()->AddOutline( outline );
1158
1159 m_loadBoard->Add( zone );
1160 }
1161}
1162
1163
1165{
1166 const auto& pours = m_parser->GetPours();
1167 const auto& params = m_parser->GetParameters();
1168
1169 int maxPriority = 0;
1170
1171 for( const auto& pour_def : pours )
1172 {
1173 if( pour_def.priority > maxPriority )
1174 maxPriority = pour_def.priority;
1175 }
1176
1177 for( const auto& pour_def : pours )
1178 {
1179 if( pour_def.points.size() < 3 )
1180 continue;
1181
1182 PCB_LAYER_ID pourLayer = getMappedLayer( pour_def.layer );
1183
1184 if( pourLayer == UNDEFINED_LAYER )
1185 {
1186 if( m_reporter )
1187 {
1188 m_reporter->Report( wxString::Format( _( "Skipping pour on unmapped layer %d" ), pour_def.layer ),
1190 }
1191
1192 continue;
1193 }
1194
1195 if( !IsCopperLayer( pourLayer ) )
1196 {
1197 SHAPE_LINE_CHAIN outline;
1198
1199 for( const auto& point : pour_def.points )
1200 outline.Append( scalePoint( point.x, point.y ) );
1201
1202 outline.SetClosed( true );
1203
1205 shape->SetLayer( pourLayer );
1206 shape->SetFilled( true );
1207 shape->SetPolyShape( SHAPE_POLY_SET( outline ) );
1208 m_loadBoard->Add( shape );
1209 continue;
1210 }
1211
1212 ZONE* zone = new ZONE( m_loadBoard );
1213 zone->SetLayer( pourLayer );
1214
1215 zone->Outline()->NewOutline();
1216
1217 for( const auto& pt : pour_def.points )
1218 {
1219 zone->Outline()->Append( scalePoint( pt.x, pt.y ) );
1220 }
1221
1222 if( zone->GetNumCorners() == 0 )
1223 {
1224 delete zone;
1225 continue;
1226 }
1227
1228 m_converter->ApplyPourSettings( zone, pour_def, maxPriority, params );
1229
1230 m_loadBoard->Add( zone );
1231 }
1232}
1233
1234
1235std::map<wxString, PCB_LAYER_ID>
1236PCB_IO_PADS_BINARY::DefaultLayerMappingCallback( const std::vector<INPUT_LAYER_DESC>& aInputLayerDescriptionVector )
1237{
1238 std::map<wxString, PCB_LAYER_ID> layerMap;
1239
1240 for( const INPUT_LAYER_DESC& layer : aInputLayerDescriptionVector )
1241 layerMap[layer.Name] = layer.AutoMapLayer;
1242
1243 return layerMap;
1244}
1245
1246
1248{
1249 m_loadBoard = nullptr;
1250 m_parser = nullptr;
1251 m_converter.reset();
1252 m_pinToNetMap.clear();
1253 m_partFootprints.clear();
1254}
int index
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
BASE_SET & set(size_t pos)
Definition base_set.h:126
virtual void SetNet(NETINFO_ITEM *aNetInfo)
Set a NET_INFO object for the item.
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition board_item.h:383
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:411
virtual void SetFilled(bool aFlag)
Definition eda_shape.h:144
void SetVertJustify(GR_TEXT_V_ALIGN_T aType)
Definition eda_text.cpp:378
virtual void SetVisible(bool aVisible)
Definition eda_text.cpp:347
void SetKeepUpright(bool aKeepUpright)
Definition eda_text.cpp:386
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
Definition eda_text.cpp:370
void SetPosition(const VECTOR2I &aPos) override
void SetFPID(const LIB_ID &aFPID)
Definition footprint.h:418
void SetOrientation(const EDA_ANGLE &aNewAngle)
void SetPath(const KIID_PATH &aPath)
Definition footprint.h:456
PCB_FIELD & Value()
read/write accessors:
Definition footprint.h:831
std::deque< PAD * > & Pads()
Definition footprint.h:355
void SetReference(const wxString &aReference)
Definition footprint.h:799
void SetValue(const wxString &aValue)
Definition footprint.h:822
PCB_FIELD & Reference()
Definition footprint.h:832
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Adds an item to the container.
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
void Flip(const VECTOR2I &aCentre, FLIP_DIRECTION aFlipDirection) override
Flip this object, i.e.
const wxString & GetReference() const
Definition footprint.h:793
VECTOR2I GetPosition() const override
Definition footprint.h:379
REPORTER * m_reporter
Reporter to log errors/warnings to, may be nullptr.
Definition io_base.h:242
PROGRESS_REPORTER * m_progressReporter
Progress reporter to track the progress of the operation, may be nullptr.
Definition io_base.h:245
virtual bool CanReadLibrary(const wxString &aFileName) const
Checks if this IO object can read the specified library file/directory.
Definition io_base.cpp:71
Definition kiid.h:46
virtual void RegisterCallback(LAYER_MAPPING_HANDLER aLayerMappingHandler)
Register a different handler to be called when mapping of input layers to KiCad layers occurs.
LAYER_MAPPING_HANDLER m_layer_mapping_handler
Callback to get layer mapping.
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:45
int SetLibItemName(const UTF8 &aLibItemName)
Override the library item name portion of the LIB_ID to aLibItemName.
Definition lib_id.cpp:124
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition locale_io.h:37
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
Handle the data for a net.
Definition netinfo.h:50
@ 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
static constexpr PCB_LAYER_ID INNER_LAYERS
! The layer identifier to use for "inner layers" on top/inner/bottom padstacks
Definition padstack.h:182
Reader for the PADS PowerPCB binary .pcb format.
static bool IsBinaryPadsFile(const wxString &aFileName)
Check if a file appears to be a PADS binary PCB file.
void Parse(const wxString &aFileName)
static constexpr double BASIC_TO_NM
Definition pad.h:61
static LSET PTHMask()
layer set for a through hole pad
Definition pad.cpp:615
void SetShape(PCB_LAYER_ID aLayer, PAD_SHAPE aShape)
Set the new shape of this pad.
Definition pad.h:196
static LSET UnplatedHoleMask()
layer set for a mechanical unplated through hole pad
Definition pad.cpp:636
void SetOffset(PCB_LAYER_ID aLayer, const VECTOR2I &aOffset)
Definition pad.cpp:826
void SetSize(PCB_LAYER_ID aLayer, const VECTOR2I &aSize)
Definition pad.cpp:264
void SetRoundRectRadiusRatio(PCB_LAYER_ID aLayer, double aRadiusScale)
Has meaning only for rounded rectangle pads.
Definition pad.cpp:1193
A set of BOARD_ITEMs (i.e., without duplicates).
Definition pcb_group.h:51
long long GetLibraryTimestamp(const wxString &aLibraryPath) const override
Generate a timestamp representing all the files in the library (including the library directory).
void loadClusterGroups()
Build one PCB_GROUP per PADS part cluster and add each footprint to the group named by its part's CLS...
void setBoardOutlineArc(PCB_SHAPE *aShape, const PADS_IO::ARC_POINT &aPrev, const PADS_IO::ARC_POINT &aCurr)
const IO_FILE_DESC GetBoardFileDesc() const override
Return board file description for the PCB_IO.
bool CanReadBoard(const wxString &aFileName) const override
~PCB_IO_PADS_BINARY() override
int scaleSize(double aVal) const
Shorthands for the converter's transform, which the loaders below use everywhere.
const IO_FILE_DESC GetLibraryDesc() const override
Get the descriptor for the library container that this IO plugin operates on.
void buildPad(FOOTPRINT *aFootprint, const PADS_IO::PART_DECAL &aDecal, size_t aTermIdx, const EDA_ANGLE &aPartOrient)
Build one terminal's pad on aFootprint from decal terminal aTermIdx, oriented by the part orientation...
const PADS_IO::BINARY_PARSER * m_parser
std::map< wxString, std::string > m_pinToNetMap
"<refdes>.<pin>" to PADS net name
PCB_LAYER_ID getMappedLayer(int aPadsLayer) const
std::unique_ptr< PADS_PCB_CONVERTER > m_converter
bool CanReadLibrary(const wxString &aFileName) const override
Checks if this IO object can read the specified library file/directory.
void loadBoard(const wxString &aFileName, BOARD &aBoard, bool aIsNewLoad, const std::map< std::string, UTF8 > *aProperties, PROJECT *aProject) override
Parse aFileName into aBoard.
void applyPadShape(PAD *aPad, const PADS_IO::PAD_STACK_LAYER &aLayer, PCB_LAYER_ID aKiCadLayer)
Apply a pad-stack layer's shape, size and finger offset to aPad.
std::vector< FOOTPRINT * > m_partFootprints
VECTOR2I scalePoint(double aX, double aY) const
Scale a board point to a KiCad position, applying the per-axis origin and the Y-flip.
std::map< wxString, PCB_LAYER_ID > DefaultLayerMappingCallback(const std::vector< INPUT_LAYER_DESC > &aInputLayerDescriptionVector)
virtual bool CanReadBoard(const wxString &aFileName) const
Definition pcb_io.cpp:40
PCB_IO(const wxString &aName)
Definition pcb_io.h:383
void SetCenter(const VECTOR2I &aCenter) override
void SetWidth(int aWidth) override
void SetShape(SHAPE_T aShape) override
Definition pcb_shape.h:212
void SetEnd(const VECTOR2I &aEnd) override
void SetPolyShape(const SHAPE_POLY_SET &aShape) override
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
void SetStart(const VECTOR2I &aStart) override
void SetArcGeometry(const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd) override
Set the three controlling points for an arc.
void SetTextThickness(int aWidth) override
The TextThickness is that set by the user.
Definition pcb_text.cpp:512
void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true) override
Definition pcb_text.cpp:484
void SetPosition(const VECTOR2I &aPos) override
Definition pcb_text.h:103
void SetTextAngle(const EDA_ANGLE &aAngle) override
Definition pcb_text.cpp:572
void SetEnd(const VECTOR2I &aEnd)
Definition pcb_track.h:94
void SetStart(const VECTOR2I &aStart)
Definition pcb_track.h:97
virtual void SetWidth(int aWidth)
Definition pcb_track.h:91
Container for project specific data.
Definition project.h:63
SHAPE_ARC & ConstructFromStartEndCenter(const VECTOR2I &aStart, const VECTOR2I &aEnd, const VECTOR2I &aCenter, bool aClockwise=false, double aWidth=0)
Constructs this arc from the given start, end and center.
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
Represent a set of closed polygons.
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
int NewOutline()
Creates a new empty polygon in the set and returns its index.
Handle a list of polygons defining a copper zone.
Definition zone.h:70
void SetBorderDisplayStyle(ZONE_BORDER_DISPLAY_STYLE aBorderHatchStyle, int aBorderHatchPitch, bool aRebuildBorderHatch)
Set all hatch parameters for the zone.
Definition zone.cpp:1595
virtual void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
Definition zone.cpp:675
SHAPE_POLY_SET * Outline()
Definition zone.h:421
void SetIsRuleArea(bool aEnable)
Definition zone.h:833
static int GetDefaultHatchPitch()
Definition zone.cpp:1672
int GetNumCorners(void) const
Access to m_Poly parameters.
Definition zone.h:617
#define _(s)
@ DEGREES_T
Definition eda_angle.h:30
@ SEGMENT
Definition eda_shape.h:56
double m_PadsPcbTextWidthScale
PADS text width scale factor for PCB imports.
double m_PadsPcbTextHeightScale
PADS text height scale factor for PCB imports.
int m_PcbImportMinObjectSizeNm
Minimum object size in nanometers for PCB imports.
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition layer_ids.h:741
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
@ Edge_Cuts
Definition layer_ids.h:108
@ F_Paste
Definition layer_ids.h:100
@ 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
@ UNDEFINED_LAYER
Definition layer_ids.h:57
@ In1_Cu
Definition layer_ids.h:62
@ F_Cu
Definition layer_ids.h:60
@ LEFT_RIGHT
Flip left to right (around the Y axis)
Definition mirror.h:24
wxString ConvertText(const std::string &aText)
Decode text from a PADS file, which uses an 8-bit codepage rather than UTF-8.
wxString ConvertInvertedNetName(const std::string &aNetName)
Convert a PADS net name to KiCad notation.
KIID GenerateDeterministicUuid(const std::string &aIdentifier)
Generate a deterministic KIID from a PADS component identifier.
constexpr double SDB_BASIC_PER_MIL
bool IsAntiPadRow(const PAD_STACK_LAYER &aLayer)
RA and SA rows carry a plane's anti-pad clearance rather than the pad's own copper.
bool IsThermalReliefPadRow(const PAD_STACK_LAYER &aLayer)
RT and ST rows carry a plane's thermal-relief spoke pattern rather than the pad's own copper.
bool IsCopperPadRow(const PAD_STACK_LAYER &aLayer)
True when the row describes pad or via copper.
PAD_SHAPE PadsShapeToKiCad(const std::string &aShape)
Map a PADS pad-stack shape code to a KiCad pad shape, shared by both PADS PCB importers.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:437
@ 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
@ ROUNDRECT
Definition padstack.h:56
Class to handle a set of BOARD_ITEMs.
@ RPT_SEVERITY_WARNING
@ RPT_SEVERITY_INFO
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
@ CTX_REGEX
Describes an imported layer and how it could be mapped to KiCad Layers.
Container that describes file type info.
Definition io_base.h:43
wxString m_Description
Description shown in the file picker dialog.
Definition io_base.h:44
std::vector< std::string > m_FileExtensions
Filter used for file pickers if m_IsFile is true.
Definition io_base.h:47
A polyline point that may instead be an arc segment.
Definition pads_parser.h:64
ARC arc
Only valid when is_arc is true.
Definition pads_parser.h:68
double radius
Definition pads_parser.h:53
double delta_angle
Definition pads_parser.h:55
double start_angle
Definition pads_parser.h:54
std::string hjust
std::string vjust
A PADS net class recovered from the binary design-rule graph.
Standalone copper area from the LINES section (type=COPPER), not part of a pour.
Non-electrical drawing item from the LINES section (type=LINES).
double drill
0 for SMD
std::string shape
R, S, A, O, OF, RF, RT, ST, RA, SA, RC, OC.
bool plated
PTH vs NPTH.
double slot_orientation
0-179.999 degrees
double finger_offset
Along orientation axis.
double sizeB
Height for rectangles/ovals.
double corner_radius
Always positive.
double sizeA
Diameter or width.
A PADS part cluster (named group of parts).
std::vector< TERMINAL > terminals
std::map< int, std::vector< PAD_STACK_LAYER > > pad_stacks
A polyline that may contain arc segments, used for board outlines and graphics.
std::string path
KIBIS_PIN * pin
VECTOR2I center
int radius
VECTOR2I end
@ GR_TEXT_H_ALIGN_CENTER
@ GR_TEXT_H_ALIGN_RIGHT
@ GR_TEXT_H_ALIGN_LEFT
@ GR_TEXT_V_ALIGN_BOTTOM
@ GR_TEXT_V_ALIGN_CENTER
@ GR_TEXT_V_ALIGN_TOP
#define M_PI
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
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708
@ THERMAL
Use thermal relief for pads.
Definition zones.h:46