47#include <wx/filename.h>
50#include <wx/tokenzr.h>
51#include <wx/translation.h>
96constexpr double DBU_TO_MM = 0.254;
99constexpr int COMMENT_COUNT = 9;
102std::string trimmed(
const std::string& aText )
104 size_t begin = aText.find_first_not_of(
" \t\r\n\f\v" );
106 if( begin == std::string::npos )
107 return std::string();
109 size_t end = aText.find_last_not_of(
" \t\r\n\f\v" );
111 return aText.substr( begin,
end - begin + 1 );
115std::optional<std::chrono::sys_days> orcadCalendarDay( uint32_t aTimestamp )
117 if( aTimestamp == 0 )
120 using namespace std::chrono;
123 sys_days date = floor<days>( sys_seconds( seconds( aTimestamp ) ) - hours( 8 ) );
124 year_month_day ymd( date );
134static std::string orcadMonthDayYear( std::chrono::sys_days aDate,
bool aShortMonth )
136 static constexpr std::array<const char*, 12> months = {
"January",
"February",
"March",
"April",
137 "May",
"June",
"July",
"August",
138 "September",
"October",
"November",
"December" };
140 std::chrono::year_month_day ymd( aDate );
141 std::string month = months[
static_cast<unsigned>( ymd.month() ) - 1];
147 + wxString::Format( wxS(
" %02u, %d" ),
static_cast<unsigned>( ymd.day() ),
static_cast<int>( ymd.year() ) )
152std::string orcadCalendarDate( uint32_t aTimestamp )
154 using namespace std::chrono;
156 std::optional<sys_days> date = orcadCalendarDay( aTimestamp );
161 static constexpr std::array<const char*, 7> weekdays = {
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
162 "Thursday",
"Friday",
"Saturday" };
164 return std::string( weekdays[weekday( *date ).c_encoding()] ) +
", " + orcadMonthDayYear( *date,
false );
168std::string orcadShortCalendarDate( uint32_t aTimestamp )
170 std::optional<std::chrono::sys_days> date = orcadCalendarDay( aTimestamp );
171 return date ? orcadMonthDayYear( *date,
true ) :
std::string();
175std::string kicadBusName( std::string aName )
179 while( ( open = aName.find(
'[', open ) ) != std::string::npos )
181 size_t close = aName.find(
']', open + 1 );
183 if( close == std::string::npos )
186 size_t colon = aName.find(
':', open + 1 );
190 aName.replace( colon, 1,
".." );
201std::string kicadElectricalNetName( std::string aName )
203 aName = kicadBusName( std::move( aName ) );
205 if( !aName.empty() && aName.front() ==
'/' )
207 size_t lastSlash = aName.find_last_of(
'/' );
210 aName.replace( 0, 1,
"{slash}" );
212 aName.erase( 0, lastSlash + 1 );
219std::string kicadOccurrenceNetName( std::string aName )
221 if( !aName.empty() && aName.front() ==
'/' )
222 aName.erase( 0, aName.find_last_of(
'/' ) + 1 );
224 return kicadElectricalNetName( std::move( aName ) );
228static std::string generatedPinNetName( uint32_t aInstanceId,
size_t aPinIndex )
230 std::string instance = std::to_string( aInstanceId );
232 if( instance.size() < 5 )
233 instance.insert( 0, 5 - instance.size(),
'0' );
235 return "N" + instance + std::to_string( aPinIndex );
240bool isImplicitGeneratedName(
const std::string& aName )
242 return aName.size() > 1 && aName[0] ==
'N'
243 && std::all_of( aName.begin() + 1, aName.end(),
244 [](
unsigned char c )
246 return std::isdigit( c );
251std::optional<uint32_t> occurrenceNetObjectId(
const std::string& aName )
253 size_t begin = std::string::npos;
254 size_t separator = aName.find_last_of(
'_' );
256 if( separator != std::string::npos && separator + 1 < aName.size()
257 && std::isdigit(
static_cast<unsigned char>( aName[separator + 1] ) ) )
258 begin = separator + 1;
259 else if( aName.size() > 1 && aName[0] ==
'N' )
262 if( begin == std::string::npos )
267 while(
end < aName.size() && std::isdigit(
static_cast<unsigned char>( aName[
end] ) ) )
270 if(
end == begin || (
end != aName.size() && aName[
end] !=
'_' ) )
273 uint64_t objectId = 0;
274 auto [
next, error] = std::from_chars( aName.data() + begin, aName.data() +
end, objectId );
276 if( error != std::errc() ||
next != aName.data() +
end || objectId == 0
277 || objectId > std::numeric_limits<uint32_t>::max() )
282 return static_cast<uint32_t
>( objectId );
300 bool aUseSymbolLineWidths =
false )
312 if( aCanFill && aPrimitive.
fillStyle == 0 )
321VECTOR2I dbuPointToIu(
double aX,
double aY )
333 point = aMap( point );
339 aPrim.
end = aMap( *aPrim.
end );
358 const std::function<
void(
const ORCAD_PRIMITIVE&,
int,
int )>& aVisit )
360 std::function<void(
const std::vector<ORCAD_PRIMITIVE>&,
int,
int )> visit =
361 [&](
const std::vector<ORCAD_PRIMITIVE>& aList,
int aOffsetX,
int aOffsetY )
366 visit( primitive.children, aOffsetX + primitive.x1, aOffsetY + primitive.y1 );
368 aVisit( primitive, aOffsetX, aOffsetY );
372 visit( aPrimitives, 0, 0 );
378 if( aWidth <= 0 || aHeight <= 0 || aBoxWidth <= 0 || aBoxHeight <= 0 )
381 int64_t imageAspect =
static_cast<int64_t
>( aWidth ) * aBoxHeight;
382 int64_t boxAspect =
static_cast<int64_t
>( aBoxWidth ) * aHeight;
384 if( imageAspect == boxAspect )
387 auto roundedRatio = []( int64_t aNumerator, int64_t aDenominator )
389 int64_t value = ( aNumerator + aDenominator / 2 ) / aDenominator;
390 return static_cast<int>( std::clamp<int64_t>( value, 1, std::numeric_limits<int>::max() ) );
393 if( imageAspect < boxAspect )
394 return VECTOR2I( roundedRatio(
static_cast<int64_t
>( aHeight ) * aBoxWidth, aBoxHeight ), aHeight );
396 return VECTOR2I( aWidth, roundedRatio(
static_cast<int64_t
>( aWidth ) * aBoxHeight, aBoxWidth ) );
402 static constexpr uint8_t palette[][3] = {
403 { 0, 0, 0 }, { 255, 255, 128 }, { 128, 255, 128 }, { 0, 255, 128 }, { 128, 255, 255 }, { 0, 128, 255 },
404 { 255, 128, 192 }, { 255, 128, 255 }, { 255, 0, 0 }, { 255, 255, 0 }, { 128, 255, 0 }, { 0, 255, 64 },
405 { 0, 255, 255 }, { 0, 128, 192 }, { 128, 128, 192 }, { 255, 0, 255 }, { 128, 64, 64 }, { 255, 128, 64 },
406 { 0, 255, 0 }, { 0, 128, 128 }, { 0, 64, 128 }, { 128, 128, 255 }, { 128, 0, 64 }, { 255, 0, 128 },
407 { 128, 0, 0 }, { 255, 128, 0 }, { 0, 128, 0 }, { 0, 128, 64 }, { 0, 0, 255 }, { 0, 0, 160 },
408 { 128, 0, 128 }, { 128, 0, 255 }, { 64, 0, 0 }, { 128, 64, 0 }, { 0, 64, 0 }, { 0, 64, 64 },
409 { 0, 0, 128 }, { 0, 0, 64 }, { 64, 0, 64 }, { 64, 0, 128 }, { 0, 0, 0 }, { 128, 128, 0 },
410 { 128, 128, 64 }, { 128, 128, 128 }, { 64, 128, 128 }, { 192, 192, 192 }, { 64, 0, 64 }, { 255, 255, 255 }
413 if( aColorIndex < 1 || aColorIndex >=
static_cast<int>( std::size( palette ) ) )
416 return KIGFX::COLOR4D( palette[aColorIndex][0] / 255.0, palette[aColorIndex][1] / 255.0,
417 palette[aColorIndex][2] / 255.0, 1.0 );
439 return KIID::FromName(
"orcad-import:" +
m_design.sourceId +
":" + aRole +
":" + std::to_string( aOrdinal ) );
445 std::map<std::string, size_t> pinOrdinals;
447 for(
const std::unique_ptr<SCH_PIN>& ownedPin : aSymbol->
GetRawPins() )
451 std::string pinRole = std::string(
pin->GetNumber().ToUTF8() ) +
":" + std::string(
pin->GetName().ToUTF8() )
452 +
":" + std::to_string( position.
x ) +
":" + std::to_string( position.
y );
453 size_t pinOrdinal = pinOrdinals[pinRole]++;
458 [](
const std::unique_ptr<SCH_PIN>& a,
const std::unique_ptr<SCH_PIN>& b )
460 return a->m_Uuid < b->m_Uuid;
482 sheets.insert( sheets.end(), detached.begin(), detached.end() );
486 std::set<SCH_SCREEN*> visited;
487 size_t screenOrdinal = 0;
496 std::map<std::string, size_t> ordinals;
500 std::string uuid = item->m_Uuid.AsStdString();
508 [](
const std::unique_ptr<SCH_PIN>& aPin )
510 return aPin->m_Uuid.AsStdString()[14] !=
'5';
521 VECTOR2I position = item->GetPosition();
522 std::string role = std::to_string(
static_cast<int>( item->Type() ) ) +
":" + std::to_string( position.
x )
523 +
":" + std::to_string( position.
y );
524 size_t ordinal = ordinals[role]++;
525 const_cast<KIID&
>( item->m_Uuid ) =
527 +
":" + role +
":" + std::to_string( ordinal ) );
546 std::map<KICAD_T, size_t> ordinals;
553 size_t ordinal = ordinals[item->Type()]++;
554 std::string role =
"page:" + std::to_string( aPageOrdinal )
555 +
":item:" + std::to_string(
static_cast<int>( item->Type() ) );
580 auto addName = [&](
const std::string& aName )
582 std::string
name = trimmed( aName );
594 std::string displayName =
name != global.
props.end() ? trimmed(
name->second ) : std::string();
595 std::string logicalName = trimmed( global.
logicalName );
596 std::string powerName = !displayName.empty() ? displayName : logicalName;
597 addName( powerName );
601 if( !powerName.empty() )
625 std::string
name = trimmed( aName );
631 return kicadElectricalNetName( alias->second );
634 return kicadElectricalNetName( canonical !=
m_globalNetNames.end() ? canonical->second :
name );
649 auto effective =
m_scope.interfaceNetAliases.find( key );
650 return effective !=
m_scope.interfaceNetAliases.end() ? effective->second :
name;
658 m_scope.electricalKeyCounts.clear();
662 for(
const auto& [occurrenceId,
name] :
m_scope.occ->netNames )
670 std::string
name = kicadOccurrenceNetName( aName );
672 auto occurrenceAlias =
m_scope.occurrenceNetAliases.find( key );
674 if( occurrenceAlias !=
m_scope.occurrenceNetAliases.end() )
675 return occurrenceAlias->second;
677 auto interfaceAlias =
m_scope.interfaceNetAliases.find( key );
678 return interfaceAlias !=
m_scope.interfaceNetAliases.end() ? interfaceAlias->second :
name;
683 const std::string& aName )
const
688 if( peers !=
m_scope.electricalKeyCounts.end() && peers->second > 1 )
690 std::string suffix = std::to_string( aOccurrenceId );
692 if( suffix.size() < 6 )
693 suffix.insert( 0, 6 - suffix.size(),
'0' );
695 electricalName +=
"_" + suffix;
698 return electricalName;
704 std::string key =
OrcadLower( trimmed( aName ) );
711 std::string key =
OrcadLower( trimmed( aName ) );
719 size_t digitStart = 0;
720 wxString upper = aName.Upper();
722 for(
const wxString& prefix : { wxString(
"PAGE" ), wxString(
"SCH" ), wxString(
"PAG" ) } )
724 if( upper.StartsWith( prefix )
725 && ( aName.length() == prefix.length() || wxIsdigit( aName[prefix.length()] )
726 || wxIsspace( aName[prefix.length()] ) || aName[prefix.length()] ==
'_' ) )
728 digitStart = prefix.length();
730 while( digitStart < aName.length() && ( wxIsspace( aName[digitStart] ) || aName[digitStart] ==
'_' ) )
739 size_t digitEnd = digitStart;
741 while( digitEnd < aName.length() && wxIsdigit( aName[digitEnd] ) )
746 if( digitEnd == digitStart || !aName.Mid( digitStart, digitEnd - digitStart ).ToLong( &order ) )
751 size_t separator = digitEnd;
753 while( separator < aName.length() && wxIsspace( aName[separator] ) )
756 bool separatedBySpace = separator > digitEnd;
758 if( !separatedBySpace && separator < aName.length() && aName[separator] !=
'-' && aName[separator] !=
'.'
759 && aName[separator] !=
':' && aName[separator] !=
'_' )
762 if( separator < aName.length() && aName[separator] ==
'-' )
764 wxString rest = aName.Mid( separator + 1 );
769 return static_cast<int>( order );
775 size_t range = aName.find(
'[' );
777 if( range == std::string::npos || aName.find(
"..", range ) == std::string::npos )
780 return aName.substr( 0, range ) +
"_ORCAD_" + std::to_string( aOccurrenceId ) + aName.substr( range );
791 static std::optional<BUS_RANGE>
Parse(
const std::string& aName );
797 std::optional<int64_t>
Ordinal( int64_t aIndex )
const
799 int64_t ordinal = ( aIndex -
first ) *
Step();
800 return ordinal >= 0 && ordinal < Count() ? std::optional<int64_t>( ordinal ) : std::nullopt;
803 int64_t
At( int64_t aOrdinal )
const {
return first + aOrdinal *
Step(); }
809 size_t open = aName.find(
'[' );
810 size_t dots = open == std::string::npos ? std::string::npos : aName.find(
"..", open + 1 );
811 size_t separatorSize = 2;
813 if( dots == std::string::npos && open != std::string::npos )
815 dots = aName.find(
':', open + 1 );
819 size_t close = dots == std::string::npos ? std::string::npos : aName.find(
']', dots + separatorSize );
821 if( open == std::string::npos || dots == std::string::npos || close != aName.size() - 1 )
824 auto parseIndex = []( std::string_view aText,
int& aValue )
826 const char* begin = aText.data();
827 const char*
end = begin + aText.size();
828 auto [
next, error] = std::from_chars( begin,
end, aValue );
829 return error == std::errc() &&
next ==
end;
834 if( !parseIndex( std::string_view( aName ).substr( open + 1, dots - open - 1 ), range.first )
835 || !parseIndex( std::string_view( aName ).substr( dots + separatorSize, close - dots - separatorSize ),
841 range.
prefix = aName.substr( 0, open );
847static std::vector<std::pair<BUS_RANGE, BUS_RANGE>>
850 std::vector<std::pair<BUS_RANGE, BUS_RANGE>> ranges;
852 for(
const auto& [sourceBus, scopedBus] : aBusNames )
857 if(
source && scoped &&
source->Count() == scoped->Count() )
858 ranges.emplace_back( std::move( *
source ), std::move( *scoped ) );
865static std::string
scopedHierBusMember(
const std::string& aName,
const std::map<std::string, std::string>& aBusNames )
869 if( aName.compare( 0,
source.prefix.size(),
source.prefix ) != 0 )
873 std::string_view suffix( aName.data() +
source.prefix.size(), aName.size() -
source.prefix.size() );
874 auto [
next, error] = std::from_chars( suffix.data(), suffix.data() + suffix.size(), member );
876 if( suffix.empty() || error != std::errc() ||
next != suffix.data() + suffix.size() )
879 if( std::optional<int64_t> ordinal =
source.Ordinal( member ) )
880 return scoped.prefix + std::to_string( scoped.At( *ordinal ) );
887static std::string
scopedHierBusRange(
const std::string& aName,
const std::map<std::string, std::string>& aBusNames )
896 if( member->prefix !=
source.prefix )
899 std::optional<int64_t> firstOrdinal =
source.Ordinal( member->first );
900 std::optional<int64_t> lastOrdinal =
source.Ordinal( member->last );
902 if( firstOrdinal && lastOrdinal )
904 return scoped.prefix +
"[" + std::to_string( scoped.At( *firstOrdinal ) ) +
".."
905 + std::to_string( scoped.At( *lastOrdinal ) ) +
"]";
915 int64_t cross =
static_cast<int64_t
>( aX - aWire.
x1 ) * ( aWire.
y2 - aWire.
y1 )
916 -
static_cast<int64_t
>( aY - aWire.
y1 ) * ( aWire.
x2 - aWire.
x1 );
917 return cross == 0 && aX >= std::min( aWire.
x1, aWire.
x2 ) && aX <= std::max( aWire.
x1, aWire.
x2 )
918 && aY >= std::min( aWire.
y1, aWire.
y2 ) && aY <= std::max( aWire.
y1, aWire.
y2 );
924 int64_t firstDx =
static_cast<int64_t
>( aFirst.
x2 ) - aFirst.
x1;
925 int64_t firstDy =
static_cast<int64_t
>( aFirst.
y2 ) - aFirst.
y1;
926 int64_t secondDx =
static_cast<int64_t
>( aSecond.
x2 ) - aSecond.
x1;
927 int64_t secondDy =
static_cast<int64_t
>( aSecond.
y2 ) - aSecond.
y1;
928 int64_t deltaX =
static_cast<int64_t
>( aSecond.
x1 ) - aFirst.
x1;
929 int64_t deltaY =
static_cast<int64_t
>( aSecond.
y1 ) - aFirst.
y1;
930 int64_t denominator = firstDx * secondDy - firstDy * secondDx;
932 if( denominator == 0 )
935 int64_t firstNumerator = deltaX * secondDy - deltaY * secondDx;
936 int64_t secondNumerator = deltaX * firstDy - deltaY * firstDx;
938 if( denominator < 0 )
940 denominator = -denominator;
941 firstNumerator = -firstNumerator;
942 secondNumerator = -secondNumerator;
945 if( firstNumerator < 0 || firstNumerator > denominator || secondNumerator < 0
946 || secondNumerator > denominator )
951 int64_t xNumerator =
static_cast<int64_t
>( aFirst.
x1 ) * denominator + firstDx * firstNumerator;
952 int64_t yNumerator =
static_cast<int64_t
>( aFirst.
y1 ) * denominator + firstDy * firstNumerator;
954 if( xNumerator % denominator != 0 || yNumerator % denominator != 0 )
957 return VECTOR2I(
static_cast<int>( xNumerator / denominator ),
static_cast<int>( yNumerator / denominator ) );
971 std::vector<std::string> runs;
974 while( start < aPrefix.size() )
976 while( start < aPrefix.size() && !std::isalnum(
static_cast<unsigned char>( aPrefix[start] ) ) )
981 while(
end < aPrefix.size() && std::isalnum(
static_cast<unsigned char>( aPrefix[
end] ) ) )
985 runs.push_back( aPrefix.substr( start,
end - start ) );
996 std::set<std::string>
result;
1000 if( run.size() > 1 )
1001 result.insert( std::move( run ) );
1011 return !runs.empty() && runs.front().size() > 1 ? runs.front() : std::string();
1017 std::set<std::string> names;
1018 auto net = aPage.
netmap.find( aNetId );
1020 if( net != aPage.
netmap.end() )
1021 names.insert( net->second );
1023 auto aliases = aPage.
netAliases.find( aNetId );
1026 names.insert( aliases->second.begin(), aliases->second.end() );
1034 std::set<uint32_t> netIds;
1036 for(
const auto& [netId, primaryName] : aPage.
netmap )
1038 std::set<std::string> names =
pageNetNames( aPage, netId );
1040 if( std::any_of( names.begin(), names.end(),
1041 [&](
const std::string& aNetName )
1043 return OrcadIEquals( aNetName, aName );
1046 netIds.insert( netId );
1054std::set<const std::string*>
1056 const std::map<uint32_t, std::string>& aScopeNets,
bool aSkipGenerated,
1057 std::set<std::string>* aSourceKeys )
const
1060 std::set<uint32_t> wireObjectIds;
1067 wireObjectIds.insert( wire.
dbId );
1073 std::set<const std::string*> targets;
1075 for(
const auto& [occurrenceId, occurrenceName] : aScopeNets )
1079 if( std::optional<uint32_t> objectId = occurrenceNetObjectId( occurrenceName ) )
1080 matches = matches || wireObjectIds.count( *objectId );
1082 if( matches && !( aSkipGenerated && isImplicitGeneratedName( occurrenceName ) ) )
1083 targets.insert( &occurrenceName );
1087 *aSourceKeys = std::move( sourceKeys );
1094 const std::string& aFallback )
1101 std::vector<size_t> pending;
1102 std::set<size_t> seen;
1104 for(
size_t i = 0; i < aPage.
wires.size(); ++i )
1108 pending.push_back( i );
1117 for(
size_t i = 0; i < aPage.
wires.size(); ++i )
1122 pending.push_back( i );
1127 std::set<std::string> names;
1129 for(
size_t wireIndex : pending )
1134 names.insert( alias.
name );
1141 if( std::any_of( pending.begin(), pending.end(),
1142 [&](
size_t aWireIndex )
1144 return rawPointOnSegment( port.x, port.y, aPage.wires[aWireIndex] );
1147 names.insert( port.
name );
1154 if( std::any_of( pending.begin(), pending.end(),
1155 [&](
size_t aWireIndex )
1157 return rawPointOnSegment( connector.x, connector.y, aPage.wires[aWireIndex] );
1160 names.insert( connector.
name );
1165 if( pending.empty() )
1169 names.insert( port.
name );
1175 names.insert( connector.
name );
1180 if( names.count( aFallback ) )
1183 std::set<uint32_t> connectedNetIds;
1185 for(
size_t wireIndex : pending )
1186 connectedNetIds.insert( aPage.
wires[wireIndex].id );
1188 std::set<std::string> sourceMembers;
1190 for( int64_t ordinal = 0; ordinal <
source->Count(); ++ordinal )
1191 sourceMembers.insert(
source->prefix + std::to_string(
source->At( ordinal ) ) );
1195 if( !connectedNetIds.count(
group.id ) ||
static_cast<int64_t
>(
group.members.size() ) !=
source->Count() )
1198 std::set<std::string> memberNames;
1200 for( uint32_t memberId :
group.members )
1203 if( std::includes( memberNames.begin(), memberNames.end(), sourceMembers.begin(), sourceMembers.end() ) )
1209 for(
const std::string&
name : names )
1213 if( target && target->Count() ==
source->Count() )
1219 for(
const std::string& candidate :
candidates )
1223 if( !candidateRange )
1226 const std::string& candidatePrefix = candidateRange->prefix;
1227 std::set<std::string> candidateTokens =
busPrefixTokens( candidatePrefix );
1228 std::vector<std::string> sharedTokens;
1229 std::set_intersection( sourceTokens.begin(), sourceTokens.end(), candidateTokens.begin(), candidateTokens.end(),
1230 std::back_inserter( sharedTokens ) );
1234 bool leadingNamespaceOnly = sharedTokens.size() == 1 && sourceTokens.size() > 1 && candidateTokens.size() > 1
1238 if( !sharedTokens.empty() && !leadingNamespaceOnly )
1266 uint32_t endpointNet = 0;
1267 uint32_t throughNet = 0;
1274 bool endpoint = ( aPin.
x == wire.
x1 && aPin.
y == wire.
y1 ) || ( aPin.
x == wire.
x2 && aPin.
y == wire.
y2 );
1275 uint32_t& candidate = endpoint ? endpointNet : throughNet;
1277 if( candidate == 0 || wire.
id < candidate )
1278 candidate = wire.
id;
1281 return endpointNet ? endpointNet : throughNet;
1287 if( !aBlock.
name.empty() )
1290 auto name = aBlock.
props.find(
"Name" );
1292 return name != aBlock.
props.end() ?
name->second : std::string();
1298 std::string suffix = aParentSuffix;
1301 if( !blockSuffix.empty() )
1303 if( !suffix.empty() )
1306 suffix += blockSuffix;
1315 auto block = std::find_if( aPage.
blocks.begin(), aPage.
blocks.end(),
1318 return aBlock.dbId == aDbId;
1321 return block != aPage.
blocks.end() ? &*block :
nullptr;
1325static std::pair<const ORCAD_DRAWN_INSTANCE*, const ORCAD_RAW_PAGE*>
1331 return { block, &page };
1341 std::vector<const ORCAD_OCC_BLOCK*> occurrences;
1344 occurrences.push_back( &occurrence );
1346 std::stable_sort( occurrences.begin(), occurrences.end(),
1349 wxString aName = FromOrcadString( a->childFolder );
1350 wxString bName = FromOrcadString( b->childFolder );
1351 int aOrder = OrcadPageOrder( aName );
1352 int bOrder = OrcadPageOrder( bName );
1353 int aKey = aOrder >= 0 ? aOrder : std::numeric_limits<int>::max();
1354 int bKey = bOrder >= 0 ? bOrder : std::numeric_limits<int>::max();
1359 return aName.CmpNoCase( bName ) < 0;
1367 bool aUnreferenced )
const
1372 for(
const auto& [folder, pages] :
m_design.childFolderPages )
1378 if( !aUnreferenced )
1381 for(
const auto& [folder, pages] :
m_design.unreferencedFolderPages )
1391 wxString
name = aBase;
1394 name = wxString::Format( wxS(
"%s (%d)" ), aBase, suffix );
1406 if( candidate.Last() == aSheet )
1414 path.push_back( aSheet );
1416 path.SetPageNumber( wxString::Format( wxS(
"%zu" ), aPageNumber ) );
1423 std::array<std::pair<int, SHEET_SIDE>, 4> sides = {
1430 return std::min_element( sides.begin(), sides.end(),
1431 [](
const auto& a,
const auto& b )
1433 return a.first < b.first;
1443 bool leading =
false;
1444 std::set<std::string> embedded;
1447 std::map<std::string, SLASH_NAMES> slashNames;
1448 auto collectSlashName = [&](
const std::string& aName )
1450 if( aName.empty() || aName.find(
'/' ) == std::string::npos )
1453 std::string key = aName;
1454 std::erase( key,
'/' );
1457 if( aName.front() ==
'/' )
1458 slashNames[key].leading =
true;
1460 slashNames[key].embedded.insert( kicadOccurrenceNetName( aName ) );
1464 for(
const auto& [netId,
name] : aPage.netmap )
1465 collectSlashName(
name );
1467 for(
const auto& [netId, aliases] : aPage.netAliases )
1469 for(
const std::string& alias : aliases )
1470 collectSlashName( alias );
1476 for(
const auto& [key, names] : slashNames )
1478 if( names.leading && names.embedded.size() == 1 )
1482 std::function<void(
const ORCAD_OCC_SCOPE&,
size_t )> countOccurrenceNetNameScopes =
1485 std::set<std::string> scopeNames;
1487 for(
const auto& occurrence : aScope.
netNames )
1489 const std::string&
name = occurrence.second;
1491 scopeNames.insert( key );
1499 for(
const std::string&
name : scopeNames )
1505 countOccurrenceNetNameScopes( block.
scope, aDepth + 1 );
1508 countOccurrenceNetNameScopes(
m_design.occurrenceRoot, 0 );
1510 std::set<std::string> rootChildFolders;
1516 rootChildFolders.insert( key );
1517 auto pages =
m_design.childFolderPages.find( key );
1519 if( pages ==
m_design.childFolderPages.end()
1520 || !std::all_of( pages->second.begin(), pages->second.end(),
1523 return aPage.blocks.empty();
1539 if(
pin.noConnect ||
pin.name.empty() )
1549 auto netName = aPage.
netmap.find( wire.
id );
1574std::map<std::string, std::string>
1576 const std::string& aFlatNetSuffix )
const
1578 std::map<std::string, std::string>
result;
1582 if( !
pin.noConnect ||
pin.name.empty() || aFlatNetSuffix.empty() )
1586 std::string localKey =
OrcadLower( localName );
1591 result.emplace( std::move( localKey ), localName +
"_" + aFlatNetSuffix );
1600 const wxString& aName,
const std::string& aFilePageName,
1615 auto implementation = aBlock.
props.find(
"Implementation" );
1617 if( implementation != aBlock.
props.end() && !implementation->second.empty()
1623 for(
size_t pinIndex = 0; pinIndex < aBlock.
pins.size(); ++pinIndex )
1628 uint32_t busNetId =
busNetAt( aParentPage, sourcePin );
1629 std::string pinName = busNetId ?
connectedBusName( aParentPage, sourcePin, sourceName )
1632 if( busNetId && pinName != sourceName )
1640 if( pinName != sourceName )
1644 const_cast<KIID&
>(
pin->m_Uuid ) =
1647 pin->SetPosition( position );
1653 parentScreen->
Append( sheet );
1658std::vector<SCH_SHEET*>
1660 bool aReuseRoot,
bool aOrdinalSheetUuids )
1662 std::vector<SCH_SHEET*> topSheets;
1667 size_t first = topSheets.size();
1669 for(
size_t i = 0; i < aNamesAndFiles.size(); ++i )
1673 if( !aReuseRoot || i > 0 )
1679 if( aOrdinalSheetUuids )
1685 const auto& [
name, fileName] = aNamesAndFiles[i];
1689 topSheets.push_back( sheet );
1693 return std::vector<SCH_SHEET*>( topSheets.begin() + first, topSheets.end() );
1698 const std::string& aSourceName,
const std::string& aElectricalName )
const
1700 if( aSourceName.empty() || aElectricalName.empty() )
1710 target.first = aElectricalName;
1717 for(
const auto& [sourceName, evidence] : aCandidates )
1719 if( evidence.targets.size() != 1 )
1722 const auto& target = evidence.targets.begin()->second;
1724 if( target.second * 2 > evidence.placements )
1746 bool hasBlocks = !
m_design.occurrenceRoot.blocks.empty();
1750 bool native =
m_design.pages.size() == 1
1770 std::set<uint32_t> matchedBlocks;
1776 if( !matchedBlocks.insert( occurrence.
targetDbId ).second
1778 || pages ==
m_design.childFolderPages.end() || pages->second.size() != 1
1792 size_t blockCount = 0;
1795 blockCount += page.blocks.size();
1797 if( blockCount != aScope.
blocks.size() )
1800 std::set<uint32_t> matchedBlocks;
1808 matches += std::count_if( page.blocks.begin(), page.blocks.end(),
1811 return aBlock.dbId == occurrence.targetDbId;
1817 if( matches != 1 || !matchedBlocks.insert( occurrence.
targetDbId ).second
1818 || pages ==
m_design.childFolderPages.end() || pages->second.empty()
1839 if( targets.size() == 1 )
1841 std::string sourceName =
OrcadLower( kicadOccurrenceNetName(
pin.name ) );
1842 std::string targetName = kicadOccurrenceNetName( **targets.begin() );
1845 childAliases[std::move( sourceName )] = std::move( targetName );
1869 if( parentPage && drawn && childPages !=
m_design.childFolderPages.end() )
1880 std::function<size_t(
const std::vector<ORCAD_RAW_PAGE>&,
const ORCAD_OCC_SCOPE& )> countSourcePages =
1881 [&](
const std::vector<ORCAD_RAW_PAGE>& aPages,
const ORCAD_OCC_SCOPE& aScope )
1883 size_t count = aPages.size();
1888 pages !=
m_design.childFolderPages.end() )
1890 count += countSourcePages( pages->second, occurrence.
scope );
1911 std::map<std::string, POWER_ALIAS_EVIDENCE> powerAliasCandidates;
1924 const SCH_SHEET_PATH& aFolderPath,
const std::string& aOccurrenceSuffix,
1925 bool aRepeatedFolder,
1926 const std::map<std::string, std::string>& aUnconnectedInterfaceNetNames,
1927 std::map<std::string, std::string> aInterfaceNetAliases )
1929 struct PAGE_PLACEMENT
1945 auto folderSheetName = [&](
const std::string& aName )
1951 std::vector<PAGE_PLACEMENT> placements;
1952 bool leafFolder = std::all_of( aPages.begin(), aPages.end(),
1955 return aPage.blocks.empty();
1970 bool aContainerPage,
bool aSharedFolderPage )
1973 numberSourcePage( aPage );
1975 convertPage( aPage, aSheet->GetScreen(), aPath, aContainerPage, aSharedFolderPage );
1976 placements.push_back( { &aPage, aSheet, aPath } );
1979 if( aPages.size() == 1 )
1982 convertFolderPage( aPages.front(), aFolderSheet, aFolderPath, !root,
1987 std::vector<std::pair<wxString, wxString>> names;
1989 for(
size_t i = 0; i < aPages.size(); ++i )
1990 names.emplace_back( folderSheetName( aPages[i].
name ),
1994 aWalk.
pageIndex =
static_cast<int>( aPages.size() );
1996 for(
size_t i = 0; i < aPages.size(); ++i )
1997 convertFolderPage( aPages[i], topSheets[i],
topLevelPath( topSheets[i], i + 1 ),
false,
true );
2003 std::vector<std::string> names;
2004 std::set<std::string> seen;
2006 auto collect = [&](
const std::vector<ORCAD_GRAPHIC_INST>& aConnectors )
2017 if( !
name.empty() && seen.insert( key ).second )
2018 names.push_back( std::move(
name ) );
2022 collect( aPage.
ports );
2027 auto addContainerLabel =
2028 [&](
SCH_SCREEN* aScreen,
const wxString& aName,
const VECTOR2I& aPosition,
bool aHierarchical )
2039 size_t outerOrdinal = 0;
2045 schIUScale.mmToIU( 20 + 5 *
static_cast<int>( outerOrdinal++ ) ) );
2046 addContainerLabel( container,
pin->GetText(), position,
true );
2049 for(
size_t i = 0; i < aPages.size(); ++i )
2052 int column =
static_cast<int>( i % 3 );
2053 int row =
static_cast<int>( i / 3 );
2054 std::vector<std::string> names = interfaceNames( page );
2058 for( std::string&
name : names )
2060 auto renamed = folderBusNames->second.find(
name );
2062 if( renamed != folderBusNames->second.end() )
2063 name = renamed->second;
2067 int heightMm = std::max( 25, 10 + 5 *
static_cast<int>( names.size() ) );
2084 for(
size_t pinIndex = 0; pinIndex < names.size(); ++pinIndex )
2087 position.
y +
schIUScale.mmToIU( 5 + 5 *
static_cast<int>( pinIndex ) ) );
2090 const_cast<KIID&
>(
pin->m_Uuid ) =
2095 addContainerLabel( container,
name, pinPosition,
false );
2098 container->
Append( pageSheet );
2101 pagePath.
SetPageNumber( wxString::Format( wxS(
"%d" ), currentPage ) );
2102 convertFolderPage( page, pageSheet, pagePath,
true,
true );
2109 PAGE_PLACEMENT* parent =
nullptr;
2112 for( PAGE_PLACEMENT& placement : placements )
2118 parent = &placement;
2123 if( !parent || !drawn )
2127 std::vector<ORCAD_RAW_PAGE>& childPages =
m_design.childFolderPages.at( childKey );
2128 std::string filePageName =
2129 childPages.size() == 1 ? childPages.front().name : occurrence.
childFolder +
" container";
2148 std::string childSuffix;
2153 std::map<std::string, std::string> interfaceAliases;
2159 std::set<const std::string*> targets =
2162 if( targets.size() == 1 )
2172 placeFolder( aWalk, childPages, occurrence.
scope, childSheet, childPath, childSuffix,
2187 const std::map<uint32_t, std::string>* netNames()
const {
return &scope.
occ->
netNames; }
2190 std::vector<PAGE_JOB> jobs;
2195 auto findBlock = [&]( uint32_t aDbId )
2197 std::pair<const ORCAD_DRAWN_INSTANCE*, const ORCAD_RAW_PAGE*>
result;
2205 result = { block, &aPage };
2211 std::function<void(
const ORCAD_OCC_SCOPE&,
const std::string& )> expand =
2212 [&](
const ORCAD_OCC_SCOPE& aScope,
const std::string& aParentSuffix )
2218 auto it =
m_design.childFolderPages.find( key );
2222 if( it !=
m_design.childFolderPages.end() )
2224 bool leafFolder = std::all_of( it->second.begin(), it->second.end(),
2227 return aPage.blocks.empty();
2229 std::map<std::string, std::string> unconnectedNames;
2235 scope.
flatNetSuffix = leafFolder ? occurrenceSuffix : std::string();
2241 jobs.push_back( { &childPage, scope } );
2244 expand( block.
scope, occurrenceSuffix );
2248 expand(
m_design.occurrenceRoot, {} );
2250 std::map<const std::map<uint32_t, std::string>*, std::map<std::string, std::set<std::string>>>
2251 interfaceAliasCandidates;
2252 std::map<const std::map<uint32_t, std::string>*, std::map<std::string, std::set<std::string>>>
2253 connectorAliasCandidates;
2255 using NET_NAME_SCOPE =
const std::map<uint32_t, std::string>*;
2256 std::map<NET_NAME_SCOPE, std::map<std::string, std::set<std::string>>> interfaceNameGraphs;
2258 for(
const PAGE_JOB& job : jobs )
2260 for(
const auto& [netId, aliases] : job.page->netAliases )
2262 std::set<std::string> names;
2263 auto primary = job.page->netmap.find( netId );
2264 bool allPowerNames =
true;
2265 bool anyPowerName =
false;
2267 if( primary != job.page->netmap.end() && !primary->second.empty() )
2270 names.insert(
name );
2272 anyPowerName = allPowerNames;
2275 for(
const std::string& alias : aliases )
2277 if( !alias.empty() )
2285 if( anyPowerName && !allPowerNames )
2288 for(
const std::string&
name : names )
2290 auto& neighbors = interfaceNameGraphs[job.netNames()][
name];
2291 neighbors.insert( names.begin(), names.end() );
2296 for(
const PAGE_JOB& job : jobs )
2298 for(
const auto& [netId, aliases] : job.page->netAliases )
2300 std::set<std::string> distinctAliases;
2302 for(
const std::string& alias : aliases )
2304 if( !alias.empty() )
2305 distinctAliases.insert(
OrcadLower( alias ) );
2308 auto primary = job.page->netmap.find( netId );
2310 if( distinctAliases.size() < 2 || primary == job.page->netmap.end() || primary->second.empty() )
2313 std::string effectiveName;
2314 int64_t bestConnectorAliasDistance = std::numeric_limits<int64_t>::max();
2315 bool connectorAlias =
false;
2316 auto firstAlias = std::find_if( aliases.begin(), aliases.end(),
2317 [](
const std::string& aName )
2319 return !aName.empty();
2322 for(
const auto& [occurrenceId, occurrenceName] : *job.netNames() )
2328 if( effectiveName.empty() )
2333 || std::toupper(
static_cast<unsigned char>( instance.
reference.front() ) ) !=
'J' )
2340 for(
const ORCAD_WIRE& wire : job.page->wires )
2342 if( wire.
id != netId
2349 size_t localAliasCount = std::count_if(
2353 if( aAlias.name.empty() || isOffpageNetName( aAlias.name ) )
2360 return std::none_of( aliases.begin(), aliases.end(),
2361 [&](
const std::string& aName )
2363 return isOffpageNetName( aName )
2364 && OrcadLower( aName ).find( aliasName )
2365 != std::string::npos;
2369 if( localAliasCount < 2 )
2374 if( alias.name.empty() ||
isOffpageNetName( alias.name ) || firstAlias == aliases.end()
2380 int64_t dx = alias.x -
pin.x;
2381 int64_t dy = alias.y -
pin.y;
2382 int64_t
distance = dx * dx + dy * dy;
2384 if(
distance < bestConnectorAliasDistance )
2386 bestConnectorAliasDistance =
distance;
2388 connectorAlias =
true;
2396 if( !effectiveName.empty() && !connectorAlias )
2398 connectorAlias = std::any_of(
2399 job.page->instances.begin(), job.page->instances.end(),
2402 if( aInstance.reference.empty()
2403 || std::toupper( static_cast<unsigned char>( aInstance.reference.front() ) ) !=
'J' )
2409 aInstance.
pins.begin(), aInstance.
pins.end(),
2413 job.page->wires.begin(), job.page->wires.end(),
2414 [&]( const ORCAD_WIRE& aWire )
2416 if( aWire.id != netId
2417 || ( aPin.wordA != aWire.dbId && aPin.wordB != aWire.dbId
2418 && !rawPointOnSegment( aPin.x, aPin.y, aWire ) ) )
2423 return std::any_of( aWire.aliases.begin(), aWire.aliases.end(),
2424 [&]( const ORCAD_ALIAS& aAlias )
2426 return canonicalGlobalNetKey( aAlias.name )
2427 == OrcadLower( effectiveName );
2434 if( effectiveName.empty() )
2437 for(
const std::string& alias : aliases )
2439 if( isOffpageNetName( alias ) )
2441 std::string sourceName = canonicalGlobalNetKey( alias );
2442 interfaceAliasCandidates[job.netNames()][sourceName].insert( effectiveName );
2444 if( connectorAlias )
2445 connectorAliasCandidates[job.netNames()][sourceName].insert( effectiveName );
2451 std::map<const std::map<uint32_t, std::string>*, std::map<std::string, std::string>> interfaceAliasesByScope;
2452 std::map<const std::map<uint32_t, std::string>*, std::set<std::string>> connectorAliasesByScope;
2454 for(
const auto& [scope, aliases] : interfaceAliasCandidates )
2456 for(
const auto& [sourceName, effectiveNames] : aliases )
2458 auto selected = std::max_element( effectiveNames.begin(), effectiveNames.end(),
2459 [](
const std::string& aLeft,
const std::string& aRight )
2461 return aLeft.size() < aRight.size();
2464 if( selected == effectiveNames.end() )
2467 bool sourceIsOccurrenceName =
2468 std::any_of( scope->begin(), scope->end(),
2469 [&](
const auto& aOccurrenceNet )
2471 return canonicalGlobalNetKey( aOccurrenceNet.second ) == sourceName;
2473 bool selectedIsOccurrenceName =
2474 std::any_of( scope->begin(), scope->end(),
2475 [&](
const auto& aOccurrenceNet )
2477 return canonicalGlobalNetKey( aOccurrenceNet.second ) == OrcadLower( *selected );
2480 if( sourceIsOccurrenceName && selectedIsOccurrenceName &&
OrcadLower( *selected ) != sourceName )
2483 bool uniqueLength = std::none_of( effectiveNames.begin(), effectiveNames.end(),
2484 [&](
const std::string& aName )
2486 return aName != *selected && aName.size() == selected->size();
2491 interfaceAliasesByScope[scope][sourceName] = *selected;
2493 auto connectorScope = connectorAliasCandidates.find( scope );
2495 if( connectorScope != connectorAliasCandidates.end() )
2497 auto connectorNames = connectorScope->second.find( sourceName );
2499 if( connectorNames != connectorScope->second.end() && connectorNames->second.count( *selected ) )
2500 connectorAliasesByScope[scope].insert( sourceName );
2506 for(
const auto& [scope, graph] : interfaceNameGraphs )
2508 std::set<std::string> unseen;
2510 for(
const auto& [
name, neighbors] : graph )
2511 unseen.insert(
name );
2513 while( !unseen.empty() )
2515 std::set<std::string> component;
2516 std::vector<std::string> pending = { *unseen.begin() };
2517 unseen.erase( pending.front() );
2519 while( !pending.empty() )
2521 std::string
name = std::move( pending.back() );
2523 component.insert(
name );
2525 for(
const std::string& neighbor : graph.at(
name ) )
2527 if( unseen.erase( neighbor ) )
2528 pending.push_back( neighbor );
2532 std::set<std::string> authoritativeNames;
2534 for(
const auto& [occurrenceId, occurrenceName] : *scope )
2536 std::string key = canonicalGlobalNetKey( occurrenceName );
2538 if( component.count( key ) )
2539 authoritativeNames.insert( canonicalGlobalNetName( occurrenceName ) );
2542 if( authoritativeNames.size() != 1 )
2545 for(
const std::string& sourceName : component )
2547 if( connectorAliasesByScope[scope].count( sourceName ) )
2550 interfaceAliasesByScope[scope][sourceName] = *authoritativeNames.begin();
2555 std::function<void(
const ORCAD_OCC_SCOPE& )> propagateInterfaceAliases =
2558 const auto& parentAliases = interfaceAliasesByScope[&aParentScope.netNames];
2562 auto& childAliases = interfaceAliasesByScope[&block.
scope.
netNames];
2563 auto [drawnBlock, parentPage] = findBlock( block.
targetDbId );
2564 if( drawnBlock && parentPage )
2568 if(
pin.name.empty() )
2571 std::set<std::string> sourceNames;
2572 std::set<const std::string*> targets =
2573 pinOccurrenceTargets( *parentPage,
pin, aParentScope.netNames,
false, &sourceNames );
2574 std::string targetName;
2576 if( targets.size() == 1 )
2577 targetName = canonicalGlobalNetName( **targets.begin() );
2580 for(
const std::string& sourceName : sourceNames )
2582 auto inherited = parentAliases.find( sourceName );
2584 if( inherited != parentAliases.end() )
2585 targetName = inherited->second;
2589 if( !targetName.empty() )
2590 childAliases[canonicalGlobalNetKey(
pin.name )] = std::move( targetName );
2594 for(
auto& [sourceName, targetName] : childAliases )
2596 auto inherited = parentAliases.find( canonicalGlobalNetKey( targetName ) );
2598 if( inherited != parentAliases.end() )
2599 targetName = inherited->second;
2602 for(
const auto& [occurrenceId, occurrenceName] : block.
scope.
netNames )
2604 std::string sourceName = canonicalGlobalNetKey( occurrenceName );
2605 auto inherited = parentAliases.find( sourceName );
2607 if( inherited != parentAliases.end() )
2608 childAliases[sourceName] = inherited->second;
2611 propagateInterfaceAliases( block.
scope );
2614 propagateInterfaceAliases( m_design.occurrenceRoot );
2616 auto jobScope = [&](
const PAGE_JOB& aJob )
2618 PAGE_SCOPE scope = aJob.scope;
2619 scope.interfaceNetAliases = interfaceAliasesByScope[aJob.netNames()];
2620 scope.connectorInterfaceNetAliases = connectorAliasesByScope[aJob.netNames()];
2624 std::map<std::string, POWER_ALIAS_EVIDENCE> powerAliasCandidates;
2626 for(
const PAGE_JOB& job : jobs )
2628 enterScope( jobScope( job ) );
2629 buildNetLookup( *job.page );
2633 std::string sourceName = trimmed( global.
logicalName );
2634 std::string electricalName = powerNet( *job.page, global );
2635 recordPowerAlias( powerAliasCandidates, sourceName, electricalName );
2639 acceptPowerAliases( powerAliasCandidates );
2640 m_scope = PAGE_SCOPE();
2642 if( jobs.size() == 1 )
2644 PAGE_JOB& job = jobs[0];
2646 pollProgress( m_progressReporter, job.page->name );
2647 enterScope( jobScope( job ) );
2648 applyPageSettings( *job.page, m_rootSheet->GetScreen() );
2649 convertPage( *job.page, m_rootSheet->GetScreen(), aRootPath );
2650 m_scope = PAGE_SCOPE();
2663 std::vector<SHEET_JOB> sheetJobs;
2665 for(
size_t i = 0; i < jobs.size(); ++i )
2670 if( order < 0 && i < m_design.pages.size() )
2674 auto pageNumber = titleBlock.props.find(
"Page Number" );
2677 if( pageNumber != titleBlock.props.end()
2678 && wxString::FromUTF8( pageNumber->second ).ToLong( &parsed ) && parsed > 0 )
2680 order =
static_cast<int>( parsed );
2686 if( order < 0 && i < m_design.pages.size() && jobs[i].page->sourcePageNumber != 0 )
2687 order =
static_cast<int>( jobs[i].page->sourcePageNumber );
2689 if(
name.IsEmpty() )
2690 name = wxString::Format( wxS(
"PAGE%zu" ), i + 1 );
2692 sheetJobs.push_back( { jobs[i],
name, order } );
2695 std::stable_sort( sheetJobs.begin(), sheetJobs.end(),
2696 [](
const SHEET_JOB& a,
const SHEET_JOB& b )
2698 int ka = a.order >= 0 ? a.order : std::numeric_limits<int>::max();
2699 int kb = b.order >= 0 ? b.order : std::numeric_limits<int>::max();
2703 if( jobs.size() == m_design.pages.size() )
2705 for(
size_t i = 0; i < sheetJobs.size(); ++i )
2707 sheetJobs[i].job.page->sourcePageNumber = i + 1;
2708 sheetJobs[i].job.page->sourcePageCount = sheetJobs.size();
2712 std::vector<std::pair<wxString, wxString>> names;
2714 for(
size_t i = 0; i < sheetJobs.size(); ++i )
2716 names.emplace_back( uniqueSheetName( sheetJobs[i].
name ),
2717 MakePageFileName(
static_cast<int>( i + 1 ), sheetJobs[i].job.page->name ) );
2720 std::vector<SCH_SHEET*> topSheets = createTopLevelSheets( names,
true,
false );
2722 for(
size_t i = 0; i < sheetJobs.size(); ++i )
2724 SHEET_JOB& sj = sheetJobs[i];
2726 pollProgress( m_progressReporter, sj.job.page->name );
2727 enterScope( jobScope( sj.job ) );
2728 applyPageSettings( *sj.job.page, topSheets[i]->GetScreen() );
2729 convertPage( *sj.job.page, topSheets[i]->GetScreen(), pagePath );
2730 m_scope = PAGE_SCOPE();
2738 if(
m_design.unreferencedFolderPages.empty() )
2741 std::vector<SCH_SHEET*> topSheets =
m_schematic->GetTopLevelSheets();
2746 std::set<wxString> usedFileNames;
2750 if(
path.LastScreen() )
2751 usedFileNames.insert( wxFileName(
path.LastScreen()->GetFileName() ).GetFullName().Lower() );
2754 size_t fileIndex = topSheets.size() + 1;
2755 std::vector<ORCAD_RAW_PAGE*> pages;
2756 std::vector<std::pair<wxString, wxString>> names;
2758 for(
auto& [folder, folderPages] :
m_design.unreferencedFolderPages )
2768 }
while( !usedFileNames.insert( fileName.Lower() ).second );
2770 pages.push_back( &page );
2771 names.emplace_back(
name, fileName );
2778 for(
size_t i = 0; i < pages.size(); ++i )
2783 sheets[i]->SetExcludedFromBoard(
true );
2790 static_cast<SCH_SYMBOL*
>( item )->SetExcludedFromBoard(
true );
2797 const std::optional<std::vector<SEG>>& aSourceWires );
2801 const std::vector<SEG>& aSourceWires )
2814 if( emitted.
A != emitted.
B
2815 && std::any_of( aSourceWires.begin(), aSourceWires.end(),
2816 [&](
const SEG& eligible )
2818 return eligible.Contains( emitted.A ) && eligible.Contains( emitted.B );
2821 source.wires.push_back( line );
2825 if( !aSourceWires.empty() &&
source.wires.empty() )
2826 THROW_IO_ERROR(
_(
"OrCAD interface has no surviving source wire for label placement." ) );
2845 using MEMBER = std::pair<SCH_SHEET_PATH, SCH_ITEM*>;
2846 auto itemKey = [](
const SCH_ITEM* item )
2851 return wxS(
"pin:" ) +
pin->GetParentSymbol()->m_Uuid.AsString() + wxS(
":" ) +
pin->GetNumber()
2852 + wxString::Format( wxS(
":%d:%d" ),
pin->GetPosition().x,
pin->GetPosition().y );
2855 return item->m_Uuid.AsString();
2858 struct SOURCE_PARTITION
2860 std::vector<MEMBER> members;
2861 std::set<wxString> explicitNames;
2862 wxString sourceName;
2868 std::map<SCH_ITEM*, bool> intents;
2876 intents.emplace( intent.label, intent.explicitName );
2880 for(
const auto& [key, subgraphs] : graph->
GetNetMap() )
2884 for(
const auto& [member, parents] : subgraph->GetBusParents() )
2886 wxString
name = member->Name(
true );
2888 bool nativeDriver =
false;
2890 for(
SCH_ITEM* item : subgraph->GetItems() )
2894 if( !label || label->GetText() !=
name )
2897 if( !intents.count( item ) )
2898 nativeDriver =
true;
2899 else if( !selected || label->
m_Uuid < selected->
m_Uuid )
2903 if( !nativeDriver && selected )
2904 intents.erase( selected );
2909 std::vector<SOURCE_PARTITION> partitions;
2911 for(
const auto& [key, subgraphs] : graph->
GetNetMap() )
2913 if( std::any_of( subgraphs.begin(), subgraphs.end(),
2916 return subgraph->GetDriverConnection() && subgraph->GetDriverConnection()->IsBus();
2920 SOURCE_PARTITION partition;
2921 partition.sourceName = key.Name;
2927 auto intent = intents.find( item );
2929 if( intent != intents.end() )
2931 if( intent->second )
2932 partition.explicitNames.insert(
static_cast<SCH_LABEL_BASE*
>( item )->GetText() );
2939 partition.members.emplace_back( subgraph->
GetSheet(), item );
2944 if( !partition.members.empty() )
2948 std::vector<std::pair<wxString, MEMBER>> keyed;
2949 keyed.reserve( partition.members.size() );
2951 for( MEMBER& member : partition.members )
2952 keyed.emplace_back( itemKey( member.second ), std::move( member ) );
2955 std::sort( keyed.begin(), keyed.end(),
2956 [](
const auto&
left,
const auto&
right )
2958 int sheetOrder = left.second.first.Cmp( right.second.first );
2959 return sheetOrder == 0 ? left.first < right.first : sheetOrder < 0;
2962 for(
size_t i = 0; i < keyed.size(); ++i )
2963 partition.members[i] = std::move( keyed[i].second );
2965 partitions.push_back( std::move( partition ) );
2971 if( intents.count( intent.label ) )
2972 intent.screen->Remove( intent.label );
2978 for(
const auto& [item, explicitName] : intents )
2983 auto component = [&](
const MEMBER& member ) -> std::pair<int, CONNECTION_SUBGRAPH*>
2985 SCH_CONNECTION* connection = member.second->Connection( &member.first );
2987 if( connection && connection->
IsNet() && connection->
NetCode() > 0 )
2988 return { connection->
NetCode(),
nullptr };
2994 using COMPONENT = std::pair<int, CONNECTION_SUBGRAPH*>;
2995 std::map<COMPONENT, size_t> owners;
2999 for(
const MEMBER& member : partitions[
index].members )
3003 if( key.first == 0 && !key.second )
3006 auto [owner, inserted] = owners.emplace( key,
index );
3008 if( !inserted && owner->second !=
index )
3009 THROW_IO_ERROR(
_(
"OrCAD native connectivity joins distinct source nets." ) );
3013 std::map<SCH_SHEET_PATH, std::map<wxString, std::set<size_t>>> reservedNames;
3014 std::map<wxString, std::set<size_t>> globalNames;
3018 std::set<SCH_SHEET_PATH> memberSheets;
3020 for(
const MEMBER& member : partitions[
index].members )
3022 auto& names = reservedNames[member.first];
3023 SCH_CONNECTION* connection = member.second->Connection( &member.first );
3024 memberSheets.insert( member.first );
3026 if( connection && connection->
IsNet() )
3027 names[connection->
Name(
true )].insert(
index );
3038 names[driverName].insert(
index );
3041 globalNames[driverName].insert(
index );
3049 auto& names = reservedNames[memberSheet];
3051 for(
const wxString&
name : partitions[
index].explicitNames )
3058 SOURCE_PARTITION& partition = partitions[
index];
3061 return aLeft.
Cmp( aRight ) < 0;
3064 std::map<SCH_SHEET_PATH, std::map<COMPONENT, std::vector<MEMBER>>,
decltype( sheetLess )> bySheet( sheetLess );
3065 bool hasExplicitDriver =
false;
3066 bool needsDriver =
false;
3069 for(
const MEMBER& member : partition.members )
3073 if( key.first == 0 && !key.second )
3076 bySheet[member.first][key].push_back( member );
3078 if( member.second->Type() ==
SCH_PIN_T )
3081 needsDriver |= subgraph && !subgraph->
GetDriver();
3088 hasExplicitDriver =
true;
3096 bool needsBridge = std::any_of( bySheet.begin(), bySheet.end(),
3097 [](
const auto& sheet ) { return sheet.second.size() > 1; } );
3098 bool needsName = needsDriver || ( !hasExplicitDriver && !partition.explicitNames.empty() );
3100 if( !needsBridge && !needsName )
3103 if(
name.IsEmpty() && !partition.explicitNames.empty() )
3104 name = *partition.explicitNames.begin();
3106 const bool generatedName =
name.IsEmpty();
3110 for(
const MEMBER& member : partition.members )
3112 if( member.second->Type() ==
SCH_PIN_T )
3114 wxString candidate =
static_cast<SCH_PIN*
>( member.second )->GetDefaultNetName( member.first );
3116 if( !candidate.IsEmpty() && (
name.IsEmpty() || candidate <
name ) )
3121 if(
name.IsEmpty() )
3122 name = wxS(
"Net-(" ) + partition.members.front().second->m_Uuid.AsString() + wxS(
")" );
3124 const wxString base =
name;
3125 auto conflicts = [&]()
3127 auto global = globalNames.find(
name );
3129 if( global != globalNames.end()
3130 && std::any_of( global->second.begin(), global->second.end(),
3131 [&](
size_t owner ) { return owner != index; } ) )
3134 for(
const auto& [sheet, components] : bySheet )
3136 const auto& names = reservedNames[sheet];
3137 auto reserved = names.find(
name );
3139 if( reserved != names.end()
3140 && std::any_of( reserved->second.begin(), reserved->second.end(),
3141 [&](
size_t owner ) { return owner != index; } ) )
3148 for(
size_t suffix = 2; conflicts(); ++suffix )
3149 name = wxString::Format( wxS(
"%s_%zu" ), base, suffix );
3152 for(
const auto& [sheet, components] : bySheet )
3154 if( components.size() < 2 && !needsName )
3158 std::vector<const std::vector<MEMBER>*> ordered;
3160 for(
const auto& [key, members] : components )
3161 ordered.push_back( &members );
3163 std::sort( ordered.begin(), ordered.end(),
3164 [&](
const std::vector<MEMBER>* aLeft,
const std::vector<MEMBER>* aRight )
3166 return itemKey( aLeft->front().second ) < itemKey( aRight->front().second );
3169 for(
const std::vector<MEMBER>* componentMembers : ordered )
3171 const std::vector<MEMBER>& members = *componentMembers;
3172 bool alreadyNamed = std::any_of( members.begin(), members.end(),
3173 [&](
const MEMBER& member )
3175 if( member.second->Type() == SCH_SHEET_PIN_T
3176 || CONNECTION_SUBGRAPH::GetDriverPriority( member.second )
3177 <= CONNECTION_SUBGRAPH::PRIORITY::PIN )
3180 CONNECTION_SUBGRAPH* subgraph = graph->GetSubgraphForItem( member.second );
3181 return subgraph && subgraph->GetNameForDriver( member.second ) == name;
3187 std::vector<SEG> wires;
3188 VECTOR2I preferred = members.front().second->GetPosition();
3190 for(
const MEMBER& member : members )
3193 wires.push_back(
static_cast<SCH_LINE*
>( member.second )->
GetSeg() );
3199 THROW_IO_ERROR( wxString::Format(
_(
"Cannot place OrCAD net repair '%s' without a wire intersection." ),
name ) );
3203 "net-repair:" + sheet.PathAsString().ToStdString() +
":"
3204 + itemKey( members.front().second ).ToStdString() +
":" +
name.ToStdString(), 0 );
3205 sheet.LastScreen()->Append( label );
3206 reservedNames[sheet][
name].insert(
index );
3217 std::set<COMPONENT> connected;
3219 for(
const MEMBER& member : partitions[
index].members )
3223 if( key.first == 0 && !key.second )
3226 connected.insert( key );
3227 auto [owner, inserted] = owners.emplace( key,
index );
3229 if( !inserted && owner->second !=
index )
3231 SCH_CONNECTION* connection = member.second->Connection( &member.first );
3233 _(
"OrCAD net repair joins source nets '%s' and '%s' at '%s' on sheet '%s' (net '%s')." ),
3234 partitions[owner->second].sourceName, partitions[
index].sourceName,
3235 itemKey( member.second ), member.first.Last()->GetName(),
3236 connection ? connection->
Name() : wxString() ) );
3240 if( connected.size() > 1 )
3243 std::set<COMPONENT> described;
3245 for(
const MEMBER& member : partitions[
index].members )
3247 if( described.insert( component( member ) ).second )
3249 SCH_CONNECTION* connection = member.second->Connection( &member.first );
3250 detail += wxS(
" " ) + member.first.Last()->GetName() + wxS(
":" )
3251 + ( connection ? connection->
Name() : wxString() );
3255 THROW_IO_ERROR( wxString::Format(
_(
"OrCAD source net '%s' remains disconnected after local repair:%s" ),
3265 return std::nullopt;
3268 auto entry = std::find_if(
m_scope.occ->netNames.begin(),
m_scope.occ->netNames.end(),
3269 [&](
const auto& aEntry )
3271 return &aEntry.second == aName;
3274 if( entry ==
m_scope.occ->netNames.end() )
3275 return std::nullopt;
3277 return entry->first;
3285 using TERMINAL = std::pair<SCH_SHEET_PATH, SCH_PIN*>;
3286 std::map<int, std::vector<TERMINAL>> terminals;
3287 std::map<int, wxString> netNames;
3289 for(
const auto& [key, subgraphs] :
m_schematic->ConnectionGraph()->GetNetMap() )
3293 for(
SCH_ITEM* item : subgraph->GetItems() )
3300 if( connection && connection->
IsNet() )
3302 const int code = connection->
NetCode();
3303 terminals[code].emplace_back( subgraph->GetSheet(),
pin );
3305 if(
auto [entry, inserted] = netNames.try_emplace( code ); inserted )
3306 entry->second = connection->
Name();
3313 std::map<SCH_PIN*, uint32_t> sourcePinIds;
3323 std::map<SCH_SCREEN*, std::vector<EXTRA_RECORD>> extraRecords;
3342 std::set<SCH_PIN*> assigned;
3356 if( candidate->GetNumber() == identity.
number && candidate->GetPosition() == identity.
position
3357 && !assigned.count( candidate )
3358 && ( !identity.
libraryPin || ( candidate->GetLibPin()
3359 && candidate->GetLibPin()->m_Uuid == *identity.
libraryPin ) ) )
3367 warn( wxString::Format(
_(
"Cannot uniquely map OrCAD source pin %zu of '%s'." ),
3373 assigned.insert(
pin );
3375 std::set<uint32_t> netIds;
3377 if( sourcePin.
wordB && page->second->netmap.count( sourcePin.
wordB ) )
3378 netIds.insert( sourcePin.
wordB );
3380 if( netIds.empty() && sourcePin.
wordA )
3382 for(
const ORCAD_WIRE& wire : page->second->wires )
3385 netIds.insert( wire.
id );
3391 for(
const ORCAD_WIRE& wire : page->second->wires )
3394 netIds.insert( wire.
id );
3397 if( netIds.size() > 1 )
3404 extraRecords[screen].push_back( { wireless->second.first, wireless->second.second,
pin,
false } );
3407 extraRecords[screen].push_back( { 0, std::string(),
pin,
true } );
3409 for( uint32_t netId : netIds )
3423 std::map<uint32_t, std::vector<const SCH_CONNECTION*>> busMembers;
3424 std::map<uint32_t, std::vector<KIID>> busMemberItems;
3434 for(
SCH_ITEM* item : groupItems->second )
3438 if( !connection || !connection->
IsBus() )
3441 const auto members = connection->
AllMembers();
3443 for( uint32_t memberId :
group.members )
3450 std::set<wxString> memberNames;
3452 for(
const std::string& sourceName : sourceNames->second )
3454 memberNames.insert(
FromOrcadString( kicadElectricalNetName( sourceName ) ) );
3464 for(
const std::shared_ptr<SCH_CONNECTION>& member : members )
3466 if( member->IsNet() && memberNames.count( member->Name(
true ) ) )
3468 busMembers[memberId].push_back( member.get() );
3469 busMemberItems[memberId].push_back( item->
m_Uuid );
3478 auto appendRecord = [&]( uint32_t id,
const std::set<std::string>& names,
3479 const std::vector<SCH_ITEM*>& items,
bool noConnect )
3487 std::set<int> codes;
3488 std::set<wxString> finalNames;
3489 std::set<int> busCodes;
3490 std::set<wxString> finalBusNames;
3493 if( connection && connection->IsNet() && connection->NetCode() > 0 )
3495 codes.insert( connection->NetCode() );
3496 auto name = netNames.find( connection->NetCode() );
3497 finalNames.insert(
name != netNames.end() ?
name->second : connection->Name() );
3508 if( connection && connection->
IsBus() )
3510 busCodes.insert( connection->
BusCode() );
3511 finalBusNames.insert( connection->
Name() );
3513 for(
const std::shared_ptr<SCH_CONNECTION>& member : connection->
AllMembers() )
3514 addNet( member.get() );
3518 addNet( connection );
3530 entry.
itemUuids.insert( entry.
itemUuids.end(), busMemberItems[
id].begin(), busMemberItems[
id].end() );
3532 std::set<std::tuple<KIID, int, wxString, unsigned>> seen;
3534 std::vector<TERMINAL> sourceTerminals;
3536 for(
int code : codes )
3537 sourceTerminals.insert( sourceTerminals.end(), terminals[code].begin(), terminals[code].end() );
3542 sourceTerminals.emplace_back( sheet,
static_cast<SCH_PIN*
>( item ) );
3545 for(
const auto& [pinSheet,
pin] : sourceTerminals )
3548 unsigned duplicateIndex = 0;
3549 auto pinIdentity = [&](
SCH_PIN* candidate )
3555 sourcePinIds[candidate] );
3560 if( peer->GetNumber() ==
pin->GetNumber() && pinIdentity( peer ) < pinIdentity(
pin ) )
3566 if( !seen.emplace( symbol->
m_Uuid, unit,
pin->GetNumber(), duplicateIndex ).second )
3576 return std::tie( left.symbolUuid, left.unit, left.pinNumber, left.duplicateIndex )
3577 < std::tie( right.symbolUuid, right.unit, right.pinNumber, right.duplicateIndex );
3584 else if( !busCodes.empty() )
3586 else if( codes.empty() )
3591 if( busCodes.size() == 1 && finalBusNames.size() == 1 )
3593 else if( busCodes.empty() && finalNames.size() == 1 )
3596 for(
const std::string&
name : names )
3603 && kicadOccurrenceNetName(
name ) == generated->second )
3608 map.
entries.push_back( entry );
3614 static const std::vector<SCH_ITEM*> noItems;
3621 appendRecord( it->first.second, it->second,
3625 for(
const EXTRA_RECORD& record : extraRecords[screen] )
3626 appendRecord( record.id, { record.name }, { record.pin }, record.noConnect );
3632 auto leftKey = std::tie( left.view, left.occurrence, left.sourceNetId, left.originalName,
3633 left.nameAtImport, left.status, left.itemUuids );
3634 auto rightKey = std::tie( right.view, right.occurrence, right.sourceNetId, right.originalName,
3635 right.nameAtImport, right.status, right.itemUuids );
3637 if( leftKey != rightKey )
3638 return leftKey < rightKey;
3640 return std::lexicographical_compare( left.terminals.begin(), left.terminals.end(),
3641 right.terminals.begin(), right.terminals.end(),
3642 []( const IMPORT_NET_TERMINAL& a, const IMPORT_NET_TERMINAL& b )
3644 return std::tie( a.symbolUuid, a.unit, a.pinNumber, a.duplicateIndex,
3646 < std::tie( b.symbolUuid, b.unit, b.pinNumber, b.duplicateIndex,
3651 m_schematic->SetImportNetMap( std::move( map ) );
3671 std::vector<SEG> wires;
3676 for(
SCH_ITEM* item : sourceItems->second )
3679 wires.push_back(
static_cast<SCH_LINE*
>( item )->GetSeg() );
3686 THROW_IO_ERROR( wxString::Format(
_(
"Cannot place OrCAD label '%s' without a wire intersection." ),
3687 label->GetText() ) );
3689 sourceKey.first->Remove( label );
3690 label->SetPosition( *position );
3691 sourceKey.first->Append( label );
3698 std::vector<SEG> wires;
3701 wires.push_back( wire->
GetSeg() );
3706 THROW_IO_ERROR( wxString::Format(
_(
"Cannot place OrCAD interface '%s' clear of wires and pins." ),
3707 source.label->GetText() ) );
3710 source.label->SetPosition( *position );
3716 std::map<SCH_LINE*, std::vector<std::pair<SCH_SCREEN*, uint32_t>>> wireSources;
3735 + std::to_string( start.
x ) +
":" + std::to_string( start.
y ) +
":"
3736 + std::to_string(
end.x ) +
":" + std::to_string(
end.y ) );
3737 std::vector<std::pair<SCH_SCREEN*, uint32_t>> sources = wireSources[original];
3739 for(
const auto&
source : sources )
3742 wireSources[segment] = std::move( sources );
3751 bool aContainerPage,
bool aSharedFolderPage )
3764 occurrencePath.push_back( wxString::Format( wxS(
"%u" ), block.
targetDbId ) );
3767 if( findOccurrence( block.
scope ) )
3770 occurrencePath.pop_back();
3771 occurrencePath.pop_back();
3778 findOccurrence(
m_design.occurrenceRoot );
3785 for(
const auto& [
id, aliases] : aPage.
netAliases )
3786 m_sourceNetNames[{ aScreen,
id }].insert( aliases.begin(), aliases.end() );
3801 bool sharedFolderPage = aSharedFolderPage
3804 [&](
const auto& aFolder )
3806 return aFolder.second.size() > 1
3807 && std::any_of( aFolder.second.begin(), aFolder.second.end(),
3808 [&]( const ORCAD_RAW_PAGE& aCandidate )
3810 return &aCandidate == &aPage;
3813 wxString syntheticPageSuffix = aSheetPath.Last()->GetName().Mid( 5 );
3814 syntheticPageSuffix.Trim(
true ).Trim(
false );
3815 bool syntheticPage = aSheetPath.Last()->GetName().StartsWith( wxS(
"Sheet" ) )
3816 && !syntheticPageSuffix.empty()
3817 && std::all_of( syntheticPageSuffix.begin(), syntheticPageSuffix.end(),
3820 return wxIsdigit( c );
3822 sharedFolderPage |= syntheticPage;
3823 bool semanticNestedHierarchy = aSheetPath.size() > 2 && !sharedFolderPage
3824 && !aSheetPath.Last()->GetPins().empty();
3825 placeWires( aPage, aScreen, hierarchical, semanticNestedHierarchy, sharedFolderPage );
3826 placeOffpageConnectors( aPage, aScreen, aSheetPath, hierarchical );
3827 placePorts( aPage, aScreen, !aSheetPath.Last()->IsTopLevelSheet() );
3828 placeGraphics( aPage, aScreen );
3831 placeInstance( aPage, instance, aScreen, aSheetPath );
3834 placePowerSymbol( aPage, global, powerNet( aPage, global ), aScreen, aSheetPath );
3836 assignPageItemUuids( m_pageOrdinal++ );
3837 m_pageItemScreen =
nullptr;
3838 m_pageItems.clear();
3852 if( widthDbu <= 0 || heightDbu <= 0 )
3861 auto addLine = [&]( std::initializer_list<ORCAD_POINT> aPoints )
3863 std::vector<VECTOR2I> points;
3868 appendPageItem( aScreen, makeSheetPoly( points, border, color ) );
3871 addLine( { { 0, 0 }, { widthDbu, 0 }, { widthDbu, heightDbu }, { 0, heightDbu }, { 0, 0 } } );
3879 horizontalBand = std::clamp( horizontalBand, 0, heightDbu / 2 );
3880 verticalBand = std::clamp( verticalBand, 0, widthDbu / 2 );
3882 if( horizontalBand > 0 && verticalBand > 0 )
3884 addLine( { { verticalBand, horizontalBand }, { widthDbu - verticalBand, horizontalBand },
3885 { widthDbu - verticalBand, heightDbu - horizontalBand },
3886 { verticalBand, heightDbu - horizontalBand }, { verticalBand, horizontalBand } } );
3889 auto addLabel = [&](
const wxString& aContent,
int aX,
int aY )
3906 wxString label = settings.
horizontalChar ? wxString(
static_cast<wxUniChar
>(
'A' + value ) )
3907 : wxString::Format( wxS(
"%d" ), value + 1 );
3911 addLine( { {
left, 0 }, {
left, horizontalBand } } );
3912 addLine( { {
left, heightDbu - horizontalBand }, {
left, heightDbu } } );
3915 addLabel( label, (
left +
right ) / 2, horizontalBand / 2 );
3916 addLabel( label, (
left +
right ) / 2, heightDbu - horizontalBand / 2 );
3924 wxString label = settings.
verticalChar ? wxString(
static_cast<wxUniChar
>(
'A' + value ) )
3925 : wxString::Format( wxS(
"%d" ), value + 1 );
3929 addLine( { { 0,
top }, { verticalBand,
top } } );
3930 addLine( { { widthDbu - verticalBand,
top }, { widthDbu,
top } } );
3933 addLabel( label, verticalBand / 2, (
top + bottom ) / 2 );
3934 addLabel( label, widthDbu - verticalBand / 2, (
top + bottom ) / 2 );
3942 wxString::Format( wxS(
"P%02d_" ), aPageIndex ) +
SanitizeFileName( aPageName ) + wxS(
".kicad_sch" );
3952 const wxString illegal( wxS(
"<>:\"/\\|?*" ) );
3956 for( wxUniChar c : in )
3958 if( c.GetValue() < 0x20 || illegal.Find( c ) != wxNOT_FOUND )
3964 while( !out.IsEmpty() && ( out.Last() ==
' ' || out.Last() ==
'.' ) )
3967 while( !out.IsEmpty() && ( out.GetChar( 0 ) ==
' ' || out.GetChar( 0 ) ==
'.' ) )
3971 out = wxS(
"unnamed" );
3998 double k = settings.
isMetric ? 0.001 : 0.0254;
3999 double nominalWmm = settings.
width * k;
4000 double nominalHmm = settings.
height * k;
4019 dx = ( dx + 9 ) / 10 * 10;
4020 dy = ( dy + 9 ) / 10 * 10;
4033 double neededWmm = ( maxX +
MARGIN_R_DBU ) * DBU_TO_MM;
4034 double neededHmm = ( maxY +
MARGIN_B_DBU ) * DBU_TO_MM;
4036 int paperWmm =
static_cast<int>( std::ceil( std::max( nominalWmm, neededWmm ) ) );
4037 int paperHmm =
static_cast<int>( std::ceil( std::max( nominalHmm, neededHmm ) ) );
4056 auto add = [&](
int aX,
int aY )
4066 minX = std::min( minX, aX );
4067 minY = std::min( minY, aY );
4068 maxX = std::max( maxX, aX );
4069 maxY = std::max( maxY, aY );
4075 add( wire.
x1, wire.
y1 );
4076 add( wire.
x2, wire.
y2 );
4088 for(
const std::vector<ORCAD_GRAPHIC_INST>* list :
4093 add( inst.x, inst.y );
4094 add( inst.bbox.x1, inst.bbox.y1 );
4095 add( inst.bbox.x2, inst.bbox.y2 );
4107 if( !prim.
points.empty() )
4114 add( prim.
x1, prim.
y1 );
4115 add( prim.
x2, prim.
y2 );
4122 add( entry.
x1, entry.
y1 );
4123 add( entry.
x2, entry.
y2 );
4128 add( block.
x1, block.
y1 );
4129 add( block.
x1 + block.
w, block.
y1 + block.
h );
4178 aInst.bbox.x1 += aDx;
4179 aInst.bbox.y1 += aDy;
4180 aInst.bbox.x2 += aDx;
4181 aInst.bbox.y2 += aDy;
4190 for( std::vector<ORCAD_GRAPHIC_INST>* list :
4194 shiftGraphic( inst );
4223 if( symbolIt ==
m_design.symbols.end() )
4230 std::transform( aPath.begin(), aPath.end(), aPath.begin(),
4231 [](
unsigned char aChar )
4233 return aChar ==
'\\' ?
'/' : static_cast<char>( std::tolower( aChar ) );
4238 bool sourceMatched =
false;
4240 if(
auto source = aInst.
props.find(
"Source Library" );
4247 sourceMatched =
true;
4255 symbolDef = &variant;
4256 sourceMatched =
true;
4269 if( !aDefinition.bbox )
4272 int width =
std::abs( aDefinition.bbox->x2 - aDefinition.bbox->x1 );
4273 int height =
std::abs( aDefinition.bbox->y2 - aDefinition.bbox->y1 );
4276 std::swap( width, height );
4278 return width == placedWidth && height == placedHeight;
4281 if( !sourceMatched && !matchesPlacedBounds( *symbolDef ) )
4285 if( matchesPlacedBounds( variant ) )
4287 symbolDef = &variant;
4303 auto calendarDate = [&]( uint32_t aTimestamp )
4305 return tbInst.
name ==
"TITLEBLK/Rudy" ? orcadShortCalendarDate( aTimestamp )
4306 : orcadCalendarDate( aTimestamp );
4309 auto sourceValue = [&](
const std::string& aKey ) -> std::string
4311 if( aKey ==
"Page Size" )
4320 if( aKey ==
"SIZE" || aKey ==
"Page Number" || aKey ==
"Page Count" )
4322 if(
auto value = tbInst.
props.find( aKey ); value != tbInst.
props.end() && !value->second.empty() )
4324 return value->second;
4327 if(
auto value = aPage.
props.find( aKey );
4328 value != aPage.
props.end() && !value->second.empty() )
4330 return value->second;
4335 if(
auto value = symbolDef->
props.find( aKey );
4336 value != symbolDef->
props.end() && !value->second.empty() )
4338 return value->second;
4343 if( aKey ==
"SIZE" )
4346 if( ( aKey ==
"Page Modify Date" || aKey ==
"Schematic Modify Date" )
4350 if( aKey ==
"Design Modify Date" &&
m_design.library.modifyTimestamp != 0 )
4351 return calendarDate(
m_design.library.modifyTimestamp );
4353 if( ( aKey ==
"Page Create Date" || aKey ==
"Schematic Create Date" )
4357 if( aKey ==
"Design Create Date" &&
m_design.library.createTimestamp != 0 )
4358 return calendarDate(
m_design.library.createTimestamp );
4360 if(
auto value = tbInst.
props.find( aKey ); value != tbInst.
props.end() && !value->second.empty() )
4361 return value->second;
4363 if(
auto value = aPage.
props.find( aKey ); value != aPage.
props.end() && !value->second.empty() )
4364 return value->second;
4368 if(
auto value = symbolDef->
props.find( aKey );
4369 value != symbolDef->
props.end() && !value->second.empty() )
4371 return value->second;
4375 if( aKey ==
"Page Modify Date" )
4392 std::string value = sourceValue( dp.
name );
4397 if( value.empty() || value ==
"?" )
4398 value =
"<" + dp.
name +
">";
4427 if( tbInst.
props.empty() )
4430 auto get = [&](
const char* aKey ) -> wxString
4432 std::string value = sourceValue( aKey );
4438 titleBlock.
SetTitle( get(
"Title" ) );
4440 wxString date = get(
"Page Modify Date" );
4442 if( date.IsEmpty() )
4443 date = get(
"Doc Date" );
4451 for(
const char* stock : {
"Doc",
"OrgAddr1",
"OrgAddr2" } )
4453 if( wxString
text = get( stock ); !
text.IsEmpty() )
4459 static const std::set<std::string> mapped = {
"Title",
"RevCode",
"OrgName",
"Doc",
4460 "OrgAddr1",
"OrgAddr2",
"Doc Date",
"Page Count",
4461 "Page Number",
"Page Modify Date" };
4463 for(
const auto& [propName, propValue] : tbInst.
props )
4465 if( slot >= COMMENT_COUNT || propValue.empty() || mapped.count( propName ) )
4478 SCH_SCREEN* aScreen,
double aTextScaleX,
double aTextScaleY,
4479 bool aUseGenericTextBaseline )
4482 int width = bbox.
x2 - bbox.
x1;
4483 int height = bbox.
y2 - bbox.
y1;
4485 auto transform = [&](
int aX,
int aY )
4497 graphic.
nested = std::make_unique<ORCAD_SYMBOL_DEF>();
4503 if( source.kind == ORCAD_PRIM_KIND::IMAGE )
4506 ORCAD_PRIMITIVE primitive = source;
4508 auto transformBox = [&]
4510 std::array<VECTOR2I, 4> corners = { transform( aOffsetX + source.x1, aOffsetY + source.y1 ),
4511 transform( aOffsetX + source.x2, aOffsetY + source.y1 ),
4512 transform( aOffsetX + source.x2, aOffsetY + source.y2 ),
4513 transform( aOffsetX + source.x1, aOffsetY + source.y2 ) };
4515 primitive.x1 = primitive.x2 = corners[0].x;
4516 primitive.y1 = primitive.y2 = corners[0].y;
4518 for( const VECTOR2I& corner : corners )
4520 primitive.x1 = std::min( primitive.x1, corner.x );
4521 primitive.y1 = std::min( primitive.y1, corner.y );
4522 primitive.x2 = std::max( primitive.x2, corner.x );
4523 primitive.y2 = std::max( primitive.y2, corner.y );
4529 VECTOR2I p1 = transform( aOffsetX + source.x1, aOffsetY + source.y1 );
4530 VECTOR2I p2 = transform( aOffsetX + source.x2, aOffsetY + source.y2 );
4531 primitive.x1 = p1.x;
4532 primitive.y1 = p1.y;
4533 primitive.x2 = p2.x;
4534 primitive.y2 = p2.y;
4538 VECTOR2I anchor = transform( aOffsetX + source.x1, aOffsetY + source.y1 );
4539 primitive.textBoundsStart.reset();
4540 primitive.x1 = primitive.x2 = anchor.x;
4541 primitive.y1 = primitive.y2 = anchor.y;
4552 transform( aOffsetX + aPoint.
x, aOffsetY + aPoint.
y );
4560 page.
graphics.push_back( std::move( graphic ) );
4561 placeGraphics( page, aScreen );
4569 int width = bbox.
x2 - bbox.
x1;
4570 int height = bbox.
y2 - bbox.
y1;
4575 if( primitive.kind != ORCAD_PRIM_KIND::IMAGE )
4579 OrcadTransformPoint( aOrient, width, height, aBaseX, aBaseY,
4580 aOffsetX + ( primitive.x1 + primitive.x2 ) / 2,
4581 aOffsetY + ( primitive.y1 + primitive.y2 ) / 2 );
4582 int imageWidth = std::abs( primitive.x2 - primitive.x1 );
4583 int imageHeight = std::abs( primitive.y2 - primitive.y1 );
4584 ORCAD_PRIMITIVE image = primitive;
4585 image.x1 = center.x - imageWidth / 2;
4586 image.y1 = center.y - imageHeight / 2;
4587 image.x2 = image.x1 + imageWidth;
4588 image.y2 = image.y1 + imageHeight;
4589 placeBitmap( image, aScreen, aOrient );
4601 m_netIndex.wireEndpoints[{ wire.
x1, wire.
y1 }].push_back( &wire );
4602 m_netIndex.wireEndpoints[{ wire.
x2, wire.
y2 }].push_back( &wire );
4612 netIds.insert(
pin.wordB );
4617 netIds.insert( wire.
id );
4626 for(
const auto& [occurrenceId, occurrenceName] :
m_scope.occ->netNames )
4628 if( std::optional<uint32_t> objectId = occurrenceNetObjectId( occurrenceName ) )
4630 auto sourceWire = std::find_if( aPage.
wires.begin(), aPage.
wires.end(),
4633 return aWire.dbId == *objectId;
4636 if( sourceWire != aPage.
wires.end() )
4638 m_netIndex.occurrenceNamesByNetId[sourceWire->id].insert( &occurrenceName );
4645 return aInstance.dbId == *objectId;
4648 if( sourceInstance == aPage.
instances.end() )
4651 std::string occurrenceKey =
OrcadLower( occurrenceName );
4653 auto matchesOccurrenceName = [&]( uint32_t aNetId )
4655 std::set<std::string> localNames =
pageNetNames( aPage, aNetId );
4657 return std::any_of( localNames.begin(), localNames.end(),
4658 [&]( std::string aName )
4660 aName = OrcadLower( aName );
4661 return occurrenceKey == aName
4662 || ( occurrenceKey.size() > aName.size()
4663 && occurrenceKey[aName.size()] ==
'_'
4664 && occurrenceKey.compare( 0, aName.size(), aName ) == 0 );
4672 if( matchesOccurrenceName( netId ) )
4673 m_netIndex.occurrenceNamesByNetId[netId].insert( &occurrenceName );
4684 static const std::set<uint32_t> none;
4685 auto netIds =
m_netIndex.pinNets.find( &aPin );
4687 wxCHECK_MSG( netIds !=
m_netIndex.pinNets.end(), none, wxS(
"Pin is not on the indexed page" ) );
4688 return netIds->second;
4694 auto wireName = [&aPage](
const ORCAD_WIRE& aWire )
4698 if( !trimmed( alias.
name ).empty() )
4702 auto aliases = aPage.
netAliases.find( aWire.id );
4706 std::set<std::string> names;
4708 for(
const std::string& alias : aliases->second )
4710 if( !trimmed( alias ).
empty() )
4711 names.insert( alias );
4714 if( names.size() == 1 )
4715 return *names.begin();
4717 return std::string();
4720 auto net = aPage.
netmap.find( aWire.id );
4721 return net != aPage.
netmap.end() ? net->second : std::string();
4724 auto endIt =
m_netIndex.wireEndpoints.find( { aX, aY } );
4726 const std::vector<const ORCAD_WIRE*>* endWires = endIt !=
m_netIndex.wireEndpoints.end() ? &endIt->second :
nullptr;
4732 std::string
name = wireName( *wire );
4744 std::string
name = wireName( wire );
4751 return std::string();
4759 auto memo =
m_netIndex.powerNets.find( &aInst );
4764 return memo->second;
4772 auto nameIt = aInst.
props.find(
"Name" );
4773 std::string propertyName = nameIt != aInst.
props.end() ? trimmed( nameIt->second ) : std::string();
4774 std::string logicalName = trimmed( aInst.
logicalName );
4776 bool authoritativeOccurrenceNet =
false;
4777 const auto& occurrenceNamesByPageNetId =
m_netIndex.occurrenceNamesByNetId;
4778 auto occurrenceElectricalName = [&](
const std::string* aName )
4780 return aName ? *aName : std::string();
4785 std::set<const std::string*> generatedNamesAtPin;
4789 for(
size_t pinIndex = 0; pinIndex < instance.
pins.size(); ++pinIndex )
4797 bool touchesWire = std::any_of( aPage.
wires.begin(), aPage.
wires.end(),
4800 return onSegment( placedPin.x, placedPin.y, aWire );
4803 if( electricalPosition !=
pin
4804 || ( electricalPosition ==
VECTOR2I( placedPin.
x, placedPin.
y ) && touchesWire ) )
4809 std::string generatedName = generatedPinNetName( instance.
dbId, pinIndex );
4811 for(
const auto& [occurrenceId, occurrenceName] :
m_scope.occ->netNames )
4813 if( occurrenceName == generatedName )
4814 generatedNamesAtPin.insert( &occurrenceName );
4819 if( generatedNamesAtPin.size() == 1 )
4820 return occurrenceElectricalName( *generatedNamesAtPin.begin() );
4822 if( net.empty() && !logicalName.empty() )
4824 std::set<const std::string*> matchingNames;
4826 for(
const auto& [occurrenceId, occurrenceName] :
m_scope.occ->netNames )
4828 if(
OrcadIEquals( kicadOccurrenceNetName( occurrenceName ), logicalName ) )
4830 matchingNames.insert( &occurrenceName );
4834 if( matchingNames.size() == 1 )
4836 if( std::optional<uint32_t> occurrenceId =
occurrenceNetIdFor( *matchingNames.begin() ) )
4841 std::set<const std::string*> objectNets;
4842 std::set<const std::string*> occurrenceNets;
4846 bool endpoint = (
pin.x == wire.
x1 &&
pin.y == wire.
y1 ) || (
pin.x == wire.
x2 &&
pin.y == wire.
y2 );
4851 auto objectNames = occurrenceNamesByPageNetId.find( wire.
id );
4853 if( objectNames != occurrenceNamesByPageNetId.end() && objectNames->second.size() == 1 )
4854 objectNets.insert( *objectNames->second.begin() );
4856 auto pageNet = aPage.
netmap.find( wire.
id );
4858 if( pageNet == aPage.
netmap.end() || pageNet->second.empty() )
4861 for(
const auto& [occurrenceId, occurrenceName] :
m_scope.occ->netNames )
4864 occurrenceNets.insert( &occurrenceName );
4868 if( objectNets.size() == 1 )
4870 net = occurrenceElectricalName( *objectNets.begin() );
4871 authoritativeOccurrenceNet =
true;
4873 else if( occurrenceNets.size() == 1 )
4875 net = occurrenceElectricalName( *occurrenceNets.begin() );
4876 authoritativeOccurrenceNet =
true;
4880 if(
m_scope.occ && !authoritativeOccurrenceNet )
4882 std::set<const std::string*> directPinNets;
4896 auto names = occurrenceNamesByPageNetId.find( wire.
id );
4898 if( names != occurrenceNamesByPageNetId.end() && names->second.size() == 1 )
4899 directPinNets.insert( *names->second.begin() );
4904 if( directPinNets.size() == 1 )
4906 net = occurrenceElectricalName( *directPinNets.begin() );
4907 authoritativeOccurrenceNet =
true;
4911 if(
m_scope.occ && !authoritativeOccurrenceNet )
4915 if( matchingNetIds.size() == 1 )
4917 auto names = occurrenceNamesByPageNetId.find( *matchingNetIds.begin() );
4919 if( names != occurrenceNamesByPageNetId.end() && names->second.size() == 1 )
4921 net = occurrenceElectricalName( *names->second.begin() );
4922 authoritativeOccurrenceNet =
true;
4929 std::set<std::string> pinNetNames;
4938 for( uint32_t netId : { componentPin.
wordB, componentPin.
wordA } )
4940 std::set<std::string> sourceNames =
pageNetNames( aPage, netId );
4942 std::set<std::string> occurrenceNames;
4946 for(
const std::string& sourceName : sourceNames )
4948 for(
const auto& [occurrenceId, occurrenceName] :
m_scope.occ->netNames )
4952 occurrenceNames.insert( occurrenceName );
4958 if( occurrenceNames.size() == 1 )
4959 pinNetNames.insert( *occurrenceNames.begin() );
4960 else if( sourceNames.size() == 1 )
4961 pinNetNames.insert( *sourceNames.begin() );
4966 if( pinNetNames.size() == 1 )
4967 net = *pinNetNames.begin();
4970 std::string physicalName = !propertyName.empty() ? propertyName : logicalName;
4972 if( !physicalName.empty() )
4976 bool endpoint = (
pin.x == wire.
x1 &&
pin.y == wire.
y1 ) || (
pin.x == wire.
x2 &&
pin.y == wire.
y2 );
4982 std::set<std::string> distinctNames;
4984 for(
const std::string&
name : names )
4987 bool hasPhysicalName = std::any_of( names.begin(), names.end(),
4988 [&](
const std::string& aName )
4990 return OrcadIEquals( aName, physicalName );
4993 if( ( !
m_scope.occ ||
m_scope.occ->netNames.empty() ) && distinctNames.size() > 1
4994 && hasPhysicalName )
5001 std::string sourcePowerName = !logicalName.empty() ? logicalName : propertyName;
5004 net = std::move( sourcePowerName );
5007 if(
m_scope.occ && !authoritativeOccurrenceNet )
5009 std::set<const std::string*> occurrenceAliases;
5013 bool endpoint = (
pin.x == wire.
x1 &&
pin.y == wire.
y1 ) || (
pin.x == wire.
x2 &&
pin.y == wire.
y2 );
5023 for(
const std::string& alias : aliases->second )
5025 for(
const auto& [occurrenceId, occurrenceName] :
m_scope.occ->netNames )
5028 occurrenceAliases.insert( &occurrenceName );
5033 if( occurrenceAliases.size() == 1 )
5034 net = occurrenceElectricalName( *occurrenceAliases.begin() );
5037 if( net.empty() || ( isImplicitGeneratedName( net ) && !authoritativeOccurrenceNet ) )
5039 if( !logicalName.empty() )
5041 else if( !propertyName.empty() )
5056 if( !definition || definition->
pins.empty() )
5064 int width = symBox.
x2 - symBox.
x1;
5065 int height = symBox.
y2 - symBox.
y1;
5069 bool legacyExtent = width > 0 && height > 0 && storedExtent && ( bboxWidth > 4 * width || bboxHeight > 4 * height );
5087 std::string logicalName = trimmed( aInst.
logicalName );
5088 constexpr int MAX_PIN_SNAP_DISTANCE = 20;
5092 if( logicalName.empty() )
5095 size_t matchingConnectors = 0;
5096 auto countMatchingConnectors = [&](
const std::vector<ORCAD_GRAPHIC_INST>& aConnectors )
5098 matchingConnectors += std::count_if( aConnectors.begin(), aConnectors.end(),
5101 std::string name = OrcadLower( trimmed( aConnector.logicalName ) );
5102 return name == logicalName;
5106 countMatchingConnectors( aPage.
globals );
5107 countMatchingConnectors( aPage.
offpage );
5108 countMatchingConnectors( aPage.
ports );
5110 int64_t bestDistanceSquared = matchingConnectors > 1 ? MAX_PIN_SNAP_DISTANCE * MAX_PIN_SNAP_DISTANCE + 1
5111 : std::numeric_limits<int64_t>::max();
5116 auto netIt = aPage.
netmap.find( wire.
id );
5118 if( netIt == aPage.
netmap.end() )
5121 std::string wireName =
OrcadLower( trimmed( netIt->second ) );
5123 if( wireName != logicalName )
5128 int64_t dx = endpoint.x - candidate.
x;
5129 int64_t dy = endpoint.y - candidate.
y;
5130 int64_t distanceSquared = dx * dx + dy * dy;
5132 if( distanceSquared < bestDistanceSquared )
5134 bestDistanceSquared = distanceSquared;
5147 constexpr int MAX_PIN_SNAP_DISTANCE = 20;
5148 int64_t bestDistanceSquared = MAX_PIN_SNAP_DISTANCE * MAX_PIN_SNAP_DISTANCE + 1;
5150 std::string powerName = trimmed( aInst.
logicalName );
5152 if( powerName.empty() )
5154 auto property = aInst.
props.find(
"Name" );
5156 if( property != aInst.
props.end() )
5157 powerName = trimmed( property->second );
5164 if(
pin.IsNoConnect() ||
pin.wordA != std::numeric_limits<uint32_t>::max() || !
pin.wordB )
5168 auto pageName = aPage.
netmap.find(
pin.wordB );
5170 if( pageName != aPage.
netmap.end() && !trimmed( pageName->second ).empty() )
5171 pinNetNames.insert( trimmed( pageName->second ) );
5173 if( !powerName.empty() && !pinNetNames.empty()
5174 && std::none_of( pinNetNames.begin(), pinNetNames.end(),
5175 [&](
const std::string& aName )
5177 return OrcadIEquals( aName, powerName );
5183 int64_t dx =
pin.x - sourceAnchor.
x;
5184 int64_t dy =
pin.y - sourceAnchor.
y;
5185 int64_t distanceSquared = dx * dx + dy * dy;
5187 if( distanceSquared < bestDistanceSquared )
5189 bestDistanceSquared = distanceSquared;
5195 if( bestDistanceSquared <= MAX_PIN_SNAP_DISTANCE * MAX_PIN_SNAP_DISTANCE )
5204 std::vector<int> offsets( aInstance.
pins.size() );
5208 if( ( !aLeft.
wordA && !aLeft.
wordB ) || ( !aRight.wordA && !aRight.wordB ) )
5211 return ( aLeft.
wordA && aLeft.
wordA == aRight.wordA ) || ( aLeft.
wordB && aLeft.
wordB == aRight.wordB );
5214 for(
size_t i = 0; i < aInstance.
pins.size(); ++i )
5219 for(
size_t j = 0; j < i; ++j )
5223 if( peer.
x !=
pin.x || peer.
y !=
pin.y )
5226 if( shareNet(
pin, peer ) )
5228 offsets[i] = offsets[j];
5233 nextOffset = std::max( nextOffset, offsets[j] + 1 );
5236 if( nextOffset >= 0 )
5237 offsets[i] = nextOffset;
5251 return VECTOR2I(
pin.x + transform.
a * offsets[aPinIndex],
pin.y + transform.
c * offsets[aPinIndex] );
5259 std::vector<OFFPAGE_NET> out;
5260 const auto& occurrenceNamesByPageNetId =
m_netIndex.occurrenceNamesByNetId;
5262 for(
size_t i = 0; i < aPage.
offpage.size(); ++i )
5268 entry.
index =
static_cast<int>( i );
5270 std::set<const std::string*> occurrenceNets;
5271 std::set<uint32_t> attachedNetIds;
5278 attachedNetIds.insert( wire.
id );
5279 auto occurrenceNames = occurrenceNamesByPageNetId.find( wire.
id );
5281 if( occurrenceNames != occurrenceNamesByPageNetId.end() && occurrenceNames->second.size() == 1 )
5282 occurrenceNets.insert( *occurrenceNames->second.begin() );
5287 if( occurrenceNets.empty() )
5289 if( matchingNetIds.size() == 1 )
5291 auto names = occurrenceNamesByPageNetId.find( *matchingNetIds.begin() );
5293 if( names != occurrenceNamesByPageNetId.end() && names->second.size() == 1 )
5294 occurrenceNets.insert( *names->second.begin() );
5298 if( occurrenceNets.size() == 1 )
5300 const std::string& occurrenceName = **occurrenceNets.begin();
5301 std::optional<uint32_t> objectId = occurrenceNetObjectId( occurrenceName );
5302 bool instanceName = objectId
5306 return instance.dbId == *objectId;
5308 && std::none_of( aPage.
wires.begin(), aPage.
wires.end(),
5311 return wire.dbId == *objectId;
5313 bool declaredNet = attachedNetIds.size() == 1 && matchingNetIds.count( *attachedNetIds.begin() );
5314 bool declaredOccurrence =
m_scope.occ
5315 && std::any_of(
m_scope.occ->netNames.begin(),
m_scope.occ->netNames.end(),
5316 [&](
const auto& occurrence )
5318 return OrcadIEquals( occurrence.second, conn.logicalName );
5335 out.push_back( entry );
5344 std::set<std::pair<int, int>> pinPts;
5349 pinPts.insert( {
pin.x,
pin.y } );
5355 pinPts.insert( {
pin.x,
pin.y } );
5358 std::map<std::pair<int, int>,
int> ends;
5362 ends[{ wire.
x1, wire.
y1 }]++;
5363 ends[{ wire.
x2, wire.
y2 }]++;
5366 std::set<std::pair<int, int>>
candidates = pinPts;
5367 std::set<std::pair<int, int>> interiorCrossings;
5369 for(
const std::pair<
const std::pair<int, int>,
int>&
end : ends )
5372 for(
size_t firstIndex = 0; firstIndex < aPage.
wires.size(); ++firstIndex )
5379 for(
size_t secondIndex = firstIndex + 1; secondIndex < aPage.
wires.size(); ++secondIndex )
5383 if( second.
isBus || first.
id != second.
id )
5388 if( intersection &&
onSegment( intersection->x, intersection->y, first )
5389 &&
onSegment( intersection->x, intersection->y, second ) )
5391 interiorCrossings.insert( { intersection->x, intersection->y } );
5392 candidates.insert( { intersection->x, intersection->y } );
5397 std::vector<VECTOR2I> out;
5399 for(
const std::pair<int, int>& pt :
candidates )
5401 auto endIt = ends.find( pt );
5402 int endCount = endIt != ends.end() ? endIt->second : 0;
5404 std::set<uint32_t> netIds;
5408 if(
onSegment( pt.first, pt.second, wire ) )
5411 netIds.insert( wire.
id );
5415 int pinCount = pinPts.count( pt ) ? 1 : 0;
5416 int score = endCount + 2 * through + pinCount;
5419 bool interiorCrossing = interiorCrossings.count( pt ) != 0;
5421 if( netIds.size() <= 1 && score >= 3 && ( endCount + pinCount >= 1 || interiorCrossing )
5422 && endCount + through >= 2 )
5424 out.emplace_back( pt.first, pt.second );
5441 bool aBus =
false, uint32_t* aNetId =
nullptr )
5443 std::map<uint32_t, std::vector<SEG>> incidentNets;
5444 std::set<uint32_t> matchingNets;
5453 auto matchesName = [&](
const std::string& aName )
5455 return std::any_of( aNames.begin(), aNames.end(),
5456 [&](
const std::string& aCandidate )
5458 return !aCandidate.empty() && OrcadIEquals( aName, aCandidate );
5463 if( std::any_of( names.begin(), names.end(), matchesName ) )
5464 matchingNets.insert( wire.
id );
5467 if( matchingNets.size() == 1 || ( matchingNets.empty() && incidentNets.size() == 1 ) )
5469 uint32_t netId = matchingNets.empty() ? incidentNets.begin()->first : *matchingNets.begin();
5474 return incidentNets.at( netId );
5477 if( incidentNets.empty() )
5478 return std::vector<SEG>();
5480 return std::nullopt;
5485 bool aNestedHierarchy,
bool aSharedFolderPage )
5487 bool sharedFlatFolder = aSharedFolderPage && !
m_scope.namedFlatNets && !
m_scope.generatedFlatNets;
5488 std::map<uint32_t, const std::string*> generatedNamesByObjectId;
5489 std::map<uint32_t, const std::string*> occurrenceNamesByNetId;
5490 std::set<uint32_t> localizedOwnedOccurrenceNetIds;
5491 std::map<uint32_t, std::string> connectorNamesByObjectId;
5492 std::set<uint32_t> globalConnectorObjectIds;
5493 std::map<uint32_t, std::string> netNamesByObjectId;
5494 std::map<uint32_t, const std::string*> netNamesByWireObjectId;
5495 std::map<uint32_t, std::set<std::string>> blockPinNamesByNetId;
5496 std::map<std::pair<int, int>, std::set<std::string>> connectorNamesByPosition;
5497 std::set<std::pair<int, int>> globalConnectorPositions;
5498 std::vector<size_t> wireParents( aPage.
wires.size() );
5499 std::map<size_t, std::set<std::string>> powerAliasesByWireGroup;
5500 std::map<size_t, std::set<std::string>> powerGlobalNamesByWireGroup;
5501 std::map<size_t, std::set<std::string>> resolvedPowerNamesByWireGroup;
5502 std::map<uint32_t, std::set<std::string>> resolvedPowerNamesByNetId;
5503 std::map<uint32_t, std::string> flattenedNamesByNetId;
5504 std::set<uint32_t> renamedNetIds;
5505 std::set<std::string> occurrenceNames;
5506 std::map<const std::string*, std::string> occurrenceElectricalNames;
5507 const std::map<std::string, std::string>* hierBusNames =
nullptr;
5508 std::iota( wireParents.begin(), wireParents.end(), 0 );
5512 for(
const auto& [occurrenceId,
name] :
m_scope.occ->netNames )
5516 auto occurrenceElectricalName = [&](
const std::string* aName ) ->
const std::string&
5518 return occurrenceElectricalNames.at( aName );
5521 auto wireRoot = [&](
size_t aIndex )
5523 while( wireParents[aIndex] != aIndex )
5525 wireParents[aIndex] = wireParents[wireParents[aIndex]];
5526 aIndex = wireParents[aIndex];
5532 auto joinWires = [&](
size_t aLeft,
size_t aRight )
5534 size_t left = wireRoot( aLeft );
5535 size_t right = wireRoot( aRight );
5543 return ( aPoint.
x == aWire.x1 && aPoint.
y == aWire.y1 ) || ( aPoint.
x == aWire.x2 && aPoint.
y == aWire.y2 )
5547 std::map<uint32_t, std::vector<size_t>> powerWireIndicesByNetId;
5549 for(
size_t i = 0; i < aPage.
wires.size(); ++i )
5551 if( !aPage.
wires[i].isBus )
5552 powerWireIndicesByNetId[aPage.
wires[i].id].push_back( i );
5555 const std::vector<VECTOR2I>& junctions =
m_netIndex.junctions;
5557 for(
const auto& [netId, indices] : powerWireIndicesByNetId )
5566 bool connected = pointOnWire(
VECTOR2I( leftWire.
x1, leftWire.
y1 ), rightWire )
5567 || pointOnWire(
VECTOR2I( leftWire.
x2, leftWire.
y2 ), rightWire )
5568 || pointOnWire(
VECTOR2I( rightWire.
x1, rightWire.
y1 ), leftWire )
5569 || pointOnWire(
VECTOR2I( rightWire.
x2, rightWire.
y2 ), leftWire );
5573 connected = std::any_of( junctions.begin(), junctions.end(),
5576 return pointOnWire( aJunction, leftWire )
5577 && pointOnWire( aJunction, rightWire );
5582 joinWires( indices[
left], indices[
right] );
5589 if( !net.
name.empty() )
5596 connectorNamesByObjectId[global.
dbId] =
name;
5597 globalConnectorObjectIds.insert( global.
dbId );
5599 connectorNamesByPosition[{ position.
x, position.
y }].insert(
name );
5600 globalConnectorPositions.insert( { position.
x, position.
y } );
5602 std::set<std::string> sourceNames;
5605 if( !logicalName.empty() )
5606 sourceNames.insert( logicalName );
5608 auto property = global.
props.find(
"Name" );
5610 if( property != global.
props.end() )
5614 if( !propertyName.empty() )
5615 sourceNames.insert( propertyName );
5620 for(
size_t wireIndex = 0; wireIndex < aPage.
wires.size(); ++wireIndex )
5623 bool endpoint = (
pin.x == wire.
x1 &&
pin.y == wire.
y1 ) || (
pin.x == wire.
x2 &&
pin.y == wire.
y2 );
5627 size_t root = wireRoot( wireIndex );
5628 powerAliasesByWireGroup[root].insert( sourceNames.begin(), sourceNames.end() );
5629 powerGlobalNamesByWireGroup[root].insert( sourceNames.begin(), sourceNames.end() );
5630 resolvedPowerNamesByWireGroup[root].insert(
name );
5631 resolvedPowerNamesByNetId[wire.
id].insert(
name );
5636 for(
const auto& [root, globalNames] : powerGlobalNamesByWireGroup )
5638 if( globalNames.size() < 2 )
5641 for(
size_t wireIndex = 0; wireIndex < aPage.
wires.size(); ++wireIndex )
5643 if( aPage.
wires[wireIndex].isBus || wireRoot( wireIndex ) != root )
5651 powerAliasesByWireGroup[root].insert( std::move(
name ) );
5660 connectorNamesByObjectId[offpage.
dbId] =
name;
5661 if( !aHierarchical )
5662 globalConnectorObjectIds.insert( offpage.
dbId );
5664 connectorNamesByPosition[{ position.
x, position.
y }].insert( std::move(
name ) );
5665 if( !aHierarchical )
5666 globalConnectorPositions.insert( { position.
x, position.
y } );
5672 connectorNamesByObjectId[port.
dbId] =
name;
5673 if( !aHierarchical )
5674 globalConnectorObjectIds.insert( port.
dbId );
5676 connectorNamesByPosition[{ position.
x, position.
y }].insert( std::move(
name ) );
5677 if( !aHierarchical )
5678 globalConnectorPositions.insert( { position.
x, position.
y } );
5690 connectorNamesByPosition[{
pin.x,
pin.y }].insert(
name );
5695 blockPinNamesByNetId[wire.
id].insert(
name );
5703 hierBusNames = &busNames->second;
5707 std::map<uint32_t, uint32_t> netIdByWireObjectId;
5708 std::map<uint32_t, std::set<const std::string*>> objectNamesByNetId;
5711 netIdByWireObjectId[wire.
dbId] = wire.
id;
5713 for(
const auto& [netId, localName] : aPage.
netmap )
5715 std::set<std::string> localNames =
pageNetNames( aPage, netId );
5717 std::set<const std::string*> ownedCandidates;
5718 bool localizedOwnedCandidate =
false;
5720 bool directOffpage = std::any_of(
5724 std::string connectorName = aConnector.logicalName.empty() ? aConnector.name
5725 : aConnector.logicalName;
5726 std::string connectorKey = OrcadLower( connectorName );
5727 return std::any_of( localNames.begin(), localNames.end(),
5728 [&]( const std::string& aName )
5730 return OrcadLower( aName ) == connectorKey;
5734 for(
const std::string& candidateLocalName : localNames )
5736 bool implicitGenerated = isImplicitGeneratedName( candidateLocalName );
5737 std::string localKey =
OrcadLower( candidateLocalName );
5739 for(
const auto& [occurrenceId, occurrenceName] :
m_scope.occ->netNames )
5741 std::string occurrenceKey =
OrcadLower( occurrenceName );
5742 bool occurrenceOwnedByNet =
false;
5744 if( std::optional<uint32_t> objectId = occurrenceNetObjectId( occurrenceName ) )
5746 occurrenceOwnedByNet = std::any_of(
5750 if( aInstance.dbId != *objectId )
5753 return std::any_of( aInstance.pins.begin(), aInstance.pins.end(),
5754 [&]( const ORCAD_PIN_INST& aPin )
5756 return pinNetIds( aPin ).count( netId ) > 0;
5761 if( occurrenceKey == localKey
5762 || ( !implicitGenerated
5764 && !
isPowerNetName( candidateLocalName ) && occurrenceKey.size() > localKey.size()
5765 && occurrenceKey[localKey.size()] ==
'_'
5766 && occurrenceKey.compare( 0, localKey.size(), localKey ) == 0 ) )
5770 if( occurrenceOwnedByNet && !directOffpage )
5772 ownedCandidates.insert( &occurrenceName );
5773 localizedOwnedCandidate |= !sharedFlatFolder &&
isOffpageNetName( candidateLocalName );
5779 if( ownedCandidates.size() == 1 )
5781 occurrenceNamesByNetId[netId] = *ownedCandidates.begin();
5782 if( localizedOwnedCandidate )
5783 localizedOwnedOccurrenceNetIds.insert( netId );
5787 occurrenceNamesByNetId[netId] = *
candidates.begin();
5789 const std::string* selected = *
candidates.begin();
5790 std::string selectedKey =
OrcadLower( kicadOccurrenceNetName( *selected ) );
5792 std::any_of( localNames.begin(), localNames.end(),
5793 [&](
const std::string& aName )
5795 return isOffpageNetName( aName ) && OrcadLower( aName ) == selectedKey;
5797 bool competingSuffixedOccurrence = std::any_of(
5799 [&](
const auto& aOccurrence )
5801 std::string key = OrcadLower( kicadOccurrenceNetName( aOccurrence.second ) );
5802 return &aOccurrence.second != selected && key.size() > selectedKey.size()
5803 && key[selectedKey.size()] ==
'_'
5804 && key.compare( 0, selectedKey.size(), selectedKey ) == 0
5805 && occurrenceNetObjectId( aOccurrence.second ).has_value();
5808 if( localOffpage && !directOffpage && competingSuffixedOccurrence )
5810 std::optional<uint32_t> componentId;
5814 bool connected = std::any_of( instance.
pins.begin(), instance.
pins.end(),
5817 return pinNetIds( aPin ).count( netId ) > 0;
5820 if( connected && ( !componentId || instance.
dbId < *componentId ) )
5821 componentId = instance.
dbId;
5826 occurrenceElectricalNames[selected] = kicadOccurrenceNetName( *selected ) +
"_"
5827 + std::to_string( *componentId );
5829 if( !sharedFlatFolder )
5830 localizedOwnedOccurrenceNetIds.insert( netId );
5836 for(
const auto& [occurrenceId,
name] : m_scope.occ->netNames )
5838 occurrenceNames.insert(
name );
5840 if( std::optional<uint32_t> objectId = occurrenceNetObjectId(
name ) )
5842 auto netId = netIdByWireObjectId.find( *objectId );
5844 if( netId != netIdByWireObjectId.end() )
5845 objectNamesByNetId[netId->second].insert( &
name );
5848 if(
name.size() < 2 ||
name[0] !=
'N' )
5851 uint64_t objectId = 0;
5853 auto it =
name.begin() + 1;
5855 for( ; it !=
name.end() && std::isdigit(
static_cast<unsigned char>( *it ) ); ++it )
5857 objectId = objectId * 10 +
static_cast<unsigned>( *it -
'0' );
5860 if( objectId && objectId <= std::numeric_limits<uint32_t>::max() && ( it ==
name.end() || *it ==
'_' ) )
5862 generatedNamesByObjectId[
static_cast<uint32_t
>( objectId )] = &
name;
5866 for(
const auto& [netId, names] : objectNamesByNetId )
5868 if( names.size() == 1 )
5869 occurrenceNamesByNetId[netId] = *names.begin();
5872 for(
const auto& [netId, occurrenceName] : occurrenceNamesByNetId )
5874 std::string electricalName = occurrenceElectricalNames.at( occurrenceName );
5875 bool collides = std::any_of( aPage.netmap.begin(), aPage.netmap.end(),
5876 [&](
const auto& aPageNet )
5878 return aPageNet.first != netId
5879 && OrcadIEquals( kicadElectricalNetName( aPageNet.second ),
5886 std::optional<uint32_t> occurrenceId = occurrenceNetIdFor( occurrenceName );
5891 std::string suffix = std::to_string( *occurrenceId );
5893 if( suffix.size() < 6 )
5894 suffix.insert( 0, 6 - suffix.size(),
'0' );
5896 occurrenceElectricalNames[occurrenceName] +=
"_" + suffix;
5900 std::map<uint32_t, const std::string*> netNamesById;
5901 std::map<uint32_t, std::vector<size_t>> wiresByNetId;
5902 std::set<uint32_t> ambiguousNetIds;
5904 for(
const auto& [netId,
name] : aPage.netmap )
5906 auto aliases = aPage.netAliases.find( netId );
5907 std::set<std::string> distinctNames;
5909 if( aliases != aPage.netAliases.end() )
5911 for(
const std::string& alias : aliases->second )
5913 if( !alias.empty() )
5914 distinctNames.insert( alias );
5918 if( distinctNames.size() > 1 )
5920 ambiguousNetIds.insert( netId );
5922 if( isPowerNetName(
name ) )
5923 netNamesById[netId] = &
name;
5928 bool explicitAlias =
5929 aliases != aPage.netAliases.end()
5930 && std::find( aliases->second.begin(), aliases->second.end(),
name ) != aliases->second.end();
5932 if( !
name.empty() && ( !isImplicitGeneratedName(
name ) || explicitAlias ) )
5933 netNamesById[netId] = &
name;
5936 for(
const auto& [netId,
name] : occurrenceNamesByNetId )
5938 netNamesById[netId] =
name;
5939 m_sourceNetNames[{ aScreen, netId }].insert( *
name );
5942 std::set<uint32_t> explicitlyAliasedNets;
5947 explicitlyAliasedNets.insert( wire.
id );
5951 std::map<uint32_t, std::string> generatedSourceNames = aPage.netmap;
5953 for(
const auto& [netId,
name] : occurrenceNamesByNetId )
5954 generatedSourceNames.try_emplace( netId, kicadOccurrenceNetName( *
name ) );
5956 for(
const auto& [netId, sourceName] : generatedSourceNames )
5958 bool occurrenceOnly = !aPage.netmap.count( netId );
5959 std::string generatedBase = occurrenceOnly ? sourceName.substr( 0, sourceName.find(
'_' ) ) : sourceName;
5961 if( !isImplicitGeneratedName( generatedBase ) )
5964 auto aliases = aPage.netAliases.find( netId );
5967 if( explicitlyAliasedNets.count( netId )
5968 || ( aliases != aPage.netAliases.end()
5969 && std::any_of( aliases->second.begin(), aliases->second.end(),
5970 [&](
const std::string& alias )
5972 return !alias.empty() && alias != sourceName;
5976 auto occurrence = occurrenceNamesByNetId.find( netId );
5977 std::string
name = occurrence != occurrenceNamesByNetId.end()
5978 ? kicadOccurrenceNetName( *occurrence->second ) : sourceName;
5980 if( m_scope.generatedFlatNets && isImplicitGeneratedName(
name ) )
5984 std::optional<uint32_t> occurrenceId;
5986 if( occurrence != occurrenceNamesByNetId.end() )
5987 occurrenceId = occurrenceNetIdFor( occurrence->second );
5991 name +=
"_" + std::to_string( *occurrenceId );
5995 if( m_scope.flatNetSuffix.empty() )
5998 std::string suffix = m_scope.flatNetSuffix;
5999 std::transform( suffix.begin(), suffix.end(), suffix.begin(),
6000 [](
unsigned char c )
6002 return static_cast<char>( std::toupper( c ) );
6004 name +=
"_" + suffix;
6008 if( ( isImplicitGeneratedName(
name ) ||
name.starts_with( generatedBase +
"_" ) )
6009 && !isPowerNetName(
name ) && !isOffpageNetName(
name ) )
6011 m_sourceNetNames[{ aScreen, netId }].insert(
name );
6012 m_sourceGeneratedNetNames[{ aScreen, netId }] = std::move(
name );
6016 for(
const auto& [netId, occurrenceName] : occurrenceNamesByNetId )
6018 std::string occurrenceKey =
OrcadLower( kicadOccurrenceNetName( *occurrenceName ) );
6019 auto occurrenceDepth = m_occurrenceNetNameMinDepth.find( occurrenceKey );
6021 if( occurrenceDepth == m_occurrenceNetNameMinDepth.end() )
6024 std::map<size_t, std::set<std::string>> candidatesByDepth;
6025 std::set<std::string> sourceNames;
6028 sourceNames.insert( canonicalGlobalNetName(
name ) );
6030 for(
const std::string& sourceName : sourceNames )
6032 std::string sourceKey =
OrcadLower( sourceName );
6033 auto sourceDepth = m_occurrenceNetNameMinDepth.find( sourceKey );
6035 if( sourceDepth != m_occurrenceNetNameMinDepth.end() && sourceDepth->second < occurrenceDepth->second )
6036 candidatesByDepth[sourceDepth->second].insert( sourceName );
6039 if( !candidatesByDepth.empty() && candidatesByDepth.begin()->second.size() == 1 )
6041 std::string& flattened = flattenedNamesByNetId[netId];
6042 flattened = *candidatesByDepth.begin()->second.begin();
6043 netNamesById[netId] = &flattened;
6044 renamedNetIds.insert( netId );
6048 std::map<std::string, std::set<uint32_t>> blockNetIdsByName;
6050 for(
const auto& [netId,
name] : aPage.netmap )
6052 if( !
name.empty() && !isImplicitGeneratedName(
name ) )
6053 blockNetIdsByName[canonicalGlobalNetName(
name )].insert( netId );
6056 for(
const auto& [netId, names] : blockPinNamesByNetId )
6058 if( !names.empty() )
6059 blockNetIdsByName[*names.begin()].insert( netId );
6062 std::map<uint32_t, std::string> blockElectricalNames;
6063 std::set<uint32_t> blockElectricalNetIds;
6065 for(
const auto& [netId, names] : blockPinNamesByNetId )
6067 auto currentName = netNamesById.find( netId );
6069 if( !names.empty() && ( currentName == netNamesById.end() || isImplicitGeneratedName( *currentName->second ) ) )
6071 std::string
name = *names.begin();
6073 if( blockNetIdsByName.at(
name ).size() > 1 )
6075 std::string suffix = std::to_string( netId );
6077 if( suffix.size() < 6 )
6078 suffix.insert( 0, 6 - suffix.size(),
'0' );
6080 name +=
"_" + suffix;
6083 auto inserted = blockElectricalNames.emplace( netId, std::move(
name ) ).first;
6084 netNamesById[netId] = &inserted->second;
6085 blockElectricalNetIds.insert( netId );
6089 if( !m_scope.unconnectedInterfaceNetNames.empty() )
6096 auto targetName = m_scope.unconnectedInterfaceNetNames.find( key );
6098 if( targetName == m_scope.unconnectedInterfaceNetNames.end() )
6105 if( wire.
isBus || !pointOnWire(
pin, wire ) )
6108 std::string& flattened = flattenedNamesByNetId[wire.
id];
6109 flattened = targetName->second;
6110 netNamesById[wire.
id] = &flattened;
6111 renamedNetIds.insert( wire.
id );
6118 auto name = netNamesById.find( wire.
id );
6120 if(
name != netNamesById.end() )
6121 netNamesByWireObjectId[wire.
dbId] =
name->second;
6124 std::set<std::string> interfaceNames;
6125 std::set<uint32_t> interfaceNetIds;
6126 std::map<uint32_t, std::set<std::string>> globalInterfaceNamesByNetId;
6128 auto addInterfacePoint = [&](
const VECTOR2I& aPin,
const std::string* aGlobalName,
6129 std::optional<uint32_t> aNetId )
6133 bool endpoint = ( aPin.
x == wire.
x1 && aPin.
y == wire.
y1 ) || ( aPin.
x == wire.
x2 && aPin.
y == wire.
y2 );
6135 if( !wire.
isBus && ( !aNetId || wire.
id == *aNetId )
6136 && ( endpoint || onSegment( aPin.
x, aPin.
y, wire ) ) )
6138 interfaceNetIds.insert( wire.
id );
6140 if( aGlobalName && !aGlobalName->empty() )
6141 globalInterfaceNamesByNetId[wire.
id].insert( *aGlobalName );
6146 auto addInterfaceName = [&](
const ORCAD_GRAPHIC_INST& aInstance,
bool aGlobal,
bool aPower )
6151 name = powerNet( aPage, aInstance );
6153 name = effectiveInterfaceNetName(
name );
6156 interfaceNames.insert(
name );
6158 VECTOR2I pin = aPower ? powerPinPos( aPage, aInstance ) : namedGraphicPinPos( aPage, aInstance );
6159 std::optional<uint32_t> sourceNetId;
6170 THROW_IO_ERROR( wxString::Format(
_(
"Page '%s': cannot determine the source net for interface '%s' "
6175 if( sourceWires->empty() || bus )
6178 sourceNetId = netId;
6181 addInterfacePoint(
pin, aGlobal ? &
name :
nullptr, sourceNetId );
6185 addInterfaceName( port,
false,
false );
6188 addInterfaceName( connector, !aHierarchical,
false );
6191 addInterfaceName( global,
true,
true );
6193 for(
const auto& [netId,
name] : occurrenceNamesByNetId )
6195 auto selectedName = netNamesById.find( netId );
6197 if( selectedName == netNamesById.end() || selectedName->second !=
name )
6200 std::string sourceName =
OrcadLower( kicadOccurrenceNetName( *
name ) );
6202 if( !sharedFlatFolder && ( m_scope.namedFlatNets || m_scope.generatedFlatNets || aNestedHierarchy )
6203 && !m_scope.interfaceNetAliases.count( sourceName )
6204 && m_occurrenceNetNameScopeCounts[sourceName] > 1 )
6209 if( !aNestedHierarchy
6210 && ( localizedOwnedOccurrenceNetIds.count( netId )
6211 || !m_scope.connectorInterfaceNetAliases.count( sourceName ) ) )
6213 globalInterfaceNamesByNetId[netId].clear();
6214 globalInterfaceNamesByNetId[netId].insert( occurrenceElectricalName(
name ) );
6222 addInterfacePoint(
VECTOR2I(
pin.x,
pin.y ),
nullptr, std::nullopt );
6225 if( m_scope.namedFlatNets && !m_scope.flatNetSuffix.empty() )
6227 for(
const auto& [netId,
name] : aPage.netmap )
6229 if(
name.empty() || interfaceNetIds.count( netId ) || interfaceNames.count(
name )
6230 || isOffpageNetName(
name ) )
6233 auto selected = netNamesById.find( netId );
6235 if( selected == netNamesById.end() || *selected->second !=
name )
6238 std::string& flattened = flattenedNamesByNetId[netId];
6239 flattened =
name +
"_" + m_scope.flatNetSuffix;
6240 netNamesById[netId] = &flattened;
6241 renamedNetIds.insert( netId );
6245 for(
size_t i = 0; i < aPage.wires.size(); ++i )
6252 wiresByNetId[wire.
id].push_back( i );
6254 auto generatedName = generatedNamesByObjectId.find( wire.
dbId );
6256 if( generatedName != generatedNamesByObjectId.end() )
6258 if( m_scope.generatedFlatNets && !m_scope.flatNetSuffix.empty() && !interfaceNetIds.count( wire.
id ) )
6260 std::string& flattened = flattenedNamesByNetId[wire.
id];
6261 flattened = *generatedName->second +
"_" + m_scope.flatNetSuffix;
6262 netNamesById[wire.
id] = &flattened;
6263 renamedNetIds.insert( wire.
id );
6268 std::set<VECTOR2I> electricalContacts;
6272 electricalContacts.emplace( wire.
x1, wire.
y1 );
6273 electricalContacts.emplace( wire.
x2, wire.
y2 );
6279 electricalContacts.insert( placedPinElectricalPosition( instance,
index ) );
6282 for(
const auto* connectors : { &aPage.globals, &aPage.ports, &aPage.offpage } )
6285 electricalContacts.emplace( connector.
x, connector.
y );
6291 electricalContacts.emplace(
pin.x,
pin.y );
6294 std::map<int, std::vector<size_t>> horizontalWires;
6295 std::map<int, std::vector<size_t>> verticalWires;
6296 std::map<size_t, std::vector<VECTOR2I>> cutsByWire;
6298 for(
size_t i = 0; i < aPage.wires.size(); ++i )
6305 if( wire.
y1 == wire.
y2 )
6306 horizontalWires[wire.
y1].push_back( i );
6307 else if( wire.
x1 == wire.
x2 )
6308 verticalWires[wire.
x1].push_back( i );
6311 for(
const auto& [y, horizontalIndices] : horizontalWires )
6313 for(
size_t horizontalIndex : horizontalIndices )
6315 const ORCAD_WIRE& horizontal = aPage.wires[horizontalIndex];
6316 int minX = std::min( horizontal.
x1, horizontal.
x2 );
6317 int maxX = std::max( horizontal.
x1, horizontal.
x2 );
6319 for(
auto verticalIt = verticalWires.lower_bound( minX );
6320 verticalIt != verticalWires.end() && verticalIt->first <= maxX; ++verticalIt )
6322 for(
size_t verticalIndex : verticalIt->second )
6324 const ORCAD_WIRE& vertical = aPage.wires[verticalIndex];
6332 if( !electricalContacts.count(
VECTOR2I( vertical.
x1, y ) ) )
6336 size_t cutIndex = netNamesById.count( vertical.
id ) ? verticalIndex : horizontalIndex;
6338 if( netNamesById.count( aPage.wires[cutIndex].id ) )
6339 cutsByWire[cutIndex].emplace_back( vertical.
x1, y );
6349 if(
pin.wordA ||
pin.wordB )
6352 for(
size_t wireIndex = 0; wireIndex < aPage.wires.size(); ++wireIndex )
6354 const ORCAD_WIRE& wire = aPage.wires[wireIndex];
6356 if( !wire.
isBus && netNamesById.count( wire.
id ) && onSegment(
pin.x,
pin.y, wire ) )
6357 cutsByWire[wireIndex].emplace_back(
pin.x,
pin.y );
6362 std::set<size_t> labelWireIndices;
6364 for(
const auto& [netId, wireIndices] : wiresByNetId )
6366 if( !netNamesById.count( netId ) && globalInterfaceNamesByNetId[netId].size() != 1 )
6369 std::set<size_t> unseen( wireIndices.begin(), wireIndices.end() );
6371 while( !unseen.empty() )
6373 size_t representative = *unseen.begin();
6374 std::vector<size_t> pending = { representative };
6375 unseen.erase( representative );
6377 while( !pending.empty() )
6379 const ORCAD_WIRE& current = aPage.wires[pending.back()];
6382 for(
auto it = unseen.begin(); it != unseen.end(); )
6384 const ORCAD_WIRE& candidate = aPage.wires[*it];
6385 bool touches = onSegment( current.
x1, current.
y1, candidate )
6386 || onSegment( current.
x2, current.
y2, candidate )
6387 || onSegment( candidate.
x1, candidate.
y1, current )
6388 || onSegment( candidate.
x2, candidate.
y2, current );
6392 pending.push_back( *it );
6393 it = unseen.erase( it );
6402 labelWireIndices.insert( representative );
6406 for(
size_t wireIndex = 0; wireIndex < aPage.wires.size(); ++wireIndex )
6408 const ORCAD_WIRE& wire = aPage.wires[wireIndex];
6409 auto appendSegment = [&](
const VECTOR2I& aStart,
const VECTOR2I& aEnd,
int aLayer )
6411 if( aStart == aEnd )
6419 appendPageItem( aScreen, line );
6422 m_sourceNetItems[{ aScreen, wire.
id }].push_back( line );
6425 std::vector<VECTOR2I> cuts = cutsByWire[wireIndex];
6427 int64_t dx =
static_cast<int64_t
>( wire.
x2 ) - wire.
x1;
6428 int64_t dy =
static_cast<int64_t
>( wire.
y2 ) - wire.
y1;
6430 std::sort( cuts.begin(), cuts.end(),
6433 int64_t ta = ( static_cast<int64_t>( a.x ) - wire.x1 ) * dx
6434 + ( static_cast<int64_t>( a.y ) - wire.y1 ) * dy;
6435 int64_t tb = ( static_cast<int64_t>( b.x ) - wire.x1 ) * dx
6436 + ( static_cast<int64_t>( b.y ) - wire.y1 ) * dy;
6439 cuts.erase( std::unique( cuts.begin(), cuts.end() ), cuts.end() );
6441 VECTOR2I step( dx == 0 ? 0 : ( dx > 0 ? 1 : -1 ), dy == 0 ? 0 : ( dy > 0 ? 1 : -1 ) );
6444 auto netName = netNamesById.find( wire.
id );
6448 return VECTOR2I( aStart.
x + ( aEnd.x - aStart.
x ) / 2, aStart.
y + ( aEnd.y - aStart.
y ) / 2 );
6450 auto wireIntentPosition = [&](
const VECTOR2I& aStart,
const VECTOR2I& aEnd )
6452 VECTOR2I midpoint = segmentMidpoint( aStart, aEnd );
6453 VECTOR2I direction( aEnd.x == aStart.
x ? 0 : ( aEnd.x > aStart.
x ? 1 : -1 ),
6454 aEnd.y == aStart.
y ? 0 : ( aEnd.y > aStart.
y ? 1 : -1 ) );
6455 std::vector<VECTOR2I>
candidates = { midpoint, aStart + direction, aEnd - direction };
6457 for(
int numerator : { 1, 3, 2, 6 } )
6459 constexpr int denominator = 8;
6460 candidates.emplace_back( aStart.
x + ( aEnd.x - aStart.
x ) * numerator / denominator,
6461 aStart.
y + ( aEnd.y - aStart.
y ) * numerator / denominator );
6466 if( candidate == aStart || candidate == aEnd || !onSegment( candidate.x, candidate.y, wire ) )
6469 bool crossesAnotherNet =
6470 std::any_of( aPage.wires.begin(), aPage.wires.end(),
6473 return &aOther != &wire
6474 && ( aOther.isBus != wire.isBus || aOther.id != wire.id )
6475 && onSegment( candidate.x, candidate.y, aOther );
6478 if( !crossesAnotherNet )
6484 auto appendWireNetIntents = [&](
const VECTOR2I& aPosition )
6486 std::set<std::string> names;
6487 size_t wireGroup = wireRoot( wireIndex );
6488 bool ambiguousPhysicalNet = ambiguousNetIds.count( wire.
id );
6489 auto resolvedPower = resolvedPowerNamesByWireGroup.find( wireGroup );
6491 if( ambiguousPhysicalNet && resolvedPower != resolvedPowerNamesByWireGroup.end() )
6492 names.insert( resolvedPower->second.begin(), resolvedPower->second.end() );
6493 else if( ambiguousPhysicalNet )
6495 auto netPower = resolvedPowerNamesByNetId.find( wire.
id );
6497 if( netPower != resolvedPowerNamesByNetId.end() && netPower->second.size() == 1 )
6498 names.insert( *netPower->second.begin() );
6501 auto aliases = aPage.netAliases.find( wire.
id );
6503 if( aliases != aPage.netAliases.end() && !ambiguousPhysicalNet && !occurrenceNamesByNetId.count( wire.
id ) )
6505 for(
const std::string& alias : aliases->second )
6506 names.insert( alias );
6509 auto powerAliases = powerAliasesByWireGroup.find( wireGroup );
6511 bool joinedPowerAliases = !ambiguousPhysicalNet && powerAliases != powerAliasesByWireGroup.end()
6512 && powerAliases->second.size() > 1
6513 && powerGlobalNamesByWireGroup[wireGroup].size() > 1;
6515 if( joinedPowerAliases )
6516 names.insert( powerAliases->second.begin(), powerAliases->second.end() );
6518 if( ambiguousPhysicalNet && occurrenceNamesByNetId.count( wire.
id ) )
6520 names.insert( *occurrenceNamesByNetId.at( wire.
id ) );
6522 else if( !ambiguousPhysicalNet && netName != netNamesById.end() )
6524 std::string key =
OrcadLower( *netName->second );
6526 if( !m_scope.connectorInterfaceNetAliases.count( key ) )
6527 names.insert( *netName->second );
6530 if( !ambiguousPhysicalNet )
6531 names.insert( globalInterfaceNamesByNetId[wire.
id].begin(), globalInterfaceNamesByNetId[wire.
id].end() );
6532 else if( globalInterfaceNamesByNetId[wire.
id].size() == 1 )
6533 names.insert( *globalInterfaceNamesByNetId[wire.
id].begin() );
6537 std::vector<std::string> sourceNames( names.begin(), names.end() );
6539 for(
const std::string&
name : sourceNames )
6543 for(
const std::string&
name : names )
6548 bool occurrenceName = occurrenceNamesByNetId.count( wire.
id )
6549 &&
name == *occurrenceNamesByNetId.at( wire.
id );
6551 occurrenceName ? occurrenceElectricalName( occurrenceNamesByNetId.at( wire.
id ) )
6552 : kicadElectricalNetName(
name ) );
6555 auto sourceName = aPage.netmap.find( wire.
id );
6556 bool generated = isImplicitGeneratedName(
name )
6557 || ( sourceName != aPage.netmap.end() && isImplicitGeneratedName( sourceName->second )
6558 &&
name.starts_with( sourceName->second +
"_" ) );
6559 bool explicitName = ( !generated && sourceName != aPage.netmap.end()
6560 && canonicalGlobalNetName( sourceName->second ) ==
name )
6564 return alias.name == name;
6566 appendNetIntent( aScreen, label, explicitName, wire.
id );
6575 if( !onSegment( before.
x, before.
y, wire ) )
6578 if( !onSegment( after.
x, after.
y, wire ) )
6584 appendWireNetIntents( wireIntentPosition(
cursor, before ) );
6594 appendWireNetIntents( wireIntentPosition(
cursor,
end ) );
6599 std::string electricalName = kicadElectricalNetName( trimmed( alias.
name ) );
6600 std::string mappedName = electricalName;
6608 bool mappedBusAlias = mappedName != electricalName;
6611 if(
text.IsEmpty() )
6617 int fontId = wireAliasFontId( alias );
6618 bool electrical = !( ambiguousNetIds.count( wire.
id ) && netName != netNamesById.end()
6619 && isPowerNetName( *netName->second )
6620 && canonicalGlobalNetName( alias.
name ) != *netName->second );
6622 if( !mappedBusAlias && occurrenceNamesByNetId.count( wire.
id ) && netName != netNamesById.end()
6623 && canonicalGlobalNetName( alias.
name ) != canonicalGlobalNetName( *netName->second ) )
6630 && std::any_of( aPage.wires.begin(), aPage.wires.end(),
6633 return !aOther.isBus && aOther.id != wire.id
6634 && anchor != VECTOR2I( aOther.x1, aOther.y1 )
6635 && anchor != VECTOR2I( aOther.x2, aOther.y2 )
6636 && onSegment( anchor.x, anchor.y, aOther );
6639 if( interiorCrossing && std::find( cuts.begin(), cuts.end(),
anchor ) != cuts.end() )
6643 if( candidate ==
anchor || !onSegment( candidate.
x, candidate.
y, wire ) )
6644 candidate =
anchor + step;
6646 electricalAnchor = candidate;
6649 if( electrical && ( ( electricalText !=
text && !mappedBusAlias ) || electricalAnchor !=
anchor ) )
6653 appendNetIntent( aScreen, label,
true, wire.
id );
6662 applyFont( label, fontId );
6664 appendPageItem( aScreen, label );
6665 m_labelSourceNets.push_back( { label, { aScreen, wire.
id } } );
6674 applyFont( note, fontId );
6676 appendPageItem( aScreen, note );
6680 size_t wireGroup = wireRoot( wireIndex );
6681 bool hasPowerAliases = powerAliasesByWireGroup.count( wireGroup )
6682 && powerAliasesByWireGroup.at( wireGroup ).size() > 1
6683 && powerGlobalNamesByWireGroup[wireGroup].size() > 1;
6685 bool authoritativeInterface = globalInterfaceNamesByNetId[wire.
id].size() == 1;
6688 && ( hasPowerAliases
6689 || ( labelWireIndices.count( wireIndex )
6690 && ( netName != netNamesById.end() || authoritativeInterface ) ) ) )
6692 appendWireNetIntents( wireIntentPosition(
VECTOR2I( wire.
x1, wire.
y1 ),
end ) );
6699 return std::any_of( aPage.wires.begin(), aPage.wires.end(),
6702 return ( aPin.x == aWire.x1 && aPin.y == aWire.y1 )
6703 || ( aPin.x == aWire.x2 && aPin.y == aWire.y2 )
6704 || onSegment( aPin.x, aPin.y, aWire );
6708 m_currentImplicitPowerPins.clear();
6709 std::map<std::pair<int, int>, std::string> generatedWirelessNets;
6713 for(
size_t pinIndex = 0; pinIndex < instance.
pins.size(); ++pinIndex )
6716 VECTOR2I electricalPosition = placedPinElectricalPosition( instance, pinIndex );
6718 if( (
pin.wordA ||
pin.wordB )
6719 && ( electricalPosition !=
VECTOR2I(
pin.x,
pin.y ) || !pinTouchesWire(
pin ) ) )
6721 std::string generatedName = generatedPinNetName( instance.
dbId, pinIndex );
6723 if( occurrenceNames.count( generatedName ) )
6724 generatedWirelessNets[{ electricalPosition.
x, electricalPosition.
y }] = std::move( generatedName );
6733 for(
size_t pinIndex = 0; pinIndex < instance.
pins.size(); ++pinIndex )
6736 VECTOR2I electricalPosition = placedPinElectricalPosition( instance, pinIndex );
6738 if( !
pin.wordA && !
pin.wordB )
6741 std::string generatedName = generatedPinNetName( instance.
dbId, pinIndex );
6743 bool globalName =
false;
6748 if( occurrenceNames.count( generatedName ) )
6749 name = std::move( generatedName );
6750 else if( generatedWirelessNets.count( { electricalPosition.x, electricalPosition.y } ) )
6751 name = generatedWirelessNets.at( { electricalPosition.
x, electricalPosition.
y } );
6752 else if(
pin.wordA && netNamesByWireObjectId.count(
pin.wordA ) )
6753 name = *netNamesByWireObjectId.at(
pin.wordA );
6754 else if(
pin.wordA && netNamesByObjectId.count(
pin.wordA ) )
6755 name = netNamesByObjectId.at(
pin.wordA );
6756 else if(
pin.wordA && connectorNamesByObjectId.count(
pin.wordA ) )
6758 name = connectorNamesByObjectId.at(
pin.wordA );
6759 globalName = globalConnectorObjectIds.count(
pin.wordA );
6761 else if(
pin.wordB )
6763 auto occurrenceName = occurrenceNamesByNetId.find(
pin.wordB );
6764 auto pageName = aPage.netmap.find(
pin.wordB );
6766 if( occurrenceName != occurrenceNamesByNetId.end() )
6768 name = occurrenceElectricalName( occurrenceName->second );
6769 std::string sourceName = kicadOccurrenceNetName( *occurrenceName->second );
6771 globalName = !localizedOwnedOccurrenceNetIds.count(
pin.wordB )
6772 && ( sharedFlatFolder
6773 || !( m_scope.namedFlatNets || m_scope.generatedFlatNets || aNestedHierarchy )
6774 || m_scope.interfaceNetAliases.count( key )
6775 || m_occurrenceNetNameScopeCounts[key] == 1 );
6778 else if( !ambiguousNetIds.count(
pin.wordB ) && pageName != aPage.netmap.end() )
6779 name = pageName->second;
6782 if(
name.empty() && connectorNamesByPosition[{ pin.x, pin.y }].size() == 1 )
6784 name = *connectorNamesByPosition.at( {
pin.x,
pin.y } ).begin();
6785 globalName = globalConnectorPositions.count( {
pin.x,
pin.y } );
6788 bool stackedPeer = std::any_of( instance.
pins.begin(), instance.
pins.end(),
6791 return &aPeer != &pin && aPeer.x == pin.x && aPeer.y == pin.y;
6793 bool sameNetPeer = std::any_of( instance.
pins.begin(), instance.
pins.end(),
6796 return &aPeer != &pin && aPeer.x == pin.x && aPeer.y == pin.y
6797 && ( ( pin.wordA && pin.wordA == aPeer.wordA )
6798 || ( pin.wordB && pin.wordB == aPeer.wordB ) );
6801 if(
name.empty() && ( !stackedPeer || sameNetPeer ) && electricalPosition !=
VECTOR2I(
pin.x,
pin.y )
6802 && pinTouchesWire(
pin ) )
6809 auto sourceNet = generatedWirelessNets.find( {
pin.x,
pin.y } );
6811 if( sourceNet != generatedWirelessNets.end() )
6812 name = sourceNet->second;
6815 if(
name.empty() && !generatedWirelessNets.count( { electricalPosition.x, electricalPosition.y } )
6816 && definition &&
pin.pinIndex > 0 &&
static_cast<size_t>(
pin.pinIndex ) <= definition->
pins.size() )
6818 std::string sourceName = trimmed( definition->
pins[
pin.pinIndex - 1].name );
6820 if( occurrenceNames.count( sourceName ) )
6821 name = std::move( sourceName );
6827 std::string scopedName =
name;
6832 bool globalNet = scopedName ==
name
6833 && ( globalName ||
name.rfind(
"$$$", 0 ) == 0
6834 || ( !aHierarchical && isOffpageNetName(
name ) ) || isPowerNetName(
name ) );
6836 uint32_t sourceNetId =
pin.wordB;
6840 for(
const auto& [
id, occurrenceName] : m_scope.occ->netNames )
6842 if( kicadOccurrenceNetName( occurrenceName ) ==
name )
6850 m_wirelessNetNames[{ aScreen, &instance, pinIndex }] = { sourceNetId,
name };
6852 if( isImplicitGeneratedName(
name )
6853 && generatedWirelessNets.count( { electricalPosition.x, electricalPosition.y } ) )
6855 m_sourceGeneratedNetNames[{ aScreen, sourceNetId }] =
name;
6859 if( globalNet && !
pin.IsNoConnect() && !stackedPeer
6861 && hasImplicitPowerPinName( instance, pinIndex, scopedName ) )
6863 m_currentImplicitPowerPins.insert( &
pin );
6870 appendNetIntent( aScreen, label, !isImplicitGeneratedName(
name ) );
6872 if( scopedName !=
name )
6876 appendNetIntent( aScreen, scopedLabel, !isImplicitGeneratedName(
name ) );
6884 const std::string& aChildFolder )
6896 referenceDisplay = &display;
6898 referenceDisplay = &display;
6900 valueDisplay = &display;
6910 if( referenceDisplay )
6911 applyDisplay( *sheetName, *referenceDisplay );
6915 auto value = std::find_if( aBlock.
props.begin(), aBlock.
props.end(),
6916 [&](
const auto& aProperty )
6918 return OrcadIEquals( aProperty.first,
"Value" );
6920 std::string valueText;
6922 if( value != aBlock.
props.end() )
6923 valueText = value->second;
6925 if( valueText.empty() )
6928 if( valueText.empty() )
6929 valueText = aChildFolder;
6931 if( !valueText.empty() )
6935 applyDisplay( implementation, *valueDisplay );
6936 aSheet->
AddField( implementation );
6944 std::vector<VECTOR2I> points;
6947 if( points.empty() )
6953 for(
const VECTOR2I& point : points )
6978 const std::string& aText,
SCH_SCREEN* aScreen )
6983 int textRotation = aDisplay.
rotation & 3;
6984 bool vertical = ( textRotation & 1 ) != 0;
6985 int baseX = std::min( aGraphic.
bbox.
x1, aGraphic.
bbox.
x2 );
6986 int baseY = std::min( aGraphic.
bbox.
y1, aGraphic.
bbox.
y2 );
6991 switch( textRotation )
7007 text->SetTextColor( color );
7018 const std::set<std::string>& aNames,
7019 const std::string& aNet )
7024 if( !bus && sourceWires && sourceWires->empty() )
7032 const std::optional<std::vector<SEG>>& aSourceWires )
7035 return std::nullopt;
7037 std::vector<SEG> wires;
7038 std::set<VECTOR2I> junctions;
7039 std::set<VECTOR2I> busEntries;
7040 std::set<VECTOR2I> pins;
7049 wires.push_back( line->
GetSeg() );
7057 pins.insert(
pin->GetPosition() );
7062 pins.insert(
pin->GetPosition() );
7066 junctions.insert( item->GetPosition() );
7070 for(
const VECTOR2I& point : item->GetConnectionPoints() )
7071 busEntries.insert( point );
7078 if( busEntries.count( aCandidate ) )
7081 int contacts = std::count_if( wires.begin(), wires.end(),
7082 [&](
const SEG& wire )
7084 return wire.Contains( aCandidate );
7087 if( aSourceWires->empty() )
7090 return aCandidate == aPosition && contacts == 0
7091 && ( !junctions.count( aCandidate ) || pins.count( aCandidate ) );
7094 return !junctions.count( aCandidate ) && !pins.count( aCandidate ) && contacts <= 1;
7098 [&](
const SEG& aWire,
const VECTOR2I& aCandidate )
7100 return aWire.
Contains( aCandidate )
7101 && std::any_of( aSourceWires->begin(), aSourceWires->end(),
7102 [&](
const SEG& aSource )
7104 return aSource.A != aSource.B && aSource.Contains( aCandidate )
7105 && ( aSource.B - aSource.A ).Cross( aWire.B - aWire.A ) == 0;
7109 if( safe( aPosition )
7110 && ( aSourceWires->empty() || std::any_of( wires.begin(), wires.end(),
7111 [&](
const SEG& aWire )
7113 return supported( aWire, aPosition );
7121 for(
const SEG& wire : wires )
7124 if( !std::any_of( aSourceWires->begin(), aSourceWires->end(),
7125 [&](
const SEG& aSource )
7127 return aSource.A != aSource.B
7128 && ( aSource.B - aSource.A ).Cross( wire.B - wire.A ) == 0
7129 && ( aSource.Contains( wire.A ) || aSource.Contains( wire.B )
7130 || wire.Contains( aSource.A ) || wire.Contains( aSource.B ) );
7141 std::set<int> offsets = { 0, steps, steps / 2 };
7144 [&](
long double aOffset )
7146 if( aOffset < -2 || aOffset > steps + 2.0L )
7149 int offset =
static_cast<int>( std::floor( aOffset ) );
7151 for(
int adjacent = -1; adjacent <= 2; ++adjacent )
7153 if( offset + adjacent >= 0 && offset + adjacent <= steps )
7154 offsets.insert( offset + adjacent );
7159 [&](
const VECTOR2I& aPoint ) ->
long double
7161 return step.
x ? ( (
long double) aPoint.x - wire.A.x ) / step.
x
7162 : ( (
long double) aPoint.y - wire.A.y ) / step.
y;
7165 addOffset( projection( aPosition ) );
7166 long double inset =
schIUScale.MilsToIU( 50 ) / std::hypot( step.
x, step.
y );
7167 addOffset( projection( aPosition ) - inset );
7168 addOffset( projection( aPosition ) + inset );
7171 for(
const SEG& other : wires )
7173 addOffset( projection( other.A ) );
7174 addOffset( projection( other.B ) );
7175 VECTOR2I direction = other.B - other.A;
7176 long double denominator = (
long double) step.
x * direction.
y - (
long double) step.
y * direction.
x;
7178 if( denominator != 0 )
7180 long double x = (
long double) other.A.x - wire.A.x;
7181 long double y = (
long double) other.A.y - wire.A.y;
7182 addOffset( ( x * direction.
y - y * direction.
x ) / denominator );
7186 for(
const SEG&
source : *aSourceWires )
7188 addOffset( projection(
source.A ) );
7189 addOffset( projection(
source.B ) );
7192 for(
const VECTOR2I& junction : junctions )
7193 addOffset( projection( junction ) );
7195 for(
const VECTOR2I& entry : busEntries )
7196 addOffset( projection( entry ) );
7199 addOffset( projection(
pin ) );
7201 for(
int offset : offsets )
7203 VECTOR2I candidate = wire.A + step * offset;
7205 if( safe( candidate ) && supported( wire, candidate ) )
7211 return std::nullopt;
7216 int64_t left = ( aLeft - aPosition ).SquaredEuclideanNorm();
7217 int64_t right = ( aRight - aPosition ).SquaredEuclideanNorm();
7218 int64_t clearance = schIUScale.MilsToIU( 50 );
7219 bool leftClear = left >= clearance * clearance;
7220 bool rightClear = right >= clearance * clearance;
7222 return leftClear != rightClear ? leftClear : left < right;
7232 std::string net = offpage.net;
7239 if( renamed != busNames->second.end() )
7240 net = renamed->second;
7245 note( wxString::Format(
_(
"Page '%s': the off-page connector at (%d, %d) is "
7246 "unconnected in the source design; skipped." ),
7253 { connector.logicalName, offpage.net }, net );
7260 THROW_IO_ERROR( wxString::Format(
_(
"Page '%s': cannot place off-page connector '%s' at (%d, %d) "
7261 "without a wire intersection." ),
7263 offpage.x, offpage.y ) );
7274 const auto& parentPins = aSheetPath.
Last()->
GetPins();
7275 auto parentPin = std::find_if( parentPins.begin(), parentPins.end(),
7278 return aPin->GetText().CmpNoCase( label->GetText() ) == 0;
7281 if( aHierarchical && parentPin != parentPins.end() )
7284 parentLabel->
SetShape( ( *parentPin )->GetShape() );
7306 std::map<size_t, std::set<std::string>> occurrenceNamesByDepth;
7313 std::set<std::string> sourceNames;
7318 for(
const std::string& sourceName : sourceNames )
7324 occurrenceNamesByDepth[depth->second].insert( sourceName );
7328 if( !occurrenceNamesByDepth.empty() && occurrenceNamesByDepth.begin()->second.size() == 1 )
7329 net = *occurrenceNamesByDepth.begin()->second.begin();
7333 auto renamed = busNames->second.find( net );
7335 if( renamed != busNames->second.end() )
7336 net = renamed->second;
7349 THROW_IO_ERROR( wxString::Format(
_(
"Page '%s': cannot place port '%s' at (%d, %d) "
7350 "without a wire intersection." ),
7358 if( symbolName.Contains( wxS(
"LEFT" ) ) )
7360 else if( symbolName.Contains( wxS(
"RIGHT" ) ) )
7386 int64_t dx =
static_cast<int64_t
>( wire.
x1 ) + wire.
x2 - 2LL * aPosDbu.
x;
7387 int64_t dy =
static_cast<int64_t
>( wire.
y1 ) + wire.
y2 - 2LL * aPosDbu.
y;
7398 const std::vector<SEG>& aSourceWires,
7406 return aProp.name == aName;
7408 return it != aGraphic.
displayProps.end() ? &*it :
nullptr;
7416 refs->SetVisible(
false );
7421 auto storedIref = aGraphic.
props.find(
"IREF" );
7435 return displayedName;
7447 bool invisibleColor =
7451 auto placePrimitive = [&](
const ORCAD_PRIMITIVE& aSource,
int aOffsetX,
int aOffsetY )
7468 bool usedEmbeddedEmf =
false;
7469 placeBitmap( prim, aScreen, 0, &usedEmbeddedEmf );
7486 frame, frameColor,
true, false ) );
7495 std::string sourceFace;
7504 if( sourceFace ==
"greekc" )
7505 content.Replace( wxS(
"m" ), wxString::FromUTF8(
"µ" ) );
7506 else if( sourceFace ==
"commercialpi bt" )
7507 content.Replace( wxS(
"b" ), wxString::FromUTF8(
"®" ) );
7509 if( content.IsEmpty() )
7516 int size = scaledTextSize.
y;
7519 bool vertical = ( gfx.
rotation & 3 ) == 1;
7520 bool hasBox = prim.
x2 > prim.
x1 && prim.
y2 > prim.
y1 && !content.Contains(
'\n' );
7522 bool wrappedToSourceBounds =
false;
7527 int anchorX = hasSourceAnchor || vertical || !hasBox ? prim.
x1 : ( prim.
x1 + prim.
x2 ) / 2;
7528 int anchorY = hasSourceAnchor || !vertical || !hasBox ? prim.
y1 : ( prim.
y1 + prim.
y2 ) / 2;
7533 multilineText = sheetText;
7541 text->SetTextSize( scaledTextSize );
7544 if( sourceFace ==
"greekc" || sourceFace ==
"commercialpi bt" )
7547 auto sourceCellWidthDbu = [&]()
7554 if( sourceFace ==
"arial narrow" && sourceFont->
bold )
7556 sourceCellWidth = std::max( sourceCellWidth,
7560 return sourceCellWidth;
7563 if( hasBox && hasSourceAnchor && !vertical && !
text->GetText().Contains(
'\n' ) )
7565 int sourceWidthDbu = prim.
x2 - prim.
x1;
7566 int sourceHeightDbu = prim.
y2 - prim.
y1;
7567 int sourceCellWidth = sourceCellWidthDbu();
7569 if( sourceWidthDbu > 0 && sourceCellWidth > 0
7571 &&
static_cast<int>(
text->GetText().length() ) * sourceCellWidth > sourceWidthDbu )
7573 wxString original =
text->GetText();
7575 size_t maxCharacters = sourceWidthDbu / sourceCellWidth;
7576 size_t bestWidth = std::numeric_limits<size_t>::max();
7578 for(
size_t pos = original.find(
' ' ); pos != wxString::npos;
7579 pos = original.find(
' ', pos + 1 ) )
7581 wxString candidate = original.Left( pos ) + wxS(
"\n" ) + original.Mid( pos + 1 );
7582 size_t candidateWidth = std::max( pos, original.length() - pos - 1 );
7584 if( candidateWidth <= maxCharacters && candidateWidth < bestWidth )
7586 wrapped = candidate;
7587 bestWidth = candidateWidth;
7591 if( !wrapped.IsEmpty() )
7593 text->SetText( wrapped );
7594 wrappedToSourceBounds =
true;
7598 text->SetText( original );
7603 if( sourceFace ==
"elephant" )
7610 if( hasBox && hasSourceAnchor )
7612 int sourceLengthDbu = vertical ? prim.
y2 - prim.
y1 : prim.
x2 - prim.
x1;
7614 if( !wrappedToSourceBounds && !vertical &&
text->GetText().Contains(
'\n' )
7615 && sourceCellWidthDbu() > 0 )
7617 size_t maxCharacters = 0;
7618 wxStringTokenizer lines(
text->GetText(), wxS(
"\n" ), wxTOKEN_RET_EMPTY_ALL );
7620 while( lines.HasMoreTokens() )
7621 maxCharacters = std::max( maxCharacters, lines.GetNextToken().length() );
7623 sourceLengthDbu = std::min( sourceLengthDbu,
7624 static_cast<int>( maxCharacters ) * sourceCellWidthDbu() );
7628 int renderedLength =
text->GetTextBox(
nullptr ).GetWidth();
7630 if( sourceLength > 0 && renderedLength > 0 )
7632 scaledTextSize.
x =
KiROUND(
static_cast<double>( scaledTextSize.
x ) * sourceLength
7634 text->SetTextSize( scaledTextSize );
7641 text->SetTextColor( graphicColor );
7671 if( prim.
points.size() < 2 )
7674 std::vector<VECTOR2I> pts;
7680 pts.push_back( pts.front() );
7683 makeSheetPoly( pts, prim, graphicColor,
7691 if( prim.
points.size() < 4 || ( prim.
points.size() - 1 ) % 3 != 0 )
7693 if( prim.
points.size() >= 2 )
7695 std::vector<VECTOR2I> pts;
7701 makeSheetPoly( pts, prim, graphicColor,
false,
7708 for(
size_t i = 0; i + 3 < prim.
points.size(); i += 3 )
7733 double cx = ( prim.
x1 + prim.
x2 ) / 2.0;
7734 double cy = ( prim.
y1 + prim.
y2 ) / 2.0;
7745 double a1 = 2.0 *
M_PI;
7749 a0 = std::atan2( ( prim.
start->y - cy ) / ry, ( prim.
start->x - cx ) / rx );
7750 a1 = std::atan2( ( prim.
end->y - cy ) / ry, ( prim.
end->x - cx ) / rx );
7757 int steps = std::max( 8,
static_cast<int>(
std::abs( a1 - a0 ) / (
M_PI / 16.0 ) ) );
7759 std::vector<VECTOR2I> pts;
7761 for(
int k = 0; k <= steps; ++k )
7763 double a = a0 + ( a1 - a0 ) * k / steps;
7764 pts.push_back( dbuPointToIu( cx + rx * std::cos( a ), cy + ry * std::sin( a ) ) );
7768 makeSheetPoly( pts, prim, graphicColor,
7782 bool* aUsedEmbeddedEmf )
7784 if( aUsedEmbeddedEmf )
7785 *aUsedEmbeddedEmf =
false;
7790 if( widthDbu < 2 || heightDbu < 2 || aPrim.
data.empty() )
7793 wxMemoryBuffer bmpData;
7797 std::unique_ptr<SCH_BITMAP> bitmap = std::make_unique<SCH_BITMAP>(
center );
7800 bool readOk =
false;
7804 if( !ciImage.empty() )
7806 bmpData.AppendData( ciImage.data(), ciImage.size() );
7826 bmpData.AppendData( preview.
data.data(), preview.
data.size() );
7838 int maxWidth =
static_cast<int>( std::clamp<int64_t>(
static_cast<int64_t
>( widthDbu ) * 4, 1, 4096 ) );
7839 int maxHeight =
static_cast<int>( std::clamp<int64_t>(
static_cast<int64_t
>( heightDbu ) * 4, 1, 4096 ) );
7842 static_cast<double>( widthDbu ) / heightDbu, aUsedEmbeddedEmf ) )
7849 warn( wxString::Format(
_(
"An embedded picture could not be decoded and was skipped "
7858 widthDbu, heightDbu );
7860 if( stretchedSize.
x != sourceImage->GetWidth() || stretchedSize.
y != sourceImage->GetHeight() )
7862 wxImage stretched = sourceImage->Scale( stretchedSize.
x, stretchedSize.
y, wxIMAGE_QUALITY_HIGH );
7864 if( stretched.IsOk() )
7871 if( nativeSize.
x > 0 && nativeSize.
y > 0 )
7873 double scaleX =
static_cast<double>( widthDbu *
ORCAD_IU_PER_DBU ) / nativeSize.
x;
7874 double scaleY =
static_cast<double>( heightDbu *
ORCAD_IU_PER_DBU ) / nativeSize.
y;
7881 if( orientation.
mirror ==
'x' )
7882 bitmap->MirrorVertically(
center.y );
7883 else if( orientation.
mirror ==
'y' )
7884 bitmap->MirrorHorizontally(
center.x );
7886 for(
int angle = 0; angle < orientation.
angle; angle += 90 )
7887 bitmap->Rotate(
center,
true );
7895 if( aWire.
x1 == aWire.
x2 )
7897 return VECTOR2I( aWire.
x1, std::clamp( aY, std::min( aWire.
y1, aWire.
y2 ), std::max( aWire.
y1, aWire.
y2 ) ) );
7900 if( aWire.
y1 == aWire.
y2 )
7902 return VECTOR2I( std::clamp( aX, std::min( aWire.
x1, aWire.
x2 ), std::max( aWire.
x1, aWire.
x2 ) ), aWire.
y1 );
7906 double dx = aWire.
x2 - aWire.
x1;
7907 double dy = aWire.
y2 - aWire.
y1;
7908 double t = ( ( aX - aWire.
x1 ) * dx + ( aY - aWire.
y1 ) * dy ) / ( dx * dx + dy * dy );
7910 t = std::clamp( t, 0.0, 1.0 );
7918 if( ( aX == aWire.
x1 && aY == aWire.
y1 ) || ( aX == aWire.
x2 && aY == aWire.
y2 ) )
7921 if( aWire.
x1 == aWire.
x2 && aWire.
x1 == aX )
7922 return std::min( aWire.
y1, aWire.
y2 ) < aY && aY < std::max( aWire.
y1, aWire.
y2 );
7924 if( aWire.
y1 == aWire.
y2 && aWire.
y1 == aY )
7925 return std::min( aWire.
x1, aWire.
x2 ) < aX && aX < std::max( aWire.
x1, aWire.
x2 );
constexpr EDA_IU_SCALE schIUScale
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
constexpr coord_type GetLeft() const
constexpr coord_type GetRight() const
constexpr coord_type GetTop() const
constexpr coord_type GetBottom() const
Store all of the related component information found in a netlist.
Calculate the connectivity of a schematic and generate netlists.
const NET_MAP & GetNetMap() const
void Recalculate(const SCH_SHEET_LIST &aSheetList, bool aUnconditional=false, std::function< void(SCH_ITEM *)> *aChangedItemHandler=nullptr, PROGRESS_REPORTER *aProgressReporter=nullptr)
Update the connection graph for the given list of sheets.
CONNECTION_SUBGRAPH * GetSubgraphForItem(SCH_ITEM *aItem) const
A subgraph is a set of items that are electrically connected on a single sheet.
PRIORITY GetDriverPriority()
const std::set< SCH_ITEM * > & GetItems() const
Provide a read-only reference to the items in the subgraph.
const SCH_ITEM * GetDriver() const
const wxString & GetNameForDriver(SCH_ITEM *aItem) const
Return the candidate net name for a driver.
const SCH_SHEET_PATH & GetSheet() const
const SCH_CONNECTION * GetDriverConnection() const
KICAD_T Type() const
Returns the type of object.
virtual void SetEnd(const VECTOR2I &aEnd)
virtual void SetBezierC2(const VECTOR2I &aPt)
virtual void SetBezierC1(const VECTOR2I &aPt)
void SetFillColor(const COLOR4D &aColor)
void SetFillMode(FILL_T aFill)
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
virtual VECTOR2I GetTextSize() const
void SetTextColor(const COLOR4D &aColor)
COLOR4D GetTextColor() const
virtual void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true)
void SetVertJustify(GR_TEXT_V_ALIGN_T aType)
virtual void SetVisible(bool aVisible)
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
void SetMultilineAllowed(bool aAllow)
void SetFont(KIFONT::FONT *aFont)
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
EE_TYPE OfType(KICAD_T aType) const
static FONT * GetFont(const wxString &aFontName=wxEmptyString, bool aBold=false, bool aItalic=false, const std::vector< wxString > *aEmbeddedFiles=nullptr, bool aForDrawingSheet=false)
A color representation with 4 components: red, green, blue, alpha.
static const COLOR4D UNSPECIFIED
For legacy support; used as a value to indicate color hasn't been set yet.
std::string AsStdString() const
static KIID FromName(const std::string &aName)
Return a KIID derived from a name, the same name always gives the same KIID.
void placePageFrame(const ORCAD_RAW_PAGE &aPage, SCH_SCREEN *aScreen)
void placeJunctions(const ORCAD_RAW_PAGE &aPage, SCH_SCREEN *aScreen)
Append computed junctions as SCH_JUNCTION items.
bool displayUsesTemplateFont(const ORCAD_DISPLAY_PROP &aProp) const
std::map< std::string, size_t > m_occurrenceFolderCounts
std::vector< VECTOR2I > computeJunctions(const ORCAD_RAW_PAGE &aPage) const
Use both geometry and net IDs; a crossing alone does not create a junction.
int displayFontId(const ORCAD_DISPLAY_PROP &aProp) const
std::vector< OFFPAGE_NET > offpageNets(const ORCAD_RAW_PAGE &aPage) const
Resolve every off-page connector on the page to (index, net, pin position).
void addChildOccurrenceAliases(const ORCAD_RAW_PAGE &aParentPage, const ORCAD_OCC_SCOPE &aParentScope, const ORCAD_DRAWN_INSTANCE &aDrawn, const ORCAD_OCC_SCOPE &aChildScope)
std::string netAt(const ORCAD_RAW_PAGE &aPage, int aX, int aY) const
Prefer endpoint nets, then intersecting wires, then endpoint aliases.
static constexpr int MARGIN_B_DBU
PROGRESS_REPORTER * m_progressReporter
SCH_SHEET * Convert(SCH_SHEET *aRootSheet)
aRootSheet must have a screen and be registered on the schematic.
void assignPageItemUuids(size_t aPageOrdinal)
void buildNetLookup(const ORCAD_RAW_PAGE &aPage)
Rebuild m_netIndex for a page in the current scope.
std::map< SCH_SYMBOL *, std::vector< SOURCE_PIN_IDENTITY > > m_sourcePinIdentities
void assignPinUuids(SCH_SYMBOL *aSymbol, const std::string &aRole) const
Name-based UUIDs for a symbol's raw pins, derived from aRole and each pin's number,...
std::vector< int > placedStackedPinOffsets(const ORCAD_PLACED_INSTANCE &aInstance) const
void rememberInterfaceLabelSource(SCH_SCREEN *aScreen, SCH_LABEL_BASE *aLabel, const std::vector< SEG > &aSourceWires)
void forEachDesignPage(const std::function< void(const ORCAD_RAW_PAGE &)> &aVisit, bool aUnreferenced=false) const
Visit root pages, then child-folder pages, then unreferenced folder pages if asked.
static constexpr int MARGIN_R_DBU
std::map< SCH_SCREEN *, std::vector< wxString > > m_sourceOccurrences
std::map< SCH_SCREEN *, const ORCAD_RAW_PAGE * > m_sourcePages
std::map< SCH_SYMBOL *, const ORCAD_PLACED_INSTANCE * > m_sourceInstances
void acceptPowerAliases(const std::map< std::string, POWER_ALIAS_EVIDENCE > &aCandidates)
Rename a power symbol to the net most of its placements resolve to.
bool canBuildFolderHierarchy(const std::vector< ORCAD_RAW_PAGE > &aPages, const ORCAD_OCC_SCOPE &aScope) const
Every occurrence block is drawn exactly once on its parent folder's pages.
SCH_SCREEN * newScreen()
A new screen with the next deterministic screen UUID, recorded as created by this import.
PAGE_SCOPE occurrenceScope(const ORCAD_OCC_SCOPE &aOcc) const
A scope for aOcc carrying the occurrence aliases known so far.
std::string occurrenceBaseNetName(const std::string &aName) const
std::set< SCH_SCREEN * > m_importedScreens
std::vector< SCH_SHEET * > createTopLevelSheets(const std::vector< std::pair< wxString, wxString > > &aNamesAndFiles, bool aReuseRoot, bool aOrdinalSheetUuids)
Top-level sheets named by aNamesAndFiles.
bool isOffpageNetName(const std::string &aName) const
void placeBitmap(const ORCAD_PRIMITIVE &aPrim, SCH_SCREEN *aScreen, int aOrient=0, bool *aUsedEmbeddedEmf=nullptr)
Skip undecodable images with a warning.
VECTOR2I graphicPinPos(const ORCAD_GRAPHIC_INST &aInst) const
Use the transformed cache pin position, or the instance anchor if no pin is available.
SCH_SHEET_PATH topLevelPath(SCH_SHEET *aSheet, size_t aPageNumber) const
The hierarchy path ending at a top-level sheet, numbered aPageNumber.
void applyPageSettings(ORCAD_RAW_PAGE &aPage, SCH_SCREEN *aScreen)
Shift content on the 10-DBU grid to preserve connectivity.
VECTOR2I displayPropPosition(const ORCAD_DISPLAY_PROP &aDisplay, const VECTOR2I &aAnchorIu) const
Capture's display-property origin sits on the font baseline; return the KiCad text origin.
SPIN_STYLE spinAwayFromWire(const VECTOR2I &aPosDbu) const
Point an interface label at aPosDbu away from the wire that ends there.
std::set< const SCH_ITEM * > m_preExistingItems
already on the root screen
ORCAD_CONVERTER(ORCAD_DESIGN &aDesign, SCHEMATIC *aSchematic, REPORTER *aReporter, PROGRESS_REPORTER *aProgressReporter=nullptr)
bool m_simpleRepeatedLeafDesign
static bool onSegment(int aX, int aY, const ORCAD_WIRE &aWire)
True when the point lies strictly INSIDE (not at an endpoint of) an H/V wire.
wxString uniqueSheetName(const wxString &aBase)
aBase, or "aBase (N)" for the first N >= 2 not already used by a sibling sheet.
std::map< std::tuple< SCH_SCREEN *, const ORCAD_PLACED_INSTANCE *, size_t >, std::pair< uint32_t, std::string > > m_wirelessNetNames
~ORCAD_CONVERTER()
Out-of-line: LIB_ENTRY holds LIB_SYMBOL by unique_ptr.
void placeGraphicDisplayText(const ORCAD_GRAPHIC_INST &aGraphic, const ORCAD_DISPLAY_PROP &aDisplay, const std::string &aText, SCH_SCREEN *aScreen)
One displayed property attached to a placed page symbol, preserving source text geometry.
VECTOR2I namedGraphicPinPos(const ORCAD_RAW_PAGE &aPage, const ORCAD_GRAPHIC_INST &aInst) const
Graphic-symbol connection point, corrected to a nearby endpoint of its named wire.
static wxString MakePageFileName(int aPageIndex, const std::string &aPageName)
static BOX2I pageExtentDbu(const ORCAD_RAW_PAGE &aPage)
Free graphics use nested primitive bounds; their outer boxes do not describe page coordinates.
void appendPageItem(SCH_SCREEN *aScreen, SCH_ITEM *aItem)
void note(const wxString &aMsg)
Fact about the source design (not a conversion problem): RPT_SEVERITY_INFO.
std::vector< NET_LABEL_INTENT > m_netLabelIntents
int textBaselineOffset(int aTextSize, int aFontIdx, bool aTemplateFont=true) const
int m_fontBaselineDbu
dominant text height; 0 = none
std::set< wxString > m_usedSheetNames
Lower-cased sheet names already emitted, to keep sibling sheet names unique.
void convertFlatPages(const SCH_SHEET_PATH &aRootPath)
Every page, each child occurrence expanded, becomes a top-level sheet.
std::map< std::string, std::string > m_baseOccurrenceNetAliases
Occurrence net aliases shared by every scope, then those a parent block adds per child scope.
std::vector< INTERFACE_LABEL_SOURCE > m_interfaceLabelSources
PAGE_NET_INDEX m_netIndex
SCH_SCREEN * m_pageItemScreen
void placeFolder(FOLDER_WALK &aWalk, std::vector< ORCAD_RAW_PAGE > &aPages, const ORCAD_OCC_SCOPE &aScope, SCH_SHEET *aFolderSheet, const SCH_SHEET_PATH &aFolderPath, const std::string &aOccurrenceSuffix, bool aRepeatedFolder, const std::map< std::string, std::string > &aUnconnectedInterfaceNetNames, std::map< std::string, std::string > aInterfaceNetAliases)
void prepareGlobalNetNames()
Capture net names ignore case; KiCad net names do not.
std::map< std::string, size_t > m_occurrenceNetNameScopeCounts
std::string resolvePowerNet(const ORCAD_RAW_PAGE &aPage, const ORCAD_GRAPHIC_INST &aInst) const
int m_powerCount
"#PWR%04d" counter
void convertUnreferencedPages()
void convertPage(ORCAD_RAW_PAGE &aPage, SCH_SCREEN *aScreen, const SCH_SHEET_PATH &aSheetPath, bool aContainerPage=false, bool aSharedFolderPage=false)
VECTOR2I powerPinPos(const ORCAD_RAW_PAGE &aPage, const ORCAD_GRAPHIC_INST &aInst) const
Power-symbol connection point, corrected to a nearby endpoint of its named wire.
KIID deterministicUuid(const std::string &aRole, size_t aOrdinal) const
std::set< std::string > m_offpageNetNames
void applyTitleBlock(const ORCAD_RAW_PAGE &aPage, SCH_SCREEN *aScreen)
void finalizeNativePowerPackages()
void finishConversion()
Run the shared finalization sequence that ends every conversion entry point.
std::map< std::pair< SCH_SCREEN *, uint32_t >, std::vector< SCH_ITEM * > > m_sourceNetItems
void placeDefinitionImages(const ORCAD_SYMBOL_DEF &aDefinition, int aBaseX, int aBaseY, int aOrient, SCH_SCREEN *aScreen)
std::string occurrenceElectricalNetName(uint32_t aOccurrenceId, const std::string &aName) const
std::map< std::pair< SCH_SCREEN *, uint32_t >, std::string > m_sourceGeneratedNetNames
void applyFont(EDA_TEXT *aText, int aFontIdx, bool aTemplateFont=true) const
std::map< std::pair< SCH_SCREEN *, uint32_t >, std::set< std::string > > m_sourceNetNames
SCH_SHEET * createBlockSheet(SCH_SHEET *aParentSheet, const ORCAD_RAW_PAGE &aParentPage, const ORCAD_DRAWN_INSTANCE &aBlock, const ORCAD_OCC_BLOCK &aOccurrence, const wxString &aName, const std::string &aFilePageName, int aPageIndex)
The child sheet for a hierarchical block, with its pins, appended to aParentSheet's screen.
static void offsetPage(ORCAD_RAW_PAGE &aPage, int aDx, int aDy)
aDx and aDy must be multiples of the 10-DBU grid.
void recordPowerAlias(std::map< std::string, POWER_ALIAS_EVIDENCE > &aCandidates, const std::string &aSourceName, const std::string &aElectricalName) const
void convertFolderHierarchy(const SCH_SHEET_PATH &aRootPath, bool aNative)
VECTOR2I textSize(int aFontIdx, bool aTemplateFont=true) const
Preserve an explicit LOGFONT width while retaining natural font aspect when it is zero.
bool isPowerNetName(const std::string &aName) const
std::vector< std::pair< SCH_LABEL_BASE *, std::pair< SCH_SCREEN *, uint32_t > > > m_labelSourceNets
std::string canonicalGlobalNetKey(const std::string &aName) const
Case-folded canonicalGlobalNetName() for use as a map key.
static constexpr int MARGIN_T_DBU
void placeHierarchicalBlockFields(SCH_SHEET *aSheet, const ORCAD_DRAWN_INSTANCE &aBlock, const std::string &aChildFolder)
void placeGraphics(const ORCAD_RAW_PAGE &aPage, SCH_SCREEN *aScreen)
std::map< std::string, std::string > unconnectedInterfaceNetNames(const ORCAD_DRAWN_INSTANCE &aBlock, const std::string &aFlatNetSuffix) const
No-connect block pins whose names are wired elsewhere become per-occurrence nets.
void placeHierarchicalBlockPinFill(SCH_SCREEN *aScreen, SCH_SHEET_PIN *aPin)
void collectFolderPowerAliases(std::map< std::string, POWER_ALIAS_EVIDENCE > &aCandidates, std::vector< ORCAD_RAW_PAGE > &aPages, const ORCAD_OCC_SCOPE &aScope)
std::vector< SCH_ITEM * > m_pageItems
void placeWires(const ORCAD_RAW_PAGE &aPage, SCH_SCREEN *aScreen, bool aHierarchical, bool aNestedHierarchy, bool aSharedFolderPage)
int textSizeIU(int aFontIdx, bool aTemplateFont=true) const
std::map< std::string, std::map< std::string, std::string > > m_hierBusNamesByScreen
void assignRemainingUuids()
Give items created after page conversion, such as moved labels and cleanup junctions,...
void warn(const wxString &aMsg)
– reporting [orcad_converter_sheet.cpp] ---------------------------------------—
void placeDefinitionVectors(const ORCAD_SYMBOL_DEF &aDefinition, int aBaseX, int aBaseY, int aOrient, SCH_SCREEN *aScreen, double aTextScaleX=1.0, double aTextScaleY=1.0, bool aUseGenericTextBaseline=false)
std::map< std::string, std::string > m_globalNetAliases
std::string canonicalGlobalNetName(const std::string &aName) const
Return the design-wide spelling selected by prepareGlobalNetNames().
void applyMultilineSpacing(SCH_TEXT *aText, int aFontIdx, bool aTemplateFont=true) const
std::map< std::string, size_t > m_occurrenceNetNameMinDepth
std::map< const std::map< uint32_t, std::string > *, std::map< std::string, std::string > > m_occurrenceAliasesByScope
void placePorts(const ORCAD_RAW_PAGE &aPage, SCH_SCREEN *aScreen, bool aHierarchical)
void prepareOccurrenceNets()
– hierarchy [orcad_converter_sheet.cpp] --------------------------------------—
static VECTOR2I snapToWire(int aX, int aY, const ORCAD_WIRE &aWire)
Closest point (DBU) on a wire segment to (aX, aY); exact for H/V wires.
static constexpr int MARGIN_L_DBU
Page margins in DBU leave room for the KiCad frame and title block.
std::set< std::string > m_connectedBlockInterfaceNames
VECTOR2I placedPinElectricalPosition(const ORCAD_PLACED_INSTANCE &aInstance, size_t aPinIndex) const
void enterScope(PAGE_SCOPE aScope)
std::string powerNet(const ORCAD_RAW_PAGE &aPage, const ORCAD_GRAPHIC_INST &aInst) const
Memoized resolvePowerNet() for the indexed page.
std::set< const std::string * > pinOccurrenceTargets(const ORCAD_RAW_PAGE &aPage, const ORCAD_BLOCK_PIN &aPin, const std::map< uint32_t, std::string > &aScopeNets, bool aSkipGenerated, std::set< std::string > *aSourceKeys=nullptr) const
Occurrence nets in aScopeNets that a block pin on aPage reaches by name or by wire object id.
void placeBusEntries(const ORCAD_RAW_PAGE &aPage, SCH_SCREEN *aScreen)
SCH_BUS_WIRE_ENTRY per bus entry (position x1,y1; size x2-x1, y2-y1).
const std::set< uint32_t > & pinNetIds(const ORCAD_PIN_INST &aPin) const
Page nets a placed pin joins through its net id, its wire object id or a wire under it.
const ORCAD_SYMBOL_DEF * graphicDefinition(const ORCAD_GRAPHIC_INST &aInst) const
The cached variant a page graphic uses: its Source Library first, then its placed bounds,...
std::optional< uint32_t > occurrenceNetIdFor(const std::string *aName) const
Return the occurrence net id owning aName, which the table identifies by address.
static wxString SanitizeFileName(const std::string &aName)
std::map< std::string, std::string > m_globalNetNames
void applyDisplayProp(SCH_FIELD &aField, const ORCAD_DISPLAY_PROP &aDisplay, const VECTOR2I &aAnchorIu, bool aSymbolFlips, bool aApplyVisibility=true) const
Style a field from a display property.
void appendNetIntent(SCH_SCREEN *aScreen, SCH_LABEL *aLabel, bool aExplicitName, uint32_t aNetId=0)
bool canBuildNativeHierarchy(const ORCAD_RAW_PAGE &aPage, const ORCAD_OCC_SCOPE &aScope) const
One root page whose every block opens a single-page child.
std::set< std::string > m_powerNetNames
std::string effectiveInterfaceNetName(const std::string &aName) const
const ORCAD_DISPLAY_PROP * finishInterfaceLabel(const ORCAD_GRAPHIC_INST &aGraphic, SCH_LABEL_BASE *aLabel, const std::vector< SEG > &aSourceWires, SCH_SCREEN *aScreen)
Style a port or off-page label from its source graphic, draw its stored IREF text and add it.
void placeOffpageConnectors(const ORCAD_RAW_PAGE &aPage, SCH_SCREEN *aScreen, const SCH_SHEET_PATH &aSheetPath, bool aHierarchical)
Keep computed intersheet references hidden; display the stored OrCAD IREF text.
Describe the page size and margins of a paper page on which to eventually print or plot.
bool SetType(PAGE_SIZE_TYPE aPageSize, bool aIsPortrait=false)
Set the name of the page type and also the sizes and margins commonly associated with that type name.
static void SetCustomWidthMils(double aWidthInMils)
Set the width of Custom page in mils for any custom page constructed or made via SetType() after maki...
double GetHeightMM() const
double GetWidthMM() const
static void SetCustomHeightMils(double aHeightInMils)
Set the height of Custom page in mils for any custom page constructed or made via SetType() after mak...
const PAGE_SIZE_TYPE & GetType() const
A progress reporter interface for use in multi-threaded environments.
virtual bool KeepRefreshing(bool aWait=false)=0
Update the UI (if any).
virtual void Report(const wxString &aMessage)=0
Display aMessage in the progress bar dialog.
A REFERENCE_IMAGE is a wrapper around a BITMAP_IMAGE that is displayed in an editor as a reference fo...
bool ReadImageFile(const wxString &aFullFilename)
Read and store an image file.
bool SetImage(const wxImage &aImage)
Set the image from an existing wxImage.
const BITMAP_BASE & GetImage() const
Get the underlying image.
void SetImageScale(double aScale)
Set the image "zoom" value.
A pure virtual class used to derive REPORTER objects from.
Holds all the data relating to one schematic.
void SetSize(const VECTOR2I &aSize)
virtual void SetStroke(const STROKE_PARAMS &aStroke) override
Class for a wire to bus entry.
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
const std::vector< std::shared_ptr< SCH_CONNECTION > > AllMembers() const
wxString Name(bool aIgnoreSheet=false) const
static bool IsBusLabel(const wxString &aLabel)
Test if aLabel has a bus notation.
void SetText(const wxString &aText) override
void SetSpinStyle(SPIN_STYLE aSpinStyle) override
void SetSpinStyle(SPIN_STYLE aSpinStyle) override
Base class for any item which can be embedded within the SCHEMATIC container class,...
const SYMBOL * GetParentSymbol() const
SCH_LAYER_ID GetLayer() const
Return the layer this item is on.
SCH_CONNECTION * Connection(const SCH_SHEET_PATH *aSheet=nullptr) const
Retrieve the connection associated with this object in the given sheet.
void SetShape(LABEL_FLAG_SHAPE aShape)
virtual void SetSpinStyle(SPIN_STYLE aSpinStyle)
Segment description base class to describe items which have 2 end points (track, wire,...
void SetLineWidth(const int aSize)
VECTOR2I GetEndPoint() const
VECTOR2I GetStartPoint() const
SEG GetSeg() const
Get the geometric aspect of the wire as a SEG.
void SetLineStyle(const LINE_STYLE aStyle)
void SetLineColor(const KIGFX::COLOR4D &aColor)
void SetEndPoint(const VECTOR2I &aPosition)
SCH_PIN * GetLibPin() const
const wxString & GetName() const
PIN_ORIENTATION GetOrientation() const
VECTOR2I GetPosition() const override
ELECTRICAL_PINTYPE GetType() const
void SetTitleBlock(const TITLE_BLOCK &aTitleBlock)
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
void SetPageSettings(const PAGE_INFO &aPageSettings)
EE_RTREE & Items()
Get the full RTree, usually for iterating.
const KIID & GetUuid() const
void SetFileName(const wxString &aFileName)
Set the file name for this screen to aFileName.
void SetPosition(const VECTOR2I &aPos) override
void SetStroke(const STROKE_PARAMS &aStroke) override
void AddPoint(const VECTOR2I &aPosition)
A container for handling SCH_SHEET_PATH objects in a flattened hierarchy.
void SortByPageNumbers(bool aUpdateVirtualPageNums=true)
Sort the list of sheets by page number.
bool ContainsSheet(const SCH_SHEET *aSheet) const
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
int Cmp(const SCH_SHEET_PATH &aSheetPathToTest) const
Compare if this is the same sheet path as aSheetPathToTest.
void SetPageNumber(const wxString &aPageNumber)
Set the sheet instance user definable page number.
SCH_SHEET * Last() const
Return a pointer to the last SCH_SHEET of the list.
void push_back(SCH_SHEET *aSheet)
Forwarded method from std::vector.
Define a sheet pin (label) used in sheets to create hierarchical schematics.
void CreateGraphicShape(const RENDER_SETTINGS *aSettings, std::vector< VECTOR2I > &aPoints, const VECTOR2I &aPos) const override
Calculate the graphic shape (a polygon) associated to the text.
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
void AddPin(SCH_SHEET_PIN *aSheetPin)
Add aSheetPin to the sheet.
void SyncUuidToScreen()
Take the identity of the screen this sheet owns.
bool IsTopLevelSheet() const
Check if this sheet is a top-level sheet.
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this sheet.
void SetExcludedFromBoard(bool aExclude, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
Set or clear exclude from board netlist flag.
SCH_SCREEN * GetScreen() const
void SetScreen(SCH_SCREEN *aScreen)
Set the SCH_SCREEN associated with this sheet to aScreen.
SCH_FIELD * AddField(const SCH_FIELD &aField)
Add aFieldName to the list of fields.
std::vector< SCH_SHEET_PIN * > & GetPins()
std::vector< std::unique_ptr< SCH_PIN > > & GetRawPins()
std::vector< const SCH_PIN * > GetPins(const SCH_SHEET_PATH *aSheet) const
Retrieve a list of the SCH_PINs for the given sheet path.
int GetUnitSelection(const SCH_SHEET_PATH *aSheet) const
Return the instance-specific unit selection for the given sheet path.
const wxString GetRef(const SCH_SHEET_PATH *aSheet, bool aIncludeUnit=false) const override
VECTOR2I GetPosition() const override
VECTOR2I GetOffsetToMatchSCH_FIELD(SCH_RENDER_SETTINGS *aRenderSettings) const
void SetPosition(const VECTOR2I &aPosition) override
virtual VECTOR2I GetSchematicTextOffset(const RENDER_SETTINGS *aSettings) const
This offset depends on the orientation, the type of text, and the area required to draw the associate...
bool Contains(const SEG &aSeg) const
Spin style for labels of all kinds on schematics.
Simple container to manage line stroke parameters.
Hold the information shown in the lower right corner of a plot, printout, or editing view.
void SetRevision(const wxString &aRevision)
void SetComment(int aIdx, const wxString &aComment)
void SetTitle(const wxString &aTitle)
void SetCompany(const wxString &aCompany)
void SetDate(const wxString &aDate)
Set the date field, and defaults to the current time and date.
A type-safe container of any type.
static bool empty(const wxTextEntryBase *aCtrl)
static constexpr EDA_ANGLE ANGLE_0
static constexpr EDA_ANGLE ANGLE_90
static constexpr EDA_ANGLE ANGLE_VERTICAL
static constexpr EDA_ANGLE ANGLE_HORIZONTAL
static constexpr EDA_ANGLE ANGLE_270
static constexpr EDA_ANGLE ANGLE_180
@ FILLED_SHAPE
Fill with object color.
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
#define THROW_IO_CANCELLED()
@ BUS
the source net is carried by a bus
@ NO_CONNECT
the source marks the net as deliberately unconnected
@ RESOLVED
exactly one physical net carries the source net
@ SPLIT
the source net reaches more than one physical net
@ UNCONNECTED
the source net reaches no physical net
void remove_duplicates(_Container &__c)
Deletes all duplicate values from __c.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
std::vector< uint8_t > OleExtractCiImage(const std::vector< uint8_t > &aPayload)
The CI marker follows the preview DIB; the raster has a counted decimal length.
OLE_IMAGE_PAYLOAD ExtractOleImageFromPayload(const std::vector< uint8_t > &aPayload)
Read the picture out of an OLE object payload that carries the 26-byte prologue.
bool OleRenderMetafilePreview(const std::vector< uint8_t > &aWmf, int aMaxWidth, int aMaxHeight, wxImage &aImage, double aTargetAspect, bool *aUsedEmbeddedEmf)
Render a metafile preview, preferring an EMF the WMF carries over the WMF itself.
bool OleMakeBmpFromDib(const std::vector< uint8_t > &aDib, wxMemoryBuffer &aOut)
wxString OleDescribeImagePayload(const std::vector< uint8_t > &aPayload)
Include leading bytes when the payload format is unknown.
VECTOR2I OrcadDbuToIu(int aX, int aY)
bool OrcadDisplayPropShowsName(const ORCAD_DISPLAY_PROP &aProp)
FILL_T OrcadFillType(int aFillStyle, int aHatchStyle)
int OrcadLineWidthIu(int aWidth)
int OrcadTextBaselineOffset(int aTextSize)
bool OrcadDisplayPropShowsValue(const ORCAD_DISPLAY_PROP &aProp)
void OrcadTransformPrimitivePoints(ORCAD_PRIMITIVE &aPrim, const std::function< ORCAD_POINT(const ORCAD_POINT &)> &aMap)
Map the point members of a primitive: points, arc start and arc end.
KIGFX::COLOR4D OrcadColor(int aColorIndex)
void OrcadOffsetPrimitive(ORCAD_PRIMITIVE &aPrim, int aDx, int aDy)
Translate a primitive, box included.
int OrcadDisplayFontId(const ORCAD_DISPLAY_PROP &aProp)
void OrcadForEachLeafPrimitive(const std::vector< ORCAD_PRIMITIVE > &aPrimitives, const std::function< void(const ORCAD_PRIMITIVE &, int, int)> &aVisit)
Visit every non-group primitive in drawing order with the accumulated offset of its enclosing groups.
constexpr int ORCAD_IU_PER_DBU
Schematic internal units per OrCAD DBU: 10 mil * 254 IU/mil.
bool OrcadDisplayPropVisible(const ORCAD_DISPLAY_PROP &aProp)
LINE_STYLE OrcadLineStyle(int aStyle)
int OrcadPageGraphicLineWidthIu(int aWidth)
VECTOR2I OrcadStretchedImageSize(int aWidth, int aHeight, int aBoxWidth, int aBoxHeight)
static std::set< std::string > busPrefixTokens(const std::string &aPrefix)
static std::set< uint32_t > pageNetIdsNamed(const ORCAD_RAW_PAGE &aPage, std::string_view aName)
static const ORCAD_DRAWN_INSTANCE * findDrawnBlock(const ORCAD_RAW_PAGE &aPage, uint32_t aDbId)
static std::string scopedHierBusRange(const std::string &aName, const std::map< std::string, std::string > &aBusNames)
static bool rawPointOnSegment(int aX, int aY, const ORCAD_WIRE &aWire)
static bool rawBusSegmentsTouch(const ORCAD_WIRE &aFirst, const ORCAD_WIRE &aSecond)
static std::optional< VECTOR2I > safeConnectivityLabelPosition(SCH_SCREEN *aScreen, const VECTOR2I &aPosition, const std::optional< std::vector< SEG > > &aSourceWires)
static uint32_t busNetAt(const ORCAD_RAW_PAGE &aPage, const ORCAD_BLOCK_PIN &aPin)
static std::string scopedHierBusName(const std::string &aName, uint32_t aOccurrenceId)
static std::string firstBusPrefixToken(const std::string &aPrefix)
int OrcadPageOrder(wxString &aName)
Return a numeric page prefix (or -1); strip only the "N - title" convention.
static std::optional< std::vector< SEG > > eligibleSourceConnectivityWires(const ORCAD_RAW_PAGE &aPage, const VECTOR2I &aPosition, const std::set< std::string > &aNames, bool aBus=false, uint32_t *aNetId=nullptr)
static std::vector< const ORCAD_OCC_BLOCK * > sortedOccurrences(const ORCAD_OCC_SCOPE &aScope)
Capture orders child pages by numeric folder prefix, then by folder name without case.
static std::optional< std::vector< SEG > > interfaceSourceWires(const ORCAD_RAW_PAGE &aPage, const VECTOR2I &aPosition, const std::set< std::string > &aNames, const std::string &aNet)
Bus labels fall back to bus wires; a net label with no eligible net wire may still sit on a bus.
static SHEET_SIDE nearestSheetSide(const ORCAD_BLOCK_PIN &aPin, const ORCAD_DRAWN_INSTANCE &aBlock)
static std::vector< std::string > busPrefixRuns(const std::string &aPrefix)
static std::string flatNetSuffix(const ORCAD_DRAWN_INSTANCE &aBlock)
static std::string appendOccurrenceSuffix(const std::string &aParentSuffix, const ORCAD_DRAWN_INSTANCE &aBlock)
void OrcadTransformPrimitivePoints(ORCAD_PRIMITIVE &aPrim, const std::function< ORCAD_POINT(const ORCAD_POINT &)> &aMap)
Map the point members of a primitive: points, arc start and arc end.
KIGFX::COLOR4D OrcadColor(int aColorIndex)
void OrcadOffsetPrimitive(ORCAD_PRIMITIVE &aPrim, int aDx, int aDy)
Translate a primitive, box included.
static std::string scopedHierBusMember(const std::string &aName, const std::map< std::string, std::string > &aBusNames)
static std::optional< VECTOR2I > rawWireIntersection(const ORCAD_WIRE &aFirst, const ORCAD_WIRE &aSecond)
static std::vector< std::pair< BUS_RANGE, BUS_RANGE > > scopedBusRanges(const std::map< std::string, std::string > &aBusNames)
Only renames whose source and scoped ranges have the same length map member by member.
static std::set< std::string > pageNetNames(const ORCAD_RAW_PAGE &aPage, uint32_t aNetId)
void OrcadForEachLeafPrimitive(const std::vector< ORCAD_PRIMITIVE > &aPrimitives, const std::function< void(const ORCAD_PRIMITIVE &, int, int)> &aVisit)
Visit every non-group primitive in drawing order with the accumulated offset of its enclosing groups.
static LABEL_FLAG_SHAPE hierarchicalPinShape(ORCAD_PORT_TYPE aType)
static std::string connectedBusName(const ORCAD_RAW_PAGE &aPage, const ORCAD_BLOCK_PIN &aPin, const std::string &aFallback)
VECTOR2I OrcadStretchedImageSize(int aWidth, int aHeight, int aBoxWidth, int aBoxHeight)
static std::string normalizedPath(std::string aPath)
constexpr ORCAD_ORIENT_ENTRY ORCAD_ORIENT_TABLE[8]
Indexed by orientation bits: angle, mirror, offset selectors, then matrix coefficients.
VECTOR2I OrcadTransformPoint(int aOrient, int aWidth, int aHeight, int aBaseX, int aBaseY, int aPx, int aPy)
Parts use the instance anchor as the base.
int OrcadOrientOf(int aRotation, bool aMirror)
Compose the 3-bit orientation code from the rotation bits and mirror bit.
ORCAD_PORT_TYPE
Map unknown electrical type codes to PASSIVE.
@ ORCAD_ST_GRAPHIC_OLE_INST
std::string OrcadLower(std::string_view aText)
Fold ASCII letters only.
wxString FromOrcadString(const std::string &aText)
Use an 8-bit fallback if Windows-1252 decoding fails.
bool OrcadIEquals(std::string_view aLeft, std::string_view aRight)
Case-insensitive comparison with the folding of OrcadLower.
static float distance(const SFVEC2UI &a, const SFVEC2UI &b)
LABEL_FLAG_SHAPE
Label and flag shapes used with text objects.
Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema.
SHEET_SIDE
Define the edge of the sheet that the sheet pin is positioned.
bool ReplaceIllegalFileNameChars(std::string &aName, int aReplaceChar)
Checks aName for illegal file name characters.
A vector bus name "PREFIX[first..last]" (or ':' as separator); last may be below first.
static std::optional< BUS_RANGE > Parse(const std::string &aName)
std::optional< int64_t > Ordinal(int64_t aIndex) const
Position of aIndex within the range, or nullopt outside it.
int64_t At(int64_t aOrdinal) const
std::vector< wxString > occurrence
std::vector< KIID > itemUuids
std::vector< IMPORT_NET_TERMINAL > terminals
Import provenance, held only for the lifetime of the importing SCHEMATIC.
std::vector< IMPORT_NET_MAP_ENTRY > entries
std::vector< uint8_t > data
The owning wire defines the connection.
int rotation
0..3 quarter turns
Axis-aligned box in OrCAD DBU; corner order as stored (not normalized).
One interface pin of a hierarchical block, at its absolute page position.
Page counters and rules threaded through a folder hierarchy walk.
bool folderSheetNames
name an unreferenced block after its folder, else its page
bool occurrenceAliases
learn power and child occurrence aliases before placing pages
bool rootSharedFolderPage
convert the root page as a shared folder page
bool numberSourcePages
fill title-block page numbers from the walk order
bool nestedFlatSuffix
suffix by block path; else only in simple repeated leaf designs
bool interfaceAliases
alias a child's interface nets to the parent occurrence net
One resolved off-page connector: index into page.offpage, net, pin position.
Lookups for the page and scope being converted, rebuilt by buildNetLookup().
Occurrence context of the page being converted.
std::map< std::string, std::string > interfaceNetAliases
std::map< std::string, std::string > unconnectedInterfaceNetNames
std::map< std::string, std::string > occurrenceNetAliases
const ORCAD_OCC_SCOPE * occ
null when the page has no occurrence
std::string flatNetSuffix
Placements of a power symbol name and the power nets they resolved to.
std::map< std::string, std::pair< std::string, size_t > > targets
std::optional< KIID > libraryPin
Child-folder pages are instantiated for each occurrence, with that occurrence's references.
Display positions use symbol coordinates; rotFont combines the font index and quarter turns.
int rotation
0..3 quarter turns
std::string name
resolved property name (empty when index invalid)
The inline LibraryPart defines the block interface; placed pin records supply absolute positions.
std::string name
intrinsic Name property used for flat-net scoping
int x1
block rectangle top-left, page DBU
std::vector< ORCAD_BLOCK_PIN > pins
std::vector< ORCAD_DISPLAY_PROP > displayProps
std::string childName
child folder, when embedded
std::map< std::string, std::string > props
Font indices are one-based; zero selects the default.
int width
raw lfWidth; zero lets the font choose its natural aspect ratio
int height
raw lfHeight (typically negative)
Free graphics use nested primitive coordinates.
std::unique_ptr< ORCAD_SYMBOL_DEF > nested
SthInPages0 body, else nullptr.
std::map< std::string, std::string > props
int rotation
0..3 quarter turns
bool useGenericTextBaseline
std::string name
cache symbol name
std::vector< ORCAD_DISPLAY_PROP > displayProps
std::string logicalName
ports: resolved net/port name
int typeId
ORCAD_ST value.
Repeated child folders have separate scopes and reference designators.
uint32_t targetDbId
type-12 drawn-instance dbId on the parent page
ORCAD_OCC_SCOPE scope
the child's occurrences under this path
std::string childFolder
child schematic folder name
Each scope holds the references and child blocks for one instantiation path.
std::vector< ORCAD_OCC_BLOCK > blocks
hierarchical block occurrences
std::map< uint32_t, std::string > netNames
occurrence net id -> effective net name
OrCAD rotates about the bounding box; KiCad rotates about the anchor.
char mirror
0 = none, 'x' or 'y' = KiCad mirror axis
int angle
KiCad placement angle in degrees (0/90/180/270, CCW)
Dimensions use mils when isMetric is zero, otherwise micrometres.
Pin positions are absolute page connection points.
uint32_t wordA
two flag/id words after (x, y)
The placed box includes displayed text.
ORCAD_BBOX bbox
placed box, page DBU
int rotation
0..3 quarter turns
bool mirror
orientation bit 2
std::vector< ORCAD_PIN_INST > pins
successfully parsed T0x10 records
Integer point in OrCAD DBU.
Primitive byte lengths can include or exclude the eight-byte size envelope.
int fillStyle
0 solid, 1 none, 2 hatch pattern
std::string text
kind == TEXT
std::vector< ORCAD_POINT > points
polygon/polyline/bezier vertices
std::optional< ORCAD_POINT > textBoundsStart
std::vector< uint8_t > data
kind == IMAGE: raw embedded payload
int lineStyle
0 solid, 1 dash, 2 dot, 3 dash-dot, 4 dash-dot-dot, 5 default
std::optional< ORCAD_POINT > start
arc start point
std::optional< ORCAD_POINT > end
arc end point
int lineWidth
Capture width enum: 0 thin, 1 medium, 2 wide, 3 default.
One parsed 'Views/<folder>/Pages/<page>' stream, raw structure lists in stream order.
std::vector< ORCAD_GRAPHIC_INST > ports
size_t sourcePageCount
pages in the OrCAD folder
std::map< uint32_t, std::vector< std::string > > netAliases
every name recorded for a net db id
std::vector< ORCAD_GRAPHIC_INST > globals
placed power symbols
std::map< uint32_t, std::string > netmap
net db id -> net name
std::map< std::string, std::string > props
std::vector< ORCAD_WIRE > wires
size_t sourcePageNumber
1-based within the OrCAD folder
std::vector< ORCAD_NET_GROUP > netGroups
bus net id -> member net ids
std::vector< ORCAD_DRAWN_INSTANCE > blocks
hierarchical blocks (detection only)
std::vector< ORCAD_PLACED_INSTANCE > instances
std::vector< ORCAD_GRAPHIC_INST > graphics
free comment text/shapes/images
std::vector< ORCAD_GRAPHIC_INST > offpage
off-page connectors
std::vector< ORCAD_GRAPHIC_INST > titleBlocks
std::vector< ORCAD_BUS_ENTRY > busEntries
std::string pageSize
page-size name string, e.g. "B"
ORCAD_PAGE_SETTINGS settings
std::vector< ORCAD_GRAPHIC_INST > ercObjects
saved design-rule-check markers
The bounding box occupies the final eight bytes before the next prefix stop.
std::vector< ORCAD_SYMBOL_PIN > pins
std::vector< ORCAD_PRIMITIVE > primitives
std::map< std::string, std::string > props
std::optional< ORCAD_BBOX > bbox
symbol-space body box
std::vector< ORCAD_SYMBOL_DEF > variants
Variant zero is this entry.
Pin coordinates use symbol space with Y down.
The wire ID refers to the page net table.
bool isBus
true for structure type 21
std::vector< ORCAD_ALIAS > aliases
@ USER
The field ID hasn't been set yet; field is invalid.
@ INTERSHEET_REFS
Global label cross-reference page numbers.
KIBIS top(path, &reporter)
static std::vector< int > candidates(const SEGMENT_INDEX &aIndex, const SEG &aQuery, int aPadding)
wxString result
Test unit parsing edge cases and error handling.
VECTOR2< int32_t > VECTOR2I