56#include <wx/numformatter.h>
57#include <wx/xml/xml.h>
78 static_cast<int>( aDrill.end ), aDrill.size.x, aDrill.size.y,
79 static_cast<int>( aDrill.shape ), aDrill.is_capped.has_value(),
80 aDrill.is_capped.value_or(
false ), aDrill.is_filled.has_value(),
81 aDrill.is_filled.value_or(
false ) );
89 aPost.size, aPost.depth, aPost.angle );
193 std::vector<FOOTPRINT*> retval;
196 retval.push_back(
static_cast<FOOTPRINT*
>( fp->Clone() ) );
206 if( aParent->GetChildren() )
207 aNode->SetNext( aParent->GetChildren() );
209 aNode->SetNext(
nullptr );
211 aParent->SetChildren( aNode );
212 aNode->SetParent( aParent );
221 aNode->SetNext( aPrev->GetNext() );
222 aPrev->SetNext( aNode );
223 aNode->SetParent( aPrev->GetParent() );
244 check = check->GetParent();
257 wxXmlNode* node =
new wxXmlNode( wxXML_ELEMENT_NODE, aName );
272 aNode->SetParent( aParent );
277 aParent->AddChild( aNode );
289 wxXmlNode* node =
new wxXmlNode( wxXML_ELEMENT_NODE, aName );
303 str.Replace( wxT(
":" ), wxT(
"_" ) );
307 for( wxString::const_iterator iter = aStr.begin(); iter != aStr.end(); ++iter )
324 wxString key = aPrefix ? wxString( aPrefix ) + wxT(
":" ) + aStr : aStr;
334 wxString
name = base;
338 name = wxString::Format(
"%s_%d", base, suffix++ );
354 const char* aPrefix )
const
356 return genString( wxString::Format( wxS(
"%s_%s" ),
358 m_board->GetLayerName( aBottom ) ), aPrefix );
369 if(
name.empty() && fp )
373 if( fp->
Pads()[ii] == aPad )
381 name = wxString::Format(
"NPTH%zu", ii );
382 else if(
name.empty() )
383 name = wxString::Format(
"PAD%zu", ii );
394 [&](
const wxString& aName )
417 wxString baseName =
genString( ref,
"CMP" );
418 wxString
name = baseName;
421 while( !tryInsert(
name ) )
422 name = wxString::Format(
"%s_%d", baseName, suffix++ );
432 wxString str = wxString::FromCDouble( aVal, aSigFig == -1 ?
m_sigfig : aSigFig );
435 while( str.EndsWith( wxT(
"00" ) ) )
439 if( str == wxT(
"-0.0" ) )
464 aNode->AddAttribute( aName, aValue );
470 wxXmlNode* xmlHeaderNode =
new wxXmlNode(wxXML_ELEMENT_NODE,
"IPC-2581");
472 addAttribute( xmlHeaderNode,
"xmlns",
"http://webstds.ipc.org/2581");
473 addAttribute( xmlHeaderNode,
"xmlns:xsi",
"http://www.w3.org/2001/XMLSchema-instance");
474 addAttribute( xmlHeaderNode,
"xmlns:xsd",
"http://www.w3.org/2001/XMLSchema");
479 "http://webstds.ipc.org/2581 http://webstds.ipc.org/2581/IPC-2581B1.xsd" );
484 "http://webstds.ipc.org/2581 http://webstds.ipc.org/2581/IPC-2581C.xsd" );
489 return xmlHeaderNode;
502 wxXmlNode* node =
appendNode( contentNode,
"FunctionMode" );
510 wxFileName fn(
m_board->GetFileName() );
517 contentNode->AddChild( color_node );
521 wxXmlNode* fillNode =
appendNode( contentNode,
"DictionaryFillDesc" );
541 contentNode->AddChild( color_node );
550 wxXmlNode* location_node =
appendNode( aNode,
"Location" );
632 wxXmlNode* color_node =
new wxXmlNode( wxXML_ELEMENT_NODE,
"DictionaryColor" );
636 wxString layer_name = item->GetLayerName();
637 int sub_layer_count = 1;
639 if( layer_name.empty() )
640 layer_name =
m_board->GetLayerName( item->GetBrdLayerId() );
642 layer_name =
genString( layer_name,
"LAYER" );
646 layer_name =
genString( wxString::Format(
"DIELECTRIC_%d", item->GetDielectricLayerId() ),
648 sub_layer_count = item->GetSublayersCount();
655 for(
int sub_idx = 0; sub_idx < sub_layer_count; sub_idx++ )
657 wxString sub_layer_name = layer_name;
660 sub_layer_name += wxString::Format(
"_%d", sub_idx );
662 wxXmlNode* node =
appendNode( aContentNode,
"LayerRef" );
668 wxXmlNode* entry_color =
appendNode( color_node,
"EntryColor" );
670 wxXmlNode* color =
appendNode( entry_color,
"Color" );
672 wxString colorName = item->GetColor( sub_idx );
674 if( colorName.StartsWith( wxT(
"#" ) ) )
677 COLOR4D layer_color( colorName );
689 if( fab_color.GetName() == colorName )
691 addAttribute( color,
"r", wxString::Format(
"%d",
KiROUND( fab_color.GetColor( item->GetType() ).r * 255 ) ) );
692 addAttribute( color,
"g", wxString::Format(
"%d",
KiROUND( fab_color.GetColor( item->GetType() ).g * 255 ) ) );
693 addAttribute( color,
"b", wxString::Format(
"%d",
KiROUND( fab_color.GetColor( item->GetType() ).b * 255 ) ) );
713 wxXmlNode* fillDesc_node =
appendNode( aNode,
"FillDesc" );
719 wxXmlNode* fillDesc_node =
appendNode( aNode,
"FillDesc" );
720 addAttribute( fillDesc_node,
"fillProperty",
"HOLLOW" );
727 wxCHECK_RET( aNode,
"aNode is null" );
732 wxXmlNode* entry_node =
nullptr;
736 size_t hash =
lineHash( aWidth, aDashType );
737 wxString
name = wxString::Format(
"LINE_%zu",
m_line_dict.size() + 1 );
741 wxXmlNode* lineDesc_node =
appendNode( aNode,
"LineDescRef" );
756 wxXmlNode* line_node =
appendNode( entry_node,
"LineDesc" );
789 if( outlineCount == 0 )
796 if( outlineCount == 1 )
802 wxXmlNode* special_node =
appendNode( aContentNode,
"UserSpecial" );
804 for(
int ii = 0; ii < outlineCount; ++ii )
820 wxXmlNode* text_node =
appendNode( aContentNode,
"UserSpecial" );
822 std::list<VECTOR2I> pts;
830 wxXmlNode* line_node =
nullptr;
837 addXY( line_node, pts.front(),
"startX",
"startY" );
838 addXY( line_node, pts.back(),
"endX",
"endY" );
842 line_node =
appendNode( text_node,
"Polyline" );
843 wxXmlNode* point_node =
appendNode( line_node,
"PolyBegin" );
844 addXY( point_node, pts.front() );
846 auto iter = pts.begin();
848 for( ++iter; iter != pts.end(); ++iter )
850 wxXmlNode* step_node =
appendNode( line_node,
"PolyStepSegment" );
851 addXY( step_node, *iter );
866 if( aPt1 == pts.back() )
867 pts.push_back( aPt2 );
868 else if( aPt2 == pts.front() )
869 pts.push_front( aPt1 );
870 else if( aPt1 == pts.front() )
871 pts.push_front( aPt2 );
872 else if( aPt2 == pts.back() )
873 pts.push_back( aPt1 );
877 pts.push_back( aPt1 );
878 pts.push_back( aPt2 );
883 pts.push_back( aPt1 );
884 pts.push_back( aPt2 );
890 if( aPoly.PointCount() < 3 )
893 wxXmlNode* outline_node =
appendNode( text_node,
"Outline" );
894 wxXmlNode* poly_node =
appendNode( outline_node,
"Polygon" );
897 const std::vector<VECTOR2I>& polyPts = aPoly.CPoints();
898 wxXmlNode* point_node =
appendNode( poly_node,
"PolyBegin" );
899 addXY( point_node, polyPts.front() );
901 for(
size_t ii = 1; ii < polyPts.size(); ++ii )
903 wxXmlNode* poly_step_node =
905 addXY( poly_step_node, polyPts[ii] );
908 point_node =
appendNode( poly_node,
"PolyStepSegment" );
909 addXY( point_node, polyPts.front() );
920 if( text_node->GetChildren() ==
nullptr )
922 aContentNode->RemoveChild( text_node );
930 int maxError =
m_board->GetDesignSettings().m_MaxError;
955 wxXmlNode* shape_node =
appendNode( aContentNode,
"StandardPrimitiveRef" );
970 int diameter = aPad.
GetSize( aLayer ).
x + 2 * margin.
x;
972 wxXmlNode* circle_node =
appendNode( entry_node,
"Circle" );
992 wxXmlNode* rect_node =
appendNode( entry_node,
"RectRound" );
1003 wxXmlNode* rect_node =
appendNode( entry_node,
"RectCenter" );
1021 wxXmlNode* oval_node =
appendNode( entry_node,
"Oval" );
1044 if( margin.
x == margin.
y )
1054 wxXmlNode* roundrect_node =
appendNode( entry_node,
"RectRound" );
1074 if( margin.
x <= 0 || margin.
x != margin.
y )
1081 wxXmlNode* chamfered_node =
appendNode( entry_node,
"RectCham" );
1085 int shorterSide = std::min( pad_size.
x, pad_size.
y );
1133 int dx = pad_size.
x / 2;
1134 int dy = pad_size.
y / 2;
1135 int ddx = trap_delta.
x / 2;
1136 int ddy = trap_delta.
y / 2;
1138 outline.
Append( -dx - ddy, dy + ddx );
1139 outline.
Append( dx + ddy, dy - ddx );
1140 outline.
Append( dx - ddy, -dy + ddx );
1141 outline.
Append( -dx + ddy, -dy - ddx );
1181 wxXmlNode* shape_node =
appendNode( aContentNode,
"StandardPrimitiveRef" );
1196 wxXmlNode* shape_node =
appendNode( aContentNode,
"UserPrimitiveRef" );
1213 wxXmlNode* polyline_node =
appendNode( aContentNode,
"Polyline" );
1221 wxXmlNode* begin_node =
appendNode( polyline_node,
"PolyBegin" );
1222 addXY( begin_node, start );
1225 wxXmlNode* arc1_node =
appendNode( polyline_node,
"PolyStepCurve" );
1226 addXY( arc1_node, mid );
1231 wxXmlNode* arc2_node =
appendNode( polyline_node,
"PolyStepCurve" );
1232 addXY( arc2_node, start );
1244 int diameter = aShape.
GetRadius() * 2.0;
1251 wxXmlNode* special_node =
appendNode( entry_node,
"UserSpecial" );
1253 wxXmlNode* circle_node =
appendNode( special_node,
"Circle" );
1279 wxXmlNode* polyline_node =
appendNode( aContentNode,
"Polyline" );
1284 wxXmlNode* begin_node =
appendNode( polyline_node,
"PolyBegin" );
1285 addXY( begin_node, corners[0] );
1287 for(
size_t i = 1; i < corners.size(); ++i )
1289 wxXmlNode* step_node =
appendNode( polyline_node,
"PolyStepSegment" );
1290 addXY( step_node, corners[i] );
1294 wxXmlNode* close_node =
appendNode( polyline_node,
"PolyStepSegment" );
1295 addXY( close_node, corners[0] );
1297 if( stroke_width > 0 )
1298 addLineDesc( polyline_node, stroke_width, dash,
true );
1308 wxXmlNode* special_node =
appendNode( entry_node,
"UserSpecial" );
1315 wxXmlNode* rect_node =
appendNode( special_node,
"RectRound" );
1322 wxString cornerFlag = corner_radius > 0 ?
"true" :
"false";
1330 width += stroke_width;
1331 height += stroke_width;
1359 wxXmlNode* polyline_node =
appendNode( aContentNode,
"Polyline" );
1360 const std::vector<VECTOR2I>& pts = outline.
CPoints();
1362 wxXmlNode* begin_node =
appendNode( polyline_node,
"PolyBegin" );
1363 addXY( begin_node, pts[0] );
1365 for(
size_t jj = 1; jj < pts.size(); ++jj )
1367 wxXmlNode* step_node =
appendNode( polyline_node,
"PolyStepSegment" );
1368 addXY( step_node, pts[jj] );
1372 if( pts.size() > 2 && pts.front() != pts.back() )
1374 wxXmlNode* close_node =
appendNode( polyline_node,
"PolyStepSegment" );
1375 addXY( close_node, pts[0] );
1378 if( stroke_width > 0 )
1379 addLineDesc( polyline_node, stroke_width, dash,
true );
1393 wxXmlNode* special_node =
appendNode( entry_node,
"UserSpecial" );
1415 wxXmlNode* arc_node =
appendNode( aContentNode,
"Arc" );
1417 addXY( arc_node, aShape.
GetEnd(),
"endX",
"endY" );
1434 wxXmlNode* polyline_node =
appendNode( aContentNode,
"Polyline" );
1438 std::vector<VECTOR2I> points;
1441 wxXmlNode* point_node =
appendNode( polyline_node,
"PolyBegin" );
1442 addXY( point_node, points[0] );
1444 for(
size_t i = 1; i < points.size(); i++ )
1446 wxXmlNode* seg_node =
appendNode( polyline_node,
"PolyStepSegment" );
1447 addXY( seg_node, points[i] );
1461 wxXmlNode* line_node =
appendNode( aContentNode,
"Line" );
1463 addXY( line_node, aShape.
GetEnd(),
"endX",
"endY" );
1493 if(
chain.PointCount() < 2 )
1496 wxXmlNode* polyline_node =
appendNode( aContentNode,
"Polyline" );
1497 const std::vector<VECTOR2I>& pts =
chain.CPoints();
1499 wxXmlNode* begin_node =
appendNode( polyline_node,
"PolyBegin" );
1500 addXY( begin_node, pts[0] );
1502 for(
size_t jj = 1; jj < pts.size(); ++jj )
1504 wxXmlNode* step_node =
appendNode( polyline_node,
"PolyStepSegment" );
1505 addXY( step_node, pts[jj] );
1509 if( !isArc && pts.size() > 2 && pts.front() != pts.back() )
1511 wxXmlNode* close_node =
appendNode( polyline_node,
"PolyStepSegment" );
1512 addXY( close_node, pts[0] );
1515 if( stroke_width > 0 )
1516 addLineDesc( polyline_node, stroke_width, dash,
true );
1526 wxXmlNode* special_node =
appendNode( entry_node,
"UserSpecial" );
1550 if( !aInline && !
name.empty() )
1552 wxXmlNode* shape_node =
appendNode( aContentNode,
"UserPrimitiveRef" );
1561 wxXmlNode* slotNode =
appendNode( aNode,
"SlotCavity" );
1581 if( drill_size.
y > drill_size.
x )
1583 std::swap( drill_size.
x, drill_size.
y );
1584 rotation = ( rotation +
ANGLE_90 ).Normalize();
1590 wxXmlNode* xformNode =
appendNode( slotNode,
"Xform" );
1595 wxXmlNode* ovalNode =
appendNode( slotNode,
"Oval" );
1603 int maxError =
m_board->GetDesignSettings().m_MaxError;
1615 wxXmlNode* roleNode =
appendNode( logisticNode,
"Role" );
1623 wxXmlNode* personNode =
appendNode( logisticNode,
"Person" );
1625 addAttribute( personNode,
"enterpriseRef",
"UNKNOWN" );
1628 return logisticNode;
1639 addAttribute( historyNode,
"origination", wxDateTime::Now().FormatISOCombined() );
1641 addAttribute( historyNode,
"lastChange", wxDateTime::Now().FormatISOCombined() );
1643 wxXmlNode* fileRevisionNode =
appendNode( historyNode,
"FileRevision" );
1644 addAttribute( fileRevisionNode,
"fileRevisionId",
"1" );
1645 addAttribute( fileRevisionNode,
"comment",
"NO COMMENT" );
1648 wxXmlNode* softwarePackageNode =
appendNode( fileRevisionNode,
"SoftwarePackage" );
1651 addAttribute( softwarePackageNode,
"vendor",
"KiCad EDA" );
1653 wxXmlNode* certificationNode =
appendNode( softwarePackageNode,
"Certification" );
1654 addAttribute( certificationNode,
"certificationStatus",
"SELFTEST" );
1677 m_refdes =
new std::vector<REFDES>();
1678 m_props =
new std::map<wxString, wxString>();
1689 wxString m_OEMDesignRef;
1693 wxString m_description;
1695 std::vector<REFDES>* m_refdes;
1696 std::map<wxString, wxString>*
m_props;
1699 std::set<std::unique_ptr<struct BOM_ENTRY>,
1700 std::function<bool(
const std::unique_ptr<struct BOM_ENTRY>&,
1701 const std::unique_ptr<struct BOM_ENTRY>& )>> bom_entries(
1702 [](
const std::unique_ptr<struct BOM_ENTRY>& a,
1703 const std::unique_ptr<struct BOM_ENTRY>& b )
1705 return a->m_OEMDesignRef < b->m_OEMDesignRef;
1710 std::unique_ptr<FOOTPRINT> fp(
static_cast<FOOTPRINT*
>( fp_it->Clone() ) );
1711 fp->SetParentGroup(
nullptr );
1712 fp->SetPosition( {0, 0} );
1713 fp->SetOrientation(
ANGLE_0 );
1716 if( fp->IsFlipped() )
1724 Report( wxString::Format(
_(
"Footprint %s not found in dictionary; BOM data may be incomplete." ),
1725 fp->GetFPID().GetLibItemName().wx_str() ),
1730 auto entry = std::make_unique<struct BOM_ENTRY>();
1736 entry->m_OEMDesignRef = it->second;
1740 Report( wxString::Format(
_(
"Component \"%s\" missing OEM reference; BOM entry will be skipped." ),
1741 fp->GetFPID().GetLibItemName().wx_str() ),
1745 entry->m_OEMDesignRef =
genString( entry->m_OEMDesignRef,
"REF" );
1747 entry->m_pads = fp->GetPadCount();
1751 const wxString variantName =
m_board ?
m_board->GetCurrentVariant() : wxString();
1753 if( entry->m_pads == 0 || fp_it->GetExcludedFromBOMForVariant( variantName ) )
1754 entry->m_type =
"DOCUMENT";
1756 entry->m_type =
"ELECTRICAL";
1761 if( descField && !descField->
GetShownText(
false ).IsEmpty() )
1762 entry->m_description = descField->
GetShownText(
false );
1764 auto[ bom_iter, inserted ] = bom_entries.insert( std::move( entry ) );
1767 ( *bom_iter )->m_count++;
1771 refdes.m_pkg = fp->GetFPID().GetLibItemName().wx_str();
1772 refdes.m_populate = !fp->GetDNPForVariant( variantName )
1773 && !fp->GetExcludedFromBOMForVariant( variantName );
1776 ( *bom_iter )->m_refdes->push_back( refdes );
1780 for(
PCB_FIELD* prop : fp->GetFields() )
1785 if( prop->IsMandatory() && !prop->IsValue() )
1788 ( *bom_iter )->m_props->emplace( prop->GetName(), prop->GetShownText(
false ) );
1792 if( bom_entries.empty() )
1795 wxFileName fn(
m_board->GetFileName() );
1797 wxXmlNode* bomNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"Bom" );
1798 m_xml_root->InsertChild( bomNode, aEcadNode );
1801 wxXmlNode* bomHeaderNode =
appendNode( bomNode,
"BomHeader" );
1804 if( bomRevision.IsEmpty() )
1805 bomRevision =
m_board->GetTitleBlock().GetRevision();
1807 if( bomRevision.IsEmpty() )
1808 bomRevision = wxS(
"1.0" );
1810 addAttribute( bomHeaderNode,
"revision", bomRevision );
1813 wxXmlNode* stepRefNode =
appendNode( bomHeaderNode,
"StepRef" );
1816 for(
const auto& entry : bom_entries )
1818 wxXmlNode* bomEntryNode =
appendNode( bomNode,
"BomItem" );
1819 addAttribute( bomEntryNode,
"OEMDesignNumberRef", entry->m_OEMDesignRef );
1820 addAttribute( bomEntryNode,
"quantity", wxString::Format(
"%d", entry->m_count ) );
1821 addAttribute( bomEntryNode,
"pinCount", wxString::Format(
"%d", entry->m_pads ) );
1822 addAttribute( bomEntryNode,
"category", entry->m_type );
1824 if( !entry->m_description.IsEmpty() )
1825 addAttribute( bomEntryNode,
"description", entry->m_description );
1827 for(
const REFDES& refdes : *( entry->m_refdes ) )
1829 wxXmlNode* refdesNode =
appendNode( bomEntryNode,
"RefDes" );
1832 addAttribute( refdesNode,
"populate", refdes.m_populate ?
"true" :
"false" );
1833 addAttribute( refdesNode,
"layerRef", refdes.m_layer );
1836 wxXmlNode* characteristicsNode =
appendNode( bomEntryNode,
"Characteristics" );
1837 addAttribute( characteristicsNode,
"category", entry->m_type );
1839 for(
const auto& prop : *( entry->m_props ) )
1841 wxXmlNode* textualDefNode =
appendNode( characteristicsNode,
"Textual" );
1842 addAttribute( textualDefNode,
"definitionSource",
"KICAD" );
1843 addAttribute( textualDefNode,
"textualCharacteristicName", prop.first );
1844 addAttribute( textualDefNode,
"textualCharacteristicValue", prop.second );
1862 wxXmlNode* cadDataNode =
appendNode( ecadNode,
"CadData" );
1881 std::vector<BOARD_STACKUP_ITEM*> layers = stackup.
GetList();
1882 std::set<PCB_LAYER_ID> added_layers;
1884 for(
int i = 0; i < stackup.
GetCount(); i++ )
1888 for(
int sublayer_id = 0; sublayer_id < stackup_item->
GetSublayersCount(); sublayer_id++ )
1892 if( ly_name.IsEmpty() )
1901 if( sublayer_id > 0 )
1902 ly_name += wxString::Format(
"_%d", sublayer_id );
1906 ly_name =
genString( ly_name,
"SPEC_LAYER" );
1908 wxXmlNode* specNode =
appendNode( aCadLayerNode,
"Spec" );
1910 wxXmlNode* generalNode =
appendNode( specNode,
"General" );
1912 wxXmlNode* propertyNode =
appendNode( generalNode,
"Property" );
1914 switch ( stackup_item->
GetType() )
1919 wxXmlNode* conductorNode =
appendNode( specNode,
"Conductor" );
1921 propertyNode =
appendNode( conductorNode,
"Property" );
1922 addAttribute( propertyNode,
"unit", wxT(
"SIEMENS/M" ) );
1923 addAttribute( propertyNode,
"value", wxT(
"5.959E7" ) );
1929 propertyNode =
appendNode( generalNode,
"Property" );
1930 addAttribute( propertyNode,
"text", wxString::Format(
"Type : %s",
1932 wxXmlNode* dielectricNode =
appendNode( specNode,
"Dielectric" );
1933 addAttribute( dielectricNode,
"type",
"DIELECTRIC_CONSTANT" );
1934 propertyNode =
appendNode( dielectricNode,
"Property" );
1937 dielectricNode =
appendNode( specNode,
"Dielectric" );
1938 addAttribute( dielectricNode,
"type",
"LOSS_TANGENT" );
1939 propertyNode =
appendNode( dielectricNode,
"Property" );
1946 propertyNode =
appendNode( generalNode,
"Property" );
1947 addAttribute( propertyNode,
"text", wxString::Format(
"Color : %s",
1949 propertyNode =
appendNode( generalNode,
"Property" );
1950 addAttribute( propertyNode,
"text", wxString::Format(
"Type : %s",
1956 propertyNode =
appendNode( generalNode,
"Property" );
1957 addAttribute( propertyNode,
"text", wxString::Format(
"Color : %s",
1959 propertyNode =
appendNode( generalNode,
"Property" );
1960 addAttribute( propertyNode,
"text", wxString::Format(
"Type : %s",
1964 if( stackup_item->
GetEpsilonR( sublayer_id ) > 1.0 )
1966 wxXmlNode* dielectricNode =
appendNode( specNode,
"Dielectric" );
1967 addAttribute( dielectricNode,
"type",
"DIELECTRIC_CONSTANT" );
1968 propertyNode =
appendNode( dielectricNode,
"Property" );
1975 wxXmlNode* dielectricNode =
appendNode( specNode,
"Dielectric" );
1976 addAttribute( dielectricNode,
"type",
"LOSS_TANGENT" );
1977 propertyNode =
appendNode( dielectricNode,
"Property" );
1995 wxXmlNode* specNode =
appendNode( aCadLayerNode,
"Spec" );
1998 wxXmlNode* surfaceFinishNode =
appendNode( specNode,
"SurfaceFinish" );
2010 wxXmlNode* cadHeaderNode =
appendNode( aEcadNode,
"CadHeader" );
2054 addAttribute( aNode,
"layerFunction",
"BOARD_OUTLINE" );
2095 aLayer ==
F_Cu ?
"TOP"
2096 : aLayer ==
B_Cu ?
"BOTTOM"
2115 wxXmlNode* stackupNode =
appendNode( aCadLayerNode,
"Stackup" );
2116 addAttribute( stackupNode,
"name",
"Primary_Stackup" );
2123 addAttribute( stackupNode,
"stackupStatus",
"PROPOSED" );
2125 wxXmlNode* stackupGroup =
appendNode( stackupNode,
"StackupGroup" );
2126 addAttribute( stackupGroup,
"name",
"Primary_Stackup_Group" );
2131 std::vector<BOARD_STACKUP_ITEM*> layers = stackup.
GetList();
2132 std::set<PCB_LAYER_ID> added_layers;
2135 for(
int i = 0; i < stackup.
GetCount(); i++ )
2139 for(
int sublayer_id = 0; sublayer_id < stackup_item->
GetSublayersCount(); sublayer_id++ )
2144 if( hasCoating && layer_id ==
F_Cu && sublayer_id == 0 )
2146 wxXmlNode* coatingLayer =
appendNode( stackupGroup,
"StackupLayer" );
2147 addAttribute( coatingLayer,
"layerOrGroupRef",
"COATING_TOP" );
2151 addAttribute( coatingLayer,
"sequence", wxString::Format(
"%d", sequence++ ) );
2153 wxXmlNode* specRefNode =
appendNode( coatingLayer,
"SpecRef" );
2157 wxXmlNode* stackupLayer =
appendNode( stackupGroup,
"StackupLayer" );
2160 if( ly_name.IsEmpty() )
2169 if( sublayer_id > 0 )
2170 ly_name += wxString::Format(
"_%d", sublayer_id );
2174 wxString spec_name =
genString( ly_name,
"SPEC_LAYER" );
2175 ly_name =
genString( ly_name,
"LAYER" );
2177 addAttribute( stackupLayer,
"layerOrGroupRef", ly_name );
2181 addAttribute( stackupLayer,
"sequence", wxString::Format(
"%d", sequence++ ) );
2183 wxXmlNode* specLayerNode =
appendNode( stackupLayer,
"SpecRef" );
2189 wxXmlNode* coatingLayer =
appendNode( stackupGroup,
"StackupLayer" );
2190 addAttribute( coatingLayer,
"layerOrGroupRef",
"COATING_BOTTOM" );
2194 addAttribute( coatingLayer,
"sequence", wxString::Format(
"%d", sequence++ ) );
2196 wxXmlNode* specRefNode =
appendNode( coatingLayer,
"SpecRef" );
2211 std::vector<BOARD_STACKUP_ITEM*> layers = stackup.
GetList();
2212 std::set<PCB_LAYER_ID> added_layers;
2214 for(
int i = 0; i < stackup.
GetCount(); i++ )
2221 for(
int sublayer_id = 0; sublayer_id < stackup_item->
GetSublayersCount(); sublayer_id++ )
2223 wxXmlNode* cadLayerNode =
appendNode( aCadLayerNode,
"Layer" );
2226 if( ly_name.IsEmpty() )
2236 if( sublayer_id > 0 )
2237 ly_name += wxString::Format(
"_%d", sublayer_id );
2241 ly_name =
genString( ly_name,
"LAYER" );
2248 addAttribute( cadLayerNode,
"layerFunction",
"DIELCORE" );
2250 addAttribute( cadLayerNode,
"layerFunction",
"DIELPREG" );
2265 LSEQ layer_seq =
m_board->GetEnabledLayers().Seq();
2274 added_layers.insert( layer );
2275 wxXmlNode* cadLayerNode =
appendNode( aCadLayerNode,
"Layer" );
2288 wxXmlNode* topCoatingNode =
appendNode( aCadLayerNode,
"Layer" );
2290 addAttribute( topCoatingNode,
"layerFunction",
"COATINGCOND" );
2292 addAttribute( topCoatingNode,
"polarity",
"POSITIVE" );
2294 wxXmlNode* botCoatingNode =
appendNode( aCadLayerNode,
"Layer" );
2295 addAttribute( botCoatingNode,
"name",
"COATING_BOTTOM" );
2296 addAttribute( botCoatingNode,
"layerFunction",
"COATINGCOND" );
2298 addAttribute( botCoatingNode,
"polarity",
"POSITIVE" );
2317 for(
PAD*
pad : fp->Pads() )
2319 if(
pad->HasDrilledHole() )
2321 else if(
pad->HasHole() )
2328 wxXmlNode* drillNode =
appendNode( aCadLayerNode,
"Layer" );
2329 drillNode->AddAttribute(
"name",
genLayersString( layers.first, layers.second,
"DRILL" ) );
2334 wxXmlNode* spanNode =
appendNode( drillNode,
"Span" );
2341 wxXmlNode* drillNode =
appendNode( aCadLayerNode,
"Layer" );
2342 drillNode->AddAttribute(
"name",
genLayersString( layers.first, layers.second,
"SLOT" ) );
2348 wxXmlNode* spanNode =
appendNode( drillNode,
"Span" );
2364 std::vector<std::tuple<auxLayerType, PCB_LAYER_ID, PCB_LAYER_ID>> new_layers;
2366 if(
via->Padstack().IsFilled().value_or(
false ) )
2369 if(
via->Padstack().IsCapped().value_or(
false ) )
2374 if(
via->Padstack().IsPlugged( layer ).value_or(
false ) )
2377 if(
via->Padstack().IsCovered( layer ).value_or(
false ) )
2380 if(
via->Padstack().IsTented( layer ).value_or(
false ) )
2384 for(
auto& tuple : new_layers )
2390 bool add_node =
true;
2393 wxString layerFunction;
2396 switch( std::get<0>(layers) )
2400 layerFunction =
"COATINGNONCOND";
2404 layerFunction =
"HOLEFILL";
2408 layerFunction =
"COATINGNONCOND";
2412 layerFunction =
"HOLEFILL";
2416 layerFunction =
"COATINGCOND";
2424 if( add_node && !vec.empty() )
2426 wxXmlNode* node =
appendNode( aCadLayerNode,
"Layer" );
2440 const bool first_external = std::get<1>( layers ) ==
F_Cu || std::get<1>( layers ) ==
B_Cu;
2441 const bool second_external = std::get<2>( layers ) ==
F_Cu || std::get<2>( layers ) ==
B_Cu;
2443 if( first_external )
2445 if( second_external )
2452 if( second_external )
2458 wxXmlNode* spanNode =
appendNode( node,
"Span" );
2469 wxXmlNode* stepNode =
appendNode( aCadNode,
"Step" );
2470 wxFileName fn(
m_board->GetFileName() );
2476 wxXmlNode* datumNode =
appendNode( stepNode,
"Datum" );
2496 wxXmlNode* padNode =
appendNode( aContentNode,
"Pad" );
2503 wxXmlNode* xformNode =
appendNode( padNode,
"Xform" );
2510 addShape( padNode, *aPad, aLayer );
2514 wxXmlNode* pinRefNode =
appendNode( padNode,
"PinRef" );
2527 wxXmlNode* padNode =
appendNode( aContentNode,
"Pad" );
2548 addAttribute( aPadNode,
"padstackDefRef", th_pair->second );
2555 wxXmlNode* padStackDefNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"PadStackDef" );
2570 wxXmlNode* padStackHoleNode =
appendNode( padStackDefNode,
"PadstackHoleDef" );
2571 padStackHoleNode->AddAttribute(
"name",
2572 wxString::Format(
"%s%d_%d",
2588 if( !
m_board->IsLayerEnabled( layer ) )
2591 wxXmlNode* padStackPadDefNode =
appendNode( padStackDefNode,
"PadstackPadDef" );
2593 addAttribute( padStackPadDefNode,
"padUse",
"REGULAR" );
2601 addShape( padStackPadDefNode, shape );
2605 addShape( padStackPadDefNode, *aPad, layer );
2617 addAttribute( aContentNode,
"padstackDefRef", via_pair->second );
2624 wxXmlNode* padStackDefNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"PadStackDef" );
2630 wxXmlNode* padStackHoleNode =
appendNode( padStackDefNode,
"PadstackHoleDef" );
2633 addAttribute( padStackHoleNode,
"platingStatus",
"VIA" );
2641 auto addPadShape{ [&](
PCB_LAYER_ID aLayer,
const PCB_VIA* aViaShape,
const wxString& aLayerRef,
2642 bool aDrill ) ->
void
2647 shape.
SetEnd( {
KiROUND( aViaShape->GetDrillValue() / 2.0 ), 0 } );
2649 shape.
SetEnd( {
KiROUND( aViaShape->GetWidth( aLayer ) / 2.0 ), 0 } );
2651 wxXmlNode* padStackPadDefNode =
2652 appendNode( padStackDefNode,
"PadstackPadDef" );
2653 addAttribute( padStackPadDefNode,
"layerRef", aLayerRef );
2654 addAttribute( padStackPadDefNode,
"padUse",
"REGULAR" );
2657 addShape( padStackPadDefNode, shape );
2677 addPadShape( layer, aVia,
genLayerString( layer,
"PLUGGING" ),
true );
2680 addPadShape( layer, aVia,
genLayerString( layer,
"COVERING" ),
false );
2683 addPadShape( layer, aVia,
genLayerString( layer,
"TENTING" ),
false );
2692 if( aCadUnits == wxT(
"MILLIMETER" ) )
2695 if( aCadUnits == wxT(
"MICRON" ) )
2696 return wxT(
"MICRON" );
2698 if( aCadUnits == wxT(
"INCH" ) )
2699 return wxT(
"INCH" );
2716 && ( aDrill.size.x > 0 || aDrill.size.y > 0 );
2719 if( !hasBackdrill( secondary ) && !hasBackdrill( tertiary ) )
2730 if( hasBackdrill( secondary )
2731 && ( !layerHasRef( secondary.
start ) || !layerHasRef( secondary.
end ) ) )
2736 if( hasBackdrill( tertiary )
2737 && ( !layerHasRef( tertiary.
start ) || !layerHasRef( tertiary.
end ) ) )
2750 LSEQ cuStack =
m_board->GetEnabledLayers().CuStack();
2754 auto it = std::find( cuStack.begin(), cuStack.end(), aDrill.end );
2756 if( it == cuStack.end() )
2759 if( aDrill.start ==
F_Cu )
2763 if( it == cuStack.end() )
2769 if( aDrill.start ==
B_Cu )
2771 if( it == cuStack.begin() )
2781 const wxString& aSpecName ) -> wxString
2783 if( !hasBackdrill( aDrill ) )
2791 PCB_LAYER_ID mustNotCut = computeMustNotCutLayer( aDrill );
2813 wxString postMachiningComment;
2816 postMachiningComment = wxT(
"post-machining=COUNTERBORE" );
2818 postMachiningComment = wxT(
"post-machining=COUNTERSINK" );
2822 wxXmlNode* bd =
appendNode( specNode,
"Backdrill" );
2826 addAttribute( p,
"layerOrGroupRef", startLayer->second );
2832 wxXmlNode* bd =
appendNode( specNode,
"Backdrill" );
2833 addAttribute( bd,
"type", wxT(
"MUST_NOT_CUT_LAYER" ) );
2836 addAttribute( p,
"layerOrGroupRef", mustNotCutEntry->second );
2849 if( dielectric > 0 )
2850 stubLength = dielectric / 2;
2854 wxXmlNode* bd =
appendNode( specNode,
"Backdrill" );
2862 if( !postMachiningComment.IsEmpty() )
2864 wxXmlNode* bd =
appendNode( specNode,
"Backdrill" );
2876 wxString secondarySpec = createSpec( secondary, wxString::Format( wxT(
"BD_%dA" ), specIndex ) );
2877 wxString tertiarySpec = createSpec( tertiary, wxString::Format( wxT(
"BD_%dB" ), specIndex ) );
2879 if( secondarySpec.IsEmpty() && tertiarySpec.IsEmpty() )
2884 std::array<wxString, 2>{ secondarySpec, tertiarySpec } );
2895 auto addRef = [&](
const wxString& aSpecName )
2897 if( aSpecName.IsEmpty() )
2900 wxXmlNode* specRefNode =
appendNode( aHoleNode,
"SpecRef" );
2905 for(
const wxString& specName : it->second )
2921 wxXmlNode* specNode = it->second;
2943 wxXmlNode* polygonNode =
nullptr;
2951 polygonNode =
appendNode( aParentNode,
"Polygon" );
2952 wxXmlNode* polybeginNode =
appendNode( polygonNode,
"PolyBegin" );
2954 const std::vector<VECTOR2I>& pts = aPolygon.
CPoints();
2955 addXY( polybeginNode, pts[0] );
2957 for(
size_t ii = 1; ii < pts.size(); ++ii )
2959 wxXmlNode* polyNode =
appendNode( polygonNode,
"PolyStepSegment" );
2960 addXY( polyNode, pts[ii] );
2963 wxXmlNode* polyendNode =
appendNode( polygonNode,
"PolyStepSegment" );
2964 addXY( polyendNode, pts[0] );
2975 addLineDesc( polygonNode, aWidth, aDashType,
true );
2979 wxCHECK( aWidth == 0,
false );
2992 for(
size_t ii = 1; ii < aPolygon.size(); ++ii )
2994 wxCHECK2( aPolygon[ii].PointCount() >= 3,
continue );
2996 wxXmlNode* cutoutNode =
appendNode( aParentNode,
"Cutout" );
2997 wxXmlNode* polybeginNode =
appendNode( cutoutNode,
"PolyBegin" );
2999 const std::vector<VECTOR2I>& hole = aPolygon[ii].CPoints();
3000 addXY( polybeginNode, hole[0] );
3002 for(
size_t jj = 1; jj < hole.size(); ++jj )
3004 wxXmlNode* polyNode =
appendNode( cutoutNode,
"PolyStepSegment" );
3005 addXY( polyNode, hole[jj] );
3008 wxXmlNode* polyendNode =
appendNode( cutoutNode,
"PolyStepSegment" );
3009 addXY( polyendNode, hole[0] );
3022 wxXmlNode* outlineNode =
appendNode( aParentNode,
"Outline" );
3039 wxLogTrace(
traceIpc2581, wxS(
"Failed to add polygon to outline" ) );
3042 if( !outlineNode->GetChildren() )
3044 aParentNode->RemoveChild( outlineNode );
3061 wxXmlNode* contourNode =
appendNode( aParentNode,
"Contour" );
3071 aParentNode->RemoveChild( contourNode );
3084 if( !
m_board->GetBoardPolygonOutlines( board_outline,
false ) )
3090 wxXmlNode* profileNode =
appendNode( aStepNode,
"Profile" );
3094 wxLogTrace(
traceIpc2581, wxS(
"Failed to add polygon to profile" ) );
3095 aStepNode->RemoveChild( profileNode );
3121 std::unique_ptr<FOOTPRINT> fp(
static_cast<FOOTPRINT*
>( aFp->
Clone() ) );
3122 fp->SetParentGroup(
nullptr );
3123 fp->SetPosition( { 0, 0 } );
3124 fp->SetOrientation(
ANGLE_0 );
3129 bool wasFlipped = fp->IsFlipped();
3132 if( fp->IsFlipped() )
3137 fp->GetFPID().GetLibItemName().wx_str(),
3141 addAttribute( aContentNode,
"packageRef", iter->second );
3148 wxXmlNode* packageNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"Package" );
3149 wxXmlNode* otherSideViewNode =
nullptr;
3155 if( fp->FindPadByNumber(
"1" ) )
3157 else if ( fp->FindPadByNumber(
"A1" ) )
3159 else if ( fp->FindPadByNumber(
"A" ) )
3161 else if ( fp->FindPadByNumber(
"a" ) )
3163 else if ( fp->FindPadByNumber(
"a1" ) )
3165 else if ( fp->FindPadByNumber(
"Anode" ) )
3167 else if ( fp->FindPadByNumber(
"ANODE" ) )
3174 PAD* pinOnePad = fp->FindPadByNumber(
"1" );
3177 pinOnePad = fp->FindPadByNumber(
"A1" );
3179 if( pinOnePad && fp->Pads().size() >= 2 )
3182 BOX2I fpBBox = fp->GetBoundingBox();
3192 const char* orientation =
"OTHER";
3194 if( onCenterX && onCenterY )
3195 orientation =
"CENTER";
3196 else if( onCenterX && pinPos.
y <
center.y )
3197 orientation =
"UPPER_CENTER";
3198 else if( onCenterX && pinPos.
y >
center.y )
3199 orientation =
"LOWER_CENTER";
3200 else if( onCenterY && pinPos.
x <
center.x )
3201 orientation =
"LEFT";
3202 else if( onCenterY && pinPos.
x >
center.x )
3203 orientation =
"RIGHT";
3205 orientation =
"UPPER_LEFT";
3207 orientation =
"UPPER_RIGHT";
3209 orientation =
"LOWER_LEFT";
3211 orientation =
"LOWER_RIGHT";
3213 addAttribute( packageNode,
"pinOneOrientation", orientation );
3217 addAttribute( packageNode,
"pinOneOrientation",
"OTHER" );
3218 addAttribute( packageNode,
"comment",
"Pin 1 orientation could not be determined" );
3224 : fp->GetCourtyard(
F_CrtYd );
3226 : fp->GetCourtyard(
B_CrtYd );
3243 otherSideViewNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"OtherSideView" );
3249 wxXmlNode* pickupPointNode =
appendNode( packageNode,
"PickupPoint" );
3253 std::map<PCB_LAYER_ID, std::map<bool, std::vector<BOARD_ITEM*>>> elements;
3255 for(
BOARD_ITEM* item : fp->GraphicalItems() )
3280 elements[item->GetLayer()][is_abs].push_back( item );
3283 auto add_base_node =
3286 wxXmlNode* parent = packageNode;
3295 bool is_other_side = wasFlipped ? ( aLayer ==
F_SilkS || aLayer ==
F_Fab )
3300 if( !otherSideViewNode )
3301 otherSideViewNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"OtherSideView" );
3303 parent = otherSideViewNode;
3310 else if( aLayer ==
F_Fab || aLayer ==
B_Fab )
3319 auto add_marking_node =
3320 [&]( wxXmlNode* aNode ) -> wxXmlNode*
3322 wxXmlNode* marking_node =
appendNode( aNode,
"Marking" );
3324 return marking_node;
3327 std::map<PCB_LAYER_ID, wxXmlNode*> layer_nodes;
3328 std::map<PCB_LAYER_ID, BOX2I> layer_bbox;
3332 if( elements.find( layer ) != elements.end() )
3334 if( elements[layer][
true].size() > 0 )
3335 layer_bbox[layer] = elements[layer][
true][0]->GetBoundingBox();
3336 else if( elements[layer][
false].size() > 0 )
3337 layer_bbox[layer] = elements[layer][
false][0]->GetBoundingBox();
3341 for(
auto& [layer, map] : elements )
3343 wxXmlNode* layer_node = add_base_node( layer );
3344 wxXmlNode* marking_node = add_marking_node( layer_node );
3345 wxXmlNode* group_node =
appendNode( marking_node,
"UserSpecial" );
3346 bool update_bbox =
false;
3350 layer_nodes[layer] = layer_node;
3354 for(
auto& [is_abs, vec] : map )
3358 wxXmlNode* output_node =
nullptr;
3361 layer_bbox[layer].Merge( item->GetBoundingBox() );
3364 output_node = add_marking_node( layer_node );
3366 output_node = group_node;
3368 switch( item->Type() )
3374 if(
text->IsKnockout() )
3388 if(
text->IsBorderEnabled() )
3391 text->GetEffectiveShape()->TransformToPolygon( poly_set, 0,
ERROR_INSIDE );
3393 text->GetBorderWidth() );
3416 if( group_node->GetChildren() ==
nullptr )
3418 marking_node->RemoveChild( group_node );
3419 layer_node->RemoveChild( marking_node );
3421 delete marking_node;
3425 for(
auto&[layer, bbox] : layer_bbox )
3427 if( bbox.GetWidth() > 0 )
3429 wxXmlNode* outlineNode =
insertNode( layer_nodes[layer],
"Outline" );
3432 std::vector<VECTOR2I> points( 4 );
3433 points[0] = bbox.GetPosition();
3434 points[2] = bbox.GetEnd();
3435 points[1].x = points[0].x;
3436 points[1].y = points[2].y;
3437 points[3].x = points[2].x;
3438 points[3].y = points[0].y;
3440 outline.
Append( points );
3446 std::map<wxString, wxXmlNode*> pin_nodes;
3448 for(
size_t ii = 0; ii < fp->Pads().size(); ++ii )
3450 PAD*
pad = fp->Pads()[ii];
3452 wxXmlNode* pinNode =
nullptr;
3454 auto [ it, inserted ] = pin_nodes.emplace( pin_name,
nullptr );
3459 it->second = pinNode;
3464 genString( fp->GetReference(),
"CMP" ), pin_name );
3467 addAttribute( pinNode,
"electricalType",
"MECHANICAL" );
3468 else if(
pad->IsOnCopperLayer() )
3469 addAttribute( pinNode,
"electricalType",
"ELECTRICAL" );
3471 addAttribute( pinNode,
"electricalType",
"UNDEFINED" );
3473 if(
pad->HasHole() )
3478 if(
pad->GetFPRelativeOrientation() !=
ANGLE_0 )
3480 wxXmlNode* xformNode =
appendNode( pinNode,
"Xform" );
3481 EDA_ANGLE pad_angle =
pad->GetFPRelativeOrientation().Normalize();
3483 if( fp->IsFlipped() )
3500 if( otherSideViewNode )
3501 packageNode->AddChild( otherSideViewNode );
3509 std::vector<wxXmlNode*> componentNodes;
3510 std::vector<wxXmlNode*> packageNodes;
3511 std::set<wxString> packageNames;
3513 bool generate_unique =
m_OEMRef.empty();
3517 wxXmlNode* componentNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"Component" );
3519 wxXmlNode* pkg =
addPackage( componentNode, fp );
3522 packageNodes.push_back( pkg );
3528 if( !generate_unique )
3531 if( field && !field->
GetText().empty() )
3537 name = wxString::Format(
"%s_%s_%s", fp->GetFPID().GetFullLibraryName(),
3538 fp->GetFPID().GetLibItemName().wx_str(),
3543 Report(
_(
"Duplicate footprint pointers encountered; IPC-2581 output may be incorrect." ),
3551 else if( fp->GetAttributes() &
FP_SMD )
3556 if( fp->GetOrientation() !=
ANGLE_0 || fp->IsFlipped() )
3558 wxXmlNode* xformNode =
appendNode( componentNode,
"Xform" );
3562 if( fp->IsFlipped() )
3568 if( fp->IsFlipped() )
3572 addLocationNode( componentNode, fp->GetPosition().x, fp->GetPosition().y );
3574 componentNodes.push_back( componentNode );
3583 for( wxXmlNode* pkg : packageNodes )
3584 aStepNode->AddChild( pkg );
3586 for( wxXmlNode* cmp : componentNodes )
3587 aStepNode->AddChild( cmp );
3595 wxXmlNode* netNode =
appendNode( aStepNode,
"LogicalNet" );
3597 genString(
m_board->GetNetInfo().GetNetItem( net )->GetNetname(),
"NET" ) ) ;
3599 for(
auto& [cmp,
pin] : pin_pair )
3601 wxXmlNode* netPinNode =
appendNode( netNode,
"PinRef" );
3615 std::vector<std::unique_ptr<FOOTPRINT>> footprints;
3619 std::map<PCB_LAYER_ID, std::map<int, std::vector<BOARD_ITEM*>>> elements;
3621 std::for_each(
m_board->Tracks().begin(),
m_board->Tracks().end(),
3622 [&layers, &elements](
PCB_TRACK* aTrack )
3624 if( aTrack->Type() == PCB_VIA_T )
3626 PCB_VIA* via = static_cast<PCB_VIA*>( aTrack );
3628 for( PCB_LAYER_ID layer : layers )
3630 if( via->FlashLayer( layer ) )
3631 elements[layer][via->GetNetCode()].push_back( via );
3636 elements[aTrack->GetLayer()][aTrack->GetNetCode()].push_back( aTrack );
3640 std::for_each( m_board->Zones().begin(), m_board->Zones().end(),
3641 [ &elements ](
ZONE* zone )
3643 LSEQ zone_layers = zone->GetLayerSet().Seq();
3645 for( PCB_LAYER_ID layer : zone_layers )
3646 elements[layer][zone->GetNetCode()].push_back( zone );
3649 for(
BOARD_ITEM* item : m_board->Drawings() )
3652 elements[conn_it->GetLayer()][conn_it->GetNetCode()].push_back( conn_it );
3654 elements[item->GetLayer()][0].push_back( item );
3657 for(
FOOTPRINT* fp : m_board->Footprints() )
3659 for(
PCB_FIELD* field : fp->GetFields() )
3660 elements[field->GetLayer()][0].push_back( field );
3664 for(
BOARD_ITEM* item : fp->GraphicalItems() )
3667 elements[layer][0].push_back( item );
3670 for(
PAD*
pad : fp->Pads() )
3672 LSEQ pad_layers =
pad->GetLayerSet().Seq();
3676 if(
pad->FlashLayer( layer ) )
3677 elements[layer][
pad->GetNetCode()].push_back(
pad );
3690 if( !hasAuthoredMask )
3703 if( m_progressReporter )
3704 m_progressReporter->SetMaxProgress( nets.GetNetCount() * layers.size() );
3706 wxXmlNode* layerNode = appendNode( aStepNode,
"LayerFeature" );
3707 addAttribute( layerNode,
"layerRef", m_layer_name_map[layer] );
3709 auto process_net = [&] (
int net )
3711 std::vector<BOARD_ITEM*>& vec = elements[layer][net];
3716 std::stable_sort( vec.begin(), vec.end(),
3719 if( a->GetParentFootprint() == b->GetParentFootprint() )
3720 return a->Type() < b->Type();
3722 return a->GetParentFootprint() < b->GetParentFootprint();
3725 generateLayerSetNet( layerNode, layer, vec );
3730 if( m_progressReporter )
3732 m_progressReporter->Report( wxString::Format(
_(
"Exporting Layer %s, Net %s" ),
3733 m_board->GetLayerName( layer ),
3734 net->GetNetname() ) );
3735 m_progressReporter->AdvanceProgress();
3738 process_net( net->GetNetCode() );
3741 if( layerNode->GetChildren() ==
nullptr )
3743 aStepNode->RemoveChild( layerNode );
3744 deleteNode( layerNode );
3756 wxXmlNode* layerNode =
appendNode( aLayerNode,
"LayerFeature" );
3757 layerNode->AddAttribute(
"layerRef",
genLayersString( layers.first, layers.second,
"DRILL" ) );
3768 Report(
_(
"Via uses unsupported padstack; omitted from drill data." ),
3773 wxXmlNode* padNode =
appendNode( layerNode,
"Set" );
3776 if(
via->GetNetCode() > 0 )
3779 wxXmlNode* holeNode =
appendNode( padNode,
"Hole" );
3780 addAttribute( holeNode,
"name", wxString::Format(
"H%d", hole_count++ ) );
3785 addXY( holeNode,
via->GetPosition() );
3795 Report(
_(
"Pad uses unsupported padstack; hole was omitted from drill data." ),
3800 wxXmlNode* padNode =
appendNode( layerNode,
"Set" );
3803 if(
pad->GetNetCode() > 0 )
3806 wxXmlNode* holeNode =
appendNode( padNode,
"Hole" );
3807 addAttribute( holeNode,
"name", wxString::Format(
"H%d", hole_count++ ) );
3813 addXY( holeNode,
pad->GetPosition() );
3823 wxXmlNode* layerNode =
appendNode( aLayerNode,
"LayerFeature" );
3824 layerNode->AddAttribute(
"layerRef",
genLayersString( layers.first, layers.second,
"SLOT" ) );
3828 wxXmlNode* padNode =
appendNode( layerNode,
"Set" );
3830 if(
pad->GetNetCode() > 0 )
3833 addSlotCavity( padNode, *
pad, wxString::Format(
"SLOT%d", hole_count++ ) );
3840 std::vector<BOARD_ITEM*>& aItems )
3842 auto it = aItems.begin();
3843 wxXmlNode* layerSetNode =
appendNode( aLayerNode,
"Set" );
3844 wxXmlNode* featureSetNode =
appendNode( layerSetNode,
"Features" );
3845 wxXmlNode* specialNode =
appendNode( featureSetNode,
"UserSpecial" );
3847 bool has_via =
false;
3848 bool has_pad =
false;
3850 wxXmlNode* padSetNode =
nullptr;
3852 wxXmlNode* viaSetNode =
nullptr;
3854 wxXmlNode* teardropLayerSetNode =
nullptr;
3855 wxXmlNode* teardropFeatureSetNode =
nullptr;
3857 bool teardrop_warning =
false;
3862 if( item->GetNetCode() > 0 )
3872 shape.
SetStart( track->GetStart() );
3873 shape.
SetEnd( track->GetEnd() );
3874 shape.
SetWidth( track->GetWidth() );
3891 viaSetNode = layerSetNode;
3896 viaSetNode =
appendNode( layerSetNode,
"Set" );
3898 if( track->GetNetCode() > 0 )
3905 addVia( viaSetNode,
static_cast<PCB_VIA*
>( track ), aLayer );
3912 wxXmlNode* zoneFeatureNode = specialNode;
3914 if( zone->IsTeardropArea() )
3918 if( !teardropFeatureSetNode )
3920 teardropLayerSetNode =
appendNode( aLayerNode,
"Set" );
3921 addAttribute( teardropLayerSetNode,
"geometryUsage",
"TEARDROP" );
3923 if( zone->GetNetCode() > 0 )
3926 genString( zone->GetNetname(),
"NET" ) );
3929 wxXmlNode* new_teardrops =
appendNode( teardropLayerSetNode,
"Features" );
3931 teardropFeatureSetNode =
appendNode( new_teardrops,
"UserSpecial" );
3934 zoneFeatureNode = teardropFeatureSetNode;
3936 else if( !teardrop_warning )
3938 Report(
_(
"Teardrops are not supported in IPC-2581 revision B; they were exported as zones." ),
3940 teardrop_warning =
true;
3947 wxXmlNode* tempSetNode =
appendNode( aLayerNode,
"Set" );
3950 wxXmlNode* newFeatures =
appendNode( tempSetNode,
"Features" );
3952 zoneFeatureNode =
appendNode( newFeatures,
"UserSpecial" );
3956 SHAPE_POLY_SET& zone_shape = *zone->GetFilledPolysList( aLayer );
3958 for(
int ii = 0; ii < zone_shape.
OutlineCount(); ++ii )
3969 wxXmlNode* tempSetNode =
appendNode( aLayerNode,
"Set" );
3972 addAttribute( tempSetNode,
"geometryUsage",
"GRAPHIC" );
3974 bool link_to_component =
true;
3977 link_to_component =
false;
3979 if( link_to_component )
3982 wxXmlNode* tempFeature =
appendNode( tempSetNode,
"Features" );
3991 wxXmlNode* tempSetNode =
appendNode( aLayerNode,
"Set" );
3993 if( shape->GetNetCode() > 0 )
3996 wxXmlNode* tempFeature =
appendNode( tempSetNode,
"Features" );
4013 text_item =
static_cast<EDA_TEXT*
>( pcb_text );
4015 text_item =
static_cast<EDA_TEXT*
>( pcb_textbox );
4020 wxXmlNode* tempSetNode =
appendNode( aLayerNode,
"Set" );
4025 bool link_to_component = fp !=
nullptr;
4028 link_to_component =
false;
4030 if( link_to_component )
4033 wxXmlNode* nonStandardAttributeNode =
appendNode( tempSetNode,
"NonstandardAttribute" );
4034 addAttribute( nonStandardAttributeNode,
"name",
"TEXT" );
4036 addAttribute( nonStandardAttributeNode,
"type",
"STRING" );
4038 wxXmlNode* tempFeature =
appendNode( tempSetNode,
"Features" );
4044 addText( tempFeature, text_item,
text->GetFontMetrics() );
4062 padSetNode = layerSetNode;
4067 padSetNode =
appendNode( aLayerNode,
"Set" );
4069 if(
pad->GetNetCode() > 0 )
4079 switch( item->Type() )
4084 add_track(
static_cast<PCB_TRACK*
>( item ) );
4092 add_pad(
static_cast<PAD*
>( item ) );
4096 add_shape(
static_cast<PCB_SHAPE*
>( item ) );
4121 if( specialNode->GetChildren() ==
nullptr )
4123 featureSetNode->RemoveChild( specialNode );
4127 if( featureSetNode->GetChildren() ==
nullptr )
4129 layerSetNode->RemoveChild( featureSetNode );
4133 if( layerSetNode->GetChildren() ==
nullptr )
4135 aLayerNode->RemoveChild( layerSetNode );
4144 bool add_node =
true;
4150 switch( std::get<0>(layers) )
4179 wxXmlNode* layerNode =
appendNode( aStepNode,
"LayerFeature" );
4183 layerNode->AddAttribute(
"layerRef",
genLayersString( std::get<1>( layers ),
4197 shape.
SetEnd( {
KiROUND(
via->GetWidth( std::get<1>( layers ) ) / 2.0 ), 0 } );
4199 wxXmlNode* padNode =
appendNode( layerNode,
"Pad" );
4230 std::set<wxString> unique_parts;
4231 std::map<wxString,wxString> unique_vendors;
4235 auto [ it, success ] = unique_parts.insert(
name );
4240 wxXmlNode* part =
appendNode( avl,
"AvlItem" );
4247 for (
int ii = 0; ii < 2; ++ii )
4253 if( mpn_name.empty() )
4256 wxXmlNode* vmpn =
appendNode( part,
"AvlVmpn" );
4260 wxXmlNode* mpn =
appendNode( vmpn,
"AvlMpn" );
4263 wxXmlNode* vendor =
appendNode( vmpn,
"AvlVendor" );
4265 wxString vendor_name = wxT(
"UNKNOWN" );
4268 if( !ii && company[ii] )
4276 else if( !ii && !company_name[ii].
empty() )
4278 vendor_name = company_name[ii];
4280 else if( ii && !
m_dist.empty() )
4285 auto [vendor_id, inserted] = unique_vendors.emplace(
4287 wxString::Format(
"VENDOR_%zu", unique_vendors.size() ) );
4289 addAttribute( vendor,
"enterpriseRef", vendor_id->second );
4293 wxXmlNode* new_vendor =
new wxXmlNode( wxXML_ELEMENT_NODE,
"Enterprise" );
4309 const std::map<std::string, UTF8>* aProperties )
4355 const std::map<std::string, UTF8> emptyProperties;
4358 aProperties = &emptyProperties;
4360 if(
auto it = aProperties->find(
"units" ); it != aProperties->end() )
4362 if( it->second ==
"inch" )
4369 if(
auto it = aProperties->find(
"sigfig" ); it != aProperties->end() )
4370 m_sigfig = std::stoi( it->second );
4372 if(
auto it = aProperties->find(
"version" ); it != aProperties->end() )
4375 if(
auto it = aProperties->find(
"OEMRef" ); it != aProperties->end() )
4378 if(
auto it = aProperties->find(
"mpn" ); it != aProperties->end() )
4379 m_mpn = it->second.wx_str();
4381 if(
auto it = aProperties->find(
"mfg" ); it != aProperties->end() )
4382 m_mfg = it->second.wx_str();
4384 if(
auto it = aProperties->find(
"dist" ); it != aProperties->end() )
4385 m_dist = it->second.wx_str();
4387 if(
auto it = aProperties->find(
"distpn" ); it != aProperties->end() )
4390 if(
auto it = aProperties->find(
"bomrev" ); it != aProperties->end() )
4395 for(
char c =
'a'; c <=
'z'; ++c )
4398 for(
char c =
'A'; c <=
'Z'; ++c )
4401 for(
char c =
'0'; c <=
'9'; ++c )
4405 std::string specialChars =
"_\\-.+><";
4407 for(
char c : specialChars )
4434 wxXmlNode* insertBefore =
nullptr;
4436 for( wxXmlNode* child =
m_contentNode->GetChildren(); child; child = child->GetNext() )
4438 if( child->GetName().StartsWith(
"Dictionary" ) )
4440 insertBefore = child;
4446 [&](
const wxString& aNodeName, wxXmlNode* aSection )
4451 wxXmlNode* ref =
new wxXmlNode( wxXML_ELEMENT_NODE, aNodeName );
4452 ref->AddAttribute(
"name", aSection->GetAttribute(
"name" ) );
4460 insertRef(
"BomRef", bom_node );
4461 insertRef(
"AvlRef", avl_node );
4470 double written_bytes = 0.0;
4471 double last_yield = 0.0;
4478 auto update_progress = [&](
size_t aBytes )
4480 written_bytes += aBytes;
4481 double percent = written_bytes /
static_cast<double>(
m_total_bytes );
4486 if( last_yield + 0.01 < percent )
4488 last_yield = percent;
constexpr int ARC_HIGH_DEF
constexpr double PCB_IU_PER_MM
Pcbnew IU is 1 nanometer.
bool IsPrmSpecified(const wxString &aPrmValue)
@ BS_ITEM_TYPE_SILKSCREEN
@ BS_ITEM_TYPE_DIELECTRIC
@ BS_ITEM_TYPE_SOLDERMASK
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
wxString GetMajorMinorPatchVersion()
Get the major, minor and patch version in a string major.minor.patch This is extracted by CMake from ...
Bezier curves to polygon converter.
void GetPoly(std::vector< VECTOR2I > &aOutput, int aMaxError=10)
Convert a Bezier curve to a polygon.
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
Container for design settings for a BOARD object.
BOARD_STACKUP & GetStackupDescriptor()
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
virtual bool IsKnockout() const
FOOTPRINT * GetParentFootprint() const
VECTOR2I GetFPRelativePosition() const
Manage one layer needed to make a physical board.
wxString GetTypeName() const
int GetSublayersCount() const
double GetEpsilonR(int aDielectricSubLayer=0) const
wxString GetColor(int aDielectricSubLayer=0) const
wxString GetLayerName() const
PCB_LAYER_ID GetBrdLayerId() const
int GetThickness(int aDielectricSubLayer=0) const
BOARD_STACKUP_ITEM_TYPE GetType() const
wxString GetMaterial(int aDielectricSubLayer=0) const
int GetDielectricLayerId() const
double GetLossTangent(int aDielectricSubLayer=0) const
Manage layers needed to make a physical board.
const std::vector< BOARD_STACKUP_ITEM * > & GetList() const
bool SynchronizeWithBoard(BOARD_DESIGN_SETTINGS *aSettings)
Synchronize the BOARD_STACKUP_ITEM* list with the board.
int BuildBoardThicknessFromStackup() const
int GetLayerDistance(PCB_LAYER_ID aFirstLayer, PCB_LAYER_ID aSecondLayer) const
Calculate the distance (height) between the two given copper layers.
wxString m_FinishType
The name of external copper finish.
Information pertinent to a Pcbnew printed circuit board.
constexpr size_type GetWidth() const
constexpr const Vec GetCenter() const
constexpr size_type GetHeight() const
int GetEllipseMinorRadius() const
const VECTOR2I & GetBezierC2() const
const VECTOR2I & GetEllipseCenter() const
EDA_ANGLE GetEllipseEndAngle() const
FILL_T GetFillMode() const
int GetEllipseMajorRadius() const
int GetRectangleWidth() const
SHAPE_POLY_SET & GetPolyShape()
EDA_ANGLE GetEllipseRotation() const
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
std::vector< VECTOR2I > GetRectCorners() const
EDA_ANGLE GetEllipseStartAngle() const
const VECTOR2I & GetBezierC1() const
int GetRectangleHeight() const
bool IsClockwiseArc() const
int GetCornerRadius() const
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
virtual VECTOR2I GetTextPos() const
virtual const wxString & GetText() const
Return the string associated with the text object.
virtual bool IsVisible() const
virtual EDA_ANGLE GetDrawRotation() const
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.
virtual wxString GetShownText(bool aAllowExtraText, int aDepth=0) const
Return the string actually shown after processing of the base text.
static ENUM_MAP< T > & Instance()
wxString m_name
Name of the IO loader.
PROGRESS_REPORTER * m_progressReporter
Progress reporter to track the progress of the operation, may be nullptr.
virtual void Report(const wxString &aText, SEVERITY aSeverity=RPT_SEVERITY_UNDEFINED)
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.
Container for NETINFO_ITEM elements, which are the nets.
A PADSTACK defines the characteristics of a single or multi-layer pad, in the IPC sense of the word.
std::optional< bool > IsFilled() const
std::optional< bool > IsTented(PCB_LAYER_ID aSide) const
Checks if this padstack is tented (covered in soldermask) on the given side.
PCB_LAYER_ID EffectiveLayerFor(PCB_LAYER_ID aLayer) const
Determines which geometry layer should be used for the given input layer.
POST_MACHINING_PROPS & FrontPostMachining()
std::optional< bool > IsPlugged(PCB_LAYER_ID aSide) const
DRILL_PROPS & TertiaryDrill()
std::optional< bool > IsCapped() const
std::optional< bool > IsCovered(PCB_LAYER_ID aSide) const
DRILL_PROPS & SecondaryDrill()
POST_MACHINING_PROPS & BackPostMachining()
static constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
void MergePrimitivesAsPolygon(PCB_LAYER_ID aLayer, SHAPE_POLY_SET *aMergedPolygon, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Merge all basic shapes to a SHAPE_POLY_SET.
int GetRoundRectCornerRadius(PCB_LAYER_ID aLayer) const
bool FlashLayer(int aLayer, bool aOnlyCheckIfPermitted=false) const
Check to see whether the pad should be flashed on the specific layer.
int GetDrillSizeY() const
PAD_ATTRIB GetAttribute() const
const wxString & GetNumber() const
const VECTOR2I & GetDelta(PCB_LAYER_ID aLayer) const
VECTOR2I GetPosition() const override
VECTOR2I GetOffset(PCB_LAYER_ID aLayer) const
VECTOR2I GetDrillSize() const
int GetDrillSizeX() const
double GetRoundRectRadiusRatio(PCB_LAYER_ID aLayer) const
PAD_SHAPE GetShape(PCB_LAYER_ID aLayer) const
int GetSolderMaskExpansion(PCB_LAYER_ID aLayer) const
VECTOR2I GetSize(PCB_LAYER_ID aLayer) const
const PADSTACK & Padstack() const
EDA_ANGLE GetOrientation() const
Return the rotation angle of the pad.
PAD_DRILL_SHAPE GetDrillShape() const
int GetChamferPositions(PCB_LAYER_ID aLayer) const
double GetChamferRectRatio(PCB_LAYER_ID aLayer) const
VECTOR2I GetSolderPasteMargin(PCB_LAYER_ID aLayer) const
Usually < 0 (mask shape smaller than pad)because the margin can be dependent on the pad size,...
bool HasDrilledHole() const override
bool HasHole() const override
bool TransformHoleToPolygon(SHAPE_POLY_SET &aBuffer, int aClearance, int aError, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Build the corner list of the polygonal drill shape in the board coordinate system.
const VECTOR2I & GetMid() const
wxString GetShownText(bool aAllowExtraText, 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)
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)
wxString componentName(FOOTPRINT *aFootprint)
void addShape(wxXmlNode *aContentNode, const PCB_SHAPE &aShape, bool aInline=false)
bool addOutlineNode(wxXmlNode *aParentNode, const SHAPE_POLY_SET &aPolySet, int aWidth=0, LINE_STYLE aDashType=LINE_STYLE::SOLID)
void generateStackup(wxXmlNode *aCadLayerNode)
std::map< std::tuple< auxLayerType, PCB_LAYER_ID, PCB_LAYER_ID >, std::vector< BOARD_ITEM * > > m_auxilliary_Layers
bool addPolygonNode(wxXmlNode *aParentNode, const SHAPE_LINE_CHAIN &aPolygon, FILL_T aFillType=FILL_T::FILLED_SHAPE, int aWidth=0, LINE_STYLE aDashType=LINE_STYLE::SOLID)
void generateLayerSetNet(wxXmlNode *aLayerNode, PCB_LAYER_ID aLayer, std::vector< BOARD_ITEM * > &aItems)
bool isValidLayerFor2581(PCB_LAYER_ID aLayer)
void insertNodeAfter(wxXmlNode *aPrev, wxXmlNode *aNode)
void generateCadLayers(wxXmlNode *aCadLayerNode)
std::vector< wxXmlNode * > m_padstacks
wxString pinName(const PAD *aPad) const
void generateCadSpecs(wxXmlNode *aCadLayerNode)
void addVia(wxXmlNode *aContentNode, const PCB_VIA *aVia, PCB_LAYER_ID aLayer)
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)
std::map< size_t, wxString > m_std_shape_dict
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.
wxXmlNode * m_contentNode
void addXY(wxXmlNode *aNode, const VECTOR2I &aVec, const char *aXName=nullptr, const char *aYName=nullptr)
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 * generateLogisticSection()
Creates the logistical data header.
std::set< wxString > m_element_names
std::map< size_t, wxString > m_line_dict
void addLineDesc(wxXmlNode *aNode, int aWidth, LINE_STYLE aDashType, bool aForce=false)
void addKnockoutText(wxXmlNode *aContentNode, PCB_TEXT *aText)
std::map< size_t, wxString > m_padstack_dict
std::map< std::pair< PCB_LAYER_ID, PCB_LAYER_ID >, std::vector< BOARD_ITEM * > > m_drill_layers
std::map< wxString, FOOTPRINT * > m_footprint_refdes_dict
void generateProfile(wxXmlNode *aStepNode)
void generateLayerFeatures(wxXmlNode *aStepNode)
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...
wxXmlNode * generateBOMSection(wxXmlNode *aEcadNode)
Creates the BOM section.
wxXmlNode * generateContentStackup(wxXmlNode *aContentNode)
void generateAuxilliaryLayers(wxXmlNode *aCadLayerNode)
wxXmlNode * m_cad_header_node
void addCadHeader(wxXmlNode *aEcadNode)
void generateLayerSetAuxilliary(wxXmlNode *aStepNode)
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)
~PCB_IO_IPC2581() override
wxString genString(const wxString &aStr, const char *aPrefix=nullptr) const
std::vector< FOOTPRINT * > m_loaded_footprints
bool addPolygonCutouts(wxXmlNode *aParentNode, const SHAPE_POLY_SET::POLYGON &aPolygon)
void pruneUnusedBackdrillSpecs()
std::set< wxUniChar > m_acceptable_chars
void addLayerAttributes(wxXmlNode *aNode, PCB_LAYER_ID aLayer)
wxXmlNode * generateXmlHeader()
Creates the XML header for IPC-2581.
void ensureBackdrillSpecs(const wxString &aPadstackName, const PADSTACK &aPadstack)
wxXmlNode * generateEcadSection()
Creates the ECAD section.
wxXmlDocument * m_xml_doc
wxXmlNode * insertNode(wxXmlNode *aParent, const wxString &aName)
void addPad(wxXmlNode *aContentNode, const PAD *aPad, PCB_LAYER_ID aLayer)
void generateStepSection(wxXmlNode *aCadNode)
std::map< PCB_LAYER_ID, wxString > m_layer_name_map
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
std::map< FOOTPRINT *, wxString > m_footprint_refdes_reverse_dict
wxXmlNode * m_lastAppendedNode
Optimization for appendNode to avoid O(n) child traversal.
wxXmlNode * m_enterpriseNode
VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
void SetWidth(int aWidth) override
void SetEnd(const VECTOR2I &aEnd) override
void SetArcGeometry(const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd)
STROKE_PARAMS GetStroke() const override
void SetStart(const VECTOR2I &aStart) override
VECTOR2I GetPosition() const override
bool IsBorderEnabled() const
Disables the border, this is done by changing the stroke internally.
void TransformTextToPolySet(SHAPE_POLY_SET &aBuffer, int aClearance, int aMaxError, ERROR_LOC aErrorLoc) const
Function TransformTextToPolySet Convert the text to a polygonSet describing the actual character stro...
const VECTOR2I & GetStart() const
const VECTOR2I & GetEnd() const
virtual int GetWidth() const
PCB_LAYER_ID BottomLayer() const
VECTOR2I GetPosition() const override
bool FlashLayer(int aLayer) const
Check to see whether the via should have a pad on the specific layer.
const PADSTACK & Padstack() const
int GetWidth() const override
PCB_LAYER_ID TopLayer() const
int GetDrillValue() const
Calculate the drill value for vias (m_drill if > 0, or default drill value for the board).
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
SHAPE_LINE_CHAIN ConvertToPolyline(int aMaxError) const
Build a polyline approximation of the ellipse or arc.
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
int Width() const
Get the current width of the segments in the chain.
int PointCount() const
Return the number of points (vertices) in this line chain.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
const std::vector< VECTOR2I > & CPoints() const
Represent a set of closed polygons.
POLYGON & Polygon(int aIndex)
Return the aIndex-th subpolygon in the set.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
void Simplify()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
std::vector< SHAPE_LINE_CHAIN > POLYGON
represents a single polygon outline with holes.
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
int NewOutline()
Creates a new empty polygon in the set and returns its index.
int OutlineCount() const
Return the number of outlines in the set.
void InflateWithLinkedHoles(int aFactor, CORNER_STRATEGY aCornerStrategy, int aMaxError)
Perform outline inflation/deflation, using round corners.
void Fracture(bool aSimplify=true)
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
LINE_STYLE GetLineStyle() const
Handle a list of polygons defining a copper zone.
void SetProgressCallback(std::function< void(size_t)> aCallback)
@ RECT_CHAMFER_BOTTOM_RIGHT
@ RECT_CHAMFER_BOTTOM_LEFT
@ ROUND_ALL_CORNERS
All angles are rounded.
static bool empty(const wxTextEntryBase *aCtrl)
static constexpr EDA_ANGLE ANGLE_0
static constexpr EDA_ANGLE ANGLE_90
static constexpr EDA_ANGLE ANGLE_180
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
@ FILLED_SHAPE
Fill with object color.
static const wxChar traceIpc2581[]
This program source code file is part of KiCad, a free EDA CAD application.
static constexpr void hash_combine(std::size_t &seed)
This is a dummy function to take the final case of hash_combine below.
static constexpr std::size_t hash_val(const Types &... args)
size_t hash_fp_item(const EDA_ITEM *aItem, int aFlags)
Calculate hash of an EDA_ITEM.
Hashing functions for EDA_ITEMs.
@ REL_COORD
Use coordinates relative to the parent object.
surfaceFinishType
IPC-6012 surface finish types from Table 3-3 "Final Finish and Coating Requirements".
@ OTHER
Non-standard finish.
@ DIG
Direct Immersion Gold.
@ HT_OSP
High Temperature OSP.
@ ENEPIG_N
ENEPIG for soldering (normal gold thickness)
@ NONE
No surface finish / not specified - skip coating layer generation.
@ OSP
Organic Solderability Preservative.
@ ENIG_N
ENIG for soldering (normal gold thickness)
bool IsSolderMaskLayer(int aLayer)
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)
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
PAD_DRILL_POST_MACHINING_MODE
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
@ PTH
Plated through hole pad.
static size_t ipcPadstackHash(const PCB_VIA *aVia)
static const std::map< surfaceFinishType, wxString > surfaceFinishTypeToString
Map surfaceFinishType enum to IPC-2581 XML string values.
static bool isOppositeSideSilk(const FOOTPRINT *aFootprint, PCB_LAYER_ID aLayer)
static void mixBackdrillIntoPadstackHash(size_t &aHash, const PADSTACK &aPadstack)
static const std::map< wxString, surfaceFinishType > surfaceFinishMap
Map KiCad surface finish strings to IPC-6012 surfaceFinishType enum.
static wxString propertyUnitForCadUnits(const wxString &aCadUnits)
static surfaceFinishType getSurfaceFinishType(const wxString &aFinish)
static wxString nodeName(const wxString &aSymbolPin)
std::vector< FAB_LAYER_COLOR > dummy
const std::vector< FAB_LAYER_COLOR > & GetStandardColors(BOARD_STACKUP_ITEM_TYPE aType)
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
LINE_STYLE
Dashed line types.
! The properties of a padstack drill. Drill position is always the pad position (origin).
std::optional< PAD_DRILL_POST_MACHINING_MODE > mode
@ DESCRIPTION
Field Description of part, i.e. "1/4W 1% Metal Film Resistor".
std::vector< std::string > header
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