45 std::vector<std::string>
result;
47 size_t braceStart = aPattern.find(
'{' );
48 size_t braceEnd = aPattern.find(
'}' );
50 if( braceStart == std::string::npos || braceEnd == std::string::npos || braceEnd <= braceStart )
52 result.push_back( aPattern );
56 std::string prefix = aPattern.substr( 0, braceStart );
57 std::string suffix = ( braceEnd + 1 < aPattern.length() ) ? aPattern.substr( braceEnd + 1 ) :
"";
58 std::string range = aPattern.substr( braceStart + 1, braceEnd - braceStart - 1 );
60 size_t dashPos = range.find(
'-' );
62 if( dashPos == std::string::npos )
64 result.push_back( aPattern );
71 if( start == INT_MIN ||
end == INT_MIN )
73 result.push_back( aPattern );
77 static constexpr int MAX_EXPANSION = 10000;
81 wxLogWarning( wxT(
"PADS Import: shortcut range {%d-%d} exceeds limit, skipped" ),
83 result.push_back( aPattern );
87 for(
int i = start; i <=
end; ++i )
89 result.push_back( prefix + std::to_string( i ) + suffix );
106 std::ifstream file( aFileName.ToStdString() );
107 if( !file.is_open() )
109 throw std::runtime_error(
"Could not open file " + aFileName.ToStdString() );
117 throw std::runtime_error(
"Empty file" );
129 if( line.size() > 2 && line[0] ==
'*' && line.back() ==
'*' )
131 std::string
header = line.substr( 1, line.size() - 2 );
135 if(
header.find(
"LIBRARY-LINE-ITEMS" ) != std::string::npos ||
136 header.find(
"LIBRARY-LINE" ) != std::string::npos )
140 else if(
header.find(
"LIBRARY-SCH-DECALS" ) != std::string::npos )
144 else if(
header.find(
"LIBRARY-PCB-DECALS" ) != std::string::npos ||
145 header.find(
"LIBRARY-DECALS" ) != std::string::npos )
149 else if(
header.find(
"LIBRARY-PART-TYPES" ) != std::string::npos )
155 size_t v_pos =
header.rfind(
"-V" );
157 if( v_pos != std::string::npos )
165 else if( line.size() > 2 && line[0] ==
'!' )
169 size_t close_pos = line.find(
'!', 1 );
171 if( close_pos == std::string::npos )
172 close_pos = line.size();
174 std::string
header = line.substr( 1, close_pos - 1 );
177 std::vector<std::string> parts;
181 while( ( pos =
header.find(
'-', start ) ) != std::string::npos )
183 parts.push_back(
header.substr( start, pos - start ) );
187 parts.push_back(
header.substr( start ) );
190 if( parts.size() >= 4 )
197 if( parts.size() >= 5 )
200 if( parts.size() >= 6 )
203 else if( parts.size() >= 2 )
208 if( parts.size() >= 2 )
211 if( parts.size() >= 3 )
233 else if( line.find(
"BASIC" ) != std::string::npos )
240 if( line.empty() )
continue;
242 if( line.rfind(
"*PCB*", 0 ) == 0 )
246 else if( line.rfind(
"*PART*", 0 ) == 0 )
250 else if( line.rfind(
"*NET*", 0 ) == 0 )
254 else if( line.rfind(
"*ROUTE*", 0 ) == 0 )
258 else if( line.rfind(
"*TEXT*", 0 ) == 0 )
262 else if( line.rfind(
"*BOARD*", 0 ) == 0 )
266 else if( line.rfind(
"*LINES*", 0 ) == 0 )
270 else if( line.rfind(
"*VIA*", 0 ) == 0 )
274 else if( line.rfind(
"*POUR*", 0 ) == 0 )
278 else if( line.rfind(
"*PARTDECAL*", 0 ) == 0 )
282 else if( line.rfind(
"*PARTTYPE*", 0 ) == 0 )
286 else if( line.rfind(
"*REUSE*", 0 ) == 0 )
290 else if( line.rfind(
"*CLUSTER*", 0 ) == 0 )
294 else if( line.rfind(
"*JUMPER*", 0 ) == 0 )
298 else if( line.rfind(
"*TESTPOINT*", 0 ) == 0 )
302 else if( line.rfind(
"*NETCLASS*", 0 ) == 0 || line.rfind(
"*NETDEF*", 0 ) == 0 )
306 else if( line.rfind(
"*DIFFPAIR*", 0 ) == 0 || line.rfind(
"*DIFFPAIRS*", 0 ) == 0 )
310 else if( line.rfind(
"LAYER MILS", 0 ) == 0 || line.rfind(
"LAYER METRIC", 0 ) == 0 )
314 else if( line.rfind(
"*MISC*", 0 ) == 0 )
330 while( std::getline( aStream, aLine ) )
333 aLine.erase( 0, aLine.find_first_not_of(
" \t\r\n" ) );
334 aLine.erase( aLine.find_last_not_of(
" \t\r\n" ) + 1 );
336 if( aLine.empty() )
continue;
337 if( aLine.rfind(
"*REMARK*", 0 ) == 0 )
continue;
359 std::istringstream iss( line );
363 if( token ==
"UNITS" )
372 else if( token ==
"USERGRID" )
376 else if( token ==
"MAXIMUMLAYER" )
380 else if( token ==
"ORIGIN" )
384 else if( token ==
"THERLINEWID" )
388 else if( token ==
"THERSMDWID" )
392 else if( token ==
"THERFLAGS" )
394 std::string flags_str;
399 m_parameters.thermal_flags = std::stoi( flags_str,
nullptr, 0 );
401 catch(
const std::exception& )
406 else if( token ==
"DRLOVERSIZE" )
410 else if( token ==
"VIAPSHVIA" )
414 else if( token ==
"STMINCLEAR" )
418 else if( token ==
"STMINSPOKES" )
422 else if( token ==
"MINCLEAR" )
426 else if( token ==
"DEFAULTCLEAR" )
430 else if( token ==
"MINTRACKWID" )
434 else if( token ==
"DEFAULTTRACKWID" )
438 else if( token ==
"MINVIASIZE" )
442 else if( token ==
"DEFAULTVIASIZE" )
446 else if( token ==
"MINVIADRILL" )
450 else if( token ==
"DEFAULTVIADRILL" )
454 else if( token ==
"HOLEHOLE" )
458 else if( token ==
"SILKCLEAR" )
462 else if( token ==
"MASKCLEAR" )
474 if( line.find(
"*REMARK*" ) == 0 )
484 if( line.rfind(
"}", 0 ) == 0 ||
485 line.rfind(
"{", 0 ) == 0 )
490 std::istringstream iss( line );
495 std::string name_token, parttype_string;
506 bool is_shortcut = ( expanded_names.size() > 1 );
507 part.
name = expanded_names[0];
511 size_t at_pos = parttype_string.find(
'@' );
513 if( at_pos != std::string::npos )
516 part.
part_type = parttype_string.substr( 0, at_pos );
517 part.
decal = parttype_string.substr( at_pos + 1 );
526 size_t colon_pos = 0;
529 while( ( colon_pos = parttype_string.find(
':', pos ) ) != std::string::npos )
531 std::string decal_name = parttype_string.substr( pos, colon_pos - pos );
535 part.
decal = decal_name;
547 std::string last_decal = parttype_string.substr( pos );
551 part.
decal = last_decal;
560 std::vector<std::string> tokens;
562 while( iss >> token )
564 tokens.push_back( token );
574 for(
size_t i = 0; i < tokens.size(); ++i )
576 const std::string& t = tokens[i];
597 if( i == tokens.size() - 1 )
602 labels = std::stoi( t, &pos );
604 if( pos != t.length() )
607 catch(
const std::exception& )
618 if( line.find(
".REUSE." ) == 0 )
620 std::istringstream riss( line );
621 std::string reuse_keyword;
630 for(
int i = 0; i < labels; ++i )
633 if( !
readLine( aStream, line ) )
break;
635 std::stringstream iss_attr( line );
636 std::string visible_str;
637 std::string mirrored_str;
638 std::string right_reading_str;
644 attr.
visible = ( visible_str ==
"VALUE" || visible_str ==
"FULL_NAME"
645 || visible_str ==
"NAME" || visible_str ==
"FULL_BOTH"
646 || visible_str ==
"BOTH" );
647 attr.
mirrored = ( mirrored_str ==
"M" );
648 iss_attr >> right_reading_str;
649 attr.
right_reading = ( right_reading_str ==
"Y" || right_reading_str ==
"ORTHO" );
653 if( !
readLine( aStream, line ) )
break;
657 if( !
readLine( aStream, line ) )
break;
670 for(
size_t i = 1; i < expanded_names.size(); ++i )
672 PART additional_part = part;
673 additional_part.
name = expanded_names[i];
674 m_parts.push_back( additional_part );
687 NET* current_net =
nullptr;
690 auto parsePinToken = [](
const std::string& token,
NET_PIN&
pin ) ->
bool
692 size_t dot_pos = token.find(
'.' );
694 if( dot_pos == std::string::npos )
697 pin.ref_des = token.substr( 0, dot_pos );
698 pin.pin_name = token.substr( dot_pos + 1 );
704 auto expandShortcutPin = [](
const std::string& token ) -> std::vector<std::string>
706 std::vector<std::string> results;
709 if( token.find(
'{' ) == std::string::npos )
711 results.push_back( token );
722 bool is_range =
false;
725 std::vector<RangePart> parts;
727 std::string current_prefix;
729 while( pos < token.size() )
731 if( token[pos] ==
'{' )
733 size_t close_pos = token.find(
'}', pos );
735 if( close_pos == std::string::npos )
738 results.push_back( token );
742 std::string range_str = token.substr( pos + 1, close_pos - pos - 1 );
743 size_t dash_pos = range_str.find(
'-' );
745 if( dash_pos != std::string::npos )
748 part.prefix = current_prefix;
749 part.is_range =
true;
752 INT_MIN,
"net range" );
754 INT_MIN,
"net range" );
756 if( part.start == INT_MIN || part.end == INT_MIN )
758 results.push_back( token );
762 parts.push_back( part );
763 current_prefix.clear();
768 current_prefix += range_str;
775 current_prefix += token[pos];
781 if( !current_prefix.empty() || parts.empty() )
783 RangePart final_part;
784 final_part.prefix = current_prefix;
785 final_part.is_range =
false;
786 final_part.start = 0;
788 parts.push_back( final_part );
793 results.push_back(
"" );
795 for(
const auto& part : parts )
797 std::vector<std::string> new_results;
801 for(
const auto& base : results )
803 int step = ( part.start <= part.end ) ? 1 : -1;
805 for(
int i = part.start; step > 0 ? i <= part.end : i >= part.end; i += step )
807 new_results.push_back( base + part.prefix + std::to_string( i ) );
813 for(
const auto& base : results )
815 new_results.push_back( base + part.prefix );
819 results = std::move( new_results );
833 std::istringstream iss( line );
837 if( token ==
"SIGNAL" )
842 current_net = &
m_nets.back();
845 std::string pin_token;
847 while( iss >> pin_token )
850 if( pin_token ==
".REUSE." )
853 std::string instance, rsignal;
855 if( ( iss >> instance >> rsignal ) && !current_net->
pins.empty() )
857 current_net->
pins.back().reuse_instance = instance;
858 current_net->
pins.back().reuse_signal = rsignal;
865 for(
const auto& expanded : expandShortcutPin( pin_token ) )
869 if( parsePinToken( expanded,
pin ) )
870 current_net->
pins.push_back(
pin );
882 if( token ==
".REUSE." )
884 std::string instance, rsignal;
886 if( ( iss >> instance >> rsignal ) && !current_net->
pins.empty() )
888 current_net->
pins.back().reuse_instance = instance;
889 current_net->
pins.back().reuse_signal = rsignal;
896 for(
const auto& expanded : expandShortcutPin( token ) )
900 if( parsePinToken( expanded,
pin ) )
901 current_net->
pins.push_back(
pin );
904 }
while( iss >> token );
922 std::stringstream iss( line );
927 if( !( iss >>
name >> drill >> stacklines ) )
935 int drill_start_val = 0;
936 int drill_end_val = 0;
938 if( iss >> drill_start_val >> drill_end_val )
944 int min_layer = INT_MAX;
945 int max_layer = INT_MIN;
947 for(
int i = 0; i < stacklines; ++i )
952 std::stringstream iss2( line );
957 if( !( iss2 >> level >> size >> shape ) )
961 layer_data.
layer = level;
962 layer_data.
shape = shape;
963 layer_data.
sizeA = size;
967 if( shape ==
"R" || shape ==
"S" )
973 if( shape ==
"S" && ( iss2 >> corner ) )
986 else if( shape ==
"RA" || shape ==
"SA" )
991 else if( shape ==
"A" )
999 else if( shape ==
"OF" )
1002 double ori = 0, length = 0, offset = 0;
1004 if( iss2 >> ori >> length >> offset )
1007 layer_data.
sizeB = length;
1011 else if( shape ==
"RF" )
1015 double ori = 0, length = 0, offset = 0;
1017 if( iss2 >> ori >> length >> offset )
1020 layer_data.
sizeB = length;
1024 else if( shape ==
"RT" || shape ==
"ST" )
1027 double ori = 0, intd = 0, spkwid = 0;
1030 if( iss2 >> ori >> intd >> spkwid >> spknum )
1038 else if( shape ==
"O" || shape ==
"OC" )
1044 else if( shape ==
"RC" )
1048 double ori = 0, length = 0, offset = 0, corner = 0;
1050 if( iss2 >> ori >> length >> offset )
1053 layer_data.
sizeB = length;
1056 if( iss2 >> corner )
1071 def.
stack.push_back( layer_data );
1076 int effective_layer = level;
1079 effective_layer = 1;
1080 else if( level == -1 )
1083 bool is_copper = ( effective_layer >= 1
1088 if( size > def.
size )
1091 if( effective_layer < min_layer )
1092 min_layer = effective_layer;
1094 if( effective_layer > max_layer )
1095 max_layer = effective_layer;
1101 else if( level == 28 )
1106 if( min_layer <= max_layer )
1112 bool starts_at_surface = ( min_layer == 1 || max_layer == layer_count );
1113 bool ends_at_surface = ( max_layer == layer_count || min_layer == 1 );
1114 bool is_full_span = ( min_layer == 1 && max_layer == layer_count );
1115 int span = max_layer - min_layer;
1121 else if( span == 1 && ( min_layer == 1 || max_layer == layer_count ) )
1125 else if( starts_at_surface || ends_at_surface )
1149 if( line[0] ==
'*' )
1157 std::stringstream iss( line );
1158 std::string
name, type;
1159 double x = 0.0, y = 0.0;
1160 int pieces = 0, flags = 0;
1162 if( !( iss >>
name >> type >> x >> y >> pieces >> flags ) )
1165 std::string owner, signame;
1166 double hatchgrid = 0.0, hatchrad = 0.0;
1169 if( iss >> owner >> signame )
1171 iss >> hatchgrid >> hatchrad >> priority;
1174 for(
int i = 0; i < pieces; ++i )
1181 std::stringstream iss2( line );
1182 std::string poly_type;
1183 int corners = 0, arcs = 0;
1187 if( !( iss2 >> poly_type >> corners >> arcs >> width >> level ) )
1196 pour.
is_cutout = ( poly_type ==
"POCUT" || poly_type ==
"CUTOUT"
1197 || poly_type ==
"CIRCUT" );
1205 if( type ==
"HATOUT" )
1209 else if( type ==
"VOIDOUT" )
1214 else if( type ==
"PADTHERM" )
1218 else if( type ==
"VIATHERM" )
1224 if( poly_type ==
"CIRCLE" || poly_type ==
"CIRCUT" )
1231 std::stringstream iss3( line );
1232 double cx = 0.0, cy = 0.0,
radius = 0.0;
1234 if( iss3 >> cx >> cy >>
radius )
1241 arc.start_angle = 0.0;
1242 arc.delta_angle = 360.0;
1243 pour.
points.emplace_back( x + cx +
radius, y + cy, arc );
1246 else if( poly_type ==
"SEG" )
1249 for(
int j = 0; j < corners; ++j )
1254 std::stringstream iss3( line );
1255 double px = 0.0, py = 0.0;
1257 if( iss3 >> px >> py )
1259 pour.
points.emplace_back( x + px, y + py );
1271 int totalLines = corners + arcs;
1272 bool nextIsArcEndpoint =
false;
1275 for(
int j = 0; j < totalLines; ++j )
1280 std::stringstream iss3( line );
1281 double px = 0.0, py = 0.0;
1283 if( !( iss3 >> px >> py ) )
1286 int angle1 = 0, angle2 = 0;
1288 if( iss3 >> angle1 >> angle2 )
1294 pendingArc.
cx = x + px;
1295 pendingArc.cy = y + py;
1296 pendingArc.start_angle = angle1 / 10.0;
1297 pendingArc.delta_angle = angle2 / 10.0;
1299 if( !pour.
points.empty() )
1301 double dx = pour.
points.back().x - pendingArc.cx;
1302 double dy = pour.
points.back().y - pendingArc.cy;
1303 pendingArc.radius = std::sqrt( dx * dx + dy * dy );
1306 nextIsArcEndpoint =
true;
1308 else if( nextIsArcEndpoint )
1310 if( pendingArc.radius == 0.0 )
1312 double dx = ( x + px ) - pendingArc.cx;
1313 double dy = ( y + py ) - pendingArc.cy;
1314 pendingArc.radius = std::sqrt( dx * dx + dy * dy );
1317 pour.
points.emplace_back( x + px, y + py, pendingArc );
1318 nextIsArcEndpoint =
false;
1322 pour.
points.emplace_back( x + px, y + py );
1337 if( line[0] ==
'*' )
1344 std::stringstream iss( line );
1345 std::string
name, units;
1346 double orix = 0.0, oriy = 0.0;
1347 int pieces = 0, terminals = 0, stacks = 0, text_cnt = 0, labels = 0;
1349 if( !( iss >>
name >> units >> orix >> oriy >> pieces >> terminals >> stacks >> text_cnt >> labels ) )
1354 decal.
units = units;
1357 for(
int i = 0; i < pieces; ++i )
1359 if( !
readLine( aStream, line ) )
break;
1362 std::stringstream iss2( line );
1368 if( !( iss2 >> type >> corners >> width ) )
1401 decal.
items.push_back( item );
1407 if( type.find(
"COP" ) == 0 )
1409 std::string remaining;
1410 std::getline( iss2, remaining );
1413 std::istringstream rem_ss( remaining );
1414 int pinnum_val = -1;
1416 if( rem_ss >> pinnum_val )
1417 item.
pinnum = pinnum_val;
1421 if( type.find(
"KPT" ) == 0 )
1423 std::string restrictions;
1425 if( iss2 >> restrictions )
1429 for(
int j = 0; j < corners; ++j )
1434 std::stringstream iss3( line );
1435 double px = 0.0, py = 0.0;
1437 if( !( iss3 >> px >> py ) )
1443 int startAngleTenths = 0, deltaAngleTenths = 0;
1444 double bboxMinX = 0.0, bboxMinY = 0.0, bboxMaxX = 0.0, bboxMaxY = 0.0;
1446 if( iss3 >> startAngleTenths >> deltaAngleTenths
1447 >> bboxMinX >> bboxMinY >> bboxMaxX >> bboxMaxY )
1449 double cx = ( bboxMinX + bboxMaxX ) / 2.0;
1450 double cy = ( bboxMinY + bboxMaxY ) / 2.0;
1451 double radius = ( bboxMaxX - bboxMinX ) / 2.0;
1452 double startAngle = startAngleTenths / 10.0;
1453 double deltaAngle = deltaAngleTenths / 10.0;
1456 double startAngleRad = startAngle *
M_PI / 180.0;
1457 double startX = cx +
radius * std::cos( startAngleRad );
1458 double startY = cy +
radius * std::sin( startAngleRad );
1461 double endAngleRad = ( startAngle + deltaAngle ) *
M_PI / 180.0;
1462 double endX = cx +
radius * std::cos( endAngleRad );
1463 double endY = cy +
radius * std::sin( endAngleRad );
1466 item.
points.emplace_back( startX, startY );
1472 arc.start_angle = startAngle;
1473 arc.delta_angle = deltaAngle;
1476 item.
points.emplace_back( endX, endY, arc );
1480 item.
points.emplace_back( px, py );
1484 decal.
items.push_back( item );
1500 for(
int i = 0; i < text_cnt + labels; ++i )
1502 std::string line1, line2, line3;
1503 if( !
readLine( aStream, line1 ) )
break;
1504 if( !
readLine( aStream, line2 ) )
break;
1505 if( !
readLine( aStream, line3 ) )
break;
1509 std::stringstream ss( line1 );
1510 std::string type_token;
1514 std::string mirrored_str, right_reading_str;
1519 attr.
visible = ( type_token ==
"VALUE" || type_token ==
"FULL_NAME"
1520 || type_token ==
"NAME" || type_token ==
"FULL_BOTH"
1521 || type_token ==
"BOTH" );
1522 attr.
mirrored = ( mirrored_str ==
"M" );
1523 ss >> right_reading_str;
1524 attr.
right_reading = ( right_reading_str ==
"Y" || right_reading_str ==
"ORTHO" );
1538 for(
int i = 0; i < terminals; ++i )
1540 if( !
readLine( aStream, line ) )
break;
1543 size_t t_pos = line.find(
'T' );
1544 if( t_pos != std::string::npos )
1549 std::stringstream iss_t( line );
1551 double nmx = 0.0, nmy = 0.0;
1553 if( iss_t >> term.
x >> term.
y >> nmx >> nmy >> term.
name )
1563 for(
int i = 0; i < stacks; ++i )
1568 std::stringstream iss_pad( line );
1571 int stack_lines = 0;
1572 iss_pad >> token >> pin_idx >> stack_lines;
1574 if( token !=
"PAD" )
1578 std::string plated_token;
1579 bool default_plated =
true;
1580 double header_drill = 0.0;
1582 if( iss_pad >> plated_token )
1584 if( plated_token ==
"P" )
1585 default_plated =
true;
1586 else if( plated_token ==
"N" )
1587 default_plated =
false;
1595 double header_slot_ori = 0.0;
1596 double header_slot_len = 0.0;
1597 double header_slot_off = 0.0;
1599 if( iss_pad >> header_slot_ori >> header_slot_len >> header_slot_off )
1604 std::vector<PAD_STACK_LAYER> stack;
1606 for(
int j = 0; j < stack_lines; ++j )
1611 std::stringstream line_ss( line );
1617 if( !( line_ss >> layer >> size >> shape ) )
1621 layer_data.
layer = layer;
1622 layer_data.
sizeA = size;
1623 layer_data.
sizeB = size;
1624 layer_data.
shape = shape;
1625 layer_data.
plated = default_plated;
1626 layer_data.
drill = header_drill;
1637 else if( shape ==
"S" )
1641 double corner = 0.0;
1643 if( line_ss >> corner )
1656 else if( shape ==
"RA" || shape ==
"SA" )
1661 else if( shape ==
"A" )
1666 if( line_ss >> intd )
1669 else if( shape ==
"OF" )
1672 double ori = 0.0, length = 0.0, offset = 0.0;
1674 if( line_ss >> ori >> length >> offset )
1677 layer_data.
sizeB = length;
1681 else if( shape ==
"RF" )
1685 double ori = 0.0, length = 0.0, offset = 0.0;
1687 if( line_ss >> ori >> length >> offset )
1690 layer_data.
sizeB = length;
1693 double corner = 0.0;
1695 if( line_ss >> corner )
1709 else if( shape ==
"RT" || shape ==
"ST" )
1712 double ori = 0.0, outsize = 0.0, spkwid = 0.0;
1715 if( line_ss >> ori >> outsize >> spkwid >> spknum )
1723 else if( shape ==
"O" || shape ==
"OC" )
1729 else if( shape ==
"RC" )
1733 double ori = 0.0, length = 0.0, offset = 0.0, corner = 0.0;
1735 if( line_ss >> ori >> length >> offset )
1738 layer_data.
sizeB = length;
1741 if( line_ss >> corner )
1758 std::vector<std::string> remaining;
1759 std::string token_rem;
1761 while( line_ss >> token_rem )
1762 remaining.push_back( token_rem );
1765 if( !remaining.empty() )
1771 -1.0,
"pad layer drill" );
1773 if( drill_val >= 0.0 )
1775 layer_data.
drill = drill_val;
1780 if( idx < remaining.size() )
1782 if( remaining[idx] ==
"P" || remaining[idx] ==
"Y" )
1784 layer_data.
plated =
true;
1787 else if( remaining[idx] ==
"N" )
1789 layer_data.
plated =
false;
1795 if( idx + 2 < remaining.size() )
1806 stack.push_back( layer_data );
1819 ROUTE* current_route =
nullptr;
1820 TRACK current_track;
1821 bool in_track =
false;
1822 bool prev_is_plane_connection =
false;
1824 int last_plane_connection_layer = 0;
1825 double last_plane_connection_width = 0;
1826 bool last_plane_on_copper =
false;
1827 std::string default_via_name;
1831 if( line[0] ==
'*' )
1833 if( line.rfind(
"*SIGNAL*", 0 ) == 0 )
1835 if( in_track && current_route )
1837 current_route->
tracks.push_back( current_track );
1838 current_track.
points.clear();
1842 prev_is_plane_connection =
false;
1844 std::istringstream iss( line );
1848 std::string net_name;
1852 default_via_name.clear();
1854 while( iss >> token )
1856 if( !token.empty() && token.back() ==
';' )
1860 default_via_name = token;
1865 current_route->
net_name = net_name;
1876 if( !isdigit( line[0] ) && line[0] !=
'-' && line[0] !=
'+' )
1878 if( in_track && current_route )
1880 current_route->
tracks.push_back( current_track );
1881 current_track.
points.clear();
1885 prev_is_plane_connection =
false;
1890 std::istringstream pin_iss( line );
1891 std::string pin_token;
1893 while( pin_iss >> pin_token )
1895 size_t dot_pos = pin_token.find(
'.' );
1897 if( dot_pos != std::string::npos )
1900 pin.ref_des = pin_token.substr( 0, dot_pos );
1901 pin.pin_name = pin_token.substr( dot_pos + 1 );
1906 for(
const auto& existing : current_route->
pins )
1908 if( existing.ref_des ==
pin.ref_des &&
1909 existing.pin_name ==
pin.pin_name )
1917 current_route->
pins.push_back(
pin );
1925 std::istringstream iss( line );
1930 iss >> pt.
x >> pt.
y >> layer >> width >> flags;
1942 std::string via_name;
1943 std::string arc_dir;
1949 bool is_unrouted = ( layer == 0 );
1950 bool is_plane_connection = is_unrouted;
1953 bool has_teardrop =
false;
1954 bool has_jumper =
false;
1955 bool has_power =
false;
1957 while( iss >> token )
1960 if( token ==
"CW" || token ==
"CCW" )
1969 if( token ==
"POWER" )
1979 if( token ==
"THERMAL" )
1990 if( token ==
"TEARDROP" )
1992 has_teardrop =
true;
1993 std::string td_token;
1995 while( iss >> td_token )
1997 if( td_token ==
"P" )
2003 std::streampos pos = iss.tellg();
2006 if( iss >> td_flags )
2016 else if( td_token ==
"N" )
2021 std::streampos pos = iss.tellg();
2024 if( iss >> td_flags )
2038 if( td_token ==
"CW" || td_token ==
"CCW" )
2040 else if( td_token ==
"POWER" )
2045 via_name = td_token;
2047 else if( td_token ==
"THERMAL" )
2050 via_name = td_token;
2061 std::streampos pos = iss.tellg();
2062 std::string jumper_flag;
2064 if( iss >> jumper_flag )
2066 if( jumper_flag ==
"S" || jumper_flag ==
"E" )
2069 jumper.
name = token;
2070 jumper.
is_start = ( jumper_flag ==
"S" );
2089 if( token ==
"REUSE" || token ==
".REUSE." )
2092 std::string instance;
2100 if( !arc_dir.empty() )
2116 int effective_layer = layer;
2117 bool is_pad_connection = ( layer == 65 );
2121 if( is_unrouted && in_track )
2122 effective_layer = current_track.
layer;
2127 if( !via_name.empty() && current_route )
2130 via.name = via_name;
2131 via.location = { pt.
x, pt.
y };
2132 current_route->
vias.push_back(
via );
2140 if( has_power && via_name.empty() && !is_unrouted && !is_pad_connection && current_route )
2144 if( !default_via_name.empty() )
2145 implicit_via.
name = default_via_name;
2150 current_route->
vias.push_back( implicit_via );
2154 if( has_teardrop && current_route )
2156 current_route->
teardrops.push_back( teardrop );
2160 if( has_jumper && current_route )
2162 current_route->
jumpers.push_back( jumper );
2168 if( is_plane_connection && prev_is_plane_connection )
2177 last_plane_connection_pt = pt;
2178 last_plane_connection_layer = effective_layer;
2179 last_plane_connection_width = width;
2180 last_plane_on_copper =
true;
2183 prev_is_plane_connection =
true;
2187 if( is_plane_connection && !prev_is_plane_connection )
2193 current_track.
points.push_back( pt );
2195 if( current_route && current_track.
points.size() > 1 )
2196 current_route->
tracks.push_back( current_track );
2198 current_track.
points.clear();
2205 last_plane_on_copper = !is_unrouted;
2207 if( last_plane_on_copper )
2209 last_plane_connection_pt = pt;
2210 last_plane_connection_layer = effective_layer;
2211 last_plane_connection_width = width;
2214 prev_is_plane_connection =
true;
2218 if( !is_plane_connection && prev_is_plane_connection )
2222 if( in_track && current_route && current_track.
points.size() > 1 )
2223 current_route->
tracks.push_back( current_track );
2225 prev_is_plane_connection =
false;
2227 if( is_pad_connection )
2233 current_track.
points.clear();
2235 if( last_plane_on_copper && last_plane_connection_layer == effective_layer )
2237 current_track.
layer = effective_layer;
2238 current_track.
width = std::max( width, last_plane_connection_width );
2239 current_track.
points.push_back( last_plane_connection_pt );
2240 current_track.
points.push_back( pt );
2246 if( !has_power && via_name.empty() && current_route && last_plane_on_copper &&
2247 std::abs( pt.
x - last_plane_connection_pt.
x ) < 0.001 &&
2248 std::abs( pt.
y - last_plane_connection_pt.
y ) < 0.001 )
2252 if( !default_via_name.empty() )
2253 implicit_via.
name = default_via_name;
2258 current_route->
vias.push_back( implicit_via );
2261 current_track.
layer = effective_layer;
2262 current_track.
width = width;
2263 current_track.
points.push_back( pt );
2266 last_plane_on_copper =
false;
2273 if( is_pad_connection )
2275 if( in_track && !current_track.
points.empty() )
2277 current_track.
points.push_back( pt );
2279 if( current_route && current_track.
points.size() > 1 )
2280 current_route->
tracks.push_back( current_track );
2282 current_track.
points.clear();
2290 prev_is_plane_connection =
false;
2294 current_track.
layer = effective_layer;
2295 current_track.
width = width;
2296 current_track.
points.clear();
2297 current_track.
points.push_back( pt );
2302 bool layer_changed = ( effective_layer != current_track.
layer );
2303 bool width_changed = (
std::abs( width - current_track.
width ) > 0.001 );
2305 if( layer_changed || width_changed )
2308 bool connect =
true;
2310 if( layer_changed && via_name.empty() )
2312 bool same_location =
2313 ( pt.
x == current_track.
points.back().x &&
2314 pt.
y == current_track.
points.back().y );
2320 if( !has_power && current_route )
2324 default_via_name.empty() ?
"STANDARDVIA" : default_via_name;
2326 current_route->
vias.push_back( implicit_via );
2329 else if( !has_power )
2339 current_track.
points.push_back( pt );
2343 current_route->
tracks.push_back( current_track );
2348 current_track.
layer = effective_layer;
2349 current_track.
width = width;
2350 current_track.
points.clear();
2351 current_track.
points.push_back( prev_pt );
2355 current_track.
points.push_back( pt );
2360 if( in_track && current_route )
2362 current_route->
tracks.push_back( current_track );
2372 if( line[0] ==
'*' )
2381 std::istringstream iss( line );
2390 std::string mirrored;
2392 text.mirrored = ( mirrored ==
"M" );
2402 if( token ==
".REUSE." )
2404 iss >>
text.reuse_instance;
2410 if( iss >> token && token ==
".REUSE." )
2412 iss >>
text.reuse_instance;
2421 std::istringstream fiss( line );
2422 std::string font_style_part;
2424 fiss >> font_style_part;
2426 size_t colon_pos = font_style_part.find(
':' );
2428 if( colon_pos != std::string::npos )
2430 text.font_style = font_style_part.substr( 0, colon_pos );
2431 std::string remaining = font_style_part.substr( colon_pos + 1 );
2433 size_t second_colon = remaining.find(
':' );
2435 if( second_colon != std::string::npos )
2438 remaining.substr( 0, second_colon ), 0.0,
"font height" );
2440 remaining.substr( second_colon + 1 ), 0.0,
"font descent" );
2449 text.font_style = font_style_part;
2453 size_t bracket_start = line.find(
'<' );
2454 size_t bracket_end = line.find(
'>' );
2456 if( bracket_start != std::string::npos && bracket_end != std::string::npos )
2458 text.font_face = line.substr( bracket_start + 1, bracket_end - bracket_start - 1 );
2463 std::getline( fiss, rest );
2465 if( !rest.empty() && rest[0] ==
' ' )
2466 rest = rest.substr( 1 );
2468 text.font_face = rest;
2478 while( ( pos = line.find(
"\\n", pos ) ) != std::string::npos )
2480 line.replace( pos, 2,
"\n" );
2486 std::replace( line.begin(), line.end(),
'_',
'\n' );
2488 text.content = line;
2502 if( line[0] ==
'*' )
2508 std::istringstream iss( line );
2509 std::string
name, type;
2510 double xloc = 0.0, yloc = 0.0;
2512 iss >>
name >> type >> xloc >> yloc >> pieces;
2515 for(
int i = 0; i < pieces; ++i )
2520 if( line[0] ==
'*' )
2526 std::istringstream piss( line );
2527 std::string shape_type;
2530 int linestyle = 0, level = 0;
2531 piss >> shape_type >> corners >> width >> linestyle >> level;
2534 if( shape_type ==
"CLOSED" || shape_type ==
"OPEN" || shape_type ==
"BRDCLS" )
2538 polyline.
width = width;
2539 polyline.
closed = ( shape_type ==
"CLOSED" || shape_type ==
"BRDCLS" );
2541 for(
int j = 0; j < corners; ++j )
2546 if( line[0] ==
'*' )
2552 std::istringstream ciss( line );
2553 double dx = 0.0, dy = 0.0;
2558 int startAngleTenths = 0, deltaAngleTenths = 0;
2559 double bboxMinX = 0.0, bboxMinY = 0.0, bboxMaxX = 0.0, bboxMaxY = 0.0;
2561 if( ciss >> startAngleTenths >> deltaAngleTenths
2562 >> bboxMinX >> bboxMinY >> bboxMaxX >> bboxMaxY )
2564 double cx = ( bboxMinX + bboxMaxX ) / 2.0;
2565 double cy = ( bboxMinY + bboxMaxY ) / 2.0;
2566 double radius = ( bboxMaxX - bboxMinX ) / 2.0;
2567 double startAngle = startAngleTenths / 10.0;
2568 double deltaAngle = deltaAngleTenths / 10.0;
2570 double startAngleRad = startAngle *
M_PI / 180.0;
2571 double startX = cx +
radius * std::cos( startAngleRad );
2572 double startY = cy +
radius * std::sin( startAngleRad );
2574 double endAngleRad = ( startAngle + deltaAngle ) *
M_PI / 180.0;
2575 double endX = cx +
radius * std::cos( endAngleRad );
2576 double endY = cy +
radius * std::sin( endAngleRad );
2578 polyline.
points.emplace_back( xloc + startX, yloc + startY );
2584 arc.start_angle = startAngle;
2585 arc.delta_angle = deltaAngle;
2587 polyline.
points.emplace_back( xloc + endX, yloc + endY, arc );
2591 polyline.
points.emplace_back( xloc + dx, yloc + dy );
2595 if( !polyline.
points.empty() )
2598 else if( shape_type ==
"CIRCLE" || shape_type ==
"BRDCIR" )
2603 polyline.
width = width;
2606 double x1 = 0.0, y1 = 0.0, x2 = 0.0, y2 = 0.0;
2610 std::istringstream c1( line );
2614 if( corners >= 2 &&
readLine( aStream, line ) )
2616 std::istringstream c2( line );
2621 double cx = xloc + ( x1 + x2 ) / 2.0;
2622 double cy = yloc + ( y1 + y2 ) / 2.0;
2623 double radius = std::sqrt( ( x2 - x1 ) * ( x2 - x1 ) + ( y2 - y1 ) * ( y2 - y1 ) ) / 2.0;
2630 arc.start_angle = 0.0;
2631 arc.delta_angle = 360.0;
2635 if( !polyline.
points.empty() )
2641 for(
int j = 0; j < corners; ++j )
2646 if( line[0] ==
'*' )
2663 if( line[0] ==
'*' )
2670 std::istringstream iss( line );
2671 std::string
name, type;
2672 double xloc = 0.0, yloc = 0.0;
2673 int pieces = 0, flags = 0, textCount = 0;
2674 std::string signame;
2676 iss >>
name >> type >> xloc >> yloc >> pieces >> flags;
2681 if( iss >> textCount )
2692 std::string reuse_instance, reuse_signal;
2696 if( line.find(
".REUSE." ) != std::string::npos )
2698 std::istringstream riss( line );
2699 std::string reuse_keyword;
2700 riss >> reuse_keyword >> reuse_instance >> reuse_signal;
2708 if( type ==
"BOARD" )
2710 for(
int i=0; i<pieces; ++i )
2712 if( !
readLine( aStream, line ) )
break;
2715 std::istringstream piss( line );
2716 std::string shape_type;
2719 int piece_flags = 0;
2721 piss >> shape_type >> corners >> width >> piece_flags >> level;
2723 if( shape_type ==
"CLOSED" || shape_type ==
"OPEN" || shape_type ==
"BRDCLS" )
2727 polyline.
width = width;
2728 polyline.
closed = ( shape_type ==
"CLOSED" || shape_type ==
"BRDCLS" );
2730 for(
int j = 0; j < corners; ++j )
2735 if( line[0] ==
'*' )
2741 std::istringstream ciss( line );
2742 double dx = 0.0, dy = 0.0;
2747 int startAngleTenths = 0, deltaAngleTenths = 0;
2748 double bboxMinX = 0.0, bboxMinY = 0.0, bboxMaxX = 0.0, bboxMaxY = 0.0;
2750 if( ciss >> startAngleTenths >> deltaAngleTenths
2751 >> bboxMinX >> bboxMinY >> bboxMaxX >> bboxMaxY )
2753 double cx = ( bboxMinX + bboxMaxX ) / 2.0;
2754 double cy = ( bboxMinY + bboxMaxY ) / 2.0;
2755 double radius = ( bboxMaxX - bboxMinX ) / 2.0;
2756 double startAngle = startAngleTenths / 10.0;
2757 double deltaAngle = deltaAngleTenths / 10.0;
2759 double startAngleRad = startAngle *
M_PI / 180.0;
2760 double startX = cx +
radius * std::cos( startAngleRad );
2761 double startY = cy +
radius * std::sin( startAngleRad );
2763 double endAngleRad = ( startAngle + deltaAngle ) *
M_PI / 180.0;
2764 double endX = cx +
radius * std::cos( endAngleRad );
2765 double endY = cy +
radius * std::sin( endAngleRad );
2767 polyline.
points.emplace_back( xloc + startX, yloc + startY );
2773 arc.start_angle = startAngle;
2774 arc.delta_angle = deltaAngle;
2776 polyline.
points.emplace_back( xloc + endX, yloc + endY, arc );
2780 polyline.
points.emplace_back( xloc + dx, yloc + dy );
2784 if( !polyline.
points.empty() )
2787 else if( shape_type ==
"CIRCLE" || shape_type ==
"BRDCIR" )
2790 double x1 = 0.0, y1 = 0.0, x2 = 0.0, y2 = 0.0;
2794 std::istringstream c1( line );
2798 if( corners >= 2 &&
readLine( aStream, line ) )
2800 std::istringstream c2( line );
2804 double cx = xloc + ( x1 + x2 ) / 2.0;
2805 double cy = yloc + ( y1 + y2 ) / 2.0;
2806 double radius = std::sqrt( ( x2 - x1 ) * ( x2 - x1 ) +
2807 ( y2 - y1 ) * ( y2 - y1 ) ) / 2.0;
2811 polyline.
width = width;
2818 arc.start_angle = 0.0;
2819 arc.delta_angle = 360.0;
2823 if( !polyline.
points.empty() )
2828 for(
int j=0; j<corners; ++j )
2830 if( !
readLine( aStream, line ) )
break;
2836 else if(
name.rfind(
"DIM", 0 ) == 0 && type ==
"LINES" )
2856 double baspnt1_x = 0, baspnt1_y = 0;
2857 double baspnt2_x = 0, baspnt2_y = 0;
2858 double arwln_x = 0, arwln_y = 0;
2859 int baspnt_count = 0;
2860 bool hasArwln =
false;
2862 for(
int i = 0; i < pieces; ++i )
2867 if( line[0] ==
'*' )
2873 std::istringstream piss( line );
2874 std::string shape_type;
2877 int piece_flags = 0;
2879 piss >> shape_type >> corners >> width >> piece_flags >> level;
2883 for(
int j = 0; j < corners; ++j )
2888 if( line[0] ==
'*' )
2894 std::istringstream ciss( line );
2895 double dx = 0.0, dy = 0.0;
2900 if( shape_type ==
"BASPNT" && j == 0 )
2902 if( baspnt_count == 0 )
2904 baspnt1_x = xloc + dx;
2905 baspnt1_y = yloc + dy;
2907 else if( baspnt_count == 1 )
2909 baspnt2_x = xloc + dx;
2910 baspnt2_y = yloc + dy;
2917 if( shape_type ==
"ARWLN1" && j == 0 )
2919 arwln_x = xloc + dx;
2920 arwln_y = yloc + dy;
2927 if( baspnt_count >= 2 )
2931 double dx =
std::abs( baspnt2_x - baspnt1_x );
2932 double dy =
std::abs( baspnt2_y - baspnt1_y );
2933 bool isHorizontal = dx > dy;
2952 dim.
points.push_back( pt1 );
2953 dim.
points.push_back( pt2 );
2958 for(
int t = 0; t < textCount; ++t )
2963 if( line[0] ==
'*' )
2969 std::istringstream tiss( line );
2970 double tx = 0.0, ty = 0.0;
2982 double theight = 0.0, twidth = 0.0;
2983 tiss >> trot >> tlayer >> theight >> twidth;
3004 if( !dim.
points.empty() )
3007 else if( type ==
"KEEPOUT" || type ==
"RESTRICTVIA" || type ==
"RESTRICTROUTE"
3008 || type ==
"RESTRICTAREA" || type ==
"PLACEMENT_KEEPOUT" )
3014 if( type ==
"KEEPOUT" || type ==
"RESTRICTAREA" )
3021 else if( type ==
"RESTRICTVIA" )
3028 else if( type ==
"RESTRICTROUTE" )
3035 else if( type ==
"PLACEMENT_KEEPOUT" )
3044 for(
int i = 0; i < pieces; ++i )
3049 if( line[0] ==
'*' )
3057 std::istringstream piss( line );
3058 std::string shape_type;
3061 int piece_flags = 0;
3063 std::string restrictions;
3064 piss >> shape_type >> corners >> width >> piece_flags >> level >> restrictions;
3067 keepout.
layers.push_back( level );
3073 if( !restrictions.empty() )
3076 bool has_restriction_codes =
false;
3078 for(
char c : restrictions )
3080 if( std::isalpha( c ) )
3082 has_restriction_codes =
true;
3087 if( has_restriction_codes )
3098 for(
char c : restrictions )
3139 if( shape_type ==
"KPTCIR" )
3142 double x1 = 0.0, y1 = 0.0, x2 = 0.0, y2 = 0.0;
3146 std::istringstream c1( line );
3150 if( corners >= 2 &&
readLine( aStream, line ) )
3152 std::istringstream c2( line );
3157 double cx = xloc + ( x1 + x2 ) / 2.0;
3158 double cy = yloc + ( y1 + y2 ) / 2.0;
3159 double radius = std::sqrt( ( x2 - x1 ) * ( x2 - x1 ) +
3160 ( y2 - y1 ) * ( y2 - y1 ) ) / 2.0;
3167 arc.start_angle = 0.0;
3168 arc.delta_angle = 360.0;
3175 for(
int j = 0; j < corners; ++j )
3180 if( line[0] ==
'*' )
3186 std::istringstream ciss( line );
3187 double dx = 0.0, dy = 0.0;
3192 int startAngleTenths = 0, deltaAngleTenths = 0;
3193 double bboxMinX = 0.0, bboxMinY = 0.0, bboxMaxX = 0.0, bboxMaxY = 0.0;
3195 if( ciss >> startAngleTenths >> deltaAngleTenths
3196 >> bboxMinX >> bboxMinY >> bboxMaxX >> bboxMaxY )
3198 double cx = ( bboxMinX + bboxMaxX ) / 2.0;
3199 double cy = ( bboxMinY + bboxMaxY ) / 2.0;
3200 double radius = ( bboxMaxX - bboxMinX ) / 2.0;
3201 double startAngle = startAngleTenths / 10.0;
3202 double deltaAngle = deltaAngleTenths / 10.0;
3204 double startAngleRad = startAngle *
M_PI / 180.0;
3205 double startX = cx +
radius * std::cos( startAngleRad );
3206 double startY = cy +
radius * std::sin( startAngleRad );
3208 double endAngleRad = ( startAngle + deltaAngle ) *
M_PI / 180.0;
3209 double endX = cx +
radius * std::cos( endAngleRad );
3210 double endY = cy +
radius * std::sin( endAngleRad );
3212 keepout.
outline.emplace_back( xloc + startX, yloc + startY );
3218 arc.start_angle = startAngle;
3219 arc.delta_angle = deltaAngle;
3221 keepout.
outline.emplace_back( xloc + endX, yloc + endY, arc );
3225 keepout.
outline.emplace_back( xloc + dx, yloc + dy );
3231 if( !keepout.
outline.empty() )
3234 else if( type ==
"COPPER" || type ==
"COPCUT" )
3240 for(
int i = 0; i < pieces; ++i )
3245 if( line[0] ==
'*' )
3254 std::istringstream piss( line );
3255 std::string shape_type;
3258 int piece_flags = 0;
3260 piss >> shape_type >> corners >> width >> piece_flags >> level;
3264 copper.
layer = level;
3265 copper.
width = width;
3268 copper.
filled = ( shape_type ==
"COPCLS" || shape_type ==
"COPCIR" );
3269 copper.
is_cutout = ( shape_type ==
"COPCUT" || shape_type ==
"COPCCO" ||
3270 shape_type ==
"CIRCUR" || type ==
"COPCUT" );
3273 if( shape_type ==
"COPCIR" || shape_type ==
"COPCCO" || shape_type ==
"CIRCUR" )
3276 double x1 = 0.0, y1 = 0.0, x2 = 0.0, y2 = 0.0;
3280 std::istringstream c1( line );
3284 if( corners >= 2 &&
readLine( aStream, line ) )
3286 std::istringstream c2( line );
3290 double cx = xloc + ( x1 + x2 ) / 2.0;
3291 double cy = yloc + ( y1 + y2 ) / 2.0;
3292 double radius = std::sqrt( ( x2 - x1 ) * ( x2 - x1 ) +
3293 ( y2 - y1 ) * ( y2 - y1 ) ) / 2.0;
3299 arc.start_angle = 0.0;
3300 arc.delta_angle = 360.0;
3307 for(
int j = 0; j < corners; ++j )
3312 if( line[0] ==
'*' )
3318 std::istringstream ciss( line );
3319 double dx = 0.0, dy = 0.0;
3324 int startAngleTenths = 0, deltaAngleTenths = 0;
3325 double bboxMinX = 0.0, bboxMinY = 0.0, bboxMaxX = 0.0, bboxMaxY = 0.0;
3327 if( ciss >> startAngleTenths >> deltaAngleTenths
3328 >> bboxMinX >> bboxMinY >> bboxMaxX >> bboxMaxY )
3330 double cx = ( bboxMinX + bboxMaxX ) / 2.0;
3331 double cy = ( bboxMinY + bboxMaxY ) / 2.0;
3332 double radius = ( bboxMaxX - bboxMinX ) / 2.0;
3333 double startAngle = startAngleTenths / 10.0;
3334 double deltaAngle = deltaAngleTenths / 10.0;
3336 double startAngleRad = startAngle *
M_PI / 180.0;
3337 double startX = cx +
radius * std::cos( startAngleRad );
3338 double startY = cy +
radius * std::sin( startAngleRad );
3340 double endAngleRad = ( startAngle + deltaAngle ) *
M_PI / 180.0;
3341 double endX = cx +
radius * std::cos( endAngleRad );
3342 double endY = cy +
radius * std::sin( endAngleRad );
3344 copper.
outline.emplace_back( xloc + startX, yloc + startY );
3350 arc.start_angle = startAngle;
3351 arc.delta_angle = deltaAngle;
3353 copper.
outline.emplace_back( xloc + endX, yloc + endY, arc );
3357 copper.
outline.emplace_back( xloc + dx, yloc + dy );
3366 else if( type ==
"LINES" )
3369 for(
int i = 0; i < pieces; ++i )
3374 if( line[0] ==
'*' )
3381 std::istringstream piss( line );
3382 std::string shape_type;
3385 int piece_flags = 0;
3387 piss >> shape_type >> corners >> width >> piece_flags >> level;
3391 graphic.
layer = level;
3392 graphic.
width = width;
3396 graphic.
closed = ( shape_type ==
"CLOSED" || shape_type ==
"CIRCLE" );
3398 if( shape_type ==
"CIRCLE" )
3401 double x1 = 0.0, y1 = 0.0, x2 = 0.0, y2 = 0.0;
3405 std::istringstream c1( line );
3409 if( corners >= 2 &&
readLine( aStream, line ) )
3411 std::istringstream c2( line );
3415 double cx = xloc + ( x1 + x2 ) / 2.0;
3416 double cy = yloc + ( y1 + y2 ) / 2.0;
3417 double radius = std::sqrt( ( x2 - x1 ) * ( x2 - x1 ) +
3418 ( y2 - y1 ) * ( y2 - y1 ) ) / 2.0;
3424 arc.start_angle = 0.0;
3425 arc.delta_angle = 360.0;
3432 for(
int j = 0; j < corners; ++j )
3437 if( line[0] ==
'*' )
3443 std::istringstream ciss( line );
3444 double dx = 0.0, dy = 0.0;
3448 int startAngleTenths = 0, deltaAngleTenths = 0;
3449 double bboxMinX = 0.0, bboxMinY = 0.0, bboxMaxX = 0.0, bboxMaxY = 0.0;
3451 if( ciss >> startAngleTenths >> deltaAngleTenths
3452 >> bboxMinX >> bboxMinY >> bboxMaxX >> bboxMaxY )
3454 double cx = ( bboxMinX + bboxMaxX ) / 2.0;
3455 double cy = ( bboxMinY + bboxMaxY ) / 2.0;
3456 double radius = ( bboxMaxX - bboxMinX ) / 2.0;
3457 double startAngle = startAngleTenths / 10.0;
3458 double deltaAngle = deltaAngleTenths / 10.0;
3460 double startAngleRad = startAngle *
M_PI / 180.0;
3461 double startX = cx +
radius * std::cos( startAngleRad );
3462 double startY = cy +
radius * std::sin( startAngleRad );
3464 double endAngleRad = ( startAngle + deltaAngle ) *
M_PI / 180.0;
3465 double endX = cx +
radius * std::cos( endAngleRad );
3466 double endY = cy +
radius * std::sin( endAngleRad );
3468 graphic.
points.emplace_back( xloc + startX, yloc + startY );
3474 arc.start_angle = startAngle;
3475 arc.delta_angle = deltaAngle;
3477 graphic.
points.emplace_back( xloc + endX, yloc + endY, arc );
3481 graphic.
points.emplace_back( xloc + dx, yloc + dy );
3486 if( !graphic.
points.empty() )
3493 for(
int i = 0; i < pieces; ++i )
3498 if( line[0] ==
'*' )
3504 std::istringstream piss( line );
3505 std::string shape_type;
3507 piss >> shape_type >> corners;
3509 for(
int j = 0; j < corners; ++j )
3514 if( line[0] ==
'*' )
3525 for(
int t = 0; t < textCount; ++t )
3530 if( line[0] ==
'*' )
3536 std::istringstream tiss( line );
3550 text.location.x += xloc;
3551 text.location.y += yloc;
3553 std::string mirrored;
3555 text.mirrored = ( mirrored ==
"M" );
3562 if( line[0] ==
'*' )
3568 size_t bracket_start = line.find(
'<' );
3569 size_t bracket_end = line.find(
'>' );
3571 if( bracket_start != std::string::npos && bracket_end != std::string::npos )
3572 text.font_face = line.substr( bracket_start + 1, bracket_end - bracket_start - 1 );
3574 std::istringstream fiss( line );
3575 std::string font_style_part;
3576 fiss >> font_style_part;
3578 size_t colon_pos = font_style_part.find(
':' );
3580 if( colon_pos != std::string::npos )
3581 text.font_style = font_style_part.substr( 0, colon_pos );
3583 text.font_style = font_style_part;
3589 if( line[0] ==
'*' )
3595 text.content = line;
3625 if( line[0] ==
'*' )
3635 if( line.rfind(
"G ", 0 ) == 0 && currentPartType )
3637 std::istringstream gss( line );
3638 std::string g_keyword;
3639 int gateSwap = 0, pinCount = 0;
3640 gss >> g_keyword >> gateSwap >> pinCount;
3644 currentPartType->
gates.push_back( gate );
3645 currentGate = ¤tPartType->
gates.back();
3650 if( line.rfind(
"SIGPIN", 0 ) == 0 && currentPartType )
3652 std::istringstream sss( line );
3653 std::string keyword;
3668 if( line.find(
'.' ) != std::string::npos && currentPartType )
3673 std::stringstream check_ss( line );
3674 std::string first_token;
3675 check_ss >> first_token;
3679 for(
char c : first_token )
3692 std::stringstream ss( line );
3695 while( ss >> token )
3698 std::vector<std::string> parts;
3702 while( ( pos = token.find(
'.', start ) ) != std::string::npos )
3704 parts.push_back( token.substr( start, pos - start ) );
3708 parts.push_back( token.substr( start ) );
3710 if( parts.size() >= 3 )
3716 bool isNumericSecond = !parts[1].empty() &&
3717 std::all_of( parts[1].begin(), parts[1].
end(), ::isdigit );
3719 if( currentGate && parts[2].size() == 1 && !isNumericSecond )
3726 if( !parts[2].
empty() )
3727 gpin.
elec_type = parsePinElecType( parts[2][0] );
3729 if( parts.size() >= 4 )
3732 currentGate->
pins.push_back( gpin );
3734 else if( isNumericSecond )
3749 if( line[0] ==
'{' && currentPartType )
3753 if( line.empty() || line[0] ==
'}' )
3756 if( line[0] ==
'*' )
3762 std::string attrName, attrValue;
3764 if( line[0] ==
'"' )
3766 size_t endQuote = line.find(
'"', 1 );
3768 if( endQuote != std::string::npos )
3770 attrName = line.substr( 1, endQuote - 1 );
3771 attrValue = line.substr( endQuote + 1 );
3776 std::istringstream attrSS( line );
3778 std::getline( attrSS >> std::ws, attrValue );
3781 if( !attrValue.empty() && attrValue[0] ==
' ' )
3782 attrValue = attrValue.substr( 1 );
3784 if( !attrName.empty() && !attrValue.empty() )
3785 currentPartType->
attributes[attrName] = attrValue;
3791 if( line[0] ==
'{' || line[0] ==
'}' )
3795 std::stringstream ss( line );
3796 std::string
name, decal;
3797 ss >>
name >> decal;
3799 if( !
name.empty() &&
name[0] !=
'G' )
3806 currentGate =
nullptr;
3819 if( line[0] ==
'*' )
3825 std::stringstream ss( line );
3826 std::string keyword;
3829 if( keyword ==
"TYPE" )
3831 std::string typename_val;
3832 std::getline( ss, typename_val );
3834 if( !typename_val.empty() && typename_val[0] ==
' ' )
3835 typename_val = typename_val.substr( 1 );
3838 block.
name = typename_val;
3842 else if( keyword ==
"TIMESTAMP" && currentBlock )
3848 else if( keyword ==
"PART_NAMING" && currentBlock )
3851 std::getline( ss, naming );
3853 if( !naming.empty() && naming[0] ==
' ' )
3854 naming = naming.substr( 1 );
3858 else if( keyword ==
"PART" && currentBlock )
3860 std::string partname;
3861 std::getline( ss, partname );
3863 if( !partname.empty() && partname[0] ==
' ' )
3864 partname = partname.substr( 1 );
3866 currentBlock->
part_names.push_back( partname );
3868 else if( keyword ==
"NET_NAMING" && currentBlock )
3871 std::getline( ss, naming );
3873 if( !naming.empty() && naming[0] ==
' ' )
3874 naming = naming.substr( 1 );
3878 else if( keyword ==
"NET" && currentBlock )
3881 std::string netname;
3884 std::getline( ss, netname );
3886 if( !netname.empty() && netname[0] ==
' ' )
3887 netname = netname.substr( 1 );
3890 net.
merge = ( merge_flag == 1 );
3892 currentBlock->
nets.push_back( net );
3894 else if( keyword ==
"REUSE" && currentBlock )
3899 std::string next_token;
3902 if( next_token ==
"PREFIX" || next_token ==
"SUFFIX" )
3909 else if( next_token ==
"START" || next_token ==
"INCREMENT" )
3916 else if( next_token ==
"NEXT" )
3922 if( next_token ==
"PREFIX" || next_token ==
"SUFFIX" )
3926 instance.
net_naming = next_token +
" " + param;
3928 else if( next_token ==
"START" || next_token ==
"INCREMENT" )
3932 instance.
net_naming = next_token +
" " + num;
3934 else if( next_token ==
"NEXT" )
3939 std::string glued_str;
3942 instance.
glued = ( glued_str ==
"Y" || glued_str ==
"YES" || glued_str ==
"1" );
3943 currentBlock->
instances.push_back( instance );
3952 CLUSTER* currentCluster =
nullptr;
3956 if( line[0] ==
'*' )
3962 std::stringstream ss( line );
3963 std::string firstToken;
3968 if( firstToken.empty() )
3972 bool isNumeric = !firstToken.empty() &&
3973 std::all_of( firstToken.begin(), firstToken.end(), ::isdigit );
3987 cluster.
name =
"Cluster_" + firstToken;
3992 else if( currentCluster )
3996 if( firstToken.find(
'.' ) != std::string::npos )
4004 currentCluster->
net_names.push_back( firstToken );
4012 if( item.find(
'.' ) != std::string::npos )
4015 currentCluster->
net_names.push_back( item );
4028 if( line[0] ==
'*' )
4036 std::stringstream ss( line );
4037 std::string
name, flags;
4038 double minlen = 0.0, maxlen = 0.0, lenincr = 0.0;
4040 std::string padstack, end_padstack;
4042 if( !( ss >>
name >> flags >> minlen >> maxlen >> lenincr >> lcount >> padstack ) )
4056 for(
char c : flags )
4062 case 'W': jumper.
wirebond =
true;
break;
4064 case 'G': jumper.
glued =
true;
break;
4070 for(
int i = 0; i < lcount; ++i )
4078 std::stringstream ss_attr( line );
4079 std::string visible_str, mirrored_str, right_reading_str;
4084 attr.
visible = ( visible_str ==
"VALUE" || visible_str ==
"FULL_NAME" ||
4085 visible_str ==
"NAME" || visible_str ==
"FULL_BOTH" ||
4086 visible_str ==
"BOTH" );
4087 attr.
mirrored = ( mirrored_str ==
"M" || mirrored_str ==
"1" );
4088 ss_attr >> right_reading_str;
4089 attr.
right_reading = ( right_reading_str ==
"Y" || right_reading_str ==
"ORTHO" );
4098 jumper.
labels.push_back( attr );
4112 if( line[0] ==
'*' )
4118 std::stringstream ss( line );
4130 ss >>
tp.x >>
tp.y >>
tp.side >>
tp.net_name >>
tp.symbol_name;
4132 if( !
tp.net_name.empty() )
4144 bool inClass =
false;
4148 if( line[0] ==
'*' )
4151 if( inClass && !currentClass.
name.empty() )
4158 std::stringstream ss( line );
4166 if( token ==
"CLASS" || token ==
"NETCLASS" )
4169 if( inClass && !currentClass.
name.empty() )
4174 ss >> currentClass.
name;
4177 else if( token ==
"CLEARANCE" && inClass )
4181 else if( token ==
"TRACKWIDTH" && inClass )
4185 else if( token ==
"VIASIZE" && inClass )
4189 else if( token ==
"VIADRILL" && inClass )
4193 else if( token ==
"DIFFPAIRGAP" && inClass )
4197 else if( token ==
"DIFFPAIRWIDTH" && inClass )
4201 else if( token ==
"NET" && inClass )
4204 std::string netName;
4207 if( !netName.empty() )
4208 currentClass.
net_names.push_back( netName );
4210 else if( !token.empty() && token[0] !=
'#' )
4213 if( !inClass || ( inClass && currentClass.
name.empty() ) )
4216 if( inClass && !currentClass.
name.empty() )
4220 currentClass.
name = token;
4227 if( inClass && !currentClass.
name.empty() )
4238 if( line[0] ==
'*' )
4244 std::stringstream ss( line );
4260 if( token ==
"DIFFPAIR" || token ==
"PAIR" )
4266 std::string posNet, negNet;
4267 ss >> posNet >> negNet;
4269 if( !posNet.empty() )
4272 if( !negNet.empty() )
4276 double gap = 0.0, width = 0.0;
4284 if( !dp.
name.empty() )
4299 else if( ( token ==
"WIDTH" || token ==
"TRACKWIDTH" ) && !
m_diff_pairs.empty() )
4311 int currentLayerNum = -1;
4313 bool inLayerBlock =
false;
4317 if( typeStr ==
"ROUTING" )
4319 else if( typeStr ==
"PLANE" )
4321 else if( typeStr ==
"MIXED" )
4323 else if( typeStr ==
"UNASSIGNED" )
4325 else if( typeStr ==
"SOLDER_MASK" )
4327 else if( typeStr ==
"PASTE_MASK" )
4329 else if( typeStr ==
"SILK_SCREEN" )
4331 else if( typeStr ==
"ASSEMBLY" )
4333 else if( typeStr ==
"DOCUMENTATION" )
4335 else if( typeStr ==
"DRILL" )
4346 if( line[0] ==
'*' )
4352 std::istringstream iss( line );
4367 if( inLayerBlock && braceDepth == 1 )
4369 if( currentLayerNum >= 0 )
4371 currentLayer.
number = currentLayerNum;
4381 inLayerBlock =
false;
4382 currentLayerNum = -1;
4386 if( braceDepth <= 0 )
4392 if( token ==
"LAYER" )
4397 if( !iss.fail() && layerNum >= 0 )
4400 currentLayerNum = layerNum;
4402 currentLayer.
number = layerNum;
4404 inLayerBlock =
true;
4407 else if( token ==
"LAYER_NAME" && inLayerBlock )
4411 std::getline( iss >> std::ws,
name );
4414 else if( token ==
"LAYER_TYPE" && inLayerBlock )
4416 std::string typeStr;
4418 currentLayer.
layer_type = parseLayerType( typeStr );
4420 else if( token ==
"LAYER_THICKNESS" && inLayerBlock )
4424 else if( token ==
"COPPER_THICKNESS" && inLayerBlock )
4428 else if( token ==
"DIELECTRIC" && inLayerBlock )
4450 bool inDifPair =
false;
4451 bool inNetClassData =
false;
4452 bool inNetClass =
false;
4453 bool inRuleSet =
false;
4454 bool inRuleSetFor =
false;
4455 bool inClearanceRule =
false;
4456 int netClassDataDepth = -1;
4457 int netClassDepth = -1;
4458 int ruleSetDepth = -1;
4459 int clearanceRuleDepth = -1;
4460 bool foundDefaultRules =
false;
4461 bool isDefaultRuleSet =
false;
4462 std::string ruleSetNetClass;
4472 if( line[0] ==
'*' && braceDepth == 0 )
4479 for(
char c : line )
4487 if( braceDepth == 0 && inDifPair )
4490 if( !currentDiffPair.
name.empty() )
4497 if( inNetClass && braceDepth <= netClassDepth )
4499 if( !currentNetClass.
name.empty() )
4506 if( inNetClassData && braceDepth <= netClassDataDepth )
4508 inNetClassData =
false;
4511 if( inClearanceRule && braceDepth < clearanceRuleDepth )
4513 inClearanceRule =
false;
4515 if( isDefaultRuleSet )
4518 == std::numeric_limits<double>::max() )
4527 == std::numeric_limits<double>::max() )
4533 foundDefaultRules =
true;
4537 if( inRuleSetFor && braceDepth < ruleSetDepth + 1 )
4538 inRuleSetFor =
false;
4540 if( inRuleSet && braceDepth < ruleSetDepth )
4543 isDefaultRuleSet =
false;
4544 ruleSetNetClass.clear();
4549 std::istringstream iss( line );
4555 if( token ==
"LAYER" )
4557 std::string secondToken;
4560 if( secondToken ==
"DATA" )
4567 if( token ==
"NET_CLASS" )
4569 std::string secondToken;
4572 if( secondToken ==
"DATA" )
4574 inNetClassData =
true;
4575 netClassDataDepth = braceDepth;
4577 else if( inNetClassData && !secondToken.empty() )
4579 if( inNetClass && !currentNetClass.
name.empty() )
4583 currentNetClass.
name = secondToken;
4585 netClassDepth = braceDepth;
4587 else if( inRuleSetFor && !secondToken.empty() )
4589 ruleSetNetClass = secondToken;
4592 else if( inNetClass && token ==
"NET" )
4594 std::string netName;
4597 if( !netName.empty() )
4598 currentNetClass.
net_names.push_back( netName );
4600 else if( token ==
"RULE_SET" )
4602 std::string ruleNum;
4606 ruleSetDepth = braceDepth;
4607 ruleSetNetClass.clear();
4608 isDefaultRuleSet = ( ruleNum ==
"(1)" && !foundDefaultRules );
4610 else if( inRuleSet && !inClearanceRule && token ==
"FOR" )
4612 inRuleSetFor =
true;
4614 else if( inRuleSet && token ==
"CLEARANCE_RULE" )
4616 inClearanceRule =
true;
4617 clearanceRuleDepth = braceDepth;
4619 if( isDefaultRuleSet )
4621 m_design_rules.default_clearance = std::numeric_limits<double>::max();
4622 m_design_rules.copper_edge_clearance = std::numeric_limits<double>::max();
4625 else if( inClearanceRule )
4630 if( !iss.fail() && val > 0.0 )
4632 if( isDefaultRuleSet )
4634 if( token ==
"MIN_TRACK_WIDTH" )
4638 else if( token ==
"REC_TRACK_WIDTH" )
4642 else if( token ==
"DRILL_TO_DRILL" )
4646 else if( token ==
"OUTLINE_TO_TRACK" || token ==
"OUTLINE_TO_VIA"
4647 || token ==
"OUTLINE_TO_PAD" || token ==
"OUTLINE_TO_COPPER"
4648 || token ==
"OUTLINE_TO_SMD" )
4653 else if( token.rfind(
"SAME_NET_", 0 ) == 0 || token ==
"BODY_TO_BODY"
4654 || token ==
"MAX_TRACK_WIDTH"
4655 || token.rfind(
"TEXT_TO_", 0 ) == 0
4656 || token.rfind(
"COPPER_TO_", 0 ) == 0 )
4662 else if( token ==
"TRACK_TO_TRACK" || token.rfind(
"VIA_TO_", 0 ) == 0
4663 || token.rfind(
"PAD_TO_", 0 ) == 0
4664 || token.rfind(
"SMD_TO_", 0 ) == 0
4665 || token.rfind(
"DRILL_TO_", 0 ) == 0 )
4671 else if( !ruleSetNetClass.empty() )
4675 if( nc.name == ruleSetNetClass )
4677 if( token ==
"REC_TRACK_WIDTH" )
4678 nc.track_width = val;
4679 else if( token ==
"TRACK_TO_TRACK" )
4688 else if( token ==
"DIF_PAIR" )
4691 if( inDifPair && !currentDiffPair.
name.empty() )
4695 iss >> currentDiffPair.
name;
4698 else if( inDifPair )
4700 if( token ==
"NET" )
4702 std::string netName;
4711 else if( token ==
"GAP" )
4713 iss >> currentDiffPair.
gap;
4715 else if( token ==
"WIDTH" )
4717 iss >> currentDiffPair.
width;
4719 else if( token ==
"CONNECTION" )
4725 else if( token ==
"ASSOCIATED" )
4728 std::string keyword, netName;
4729 iss >> keyword >> netName;
4731 if( keyword ==
"NET" )
4743 if( token ==
"PART" && !inDifPair && !inNetClass )
4745 std::string partName;
4748 if( !partName.empty() )
4751 int savedDepth = braceDepth;
4759 if( line[0] ==
'}' )
4762 if( line[0] ==
'{' )
4765 if( line[0] ==
'*' )
4772 std::string attrName, attrValue;
4774 if( line[0] ==
'"' )
4776 size_t endQuote = line.find(
'"', 1 );
4778 if( endQuote != std::string::npos )
4780 attrName = line.substr( 1, endQuote - 1 );
4781 attrValue = line.substr( endQuote + 1 );
4786 std::istringstream attrSS( line );
4788 std::getline( attrSS >> std::ws, attrValue );
4791 if( !attrValue.empty() && attrValue[0] ==
' ' )
4792 attrValue = attrValue.substr( 1 );
4794 if( !attrName.empty() && !attrValue.empty() )
4795 attrs[attrName] = attrValue;
4799 braceDepth = savedDepth;
4816 if(
m_design_rules.default_clearance == std::numeric_limits<double>::max() )
4819 if(
m_design_rules.copper_edge_clearance == std::numeric_limits<double>::max() )
4826 std::vector<LAYER_INFO> layers;
4830 if( layerCount < 1 )
4834 auto isCopperLayer = [&](
int num ) {
4835 return num >= 1 && num <= layerCount;
4839 auto getLayerDef = [&](
int num ) ->
const LAYER_INFO* {
4841 return it !=
m_layer_defs.end() ? &it->second :
nullptr;
4845 for(
int i = 1; i <= layerCount; ++i )
4851 layers.push_back( *parsed );
4859 info.is_copper =
true;
4860 info.required =
true;
4864 else if( i == layerCount )
4865 info.name =
"Bottom";
4867 info.name =
"Inner " + std::to_string( i - 1 );
4869 layers.push_back(
info );
4876 if( !isCopperLayer( num ) )
4878 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
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
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)
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.