49 std::vector<std::string>
result;
51 size_t braceStart = aPattern.find(
'{' );
52 size_t braceEnd = aPattern.find(
'}' );
54 if( braceStart == std::string::npos || braceEnd == std::string::npos || braceEnd <= braceStart )
56 result.push_back( aPattern );
60 std::string prefix = aPattern.substr( 0, braceStart );
61 std::string suffix = ( braceEnd + 1 < aPattern.length() ) ? aPattern.substr( braceEnd + 1 ) :
"";
62 std::string range = aPattern.substr( braceStart + 1, braceEnd - braceStart - 1 );
64 size_t dashPos = range.find(
'-' );
66 if( dashPos == std::string::npos )
68 result.push_back( aPattern );
75 if( start == INT_MIN ||
end == INT_MIN )
77 result.push_back( aPattern );
81 static constexpr int MAX_EXPANSION = 10000;
85 wxLogWarning( wxT(
"PADS Import: shortcut range {%d-%d} exceeds limit, skipped" ),
87 result.push_back( aPattern );
91 for(
int i = start; i <=
end; ++i )
93 result.push_back( prefix + std::to_string( i ) + suffix );
110 std::ifstream file( aFileName.ToStdString() );
111 if( !file.is_open() )
113 throw std::runtime_error(
"Could not open file " + aFileName.ToStdString() );
121 throw std::runtime_error(
"Empty file" );
133 if( line.size() > 2 && line[0] ==
'*' && line.back() ==
'*' )
135 std::string header = line.substr( 1, line.size() - 2 );
139 if( header.find(
"LIBRARY-LINE-ITEMS" ) != std::string::npos ||
140 header.find(
"LIBRARY-LINE" ) != std::string::npos )
144 else if( header.find(
"LIBRARY-SCH-DECALS" ) != std::string::npos )
148 else if( header.find(
"LIBRARY-PCB-DECALS" ) != std::string::npos ||
149 header.find(
"LIBRARY-DECALS" ) != std::string::npos )
153 else if( header.find(
"LIBRARY-PART-TYPES" ) != std::string::npos )
159 size_t v_pos = header.rfind(
"-V" );
161 if( v_pos != std::string::npos )
169 else if( line.size() > 2 && line[0] ==
'!' )
173 size_t close_pos = line.find(
'!', 1 );
175 if( close_pos == std::string::npos )
176 close_pos = line.size();
178 std::string header = line.substr( 1, close_pos - 1 );
181 std::vector<std::string> parts;
185 while( ( pos = header.find(
'-', start ) ) != std::string::npos )
187 parts.push_back( header.substr( start, pos - start ) );
191 parts.push_back( header.substr( start ) );
194 if( parts.size() >= 4 )
201 if( parts.size() >= 5 )
204 if( parts.size() >= 6 )
207 else if( parts.size() >= 2 )
212 if( parts.size() >= 2 )
215 if( parts.size() >= 3 )
237 else if( line.find(
"BASIC" ) != std::string::npos )
244 if( line.empty() )
continue;
246 if( line.rfind(
"*PCB*", 0 ) == 0 )
250 else if( line.rfind(
"*PART*", 0 ) == 0 )
254 else if( line.rfind(
"*NET*", 0 ) == 0 )
258 else if( line.rfind(
"*ROUTE*", 0 ) == 0 )
262 else if( line.rfind(
"*TEXT*", 0 ) == 0 )
266 else if( line.rfind(
"*BOARD*", 0 ) == 0 )
270 else if( line.rfind(
"*LINES*", 0 ) == 0 )
274 else if( line.rfind(
"*VIA*", 0 ) == 0 )
278 else if( line.rfind(
"*POUR*", 0 ) == 0 )
282 else if( line.rfind(
"*PARTDECAL*", 0 ) == 0 )
286 else if( line.rfind(
"*PARTTYPE*", 0 ) == 0 )
290 else if( line.rfind(
"*REUSE*", 0 ) == 0 )
294 else if( line.rfind(
"*CLUSTER*", 0 ) == 0 )
298 else if( line.rfind(
"*JUMPER*", 0 ) == 0 )
302 else if( line.rfind(
"*TESTPOINT*", 0 ) == 0 )
306 else if( line.rfind(
"*NETCLASS*", 0 ) == 0 || line.rfind(
"*NETDEF*", 0 ) == 0 )
310 else if( line.rfind(
"*DIFFPAIR*", 0 ) == 0 || line.rfind(
"*DIFFPAIRS*", 0 ) == 0 )
314 else if( line.rfind(
"LAYER MILS", 0 ) == 0 || line.rfind(
"LAYER METRIC", 0 ) == 0 )
318 else if( line.rfind(
"*MISC*", 0 ) == 0 )
334 while( std::getline( aStream, aLine ) )
337 aLine.erase( 0, aLine.find_first_not_of(
" \t\r\n" ) );
338 aLine.erase( aLine.find_last_not_of(
" \t\r\n" ) + 1 );
340 if( aLine.empty() )
continue;
341 if( aLine.rfind(
"*REMARK*", 0 ) == 0 )
continue;
363 std::istringstream iss( line );
367 if( token ==
"UNITS" )
376 else if( token ==
"USERGRID" )
380 else if( token ==
"MAXIMUMLAYER" )
384 else if( token ==
"ORIGIN" )
388 else if( token ==
"THERLINEWID" )
392 else if( token ==
"THERSMDWID" )
396 else if( token ==
"THERFLAGS" )
398 std::string flags_str;
403 m_parameters.thermal_flags = std::stoi( flags_str,
nullptr, 0 );
405 catch(
const std::exception& )
410 else if( token ==
"DRLOVERSIZE" )
414 else if( token ==
"VIAPSHVIA" )
418 else if( token ==
"STMINCLEAR" )
422 else if( token ==
"STMINSPOKES" )
426 else if( token ==
"MINCLEAR" )
430 else if( token ==
"DEFAULTCLEAR" )
434 else if( token ==
"MINTRACKWID" )
438 else if( token ==
"DEFAULTTRACKWID" )
442 else if( token ==
"MINVIASIZE" )
446 else if( token ==
"DEFAULTVIASIZE" )
450 else if( token ==
"MINVIADRILL" )
454 else if( token ==
"DEFAULTVIADRILL" )
458 else if( token ==
"HOLEHOLE" )
462 else if( token ==
"SILKCLEAR" )
466 else if( token ==
"MASKCLEAR" )
478 if( line.find(
"*REMARK*" ) == 0 )
488 if( line.rfind(
"}", 0 ) == 0 ||
489 line.rfind(
"{", 0 ) == 0 )
494 std::istringstream iss( line );
499 std::string name_token, parttype_string;
510 bool is_shortcut = ( expanded_names.size() > 1 );
511 part.
name = expanded_names[0];
515 size_t at_pos = parttype_string.find(
'@' );
517 if( at_pos != std::string::npos )
520 part.
part_type = parttype_string.substr( 0, at_pos );
521 part.
decal = parttype_string.substr( at_pos + 1 );
530 size_t colon_pos = 0;
533 while( ( colon_pos = parttype_string.find(
':', pos ) ) != std::string::npos )
535 std::string decal_name = parttype_string.substr( pos, colon_pos - pos );
539 part.
decal = decal_name;
551 std::string last_decal = parttype_string.substr( pos );
555 part.
decal = last_decal;
564 std::vector<std::string> tokens;
566 while( iss >> token )
568 tokens.push_back( token );
578 for(
size_t i = 0; i < tokens.size(); ++i )
580 const std::string& t = tokens[i];
601 if( i == tokens.size() - 1 )
606 labels = std::stoi( t, &pos );
608 if( pos != t.length() )
611 catch(
const std::exception& )
622 if( line.find(
".REUSE." ) == 0 )
624 std::istringstream riss( line );
625 std::string reuse_keyword;
634 for(
int i = 0; i < labels; ++i )
637 if( !
readLine( aStream, line ) )
break;
639 std::stringstream iss_attr( line );
640 std::string visible_str;
641 std::string mirrored_str;
642 std::string right_reading_str;
648 attr.
visible = ( visible_str ==
"VALUE" || visible_str ==
"FULL_NAME"
649 || visible_str ==
"NAME" || visible_str ==
"FULL_BOTH"
650 || visible_str ==
"BOTH" );
651 attr.
mirrored = ( mirrored_str ==
"M" );
652 iss_attr >> right_reading_str;
653 attr.
right_reading = ( right_reading_str ==
"Y" || right_reading_str ==
"ORTHO" );
657 if( !
readLine( aStream, line ) )
break;
661 if( !
readLine( aStream, line ) )
break;
674 for(
size_t i = 1; i < expanded_names.size(); ++i )
676 PART additional_part = part;
677 additional_part.
name = expanded_names[i];
678 m_parts.push_back( additional_part );
691 NET* current_net =
nullptr;
694 auto parsePinToken = [](
const std::string& token,
NET_PIN&
pin ) ->
bool
696 size_t dot_pos = token.find(
'.' );
698 if( dot_pos == std::string::npos )
701 pin.ref_des = token.substr( 0, dot_pos );
702 pin.pin_name = token.substr( dot_pos + 1 );
708 auto expandShortcutPin = [](
const std::string& token ) -> std::vector<std::string>
710 std::vector<std::string> results;
713 if( token.find(
'{' ) == std::string::npos )
715 results.push_back( token );
726 bool is_range =
false;
729 std::vector<RangePart> parts;
731 std::string current_prefix;
733 while( pos < token.size() )
735 if( token[pos] ==
'{' )
737 size_t close_pos = token.find(
'}', pos );
739 if( close_pos == std::string::npos )
742 results.push_back( token );
746 std::string range_str = token.substr( pos + 1, close_pos - pos - 1 );
747 size_t dash_pos = range_str.find(
'-' );
749 if( dash_pos != std::string::npos )
752 part.prefix = current_prefix;
753 part.is_range =
true;
756 INT_MIN,
"net range" );
758 INT_MIN,
"net range" );
760 if( part.start == INT_MIN || part.end == INT_MIN )
762 results.push_back( token );
766 parts.push_back( part );
767 current_prefix.clear();
772 current_prefix += range_str;
779 current_prefix += token[pos];
785 if( !current_prefix.empty() || parts.empty() )
787 RangePart final_part;
788 final_part.prefix = current_prefix;
789 final_part.is_range =
false;
790 final_part.start = 0;
792 parts.push_back( final_part );
797 results.push_back(
"" );
799 for(
const auto& part : parts )
801 std::vector<std::string> new_results;
805 for(
const auto& base : results )
807 int step = ( part.start <= part.end ) ? 1 : -1;
809 for(
int i = part.start; step > 0 ? i <= part.end : i >= part.end; i += step )
811 new_results.push_back( base + part.prefix + std::to_string( i ) );
817 for(
const auto& base : results )
819 new_results.push_back( base + part.prefix );
823 results = std::move( new_results );
837 std::istringstream iss( line );
841 if( token ==
"SIGNAL" )
846 current_net = &
m_nets.back();
849 std::string pin_token;
851 while( iss >> pin_token )
854 if( pin_token ==
".REUSE." )
857 std::string instance, rsignal;
859 if( ( iss >> instance >> rsignal ) && !current_net->
pins.empty() )
861 current_net->
pins.back().reuse_instance = instance;
862 current_net->
pins.back().reuse_signal = rsignal;
869 for(
const auto& expanded : expandShortcutPin( pin_token ) )
873 if( parsePinToken( expanded,
pin ) )
874 current_net->
pins.push_back(
pin );
886 if( token ==
".REUSE." )
888 std::string instance, rsignal;
890 if( ( iss >> instance >> rsignal ) && !current_net->
pins.empty() )
892 current_net->
pins.back().reuse_instance = instance;
893 current_net->
pins.back().reuse_signal = rsignal;
900 for(
const auto& expanded : expandShortcutPin( token ) )
904 if( parsePinToken( expanded,
pin ) )
905 current_net->
pins.push_back(
pin );
908 }
while( iss >> token );
926 std::stringstream iss( line );
931 if( !( iss >>
name >> drill >> stacklines ) )
939 int drill_start_val = 0;
940 int drill_end_val = 0;
942 if( iss >> drill_start_val >> drill_end_val )
948 int min_layer = INT_MAX;
949 int max_layer = INT_MIN;
951 for(
int i = 0; i < stacklines; ++i )
956 std::stringstream iss2( line );
961 if( !( iss2 >> level >> size >> shape ) )
965 layer_data.
layer = level;
966 layer_data.
shape = shape;
967 layer_data.
sizeA = size;
971 if( shape ==
"R" || shape ==
"S" )
977 if( shape ==
"S" && ( iss2 >> corner ) )
990 else if( shape ==
"RA" || shape ==
"SA" )
995 else if( shape ==
"A" )
1003 else if( shape ==
"OF" )
1006 double ori = 0, length = 0, offset = 0;
1008 if( iss2 >> ori >> length >> offset )
1011 layer_data.
sizeB = length;
1015 else if( shape ==
"RF" )
1019 double ori = 0, length = 0, offset = 0;
1021 if( iss2 >> ori >> length >> offset )
1024 layer_data.
sizeB = length;
1028 else if( shape ==
"RT" || shape ==
"ST" )
1031 double ori = 0, intd = 0, spkwid = 0;
1034 if( iss2 >> ori >> intd >> spkwid >> spknum )
1042 else if( shape ==
"O" || shape ==
"OC" )
1048 else if( shape ==
"RC" )
1052 double ori = 0, length = 0, offset = 0, corner = 0;
1054 if( iss2 >> ori >> length >> offset )
1057 layer_data.
sizeB = length;
1060 if( iss2 >> corner )
1075 def.
stack.push_back( layer_data );
1080 int effective_layer = level;
1083 effective_layer = 1;
1084 else if( level == -1 )
1087 bool is_copper = ( effective_layer >= 1
1092 if( size > def.
size )
1095 if( effective_layer < min_layer )
1096 min_layer = effective_layer;
1098 if( effective_layer > max_layer )
1099 max_layer = effective_layer;
1105 else if( level == 28 )
1110 if( min_layer <= max_layer )
1116 bool starts_at_surface = ( min_layer == 1 || max_layer == layer_count );
1117 bool ends_at_surface = ( max_layer == layer_count || min_layer == 1 );
1118 bool is_full_span = ( min_layer == 1 && max_layer == layer_count );
1119 int span = max_layer - min_layer;
1125 else if( span == 1 && ( min_layer == 1 || max_layer == layer_count ) )
1129 else if( starts_at_surface || ends_at_surface )
1153 if( line[0] ==
'*' )
1161 std::stringstream iss( line );
1162 std::string
name, type;
1163 double x = 0.0, y = 0.0;
1164 int pieces = 0, flags = 0;
1166 if( !( iss >>
name >> type >> x >> y >> pieces >> flags ) )
1169 std::string owner, signame;
1170 double hatchgrid = 0.0, hatchrad = 0.0;
1173 if( iss >> owner >> signame )
1175 iss >> hatchgrid >> hatchrad >> priority;
1178 for(
int i = 0; i < pieces; ++i )
1185 std::stringstream iss2( line );
1186 std::string poly_type;
1187 int corners = 0, arcs = 0;
1191 if( !( iss2 >> poly_type >> corners >> arcs >> width >> level ) )
1200 pour.
is_cutout = ( poly_type ==
"POCUT" || poly_type ==
"CUTOUT"
1201 || poly_type ==
"CIRCUT" );
1209 if( type ==
"HATOUT" )
1213 else if( type ==
"VOIDOUT" )
1218 else if( type ==
"PADTHERM" )
1222 else if( type ==
"VIATHERM" )
1228 if( poly_type ==
"CIRCLE" || poly_type ==
"CIRCUT" )
1235 std::stringstream iss3( line );
1236 double cx = 0.0, cy = 0.0,
radius = 0.0;
1238 if( iss3 >> cx >> cy >>
radius )
1245 arc.start_angle = 0.0;
1246 arc.delta_angle = 360.0;
1247 pour.
points.emplace_back( x + cx +
radius, y + cy, arc );
1250 else if( poly_type ==
"SEG" )
1253 for(
int j = 0; j < corners; ++j )
1258 std::stringstream iss3( line );
1259 double px = 0.0, py = 0.0;
1261 if( iss3 >> px >> py )
1263 pour.
points.emplace_back( x + px, y + py );
1275 int totalLines = corners + arcs;
1276 bool nextIsArcEndpoint =
false;
1279 for(
int j = 0; j < totalLines; ++j )
1284 std::stringstream iss3( line );
1285 double px = 0.0, py = 0.0;
1287 if( !( iss3 >> px >> py ) )
1290 int angle1 = 0, angle2 = 0;
1292 if( iss3 >> angle1 >> angle2 )
1298 pendingArc.
cx = x + px;
1299 pendingArc.cy = y + py;
1300 pendingArc.start_angle = angle1 / 10.0;
1301 pendingArc.delta_angle = angle2 / 10.0;
1303 if( !pour.
points.empty() )
1305 double dx = pour.
points.back().x - pendingArc.cx;
1306 double dy = pour.
points.back().y - pendingArc.cy;
1307 pendingArc.radius = std::sqrt( dx * dx + dy * dy );
1310 nextIsArcEndpoint =
true;
1312 else if( nextIsArcEndpoint )
1314 if( pendingArc.radius == 0.0 )
1316 double dx = ( x + px ) - pendingArc.cx;
1317 double dy = ( y + py ) - pendingArc.cy;
1318 pendingArc.radius = std::sqrt( dx * dx + dy * dy );
1321 pour.
points.emplace_back( x + px, y + py, pendingArc );
1322 nextIsArcEndpoint =
false;
1326 pour.
points.emplace_back( x + px, y + py );
1341 if( line[0] ==
'*' )
1348 std::stringstream iss( line );
1349 std::string
name, units;
1350 double orix = 0.0, oriy = 0.0;
1351 int pieces = 0, terminals = 0, stacks = 0, text_cnt = 0, labels = 0;
1353 if( !( iss >>
name >> units >> orix >> oriy >> pieces >> terminals >> stacks >> text_cnt >> labels ) )
1358 decal.
units = units;
1361 for(
int i = 0; i < pieces; ++i )
1363 if( !
readLine( aStream, line ) )
break;
1366 std::stringstream iss2( line );
1372 if( !( iss2 >> type >> corners >> width ) )
1405 decal.
items.push_back( item );
1411 if( type.find(
"COP" ) == 0 )
1413 std::string remaining;
1414 std::getline( iss2, remaining );
1417 std::istringstream rem_ss( remaining );
1418 int pinnum_val = -1;
1420 if( rem_ss >> pinnum_val )
1421 item.
pinnum = pinnum_val;
1425 if( type.find(
"KPT" ) == 0 )
1427 std::string restrictions;
1429 if( iss2 >> restrictions )
1433 for(
int j = 0; j < corners; ++j )
1438 std::stringstream iss3( line );
1439 double px = 0.0, py = 0.0;
1441 if( !( iss3 >> px >> py ) )
1447 int startAngleTenths = 0, deltaAngleTenths = 0;
1448 double bboxMinX = 0.0, bboxMinY = 0.0, bboxMaxX = 0.0, bboxMaxY = 0.0;
1450 if( iss3 >> startAngleTenths >> deltaAngleTenths
1451 >> bboxMinX >> bboxMinY >> bboxMaxX >> bboxMaxY )
1453 double cx = ( bboxMinX + bboxMaxX ) / 2.0;
1454 double cy = ( bboxMinY + bboxMaxY ) / 2.0;
1455 double radius = ( bboxMaxX - bboxMinX ) / 2.0;
1456 double startAngle = startAngleTenths / 10.0;
1457 double deltaAngle = deltaAngleTenths / 10.0;
1460 double startAngleRad = startAngle *
M_PI / 180.0;
1461 double startX = cx +
radius * std::cos( startAngleRad );
1462 double startY = cy +
radius * std::sin( startAngleRad );
1465 double endAngleRad = ( startAngle + deltaAngle ) *
M_PI / 180.0;
1466 double endX = cx +
radius * std::cos( endAngleRad );
1467 double endY = cy +
radius * std::sin( endAngleRad );
1470 item.
points.emplace_back( startX, startY );
1476 arc.start_angle = startAngle;
1477 arc.delta_angle = deltaAngle;
1480 item.
points.emplace_back( endX, endY, arc );
1484 item.
points.emplace_back( px, py );
1488 decal.
items.push_back( item );
1504 for(
int i = 0; i < text_cnt + labels; ++i )
1506 std::string line1, line2, line3;
1507 if( !
readLine( aStream, line1 ) )
break;
1508 if( !
readLine( aStream, line2 ) )
break;
1509 if( !
readLine( aStream, line3 ) )
break;
1513 std::stringstream ss( line1 );
1514 std::string type_token;
1518 std::string mirrored_str, right_reading_str;
1523 attr.
visible = ( type_token ==
"VALUE" || type_token ==
"FULL_NAME"
1524 || type_token ==
"NAME" || type_token ==
"FULL_BOTH"
1525 || type_token ==
"BOTH" );
1526 attr.
mirrored = ( mirrored_str ==
"M" );
1527 ss >> right_reading_str;
1528 attr.
right_reading = ( right_reading_str ==
"Y" || right_reading_str ==
"ORTHO" );
1542 for(
int i = 0; i < terminals; ++i )
1544 if( !
readLine( aStream, line ) )
break;
1547 size_t t_pos = line.find(
'T' );
1548 if( t_pos != std::string::npos )
1553 std::stringstream iss_t( line );
1555 double nmx = 0.0, nmy = 0.0;
1557 if( iss_t >> term.
x >> term.
y >> nmx >> nmy >> term.
name )
1567 for(
int i = 0; i < stacks; ++i )
1572 std::stringstream iss_pad( line );
1575 int stack_lines = 0;
1576 iss_pad >> token >> pin_idx >> stack_lines;
1578 if( token !=
"PAD" )
1582 std::string plated_token;
1583 bool default_plated =
true;
1584 double header_drill = 0.0;
1586 if( iss_pad >> plated_token )
1588 if( plated_token ==
"P" )
1589 default_plated =
true;
1590 else if( plated_token ==
"N" )
1591 default_plated =
false;
1599 double header_slot_ori = 0.0;
1600 double header_slot_len = 0.0;
1601 double header_slot_off = 0.0;
1603 if( iss_pad >> header_slot_ori >> header_slot_len >> header_slot_off )
1608 std::vector<PAD_STACK_LAYER> stack;
1610 for(
int j = 0; j < stack_lines; ++j )
1615 std::stringstream line_ss( line );
1621 if( !( line_ss >> layer >> size >> shape ) )
1625 layer_data.
layer = layer;
1626 layer_data.
sizeA = size;
1627 layer_data.
sizeB = size;
1628 layer_data.
shape = shape;
1629 layer_data.
plated = default_plated;
1630 layer_data.
drill = header_drill;
1641 else if( shape ==
"S" )
1645 double corner = 0.0;
1647 if( line_ss >> corner )
1660 else if( shape ==
"RA" || shape ==
"SA" )
1665 else if( shape ==
"A" )
1670 if( line_ss >> intd )
1673 else if( shape ==
"OF" )
1676 double ori = 0.0, length = 0.0, offset = 0.0;
1678 if( line_ss >> ori >> length >> offset )
1681 layer_data.
sizeB = length;
1685 else if( shape ==
"RF" )
1689 double ori = 0.0, length = 0.0, offset = 0.0;
1691 if( line_ss >> ori >> length >> offset )
1694 layer_data.
sizeB = length;
1697 double corner = 0.0;
1699 if( line_ss >> corner )
1713 else if( shape ==
"RT" || shape ==
"ST" )
1716 double ori = 0.0, outsize = 0.0, spkwid = 0.0;
1719 if( line_ss >> ori >> outsize >> spkwid >> spknum )
1727 else if( shape ==
"O" || shape ==
"OC" )
1733 else if( shape ==
"RC" )
1737 double ori = 0.0, length = 0.0, offset = 0.0, corner = 0.0;
1739 if( line_ss >> ori >> length >> offset )
1742 layer_data.
sizeB = length;
1745 if( line_ss >> corner )
1762 std::vector<std::string> remaining;
1763 std::string token_rem;
1765 while( line_ss >> token_rem )
1766 remaining.push_back( token_rem );
1769 if( !remaining.empty() )
1775 -1.0,
"pad layer drill" );
1777 if( drill_val >= 0.0 )
1779 layer_data.
drill = drill_val;
1784 if( idx < remaining.size() )
1786 if( remaining[idx] ==
"P" || remaining[idx] ==
"Y" )
1788 layer_data.
plated =
true;
1791 else if( remaining[idx] ==
"N" )
1793 layer_data.
plated =
false;
1799 if( idx + 2 < remaining.size() )
1810 stack.push_back( layer_data );
1823 ROUTE* current_route =
nullptr;
1824 TRACK current_track;
1825 bool in_track =
false;
1826 bool prev_is_plane_connection =
false;
1828 int last_plane_connection_layer = 0;
1829 double last_plane_connection_width = 0;
1830 bool last_plane_on_copper =
false;
1831 std::string default_via_name;
1835 if( line[0] ==
'*' )
1837 if( line.rfind(
"*SIGNAL*", 0 ) == 0 )
1839 if( in_track && current_route )
1841 current_route->
tracks.push_back( current_track );
1842 current_track.
points.clear();
1846 prev_is_plane_connection =
false;
1848 std::istringstream iss( line );
1852 std::string net_name;
1856 default_via_name.clear();
1858 while( iss >> token )
1860 if( !token.empty() && token.back() ==
';' )
1864 default_via_name = token;
1869 current_route->
net_name = net_name;
1880 if( !isdigit( line[0] ) && line[0] !=
'-' && line[0] !=
'+' )
1882 if( in_track && current_route )
1884 current_route->
tracks.push_back( current_track );
1885 current_track.
points.clear();
1889 prev_is_plane_connection =
false;
1894 std::istringstream pin_iss( line );
1895 std::string pin_token;
1897 while( pin_iss >> pin_token )
1899 size_t dot_pos = pin_token.find(
'.' );
1901 if( dot_pos != std::string::npos )
1904 pin.ref_des = pin_token.substr( 0, dot_pos );
1905 pin.pin_name = pin_token.substr( dot_pos + 1 );
1910 for(
const auto& existing : current_route->
pins )
1912 if( existing.ref_des ==
pin.ref_des &&
1913 existing.pin_name ==
pin.pin_name )
1921 current_route->
pins.push_back(
pin );
1929 std::istringstream iss( line );
1934 iss >> pt.
x >> pt.
y >> layer >> width >> flags;
1946 std::string via_name;
1947 std::string arc_dir;
1953 bool is_unrouted = ( layer == 0 );
1954 bool is_plane_connection = is_unrouted;
1957 bool has_teardrop =
false;
1958 bool has_jumper =
false;
1959 bool has_power =
false;
1961 while( iss >> token )
1964 if( token ==
"CW" || token ==
"CCW" )
1973 if( token ==
"POWER" )
1983 if( token ==
"THERMAL" )
1994 if( token ==
"TEARDROP" )
1996 has_teardrop =
true;
1997 std::string td_token;
1999 while( iss >> td_token )
2001 if( td_token ==
"P" )
2007 std::streampos pos = iss.tellg();
2010 if( iss >> td_flags )
2020 else if( td_token ==
"N" )
2025 std::streampos pos = iss.tellg();
2028 if( iss >> td_flags )
2042 if( td_token ==
"CW" || td_token ==
"CCW" )
2044 else if( td_token ==
"POWER" )
2049 via_name = td_token;
2051 else if( td_token ==
"THERMAL" )
2054 via_name = td_token;
2065 std::streampos pos = iss.tellg();
2066 std::string jumper_flag;
2068 if( iss >> jumper_flag )
2070 if( jumper_flag ==
"S" || jumper_flag ==
"E" )
2073 jumper.
name = token;
2074 jumper.
is_start = ( jumper_flag ==
"S" );
2093 if( token ==
"REUSE" || token ==
".REUSE." )
2096 std::string instance;
2104 if( !arc_dir.empty() )
2120 int effective_layer = layer;
2121 bool is_pad_connection = ( layer == 65 );
2125 if( is_unrouted && in_track )
2126 effective_layer = current_track.
layer;
2131 if( !via_name.empty() && current_route )
2134 via.name = via_name;
2135 via.location = { pt.
x, pt.
y };
2136 current_route->
vias.push_back(
via );
2144 if( has_power && via_name.empty() && !is_unrouted && !is_pad_connection && current_route )
2148 if( !default_via_name.empty() )
2149 implicit_via.
name = default_via_name;
2154 current_route->
vias.push_back( implicit_via );
2158 if( has_teardrop && current_route )
2160 current_route->
teardrops.push_back( teardrop );
2164 if( has_jumper && current_route )
2166 current_route->
jumpers.push_back( jumper );
2172 if( is_plane_connection && prev_is_plane_connection )
2181 last_plane_connection_pt = pt;
2182 last_plane_connection_layer = effective_layer;
2183 last_plane_connection_width = width;
2184 last_plane_on_copper =
true;
2187 prev_is_plane_connection =
true;
2191 if( is_plane_connection && !prev_is_plane_connection )
2197 current_track.
points.push_back( pt );
2199 if( current_route && current_track.
points.size() > 1 )
2200 current_route->
tracks.push_back( current_track );
2202 current_track.
points.clear();
2209 last_plane_on_copper = !is_unrouted;
2211 if( last_plane_on_copper )
2213 last_plane_connection_pt = pt;
2214 last_plane_connection_layer = effective_layer;
2215 last_plane_connection_width = width;
2218 prev_is_plane_connection =
true;
2222 if( !is_plane_connection && prev_is_plane_connection )
2226 if( in_track && current_route && current_track.
points.size() > 1 )
2227 current_route->
tracks.push_back( current_track );
2229 prev_is_plane_connection =
false;
2231 if( is_pad_connection )
2237 current_track.
points.clear();
2239 if( last_plane_on_copper && last_plane_connection_layer == effective_layer )
2241 current_track.
layer = effective_layer;
2242 current_track.
width = std::max( width, last_plane_connection_width );
2243 current_track.
points.push_back( last_plane_connection_pt );
2244 current_track.
points.push_back( pt );
2250 if( !has_power && via_name.empty() && current_route && last_plane_on_copper &&
2251 std::abs( pt.
x - last_plane_connection_pt.
x ) < 0.001 &&
2252 std::abs( pt.
y - last_plane_connection_pt.
y ) < 0.001 )
2256 if( !default_via_name.empty() )
2257 implicit_via.
name = default_via_name;
2262 current_route->
vias.push_back( implicit_via );
2265 current_track.
layer = effective_layer;
2266 current_track.
width = width;
2267 current_track.
points.push_back( pt );
2270 last_plane_on_copper =
false;
2277 if( is_pad_connection )
2279 if( in_track && !current_track.
points.empty() )
2281 current_track.
points.push_back( pt );
2283 if( current_route && current_track.
points.size() > 1 )
2284 current_route->
tracks.push_back( current_track );
2286 current_track.
points.clear();
2294 prev_is_plane_connection =
false;
2298 current_track.
layer = effective_layer;
2299 current_track.
width = width;
2300 current_track.
points.clear();
2301 current_track.
points.push_back( pt );
2306 bool layer_changed = ( effective_layer != current_track.
layer );
2307 bool width_changed = (
std::abs( width - current_track.
width ) > 0.001 );
2309 if( layer_changed || width_changed )
2312 bool connect =
true;
2314 if( layer_changed && via_name.empty() )
2316 bool same_location =
2317 ( pt.
x == current_track.
points.back().x &&
2318 pt.
y == current_track.
points.back().y );
2324 if( !has_power && current_route )
2328 default_via_name.empty() ?
"STANDARDVIA" : default_via_name;
2330 current_route->
vias.push_back( implicit_via );
2333 else if( !has_power )
2343 current_track.
points.push_back( pt );
2347 current_route->
tracks.push_back( current_track );
2352 current_track.
layer = effective_layer;
2353 current_track.
width = width;
2354 current_track.
points.clear();
2355 current_track.
points.push_back( prev_pt );
2359 current_track.
points.push_back( pt );
2364 if( in_track && current_route )
2366 current_route->
tracks.push_back( current_track );
2376 if( line[0] ==
'*' )
2385 std::istringstream iss( line );
2394 std::string mirrored;
2396 text.mirrored = ( mirrored ==
"M" );
2406 if( token ==
".REUSE." )
2408 iss >>
text.reuse_instance;
2414 if( iss >> token && token ==
".REUSE." )
2416 iss >>
text.reuse_instance;
2425 std::istringstream fiss( line );
2426 std::string font_style_part;
2428 fiss >> font_style_part;
2430 size_t colon_pos = font_style_part.find(
':' );
2432 if( colon_pos != std::string::npos )
2434 text.font_style = font_style_part.substr( 0, colon_pos );
2435 std::string remaining = font_style_part.substr( colon_pos + 1 );
2437 size_t second_colon = remaining.find(
':' );
2439 if( second_colon != std::string::npos )
2442 remaining.substr( 0, second_colon ), 0.0,
"font height" );
2444 remaining.substr( second_colon + 1 ), 0.0,
"font descent" );
2453 text.font_style = font_style_part;
2457 size_t bracket_start = line.find(
'<' );
2458 size_t bracket_end = line.find(
'>' );
2460 if( bracket_start != std::string::npos && bracket_end != std::string::npos )
2462 text.font_face = line.substr( bracket_start + 1, bracket_end - bracket_start - 1 );
2467 std::getline( fiss, rest );
2469 if( !rest.empty() && rest[0] ==
' ' )
2470 rest = rest.substr( 1 );
2472 text.font_face = rest;
2482 while( ( pos = line.find(
"\\n", pos ) ) != std::string::npos )
2484 line.replace( pos, 2,
"\n" );
2490 std::replace( line.begin(), line.end(),
'_',
'\n' );
2492 text.content = line;
2506 if( line[0] ==
'*' )
2512 std::istringstream iss( line );
2513 std::string
name, type;
2514 double xloc = 0.0, yloc = 0.0;
2516 iss >>
name >> type >> xloc >> yloc >> pieces;
2519 for(
int i = 0; i < pieces; ++i )
2524 if( line[0] ==
'*' )
2530 std::istringstream piss( line );
2531 std::string shape_type;
2534 int linestyle = 0, level = 0;
2535 piss >> shape_type >> corners >> width >> linestyle >> level;
2538 if( shape_type ==
"CLOSED" || shape_type ==
"OPEN" || shape_type ==
"BRDCLS" )
2542 polyline.
width = width;
2543 polyline.
closed = ( shape_type ==
"CLOSED" || shape_type ==
"BRDCLS" );
2545 for(
int j = 0; j < corners; ++j )
2550 if( line[0] ==
'*' )
2556 std::istringstream ciss( line );
2557 double dx = 0.0, dy = 0.0;
2562 int startAngleTenths = 0, deltaAngleTenths = 0;
2563 double bboxMinX = 0.0, bboxMinY = 0.0, bboxMaxX = 0.0, bboxMaxY = 0.0;
2565 if( ciss >> startAngleTenths >> deltaAngleTenths
2566 >> bboxMinX >> bboxMinY >> bboxMaxX >> bboxMaxY )
2568 double cx = ( bboxMinX + bboxMaxX ) / 2.0;
2569 double cy = ( bboxMinY + bboxMaxY ) / 2.0;
2570 double radius = ( bboxMaxX - bboxMinX ) / 2.0;
2571 double startAngle = startAngleTenths / 10.0;
2572 double deltaAngle = deltaAngleTenths / 10.0;
2574 double startAngleRad = startAngle *
M_PI / 180.0;
2575 double startX = cx +
radius * std::cos( startAngleRad );
2576 double startY = cy +
radius * std::sin( startAngleRad );
2578 double endAngleRad = ( startAngle + deltaAngle ) *
M_PI / 180.0;
2579 double endX = cx +
radius * std::cos( endAngleRad );
2580 double endY = cy +
radius * std::sin( endAngleRad );
2582 polyline.
points.emplace_back( xloc + startX, yloc + startY );
2588 arc.start_angle = startAngle;
2589 arc.delta_angle = deltaAngle;
2591 polyline.
points.emplace_back( xloc + endX, yloc + endY, arc );
2595 polyline.
points.emplace_back( xloc + dx, yloc + dy );
2599 if( !polyline.
points.empty() )
2602 else if( shape_type ==
"CIRCLE" || shape_type ==
"BRDCIR" )
2607 polyline.
width = width;
2610 double x1 = 0.0, y1 = 0.0, x2 = 0.0, y2 = 0.0;
2614 std::istringstream c1( line );
2618 if( corners >= 2 &&
readLine( aStream, line ) )
2620 std::istringstream c2( line );
2625 double cx = xloc + ( x1 + x2 ) / 2.0;
2626 double cy = yloc + ( y1 + y2 ) / 2.0;
2627 double radius = std::sqrt( ( x2 - x1 ) * ( x2 - x1 ) + ( y2 - y1 ) * ( y2 - y1 ) ) / 2.0;
2634 arc.start_angle = 0.0;
2635 arc.delta_angle = 360.0;
2639 if( !polyline.
points.empty() )
2645 for(
int j = 0; j < corners; ++j )
2650 if( line[0] ==
'*' )
2667 if( line[0] ==
'*' )
2674 std::istringstream iss( line );
2675 std::string
name, type;
2676 double xloc = 0.0, yloc = 0.0;
2677 int pieces = 0, flags = 0, textCount = 0;
2678 std::string signame;
2680 iss >>
name >> type >> xloc >> yloc >> pieces >> flags;
2685 if( iss >> textCount )
2696 std::string reuse_instance, reuse_signal;
2700 if( line.find(
".REUSE." ) != std::string::npos )
2702 std::istringstream riss( line );
2703 std::string reuse_keyword;
2704 riss >> reuse_keyword >> reuse_instance >> reuse_signal;
2712 if( type ==
"BOARD" )
2714 for(
int i=0; i<pieces; ++i )
2716 if( !
readLine( aStream, line ) )
break;
2719 std::istringstream piss( line );
2720 std::string shape_type;
2723 int piece_flags = 0;
2725 piss >> shape_type >> corners >> width >> piece_flags >> level;
2727 if( shape_type ==
"CLOSED" || shape_type ==
"OPEN" || shape_type ==
"BRDCLS" )
2731 polyline.
width = width;
2732 polyline.
closed = ( shape_type ==
"CLOSED" || shape_type ==
"BRDCLS" );
2734 for(
int j = 0; j < corners; ++j )
2739 if( line[0] ==
'*' )
2745 std::istringstream ciss( line );
2746 double dx = 0.0, dy = 0.0;
2751 int startAngleTenths = 0, deltaAngleTenths = 0;
2752 double bboxMinX = 0.0, bboxMinY = 0.0, bboxMaxX = 0.0, bboxMaxY = 0.0;
2754 if( ciss >> startAngleTenths >> deltaAngleTenths
2755 >> bboxMinX >> bboxMinY >> bboxMaxX >> bboxMaxY )
2757 double cx = ( bboxMinX + bboxMaxX ) / 2.0;
2758 double cy = ( bboxMinY + bboxMaxY ) / 2.0;
2759 double radius = ( bboxMaxX - bboxMinX ) / 2.0;
2760 double startAngle = startAngleTenths / 10.0;
2761 double deltaAngle = deltaAngleTenths / 10.0;
2763 double startAngleRad = startAngle *
M_PI / 180.0;
2764 double startX = cx +
radius * std::cos( startAngleRad );
2765 double startY = cy +
radius * std::sin( startAngleRad );
2767 double endAngleRad = ( startAngle + deltaAngle ) *
M_PI / 180.0;
2768 double endX = cx +
radius * std::cos( endAngleRad );
2769 double endY = cy +
radius * std::sin( endAngleRad );
2771 polyline.
points.emplace_back( xloc + startX, yloc + startY );
2777 arc.start_angle = startAngle;
2778 arc.delta_angle = deltaAngle;
2780 polyline.
points.emplace_back( xloc + endX, yloc + endY, arc );
2784 polyline.
points.emplace_back( xloc + dx, yloc + dy );
2788 if( !polyline.
points.empty() )
2791 else if( shape_type ==
"CIRCLE" || shape_type ==
"BRDCIR" )
2794 double x1 = 0.0, y1 = 0.0, x2 = 0.0, y2 = 0.0;
2798 std::istringstream c1( line );
2802 if( corners >= 2 &&
readLine( aStream, line ) )
2804 std::istringstream c2( line );
2808 double cx = xloc + ( x1 + x2 ) / 2.0;
2809 double cy = yloc + ( y1 + y2 ) / 2.0;
2810 double radius = std::sqrt( ( x2 - x1 ) * ( x2 - x1 ) +
2811 ( y2 - y1 ) * ( y2 - y1 ) ) / 2.0;
2815 polyline.
width = width;
2822 arc.start_angle = 0.0;
2823 arc.delta_angle = 360.0;
2827 if( !polyline.
points.empty() )
2832 for(
int j=0; j<corners; ++j )
2834 if( !
readLine( aStream, line ) )
break;
2840 else if(
name.rfind(
"DIM", 0 ) == 0 && type ==
"LINES" )
2860 double baspnt1_x = 0, baspnt1_y = 0;
2861 double baspnt2_x = 0, baspnt2_y = 0;
2862 double arwln_x = 0, arwln_y = 0;
2863 int baspnt_count = 0;
2864 bool hasArwln =
false;
2866 for(
int i = 0; i < pieces; ++i )
2871 if( line[0] ==
'*' )
2877 std::istringstream piss( line );
2878 std::string shape_type;
2881 int piece_flags = 0;
2883 piss >> shape_type >> corners >> width >> piece_flags >> level;
2887 for(
int j = 0; j < corners; ++j )
2892 if( line[0] ==
'*' )
2898 std::istringstream ciss( line );
2899 double dx = 0.0, dy = 0.0;
2904 if( shape_type ==
"BASPNT" && j == 0 )
2906 if( baspnt_count == 0 )
2908 baspnt1_x = xloc + dx;
2909 baspnt1_y = yloc + dy;
2911 else if( baspnt_count == 1 )
2913 baspnt2_x = xloc + dx;
2914 baspnt2_y = yloc + dy;
2921 if( shape_type ==
"ARWLN1" && j == 0 )
2923 arwln_x = xloc + dx;
2924 arwln_y = yloc + dy;
2931 if( baspnt_count >= 2 )
2935 double dx =
std::abs( baspnt2_x - baspnt1_x );
2936 double dy =
std::abs( baspnt2_y - baspnt1_y );
2937 bool isHorizontal = dx > dy;
2956 dim.
points.push_back( pt1 );
2957 dim.
points.push_back( pt2 );
2962 for(
int t = 0; t < textCount; ++t )
2967 if( line[0] ==
'*' )
2973 std::istringstream tiss( line );
2974 double tx = 0.0, ty = 0.0;
2986 double theight = 0.0, twidth = 0.0;
2987 tiss >> trot >> tlayer >> theight >> twidth;
3008 if( !dim.
points.empty() )
3011 else if( type ==
"KEEPOUT" || type ==
"RESTRICTVIA" || type ==
"RESTRICTROUTE"
3012 || type ==
"RESTRICTAREA" || type ==
"PLACEMENT_KEEPOUT" )
3018 if( type ==
"KEEPOUT" || type ==
"RESTRICTAREA" )
3025 else if( type ==
"RESTRICTVIA" )
3032 else if( type ==
"RESTRICTROUTE" )
3039 else if( type ==
"PLACEMENT_KEEPOUT" )
3048 for(
int i = 0; i < pieces; ++i )
3053 if( line[0] ==
'*' )
3061 std::istringstream piss( line );
3062 std::string shape_type;
3065 int piece_flags = 0;
3067 std::string restrictions;
3068 piss >> shape_type >> corners >> width >> piece_flags >> level >> restrictions;
3071 keepout.
layers.push_back( level );
3077 if( !restrictions.empty() )
3080 bool has_restriction_codes =
false;
3082 for(
char c : restrictions )
3084 if( std::isalpha( c ) )
3086 has_restriction_codes =
true;
3091 if( has_restriction_codes )
3102 for(
char c : restrictions )
3143 if( shape_type ==
"KPTCIR" )
3146 double x1 = 0.0, y1 = 0.0, x2 = 0.0, y2 = 0.0;
3150 std::istringstream c1( line );
3154 if( corners >= 2 &&
readLine( aStream, line ) )
3156 std::istringstream c2( line );
3161 double cx = xloc + ( x1 + x2 ) / 2.0;
3162 double cy = yloc + ( y1 + y2 ) / 2.0;
3163 double radius = std::sqrt( ( x2 - x1 ) * ( x2 - x1 ) +
3164 ( y2 - y1 ) * ( y2 - y1 ) ) / 2.0;
3171 arc.start_angle = 0.0;
3172 arc.delta_angle = 360.0;
3179 for(
int j = 0; j < corners; ++j )
3184 if( line[0] ==
'*' )
3190 std::istringstream ciss( line );
3191 double dx = 0.0, dy = 0.0;
3196 int startAngleTenths = 0, deltaAngleTenths = 0;
3197 double bboxMinX = 0.0, bboxMinY = 0.0, bboxMaxX = 0.0, bboxMaxY = 0.0;
3199 if( ciss >> startAngleTenths >> deltaAngleTenths
3200 >> bboxMinX >> bboxMinY >> bboxMaxX >> bboxMaxY )
3202 double cx = ( bboxMinX + bboxMaxX ) / 2.0;
3203 double cy = ( bboxMinY + bboxMaxY ) / 2.0;
3204 double radius = ( bboxMaxX - bboxMinX ) / 2.0;
3205 double startAngle = startAngleTenths / 10.0;
3206 double deltaAngle = deltaAngleTenths / 10.0;
3208 double startAngleRad = startAngle *
M_PI / 180.0;
3209 double startX = cx +
radius * std::cos( startAngleRad );
3210 double startY = cy +
radius * std::sin( startAngleRad );
3212 double endAngleRad = ( startAngle + deltaAngle ) *
M_PI / 180.0;
3213 double endX = cx +
radius * std::cos( endAngleRad );
3214 double endY = cy +
radius * std::sin( endAngleRad );
3216 keepout.
outline.emplace_back( xloc + startX, yloc + startY );
3222 arc.start_angle = startAngle;
3223 arc.delta_angle = deltaAngle;
3225 keepout.
outline.emplace_back( xloc + endX, yloc + endY, arc );
3229 keepout.
outline.emplace_back( xloc + dx, yloc + dy );
3235 if( !keepout.
outline.empty() )
3238 else if( type ==
"COPPER" || type ==
"COPCUT" )
3244 for(
int i = 0; i < pieces; ++i )
3249 if( line[0] ==
'*' )
3258 std::istringstream piss( line );
3259 std::string shape_type;
3262 int piece_flags = 0;
3264 piss >> shape_type >> corners >> width >> piece_flags >> level;
3268 copper.
layer = level;
3269 copper.
width = width;
3272 copper.
filled = ( shape_type ==
"COPCLS" || shape_type ==
"COPCIR" );
3273 copper.
is_cutout = ( shape_type ==
"COPCUT" || shape_type ==
"COPCCO" ||
3274 shape_type ==
"CIRCUR" || type ==
"COPCUT" );
3277 if( shape_type ==
"COPCIR" || shape_type ==
"COPCCO" || shape_type ==
"CIRCUR" )
3280 double x1 = 0.0, y1 = 0.0, x2 = 0.0, y2 = 0.0;
3284 std::istringstream c1( line );
3288 if( corners >= 2 &&
readLine( aStream, line ) )
3290 std::istringstream c2( line );
3294 double cx = xloc + ( x1 + x2 ) / 2.0;
3295 double cy = yloc + ( y1 + y2 ) / 2.0;
3296 double radius = std::sqrt( ( x2 - x1 ) * ( x2 - x1 ) +
3297 ( y2 - y1 ) * ( y2 - y1 ) ) / 2.0;
3303 arc.start_angle = 0.0;
3304 arc.delta_angle = 360.0;
3311 for(
int j = 0; j < corners; ++j )
3316 if( line[0] ==
'*' )
3322 std::istringstream ciss( line );
3323 double dx = 0.0, dy = 0.0;
3328 int startAngleTenths = 0, deltaAngleTenths = 0;
3329 double bboxMinX = 0.0, bboxMinY = 0.0, bboxMaxX = 0.0, bboxMaxY = 0.0;
3331 if( ciss >> startAngleTenths >> deltaAngleTenths
3332 >> bboxMinX >> bboxMinY >> bboxMaxX >> bboxMaxY )
3334 double cx = ( bboxMinX + bboxMaxX ) / 2.0;
3335 double cy = ( bboxMinY + bboxMaxY ) / 2.0;
3336 double radius = ( bboxMaxX - bboxMinX ) / 2.0;
3337 double startAngle = startAngleTenths / 10.0;
3338 double deltaAngle = deltaAngleTenths / 10.0;
3340 double startAngleRad = startAngle *
M_PI / 180.0;
3341 double startX = cx +
radius * std::cos( startAngleRad );
3342 double startY = cy +
radius * std::sin( startAngleRad );
3344 double endAngleRad = ( startAngle + deltaAngle ) *
M_PI / 180.0;
3345 double endX = cx +
radius * std::cos( endAngleRad );
3346 double endY = cy +
radius * std::sin( endAngleRad );
3348 copper.
outline.emplace_back( xloc + startX, yloc + startY );
3354 arc.start_angle = startAngle;
3355 arc.delta_angle = deltaAngle;
3357 copper.
outline.emplace_back( xloc + endX, yloc + endY, arc );
3361 copper.
outline.emplace_back( xloc + dx, yloc + dy );
3370 else if( type ==
"LINES" )
3373 for(
int i = 0; i < pieces; ++i )
3378 if( line[0] ==
'*' )
3385 std::istringstream piss( line );
3386 std::string shape_type;
3389 int piece_flags = 0;
3391 piss >> shape_type >> corners >> width >> piece_flags >> level;
3395 graphic.
layer = level;
3396 graphic.
width = width;
3400 graphic.
closed = ( shape_type ==
"CLOSED" || shape_type ==
"CIRCLE" );
3402 if( shape_type ==
"CIRCLE" )
3405 double x1 = 0.0, y1 = 0.0, x2 = 0.0, y2 = 0.0;
3409 std::istringstream c1( line );
3413 if( corners >= 2 &&
readLine( aStream, line ) )
3415 std::istringstream c2( line );
3419 double cx = xloc + ( x1 + x2 ) / 2.0;
3420 double cy = yloc + ( y1 + y2 ) / 2.0;
3421 double radius = std::sqrt( ( x2 - x1 ) * ( x2 - x1 ) +
3422 ( y2 - y1 ) * ( y2 - y1 ) ) / 2.0;
3428 arc.start_angle = 0.0;
3429 arc.delta_angle = 360.0;
3436 for(
int j = 0; j < corners; ++j )
3441 if( line[0] ==
'*' )
3447 std::istringstream ciss( line );
3448 double dx = 0.0, dy = 0.0;
3452 int startAngleTenths = 0, deltaAngleTenths = 0;
3453 double bboxMinX = 0.0, bboxMinY = 0.0, bboxMaxX = 0.0, bboxMaxY = 0.0;
3455 if( ciss >> startAngleTenths >> deltaAngleTenths
3456 >> bboxMinX >> bboxMinY >> bboxMaxX >> bboxMaxY )
3458 double cx = ( bboxMinX + bboxMaxX ) / 2.0;
3459 double cy = ( bboxMinY + bboxMaxY ) / 2.0;
3460 double radius = ( bboxMaxX - bboxMinX ) / 2.0;
3461 double startAngle = startAngleTenths / 10.0;
3462 double deltaAngle = deltaAngleTenths / 10.0;
3464 double startAngleRad = startAngle *
M_PI / 180.0;
3465 double startX = cx +
radius * std::cos( startAngleRad );
3466 double startY = cy +
radius * std::sin( startAngleRad );
3468 double endAngleRad = ( startAngle + deltaAngle ) *
M_PI / 180.0;
3469 double endX = cx +
radius * std::cos( endAngleRad );
3470 double endY = cy +
radius * std::sin( endAngleRad );
3472 graphic.
points.emplace_back( xloc + startX, yloc + startY );
3478 arc.start_angle = startAngle;
3479 arc.delta_angle = deltaAngle;
3481 graphic.
points.emplace_back( xloc + endX, yloc + endY, arc );
3485 graphic.
points.emplace_back( xloc + dx, yloc + dy );
3490 if( !graphic.
points.empty() )
3497 for(
int i = 0; i < pieces; ++i )
3502 if( line[0] ==
'*' )
3508 std::istringstream piss( line );
3509 std::string shape_type;
3511 piss >> shape_type >> corners;
3513 for(
int j = 0; j < corners; ++j )
3518 if( line[0] ==
'*' )
3529 for(
int t = 0; t < textCount; ++t )
3534 if( line[0] ==
'*' )
3540 std::istringstream tiss( line );
3554 text.location.x += xloc;
3555 text.location.y += yloc;
3557 std::string mirrored;
3559 text.mirrored = ( mirrored ==
"M" );
3566 if( line[0] ==
'*' )
3572 size_t bracket_start = line.find(
'<' );
3573 size_t bracket_end = line.find(
'>' );
3575 if( bracket_start != std::string::npos && bracket_end != std::string::npos )
3576 text.font_face = line.substr( bracket_start + 1, bracket_end - bracket_start - 1 );
3578 std::istringstream fiss( line );
3579 std::string font_style_part;
3580 fiss >> font_style_part;
3582 size_t colon_pos = font_style_part.find(
':' );
3584 if( colon_pos != std::string::npos )
3585 text.font_style = font_style_part.substr( 0, colon_pos );
3587 text.font_style = font_style_part;
3593 if( line[0] ==
'*' )
3599 text.content = line;
3629 if( line[0] ==
'*' )
3639 if( line.rfind(
"G ", 0 ) == 0 && currentPartType )
3641 std::istringstream gss( line );
3642 std::string g_keyword;
3643 int gateSwap = 0, pinCount = 0;
3644 gss >> g_keyword >> gateSwap >> pinCount;
3648 currentPartType->
gates.push_back( gate );
3649 currentGate = ¤tPartType->
gates.back();
3654 if( line.rfind(
"SIGPIN", 0 ) == 0 && currentPartType )
3656 std::istringstream sss( line );
3657 std::string keyword;
3672 if( line.find(
'.' ) != std::string::npos && currentPartType )
3677 std::stringstream check_ss( line );
3678 std::string first_token;
3679 check_ss >> first_token;
3683 for(
char c : first_token )
3696 std::stringstream ss( line );
3699 while( ss >> token )
3702 std::vector<std::string> parts;
3706 while( ( pos = token.find(
'.', start ) ) != std::string::npos )
3708 parts.push_back( token.substr( start, pos - start ) );
3712 parts.push_back( token.substr( start ) );
3714 if( parts.size() >= 3 )
3720 bool isNumericSecond = !parts[1].empty() &&
3721 std::all_of( parts[1].begin(), parts[1].
end(), ::isdigit );
3723 if( currentGate && parts[2].size() == 1 && !isNumericSecond )
3730 if( !parts[2].
empty() )
3731 gpin.
elec_type = parsePinElecType( parts[2][0] );
3733 if( parts.size() >= 4 )
3736 currentGate->
pins.push_back( gpin );
3738 else if( isNumericSecond )
3753 if( line[0] ==
'{' && currentPartType )
3757 if( line.empty() || line[0] ==
'}' )
3760 if( line[0] ==
'*' )
3766 std::string attrName, attrValue;
3768 if( line[0] ==
'"' )
3770 size_t endQuote = line.find(
'"', 1 );
3772 if( endQuote != std::string::npos )
3774 attrName = line.substr( 1, endQuote - 1 );
3775 attrValue = line.substr( endQuote + 1 );
3780 std::istringstream attrSS( line );
3782 std::getline( attrSS >> std::ws, attrValue );
3785 if( !attrValue.empty() && attrValue[0] ==
' ' )
3786 attrValue = attrValue.substr( 1 );
3788 if( !attrName.empty() && !attrValue.empty() )
3789 currentPartType->
attributes[attrName] = attrValue;
3795 if( line[0] ==
'{' || line[0] ==
'}' )
3799 std::stringstream ss( line );
3800 std::string
name, decal;
3801 ss >>
name >> decal;
3803 if( !
name.empty() &&
name[0] !=
'G' )
3810 currentGate =
nullptr;
3823 if( line[0] ==
'*' )
3829 std::stringstream ss( line );
3830 std::string keyword;
3833 if( keyword ==
"TYPE" )
3835 std::string typename_val;
3836 std::getline( ss, typename_val );
3838 if( !typename_val.empty() && typename_val[0] ==
' ' )
3839 typename_val = typename_val.substr( 1 );
3842 block.
name = typename_val;
3846 else if( keyword ==
"TIMESTAMP" && currentBlock )
3852 else if( keyword ==
"PART_NAMING" && currentBlock )
3855 std::getline( ss, naming );
3857 if( !naming.empty() && naming[0] ==
' ' )
3858 naming = naming.substr( 1 );
3862 else if( keyword ==
"PART" && currentBlock )
3864 std::string partname;
3865 std::getline( ss, partname );
3867 if( !partname.empty() && partname[0] ==
' ' )
3868 partname = partname.substr( 1 );
3870 currentBlock->
part_names.push_back( partname );
3872 else if( keyword ==
"NET_NAMING" && currentBlock )
3875 std::getline( ss, naming );
3877 if( !naming.empty() && naming[0] ==
' ' )
3878 naming = naming.substr( 1 );
3882 else if( keyword ==
"NET" && currentBlock )
3885 std::string netname;
3888 std::getline( ss, netname );
3890 if( !netname.empty() && netname[0] ==
' ' )
3891 netname = netname.substr( 1 );
3894 net.
merge = ( merge_flag == 1 );
3896 currentBlock->
nets.push_back( net );
3898 else if( keyword ==
"REUSE" && currentBlock )
3903 std::string next_token;
3906 if( next_token ==
"PREFIX" || next_token ==
"SUFFIX" )
3913 else if( next_token ==
"START" || next_token ==
"INCREMENT" )
3920 else if( next_token ==
"NEXT" )
3926 if( next_token ==
"PREFIX" || next_token ==
"SUFFIX" )
3930 instance.
net_naming = next_token +
" " + param;
3932 else if( next_token ==
"START" || next_token ==
"INCREMENT" )
3936 instance.
net_naming = next_token +
" " + num;
3938 else if( next_token ==
"NEXT" )
3943 std::string glued_str;
3946 instance.
glued = ( glued_str ==
"Y" || glued_str ==
"YES" || glued_str ==
"1" );
3947 currentBlock->
instances.push_back( instance );
3956 CLUSTER* currentCluster =
nullptr;
3960 if( line[0] ==
'*' )
3966 std::stringstream ss( line );
3967 std::string firstToken;
3972 if( firstToken.empty() )
3976 bool isNumeric = !firstToken.empty() &&
3977 std::all_of( firstToken.begin(), firstToken.end(), ::isdigit );
3991 cluster.
name =
"Cluster_" + firstToken;
3996 else if( currentCluster )
4000 if( firstToken.find(
'.' ) != std::string::npos )
4008 currentCluster->
net_names.push_back( firstToken );
4016 if( item.find(
'.' ) != std::string::npos )
4019 currentCluster->
net_names.push_back( item );
4032 if( line[0] ==
'*' )
4040 std::stringstream ss( line );
4041 std::string
name, flags;
4042 double minlen = 0.0, maxlen = 0.0, lenincr = 0.0;
4044 std::string padstack, end_padstack;
4046 if( !( ss >>
name >> flags >> minlen >> maxlen >> lenincr >> lcount >> padstack ) )
4060 for(
char c : flags )
4066 case 'W': jumper.
wirebond =
true;
break;
4068 case 'G': jumper.
glued =
true;
break;
4074 for(
int i = 0; i < lcount; ++i )
4082 std::stringstream ss_attr( line );
4083 std::string visible_str, mirrored_str, right_reading_str;
4088 attr.
visible = ( visible_str ==
"VALUE" || visible_str ==
"FULL_NAME" ||
4089 visible_str ==
"NAME" || visible_str ==
"FULL_BOTH" ||
4090 visible_str ==
"BOTH" );
4091 attr.
mirrored = ( mirrored_str ==
"M" || mirrored_str ==
"1" );
4092 ss_attr >> right_reading_str;
4093 attr.
right_reading = ( right_reading_str ==
"Y" || right_reading_str ==
"ORTHO" );
4102 jumper.
labels.push_back( attr );
4116 if( line[0] ==
'*' )
4122 std::stringstream ss( line );
4134 ss >>
tp.x >>
tp.y >>
tp.side >>
tp.net_name >>
tp.symbol_name;
4136 if( !
tp.net_name.empty() )
4148 bool inClass =
false;
4152 if( line[0] ==
'*' )
4155 if( inClass && !currentClass.
name.empty() )
4162 std::stringstream ss( line );
4170 if( token ==
"CLASS" || token ==
"NETCLASS" )
4173 if( inClass && !currentClass.
name.empty() )
4178 ss >> currentClass.
name;
4181 else if( token ==
"CLEARANCE" && inClass )
4185 else if( token ==
"TRACKWIDTH" && inClass )
4189 else if( token ==
"VIASIZE" && inClass )
4193 else if( token ==
"VIADRILL" && inClass )
4197 else if( token ==
"DIFFPAIRGAP" && inClass )
4201 else if( token ==
"DIFFPAIRWIDTH" && inClass )
4205 else if( token ==
"NET" && inClass )
4208 std::string netName;
4211 if( !netName.empty() )
4212 currentClass.
net_names.push_back( netName );
4214 else if( !token.empty() && token[0] !=
'#' )
4217 if( !inClass || ( inClass && currentClass.
name.empty() ) )
4220 if( inClass && !currentClass.
name.empty() )
4224 currentClass.
name = token;
4231 if( inClass && !currentClass.
name.empty() )
4242 if( line[0] ==
'*' )
4248 std::stringstream ss( line );
4264 if( token ==
"DIFFPAIR" || token ==
"PAIR" )
4270 std::string posNet, negNet;
4271 ss >> posNet >> negNet;
4273 if( !posNet.empty() )
4276 if( !negNet.empty() )
4280 double gap = 0.0, width = 0.0;
4288 if( !dp.
name.empty() )
4303 else if( ( token ==
"WIDTH" || token ==
"TRACKWIDTH" ) && !
m_diff_pairs.empty() )
4315 int currentLayerNum = -1;
4317 bool inLayerBlock =
false;
4321 if( typeStr ==
"ROUTING" )
4323 else if( typeStr ==
"PLANE" )
4325 else if( typeStr ==
"MIXED" )
4327 else if( typeStr ==
"UNASSIGNED" )
4329 else if( typeStr ==
"SOLDER_MASK" )
4331 else if( typeStr ==
"PASTE_MASK" )
4333 else if( typeStr ==
"SILK_SCREEN" )
4335 else if( typeStr ==
"ASSEMBLY" )
4337 else if( typeStr ==
"DOCUMENTATION" )
4339 else if( typeStr ==
"DRILL" )
4350 if( line[0] ==
'*' )
4356 std::istringstream iss( line );
4371 if( inLayerBlock && braceDepth == 1 )
4373 if( currentLayerNum >= 0 )
4375 currentLayer.
number = currentLayerNum;
4385 inLayerBlock =
false;
4386 currentLayerNum = -1;
4390 if( braceDepth <= 0 )
4396 if( token ==
"LAYER" )
4401 if( !iss.fail() && layerNum >= 0 )
4404 currentLayerNum = layerNum;
4406 currentLayer.
number = layerNum;
4408 inLayerBlock =
true;
4411 else if( token ==
"LAYER_NAME" && inLayerBlock )
4415 std::getline( iss >> std::ws,
name );
4418 else if( token ==
"LAYER_TYPE" && inLayerBlock )
4420 std::string typeStr;
4422 currentLayer.
layer_type = parseLayerType( typeStr );
4424 else if( token ==
"LAYER_THICKNESS" && inLayerBlock )
4428 else if( token ==
"COPPER_THICKNESS" && inLayerBlock )
4432 else if( token ==
"DIELECTRIC" && inLayerBlock )
4454 bool inDifPair =
false;
4455 bool inNetClassData =
false;
4456 bool inNetClass =
false;
4457 bool inRuleSet =
false;
4458 bool inRuleSetFor =
false;
4459 bool inClearanceRule =
false;
4460 int ruleSetDepth = -1;
4461 int clearanceRuleDepth = -1;
4462 bool foundDefaultRules =
false;
4463 bool isDefaultRuleSet =
false;
4464 std::string ruleSetNetClass;
4474 if( line[0] ==
'*' && braceDepth == 0 )
4481 for(
char c : line )
4489 if( braceDepth == 0 && inDifPair )
4492 if( !currentDiffPair.
name.empty() )
4499 if( braceDepth == 1 && inNetClass )
4502 if( !currentNetClass.
name.empty() )
4509 if( braceDepth == 0 && inNetClassData )
4512 inNetClassData =
false;
4515 if( inClearanceRule && braceDepth < clearanceRuleDepth )
4517 inClearanceRule =
false;
4519 if( isDefaultRuleSet )
4522 == std::numeric_limits<double>::max() )
4531 == std::numeric_limits<double>::max() )
4537 foundDefaultRules =
true;
4541 if( inRuleSetFor && braceDepth < ruleSetDepth + 1 )
4542 inRuleSetFor =
false;
4544 if( inRuleSet && braceDepth < ruleSetDepth )
4547 isDefaultRuleSet =
false;
4548 ruleSetNetClass.clear();
4553 std::istringstream iss( line );
4559 if( token ==
"LAYER" )
4561 std::string secondToken;
4564 if( secondToken ==
"DATA" )
4572 if( token ==
"NET_CLASS" )
4574 std::string secondToken;
4577 if( secondToken ==
"DATA" )
4580 inNetClassData =
true;
4582 else if( inNetClassData && !secondToken.empty() )
4586 if( inNetClass && !currentNetClass.
name.empty() )
4590 currentNetClass.
name = secondToken;
4594 else if( inNetClass && token ==
"NET" )
4597 std::string netName;
4600 if( !netName.empty() )
4601 currentNetClass.
net_names.push_back( netName );
4603 else if( token ==
"RULE_SET" )
4605 std::string ruleNum;
4609 ruleSetDepth = braceDepth;
4610 ruleSetNetClass.clear();
4611 isDefaultRuleSet = ( ruleNum ==
"(1)" && !foundDefaultRules );
4613 else if( inRuleSet && !inClearanceRule && token ==
"FOR" )
4615 inRuleSetFor =
true;
4617 else if( inRuleSetFor && token ==
"NET_CLASS" )
4619 iss >> ruleSetNetClass;
4621 else if( inRuleSet && token ==
"CLEARANCE_RULE" )
4623 inClearanceRule =
true;
4624 clearanceRuleDepth = braceDepth;
4626 if( isDefaultRuleSet )
4628 m_design_rules.default_clearance = std::numeric_limits<double>::max();
4629 m_design_rules.copper_edge_clearance = std::numeric_limits<double>::max();
4632 else if( inClearanceRule )
4637 if( !iss.fail() && val > 0.0 )
4639 if( isDefaultRuleSet )
4641 if( token ==
"MIN_TRACK_WIDTH" )
4645 else if( token ==
"REC_TRACK_WIDTH" )
4649 else if( token ==
"DRILL_TO_DRILL" )
4653 else if( token ==
"OUTLINE_TO_TRACK" || token ==
"OUTLINE_TO_VIA"
4654 || token ==
"OUTLINE_TO_PAD" || token ==
"OUTLINE_TO_COPPER"
4655 || token ==
"OUTLINE_TO_SMD" )
4660 else if( token.rfind(
"SAME_NET_", 0 ) == 0 || token ==
"BODY_TO_BODY"
4661 || token ==
"MAX_TRACK_WIDTH"
4662 || token.rfind(
"TEXT_TO_", 0 ) == 0
4663 || token.rfind(
"COPPER_TO_", 0 ) == 0 )
4669 else if( token ==
"TRACK_TO_TRACK" || token.rfind(
"VIA_TO_", 0 ) == 0
4670 || token.rfind(
"PAD_TO_", 0 ) == 0
4671 || token.rfind(
"SMD_TO_", 0 ) == 0
4672 || token.rfind(
"DRILL_TO_", 0 ) == 0 )
4678 else if( !ruleSetNetClass.empty() )
4682 if( nc.name == ruleSetNetClass )
4684 if( token ==
"REC_TRACK_WIDTH" )
4685 nc.track_width = val;
4686 else if( token ==
"TRACK_TO_TRACK" )
4695 else if( token ==
"DIF_PAIR" )
4698 if( inDifPair && !currentDiffPair.
name.empty() )
4702 iss >> currentDiffPair.
name;
4705 else if( inDifPair )
4707 if( token ==
"NET" )
4709 std::string netName;
4718 else if( token ==
"GAP" )
4720 iss >> currentDiffPair.
gap;
4722 else if( token ==
"WIDTH" )
4724 iss >> currentDiffPair.
width;
4726 else if( token ==
"CONNECTION" )
4732 else if( token ==
"ASSOCIATED" )
4735 std::string keyword, netName;
4736 iss >> keyword >> netName;
4738 if( keyword ==
"NET" )
4750 if( token ==
"PART" && !inDifPair && !inNetClass )
4752 std::string partName;
4755 if( !partName.empty() )
4758 int savedDepth = braceDepth;
4766 if( line[0] ==
'}' )
4769 if( line[0] ==
'{' )
4772 if( line[0] ==
'*' )
4779 std::string attrName, attrValue;
4781 if( line[0] ==
'"' )
4783 size_t endQuote = line.find(
'"', 1 );
4785 if( endQuote != std::string::npos )
4787 attrName = line.substr( 1, endQuote - 1 );
4788 attrValue = line.substr( endQuote + 1 );
4793 std::istringstream attrSS( line );
4795 std::getline( attrSS >> std::ws, attrValue );
4798 if( !attrValue.empty() && attrValue[0] ==
' ' )
4799 attrValue = attrValue.substr( 1 );
4801 if( !attrName.empty() && !attrValue.empty() )
4802 attrs[attrName] = attrValue;
4806 braceDepth = savedDepth;
4823 if(
m_design_rules.default_clearance == std::numeric_limits<double>::max() )
4826 if(
m_design_rules.copper_edge_clearance == std::numeric_limits<double>::max() )
4833 std::vector<LAYER_INFO> layers;
4837 if( layerCount < 1 )
4841 auto isCopperLayer = [&](
int num ) {
4842 return num >= 1 && num <= layerCount;
4846 auto getLayerDef = [&](
int num ) ->
const LAYER_INFO* {
4848 return it !=
m_layer_defs.end() ? &it->second :
nullptr;
4852 for(
int i = 1; i <= layerCount; ++i )
4858 layers.push_back( *parsed );
4866 info.is_copper =
true;
4867 info.required =
true;
4871 else if( i == layerCount )
4872 info.name =
"Bottom";
4874 info.name =
"Inner " + std::to_string( i - 1 );
4876 layers.push_back(
info );
4883 if( !isCopperLayer( num ) )
4885 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)
wxString result
Test unit parsing edge cases and error handling.