1170 bool leading =
false;
1171 std::set<std::string> embedded;
1174 std::map<std::string, SLASH_NAMES> slashNames;
1175 auto collectSlashName = [&](
const std::string& aName )
1177 if( aName.empty() || aName.find(
'/' ) == std::string::npos )
1180 std::string key = aName;
1181 std::erase( key,
'/' );
1182 std::transform( key.begin(), key.end(), key.begin(),
1183 [](
unsigned char c )
1185 return static_cast<char>( std::tolower( c ) );
1188 if( aName.front() ==
'/' )
1189 slashNames[key].leading =
true;
1191 slashNames[key].embedded.insert( kicadOccurrenceNetName( aName ) );
1195 for(
const auto& [netId,
name] : aPage.netmap )
1196 collectSlashName(
name );
1198 for(
const auto& [netId, aliases] : aPage.netAliases )
1200 for(
const std::string& alias : aliases )
1201 collectSlashName( alias );
1206 collectPageSlashNames( page );
1208 for(
const auto& [folder, pages] :
m_design.childFolderPages )
1211 collectPageSlashNames( page );
1214 std::map<std::string, std::string> baseOccurrenceNetAliases;
1216 for(
const auto& [key, names] : slashNames )
1218 if( names.leading && names.embedded.size() == 1 )
1219 baseOccurrenceNetAliases[key] = *names.embedded.begin();
1222 std::map<const std::map<uint32_t, std::string>*, std::map<std::string, std::string>> occurrenceAliasesByScope;
1224 auto selectOccurrenceAliases = [&](
const std::map<uint32_t, std::string>* aScope )
1227 auto aliases = occurrenceAliasesByScope.find( aScope );
1229 if( aliases != occurrenceAliasesByScope.end() )
1235 std::function<void(
const ORCAD_OCC_SCOPE&,
size_t )> countOccurrenceNetNameScopes =
1238 std::set<std::string> scopeNames;
1240 for(
const auto& occurrence : aScope.
netNames )
1242 const std::string&
name = occurrence.second;
1243 std::string key = kicadOccurrenceNetName(
name );
1244 std::transform( key.begin(), key.end(), key.begin(),
1245 [](
unsigned char c )
1247 return static_cast<char>( std::tolower( c ) );
1249 scopeNames.insert( key );
1257 for(
const std::string&
name : scopeNames )
1261 countOccurrenceNetNameScopes( block.
scope, aDepth + 1 );
1263 countOccurrenceNetNameScopes(
m_design.occurrenceRoot, 0 );
1271 std::map<std::string, size_t> occurrenceFolderCounts;
1277 std::transform( key.begin(), key.end(), key.begin(),
1278 [](
unsigned char c )
1280 return static_cast<char>( std::tolower( c ) );
1282 ++occurrenceFolderCounts[key];
1283 countOccurrenceFolders( block.
scope );
1286 countOccurrenceFolders(
m_design.occurrenceRoot );
1288 std::set<std::string> rootChildFolders;
1289 bool simpleRepeatedLeafDesign = !
m_design.occurrenceRoot.blocks.empty();
1294 std::transform( key.begin(), key.end(), key.begin(),
1295 [](
unsigned char c )
1297 return static_cast<char>( std::tolower( c ) );
1299 rootChildFolders.insert( key );
1300 auto pages =
m_design.childFolderPages.find( key );
1302 if( pages ==
m_design.childFolderPages.end()
1303 || !std::all_of( pages->second.begin(), pages->second.end(),
1306 return aPage.blocks.empty();
1309 simpleRepeatedLeafDesign =
false;
1313 simpleRepeatedLeafDesign &= rootChildFolders.size() == 1 &&
m_design.occurrenceRoot.blocks.size() > 1;
1316 auto collectConnectedBlockInterfaceNames = [&](
const ORCAD_RAW_PAGE& aPage )
1322 if(
pin.noConnect ||
pin.name.empty() )
1326 std::transform( pinName.begin(), pinName.end(), pinName.begin(),
1327 [](
unsigned char c )
1329 return static_cast<char>( std::tolower( c ) );
1337 auto netName = aPage.netmap.find( wire.
id );
1339 if( netName == aPage.netmap.end() )
1343 std::transform( wireName.begin(), wireName.end(), wireName.begin(),
1344 [](
unsigned char c )
1346 return static_cast<char>( std::tolower( c ) );
1349 if( wireName == pinName )
1357 collectConnectedBlockInterfaceNames( page );
1359 for(
const auto& [folder, pages] :
m_design.childFolderPages )
1362 collectConnectedBlockInterfaceNames( page );
1365 auto unconnectedInterfaceNetNames = [&](
const ORCAD_DRAWN_INSTANCE& aDrawn,
const std::string& aFlatNetSuffix )
1367 std::map<std::string, std::string>
result;
1371 if( !
pin.noConnect ||
pin.name.empty() || aFlatNetSuffix.empty() )
1375 std::string localKey = localName;
1376 std::transform( localKey.begin(), localKey.end(), localKey.begin(),
1377 [](
unsigned char c )
1379 return static_cast<char>( std::tolower( c ) );
1385 result.emplace( std::move( localKey ), localName +
"_" + aFlatNetSuffix );
1397 std::set<uint32_t> matchedBlocks;
1401 auto drawn = std::find_if( aPage.
blocks.begin(), aPage.
blocks.end(),
1404 return aBlock.dbId == occurrence.targetDbId;
1408 std::transform( key.begin(), key.end(), key.begin(),
1409 [](
unsigned char c )
1411 return static_cast<char>( std::tolower( c ) );
1414 auto pages =
m_design.childFolderPages.find( key );
1416 if( !matchedBlocks.insert( occurrence.
targetDbId ).second || drawn == aPage.
blocks.end()
1417 || pages ==
m_design.childFolderPages.end() || pages->second.size() != 1
1418 || !canBuildHierarchy( pages->second.front(), occurrence.
scope ) )
1427 bool nativeHierarchy =
m_design.pages.size() == 1 && !
m_design.occurrenceRoot.blocks.empty()
1430 if( nativeHierarchy )
1453 std::vector<const ORCAD_OCC_BLOCK*> occurrences;
1456 occurrences.push_back( &occurrence );
1458 std::stable_sort( occurrences.begin(), occurrences.end(),
1461 wxString aName = FromOrcadString( a->childFolder );
1462 wxString bName = FromOrcadString( b->childFolder );
1463 int aOrder = OrcadPageOrder( aName );
1464 int bOrder = OrcadPageOrder( bName );
1465 int aKey = aOrder >= 0 ? aOrder : std::numeric_limits<int>::max();
1466 int bKey = bOrder >= 0 ? bOrder : std::numeric_limits<int>::max();
1471 return aName.CmpNoCase( bName ) < 0;
1477 auto drawn = std::find_if( aParentPage.
blocks.begin(), aParentPage.
blocks.end(),
1480 return aBlock.dbId == occurrence.targetDbId;
1484 std::transform( key.begin(), key.end(), key.begin(),
1485 [](
unsigned char c )
1487 return static_cast<char>( std::tolower( c ) );
1497 if( sheetName.IsEmpty() )
1500 wxString base = sheetName;
1502 for(
int suffix = 2; !
m_usedSheetNames.insert( sheetName.Lower() ).second; ++suffix )
1503 sheetName = wxString::Format( wxS(
"%s (%d)" ), base, suffix );
1513 auto implementation = drawn->props.find(
"Implementation" );
1515 if( implementation != drawn->props.end() && !implementation->second.empty()
1523 size_t pinOrdinal = 0;
1529 uint32_t busNetId =
busNetAt( aParentPage, sourcePin );
1530 std::string pinName = busNetId ?
connectedBusName( aParentPage, sourcePin, sourceName )
1533 if( busNetId && pinName != sourceName )
1535 auto parentBusNames =
1542 if( pinName != sourceName )
1546 const_cast<KIID&
>(
pin->m_Uuid ) =
1548 std::array<std::pair<int, SHEET_SIDE>, 4> sides = {
1555 pin->SetSide( std::min_element( sides.begin(), sides.end(),
1556 [](
const auto& a,
const auto& b )
1558 return a.first < b.first;
1561 pin->SetPosition( position );
1569 aParentSheet->GetScreen()->Append( childSheet );
1573 childPath.
SetPageNumber( wxString::Format( wxS(
"%d" ), pageIndex ) );
1575 std::map<std::string, std::string> childInterfaceAliases;
1579 std::set<std::string> sourceNames;
1580 std::set<uint32_t> wireObjectIds;
1582 std::string pinKey = pinName;
1583 std::transform( pinKey.begin(), pinKey.end(), pinKey.begin(),
1584 [](
unsigned char c )
1586 return static_cast<char>( std::tolower( c ) );
1588 sourceNames.insert( pinKey );
1595 wireObjectIds.insert( wire.
dbId );
1596 auto pageName = aParentPage.
netmap.find( wire.
id );
1598 if( pageName != aParentPage.
netmap.end() && !pageName->second.empty() )
1601 std::transform(
name.begin(),
name.end(),
name.begin(),
1602 [](
unsigned char c )
1604 return static_cast<char>( std::tolower( c ) );
1606 sourceNames.insert( std::move(
name ) );
1611 if( aliases != aParentPage.
netAliases.end() )
1613 for(
const std::string& alias : aliases->second )
1616 std::transform(
name.begin(),
name.end(),
name.begin(),
1617 [](
unsigned char c )
1619 return static_cast<char>( std::tolower( c ) );
1621 sourceNames.insert( std::move(
name ) );
1626 std::set<const std::string*> targets;
1628 for(
const auto& [occurrenceId, occurrenceName] : aScope.netNames )
1631 std::transform( occurrenceKey.begin(), occurrenceKey.end(), occurrenceKey.begin(),
1632 [](
unsigned char c )
1634 return static_cast<char>( std::tolower( c ) );
1636 bool matches = sourceNames.count( occurrenceKey );
1638 if( std::optional<uint32_t> objectId = occurrenceNetObjectId( occurrenceName ) )
1639 matches = matches || wireObjectIds.count( *objectId );
1642 targets.insert( &occurrenceName );
1645 if( targets.size() == 1 )
1662 convertPage( childPage, childScreen, childPath,
true, drawn->pins.
empty() );
1663 placeChildren( childPage, occurrence.
scope, childSheet, childPath );
1667 placeChildren( rootPage,
m_design.occurrenceRoot, aRootSheet, rootPath );
1680 std::function<bool(
const std::vector<ORCAD_RAW_PAGE>&,
const ORCAD_OCC_SCOPE& )> canBuildFolderHierarchy =
1681 [&](
const std::vector<ORCAD_RAW_PAGE>& aPages,
const ORCAD_OCC_SCOPE& aScope )
1683 size_t blockCount = 0;
1686 blockCount += page.
blocks.size();
1688 if( blockCount != aScope.
blocks.size() )
1691 std::set<uint32_t> matchedBlocks;
1699 matches += std::count_if( page.
blocks.begin(), page.
blocks.end(),
1702 return aBlock.dbId == occurrence.targetDbId;
1707 std::transform( key.begin(), key.end(), key.begin(),
1708 [](
unsigned char c )
1710 return static_cast<char>( std::tolower( c ) );
1713 auto pages =
m_design.childFolderPages.find( key );
1715 if( matches != 1 || !matchedBlocks.insert( occurrence.
targetDbId ).second
1716 || pages ==
m_design.childFolderPages.end() || pages->second.empty()
1717 || !canBuildFolderHierarchy( pages->second, occurrence.
scope ) )
1726 bool folderHierarchy = !
m_design.occurrenceRoot.blocks.empty()
1729 struct POWER_ALIAS_EVIDENCE
1731 size_t placements = 0;
1732 std::map<std::string, std::pair<std::string, size_t>> targets;
1735 auto lowerPowerName = []( std::string aName )
1737 std::transform( aName.begin(), aName.end(), aName.begin(),
1738 [](
unsigned char c )
1740 return static_cast<char>( std::tolower( c ) );
1745 auto recordPowerAlias = [&]( std::map<std::string, POWER_ALIAS_EVIDENCE>& aCandidates,
1746 const std::string& aSourceName,
const std::string& aElectricalName )
1748 if( aSourceName.empty() || aElectricalName.empty() )
1751 POWER_ALIAS_EVIDENCE& evidence = aCandidates[lowerPowerName( aSourceName )];
1752 ++evidence.placements;
1755 || wxString::FromUTF8( aSourceName ).CmpNoCase( wxString::FromUTF8( aElectricalName ) ) == 0 )
1760 auto& target = evidence.targets[lowerPowerName( aElectricalName )];
1761 target.first = aElectricalName;
1765 auto acceptPowerAliases = [&](
const std::map<std::string, POWER_ALIAS_EVIDENCE>& aCandidates )
1767 for(
const auto& [sourceName, evidence] : aCandidates )
1769 if( evidence.targets.size() != 1 )
1772 const auto& target = evidence.targets.begin()->second;
1774 if( target.second * 2 > evidence.placements )
1779 if( folderHierarchy )
1782 size_t sourcePageIndex = 0;
1784 std::function<size_t(
const std::vector<ORCAD_RAW_PAGE>&,
const ORCAD_OCC_SCOPE& )> countSourcePages =
1785 [&](
const std::vector<ORCAD_RAW_PAGE>& aPages,
const ORCAD_OCC_SCOPE& aScope )
1787 size_t count = aPages.size();
1792 std::transform( key.begin(), key.end(), key.begin(),
1793 [](
unsigned char c )
1795 return static_cast<char>( std::tolower( c ) );
1798 if(
auto pages =
m_design.childFolderPages.find( key ); pages !=
m_design.childFolderPages.end() )
1799 count += countSourcePages( pages->second, occurrence.
scope );
1805 size_t sourcePageCount = countSourcePages(
m_design.pages,
m_design.occurrenceRoot );
1812 auto uniqueSheetName = [&](
const std::string& aName )
1816 if(
name.IsEmpty() )
1817 name = wxS(
"PAGE" );
1819 wxString base =
name;
1822 name = wxString::Format( wxS(
"%s (%d)" ), base, suffix );
1829 std::vector<std::string> names;
1830 std::set<std::string> seen;
1832 auto collect = [&](
const std::vector<ORCAD_GRAPHIC_INST>& aConnectors )
1841 std::string key =
name;
1842 std::transform( key.begin(), key.end(), key.begin(),
1843 [](
unsigned char c )
1845 return static_cast<char>( std::tolower( c ) );
1848 if( !
name.empty() && seen.insert( key ).second )
1849 names.push_back( std::move(
name ) );
1853 collect( aPage.
ports );
1858 auto addContainerLabel =
1859 [&](
SCH_SCREEN* aScreen,
const wxString& aName,
const VECTOR2I& aPosition,
bool aHierarchical )
1871 auto lower = []( std::string aName )
1873 std::transform( aName.begin(), aName.end(), aName.begin(),
1874 [](
unsigned char c )
1876 return static_cast<char>( std::tolower( c ) );
1880 auto generated = [](
const std::string& aName )
1882 return aName.size() > 1 && aName.front() ==
'N'
1883 && std::all_of( aName.begin() + 1, aName.end(),
1884 [](
unsigned char c )
1886 return std::isdigit( c );
1890 auto& childAliases = occurrenceAliasesByScope[&aChildScope.netNames];
1895 std::set<uint32_t> wireObjectIds;
1902 wireObjectIds.insert( wire.
dbId );
1903 auto pageName = aParentPage.
netmap.find( wire.
id );
1905 if( pageName != aParentPage.
netmap.end() && !pageName->second.empty() )
1910 if( aliases != aParentPage.
netAliases.end() )
1912 for(
const std::string& alias : aliases->second )
1917 std::set<const std::string*> targets;
1919 for(
const auto& [occurrenceId, occurrenceName] : aParentScope.netNames )
1923 if( std::optional<uint32_t> objectId = occurrenceNetObjectId( occurrenceName ) )
1924 matches = matches || wireObjectIds.count( *objectId );
1926 if( matches && !generated( occurrenceName ) )
1927 targets.insert( &occurrenceName );
1930 if( targets.size() == 1 )
1932 std::string sourceName = lower( kicadOccurrenceNetName(
pin.name ) );
1933 std::string targetName = kicadOccurrenceNetName( **targets.begin() );
1935 if( sourceName != lower( targetName ) )
1936 childAliases[std::move( sourceName )] = std::move( targetName );
1942 const std::string&,
bool,
const std::map<std::string, std::string>& )>
1946 const SCH_SHEET_PATH& aFolderPath,
const std::string& aOccurrenceSuffix,
1947 bool aRepeatedFolder,
1948 const std::map<std::string, std::string>& aUnconnectedInterfaceNetNames )
1950 struct PAGE_PLACEMENT
1958 std::vector<PAGE_PLACEMENT> placements;
1959 bool leafFolder = std::all_of( aPages.begin(), aPages.end(),
1962 return aPage.blocks.empty();
1968 leafFolder ? aUnconnectedInterfaceNetNames : std::map<std::string, std::string>();
1970 if( aPages.size() == 1 )
1980 numberSourcePage( page );
1982 convertPage( page, aFolderSheet->GetScreen(), aFolderPath, aFolderSheet != aRootSheet,
1983 aFolderSheet->GetPins().empty() );
1984 placements.push_back( { &page, aFolderSheet, aFolderSheet->GetScreen(), aFolderPath } );
1986 else if( aFolderSheet == aRootSheet )
1988 std::vector<SCH_SHEET*> topSheets;
1989 std::vector<SCH_SCREEN*> topScreens;
1991 for(
size_t i = 0; i < aPages.size(); ++i )
1996 int currentPage =
static_cast<int>( i + 1 );
2009 topSheets.push_back( pageSheet );
2010 topScreens.push_back( pageScreen );
2014 pageIndex =
static_cast<int>( aPages.size() );
2016 for(
size_t i = 0; i < aPages.size(); ++i )
2023 if( candidate.Last() == topSheets[i] )
2025 pagePath = candidate;
2030 if( pagePath.
empty() )
2033 pagePath.
SetPageNumber( wxString::Format( wxS(
"%zu" ), i + 1 ) );
2040 numberSourcePage( page );
2042 convertPage( page, topScreens[i], pagePath,
false,
true );
2043 placements.push_back( { &page, topSheets[i], topScreens[i], pagePath } );
2048 SCH_SCREEN* container = aFolderSheet->GetScreen();
2050 size_t outerOrdinal = 0;
2056 schIUScale.mmToIU( 20 + 5 *
static_cast<int>( outerOrdinal++ ) ) );
2057 addContainerLabel( container,
pin->GetText(), position,
true );
2060 for(
size_t i = 0; i < aPages.size(); ++i )
2063 int column =
static_cast<int>( i % 3 );
2064 int row =
static_cast<int>( i / 3 );
2065 std::vector<std::string> names = interfaceNames( page );
2069 for( std::string&
name : names )
2071 auto renamed = folderBusNames->second.find(
name );
2073 if( renamed != folderBusNames->second.end() )
2074 name = renamed->second;
2078 int heightMm = std::max( 25, 10 + 5 *
static_cast<int>( names.size() ) );
2088 int currentPage = ++pageIndex;
2096 for(
size_t pinIndex = 0; pinIndex < names.size(); ++pinIndex )
2099 position.
y +
schIUScale.mmToIU( 5 + 5 *
static_cast<int>( pinIndex ) ) );
2102 const_cast<KIID&
>(
pin->m_Uuid ) =
2107 addContainerLabel( container,
name, pinPosition,
false );
2110 container->
Append( pageSheet );
2113 pagePath.
SetPageNumber( wxString::Format( wxS(
"%d" ), currentPage ) );
2120 numberSourcePage( page );
2122 convertPage( page, pageScreen, pagePath,
true,
true );
2123 placements.push_back( { &page, pageSheet, pageScreen, pagePath } );
2127 std::vector<const ORCAD_OCC_BLOCK*> occurrences;
2130 occurrences.push_back( &occurrence );
2132 std::stable_sort( occurrences.begin(), occurrences.end(),
2135 wxString aName = FromOrcadString( a->childFolder );
2136 wxString bName = FromOrcadString( b->childFolder );
2137 int aOrder = OrcadPageOrder( aName );
2138 int bOrder = OrcadPageOrder( bName );
2139 int aKey = aOrder >= 0 ? aOrder : std::numeric_limits<int>::max();
2140 int bKey = bOrder >= 0 ? bOrder : std::numeric_limits<int>::max();
2145 return aName.CmpNoCase( bName ) < 0;
2151 PAGE_PLACEMENT* parent =
nullptr;
2154 for( PAGE_PLACEMENT& placement : placements )
2156 auto found = std::find_if( placement.page->blocks.begin(), placement.page->blocks.end(),
2159 return aBlock.dbId == occurrence.targetDbId;
2162 if( found != placement.page->blocks.end() )
2164 parent = &placement;
2170 if( !parent || !drawn )
2174 std::transform( key.begin(), key.end(), key.begin(),
2175 [](
unsigned char c )
2177 return static_cast<char>( std::tolower( c ) );
2179 std::vector<ORCAD_RAW_PAGE>& childPages =
m_design.childFolderPages.at( key );
2184 int currentPage = ++pageIndex;
2187 MakePageFileName( currentPage, childPages.size() == 1 ? childPages.front().name
2197 auto implementation = drawn->
props.find(
"Implementation" );
2199 if( implementation != drawn->
props.end() && !implementation->second.empty()
2207 for(
size_t pinIndex = 0; pinIndex < drawn->
pins.size(); ++pinIndex )
2212 uint32_t busNetId =
busNetAt( *parent->page, sourcePin );
2213 std::string pinName = busNetId ?
connectedBusName( *parent->page, sourcePin, sourceName )
2216 if( busNetId && pinName != sourceName )
2224 if( pinName != sourceName )
2228 const_cast<KIID&
>(
pin->m_Uuid ) =
2230 std::array<std::pair<int, SHEET_SIDE>, 4> sides = {
2236 pin->SetSide( std::min_element( sides.begin(), sides.end(),
2237 [](
const auto& a,
const auto& b )
2239 return a.first < b.first;
2242 pin->SetPosition( position );
2248 parent->screen->Append( childSheet );
2251 childPath.
SetPageNumber( wxString::Format( wxS(
"%d" ), currentPage ) );
2252 std::string childSuffix = aOccurrenceSuffix;
2254 std::transform( childKey.begin(), childKey.end(), childKey.begin(),
2255 [](
unsigned char c )
2257 return static_cast<char>( std::tolower( c ) );
2262 if( !childSuffix.empty() )
2268 auto unconnectedNames = unconnectedInterfaceNetNames( *drawn, childSuffix );
2269 addChildOccurrenceAliases( *parent->page, aScope, *drawn, occurrence.
scope );
2270 placeFolder( childPages, occurrence.
scope, childSheet, childPath, childSuffix,
2271 occurrenceFolderCounts[childKey] > 1, unconnectedNames );
2275 std::map<std::string, POWER_ALIAS_EVIDENCE> powerAliasCandidates;
2276 std::function<void( std::vector<ORCAD_RAW_PAGE>&,
const ORCAD_OCC_SCOPE& )> collectPowerAliases =
2277 [&]( std::vector<ORCAD_RAW_PAGE>& aPages,
const ORCAD_OCC_SCOPE& aScope )
2291 std::string sourceName = trimmed( global.
logicalName );
2292 std::string electricalName =
powerNet( page, global );
2293 recordPowerAlias( powerAliasCandidates, sourceName, electricalName );
2304 auto found = std::find_if( page.
blocks.begin(), page.
blocks.end(),
2307 return aBlock.dbId == occurrence.targetDbId;
2310 if( found != page.
blocks.end() )
2318 std::string key = lowerPowerName( occurrence.
childFolder );
2319 auto childPages =
m_design.childFolderPages.find( key );
2321 if( parentPage && drawn && childPages !=
m_design.childFolderPages.end() )
2323 addChildOccurrenceAliases( *parentPage, aScope, *drawn, occurrence.
scope );
2324 collectPowerAliases( childPages->second, occurrence.
scope );
2330 acceptPowerAliases( powerAliasCandidates );
2338 placeFolder(
m_design.pages,
m_design.occurrenceRoot, aRootSheet, rootPath, {},
false, {} );
2357 const std::map<uint32_t, std::string>* refs;
2358 const std::map<uint32_t, std::string>* unitRefs;
2359 const std::map<uint32_t, std::map<std::string, std::string>>* props;
2360 const std::map<uint32_t, std::string>* netNames;
2362 bool scopeNamedFlatNets;
2363 bool scopeGeneratedFlatNets;
2364 std::map<std::string, std::string> unconnectedInterfaceNetNames;
2367 std::vector<PAGE_JOB> jobs;
2370 jobs.push_back( { &page,
2372 &
m_design.occurrenceRoot.partUnitRefs,
2373 &
m_design.occurrenceRoot.partProps,
2380 auto findBlock = [&]( uint32_t aDbId ) -> std::pair<const ORCAD_DRAWN_INSTANCE*, const ORCAD_RAW_PAGE*>
2382 auto findInPages = [&](
const std::vector<ORCAD_RAW_PAGE>& aPages )
2383 -> std::pair<const ORCAD_DRAWN_INSTANCE*, const ORCAD_RAW_PAGE*>
2389 if( block.
dbId == aDbId )
2390 return { &block, &page };
2402 for(
const auto& [folder, pages] :
m_design.childFolderPages )
2404 result = findInPages( pages );
2413 std::function<void(
const ORCAD_OCC_SCOPE&,
const std::string& )> expand =
2414 [&](
const ORCAD_OCC_SCOPE& aScope,
const std::string& aParentSuffix )
2419 std::transform( key.begin(), key.end(), key.begin(),
2420 [](
unsigned char c )
2422 return static_cast<char>( std::tolower( c ) );
2425 auto it =
m_design.childFolderPages.find( key );
2427 std::string occurrenceSuffix = aParentSuffix;
2431 if( !occurrenceSuffix.empty() )
2432 occurrenceSuffix +=
'_';
2437 if( it !=
m_design.childFolderPages.end() )
2439 bool leafFolder = std::all_of( it->second.begin(), it->second.end(),
2442 return aPage.blocks.empty();
2444 std::map<std::string, std::string> unconnectedNames;
2447 unconnectedNames = unconnectedInterfaceNetNames( *drawn, occurrenceSuffix );
2453 leafFolder ? occurrenceSuffix : std::string(),
2454 simpleRepeatedLeafDesign && leafFolder,
2455 leafFolder && occurrenceFolderCounts[key] > 1, unconnectedNames } );
2459 expand( block.
scope, occurrenceSuffix );
2463 expand(
m_design.occurrenceRoot, {} );
2465 std::map<const std::map<uint32_t, std::string>*, std::map<std::string, std::set<std::string>>>
2466 interfaceAliasCandidates;
2467 std::map<const std::map<uint32_t, std::string>*, std::map<std::string, std::set<std::string>>>
2468 connectorAliasCandidates;
2470 auto lowerName = []( std::string aName )
2472 std::transform( aName.begin(), aName.end(), aName.begin(),
2473 [](
unsigned char c )
2475 return static_cast<char>( std::tolower( c ) );
2480 using NET_NAME_SCOPE =
const std::map<uint32_t, std::string>*;
2481 std::map<NET_NAME_SCOPE, std::map<std::string, std::set<std::string>>> interfaceNameGraphs;
2483 for(
const PAGE_JOB& job : jobs )
2485 for(
const auto& [netId, aliases] : job.page->netAliases )
2487 std::set<std::string> names;
2488 auto primary = job.page->netmap.find( netId );
2489 bool allPowerNames =
true;
2490 bool anyPowerName =
false;
2492 if( primary != job.page->netmap.end() && !primary->second.empty() )
2495 names.insert(
name );
2497 anyPowerName = allPowerNames;
2500 for(
const std::string& alias : aliases )
2502 if( !alias.empty() )
2510 if( anyPowerName && !allPowerNames )
2513 for(
const std::string&
name : names )
2515 auto& neighbors = interfaceNameGraphs[job.netNames][
name];
2516 neighbors.insert( names.begin(), names.end() );
2521 for(
const PAGE_JOB& job : jobs )
2523 for(
const auto& [netId, aliases] : job.page->netAliases )
2525 std::set<std::string> distinctAliases;
2527 for(
const std::string& alias : aliases )
2529 if( !alias.empty() )
2530 distinctAliases.insert( lowerName( alias ) );
2533 auto primary = job.page->netmap.find( netId );
2535 if( distinctAliases.size() < 2 || primary == job.page->netmap.end() || primary->second.empty() )
2538 std::string effectiveName;
2539 int64_t bestConnectorAliasDistance = std::numeric_limits<int64_t>::max();
2540 bool connectorAlias =
false;
2541 auto firstAlias = std::find_if( aliases.begin(), aliases.end(),
2542 [](
const std::string& aName )
2544 return !aName.empty();
2547 for(
const auto& [occurrenceId, occurrenceName] : *job.netNames )
2549 if( lowerName( primary->second ) == lowerName( occurrenceName ) )
2553 if( effectiveName.empty() )
2558 || std::toupper(
static_cast<unsigned char>( instance.
reference.front() ) ) !=
'J' )
2565 for(
const ORCAD_WIRE& wire : job.page->wires )
2567 if( wire.
id != netId
2574 size_t localAliasCount = std::count_if(
2578 if( aAlias.name.empty() || isOffpageNetName( aAlias.name ) )
2583 std::string aliasName = lowerName( aAlias.
name );
2585 return std::none_of( aliases.begin(), aliases.end(),
2586 [&](
const std::string& aName )
2588 return isOffpageNetName( aName )
2589 && lowerName( aName ).find( aliasName )
2590 != std::string::npos;
2594 if( localAliasCount < 2 )
2599 if( alias.name.empty() ||
isOffpageNetName( alias.name ) || firstAlias == aliases.end()
2600 || lowerName( alias.name ) != lowerName( *firstAlias ) )
2605 int64_t dx = alias.x -
pin.x;
2606 int64_t dy = alias.y -
pin.y;
2607 int64_t
distance = dx * dx + dy * dy;
2609 if(
distance < bestConnectorAliasDistance )
2611 bestConnectorAliasDistance =
distance;
2613 connectorAlias =
true;
2621 if( !effectiveName.empty() && !connectorAlias )
2623 connectorAlias = std::any_of(
2624 job.page->instances.begin(), job.page->instances.end(),
2627 if( aInstance.reference.empty()
2628 || std::toupper( static_cast<unsigned char>( aInstance.reference.front() ) ) !=
'J' )
2634 aInstance.
pins.begin(), aInstance.
pins.end(),
2638 job.page->wires.begin(), job.page->wires.end(),
2639 [&]( const ORCAD_WIRE& aWire )
2641 if( aWire.id != netId
2642 || ( aPin.wordA != aWire.dbId && aPin.wordB != aWire.dbId
2643 && !rawPointOnSegment( aPin.x, aPin.y, aWire ) ) )
2648 return std::any_of( aWire.aliases.begin(), aWire.aliases.end(),
2649 [&]( const ORCAD_ALIAS& aAlias )
2651 return lowerName( canonicalGlobalNetName(
2653 == lowerName( effectiveName );
2660 if( effectiveName.empty() )
2663 for(
const std::string& alias : aliases )
2665 if( isOffpageNetName( alias ) )
2667 std::string sourceName = lowerName( canonicalGlobalNetName( alias ) );
2668 interfaceAliasCandidates[job.netNames][sourceName].insert( effectiveName );
2670 if( connectorAlias )
2671 connectorAliasCandidates[job.netNames][sourceName].insert( effectiveName );
2677 std::map<const std::map<uint32_t, std::string>*, std::map<std::string, std::string>> interfaceAliasesByScope;
2678 std::map<const std::map<uint32_t, std::string>*, std::set<std::string>> connectorAliasesByScope;
2680 for(
const auto& [scope, aliases] : interfaceAliasCandidates )
2682 for(
const auto& [sourceName, effectiveNames] : aliases )
2684 auto selected = std::max_element( effectiveNames.begin(), effectiveNames.end(),
2685 [](
const std::string& aLeft,
const std::string& aRight )
2687 return aLeft.size() < aRight.size();
2690 if( selected == effectiveNames.end() )
2693 bool sourceIsOccurrenceName = std::any_of(
2694 scope->begin(), scope->end(),
2695 [&](
const auto& aOccurrenceNet )
2697 return lowerName( canonicalGlobalNetName( aOccurrenceNet.second ) ) == sourceName;
2699 bool selectedIsOccurrenceName = std::any_of(
2700 scope->begin(), scope->end(),
2701 [&](
const auto& aOccurrenceNet )
2703 return lowerName( canonicalGlobalNetName( aOccurrenceNet.second ) ) == lowerName( *selected );
2706 if( sourceIsOccurrenceName && selectedIsOccurrenceName && lowerName( *selected ) != sourceName )
2709 bool uniqueLength = std::none_of( effectiveNames.begin(), effectiveNames.end(),
2710 [&](
const std::string& aName )
2712 return aName != *selected && aName.size() == selected->size();
2717 interfaceAliasesByScope[scope][sourceName] = *selected;
2719 auto connectorScope = connectorAliasCandidates.find( scope );
2721 if( connectorScope != connectorAliasCandidates.end() )
2723 auto connectorNames = connectorScope->second.find( sourceName );
2725 if( connectorNames != connectorScope->second.end() && connectorNames->second.count( *selected ) )
2726 connectorAliasesByScope[scope].insert( sourceName );
2732 for(
const auto& [scope, graph] : interfaceNameGraphs )
2734 std::set<std::string> unseen;
2736 for(
const auto& [
name, neighbors] : graph )
2737 unseen.insert(
name );
2739 while( !unseen.empty() )
2741 std::set<std::string> component;
2742 std::vector<std::string> pending = { *unseen.begin() };
2743 unseen.erase( pending.front() );
2745 while( !pending.empty() )
2747 std::string
name = std::move( pending.back() );
2749 component.insert(
name );
2751 for(
const std::string& neighbor : graph.at(
name ) )
2753 if( unseen.erase( neighbor ) )
2754 pending.push_back( neighbor );
2758 std::set<std::string> authoritativeNames;
2760 for(
const auto& [occurrenceId, occurrenceName] : *scope )
2762 std::string key = lowerName( canonicalGlobalNetName( occurrenceName ) );
2764 if( component.count( key ) )
2765 authoritativeNames.insert( canonicalGlobalNetName( occurrenceName ) );
2768 if( authoritativeNames.size() != 1 )
2771 for(
const std::string& sourceName : component )
2773 if( connectorAliasesByScope[scope].count( sourceName ) )
2776 interfaceAliasesByScope[scope][sourceName] = *authoritativeNames.begin();
2777 connectorAliasesByScope[scope].erase( sourceName );
2782 std::function<void(
const ORCAD_OCC_SCOPE& )> propagateInterfaceAliases =
2785 const auto& parentAliases = interfaceAliasesByScope[&aParentScope.netNames];
2789 auto& childAliases = interfaceAliasesByScope[&block.
scope.
netNames];
2790 auto [drawnBlock, parentPage] = findBlock( block.
targetDbId );
2791 if( drawnBlock && parentPage )
2795 if(
pin.name.empty() )
2798 std::set<std::string> sourceNames = { lowerName( canonicalGlobalNetName(
pin.name ) ) };
2799 std::set<uint32_t> wireObjectIds;
2801 for(
const ORCAD_WIRE& wire : parentPage->wires )
2806 wireObjectIds.insert( wire.
dbId );
2807 auto pageName = parentPage->netmap.find( wire.
id );
2809 if( pageName != parentPage->netmap.end() && !pageName->second.empty() )
2810 sourceNames.insert( lowerName( canonicalGlobalNetName( pageName->second ) ) );
2812 auto aliases = parentPage->netAliases.find( wire.
id );
2814 if( aliases != parentPage->netAliases.end() )
2816 for(
const std::string& alias : aliases->second )
2817 sourceNames.insert( lowerName( canonicalGlobalNetName( alias ) ) );
2821 std::set<const std::string*> targets;
2823 for(
const auto& [occurrenceId, occurrenceName] : aParentScope.netNames )
2825 std::string occurrenceKey = lowerName( canonicalGlobalNetName( occurrenceName ) );
2826 bool matches = sourceNames.count( occurrenceKey );
2828 if( std::optional<uint32_t> objectId = occurrenceNetObjectId( occurrenceName ) )
2829 matches = matches || wireObjectIds.count( *objectId );
2832 targets.insert( &occurrenceName );
2835 std::string targetName;
2837 if( targets.size() == 1 )
2838 targetName = canonicalGlobalNetName( **targets.begin() );
2841 for(
const std::string& sourceName : sourceNames )
2843 auto inherited = parentAliases.find( sourceName );
2845 if( inherited != parentAliases.end() )
2846 targetName = inherited->second;
2850 if( !targetName.empty() )
2851 childAliases[lowerName( canonicalGlobalNetName(
pin.name ) )] = std::move( targetName );
2856 for(
auto& [sourceName, targetName] : childAliases )
2858 auto inherited = parentAliases.find( lowerName( canonicalGlobalNetName( targetName ) ) );
2860 if( inherited != parentAliases.end() )
2861 targetName = inherited->second;
2864 for(
const auto& [occurrenceId, occurrenceName] : block.
scope.
netNames )
2866 std::string sourceName = lowerName( canonicalGlobalNetName( occurrenceName ) );
2867 auto inherited = parentAliases.find( sourceName );
2869 if( inherited != parentAliases.end() )
2870 childAliases[sourceName] = inherited->second;
2873 propagateInterfaceAliases( block.
scope );
2876 propagateInterfaceAliases( m_design.occurrenceRoot );
2878 std::map<std::string, POWER_ALIAS_EVIDENCE> powerAliasCandidates;
2880 for(
const PAGE_JOB& job : jobs )
2882 m_currentOccRefs = job.refs;
2883 m_currentOccUnitRefs = job.unitRefs;
2884 m_currentOccProps = job.props;
2885 m_currentOccNetNames = job.netNames;
2886 selectOccurrenceAliases( m_currentOccNetNames );
2887 m_currentFlatNetSuffix = job.flatNetSuffix;
2888 m_scopeNamedFlatNets = job.scopeNamedFlatNets;
2889 m_scopeGeneratedFlatNets = job.scopeGeneratedFlatNets;
2890 m_currentUnconnectedInterfaceNetNames = job.unconnectedInterfaceNetNames;
2891 m_currentInterfaceNetAliases = interfaceAliasesByScope[job.netNames];
2892 m_currentConnectorInterfaceNetAliases = connectorAliasesByScope[job.netNames];
2893 buildNetLookup( *job.page );
2897 std::string sourceName = trimmed( global.
logicalName );
2898 std::string electricalName = powerNet( *job.page, global );
2899 recordPowerAlias( powerAliasCandidates, sourceName, electricalName );
2903 acceptPowerAliases( powerAliasCandidates );
2905 m_currentOccRefs =
nullptr;
2906 m_currentOccUnitRefs =
nullptr;
2907 m_currentOccProps =
nullptr;
2908 m_currentOccNetNames =
nullptr;
2909 m_currentFlatNetSuffix.clear();
2910 m_scopeNamedFlatNets =
false;
2911 m_scopeGeneratedFlatNets =
false;
2912 m_currentUnconnectedInterfaceNetNames.clear();
2913 m_currentInterfaceNetAliases.clear();
2914 m_currentConnectorInterfaceNetAliases.clear();
2915 m_currentOccurrenceNetAliases.clear();
2917 if( jobs.size() == 1 )
2919 PAGE_JOB& job = jobs[0];
2921 pollProgress( m_progressReporter, job.page->name );
2922 m_currentOccRefs = job.refs;
2923 m_currentOccUnitRefs = job.unitRefs;
2924 m_currentOccProps = job.props;
2925 m_currentOccNetNames = job.netNames;
2926 selectOccurrenceAliases( m_currentOccNetNames );
2927 m_currentFlatNetSuffix = job.flatNetSuffix;
2928 m_scopeNamedFlatNets = job.scopeNamedFlatNets;
2929 m_scopeGeneratedFlatNets = job.scopeGeneratedFlatNets;
2930 m_currentUnconnectedInterfaceNetNames = job.unconnectedInterfaceNetNames;
2931 m_currentInterfaceNetAliases = interfaceAliasesByScope[job.netNames];
2932 m_currentConnectorInterfaceNetAliases = connectorAliasesByScope[job.netNames];
2933 applyPageSettings( *job.page, rootScreen );
2934 convertPage( *job.page, rootScreen, rootPath );
2935 m_currentOccRefs =
nullptr;
2936 m_currentOccUnitRefs =
nullptr;
2937 m_currentOccProps =
nullptr;
2938 m_currentOccNetNames =
nullptr;
2939 m_currentFlatNetSuffix.clear();
2940 m_scopeNamedFlatNets =
false;
2941 m_scopeGeneratedFlatNets =
false;
2942 m_currentUnconnectedInterfaceNetNames.clear();
2943 m_currentInterfaceNetAliases.clear();
2944 m_currentConnectorInterfaceNetAliases.clear();
2957 std::vector<SHEET_JOB> sheetJobs;
2959 for(
size_t i = 0; i < jobs.size(); ++i )
2964 if( order < 0 && i < m_design.pages.size() )
2968 auto pageNumber = titleBlock.props.find(
"Page Number" );
2971 if( pageNumber != titleBlock.props.end()
2972 && wxString::FromUTF8( pageNumber->second ).ToLong( &parsed ) && parsed > 0 )
2974 order =
static_cast<int>( parsed );
2980 if( order < 0 && i < m_design.pages.size() && jobs[i].page->sourcePageNumber != 0 )
2981 order =
static_cast<int>( jobs[i].page->sourcePageNumber );
2983 if(
name.IsEmpty() )
2984 name = wxString::Format( wxS(
"PAGE%zu" ), i + 1 );
2986 sheetJobs.push_back( { jobs[i],
name, order } );
2989 std::stable_sort( sheetJobs.begin(), sheetJobs.end(),
2990 [](
const SHEET_JOB& a,
const SHEET_JOB& b )
2992 int ka = a.order >= 0 ? a.order : std::numeric_limits<int>::max();
2993 int kb = b.order >= 0 ? b.order : std::numeric_limits<int>::max();
2997 if( jobs.size() == m_design.pages.size() )
2999 for(
size_t i = 0; i < sheetJobs.size(); ++i )
3001 sheetJobs[i].job.page->sourcePageNumber = i + 1;
3002 sheetJobs[i].job.page->sourcePageCount = sheetJobs.size();
3006 std::vector<SCH_SHEET*> topSheets;
3007 std::vector<SCH_SCREEN*> topScreens;
3009 for(
size_t i = 0; i < sheetJobs.size(); ++i )
3011 SHEET_JOB& sj = sheetJobs[i];
3020 screen = rootScreen;
3025 const_cast<KIID&
>( screen->
GetUuid() ) = deterministicUuid(
"screen", m_screenOrdinal++ );
3031 wxString base = sj.name;
3033 for(
int suffix = 2; !m_usedSheetNames.insert( sj.name.Lower() ).second; ++suffix )
3034 sj.name = wxString::Format( wxS(
"%s (%d)" ), base, suffix );
3036 wxString fileName = MakePageFileName(
static_cast<int>( i + 1 ), sj.job.page->name );
3040 screen->
SetFileName( m_schematic->Project().GetProjectPath() + fileName );
3042 topSheets.push_back( sheet );
3043 topScreens.push_back( screen );
3046 m_schematic->SetTopLevelSheets( topSheets );
3048 for(
size_t i = 0; i < sheetJobs.size(); ++i )
3050 SHEET_JOB& sj = sheetJobs[i];
3053 for(
const SCH_SHEET_PATH& candidate : m_schematic->Hierarchy() )
3055 if( candidate.Last() == topSheets[i] )
3057 pagePath = candidate;
3062 if( pagePath.
empty() )
3065 pagePath.
SetPageNumber( wxString::Format( wxS(
"%zu" ), i + 1 ) );
3066 pollProgress( m_progressReporter, sj.job.page->name );
3067 m_currentOccRefs = sj.job.refs;
3068 m_currentOccUnitRefs = sj.job.unitRefs;
3069 m_currentOccProps = sj.job.props;
3070 m_currentOccNetNames = sj.job.netNames;
3071 selectOccurrenceAliases( m_currentOccNetNames );
3072 m_currentFlatNetSuffix = sj.job.flatNetSuffix;
3073 m_scopeNamedFlatNets = sj.job.scopeNamedFlatNets;
3074 m_scopeGeneratedFlatNets = sj.job.scopeGeneratedFlatNets;
3075 m_currentUnconnectedInterfaceNetNames = sj.job.unconnectedInterfaceNetNames;
3076 m_currentInterfaceNetAliases = interfaceAliasesByScope[sj.job.netNames];
3077 m_currentConnectorInterfaceNetAliases = connectorAliasesByScope[sj.job.netNames];
3078 applyPageSettings( *sj.job.page, topScreens[i] );
3079 convertPage( *sj.job.page, topScreens[i], pagePath );
3080 m_currentOccRefs =
nullptr;
3081 m_currentOccUnitRefs =
nullptr;
3082 m_currentOccProps =
nullptr;
3083 m_currentOccNetNames =
nullptr;
3084 m_currentFlatNetSuffix.clear();
3085 m_scopeNamedFlatNets =
false;
3086 m_scopeGeneratedFlatNets =
false;
3087 m_currentUnconnectedInterfaceNetNames.clear();
3088 m_currentInterfaceNetAliases.clear();
3089 m_currentConnectorInterfaceNetAliases.clear();
5116 auto nameIt = aInst.
props.find(
"Name" );
5117 std::string propertyName = nameIt != aInst.
props.end() ? trimmed( nameIt->second ) : std::string();
5118 std::string logicalName = trimmed( aInst.
logicalName );
5120 bool authoritativeOccurrenceNet =
false;
5121 std::map<uint32_t, std::set<const std::string*>> occurrenceNamesByPageNetId;
5122 auto occurrenceElectricalName = [&](
const std::string* aName )
5124 return aName ? *aName : std::string();
5129 std::set<const std::string*> generatedNamesAtPin;
5133 for(
size_t pinIndex = 0; pinIndex < instance.
pins.size(); ++pinIndex )
5141 bool touchesWire = std::any_of( aPage.
wires.begin(), aPage.
wires.end(),
5144 return onSegment( placedPin.x, placedPin.y, aWire );
5147 if( electricalPosition !=
pin
5148 || ( electricalPosition ==
VECTOR2I( placedPin.
x, placedPin.
y ) && touchesWire ) )
5153 std::string generatedName = generatedPinNetName( instance.
dbId, pinIndex );
5157 if( occurrenceName == generatedName )
5158 generatedNamesAtPin.insert( &occurrenceName );
5163 if( generatedNamesAtPin.size() == 1 )
5164 return occurrenceElectricalName( *generatedNamesAtPin.begin() );
5166 if( net.empty() && !logicalName.empty() )
5168 std::set<const std::string*> matchingNames;
5172 if( wxString::FromUTF8( kicadOccurrenceNetName( occurrenceName ) )
5173 .CmpNoCase( wxString::FromUTF8( logicalName ) )
5176 matchingNames.insert( &occurrenceName );
5180 if( matchingNames.size() == 1 )
5182 if( std::optional<uint32_t> occurrenceId =
occurrenceNetIdFor( *matchingNames.begin() ) )
5189 if( std::optional<uint32_t> objectId = occurrenceNetObjectId( occurrenceName ) )
5191 auto sourceWire = std::find_if( aPage.
wires.begin(), aPage.
wires.end(),
5194 return aWire.dbId == *objectId;
5197 if( sourceWire != aPage.
wires.end() )
5199 occurrenceNamesByPageNetId[sourceWire->id].insert( &occurrenceName );
5206 return aInstance.dbId == *objectId;
5209 if( sourceInstance == aPage.
instances.end() )
5212 std::string occurrenceKey = occurrenceName;
5213 std::transform( occurrenceKey.begin(), occurrenceKey.end(), occurrenceKey.begin(),
5214 [](
unsigned char c )
5216 return static_cast<char>( std::tolower( c ) );
5219 auto matchesOccurrenceName = [&]( uint32_t aNetId )
5221 std::set<std::string> localNames;
5222 auto pageName = aPage.
netmap.find( aNetId );
5224 if( pageName != aPage.
netmap.end() )
5225 localNames.insert( pageName->second );
5227 auto aliases = aPage.
netAliases.find( aNetId );
5230 localNames.insert( aliases->second.begin(), aliases->second.end() );
5232 return std::any_of( localNames.begin(), localNames.end(),
5233 [&]( std::string aName )
5235 std::transform( aName.begin(), aName.end(), aName.begin(),
5236 []( unsigned char c )
5238 return static_cast<char>( std::tolower( c ) );
5240 return occurrenceKey == aName
5241 || ( occurrenceKey.size() > aName.size()
5242 && occurrenceKey[aName.size()] ==
'_'
5243 && occurrenceKey.compare( 0, aName.size(), aName ) == 0 );
5249 if( sourcePin.
wordB && matchesOccurrenceName( sourcePin.
wordB ) )
5250 occurrenceNamesByPageNetId[sourcePin.
wordB].insert( &occurrenceName );
5254 if( matchesOccurrenceName( wire.
id )
5258 occurrenceNamesByPageNetId[wire.
id].insert( &occurrenceName );
5265 std::set<const std::string*> objectNets;
5266 std::set<const std::string*> occurrenceNets;
5270 bool endpoint = (
pin.x == wire.
x1 &&
pin.y == wire.
y1 ) || (
pin.x == wire.
x2 &&
pin.y == wire.
y2 );
5275 auto objectNames = occurrenceNamesByPageNetId.find( wire.
id );
5277 if( objectNames != occurrenceNamesByPageNetId.end() && objectNames->second.size() == 1 )
5278 objectNets.insert( *objectNames->second.begin() );
5280 auto pageNet = aPage.
netmap.find( wire.
id );
5282 if( pageNet == aPage.
netmap.end() || pageNet->second.empty() )
5287 if( wxString::FromUTF8( pageNet->second ).CmpNoCase( wxString::FromUTF8( occurrenceName ) ) == 0 )
5288 occurrenceNets.insert( &occurrenceName );
5292 if( objectNets.size() == 1 )
5294 net = occurrenceElectricalName( *objectNets.begin() );
5295 authoritativeOccurrenceNet =
true;
5297 else if( occurrenceNets.size() == 1 )
5299 net = occurrenceElectricalName( *occurrenceNets.begin() );
5300 authoritativeOccurrenceNet =
true;
5304 if( m_currentOccNetNames && !authoritativeOccurrenceNet )
5306 std::set<const std::string*> directPinNets;
5320 auto names = occurrenceNamesByPageNetId.find( wire.
id );
5322 if( names != occurrenceNamesByPageNetId.end() && names->second.size() == 1 )
5323 directPinNets.insert( *names->second.begin() );
5328 if( directPinNets.size() == 1 )
5330 net = occurrenceElectricalName( *directPinNets.begin() );
5331 authoritativeOccurrenceNet =
true;
5335 if( m_currentOccNetNames && !authoritativeOccurrenceNet )
5337 std::string sourceName = trimmed( aInst.logicalName );
5338 std::set<uint32_t> matchingNetIds;
5340 for(
const auto& [netId, pageName] : aPage.netmap )
5342 bool matches = wxString::FromUTF8( pageName ).CmpNoCase( wxString::FromUTF8( sourceName ) ) == 0;
5343 auto aliases = aPage.netAliases.find( netId );
5345 if( aliases != aPage.netAliases.end() )
5348 || std::any_of( aliases->second.begin(), aliases->second.end(),
5349 [&](
const std::string& aAlias )
5351 return wxString::FromUTF8( aAlias ).CmpNoCase(
5352 wxString::FromUTF8( sourceName ) )
5358 matchingNetIds.insert( netId );
5361 if( matchingNetIds.size() == 1 )
5363 auto names = occurrenceNamesByPageNetId.find( *matchingNetIds.begin() );
5365 if( names != occurrenceNamesByPageNetId.end() && names->second.size() == 1 )
5367 net = occurrenceElectricalName( *names->second.begin() );
5368 authoritativeOccurrenceNet =
true;
5375 std::set<std::string> pinNetNames;
5384 for( uint32_t netId : { componentPin.
wordB, componentPin.
wordA } )
5386 std::set<std::string> sourceNames;
5387 auto netName = aPage.netmap.find( netId );
5389 if( netName != aPage.netmap.end() && !netName->second.empty() )
5390 sourceNames.insert( netName->second );
5392 auto aliases = aPage.netAliases.find( netId );
5394 if( aliases != aPage.netAliases.end() )
5395 sourceNames.insert( aliases->second.begin(), aliases->second.end() );
5397 std::set<std::string> occurrenceNames;
5399 if( m_currentOccNetNames )
5401 for(
const std::string& sourceName : sourceNames )
5403 for(
const auto& [occurrenceId, occurrenceName] : *m_currentOccNetNames )
5405 if( wxString::FromUTF8( sourceName ).CmpNoCase( wxString::FromUTF8( occurrenceName ) )
5408 occurrenceNames.insert( occurrenceName );
5414 if( occurrenceNames.size() == 1 )
5415 pinNetNames.insert( *occurrenceNames.begin() );
5416 else if( sourceNames.size() == 1 )
5417 pinNetNames.insert( *sourceNames.begin() );
5422 if( pinNetNames.size() == 1 )
5423 net = *pinNetNames.begin();
5426 auto namesEqual = [](
const std::string& aLeft,
const std::string& aRight )
5428 return wxString::FromUTF8( aLeft ).CmpNoCase( wxString::FromUTF8( aRight ) ) == 0;
5431 std::string physicalName = !propertyName.empty() ? propertyName : logicalName;
5433 if( !physicalName.empty() )
5437 bool endpoint = (
pin.x == wire.
x1 &&
pin.y == wire.
y1 ) || (
pin.x == wire.
x2 &&
pin.y == wire.
y2 );
5439 if( !endpoint && !onSegment(
pin.x,
pin.y, wire ) )
5442 std::vector<std::string> names;
5443 auto pageName = aPage.netmap.find( wire.
id );
5445 if( pageName != aPage.netmap.end() )
5446 names.push_back( pageName->second );
5448 auto aliases = aPage.netAliases.find( wire.
id );
5450 if( aliases != aPage.netAliases.end() )
5451 names.insert( names.end(), aliases->second.begin(), aliases->second.end() );
5453 std::set<std::string> distinctNames;
5455 for( std::string
name : names )
5457 std::transform(
name.begin(),
name.end(),
name.begin(),
5458 [](
unsigned char aChar ) { return static_cast<char>( std::tolower( aChar ) ); } );
5459 distinctNames.insert( std::move(
name ) );
5462 bool hasPhysicalName = std::any_of( names.begin(), names.end(),
5463 [&](
const std::string& aName )
5464 { return namesEqual( aName, physicalName ); } );
5466 if( ( !m_currentOccNetNames || m_currentOccNetNames->empty() ) && distinctNames.size() > 1
5467 && hasPhysicalName )
5468 return canonicalGlobalNetName( physicalName );
5472 if( m_currentOccNetNames && m_currentOccNetNames->empty() && !net.empty() && !isPowerNetName( net ) )
5474 std::string sourcePowerName = !logicalName.empty() ? logicalName : propertyName;
5476 if( isPowerNetName( sourcePowerName ) )
5477 net = std::move( sourcePowerName );
5480 if( m_currentOccNetNames && !authoritativeOccurrenceNet )
5482 std::set<const std::string*> occurrenceAliases;
5486 bool endpoint = (
pin.x == wire.
x1 &&
pin.y == wire.
y1 ) || (
pin.x == wire.
x2 &&
pin.y == wire.
y2 );
5488 if( !endpoint && !onSegment(
pin.x,
pin.y, wire ) )
5491 auto aliases = aPage.netAliases.find( wire.
id );
5493 if( aliases == aPage.netAliases.end() )
5496 for(
const std::string& alias : aliases->second )
5498 for(
const auto& [occurrenceId, occurrenceName] : *m_currentOccNetNames )
5500 if( wxString::FromUTF8( alias ).CmpNoCase( wxString::FromUTF8( occurrenceName ) ) == 0 )
5501 occurrenceAliases.insert( &occurrenceName );
5506 if( occurrenceAliases.size() == 1 )
5507 net = occurrenceElectricalName( *occurrenceAliases.begin() );
5510 bool implicitGeneratedName = net.size() > 1 && net[0] ==
'N'
5511 && std::all_of( net.begin() + 1, net.end(),
5512 [](
unsigned char c )
5514 return std::isdigit( c );
5517 if( net.empty() || ( implicitGeneratedName && !authoritativeOccurrenceNet ) )
5519 if( !logicalName.empty() )
5521 else if( !propertyName.empty() )
5528 return effectiveInterfaceNetName( net );
6095 bool aNestedHierarchy,
bool aSharedFolderPage )
6098 std::map<uint32_t, const std::string*> generatedNamesByObjectId;
6099 std::map<uint32_t, const std::string*> occurrenceNamesByNetId;
6100 std::set<uint32_t> localizedOwnedOccurrenceNetIds;
6101 std::map<uint32_t, std::string> connectorNamesByObjectId;
6102 std::set<uint32_t> globalConnectorObjectIds;
6103 std::map<uint32_t, std::string> netNamesByObjectId;
6104 std::map<uint32_t, const std::string*> netNamesByWireObjectId;
6105 std::map<uint32_t, std::set<std::string>> blockPinNamesByNetId;
6106 std::map<std::pair<int, int>, std::set<std::string>> connectorNamesByPosition;
6107 std::set<std::pair<int, int>> globalConnectorPositions;
6108 std::vector<size_t> wireParents( aPage.
wires.size() );
6109 std::map<size_t, std::set<std::string>> powerAliasesByWireGroup;
6110 std::map<size_t, std::set<std::string>> powerGlobalNamesByWireGroup;
6111 std::map<size_t, std::set<std::string>> resolvedPowerNamesByWireGroup;
6112 std::map<uint32_t, std::set<std::string>> resolvedPowerNamesByNetId;
6113 std::map<uint32_t, std::string> flattenedNamesByNetId;
6114 std::set<uint32_t> renamedNetIds;
6115 std::set<std::string> occurrenceNames;
6116 std::map<const std::string*, std::string> occurrenceElectricalNames;
6117 const std::map<std::string, std::string>* hierBusNames =
nullptr;
6118 std::iota( wireParents.begin(), wireParents.end(), 0 );
6126 auto occurrenceElectricalName = [&](
const std::string* aName ) ->
const std::string&
6128 return occurrenceElectricalNames.at( aName );
6131 auto wireRoot = [&](
size_t aIndex )
6133 while( wireParents[aIndex] != aIndex )
6135 wireParents[aIndex] = wireParents[wireParents[aIndex]];
6136 aIndex = wireParents[aIndex];
6142 auto joinWires = [&](
size_t aLeft,
size_t aRight )
6144 size_t left = wireRoot( aLeft );
6145 size_t right = wireRoot( aRight );
6153 return ( aPoint.
x == aWire.x1 && aPoint.
y == aWire.y1 ) || ( aPoint.
x == aWire.x2 && aPoint.
y == aWire.y2 )
6157 std::map<uint32_t, std::vector<size_t>> powerWireIndicesByNetId;
6159 for(
size_t i = 0; i < aPage.
wires.size(); ++i )
6161 if( !aPage.
wires[i].isBus )
6162 powerWireIndicesByNetId[aPage.
wires[i].id].push_back( i );
6167 for(
const auto& [netId, indices] : powerWireIndicesByNetId )
6176 bool connected = pointOnWire(
VECTOR2I( leftWire.
x1, leftWire.
y1 ), rightWire )
6177 || pointOnWire(
VECTOR2I( leftWire.
x2, leftWire.
y2 ), rightWire )
6178 || pointOnWire(
VECTOR2I( rightWire.
x1, rightWire.
y1 ), leftWire )
6179 || pointOnWire(
VECTOR2I( rightWire.
x2, rightWire.
y2 ), leftWire );
6183 connected = std::any_of( junctions.begin(), junctions.end(),
6186 return pointOnWire( aJunction, leftWire )
6187 && pointOnWire( aJunction, rightWire );
6192 joinWires( indices[
left], indices[
right] );
6199 if( !net.
name.empty() )
6206 connectorNamesByObjectId[global.
dbId] =
name;
6207 globalConnectorObjectIds.insert( global.
dbId );
6209 connectorNamesByPosition[{ position.
x, position.
y }].insert(
name );
6210 globalConnectorPositions.insert( { position.
x, position.
y } );
6212 std::set<std::string> sourceNames;
6215 if( !logicalName.empty() )
6216 sourceNames.insert( logicalName );
6218 auto property = global.
props.find(
"Name" );
6220 if( property != global.
props.end() )
6224 if( !propertyName.empty() )
6225 sourceNames.insert( propertyName );
6230 for(
size_t wireIndex = 0; wireIndex < aPage.
wires.size(); ++wireIndex )
6233 bool endpoint = (
pin.x == wire.
x1 &&
pin.y == wire.
y1 ) || (
pin.x == wire.
x2 &&
pin.y == wire.
y2 );
6237 size_t root = wireRoot( wireIndex );
6238 powerAliasesByWireGroup[root].insert( sourceNames.begin(), sourceNames.end() );
6239 powerGlobalNamesByWireGroup[root].insert( sourceNames.begin(), sourceNames.end() );
6240 resolvedPowerNamesByWireGroup[root].insert(
name );
6241 resolvedPowerNamesByNetId[wire.
id].insert(
name );
6246 for(
const auto& [root, globalNames] : powerGlobalNamesByWireGroup )
6248 if( globalNames.size() < 2 )
6251 for(
size_t wireIndex = 0; wireIndex < aPage.
wires.size(); ++wireIndex )
6253 if( aPage.
wires[wireIndex].isBus || wireRoot( wireIndex ) != root )
6261 powerAliasesByWireGroup[root].insert( std::move(
name ) );
6270 connectorNamesByObjectId[offpage.
dbId] =
name;
6271 if( !aHierarchical )
6272 globalConnectorObjectIds.insert( offpage.
dbId );
6274 connectorNamesByPosition[{ position.
x, position.
y }].insert( std::move(
name ) );
6275 if( !aHierarchical )
6276 globalConnectorPositions.insert( { position.
x, position.
y } );
6282 connectorNamesByObjectId[port.
dbId] =
name;
6283 if( !aHierarchical )
6284 globalConnectorObjectIds.insert( port.
dbId );
6286 connectorNamesByPosition[{ position.
x, position.
y }].insert( std::move(
name ) );
6287 if( !aHierarchical )
6288 globalConnectorPositions.insert( { position.
x, position.
y } );
6300 connectorNamesByPosition[{
pin.x,
pin.y }].insert(
name );
6305 blockPinNamesByNetId[wire.
id].insert(
name );
6310 auto isImplicitGeneratedName = [](
const std::string& aName )
6312 if( aName.size() < 2 || aName[0] !=
'N' || !std::isdigit(
static_cast<unsigned char>( aName[1] ) ) )
6315 return std::all_of( aName.begin() + 1, aName.end(),
6316 [](
unsigned char c )
6318 return std::isdigit( c );
6325 hierBusNames = &busNames->second;
6329 std::map<uint32_t, uint32_t> netIdByWireObjectId;
6330 std::map<uint32_t, std::set<const std::string*>> objectNamesByNetId;
6333 netIdByWireObjectId[wire.
dbId] = wire.
id;
6335 auto lower = [](
const std::string& aName )
6337 std::string
result = aName;
6339 [](
unsigned char c )
6341 return static_cast<char>( std::tolower( c ) );
6345 for(
const auto& [netId, localName] : aPage.
netmap )
6347 std::set<std::string> localNames = { localName };
6348 std::set<const std::string*> candidates;
6349 std::set<const std::string*> ownedCandidates;
6350 bool localizedOwnedCandidate =
false;
6352 auto aliases = aPage.
netAliases.find( netId );
6355 localNames.insert( aliases->second.begin(), aliases->second.end() );
6357 bool directOffpage = std::any_of(
6361 std::string connectorName = aConnector.logicalName.empty() ? aConnector.name
6362 : aConnector.logicalName;
6363 std::string connectorKey = lower( connectorName );
6364 return std::any_of( localNames.begin(), localNames.end(),
6365 [&]( const std::string& aName )
6367 return lower( aName ) == connectorKey;
6371 for(
const std::string& candidateLocalName : localNames )
6373 bool implicitGenerated = isImplicitGeneratedName( candidateLocalName );
6374 std::string localKey = lower( candidateLocalName );
6378 std::string occurrenceKey = lower( occurrenceName );
6379 bool occurrenceOwnedByNet =
false;
6381 if( std::optional<uint32_t> objectId = occurrenceNetObjectId( occurrenceName ) )
6383 occurrenceOwnedByNet = std::any_of(
6387 if( aInstance.dbId != *objectId )
6391 aInstance.pins.begin(), aInstance.pins.end(),
6392 [&]( const ORCAD_PIN_INST& aPin )
6394 if( aPin.wordB == netId )
6398 aPage.wires.begin(), aPage.wires.end(),
6399 [&]( const ORCAD_WIRE& aWire )
6401 return aWire.id == netId
6402 && ( aPin.wordA == aWire.dbId
6403 || rawPointOnSegment( aPin.x, aPin.y,
6410 if( occurrenceKey == localKey
6411 || ( !implicitGenerated
6413 && !
isPowerNetName( candidateLocalName ) && occurrenceKey.size() > localKey.size()
6414 && occurrenceKey[localKey.size()] ==
'_'
6415 && occurrenceKey.compare( 0, localKey.size(), localKey ) == 0 ) )
6417 candidates.insert( &occurrenceName );
6419 if( occurrenceOwnedByNet && !directOffpage )
6421 ownedCandidates.insert( &occurrenceName );
6422 localizedOwnedCandidate |= !sharedFlatFolder &&
isOffpageNetName( candidateLocalName );
6428 if( ownedCandidates.size() == 1 )
6430 occurrenceNamesByNetId[netId] = *ownedCandidates.begin();
6431 if( localizedOwnedCandidate )
6432 localizedOwnedOccurrenceNetIds.insert( netId );
6434 else if( candidates.size() == 1 )
6436 occurrenceNamesByNetId[netId] = *candidates.begin();
6438 const std::string* selected = *candidates.begin();
6439 std::string selectedKey = lower( kicadOccurrenceNetName( *selected ) );
6440 bool localOffpage = std::any_of( localNames.begin(), localNames.end(),
6441 [&](
const std::string& aName )
6443 return isOffpageNetName( aName )
6444 && lower( aName ) == selectedKey;
6446 bool competingSuffixedOccurrence = std::any_of(
6448 [&](
const auto& aOccurrence )
6450 std::string key = lower( kicadOccurrenceNetName( aOccurrence.second ) );
6451 return &aOccurrence.second != selected && key.size() > selectedKey.size()
6452 && key[selectedKey.size()] ==
'_'
6453 && key.compare( 0, selectedKey.size(), selectedKey ) == 0
6454 && occurrenceNetObjectId( aOccurrence.second ).has_value();
6457 if( localOffpage && !directOffpage && competingSuffixedOccurrence )
6459 std::optional<uint32_t> componentId;
6463 bool connected = std::any_of(
6464 instance.
pins.begin(), instance.
pins.end(),
6467 if( aPin.wordB == netId )
6470 return std::any_of( aPage.wires.begin(), aPage.wires.end(),
6471 [&]( const ORCAD_WIRE& aWire )
6473 return aWire.id == netId
6474 && ( aPin.wordA == aWire.dbId
6475 || rawPointOnSegment( aPin.x, aPin.y,
6480 if( connected && ( !componentId || instance.
dbId < *componentId ) )
6481 componentId = instance.
dbId;
6486 occurrenceElectricalNames[selected] = kicadOccurrenceNetName( *selected ) +
"_"
6487 + std::to_string( *componentId );
6489 if( !sharedFlatFolder )
6490 localizedOwnedOccurrenceNetIds.insert( netId );
6496 for(
const auto& [occurrenceId,
name] : *m_currentOccNetNames )
6498 occurrenceNames.insert(
name );
6500 if( std::optional<uint32_t> objectId = occurrenceNetObjectId(
name ) )
6502 auto netId = netIdByWireObjectId.find( *objectId );
6504 if( netId != netIdByWireObjectId.end() )
6505 objectNamesByNetId[netId->second].insert( &
name );
6508 if(
name.size() < 2 ||
name[0] !=
'N' )
6511 uint64_t objectId = 0;
6513 auto it =
name.begin() + 1;
6515 for( ; it !=
name.end() && std::isdigit(
static_cast<unsigned char>( *it ) ); ++it )
6517 objectId = objectId * 10 +
static_cast<unsigned>( *it -
'0' );
6520 if( objectId && objectId <= std::numeric_limits<uint32_t>::max() && ( it ==
name.end() || *it ==
'_' ) )
6522 generatedNamesByObjectId[
static_cast<uint32_t
>( objectId )] = &
name;
6526 for(
const auto& [netId, names] : objectNamesByNetId )
6528 if( names.size() == 1 )
6529 occurrenceNamesByNetId[netId] = *names.begin();
6532 for(
const auto& [netId, occurrenceName] : occurrenceNamesByNetId )
6534 std::string electricalName = occurrenceElectricalNames.at( occurrenceName );
6535 bool collides = std::any_of( aPage.netmap.begin(), aPage.netmap.end(),
6536 [&](
const auto& aPageNet )
6538 return aPageNet.first != netId
6539 && wxString::FromUTF8(
6540 kicadElectricalNetName( aPageNet.second ) )
6541 .CmpNoCase( wxString::FromUTF8( electricalName ) )
6548 std::optional<uint32_t> occurrenceId = occurrenceNetIdFor( occurrenceName );
6553 std::string suffix = std::to_string( *occurrenceId );
6555 if( suffix.size() < 6 )
6556 suffix.insert( 0, 6 - suffix.size(),
'0' );
6558 occurrenceElectricalNames[occurrenceName] +=
"_" + suffix;
6562 std::map<uint32_t, const std::string*> netNamesById;
6563 std::map<uint32_t, std::vector<size_t>> wiresByNetId;
6564 std::set<uint32_t> ambiguousNetIds;
6566 for(
const auto& [netId,
name] : aPage.netmap )
6568 auto aliases = aPage.netAliases.find( netId );
6569 std::set<std::string> distinctNames;
6571 if( aliases != aPage.netAliases.end() )
6573 for(
const std::string& alias : aliases->second )
6575 if( !alias.empty() )
6576 distinctNames.insert( alias );
6580 if( distinctNames.size() > 1 )
6582 ambiguousNetIds.insert( netId );
6584 if( isPowerNetName(
name ) )
6585 netNamesById[netId] = &
name;
6590 bool explicitAlias =
6591 aliases != aPage.netAliases.end()
6592 && std::find( aliases->second.begin(), aliases->second.end(),
name ) != aliases->second.end();
6594 if( !
name.empty() && ( !isImplicitGeneratedName(
name ) || explicitAlias ) )
6595 netNamesById[netId] = &
name;
6598 for(
const auto& [netId,
name] : occurrenceNamesByNetId )
6600 netNamesById[netId] =
name;
6601 m_sourceNetNames[{ aScreen, netId }].insert( *
name );
6604 std::set<uint32_t> explicitlyAliasedNets;
6609 explicitlyAliasedNets.insert( wire.
id );
6613 std::map<uint32_t, std::string> generatedSourceNames = aPage.netmap;
6615 for(
const auto& [netId,
name] : occurrenceNamesByNetId )
6616 generatedSourceNames.try_emplace( netId, kicadOccurrenceNetName( *
name ) );
6618 for(
const auto& [netId, sourceName] : generatedSourceNames )
6620 bool occurrenceOnly = !aPage.netmap.count( netId );
6621 std::string generatedBase = occurrenceOnly ? sourceName.substr( 0, sourceName.find(
'_' ) ) : sourceName;
6623 if( !isImplicitGeneratedName( generatedBase ) )
6626 auto aliases = aPage.netAliases.find( netId );
6629 if( explicitlyAliasedNets.count( netId )
6630 || ( aliases != aPage.netAliases.end()
6631 && std::any_of( aliases->second.begin(), aliases->second.end(),
6632 [&](
const std::string& alias )
6634 return !alias.empty() && alias != sourceName;
6638 auto occurrence = occurrenceNamesByNetId.find( netId );
6639 std::string
name = occurrence != occurrenceNamesByNetId.end()
6640 ? kicadOccurrenceNetName( *occurrence->second ) : sourceName;
6642 if( m_scopeGeneratedFlatNets && isImplicitGeneratedName(
name ) )
6646 std::optional<uint32_t> occurrenceId;
6648 if( occurrence != occurrenceNamesByNetId.end() )
6649 occurrenceId = occurrenceNetIdFor( occurrence->second );
6653 name +=
"_" + std::to_string( *occurrenceId );
6657 if( m_currentFlatNetSuffix.empty() )
6660 std::string suffix = m_currentFlatNetSuffix;
6661 std::transform( suffix.begin(), suffix.end(), suffix.begin(),
6662 [](
unsigned char c )
6664 return static_cast<char>( std::toupper( c ) );
6666 name +=
"_" + suffix;
6670 if( ( isImplicitGeneratedName(
name ) ||
name.starts_with( generatedBase +
"_" ) )
6671 && !isPowerNetName(
name ) && !isOffpageNetName(
name ) )
6673 m_sourceNetNames[{ aScreen, netId }].insert(
name );
6674 m_sourceGeneratedNetNames[{ aScreen, netId }] = std::move(
name );
6678 for(
const auto& [netId, occurrenceName] : occurrenceNamesByNetId )
6680 std::string occurrenceKey = kicadOccurrenceNetName( *occurrenceName );
6681 std::transform( occurrenceKey.begin(), occurrenceKey.end(), occurrenceKey.begin(),
6682 [](
unsigned char c )
6684 return static_cast<char>( std::tolower( c ) );
6686 auto occurrenceDepth = m_occurrenceNetNameMinDepth.find( occurrenceKey );
6688 if( occurrenceDepth == m_occurrenceNetNameMinDepth.end() )
6691 std::map<size_t, std::set<std::string>> candidatesByDepth;
6692 std::set<std::string> sourceNames;
6693 auto pageName = aPage.netmap.find( netId );
6695 if( pageName != aPage.netmap.end() && !pageName->second.empty() )
6696 sourceNames.insert( canonicalGlobalNetName( pageName->second ) );
6698 auto aliases = aPage.netAliases.find( netId );
6700 if( aliases != aPage.netAliases.end() )
6702 for(
const std::string& alias : aliases->second )
6703 sourceNames.insert( canonicalGlobalNetName( alias ) );
6706 for(
const std::string& sourceName : sourceNames )
6708 std::string sourceKey = sourceName;
6709 std::transform( sourceKey.begin(), sourceKey.end(), sourceKey.begin(),
6710 [](
unsigned char c )
6712 return static_cast<char>( std::tolower( c ) );
6714 auto sourceDepth = m_occurrenceNetNameMinDepth.find( sourceKey );
6716 if( sourceDepth != m_occurrenceNetNameMinDepth.end() && sourceDepth->second < occurrenceDepth->second )
6717 candidatesByDepth[sourceDepth->second].insert( sourceName );
6720 if( !candidatesByDepth.empty() && candidatesByDepth.begin()->second.size() == 1 )
6722 std::string& flattened = flattenedNamesByNetId[netId];
6723 flattened = *candidatesByDepth.begin()->second.begin();
6724 netNamesById[netId] = &flattened;
6725 renamedNetIds.insert( netId );
6729 std::map<std::string, std::set<uint32_t>> blockNetIdsByName;
6731 for(
const auto& [netId,
name] : aPage.netmap )
6733 if( !
name.empty() && !isImplicitGeneratedName(
name ) )
6734 blockNetIdsByName[canonicalGlobalNetName(
name )].insert( netId );
6737 for(
const auto& [netId, names] : blockPinNamesByNetId )
6739 if( !names.empty() )
6740 blockNetIdsByName[*names.begin()].insert( netId );
6743 std::map<uint32_t, std::string> blockElectricalNames;
6744 std::set<uint32_t> blockElectricalNetIds;
6746 for(
const auto& [netId, names] : blockPinNamesByNetId )
6748 auto currentName = netNamesById.find( netId );
6750 if( !names.empty() && ( currentName == netNamesById.end() || isImplicitGeneratedName( *currentName->second ) ) )
6752 std::string
name = *names.begin();
6754 if( blockNetIdsByName.at(
name ).size() > 1 )
6756 std::string suffix = std::to_string( netId );
6758 if( suffix.size() < 6 )
6759 suffix.insert( 0, 6 - suffix.size(),
'0' );
6761 name +=
"_" + suffix;
6764 auto inserted = blockElectricalNames.emplace( netId, std::move(
name ) ).first;
6765 netNamesById[netId] = &inserted->second;
6766 blockElectricalNetIds.insert( netId );
6770 if( !m_currentUnconnectedInterfaceNetNames.empty() )
6775 std::string key =
name;
6776 std::transform( key.begin(), key.end(), key.begin(),
6777 [](
unsigned char c )
6779 return static_cast<char>( std::tolower( c ) );
6782 auto targetName = m_currentUnconnectedInterfaceNetNames.find( key );
6784 if( targetName == m_currentUnconnectedInterfaceNetNames.end() )
6791 if( wire.
isBus || !pointOnWire(
pin, wire ) )
6794 std::string& flattened = flattenedNamesByNetId[wire.
id];
6795 flattened = targetName->second;
6796 netNamesById[wire.
id] = &flattened;
6797 renamedNetIds.insert( wire.
id );
6804 auto name = netNamesById.find( wire.
id );
6806 if(
name != netNamesById.end() )
6807 netNamesByWireObjectId[wire.
dbId] =
name->second;
6810 std::set<std::string> interfaceNames;
6811 std::set<uint32_t> interfaceNetIds;
6812 std::map<uint32_t, std::set<std::string>> globalInterfaceNamesByNetId;
6814 auto addInterfacePoint = [&](
const VECTOR2I& aPin,
const std::string* aGlobalName,
6815 std::optional<uint32_t> aNetId )
6819 bool endpoint = ( aPin.
x == wire.
x1 && aPin.
y == wire.
y1 ) || ( aPin.
x == wire.
x2 && aPin.
y == wire.
y2 );
6821 if( !wire.
isBus && ( !aNetId || wire.
id == *aNetId )
6822 && ( endpoint || onSegment( aPin.
x, aPin.
y, wire ) ) )
6824 interfaceNetIds.insert( wire.
id );
6826 if( aGlobalName && !aGlobalName->empty() )
6827 globalInterfaceNamesByNetId[wire.
id].insert( *aGlobalName );
6832 auto addInterfaceName = [&](
const ORCAD_GRAPHIC_INST& aInstance,
bool aGlobal,
bool aPower )
6837 name = powerNet( aPage, aInstance );
6839 name = effectiveInterfaceNetName(
name );
6842 interfaceNames.insert(
name );
6844 VECTOR2I pin = aPower ? powerPinPos( aPage, aInstance ) : namedGraphicPinPos( aPage, aInstance );
6845 std::optional<uint32_t> sourceNetId;
6856 THROW_IO_ERROR( wxString::Format(
_(
"Page '%s': cannot determine the source net for interface '%s' "
6861 if( sourceWires->empty() || bus )
6864 sourceNetId = netId;
6867 addInterfacePoint(
pin, aGlobal ? &
name :
nullptr, sourceNetId );
6871 addInterfaceName( port,
false,
false );
6874 addInterfaceName( connector, !aHierarchical,
false );
6877 addInterfaceName( global,
true,
true );
6879 for(
const auto& [netId,
name] : occurrenceNamesByNetId )
6881 auto selectedName = netNamesById.find( netId );
6883 if( selectedName == netNamesById.end() || selectedName->second !=
name )
6886 std::string sourceName = kicadOccurrenceNetName( *
name );
6888 std::transform( sourceName.begin(), sourceName.end(), sourceName.begin(),
6889 [](
unsigned char c )
6891 return static_cast<char>( std::tolower( c ) );
6894 if( !sharedFlatFolder && ( m_scopeNamedFlatNets || m_scopeGeneratedFlatNets || aNestedHierarchy )
6895 && !m_currentInterfaceNetAliases.count( sourceName )
6896 && m_occurrenceNetNameScopeCounts[sourceName] > 1 )
6901 if( !aNestedHierarchy
6902 && ( localizedOwnedOccurrenceNetIds.count( netId )
6903 || !m_currentConnectorInterfaceNetAliases.count( sourceName ) ) )
6905 globalInterfaceNamesByNetId[netId].clear();
6906 globalInterfaceNamesByNetId[netId].insert( occurrenceElectricalName(
name ) );
6914 addInterfacePoint(
VECTOR2I(
pin.x,
pin.y ),
nullptr, std::nullopt );
6917 if( m_scopeNamedFlatNets && !m_currentFlatNetSuffix.empty() )
6919 for(
const auto& [netId,
name] : aPage.netmap )
6921 if(
name.empty() || interfaceNetIds.count( netId ) || interfaceNames.count(
name )
6922 || isOffpageNetName(
name ) )
6925 auto selected = netNamesById.find( netId );
6927 if( selected == netNamesById.end() || *selected->second !=
name )
6930 std::string& flattened = flattenedNamesByNetId[netId];
6931 flattened =
name +
"_" + m_currentFlatNetSuffix;
6932 netNamesById[netId] = &flattened;
6933 renamedNetIds.insert( netId );
6937 for(
size_t i = 0; i < aPage.wires.size(); ++i )
6944 wiresByNetId[wire.
id].push_back( i );
6946 auto generatedName = generatedNamesByObjectId.find( wire.
dbId );
6948 if( generatedName != generatedNamesByObjectId.end() )
6950 if( m_scopeGeneratedFlatNets && !m_currentFlatNetSuffix.empty() && !interfaceNetIds.count( wire.
id ) )
6952 std::string& flattened = flattenedNamesByNetId[wire.
id];
6953 flattened = *generatedName->second +
"_" + m_currentFlatNetSuffix;
6954 netNamesById[wire.
id] = &flattened;
6955 renamedNetIds.insert( wire.
id );
6960 std::set<VECTOR2I> electricalContacts;
6964 electricalContacts.emplace( wire.
x1, wire.
y1 );
6965 electricalContacts.emplace( wire.
x2, wire.
y2 );
6971 electricalContacts.insert( placedPinElectricalPosition( instance,
index ) );
6974 for(
const auto* connectors : { &aPage.globals, &aPage.ports, &aPage.offpage } )
6977 electricalContacts.emplace( connector.
x, connector.
y );
6983 electricalContacts.emplace(
pin.x,
pin.y );
6986 std::map<int, std::vector<size_t>> horizontalWires;
6987 std::map<int, std::vector<size_t>> verticalWires;
6988 std::map<size_t, std::vector<VECTOR2I>> cutsByWire;
6990 for(
size_t i = 0; i < aPage.wires.size(); ++i )
6997 if( wire.
y1 == wire.
y2 )
6998 horizontalWires[wire.
y1].push_back( i );
6999 else if( wire.
x1 == wire.
x2 )
7000 verticalWires[wire.
x1].push_back( i );
7003 for(
const auto& [y, horizontalIndices] : horizontalWires )
7005 for(
size_t horizontalIndex : horizontalIndices )
7007 const ORCAD_WIRE& horizontal = aPage.wires[horizontalIndex];
7008 int minX = std::min( horizontal.
x1, horizontal.
x2 );
7009 int maxX = std::max( horizontal.
x1, horizontal.
x2 );
7011 for(
auto verticalIt = verticalWires.lower_bound( minX );
7012 verticalIt != verticalWires.end() && verticalIt->first <= maxX; ++verticalIt )
7014 for(
size_t verticalIndex : verticalIt->second )
7016 const ORCAD_WIRE& vertical = aPage.wires[verticalIndex];
7024 if( !electricalContacts.count(
VECTOR2I( vertical.
x1, y ) ) )
7028 size_t cutIndex = netNamesById.count( vertical.
id ) ? verticalIndex : horizontalIndex;
7030 if( netNamesById.count( aPage.wires[cutIndex].id ) )
7031 cutsByWire[cutIndex].emplace_back( vertical.
x1, y );
7041 if(
pin.wordA ||
pin.wordB )
7044 for(
size_t wireIndex = 0; wireIndex < aPage.wires.size(); ++wireIndex )
7046 const ORCAD_WIRE& wire = aPage.wires[wireIndex];
7048 if( !wire.
isBus && netNamesById.count( wire.
id ) && onSegment(
pin.x,
pin.y, wire ) )
7049 cutsByWire[wireIndex].emplace_back(
pin.x,
pin.y );
7054 std::set<size_t> labelWireIndices;
7056 for(
const auto& [netId, wireIndices] : wiresByNetId )
7058 if( !netNamesById.count( netId ) && globalInterfaceNamesByNetId[netId].size() != 1 )
7061 std::set<size_t> unseen( wireIndices.begin(), wireIndices.end() );
7063 while( !unseen.empty() )
7065 size_t representative = *unseen.begin();
7066 std::vector<size_t> pending = { representative };
7067 unseen.erase( representative );
7069 while( !pending.empty() )
7071 const ORCAD_WIRE& current = aPage.wires[pending.back()];
7074 for(
auto it = unseen.begin(); it != unseen.end(); )
7076 const ORCAD_WIRE& candidate = aPage.wires[*it];
7077 bool touches = onSegment( current.
x1, current.
y1, candidate )
7078 || onSegment( current.
x2, current.
y2, candidate )
7079 || onSegment( candidate.
x1, candidate.
y1, current )
7080 || onSegment( candidate.
x2, candidate.
y2, current );
7084 pending.push_back( *it );
7085 it = unseen.erase( it );
7094 labelWireIndices.insert( representative );
7098 for(
size_t wireIndex = 0; wireIndex < aPage.wires.size(); ++wireIndex )
7100 const ORCAD_WIRE& wire = aPage.wires[wireIndex];
7101 auto appendSegment = [&](
const VECTOR2I& aStart,
const VECTOR2I& aEnd,
int aLayer )
7103 if( aStart == aEnd )
7111 appendPageItem( aScreen, line );
7114 m_sourceNetItems[{ aScreen, wire.
id }].push_back( line );
7117 std::vector<VECTOR2I> cuts = cutsByWire[wireIndex];
7119 int64_t dx =
static_cast<int64_t
>( wire.
x2 ) - wire.
x1;
7120 int64_t dy =
static_cast<int64_t
>( wire.
y2 ) - wire.
y1;
7122 std::sort( cuts.begin(), cuts.end(),
7125 int64_t ta = ( static_cast<int64_t>( a.x ) - wire.x1 ) * dx
7126 + ( static_cast<int64_t>( a.y ) - wire.y1 ) * dy;
7127 int64_t tb = ( static_cast<int64_t>( b.x ) - wire.x1 ) * dx
7128 + ( static_cast<int64_t>( b.y ) - wire.y1 ) * dy;
7131 cuts.erase( std::unique( cuts.begin(), cuts.end() ), cuts.end() );
7133 VECTOR2I step( dx == 0 ? 0 : ( dx > 0 ? 1 : -1 ), dy == 0 ? 0 : ( dy > 0 ? 1 : -1 ) );
7136 auto netName = netNamesById.find( wire.
id );
7140 return VECTOR2I( aStart.
x + ( aEnd.x - aStart.
x ) / 2, aStart.
y + ( aEnd.y - aStart.
y ) / 2 );
7142 auto wireIntentPosition = [&](
const VECTOR2I& aStart,
const VECTOR2I& aEnd )
7144 VECTOR2I midpoint = segmentMidpoint( aStart, aEnd );
7145 VECTOR2I direction( aEnd.x == aStart.
x ? 0 : ( aEnd.x > aStart.
x ? 1 : -1 ),
7146 aEnd.y == aStart.
y ? 0 : ( aEnd.y > aStart.
y ? 1 : -1 ) );
7147 std::vector<VECTOR2I> candidates = { midpoint, aStart + direction, aEnd - direction };
7149 for(
int numerator : { 1, 3, 2, 6 } )
7151 constexpr int denominator = 8;
7152 candidates.emplace_back( aStart.
x + ( aEnd.x - aStart.
x ) * numerator / denominator,
7153 aStart.
y + ( aEnd.y - aStart.
y ) * numerator / denominator );
7156 for(
const VECTOR2I& candidate : candidates )
7158 if( candidate == aStart || candidate == aEnd || !onSegment( candidate.x, candidate.y, wire ) )
7161 bool crossesAnotherNet =
7162 std::any_of( aPage.wires.begin(), aPage.wires.end(),
7165 return &aOther != &wire
7166 && ( aOther.isBus != wire.isBus || aOther.id != wire.id )
7167 && onSegment( candidate.x, candidate.y, aOther );
7170 if( !crossesAnotherNet )
7176 auto appendWireNetIntents = [&](
const VECTOR2I& aPosition )
7178 std::set<std::string> names;
7179 size_t wireGroup = wireRoot( wireIndex );
7180 bool ambiguousPhysicalNet = ambiguousNetIds.count( wire.
id );
7181 auto resolvedPower = resolvedPowerNamesByWireGroup.find( wireGroup );
7183 if( ambiguousPhysicalNet && resolvedPower != resolvedPowerNamesByWireGroup.end() )
7184 names.insert( resolvedPower->second.begin(), resolvedPower->second.end() );
7185 else if( ambiguousPhysicalNet )
7187 auto netPower = resolvedPowerNamesByNetId.find( wire.
id );
7189 if( netPower != resolvedPowerNamesByNetId.end() && netPower->second.size() == 1 )
7190 names.insert( *netPower->second.begin() );
7193 auto aliases = aPage.netAliases.find( wire.
id );
7195 if( aliases != aPage.netAliases.end() && !ambiguousPhysicalNet && !occurrenceNamesByNetId.count( wire.
id ) )
7197 for(
const std::string& alias : aliases->second )
7198 names.insert( alias );
7201 auto powerAliases = powerAliasesByWireGroup.find( wireGroup );
7203 bool joinedPowerAliases = !ambiguousPhysicalNet && powerAliases != powerAliasesByWireGroup.end()
7204 && powerAliases->second.size() > 1
7205 && powerGlobalNamesByWireGroup[wireGroup].size() > 1;
7207 if( joinedPowerAliases )
7208 names.insert( powerAliases->second.begin(), powerAliases->second.end() );
7210 if( ambiguousPhysicalNet && occurrenceNamesByNetId.count( wire.
id ) )
7212 names.insert( *occurrenceNamesByNetId.at( wire.
id ) );
7214 else if( !ambiguousPhysicalNet && netName != netNamesById.end() )
7216 std::string key = *netName->second;
7217 std::transform( key.begin(), key.end(), key.begin(),
7218 [](
unsigned char c )
7220 return static_cast<char>( std::tolower( c ) );
7223 if( !m_currentConnectorInterfaceNetAliases.count( key ) )
7224 names.insert( *netName->second );
7227 if( !ambiguousPhysicalNet )
7228 names.insert( globalInterfaceNamesByNetId[wire.
id].begin(), globalInterfaceNamesByNetId[wire.
id].end() );
7229 else if( globalInterfaceNamesByNetId[wire.
id].size() == 1 )
7230 names.insert( *globalInterfaceNamesByNetId[wire.
id].begin() );
7234 std::vector<std::string> sourceNames( names.begin(), names.end() );
7236 for(
const std::string&
name : sourceNames )
7240 for(
const std::string&
name : names )
7245 bool occurrenceName = occurrenceNamesByNetId.count( wire.
id )
7246 &&
name == *occurrenceNamesByNetId.at( wire.
id );
7248 occurrenceName ? occurrenceElectricalName( occurrenceNamesByNetId.at( wire.
id ) )
7249 : kicadElectricalNetName(
name ) );
7252 auto sourceName = aPage.netmap.find( wire.
id );
7253 bool generated = isImplicitGeneratedName(
name )
7254 || ( sourceName != aPage.netmap.end() && isImplicitGeneratedName( sourceName->second )
7255 &&
name.starts_with( sourceName->second +
"_" ) );
7256 bool explicitName = ( !generated && sourceName != aPage.netmap.end()
7257 && canonicalGlobalNetName( sourceName->second ) ==
name )
7261 return alias.name == name;
7263 appendNetIntent( aScreen, label, explicitName, wire.
id );
7272 if( !onSegment( before.
x, before.
y, wire ) )
7275 if( !onSegment( after.
x, after.
y, wire ) )
7281 appendWireNetIntents( wireIntentPosition(
cursor, before ) );
7291 appendWireNetIntents( wireIntentPosition(
cursor,
end ) );
7296 std::string electricalName = kicadElectricalNetName( trimmed( alias.
name ) );
7297 std::string mappedName = electricalName;
7305 bool mappedBusAlias = mappedName != electricalName;
7308 if(
text.IsEmpty() )
7314 int fontId = wireAliasFontId( alias );
7315 bool electrical = !( ambiguousNetIds.count( wire.
id ) && netName != netNamesById.end()
7316 && isPowerNetName( *netName->second )
7317 && canonicalGlobalNetName( alias.
name ) != *netName->second );
7319 if( !mappedBusAlias && occurrenceNamesByNetId.count( wire.
id ) && netName != netNamesById.end()
7320 && canonicalGlobalNetName( alias.
name ) != canonicalGlobalNetName( *netName->second ) )
7327 && std::any_of( aPage.wires.begin(), aPage.wires.end(),
7330 return !aOther.isBus && aOther.id != wire.id
7331 && anchor != VECTOR2I( aOther.x1, aOther.y1 )
7332 && anchor != VECTOR2I( aOther.x2, aOther.y2 )
7333 && onSegment( anchor.x, anchor.y, aOther );
7336 if( interiorCrossing && std::find( cuts.begin(), cuts.end(),
anchor ) != cuts.end() )
7340 if( candidate ==
anchor || !onSegment( candidate.
x, candidate.
y, wire ) )
7341 candidate =
anchor + step;
7343 electricalAnchor = candidate;
7346 if( electrical && ( ( electricalText !=
text && !mappedBusAlias ) || electricalAnchor !=
anchor ) )
7350 appendNetIntent( aScreen, label,
true, wire.
id );
7359 applyFont( label, fontId );
7361 appendPageItem( aScreen, label );
7362 m_labelSourceNets[label] = { aScreen, wire.
id };
7371 applyFont( note, fontId );
7373 appendPageItem( aScreen, note );
7377 size_t wireGroup = wireRoot( wireIndex );
7378 bool hasPowerAliases = powerAliasesByWireGroup.count( wireGroup )
7379 && powerAliasesByWireGroup.at( wireGroup ).size() > 1
7380 && powerGlobalNamesByWireGroup[wireGroup].size() > 1;
7382 bool authoritativeInterface = globalInterfaceNamesByNetId[wire.
id].size() == 1;
7385 && ( hasPowerAliases
7386 || ( labelWireIndices.count( wireIndex )
7387 && ( netName != netNamesById.end() || authoritativeInterface ) ) ) )
7389 appendWireNetIntents( wireIntentPosition(
VECTOR2I( wire.
x1, wire.
y1 ),
end ) );
7396 return std::any_of( aPage.wires.begin(), aPage.wires.end(),
7399 return ( aPin.x == aWire.x1 && aPin.y == aWire.y1 )
7400 || ( aPin.x == aWire.x2 && aPin.y == aWire.y2 )
7401 || onSegment( aPin.x, aPin.y, aWire );
7405 m_currentImplicitPowerPins.clear();
7406 std::map<std::pair<int, int>, std::string> generatedWirelessNets;
7410 for(
size_t pinIndex = 0; pinIndex < instance.
pins.size(); ++pinIndex )
7413 VECTOR2I electricalPosition = placedPinElectricalPosition( instance, pinIndex );
7415 if( (
pin.wordA ||
pin.wordB )
7416 && ( electricalPosition !=
VECTOR2I(
pin.x,
pin.y ) || !pinTouchesWire(
pin ) ) )
7418 std::string generatedName = generatedPinNetName( instance.
dbId, pinIndex );
7420 if( occurrenceNames.count( generatedName ) )
7421 generatedWirelessNets[{ electricalPosition.
x, electricalPosition.
y }] = std::move( generatedName );
7430 for(
size_t pinIndex = 0; pinIndex < instance.
pins.size(); ++pinIndex )
7433 VECTOR2I electricalPosition = placedPinElectricalPosition( instance, pinIndex );
7435 if( !
pin.wordA && !
pin.wordB )
7438 std::string generatedName = generatedPinNetName( instance.
dbId, pinIndex );
7440 bool globalName =
false;
7445 if( occurrenceNames.count( generatedName ) )
7446 name = std::move( generatedName );
7447 else if( generatedWirelessNets.count( { electricalPosition.x, electricalPosition.y } ) )
7448 name = generatedWirelessNets.at( { electricalPosition.
x, electricalPosition.
y } );
7449 else if(
pin.wordA && netNamesByWireObjectId.count(
pin.wordA ) )
7450 name = *netNamesByWireObjectId.at(
pin.wordA );
7451 else if(
pin.wordA && netNamesByObjectId.count(
pin.wordA ) )
7452 name = netNamesByObjectId.at(
pin.wordA );
7453 else if(
pin.wordA && connectorNamesByObjectId.count(
pin.wordA ) )
7455 name = connectorNamesByObjectId.at(
pin.wordA );
7456 globalName = globalConnectorObjectIds.count(
pin.wordA );
7458 else if(
pin.wordB )
7460 auto occurrenceName = occurrenceNamesByNetId.find(
pin.wordB );
7461 auto pageName = aPage.netmap.find(
pin.wordB );
7463 if( occurrenceName != occurrenceNamesByNetId.end() )
7465 name = occurrenceElectricalName( occurrenceName->second );
7466 std::string sourceName = kicadOccurrenceNetName( *occurrenceName->second );
7467 std::string key = sourceName;
7468 std::transform( key.begin(), key.end(), key.begin(),
7469 [](
unsigned char c )
7471 return static_cast<char>( std::tolower( c ) );
7473 globalName = !localizedOwnedOccurrenceNetIds.count(
pin.wordB )
7474 && ( sharedFlatFolder
7475 || !( m_scopeNamedFlatNets || m_scopeGeneratedFlatNets || aNestedHierarchy )
7476 || m_currentInterfaceNetAliases.count( key )
7477 || m_occurrenceNetNameScopeCounts[key] == 1 );
7480 else if( !ambiguousNetIds.count(
pin.wordB ) && pageName != aPage.netmap.end() )
7481 name = pageName->second;
7484 if(
name.empty() && connectorNamesByPosition[{ pin.x, pin.y }].size() == 1 )
7486 name = *connectorNamesByPosition.at( {
pin.x,
pin.y } ).begin();
7487 globalName = globalConnectorPositions.count( {
pin.x,
pin.y } );
7490 bool stackedPeer = std::any_of( instance.
pins.begin(), instance.
pins.end(),
7493 return &aPeer != &pin && aPeer.x == pin.x && aPeer.y == pin.y;
7495 bool sameNetPeer = std::any_of( instance.
pins.begin(), instance.
pins.end(),
7498 return &aPeer != &pin && aPeer.x == pin.x && aPeer.y == pin.y
7499 && ( ( pin.wordA && pin.wordA == aPeer.wordA )
7500 || ( pin.wordB && pin.wordB == aPeer.wordB ) );
7503 if(
name.empty() && ( !stackedPeer || sameNetPeer ) && electricalPosition !=
VECTOR2I(
pin.x,
pin.y )
7504 && pinTouchesWire(
pin ) )
7511 auto sourceNet = generatedWirelessNets.find( {
pin.x,
pin.y } );
7513 if( sourceNet != generatedWirelessNets.end() )
7514 name = sourceNet->second;
7517 if(
name.empty() && !generatedWirelessNets.count( { electricalPosition.x, electricalPosition.y } )
7518 && definition &&
pin.pinIndex > 0 &&
static_cast<size_t>(
pin.pinIndex ) <= definition->
pins.size() )
7520 std::string sourceName = trimmed( definition->
pins[
pin.pinIndex - 1].name );
7522 if( occurrenceNames.count( sourceName ) )
7523 name = std::move( sourceName );
7529 std::string scopedName =
name;
7534 bool globalNet = scopedName ==
name
7535 && ( globalName ||
name.rfind(
"$$$", 0 ) == 0
7536 || ( !aHierarchical && isOffpageNetName(
name ) ) || isPowerNetName(
name ) );
7538 uint32_t sourceNetId =
pin.wordB;
7540 if( m_currentOccNetNames )
7542 for(
const auto& [
id, occurrenceName] : *m_currentOccNetNames )
7544 if( kicadOccurrenceNetName( occurrenceName ) ==
name )
7552 m_wirelessNetNames[{ aScreen, &instance, pinIndex }] = { sourceNetId,
name };
7554 if( isImplicitGeneratedName(
name )
7555 && generatedWirelessNets.count( { electricalPosition.x, electricalPosition.y } ) )
7557 m_sourceGeneratedNetNames[{ aScreen, sourceNetId }] =
name;
7561 if( globalNet && !
pin.IsNoConnect() && !stackedPeer
7563 && hasImplicitPowerPinName( instance, pinIndex, scopedName ) )
7565 m_currentImplicitPowerPins.insert( &
pin );
7572 appendNetIntent( aScreen, label, !isImplicitGeneratedName(
name ) );
7574 if( scopedName !=
name )
7578 appendNetIntent( aScreen, scopedLabel, !isImplicitGeneratedName(
name ) );