40#include <wx/translation.h>
73 std::transform( aPath.begin(), aPath.end(), aPath.begin(),
76 return c ==
'\\' ?
'/' : static_cast<char>( std::tolower( c ) );
84 return aLeft.size() == aRight.size()
85 && std::equal( aLeft.begin(), aLeft.end(), aRight.begin(),
86 [](
unsigned char a,
unsigned char b )
88 return std::tolower( a ) == std::tolower( b );
95 std::string normalized;
97 for(
unsigned char character : aName )
99 if( std::isalnum( character ) )
100 normalized.push_back(
static_cast<char>( std::tolower( character ) ) );
103 return normalized ==
"installedcomponent" || normalized ==
"installedcomponents"
104 || normalized ==
"installedproperty";
110 return ( aProp.
dispMode >> 8 ) & 0xFF;
126 return type >= 1 && type <= 4;
133 return type == 2 || type == 3;
140 return type == 1 || type == 2 || type == 4;
149 if( aProp.
name ==
"Part Reference" || aProp.
name ==
"Reference" )
152 if( aProp.
name ==
"Value" )
165 auto flushOverbar = [&]()
167 if( !overbar.IsEmpty() )
169 result += wxS(
"~{" ) + overbar + wxS(
"}" );
174 for( wxUniChar character : aName )
176 if( character ==
'\\' )
182 if( marked && character !=
' ' && character !=
'\t' && character !=
'\r' && character !=
'\n' )
184 overbar += character;
217 if( aFormatVersionMajor < 3 )
218 return { 67.0, 21.0 };
245 if( aFillStyle == 0 )
248 if( aFillStyle == 2 )
250 switch( aHatchStyle )
265 constexpr uint32_t currentHatchEpoch = 1577836800;
266 return schIUScale.MilsToIU( aModifyTimestamp >= currentHatchEpoch ? 80 : 25 );
272 constexpr uint32_t currentHatchEpoch = 1577836800;
273 return schIUScale.MilsToIU( aModifyTimestamp >= currentHatchEpoch ? 10 : 3 );
285 std::vector<SEG> lines;
287 auto append = [&](
const std::vector<double>& aSlopes,
bool aVertical )
298 for(
SEG& line : generated )
305 lines.insert( lines.end(), generated.begin(), generated.end() );
308 switch( aHatchStyle )
310 case 0: append( { 0.0 }, false );
break;
311 case 1: append( { 0.0 }, true );
break;
312 case 2: append( { 1.0 }, false );
break;
313 case 3: append( { -1.0 }, false );
break;
315 append( { 0.0 }, false );
316 append( { 0.0 }, true );
318 case 5: append( { -1.0, 1.0 }, false );
break;
319 default: append( { -1.0 }, false );
break;
328 return KiROUND( aTextSize * 8.0 / 21.0 );
335int schMm(
double aMm )
341int dbuIu(
double aDbu )
354bool laterRectangleOccludesTextUnderscores(
const std::vector<ORCAD_PRIMITIVE>& aPrimitives,
362 int textLeft = std::min(
text.x1,
text.x2 );
363 int textRight = std::max(
text.x1,
text.x2 );
364 int textTop = std::min(
text.y1,
text.y2 );
365 int textBottom = std::max(
text.y1,
text.y2 );
367 for(
size_t i = aTextIndex + 1; i < aPrimitives.size(); ++i )
374 int rectangleLeft = std::min( rectangle.
x1, rectangle.
x2 );
375 int rectangleRight = std::max( rectangle.
x1, rectangle.
x2 );
376 int rectangleTop = std::min( rectangle.
y1, rectangle.
y2 );
377 int rectangleBottom = std::max( rectangle.
y1, rectangle.
y2 );
381 if( textLeft >= rectangleLeft && textRight <= rectangleRight && textTop >= rectangleTop
382 && textBottom <= rectangleBottom && rectangleBottom - textBottom <= halfStroke )
412bool isBookkeepingProp(
const std::string& aName )
414 static const char*
const skipped[] = {
415 "Part Reference",
"Reference",
"Name",
"Graphic",
"Implementation",
416 "Implementation Type",
"Source Library",
"Source Package",
"Source Part",
419 for(
const char*
name : skipped )
436 for(
size_t i = 0; i < aSymbol.
pins.size(); ++i )
438 if( aSymbol.
pins[i].position == position )
442 return static_cast<size_t>( position );
448 if( aInstance.
pins.size() > aSymbol.
pins.size() )
454 for(
size_t i = 0; i < aInstance.
pins.size(); ++i )
456 size_t symbolPin = symbolPinIndex( aSymbol, aInstance.
pins[i], i );
458 if( symbolPin >= aSymbol.
pins.size() )
462 aSymbol.
pins[symbolPin].hotptX, aSymbol.
pins[symbolPin].hotptY );
464 if( point.
x != aInstance.
pins[i].x || point.
y != aInstance.
pins[i].y )
474 if( aInstance.
pins.size() != aSymbol.
pins.size() )
480 for(
size_t i = 0; i < aInstance.
pins.size(); ++i )
483 aSymbol.
pins[i].hotptX, aSymbol.
pins[i].hotptY );
485 if( point.
x != aInstance.
pins[i].x || point.
y != aInstance.
pins[i].y )
495 if( aLeft.
bbox.has_value() != aRight.
bbox.has_value() || aLeft.
pins.size() != aRight.
pins.size() )
500 || aLeft.
bbox->y2 != aRight.
bbox->y2 ) )
505 for(
size_t i = 0; i < aLeft.
pins.size(); ++i )
523 if( aInstance.
pins.size() > aSymbol.
pins.size() )
528 int64_t displacement = 0;
530 for(
size_t i = 0; i < aInstance.
pins.size(); ++i )
532 size_t symbolPin = symbolPinIndex( aSymbol, aInstance.
pins[i], i );
534 if( symbolPin >= aSymbol.
pins.size() )
538 aSymbol.
pins[symbolPin].hotptX, aSymbol.
pins[symbolPin].hotptY );
539 displacement +=
std::abs(
static_cast<int64_t
>( point.
x ) - aInstance.
pins[i].x );
540 displacement +=
std::abs(
static_cast<int64_t
>( point.
y ) - aInstance.
pins[i].y );
553 if( aInstance.
pins.size() > fitted.
pins.size() )
560 int determinant = transform.
a * transform.
d - transform.
b * transform.
c;
561 std::map<std::pair<int, int>,
size_t> targetCounts;
562 std::map<std::pair<int, int>, std::set<size_t>> targetPins;
564 for(
size_t i = 0; i < aInstance.
pins.size(); ++i )
566 size_t symbolPin = symbolPinIndex( fitted, aInstance.
pins[i], i );
568 if( symbolPin >= fitted.
pins.size() )
571 int x = aInstance.
pins[i].x - aInstance.
x - offset.
x;
572 int y = aInstance.
pins[i].y - aInstance.
y - offset.
y;
573 int hotptX = ( transform.
d * x - transform.
b * y ) / determinant;
574 int hotptY = ( -transform.
c * x + transform.
a * y ) / determinant;
575 ++targetCounts[{ hotptX, hotptY }];
576 targetPins[{ hotptX, hotptY }].insert( symbolPin );
579 std::set<std::pair<int, int>> handledStackedTargets;
581 for(
size_t i = 0; i < aInstance.
pins.size(); ++i )
583 size_t symbolPin = symbolPinIndex( fitted, aInstance.
pins[i], i );
585 if( symbolPin >= fitted.
pins.size() )
588 int x = aInstance.
pins[i].x - aInstance.
x - offset.
x;
589 int y = aInstance.
pins[i].y - aInstance.
y - offset.
y;
590 int hotptX = ( transform.
d * x - transform.
b * y ) / determinant;
591 int hotptY = ( -transform.
c * x + transform.
a * y ) / determinant;
592 auto target = std::pair{ hotptX, hotptY };
593 const std::set<size_t>& stackedPins = targetPins.at( target );
594 bool stackedTarget = targetCounts.at( target ) > 1;
596 auto occupant = std::find_if( fitted.
pins.begin(), fitted.
pins.end(),
599 return aPin.hotptX == hotptX && aPin.hotptY == hotptY;
602 if( stackedTarget && !handledStackedTargets.count( target ) )
604 occupant = std::find_if( fitted.
pins.begin(), fitted.
pins.end(),
607 size_t index = static_cast<size_t>( &aPin - fitted.pins.data() );
608 return aPin.hotptX == hotptX && aPin.hotptY == hotptY
609 && !stackedPins.count( index );
611 handledStackedTargets.insert( target );
613 else if( stackedTarget )
615 occupant = fitted.
pins.end();
618 if( occupant != fitted.
pins.end() && occupant != fitted.
pins.begin() + symbolPin )
620 std::swap( occupant->hotptX, fitted.
pins[symbolPin].hotptX );
621 std::swap( occupant->hotptY, fitted.
pins[symbolPin].hotptY );
622 std::swap( occupant->startX, fitted.
pins[symbolPin].startX );
623 std::swap( occupant->startY, fitted.
pins[symbolPin].startY );
627 int deltaX = hotptX - fitted.
pins[symbolPin].hotptX;
628 int deltaY = hotptY - fitted.
pins[symbolPin].hotptY;
630 fitted.
pins[symbolPin].hotptX = hotptX;
631 fitted.
pins[symbolPin].hotptY = hotptY;
632 fitted.
pins[symbolPin].startX += deltaX;
633 fitted.
pins[symbolPin].startY += deltaY;
646 std::vector<std::string> missingOrder;
647 std::map<std::string, std::vector<const ORCAD_PLACED_INSTANCE*>> missing;
651 std::vector<const ORCAD_RAW_PAGE*> allPages;
654 allPages.push_back( &page );
656 for(
const auto& [folder, pages] :
m_design.childFolderPages )
659 allPages.push_back( &page );
662 for(
const auto& [folder, pages] :
m_design.unreferencedFolderPages )
665 allPages.push_back( &page );
675 auto [it, isNew] = missing.try_emplace( inst.
pkgName );
678 missingOrder.push_back( inst.
pkgName );
680 it->second.push_back( &inst );
684 for(
const std::string&
name : missingOrder )
686 const std::vector<const ORCAD_PLACED_INSTANCE*>& insts = missing[
name];
688 note( wxString::Format(
_(
"Symbol '%s' is absent from the design cache; synthesized "
689 "placeholder from %d instance(s)." ),
701 if( symbol ==
m_design.symbols.end() || inst.
pins.empty() )
704 std::vector<const ORCAD_SYMBOL_DEF*> candidates = { &symbol->second };
709 candidates.push_back( &variant );
715 candidates.push_back( &variant );
722 if( symbolPinsMatch( *candidate, inst ) )
724 matching = candidate;
733 if( !sequentialSymbolPinsMatch( *candidate, inst ) )
740 for(
size_t i = 0; i < inst.
pins.size(); ++i )
742 if( inst.
pins[i].pinIndex )
743 fitted.
pins[i].position =
std::abs(
static_cast<int>( inst.
pins[i].pinIndex ) ) - 1;
746 if( symbolPinsMatch( fitted, inst ) )
748 symbol->second.variants.insert( symbol->second.variants.begin(), std::move( fitted ) );
749 matching = &symbol->second.
variants.front();
758 auto sourceProperty = inst.
props.find(
"Source Library" );
759 std::string sourceLibrary = sourceProperty != inst.
props.end() ? sourceProperty->second
762 bool sourceMatchedGraphics = !sourceLibrary.empty() && !matching->
sourceLib.empty()
765 if( matching != &symbol->second && !sourceMatchedGraphics
766 && std::none_of( symbol->second.variants.begin(), symbol->second.variants.end(),
769 return aVariant.synthesized && symbolGeometryMatches( aVariant, *matching );
773 fitted.
primitives = symbol->second.primitives;
774 fitted.
color = symbol->second.color;
775 fitted.
props = symbol->second.props;
780 if( symbolPinsMatch( fitted, inst ) )
781 symbol->second.variants.insert( symbol->second.variants.begin(), std::move( fitted ) );
788 int64_t bestDisplacement = std::numeric_limits<int64_t>::max();
792 std::optional<int64_t> displacement = symbolPinDisplacement( *candidate, inst );
794 if( displacement && *displacement < bestDisplacement )
797 bestDisplacement = *displacement;
805 if( symbolPinsMatch( fitted, inst ) )
806 symbol->second.variants.push_back( std::move( fitted ) );
830 auto stripView = [](
const std::string& aName ) -> std::string
832 size_t dot = aName.rfind(
'.' );
834 if( dot != std::string::npos )
836 std::string view = aName.substr( dot + 1 );
838 if( view ==
"Normal" || view ==
"Convert" )
839 return aName.substr( 0, dot );
845 for(
auto& [cacheName, def] :
m_design.symbols )
851 bool convertView = cacheName.size() > 8 && cacheName.compare( cacheName.size() - 8, 8,
".Convert" ) == 0;
852 std::string base = stripView( cacheName );
853 std::string libname =
SymbolId( base );
859 if( !ls.
name.empty() )
862 if( convertView &&
m_design.symbols.count( base +
".Normal" ) )
867 std::string bare = base.substr( 0, base.find(
'.' ) );
870 for(
const std::string& key : { base, bare } )
872 auto pkgIt =
m_design.packages.find( key );
874 if( pkgIt !=
m_design.packages.end() )
876 pkg = &pkgIt->second;
888 std::vector<std::string> pinNumbers;
889 std::vector<bool> pinNumberVisible;
890 std::vector<bool> pinIgnore;
892 if( pkg && !pkg->
devices.empty() )
894 pinNumbers = pkg->
devices.front().pinNumbers;
895 pinNumberVisible.reserve( pinNumbers.size() );
897 for(
const std::string& number : pinNumbers )
898 pinNumberVisible.push_back( !number.empty() );
900 pinIgnore = pkg->
devices.front().pinIgnore;
903 ls.
units.push_back( {
"A", &def, pinNumbers, pinNumberVisible, pinIgnore, {}, {} } );
908 std::vector<LIB_SYMBOL*> out;
917 out.push_back(
static_cast<LIB_SYMBOL*
>( symbol->Duplicate() ) );
919 catch(
const std::exception& e )
921 warn( wxString::Format(
_(
"The symbol '%s' could not be converted and was left out of the "
933 const std::vector<const ORCAD_PLACED_INSTANCE*>& aInstances )
const
950 int det = e.
a * e.
d - e.
b * e.
c;
954 return { ( e.
d * aX - e.
b * aY ) / det, ( -e.
c * aX + e.
a * aY ) / det };
958 std::vector<ORCAD_POINT> r;
961 r.push_back( inv( t.
x - ref->
x, t.
y - ref->
y ) );
963 std::optional<int> inferredWidth;
964 std::optional<int> inferredHeight;
966 if( r.size() == 1 && ori == 0 )
968 std::map<int, int> widthCounts;
969 std::map<int, int> heightCounts;
973 if( inst->pins.size() != 1 )
976 int instOrient =
OrcadOrientOf( inst->rotation, inst->mirror );
978 int localX = transform.
a * r.front().x + transform.
b * r.front().y;
979 int localY = transform.
c * r.front().x + transform.
d * r.front().y;
980 int offsetX = inst->pins.front().x - inst->x - localX;
981 int offsetY = inst->pins.front().y - inst->y - localY;
983 auto tally = [&](
int aSelector,
int aOffset )
989 ++widthCounts[aOffset];
990 else if( aSelector == 2 )
991 ++heightCounts[aOffset];
994 tally( transform.
txSel, offsetX );
995 tally( transform.
tySel, offsetY );
998 auto mostFrequent = [](
const std::map<int, int>& aCounts ) -> std::optional<int>
1000 auto best = std::max_element( aCounts.begin(), aCounts.end(),
1001 [](
const auto& aLeft,
const auto& aRight )
1003 return aLeft.second < aRight.second;
1005 return best == aCounts.end() ? std::nullopt : std::optional<int>( best->first );
1008 inferredWidth = mostFrequent( widthCounts );
1009 inferredHeight = mostFrequent( heightCounts );
1012 std::vector<char> sides;
1020 int x0 = r.front().x;
1021 int x1 = r.front().x;
1022 int y0 = r.front().y;
1023 int y1 = r.front().y;
1027 x0 = std::min( x0, p.x );
1028 x1 = std::max( x1, p.x );
1029 y0 = std::min( y0, p.y );
1030 y1 = std::max( y1, p.y );
1033 bool horizFirst = ( x1 - x0 ) >= ( y1 - y0 );
1037 std::vector<char> cand;
1040 cand.push_back(
'L' );
1043 cand.push_back(
'R' );
1046 cand.push_back(
'T' );
1049 cand.push_back(
'B' );
1053 sides.push_back( 0 );
1059 char pick = cand.front();
1061 for(
char c : cand )
1063 bool isTB = c ==
'T' || c ==
'B';
1065 if( isTB != horizFirst )
1072 sides.push_back( pick );
1075 if( r.size() == 1 && inferredWidth && inferredHeight )
1079 bx2 = *inferredWidth;
1080 by2 = *inferredHeight;
1084 auto hasSide = [&](
char aSide )
1086 return std::find( sides.begin(), sides.end(), aSide ) != sides.end();
1096 int m = (int) std::floor( ( bx1 + bx2 ) / 2.0 );
1103 int m = (int) std::floor( ( by1 + by2 ) / 2.0 );
1115 bx1 = std::min( c1.
x, c2.
x );
1116 bx2 = std::max( c1.
x, c2.
x );
1117 by1 = std::min( c1.
y, c2.
y );
1118 by2 = std::max( c1.
y, c2.
y );
1130 sym.
name = aPkgName;
1136 rect.
x1 = bx1 - s.
x;
1137 rect.
y1 = by1 - s.
y;
1138 rect.
x2 = bx2 - s.
x;
1139 rect.
y2 = by2 - s.
y;
1142 auto hasDualRowDescription = [](
const std::map<std::string, std::string>& aProps )
1144 return std::any_of( aProps.begin(), aProps.end(),
1145 [](
const auto& aProperty )
1147 std::string value = aProperty.second;
1148 std::transform( value.begin(), value.end(), value.begin(),
1149 []( unsigned char c )
1151 return static_cast<char>( std::toupper( c ) );
1153 return value.find(
"DUAL ROW" ) != std::string::npos;
1156 bool dualRowConnector = hasDualRowDescription( ref->props );
1157 auto package = m_design.packages.find( ref->sourcePackage );
1159 if( package != m_design.packages.end() )
1160 dualRowConnector = dualRowConnector || hasDualRowDescription( package->second.props );
1162 for(
size_t i = 0; i < r.size(); ++i )
1164 int px = r[i].x - s.x;
1165 int py = r[i].y - s.y;
1171 case
'L': ddx = PIN_LEN_DBU; break;
1172 case
'R': ddx = -PIN_LEN_DBU; break;
1173 case
'T': ddy = PIN_LEN_DBU; break;
1174 case
'B': ddy = -PIN_LEN_DBU; break;
1180 if( dualRowConnector )
1182 int pinIndex = std::abs( static_cast<int>( ref->pins[i].pinIndex ) );
1183 pin.position = pinIndex > 0 ? pinIndex - 1 : static_cast<int>( i );
1184 pin.name = std::to_string( pinIndex > 0 ? pinIndex : i + 1 );
1187 pin.startX = px + ddx;
1188 pin.startY = py + ddy;
1193 sym.pins.push_back(
pin );
1204 const std::string& v = aInst.
pkgName;
1205 auto sourceProperty = aInst.
props.find(
"Source Package" );
1206 std::string base = sourceProperty != aInst.
props.end() && !sourceProperty->second.empty() ? sourceProperty->second
1208 : v.substr( 0, v.find(
'.' ) );
1210 std::string tail = ( v.compare( 0, base.size(), base ) == 0 ) ? v.substr( base.size() ) : v;
1212 size_t dot = tail.find(
'.' );
1213 std::string unit = tail.substr( 0, dot );
1214 std::string view = dot == std::string::npos ? std::string() : tail.substr( dot + 1 );
1218 std::string lower = view;
1220 std::transform( lower.begin(), lower.end(), lower.begin(),
1221 [](
unsigned char c )
1223 return (char) std::tolower( c );
1228 if( lower !=
"normal" )
1241 return {
nullptr, 0 };
1245 std::vector<const ORCAD_SYMBOL_DEF*> variants;
1246 variants.push_back( prime );
1249 variants.push_back( &v );
1251 if( aInst.
pins.empty() )
1252 return { prime, 0 };
1254 auto sourceProperty = aInst.
props.find(
"Source Library" );
1255 std::string sourceLibrary = sourceProperty != aInst.
props.end() ? sourceProperty->second : aInst.
sourceLibrary;
1257 if( !sourceLibrary.empty() )
1261 for(
size_t vi = 0; vi < variants.size(); ++vi )
1263 if(
normalizedPath( variants[vi]->sourceLib ) == sourceKey && symbolPinsMatch( *variants[vi], aInst ) )
1264 return { variants[vi],
static_cast<int>( vi ) };
1268 for(
size_t vi = 0; vi < variants.size(); ++vi )
1272 if( symbolPinsMatch( *sym, aInst ) )
1273 return { sym, (int) vi };
1276 return { prime, 0 };
1282 auto packageProperty = aInst.
props.find(
"Source Package" );
1283 std::string base = packageProperty != aInst.
props.end() && !packageProperty->second.empty()
1284 ? packageProperty->second
1288 auto it =
m_design.packages.find( base );
1290 if( it ==
m_design.packages.end() )
1297 size_t activePins = 0;
1299 for(
size_t i = 0; i < device.
pinNumbers.size(); ++i )
1305 if( activePins == aInst.
pins.size() )
1312 std::vector<const ORCAD_PACKAGE*> candidates = { &it->second };
1315 candidates.push_back( &variant );
1319 auto sourceProperty = aInst.
props.find(
"Source Library" );
1320 std::string sourceLibrary = sourceProperty != aInst.
props.end() ? sourceProperty->second : std::string();
1322 if( sourceLibrary.empty() )
1325 if( sourceLibrary.empty() && selectedSymbol )
1326 sourceLibrary = selectedSymbol->
sourceLib;
1328 auto candidateFootprint = [](
const ORCAD_PACKAGE& aPackage )
1330 std::string footprint = aPackage.pcbFootprint;
1331 auto property = aPackage.props.find(
"PCB Footprint" );
1333 if( footprint.empty() && property != aPackage.props.end() )
1334 footprint =
property->second;
1341 return std::any_of( aPackage.devices.begin(), aPackage.devices.end(),
1344 return std::any_of( aDevice.pinNumbers.begin(), aDevice.pinNumbers.end(),
1345 []( const std::string& aNumber )
1347 return !aNumber.empty();
1352 if( !sourceLibrary.empty() )
1355 bool designLibrary = sourceKey.ends_with(
".dsn" );
1356 bool numberedAlternative =
1357 std::any_of( candidates.begin(), candidates.end(),
1360 return matchesInstance( *aCandidate ) && hasNumberedPins( *aCandidate );
1365 if( !matchesInstance( *candidate ) ||
normalizedPath( candidate->sourceLib ) != sourceKey )
1368 if( !designLibrary && numberedAlternative && !hasNumberedPins( *candidate ) )
1375 auto footprintProperty = aInst.props.find(
"PCB Footprint" );
1376 std::string footprintKey =
1377 footprintProperty != aInst.props.end() ?
normalizedPath( footprintProperty->second ) :
std::string();
1379 if( !footprintKey.empty() )
1381 std::vector<const ORCAD_PACKAGE*> footprintMatches;
1383 for( const ORCAD_PACKAGE* candidate : candidates )
1385 if( matchesInstance( *candidate ) && normalizedPath( candidateFootprint( *candidate ) ) == footprintKey )
1386 footprintMatches.push_back( candidate );
1389 if( footprintMatches.size() == 1 )
1390 return footprintMatches.front();
1393 auto logicalPinMatches = [&](
const ORCAD_PACKAGE& aPackage )
1395 if( !selectedSymbol || aInst.unitIndex >= aPackage.devices.size() )
1398 const std::vector<std::string>& numbers = aPackage.devices[aInst.unitIndex].pinNumbers;
1403 if(
pin.position >= 0 &&
static_cast<size_t>(
pin.position ) < numbers.size() && !
pin.name.empty()
1404 &&
pin.name == numbers[
pin.position] )
1414 int bestLogicalMatches = -1;
1418 if( !matchesInstance( *candidate ) || !hasNumberedPins( *candidate ) )
1421 int logicalMatches = logicalPinMatches( *candidate );
1423 if( logicalMatches > bestLogicalMatches )
1425 bestNumbered = candidate;
1426 bestLogicalMatches = logicalMatches;
1431 return bestNumbered;
1435 if( matchesInstance( *candidate ) )
1446 std::map<std::string, std::string> props = aDef.
props;
1448 auto overlay = [&](
const std::map<std::string, std::string>& aProperties,
bool aAllowEmpty = false )
1450 for(
const auto& [
name, value] : aProperties )
1452 auto existing = std::find_if( props.begin(), props.end(),
1453 [&](
const auto& aProperty )
1454 { return propertyNamesEqual( aProperty.first, name ); } );
1456 if( existing != props.end() )
1458 if( aAllowEmpty || !value.empty() || existing->second.empty() )
1459 existing->second = value;
1462 props[
name] = value;
1476 overlay( occurrence->second,
true );
1484 const std::string& aNetName )
const
1488 if( !definition || aPinIndex >= aInstance.
pins.size() )
1491 size_t index = symbolPinIndex( *definition, aInstance.
pins[aPinIndex], aPinIndex );
1499 &&
pin.hotptX ==
pin.startX &&
pin.hotptY ==
pin.startY && !
pin.name.empty()
1500 &&
pin.name.compare( 0, 4,
"$PIN" ) != 0 &&
pin.name == aNetName;
1509 auto sourceProperty = aInst.
props.find(
"Source Library" );
1510 std::string sourceLibrary = sourceProperty != aInst.
props.end() ? sourceProperty->second : std::string();
1512 if( sourceLibrary.empty() )
1515 if( sourceLibrary.empty() && sym )
1516 sourceLibrary = sym->sourceLib;
1518 auto packageProperty = aInst.
props.find(
"Source Package" );
1519 std::string sourcePackage = packageProperty != aInst.
props.end() && !packageProperty->second.empty()
1520 ? packageProperty->second
1524 std::string srcOrPkg = sourceLibrary +
"\n" + sourcePackage;
1526 auto footprintProperty = aInst.
props.find(
"PCB Footprint" );
1528 if( footprintProperty != aInst.
props.end() )
1529 srcOrPkg +=
"\n" + footprintProperty->second;
1530 std::string base = sourcePackage;
1536 warn( wxString::Format(
_(
"No cached symbol for '%s' (%s); placeholder emitted." ),
1542 if( slot.
name.empty() )
1560 letter = unitRefIt->second;
1563 if( letter.empty() && pkg && unitIndex < pkg->devices.size() )
1564 letter = pkg->
devices[unitIndex].unitRef;
1566 if( letter.empty() && pkg && pkg->
devices.size() > 1 )
1568 std::string
index = std::to_string( unitIndex );
1569 letter =
"#" + std::string( 10 - std::min<size_t>( 10,
index.size() ),
'0' ) +
index;
1574 std::vector<std::string> pinNumbers;
1575 std::vector<bool> pinIgnore;
1579 bool foundDevice =
false;
1581 if( unitIndex < pkg->devices.size() )
1583 pinNumbers = pkg->
devices[unitIndex].pinNumbers;
1584 pinIgnore = pkg->
devices[unitIndex].pinIgnore;
1588 std::string bare = letter.substr( 0, letter.find(
':' ) );
1604 if( !foundDevice && !pkg->
devices.empty() && bare.empty() )
1606 pinNumbers = pkg->
devices.front().pinNumbers;
1607 pinIgnore = pkg->
devices.front().pinIgnore;
1611 std::string normalizedSourceLibrary =
normalizedPath( sourceLibrary );
1614 bool logicalNumbers = sym
1615 && std::all_of( sym->pins.begin(), sym->pins.end(),
1618 return !aPin.name.empty()
1619 && std::all_of( aPin.name.begin(), aPin.name.end(),
1620 []( unsigned char c )
1622 return std::isdigit( c );
1625 bool packagePinCountMatches = pkg
1626 && std::any_of( pkg->devices.begin(), pkg->devices.end(),
1629 size_t activePins = 0;
1631 for( size_t i = 0; i < aDevice.pinNumbers.size(); ++i )
1633 if( i >= aDevice.pinIgnore.size() || !aDevice.pinIgnore[i] )
1639 return activePins == aInst.pins.size();
1641 bool stalePackageMap = logicalNumbers && pkg && pkg->devices.size() == 1
1642 && !normalizedSourceLibrary.ends_with(
".dsn" )
1643 && normalizedPackageLibrary != normalizedSourceLibrary;
1645 if( logicalNumbers && pkg && !packagePinCountMatches && normalizedPackageLibrary != normalizedSourceLibrary )
1647 pinNumbers.resize( sym->pins.size() );
1648 pinIgnore.assign( sym->pins.size(),
false );
1650 for(
size_t pi = 0; pi < sym->pins.size(); ++pi )
1652 int position = sym->pins[pi].position >= 0 ? sym->pins[pi].position :
static_cast<int>( pi );
1654 if( position >= 0 &&
static_cast<size_t>( position ) < pinNumbers.size() )
1655 pinNumbers[position] = sym->pins[pi].name;
1659 bool packageUsesLogicalPinNames = vi > 0 && sym && sym->pins.size() == 2 && pinNumbers.size() == 2;
1661 if( packageUsesLogicalPinNames )
1663 for(
size_t pi = 0; pi < sym->pins.size(); ++pi )
1665 int position = sym->pins[pi].position >= 0 ? sym->pins[pi].position :
static_cast<int>( pi );
1667 if( position < 0 ||
static_cast<size_t>( position ) >= pinNumbers.size()
1668 || wxString::FromUTF8( pinNumbers[position] ).CmpNoCase( wxString::FromUTF8( sym->pins[pi].name ) )
1671 packageUsesLogicalPinNames =
false;
1677 if( packageUsesLogicalPinNames && normalizedSourceLibrary.ends_with(
".dsn" ) )
1679 const std::map<std::string, std::string> diodeNumbers = {
1680 {
"a",
"2" }, {
"anode",
"2" }, {
"k",
"1" }, {
"cathode",
"1" }
1682 bool diodePins =
true;
1687 std::transform(
name.begin(),
name.end(),
name.begin(),
1688 [](
unsigned char c )
1690 return static_cast<char>( std::tolower( c ) );
1692 diodePins = diodePins && diodeNumbers.count(
name );
1697 for(
size_t pi = 0; pi < sym->pins.size(); ++pi )
1699 int position = sym->pins[pi].position >= 0 ? sym->pins[pi].position :
static_cast<int>( pi );
1700 std::string
name = sym->pins[pi].name;
1701 std::transform(
name.begin(),
name.end(),
name.begin(),
1702 [](
unsigned char c )
1704 return static_cast<char>( std::tolower( c ) );
1706 pinNumbers[position] = diodeNumbers.at(
name );
1711 auto hasDualRowDescription = [](
const std::map<std::string, std::string>& aProps )
1713 return std::any_of( aProps.begin(), aProps.end(),
1714 [](
const auto& aProperty )
1716 std::string value = aProperty.second;
1717 std::transform( value.begin(), value.end(), value.begin(),
1718 []( unsigned char c )
1720 return static_cast<char>( std::toupper( c ) );
1722 return value.find(
"DUAL ROW" ) != std::string::npos;
1726 bool blankPackageMap = !pinNumbers.empty()
1727 && std::all_of( pinNumbers.begin(), pinNumbers.end(),
1728 [](
const std::string& aNumber )
1730 return aNumber.empty();
1732 std::vector<bool> pinNumberVisible;
1733 pinNumberVisible.reserve( pinNumbers.size() );
1735 for(
const std::string& number : pinNumbers )
1736 pinNumberVisible.push_back( !number.empty() );
1738 bool dualRowConnector =
1739 sym && sym->synthesized && pinNumbers.size() == sym->pins.size() && pinNumbers.size() % 2 == 0
1740 && ( hasDualRowDescription( aInst.props ) || ( pkg && hasDualRowDescription( pkg->props ) ) );
1742 if( blankPackageMap && dualRowConnector )
1744 size_t half = pinNumbers.size() / 2;
1745 std::set<int> positions;
1747 for(
size_t pi = 0; pi < sym->pins.size(); ++pi )
1749 int position = sym->pins[pi].position >= 0 ? sym->pins[pi].position :
static_cast<int>( pi );
1751 if( position >= 0 &&
static_cast<size_t>( position ) < pinNumbers.size() )
1752 positions.insert( position );
1755 if( positions.size() == pinNumbers.size() )
1757 for(
size_t position = 0; position < pinNumbers.size(); ++position )
1759 size_t number = position < half ? 2 * position + 1 : 2 * ( position - half + 1 );
1760 pinNumbers[position] = std::to_string( number );
1761 pinNumberVisible[position] =
true;
1766 if( sym && !pinNumbers.empty() )
1768 for(
size_t pi = 0; pi < sym->pins.size(); ++pi )
1770 int position = sym->pins[pi].position >= 0 ? sym->pins[pi].position :
static_cast<int>( pi );
1772 if( position >= 0 &&
static_cast<size_t>( position ) < pinNumbers.size() && pinNumbers[position].empty()
1773 && (
static_cast<size_t>( position ) >= pinIgnore.size() || !pinIgnore[position] ) )
1775 pinNumbers[position] = sym->pins[pi].name;
1780 if( !normalizedSourceLibrary.ends_with(
".dsn" ) && sym && sym->pins.size() == 2 && logicalNumbers && pkg
1781 && pkg->devices.size() == 1 )
1783 for(
size_t pi = 0; pi < sym->pins.size(); ++pi )
1785 int position = sym->pins[pi].position >= 0 ? sym->pins[pi].position :
static_cast<int>( pi );
1787 if( position >= 0 &&
static_cast<size_t>( position ) < pinNumbers.size() && stalePackageMap
1788 && (
static_cast<size_t>( position ) >= pinIgnore.size() || !pinIgnore[position] ) )
1790 pinNumbers[position] = sym->pins[pi].name;
1795 std::vector<int> pinOffsets( sym->pins.size() );
1796 std::vector<bool> explicitPinNets( sym->pins.size() );
1797 std::vector<int> placedOffsets = placedStackedPinOffsets( aInst );
1799 for(
size_t i = 0; i < aInst.pins.size(); ++i )
1801 size_t symbolPin = symbolPinIndex( *sym, aInst.pins[i], i );
1803 if( symbolPin < pinOffsets.size() )
1805 pinOffsets[symbolPin] = placedOffsets[i];
1807 if( !aInst.pins[i].IsNoConnect() && ( aInst.pins[i].wordA || aInst.pins[i].wordB )
1808 && !m_currentImplicitPowerPins.count( &aInst.pins[i] ) )
1809 explicitPinNets[symbolPin] =
true;
1813 PKG_KEY key{ srcOrPkg, aInst.pkgName, vi, letter };
1817 *aSourceUnit =
nullptr;
1818 auto prepared = m_preparedPkgToLib.find( key );
1820 if( prepared != m_preparedPkgToLib.end() )
1822 *aSourceUnit = &prepared->first;
1827 for(
const auto& [sourceKey, selection] : m_preparedPkgToLib )
1829 if( std::get<0>( sourceKey ) != srcOrPkg || std::get<1>( sourceKey ) != aInst.pkgName
1830 || std::get<2>( sourceKey ) != vi )
1833 const UNIT_INFO& source = m_preparedLibUnits.at( selection.first )[selection.second - 1];
1835 if( source.symbol == sym && source.pinNumbers == pinNumbers )
1839 *aSourceUnit =
nullptr;
1843 *aSourceUnit = &sourceKey;
1849 auto found = m_pkgToLib.find( key );
1851 if( found != m_pkgToLib.end() )
1853 auto libIt = m_libSymbols.find( found->second.first );
1854 int cachedUnit = found->second.second;
1856 if( libIt != m_libSymbols.end() && cachedUnit > 0
1857 &&
static_cast<size_t>( cachedUnit ) <= libIt->second.units.size() )
1859 const UNIT_INFO& cached = libIt->second.units[cachedUnit - 1];
1861 if( cached.pinNumbers == pinNumbers && cached.pinNumberVisible == pinNumberVisible
1862 && cached.pinIgnore == pinIgnore && cached.pinOffsets == pinOffsets
1863 && cached.explicitPinNets == explicitPinNets )
1864 return found->second;
1868 std::string libnameBase = SymbolId( base );
1871 libnameBase +=
"_v" + std::to_string( vi + 1 );
1873 std::string libname = libnameBase;
1875 for(
size_t discriminator = 2;; ++discriminator )
1877 auto lib = m_libSymbols.find( libname );
1879 if( lib == m_libSymbols.end() )
1882 auto unit = std::find_if( lib->second.units.begin(), lib->second.units.end(),
1883 [&](
const UNIT_INFO& aUnit )
1885 return aUnit.letter == letter;
1888 if( unit == lib->second.units.end()
1889 || ( unit->pinNumbers == pinNumbers && unit->pinNumberVisible == pinNumberVisible
1890 && unit->pinIgnore == pinIgnore && unit->pinOffsets == pinOffsets
1891 && unit->explicitPinNets == explicitPinNets ) )
1896 libname = libnameBase +
"_pins" + std::to_string( discriminator );
1899 LIB_ENTRY& ls = m_libSymbols[libname];
1901 if( ls.name.empty() )
1904 ls.refPrefix = ( pkg && !pkg->refDes.empty() ) ? pkg->refDes :
"U";
1905 ls.footprint = pkg ? pkg->pcbFootprint :
"";
1910 for(
size_t i = 0; i < ls.units.size(); ++i )
1912 if( ls.units[i].letter == letter )
1914 unitNo = (int) i + 1;
1922 unit.letter = letter;
1924 unit.pinNumbers = pinNumbers;
1925 unit.pinNumberVisible = pinNumberVisible;
1926 unit.pinIgnore = pinIgnore;
1927 unit.pinOffsets = pinOffsets;
1928 unit.explicitPinNets = explicitPinNets;
1929 ls.units.push_back( std::move( unit ) );
1930 ls.kicadSymbol.reset();
1932 std::stable_sort( ls.units.begin(), ls.units.end(),
1933 [](
const UNIT_INFO& a,
const UNIT_INFO& b )
1935 return StrNumCmp( wxString::FromUTF8( a.letter ), wxString::FromUTF8( b.letter ) ) < 0;
1938 for(
size_t i = 0; i < ls.units.size(); ++i )
1940 if( ls.units[i].letter == letter )
1942 unitNo = (int) i + 1;
1949 for(
auto mapIt = m_pkgToLib.begin(); mapIt != m_pkgToLib.end(); )
1951 if( mapIt->second.first == libname )
1952 mapIt = m_pkgToLib.erase( mapIt );
1957 for(
size_t i = 0; i < ls.units.size(); ++i )
1959 std::string pkgName = sourcePackage + ls.units[i].letter +
".Normal";
1961 m_pkgToLib[PKG_KEY{ srcOrPkg, pkgName, vi, ls.units[i].letter }] = { libname, (int) i + 1 };
1965 m_pkgToLib[key] = { libname, unitNo };
1966 return { libname, unitNo };
1972 std::string libname =
"PWR_" +
SymbolId( aNetName ) +
"_" +
SymbolId( aSymbolName );
1978 auto it =
m_design.symbols.find( aSymbolName );
1989 if( slot.
name.empty() )
1992 slot.
name = aSymbolName;
2007 ls.
units.push_back( std::move( unit ) );
2029 std::unique_ptr<LIB_SYMBOL> symbol = std::make_unique<LIB_SYMBOL>(
name );
2031 symbol->SetPinNameOffset( schMm( 0.254 ) );
2034 bool defaultShowPinNames = symbol->GetShowPinNames();
2035 bool defaultShowPinNumbers = symbol->GetShowPinNumbers();
2042 defaultShowPinNumbers = ( flags & 0x04 ) == 0;
2043 defaultShowPinNames = ( flags & 0x01 ) != 0;
2048 bool showPinNames = defaultShowPinNames;
2049 bool showPinNumbers = defaultShowPinNumbers;
2056 for(
size_t pinIndex = 0; pinIndex < unit.
symbol->
pins.size(); ++pinIndex )
2059 int position = sourcePin.
position >= 0 ? sourcePin.
position :
static_cast<int>( pinIndex );
2079 symbol->SetShowPinNames( showPinNames );
2080 symbol->SetShowPinNumbers( showPinNumbers );
2083 symbol->SetGlobalPower();
2085 if( (
int) entry.
units.size() > 1 )
2087 symbol->SetUnitCount( (
int) entry.
units.size(),
false );
2089 for(
size_t unit = 0; unit < entry.
units.size(); ++unit )
2090 symbol->GetUnitDisplayNames()[
static_cast<int>( unit ) + 1] = wxEmptyString;
2100 SCH_FIELD& refField = symbol->GetReferenceField();
2101 SCH_FIELD& valField = symbol->GetValueField();
2105 refField.
SetText( wxS(
"#PWR" ) );
2125 symbol->GetFootprintField().SetVisible(
false );
2126 symbol->GetDatasheetField().SetVisible(
false );
2128 for(
size_t ui = 0; ui < entry.
units.size(); ++ui )
2131 int unitNo = (int) ui + 1;
2136 for(
size_t primitiveIndex = 0; primitiveIndex < unit.
symbol->
primitives.size(); ++primitiveIndex )
2140 if( laterRectangleOccludesTextUnderscores( unit.
symbol->
primitives, primitiveIndex ) )
2143 std::replace( visible.
text.begin(), visible.
text.end(),
'_',
' ' );
2152 BOX2I bodyBox = symbol->GetBodyBoundingBox( unitNo, 0,
false,
false );
2154 for(
size_t pi = 0; pi < unit.
symbol->
pins.size(); ++pi )
2160 if( position <
static_cast<int>( unit.
pinIgnore.size() ) && unit.
pinIgnore[position] )
2163 wxString number = position < static_cast<int>( unit.
pinNumbers.size() )
2165 : wxString::Format( wxS(
"%d" ), (
int) pi + 1 );
2168 sourcePin.
hotptX += pinOffset;
2169 sourcePin.
startX += pinOffset;
2173 defaultShowPinNumbers,
2189 uint32_t aModifyTimestamp )
2212 int aOffsetX,
int aOffsetY )
2216 auto toX = [aOffsetX](
int aV )
2220 auto toY = [aOffsetY](
int aV )
2225 switch( aPrim.
kind )
2238 shape->
SetStroke( strokeFor( aPrim, aColor ) );
2252 shape->
SetStroke( strokeFor( aPrim, aColor ) );
2262 if( aPrim.
points.size() < 2 )
2272 if( isPolygon && aPrim.
points.front() != aPrim.
points.back() )
2275 shape->
SetStroke( strokeFor( aPrim, aColor ) );
2290 if( aPrim.
points.size() < 4 || ( aPrim.
points.size() - 1 ) % 3 != 0 )
2292 if( aPrim.
points.size() >= 2 )
2299 shape->
SetStroke( strokeFor( aPrim, aColor ) );
2308 for(
size_t i = 0; i + 3 < aPrim.
points.size(); i += 3 )
2315 shape->
SetStroke( strokeFor( aPrim, aColor ) );
2326 double cx = ( aPrim.
x1 + aPrim.
x2 ) / 2.0;
2327 double cy = ( aPrim.
y1 + aPrim.
y2 ) / 2.0;
2337 shape->
SetStroke( strokeFor( aPrim, aColor ) );
2349 for(
int k = 0; k <= 32; ++k )
2351 double a = 2.0 *
M_PI * k / 32.0;
2352 shape->
AddPoint(
VECTOR2I( dbuIu( cx + rx * std::cos( a ) ), dbuIu( cy + ry * std::sin( a ) ) ) );
2355 shape->
SetStroke( strokeFor( aPrim, aColor ) );
2370 bool multiline = aPrim.
text.find(
'\n' ) != std::string::npos;
2371 bool hasBox = aPrim.
x1 != aPrim.
x2 || aPrim.
y1 != aPrim.
y2;
2372 int textX = hasBox && !multiline ? ( aPrim.
x1 + aPrim.
x2 ) / 2 : aPrim.
x1;
2373 int textY = hasBox ? ( aPrim.
y1 + aPrim.
y2 ) / 2 : aPrim.
y1;
2374 int boxedTextYOffset = 0;
2386 if(
std::abs( quarterTurns ) % 2 == 1 )
2399 BOX2I inkBox =
text->GetEffectiveTextShape(
false )->BBox();
2404 int inkHeight =
KiROUND( boxHeight * 0.7 );
2409 size.
x =
KiROUND(
static_cast<double>( size.
x ) * inkWidth / inkBox.
GetWidth() );
2411 text->SetTextSize( size );
2412 boxedTextYOffset = ( boxHeight - inkHeight ) / 4;
2418 text->SetPosition(
VECTOR2I( toX( textX ), toY( textY ) + boxedTextYOffset ) );
2420 text->SetUnit( aUnit );
2433 int aOffsetX,
int aOffsetY )
2441 double cx = ( aPrim.
x1 + aPrim.
x2 ) / 2.0;
2442 double cy = ( aPrim.
y1 + aPrim.
y2 ) / 2.0;
2452 double a0 = std::atan2( ( aPrim.
start->y - cy ) / ry, ( aPrim.
start->x - cx ) / rx );
2453 double a1 = std::atan2( ( aPrim.
end->y - cy ) / ry, ( aPrim.
end->x - cx ) / rx );
2460 int steps = std::max( 4, (
int) (
std::abs( a1 - a0 ) / (
M_PI / 16.0 ) ) );
2465 for(
int k = 0; k <= steps; ++k )
2467 double a = a0 + ( a1 - a0 ) * k / steps;
2469 VECTOR2I( dbuIu( cx + rx * std::cos( a ) + aOffsetX ), dbuIu( cy + ry * std::sin( a ) + aOffsetY ) ) );
2472 shape->
SetStroke( strokeFor( aPrim, aColor ) );
2480 int aUnit,
bool aPower,
const std::string& aNameOverride,
bool aNameVisible,
2481 bool aShowPinNumbers,
bool aNumberVisible,
const BOX2I* aBodyBox,
bool aHidden,
2487 bool hiddenPowerStyle = pinLength == 0 && ( aPin.
shapeBits & 0x80 ) != 0;
2489 if( dx == 0 && dy == 0 && aBodyBox )
2492 std::array<int, 4> distances = {
2497 switch( std::min_element( distances.begin(), distances.end() ) - distances.begin() )
2499 case 0: dx = 1;
break;
2500 case 1: dx = -1;
break;
2501 case 2: dy = 1;
break;
2502 case 3: dy = -1;
break;
2510 pin->SetLength( pinLength );
2523 pin->SetOrientation( orientation );
2526 bool isClock = ( aPin.
shapeBits & 0x2 ) != 0;
2527 bool isDot = ( aPin.
shapeBits & 0x4 ) != 0;
2529 if( isClock && isDot )
2541 pin->SetVisible(
false );
2548 if( hiddenPowerStyle )
2549 pin->SetVisible(
false );
2553 pin->SetVisible(
false );
2554 pin->SetLength( 0 );
2563 if( !aNameOverride.empty() )
2565 else if( !aPin.
name.empty() && aPin.
name.compare( 0, 4,
"$PIN" ) != 0 )
2567 else if( aNameVisible && !aShowPinNumbers )
2570 auto pinTextSize = [&](
int aFontIdx )
2574 if( resolved > 0 && resolved <=
static_cast<int>(
m_design.library.fonts.size() ) )
2577 return schMm( 1.78 );
2580 auto findDisplay = [&](
const char* aName,
const char* aAlternate ) ->
const ORCAD_DISPLAY_PROP*
2585 return propertyNamesEqual( aProp.name, aName )
2586 || propertyNamesEqual( aProp.name, aAlternate );
2597 aNumberVisible = aNumberVisible
2600 int nameFont = nameDisplay && nameDisplay->
fontIdx > 0 ? nameDisplay->
fontIdx :
m_design.library.pinNameFont;
2601 int numberFont = numberDisplay && numberDisplay->
fontIdx > 0 ? numberDisplay->
fontIdx
2605 pin->SetNumber( aNumber );
2606 pin->SetNameTextSize( aNameVisible && !
name.IsEmpty() ? pinTextSize( nameFont ) : 0 );
2607 pin->SetNumberTextSize( aNumberVisible && !aNumber.IsEmpty() ? pinTextSize( numberFont ) : 0 );
2608 pin->SetUnit( aUnit );
2612 pin->SetNameTextSize( 0 );
2613 pin->SetNumberTextSize( 0 );
2620 VECTOR2I direction( ( dx > 0 ) - ( dx < 0 ), ( dy > 0 ) - ( dy < 0 ) );
2623 VECTOR2I base = apex - direction * dbuIu( 4 );
2627 wedge->
AddPoint( base + halfWidth );
2628 wedge->
AddPoint( base - halfWidth );
2636 if( aPower || aHidden || hiddenPowerStyle )
2643 switch( aOrient & 7 )
2660 using PART_KEY = std::pair<const void*, wxString>;
2661 std::map<PART_KEY, size_t> indices;
2662 std::vector<std::vector<const PLACED_PACKAGE_UNIT*>> parts;
2666 auto [entry, inserted] = indices.emplace( PART_KEY{ unit.scope, unit.reference }, parts.size() );
2669 parts.emplace_back();
2671 parts[entry->second].push_back( &unit );
2674 for(
const auto& part : parts )
2682 std::set<size_t> placedUnits;
2683 std::vector<size_t> unitIndices;
2684 bool compatible = !first.
reference.empty() && !first.
reference.EndsWith( wxS(
"?" ) );
2689 size_t index =
static_cast<size_t>( source.second - 1 );
2691 if( source.first != templateName || std::get<0>( *placed->sourceUnit ) != std::get<0>( *first.
sourceUnit )
2692 ||
index >= units.size() || !placedUnits.insert(
index ).second )
2698 units[
index] = placed->unit;
2699 unitIndices.push_back(
index );
2702 std::set<std::string> letters;
2705 compatible &= letters.insert( unit.letter ).second;
2709 warn( wxString::Format(
_(
"Native power units for '%s' have ambiguous package identity; "
2710 "their symbol definitions were kept separate." ), first.
reference ) );
2714 std::string libname = templateName;
2716 for(
size_t discriminator = 2;; ++discriminator )
2720 if( candidate ==
m_libSymbols.end() || candidate->second.units == units )
2723 libname = templateName +
"_pins" + std::to_string( discriminator );
2726 auto [entry, inserted] =
m_libSymbols.try_emplace( libname );
2731 entry->second.name = libname;
2732 entry->second.units = std::move( units );
2733 entry->second.refPrefix = source.
refPrefix;
2734 entry->second.footprint = source.
footprint;
2746 for(
size_t i = 0; i < part.size(); ++i )
2749 int targetUnit =
static_cast<int>( unitIndices[i] + 1 );
2750 std::vector<SCH_ITEM*> replaced;
2754 if( item.GetUnit() == targetUnit && item.Type() !=
SCH_FIELD_T )
2755 replaced.push_back( &item );
2766 copy->SetUnit( targetUnit );
2777 for(
size_t i = 0; i < part.size(); ++i )
2781 int unit =
static_cast<int>( unitIndices[i] + 1 );
2782 screen->
Remove( symbol );
2788 screen->
Append( symbol );
2799 const PKG_KEY* sourceUnit =
nullptr;
2807 int w = bb.
x2 - bb.
x1;
2808 int h = bb.
y2 - bb.
y1;
2815 if( !aInst.
pins.empty() && !symbolPinsMatch( def, aInst ) )
2819 note( wxString::Format(
_(
"Page %s: %s uses a synthesized placeholder at a "
2820 "different orientation; pin layout approximate." ),
2825 warn( wxString::Format(
_(
"Page %s: %s pin positions mismatch (orientation %d); "
2826 "geometry may be off." ),
2843 std::vector<std::pair<SCH_TEXT*, SCH_SHAPE*>> degreeMarks;
2845 auto circleTouchesStroke = [&](
const SCH_SHAPE& aCircle )
2847 int64_t radiusSquared =
static_cast<int64_t
>( aCircle.GetRadius() ) * aCircle.GetRadius();
2861 if( ( point - aCircle.GetPosition() ).SquaredEuclideanNorm() <= radiusSquared )
2887 || circleTouchesStroke( *shape ) )
2895 degreeMarks.emplace_back(
text, shape );
2909 bool degreeCue = std::any_of( degreeMarks.begin(), degreeMarks.end(),
2910 [&](
const auto& aPair )
2912 return aPair.first == &text;
2919 BOX2I glyphBox =
text.GetEffectiveTextShape(
false )->BBox();
2930 bool sourceVertical =
text.GetTextAngle().IsVertical();
2933 VECTOR2I canvasPosition = sourceCanvas - canvasOffset +
VECTOR2I( 0, baseline );
2935 text.SetPosition( target );
2940 for(
const auto& [
text, degree] : degreeMarks )
2943 int radius = degree->GetRadius();
2946 degree->SetPosition( degreeLocal );
2950 std::vector<SCH_ITEM*> pinTexts;
2957 pinTexts.push_back( &item );
2966 std::map<std::string, std::string> props =
effectiveProps( aInst, def );
2968 auto occurrenceProperty = [&](
const char* aName ) ->
const std::string*
2978 auto property = std::find_if( occurrence->second.begin(), occurrence->second.end(),
2979 [&](
const auto& aProperty )
2981 return propertyNamesEqual( aProperty.first, aName );
2983 return property != occurrence->second.end() ? &
property->second :
nullptr;
2986 const std::string* occurrenceValue = occurrenceProperty(
"Value" );
2987 std::string value = occurrenceValue ? *occurrenceValue : aInst.
value;
2989 if( !occurrenceValue && value.empty() )
2991 auto vIt = props.find(
"Value" );
2993 if( vIt != props.end() )
2994 value = vIt->second;
2997 if( !occurrenceValue && value.empty() )
3000 auto installed = std::find_if( props.begin(), props.end(),
3001 [](
const auto& aProperty )
3003 return isInstalledPropertyName( aProperty.first );
3006 installed != props.end() && wxString::FromUTF8( installed->second ).CmpNoCase( wxS(
"NI" ) ) == 0;
3008 const std::string* occurrenceFootprint = occurrenceProperty(
"PCB Footprint" );
3009 std::string footprint = occurrenceFootprint ? *occurrenceFootprint : std::string();
3010 auto fIt = props.find(
"PCB Footprint" );
3012 if( !occurrenceFootprint && fIt != props.end() )
3013 footprint = fIt->second;
3015 if( !occurrenceFootprint && footprint.empty() )
3027 && field.GetText().CmpNoCase( wxS(
"NI" ) ) == 0 )
3029 notInstalled =
true;
3041 if( valueField && valueField->
IsVisible() )
3042 valueField->
SetText( wxS(
"NI" ) );
3045 symbol->
SetRef( &aSheetPath, reference );
3050 bool nativePower = std::any_of( aInst.
pins.begin(), aInst.
pins.end(),
3053 return m_currentImplicitPowerPins.count( &aPin );
3063 if( def.
pins.empty() && aInst.
pins.empty() )
3076 if( pi < def.
pins.size() )
3078 size_t position = def.
pins[pi].position >= 0 ? def.
pins[pi].position : pi;
3081 : wxString::Format( wxS(
"%zu" ), pi + 1 );
3082 std::vector<SCH_PIN*> candidates;
3087 candidates.push_back(
pin );
3090 if( candidates.size() == 1 && candidates.front()->GetLibPin() )
3091 identity.
libraryPin = candidates.front()->GetLibPin()->m_Uuid;
3094 sourcePins.push_back( std::move( identity ) );
3102 if(
pin.IsNoConnect() && !
pin.wordA && !
pin.wordB )
3122 if( !occurrence.IsEmpty() && !occurrence.EndsWith( wxS(
"?" ) ) )
3123 reference = occurrence;
3127 if( reference.IsEmpty() )
3128 reference = wxS(
"?" );
3149 int w = bb.
x2 - bb.
x1;
3150 int h = bb.
y2 - bb.
y1;
3155 int bx = hasBbox ? std::min( aInst.
bbox.
x1, aInst.
bbox.
x2 ) : aInst.
x;
3156 int by = hasBbox ? std::min( aInst.
bbox.
y1, aInst.
bbox.
y2 ) : aInst.
y;
3161 wxString reference = wxString::Format( wxS(
"#PWR%04d" ),
m_powerCount );
3174 std::vector<SCH_PIN*> pins = symbol->
GetPins();
3189 auto nameProperty = aInst.
props.find(
"Name" );
3190 std::string displayName = nameProperty != aInst.
props.end() ? nameProperty->second : std::string();
3201 return propertyNamesEqual( aProp.name,
"Name" )
3202 || propertyNamesEqual( aProp.name,
"NODENAME" );
3209 : !logicalName.empty() ? logicalName
3213 int size =
textSizeIU( fontId, templateFont );
3215 bool textVertical = ( displayedName->rotation & 1 ) != 0;
3222 applyFont( &displayField, fontId, templateFont );
3239 symbol->
SetRef( &aSheetPath, reference );
3248 const std::string& aFootprint )
3253 int w = bb.
x2 - bb.
x1;
3254 int h = bb.
y2 - bb.
y1;
3259 int bxmin = std::min( c1.
x, c2.
x );
3260 int bxmax = std::max( c1.
x, c2.
x );
3261 int bymin = std::min( c1.
y, c2.
y );
3262 int bymax = std::max( c1.
y, c2.
y );
3270 bool vertical = angle == 90 || angle == 270;
3274 bool showRef =
false;
3275 bool showVal =
false;
3276 bool showRefName =
false;
3277 bool showValName =
false;
3279 auto findReferenceDisplay = [&](
const char* aName,
bool aVisibleOnly ) ->
const ORCAD_DISPLAY_PROP*
3284 return propertyNamesEqual( aDisplay.name, aName )
3285 && ( !aVisibleOnly || OrcadDisplayPropVisible( aDisplay ) );
3288 return it != aInst.
displayProps.end() ? &*it :
nullptr;
3291 const ORCAD_DISPLAY_PROP* referenceDisplay = findReferenceDisplay(
"Part Reference",
true );
3293 if( !referenceDisplay )
3294 referenceDisplay = findReferenceDisplay(
"Reference",
true );
3296 if( !referenceDisplay )
3297 referenceDisplay = findReferenceDisplay(
"Part Reference",
false );
3299 if( !referenceDisplay )
3300 referenceDisplay = findReferenceDisplay(
"Reference",
false );
3302 if( referenceDisplay )
3326 bool side = !vertical && aDef.
pins.size() == 2 && aInst.
pins.size() == 2
3332 int ry = showVal ? cym - schMm( 0.9 ) : cym;
3363 std::map<std::string, std::pair<VECTOR2I, const ORCAD_DISPLAY_PROP*>> shown;
3367 auto value = std::make_pair(
OrcadDbuToIu( aInst.
x + dp.
x, aInst.
y + dp.
y ), &dp );
3369 if( &dp == referenceDisplay )
3370 shown[
"Part Reference"] = value;
3374 shown[dp.
name] = value;
3377 auto findShown = [&](
const std::string& aName )
3379 auto exact = shown.find( aName );
3381 if( exact != shown.end() )
3384 return std::find_if( shown.begin(), shown.end(),
3385 [&](
const auto& aItem ) { return propertyNamesEqual( aItem.first, aName ); } );
3394 bool textVertical = ( aDp->rotation & 1 ) != 0;
3412 content += wxS(
" = " ) + aField->
GetText();
3433 if( !fpName.IsEmpty() )
3438 auto shownFootprint = findShown(
"PCB Footprint" );
3440 if( shownFootprint != shown.end() )
3445 int size =
textSizeIU( fontId, templateFont );
3447 fpMeta.
SetPosition( shownFootprint->second.first + displayBaselineShift( dp, size ) );
3450 applyFont( &fpMeta, fontId, templateFont );
3456 drawDisplayedField( &fpMeta, *dp );
3477 auto applyDisplayPos = [&](
SCH_FIELD* aField,
const char* aName )
3479 auto it = findShown( aName );
3481 if( it == shown.end() )
3487 int size =
textSizeIU( fontId, templateFont );
3490 aField->
SetPosition( it->second.first + displayBaselineShift( dp, size ) );
3492 applyFont( aField, fontId, templateFont );
3499 applyDisplayPos( refField,
"Part Reference" );
3500 applyDisplayPos( valField,
"Value" );
3502 if(
auto shownValue = findShown(
"Value" ); shownValue != shown.end() )
3503 drawDisplayedField( valField, *shownValue->second.second );
3505 std::map<std::string, std::string> properties =
effectiveProps( aInst, aDef );
3507 auto partReference = std::find_if( properties.begin(), properties.end(),
3508 [](
const auto& aProperty )
3509 { return propertyNamesEqual( aProperty.first,
"Part Reference" ); } );
3513 wxString displayedText;
3515 if( partReference != properties.end() && !occurrenceOverridesReference )
3521 std::string unitDesignator;
3528 unitDesignator = unitRef->second;
3533 if( unitDesignator.empty() && package && aInst.
unitIndex < package->devices.size() )
3534 unitDesignator = package->devices[aInst.
unitIndex].unitRef;
3536 if( unitDesignator.empty() && !package )
3539 if( unitDesignator.empty() && package && package->devices.size() > 1 )
3542 unitDesignator = unitDesignator.substr( 0, unitDesignator.find(
':' ) );
3544 if( !unitDesignator.empty() && unitDesignator.front() !=
'#' )
3545 displayedText = resolvedReference +
FromOrcadString( unitDesignator );
3550 if( !displayedText.IsEmpty() && displayedText != resolvedReference )
3555 displayedReference.
SetText( displayedText );
3558 applyDisplayPos( &displayedReference,
"Part Reference" );
3559 aSymbol->
AddField( displayedReference );
3563 if( findShown(
"Implementation" ) != shown.end() && !aInst.
value.empty() )
3565 auto implementation = std::find_if( properties.begin(), properties.end(),
3566 [](
const auto& aProperty )
3567 { return propertyNamesEqual( aProperty.first,
"Implementation" ); } );
3569 if( implementation == properties.end() )
3570 properties[
"Implementation"] = aInst.
value;
3571 else if( implementation->second.empty() )
3572 implementation->second = aInst.
value;
3575 for(
const auto& [propName, propValue] : properties )
3581 if( isBookkeepingProp( propName ) && findShown( propName ) == shown.end() )
3584 bool unset = propValue.empty() || propValue ==
"<" + propName +
">";
3594 std::vector<SCH_FIELD*> fields;
3615 applyDisplayPos( descriptionField,
"Description" );
3617 if(
auto shownDescription = findShown(
"Description" ); shownDescription != shown.end() )
3622 drawDisplayedField( descriptionField, dp );
3632 applyDisplayPos( datasheetField,
"Datasheet" );
3634 if(
auto shownDatasheet = findShown(
"Datasheet" ); shownDatasheet != shown.end() )
3639 drawDisplayedField( datasheetField, dp );
3645 wxString fieldName =
propertyNamesEqual( propName,
"Footprint" ) ? wxString(
"OrCAD Footprint Property" )
3650 auto sIt = findShown( propName );
3652 if( sIt != shown.end() )
3657 int size =
textSizeIU( fontId, templateFont );
3659 field.
SetPosition( sIt->second.first + displayBaselineShift( dp, size ) );
3662 applyFont( &field, fontId, templateFont );
3668 drawDisplayedField( &field, *dp );
3684 std::map<int, int> counts;
3685 std::vector<int> order;
3687 auto tally = [&](
int aFontIdx,
bool aTemplateFont = true )
3694 auto [it, isNew] = counts.try_emplace( height, 0 );
3697 order.push_back( height );
3720 for(
int height : order )
3722 if( counts[height] > bestCount )
3725 bestCount = counts[height];
3747 if( !
m_design.library.templateFonts.empty() )
3761 if( resolved > 0 && resolved <=
static_cast<int>(
m_design.library.fonts.size() ) )
3763 std::string face =
m_design.library.fonts[resolved - 1].face;
3764 std::transform( face.begin(), face.end(), face.begin(),
3765 [](
unsigned char aChar ) { return std::tolower( aChar ); } );
3767 if( face ==
"arial narrow" )
3768 return KiROUND( aTextSize * (
m_design.library.fonts[resolved - 1].bold ? 0.62 : 0.47 ) );
3770 if( face ==
"verdana" )
3771 return KiROUND( aTextSize * 0.675 );
3780 const std::vector<int>& templateFonts =
m_design.library.templateFonts;
3782 if( !templateFonts.empty() && aFontIdx >= 0 && aFontIdx <
static_cast<int>( templateFonts.size() ) )
3784 int mapped = templateFonts[aFontIdx];
3789 if( templateFonts.front() > 0 )
3790 return templateFonts.front();
3793 if( aFontIdx == 0 && !
m_design.library.fonts.empty() )
3805 if( aFontIdx > 0 && aFontIdx <= (
int)
m_design.library.fonts.size() )
3817 return schMm( 1.27 );
3819 double compensation = 1.4;
3822 if( resolved > 0 && resolved <=
static_cast<int>(
m_design.library.fonts.size() ) )
3824 std::string face =
m_design.library.fonts[resolved - 1].face;
3825 std::transform( face.begin(), face.end(), face.begin(),
3826 [](
unsigned char aChar ) { return std::tolower( aChar ); } );
3828 if( face ==
"arial narrow" )
3829 compensation =
m_design.library.fonts[resolved - 1].bold ? 1.6 : 1.46;
3830 else if( face ==
"verdana" )
3831 compensation = 1.46;
3834 double mm = std::round( height * 25.4 / ( 96.0 * compensation ) * 100.0 ) / 100.0;
3842 int height =
textSizeIU( aFontIdx, aTemplateFont );
3847 if( aFontIdx <= 0 || aFontIdx >
static_cast<int>(
m_design.library.fonts.size() ) )
3852 constexpr uint8_t c_FIXED_PITCH = 1;
3854 if( font.
width == 0 )
3859 std::string face = font.
face;
3860 std::transform( face.begin(), face.end(), face.begin(),
3861 [](
unsigned char aChar ) { return std::tolower( aChar ); } );
3863 double averageEmRatio = 0.5;
3865 if( face ==
"arial narrow" )
3868 averageEmRatio = font.
bold ? 803.0 / 2048.0 : 0.358;
3872 double mm = std::round(
schIUScale.IUTomm( height ) * aspect * 100.0 ) / 100.0;
3873 return VECTOR2I( schMm( mm ), height );
3876 double mm = std::round(
std::abs( font.
width ) * 25.4 * 0.9 / 96.0 * 100.0 ) / 100.0;
3878 return VECTOR2I( schMm( mm ), height );
3887 if( !aText || aFontIdx <= 0 || aFontIdx >
static_cast<int>(
m_design.library.fonts.size() ) )
3894 if( !font.
face.empty() )
3897 const std::vector<wxString>* embeddedFonts =
nullptr;
3899 if( face.CmpNoCase( wxS(
"Elephant" ) ) == 0 )
3901 face = wxS(
"KiCad OrCAD Elephant" );
3903 + wxS(
"/libwmf/fonts/KiCadOrCADElephant-Black.ttf" ) );
3906 if( files->
AddFile( fontFile,
false ) )
3920 if( !aText || aText->
GetText().Find(
'\n' ) == wxNOT_FOUND )
3923 int sourceHeight =
fontHeightDbu( aFontIdx, aTemplateFont );
3925 if( sourceHeight <= 0 )
3929 int sourceInterline = schMm( sourceHeight * 25.4 / 96.0 );
3932 if( kicadInterline > 0 )
3933 aText->
SetLineSpacing(
static_cast<double>( sourceInterline ) / kicadInterline );
3942 for(
unsigned char c : aName )
3945 bool separator = c ==
':' || c ==
'"' || c ==
'/' || c ==
' ' || c ==
'\t' || c ==
'\n' || c ==
'\r'
3946 || c ==
'\f' || c ==
'\v' || c == 0xA0;
3962 size_t first = out.find_first_not_of(
'_' );
3964 if( first == std::string::npos )
3967 size_t last = out.find_last_not_of(
'_' );
3968 out = out.substr( first, last - first + 1 );
3970 return out.empty() ?
"SYM" : out;
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)
bool displayUsesTemplateFont(const ORCAD_DISPLAY_PROP &aProp) const
void computeFontBaseline()
int displayFontId(const ORCAD_DISPLAY_PROP &aProp) const
const std::map< uint32_t, std::string > * m_currentOccUnitRefs
std::map< SCH_SYMBOL *, std::vector< SOURCE_PIN_IDENTITY > > m_sourcePinIdentities
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 std::map< uint32_t, std::string > * m_currentOccRefs
Per-page occurrence references distinguish repeated child schematics.
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
const std::map< uint32_t, std::map< std::string, std::string > > * m_currentOccProps
int resolveFontIndex(int aFontIdx) const
Resolve a Design Template font ID to its 1-based LOGFONT index.
void addSymbolPin(LIB_SYMBOL *aSymbol, const ORCAD_SYMBOL_PIN &aPin, const wxString &aNumber, int aUnit, bool aPower, const std::string &aNameOverride, bool aNameVisible, bool aShowPinNumbers, bool aNumberVisible, const BOX2I *aBodyBox, bool aHidden=false, bool aExplicitNet=false)
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.
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
VECTOR2I placedPinElectricalPosition(const ORCAD_PLACED_INSTANCE &aInstance, size_t aPinIndex) const
std::set< std::string > m_nativePowerFamilies
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.
static wxString GetStockDataPath(bool aRespectRunFromBuildDir=true)
Gets the stock (install) data path, which is the base path for things like scripting,...
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.
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...
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.
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)
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.
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.
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
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)
constexpr ORCAD_ORIENT_ENTRY ORCAD_ORIENT_TABLE[8]
Indexed by orientation bits: angle, mirror, offset selectors, then matrix coefficients.
VECTOR2I OrcadDbuToIu(int aX, int aY)
bool OrcadDisplayPropShowsName(const ORCAD_DISPLAY_PROP &aProp)
FILL_T OrcadFillType(int aFillStyle, int aHatchStyle)
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 OrcadTextBaselineOffset(int aTextSize)
int OrcadHatchPitchIu(uint32_t aModifyTimestamp)
bool OrcadDisplayPropShowsValue(const ORCAD_DISPLAY_PROP &aProp)
KIGFX::COLOR4D OrcadColor(int aColorIndex)
int OrcadOrientOf(int aRotation, bool aMirror)
Compose the 3-bit orientation code from the rotation bits and mirror bit.
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)
VECTOR2I OrcadOrientOffset(int aOrient, int aWidth, int aHeight)
Bbox re-anchoring offset for the given orientation and body size (DBU).
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)
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)
static bool propertyNamesEqual(const std::string &aLeft, const std::string &aRight)
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)
int OrcadPageGraphicLineWidthIu(int aWidth)
ORCAD_PORT_TYPE
Map unknown electrical type codes to PASSIVE.
@ ORCAD_ST_GLOBAL_SYMBOL
power symbol definition
wxString FromOrcadString(const std::string &aText)
Use an 8-bit fallback if Windows-1252 decoding fails.
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.
LINE_STYLE
Dashed line types.
The owning wire defines the connection.
Axis-aligned box in OrCAD DBU; corner order as stored (not normalized).
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
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 * 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::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
OrCAD rotates about the bounding box; KiCad rotates about the anchor.
int8_t tySel
Y offset selector.
int8_t txSel
X offset selector.
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.
Wire IDs refer to netmap, which supplies the source net names.
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
@ 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".
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