37 double sx = aStart.
x - aCenter.
x;
38 double sy = aStart.
y - aCenter.
y;
39 double ex = aEnd.
x - aCenter.
x;
40 double ey = aEnd.
y - aCenter.
y;
41 double radius = std::sqrt( sx * sx + sy * sy );
45 double mlen = std::sqrt( mx * mx + my * my );
51 midPt.
x = aCenter.
x +
static_cast<int>(
radius * mx / mlen );
52 midPt.
y = aCenter.
y +
static_cast<int>(
radius * my / mlen );
56 midPt.
x = aCenter.
x +
static_cast<int>( -sy *
radius / std::max(
radius, 1.0 ) );
57 midPt.
y = aCenter.
y +
static_cast<int>( sx *
radius / std::max(
radius, 1.0 ) );
79 if( aLine.size() < 3 || aLine[0] !=
'*' )
82 size_t endPos = aLine.find(
'*', 1 );
83 return endPos != std::string::npos && endPos > 1;
89 if( aLine.size() < 3 || aLine[0] !=
'*' )
92 size_t endPos = aLine.find(
'*', 1 );
94 if( endPos == std::string::npos || endPos <= 1 )
97 return aLine.substr( 1, endPos - 1 );
119 std::ifstream file( aFileName );
121 if( !file.is_open() )
129 std::vector<std::string> lines;
132 while( std::getline( file, line ) )
134 if( !line.empty() && line.back() ==
'\r' )
137 lines.push_back( line );
160 for(
size_t i = 1; i < lines.size(); i++ )
163 const std::string& currentLine = lines[i];
165 if( currentLine.empty() )
168 if( currentLine.find(
"*REMARK*" ) == 0 )
176 if( sectionName ==
"SCH" )
180 else if( sectionName ==
"CAM" || sectionName ==
"MISC" )
184 else if( sectionName ==
"FIELDS" )
188 else if( sectionName ==
"SHT" )
192 else if( sectionName ==
"CAE" )
196 else if( sectionName ==
"TEXT" )
200 else if( sectionName ==
"LINES" )
204 else if( sectionName ==
"CAEDECAL" )
208 else if( sectionName ==
"PARTTYPE" )
212 else if( sectionName ==
"PART" )
216 else if( sectionName ==
"BUSSES" )
220 else if( sectionName ==
"OFFPAGE REFS" )
224 else if( sectionName ==
"TIEDOTS" )
228 else if( sectionName ==
"CONNECTION" )
232 else if( sectionName ==
"NETNAMES" )
236 else if( sectionName ==
"END" )
256 for(
auto& attr : part.attributes )
258 if( attr.name ==
"Ref.Des." && attr.value.empty() )
259 attr.value = part.reference;
261 auto ovr = part.attr_overrides.find( attr.name );
263 if( ovr != part.attr_overrides.end() && attr.value.empty() )
264 attr.value = ovr->second;
272 std::ifstream file( aFileName );
274 if( !file.is_open() )
277 std::string firstLine;
279 if( !std::getline( file, firstLine ) )
282 if( !firstLine.empty() && firstLine.back() ==
'\r' )
283 firstLine.pop_back();
285 if( firstLine.find(
"*PADS-LOGIC" ) == 0 )
288 if( firstLine.find(
"*PADS-POWERLOGIC" ) == 0 )
297 if( aLine.empty() || aLine[0] !=
'*' )
300 size_t endPos = aLine.find(
'*', 1 );
302 if( endPos == std::string::npos )
305 std::string headerTag = aLine.substr( 1, endPos - 1 );
308 std::regex headerRegex( R
"(PADS-(POWER)?LOGIC-V(\d+\.\d+)(?:-([A-Za-z0-9]+))?)" );
311 if( !std::regex_match( headerTag, match, headerRegex ) )
314 if( match[1].matched )
315 m_header.product =
"PADS-POWERLOGIC";
319 m_header.version =
"V" + match[2].str();
321 if( match[3].matched )
324 if( endPos + 1 < aLine.size() )
326 std::string desc = aLine.substr( endPos + 1 );
327 size_t start = desc.find_first_not_of(
' ' );
329 if( start != std::string::npos )
330 m_header.description = desc.substr( start );
339 size_t i = aStartLine + 1;
341 while( i < aLines.size() )
343 const std::string& line = aLines[i];
354 std::istringstream iss( line );
358 if( keyword ==
"UNITS" )
371 else if( keyword ==
"CUR" )
376 if( second ==
"SHEET" )
379 else if( keyword ==
"SHEET" )
384 if( second ==
"SIZE" )
386 std::string sizeCode;
391 if( sizeCode ==
"A" )
396 else if( sizeCode ==
"B" )
401 else if( sizeCode ==
"C" )
406 else if( sizeCode ==
"D" )
411 else if( sizeCode ==
"E" )
416 else if( sizeCode ==
"A0" )
421 else if( sizeCode ==
"A1" )
426 else if( sizeCode ==
"A2" )
431 else if( sizeCode ==
"A3" )
436 else if( sizeCode ==
"A4" )
443 else if( keyword ==
"USERGRID" )
447 else if( keyword ==
"LINEWIDTH" )
451 else if( keyword ==
"CONNWIDTH" )
455 else if( keyword ==
"BUSWIDTH" )
459 else if( keyword ==
"BUSANGLE" )
463 else if( keyword ==
"TEXTSIZE" )
468 else if( keyword ==
"PINNAMESIZE" )
472 else if( keyword ==
"REFNAMESIZE" )
476 else if( keyword ==
"PARTNAMESIZE" )
480 else if( keyword ==
"PINNOSIZE" )
484 else if( keyword ==
"NETNAMESIZE" )
488 else if( keyword ==
"DOTGRID" )
492 else if( keyword ==
"TIEDOTSIZE" )
496 else if( keyword ==
"REAL" )
501 if( second ==
"WIDTH" )
504 else if( keyword ==
"FONT" )
509 if( second ==
"MODE" )
512 else if( keyword ==
"DEFAULT" )
517 if( second ==
"FONT" )
520 std::getline( iss, rest );
521 size_t start = rest.find(
'"' );
523 if( start != std::string::npos )
525 size_t end = rest.find(
'"', start + 1 );
527 if(
end != std::string::npos )
532 else if( keyword ==
"BORDER" )
537 if( second ==
"NAME" )
548 else if( keyword ==
"JOBNAME" )
551 std::getline( iss, rest );
552 size_t start = rest.find_first_not_of(
" \t" );
554 if( start != std::string::npos )
556 rest = rest.substr( start );
558 if( rest.size() >= 2 && rest.front() ==
'"' && rest.back() ==
'"' )
559 rest = rest.substr( 1, rest.size() - 2 );
565 else if( keyword ==
"NTXCOL" || keyword ==
"HIRCOL" || keyword ==
"LINCOL" || keyword ==
"TXTCOL"
566 || keyword ==
"CONCOL" || keyword ==
"BUSCOL" || keyword ==
"PTXCOL" || keyword ==
"COMCOL"
567 || keyword ==
"NMCOL" || keyword ==
"PNMCOL" || keyword ==
"PINCOL" || keyword ==
"NETCOL"
568 || keyword ==
"FBGCOL" || keyword ==
"FIELDCOL" || keyword ==
"NNVISPWRGND" || keyword ==
"PCBFLAGS"
569 || keyword ==
"JOBTIME" || keyword ==
"BACKUPTIME" || keyword ==
"OFFREFVIEW" || keyword ==
"OFFREFNUM"
570 || keyword ==
"SHEETNUMSEP" )
577 return aLines.size() - 1;
583 size_t i = aStartLine + 1;
585 while( i < aLines.size() )
587 const std::string& line = aLines[i];
592 if( line.empty() || line[0] !=
'"' )
599 size_t closeQuote = line.find(
'"', 1 );
601 if( closeQuote != std::string::npos )
603 std::string fieldName = line.substr( 1, closeQuote - 1 );
604 std::string fieldValue;
606 if( closeQuote + 1 < line.size() )
608 fieldValue = line.substr( closeQuote + 1 );
609 size_t start = fieldValue.find_first_not_of(
" \t" );
611 if( start != std::string::npos )
612 fieldValue = fieldValue.substr( start );
623 return aLines.size() - 1;
630 const std::string& line = aLines[aStartLine];
631 std::string afterMarker = line.substr( line.find(
'*', 1 ) + 1 );
633 std::istringstream iss( afterMarker );
648 size_t i = aStartLine + 1;
650 while( i < aLines.size() )
652 const std::string& line = aLines[i];
660 return aLines.size() - 1;
666 size_t i = aStartLine + 1;
668 while( i < aLines.size() )
670 const std::string& line = aLines[i];
684 std::istringstream iss( line );
693 std::getline( iss, rest );
694 size_t qStart = rest.find(
'"' );
696 if( qStart != std::string::npos )
698 size_t qEnd = rest.find(
'"', qStart + 1 );
700 if( qEnd != std::string::npos )
701 item.
font_name = rest.substr( qStart + 1, qEnd - qStart - 1 );
706 if( i < aLines.size() )
713 return aLines.size() - 1;
719 size_t i = aStartLine + 1;
721 while( i < aLines.size() )
723 const std::string& line = aLines[i];
735 if( line.find(
"LINES" ) != std::string::npos )
738 std::istringstream iss( line );
739 std::string
name, keyword;
744 if( keyword ==
"LINES" )
754 while( i < aLines.size() )
756 const std::string& pline = aLines[i];
767 if( pline.find(
"LINES" ) != std::string::npos )
769 std::istringstream tiss( pline );
770 std::string tname, tkw;
771 tiss >> tname >> tkw;
777 std::istringstream piss( pline );
778 std::string firstToken;
781 if( firstToken ==
"OPEN" || firstToken ==
"CLOSED" || firstToken ==
"CIRCLE"
782 || firstToken ==
"COPCLS" )
794 && ( std::isdigit( firstToken[0] ) || firstToken[0] ==
'-' || firstToken[0] ==
'+' );
796 if(
isNumber && pline.find(
'"' ) != std::string::npos )
800 std::istringstream tiss( pline );
803 tiss >> tx >> ty >>
text.rotation >>
text.justification >>
text.height >>
text.width_factor;
805 text.position.x = tx;
806 text.position.y = ty;
809 std::getline( tiss, trest );
810 size_t qStart = trest.find(
'"' );
812 if( qStart != std::string::npos )
814 size_t qEnd = trest.find(
'"', qStart + 1 );
816 if( qEnd != std::string::npos )
817 text.font_name = trest.substr( qStart + 1, qEnd - qStart - 1 );
822 if( i < aLines.size() )
823 text.content = aLines[i];
839 return aLines.size() - 1;
845 size_t i = aStartLine + 1;
847 while( i < aLines.size() )
849 const std::string& line = aLines[i];
863 if( !symbol.
name.empty() )
871 std::map<std::string, double> pinDecalLengths;
875 if( !sym.is_pin_decal )
878 for(
const auto& graphic : sym.graphics )
883 if( graphic.points.size() < 2 )
886 const auto& first = graphic.points.front().coord;
887 const auto& last = graphic.points.back().coord;
888 double dx = last.x - first.x;
889 double dy = last.y - first.y;
890 pinDecalLengths[sym.name] = std::sqrt( dx * dx + dy * dy );
897 if( sym.is_pin_decal )
900 for(
auto&
pin : sym.pins )
902 if(
pin.pin_decal_name.empty() )
905 auto it = pinDecalLengths.find(
pin.pin_decal_name );
907 if( it != pinDecalLengths.end() )
908 pin.length = it->second;
912 return i > 0 ? i - 1 : aLines.size() - 1;
918 if( aStartLine >= aLines.size() )
921 const std::string& headerLine = aLines[aStartLine];
925 std::istringstream iss( headerLine );
934 std::vector<std::string> tokens;
937 while( iss >> token )
938 tokens.push_back( token );
940 if( tokens.size() >= 12 )
958 if( tokens.size() >= 3 )
969 size_t idx = aStartLine + 1;
971 for(
int p = 0; p < aSymbol.
num_pieces && idx < aLines.size(); p++ )
973 const std::string& gline = aLines[idx];
979 std::istringstream giss( gline );
983 if( typeStr ==
"OPEN" || typeStr ==
"LINE" )
987 giss >> p1.
x >> p1.
y >> p2.
x >> p2.
y;
988 graphic.
points.push_back( { p1, std::nullopt } );
989 graphic.
points.push_back( { p2, std::nullopt } );
992 else if( typeStr ==
"CLOSED" || typeStr ==
"RECT" )
996 giss >> p1.
x >> p1.
y >> p2.
x >> p2.
y;
997 graphic.
points.push_back( { p1, std::nullopt } );
998 graphic.
points.push_back( { p2, std::nullopt } );
1001 else if( typeStr ==
"CIRCLE" )
1008 aSymbol.
graphics.push_back( graphic );
1012 for(
int p = 0; p < aSymbol.
num_pins && idx < aLines.size(); p++ )
1014 const std::string& pline = aLines[idx];
1020 std::istringstream piss( pline );
1021 double orientation = 0;
1023 piss >>
pin.position.x >>
pin.position.y >> orientation >>
pin.length;
1024 piss >>
pin.number >>
pin.name;
1026 pin.rotation = orientation;
1028 std::string typeStr;
1030 if( piss >> typeStr )
1033 aSymbol.
pins.push_back(
pin );
1040 size_t idx = aStartLine + 1;
1042 if( idx < aLines.size() && aLines[idx].find(
"TIMESTAMP" ) == 0 )
1044 std::istringstream tiss( aLines[idx] );
1051 if( idx < aLines.size() && aLines[idx].size() >= 2 && aLines[idx][0] ==
'"' )
1053 size_t qEnd = aLines[idx].find(
'"', 1 );
1055 if( qEnd != std::string::npos )
1056 aSymbol.
font1 = aLines[idx].substr( 1, qEnd - 1 );
1061 if( idx < aLines.size() && aLines[idx].size() >= 2 && aLines[idx][0] ==
'"' )
1063 size_t qEnd = aLines[idx].find(
'"', 1 );
1065 if( qEnd != std::string::npos )
1066 aSymbol.
font2 = aLines[idx].substr( 1, qEnd - 1 );
1072 for(
int a = 0; a < aSymbol.
num_attrs && idx + 1 < aLines.size(); a++ )
1075 std::istringstream aiss( aLines[idx] );
1083 std::getline( aiss, rest );
1084 size_t qStart = rest.find(
'"' );
1086 if( qStart != std::string::npos )
1088 size_t qEnd = rest.find(
'"', qStart + 1 );
1090 if( qEnd != std::string::npos )
1091 attr.
font_name = rest.substr( qStart + 1, qEnd - qStart - 1 );
1096 if( idx < aLines.size() )
1099 aSymbol.
attrs.push_back( attr );
1103 for(
int p = 0; p < aSymbol.
num_pieces && idx < aLines.size(); p++ )
1105 if( aLines[idx].
empty() )
1114 aSymbol.
graphics.push_back( graphic );
1120 while( idx < aLines.size() )
1122 const std::string& tline = aLines[idx];
1131 if( tline.size() > 1 && tline[0] ==
'T'
1132 && ( std::isdigit(
static_cast<unsigned char>( tline[1] ) ) || tline[1] ==
'-' ) )
1138 std::istringstream tiss( tline );
1141 tiss >> tx >> ty >>
text.rotation >>
text.justification;
1143 int height = 0, width = 0;
1144 tiss >> height >> width;
1146 text.width_factor = width;
1148 text.position.x = tx;
1149 text.position.y = ty;
1153 if( idx < aLines.size() )
1155 text.content = aLines[idx];
1163 for(
int p = 0; p < aSymbol.
num_pins && idx < aLines.size(); p++ )
1165 const std::string& tLine = aLines[idx];
1181 if( tLine.size() > 1 && tLine[0] ==
'T' )
1183 std::string tContent = tLine.substr( 1 );
1184 std::istringstream tiss( tContent );
1185 int tx = 0, ty = 0, angle = 0;
1187 tiss >> tx >> ty >> angle >>
pin.side >>
pin.pn_h >>
pin.pn_w >>
pin.pn_angle >>
pin.pn_just >>
pin.pl_h
1188 >>
pin.pl_w >>
pin.pl_angle >>
pin.pl_just >>
pin.pin_decal_name;
1190 pin.position.x = tx;
1191 pin.position.y = ty;
1192 pin.rotation = angle;
1195 if(
pin.pin_decal_name ==
"PINB" ||
pin.pin_decal_name ==
"PINORB" ||
pin.pin_decal_name ==
"PCLKB"
1196 ||
pin.pin_decal_name ==
"PINIEB" ||
pin.pin_decal_name ==
"PINCLKB" )
1198 pin.inverted =
true;
1201 if(
pin.pin_decal_name ==
"PCLK" ||
pin.pin_decal_name ==
"PCLKB" ||
pin.pin_decal_name ==
"PINCLK"
1202 ||
pin.pin_decal_name ==
"PINCLKB" )
1209 if(
pin.pin_decal_name.empty() )
1211 else if(
pin.pin_decal_name.find(
"SHORT" ) != std::string::npos )
1213 else if(
pin.pin_decal_name.find(
"LONG" ) != std::string::npos )
1220 if( idx < aLines.size() )
1222 const std::string& pLine = aLines[idx];
1224 if( pLine.size() > 1 && pLine[0] ==
'P' )
1226 std::string pContent = pLine.substr( 1 );
1227 std::istringstream piss( pContent );
1228 int px1 = 0, py1 = 0, px2 = 0, py2 = 0;
1230 piss >> px1 >> py1 >>
pin.pn_off_angle >>
pin.pn_off_just >> px2 >> py2 >>
pin.pl_off_angle
1231 >>
pin.pl_off_just >>
pin.p_flags;
1233 pin.pn_offset.x = px1;
1234 pin.pn_offset.y = py1;
1235 pin.pl_offset.x = px2;
1236 pin.pl_offset.y = py2;
1239 if(
pin.p_flags & 128 )
1247 pin.number = std::to_string( p + 1 );
1249 aSymbol.
pins.push_back(
pin );
1252 return idx > 0 ? idx - 1 : 0;
1259 if( aStartLine >= aLines.size() )
1262 const std::string& headerLine = aLines[aStartLine];
1263 std::istringstream iss( headerLine );
1264 std::string typeStr;
1265 int pointCount = 0, lineWidth = 0, lineStyle = 255;
1267 iss >> typeStr >> pointCount >> lineWidth >> lineStyle;
1272 if( typeStr ==
"OPEN" )
1277 else if( typeStr ==
"CLOSED" )
1282 else if( typeStr ==
"CIRCLE" )
1287 else if( typeStr ==
"COPCLS" )
1293 size_t idx = aStartLine + 1;
1295 for(
int p = 0; p < pointCount && idx < aLines.size(); p++ )
1297 const std::string& ptLine = aLines[idx];
1302 std::istringstream piss( ptLine );
1306 std::vector<std::string> extraTokens;
1309 while( piss >> tok )
1310 extraTokens.push_back( tok );
1312 if( extraTokens.size() >= 6 )
1324 aGraphic.
points.push_back( gpt );
1333 std::set<double> uniqueX, uniqueY;
1335 for(
const auto& pt : aGraphic.
points )
1337 uniqueX.insert( pt.coord.x );
1338 uniqueY.insert( pt.coord.y );
1341 bool isRect = ( uniqueX.size() == 2 && uniqueY.size() == 2 );
1345 double minX = *uniqueX.begin();
1346 double maxX = *uniqueX.rbegin();
1347 double minY = *uniqueY.begin();
1348 double maxY = *uniqueY.rbegin();
1351 aGraphic.
points.push_back( { { minX, minY }, std::nullopt } );
1352 aGraphic.
points.push_back( { { maxX, maxY }, std::nullopt } );
1365 double dx = aGraphic.
points[1].coord.x - aGraphic.
points[0].coord.x;
1366 double dy = aGraphic.
points[1].coord.y - aGraphic.
points[0].coord.y;
1367 aGraphic.
radius = std::sqrt( dx * dx + dy * dy ) / 2.0;
1370 return idx > 0 ? idx - 1 : aStartLine;
1376 size_t i = aStartLine + 1;
1378 while( i < aLines.size() )
1380 const std::string& line = aLines[i];
1393 std::istringstream iss( line );
1396 if( pt.
name.empty() )
1410 if( i < aLines.size() && aLines[i].find(
"TIMESTAMP" ) == 0 )
1412 std::istringstream tiss( aLines[i] );
1418 bool isSpecial = ( pt.
name ==
"$GND_SYMS" || pt.
name ==
"$PWR_SYMS" || pt.
name ==
"$OSR_SYMS" );
1423 bool isV52Gates = ( i < aLines.size() && aLines[i].size() >= 3 && aLines[i][0] ==
'G' && aLines[i][1] ==
':' );
1425 if( isSpecial && !isV52Gates )
1428 if( i < aLines.size() )
1430 std::istringstream siss( aLines[i] );
1431 int numVariants = 0;
1435 for(
int v = 0; v < numVariants && i < aLines.size(); v++ )
1438 std::istringstream viss( aLines[i] );
1451 else if( i < aLines.size() )
1455 if( pt.
name ==
"$GND_SYMS" )
1457 else if( pt.
name ==
"$PWR_SYMS" )
1464 while( i < aLines.size() )
1466 const std::string& gline = aLines[i];
1476 std::istringstream giss( gline );
1477 std::string keyword;
1480 if( keyword ==
"GATE" )
1495 for(
int p = 0; p < gate.
num_pins && i < aLines.size(); p++ )
1501 std::istringstream piss( aLines[i] );
1502 std::string pinType;
1504 piss >>
pin.pin_id >>
pin.swap_group >> pinType;
1506 if( !pinType.empty() )
1507 pin.pin_type = pinType[0];
1509 std::string pinName;
1511 if( piss >> pinName )
1512 pin.pin_name = pinName;
1518 pt.
gates.push_back( gate );
1521 else if( keyword.size() >= 3 && keyword[0] ==
'G' && keyword[1] ==
':' )
1530 std::string decalStr = keyword.substr( 2 );
1531 std::istringstream diss( decalStr );
1532 std::string decalName;
1534 while( std::getline( diss, decalName,
':' ) )
1536 if( !decalName.empty() )
1546 while( pinsRead < gate.
num_pins && i < aLines.size() )
1548 const std::string& pline = aLines[i];
1553 if( ( pline[0] ==
'G' && pline.size() >= 2 && pline[1] ==
':' ) || pline.find(
"SIGPIN" ) == 0 )
1558 std::istringstream piss( pline );
1559 std::string pinToken;
1561 while( piss >> pinToken && pinsRead < gate.
num_pins )
1564 std::vector<std::string> fields;
1565 std::istringstream fiss( pinToken );
1568 while( std::getline( fiss, field,
'.' ) )
1569 fields.push_back( field );
1571 if( fields.size() >= 1 )
1572 pin.pin_id = fields[0];
1574 if( fields.size() >= 2 )
1579 if( fields.size() >= 3 && !fields[2].empty() )
1580 pin.pin_type = fields[2][0];
1582 if( fields.size() >= 4 )
1583 pin.pin_name = fields[3];
1597 if( !gate.
pins.empty() )
1603 pt.
gates.push_back( gate );
1606 else if( keyword ==
"CONN" )
1620 std::istringstream diss( aLines[i] );
1621 std::string decalName, pinType;
1622 diss >> decalName >> pinType;
1627 for(
int p = 0; p < numPins && i < aLines.size(); p++ )
1633 std::istringstream piss( aLines[i] );
1634 std::string pinType;
1636 piss >>
pin.pin_id >>
pin.swap_group >> pinType;
1638 if( !pinType.empty() )
1639 pin.pin_type = pinType[0];
1645 pt.
gates.push_back( gate );
1648 else if( keyword ==
"SIGPIN" )
1656 if( token.find(
'.' ) != std::string::npos )
1658 std::vector<std::string> fields;
1659 std::istringstream fiss( token );
1662 while( std::getline( fiss, field,
'.' ) )
1663 fields.push_back( field );
1665 if( fields.size() >= 1 )
1668 if( fields.size() >= 3 )
1694 return aLines.size() - 1;
1700 size_t i = aStartLine + 1;
1702 while( i < aLines.size() && aLines[i].empty() )
1705 while( i < aLines.size() )
1707 const std::string& line = aLines[i];
1719 if( std::isalpha(
static_cast<unsigned char>( line[0] ) ) )
1737 return aLines.size() - 1;
1744 if( aStartLine >= aLines.size() )
1747 const std::string& headerLine = aLines[aStartLine];
1748 std::istringstream iss( headerLine );
1753 std::string refdes, partType;
1754 int x = 0, y = 0, angleCode = 0, mirrorFlag = 0;
1756 iss >> refdes >> partType;
1762 std::string actualPartType;
1763 iss >> actualPartType >> x >> y >> angleCode >> mirrorFlag;
1766 partType = actualPartType;
1770 iss >> y >> angleCode >> mirrorFlag;
1781 case 0: aPart.
rotation = 0.0;
break;
1782 case 1: aPart.
rotation = 90.0;
break;
1783 case 2: aPart.
rotation = 180.0;
break;
1784 case 3: aPart.
rotation = 270.0;
break;
1785 default: aPart.
rotation = angleCode;
break;
1795 if( iss >> variantIdx )
1800 int numAttrs = 0, numDisplayedValues = 0, numPins = 0, unused1 = 0, gateIdx = 0;
1803 if( iss >> aPart.
h1 >> aPart.
w1 >> aPart.
h2 >> aPart.
w2 >> numAttrs >> numDisplayedValues >> numPins >> unused1
1804 >> gateIdx >> unused2 )
1815 std::istringstream iss2( headerLine );
1823 std::string mirrorStr;
1825 if( iss2 >> mirrorStr )
1827 if( mirrorStr ==
"M" || mirrorStr ==
"Y" || mirrorStr ==
"1" )
1836 size_t sepPos = refdes.rfind(
'-' );
1838 if( sepPos == std::string::npos )
1839 sepPos = refdes.rfind(
'.' );
1841 if( sepPos != std::string::npos && sepPos + 1 < refdes.size() )
1843 char gateLetter = refdes[sepPos + 1];
1845 if( std::isalpha(
static_cast<unsigned char>( gateLetter ) ) )
1850 aPart.
gate_index = std::toupper(
static_cast<unsigned char>( gateLetter ) ) -
'A';
1860 const PARTTYPE_DEF& definition = partTypeDefinition->second;
1873 size_t i = aStartLine + 1;
1878 if( i < aLines.size() )
1880 const std::string& fl = aLines[i];
1882 if( fl.size() >= 2 && fl[0] ==
'"' )
1884 size_t qEnd = fl.find(
'"', 1 );
1886 if( qEnd != std::string::npos )
1887 aPart.
font1 = fl.substr( 1, qEnd - 1 );
1893 if( i < aLines.size() )
1895 const std::string& fl = aLines[i];
1897 if( fl.size() >= 2 && fl[0] ==
'"' )
1899 size_t qEnd = fl.find(
'"', 1 );
1901 if( qEnd != std::string::npos )
1902 aPart.
font2 = fl.substr( 1, qEnd - 1 );
1908 for(
int a = 0; a < aPart.
num_attrs && i + 1 < aLines.size(); a++ )
1911 std::istringstream aiss( aLines[i] );
1912 int ax = 0, ay = 0, angle = 0, disp = 0, h = 0, w = 0, vis = 0;
1914 aiss >> ax >> ay >> angle >> disp >> h >> w >> vis;
1928 attr.
visible = ( ( vis & 0x8 ) == 0 );
1931 std::getline( aiss, rest );
1932 size_t qStart = rest.find(
'"' );
1934 if( qStart != std::string::npos )
1936 size_t qEnd = rest.find(
'"', qStart + 1 );
1938 if( qEnd != std::string::npos )
1939 attr.
font_name = rest.substr( qStart + 1, qEnd - qStart - 1 );
1944 if( i < aLines.size() )
1945 attr.
name = aLines[i];
1954 if( !aLines[i].
empty() && std::isdigit(
static_cast<unsigned char>( aLines[i][0] ) ) )
1959 if( i >= aLines.size() )
1962 const std::string& valLine = aLines[i];
1964 if( valLine.size() > 2 && valLine[0] ==
'"' )
1966 size_t closeQ = valLine.find(
'"', 1 );
1968 if( closeQ != std::string::npos )
1970 std::string attrName = valLine.substr( 1, closeQ - 1 );
1971 std::string attrValue;
1973 if( closeQ + 1 < valLine.size() )
1975 attrValue = valLine.substr( closeQ + 1 );
1976 size_t start = attrValue.find_first_not_of(
" \t" );
1978 if( start != std::string::npos )
1979 attrValue = attrValue.substr( start );
1997 attr.value = it->second;
2001 while( i < aLines.size() )
2003 const std::string& pline = aLines[i];
2012 if( std::isalpha(
static_cast<unsigned char>( pline[0] ) ) )
2016 if( std::isdigit(
static_cast<unsigned char>( pline[0] ) ) )
2019 std::istringstream poiss( pline );
2031 while( i < aLines.size() )
2033 const std::string& attrLine = aLines[i];
2035 if( attrLine.empty() )
2041 if( attrLine[0] ==
'@' )
2044 std::istringstream aiss( attrLine.substr( 1 ) );
2048 std::getline( aiss, rest );
2049 size_t start = rest.find_first_not_of(
" \t" );
2051 if( start != std::string::npos )
2053 rest = rest.substr( start );
2055 if( !rest.empty() && rest[0] ==
'"' )
2057 size_t endQuote = rest.find(
'"', 1 );
2059 if( endQuote != std::string::npos )
2061 attr.
value = rest.substr( 1, endQuote - 1 );
2062 rest = rest.substr( endQuote + 1 );
2067 std::istringstream viss( rest );
2069 std::getline( viss, rest );
2072 std::istringstream piss( rest );
2077 if( piss >> visStr )
2078 attr.
visible = ( visStr !=
"N" && visStr !=
"0" && visStr !=
"H" );
2084 else if( std::isalpha(
static_cast<unsigned char>( attrLine[0] ) ) )
2101 constexpr long long MAX_BUS_POINTS = 1'000'000;
2102 size_t i = aStartLine + 1;
2107 [&](
size_t aLine,
const wxString& aDetail )
2111 m_reporter->Report( wxString::Format(
_(
"BUSSES line %llu: unsupported record, %s. "
2112 "The bus was skipped." ),
2113 static_cast<unsigned long long>( aLine + 1 ),
2119 while( i < aLines.size() )
2121 const std::string& line = aLines[i];
2133 long long parsedPointCount = -1;
2134 std::istringstream header( line );
2137 if( !( header >> bus.
handle >> bus.
name >> parsedPointCount ) || header >> extra
2138 || !bus.
handle.starts_with(
"@@@B" ) || bus.
handle.size() == 4
2139 || parsedPointCount < 0 || parsedPointCount > MAX_BUS_POINTS )
2141 unsupported( i, wxS(
"invalid bus header or point count" ) );
2146 const size_t pointCount =
static_cast<size_t>( parsedPointCount );
2147 bool busMalformed =
false;
2150 if( !bus.
name.empty() )
2155 while( i < aLines.size() && bus.
path.size() < pointCount )
2161 if( aLines[i].
empty() )
2168 std::istringstream coordinates( aLines[i] );
2171 if( !( coordinates >> point.
x >> point.
y ) || coordinates >> extra )
2173 busMalformed =
true;
2178 bus.
path.push_back( point );
2183 if( busMalformed || bus.
path.size() != pointCount )
2185 unsupported( i == aLines.size() ? i - 1 : i,
2186 busMalformed ? wxS(
"invalid bus point" )
2187 : wxS(
"bus ended before its declared point count" ) );
2191 m_buses.push_back( std::move( bus ) );
2194 return aLines.size() - 1;
2200 size_t i = aStartLine + 1;
2202 while( i < aLines.size() )
2204 const std::string& line = aLines[i];
2216 if( line.find(
"@@@O" ) == 0 )
2219 std::istringstream iss( line );
2220 std::string idToken;
2223 if( idToken.size() > 4 )
2238 return aBus.handle == opc.symbol_lib && aBus.sheet_number == m_currentSheet;
2245 if( std::find( bus->member_nets.begin(), bus->member_nets.end(), opc.
signal_name )
2246 == bus->member_nets.end() )
2256 return aLines.size() - 1;
2262 size_t i = aStartLine + 1;
2264 while( i < aLines.size() )
2266 const std::string& line = aLines[i];
2278 if( line.find(
"@@@D" ) == 0 )
2281 std::istringstream iss( line );
2282 std::string idToken;
2285 if( idToken.size() > 4 )
2300 return aLines.size() - 1;
2307 size_t i = aStartLine + 1;
2309 while( i < aLines.size() )
2311 const std::string& line = aLines[i];
2324 if( secName ==
"SIGNAL" )
2329 if( !signal.
name.empty() )
2331 for(
auto& wire : signal.
wires )
2335 for(
const auto& wire : signal.
wires )
2337 for(
const auto& ep : { wire.endpoint_a, wire.endpoint_b } )
2339 if( ep.find(
'.' ) != std::string::npos && ep.find(
"@@@" ) == std::string::npos )
2341 size_t dotPos = ep.find(
'.' );
2343 conn.
reference = ep.substr( 0, dotPos );
2364 m_signals.push_back( std::move( signal ) );
2379 return aLines.size() - 1;
2385 if( aStartLine >= aLines.size() )
2389 const std::string& headerLine = aLines[aStartLine];
2392 if( secName !=
"SIGNAL" )
2395 size_t afterMarker = headerLine.find(
'*', 1 );
2397 if( afterMarker == std::string::npos )
2400 std::string rest = headerLine.substr( afterMarker + 1 );
2401 std::istringstream iss( rest );
2405 size_t i = aStartLine + 1;
2407 if( aSignal.
flags2 == 1 && i < aLines.size() )
2409 const std::string& funcLine = aLines[i];
2411 if( funcLine.find(
"\"FUNCTION\"" ) != std::string::npos || funcLine.find(
"FUNCTION" ) == 0 )
2413 size_t qStart = funcLine.find(
'"' );
2415 if( qStart != std::string::npos )
2417 size_t qEnd = funcLine.find(
'"', qStart + 1 );
2419 if( qEnd != std::string::npos )
2421 size_t afterQ = funcLine.find_first_not_of(
" \t", qEnd + 1 );
2423 if( afterQ != std::string::npos )
2424 aSignal.
function = funcLine.substr( afterQ );
2434 while( i < aLines.size() )
2436 const std::string& line = aLines[i];
2448 std::istringstream wiss( line );
2459 for(
int v = 0; v < wire.
vertex_count && i < aLines.size(); v++ )
2461 const std::string& ptLine = aLines[i];
2467 std::istringstream piss( ptLine );
2468 piss >> pt.
x >> pt.
y;
2479 aSignal.
wires.push_back( wire );
2482 return i > 0 ? i - 1 : aStartLine;
2488 size_t i = aStartLine + 1;
2490 while( i < aLines.size() )
2492 const std::string& line = aLines[i];
2506 std::istringstream iss( line );
2513 std::getline( iss, rest );
2514 size_t qStart = rest.find(
'"' );
2516 if( qStart != std::string::npos )
2518 size_t qEnd = rest.find(
'"', qStart + 1 );
2520 if( qEnd != std::string::npos )
2521 label.
font_name = rest.substr( qStart + 1, qEnd - qStart - 1 );
2528 return aLines.size() - 1;
2534 size_t i = aStartLine + 1;
2536 bool foundFirstBrace =
false;
2538 while( i < aLines.size() )
2540 const std::string& line = aLines[i];
2542 for(
char c : line )
2547 foundFirstBrace =
true;
2555 if( foundFirstBrace && braceDepth <= 0 )
2565 return aLines.size() - 1;
2573 if( sym.name == aName )
2585 if( part.reference == aReference )
2597 if( signal.name == aName )
2609 if( sheets.empty() )
2612 return *sheets.rbegin();
2618 std::set<int> sheets;
2621 sheets.insert( header.sheet_num );
2624 sheets.insert( part.sheet_number );
2628 for(
const auto& wire : signal.wires )
2629 sheets.insert( wire.sheet_number );
2631 for(
const auto& conn : signal.connections )
2632 sheets.insert( conn.sheet_number );
2635 if( sheets.empty() )
2644 std::vector<SCH_SIGNAL>
result;
2649 filteredSignal.
name = signal.name;
2651 for(
const auto& wire : signal.wires )
2653 if( wire.sheet_number == aSheetNumber )
2654 filteredSignal.
wires.push_back( wire );
2657 for(
const auto& conn : signal.connections )
2659 if( conn.sheet_number == aSheetNumber )
2664 result.push_back( filteredSignal );
2673 std::vector<PART_PLACEMENT>
result;
2677 if( part.sheet_number == aSheetNumber )
2678 result.push_back( part );
2687 std::string upper = aTypeStr;
2688 std::transform( upper.begin(), upper.end(), upper.begin(), ::toupper );
2690 if( upper ==
"I" || upper ==
"IN" || upper ==
"INPUT" || upper ==
"L" )
2693 if( upper ==
"O" || upper ==
"OUT" || upper ==
"OUTPUT" || upper ==
"S" )
2696 if( upper ==
"B" || upper ==
"BI" || upper ==
"BIDIR" || upper ==
"BIDIRECTIONAL" )
2699 if( upper ==
"T" || upper ==
"TRI" || upper ==
"TRISTATE" )
2702 if( upper ==
"OC" || upper ==
"OPENCOLLECTOR" )
2705 if( upper ==
"OE" || upper ==
"OPENEMITTER" )
2708 if( upper ==
"P" || upper ==
"PWR" || upper ==
"POWER" || upper ==
"G" )
2711 if( upper ==
"PAS" || upper ==
"PASSIVE" )
2720 switch( std::toupper( aTypeChar ) )
size_t skipBraceDelimitedSection(const std::vector< std::string > &aLines, size_t aStartLine)
size_t parseSectionBUSSES(const std::vector< std::string > &aLines, size_t aStartLine)
size_t parseSectionPARTTYPE(const std::vector< std::string > &aLines, size_t aStartLine)
bool isSectionMarker(const std::string &aLine) const
bool Parse(const std::string &aFileName)
size_t parseSymbolDef(const std::vector< std::string > &aLines, size_t aStartLine, SYMBOL_DEF &aSymbol)
size_t parseSectionSCH(const std::vector< std::string > &aLines, size_t aStartLine)
size_t parseSectionCAEDECAL(const std::vector< std::string > &aLines, size_t aStartLine)
std::vector< OFF_PAGE_CONNECTOR > m_offPageConnectors
size_t parseSectionTIEDOTS(const std::vector< std::string > &aLines, size_t aStartLine)
size_t parsePartPlacement(const std::vector< std::string > &aLines, size_t aStartLine, PART_PLACEMENT &aPart)
size_t parseSectionSHT(const std::vector< std::string > &aLines, size_t aStartLine)
std::vector< SCH_SIGNAL > m_signals
size_t parseSectionOFFPAGEREFS(const std::vector< std::string > &aLines, size_t aStartLine)
std::string extractSectionName(const std::string &aLine) const
size_t parseSectionCONNECTION(const std::vector< std::string > &aLines, size_t aStartLine)
size_t parseSectionLINES(const std::vector< std::string > &aLines, size_t aStartLine)
size_t parseGraphicPrimitive(const std::vector< std::string > &aLines, size_t aStartLine, SYMBOL_GRAPHIC &aGraphic)
static PIN_TYPE ParsePinTypeChar(char aTypeChar)
bool parseHeader(const std::string &aLine)
std::vector< SHEET_HEADER > m_sheetHeaders
size_t parseSectionNETNAMES(const std::vector< std::string > &aLines, size_t aStartLine)
std::vector< SYMBOL_DEF > m_symbolDefs
std::vector< PART_PLACEMENT > m_partPlacements
PIN_TYPE parsePinType(const std::string &aTypeStr)
std::vector< SCH_SIGNAL > GetSignalsOnSheet(int aSheetNumber) const
std::set< int > GetSheetNumbers() const
std::vector< TEXT_ITEM > m_textItems
static bool CheckFileHeader(const std::string &aFileName)
size_t parseSectionTEXT(const std::vector< std::string > &aLines, size_t aStartLine)
size_t parseSignalDef(const std::vector< std::string > &aLines, size_t aStartLine, SCH_SIGNAL &aSignal)
std::vector< NETNAME_LABEL > m_netNameLabels
std::vector< PART_PLACEMENT > GetPartsOnSheet(int aSheetNumber) const
std::vector< LINES_ITEM > m_linesItems
const SCH_SIGNAL * GetSignal(const std::string &aName) const
std::vector< TIED_DOT > m_tiedDots
std::map< std::string, PARTTYPE_DEF > m_partTypes
std::vector< BUS_DEF > m_buses
const SYMBOL_DEF * GetSymbolDef(const std::string &aName) const
const PART_PLACEMENT * GetPartPlacement(const std::string &aReference) const
size_t parseSectionCAE(const std::vector< std::string > &aLines, size_t aStartLine)
size_t parseSectionFIELDS(const std::vector< std::string > &aLines, size_t aStartLine)
size_t parseSectionPART(const std::vector< std::string > &aLines, size_t aStartLine)
int GetSheetCount() const
static bool empty(const wxTextEntryBase *aCtrl)
static bool isNumber(const char *cp, const char *limit)
Return true if the next sequence of text is a number: either an integer, fixed point,...
int ParseInt(const std::string &aStr, int aDefault, const std::string &aContext)
Parse integer from string with error context.
double ParseDouble(const std::string &aStr, double aDefault, const std::string &aContext)
Parse double from string with error context.
VECTOR2I padsSchArcMidpoint(const VECTOR2I &aStart, const VECTOR2I &aEnd, const VECTOR2I &aCenter)
Midpoint of the arc through aStart and aEnd about aCenter, on the minor-arc side (the perpendicular b...
std::vector< FAB_LAYER_COLOR > dummy
std::vector< POINT > path
std::vector< std::string > aliases
std::vector< std::string > decal_names
std::vector< PARTTYPE_PIN > pins
std::optional< ARC_DATA > arc
std::vector< TEXT_ITEM > texts
std::vector< SYMBOL_GRAPHIC > primitives
std::vector< GATE_DEF > gates
std::vector< SPECIAL_VARIANT > special_variants
std::vector< std::string > swap_lines
std::vector< SIGPIN > sigpins
std::string special_keyword
std::string power_net_name
std::map< std::string, std::string > attr_overrides
std::string symbol_name
The part type, which is also the power symbol's net name.
std::string decal_name
CAEDECAL the placed gate draws, empty when unresolved.
std::vector< PART_ATTRIBUTE > attributes
std::vector< PIN_OVERRIDE > pin_overrides
std::vector< PIN_CONNECTION > connections
std::vector< WIRE_SEGMENT > wires
std::vector< SYMBOL_GRAPHIC > graphics
std::vector< SYMBOL_PIN > pins
std::vector< CAEDECAL_ATTR > attrs
std::vector< SYMBOL_TEXT > texts
std::vector< GRAPHIC_POINT > points
Wire segment connecting two endpoints through coordinate vertices.
std::vector< POINT > vertices
wxString result
Test unit parsing edge cases and error handling.
VECTOR2< int32_t > VECTOR2I