57#include <wx/numformatter.h>
62#include <wx/xml/xml.h>
83 static_cast<int>( aDrill.end ), aDrill.size.x, aDrill.size.y,
84 static_cast<int>( aDrill.shape ), aDrill.is_capped.has_value(),
85 aDrill.is_capped.value_or(
false ), aDrill.is_filled.has_value(),
86 aDrill.is_filled.value_or(
false ) );
94 aPost.size, aPost.depth, aPost.angle );
198 std::vector<FOOTPRINT*> retval;
201 retval.push_back(
static_cast<FOOTPRINT*
>( fp->Clone() ) );
211 if( aParent->GetChildren() )
212 aNode->SetNext( aParent->GetChildren() );
214 aNode->SetNext(
nullptr );
216 aParent->SetChildren( aNode );
217 aNode->SetParent( aParent );
228 aNode->SetNext( aPrev->GetNext() );
229 aPrev->SetNext( aNode );
230 aNode->SetParent( aPrev->GetParent() );
251 check = check->GetParent();
255 if( aNode->GetParent() )
256 aNode->GetParent()->RemoveChild( aNode );
267 wxXmlNode* node =
new wxXmlNode( wxXML_ELEMENT_NODE, aName );
282 aNode->SetParent( aParent );
287 aParent->AddChild( aNode );
299 wxXmlNode* node =
new wxXmlNode( wxXML_ELEMENT_NODE, aName );
313 str.Replace( wxT(
":" ), wxT(
"_" ) );
317 for( wxString::const_iterator iter = aStr.begin(); iter != aStr.end(); ++iter )
334 wxString key = aPrefix ? wxString( aPrefix ) + wxT(
":" ) + aStr : aStr;
344 wxString
name = base;
348 name = wxString::Format(
"%s_%d", base, suffix++ );
379 if( aSublayerId > 0 )
380 name += wxString::Format(
"_%d", aSublayerId );
387 const char* aPrefix )
const
389 return genString( wxString::Format( wxS(
"%s_%s" ),
391 m_board->GetLayerName( aBottom ) ), aPrefix );
402 if(
name.empty() && fp )
406 if( fp->
Pads()[ii] == aPad )
414 name = wxString::Format(
"NPTH%zu", ii );
415 else if(
name.empty() )
416 name = wxString::Format(
"PAD%zu", ii );
427 [&](
const wxString& aName )
462 wxString baseName =
genString( ref,
"CMP" );
463 wxString
name = baseName;
466 while( !tryInsert(
name ) )
467 name = wxString::Format(
"%s_%d", baseName, suffix++ );
477 wxString str = wxString::FromCDouble( aVal, aSigFig == -1 ?
m_sigfig : aSigFig );
480 while( str.EndsWith( wxT(
"00" ) ) )
484 if( str == wxT(
"-0.0" ) )
509 aNode->AddAttribute( aName, aValue );
515 wxXmlNode* xmlHeaderNode =
new wxXmlNode(wxXML_ELEMENT_NODE,
"IPC-2581");
518 addAttribute( xmlHeaderNode,
"xmlns",
"http://webstds.ipc.org/2581");
519 addAttribute( xmlHeaderNode,
"xmlns:xsi",
"http://www.w3.org/2001/XMLSchema-instance");
520 addAttribute( xmlHeaderNode,
"xmlns:xsd",
"http://www.w3.org/2001/XMLSchema");
525 "http://webstds.ipc.org/2581 http://webstds.ipc.org/2581/IPC-2581B1.xsd" );
530 "http://webstds.ipc.org/2581 http://webstds.ipc.org/2581/IPC-2581C.xsd" );
535 return xmlHeaderNode;
547 wxXmlNode* node =
appendNode( contentNode,
"FunctionMode" );
561 wxFileName fn(
m_board->GetFileName() );
567 :
new wxXmlNode( wxXML_ELEMENT_NODE,
"DictionaryColor" );
571 contentNode->AddChild( color_node );
575 wxXmlNode* fillNode =
appendNode( contentNode,
"DictionaryFillDesc" );
595 contentNode->AddChild( color_node );
604 wxXmlNode* location_node =
appendNode( aNode,
"Location" );
621 if( offset.
x != 0 || offset.
y != 0 )
689 wxXmlNode* color_node =
new wxXmlNode( wxXML_ELEMENT_NODE,
"DictionaryColor" );
693 for(
int sub_idx = 0; sub_idx < item->GetSublayersCount(); sub_idx++ )
703 wxXmlNode* entry_color =
appendNode( color_node,
"EntryColor" );
705 wxXmlNode* color =
appendNode( entry_color,
"Color" );
707 wxString colorName = item->GetColor( sub_idx );
709 if( colorName.StartsWith( wxT(
"#" ) ) )
712 COLOR4D layer_color( colorName );
724 if( fab_color.GetName() == colorName )
726 addAttribute( color,
"r", wxString::Format(
"%d",
KiROUND( fab_color.GetColor( item->GetType() ).r * 255 ) ) );
727 addAttribute( color,
"g", wxString::Format(
"%d",
KiROUND( fab_color.GetColor( item->GetType() ).g * 255 ) ) );
728 addAttribute( color,
"b", wxString::Format(
"%d",
KiROUND( fab_color.GetColor( item->GetType() ).b * 255 ) ) );
751 return it->second + aSuffix;
755 return genString( aNetname + aSuffix,
"NET" );
776 if( !aMessage.IsEmpty() )
800 return section &&
included( *section );
811 std::function<void( wxXmlNode* )> visit =
812 [&]( wxXmlNode* aNode )
814 for( wxXmlNode* child = aNode->GetChildren(); child; child = child->GetNext() )
816 const wxString&
name = child->GetName();
818 if(
name ==
"Layer" )
821 child->GetAttribute(
"layerFunction" ),
822 child->GetAttribute(
"side" ) );
825 sections.
Set( *section );
827 else if(
name ==
"Bom" )
829 else if(
name ==
"PadStackDef" )
831 else if(
name ==
"Package" )
833 else if(
name ==
"Component" )
835 else if(
name ==
"Stackup" )
837 else if(
name ==
"Profile" )
839 else if(
name ==
"LogicalNet" )
841 else if(
name ==
"PhyNetGroup" )
843 else if(
name ==
"Dfx" )
865 wxXmlNode*
next = child->GetNext();
867 if( child->GetName() ==
"StepRef" )
880 wxXmlNode* insertBefore =
nullptr;
882 for( wxXmlNode* child =
m_contentNode->GetChildren(); child; child = child->GetNext() )
884 if( child->GetName().StartsWith(
"Dictionary" ) )
886 insertBefore = child;
891 for( wxXmlNode* layer = aCadDataNode->GetChildren(); layer; layer = layer->GetNext() )
893 if( layer->GetName() !=
"Layer" )
896 wxXmlNode* ref =
new wxXmlNode( wxXML_ELEMENT_NODE,
"LayerRef" );
897 addAttribute( ref,
"name", layer->GetAttribute(
"name" ) );
915 wxXmlNode* fillDesc_node =
appendNode( aNode,
"FillDesc" );
921 wxXmlNode* fillDesc_node =
appendNode( aNode,
"FillDesc" );
922 addAttribute( fillDesc_node,
"fillProperty",
"HOLLOW" );
929 wxCHECK_RET( aNode,
"aNode is null" );
934 wxXmlNode* entry_node =
nullptr;
938 size_t hash =
lineHash( aWidth, aDashType );
939 wxString
name = wxString::Format(
"LINE_%zu",
m_line_dict.size() + 1 );
943 wxXmlNode* lineDesc_node =
appendNode( aNode,
"LineDescRef" );
958 wxXmlNode* line_node =
appendNode( entry_node,
"LineDesc" );
991 if( outlineCount == 0 )
998 if( outlineCount == 1 )
1004 wxXmlNode* special_node =
appendNode( aContentNode,
"UserSpecial" );
1006 for(
int ii = 0; ii < outlineCount; ++ii )
1022 wxXmlNode* text_node =
appendNode( aContentNode,
"UserSpecial" );
1024 std::list<VECTOR2I> pts;
1029 if( pts.size() < 2 )
1032 wxXmlNode* line_node =
nullptr;
1036 if( pts.size() < 3 )
1039 addXY( line_node, pts.front(),
"startX",
"startY" );
1040 addXY( line_node, pts.back(),
"endX",
"endY" );
1044 line_node =
appendNode( text_node,
"Polyline" );
1045 wxXmlNode* point_node =
appendNode( line_node,
"PolyBegin" );
1046 addXY( point_node, pts.front() );
1048 auto iter = pts.begin();
1050 for( ++iter; iter != pts.end(); ++iter )
1052 wxXmlNode* step_node =
appendNode( line_node,
"PolyStepSegment" );
1053 addXY( step_node, *iter );
1068 if( aPt1 == pts.back() )
1069 pts.push_back( aPt2 );
1070 else if( aPt2 == pts.front() )
1071 pts.push_front( aPt1 );
1072 else if( aPt1 == pts.front() )
1073 pts.push_front( aPt2 );
1074 else if( aPt2 == pts.back() )
1075 pts.push_back( aPt1 );
1079 pts.push_back( aPt1 );
1080 pts.push_back( aPt2 );
1085 pts.push_back( aPt1 );
1086 pts.push_back( aPt2 );
1092 if( aPoly.PointCount() < 3 )
1095 wxXmlNode* outline_node =
appendNode( text_node,
"Outline" );
1096 wxXmlNode* poly_node =
appendNode( outline_node,
"Polygon" );
1099 const std::vector<VECTOR2I>& polyPts = aPoly.CPoints();
1100 wxXmlNode* point_node =
appendNode( poly_node,
"PolyBegin" );
1101 addXY( point_node, polyPts.front() );
1103 for(
size_t ii = 1; ii < polyPts.size(); ++ii )
1105 wxXmlNode* poly_step_node =
1107 addXY( poly_step_node, polyPts[ii] );
1110 point_node =
appendNode( poly_node,
"PolyStepSegment" );
1111 addXY( point_node, polyPts.front() );
1121 if( text_node->GetChildren() ==
nullptr )
1123 aContentNode->RemoveChild( text_node );
1131 int maxError =
m_board->GetDesignSettings().m_MaxError;
1156 wxXmlNode* shape_node =
appendNode( aContentNode,
"StandardPrimitiveRef" );
1171 int diameter = aPad.
GetSize( aLayer ).
x + 2 * margin.
x;
1173 wxXmlNode* circle_node =
appendNode( entry_node,
"Circle" );
1193 wxXmlNode* rect_node =
appendNode( entry_node,
"RectRound" );
1204 wxXmlNode* rect_node =
appendNode( entry_node,
"RectCenter" );
1222 wxXmlNode* oval_node =
appendNode( entry_node,
"Oval" );
1245 if( margin.
x == margin.
y )
1255 wxXmlNode* roundrect_node =
appendNode( entry_node,
"RectRound" );
1275 if( margin.
x <= 0 || margin.
x != margin.
y )
1282 wxXmlNode* chamfered_node =
appendNode( entry_node,
"RectCham" );
1286 int shorterSide = std::min( pad_size.
x, pad_size.
y );
1334 int dx = pad_size.
x / 2;
1335 int dy = pad_size.
y / 2;
1336 int ddx = trap_delta.
x / 2;
1337 int ddy = trap_delta.
y / 2;
1339 outline.
Append( -dx - ddy, dy + ddx );
1340 outline.
Append( dx + ddy, dy - ddx );
1341 outline.
Append( dx - ddy, -dy + ddx );
1342 outline.
Append( -dx + ddy, -dy - ddx );
1382 wxXmlNode* shape_node =
appendNode( aContentNode,
"StandardPrimitiveRef" );
1397 wxXmlNode* shape_node =
appendNode( aContentNode,
"UserPrimitiveRef" );
1414 wxXmlNode* polyline_node =
appendNode( aContentNode,
"Polyline" );
1422 wxXmlNode* begin_node =
appendNode( polyline_node,
"PolyBegin" );
1423 addXY( begin_node, start );
1426 wxXmlNode* arc1_node =
appendNode( polyline_node,
"PolyStepCurve" );
1427 addXY( arc1_node, mid );
1432 wxXmlNode* arc2_node =
appendNode( polyline_node,
"PolyStepCurve" );
1433 addXY( arc2_node, start );
1444 int diameter = aShape.
GetRadius() * 2.0;
1451 wxXmlNode* special_node =
appendNode( entry_node,
"UserSpecial" );
1453 wxXmlNode* circle_node =
appendNode( special_node,
"Circle" );
1479 wxXmlNode* polyline_node =
appendNode( aContentNode,
"Polyline" );
1484 wxXmlNode* begin_node =
appendNode( polyline_node,
"PolyBegin" );
1485 addXY( begin_node, corners[0] );
1487 for(
size_t i = 1; i < corners.size(); ++i )
1489 wxXmlNode* step_node =
appendNode( polyline_node,
"PolyStepSegment" );
1490 addXY( step_node, corners[i] );
1494 wxXmlNode* close_node =
appendNode( polyline_node,
"PolyStepSegment" );
1495 addXY( close_node, corners[0] );
1497 addLineDesc( polyline_node, stroke_width, dash,
true );
1507 wxXmlNode* special_node =
appendNode( entry_node,
"UserSpecial" );
1514 wxXmlNode* rect_node =
appendNode( special_node,
"RectRound" );
1521 wxString cornerFlag = corner_radius > 0 ?
"true" :
"false";
1529 width += stroke_width;
1530 height += stroke_width;
1558 wxXmlNode* polyline_node =
appendNode( aContentNode,
"Polyline" );
1559 const std::vector<VECTOR2I>& pts = outline.
CPoints();
1561 wxXmlNode* begin_node =
appendNode( polyline_node,
"PolyBegin" );
1562 addXY( begin_node, pts[0] );
1564 for(
size_t jj = 1; jj < pts.size(); ++jj )
1566 wxXmlNode* step_node =
appendNode( polyline_node,
"PolyStepSegment" );
1567 addXY( step_node, pts[jj] );
1571 if( pts.size() > 2 && pts.front() != pts.back() )
1573 wxXmlNode* close_node =
appendNode( polyline_node,
"PolyStepSegment" );
1574 addXY( close_node, pts[0] );
1577 addLineDesc( polyline_node, stroke_width, dash,
true );
1591 wxXmlNode* special_node =
appendNode( entry_node,
"UserSpecial" );
1613 wxXmlNode* arc_node =
appendNode( aContentNode,
"Arc" );
1615 addXY( arc_node, aShape.
GetEnd(),
"endX",
"endY" );
1628 wxXmlNode* polyline_node =
appendNode( aContentNode,
"Polyline" );
1632 std::vector<VECTOR2I> points;
1635 wxXmlNode* point_node =
appendNode( polyline_node,
"PolyBegin" );
1636 addXY( point_node, points[0] );
1638 for(
size_t i = 1; i < points.size(); i++ )
1640 wxXmlNode* seg_node =
appendNode( polyline_node,
"PolyStepSegment" );
1641 addXY( seg_node, points[i] );
1651 wxXmlNode* line_node =
appendNode( aContentNode,
"Line" );
1653 addXY( line_node, aShape.
GetEnd(),
"endX",
"endY" );
1679 if(
chain.PointCount() < 2 )
1682 wxXmlNode* polyline_node =
appendNode( aContentNode,
"Polyline" );
1683 const std::vector<VECTOR2I>& pts =
chain.CPoints();
1685 wxXmlNode* begin_node =
appendNode( polyline_node,
"PolyBegin" );
1686 addXY( begin_node, pts[0] );
1688 for(
size_t jj = 1; jj < pts.size(); ++jj )
1690 wxXmlNode* step_node =
appendNode( polyline_node,
"PolyStepSegment" );
1691 addXY( step_node, pts[jj] );
1695 if( !isArc && pts.size() > 2 && pts.front() != pts.back() )
1697 wxXmlNode* close_node =
appendNode( polyline_node,
"PolyStepSegment" );
1698 addXY( close_node, pts[0] );
1701 addLineDesc( polyline_node, stroke_width, dash,
true );
1711 wxXmlNode* special_node =
appendNode( entry_node,
"UserSpecial" );
1735 if( !aInline && !
name.empty() )
1737 wxXmlNode* shape_node =
appendNode( aContentNode,
"UserPrimitiveRef" );
1746 wxXmlNode* slotNode =
appendNode( aNode,
"SlotCavity" );
1766 if( drill_size.
y > drill_size.
x )
1768 std::swap( drill_size.
x, drill_size.
y );
1769 rotation = ( rotation +
ANGLE_90 ).Normalize();
1775 wxXmlNode* xformNode =
appendNode( slotNode,
"Xform" );
1780 wxXmlNode* ovalNode =
appendNode( slotNode,
"Oval" );
1788 int maxError =
m_board->GetDesignSettings().m_MaxError;
1800 wxXmlNode* roleNode =
appendNode( logisticNode,
"Role" );
1808 wxXmlNode* personNode =
appendNode( logisticNode,
"Person" );
1810 addAttribute( personNode,
"enterpriseRef",
"UNKNOWN" );
1813 return logisticNode;
1823 addAttribute( historyNode,
"origination", wxDateTime::Now().FormatISOCombined() );
1825 addAttribute( historyNode,
"lastChange", wxDateTime::Now().FormatISOCombined() );
1827 wxXmlNode* fileRevisionNode =
appendNode( historyNode,
"FileRevision" );
1828 addAttribute( fileRevisionNode,
"fileRevisionId",
"1" );
1829 addAttribute( fileRevisionNode,
"comment",
"NO COMMENT" );
1832 wxXmlNode* softwarePackageNode =
appendNode( fileRevisionNode,
"SoftwarePackage" );
1835 addAttribute( softwarePackageNode,
"vendor",
"KiCad EDA" );
1837 wxXmlNode* certificationNode =
appendNode( softwarePackageNode,
"Certification" );
1838 addAttribute( certificationNode,
"certificationStatus",
"SELFTEST" );
1863 m_refdes =
new std::vector<REFDES>();
1864 m_props =
new std::map<wxString, wxString>();
1875 wxString m_OEMDesignRef;
1879 wxString m_description;
1881 std::vector<REFDES>* m_refdes;
1882 std::map<wxString, wxString>*
m_props;
1885 std::set<std::unique_ptr<struct BOM_ENTRY>,
1886 std::function<bool(
const std::unique_ptr<struct BOM_ENTRY>&,
1887 const std::unique_ptr<struct BOM_ENTRY>& )>> bom_entries(
1888 [](
const std::unique_ptr<struct BOM_ENTRY>& a,
1889 const std::unique_ptr<struct BOM_ENTRY>& b )
1891 return a->m_OEMDesignRef < b->m_OEMDesignRef;
1896 std::unique_ptr<FOOTPRINT> fp(
static_cast<FOOTPRINT*
>( fp_it->Clone() ) );
1897 fp->SetParentGroup(
nullptr );
1898 fp->SetPosition( {0, 0} );
1899 fp->SetOrientation(
ANGLE_0 );
1902 if( fp->IsFlipped() )
1910 Report( wxString::Format(
_(
"Footprint %s not found in dictionary; BOM data may be incomplete." ),
1911 fp->GetFPID().GetLibItemName().wx_str() ),
1916 auto entry = std::make_unique<struct BOM_ENTRY>();
1922 entry->m_OEMDesignRef = it->second;
1926 Report( wxString::Format(
_(
"Component \"%s\" missing OEM reference; BOM entry will be skipped." ),
1927 fp->GetFPID().GetLibItemName().wx_str() ),
1931 entry->m_OEMDesignRef =
genString( entry->m_OEMDesignRef,
"REF" );
1933 entry->m_pads = fp->GetPadCount();
1937 const wxString variantName =
m_board ?
m_board->GetCurrentVariant() : wxString();
1939 if( entry->m_pads == 0 || fp_it->GetExcludedFromBOMForVariant( variantName ) )
1940 entry->m_type =
"DOCUMENT";
1942 entry->m_type =
"ELECTRICAL";
1950 auto[ bom_iter, inserted ] = bom_entries.insert( std::move( entry ) );
1953 ( *bom_iter )->m_count++;
1957 refdes.m_pkg = iter->second;
1958 refdes.m_populate = !fp->GetDNPForVariant( variantName )
1959 && !fp->GetExcludedFromBOMForVariant( variantName );
1962 ( *bom_iter )->m_refdes->push_back( refdes );
1966 for(
PCB_FIELD* prop : fp->GetFields() )
1971 if( prop->IsMandatory() && !prop->IsValue() )
1974 ( *bom_iter )->m_props->emplace( prop->GetName(), prop->GetShownText(
RESOLVED ) );
1978 if( bom_entries.empty() )
1981 wxFileName fn(
m_board->GetFileName() );
1983 wxXmlNode* bomNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"Bom" );
1984 m_xml_root->InsertChild( bomNode, aEcadNode );
1987 wxXmlNode* bomHeaderNode =
appendNode( bomNode,
"BomHeader" );
1990 if( bomRevision.IsEmpty() )
1991 bomRevision =
m_board->GetTitleBlock().GetRevision();
1993 if( bomRevision.IsEmpty() )
1994 bomRevision = wxS(
"1.0" );
1996 addAttribute( bomHeaderNode,
"revision", bomRevision );
2001 wxXmlNode* stepRefNode =
appendNode( bomHeaderNode,
"StepRef" );
2005 for(
const auto& entry : bom_entries )
2007 wxXmlNode* bomEntryNode =
appendNode( bomNode,
"BomItem" );
2008 addAttribute( bomEntryNode,
"OEMDesignNumberRef", entry->m_OEMDesignRef );
2009 addAttribute( bomEntryNode,
"quantity", wxString::Format(
"%d", entry->m_count ) );
2010 addAttribute( bomEntryNode,
"pinCount", wxString::Format(
"%d", entry->m_pads ) );
2011 addAttribute( bomEntryNode,
"category", entry->m_type );
2013 if( !entry->m_description.IsEmpty() )
2014 addAttribute( bomEntryNode,
"description", entry->m_description );
2016 for(
const REFDES& refdes : *( entry->m_refdes ) )
2021 wxXmlNode* refdesNode =
appendNode( bomEntryNode,
"RefDes" );
2024 addAttribute( refdesNode,
"packageRef", refdes.m_pkg );
2025 addAttribute( refdesNode,
"populate", refdes.m_populate ?
"true" :
"false" );
2027 addAttribute( refdesNode,
"layerRef", refdes.m_layer );
2030 wxXmlNode* characteristicsNode =
appendNode( bomEntryNode,
"Characteristics" );
2031 addAttribute( characteristicsNode,
"category", entry->m_type );
2033 for(
const auto& prop : *( entry->m_props ) )
2035 wxXmlNode* textualDefNode =
appendNode( characteristicsNode,
"Textual" );
2036 addAttribute( textualDefNode,
"definitionSource",
"KICAD" );
2037 addAttribute( textualDefNode,
"textualCharacteristicName", prop.first );
2038 addAttribute( textualDefNode,
"textualCharacteristicValue", prop.second );
2055 wxXmlNode* cadDataNode =
appendNode( ecadNode,
"CadData" );
2072 bool haveLayer =
false;
2074 for( wxXmlNode* child = cadDataNode->GetChildren(); child; child = child->GetNext() )
2076 if( child->GetName() ==
"Layer" )
2104 std::vector<BOARD_STACKUP_ITEM*> layers = stackup.
GetList();
2105 std::set<PCB_LAYER_ID> added_layers;
2107 for(
int i = 0; i < stackup.
GetCount(); i++ )
2111 for(
int sublayer_id = 0; sublayer_id < stackup_item->
GetSublayersCount(); sublayer_id++ )
2113 wxString ly_name =
stackupLayerName( stackup_item, sublayer_id,
"SPEC_LAYER" );
2115 wxXmlNode* specNode =
appendNode( aCadLayerNode,
"Spec" );
2117 wxXmlNode* generalNode =
appendNode( specNode,
"General" );
2119 wxXmlNode* propertyNode =
appendNode( generalNode,
"Property" );
2121 switch ( stackup_item->
GetType() )
2126 wxXmlNode* conductorNode =
appendNode( specNode,
"Conductor" );
2128 propertyNode =
appendNode( conductorNode,
"Property" );
2129 addAttribute( propertyNode,
"unit", wxT(
"SIEMENS/M" ) );
2130 addAttribute( propertyNode,
"value", wxT(
"5.959E7" ) );
2136 propertyNode =
appendNode( generalNode,
"Property" );
2137 addAttribute( propertyNode,
"text", wxString::Format(
"Type : %s",
2139 wxXmlNode* dielectricNode =
appendNode( specNode,
"Dielectric" );
2140 addAttribute( dielectricNode,
"type",
"DIELECTRIC_CONSTANT" );
2141 propertyNode =
appendNode( dielectricNode,
"Property" );
2144 dielectricNode =
appendNode( specNode,
"Dielectric" );
2145 addAttribute( dielectricNode,
"type",
"LOSS_TANGENT" );
2146 propertyNode =
appendNode( dielectricNode,
"Property" );
2153 propertyNode =
appendNode( generalNode,
"Property" );
2154 addAttribute( propertyNode,
"text", wxString::Format(
"Color : %s",
2156 propertyNode =
appendNode( generalNode,
"Property" );
2157 addAttribute( propertyNode,
"text", wxString::Format(
"Type : %s",
2163 propertyNode =
appendNode( generalNode,
"Property" );
2164 addAttribute( propertyNode,
"text", wxString::Format(
"Color : %s",
2166 propertyNode =
appendNode( generalNode,
"Property" );
2167 addAttribute( propertyNode,
"text", wxString::Format(
"Type : %s",
2171 if( stackup_item->
GetEpsilonR( sublayer_id ) > 1.0 )
2173 wxXmlNode* dielectricNode =
appendNode( specNode,
"Dielectric" );
2174 addAttribute( dielectricNode,
"type",
"DIELECTRIC_CONSTANT" );
2175 propertyNode =
appendNode( dielectricNode,
"Property" );
2182 wxXmlNode* dielectricNode =
appendNode( specNode,
"Dielectric" );
2183 addAttribute( dielectricNode,
"type",
"LOSS_TANGENT" );
2184 propertyNode =
appendNode( dielectricNode,
"Property" );
2202 wxXmlNode* specNode =
appendNode( aCadLayerNode,
"Spec" );
2205 wxXmlNode* surfaceFinishNode =
appendNode( specNode,
"SurfaceFinish" );
2217 wxXmlNode* cadHeaderNode =
appendNode( aEcadNode,
"CadHeader" );
2262 addAttribute( aNode,
"layerFunction",
"BOARD_OUTLINE" );
2303 aLayer ==
F_Cu ?
"TOP"
2304 : aLayer ==
B_Cu ?
"BOTTOM"
2325 wxXmlNode* stackupNode =
appendNode( aCadLayerNode,
"Stackup" );
2326 addAttribute( stackupNode,
"name",
"Primary_Stackup" );
2333 addAttribute( stackupNode,
"stackupStatus",
"PROPOSED" );
2335 wxXmlNode* stackupGroup =
appendNode( stackupNode,
"StackupGroup" );
2336 addAttribute( stackupGroup,
"name",
"Primary_Stackup_Group" );
2341 std::vector<BOARD_STACKUP_ITEM*> layers = stackup.
GetList();
2342 std::set<PCB_LAYER_ID> added_layers;
2345 for(
int i = 0; i < stackup.
GetCount(); i++ )
2349 for(
int sublayer_id = 0; sublayer_id < stackup_item->
GetSublayersCount(); sublayer_id++ )
2354 if( hasCoating && layer_id ==
F_Cu && sublayer_id == 0 )
2356 wxXmlNode* coatingLayer =
appendNode( stackupGroup,
"StackupLayer" );
2357 addAttribute( coatingLayer,
"layerOrGroupRef",
"COATING_TOP" );
2361 addAttribute( coatingLayer,
"sequence", wxString::Format(
"%d", sequence++ ) );
2363 wxXmlNode* specRefNode =
appendNode( coatingLayer,
"SpecRef" );
2374 wxXmlNode* stackupLayer =
appendNode( stackupGroup,
"StackupLayer" );
2375 wxString spec_name =
stackupLayerName( stackup_item, sublayer_id,
"SPEC_LAYER" );
2378 addAttribute( stackupLayer,
"layerOrGroupRef", ly_name );
2382 addAttribute( stackupLayer,
"sequence", wxString::Format(
"%d", sequence++ ) );
2384 wxXmlNode* specLayerNode =
appendNode( stackupLayer,
"SpecRef" );
2390 wxXmlNode* coatingLayer =
appendNode( stackupGroup,
"StackupLayer" );
2391 addAttribute( coatingLayer,
"layerOrGroupRef",
"COATING_BOTTOM" );
2395 addAttribute( coatingLayer,
"sequence", wxString::Format(
"%d", sequence++ ) );
2397 wxXmlNode* specRefNode =
appendNode( coatingLayer,
"SpecRef" );
2412 std::vector<BOARD_STACKUP_ITEM*> layers = stackup.
GetList();
2413 std::set<PCB_LAYER_ID> added_layers;
2415 for(
int i = 0; i < stackup.
GetCount(); i++ )
2419 for(
int sublayer_id = 0; sublayer_id < stackup_item->
GetSublayersCount(); sublayer_id++ )
2432 wxXmlNode* cadLayerNode =
appendNode( aCadLayerNode,
"Layer" );
2439 addAttribute( cadLayerNode,
"layerFunction",
"DIELCORE" );
2441 addAttribute( cadLayerNode,
"layerFunction",
"DIELPREG" );
2456 LSEQ layer_seq =
m_board->GetEnabledLayers().Seq();
2468 added_layers.insert( layer );
2469 wxXmlNode* cadLayerNode =
appendNode( aCadLayerNode,
"Layer" );
2482 wxXmlNode* topCoatingNode =
appendNode( aCadLayerNode,
"Layer" );
2484 addAttribute( topCoatingNode,
"layerFunction",
"COATINGCOND" );
2486 addAttribute( topCoatingNode,
"polarity",
"POSITIVE" );
2488 wxXmlNode* botCoatingNode =
appendNode( aCadLayerNode,
"Layer" );
2489 addAttribute( botCoatingNode,
"name",
"COATING_BOTTOM" );
2490 addAttribute( botCoatingNode,
"layerFunction",
"COATINGCOND" );
2492 addAttribute( botCoatingNode,
"polarity",
"POSITIVE" );
2511 for(
PAD*
pad : fp->Pads() )
2517 else if(
pad->HasHole() )
2524 wxXmlNode* drillNode =
appendNode( aCadLayerNode,
"Layer" );
2525 drillNode->AddAttribute(
"name",
genLayersString( layers.first, layers.second,
"DRILL" ) );
2530 wxXmlNode* spanNode =
appendNode( drillNode,
"Span" );
2537 wxXmlNode* drillNode =
appendNode( aCadLayerNode,
"Layer" );
2538 drillNode->AddAttribute(
"name",
genLayersString( layers.first, layers.second,
"SLOT" ) );
2544 wxXmlNode* spanNode =
appendNode( drillNode,
"Span" );
2560 std::vector<std::tuple<auxLayerType, PCB_LAYER_ID, PCB_LAYER_ID>> new_layers;
2562 if(
via->Padstack().IsFilled().value_or(
false ) )
2565 if(
via->Padstack().IsCapped().value_or(
false ) )
2570 if(
via->Padstack().IsPlugged( layer ).value_or(
false ) )
2573 if(
via->Padstack().IsCovered( layer ).value_or(
false ) )
2576 if(
via->Padstack().IsTented( layer ).value_or(
false ) )
2580 for(
auto& tuple : new_layers )
2586 bool add_node =
true;
2589 wxString layerFunction;
2592 switch( std::get<0>(layers) )
2596 layerFunction =
"COATINGNONCOND";
2600 layerFunction =
"HOLEFILL";
2604 layerFunction =
"COATINGNONCOND";
2608 layerFunction =
"HOLEFILL";
2612 layerFunction =
"COATINGCOND";
2620 if( add_node && !vec.empty() )
2622 wxXmlNode* node =
appendNode( aCadLayerNode,
"Layer" );
2636 const bool first_external = std::get<1>( layers ) ==
F_Cu || std::get<1>( layers ) ==
B_Cu;
2637 const bool second_external = std::get<2>( layers ) ==
F_Cu || std::get<2>( layers ) ==
B_Cu;
2639 if( first_external )
2641 if( second_external )
2648 if( second_external )
2654 wxXmlNode* spanNode =
appendNode( node,
"Span" );
2665 wxXmlNode* stepNode =
appendNode( aCadNode,
"Step" );
2667 wxFileName fn(
m_board->GetFileName() );
2673 wxXmlNode* datumNode =
appendNode( stepNode,
"Datum" );
2689 wxString::Format(
"%zu",
m_board->Footprints().size() ) );
2706 wxXmlNode* padNode =
appendNode( aContentNode,
"Pad" );
2713 wxXmlNode* xformNode =
appendNode( padNode,
"Xform" );
2720 addShape( padNode, *aPad, aLayer );
2724 wxXmlNode* pinRefNode =
appendNode( padNode,
"PinRef" );
2738 wxXmlNode* padNode =
appendNode( aContentNode,
"Pad" );
2760 addAttribute( aPadNode,
"padstackDefRef", th_pair->second );
2767 wxXmlNode* padStackDefNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"PadStackDef" );
2792 wxXmlNode* padStackHoleNode =
appendNode( padStackDefNode,
"PadstackHoleDef" );
2793 padStackHoleNode->AddAttribute(
"name",
2794 wxString::Format(
"%s%d_%d",
2816 wxXmlNode* padStackPadDefNode =
appendNode( padStackDefNode,
"PadstackPadDef" );
2818 addAttribute( padStackPadDefNode,
"padUse",
"REGULAR" );
2826 addShape( padStackPadDefNode, shape );
2830 addShape( padStackPadDefNode, *aPad, layer );
2843 addAttribute( aContentNode,
"padstackDefRef", via_pair->second );
2850 wxXmlNode* padStackDefNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"PadStackDef" );
2861 wxXmlNode* padStackHoleNode =
appendNode( padStackDefNode,
"PadstackHoleDef" );
2864 addAttribute( padStackHoleNode,
"platingStatus",
"VIA" );
2872 auto addPadShape{ [&](
PCB_LAYER_ID aLayer,
const PCB_VIA* aViaShape,
const wxString& aLayerRef,
2873 bool aDrill ) ->
void
2878 shape.
SetEnd( {
KiROUND( aViaShape->GetDrillValue() / 2.0 ), 0 } );
2880 shape.
SetEnd( {
KiROUND( aViaShape->GetWidth( aLayer ) / 2.0 ), 0 } );
2882 wxXmlNode* padStackPadDefNode =
2883 appendNode( padStackDefNode,
"PadstackPadDef" );
2884 addAttribute( padStackPadDefNode,
"layerRef", aLayerRef );
2885 addAttribute( padStackPadDefNode,
"padUse",
"REGULAR" );
2888 addShape( padStackPadDefNode, shape );
2917 addPadShape( layer, aVia,
genLayerString( layer,
"PLUGGING" ),
true );
2920 addPadShape( layer, aVia,
genLayerString( layer,
"COVERING" ),
false );
2923 addPadShape( layer, aVia,
genLayerString( layer,
"TENTING" ),
false );
2932 if( aCadUnits == wxT(
"MILLIMETER" ) )
2935 if( aCadUnits == wxT(
"MICRON" ) )
2936 return wxT(
"MICRON" );
2938 if( aCadUnits == wxT(
"INCH" ) )
2939 return wxT(
"INCH" );
2956 && ( aDrill.size.x > 0 || aDrill.size.y > 0 );
2959 if( !hasBackdrill( secondary ) && !hasBackdrill( tertiary ) )
2970 if( hasBackdrill( secondary )
2971 && ( !layerHasRef( secondary.
start ) || !layerHasRef( secondary.
end ) ) )
2976 if( hasBackdrill( tertiary )
2977 && ( !layerHasRef( tertiary.
start ) || !layerHasRef( tertiary.
end ) ) )
2990 LSEQ cuStack =
m_board->GetEnabledLayers().CuStack();
2994 auto it = std::find( cuStack.begin(), cuStack.end(), aDrill.end );
2996 if( it == cuStack.end() )
2999 if( aDrill.start ==
F_Cu )
3003 if( it == cuStack.end() )
3009 if( aDrill.start ==
B_Cu )
3011 if( it == cuStack.begin() )
3021 const wxString& aSpecName ) -> wxString
3023 if( !hasBackdrill( aDrill ) )
3031 PCB_LAYER_ID mustNotCut = computeMustNotCutLayer( aDrill );
3053 wxString postMachiningComment;
3056 postMachiningComment = wxT(
"post-machining=COUNTERBORE" );
3058 postMachiningComment = wxT(
"post-machining=COUNTERSINK" );
3062 wxXmlNode* bd =
appendNode( specNode,
"Backdrill" );
3066 addAttribute( p,
"layerOrGroupRef", startLayer->second );
3072 wxXmlNode* bd =
appendNode( specNode,
"Backdrill" );
3073 addAttribute( bd,
"type", wxT(
"MUST_NOT_CUT_LAYER" ) );
3076 addAttribute( p,
"layerOrGroupRef", mustNotCutEntry->second );
3089 if( dielectric > 0 )
3090 stubLength = dielectric / 2;
3094 wxXmlNode* bd =
appendNode( specNode,
"Backdrill" );
3102 if( !postMachiningComment.IsEmpty() )
3104 wxXmlNode* bd =
appendNode( specNode,
"Backdrill" );
3116 wxString secondarySpec = createSpec( secondary, wxString::Format( wxT(
"BD_%dA" ), specIndex ) );
3117 wxString tertiarySpec = createSpec( tertiary, wxString::Format( wxT(
"BD_%dB" ), specIndex ) );
3119 if( secondarySpec.IsEmpty() && tertiarySpec.IsEmpty() )
3124 std::array<wxString, 2>{ secondarySpec, tertiarySpec } );
3135 auto addRef = [&](
const wxString& aSpecName )
3137 if( aSpecName.IsEmpty() )
3140 wxXmlNode* specRefNode =
appendNode( aHoleNode,
"SpecRef" );
3145 for(
const wxString& specName : it->second )
3161 wxXmlNode* specNode = it->second;
3183 wxXmlNode* polygonNode =
nullptr;
3191 polygonNode =
appendNode( aParentNode,
"Polygon" );
3192 wxXmlNode* polybeginNode =
appendNode( polygonNode,
"PolyBegin" );
3194 const std::vector<VECTOR2I>& pts = aPolygon.
CPoints();
3195 addXY( polybeginNode, pts[0] );
3197 for(
size_t ii = 1; ii < pts.size(); ++ii )
3199 wxXmlNode* polyNode =
appendNode( polygonNode,
"PolyStepSegment" );
3200 addXY( polyNode, pts[ii] );
3203 wxXmlNode* polyendNode =
appendNode( polygonNode,
"PolyStepSegment" );
3204 addXY( polyendNode, pts[0] );
3215 addLineDesc( polygonNode, aWidth, aDashType,
true );
3219 wxCHECK( aWidth == 0,
false );
3232 for(
size_t ii = 1; ii < aPolygon.size(); ++ii )
3234 wxCHECK2( aPolygon[ii].PointCount() >= 3,
continue );
3236 wxXmlNode* cutoutNode =
appendNode( aParentNode,
"Cutout" );
3237 wxXmlNode* polybeginNode =
appendNode( cutoutNode,
"PolyBegin" );
3239 const std::vector<VECTOR2I>& hole = aPolygon[ii].CPoints();
3240 addXY( polybeginNode, hole[0] );
3242 for(
size_t jj = 1; jj < hole.size(); ++jj )
3244 wxXmlNode* polyNode =
appendNode( cutoutNode,
"PolyStepSegment" );
3245 addXY( polyNode, hole[jj] );
3248 wxXmlNode* polyendNode =
appendNode( cutoutNode,
"PolyStepSegment" );
3249 addXY( polyendNode, hole[0] );
3262 wxXmlNode* outlineNode =
appendNode( aParentNode,
"Outline" );
3279 wxLogTrace(
traceIpc2581, wxS(
"Failed to add polygon to outline" ) );
3282 if( !outlineNode->GetChildren() )
3284 aParentNode->RemoveChild( outlineNode );
3301 wxXmlNode* contourNode =
appendNode( aParentNode,
"Contour" );
3311 aParentNode->RemoveChild( contourNode );
3324 if( !
m_board->GetBoardPolygonOutlines( board_outline,
false ) || board_outline.
OutlineCount() == 0 )
3330 wxXmlNode* profileNode =
appendNode( aStepNode,
"Profile" );
3334 wxLogTrace(
traceIpc2581, wxS(
"Failed to add polygon to profile" ) );
3335 aStepNode->RemoveChild( profileNode );
3361 std::unique_ptr<FOOTPRINT> fp(
static_cast<FOOTPRINT*
>( aFp->
Clone() ) );
3362 fp->SetParentGroup(
nullptr );
3363 fp->SetPosition( { 0, 0 } );
3364 fp->SetOrientation(
ANGLE_0 );
3369 bool wasFlipped = fp->IsFlipped();
3372 if( fp->IsFlipped() )
3377 fp->GetFPID().GetLibItemName().wx_str(),
3383 addAttribute( aContentNode,
"packageRef", iter->second );
3392 wxXmlNode* packageNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"Package" );
3393 wxXmlNode* otherSideViewNode =
nullptr;
3399 if( fp->FindPadByNumber(
"1" ) )
3401 else if ( fp->FindPadByNumber(
"A1" ) )
3403 else if ( fp->FindPadByNumber(
"A" ) )
3405 else if ( fp->FindPadByNumber(
"a" ) )
3407 else if ( fp->FindPadByNumber(
"a1" ) )
3409 else if ( fp->FindPadByNumber(
"Anode" ) )
3411 else if ( fp->FindPadByNumber(
"ANODE" ) )
3418 PAD* pinOnePad = fp->FindPadByNumber(
"1" );
3421 pinOnePad = fp->FindPadByNumber(
"A1" );
3423 if( pinOnePad && fp->Pads().size() >= 2 )
3426 BOX2I fpBBox = fp->GetBoundingBox();
3436 const char* orientation =
"OTHER";
3438 if( onCenterX && onCenterY )
3439 orientation =
"CENTER";
3440 else if( onCenterX && pinPos.
y <
center.y )
3441 orientation =
"UPPER_CENTER";
3442 else if( onCenterX && pinPos.
y >
center.y )
3443 orientation =
"LOWER_CENTER";
3444 else if( onCenterY && pinPos.
x <
center.x )
3445 orientation =
"LEFT";
3446 else if( onCenterY && pinPos.
x >
center.x )
3447 orientation =
"RIGHT";
3449 orientation =
"UPPER_LEFT";
3451 orientation =
"UPPER_RIGHT";
3453 orientation =
"LOWER_LEFT";
3455 orientation =
"LOWER_RIGHT";
3457 addAttribute( packageNode,
"pinOneOrientation", orientation );
3461 addAttribute( packageNode,
"pinOneOrientation",
"OTHER" );
3462 addAttribute( packageNode,
"comment",
"Pin 1 orientation could not be determined" );
3468 : fp->GetCourtyard(
F_CrtYd );
3470 : fp->GetCourtyard(
B_CrtYd );
3487 otherSideViewNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"OtherSideView" );
3493 wxXmlNode* pickupPointNode =
appendNode( packageNode,
"PickupPoint" );
3497 std::map<PCB_LAYER_ID, std::map<bool, std::vector<BOARD_ITEM*>>> elements;
3499 for(
BOARD_ITEM* item : fp->GraphicalItems() )
3524 elements[item->GetLayer()][is_abs].push_back( item );
3527 auto add_base_node =
3530 wxXmlNode* parent = packageNode;
3539 bool is_other_side = wasFlipped ? ( aLayer ==
F_SilkS || aLayer ==
F_Fab )
3544 if( !otherSideViewNode )
3545 otherSideViewNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"OtherSideView" );
3547 parent = otherSideViewNode;
3554 else if( aLayer ==
F_Fab || aLayer ==
B_Fab )
3563 auto add_marking_node =
3564 [&]( wxXmlNode* aNode ) -> wxXmlNode*
3566 wxXmlNode* marking_node =
appendNode( aNode,
"Marking" );
3568 return marking_node;
3571 std::map<PCB_LAYER_ID, wxXmlNode*> layer_nodes;
3572 std::map<PCB_LAYER_ID, BOX2I> layer_bbox;
3576 if( elements.find( layer ) != elements.end() )
3578 if( elements[layer][
true].size() > 0 )
3579 layer_bbox[layer] = elements[layer][
true][0]->GetBoundingBox();
3580 else if( elements[layer][
false].size() > 0 )
3581 layer_bbox[layer] = elements[layer][
false][0]->GetBoundingBox();
3585 for(
auto& [layer, map] : elements )
3587 wxXmlNode* layer_node = add_base_node( layer );
3588 wxXmlNode* marking_node = add_marking_node( layer_node );
3589 wxXmlNode* group_node =
appendNode( marking_node,
"UserSpecial" );
3590 bool update_bbox =
false;
3594 layer_nodes[layer] = layer_node;
3598 for(
auto& [is_abs, vec] : map )
3602 wxXmlNode* output_node =
nullptr;
3605 layer_bbox[layer].Merge( item->GetBoundingBox() );
3608 output_node = add_marking_node( layer_node );
3610 output_node = group_node;
3612 switch( item->Type() )
3618 if(
text->IsKnockout() )
3632 if(
text->IsBorderEnabled() )
3635 text->GetEffectiveShape()->TransformToPolygon( poly_set, 0,
ERROR_INSIDE );
3637 text->GetBorderWidth() );
3660 if( group_node->GetChildren() ==
nullptr )
3662 marking_node->RemoveChild( group_node );
3663 layer_node->RemoveChild( marking_node );
3665 delete marking_node;
3669 for(
auto&[layer, bbox] : layer_bbox )
3671 if( bbox.GetWidth() > 0 )
3673 wxXmlNode* outlineNode =
insertNode( layer_nodes[layer],
"Outline" );
3676 std::vector<VECTOR2I> points( 4 );
3677 points[0] = bbox.GetPosition();
3678 points[2] = bbox.GetEnd();
3679 points[1].x = points[0].x;
3680 points[1].y = points[2].y;
3681 points[3].x = points[2].x;
3682 points[3].y = points[0].y;
3684 outline.
Append( points );
3690 std::map<wxString, wxXmlNode*> pin_nodes;
3692 for(
size_t ii = 0; ii < fp->Pads().size(); ++ii )
3694 PAD*
pad = fp->Pads()[ii];
3696 wxXmlNode* pinNode =
nullptr;
3698 auto [ it, inserted ] = pin_nodes.emplace( pin_name,
nullptr );
3703 it->second = pinNode;
3708 addAttribute( pinNode,
"electricalType",
"MECHANICAL" );
3709 else if(
pad->IsOnCopperLayer() )
3710 addAttribute( pinNode,
"electricalType",
"ELECTRICAL" );
3712 addAttribute( pinNode,
"electricalType",
"UNDEFINED" );
3714 if(
pad->HasHole() )
3719 if(
pad->GetFPRelativeOrientation() !=
ANGLE_0 )
3721 wxXmlNode* xformNode =
appendNode( pinNode,
"Xform" );
3722 EDA_ANGLE pad_angle =
pad->GetFPRelativeOrientation().Normalize();
3724 if( fp->IsFlipped() )
3741 if( otherSideViewNode )
3742 packageNode->AddChild( otherSideViewNode );
3750 std::vector<wxXmlNode*> componentNodes;
3751 std::vector<wxXmlNode*> packageNodes;
3752 std::set<wxString> packageNames;
3754 bool generate_unique =
m_OEMRef.empty();
3765 wxXmlNode* componentNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"Component" );
3771 for(
PAD*
pad : fp->Pads() )
3773 if(
pad->GetNetCode() > 0 )
3776 wxXmlNode* pkg =
addPackage( componentNode, fp );
3779 packageNodes.push_back( pkg );
3785 if( !generate_unique )
3788 if( field && !field->
GetText().empty() )
3794 name = wxString::Format(
"%s_%s_%s",
3795 fp->GetFPID().GetFullLibraryName(),
3796 fp->GetFPID().GetLibItemName().wx_str(),
3802 Report(
_(
"Duplicate footprint pointers encountered; IPC-2581 output may be incorrect." ),
3811 else if( fp->GetAttributes() &
FP_SMD )
3816 if( fp->GetOrientation() !=
ANGLE_0 || fp->IsFlipped() )
3818 wxXmlNode* xformNode =
appendNode( componentNode,
"Xform" );
3822 if( fp->IsFlipped() )
3828 if( fp->IsFlipped() )
3832 addLocationNode( componentNode, fp->GetPosition().x, fp->GetPosition().y );
3834 componentNodes.push_back( componentNode );
3840 [&]( std::vector<wxXmlNode*>& aNodes,
IPC2581::SECTION aSection,
bool aInsert )
3844 for( wxXmlNode*& node : aNodes )
3857 aStepNode->AddChild( node );
3877 wxXmlNode* netNode =
appendNode( aStepNode,
"LogicalNet" );
3879 netName(
m_board->GetNetInfo().GetNetItem( net )->GetNetname() ) ) ;
3881 for(
auto& [cmp,
pin] : pin_pair )
3883 wxXmlNode* netPinNode =
appendNode( netNode,
"PinRef" );
3901 wxString m_exposure;
3909 std::map<int, std::vector<NET_POINT>> byNet;
3922 [&](
const LSET& aLayers,
bool& aFront,
bool& aBack )
3924 aFront = aLayers.test(
F_Cu );
3925 aBack = aLayers.test(
B_Cu );
3926 return aFront || aBack;
3930 [&](
const LSET& aLayers,
bool aFront,
bool aBack ) -> wxString
3932 bool frontOpen = !aFront || aLayers.test(
F_Mask );
3933 bool backOpen = !aBack || aLayers.test(
B_Mask );
3935 if( frontOpen && backOpen )
3936 return wxT(
"EXPOSED" );
3939 return wxT(
"COVERED_PRIMARY" );
3942 return wxT(
"COVERED_SECONDARY" );
3944 return wxT(
"COVERED" );
3951 for(
PAD*
pad : fp->Pads() )
3956 if(
pad->GetNetCode() <= 0 || !access(
pad->GetLayerSet(), front, back ) )
3960 point.m_pos =
pad->GetPosition();
3961 point.m_layer = front ?
F_Cu :
B_Cu;
3963 point.m_exposure = exposure(
pad->GetLayerSet(), front, back );
3965 point.m_via =
false;
3966 point.m_width =
pad->GetSize( point.m_layer ).x;
3967 point.m_drill =
pad->HasHole() ? std::min(
pad->GetDrillSize().x,
3968 pad->GetDrillSize().y )
3972 byNet[
pad->GetNetCode()].push_back( point );
3976 std::shared_ptr<CONNECTIVITY_DATA> connectivity =
m_board->GetConnectivity();
3982 if( track->Type() !=
PCB_VIA_T || track->GetNetCode() <= 0 )
3990 if( !access(
via->GetLayerSet(), front, back ) )
3994 point.m_pos =
via->GetPosition();
3995 point.m_layer = front ?
F_Cu :
B_Cu;
3997 point.m_exposure = exposure(
via->GetLayerSet(), front, back );
3999 point.m_width =
via->GetWidth( point.m_layer );
4000 point.m_drill =
via->GetDrillValue();
4001 point.m_pad =
nullptr;
4004 point.m_end = connectivity->GetConnectedItemsAtAnchor(
via,
via->GetPosition(),
4005 { PCB_TRACE_T, PCB_ARC_T } ).size() < 2;
4007 byNet[
via->GetNetCode()].push_back( point );
4013 wxXmlNode* groupNode =
appendNode( aStepNode,
"PhyNetGroup" );
4016 for(
const auto& [netcode, points] : byNet )
4025 wxXmlNode* netNode =
appendNode( groupNode,
"PhyNet" );
4028 for(
const NET_POINT& point : points )
4030 wxXmlNode* pointNode =
appendNode( netNode,
"PhyNetPoint" );
4031 addXY( pointNode, point.m_pos );
4040 addAttribute( pointNode,
"netNode", point.m_end ?
"END" :
"MIDDLE" );
4041 addAttribute( pointNode,
"exposure", point.m_exposure );
4048 addShape( pointNode, *point.m_pad, point.m_layer );
4053 dummy.SetPosition( point.m_pos );
4054 dummy.SetSize( point.m_layer,
VECTOR2I( point.m_width, point.m_width ) );
4056 if( point.m_drill > 0 )
4057 dummy.SetDrillSize(
VECTOR2I( point.m_drill, point.m_drill ) );
4070 std::vector<std::unique_ptr<FOOTPRINT>> footprints;
4074 std::map<PCB_LAYER_ID, std::map<int, std::vector<BOARD_ITEM*>>> elements;
4076 std::for_each(
m_board->Tracks().begin(),
m_board->Tracks().end(),
4077 [&layers, &elements](
PCB_TRACK* aTrack )
4079 if( aTrack->Type() == PCB_VIA_T )
4081 PCB_VIA* via = static_cast<PCB_VIA*>( aTrack );
4083 for( PCB_LAYER_ID layer : layers )
4085 if( via->FlashLayer( layer ) )
4086 elements[layer][via->GetNetCode()].push_back( via );
4093 for( PCB_LAYER_ID layer : aTrack->GetLayerSet().Seq() )
4094 elements[layer][aTrack->GetNetCode()].push_back( aTrack );
4098 std::for_each( m_board->Zones().begin(), m_board->Zones().end(),
4099 [ &elements ](
ZONE* zone )
4101 LSEQ zone_layers = zone->GetLayerSet().Seq();
4103 for( PCB_LAYER_ID layer : zone_layers )
4104 elements[layer][zone->GetNetCode()].push_back( zone );
4107 for(
BOARD_ITEM* item : m_board->Drawings() )
4112 netcode = conn_it->GetNetCode();
4118 elements[layer][netcode].push_back( item );
4121 for(
FOOTPRINT* fp : m_board->Footprints() )
4123 for(
PCB_FIELD* field : fp->GetFields() )
4124 elements[field->GetLayer()][0].push_back( field );
4128 for(
BOARD_ITEM* item : fp->GraphicalItems() )
4131 elements[layer][0].push_back( item );
4134 for(
PAD*
pad : fp->Pads() )
4136 LSEQ pad_layers =
pad->GetLayerSet().Seq();
4140 if(
pad->FlashLayer( layer ) )
4141 elements[layer][
pad->GetNetCode()].push_back(
pad );
4154 if( !hasAuthoredMask )
4167 if( !layerIncluded( layer ) )
4170 if( m_progressReporter )
4171 m_progressReporter->SetMaxProgress( nets.GetNetCount() * layers.size() );
4174 wxXmlNode* layerNode = appendNode( aStepNode,
"LayerFeature" );
4175 addAttribute( layerNode,
"layerRef", m_layer_name_map[layer] );
4177 auto process_net = [&] (
int net )
4179 std::vector<BOARD_ITEM*>& vec = elements[layer][net];
4184 std::stable_sort( vec.begin(), vec.end(),
4187 if( a->GetParentFootprint() == b->GetParentFootprint() )
4188 return a->Type() < b->Type();
4190 return a->GetParentFootprint() < b->GetParentFootprint();
4193 generateLayerSetNet( layerNode, layer, vec );
4198 tickProgress( wxString::Format(
_(
"Exporting layer %s, net %s" ),
4199 m_board->GetLayerName( layer ),
4200 net->GetNetname() ) );
4202 process_net( net->GetNetCode() );
4205 if( layerNode->GetChildren() ==
nullptr )
4207 aStepNode->RemoveChild( layerNode );
4208 deleteNode( layerNode );
4223 wxXmlNode* layerNode =
appendNode( aLayerNode,
"LayerFeature" );
4224 layerNode->AddAttribute(
"layerRef",
genLayersString( layers.first, layers.second,
"DRILL" ) );
4235 Report(
_(
"Via uses unsupported padstack; omitted from drill data." ),
4240 wxXmlNode* padNode =
appendNode( layerNode,
"Set" );
4243 if(
via->GetNetCode() > 0 )
4246 wxXmlNode* holeNode =
appendNode( padNode,
"Hole" );
4247 addAttribute( holeNode,
"name", wxString::Format(
"H%d", hole_count++ ) );
4252 addXY( holeNode,
via->GetPosition() );
4262 Report(
_(
"Pad uses unsupported padstack; hole was omitted from drill data." ),
4267 wxXmlNode* padNode =
appendNode( layerNode,
"Set" );
4270 if(
pad->GetNetCode() > 0 )
4273 wxXmlNode* holeNode =
appendNode( padNode,
"Hole" );
4274 addAttribute( holeNode,
"name", wxString::Format(
"H%d", hole_count++ ) );
4280 addXY( holeNode,
pad->GetPosition() );
4290 wxXmlNode* layerNode =
appendNode( aLayerNode,
"LayerFeature" );
4291 layerNode->AddAttribute(
"layerRef",
genLayersString( layers.first, layers.second,
"SLOT" ) );
4295 wxXmlNode* padNode =
appendNode( layerNode,
"Set" );
4297 if(
pad->GetNetCode() > 0 )
4300 addSlotCavity( padNode, *
pad, wxString::Format(
"SLOT%d", hole_count++ ) );
4307 std::vector<BOARD_ITEM*>& aItems )
4309 auto it = aItems.begin();
4310 wxXmlNode* layerSetNode =
appendNode( aLayerNode,
"Set" );
4311 wxXmlNode* featureSetNode =
appendNode( layerSetNode,
"Features" );
4312 wxXmlNode* specialNode =
appendNode( featureSetNode,
"UserSpecial" );
4314 bool has_via =
false;
4315 bool has_pad =
false;
4317 wxXmlNode* padSetNode =
nullptr;
4319 wxXmlNode* viaSetNode =
nullptr;
4321 wxXmlNode* teardropLayerSetNode =
nullptr;
4322 wxXmlNode* teardropFeatureSetNode =
nullptr;
4324 bool teardrop_warning =
false;
4329 if( item->GetNetCode() > 0 )
4339 auto maskAdjustedWidth =
4342 int width = aTrack->GetWidth();
4345 width += 2 * aTrack->GetSolderMaskExpansion();
4353 shape.
SetStart( track->GetStart() );
4354 shape.
SetEnd( track->GetEnd() );
4355 shape.
SetWidth( maskAdjustedWidth( track ) );
4368 shape.
SetWidth( maskAdjustedWidth( arc ) );
4375 shape.
SetStart( track->GetStart() );
4376 shape.
SetEnd( track->GetEnd() );
4377 shape.
SetWidth( maskAdjustedWidth( track ) );
4387 viaSetNode = layerSetNode;
4392 viaSetNode =
appendNode( layerSetNode,
"Set" );
4394 if( track->GetNetCode() > 0 )
4401 addVia( viaSetNode,
static_cast<PCB_VIA*
>( track ), aLayer );
4408 wxXmlNode* zoneFeatureNode = specialNode;
4410 if( zone->IsTeardropArea() )
4414 if( !teardropFeatureSetNode )
4416 teardropLayerSetNode =
appendNode( aLayerNode,
"Set" );
4417 addAttribute( teardropLayerSetNode,
"geometryUsage",
"TEARDROP" );
4419 if( zone->GetNetCode() > 0 )
4422 wxXmlNode* new_teardrops =
appendNode( teardropLayerSetNode,
"Features" );
4424 teardropFeatureSetNode =
appendNode( new_teardrops,
"UserSpecial" );
4427 zoneFeatureNode = teardropFeatureSetNode;
4429 else if( !teardrop_warning )
4431 Report(
_(
"Teardrops are not supported in IPC-2581 revision B; they were exported as zones." ),
4433 teardrop_warning =
true;
4440 wxXmlNode* tempSetNode =
appendNode( aLayerNode,
"Set" );
4446 wxXmlNode* newFeatures =
appendNode( tempSetNode,
"Features" );
4448 zoneFeatureNode =
appendNode( newFeatures,
"UserSpecial" );
4452 SHAPE_POLY_SET& zone_shape = *zone->GetFilledPolysList( aLayer );
4454 for(
int ii = 0; ii < zone_shape.
OutlineCount(); ++ii )
4461 std::optional<PCB_SHAPE> maskShape;
4468 maskShape.emplace( *shape );
4469 maskShape->SetWidth( std::max( shape->GetWidth() + 2 * shape->GetSolderMaskExpansion(), 0 ) );
4470 shape = &maskShape.value();
4477 wxXmlNode* tempSetNode =
appendNode( aLayerNode,
"Set" );
4480 addAttribute( tempSetNode,
"geometryUsage",
"GRAPHIC" );
4482 bool link_to_component =
true;
4485 link_to_component =
false;
4487 if( link_to_component )
4493 wxXmlNode* tempFeature =
appendNode( tempSetNode,
"Features" );
4502 wxXmlNode* tempSetNode =
appendNode( aLayerNode,
"Set" );
4509 wxXmlNode* tempFeature =
appendNode( tempSetNode,
"Features" );
4526 text_item =
static_cast<EDA_TEXT*
>( pcb_text );
4528 text_item =
static_cast<EDA_TEXT*
>( pcb_textbox );
4530 if( !text_item || !text_item->
IsVisible() )
4535 if( content.empty() )
4538 bool isWhitespace = content.Strip( wxString::both ).empty();
4542 if( isWhitespace && !isKnockout && !hasBorder )
4545 wxXmlNode* tempSetNode =
appendNode( aLayerNode,
"Set" );
4550 bool link_to_component = fp !=
nullptr;
4553 link_to_component =
false;
4555 if( link_to_component )
4561 wxXmlNode* nonStandardAttributeNode =
appendNode( tempSetNode,
"NonstandardAttribute" );
4562 addAttribute( nonStandardAttributeNode,
"name",
"TEXT" );
4563 addAttribute( nonStandardAttributeNode,
"value", content );
4564 addAttribute( nonStandardAttributeNode,
"type",
"STRING" );
4566 if( !isWhitespace || isKnockout )
4568 wxXmlNode* glyphFeature =
appendNode( tempSetNode,
"Features" );
4574 addText( glyphFeature, text_item,
text->GetFontMetrics() );
4580 wxXmlNode* borderFeature =
appendNode( tempSetNode,
"Features" );
4583 addShape( borderFeature, *border );
4594 padSetNode = layerSetNode;
4599 padSetNode =
appendNode( aLayerNode,
"Set" );
4601 if(
pad->GetNetCode() > 0 )
4611 switch( item->Type() )
4616 add_track(
static_cast<PCB_TRACK*
>( item ) );
4624 add_pad(
static_cast<PAD*
>( item ) );
4628 add_shape(
static_cast<PCB_SHAPE*
>( item ) );
4653 if( specialNode->GetChildren() ==
nullptr )
4655 featureSetNode->RemoveChild( specialNode );
4659 if( featureSetNode->GetChildren() ==
nullptr )
4661 layerSetNode->RemoveChild( featureSetNode );
4665 if( layerSetNode->GetChildren() ==
nullptr )
4667 aLayerNode->RemoveChild( layerSetNode );
4679 bool add_node =
true;
4685 switch( std::get<0>(layers) )
4714 wxXmlNode* layerNode =
appendNode( aStepNode,
"LayerFeature" );
4722 layerNode->AddAttribute(
"layerRef",
genLayersString( std::get<1>( layers ),
4726 wxXmlNode* setNode =
appendNode( layerNode,
"Set" );
4740 shape.
SetEnd( {
KiROUND(
via->GetWidth( std::get<1>( layers ) ) / 2.0 ), 0 } );
4742 wxXmlNode* padNode =
appendNode( setNode,
"Pad" );
4767 wxXmlNode* header =
appendNode( avl,
"AvlHeader" );
4771 addAttribute( header,
"datetime", wxDateTime::Now().FormatISOCombined() );
4774 std::set<wxString> unique_parts;
4775 std::map<wxString,wxString> unique_vendors;
4779 auto [ it, success ] = unique_parts.insert(
name );
4784 wxXmlNode* part =
appendNode( avl,
"AvlItem" );
4791 for (
int ii = 0; ii < 2; ++ii )
4797 if( mpn_name.empty() )
4800 wxXmlNode* vmpn =
appendNode( part,
"AvlVmpn" );
4804 wxXmlNode* mpn =
appendNode( vmpn,
"AvlMpn" );
4807 wxXmlNode* vendor =
appendNode( vmpn,
"AvlVendor" );
4809 wxString vendor_name = wxT(
"UNKNOWN" );
4812 if( !ii && company[ii] )
4820 else if( !ii && !company_name[ii].
empty() )
4822 vendor_name = company_name[ii];
4824 else if( ii && !
m_dist.empty() )
4829 auto [vendor_id, inserted] = unique_vendors.emplace(
4831 wxString::Format(
"VENDOR_%zu", unique_vendors.size() ) );
4833 addAttribute( vendor,
"enterpriseRef", vendor_id->second );
4837 wxXmlNode* new_vendor =
new wxXmlNode( wxXML_ELEMENT_NODE,
"Enterprise" );
4853 const std::map<std::string, UTF8>* aProperties )
4907 const std::map<std::string, UTF8> emptyProperties;
4910 aProperties = &emptyProperties;
4912 if(
auto it = aProperties->find(
"units" ); it != aProperties->end() )
4914 if( it->second ==
"inch" )
4921 if(
auto it = aProperties->find(
"sigfig" ); it != aProperties->end() )
4922 m_sigfig = std::stoi( it->second );
4924 if(
auto it = aProperties->find(
"version" ); it != aProperties->end() )
4927 if(
auto it = aProperties->find(
"OEMRef" ); it != aProperties->end() )
4930 if(
auto it = aProperties->find(
"mpn" ); it != aProperties->end() )
4931 m_mpn = it->second.wx_str();
4933 if(
auto it = aProperties->find(
"mfg" ); it != aProperties->end() )
4934 m_mfg = it->second.wx_str();
4936 if(
auto it = aProperties->find(
"dist" ); it != aProperties->end() )
4937 m_dist = it->second.wx_str();
4939 if(
auto it = aProperties->find(
"distpn" ); it != aProperties->end() )
4942 if(
auto it = aProperties->find(
"bomrev" ); it != aProperties->end() )
4948 if(
auto it = aProperties->find(
"mode" ); it != aProperties->end() )
4953 THROW_IO_ERROR( wxString::Format(
_(
"Unknown IPC-2581 data set '%s'." ),
4954 it->second.wx_str() ) );
4960 if(
auto it = aProperties->find(
"sections" ); it != aProperties->end() )
4964 THROW_IO_ERROR( wxString::Format(
_(
"Invalid IPC-2581 section key '%s'." ),
4965 it->second.wx_str() ) );
4969 if(
auto it = aProperties->find(
"netnames" ); it != aProperties->end() )
4972 if(
auto it = aProperties->find(
"refdes" ); it != aProperties->end() )
4982 for(
char c =
'a'; c <=
'z'; ++c )
4985 for(
char c =
'A'; c <=
'Z'; ++c )
4988 for(
char c =
'0'; c <=
'9'; ++c )
4992 std::string specialChars =
"_\\-.+><";
4994 for(
char c : specialChars )
5032 wxXmlNode* insertBefore =
nullptr;
5034 for( wxXmlNode* child =
m_contentNode->GetChildren(); child; child = child->GetNext() )
5036 if( child->GetName().StartsWith(
"Dictionary" ) )
5038 insertBefore = child;
5044 [&](
const wxString& aNodeName, wxXmlNode* aSection )
5049 wxXmlNode* ref =
new wxXmlNode( wxXML_ELEMENT_NODE, aNodeName );
5050 ref->AddAttribute(
"name", aSection->GetAttribute(
"name" ) );
5058 insertRef(
"BomRef", bom_node );
5059 insertRef(
"AvlRef", avl_node );
5073 double written_bytes = 0.0;
5074 double last_yield = 0.0;
5081 auto update_progress = [&](
size_t aBytes )
5083 written_bytes += aBytes;
5084 double percent = written_bytes /
static_cast<double>(
m_total_bytes );
5089 if( last_yield + 0.01 < percent )
5091 last_yield = percent;
5103 wxBufferedOutputStream buffered_stream( out_stream, 1 << 20 );
5105 if( !
m_xml_doc->Save( buffered_stream ) )
5108 buffered_stream.Sync();
constexpr int ARC_HIGH_DEF
constexpr double PCB_IU_PER_MM
Pcbnew IU is 1 nanometer.
bool IsPrmSpecified(const wxString &aPrmValue)
@ BS_ITEM_TYPE_SILKSCREEN
@ BS_ITEM_TYPE_DIELECTRIC
@ BS_ITEM_TYPE_SOLDERMASK
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
wxString GetMajorMinorPatchVersion()
Get the major, minor and patch version in a string major.minor.patch This is extracted by CMake from ...
Bezier curves to polygon converter.
void GetPoly(std::vector< VECTOR2I > &aOutput, int aMaxError=10)
Convert a Bezier curve to a polygon.
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
Container for design settings for a BOARD object.
BOARD_STACKUP & GetStackupDescriptor()
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
FOOTPRINT * GetParentFootprint() const
VECTOR2I GetFPRelativePosition() const
Manage one layer needed to make a physical board.
wxString GetTypeName() const
int GetSublayersCount() const
double GetEpsilonR(int aDielectricSubLayer=0) const
wxString GetColor(int aDielectricSubLayer=0) const
wxString GetLayerName() const
PCB_LAYER_ID GetBrdLayerId() const
int GetThickness(int aDielectricSubLayer=0) const
BOARD_STACKUP_ITEM_TYPE GetType() const
wxString GetMaterial(int aDielectricSubLayer=0) const
int GetDielectricLayerId() const
double GetLossTangent(int aDielectricSubLayer=0) const
Manage layers needed to make a physical board.
const std::vector< BOARD_STACKUP_ITEM * > & GetList() const
bool SynchronizeWithBoard(BOARD_DESIGN_SETTINGS *aSettings)
Synchronize the BOARD_STACKUP_ITEM* list with the board.
int BuildBoardThicknessFromStackup() const
int GetLayerDistance(PCB_LAYER_ID aFirstLayer, PCB_LAYER_ID aSecondLayer) const
Calculate the distance (height) between the two given copper layers.
wxString m_FinishType
The name of external copper finish.
Information pertinent to a Pcbnew printed circuit board.
constexpr size_type GetWidth() const
constexpr const Vec GetCenter() const
constexpr size_type GetHeight() const
int GetEllipseMinorRadius() const
const VECTOR2I & GetBezierC2() const
const VECTOR2I & GetEllipseCenter() const
EDA_ANGLE GetEllipseEndAngle() const
FILL_T GetFillMode() const
int GetEllipseMajorRadius() const
int GetRectangleWidth() const
SHAPE_POLY_SET & GetPolyShape()
EDA_ANGLE GetEllipseRotation() const
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
std::vector< VECTOR2I > GetRectCorners() const
EDA_ANGLE GetEllipseStartAngle() const
const VECTOR2I & GetBezierC1() const
int GetRectangleHeight() const
bool IsClockwiseArc() const
int GetCornerRadius() const
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
virtual const wxString & GetText() const
Return the string associated with the text object.
virtual bool IsVisible() const
virtual EDA_ANGLE GetDrawRotation() const
virtual VECTOR2I GetDrawPos() const
virtual wxString GetShownText(RESOLUTION_CONTEXT aContext, int aDepth=0) const
Return the string actually shown after processing of the base text.
virtual KIFONT::FONT * GetDrawFont(const RENDER_SETTINGS *aSettings) const
const TEXT_ATTRIBUTES & GetAttributes() const
int GetEffectiveTextPenWidth(int aDefaultPenWidth=0) const
The EffectiveTextPenWidth uses the text thickness if > 1 or aDefaultPenWidth.
static ENUM_MAP< T > & Instance()
wxString m_name
Name of the IO loader.
virtual void Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED) const
PROGRESS_REPORTER * m_progressReporter
Progress reporter to track the progress of the operation, may be nullptr.
SECTION_SET & Set(SECTION aSection, bool aOn=true)
FONT is an abstract base class for both outline and stroke fonts.
void Draw(KIGFX::GAL *aGal, const wxString &aText, const VECTOR2I &aPosition, const VECTOR2I &aCursor, const TEXT_ATTRIBUTES &aAttributes, const METRICS &aFontMetrics, std::optional< VECTOR2I > aMousePos=std::nullopt, wxString *aActiveUrl=nullptr) const
Draw a string.
A color representation with 4 components: red, green, blue, alpha.
wxString AsString() const
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
LSET is a set of PCB_LAYER_IDs.
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
Handle the data for a net.
const wxString & GetNetname() const
Container for NETINFO_ITEM elements, which are the nets.
A PADSTACK defines the characteristics of a single or multi-layer pad, in the IPC sense of the word.
std::optional< bool > IsFilled() const
std::optional< bool > IsTented(PCB_LAYER_ID aSide) const
Checks if this padstack is tented (covered in soldermask) on the given side.
PCB_LAYER_ID EffectiveLayerFor(PCB_LAYER_ID aLayer) const
Determines which geometry layer should be used for the given input layer.
POST_MACHINING_PROPS & FrontPostMachining()
std::optional< bool > IsPlugged(PCB_LAYER_ID aSide) const
DRILL_PROPS & TertiaryDrill()
std::optional< bool > IsCapped() const
std::optional< bool > IsCovered(PCB_LAYER_ID aSide) const
DRILL_PROPS & SecondaryDrill()
POST_MACHINING_PROPS & BackPostMachining()
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
void MergePrimitivesAsPolygon(PCB_LAYER_ID aLayer, SHAPE_POLY_SET *aMergedPolygon, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Merge all basic shapes to a SHAPE_POLY_SET.
int GetRoundRectCornerRadius(PCB_LAYER_ID aLayer) const
bool FlashLayer(int aLayer, bool aOnlyCheckIfPermitted=false) const
Check to see whether the pad should be flashed on the specific layer.
int GetDrillSizeY() const
PAD_ATTRIB GetAttribute() const
const wxString & GetNumber() const
const VECTOR2I & GetDelta(PCB_LAYER_ID aLayer) const
VECTOR2I GetPosition() const override
VECTOR2I GetOffset(PCB_LAYER_ID aLayer) const
VECTOR2I GetDrillSize() const
int GetDrillSizeX() const
double GetRoundRectRadiusRatio(PCB_LAYER_ID aLayer) const
PAD_SHAPE GetShape(PCB_LAYER_ID aLayer) const
int GetSolderMaskExpansion(PCB_LAYER_ID aLayer) const
VECTOR2I GetSize(PCB_LAYER_ID aLayer) const
const PADSTACK & Padstack() const
EDA_ANGLE GetOrientation() const
Return the rotation angle of the pad.
PAD_DRILL_SHAPE GetDrillShape() const
int GetChamferPositions(PCB_LAYER_ID aLayer) const
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
double GetChamferRectRatio(PCB_LAYER_ID aLayer) const
VECTOR2I GetSolderPasteMargin(PCB_LAYER_ID aLayer) const
Usually < 0 (mask shape smaller than pad)because the margin can be dependent on the pad size,...
bool HasDrilledHole() const override
bool HasHole() const override
bool TransformHoleToPolygon(SHAPE_POLY_SET &aBuffer, int aClearance, int aError, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Build the corner list of the polygonal drill shape in the board coordinate system.
bool IsDegenerated(int aThreshold=5) const
const VECTOR2I & GetMid() const
wxString GetShownText(RESOLUTION_CONTEXT aContext, int aDepth=0) const override
Return the string actually shown after processing of the base text.
void addText(wxXmlNode *aContentNode, EDA_TEXT *aShape, const KIFONT::METRICS &aFontMetrics)
wxString floatVal(double aVal, int aSigFig=-1) const
void generateLayerSetDrill(wxXmlNode *aStepNode)
wxString genLayerString(PCB_LAYER_ID aLayer, const char *aPrefix) const
wxXmlNode * generateContentSection()
Creates the Content section of the XML file.
wxXmlNode * appendNode(wxXmlNode *aParent, const wxString &aName)
void addBackdrillSpecRefs(wxXmlNode *aHoleNode, const wxString &aPadstackName)
void generateDrillLayers(wxXmlNode *aCadLayerNode)
wxString sanitizeId(const wxString &aStr) const
wxXmlNode * addPackage(wxXmlNode *aStepNode, FOOTPRINT *aFootprint)
void generateComponents(wxXmlNode *aStepNode)
IPC2581::SECTION_SET emittedSections() const
Schema sections that the finished document holds.
bool addContourNode(wxXmlNode *aParentNode, const SHAPE_POLY_SET &aPolySet, int aOutline=0, FILL_T aFillType=FILL_T::FILLED_SHAPE, int aWidth=0, LINE_STYLE aDashType=LINE_STYLE::SOLID)
bool refDesEmitted() const
True if a Component keeps a designator that a reference can name.
wxString componentName(FOOTPRINT *aFootprint)
void addShape(wxXmlNode *aContentNode, const PCB_SHAPE &aShape, bool aInline=false)
IPC2581::RESOLVE_RESULT m_resolved
std::map< FOOTPRINT *, wxString > m_anon_refdes_dict
bool componentRefEmitted() const
True if a component reference can name a Component that the export wrote.
bool addOutlineNode(wxXmlNode *aParentNode, const SHAPE_POLY_SET &aPolySet, int aWidth=0, LINE_STYLE aDashType=LINE_STYLE::SOLID)
void generateStackup(wxXmlNode *aCadLayerNode)
std::map< std::tuple< auxLayerType, PCB_LAYER_ID, PCB_LAYER_ID >, std::vector< BOARD_ITEM * > > m_auxilliary_Layers
bool addPolygonNode(wxXmlNode *aParentNode, const SHAPE_LINE_CHAIN &aPolygon, FILL_T aFillType=FILL_T::FILLED_SHAPE, int aWidth=0, LINE_STYLE aDashType=LINE_STYLE::SOLID)
void generateLayerSetNet(wxXmlNode *aLayerNode, PCB_LAYER_ID aLayer, std::vector< BOARD_ITEM * > &aItems)
bool isValidLayerFor2581(PCB_LAYER_ID aLayer)
void insertNodeAfter(wxXmlNode *aPrev, wxXmlNode *aNode)
void generateCadLayers(wxXmlNode *aCadLayerNode)
std::vector< wxXmlNode * > m_padstacks
wxString pinName(const PAD *aPad) const
bool stackupRowIncluded(bool aDielectric, PCB_LAYER_ID aLayer) const
True if a stackup row is in a schema section that this export holds.
void generateCadSpecs(wxXmlNode *aCadLayerNode)
void addVia(wxXmlNode *aContentNode, const PCB_VIA *aVia, PCB_LAYER_ID aLayer)
IPC2581::SECTION_SET m_requestedSections
void addSlotCavity(wxXmlNode *aContentNode, const PAD &aPad, const wxString &aName)
void deleteNode(wxXmlNode *&aNode)
wxXmlNode * m_last_padstack
size_t lineHash(int aWidth, LINE_STYLE aDashType)
void SaveBoard(const wxString &aFileName, BOARD &aBoard, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Write aBoard to a storage file in a format that this PCB_IO implementation knows about or it can be u...
std::map< size_t, wxString > m_std_shape_dict
wxString netName(const wxString &aNetname, const wxString &aSuffix=wxEmptyString)
Name to write for aNetname with the net name policy.
void addAttribute(wxXmlNode *aNode, const wxString &aName, const wxString &aValue)
wxXmlNode * m_shape_user_node
wxXmlNode * generateAvlSection()
Creates the Approved Vendor List section.
wxXmlNode * generateHistorySection()
Creates the history section.
wxString stackupLayerName(const BOARD_STACKUP_ITEM *aItem, int aSublayerId, const char *aPrefix) const
wxXmlNode * m_contentNode
void addXY(wxXmlNode *aNode, const VECTOR2I &aVec, const char *aXName=nullptr, const char *aYName=nullptr)
void reportPhase(const wxString &aMessage)
Go to the next progress phase and repaint.
wxXmlNode * m_shape_std_node
void addPadStack(wxXmlNode *aContentNode, const PAD *aPad)
std::map< FOOTPRINT *, wxString > m_OEMRef_dict
void clearLoadedFootprints()
Frees the memory allocated for the loaded footprints in m_loaded_footprints.
std::map< wxString, wxXmlNode * > m_backdrill_spec_nodes
std::map< std::pair< PCB_LAYER_ID, PCB_LAYER_ID >, std::vector< PAD * > > m_slot_holes
std::map< size_t, wxString > m_footprint_dict
wxXmlNode * m_functionModeNode
wxXmlNode * generateLogisticSection()
Creates the logistical data header.
std::map< wxString, wxString > m_net_name_dict
std::set< wxString > m_element_names
std::map< size_t, wxString > m_line_dict
void addLineDesc(wxXmlNode *aNode, int aWidth, LINE_STYLE aDashType, bool aForce=false)
void addKnockoutText(wxXmlNode *aContentNode, PCB_TEXT *aText)
std::map< size_t, wxString > m_padstack_dict
std::map< std::pair< PCB_LAYER_ID, PCB_LAYER_ID >, std::vector< BOARD_ITEM * > > m_drill_layers
std::map< wxString, FOOTPRINT * > m_footprint_refdes_dict
void generateProfile(wxXmlNode *aStepNode)
void generateLayerFeatures(wxXmlNode *aStepNode)
bool suppressed(IPC2581::SUPPRESS aWhat) const
wxXmlNode * generateBOMSection(wxXmlNode *aEcadNode)
Creates the BOM section.
wxXmlNode * generateContentStackup(wxXmlNode *aContentNode)
void generateAuxilliaryLayers(wxXmlNode *aCadLayerNode)
wxXmlNode * m_cad_header_node
void addCadHeader(wxXmlNode *aEcadNode)
void generateLayerSetAuxilliary(wxXmlNode *aStepNode)
bool layerIncluded(PCB_LAYER_ID aLayer) const
True if aLayer is in a schema section that this export holds.
std::vector< FOOTPRINT * > GetImportedCachedLibraryFootprints() override
Return a container with the cached library footprints generated in the last call to Load.
const std::map< std::string, UTF8 > * m_props
wxString genLayersString(PCB_LAYER_ID aTop, PCB_LAYER_ID aBottom, const char *aPrefix) const
void generateLogicalNets(wxXmlNode *aStepNode)
void addFillDesc(wxXmlNode *aNode, FILL_T aFillType, bool aForce=false)
std::map< size_t, wxString > m_user_shape_dict
size_t shapeHash(const PCB_SHAPE &aShape)
void generatePhyNetGroup(wxXmlNode *aStepNode)
~PCB_IO_IPC2581() override
wxString genString(const wxString &aStr, const char *aPrefix=nullptr) const
static constexpr int EXPORT_PHASES
Content logistic history CAD data components the two netlists BOM vendor list references the write an...
std::vector< FOOTPRINT * > m_loaded_footprints
bool addPolygonCutouts(wxXmlNode *aParentNode, const SHAPE_POLY_SET::POLYGON &aPolygon)
void pruneUnusedBackdrillSpecs()
IPC2581::REVISION m_revision
std::set< wxUniChar > m_acceptable_chars
void addLayerAttributes(wxXmlNode *aNode, PCB_LAYER_ID aLayer)
wxXmlNode * generateXmlHeader()
Creates the XML header for IPC-2581.
void ensureBackdrillSpecs(const wxString &aPadstackName, const PADSTACK &aPadstack)
wxXmlNode * generateEcadSection()
Creates the ECAD section.
wxXmlDocument * m_xml_doc
bool included(IPC2581::SECTION aSection) const
wxXmlNode * insertNode(wxXmlNode *aParent, const wxString &aName)
void addPad(wxXmlNode *aContentNode, const PAD *aPad, PCB_LAYER_ID aLayer)
void generateContentLayerRefs(wxXmlNode *aCadDataNode)
void generateStepSection(wxXmlNode *aCadNode)
std::map< PCB_LAYER_ID, wxString > m_layer_name_map
void dropContentStepRefs()
Remove Content/StepRef when the export writes no Step.
std::map< wxString, wxString > m_generated_names
std::set< wxString > m_backdrill_spec_used
void addLocationNode(wxXmlNode *aContentNode, double aX, double aY)
std::map< wxString, std::array< wxString, 2 > > m_padstack_backdrill_specs
std::map< int, std::vector< std::pair< wxString, wxString > > > m_net_pin_dict
int m_backdrill_spec_index
void tickProgress(const wxString &aMessage=wxEmptyString)
Count one unit of work in this phase and repaint at intervals.
std::map< FOOTPRINT *, wxString > m_footprint_refdes_reverse_dict
wxXmlNode * m_lastAppendedNode
Optimization for appendNode to avoid O(n) child traversal.
wxXmlNode * m_enterpriseNode
VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
void SetWidth(int aWidth) override
void SetEnd(const VECTOR2I &aEnd) override
void SetArcGeometry(const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd)
STROKE_PARAMS GetStroke() const override
void SetStart(const VECTOR2I &aStart) override
VECTOR2I GetPosition() const override
void TransformTextToPolySet(SHAPE_POLY_SET &aBuffer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc) const
Function TransformTextToPolySet Convert the text to a polygonSet describing the actual character stro...
const VECTOR2I & GetStart() const
const VECTOR2I & GetEnd() const
PCB_LAYER_ID BottomLayer() const
VECTOR2I GetPosition() const override
bool FlashLayer(int aLayer) const
Check to see whether the via should have a pad on the specific layer.
const PADSTACK & Padstack() const
int GetWidth() const override
PCB_LAYER_ID TopLayer() const
int GetDrillValue() const
Calculate the drill value for vias (m_drill if > 0, or default drill value for the board).
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
SHAPE_LINE_CHAIN ConvertToPolyline(int aMaxError) const
Build a polyline approximation of the ellipse or arc.
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
int Width() const
Get the current width of the segments in the chain.
int PointCount() const
Return the number of points (vertices) in this line chain.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
const std::vector< VECTOR2I > & CPoints() const
Represent a set of closed polygons.
POLYGON & Polygon(int aIndex)
Return the aIndex-th subpolygon in the set.
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)
void Simplify()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
std::vector< SHAPE_LINE_CHAIN > POLYGON
represents a single polygon outline with holes.
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
int NewOutline()
Creates a new empty polygon in the set and returns its index.
int OutlineCount() const
Return the number of outlines in the set.
void InflateWithLinkedHoles(int aFactor, CORNER_STRATEGY aCornerStrategy, int aMaxError)
Perform outline inflation/deflation, using round corners.
void Fracture(bool aSimplify=true)
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
LINE_STYLE GetLineStyle() const
Handle a list of polygons defining a copper zone.
void SetProgressCallback(std::function< void(size_t)> aCallback)
@ RECT_CHAMFER_BOTTOM_RIGHT
@ RECT_CHAMFER_BOTTOM_LEFT
@ ROUND_ALL_CORNERS
All angles are rounded.
static bool empty(const wxTextEntryBase *aCtrl)
bool IsDrillSlot(const PAD &aPad)
Whether a pad's hole is a slot rather than a round drill.
static constexpr EDA_ANGLE ANGLE_0
static constexpr EDA_ANGLE ANGLE_90
static constexpr EDA_ANGLE ANGLE_180
@ FILLED_SHAPE
Fill with object color.
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
static const wxChar traceIpc2581[]
This program source code file is part of KiCad, a free EDA CAD application.
static constexpr void hash_combine(std::size_t &seed)
This is a dummy function to take the final case of hash_combine below.
static constexpr std::size_t hash_val(const Types &... args)
size_t hash_fp_item(const EDA_ITEM *aItem, int aFlags)
Calculate hash of an EDA_ITEM.
Hashing functions for EDA_ITEMs.
@ REL_COORD
Use coordinates relative to the parent object.
surfaceFinishType
IPC-6012 surface finish types from Table 3-3 "Final Finish and Coating Requirements".
@ OTHER
Non-standard finish.
@ DIG
Direct Immersion Gold.
@ HT_OSP
High Temperature OSP.
@ ENEPIG_N
ENEPIG for soldering (normal gold thickness)
@ NONE
No surface finish / not specified - skip coating layer generation.
@ OSP
Organic Solderability Preservative.
@ ENIG_N
ENIG for soldering (normal gold thickness)
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
#define THROW_IO_CANCELLED()
bool IsSolderMaskLayer(int aLayer)
bool IsFrontLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a front layer.
bool IsNonCopperLayer(int aLayerId)
Test whether a layer is a non copper layer.
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
bool IsExternalCopperLayer(int aLayerId)
Test whether a layer is an external (F_Cu or B_Cu) copper layer.
PCB_LAYER_ID
A quick note on layer IDs:
bool IsValidLayer(int aLayerId)
Test whether a given integer is a valid layer index, i.e.
@ TOP_BOTTOM
Flip top to bottom (around the X axis)
SECTION_SET RecommendedOptionalSections(MODE aMode)
Optional schema sections that aMode selects by default.
wxString ModeToken(MODE aMode)
Table 4 function mode token such as FABRICATION.
bool SectionSetFromKeyString(const wxString &aKey, SECTION_SET &aResult)
Read a sectionKey attribute value Return false for an unknown character.
SECTION
Schema sections of the IPC-2581C function mode table, Table 4 p 80.
RESOLVE_RESULT ResolveSections(REVISION aRevision, MODE aMode, const SECTION_SET &aRequested)
Compare aRequested with Table 4 and give the attributes to remove and the conflicts.
std::optional< SECTION > SectionForLayerFunction(const wxString &aLayerFunction, const wxString &aSide)
Schema section that holds the layers with aLayerFunction.
bool NeedsCadData(const SECTION_SET &aSet)
True if an included schema section needs an Ecad/CadData element.
@ PINREF_COMPONENTREF
Pad/PinRef@componentRef and LogicalNet/PinRef@componentRef.
@ PAD_PADSTACKDEFREF
Pad@padstackDefRef, and the PadStackDef elements themselves.
@ COMPONENT_PACKAGEREF
Component@packageRef.
@ BOM_REFDES_PACKAGEREF
Bom/BomItem/RefDes@packageRef.
@ BOM_REFDES
Bom/BomItem/RefDes and all its attributes.
@ BOM_REFDES_LAYERREF
Bom/BomItem/RefDes@layerRef.
wxString SectionKeyString(const SECTION_SET &aSet)
Give aSet as a sectionKey attribute value.
std::optional< MODE > ModeFromToken(const wxString &aToken)
Read a Table 4 function mode token in upper case or in lower case.
std::optional< SECTION > SectionForBoardLayer(PCB_LAYER_ID aLayer)
Schema section that holds the artwork of aLayer.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
PAD_DRILL_POST_MACHINING_MODE
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
@ PTH
Plated through hole pad.
static size_t ipcPadstackHash(const PCB_VIA *aVia)
static const std::map< surfaceFinishType, wxString > surfaceFinishTypeToString
Map surfaceFinishType enum to IPC-2581 XML string values.
static bool isOppositeSideSilk(const FOOTPRINT *aFootprint, PCB_LAYER_ID aLayer)
static void mixBackdrillIntoPadstackHash(size_t &aHash, const PADSTACK &aPadstack)
static const std::map< wxString, surfaceFinishType > surfaceFinishMap
Map KiCad surface finish strings to IPC-6012 surfaceFinishType enum.
static wxString propertyUnitForCadUnits(const wxString &aCadUnits)
static surfaceFinishType getSurfaceFinishType(const wxString &aFinish)
static wxString nodeName(const wxString &aSymbolPin)
std::vector< FAB_LAYER_COLOR > dummy
const std::vector< FAB_LAYER_COLOR > & GetStandardColors(BOARD_STACKUP_ITEM_TYPE aType)
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
LINE_STYLE
Dashed line types.
The properties of a padstack drill.
std::optional< PAD_DRILL_POST_MACHINING_MODE > mode
@ DESCRIPTION
Field Description of part, i.e. "1/4W 1% Metal Film Resistor".
const SHAPE_LINE_CHAIN chain
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
@ PCB_DIM_ORTHOGONAL_T
class PCB_DIM_ORTHOGONAL, a linear dimension constrained to x/y
@ PCB_DIM_LEADER_T
class PCB_DIM_LEADER, a leader dimension (graphic item)
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
@ PCB_DIM_CENTER_T
class PCB_DIM_CENTER, a center point marking (graphic item)
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
@ PCB_ZONE_T
class ZONE, a copper pour area
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
@ PCB_TARGET_T
class PCB_TARGET, a target (graphic item)
@ PCB_DIM_ALIGNED_T
class PCB_DIM_ALIGNED, a linear dimension (graphic item)
@ PCB_PAD_T
class PAD, a pad in a footprint
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
@ PCB_DIMENSION_T
class PCB_DIMENSION_BASE: abstract dimension meta-type
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
@ PCB_DIM_RADIAL_T
class PCB_DIM_RADIAL, a radius or diameter dimension
VECTOR2< int32_t > VECTOR2I
VECTOR2< double > VECTOR2D