46#include <wx/numformatter.h>
47#include <wx/xml/xml.h>
75 std::vector<FOOTPRINT*> retval;
78 retval.push_back(
static_cast<FOOTPRINT*
>( fp->Clone() ) );
88 if( aParent->GetChildren() )
89 aNode->SetNext( aParent->GetChildren() );
91 aNode->SetNext(
nullptr );
93 aParent->SetChildren( aNode );
94 aNode->SetParent( aParent );
103 aNode->SetNext( aPrev->GetNext() );
104 aPrev->SetNext( aNode );
105 aNode->SetParent( aPrev->GetParent() );
114 wxXmlNode* node =
new wxXmlNode( wxXML_ELEMENT_NODE, aName );
126 static wxXmlNode* lastNode =
nullptr;
128 if( lastNode && lastNode->GetParent() == aParent && lastNode->GetNext() ==
nullptr )
130 aNode->SetParent( aParent );
131 lastNode->SetNext( aNode );
135 aParent->AddChild( aNode );
147 wxXmlNode* node =
new wxXmlNode( wxXML_ELEMENT_NODE, aName );
158 wxString key = aPrefix ? wxString( aPrefix ) + wxT(
":" ) + aStr : aStr;
170 str.Replace( wxT(
":" ), wxT(
"_" ) );
174 for( wxString::const_iterator iter = aStr.begin(); iter != aStr.end(); ++iter )
184 wxString
name = base;
188 name = wxString::Format(
"%s_%d", base, suffix++ );
204 const char* aPrefix )
const
206 return genString( wxString::Format( wxS(
"%s_%s" ),
219 if(
name.empty() && fp )
223 if( fp->
Pads()[ii] == aPad )
231 name = wxString::Format(
"NPTH%zu", ii );
232 else if(
name.empty() )
233 name = wxString::Format(
"PAD%zu", ii );
242 [&](
const wxString& aName )
261 wxString
name = baseName;
264 while( !tryInsert(
name ) )
265 name = wxString::Format(
"%s_%d", baseName, suffix++ );
275 wxString str = wxString::FromCDouble( aVal, aSigFig == -1 ?
m_sigfig : aSigFig );
278 while( str.EndsWith( wxT(
"00" ) ) )
282 if( str == wxT(
"-0.0" ) )
307 aNode->AddAttribute( aName, aValue );
313 wxXmlNode* xmlHeaderNode =
new wxXmlNode(wxXML_ELEMENT_NODE,
"IPC-2581");
315 addAttribute( xmlHeaderNode,
"xmlns",
"http://webstds.ipc.org/2581");
316 addAttribute( xmlHeaderNode,
"xmlns:xsi",
"http://www.w3.org/2001/XMLSchema-instance");
317 addAttribute( xmlHeaderNode,
"xmlns:xsd",
"http://www.w3.org/2001/XMLSchema");
322 "http://webstds.ipc.org/2581 http://webstds.ipc.org/2581/IPC-2581B1.xsd" );
327 "http://webstds.ipc.org/2581 http://webstds.ipc.org/2581/IPC-2581C.xsd" );
332 return xmlHeaderNode;
344 wxXmlNode* node =
appendNode( contentNode,
"FunctionMode" );
359 contentNode->AddChild( color_node );
363 wxXmlNode* fillNode =
appendNode( contentNode,
"DictionaryFillDesc" );
383 contentNode->AddChild( color_node );
392 wxXmlNode* location_node =
appendNode( aNode,
"Location" );
420 case SHAPE_T::RECTANGLE:
425 case SHAPE_T::CIRCLE:
431 case SHAPE_T::BEZIER:
432 case SHAPE_T::SEGMENT:
437 case SHAPE_T::UNDEFINED:
467 wxXmlNode* color_node =
new wxXmlNode( wxXML_ELEMENT_NODE,
"DictionaryColor" );
471 wxString layer_name = item->GetLayerName();
472 int sub_layer_count = 1;
474 if( layer_name.empty() )
477 layer_name =
genString( layer_name,
"LAYER" );
481 layer_name =
genString( wxString::Format(
"DIELECTRIC_%d", item->GetDielectricLayerId() ),
483 sub_layer_count = item->GetSublayersCount();
490 for(
int sub_idx = 0; sub_idx < sub_layer_count; sub_idx++ )
492 wxString sub_layer_name = layer_name;
495 sub_layer_name += wxString::Format(
"_%d", sub_idx );
497 wxXmlNode* node =
appendNode( aContentNode,
"LayerRef" );
503 wxXmlNode* entry_color =
appendNode( color_node,
"EntryColor" );
507 wxString colorName = item->GetColor( sub_idx );
509 if( colorName.StartsWith( wxT(
"#" ) ) )
512 COLOR4D layer_color( colorName );
524 if( fab_color.GetName() == colorName )
542 if( aFill == FILL_T::FILLED_SHAPE )
548 wxXmlNode* fillDesc_node =
appendNode( aNode,
"FillDesc" );
554 wxXmlNode* fillDesc_node =
appendNode( aNode,
"FillDesc" );
555 addAttribute( fillDesc_node,
"fillProperty",
"HOLLOW" );
562 wxCHECK_RET( aNode,
"aNode is null" );
567 wxXmlNode* entry_node =
nullptr;
571 size_t hash =
lineHash( aWidth, aDashType );
572 wxString
name = wxString::Format(
"LINE_%zu",
m_line_dict.size() + 1 );
576 wxXmlNode* lineDesc_node =
appendNode( aNode,
"LineDescRef" );
591 wxXmlNode* line_node =
appendNode( entry_node,
"LineDesc" );
597 case LINE_STYLE::DOT:
600 case LINE_STYLE::DASH:
603 case LINE_STYLE::DASHDOT:
606 case LINE_STYLE::DASHDOTDOT:
638 wxXmlNode* text_node =
appendNode( aContentNode,
"UserSpecial" );
640 std::list<VECTOR2I> pts;
648 wxXmlNode* line_node =
nullptr;
655 addXY( line_node, pts.front(),
"startX",
"startY" );
656 addXY( line_node, pts.back(),
"endX",
"endY" );
660 line_node =
appendNode( text_node,
"Polyline" );
661 wxXmlNode* point_node =
appendNode( line_node,
"PolyBegin" );
662 addXY( point_node, pts.front() );
664 auto iter = pts.begin();
666 for( ++iter; iter != pts.end(); ++iter )
668 wxXmlNode* point_node =
appendNode( line_node,
"PolyStepSegment" );
669 addXY( point_node, *iter );
684 if( aPt1 == pts.back() )
685 pts.push_back( aPt2 );
686 else if( aPt2 == pts.front() )
687 pts.push_front( aPt1 );
688 else if( aPt1 == pts.front() )
689 pts.push_front( aPt2 );
690 else if( aPt2 == pts.back() )
691 pts.push_back( aPt1 );
695 pts.push_back( aPt1 );
696 pts.push_back( aPt2 );
701 pts.push_back( aPt1 );
702 pts.push_back( aPt2 );
708 if( aPoly.PointCount() < 3 )
711 wxXmlNode* outline_node = appendNode( text_node,
"Outline" );
712 wxXmlNode* poly_node = appendNode( outline_node,
"Polygon" );
715 const std::vector<VECTOR2I>& pts = aPoly.CPoints();
716 wxXmlNode* point_node = appendNode( poly_node,
"PolyBegin" );
717 addXY( point_node, pts.front() );
719 for(
size_t ii = 1; ii < pts.size(); ++ii )
721 wxXmlNode* point_node =
722 appendNode( poly_node,
"PolyStepSegment" );
723 addXY( point_node, pts[ii] );
726 point_node = appendNode( poly_node,
"PolyStepSegment" );
727 addXY( point_node, pts.front() );
732 font->Draw( &callback_gal, aText->GetShownText(
true ), aText->GetTextPos(), attrs,
738 if( text_node->GetChildren() == nullptr )
740 aContentNode->RemoveChild( text_node );
753 wxXmlNode* shape_node =
appendNode( aContentNode,
"StandardPrimitiveRef" );
770 case PAD_SHAPE::CIRCLE:
778 wxXmlNode* circle_node =
appendNode( entry_node,
"Circle" );
779 circle_node->AddAttribute(
"diameter",
784 case PAD_SHAPE::RECTANGLE:
792 wxXmlNode* rect_node =
appendNode( entry_node,
"RectCenter" );
800 case PAD_SHAPE::OVAL:
808 wxXmlNode* oval_node =
appendNode( entry_node,
"Oval" );
816 case PAD_SHAPE::ROUNDRECT:
824 wxXmlNode* roundrect_node =
appendNode( entry_node,
"RectRound" );
828 roundrect_node->AddAttribute(
"radius",
838 case PAD_SHAPE::CHAMFERED_RECT:
846 wxXmlNode* chamfered_node =
appendNode( entry_node,
"RectCham" );
851 int shorterSide = std::min( pad_size.
x, pad_size.
y );
870 case PAD_SHAPE::TRAPEZOID:
882 int dx = pad_size.
x / 2;
883 int dy = pad_size.
y / 2;
884 int ddx = trap_delta.
x / 2;
885 int ddy = trap_delta.
y / 2;
887 outline.
Append( -dx - ddy, dy + ddx );
888 outline.
Append( dx + ddy, dy - ddx );
889 outline.
Append( dx - ddy, -dy + ddx );
890 outline.
Append( -dx + ddy, -dy - ddx );
904 case PAD_SHAPE::CUSTOM:
918 CORNER_STRATEGY::ROUND_ALL_CORNERS, maxError );
925 wxLogError(
"Unknown pad type" );
932 wxXmlNode* shape_node =
appendNode( aContentNode,
"StandardPrimitiveRef" );
946 wxXmlNode* shape_node =
appendNode( aContentNode,
"UserPrimitiveRef" );
953 case SHAPE_T::CIRCLE:
964 wxXmlNode* special_node =
appendNode( entry_node,
"UserSpecial" );
966 wxXmlNode* circle_node =
appendNode( special_node,
"Circle" );
984 case SHAPE_T::RECTANGLE:
991 wxXmlNode* special_node =
appendNode( entry_node,
"UserSpecial" );
998 wxXmlNode* rect_node =
appendNode( special_node,
"RectRound" );
1015 width += stroke_width;
1016 height += stroke_width;
1038 wxXmlNode* special_node =
appendNode( entry_node,
"UserSpecial" );
1047 addContourNode( special_node, poly_set, ii, FILL_T::FILLED_SHAPE, 0,
1048 LINE_STYLE::SOLID );
1060 wxXmlNode* arc_node =
appendNode( aContentNode,
"Arc" );
1062 addXY( arc_node, aShape.
GetEnd(),
"endX",
"endY" );
1077 case SHAPE_T::BEZIER:
1079 wxXmlNode* polyline_node =
appendNode( aContentNode,
"Polyline" );
1083 std::vector<VECTOR2I> points;
1086 wxXmlNode* point_node =
appendNode( polyline_node,
"PolyBegin" );
1087 addXY( point_node, points[0] );
1089 for(
size_t i = 1; i < points.size(); i++ )
1091 wxXmlNode* point_node =
appendNode( polyline_node,
"PolyStepSegment" );
1092 addXY( point_node, points[i] );
1104 case SHAPE_T::SEGMENT:
1106 wxXmlNode* line_node =
appendNode( aContentNode,
"Line" );
1108 addXY( line_node, aShape.
GetEnd(),
"endX",
"endY" );
1119 case SHAPE_T::UNDEFINED:
1125 wxXmlNode* shape_node =
appendNode( aContentNode,
"UserPrimitiveRef" );
1134 wxXmlNode* slotNode =
appendNode( aNode,
"SlotCavity" );
1155 wxXmlNode* roleNode =
appendNode( logisticNode,
"Role" );
1163 wxXmlNode* personNode =
appendNode( logisticNode,
"Person" );
1165 addAttribute( personNode,
"enterpriseRef",
"UNKNOWN" );
1168 return logisticNode;
1179 addAttribute( historyNode,
"origination", wxDateTime::Now().FormatISOCombined() );
1181 addAttribute( historyNode,
"lastChange", wxDateTime::Now().FormatISOCombined() );
1183 wxXmlNode* fileRevisionNode =
appendNode( historyNode,
"FileRevision" );
1184 addAttribute( fileRevisionNode,
"fileRevisionId",
"1" );
1185 addAttribute( fileRevisionNode,
"comment",
"NO COMMENT" );
1188 wxXmlNode* softwarePackageNode =
appendNode( fileRevisionNode,
"SoftwarePackage" );
1191 addAttribute( softwarePackageNode,
"vendor",
"KiCad EDA" );
1193 wxXmlNode* certificationNode =
appendNode( softwarePackageNode,
"Certification" );
1194 addAttribute( certificationNode,
"certificationStatus",
"SELFTEST" );
1217 m_refdes =
new std::vector<REFDES>();
1218 m_props =
new std::map<wxString, wxString>();
1229 wxString m_OEMDesignRef;
1233 std::vector<REFDES>* m_refdes;
1234 std::map<wxString, wxString>* m_props;
1237 std::set<std::unique_ptr<struct BOM_ENTRY>,
1238 std::function<bool(
const std::unique_ptr<struct BOM_ENTRY>&,
1239 const std::unique_ptr<struct BOM_ENTRY>& )>> bom_entries(
1240 [](
const std::unique_ptr<struct BOM_ENTRY>& a,
1241 const std::unique_ptr<struct BOM_ENTRY>& b )
1243 return a->m_OEMDesignRef < b->m_OEMDesignRef;
1248 std::unique_ptr<FOOTPRINT> fp(
static_cast<FOOTPRINT*
>( fp_it->Clone() ) );
1249 fp->SetParentGroup(
nullptr );
1250 fp->SetPosition( {0, 0} );
1251 fp->SetOrientation(
ANGLE_0 );
1258 wxLogError(
"Footprint %s not found in dictionary",
1259 fp->GetFPID().GetLibItemName().wx_str() );
1263 auto entry = std::make_unique<struct BOM_ENTRY>();
1269 entry->m_OEMDesignRef = it->second;
1273 wxLogError(
"Footprint %s not found in OEMRef dictionary",
1274 fp->GetFPID().GetLibItemName().wx_str() );
1277 entry->m_OEMDesignRef =
genString( entry->m_OEMDesignRef,
"REF" );
1279 entry->m_pads = fp->GetPadCount();
1284 entry->m_type =
"DOCUMENT";
1286 entry->m_type =
"ELECTRICAL";
1288 auto[ bom_iter, inserted ] = bom_entries.insert( std::move( entry ) );
1291 ( *bom_iter )->m_count++;
1295 refdes.m_pkg = fp->GetFPID().GetLibItemName().wx_str();
1299 ( *bom_iter )->m_refdes->push_back( refdes );
1303 for(
PCB_FIELD* prop : fp->GetFields() )
1307 if( prop->IsMandatory() && !prop->IsValue() )
1310 ( *bom_iter )->m_props->emplace( prop->GetName(), prop->GetText() );
1314 if( bom_entries.empty() )
1319 wxXmlNode* bomNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"Bom" );
1320 m_xml_root->InsertChild( bomNode, aEcadNode );
1323 wxXmlNode* bomHeaderNode =
appendNode( bomNode,
"BomHeader" );
1327 wxXmlNode* stepRefNode =
appendNode( bomHeaderNode,
"StepRef" );
1330 for(
const auto& entry : bom_entries )
1332 wxXmlNode* bomEntryNode =
appendNode( bomNode,
"BomItem" );
1333 addAttribute( bomEntryNode,
"OEMDesignNumberRef", entry->m_OEMDesignRef );
1334 addAttribute( bomEntryNode,
"quantity", wxString::Format(
"%d", entry->m_count ) );
1335 addAttribute( bomEntryNode,
"pinCount", wxString::Format(
"%d", entry->m_pads ) );
1336 addAttribute( bomEntryNode,
"category", entry->m_type );
1338 for(
const REFDES& refdes : *( entry->m_refdes ) )
1340 wxXmlNode* refdesNode =
appendNode( bomEntryNode,
"RefDes" );
1343 addAttribute( refdesNode,
"populate", refdes.m_populate ?
"true" :
"false" );
1344 addAttribute( refdesNode,
"layerRef", refdes.m_layer );
1347 wxXmlNode* characteristicsNode =
appendNode( bomEntryNode,
"Characteristics" );
1348 addAttribute( characteristicsNode,
"category", entry->m_type );
1350 for(
const auto& prop : *( entry->m_props ) )
1352 wxXmlNode* textualDefNode =
appendNode( characteristicsNode,
"Textual" );
1353 addAttribute( textualDefNode,
"definitionSource",
"KICAD" );
1354 addAttribute( textualDefNode,
"textualCharacteristicName", prop.first );
1355 addAttribute( textualDefNode,
"textualCharacteristicValue", prop.second );
1373 wxXmlNode* cadDataNode =
appendNode( ecadNode,
"CadData" );
1390 std::vector<BOARD_STACKUP_ITEM*> layers = stackup.
GetList();
1391 std::set<PCB_LAYER_ID> added_layers;
1393 for(
int i = 0; i < stackup.
GetCount(); i++ )
1397 for(
int sublayer_id = 0; sublayer_id < stackup_item->
GetSublayersCount(); sublayer_id++ )
1401 if( ly_name.IsEmpty() )
1410 if( sublayer_id > 0 )
1411 ly_name += wxString::Format(
"_%d", sublayer_id );
1415 ly_name =
genString( ly_name,
"SPEC_LAYER" );
1417 wxXmlNode* specNode =
appendNode( aCadLayerNode,
"Spec" );
1419 wxXmlNode* generalNode =
appendNode( specNode,
"General" );
1421 wxXmlNode* propertyNode =
appendNode( generalNode,
"Property" );
1423 switch ( stackup_item->
GetType() )
1428 wxXmlNode* conductorNode =
appendNode( specNode,
"Conductor" );
1430 propertyNode =
appendNode( conductorNode,
"Property" );
1431 addAttribute( propertyNode,
"unit", wxT(
"SIEMENS/M" ) );
1432 addAttribute( propertyNode,
"value", wxT(
"5.959E7" ) );
1438 propertyNode =
appendNode( generalNode,
"Property" );
1439 addAttribute( propertyNode,
"text", wxString::Format(
"Type : %s",
1441 wxXmlNode* dielectricNode =
appendNode( specNode,
"Dielectric" );
1442 addAttribute( dielectricNode,
"type",
"DIELECTRIC_CONSTANT" );
1443 propertyNode =
appendNode( dielectricNode,
"Property" );
1446 dielectricNode =
appendNode( specNode,
"Dielectric" );
1447 addAttribute( dielectricNode,
"type",
"LOSS_TANGENT" );
1448 propertyNode =
appendNode( dielectricNode,
"Property" );
1455 propertyNode =
appendNode( generalNode,
"Property" );
1456 addAttribute( propertyNode,
"text", wxString::Format(
"Color : %s",
1458 propertyNode =
appendNode( generalNode,
"Property" );
1459 addAttribute( propertyNode,
"text", wxString::Format(
"Type : %s",
1464 propertyNode =
appendNode( generalNode,
"Property" );
1465 addAttribute( propertyNode,
"text", wxString::Format(
"Color : %s",
1467 propertyNode =
appendNode( generalNode,
"Property" );
1468 addAttribute( propertyNode,
"text", wxString::Format(
"Type : %s",
1481 wxXmlNode* cadHeaderNode =
appendNode( aEcadNode,
"CadHeader" );
1523 addAttribute( aNode,
"layerFunction",
"BOARD_OUTLINE" );
1564 aLayer ==
F_Cu ?
"TOP"
1565 : aLayer ==
B_Cu ?
"BOTTOM"
1580 wxXmlNode* stackupNode =
appendNode( aCadLayerNode,
"Stackup" );
1581 addAttribute( stackupNode,
"name",
"Primary_Stackup" );
1588 addAttribute( stackupNode,
"stackupStatus",
"PROPOSED" );
1590 wxXmlNode* stackupGroup =
appendNode( stackupNode,
"StackupGroup" );
1591 addAttribute( stackupGroup,
"name",
"Primary_Stackup_Group" );
1596 std::vector<BOARD_STACKUP_ITEM*> layers = stackup.
GetList();
1597 std::set<PCB_LAYER_ID> added_layers;
1599 for(
int i = 0; i < stackup.
GetCount(); i++ )
1603 for(
int sublayer_id = 0; sublayer_id < stackup_item->
GetSublayersCount(); sublayer_id++ )
1606 wxXmlNode* stackupLayer =
appendNode( stackupGroup,
"StackupLayer" );
1609 if( ly_name.IsEmpty() )
1618 if( sublayer_id > 0 )
1619 ly_name += wxString::Format(
"_%d", sublayer_id );
1623 ly_name =
genString( ly_name,
"LAYER" );
1625 addAttribute( stackupLayer,
"layerOrGroupRef", ly_name );
1629 addAttribute( stackupLayer,
"sequence", wxString::Format(
"%d", i ) );
1631 wxXmlNode* specLayerNode =
appendNode( stackupLayer,
"SpecRef" );
1632 addAttribute( specLayerNode,
"id", wxString::Format(
"SPEC_%s", ly_name ) );
1645 std::vector<BOARD_STACKUP_ITEM*> layers = stackup.
GetList();
1646 std::set<PCB_LAYER_ID> added_layers;
1648 for(
int i = 0; i < stackup.
GetCount(); i++ )
1655 for(
int sublayer_id = 0; sublayer_id < stackup_item->
GetSublayersCount(); sublayer_id++ )
1657 wxXmlNode* cadLayerNode =
appendNode( aCadLayerNode,
"Layer" );
1660 if( ly_name.IsEmpty() )
1670 if( sublayer_id > 0 )
1671 ly_name += wxString::Format(
"_%d", sublayer_id );
1675 ly_name =
genString( ly_name,
"LAYER" );
1682 addAttribute( cadLayerNode,
"layerFunction",
"DIELCORE" );
1684 addAttribute( cadLayerNode,
"layerFunction",
"DIELPREG" );
1708 added_layers.insert( layer );
1709 wxXmlNode* cadLayerNode =
appendNode( aCadLayerNode,
"Layer" );
1730 for(
PAD*
pad : fp->Pads() )
1732 if(
pad->HasDrilledHole() )
1734 else if(
pad->HasHole() )
1741 wxXmlNode* drillNode =
appendNode( aCadLayerNode,
"Layer" );
1742 drillNode->AddAttribute(
"name",
genLayersString( layers.first, layers.second,
"DRILL" ) );
1747 wxXmlNode* spanNode =
appendNode( drillNode,
"Span" );
1754 wxXmlNode* drillNode =
appendNode( aCadLayerNode,
"Layer" );
1755 drillNode->AddAttribute(
"name",
genLayersString( layers.first, layers.second,
"SLOT" ) );
1761 wxXmlNode* spanNode =
appendNode( drillNode,
"Span" );
1777 std::vector<std::tuple<auxLayerType, PCB_LAYER_ID, PCB_LAYER_ID>> new_layers;
1779 if(
via->Padstack().IsFilled().value_or(
false ) )
1780 new_layers.emplace_back( auxLayerType::FILLING,
via->TopLayer(),
via->BottomLayer() );
1782 if(
via->Padstack().IsCapped().value_or(
false ) )
1783 new_layers.emplace_back( auxLayerType::CAPPING,
via->TopLayer(),
via->BottomLayer() );
1787 if(
via->Padstack().IsPlugged( layer ).value_or(
false ) )
1788 new_layers.emplace_back( auxLayerType::PLUGGING, layer,
UNDEFINED_LAYER );
1790 if(
via->Padstack().IsCovered( layer ).value_or(
false ) )
1791 new_layers.emplace_back( auxLayerType::COVERING, layer,
UNDEFINED_LAYER );
1793 if(
via->Padstack().IsTented( layer ).value_or(
false ) )
1794 new_layers.emplace_back( auxLayerType::TENTING, layer,
UNDEFINED_LAYER );
1797 for(
auto& tuple : new_layers )
1803 bool add_node =
true;
1806 wxString layerFunction;
1809 switch( std::get<0>(layers) )
1811 case auxLayerType::COVERING:
1813 layerFunction =
"COATINGNONCOND";
1815 case auxLayerType::PLUGGING:
1817 layerFunction =
"HOLEFILL";
1819 case auxLayerType::TENTING:
1821 layerFunction =
"COATINGNONCOND";
1823 case auxLayerType::FILLING:
1825 layerFunction =
"HOLEFILL";
1827 case auxLayerType::CAPPING:
1829 layerFunction =
"COATINGCOND";
1837 if( add_node && !vec.empty() )
1839 wxXmlNode* node =
appendNode( aCadLayerNode,
"LAYER" );
1853 const bool first_external = std::get<1>( layers ) ==
F_Cu || std::get<1>( layers ) ==
B_Cu;
1854 const bool second_external = std::get<2>( layers ) ==
F_Cu || std::get<2>( layers ) ==
B_Cu;
1856 if( first_external )
1858 if( second_external )
1865 if( second_external )
1871 wxXmlNode* spanNode =
appendNode( node,
"SPAN" );
1882 wxXmlNode* stepNode =
appendNode( aCadNode,
"Step" );
1889 wxXmlNode* datumNode =
appendNode( stepNode,
"Datum" );
1909 wxXmlNode* padNode =
appendNode( aContentNode,
"Pad" );
1916 wxXmlNode* xformNode =
appendNode( padNode,
"Xform" );
1923 addShape( padNode, *aPad, aLayer );
1927 wxXmlNode* pinRefNode =
appendNode( padNode,
"PinRef" );
1940 wxXmlNode* padNode =
appendNode( aContentNode,
"Pad" );
1961 addAttribute( aPadNode,
"padstackDefRef", th_pair->second );
1968 wxXmlNode* padStackDefNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"PadStackDef" );
1982 wxXmlNode* padStackHoleNode =
appendNode( padStackDefNode,
"PadstackHoleDef" );
1983 padStackHoleNode->AddAttribute(
"name",
1984 wxString::Format(
"%s%d_%d",
1985 aPad->
GetAttribute() == PAD_ATTRIB::PTH ?
"PTH" :
"NPTH",
1990 aPad->
GetAttribute() == PAD_ATTRIB::PTH ?
"PLATED" :
"NONPLATED" );
2005 wxXmlNode* padStackPadDefNode =
appendNode( padStackDefNode,
"PadstackPadDef" );
2007 addAttribute( padStackPadDefNode,
"padUse",
"REGULAR" );
2012 PCB_SHAPE shape(
nullptr, SHAPE_T::CIRCLE );
2015 addShape( padStackPadDefNode, shape );
2019 addShape( padStackPadDefNode, *aPad, layer );
2031 addAttribute( aContentNode,
"padstackDefRef", via_pair->second );
2038 wxXmlNode* padStackDefNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"PadStackDef" );
2043 wxXmlNode* padStackHoleNode =
appendNode( padStackDefNode,
"PadstackHoleDef" );
2046 addAttribute( padStackHoleNode,
"platingStatus",
"VIA" );
2055 bool drill ) ->
void
2057 PCB_SHAPE shape(
nullptr, SHAPE_T::CIRCLE );
2060 shape.
SetEnd( {
KiROUND( aVia->GetDrillValue() / 2.0 ), 0 } );
2062 shape.
SetEnd( {
KiROUND( aVia->GetWidth( layer ) / 2.0 ), 0 } );
2064 wxXmlNode* padStackPadDefNode =
2065 appendNode( padStackDefNode,
"PadstackPadDef" );
2067 addAttribute( padStackPadDefNode,
"padUse",
"REGULAR" );
2070 addShape( padStackPadDefNode, shape );
2090 addPadShape( layer, aVia,
genLayerString( layer,
"PLUGGING" ),
true );
2093 addPadShape( layer, aVia,
genLayerString( layer,
"COVERING" ),
false );
2096 addPadShape( layer, aVia,
genLayerString( layer,
"TENTING" ),
false );
2105 wxXmlNode* polygonNode =
nullptr;
2113 polygonNode =
appendNode( aParentNode,
"Polygon" );
2114 wxXmlNode* polybeginNode =
appendNode( polygonNode,
"PolyBegin" );
2116 const std::vector<VECTOR2I>& pts = aPolygon.
CPoints();
2117 addXY( polybeginNode, pts[0] );
2119 for(
size_t ii = 1; ii < pts.size(); ++ii )
2121 wxXmlNode* polyNode =
appendNode( polygonNode,
"PolyStepSegment" );
2122 addXY( polyNode, pts[ii] );
2125 wxXmlNode* polyendNode =
appendNode( polygonNode,
"PolyStepSegment" );
2126 addXY( polyendNode, pts[0] );
2130 if( aFillType == FILL_T::NO_FILL )
2137 addLineDesc( polygonNode, aWidth, aDashType,
true );
2141 wxCHECK( aWidth == 0,
false );
2154 for(
size_t ii = 1; ii < aPolygon.size(); ++ii )
2156 wxCHECK2( aPolygon[ii].PointCount() >= 3,
continue );
2158 wxXmlNode* cutoutNode =
appendNode( aParentNode,
"Cutout" );
2159 wxXmlNode* polybeginNode =
appendNode( cutoutNode,
"PolyBegin" );
2161 const std::vector<VECTOR2I>& hole = aPolygon[ii].CPoints();
2162 addXY( polybeginNode, hole[0] );
2164 for(
size_t jj = 1; jj < hole.size(); ++jj )
2166 wxXmlNode* polyNode =
appendNode( cutoutNode,
"PolyStepSegment" );
2167 addXY( polyNode, hole[jj] );
2170 wxXmlNode* polyendNode =
appendNode( cutoutNode,
"PolyStepSegment" );
2171 addXY( polyendNode, hole[0] );
2184 wxXmlNode* outlineNode =
appendNode( aParentNode,
"Outline" );
2204 outline = &bbox_outline;
2209 wxLogTrace(
traceIpc2581, wxS(
"Failed to add polygon to outline" ) );
2211 if( !outlineNode->GetChildren() )
2213 aParentNode->RemoveChild( outlineNode );
2230 wxXmlNode* contourNode =
appendNode( aParentNode,
"Contour" );
2235 if( aFillType != FILL_T::NO_FILL )
2240 aParentNode->RemoveChild( contourNode );
2255 wxLogError(
"Failed to get board outline" );
2259 wxXmlNode* profileNode =
appendNode( aStepNode,
"Profile" );
2263 wxLogTrace(
traceIpc2581, wxS(
"Failed to add polygon to profile" ) );
2264 aStepNode->RemoveChild( profileNode );
2272 std::unique_ptr<FOOTPRINT> fp(
static_cast<FOOTPRINT*
>( aFp->
Clone() ) );
2273 fp->SetParentGroup(
nullptr );
2274 fp->SetPosition( { 0, 0 } );
2275 fp->SetOrientation(
ANGLE_0 );
2279 fp->GetFPID().GetLibItemName().wx_str(),
2283 addAttribute( aContentNode,
"packageRef", iter->second );
2290 wxXmlNode* packageNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"Package" );
2291 wxXmlNode* otherSideViewNode =
nullptr;
2297 if( fp->FindPadByNumber(
"1" ) )
2299 else if ( fp->FindPadByNumber(
"A1" ) )
2301 else if ( fp->FindPadByNumber(
"A" ) )
2303 else if ( fp->FindPadByNumber(
"a" ) )
2305 else if ( fp->FindPadByNumber(
"a1" ) )
2307 else if ( fp->FindPadByNumber(
"Anode" ) )
2309 else if ( fp->FindPadByNumber(
"ANODE" ) )
2314 addAttribute( packageNode,
"pinOneOrientation",
"OTHER" );
2324 otherSideViewNode =
appendNode( packageNode,
"OtherSideView" );
2326 LINE_STYLE::SOLID );
2335 wxXmlNode* pickupPointNode =
appendNode( packageNode,
"PickupPoint" );
2339 std::map<PCB_LAYER_ID, std::map<bool, std::vector<BOARD_ITEM*>>> elements;
2341 for(
BOARD_ITEM* item : fp->GraphicalItems() )
2359 if( shape->
GetShape() == SHAPE_T::CIRCLE || shape->
GetShape() == SHAPE_T::RECTANGLE )
2363 elements[item->GetLayer()][is_abs].push_back( item );
2366 auto add_base_node =
2369 wxXmlNode* parent = packageNode;
2374 if( !otherSideViewNode )
2375 otherSideViewNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"OtherSideView" );
2377 parent = otherSideViewNode;
2383 name =
"SilkScreen";
2384 else if( aLayer ==
F_Fab || aLayer ==
B_Fab )
2385 name =
"AssemblyDrawing";
2393 auto add_marking_node =
2394 [&]( wxXmlNode* aNode ) -> wxXmlNode*
2396 wxXmlNode* marking_node =
appendNode( aNode,
"Marking" );
2398 return marking_node;
2401 std::map<PCB_LAYER_ID, wxXmlNode*> layer_nodes;
2402 std::map<PCB_LAYER_ID, BOX2I> layer_bbox;
2406 if( elements.find( layer ) != elements.end() )
2408 if( elements[layer][
true].size() > 0 )
2409 layer_bbox[layer] = elements[layer][
true][0]->GetBoundingBox();
2410 else if( elements[layer][
false].size() > 0 )
2411 layer_bbox[layer] = elements[layer][
false][0]->GetBoundingBox();
2415 for(
auto& [layer, map] : elements )
2417 wxXmlNode* layer_node = add_base_node( layer );
2418 wxXmlNode* marking_node = add_marking_node( layer_node );
2419 wxXmlNode* group_node =
appendNode( marking_node,
"UserSpecial" );
2420 bool update_bbox =
false;
2424 layer_nodes[layer] = layer_node;
2428 for(
auto& [is_abs, vec] : map )
2432 wxXmlNode* output_node =
nullptr;
2435 layer_bbox[layer].Merge( item->GetBoundingBox() );
2438 output_node = add_marking_node( layer_node );
2440 output_node = group_node;
2442 switch( item->Type() )
2448 if(
text->IsKnockout() )
2462 if(
text->IsBorderEnabled() )
2465 text->GetEffectiveShape()->TransformToPolygon( poly_set, 0,
ERROR_INSIDE );
2467 text->GetBorderWidth() );
2488 if( group_node->GetChildren() ==
nullptr )
2490 marking_node->RemoveChild( group_node );
2491 layer_node->RemoveChild( marking_node );
2493 delete marking_node;
2497 for(
auto&[layer, bbox] : layer_bbox )
2499 if( bbox.GetWidth() > 0 )
2501 wxXmlNode* outlineNode =
insertNode( layer_nodes[layer],
"Outline" );
2504 std::vector<VECTOR2I> points( 4 );
2505 points[0] = bbox.GetPosition();
2506 points[2] = bbox.GetEnd();
2507 points[1].x = points[0].x;
2508 points[1].y = points[2].y;
2509 points[3].x = points[2].x;
2510 points[3].y = points[0].y;
2512 outline.
Append( points );
2518 for(
size_t ii = 0; ii < fp->Pads().size(); ++ii )
2520 PAD*
pad = fp->Pads()[ii];
2521 wxXmlNode* pinNode =
appendNode( packageNode,
"Pin" );
2529 if(
pad->GetAttribute() == PAD_ATTRIB::NPTH )
2530 addAttribute( pinNode,
"electricalType",
"MECHANICAL" );
2531 else if(
pad->IsOnCopperLayer() )
2532 addAttribute( pinNode,
"electricalType",
"ELECTRICAL" );
2534 addAttribute( pinNode,
"electricalType",
"UNDEFINED" );
2536 if(
pad->HasHole() )
2541 if(
pad->GetFPRelativeOrientation() !=
ANGLE_0 )
2543 wxXmlNode* xformNode =
appendNode( pinNode,
"Xform" );
2544 EDA_ANGLE pad_angle =
pad->GetFPRelativeOrientation().Normalize();
2546 if( fp->IsFlipped() )
2568 std::vector<wxXmlNode*> componentNodes;
2569 std::vector<wxXmlNode*> packageNodes;
2570 std::set<wxString> packageNames;
2572 bool generate_unique =
m_OEMRef.empty();
2576 wxXmlNode* componentNode =
new wxXmlNode( wxXML_ELEMENT_NODE,
"Component" );
2578 wxXmlNode* pkg =
addPackage( componentNode, fp );
2581 packageNodes.push_back( pkg );
2587 if( !generate_unique )
2590 if( field && !field->
GetText().empty() )
2596 name = wxString::Format(
"%s_%s_%s", fp->GetFPID().GetFullLibraryName(),
2597 fp->GetFPID().GetLibItemName().wx_str(),
2602 wxLogError(
"Duplicate footprint pointers. Please report this bug." );
2609 else if( fp->GetAttributes() &
FP_SMD )
2614 if( fp->GetOrientation() !=
ANGLE_0 || fp->IsFlipped() )
2616 wxXmlNode* xformNode =
appendNode( componentNode,
"Xform" );
2620 if( fp->IsFlipped() )
2626 if( fp->IsFlipped() )
2630 addLocationNode( componentNode, fp->GetPosition().x, fp->GetPosition().y );
2632 componentNodes.push_back( componentNode );
2641 for( wxXmlNode* pkg : packageNodes )
2642 aStepNode->AddChild( pkg );
2644 for( wxXmlNode* cmp : componentNodes )
2645 aStepNode->AddChild( cmp );
2653 wxXmlNode* netNode =
appendNode( aStepNode,
"LogicalNet" );
2657 for(
auto& [cmp,
pin] : pin_pair )
2659 wxXmlNode* netPinNode =
appendNode( netNode,
"PinRef" );
2673 std::vector<std::unique_ptr<FOOTPRINT>> footprints;
2677 std::map<PCB_LAYER_ID, std::map<int, std::vector<BOARD_ITEM*>>> elements;
2680 [&layers, &elements](
PCB_TRACK* aTrack )
2682 if( aTrack->Type() == PCB_VIA_T )
2684 PCB_VIA* via = static_cast<PCB_VIA*>( aTrack );
2686 for( PCB_LAYER_ID layer : layers )
2688 if( via->FlashLayer( layer ) )
2689 elements[layer][via->GetNetCode()].push_back( via );
2694 elements[aTrack->GetLayer()][aTrack->GetNetCode()].push_back( aTrack );
2698 std::for_each( m_board->Zones().begin(), m_board->Zones().end(),
2699 [ &elements ](
ZONE* zone )
2701 LSEQ zone_layers = zone->GetLayerSet().Seq();
2703 for( PCB_LAYER_ID layer : zone_layers )
2704 elements[layer][zone->GetNetCode()].push_back( zone );
2707 for(
BOARD_ITEM* item : m_board->Drawings() )
2710 elements[conn_it->GetLayer()][conn_it->GetNetCode()].push_back( conn_it );
2712 elements[item->GetLayer()][0].push_back( item );
2715 for(
FOOTPRINT* fp : m_board->Footprints() )
2717 for(
PCB_FIELD* field : fp->GetFields() )
2718 elements[field->GetLayer()][0].push_back( field );
2720 for(
BOARD_ITEM* item : fp->GraphicalItems() )
2721 elements[item->GetLayer()][0].push_back( item );
2723 for(
PAD*
pad : fp->Pads() )
2725 LSEQ pad_layers =
pad->GetLayerSet().Seq();
2729 if(
pad->FlashLayer( layer ) )
2730 elements[layer][
pad->GetNetCode()].push_back(
pad );
2737 if( m_progressReporter )
2738 m_progressReporter->SetMaxProgress( nets.GetNetCount() * layers.size() );
2740 wxXmlNode* layerNode = appendNode( aStepNode,
"LayerFeature" );
2741 addAttribute( layerNode,
"layerRef", m_layer_name_map[layer] );
2743 auto process_net = [&] (
int net )
2745 std::vector<BOARD_ITEM*>& vec = elements[layer][net];
2750 std::stable_sort( vec.begin(), vec.end(),
2753 if( a->GetParentFootprint() == b->GetParentFootprint() )
2754 return a->Type() < b->Type();
2756 return a->GetParentFootprint() < b->GetParentFootprint();
2759 generateLayerSetNet( layerNode, layer, vec );
2764 if( m_progressReporter )
2766 m_progressReporter->Report( wxString::Format(
_(
"Exporting Layer %s, Net %s" ),
2767 m_board->GetLayerName( layer ),
2768 net->GetNetname() ) );
2769 m_progressReporter->AdvanceProgress();
2772 process_net( net->GetNetCode() );
2775 if( layerNode->GetChildren() ==
nullptr )
2777 aStepNode->RemoveChild( layerNode );
2790 wxXmlNode* layerNode =
appendNode( aLayerNode,
"LayerFeature" );
2791 layerNode->AddAttribute(
"layerRef",
genLayersString( layers.first, layers.second,
"DRILL" ) );
2802 wxLogError(
"Failed to find padstack for via" );
2806 wxXmlNode* padNode =
appendNode( layerNode,
"Set" );
2809 if(
via->GetNetCode() > 0 )
2812 wxXmlNode* holeNode =
appendNode( padNode,
"Hole" );
2813 addAttribute( holeNode,
"name", wxString::Format(
"H%d", hole_count++ ) );
2818 addXY( holeNode,
via->GetPosition() );
2827 wxLogError(
"Failed to find padstack for pad" );
2831 wxXmlNode* padNode =
appendNode( layerNode,
"Set" );
2834 if(
pad->GetNetCode() > 0 )
2837 wxXmlNode* holeNode =
appendNode( padNode,
"Hole" );
2838 addAttribute( holeNode,
"name", wxString::Format(
"H%d", hole_count++ ) );
2841 pad->GetAttribute() == PAD_ATTRIB::PTH ?
"PLATED" :
"NONPLATED" );
2844 addXY( holeNode,
pad->GetPosition() );
2853 wxXmlNode* layerNode =
appendNode( aLayerNode,
"LayerFeature" );
2854 layerNode->AddAttribute(
"layerRef",
genLayersString( layers.first, layers.second,
"SLOT" ) );
2858 wxXmlNode* padNode =
appendNode( layerNode,
"Set" );
2860 if(
pad->GetNetCode() > 0 )
2863 addSlotCavity( padNode, *
pad, wxString::Format(
"SLOT%d", hole_count++ ) );
2870 std::vector<BOARD_ITEM*>& aItems )
2872 auto it = aItems.begin();
2873 wxXmlNode* layerSetNode =
appendNode( aLayerNode,
"Set" );
2874 wxXmlNode* featureSetNode =
appendNode( layerSetNode,
"Features" );
2875 wxXmlNode* specialNode =
appendNode( featureSetNode,
"UserSpecial" );
2877 bool has_via =
false;
2878 bool has_pad =
false;
2880 wxXmlNode* padSetNode =
nullptr;
2882 wxXmlNode* viaSetNode =
nullptr;
2884 wxXmlNode* teardropLayerSetNode =
nullptr;
2885 wxXmlNode* teardropFeatureSetNode =
nullptr;
2890 if( item->GetNetCode() > 0 )
2899 PCB_SHAPE shape(
nullptr, SHAPE_T::SEGMENT );
2900 shape.
SetStart( track->GetStart() );
2901 shape.
SetEnd( track->GetEnd() );
2902 shape.
SetWidth( track->GetWidth() );
2908 PCB_SHAPE shape(
nullptr, SHAPE_T::ARC );
2919 viaSetNode = layerSetNode;
2924 viaSetNode =
appendNode( layerSetNode,
"Set" );
2926 if( track->GetNetCode() > 0 )
2933 addVia( viaSetNode,
static_cast<PCB_VIA*
>( track ), aLayer );
2940 wxXmlNode* zoneFeatureNode = specialNode;
2942 if( zone->IsTeardropArea() &&
m_version >
'B' )
2944 if( !teardropFeatureSetNode )
2946 teardropLayerSetNode =
appendNode( aLayerNode,
"Set" );
2947 addAttribute( teardropLayerSetNode,
"geometryUsage",
"TEARDROP" );
2949 if( zone->GetNetCode() > 0 )
2952 genString( zone->GetNetname(),
"NET" ) );
2955 wxXmlNode* new_teardrops =
appendNode( teardropLayerSetNode,
"Features" );
2957 teardropFeatureSetNode =
appendNode( new_teardrops,
"UserSpecial" );
2960 zoneFeatureNode = teardropFeatureSetNode;
2966 wxXmlNode* tempSetNode =
appendNode( aLayerNode,
"Set" );
2967 wxString refDes =
componentName( zone->GetParentFootprint() );
2969 wxXmlNode* newFeatures =
appendNode( tempSetNode,
"Features" );
2971 zoneFeatureNode =
appendNode( newFeatures,
"UserSpecial" );
2975 SHAPE_POLY_SET& zone_shape = *zone->GetFilledPolysList( aLayer );
2977 for(
int ii = 0; ii < zone_shape.
OutlineCount(); ++ii )
2988 wxXmlNode* tempSetNode =
appendNode( aLayerNode,
"Set" );
2991 addAttribute( tempSetNode,
"geometryUsage",
"GRAPHIC" );
2995 wxXmlNode* tempFeature =
appendNode( tempSetNode,
"Features" );
3000 else if( shape->GetShape() == SHAPE_T::CIRCLE
3001 || shape->GetShape() == SHAPE_T::RECTANGLE
3002 || shape->GetShape() == SHAPE_T::POLY )
3004 wxXmlNode* tempSetNode =
appendNode( aLayerNode,
"Set" );
3006 if( shape->GetNetCode() > 0 )
3009 wxXmlNode* tempFeature =
appendNode( tempSetNode,
"Features" );
3026 text_item =
static_cast<EDA_TEXT*
>( tmp_text );
3028 text_item =
static_cast<EDA_TEXT*
>( tmp_text );
3033 wxXmlNode* tempSetNode =
appendNode( aLayerNode,
"Set" );
3041 wxXmlNode* nonStandardAttributeNode =
appendNode( tempSetNode,
"NonstandardAttribute" );
3042 addAttribute( nonStandardAttributeNode,
"name",
"TEXT" );
3044 addAttribute( nonStandardAttributeNode,
"type",
"STRING" );
3046 wxXmlNode* tempFeature =
appendNode( tempSetNode,
"Features" );
3052 addText( tempFeature, text_item,
text->GetFontMetrics() );
3070 padSetNode = layerSetNode;
3075 padSetNode =
appendNode( aLayerNode,
"Set" );
3077 if(
pad->GetNetCode() > 0 )
3092 switch( item->Type() )
3097 add_track(
static_cast<PCB_TRACK*
>( item ) );
3105 add_pad(
static_cast<PAD*
>( item ) );
3109 add_shape(
static_cast<PCB_SHAPE*
>( item ) );
3134 if( specialNode->GetChildren() ==
nullptr )
3136 featureSetNode->RemoveChild( specialNode );
3140 if( featureSetNode->GetChildren() ==
nullptr )
3142 layerSetNode->RemoveChild( featureSetNode );
3143 delete featureSetNode;
3146 if( layerSetNode->GetChildren() ==
nullptr )
3148 aLayerNode->RemoveChild( layerSetNode );
3149 delete layerSetNode;
3160 bool add_node =
true;
3166 switch( std::get<0>(layers) )
3168 case auxLayerType::COVERING:
3171 case auxLayerType::PLUGGING:
3175 case auxLayerType::TENTING:
3178 case auxLayerType::FILLING:
3182 case auxLayerType::CAPPING:
3195 wxXmlNode* layerNode =
appendNode( aStepNode,
"LayerFeature" );
3199 layerNode->AddAttribute(
"layerRef",
genLayersString( std::get<1>( layers ),
3208 PCB_SHAPE shape(
nullptr, SHAPE_T::CIRCLE );
3213 shape.
SetEnd( {
KiROUND(
via->GetWidth( std::get<1>( layers ) ) / 2.0 ), 0 } );
3215 wxXmlNode* padNode =
appendNode( layerNode,
"Pad" );
3234 wxXmlNode* header =
appendNode( avl,
"AvlHeader" );
3238 addAttribute( header,
"datetime", wxDateTime::Now().FormatISOCombined() );
3241 std::set<wxString> unique_parts;
3242 std::map<wxString,wxString> unique_vendors;
3246 auto [ it, success ] = unique_parts.insert(
name );
3251 wxXmlNode* part =
appendNode( avl,
"AvlItem" );
3258 for (
int ii = 0; ii < 2; ++ii )
3264 if( mpn_name.empty() )
3267 wxXmlNode* vmpn =
appendNode( part,
"AvlVmpn" );
3271 wxXmlNode* mpn =
appendNode( vmpn,
"AvlMpn" );
3274 wxXmlNode* vendor =
appendNode( vmpn,
"AvlVendor" );
3276 wxString
name = wxT(
"UNKNOWN" );
3279 if( !ii && company[ii] )
3287 else if( !ii && !company_name[ii].
empty() )
3289 name = company_name[ii];
3291 else if( ii && !
m_dist.empty() )
3296 auto [vendor_id, inserted] = unique_vendors.emplace(
3298 wxString::Format(
"VENDOR_%zu", unique_vendors.size() ) );
3300 addAttribute( vendor,
"enterpriseRef", vendor_id->second );
3304 wxXmlNode* new_vendor =
new wxXmlNode( wxXML_ELEMENT_NODE,
"Enterprise" );
3320 const std::map<std::string, UTF8>* aProperties )
3327 if(
auto it = aProperties->find(
"units" ); it != aProperties->end() )
3329 if( it->second ==
"inch" )
3336 if(
auto it = aProperties->find(
"sigfig" ); it != aProperties->end() )
3337 m_sigfig = std::stoi( it->second );
3339 if(
auto it = aProperties->find(
"version" ); it != aProperties->end() )
3342 if(
auto it = aProperties->find(
"OEMRef" ); it != aProperties->end() )
3345 if(
auto it = aProperties->find(
"mpn" ); it != aProperties->end() )
3346 m_mpn = it->second.wx_str();
3348 if(
auto it = aProperties->find(
"mfg" ); it != aProperties->end() )
3349 m_mfg = it->second.wx_str();
3351 if(
auto it = aProperties->find(
"dist" ); it != aProperties->end() )
3352 m_dist = it->second.wx_str();
3354 if(
auto it = aProperties->find(
"distpn" ); it != aProperties->end() )
3359 for(
char c =
'a'; c <=
'z'; ++c )
3362 for(
char c =
'A'; c <=
'Z'; ++c )
3365 for(
char c =
'0'; c <=
'9'; ++c )
3369 std::string specialChars =
"_\\-.+><";
3371 for(
char c : specialChars )
3400 double written_bytes = 0.0;
3401 double last_yield = 0.0;
3408 auto update_progress = [&](
size_t aBytes )
3410 written_bytes += aBytes;
3411 double percent = written_bytes /
static_cast<double>(
m_total_bytes );
3416 if( last_yield + 0.01 < percent )
3418 last_yield = percent;
3428 wxLogError(
_(
"Failed to save file to buffer" ) );
3432 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
Information pertinent to a Pcbnew printed circuit board.
bool GetBoardPolygonOutlines(SHAPE_POLY_SET &aOutlines, OUTLINE_ERROR_HANDLER *aErrorHandler=nullptr, bool aAllowUseArcsInPolygons=false, bool aIncludeNPTHAsOutlines=false)
Extract the board outlines and build a closed polygon from lines, arcs and circle items on edge cut l...
const NETINFO_LIST & GetNetInfo() const
bool IsLayerEnabled(PCB_LAYER_ID aLayer) const
A proxy function that calls the correspondent function in m_BoardSettings tests whether a given layer...
const FOOTPRINTS & Footprints() const
const TRACKS & Tracks() const
const wxString & GetFileName() const
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
const LSET & GetEnabledLayers() const
A proxy function that calls the corresponding function in m_BoardSettings.
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,...
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.
PROGRESS_REPORTER * m_progressReporter
Progress reporter to track the progress of the operation, may be nullptr.
FONT is an abstract base class for both outline and stroke fonts.
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.
Handle the data for a net.
const wxString & GetNetname() const
Container for NETINFO_ITEM elements, which are the nets.
NETINFO_ITEM * GetNetItem(int aNetCode) const
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.
std::optional< bool > IsPlugged(PCB_LAYER_ID aSide) const
std::optional< bool > IsCapped() const
std::optional< bool > IsCovered(PCB_LAYER_ID aSide) const
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.
virtual std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer, FLASHING flashPTHPads=FLASHING::DEFAULT) const override
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
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 VECTOR2I & GetOffset(PCB_LAYER_ID aLayer) const
EDA_ANGLE GetOrientation() const
Return the rotation angle of the pad.
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
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 generateDrillLayers(wxXmlNode *aCadLayerNode)
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< std::pair< PCB_LAYER_ID, PCB_LAYER_ID >, std::vector< PAD * > > m_slot_holes
std::map< size_t, wxString > m_footprint_dict
wxXmlNode * generateLogisticSection()
Creates the logistical data header.
std::set< wxString > m_element_names
std::map< size_t, wxString > m_line_dict
void addLineDesc(wxXmlNode *aNode, int aWidth, LINE_STYLE aDashType, bool aForce=false)
void addKnockoutText(wxXmlNode *aContentNode, PCB_TEXT *aText)
std::map< size_t, wxString > m_padstack_dict
std::map< std::pair< PCB_LAYER_ID, PCB_LAYER_ID >, std::vector< BOARD_ITEM * > > m_drill_layers
std::map< wxString, FOOTPRINT * > m_footprint_refdes_dict
void generateProfile(wxXmlNode *aStepNode)
void generateLayerFeatures(wxXmlNode *aStepNode)
void SaveBoard(const wxString &aFileName, BOARD *aBoard, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Write aBoard to a storage file in a format that this PCB_IO implementation knows about or it can be u...
wxXmlNode * generateBOMSection(wxXmlNode *aEcadNode)
Creates the BOM section.
wxXmlNode * generateContentStackup(wxXmlNode *aContentNode)
void addShape(wxXmlNode *aContentNode, const PCB_SHAPE &aShape)
void generateAuxilliaryLayers(wxXmlNode *aCadLayerNode)
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.
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)
std::set< wxUniChar > m_acceptable_chars
void addLayerAttributes(wxXmlNode *aNode, PCB_LAYER_ID aLayer)
wxXmlNode * generateXmlHeader()
Creates the XML header for IPC-2581.
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
void addLocationNode(wxXmlNode *aContentNode, double aX, double aY)
std::map< int, std::vector< std::pair< wxString, wxString > > > m_net_pin_dict
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.
virtual void SetNumPhases(int aNumPhases)=0
Set the number of phases.
virtual void Report(const wxString &aMessage)=0
Display aMessage in the progress bar dialog.
virtual void BeginPhase(int aPhase)=0
Initialize the aPhase virtual zone of the dialog progress bar.
virtual void AdvancePhase()=0
Use the next available virtual zone of the dialog progress bar.
virtual void SetCurrentProgress(double aProgress)=0
Set the progress value to aProgress (0..1).
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
static bool empty(const wxTextEntryBase *aCtrl)
static constexpr EDA_ANGLE ANGLE_0
static constexpr EDA_ANGLE ANGLE_180
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)
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.
@ 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