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();
1332 entry->m_type =
"DOCUMENT";
1334 entry->m_type =
"ELECTRICAL";
1339 if( descField && !descField->
GetText().IsEmpty() )
1340 entry->m_description = descField->
GetText();
1342 auto[ bom_iter, inserted ] = bom_entries.insert( std::move( entry ) );
1345 ( *bom_iter )->m_count++;
1349 refdes.m_pkg = fp->GetFPID().GetLibItemName().wx_str();
1353 ( *bom_iter )->m_refdes->push_back( refdes );
1357 for(
PCB_FIELD* prop : fp->GetFields() )
1362 if( prop->IsMandatory() && !prop->IsValue() )
1365 ( *bom_iter )->m_props->emplace( prop->GetName(), prop->GetText() );
1369 if( bom_entries.empty() )
1372 wxFileName fn(
m_board->GetFileName() );
1374 wxXmlNode* bomNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"Bom" );
1375 m_xml_root->InsertChild( bomNode, aEcadNode );
1378 wxXmlNode* bomHeaderNode =
appendNode( bomNode,
"BomHeader" );
1382 wxXmlNode* stepRefNode =
appendNode( bomHeaderNode,
"StepRef" );
1385 for(
const auto& entry : bom_entries )
1387 wxXmlNode* bomEntryNode =
appendNode( bomNode,
"BomItem" );
1388 addAttribute( bomEntryNode,
"OEMDesignNumberRef", entry->m_OEMDesignRef );
1389 addAttribute( bomEntryNode,
"quantity", wxString::Format(
"%d", entry->m_count ) );
1390 addAttribute( bomEntryNode,
"pinCount", wxString::Format(
"%d", entry->m_pads ) );
1391 addAttribute( bomEntryNode,
"category", entry->m_type );
1393 if( !entry->m_description.IsEmpty() )
1394 addAttribute( bomEntryNode,
"description", entry->m_description );
1396 for(
const REFDES& refdes : *( entry->m_refdes ) )
1398 wxXmlNode* refdesNode =
appendNode( bomEntryNode,
"RefDes" );
1401 addAttribute( refdesNode,
"populate", refdes.m_populate ?
"true" :
"false" );
1402 addAttribute( refdesNode,
"layerRef", refdes.m_layer );
1405 wxXmlNode* characteristicsNode =
appendNode( bomEntryNode,
"Characteristics" );
1406 addAttribute( characteristicsNode,
"category", entry->m_type );
1408 for(
const auto& prop : *( entry->m_props ) )
1410 wxXmlNode* textualDefNode =
appendNode( characteristicsNode,
"Textual" );
1411 addAttribute( textualDefNode,
"definitionSource",
"KICAD" );
1412 addAttribute( textualDefNode,
"textualCharacteristicName", prop.first );
1413 addAttribute( textualDefNode,
"textualCharacteristicValue", prop.second );
1431 wxXmlNode* cadDataNode =
appendNode( ecadNode,
"CadData" );
1450 std::vector<BOARD_STACKUP_ITEM*> layers = stackup.
GetList();
1451 std::set<PCB_LAYER_ID> added_layers;
1453 for(
int i = 0; i < stackup.
GetCount(); i++ )
1457 for(
int sublayer_id = 0; sublayer_id < stackup_item->
GetSublayersCount(); sublayer_id++ )
1461 if( ly_name.IsEmpty() )
1470 if( sublayer_id > 0 )
1471 ly_name += wxString::Format(
"_%d", sublayer_id );
1475 ly_name =
genString( ly_name,
"SPEC_LAYER" );
1477 wxXmlNode* specNode =
appendNode( aCadLayerNode,
"Spec" );
1479 wxXmlNode* generalNode =
appendNode( specNode,
"General" );
1481 wxXmlNode* propertyNode =
appendNode( generalNode,
"Property" );
1483 switch ( stackup_item->
GetType() )
1488 wxXmlNode* conductorNode =
appendNode( specNode,
"Conductor" );
1490 propertyNode =
appendNode( conductorNode,
"Property" );
1491 addAttribute( propertyNode,
"unit", wxT(
"SIEMENS/M" ) );
1492 addAttribute( propertyNode,
"value", wxT(
"5.959E7" ) );
1498 propertyNode =
appendNode( generalNode,
"Property" );
1499 addAttribute( propertyNode,
"text", wxString::Format(
"Type : %s",
1501 wxXmlNode* dielectricNode =
appendNode( specNode,
"Dielectric" );
1502 addAttribute( dielectricNode,
"type",
"DIELECTRIC_CONSTANT" );
1503 propertyNode =
appendNode( dielectricNode,
"Property" );
1506 dielectricNode =
appendNode( specNode,
"Dielectric" );
1507 addAttribute( dielectricNode,
"type",
"LOSS_TANGENT" );
1508 propertyNode =
appendNode( dielectricNode,
"Property" );
1515 propertyNode =
appendNode( generalNode,
"Property" );
1516 addAttribute( propertyNode,
"text", wxString::Format(
"Color : %s",
1518 propertyNode =
appendNode( generalNode,
"Property" );
1519 addAttribute( propertyNode,
"text", wxString::Format(
"Type : %s",
1525 propertyNode =
appendNode( generalNode,
"Property" );
1526 addAttribute( propertyNode,
"text", wxString::Format(
"Color : %s",
1528 propertyNode =
appendNode( generalNode,
"Property" );
1529 addAttribute( propertyNode,
"text", wxString::Format(
"Type : %s",
1533 if( stackup_item->
GetEpsilonR( sublayer_id ) > 1.0 )
1535 wxXmlNode* dielectricNode =
appendNode( specNode,
"Dielectric" );
1536 addAttribute( dielectricNode,
"type",
"DIELECTRIC_CONSTANT" );
1537 propertyNode =
appendNode( dielectricNode,
"Property" );
1544 wxXmlNode* dielectricNode =
appendNode( specNode,
"Dielectric" );
1545 addAttribute( dielectricNode,
"type",
"LOSS_TANGENT" );
1546 propertyNode =
appendNode( dielectricNode,
"Property" );
1561 wxXmlNode* cadHeaderNode =
appendNode( aEcadNode,
"CadHeader" );
1605 addAttribute( aNode,
"layerFunction",
"BOARD_OUTLINE" );
1646 aLayer ==
F_Cu ?
"TOP"
1647 : aLayer ==
B_Cu ?
"BOTTOM"
1662 wxXmlNode* stackupNode =
appendNode( aCadLayerNode,
"Stackup" );
1663 addAttribute( stackupNode,
"name",
"Primary_Stackup" );
1670 addAttribute( stackupNode,
"stackupStatus",
"PROPOSED" );
1672 wxXmlNode* stackupGroup =
appendNode( stackupNode,
"StackupGroup" );
1673 addAttribute( stackupGroup,
"name",
"Primary_Stackup_Group" );
1678 std::vector<BOARD_STACKUP_ITEM*> layers = stackup.
GetList();
1679 std::set<PCB_LAYER_ID> added_layers;
1681 for(
int i = 0; i < stackup.
GetCount(); i++ )
1685 for(
int sublayer_id = 0; sublayer_id < stackup_item->
GetSublayersCount(); sublayer_id++ )
1688 wxXmlNode* stackupLayer =
appendNode( stackupGroup,
"StackupLayer" );
1691 if( ly_name.IsEmpty() )
1700 if( sublayer_id > 0 )
1701 ly_name += wxString::Format(
"_%d", sublayer_id );
1705 wxString spec_name =
genString( ly_name,
"SPEC_LAYER" );
1706 ly_name =
genString( ly_name,
"LAYER" );
1708 addAttribute( stackupLayer,
"layerOrGroupRef", ly_name );
1712 addAttribute( stackupLayer,
"sequence", wxString::Format(
"%d", i ) );
1714 wxXmlNode* specLayerNode =
appendNode( stackupLayer,
"SpecRef" );
1728 std::vector<BOARD_STACKUP_ITEM*> layers = stackup.
GetList();
1729 std::set<PCB_LAYER_ID> added_layers;
1731 for(
int i = 0; i < stackup.
GetCount(); i++ )
1738 for(
int sublayer_id = 0; sublayer_id < stackup_item->
GetSublayersCount(); sublayer_id++ )
1740 wxXmlNode* cadLayerNode =
appendNode( aCadLayerNode,
"Layer" );
1743 if( ly_name.IsEmpty() )
1753 if( sublayer_id > 0 )
1754 ly_name += wxString::Format(
"_%d", sublayer_id );
1758 ly_name =
genString( ly_name,
"LAYER" );
1765 addAttribute( cadLayerNode,
"layerFunction",
"DIELCORE" );
1767 addAttribute( cadLayerNode,
"layerFunction",
"DIELPREG" );
1782 LSEQ layer_seq =
m_board->GetEnabledLayers().Seq();
1791 added_layers.insert( layer );
1792 wxXmlNode* cadLayerNode =
appendNode( aCadLayerNode,
"Layer" );
1813 for(
PAD*
pad : fp->Pads() )
1815 if(
pad->HasDrilledHole() )
1817 else if(
pad->HasHole() )
1824 wxXmlNode* drillNode =
appendNode( aCadLayerNode,
"Layer" );
1825 drillNode->AddAttribute(
"name",
genLayersString( layers.first, layers.second,
"DRILL" ) );
1830 wxXmlNode* spanNode =
appendNode( drillNode,
"Span" );
1837 wxXmlNode* drillNode =
appendNode( aCadLayerNode,
"Layer" );
1838 drillNode->AddAttribute(
"name",
genLayersString( layers.first, layers.second,
"SLOT" ) );
1844 wxXmlNode* spanNode =
appendNode( drillNode,
"Span" );
1860 std::vector<std::tuple<auxLayerType, PCB_LAYER_ID, PCB_LAYER_ID>> new_layers;
1862 if(
via->Padstack().IsFilled().value_or(
false ) )
1865 if(
via->Padstack().IsCapped().value_or(
false ) )
1870 if(
via->Padstack().IsPlugged( layer ).value_or(
false ) )
1873 if(
via->Padstack().IsCovered( layer ).value_or(
false ) )
1876 if(
via->Padstack().IsTented( layer ).value_or(
false ) )
1880 for(
auto& tuple : new_layers )
1886 bool add_node =
true;
1889 wxString layerFunction;
1892 switch( std::get<0>(layers) )
1896 layerFunction =
"COATINGNONCOND";
1900 layerFunction =
"HOLEFILL";
1904 layerFunction =
"COATINGNONCOND";
1908 layerFunction =
"HOLEFILL";
1912 layerFunction =
"COATINGCOND";
1920 if( add_node && !vec.empty() )
1922 wxXmlNode* node =
appendNode( aCadLayerNode,
"LAYER" );
1936 const bool first_external = std::get<1>( layers ) ==
F_Cu || std::get<1>( layers ) ==
B_Cu;
1937 const bool second_external = std::get<2>( layers ) ==
F_Cu || std::get<2>( layers ) ==
B_Cu;
1939 if( first_external )
1941 if( second_external )
1948 if( second_external )
1954 wxXmlNode* spanNode =
appendNode( node,
"SPAN" );
1965 wxXmlNode* stepNode =
appendNode( aCadNode,
"Step" );
1966 wxFileName fn(
m_board->GetFileName() );
1972 wxXmlNode* datumNode =
appendNode( stepNode,
"Datum" );
1992 wxXmlNode* padNode =
appendNode( aContentNode,
"Pad" );
1999 wxXmlNode* xformNode =
appendNode( padNode,
"Xform" );
2006 addShape( padNode, *aPad, aLayer );
2010 wxXmlNode* pinRefNode =
appendNode( padNode,
"PinRef" );
2023 wxXmlNode* padNode =
appendNode( aContentNode,
"Pad" );
2044 addAttribute( aPadNode,
"padstackDefRef", th_pair->second );
2051 wxXmlNode* padStackDefNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"PadStackDef" );
2066 wxXmlNode* padStackHoleNode =
appendNode( padStackDefNode,
"PadstackHoleDef" );
2067 padStackHoleNode->AddAttribute(
"name",
2068 wxString::Format(
"%s%d_%d",
2086 if( !
m_board->IsLayerEnabled( layer ) )
2089 wxXmlNode* padStackPadDefNode =
appendNode( padStackDefNode,
"PadstackPadDef" );
2091 addAttribute( padStackPadDefNode,
"padUse",
"REGULAR" );
2099 addShape( padStackPadDefNode, shape );
2103 addShape( padStackPadDefNode, *aPad, layer );
2115 addAttribute( aContentNode,
"padstackDefRef", via_pair->second );
2122 wxXmlNode* padStackDefNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"PadStackDef" );
2128 wxXmlNode* padStackHoleNode =
appendNode( padStackDefNode,
"PadstackHoleDef" );
2131 addAttribute( padStackHoleNode,
"platingStatus",
"VIA" );
2140 bool drill ) ->
void
2145 shape.
SetEnd( {
KiROUND( aVia->GetDrillValue() / 2.0 ), 0 } );
2147 shape.
SetEnd( {
KiROUND( aVia->GetWidth( layer ) / 2.0 ), 0 } );
2149 wxXmlNode* padStackPadDefNode =
2150 appendNode( padStackDefNode,
"PadstackPadDef" );
2152 addAttribute( padStackPadDefNode,
"padUse",
"REGULAR" );
2155 addShape( padStackPadDefNode, shape );
2175 addPadShape( layer, aVia,
genLayerString( layer,
"PLUGGING" ),
true );
2178 addPadShape( layer, aVia,
genLayerString( layer,
"COVERING" ),
false );
2181 addPadShape( layer, aVia,
genLayerString( layer,
"TENTING" ),
false );
2196 if( secondary.
size.
x <= 0 && secondary.
size.
y <= 0 )
2207 if( !layerHasRef( secondary.
start ) || !layerHasRef( secondary.
end ) )
2228 wxXmlNode* backdrillNode =
appendNode( specNode,
"Backdrill" );
2229 addAttribute( backdrillNode,
"startLayerRef", startLayer->second );
2230 addAttribute( backdrillNode,
"mustNotCutLayerRef", endLayer->second );
2234 if( stubLength < 0 )
2249 addAttribute( backdrillNode,
"postMachining", isPostMachined ? wxT(
"true" )
2260 wxString primarySpec = createSpec( primary, wxString::Format( wxT(
"BD_%dA" ), specIndex ) );
2262 wxString secondarySpec = createSpec( secondary, wxString::Format( wxT(
"BD_%dB" ), specIndex ) );
2264 if( primarySpec.IsEmpty() && secondarySpec.IsEmpty() )
2279 auto addRef = [&](
const wxString& aSpecName )
2281 if( aSpecName.IsEmpty() )
2284 wxXmlNode* specRefNode =
appendNode( aHoleNode,
"SpecRef" );
2289 addRef( it->second.first );
2290 addRef( it->second.second );
2305 wxXmlNode* specNode = it->second;
2327 wxXmlNode* polygonNode =
nullptr;
2335 polygonNode =
appendNode( aParentNode,
"Polygon" );
2336 wxXmlNode* polybeginNode =
appendNode( polygonNode,
"PolyBegin" );
2338 const std::vector<VECTOR2I>& pts = aPolygon.
CPoints();
2339 addXY( polybeginNode, pts[0] );
2341 for(
size_t ii = 1; ii < pts.size(); ++ii )
2343 wxXmlNode* polyNode =
appendNode( polygonNode,
"PolyStepSegment" );
2344 addXY( polyNode, pts[ii] );
2347 wxXmlNode* polyendNode =
appendNode( polygonNode,
"PolyStepSegment" );
2348 addXY( polyendNode, pts[0] );
2359 addLineDesc( polygonNode, aWidth, aDashType,
true );
2363 wxCHECK( aWidth == 0,
false );
2376 for(
size_t ii = 1; ii < aPolygon.size(); ++ii )
2378 wxCHECK2( aPolygon[ii].PointCount() >= 3,
continue );
2380 wxXmlNode* cutoutNode =
appendNode( aParentNode,
"Cutout" );
2381 wxXmlNode* polybeginNode =
appendNode( cutoutNode,
"PolyBegin" );
2383 const std::vector<VECTOR2I>& hole = aPolygon[ii].CPoints();
2384 addXY( polybeginNode, hole[0] );
2386 for(
size_t jj = 1; jj < hole.size(); ++jj )
2388 wxXmlNode* polyNode =
appendNode( cutoutNode,
"PolyStepSegment" );
2389 addXY( polyNode, hole[jj] );
2392 wxXmlNode* polyendNode =
appendNode( cutoutNode,
"PolyStepSegment" );
2393 addXY( polyendNode, hole[0] );
2406 wxXmlNode* outlineNode =
appendNode( aParentNode,
"Outline" );
2426 outline = &bbox_outline;
2431 wxLogTrace(
traceIpc2581, wxS(
"Failed to add polygon to outline" ) );
2433 if( !outlineNode->GetChildren() )
2435 aParentNode->RemoveChild( outlineNode );
2452 wxXmlNode* contourNode =
appendNode( aParentNode,
"Contour" );
2462 aParentNode->RemoveChild( contourNode );
2475 if( !
m_board->GetBoardPolygonOutlines( board_outline ) )
2481 wxXmlNode* profileNode =
appendNode( aStepNode,
"Profile" );
2485 wxLogTrace(
traceIpc2581, wxS(
"Failed to add polygon to profile" ) );
2486 aStepNode->RemoveChild( profileNode );
2509 std::unique_ptr<FOOTPRINT> fp(
static_cast<FOOTPRINT*
>( aFp->
Clone() ) );
2510 fp->SetParentGroup(
nullptr );
2511 fp->SetPosition( { 0, 0 } );
2512 fp->SetOrientation(
ANGLE_0 );
2516 fp->GetFPID().GetLibItemName().wx_str(),
2520 addAttribute( aContentNode,
"packageRef", iter->second );
2527 wxXmlNode* packageNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"Package" );
2528 wxXmlNode* otherSideViewNode =
nullptr;
2534 if( fp->FindPadByNumber(
"1" ) )
2536 else if ( fp->FindPadByNumber(
"A1" ) )
2538 else if ( fp->FindPadByNumber(
"A" ) )
2540 else if ( fp->FindPadByNumber(
"a" ) )
2542 else if ( fp->FindPadByNumber(
"a1" ) )
2544 else if ( fp->FindPadByNumber(
"Anode" ) )
2546 else if ( fp->FindPadByNumber(
"ANODE" ) )
2551 addAttribute( packageNode,
"pinOneOrientation",
"OTHER" );
2563 otherSideViewNode =
appendNode( packageNode,
"OtherSideView" );
2575 wxXmlNode* pickupPointNode =
appendNode( packageNode,
"PickupPoint" );
2579 std::map<PCB_LAYER_ID, std::map<bool, std::vector<BOARD_ITEM*>>> elements;
2581 for(
BOARD_ITEM* item : fp->GraphicalItems() )
2606 elements[item->GetLayer()][is_abs].push_back( item );
2609 auto add_base_node =
2612 wxXmlNode* parent = packageNode;
2617 if( !otherSideViewNode )
2618 otherSideViewNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"OtherSideView" );
2620 parent = otherSideViewNode;
2626 name =
"SilkScreen";
2627 else if( aLayer ==
F_Fab || aLayer ==
B_Fab )
2628 name =
"AssemblyDrawing";
2636 auto add_marking_node =
2637 [&]( wxXmlNode* aNode ) -> wxXmlNode*
2639 wxXmlNode* marking_node =
appendNode( aNode,
"Marking" );
2641 return marking_node;
2644 std::map<PCB_LAYER_ID, wxXmlNode*> layer_nodes;
2645 std::map<PCB_LAYER_ID, BOX2I> layer_bbox;
2649 if( elements.find( layer ) != elements.end() )
2651 if( elements[layer][
true].size() > 0 )
2652 layer_bbox[layer] = elements[layer][
true][0]->GetBoundingBox();
2653 else if( elements[layer][
false].size() > 0 )
2654 layer_bbox[layer] = elements[layer][
false][0]->GetBoundingBox();
2658 for(
auto& [layer, map] : elements )
2660 wxXmlNode* layer_node = add_base_node( layer );
2661 wxXmlNode* marking_node = add_marking_node( layer_node );
2662 wxXmlNode* group_node =
appendNode( marking_node,
"UserSpecial" );
2663 bool update_bbox =
false;
2667 layer_nodes[layer] = layer_node;
2671 for(
auto& [is_abs, vec] : map )
2675 wxXmlNode* output_node =
nullptr;
2678 layer_bbox[layer].Merge( item->GetBoundingBox() );
2681 output_node = add_marking_node( layer_node );
2683 output_node = group_node;
2685 switch( item->Type() )
2691 if(
text->IsKnockout() )
2705 if(
text->IsBorderEnabled() )
2708 text->GetEffectiveShape()->TransformToPolygon( poly_set, 0,
ERROR_INSIDE );
2710 text->GetBorderWidth() );
2731 if( group_node->GetChildren() ==
nullptr )
2733 marking_node->RemoveChild( group_node );
2734 layer_node->RemoveChild( marking_node );
2736 delete marking_node;
2740 for(
auto&[layer, bbox] : layer_bbox )
2742 if( bbox.GetWidth() > 0 )
2744 wxXmlNode* outlineNode =
insertNode( layer_nodes[layer],
"Outline" );
2747 std::vector<VECTOR2I> points( 4 );
2748 points[0] = bbox.GetPosition();
2749 points[2] = bbox.GetEnd();
2750 points[1].x = points[0].x;
2751 points[1].y = points[2].y;
2752 points[3].x = points[2].x;
2753 points[3].y = points[0].y;
2755 outline.
Append( points );
2761 std::map<wxString, wxXmlNode*> pin_nodes;
2763 for(
size_t ii = 0; ii < fp->Pads().size(); ++ii )
2765 PAD*
pad = fp->Pads()[ii];
2767 wxXmlNode* pinNode =
nullptr;
2769 auto [ it, inserted ] = pin_nodes.emplace(
name,
nullptr );
2774 it->second = pinNode;
2782 addAttribute( pinNode,
"electricalType",
"MECHANICAL" );
2783 else if(
pad->IsOnCopperLayer() )
2784 addAttribute( pinNode,
"electricalType",
"ELECTRICAL" );
2786 addAttribute( pinNode,
"electricalType",
"UNDEFINED" );
2788 if(
pad->HasHole() )
2793 if(
pad->GetFPRelativeOrientation() !=
ANGLE_0 )
2795 wxXmlNode* xformNode =
appendNode( pinNode,
"Xform" );
2796 EDA_ANGLE pad_angle =
pad->GetFPRelativeOrientation().Normalize();
2798 if( fp->IsFlipped() )
2807 pinNode = it->second;
2825 std::vector<wxXmlNode*> componentNodes;
2826 std::vector<wxXmlNode*> packageNodes;
2827 std::set<wxString> packageNames;
2829 bool generate_unique =
m_OEMRef.empty();
2833 wxXmlNode* componentNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"Component" );
2835 wxXmlNode* pkg =
addPackage( componentNode, fp );
2838 packageNodes.push_back( pkg );
2844 if( !generate_unique )
2847 if( field && !field->
GetText().empty() )
2853 name = wxString::Format(
"%s_%s_%s", fp->GetFPID().GetFullLibraryName(),
2854 fp->GetFPID().GetLibItemName().wx_str(),
2859 Report(
_(
"Duplicate footprint pointers encountered; IPC-2581 output may be incorrect." ),
2867 else if( fp->GetAttributes() &
FP_SMD )
2872 if( fp->GetOrientation() !=
ANGLE_0 || fp->IsFlipped() )
2874 wxXmlNode* xformNode =
appendNode( componentNode,
"Xform" );
2878 if( fp->IsFlipped() )
2884 if( fp->IsFlipped() )
2888 addLocationNode( componentNode, fp->GetPosition().x, fp->GetPosition().y );
2890 componentNodes.push_back( componentNode );
2899 for( wxXmlNode* pkg : packageNodes )
2900 aStepNode->AddChild( pkg );
2902 for( wxXmlNode* cmp : componentNodes )
2903 aStepNode->AddChild( cmp );
2911 wxXmlNode* netNode =
appendNode( aStepNode,
"LogicalNet" );
2913 genString(
m_board->GetNetInfo().GetNetItem( net )->GetNetname(),
"NET" ) ) ;
2915 for(
auto& [cmp,
pin] : pin_pair )
2917 wxXmlNode* netPinNode =
appendNode( netNode,
"PinRef" );
2931 std::vector<std::unique_ptr<FOOTPRINT>> footprints;
2935 std::map<PCB_LAYER_ID, std::map<int, std::vector<BOARD_ITEM*>>> elements;
2937 std::for_each(
m_board->Tracks().begin(),
m_board->Tracks().end(),
2938 [&layers, &elements](
PCB_TRACK* aTrack )
2940 if( aTrack->Type() == PCB_VIA_T )
2942 PCB_VIA* via = static_cast<PCB_VIA*>( aTrack );
2944 for( PCB_LAYER_ID layer : layers )
2946 if( via->FlashLayer( layer ) )
2947 elements[layer][via->GetNetCode()].push_back( via );
2952 elements[aTrack->GetLayer()][aTrack->GetNetCode()].push_back( aTrack );
2956 std::for_each( m_board->Zones().begin(), m_board->Zones().end(),
2957 [ &elements ](
ZONE* zone )
2959 LSEQ zone_layers = zone->GetLayerSet().Seq();
2961 for( PCB_LAYER_ID layer : zone_layers )
2962 elements[layer][zone->GetNetCode()].push_back( zone );
2965 for(
BOARD_ITEM* item : m_board->Drawings() )
2968 elements[conn_it->GetLayer()][conn_it->GetNetCode()].push_back( conn_it );
2970 elements[item->GetLayer()][0].push_back( item );
2973 for(
FOOTPRINT* fp : m_board->Footprints() )
2975 for(
PCB_FIELD* field : fp->GetFields() )
2976 elements[field->GetLayer()][0].push_back( field );
2978 for(
BOARD_ITEM* item : fp->GraphicalItems() )
2979 elements[item->GetLayer()][0].push_back( item );
2981 for(
PAD*
pad : fp->Pads() )
2983 LSEQ pad_layers =
pad->GetLayerSet().Seq();
2987 if(
pad->FlashLayer( layer ) )
2988 elements[layer][
pad->GetNetCode()].push_back(
pad );
2995 if( m_progressReporter )
2996 m_progressReporter->SetMaxProgress( nets.GetNetCount() * layers.size() );
2998 wxXmlNode* layerNode = appendNode( aStepNode,
"LayerFeature" );
2999 addAttribute( layerNode,
"layerRef", m_layer_name_map[layer] );
3001 auto process_net = [&] (
int net )
3003 std::vector<BOARD_ITEM*>& vec = elements[layer][net];
3008 std::stable_sort( vec.begin(), vec.end(),
3011 if( a->GetParentFootprint() == b->GetParentFootprint() )
3012 return a->Type() < b->Type();
3014 return a->GetParentFootprint() < b->GetParentFootprint();
3017 generateLayerSetNet( layerNode, layer, vec );
3022 if( m_progressReporter )
3024 m_progressReporter->Report( wxString::Format(
_(
"Exporting Layer %s, Net %s" ),
3025 m_board->GetLayerName( layer ),
3026 net->GetNetname() ) );
3027 m_progressReporter->AdvanceProgress();
3030 process_net( net->GetNetCode() );
3033 if( layerNode->GetChildren() ==
nullptr )
3035 aStepNode->RemoveChild( layerNode );
3048 wxXmlNode* layerNode =
appendNode( aLayerNode,
"LayerFeature" );
3049 layerNode->AddAttribute(
"layerRef",
genLayersString( layers.first, layers.second,
"DRILL" ) );
3060 Report(
_(
"Via uses unsupported padstack; omitted from drill data." ),
3065 wxXmlNode* padNode =
appendNode( layerNode,
"Set" );
3068 if(
via->GetNetCode() > 0 )
3071 wxXmlNode* holeNode =
appendNode( padNode,
"Hole" );
3072 addAttribute( holeNode,
"name", wxString::Format(
"H%d", hole_count++ ) );
3077 addXY( holeNode,
via->GetPosition() );
3087 Report(
_(
"Pad uses unsupported padstack; hole was omitted from drill data." ),
3092 wxXmlNode* padNode =
appendNode( layerNode,
"Set" );
3095 if(
pad->GetNetCode() > 0 )
3098 wxXmlNode* holeNode =
appendNode( padNode,
"Hole" );
3099 addAttribute( holeNode,
"name", wxString::Format(
"H%d", hole_count++ ) );
3105 addXY( holeNode,
pad->GetPosition() );
3115 wxXmlNode* layerNode =
appendNode( aLayerNode,
"LayerFeature" );
3116 layerNode->AddAttribute(
"layerRef",
genLayersString( layers.first, layers.second,
"SLOT" ) );
3120 wxXmlNode* padNode =
appendNode( layerNode,
"Set" );
3122 if(
pad->GetNetCode() > 0 )
3125 addSlotCavity( padNode, *
pad, wxString::Format(
"SLOT%d", hole_count++ ) );
3132 std::vector<BOARD_ITEM*>& aItems )
3134 auto it = aItems.begin();
3135 wxXmlNode* layerSetNode =
appendNode( aLayerNode,
"Set" );
3136 wxXmlNode* featureSetNode =
appendNode( layerSetNode,
"Features" );
3137 wxXmlNode* specialNode =
appendNode( featureSetNode,
"UserSpecial" );
3139 bool has_via =
false;
3140 bool has_pad =
false;
3142 wxXmlNode* padSetNode =
nullptr;
3144 wxXmlNode* viaSetNode =
nullptr;
3146 wxXmlNode* teardropLayerSetNode =
nullptr;
3147 wxXmlNode* teardropFeatureSetNode =
nullptr;
3149 bool teardrop_warning =
false;
3154 if( item->GetNetCode() > 0 )
3164 shape.
SetStart( track->GetStart() );
3165 shape.
SetEnd( track->GetEnd() );
3166 shape.
SetWidth( track->GetWidth() );
3183 viaSetNode = layerSetNode;
3188 viaSetNode =
appendNode( layerSetNode,
"Set" );
3190 if( track->GetNetCode() > 0 )
3197 addVia( viaSetNode,
static_cast<PCB_VIA*
>( track ), aLayer );
3204 wxXmlNode* zoneFeatureNode = specialNode;
3206 if( zone->IsTeardropArea() )
3210 if( !teardropFeatureSetNode )
3212 teardropLayerSetNode =
appendNode( aLayerNode,
"Set" );
3213 addAttribute( teardropLayerSetNode,
"geometryUsage",
"TEARDROP" );
3215 if( zone->GetNetCode() > 0 )
3218 genString( zone->GetNetname(),
"NET" ) );
3221 wxXmlNode* new_teardrops =
appendNode( teardropLayerSetNode,
"Features" );
3223 teardropFeatureSetNode =
appendNode( new_teardrops,
"UserSpecial" );
3226 zoneFeatureNode = teardropFeatureSetNode;
3228 else if( !teardrop_warning )
3230 Report(
_(
"Teardrops are not supported in IPC-2581 revision B; they were exported as zones." ),
3232 teardrop_warning =
true;
3239 wxXmlNode* tempSetNode =
appendNode( aLayerNode,
"Set" );
3240 wxString refDes =
componentName( zone->GetParentFootprint() );
3242 wxXmlNode* newFeatures =
appendNode( tempSetNode,
"Features" );
3244 zoneFeatureNode =
appendNode( newFeatures,
"UserSpecial" );
3248 SHAPE_POLY_SET& zone_shape = *zone->GetFilledPolysList( aLayer );
3250 for(
int ii = 0; ii < zone_shape.
OutlineCount(); ++ii )
3261 wxXmlNode* tempSetNode =
appendNode( aLayerNode,
"Set" );
3264 addAttribute( tempSetNode,
"geometryUsage",
"GRAPHIC" );
3266 bool link_to_component =
true;
3269 link_to_component =
false;
3271 if( link_to_component )
3274 wxXmlNode* tempFeature =
appendNode( tempSetNode,
"Features" );
3281 wxXmlNode* xformNode =
appendNode( tempFeature,
"Xform" );
3291 wxXmlNode* tempSetNode =
appendNode( aLayerNode,
"Set" );
3293 if( shape->GetNetCode() > 0 )
3296 wxXmlNode* tempFeature =
appendNode( tempSetNode,
"Features" );
3313 text_item =
static_cast<EDA_TEXT*
>( tmp_text );
3315 text_item =
static_cast<EDA_TEXT*
>( tmp_text );
3320 wxXmlNode* tempSetNode =
appendNode( aLayerNode,
"Set" );
3325 bool link_to_component = fp !=
nullptr;
3328 link_to_component =
false;
3330 if( link_to_component )
3333 wxXmlNode* nonStandardAttributeNode =
appendNode( tempSetNode,
"NonstandardAttribute" );
3334 addAttribute( nonStandardAttributeNode,
"name",
"TEXT" );
3336 addAttribute( nonStandardAttributeNode,
"type",
"STRING" );
3338 wxXmlNode* tempFeature =
appendNode( tempSetNode,
"Features" );
3344 addText( tempFeature, text_item,
text->GetFontMetrics() );
3362 padSetNode = layerSetNode;
3367 padSetNode =
appendNode( aLayerNode,
"Set" );
3369 if(
pad->GetNetCode() > 0 )
3384 switch( item->Type() )
3389 add_track(
static_cast<PCB_TRACK*
>( item ) );
3397 add_pad(
static_cast<PAD*
>( item ) );
3401 add_shape(
static_cast<PCB_SHAPE*
>( item ) );
3426 if( specialNode->GetChildren() ==
nullptr )
3428 featureSetNode->RemoveChild( specialNode );
3432 if( featureSetNode->GetChildren() ==
nullptr )
3434 layerSetNode->RemoveChild( featureSetNode );
3435 delete featureSetNode;
3438 if( layerSetNode->GetChildren() ==
nullptr )
3440 aLayerNode->RemoveChild( layerSetNode );
3441 delete layerSetNode;
3452 bool add_node =
true;
3458 switch( std::get<0>(layers) )
3487 wxXmlNode* layerNode =
appendNode( aStepNode,
"LayerFeature" );
3491 layerNode->AddAttribute(
"layerRef",
genLayersString( std::get<1>( layers ),
3505 shape.
SetEnd( {
KiROUND(
via->GetWidth( std::get<1>( layers ) ) / 2.0 ), 0 } );
3507 wxXmlNode* padNode =
appendNode( layerNode,
"Pad" );
3526 wxXmlNode* header =
appendNode( avl,
"AvlHeader" );
3530 addAttribute( header,
"datetime", wxDateTime::Now().FormatISOCombined() );
3533 std::set<wxString> unique_parts;
3534 std::map<wxString,wxString> unique_vendors;
3538 auto [ it, success ] = unique_parts.insert(
name );
3543 wxXmlNode* part =
appendNode( avl,
"AvlItem" );
3550 for (
int ii = 0; ii < 2; ++ii )
3556 if( mpn_name.empty() )
3559 wxXmlNode* vmpn =
appendNode( part,
"AvlVmpn" );
3563 wxXmlNode* mpn =
appendNode( vmpn,
"AvlMpn" );
3566 wxXmlNode* vendor =
appendNode( vmpn,
"AvlVendor" );
3568 wxString
name = wxT(
"UNKNOWN" );
3571 if( !ii && company[ii] )
3579 else if( !ii && !company_name[ii].
empty() )
3581 name = company_name[ii];
3583 else if( ii && !
m_dist.empty() )
3588 auto [vendor_id, inserted] = unique_vendors.emplace(
3590 wxString::Format(
"VENDOR_%zu", unique_vendors.size() ) );
3592 addAttribute( vendor,
"enterpriseRef", vendor_id->second );
3596 wxXmlNode* new_vendor =
new wxXmlNode( wxXML_ELEMENT_NODE,
"Enterprise" );
3612 const std::map<std::string, UTF8>* aProperties )
3625 if(
auto it = aProperties->find(
"units" ); it != aProperties->end() )
3627 if( it->second ==
"inch" )
3634 if(
auto it = aProperties->find(
"sigfig" ); it != aProperties->end() )
3635 m_sigfig = std::stoi( it->second );
3637 if(
auto it = aProperties->find(
"version" ); it != aProperties->end() )
3640 if(
auto it = aProperties->find(
"OEMRef" ); it != aProperties->end() )
3643 if(
auto it = aProperties->find(
"mpn" ); it != aProperties->end() )
3644 m_mpn = it->second.wx_str();
3646 if(
auto it = aProperties->find(
"mfg" ); it != aProperties->end() )
3647 m_mfg = it->second.wx_str();
3649 if(
auto it = aProperties->find(
"dist" ); it != aProperties->end() )
3650 m_dist = it->second.wx_str();
3652 if(
auto it = aProperties->find(
"distpn" ); it != aProperties->end() )
3657 for(
char c =
'a'; c <=
'z'; ++c )
3660 for(
char c =
'A'; c <=
'Z'; ++c )
3663 for(
char c =
'0'; c <=
'9'; ++c )
3667 std::string specialChars =
"_\\-.+><";
3669 for(
char c : specialChars )
3698 double written_bytes = 0.0;
3699 double last_yield = 0.0;
3706 auto update_progress = [&](
size_t aBytes )
3708 written_bytes += aBytes;
3709 double percent = written_bytes /
static_cast<double>(
m_total_bytes );
3714 if( last_yield + 0.01 < percent )
3716 last_yield = percent;
3730 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) 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
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.
wxString GetShownText(bool aAllowExtraText, int aDepth=0) const override
Return the string actually shown after processing of the base text.
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
static constexpr EDA_ANGLE ANGLE_180
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
@ FILLED_SHAPE
Fill with object color.
static const wxChar traceIpc2581[]
This program source code file is part of KiCad, a free EDA CAD application.
static constexpr void hash_combine(std::size_t &seed)
This is a dummy function to take the final case of hash_combine below.
static constexpr std::size_t hash_val(const Types &... args)
size_t hash_fp_item(const EDA_ITEM *aItem, int aFlags)
Calculate hash of an EDA_ITEM.
Hashing functions for EDA_ITEMs.
@ REL_COORD
Use coordinates relative to the parent object.
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.
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