68#include <wx/numformatter.h>
73#include <wx/xml/xml.h>
94 static_cast<int>( aDrill.end ), aDrill.size.x, aDrill.size.y,
95 static_cast<int>( aDrill.shape ), aDrill.is_capped.has_value(),
96 aDrill.is_capped.value_or(
false ), aDrill.is_filled.has_value(),
97 aDrill.is_filled.value_or(
false ) );
105 aPost.size, aPost.depth, aPost.angle );
218 std::vector<FOOTPRINT*> retval;
221 retval.push_back(
static_cast<FOOTPRINT*
>( fp->Clone() ) );
231 if( aParent->GetChildren() )
232 aNode->SetNext( aParent->GetChildren() );
234 aNode->SetNext(
nullptr );
236 aParent->SetChildren( aNode );
237 aNode->SetParent( aParent );
248 aNode->SetNext( aPrev->GetNext() );
249 aPrev->SetNext( aNode );
250 aNode->SetParent( aPrev->GetParent() );
271 check = check->GetParent();
275 if( aNode->GetParent() )
276 aNode->GetParent()->RemoveChild( aNode );
287 wxXmlNode* node =
new wxXmlNode( wxXML_ELEMENT_NODE, aName );
302 aNode->SetParent( aParent );
307 aParent->AddChild( aNode );
319 wxXmlNode* node =
new wxXmlNode( wxXML_ELEMENT_NODE, aName );
333 str.Replace( wxT(
":" ), wxT(
"_" ) );
337 for( wxString::const_iterator iter = aStr.begin(); iter != aStr.end(); ++iter )
354 wxString key = aPrefix ? wxString( aPrefix ) + wxT(
":" ) + aStr : aStr;
364 wxString
name = base;
367 wxString prefix = aPrefix ? wxString( aPrefix ) : wxString();
368 bool ownSet = prefix == wxS(
"CMP" ) || prefix == wxS(
"REF" );
369 std::set<wxString>& names =
m_element_names[ownSet ? prefix : wxString()];
371 while( names.count(
name ) )
372 name = wxString::Format(
"%s_%d", base, suffix++ );
374 names.insert(
name );
403 if( aSublayerId > 0 )
404 name += wxString::Format(
"_%d", aSublayerId );
411 const char* aPrefix )
const
413 return genString( wxString::Format( wxS(
"%s_%s" ),
415 m_board->GetLayerName( aBottom ) ), aPrefix );
444 [&](
const wxString& aName )
479 wxString baseName =
genString( ref,
"CMP" );
480 wxString
name = baseName;
483 while( !tryInsert(
name ) )
484 name = wxString::Format(
"%s_%d", baseName, suffix++ );
516 aNode->AddAttribute( aName, aValue );
522 wxXmlNode* xmlHeaderNode =
new wxXmlNode(wxXML_ELEMENT_NODE,
"IPC-2581");
525 addAttribute( xmlHeaderNode,
"xmlns",
"http://webstds.ipc.org/2581");
526 addAttribute( xmlHeaderNode,
"xmlns:xsi",
"http://www.w3.org/2001/XMLSchema-instance");
527 addAttribute( xmlHeaderNode,
"xmlns:xsd",
"http://www.w3.org/2001/XMLSchema");
532 "http://webstds.ipc.org/2581 http://webstds.ipc.org/2581/IPC-2581B1.xsd" );
537 "http://webstds.ipc.org/2581 http://webstds.ipc.org/2581/IPC-2581C.xsd" );
542 return xmlHeaderNode;
554 wxXmlNode* node =
appendNode( contentNode,
"FunctionMode" );
568 wxFileName fn(
m_board->GetFileName() );
572 wxXmlNode* color_node =
included( IPC2581::SECTION::STACKUP )
574 :
new wxXmlNode( wxXML_ELEMENT_NODE,
"DictionaryColor" );
578 contentNode->AddChild( color_node );
582 wxXmlNode* fillNode =
appendNode( contentNode,
"DictionaryFillDesc" );
602 contentNode->AddChild( color_node );
611 wxXmlNode* location_node =
appendNode( aNode,
"Location" );
628 if( offset.
x != 0 || offset.
y != 0 )
693 wxXmlNode* color_node =
new wxXmlNode( wxXML_ELEMENT_NODE,
"DictionaryColor" );
697 for(
int sub_idx = 0; sub_idx < item->GetSublayersCount(); sub_idx++ )
707 wxXmlNode* entry_color =
appendNode( color_node,
"EntryColor" );
709 wxXmlNode* color =
appendNode( entry_color,
"Color" );
711 wxString colorName = item->GetColor( sub_idx );
713 if( colorName.StartsWith( wxT(
"#" ) ) )
716 COLOR4D layer_color( colorName );
728 if( fab_color.GetName() == colorName )
730 addAttribute( color,
"r", wxString::Format(
"%d",
KiROUND( fab_color.GetColor( item->GetType() ).r * 255 ) ) );
731 addAttribute( color,
"g", wxString::Format(
"%d",
KiROUND( fab_color.GetColor( item->GetType() ).g * 255 ) ) );
732 addAttribute( color,
"b", wxString::Format(
"%d",
KiROUND( fab_color.GetColor( item->GetType() ).b * 255 ) ) );
751 return it->second + aSuffix;
753 return wxS(
"NET_0" ) + aSuffix;
757 return genString( aNetname + aSuffix,
"NET" );
778 if( !aMessage.IsEmpty() )
802 return section &&
included( *section );
813 std::function<void( wxXmlNode* )> visit =
814 [&]( wxXmlNode* aNode )
816 for( wxXmlNode* child = aNode->GetChildren(); child; child = child->GetNext() )
818 const wxString&
name = child->GetName();
820 if(
name ==
"Layer" )
823 child->GetAttribute(
"layerFunction" ),
824 child->GetAttribute(
"side" ) );
827 sections.
Set( *section );
829 else if(
name ==
"Bom" )
830 sections.
Set( IPC2581::SECTION::BOM_AVL );
831 else if(
name ==
"PadStackDef" )
832 sections.
Set( IPC2581::SECTION::PADSTACKS );
833 else if(
name ==
"Package" )
834 sections.
Set( IPC2581::SECTION::PACKAGES );
835 else if(
name ==
"Component" )
836 sections.
Set( IPC2581::SECTION::COMPONENTS );
837 else if(
name ==
"Stackup" )
838 sections.
Set( IPC2581::SECTION::STACKUP );
839 else if(
name ==
"Profile" )
840 sections.
Set( IPC2581::SECTION::PROFILE );
841 else if(
name ==
"LogicalNet" )
842 sections.
Set( IPC2581::SECTION::LOGICAL_NET );
843 else if(
name ==
"PhyNetGroup" )
844 sections.
Set( IPC2581::SECTION::PHYSICAL_NET );
845 else if(
name ==
"Dfx" )
846 sections.
Set( IPC2581::SECTION::DFX );
867 wxXmlNode*
next = child->GetNext();
869 if( child->GetName() ==
"StepRef" )
882 wxXmlNode* insertBefore =
nullptr;
884 for( wxXmlNode* child =
m_contentNode->GetChildren(); child; child = child->GetNext() )
886 if( child->GetName().StartsWith(
"Dictionary" ) )
888 insertBefore = child;
893 for( wxXmlNode* layer = aCadDataNode->GetChildren(); layer; layer = layer->GetNext() )
895 if( layer->GetName() !=
"Layer" )
898 wxXmlNode* ref =
new wxXmlNode( wxXML_ELEMENT_NODE,
"LayerRef" );
899 addAttribute( ref,
"name", layer->GetAttribute(
"name" ) );
917 wxXmlNode* fillDesc_node =
appendNode( aNode,
"FillDesc" );
923 wxXmlNode* fillDesc_node =
appendNode( aNode,
"FillDesc" );
924 addAttribute( fillDesc_node,
"fillProperty",
"HOLLOW" );
931 wxCHECK_RET( aNode,
"aNode is null" );
936 wxXmlNode* entry_node =
nullptr;
940 size_t hash =
lineHash( aWidth, aDashType );
941 wxString
name = wxString::Format(
"LINE_%zu",
m_line_dict.size() + 1 );
945 wxXmlNode* lineDesc_node =
appendNode( aNode,
"LineDescRef" );
960 wxXmlNode* line_node =
appendNode( entry_node,
"LineDesc" );
993 if( outlineCount == 0 )
1000 if( outlineCount == 1 )
1006 wxXmlNode* special_node =
appendNode( aContentNode,
"UserSpecial" );
1008 for(
int ii = 0; ii < outlineCount; ++ii )
1024 wxXmlNode* text_node =
appendNode( aContentNode,
"UserSpecial" );
1026 std::list<VECTOR2I> pts;
1031 if( pts.size() < 2 )
1034 wxXmlNode* line_node =
nullptr;
1038 if( pts.size() < 3 )
1041 addXY( line_node, pts.front(),
"startX",
"startY" );
1042 addXY( line_node, pts.back(),
"endX",
"endY" );
1046 line_node =
appendNode( text_node,
"Polyline" );
1047 wxXmlNode* point_node =
appendNode( line_node,
"PolyBegin" );
1048 addXY( point_node, pts.front() );
1050 auto iter = pts.begin();
1052 for( ++iter; iter != pts.end(); ++iter )
1054 wxXmlNode* step_node =
appendNode( line_node,
"PolyStepSegment" );
1055 addXY( step_node, *iter );
1070 if( aPt1 == pts.back() )
1071 pts.push_back( aPt2 );
1072 else if( aPt2 == pts.front() )
1073 pts.push_front( aPt1 );
1074 else if( aPt1 == pts.front() )
1075 pts.push_front( aPt2 );
1076 else if( aPt2 == pts.back() )
1077 pts.push_back( aPt1 );
1081 pts.push_back( aPt1 );
1082 pts.push_back( aPt2 );
1087 pts.push_back( aPt1 );
1088 pts.push_back( aPt2 );
1094 if( aPoly.PointCount() < 3 )
1097 wxXmlNode* outline_node =
appendNode( text_node,
"Outline" );
1098 wxXmlNode* poly_node =
appendNode( outline_node,
"Polygon" );
1101 const std::vector<VECTOR2I>& polyPts = aPoly.CPoints();
1102 wxXmlNode* point_node =
appendNode( poly_node,
"PolyBegin" );
1103 addXY( point_node, polyPts.front() );
1105 for(
size_t ii = 1; ii < polyPts.size(); ++ii )
1107 wxXmlNode* poly_step_node =
1109 addXY( poly_step_node, polyPts[ii] );
1112 point_node =
appendNode( poly_node,
"PolyStepSegment" );
1113 addXY( point_node, polyPts.front() );
1123 if( text_node->GetChildren() ==
nullptr )
1125 aContentNode->RemoveChild( text_node );
1133 int maxError =
m_board->GetDesignSettings().m_MaxError;
1149 wxXmlNode* shape_node =
appendNode( aContentNode,
"StandardPrimitiveRef" );
1155 const PAD& resolved = geometry.
Pad();
1167 int diameter = resolved.
GetSize( aLayer ).
x;
1169 wxXmlNode* circle_node =
appendNode( entry_node,
"Circle" );
1189 wxXmlNode* rect_node =
appendNode( entry_node,
"RectRound" );
1200 wxXmlNode* rect_node =
appendNode( entry_node,
"RectCenter" );
1218 wxXmlNode* oval_node =
appendNode( entry_node,
"Oval" );
1236 wxXmlNode* roundrect_node =
appendNode( entry_node,
"RectRound" );
1256 if( margin.
x <= 0 || margin.
x != margin.
y )
1263 wxXmlNode* chamfered_node =
appendNode( entry_node,
"RectCham" );
1267 int shorterSide = std::min( pad_size.
x, pad_size.
y );
1324 wxXmlNode* shape_node =
appendNode( aContentNode,
"StandardPrimitiveRef" );
1339 wxXmlNode* shape_node =
appendNode( aContentNode,
"UserPrimitiveRef" );
1356 wxXmlNode* polyline_node =
appendNode( aContentNode,
"Polyline" );
1364 wxXmlNode* begin_node =
appendNode( polyline_node,
"PolyBegin" );
1365 addXY( begin_node, start );
1368 wxXmlNode* arc1_node =
appendNode( polyline_node,
"PolyStepCurve" );
1369 addXY( arc1_node, mid );
1374 wxXmlNode* arc2_node =
appendNode( polyline_node,
"PolyStepCurve" );
1375 addXY( arc2_node, start );
1386 int diameter = aShape.
GetRadius() * 2.0;
1393 wxXmlNode* special_node =
appendNode( entry_node,
"UserSpecial" );
1395 wxXmlNode* circle_node =
appendNode( special_node,
"Circle" );
1421 wxXmlNode* polyline_node =
appendNode( aContentNode,
"Polyline" );
1426 wxXmlNode* begin_node =
appendNode( polyline_node,
"PolyBegin" );
1427 addXY( begin_node, corners[0] );
1429 for(
size_t i = 1; i < corners.size(); ++i )
1431 wxXmlNode* step_node =
appendNode( polyline_node,
"PolyStepSegment" );
1432 addXY( step_node, corners[i] );
1436 wxXmlNode* close_node =
appendNode( polyline_node,
"PolyStepSegment" );
1437 addXY( close_node, corners[0] );
1439 addLineDesc( polyline_node, stroke_width, dash,
true );
1449 wxXmlNode* special_node =
appendNode( entry_node,
"UserSpecial" );
1456 wxXmlNode* rect_node =
appendNode( special_node,
"RectRound" );
1463 wxString cornerFlag = corner_radius > 0 ?
"true" :
"false";
1471 width += stroke_width;
1472 height += stroke_width;
1500 wxXmlNode* polyline_node =
appendNode( aContentNode,
"Polyline" );
1501 const std::vector<VECTOR2I>& pts = outline.
CPoints();
1503 wxXmlNode* begin_node =
appendNode( polyline_node,
"PolyBegin" );
1504 addXY( begin_node, pts[0] );
1506 for(
size_t jj = 1; jj < pts.size(); ++jj )
1508 wxXmlNode* step_node =
appendNode( polyline_node,
"PolyStepSegment" );
1509 addXY( step_node, pts[jj] );
1513 if( pts.size() > 2 && pts.front() != pts.back() )
1515 wxXmlNode* close_node =
appendNode( polyline_node,
"PolyStepSegment" );
1516 addXY( close_node, pts[0] );
1519 addLineDesc( polyline_node, stroke_width, dash,
true );
1533 wxXmlNode* special_node =
appendNode( entry_node,
"UserSpecial" );
1555 wxXmlNode* arc_node =
appendNode( aContentNode,
"Arc" );
1557 addXY( arc_node, aShape.
GetEnd(),
"endX",
"endY" );
1570 wxXmlNode* polyline_node =
appendNode( aContentNode,
"Polyline" );
1574 std::vector<VECTOR2I> points;
1577 wxXmlNode* point_node =
appendNode( polyline_node,
"PolyBegin" );
1578 addXY( point_node, points[0] );
1580 for(
size_t i = 1; i < points.size(); i++ )
1582 wxXmlNode* seg_node =
appendNode( polyline_node,
"PolyStepSegment" );
1583 addXY( seg_node, points[i] );
1593 wxXmlNode* line_node =
appendNode( aContentNode,
"Line" );
1595 addXY( line_node, aShape.
GetEnd(),
"endX",
"endY" );
1621 if(
chain.PointCount() < 2 )
1624 wxXmlNode* polyline_node =
appendNode( aContentNode,
"Polyline" );
1625 const std::vector<VECTOR2I>& pts =
chain.CPoints();
1627 wxXmlNode* begin_node =
appendNode( polyline_node,
"PolyBegin" );
1628 addXY( begin_node, pts[0] );
1630 for(
size_t jj = 1; jj < pts.size(); ++jj )
1632 wxXmlNode* step_node =
appendNode( polyline_node,
"PolyStepSegment" );
1633 addXY( step_node, pts[jj] );
1637 if( !isArc && pts.size() > 2 && pts.front() != pts.back() )
1639 wxXmlNode* close_node =
appendNode( polyline_node,
"PolyStepSegment" );
1640 addXY( close_node, pts[0] );
1643 addLineDesc( polyline_node, stroke_width, dash,
true );
1653 wxXmlNode* special_node =
appendNode( entry_node,
"UserSpecial" );
1677 if( !aInline && !
name.empty() )
1679 wxXmlNode* shape_node =
appendNode( aContentNode,
"UserPrimitiveRef" );
1688 wxXmlNode* slotNode =
appendNode( aNode,
"SlotCavity" );
1706 if( drill_size.
y > drill_size.
x )
1708 std::swap( drill_size.
x, drill_size.
y );
1709 rotation = ( rotation +
ANGLE_90 ).Normalize();
1715 wxXmlNode* xformNode =
appendNode( slotNode,
"Xform" );
1720 wxXmlNode* ovalNode =
appendNode( slotNode,
"Oval" );
1728 int maxError =
m_board->GetDesignSettings().m_MaxError;
1740 wxXmlNode* roleNode =
appendNode( logisticNode,
"Role" );
1748 wxXmlNode* personNode =
appendNode( logisticNode,
"Person" );
1750 addAttribute( personNode,
"enterpriseRef",
"UNKNOWN" );
1753 return logisticNode;
1763 addAttribute( historyNode,
"origination", wxDateTime::Now().FormatISOCombined() );
1765 addAttribute( historyNode,
"lastChange", wxDateTime::Now().FormatISOCombined() );
1767 wxXmlNode* fileRevisionNode =
appendNode( historyNode,
"FileRevision" );
1768 addAttribute( fileRevisionNode,
"fileRevisionId",
"1" );
1769 addAttribute( fileRevisionNode,
"comment",
"NO COMMENT" );
1772 wxXmlNode* softwarePackageNode =
appendNode( fileRevisionNode,
"SoftwarePackage" );
1775 addAttribute( softwarePackageNode,
"vendor",
"KiCad EDA" );
1777 wxXmlNode* certificationNode =
appendNode( softwarePackageNode,
"Certification" );
1778 addAttribute( certificationNode,
"certificationStatus",
"SELFTEST" );
1786 if( !
included( IPC2581::SECTION::BOM_AVL ) )
1803 m_refdes =
new std::vector<REFDES>();
1804 m_props =
new std::map<wxString, wxString>();
1815 wxString m_OEMDesignRef;
1819 wxString m_description;
1821 std::vector<REFDES>* m_refdes;
1822 std::map<wxString, wxString>*
m_props;
1825 std::set<std::unique_ptr<struct BOM_ENTRY>,
1826 std::function<bool(
const std::unique_ptr<struct BOM_ENTRY>&,
1827 const std::unique_ptr<struct BOM_ENTRY>& )>> bom_entries(
1828 [](
const std::unique_ptr<struct BOM_ENTRY>& a,
1829 const std::unique_ptr<struct BOM_ENTRY>& b )
1831 return a->m_OEMDesignRef < b->m_OEMDesignRef;
1837 std::unique_ptr<FOOTPRINT> fp(
static_cast<FOOTPRINT*
>( fp_it->Clone() ) );
1838 fp->SetParentGroup(
nullptr );
1839 fp->SetPosition( {0, 0} );
1840 fp->SetOrientation(
ANGLE_0 );
1843 if( fp->IsFlipped() )
1851 Report( wxString::Format(
_(
"Footprint %s not found in dictionary; BOM data may be incomplete." ),
1852 fp->GetFPID().GetLibItemName().wx_str() ),
1857 auto entry = std::make_unique<struct BOM_ENTRY>();
1863 entry->m_OEMDesignRef = it->second;
1867 Report( wxString::Format(
_(
"Component \"%s\" missing OEM reference; BOM entry will be skipped." ),
1868 fp->GetFPID().GetLibItemName().wx_str() ),
1872 entry->m_OEMDesignRef =
genString( entry->m_OEMDesignRef,
"REF" );
1874 entry->m_pads = fp->GetPadCount();
1879 entry->m_type =
"DOCUMENT";
1881 entry->m_type =
"ELECTRICAL";
1889 auto[ bom_iter, inserted ] = bom_entries.insert( std::move( entry ) );
1892 ( *bom_iter )->m_count++;
1896 refdes.m_pkg = iter->second;
1900 ( *bom_iter )->m_refdes->push_back( refdes );
1904 for(
PCB_FIELD* prop : fp_it->GetFields() )
1909 if( prop->IsMandatory() && !prop->IsValue() )
1912 ( *bom_iter )->m_props->emplace( prop->GetName(), row.
Field( prop->GetName() ) );
1916 if( bom_entries.empty() )
1919 wxFileName fn(
m_board->GetFileName() );
1921 wxXmlNode* bomNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"Bom" );
1922 m_xml_root->InsertChild( bomNode, aEcadNode );
1925 wxXmlNode* bomHeaderNode =
appendNode( bomNode,
"BomHeader" );
1928 if( bomRevision.IsEmpty() )
1929 bomRevision =
m_board->GetTitleBlock().GetRevision();
1931 if( bomRevision.IsEmpty() )
1932 bomRevision = wxS(
"1.0" );
1934 addAttribute( bomHeaderNode,
"revision", bomRevision );
1939 wxXmlNode* stepRefNode =
appendNode( bomHeaderNode,
"StepRef" );
1943 for(
const auto& entry : bom_entries )
1945 wxXmlNode* bomEntryNode =
appendNode( bomNode,
"BomItem" );
1946 addAttribute( bomEntryNode,
"OEMDesignNumberRef", entry->m_OEMDesignRef );
1947 addAttribute( bomEntryNode,
"quantity", wxString::Format(
"%d", entry->m_count ) );
1948 addAttribute( bomEntryNode,
"pinCount", wxString::Format(
"%d", entry->m_pads ) );
1949 addAttribute( bomEntryNode,
"category", entry->m_type );
1951 if( !entry->m_description.IsEmpty() )
1952 addAttribute( bomEntryNode,
"description", entry->m_description );
1954 for(
const REFDES& refdes : *( entry->m_refdes ) )
1959 wxXmlNode* refdesNode =
appendNode( bomEntryNode,
"RefDes" );
1962 addAttribute( refdesNode,
"packageRef", refdes.m_pkg );
1963 addAttribute( refdesNode,
"populate", refdes.m_populate ?
"true" :
"false" );
1965 addAttribute( refdesNode,
"layerRef", refdes.m_layer );
1968 wxXmlNode* characteristicsNode =
appendNode( bomEntryNode,
"Characteristics" );
1969 addAttribute( characteristicsNode,
"category", entry->m_type );
1971 for(
const auto& prop : *( entry->m_props ) )
1973 wxXmlNode* textualDefNode =
appendNode( characteristicsNode,
"Textual" );
1974 addAttribute( textualDefNode,
"definitionSource",
"KICAD" );
1975 addAttribute( textualDefNode,
"textualCharacteristicName", prop.first );
1976 addAttribute( textualDefNode,
"textualCharacteristicValue", prop.second );
1993 wxXmlNode* cadDataNode =
appendNode( ecadNode,
"CadData" );
1996 if(
included( IPC2581::SECTION::DRILL_ROUT ) )
1999 if(
included( IPC2581::SECTION::MISC_FAB ) )
2002 if(
included( IPC2581::SECTION::STACKUP ) )
2010 bool haveLayer =
false;
2012 for( wxXmlNode* child = cadDataNode->GetChildren(); child; child = child->GetNext() )
2014 if( child->GetName() ==
"Layer" )
2040 std::vector<BOARD_STACKUP_ITEM*> layers = stackup.
GetList();
2041 std::set<PCB_LAYER_ID> added_layers;
2043 for(
int i = 0; i < stackup.
GetCount(); i++ )
2047 for(
int sublayer_id = 0; sublayer_id < stackup_item->
GetSublayersCount(); sublayer_id++ )
2049 wxString ly_name =
stackupLayerName( stackup_item, sublayer_id,
"SPEC_LAYER" );
2051 wxXmlNode* specNode =
appendNode( aCadLayerNode,
"Spec" );
2053 wxXmlNode* generalNode =
appendNode( specNode,
"General" );
2055 wxXmlNode* propertyNode =
appendNode( generalNode,
"Property" );
2057 switch ( stackup_item->
GetType() )
2062 wxXmlNode* conductorNode =
appendNode( specNode,
"Conductor" );
2064 propertyNode =
appendNode( conductorNode,
"Property" );
2065 addAttribute( propertyNode,
"unit", wxT(
"SIEMENS/M" ) );
2066 addAttribute( propertyNode,
"value", wxT(
"5.959E7" ) );
2072 propertyNode =
appendNode( generalNode,
"Property" );
2073 addAttribute( propertyNode,
"text", wxString::Format(
"Type : %s",
2075 wxXmlNode* dielectricNode =
appendNode( specNode,
"Dielectric" );
2076 addAttribute( dielectricNode,
"type",
"DIELECTRIC_CONSTANT" );
2077 propertyNode =
appendNode( dielectricNode,
"Property" );
2080 dielectricNode =
appendNode( specNode,
"Dielectric" );
2081 addAttribute( dielectricNode,
"type",
"LOSS_TANGENT" );
2082 propertyNode =
appendNode( dielectricNode,
"Property" );
2089 propertyNode =
appendNode( generalNode,
"Property" );
2090 addAttribute( propertyNode,
"text", wxString::Format(
"Color : %s",
2092 propertyNode =
appendNode( generalNode,
"Property" );
2093 addAttribute( propertyNode,
"text", wxString::Format(
"Type : %s",
2099 propertyNode =
appendNode( generalNode,
"Property" );
2100 addAttribute( propertyNode,
"text", wxString::Format(
"Color : %s",
2102 propertyNode =
appendNode( generalNode,
"Property" );
2103 addAttribute( propertyNode,
"text", wxString::Format(
"Type : %s",
2107 if( stackup_item->
GetEpsilonR( sublayer_id ) > 1.0 )
2109 wxXmlNode* dielectricNode =
appendNode( specNode,
"Dielectric" );
2110 addAttribute( dielectricNode,
"type",
"DIELECTRIC_CONSTANT" );
2111 propertyNode =
appendNode( dielectricNode,
"Property" );
2118 wxXmlNode* dielectricNode =
appendNode( specNode,
"Dielectric" );
2119 addAttribute( dielectricNode,
"type",
"LOSS_TANGENT" );
2120 propertyNode =
appendNode( dielectricNode,
"Property" );
2138 wxXmlNode* specNode =
appendNode( aCadLayerNode,
"Spec" );
2141 wxXmlNode* surfaceFinishNode =
appendNode( specNode,
"SurfaceFinish" );
2153 wxXmlNode* cadHeaderNode =
appendNode( aEcadNode,
"CadHeader" );
2158 if(
included( IPC2581::SECTION::STACKUP ) ||
included( IPC2581::SECTION::DIELECTRIC ) )
2192 addAttribute( aNode,
"layerFunction",
"BOARD_OUTLINE" );
2224 aLayer ==
F_Cu ?
"TOP"
2225 : aLayer ==
B_Cu ?
"BOTTOM"
2248 &&
included( IPC2581::SECTION::MISC_FAB ) );
2250 wxXmlNode* stackupNode =
appendNode( aCadLayerNode,
"Stackup" );
2251 addAttribute( stackupNode,
"name",
"Primary_Stackup" );
2258 addAttribute( stackupNode,
"stackupStatus",
"PROPOSED" );
2260 wxXmlNode* stackupGroup =
appendNode( stackupNode,
"StackupGroup" );
2261 addAttribute( stackupGroup,
"name",
"Primary_Stackup_Group" );
2266 std::vector<BOARD_STACKUP_ITEM*> layers = stackup.
GetList();
2267 std::set<PCB_LAYER_ID> added_layers;
2270 for(
int i = 0; i < stackup.
GetCount(); i++ )
2274 for(
int sublayer_id = 0; sublayer_id < stackup_item->
GetSublayersCount(); sublayer_id++ )
2279 if( hasCoating && layer_id ==
F_Cu && sublayer_id == 0 )
2281 wxXmlNode* coatingLayer =
appendNode( stackupGroup,
"StackupLayer" );
2282 addAttribute( coatingLayer,
"layerOrGroupRef",
"COATING_TOP" );
2286 addAttribute( coatingLayer,
"sequence", wxString::Format(
"%d", sequence++ ) );
2288 wxXmlNode* specRefNode =
appendNode( coatingLayer,
"SpecRef" );
2299 wxXmlNode* stackupLayer =
appendNode( stackupGroup,
"StackupLayer" );
2300 wxString spec_name =
stackupLayerName( stackup_item, sublayer_id,
"SPEC_LAYER" );
2303 addAttribute( stackupLayer,
"layerOrGroupRef", ly_name );
2307 addAttribute( stackupLayer,
"sequence", wxString::Format(
"%d", sequence++ ) );
2309 wxXmlNode* specLayerNode =
appendNode( stackupLayer,
"SpecRef" );
2315 wxXmlNode* coatingLayer =
appendNode( stackupGroup,
"StackupLayer" );
2316 addAttribute( coatingLayer,
"layerOrGroupRef",
"COATING_BOTTOM" );
2320 addAttribute( coatingLayer,
"sequence", wxString::Format(
"%d", sequence++ ) );
2322 wxXmlNode* specRefNode =
appendNode( coatingLayer,
"SpecRef" );
2334 std::vector<BOARD_STACKUP_ITEM*> layers = stackup.
GetList();
2335 std::set<PCB_LAYER_ID> added_layers;
2337 for(
int i = 0; i < stackup.
GetCount(); i++ )
2341 for(
int sublayer_id = 0; sublayer_id < stackup_item->
GetSublayersCount(); sublayer_id++ )
2354 wxXmlNode* cadLayerNode =
appendNode( aCadLayerNode,
"Layer" );
2361 addAttribute( cadLayerNode,
"layerFunction",
"DIELCORE" );
2363 addAttribute( cadLayerNode,
"layerFunction",
"DIELPREG" );
2378 LSEQ layer_seq =
m_board->GetEnabledLayers().Seq();
2382 if( added_layers.find( layer ) != added_layers.end() || !
layerIncluded( layer ) )
2389 added_layers.insert( layer );
2390 wxXmlNode* cadLayerNode =
appendNode( aCadLayerNode,
"Layer" );
2403 wxXmlNode* topCoatingNode =
appendNode( aCadLayerNode,
"Layer" );
2405 addAttribute( topCoatingNode,
"layerFunction",
"COATINGCOND" );
2407 addAttribute( topCoatingNode,
"polarity",
"POSITIVE" );
2409 wxXmlNode* botCoatingNode =
appendNode( aCadLayerNode,
"Layer" );
2410 addAttribute( botCoatingNode,
"name",
"COATING_BOTTOM" );
2411 addAttribute( botCoatingNode,
"layerFunction",
"COATINGCOND" );
2413 addAttribute( botCoatingNode,
"polarity",
"POSITIVE" );
2423 if( layer.m_Span.m_IsBackdrill )
2438 wxXmlNode* drillNode =
appendNode( aCadLayerNode,
"Layer" );
2439 drillNode->AddAttribute(
"name",
genLayersString( span.TopLayer(), span.BottomLayer(),
"DRILL" ) );
2444 wxXmlNode* spanNode =
appendNode( drillNode,
"Span" );
2451 wxXmlNode* drillNode =
appendNode( aCadLayerNode,
"Layer" );
2452 drillNode->AddAttribute(
"name",
genLayersString( layers.first, layers.second,
"SLOT" ) );
2458 wxXmlNode* spanNode =
appendNode( drillNode,
"Span" );
2479 std::vector<std::tuple<auxLayerType, PCB_LAYER_ID, PCB_LAYER_ID>> new_layers;
2501 for(
auto& tuple : new_layers )
2507 bool add_node =
true;
2510 wxString layerFunction;
2513 switch( std::get<0>(layers) )
2517 layerFunction =
"COATINGNONCOND";
2521 layerFunction =
"HOLEFILL";
2525 layerFunction =
"COATINGNONCOND";
2529 layerFunction =
"HOLEFILL";
2533 layerFunction =
"COATINGCOND";
2541 if( add_node && !vec.empty() )
2543 wxXmlNode* node =
appendNode( aCadLayerNode,
"Layer" );
2557 const bool first_external = std::get<1>( layers ) ==
F_Cu || std::get<1>( layers ) ==
B_Cu;
2558 const bool second_external = std::get<2>( layers ) ==
F_Cu || std::get<2>( layers ) ==
B_Cu;
2560 if( first_external )
2562 if( second_external )
2569 if( second_external )
2575 wxXmlNode* spanNode =
appendNode( node,
"Span" );
2586 wxXmlNode* stepNode =
appendNode( aCadNode,
"Step" );
2588 wxFileName fn(
m_board->GetFileName() );
2594 wxXmlNode* datumNode =
appendNode( stepNode,
"Datum" );
2598 if(
included( IPC2581::SECTION::PROFILE ) )
2610 wxString::Format(
"%zu",
m_board->Footprints().size() ) );
2613 if(
included( IPC2581::SECTION::LOGICAL_NET ) )
2616 if(
included( IPC2581::SECTION::PHYSICAL_NET ) )
2627 wxXmlNode* padNode =
appendNode( aContentNode,
"Pad" );
2634 wxXmlNode* xformNode =
appendNode( padNode,
"Xform" );
2641 addShape( padNode, *aPad, aLayer );
2645 wxXmlNode* pinRefNode =
appendNode( padNode,
"PinRef" );
2659 wxXmlNode* padNode =
appendNode( aContentNode,
"Pad" );
2681 addAttribute( aPadNode,
"padstackDefRef", th_pair->second );
2685 if( !success || !
included( IPC2581::SECTION::PADSTACKS ) )
2688 wxXmlNode* padStackDefNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"PadStackDef" );
2713 wxXmlNode* padStackHoleNode =
appendNode( padStackDefNode,
"PadstackHoleDef" );
2714 padStackHoleNode->AddAttribute(
"name",
2715 wxString::Format(
"%s%d_%d",
2739 wxXmlNode* padStackPadDefNode =
appendNode( padStackDefNode,
"PadstackPadDef" );
2741 addAttribute( padStackPadDefNode,
"padUse",
"REGULAR" );
2749 addShape( padStackPadDefNode, shape );
2753 addShape( padStackPadDefNode, *aPad, layer );
2768 addAttribute( aContentNode,
"padstackDefRef", via_pair->second );
2772 if( !success || !
included( IPC2581::SECTION::PADSTACKS ) )
2775 wxXmlNode* padStackDefNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"PadStackDef" );
2786 wxXmlNode* padStackHoleNode =
appendNode( padStackDefNode,
"PadstackHoleDef" );
2789 addAttribute( padStackHoleNode,
"platingStatus",
"VIA" );
2797 auto addPadShape{ [&](
PCB_LAYER_ID aLayer,
const PCB_VIA* aViaShape,
const wxString& aLayerRef,
2798 bool aDrill ) ->
void
2803 shape.
SetEnd( {
KiROUND( aViaShape->GetDrillValue() / 2.0 ), 0 } );
2805 shape.
SetEnd( {
KiROUND( aViaShape->GetWidth( aLayer ) / 2.0 ), 0 } );
2807 wxXmlNode* padStackPadDefNode =
2808 appendNode( padStackDefNode,
"PadstackPadDef" );
2809 addAttribute( padStackPadDefNode,
"layerRef", aLayerRef );
2810 addAttribute( padStackPadDefNode,
"padUse",
"REGULAR" );
2813 addShape( padStackPadDefNode, shape );
2827 if( !op || !
included( IPC2581::SECTION::MISC_FAB ) )
2847 addPadShape( layer, aVia,
genLayerString( layer,
"PLUGGING" ),
true );
2850 addPadShape( layer, aVia,
genLayerString( layer,
"COVERING" ),
false );
2853 addPadShape( layer, aVia,
genLayerString( layer,
"TENTING" ),
false );
2862 if( aCadUnits == wxT(
"MILLIMETER" ) )
2865 if( aCadUnits == wxT(
"MICRON" ) )
2866 return wxT(
"MICRON" );
2868 if( aCadUnits == wxT(
"INCH" ) )
2869 return wxT(
"INCH" );
2886 && ( aDrill.size.x > 0 || aDrill.size.y > 0 );
2901 && ( !layerHasRef( secondary.
start ) || !layerHasRef( secondary.
end ) ) )
2907 && ( !layerHasRef( tertiary.
start ) || !layerHasRef( tertiary.
end ) ) )
2914 LSEQ cuStack =
m_board->GetEnabledLayers().CuStack();
2917 const wxString& aSpecName ) -> wxString
2935 wxXmlNode* bd =
appendNode( specNode,
"Backdrill" );
2939 addAttribute( p,
"layerOrGroupRef", startLayer->second );
2945 wxXmlNode* bd =
appendNode( specNode,
"Backdrill" );
2946 addAttribute( bd,
"type", wxT(
"MUST_NOT_CUT_LAYER" ) );
2949 addAttribute( p,
"layerOrGroupRef", mustNotCutEntry->second );
2959 wxXmlNode* bd =
appendNode( specNode,
"Backdrill" );
2974 wxString secondarySpec = createSpec( secondary, wxString::Format( wxT(
"BD_%dA" ), specIndex ) );
2975 wxString tertiarySpec = createSpec( tertiary, wxString::Format( wxT(
"BD_%dB" ), specIndex ) );
2977 if( secondarySpec.IsEmpty() && tertiarySpec.IsEmpty() )
2982 std::array<wxString, 2>{ secondarySpec, tertiarySpec } );
2993 auto addRef = [&](
const wxString& aSpecName )
2995 if( aSpecName.IsEmpty() )
2998 wxXmlNode* specRefNode =
appendNode( aHoleNode,
"SpecRef" );
3003 for(
const wxString& specName : it->second )
3018 if( aMachining.
m_Size <= 0 || ( !countersink && !counterbore ) )
3021 auto key = std::make_tuple( aFront,
static_cast<int>( aMachining.
m_Mode ), aMachining.
m_Size,
3022 counterbore ? aMachining.
m_Depth : 0, countersink ? aMachining.
m_Angle : 0 );
3027 it->second = wxString::Format( countersink ? wxT(
"CSK_%zu" ) : wxT(
"CBORE_%zu" ),
3032 auto addValue = [&](
const wxString& aType,
const wxString& aValue,
const wxString& aUnit )
3034 wxXmlNode* drill =
appendNode( spec,
"SecondaryDrill" );
3036 wxXmlNode*
property =
appendNode( drill,
"Property" );
3044 if( counterbore && aMachining.
m_Depth > 0 )
3047 if( countersink && aMachining.
m_Angle > 0 )
3048 addValue( wxT(
"ANGLE" ),
floatVal( aMachining.
m_Angle / 10.0 ), wxT(
"DEGREES" ) );
3050 wxXmlNode* side =
appendNode( spec,
"SecondaryDrill" );
3052 wxXmlNode*
property =
appendNode( side,
"Property" );
3053 addAttribute( property,
"text", aFront ? wxT(
"TOP" ) : wxT(
"BOTTOM" ) );
3055 if( ( counterbore && aMachining.
m_Depth <= 0 ) || ( countersink && aMachining.
m_Angle <= 0 ) )
3057 wxXmlNode* other =
appendNode( spec,
"SecondaryDrill" );
3059 addAttribute( other,
"comment", counterbore ? wxT(
"COUNTERBORE" ) : wxT(
"COUNTERSINK" ) );
3063 wxXmlNode* ref =
appendNode( aHoleNode,
"SpecRef" );
3083 wxXmlNode* specNode = it->second;
3105 wxXmlNode* polygonNode =
nullptr;
3113 polygonNode =
appendNode( aParentNode,
"Polygon" );
3114 wxXmlNode* polybeginNode =
appendNode( polygonNode,
"PolyBegin" );
3116 const std::vector<VECTOR2I>& pts = aPolygon.
CPoints();
3117 addXY( polybeginNode, pts[0] );
3119 for(
size_t ii = 1; ii < pts.size(); ++ii )
3121 wxXmlNode* polyNode =
appendNode( polygonNode,
"PolyStepSegment" );
3122 addXY( polyNode, pts[ii] );
3125 wxXmlNode* polyendNode =
appendNode( polygonNode,
"PolyStepSegment" );
3126 addXY( polyendNode, pts[0] );
3137 addLineDesc( polygonNode, aWidth, aDashType,
true );
3141 wxCHECK( aWidth == 0,
false );
3154 for(
size_t ii = 1; ii < aPolygon.size(); ++ii )
3156 wxCHECK2( aPolygon[ii].PointCount() >= 3,
continue );
3158 wxXmlNode* cutoutNode =
appendNode( aParentNode,
"Cutout" );
3159 wxXmlNode* polybeginNode =
appendNode( cutoutNode,
"PolyBegin" );
3161 const std::vector<VECTOR2I>& hole = aPolygon[ii].CPoints();
3162 addXY( polybeginNode, hole[0] );
3164 for(
size_t jj = 1; jj < hole.size(); ++jj )
3166 wxXmlNode* polyNode =
appendNode( cutoutNode,
"PolyStepSegment" );
3167 addXY( polyNode, hole[jj] );
3170 wxXmlNode* polyendNode =
appendNode( cutoutNode,
"PolyStepSegment" );
3171 addXY( polyendNode, hole[0] );
3184 wxXmlNode* outlineNode =
appendNode( aParentNode,
"Outline" );
3198 for(
int ii = 0; ii <
source->OutlineCount(); ++ii )
3201 wxLogTrace(
traceIpc2581, wxS(
"Failed to add polygon to outline" ) );
3204 if( !outlineNode->GetChildren() )
3206 aParentNode->RemoveChild( outlineNode );
3223 wxXmlNode* contourNode =
appendNode( aParentNode,
"Contour" );
3233 aParentNode->RemoveChild( contourNode );
3246 if( !
m_board->GetBoardPolygonOutlines( board_outline,
false ) || board_outline.
OutlineCount() == 0 )
3252 wxXmlNode* profileNode =
appendNode( aStepNode,
"Profile" );
3256 wxLogTrace(
traceIpc2581, wxS(
"Failed to add polygon to profile" ) );
3257 aStepNode->RemoveChild( profileNode );
3283 std::unique_ptr<FOOTPRINT> fp(
static_cast<FOOTPRINT*
>( aFp->
Clone() ) );
3284 fp->SetParentGroup(
nullptr );
3285 fp->SetPosition( { 0, 0 } );
3286 fp->SetOrientation(
ANGLE_0 );
3291 bool wasFlipped = fp->IsFlipped();
3294 if( fp->IsFlipped() )
3299 fp->GetFPID().GetLibItemName().wx_str(),
3305 addAttribute( aContentNode,
"packageRef", iter->second );
3309 if( !success || !
included( IPC2581::SECTION::PACKAGES ) )
3314 wxXmlNode* packageNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"Package" );
3315 wxXmlNode* otherSideViewNode =
nullptr;
3321 if( fp->FindPadByNumber(
"1" ) )
3323 else if ( fp->FindPadByNumber(
"A1" ) )
3325 else if ( fp->FindPadByNumber(
"A" ) )
3327 else if ( fp->FindPadByNumber(
"a" ) )
3329 else if ( fp->FindPadByNumber(
"a1" ) )
3331 else if ( fp->FindPadByNumber(
"Anode" ) )
3333 else if ( fp->FindPadByNumber(
"ANODE" ) )
3340 PAD* pinOnePad = fp->FindPadByNumber(
"1" );
3343 pinOnePad = fp->FindPadByNumber(
"A1" );
3345 if( pinOnePad && fp->Pads().size() >= 2 )
3348 BOX2I fpBBox = fp->GetBoundingBox();
3358 const char* orientation =
"OTHER";
3360 if( onCenterX && onCenterY )
3361 orientation =
"CENTER";
3362 else if( onCenterX && pinPos.
y <
center.y )
3363 orientation =
"UPPER_CENTER";
3364 else if( onCenterX && pinPos.
y >
center.y )
3365 orientation =
"LOWER_CENTER";
3366 else if( onCenterY && pinPos.
x <
center.x )
3367 orientation =
"LEFT";
3368 else if( onCenterY && pinPos.
x >
center.x )
3369 orientation =
"RIGHT";
3371 orientation =
"UPPER_LEFT";
3373 orientation =
"UPPER_RIGHT";
3375 orientation =
"LOWER_LEFT";
3377 orientation =
"LOWER_RIGHT";
3379 addAttribute( packageNode,
"pinOneOrientation", orientation );
3383 addAttribute( packageNode,
"pinOneOrientation",
"OTHER" );
3384 addAttribute( packageNode,
"comment",
"Pin 1 orientation could not be determined" );
3390 : fp->GetCourtyard(
F_CrtYd );
3392 : fp->GetCourtyard(
B_CrtYd );
3409 otherSideViewNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"OtherSideView" );
3415 wxXmlNode* pickupPointNode =
appendNode( packageNode,
"PickupPoint" );
3419 std::map<PCB_LAYER_ID, std::map<bool, std::vector<BOARD_ITEM*>>> elements;
3421 for(
BOARD_ITEM* item : fp->GraphicalItems() )
3446 elements[item->GetLayer()][is_abs].push_back( item );
3449 auto add_base_node =
3452 wxXmlNode* parent = packageNode;
3461 bool is_other_side = wasFlipped ? ( aLayer ==
F_SilkS || aLayer ==
F_Fab )
3466 if( !otherSideViewNode )
3467 otherSideViewNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"OtherSideView" );
3469 parent = otherSideViewNode;
3476 else if( aLayer ==
F_Fab || aLayer ==
B_Fab )
3485 auto add_marking_node =
3486 [&]( wxXmlNode* aNode ) -> wxXmlNode*
3488 wxXmlNode* marking_node =
appendNode( aNode,
"Marking" );
3490 return marking_node;
3493 std::map<PCB_LAYER_ID, wxXmlNode*> layer_nodes;
3494 std::map<PCB_LAYER_ID, BOX2I> layer_bbox;
3498 if( elements.find( layer ) != elements.end() )
3500 if( elements[layer][
true].size() > 0 )
3501 layer_bbox[layer] = elements[layer][
true][0]->GetBoundingBox();
3502 else if( elements[layer][
false].size() > 0 )
3503 layer_bbox[layer] = elements[layer][
false][0]->GetBoundingBox();
3507 for(
auto& [layer, map] : elements )
3509 wxXmlNode* layer_node = add_base_node( layer );
3510 wxXmlNode* marking_node = add_marking_node( layer_node );
3511 wxXmlNode* group_node =
appendNode( marking_node,
"UserSpecial" );
3512 bool update_bbox =
false;
3516 layer_nodes[layer] = layer_node;
3520 for(
auto& [is_abs, vec] : map )
3524 wxXmlNode* output_node =
nullptr;
3527 layer_bbox[layer].Merge( item->GetBoundingBox() );
3530 output_node = add_marking_node( layer_node );
3532 output_node = group_node;
3534 switch( item->Type() )
3540 if(
text->IsKnockout() )
3554 if(
text->IsBorderEnabled() )
3557 text->GetEffectiveShape()->TransformToPolygon( poly_set, 0,
ERROR_INSIDE );
3559 text->GetBorderWidth() );
3582 if( group_node->GetChildren() ==
nullptr )
3584 marking_node->RemoveChild( group_node );
3585 layer_node->RemoveChild( marking_node );
3587 delete marking_node;
3591 for(
auto&[layer, bbox] : layer_bbox )
3593 if( bbox.GetWidth() > 0 )
3595 wxXmlNode* outlineNode =
insertNode( layer_nodes[layer],
"Outline" );
3598 std::vector<VECTOR2I> points( 4 );
3599 points[0] = bbox.GetPosition();
3600 points[2] = bbox.GetEnd();
3601 points[1].x = points[0].x;
3602 points[1].y = points[2].y;
3603 points[3].x = points[2].x;
3604 points[3].y = points[0].y;
3606 outline.
Append( points );
3612 std::map<wxString, wxXmlNode*> pin_nodes;
3614 for(
size_t ii = 0; ii < fp->Pads().size(); ++ii )
3616 PAD*
pad = fp->Pads()[ii];
3619 wxXmlNode* pinNode =
nullptr;
3621 auto [ it, inserted ] = pin_nodes.emplace( pin_name,
nullptr );
3626 it->second = pinNode;
3637 if(
pad->HasHole() )
3642 if(
pad->GetFPRelativeOrientation() !=
ANGLE_0 )
3644 wxXmlNode* xformNode =
appendNode( pinNode,
"Xform" );
3645 EDA_ANGLE pad_angle =
pad->GetFPRelativeOrientation().Normalize();
3647 if( fp->IsFlipped() )
3664 if( otherSideViewNode )
3665 packageNode->AddChild( otherSideViewNode );
3673 std::vector<wxXmlNode*> componentNodes;
3674 std::vector<wxXmlNode*> packageNodes;
3675 std::set<wxString> packageNames;
3677 bool generate_unique =
m_OEMRef.empty();
3689 wxXmlNode* componentNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"Component" );
3695 for(
PAD*
pad : fp->Pads() )
3697 if(
pad->GetNetCode() > 0 )
3700 wxXmlNode* pkg =
addPackage( componentNode, fp );
3703 packageNodes.push_back( pkg );
3707 if(
name.IsEmpty() )
3709 name = wxString::Format(
"%s_%s_%s",
3710 fp->GetFPID().GetFullLibraryName(),
3711 fp->GetFPID().GetLibItemName().wx_str(),
3717 Report(
_(
"Duplicate footprint pointers encountered; IPC-2581 output may be incorrect." ),
3731 if( fp->GetOrientation() !=
ANGLE_0 || fp->IsFlipped() )
3733 wxXmlNode* xformNode =
appendNode( componentNode,
"Xform" );
3737 if( fp->IsFlipped() )
3743 if( fp->IsFlipped() )
3747 addLocationNode( componentNode, fp->GetPosition().x, fp->GetPosition().y );
3749 componentNodes.push_back( componentNode );
3755 [&]( std::vector<wxXmlNode*>& aNodes,
IPC2581::SECTION aSection,
bool aInsert )
3759 for( wxXmlNode*& node : aNodes )
3772 aStepNode->AddChild( node );
3780 attachOrDrop(
m_padstacks, IPC2581::SECTION::PADSTACKS,
true );
3781 attachOrDrop( packageNodes, IPC2581::SECTION::PACKAGES,
false );
3782 attachOrDrop( componentNodes, IPC2581::SECTION::COMPONENTS,
false );
3792 wxXmlNode* netNode =
appendNode( aStepNode,
"LogicalNet" );
3794 netName(
m_board->GetNetInfo().GetNetItem( net )->GetNetname() ) ) ;
3796 for(
auto& [cmp,
pin] : pin_pair )
3798 wxXmlNode* netPinNode =
appendNode( netNode,
"PinRef" );
3816 wxString m_exposure;
3824 std::map<int, std::vector<NET_POINT>> byNet;
3837 bool frontOpen = !aPoint.m_front || aPoint.m_frontMask;
3838 bool backOpen = !aPoint.m_back || aPoint.m_backMask;
3840 if( frontOpen && backOpen )
3841 return wxT(
"EXPOSED" );
3844 return wxT(
"COVERED_PRIMARY" );
3847 return wxT(
"COVERED_SECONDARY" );
3849 return wxT(
"COVERED" );
3853 for(
bool wantPad : {
true,
false } )
3858 if( ( testPoint.m_pad !=
nullptr ) != wantPad || testPoint.m_netCode <= 0
3859 || ( !testPoint.m_front && !testPoint.m_back ) )
3865 point.m_pos = testPoint.m_position;
3866 point.m_layer = testPoint.m_front ?
F_Cu :
B_Cu;
3868 point.m_exposure = exposure( testPoint );
3869 point.m_end = testPoint.m_netEnd;
3870 point.m_via = testPoint.m_via !=
nullptr;
3871 point.m_width = testPoint.m_pad ? testPoint.m_pad->GetSize( point.m_layer ).x
3872 : testPoint.m_via->GetWidth( point.m_layer );
3873 point.m_drill = testPoint.m_drill;
3874 point.m_pad = testPoint.m_pad;
3875 byNet[testPoint.m_netCode].push_back( point );
3883 wxXmlNode* groupNode =
appendNode( aStepNode,
"PhyNetGroup" );
3886 for(
const auto& [netcode, points] : byNet )
3895 wxXmlNode* netNode =
appendNode( groupNode,
"PhyNet" );
3898 for(
const NET_POINT& point : points )
3900 wxXmlNode* pointNode =
appendNode( netNode,
"PhyNetPoint" );
3901 addXY( pointNode, point.m_pos );
3910 addAttribute( pointNode,
"netNode", point.m_end ?
"END" :
"MIDDLE" );
3911 addAttribute( pointNode,
"exposure", point.m_exposure );
3918 addShape( pointNode, *point.m_pad, point.m_layer );
3923 dummy.SetPosition( point.m_pos );
3924 dummy.SetSize( point.m_layer,
VECTOR2I( point.m_width, point.m_width ) );
3926 if( point.m_drill > 0 )
3927 dummy.SetDrillSize(
VECTOR2I( point.m_drill, point.m_drill ) );
3951 wxXmlNode* layerNode =
appendNode( aStepNode,
"LayerFeature" );
3956 auto process_net = [&] (
int net )
3958 auto netItems = netsOnLayer.find( net );
3960 if( netItems == netsOnLayer.end() || netItems->second.empty() )
3968 tickProgress( wxString::Format(
_(
"Exporting layer %s, net %s" ),
3969 m_board->GetLayerName( layer ),
3970 net->GetNetname() ) );
3972 process_net( net->GetNetCode() );
3975 if( layerNode->GetChildren() ==
nullptr )
3977 aStepNode->RemoveChild( layerNode );
3986 if( !
included( IPC2581::SECTION::DRILL_ROUT ) )
3993 wxXmlNode* layerNode =
appendNode( aLayerNode,
"LayerFeature" );
3994 layerNode->AddAttribute(
"layerRef",
genLayersString( span.TopLayer(), span.BottomLayer(),
"DRILL" ) );
4010 Report(
_(
"Via uses unsupported padstack; omitted from drill data." ),
4015 wxXmlNode* padNode =
appendNode( layerNode,
"Set" );
4018 if(
via->GetNetCode() > 0 )
4021 wxXmlNode* holeNode =
appendNode( padNode,
"Hole" );
4022 addAttribute( holeNode,
"name", wxString::Format(
"H%d", hole_count++ ) );
4027 addXY( holeNode,
via->GetPosition() );
4043 Report(
_(
"Pad uses unsupported padstack; hole was omitted from drill data." ),
4048 wxXmlNode* padNode =
appendNode( layerNode,
"Set" );
4051 if(
pad->GetNetCode() > 0 )
4054 wxXmlNode* holeNode =
appendNode( padNode,
"Hole" );
4055 addAttribute( holeNode,
"name", wxString::Format(
"H%d", hole_count++ ) );
4061 addXY( holeNode,
pad->GetPosition() );
4072 wxXmlNode* layerNode =
appendNode( aLayerNode,
"LayerFeature" );
4073 layerNode->AddAttribute(
"layerRef",
genLayersString( layers.first, layers.second,
"SLOT" ) );
4077 wxXmlNode* padNode =
appendNode( layerNode,
"Set" );
4079 if(
pad->GetNetCode() > 0 )
4082 addSlotCavity( padNode, *
pad, wxString::Format(
"SLOT%d", hole_count++ ) );
4085 DRILL_SPAN span( layers.first, layers.second,
false,
false );
4095 const std::vector<BOARD_ITEM*>& aItems )
4097 auto it = aItems.begin();
4098 wxXmlNode* layerSetNode =
appendNode( aLayerNode,
"Set" );
4099 wxXmlNode* featureSetNode =
appendNode( layerSetNode,
"Features" );
4100 wxXmlNode* specialNode =
appendNode( featureSetNode,
"UserSpecial" );
4102 bool has_via =
false;
4103 bool has_pad =
false;
4105 wxXmlNode* padSetNode =
nullptr;
4107 wxXmlNode* viaSetNode =
nullptr;
4109 wxXmlNode* teardropLayerSetNode =
nullptr;
4110 wxXmlNode* teardropFeatureSetNode =
nullptr;
4112 bool teardrop_warning =
false;
4117 if( item->GetNetCode() > 0 )
4127 shape.
SetStart( track->GetStart() );
4128 shape.
SetEnd( track->GetEnd() );
4149 shape.
SetStart( track->GetStart() );
4150 shape.
SetEnd( track->GetEnd() );
4161 viaSetNode = layerSetNode;
4166 viaSetNode =
appendNode( layerSetNode,
"Set" );
4168 if( track->GetNetCode() > 0 )
4175 addVia( viaSetNode,
static_cast<PCB_VIA*
>( track ), aLayer );
4182 wxXmlNode* zoneFeatureNode = specialNode;
4184 if( zone->IsTeardropArea() )
4188 if( !teardropFeatureSetNode )
4190 teardropLayerSetNode =
appendNode( aLayerNode,
"Set" );
4191 addAttribute( teardropLayerSetNode,
"geometryUsage",
"TEARDROP" );
4193 if( zone->GetNetCode() > 0 )
4196 wxXmlNode* new_teardrops =
appendNode( teardropLayerSetNode,
"Features" );
4198 teardropFeatureSetNode =
appendNode( new_teardrops,
"UserSpecial" );
4201 zoneFeatureNode = teardropFeatureSetNode;
4203 else if( !teardrop_warning )
4205 Report(
_(
"Teardrops are not supported in IPC-2581 revision B; they were exported as zones." ),
4207 teardrop_warning =
true;
4214 wxXmlNode* tempSetNode =
appendNode( aLayerNode,
"Set" );
4220 wxXmlNode* newFeatures =
appendNode( tempSetNode,
"Features" );
4222 zoneFeatureNode =
appendNode( newFeatures,
"UserSpecial" );
4226 SHAPE_POLY_SET& zone_shape = *zone->GetFilledPolysList( aLayer );
4228 for(
int ii = 0; ii < zone_shape.
OutlineCount(); ++ii )
4244 wxXmlNode* tempSetNode =
appendNode( aLayerNode,
"Set" );
4247 addAttribute( tempSetNode,
"geometryUsage",
"GRAPHIC" );
4249 bool link_to_component =
true;
4252 link_to_component =
false;
4254 if( link_to_component )
4260 wxXmlNode* tempFeature =
appendNode( tempSetNode,
"Features" );
4269 wxXmlNode* tempSetNode =
appendNode( aLayerNode,
"Set" );
4276 wxXmlNode* tempFeature =
appendNode( tempSetNode,
"Features" );
4293 text_item =
static_cast<EDA_TEXT*
>( pcb_text );
4295 text_item =
static_cast<EDA_TEXT*
>( pcb_textbox );
4297 if( !text_item || !text_item->
IsVisible() )
4302 if( content.empty() )
4305 bool isWhitespace = content.Strip( wxString::both ).empty();
4309 if( isWhitespace && !isKnockout && !hasBorder )
4312 wxXmlNode* tempSetNode =
appendNode( aLayerNode,
"Set" );
4317 bool link_to_component = fp !=
nullptr;
4320 link_to_component =
false;
4322 if( link_to_component )
4328 wxXmlNode* nonStandardAttributeNode =
appendNode( tempSetNode,
"NonstandardAttribute" );
4329 addAttribute( nonStandardAttributeNode,
"name",
"TEXT" );
4330 addAttribute( nonStandardAttributeNode,
"value", content );
4331 addAttribute( nonStandardAttributeNode,
"type",
"STRING" );
4333 if( !isWhitespace || isKnockout )
4335 wxXmlNode* glyphFeature =
appendNode( tempSetNode,
"Features" );
4341 addText( glyphFeature, text_item,
text->GetFontMetrics() );
4347 wxXmlNode* borderFeature =
appendNode( tempSetNode,
"Features" );
4350 addShape( borderFeature, *border );
4361 padSetNode = layerSetNode;
4366 padSetNode =
appendNode( aLayerNode,
"Set" );
4368 if(
pad->GetNetCode() > 0 )
4378 switch( item->Type() )
4383 add_track(
static_cast<PCB_TRACK*
>( item ) );
4391 add_pad(
static_cast<PAD*
>( item ) );
4395 add_shape(
static_cast<PCB_SHAPE*
>( item ) );
4420 if( specialNode->GetChildren() ==
nullptr )
4422 featureSetNode->RemoveChild( specialNode );
4426 if( featureSetNode->GetChildren() ==
nullptr )
4428 layerSetNode->RemoveChild( featureSetNode );
4432 if( layerSetNode->GetChildren() ==
nullptr )
4434 aLayerNode->RemoveChild( layerSetNode );
4441 if( !
included( IPC2581::SECTION::MISC_FAB ) )
4446 bool add_node =
true;
4452 switch( std::get<0>(layers) )
4481 wxXmlNode* layerNode =
appendNode( aStepNode,
"LayerFeature" );
4489 layerNode->AddAttribute(
"layerRef",
genLayersString( std::get<1>( layers ),
4493 wxXmlNode* setNode =
appendNode( layerNode,
"Set" );
4507 shape.
SetEnd( {
KiROUND(
via->GetWidth( std::get<1>( layers ) ) / 2.0 ), 0 } );
4509 wxXmlNode* padNode =
appendNode( setNode,
"Pad" );
4521 if( !
included( IPC2581::SECTION::BOM_AVL ) )
4534 wxXmlNode* header =
appendNode( avl,
"AvlHeader" );
4538 addAttribute( header,
"datetime", wxDateTime::Now().FormatISOCombined() );
4541 std::set<wxString> unique_parts;
4542 std::map<wxString,wxString> unique_vendors;
4543 std::vector<FOOTPRINT*> footprints;
4544 std::vector<AVL_ROW> rows;
4553 footprints.push_back( fp );
4554 rows.push_back( { it->second, fp->GetReference() } );
4560 const wxString&
name = rows[
index].m_oemName;
4561 auto [ it, success ] = unique_parts.insert(
name );
4566 wxXmlNode* part =
appendNode( avl,
"AvlItem" );
4573 for (
int ii = 0; ii < 2; ++ii )
4579 if( mpn_name.empty() )
4582 wxXmlNode* vmpn =
appendNode( part,
"AvlVmpn" );
4586 wxXmlNode* mpn =
appendNode( vmpn,
"AvlMpn" );
4589 wxXmlNode* vendor =
appendNode( vmpn,
"AvlVendor" );
4591 wxString vendor_name = wxT(
"UNKNOWN" );
4594 if( !ii && company[ii] )
4602 else if( !ii && !company_name[ii].
empty() )
4604 vendor_name = company_name[ii];
4606 else if( ii && !
m_dist.empty() )
4611 auto [vendor_id, inserted] = unique_vendors.emplace(
4613 wxString::Format(
"VENDOR_%zu", unique_vendors.size() ) );
4615 addAttribute( vendor,
"enterpriseRef", vendor_id->second );
4619 wxXmlNode* new_vendor =
new wxXmlNode( wxXML_ELEMENT_NODE,
"Enterprise" );
4635 const std::map<std::string, UTF8>* aProperties )
4695 const std::map<std::string, UTF8> emptyProperties;
4698 aProperties = &emptyProperties;
4700 if(
auto it = aProperties->find(
"variant" ); it != aProperties->end() )
4703 if(
auto it = aProperties->find(
"units" ); it != aProperties->end() )
4705 if( it->second ==
"inch" )
4712 if(
auto it = aProperties->find(
"sigfig" ); it != aProperties->end() )
4713 m_sigfig = std::stoi( it->second );
4715 if(
auto it = aProperties->find(
"version" ); it != aProperties->end() )
4718 if(
auto it = aProperties->find(
"OEMRef" ); it != aProperties->end() )
4721 if(
auto it = aProperties->find(
"mpn" ); it != aProperties->end() )
4722 m_mpn = it->second.wx_str();
4724 if(
auto it = aProperties->find(
"mfg" ); it != aProperties->end() )
4725 m_mfg = it->second.wx_str();
4727 if(
auto it = aProperties->find(
"dist" ); it != aProperties->end() )
4728 m_dist = it->second.wx_str();
4730 if(
auto it = aProperties->find(
"distpn" ); it != aProperties->end() )
4733 if(
auto it = aProperties->find(
"bomrev" ); it != aProperties->end() )
4736 m_mode = IPC2581::MODE::USERDEF;
4739 if(
auto it = aProperties->find(
"mode" ); it != aProperties->end() )
4744 THROW_IO_ERROR( wxString::Format(
_(
"Unknown IPC-2581 data set '%s'." ),
4745 it->second.wx_str() ) );
4751 if(
auto it = aProperties->find(
"sections" ); it != aProperties->end() )
4755 THROW_IO_ERROR( wxString::Format(
_(
"Invalid IPC-2581 section key '%s'." ),
4756 it->second.wx_str() ) );
4760 if(
auto it = aProperties->find(
"netnames" ); it != aProperties->end() )
4772 if(
auto it = aProperties->find(
"refdes" ); it != aProperties->end() )
4782 for(
char c =
'a'; c <=
'z'; ++c )
4785 for(
char c =
'A'; c <=
'Z'; ++c )
4788 for(
char c =
'0'; c <=
'9'; ++c )
4792 std::string specialChars =
"_\\-.+><";
4794 for(
char c : specialChars )
4805 if( !
included( IPC2581::SECTION::LOGICAL_NET ) )
4808 if( !
included( IPC2581::SECTION::PHYSICAL_NET ) )
4811 if( !
included( IPC2581::SECTION::BOM_AVL ) )
4832 wxXmlNode* insertBefore =
nullptr;
4834 for( wxXmlNode* child =
m_contentNode->GetChildren(); child; child = child->GetNext() )
4836 if( child->GetName().StartsWith(
"Dictionary" ) )
4838 insertBefore = child;
4844 [&](
const wxString& aNodeName, wxXmlNode* aSection )
4849 wxXmlNode* ref =
new wxXmlNode( wxXML_ELEMENT_NODE, aNodeName );
4850 ref->AddAttribute(
"name", aSection->GetAttribute(
"name" ) );
4858 insertRef(
"BomRef", bom_node );
4859 insertRef(
"AvlRef", avl_node );
4873 double written_bytes = 0.0;
4874 double last_yield = 0.0;
4881 auto update_progress = [&](
size_t aBytes )
4883 written_bytes += aBytes;
4884 double percent = written_bytes /
static_cast<double>(
m_total_bytes );
4889 if( last_yield + 0.01 < percent )
4891 last_yield = percent;
4903 wxBufferedOutputStream buffered_stream( out_stream, 1 << 20 );
4905 if( !
m_xml_doc->Save( buffered_stream ) )
4908 buffered_stream.Sync();
constexpr int ARC_HIGH_DEF
constexpr double PCB_IU_PER_MM
Pcbnew IU is 1 nanometer.
static bool hasBackdrill(const PADSTACK &aPadstack)
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,...
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.
int GetDrillDepth(PCB_LAYER_ID aFirstLayer, PCB_LAYER_ID aSecondLayer) const
Calculate the drill depth needed to cut from aFirstLayer /through/ aSecondLayer.
const std::vector< BOARD_STACKUP_ITEM * > & GetList() const
int BuildBoardThicknessFromStackup() const
wxString m_FinishType
The name of external copper finish.
Information pertinent to a Pcbnew printed circuit board.
wxString GetCurrentVariant() const
constexpr size_type GetWidth() const
constexpr const Vec GetCenter() const
constexpr size_type GetHeight() const
KICAD_T Type() const
Returns the type of object.
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 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()
SECTION_SET & Set(SECTION aSection, bool aOn=true)
Board items grouped by authored layer and net, sorted by FabItemLess.
std::map< int, std::vector< BOARD_ITEM * > > NET_ITEMS
Board stackup snapshot synchronized without changing the source board.
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.
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.
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.
unsigned GetNetCount() const
A PADSTACK defines the characteristics of a single or multi-layer pad, in the IPC sense of the word.
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()
DRILL_PROPS & TertiaryDrill()
DRILL_PROPS & SecondaryDrill()
POST_MACHINING_PROPS & BackPostMachining()
A pad's resolved artwork on one fabrication layer.
const SHAPE_POLY_SET & Contour() const
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
bool FlashLayer(int aLayer, bool aOnlyCheckIfPermitted=false) const
Check to see whether the pad should be flashed on the specific layer.
PAD_ATTRIB GetAttribute() const
const wxString & GetNumber() const
VECTOR2I GetPosition() const override
VECTOR2I GetOffset(PCB_LAYER_ID aLayer) const
VECTOR2I GetDrillSize() 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
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 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 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< std::tuple< bool, int, int, int, int >, wxString > m_post_machining_specs
std::map< wxString, wxString > m_net_name_dict
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
void addPostMachiningSpecRefs(wxXmlNode *aHoleNode, const DRILL_OPERATION &aOperation)
std::map< DRILL_SPAN, std::vector< BOARD_ITEM * > > m_drill_layers
std::map< wxString, FOOTPRINT * > m_footprint_refdes_dict
void generateProfile(wxXmlNode *aStepNode)
void generateLayerFeatures(wxXmlNode *aStepNode)
void generateLayerSetNet(wxXmlNode *aLayerNode, PCB_LAYER_ID aLayer, const std::vector< BOARD_ITEM * > &aItems)
bool suppressed(IPC2581::SUPPRESS aWhat) const
wxXmlNode * generateBOMSection(wxXmlNode *aEcadNode)
Creates the BOM section.
wxXmlNode * generateContentStackup(wxXmlNode *aContentNode)
const FAB_DRILL_MODEL * m_fabDrillModel
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)
std::map< wxString, std::set< wxString > > m_element_names
~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.
const FAB_STACKUP * m_fabStackup
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
STROKE_PARAMS GetStroke() const override
void SetStart(const VECTOR2I &aStart) override
void SetArcGeometry(const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd) override
Set the three controlling points for an arc.
VECTOR2I GetPosition() const override
void TransformTextToPolySet(SHAPE_POLY_SET &aBuffer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc) const
Convert the text to a polygonSet describing the actual character strokes (one per segment).
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.
RAII class that sets an value at construction and resets it to the original value at destruction.
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 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
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.
FAB_COMPONENT_ROW MakeFabComponentRow(const FOOTPRINT &aFootprint, const wxString &aVariant)
PCB_LAYER_ID FabBackdrillMustNotCut(const LSEQ &aCopperStack, PCB_LAYER_ID aStart, PCB_LAYER_ID aMustCut)
aMustCut is DRILL_PROPS.end; returns the next enabled copper past it away from aStart,...
int FabTrackWidth(const PCB_TRACK &aTrack, PCB_LAYER_ID aLayer)
Use only for traces and arcs; vias require a layer-specific width.
bool FabMaskShape(const PCB_SHAPE &aShape, PCB_LAYER_ID aLayer, PCB_SHAPE &aResult)
Build an expanded mask copy of an exposed copper shape when needed.
std::map< int, wxString > FabAnonymousNetNames(const BOARD &aBoard)
Anonymous names NET_1 through NET_n keyed and numbered by net code.
PAD_LAYER_GEOMETRY ResolvePadLayer(const PAD &aPad, PCB_LAYER_ID aLayer, int aMaxError)
Artwork on one layer as plotted by PlotStandardLayer; keep the plotter independent as the parity orac...
VECTOR2I ResolvePadMargin(const PAD &aPad, PCB_LAYER_ID aLayer)
Per-side mask or paste margin as PlotStandardLayer applies it.
FAB_PIN MakeFabPin(const PAD &aPad, size_t aIndexInFootprint)
aIndexInFootprint is the pad's position in its footprint, used to name NPTH and unnumbered pads
std::vector< FAB_TEST_POINT > FabTestPoints(const BOARD &aBoard)
The caller must build board connectivity before enumerating net endpoints.
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
#define THROW_IO_CANCELLED()
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.
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
std::vector< size_t > OrderAvlRows(const std::vector< AVL_ROW > &aRows)
Return row indices sorted by OEM name, reference, then input order.
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)
bool IsUserLayer(PCB_LAYER_ID aLayerId)
Test whether a layer is a non copper and a non tech layer.
bool IsFrontLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a front layer.
bool IsCopperLayer(int aLayerId)
Test whether a layer is a 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)
wxString SectionKeyString(const SECTION_SET &aSet)
Give aSet as a sectionKey attribute value.
SECTION
Schema sections of the IPC-2581C function mode table, Table 4 p 80.
bool SectionSetFromKeyString(const wxString &aKey, SECTION_SET &aResult)
Read a sectionKey attribute value Return false for an unknown character.
SECTION_SET RecommendedOptionalSections(MODE aMode)
Optional schema sections that aMode selects by default.
std::optional< MODE > ModeFromToken(const wxString &aToken)
Read a Table 4 function mode token in upper case or in lower case.
wxString ModeToken(MODE aMode)
Table 4 function mode token such as FABRICATION.
bool NeedsCadData(const SECTION_SET &aSet)
True if an included schema section needs an Ecad/CadData element.
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.
@ 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.
std::optional< SECTION > SectionForBoardLayer(PCB_LAYER_ID aLayer)
Schema section that holds the artwork of aLayer.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
@ PTH
Plated through hole pad.
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 size_t ipcPadstackHash(const PCB_VIA *aVia, const DRILL_OPERATION *aOperation)
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)
wxString FormatTrimmedDecimal(double aValue, int aPrecision)
Format a value to aPrecision decimal digits and strip trailing zeros, keeping one digit after the dec...
LINE_STYLE
Dashed line types.
One machining action, which is also one NC hit and one tool assignment.
DRILL_POST_MACHINING m_BackPostMachining
BOARD_ITEM * m_SourceItem
non-owning, valid only for this enumeration
DRILL_POST_MACHINING m_FrontPostMachining
PAD_DRILL_POST_MACHINING_MODE m_Mode
Footprint facts resolved for one assembly variant.
wxString Field(const wxString &aName) const
Variant-resolved shown text, empty when the field is missing.
FAB_ELECTRICAL m_electrical
The properties of a padstack drill.
@ DESCRIPTION
Field Description of part, i.e. "1/4W 1% Metal Film Resistor".
KIBIS top(path, &reporter)
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