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 );
182 std::vector<FOOTPRINT*> retval;
185 retval.push_back(
static_cast<FOOTPRINT*
>( fp->Clone() ) );
195 if( aParent->GetChildren() )
196 aNode->SetNext( aParent->GetChildren() );
198 aNode->SetNext(
nullptr );
200 aParent->SetChildren( aNode );
201 aNode->SetParent( aParent );
210 aNode->SetNext( aPrev->GetNext() );
211 aPrev->SetNext( aNode );
212 aNode->SetParent( aPrev->GetParent() );
233 check = check->GetParent();
246 wxXmlNode* node =
new wxXmlNode( wxXML_ELEMENT_NODE, aName );
261 aNode->SetParent( aParent );
266 aParent->AddChild( aNode );
278 wxXmlNode* node =
new wxXmlNode( wxXML_ELEMENT_NODE, aName );
292 str.Replace( wxT(
":" ), wxT(
"_" ) );
296 for( wxString::const_iterator iter = aStr.begin(); iter != aStr.end(); ++iter )
313 wxString key = aPrefix ? wxString( aPrefix ) + wxT(
":" ) + aStr : aStr;
323 wxString
name = base;
327 name = wxString::Format(
"%s_%d", base, suffix++ );
343 const char* aPrefix )
const
345 return genString( wxString::Format( wxS(
"%s_%s" ),
347 m_board->GetLayerName( aBottom ) ), aPrefix );
358 if(
name.empty() && fp )
362 if( fp->
Pads()[ii] == aPad )
370 name = wxString::Format(
"NPTH%zu", ii );
371 else if(
name.empty() )
372 name = wxString::Format(
"PAD%zu", ii );
383 [&](
const wxString& aName )
406 wxString baseName =
genString( ref,
"CMP" );
407 wxString
name = baseName;
410 while( !tryInsert(
name ) )
411 name = wxString::Format(
"%s_%d", baseName, suffix++ );
421 wxString str = wxString::FromCDouble( aVal, aSigFig == -1 ?
m_sigfig : aSigFig );
424 while( str.EndsWith( wxT(
"00" ) ) )
428 if( str == wxT(
"-0.0" ) )
453 aNode->AddAttribute( aName, aValue );
459 wxXmlNode* xmlHeaderNode =
new wxXmlNode(wxXML_ELEMENT_NODE,
"IPC-2581");
461 addAttribute( xmlHeaderNode,
"xmlns",
"http://webstds.ipc.org/2581");
462 addAttribute( xmlHeaderNode,
"xmlns:xsi",
"http://www.w3.org/2001/XMLSchema-instance");
463 addAttribute( xmlHeaderNode,
"xmlns:xsd",
"http://www.w3.org/2001/XMLSchema");
468 "http://webstds.ipc.org/2581 http://webstds.ipc.org/2581/IPC-2581B1.xsd" );
473 "http://webstds.ipc.org/2581 http://webstds.ipc.org/2581/IPC-2581C.xsd" );
478 return xmlHeaderNode;
491 wxXmlNode* node =
appendNode( contentNode,
"FunctionMode" );
499 wxFileName fn(
m_board->GetFileName() );
506 contentNode->AddChild( color_node );
510 wxXmlNode* fillNode =
appendNode( contentNode,
"DictionaryFillDesc" );
530 contentNode->AddChild( color_node );
539 wxXmlNode* location_node =
appendNode( aNode,
"Location" );
614 wxXmlNode* color_node =
new wxXmlNode( wxXML_ELEMENT_NODE,
"DictionaryColor" );
618 wxString layer_name = item->GetLayerName();
619 int sub_layer_count = 1;
621 if( layer_name.empty() )
622 layer_name =
m_board->GetLayerName( item->GetBrdLayerId() );
624 layer_name =
genString( layer_name,
"LAYER" );
628 layer_name =
genString( wxString::Format(
"DIELECTRIC_%d", item->GetDielectricLayerId() ),
630 sub_layer_count = item->GetSublayersCount();
637 for(
int sub_idx = 0; sub_idx < sub_layer_count; sub_idx++ )
639 wxString sub_layer_name = layer_name;
642 sub_layer_name += wxString::Format(
"_%d", sub_idx );
644 wxXmlNode* node =
appendNode( aContentNode,
"LayerRef" );
650 wxXmlNode* entry_color =
appendNode( color_node,
"EntryColor" );
652 wxXmlNode* color =
appendNode( entry_color,
"Color" );
654 wxString colorName = item->GetColor( sub_idx );
656 if( colorName.StartsWith( wxT(
"#" ) ) )
659 COLOR4D layer_color( colorName );
671 if( fab_color.GetName() == colorName )
673 addAttribute( color,
"r", wxString::Format(
"%d",
KiROUND( fab_color.GetColor( item->GetType() ).r * 255 ) ) );
674 addAttribute( color,
"g", wxString::Format(
"%d",
KiROUND( fab_color.GetColor( item->GetType() ).g * 255 ) ) );
675 addAttribute( color,
"b", wxString::Format(
"%d",
KiROUND( fab_color.GetColor( item->GetType() ).b * 255 ) ) );
695 wxXmlNode* fillDesc_node =
appendNode( aNode,
"FillDesc" );
701 wxXmlNode* fillDesc_node =
appendNode( aNode,
"FillDesc" );
702 addAttribute( fillDesc_node,
"fillProperty",
"HOLLOW" );
709 wxCHECK_RET( aNode,
"aNode is null" );
714 wxXmlNode* entry_node =
nullptr;
718 size_t hash =
lineHash( aWidth, aDashType );
719 wxString
name = wxString::Format(
"LINE_%zu",
m_line_dict.size() + 1 );
723 wxXmlNode* lineDesc_node =
appendNode( aNode,
"LineDescRef" );
738 wxXmlNode* line_node =
appendNode( entry_node,
"LineDesc" );
771 if( outlineCount == 0 )
778 if( outlineCount == 1 )
784 wxXmlNode* special_node =
appendNode( aContentNode,
"UserSpecial" );
786 for(
int ii = 0; ii < outlineCount; ++ii )
802 wxXmlNode* text_node =
appendNode( aContentNode,
"UserSpecial" );
804 std::list<VECTOR2I> pts;
812 wxXmlNode* line_node =
nullptr;
819 addXY( line_node, pts.front(),
"startX",
"startY" );
820 addXY( line_node, pts.back(),
"endX",
"endY" );
824 line_node =
appendNode( text_node,
"Polyline" );
825 wxXmlNode* point_node =
appendNode( line_node,
"PolyBegin" );
826 addXY( point_node, pts.front() );
828 auto iter = pts.begin();
830 for( ++iter; iter != pts.end(); ++iter )
832 wxXmlNode* step_node =
appendNode( line_node,
"PolyStepSegment" );
833 addXY( step_node, *iter );
848 if( aPt1 == pts.back() )
849 pts.push_back( aPt2 );
850 else if( aPt2 == pts.front() )
851 pts.push_front( aPt1 );
852 else if( aPt1 == pts.front() )
853 pts.push_front( aPt2 );
854 else if( aPt2 == pts.back() )
855 pts.push_back( aPt1 );
859 pts.push_back( aPt1 );
860 pts.push_back( aPt2 );
865 pts.push_back( aPt1 );
866 pts.push_back( aPt2 );
872 if( aPoly.PointCount() < 3 )
875 wxXmlNode* outline_node =
appendNode( text_node,
"Outline" );
876 wxXmlNode* poly_node =
appendNode( outline_node,
"Polygon" );
879 const std::vector<VECTOR2I>& polyPts = aPoly.CPoints();
880 wxXmlNode* point_node =
appendNode( poly_node,
"PolyBegin" );
881 addXY( point_node, polyPts.front() );
883 for(
size_t ii = 1; ii < polyPts.size(); ++ii )
885 wxXmlNode* poly_step_node =
887 addXY( poly_step_node, polyPts[ii] );
890 point_node =
appendNode( poly_node,
"PolyStepSegment" );
891 addXY( point_node, polyPts.front() );
902 if( text_node->GetChildren() ==
nullptr )
904 aContentNode->RemoveChild( text_node );
917 wxXmlNode* shape_node =
appendNode( aContentNode,
"StandardPrimitiveRef" );
922 int maxError =
m_board->GetDesignSettings().m_MaxError;
942 wxXmlNode* circle_node =
appendNode( entry_node,
"Circle" );
943 circle_node->AddAttribute(
"diameter",
956 wxXmlNode* rect_node =
appendNode( entry_node,
"RectCenter" );
972 wxXmlNode* oval_node =
appendNode( entry_node,
"Oval" );
988 wxXmlNode* roundrect_node =
appendNode( entry_node,
"RectRound" );
992 roundrect_node->AddAttribute(
"radius",
1010 wxXmlNode* chamfered_node =
appendNode( entry_node,
"RectCham" );
1015 int shorterSide = std::min( pad_size.
x, pad_size.
y );
1046 int dx = pad_size.
x / 2;
1047 int dy = pad_size.
y / 2;
1048 int ddx = trap_delta.
x / 2;
1049 int ddy = trap_delta.
y / 2;
1051 outline.
Append( -dx - ddy, dy + ddx );
1052 outline.
Append( dx + ddy, dy - ddx );
1053 outline.
Append( dx - ddy, -dy + ddx );
1054 outline.
Append( -dx + ddy, -dy - ddx );
1079 if( expansion !=
VECTOR2I( 0, 0 ) )
1096 wxXmlNode* shape_node =
appendNode( aContentNode,
"StandardPrimitiveRef" );
1111 wxXmlNode* shape_node =
appendNode( aContentNode,
"UserPrimitiveRef" );
1128 wxXmlNode* polyline_node =
appendNode( aContentNode,
"Polyline" );
1136 wxXmlNode* begin_node =
appendNode( polyline_node,
"PolyBegin" );
1137 addXY( begin_node, start );
1140 wxXmlNode* arc1_node =
appendNode( polyline_node,
"PolyStepCurve" );
1141 addXY( arc1_node, mid );
1146 wxXmlNode* arc2_node =
appendNode( polyline_node,
"PolyStepCurve" );
1147 addXY( arc2_node, start );
1159 int diameter = aShape.
GetRadius() * 2.0;
1166 wxXmlNode* special_node =
appendNode( entry_node,
"UserSpecial" );
1168 wxXmlNode* circle_node =
appendNode( special_node,
"Circle" );
1194 wxXmlNode* polyline_node =
appendNode( aContentNode,
"Polyline" );
1199 wxXmlNode* begin_node =
appendNode( polyline_node,
"PolyBegin" );
1200 addXY( begin_node, corners[0] );
1202 for(
size_t i = 1; i < corners.size(); ++i )
1204 wxXmlNode* step_node =
appendNode( polyline_node,
"PolyStepSegment" );
1205 addXY( step_node, corners[i] );
1209 wxXmlNode* close_node =
appendNode( polyline_node,
"PolyStepSegment" );
1210 addXY( close_node, corners[0] );
1212 if( stroke_width > 0 )
1213 addLineDesc( polyline_node, stroke_width, dash,
true );
1223 wxXmlNode* special_node =
appendNode( entry_node,
"UserSpecial" );
1229 wxXmlNode* rect_node =
appendNode( special_node,
"RectRound" );
1246 width += stroke_width;
1247 height += stroke_width;
1275 wxXmlNode* polyline_node =
appendNode( aContentNode,
"Polyline" );
1276 const std::vector<VECTOR2I>& pts = outline.
CPoints();
1278 wxXmlNode* begin_node =
appendNode( polyline_node,
"PolyBegin" );
1279 addXY( begin_node, pts[0] );
1281 for(
size_t jj = 1; jj < pts.size(); ++jj )
1283 wxXmlNode* step_node =
appendNode( polyline_node,
"PolyStepSegment" );
1284 addXY( step_node, pts[jj] );
1288 if( pts.size() > 2 && pts.front() != pts.back() )
1290 wxXmlNode* close_node =
appendNode( polyline_node,
"PolyStepSegment" );
1291 addXY( close_node, pts[0] );
1294 if( stroke_width > 0 )
1295 addLineDesc( polyline_node, stroke_width, dash,
true );
1309 wxXmlNode* special_node =
appendNode( entry_node,
"UserSpecial" );
1331 wxXmlNode* arc_node =
appendNode( aContentNode,
"Arc" );
1333 addXY( arc_node, aShape.
GetEnd(),
"endX",
"endY" );
1350 wxXmlNode* polyline_node =
appendNode( aContentNode,
"Polyline" );
1354 std::vector<VECTOR2I> points;
1357 wxXmlNode* point_node =
appendNode( polyline_node,
"PolyBegin" );
1358 addXY( point_node, points[0] );
1360 for(
size_t i = 1; i < points.size(); i++ )
1362 wxXmlNode* seg_node =
appendNode( polyline_node,
"PolyStepSegment" );
1363 addXY( seg_node, points[i] );
1377 wxXmlNode* line_node =
appendNode( aContentNode,
"Line" );
1379 addXY( line_node, aShape.
GetEnd(),
"endX",
"endY" );
1409 if(
chain.PointCount() < 2 )
1412 wxXmlNode* polyline_node =
appendNode( aContentNode,
"Polyline" );
1413 const std::vector<VECTOR2I>& pts =
chain.CPoints();
1415 wxXmlNode* begin_node =
appendNode( polyline_node,
"PolyBegin" );
1416 addXY( begin_node, pts[0] );
1418 for(
size_t jj = 1; jj < pts.size(); ++jj )
1420 wxXmlNode* step_node =
appendNode( polyline_node,
"PolyStepSegment" );
1421 addXY( step_node, pts[jj] );
1425 if( !isArc && pts.size() > 2 && pts.front() != pts.back() )
1427 wxXmlNode* close_node =
appendNode( polyline_node,
"PolyStepSegment" );
1428 addXY( close_node, pts[0] );
1431 if( stroke_width > 0 )
1432 addLineDesc( polyline_node, stroke_width, dash,
true );
1442 wxXmlNode* special_node =
appendNode( entry_node,
"UserSpecial" );
1466 if( !aInline && !
name.empty() )
1468 wxXmlNode* shape_node =
appendNode( aContentNode,
"UserPrimitiveRef" );
1477 wxXmlNode* slotNode =
appendNode( aNode,
"SlotCavity" );
1497 if( drill_size.
y > drill_size.
x )
1499 std::swap( drill_size.
x, drill_size.
y );
1500 rotation = ( rotation +
ANGLE_90 ).Normalize();
1506 wxXmlNode* xformNode =
appendNode( slotNode,
"Xform" );
1511 wxXmlNode* ovalNode =
appendNode( slotNode,
"Oval" );
1519 int maxError =
m_board->GetDesignSettings().m_MaxError;
1531 wxXmlNode* roleNode =
appendNode( logisticNode,
"Role" );
1539 wxXmlNode* personNode =
appendNode( logisticNode,
"Person" );
1541 addAttribute( personNode,
"enterpriseRef",
"UNKNOWN" );
1544 return logisticNode;
1555 addAttribute( historyNode,
"origination", wxDateTime::Now().FormatISOCombined() );
1557 addAttribute( historyNode,
"lastChange", wxDateTime::Now().FormatISOCombined() );
1559 wxXmlNode* fileRevisionNode =
appendNode( historyNode,
"FileRevision" );
1560 addAttribute( fileRevisionNode,
"fileRevisionId",
"1" );
1561 addAttribute( fileRevisionNode,
"comment",
"NO COMMENT" );
1564 wxXmlNode* softwarePackageNode =
appendNode( fileRevisionNode,
"SoftwarePackage" );
1567 addAttribute( softwarePackageNode,
"vendor",
"KiCad EDA" );
1569 wxXmlNode* certificationNode =
appendNode( softwarePackageNode,
"Certification" );
1570 addAttribute( certificationNode,
"certificationStatus",
"SELFTEST" );
1593 m_refdes =
new std::vector<REFDES>();
1594 m_props =
new std::map<wxString, wxString>();
1605 wxString m_OEMDesignRef;
1609 wxString m_description;
1611 std::vector<REFDES>* m_refdes;
1612 std::map<wxString, wxString>*
m_props;
1615 std::set<std::unique_ptr<struct BOM_ENTRY>,
1616 std::function<bool(
const std::unique_ptr<struct BOM_ENTRY>&,
1617 const std::unique_ptr<struct BOM_ENTRY>& )>> bom_entries(
1618 [](
const std::unique_ptr<struct BOM_ENTRY>& a,
1619 const std::unique_ptr<struct BOM_ENTRY>& b )
1621 return a->m_OEMDesignRef < b->m_OEMDesignRef;
1626 std::unique_ptr<FOOTPRINT> fp(
static_cast<FOOTPRINT*
>( fp_it->Clone() ) );
1627 fp->SetParentGroup(
nullptr );
1628 fp->SetPosition( {0, 0} );
1629 fp->SetOrientation(
ANGLE_0 );
1632 if( fp->IsFlipped() )
1640 Report( wxString::Format(
_(
"Footprint %s not found in dictionary; BOM data may be incomplete." ),
1641 fp->GetFPID().GetLibItemName().wx_str() ),
1646 auto entry = std::make_unique<struct BOM_ENTRY>();
1652 entry->m_OEMDesignRef = it->second;
1656 Report( wxString::Format(
_(
"Component \"%s\" missing OEM reference; BOM entry will be skipped." ),
1657 fp->GetFPID().GetLibItemName().wx_str() ),
1661 entry->m_OEMDesignRef =
genString( entry->m_OEMDesignRef,
"REF" );
1663 entry->m_pads = fp->GetPadCount();
1667 const wxString variantName =
m_board ?
m_board->GetCurrentVariant() : wxString();
1669 if( entry->m_pads == 0 || fp_it->GetExcludedFromBOMForVariant( variantName ) )
1670 entry->m_type =
"DOCUMENT";
1672 entry->m_type =
"ELECTRICAL";
1677 if( descField && !descField->
GetShownText(
false ).IsEmpty() )
1678 entry->m_description = descField->
GetShownText(
false );
1680 auto[ bom_iter, inserted ] = bom_entries.insert( std::move( entry ) );
1683 ( *bom_iter )->m_count++;
1687 refdes.m_pkg = fp->GetFPID().GetLibItemName().wx_str();
1688 refdes.m_populate = !fp->GetDNPForVariant( variantName )
1689 && !fp->GetExcludedFromBOMForVariant( variantName );
1692 ( *bom_iter )->m_refdes->push_back( refdes );
1696 for(
PCB_FIELD* prop : fp->GetFields() )
1701 if( prop->IsMandatory() && !prop->IsValue() )
1704 ( *bom_iter )->m_props->emplace( prop->GetName(), prop->GetShownText(
false ) );
1708 if( bom_entries.empty() )
1711 wxFileName fn(
m_board->GetFileName() );
1713 wxXmlNode* bomNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"Bom" );
1714 m_xml_root->InsertChild( bomNode, aEcadNode );
1717 wxXmlNode* bomHeaderNode =
appendNode( bomNode,
"BomHeader" );
1720 if( bomRevision.IsEmpty() )
1721 bomRevision =
m_board->GetTitleBlock().GetRevision();
1723 if( bomRevision.IsEmpty() )
1724 bomRevision = wxS(
"1.0" );
1726 addAttribute( bomHeaderNode,
"revision", bomRevision );
1729 wxXmlNode* stepRefNode =
appendNode( bomHeaderNode,
"StepRef" );
1732 for(
const auto& entry : bom_entries )
1734 wxXmlNode* bomEntryNode =
appendNode( bomNode,
"BomItem" );
1735 addAttribute( bomEntryNode,
"OEMDesignNumberRef", entry->m_OEMDesignRef );
1736 addAttribute( bomEntryNode,
"quantity", wxString::Format(
"%d", entry->m_count ) );
1737 addAttribute( bomEntryNode,
"pinCount", wxString::Format(
"%d", entry->m_pads ) );
1738 addAttribute( bomEntryNode,
"category", entry->m_type );
1740 if( !entry->m_description.IsEmpty() )
1741 addAttribute( bomEntryNode,
"description", entry->m_description );
1743 for(
const REFDES& refdes : *( entry->m_refdes ) )
1745 wxXmlNode* refdesNode =
appendNode( bomEntryNode,
"RefDes" );
1748 addAttribute( refdesNode,
"populate", refdes.m_populate ?
"true" :
"false" );
1749 addAttribute( refdesNode,
"layerRef", refdes.m_layer );
1752 wxXmlNode* characteristicsNode =
appendNode( bomEntryNode,
"Characteristics" );
1753 addAttribute( characteristicsNode,
"category", entry->m_type );
1755 for(
const auto& prop : *( entry->m_props ) )
1757 wxXmlNode* textualDefNode =
appendNode( characteristicsNode,
"Textual" );
1758 addAttribute( textualDefNode,
"definitionSource",
"KICAD" );
1759 addAttribute( textualDefNode,
"textualCharacteristicName", prop.first );
1760 addAttribute( textualDefNode,
"textualCharacteristicValue", prop.second );
1778 wxXmlNode* cadDataNode =
appendNode( ecadNode,
"CadData" );
1797 std::vector<BOARD_STACKUP_ITEM*> layers = stackup.
GetList();
1798 std::set<PCB_LAYER_ID> added_layers;
1800 for(
int i = 0; i < stackup.
GetCount(); i++ )
1804 for(
int sublayer_id = 0; sublayer_id < stackup_item->
GetSublayersCount(); sublayer_id++ )
1808 if( ly_name.IsEmpty() )
1817 if( sublayer_id > 0 )
1818 ly_name += wxString::Format(
"_%d", sublayer_id );
1822 ly_name =
genString( ly_name,
"SPEC_LAYER" );
1824 wxXmlNode* specNode =
appendNode( aCadLayerNode,
"Spec" );
1826 wxXmlNode* generalNode =
appendNode( specNode,
"General" );
1828 wxXmlNode* propertyNode =
appendNode( generalNode,
"Property" );
1830 switch ( stackup_item->
GetType() )
1835 wxXmlNode* conductorNode =
appendNode( specNode,
"Conductor" );
1837 propertyNode =
appendNode( conductorNode,
"Property" );
1838 addAttribute( propertyNode,
"unit", wxT(
"SIEMENS/M" ) );
1839 addAttribute( propertyNode,
"value", wxT(
"5.959E7" ) );
1845 propertyNode =
appendNode( generalNode,
"Property" );
1846 addAttribute( propertyNode,
"text", wxString::Format(
"Type : %s",
1848 wxXmlNode* dielectricNode =
appendNode( specNode,
"Dielectric" );
1849 addAttribute( dielectricNode,
"type",
"DIELECTRIC_CONSTANT" );
1850 propertyNode =
appendNode( dielectricNode,
"Property" );
1853 dielectricNode =
appendNode( specNode,
"Dielectric" );
1854 addAttribute( dielectricNode,
"type",
"LOSS_TANGENT" );
1855 propertyNode =
appendNode( dielectricNode,
"Property" );
1862 propertyNode =
appendNode( generalNode,
"Property" );
1863 addAttribute( propertyNode,
"text", wxString::Format(
"Color : %s",
1865 propertyNode =
appendNode( generalNode,
"Property" );
1866 addAttribute( propertyNode,
"text", wxString::Format(
"Type : %s",
1872 propertyNode =
appendNode( generalNode,
"Property" );
1873 addAttribute( propertyNode,
"text", wxString::Format(
"Color : %s",
1875 propertyNode =
appendNode( generalNode,
"Property" );
1876 addAttribute( propertyNode,
"text", wxString::Format(
"Type : %s",
1880 if( stackup_item->
GetEpsilonR( sublayer_id ) > 1.0 )
1882 wxXmlNode* dielectricNode =
appendNode( specNode,
"Dielectric" );
1883 addAttribute( dielectricNode,
"type",
"DIELECTRIC_CONSTANT" );
1884 propertyNode =
appendNode( dielectricNode,
"Property" );
1891 wxXmlNode* dielectricNode =
appendNode( specNode,
"Dielectric" );
1892 addAttribute( dielectricNode,
"type",
"LOSS_TANGENT" );
1893 propertyNode =
appendNode( dielectricNode,
"Property" );
1911 wxXmlNode* specNode =
appendNode( aCadLayerNode,
"Spec" );
1914 wxXmlNode* surfaceFinishNode =
appendNode( specNode,
"SurfaceFinish" );
1926 wxXmlNode* cadHeaderNode =
appendNode( aEcadNode,
"CadHeader" );
1970 addAttribute( aNode,
"layerFunction",
"BOARD_OUTLINE" );
2011 aLayer ==
F_Cu ?
"TOP"
2012 : aLayer ==
B_Cu ?
"BOTTOM"
2031 wxXmlNode* stackupNode =
appendNode( aCadLayerNode,
"Stackup" );
2032 addAttribute( stackupNode,
"name",
"Primary_Stackup" );
2039 addAttribute( stackupNode,
"stackupStatus",
"PROPOSED" );
2041 wxXmlNode* stackupGroup =
appendNode( stackupNode,
"StackupGroup" );
2042 addAttribute( stackupGroup,
"name",
"Primary_Stackup_Group" );
2047 std::vector<BOARD_STACKUP_ITEM*> layers = stackup.
GetList();
2048 std::set<PCB_LAYER_ID> added_layers;
2051 for(
int i = 0; i < stackup.
GetCount(); i++ )
2055 for(
int sublayer_id = 0; sublayer_id < stackup_item->
GetSublayersCount(); sublayer_id++ )
2060 if( hasCoating && layer_id ==
F_Cu && sublayer_id == 0 )
2062 wxXmlNode* coatingLayer =
appendNode( stackupGroup,
"StackupLayer" );
2063 addAttribute( coatingLayer,
"layerOrGroupRef",
"COATING_TOP" );
2067 addAttribute( coatingLayer,
"sequence", wxString::Format(
"%d", sequence++ ) );
2069 wxXmlNode* specRefNode =
appendNode( coatingLayer,
"SpecRef" );
2073 wxXmlNode* stackupLayer =
appendNode( stackupGroup,
"StackupLayer" );
2076 if( ly_name.IsEmpty() )
2085 if( sublayer_id > 0 )
2086 ly_name += wxString::Format(
"_%d", sublayer_id );
2090 wxString spec_name =
genString( ly_name,
"SPEC_LAYER" );
2091 ly_name =
genString( ly_name,
"LAYER" );
2093 addAttribute( stackupLayer,
"layerOrGroupRef", ly_name );
2097 addAttribute( stackupLayer,
"sequence", wxString::Format(
"%d", sequence++ ) );
2099 wxXmlNode* specLayerNode =
appendNode( stackupLayer,
"SpecRef" );
2105 wxXmlNode* coatingLayer =
appendNode( stackupGroup,
"StackupLayer" );
2106 addAttribute( coatingLayer,
"layerOrGroupRef",
"COATING_BOTTOM" );
2110 addAttribute( coatingLayer,
"sequence", wxString::Format(
"%d", sequence++ ) );
2112 wxXmlNode* specRefNode =
appendNode( coatingLayer,
"SpecRef" );
2127 std::vector<BOARD_STACKUP_ITEM*> layers = stackup.
GetList();
2128 std::set<PCB_LAYER_ID> added_layers;
2130 for(
int i = 0; i < stackup.
GetCount(); i++ )
2137 for(
int sublayer_id = 0; sublayer_id < stackup_item->
GetSublayersCount(); sublayer_id++ )
2139 wxXmlNode* cadLayerNode =
appendNode( aCadLayerNode,
"Layer" );
2142 if( ly_name.IsEmpty() )
2152 if( sublayer_id > 0 )
2153 ly_name += wxString::Format(
"_%d", sublayer_id );
2157 ly_name =
genString( ly_name,
"LAYER" );
2164 addAttribute( cadLayerNode,
"layerFunction",
"DIELCORE" );
2166 addAttribute( cadLayerNode,
"layerFunction",
"DIELPREG" );
2181 LSEQ layer_seq =
m_board->GetEnabledLayers().Seq();
2190 added_layers.insert( layer );
2191 wxXmlNode* cadLayerNode =
appendNode( aCadLayerNode,
"Layer" );
2204 wxXmlNode* topCoatingNode =
appendNode( aCadLayerNode,
"Layer" );
2206 addAttribute( topCoatingNode,
"layerFunction",
"COATINGCOND" );
2208 addAttribute( topCoatingNode,
"polarity",
"POSITIVE" );
2210 wxXmlNode* botCoatingNode =
appendNode( aCadLayerNode,
"Layer" );
2211 addAttribute( botCoatingNode,
"name",
"COATING_BOTTOM" );
2212 addAttribute( botCoatingNode,
"layerFunction",
"COATINGCOND" );
2214 addAttribute( botCoatingNode,
"polarity",
"POSITIVE" );
2233 for(
PAD*
pad : fp->Pads() )
2235 if(
pad->HasDrilledHole() )
2237 else if(
pad->HasHole() )
2244 wxXmlNode* drillNode =
appendNode( aCadLayerNode,
"Layer" );
2245 drillNode->AddAttribute(
"name",
genLayersString( layers.first, layers.second,
"DRILL" ) );
2250 wxXmlNode* spanNode =
appendNode( drillNode,
"Span" );
2257 wxXmlNode* drillNode =
appendNode( aCadLayerNode,
"Layer" );
2258 drillNode->AddAttribute(
"name",
genLayersString( layers.first, layers.second,
"SLOT" ) );
2264 wxXmlNode* spanNode =
appendNode( drillNode,
"Span" );
2280 std::vector<std::tuple<auxLayerType, PCB_LAYER_ID, PCB_LAYER_ID>> new_layers;
2282 if(
via->Padstack().IsFilled().value_or(
false ) )
2285 if(
via->Padstack().IsCapped().value_or(
false ) )
2290 if(
via->Padstack().IsPlugged( layer ).value_or(
false ) )
2293 if(
via->Padstack().IsCovered( layer ).value_or(
false ) )
2296 if(
via->Padstack().IsTented( layer ).value_or(
false ) )
2300 for(
auto& tuple : new_layers )
2306 bool add_node =
true;
2309 wxString layerFunction;
2312 switch( std::get<0>(layers) )
2316 layerFunction =
"COATINGNONCOND";
2320 layerFunction =
"HOLEFILL";
2324 layerFunction =
"COATINGNONCOND";
2328 layerFunction =
"HOLEFILL";
2332 layerFunction =
"COATINGCOND";
2340 if( add_node && !vec.empty() )
2342 wxXmlNode* node =
appendNode( aCadLayerNode,
"Layer" );
2356 const bool first_external = std::get<1>( layers ) ==
F_Cu || std::get<1>( layers ) ==
B_Cu;
2357 const bool second_external = std::get<2>( layers ) ==
F_Cu || std::get<2>( layers ) ==
B_Cu;
2359 if( first_external )
2361 if( second_external )
2368 if( second_external )
2374 wxXmlNode* spanNode =
appendNode( node,
"Span" );
2385 wxXmlNode* stepNode =
appendNode( aCadNode,
"Step" );
2386 wxFileName fn(
m_board->GetFileName() );
2392 wxXmlNode* datumNode =
appendNode( stepNode,
"Datum" );
2412 wxXmlNode* padNode =
appendNode( aContentNode,
"Pad" );
2419 wxXmlNode* xformNode =
appendNode( padNode,
"Xform" );
2426 addShape( padNode, *aPad, aLayer );
2430 wxXmlNode* pinRefNode =
appendNode( padNode,
"PinRef" );
2443 wxXmlNode* padNode =
appendNode( aContentNode,
"Pad" );
2464 addAttribute( aPadNode,
"padstackDefRef", th_pair->second );
2471 wxXmlNode* padStackDefNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"PadStackDef" );
2486 wxXmlNode* padStackHoleNode =
appendNode( padStackDefNode,
"PadstackHoleDef" );
2487 padStackHoleNode->AddAttribute(
"name",
2488 wxString::Format(
"%s%d_%d",
2504 if( !
m_board->IsLayerEnabled( layer ) )
2507 wxXmlNode* padStackPadDefNode =
appendNode( padStackDefNode,
"PadstackPadDef" );
2509 addAttribute( padStackPadDefNode,
"padUse",
"REGULAR" );
2517 addShape( padStackPadDefNode, shape );
2521 addShape( padStackPadDefNode, *aPad, layer );
2533 addAttribute( aContentNode,
"padstackDefRef", via_pair->second );
2540 wxXmlNode* padStackDefNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"PadStackDef" );
2546 wxXmlNode* padStackHoleNode =
appendNode( padStackDefNode,
"PadstackHoleDef" );
2549 addAttribute( padStackHoleNode,
"platingStatus",
"VIA" );
2557 auto addPadShape{ [&](
PCB_LAYER_ID aLayer,
const PCB_VIA* aViaShape,
const wxString& aLayerRef,
2558 bool aDrill ) ->
void
2563 shape.
SetEnd( {
KiROUND( aViaShape->GetDrillValue() / 2.0 ), 0 } );
2565 shape.
SetEnd( {
KiROUND( aViaShape->GetWidth( aLayer ) / 2.0 ), 0 } );
2567 wxXmlNode* padStackPadDefNode =
2568 appendNode( padStackDefNode,
"PadstackPadDef" );
2569 addAttribute( padStackPadDefNode,
"layerRef", aLayerRef );
2570 addAttribute( padStackPadDefNode,
"padUse",
"REGULAR" );
2573 addShape( padStackPadDefNode, shape );
2593 addPadShape( layer, aVia,
genLayerString( layer,
"PLUGGING" ),
true );
2596 addPadShape( layer, aVia,
genLayerString( layer,
"COVERING" ),
false );
2599 addPadShape( layer, aVia,
genLayerString( layer,
"TENTING" ),
false );
2608 if( aCadUnits == wxT(
"MILLIMETER" ) )
2611 if( aCadUnits == wxT(
"MICRON" ) )
2612 return wxT(
"MICRON" );
2614 if( aCadUnits == wxT(
"INCH" ) )
2615 return wxT(
"INCH" );
2632 && ( aDrill.size.x > 0 || aDrill.size.y > 0 );
2635 if( !hasBackdrill( secondary ) && !hasBackdrill( tertiary ) )
2646 if( hasBackdrill( secondary )
2647 && ( !layerHasRef( secondary.
start ) || !layerHasRef( secondary.
end ) ) )
2652 if( hasBackdrill( tertiary )
2653 && ( !layerHasRef( tertiary.
start ) || !layerHasRef( tertiary.
end ) ) )
2666 LSEQ cuStack =
m_board->GetEnabledLayers().CuStack();
2670 auto it = std::find( cuStack.begin(), cuStack.end(), aDrill.end );
2672 if( it == cuStack.end() )
2675 if( aDrill.start ==
F_Cu )
2679 if( it == cuStack.end() )
2685 if( aDrill.start ==
B_Cu )
2687 if( it == cuStack.begin() )
2697 const wxString& aSpecName ) -> wxString
2699 if( !hasBackdrill( aDrill ) )
2707 PCB_LAYER_ID mustNotCut = computeMustNotCutLayer( aDrill );
2729 wxString postMachiningComment;
2732 postMachiningComment = wxT(
"post-machining=COUNTERBORE" );
2734 postMachiningComment = wxT(
"post-machining=COUNTERSINK" );
2738 wxXmlNode* bd =
appendNode( specNode,
"Backdrill" );
2742 addAttribute( p,
"layerOrGroupRef", startLayer->second );
2748 wxXmlNode* bd =
appendNode( specNode,
"Backdrill" );
2749 addAttribute( bd,
"type", wxT(
"MUST_NOT_CUT_LAYER" ) );
2752 addAttribute( p,
"layerOrGroupRef", mustNotCutEntry->second );
2765 if( dielectric > 0 )
2766 stubLength = dielectric / 2;
2770 wxXmlNode* bd =
appendNode( specNode,
"Backdrill" );
2778 if( !postMachiningComment.IsEmpty() )
2780 wxXmlNode* bd =
appendNode( specNode,
"Backdrill" );
2792 wxString secondarySpec = createSpec( secondary, wxString::Format( wxT(
"BD_%dA" ), specIndex ) );
2793 wxString tertiarySpec = createSpec( tertiary, wxString::Format( wxT(
"BD_%dB" ), specIndex ) );
2795 if( secondarySpec.IsEmpty() && tertiarySpec.IsEmpty() )
2800 std::array<wxString, 2>{ secondarySpec, tertiarySpec } );
2811 auto addRef = [&](
const wxString& aSpecName )
2813 if( aSpecName.IsEmpty() )
2816 wxXmlNode* specRefNode =
appendNode( aHoleNode,
"SpecRef" );
2821 for(
const wxString& specName : it->second )
2837 wxXmlNode* specNode = it->second;
2859 wxXmlNode* polygonNode =
nullptr;
2867 polygonNode =
appendNode( aParentNode,
"Polygon" );
2868 wxXmlNode* polybeginNode =
appendNode( polygonNode,
"PolyBegin" );
2870 const std::vector<VECTOR2I>& pts = aPolygon.
CPoints();
2871 addXY( polybeginNode, pts[0] );
2873 for(
size_t ii = 1; ii < pts.size(); ++ii )
2875 wxXmlNode* polyNode =
appendNode( polygonNode,
"PolyStepSegment" );
2876 addXY( polyNode, pts[ii] );
2879 wxXmlNode* polyendNode =
appendNode( polygonNode,
"PolyStepSegment" );
2880 addXY( polyendNode, pts[0] );
2891 addLineDesc( polygonNode, aWidth, aDashType,
true );
2895 wxCHECK( aWidth == 0,
false );
2908 for(
size_t ii = 1; ii < aPolygon.size(); ++ii )
2910 wxCHECK2( aPolygon[ii].PointCount() >= 3,
continue );
2912 wxXmlNode* cutoutNode =
appendNode( aParentNode,
"Cutout" );
2913 wxXmlNode* polybeginNode =
appendNode( cutoutNode,
"PolyBegin" );
2915 const std::vector<VECTOR2I>& hole = aPolygon[ii].CPoints();
2916 addXY( polybeginNode, hole[0] );
2918 for(
size_t jj = 1; jj < hole.size(); ++jj )
2920 wxXmlNode* polyNode =
appendNode( cutoutNode,
"PolyStepSegment" );
2921 addXY( polyNode, hole[jj] );
2924 wxXmlNode* polyendNode =
appendNode( cutoutNode,
"PolyStepSegment" );
2925 addXY( polyendNode, hole[0] );
2938 wxXmlNode* outlineNode =
appendNode( aParentNode,
"Outline" );
2955 wxLogTrace(
traceIpc2581, wxS(
"Failed to add polygon to outline" ) );
2958 if( !outlineNode->GetChildren() )
2960 aParentNode->RemoveChild( outlineNode );
2977 wxXmlNode* contourNode =
appendNode( aParentNode,
"Contour" );
2987 aParentNode->RemoveChild( contourNode );
3000 if( !
m_board->GetBoardPolygonOutlines( board_outline,
false ) )
3006 wxXmlNode* profileNode =
appendNode( aStepNode,
"Profile" );
3010 wxLogTrace(
traceIpc2581, wxS(
"Failed to add polygon to profile" ) );
3011 aStepNode->RemoveChild( profileNode );
3037 std::unique_ptr<FOOTPRINT> fp(
static_cast<FOOTPRINT*
>( aFp->
Clone() ) );
3038 fp->SetParentGroup(
nullptr );
3039 fp->SetPosition( { 0, 0 } );
3040 fp->SetOrientation(
ANGLE_0 );
3045 bool wasFlipped = fp->IsFlipped();
3048 if( fp->IsFlipped() )
3053 fp->GetFPID().GetLibItemName().wx_str(),
3057 addAttribute( aContentNode,
"packageRef", iter->second );
3064 wxXmlNode* packageNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"Package" );
3065 wxXmlNode* otherSideViewNode =
nullptr;
3071 if( fp->FindPadByNumber(
"1" ) )
3073 else if ( fp->FindPadByNumber(
"A1" ) )
3075 else if ( fp->FindPadByNumber(
"A" ) )
3077 else if ( fp->FindPadByNumber(
"a" ) )
3079 else if ( fp->FindPadByNumber(
"a1" ) )
3081 else if ( fp->FindPadByNumber(
"Anode" ) )
3083 else if ( fp->FindPadByNumber(
"ANODE" ) )
3090 PAD* pinOnePad = fp->FindPadByNumber(
"1" );
3093 pinOnePad = fp->FindPadByNumber(
"A1" );
3095 if( pinOnePad && fp->Pads().size() >= 2 )
3098 BOX2I fpBBox = fp->GetBoundingBox();
3108 const char* orientation =
"OTHER";
3110 if( onCenterX && onCenterY )
3111 orientation =
"CENTER";
3112 else if( onCenterX && pinPos.
y <
center.y )
3113 orientation =
"UPPER_CENTER";
3114 else if( onCenterX && pinPos.
y >
center.y )
3115 orientation =
"LOWER_CENTER";
3116 else if( onCenterY && pinPos.
x <
center.x )
3117 orientation =
"LEFT";
3118 else if( onCenterY && pinPos.
x >
center.x )
3119 orientation =
"RIGHT";
3121 orientation =
"UPPER_LEFT";
3123 orientation =
"UPPER_RIGHT";
3125 orientation =
"LOWER_LEFT";
3127 orientation =
"LOWER_RIGHT";
3129 addAttribute( packageNode,
"pinOneOrientation", orientation );
3133 addAttribute( packageNode,
"pinOneOrientation",
"OTHER" );
3134 addAttribute( packageNode,
"comment",
"Pin 1 orientation could not be determined" );
3140 : fp->GetCourtyard(
F_CrtYd );
3142 : fp->GetCourtyard(
B_CrtYd );
3159 otherSideViewNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"OtherSideView" );
3165 wxXmlNode* pickupPointNode =
appendNode( packageNode,
"PickupPoint" );
3169 std::map<PCB_LAYER_ID, std::map<bool, std::vector<BOARD_ITEM*>>> elements;
3171 for(
BOARD_ITEM* item : fp->GraphicalItems() )
3196 elements[item->GetLayer()][is_abs].push_back( item );
3199 auto add_base_node =
3202 wxXmlNode* parent = packageNode;
3211 bool is_other_side = wasFlipped ? ( aLayer ==
F_SilkS || aLayer ==
F_Fab )
3216 if( !otherSideViewNode )
3217 otherSideViewNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"OtherSideView" );
3219 parent = otherSideViewNode;
3225 nodeName =
"SilkScreen";
3226 else if( aLayer ==
F_Fab || aLayer ==
B_Fab )
3227 nodeName =
"AssemblyDrawing";
3231 wxXmlNode* new_node =
appendNode( parent, nodeName );
3235 auto add_marking_node =
3236 [&]( wxXmlNode* aNode ) -> wxXmlNode*
3238 wxXmlNode* marking_node =
appendNode( aNode,
"Marking" );
3240 return marking_node;
3243 std::map<PCB_LAYER_ID, wxXmlNode*> layer_nodes;
3244 std::map<PCB_LAYER_ID, BOX2I> layer_bbox;
3248 if( elements.find( layer ) != elements.end() )
3250 if( elements[layer][
true].size() > 0 )
3251 layer_bbox[layer] = elements[layer][
true][0]->GetBoundingBox();
3252 else if( elements[layer][
false].size() > 0 )
3253 layer_bbox[layer] = elements[layer][
false][0]->GetBoundingBox();
3257 for(
auto& [layer, map] : elements )
3259 wxXmlNode* layer_node = add_base_node( layer );
3260 wxXmlNode* marking_node = add_marking_node( layer_node );
3261 wxXmlNode* group_node =
appendNode( marking_node,
"UserSpecial" );
3262 bool update_bbox =
false;
3266 layer_nodes[layer] = layer_node;
3270 for(
auto& [is_abs, vec] : map )
3274 wxXmlNode* output_node =
nullptr;
3277 layer_bbox[layer].Merge( item->GetBoundingBox() );
3280 output_node = add_marking_node( layer_node );
3282 output_node = group_node;
3284 switch( item->Type() )
3290 if(
text->IsKnockout() )
3304 if(
text->IsBorderEnabled() )
3307 text->GetEffectiveShape()->TransformToPolygon( poly_set, 0,
ERROR_INSIDE );
3309 text->GetBorderWidth() );
3332 if( group_node->GetChildren() ==
nullptr )
3334 marking_node->RemoveChild( group_node );
3335 layer_node->RemoveChild( marking_node );
3337 delete marking_node;
3341 for(
auto&[layer, bbox] : layer_bbox )
3343 if( bbox.GetWidth() > 0 )
3345 wxXmlNode* outlineNode =
insertNode( layer_nodes[layer],
"Outline" );
3348 std::vector<VECTOR2I> points( 4 );
3349 points[0] = bbox.GetPosition();
3350 points[2] = bbox.GetEnd();
3351 points[1].x = points[0].x;
3352 points[1].y = points[2].y;
3353 points[3].x = points[2].x;
3354 points[3].y = points[0].y;
3356 outline.
Append( points );
3362 std::map<wxString, wxXmlNode*> pin_nodes;
3364 for(
size_t ii = 0; ii < fp->Pads().size(); ++ii )
3366 PAD*
pad = fp->Pads()[ii];
3368 wxXmlNode* pinNode =
nullptr;
3370 auto [ it, inserted ] = pin_nodes.emplace( pin_name,
nullptr );
3375 it->second = pinNode;
3380 genString( fp->GetReference(),
"CMP" ), pin_name );
3383 addAttribute( pinNode,
"electricalType",
"MECHANICAL" );
3384 else if(
pad->IsOnCopperLayer() )
3385 addAttribute( pinNode,
"electricalType",
"ELECTRICAL" );
3387 addAttribute( pinNode,
"electricalType",
"UNDEFINED" );
3389 if(
pad->HasHole() )
3394 if(
pad->GetFPRelativeOrientation() !=
ANGLE_0 )
3396 wxXmlNode* xformNode =
appendNode( pinNode,
"Xform" );
3397 EDA_ANGLE pad_angle =
pad->GetFPRelativeOrientation().Normalize();
3399 if( fp->IsFlipped() )
3416 if( otherSideViewNode )
3417 packageNode->AddChild( otherSideViewNode );
3425 std::vector<wxXmlNode*> componentNodes;
3426 std::vector<wxXmlNode*> packageNodes;
3427 std::set<wxString> packageNames;
3429 bool generate_unique =
m_OEMRef.empty();
3433 wxXmlNode* componentNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"Component" );
3435 wxXmlNode* pkg =
addPackage( componentNode, fp );
3438 packageNodes.push_back( pkg );
3444 if( !generate_unique )
3447 if( field && !field->
GetText().empty() )
3453 name = wxString::Format(
"%s_%s_%s", fp->GetFPID().GetFullLibraryName(),
3454 fp->GetFPID().GetLibItemName().wx_str(),
3459 Report(
_(
"Duplicate footprint pointers encountered; IPC-2581 output may be incorrect." ),
3467 else if( fp->GetAttributes() &
FP_SMD )
3472 if( fp->GetOrientation() !=
ANGLE_0 || fp->IsFlipped() )
3474 wxXmlNode* xformNode =
appendNode( componentNode,
"Xform" );
3481 if( fp->IsFlipped() )
3485 addLocationNode( componentNode, fp->GetPosition().x, fp->GetPosition().y );
3487 componentNodes.push_back( componentNode );
3496 for( wxXmlNode* pkg : packageNodes )
3497 aStepNode->AddChild( pkg );
3499 for( wxXmlNode* cmp : componentNodes )
3500 aStepNode->AddChild( cmp );
3508 wxXmlNode* netNode =
appendNode( aStepNode,
"LogicalNet" );
3510 genString(
m_board->GetNetInfo().GetNetItem( net )->GetNetname(),
"NET" ) ) ;
3512 for(
auto& [cmp,
pin] : pin_pair )
3514 wxXmlNode* netPinNode =
appendNode( netNode,
"PinRef" );
3528 std::vector<std::unique_ptr<FOOTPRINT>> footprints;
3532 std::map<PCB_LAYER_ID, std::map<int, std::vector<BOARD_ITEM*>>> elements;
3534 std::for_each(
m_board->Tracks().begin(),
m_board->Tracks().end(),
3535 [&layers, &elements](
PCB_TRACK* aTrack )
3537 if( aTrack->Type() == PCB_VIA_T )
3539 PCB_VIA* via = static_cast<PCB_VIA*>( aTrack );
3541 for( PCB_LAYER_ID layer : layers )
3543 if( via->FlashLayer( layer ) )
3544 elements[layer][via->GetNetCode()].push_back( via );
3549 elements[aTrack->GetLayer()][aTrack->GetNetCode()].push_back( aTrack );
3553 std::for_each( m_board->Zones().begin(), m_board->Zones().end(),
3554 [ &elements ](
ZONE* zone )
3556 LSEQ zone_layers = zone->GetLayerSet().Seq();
3558 for( PCB_LAYER_ID layer : zone_layers )
3559 elements[layer][zone->GetNetCode()].push_back( zone );
3562 for(
BOARD_ITEM* item : m_board->Drawings() )
3565 elements[conn_it->GetLayer()][conn_it->GetNetCode()].push_back( conn_it );
3567 elements[item->GetLayer()][0].push_back( item );
3570 for(
FOOTPRINT* fp : m_board->Footprints() )
3572 for(
PCB_FIELD* field : fp->GetFields() )
3573 elements[field->GetLayer()][0].push_back( field );
3575 for(
BOARD_ITEM* item : fp->GraphicalItems() )
3576 elements[item->GetLayer()][0].push_back( item );
3578 for(
PAD*
pad : fp->Pads() )
3580 LSEQ pad_layers =
pad->GetLayerSet().Seq();
3584 if(
pad->FlashLayer( layer ) )
3585 elements[layer][
pad->GetNetCode()].push_back(
pad );
3612 if( m_progressReporter )
3613 m_progressReporter->SetMaxProgress( nets.GetNetCount() * layers.size() );
3615 wxXmlNode* layerNode = appendNode( aStepNode,
"LayerFeature" );
3616 addAttribute( layerNode,
"layerRef", m_layer_name_map[layer] );
3618 auto process_net = [&] (
int net )
3620 std::vector<BOARD_ITEM*>& vec = elements[layer][net];
3625 std::stable_sort( vec.begin(), vec.end(),
3628 if( a->GetParentFootprint() == b->GetParentFootprint() )
3629 return a->Type() < b->Type();
3631 return a->GetParentFootprint() < b->GetParentFootprint();
3634 generateLayerSetNet( layerNode, layer, vec );
3639 if( m_progressReporter )
3641 m_progressReporter->Report( wxString::Format(
_(
"Exporting Layer %s, Net %s" ),
3642 m_board->GetLayerName( layer ),
3643 net->GetNetname() ) );
3644 m_progressReporter->AdvanceProgress();
3647 process_net( net->GetNetCode() );
3650 if( layerNode->GetChildren() ==
nullptr )
3652 aStepNode->RemoveChild( layerNode );
3653 deleteNode( layerNode );
3665 wxXmlNode* layerNode =
appendNode( aLayerNode,
"LayerFeature" );
3666 layerNode->AddAttribute(
"layerRef",
genLayersString( layers.first, layers.second,
"DRILL" ) );
3677 Report(
_(
"Via uses unsupported padstack; omitted from drill data." ),
3682 wxXmlNode* padNode =
appendNode( layerNode,
"Set" );
3685 if(
via->GetNetCode() > 0 )
3688 wxXmlNode* holeNode =
appendNode( padNode,
"Hole" );
3689 addAttribute( holeNode,
"name", wxString::Format(
"H%d", hole_count++ ) );
3694 addXY( holeNode,
via->GetPosition() );
3704 Report(
_(
"Pad uses unsupported padstack; hole was omitted from drill data." ),
3709 wxXmlNode* padNode =
appendNode( layerNode,
"Set" );
3712 if(
pad->GetNetCode() > 0 )
3715 wxXmlNode* holeNode =
appendNode( padNode,
"Hole" );
3716 addAttribute( holeNode,
"name", wxString::Format(
"H%d", hole_count++ ) );
3722 addXY( holeNode,
pad->GetPosition() );
3732 wxXmlNode* layerNode =
appendNode( aLayerNode,
"LayerFeature" );
3733 layerNode->AddAttribute(
"layerRef",
genLayersString( layers.first, layers.second,
"SLOT" ) );
3737 wxXmlNode* padNode =
appendNode( layerNode,
"Set" );
3739 if(
pad->GetNetCode() > 0 )
3742 addSlotCavity( padNode, *
pad, wxString::Format(
"SLOT%d", hole_count++ ) );
3749 std::vector<BOARD_ITEM*>& aItems )
3751 auto it = aItems.begin();
3752 wxXmlNode* layerSetNode =
appendNode( aLayerNode,
"Set" );
3753 wxXmlNode* featureSetNode =
appendNode( layerSetNode,
"Features" );
3754 wxXmlNode* specialNode =
appendNode( featureSetNode,
"UserSpecial" );
3756 bool has_via =
false;
3757 bool has_pad =
false;
3759 wxXmlNode* padSetNode =
nullptr;
3761 wxXmlNode* viaSetNode =
nullptr;
3763 wxXmlNode* teardropLayerSetNode =
nullptr;
3764 wxXmlNode* teardropFeatureSetNode =
nullptr;
3766 bool teardrop_warning =
false;
3771 if( item->GetNetCode() > 0 )
3781 shape.
SetStart( track->GetStart() );
3782 shape.
SetEnd( track->GetEnd() );
3783 shape.
SetWidth( track->GetWidth() );
3800 viaSetNode = layerSetNode;
3805 viaSetNode =
appendNode( layerSetNode,
"Set" );
3807 if( track->GetNetCode() > 0 )
3814 addVia( viaSetNode,
static_cast<PCB_VIA*
>( track ), aLayer );
3821 wxXmlNode* zoneFeatureNode = specialNode;
3823 if( zone->IsTeardropArea() )
3827 if( !teardropFeatureSetNode )
3829 teardropLayerSetNode =
appendNode( aLayerNode,
"Set" );
3830 addAttribute( teardropLayerSetNode,
"geometryUsage",
"TEARDROP" );
3832 if( zone->GetNetCode() > 0 )
3835 genString( zone->GetNetname(),
"NET" ) );
3838 wxXmlNode* new_teardrops =
appendNode( teardropLayerSetNode,
"Features" );
3840 teardropFeatureSetNode =
appendNode( new_teardrops,
"UserSpecial" );
3843 zoneFeatureNode = teardropFeatureSetNode;
3845 else if( !teardrop_warning )
3847 Report(
_(
"Teardrops are not supported in IPC-2581 revision B; they were exported as zones." ),
3849 teardrop_warning =
true;
3856 wxXmlNode* tempSetNode =
appendNode( aLayerNode,
"Set" );
3859 wxXmlNode* newFeatures =
appendNode( tempSetNode,
"Features" );
3861 zoneFeatureNode =
appendNode( newFeatures,
"UserSpecial" );
3865 SHAPE_POLY_SET& zone_shape = *zone->GetFilledPolysList( aLayer );
3867 for(
int ii = 0; ii < zone_shape.
OutlineCount(); ++ii )
3878 wxXmlNode* tempSetNode =
appendNode( aLayerNode,
"Set" );
3881 addAttribute( tempSetNode,
"geometryUsage",
"GRAPHIC" );
3883 bool link_to_component =
true;
3886 link_to_component =
false;
3888 if( link_to_component )
3891 wxXmlNode* tempFeature =
appendNode( tempSetNode,
"Features" );
3900 wxXmlNode* tempSetNode =
appendNode( aLayerNode,
"Set" );
3902 if( shape->GetNetCode() > 0 )
3905 wxXmlNode* tempFeature =
appendNode( tempSetNode,
"Features" );
3922 text_item =
static_cast<EDA_TEXT*
>( pcb_text );
3924 text_item =
static_cast<EDA_TEXT*
>( pcb_textbox );
3929 wxXmlNode* tempSetNode =
appendNode( aLayerNode,
"Set" );
3934 bool link_to_component = fp !=
nullptr;
3937 link_to_component =
false;
3939 if( link_to_component )
3942 wxXmlNode* nonStandardAttributeNode =
appendNode( tempSetNode,
"NonstandardAttribute" );
3943 addAttribute( nonStandardAttributeNode,
"name",
"TEXT" );
3945 addAttribute( nonStandardAttributeNode,
"type",
"STRING" );
3947 wxXmlNode* tempFeature =
appendNode( tempSetNode,
"Features" );
3953 addText( tempFeature, text_item,
text->GetFontMetrics() );
3971 padSetNode = layerSetNode;
3976 padSetNode =
appendNode( aLayerNode,
"Set" );
3978 if(
pad->GetNetCode() > 0 )
3993 switch( item->Type() )
3998 add_track(
static_cast<PCB_TRACK*
>( item ) );
4006 add_pad(
static_cast<PAD*
>( item ) );
4010 add_shape(
static_cast<PCB_SHAPE*
>( item ) );
4035 if( specialNode->GetChildren() ==
nullptr )
4037 featureSetNode->RemoveChild( specialNode );
4041 if( featureSetNode->GetChildren() ==
nullptr )
4043 layerSetNode->RemoveChild( featureSetNode );
4047 if( layerSetNode->GetChildren() ==
nullptr )
4049 aLayerNode->RemoveChild( layerSetNode );
4058 bool add_node =
true;
4064 switch( std::get<0>(layers) )
4093 wxXmlNode* layerNode =
appendNode( aStepNode,
"LayerFeature" );
4097 layerNode->AddAttribute(
"layerRef",
genLayersString( std::get<1>( layers ),
4111 shape.
SetEnd( {
KiROUND(
via->GetWidth( std::get<1>( layers ) ) / 2.0 ), 0 } );
4113 wxXmlNode* padNode =
appendNode( layerNode,
"Pad" );
4144 std::set<wxString> unique_parts;
4145 std::map<wxString,wxString> unique_vendors;
4149 auto [ it, success ] = unique_parts.insert(
name );
4154 wxXmlNode* part =
appendNode( avl,
"AvlItem" );
4161 for (
int ii = 0; ii < 2; ++ii )
4167 if( mpn_name.empty() )
4170 wxXmlNode* vmpn =
appendNode( part,
"AvlVmpn" );
4174 wxXmlNode* mpn =
appendNode( vmpn,
"AvlMpn" );
4177 wxXmlNode* vendor =
appendNode( vmpn,
"AvlVendor" );
4179 wxString vendor_name = wxT(
"UNKNOWN" );
4182 if( !ii && company[ii] )
4190 else if( !ii && !company_name[ii].
empty() )
4192 vendor_name = company_name[ii];
4194 else if( ii && !
m_dist.empty() )
4199 auto [vendor_id, inserted] = unique_vendors.emplace(
4201 wxString::Format(
"VENDOR_%zu", unique_vendors.size() ) );
4203 addAttribute( vendor,
"enterpriseRef", vendor_id->second );
4207 wxXmlNode* new_vendor =
new wxXmlNode( wxXML_ELEMENT_NODE,
"Enterprise" );
4223 const std::map<std::string, UTF8>* aProperties )
4267 if(
auto it = aProperties->find(
"units" ); it != aProperties->end() )
4269 if( it->second ==
"inch" )
4276 if(
auto it = aProperties->find(
"sigfig" ); it != aProperties->end() )
4277 m_sigfig = std::stoi( it->second );
4279 if(
auto it = aProperties->find(
"version" ); it != aProperties->end() )
4282 if(
auto it = aProperties->find(
"OEMRef" ); it != aProperties->end() )
4285 if(
auto it = aProperties->find(
"mpn" ); it != aProperties->end() )
4286 m_mpn = it->second.wx_str();
4288 if(
auto it = aProperties->find(
"mfg" ); it != aProperties->end() )
4289 m_mfg = it->second.wx_str();
4291 if(
auto it = aProperties->find(
"dist" ); it != aProperties->end() )
4292 m_dist = it->second.wx_str();
4294 if(
auto it = aProperties->find(
"distpn" ); it != aProperties->end() )
4297 if(
auto it = aProperties->find(
"bomrev" ); it != aProperties->end() )
4302 for(
char c =
'a'; c <=
'z'; ++c )
4305 for(
char c =
'A'; c <=
'Z'; ++c )
4308 for(
char c =
'0'; c <=
'9'; ++c )
4312 std::string specialChars =
"_\\-.+><";
4314 for(
char c : specialChars )
4341 wxXmlNode* insertBefore =
nullptr;
4343 for( wxXmlNode* child =
m_contentNode->GetChildren(); child; child = child->GetNext() )
4345 if( child->GetName().StartsWith(
"Dictionary" ) )
4347 insertBefore = child;
4353 [&](
const wxString& aNodeName, wxXmlNode* aSection )
4358 wxXmlNode* ref =
new wxXmlNode( wxXML_ELEMENT_NODE, aNodeName );
4359 ref->AddAttribute(
"name", aSection->GetAttribute(
"name" ) );
4367 insertRef(
"BomRef", bom_node );
4368 insertRef(
"AvlRef", avl_node );
4377 double written_bytes = 0.0;
4378 double last_yield = 0.0;
4385 auto update_progress = [&](
size_t aBytes )
4387 written_bytes += aBytes;
4388 double percent = written_bytes /
static_cast<double>(
m_total_bytes );
4393 if( last_yield + 0.01 < percent )
4395 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.
void SetStart(const VECTOR2I &aStart)
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
std::vector< VECTOR2I > GetRectCorners() const
EDA_ANGLE GetEllipseStartAngle() const
void SetEnd(const VECTOR2I &aEnd)
void SetArcGeometry(const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd)
Set the three controlling points for an arc.
const VECTOR2I & GetBezierC1() const
int GetRectangleHeight() const
bool IsClockwiseArc() const
void SetWidth(int aWidth)
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
const 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.
LSET is a set of PCB_LAYER_IDs.
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
bool Contains(PCB_LAYER_ID aLayer) const
See if the layer set contains a PCB layer.
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.
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
const VECTOR2I & GetDrillSize() const
PAD_ATTRIB GetAttribute() const
const wxString & GetNumber() const
const VECTOR2I & GetDelta(PCB_LAYER_ID aLayer) const
VECTOR2I GetPosition() const override
int GetDrillSizeX() const
PAD_SHAPE GetShape(PCB_LAYER_ID aLayer) const
int GetSolderMaskExpansion(PCB_LAYER_ID aLayer) const
const PADSTACK & Padstack() const
const VECTOR2I & GetOffset(PCB_LAYER_ID aLayer) 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 & GetSize(PCB_LAYER_ID aLayer) const
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.
STROKE_PARAMS GetStroke() const 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
@ 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)
PCB_LAYER_ID FlipLayer(PCB_LAYER_ID aLayerId, int aCopperLayersCount)
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)
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