32#include <unordered_set>
76#define BLK_FIELD( BLK_T, FIELD ) BlockDataAs<BLK_T>( aBlock ).FIELD
88 THROW_IO_ERRORF( wxT(
"Unexpected next item in 0x32 pad list: block type %#04x, offset %#lx, key %#010x" ),
104 return ( aLayerInfo.m_Class << 8 ) + aLayerInfo.m_Subclass;
117static const std::unordered_map<LAYER_INFO, PCB_LAYER_ID>
s_LayerKiMap = {
201 static const std::unordered_map<uint8_t, wxString> s_ClassNames = {
224 static const std::unordered_map<uint8_t, wxString> s_BoardGeomSubclassNames = {
248 static const std::unordered_map<uint8_t, wxString> s_ComponentValueSubclassNames = {
257 static const std::unordered_map<uint8_t, wxString> s_DrawingFormatSubclassNames = {
265 static const std::unordered_map<uint8_t, wxString> s_PackageGeometrySubclassNames = {
285 static const std::unordered_map<uint8_t, wxString> s_ManufacturingSubclassNames = {
302 static const std::unordered_map<uint8_t, wxString> s_AnalysisSubclassNames = {
311 static const std::unordered_map<uint8_t, wxString> s_ConstraintSubclassNames = {
315 static const std::unordered_map<uint8_t, wxString> s_KeepinSubclassNames = {
319 static const std::unordered_map<uint8_t, wxString> s_KeepoutSubclassNames = {
325 static const std::unordered_map<uint8_t, const std::unordered_map<uint8_t, wxString>&> s_SubclassNameMaps = {
349 const auto classIt = s_ClassNames.find( aLayerInfo.
m_Class );
351 if( classIt != s_ClassNames.end() )
352 className = classIt->second;
354 className = wxString::Format( wxS(
"Class_%02X" ), aLayerInfo.
m_Class );
356 wxString subclassName;
359 auto classMapIt = s_SubclassNameMaps.find( aLayerInfo.
m_Class );
361 if( classMapIt != s_SubclassNameMaps.end() )
363 const std::unordered_map<uint8_t, wxString>& subclassMap = classMapIt->second;
365 const auto subIt = subclassMap.find( aLayerInfo.
m_Subclass );
367 if( subIt != subclassMap.end() )
368 subclassName = subIt->second;
372 subclassName = wxString::Format( wxS(
"Subclass_%02X" ), aLayerInfo.
m_Subclass );
378 subclassName = wxString::Format( wxS(
"Subclass_%02X" ), aLayerInfo.
m_Subclass );
381 return className + wxS(
"/" ) + subclassName;
424 return trace.m_Layer;
434 return shape.m_Layer;
452 wxCHECK( layerInfo.has_value(),
LAYER_INFO() );
454 return layerInfo.value();
464 if( aIndex >= aTotal - 1 )
503 if(
m_Lists.count( &aList ) == 0 )
505 std::vector<CUSTOM_LAYER>& classLayers =
m_Lists[&aList];
511 const wxString& layerName =
m_brdDb.GetString( entry.mLayerNameId );
516 classLayers.emplace_back( std::move( layer ) );
526 classLayers.emplace_back( std::move( layer ) );
536 classLayers.size(), aClass, aList.
m_Key );
558 const std::vector<CUSTOM_LAYER>& etchLayers = *customLayerIt->second;
559 const size_t numCuLayers = etchLayers.size();
564 m_board.GetDesignSettings().SetCopperLayerCount(
static_cast<int>( numCuLayers + numCuLayers % 2 ) );
566 std::vector<INPUT_LAYER_DESC> inputLayers;
568 for(
size_t li = 0; li < numCuLayers; ++li )
571 desc.
Name = etchLayers[li].m_Name;
575 inputLayers.push_back( desc );
580 int nextAutoUser = 0;
587 for(
size_t si = 0; si < layerList->size(); ++si )
589 const LAYER_INFO li{ classId,
static_cast<uint8_t
>( si ) };
598 if( layerList->at( si ).m_Name.length() > 0 )
599 desc.
Name = layerList->at( si ).m_Name;
604 inputLayers.push_back( desc );
615 desc.
Name = layerName;
619 inputLayers.push_back( desc );
629 inputLayers.push_back( desc );
635 for(
size_t li = 0; li < numCuLayers; ++li )
638 const wxString& layerName = etchLayers[li].m_Name;
640 auto it = resolvedMapping.find( layerName );
641 PCB_LAYER_ID lId = ( it != resolvedMapping.end() ) ? it->second
645 m_board.SetLayerName( lId, layerName );
649 for(
const auto& [layerInfo, defaultKiLayer] :
s_LayerKiMap )
664 auto rmIt = resolvedMapping.find( dialogName );
669 m_board.SetLayerName( rmIt->second, dialogName );
674 LSET enabledLayersMask =
m_board.GetEnabledLayers();
676 for(
const auto& [
name, layerId] : resolvedMapping )
679 enabledLayersMask |=
LSET{ layerId };
685 m_board.GetLayerName( layerId ), layerId );
689 m_board.SetEnabledLayers( enabledLayersMask );
691 m_board.GetDesignSettings().SetUserDefinedLayerCount( userLayers );
717 && cLayerList == etchIt->second
718 && aLayerInfo.
m_Subclass < cLayerList->size() )
726 if( aLayerInfo.
m_Subclass < cLayerList->size() )
773 || classIt->second != etchIt->second || !etchIt->second
774 || aLayerInfo.
m_Subclass >= etchIt->second->size() )
801 const wxString
name = aTop ?
"PLACE_BOUND_TOP" :
"PLACE_BOUND_BOTTOM";
889 wxLogTrace(
traceAllegroBuilder,
" Unhandled non-copper zone layer class %#02x, using default layers",
932 m_board.GetDesignSettings().SetUserDefinedLayerCount(
m_board.GetDesignSettings().GetUserDefinedLayerCount() + 1 );
933 m_board.SetLayerName( lId, aName );
940 std::unordered_map<const BLK_0x2A_LAYER_LIST*, std::vector<CUSTOM_LAYER>>
m_Lists;
1004 if(
m_brdDb.m_Header->m_UnitsDivisor == 0 )
1007 if( !c_baseScales.contains(
m_brdDb.m_Header->m_BoardUnits ) )
1010 double baseScale( c_baseScales.at(
m_brdDb.m_Header->m_BoardUnits ) );
1093 wxLogTrace(
traceAllegroPerf, wxT(
" Intersected and fractured zone fills in %.3f ms" ),
1103 m_FillInfos.emplace_back( &aZone, aLayer, std::move( aFilledArea ) );
1118 double result = std::round( aValue );
1120 if(
result > std::numeric_limits<int>::max() )
1121 return std::numeric_limits<int>::max();
1123 if(
result < std::numeric_limits<int>::min() )
1124 return std::numeric_limits<int>::min();
1126 return static_cast<int>(
result );
1161 m_reporter.Report( wxString::Format(
"Could not find expected block with key %#010x and type %#04x", aKey, aType ),
1167 const wxString& aName )
const
1169 wxString
name = aName.IsEmpty() ? wxString(
"Object" ) : aName;
1170 wxString withKey = ( aKey == 0 ) ? wxString(
"" ) : wxString::Format(
", with key %#010x ", aKey );
1171 wxString withOffset = ( aOffset == 0 ) ? wxString(
"" ) : wxString::Format(
", at offset %#zx ", aOffset );
1173 wxString s = wxString::Format(
"%s has unexpected type %#04x (expected %#04x)%s%s",
name, aGot, aExpected, withKey,
1184 if( blk0x30 ==
nullptr )
1189 if( blk0x31 ==
nullptr )
1201 bool encountered =
false;
1205 if( blk0x36.m_Code != 0x08 )
1216 for(
const auto& item : blk0x36.m_Items )
1218 const auto& fontDef = std::get<BLK_0x36_DEF_TABLE::FontDef_X08>( item );
1234 std::vector<BOARD_ITEM*> bulkAdded;
1237 m_brdDb.m_Header->m_LL_0x1B_Nets,
1244 wxString netName =
m_brdDb.GetString( netBlk.m_NetName );
1249 if( netName.IsEmpty() )
1250 netName = wxString::Format( wxS(
"Net_%d" ), netCode );
1252 std::unique_ptr<NETINFO_ITEM> kiNetInfo = std::make_unique<NETINFO_ITEM>( &
m_board, netName, netCode );
1256 bulkAdded.push_back( kiNetInfo.get() );
1260 m_board.FinalizeBulkAdd( bulkAdded );
1270 if( !fieldBlock || fieldBlock->
GetBlockType() != 0x03 )
1271 return wxEmptyString;
1274 const std::string* str = std::get_if<std::string>( &field.
m_Substruct );
1277 return wxEmptyString;
1281 size_t sep = str->find(
":\\" );
1283 if( sep == std::string::npos )
1284 return wxEmptyString;
1286 std::string extracted = str->substr( sep + 2 );
1288 if( !extracted.empty() && extracted.back() ==
'\\' )
1289 extracted.pop_back();
1291 return wxString( extracted );
1300 std::shared_ptr<NET_SETTINGS> netSettings = bds.
m_NetSettings;
1309 int diffPairGap = 0;
1313 std::map<wxString, CS_DEF> constraintSets;
1316 std::map<uint32_t, wxString> keyToSetName;
1324 const wxString& resolved =
m_brdDb.GetString( csBlock.m_NameStrKey );
1326 if( !resolved.IsEmpty() )
1330 else if( csBlock.m_FieldPtr != 0 )
1336 if( setName.IsEmpty() )
1337 setName = wxString::Format( wxS(
"CS_%d" ), csIndex );
1341 if( csBlock.m_DataB.empty() )
1343 wxLogTrace(
traceAllegroBuilder,
"Constraint set '%s' has no DataB records, skipping", setName );
1348 const auto& record = csBlock.m_DataB[0];
1350 static_assert(
sizeof( fields ) == std::tuple_size_v<std::decay_t<
decltype( record )>> );
1351 memcpy( fields, record.data(),
sizeof( fields ) );
1358 def.lineWidth =
scale( fields[1] );
1359 def.clearance =
scale( fields[4] );
1365 def.lineWidth =
scale( fields[0] );
1366 def.clearance =
scale( fields[1] );
1369 def.diffPairGap =
scale( fields[7] );
1371 constraintSets[setName] = def;
1372 keyToSetName[csBlock.m_NameStrKey] = setName;
1375 "Constraint set '%s': line_width=%d nm, clearance=%d nm, dp_gap=%d nm",
1376 setName, def.lineWidth, def.clearance, def.diffPairGap );
1379 if( constraintSets.empty() )
1386 for(
const auto& [
name, def] : constraintSets )
1388 wxString ncName =
name;
1391 ncName = wxS(
"Allegro_Default" );
1393 if( netSettings->HasNetclass( ncName ) )
1396 std::shared_ptr<NETCLASS> nc = std::make_shared<NETCLASS>( ncName );
1398 if( def.lineWidth > 0 )
1399 nc->SetTrackWidth( def.lineWidth );
1401 if( def.clearance > 0 )
1402 nc->SetClearance( def.clearance );
1404 if( def.diffPairGap > 0 )
1406 nc->SetDiffPairGap( def.diffPairGap );
1409 if( def.lineWidth > 0 )
1410 nc->SetDiffPairWidth( def.lineWidth );
1413 netSettings->SetNetclass( ncName, nc );
1419 wxString defaultSetName;
1421 for(
const auto& [
name, def] : constraintSets )
1423 if(
name.CmpNoCase( wxS(
"DEFAULT" ) ) == 0 )
1425 defaultSetName =
name;
1439 wxString assignedSetName;
1441 if( csField.has_value() )
1443 if(
auto* intVal = std::get_if<uint32_t>( &csField.value() ) )
1445 auto it = keyToSetName.find( *intVal );
1447 if( it != keyToSetName.end() )
1448 assignedSetName = it->second;
1450 else if(
auto* strVal = std::get_if<wxString>( &csField.value() ) )
1452 if( constraintSets.count( *strVal ) )
1453 assignedSetName = *strVal;
1458 if( assignedSetName.IsEmpty() && !defaultSetName.IsEmpty() )
1459 assignedSetName = defaultSetName;
1461 if( assignedSetName.IsEmpty() )
1464 wxString ncName = assignedSetName;
1467 ncName = wxS(
"Allegro_Default" );
1469 if( !netSettings->HasNetclass( ncName ) )
1472 auto netIt =
m_netCache.find( netBlk.m_Key );
1478 netSettings->SetNetclassPatternAssignment( kiNet->
GetNetname(), ncName );
1479 kiNet->
SetNetClass( netSettings->GetNetClassByName( ncName ) );
1482 wxLogTrace(
traceAllegroBuilder,
"Applied %zu physical constraint sets", constraintSets.size() );
1491 std::shared_ptr<NET_SETTINGS> netSettings = bds.
m_NetSettings;
1495 std::map<int, std::vector<uint32_t>> widthToNetKeys;
1501 std::optional<int> minWidth =
1504 if( !minWidth.has_value() || minWidth.value() <= 0 )
1507 int widthNm =
scale( minWidth.value() );
1508 widthToNetKeys[widthNm].push_back( netBlk.m_Key );
1511 if( widthToNetKeys.empty() )
1517 for(
const auto& [widthNm, netKeys] : widthToNetKeys )
1519 int widthMils = ( widthNm + 12700 ) / 25400;
1520 wxString ncName = wxString::Format( wxS(
"W%dmil" ), widthMils );
1522 if( netSettings->HasNetclass( ncName ) )
1525 std::shared_ptr<NETCLASS> nc = std::make_shared<NETCLASS>( ncName );
1526 nc->SetTrackWidth( widthNm );
1527 netSettings->SetNetclass( ncName, nc );
1529 for( uint32_t netKey : netKeys )
1537 netSettings->SetNetclassPatternAssignment( kiNet->
GetNetname(), ncName );
1541 wxLogTrace(
traceAllegroBuilder,
"Created netclass '%s' (track width %d nm) with %zu nets",
1542 ncName, widthNm, netKeys.size() );
1545 wxLogTrace(
traceAllegroBuilder,
"Applied trace width constraints from %zu unique width groups",
1546 widthToNetKeys.size() );
1553 return wxEmptyString;
1558 return wxEmptyString;
1560 uint32_t tableKey = 0;
1566 tableKey = x26.m_GroupPtr;
1573 if(
next &&
next->GetBlockType() == 0x26 )
1576 tableKey = x26b.m_GroupPtr;
1587 return wxEmptyString;
1591 return wxEmptyString;
1597 if( !tableBlock || tableBlock->
GetBlockType() != 0x2C )
1598 return wxEmptyString;
1603 return wxEmptyString;
1607 wxLogTrace(
traceAllegroBuilder,
"Resolving match group name for NET '%s': found table at key %#010x, subtype %#x, name '%s'",
1617 wxLogTrace(
traceAllegroBuilder,
"Applying match group / differential pair assignments" );
1620 std::shared_ptr<NET_SETTINGS> netSettings = bds.
m_NetSettings;
1623 std::map<wxString, std::vector<uint32_t>> groupToNetKeys;
1631 if( groupName.empty() )
1634 groupToNetKeys[groupName].push_back( netBlk.m_Key );
1637 if( groupToNetKeys.empty() )
1646 for(
const auto& [groupName, netKeys] : groupToNetKeys )
1650 bool isDiffPair = ( netKeys.size() == 2 );
1651 wxString ncPrefix = isDiffPair ? wxS(
"DP_" ) : wxS(
"MG_" );
1652 wxString ncName = ncPrefix + groupName;
1654 if( netSettings->HasNetclass( ncName ) )
1657 std::shared_ptr<NETCLASS> nc = std::make_shared<NETCLASS>( ncName );
1661 for( uint32_t netKey : netKeys )
1668 NETCLASS* existing = it->second->GetNetClass();
1688 netSettings->SetNetclass( ncName, nc );
1690 for( uint32_t netKey : netKeys )
1698 netSettings->SetNetclassPatternAssignment( kiNet->
GetNetname(), ncName );
1708 isDiffPair ? wxS(
"Diff pair" ) : wxS(
"Match" ),
1709 groupName, ncName, netKeys.size() );
1713 "Applied match groups: %d diff pairs, %d match groups (%zu total groups)",
1714 dpCount, mgCount, groupToNetKeys.size() );
1733 std::unordered_set<LAYER_INFO> layersFound;
1735 const auto& addLayer =
1736 [&]( std::optional<LAYER_INFO>&
info )
1738 if(
info.has_value() )
1739 layersFound.insert( std::move(
info.value() ) );
1742 const auto& simpleWalker =
1754 simpleWalker( aDb.
m_Header->m_LL_Shapes );
1755 simpleWalker( aDb.
m_Header->m_LL_0x24_0x28 );
1756 simpleWalker( aDb.
m_Header->m_LL_0x14 );
1766 const std::array<FILE_HEADER::LAYER_MAP_ENTRY, 25>& layerMap =
m_brdDb.m_Header->m_LayerMap;
1768 for(
size_t i = 0; i < layerMap.size(); ++i )
1770 const uint8_t classNum =
static_cast<uint8_t
>( i );
1772 const uint32_t x2aKey = layerMap[i].m_LayerList0x2A;
1802 if( layersFound.count( outlineInfo ) && layersFound.count( designOutlineInfo ) )
1806 "Both OUTLINE and DESIGN_OUTLINE layers found, remapping DESIGN_OUTLINE to a user layer" );
1818 m_reporter.Report( wxString::Format(
"Font def index %u requested, have %zu entries",
1846 std::unique_ptr<PCB_SHAPE> shape = std::make_unique<PCB_SHAPE>( &aParent,
SHAPE_T::SEGMENT );
1847 shape->SetLayer( aLayer );
1848 shape->SetStart( start );
1849 shape->SetEnd(
end );
1852 int adjustedWidth = width;
1854 if( adjustedWidth <= 0 )
1855 adjustedWidth =
m_board.GetDesignSettings().GetLineThickness( aLayer );
1857 shape->SetWidth( adjustedWidth );
1870 std::unique_ptr<PCB_SHAPE> shape = std::make_unique<PCB_SHAPE>( &aParent,
SHAPE_T::ARC );
1872 shape->SetLayer( aLayer );
1877 start.Format(),
end.Format() );
1880 start =
scale( start );
1887 bool clockwise = ( aArc.
m_SubType & 0x40 ) != 0;
1893 arcWidth =
m_board.GetDesignSettings().GetLineThickness( aLayer );
1895 shape->SetWidth( arcWidth );
1901 shape->SetCenter( c );
1902 shape->SetRadius(
radius );
1913 EDA_ANGLE angle = endangle - startangle;
1915 if( clockwise && angle <
ANGLE_0 )
1917 if( !clockwise && angle >
ANGLE_0 )
1928 const double centreDistance =
1932 if( !std::isfinite( centreDistance ) || centreDistance > std::numeric_limits<int>::max() / 4 )
1935 shape->SetStart( start );
1936 shape->SetEnd(
end );
1940 shape->SetArcGeometry( start, mid,
end );
1951 std::unique_ptr<PCB_TEXT>
text = std::make_unique<PCB_TEXT>( &aParent );
1954 text->SetLayer( layer );
1960 m_reporter.Report( wxString::Format(
"Failed to find string graphic (0x31) with key %#010x "
1961 "in string wrapper (0x30) with key %#010x",
1969 if( aStrWrapper.
m_Font.has_value() )
1970 props = &aStrWrapper.
m_Font.value();
1972 if( !props && aStrWrapper.
m_Font16x.has_value() )
1977 m_reporter.Report( wxString::Format(
"Expected one of the font properties fields in 0x30 object (key %#010x) "
1979 aStrWrapper.
m_Key ),
1999 text->SetTextAngle( textAngle );
2008 text->SetPosition( textPos + textFontOffset );
2013 text->SetMirrored(
true );
2039 std::vector<std::unique_ptr<PCB_SHAPE>> shapes;
2041 const uint32_t markerShape = aPinDef.
GetShape();
2047 const auto addLine =
2048 [&](
const SEG& aSeg )
2050 std::unique_ptr<PCB_SHAPE> shape = std::make_unique<PCB_SHAPE>( &aParent,
SHAPE_T::SEGMENT );
2051 shape->SetStart( aSeg.A );
2052 shape->SetEnd( aSeg.B );
2053 shapes.push_back( std::move( shape ) );
2056 const auto addPolyPts =
2057 [&](
const std::vector<VECTOR2I>& aPts )
2059 std::unique_ptr<PCB_SHAPE> shape = std::make_unique<PCB_SHAPE>( &aParent,
SHAPE_T::POLY );
2060 shape->SetPolyPoints( aPts );
2061 shapes.push_back( std::move( shape ) );
2064 switch( markerShape )
2068 std::unique_ptr<PCB_SHAPE> shape = std::make_unique<PCB_SHAPE>( &aParent,
SHAPE_T::CIRCLE );
2069 shape->SetCenter(
center );
2070 shape->SetRadius( size.x / 2 );
2071 shapes.push_back( std::move( shape ) );
2077 std::unique_ptr<PCB_SHAPE> shape = std::make_unique<PCB_SHAPE>( &aParent,
SHAPE_T::RECTANGLE );
2078 shape->SetStart(
center - size / 2 );
2079 shape->SetEnd(
center + size / 2 );
2080 shapes.push_back( std::move( shape ) );
2085 std::unique_ptr<PCB_SHAPE> shape;
2089 for(
const SEG& seg : segs )
2097 std::unique_ptr<PCB_SHAPE> shape = std::make_unique<PCB_SHAPE>( &aParent,
SHAPE_T::RECTANGLE );
2098 shape->SetStart(
center - size / 2 );
2099 shape->SetEnd(
center + size / 2 );
2101 int minSize = std::min( size.x, size.y );
2102 shape->SetCornerRadius(
minSize / 2 );
2103 shapes.push_back( std::move( shape ) );
2144 wxLogTrace(
traceAllegroBuilder,
"Unsupported drill marker shape type %#04x for pin definition with key %#010x",
2145 markerShape, aPinDef.
m_Key );
2149 std::vector<std::unique_ptr<BOARD_ITEM>> items;
2151 for( std::unique_ptr<PCB_SHAPE>& shape : shapes )
2153 shape->SetLayer( layer );
2154 shape->SetWidth( 0 );
2156 items.push_back( std::move( shape ) );
2166 std::vector<std::unique_ptr<BOARD_ITEM>> newItems;
2180 std::unique_ptr<PCB_SHAPE> shape =
buildRect( rect, aParent );
2182 newItems.push_back( std::move( shape ) );
2189 std::vector<std::unique_ptr<PCB_SHAPE>> shapes =
buildShapes( graphicContainer, aParent );
2191 for( std::unique_ptr<PCB_SHAPE>& shape : shapes )
2192 newItems.push_back( std::move( shape ) );
2200 std::unique_ptr<PCB_SHAPE> shape =
buildRect( rect, aParent );
2203 newItems.push_back( std::move( shape ) );
2210 std::unique_ptr<PCB_SHAPE> shape =
buildPolygon( shapeData, aParent );
2213 newItems.push_back( std::move( shape ) );
2221 std::unique_ptr<BOARD_ITEM> newItem =
buildPcbText( strWrapper, aParent );
2224 newItems.push_back( std::move( newItem ) );
2248 return static_cast<const PCB_SHAPE&
>( aItem ).GetNetCode();
2279 if( aFirst->
Type() != aSecond->
Type()
2287 return static_cast<const PCB_SHAPE*
>( aFirst )->Compare(
static_cast<const PCB_SHAPE*
>( aSecond ) ) == 0;
2290 return static_cast<const PCB_TEXT*
>( aFirst )->Compare(
static_cast<const PCB_TEXT*
>( aSecond ) ) == 0;
2301 return m_seen.insert( aItem ).second;
2329 std::vector<std::unique_ptr<PCB_SHAPE>> shapes;
2348 for(
const BLOCK_BASE* segBlock : segWalker )
2350 std::unique_ptr<PCB_SHAPE> shape;
2352 switch( segBlock->GetBlockType() )
2370 segBlock->GetBlockType() );
2384 shapes.push_back( std::move( shape ) );
2393 std::unique_ptr<PCB_SHAPE> shape = std::make_unique<PCB_SHAPE>( &aParent );
2396 shape->SetLayer( layer );
2403 shape->SetStart( cornerA );
2404 shape->SetEnd( cornerB );
2407 shape->Rotate( cornerA, angle );
2409 const int lineWidth = 0;
2410 shape->SetWidth( lineWidth );
2418 std::unique_ptr<PCB_SHAPE> shape = std::make_unique<PCB_SHAPE>( &aParent );
2421 shape->SetLayer( layer );
2428 shape->SetStart( cornerA );
2429 shape->SetEnd( cornerB );
2432 shape->Rotate( cornerA, angle );
2434 const int lineWidth = 0;
2435 shape->SetWidth( lineWidth );
2443 std::unique_ptr<PCB_SHAPE> shape = std::make_unique<PCB_SHAPE>( &aParent );
2446 shape->SetLayer( layer );
2452 if(
chain.PointCount() < 3 )
2454 wxLogTrace(
traceAllegroBuilder,
"Polygon (0x28) with key %#010x has fewer than 3 points, skipping",
2459 chain.SetClosed(
true );
2460 shape->SetPolyShape(
chain );
2462 const int lineWidth = 0;
2463 shape->SetWidth( lineWidth );
2472 std::vector<std::unique_ptr<PCB_SHAPE>> shapes;
2479 for(
const BLOCK_BASE* segBlock : segWalker )
2481 std::unique_ptr<PCB_SHAPE> shape = std::make_unique<PCB_SHAPE>( &
m_board );
2482 shape->SetLayer( layer );
2483 shape->SetWidth(
m_board.GetDesignSettings().GetLineThickness( layer ) );
2485 switch( segBlock->GetBlockType() )
2499 shape->SetCenter( c );
2500 shape->SetRadius(
radius );
2506 bool clockwise = ( arc.m_SubType & 0x40 ) != 0;
2514 EDA_ANGLE angle = endangle - startangle;
2516 if( clockwise && angle <
ANGLE_0 )
2519 if( !clockwise && angle >
ANGLE_0 )
2525 shape->SetArcGeometry( start, mid,
end );
2538 shape->SetStart( start );
2539 shape->SetEnd(
end );
2540 shape->SetWidth(
m_board.GetDesignSettings().GetLineThickness( layer ) );
2544 wxLogTrace(
traceAllegroBuilder,
" Unhandled segment type in outline: %#04x", segBlock->GetBlockType() );
2548 shapes.push_back( std::move( shape ) );
2557 uint32_t refKey = 0x00;
2575 FOOTPRINT& aFp,
const wxString& aPadName,
2576 int aNetcode,
bool aBackSide )
2582 std::vector<std::unique_ptr<BOARD_ITEM>> padItems;
2584 std::vector<std::unique_ptr<PADSTACK::COPPER_LAYER_PROPS>> copperLayers( aPadstack.
GetLayerCount() );
2587 std::optional<int> thermalGap;
2589 const wxString& padStackName =
m_brdDb.GetString( aPadstack.
m_PadStr );
2610 m_reporter.Report( wxString::Format(
"Padstack %s: Copper layer %zu has no pad component, but has "
2618 m_reporter.Report( wxString::Format(
"Copper layer %zu has no pad component, but has thermal relief",
2625 auto& layerCuProps = copperLayers[i];
2627 layerCuProps = std::make_unique<PADSTACK::COPPER_LAYER_PROPS>();
2660 if( padComp.
m_Z1.has_value() && padComp.
m_Z1.value() > 0 && minDim > 0 )
2661 layerCuProps->shape.round_rect_radius_ratio = padComp.
m_Z1.value() / (double) minDim;
2663 layerCuProps->shape.round_rect_radius_ratio = 0.25;
2675 if( padComp.
m_Z1.has_value() && padComp.
m_Z1.value() > 0 && minDim > 0 )
2676 layerCuProps->shape.chamfered_rect_ratio = padComp.
m_Z1.value() / (double) minDim;
2678 layerCuProps->shape.chamfered_rect_ratio = 0.25;
2690 layerCuProps->shape.chamfered_rect_ratio = 1.0 - 1.0 / sqrt( 2.0 );
2702 wxLogTrace(
traceAllegroBuilder,
"Padstack %s: SHAPE_SYMBOL on layer %zu has no 0x28 shape at %#010x",
2721 int anchorSize =
static_cast<int>(
2724 if( anchorSize < 1 )
2727 layerCuProps->shape.size =
VECTOR2I( anchorSize, anchorSize );
2729 std::shared_ptr<PCB_SHAPE> poly = std::make_shared<PCB_SHAPE>(
nullptr,
SHAPE_T::POLY );
2731 poly->SetFilled(
true );
2732 poly->SetWidth( 0 );
2733 layerCuProps->custom_shapes.push_back( poly );
2737 wxLogTrace(
traceAllegroBuilder,
"Padstack %s: SHAPE_SYMBOL on layer %zu produced only %d points",
2748 const int w = std::max( padComp.
m_W, 300 );
2749 const int h = std::max( padComp.
m_H, 220 );
2752 auto S = [&](
int x,
int y )
2758 outline.
Append(
S( 0, -h / 2 ) );
2759 outline.
Append(
S( w / 2, -h / 6 ) );
2760 outline.
Append(
S( w / 3, h / 2 ) );
2761 outline.
Append(
S( -w / 3, h / 2 ) );
2762 outline.
Append(
S( -w / 2, -h / 6 ) );
2767 int anchorSize =
static_cast<int>(
2770 if( anchorSize < 1 )
2773 layerCuProps->shape.size =
VECTOR2I( anchorSize, anchorSize );
2775 std::shared_ptr<PCB_SHAPE> poly = std::make_shared<PCB_SHAPE>(
nullptr,
SHAPE_T::POLY );
2777 poly->SetFilled(
true );
2778 poly->SetWidth( 0 );
2779 layerCuProps->custom_shapes.push_back( poly );
2783 m_reporter.Report( wxString::Format(
"Padstack %s: unhandled copper pad shape type %d on layer %zu",
2785 static_cast<int>( padComp.
m_Type ),
2796 "Padstack %s: copper layer %zu antipad shape %d differs from pad shape %d",
2800 int clearanceX =
scale( ( antiPadComp.
m_W - padComp.
m_W ) / 2 );
2801 int clearanceY =
scale( ( antiPadComp.
m_H - padComp.
m_H ) / 2 );
2803 if( clearanceX && clearanceX != clearanceY )
2805 wxLogTrace(
traceAllegroBuilder,
"Padstack %s: copper layer %zu unequal antipad clearance X=%d Y=%d",
2806 padStackName, i, clearanceX, clearanceY );
2811 wxLogTrace(
traceAllegroBuilder,
"Padstack %s: copper layer %zu antipad offset %d, %d", padStackName, i,
2815 layerCuProps->clearance = clearanceX;
2824 int gap =
scale( ( antiPadComp.
m_W - padComp.
m_W ) / 2 );
2833 thermalGap.has_value() ? wxString::Format(
"%d", thermalGap.value() )
2834 : wxString(
"N/A" ) );
2844 if( copperLayers.size() == 0 )
2850 const auto layersEqual =
2851 [&](
size_t aFrom,
size_t aTo) ->
bool
2855 for(
size_t i = aFrom + 1; i < aTo; ++i )
2857 if( !copperLayers[i - 1] || !copperLayers[i] || *copperLayers[i - 1] != *copperLayers[i] )
2866 for(
size_t i = 0; i < copperLayers.size(); ++i )
2867 wxLogTrace(
traceAllegroBuilder,
" Layer %zu: %s", i, copperLayers[i] ?
"present" :
"null" );
2871 if( copperLayers.front() && copperLayers.back() && layersEqual( 0, copperLayers.size() ) )
2876 layerProps = *copperLayers.front();
2878 else if( copperLayers.front() && copperLayers.back() && layersEqual( 1, copperLayers.size() - 1 ) )
2880 wxLogTrace(
traceAllegroBuilder,
" Using FRONT_INNER_BACK padstack mode (inner layers identical)" );
2886 if( copperLayers.size() > 2 && copperLayers[1] )
2894 for(
size_t i = 0; i < copperLayers.size(); ++i )
2896 if( !copperLayers[i] )
2899 const int count =
static_cast<int>( copperLayers.size() );
2903 if( aBackSide && count % 2 != 0 )
2925 if( std::holds_alternative<BLK_0x1C_PADSTACK::HEADER_v16x>( aPadstack.
m_Header ) )
2927 const auto& hdr16x = std::get<BLK_0x1C_PADSTACK::HEADER_v16x>( aPadstack.
m_Header );
2929 if( hdr16x.m_SlotY > 0 )
2931 drillW =
scale(
static_cast<int>( hdr16x.m_SlotX ) );
2932 drillH =
scale(
static_cast<int>( hdr16x.m_SlotY ) );
2941 const auto& hdr17x = std::get<BLK_0x1C_PADSTACK::HEADER_v17x>( aPadstack.
m_Header );
2943 if( hdr17x.m_SlotY > 0 )
2945 drillW =
scale(
static_cast<int>( hdr17x.m_SlotX ) );
2946 drillH =
scale(
static_cast<int>( hdr17x.m_SlotY ) );
2950 drillW =
scale(
static_cast<int>( hdr17x.m_DrillSize ) );
2967 bool drillIsTaller = ( drillH > drillW );
2969 if( padIsTaller != drillIsTaller )
2970 std::swap( drillW, drillH );
2973 bool isSmd = ( drillW == 0 ) || ( aPadstack.
GetLayerCount() == 1 );
2983 if( drillW != drillH )
2990 if( !isSmd && !aPadstack.
IsPlated() )
3005 if( isSmd && std::none_of( copperLayers.begin(), copperLayers.end(),
3006 [](
const auto& aProps ) { return aProps != nullptr; } ) )
3008 wxLogTrace(
traceAllegroBuilder,
"Padstack %s has no copper and no drill, skipping pad '%s'", padStackName,
3013 std::unique_ptr<PAD>
pad = std::make_unique<PAD>( &aFp );
3014 pad->SetPadstack( padStack );
3015 pad->SetNumber( aPadName );
3016 pad->SetNetCode( aNetcode );
3031 static_cast<uint8_t
>( boardIndex ) } );
3034 padLayer = aBackSide ?
m_board.FlipLayer( boardLayer ) : boardLayer;
3037 if( padLayer ==
F_Cu )
3041 else if( padLayer ==
B_Cu )
3044 pad->SetLayerSet(
LSET( { padLayer } ) );
3057 if( thermalGap.has_value() )
3058 pad->SetThermalGap( thermalGap.value() );
3072 pad->SetLayerSet(
pad->GetLayerSet().reset(
F_Mask ) );
3074 pad->SetLayerSet(
pad->GetLayerSet().reset(
B_Mask ) );
3081 pad->SetLayerSet(
pad->GetLayerSet().reset(
F_Mask ) );
3083 pad->SetLayerSet(
pad->GetLayerSet().reset(
B_Mask ) );
3097 i,
static_cast<int>( psComp.
m_Type ), psComp.
m_W, psComp.
m_H );
3100 padItems.push_back( std::move(
pad ) );
3108 if( aUnits == wxS(
"MM" ) )
3110 else if( aUnits == wxS(
"CM" ) )
3112 else if( aUnits == wxS(
"MICRONS" ) )
3114 else if( aUnits == wxS(
"MILS" ) )
3116 else if( aUnits == wxS(
"INCH" ) )
3119 return std::nullopt;
3127 std::optional<FIELD_VALUE> fileField =
3130 const wxString* fileValue = fileField.has_value() ? std::get_if<wxString>( &fileField.value() ) :
nullptr;
3133 return std::nullopt;
3135 wxString fileName = fileValue->BeforeFirst(
',' ).Trim(
true ).Trim(
false );
3137 if( fileName.IsEmpty() )
3138 return std::nullopt;
3141 model.m_Filename = fileName;
3143 std::optional<FIELD_VALUE> placementField =
3146 const wxString* placementValue =
3147 placementField.has_value() ? std::get_if<wxString>( &placementField.value() ) :
nullptr;
3149 if( !placementValue )
3152 wxArrayString tokens = wxSplit( *placementValue,
',',
'\0' );
3154 if( tokens.size() < 7 )
3156 wxLogTrace(
traceAllegroBuilder,
" Ignoring malformed 3D placement '%s'", *placementValue );
3160 const std::optional<double> toMm =
modelUnitToMm( tokens[0].Trim(
true ).Trim(
false ).Upper() );
3162 if( !toMm.has_value() )
3168 std::array<double, 6> placement{};
3170 for(
size_t i = 0; i < placement.size(); ++i )
3172 if( !tokens[i + 1].Trim(
true ).Trim(
false ).ToCDouble( &placement[i] ) )
3174 wxLogTrace(
traceAllegroBuilder,
" Ignoring malformed 3D placement '%s'", *placementValue );
3181 model.m_Offset =
VECTOR3D( placement[0] * *toMm, placement[1] * *toMm, placement[2] * *toMm );
3182 model.m_Rotation =
VECTOR3D( -placement[3], -placement[4], -placement[5] );
3190 std::unique_ptr<FOOTPRINT> fp = std::make_unique<FOOTPRINT>( &
m_board );
3194 const bool backSide = ( aFpInstance.
m_Layer != 0 );
3203 if( refDesStr.IsEmpty() )
3206 m_reporter.Report( wxString::Format(
"Empty ref des for 0x2D key %#010x", aFpInstance.
m_Key ),
3213 fp->SetReference( refDesStr );
3217 if( refDesStr.IsEmpty() )
3223 fp->SetPosition( fpPos );
3256 netCode = netIt->second->GetNetCode();
3267 std::vector<std::unique_ptr<BOARD_ITEM>> padItems =
buildPadItems( *padStack, *fp, padName, netCode, backSide );
3269 for( std::unique_ptr<BOARD_ITEM>& item : padItems )
3273 PAD*
pad =
static_cast<PAD*
>( item.get() );
3274 pad->SetFPRelativeOrientation( padLocalRot );
3277 item->SetFPRelativePosition( padLocalPos );
3279 if( padDedup.
IsFirst( item.get() ) )
3280 fp->Add( item.release() );
3290 fp->Rotate( fpPos, rotation );
3295 for(
BOARD_ITEM* placed : fp->GraphicalItems() )
3307 m_reporter.Report( wxString::Format(
"Unexpected type in graphics list: %#04x", aType ),
3313 std::vector<std::unique_ptr<PCB_SHAPE>> shapes =
buildShapes( graphics, *fp );
3315 for( std::unique_ptr<PCB_SHAPE>& shape : shapes )
3317 if( fpGraphics.
IsFirst( shape.get() ) )
3318 fp->Add( shape.release() );
3322 bool valueFieldSet =
false;
3334 const uint8_t textClass = strWrapper.m_Layer.m_Class;
3335 const uint8_t textSubclass = strWrapper.m_Layer.m_Subclass;
3348 if( !
text->GetText().IsEmpty() && !wxIsalpha(
text->GetText()[0] ) )
3349 text->SetText( wxString(
"UNK" ) +
text->GetText() );
3358 field->
SetText( wxS(
"${REFERENCE}" ) );
3364 if( !valueFieldSet )
3371 valueFieldSet =
true;
3406 fp->Add(
text.release() );
3413 for(
const BLOCK_BASE* assemblyBlock : assemblyWalker )
3415 std::vector<std::unique_ptr<BOARD_ITEM>> shapes =
buildGraphicItems( *assemblyBlock, *fp );
3417 for( std::unique_ptr<BOARD_ITEM>& item : shapes )
3419 if( fpGraphics.
IsFirst( item.get() ) )
3420 fp->Add( item.release() );
3430 for(
const BLOCK_BASE* areaBlock : areaWalker )
3434 if( layerInfo.has_value() &&
layerIsZone( *layerInfo ) )
3437 std::unique_ptr<ZONE> zone =
buildZone( *areaBlock, {}, zoneFillHandler, *fp );
3440 fp->Add( zone.release() );
3444 std::vector<std::unique_ptr<BOARD_ITEM>> shapes =
buildGraphicItems( *areaBlock, *fp );
3446 for( std::unique_ptr<BOARD_ITEM>& item : shapes )
3459 if( fpGraphics.
IsFirst( item.get() ) )
3460 fp->Add( item.release() );
3466 if( fp->Pads().size() != 2 )
3470 std::vector<std::set<wxString>> tieGroups;
3472 for(
PAD* padA : fp->Pads() )
3474 for(
PAD* padB : fp->Pads() )
3476 if( padA->GetNetCode() <= 0 || padB->GetNetCode() <= 0 || padA->GetNetCode() == padB->GetNetCode()
3477 || padA->GetPosition() != padB->GetPosition() )
3482 bool overlaps =
false;
3486 if( padA->GetEffectiveShape( layer )->Collide( padB->GetEffectiveShape( layer ).get() ) )
3496 std::set<wxString> merged{ padA->GetNumber(), padB->GetNumber() };
3498 for(
auto it = tieGroups.begin(); it != tieGroups.end(); )
3500 if( it->count( padA->GetNumber() ) || it->count( padB->GetNumber() ) )
3502 merged.insert( it->begin(), it->end() );
3503 it = tieGroups.erase( it );
3511 tieGroups.push_back( std::move( merged ) );
3515 for(
const std::set<wxString>&
group : tieGroups )
3519 for(
const wxString& number :
group )
3521 wxString escaped = number;
3523 escaped.Replace( wxS(
"\\" ), wxS(
"\\\\" ) );
3524 escaped.Replace( wxS(
"," ), wxS(
"\\," ) );
3526 if( !numbers.IsEmpty() )
3527 numbers += wxS(
"," );
3532 fp->AddNetTiePadGroup( numbers );
3534 m_reporter.Report( wxString::Format(
_(
"Footprint %s has stacked pads on different nets and is imported as a "
3545 std::vector<std::unique_ptr<BOARD_ITEM>> items;
3551 wxLogTrace(
traceAllegroBuilder,
"Skipping ANTI_ETCH track (class=%#04x, subclass=%#04x)",
3562 const uint8_t segType = block->GetBlockType();
3574 int width =
static_cast<int>( segInfo.
m_Width );
3576 std::unique_ptr<PCB_TRACK> seg = std::make_unique<PCB_TRACK>( &
m_board );
3578 seg->SetNetCode( aNetCode );
3579 seg->SetLayer( layer );
3581 seg->SetStart(
scale( start ) );
3583 seg->SetWidth(
scale( width ) );
3585 items.push_back( std::move( seg ) );
3595 int width =
scale(
static_cast<int>( arcInfo.
m_Width ) );
3597 bool clockwise = ( arcInfo.
m_SubType & 0x40 ) != 0;
3604 EDA_ANGLE angle = endAngle - startAngle;
3606 if( clockwise && angle <
ANGLE_0 )
3609 if( !clockwise && angle >
ANGLE_0 )
3615 std::unique_ptr<PCB_ARC> arc = std::make_unique<PCB_ARC>( &
m_board );
3617 arc->SetNetCode( aNetCode );
3618 arc->SetLayer( layer );
3620 arc->SetStart( start );
3623 arc->SetWidth( width );
3625 items.push_back( std::move( arc ) );
3646 std::unique_ptr<PCB_VIA>
via = std::make_unique<PCB_VIA>( &
m_board );
3647 via->SetPosition(
scale( viaPos ) );
3648 via->SetNetCode( aNetCode );
3666 int endLayer = startLayer + layerCount - 1;
3668 if( layerCount > 1 && layerCount < totalCu )
3672 const bool touchesOuter = ( startLayer == 0 ) || ( endLayer == totalCu - 1 );
3688 viaDrill = viaWidth / 2;
3689 const wxString& padstackName =
m_brdDb.GetString( viaPadstack->
m_PadStr );
3690 wxLogTrace(
traceAllegroBuilder,
"Via at (%d, %d): no drill in padstack '%s' key %#010x, using fallback %d",
3696 const wxString& padstackName =
m_brdDb.GetString( viaPadstack->
m_PadStr );
3697 wxLogTrace(
traceAllegroBuilder,
"Via at (%d, %d) in padstack '%s' key %#010x has no valid pad component, "
3698 "using drill-based fallback (%d * 2)",
3700 viaWidth = viaDrill * 2;
3703 via->SetWidth(
F_Cu, viaWidth );
3704 via->SetDrill( viaDrill );
3714 std::vector<BOARD_ITEM*> newItems;
3719 [
this]( uint8_t aType,
const BLOCK_BASE& aBlock )
3731 const int netCode = netIt->second->GetNetCode();
3736 [
this]( uint8_t aType,
const BLOCK_BASE& aBlock )
3746 for(
const BLOCK_BASE* connItemBlock : connWalker )
3748 const uint8_t connType = connItemBlock->GetBlockType();
3752 std::vector<std::unique_ptr<BOARD_ITEM>> newItemList;
3760 newItemList =
buildTrack( trackData, netCode );
3768 if( std::unique_ptr<BOARD_ITEM>
via =
buildVia( viaData, netCode ) )
3769 newItemList.push_back( std::move(
via ) );
3794 wxLogTrace(
traceAllegroBuilder,
" Unhandled connected item code: %#04x", (
int) connType );
3799 for( std::unique_ptr<BOARD_ITEM>& newItem : newItemList )
3801 stampIds( *newItem, connItemBlock->GetKey(), idSeq );
3802 newItems.push_back( newItem.get() );
3809 m_board.FinalizeBulkAdd( newItems );
3811 wxLogTrace(
traceAllegroBuilder,
"Finished creating %zu track/via items", newItems.size() );
3823 std::vector<std::unique_ptr<BOARD_ITEM>> newItems;
3829 switch( block->GetBlockType() )
3841 newItems.push_back( std::move( rectShape ) );
3855 for( std::unique_ptr<PCB_SHAPE>& shapeItem : shapeItems )
3858 newItems.push_back( std::move( shapeItem ) );
3864 wxLogTrace(
traceAllegroBuilder,
" Unhandled block type in outline walker: %#04x", block->GetBlockType() );
3874 for(
const BLOCK_BASE* block : outline2Walker )
3878 switch( block->GetBlockType() )
3889 newItems.push_back( std::move( rectShape ) );
3901 newItems.push_back( std::move( rectShape ) );
3914 for( std::unique_ptr<PCB_SHAPE>& shapeItem : shapeItems )
3917 newItems.push_back( std::move( shapeItem ) );
3922 wxLogTrace(
traceAllegroBuilder,
" Unhandled block type in outline walker: %#04x", block->GetBlockType() );
3940 std::vector<std::unique_ptr<PCB_SHAPE>> graphicItems =
buildShapes( graphicContainer,
m_board );
3943 for( std::unique_ptr<PCB_SHAPE>& item : graphicItems )
3945 stampIds( *item, graphicContainer.m_Key, idSeq );
3946 newItems.push_back( std::move( item ) );
3952 std::vector<BOARD_ITEM*> addedItems;
3955 for( std::unique_ptr<BOARD_ITEM>& item : newItems )
3963 addedItems.push_back( item.get() );
3967 m_board.FinalizeBulkAdd( addedItems );
3985 return cacheIt->second;
3990 uint32_t currentKey = aStartKey;
3993 static constexpr int MAX_CHAIN_LENGTH = 50000;
3996 while( currentKey != 0 && visited < MAX_CHAIN_LENGTH )
4020 outline.
Append( shapeArc );
4024 bool clockwise = ( arc.m_SubType & 0x40 ) != 0;
4031 EDA_ANGLE arcAngle = endAngle - startAngle;
4033 if( clockwise && arcAngle <
ANGLE_0 )
4036 if( !clockwise && arcAngle >
ANGLE_0 )
4047 outline.
Append( shapeArc );
4050 currentKey = arc.m_Next;
4065 currentKey = seg.m_Next;
4084 VECTOR2I topRight{ botRight.x, topLeft.
y };
4085 VECTOR2I botLeft{ topLeft.
x, botRight.y };
4087 outline.
Append( topLeft );
4088 outline.
Append( topRight );
4089 outline.
Append( botRight );
4090 outline.
Append( botLeft );
4093 outline.
Rotate( angle, topLeft );
4095 for(
int i = 0; i < outline.
PointCount(); i++ )
4108 VECTOR2I topRight{ botRight.x, topLeft.
y };
4109 VECTOR2I botLeft{ topLeft.
x, botRight.y };
4111 outline.
Append( topLeft );
4112 outline.
Append( topRight );
4113 outline.
Append( botRight );
4114 outline.
Append( botLeft );
4117 outline.
Rotate( angle, topLeft );
4119 for(
int i = 0; i < outline.
PointCount(); i++ )
4149 while( holeKey != 0 )
4163 polySet.
AddHole( holeOutline );
4166 holeKey = keepout.m_Next;
4185 chain.SetClosed(
true );
4195 chain.SetClosed(
true );
4205 chain.SetClosed(
true );
4225 const std::vector<const BLOCK_BASE*>& aRelatedBlocks,
4258 wxLogTrace(
traceAllegroBuilder,
" Skipping shape on layer %#02x:%#02x - unmapped copper layer",
4268 xform = fp->GetTransform();
4274 wxLogTrace(
traceAllegroBuilder,
" Skipping zone with type %#04x, key %#010x - failed to build outline",
4279 std::unique_ptr<ZONE> zone = std::make_unique<ZONE>( &aParent );
4284 zone->SetLayer( layer );
4297 zone->SetIsRuleArea(
true );
4298 zone->SetLayerSet( layerSet );
4299 zone->SetDoNotAllowTracks( isRouteKeepout );
4300 zone->SetDoNotAllowVias( isViaKeepout );
4301 zone->SetDoNotAllowZoneFills( isRouteKeepout || isViaKeepout );
4302 zone->SetDoNotAllowPads(
false );
4303 zone->SetDoNotAllowFootprints( isPackageKeepout );
4309 zone->SetZoneName(
"Route Keepin" );
4310 else if( isPackageKeepin )
4311 zone->SetZoneName(
"Package Keepin" );
4316 for(
const BLOCK_BASE* block : aRelatedBlocks )
4321 switch( block->GetBlockType() )
4325 const auto it =
m_netCache.find( block->GetKey() );
4330 aBoundaryBlock.
GetKey(), it->second->GetNetname(), it->second->GetNetCode() );
4332 netCode = it->second->GetNetCode();
4336 m_reporter.Report( wxString::Format(
"Could not find net key %#010x in cache for BOUNDARY %#010x",
4337 block->GetKey(), aBoundaryBlock.
GetKey() ),
4347 combinedFill.
Append( fillPolySet );
4357 zone->SetNetCode( netCode );
4360 zone->AddPolygon(
chain );
4363 if( isCopperZone && !combinedFill.
IsEmpty() )
4377 zone->SetIsFilled(
true );
4378 zone->SetNeedRefill(
false );
4391 std::vector<const BLOCK_BASE*> ret;
4404 if( !ptrArray || ptrArray->
m_Count == 0 )
4407 const size_t count = std::min( std::min( ptrArray->
m_Count, ptrArray->
m_Capacity ), 100u );
4408 ret.resize( count );
4410 for(
size_t i = 0; i < count; i++ )
4431 if( strWrapper.GetGroupPtr() != 0 )
4452template <std::derived_from<BOARD_ITEM> T>
4455 std::vector<BOARD_ITEM*> rawPointers;
4456 rawPointers.reserve( aItems.size() );
4458 for( std::unique_ptr<T>& item : aItems )
4460 rawPointers.push_back( item.get() );
4472 std::vector<std::unique_ptr<ZONE>> newZones;
4473 std::vector<std::unique_ptr<ZONE>> keepoutZones;
4483 std::unique_ptr<ZONE> zone;
4486 switch( block->GetBlockType() )
4518 layerInfo = shapeData.
m_Layer;
4523 wxLogTrace(
traceAllegroBuilder,
"Unhandled block type in zone shape walker: %#04x, key: %#010x",
4524 block->GetBlockType(), block->GetKey() );
4531 wxLogTrace(
traceAllegroBuilder,
" Zone %#010x net=%d layer=%s class=%#04x:%#04x", block->GetKey(),
4532 zone->GetNetCode(),
m_board.GetLayerName( zone->GetFirstLayer() ), layerInfo.m_Class,
4533 layerInfo.m_Subclass );
4535 stampIds( *zone, block->GetKey() );
4536 newZones.push_back( std::move( zone ) );
4543 for(
const BLOCK_BASE* block : keepoutWalker )
4545 std::unique_ptr<ZONE> zone;
4547 switch( block->GetBlockType() )
4581 stampIds( *zone, block->GetKey() );
4582 newZones.push_back( std::move( zone ) );
4589 int originalCount = newZones.size();
4598 int mergedCount = mergedZones.size();
4600 int keepoutCount = 0;
4601 int boundaryCount = 0;
4603 for(
const std::unique_ptr<ZONE>& zone : mergedZones )
4605 if( zone->GetIsRuleArea() )
4613 wxLogTrace(
traceAllegroBuilder,
"Created %d zone outlines and %d keepout areas (%d merged away), ", boundaryCount,
4614 keepoutCount, originalCount - mergedCount );
4624 if( voids.IsEmpty() )
4630 std::unique_ptr<ZONE> area = std::make_unique<ZONE>( &
m_board );
4632 area->SetIsRuleArea(
true );
4633 area->SetLayerSet(
LSET( { layer } ) );
4634 area->SetDoNotAllowZoneFills(
true );
4635 area->SetDoNotAllowTracks(
false );
4636 area->SetDoNotAllowVias(
false );
4637 area->SetDoNotAllowPads(
false );
4638 area->SetDoNotAllowFootprints(
false );
4639 area->SetZoneName( wxS(
"Plane void" ) );
4643 m_board.Add( area.release() );
4664 const wxString& tableName =
m_brdDb.GetString( tableData.m_StringPtr );
4666 std::vector<std::unique_ptr<BOARD_ITEM>> newItems;
4670 for(
const BLOCK_BASE* keyTable : keyTableWalker )
4672 wxLogTrace(
traceAllegroBuilder,
" Table '%s' (key %#010x, table block key %#010x)", tableName,
4673 tableData.m_Key, tableData.m_Ptr1 );
4677 wxLogTrace(
traceAllegroBuilder,
" Key table pointer %#010x is invalid", tableData.m_Ptr1 );
4681 switch( keyTable->GetBlockType() )
4687 uint32_t count = std::min( ptrArray.
m_Count,
static_cast<uint32_t
>( ptrArray.
m_Ptrs.size() ) );
4689 wxLogTrace(
traceAllegroBuilder,
" Pointer array with %zu entries",
static_cast<size_t>( count ) );
4691 for( uint32_t ptrIndex = 0; ptrIndex < count; ptrIndex++ )
4693 uint32_t ptrKey = ptrArray.
m_Ptrs[ptrIndex];
4709 newItems.push_back( std::move( newItem ) );
4726 keyTable->GetBlockType() );
4732 if( newItems.size() > 0 )
4734 wxLogTrace(
traceAllegroBuilder,
" Creating group '%s' with %zu items", tableName, newItems.size() );
4736 std::unique_ptr<PCB_GROUP>
group = std::make_unique<PCB_GROUP>( &
m_board );
4737 group->SetName( tableName );
4741 for(
const std::unique_ptr<BOARD_ITEM>& item : newItems )
4743 stampIds( *item, tableData.m_Key, idSeq );
4744 group->AddItem( item.get() );
4748 newItems.push_back( std::move(
group ) );
4771 int copperShapeCount = 0;
4772 int teardropCount = 0;
4790 const bool isDynCopperShape = ( fill.shape->m_Unknown2.value_or( 0 ) & 0x1000 ) != 0;
4792 if( isDynCopperShape )
4794 std::unique_ptr<ZONE> zone = std::make_unique<ZONE>( &
m_board );
4797 zone->SetLayer( fill.layer );
4798 zone->SetNetCode( fill.netCode );
4799 zone->SetLocalClearance( 0 );
4805 zone->AddPolygon(
chain );
4807 zone->SetFilledPolysList( fill.layer, fractured );
4808 zone->SetIsFilled(
true );
4809 zone->SetNeedRefill(
false );
4810 zone->CalculateFilledArea();
4816 else if(
m_layerMapper->IsPlaneLayer( fill.shape->m_Layer ) )
4820 std::unique_ptr<ZONE> zone = std::make_unique<ZONE>( &
m_board );
4822 zone->SetLayer( fill.layer );
4823 zone->SetNetCode( fill.netCode );
4826 zone->SetLocalClearance( 0 );
4827 zone->SetMinThickness( 0 );
4828 zone->Outline()->AddPolygon( poly );
4829 zone->SetNeedRefill(
true );
4838 shape->SetPolyShape( fractured );
4839 shape->SetFilled(
true );
4840 shape->SetLayer( fill.layer );
4841 shape->SetNetCode( fill.netCode );
4847 stampIds( *shape, fillKey, idSeq );
4854 wxLogTrace(
traceAllegroPerf, wxT(
" applyZoneFills unmatched loop: %.3f ms (%d shapes, %d teardrops)" ),
4855 fillTimer.
msecs(
true ), copperShapeCount, teardropCount );
4861 std::unordered_map<int, std::vector<ZONE*>> teardropsByNet;
4865 if( zone->IsTeardropArea() )
4866 teardropsByNet[zone->GetNetCode()].push_back( zone );
4869 if( teardropsByNet.empty() )
4877 for(
PAD*
pad : fp->Pads() )
4879 auto it = teardropsByNet.find(
pad->GetNetCode() );
4881 if( it == teardropsByNet.end() )
4884 for(
ZONE* tdZone : it->second )
4891 pad->SetTeardropsEnabled(
true );
4905 auto it = teardropsByNet.find(
via->GetNetCode() );
4907 if( it == teardropsByNet.end() )
4910 for(
ZONE* tdZone : it->second )
4917 via->SetTeardropsEnabled(
true );
4924 wxLogTrace(
traceAllegroBuilder,
"Enabled teardrops on %d pads and %d vias", padCount, viaCount );
5006 std::vector<BOARD_ITEM*> bulkAddedItems;
5008 THROTTLE refreshThrottle( std::chrono::milliseconds( 100 ) );
5015 [
this, &fpBlock]( uint8_t aType,
const BLOCK_BASE& )
5017 m_reporter.Report( wxString::Format(
"Unexpected object of type %#04x found in footprint %#010x",
5034 fp->SetFPID( fpId );
5036 if( model3D.has_value() )
5037 fp->Models().push_back( *model3D );
5040 bulkAddedItems.push_back( fp.get() );
5045 m_reporter.Report( wxString::Format(
"Failed to construct footprint for 0x2D key %#010x", inst.m_Key ),
5054 wxLogTrace(
traceAllegroPerf, wxT(
" convertFootprints (%zu footprints): %.3f ms" ),
5055 bulkAddedItems.size(), buildTimer.
msecs(
true ) );
5057 if( !bulkAddedItems.empty() )
5058 m_board.FinalizeBulkAdd( bulkAddedItems );
static std::unordered_set< LAYER_INFO > ScanForLayers(const BRD_DB &aDb)
Look through some lists for a list of layers used.
static std::optional< LAYER_INFO > tryLayerFromBlock(const BLOCK_BASE &aBlock)
Some blocks report layer info - if they do, return it else std::nullopt.
static PCB_LAYER_ID nthCopperLayerId(int aIndex, int aTotal)
Map a 0-based copper index (0 = F_Cu, aTotal-1 = B_Cu) to a KiCad copper layer.
static wxString layerInfoDisplayName(const LAYER_INFO &aLayerInfo)
Build a unique display name for a LAYER_INFO entry from the static maps above, suitable for presentat...
static bool layerIsZone(const LAYER_INFO &aLayerInfo)
Some layers map to KiCad rule areas (zones) - for example a package keepout on ALL maps to a rule are...
static EDA_ANGLE fromMillidegrees(uint32_t aMilliDegrees)
#define BLK_FIELD(BLK_T, FIELD)
static std::optional< FP_3DMODEL > build3DModel(const BRD_DB &aDb, const BLK_0x2B_FOOTPRINT_DEF &aFpDef)
static const std::unordered_map< LAYER_INFO, PCB_LAYER_ID > s_LayerKiMap
Map of the pre-set class:subclass pairs to standard layers.
static const std::unordered_map< LAYER_INFO, wxString > s_OptionalFixedMappings
Names for custom KiCad layers that correspond to pre-defined Allegro layers.
void BulkAddToBoard(BOARD &aBoard, std::vector< std::unique_ptr< T > > &&aItems)
static uint32_t PadGetNextInFootprint(const BLOCK_BASE &aBlock)
"Get Next" function for the pad list in a footprint's 0x32 list.
LAYER_INFO expectLayerFromBlock(const BLOCK_BASE &aBlock)
Get a layer from a block that has layer info.
static int graphicNetCode(const BOARD_ITEM &aItem)
static int clampForScale(double aValue)
static std::optional< double > modelUnitToMm(const wxString &aUnits)
static constexpr uint32_t LAYER_PROP_PLANE
Layer list property bit of a negative plane layer.
Utility functions that operate over BRD_DBs and BLOCKs.
constexpr int ARC_HIGH_DEF
constexpr EDA_IU_SCALE pcbIUScale
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
The base class for all blocks in the main body of an Allegro file.
uint8_t GetBlockType() const
This is the actual type code as read from the file.
Rejects graphics that repeat one already accepted into the same container.
bool IsFirst(const BOARD_ITEM *aItem)
True when this graphic has not been seen before, and records it.
std::unordered_set< const BOARD_ITEM *, GRAPHIC_KEY_HASH, GRAPHIC_KEY_EQ > m_seen
VECTOR2I scale(const VECTOR2I &aVector) const
wxString resolveMatchGroupName(const BLK_0x1B_NET &aNet) const
Follow m_MatchGroupPtr through the 0x26/0x2C pointer chain to get the match group name for a NET.
void createPlaneVoidAreas()
LAYER_MAPPING_HANDLER m_layerMappingHandler
PROGRESS_REPORTER * m_progressReporter
std::map< PCB_LAYER_ID, SHAPE_POLY_SET > m_planeVoids
void reportUnexpectedBlockType(uint8_t aGot, uint8_t aExpected, uint32_t aKey=0, size_t aOffset=0, const wxString &aName=wxEmptyString) const
const BLK_0x07_COMPONENT_INST * getFpInstRef(const BLK_0x2D_FOOTPRINT_INST &aFpInstance) const
Look up 0x07 FP instance data (0x07) for a given 0x2D FP instance.
SHAPE_POLY_SET tryBuildZoneShape(const BLOCK_BASE &aBlock, const TRANSFORM_TRS &aXform=TRANSFORM_TRS()) const
Try to build a zone shape for the given block, with holes.
std::vector< const BLOCK_BASE * > getShapeRelatedBlocks(const BLK_0x28_SHAPE &aShape) const
Get blocks that are related to the BOUNDARY shape, i.e.
VECTOR2I scaleSize(const VECTOR2I &aSize) const
PCB_LAYER_ID getLayer(const LAYER_INFO &aLayerInfo) const
std::unordered_map< uint32_t, SHAPE_LINE_CHAIN > m_segChainCache
std::vector< std::unique_ptr< PCB_SHAPE > > buildShapes(const BLK_0x14_GRAPHIC &aGraphicList, BOARD_ITEM_CONTAINER &aParent)
Build the shapes from an 0x14 shape list.
static void stampIds(BOARD_ITEM &aItem, uint32_t aKey, uint32_t &aSeq)
Give aItem and its children ids derived from the Allegro block they came from.
GRAPHIC_DEDUP m_boardGraphics
Coincidence filter for everything added straight to the board, which is one container.
BOARD_BUILDER(const BRD_DB &aBrdDb, BOARD &aBoard, REPORTER &aReporter, PROGRESS_REPORTER *aProgressReporter, const LAYER_MAPPING_HANDLER &aLayerMappingHandler)
std::unique_ptr< LAYER_MAPPER > m_layerMapper
const T * expectBlockByKey(uint32_t aKey) const
Get a block by its key, and check that it is of the expected type.
std::vector< std::unique_ptr< BOARD_ITEM > > buildDrillMarker(const BLK_0x0C_PIN_DEF &aPinDef, BOARD_ITEM_CONTAINER &aParent)
Build a drill marker from a 0x0C PIN_DEF block.
std::unique_ptr< PCB_SHAPE > buildRect(const BLK_0x24_RECT &aRect, BOARD_ITEM_CONTAINER &aParent)
Build a rectangular shape from a 0x24 RECT block.
std::vector< std::unique_ptr< PCB_SHAPE > > buildPolygonShapes(const BLK_0x28_SHAPE &aShape, BOARD_ITEM_CONTAINER &aParent)
Build graphics from an 0x28 SHAPE, with separate items per segment/arc.
SHAPE_POLY_SET shapeToPolySet(const BLK_0x28_SHAPE &aShape, const TRANSFORM_TRS &aXform=TRANSFORM_TRS()) const
std::unique_ptr< PCB_SHAPE > buildArc(const BLK_0x01_ARC &aArc, const LAYER_INFO &aLayerInfo, PCB_LAYER_ID aLayer, BOARD_ITEM_CONTAINER &aParent)
std::unique_ptr< PCB_TEXT > buildPcbText(const BLK_0x30_STR_WRAPPER &aStrWrapper, BOARD_ITEM_CONTAINER &aParent)
std::unique_ptr< FOOTPRINT > buildFootprint(const BLK_0x2D_FOOTPRINT_INST &aFpInstance)
std::vector< std::unique_ptr< BOARD_ITEM > > buildPadItems(const BLK_0x1C_PADSTACK &aPadstack, FOOTPRINT &aFp, const wxString &aPadName, int aNetcode, bool aBackSide)
Construct "pad" items for a given 0x1C PADSTACK block.
void reportMissingBlock(uint32_t aKey, uint8_t aType) const
std::unordered_map< uint32_t, NETINFO_ITEM * > m_netCache
void applyConstraintSets()
void applyNetConstraints()
std::unique_ptr< PCB_SHAPE > buildLineSegment(const BLK_0x15_16_17_SEGMENT &aSegment, const LAYER_INFO &aLayerInfo, PCB_LAYER_ID aLayer, BOARD_ITEM_CONTAINER &aParent)
Build a single line segment.
std::vector< std::unique_ptr< BOARD_ITEM > > buildTrack(const BLK_0x05_TRACK &aBlock, int aNetcode)
std::vector< const BLK_0x36_DEF_TABLE::FontDef_X08 * > m_fontDefList
std::unordered_map< uint32_t, ZoneFillEntry > m_zoneFillShapes
wxString get0x30StringValue(uint32_t a0x30Key) const
Get just the string value from a 0x31 STRING WRAPPER -> 0x30 STRING GRAPHIC pair.
const BLK_0x36_DEF_TABLE::FontDef_X08 * getFontDef(unsigned aIndex) const
Get the font definition for a given index in a 0x30, etc.
std::vector< std::unique_ptr< BOARD_ITEM > > buildGraphicItems(const BLOCK_BASE &aBlock, BOARD_ITEM_CONTAINER &aParent)
Build a list of graphic items, e.g.
std::unique_ptr< BOARD_ITEM > buildVia(const BLK_0x33_VIA &aBlock, int aNetcode)
void enablePadTeardrops()
std::unique_ptr< PCB_SHAPE > buildPolygon(const BLK_0x28_SHAPE &aShape, BOARD_ITEM_CONTAINER &aParent)
Build a graphic polygon from a 0x28 SHAPE block.
wxString resolveConstraintSetNameFromField(uint32_t aFieldKey) const
Extract constraint set name from a 0x03 FIELD block pointer.
std::unordered_set< uint32_t > m_usedZoneFillShapes
SHAPE_LINE_CHAIN buildOutline(const BLK_0x0E_RECT &aRect, const TRANSFORM_TRS &aXform=TRANSFORM_TRS()) const
SHAPE_LINE_CHAIN buildSegmentChain(uint32_t aStartKey, const TRANSFORM_TRS &aXform=TRANSFORM_TRS()) const
Walk a geometry chain (0x01 arcs and 0x15-17 segments) starting from the given key,...
std::unique_ptr< ZONE > buildZone(const BLOCK_BASE &aBoundaryBlock, const std::vector< const BLOCK_BASE * > &aRelatedBlocks, ZONE_FILL_HANDLER &aZoneFillHandler, BOARD_ITEM_CONTAINER &aParent)
Build a ZONE from an 0x0E, 0x24 or 0x28 block.
An Allegro board database representing the contents of a .brd (and presumably .dra) file.
std::unique_ptr< FILE_HEADER > m_Header
Class to handle the mapping for Allegro CLASS/SUBCLASS idiom to KiCad layers.
PCB_LAYER_ID GetPlaceBounds(bool aTop)
Allegro puts more graphics than just the polygon on PBT/B, but we don't want to always make a static ...
int GetEtchLayerCount() const
Return whether this layer ID is something we mapped to, or the catch-all unmapped layer.
void FinalizeLayers()
Called after all the custom layers are loaded.
void ProcessLayerList(uint8_t aClass, const BLK_0x2A_LAYER_LIST &aList)
LAYER_MAPPER(const BRD_DB &aRawBoard, BOARD &aBoard, const LAYER_MAPPING_HANDLER &aLayerMappingHandler)
PCB_LAYER_ID addUserLayer(const wxString &aName)
std::unordered_map< LAYER_INFO, wxString > m_customLayerDialogNames
Names used in the layer mapping dialog for custom (non-ETCH, non-static) layers.
static PCB_LAYER_ID getNthUserLayer(int aNum)
std::unordered_map< const BLK_0x2A_LAYER_LIST *, std::vector< CUSTOM_LAYER > > m_Lists
PCB_LAYER_ID mapCustomLayerByName(const wxString &aLayerName)
Create or find a mapped layer with a given name, but not specifically bound to a specific class:subcl...
LSET GetRuleAreaLayers(const LAYER_INFO &aLayerInfo)
std::unordered_map< LAYER_INFO, PCB_LAYER_ID > m_staticLayerOverrides
Overrides for the static s_LayerKiMap entries, populated by the layer mapping handler.
std::unordered_map< wxString, PCB_LAYER_ID > m_MappedOptionalLayers
This is a map of optional, Allegro layers that we have mapped to KiCad layers with given names.
PCB_LAYER_ID GetLayer(const LAYER_INFO &aLayerInfo)
bool IsOutlineLayer(const LAYER_INFO &aLayerInfo) const
Resolve the subclass name for a given class:subclass pair using the per-class custom layer list.
bool IsLayerMapped(PCB_LAYER_ID aLayerId) const
std::unordered_map< LAYER_INFO, int > m_unknownLayers
A record of what we failed to map.
std::unordered_map< uint8_t, std::vector< CUSTOM_LAYER > * > m_ClassCustomLayerLists
bool IsPlaneLayer(const LAYER_INFO &aLayerInfo) const
Plane layers are drawn as negatives, so a line on one is a void and not copper.
static PCB_LAYER_ID getNthCopperLayer(int aNum, int aTotal)
std::unordered_map< LAYER_INFO, PCB_LAYER_ID > m_customLayerToKiMap
The main map from CLASS:SUBCLASS custom mappings to KiCadLayers.
PCB_LAYER_ID m_unmappedLayer
PCB_LAYER_ID MapCustomLayer(const LAYER_INFO &aLayerInfo, const wxString &aLayerName)
Record a specific class:subclass layer as mapping to some KiCad user layer, with a given name.
const LAYER_MAPPING_HANDLER & m_layerMappingHandler
Range-for-compatible walker over a linked list of BLOCK_BASE objects in a BRD_DB.
Range-for-compatible walker that yields only typed data from a linked list.
void SetMismatchReporter(MISMATCH_REPORTER aReporter)
Priority task dispatcher for zone fills - we want to do the biggest ones first.
COMPLEX_FIRST_FILL_TASK(bool aSimplify)
int computePriorityKey(const FILL_INFO &a) const override
size_t task(FILL_INFO &fillInfo) override
Filled zones have their own outline and the fill itself comes from a bunch of "related" spaces.
void ProcessPolygons(bool aSimplify)
Process the polygons in a thread pool for more fans, more faster.
void QueuePolygonForZone(ZONE &aZone, SHAPE_POLY_SET aFilledArea, PCB_LAYER_ID aLayer)
std::vector< FILL_INFO > m_FillInfos
Container for design settings for a BOARD object.
std::shared_ptr< NET_SETTINGS > m_NetSettings
Abstract interface for BOARD_ITEMs capable of storing other items inside.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
void SetUuidDirect(const KIID &aUuid)
Raw UUID assignment.
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
virtual void RunOnChildren(const std::function< void(BOARD_ITEM *)> &aFunction, RECURSE_MODE aMode) const
Invoke a function on all children.
Information pertinent to a Pcbnew printed circuit board.
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
void FinalizeBulkAdd(std::vector< BOARD_ITEM * > &aNewItems)
Must be used if Add() is used using a BULK_x ADD_MODE to generate a change event for listeners.
constexpr size_type GetWidth() const
constexpr size_type GetHeight() const
KICAD_T Type() const
Returns the type of object.
virtual void SetFilled(bool aFlag)
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
virtual void SetVisible(bool aVisible)
virtual void SetText(const wxString &aText)
static KIID FromName(const std::string &aName)
Return a KIID derived from a name, the same name always gives the same KIID.
A logical library item identifier and consists of various portions much like a URI.
int SetLibItemName(const UTF8 &aLibItemName)
Override the library item name portion of the LIB_ID to aLibItemName.
static UTF8 FixIllegalChars(const UTF8 &aLibItemName, bool aLib)
Replace illegal LIB_ID item name characters with underscores '_'.
LSET is a set of PCB_LAYER_IDs.
static const LSET & AllCuMask()
return AllCuMask( MAX_CU_LAYERS );
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
static LSET AllCuMask(int aCuLayerCount)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
static const LSET & AllLayersMask()
A collection of nets and the parameters used to route or test these nets.
static const char Default[]
the name of the default NETCLASS
int GetDiffPairGap() const
bool HasDiffPairWidth() const
const wxString GetName() const
Gets the name of this (maybe aggregate) netclass in a format for internal usage or for export to exte...
bool HasTrackWidth() const
int GetDiffPairWidth() const
bool HasDiffPairGap() const
int GetTrackWidth() const
bool HasClearance() const
Handle the data for a net.
const wxString & GetNetname() const
void SetNetClass(const std::shared_ptr< NETCLASS > &aNetClass)
static const int UNCONNECTED
Constant that holds the "unconnected net" number (typically 0) all items "connected" to this net are ...
A PADSTACK defines the characteristics of a single or multi-layer pad, in the IPC sense of the word.
COPPER_LAYER_PROPS & CopperLayer(PCB_LAYER_ID aLayer)
std::vector< PCB_LAYER_ID > UniqueLayers() const
@ NORMAL
Shape is the same on all layers.
@ CUSTOM
Shapes can be defined on arbitrary layers.
@ FRONT_INNER_BACK
Up to three shapes can be defined (F_Cu, inner copper layers, B_Cu)
void SetLayerSet(const LSET &aSet)
static LSET PTHMask()
layer set for a through hole pad
static LSET UnplatedHoleMask()
layer set for a mechanical unplated through hole pad
static LSET SMDMask()
layer set for a SMD pad on Front layer
int GetWidth() const override
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
void SetTextAngle(const EDA_ANGLE &aAngle) override
PRIORITY_THREAD_POOL_TASK()
size_t Execute(ContainerT &aItems)
Call this to execute the task on all items in aItems, using the thread pool and dispatching the tasks...
A small class to help profiling.
double msecs(bool aSinceLast=false)
A progress reporter interface for use in multi-threaded environments.
A pure virtual class used to derive REPORTER objects from.
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
void Move(const VECTOR2I &aVector) override
void SetPoint(int aIndex, const VECTOR2I &aPos)
Move a point to a specific location.
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
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.
void Rotate(const EDA_ANGLE &aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Rotate all vertices by a given angle.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
const VECTOR2I & CLastPoint() const
Return the last point in the line chain.
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 ClearArcs()
Removes all arc references from all the outlines and holes in the polyset.
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index.
bool IsEmpty() const
Return true if the set is empty (no polygons at all)
int TotalVertices() const
Return total number of vertices stored in the set.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
void Simplify()
Simplify the polyset (merges overlapping polys, eliminates degeneracy/self-intersections)
std::vector< SHAPE_LINE_CHAIN > POLYGON
represents a single polygon outline with holes.
int AddHole(const SHAPE_LINE_CHAIN &aHole, int aOutline=-1)
Adds a new hole to the given outline (default: last) and returns its index.
void BooleanIntersection(const SHAPE_POLY_SET &b)
Perform boolean polyset intersection.
int OutlineCount() const
Return the number of outlines in the set.
void Fracture(bool aSimplify=true)
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
bool Contains(const VECTOR2I &aP, int aSubpolyIndex=-1, int aAccuracy=0, bool aUseBBoxCaches=false) const
Return true if a given subpolygon contains the point aP.
const POLYGON & CPolygon(int aIndex) const
const std::vector< POLYGON > & CPolygons() const
Simple container to manage line stroke parameters.
Rate-limiter that fires at most once per interval.
const std::string Format() const
Return the vector formatted as a string.
Handle a list of polygons defining a copper zone.
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
virtual PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
SHAPE_POLY_SET * Outline()
void SetFilledPolysList(PCB_LAYER_ID aLayer, const SHAPE_POLY_SET &aPolysList)
Set the list of filled polygons.
SHAPE_POLY_SET GetBoardOutline() const
static wxString displayName(const DATABASE_LIB_TABLE &aTable)
const int minSize
Push and Shove router track width and via size dialog.
static constexpr EDA_ANGLE ANGLE_0
static constexpr EDA_ANGLE ANGLE_90
static constexpr EDA_ANGLE FULL_CIRCLE
static constexpr EDA_ANGLE ANGLE_360
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
int GetPenSizeForNormal(int aTextSize)
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
#define THROW_IO_ERRORF(msg,...)
static const wxChar *const traceAllegroBuilder
Flag to enable debug output of Allegro board construction.
static constexpr void hash_combine(std::size_t &seed)
This is a dummy function to take the final case of hash_combine below.
wxString LayerName(int aLayer)
Returns the default display name for a given layer.
#define MAX_USER_DEFINED_LAYERS
bool IsUserLayer(PCB_LAYER_ID aLayerId)
Test whether a layer is a non copper and a non tech layer.
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
PCB_LAYER_ID
A quick note on layer IDs:
PCB_LAYER_ID ToLAYER_ID(int aLayer)
@ LEFT_RIGHT
Flip left to right (around the Y axis)
@ THROW
THROW_IO_ERROR on mismatch.
@ LOG_TRACE
wxLogTrace the mismatch and skip
@ REPORT
invoke a user-supplied callback, then skip
std::optional< FIELD_VALUE > GetFirstFieldOfType(const BRD_DB &aDb, uint32_t aFieldsPtr, uint32_t aEndKey, uint16_t aFieldCode)
Look up the first 0x03 FIELD value of a given type in a linked field chain.
std::optional< int > GetFirstFieldOfTypeInt(const BRD_DB &aDb, uint32_t aFieldsPtr, uint32_t aEndKey, uint16_t aFieldCode)
Convenience wrapper around GetFirstFieldOfType() for integer-valued fields.
wxString DecodeEscapedIdentifiers(const wxString &aName)
Remove the backslash wrapper Cadence puts around an identifier that holds special characters.
@ MODEL_3D_PLACEMENT
3D model units, XYZ offset and XYZ rotation
@ MODEL_3D_FILE
3D model file name, size, mtime and display colour
@ PHYS_CONSTRAINT_SET
Physical Constraint Set assignment.
const BLK_T & BlockDataAs(const BLOCK_BASE &aBlock)
Cast a BLOCK_BASE to a typed BLOCK<T> and return the data.
std::vector< VECTOR2I > MakeRegularPolygonPoints(const VECTOR2I &aCenter, size_t aN, const VECTOR2I &aPt0)
Get the corners of a regular polygon from the centre, one point and the number of sides.
std::vector< SEG > MakeCrossSegments(const VECTOR2I &aCenter, const VECTOR2I &aSize, EDA_ANGLE aAngle)
Create the two segments for a cross.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
@ SMD
Smd pad, appears on the solder paste layer (default)
@ PTH
Plated through hole pad.
Class to handle a set of BOARD_ITEMs.
static const wxChar *const traceAllegroPerf
std::function< std::map< wxString, PCB_LAYER_ID >(const std::vector< INPUT_LAYER_DESC > &)> LAYER_MAPPING_HANDLER
Pointer to a function that takes a map of source and KiCad layers and returns a re-mapped version.
Utility functions for working with shapes.
Arc segment used in tracks, zone outlines, and shape boundaries.
uint8_t m_SubType
Bit 6 (0x40) = clockwise direction.
Field/property references with variable-typed substructs.
std::variant< uint32_t, std::array< uint32_t, 2 >, std::string, SUB_0x6C, SUB_0x70_0x74, SUB_0xF6 > m_Substruct
Net assignment linking a net (0x1B) to its member objects.
Component instance reference data.
Pin definition with shape type, drill character, coordinates, and size.
std::array< int32_t, 2 > m_Size
uint32_t GetShape() const
std::array< int32_t, 2 > m_Coords
Pad geometry and placement in board-absolute coordinates.
uint32_t m_Rotation
Board-absolute millidegrees. Subtract footprint rotation for FP-local orientation.
int32_t m_CoordsX
Board coordinates. Use SetFPRelativePosition() for KiCad FP-local space.
int32_t m_CoordsY
Board coordinates. Use SetFPRelativePosition() for KiCad FP-local space.
uint32_t m_Rotation
Rotation in millidegrees.
std::array< int32_t, 4 > m_Coords
Graphics container holding a chain of line segments and arcs.
0x15 , 0x16, 0x17 are segments:
static constexpr uint8_t BLOCK_TYPE_CODE
uint32_t m_MatchGroupPtr
Diff pair / match group pointer (0x26 or 0x2C)
Padstack definition containing drill dimensions and a table of per-layer pad/antipad/thermal componen...
size_t m_NumCompsPerLayer
uint32_t GetDrillSize() const
size_t m_NumFixedCompEntries
How many of the entries are fixed roles (after this is n*layers)
std::vector< PADSTACK_COMPONENT > m_Components
Collection of components that make up the padstack.
uint32_t GetLayerCount() const
Physical constraint sets containing trace width, clearance, and routing rules.
Rectangle defined by four coordinates.
uint32_t m_Rotation
Rotation in millidegrees.
std::array< int32_t, 4 > m_Coords
Polygon shape defined by a linked list of segments starting at m_FirstSegmentPtr (0x15/0x16/0x17 line...
uint32_t m_FirstSegmentPtr
uint32_t m_FirstKeepoutPtr
uint32_t GetTablePtr() const
Represents a list of layers.
COND_GE< FMT_VER::V_165, std::vector< REF_ENTRY > > m_RefEntries
COND_LT< FMT_VER::V_165, std::vector< NONREF_ENTRY > > m_NonRefEntries
Lookup table used for named associations.
@ SUBTYPE_GRAPHICAL_GROUP
Used for drill charts and x-section charts.
TEXT_ALIGNMENT m_Alignment
Text object with position, rotation, layer, font properties, and alignment.
COND_GE< FMT_VER::V_172, TEXT_PROPERTIES > m_Font
uint32_t m_Rotation
Millidegrees.
COND_LT< FMT_VER::V_172, TEXT_PROPERTIES > m_Font16x
String graphic content holding the actual text value and its display layer category.
Placed pad instance linking a pad definition (0x0D via m_PadPtr) to its parent footprint (m_ParentFp)...
Via instance with board position, padstack reference (m_Padstack for drill/annular ring definitions),...
Heterogeneous definition table containing font metrics (FontDef_X08), layer name definitions (X03),...
Fixed-capacity pointer array (100 entries).
std::array< uint32_t, 100 > m_Ptrs
bool operator()(const BOARD_ITEM *aFirst, const BOARD_ITEM *aSecond) const
size_t operator()(const BOARD_ITEM *aItem) const
@ ANALYSIS_MEDIUM1_ISOCONTOUR
@ ANALYSIS_PCB_TEMPERATURE
@ BGEOM_SILKSCREEN_BOTTOM
@ PGEOM_SILKSCREEN_BOTTOM
@ ANALYSIS_LOW_ISOCONTOUR
@ BGEOM_SWITCH_AREA_BOTTOM
@ BGEOM_SOLDERMASK_BOTTOM
@ ANALYSIS_MEDIUM3_ISOCONTOUR
@ PGEOM_PLACE_BOUND_BOTTOM
@ ANALYSIS_MEDIUM2_ISOCONTOUR
@ PGEOM_SOLDERMASK_BOTTOM
@ ANALYSIS_HIGH_ISOCONTOUR
@ BGEOM_PLACE_GRID_BOTTOM
Represents the information found in a single entry of a layer list.
Substruct in a padstack object.
@ TYPE_CHAMFERED_RECTANGLE
COND_GE< FMT_VER::V_172, int32_t > m_Z1
uint32_t m_ShapePtr
Seems to point to various things:
This is all the info needed to do the fill of one layer of one zone.
SHAPE_POLY_SET m_CombinedFill
The wider filled area we will chop a piece out of for this layer of this zone.
The features of a padstack that can vary between copper layers All parameters are optional; leaving t...
VECTOR2I size
Drill diameter (x == y) or slot dimensions (x != y)
VECTOR2I size
Size of the shape, or of the anchor pad for custom shape pads.
PAD_SHAPE shape
Shape of the pad.
size_t operator()(const LAYER_INFO &aLayerInfo) const noexcept
@ USER
The field ID hasn't been set yet; field is invalid.
@ REFERENCE
Field Reference of part, i.e. "IC21".
@ VALUE
Field Value of part, i.e. "3.3K".
const SHAPE_LINE_CHAIN chain
wxString result
Test unit parsing edge cases and error handling.
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
const VECTOR2I CalcArcCenter(const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd)
Determine the center of an arc or circle given three points on its circumference.
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
@ PCB_PAD_T
class PAD, a pad in a footprint
VECTOR2< int32_t > VECTOR2I
VECTOR2< double > VECTOR2D
VECTOR3< double > VECTOR3D
std::vector< std::unique_ptr< ZONE > > MergeZonesWithSameOutline(std::vector< std::unique_ptr< ZONE > > &&aZones)
Merges zones with identical outlines and nets on different layers into single multi-layer zones.
@ FULL
pads are covered by copper