47 std::vector<std::string>
result;
49 size_t braceStart = aPattern.find(
'{' );
50 size_t braceEnd = aPattern.find(
'}' );
52 if( braceStart == std::string::npos || braceEnd == std::string::npos || braceEnd <= braceStart )
54 result.push_back( aPattern );
58 std::string prefix = aPattern.substr( 0, braceStart );
59 std::string suffix = ( braceEnd + 1 < aPattern.length() ) ? aPattern.substr( braceEnd + 1 ) :
"";
60 std::string range = aPattern.substr( braceStart + 1, braceEnd - braceStart - 1 );
62 size_t dashPos = range.find(
'-' );
64 if( dashPos == std::string::npos )
66 result.push_back( aPattern );
73 if( start == INT_MIN ||
end == INT_MIN )
75 result.push_back( aPattern );
79 static constexpr int MAX_EXPANSION = 10000;
83 wxLogTrace(
tracePadsIo, wxT(
"PADS Import: shortcut range {%d-%d} exceeds limit, skipped" ),
85 result.push_back( aPattern );
89 for(
int i = start; i <=
end; ++i )
91 result.push_back( prefix + std::to_string( i ) + suffix );
108 std::ifstream file( aFileName.ToStdString() );
109 if( !file.is_open() )
111 throw std::runtime_error(
"Could not open file " + aFileName.ToStdString() );
119 throw std::runtime_error(
"Empty file" );
131 if( line.size() > 2 && line[0] ==
'*' && line.back() ==
'*' )
133 std::string header = line.substr( 1, line.size() - 2 );
137 if( header.find(
"LIBRARY-LINE-ITEMS" ) != std::string::npos ||
138 header.find(
"LIBRARY-LINE" ) != std::string::npos )
142 else if( header.find(
"LIBRARY-SCH-DECALS" ) != std::string::npos )
146 else if( header.find(
"LIBRARY-PCB-DECALS" ) != std::string::npos ||
147 header.find(
"LIBRARY-DECALS" ) != std::string::npos )
151 else if( header.find(
"LIBRARY-PART-TYPES" ) != std::string::npos )
157 size_t v_pos = header.rfind(
"-V" );
159 if( v_pos != std::string::npos )
167 else if( line.size() > 2 && line[0] ==
'!' )
171 size_t close_pos = line.find(
'!', 1 );
173 if( close_pos == std::string::npos )
174 close_pos = line.size();
176 std::string header = line.substr( 1, close_pos - 1 );
179 std::vector<std::string> parts;
183 while( ( pos = header.find(
'-', start ) ) != std::string::npos )
185 parts.push_back( header.substr( start, pos - start ) );
189 parts.push_back( header.substr( start ) );
192 if( parts.size() >= 4 )
199 if( parts.size() >= 5 )
202 if( parts.size() >= 6 )
205 else if( parts.size() >= 2 )
210 if( parts.size() >= 2 )
213 if( parts.size() >= 3 )
235 else if( line.find(
"BASIC" ) != std::string::npos )
249 if( line.empty() )
continue;
251 if( line.rfind(
"*PCB*", 0 ) == 0 )
255 else if( line.rfind(
"*PART*", 0 ) == 0 )
259 else if( line.rfind(
"*NET*", 0 ) == 0 )
263 else if( line.rfind(
"*ROUTE*", 0 ) == 0 )
267 else if( line.rfind(
"*TEXT*", 0 ) == 0 )
271 else if( line.rfind(
"*BOARD*", 0 ) == 0 )
275 else if( line.rfind(
"*LINES*", 0 ) == 0 )
279 else if( line.rfind(
"*VIA*", 0 ) == 0 )
283 else if( line.rfind(
"*POUR*", 0 ) == 0 )
287 else if( line.rfind(
"*PARTDECAL*", 0 ) == 0 )
291 else if( line.rfind(
"*PARTTYPE*", 0 ) == 0 )
295 else if( line.rfind(
"*REUSE*", 0 ) == 0 )
299 else if( line.rfind(
"*CLUSTER*", 0 ) == 0 )
303 else if( line.rfind(
"*JUMPER*", 0 ) == 0 )
307 else if( line.rfind(
"*TESTPOINT*", 0 ) == 0 )
311 else if( line.rfind(
"*NETCLASS*", 0 ) == 0 || line.rfind(
"*NETDEF*", 0 ) == 0 )
315 else if( line.rfind(
"*DIFFPAIR*", 0 ) == 0 || line.rfind(
"*DIFFPAIRS*", 0 ) == 0 )
319 else if( line.rfind(
"LAYER MILS", 0 ) == 0 || line.rfind(
"LAYER METRIC", 0 ) == 0 )
323 else if( line.rfind(
"*MISC*", 0 ) == 0 )
339 while( std::getline( aStream, aLine ) )
342 aLine.erase( 0, aLine.find_first_not_of(
" \t\r\n" ) );
343 aLine.erase( aLine.find_last_not_of(
" \t\r\n" ) + 1 );
345 if( aLine.empty() )
continue;
346 if( aLine.rfind(
"*REMARK*", 0 ) == 0 )
continue;
365 if( !ver.empty() && ( ver[0] ==
'V' || ver[0] ==
'v' ) )
368 size_t dot = ver.find(
'.', start );
369 std::string major_str = ( dot != std::string::npos ) ? ver.substr( start, dot - start )
370 : ver.substr( start );
374 return std::stoi( major_str );
376 catch(
const std::exception& )
393 std::istringstream iss( line );
397 if( token ==
"UNITS" )
406 else if( token ==
"USERGRID" )
410 else if( token ==
"MAXIMUMLAYER" )
414 else if( token ==
"ORIGIN" )
418 else if( token ==
"THERLINEWID" )
422 else if( token ==
"THERSMDWID" )
426 else if( token ==
"THERFLAGS" )
428 std::string flags_str;
433 m_parameters.thermal_flags = std::stoi( flags_str,
nullptr, 0 );
435 catch(
const std::exception& )
440 else if( token ==
"DRLOVERSIZE" )
444 else if( token ==
"VIAPSHVIA" )
448 else if( token ==
"STMINCLEAR" )
452 else if( token ==
"STMINSPOKES" )
456 else if( token ==
"MINCLEAR" )
460 else if( token ==
"DEFAULTCLEAR" )
464 else if( token ==
"MINTRACKWID" )
468 else if( token ==
"DEFAULTTRACKWID" )
472 else if( token ==
"MINVIASIZE" )
476 else if( token ==
"DEFAULTVIASIZE" )
480 else if( token ==
"MINVIADRILL" )
484 else if( token ==
"DEFAULTVIADRILL" )
488 else if( token ==
"HOLEHOLE" )
492 else if( token ==
"SILKCLEAR" )
496 else if( token ==
"MASKCLEAR" )
508 if( line.find(
"*REMARK*" ) == 0 )
518 if( line.rfind(
"}", 0 ) == 0 ||
519 line.rfind(
"{", 0 ) == 0 )
524 std::istringstream iss( line );
529 std::string name_token, parttype_string;
540 bool is_shortcut = ( expanded_names.size() > 1 );
541 part.
name = expanded_names[0];
545 size_t at_pos = parttype_string.find(
'@' );
547 if( at_pos != std::string::npos )
550 part.
part_type = parttype_string.substr( 0, at_pos );
551 part.
decal = parttype_string.substr( at_pos + 1 );
560 size_t colon_pos = 0;
563 while( ( colon_pos = parttype_string.find(
':', pos ) ) != std::string::npos )
565 std::string decal_name = parttype_string.substr( pos, colon_pos - pos );
569 part.
decal = decal_name;
581 std::string last_decal = parttype_string.substr( pos );
585 part.
decal = last_decal;
594 std::vector<std::string> tokens;
596 while( iss >> token )
598 tokens.push_back( token );
608 for(
size_t i = 0; i < tokens.size(); ++i )
610 const std::string& t = tokens[i];
631 if( i == tokens.size() - 1 )
636 labels = std::stoi( t, &pos );
638 if( pos != t.length() )
641 catch(
const std::exception& )
652 if( line.find(
".REUSE." ) == 0 )
654 std::istringstream riss( line );
655 std::string reuse_keyword;
664 for(
int i = 0; i < labels; ++i )
667 if( !
readLine( aStream, line ) )
break;
669 std::stringstream iss_attr( line );
670 std::string visible_str;
671 std::string mirrored_str;
672 std::string right_reading_str;
678 attr.
visible = ( visible_str ==
"VALUE" || visible_str ==
"FULL_NAME"
679 || visible_str ==
"NAME" || visible_str ==
"FULL_BOTH"
680 || visible_str ==
"BOTH" );
681 attr.
mirrored = ( mirrored_str ==
"M" );
682 iss_attr >> right_reading_str;
683 attr.
right_reading = ( right_reading_str ==
"Y" || right_reading_str ==
"ORTHO" );
688 if( !
readLine( aStream, line ) )
break;
692 if( !
readLine( aStream, line ) )
break;
705 for(
size_t i = 1; i < expanded_names.size(); ++i )
707 PART additional_part = part;
708 additional_part.
name = expanded_names[i];
709 m_parts.push_back( additional_part );
722 NET* current_net =
nullptr;
725 auto parsePinToken = [](
const std::string& token,
NET_PIN&
pin ) ->
bool
727 size_t dot_pos = token.find(
'.' );
729 if( dot_pos == std::string::npos )
732 pin.ref_des = token.substr( 0, dot_pos );
733 pin.pin_name = token.substr( dot_pos + 1 );
739 auto expandShortcutPin = [](
const std::string& token ) -> std::vector<std::string>
741 std::vector<std::string> results;
744 if( token.find(
'{' ) == std::string::npos )
746 results.push_back( token );
757 bool is_range =
false;
760 std::vector<RangePart> parts;
762 std::string current_prefix;
764 while( pos < token.size() )
766 if( token[pos] ==
'{' )
768 size_t close_pos = token.find(
'}', pos );
770 if( close_pos == std::string::npos )
773 results.push_back( token );
777 std::string range_str = token.substr( pos + 1, close_pos - pos - 1 );
778 size_t dash_pos = range_str.find(
'-' );
780 if( dash_pos != std::string::npos )
783 part.prefix = current_prefix;
784 part.is_range =
true;
787 INT_MIN,
"net range" );
789 INT_MIN,
"net range" );
791 if( part.start == INT_MIN || part.end == INT_MIN )
793 results.push_back( token );
797 parts.push_back( part );
798 current_prefix.clear();
803 current_prefix += range_str;
810 current_prefix += token[pos];
816 if( !current_prefix.empty() || parts.empty() )
818 RangePart final_part;
819 final_part.prefix = current_prefix;
820 final_part.is_range =
false;
821 final_part.start = 0;
823 parts.push_back( final_part );
828 results.push_back(
"" );
830 for(
const auto& part : parts )
832 std::vector<std::string> new_results;
836 for(
const auto& base : results )
838 int step = ( part.start <= part.end ) ? 1 : -1;
840 for(
int i = part.start; step > 0 ? i <= part.end : i >= part.end; i += step )
842 new_results.push_back( base + part.prefix + std::to_string( i ) );
848 for(
const auto& base : results )
850 new_results.push_back( base + part.prefix );
854 results = std::move( new_results );
868 std::istringstream iss( line );
872 if( token ==
"SIGNAL" )
877 current_net = &
m_nets.back();
880 std::string pin_token;
882 while( iss >> pin_token )
885 if( pin_token ==
".REUSE." )
888 std::string instance, rsignal;
890 if( ( iss >> instance >> rsignal ) && !current_net->
pins.empty() )
892 current_net->
pins.back().reuse_instance = instance;
893 current_net->
pins.back().reuse_signal = rsignal;
900 for(
const auto& expanded : expandShortcutPin( pin_token ) )
904 if( parsePinToken( expanded,
pin ) )
905 current_net->
pins.push_back(
pin );
917 if( token ==
".REUSE." )
919 std::string instance, rsignal;
921 if( ( iss >> instance >> rsignal ) && !current_net->
pins.empty() )
923 current_net->
pins.back().reuse_instance = instance;
924 current_net->
pins.back().reuse_signal = rsignal;
931 for(
const auto& expanded : expandShortcutPin( token ) )
935 if( parsePinToken( expanded,
pin ) )
936 current_net->
pins.push_back(
pin );
939 }
while( iss >> token );
957 std::stringstream iss( line );
962 if( !( iss >>
name >> drill >> stacklines ) )
970 int drill_start_val = 0;
971 int drill_end_val = 0;
973 if( iss >> drill_start_val >> drill_end_val )
979 int min_layer = INT_MAX;
980 int max_layer = INT_MIN;
982 for(
int i = 0; i < stacklines; ++i )
987 std::stringstream iss2( line );
992 if( !( iss2 >> level >> size >> shape ) )
996 layer_data.
layer = level;
997 layer_data.
shape = shape;
998 layer_data.
sizeA = size;
1002 if( shape ==
"R" || shape ==
"S" )
1008 if( shape ==
"S" && ( iss2 >> corner ) )
1021 else if( shape ==
"RA" || shape ==
"SA" )
1026 else if( shape ==
"A" )
1034 else if( shape ==
"OF" )
1037 double ori = 0, length = 0, offset = 0;
1039 if( iss2 >> ori >> length >> offset )
1042 layer_data.
sizeB = length;
1046 else if( shape ==
"RF" )
1050 double ori = 0, length = 0, offset = 0;
1052 if( iss2 >> ori >> length >> offset )
1055 layer_data.
sizeB = length;
1059 else if( shape ==
"RT" || shape ==
"ST" )
1062 double ori = 0, intd = 0, spkwid = 0;
1065 if( iss2 >> ori >> intd >> spkwid >> spknum )
1073 else if( shape ==
"O" || shape ==
"OC" )
1079 else if( shape ==
"RC" )
1083 double ori = 0, length = 0, offset = 0, corner = 0;
1085 if( iss2 >> ori >> length >> offset )
1088 layer_data.
sizeB = length;
1091 if( iss2 >> corner )
1106 def.
stack.push_back( layer_data );
1111 int effective_layer = level;
1114 effective_layer = 1;
1115 else if( level == -1 )
1118 bool is_copper = ( effective_layer >= 1
1123 if( size > def.
size )
1126 if( effective_layer < min_layer )
1127 min_layer = effective_layer;
1129 if( effective_layer > max_layer )
1130 max_layer = effective_layer;
1136 else if( level == 28 )
1141 if( min_layer <= max_layer )
1147 bool starts_at_surface = ( min_layer == 1 || max_layer == layer_count );
1148 bool ends_at_surface = ( max_layer == layer_count || min_layer == 1 );
1149 bool is_full_span = ( min_layer == 1 && max_layer == layer_count );
1150 int span = max_layer - min_layer;
1156 else if( span == 1 && ( min_layer == 1 || max_layer == layer_count ) )
1160 else if( starts_at_surface || ends_at_surface )
1184 if( line[0] ==
'*' )
1192 std::stringstream iss( line );
1193 std::string
name, type;
1194 double x = 0.0, y = 0.0;
1195 int pieces = 0, flags = 0;
1197 if( !( iss >>
name >> type >> x >> y >> pieces >> flags ) )
1200 std::string owner, signame;
1201 double hatchgrid = 0.0, hatchrad = 0.0;
1204 if( iss >> owner >> signame )
1206 iss >> hatchgrid >> hatchrad >> priority;
1209 for(
int i = 0; i < pieces; ++i )
1216 std::stringstream iss2( line );
1217 std::string poly_type;
1218 int corners = 0, arcs = 0;
1222 if( !( iss2 >> poly_type >> corners >> arcs >> width >> level ) )
1231 pour.
is_cutout = ( poly_type ==
"POCUT" || poly_type ==
"CUTOUT"
1232 || poly_type ==
"CIRCUT" );
1240 if( type ==
"HATOUT" )
1244 else if( type ==
"VOIDOUT" )
1249 else if( type ==
"PADTHERM" )
1253 else if( type ==
"VIATHERM" )
1259 if( poly_type ==
"CIRCLE" || poly_type ==
"CIRCUT" )
1266 std::stringstream iss3( line );
1267 double cx = 0.0, cy = 0.0,
radius = 0.0;
1269 if( iss3 >> cx >> cy >>
radius )
1276 arc.start_angle = 0.0;
1277 arc.delta_angle = 360.0;
1278 pour.
points.emplace_back( x + cx +
radius, y + cy, arc );
1281 else if( poly_type ==
"SEG" )
1284 for(
int j = 0; j < corners; ++j )
1289 std::stringstream iss3( line );
1290 double px = 0.0, py = 0.0;
1292 if( iss3 >> px >> py )
1294 pour.
points.emplace_back( x + px, y + py );
1306 int totalLines = corners + arcs;
1307 bool nextIsArcEndpoint =
false;
1310 for(
int j = 0; j < totalLines; ++j )
1315 std::stringstream iss3( line );
1316 double px = 0.0, py = 0.0;
1318 if( !( iss3 >> px >> py ) )
1321 int angle1 = 0, angle2 = 0;
1323 if( iss3 >> angle1 >> angle2 )
1329 pendingArc.
cx = x + px;
1330 pendingArc.cy = y + py;
1331 pendingArc.start_angle = angle1 / 10.0;
1332 pendingArc.delta_angle = angle2 / 10.0;
1334 if( !pour.
points.empty() )
1336 double dx = pour.
points.back().x - pendingArc.cx;
1337 double dy = pour.
points.back().y - pendingArc.cy;
1338 pendingArc.radius = std::sqrt( dx * dx + dy * dy );
1341 nextIsArcEndpoint =
true;
1343 else if( nextIsArcEndpoint )
1345 if( pendingArc.radius == 0.0 )
1347 double dx = ( x + px ) - pendingArc.cx;
1348 double dy = ( y + py ) - pendingArc.cy;
1349 pendingArc.radius = std::sqrt( dx * dx + dy * dy );
1352 pour.
points.emplace_back( x + px, y + py, pendingArc );
1353 nextIsArcEndpoint =
false;
1357 pour.
points.emplace_back( x + px, y + py );
1372 if( line[0] ==
'*' )
1379 std::stringstream iss( line );
1380 std::string
name, units;
1381 double orix = 0.0, oriy = 0.0;
1382 int pieces = 0, terminals = 0, stacks = 0, text_cnt = 0, labels = 0;
1384 if( !( iss >>
name >> units >> orix >> oriy >> pieces >> terminals >> stacks >> text_cnt >> labels ) )
1389 decal.
units = units;
1392 for(
int i = 0; i < pieces; ++i )
1394 if( !
readLine( aStream, line ) )
break;
1397 std::stringstream iss2( line );
1403 if( !( iss2 >> type >> corners >> width ) )
1436 decal.
items.push_back( item );
1442 if( type.find(
"COP" ) == 0 )
1444 std::string remaining;
1445 std::getline( iss2, remaining );
1448 std::istringstream rem_ss( remaining );
1449 int pinnum_val = -1;
1451 if( rem_ss >> pinnum_val )
1452 item.
pinnum = pinnum_val;
1456 if( type.find(
"KPT" ) == 0 )
1458 std::string restrictions;
1460 if( iss2 >> restrictions )
1464 for(
int j = 0; j < corners; ++j )
1469 std::stringstream iss3( line );
1470 double px = 0.0, py = 0.0;
1472 if( !( iss3 >> px >> py ) )
1478 int startAngleTenths = 0, deltaAngleTenths = 0;
1479 double bboxMinX = 0.0, bboxMinY = 0.0, bboxMaxX = 0.0, bboxMaxY = 0.0;
1481 if( iss3 >> startAngleTenths >> deltaAngleTenths
1482 >> bboxMinX >> bboxMinY >> bboxMaxX >> bboxMaxY )
1484 double cx = ( bboxMinX + bboxMaxX ) / 2.0;
1485 double cy = ( bboxMinY + bboxMaxY ) / 2.0;
1486 double radius = ( bboxMaxX - bboxMinX ) / 2.0;
1487 double startAngle = startAngleTenths / 10.0;
1488 double deltaAngle = deltaAngleTenths / 10.0;
1491 double startAngleRad = startAngle *
M_PI / 180.0;
1492 double startX = cx +
radius * std::cos( startAngleRad );
1493 double startY = cy +
radius * std::sin( startAngleRad );
1496 double endAngleRad = ( startAngle + deltaAngle ) *
M_PI / 180.0;
1497 double endX = cx +
radius * std::cos( endAngleRad );
1498 double endY = cy +
radius * std::sin( endAngleRad );
1501 item.
points.emplace_back( startX, startY );
1507 arc.start_angle = startAngle;
1508 arc.delta_angle = deltaAngle;
1511 item.
points.emplace_back( endX, endY, arc );
1515 item.
points.emplace_back( px, py );
1519 decal.
items.push_back( item );
1526 for(
int i = 0; i < text_cnt + labels; ++i )
1528 std::string attrLine, fontLine, nameLine;
1530 if( !
readLine( aStream, attrLine ) )
1535 if( !
readLine( aStream, fontLine ) )
1539 if( !
readLine( aStream, nameLine ) )
1543 std::stringstream ss( attrLine );
1544 std::string type_token;
1547 std::string mirrored_str, right_reading_str;
1552 attr.
visible = ( type_token ==
"VALUE" || type_token ==
"FULL_NAME"
1553 || type_token ==
"NAME" || type_token ==
"FULL_BOTH"
1554 || type_token ==
"BOTH" );
1555 attr.
mirrored = ( mirrored_str ==
"M" );
1556 ss >> right_reading_str;
1557 attr.
right_reading = ( right_reading_str ==
"Y" || right_reading_str ==
"ORTHO" );
1561 attr.
name = nameLine;
1572 for(
int i = 0; i < terminals; ++i )
1574 if( !
readLine( aStream, line ) )
break;
1576 size_t t_pos = line.find(
'T' );
1578 if( t_pos != std::string::npos )
1581 std::stringstream iss_t( line );
1583 double nmx = 0.0, nmy = 0.0;
1585 if( iss_t >> term.
x >> term.
y >> nmx >> nmy )
1589 if( term.
name.empty() )
1590 term.
name = std::to_string( i + 1 );
1600 for(
int i = 0; i < stacks; ++i )
1605 std::stringstream iss_pad( line );
1608 int stack_lines = 0;
1609 iss_pad >> token >> pin_idx >> stack_lines;
1611 if( token !=
"PAD" )
1615 std::string plated_token;
1616 bool default_plated =
true;
1617 double header_drill = 0.0;
1619 if( iss_pad >> plated_token )
1621 if( plated_token ==
"P" )
1622 default_plated =
true;
1623 else if( plated_token ==
"N" )
1624 default_plated =
false;
1632 double header_slot_ori = 0.0;
1633 double header_slot_len = 0.0;
1634 double header_slot_off = 0.0;
1636 if( iss_pad >> header_slot_ori >> header_slot_len >> header_slot_off )
1641 std::vector<PAD_STACK_LAYER> stack;
1643 for(
int j = 0; j < stack_lines; ++j )
1648 std::stringstream line_ss( line );
1654 if( !( line_ss >> layer >> size >> shape ) )
1658 layer_data.
layer = layer;
1659 layer_data.
sizeA = size;
1660 layer_data.
sizeB = size;
1661 layer_data.
shape = shape;
1662 layer_data.
plated = default_plated;
1663 layer_data.
drill = header_drill;
1674 else if( shape ==
"S" )
1678 double corner = 0.0;
1680 if( line_ss >> corner )
1693 else if( shape ==
"RA" || shape ==
"SA" )
1698 else if( shape ==
"A" )
1703 if( line_ss >> intd )
1706 else if( shape ==
"OF" )
1709 double ori = 0.0, length = 0.0, offset = 0.0;
1711 if( line_ss >> ori >> length >> offset )
1714 layer_data.
sizeB = length;
1718 else if( shape ==
"RF" )
1722 double ori = 0.0, length = 0.0, offset = 0.0;
1724 if( line_ss >> ori >> length >> offset )
1727 layer_data.
sizeB = length;
1730 double corner = 0.0;
1732 if( line_ss >> corner )
1746 else if( shape ==
"RT" || shape ==
"ST" )
1749 double ori = 0.0, outsize = 0.0, spkwid = 0.0;
1752 if( line_ss >> ori >> outsize >> spkwid >> spknum )
1760 else if( shape ==
"O" || shape ==
"OC" )
1766 else if( shape ==
"RC" )
1770 double ori = 0.0, length = 0.0, offset = 0.0, corner = 0.0;
1772 if( line_ss >> ori >> length >> offset )
1775 layer_data.
sizeB = length;
1778 if( line_ss >> corner )
1795 std::vector<std::string> remaining;
1796 std::string token_rem;
1798 while( line_ss >> token_rem )
1799 remaining.push_back( token_rem );
1802 if( !remaining.empty() )
1808 -1.0,
"pad layer drill" );
1810 if( drill_val >= 0.0 )
1812 layer_data.
drill = drill_val;
1817 if( idx < remaining.size() )
1819 if( remaining[idx] ==
"P" || remaining[idx] ==
"Y" )
1821 layer_data.
plated =
true;
1824 else if( remaining[idx] ==
"N" )
1826 layer_data.
plated =
false;
1832 if( idx + 2 < remaining.size() )
1843 stack.push_back( layer_data );
1856 ROUTE* current_route =
nullptr;
1857 TRACK current_track;
1858 bool in_track =
false;
1859 bool prev_is_plane_connection =
false;
1861 int last_plane_connection_layer = 0;
1862 double last_plane_connection_width = 0;
1863 bool last_plane_on_copper =
false;
1864 std::string default_via_name;
1865 bool has_pending_arc_center =
false;
1867 std::string pending_arc_dir;
1871 if( line[0] ==
'*' )
1873 if( line.rfind(
"*SIGNAL*", 0 ) == 0 )
1875 if( in_track && current_route )
1877 current_route->
tracks.push_back( current_track );
1878 current_track.
points.clear();
1882 prev_is_plane_connection =
false;
1883 has_pending_arc_center =
false;
1885 std::istringstream iss( line );
1889 std::string net_name;
1893 default_via_name.clear();
1895 while( iss >> token )
1897 if( !token.empty() && token.back() ==
';' )
1901 default_via_name = token;
1906 current_route->
net_name = net_name;
1917 if( !isdigit( line[0] ) && line[0] !=
'-' && line[0] !=
'+' )
1919 if( in_track && current_route )
1921 current_route->
tracks.push_back( current_track );
1922 current_track.
points.clear();
1926 prev_is_plane_connection =
false;
1931 std::istringstream pin_iss( line );
1932 std::string pin_token;
1934 while( pin_iss >> pin_token )
1936 size_t dot_pos = pin_token.find(
'.' );
1938 if( dot_pos != std::string::npos )
1941 pin.ref_des = pin_token.substr( 0, dot_pos );
1942 pin.pin_name = pin_token.substr( dot_pos + 1 );
1947 for(
const auto& existing : current_route->
pins )
1949 if( existing.ref_des ==
pin.ref_des &&
1950 existing.pin_name ==
pin.pin_name )
1958 current_route->
pins.push_back(
pin );
1966 std::istringstream iss( line );
1971 iss >> pt.
x >> pt.
y >> layer >> width >> flags;
1983 std::string via_name;
1984 std::string arc_dir;
1990 bool is_unrouted = ( layer == 0 );
1991 bool is_plane_connection = is_unrouted;
1994 bool has_teardrop =
false;
1995 bool has_jumper =
false;
1996 bool has_power =
false;
1998 while( iss >> token )
2001 if( token ==
"CW" || token ==
"CCW" )
2010 if( token ==
"POWER" )
2020 if( token ==
"THERMAL" )
2031 if( token ==
"TEARDROP" )
2033 has_teardrop =
true;
2034 std::string td_token;
2036 while( iss >> td_token )
2038 if( td_token ==
"P" )
2044 std::streampos pos = iss.tellg();
2047 if( iss >> td_flags )
2057 else if( td_token ==
"N" )
2062 std::streampos pos = iss.tellg();
2065 if( iss >> td_flags )
2079 if( td_token ==
"CW" || td_token ==
"CCW" )
2081 else if( td_token ==
"POWER" )
2086 via_name = td_token;
2088 else if( td_token ==
"THERMAL" )
2091 via_name = td_token;
2102 std::streampos pos = iss.tellg();
2103 std::string jumper_flag;
2105 if( iss >> jumper_flag )
2107 if( jumper_flag ==
"S" || jumper_flag ==
"E" )
2110 jumper.
name = token;
2111 jumper.
is_start = ( jumper_flag ==
"S" );
2130 if( token ==
"REUSE" || token ==
".REUSE." )
2133 std::string instance;
2143 if( !arc_dir.empty() )
2145 pending_arc_center = pt;
2146 pending_arc_dir = arc_dir;
2147 has_pending_arc_center =
true;
2151 if( has_pending_arc_center )
2153 has_pending_arc_center =
false;
2155 if( in_track && !current_track.
points.empty() )
2158 double dx0 = arc_start.
x - pending_arc_center.
x;
2159 double dy0 = arc_start.
y - pending_arc_center.
y;
2160 double start_angle = std::atan2( dy0, dx0 );
2162 std::atan2( pt.
y - pending_arc_center.
y, pt.
x - pending_arc_center.
x );
2163 double sweep = end_angle - start_angle;
2167 if( pending_arc_dir ==
"CCW" )
2169 while( sweep <= 0.0 )
2170 sweep += 2.0 *
M_PI;
2174 while( sweep >= 0.0 )
2175 sweep -= 2.0 *
M_PI;
2179 pt.
arc.
cx = pending_arc_center.
x;
2180 pt.
arc.
cy = pending_arc_center.
y;
2181 pt.
arc.
radius = std::sqrt( dx0 * dx0 + dy0 * dy0 );
2191 int effective_layer = layer;
2192 bool is_pad_connection = ( layer == 65 );
2196 if( is_unrouted && in_track )
2197 effective_layer = current_track.
layer;
2202 if( !via_name.empty() && current_route )
2205 via.name = via_name;
2206 via.location = { pt.
x, pt.
y };
2207 current_route->
vias.push_back(
via );
2215 if( has_power && via_name.empty() && !is_unrouted && !is_pad_connection && current_route )
2219 if( !default_via_name.empty() )
2220 implicit_via.
name = default_via_name;
2225 current_route->
vias.push_back( implicit_via );
2229 if( has_teardrop && current_route )
2231 current_route->
teardrops.push_back( teardrop );
2235 if( has_jumper && current_route )
2237 current_route->
jumpers.push_back( jumper );
2243 if( is_plane_connection && prev_is_plane_connection )
2252 last_plane_connection_pt = pt;
2253 last_plane_connection_layer = effective_layer;
2254 last_plane_connection_width = width;
2255 last_plane_on_copper =
true;
2258 prev_is_plane_connection =
true;
2262 if( is_plane_connection && !prev_is_plane_connection )
2268 current_track.
points.push_back( pt );
2270 if( current_route && current_track.
points.size() > 1 )
2271 current_route->
tracks.push_back( current_track );
2273 current_track.
points.clear();
2280 last_plane_on_copper = !is_unrouted;
2282 if( last_plane_on_copper )
2284 last_plane_connection_pt = pt;
2285 last_plane_connection_layer = effective_layer;
2286 last_plane_connection_width = width;
2289 prev_is_plane_connection =
true;
2293 if( !is_plane_connection && prev_is_plane_connection )
2297 if( in_track && current_route && current_track.
points.size() > 1 )
2298 current_route->
tracks.push_back( current_track );
2300 prev_is_plane_connection =
false;
2302 if( is_pad_connection )
2308 current_track.
points.clear();
2310 if( last_plane_on_copper && last_plane_connection_layer == effective_layer )
2312 current_track.
layer = effective_layer;
2313 current_track.
width = std::max( width, last_plane_connection_width );
2314 current_track.
points.push_back( last_plane_connection_pt );
2315 current_track.
points.push_back( pt );
2321 if( !has_power && via_name.empty() && current_route && last_plane_on_copper &&
2322 std::abs( pt.
x - last_plane_connection_pt.
x ) < 0.001 &&
2323 std::abs( pt.
y - last_plane_connection_pt.
y ) < 0.001 )
2327 if( !default_via_name.empty() )
2328 implicit_via.
name = default_via_name;
2333 current_route->
vias.push_back( implicit_via );
2336 current_track.
layer = effective_layer;
2337 current_track.
width = width;
2338 current_track.
points.push_back( pt );
2341 last_plane_on_copper =
false;
2348 if( is_pad_connection )
2350 if( in_track && !current_track.
points.empty() )
2352 current_track.
points.push_back( pt );
2354 if( current_route && current_track.
points.size() > 1 )
2355 current_route->
tracks.push_back( current_track );
2357 current_track.
points.clear();
2365 prev_is_plane_connection =
false;
2369 current_track.
layer = effective_layer;
2370 current_track.
width = width;
2371 current_track.
points.clear();
2372 current_track.
points.push_back( pt );
2377 bool layer_changed = ( effective_layer != current_track.
layer );
2378 bool width_changed = (
std::abs( width - current_track.
width ) > 0.001 );
2380 if( layer_changed || width_changed )
2383 bool connect =
true;
2385 if( layer_changed && via_name.empty() )
2387 bool same_location =
2388 ( pt.
x == current_track.
points.back().x &&
2389 pt.
y == current_track.
points.back().y );
2395 if( !has_power && current_route )
2399 default_via_name.empty() ?
"STANDARDVIA" : default_via_name;
2401 current_route->
vias.push_back( implicit_via );
2404 else if( !has_power )
2414 current_track.
points.push_back( pt );
2418 current_route->
tracks.push_back( current_track );
2423 current_track.
layer = effective_layer;
2424 current_track.
width = width;
2425 current_track.
points.clear();
2426 current_track.
points.push_back( prev_pt );
2430 current_track.
points.push_back( pt );
2435 if( in_track && current_route )
2437 current_route->
tracks.push_back( current_track );
2447 if( line[0] ==
'*' )
2456 std::istringstream iss( line );
2465 std::string mirrored;
2467 text.mirrored = ( mirrored ==
"M" );
2477 if( token ==
".REUSE." )
2479 iss >>
text.reuse_instance;
2485 if( iss >> token && token ==
".REUSE." )
2487 iss >>
text.reuse_instance;
2498 std::istringstream fiss( line );
2499 std::string font_style_part;
2501 fiss >> font_style_part;
2503 size_t colon_pos = font_style_part.find(
':' );
2505 if( colon_pos != std::string::npos )
2507 text.font_style = font_style_part.substr( 0, colon_pos );
2508 std::string remaining = font_style_part.substr( colon_pos + 1 );
2510 size_t second_colon = remaining.find(
':' );
2512 if( second_colon != std::string::npos )
2515 remaining.substr( 0, second_colon ), 0.0,
"font height" );
2517 remaining.substr( second_colon + 1 ), 0.0,
"font descent" );
2527 text.font_style = font_style_part;
2530 size_t bracket_start = line.find(
'<' );
2531 size_t bracket_end = line.find(
'>' );
2533 if( bracket_start != std::string::npos && bracket_end != std::string::npos )
2536 line.substr( bracket_start + 1, bracket_end - bracket_start - 1 );
2541 std::getline( fiss, rest );
2543 if( !rest.empty() && rest[0] ==
' ' )
2544 rest = rest.substr( 1 );
2546 text.font_face = rest;
2557 while( ( pos = line.find(
"\\n", pos ) ) != std::string::npos )
2559 line.replace( pos, 2,
"\n" );
2565 std::replace( line.begin(), line.end(),
'_',
'\n' );
2567 text.content = line;
2581 if( line[0] ==
'*' )
2587 std::istringstream iss( line );
2588 std::string
name, type;
2589 double xloc = 0.0, yloc = 0.0;
2591 iss >>
name >> type >> xloc >> yloc >> pieces;
2594 for(
int i = 0; i < pieces; ++i )
2599 if( line[0] ==
'*' )
2605 std::istringstream piss( line );
2606 std::string shape_type;
2609 int linestyle = 0, level = 0;
2610 piss >> shape_type >> corners >> width >> linestyle >> level;
2613 if( shape_type ==
"CLOSED" || shape_type ==
"OPEN" || shape_type ==
"BRDCLS" )
2617 polyline.
width = width;
2618 polyline.
closed = ( shape_type ==
"CLOSED" || shape_type ==
"BRDCLS" );
2620 for(
int j = 0; j < corners; ++j )
2625 if( line[0] ==
'*' )
2631 std::istringstream ciss( line );
2632 double dx = 0.0, dy = 0.0;
2637 int startAngleTenths = 0, deltaAngleTenths = 0;
2638 double bboxMinX = 0.0, bboxMinY = 0.0, bboxMaxX = 0.0, bboxMaxY = 0.0;
2640 if( ciss >> startAngleTenths >> deltaAngleTenths
2641 >> bboxMinX >> bboxMinY >> bboxMaxX >> bboxMaxY )
2643 double cx = ( bboxMinX + bboxMaxX ) / 2.0;
2644 double cy = ( bboxMinY + bboxMaxY ) / 2.0;
2645 double radius = ( bboxMaxX - bboxMinX ) / 2.0;
2646 double startAngle = startAngleTenths / 10.0;
2647 double deltaAngle = deltaAngleTenths / 10.0;
2649 double startAngleRad = startAngle *
M_PI / 180.0;
2650 double startX = cx +
radius * std::cos( startAngleRad );
2651 double startY = cy +
radius * std::sin( startAngleRad );
2653 double endAngleRad = ( startAngle + deltaAngle ) *
M_PI / 180.0;
2654 double endX = cx +
radius * std::cos( endAngleRad );
2655 double endY = cy +
radius * std::sin( endAngleRad );
2657 polyline.
points.emplace_back( xloc + startX, yloc + startY );
2663 arc.start_angle = startAngle;
2664 arc.delta_angle = deltaAngle;
2666 polyline.
points.emplace_back( xloc + endX, yloc + endY, arc );
2670 polyline.
points.emplace_back( xloc + dx, yloc + dy );
2674 if( !polyline.
points.empty() )
2677 else if( shape_type ==
"CIRCLE" || shape_type ==
"BRDCIR" )
2682 polyline.
width = width;
2685 double x1 = 0.0, y1 = 0.0, x2 = 0.0, y2 = 0.0;
2689 std::istringstream c1( line );
2693 if( corners >= 2 &&
readLine( aStream, line ) )
2695 std::istringstream c2( line );
2700 double cx = xloc + ( x1 + x2 ) / 2.0;
2701 double cy = yloc + ( y1 + y2 ) / 2.0;
2702 double radius = std::sqrt( ( x2 - x1 ) * ( x2 - x1 ) + ( y2 - y1 ) * ( y2 - y1 ) ) / 2.0;
2709 arc.start_angle = 0.0;
2710 arc.delta_angle = 360.0;
2714 if( !polyline.
points.empty() )
2720 for(
int j = 0; j < corners; ++j )
2725 if( line[0] ==
'*' )
2742 if( line[0] ==
'*' )
2749 std::istringstream iss( line );
2750 std::string
name, type;
2751 double xloc = 0.0, yloc = 0.0;
2752 int pieces = 0, flags = 0, textCount = 0;
2753 std::string signame;
2755 iss >>
name >> type >> xloc >> yloc >> pieces >> flags;
2760 if( iss >> textCount )
2771 std::string reuse_instance, reuse_signal;
2775 if( line.find(
".REUSE." ) != std::string::npos )
2777 std::istringstream riss( line );
2778 std::string reuse_keyword;
2779 riss >> reuse_keyword >> reuse_instance >> reuse_signal;
2787 if( type ==
"BOARD" )
2789 for(
int i=0; i<pieces; ++i )
2791 if( !
readLine( aStream, line ) )
break;
2794 std::istringstream piss( line );
2795 std::string shape_type;
2798 int piece_flags = 0;
2800 piss >> shape_type >> corners >> width >> piece_flags >> level;
2802 if( shape_type ==
"CLOSED" || shape_type ==
"OPEN" || shape_type ==
"BRDCLS" )
2806 polyline.
width = width;
2807 polyline.
closed = ( shape_type ==
"CLOSED" || shape_type ==
"BRDCLS" );
2809 for(
int j = 0; j < corners; ++j )
2814 if( line[0] ==
'*' )
2820 std::istringstream ciss( line );
2821 double dx = 0.0, dy = 0.0;
2826 int startAngleTenths = 0, deltaAngleTenths = 0;
2827 double bboxMinX = 0.0, bboxMinY = 0.0, bboxMaxX = 0.0, bboxMaxY = 0.0;
2829 if( ciss >> startAngleTenths >> deltaAngleTenths
2830 >> bboxMinX >> bboxMinY >> bboxMaxX >> bboxMaxY )
2832 double cx = ( bboxMinX + bboxMaxX ) / 2.0;
2833 double cy = ( bboxMinY + bboxMaxY ) / 2.0;
2834 double radius = ( bboxMaxX - bboxMinX ) / 2.0;
2835 double startAngle = startAngleTenths / 10.0;
2836 double deltaAngle = deltaAngleTenths / 10.0;
2838 double startAngleRad = startAngle *
M_PI / 180.0;
2839 double startX = cx +
radius * std::cos( startAngleRad );
2840 double startY = cy +
radius * std::sin( startAngleRad );
2842 double endAngleRad = ( startAngle + deltaAngle ) *
M_PI / 180.0;
2843 double endX = cx +
radius * std::cos( endAngleRad );
2844 double endY = cy +
radius * std::sin( endAngleRad );
2846 polyline.
points.emplace_back( xloc + startX, yloc + startY );
2852 arc.start_angle = startAngle;
2853 arc.delta_angle = deltaAngle;
2855 polyline.
points.emplace_back( xloc + endX, yloc + endY, arc );
2859 polyline.
points.emplace_back( xloc + dx, yloc + dy );
2863 if( !polyline.
points.empty() )
2866 else if( shape_type ==
"CIRCLE" || shape_type ==
"BRDCIR" )
2869 double x1 = 0.0, y1 = 0.0, x2 = 0.0, y2 = 0.0;
2873 std::istringstream c1( line );
2877 if( corners >= 2 &&
readLine( aStream, line ) )
2879 std::istringstream c2( line );
2883 double cx = xloc + ( x1 + x2 ) / 2.0;
2884 double cy = yloc + ( y1 + y2 ) / 2.0;
2885 double radius = std::sqrt( ( x2 - x1 ) * ( x2 - x1 ) +
2886 ( y2 - y1 ) * ( y2 - y1 ) ) / 2.0;
2890 polyline.
width = width;
2897 arc.start_angle = 0.0;
2898 arc.delta_angle = 360.0;
2902 if( !polyline.
points.empty() )
2907 for(
int j=0; j<corners; ++j )
2909 if( !
readLine( aStream, line ) )
break;
2915 else if(
name.rfind(
"DIM", 0 ) == 0 && type ==
"LINES" )
2935 double baspnt1_x = 0, baspnt1_y = 0;
2936 double baspnt2_x = 0, baspnt2_y = 0;
2937 double arwln_x = 0, arwln_y = 0;
2938 int baspnt_count = 0;
2939 bool hasArwln =
false;
2941 for(
int i = 0; i < pieces; ++i )
2946 if( line[0] ==
'*' )
2952 std::istringstream piss( line );
2953 std::string shape_type;
2956 int piece_flags = 0;
2958 piss >> shape_type >> corners >> width >> piece_flags >> level;
2962 for(
int j = 0; j < corners; ++j )
2967 if( line[0] ==
'*' )
2973 std::istringstream ciss( line );
2974 double dx = 0.0, dy = 0.0;
2979 if( shape_type ==
"BASPNT" && j == 0 )
2981 if( baspnt_count == 0 )
2983 baspnt1_x = xloc + dx;
2984 baspnt1_y = yloc + dy;
2986 else if( baspnt_count == 1 )
2988 baspnt2_x = xloc + dx;
2989 baspnt2_y = yloc + dy;
2996 if( shape_type ==
"ARWLN1" && j == 0 )
2998 arwln_x = xloc + dx;
2999 arwln_y = yloc + dy;
3006 if( baspnt_count >= 2 )
3010 double dx =
std::abs( baspnt2_x - baspnt1_x );
3011 double dy =
std::abs( baspnt2_y - baspnt1_y );
3012 bool isHorizontal = dx > dy;
3031 dim.
points.push_back( pt1 );
3032 dim.
points.push_back( pt2 );
3037 for(
int t = 0; t < textCount; ++t )
3042 if( line[0] ==
'*' )
3048 std::istringstream tiss( line );
3049 double tx = 0.0, ty = 0.0;
3056 for(
int s = 0; s < skipLines; ++s )
3064 double theight = 0.0, twidth = 0.0;
3065 tiss >> trot >> tlayer >> theight >> twidth;
3088 if( !dim.
points.empty() )
3091 else if( type ==
"KEEPOUT" || type ==
"RESTRICTVIA" || type ==
"RESTRICTROUTE"
3092 || type ==
"RESTRICTAREA" || type ==
"PLACEMENT_KEEPOUT" )
3098 if( type ==
"KEEPOUT" || type ==
"RESTRICTAREA" )
3105 else if( type ==
"RESTRICTVIA" )
3112 else if( type ==
"RESTRICTROUTE" )
3119 else if( type ==
"PLACEMENT_KEEPOUT" )
3128 for(
int i = 0; i < pieces; ++i )
3133 if( line[0] ==
'*' )
3141 std::istringstream piss( line );
3142 std::string shape_type;
3145 int piece_flags = 0;
3147 std::string restrictions;
3148 piss >> shape_type >> corners >> width >> piece_flags >> level >> restrictions;
3151 keepout.
layers.push_back( level );
3157 if( !restrictions.empty() )
3160 bool has_restriction_codes =
false;
3162 for(
char c : restrictions )
3164 if( std::isalpha( c ) )
3166 has_restriction_codes =
true;
3171 if( has_restriction_codes )
3182 for(
char c : restrictions )
3223 if( shape_type ==
"KPTCIR" )
3226 double x1 = 0.0, y1 = 0.0, x2 = 0.0, y2 = 0.0;
3230 std::istringstream c1( line );
3234 if( corners >= 2 &&
readLine( aStream, line ) )
3236 std::istringstream c2( line );
3241 double cx = xloc + ( x1 + x2 ) / 2.0;
3242 double cy = yloc + ( y1 + y2 ) / 2.0;
3243 double radius = std::sqrt( ( x2 - x1 ) * ( x2 - x1 ) +
3244 ( y2 - y1 ) * ( y2 - y1 ) ) / 2.0;
3251 arc.start_angle = 0.0;
3252 arc.delta_angle = 360.0;
3259 for(
int j = 0; j < corners; ++j )
3264 if( line[0] ==
'*' )
3270 std::istringstream ciss( line );
3271 double dx = 0.0, dy = 0.0;
3276 int startAngleTenths = 0, deltaAngleTenths = 0;
3277 double bboxMinX = 0.0, bboxMinY = 0.0, bboxMaxX = 0.0, bboxMaxY = 0.0;
3279 if( ciss >> startAngleTenths >> deltaAngleTenths
3280 >> bboxMinX >> bboxMinY >> bboxMaxX >> bboxMaxY )
3282 double cx = ( bboxMinX + bboxMaxX ) / 2.0;
3283 double cy = ( bboxMinY + bboxMaxY ) / 2.0;
3284 double radius = ( bboxMaxX - bboxMinX ) / 2.0;
3285 double startAngle = startAngleTenths / 10.0;
3286 double deltaAngle = deltaAngleTenths / 10.0;
3288 double startAngleRad = startAngle *
M_PI / 180.0;
3289 double startX = cx +
radius * std::cos( startAngleRad );
3290 double startY = cy +
radius * std::sin( startAngleRad );
3292 double endAngleRad = ( startAngle + deltaAngle ) *
M_PI / 180.0;
3293 double endX = cx +
radius * std::cos( endAngleRad );
3294 double endY = cy +
radius * std::sin( endAngleRad );
3296 keepout.
outline.emplace_back( xloc + startX, yloc + startY );
3302 arc.start_angle = startAngle;
3303 arc.delta_angle = deltaAngle;
3305 keepout.
outline.emplace_back( xloc + endX, yloc + endY, arc );
3309 keepout.
outline.emplace_back( xloc + dx, yloc + dy );
3315 if( !keepout.
outline.empty() )
3318 else if( type ==
"COPPER" || type ==
"COPCUT" )
3324 for(
int i = 0; i < pieces; ++i )
3329 if( line[0] ==
'*' )
3338 std::istringstream piss( line );
3339 std::string shape_type;
3342 int piece_flags = 0;
3344 piss >> shape_type >> corners >> width >> piece_flags >> level;
3348 copper.
layer = level;
3349 copper.
width = width;
3352 copper.
filled = ( shape_type ==
"COPCLS" || shape_type ==
"COPCIR" );
3353 copper.
is_cutout = ( shape_type ==
"COPCUT" || shape_type ==
"COPCCO" ||
3354 shape_type ==
"CIRCUR" || type ==
"COPCUT" );
3357 if( shape_type ==
"COPCIR" || shape_type ==
"COPCCO" || shape_type ==
"CIRCUR" )
3360 double x1 = 0.0, y1 = 0.0, x2 = 0.0, y2 = 0.0;
3364 std::istringstream c1( line );
3368 if( corners >= 2 &&
readLine( aStream, line ) )
3370 std::istringstream c2( line );
3374 double cx = xloc + ( x1 + x2 ) / 2.0;
3375 double cy = yloc + ( y1 + y2 ) / 2.0;
3376 double radius = std::sqrt( ( x2 - x1 ) * ( x2 - x1 ) +
3377 ( y2 - y1 ) * ( y2 - y1 ) ) / 2.0;
3383 arc.start_angle = 0.0;
3384 arc.delta_angle = 360.0;
3391 for(
int j = 0; j < corners; ++j )
3396 if( line[0] ==
'*' )
3402 std::istringstream ciss( line );
3403 double dx = 0.0, dy = 0.0;
3408 int startAngleTenths = 0, deltaAngleTenths = 0;
3409 double bboxMinX = 0.0, bboxMinY = 0.0, bboxMaxX = 0.0, bboxMaxY = 0.0;
3411 if( ciss >> startAngleTenths >> deltaAngleTenths
3412 >> bboxMinX >> bboxMinY >> bboxMaxX >> bboxMaxY )
3414 double cx = ( bboxMinX + bboxMaxX ) / 2.0;
3415 double cy = ( bboxMinY + bboxMaxY ) / 2.0;
3416 double radius = ( bboxMaxX - bboxMinX ) / 2.0;
3417 double startAngle = startAngleTenths / 10.0;
3418 double deltaAngle = deltaAngleTenths / 10.0;
3420 double startAngleRad = startAngle *
M_PI / 180.0;
3421 double startX = cx +
radius * std::cos( startAngleRad );
3422 double startY = cy +
radius * std::sin( startAngleRad );
3424 double endAngleRad = ( startAngle + deltaAngle ) *
M_PI / 180.0;
3425 double endX = cx +
radius * std::cos( endAngleRad );
3426 double endY = cy +
radius * std::sin( endAngleRad );
3428 copper.
outline.emplace_back( xloc + startX, yloc + startY );
3434 arc.start_angle = startAngle;
3435 arc.delta_angle = deltaAngle;
3437 copper.
outline.emplace_back( xloc + endX, yloc + endY, arc );
3441 copper.
outline.emplace_back( xloc + dx, yloc + dy );
3450 else if( type ==
"LINES" )
3453 for(
int i = 0; i < pieces; ++i )
3458 if( line[0] ==
'*' )
3465 std::istringstream piss( line );
3466 std::string shape_type;
3469 int piece_flags = 0;
3471 piss >> shape_type >> corners >> width >> piece_flags >> level;
3475 graphic.
layer = level;
3476 graphic.
width = width;
3480 graphic.
closed = ( shape_type ==
"CLOSED" || shape_type ==
"CIRCLE" );
3482 if( shape_type ==
"CIRCLE" )
3485 double x1 = 0.0, y1 = 0.0, x2 = 0.0, y2 = 0.0;
3489 std::istringstream c1( line );
3493 if( corners >= 2 &&
readLine( aStream, line ) )
3495 std::istringstream c2( line );
3499 double cx = xloc + ( x1 + x2 ) / 2.0;
3500 double cy = yloc + ( y1 + y2 ) / 2.0;
3501 double radius = std::sqrt( ( x2 - x1 ) * ( x2 - x1 ) +
3502 ( y2 - y1 ) * ( y2 - y1 ) ) / 2.0;
3508 arc.start_angle = 0.0;
3509 arc.delta_angle = 360.0;
3516 for(
int j = 0; j < corners; ++j )
3521 if( line[0] ==
'*' )
3527 std::istringstream ciss( line );
3528 double dx = 0.0, dy = 0.0;
3532 int startAngleTenths = 0, deltaAngleTenths = 0;
3533 double bboxMinX = 0.0, bboxMinY = 0.0, bboxMaxX = 0.0, bboxMaxY = 0.0;
3535 if( ciss >> startAngleTenths >> deltaAngleTenths
3536 >> bboxMinX >> bboxMinY >> bboxMaxX >> bboxMaxY )
3538 double cx = ( bboxMinX + bboxMaxX ) / 2.0;
3539 double cy = ( bboxMinY + bboxMaxY ) / 2.0;
3540 double radius = ( bboxMaxX - bboxMinX ) / 2.0;
3541 double startAngle = startAngleTenths / 10.0;
3542 double deltaAngle = deltaAngleTenths / 10.0;
3544 double startAngleRad = startAngle *
M_PI / 180.0;
3545 double startX = cx +
radius * std::cos( startAngleRad );
3546 double startY = cy +
radius * std::sin( startAngleRad );
3548 double endAngleRad = ( startAngle + deltaAngle ) *
M_PI / 180.0;
3549 double endX = cx +
radius * std::cos( endAngleRad );
3550 double endY = cy +
radius * std::sin( endAngleRad );
3552 graphic.
points.emplace_back( xloc + startX, yloc + startY );
3558 arc.start_angle = startAngle;
3559 arc.delta_angle = deltaAngle;
3561 graphic.
points.emplace_back( xloc + endX, yloc + endY, arc );
3565 graphic.
points.emplace_back( xloc + dx, yloc + dy );
3570 if( !graphic.
points.empty() )
3577 for(
int i = 0; i < pieces; ++i )
3582 if( line[0] ==
'*' )
3588 std::istringstream piss( line );
3589 std::string shape_type;
3591 piss >> shape_type >> corners;
3593 for(
int j = 0; j < corners; ++j )
3598 if( line[0] ==
'*' )
3610 for(
int t = 0; t < textCount; ++t )
3615 if( line[0] ==
'*' )
3621 std::istringstream tiss( line );
3631 for(
int s = 0; s < skipLines; ++s )
3637 text.location.x += xloc;
3638 text.location.y += yloc;
3640 std::string mirrored;
3642 text.mirrored = ( mirrored ==
"M" );
3650 if( line[0] ==
'*' )
3656 size_t bracket_start = line.find(
'<' );
3657 size_t bracket_end = line.find(
'>' );
3659 if( bracket_start != std::string::npos && bracket_end != std::string::npos )
3662 line.substr( bracket_start + 1, bracket_end - bracket_start - 1 );
3665 std::istringstream fiss( line );
3666 std::string font_style_part;
3667 fiss >> font_style_part;
3669 size_t colon_pos = font_style_part.find(
':' );
3671 if( colon_pos != std::string::npos )
3672 text.font_style = font_style_part.substr( 0, colon_pos );
3674 text.font_style = font_style_part;
3681 if( line[0] ==
'*' )
3687 text.content = line;
3717 if( line[0] ==
'*' )
3727 if( line.rfind(
"G ", 0 ) == 0 && currentPartType )
3729 std::istringstream gss( line );
3730 std::string g_keyword;
3731 int gateSwap = 0, pinCount = 0;
3732 gss >> g_keyword >> gateSwap >> pinCount;
3736 currentPartType->
gates.push_back( gate );
3737 currentGate = ¤tPartType->
gates.back();
3742 if( line.rfind(
"SIGPIN", 0 ) == 0 && currentPartType )
3744 std::istringstream sss( line );
3745 std::string keyword;
3760 if( line.find(
'.' ) != std::string::npos && currentPartType )
3765 std::stringstream check_ss( line );
3766 std::string first_token;
3767 check_ss >> first_token;
3771 for(
char c : first_token )
3784 std::stringstream ss( line );
3787 while( ss >> token )
3790 std::vector<std::string> parts;
3794 while( ( pos = token.find(
'.', start ) ) != std::string::npos )
3796 parts.push_back( token.substr( start, pos - start ) );
3800 parts.push_back( token.substr( start ) );
3802 if( parts.size() >= 3 )
3808 bool isNumericSecond = !parts[1].empty() &&
3809 std::all_of( parts[1].begin(), parts[1].
end(), ::isdigit );
3811 if( currentGate && parts[2].size() == 1 && !isNumericSecond )
3818 if( !parts[2].
empty() )
3819 gpin.
elec_type = parsePinElecType( parts[2][0] );
3821 if( parts.size() >= 4 )
3824 currentGate->
pins.push_back( gpin );
3826 else if( isNumericSecond )
3841 if( line[0] ==
'{' && currentPartType )
3845 if( line.empty() || line[0] ==
'}' )
3848 if( line[0] ==
'*' )
3854 std::string attrName, attrValue;
3856 if( line[0] ==
'"' )
3858 size_t endQuote = line.find(
'"', 1 );
3860 if( endQuote != std::string::npos )
3862 attrName = line.substr( 1, endQuote - 1 );
3863 attrValue = line.substr( endQuote + 1 );
3868 std::istringstream attrSS( line );
3870 std::getline( attrSS >> std::ws, attrValue );
3873 if( !attrValue.empty() && attrValue[0] ==
' ' )
3874 attrValue = attrValue.substr( 1 );
3876 if( !attrName.empty() && !attrValue.empty() )
3877 currentPartType->
attributes[attrName] = attrValue;
3883 if( line[0] ==
'{' || line[0] ==
'}' )
3887 std::stringstream ss( line );
3888 std::string
name, decal;
3889 ss >>
name >> decal;
3891 if( !
name.empty() &&
name[0] !=
'G' )
3898 currentGate =
nullptr;
3911 if( line[0] ==
'*' )
3917 std::stringstream ss( line );
3918 std::string keyword;
3921 if( keyword ==
"TYPE" )
3923 std::string typename_val;
3924 std::getline( ss, typename_val );
3926 if( !typename_val.empty() && typename_val[0] ==
' ' )
3927 typename_val = typename_val.substr( 1 );
3930 block.
name = typename_val;
3934 else if( keyword ==
"TIMESTAMP" && currentBlock )
3940 else if( keyword ==
"PART_NAMING" && currentBlock )
3943 std::getline( ss, naming );
3945 if( !naming.empty() && naming[0] ==
' ' )
3946 naming = naming.substr( 1 );
3950 else if( keyword ==
"PART" && currentBlock )
3952 std::string partname;
3953 std::getline( ss, partname );
3955 if( !partname.empty() && partname[0] ==
' ' )
3956 partname = partname.substr( 1 );
3958 currentBlock->
part_names.push_back( partname );
3960 else if( keyword ==
"NET_NAMING" && currentBlock )
3963 std::getline( ss, naming );
3965 if( !naming.empty() && naming[0] ==
' ' )
3966 naming = naming.substr( 1 );
3970 else if( keyword ==
"NET" && currentBlock )
3973 std::string netname;
3976 std::getline( ss, netname );
3978 if( !netname.empty() && netname[0] ==
' ' )
3979 netname = netname.substr( 1 );
3982 net.
merge = ( merge_flag == 1 );
3984 currentBlock->
nets.push_back( net );
3986 else if( keyword ==
"REUSE" && currentBlock )
3991 std::string next_token;
3994 if( next_token ==
"PREFIX" || next_token ==
"SUFFIX" )
4001 else if( next_token ==
"START" || next_token ==
"INCREMENT" )
4008 else if( next_token ==
"NEXT" )
4014 if( next_token ==
"PREFIX" || next_token ==
"SUFFIX" )
4018 instance.
net_naming = next_token +
" " + param;
4020 else if( next_token ==
"START" || next_token ==
"INCREMENT" )
4024 instance.
net_naming = next_token +
" " + num;
4026 else if( next_token ==
"NEXT" )
4031 std::string glued_str;
4034 instance.
glued = ( glued_str ==
"Y" || glued_str ==
"YES" || glued_str ==
"1" );
4035 currentBlock->
instances.push_back( instance );
4044 CLUSTER* currentCluster =
nullptr;
4048 if( line[0] ==
'*' )
4054 std::stringstream ss( line );
4055 std::string firstToken;
4060 if( firstToken.empty() )
4064 bool isNumeric = !firstToken.empty() &&
4065 std::all_of( firstToken.begin(), firstToken.end(), ::isdigit );
4079 cluster.
name =
"Cluster_" + firstToken;
4084 else if( currentCluster )
4088 if( firstToken.find(
'.' ) != std::string::npos )
4096 currentCluster->
net_names.push_back( firstToken );
4104 if( item.find(
'.' ) != std::string::npos )
4107 currentCluster->
net_names.push_back( item );
4120 if( line[0] ==
'*' )
4128 std::stringstream ss( line );
4129 std::string
name, flags;
4130 double minlen = 0.0, maxlen = 0.0, lenincr = 0.0;
4132 std::string padstack, end_padstack;
4134 if( !( ss >>
name >> flags >> minlen >> maxlen >> lenincr >> lcount >> padstack ) )
4148 for(
char c : flags )
4154 case 'W': jumper.
wirebond =
true;
break;
4156 case 'G': jumper.
glued =
true;
break;
4162 for(
int i = 0; i < lcount; ++i )
4170 std::stringstream ss_attr( line );
4171 std::string visible_str, mirrored_str, right_reading_str;
4176 attr.
visible = ( visible_str ==
"VALUE" || visible_str ==
"FULL_NAME" ||
4177 visible_str ==
"NAME" || visible_str ==
"FULL_BOTH" ||
4178 visible_str ==
"BOTH" );
4179 attr.
mirrored = ( mirrored_str ==
"M" || mirrored_str ==
"1" );
4180 ss_attr >> right_reading_str;
4181 attr.
right_reading = ( right_reading_str ==
"Y" || right_reading_str ==
"ORTHO" );
4192 jumper.
labels.push_back( attr );
4206 if( line[0] ==
'*' )
4212 std::stringstream ss( line );
4224 ss >>
tp.x >>
tp.y >>
tp.side >>
tp.net_name >>
tp.symbol_name;
4226 if( !
tp.net_name.empty() )
4238 bool inClass =
false;
4242 if( line[0] ==
'*' )
4245 if( inClass && !currentClass.
name.empty() )
4252 std::stringstream ss( line );
4260 if( token ==
"CLASS" || token ==
"NETCLASS" )
4263 if( inClass && !currentClass.
name.empty() )
4268 ss >> currentClass.
name;
4271 else if( token ==
"CLEARANCE" && inClass )
4275 else if( token ==
"TRACKWIDTH" && inClass )
4279 else if( token ==
"VIASIZE" && inClass )
4283 else if( token ==
"VIADRILL" && inClass )
4287 else if( token ==
"DIFFPAIRGAP" && inClass )
4291 else if( token ==
"DIFFPAIRWIDTH" && inClass )
4295 else if( token ==
"NET" && inClass )
4298 std::string netName;
4301 if( !netName.empty() )
4302 currentClass.
net_names.push_back( netName );
4304 else if( !token.empty() && token[0] !=
'#' )
4307 if( !inClass || ( inClass && currentClass.
name.empty() ) )
4310 if( inClass && !currentClass.
name.empty() )
4314 currentClass.
name = token;
4321 if( inClass && !currentClass.
name.empty() )
4332 if( line[0] ==
'*' )
4338 std::stringstream ss( line );
4354 if( token ==
"DIFFPAIR" || token ==
"PAIR" )
4360 std::string posNet, negNet;
4361 ss >> posNet >> negNet;
4363 if( !posNet.empty() )
4366 if( !negNet.empty() )
4370 double gap = 0.0, width = 0.0;
4378 if( !dp.
name.empty() )
4393 else if( ( token ==
"WIDTH" || token ==
"TRACKWIDTH" ) && !
m_diff_pairs.empty() )
4405 int currentLayerNum = -1;
4407 bool inLayerBlock =
false;
4411 if( typeStr ==
"ROUTING" )
4413 else if( typeStr ==
"PLANE" )
4415 else if( typeStr ==
"MIXED" )
4417 else if( typeStr ==
"UNASSIGNED" )
4419 else if( typeStr ==
"SOLDER_MASK" )
4421 else if( typeStr ==
"PASTE_MASK" )
4423 else if( typeStr ==
"SILK_SCREEN" )
4425 else if( typeStr ==
"ASSEMBLY" )
4427 else if( typeStr ==
"DOCUMENTATION" )
4429 else if( typeStr ==
"DRILL" )
4440 if( line[0] ==
'*' )
4446 std::istringstream iss( line );
4461 if( inLayerBlock && braceDepth == 1 )
4463 if( currentLayerNum >= 0 )
4465 currentLayer.
number = currentLayerNum;
4475 inLayerBlock =
false;
4476 currentLayerNum = -1;
4480 if( braceDepth <= 0 )
4486 if( token ==
"LAYER" )
4491 if( !iss.fail() && layerNum >= 0 )
4494 currentLayerNum = layerNum;
4496 currentLayer.
number = layerNum;
4498 inLayerBlock =
true;
4501 else if( token ==
"LAYER_NAME" && inLayerBlock )
4505 std::getline( iss >> std::ws,
name );
4508 else if( token ==
"LAYER_TYPE" && inLayerBlock )
4510 std::string typeStr;
4512 currentLayer.
layer_type = parseLayerType( typeStr );
4514 else if( token ==
"LAYER_THICKNESS" && inLayerBlock )
4518 else if( token ==
"COPPER_THICKNESS" && inLayerBlock )
4522 else if( token ==
"DIELECTRIC" && inLayerBlock )
4544 bool inDifPair =
false;
4545 bool inNetClassData =
false;
4546 bool inNetClass =
false;
4547 bool inRuleSet =
false;
4548 bool inRuleSetFor =
false;
4549 bool inClearanceRule =
false;
4550 int netClassDataDepth = -1;
4551 int netClassDepth = -1;
4552 int ruleSetDepth = -1;
4553 int clearanceRuleDepth = -1;
4554 bool foundDefaultRules =
false;
4555 bool isDefaultRuleSet =
false;
4556 std::string ruleSetNetClass;
4566 if( line[0] ==
'*' && braceDepth == 0 )
4573 for(
char c : line )
4581 if( braceDepth == 0 && inDifPair )
4584 if( !currentDiffPair.
name.empty() )
4591 if( inNetClass && braceDepth <= netClassDepth )
4593 if( !currentNetClass.
name.empty() )
4600 if( inNetClassData && braceDepth <= netClassDataDepth )
4602 inNetClassData =
false;
4605 if( inClearanceRule && braceDepth < clearanceRuleDepth )
4607 inClearanceRule =
false;
4609 if( isDefaultRuleSet )
4612 == std::numeric_limits<double>::max() )
4621 == std::numeric_limits<double>::max() )
4627 foundDefaultRules =
true;
4631 if( inRuleSetFor && braceDepth < ruleSetDepth + 1 )
4632 inRuleSetFor =
false;
4634 if( inRuleSet && braceDepth < ruleSetDepth )
4637 isDefaultRuleSet =
false;
4638 ruleSetNetClass.clear();
4643 std::istringstream iss( line );
4649 if( token ==
"LAYER" )
4651 std::string secondToken;
4654 if( secondToken ==
"DATA" )
4661 if( token ==
"NET_CLASS" )
4663 std::string secondToken;
4666 if( secondToken ==
"DATA" )
4668 inNetClassData =
true;
4669 netClassDataDepth = braceDepth;
4671 else if( inNetClassData && !secondToken.empty() )
4673 if( inNetClass && !currentNetClass.
name.empty() )
4677 currentNetClass.
name = secondToken;
4679 netClassDepth = braceDepth;
4681 else if( inRuleSetFor && !secondToken.empty() )
4683 ruleSetNetClass = secondToken;
4686 else if( inNetClass && token ==
"NET" )
4688 std::string netName;
4691 if( !netName.empty() )
4692 currentNetClass.
net_names.push_back( netName );
4694 else if( token ==
"RULE_SET" )
4696 std::string ruleNum;
4700 ruleSetDepth = braceDepth;
4701 ruleSetNetClass.clear();
4702 isDefaultRuleSet = ( ruleNum ==
"(1)" && !foundDefaultRules );
4704 else if( inRuleSet && !inClearanceRule && token ==
"FOR" )
4706 inRuleSetFor =
true;
4708 else if( inRuleSet && token ==
"CLEARANCE_RULE" )
4710 inClearanceRule =
true;
4711 clearanceRuleDepth = braceDepth;
4713 if( isDefaultRuleSet )
4715 m_design_rules.default_clearance = std::numeric_limits<double>::max();
4716 m_design_rules.copper_edge_clearance = std::numeric_limits<double>::max();
4719 else if( inClearanceRule )
4724 if( !iss.fail() && val > 0.0 )
4726 if( isDefaultRuleSet )
4728 if( token ==
"MIN_TRACK_WIDTH" )
4732 else if( token ==
"REC_TRACK_WIDTH" )
4736 else if( token ==
"DRILL_TO_DRILL" )
4740 else if( token ==
"OUTLINE_TO_TRACK" || token ==
"OUTLINE_TO_VIA"
4741 || token ==
"OUTLINE_TO_PAD" || token ==
"OUTLINE_TO_COPPER"
4742 || token ==
"OUTLINE_TO_SMD" )
4747 else if( token.rfind(
"SAME_NET_", 0 ) == 0 || token ==
"BODY_TO_BODY"
4748 || token ==
"MAX_TRACK_WIDTH"
4749 || token.rfind(
"TEXT_TO_", 0 ) == 0
4750 || token.rfind(
"COPPER_TO_", 0 ) == 0 )
4756 else if( token ==
"TRACK_TO_TRACK" || token.rfind(
"VIA_TO_", 0 ) == 0
4757 || token.rfind(
"PAD_TO_", 0 ) == 0
4758 || token.rfind(
"SMD_TO_", 0 ) == 0
4759 || token.rfind(
"DRILL_TO_", 0 ) == 0 )
4765 else if( !ruleSetNetClass.empty() )
4769 if( nc.name == ruleSetNetClass )
4771 if( token ==
"REC_TRACK_WIDTH" )
4772 nc.track_width = val;
4773 else if( token ==
"TRACK_TO_TRACK" )
4782 else if( token ==
"DIF_PAIR" )
4785 if( inDifPair && !currentDiffPair.
name.empty() )
4789 iss >> currentDiffPair.
name;
4792 else if( inDifPair )
4794 if( token ==
"NET" )
4796 std::string netName;
4805 else if( token ==
"GAP" )
4807 iss >> currentDiffPair.
gap;
4809 else if( token ==
"WIDTH" )
4811 iss >> currentDiffPair.
width;
4813 else if( token ==
"CONNECTION" )
4819 else if( token ==
"ASSOCIATED" )
4822 std::string keyword, netName;
4823 iss >> keyword >> netName;
4825 if( keyword ==
"NET" )
4837 if( token ==
"PART" && !inDifPair && !inNetClass )
4839 std::string partName;
4842 if( !partName.empty() )
4845 int savedDepth = braceDepth;
4853 if( line[0] ==
'}' )
4856 if( line[0] ==
'{' )
4859 if( line[0] ==
'*' )
4866 std::string attrName, attrValue;
4868 if( line[0] ==
'"' )
4870 size_t endQuote = line.find(
'"', 1 );
4872 if( endQuote != std::string::npos )
4874 attrName = line.substr( 1, endQuote - 1 );
4875 attrValue = line.substr( endQuote + 1 );
4880 std::istringstream attrSS( line );
4882 std::getline( attrSS >> std::ws, attrValue );
4885 if( !attrValue.empty() && attrValue[0] ==
' ' )
4886 attrValue = attrValue.substr( 1 );
4888 if( !attrName.empty() && !attrValue.empty() )
4889 attrs[attrName] = attrValue;
4893 braceDepth = savedDepth;
4910 if(
m_design_rules.default_clearance == std::numeric_limits<double>::max() )
4913 if(
m_design_rules.copper_edge_clearance == std::numeric_limits<double>::max() )
4920 std::vector<LAYER_INFO> layers;
4924 if( layerCount < 1 )
4928 auto isCopperLayer = [&](
int num ) {
4929 return num >= 1 && num <= layerCount;
4933 auto getLayerDef = [&](
int num ) ->
const LAYER_INFO* {
4935 return it !=
m_layer_defs.end() ? &it->second :
nullptr;
4939 for(
int i = 1; i <= layerCount; ++i )
4945 layers.push_back( *parsed );
4953 info.is_copper =
true;
4954 info.required =
true;
4958 else if( i == layerCount )
4959 info.name =
"Bottom";
4961 info.name =
"Inner " + std::to_string( i - 1 );
4963 layers.push_back(
info );
4970 if( !isCopperLayer( num ) )
4972 layers.push_back( layerDef );
bool readLine(std::ifstream &aStream, std::string &aLine)
std::map< std::string, PART_DECAL > m_decals
std::vector< CLUSTER > m_clusters
std::map< std::string, REUSE_BLOCK > m_reuse_blocks
bool m_has_font_lines
True if text/label entries include a font line.
std::vector< KEEPOUT > m_keepouts
std::vector< POUR > m_pours
std::vector< JUMPER_DEF > m_jumper_defs
Jumper definitions from JUMPER section.
std::vector< TEXT > m_texts
void parseSectionPARTTYPE(std::ifstream &aStream)
void parseSectionJUMPER(std::ifstream &aStream)
void parseSectionTESTPOINT(std::ifstream &aStream)
void parseSectionLINES(std::ifstream &aStream)
std::map< std::string, VIA_DEF > m_via_defs
void parseSectionBOARD(std::ifstream &aStream)
void parseSectionVIA(std::ifstream &aStream)
std::vector< COPPER_SHAPE > m_copper_shapes
Copper shapes from LINES section.
std::map< std::string, PART_TYPE > m_part_types
Per-instance attribute overrides from PART <name> {...} blocks in PARTTYPE section.
std::vector< NET > m_nets
void parseSectionPARTS(std::ifstream &aStream)
std::vector< ROUTE > m_routes
std::map< std::string, std::map< std::string, std::string > > m_part_instance_attrs
std::vector< NET_CLASS_DEF > m_net_classes
void parseSectionNETCLASS(std::ifstream &aStream)
void parseSectionMISC(std::ifstream &aStream)
void parseSectionREUSE(std::ifstream &aStream)
void parseSectionCLUSTER(std::ifstream &aStream)
void parseSectionLAYERDEFS(std::ifstream &aStream)
std::vector< LAYER_INFO > GetLayerInfos() const
Get layer information for layer mapping dialog.
DESIGN_RULES m_design_rules
void parseSectionNETS(std::ifstream &aStream)
void Parse(const wxString &aFileName)
FILE_HEADER m_file_header
Parsed file header info.
std::vector< GRAPHIC_LINE > m_graphic_lines
2D graphic lines from LINES section
std::vector< DIMENSION > m_dimensions
std::vector< DIFF_PAIR_DEF > m_diff_pairs
void parseSectionPCB(std::ifstream &aStream)
void clampDesignRuleSentinels()
void parseSectionTEXT(std::ifstream &aStream)
std::vector< POLYLINE > m_board_outlines
std::vector< PART > m_parts
int parseMajorVersion() const
Parse the major version number from the file header version string.
std::map< int, LAYER_INFO > m_layer_defs
Parsed layer definitions by layer number.
void parseSectionROUTES(std::ifstream &aStream)
std::vector< TEST_POINT > m_test_points
std::optional< std::string > m_pushed_line
void pushBackLine(const std::string &aLine)
void parseSectionDIFFPAIR(std::ifstream &aStream)
void parseSectionPOUR(std::ifstream &aStream)
void parseSectionPARTDECAL(std::ifstream &aStream)
static bool empty(const wxTextEntryBase *aCtrl)
const wxChar *const tracePadsIo
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.
@ VIA
Via thermal relief (VIATHERM)
@ PAD
Pad thermal relief (PADTHERM)
static std::vector< std::string > expandShortcutPattern(const std::string &aPattern)
Expand a shortcut format string like "PRE{n1-n2}" into individual names.
@ BURIED
Via spans only inner layers.
@ THROUGH
Via spans all copper layers.
@ BLIND
Via starts at top or bottom and ends at inner layer.
@ MICROVIA
Single-layer blind via (typically HDI)
PIN_ELEC_TYPE
Pin type classification for gate definitions.
@ BIDIRECTIONAL
B - Bidirectional pin.
@ UNDEFINED
U - Undefined.
@ OPEN_COLLECTOR
C - Open collector or or-tieable source.
@ TERMINATOR
Z - Terminator pin.
@ TRISTATE
T - Tri-state pin.
@ LIB_PCB_DECAL
Library PCB decals (footprints)
@ LIB_PART_TYPE
Library part types.
@ LIB_SCH_DECAL
Library schematic decals.
@ LIB_LINE
Library line items (drafting)
@ PCB
PCB design file (POWERPCB, PADS-LAYOUT, etc.)
@ ROUTE
Routing keepout (traces)
@ PLACEMENT
Component placement keepout.
@ VOIDOUT
Void/empty region (VOIDOUT)
@ HATCHED
Hatched pour (HATOUT)
PADS_LAYER_FUNCTION
Layer types from PADS LAYER_TYPE field.
@ ASSEMBLY
Assembly drawing.
@ ROUTING
Copper routing layer.
@ PASTE_MASK
Solder paste mask.
@ MIXED
Mixed signal/plane.
@ UNASSIGNED
Unassigned layer.
@ DOCUMENTATION
Documentation layer.
@ SILK_SCREEN
Silkscreen/legend.
@ PLANE
Power/ground plane.
@ SOLDER_MASK
Solder mask.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Common utilities and types for parsing PADS file formats.
A point that may be either a line endpoint or an arc segment.
ARC arc
Arc parameters (only valid when is_arc is true)
bool is_arc
True if this segment is an arc, false for line.
double y
Endpoint Y coordinate.
double x
Endpoint X coordinate.
Arc definition using center point, radius, and angles.
double cx
Center X coordinate.
double delta_angle
Arc sweep angle in degrees (positive = CCW)
double start_angle
Start angle in degrees (0 = +X, CCW positive)
double cy
Center Y coordinate.
A cluster of related route segments that should be grouped together.
std::vector< std::string > segment_refs
References to route segments in cluster.
std::string name
Cluster name/identifier.
std::vector< std::string > net_names
Nets belonging to this cluster.
A copper shape from the LINES section (type=COPPER).
std::vector< ARC_POINT > outline
Shape outline vertices.
bool is_cutout
True for cutouts (COPCUT, COPCCO)
std::string net_name
Associated net (empty if unconnected)
bool filled
True for filled shapes (COPCLS, COPCIR)
double width
Line width (for open polylines)
std::string name
Shape name.
std::string restrictions
Keepout restrictions (R,C,V,T,A) for KPTCLS/KPTCIR.
bool is_tag_close
True if this is a closing TAG (level=0)
std::vector< ARC_POINT > points
Shape points, may include arc segments.
int pinnum
Pin association for copper pieces (-1 = none, 0+ = pin index)
std::string type
CLOSED, OPEN, CIRCLE, COPCLS, TAG, etc.
bool is_tag_open
True if this is an opening TAG (level=1)
Design rule definitions from PCB section.
double copper_edge_clearance
Board outline clearance (OUTLINE_TO_*)
double default_clearance
Default copper clearance (DEFAULTCLEAR)
Differential pair definition.
std::string positive_net
Positive net name.
std::string negative_net
Negative net name.
double gap
Spacing between traces.
std::string name
Pair name.
A dimension annotation for measurement display.
std::string name
Dimension identifier.
double text_width
Text width.
double y
Origin Y coordinate.
double rotation
Text rotation angle.
bool is_horizontal
True for horizontal dimension.
double x
Origin X coordinate.
std::string text
Dimension text/value.
int layer
Layer for dimension graphics.
double crossbar_pos
Crossbar position (Y for horizontal, X for vertical)
double text_height
Text height.
std::vector< POINT > points
Dimension geometry points (measurement endpoints)
Gate definition for gate-swappable parts.
int gate_swap_type
Gate swap type (0 = not swappable)
std::vector< GATE_PIN > pins
Pins in this gate.
Pin definition within a gate.
std::string func_name
Optional functional name.
int swap_type
Swap type (0 = not swappable)
std::string pin_number
Electrical pin number.
A 2D graphic line/shape from the LINES section (type=LINES).
std::vector< ARC_POINT > points
Shape vertices, may include arcs.
bool closed
True if shape is closed (polygon/circle)
std::string name
Item name.
std::string reuse_instance
Reuse block instance name (if member of reuse)
Jumper definition from JUMPER section.
std::string padstack
Pad stack for start pin (or both if end_padstack empty)
bool wirebond
W flag: wirebond jumper.
double min_length
Minimum possible length.
std::string end_padstack
Pad stack for end pin (optional)
std::string name
Jumper name/reference designator.
bool display_silk
D flag: display special silk.
std::vector< ATTRIBUTE > labels
Reference designator labels.
double length_increment
Length increment.
double max_length
Maximum possible length.
bool via_enabled
V flag: via enabled.
Jumper endpoint marker in a route.
bool is_start
True if start (S), false if end (E)
std::string name
Jumper part name.
A keepout area definition.
std::vector< ARC_POINT > outline
Keepout boundary.
bool no_vias
Prohibit vias (V restriction)
bool no_components
Prohibit component placement (P restriction)
double max_height
Maximum component height when height_restriction is true.
bool no_copper
Prohibit copper pours (C restriction)
bool no_accordion
Prohibit accordion flex (A restriction for accordion, not all)
bool height_restriction
Component height restriction (H restriction)
KEEPOUT_TYPE type
Type of keepout.
bool no_traces
Prohibit traces (R restriction)
std::vector< int > layers
Affected layers (empty = all)
bool no_test_points
Prohibit test points (T restriction)
PADS_LAYER_FUNCTION layer_type
Parsed layer type from file.
bool required
True if layer must be mapped.
bool is_copper
True if copper layer.
int number
PADS layer number.
double layer_thickness
Dielectric thickness (BASIC units)
std::string name
Layer name.
double dielectric_constant
Relative permittivity (Er)
double copper_thickness
Copper foil thickness (BASIC units)
Net class definition with routing constraints.
double via_drill
Via drill diameter (VIADRILL)
double clearance
Copper clearance (CLEARANCE)
std::vector< std::string > net_names
Nets assigned to this class.
double track_width
Track width (TRACKWIDTH)
std::string name
Net class name.
double diff_pair_width
Differential pair width (DIFFPAIRWIDTH)
double diff_pair_gap
Differential pair gap (DIFFPAIRGAP)
double via_size
Via diameter (VIASIZE)
std::vector< NET_PIN > pins
bool chamfered
True if corners are chamfered (negative corner in PADS)
double drill
Drill hole diameter (0 for SMD)
int thermal_spoke_count
Number of thermal spokes (typically 4)
std::string shape
Shape code: R, S, A, O, OF, RF, RT, ST, RA, SA, RC, OC.
bool plated
True if drill is plated (PTH vs NPTH)
double rotation
Pad rotation angle in degrees.
double thermal_outer_diameter
Outer diameter of thermal or void in plane.
double slot_orientation
Slot orientation in degrees (0-179.999)
double thermal_spoke_orientation
First spoke orientation in degrees.
double slot_length
Slot length.
double inner_diameter
Inner diameter for annular ring (0 = solid)
double thermal_spoke_width
Width of thermal spokes.
double finger_offset
Finger pad offset along orientation axis.
double sizeB
Secondary size (height for rectangles/ovals)
double slot_offset
Slot offset from electrical center.
double corner_radius
Corner radius magnitude (always positive)
double sizeA
Primary size (diameter or width)
std::vector< DECAL_ITEM > items
std::vector< TERMINAL > terminals
std::vector< ATTRIBUTE > attributes
std::map< int, std::vector< PAD_STACK_LAYER > > pad_stacks
std::map< std::string, std::string > attributes
Attribute name-value pairs from {...} block.
std::map< std::string, int > pin_pad_map
Maps pin name to pad stack index.
std::vector< GATE_DEF > gates
Gate definitions for swap support.
std::vector< SIGPIN > signal_pins
Standard signal pin definitions.
std::string part_type
Part type name when using PARTTYPE@DECAL syntax.
bool explicit_decal
True if decal was explicitly specified with @ syntax.
std::string reuse_instance
Reuse block instance name (if member of reuse)
std::string decal
Primary decal (first in colon-separated list)
int alt_decal_index
ALT field from placement (-1 = use primary decal)
std::vector< ATTRIBUTE > attributes
std::string reuse_part
Original part ref des inside the reuse block.
std::vector< std::string > alternate_decals
Alternate decals (remaining after ':' splits)
A polyline that may contain arc segments.
bool closed
True if polyline forms a closed shape.
std::vector< ARC_POINT > points
Polyline vertices, may include arcs.
std::string name
This pour record's name.
bool is_cutout
True if this is a cutout (POCUT) piece.
POUR_STYLE style
Pour fill style.
std::string owner_pour
Name of parent pour (7th field in header)
double hatch_grid
Hatch grid spacing for hatched pours.
std::vector< ARC_POINT > points
Pour outline, may include arc segments.
THERMAL_TYPE thermal_type
double hatch_width
Hatch line width.
A reuse block definition containing parts and routes that can be instantiated.
std::vector< REUSE_NET > nets
Nets contained in this block with merge flags.
std::string net_naming
Default net naming scheme.
long timestamp
Creation/modification timestamp.
std::string part_naming
Default part naming scheme.
std::vector< std::string > part_names
Parts contained in this block.
std::vector< REUSE_INSTANCE > instances
Placements of this block.
std::string name
Block type name.
std::string instance_name
Instance name.
std::string part_naming
Part naming scheme (may be multi-word like "PREFIX pref")
std::string net_naming
Net naming scheme (may be multi-word like "SUFFIX suf")
bool glued
True if glued in place.
POINT location
Placement location.
double rotation
Rotation angle in degrees.
A reuse block instance placement.
std::string name
Original net name from reuse definition.
bool merge
True to merge nets, false to rename.
std::vector< TEARDROP > teardrops
Teardrop locations in this route.
std::vector< TRACK > tracks
std::vector< NET_PIN > pins
Pins connected to this net (from pin pair lines)
std::vector< JUMPER_MARKER > jumpers
Jumper start/end points in this route.
Standard signal pin definition (power, ground, etc.)
std::string pin_number
Pin number.
double width
Track width for connections.
std::string signal_name
Standard signal name (e.g., VCC, GND)
Teardrop parameters for a route point.
int net_flags
Net-side teardrop flags.
double pad_width
Teardrop width at pad side.
int pad_flags
Pad-side teardrop flags.
double net_width
Teardrop width at net side.
double pad_length
Teardrop length toward pad.
double net_length
Teardrop length toward net.
A test point definition for manufacturing/testing access.
std::vector< ARC_POINT > points
Track points, may include arc segments.
bool has_mask_front
Stack includes top soldermask opening (layer 25)
int drill_start
Drill start layer from file (for blind/buried vias)
int start_layer
First PADS layer number in via span.
int end_layer
Last PADS layer number in via span.
std::vector< PAD_STACK_LAYER > stack
int drill_end
Drill end layer from file (for blind/buried vias)
VIA_TYPE via_type
Classified via type.
bool has_mask_back
Stack includes bottom soldermask opening (layer 28)
wxString result
Test unit parsing edge cases and error handling.
wxLogTrace helper definitions.