55#include <wx/numformatter.h>
56#include <wx/xml/xml.h>
77 static_cast<int>( aDrill.end ), aDrill.size.x, aDrill.size.y,
78 static_cast<int>( aDrill.shape ), aDrill.is_capped.has_value(),
79 aDrill.is_capped.value_or(
false ), aDrill.is_filled.has_value(),
80 aDrill.is_filled.value_or(
false ) );
88 aPost.size, aPost.depth, aPost.angle );
181 std::vector<FOOTPRINT*> retval;
184 retval.push_back(
static_cast<FOOTPRINT*
>( fp->Clone() ) );
194 if( aParent->GetChildren() )
195 aNode->SetNext( aParent->GetChildren() );
197 aNode->SetNext(
nullptr );
199 aParent->SetChildren( aNode );
200 aNode->SetParent( aParent );
209 aNode->SetNext( aPrev->GetNext() );
210 aPrev->SetNext( aNode );
211 aNode->SetParent( aPrev->GetParent() );
232 check = check->GetParent();
245 wxXmlNode* node =
new wxXmlNode( wxXML_ELEMENT_NODE, aName );
260 aNode->SetParent( aParent );
265 aParent->AddChild( aNode );
277 wxXmlNode* node =
new wxXmlNode( wxXML_ELEMENT_NODE, aName );
291 str.Replace( wxT(
":" ), wxT(
"_" ) );
295 for( wxString::const_iterator iter = aStr.begin(); iter != aStr.end(); ++iter )
312 wxString key = aPrefix ? wxString( aPrefix ) + wxT(
":" ) + aStr : aStr;
322 wxString
name = base;
326 name = wxString::Format(
"%s_%d", base, suffix++ );
342 const char* aPrefix )
const
344 return genString( wxString::Format( wxS(
"%s_%s" ),
346 m_board->GetLayerName( aBottom ) ), aPrefix );
357 if(
name.empty() && fp )
361 if( fp->
Pads()[ii] == aPad )
369 name = wxString::Format(
"NPTH%zu", ii );
370 else if(
name.empty() )
371 name = wxString::Format(
"PAD%zu", ii );
382 [&](
const wxString& aName )
405 wxString baseName =
genString( ref,
"CMP" );
406 wxString
name = baseName;
409 while( !tryInsert(
name ) )
410 name = wxString::Format(
"%s_%d", baseName, suffix++ );
420 wxString str = wxString::FromCDouble( aVal, aSigFig == -1 ?
m_sigfig : aSigFig );
423 while( str.EndsWith( wxT(
"00" ) ) )
427 if( str == wxT(
"-0.0" ) )
452 aNode->AddAttribute( aName, aValue );
458 wxXmlNode* xmlHeaderNode =
new wxXmlNode(wxXML_ELEMENT_NODE,
"IPC-2581");
460 addAttribute( xmlHeaderNode,
"xmlns",
"http://webstds.ipc.org/2581");
461 addAttribute( xmlHeaderNode,
"xmlns:xsi",
"http://www.w3.org/2001/XMLSchema-instance");
462 addAttribute( xmlHeaderNode,
"xmlns:xsd",
"http://www.w3.org/2001/XMLSchema");
467 "http://webstds.ipc.org/2581 http://webstds.ipc.org/2581/IPC-2581B1.xsd" );
472 "http://webstds.ipc.org/2581 http://webstds.ipc.org/2581/IPC-2581C.xsd" );
477 return xmlHeaderNode;
490 wxXmlNode* node =
appendNode( contentNode,
"FunctionMode" );
498 wxFileName fn(
m_board->GetFileName() );
505 contentNode->AddChild( color_node );
509 wxXmlNode* fillNode =
appendNode( contentNode,
"DictionaryFillDesc" );
529 contentNode->AddChild( color_node );
538 wxXmlNode* location_node =
appendNode( aNode,
"Location" );
613 wxXmlNode* color_node =
new wxXmlNode( wxXML_ELEMENT_NODE,
"DictionaryColor" );
617 wxString layer_name = item->GetLayerName();
618 int sub_layer_count = 1;
620 if( layer_name.empty() )
621 layer_name =
m_board->GetLayerName( item->GetBrdLayerId() );
623 layer_name =
genString( layer_name,
"LAYER" );
627 layer_name =
genString( wxString::Format(
"DIELECTRIC_%d", item->GetDielectricLayerId() ),
629 sub_layer_count = item->GetSublayersCount();
636 for(
int sub_idx = 0; sub_idx < sub_layer_count; sub_idx++ )
638 wxString sub_layer_name = layer_name;
641 sub_layer_name += wxString::Format(
"_%d", sub_idx );
643 wxXmlNode* node =
appendNode( aContentNode,
"LayerRef" );
649 wxXmlNode* entry_color =
appendNode( color_node,
"EntryColor" );
651 wxXmlNode* color =
appendNode( entry_color,
"Color" );
653 wxString colorName = item->GetColor( sub_idx );
655 if( colorName.StartsWith( wxT(
"#" ) ) )
658 COLOR4D layer_color( colorName );
670 if( fab_color.GetName() == colorName )
672 addAttribute( color,
"r", wxString::Format(
"%d",
KiROUND( fab_color.GetColor( item->GetType() ).r * 255 ) ) );
673 addAttribute( color,
"g", wxString::Format(
"%d",
KiROUND( fab_color.GetColor( item->GetType() ).g * 255 ) ) );
674 addAttribute( color,
"b", wxString::Format(
"%d",
KiROUND( fab_color.GetColor( item->GetType() ).b * 255 ) ) );
694 wxXmlNode* fillDesc_node =
appendNode( aNode,
"FillDesc" );
700 wxXmlNode* fillDesc_node =
appendNode( aNode,
"FillDesc" );
701 addAttribute( fillDesc_node,
"fillProperty",
"HOLLOW" );
708 wxCHECK_RET( aNode,
"aNode is null" );
713 wxXmlNode* entry_node =
nullptr;
717 size_t hash =
lineHash( aWidth, aDashType );
718 wxString
name = wxString::Format(
"LINE_%zu",
m_line_dict.size() + 1 );
722 wxXmlNode* lineDesc_node =
appendNode( aNode,
"LineDescRef" );
737 wxXmlNode* line_node =
appendNode( entry_node,
"LineDesc" );
770 if( outlineCount == 0 )
777 if( outlineCount == 1 )
783 wxXmlNode* special_node =
appendNode( aContentNode,
"UserSpecial" );
785 for(
int ii = 0; ii < outlineCount; ++ii )
801 wxXmlNode* text_node =
appendNode( aContentNode,
"UserSpecial" );
803 std::list<VECTOR2I> pts;
811 wxXmlNode* line_node =
nullptr;
818 addXY( line_node, pts.front(),
"startX",
"startY" );
819 addXY( line_node, pts.back(),
"endX",
"endY" );
823 line_node =
appendNode( text_node,
"Polyline" );
824 wxXmlNode* point_node =
appendNode( line_node,
"PolyBegin" );
825 addXY( point_node, pts.front() );
827 auto iter = pts.begin();
829 for( ++iter; iter != pts.end(); ++iter )
831 wxXmlNode* step_node =
appendNode( line_node,
"PolyStepSegment" );
832 addXY( step_node, *iter );
847 if( aPt1 == pts.back() )
848 pts.push_back( aPt2 );
849 else if( aPt2 == pts.front() )
850 pts.push_front( aPt1 );
851 else if( aPt1 == pts.front() )
852 pts.push_front( aPt2 );
853 else if( aPt2 == pts.back() )
854 pts.push_back( aPt1 );
858 pts.push_back( aPt1 );
859 pts.push_back( aPt2 );
864 pts.push_back( aPt1 );
865 pts.push_back( aPt2 );
871 if( aPoly.PointCount() < 3 )
874 wxXmlNode* outline_node =
appendNode( text_node,
"Outline" );
875 wxXmlNode* poly_node =
appendNode( outline_node,
"Polygon" );
878 const std::vector<VECTOR2I>& polyPts = aPoly.CPoints();
879 wxXmlNode* point_node =
appendNode( poly_node,
"PolyBegin" );
880 addXY( point_node, polyPts.front() );
882 for(
size_t ii = 1; ii < polyPts.size(); ++ii )
884 wxXmlNode* poly_step_node =
886 addXY( poly_step_node, polyPts[ii] );
889 point_node =
appendNode( poly_node,
"PolyStepSegment" );
890 addXY( point_node, polyPts.front() );
901 if( text_node->GetChildren() ==
nullptr )
903 aContentNode->RemoveChild( text_node );
916 wxXmlNode* shape_node =
appendNode( aContentNode,
"StandardPrimitiveRef" );
921 int maxError =
m_board->GetDesignSettings().m_MaxError;
941 wxXmlNode* circle_node =
appendNode( entry_node,
"Circle" );
942 circle_node->AddAttribute(
"diameter",
955 wxXmlNode* rect_node =
appendNode( entry_node,
"RectCenter" );
971 wxXmlNode* oval_node =
appendNode( entry_node,
"Oval" );
987 wxXmlNode* roundrect_node =
appendNode( entry_node,
"RectRound" );
991 roundrect_node->AddAttribute(
"radius",
1009 wxXmlNode* chamfered_node =
appendNode( entry_node,
"RectCham" );
1014 int shorterSide = std::min( pad_size.
x, pad_size.
y );
1045 int dx = pad_size.
x / 2;
1046 int dy = pad_size.
y / 2;
1047 int ddx = trap_delta.
x / 2;
1048 int ddy = trap_delta.
y / 2;
1050 outline.
Append( -dx - ddy, dy + ddx );
1051 outline.
Append( dx + ddy, dy - ddx );
1052 outline.
Append( dx - ddy, -dy + ddx );
1053 outline.
Append( -dx + ddy, -dy - ddx );
1078 if( expansion !=
VECTOR2I( 0, 0 ) )
1095 wxXmlNode* shape_node =
appendNode( aContentNode,
"StandardPrimitiveRef" );
1110 wxXmlNode* shape_node =
appendNode( aContentNode,
"UserPrimitiveRef" );
1127 wxXmlNode* polyline_node =
appendNode( aContentNode,
"Polyline" );
1135 wxXmlNode* begin_node =
appendNode( polyline_node,
"PolyBegin" );
1136 addXY( begin_node, start );
1139 wxXmlNode* arc1_node =
appendNode( polyline_node,
"PolyStepCurve" );
1140 addXY( arc1_node, mid );
1145 wxXmlNode* arc2_node =
appendNode( polyline_node,
"PolyStepCurve" );
1146 addXY( arc2_node, start );
1158 int diameter = aShape.
GetRadius() * 2.0;
1165 wxXmlNode* special_node =
appendNode( entry_node,
"UserSpecial" );
1167 wxXmlNode* circle_node =
appendNode( special_node,
"Circle" );
1193 wxXmlNode* polyline_node =
appendNode( aContentNode,
"Polyline" );
1198 wxXmlNode* begin_node =
appendNode( polyline_node,
"PolyBegin" );
1199 addXY( begin_node, corners[0] );
1201 for(
size_t i = 1; i < corners.size(); ++i )
1203 wxXmlNode* step_node =
appendNode( polyline_node,
"PolyStepSegment" );
1204 addXY( step_node, corners[i] );
1208 wxXmlNode* close_node =
appendNode( polyline_node,
"PolyStepSegment" );
1209 addXY( close_node, corners[0] );
1211 if( stroke_width > 0 )
1212 addLineDesc( polyline_node, stroke_width, dash,
true );
1222 wxXmlNode* special_node =
appendNode( entry_node,
"UserSpecial" );
1228 wxXmlNode* rect_node =
appendNode( special_node,
"RectRound" );
1245 width += stroke_width;
1246 height += stroke_width;
1274 wxXmlNode* polyline_node =
appendNode( aContentNode,
"Polyline" );
1275 const std::vector<VECTOR2I>& pts = outline.
CPoints();
1277 wxXmlNode* begin_node =
appendNode( polyline_node,
"PolyBegin" );
1278 addXY( begin_node, pts[0] );
1280 for(
size_t jj = 1; jj < pts.size(); ++jj )
1282 wxXmlNode* step_node =
appendNode( polyline_node,
"PolyStepSegment" );
1283 addXY( step_node, pts[jj] );
1287 if( pts.size() > 2 && pts.front() != pts.back() )
1289 wxXmlNode* close_node =
appendNode( polyline_node,
"PolyStepSegment" );
1290 addXY( close_node, pts[0] );
1293 if( stroke_width > 0 )
1294 addLineDesc( polyline_node, stroke_width, dash,
true );
1308 wxXmlNode* special_node =
appendNode( entry_node,
"UserSpecial" );
1330 wxXmlNode* arc_node =
appendNode( aContentNode,
"Arc" );
1332 addXY( arc_node, aShape.
GetEnd(),
"endX",
"endY" );
1349 wxXmlNode* polyline_node =
appendNode( aContentNode,
"Polyline" );
1353 std::vector<VECTOR2I> points;
1356 wxXmlNode* point_node =
appendNode( polyline_node,
"PolyBegin" );
1357 addXY( point_node, points[0] );
1359 for(
size_t i = 1; i < points.size(); i++ )
1361 wxXmlNode* seg_node =
appendNode( polyline_node,
"PolyStepSegment" );
1362 addXY( seg_node, points[i] );
1376 wxXmlNode* line_node =
appendNode( aContentNode,
"Line" );
1378 addXY( line_node, aShape.
GetEnd(),
"endX",
"endY" );
1394 if( !aInline && !
name.empty() )
1396 wxXmlNode* shape_node =
appendNode( aContentNode,
"UserPrimitiveRef" );
1405 wxXmlNode* slotNode =
appendNode( aNode,
"SlotCavity" );
1425 if( drill_size.
y > drill_size.
x )
1427 std::swap( drill_size.
x, drill_size.
y );
1428 rotation = ( rotation +
ANGLE_90 ).Normalize();
1434 wxXmlNode* xformNode =
appendNode( slotNode,
"Xform" );
1439 wxXmlNode* ovalNode =
appendNode( slotNode,
"Oval" );
1447 int maxError =
m_board->GetDesignSettings().m_MaxError;
1459 wxXmlNode* roleNode =
appendNode( logisticNode,
"Role" );
1467 wxXmlNode* personNode =
appendNode( logisticNode,
"Person" );
1469 addAttribute( personNode,
"enterpriseRef",
"UNKNOWN" );
1472 return logisticNode;
1483 addAttribute( historyNode,
"origination", wxDateTime::Now().FormatISOCombined() );
1485 addAttribute( historyNode,
"lastChange", wxDateTime::Now().FormatISOCombined() );
1487 wxXmlNode* fileRevisionNode =
appendNode( historyNode,
"FileRevision" );
1488 addAttribute( fileRevisionNode,
"fileRevisionId",
"1" );
1489 addAttribute( fileRevisionNode,
"comment",
"NO COMMENT" );
1492 wxXmlNode* softwarePackageNode =
appendNode( fileRevisionNode,
"SoftwarePackage" );
1495 addAttribute( softwarePackageNode,
"vendor",
"KiCad EDA" );
1497 wxXmlNode* certificationNode =
appendNode( softwarePackageNode,
"Certification" );
1498 addAttribute( certificationNode,
"certificationStatus",
"SELFTEST" );
1521 m_refdes =
new std::vector<REFDES>();
1522 m_props =
new std::map<wxString, wxString>();
1533 wxString m_OEMDesignRef;
1537 wxString m_description;
1539 std::vector<REFDES>* m_refdes;
1540 std::map<wxString, wxString>*
m_props;
1543 std::set<std::unique_ptr<struct BOM_ENTRY>,
1544 std::function<bool(
const std::unique_ptr<struct BOM_ENTRY>&,
1545 const std::unique_ptr<struct BOM_ENTRY>& )>> bom_entries(
1546 [](
const std::unique_ptr<struct BOM_ENTRY>& a,
1547 const std::unique_ptr<struct BOM_ENTRY>& b )
1549 return a->m_OEMDesignRef < b->m_OEMDesignRef;
1554 std::unique_ptr<FOOTPRINT> fp(
static_cast<FOOTPRINT*
>( fp_it->Clone() ) );
1555 fp->SetParentGroup(
nullptr );
1556 fp->SetPosition( {0, 0} );
1557 fp->SetOrientation(
ANGLE_0 );
1560 if( fp->IsFlipped() )
1568 Report( wxString::Format(
_(
"Footprint %s not found in dictionary; BOM data may be incomplete." ),
1569 fp->GetFPID().GetLibItemName().wx_str() ),
1574 auto entry = std::make_unique<struct BOM_ENTRY>();
1580 entry->m_OEMDesignRef = it->second;
1584 Report( wxString::Format(
_(
"Component \"%s\" missing OEM reference; BOM entry will be skipped." ),
1585 fp->GetFPID().GetLibItemName().wx_str() ),
1589 entry->m_OEMDesignRef =
genString( entry->m_OEMDesignRef,
"REF" );
1591 entry->m_pads = fp->GetPadCount();
1595 const wxString variantName =
m_board ?
m_board->GetCurrentVariant() : wxString();
1597 if( entry->m_pads == 0 || fp_it->GetExcludedFromBOMForVariant( variantName ) )
1598 entry->m_type =
"DOCUMENT";
1600 entry->m_type =
"ELECTRICAL";
1605 if( descField && !descField->
GetShownText(
false ).IsEmpty() )
1606 entry->m_description = descField->
GetShownText(
false );
1608 auto[ bom_iter, inserted ] = bom_entries.insert( std::move( entry ) );
1611 ( *bom_iter )->m_count++;
1615 refdes.m_pkg = fp->GetFPID().GetLibItemName().wx_str();
1616 refdes.m_populate = !fp->GetDNPForVariant( variantName )
1617 && !fp->GetExcludedFromBOMForVariant( variantName );
1620 ( *bom_iter )->m_refdes->push_back( refdes );
1624 for(
PCB_FIELD* prop : fp->GetFields() )
1629 if( prop->IsMandatory() && !prop->IsValue() )
1632 ( *bom_iter )->m_props->emplace( prop->GetName(), prop->GetShownText(
false ) );
1636 if( bom_entries.empty() )
1639 wxFileName fn(
m_board->GetFileName() );
1641 wxXmlNode* bomNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"Bom" );
1642 m_xml_root->InsertChild( bomNode, aEcadNode );
1645 wxXmlNode* bomHeaderNode =
appendNode( bomNode,
"BomHeader" );
1648 if( bomRevision.IsEmpty() )
1649 bomRevision =
m_board->GetTitleBlock().GetRevision();
1651 if( bomRevision.IsEmpty() )
1652 bomRevision = wxS(
"1.0" );
1654 addAttribute( bomHeaderNode,
"revision", bomRevision );
1657 wxXmlNode* stepRefNode =
appendNode( bomHeaderNode,
"StepRef" );
1660 for(
const auto& entry : bom_entries )
1662 wxXmlNode* bomEntryNode =
appendNode( bomNode,
"BomItem" );
1663 addAttribute( bomEntryNode,
"OEMDesignNumberRef", entry->m_OEMDesignRef );
1664 addAttribute( bomEntryNode,
"quantity", wxString::Format(
"%d", entry->m_count ) );
1665 addAttribute( bomEntryNode,
"pinCount", wxString::Format(
"%d", entry->m_pads ) );
1666 addAttribute( bomEntryNode,
"category", entry->m_type );
1668 if( !entry->m_description.IsEmpty() )
1669 addAttribute( bomEntryNode,
"description", entry->m_description );
1671 for(
const REFDES& refdes : *( entry->m_refdes ) )
1673 wxXmlNode* refdesNode =
appendNode( bomEntryNode,
"RefDes" );
1676 addAttribute( refdesNode,
"populate", refdes.m_populate ?
"true" :
"false" );
1677 addAttribute( refdesNode,
"layerRef", refdes.m_layer );
1680 wxXmlNode* characteristicsNode =
appendNode( bomEntryNode,
"Characteristics" );
1681 addAttribute( characteristicsNode,
"category", entry->m_type );
1683 for(
const auto& prop : *( entry->m_props ) )
1685 wxXmlNode* textualDefNode =
appendNode( characteristicsNode,
"Textual" );
1686 addAttribute( textualDefNode,
"definitionSource",
"KICAD" );
1687 addAttribute( textualDefNode,
"textualCharacteristicName", prop.first );
1688 addAttribute( textualDefNode,
"textualCharacteristicValue", prop.second );
1706 wxXmlNode* cadDataNode =
appendNode( ecadNode,
"CadData" );
1725 std::vector<BOARD_STACKUP_ITEM*> layers = stackup.
GetList();
1726 std::set<PCB_LAYER_ID> added_layers;
1728 for(
int i = 0; i < stackup.
GetCount(); i++ )
1732 for(
int sublayer_id = 0; sublayer_id < stackup_item->
GetSublayersCount(); sublayer_id++ )
1736 if( ly_name.IsEmpty() )
1745 if( sublayer_id > 0 )
1746 ly_name += wxString::Format(
"_%d", sublayer_id );
1750 ly_name =
genString( ly_name,
"SPEC_LAYER" );
1752 wxXmlNode* specNode =
appendNode( aCadLayerNode,
"Spec" );
1754 wxXmlNode* generalNode =
appendNode( specNode,
"General" );
1756 wxXmlNode* propertyNode =
appendNode( generalNode,
"Property" );
1758 switch ( stackup_item->
GetType() )
1763 wxXmlNode* conductorNode =
appendNode( specNode,
"Conductor" );
1765 propertyNode =
appendNode( conductorNode,
"Property" );
1766 addAttribute( propertyNode,
"unit", wxT(
"SIEMENS/M" ) );
1767 addAttribute( propertyNode,
"value", wxT(
"5.959E7" ) );
1773 propertyNode =
appendNode( generalNode,
"Property" );
1774 addAttribute( propertyNode,
"text", wxString::Format(
"Type : %s",
1776 wxXmlNode* dielectricNode =
appendNode( specNode,
"Dielectric" );
1777 addAttribute( dielectricNode,
"type",
"DIELECTRIC_CONSTANT" );
1778 propertyNode =
appendNode( dielectricNode,
"Property" );
1781 dielectricNode =
appendNode( specNode,
"Dielectric" );
1782 addAttribute( dielectricNode,
"type",
"LOSS_TANGENT" );
1783 propertyNode =
appendNode( dielectricNode,
"Property" );
1790 propertyNode =
appendNode( generalNode,
"Property" );
1791 addAttribute( propertyNode,
"text", wxString::Format(
"Color : %s",
1793 propertyNode =
appendNode( generalNode,
"Property" );
1794 addAttribute( propertyNode,
"text", wxString::Format(
"Type : %s",
1800 propertyNode =
appendNode( generalNode,
"Property" );
1801 addAttribute( propertyNode,
"text", wxString::Format(
"Color : %s",
1803 propertyNode =
appendNode( generalNode,
"Property" );
1804 addAttribute( propertyNode,
"text", wxString::Format(
"Type : %s",
1808 if( stackup_item->
GetEpsilonR( sublayer_id ) > 1.0 )
1810 wxXmlNode* dielectricNode =
appendNode( specNode,
"Dielectric" );
1811 addAttribute( dielectricNode,
"type",
"DIELECTRIC_CONSTANT" );
1812 propertyNode =
appendNode( dielectricNode,
"Property" );
1819 wxXmlNode* dielectricNode =
appendNode( specNode,
"Dielectric" );
1820 addAttribute( dielectricNode,
"type",
"LOSS_TANGENT" );
1821 propertyNode =
appendNode( dielectricNode,
"Property" );
1839 wxXmlNode* specNode =
appendNode( aCadLayerNode,
"Spec" );
1842 wxXmlNode* surfaceFinishNode =
appendNode( specNode,
"SurfaceFinish" );
1854 wxXmlNode* cadHeaderNode =
appendNode( aEcadNode,
"CadHeader" );
1898 addAttribute( aNode,
"layerFunction",
"BOARD_OUTLINE" );
1939 aLayer ==
F_Cu ?
"TOP"
1940 : aLayer ==
B_Cu ?
"BOTTOM"
1959 wxXmlNode* stackupNode =
appendNode( aCadLayerNode,
"Stackup" );
1960 addAttribute( stackupNode,
"name",
"Primary_Stackup" );
1967 addAttribute( stackupNode,
"stackupStatus",
"PROPOSED" );
1969 wxXmlNode* stackupGroup =
appendNode( stackupNode,
"StackupGroup" );
1970 addAttribute( stackupGroup,
"name",
"Primary_Stackup_Group" );
1975 std::vector<BOARD_STACKUP_ITEM*> layers = stackup.
GetList();
1976 std::set<PCB_LAYER_ID> added_layers;
1979 for(
int i = 0; i < stackup.
GetCount(); i++ )
1983 for(
int sublayer_id = 0; sublayer_id < stackup_item->
GetSublayersCount(); sublayer_id++ )
1988 if( hasCoating && layer_id ==
F_Cu && sublayer_id == 0 )
1990 wxXmlNode* coatingLayer =
appendNode( stackupGroup,
"StackupLayer" );
1991 addAttribute( coatingLayer,
"layerOrGroupRef",
"COATING_TOP" );
1995 addAttribute( coatingLayer,
"sequence", wxString::Format(
"%d", sequence++ ) );
1997 wxXmlNode* specRefNode =
appendNode( coatingLayer,
"SpecRef" );
2001 wxXmlNode* stackupLayer =
appendNode( stackupGroup,
"StackupLayer" );
2004 if( ly_name.IsEmpty() )
2013 if( sublayer_id > 0 )
2014 ly_name += wxString::Format(
"_%d", sublayer_id );
2018 wxString spec_name =
genString( ly_name,
"SPEC_LAYER" );
2019 ly_name =
genString( ly_name,
"LAYER" );
2021 addAttribute( stackupLayer,
"layerOrGroupRef", ly_name );
2025 addAttribute( stackupLayer,
"sequence", wxString::Format(
"%d", sequence++ ) );
2027 wxXmlNode* specLayerNode =
appendNode( stackupLayer,
"SpecRef" );
2033 wxXmlNode* coatingLayer =
appendNode( stackupGroup,
"StackupLayer" );
2034 addAttribute( coatingLayer,
"layerOrGroupRef",
"COATING_BOTTOM" );
2038 addAttribute( coatingLayer,
"sequence", wxString::Format(
"%d", sequence++ ) );
2040 wxXmlNode* specRefNode =
appendNode( coatingLayer,
"SpecRef" );
2055 std::vector<BOARD_STACKUP_ITEM*> layers = stackup.
GetList();
2056 std::set<PCB_LAYER_ID> added_layers;
2058 for(
int i = 0; i < stackup.
GetCount(); i++ )
2065 for(
int sublayer_id = 0; sublayer_id < stackup_item->
GetSublayersCount(); sublayer_id++ )
2067 wxXmlNode* cadLayerNode =
appendNode( aCadLayerNode,
"Layer" );
2070 if( ly_name.IsEmpty() )
2080 if( sublayer_id > 0 )
2081 ly_name += wxString::Format(
"_%d", sublayer_id );
2085 ly_name =
genString( ly_name,
"LAYER" );
2092 addAttribute( cadLayerNode,
"layerFunction",
"DIELCORE" );
2094 addAttribute( cadLayerNode,
"layerFunction",
"DIELPREG" );
2109 LSEQ layer_seq =
m_board->GetEnabledLayers().Seq();
2118 added_layers.insert( layer );
2119 wxXmlNode* cadLayerNode =
appendNode( aCadLayerNode,
"Layer" );
2132 wxXmlNode* topCoatingNode =
appendNode( aCadLayerNode,
"Layer" );
2134 addAttribute( topCoatingNode,
"layerFunction",
"COATINGCOND" );
2136 addAttribute( topCoatingNode,
"polarity",
"POSITIVE" );
2138 wxXmlNode* botCoatingNode =
appendNode( aCadLayerNode,
"Layer" );
2139 addAttribute( botCoatingNode,
"name",
"COATING_BOTTOM" );
2140 addAttribute( botCoatingNode,
"layerFunction",
"COATINGCOND" );
2142 addAttribute( botCoatingNode,
"polarity",
"POSITIVE" );
2161 for(
PAD*
pad : fp->Pads() )
2163 if(
pad->HasDrilledHole() )
2165 else if(
pad->HasHole() )
2172 wxXmlNode* drillNode =
appendNode( aCadLayerNode,
"Layer" );
2173 drillNode->AddAttribute(
"name",
genLayersString( layers.first, layers.second,
"DRILL" ) );
2178 wxXmlNode* spanNode =
appendNode( drillNode,
"Span" );
2185 wxXmlNode* drillNode =
appendNode( aCadLayerNode,
"Layer" );
2186 drillNode->AddAttribute(
"name",
genLayersString( layers.first, layers.second,
"SLOT" ) );
2192 wxXmlNode* spanNode =
appendNode( drillNode,
"Span" );
2208 std::vector<std::tuple<auxLayerType, PCB_LAYER_ID, PCB_LAYER_ID>> new_layers;
2210 if(
via->Padstack().IsFilled().value_or(
false ) )
2213 if(
via->Padstack().IsCapped().value_or(
false ) )
2218 if(
via->Padstack().IsPlugged( layer ).value_or(
false ) )
2221 if(
via->Padstack().IsCovered( layer ).value_or(
false ) )
2224 if(
via->Padstack().IsTented( layer ).value_or(
false ) )
2228 for(
auto& tuple : new_layers )
2234 bool add_node =
true;
2237 wxString layerFunction;
2240 switch( std::get<0>(layers) )
2244 layerFunction =
"COATINGNONCOND";
2248 layerFunction =
"HOLEFILL";
2252 layerFunction =
"COATINGNONCOND";
2256 layerFunction =
"HOLEFILL";
2260 layerFunction =
"COATINGCOND";
2268 if( add_node && !vec.empty() )
2270 wxXmlNode* node =
appendNode( aCadLayerNode,
"Layer" );
2284 const bool first_external = std::get<1>( layers ) ==
F_Cu || std::get<1>( layers ) ==
B_Cu;
2285 const bool second_external = std::get<2>( layers ) ==
F_Cu || std::get<2>( layers ) ==
B_Cu;
2287 if( first_external )
2289 if( second_external )
2296 if( second_external )
2302 wxXmlNode* spanNode =
appendNode( node,
"Span" );
2313 wxXmlNode* stepNode =
appendNode( aCadNode,
"Step" );
2314 wxFileName fn(
m_board->GetFileName() );
2320 wxXmlNode* datumNode =
appendNode( stepNode,
"Datum" );
2340 wxXmlNode* padNode =
appendNode( aContentNode,
"Pad" );
2347 wxXmlNode* xformNode =
appendNode( padNode,
"Xform" );
2354 addShape( padNode, *aPad, aLayer );
2358 wxXmlNode* pinRefNode =
appendNode( padNode,
"PinRef" );
2371 wxXmlNode* padNode =
appendNode( aContentNode,
"Pad" );
2392 addAttribute( aPadNode,
"padstackDefRef", th_pair->second );
2399 wxXmlNode* padStackDefNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"PadStackDef" );
2414 wxXmlNode* padStackHoleNode =
appendNode( padStackDefNode,
"PadstackHoleDef" );
2415 padStackHoleNode->AddAttribute(
"name",
2416 wxString::Format(
"%s%d_%d",
2432 if( !
m_board->IsLayerEnabled( layer ) )
2435 wxXmlNode* padStackPadDefNode =
appendNode( padStackDefNode,
"PadstackPadDef" );
2437 addAttribute( padStackPadDefNode,
"padUse",
"REGULAR" );
2445 addShape( padStackPadDefNode, shape );
2449 addShape( padStackPadDefNode, *aPad, layer );
2461 addAttribute( aContentNode,
"padstackDefRef", via_pair->second );
2468 wxXmlNode* padStackDefNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"PadStackDef" );
2474 wxXmlNode* padStackHoleNode =
appendNode( padStackDefNode,
"PadstackHoleDef" );
2477 addAttribute( padStackHoleNode,
"platingStatus",
"VIA" );
2485 auto addPadShape{ [&](
PCB_LAYER_ID aLayer,
const PCB_VIA* aViaShape,
const wxString& aLayerRef,
2486 bool aDrill ) ->
void
2491 shape.
SetEnd( {
KiROUND( aViaShape->GetDrillValue() / 2.0 ), 0 } );
2493 shape.
SetEnd( {
KiROUND( aViaShape->GetWidth( aLayer ) / 2.0 ), 0 } );
2495 wxXmlNode* padStackPadDefNode =
2496 appendNode( padStackDefNode,
"PadstackPadDef" );
2497 addAttribute( padStackPadDefNode,
"layerRef", aLayerRef );
2498 addAttribute( padStackPadDefNode,
"padUse",
"REGULAR" );
2501 addShape( padStackPadDefNode, shape );
2521 addPadShape( layer, aVia,
genLayerString( layer,
"PLUGGING" ),
true );
2524 addPadShape( layer, aVia,
genLayerString( layer,
"COVERING" ),
false );
2527 addPadShape( layer, aVia,
genLayerString( layer,
"TENTING" ),
false );
2543 && ( aDrill.size.x > 0 || aDrill.size.y > 0 );
2546 if( !hasBackdrill( secondary ) && !hasBackdrill( tertiary ) )
2557 if( hasBackdrill( secondary )
2558 && ( !layerHasRef( secondary.
start ) || !layerHasRef( secondary.
end ) ) )
2563 if( hasBackdrill( tertiary )
2564 && ( !layerHasRef( tertiary.
start ) || !layerHasRef( tertiary.
end ) ) )
2587 wxXmlNode* backdrillNode =
appendNode( specNode,
"Backdrill" );
2588 addAttribute( backdrillNode,
"startLayerRef", startLayer->second );
2589 addAttribute( backdrillNode,
"mustNotCutLayerRef", endLayer->second );
2593 if( stubLength < 0 )
2608 addAttribute( backdrillNode,
"postMachining", isPostMachined ? wxT(
"true" )
2619 wxString primarySpec = createSpec( primary, wxString::Format( wxT(
"BD_%dA" ), specIndex ) );
2621 wxString secondarySpec = createSpec( secondary, wxString::Format( wxT(
"BD_%dB" ), specIndex ) );
2622 wxString tertiarySpec = createSpec( tertiary, wxString::Format( wxT(
"BD_%dC" ), specIndex ) );
2624 if( primarySpec.IsEmpty() && secondarySpec.IsEmpty() && tertiarySpec.IsEmpty() )
2629 std::array<wxString, 3>{ primarySpec, secondarySpec,
2641 auto addRef = [&](
const wxString& aSpecName )
2643 if( aSpecName.IsEmpty() )
2646 wxXmlNode* specRefNode =
appendNode( aHoleNode,
"SpecRef" );
2651 for(
const wxString& specName : it->second )
2667 wxXmlNode* specNode = it->second;
2689 wxXmlNode* polygonNode =
nullptr;
2697 polygonNode =
appendNode( aParentNode,
"Polygon" );
2698 wxXmlNode* polybeginNode =
appendNode( polygonNode,
"PolyBegin" );
2700 const std::vector<VECTOR2I>& pts = aPolygon.
CPoints();
2701 addXY( polybeginNode, pts[0] );
2703 for(
size_t ii = 1; ii < pts.size(); ++ii )
2705 wxXmlNode* polyNode =
appendNode( polygonNode,
"PolyStepSegment" );
2706 addXY( polyNode, pts[ii] );
2709 wxXmlNode* polyendNode =
appendNode( polygonNode,
"PolyStepSegment" );
2710 addXY( polyendNode, pts[0] );
2721 addLineDesc( polygonNode, aWidth, aDashType,
true );
2725 wxCHECK( aWidth == 0,
false );
2738 for(
size_t ii = 1; ii < aPolygon.size(); ++ii )
2740 wxCHECK2( aPolygon[ii].PointCount() >= 3,
continue );
2742 wxXmlNode* cutoutNode =
appendNode( aParentNode,
"Cutout" );
2743 wxXmlNode* polybeginNode =
appendNode( cutoutNode,
"PolyBegin" );
2745 const std::vector<VECTOR2I>& hole = aPolygon[ii].CPoints();
2746 addXY( polybeginNode, hole[0] );
2748 for(
size_t jj = 1; jj < hole.size(); ++jj )
2750 wxXmlNode* polyNode =
appendNode( cutoutNode,
"PolyStepSegment" );
2751 addXY( polyNode, hole[jj] );
2754 wxXmlNode* polyendNode =
appendNode( cutoutNode,
"PolyStepSegment" );
2755 addXY( polyendNode, hole[0] );
2768 wxXmlNode* outlineNode =
appendNode( aParentNode,
"Outline" );
2785 wxLogTrace(
traceIpc2581, wxS(
"Failed to add polygon to outline" ) );
2788 if( !outlineNode->GetChildren() )
2790 aParentNode->RemoveChild( outlineNode );
2807 wxXmlNode* contourNode =
appendNode( aParentNode,
"Contour" );
2817 aParentNode->RemoveChild( contourNode );
2830 if( !
m_board->GetBoardPolygonOutlines( board_outline,
false ) )
2836 wxXmlNode* profileNode =
appendNode( aStepNode,
"Profile" );
2840 wxLogTrace(
traceIpc2581, wxS(
"Failed to add polygon to profile" ) );
2841 aStepNode->RemoveChild( profileNode );
2867 std::unique_ptr<FOOTPRINT> fp(
static_cast<FOOTPRINT*
>( aFp->
Clone() ) );
2868 fp->SetParentGroup(
nullptr );
2869 fp->SetPosition( { 0, 0 } );
2870 fp->SetOrientation(
ANGLE_0 );
2875 bool wasFlipped = fp->IsFlipped();
2878 if( fp->IsFlipped() )
2883 fp->GetFPID().GetLibItemName().wx_str(),
2887 addAttribute( aContentNode,
"packageRef", iter->second );
2894 wxXmlNode* packageNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"Package" );
2895 wxXmlNode* otherSideViewNode =
nullptr;
2901 if( fp->FindPadByNumber(
"1" ) )
2903 else if ( fp->FindPadByNumber(
"A1" ) )
2905 else if ( fp->FindPadByNumber(
"A" ) )
2907 else if ( fp->FindPadByNumber(
"a" ) )
2909 else if ( fp->FindPadByNumber(
"a1" ) )
2911 else if ( fp->FindPadByNumber(
"Anode" ) )
2913 else if ( fp->FindPadByNumber(
"ANODE" ) )
2920 PAD* pinOnePad = fp->FindPadByNumber(
"1" );
2923 pinOnePad = fp->FindPadByNumber(
"A1" );
2925 if( pinOnePad && fp->Pads().size() >= 2 )
2928 BOX2I fpBBox = fp->GetBoundingBox();
2938 const char* orientation =
"OTHER";
2940 if( onCenterX && onCenterY )
2941 orientation =
"CENTER";
2942 else if( onCenterX && pinPos.
y <
center.y )
2943 orientation =
"UPPER_CENTER";
2944 else if( onCenterX && pinPos.
y >
center.y )
2945 orientation =
"LOWER_CENTER";
2946 else if( onCenterY && pinPos.
x <
center.x )
2947 orientation =
"LEFT";
2948 else if( onCenterY && pinPos.
x >
center.x )
2949 orientation =
"RIGHT";
2951 orientation =
"UPPER_LEFT";
2953 orientation =
"UPPER_RIGHT";
2955 orientation =
"LOWER_LEFT";
2957 orientation =
"LOWER_RIGHT";
2959 addAttribute( packageNode,
"pinOneOrientation", orientation );
2963 addAttribute( packageNode,
"pinOneOrientation",
"OTHER" );
2964 addAttribute( packageNode,
"comment",
"Pin 1 orientation could not be determined" );
2970 : fp->GetCourtyard(
F_CrtYd );
2972 : fp->GetCourtyard(
B_CrtYd );
2989 otherSideViewNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"OtherSideView" );
2995 wxXmlNode* pickupPointNode =
appendNode( packageNode,
"PickupPoint" );
2999 std::map<PCB_LAYER_ID, std::map<bool, std::vector<BOARD_ITEM*>>> elements;
3001 for(
BOARD_ITEM* item : fp->GraphicalItems() )
3026 elements[item->GetLayer()][is_abs].push_back( item );
3029 auto add_base_node =
3032 wxXmlNode* parent = packageNode;
3041 bool is_other_side = wasFlipped ? ( aLayer ==
F_SilkS || aLayer ==
F_Fab )
3046 if( !otherSideViewNode )
3047 otherSideViewNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"OtherSideView" );
3049 parent = otherSideViewNode;
3055 nodeName =
"SilkScreen";
3056 else if( aLayer ==
F_Fab || aLayer ==
B_Fab )
3057 nodeName =
"AssemblyDrawing";
3061 wxXmlNode* new_node =
appendNode( parent, nodeName );
3065 auto add_marking_node =
3066 [&]( wxXmlNode* aNode ) -> wxXmlNode*
3068 wxXmlNode* marking_node =
appendNode( aNode,
"Marking" );
3070 return marking_node;
3073 std::map<PCB_LAYER_ID, wxXmlNode*> layer_nodes;
3074 std::map<PCB_LAYER_ID, BOX2I> layer_bbox;
3078 if( elements.find( layer ) != elements.end() )
3080 if( elements[layer][
true].size() > 0 )
3081 layer_bbox[layer] = elements[layer][
true][0]->GetBoundingBox();
3082 else if( elements[layer][
false].size() > 0 )
3083 layer_bbox[layer] = elements[layer][
false][0]->GetBoundingBox();
3087 for(
auto& [layer, map] : elements )
3089 wxXmlNode* layer_node = add_base_node( layer );
3090 wxXmlNode* marking_node = add_marking_node( layer_node );
3091 wxXmlNode* group_node =
appendNode( marking_node,
"UserSpecial" );
3092 bool update_bbox =
false;
3096 layer_nodes[layer] = layer_node;
3100 for(
auto& [is_abs, vec] : map )
3104 wxXmlNode* output_node =
nullptr;
3107 layer_bbox[layer].Merge( item->GetBoundingBox() );
3110 output_node = add_marking_node( layer_node );
3112 output_node = group_node;
3114 switch( item->Type() )
3120 if(
text->IsKnockout() )
3134 if(
text->IsBorderEnabled() )
3137 text->GetEffectiveShape()->TransformToPolygon( poly_set, 0,
ERROR_INSIDE );
3139 text->GetBorderWidth() );
3162 if( group_node->GetChildren() ==
nullptr )
3164 marking_node->RemoveChild( group_node );
3165 layer_node->RemoveChild( marking_node );
3167 delete marking_node;
3171 for(
auto&[layer, bbox] : layer_bbox )
3173 if( bbox.GetWidth() > 0 )
3175 wxXmlNode* outlineNode =
insertNode( layer_nodes[layer],
"Outline" );
3178 std::vector<VECTOR2I> points( 4 );
3179 points[0] = bbox.GetPosition();
3180 points[2] = bbox.GetEnd();
3181 points[1].x = points[0].x;
3182 points[1].y = points[2].y;
3183 points[3].x = points[2].x;
3184 points[3].y = points[0].y;
3186 outline.
Append( points );
3192 std::map<wxString, wxXmlNode*> pin_nodes;
3194 for(
size_t ii = 0; ii < fp->Pads().size(); ++ii )
3196 PAD*
pad = fp->Pads()[ii];
3198 wxXmlNode* pinNode =
nullptr;
3200 auto [ it, inserted ] = pin_nodes.emplace( pin_name,
nullptr );
3205 it->second = pinNode;
3210 genString( fp->GetReference(),
"CMP" ), pin_name );
3213 addAttribute( pinNode,
"electricalType",
"MECHANICAL" );
3214 else if(
pad->IsOnCopperLayer() )
3215 addAttribute( pinNode,
"electricalType",
"ELECTRICAL" );
3217 addAttribute( pinNode,
"electricalType",
"UNDEFINED" );
3219 if(
pad->HasHole() )
3224 if(
pad->GetFPRelativeOrientation() !=
ANGLE_0 )
3226 wxXmlNode* xformNode =
appendNode( pinNode,
"Xform" );
3227 EDA_ANGLE pad_angle =
pad->GetFPRelativeOrientation().Normalize();
3229 if( fp->IsFlipped() )
3246 if( otherSideViewNode )
3247 packageNode->AddChild( otherSideViewNode );
3255 std::vector<wxXmlNode*> componentNodes;
3256 std::vector<wxXmlNode*> packageNodes;
3257 std::set<wxString> packageNames;
3259 bool generate_unique =
m_OEMRef.empty();
3263 wxXmlNode* componentNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"Component" );
3265 wxXmlNode* pkg =
addPackage( componentNode, fp );
3268 packageNodes.push_back( pkg );
3274 if( !generate_unique )
3277 if( field && !field->
GetText().empty() )
3283 name = wxString::Format(
"%s_%s_%s", fp->GetFPID().GetFullLibraryName(),
3284 fp->GetFPID().GetLibItemName().wx_str(),
3289 Report(
_(
"Duplicate footprint pointers encountered; IPC-2581 output may be incorrect." ),
3297 else if( fp->GetAttributes() &
FP_SMD )
3302 if( fp->GetOrientation() !=
ANGLE_0 || fp->IsFlipped() )
3304 wxXmlNode* xformNode =
appendNode( componentNode,
"Xform" );
3311 if( fp->IsFlipped() )
3315 addLocationNode( componentNode, fp->GetPosition().x, fp->GetPosition().y );
3317 componentNodes.push_back( componentNode );
3326 for( wxXmlNode* pkg : packageNodes )
3327 aStepNode->AddChild( pkg );
3329 for( wxXmlNode* cmp : componentNodes )
3330 aStepNode->AddChild( cmp );
3338 wxXmlNode* netNode =
appendNode( aStepNode,
"LogicalNet" );
3340 genString(
m_board->GetNetInfo().GetNetItem( net )->GetNetname(),
"NET" ) ) ;
3342 for(
auto& [cmp,
pin] : pin_pair )
3344 wxXmlNode* netPinNode =
appendNode( netNode,
"PinRef" );
3358 std::vector<std::unique_ptr<FOOTPRINT>> footprints;
3362 std::map<PCB_LAYER_ID, std::map<int, std::vector<BOARD_ITEM*>>> elements;
3364 std::for_each(
m_board->Tracks().begin(),
m_board->Tracks().end(),
3365 [&layers, &elements](
PCB_TRACK* aTrack )
3367 if( aTrack->Type() == PCB_VIA_T )
3369 PCB_VIA* via = static_cast<PCB_VIA*>( aTrack );
3371 for( PCB_LAYER_ID layer : layers )
3373 if( via->FlashLayer( layer ) )
3374 elements[layer][via->GetNetCode()].push_back( via );
3379 elements[aTrack->GetLayer()][aTrack->GetNetCode()].push_back( aTrack );
3383 std::for_each( m_board->Zones().begin(), m_board->Zones().end(),
3384 [ &elements ](
ZONE* zone )
3386 LSEQ zone_layers = zone->GetLayerSet().Seq();
3388 for( PCB_LAYER_ID layer : zone_layers )
3389 elements[layer][zone->GetNetCode()].push_back( zone );
3392 for(
BOARD_ITEM* item : m_board->Drawings() )
3395 elements[conn_it->GetLayer()][conn_it->GetNetCode()].push_back( conn_it );
3397 elements[item->GetLayer()][0].push_back( item );
3400 for(
FOOTPRINT* fp : m_board->Footprints() )
3402 for(
PCB_FIELD* field : fp->GetFields() )
3403 elements[field->GetLayer()][0].push_back( field );
3405 for(
BOARD_ITEM* item : fp->GraphicalItems() )
3406 elements[item->GetLayer()][0].push_back( item );
3408 for(
PAD*
pad : fp->Pads() )
3410 LSEQ pad_layers =
pad->GetLayerSet().Seq();
3414 if(
pad->FlashLayer( layer ) )
3415 elements[layer][
pad->GetNetCode()].push_back(
pad );
3442 if( m_progressReporter )
3443 m_progressReporter->SetMaxProgress( nets.GetNetCount() * layers.size() );
3445 wxXmlNode* layerNode = appendNode( aStepNode,
"LayerFeature" );
3446 addAttribute( layerNode,
"layerRef", m_layer_name_map[layer] );
3448 auto process_net = [&] (
int net )
3450 std::vector<BOARD_ITEM*>& vec = elements[layer][net];
3455 std::stable_sort( vec.begin(), vec.end(),
3458 if( a->GetParentFootprint() == b->GetParentFootprint() )
3459 return a->Type() < b->Type();
3461 return a->GetParentFootprint() < b->GetParentFootprint();
3464 generateLayerSetNet( layerNode, layer, vec );
3469 if( m_progressReporter )
3471 m_progressReporter->Report( wxString::Format(
_(
"Exporting Layer %s, Net %s" ),
3472 m_board->GetLayerName( layer ),
3473 net->GetNetname() ) );
3474 m_progressReporter->AdvanceProgress();
3477 process_net( net->GetNetCode() );
3480 if( layerNode->GetChildren() ==
nullptr )
3482 aStepNode->RemoveChild( layerNode );
3483 deleteNode( layerNode );
3495 wxXmlNode* layerNode =
appendNode( aLayerNode,
"LayerFeature" );
3496 layerNode->AddAttribute(
"layerRef",
genLayersString( layers.first, layers.second,
"DRILL" ) );
3507 Report(
_(
"Via uses unsupported padstack; omitted from drill data." ),
3512 wxXmlNode* padNode =
appendNode( layerNode,
"Set" );
3515 if(
via->GetNetCode() > 0 )
3518 wxXmlNode* holeNode =
appendNode( padNode,
"Hole" );
3519 addAttribute( holeNode,
"name", wxString::Format(
"H%d", hole_count++ ) );
3524 addXY( holeNode,
via->GetPosition() );
3534 Report(
_(
"Pad uses unsupported padstack; hole was omitted from drill data." ),
3539 wxXmlNode* padNode =
appendNode( layerNode,
"Set" );
3542 if(
pad->GetNetCode() > 0 )
3545 wxXmlNode* holeNode =
appendNode( padNode,
"Hole" );
3546 addAttribute( holeNode,
"name", wxString::Format(
"H%d", hole_count++ ) );
3552 addXY( holeNode,
pad->GetPosition() );
3562 wxXmlNode* layerNode =
appendNode( aLayerNode,
"LayerFeature" );
3563 layerNode->AddAttribute(
"layerRef",
genLayersString( layers.first, layers.second,
"SLOT" ) );
3567 wxXmlNode* padNode =
appendNode( layerNode,
"Set" );
3569 if(
pad->GetNetCode() > 0 )
3572 addSlotCavity( padNode, *
pad, wxString::Format(
"SLOT%d", hole_count++ ) );
3579 std::vector<BOARD_ITEM*>& aItems )
3581 auto it = aItems.begin();
3582 wxXmlNode* layerSetNode =
appendNode( aLayerNode,
"Set" );
3583 wxXmlNode* featureSetNode =
appendNode( layerSetNode,
"Features" );
3584 wxXmlNode* specialNode =
appendNode( featureSetNode,
"UserSpecial" );
3586 bool has_via =
false;
3587 bool has_pad =
false;
3589 wxXmlNode* padSetNode =
nullptr;
3591 wxXmlNode* viaSetNode =
nullptr;
3593 wxXmlNode* teardropLayerSetNode =
nullptr;
3594 wxXmlNode* teardropFeatureSetNode =
nullptr;
3596 bool teardrop_warning =
false;
3601 if( item->GetNetCode() > 0 )
3611 shape.
SetStart( track->GetStart() );
3612 shape.
SetEnd( track->GetEnd() );
3613 shape.
SetWidth( track->GetWidth() );
3630 viaSetNode = layerSetNode;
3635 viaSetNode =
appendNode( layerSetNode,
"Set" );
3637 if( track->GetNetCode() > 0 )
3644 addVia( viaSetNode,
static_cast<PCB_VIA*
>( track ), aLayer );
3651 wxXmlNode* zoneFeatureNode = specialNode;
3653 if( zone->IsTeardropArea() )
3657 if( !teardropFeatureSetNode )
3659 teardropLayerSetNode =
appendNode( aLayerNode,
"Set" );
3660 addAttribute( teardropLayerSetNode,
"geometryUsage",
"TEARDROP" );
3662 if( zone->GetNetCode() > 0 )
3665 genString( zone->GetNetname(),
"NET" ) );
3668 wxXmlNode* new_teardrops =
appendNode( teardropLayerSetNode,
"Features" );
3670 teardropFeatureSetNode =
appendNode( new_teardrops,
"UserSpecial" );
3673 zoneFeatureNode = teardropFeatureSetNode;
3675 else if( !teardrop_warning )
3677 Report(
_(
"Teardrops are not supported in IPC-2581 revision B; they were exported as zones." ),
3679 teardrop_warning =
true;
3686 wxXmlNode* tempSetNode =
appendNode( aLayerNode,
"Set" );
3689 wxXmlNode* newFeatures =
appendNode( tempSetNode,
"Features" );
3691 zoneFeatureNode =
appendNode( newFeatures,
"UserSpecial" );
3695 SHAPE_POLY_SET& zone_shape = *zone->GetFilledPolysList( aLayer );
3697 for(
int ii = 0; ii < zone_shape.
OutlineCount(); ++ii )
3708 wxXmlNode* tempSetNode =
appendNode( aLayerNode,
"Set" );
3711 addAttribute( tempSetNode,
"geometryUsage",
"GRAPHIC" );
3713 bool link_to_component =
true;
3716 link_to_component =
false;
3718 if( link_to_component )
3721 wxXmlNode* tempFeature =
appendNode( tempSetNode,
"Features" );
3730 wxXmlNode* tempSetNode =
appendNode( aLayerNode,
"Set" );
3732 if( shape->GetNetCode() > 0 )
3735 wxXmlNode* tempFeature =
appendNode( tempSetNode,
"Features" );
3752 text_item =
static_cast<EDA_TEXT*
>( pcb_text );
3754 text_item =
static_cast<EDA_TEXT*
>( pcb_textbox );
3759 wxXmlNode* tempSetNode =
appendNode( aLayerNode,
"Set" );
3764 bool link_to_component = fp !=
nullptr;
3767 link_to_component =
false;
3769 if( link_to_component )
3772 wxXmlNode* nonStandardAttributeNode =
appendNode( tempSetNode,
"NonstandardAttribute" );
3773 addAttribute( nonStandardAttributeNode,
"name",
"TEXT" );
3775 addAttribute( nonStandardAttributeNode,
"type",
"STRING" );
3777 wxXmlNode* tempFeature =
appendNode( tempSetNode,
"Features" );
3783 addText( tempFeature, text_item,
text->GetFontMetrics() );
3801 padSetNode = layerSetNode;
3806 padSetNode =
appendNode( aLayerNode,
"Set" );
3808 if(
pad->GetNetCode() > 0 )
3823 switch( item->Type() )
3828 add_track(
static_cast<PCB_TRACK*
>( item ) );
3836 add_pad(
static_cast<PAD*
>( item ) );
3840 add_shape(
static_cast<PCB_SHAPE*
>( item ) );
3865 if( specialNode->GetChildren() ==
nullptr )
3867 featureSetNode->RemoveChild( specialNode );
3871 if( featureSetNode->GetChildren() ==
nullptr )
3873 layerSetNode->RemoveChild( featureSetNode );
3877 if( layerSetNode->GetChildren() ==
nullptr )
3879 aLayerNode->RemoveChild( layerSetNode );
3888 bool add_node =
true;
3894 switch( std::get<0>(layers) )
3923 wxXmlNode* layerNode =
appendNode( aStepNode,
"LayerFeature" );
3927 layerNode->AddAttribute(
"layerRef",
genLayersString( std::get<1>( layers ),
3941 shape.
SetEnd( {
KiROUND(
via->GetWidth( std::get<1>( layers ) ) / 2.0 ), 0 } );
3943 wxXmlNode* padNode =
appendNode( layerNode,
"Pad" );
3974 std::set<wxString> unique_parts;
3975 std::map<wxString,wxString> unique_vendors;
3979 auto [ it, success ] = unique_parts.insert(
name );
3984 wxXmlNode* part =
appendNode( avl,
"AvlItem" );
3991 for (
int ii = 0; ii < 2; ++ii )
3997 if( mpn_name.empty() )
4000 wxXmlNode* vmpn =
appendNode( part,
"AvlVmpn" );
4004 wxXmlNode* mpn =
appendNode( vmpn,
"AvlMpn" );
4007 wxXmlNode* vendor =
appendNode( vmpn,
"AvlVendor" );
4009 wxString vendor_name = wxT(
"UNKNOWN" );
4012 if( !ii && company[ii] )
4020 else if( !ii && !company_name[ii].
empty() )
4022 vendor_name = company_name[ii];
4024 else if( ii && !
m_dist.empty() )
4029 auto [vendor_id, inserted] = unique_vendors.emplace(
4031 wxString::Format(
"VENDOR_%zu", unique_vendors.size() ) );
4033 addAttribute( vendor,
"enterpriseRef", vendor_id->second );
4037 wxXmlNode* new_vendor =
new wxXmlNode( wxXML_ELEMENT_NODE,
"Enterprise" );
4053 const std::map<std::string, UTF8>* aProperties )
4097 if(
auto it = aProperties->find(
"units" ); it != aProperties->end() )
4099 if( it->second ==
"inch" )
4106 if(
auto it = aProperties->find(
"sigfig" ); it != aProperties->end() )
4107 m_sigfig = std::stoi( it->second );
4109 if(
auto it = aProperties->find(
"version" ); it != aProperties->end() )
4112 if(
auto it = aProperties->find(
"OEMRef" ); it != aProperties->end() )
4115 if(
auto it = aProperties->find(
"mpn" ); it != aProperties->end() )
4116 m_mpn = it->second.wx_str();
4118 if(
auto it = aProperties->find(
"mfg" ); it != aProperties->end() )
4119 m_mfg = it->second.wx_str();
4121 if(
auto it = aProperties->find(
"dist" ); it != aProperties->end() )
4122 m_dist = it->second.wx_str();
4124 if(
auto it = aProperties->find(
"distpn" ); it != aProperties->end() )
4127 if(
auto it = aProperties->find(
"bomrev" ); it != aProperties->end() )
4132 for(
char c =
'a'; c <=
'z'; ++c )
4135 for(
char c =
'A'; c <=
'Z'; ++c )
4138 for(
char c =
'0'; c <=
'9'; ++c )
4142 std::string specialChars =
"_\\-.+><";
4144 for(
char c : specialChars )
4171 wxXmlNode* insertBefore =
nullptr;
4173 for( wxXmlNode* child =
m_contentNode->GetChildren(); child; child = child->GetNext() )
4175 if( child->GetName().StartsWith(
"Dictionary" ) )
4177 insertBefore = child;
4183 [&](
const wxString& aNodeName, wxXmlNode* aSection )
4188 wxXmlNode* ref =
new wxXmlNode( wxXML_ELEMENT_NODE, aNodeName );
4189 ref->AddAttribute(
"name", aSection->GetAttribute(
"name" ) );
4197 insertRef(
"BomRef", bom_node );
4198 insertRef(
"AvlRef", avl_node );
4207 double written_bytes = 0.0;
4208 double last_yield = 0.0;
4215 auto update_progress = [&](
size_t aBytes )
4217 written_bytes += aBytes;
4218 double percent = written_bytes /
static_cast<double>(
m_total_bytes );
4223 if( last_yield + 0.01 < percent )
4225 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
const VECTOR2I & GetBezierC2() const
FILL_T GetFillMode() const
int GetRectangleWidth() const
SHAPE_POLY_SET & GetPolyShape()
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
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)
std::map< wxString, std::array< wxString, 3 > > m_padstack_backdrill_specs
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< 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.
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 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
@ 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