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 );
2889 if( !hasBackdrill( secondary ) && !hasBackdrill( tertiary ) )
2900 if( hasBackdrill( secondary )
2901 && ( !layerHasRef( secondary.
start ) || !layerHasRef( secondary.
end ) ) )
2906 if( hasBackdrill( tertiary )
2907 && ( !layerHasRef( tertiary.
start ) || !layerHasRef( tertiary.
end ) ) )
2914 LSEQ cuStack =
m_board->GetEnabledLayers().CuStack();
2917 const wxString& aSpecName ) -> wxString
2919 if( !hasBackdrill( aDrill ) )
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 );
2962 if( dielectric > 0 )
2963 stubLength = dielectric / 2;
2967 wxXmlNode* bd =
appendNode( specNode,
"Backdrill" );
2982 wxString secondarySpec = createSpec( secondary, wxString::Format( wxT(
"BD_%dA" ), specIndex ) );
2983 wxString tertiarySpec = createSpec( tertiary, wxString::Format( wxT(
"BD_%dB" ), specIndex ) );
2985 if( secondarySpec.IsEmpty() && tertiarySpec.IsEmpty() )
2990 std::array<wxString, 2>{ secondarySpec, tertiarySpec } );
3001 auto addRef = [&](
const wxString& aSpecName )
3003 if( aSpecName.IsEmpty() )
3006 wxXmlNode* specRefNode =
appendNode( aHoleNode,
"SpecRef" );
3011 for(
const wxString& specName : it->second )
3026 if( aMachining.
m_Size <= 0 || ( !countersink && !counterbore ) )
3029 auto key = std::make_tuple( aFront,
static_cast<int>( aMachining.
m_Mode ), aMachining.
m_Size,
3030 counterbore ? aMachining.
m_Depth : 0, countersink ? aMachining.
m_Angle : 0 );
3035 it->second = wxString::Format( countersink ? wxT(
"CSK_%zu" ) : wxT(
"CBORE_%zu" ),
3040 auto addValue = [&](
const wxString& aType,
const wxString& aValue,
const wxString& aUnit )
3042 wxXmlNode* drill =
appendNode( spec,
"SecondaryDrill" );
3044 wxXmlNode*
property =
appendNode( drill,
"Property" );
3052 if( counterbore && aMachining.
m_Depth > 0 )
3055 if( countersink && aMachining.
m_Angle > 0 )
3056 addValue( wxT(
"ANGLE" ),
floatVal( aMachining.
m_Angle / 10.0 ), wxT(
"DEGREES" ) );
3058 wxXmlNode* side =
appendNode( spec,
"SecondaryDrill" );
3060 wxXmlNode*
property =
appendNode( side,
"Property" );
3061 addAttribute( property,
"text", aFront ? wxT(
"TOP" ) : wxT(
"BOTTOM" ) );
3063 if( ( counterbore && aMachining.
m_Depth <= 0 ) || ( countersink && aMachining.
m_Angle <= 0 ) )
3065 wxXmlNode* other =
appendNode( spec,
"SecondaryDrill" );
3067 addAttribute( other,
"comment", counterbore ? wxT(
"COUNTERBORE" ) : wxT(
"COUNTERSINK" ) );
3071 wxXmlNode* ref =
appendNode( aHoleNode,
"SpecRef" );
3091 wxXmlNode* specNode = it->second;
3113 wxXmlNode* polygonNode =
nullptr;
3121 polygonNode =
appendNode( aParentNode,
"Polygon" );
3122 wxXmlNode* polybeginNode =
appendNode( polygonNode,
"PolyBegin" );
3124 const std::vector<VECTOR2I>& pts = aPolygon.
CPoints();
3125 addXY( polybeginNode, pts[0] );
3127 for(
size_t ii = 1; ii < pts.size(); ++ii )
3129 wxXmlNode* polyNode =
appendNode( polygonNode,
"PolyStepSegment" );
3130 addXY( polyNode, pts[ii] );
3133 wxXmlNode* polyendNode =
appendNode( polygonNode,
"PolyStepSegment" );
3134 addXY( polyendNode, pts[0] );
3145 addLineDesc( polygonNode, aWidth, aDashType,
true );
3149 wxCHECK( aWidth == 0,
false );
3162 for(
size_t ii = 1; ii < aPolygon.size(); ++ii )
3164 wxCHECK2( aPolygon[ii].PointCount() >= 3,
continue );
3166 wxXmlNode* cutoutNode =
appendNode( aParentNode,
"Cutout" );
3167 wxXmlNode* polybeginNode =
appendNode( cutoutNode,
"PolyBegin" );
3169 const std::vector<VECTOR2I>& hole = aPolygon[ii].CPoints();
3170 addXY( polybeginNode, hole[0] );
3172 for(
size_t jj = 1; jj < hole.size(); ++jj )
3174 wxXmlNode* polyNode =
appendNode( cutoutNode,
"PolyStepSegment" );
3175 addXY( polyNode, hole[jj] );
3178 wxXmlNode* polyendNode =
appendNode( cutoutNode,
"PolyStepSegment" );
3179 addXY( polyendNode, hole[0] );
3192 wxXmlNode* outlineNode =
appendNode( aParentNode,
"Outline" );
3206 for(
int ii = 0; ii <
source->OutlineCount(); ++ii )
3209 wxLogTrace(
traceIpc2581, wxS(
"Failed to add polygon to outline" ) );
3212 if( !outlineNode->GetChildren() )
3214 aParentNode->RemoveChild( outlineNode );
3231 wxXmlNode* contourNode =
appendNode( aParentNode,
"Contour" );
3241 aParentNode->RemoveChild( contourNode );
3254 if( !
m_board->GetBoardPolygonOutlines( board_outline,
false ) || board_outline.
OutlineCount() == 0 )
3260 wxXmlNode* profileNode =
appendNode( aStepNode,
"Profile" );
3264 wxLogTrace(
traceIpc2581, wxS(
"Failed to add polygon to profile" ) );
3265 aStepNode->RemoveChild( profileNode );
3291 std::unique_ptr<FOOTPRINT> fp(
static_cast<FOOTPRINT*
>( aFp->
Clone() ) );
3292 fp->SetParentGroup(
nullptr );
3293 fp->SetPosition( { 0, 0 } );
3294 fp->SetOrientation(
ANGLE_0 );
3299 bool wasFlipped = fp->IsFlipped();
3302 if( fp->IsFlipped() )
3307 fp->GetFPID().GetLibItemName().wx_str(),
3313 addAttribute( aContentNode,
"packageRef", iter->second );
3317 if( !success || !
included( IPC2581::SECTION::PACKAGES ) )
3322 wxXmlNode* packageNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"Package" );
3323 wxXmlNode* otherSideViewNode =
nullptr;
3329 if( fp->FindPadByNumber(
"1" ) )
3331 else if ( fp->FindPadByNumber(
"A1" ) )
3333 else if ( fp->FindPadByNumber(
"A" ) )
3335 else if ( fp->FindPadByNumber(
"a" ) )
3337 else if ( fp->FindPadByNumber(
"a1" ) )
3339 else if ( fp->FindPadByNumber(
"Anode" ) )
3341 else if ( fp->FindPadByNumber(
"ANODE" ) )
3348 PAD* pinOnePad = fp->FindPadByNumber(
"1" );
3351 pinOnePad = fp->FindPadByNumber(
"A1" );
3353 if( pinOnePad && fp->Pads().size() >= 2 )
3356 BOX2I fpBBox = fp->GetBoundingBox();
3366 const char* orientation =
"OTHER";
3368 if( onCenterX && onCenterY )
3369 orientation =
"CENTER";
3370 else if( onCenterX && pinPos.
y <
center.y )
3371 orientation =
"UPPER_CENTER";
3372 else if( onCenterX && pinPos.
y >
center.y )
3373 orientation =
"LOWER_CENTER";
3374 else if( onCenterY && pinPos.
x <
center.x )
3375 orientation =
"LEFT";
3376 else if( onCenterY && pinPos.
x >
center.x )
3377 orientation =
"RIGHT";
3379 orientation =
"UPPER_LEFT";
3381 orientation =
"UPPER_RIGHT";
3383 orientation =
"LOWER_LEFT";
3385 orientation =
"LOWER_RIGHT";
3387 addAttribute( packageNode,
"pinOneOrientation", orientation );
3391 addAttribute( packageNode,
"pinOneOrientation",
"OTHER" );
3392 addAttribute( packageNode,
"comment",
"Pin 1 orientation could not be determined" );
3398 : fp->GetCourtyard(
F_CrtYd );
3400 : fp->GetCourtyard(
B_CrtYd );
3417 otherSideViewNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"OtherSideView" );
3423 wxXmlNode* pickupPointNode =
appendNode( packageNode,
"PickupPoint" );
3427 std::map<PCB_LAYER_ID, std::map<bool, std::vector<BOARD_ITEM*>>> elements;
3429 for(
BOARD_ITEM* item : fp->GraphicalItems() )
3454 elements[item->GetLayer()][is_abs].push_back( item );
3457 auto add_base_node =
3460 wxXmlNode* parent = packageNode;
3469 bool is_other_side = wasFlipped ? ( aLayer ==
F_SilkS || aLayer ==
F_Fab )
3474 if( !otherSideViewNode )
3475 otherSideViewNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"OtherSideView" );
3477 parent = otherSideViewNode;
3484 else if( aLayer ==
F_Fab || aLayer ==
B_Fab )
3493 auto add_marking_node =
3494 [&]( wxXmlNode* aNode ) -> wxXmlNode*
3496 wxXmlNode* marking_node =
appendNode( aNode,
"Marking" );
3498 return marking_node;
3501 std::map<PCB_LAYER_ID, wxXmlNode*> layer_nodes;
3502 std::map<PCB_LAYER_ID, BOX2I> layer_bbox;
3506 if( elements.find( layer ) != elements.end() )
3508 if( elements[layer][
true].size() > 0 )
3509 layer_bbox[layer] = elements[layer][
true][0]->GetBoundingBox();
3510 else if( elements[layer][
false].size() > 0 )
3511 layer_bbox[layer] = elements[layer][
false][0]->GetBoundingBox();
3515 for(
auto& [layer, map] : elements )
3517 wxXmlNode* layer_node = add_base_node( layer );
3518 wxXmlNode* marking_node = add_marking_node( layer_node );
3519 wxXmlNode* group_node =
appendNode( marking_node,
"UserSpecial" );
3520 bool update_bbox =
false;
3524 layer_nodes[layer] = layer_node;
3528 for(
auto& [is_abs, vec] : map )
3532 wxXmlNode* output_node =
nullptr;
3535 layer_bbox[layer].Merge( item->GetBoundingBox() );
3538 output_node = add_marking_node( layer_node );
3540 output_node = group_node;
3542 switch( item->Type() )
3548 if(
text->IsKnockout() )
3562 if(
text->IsBorderEnabled() )
3565 text->GetEffectiveShape()->TransformToPolygon( poly_set, 0,
ERROR_INSIDE );
3567 text->GetBorderWidth() );
3590 if( group_node->GetChildren() ==
nullptr )
3592 marking_node->RemoveChild( group_node );
3593 layer_node->RemoveChild( marking_node );
3595 delete marking_node;
3599 for(
auto&[layer, bbox] : layer_bbox )
3601 if( bbox.GetWidth() > 0 )
3603 wxXmlNode* outlineNode =
insertNode( layer_nodes[layer],
"Outline" );
3606 std::vector<VECTOR2I> points( 4 );
3607 points[0] = bbox.GetPosition();
3608 points[2] = bbox.GetEnd();
3609 points[1].x = points[0].x;
3610 points[1].y = points[2].y;
3611 points[3].x = points[2].x;
3612 points[3].y = points[0].y;
3614 outline.
Append( points );
3620 std::map<wxString, wxXmlNode*> pin_nodes;
3622 for(
size_t ii = 0; ii < fp->Pads().size(); ++ii )
3624 PAD*
pad = fp->Pads()[ii];
3627 wxXmlNode* pinNode =
nullptr;
3629 auto [ it, inserted ] = pin_nodes.emplace( pin_name,
nullptr );
3634 it->second = pinNode;
3645 if(
pad->HasHole() )
3650 if(
pad->GetFPRelativeOrientation() !=
ANGLE_0 )
3652 wxXmlNode* xformNode =
appendNode( pinNode,
"Xform" );
3653 EDA_ANGLE pad_angle =
pad->GetFPRelativeOrientation().Normalize();
3655 if( fp->IsFlipped() )
3672 if( otherSideViewNode )
3673 packageNode->AddChild( otherSideViewNode );
3681 std::vector<wxXmlNode*> componentNodes;
3682 std::vector<wxXmlNode*> packageNodes;
3683 std::set<wxString> packageNames;
3685 bool generate_unique =
m_OEMRef.empty();
3697 wxXmlNode* componentNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"Component" );
3703 for(
PAD*
pad : fp->Pads() )
3705 if(
pad->GetNetCode() > 0 )
3708 wxXmlNode* pkg =
addPackage( componentNode, fp );
3711 packageNodes.push_back( pkg );
3715 if(
name.IsEmpty() )
3717 name = wxString::Format(
"%s_%s_%s",
3718 fp->GetFPID().GetFullLibraryName(),
3719 fp->GetFPID().GetLibItemName().wx_str(),
3725 Report(
_(
"Duplicate footprint pointers encountered; IPC-2581 output may be incorrect." ),
3739 if( fp->GetOrientation() !=
ANGLE_0 || fp->IsFlipped() )
3741 wxXmlNode* xformNode =
appendNode( componentNode,
"Xform" );
3745 if( fp->IsFlipped() )
3751 if( fp->IsFlipped() )
3755 addLocationNode( componentNode, fp->GetPosition().x, fp->GetPosition().y );
3757 componentNodes.push_back( componentNode );
3763 [&]( std::vector<wxXmlNode*>& aNodes,
IPC2581::SECTION aSection,
bool aInsert )
3767 for( wxXmlNode*& node : aNodes )
3780 aStepNode->AddChild( node );
3788 attachOrDrop(
m_padstacks, IPC2581::SECTION::PADSTACKS,
true );
3789 attachOrDrop( packageNodes, IPC2581::SECTION::PACKAGES,
false );
3790 attachOrDrop( componentNodes, IPC2581::SECTION::COMPONENTS,
false );
3800 wxXmlNode* netNode =
appendNode( aStepNode,
"LogicalNet" );
3802 netName(
m_board->GetNetInfo().GetNetItem( net )->GetNetname() ) ) ;
3804 for(
auto& [cmp,
pin] : pin_pair )
3806 wxXmlNode* netPinNode =
appendNode( netNode,
"PinRef" );
3824 wxString m_exposure;
3832 std::map<int, std::vector<NET_POINT>> byNet;
3845 bool frontOpen = !aPoint.m_front || aPoint.m_frontMask;
3846 bool backOpen = !aPoint.m_back || aPoint.m_backMask;
3848 if( frontOpen && backOpen )
3849 return wxT(
"EXPOSED" );
3852 return wxT(
"COVERED_PRIMARY" );
3855 return wxT(
"COVERED_SECONDARY" );
3857 return wxT(
"COVERED" );
3861 for(
bool wantPad : {
true,
false } )
3866 if( ( testPoint.m_pad !=
nullptr ) != wantPad || testPoint.m_netCode <= 0
3867 || ( !testPoint.m_front && !testPoint.m_back ) )
3873 point.m_pos = testPoint.m_position;
3874 point.m_layer = testPoint.m_front ?
F_Cu :
B_Cu;
3876 point.m_exposure = exposure( testPoint );
3877 point.m_end = testPoint.m_netEnd;
3878 point.m_via = testPoint.m_via !=
nullptr;
3879 point.m_width = testPoint.m_pad ? testPoint.m_pad->GetSize( point.m_layer ).x
3880 : testPoint.m_via->GetWidth( point.m_layer );
3881 point.m_drill = testPoint.m_drill;
3882 point.m_pad = testPoint.m_pad;
3883 byNet[testPoint.m_netCode].push_back( point );
3891 wxXmlNode* groupNode =
appendNode( aStepNode,
"PhyNetGroup" );
3894 for(
const auto& [netcode, points] : byNet )
3903 wxXmlNode* netNode =
appendNode( groupNode,
"PhyNet" );
3906 for(
const NET_POINT& point : points )
3908 wxXmlNode* pointNode =
appendNode( netNode,
"PhyNetPoint" );
3909 addXY( pointNode, point.m_pos );
3918 addAttribute( pointNode,
"netNode", point.m_end ?
"END" :
"MIDDLE" );
3919 addAttribute( pointNode,
"exposure", point.m_exposure );
3926 addShape( pointNode, *point.m_pad, point.m_layer );
3931 dummy.SetPosition( point.m_pos );
3932 dummy.SetSize( point.m_layer,
VECTOR2I( point.m_width, point.m_width ) );
3934 if( point.m_drill > 0 )
3935 dummy.SetDrillSize(
VECTOR2I( point.m_drill, point.m_drill ) );
3959 wxXmlNode* layerNode =
appendNode( aStepNode,
"LayerFeature" );
3964 auto process_net = [&] (
int net )
3966 auto netItems = netsOnLayer.find( net );
3968 if( netItems == netsOnLayer.end() || netItems->second.empty() )
3976 tickProgress( wxString::Format(
_(
"Exporting layer %s, net %s" ),
3977 m_board->GetLayerName( layer ),
3978 net->GetNetname() ) );
3980 process_net( net->GetNetCode() );
3983 if( layerNode->GetChildren() ==
nullptr )
3985 aStepNode->RemoveChild( layerNode );
3994 if( !
included( IPC2581::SECTION::DRILL_ROUT ) )
4001 wxXmlNode* layerNode =
appendNode( aLayerNode,
"LayerFeature" );
4002 layerNode->AddAttribute(
"layerRef",
genLayersString( span.TopLayer(), span.BottomLayer(),
"DRILL" ) );
4018 Report(
_(
"Via uses unsupported padstack; omitted from drill data." ),
4023 wxXmlNode* padNode =
appendNode( layerNode,
"Set" );
4026 if(
via->GetNetCode() > 0 )
4029 wxXmlNode* holeNode =
appendNode( padNode,
"Hole" );
4030 addAttribute( holeNode,
"name", wxString::Format(
"H%d", hole_count++ ) );
4035 addXY( holeNode,
via->GetPosition() );
4051 Report(
_(
"Pad uses unsupported padstack; hole was omitted from drill data." ),
4056 wxXmlNode* padNode =
appendNode( layerNode,
"Set" );
4059 if(
pad->GetNetCode() > 0 )
4062 wxXmlNode* holeNode =
appendNode( padNode,
"Hole" );
4063 addAttribute( holeNode,
"name", wxString::Format(
"H%d", hole_count++ ) );
4069 addXY( holeNode,
pad->GetPosition() );
4080 wxXmlNode* layerNode =
appendNode( aLayerNode,
"LayerFeature" );
4081 layerNode->AddAttribute(
"layerRef",
genLayersString( layers.first, layers.second,
"SLOT" ) );
4085 wxXmlNode* padNode =
appendNode( layerNode,
"Set" );
4087 if(
pad->GetNetCode() > 0 )
4090 addSlotCavity( padNode, *
pad, wxString::Format(
"SLOT%d", hole_count++ ) );
4093 DRILL_SPAN span( layers.first, layers.second,
false,
false );
4103 const std::vector<BOARD_ITEM*>& aItems )
4105 auto it = aItems.begin();
4106 wxXmlNode* layerSetNode =
appendNode( aLayerNode,
"Set" );
4107 wxXmlNode* featureSetNode =
appendNode( layerSetNode,
"Features" );
4108 wxXmlNode* specialNode =
appendNode( featureSetNode,
"UserSpecial" );
4110 bool has_via =
false;
4111 bool has_pad =
false;
4113 wxXmlNode* padSetNode =
nullptr;
4115 wxXmlNode* viaSetNode =
nullptr;
4117 wxXmlNode* teardropLayerSetNode =
nullptr;
4118 wxXmlNode* teardropFeatureSetNode =
nullptr;
4120 bool teardrop_warning =
false;
4125 if( item->GetNetCode() > 0 )
4135 shape.
SetStart( track->GetStart() );
4136 shape.
SetEnd( track->GetEnd() );
4157 shape.
SetStart( track->GetStart() );
4158 shape.
SetEnd( track->GetEnd() );
4169 viaSetNode = layerSetNode;
4174 viaSetNode =
appendNode( layerSetNode,
"Set" );
4176 if( track->GetNetCode() > 0 )
4183 addVia( viaSetNode,
static_cast<PCB_VIA*
>( track ), aLayer );
4190 wxXmlNode* zoneFeatureNode = specialNode;
4192 if( zone->IsTeardropArea() )
4196 if( !teardropFeatureSetNode )
4198 teardropLayerSetNode =
appendNode( aLayerNode,
"Set" );
4199 addAttribute( teardropLayerSetNode,
"geometryUsage",
"TEARDROP" );
4201 if( zone->GetNetCode() > 0 )
4204 wxXmlNode* new_teardrops =
appendNode( teardropLayerSetNode,
"Features" );
4206 teardropFeatureSetNode =
appendNode( new_teardrops,
"UserSpecial" );
4209 zoneFeatureNode = teardropFeatureSetNode;
4211 else if( !teardrop_warning )
4213 Report(
_(
"Teardrops are not supported in IPC-2581 revision B; they were exported as zones." ),
4215 teardrop_warning =
true;
4222 wxXmlNode* tempSetNode =
appendNode( aLayerNode,
"Set" );
4228 wxXmlNode* newFeatures =
appendNode( tempSetNode,
"Features" );
4230 zoneFeatureNode =
appendNode( newFeatures,
"UserSpecial" );
4234 SHAPE_POLY_SET& zone_shape = *zone->GetFilledPolysList( aLayer );
4236 for(
int ii = 0; ii < zone_shape.
OutlineCount(); ++ii )
4252 wxXmlNode* tempSetNode =
appendNode( aLayerNode,
"Set" );
4255 addAttribute( tempSetNode,
"geometryUsage",
"GRAPHIC" );
4257 bool link_to_component =
true;
4260 link_to_component =
false;
4262 if( link_to_component )
4268 wxXmlNode* tempFeature =
appendNode( tempSetNode,
"Features" );
4277 wxXmlNode* tempSetNode =
appendNode( aLayerNode,
"Set" );
4284 wxXmlNode* tempFeature =
appendNode( tempSetNode,
"Features" );
4301 text_item =
static_cast<EDA_TEXT*
>( pcb_text );
4303 text_item =
static_cast<EDA_TEXT*
>( pcb_textbox );
4305 if( !text_item || !text_item->
IsVisible() )
4310 if( content.empty() )
4313 bool isWhitespace = content.Strip( wxString::both ).empty();
4317 if( isWhitespace && !isKnockout && !hasBorder )
4320 wxXmlNode* tempSetNode =
appendNode( aLayerNode,
"Set" );
4325 bool link_to_component = fp !=
nullptr;
4328 link_to_component =
false;
4330 if( link_to_component )
4336 wxXmlNode* nonStandardAttributeNode =
appendNode( tempSetNode,
"NonstandardAttribute" );
4337 addAttribute( nonStandardAttributeNode,
"name",
"TEXT" );
4338 addAttribute( nonStandardAttributeNode,
"value", content );
4339 addAttribute( nonStandardAttributeNode,
"type",
"STRING" );
4341 if( !isWhitespace || isKnockout )
4343 wxXmlNode* glyphFeature =
appendNode( tempSetNode,
"Features" );
4349 addText( glyphFeature, text_item,
text->GetFontMetrics() );
4355 wxXmlNode* borderFeature =
appendNode( tempSetNode,
"Features" );
4358 addShape( borderFeature, *border );
4369 padSetNode = layerSetNode;
4374 padSetNode =
appendNode( aLayerNode,
"Set" );
4376 if(
pad->GetNetCode() > 0 )
4386 switch( item->Type() )
4391 add_track(
static_cast<PCB_TRACK*
>( item ) );
4399 add_pad(
static_cast<PAD*
>( item ) );
4403 add_shape(
static_cast<PCB_SHAPE*
>( item ) );
4428 if( specialNode->GetChildren() ==
nullptr )
4430 featureSetNode->RemoveChild( specialNode );
4434 if( featureSetNode->GetChildren() ==
nullptr )
4436 layerSetNode->RemoveChild( featureSetNode );
4440 if( layerSetNode->GetChildren() ==
nullptr )
4442 aLayerNode->RemoveChild( layerSetNode );
4449 if( !
included( IPC2581::SECTION::MISC_FAB ) )
4454 bool add_node =
true;
4460 switch( std::get<0>(layers) )
4489 wxXmlNode* layerNode =
appendNode( aStepNode,
"LayerFeature" );
4497 layerNode->AddAttribute(
"layerRef",
genLayersString( std::get<1>( layers ),
4501 wxXmlNode* setNode =
appendNode( layerNode,
"Set" );
4515 shape.
SetEnd( {
KiROUND(
via->GetWidth( std::get<1>( layers ) ) / 2.0 ), 0 } );
4517 wxXmlNode* padNode =
appendNode( setNode,
"Pad" );
4529 if( !
included( IPC2581::SECTION::BOM_AVL ) )
4542 wxXmlNode* header =
appendNode( avl,
"AvlHeader" );
4546 addAttribute( header,
"datetime", wxDateTime::Now().FormatISOCombined() );
4549 std::set<wxString> unique_parts;
4550 std::map<wxString,wxString> unique_vendors;
4551 std::vector<FOOTPRINT*> footprints;
4552 std::vector<AVL_ROW> rows;
4561 footprints.push_back( fp );
4562 rows.push_back( { it->second, fp->GetReference() } );
4568 const wxString&
name = rows[
index].m_oemName;
4569 auto [ it, success ] = unique_parts.insert(
name );
4574 wxXmlNode* part =
appendNode( avl,
"AvlItem" );
4581 for (
int ii = 0; ii < 2; ++ii )
4587 if( mpn_name.empty() )
4590 wxXmlNode* vmpn =
appendNode( part,
"AvlVmpn" );
4594 wxXmlNode* mpn =
appendNode( vmpn,
"AvlMpn" );
4597 wxXmlNode* vendor =
appendNode( vmpn,
"AvlVendor" );
4599 wxString vendor_name = wxT(
"UNKNOWN" );
4602 if( !ii && company[ii] )
4610 else if( !ii && !company_name[ii].
empty() )
4612 vendor_name = company_name[ii];
4614 else if( ii && !
m_dist.empty() )
4619 auto [vendor_id, inserted] = unique_vendors.emplace(
4621 wxString::Format(
"VENDOR_%zu", unique_vendors.size() ) );
4623 addAttribute( vendor,
"enterpriseRef", vendor_id->second );
4627 wxXmlNode* new_vendor =
new wxXmlNode( wxXML_ELEMENT_NODE,
"Enterprise" );
4643 const std::map<std::string, UTF8>* aProperties )
4703 const std::map<std::string, UTF8> emptyProperties;
4706 aProperties = &emptyProperties;
4708 if(
auto it = aProperties->find(
"variant" ); it != aProperties->end() )
4711 if(
auto it = aProperties->find(
"units" ); it != aProperties->end() )
4713 if( it->second ==
"inch" )
4720 if(
auto it = aProperties->find(
"sigfig" ); it != aProperties->end() )
4721 m_sigfig = std::stoi( it->second );
4723 if(
auto it = aProperties->find(
"version" ); it != aProperties->end() )
4726 if(
auto it = aProperties->find(
"OEMRef" ); it != aProperties->end() )
4729 if(
auto it = aProperties->find(
"mpn" ); it != aProperties->end() )
4730 m_mpn = it->second.wx_str();
4732 if(
auto it = aProperties->find(
"mfg" ); it != aProperties->end() )
4733 m_mfg = it->second.wx_str();
4735 if(
auto it = aProperties->find(
"dist" ); it != aProperties->end() )
4736 m_dist = it->second.wx_str();
4738 if(
auto it = aProperties->find(
"distpn" ); it != aProperties->end() )
4741 if(
auto it = aProperties->find(
"bomrev" ); it != aProperties->end() )
4744 m_mode = IPC2581::MODE::USERDEF;
4747 if(
auto it = aProperties->find(
"mode" ); it != aProperties->end() )
4752 THROW_IO_ERROR( wxString::Format(
_(
"Unknown IPC-2581 data set '%s'." ),
4753 it->second.wx_str() ) );
4759 if(
auto it = aProperties->find(
"sections" ); it != aProperties->end() )
4763 THROW_IO_ERROR( wxString::Format(
_(
"Invalid IPC-2581 section key '%s'." ),
4764 it->second.wx_str() ) );
4768 if(
auto it = aProperties->find(
"netnames" ); it != aProperties->end() )
4780 if(
auto it = aProperties->find(
"refdes" ); it != aProperties->end() )
4790 for(
char c =
'a'; c <=
'z'; ++c )
4793 for(
char c =
'A'; c <=
'Z'; ++c )
4796 for(
char c =
'0'; c <=
'9'; ++c )
4800 std::string specialChars =
"_\\-.+><";
4802 for(
char c : specialChars )
4813 if( !
included( IPC2581::SECTION::LOGICAL_NET ) )
4816 if( !
included( IPC2581::SECTION::PHYSICAL_NET ) )
4819 if( !
included( IPC2581::SECTION::BOM_AVL ) )
4840 wxXmlNode* insertBefore =
nullptr;
4842 for( wxXmlNode* child =
m_contentNode->GetChildren(); child; child = child->GetNext() )
4844 if( child->GetName().StartsWith(
"Dictionary" ) )
4846 insertBefore = child;
4852 [&](
const wxString& aNodeName, wxXmlNode* aSection )
4857 wxXmlNode* ref =
new wxXmlNode( wxXML_ELEMENT_NODE, aNodeName );
4858 ref->AddAttribute(
"name", aSection->GetAttribute(
"name" ) );
4866 insertRef(
"BomRef", bom_node );
4867 insertRef(
"AvlRef", avl_node );
4881 double written_bytes = 0.0;
4882 double last_yield = 0.0;
4889 auto update_progress = [&](
size_t aBytes )
4891 written_bytes += aBytes;
4892 double percent = written_bytes /
static_cast<double>(
m_total_bytes );
4897 if( last_yield + 0.01 < percent )
4899 last_yield = percent;
4911 wxBufferedOutputStream buffered_stream( out_stream, 1 << 20 );
4913 if( !
m_xml_doc->Save( buffered_stream ) )
4916 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,...
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
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.
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.
int GetDrillSizeY() const
PAD_ATTRIB GetAttribute() const
const wxString & GetNumber() const
VECTOR2I GetPosition() const override
VECTOR2I GetOffset(PCB_LAYER_ID aLayer) const
VECTOR2I GetDrillSize() const
int GetDrillSizeX() 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