111 const std::map<std::string, UTF8>* aProperties,
PROJECT* aProject )
125 parser.
Parse( aFileName );
127 catch(
const std::exception& e )
129 THROW_IO_ERROR( wxString::Format(
"Error parsing PADS binary file: %s", e.what() ) );
182 std::vector<PADS_IO::LAYER_INFO> padsLayerInfos =
m_parser->GetLayerInfos();
190 m_converter->UnitConverter().SetBasicUnitsMode(
true );
201 if( origin.
x == 0.0 && origin.
y == 0.0 )
208 const auto& nets =
m_parser->GetNets();
210 for(
const auto& padsNet : nets )
215 for(
const auto& padsNet : nets )
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();
230 if( netClasses.empty() && diffPairs.empty() )
233 std::shared_ptr<NET_SETTINGS> netSettings =
m_loadBoard->GetDesignSettings().m_NetSettings;
237 if( nc.name.empty() || nc.nets.empty() )
242 if( !netSettings->HasNetclass( className ) )
244 std::shared_ptr<NETCLASS> kicadClass = std::make_shared<NETCLASS>( className );
248 if( nc.hasRuleValues )
250 if( nc.clearance > 0 )
251 kicadClass->SetClearance(
scaleSize( nc.clearance ) );
253 if( nc.trackWidth > 0 )
254 kicadClass->SetTrackWidth(
scaleSize( nc.trackWidth ) );
257 netSettings->SetNetclass( className, kicadClass );
262 for(
const std::string& net : nc.nets )
269 if( dp.name.empty() )
273 std::shared_ptr<NETCLASS> dpNetclass = std::make_shared<NETCLASS>( dpClassName );
276 dpNetclass->SetDiffPairGap(
scaleSize( dp.gap ) );
280 dpNetclass->SetDiffPairWidth(
scaleSize( dp.width ) );
281 dpNetclass->SetTrackWidth(
scaleSize( dp.width ) );
284 netSettings->SetNetclass( dpClassName, dpNetclass );
286 if( !dp.positive_net.empty() )
290 if( !dp.negative_net.empty() )
299 const auto& decals =
m_parser->GetPartDecals();
300 const auto& parts =
m_parser->GetParts();
302 for(
const auto& padsPart : parts )
309 path.push_back( symbolUuid );
312 std::string decalName = padsPart.decal;
316 if( !decalName.empty() )
326 : padsPart.value ) );
336 auto decalIt = decals.find( decalName );
338 if( decalIt == decals.end() )
342 m_reporter->Report( wxString::Format(
_(
"Part '%s': decal '%s' not found, no pads created" ),
343 padsPart.name, decalName ),
348 if( decalIt != decals.end() )
353 for(
size_t termIdx = 0; termIdx < decal.
terminals.size(); ++termIdx )
354 buildPad( footprint, decal, termIdx, partOrient );
361 if( attribute.
name ==
"Ref.Des." )
363 else if( attribute.
name ==
"Part Type" )
364 field = &footprint->
Value();
374 if( attribute.
width > 0 )
391 if( attribute.
hjust ==
"LEFT" )
393 else if( attribute.
hjust ==
"RIGHT" )
398 if( attribute.
vjust ==
"UP" )
400 else if( attribute.
vjust ==
"DOWN" )
408 if( padsPart.bottom_layer )
429 const auto& term = aDecal.
terminals[aTermIdx];
439 int pinNum =
static_cast<int>( aTermIdx + 1 );
440 auto stackIt = aDecal.
pad_stacks.find( pinNum );
445 if( stackIt != aDecal.
pad_stacks.end() && !stackIt->second.empty() )
447 const std::vector<PADS_IO::PAD_STACK_LAYER>& stack = stackIt->second;
450 std::set<int> serializedLayers;
451 bool ambiguousLayers =
false;
455 for(
auto it = std::next( stack.begin() ); it != stack.end(); ++it )
458 ambiguousLayers |= !serializedLayers.insert( it->layer ).second;
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;
468 if( hasExplicitLayers )
471 bool appliedExplicitLayer =
false;
474 if( legacyZeroDefaultSmd )
476 auto inherited = std::find_if( stack.begin(), stack.end(),
479 return aLayer.layer == 0 && aLayer.sizeA > 0;
482 if( inherited != stack.end() )
483 inheritedLegacyShape = &*inherited;
488 if( stackLayer.sizeA <= 0 )
504 if( modernZeroDefaultSmd && stackLayer.layer == 0 )
507 if( legacyZeroDefaultSmd && stackLayer.layer <= 0 )
512 if( modernZeroDefaultSmd && stackLayer.layer == -1 )
517 else if( stackLayer.layer == -2 )
522 else if( stackLayer.layer == -1 )
527 else if( stackLayer.layer == 0 )
533 for(
int layer = 2; layer <
m_parser->GetParameters().layer_count; ++layer )
538 layerSet.
set( inner );
544 int padsLayer = stackLayer.layer;
548 layerSet.
set( kicadLayer );
555 if( modernZeroDefaultSmd )
557 appliedLayer.
sizeA *= 1.5;
558 appliedLayer.
sizeB *= 1.5;
561 else if( inheritedLegacyShape )
563 appliedLayer.
shape = inheritedLegacyShape->
shape;
564 appliedLayer.
sizeA = inheritedLegacyShape->
sizeA * 1.5;
565 appliedLayer.
sizeB = inheritedLegacyShape->
sizeB * 1.5;
569 appliedExplicitLayer =
true;
571 if( zeroDefaultSmd && appliedLayer.
shape ==
"R" )
572 pad->SetRoundRectRadiusRatio( kicadLayer, 0.25 );
576 if( zeroDefaultSmd && !appliedExplicitLayer )
600 if( relativeAngle < 0 )
601 relativeAngle += 360.0;
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 ) );
616 if( hasExplicitLayers )
618 if( !zeroDefaultSmd )
620 if( layerSet.test(
F_Cu ) )
623 if( layerSet.test(
B_Cu ) )
627 pad->SetLayerSet( layerSet );
650 pad->SetNumber( wxString() );
685 auto scaledPadSize = [&](
double aValue )
692 auto applyCornerRadius = [&](
const VECTOR2I& aSize,
bool aDefaultRound )
697 int minimumDimension = std::min( aSize.
x, aSize.
y );
698 double ratio = minimumDimension > 0
699 ? std::min(
static_cast<double>(
radius ) / minimumDimension, 0.5 )
705 else if( aDefaultRound )
714 if( aLayer.
shape ==
"O" || aLayer.
shape ==
"OF" )
717 aPad->
SetSize( aKiCadLayer, ovalSize );
719 else if( aLayer.
shape ==
"RF" )
722 aPad->
SetSize( aKiCadLayer, rectSize );
723 applyCornerRadius( rectSize,
false );
730 aPad->
SetOffset( aKiCadLayer, padOffset );
733 else if( aLayer.
shape ==
"RC" || aLayer.
shape ==
"OC" )
736 aPad->
SetSize( aKiCadLayer, rrSize );
737 applyCornerRadius( rrSize,
true );
741 aPad->
SetSize( aKiCadLayer, size );
743 if( aLayer.
shape ==
"S" || aLayer.
shape ==
"ST" )
744 applyCornerRadius( size,
false );
751 const std::vector<PADS_IO::PART_CLUSTER>& clusters =
m_parser->GetClusters();
753 if( clusters.empty() )
757 std::map<int, PCB_GROUP*> clusterGroups;
764 clusterGroups[cluster.id] =
group;
769 const std::map<size_t, int>& partClusterIds =
m_parser->GetPartClusterIds();
773 auto idIt = partClusterIds.find( i );
775 if( idIt == partClusterIds.end() || idIt->second <= 0 )
778 auto groupIt = clusterGroups.find( idIt->second );
780 if( groupIt != clusterGroups.end() )
795 double midX = aCurr.
arc.
cx + aCurr.
arc.
radius * std::cos( midAngle );
796 double midY = aCurr.
arc.
cy + aCurr.
arc.
radius * std::sin( midAngle );
810 const auto& pts = polyline.points;
815 for(
size_t i = 0; i < pts.size() - 1; ++i )
841 if( polyline.closed && pts.size() > 2 )
846 bool needsClosing = (
std::abs( pLast.
x - pFirst.
x ) > 0.001 ||
std::abs( pLast.
y - pFirst.
y ) > 0.001 );
881 const std::vector<PADS_IO::ARC_POINT>& points = graphic.points;
883 if( points.size() == 1 && points[0].is_arc &&
std::abs( points[0].arc.delta_angle - 360.0 ) < 0.1 )
897 if( points.size() < 2 )
931 const auto& routes =
m_parser->GetRoutes();
932 for(
const auto& route : routes )
936 if( !route.net_name.empty() )
944 m_reporter->Report( wxString::Format(
_(
"Route net '%s' not found, skipping" ), route.net_name ),
952 for(
const auto& track_def : route.tracks )
954 if( track_def.points.size() < 2 )
965 m_reporter->Report( wxString::Format(
_(
"Skipped a route on non-copper or unmapped "
974 int track_width =
scaleSize( track_def.width );
976 if( track_width <= 0 )
980 m_reporter->Report( wxString::Format(
_(
"Skipped a non-positive-width route on PADS layer %d." ),
988 for(
size_t i = 0; i < track_def.points.size() - 1; ++i )
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;
1002 if( deltaX * deltaX + deltaY * deltaY < MIN_ROUTE_LENGTH * MIN_ROUTE_LENGTH )
1039 for(
const auto& via_def : route.vias )
1043 std::unique_ptr<PCB_VIA>
via = std::make_unique<PCB_VIA>(
m_loadBoard );
1048 via->SetPosition( pos );
1050 const double viaDrill = via_def.stack.front().drill;
1060 if( layer.
layer == -2 )
1062 else if( layer.
layer == 0 )
1064 else if( layer.
layer == -1 )
1078 m_reporter->Report( wxString::Format(
_(
"Skipped a via on net '%s' with an unusable "
1079 "PADS layer span %d,%d." ),
1081 via_def.start_layer, via_def.end_layer ),
1091 if( ( startLayer ==
F_Cu && endLayer ==
B_Cu )
1092 || ( startLayer ==
B_Cu && endLayer ==
F_Cu ) )
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 ) )
1097 else if( startLayer ==
F_Cu || startLayer ==
B_Cu || endLayer ==
F_Cu || endLayer ==
B_Cu )
1102 via->SetLayerPair( startLayer, endLayer );
1112 const auto& copperShapes =
m_parser->GetCopperShapes();
1116 if( !copper.filled || copper.is_cutout || copper.outline.size() < 3 )
1125 m_reporter->Report( wxString::Format(
_(
"COPPER item on unmapped layer %d" ), copper.layer ),
1162 const auto& pours =
m_parser->GetPours();
1163 const auto& params =
m_parser->GetParameters();
1165 int maxPriority = 0;
1167 for(
const auto& pour_def : pours )
1169 if( pour_def.priority > maxPriority )
1170 maxPriority = pour_def.priority;
1173 for(
const auto& pour_def : pours )
1175 if( pour_def.points.size() < 3 )
1184 m_reporter->Report( wxString::Format(
_(
"Skipping pour on unmapped layer %d" ), pour_def.layer ),
1195 for(
const auto& point : pour_def.points )
1213 for(
const auto& pt : pour_def.points )
1224 m_converter->ApplyPourSettings( zone, pour_def, maxPriority, params );
1231std::map<wxString, PCB_LAYER_ID>
1234 std::map<wxString, PCB_LAYER_ID> layerMap;
1237 layerMap[layer.Name] = layer.AutoMapLayer;
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
BASE_SET & set(size_t pos)
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.
Information pertinent to a Pcbnew printed circuit board.
void SetCenter(const VECTOR2I &aCenter)
virtual void SetFilled(bool aFlag)
void SetVertJustify(GR_TEXT_V_ALIGN_T aType)
virtual void SetVisible(bool aVisible)
void SetKeepUpright(bool aKeepUpright)
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
REPORTER * m_reporter
Reporter to log errors/warnings to, may be nullptr.
PROGRESS_REPORTER * m_progressReporter
Progress reporter to track the progress of the operation, may be nullptr.
virtual bool CanReadLibrary(const wxString &aFileName) const
Checks if this IO object can read the specified library file/directory.
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.
int SetLibItemName(const UTF8 &aLibItemName)
Override the library item name portion of the LIB_ID to aLibItemName.
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
LSET is a set of PCB_LAYER_IDs.
Handle the data for a net.
@ NORMAL
Shape is the same on all layers.
@ FRONT_INNER_BACK
Up to three shapes can be defined (F_Cu, inner copper layers, B_Cu)
static constexpr PCB_LAYER_ID INNER_LAYERS
! The layer identifier to use for "inner layers" on top/inner/bottom padstacks
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
static LSET PTHMask()
layer set for a through hole pad
void SetShape(PCB_LAYER_ID aLayer, PAD_SHAPE aShape)
Set the new shape of this pad.
static LSET UnplatedHoleMask()
layer set for a mechanical unplated through hole pad
void SetOffset(PCB_LAYER_ID aLayer, const VECTOR2I &aOffset)
void SetSize(PCB_LAYER_ID aLayer, const VECTOR2I &aSize)
void SetRoundRectRadiusRatio(PCB_LAYER_ID aLayer, double aRadiusScale)
Has meaning only for rounded rectangle pads.
A set of BOARD_ITEMs (i.e., without duplicates).
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.
PCB_IO(const wxString &aName)
void SetWidth(int aWidth) override
void SetShape(SHAPE_T aShape) override
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.
void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true) override
void SetPosition(const VECTOR2I &aPos) override
void SetTextAngle(const EDA_ANGLE &aAngle) override
void SetEnd(const VECTOR2I &aEnd)
void SetStart(const VECTOR2I &aStart)
virtual void SetWidth(int aWidth)
Container for project specific data.
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.
virtual void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
SHAPE_POLY_SET * Outline()
void SetIsRuleArea(bool aEnable)
static int GetDefaultHatchPitch()
int GetNumCorners(void) const
Access to m_Poly parameters.
void SetBorderDisplayStyle(ZONE_BORDER_DISPLAY_STYLE aBorderHatchStyle, int aBorderHatchPitch, bool aRebuilBorderHatch)
Set all hatch parameters for the zone.
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.
PCB_LAYER_ID
A quick note on layer IDs:
@ LEFT_RIGHT
Flip left to right (around the Y axis)
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)
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
@ SMD
Smd pad, appears on the solder paste layer (default)
@ PTH
Plated through hole pad.
Class to handle a set of BOARD_ITEMs.
Container that describes file type info.
wxString m_Description
Description shown in the file picker dialog.
std::vector< std::string > m_FileExtensions
Filter used for file pickers if m_IsFile is true.
A polyline point that may instead be an arc segment.
ARC arc
Only valid when is_arc is true.
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).
std::string shape
R, S, A, O, OF, RF, RT, ST, RA, SA, RC, OC.
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.
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.
VECTOR2< int32_t > VECTOR2I
@ THERMAL
Use thermal relief for pads.