40#include <wx/translation.h>
74 std::transform( aPath.begin(), aPath.end(), aPath.begin(),
77 return c ==
'\\' ?
'/' : static_cast<char>( std::tolower( c ) );
92 return std::any_of( aProps.begin(), aProps.end(),
93 [](
const auto& aProperty )
95 return OrcadLower( aProperty.second ).find(
"dual row" ) != std::string::npos;
104 for(
unsigned char character : aName )
106 if( std::isalnum( character ) )
107 normalized.push_back(
static_cast<char>( std::tolower( character ) ) );
117 return ( aProp.
dispMode >> 8 ) & 0xFF;
132 return type >= 1 && type <= 4;
139 return type == 2 || type == 3;
146 return type == 1 || type == 2 || type == 4;
155 if( aProp.
name ==
"Part Reference" || aProp.
name ==
"Reference" )
158 if( aProp.
name ==
"Value" )
171 auto flushOverbar = [&]()
173 if( !overbar.IsEmpty() )
175 result += wxS(
"~{" ) + overbar + wxS(
"}" );
180 for( wxUniChar character : aName )
182 if( character ==
'\\' )
188 if( marked && character !=
' ' && character !=
'\t' && character !=
'\r' && character !=
'\n' )
190 overbar += character;
223 if( aFormatVersionMajor < 3 )
224 return { 67.0, 21.0 };
251 if( aFillStyle == 0 )
254 if( aFillStyle == 2 )
256 switch( aHatchStyle )
271 constexpr uint32_t currentHatchEpoch = 1577836800;
272 return schIUScale.MilsToIU( aModifyTimestamp >= currentHatchEpoch ? 80 : 25 );
278 constexpr uint32_t currentHatchEpoch = 1577836800;
279 return schIUScale.MilsToIU( aModifyTimestamp >= currentHatchEpoch ? 10 : 3 );
291 std::vector<SEG> lines;
293 auto append = [&](
const std::vector<double>& aSlopes,
bool aVertical )
304 for(
SEG& line : generated )
311 lines.insert( lines.end(), generated.begin(), generated.end() );
314 switch( aHatchStyle )
316 case 0: append( { 0.0 }, false );
break;
317 case 1: append( { 0.0 }, true );
break;
318 case 2: append( { 1.0 }, false );
break;
319 case 3: append( { -1.0 }, false );
break;
321 append( { 0.0 }, false );
322 append( { 0.0 }, true );
324 case 5: append( { -1.0, 1.0 }, false );
break;
325 default: append( { -1.0 }, false );
break;
334 return KiROUND( aTextSize * 8.0 / 21.0 );
341int schMm(
double aMm )
347int dbuIu(
double aDbu )
360bool laterRectangleOccludesTextUnderscores(
const std::vector<ORCAD_PRIMITIVE>& aPrimitives,
368 int textLeft = std::min(
text.x1,
text.x2 );
369 int textRight = std::max(
text.x1,
text.x2 );
370 int textTop = std::min(
text.y1,
text.y2 );
371 int textBottom = std::max(
text.y1,
text.y2 );
373 for(
size_t i = aTextIndex + 1; i < aPrimitives.size(); ++i )
380 int rectangleLeft = std::min( rectangle.
x1, rectangle.
x2 );
381 int rectangleRight = std::max( rectangle.
x1, rectangle.
x2 );
382 int rectangleTop = std::min( rectangle.
y1, rectangle.
y2 );
383 int rectangleBottom = std::max( rectangle.
y1, rectangle.
y2 );
387 if( textLeft >= rectangleLeft && textRight <= rectangleRight && textTop >= rectangleTop
388 && textBottom <= rectangleBottom && rectangleBottom - textBottom <= halfStroke )
418bool isBookkeepingProp(
const std::string& aName )
420 static const char*
const skipped[] = {
421 "Part Reference",
"Reference",
"Name",
"Graphic",
"Implementation",
422 "Implementation Type",
"Source Library",
"Source Package",
"Source Part",
"Power Pins Visible",
425 for(
const char*
name : skipped )
436wxString propertyFieldName(
const std::string& aProperty )
439 || isBookkeepingProp( aProperty ) )
441 return wxEmptyString;
454 return wxS(
"OrCAD Footprint" );
457 return wxS(
"OrCAD Footprint Property" );
470 for(
size_t i = 0; i < aSymbol.
pins.size(); ++i )
472 if( aSymbol.
pins[i].position == position )
476 return static_cast<size_t>( position );
484 if( aSequential ? aInstance.
pins.size() != aSymbol.
pins.size() : aInstance.
pins.size() > aSymbol.
pins.size() )
489 int64_t displacement = 0;
491 for(
size_t i = 0; i < aInstance.
pins.size(); ++i )
493 size_t symbolPin = aSequential ? i : symbolPinIndex( aSymbol, aInstance.
pins[i], i );
495 if( symbolPin >= aSymbol.
pins.size() )
499 aSymbol.
pins[symbolPin].hotptX, aSymbol.
pins[symbolPin].hotptY );
500 displacement +=
std::abs(
static_cast<int64_t
>( point.
x ) - aInstance.
pins[i].x );
501 displacement +=
std::abs(
static_cast<int64_t
>( point.
y ) - aInstance.
pins[i].y );
509 bool aSequential =
false )
511 return pinDisplacement( aSymbol, aInstance, aSequential ) == 0;
517 if( aLeft.
bbox.has_value() != aRight.
bbox.has_value() || aLeft.
pins.size() != aRight.
pins.size() )
522 || aLeft.
bbox->y2 != aRight.
bbox->y2 ) )
527 for(
size_t i = 0; i < aLeft.
pins.size(); ++i )
549 if( aInstance.
pins.size() > fitted.
pins.size() )
555 std::map<std::pair<int, int>,
size_t> targetCounts;
556 std::map<std::pair<int, int>, std::set<size_t>> targetPins;
562 return std::pair{ local.
x, local.
y };
565 for(
size_t i = 0; i < aInstance.
pins.size(); ++i )
567 size_t symbolPin = symbolPinIndex( fitted, aInstance.
pins[i], i );
569 if( symbolPin >= fitted.
pins.size() )
572 auto target = targetOf( aInstance.
pins[i] );
573 ++targetCounts[target];
574 targetPins[target].insert( symbolPin );
577 std::set<std::pair<int, int>> handledStackedTargets;
579 for(
size_t i = 0; i < aInstance.
pins.size(); ++i )
581 size_t symbolPin = symbolPinIndex( fitted, aInstance.
pins[i], i );
583 if( symbolPin >= fitted.
pins.size() )
586 auto target = targetOf( aInstance.
pins[i] );
587 int hotptX = target.first;
588 int hotptY = target.second;
589 const std::set<size_t>& stackedPins = targetPins.at( target );
590 bool stackedTarget = targetCounts.at( target ) > 1;
592 auto occupant = std::find_if( fitted.
pins.begin(), fitted.
pins.end(),
595 return aPin.hotptX == hotptX && aPin.hotptY == hotptY;
598 if( stackedTarget && !handledStackedTargets.count( target ) )
600 occupant = std::find_if( fitted.
pins.begin(), fitted.
pins.end(),
603 size_t index = static_cast<size_t>( &aPin - fitted.pins.data() );
604 return aPin.hotptX == hotptX && aPin.hotptY == hotptY
605 && !stackedPins.count( index );
607 handledStackedTargets.insert( target );
609 else if( stackedTarget )
611 occupant = fitted.
pins.end();
614 if( occupant != fitted.
pins.end() && occupant != fitted.
pins.begin() + symbolPin )
616 std::swap( occupant->hotptX, fitted.
pins[symbolPin].hotptX );
617 std::swap( occupant->hotptY, fitted.
pins[symbolPin].hotptY );
618 std::swap( occupant->startX, fitted.
pins[symbolPin].startX );
619 std::swap( occupant->startY, fitted.
pins[symbolPin].startY );
623 int deltaX = hotptX - fitted.
pins[symbolPin].hotptX;
624 int deltaY = hotptY - fitted.
pins[symbolPin].hotptY;
626 fitted.
pins[symbolPin].hotptX = hotptX;
627 fitted.
pins[symbolPin].hotptY = hotptY;
628 fitted.
pins[symbolPin].startX += deltaX;
629 fitted.
pins[symbolPin].startY += deltaY;
637std::pair<std::string, std::string> splitCacheName(
const std::string& aName,
const std::string& aBase )
639 std::string tail = aName.compare( 0, aBase.size(), aBase ) == 0 ? aName.substr( aBase.size() ) : aName;
640 size_t dot = tail.find(
'.' );
642 return { tail.substr( 0, dot ), dot == std::string::npos ? std::string() : tail.substr( dot + 1 ) };
647std::string packageUnitLetter(
const ORCAD_PACKAGE& aPackage,
size_t aIndex )
649 if( aIndex < aPackage.
devices.size() && !aPackage.
devices[aIndex].unitRef.empty() )
650 return aPackage.
devices[aIndex].unitRef;
652 if( aPackage.
devices.size() < 2 )
655 std::string
index = std::to_string( aIndex );
656 return "#" + std::string( 10 - std::min<size_t>( 10,
index.size() ),
'0' ) +
index;
660std::vector<bool> nonblankPinNumbers(
const std::vector<std::string>& aNumbers )
662 std::vector<bool> visible;
663 visible.reserve( aNumbers.size() );
665 for(
const std::string& number : aNumbers )
666 visible.push_back( !number.empty() );
672bool unitLetterLess(
const std::string& aLeft,
const std::string& aRight )
674 return StrNumCmp( wxString::FromUTF8( aLeft ), wxString::FromUTF8( aRight ) ) < 0;
684 std::vector<std::string> missingOrder;
685 std::map<std::string, std::vector<const ORCAD_PLACED_INSTANCE*>> missing;
689 std::vector<const ORCAD_RAW_PAGE*> allPages;
694 allPages.push_back( &aPage );
705 auto [it, isNew] = missing.try_emplace( inst.
pkgName );
708 missingOrder.push_back( inst.
pkgName );
710 it->second.push_back( &inst );
714 for(
const std::string&
name : missingOrder )
716 const std::vector<const ORCAD_PLACED_INSTANCE*>& insts = missing[
name];
718 note( wxString::Format(
_(
"Symbol '%s' is absent from the design cache; synthesized "
719 "placeholder from %d instance(s)." ),
731 if( symbol ==
m_design.symbols.end() || inst.
pins.empty() )
734 std::vector<const ORCAD_SYMBOL_DEF*>
candidates = { &symbol->second };
752 if( symbolPinsMatch( *candidate, inst ) )
754 matching = candidate;
763 if( !symbolPinsMatch( *candidate, inst,
true ) )
770 for(
size_t i = 0; i < inst.
pins.size(); ++i )
772 if( inst.
pins[i].pinIndex )
773 fitted.
pins[i].position =
std::abs(
static_cast<int>( inst.
pins[i].pinIndex ) ) - 1;
776 if( symbolPinsMatch( fitted, inst ) )
778 symbol->second.variants.insert( symbol->second.variants.begin(), std::move( fitted ) );
779 matching = &symbol->second.
variants.front();
788 auto sourceProperty = inst.
props.find(
"Source Library" );
789 std::string sourceLibrary = sourceProperty != inst.
props.end() ? sourceProperty->second
792 bool sourceMatchedGraphics =
793 !sourceLibrary.empty() && !matching->
sourceLib.empty()
796 if( matching != &symbol->second && !sourceMatchedGraphics
797 && std::none_of( symbol->second.variants.begin(), symbol->second.variants.end(),
800 return aVariant.synthesized && symbolGeometryMatches( aVariant, *matching );
804 fitted.
primitives = symbol->second.primitives;
805 fitted.
color = symbol->second.color;
806 fitted.
props = symbol->second.props;
811 if( symbolPinsMatch( fitted, inst ) )
812 symbol->second.variants.insert( symbol->second.variants.begin(), std::move( fitted ) );
819 int64_t bestDisplacement = std::numeric_limits<int64_t>::max();
823 std::optional<int64_t> displacement = pinDisplacement( *candidate, inst,
false );
825 if( displacement && *displacement < bestDisplacement )
828 bestDisplacement = *displacement;
836 if( symbolPinsMatch( fitted, inst ) )
837 symbol->second.variants.push_back( std::move( fitted ) );
865 auto view = [&](
const std::string& aUnit,
const char* aView ) ->
const ORCAD_SYMBOL_DEF*
867 for(
const std::string&
name : { aPackage.
name + aUnit +
"." + aView, aPackage.
name +
"." + aView } )
878 for(
size_t i = 0; i < aPackage.
devices.size(); ++i )
883 std::string letter = packageUnitLetter( aPackage, i );
891 return aUnit.letter == letter;
904 entry.
units.push_back( std::move( unit ) );
907 std::stable_sort( entry.
units.begin(), entry.
units.end(),
910 return unitLetterLess( a.letter, b.letter );
919 std::set<const ORCAD_SYMBOL_DEF*> packaged;
935 for(
const auto& [cacheName, def] :
m_design.symbols )
937 if( packaged.count( &def )
943 size_t dot = cacheName.rfind(
'.' );
944 std::string view = dot == std::string::npos ? std::string() : cacheName.substr( dot + 1 );
945 std::string base = view ==
"Normal" || view ==
"Convert" ? cacheName.substr( 0, dot ) : cacheName;
949 if( view ==
"Convert" &&
normal !=
m_design.symbols.end() && !packaged.count( &
normal->second ) )
952 std::string libname =
SymbolId( base );
956 warn( wxString::Format(
_(
"The symbol '%s' duplicates the name of another library item and was "
957 "left out of the library." ),
962 std::string bare = base.substr( 0, base.find(
'.' ) );
965 for(
const std::string& key : { base, bare } )
967 auto pkgIt =
m_design.packages.find( key );
969 if( pkgIt !=
m_design.packages.end() )
971 pkg = &pkgIt->second;
992 if( pkg && !pkg->
devices.empty() )
999 ls.
units.push_back( std::move( unit ) );
1004 std::vector<LIB_SYMBOL*> out;
1013 out.push_back(
static_cast<LIB_SYMBOL*
>( symbol->Duplicate() ) );
1015 catch(
const std::exception& e )
1017 warn( wxString::Format(
_(
"The symbol '%s' could not be converted and was left out of the "
1029 const std::vector<const ORCAD_PLACED_INSTANCE*>& aInstances )
const
1046 auto inv = [&](
int aX,
int aY )
1052 std::vector<ORCAD_POINT> r;
1055 r.push_back( inv( t.
x - ref->
x, t.
y - ref->
y ) );
1057 std::optional<int> inferredWidth;
1058 std::optional<int> inferredHeight;
1060 if( r.size() == 1 && ori == 0 )
1062 std::map<int, int> widthCounts;
1063 std::map<int, int> heightCounts;
1067 if( inst->pins.size() != 1 )
1070 int instOrient =
OrcadOrientOf( inst->rotation, inst->mirror );
1072 int localX = transform.
a * r.front().x + transform.
b * r.front().y;
1073 int localY = transform.
c * r.front().x + transform.
d * r.front().y;
1074 int offsetX = inst->pins.front().x - inst->x - localX;
1075 int offsetY = inst->pins.front().y - inst->y - localY;
1077 auto tally = [&](
int aSelector,
int aOffset )
1082 if( aSelector == 1 )
1083 ++widthCounts[aOffset];
1084 else if( aSelector == 2 )
1085 ++heightCounts[aOffset];
1088 tally( transform.
txSel, offsetX );
1089 tally( transform.
tySel, offsetY );
1092 auto mostFrequent = [](
const std::map<int, int>& aCounts ) -> std::optional<int>
1094 auto best = std::max_element( aCounts.begin(), aCounts.end(),
1095 [](
const auto& aLeft,
const auto& aRight )
1097 return aLeft.second < aRight.second;
1099 return best == aCounts.end() ? std::nullopt : std::optional<int>( best->first );
1102 inferredWidth = mostFrequent( widthCounts );
1103 inferredHeight = mostFrequent( heightCounts );
1106 std::vector<char> sides;
1114 int x0 = r.front().x;
1115 int x1 = r.front().x;
1116 int y0 = r.front().y;
1117 int y1 = r.front().y;
1121 x0 = std::min( x0, p.x );
1122 x1 = std::max( x1, p.x );
1123 y0 = std::min( y0, p.y );
1124 y1 = std::max( y1, p.y );
1127 bool horizFirst = ( x1 - x0 ) >= ( y1 - y0 );
1131 std::vector<char> cand;
1134 cand.push_back(
'L' );
1137 cand.push_back(
'R' );
1140 cand.push_back(
'T' );
1143 cand.push_back(
'B' );
1147 sides.push_back( 0 );
1153 char pick = cand.front();
1155 for(
char c : cand )
1157 bool isTB = c ==
'T' || c ==
'B';
1159 if( isTB != horizFirst )
1166 sides.push_back( pick );
1169 if( r.size() == 1 && inferredWidth && inferredHeight )
1173 bx2 = *inferredWidth;
1174 by2 = *inferredHeight;
1178 auto hasSide = [&](
char aSide )
1180 return std::find( sides.begin(), sides.end(), aSide ) != sides.end();
1190 int m = (int) std::floor( ( bx1 + bx2 ) / 2.0 );
1197 int m = (int) std::floor( ( by1 + by2 ) / 2.0 );
1209 bx1 = std::min( c1.
x, c2.
x );
1210 bx2 = std::max( c1.
x, c2.
x );
1211 by1 = std::min( c1.
y, c2.
y );
1212 by2 = std::max( c1.
y, c2.
y );
1224 sym.
name = aPkgName;
1230 rect.
x1 = bx1 - s.
x;
1231 rect.
y1 = by1 - s.
y;
1232 rect.
x2 = bx2 - s.
x;
1233 rect.
y2 = by2 - s.
y;
1237 auto package = m_design.packages.find( ref->sourcePackage );
1239 if( package !=
m_design.packages.end() )
1242 for(
size_t i = 0; i < r.size(); ++i )
1244 int px = r[i].x - s.x;
1245 int py = r[i].y - s.y;
1251 case
'L': ddx = PIN_LEN_DBU; break;
1252 case
'R': ddx = -PIN_LEN_DBU; break;
1253 case
'T': ddy = PIN_LEN_DBU; break;
1254 case
'B': ddy = -PIN_LEN_DBU; break;
1260 if( dualRowConnector )
1262 int pinIndex = std::abs( static_cast<int>( ref->pins[i].pinIndex ) );
1263 pin.position = pinIndex > 0 ? pinIndex - 1 : static_cast<int>( i );
1264 pin.name = std::to_string( pinIndex > 0 ? pinIndex : i + 1 );
1267 pin.startX = px + ddx;
1268 pin.startY = py + ddy;
1284 const std::string& v = aInst.
pkgName;
1285 auto sourceProperty = aInst.
props.find(
"Source Package" );
1286 std::string base = sourceProperty != aInst.
props.end() && !sourceProperty->second.empty() ? sourceProperty->second
1288 : v.substr( 0, v.find(
'.' ) );
1290 auto [unit, view] = splitCacheName( v, base );
1298 if( lower !=
"normal" )
1311 return {
nullptr, 0 };
1315 std::vector<const ORCAD_SYMBOL_DEF*> variants;
1316 variants.push_back( prime );
1319 variants.push_back( &v );
1321 if( aInst.
pins.empty() )
1322 return { prime, 0 };
1324 auto sourceProperty = aInst.
props.find(
"Source Library" );
1325 std::string sourceLibrary = sourceProperty != aInst.
props.end() ? sourceProperty->second : aInst.
sourceLibrary;
1327 if( !sourceLibrary.empty() )
1331 for(
size_t vi = 0; vi < variants.size(); ++vi )
1333 if(
normalizedPath( variants[vi]->sourceLib ) == sourceKey && symbolPinsMatch( *variants[vi], aInst ) )
1334 return { variants[vi],
static_cast<int>( vi ) };
1338 for(
size_t vi = 0; vi < variants.size(); ++vi )
1342 if( symbolPinsMatch( *sym, aInst ) )
1343 return { sym, (int) vi };
1346 return { prime, 0 };
1352 auto packageProperty = aInst.
props.find(
"Source Package" );
1353 std::string base = packageProperty != aInst.
props.end() && !packageProperty->second.empty()
1354 ? packageProperty->second
1358 auto it =
m_design.packages.find( base );
1360 if( it ==
m_design.packages.end() )
1367 size_t activePins = 0;
1369 for(
size_t i = 0; i < device.
pinNumbers.size(); ++i )
1375 if( activePins == aInst.
pins.size() )
1382 std::vector<const ORCAD_PACKAGE*>
candidates = { &it->second };
1389 auto sourceProperty = aInst.
props.find(
"Source Library" );
1390 std::string sourceLibrary = sourceProperty != aInst.
props.end() ? sourceProperty->second : std::string();
1392 if( sourceLibrary.empty() )
1395 if( sourceLibrary.empty() && selectedSymbol )
1396 sourceLibrary = selectedSymbol->
sourceLib;
1398 auto candidateFootprint = [](
const ORCAD_PACKAGE& aPackage )
1401 auto property = aPackage.
props.find(
"PCB Footprint" );
1403 if( footprint.empty() && property != aPackage.
props.end() )
1404 footprint =
property->second;
1411 return std::any_of( aPackage.
devices.begin(), aPackage.
devices.end(),
1414 return std::any_of( aDevice.pinNumbers.begin(), aDevice.pinNumbers.end(),
1415 []( const std::string& aNumber )
1417 return !aNumber.empty();
1422 if( !sourceLibrary.empty() )
1425 bool designLibrary = sourceKey.ends_with(
".dsn" );
1426 bool numberedAlternative =
1430 return matchesInstance( *aCandidate ) && hasNumberedPins( *aCandidate );
1435 if( !matchesInstance( *candidate ) ||
normalizedPath( candidate->sourceLib ) != sourceKey )
1438 if( !designLibrary && numberedAlternative && !hasNumberedPins( *candidate ) )
1445 auto footprintProperty = aInst.props.find(
"PCB Footprint" );
1446 std::string footprintKey =
1447 footprintProperty != aInst.props.end() ?
normalizedPath( footprintProperty->second ) :
std::string();
1449 if( !footprintKey.empty() )
1451 std::vector<const ORCAD_PACKAGE*> footprintMatches;
1453 for( const ORCAD_PACKAGE* candidate : candidates )
1455 if( matchesInstance( *candidate ) && normalizedPath( candidateFootprint( *candidate ) ) == footprintKey )
1456 footprintMatches.push_back( candidate );
1459 if( footprintMatches.size() == 1 )
1460 return footprintMatches.front();
1463 auto logicalPinMatches = [&](
const ORCAD_PACKAGE& aPackage )
1465 if( !selectedSymbol || aInst.unitIndex >= aPackage.
devices.size() )
1468 const std::vector<std::string>& numbers = aPackage.
devices[aInst.unitIndex].pinNumbers;
1473 if(
pin.position >= 0 &&
static_cast<size_t>(
pin.position ) < numbers.size() && !
pin.name.empty()
1474 &&
pin.name == numbers[
pin.position] )
1484 int bestLogicalMatches = -1;
1488 if( !matchesInstance( *candidate ) || !hasNumberedPins( *candidate ) )
1491 int logicalMatches = logicalPinMatches( *candidate );
1493 if( logicalMatches > bestLogicalMatches )
1495 bestNumbered = candidate;
1496 bestLogicalMatches = logicalMatches;
1501 return bestNumbered;
1505 if( matchesInstance( *candidate ) )
1516 std::map<std::string, std::string> props = aDef.
props;
1518 auto overlay = [&](
const std::map<std::string, std::string>& aProperties,
bool aAllowEmpty = false )
1520 for(
const auto& [
name, value] : aProperties )
1522 auto existing = std::find_if( props.begin(), props.end(),
1523 [&](
const auto& aProperty )
1525 return OrcadIEquals( aProperty.first, name );
1528 if( existing != props.end() )
1530 if( aAllowEmpty || !value.empty() || existing->second.empty() )
1531 existing->second = value;
1534 props[
name] = value;
1545 auto occurrence =
m_scope.occ->partProps.find( aInst.
dbId );
1547 if( occurrence !=
m_scope.occ->partProps.end() )
1548 overlay( occurrence->second,
true );
1556 const std::string& aNetName )
const
1560 if( !definition || aPinIndex >= aInstance.
pins.size() )
1563 size_t index = symbolPinIndex( *definition, aInstance.
pins[aPinIndex], aPinIndex );
1571 &&
pin.hotptX ==
pin.startX &&
pin.hotptY ==
pin.startY && !
pin.name.empty()
1572 &&
pin.name.compare( 0, 4,
"$PIN" ) != 0 &&
pin.name == aNetName;
1581 auto sourceProperty = aInst.
props.find(
"Source Library" );
1582 std::string sourceLibrary = sourceProperty != aInst.
props.end() ? sourceProperty->second : std::string();
1584 if( sourceLibrary.empty() )
1587 if( sourceLibrary.empty() && sym )
1588 sourceLibrary = sym->sourceLib;
1590 auto packageProperty = aInst.
props.find(
"Source Package" );
1591 std::string sourcePackage = packageProperty != aInst.
props.end() && !packageProperty->second.empty()
1592 ? packageProperty->second
1596 std::string srcOrPkg = sourceLibrary +
"\n" + sourcePackage;
1598 auto footprintProperty = aInst.
props.find(
"PCB Footprint" );
1600 if( footprintProperty != aInst.
props.end() )
1601 srcOrPkg +=
"\n" + footprintProperty->second;
1602 std::string base = sourcePackage;
1608 warn( wxString::Format(
_(
"No cached symbol for '%s' (%s); placeholder emitted." ),
1614 if( slot.
name.empty() )
1629 auto unitRefIt =
m_scope.occ->partUnitRefs.find( aInst.
dbId );
1631 if( unitRefIt !=
m_scope.occ->partUnitRefs.end() )
1632 letter = unitRefIt->second;
1635 if( letter.empty() && pkg )
1636 letter = packageUnitLetter( *pkg, unitIndex );
1640 std::vector<std::string> pinNumbers;
1641 std::vector<bool> pinIgnore;
1645 bool foundDevice =
false;
1647 if( unitIndex < pkg->devices.size() )
1649 pinNumbers = pkg->
devices[unitIndex].pinNumbers;
1650 pinIgnore = pkg->
devices[unitIndex].pinIgnore;
1654 std::string bare = letter.substr( 0, letter.find(
':' ) );
1670 if( !foundDevice && !pkg->
devices.empty() && bare.empty() )
1672 pinNumbers = pkg->
devices.front().pinNumbers;
1673 pinIgnore = pkg->
devices.front().pinIgnore;
1677 std::string normalizedSourceLibrary =
normalizedPath( sourceLibrary );
1680 bool logicalNumbers = std::all_of( sym->pins.begin(), sym->pins.end(),
1683 return !aPin.name.empty()
1684 && std::all_of( aPin.name.begin(), aPin.name.end(),
1685 []( unsigned char c )
1687 return std::isdigit( c );
1690 bool packagePinCountMatches = pkg
1691 && std::any_of( pkg->devices.begin(), pkg->devices.end(),
1694 size_t activePins = 0;
1696 for( size_t i = 0; i < aDevice.pinNumbers.size(); ++i )
1698 if( i >= aDevice.pinIgnore.size() || !aDevice.pinIgnore[i] )
1704 return activePins == aInst.pins.size();
1706 bool stalePackageMap = logicalNumbers && pkg && pkg->devices.size() == 1
1707 && !normalizedSourceLibrary.ends_with(
".dsn" )
1708 && normalizedPackageLibrary != normalizedSourceLibrary;
1710 if( logicalNumbers && pkg && !packagePinCountMatches && normalizedPackageLibrary != normalizedSourceLibrary )
1712 pinNumbers.resize( sym->pins.size() );
1713 pinIgnore.assign( sym->pins.size(),
false );
1715 for(
size_t pi = 0; pi < sym->pins.size(); ++pi )
1717 int position = sym->pins[pi].position >= 0 ? sym->pins[pi].position :
static_cast<int>( pi );
1719 if( position >= 0 &&
static_cast<size_t>( position ) < pinNumbers.size() )
1720 pinNumbers[position] = sym->pins[pi].name;
1724 bool packageUsesLogicalPinNames = vi > 0 && sym->pins.size() == 2 && pinNumbers.size() == 2;
1726 if( packageUsesLogicalPinNames )
1728 for(
size_t pi = 0; pi < sym->pins.size(); ++pi )
1730 int position = sym->pins[pi].position >= 0 ? sym->pins[pi].position :
static_cast<int>( pi );
1732 if( position < 0 ||
static_cast<size_t>( position ) >= pinNumbers.size()
1733 || !
OrcadIEquals( pinNumbers[position], sym->pins[pi].name ) )
1735 packageUsesLogicalPinNames =
false;
1741 if( packageUsesLogicalPinNames && normalizedSourceLibrary.ends_with(
".dsn" ) )
1743 const std::map<std::string, std::string> diodeNumbers = {
1744 {
"a",
"2" }, {
"anode",
"2" }, {
"k",
"1" }, {
"cathode",
"1" }
1746 bool diodePins =
true;
1751 diodePins = diodePins && diodeNumbers.count(
name );
1756 for(
size_t pi = 0; pi < sym->pins.size(); ++pi )
1758 int position = sym->pins[pi].position >= 0 ? sym->pins[pi].position :
static_cast<int>( pi );
1760 pinNumbers[position] = diodeNumbers.at(
name );
1765 bool blankPackageMap = !pinNumbers.empty()
1766 && std::all_of( pinNumbers.begin(), pinNumbers.end(),
1767 [](
const std::string& aNumber )
1769 return aNumber.empty();
1771 std::vector<bool> pinNumberVisible = nonblankPinNumbers( pinNumbers );
1773 bool dualRowConnector =
1774 sym->synthesized && pinNumbers.size() == sym->pins.size() && pinNumbers.size() % 2 == 0
1777 if( blankPackageMap && dualRowConnector )
1779 size_t half = pinNumbers.size() / 2;
1780 std::set<int> positions;
1782 for(
size_t pi = 0; pi < sym->pins.size(); ++pi )
1784 int position = sym->pins[pi].position >= 0 ? sym->pins[pi].position :
static_cast<int>( pi );
1786 if( position >= 0 &&
static_cast<size_t>( position ) < pinNumbers.size() )
1787 positions.insert( position );
1790 if( positions.size() == pinNumbers.size() )
1792 for(
size_t position = 0; position < pinNumbers.size(); ++position )
1794 size_t number = position < half ? 2 * position + 1 : 2 * ( position - half + 1 );
1795 pinNumbers[position] = std::to_string( number );
1796 pinNumberVisible[position] =
true;
1801 if( !pinNumbers.empty() )
1803 for(
size_t pi = 0; pi < sym->pins.size(); ++pi )
1805 int position = sym->pins[pi].position >= 0 ? sym->pins[pi].position :
static_cast<int>( pi );
1807 if( position >= 0 &&
static_cast<size_t>( position ) < pinNumbers.size() && pinNumbers[position].empty()
1808 && (
static_cast<size_t>( position ) >= pinIgnore.size() || !pinIgnore[position] ) )
1810 pinNumbers[position] = sym->pins[pi].name;
1815 if( !normalizedSourceLibrary.ends_with(
".dsn" ) && sym->pins.size() == 2 && logicalNumbers && pkg
1816 && pkg->devices.size() == 1 )
1818 for(
size_t pi = 0; pi < sym->pins.size(); ++pi )
1820 int position = sym->pins[pi].position >= 0 ? sym->pins[pi].position :
static_cast<int>( pi );
1822 if( position >= 0 &&
static_cast<size_t>( position ) < pinNumbers.size() && stalePackageMap
1823 && (
static_cast<size_t>( position ) >= pinIgnore.size() || !pinIgnore[position] ) )
1825 pinNumbers[position] = sym->pins[pi].name;
1830 std::vector<int> pinOffsets( sym->pins.size() );
1831 std::vector<bool> explicitPinNets( sym->pins.size() );
1832 std::vector<int> placedOffsets = placedStackedPinOffsets( aInst );
1834 for(
size_t i = 0; i < aInst.pins.size(); ++i )
1836 size_t symbolPin = symbolPinIndex( *sym, aInst.pins[i], i );
1838 if( symbolPin < pinOffsets.size() )
1840 pinOffsets[symbolPin] = placedOffsets[i];
1842 if( !aInst.pins[i].IsNoConnect() && ( aInst.pins[i].wordA || aInst.pins[i].wordB )
1843 && !m_currentImplicitPowerPins.count( &aInst.pins[i] ) )
1844 explicitPinNets[symbolPin] =
true;
1848 PKG_KEY key{ srcOrPkg, aInst.pkgName, vi, letter };
1852 *aSourceUnit =
nullptr;
1853 auto prepared = m_preparedPkgToLib.find( key );
1855 if( prepared != m_preparedPkgToLib.end() )
1857 *aSourceUnit = &prepared->first;
1862 for(
const auto& [sourceKey, selection] : m_preparedPkgToLib )
1864 if( std::get<0>( sourceKey ) != srcOrPkg || std::get<1>( sourceKey ) != aInst.pkgName
1865 || std::get<2>( sourceKey ) != vi )
1868 const UNIT_INFO&
source = m_preparedLibUnits.at( selection.first )[selection.second - 1];
1870 if(
source.symbol == sym &&
source.pinNumbers == pinNumbers )
1874 *aSourceUnit =
nullptr;
1878 *aSourceUnit = &sourceKey;
1884 auto found = m_pkgToLib.find( key );
1886 if( found != m_pkgToLib.end() )
1888 auto libIt = m_libSymbols.find( found->second.first );
1889 int cachedUnit = found->second.second;
1891 if( libIt != m_libSymbols.end() && cachedUnit > 0
1892 &&
static_cast<size_t>( cachedUnit ) <= libIt->second.units.size() )
1894 const UNIT_INFO& cached = libIt->second.units[cachedUnit - 1];
1896 if( cached.pinNumbers == pinNumbers && cached.pinNumberVisible == pinNumberVisible
1897 && cached.pinIgnore == pinIgnore && cached.pinOffsets == pinOffsets
1898 && cached.explicitPinNets == explicitPinNets )
1899 return found->second;
1903 std::string libnameBase = SymbolId( base );
1906 libnameBase +=
"_v" + std::to_string( vi + 1 );
1908 std::string libname =
1909 uniqueLibName( libnameBase,
1910 [&](
const LIB_ENTRY& aLib )
1912 auto unit = std::find_if( aLib.units.begin(), aLib.units.end(),
1913 [&](
const UNIT_INFO& aUnit )
1915 return aUnit.letter == letter;
1918 return unit == aLib.units.end()
1919 || ( unit->pinNumbers == pinNumbers && unit->pinNumberVisible == pinNumberVisible
1920 && unit->pinIgnore == pinIgnore && unit->pinOffsets == pinOffsets
1921 && unit->explicitPinNets == explicitPinNets );
1924 LIB_ENTRY& ls = m_libSymbols[libname];
1926 if( ls.name.empty() )
1929 ls.refPrefix = ( pkg && !pkg->refDes.empty() ) ? pkg->refDes :
"U";
1930 ls.footprint = pkg ? pkg->pcbFootprint :
"";
1935 for(
size_t i = 0; i < ls.units.size(); ++i )
1937 if( ls.units[i].letter == letter )
1939 unitNo = (int) i + 1;
1947 unit.letter = letter;
1949 unit.pinNumbers = pinNumbers;
1950 unit.pinNumberVisible = pinNumberVisible;
1951 unit.pinIgnore = pinIgnore;
1952 unit.pinOffsets = pinOffsets;
1953 unit.explicitPinNets = explicitPinNets;
1954 ls.units.push_back( std::move( unit ) );
1955 ls.kicadSymbol.reset();
1957 std::stable_sort( ls.units.begin(), ls.units.end(),
1958 [](
const UNIT_INFO& a,
const UNIT_INFO& b )
1960 return unitLetterLess( a.letter, b.letter );
1963 for(
size_t i = 0; i < ls.units.size(); ++i )
1965 if( ls.units[i].letter == letter )
1967 unitNo = (int) i + 1;
1974 for(
auto mapIt = m_pkgToLib.begin(); mapIt != m_pkgToLib.end(); )
1976 if( mapIt->second.first == libname )
1977 mapIt = m_pkgToLib.erase( mapIt );
1982 for(
size_t i = 0; i < ls.units.size(); ++i )
1984 std::string pkgName = sourcePackage + ls.units[i].letter +
".Normal";
1986 m_pkgToLib[PKG_KEY{ srcOrPkg, pkgName, vi, ls.units[i].letter }] = { libname, (int) i + 1 };
1990 m_pkgToLib[key] = { libname, unitNo };
1991 return { libname, unitNo };
1997 std::string libname =
"PWR_" +
SymbolId( aNetName ) +
"_" +
SymbolId( aSymbolName );
2003 auto it =
m_design.symbols.find( aSymbolName );
2014 if( slot.
name.empty() )
2017 slot.
name = aSymbolName;
2032 ls.
units.push_back( std::move( unit ) );
2054 std::unique_ptr<LIB_SYMBOL> symbol = std::make_unique<LIB_SYMBOL>(
name );
2056 symbol->SetPinNameOffset( schMm( 0.254 ) );
2059 bool defaultShowPinNames = symbol->GetShowPinNames();
2060 bool defaultShowPinNumbers = symbol->GetShowPinNumbers();
2067 defaultShowPinNumbers = ( flags & 0x04 ) == 0;
2068 defaultShowPinNames = ( flags & 0x01 ) != 0;
2073 bool showPinNames = defaultShowPinNames;
2074 bool showPinNumbers = defaultShowPinNumbers;
2081 for(
size_t pinIndex = 0; pinIndex < unit.
symbol->
pins.size(); ++pinIndex )
2084 int position = sourcePin.
position >= 0 ? sourcePin.
position :
static_cast<int>( pinIndex );
2103 symbol->SetShowPinNames( showPinNames );
2104 symbol->SetShowPinNumbers( showPinNumbers );
2107 symbol->SetGlobalPower();
2109 if( std::any_of( entry.
units.begin(), entry.
units.end(),
2112 return aUnit.convert != nullptr;
2115 symbol->SetHasDeMorganBodyStyles(
true );
2118 if( (
int) entry.
units.size() > 1 )
2120 symbol->SetUnitCount( (
int) entry.
units.size(),
false );
2122 for(
size_t unit = 0; unit < entry.
units.size(); ++unit )
2123 symbol->GetUnitDisplayNames()[
static_cast<int>( unit ) + 1] = wxEmptyString;
2133 SCH_FIELD& refField = symbol->GetReferenceField();
2134 SCH_FIELD& valField = symbol->GetValueField();
2138 refField.
SetText( wxS(
"#PWR" ) );
2158 symbol->GetFootprintField().SetVisible(
false );
2159 symbol->GetDatasheetField().SetVisible(
false );
2162 auto stampBodyStyle =
2163 [&](
int aUnit,
int aBodyStyle )
2165 for(
SCH_ITEM& item : symbol->GetDrawItems() )
2168 item.SetBodyStyle( aBodyStyle );
2172 for(
size_t ui = 0; ui < entry.
units.size(); ++ui )
2175 int unitNo = (int) ui + 1;
2180 const int bodyStyles = unit.
convert ? 2 : 1;
2182 for(
int bodyStyle = 1; bodyStyle <= bodyStyles; ++bodyStyle )
2185 const int stamp = unit.
convert ? bodyStyle : 0;
2187 for(
size_t primitiveIndex = 0; primitiveIndex < view.
primitives.size(); ++primitiveIndex )
2191 if( laterRectangleOccludesTextUnderscores( view.
primitives, primitiveIndex ) )
2194 std::replace( visible.
text.begin(), visible.
text.end(),
'_',
' ' );
2204 stampBodyStyle( unitNo, stamp );
2206 BOX2I bodyBox = symbol->GetBodyBoundingBox( unitNo, stamp,
false,
false );
2208 for(
size_t pi = 0; pi < view.
pins.size(); ++pi )
2211 int position = view.
pins[pi].position >= 0 ? view.
pins[pi].position
2212 :
static_cast<int>( pi );
2214 if( position <
static_cast<int>( unit.
pinIgnore.size() ) && unit.
pinIgnore[position] )
2217 wxString number = position < static_cast<int>( unit.
pinNumbers.size() )
2219 : wxString::Format( wxS(
"%d" ), (
int) pi + 1 );
2222 sourcePin.
hotptX += pinOffset;
2223 sourcePin.
startX += pinOffset;
2234 emit.
hidden = pinOffset != 0;
2236 addSymbolPin( symbol.get(), sourcePin, bodyBox, std::move( emit ) );
2240 stampBodyStyle( unitNo, stamp );
2251 uint32_t aModifyTimestamp )
2274 int aOffsetX,
int aOffsetY )
2278 auto toX = [aOffsetX](
int aV )
2282 auto toY = [aOffsetY](
int aV )
2287 switch( aPrim.
kind )
2300 shape->
SetStroke( strokeFor( aPrim, aColor ) );
2314 shape->
SetStroke( strokeFor( aPrim, aColor ) );
2324 if( aPrim.
points.size() < 2 )
2334 if( isPolygon && aPrim.
points.front() != aPrim.
points.back() )
2337 shape->
SetStroke( strokeFor( aPrim, aColor ) );
2352 if( aPrim.
points.size() < 4 || ( aPrim.
points.size() - 1 ) % 3 != 0 )
2354 if( aPrim.
points.size() >= 2 )
2361 shape->
SetStroke( strokeFor( aPrim, aColor ) );
2370 for(
size_t i = 0; i + 3 < aPrim.
points.size(); i += 3 )
2377 shape->
SetStroke( strokeFor( aPrim, aColor ) );
2388 double cx = ( aPrim.
x1 + aPrim.
x2 ) / 2.0;
2389 double cy = ( aPrim.
y1 + aPrim.
y2 ) / 2.0;
2399 shape->
SetStroke( strokeFor( aPrim, aColor ) );
2411 for(
int k = 0; k <= 32; ++k )
2413 double a = 2.0 *
M_PI * k / 32.0;
2414 shape->
AddPoint(
VECTOR2I( dbuIu( cx + rx * std::cos( a ) ), dbuIu( cy + ry * std::sin( a ) ) ) );
2417 shape->
SetStroke( strokeFor( aPrim, aColor ) );
2432 bool multiline = aPrim.
text.find(
'\n' ) != std::string::npos;
2433 bool hasBox = aPrim.
x1 != aPrim.
x2 || aPrim.
y1 != aPrim.
y2;
2434 int textX = hasBox && !multiline ? ( aPrim.
x1 + aPrim.
x2 ) / 2 : aPrim.
x1;
2435 int textY = hasBox ? ( aPrim.
y1 + aPrim.
y2 ) / 2 : aPrim.
y1;
2436 int boxedTextYOffset = 0;
2448 if(
std::abs( quarterTurns ) % 2 == 1 )
2461 BOX2I inkBox =
text->GetEffectiveTextShape(
false )->BBox();
2466 int inkHeight =
KiROUND( boxHeight * 0.7 );
2471 size.
x =
KiROUND(
static_cast<double>( size.
x ) * inkWidth / inkBox.
GetWidth() );
2473 text->SetTextSize( size );
2474 boxedTextYOffset = ( boxHeight - inkHeight ) / 4;
2480 text->SetPosition(
VECTOR2I( toX( textX ), toY( textY ) + boxedTextYOffset ) );
2482 text->SetUnit( aUnit );
2495 int aOffsetX,
int aOffsetY )
2503 double cx = ( aPrim.
x1 + aPrim.
x2 ) / 2.0;
2504 double cy = ( aPrim.
y1 + aPrim.
y2 ) / 2.0;
2514 double a0 = std::atan2( ( aPrim.
start->y - cy ) / ry, ( aPrim.
start->x - cx ) / rx );
2515 double a1 = std::atan2( ( aPrim.
end->y - cy ) / ry, ( aPrim.
end->x - cx ) / rx );
2522 int steps = std::max( 4, (
int) (
std::abs( a1 - a0 ) / (
M_PI / 16.0 ) ) );
2527 for(
int k = 0; k <= steps; ++k )
2529 double a = a0 + ( a1 - a0 ) * k / steps;
2531 VECTOR2I( dbuIu( cx + rx * std::cos( a ) + aOffsetX ), dbuIu( cy + ry * std::sin( a ) + aOffsetY ) ) );
2534 shape->
SetStroke( strokeFor( aPrim, aColor ) );
2542 const std::function<
bool(
const LIB_ENTRY& )>& aReusable )
const
2544 std::string libname = aBase;
2546 for(
size_t discriminator = 2;; ++discriminator )
2550 if( lib ==
m_libSymbols.end() || aReusable( lib->second ) )
2553 libname = aBase +
"_pins" + std::to_string( discriminator );
2574 bool hiddenPowerStyle = pinLength == 0 && ( aPin.
shapeBits & 0x80 ) != 0;
2576 if( dx == 0 && dy == 0 )
2579 std::array<int, 4> distances = {
2584 switch( std::min_element( distances.begin(), distances.end() ) - distances.begin() )
2586 case 0: dx = 1;
break;
2587 case 1: dx = -1;
break;
2588 case 2: dy = 1;
break;
2589 case 3: dy = -1;
break;
2597 pin->SetLength( pinLength );
2610 pin->SetOrientation( orientation );
2613 bool isClock = ( aPin.
shapeBits & 0x2 ) != 0;
2614 bool isDot = ( aPin.
shapeBits & 0x4 ) != 0;
2616 if( isClock && isDot )
2628 pin->SetVisible(
false );
2635 if( hiddenPowerStyle )
2636 pin->SetVisible(
false );
2640 pin->SetVisible(
false );
2641 pin->SetLength( 0 );
2652 else if( !aPin.
name.empty() && aPin.
name.compare( 0, 4,
"$PIN" ) != 0 )
2657 auto pinTextSize = [&](
int aFontIdx )
2661 if( resolved > 0 && resolved <=
static_cast<int>(
m_design.library.fonts.size() ) )
2664 return schMm( 1.78 );
2667 auto findDisplay = [&](
const char* aName,
const char* aAlternate ) ->
const ORCAD_DISPLAY_PROP*
2672 return OrcadIEquals( aProp.name, aName ) || OrcadIEquals( aProp.name, aAlternate );
2686 int nameFont = nameDisplay && nameDisplay->
fontIdx > 0 ? nameDisplay->
fontIdx :
m_design.library.pinNameFont;
2687 int numberFont = numberDisplay && numberDisplay->
fontIdx > 0 ? numberDisplay->
fontIdx
2692 pin->SetNameTextSize( aEmit.
nameVisible && !
name.IsEmpty() ? pinTextSize( nameFont ) : 0 );
2693 pin->SetNumberTextSize( aEmit.
numberVisible && !aEmit.
number.IsEmpty() ? pinTextSize( numberFont ) : 0 );
2698 pin->SetNameTextSize( 0 );
2699 pin->SetNumberTextSize( 0 );
2706 VECTOR2I direction( ( dx > 0 ) - ( dx < 0 ), ( dy > 0 ) - ( dy < 0 ) );
2709 VECTOR2I base = apex - direction * dbuIu( 4 );
2713 wedge->
AddPoint( base + halfWidth );
2714 wedge->
AddPoint( base - halfWidth );
2726 switch( aOrient & 7 )
2743 using PART_KEY = std::pair<const void*, wxString>;
2744 std::map<PART_KEY, size_t> indices;
2745 std::vector<std::vector<const PLACED_PACKAGE_UNIT*>> parts;
2749 auto [entry, inserted] = indices.emplace( PART_KEY{ unit.scope, unit.reference }, parts.size() );
2752 parts.emplace_back();
2754 parts[entry->second].push_back( &unit );
2757 for(
const auto& part : parts )
2765 std::set<size_t> placedUnits;
2766 std::vector<size_t> unitIndices;
2767 bool compatible = !first.
reference.empty() && !first.
reference.EndsWith( wxS(
"?" ) );
2772 size_t index =
static_cast<size_t>(
source.second - 1 );
2774 if(
source.first != templateName || std::get<0>( *placed->sourceUnit ) != std::get<0>( *first.
sourceUnit )
2775 ||
index >= units.size() || !placedUnits.insert(
index ).second )
2781 units[
index] = placed->unit;
2782 unitIndices.push_back(
index );
2785 std::set<std::string> letters;
2788 compatible &= letters.insert( unit.letter ).second;
2792 warn( wxString::Format(
_(
"Native power units for '%s' have ambiguous package identity; "
2793 "their symbol definitions were kept separate." ), first.
reference ) );
2800 return aLib.
units == units;
2803 auto [entry, inserted] =
m_libSymbols.try_emplace( libname );
2808 entry->second.name = libname;
2809 entry->second.units = std::move( units );
2810 entry->second.refPrefix =
source.refPrefix;
2811 entry->second.footprint =
source.footprint;
2823 for(
size_t i = 0; i < part.size(); ++i )
2826 int targetUnit =
static_cast<int>( unitIndices[i] + 1 );
2827 std::vector<SCH_ITEM*> replaced;
2831 if( item.GetUnit() == targetUnit && item.Type() !=
SCH_FIELD_T )
2832 replaced.push_back( &item );
2843 copy->SetUnit( targetUnit );
2853 for(
size_t i = 0; i < part.size(); ++i )
2857 int unit =
static_cast<int>( unitIndices[i] + 1 );
2858 screen->
Remove( symbol );
2864 screen->
Append( symbol );
2875 const PKG_KEY* sourceUnit =
nullptr;
2883 int w = bb.
x2 - bb.
x1;
2884 int h = bb.
y2 - bb.
y1;
2891 if( !aInst.
pins.empty() && !symbolPinsMatch( def, aInst ) )
2895 note( wxString::Format(
_(
"Page %s: %s uses a synthesized placeholder at a "
2896 "different orientation; pin layout approximate." ),
2901 warn( wxString::Format(
_(
"Page %s: %s pin positions mismatch (orientation %d); "
2902 "geometry may be off." ),
2915 std::vector<std::pair<SCH_TEXT*, SCH_SHAPE*>> degreeMarks;
2917 auto circleTouchesStroke =
2920 int64_t radiusSquared =
static_cast<int64_t
>( aCircle.GetRadius() ) * aCircle.GetRadius();
2934 if( ( point - aCircle.GetPosition() ).SquaredEuclideanNorm() <= radiusSquared )
2960 || circleTouchesStroke( *shape ) )
2968 degreeMarks.emplace_back(
text, shape );
2982 bool degreeCue = std::any_of( degreeMarks.begin(), degreeMarks.end(),
2983 [&](
const auto& aPair )
2985 return aPair.first == &text;
2992 BOX2I glyphBox =
text.GetEffectiveTextShape(
false )->BBox();
3003 bool sourceVertical =
text.GetTextAngle().IsVertical();
3006 VECTOR2I canvasPosition = sourceCanvas - canvasOffset +
VECTOR2I( 0, baseline );
3008 text.SetPosition( target );
3013 for(
const auto& [
text, degree] : degreeMarks )
3016 int radius = degree->GetRadius();
3019 degree->SetPosition( degreeLocal );
3023 std::vector<SCH_ITEM*> pinTexts;
3030 pinTexts.push_back( &item );
3039 std::map<std::string, std::string> props =
effectiveProps( aInst, def );
3041 auto occurrenceProperty = [&](
const char* aName ) ->
const std::string*
3046 auto occurrence =
m_scope.occ->partProps.find( aInst.
dbId );
3048 if( occurrence ==
m_scope.occ->partProps.end() )
3051 auto property = std::find_if( occurrence->second.begin(), occurrence->second.end(),
3052 [&](
const auto& aProperty )
3054 return OrcadIEquals( aProperty.first, aName );
3056 return property != occurrence->second.end() ? &
property->second :
nullptr;
3059 const std::string* occurrenceValue = occurrenceProperty(
"Value" );
3060 std::string value = occurrenceValue ? *occurrenceValue : aInst.
value;
3062 if( !occurrenceValue && value.empty() )
3064 auto vIt = props.find(
"Value" );
3066 if( vIt != props.end() )
3067 value = vIt->second;
3070 if( !occurrenceValue && value.empty() )
3073 auto installed = std::find_if( props.begin(), props.end(),
3074 [](
const auto& aProperty )
3076 return isInstalledPropertyName( aProperty.first );
3078 bool notInstalled = installed != props.end() &&
OrcadIEquals( installed->second,
"NI" );
3080 const std::string* occurrenceFootprint = occurrenceProperty(
"PCB Footprint" );
3081 std::string footprint = occurrenceFootprint ? *occurrenceFootprint : std::string();
3082 auto fIt = props.find(
"PCB Footprint" );
3084 if( !occurrenceFootprint && fIt != props.end() )
3085 footprint = fIt->second;
3087 if( !occurrenceFootprint && footprint.empty() )
3099 && field.GetText().CmpNoCase( wxS(
"NI" ) ) == 0 )
3101 notInstalled =
true;
3113 if( valueField && valueField->
IsVisible() )
3114 valueField->
SetText( wxS(
"NI" ) );
3117 symbol->
SetRef( &aSheetPath, reference );
3122 bool nativePower = std::any_of( aInst.
pins.begin(), aInst.
pins.end(),
3125 return m_currentImplicitPowerPins.count( &aPin );
3127 const void* scope =
m_scope.occ ?
static_cast<const void*
>( &
m_scope.occ->partRefs ) : aScreen;
3135 if( def.
pins.empty() && aInst.
pins.empty() )
3150 if( pi < def.
pins.size() )
3152 size_t position = def.
pins[pi].position >= 0 ? def.
pins[pi].position : pi;
3155 : wxString::Format( wxS(
"%zu" ), pi + 1 );
3168 sourcePins.push_back( std::move( identity ) );
3176 if(
pin.IsNoConnect() && !
pin.wordA && !
pin.wordB )
3203 if(
auto installed = cis.
installed.find( occurrence->second ); installed != cis.
installed.end() )
3204 variant.
m_DNP = !installed->second;
3210 if(
auto props = cis.
props.find( occurrence->second ); props != cis.
props.end() )
3212 for(
const auto& [property, value] : props->second )
3214 wxString fieldName = propertyFieldName( property );
3217 if( fieldName.IsEmpty() || value ==
"UNDEFINED" )
3230 field = aSymbol->
AddField( added );
3252 auto it =
m_scope.occ->partRefs.find( aInst.
dbId );
3254 if( it !=
m_scope.occ->partRefs.end() )
3258 if( !occurrence.IsEmpty() && !occurrence.EndsWith( wxS(
"?" ) ) )
3259 reference = occurrence;
3263 if( reference.IsEmpty() )
3264 reference = wxS(
"?" );
3285 int w = bb.
x2 - bb.
x1;
3286 int h = bb.
y2 - bb.
y1;
3291 int bx = hasBbox ? std::min( aInst.
bbox.
x1, aInst.
bbox.
x2 ) : aInst.
x;
3292 int by = hasBbox ? std::min( aInst.
bbox.
y1, aInst.
bbox.
y2 ) : aInst.
y;
3297 wxString reference = wxString::Format( wxS(
"#PWR%04d" ),
m_powerCount );
3321 auto nameProperty = aInst.
props.find(
"Name" );
3322 std::string displayName = nameProperty != aInst.
props.end() ? nameProperty->second : std::string();
3330 auto displayedName =
3334 return OrcadIEquals( aProp.name,
"Name" ) || OrcadIEquals( aProp.name,
"NODENAME" );
3341 : !logicalName.empty() ? logicalName
3356 symbol->
SetRef( &aSheetPath, reference );
3365 const std::string& aFootprint )
3370 int w = bb.
x2 - bb.
x1;
3371 int h = bb.
y2 - bb.
y1;
3376 int bxmin = std::min( c1.
x, c2.
x );
3377 int bxmax = std::max( c1.
x, c2.
x );
3378 int bymin = std::min( c1.
y, c2.
y );
3379 int bymax = std::max( c1.
y, c2.
y );
3387 bool vertical = angle == 90 || angle == 270;
3391 bool showRef =
false;
3392 bool showVal =
false;
3393 bool showRefName =
false;
3394 bool showValName =
false;
3396 auto findReferenceDisplay = [&](
const char* aName,
bool aVisibleOnly ) ->
const ORCAD_DISPLAY_PROP*
3401 return OrcadIEquals( aDisplay.name, aName )
3402 && ( !aVisibleOnly || OrcadDisplayPropVisible( aDisplay ) );
3405 return it != aInst.
displayProps.end() ? &*it :
nullptr;
3408 const ORCAD_DISPLAY_PROP* referenceDisplay = findReferenceDisplay(
"Part Reference",
true );
3410 if( !referenceDisplay )
3411 referenceDisplay = findReferenceDisplay(
"Reference",
true );
3413 if( !referenceDisplay )
3414 referenceDisplay = findReferenceDisplay(
"Part Reference",
false );
3416 if( !referenceDisplay )
3417 referenceDisplay = findReferenceDisplay(
"Reference",
false );
3419 if( referenceDisplay )
3443 bool side = !vertical && aDef.
pins.size() == 2 && aInst.
pins.size() == 2
3449 int ry = showVal ? cym - schMm( 0.9 ) : cym;
3480 std::map<std::string, std::pair<VECTOR2I, const ORCAD_DISPLAY_PROP*>> shown;
3484 auto value = std::make_pair(
OrcadDbuToIu( aInst.
x + dp.
x, aInst.
y + dp.
y ), &dp );
3486 if( &dp == referenceDisplay )
3487 shown[
"Part Reference"] = value;
3491 shown[dp.
name] = value;
3494 auto findShown = [&](
const std::string& aName )
3496 auto exact = shown.find( aName );
3498 if( exact != shown.end() )
3501 return std::find_if( shown.begin(), shown.end(),
3502 [&](
const auto& aItem )
3504 return OrcadIEquals( aItem.first, aName );
3520 content += wxS(
" = " ) + aField->
GetText();
3541 if( !fpName.IsEmpty() )
3546 auto shownFootprint = findShown(
"PCB Footprint" );
3548 if( shownFootprint != shown.end() )
3553 drawDisplayedField( &fpMeta, dp );
3574 auto applyDisplayPos = [&](
SCH_FIELD* aField,
const char* aName )
3576 auto it = findShown( aName );
3578 if( it == shown.end() )
3581 applyDisplayProp( *aField, *it->second.second, it->second.first, symbolFlips,
false );
3584 applyDisplayPos( refField,
"Part Reference" );
3585 applyDisplayPos( valField,
"Value" );
3587 if(
auto shownValue = findShown(
"Value" ); shownValue != shown.end() )
3588 drawDisplayedField( valField, *shownValue->second.second );
3590 std::map<std::string, std::string> properties =
effectiveProps( aInst, aDef );
3592 auto partReference = std::find_if( properties.begin(), properties.end(),
3593 [](
const auto& aProperty )
3595 return OrcadIEquals( aProperty.first,
"Part Reference" );
3600 wxString displayedText;
3602 if( partReference != properties.end() && !occurrenceOverridesReference )
3608 std::string unitDesignator;
3612 auto unitRef =
m_scope.occ->partUnitRefs.find( aInst.
dbId );
3614 if( unitRef !=
m_scope.occ->partUnitRefs.end() )
3615 unitDesignator = unitRef->second;
3620 if( unitDesignator.empty() && package && aInst.
unitIndex < package->devices.size() )
3621 unitDesignator = package->devices[aInst.
unitIndex].unitRef;
3623 if( unitDesignator.empty() && !package )
3626 if( unitDesignator.empty() && package && package->devices.size() > 1 )
3629 unitDesignator = unitDesignator.substr( 0, unitDesignator.find(
':' ) );
3631 if( !unitDesignator.empty() && unitDesignator.front() !=
'#' )
3632 displayedText = resolvedReference +
FromOrcadString( unitDesignator );
3637 if( !displayedText.IsEmpty() && displayedText != resolvedReference )
3642 displayedReference.
SetText( displayedText );
3645 applyDisplayPos( &displayedReference,
"Part Reference" );
3646 aSymbol->
AddField( displayedReference );
3650 if( findShown(
"Implementation" ) != shown.end() && !aInst.
value.empty() )
3652 auto implementation = std::find_if( properties.begin(), properties.end(),
3653 [](
const auto& aProperty )
3655 return OrcadIEquals( aProperty.first,
"Implementation" );
3658 if( implementation == properties.end() )
3659 properties[
"Implementation"] = aInst.
value;
3660 else if( implementation->second.empty() )
3661 implementation->second = aInst.
value;
3664 static const std::pair<const char*, FIELD_T> standardFields[] = { {
"Description",
FIELD_T::DESCRIPTION },
3667 for(
const auto& [propName, propValue] : properties )
3673 if( isBookkeepingProp( propName ) && findShown( propName ) == shown.end() )
3676 bool unset = propValue.empty() || propValue ==
"<" + propName +
">";
3677 auto standardField = std::find_if( std::begin( standardFields ), std::end( standardFields ),
3678 [&](
const auto& aStandard )
3685 if( standardField != std::end( standardFields ) )
3689 std::vector<SCH_FIELD*> fields;
3705 if( standardField != std::end( standardFields ) )
3710 if(
auto shownStandard = findShown( standardField->first ); shownStandard != shown.end() )
3713 applyDisplayProp( *standard, dp, shownStandard->second.first, symbolFlips );
3714 drawDisplayedField( standard, dp );
3720 wxString fieldName =
OrcadIEquals( propName,
"Footprint" ) ? wxString(
"OrCAD Footprint Property" )
3725 auto sIt = findShown( propName );
3727 if( sIt != shown.end() )
3732 drawDisplayedField( &field, dp );
3748 std::map<int, int> counts;
3749 std::vector<int> order;
3751 auto tally = [&](
int aFontIdx,
bool aTemplateFont = true )
3758 auto [it, isNew] = counts.try_emplace( height, 0 );
3761 order.push_back( height );
3784 for(
int height : order )
3786 if( counts[height] > bestCount )
3789 bestCount = counts[height];
3820 const VECTOR2I& aAnchorIu,
bool aSymbolFlips,
bool aApplyVisibility )
const
3824 bool vertical = ( aDisplay.
rotation & 1 ) != 0;
3829 applyFont( &aField, fontId, templateFont );
3836 if( aApplyVisibility )
3846 if( !
m_design.library.templateFonts.empty() )
3860 if( resolved > 0 && resolved <=
static_cast<int>(
m_design.library.fonts.size() ) )
3864 if( face ==
"arial narrow" )
3865 return KiROUND( aTextSize * (
m_design.library.fonts[resolved - 1].bold ? 0.62 : 0.47 ) );
3867 if( face ==
"verdana" )
3868 return KiROUND( aTextSize * 0.675 );
3877 const std::vector<int>& templateFonts =
m_design.library.templateFonts;
3879 if( !templateFonts.empty() && aFontIdx >= 0 && aFontIdx <
static_cast<int>( templateFonts.size() ) )
3881 int mapped = templateFonts[aFontIdx];
3886 if( templateFonts.front() > 0 )
3887 return templateFonts.front();
3890 if( aFontIdx == 0 && !
m_design.library.fonts.empty() )
3902 if( aFontIdx > 0 && aFontIdx <= (
int)
m_design.library.fonts.size() )
3914 return schMm( 1.27 );
3916 double compensation = 1.4;
3919 if( resolved > 0 && resolved <=
static_cast<int>(
m_design.library.fonts.size() ) )
3923 if( face ==
"arial narrow" )
3924 compensation =
m_design.library.fonts[resolved - 1].bold ? 1.6 : 1.46;
3925 else if( face ==
"verdana" )
3926 compensation = 1.46;
3929 double mm = std::round( height * 25.4 / ( 96.0 * compensation ) * 100.0 ) / 100.0;
3937 int height =
textSizeIU( aFontIdx, aTemplateFont );
3942 if( aFontIdx <= 0 || aFontIdx >
static_cast<int>(
m_design.library.fonts.size() ) )
3947 constexpr uint8_t c_FIXED_PITCH = 1;
3949 if( font.
width == 0 )
3956 double averageEmRatio = 0.5;
3958 if( face ==
"arial narrow" )
3961 averageEmRatio = font.
bold ? 803.0 / 2048.0 : 0.358;
3965 double mm = std::round(
schIUScale.IUTomm( height ) * aspect * 100.0 ) / 100.0;
3966 return VECTOR2I( schMm( mm ), height );
3969 double mm = std::round(
std::abs( font.
width ) * 25.4 * 0.9 / 96.0 * 100.0 ) / 100.0;
3971 return VECTOR2I( schMm( mm ), height );
3980 if( !aText || aFontIdx <= 0 || aFontIdx >
static_cast<int>(
m_design.library.fonts.size() ) )
3987 if( !font.
face.empty() )
3990 const std::vector<wxString>* embeddedFonts =
nullptr;
3992 if( face.CmpNoCase( wxS(
"Elephant" ) ) == 0 )
3994 face = wxS(
"KiCad OrCAD Elephant" );
3996 + wxS(
"/KiCadOrCADElephant-Black.ttf" ) );
3999 if( files->
AddFile( fontFile,
false ) )
4013 if( !aText || aText->
GetText().Find(
'\n' ) == wxNOT_FOUND )
4016 int sourceHeight =
fontHeightDbu( aFontIdx, aTemplateFont );
4018 if( sourceHeight <= 0 )
4022 int sourceInterline = schMm( sourceHeight * 25.4 / 96.0 );
4025 if( kicadInterline > 0 )
4026 aText->
SetLineSpacing(
static_cast<double>( sourceInterline ) / kicadInterline );
4035 for(
unsigned char c : aName )
4038 bool separator = c ==
':' || c ==
'"' || c ==
'/' || c ==
' ' || c ==
'\t' || c ==
'\n' || c ==
'\r'
4039 || c ==
'\f' || c ==
'\v' || c == 0xA0;
4055 size_t first = out.find_first_not_of(
'_' );
4057 if( first == std::string::npos )
4060 size_t last = out.find_last_not_of(
'_' );
4061 out = out.substr( first, last - first + 1 );
4063 return out.empty() ?
"SYM" : out;
static std::optional< VECTOR2D > normalized(const VECTOR2D &aVec)
constexpr EDA_IU_SCALE schIUScale
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
constexpr size_type GetWidth() const
constexpr Vec Centre() const
constexpr size_type GetHeight() const
constexpr coord_type GetLeft() const
constexpr coord_type GetRight() const
constexpr coord_type GetTop() const
constexpr coord_type GetBottom() const
EDA_ITEM * GetParent() const
virtual void SetEnd(const VECTOR2I &aEnd)
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false, bool includeFill=false) const
Convert the shape to a closed polygon.
SHAPE_POLY_SET & GetPolyShape()
virtual void SetBezierC2(const VECTOR2I &aPt)
virtual void SetBezierC1(const VECTOR2I &aPt)
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)
virtual void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true)
virtual const wxString & GetText() const
Return the string associated with the text object.
virtual bool IsVisible() const
virtual void SetTextPos(const VECTOR2I &aPoint)
virtual void SetVisible(bool aVisible)
void SetLineSpacing(double aLineSpacing)
void SetBold(bool aBold)
Set the text to be bold - this will also update the font if needed.
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
void SetItalic(bool aItalic)
Set the text to be italic - this will also update the font if needed.
void SetFont(KIFONT::FONT *aFont)
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
const std::vector< wxString > * UpdateFontFiles()
Helper function to get a list of fonts for fontconfig to add to the library.
EMBEDDED_FILE * AddFile(const wxFileName &aName, bool aOverwrite)
Load a file from disk and adds it to the collection.
void SetAreFontsEmbedded(bool aEmbedFonts)
FONT is an abstract base class for both outline and stroke fonts.
static FONT * GetFont(const wxString &aFontName=wxEmptyString, bool aBold=false, bool aItalic=false, const std::vector< wxString > *aEmbeddedFiles=nullptr, bool aForDrawingSheet=false)
virtual double GetInterline(double aGlyphHeight, const METRICS &aFontMetrics) const =0
Compute the distance (interline) between 2 lines of text (for multiline texts).
A logical library item identifier and consists of various portions much like a URI.
static UTF8 FixIllegalChars(const UTF8 &aLibItemName, bool aLib)
Replace illegal LIB_ID item name characters with underscores '_'.
Define a library symbol object.
LIB_ITEMS_CONTAINER & GetDrawItems()
Return a reference to the draw item list.
void RemoveDrawItem(SCH_ITEM *aItem)
Remove draw aItem from list.
void AddDrawItem(SCH_ITEM *aItem, bool aSort=true)
Add a new draw aItem to the draw object list and sort according to aSort.
void placePowerSymbol(ORCAD_RAW_PAGE &aPage, const ORCAD_GRAPHIC_INST &aInst, const std::string &aNet, SCH_SCREEN *aScreen, const SCH_SHEET_PATH &aSheetPath)
std::string uniqueLibName(const std::string &aBase, const std::function< bool(const LIB_ENTRY &)> &aReusable) const
aBase, or aBase_pinsN for the first N >= 2 whose existing entry is absent or passes aReusable.
bool displayUsesTemplateFont(const ORCAD_DISPLAY_PROP &aProp) const
void computeFontBaseline()
int displayFontId(const ORCAD_DISPLAY_PROP &aProp) const
LIB_ENTRY buildPackageEntry(const ORCAD_PACKAGE &aPackage) const
One unit per package device; a Convert view becomes the unit's DeMorgan body.
std::map< SCH_SYMBOL *, std::vector< SOURCE_PIN_IDENTITY > > m_sourcePinIdentities
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 PIN_LEN_DBU
– constants (calibrated; do not change) -------------------------------------—
std::pair< const ORCAD_SYMBOL_DEF *, int > pickVariant(const ORCAD_PLACED_INSTANCE &aInst) const
Match cached variants to placed pin positions; use the first entry if none matches.
std::map< SCH_SYMBOL *, const ORCAD_PLACED_INSTANCE * > m_sourceInstances
const ORCAD_PACKAGE * packageFor(const ORCAD_PLACED_INSTANCE &aInst) const
The cache package backing a placement, or nullptr when the design has none.
std::map< std::string, std::vector< UNIT_INFO > > m_preparedLibUnits
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.
int resolveFontIndex(int aFontIdx) const
Resolve a Design Template font ID to its 1-based LOGFONT index.
void applyCisVariants(SCH_SYMBOL *aSymbol, const ORCAD_PLACED_INSTANCE &aInst, const SCH_SHEET_PATH &aSheetPath, const std::string &aValue)
Record each CIS variant's installed state and property overrides as KiCad symbol variants.
LIB_SYMBOL * kicadSymbolFor(const std::string &aLibName)
std::map< PKG_KEY, std::pair< std::string, int > > m_pkgToLib
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.
void placeInstance(ORCAD_RAW_PAGE &aPage, const ORCAD_PLACED_INSTANCE &aInst, SCH_SCREEN *aScreen, const SCH_SHEET_PATH &aSheetPath)
int textBaselineOffset(int aTextSize, int aFontIdx, bool aTemplateFont=true) const
int m_fontBaselineDbu
dominant text height; 0 = none
void placeSymbolFields(SCH_SYMBOL *aSymbol, const ORCAD_PLACED_INSTANCE &aInst, const ORCAD_SYMBOL_DEF &aDef, int aOrient, const std::string &aValue, const std::string &aFootprint)
void addSymbolArc(LIB_SYMBOL *aSymbol, const ORCAD_PRIMITIVE &aPrim, int aUnit, int aColor, int aOffsetX=0, int aOffsetY=0)
Polyline approximation of an arc primitive.
SCH_SCREEN * m_pageItemScreen
std::map< std::string, LIB_ENTRY > m_libSymbols
keyed by emitted lib name
static int toKicadOrientation(int aOrient)
int m_powerCount
"#PWR%04d" counter
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.
SCH_SYMBOL * instantiateSymbol(const LIB_SYMBOL &aLibSymbol, const std::string &aLibName, int aUnit, int aOrient, const VECTOR2I &aPos, const SCH_SHEET_PATH &aSheetPath) const
New placement of a library symbol, oriented by an OrCAD orientation code.
void finalizeNativePowerPackages()
void placeDefinitionImages(const ORCAD_SYMBOL_DEF &aDefinition, int aBaseX, int aBaseY, int aOrient, SCH_SCREEN *aScreen)
wxString resolveReference(const ORCAD_PLACED_INSTANCE &aInst) const
Use the occurrence reference when the instance has an unannotated template.
void applyFont(EDA_TEXT *aText, int aFontIdx, bool aTemplateFont=true) const
std::pair< std::string, int > libForInstance(const ORCAD_PLACED_INSTANCE &aInst, const PKG_KEY **aSourceUnit=nullptr)
Returns the registered library name and unit number.
VECTOR2I textSize(int aFontIdx, bool aTemplateFont=true) const
Preserve an explicit LOGFONT width while retaining natural font aspect when it is zero.
std::string unitLetter(const ORCAD_PLACED_INSTANCE &aInst) const
The unit key includes a non-Normal view so DeMorgan graphics remain distinct.
static std::string SymbolId(const std::string &aName)
LIB_ID-safe symbol name: ':', '"', '/' and whitespace runs -> '_'; "SYM" if empty.
bool hasImplicitPowerPinName(const ORCAD_PLACED_INSTANCE &aInstance, size_t aPinIndex, const std::string &aNetName) const
std::map< PKG_KEY, std::pair< std::string, int > > m_preparedPkgToLib
void addSymbolPrimitive(LIB_SYMBOL *aSymbol, const ORCAD_PRIMITIVE &aPrim, int aUnit, int aColor, int aOffsetX=0, int aOffsetY=0)
std::vector< PLACED_PACKAGE_UNIT > m_placedPackageUnits
ORCAD_SYMBOL_DEF synthesizeSymbol(const std::string &aPkgName, const std::vector< const ORCAD_PLACED_INSTANCE * > &aInstances) const
Use placed pin positions to keep uncached symbols connected.
std::tuple< std::string, std::string, int, std::string > PKG_KEY
(sourcePackage-or-pkgName, pkgName, variant index, unit discriminator) -> (lib name,...
std::string powerLibFor(const std::string &aSymbolName, const std::string &aNetName)
Key power symbols by net name because users can rename their ports.
int textSizeIU(int aFontIdx, bool aTemplateFont=true) const
void warn(const wxString &aMsg)
– reporting [orcad_converter_sheet.cpp] ---------------------------------------—
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::vector< LIB_SYMBOL * > BuildSymbolLibrary()
The caller owns the returned library symbols.
static constexpr const char * LIB_NICK
Symbol library nickname used in every emitted LIB_ID.
int wireAliasFontId(const ORCAD_ALIAS &aAlias) const
void addSymbolPin(LIB_SYMBOL *aSymbol, const ORCAD_SYMBOL_PIN &aPin, const BOX2I &aBodyBox, PIN_EMIT aEmit)
VECTOR2I placedPinElectricalPosition(const ORCAD_PLACED_INSTANCE &aInstance, size_t aPinIndex) const
std::set< std::string > m_nativePowerFamilies
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.
int fontHeightDbu(int aFontIdx, bool aTemplateFont=true) const
|lfHeight| of a Design Template font ID; ID 0 selects the template default.
std::map< std::string, std::string > effectiveProps(const ORCAD_PLACED_INSTANCE &aInst, const ORCAD_SYMBOL_DEF &aDef) const
Empty package and placement values must not clear a library property.
VECTOR2I GetPosition() const override
void SetEffectiveHorizJustify(GR_TEXT_H_ALIGN_T)
void SetEffectiveVertJustify(GR_TEXT_V_ALIGN_T)
virtual const wxString & GetText() const override
Return the string associated with the text object.
wxString GetName(bool aUseDefaultName=true) const
Return the field name (not translated).
void SetPosition(const VECTOR2I &aPosition) override
void SetText(const wxString &aText) override
void SetNameShown(bool aShown=true)
Base class for any item which can be embedded within the SCHEMATIC container class,...
virtual void SetUnit(int aUnit)
const KIFONT::METRICS & GetFontMetrics() const
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
bool Remove(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
Remove aItem from the schematic associated with this screen.
void SetPosition(const VECTOR2I &aPos) override
void SetStroke(const STROKE_PARAMS &aStroke) override
void AddPoint(const VECTOR2I &aPosition)
VECTOR2I GetPosition() const override
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
Variant information for a schematic symbol.
void InitializeAttributes(const SCH_SYMBOL &aSymbol)
bool HasDifferentials(const SCH_SYMBOL &aSymbol) const
Return true if the variant carries any differential against the base symbol values,...
void SetLibId(const LIB_ID &aName)
virtual void SetDNP(bool aEnable, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
void SetPosition(const VECTOR2I &aPosition) override
void RemoveField(const wxString &aFieldName)
Remove a user field from the symbol.
std::vector< const SCH_PIN * > GetPins(const SCH_SHEET_PATH *aSheet) const
Retrieve a list of the SCH_PINs for the given sheet path.
SCH_FIELD * FindFieldCaseInsensitive(const wxString &aFieldName)
Search for a SCH_FIELD with aFieldName.
void SetRef(const SCH_SHEET_PATH *aSheet, const wxString &aReference)
Set the reference for the given sheet path for this symbol.
void GetFields(std::vector< SCH_FIELD * > &aVector, bool aVisibleOnly) const override
Populate a std::vector with SCH_FIELDs, sorted in ordinal order.
void SetOrientation(int aOrientation)
Compute the new transform matrix based on aOrientation for the symbol which is applied to the current...
void SetFootprintFieldText(const wxString &aFootprint)
VECTOR2I GetPosition() const override
void SetSchSymbolLibraryName(const wxString &aName)
The name of the symbol in the schematic library symbol list.
void SetValueFieldText(const wxString &aValue, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString)
std::vector< SCH_PIN * > GetGraphicalPins(int aUnit, int aBodyStyle) const override
void AddVariant(const SCH_SHEET_PATH &aInstance, const SCH_SYMBOL_VARIANT &aVariant)
SCH_FIELD * AddField(const SCH_FIELD &aField)
Add a field to the symbol.
void SetUnitSelection(const SCH_SHEET_PATH *aSheet, int aUnitSelection)
Set the selected unit of this symbol on one sheet.
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
void SetLibSymbol(LIB_SYMBOL *aLibSymbol)
Set this schematic symbol library symbol reference to aLibSymbol.
virtual bool GetDNP(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
Set or clear the 'Do Not Populate' flag.
void SetExcludedFromBoard(bool aEnable, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this symbol.
KIFONT::FONT * GetDrawFont(const RENDER_SETTINGS *aSettings) const override
const std::vector< VECTOR2I > & CPoints() const
Represent a set of closed polygons.
void Rotate(const EDA_ANGLE &aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Rotate all vertices by a given angle.
bool IsEmpty() const
Return true if the set is empty (no polygons at all)
const std::vector< SEG > GenerateHatchLines(const std::vector< double > &aSlopes, int aSpacing, int aLineLength) const
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
SHAPE_POLY_SET CloneDropTriangulation() const
Simple container to manage line stroke parameters.
const TRANSFORM & GetTransform() const
std::map< wxString, wxString > m_Fields
static constexpr EDA_ANGLE ANGLE_90
static constexpr EDA_ANGLE ANGLE_VERTICAL
static constexpr EDA_ANGLE ANGLE_HORIZONTAL
@ FILLED_SHAPE
Fill with object color.
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
wxString OleLibWmfFontDirectory()
Locate the bundled libwmf fonts directory, falling back to a search above the executable so running f...
VECTOR2I OrcadDbuToIu(int aX, int aY)
bool OrcadDisplayPropShowsName(const ORCAD_DISPLAY_PROP &aProp)
FILL_T OrcadFillType(int aFillStyle, int aHatchStyle)
ORCAD_POINT OrcadInverseOrient(int aOrient, int aX, int aY)
Undo the orientation matrix of OrcadTransformPoint.
int OrcadTextBaselineOffset(int aTextSize)
int OrcadHatchPitchIu(uint32_t aModifyTimestamp)
bool OrcadDisplayPropShowsValue(const ORCAD_DISPLAY_PROP &aProp)
KIGFX::COLOR4D OrcadColor(int aColorIndex)
int OrcadDisplayFontId(const ORCAD_DISPLAY_PROP &aProp)
wxString OrcadPinNameMarkup(const wxString &aName)
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 OrcadDisplayType(const ORCAD_DISPLAY_PROP &aProp)
bool OrcadDisplayPropShowsName(const ORCAD_DISPLAY_PROP &aProp)
FILL_T OrcadFillType(int aFillStyle, int aHatchStyle)
static bool isInstalledPropertyName(const std::string &aName)
static bool hasDualRowDescription(const std::map< std::string, std::string > &aProps)
int OrcadLineWidthIu(int aWidth)
std::pair< double, double > OrcadDashRatios(int aFormatVersionMajor)
int OrcadTextBaselineOffset(int aTextSize)
std::vector< SEG > OrcadHatchLines(const EDA_SHAPE &aShape, int aHatchStyle, int aPitch)
int OrcadHatchPitchIu(uint32_t aModifyTimestamp)
bool OrcadDisplayPropShowsValue(const ORCAD_DISPLAY_PROP &aProp)
int OrcadHatchLineWidthIu(uint32_t aModifyTimestamp)
static void addOrcadSymbolHatch(LIB_SYMBOL *aSymbol, const SCH_SHAPE &aOutline, const ORCAD_PRIMITIVE &aPrimitive, int aUnit, int aColor, uint32_t aModifyTimestamp)
int OrcadDisplayFontId(const ORCAD_DISPLAY_PROP &aProp)
wxString OrcadPinNameMarkup(const wxString &aName)
static std::string normalizedPath(std::string aPath)
bool OrcadDisplayPropVisible(const ORCAD_DISPLAY_PROP &aProp)
LINE_STYLE OrcadLineStyle(int aStyle)
static LIB_ID libIdFor(const std::string &aLibName)
int OrcadPageGraphicLineWidthIu(int aWidth)
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.
VECTOR2I OrcadOrientOffset(int aOrient, int aWidth, int aHeight)
Bbox re-anchoring offset for the given orientation and body size (DBU).
ORCAD_PORT_TYPE
Map unknown electrical type codes to PASSIVE.
@ ORCAD_ST_GLOBAL_SYMBOL
power symbol definition
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.
ELECTRICAL_PINTYPE
The symbol library pin object electrical types used in ERC tests.
@ PT_INPUT
usual pin input: must be connected
@ PT_TRISTATE
tri state bus pin
@ PT_BIDI
input or output (like port for a microprocessor)
@ PT_OPENEMITTER
pin type open emitter
@ PT_OPENCOLLECTOR
pin type open collector
@ PT_POWER_IN
power input (GND, VCC for ICs). Must be connected to a power output.
@ PT_PASSIVE
pin for passive symbols: must be connected, and can be connected to any pin.
PIN_ORIENTATION
The symbol library pin object orientations.
@ PIN_UP
The pin extends upwards from the connection point: Probably on the bottom side of the symbol.
@ PIN_RIGHT
The pin extends rightwards from the connection point.
@ PIN_LEFT
The pin extends leftwards from the connection point: Probably on the right side of the symbol.
@ PIN_DOWN
The pin extends downwards from the connection: Probably on the top side of the symbol.
std::shared_ptr< PNS_LOG_VIEWER_OVERLAY > overlay
constexpr double correction
Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema.
int StrNumCmp(const wxString &aString1, const wxString &aString2, bool aIgnoreCase)
Compare two strings with alphanumerical content.
LINE_STYLE
Dashed line types.
The owning wire defines the connection.
Axis-aligned box in OrCAD DBU; corner order as stored (not normalized).
A CIS BOM variant, keyed by part occurrence id.
std::map< uint32_t, bool > installed
std::map< uint32_t, std::map< std::string, std::string > > props
One emitted KiCad lib symbol (possibly multi-unit).
std::string name
lib item name (no nickname)
std::unique_ptr< LIB_SYMBOL > kicadSymbol
built lazily by kicadSymbolFor()
std::vector< UNIT_INFO > units
sorted by letter; unit numbers are 1-based indices
std::string powerNet
power symbols are keyed by NET name
Per-pin choices kicadSymbolFor() makes before emitting a pin.
const PKG_KEY * sourceUnit
std::optional< KIID > libraryPin
– shared bookkeeping types ------------------------------------------------—
std::vector< int > pinOffsets
hidden duplicate-pin electrical offsets, DBU
std::vector< bool > pinIgnore
package pins suppressed for this unit
const ORCAD_SYMBOL_DEF * convert
DeMorgan view sharing this unit's pin map.
const ORCAD_SYMBOL_DEF * symbol
std::vector< bool > explicitPinNets
placed pins whose source net overrides implicit power naming
std::vector< std::string > pinNumbers
device pin-number map for this unit
std::string letter
unit discriminator, e.g. "A", "-16", "B:Convert"
std::vector< bool > pinNumberVisible
nonblank source package pin numbers
Device unit names omit the view suffix.
std::vector< std::string > pinNumbers
std::vector< bool > pinIgnore
Display positions use symbol coordinates; rotFont combines the font index and quarter turns.
int fontIdx
1-based into ORCAD_LIBRARY_INFO::fonts; 0 = default
int rotation
0..3 quarter turns
std::string name
resolved property name (empty when index invalid)
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::map< std::string, std::string > props
int rotation
0..3 quarter turns
std::string name
cache symbol name
std::vector< ORCAD_DISPLAY_PROP > displayProps
std::string logicalName
ports: resolved net/port name
Each scope holds the references and child blocks for one instantiation path.
std::map< uint32_t, uint32_t > partOccurrenceIds
dbId -> part occurrence id
OrCAD rotates about the bounding box; KiCad rotates about the anchor.
int8_t tySel
Y offset selector.
int8_t txSel
X offset selector.
std::map< std::string, std::string > props
Part-level properties shared by every placement (Description, Tolerance, ...).
std::vector< ORCAD_PACKAGE > variants
later same-name cache entries in stream order
std::vector< ORCAD_DEVICE > devices
Pin positions are absolute page connection points.
The placed box includes displayed text.
std::string sourcePackage
package base name
std::vector< ORCAD_DISPLAY_PROP > displayProps
ORCAD_BBOX bbox
placed box, page DBU
int rotation
0..3 quarter turns
uint16_t unitIndex
zero-based package device index
std::map< std::string, std::string > props
short-prefix property pairs
bool mirror
orientation bit 2
std::string sourceLibrary
source library path from the placed-instance header
std::string value
resolved Part Value
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_PRIMITIVE > children
kind == GROUP, translated by (x1, y1)
std::vector< ORCAD_POINT > points
polygon/polyline/bezier vertices
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_WIRE > wires
std::vector< ORCAD_PLACED_INSTANCE > instances
The bounding box occupies the final eight bytes before the next prefix stop.
std::string name
cache name, e.g. "C.Normal"
std::vector< ORCAD_SYMBOL_PIN > pins
std::vector< ORCAD_PRIMITIVE > primitives
bool synthesized
placeholder built from T0x10 data
std::map< std::string, std::string > props
int typeId
ORCAD_ST value.
std::optional< ORCAD_BBOX > bbox
symbol-space body box
std::vector< ORCAD_SYMBOL_DEF > variants
Variant zero is this entry.
int generalFlags
LibraryPart GeneralProperties flags (-1 = absent); bit0 = pin names visible, bit1 = pin text rotates ...
Pin coordinates use symbol space with Y down.
int position
slot in the parent symbol pin vector
std::vector< ORCAD_DISPLAY_PROP > displayProps
The wire ID refers to the page net table.
std::vector< ORCAD_ALIAS > aliases
wxString GetDefaultFieldName(FIELD_T aFieldId, TRANSLATION aTranslation)
Return a default symbol field name for a mandatory field type.
@ USER
The field ID hasn't been set yet; field is invalid.
@ DESCRIPTION
Field Description of part, i.e. "1/4W 1% Metal Film Resistor".
@ FOOTPRINT
Field Name Module PCB, i.e. "16DIP300".
@ DATASHEET
name of datasheet
@ REFERENCE
Field Reference of part, i.e. "IC21".
@ VALUE
Field Value of part, i.e. "3.3K".
static std::vector< int > candidates(const SEGMENT_INDEX &aIndex, const SEG &aQuery, int aPadding)
wxString result
Test unit parsing edge cases and error handling.
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
VECTOR2< int32_t > VECTOR2I