46 std::vector<std::string>
result;
48 size_t braceStart = aPattern.find(
'{' );
49 size_t braceEnd = aPattern.find(
'}' );
51 if( braceStart == std::string::npos || braceEnd == std::string::npos || braceEnd <= braceStart )
53 result.push_back( aPattern );
57 std::string prefix = aPattern.substr( 0, braceStart );
58 std::string suffix = ( braceEnd + 1 < aPattern.length() ) ? aPattern.substr( braceEnd + 1 ) :
"";
59 std::string range = aPattern.substr( braceStart + 1, braceEnd - braceStart - 1 );
61 size_t dashPos = range.find(
'-' );
63 if( dashPos == std::string::npos )
65 result.push_back( aPattern );
72 if( start == INT_MIN ||
end == INT_MIN )
74 result.push_back( aPattern );
78 static constexpr int MAX_EXPANSION = 10000;
82 wxLogWarning( wxT(
"PADS Import: shortcut range {%d-%d} exceeds limit, skipped" ),
84 result.push_back( aPattern );
88 for(
int i = start; i <=
end; ++i )
90 result.push_back( prefix + std::to_string( i ) + suffix );
107 std::ifstream file( aFileName.ToStdString() );
108 if( !file.is_open() )
110 throw std::runtime_error(
"Could not open file " + aFileName.ToStdString() );
118 throw std::runtime_error(
"Empty file" );
130 if( line.size() > 2 && line[0] ==
'*' && line.back() ==
'*' )
132 std::string
header = line.substr( 1, line.size() - 2 );
136 if(
header.find(
"LIBRARY-LINE-ITEMS" ) != std::string::npos ||
137 header.find(
"LIBRARY-LINE" ) != std::string::npos )
141 else if(
header.find(
"LIBRARY-SCH-DECALS" ) != std::string::npos )
145 else if(
header.find(
"LIBRARY-PCB-DECALS" ) != std::string::npos ||
146 header.find(
"LIBRARY-DECALS" ) != std::string::npos )
150 else if(
header.find(
"LIBRARY-PART-TYPES" ) != std::string::npos )
156 size_t v_pos =
header.rfind(
"-V" );
158 if( v_pos != std::string::npos )
166 else if( line.size() > 2 && line[0] ==
'!' )
170 size_t close_pos = line.find(
'!', 1 );
172 if( close_pos == std::string::npos )
173 close_pos = line.size();
175 std::string
header = line.substr( 1, close_pos - 1 );
178 std::vector<std::string> parts;
182 while( ( pos =
header.find(
'-', start ) ) != std::string::npos )
184 parts.push_back(
header.substr( start, pos - start ) );
188 parts.push_back(
header.substr( start ) );
191 if( parts.size() >= 4 )
198 if( parts.size() >= 5 )
201 if( parts.size() >= 6 )
204 else if( parts.size() >= 2 )
209 if( parts.size() >= 2 )
212 if( parts.size() >= 3 )
234 else if( line.find(
"BASIC" ) != std::string::npos )
248 if( line.empty() )
continue;
250 if( line.rfind(
"*PCB*", 0 ) == 0 )
254 else if( line.rfind(
"*PART*", 0 ) == 0 )
258 else if( line.rfind(
"*NET*", 0 ) == 0 )
262 else if( line.rfind(
"*ROUTE*", 0 ) == 0 )
266 else if( line.rfind(
"*TEXT*", 0 ) == 0 )
270 else if( line.rfind(
"*BOARD*", 0 ) == 0 )
274 else if( line.rfind(
"*LINES*", 0 ) == 0 )
278 else if( line.rfind(
"*VIA*", 0 ) == 0 )
282 else if( line.rfind(
"*POUR*", 0 ) == 0 )
286 else if( line.rfind(
"*PARTDECAL*", 0 ) == 0 )
290 else if( line.rfind(
"*PARTTYPE*", 0 ) == 0 )
294 else if( line.rfind(
"*REUSE*", 0 ) == 0 )
298 else if( line.rfind(
"*CLUSTER*", 0 ) == 0 )
302 else if( line.rfind(
"*JUMPER*", 0 ) == 0 )
306 else if( line.rfind(
"*TESTPOINT*", 0 ) == 0 )
310 else if( line.rfind(
"*NETCLASS*", 0 ) == 0 || line.rfind(
"*NETDEF*", 0 ) == 0 )
314 else if( line.rfind(
"*DIFFPAIR*", 0 ) == 0 || line.rfind(
"*DIFFPAIRS*", 0 ) == 0 )
318 else if( line.rfind(
"LAYER MILS", 0 ) == 0 || line.rfind(
"LAYER METRIC", 0 ) == 0 )
322 else if( line.rfind(
"*MISC*", 0 ) == 0 )
338 while( std::getline( aStream, aLine ) )
341 aLine.erase( 0, aLine.find_first_not_of(
" \t\r\n" ) );
342 aLine.erase( aLine.find_last_not_of(
" \t\r\n" ) + 1 );
344 if( aLine.empty() )
continue;
345 if( aLine.rfind(
"*REMARK*", 0 ) == 0 )
continue;
364 if( !ver.empty() && ( ver[0] ==
'V' || ver[0] ==
'v' ) )
367 size_t dot = ver.find(
'.', start );
368 std::string major_str = ( dot != std::string::npos ) ? ver.substr( start, dot - start )
369 : ver.substr( start );
373 return std::stoi( major_str );
375 catch(
const std::exception& )
392 std::istringstream iss( line );
396 if( token ==
"UNITS" )
405 else if( token ==
"USERGRID" )
409 else if( token ==
"MAXIMUMLAYER" )
413 else if( token ==
"ORIGIN" )
417 else if( token ==
"THERLINEWID" )
421 else if( token ==
"THERSMDWID" )
425 else if( token ==
"THERFLAGS" )
427 std::string flags_str;
432 m_parameters.thermal_flags = std::stoi( flags_str,
nullptr, 0 );
434 catch(
const std::exception& )
439 else if( token ==
"DRLOVERSIZE" )
443 else if( token ==
"VIAPSHVIA" )
447 else if( token ==
"STMINCLEAR" )
451 else if( token ==
"STMINSPOKES" )
455 else if( token ==
"MINCLEAR" )
459 else if( token ==
"DEFAULTCLEAR" )
463 else if( token ==
"MINTRACKWID" )
467 else if( token ==
"DEFAULTTRACKWID" )
471 else if( token ==
"MINVIASIZE" )
475 else if( token ==
"DEFAULTVIASIZE" )
479 else if( token ==
"MINVIADRILL" )
483 else if( token ==
"DEFAULTVIADRILL" )
487 else if( token ==
"HOLEHOLE" )
491 else if( token ==
"SILKCLEAR" )
495 else if( token ==
"MASKCLEAR" )
507 if( line.find(
"*REMARK*" ) == 0 )
517 if( line.rfind(
"}", 0 ) == 0 ||
518 line.rfind(
"{", 0 ) == 0 )
523 std::istringstream iss( line );
528 std::string name_token, parttype_string;
539 bool is_shortcut = ( expanded_names.size() > 1 );
540 part.
name = expanded_names[0];
544 size_t at_pos = parttype_string.find(
'@' );
546 if( at_pos != std::string::npos )
549 part.
part_type = parttype_string.substr( 0, at_pos );
550 part.
decal = parttype_string.substr( at_pos + 1 );
559 size_t colon_pos = 0;
562 while( ( colon_pos = parttype_string.find(
':', pos ) ) != std::string::npos )
564 std::string decal_name = parttype_string.substr( pos, colon_pos - pos );
568 part.
decal = decal_name;
580 std::string last_decal = parttype_string.substr( pos );
584 part.
decal = last_decal;
593 std::vector<std::string> tokens;
595 while( iss >> token )
597 tokens.push_back( token );
607 for(
size_t i = 0; i < tokens.size(); ++i )
609 const std::string& t = tokens[i];
630 if( i == tokens.size() - 1 )
635 labels = std::stoi( t, &pos );
637 if( pos != t.length() )
640 catch(
const std::exception& )
651 if( line.find(
".REUSE." ) == 0 )
653 std::istringstream riss( line );
654 std::string reuse_keyword;
663 for(
int i = 0; i < labels; ++i )
666 if( !
readLine( aStream, line ) )
break;
668 std::stringstream iss_attr( line );
669 std::string visible_str;
670 std::string mirrored_str;
671 std::string right_reading_str;
677 attr.
visible = ( visible_str ==
"VALUE" || visible_str ==
"FULL_NAME"
678 || visible_str ==
"NAME" || visible_str ==
"FULL_BOTH"
679 || visible_str ==
"BOTH" );
680 attr.
mirrored = ( mirrored_str ==
"M" );
681 iss_attr >> right_reading_str;
682 attr.
right_reading = ( right_reading_str ==
"Y" || right_reading_str ==
"ORTHO" );
687 if( !
readLine( aStream, line ) )
break;
691 if( !
readLine( aStream, line ) )
break;
704 for(
size_t i = 1; i < expanded_names.size(); ++i )
706 PART additional_part = part;
707 additional_part.
name = expanded_names[i];
708 m_parts.push_back( additional_part );
721 NET* current_net =
nullptr;
724 auto parsePinToken = [](
const std::string& token,
NET_PIN&
pin ) ->
bool
726 size_t dot_pos = token.find(
'.' );
728 if( dot_pos == std::string::npos )
731 pin.ref_des = token.substr( 0, dot_pos );
732 pin.pin_name = token.substr( dot_pos + 1 );
738 auto expandShortcutPin = [](
const std::string& token ) -> std::vector<std::string>
740 std::vector<std::string> results;
743 if( token.find(
'{' ) == std::string::npos )
745 results.push_back( token );
756 bool is_range =
false;
759 std::vector<RangePart> parts;
761 std::string current_prefix;
763 while( pos < token.size() )
765 if( token[pos] ==
'{' )
767 size_t close_pos = token.find(
'}', pos );
769 if( close_pos == std::string::npos )
772 results.push_back( token );
776 std::string range_str = token.substr( pos + 1, close_pos - pos - 1 );
777 size_t dash_pos = range_str.find(
'-' );
779 if( dash_pos != std::string::npos )
782 part.prefix = current_prefix;
783 part.is_range =
true;
786 INT_MIN,
"net range" );
788 INT_MIN,
"net range" );
790 if( part.start == INT_MIN || part.end == INT_MIN )
792 results.push_back( token );
796 parts.push_back( part );
797 current_prefix.clear();
802 current_prefix += range_str;
809 current_prefix += token[pos];
815 if( !current_prefix.empty() || parts.empty() )
817 RangePart final_part;
818 final_part.prefix = current_prefix;
819 final_part.is_range =
false;
820 final_part.start = 0;
822 parts.push_back( final_part );
827 results.push_back(
"" );
829 for(
const auto& part : parts )
831 std::vector<std::string> new_results;
835 for(
const auto& base : results )
837 int step = ( part.start <= part.end ) ? 1 : -1;
839 for(
int i = part.start; step > 0 ? i <= part.end : i >= part.end; i += step )
841 new_results.push_back( base + part.prefix + std::to_string( i ) );
847 for(
const auto& base : results )
849 new_results.push_back( base + part.prefix );
853 results = std::move( new_results );
867 std::istringstream iss( line );
871 if( token ==
"SIGNAL" )
876 current_net = &
m_nets.back();
879 std::string pin_token;
881 while( iss >> pin_token )
884 if( pin_token ==
".REUSE." )
887 std::string instance, rsignal;
889 if( ( iss >> instance >> rsignal ) && !current_net->
pins.empty() )
891 current_net->
pins.back().reuse_instance = instance;
892 current_net->
pins.back().reuse_signal = rsignal;
899 for(
const auto& expanded : expandShortcutPin( pin_token ) )
903 if( parsePinToken( expanded,
pin ) )
904 current_net->
pins.push_back(
pin );
916 if( token ==
".REUSE." )
918 std::string instance, rsignal;
920 if( ( iss >> instance >> rsignal ) && !current_net->
pins.empty() )
922 current_net->
pins.back().reuse_instance = instance;
923 current_net->
pins.back().reuse_signal = rsignal;
930 for(
const auto& expanded : expandShortcutPin( token ) )
934 if( parsePinToken( expanded,
pin ) )
935 current_net->
pins.push_back(
pin );
938 }
while( iss >> token );
956 std::stringstream iss( line );
961 if( !( iss >>
name >> drill >> stacklines ) )
969 int drill_start_val = 0;
970 int drill_end_val = 0;
972 if( iss >> drill_start_val >> drill_end_val )
978 int min_layer = INT_MAX;
979 int max_layer = INT_MIN;
981 for(
int i = 0; i < stacklines; ++i )
986 std::stringstream iss2( line );
991 if( !( iss2 >> level >> size >> shape ) )
995 layer_data.
layer = level;
996 layer_data.
shape = shape;
997 layer_data.
sizeA = size;
1001 if( shape ==
"R" || shape ==
"S" )
1007 if( shape ==
"S" && ( iss2 >> corner ) )
1020 else if( shape ==
"RA" || shape ==
"SA" )
1025 else if( shape ==
"A" )
1033 else if( shape ==
"OF" )
1036 double ori = 0, length = 0, offset = 0;
1038 if( iss2 >> ori >> length >> offset )
1041 layer_data.
sizeB = length;
1045 else if( shape ==
"RF" )
1049 double ori = 0, length = 0, offset = 0;
1051 if( iss2 >> ori >> length >> offset )
1054 layer_data.
sizeB = length;
1058 else if( shape ==
"RT" || shape ==
"ST" )
1061 double ori = 0, intd = 0, spkwid = 0;
1064 if( iss2 >> ori >> intd >> spkwid >> spknum )
1072 else if( shape ==
"O" || shape ==
"OC" )
1078 else if( shape ==
"RC" )
1082 double ori = 0, length = 0, offset = 0, corner = 0;
1084 if( iss2 >> ori >> length >> offset )
1087 layer_data.
sizeB = length;
1090 if( iss2 >> corner )
1105 def.
stack.push_back( layer_data );
1110 int effective_layer = level;
1113 effective_layer = 1;
1114 else if( level == -1 )
1117 bool is_copper = ( effective_layer >= 1
1122 if( size > def.
size )
1125 if( effective_layer < min_layer )
1126 min_layer = effective_layer;
1128 if( effective_layer > max_layer )
1129 max_layer = effective_layer;
1135 else if( level == 28 )
1140 if( min_layer <= max_layer )
1146 bool starts_at_surface = ( min_layer == 1 || max_layer == layer_count );
1147 bool ends_at_surface = ( max_layer == layer_count || min_layer == 1 );
1148 bool is_full_span = ( min_layer == 1 && max_layer == layer_count );
1149 int span = max_layer - min_layer;
1155 else if( span == 1 && ( min_layer == 1 || max_layer == layer_count ) )
1159 else if( starts_at_surface || ends_at_surface )
1183 if( line[0] ==
'*' )
1191 std::stringstream iss( line );
1192 std::string
name, type;
1193 double x = 0.0, y = 0.0;
1194 int pieces = 0, flags = 0;
1196 if( !( iss >>
name >> type >> x >> y >> pieces >> flags ) )
1199 std::string owner, signame;
1200 double hatchgrid = 0.0, hatchrad = 0.0;
1203 if( iss >> owner >> signame )
1205 iss >> hatchgrid >> hatchrad >> priority;
1208 for(
int i = 0; i < pieces; ++i )
1215 std::stringstream iss2( line );
1216 std::string poly_type;
1217 int corners = 0, arcs = 0;
1221 if( !( iss2 >> poly_type >> corners >> arcs >> width >> level ) )
1230 pour.
is_cutout = ( poly_type ==
"POCUT" || poly_type ==
"CUTOUT"
1231 || poly_type ==
"CIRCUT" );
1239 if( type ==
"HATOUT" )
1243 else if( type ==
"VOIDOUT" )
1248 else if( type ==
"PADTHERM" )
1252 else if( type ==
"VIATHERM" )
1258 if( poly_type ==
"CIRCLE" || poly_type ==
"CIRCUT" )
1265 std::stringstream iss3( line );
1266 double cx = 0.0, cy = 0.0,
radius = 0.0;
1268 if( iss3 >> cx >> cy >>
radius )
1275 arc.start_angle = 0.0;
1276 arc.delta_angle = 360.0;
1277 pour.
points.emplace_back( x + cx +
radius, y + cy, arc );
1280 else if( poly_type ==
"SEG" )
1283 for(
int j = 0; j < corners; ++j )
1288 std::stringstream iss3( line );
1289 double px = 0.0, py = 0.0;
1291 if( iss3 >> px >> py )
1293 pour.
points.emplace_back( x + px, y + py );
1305 int totalLines = corners + arcs;
1306 bool nextIsArcEndpoint =
false;
1309 for(
int j = 0; j < totalLines; ++j )
1314 std::stringstream iss3( line );
1315 double px = 0.0, py = 0.0;
1317 if( !( iss3 >> px >> py ) )
1320 int angle1 = 0, angle2 = 0;
1322 if( iss3 >> angle1 >> angle2 )
1328 pendingArc.
cx = x + px;
1329 pendingArc.cy = y + py;
1330 pendingArc.start_angle = angle1 / 10.0;
1331 pendingArc.delta_angle = angle2 / 10.0;
1333 if( !pour.
points.empty() )
1335 double dx = pour.
points.back().x - pendingArc.cx;
1336 double dy = pour.
points.back().y - pendingArc.cy;
1337 pendingArc.radius = std::sqrt( dx * dx + dy * dy );
1340 nextIsArcEndpoint =
true;
1342 else if( nextIsArcEndpoint )
1344 if( pendingArc.radius == 0.0 )
1346 double dx = ( x + px ) - pendingArc.cx;
1347 double dy = ( y + py ) - pendingArc.cy;
1348 pendingArc.radius = std::sqrt( dx * dx + dy * dy );
1351 pour.
points.emplace_back( x + px, y + py, pendingArc );
1352 nextIsArcEndpoint =
false;
1356 pour.
points.emplace_back( x + px, y + py );
1371 if( line[0] ==
'*' )
1378 std::stringstream iss( line );
1379 std::string
name, units;
1380 double orix = 0.0, oriy = 0.0;
1381 int pieces = 0, terminals = 0, stacks = 0, text_cnt = 0, labels = 0;
1383 if( !( iss >>
name >> units >> orix >> oriy >> pieces >> terminals >> stacks >> text_cnt >> labels ) )
1388 decal.
units = units;
1391 for(
int i = 0; i < pieces; ++i )
1393 if( !
readLine( aStream, line ) )
break;
1396 std::stringstream iss2( line );
1402 if( !( iss2 >> type >> corners >> width ) )
1435 decal.
items.push_back( item );
1441 if( type.find(
"COP" ) == 0 )
1443 std::string remaining;
1444 std::getline( iss2, remaining );
1447 std::istringstream rem_ss( remaining );
1448 int pinnum_val = -1;
1450 if( rem_ss >> pinnum_val )
1451 item.
pinnum = pinnum_val;
1455 if( type.find(
"KPT" ) == 0 )
1457 std::string restrictions;
1459 if( iss2 >> restrictions )
1463 for(
int j = 0; j < corners; ++j )
1468 std::stringstream iss3( line );
1469 double px = 0.0, py = 0.0;
1471 if( !( iss3 >> px >> py ) )
1477 int startAngleTenths = 0, deltaAngleTenths = 0;
1478 double bboxMinX = 0.0, bboxMinY = 0.0, bboxMaxX = 0.0, bboxMaxY = 0.0;
1480 if( iss3 >> startAngleTenths >> deltaAngleTenths
1481 >> bboxMinX >> bboxMinY >> bboxMaxX >> bboxMaxY )
1483 double cx = ( bboxMinX + bboxMaxX ) / 2.0;
1484 double cy = ( bboxMinY + bboxMaxY ) / 2.0;
1485 double radius = ( bboxMaxX - bboxMinX ) / 2.0;
1486 double startAngle = startAngleTenths / 10.0;
1487 double deltaAngle = deltaAngleTenths / 10.0;
1490 double startAngleRad = startAngle *
M_PI / 180.0;
1491 double startX = cx +
radius * std::cos( startAngleRad );
1492 double startY = cy +
radius * std::sin( startAngleRad );
1495 double endAngleRad = ( startAngle + deltaAngle ) *
M_PI / 180.0;
1496 double endX = cx +
radius * std::cos( endAngleRad );
1497 double endY = cy +
radius * std::sin( endAngleRad );
1500 item.
points.emplace_back( startX, startY );
1506 arc.start_angle = startAngle;
1507 arc.delta_angle = deltaAngle;
1510 item.
points.emplace_back( endX, endY, arc );
1514 item.
points.emplace_back( px, py );
1518 decal.
items.push_back( item );
1525 for(
int i = 0; i < text_cnt + labels; ++i )
1527 std::string attrLine, fontLine, nameLine;
1529 if( !
readLine( aStream, attrLine ) )
1534 if( !
readLine( aStream, fontLine ) )
1538 if( !
readLine( aStream, nameLine ) )
1542 std::stringstream ss( attrLine );
1543 std::string type_token;
1546 std::string mirrored_str, right_reading_str;
1551 attr.
visible = ( type_token ==
"VALUE" || type_token ==
"FULL_NAME"
1552 || type_token ==
"NAME" || type_token ==
"FULL_BOTH"
1553 || type_token ==
"BOTH" );
1554 attr.
mirrored = ( mirrored_str ==
"M" );
1555 ss >> right_reading_str;
1556 attr.
right_reading = ( right_reading_str ==
"Y" || right_reading_str ==
"ORTHO" );
1560 attr.
name = nameLine;
1571 for(
int i = 0; i < terminals; ++i )
1573 if( !
readLine( aStream, line ) )
break;
1575 size_t t_pos = line.find(
'T' );
1577 if( t_pos != std::string::npos )
1580 std::stringstream iss_t( line );
1582 double nmx = 0.0, nmy = 0.0;
1584 if( iss_t >> term.
x >> term.
y >> nmx >> nmy )
1588 if( term.
name.empty() )
1589 term.
name = std::to_string( i + 1 );
1599 for(
int i = 0; i < stacks; ++i )
1604 std::stringstream iss_pad( line );
1607 int stack_lines = 0;
1608 iss_pad >> token >> pin_idx >> stack_lines;
1610 if( token !=
"PAD" )
1614 std::string plated_token;
1615 bool default_plated =
true;
1616 double header_drill = 0.0;
1618 if( iss_pad >> plated_token )
1620 if( plated_token ==
"P" )
1621 default_plated =
true;
1622 else if( plated_token ==
"N" )
1623 default_plated =
false;
1631 double header_slot_ori = 0.0;
1632 double header_slot_len = 0.0;
1633 double header_slot_off = 0.0;
1635 if( iss_pad >> header_slot_ori >> header_slot_len >> header_slot_off )
1640 std::vector<PAD_STACK_LAYER> stack;
1642 for(
int j = 0; j < stack_lines; ++j )
1647 std::stringstream line_ss( line );
1653 if( !( line_ss >> layer >> size >> shape ) )
1657 layer_data.
layer = layer;
1658 layer_data.
sizeA = size;
1659 layer_data.
sizeB = size;
1660 layer_data.
shape = shape;
1661 layer_data.
plated = default_plated;
1662 layer_data.
drill = header_drill;
1673 else if( shape ==
"S" )
1677 double corner = 0.0;
1679 if( line_ss >> corner )
1692 else if( shape ==
"RA" || shape ==
"SA" )
1697 else if( shape ==
"A" )
1702 if( line_ss >> intd )
1705 else if( shape ==
"OF" )
1708 double ori = 0.0, length = 0.0, offset = 0.0;
1710 if( line_ss >> ori >> length >> offset )
1713 layer_data.
sizeB = length;
1717 else if( shape ==
"RF" )
1721 double ori = 0.0, length = 0.0, offset = 0.0;
1723 if( line_ss >> ori >> length >> offset )
1726 layer_data.
sizeB = length;
1729 double corner = 0.0;
1731 if( line_ss >> corner )
1745 else if( shape ==
"RT" || shape ==
"ST" )
1748 double ori = 0.0, outsize = 0.0, spkwid = 0.0;
1751 if( line_ss >> ori >> outsize >> spkwid >> spknum )
1759 else if( shape ==
"O" || shape ==
"OC" )
1765 else if( shape ==
"RC" )
1769 double ori = 0.0, length = 0.0, offset = 0.0, corner = 0.0;
1771 if( line_ss >> ori >> length >> offset )
1774 layer_data.
sizeB = length;
1777 if( line_ss >> corner )
1794 std::vector<std::string> remaining;
1795 std::string token_rem;
1797 while( line_ss >> token_rem )
1798 remaining.push_back( token_rem );
1801 if( !remaining.empty() )
1807 -1.0,
"pad layer drill" );
1809 if( drill_val >= 0.0 )
1811 layer_data.
drill = drill_val;
1816 if( idx < remaining.size() )
1818 if( remaining[idx] ==
"P" || remaining[idx] ==
"Y" )
1820 layer_data.
plated =
true;
1823 else if( remaining[idx] ==
"N" )
1825 layer_data.
plated =
false;
1831 if( idx + 2 < remaining.size() )
1842 stack.push_back( layer_data );
1855 ROUTE* current_route =
nullptr;
1856 TRACK current_track;
1857 bool in_track =
false;
1858 bool prev_is_plane_connection =
false;
1860 int last_plane_connection_layer = 0;
1861 double last_plane_connection_width = 0;
1862 bool last_plane_on_copper =
false;
1863 std::string default_via_name;
1864 bool has_pending_arc_center =
false;
1866 std::string pending_arc_dir;
1870 if( line[0] ==
'*' )
1872 if( line.rfind(
"*SIGNAL*", 0 ) == 0 )
1874 if( in_track && current_route )
1876 current_route->
tracks.push_back( current_track );
1877 current_track.
points.clear();
1881 prev_is_plane_connection =
false;
1882 has_pending_arc_center =
false;
1884 std::istringstream iss( line );
1888 std::string net_name;
1892 default_via_name.clear();
1894 while( iss >> token )
1896 if( !token.empty() && token.back() ==
';' )
1900 default_via_name = token;
1905 current_route->
net_name = net_name;
1916 if( !isdigit( line[0] ) && line[0] !=
'-' && line[0] !=
'+' )
1918 if( in_track && current_route )
1920 current_route->
tracks.push_back( current_track );
1921 current_track.
points.clear();
1925 prev_is_plane_connection =
false;
1930 std::istringstream pin_iss( line );
1931 std::string pin_token;
1933 while( pin_iss >> pin_token )
1935 size_t dot_pos = pin_token.find(
'.' );
1937 if( dot_pos != std::string::npos )
1940 pin.ref_des = pin_token.substr( 0, dot_pos );
1941 pin.pin_name = pin_token.substr( dot_pos + 1 );
1946 for(
const auto& existing : current_route->
pins )
1948 if( existing.ref_des ==
pin.ref_des &&
1949 existing.pin_name ==
pin.pin_name )
1957 current_route->
pins.push_back(
pin );
1965 std::istringstream iss( line );
1970 iss >> pt.
x >> pt.
y >> layer >> width >> flags;
1982 std::string via_name;
1983 std::string arc_dir;
1989 bool is_unrouted = ( layer == 0 );
1990 bool is_plane_connection = is_unrouted;
1993 bool has_teardrop =
false;
1994 bool has_jumper =
false;
1995 bool has_power =
false;
1997 while( iss >> token )
2000 if( token ==
"CW" || token ==
"CCW" )
2009 if( token ==
"POWER" )
2019 if( token ==
"THERMAL" )
2030 if( token ==
"TEARDROP" )
2032 has_teardrop =
true;
2033 std::string td_token;
2035 while( iss >> td_token )
2037 if( td_token ==
"P" )
2043 std::streampos pos = iss.tellg();
2046 if( iss >> td_flags )
2056 else if( td_token ==
"N" )
2061 std::streampos pos = iss.tellg();
2064 if( iss >> td_flags )
2078 if( td_token ==
"CW" || td_token ==
"CCW" )
2080 else if( td_token ==
"POWER" )
2085 via_name = td_token;
2087 else if( td_token ==
"THERMAL" )
2090 via_name = td_token;
2101 std::streampos pos = iss.tellg();
2102 std::string jumper_flag;
2104 if( iss >> jumper_flag )
2106 if( jumper_flag ==
"S" || jumper_flag ==
"E" )
2109 jumper.
name = token;
2110 jumper.
is_start = ( jumper_flag ==
"S" );
2129 if( token ==
"REUSE" || token ==
".REUSE." )
2132 std::string instance;
2142 if( !arc_dir.empty() )
2144 pending_arc_center = pt;
2145 pending_arc_dir = arc_dir;
2146 has_pending_arc_center =
true;
2150 if( has_pending_arc_center )
2152 has_pending_arc_center =
false;
2154 if( in_track && !current_track.
points.empty() )
2157 double dx0 = arc_start.
x - pending_arc_center.
x;
2158 double dy0 = arc_start.
y - pending_arc_center.
y;
2159 double start_angle = std::atan2( dy0, dx0 );
2161 std::atan2( pt.
y - pending_arc_center.
y, pt.
x - pending_arc_center.
x );
2162 double sweep = end_angle - start_angle;
2166 if( pending_arc_dir ==
"CCW" )
2168 while( sweep <= 0.0 )
2169 sweep += 2.0 *
M_PI;
2173 while( sweep >= 0.0 )
2174 sweep -= 2.0 *
M_PI;
2178 pt.
arc.
cx = pending_arc_center.
x;
2179 pt.
arc.
cy = pending_arc_center.
y;
2180 pt.
arc.
radius = std::sqrt( dx0 * dx0 + dy0 * dy0 );
2190 int effective_layer = layer;
2191 bool is_pad_connection = ( layer == 65 );
2195 if( is_unrouted && in_track )
2196 effective_layer = current_track.
layer;
2201 if( !via_name.empty() && current_route )
2204 via.name = via_name;
2205 via.location = { pt.
x, pt.
y };
2206 current_route->
vias.push_back(
via );
2214 if( has_power && via_name.empty() && !is_unrouted && !is_pad_connection && current_route )
2218 if( !default_via_name.empty() )
2219 implicit_via.
name = default_via_name;
2224 current_route->
vias.push_back( implicit_via );
2228 if( has_teardrop && current_route )
2230 current_route->
teardrops.push_back( teardrop );
2234 if( has_jumper && current_route )
2236 current_route->
jumpers.push_back( jumper );
2242 if( is_plane_connection && prev_is_plane_connection )
2251 last_plane_connection_pt = pt;
2252 last_plane_connection_layer = effective_layer;
2253 last_plane_connection_width = width;
2254 last_plane_on_copper =
true;
2257 prev_is_plane_connection =
true;
2261 if( is_plane_connection && !prev_is_plane_connection )
2267 current_track.
points.push_back( pt );
2269 if( current_route && current_track.
points.size() > 1 )
2270 current_route->
tracks.push_back( current_track );
2272 current_track.
points.clear();
2279 last_plane_on_copper = !is_unrouted;
2281 if( last_plane_on_copper )
2283 last_plane_connection_pt = pt;
2284 last_plane_connection_layer = effective_layer;
2285 last_plane_connection_width = width;
2288 prev_is_plane_connection =
true;
2292 if( !is_plane_connection && prev_is_plane_connection )
2296 if( in_track && current_route && current_track.
points.size() > 1 )
2297 current_route->
tracks.push_back( current_track );
2299 prev_is_plane_connection =
false;
2301 if( is_pad_connection )
2307 current_track.
points.clear();
2309 if( last_plane_on_copper && last_plane_connection_layer == effective_layer )
2311 current_track.
layer = effective_layer;
2312 current_track.
width = std::max( width, last_plane_connection_width );
2313 current_track.
points.push_back( last_plane_connection_pt );
2314 current_track.
points.push_back( pt );
2320 if( !has_power && via_name.empty() && current_route && last_plane_on_copper &&
2321 std::abs( pt.
x - last_plane_connection_pt.
x ) < 0.001 &&
2322 std::abs( pt.
y - last_plane_connection_pt.
y ) < 0.001 )
2326 if( !default_via_name.empty() )
2327 implicit_via.
name = default_via_name;
2332 current_route->
vias.push_back( implicit_via );
2335 current_track.
layer = effective_layer;
2336 current_track.
width = width;
2337 current_track.
points.push_back( pt );
2340 last_plane_on_copper =
false;
2347 if( is_pad_connection )
2349 if( in_track && !current_track.
points.empty() )
2351 current_track.
points.push_back( pt );
2353 if( current_route && current_track.
points.size() > 1 )
2354 current_route->
tracks.push_back( current_track );
2356 current_track.
points.clear();
2364 prev_is_plane_connection =
false;
2368 current_track.
layer = effective_layer;
2369 current_track.
width = width;
2370 current_track.
points.clear();
2371 current_track.
points.push_back( pt );
2376 bool layer_changed = ( effective_layer != current_track.
layer );
2377 bool width_changed = (
std::abs( width - current_track.
width ) > 0.001 );
2379 if( layer_changed || width_changed )
2382 bool connect =
true;
2384 if( layer_changed && via_name.empty() )
2386 bool same_location =
2387 ( pt.
x == current_track.
points.back().x &&
2388 pt.
y == current_track.
points.back().y );
2394 if( !has_power && current_route )
2398 default_via_name.empty() ?
"STANDARDVIA" : default_via_name;
2400 current_route->
vias.push_back( implicit_via );
2403 else if( !has_power )
2413 current_track.
points.push_back( pt );
2417 current_route->
tracks.push_back( current_track );
2422 current_track.
layer = effective_layer;
2423 current_track.
width = width;
2424 current_track.
points.clear();
2425 current_track.
points.push_back( prev_pt );
2429 current_track.
points.push_back( pt );
2434 if( in_track && current_route )
2436 current_route->
tracks.push_back( current_track );
2446 if( line[0] ==
'*' )
2455 std::istringstream iss( line );
2464 std::string mirrored;
2466 text.mirrored = ( mirrored ==
"M" );
2476 if( token ==
".REUSE." )
2478 iss >>
text.reuse_instance;
2484 if( iss >> token && token ==
".REUSE." )
2486 iss >>
text.reuse_instance;
2497 std::istringstream fiss( line );
2498 std::string font_style_part;
2500 fiss >> font_style_part;
2502 size_t colon_pos = font_style_part.find(
':' );
2504 if( colon_pos != std::string::npos )
2506 text.font_style = font_style_part.substr( 0, colon_pos );
2507 std::string remaining = font_style_part.substr( colon_pos + 1 );
2509 size_t second_colon = remaining.find(
':' );
2511 if( second_colon != std::string::npos )
2514 remaining.substr( 0, second_colon ), 0.0,
"font height" );
2516 remaining.substr( second_colon + 1 ), 0.0,
"font descent" );
2526 text.font_style = font_style_part;
2529 size_t bracket_start = line.find(
'<' );
2530 size_t bracket_end = line.find(
'>' );
2532 if( bracket_start != std::string::npos && bracket_end != std::string::npos )
2535 line.substr( bracket_start + 1, bracket_end - bracket_start - 1 );
2540 std::getline( fiss, rest );
2542 if( !rest.empty() && rest[0] ==
' ' )
2543 rest = rest.substr( 1 );
2545 text.font_face = rest;
2556 while( ( pos = line.find(
"\\n", pos ) ) != std::string::npos )
2558 line.replace( pos, 2,
"\n" );
2564 std::replace( line.begin(), line.end(),
'_',
'\n' );
2566 text.content = line;
2580 if( line[0] ==
'*' )
2586 std::istringstream iss( line );
2587 std::string
name, type;
2588 double xloc = 0.0, yloc = 0.0;
2590 iss >>
name >> type >> xloc >> yloc >> pieces;
2593 for(
int i = 0; i < pieces; ++i )
2598 if( line[0] ==
'*' )
2604 std::istringstream piss( line );
2605 std::string shape_type;
2608 int linestyle = 0, level = 0;
2609 piss >> shape_type >> corners >> width >> linestyle >> level;
2612 if( shape_type ==
"CLOSED" || shape_type ==
"OPEN" || shape_type ==
"BRDCLS" )
2616 polyline.
width = width;
2617 polyline.
closed = ( shape_type ==
"CLOSED" || shape_type ==
"BRDCLS" );
2619 for(
int j = 0; j < corners; ++j )
2624 if( line[0] ==
'*' )
2630 std::istringstream ciss( line );
2631 double dx = 0.0, dy = 0.0;
2636 int startAngleTenths = 0, deltaAngleTenths = 0;
2637 double bboxMinX = 0.0, bboxMinY = 0.0, bboxMaxX = 0.0, bboxMaxY = 0.0;
2639 if( ciss >> startAngleTenths >> deltaAngleTenths
2640 >> bboxMinX >> bboxMinY >> bboxMaxX >> bboxMaxY )
2642 double cx = ( bboxMinX + bboxMaxX ) / 2.0;
2643 double cy = ( bboxMinY + bboxMaxY ) / 2.0;
2644 double radius = ( bboxMaxX - bboxMinX ) / 2.0;
2645 double startAngle = startAngleTenths / 10.0;
2646 double deltaAngle = deltaAngleTenths / 10.0;
2648 double startAngleRad = startAngle *
M_PI / 180.0;
2649 double startX = cx +
radius * std::cos( startAngleRad );
2650 double startY = cy +
radius * std::sin( startAngleRad );
2652 double endAngleRad = ( startAngle + deltaAngle ) *
M_PI / 180.0;
2653 double endX = cx +
radius * std::cos( endAngleRad );
2654 double endY = cy +
radius * std::sin( endAngleRad );
2656 polyline.
points.emplace_back( xloc + startX, yloc + startY );
2662 arc.start_angle = startAngle;
2663 arc.delta_angle = deltaAngle;
2665 polyline.
points.emplace_back( xloc + endX, yloc + endY, arc );
2669 polyline.
points.emplace_back( xloc + dx, yloc + dy );
2673 if( !polyline.
points.empty() )
2676 else if( shape_type ==
"CIRCLE" || shape_type ==
"BRDCIR" )
2681 polyline.
width = width;
2684 double x1 = 0.0, y1 = 0.0, x2 = 0.0, y2 = 0.0;
2688 std::istringstream c1( line );
2692 if( corners >= 2 &&
readLine( aStream, line ) )
2694 std::istringstream c2( line );
2699 double cx = xloc + ( x1 + x2 ) / 2.0;
2700 double cy = yloc + ( y1 + y2 ) / 2.0;
2701 double radius = std::sqrt( ( x2 - x1 ) * ( x2 - x1 ) + ( y2 - y1 ) * ( y2 - y1 ) ) / 2.0;
2708 arc.start_angle = 0.0;
2709 arc.delta_angle = 360.0;
2713 if( !polyline.
points.empty() )
2719 for(
int j = 0; j < corners; ++j )
2724 if( line[0] ==
'*' )
2741 if( line[0] ==
'*' )
2748 std::istringstream iss( line );
2749 std::string
name, type;
2750 double xloc = 0.0, yloc = 0.0;
2751 int pieces = 0, flags = 0, textCount = 0;
2752 std::string signame;
2754 iss >>
name >> type >> xloc >> yloc >> pieces >> flags;
2759 if( iss >> textCount )
2770 std::string reuse_instance, reuse_signal;
2774 if( line.find(
".REUSE." ) != std::string::npos )
2776 std::istringstream riss( line );
2777 std::string reuse_keyword;
2778 riss >> reuse_keyword >> reuse_instance >> reuse_signal;
2786 if( type ==
"BOARD" )
2788 for(
int i=0; i<pieces; ++i )
2790 if( !
readLine( aStream, line ) )
break;
2793 std::istringstream piss( line );
2794 std::string shape_type;
2797 int piece_flags = 0;
2799 piss >> shape_type >> corners >> width >> piece_flags >> level;
2801 if( shape_type ==
"CLOSED" || shape_type ==
"OPEN" || shape_type ==
"BRDCLS" )
2805 polyline.
width = width;
2806 polyline.
closed = ( shape_type ==
"CLOSED" || shape_type ==
"BRDCLS" );
2808 for(
int j = 0; j < corners; ++j )
2813 if( line[0] ==
'*' )
2819 std::istringstream ciss( line );
2820 double dx = 0.0, dy = 0.0;
2825 int startAngleTenths = 0, deltaAngleTenths = 0;
2826 double bboxMinX = 0.0, bboxMinY = 0.0, bboxMaxX = 0.0, bboxMaxY = 0.0;
2828 if( ciss >> startAngleTenths >> deltaAngleTenths
2829 >> bboxMinX >> bboxMinY >> bboxMaxX >> bboxMaxY )
2831 double cx = ( bboxMinX + bboxMaxX ) / 2.0;
2832 double cy = ( bboxMinY + bboxMaxY ) / 2.0;
2833 double radius = ( bboxMaxX - bboxMinX ) / 2.0;
2834 double startAngle = startAngleTenths / 10.0;
2835 double deltaAngle = deltaAngleTenths / 10.0;
2837 double startAngleRad = startAngle *
M_PI / 180.0;
2838 double startX = cx +
radius * std::cos( startAngleRad );
2839 double startY = cy +
radius * std::sin( startAngleRad );
2841 double endAngleRad = ( startAngle + deltaAngle ) *
M_PI / 180.0;
2842 double endX = cx +
radius * std::cos( endAngleRad );
2843 double endY = cy +
radius * std::sin( endAngleRad );
2845 polyline.
points.emplace_back( xloc + startX, yloc + startY );
2851 arc.start_angle = startAngle;
2852 arc.delta_angle = deltaAngle;
2854 polyline.
points.emplace_back( xloc + endX, yloc + endY, arc );
2858 polyline.
points.emplace_back( xloc + dx, yloc + dy );
2862 if( !polyline.
points.empty() )
2865 else if( shape_type ==
"CIRCLE" || shape_type ==
"BRDCIR" )
2868 double x1 = 0.0, y1 = 0.0, x2 = 0.0, y2 = 0.0;
2872 std::istringstream c1( line );
2876 if( corners >= 2 &&
readLine( aStream, line ) )
2878 std::istringstream c2( line );
2882 double cx = xloc + ( x1 + x2 ) / 2.0;
2883 double cy = yloc + ( y1 + y2 ) / 2.0;
2884 double radius = std::sqrt( ( x2 - x1 ) * ( x2 - x1 ) +
2885 ( y2 - y1 ) * ( y2 - y1 ) ) / 2.0;
2889 polyline.
width = width;
2896 arc.start_angle = 0.0;
2897 arc.delta_angle = 360.0;
2901 if( !polyline.
points.empty() )
2906 for(
int j=0; j<corners; ++j )
2908 if( !
readLine( aStream, line ) )
break;
2914 else if(
name.rfind(
"DIM", 0 ) == 0 && type ==
"LINES" )
2934 double baspnt1_x = 0, baspnt1_y = 0;
2935 double baspnt2_x = 0, baspnt2_y = 0;
2936 double arwln_x = 0, arwln_y = 0;
2937 int baspnt_count = 0;
2938 bool hasArwln =
false;
2940 for(
int i = 0; i < pieces; ++i )
2945 if( line[0] ==
'*' )
2951 std::istringstream piss( line );
2952 std::string shape_type;
2955 int piece_flags = 0;
2957 piss >> shape_type >> corners >> width >> piece_flags >> level;
2961 for(
int j = 0; j < corners; ++j )
2966 if( line[0] ==
'*' )
2972 std::istringstream ciss( line );
2973 double dx = 0.0, dy = 0.0;
2978 if( shape_type ==
"BASPNT" && j == 0 )
2980 if( baspnt_count == 0 )
2982 baspnt1_x = xloc + dx;
2983 baspnt1_y = yloc + dy;
2985 else if( baspnt_count == 1 )
2987 baspnt2_x = xloc + dx;
2988 baspnt2_y = yloc + dy;
2995 if( shape_type ==
"ARWLN1" && j == 0 )
2997 arwln_x = xloc + dx;
2998 arwln_y = yloc + dy;
3005 if( baspnt_count >= 2 )
3009 double dx =
std::abs( baspnt2_x - baspnt1_x );
3010 double dy =
std::abs( baspnt2_y - baspnt1_y );
3011 bool isHorizontal = dx > dy;
3030 dim.
points.push_back( pt1 );
3031 dim.
points.push_back( pt2 );
3036 for(
int t = 0; t < textCount; ++t )
3041 if( line[0] ==
'*' )
3047 std::istringstream tiss( line );
3048 double tx = 0.0, ty = 0.0;
3055 for(
int s = 0; s < skipLines; ++s )
3063 double theight = 0.0, twidth = 0.0;
3064 tiss >> trot >> tlayer >> theight >> twidth;
3087 if( !dim.
points.empty() )
3090 else if( type ==
"KEEPOUT" || type ==
"RESTRICTVIA" || type ==
"RESTRICTROUTE"
3091 || type ==
"RESTRICTAREA" || type ==
"PLACEMENT_KEEPOUT" )
3097 if( type ==
"KEEPOUT" || type ==
"RESTRICTAREA" )
3104 else if( type ==
"RESTRICTVIA" )
3111 else if( type ==
"RESTRICTROUTE" )
3118 else if( type ==
"PLACEMENT_KEEPOUT" )
3127 for(
int i = 0; i < pieces; ++i )
3132 if( line[0] ==
'*' )
3140 std::istringstream piss( line );
3141 std::string shape_type;
3144 int piece_flags = 0;
3146 std::string restrictions;
3147 piss >> shape_type >> corners >> width >> piece_flags >> level >> restrictions;
3150 keepout.
layers.push_back( level );
3156 if( !restrictions.empty() )
3159 bool has_restriction_codes =
false;
3161 for(
char c : restrictions )
3163 if( std::isalpha( c ) )
3165 has_restriction_codes =
true;
3170 if( has_restriction_codes )
3181 for(
char c : restrictions )
3222 if( shape_type ==
"KPTCIR" )
3225 double x1 = 0.0, y1 = 0.0, x2 = 0.0, y2 = 0.0;
3229 std::istringstream c1( line );
3233 if( corners >= 2 &&
readLine( aStream, line ) )
3235 std::istringstream c2( line );
3240 double cx = xloc + ( x1 + x2 ) / 2.0;
3241 double cy = yloc + ( y1 + y2 ) / 2.0;
3242 double radius = std::sqrt( ( x2 - x1 ) * ( x2 - x1 ) +
3243 ( y2 - y1 ) * ( y2 - y1 ) ) / 2.0;
3250 arc.start_angle = 0.0;
3251 arc.delta_angle = 360.0;
3258 for(
int j = 0; j < corners; ++j )
3263 if( line[0] ==
'*' )
3269 std::istringstream ciss( line );
3270 double dx = 0.0, dy = 0.0;
3275 int startAngleTenths = 0, deltaAngleTenths = 0;
3276 double bboxMinX = 0.0, bboxMinY = 0.0, bboxMaxX = 0.0, bboxMaxY = 0.0;
3278 if( ciss >> startAngleTenths >> deltaAngleTenths
3279 >> bboxMinX >> bboxMinY >> bboxMaxX >> bboxMaxY )
3281 double cx = ( bboxMinX + bboxMaxX ) / 2.0;
3282 double cy = ( bboxMinY + bboxMaxY ) / 2.0;
3283 double radius = ( bboxMaxX - bboxMinX ) / 2.0;
3284 double startAngle = startAngleTenths / 10.0;
3285 double deltaAngle = deltaAngleTenths / 10.0;
3287 double startAngleRad = startAngle *
M_PI / 180.0;
3288 double startX = cx +
radius * std::cos( startAngleRad );
3289 double startY = cy +
radius * std::sin( startAngleRad );
3291 double endAngleRad = ( startAngle + deltaAngle ) *
M_PI / 180.0;
3292 double endX = cx +
radius * std::cos( endAngleRad );
3293 double endY = cy +
radius * std::sin( endAngleRad );
3295 keepout.
outline.emplace_back( xloc + startX, yloc + startY );
3301 arc.start_angle = startAngle;
3302 arc.delta_angle = deltaAngle;
3304 keepout.
outline.emplace_back( xloc + endX, yloc + endY, arc );
3308 keepout.
outline.emplace_back( xloc + dx, yloc + dy );
3314 if( !keepout.
outline.empty() )
3317 else if( type ==
"COPPER" || type ==
"COPCUT" )
3323 for(
int i = 0; i < pieces; ++i )
3328 if( line[0] ==
'*' )
3337 std::istringstream piss( line );
3338 std::string shape_type;
3341 int piece_flags = 0;
3343 piss >> shape_type >> corners >> width >> piece_flags >> level;
3347 copper.
layer = level;
3348 copper.
width = width;
3351 copper.
filled = ( shape_type ==
"COPCLS" || shape_type ==
"COPCIR" );
3352 copper.
is_cutout = ( shape_type ==
"COPCUT" || shape_type ==
"COPCCO" ||
3353 shape_type ==
"CIRCUR" || type ==
"COPCUT" );
3356 if( shape_type ==
"COPCIR" || shape_type ==
"COPCCO" || shape_type ==
"CIRCUR" )
3359 double x1 = 0.0, y1 = 0.0, x2 = 0.0, y2 = 0.0;
3363 std::istringstream c1( line );
3367 if( corners >= 2 &&
readLine( aStream, line ) )
3369 std::istringstream c2( line );
3373 double cx = xloc + ( x1 + x2 ) / 2.0;
3374 double cy = yloc + ( y1 + y2 ) / 2.0;
3375 double radius = std::sqrt( ( x2 - x1 ) * ( x2 - x1 ) +
3376 ( y2 - y1 ) * ( y2 - y1 ) ) / 2.0;
3382 arc.start_angle = 0.0;
3383 arc.delta_angle = 360.0;
3390 for(
int j = 0; j < corners; ++j )
3395 if( line[0] ==
'*' )
3401 std::istringstream ciss( line );
3402 double dx = 0.0, dy = 0.0;
3407 int startAngleTenths = 0, deltaAngleTenths = 0;
3408 double bboxMinX = 0.0, bboxMinY = 0.0, bboxMaxX = 0.0, bboxMaxY = 0.0;
3410 if( ciss >> startAngleTenths >> deltaAngleTenths
3411 >> bboxMinX >> bboxMinY >> bboxMaxX >> bboxMaxY )
3413 double cx = ( bboxMinX + bboxMaxX ) / 2.0;
3414 double cy = ( bboxMinY + bboxMaxY ) / 2.0;
3415 double radius = ( bboxMaxX - bboxMinX ) / 2.0;
3416 double startAngle = startAngleTenths / 10.0;
3417 double deltaAngle = deltaAngleTenths / 10.0;
3419 double startAngleRad = startAngle *
M_PI / 180.0;
3420 double startX = cx +
radius * std::cos( startAngleRad );
3421 double startY = cy +
radius * std::sin( startAngleRad );
3423 double endAngleRad = ( startAngle + deltaAngle ) *
M_PI / 180.0;
3424 double endX = cx +
radius * std::cos( endAngleRad );
3425 double endY = cy +
radius * std::sin( endAngleRad );
3427 copper.
outline.emplace_back( xloc + startX, yloc + startY );
3433 arc.start_angle = startAngle;
3434 arc.delta_angle = deltaAngle;
3436 copper.
outline.emplace_back( xloc + endX, yloc + endY, arc );
3440 copper.
outline.emplace_back( xloc + dx, yloc + dy );
3449 else if( type ==
"LINES" )
3452 for(
int i = 0; i < pieces; ++i )
3457 if( line[0] ==
'*' )
3464 std::istringstream piss( line );
3465 std::string shape_type;
3468 int piece_flags = 0;
3470 piss >> shape_type >> corners >> width >> piece_flags >> level;
3474 graphic.
layer = level;
3475 graphic.
width = width;
3479 graphic.
closed = ( shape_type ==
"CLOSED" || shape_type ==
"CIRCLE" );
3481 if( shape_type ==
"CIRCLE" )
3484 double x1 = 0.0, y1 = 0.0, x2 = 0.0, y2 = 0.0;
3488 std::istringstream c1( line );
3492 if( corners >= 2 &&
readLine( aStream, line ) )
3494 std::istringstream c2( line );
3498 double cx = xloc + ( x1 + x2 ) / 2.0;
3499 double cy = yloc + ( y1 + y2 ) / 2.0;
3500 double radius = std::sqrt( ( x2 - x1 ) * ( x2 - x1 ) +
3501 ( y2 - y1 ) * ( y2 - y1 ) ) / 2.0;
3507 arc.start_angle = 0.0;
3508 arc.delta_angle = 360.0;
3515 for(
int j = 0; j < corners; ++j )
3520 if( line[0] ==
'*' )
3526 std::istringstream ciss( line );
3527 double dx = 0.0, dy = 0.0;
3531 int startAngleTenths = 0, deltaAngleTenths = 0;
3532 double bboxMinX = 0.0, bboxMinY = 0.0, bboxMaxX = 0.0, bboxMaxY = 0.0;
3534 if( ciss >> startAngleTenths >> deltaAngleTenths
3535 >> bboxMinX >> bboxMinY >> bboxMaxX >> bboxMaxY )
3537 double cx = ( bboxMinX + bboxMaxX ) / 2.0;
3538 double cy = ( bboxMinY + bboxMaxY ) / 2.0;
3539 double radius = ( bboxMaxX - bboxMinX ) / 2.0;
3540 double startAngle = startAngleTenths / 10.0;
3541 double deltaAngle = deltaAngleTenths / 10.0;
3543 double startAngleRad = startAngle *
M_PI / 180.0;
3544 double startX = cx +
radius * std::cos( startAngleRad );
3545 double startY = cy +
radius * std::sin( startAngleRad );
3547 double endAngleRad = ( startAngle + deltaAngle ) *
M_PI / 180.0;
3548 double endX = cx +
radius * std::cos( endAngleRad );
3549 double endY = cy +
radius * std::sin( endAngleRad );
3551 graphic.
points.emplace_back( xloc + startX, yloc + startY );
3557 arc.start_angle = startAngle;
3558 arc.delta_angle = deltaAngle;
3560 graphic.
points.emplace_back( xloc + endX, yloc + endY, arc );
3564 graphic.
points.emplace_back( xloc + dx, yloc + dy );
3569 if( !graphic.
points.empty() )
3576 for(
int i = 0; i < pieces; ++i )
3581 if( line[0] ==
'*' )
3587 std::istringstream piss( line );
3588 std::string shape_type;
3590 piss >> shape_type >> corners;
3592 for(
int j = 0; j < corners; ++j )
3597 if( line[0] ==
'*' )
3609 for(
int t = 0; t < textCount; ++t )
3614 if( line[0] ==
'*' )
3620 std::istringstream tiss( line );
3630 for(
int s = 0; s < skipLines; ++s )
3636 text.location.x += xloc;
3637 text.location.y += yloc;
3639 std::string mirrored;
3641 text.mirrored = ( mirrored ==
"M" );
3649 if( line[0] ==
'*' )
3655 size_t bracket_start = line.find(
'<' );
3656 size_t bracket_end = line.find(
'>' );
3658 if( bracket_start != std::string::npos && bracket_end != std::string::npos )
3661 line.substr( bracket_start + 1, bracket_end - bracket_start - 1 );
3664 std::istringstream fiss( line );
3665 std::string font_style_part;
3666 fiss >> font_style_part;
3668 size_t colon_pos = font_style_part.find(
':' );
3670 if( colon_pos != std::string::npos )
3671 text.font_style = font_style_part.substr( 0, colon_pos );
3673 text.font_style = font_style_part;
3680 if( line[0] ==
'*' )
3686 text.content = line;
3716 if( line[0] ==
'*' )
3726 if( line.rfind(
"G ", 0 ) == 0 && currentPartType )
3728 std::istringstream gss( line );
3729 std::string g_keyword;
3730 int gateSwap = 0, pinCount = 0;
3731 gss >> g_keyword >> gateSwap >> pinCount;
3735 currentPartType->
gates.push_back( gate );
3736 currentGate = ¤tPartType->
gates.back();
3741 if( line.rfind(
"SIGPIN", 0 ) == 0 && currentPartType )
3743 std::istringstream sss( line );
3744 std::string keyword;
3759 if( line.find(
'.' ) != std::string::npos && currentPartType )
3764 std::stringstream check_ss( line );
3765 std::string first_token;
3766 check_ss >> first_token;
3770 for(
char c : first_token )
3783 std::stringstream ss( line );
3786 while( ss >> token )
3789 std::vector<std::string> parts;
3793 while( ( pos = token.find(
'.', start ) ) != std::string::npos )
3795 parts.push_back( token.substr( start, pos - start ) );
3799 parts.push_back( token.substr( start ) );
3801 if( parts.size() >= 3 )
3807 bool isNumericSecond = !parts[1].empty() &&
3808 std::all_of( parts[1].begin(), parts[1].
end(), ::isdigit );
3810 if( currentGate && parts[2].size() == 1 && !isNumericSecond )
3817 if( !parts[2].
empty() )
3818 gpin.
elec_type = parsePinElecType( parts[2][0] );
3820 if( parts.size() >= 4 )
3823 currentGate->
pins.push_back( gpin );
3825 else if( isNumericSecond )
3840 if( line[0] ==
'{' && currentPartType )
3844 if( line.empty() || line[0] ==
'}' )
3847 if( line[0] ==
'*' )
3853 std::string attrName, attrValue;
3855 if( line[0] ==
'"' )
3857 size_t endQuote = line.find(
'"', 1 );
3859 if( endQuote != std::string::npos )
3861 attrName = line.substr( 1, endQuote - 1 );
3862 attrValue = line.substr( endQuote + 1 );
3867 std::istringstream attrSS( line );
3869 std::getline( attrSS >> std::ws, attrValue );
3872 if( !attrValue.empty() && attrValue[0] ==
' ' )
3873 attrValue = attrValue.substr( 1 );
3875 if( !attrName.empty() && !attrValue.empty() )
3876 currentPartType->
attributes[attrName] = attrValue;
3882 if( line[0] ==
'{' || line[0] ==
'}' )
3886 std::stringstream ss( line );
3887 std::string
name, decal;
3888 ss >>
name >> decal;
3890 if( !
name.empty() &&
name[0] !=
'G' )
3897 currentGate =
nullptr;
3910 if( line[0] ==
'*' )
3916 std::stringstream ss( line );
3917 std::string keyword;
3920 if( keyword ==
"TYPE" )
3922 std::string typename_val;
3923 std::getline( ss, typename_val );
3925 if( !typename_val.empty() && typename_val[0] ==
' ' )
3926 typename_val = typename_val.substr( 1 );
3929 block.
name = typename_val;
3933 else if( keyword ==
"TIMESTAMP" && currentBlock )
3939 else if( keyword ==
"PART_NAMING" && currentBlock )
3942 std::getline( ss, naming );
3944 if( !naming.empty() && naming[0] ==
' ' )
3945 naming = naming.substr( 1 );
3949 else if( keyword ==
"PART" && currentBlock )
3951 std::string partname;
3952 std::getline( ss, partname );
3954 if( !partname.empty() && partname[0] ==
' ' )
3955 partname = partname.substr( 1 );
3957 currentBlock->
part_names.push_back( partname );
3959 else if( keyword ==
"NET_NAMING" && currentBlock )
3962 std::getline( ss, naming );
3964 if( !naming.empty() && naming[0] ==
' ' )
3965 naming = naming.substr( 1 );
3969 else if( keyword ==
"NET" && currentBlock )
3972 std::string netname;
3975 std::getline( ss, netname );
3977 if( !netname.empty() && netname[0] ==
' ' )
3978 netname = netname.substr( 1 );
3981 net.
merge = ( merge_flag == 1 );
3983 currentBlock->
nets.push_back( net );
3985 else if( keyword ==
"REUSE" && currentBlock )
3990 std::string next_token;
3993 if( next_token ==
"PREFIX" || next_token ==
"SUFFIX" )
4000 else if( next_token ==
"START" || next_token ==
"INCREMENT" )
4007 else if( next_token ==
"NEXT" )
4013 if( next_token ==
"PREFIX" || next_token ==
"SUFFIX" )
4017 instance.
net_naming = next_token +
" " + param;
4019 else if( next_token ==
"START" || next_token ==
"INCREMENT" )
4023 instance.
net_naming = next_token +
" " + num;
4025 else if( next_token ==
"NEXT" )
4030 std::string glued_str;
4033 instance.
glued = ( glued_str ==
"Y" || glued_str ==
"YES" || glued_str ==
"1" );
4034 currentBlock->
instances.push_back( instance );
4043 CLUSTER* currentCluster =
nullptr;
4047 if( line[0] ==
'*' )
4053 std::stringstream ss( line );
4054 std::string firstToken;
4059 if( firstToken.empty() )
4063 bool isNumeric = !firstToken.empty() &&
4064 std::all_of( firstToken.begin(), firstToken.end(), ::isdigit );
4078 cluster.
name =
"Cluster_" + firstToken;
4083 else if( currentCluster )
4087 if( firstToken.find(
'.' ) != std::string::npos )
4095 currentCluster->
net_names.push_back( firstToken );
4103 if( item.find(
'.' ) != std::string::npos )
4106 currentCluster->
net_names.push_back( item );
4119 if( line[0] ==
'*' )
4127 std::stringstream ss( line );
4128 std::string
name, flags;
4129 double minlen = 0.0, maxlen = 0.0, lenincr = 0.0;
4131 std::string padstack, end_padstack;
4133 if( !( ss >>
name >> flags >> minlen >> maxlen >> lenincr >> lcount >> padstack ) )
4147 for(
char c : flags )
4153 case 'W': jumper.
wirebond =
true;
break;
4155 case 'G': jumper.
glued =
true;
break;
4161 for(
int i = 0; i < lcount; ++i )
4169 std::stringstream ss_attr( line );
4170 std::string visible_str, mirrored_str, right_reading_str;
4175 attr.
visible = ( visible_str ==
"VALUE" || visible_str ==
"FULL_NAME" ||
4176 visible_str ==
"NAME" || visible_str ==
"FULL_BOTH" ||
4177 visible_str ==
"BOTH" );
4178 attr.
mirrored = ( mirrored_str ==
"M" || mirrored_str ==
"1" );
4179 ss_attr >> right_reading_str;
4180 attr.
right_reading = ( right_reading_str ==
"Y" || right_reading_str ==
"ORTHO" );
4191 jumper.
labels.push_back( attr );
4205 if( line[0] ==
'*' )
4211 std::stringstream ss( line );
4223 ss >>
tp.x >>
tp.y >>
tp.side >>
tp.net_name >>
tp.symbol_name;
4225 if( !
tp.net_name.empty() )
4237 bool inClass =
false;
4241 if( line[0] ==
'*' )
4244 if( inClass && !currentClass.
name.empty() )
4251 std::stringstream ss( line );
4259 if( token ==
"CLASS" || token ==
"NETCLASS" )
4262 if( inClass && !currentClass.
name.empty() )
4267 ss >> currentClass.
name;
4270 else if( token ==
"CLEARANCE" && inClass )
4274 else if( token ==
"TRACKWIDTH" && inClass )
4278 else if( token ==
"VIASIZE" && inClass )
4282 else if( token ==
"VIADRILL" && inClass )
4286 else if( token ==
"DIFFPAIRGAP" && inClass )
4290 else if( token ==
"DIFFPAIRWIDTH" && inClass )
4294 else if( token ==
"NET" && inClass )
4297 std::string netName;
4300 if( !netName.empty() )
4301 currentClass.
net_names.push_back( netName );
4303 else if( !token.empty() && token[0] !=
'#' )
4306 if( !inClass || ( inClass && currentClass.
name.empty() ) )
4309 if( inClass && !currentClass.
name.empty() )
4313 currentClass.
name = token;
4320 if( inClass && !currentClass.
name.empty() )
4331 if( line[0] ==
'*' )
4337 std::stringstream ss( line );
4353 if( token ==
"DIFFPAIR" || token ==
"PAIR" )
4359 std::string posNet, negNet;
4360 ss >> posNet >> negNet;
4362 if( !posNet.empty() )
4365 if( !negNet.empty() )
4369 double gap = 0.0, width = 0.0;
4377 if( !dp.
name.empty() )
4392 else if( ( token ==
"WIDTH" || token ==
"TRACKWIDTH" ) && !
m_diff_pairs.empty() )
4404 int currentLayerNum = -1;
4406 bool inLayerBlock =
false;
4410 if( typeStr ==
"ROUTING" )
4412 else if( typeStr ==
"PLANE" )
4414 else if( typeStr ==
"MIXED" )
4416 else if( typeStr ==
"UNASSIGNED" )
4418 else if( typeStr ==
"SOLDER_MASK" )
4420 else if( typeStr ==
"PASTE_MASK" )
4422 else if( typeStr ==
"SILK_SCREEN" )
4424 else if( typeStr ==
"ASSEMBLY" )
4426 else if( typeStr ==
"DOCUMENTATION" )
4428 else if( typeStr ==
"DRILL" )
4439 if( line[0] ==
'*' )
4445 std::istringstream iss( line );
4460 if( inLayerBlock && braceDepth == 1 )
4462 if( currentLayerNum >= 0 )
4464 currentLayer.
number = currentLayerNum;
4474 inLayerBlock =
false;
4475 currentLayerNum = -1;
4479 if( braceDepth <= 0 )
4485 if( token ==
"LAYER" )
4490 if( !iss.fail() && layerNum >= 0 )
4493 currentLayerNum = layerNum;
4495 currentLayer.
number = layerNum;
4497 inLayerBlock =
true;
4500 else if( token ==
"LAYER_NAME" && inLayerBlock )
4504 std::getline( iss >> std::ws,
name );
4507 else if( token ==
"LAYER_TYPE" && inLayerBlock )
4509 std::string typeStr;
4511 currentLayer.
layer_type = parseLayerType( typeStr );
4513 else if( token ==
"LAYER_THICKNESS" && inLayerBlock )
4517 else if( token ==
"COPPER_THICKNESS" && inLayerBlock )
4521 else if( token ==
"DIELECTRIC" && inLayerBlock )
4543 bool inDifPair =
false;
4544 bool inNetClassData =
false;
4545 bool inNetClass =
false;
4546 bool inRuleSet =
false;
4547 bool inRuleSetFor =
false;
4548 bool inClearanceRule =
false;
4549 int netClassDataDepth = -1;
4550 int netClassDepth = -1;
4551 int ruleSetDepth = -1;
4552 int clearanceRuleDepth = -1;
4553 bool foundDefaultRules =
false;
4554 bool isDefaultRuleSet =
false;
4555 std::string ruleSetNetClass;
4565 if( line[0] ==
'*' && braceDepth == 0 )
4572 for(
char c : line )
4580 if( braceDepth == 0 && inDifPair )
4583 if( !currentDiffPair.
name.empty() )
4590 if( inNetClass && braceDepth <= netClassDepth )
4592 if( !currentNetClass.
name.empty() )
4599 if( inNetClassData && braceDepth <= netClassDataDepth )
4601 inNetClassData =
false;
4604 if( inClearanceRule && braceDepth < clearanceRuleDepth )
4606 inClearanceRule =
false;
4608 if( isDefaultRuleSet )
4611 == std::numeric_limits<double>::max() )
4620 == std::numeric_limits<double>::max() )
4626 foundDefaultRules =
true;
4630 if( inRuleSetFor && braceDepth < ruleSetDepth + 1 )
4631 inRuleSetFor =
false;
4633 if( inRuleSet && braceDepth < ruleSetDepth )
4636 isDefaultRuleSet =
false;
4637 ruleSetNetClass.clear();
4642 std::istringstream iss( line );
4648 if( token ==
"LAYER" )
4650 std::string secondToken;
4653 if( secondToken ==
"DATA" )
4660 if( token ==
"NET_CLASS" )
4662 std::string secondToken;
4665 if( secondToken ==
"DATA" )
4667 inNetClassData =
true;
4668 netClassDataDepth = braceDepth;
4670 else if( inNetClassData && !secondToken.empty() )
4672 if( inNetClass && !currentNetClass.
name.empty() )
4676 currentNetClass.
name = secondToken;
4678 netClassDepth = braceDepth;
4680 else if( inRuleSetFor && !secondToken.empty() )
4682 ruleSetNetClass = secondToken;
4685 else if( inNetClass && token ==
"NET" )
4687 std::string netName;
4690 if( !netName.empty() )
4691 currentNetClass.
net_names.push_back( netName );
4693 else if( token ==
"RULE_SET" )
4695 std::string ruleNum;
4699 ruleSetDepth = braceDepth;
4700 ruleSetNetClass.clear();
4701 isDefaultRuleSet = ( ruleNum ==
"(1)" && !foundDefaultRules );
4703 else if( inRuleSet && !inClearanceRule && token ==
"FOR" )
4705 inRuleSetFor =
true;
4707 else if( inRuleSet && token ==
"CLEARANCE_RULE" )
4709 inClearanceRule =
true;
4710 clearanceRuleDepth = braceDepth;
4712 if( isDefaultRuleSet )
4714 m_design_rules.default_clearance = std::numeric_limits<double>::max();
4715 m_design_rules.copper_edge_clearance = std::numeric_limits<double>::max();
4718 else if( inClearanceRule )
4723 if( !iss.fail() && val > 0.0 )
4725 if( isDefaultRuleSet )
4727 if( token ==
"MIN_TRACK_WIDTH" )
4731 else if( token ==
"REC_TRACK_WIDTH" )
4735 else if( token ==
"DRILL_TO_DRILL" )
4739 else if( token ==
"OUTLINE_TO_TRACK" || token ==
"OUTLINE_TO_VIA"
4740 || token ==
"OUTLINE_TO_PAD" || token ==
"OUTLINE_TO_COPPER"
4741 || token ==
"OUTLINE_TO_SMD" )
4746 else if( token.rfind(
"SAME_NET_", 0 ) == 0 || token ==
"BODY_TO_BODY"
4747 || token ==
"MAX_TRACK_WIDTH"
4748 || token.rfind(
"TEXT_TO_", 0 ) == 0
4749 || token.rfind(
"COPPER_TO_", 0 ) == 0 )
4755 else if( token ==
"TRACK_TO_TRACK" || token.rfind(
"VIA_TO_", 0 ) == 0
4756 || token.rfind(
"PAD_TO_", 0 ) == 0
4757 || token.rfind(
"SMD_TO_", 0 ) == 0
4758 || token.rfind(
"DRILL_TO_", 0 ) == 0 )
4764 else if( !ruleSetNetClass.empty() )
4768 if( nc.name == ruleSetNetClass )
4770 if( token ==
"REC_TRACK_WIDTH" )
4771 nc.track_width = val;
4772 else if( token ==
"TRACK_TO_TRACK" )
4781 else if( token ==
"DIF_PAIR" )
4784 if( inDifPair && !currentDiffPair.
name.empty() )
4788 iss >> currentDiffPair.
name;
4791 else if( inDifPair )
4793 if( token ==
"NET" )
4795 std::string netName;
4804 else if( token ==
"GAP" )
4806 iss >> currentDiffPair.
gap;
4808 else if( token ==
"WIDTH" )
4810 iss >> currentDiffPair.
width;
4812 else if( token ==
"CONNECTION" )
4818 else if( token ==
"ASSOCIATED" )
4821 std::string keyword, netName;
4822 iss >> keyword >> netName;
4824 if( keyword ==
"NET" )
4836 if( token ==
"PART" && !inDifPair && !inNetClass )
4838 std::string partName;
4841 if( !partName.empty() )
4844 int savedDepth = braceDepth;
4852 if( line[0] ==
'}' )
4855 if( line[0] ==
'{' )
4858 if( line[0] ==
'*' )
4865 std::string attrName, attrValue;
4867 if( line[0] ==
'"' )
4869 size_t endQuote = line.find(
'"', 1 );
4871 if( endQuote != std::string::npos )
4873 attrName = line.substr( 1, endQuote - 1 );
4874 attrValue = line.substr( endQuote + 1 );
4879 std::istringstream attrSS( line );
4881 std::getline( attrSS >> std::ws, attrValue );
4884 if( !attrValue.empty() && attrValue[0] ==
' ' )
4885 attrValue = attrValue.substr( 1 );
4887 if( !attrName.empty() && !attrValue.empty() )
4888 attrs[attrName] = attrValue;
4892 braceDepth = savedDepth;
4909 if(
m_design_rules.default_clearance == std::numeric_limits<double>::max() )
4912 if(
m_design_rules.copper_edge_clearance == std::numeric_limits<double>::max() )
4919 std::vector<LAYER_INFO> layers;
4923 if( layerCount < 1 )
4927 auto isCopperLayer = [&](
int num ) {
4928 return num >= 1 && num <= layerCount;
4932 auto getLayerDef = [&](
int num ) ->
const LAYER_INFO* {
4934 return it !=
m_layer_defs.end() ? &it->second :
nullptr;
4938 for(
int i = 1; i <= layerCount; ++i )
4944 layers.push_back( *parsed );
4952 info.is_copper =
true;
4953 info.required =
true;
4957 else if( i == layerCount )
4958 info.name =
"Bottom";
4960 info.name =
"Inner " + std::to_string( i - 1 );
4962 layers.push_back(
info );
4969 if( !isCopperLayer( num ) )
4971 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)
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)
std::vector< std::string > header
wxString result
Test unit parsing edge cases and error handling.