47#include <wx/numformatter.h>
48#include <wx/xml/xml.h>
76 std::vector<FOOTPRINT*> retval;
79 retval.push_back(
static_cast<FOOTPRINT*
>( fp->Clone() ) );
89 if( aParent->GetChildren() )
90 aNode->SetNext( aParent->GetChildren() );
92 aNode->SetNext(
nullptr );
94 aParent->SetChildren( aNode );
95 aNode->SetParent( aParent );
104 aNode->SetNext( aPrev->GetNext() );
105 aPrev->SetNext( aNode );
106 aNode->SetParent( aPrev->GetParent() );
115 wxXmlNode* node =
new wxXmlNode( wxXML_ELEMENT_NODE, aName );
127 static wxXmlNode* lastNode =
nullptr;
129 if( lastNode && lastNode->GetParent() == aParent && lastNode->GetNext() ==
nullptr )
131 aNode->SetParent( aParent );
132 lastNode->SetNext( aNode );
136 aParent->AddChild( aNode );
148 wxXmlNode* node =
new wxXmlNode( wxXML_ELEMENT_NODE, aName );
162 str.Replace( wxT(
":" ), wxT(
"_" ) );
166 for( wxString::const_iterator iter = aStr.begin(); iter != aStr.end(); ++iter )
183 wxString key = aPrefix ? wxString( aPrefix ) + wxT(
":" ) + aStr : aStr;
193 wxString
name = base;
197 name = wxString::Format(
"%s_%d", base, suffix++ );
213 const char* aPrefix )
const
215 return genString( wxString::Format( wxS(
"%s_%s" ),
217 m_board->GetLayerName( aBottom ) ), aPrefix );
228 if(
name.empty() && fp )
232 if( fp->
Pads()[ii] == aPad )
240 name = wxString::Format(
"NPTH%zu", ii );
241 else if(
name.empty() )
242 name = wxString::Format(
"PAD%zu", ii );
253 [&](
const wxString& aName )
272 wxString
name = baseName;
275 while( !tryInsert(
name ) )
276 name = wxString::Format(
"%s_%d", baseName, suffix++ );
286 wxString str = wxString::FromCDouble( aVal, aSigFig == -1 ?
m_sigfig : aSigFig );
289 while( str.EndsWith( wxT(
"00" ) ) )
293 if( str == wxT(
"-0.0" ) )
318 aNode->AddAttribute( aName, aValue );
324 wxXmlNode* xmlHeaderNode =
new wxXmlNode(wxXML_ELEMENT_NODE,
"IPC-2581");
326 addAttribute( xmlHeaderNode,
"xmlns",
"http://webstds.ipc.org/2581");
327 addAttribute( xmlHeaderNode,
"xmlns:xsi",
"http://www.w3.org/2001/XMLSchema-instance");
328 addAttribute( xmlHeaderNode,
"xmlns:xsd",
"http://www.w3.org/2001/XMLSchema");
333 "http://webstds.ipc.org/2581 http://webstds.ipc.org/2581/IPC-2581B1.xsd" );
338 "http://webstds.ipc.org/2581 http://webstds.ipc.org/2581/IPC-2581C.xsd" );
343 return xmlHeaderNode;
355 wxXmlNode* node =
appendNode( contentNode,
"FunctionMode" );
363 wxFileName fn(
m_board->GetFileName() );
370 contentNode->AddChild( color_node );
374 wxXmlNode* fillNode =
appendNode( contentNode,
"DictionaryFillDesc" );
394 contentNode->AddChild( color_node );
403 wxXmlNode* location_node =
appendNode( aNode,
"Location" );
478 wxXmlNode* color_node =
new wxXmlNode( wxXML_ELEMENT_NODE,
"DictionaryColor" );
482 wxString layer_name = item->GetLayerName();
483 int sub_layer_count = 1;
485 if( layer_name.empty() )
486 layer_name =
m_board->GetLayerName( item->GetBrdLayerId() );
488 layer_name =
genString( layer_name,
"LAYER" );
492 layer_name =
genString( wxString::Format(
"DIELECTRIC_%d", item->GetDielectricLayerId() ),
494 sub_layer_count = item->GetSublayersCount();
501 for(
int sub_idx = 0; sub_idx < sub_layer_count; sub_idx++ )
503 wxString sub_layer_name = layer_name;
506 sub_layer_name += wxString::Format(
"_%d", sub_idx );
508 wxXmlNode* node =
appendNode( aContentNode,
"LayerRef" );
514 wxXmlNode* entry_color =
appendNode( color_node,
"EntryColor" );
516 wxXmlNode* color =
appendNode( entry_color,
"Color" );
518 wxString colorName = item->GetColor( sub_idx );
520 if( colorName.StartsWith( wxT(
"#" ) ) )
523 COLOR4D layer_color( colorName );
535 if( fab_color.GetName() == colorName )
537 addAttribute( color,
"r", wxString::Format(
"%d",
KiROUND( fab_color.GetColor( item->GetType() ).r * 255 ) ) );
538 addAttribute( color,
"g", wxString::Format(
"%d",
KiROUND( fab_color.GetColor( item->GetType() ).g * 255 ) ) );
539 addAttribute( color,
"b", wxString::Format(
"%d",
KiROUND( fab_color.GetColor( item->GetType() ).b * 255 ) ) );
559 wxXmlNode* fillDesc_node =
appendNode( aNode,
"FillDesc" );
565 wxXmlNode* fillDesc_node =
appendNode( aNode,
"FillDesc" );
566 addAttribute( fillDesc_node,
"fillProperty",
"HOLLOW" );
573 wxCHECK_RET( aNode,
"aNode is null" );
578 wxXmlNode* entry_node =
nullptr;
582 size_t hash =
lineHash( aWidth, aDashType );
583 wxString
name = wxString::Format(
"LINE_%zu",
m_line_dict.size() + 1 );
587 wxXmlNode* lineDesc_node =
appendNode( aNode,
"LineDescRef" );
602 wxXmlNode* line_node =
appendNode( entry_node,
"LineDesc" );
649 wxXmlNode* text_node =
appendNode( aContentNode,
"UserSpecial" );
651 std::list<VECTOR2I> pts;
659 wxXmlNode* line_node =
nullptr;
666 addXY( line_node, pts.front(),
"startX",
"startY" );
667 addXY( line_node, pts.back(),
"endX",
"endY" );
671 line_node =
appendNode( text_node,
"Polyline" );
672 wxXmlNode* point_node =
appendNode( line_node,
"PolyBegin" );
673 addXY( point_node, pts.front() );
675 auto iter = pts.begin();
677 for( ++iter; iter != pts.end(); ++iter )
679 wxXmlNode* point_node =
appendNode( line_node,
"PolyStepSegment" );
680 addXY( point_node, *iter );
695 if( aPt1 == pts.back() )
696 pts.push_back( aPt2 );
697 else if( aPt2 == pts.front() )
698 pts.push_front( aPt1 );
699 else if( aPt1 == pts.front() )
700 pts.push_front( aPt2 );
701 else if( aPt2 == pts.back() )
702 pts.push_back( aPt1 );
706 pts.push_back( aPt1 );
707 pts.push_back( aPt2 );
712 pts.push_back( aPt1 );
713 pts.push_back( aPt2 );
719 if( aPoly.PointCount() < 3 )
722 wxXmlNode* outline_node =
appendNode( text_node,
"Outline" );
723 wxXmlNode* poly_node =
appendNode( outline_node,
"Polygon" );
726 const std::vector<VECTOR2I>& pts = aPoly.CPoints();
727 wxXmlNode* point_node =
appendNode( poly_node,
"PolyBegin" );
728 addXY( point_node, pts.front() );
730 for(
size_t ii = 1; ii < pts.size(); ++ii )
732 wxXmlNode* point_node =
734 addXY( point_node, pts[ii] );
737 point_node =
appendNode( poly_node,
"PolyStepSegment" );
738 addXY( point_node, pts.front() );
749 if( text_node->GetChildren() ==
nullptr )
751 aContentNode->RemoveChild( text_node );
764 wxXmlNode* shape_node =
appendNode( aContentNode,
"StandardPrimitiveRef" );
769 int maxError =
m_board->GetDesignSettings().m_MaxError;
789 wxXmlNode* circle_node =
appendNode( entry_node,
"Circle" );
790 circle_node->AddAttribute(
"diameter",
803 wxXmlNode* rect_node =
appendNode( entry_node,
"RectCenter" );
819 wxXmlNode* oval_node =
appendNode( entry_node,
"Oval" );
835 wxXmlNode* roundrect_node =
appendNode( entry_node,
"RectRound" );
839 roundrect_node->AddAttribute(
"radius",
857 wxXmlNode* chamfered_node =
appendNode( entry_node,
"RectCham" );
862 int shorterSide = std::min( pad_size.
x, pad_size.
y );
893 int dx = pad_size.
x / 2;
894 int dy = pad_size.
y / 2;
895 int ddx = trap_delta.
x / 2;
896 int ddy = trap_delta.
y / 2;
898 outline.
Append( -dx - ddy, dy + ddx );
899 outline.
Append( dx + ddy, dy - ddx );
900 outline.
Append( dx - ddy, -dy + ddx );
901 outline.
Append( -dx + ddy, -dy - ddx );
943 wxXmlNode* shape_node =
appendNode( aContentNode,
"StandardPrimitiveRef" );
957 wxXmlNode* shape_node =
appendNode( aContentNode,
"UserPrimitiveRef" );
975 wxXmlNode* special_node =
appendNode( entry_node,
"UserSpecial" );
977 wxXmlNode* circle_node =
appendNode( special_node,
"Circle" );
1002 wxXmlNode* special_node =
appendNode( entry_node,
"UserSpecial" );
1009 wxXmlNode* rect_node =
appendNode( special_node,
"RectRound" );
1026 width += stroke_width;
1027 height += stroke_width;
1049 wxXmlNode* special_node =
appendNode( entry_node,
"UserSpecial" );
1071 wxXmlNode* arc_node =
appendNode( aContentNode,
"Arc" );
1073 addXY( arc_node, aShape.
GetEnd(),
"endX",
"endY" );
1090 wxXmlNode* polyline_node =
appendNode( aContentNode,
"Polyline" );
1094 std::vector<VECTOR2I> points;
1097 wxXmlNode* point_node =
appendNode( polyline_node,
"PolyBegin" );
1098 addXY( point_node, points[0] );
1100 for(
size_t i = 1; i < points.size(); i++ )
1102 wxXmlNode* point_node =
appendNode( polyline_node,
"PolyStepSegment" );
1103 addXY( point_node, points[i] );
1117 wxXmlNode* line_node =
appendNode( aContentNode,
"Line" );
1119 addXY( line_node, aShape.
GetEnd(),
"endX",
"endY" );
1136 wxXmlNode* shape_node =
appendNode( aContentNode,
"UserPrimitiveRef" );
1145 wxXmlNode* slotNode =
appendNode( aNode,
"SlotCavity" );
1165 if( drill_size.
y > drill_size.
x )
1167 std::swap( drill_size.
x, drill_size.
y );
1174 wxXmlNode* xformNode =
appendNode( slotNode,
"Xform" );
1179 wxXmlNode* ovalNode =
appendNode( slotNode,
"Oval" );
1187 int maxError =
m_board->GetDesignSettings().m_MaxError;
1199 wxXmlNode* roleNode =
appendNode( logisticNode,
"Role" );
1207 wxXmlNode* personNode =
appendNode( logisticNode,
"Person" );
1209 addAttribute( personNode,
"enterpriseRef",
"UNKNOWN" );
1212 return logisticNode;
1223 addAttribute( historyNode,
"origination", wxDateTime::Now().FormatISOCombined() );
1225 addAttribute( historyNode,
"lastChange", wxDateTime::Now().FormatISOCombined() );
1227 wxXmlNode* fileRevisionNode =
appendNode( historyNode,
"FileRevision" );
1228 addAttribute( fileRevisionNode,
"fileRevisionId",
"1" );
1229 addAttribute( fileRevisionNode,
"comment",
"NO COMMENT" );
1232 wxXmlNode* softwarePackageNode =
appendNode( fileRevisionNode,
"SoftwarePackage" );
1235 addAttribute( softwarePackageNode,
"vendor",
"KiCad EDA" );
1237 wxXmlNode* certificationNode =
appendNode( softwarePackageNode,
"Certification" );
1238 addAttribute( certificationNode,
"certificationStatus",
"SELFTEST" );
1261 m_refdes =
new std::vector<REFDES>();
1262 m_props =
new std::map<wxString, wxString>();
1273 wxString m_OEMDesignRef;
1277 wxString m_description;
1279 std::vector<REFDES>* m_refdes;
1280 std::map<wxString, wxString>*
m_props;
1283 std::set<std::unique_ptr<struct BOM_ENTRY>,
1284 std::function<bool(
const std::unique_ptr<struct BOM_ENTRY>&,
1285 const std::unique_ptr<struct BOM_ENTRY>& )>> bom_entries(
1286 [](
const std::unique_ptr<struct BOM_ENTRY>& a,
1287 const std::unique_ptr<struct BOM_ENTRY>& b )
1289 return a->m_OEMDesignRef < b->m_OEMDesignRef;
1294 std::unique_ptr<FOOTPRINT> fp(
static_cast<FOOTPRINT*
>( fp_it->Clone() ) );
1295 fp->SetParentGroup(
nullptr );
1296 fp->SetPosition( {0, 0} );
1297 fp->SetOrientation(
ANGLE_0 );
1304 Report( wxString::Format(
_(
"Footprint %s not found in dictionary; BOM data may be incomplete." ),
1305 fp->GetFPID().GetLibItemName().wx_str() ),
1310 auto entry = std::make_unique<struct BOM_ENTRY>();
1316 entry->m_OEMDesignRef = it->second;
1320 Report( wxString::Format(
_(
"Component \"%s\" missing OEM reference; BOM entry will be skipped." ),
1321 fp->GetFPID().GetLibItemName().wx_str() ),
1325 entry->m_OEMDesignRef =
genString( entry->m_OEMDesignRef,
"REF" );
1327 entry->m_pads = fp->GetPadCount();
1331 const wxString variantName =
m_board ?
m_board->GetCurrentVariant() : wxString();
1333 if( entry->m_pads == 0 || fp_it->GetExcludedFromBOMForVariant( variantName ) )
1334 entry->m_type =
"DOCUMENT";
1336 entry->m_type =
"ELECTRICAL";
1341 if( descField && !descField->
GetShownText(
false ).IsEmpty() )
1342 entry->m_description = descField->
GetShownText(
false );
1344 auto[ bom_iter, inserted ] = bom_entries.insert( std::move( entry ) );
1347 ( *bom_iter )->m_count++;
1351 refdes.m_pkg = fp->GetFPID().GetLibItemName().wx_str();
1352 refdes.m_populate = !fp->GetDNPForVariant( variantName )
1353 && !fp->GetExcludedFromBOMForVariant( variantName );
1356 ( *bom_iter )->m_refdes->push_back( refdes );
1360 for(
PCB_FIELD* prop : fp->GetFields() )
1365 if( prop->IsMandatory() && !prop->IsValue() )
1368 ( *bom_iter )->m_props->emplace( prop->GetName(), prop->GetShownText(
false ) );
1372 if( bom_entries.empty() )
1375 wxFileName fn(
m_board->GetFileName() );
1377 wxXmlNode* bomNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"Bom" );
1378 m_xml_root->InsertChild( bomNode, aEcadNode );
1381 wxXmlNode* bomHeaderNode =
appendNode( bomNode,
"BomHeader" );
1385 wxXmlNode* stepRefNode =
appendNode( bomHeaderNode,
"StepRef" );
1388 for(
const auto& entry : bom_entries )
1390 wxXmlNode* bomEntryNode =
appendNode( bomNode,
"BomItem" );
1391 addAttribute( bomEntryNode,
"OEMDesignNumberRef", entry->m_OEMDesignRef );
1392 addAttribute( bomEntryNode,
"quantity", wxString::Format(
"%d", entry->m_count ) );
1393 addAttribute( bomEntryNode,
"pinCount", wxString::Format(
"%d", entry->m_pads ) );
1394 addAttribute( bomEntryNode,
"category", entry->m_type );
1396 if( !entry->m_description.IsEmpty() )
1397 addAttribute( bomEntryNode,
"description", entry->m_description );
1399 for(
const REFDES& refdes : *( entry->m_refdes ) )
1401 wxXmlNode* refdesNode =
appendNode( bomEntryNode,
"RefDes" );
1404 addAttribute( refdesNode,
"populate", refdes.m_populate ?
"true" :
"false" );
1405 addAttribute( refdesNode,
"layerRef", refdes.m_layer );
1408 wxXmlNode* characteristicsNode =
appendNode( bomEntryNode,
"Characteristics" );
1409 addAttribute( characteristicsNode,
"category", entry->m_type );
1411 for(
const auto& prop : *( entry->m_props ) )
1413 wxXmlNode* textualDefNode =
appendNode( characteristicsNode,
"Textual" );
1414 addAttribute( textualDefNode,
"definitionSource",
"KICAD" );
1415 addAttribute( textualDefNode,
"textualCharacteristicName", prop.first );
1416 addAttribute( textualDefNode,
"textualCharacteristicValue", prop.second );
1434 wxXmlNode* cadDataNode =
appendNode( ecadNode,
"CadData" );
1453 std::vector<BOARD_STACKUP_ITEM*> layers = stackup.
GetList();
1454 std::set<PCB_LAYER_ID> added_layers;
1456 for(
int i = 0; i < stackup.
GetCount(); i++ )
1460 for(
int sublayer_id = 0; sublayer_id < stackup_item->
GetSublayersCount(); sublayer_id++ )
1464 if( ly_name.IsEmpty() )
1473 if( sublayer_id > 0 )
1474 ly_name += wxString::Format(
"_%d", sublayer_id );
1478 ly_name =
genString( ly_name,
"SPEC_LAYER" );
1480 wxXmlNode* specNode =
appendNode( aCadLayerNode,
"Spec" );
1482 wxXmlNode* generalNode =
appendNode( specNode,
"General" );
1484 wxXmlNode* propertyNode =
appendNode( generalNode,
"Property" );
1486 switch ( stackup_item->
GetType() )
1491 wxXmlNode* conductorNode =
appendNode( specNode,
"Conductor" );
1493 propertyNode =
appendNode( conductorNode,
"Property" );
1494 addAttribute( propertyNode,
"unit", wxT(
"SIEMENS/M" ) );
1495 addAttribute( propertyNode,
"value", wxT(
"5.959E7" ) );
1501 propertyNode =
appendNode( generalNode,
"Property" );
1502 addAttribute( propertyNode,
"text", wxString::Format(
"Type : %s",
1504 wxXmlNode* dielectricNode =
appendNode( specNode,
"Dielectric" );
1505 addAttribute( dielectricNode,
"type",
"DIELECTRIC_CONSTANT" );
1506 propertyNode =
appendNode( dielectricNode,
"Property" );
1509 dielectricNode =
appendNode( specNode,
"Dielectric" );
1510 addAttribute( dielectricNode,
"type",
"LOSS_TANGENT" );
1511 propertyNode =
appendNode( dielectricNode,
"Property" );
1518 propertyNode =
appendNode( generalNode,
"Property" );
1519 addAttribute( propertyNode,
"text", wxString::Format(
"Color : %s",
1521 propertyNode =
appendNode( generalNode,
"Property" );
1522 addAttribute( propertyNode,
"text", wxString::Format(
"Type : %s",
1528 propertyNode =
appendNode( generalNode,
"Property" );
1529 addAttribute( propertyNode,
"text", wxString::Format(
"Color : %s",
1531 propertyNode =
appendNode( generalNode,
"Property" );
1532 addAttribute( propertyNode,
"text", wxString::Format(
"Type : %s",
1536 if( stackup_item->
GetEpsilonR( sublayer_id ) > 1.0 )
1538 wxXmlNode* dielectricNode =
appendNode( specNode,
"Dielectric" );
1539 addAttribute( dielectricNode,
"type",
"DIELECTRIC_CONSTANT" );
1540 propertyNode =
appendNode( dielectricNode,
"Property" );
1547 wxXmlNode* dielectricNode =
appendNode( specNode,
"Dielectric" );
1548 addAttribute( dielectricNode,
"type",
"LOSS_TANGENT" );
1549 propertyNode =
appendNode( dielectricNode,
"Property" );
1564 wxXmlNode* cadHeaderNode =
appendNode( aEcadNode,
"CadHeader" );
1608 addAttribute( aNode,
"layerFunction",
"BOARD_OUTLINE" );
1649 aLayer ==
F_Cu ?
"TOP"
1650 : aLayer ==
B_Cu ?
"BOTTOM"
1665 wxXmlNode* stackupNode =
appendNode( aCadLayerNode,
"Stackup" );
1666 addAttribute( stackupNode,
"name",
"Primary_Stackup" );
1673 addAttribute( stackupNode,
"stackupStatus",
"PROPOSED" );
1675 wxXmlNode* stackupGroup =
appendNode( stackupNode,
"StackupGroup" );
1676 addAttribute( stackupGroup,
"name",
"Primary_Stackup_Group" );
1681 std::vector<BOARD_STACKUP_ITEM*> layers = stackup.
GetList();
1682 std::set<PCB_LAYER_ID> added_layers;
1684 for(
int i = 0; i < stackup.
GetCount(); i++ )
1688 for(
int sublayer_id = 0; sublayer_id < stackup_item->
GetSublayersCount(); sublayer_id++ )
1691 wxXmlNode* stackupLayer =
appendNode( stackupGroup,
"StackupLayer" );
1694 if( ly_name.IsEmpty() )
1703 if( sublayer_id > 0 )
1704 ly_name += wxString::Format(
"_%d", sublayer_id );
1708 wxString spec_name =
genString( ly_name,
"SPEC_LAYER" );
1709 ly_name =
genString( ly_name,
"LAYER" );
1711 addAttribute( stackupLayer,
"layerOrGroupRef", ly_name );
1715 addAttribute( stackupLayer,
"sequence", wxString::Format(
"%d", i ) );
1717 wxXmlNode* specLayerNode =
appendNode( stackupLayer,
"SpecRef" );
1731 std::vector<BOARD_STACKUP_ITEM*> layers = stackup.
GetList();
1732 std::set<PCB_LAYER_ID> added_layers;
1734 for(
int i = 0; i < stackup.
GetCount(); i++ )
1741 for(
int sublayer_id = 0; sublayer_id < stackup_item->
GetSublayersCount(); sublayer_id++ )
1743 wxXmlNode* cadLayerNode =
appendNode( aCadLayerNode,
"Layer" );
1746 if( ly_name.IsEmpty() )
1756 if( sublayer_id > 0 )
1757 ly_name += wxString::Format(
"_%d", sublayer_id );
1761 ly_name =
genString( ly_name,
"LAYER" );
1768 addAttribute( cadLayerNode,
"layerFunction",
"DIELCORE" );
1770 addAttribute( cadLayerNode,
"layerFunction",
"DIELPREG" );
1785 LSEQ layer_seq =
m_board->GetEnabledLayers().Seq();
1794 added_layers.insert( layer );
1795 wxXmlNode* cadLayerNode =
appendNode( aCadLayerNode,
"Layer" );
1816 for(
PAD*
pad : fp->Pads() )
1818 if(
pad->HasDrilledHole() )
1820 else if(
pad->HasHole() )
1827 wxXmlNode* drillNode =
appendNode( aCadLayerNode,
"Layer" );
1828 drillNode->AddAttribute(
"name",
genLayersString( layers.first, layers.second,
"DRILL" ) );
1833 wxXmlNode* spanNode =
appendNode( drillNode,
"Span" );
1840 wxXmlNode* drillNode =
appendNode( aCadLayerNode,
"Layer" );
1841 drillNode->AddAttribute(
"name",
genLayersString( layers.first, layers.second,
"SLOT" ) );
1847 wxXmlNode* spanNode =
appendNode( drillNode,
"Span" );
1863 std::vector<std::tuple<auxLayerType, PCB_LAYER_ID, PCB_LAYER_ID>> new_layers;
1865 if(
via->Padstack().IsFilled().value_or(
false ) )
1868 if(
via->Padstack().IsCapped().value_or(
false ) )
1873 if(
via->Padstack().IsPlugged( layer ).value_or(
false ) )
1876 if(
via->Padstack().IsCovered( layer ).value_or(
false ) )
1879 if(
via->Padstack().IsTented( layer ).value_or(
false ) )
1883 for(
auto& tuple : new_layers )
1889 bool add_node =
true;
1892 wxString layerFunction;
1895 switch( std::get<0>(layers) )
1899 layerFunction =
"COATINGNONCOND";
1903 layerFunction =
"HOLEFILL";
1907 layerFunction =
"COATINGNONCOND";
1911 layerFunction =
"HOLEFILL";
1915 layerFunction =
"COATINGCOND";
1923 if( add_node && !vec.empty() )
1925 wxXmlNode* node =
appendNode( aCadLayerNode,
"LAYER" );
1939 const bool first_external = std::get<1>( layers ) ==
F_Cu || std::get<1>( layers ) ==
B_Cu;
1940 const bool second_external = std::get<2>( layers ) ==
F_Cu || std::get<2>( layers ) ==
B_Cu;
1942 if( first_external )
1944 if( second_external )
1951 if( second_external )
1957 wxXmlNode* spanNode =
appendNode( node,
"SPAN" );
1968 wxXmlNode* stepNode =
appendNode( aCadNode,
"Step" );
1969 wxFileName fn(
m_board->GetFileName() );
1975 wxXmlNode* datumNode =
appendNode( stepNode,
"Datum" );
1995 wxXmlNode* padNode =
appendNode( aContentNode,
"Pad" );
2002 wxXmlNode* xformNode =
appendNode( padNode,
"Xform" );
2009 addShape( padNode, *aPad, aLayer );
2013 wxXmlNode* pinRefNode =
appendNode( padNode,
"PinRef" );
2026 wxXmlNode* padNode =
appendNode( aContentNode,
"Pad" );
2047 addAttribute( aPadNode,
"padstackDefRef", th_pair->second );
2054 wxXmlNode* padStackDefNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"PadStackDef" );
2069 wxXmlNode* padStackHoleNode =
appendNode( padStackDefNode,
"PadstackHoleDef" );
2070 padStackHoleNode->AddAttribute(
"name",
2071 wxString::Format(
"%s%d_%d",
2089 if( !
m_board->IsLayerEnabled( layer ) )
2092 wxXmlNode* padStackPadDefNode =
appendNode( padStackDefNode,
"PadstackPadDef" );
2094 addAttribute( padStackPadDefNode,
"padUse",
"REGULAR" );
2102 addShape( padStackPadDefNode, shape );
2106 addShape( padStackPadDefNode, *aPad, layer );
2118 addAttribute( aContentNode,
"padstackDefRef", via_pair->second );
2125 wxXmlNode* padStackDefNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"PadStackDef" );
2131 wxXmlNode* padStackHoleNode =
appendNode( padStackDefNode,
"PadstackHoleDef" );
2134 addAttribute( padStackHoleNode,
"platingStatus",
"VIA" );
2143 bool drill ) ->
void
2148 shape.
SetEnd( {
KiROUND( aVia->GetDrillValue() / 2.0 ), 0 } );
2150 shape.
SetEnd( {
KiROUND( aVia->GetWidth( layer ) / 2.0 ), 0 } );
2152 wxXmlNode* padStackPadDefNode =
2153 appendNode( padStackDefNode,
"PadstackPadDef" );
2155 addAttribute( padStackPadDefNode,
"padUse",
"REGULAR" );
2158 addShape( padStackPadDefNode, shape );
2178 addPadShape( layer, aVia,
genLayerString( layer,
"PLUGGING" ),
true );
2181 addPadShape( layer, aVia,
genLayerString( layer,
"COVERING" ),
false );
2184 addPadShape( layer, aVia,
genLayerString( layer,
"TENTING" ),
false );
2199 if( secondary.
size.
x <= 0 && secondary.
size.
y <= 0 )
2210 if( !layerHasRef( secondary.
start ) || !layerHasRef( secondary.
end ) )
2231 wxXmlNode* backdrillNode =
appendNode( specNode,
"Backdrill" );
2232 addAttribute( backdrillNode,
"startLayerRef", startLayer->second );
2233 addAttribute( backdrillNode,
"mustNotCutLayerRef", endLayer->second );
2237 if( stubLength < 0 )
2252 addAttribute( backdrillNode,
"postMachining", isPostMachined ? wxT(
"true" )
2263 wxString primarySpec = createSpec( primary, wxString::Format( wxT(
"BD_%dA" ), specIndex ) );
2265 wxString secondarySpec = createSpec( secondary, wxString::Format( wxT(
"BD_%dB" ), specIndex ) );
2267 if( primarySpec.IsEmpty() && secondarySpec.IsEmpty() )
2282 auto addRef = [&](
const wxString& aSpecName )
2284 if( aSpecName.IsEmpty() )
2287 wxXmlNode* specRefNode =
appendNode( aHoleNode,
"SpecRef" );
2292 addRef( it->second.first );
2293 addRef( it->second.second );
2308 wxXmlNode* specNode = it->second;
2330 wxXmlNode* polygonNode =
nullptr;
2338 polygonNode =
appendNode( aParentNode,
"Polygon" );
2339 wxXmlNode* polybeginNode =
appendNode( polygonNode,
"PolyBegin" );
2341 const std::vector<VECTOR2I>& pts = aPolygon.
CPoints();
2342 addXY( polybeginNode, pts[0] );
2344 for(
size_t ii = 1; ii < pts.size(); ++ii )
2346 wxXmlNode* polyNode =
appendNode( polygonNode,
"PolyStepSegment" );
2347 addXY( polyNode, pts[ii] );
2350 wxXmlNode* polyendNode =
appendNode( polygonNode,
"PolyStepSegment" );
2351 addXY( polyendNode, pts[0] );
2362 addLineDesc( polygonNode, aWidth, aDashType,
true );
2366 wxCHECK( aWidth == 0,
false );
2379 for(
size_t ii = 1; ii < aPolygon.size(); ++ii )
2381 wxCHECK2( aPolygon[ii].PointCount() >= 3,
continue );
2383 wxXmlNode* cutoutNode =
appendNode( aParentNode,
"Cutout" );
2384 wxXmlNode* polybeginNode =
appendNode( cutoutNode,
"PolyBegin" );
2386 const std::vector<VECTOR2I>& hole = aPolygon[ii].CPoints();
2387 addXY( polybeginNode, hole[0] );
2389 for(
size_t jj = 1; jj < hole.size(); ++jj )
2391 wxXmlNode* polyNode =
appendNode( cutoutNode,
"PolyStepSegment" );
2392 addXY( polyNode, hole[jj] );
2395 wxXmlNode* polyendNode =
appendNode( cutoutNode,
"PolyStepSegment" );
2396 addXY( polyendNode, hole[0] );
2409 wxXmlNode* outlineNode =
appendNode( aParentNode,
"Outline" );
2429 outline = &bbox_outline;
2434 wxLogTrace(
traceIpc2581, wxS(
"Failed to add polygon to outline" ) );
2436 if( !outlineNode->GetChildren() )
2438 aParentNode->RemoveChild( outlineNode );
2455 wxXmlNode* contourNode =
appendNode( aParentNode,
"Contour" );
2465 aParentNode->RemoveChild( contourNode );
2478 if( !
m_board->GetBoardPolygonOutlines( board_outline,
false ) )
2484 wxXmlNode* profileNode =
appendNode( aStepNode,
"Profile" );
2488 wxLogTrace(
traceIpc2581, wxS(
"Failed to add polygon to profile" ) );
2489 aStepNode->RemoveChild( profileNode );
2512 std::unique_ptr<FOOTPRINT> fp(
static_cast<FOOTPRINT*
>( aFp->
Clone() ) );
2513 fp->SetParentGroup(
nullptr );
2514 fp->SetPosition( { 0, 0 } );
2515 fp->SetOrientation(
ANGLE_0 );
2517 if( fp->IsFlipped() )
2522 fp->GetFPID().GetLibItemName().wx_str(),
2526 addAttribute( aContentNode,
"packageRef", iter->second );
2533 wxXmlNode* packageNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"Package" );
2534 wxXmlNode* otherSideViewNode =
nullptr;
2540 if( fp->FindPadByNumber(
"1" ) )
2542 else if ( fp->FindPadByNumber(
"A1" ) )
2544 else if ( fp->FindPadByNumber(
"A" ) )
2546 else if ( fp->FindPadByNumber(
"a" ) )
2548 else if ( fp->FindPadByNumber(
"a1" ) )
2550 else if ( fp->FindPadByNumber(
"Anode" ) )
2552 else if ( fp->FindPadByNumber(
"ANODE" ) )
2557 addAttribute( packageNode,
"pinOneOrientation",
"OTHER" );
2569 otherSideViewNode =
appendNode( packageNode,
"OtherSideView" );
2581 wxXmlNode* pickupPointNode =
appendNode( packageNode,
"PickupPoint" );
2585 std::map<PCB_LAYER_ID, std::map<bool, std::vector<BOARD_ITEM*>>> elements;
2587 for(
BOARD_ITEM* item : fp->GraphicalItems() )
2612 elements[item->GetLayer()][is_abs].push_back( item );
2615 auto add_base_node =
2618 wxXmlNode* parent = packageNode;
2623 if( !otherSideViewNode )
2624 otherSideViewNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"OtherSideView" );
2626 parent = otherSideViewNode;
2632 name =
"SilkScreen";
2633 else if( aLayer ==
F_Fab || aLayer ==
B_Fab )
2634 name =
"AssemblyDrawing";
2642 auto add_marking_node =
2643 [&]( wxXmlNode* aNode ) -> wxXmlNode*
2645 wxXmlNode* marking_node =
appendNode( aNode,
"Marking" );
2647 return marking_node;
2650 std::map<PCB_LAYER_ID, wxXmlNode*> layer_nodes;
2651 std::map<PCB_LAYER_ID, BOX2I> layer_bbox;
2655 if( elements.find( layer ) != elements.end() )
2657 if( elements[layer][
true].size() > 0 )
2658 layer_bbox[layer] = elements[layer][
true][0]->GetBoundingBox();
2659 else if( elements[layer][
false].size() > 0 )
2660 layer_bbox[layer] = elements[layer][
false][0]->GetBoundingBox();
2664 for(
auto& [layer, map] : elements )
2666 wxXmlNode* layer_node = add_base_node( layer );
2667 wxXmlNode* marking_node = add_marking_node( layer_node );
2668 wxXmlNode* group_node =
appendNode( marking_node,
"UserSpecial" );
2669 bool update_bbox =
false;
2673 layer_nodes[layer] = layer_node;
2677 for(
auto& [is_abs, vec] : map )
2681 wxXmlNode* output_node =
nullptr;
2684 layer_bbox[layer].Merge( item->GetBoundingBox() );
2687 output_node = add_marking_node( layer_node );
2689 output_node = group_node;
2691 switch( item->Type() )
2697 if(
text->IsKnockout() )
2711 if(
text->IsBorderEnabled() )
2714 text->GetEffectiveShape()->TransformToPolygon( poly_set, 0,
ERROR_INSIDE );
2716 text->GetBorderWidth() );
2737 if( group_node->GetChildren() ==
nullptr )
2739 marking_node->RemoveChild( group_node );
2740 layer_node->RemoveChild( marking_node );
2742 delete marking_node;
2746 for(
auto&[layer, bbox] : layer_bbox )
2748 if( bbox.GetWidth() > 0 )
2750 wxXmlNode* outlineNode =
insertNode( layer_nodes[layer],
"Outline" );
2753 std::vector<VECTOR2I> points( 4 );
2754 points[0] = bbox.GetPosition();
2755 points[2] = bbox.GetEnd();
2756 points[1].x = points[0].x;
2757 points[1].y = points[2].y;
2758 points[3].x = points[2].x;
2759 points[3].y = points[0].y;
2761 outline.
Append( points );
2767 std::map<wxString, wxXmlNode*> pin_nodes;
2769 for(
size_t ii = 0; ii < fp->Pads().size(); ++ii )
2771 PAD*
pad = fp->Pads()[ii];
2773 wxXmlNode* pinNode =
nullptr;
2775 auto [ it, inserted ] = pin_nodes.emplace(
name,
nullptr );
2780 it->second = pinNode;
2788 addAttribute( pinNode,
"electricalType",
"MECHANICAL" );
2789 else if(
pad->IsOnCopperLayer() )
2790 addAttribute( pinNode,
"electricalType",
"ELECTRICAL" );
2792 addAttribute( pinNode,
"electricalType",
"UNDEFINED" );
2794 if(
pad->HasHole() )
2799 if(
pad->GetFPRelativeOrientation() !=
ANGLE_0 )
2801 wxXmlNode* xformNode =
appendNode( pinNode,
"Xform" );
2802 EDA_ANGLE pad_angle =
pad->GetFPRelativeOrientation().Normalize();
2804 if( fp->IsFlipped() )
2813 pinNode = it->second;
2831 std::vector<wxXmlNode*> componentNodes;
2832 std::vector<wxXmlNode*> packageNodes;
2833 std::set<wxString> packageNames;
2835 bool generate_unique =
m_OEMRef.empty();
2839 wxXmlNode* componentNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"Component" );
2841 wxXmlNode* pkg =
addPackage( componentNode, fp );
2844 packageNodes.push_back( pkg );
2850 if( !generate_unique )
2853 if( field && !field->
GetText().empty() )
2859 name = wxString::Format(
"%s_%s_%s", fp->GetFPID().GetFullLibraryName(),
2860 fp->GetFPID().GetLibItemName().wx_str(),
2865 Report(
_(
"Duplicate footprint pointers encountered; IPC-2581 output may be incorrect." ),
2873 else if( fp->GetAttributes() &
FP_SMD )
2878 if( fp->GetOrientation() !=
ANGLE_0 || fp->IsFlipped() )
2880 wxXmlNode* xformNode =
appendNode( componentNode,
"Xform" );
2884 if( fp->IsFlipped() )
2890 if( fp->IsFlipped() )
2894 addLocationNode( componentNode, fp->GetPosition().x, fp->GetPosition().y );
2896 componentNodes.push_back( componentNode );
2905 for( wxXmlNode* pkg : packageNodes )
2906 aStepNode->AddChild( pkg );
2908 for( wxXmlNode* cmp : componentNodes )
2909 aStepNode->AddChild( cmp );
2917 wxXmlNode* netNode =
appendNode( aStepNode,
"LogicalNet" );
2919 genString(
m_board->GetNetInfo().GetNetItem( net )->GetNetname(),
"NET" ) ) ;
2921 for(
auto& [cmp,
pin] : pin_pair )
2923 wxXmlNode* netPinNode =
appendNode( netNode,
"PinRef" );
2937 std::vector<std::unique_ptr<FOOTPRINT>> footprints;
2941 std::map<PCB_LAYER_ID, std::map<int, std::vector<BOARD_ITEM*>>> elements;
2943 std::for_each(
m_board->Tracks().begin(),
m_board->Tracks().end(),
2944 [&layers, &elements](
PCB_TRACK* aTrack )
2946 if( aTrack->Type() == PCB_VIA_T )
2948 PCB_VIA* via = static_cast<PCB_VIA*>( aTrack );
2950 for( PCB_LAYER_ID layer : layers )
2952 if( via->FlashLayer( layer ) )
2953 elements[layer][via->GetNetCode()].push_back( via );
2958 elements[aTrack->GetLayer()][aTrack->GetNetCode()].push_back( aTrack );
2962 std::for_each( m_board->Zones().begin(), m_board->Zones().end(),
2963 [ &elements ](
ZONE* zone )
2965 LSEQ zone_layers = zone->GetLayerSet().Seq();
2967 for( PCB_LAYER_ID layer : zone_layers )
2968 elements[layer][zone->GetNetCode()].push_back( zone );
2971 for(
BOARD_ITEM* item : m_board->Drawings() )
2974 elements[conn_it->GetLayer()][conn_it->GetNetCode()].push_back( conn_it );
2976 elements[item->GetLayer()][0].push_back( item );
2979 for(
FOOTPRINT* fp : m_board->Footprints() )
2981 for(
PCB_FIELD* field : fp->GetFields() )
2982 elements[field->GetLayer()][0].push_back( field );
2984 for(
BOARD_ITEM* item : fp->GraphicalItems() )
2985 elements[item->GetLayer()][0].push_back( item );
2987 for(
PAD*
pad : fp->Pads() )
2989 LSEQ pad_layers =
pad->GetLayerSet().Seq();
2993 if(
pad->FlashLayer( layer ) )
2994 elements[layer][
pad->GetNetCode()].push_back(
pad );
3001 if( m_progressReporter )
3002 m_progressReporter->SetMaxProgress( nets.GetNetCount() * layers.size() );
3004 wxXmlNode* layerNode = appendNode( aStepNode,
"LayerFeature" );
3005 addAttribute( layerNode,
"layerRef", m_layer_name_map[layer] );
3007 auto process_net = [&] (
int net )
3009 std::vector<BOARD_ITEM*>& vec = elements[layer][net];
3014 std::stable_sort( vec.begin(), vec.end(),
3017 if( a->GetParentFootprint() == b->GetParentFootprint() )
3018 return a->Type() < b->Type();
3020 return a->GetParentFootprint() < b->GetParentFootprint();
3023 generateLayerSetNet( layerNode, layer, vec );
3028 if( m_progressReporter )
3030 m_progressReporter->Report( wxString::Format(
_(
"Exporting Layer %s, Net %s" ),
3031 m_board->GetLayerName( layer ),
3032 net->GetNetname() ) );
3033 m_progressReporter->AdvanceProgress();
3036 process_net( net->GetNetCode() );
3039 if( layerNode->GetChildren() ==
nullptr )
3041 aStepNode->RemoveChild( layerNode );
3054 wxXmlNode* layerNode =
appendNode( aLayerNode,
"LayerFeature" );
3055 layerNode->AddAttribute(
"layerRef",
genLayersString( layers.first, layers.second,
"DRILL" ) );
3066 Report(
_(
"Via uses unsupported padstack; omitted from drill data." ),
3071 wxXmlNode* padNode =
appendNode( layerNode,
"Set" );
3074 if(
via->GetNetCode() > 0 )
3077 wxXmlNode* holeNode =
appendNode( padNode,
"Hole" );
3078 addAttribute( holeNode,
"name", wxString::Format(
"H%d", hole_count++ ) );
3083 addXY( holeNode,
via->GetPosition() );
3093 Report(
_(
"Pad uses unsupported padstack; hole was omitted from drill data." ),
3098 wxXmlNode* padNode =
appendNode( layerNode,
"Set" );
3101 if(
pad->GetNetCode() > 0 )
3104 wxXmlNode* holeNode =
appendNode( padNode,
"Hole" );
3105 addAttribute( holeNode,
"name", wxString::Format(
"H%d", hole_count++ ) );
3111 addXY( holeNode,
pad->GetPosition() );
3121 wxXmlNode* layerNode =
appendNode( aLayerNode,
"LayerFeature" );
3122 layerNode->AddAttribute(
"layerRef",
genLayersString( layers.first, layers.second,
"SLOT" ) );
3126 wxXmlNode* padNode =
appendNode( layerNode,
"Set" );
3128 if(
pad->GetNetCode() > 0 )
3131 addSlotCavity( padNode, *
pad, wxString::Format(
"SLOT%d", hole_count++ ) );
3138 std::vector<BOARD_ITEM*>& aItems )
3140 auto it = aItems.begin();
3141 wxXmlNode* layerSetNode =
appendNode( aLayerNode,
"Set" );
3142 wxXmlNode* featureSetNode =
appendNode( layerSetNode,
"Features" );
3143 wxXmlNode* specialNode =
appendNode( featureSetNode,
"UserSpecial" );
3145 bool has_via =
false;
3146 bool has_pad =
false;
3148 wxXmlNode* padSetNode =
nullptr;
3150 wxXmlNode* viaSetNode =
nullptr;
3152 wxXmlNode* teardropLayerSetNode =
nullptr;
3153 wxXmlNode* teardropFeatureSetNode =
nullptr;
3155 bool teardrop_warning =
false;
3160 if( item->GetNetCode() > 0 )
3170 shape.
SetStart( track->GetStart() );
3171 shape.
SetEnd( track->GetEnd() );
3172 shape.
SetWidth( track->GetWidth() );
3189 viaSetNode = layerSetNode;
3194 viaSetNode =
appendNode( layerSetNode,
"Set" );
3196 if( track->GetNetCode() > 0 )
3203 addVia( viaSetNode,
static_cast<PCB_VIA*
>( track ), aLayer );
3210 wxXmlNode* zoneFeatureNode = specialNode;
3212 if( zone->IsTeardropArea() )
3216 if( !teardropFeatureSetNode )
3218 teardropLayerSetNode =
appendNode( aLayerNode,
"Set" );
3219 addAttribute( teardropLayerSetNode,
"geometryUsage",
"TEARDROP" );
3221 if( zone->GetNetCode() > 0 )
3224 genString( zone->GetNetname(),
"NET" ) );
3227 wxXmlNode* new_teardrops =
appendNode( teardropLayerSetNode,
"Features" );
3229 teardropFeatureSetNode =
appendNode( new_teardrops,
"UserSpecial" );
3232 zoneFeatureNode = teardropFeatureSetNode;
3234 else if( !teardrop_warning )
3236 Report(
_(
"Teardrops are not supported in IPC-2581 revision B; they were exported as zones." ),
3238 teardrop_warning =
true;
3245 wxXmlNode* tempSetNode =
appendNode( aLayerNode,
"Set" );
3246 wxString refDes =
componentName( zone->GetParentFootprint() );
3248 wxXmlNode* newFeatures =
appendNode( tempSetNode,
"Features" );
3250 zoneFeatureNode =
appendNode( newFeatures,
"UserSpecial" );
3254 SHAPE_POLY_SET& zone_shape = *zone->GetFilledPolysList( aLayer );
3256 for(
int ii = 0; ii < zone_shape.
OutlineCount(); ++ii )
3267 wxXmlNode* tempSetNode =
appendNode( aLayerNode,
"Set" );
3270 addAttribute( tempSetNode,
"geometryUsage",
"GRAPHIC" );
3272 bool link_to_component =
true;
3275 link_to_component =
false;
3277 if( link_to_component )
3280 wxXmlNode* tempFeature =
appendNode( tempSetNode,
"Features" );
3287 wxXmlNode* xformNode =
appendNode( tempFeature,
"Xform" );
3297 wxXmlNode* tempSetNode =
appendNode( aLayerNode,
"Set" );
3299 if( shape->GetNetCode() > 0 )
3302 wxXmlNode* tempFeature =
appendNode( tempSetNode,
"Features" );
3319 text_item =
static_cast<EDA_TEXT*
>( tmp_text );
3321 text_item =
static_cast<EDA_TEXT*
>( tmp_text );
3326 wxXmlNode* tempSetNode =
appendNode( aLayerNode,
"Set" );
3331 bool link_to_component = fp !=
nullptr;
3334 link_to_component =
false;
3336 if( link_to_component )
3339 wxXmlNode* nonStandardAttributeNode =
appendNode( tempSetNode,
"NonstandardAttribute" );
3340 addAttribute( nonStandardAttributeNode,
"name",
"TEXT" );
3342 addAttribute( nonStandardAttributeNode,
"type",
"STRING" );
3344 wxXmlNode* tempFeature =
appendNode( tempSetNode,
"Features" );
3350 addText( tempFeature, text_item,
text->GetFontMetrics() );
3368 padSetNode = layerSetNode;
3373 padSetNode =
appendNode( aLayerNode,
"Set" );
3375 if(
pad->GetNetCode() > 0 )
3390 switch( item->Type() )
3395 add_track(
static_cast<PCB_TRACK*
>( item ) );
3403 add_pad(
static_cast<PAD*
>( item ) );
3407 add_shape(
static_cast<PCB_SHAPE*
>( item ) );
3432 if( specialNode->GetChildren() ==
nullptr )
3434 featureSetNode->RemoveChild( specialNode );
3438 if( featureSetNode->GetChildren() ==
nullptr )
3440 layerSetNode->RemoveChild( featureSetNode );
3441 delete featureSetNode;
3444 if( layerSetNode->GetChildren() ==
nullptr )
3446 aLayerNode->RemoveChild( layerSetNode );
3447 delete layerSetNode;
3458 bool add_node =
true;
3464 switch( std::get<0>(layers) )
3493 wxXmlNode* layerNode =
appendNode( aStepNode,
"LayerFeature" );
3497 layerNode->AddAttribute(
"layerRef",
genLayersString( std::get<1>( layers ),
3511 shape.
SetEnd( {
KiROUND(
via->GetWidth( std::get<1>( layers ) ) / 2.0 ), 0 } );
3513 wxXmlNode* padNode =
appendNode( layerNode,
"Pad" );
3532 wxXmlNode* header =
appendNode( avl,
"AvlHeader" );
3536 addAttribute( header,
"datetime", wxDateTime::Now().FormatISOCombined() );
3539 std::set<wxString> unique_parts;
3540 std::map<wxString,wxString> unique_vendors;
3544 auto [ it, success ] = unique_parts.insert(
name );
3549 wxXmlNode* part =
appendNode( avl,
"AvlItem" );
3556 for (
int ii = 0; ii < 2; ++ii )
3562 if( mpn_name.empty() )
3565 wxXmlNode* vmpn =
appendNode( part,
"AvlVmpn" );
3569 wxXmlNode* mpn =
appendNode( vmpn,
"AvlMpn" );
3572 wxXmlNode* vendor =
appendNode( vmpn,
"AvlVendor" );
3574 wxString
name = wxT(
"UNKNOWN" );
3577 if( !ii && company[ii] )
3585 else if( !ii && !company_name[ii].
empty() )
3587 name = company_name[ii];
3589 else if( ii && !
m_dist.empty() )
3594 auto [vendor_id, inserted] = unique_vendors.emplace(
3596 wxString::Format(
"VENDOR_%zu", unique_vendors.size() ) );
3598 addAttribute( vendor,
"enterpriseRef", vendor_id->second );
3602 wxXmlNode* new_vendor =
new wxXmlNode( wxXML_ELEMENT_NODE,
"Enterprise" );
3618 const std::map<std::string, UTF8>* aProperties )
3631 if(
auto it = aProperties->find(
"units" ); it != aProperties->end() )
3633 if( it->second ==
"inch" )
3640 if(
auto it = aProperties->find(
"sigfig" ); it != aProperties->end() )
3641 m_sigfig = std::stoi( it->second );
3643 if(
auto it = aProperties->find(
"version" ); it != aProperties->end() )
3646 if(
auto it = aProperties->find(
"OEMRef" ); it != aProperties->end() )
3649 if(
auto it = aProperties->find(
"mpn" ); it != aProperties->end() )
3650 m_mpn = it->second.wx_str();
3652 if(
auto it = aProperties->find(
"mfg" ); it != aProperties->end() )
3653 m_mfg = it->second.wx_str();
3655 if(
auto it = aProperties->find(
"dist" ); it != aProperties->end() )
3656 m_dist = it->second.wx_str();
3658 if(
auto it = aProperties->find(
"distpn" ); it != aProperties->end() )
3663 for(
char c =
'a'; c <=
'z'; ++c )
3666 for(
char c =
'A'; c <=
'Z'; ++c )
3669 for(
char c =
'0'; c <=
'9'; ++c )
3673 std::string specialChars =
"_\\-.+><";
3675 for(
char c : specialChars )
3704 double written_bytes = 0.0;
3705 double last_yield = 0.0;
3712 auto update_progress = [&](
size_t aBytes )
3714 written_bytes += aBytes;
3715 double percent = written_bytes /
static_cast<double>(
m_total_bytes );
3720 if( last_yield + 0.01 < percent )
3722 last_yield = percent;
3736 size_t size = out_stream.GetSize();
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.
Information pertinent to a Pcbnew printed circuit board.
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
constexpr coord_type GetLeft() const
constexpr coord_type GetRight() const
constexpr coord_type GetTop() const
constexpr coord_type GetBottom() 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.
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.
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
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)
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)
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.
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...
std::map< wxString, std::pair< wxString, wxString > > m_padstack_backdrill_specs
wxXmlNode * generateBOMSection(wxXmlNode *aEcadNode)
Creates the BOM section.
wxXmlNode * generateContentStackup(wxXmlNode *aContentNode)
void addShape(wxXmlNode *aContentNode, const PCB_SHAPE &aShape)
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_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
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
Represent a set of closed polygons.
void Fracture()
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
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)
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.
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.
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 bool isOppositeSideSilk(const FOOTPRINT *aFootprint, PCB_LAYER_ID aLayer)
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).
VECTOR2I size
Drill diameter (x == y) or slot dimensions (x != y)
std::optional< PAD_DRILL_POST_MACHINING_MODE > mode
@ DESCRIPTION
Field Description of part, i.e. "1/4W 1% Metal Film Resistor".
@ 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