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 );
1370 int linestyle = 0, level = 0;
1372 if( !( iss2 >> type >> corners >> width ) )
1406 decal.
items.push_back( item );
1412 if( type.find(
"COP" ) == 0 )
1414 std::string remaining;
1415 std::getline( iss2, remaining );
1418 std::istringstream rem_ss( remaining );
1419 int pinnum_val = -1;
1421 if( rem_ss >> pinnum_val )
1422 item.
pinnum = pinnum_val;
1426 if( type.find(
"KPT" ) == 0 )
1428 std::string restrictions;
1430 if( iss2 >> restrictions )
1434 for(
int j = 0; j < corners; ++j )
1439 std::stringstream iss3( line );
1440 double px = 0.0, py = 0.0;
1442 if( !( iss3 >> px >> py ) )
1448 int startAngleTenths = 0, deltaAngleTenths = 0;
1449 double bboxMinX = 0.0, bboxMinY = 0.0, bboxMaxX = 0.0, bboxMaxY = 0.0;
1451 if( iss3 >> startAngleTenths >> deltaAngleTenths
1452 >> bboxMinX >> bboxMinY >> bboxMaxX >> bboxMaxY )
1454 double cx = ( bboxMinX + bboxMaxX ) / 2.0;
1455 double cy = ( bboxMinY + bboxMaxY ) / 2.0;
1456 double radius = ( bboxMaxX - bboxMinX ) / 2.0;
1457 double startAngle = startAngleTenths / 10.0;
1458 double deltaAngle = deltaAngleTenths / 10.0;
1461 double startAngleRad = startAngle *
M_PI / 180.0;
1462 double startX = cx +
radius * std::cos( startAngleRad );
1463 double startY = cy +
radius * std::sin( startAngleRad );
1466 double endAngleRad = ( startAngle + deltaAngle ) *
M_PI / 180.0;
1467 double endX = cx +
radius * std::cos( endAngleRad );
1468 double endY = cy +
radius * std::sin( endAngleRad );
1471 item.
points.emplace_back( startX, startY );
1477 arc.start_angle = startAngle;
1478 arc.delta_angle = deltaAngle;
1481 item.
points.emplace_back( endX, endY, arc );
1485 item.
points.emplace_back( px, py );
1489 decal.
items.push_back( item );
1505 for(
int i = 0; i < text_cnt + labels; ++i )
1507 std::string line1, line2, line3;
1508 if( !
readLine( aStream, line1 ) )
break;
1509 if( !
readLine( aStream, line2 ) )
break;
1510 if( !
readLine( aStream, line3 ) )
break;
1514 std::stringstream ss( line1 );
1515 std::string type_token;
1519 std::string mirrored_str, right_reading_str;
1524 attr.
visible = ( type_token ==
"VALUE" || type_token ==
"FULL_NAME"
1525 || type_token ==
"NAME" || type_token ==
"FULL_BOTH"
1526 || type_token ==
"BOTH" );
1527 attr.
mirrored = ( mirrored_str ==
"M" );
1528 ss >> right_reading_str;
1529 attr.
right_reading = ( right_reading_str ==
"Y" || right_reading_str ==
"ORTHO" );
1543 for(
int i = 0; i < terminals; ++i )
1545 if( !
readLine( aStream, line ) )
break;
1548 size_t t_pos = line.find(
'T' );
1549 if( t_pos != std::string::npos )
1554 std::stringstream iss_t( line );
1556 double nmx = 0.0, nmy = 0.0;
1558 if( iss_t >> term.
x >> term.
y >> nmx >> nmy >> term.
name )
1568 for(
int i = 0; i < stacks; ++i )
1573 std::stringstream iss_pad( line );
1576 int stack_lines = 0;
1577 iss_pad >> token >> pin_idx >> stack_lines;
1579 if( token !=
"PAD" )
1583 std::string plated_token;
1584 bool default_plated =
true;
1585 double header_drill = 0.0;
1587 if( iss_pad >> plated_token )
1589 if( plated_token ==
"P" )
1590 default_plated =
true;
1591 else if( plated_token ==
"N" )
1592 default_plated =
false;
1600 double header_slot_ori = 0.0;
1601 double header_slot_len = 0.0;
1602 double header_slot_off = 0.0;
1604 if( iss_pad >> header_slot_ori >> header_slot_len >> header_slot_off )
1609 std::vector<PAD_STACK_LAYER> stack;
1611 for(
int j = 0; j < stack_lines; ++j )
1616 std::stringstream line_ss( line );
1622 if( !( line_ss >> layer >> size >> shape ) )
1626 layer_data.
layer = layer;
1627 layer_data.
sizeA = size;
1628 layer_data.
sizeB = size;
1629 layer_data.
shape = shape;
1630 layer_data.
plated = default_plated;
1631 layer_data.
drill = header_drill;
1642 else if( shape ==
"S" )
1646 double corner = 0.0;
1648 if( line_ss >> corner )
1661 else if( shape ==
"RA" || shape ==
"SA" )
1666 else if( shape ==
"A" )
1671 if( line_ss >> intd )
1674 else if( shape ==
"OF" )
1677 double ori = 0.0, length = 0.0, offset = 0.0;
1679 if( line_ss >> ori >> length >> offset )
1682 layer_data.
sizeB = length;
1686 else if( shape ==
"RF" )
1690 double ori = 0.0, length = 0.0, offset = 0.0;
1692 if( line_ss >> ori >> length >> offset )
1695 layer_data.
sizeB = length;
1698 double corner = 0.0;
1700 if( line_ss >> corner )
1714 else if( shape ==
"RT" || shape ==
"ST" )
1717 double ori = 0.0, outsize = 0.0, spkwid = 0.0;
1720 if( line_ss >> ori >> outsize >> spkwid >> spknum )
1728 else if( shape ==
"O" || shape ==
"OC" )
1734 else if( shape ==
"RC" )
1738 double ori = 0.0, length = 0.0, offset = 0.0, corner = 0.0;
1740 if( line_ss >> ori >> length >> offset )
1743 layer_data.
sizeB = length;
1746 if( line_ss >> corner )
1763 std::vector<std::string> remaining;
1764 std::string token_rem;
1766 while( line_ss >> token_rem )
1767 remaining.push_back( token_rem );
1770 if( !remaining.empty() )
1776 -1.0,
"pad layer drill" );
1778 if( drill_val >= 0.0 )
1780 layer_data.
drill = drill_val;
1785 if( idx < remaining.size() )
1787 if( remaining[idx] ==
"P" || remaining[idx] ==
"Y" )
1789 layer_data.
plated =
true;
1792 else if( remaining[idx] ==
"N" )
1794 layer_data.
plated =
false;
1800 if( idx + 2 < remaining.size() )
1811 stack.push_back( layer_data );
1824 ROUTE* current_route =
nullptr;
1825 TRACK current_track;
1826 bool in_track =
false;
1827 bool prev_is_plane_connection =
false;
1829 int last_plane_connection_layer = 0;
1830 double last_plane_connection_width = 0;
1831 bool last_plane_on_copper =
false;
1832 std::string default_via_name;
1836 if( line[0] ==
'*' )
1838 if( line.rfind(
"*SIGNAL*", 0 ) == 0 )
1840 if( in_track && current_route )
1842 current_route->
tracks.push_back( current_track );
1843 current_track.
points.clear();
1847 prev_is_plane_connection =
false;
1849 std::istringstream iss( line );
1853 std::string net_name;
1857 default_via_name.clear();
1859 while( iss >> token )
1861 if( !token.empty() && token.back() ==
';' )
1865 default_via_name = token;
1870 current_route->
net_name = net_name;
1881 if( !isdigit( line[0] ) && line[0] !=
'-' && line[0] !=
'+' )
1883 if( in_track && current_route )
1885 current_route->
tracks.push_back( current_track );
1886 current_track.
points.clear();
1890 prev_is_plane_connection =
false;
1895 std::istringstream pin_iss( line );
1896 std::string pin_token;
1898 while( pin_iss >> pin_token )
1900 size_t dot_pos = pin_token.find(
'.' );
1902 if( dot_pos != std::string::npos )
1905 pin.ref_des = pin_token.substr( 0, dot_pos );
1906 pin.pin_name = pin_token.substr( dot_pos + 1 );
1911 for(
const auto& existing : current_route->
pins )
1913 if( existing.ref_des ==
pin.ref_des &&
1914 existing.pin_name ==
pin.pin_name )
1922 current_route->
pins.push_back(
pin );
1930 std::istringstream iss( line );
1935 iss >> pt.
x >> pt.
y >> layer >> width >> flags;
1947 std::string via_name;
1948 std::string arc_dir;
1954 bool is_unrouted = ( layer == 0 );
1955 bool is_plane_connection = is_unrouted;
1958 bool has_teardrop =
false;
1959 bool has_jumper =
false;
1960 bool has_power =
false;
1962 while( iss >> token )
1965 if( token ==
"CW" || token ==
"CCW" )
1974 if( token ==
"POWER" )
1984 if( token ==
"THERMAL" )
1995 if( token ==
"TEARDROP" )
1997 has_teardrop =
true;
1998 std::string td_token;
2000 while( iss >> td_token )
2002 if( td_token ==
"P" )
2008 std::streampos pos = iss.tellg();
2021 else if( td_token ==
"N" )
2026 std::streampos pos = iss.tellg();
2043 if( td_token ==
"CW" || td_token ==
"CCW" )
2045 else if( td_token ==
"POWER" )
2050 via_name = td_token;
2052 else if( td_token ==
"THERMAL" )
2055 via_name = td_token;
2066 std::streampos pos = iss.tellg();
2067 std::string jumper_flag;
2069 if( iss >> jumper_flag )
2071 if( jumper_flag ==
"S" || jumper_flag ==
"E" )
2074 jumper.
name = token;
2075 jumper.
is_start = ( jumper_flag ==
"S" );
2094 if( token ==
"REUSE" || token ==
".REUSE." )
2097 std::string instance;
2105 if( !arc_dir.empty() )
2121 int effective_layer = layer;
2122 bool is_pad_connection = ( layer == 65 );
2126 if( is_unrouted && in_track )
2127 effective_layer = current_track.
layer;
2132 if( !via_name.empty() && current_route )
2135 via.name = via_name;
2136 via.location = { pt.
x, pt.
y };
2137 current_route->
vias.push_back(
via );
2145 if( has_power && via_name.empty() && !is_unrouted && !is_pad_connection && current_route )
2149 if( !default_via_name.empty() )
2150 implicit_via.
name = default_via_name;
2155 current_route->
vias.push_back( implicit_via );
2159 if( has_teardrop && current_route )
2161 current_route->
teardrops.push_back( teardrop );
2165 if( has_jumper && current_route )
2167 current_route->
jumpers.push_back( jumper );
2173 if( is_plane_connection && prev_is_plane_connection )
2182 last_plane_connection_pt = pt;
2183 last_plane_connection_layer = effective_layer;
2184 last_plane_connection_width = width;
2185 last_plane_on_copper =
true;
2188 prev_is_plane_connection =
true;
2192 if( is_plane_connection && !prev_is_plane_connection )
2198 current_track.
points.push_back( pt );
2200 if( current_route && current_track.
points.size() > 1 )
2201 current_route->
tracks.push_back( current_track );
2203 current_track.
points.clear();
2210 last_plane_on_copper = !is_unrouted;
2212 if( last_plane_on_copper )
2214 last_plane_connection_pt = pt;
2215 last_plane_connection_layer = effective_layer;
2216 last_plane_connection_width = width;
2219 prev_is_plane_connection =
true;
2223 if( !is_plane_connection && prev_is_plane_connection )
2227 if( in_track && current_route && current_track.
points.size() > 1 )
2228 current_route->
tracks.push_back( current_track );
2230 prev_is_plane_connection =
false;
2232 if( is_pad_connection )
2238 current_track.
points.clear();
2240 if( last_plane_on_copper && last_plane_connection_layer == effective_layer )
2242 current_track.
layer = effective_layer;
2243 current_track.
width = std::max( width, last_plane_connection_width );
2244 current_track.
points.push_back( last_plane_connection_pt );
2245 current_track.
points.push_back( pt );
2251 if( !has_power && via_name.empty() && current_route && last_plane_on_copper &&
2252 std::abs( pt.
x - last_plane_connection_pt.
x ) < 0.001 &&
2253 std::abs( pt.
y - last_plane_connection_pt.
y ) < 0.001 )
2257 if( !default_via_name.empty() )
2258 implicit_via.
name = default_via_name;
2263 current_route->
vias.push_back( implicit_via );
2266 current_track.
layer = effective_layer;
2267 current_track.
width = width;
2268 current_track.
points.push_back( pt );
2271 last_plane_on_copper =
false;
2278 if( is_pad_connection )
2280 if( in_track && !current_track.
points.empty() )
2282 current_track.
points.push_back( pt );
2284 if( current_route && current_track.
points.size() > 1 )
2285 current_route->
tracks.push_back( current_track );
2287 current_track.
points.clear();
2295 prev_is_plane_connection =
false;
2299 current_track.
layer = effective_layer;
2300 current_track.
width = width;
2301 current_track.
points.clear();
2302 current_track.
points.push_back( pt );
2307 bool layer_changed = ( effective_layer != current_track.
layer );
2308 bool width_changed = (
std::abs( width - current_track.
width ) > 0.001 );
2310 if( layer_changed || width_changed )
2313 bool connect =
true;
2315 if( layer_changed && via_name.empty() )
2317 bool same_location =
2318 ( pt.
x == current_track.
points.back().x &&
2319 pt.
y == current_track.
points.back().y );
2325 if( !has_power && current_route )
2329 default_via_name.empty() ?
"STANDARDVIA" : default_via_name;
2331 current_route->
vias.push_back( implicit_via );
2334 else if( !has_power )
2344 current_track.
points.push_back( pt );
2348 current_route->
tracks.push_back( current_track );
2353 current_track.
layer = effective_layer;
2354 current_track.
width = width;
2355 current_track.
points.clear();
2356 current_track.
points.push_back( prev_pt );
2360 current_track.
points.push_back( pt );
2365 if( in_track && current_route )
2367 current_route->
tracks.push_back( current_track );
2377 if( line[0] ==
'*' )
2386 std::istringstream iss( line );
2395 std::string mirrored;
2397 text.mirrored = ( mirrored ==
"M" );
2407 if( token ==
".REUSE." )
2409 iss >>
text.reuse_instance;
2415 if( iss >> token && token ==
".REUSE." )
2417 iss >>
text.reuse_instance;
2426 std::istringstream fiss( line );
2427 std::string font_style_part;
2429 fiss >> font_style_part;
2431 size_t colon_pos = font_style_part.find(
':' );
2433 if( colon_pos != std::string::npos )
2435 text.font_style = font_style_part.substr( 0, colon_pos );
2436 std::string remaining = font_style_part.substr( colon_pos + 1 );
2438 size_t second_colon = remaining.find(
':' );
2440 if( second_colon != std::string::npos )
2443 remaining.substr( 0, second_colon ), 0.0,
"font height" );
2445 remaining.substr( second_colon + 1 ), 0.0,
"font descent" );
2454 text.font_style = font_style_part;
2458 size_t bracket_start = line.find(
'<' );
2459 size_t bracket_end = line.find(
'>' );
2461 if( bracket_start != std::string::npos && bracket_end != std::string::npos )
2463 text.font_face = line.substr( bracket_start + 1, bracket_end - bracket_start - 1 );
2468 std::getline( fiss, rest );
2470 if( !rest.empty() && rest[0] ==
' ' )
2471 rest = rest.substr( 1 );
2473 text.font_face = rest;
2483 while( ( pos = line.find(
"\\n", pos ) ) != std::string::npos )
2485 line.replace( pos, 2,
"\n" );
2491 std::replace( line.begin(), line.end(),
'_',
'\n' );
2493 text.content = line;
2507 if( line[0] ==
'*' )
2513 std::istringstream iss( line );
2514 std::string
name, type;
2515 double xloc = 0.0, yloc = 0.0;
2517 iss >>
name >> type >> xloc >> yloc >> pieces;
2520 for(
int i = 0; i < pieces; ++i )
2525 if( line[0] ==
'*' )
2531 std::istringstream piss( line );
2532 std::string shape_type;
2535 int linestyle = 0, level = 0;
2536 piss >> shape_type >> corners >> width >> linestyle >> level;
2539 if( shape_type ==
"CLOSED" || shape_type ==
"OPEN" || shape_type ==
"BRDCLS" )
2543 polyline.
width = width;
2544 polyline.
closed = ( shape_type ==
"CLOSED" || shape_type ==
"BRDCLS" );
2546 for(
int j = 0; j < corners; ++j )
2551 if( line[0] ==
'*' )
2557 std::istringstream ciss( line );
2558 double dx = 0.0, dy = 0.0;
2563 int startAngleTenths = 0, deltaAngleTenths = 0;
2564 double bboxMinX = 0.0, bboxMinY = 0.0, bboxMaxX = 0.0, bboxMaxY = 0.0;
2566 if( ciss >> startAngleTenths >> deltaAngleTenths
2567 >> bboxMinX >> bboxMinY >> bboxMaxX >> bboxMaxY )
2569 double cx = ( bboxMinX + bboxMaxX ) / 2.0;
2570 double cy = ( bboxMinY + bboxMaxY ) / 2.0;
2571 double radius = ( bboxMaxX - bboxMinX ) / 2.0;
2572 double startAngle = startAngleTenths / 10.0;
2573 double deltaAngle = deltaAngleTenths / 10.0;
2575 double startAngleRad = startAngle *
M_PI / 180.0;
2576 double startX = cx +
radius * std::cos( startAngleRad );
2577 double startY = cy +
radius * std::sin( startAngleRad );
2579 double endAngleRad = ( startAngle + deltaAngle ) *
M_PI / 180.0;
2580 double endX = cx +
radius * std::cos( endAngleRad );
2581 double endY = cy +
radius * std::sin( endAngleRad );
2583 polyline.
points.emplace_back( xloc + startX, yloc + startY );
2589 arc.start_angle = startAngle;
2590 arc.delta_angle = deltaAngle;
2592 polyline.
points.emplace_back( xloc + endX, yloc + endY, arc );
2596 polyline.
points.emplace_back( xloc + dx, yloc + dy );
2600 if( !polyline.
points.empty() )
2603 else if( shape_type ==
"CIRCLE" || shape_type ==
"BRDCIR" )
2608 polyline.
width = width;
2611 double x1 = 0.0, y1 = 0.0, x2 = 0.0, y2 = 0.0;
2615 std::istringstream c1( line );
2619 if( corners >= 2 &&
readLine( aStream, line ) )
2621 std::istringstream c2( line );
2626 double cx = xloc + ( x1 + x2 ) / 2.0;
2627 double cy = yloc + ( y1 + y2 ) / 2.0;
2628 double radius = std::sqrt( ( x2 - x1 ) * ( x2 - x1 ) + ( y2 - y1 ) * ( y2 - y1 ) ) / 2.0;
2635 arc.start_angle = 0.0;
2636 arc.delta_angle = 360.0;
2640 if( !polyline.
points.empty() )
2646 for(
int j = 0; j < corners; ++j )
2651 if( line[0] ==
'*' )
2668 if( line[0] ==
'*' )
2675 std::istringstream iss( line );
2676 std::string
name, type;
2677 double xloc = 0.0, yloc = 0.0;
2678 int pieces = 0, flags = 0, textCount = 0;
2679 std::string signame;
2681 iss >>
name >> type >> xloc >> yloc >> pieces >> flags;
2686 if( iss >> textCount )
2697 std::string reuse_instance, reuse_signal;
2701 if( line.find(
".REUSE." ) != std::string::npos )
2703 std::istringstream riss( line );
2704 std::string reuse_keyword;
2705 riss >> reuse_keyword >> reuse_instance >> reuse_signal;
2713 if( type ==
"BOARD" )
2715 for(
int i=0; i<pieces; ++i )
2717 if( !
readLine( aStream, line ) )
break;
2720 std::istringstream piss( line );
2721 std::string shape_type;
2726 piss >> shape_type >> corners >> width >> flags >> level;
2728 if( shape_type ==
"CLOSED" || shape_type ==
"OPEN" || shape_type ==
"BRDCLS" )
2732 polyline.
width = width;
2733 polyline.
closed = ( shape_type ==
"CLOSED" || shape_type ==
"BRDCLS" );
2735 for(
int j = 0; j < corners; ++j )
2740 if( line[0] ==
'*' )
2746 std::istringstream ciss( line );
2747 double dx = 0.0, dy = 0.0;
2752 int startAngleTenths = 0, deltaAngleTenths = 0;
2753 double bboxMinX = 0.0, bboxMinY = 0.0, bboxMaxX = 0.0, bboxMaxY = 0.0;
2755 if( ciss >> startAngleTenths >> deltaAngleTenths
2756 >> bboxMinX >> bboxMinY >> bboxMaxX >> bboxMaxY )
2758 double cx = ( bboxMinX + bboxMaxX ) / 2.0;
2759 double cy = ( bboxMinY + bboxMaxY ) / 2.0;
2760 double radius = ( bboxMaxX - bboxMinX ) / 2.0;
2761 double startAngle = startAngleTenths / 10.0;
2762 double deltaAngle = deltaAngleTenths / 10.0;
2764 double startAngleRad = startAngle *
M_PI / 180.0;
2765 double startX = cx +
radius * std::cos( startAngleRad );
2766 double startY = cy +
radius * std::sin( startAngleRad );
2768 double endAngleRad = ( startAngle + deltaAngle ) *
M_PI / 180.0;
2769 double endX = cx +
radius * std::cos( endAngleRad );
2770 double endY = cy +
radius * std::sin( endAngleRad );
2772 polyline.
points.emplace_back( xloc + startX, yloc + startY );
2778 arc.start_angle = startAngle;
2779 arc.delta_angle = deltaAngle;
2781 polyline.
points.emplace_back( xloc + endX, yloc + endY, arc );
2785 polyline.
points.emplace_back( xloc + dx, yloc + dy );
2789 if( !polyline.
points.empty() )
2792 else if( shape_type ==
"CIRCLE" || shape_type ==
"BRDCIR" )
2795 double x1 = 0.0, y1 = 0.0, x2 = 0.0, y2 = 0.0;
2799 std::istringstream c1( line );
2803 if( corners >= 2 &&
readLine( aStream, line ) )
2805 std::istringstream c2( line );
2809 double cx = xloc + ( x1 + x2 ) / 2.0;
2810 double cy = yloc + ( y1 + y2 ) / 2.0;
2811 double radius = std::sqrt( ( x2 - x1 ) * ( x2 - x1 ) +
2812 ( y2 - y1 ) * ( y2 - y1 ) ) / 2.0;
2816 polyline.
width = width;
2823 arc.start_angle = 0.0;
2824 arc.delta_angle = 360.0;
2828 if( !polyline.
points.empty() )
2833 for(
int j=0; j<corners; ++j )
2835 if( !
readLine( aStream, line ) )
break;
2841 else if(
name.rfind(
"DIM", 0 ) == 0 && type ==
"LINES" )
2861 double baspnt1_x = 0, baspnt1_y = 0;
2862 double baspnt2_x = 0, baspnt2_y = 0;
2863 double arwln_x = 0, arwln_y = 0;
2864 int baspnt_count = 0;
2865 bool hasArwln =
false;
2867 for(
int i = 0; i < pieces; ++i )
2872 if( line[0] ==
'*' )
2878 std::istringstream piss( line );
2879 std::string shape_type;
2884 piss >> shape_type >> corners >> width >> flags >> level;
2888 for(
int j = 0; j < corners; ++j )
2893 if( line[0] ==
'*' )
2899 std::istringstream ciss( line );
2900 double dx = 0.0, dy = 0.0;
2905 if( shape_type ==
"BASPNT" && j == 0 )
2907 if( baspnt_count == 0 )
2909 baspnt1_x = xloc + dx;
2910 baspnt1_y = yloc + dy;
2912 else if( baspnt_count == 1 )
2914 baspnt2_x = xloc + dx;
2915 baspnt2_y = yloc + dy;
2922 if( shape_type ==
"ARWLN1" && j == 0 )
2924 arwln_x = xloc + dx;
2925 arwln_y = yloc + dy;
2932 if( baspnt_count >= 2 )
2936 double dx =
std::abs( baspnt2_x - baspnt1_x );
2937 double dy =
std::abs( baspnt2_y - baspnt1_y );
2938 bool isHorizontal = dx > dy;
2957 dim.
points.push_back( pt1 );
2958 dim.
points.push_back( pt2 );
2963 for(
int t = 0; t < textCount; ++t )
2968 if( line[0] ==
'*' )
2974 std::istringstream tiss( line );
2975 double tx = 0.0, ty = 0.0;
2987 double theight = 0.0, twidth = 0.0;
2988 tiss >> trot >> tlayer >> theight >> twidth;
3009 if( !dim.
points.empty() )
3012 else if( type ==
"KEEPOUT" || type ==
"RESTRICTVIA" || type ==
"RESTRICTROUTE"
3013 || type ==
"RESTRICTAREA" || type ==
"PLACEMENT_KEEPOUT" )
3019 if( type ==
"KEEPOUT" || type ==
"RESTRICTAREA" )
3026 else if( type ==
"RESTRICTVIA" )
3033 else if( type ==
"RESTRICTROUTE" )
3040 else if( type ==
"PLACEMENT_KEEPOUT" )
3049 for(
int i = 0; i < pieces; ++i )
3054 if( line[0] ==
'*' )
3062 std::istringstream piss( line );
3063 std::string shape_type;
3068 std::string restrictions;
3069 piss >> shape_type >> corners >> width >> flags >> level >> restrictions;
3072 keepout.
layers.push_back( level );
3078 if( !restrictions.empty() )
3081 bool has_restriction_codes =
false;
3083 for(
char c : restrictions )
3085 if( std::isalpha( c ) )
3087 has_restriction_codes =
true;
3092 if( has_restriction_codes )
3103 for(
char c : restrictions )
3144 if( shape_type ==
"KPTCIR" )
3147 double x1 = 0.0, y1 = 0.0, x2 = 0.0, y2 = 0.0;
3151 std::istringstream c1( line );
3155 if( corners >= 2 &&
readLine( aStream, line ) )
3157 std::istringstream c2( line );
3162 double cx = xloc + ( x1 + x2 ) / 2.0;
3163 double cy = yloc + ( y1 + y2 ) / 2.0;
3164 double radius = std::sqrt( ( x2 - x1 ) * ( x2 - x1 ) +
3165 ( y2 - y1 ) * ( y2 - y1 ) ) / 2.0;
3172 arc.start_angle = 0.0;
3173 arc.delta_angle = 360.0;
3180 for(
int j = 0; j < corners; ++j )
3185 if( line[0] ==
'*' )
3191 std::istringstream ciss( line );
3192 double dx = 0.0, dy = 0.0;
3197 int startAngleTenths = 0, deltaAngleTenths = 0;
3198 double bboxMinX = 0.0, bboxMinY = 0.0, bboxMaxX = 0.0, bboxMaxY = 0.0;
3200 if( ciss >> startAngleTenths >> deltaAngleTenths
3201 >> bboxMinX >> bboxMinY >> bboxMaxX >> bboxMaxY )
3203 double cx = ( bboxMinX + bboxMaxX ) / 2.0;
3204 double cy = ( bboxMinY + bboxMaxY ) / 2.0;
3205 double radius = ( bboxMaxX - bboxMinX ) / 2.0;
3206 double startAngle = startAngleTenths / 10.0;
3207 double deltaAngle = deltaAngleTenths / 10.0;
3209 double startAngleRad = startAngle *
M_PI / 180.0;
3210 double startX = cx +
radius * std::cos( startAngleRad );
3211 double startY = cy +
radius * std::sin( startAngleRad );
3213 double endAngleRad = ( startAngle + deltaAngle ) *
M_PI / 180.0;
3214 double endX = cx +
radius * std::cos( endAngleRad );
3215 double endY = cy +
radius * std::sin( endAngleRad );
3217 keepout.
outline.emplace_back( xloc + startX, yloc + startY );
3223 arc.start_angle = startAngle;
3224 arc.delta_angle = deltaAngle;
3226 keepout.
outline.emplace_back( xloc + endX, yloc + endY, arc );
3230 keepout.
outline.emplace_back( xloc + dx, yloc + dy );
3236 if( !keepout.
outline.empty() )
3239 else if( type ==
"COPPER" || type ==
"COPCUT" )
3245 for(
int i = 0; i < pieces; ++i )
3250 if( line[0] ==
'*' )
3259 std::istringstream piss( line );
3260 std::string shape_type;
3265 piss >> shape_type >> corners >> width >> flags >> level;
3269 copper.
layer = level;
3270 copper.
width = width;
3273 copper.
filled = ( shape_type ==
"COPCLS" || shape_type ==
"COPCIR" );
3274 copper.
is_cutout = ( shape_type ==
"COPCUT" || shape_type ==
"COPCCO" ||
3275 shape_type ==
"CIRCUR" || type ==
"COPCUT" );
3278 if( shape_type ==
"COPCIR" || shape_type ==
"COPCCO" || shape_type ==
"CIRCUR" )
3281 double x1 = 0.0, y1 = 0.0, x2 = 0.0, y2 = 0.0;
3285 std::istringstream c1( line );
3289 if( corners >= 2 &&
readLine( aStream, line ) )
3291 std::istringstream c2( line );
3295 double cx = xloc + ( x1 + x2 ) / 2.0;
3296 double cy = yloc + ( y1 + y2 ) / 2.0;
3297 double radius = std::sqrt( ( x2 - x1 ) * ( x2 - x1 ) +
3298 ( y2 - y1 ) * ( y2 - y1 ) ) / 2.0;
3304 arc.start_angle = 0.0;
3305 arc.delta_angle = 360.0;
3312 for(
int j = 0; j < corners; ++j )
3317 if( line[0] ==
'*' )
3323 std::istringstream ciss( line );
3324 double dx = 0.0, dy = 0.0;
3329 int startAngleTenths = 0, deltaAngleTenths = 0;
3330 double bboxMinX = 0.0, bboxMinY = 0.0, bboxMaxX = 0.0, bboxMaxY = 0.0;
3332 if( ciss >> startAngleTenths >> deltaAngleTenths
3333 >> bboxMinX >> bboxMinY >> bboxMaxX >> bboxMaxY )
3335 double cx = ( bboxMinX + bboxMaxX ) / 2.0;
3336 double cy = ( bboxMinY + bboxMaxY ) / 2.0;
3337 double radius = ( bboxMaxX - bboxMinX ) / 2.0;
3338 double startAngle = startAngleTenths / 10.0;
3339 double deltaAngle = deltaAngleTenths / 10.0;
3341 double startAngleRad = startAngle *
M_PI / 180.0;
3342 double startX = cx +
radius * std::cos( startAngleRad );
3343 double startY = cy +
radius * std::sin( startAngleRad );
3345 double endAngleRad = ( startAngle + deltaAngle ) *
M_PI / 180.0;
3346 double endX = cx +
radius * std::cos( endAngleRad );
3347 double endY = cy +
radius * std::sin( endAngleRad );
3349 copper.
outline.emplace_back( xloc + startX, yloc + startY );
3355 arc.start_angle = startAngle;
3356 arc.delta_angle = deltaAngle;
3358 copper.
outline.emplace_back( xloc + endX, yloc + endY, arc );
3362 copper.
outline.emplace_back( xloc + dx, yloc + dy );
3371 else if( type ==
"LINES" )
3374 for(
int i = 0; i < pieces; ++i )
3379 if( line[0] ==
'*' )
3386 std::istringstream piss( line );
3387 std::string shape_type;
3392 piss >> shape_type >> corners >> width >> flags >> level;
3396 graphic.
layer = level;
3397 graphic.
width = width;
3401 graphic.
closed = ( shape_type ==
"CLOSED" || shape_type ==
"CIRCLE" );
3403 if( shape_type ==
"CIRCLE" )
3406 double x1 = 0.0, y1 = 0.0, x2 = 0.0, y2 = 0.0;
3410 std::istringstream c1( line );
3414 if( corners >= 2 &&
readLine( aStream, line ) )
3416 std::istringstream c2( line );
3420 double cx = xloc + ( x1 + x2 ) / 2.0;
3421 double cy = yloc + ( y1 + y2 ) / 2.0;
3422 double radius = std::sqrt( ( x2 - x1 ) * ( x2 - x1 ) +
3423 ( y2 - y1 ) * ( y2 - y1 ) ) / 2.0;
3429 arc.start_angle = 0.0;
3430 arc.delta_angle = 360.0;
3437 for(
int j = 0; j < corners; ++j )
3442 if( line[0] ==
'*' )
3448 std::istringstream ciss( line );
3449 double dx = 0.0, dy = 0.0;
3453 int startAngleTenths = 0, deltaAngleTenths = 0;
3454 double bboxMinX = 0.0, bboxMinY = 0.0, bboxMaxX = 0.0, bboxMaxY = 0.0;
3456 if( ciss >> startAngleTenths >> deltaAngleTenths
3457 >> bboxMinX >> bboxMinY >> bboxMaxX >> bboxMaxY )
3459 double cx = ( bboxMinX + bboxMaxX ) / 2.0;
3460 double cy = ( bboxMinY + bboxMaxY ) / 2.0;
3461 double radius = ( bboxMaxX - bboxMinX ) / 2.0;
3462 double startAngle = startAngleTenths / 10.0;
3463 double deltaAngle = deltaAngleTenths / 10.0;
3465 double startAngleRad = startAngle *
M_PI / 180.0;
3466 double startX = cx +
radius * std::cos( startAngleRad );
3467 double startY = cy +
radius * std::sin( startAngleRad );
3469 double endAngleRad = ( startAngle + deltaAngle ) *
M_PI / 180.0;
3470 double endX = cx +
radius * std::cos( endAngleRad );
3471 double endY = cy +
radius * std::sin( endAngleRad );
3473 graphic.
points.emplace_back( xloc + startX, yloc + startY );
3479 arc.start_angle = startAngle;
3480 arc.delta_angle = deltaAngle;
3482 graphic.
points.emplace_back( xloc + endX, yloc + endY, arc );
3486 graphic.
points.emplace_back( xloc + dx, yloc + dy );
3491 if( !graphic.
points.empty() )
3498 for(
int i = 0; i < pieces; ++i )
3503 if( line[0] ==
'*' )
3509 std::istringstream piss( line );
3510 std::string shape_type;
3512 piss >> shape_type >> corners;
3514 for(
int j = 0; j < corners; ++j )
3519 if( line[0] ==
'*' )
3530 for(
int t = 0; t < textCount; ++t )
3535 if( line[0] ==
'*' )
3541 std::istringstream tiss( line );
3555 text.location.x += xloc;
3556 text.location.y += yloc;
3558 std::string mirrored;
3560 text.mirrored = ( mirrored ==
"M" );
3567 if( line[0] ==
'*' )
3573 size_t bracket_start = line.find(
'<' );
3574 size_t bracket_end = line.find(
'>' );
3576 if( bracket_start != std::string::npos && bracket_end != std::string::npos )
3577 text.font_face = line.substr( bracket_start + 1, bracket_end - bracket_start - 1 );
3579 std::istringstream fiss( line );
3580 std::string font_style_part;
3581 fiss >> font_style_part;
3583 size_t colon_pos = font_style_part.find(
':' );
3585 if( colon_pos != std::string::npos )
3586 text.font_style = font_style_part.substr( 0, colon_pos );
3588 text.font_style = font_style_part;
3594 if( line[0] ==
'*' )
3600 text.content = line;
3630 if( line[0] ==
'*' )
3640 if( line.rfind(
"G ", 0 ) == 0 && currentPartType )
3642 std::istringstream gss( line );
3643 std::string g_keyword;
3644 int gateSwap = 0, pinCount = 0;
3645 gss >> g_keyword >> gateSwap >> pinCount;
3649 currentPartType->
gates.push_back( gate );
3650 currentGate = ¤tPartType->
gates.back();
3655 if( line.rfind(
"SIGPIN", 0 ) == 0 && currentPartType )
3657 std::istringstream sss( line );
3658 std::string keyword;
3673 if( line.find(
'.' ) != std::string::npos && currentPartType )
3678 std::stringstream check_ss( line );
3679 std::string first_token;
3680 check_ss >> first_token;
3684 for(
char c : first_token )
3697 std::stringstream ss( line );
3700 while( ss >> token )
3703 std::vector<std::string> parts;
3707 while( ( pos = token.find(
'.', start ) ) != std::string::npos )
3709 parts.push_back( token.substr( start, pos - start ) );
3713 parts.push_back( token.substr( start ) );
3715 if( parts.size() >= 3 )
3721 bool isNumericSecond = !parts[1].empty() &&
3722 std::all_of( parts[1].begin(), parts[1].
end(), ::isdigit );
3724 if( currentGate && parts[2].size() == 1 && !isNumericSecond )
3731 if( !parts[2].
empty() )
3732 gpin.
elec_type = parsePinElecType( parts[2][0] );
3734 if( parts.size() >= 4 )
3737 currentGate->
pins.push_back( gpin );
3739 else if( isNumericSecond )
3754 if( line[0] ==
'{' && currentPartType )
3758 if( line.empty() || line[0] ==
'}' )
3761 if( line[0] ==
'*' )
3767 std::string attrName, attrValue;
3769 if( line[0] ==
'"' )
3771 size_t endQuote = line.find(
'"', 1 );
3773 if( endQuote != std::string::npos )
3775 attrName = line.substr( 1, endQuote - 1 );
3776 attrValue = line.substr( endQuote + 1 );
3781 std::istringstream attrSS( line );
3783 std::getline( attrSS >> std::ws, attrValue );
3786 if( !attrValue.empty() && attrValue[0] ==
' ' )
3787 attrValue = attrValue.substr( 1 );
3789 if( !attrName.empty() && !attrValue.empty() )
3790 currentPartType->
attributes[attrName] = attrValue;
3796 if( line[0] ==
'{' || line[0] ==
'}' )
3800 std::stringstream ss( line );
3801 std::string
name, decal;
3802 ss >>
name >> decal;
3804 if( !
name.empty() &&
name[0] !=
'G' )
3811 currentGate =
nullptr;
3824 if( line[0] ==
'*' )
3830 std::stringstream ss( line );
3831 std::string keyword;
3834 if( keyword ==
"TYPE" )
3836 std::string typename_val;
3837 std::getline( ss, typename_val );
3839 if( !typename_val.empty() && typename_val[0] ==
' ' )
3840 typename_val = typename_val.substr( 1 );
3843 block.
name = typename_val;
3847 else if( keyword ==
"TIMESTAMP" && currentBlock )
3853 else if( keyword ==
"PART_NAMING" && currentBlock )
3856 std::getline( ss, naming );
3858 if( !naming.empty() && naming[0] ==
' ' )
3859 naming = naming.substr( 1 );
3863 else if( keyword ==
"PART" && currentBlock )
3865 std::string partname;
3866 std::getline( ss, partname );
3868 if( !partname.empty() && partname[0] ==
' ' )
3869 partname = partname.substr( 1 );
3871 currentBlock->
part_names.push_back( partname );
3873 else if( keyword ==
"NET_NAMING" && currentBlock )
3876 std::getline( ss, naming );
3878 if( !naming.empty() && naming[0] ==
' ' )
3879 naming = naming.substr( 1 );
3883 else if( keyword ==
"NET" && currentBlock )
3886 std::string netname;
3889 std::getline( ss, netname );
3891 if( !netname.empty() && netname[0] ==
' ' )
3892 netname = netname.substr( 1 );
3895 net.
merge = ( merge_flag == 1 );
3897 currentBlock->
nets.push_back( net );
3899 else if( keyword ==
"REUSE" && currentBlock )
3904 std::string next_token;
3907 if( next_token ==
"PREFIX" || next_token ==
"SUFFIX" )
3914 else if( next_token ==
"START" || next_token ==
"INCREMENT" )
3921 else if( next_token ==
"NEXT" )
3927 if( next_token ==
"PREFIX" || next_token ==
"SUFFIX" )
3931 instance.
net_naming = next_token +
" " + param;
3933 else if( next_token ==
"START" || next_token ==
"INCREMENT" )
3937 instance.
net_naming = next_token +
" " + num;
3939 else if( next_token ==
"NEXT" )
3944 std::string glued_str;
3947 instance.
glued = ( glued_str ==
"Y" || glued_str ==
"YES" || glued_str ==
"1" );
3948 currentBlock->
instances.push_back( instance );
3957 CLUSTER* currentCluster =
nullptr;
3961 if( line[0] ==
'*' )
3967 std::stringstream ss( line );
3968 std::string firstToken;
3973 if( firstToken.empty() )
3977 bool isNumeric = !firstToken.empty() &&
3978 std::all_of( firstToken.begin(), firstToken.end(), ::isdigit );
3992 cluster.
name =
"Cluster_" + firstToken;
3997 else if( currentCluster )
4001 if( firstToken.find(
'.' ) != std::string::npos )
4009 currentCluster->
net_names.push_back( firstToken );
4017 if( item.find(
'.' ) != std::string::npos )
4020 currentCluster->
net_names.push_back( item );
4033 if( line[0] ==
'*' )
4041 std::stringstream ss( line );
4042 std::string
name, flags;
4043 double minlen = 0.0, maxlen = 0.0, lenincr = 0.0;
4045 std::string padstack, end_padstack;
4047 if( !( ss >>
name >> flags >> minlen >> maxlen >> lenincr >> lcount >> padstack ) )
4061 for(
char c : flags )
4067 case 'W': jumper.
wirebond =
true;
break;
4069 case 'G': jumper.
glued =
true;
break;
4075 for(
int i = 0; i < lcount; ++i )
4083 std::stringstream ss_attr( line );
4084 std::string visible_str, mirrored_str, right_reading_str;
4089 attr.
visible = ( visible_str ==
"VALUE" || visible_str ==
"FULL_NAME" ||
4090 visible_str ==
"NAME" || visible_str ==
"FULL_BOTH" ||
4091 visible_str ==
"BOTH" );
4092 attr.
mirrored = ( mirrored_str ==
"M" || mirrored_str ==
"1" );
4093 ss_attr >> right_reading_str;
4094 attr.
right_reading = ( right_reading_str ==
"Y" || right_reading_str ==
"ORTHO" );
4103 jumper.
labels.push_back( attr );
4117 if( line[0] ==
'*' )
4123 std::stringstream ss( line );
4135 ss >>
tp.x >>
tp.y >>
tp.side >>
tp.net_name >>
tp.symbol_name;
4137 if( !
tp.net_name.empty() )
4149 bool inClass =
false;
4153 if( line[0] ==
'*' )
4156 if( inClass && !currentClass.
name.empty() )
4163 std::stringstream ss( line );
4171 if( token ==
"CLASS" || token ==
"NETCLASS" )
4174 if( inClass && !currentClass.
name.empty() )
4179 ss >> currentClass.
name;
4182 else if( token ==
"CLEARANCE" && inClass )
4186 else if( token ==
"TRACKWIDTH" && inClass )
4190 else if( token ==
"VIASIZE" && inClass )
4194 else if( token ==
"VIADRILL" && inClass )
4198 else if( token ==
"DIFFPAIRGAP" && inClass )
4202 else if( token ==
"DIFFPAIRWIDTH" && inClass )
4206 else if( token ==
"NET" && inClass )
4209 std::string netName;
4212 if( !netName.empty() )
4213 currentClass.
net_names.push_back( netName );
4215 else if( !token.empty() && token[0] !=
'#' )
4218 if( !inClass || ( inClass && currentClass.
name.empty() ) )
4221 if( inClass && !currentClass.
name.empty() )
4225 currentClass.
name = token;
4232 if( inClass && !currentClass.
name.empty() )
4243 if( line[0] ==
'*' )
4249 std::stringstream ss( line );
4265 if( token ==
"DIFFPAIR" || token ==
"PAIR" )
4271 std::string posNet, negNet;
4272 ss >> posNet >> negNet;
4274 if( !posNet.empty() )
4277 if( !negNet.empty() )
4281 double gap = 0.0, width = 0.0;
4289 if( !dp.
name.empty() )
4304 else if( ( token ==
"WIDTH" || token ==
"TRACKWIDTH" ) && !
m_diff_pairs.empty() )
4316 int currentLayerNum = -1;
4318 bool inLayerBlock =
false;
4322 if( typeStr ==
"ROUTING" )
4324 else if( typeStr ==
"PLANE" )
4326 else if( typeStr ==
"MIXED" )
4328 else if( typeStr ==
"UNASSIGNED" )
4330 else if( typeStr ==
"SOLDER_MASK" )
4332 else if( typeStr ==
"PASTE_MASK" )
4334 else if( typeStr ==
"SILK_SCREEN" )
4336 else if( typeStr ==
"ASSEMBLY" )
4338 else if( typeStr ==
"DOCUMENTATION" )
4340 else if( typeStr ==
"DRILL" )
4351 if( line[0] ==
'*' )
4357 std::istringstream iss( line );
4372 if( inLayerBlock && braceDepth == 1 )
4374 if( currentLayerNum >= 0 )
4376 currentLayer.
number = currentLayerNum;
4386 inLayerBlock =
false;
4387 currentLayerNum = -1;
4391 if( braceDepth <= 0 )
4397 if( token ==
"LAYER" )
4402 if( !iss.fail() && layerNum >= 0 )
4405 currentLayerNum = layerNum;
4407 currentLayer.
number = layerNum;
4409 inLayerBlock =
true;
4412 else if( token ==
"LAYER_NAME" && inLayerBlock )
4416 std::getline( iss >> std::ws,
name );
4419 else if( token ==
"LAYER_TYPE" && inLayerBlock )
4421 std::string typeStr;
4423 currentLayer.
layer_type = parseLayerType( typeStr );
4425 else if( token ==
"LAYER_THICKNESS" && inLayerBlock )
4429 else if( token ==
"COPPER_THICKNESS" && inLayerBlock )
4433 else if( token ==
"DIELECTRIC" && inLayerBlock )
4455 bool inDifPair =
false;
4456 bool inNetClassData =
false;
4457 bool inNetClass =
false;
4458 bool inDefaultRuleSet =
false;
4459 bool inClearanceRule =
false;
4460 int defaultRuleSetDepth = -1;
4461 int clearanceRuleDepth = -1;
4462 bool foundDefaultRules =
false;
4472 if( line[0] ==
'*' && braceDepth == 0 )
4479 for(
char c : line )
4487 if( braceDepth == 0 && inDifPair )
4490 if( !currentDiffPair.
name.empty() )
4497 if( braceDepth == 1 && inNetClass )
4500 if( !currentNetClass.
name.empty() )
4507 if( braceDepth == 0 && inNetClassData )
4510 inNetClassData =
false;
4513 if( inClearanceRule && braceDepth < clearanceRuleDepth )
4515 inClearanceRule =
false;
4519 == std::numeric_limits<double>::max() )
4527 == std::numeric_limits<double>::max() )
4533 foundDefaultRules =
true;
4536 if( inDefaultRuleSet && braceDepth < defaultRuleSetDepth )
4537 inDefaultRuleSet =
false;
4541 std::istringstream iss( line );
4547 if( token ==
"LAYER" )
4549 std::string secondToken;
4552 if( secondToken ==
"DATA" )
4560 if( token ==
"NET_CLASS" )
4562 std::string secondToken;
4565 if( secondToken ==
"DATA" )
4568 inNetClassData =
true;
4570 else if( inNetClassData && !secondToken.empty() )
4574 if( inNetClass && !currentNetClass.
name.empty() )
4578 currentNetClass.
name = secondToken;
4582 else if( inNetClass && token ==
"NET" )
4585 std::string netName;
4588 if( !netName.empty() )
4589 currentNetClass.
net_names.push_back( netName );
4591 else if( token ==
"RULE_SET" && !foundDefaultRules )
4595 std::string ruleNum;
4598 if( ruleNum ==
"(1)" )
4600 inDefaultRuleSet =
true;
4601 defaultRuleSetDepth = braceDepth;
4604 else if( inDefaultRuleSet && token ==
"CLEARANCE_RULE" )
4606 inClearanceRule =
true;
4607 clearanceRuleDepth = braceDepth;
4608 m_design_rules.default_clearance = std::numeric_limits<double>::max();
4609 m_design_rules.copper_edge_clearance = std::numeric_limits<double>::max();
4611 else if( inClearanceRule )
4616 if( !iss.fail() && val > 0.0 )
4618 if( token ==
"MIN_TRACK_WIDTH" )
4622 else if( token ==
"REC_TRACK_WIDTH" )
4626 else if( token ==
"DRILL_TO_DRILL" )
4630 else if( token ==
"OUTLINE_TO_TRACK" || token ==
"OUTLINE_TO_VIA"
4631 || token ==
"OUTLINE_TO_PAD" || token ==
"OUTLINE_TO_COPPER" )
4646 else if( token ==
"DIF_PAIR" )
4649 if( inDifPair && !currentDiffPair.
name.empty() )
4653 iss >> currentDiffPair.
name;
4656 else if( inDifPair )
4658 if( token ==
"NET" )
4660 std::string netName;
4669 else if( token ==
"GAP" )
4671 iss >> currentDiffPair.
gap;
4673 else if( token ==
"WIDTH" )
4675 iss >> currentDiffPair.
width;
4677 else if( token ==
"CONNECTION" )
4683 else if( token ==
"ASSOCIATED" )
4686 std::string keyword, netName;
4687 iss >> keyword >> netName;
4689 if( keyword ==
"NET" )
4701 if( token ==
"PART" && !inDifPair && !inNetClass )
4703 std::string partName;
4706 if( !partName.empty() )
4709 int savedDepth = braceDepth;
4717 if( line[0] ==
'}' )
4720 if( line[0] ==
'{' )
4723 if( line[0] ==
'*' )
4730 std::string attrName, attrValue;
4732 if( line[0] ==
'"' )
4734 size_t endQuote = line.find(
'"', 1 );
4736 if( endQuote != std::string::npos )
4738 attrName = line.substr( 1, endQuote - 1 );
4739 attrValue = line.substr( endQuote + 1 );
4744 std::istringstream attrSS( line );
4746 std::getline( attrSS >> std::ws, attrValue );
4749 if( !attrValue.empty() && attrValue[0] ==
' ' )
4750 attrValue = attrValue.substr( 1 );
4752 if( !attrName.empty() && !attrValue.empty() )
4753 attrs[attrName] = attrValue;
4757 braceDepth = savedDepth;
4774 if(
m_design_rules.default_clearance == std::numeric_limits<double>::max() )
4777 if(
m_design_rules.copper_edge_clearance == std::numeric_limits<double>::max() )
4784 std::vector<LAYER_INFO> layers;
4788 if( layerCount < 1 )
4792 auto isCopperLayer = [&](
int num ) {
4793 return num >= 1 && num <= layerCount;
4797 auto getLayerDef = [&](
int num ) ->
const LAYER_INFO* {
4799 return it !=
m_layer_defs.end() ? &it->second :
nullptr;
4803 for(
int i = 1; i <= layerCount; ++i )
4809 layers.push_back( *parsed );
4817 info.is_copper =
true;
4818 info.required =
true;
4822 else if( i == layerCount )
4823 info.name =
"Bottom";
4825 info.name =
"Inner " + std::to_string( i - 1 );
4827 layers.push_back(
info );
4834 if( !isCopperLayer( num ) )
4836 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.