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& net : nc.nets )
263 netSettings->SetNetclassPatternAssignment( PADS_COMMON::ConvertInvertedNetName( net ), className );
264 }
265
266 // Each differential pair becomes one DiffPair_<name> net class.
267 for( const PADS_IO::DIFF_PAIR_DEF& dp : diffPairs )
268 {
269 if( dp.name.empty() )
270 continue;
271
272 wxString dpClassName = wxString::Format( wxT( "DiffPair_%s" ), PADS_COMMON::ConvertText( dp.name ) );
273 std::shared_ptr<NETCLASS> dpNetclass = std::make_shared<NETCLASS>( dpClassName );
274
275 if( dp.gap > 0 )
276 dpNetclass->SetDiffPairGap( scaleSize( dp.gap ) );
277
278 if( dp.width > 0 )
279 {
280 dpNetclass->SetDiffPairWidth( scaleSize( dp.width ) );
281 dpNetclass->SetTrackWidth( scaleSize( dp.width ) );
282 }
283
284 netSettings->SetNetclass( dpClassName, dpNetclass );
285
286 if( !dp.positive_net.empty() )
287 netSettings->SetNetclassPatternAssignment( PADS_COMMON::ConvertInvertedNetName( dp.positive_net ),
288 dpClassName );
289
290 if( !dp.negative_net.empty() )
291 netSettings->SetNetclassPatternAssignment( PADS_COMMON::ConvertInvertedNetName( dp.negative_net ),
292 dpClassName );
293 }
294}
295
296
298{
299 const auto& decals = m_parser->GetPartDecals();
300 const auto& parts = m_parser->GetParts();
301
302 for( const auto& padsPart : parts )
303 {
304 FOOTPRINT* footprint = new FOOTPRINT( m_loadBoard );
305 footprint->SetReference( PADS_COMMON::ConvertText( padsPart.name ) );
306
307 KIID symbolUuid = PADS_COMMON::GenerateDeterministicUuid( padsPart.name );
309 path.push_back( symbolUuid );
310 footprint->SetPath( path );
311
312 std::string decalName = padsPart.decal;
313
314 LIB_ID fpid;
315
316 if( !decalName.empty() )
317 fpid.SetLibItemName( PADS_COMMON::ConvertText( decalName ) );
318 else
319 fpid.SetLibItemName( PADS_COMMON::ConvertText( padsPart.name ) );
320
321 footprint->SetFPID( fpid );
322
323 // A part referencing a *PARTTYPE alias (often a manufacturer part number) shows that
324 // alias as its value, not the physical decal it resolves to; see linkPartsToDecals().
325 footprint->SetValue( PADS_COMMON::ConvertText( padsPart.value.empty() ? padsPart.decal
326 : padsPart.value ) );
327
328 footprint->SetPosition( scalePoint( padsPart.location.x, padsPart.location.y ) );
329 footprint->SetOrientation( EDA_ANGLE( padsPart.rotation, DEGREES_T ) );
330 footprint->SetLayer( F_Cu );
331 footprint->Reference().SetLayer( F_Fab );
332 footprint->Reference().SetVisible( false );
333 footprint->Value().SetLayer( F_Fab );
334 footprint->Value().SetVisible( false );
335
336 auto decalIt = decals.find( decalName );
337
338 if( decalIt == decals.end() )
339 {
340 if( m_reporter )
341 {
342 m_reporter->Report( wxString::Format( _( "Part '%s': decal '%s' not found, no pads created" ),
343 padsPart.name, decalName ),
345 }
346 }
347
348 if( decalIt != decals.end() )
349 {
350 const PADS_IO::PART_DECAL& decal = decalIt->second;
351 EDA_ANGLE partOrient( padsPart.rotation, DEGREES_T );
352
353 for( size_t termIdx = 0; termIdx < decal.terminals.size(); ++termIdx )
354 buildPad( footprint, decal, termIdx, partOrient );
355 }
356
357 for( const PADS_IO::ATTRIBUTE& attribute : padsPart.attributes )
358 {
359 PCB_FIELD* field = nullptr;
360
361 if( attribute.name == "Ref.Des." )
362 field = &footprint->Reference();
363 else if( attribute.name == "Part Type" )
364 field = &footprint->Value();
365
366 if( !field )
367 continue;
368
369 int scaledSize = scaleSize( attribute.height );
370 int charHeight = static_cast<int>( scaledSize * ADVANCED_CFG::GetCfg().m_PadsPcbTextHeightScale );
371 int charWidth = static_cast<int>( scaledSize * ADVANCED_CFG::GetCfg().m_PadsPcbTextWidthScale );
372 field->SetTextSize( VECTOR2I( charWidth, charHeight ) );
373
374 if( attribute.width > 0 )
375 field->SetTextThickness( scaleSize( attribute.width ) );
376
377 VECTOR2I offset( scaleSize( attribute.x ), -scaleSize( attribute.y ) );
378 EDA_ANGLE partAngle( padsPart.rotation, DEGREES_T );
379 RotatePoint( offset, partAngle );
380
381 EDA_ANGLE textAngle( attribute.orientation + padsPart.rotation, DEGREES_T );
382 VECTOR2I textShift( -ADVANCED_CFG::GetCfg().m_PadsTextAnchorOffsetNm, 0 );
383 RotatePoint( textShift, textAngle );
384
385 field->SetPosition( footprint->GetPosition() + offset + textShift );
386 field->SetTextAngle( textAngle );
387 field->SetKeepUpright( false );
388 field->SetVisible( attribute.visible );
389 field->SetLayer( F_Fab );
390
391 if( attribute.hjust == "LEFT" )
393 else if( attribute.hjust == "RIGHT" )
395 else
397
398 if( attribute.vjust == "UP" )
400 else if( attribute.vjust == "DOWN" )
402 else
404 }
405
406 m_loadBoard->Add( footprint );
407
408 if( padsPart.bottom_layer )
409 {
410 footprint->Flip( footprint->GetPosition(), FLIP_DIRECTION::LEFT_RIGHT );
411
412 for( PAD* pad : footprint->Pads() )
413 {
414 if( pad->GetAttribute() == PAD_ATTRIB::PTH && pad->Padstack().Mode() == PADSTACK::MODE::NORMAL )
415 {
416 pad->SetLayerSet( PAD::PTHMask() | ( pad->GetLayerSet() & LSET( { F_Paste, B_Paste } ) ) );
417 }
418 }
419 }
420
421 m_partFootprints.push_back( footprint );
422 }
423}
424
425
426void PCB_IO_PADS_BINARY::buildPad( FOOTPRINT* aFootprint, const PADS_IO::PART_DECAL& aDecal, size_t aTermIdx,
427 const EDA_ANGLE& aPartOrient )
428{
429 const auto& term = aDecal.terminals[aTermIdx];
430 PAD* pad = new PAD( aFootprint );
431 aFootprint->Add( pad );
432
433 pad->SetNumber( PADS_COMMON::ConvertText( term.name ) );
434
435 VECTOR2I padPos( scaleSize( term.x ), -scaleSize( term.y ) );
436 RotatePoint( padPos, aPartOrient );
437 pad->SetPosition( aFootprint->GetPosition() + padPos );
438
439 int pinNum = static_cast<int>( aTermIdx + 1 );
440 auto stackIt = aDecal.pad_stacks.find( pinNum );
441
442 if( stackIt == aDecal.pad_stacks.end() )
443 stackIt = aDecal.pad_stacks.find( 0 );
444
445 if( stackIt != aDecal.pad_stacks.end() && !stackIt->second.empty() )
446 {
447 const std::vector<PADS_IO::PAD_STACK_LAYER>& stack = stackIt->second;
448 const PADS_IO::PAD_STACK_LAYER& layerDef = stack[0];
449
450 std::set<int> serializedLayers;
451 bool ambiguousLayers = false;
452
453 // A relief or anti-pad row repeats the layer ordinal of the copper row it qualifies, so
454 // counting it here would read every plane-relief padstack as ambiguous
455 for( auto it = std::next( stack.begin() ); it != stack.end(); ++it )
456 {
457 if( PADS_IO::IsCopperPadRow( *it ) )
458 ambiguousLayers |= !serializedLayers.insert( it->layer ).second;
459 }
460
461 bool modernZeroDefaultSmd = m_parser->GetVersion() == 0x2024 && layerDef.drill == 0 && layerDef.sizeA <= 0;
462 bool legacyZeroDefaultSmd = m_parser->GetVersion() == 0x2022 && layerDef.drill == 0
463 && layerDef.sizeA <= 0;
464 bool zeroDefaultSmd = modernZeroDefaultSmd || legacyZeroDefaultSmd;
465 bool hasExplicitLayers = stack.size() > 1 && ( layerDef.drill > 0 || zeroDefaultSmd ) && !ambiguousLayers;
466 LSET layerSet;
467
468 if( hasExplicitLayers )
469 {
470 pad->Padstack().SetMode( PADSTACK::MODE::FRONT_INNER_BACK );
471 bool appliedExplicitLayer = false;
472 const PADS_IO::PAD_STACK_LAYER* inheritedLegacyShape = nullptr;
473
474 if( legacyZeroDefaultSmd )
475 {
476 auto inherited = std::find_if( stack.begin(), stack.end(),
477 []( const PADS_IO::PAD_STACK_LAYER& aLayer )
478 {
479 return aLayer.layer == 0 && aLayer.sizeA > 0;
480 } );
481
482 if( inherited != stack.end() )
483 inheritedLegacyShape = &*inherited;
484 }
485
486 for( const PADS_IO::PAD_STACK_LAYER& stackLayer : stack )
487 {
488 if( stackLayer.sizeA <= 0 )
489 continue;
490
491 // RT/ST are plane thermal-relief spoke patterns and RA/SA are anti-pad
492 // clearances. Neither is pad copper, so they must not reach the shape below.
493 // KiCad derives the relief geometry from the zone, so an RT/ST row only says
494 // that this pad connects through spokes rather than solid copper.
495 if( PADS_IO::IsThermalReliefPadRow( stackLayer ) )
496 {
497 pad->SetLocalZoneConnection( ZONE_CONNECTION::THERMAL );
498 continue;
499 }
500
501 if( PADS_IO::IsAntiPadRow( stackLayer ) )
502 continue;
503
504 if( modernZeroDefaultSmd && stackLayer.layer == 0 )
505 continue;
506
507 if( legacyZeroDefaultSmd && stackLayer.layer <= 0 )
508 continue;
509
510 PCB_LAYER_ID kicadLayer = UNDEFINED_LAYER;
511
512 if( modernZeroDefaultSmd && stackLayer.layer == -1 )
513 {
514 kicadLayer = B_Paste;
515 layerSet.set( B_Paste );
516 }
517 else if( stackLayer.layer == -2 )
518 {
519 kicadLayer = F_Cu;
520 layerSet.set( F_Cu );
521 }
522 else if( stackLayer.layer == -1 )
523 {
524 kicadLayer = B_Cu;
525 layerSet.set( B_Cu );
526 }
527 else if( stackLayer.layer == 0 )
528 {
529 if( m_loadBoard->GetCopperLayerCount() > 2 )
530 {
531 kicadLayer = In1_Cu;
532
533 for( int layer = 2; layer < m_parser->GetParameters().layer_count; ++layer )
534 {
535 PCB_LAYER_ID inner = getMappedLayer( layer );
536
537 if( IsCopperLayer( inner ) )
538 layerSet.set( inner );
539 }
540 }
541 }
542 else
543 {
544 int padsLayer = stackLayer.layer;
545 kicadLayer = getMappedLayer( padsLayer );
546
547 if( kicadLayer != UNDEFINED_LAYER )
548 layerSet.set( kicadLayer );
549 }
550
551 if( kicadLayer != UNDEFINED_LAYER )
552 {
553 PADS_IO::PAD_STACK_LAYER appliedLayer = stackLayer;
554
555 if( modernZeroDefaultSmd )
556 {
557 appliedLayer.sizeA *= 1.5;
558 appliedLayer.sizeB *= 1.5;
559 appliedLayer.corner_radius *= 1.5;
560 }
561 else if( inheritedLegacyShape )
562 {
563 appliedLayer.shape = inheritedLegacyShape->shape;
564 appliedLayer.sizeA = inheritedLegacyShape->sizeA * 1.5;
565 appliedLayer.sizeB = inheritedLegacyShape->sizeB * 1.5;
566 }
567
568 applyPadShape( pad, appliedLayer, kicadLayer );
569 appliedExplicitLayer = true;
570
571 if( zeroDefaultSmd && appliedLayer.shape == "R" )
572 pad->SetRoundRectRadiusRatio( kicadLayer, 0.25 );
573 }
574 }
575
576 if( zeroDefaultSmd && !appliedExplicitLayer )
577 {
578 applyPadShape( pad, layerDef, F_Cu );
579 applyPadShape( pad, layerDef, F_Mask );
580 applyPadShape( pad, layerDef, F_Paste );
581 layerSet = LSET( { F_Cu, F_Mask, F_Paste } );
582 }
583 }
584 else
585 {
586 applyPadShape( pad, layerDef, F_Cu );
587 }
588
589 pad->SetOrientation( aPartOrient + EDA_ANGLE( layerDef.rotation, DEGREES_T ) );
590
591 int drill = scaleSize( layerDef.drill );
592
593 if( layerDef.slot_length > 0 && layerDef.slot_length != layerDef.drill )
594 {
595 pad->SetDrillShape( PAD_DRILL_SHAPE::OBLONG );
596
597 int drillMajor = scaleSize( layerDef.slot_length );
598 double relativeAngle = std::fmod( layerDef.slot_orientation - layerDef.rotation, 360.0 );
599
600 if( relativeAngle < 0 )
601 relativeAngle += 360.0;
602
603 bool vertical = ( relativeAngle > 45.0 && relativeAngle < 135.0 )
604 || ( relativeAngle > 225.0 && relativeAngle < 315.0 );
605 pad->SetDrillSize( vertical ? VECTOR2I( drill, drillMajor ) : VECTOR2I( drillMajor, drill ) );
606 }
607 else
608 {
609 pad->SetDrillSize( VECTOR2I( drill, drill ) );
610 }
611
612 if( drill == 0 )
613 {
614 pad->SetAttribute( PAD_ATTRIB::SMD );
615
616 if( hasExplicitLayers )
617 {
618 if( !zeroDefaultSmd )
619 {
620 if( layerSet.test( F_Cu ) )
621 layerSet |= LSET( { F_Mask, F_Paste } );
622
623 if( layerSet.test( B_Cu ) )
624 layerSet |= LSET( { B_Mask, B_Paste } );
625 }
626
627 pad->SetLayerSet( layerSet );
628 }
629 else
630 {
631 pad->SetLayerSet( LSET( { F_Cu, F_Mask, F_Paste } ) );
632 }
633 }
634 else
635 {
636 // Keep whatever mask and paste rows the stack carried, the way the ASCII path does
637 LSET maskPasteBits = layerSet & LSET( { F_Mask, B_Mask, F_Paste, B_Paste } );
638
639 pad->Padstack().SetMode( PADSTACK::MODE::NORMAL );
640 applyPadShape( pad, layerDef, F_Cu );
641
642 if( layerDef.plated )
643 {
644 pad->SetAttribute( PAD_ATTRIB::PTH );
645 pad->SetLayerSet( PAD::PTHMask() | maskPasteBits );
646 }
647 else
648 {
649 pad->SetAttribute( PAD_ATTRIB::NPTH );
650 pad->SetNumber( wxString() );
651 pad->SetLayerSet( PAD::UnplatedHoleMask() | maskPasteBits );
652 }
653 }
654 }
655 else
656 {
657 // 38100 basic units = 1 mil; default 60 mil pad.
658 int defaultPad = scaleSize( 60.0 * PADS_IO::SDB_BASIC_PER_MIL );
659 pad->SetSize( F_Cu, VECTOR2I( defaultPad, defaultPad ) );
660 pad->SetShape( F_Cu, PAD_SHAPE::CIRCLE );
661 pad->SetAttribute( PAD_ATTRIB::PTH );
662 pad->SetLayerSet( PAD::PTHMask() );
663 }
664
665 // An unplated hole is mechanical; joining it to a net pulls ratsnest to a mounting hole
666 if( pad->GetAttribute() == PAD_ATTRIB::NPTH )
667 return;
668
669 auto netIt = m_pinToNetMap.find( aFootprint->GetReference() + wxT( "." )
670 + PADS_COMMON::ConvertText( term.name ) );
671
672 if( netIt != m_pinToNetMap.end() )
673 {
674 NETINFO_ITEM* net = m_loadBoard->FindNet( PADS_COMMON::ConvertInvertedNetName( netIt->second ) );
675
676 if( net )
677 pad->SetNet( net );
678 }
679}
680
681
683 PCB_LAYER_ID aKiCadLayer )
684{
685 auto scaledPadSize = [&]( double aValue )
686 {
687 return std::max( m_minObjectSize, scaleSize( aValue ) );
688 };
689
690 VECTOR2I size( scaledPadSize( aLayer.sizeA ), scaledPadSize( aLayer.sizeA ) );
691
692 auto applyCornerRadius = [&]( const VECTOR2I& aSize, bool aDefaultRound )
693 {
694 if( aLayer.corner_radius > 0 )
695 {
696 int radius = scaledPadSize( aLayer.corner_radius );
697 int minimumDimension = std::min( aSize.x, aSize.y );
698 double ratio = minimumDimension > 0
699 ? std::min( static_cast<double>( radius ) / minimumDimension, 0.5 )
700 : 0.25;
701
702 aPad->SetShape( aKiCadLayer, PAD_SHAPE::ROUNDRECT );
703 aPad->SetRoundRectRadiusRatio( aKiCadLayer, ratio );
704 }
705 else if( aDefaultRound )
706 {
707 aPad->SetShape( aKiCadLayer, PAD_SHAPE::ROUNDRECT );
708 aPad->SetRoundRectRadiusRatio( aKiCadLayer, 0.25 );
709 }
710 };
711
712 aPad->SetShape( aKiCadLayer, PADS_PCB::PadsShapeToKiCad( aLayer.shape ) );
713
714 if( aLayer.shape == "O" || aLayer.shape == "OF" )
715 {
716 VECTOR2I ovalSize( scaledPadSize( aLayer.sizeB ), scaledPadSize( aLayer.sizeA ) );
717 aPad->SetSize( aKiCadLayer, ovalSize );
718 }
719 else if( aLayer.shape == "RF" )
720 {
721 VECTOR2I rectSize( scaledPadSize( aLayer.sizeB ), scaledPadSize( aLayer.sizeA ) );
722 aPad->SetSize( aKiCadLayer, rectSize );
723 applyCornerRadius( rectSize, false );
724
725 if( aLayer.finger_offset != 0 )
726 {
727 int offset = scaleSize( aLayer.finger_offset );
728 VECTOR2I padOffset( offset, 0 );
729 RotatePoint( padOffset, EDA_ANGLE( aLayer.rotation, DEGREES_T ) );
730 aPad->SetOffset( aKiCadLayer, padOffset );
731 }
732 }
733 else if( aLayer.shape == "RC" || aLayer.shape == "OC" )
734 {
735 VECTOR2I rrSize( scaledPadSize( aLayer.sizeB ), scaledPadSize( aLayer.sizeA ) );
736 aPad->SetSize( aKiCadLayer, rrSize );
737 applyCornerRadius( rrSize, true );
738 }
739 else
740 {
741 aPad->SetSize( aKiCadLayer, size );
742
743 if( aLayer.shape == "S" || aLayer.shape == "ST" )
744 applyCornerRadius( size, false );
745 }
746}
747
748
750{
751 const std::vector<PADS_IO::PART_CLUSTER>& clusters = m_parser->GetClusters();
752
753 if( clusters.empty() )
754 return;
755
756 // One PCB_GROUP per cluster, keyed by the 1-based CLSTID the membership field references.
757 std::map<int, PCB_GROUP*> clusterGroups;
758
759 for( const PADS_IO::PART_CLUSTER& cluster : clusters )
760 {
762 group->SetName( PADS_COMMON::ConvertText( cluster.name ) );
763 m_loadBoard->Add( group );
764 clusterGroups[cluster.id] = group;
765 }
766
767 // m_partFootprints is indexed by part index, so the part-index-keyed membership map
768 // resolves directly to a footprint.
769 const std::map<size_t, int>& partClusterIds = m_parser->GetPartClusterIds();
770
771 for( size_t i = 0; i < m_partFootprints.size(); ++i )
772 {
773 auto idIt = partClusterIds.find( i );
774
775 if( idIt == partClusterIds.end() || idIt->second <= 0 )
776 continue;
777
778 auto groupIt = clusterGroups.find( idIt->second );
779
780 if( groupIt != clusterGroups.end() )
781 groupIt->second->AddItem( m_partFootprints[i] );
782 }
783}
784
785
787 const PADS_IO::ARC_POINT& aCurr )
788{
789 aShape->SetShape( SHAPE_T::ARC );
790
791 // A start/end/center triple is ambiguous (minor vs major arc) for shallow arcs, so
792 // sample a midpoint at the sweep midpoint and pass start/mid/end; scaleCoord applies the
793 // Y-axis flip uniformly.
794 double midAngle = ( aCurr.arc.start_angle + aCurr.arc.delta_angle / 2.0 ) * M_PI / 180.0;
795 double midX = aCurr.arc.cx + aCurr.arc.radius * std::cos( midAngle );
796 double midY = aCurr.arc.cy + aCurr.arc.radius * std::sin( midAngle );
797
798 VECTOR2I start = scalePoint( aPrev.x, aPrev.y );
799 VECTOR2I mid = scalePoint( midX, midY );
800 VECTOR2I end = scalePoint( aCurr.x, aCurr.y );
801
802 aShape->SetArcGeometry( start, mid, end );
803}
804
805
807{
808 for( const PADS_IO::POLYLINE& polyline : m_parser->GetBoardOutlines() )
809 {
810 const auto& pts = polyline.points;
811
812 if( pts.size() < 2 )
813 continue;
814
815 for( size_t i = 0; i < pts.size() - 1; ++i )
816 {
817 const PADS_IO::ARC_POINT& p1 = pts[i];
818 const PADS_IO::ARC_POINT& p2 = pts[i + 1];
819
820 if( std::abs( p1.x - p2.x ) < 0.001 && std::abs( p1.y - p2.y ) < 0.001 )
821 continue;
822
823 PCB_SHAPE* shape = new PCB_SHAPE( m_loadBoard );
824
825 if( p2.is_arc )
826 {
827 setBoardOutlineArc( shape, p1, p2 );
828 }
829 else
830 {
831 shape->SetShape( SHAPE_T::SEGMENT );
832 shape->SetStart( scalePoint( p1.x, p1.y ) );
833 shape->SetEnd( scalePoint( p2.x, p2.y ) );
834 }
835
836 shape->SetWidth( scaleSize( polyline.width ) );
837 shape->SetLayer( Edge_Cuts );
838 m_loadBoard->Add( shape );
839 }
840
841 if( polyline.closed && pts.size() > 2 )
842 {
843 const PADS_IO::ARC_POINT& pLast = pts.back();
844 const PADS_IO::ARC_POINT& pFirst = pts.front();
845
846 bool needsClosing = ( std::abs( pLast.x - pFirst.x ) > 0.001 || std::abs( pLast.y - pFirst.y ) > 0.001 );
847
848 if( needsClosing )
849 {
850 PCB_SHAPE* shape = new PCB_SHAPE( m_loadBoard );
851
852 if( pFirst.is_arc )
853 {
854 setBoardOutlineArc( shape, pLast, pFirst );
855 }
856 else
857 {
858 shape->SetShape( SHAPE_T::SEGMENT );
859 shape->SetStart( scalePoint( pLast.x, pLast.y ) );
860 shape->SetEnd( scalePoint( pFirst.x, pFirst.y ) );
861 }
862
863 shape->SetWidth( scaleSize( polyline.width ) );
864 shape->SetLayer( Edge_Cuts );
865 m_loadBoard->Add( shape );
866 }
867 }
868 }
869}
870
871
873{
874 for( const PADS_IO::GRAPHIC_LINE& graphic : m_parser->GetGraphicLines() )
875 {
876 PCB_LAYER_ID layer = getMappedLayer( graphic.layer );
877
878 if( layer == UNDEFINED_LAYER )
879 continue;
880
881 const std::vector<PADS_IO::ARC_POINT>& points = graphic.points;
882
883 if( points.size() == 1 && points[0].is_arc && std::abs( points[0].arc.delta_angle - 360.0 ) < 0.1 )
884 {
885 PCB_SHAPE* shape = new PCB_SHAPE( m_loadBoard );
886 VECTOR2I center = scalePoint( points[0].arc.cx, points[0].arc.cy );
887 int radius = std::max( scaleSize( points[0].arc.radius ), m_minObjectSize );
888 shape->SetShape( SHAPE_T::CIRCLE );
889 shape->SetCenter( center );
890 shape->SetEnd( VECTOR2I( center.x + radius, center.y ) );
891 shape->SetWidth( scaleSize( graphic.width ) );
892 shape->SetLayer( layer );
893 m_loadBoard->Add( shape );
894 continue;
895 }
896
897 if( points.size() < 2 )
898 continue;
899
900 for( size_t index = 1; index < points.size(); ++index )
901 {
902 const PADS_IO::ARC_POINT& previous = points[index - 1];
903 const PADS_IO::ARC_POINT& current = points[index];
904
905 if( std::abs( previous.x - current.x ) < 0.001 && std::abs( previous.y - current.y ) < 0.001 )
906 continue;
907
908 PCB_SHAPE* shape = new PCB_SHAPE( m_loadBoard );
909
910 if( current.is_arc )
911 {
912 setBoardOutlineArc( shape, previous, current );
913 }
914 else
915 {
916 shape->SetShape( SHAPE_T::SEGMENT );
917 shape->SetStart( scalePoint( previous.x, previous.y ) );
918 shape->SetEnd( scalePoint( current.x, current.y ) );
919 }
920
921 shape->SetWidth( scaleSize( graphic.width ) );
922 shape->SetLayer( layer );
923 m_loadBoard->Add( shape );
924 }
925 }
926}
927
928
930{
931 const auto& routes = m_parser->GetRoutes();
932 for( const auto& route : routes )
933 {
934 NETINFO_ITEM* net = nullptr;
935
936 if( !route.net_name.empty() )
937 {
938 net = m_loadBoard->FindNet( PADS_COMMON::ConvertInvertedNetName( route.net_name ) );
939
940 if( !net )
941 {
942 if( m_reporter )
943 {
944 m_reporter->Report( wxString::Format( _( "Route net '%s' not found, skipping" ), route.net_name ),
946 }
947
948 continue;
949 }
950 }
951
952 for( const auto& track_def : route.tracks )
953 {
954 if( track_def.points.size() < 2 )
955 continue;
956
957 PCB_LAYER_ID track_layer = getMappedLayer( track_def.layer );
958
959 // An importer is best effort, and a route layer the user mapped to a non-copper
960 // layer is ordinary input, so drop the track rather than the whole board
961 if( !IsCopperLayer( track_layer ) )
962 {
963 if( m_reporter )
964 {
965 m_reporter->Report( wxString::Format( _( "Skipped a route on non-copper or unmapped "
966 "PADS layer %d." ),
967 track_def.layer ),
969 }
970
971 continue;
972 }
973
974 int track_width = scaleSize( track_def.width );
975
976 if( track_width <= 0 )
977 {
978 if( m_reporter )
979 {
980 m_reporter->Report( wxString::Format( _( "Skipped a non-positive-width route on PADS layer %d." ),
981 track_def.layer ),
983 }
984
985 continue;
986 }
987
988 for( size_t i = 0; i < track_def.points.size() - 1; ++i )
989 {
990 const PADS_IO::ARC_POINT& p1 = track_def.points[i];
991 const PADS_IO::ARC_POINT& p2 = track_def.points[i + 1];
992
993 VECTOR2I start = scalePoint( p1.x, p1.y );
994 VECTOR2I end = scalePoint( p2.x, p2.y );
995
996 // Route-cell endpoints retain quantization residue that the PADS writer
997 // collapses when exporting the same route to ASCII.
998 constexpr int MIN_ROUTE_LENGTH = 500;
999 int64_t deltaX = static_cast<int64_t>( end.x ) - start.x;
1000 int64_t deltaY = static_cast<int64_t>( end.y ) - start.y;
1001
1002 if( deltaX * deltaX + deltaY * deltaY < MIN_ROUTE_LENGTH * MIN_ROUTE_LENGTH )
1003 continue;
1004
1005 if( p2.is_arc )
1006 {
1007 VECTOR2I center = scalePoint( p2.arc.cx, p2.arc.cy );
1008
1009 bool clockwise = ( p2.arc.delta_angle < 0 );
1010
1011 SHAPE_ARC shapeArc;
1012 shapeArc.ConstructFromStartEndCenter( start, end, center, clockwise, track_width );
1013
1014 PCB_ARC* arc = new PCB_ARC( m_loadBoard, &shapeArc );
1015
1016 if( net )
1017 arc->SetNet( net );
1018
1019 arc->SetWidth( track_width );
1020 arc->SetLayer( track_layer );
1021 m_loadBoard->Add( arc );
1022 }
1023 else
1024 {
1025 PCB_TRACK* track = new PCB_TRACK( m_loadBoard );
1026
1027 if( net )
1028 track->SetNet( net );
1029
1030 track->SetWidth( track_width );
1031 track->SetLayer( track_layer );
1032 track->SetStart( start );
1033 track->SetEnd( end );
1034 m_loadBoard->Add( track );
1035 }
1036 }
1037 }
1038
1039 for( const auto& via_def : route.vias )
1040 {
1041 VECTOR2I pos = scalePoint( via_def.location.x, via_def.location.y );
1042
1043 std::unique_ptr<PCB_VIA> via = std::make_unique<PCB_VIA>( m_loadBoard );
1044
1045 if( net )
1046 via->SetNet( net );
1047
1048 via->SetPosition( pos );
1049
1050 const double viaDrill = via_def.stack.front().drill;
1051 via->Padstack().SetMode( PADSTACK::MODE::FRONT_INNER_BACK );
1052
1053 for( const PADS_IO::PAD_STACK_LAYER& layer : via_def.stack )
1054 {
1055 if( layer.sizeA <= 0 || !PADS_IO::IsCopperPadRow( layer ) )
1056 continue;
1057
1058 int width = scaleSize( layer.sizeA );
1059
1060 if( layer.layer == -2 )
1061 via->SetWidth( F_Cu, width );
1062 else if( layer.layer == 0 )
1063 via->SetWidth( PADSTACK::INNER_LAYERS, width );
1064 else if( layer.layer == -1 )
1065 via->SetWidth( B_Cu, width );
1066 }
1067
1068 via->SetDrill( scaleSize( viaDrill ) );
1069 PCB_LAYER_ID startLayer = getMappedLayer( via_def.start_layer );
1070 PCB_LAYER_ID endLayer = getMappedLayer( via_def.end_layer );
1071
1072 // A one-layer file defaults every via to the same span, so a whole board must not be
1073 // lost to a via the layer table cannot place
1074 if( !IsCopperLayer( startLayer ) || !IsCopperLayer( endLayer ) || startLayer == endLayer )
1075 {
1076 if( m_reporter )
1077 {
1078 m_reporter->Report( wxString::Format( _( "Skipped a via on net '%s' with an unusable "
1079 "PADS layer span %d,%d." ),
1080 PADS_COMMON::ConvertText( route.net_name ),
1081 via_def.start_layer, via_def.end_layer ),
1083 }
1084
1085 continue;
1086 }
1087
1088 // SetLayerPair sanitizes the span against the current via type and PCB_VIA is
1089 // constructed as THROUGH, so the type has to be set first or the decoded span is
1090 // overwritten with F_Cu/B_Cu and every blind or buried via becomes full stack
1091 if( ( startLayer == F_Cu && endLayer == B_Cu )
1092 || ( startLayer == B_Cu && endLayer == F_Cu ) )
1093 via->SetViaType( VIATYPE::THROUGH );
1094 else if( std::abs( via_def.start_layer - via_def.end_layer ) == 1
1095 && ( startLayer == F_Cu || startLayer == B_Cu || endLayer == F_Cu || endLayer == B_Cu ) )
1096 via->SetViaType( VIATYPE::MICROVIA );
1097 else if( startLayer == F_Cu || startLayer == B_Cu || endLayer == F_Cu || endLayer == B_Cu )
1098 via->SetViaType( VIATYPE::BLIND );
1099 else
1100 via->SetViaType( VIATYPE::BURIED );
1101
1102 via->SetLayerPair( startLayer, endLayer );
1103
1104 m_loadBoard->Add( via.release() );
1105 }
1106 }
1107}
1108
1109
1111{
1112 const auto& copperShapes = m_parser->GetCopperShapes();
1113
1114 for( const PADS_IO::COPPER_SHAPE& copper : copperShapes )
1115 {
1116 if( !copper.filled || copper.is_cutout || copper.outline.size() < 3 )
1117 continue;
1118
1119 PCB_LAYER_ID layer = getMappedLayer( copper.layer );
1120
1121 if( layer == UNDEFINED_LAYER )
1122 {
1123 if( m_reporter )
1124 {
1125 m_reporter->Report( wxString::Format( _( "COPPER item on unmapped layer %d" ), copper.layer ),
1127 }
1128
1129 continue;
1130 }
1131
1132 SHAPE_LINE_CHAIN outline;
1133
1134 for( const PADS_IO::ARC_POINT& pt : copper.outline )
1135 outline.Append( scalePoint( pt.x, pt.y ) );
1136
1137 outline.SetClosed( true );
1138
1139 if( !IsCopperLayer( layer ) )
1140 {
1142 shape->SetLayer( layer );
1143 shape->SetFilled( true );
1144 shape->SetPolyShape( SHAPE_POLY_SET( outline ) );
1145 m_loadBoard->Add( shape );
1146 continue;
1147 }
1148
1149 ZONE* zone = new ZONE( m_loadBoard );
1150 zone->SetLayer( layer );
1151 zone->SetIsRuleArea( false );
1152 zone->Outline()->AddOutline( outline );
1154
1155 m_loadBoard->Add( zone );
1156 }
1157}
1158
1159
1161{
1162 const auto& pours = m_parser->GetPours();
1163 const auto& params = m_parser->GetParameters();
1164
1165 int maxPriority = 0;
1166
1167 for( const auto& pour_def : pours )
1168 {
1169 if( pour_def.priority > maxPriority )
1170 maxPriority = pour_def.priority;
1171 }
1172
1173 for( const auto& pour_def : pours )
1174 {
1175 if( pour_def.points.size() < 3 )
1176 continue;
1177
1178 PCB_LAYER_ID pourLayer = getMappedLayer( pour_def.layer );
1179
1180 if( pourLayer == UNDEFINED_LAYER )
1181 {
1182 if( m_reporter )
1183 {
1184 m_reporter->Report( wxString::Format( _( "Skipping pour on unmapped layer %d" ), pour_def.layer ),
1186 }
1187
1188 continue;
1189 }
1190
1191 if( !IsCopperLayer( pourLayer ) )
1192 {
1193 SHAPE_LINE_CHAIN outline;
1194
1195 for( const auto& point : pour_def.points )
1196 outline.Append( scalePoint( point.x, point.y ) );
1197
1198 outline.SetClosed( true );
1199
1201 shape->SetLayer( pourLayer );
1202 shape->SetFilled( true );
1203 shape->SetPolyShape( SHAPE_POLY_SET( outline ) );
1204 m_loadBoard->Add( shape );
1205 continue;
1206 }
1207
1208 ZONE* zone = new ZONE( m_loadBoard );
1209 zone->SetLayer( pourLayer );
1210
1211 zone->Outline()->NewOutline();
1212
1213 for( const auto& pt : pour_def.points )
1214 {
1215 zone->Outline()->Append( scalePoint( pt.x, pt.y ) );
1216 }
1217
1218 if( zone->GetNumCorners() == 0 )
1219 {
1220 delete zone;
1221 continue;
1222 }
1223
1224 m_converter->ApplyPourSettings( zone, pour_def, maxPriority, params );
1225
1226 m_loadBoard->Add( zone );
1227 }
1228}
1229
1230
1231std::map<wxString, PCB_LAYER_ID>
1232PCB_IO_PADS_BINARY::DefaultLayerMappingCallback( const std::vector<INPUT_LAYER_DESC>& aInputLayerDescriptionVector )
1233{
1234 std::map<wxString, PCB_LAYER_ID> layerMap;
1235
1236 for( const INPUT_LAYER_DESC& layer : aInputLayerDescriptionVector )
1237 layerMap[layer.Name] = layer.AutoMapLayer;
1238
1239 return layerMap;
1240}
1241
1242
1244{
1245 m_loadBoard = nullptr;
1246 m_parser = nullptr;
1247 m_converter.reset();
1248 m_pinToNetMap.clear();
1249 m_partFootprints.clear();
1250}
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:374
Information pertinent to a Pcbnew printed circuit board.
Definition board.h:409
void SetCenter(const VECTOR2I &aCenter)
virtual void SetFilled(bool aFlag)
Definition eda_shape.h:142
void SetVertJustify(GR_TEXT_V_ALIGN_T aType)
Definition eda_text.cpp:373
virtual void SetVisible(bool aVisible)
Definition eda_text.cpp:342
void SetKeepUpright(bool aKeepUpright)
Definition eda_text.cpp:381
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
Definition eda_text.cpp:365
void SetPosition(const VECTOR2I &aPos) override
void SetFPID(const LIB_ID &aFPID)
Definition footprint.h:474
void SetOrientation(const EDA_ANGLE &aNewAngle)
void SetPath(const KIID_PATH &aPath)
Definition footprint.h:497
PCB_FIELD & Value()
read/write accessors:
Definition footprint.h:939
std::deque< PAD * > & Pads()
Definition footprint.h:404
void SetReference(const wxString &aReference)
Definition footprint.h:907
void SetValue(const wxString &aValue)
Definition footprint.h:930
PCB_FIELD & Reference()
Definition footprint.h:940
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from 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:901
VECTOR2I GetPosition() const override
Definition footprint.h:435
REPORTER * m_reporter
Reporter to log errors/warnings to, may be nullptr.
Definition io_base.h:238
PROGRESS_REPORTER * m_progressReporter
Progress reporter to track the progress of the operation, may be nullptr.
Definition io_base.h:241
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:606
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:627
void SetOffset(PCB_LAYER_ID aLayer, const VECTOR2I &aOffset)
Definition pad.cpp:815
void SetSize(PCB_LAYER_ID aLayer, const VECTOR2I &aSize)
Definition pad.cpp:255
void SetRoundRectRadiusRatio(PCB_LAYER_ID aLayer, double aRadiusScale)
Has meaning only for rounded rectangle pads.
Definition pad.cpp:1182
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
Returns board file description for the PCB_IO.
bool CanReadBoard(const wxString &aFileName) const override
Checks if this PCB_IO can read the specified board file.
~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
Checks if this PCB_IO can read the specified board file.
Definition pcb_io.cpp:40
PCB_IO(const wxString &aName)
Definition pcb_io.h:351
void SetWidth(int aWidth) override
void SetShape(SHAPE_T aShape) override
Definition pcb_shape.h:207
void SetEnd(const VECTOR2I &aEnd) override
void SetArcGeometry(const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd)
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 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:102
void SetTextAngle(const EDA_ANGLE &aAngle) override
Definition pcb_text.cpp:569
void SetEnd(const VECTOR2I &aEnd)
Definition pcb_track.h:89
void SetStart(const VECTOR2I &aStart)
Definition pcb_track.h:92
virtual void SetWidth(int aWidth)
Definition pcb_track.h:86
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
virtual void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
Definition zone.cpp:641
SHAPE_POLY_SET * Outline()
Definition zone.h:418
void SetIsRuleArea(bool aEnable)
Definition zone.h:808
static int GetDefaultHatchPitch()
Definition zone.cpp:1617
int GetNumCorners(void) const
Access to m_Poly parameters.
Definition zone.h:610
void SetBorderDisplayStyle(ZONE_BORDER_DISPLAY_STYLE aBorderHatchStyle, int aBorderHatchPitch, bool aRebuilBorderHatch)
Set all hatch parameters for the zone.
Definition zone.cpp:1540
#define _(s)
@ DEGREES_T
Definition eda_angle.h:31
@ 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:703
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:411
@ 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
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:225
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683
@ THERMAL
Use thermal relief for pads.
Definition zones.h:46