34#include <fmt/format.h>
42#include <magic_enum.hpp>
80#include <wx/mstream.h>
89constexpr double INT_LIMIT = std::numeric_limits<int>::max() - 10;
91using namespace PCB_KEYS_T;
131 for(
int i=1; i<=14; ++i )
133 std::string key =
StrPrintf(
"Inner%d.Cu", i );
144 TIME_PT curTime = CLOCK::now();
145 unsigned curLine = reader->LineNumber();
148 if(
delta > std::chrono::milliseconds( 250 ) )
167 while( ( token = NextTok() ) != T_EOF )
169 if( token == T_LEFT )
172 if( token == T_RIGHT )
189 m_netCodes.resize(
static_cast<std::size_t
>( aIndex ) + 1 );
229 else if( token == T_no )
232 Expecting(
"yes or no" );
243 bool ret = aDefaultValue;
245 if( PrevTok() == T_LEFT )
250 if(
static_cast<int>( token ) ==
DSN_RIGHT )
251 return aDefaultValue;
253 if( token == T_yes || token == T_true )
255 else if( token == T_no || token == T_false )
258 Expecting(
"yes or no" );
265 return aDefaultValue;
274 int year, month, day;
283 if( day <= 0 || month <= 0 || month > 12 ||
284 day > wxDateTime::GetNumberOfDays( (wxDateTime::Month)( month - 1 ), year ) )
291 wxDateTime date( day, (wxDateTime::Month)( month - 1 ), year, 0, 0, 0, 0 );
292 return date.FormatDate();
298 if( CurTok() != T_LEFT )
318 if( CurTok() != T_LEFT )
337 bool has_start =
false;
338 bool has_mid =
false;
339 bool has_end =
false;
341 VECTOR2I arc_start, arc_mid, arc_end;
343 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
345 if( token != T_LEFT )
371 Expecting(
"start, mid or end" );
378 Expecting(
"start" );
386 SHAPE_ARC arc( arc_start, arc_mid, arc_end, 0 );
390 if( token != T_RIGHT )
391 Expecting( T_RIGHT );
396 Expecting(
"xy or arc" );
433 return { pName, pValue };
443 for( T token = NextTok(); token != T_RIGHT; token = NextTok() )
445 if( token == T_LEFT )
454 case T_allow_two_segments:
458 case T_prefer_zone_connections:
462 case T_best_length_ratio:
472 case T_best_width_ratio:
493 Expecting(
"enabled, allow_two_segments, prefer_zone_connections, best_length_ratio, "
494 "max_length, best_width_ratio, max_width, curve_points or filter_ratio" );
502 wxCHECK_RET( CurTok() == T_effects,
503 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as EDA_TEXT." ) );
521 bool foundTextSize =
false;
524 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
526 if( token == T_LEFT )
532 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
534 if( token == T_LEFT )
541 faceName = FromUTF8();
553 foundTextSize =
true;
582 Expecting(
"face, size, line_spacing, thickness, bold, or italic" );
586 if( !faceName.IsEmpty() )
594 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
596 if( token == T_LEFT )
622 Expecting(
"left, right, top, bottom, or mirror" );
634 Expecting(
"font, justify, or hide" );
653 NeedSYMBOLorNUMBER();
654 wxString cacheText =
From_UTF8( CurText() );
657 text->SetupRenderCache( cacheText,
text->GetFont(), cacheAngle, { 0, 0 } );
659 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
661 if( token != T_LEFT )
666 if( token != T_polygon )
667 Expecting( T_polygon );
671 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
673 if( token != T_LEFT )
683 while( (token = NextTok() ) != T_RIGHT )
694 text->AddRenderCacheGlyph( poly );
701 wxCHECK_MSG( CurTok() == T_model,
nullptr,
702 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as FP_3DMODEL." ) );
707 NeedSYMBOLorNUMBER();
710 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
712 if( token == T_LEFT )
799 Expecting(
"at, hide, opacity, offset, scale, or rotate" );
818 if( CurTok() != T_LEFT )
821 if( NextTok() != T_kicad_pcb)
839 std::unique_ptr<wxArrayString> initial_comments( ReadCommentLines() );
846 if( token != T_LEFT )
868 err.Printf(
_(
"Unknown token '%s'" ), FromUTF8() );
879 std::get<2>( params ),
908 std::map<wxString, wxString> properties;
922 std::vector<BOARD_ITEM*> bulkAddedItems;
925 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
929 if( token != T_LEFT )
956 case T_generator_version:
1012 m_board->
Add( item, ADD_MODE::BULK_APPEND,
true );
1013 bulkAddedItems.push_back( item );
1018 m_board->
Add( item, ADD_MODE::BULK_APPEND,
true );
1019 bulkAddedItems.push_back( item );
1024 m_board->
Add( item, ADD_MODE::BULK_APPEND,
true );
1025 bulkAddedItems.push_back( item );
1030 m_board->
Add( item, ADD_MODE::BULK_APPEND,
true );
1031 bulkAddedItems.push_back( item );
1036 m_board->
Add( item, ADD_MODE::BULK_APPEND,
true );
1037 bulkAddedItems.push_back( item );
1042 m_board->
Add( item, ADD_MODE::BULK_APPEND,
true );
1043 bulkAddedItems.push_back( item );
1049 m_board->
Add( item, ADD_MODE::BULK_APPEND,
true );
1050 bulkAddedItems.push_back( item );
1055 m_board->
Add( item, ADD_MODE::BULK_APPEND,
true );
1056 bulkAddedItems.push_back( item );
1061 m_board->
Add( item, ADD_MODE::BULK_APPEND,
true );
1062 bulkAddedItems.push_back( item );
1075 m_board->
Add( item, ADD_MODE::BULK_APPEND,
true );
1076 bulkAddedItems.push_back( item );
1081 m_board->
Add( item, ADD_MODE::BULK_APPEND,
true );
1082 bulkAddedItems.push_back( item );
1087 m_board->
Add( item, ADD_MODE::BULK_APPEND,
true );
1088 bulkAddedItems.push_back( item );
1091 case T_embedded_fonts:
1098 case T_embedded_files:
1101 embeddedFilesParser.SyncLineReaderWith( *
this );
1109 wxLogError( e.
What() );
1112 SyncLineReaderWith( embeddedFilesParser );
1118 err.Printf(
_(
"Unknown token '%s'" ), FromUTF8() );
1123 if( bulkAddedItems.size() > 0 )
1131 wxString msg, undefinedLayerNames, destLayerName;
1135 if( !undefinedLayerNames.IsEmpty() )
1136 undefinedLayerNames += wxT(
", " );
1138 undefinedLayerNames += layerName;
1145 msg.Printf(
_(
"Items found on undefined layers (%s).\n"
1146 "Do you wish to rescue them to the %s layer?\n"
1148 "Zones will need to be refilled." ),
1149 undefinedLayerNames, destLayerName );
1160 const auto visitItem = [&](
BOARD_ITEM& curr_item )
1162 LSET layers = curr_item.GetLayerSet();
1164 if( layers.test(
Rescue ) )
1166 layers.
set( destLayer );
1170 curr_item.SetLayerSet( layers );
1180 if(
via->GetViaType() == VIATYPE::THROUGH )
1183 via->LayerPair( &top_layer, &bottom_layer );
1187 if( top_layer ==
Rescue )
1190 if( bottom_layer ==
Rescue )
1191 bottom_layer =
B_Cu;
1193 via->SetLayerPair( top_layer, bottom_layer );
1198 visitItem( *track );
1206 visitItem( *drawing );
1210 for(
BOARD_ITEM* drawing : fp->GraphicalItems() )
1211 visitItem( *drawing );
1221 THROW_IO_ERROR( wxT(
"One or more undefined undefinedLayerNames was found; "
1222 "open the board in the PCB Editor to resolve." ) );
1232 ZONE* z =
static_cast<ZONE*
>( zone );
1248 [&](
const KIID& aId )
1252 if(
BOARD* board =
dynamic_cast<BOARD*
>( aParent ) )
1254 aItem = board->GetItem( aId );
1261 if( child->
m_Uuid == aId )
1274 std::vector<const GROUP_INFO*> groupTypeObjects;
1277 groupTypeObjects.emplace_back( &groupInfo );
1280 groupTypeObjects.emplace_back( &genInfo );
1282 for(
const GROUP_INFO* groupInfo : groupTypeObjects )
1296 _(
"Cannot create generated object of type '%s'" ), genInfo->genType ) );
1305 group->SetName( groupInfo->name );
1308 const_cast<KIID&
>(
group->m_Uuid ) = groupInfo->uuid;
1310 if( groupInfo->locked )
1311 group->SetLocked(
true );
1314 static_cast<FOOTPRINT*
>( groupInfo->parent )->
Add(
group, ADD_MODE::INSERT,
true );
1316 static_cast<BOARD*
>( groupInfo->parent )->Add(
group, ADD_MODE::INSERT,
true );
1321 for(
const GROUP_INFO* groupInfo : groupTypeObjects )
1325 for(
const KIID& aUuid : groupInfo->memberUuids )
1332 item = getItem( aUuid );
1344 group->AddItem( item );
1357 wxCHECK_RET( CurTok() == T_kicad_pcb,
1358 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as a header." ) );
1364 if( tok == T_version )
1383 wxCHECK_RET( CurTok() == T_general,
1384 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) +
1385 wxT(
" as a general section." ) );
1389 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1391 if( token != T_LEFT )
1392 Expecting( T_LEFT );
1403 case T_legacy_teardrops:
1408 while( ( token = NextTok() ) != T_RIGHT )
1410 if( !IsSymbol( token ) && token != T_NUMBER )
1411 Expecting(
"symbol or number" );
1420 wxCHECK_RET( ( CurTok() == T_page &&
m_requiredVersion <= 20200119 ) || CurTok() == T_paper,
1421 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as a PAGE_INFO." ) );
1428 wxString pageType = FromUTF8();
1430 if( !pageInfo.
SetType( pageType ) )
1433 err.Printf(
_(
"Page type '%s' is not valid." ), FromUTF8() );
1460 if( token == T_portrait )
1465 else if( token != T_RIGHT )
1467 Expecting(
"portrait|)" );
1476 wxCHECK_RET( CurTok() == T_title_block,
1477 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as TITLE_BLOCK." ) );
1482 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1484 if( token != T_LEFT )
1485 Expecting( T_LEFT );
1498 titleBlock.
SetDate( FromUTF8() );
1513 int commentNumber =
parseInt(
"comment" );
1515 switch( commentNumber )
1564 err.Printf( wxT(
"%d is not a valid title block comment number" ), commentNumber );
1572 Expecting(
"title, date, rev, company, or comment" );
1587 std::string userName;
1589 bool isVisible =
true;
1593 if( CurTok() != T_LEFT )
1594 Expecting( T_LEFT );
1597 int layer_num =
parseInt(
"layer index" );
1599 NeedSYMBOLorNUMBER();
1608 if( token == T_hide )
1613 else if( token == T_STRING )
1615 userName = CurText();
1618 else if( token != T_RIGHT )
1620 Expecting(
"hide, user defined name, or )" );
1628 if( !userName.empty() )
1643 int dielectric_idx = 1;
1646 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1648 if( CurTok() != T_LEFT )
1649 Expecting( T_LEFT );
1653 if( token != T_layer )
1657 case T_copper_finish:
1663 case T_edge_plating:
1669 case T_dielectric_constraints:
1675 case T_edge_connector:
1679 if( token == T_yes )
1681 else if( token == T_bevelled )
1687 case T_castellated_pads:
1721 else if( !( layerId & 1 ) )
1734 stackup.
Add( item );
1738 Expecting(
"layer_name" );
1741 bool has_next_sublayer =
true;
1742 int sublayer_idx = 0;
1745 while( has_next_sublayer )
1747 has_next_sublayer =
false;
1749 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1751 if( token == T_addsublayer )
1753 has_next_sublayer =
true;
1757 if( token == T_LEFT )
1773 if( token == T_LEFT )
1776 if( token == T_locked )
1799 case T_loss_tangent:
1819 wxColour wx_color =
color.ToColour();
1822 name.Printf( wxT(
"#%02X%02X%02X%02X" ),
1842 if( has_next_sublayer )
1850 if( token != T_RIGHT )
1867 aMap[
"Adesivo.Retro"] =
"B.Adhes";
1868 aMap[
"Adesivo.Fronte"] =
"F.Adhes";
1869 aMap[
"Pasta.Retro"] =
"B.Paste";
1870 aMap[
"Pasta.Fronte"] =
"F.Paste";
1871 aMap[
"Serigrafia.Retro"] =
"B.SilkS";
1872 aMap[
"Serigrafia.Fronte"] =
"F.SilkS";
1873 aMap[
"Maschera.Retro"] =
"B.Mask";
1874 aMap[
"Maschera.Fronte"] =
"F.Mask";
1875 aMap[
"Grafica"] =
"Dwgs.User";
1876 aMap[
"Commenti"] =
"Cmts.User";
1877 aMap[
"Eco1"] =
"Eco1.User";
1878 aMap[
"Eco2"] =
"Eco2.User";
1879 aMap[
"Contorno.scheda"] =
"Edge.Cuts";
1882 aMap[
"Kleju_Dolna"] =
"B.Adhes";
1883 aMap[
"Kleju_Gorna"] =
"F.Adhes";
1884 aMap[
"Pasty_Dolna"] =
"B.Paste";
1885 aMap[
"Pasty_Gorna"] =
"F.Paste";
1886 aMap[
"Opisowa_Dolna"] =
"B.SilkS";
1887 aMap[
"Opisowa_Gorna"] =
"F.SilkS";
1888 aMap[
"Maski_Dolna"] =
"B.Mask";
1889 aMap[
"Maski_Gorna"] =
"F.Mask";
1890 aMap[
"Rysunkowa"] =
"Dwgs.User";
1891 aMap[
"Komentarzy"] =
"Cmts.User";
1892 aMap[
"ECO1"] =
"Eco1.User";
1893 aMap[
"ECO2"] =
"Eco2.User";
1894 aMap[
"Krawedziowa"] =
"Edge.Cuts";
1897 aMap[
"Dessous.Adhes"] =
"B.Adhes";
1898 aMap[
"Dessus.Adhes"] =
"F.Adhes";
1899 aMap[
"Dessous.Pate"] =
"B.Paste";
1900 aMap[
"Dessus.Pate"] =
"F.Paste";
1901 aMap[
"Dessous.SilkS"] =
"B.SilkS";
1902 aMap[
"Dessus.SilkS"] =
"F.SilkS";
1903 aMap[
"Dessous.Masque"] =
"B.Mask";
1904 aMap[
"Dessus.Masque"] =
"F.Mask";
1905 aMap[
"Dessin.User"] =
"Dwgs.User";
1906 aMap[
"Contours.Ci"] =
"Edge.Cuts";
1912 wxCHECK_RET( CurTok() == T_layers,
1913 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as layers." ) );
1918 int copperLayerCount = 0;
1920 bool anyHidden =
false;
1922 std::unordered_map< std::string, std::string > v3_layer_names;
1923 std::vector<LAYER> cu;
1927 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1934 cu.push_back( layer );
1947 for(
size_t i = 1; i < cu.size() - 1; i++ )
1956 tmpLayer = ( i + 1 ) * 2;
1958 cu[i].m_number = tmpLayer;
1961 cu[0].m_number =
F_Cu;
1962 cu[cu.size()-1].m_number =
B_Cu;
1964 for(
auto& cu_layer : cu )
1966 enabledLayers.
set( cu_layer.m_number );
1968 if( cu_layer.m_visible )
1969 visibleLayers.
set( cu_layer.m_number );
1981 copperLayerCount = cu.size();
1985 while( token != T_RIGHT )
1991 auto new_layer_it = v3_layer_names.find( layer.
m_name.ToStdString() );
1993 if( new_layer_it != v3_layer_names.end() )
1999 error.Printf(
_(
"Layer '%s' in file '%s' at line %d is not in fixed layer hash." ),
2012 layer.
m_name = it->first;
2027 if( token != T_LEFT )
2034 if( copperLayerCount < 2 || (copperLayerCount % 2) != 0 )
2036 wxString err = wxString::Format(
_(
"%d is not a valid layer count" ), copperLayerCount );
2053 LSET_MAP::const_iterator it = aMap.find( curText );
2055 if( it == aMap.end() )
2065 LAYER_ID_MAP::const_iterator it = aMap.find( curText );
2067 if( it == aMap.end() )
2074 if( it->second ==
Rescue )
2084 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as layer." ) );
2098 wxCHECK_MSG( CurTok() == T_layers,
LSET(),
2099 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as item layers." ) );
2103 for( T token = NextTok(); token != T_RIGHT; token = NextTok() )
2117 Expecting(
"single copper layer" );
2120 Expecting(
"max one soldermask layer" );
2124 Expecting(
"no mask layer when track is on internal layer" );
2127 Expecting(
"copper and mask on the same side" );
2130 Expecting(
"copper and mask on the same side" );
2138 wxCHECK_RET( CurTok() == T_setup,
2139 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as setup." ) );
2142 const std::shared_ptr<NETCLASS>& defaultNetClass = bds.
m_NetSettings->GetDefaultNetclass();
2149 for( T token = NextTok(); token != T_RIGHT; token = NextTok() )
2151 if( token != T_LEFT )
2152 Expecting( T_LEFT );
2162 case T_last_trace_width:
2167 case T_user_trace_width:
2183 case T_trace_clearance:
2184 defaultNetClass->SetClearance(
parseBoardUnits( T_trace_clearance ) );
2189 case T_zone_clearance:
2195 case T_zone_45_only:
2201 case T_clearance_min:
2225 case T_via_min_annulus:
2231 case T_via_min_size:
2237 case T_through_hole_min:
2244 case T_via_min_drill:
2250 case T_hole_to_hole_min:
2286 case T_uvias_allowed:
2292 case T_blind_buried_vias_allowed:
2298 case T_uvia_min_size:
2304 case T_uvia_min_drill:
2310 case T_user_diff_pair:
2325 case T_segment_width:
2337 case T_mod_edge_width:
2343 case T_pcb_text_width:
2349 case T_mod_text_width:
2355 case T_pcb_text_size:
2362 case T_mod_text_size:
2394 case T_pad_to_mask_clearance:
2399 case T_solder_mask_min_width:
2404 case T_pad_to_paste_clearance:
2409 case T_pad_to_paste_clearance_ratio:
2414 case T_allow_soldermask_bridges_in_footprints:
2421 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2423 if( token == T_front )
2425 else if( token == T_back )
2427 else if( token == T_none )
2430 Expecting(
"front, back, or none" );
2435 case T_aux_axis_origin:
2459 case T_visible_elements:
2466 for(
size_t i = 0; i <
sizeof( int ) * CHAR_BIT; i++ )
2479 case T_filled_areas_thickness:
2485 case T_pcbplotparams:
2491 parser.SyncLineReaderWith( *
this );
2493 plotParams.
Parse( &parser );
2494 SyncLineReaderWith( parser );
2509 Unexpected( CurText() );
2528 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2530 if( token != T_LEFT )
2531 Expecting( T_LEFT );
2537 case T_edge_clearance:
2543 case T_copper_line_width:
2548 case T_copper_text_dims:
2552 case T_courtyard_line_width:
2557 case T_edge_cuts_line_width:
2562 case T_silk_line_width:
2567 case T_silk_text_dims:
2571 case T_fab_layers_line_width:
2576 case T_fab_layers_text_dims:
2580 case T_other_layers_line_width:
2585 case T_other_layers_text_dims:
2589 case T_dimension_units:
2595 case T_dimension_precision:
2602 Unexpected( CurText() );
2612 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2614 if( token == T_LEFT )
2634 case T_keep_upright:
2639 Expecting(
"size, thickness, italic or keep_upright" );
2647 wxCHECK_RET( CurTok() == T_net,
2648 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as net." ) );
2650 int netCode =
parseInt(
"net number" );
2652 NeedSYMBOLorNUMBER();
2653 wxString
name = FromUTF8();
2678 wxCHECK_RET( CurTok() == T_net_class,
2679 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as net class." ) );
2683 std::shared_ptr<NETCLASS> nc = std::make_shared<NETCLASS>( wxEmptyString );
2686 NeedSYMBOLorNUMBER();
2687 nc->SetName( FromUTF8() );
2689 nc->SetDescription( FromUTF8() );
2691 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2693 if( token != T_LEFT )
2694 Expecting( T_LEFT );
2724 case T_diff_pair_width:
2728 case T_diff_pair_gap:
2734 NeedSYMBOLorNUMBER();
2736 wxString netName = FromUTF8();
2744 netName, nc->GetName() );
2750 Expecting(
"clearance, trace_width, via_dia, via_drill, uvia_dia, uvia_drill, "
2751 "diff_pair_width, diff_pair_gap or add_net" );
2759 if( netSettings->HasNetclass( nc->GetName() ) )
2764 error.Printf(
_(
"Duplicate NETCLASS name '%s' in file '%s' at line %d, offset %d." ),
2765 nc->GetName().GetData(), CurSource().GetData(), CurLineNumber(),
2769 else if( nc->GetName() == netSettings->GetDefaultNetclass()->GetName() )
2771 netSettings->SetDefaultNetclass( nc );
2775 netSettings->SetNetclass( nc->GetName(), nc );
2782 wxCHECK_MSG( CurTok() == T_fp_arc || CurTok() == T_fp_circle || CurTok() == T_fp_curve ||
2783 CurTok() == T_fp_rect || CurTok() == T_fp_line || CurTok() == T_fp_poly ||
2784 CurTok() == T_gr_arc || CurTok() == T_gr_circle || CurTok() == T_gr_curve ||
2785 CurTok() == T_gr_rect || CurTok() == T_gr_bbox || CurTok() == T_gr_line ||
2786 CurTok() == T_gr_poly || CurTok() == T_gr_vector,
nullptr,
2787 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as PCB_SHAPE." ) );
2792 std::unique_ptr<PCB_SHAPE> shape = std::make_unique<PCB_SHAPE>( aParent );
2798 shape->SetShape( SHAPE_T::ARC );
2801 if( token == T_locked )
2803 shape->SetLocked(
true );
2807 if( token != T_LEFT )
2808 Expecting( T_LEFT );
2815 if( token != T_start )
2816 Expecting( T_start );
2820 shape->SetCenter( pt );
2826 if( token != T_end )
2831 shape->SetStart( pt );
2836 if( token != T_angle )
2837 Expecting( T_angle );
2844 VECTOR2I arc_start, arc_mid, arc_end;
2846 if( token != T_start )
2847 Expecting( T_start );
2855 if( token != T_mid )
2864 if( token != T_end )
2871 shape->SetArcGeometry( arc_start, arc_mid, arc_end );
2878 shape->SetShape( SHAPE_T::CIRCLE );
2881 if( token == T_locked )
2883 shape->SetLocked(
true );
2887 if( token != T_LEFT )
2888 Expecting( T_LEFT );
2892 if( token != T_center )
2893 Expecting( T_center );
2897 shape->SetStart( pt );
2903 if( token != T_end )
2908 shape->SetEnd( pt );
2914 shape->SetShape( SHAPE_T::BEZIER );
2917 if( token == T_locked )
2919 shape->SetLocked(
true );
2923 if( token != T_LEFT )
2924 Expecting( T_LEFT );
2928 if( token != T_pts )
2932 shape->SetBezierC1(
parseXY());
2933 shape->SetBezierC2(
parseXY());
2935 shape->RebuildBezierToSegmentsPointsList(
ARC_HIGH_DEF );
2942 shape->SetShape( SHAPE_T::RECTANGLE );
2945 if( token == T_locked )
2947 shape->SetLocked(
true );
2951 if( token != T_LEFT )
2952 Expecting( T_LEFT );
2956 if( token != T_start )
2957 Expecting( T_start );
2961 shape->SetStart( pt );
2966 if( token != T_end )
2971 shape->SetEnd( pt );
2992 if( token == T_locked )
2994 shape->SetLocked(
true );
2998 if( token != T_LEFT )
2999 Expecting( T_LEFT );
3003 if( token != T_start )
3004 Expecting( T_start );
3008 shape->SetStart( pt );
3013 if( token != T_end )
3018 shape->SetEnd( pt );
3025 shape->SetShape( SHAPE_T::POLY );
3026 shape->SetPolyPoints( {} );
3032 if( token == T_locked )
3034 shape->SetLocked(
true );
3038 if( token != T_LEFT )
3039 Expecting( T_LEFT );
3043 if( token != T_pts )
3046 while( (token = NextTok() ) != T_RIGHT )
3053 Expecting(
"gr_arc, gr_circle, gr_curve, gr_line, gr_poly, gr_rect or gr_bbox" );
3056 bool foundFill =
false;
3058 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3060 if( token != T_LEFT )
3061 Expecting( T_LEFT );
3081 case T_solder_mask_margin:
3082 shape->SetLocalSolderMaskMargin(
parseBoardUnits(
"local solder mask margin value" ) );
3094 strokeParser.SyncLineReaderWith( *
this );
3097 SyncLineReaderWith( strokeParser );
3111 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3113 if( token == T_LEFT )
3122 shape->SetFilled(
true );
3127 shape->SetFilled(
false );
3131 Expecting(
"yes, no, solid, none" );
3147 shape->SetLocked(
locked );
3154 wxLogError(
_(
"Invalid net ID in\nfile: '%s'\nline: %d\noffset: %d." ),
3155 CurSource(), CurLineNumber(), CurOffset() );
3161 Expecting(
"layer, width, fill, tstamp, uuid, locked, net, status, "
3162 "or solder_mask_margin" );
3171 && ( shape->GetShape() == SHAPE_T::RECTANGLE || shape->GetShape() == SHAPE_T::CIRCLE ) )
3173 shape->SetFilled(
true );
3175 else if( shape->GetShape() == SHAPE_T::POLY && shape->GetLayer() !=
Edge_Cuts )
3178 shape->SetFilled(
true );
3184 if( stroke.
GetWidth() <= 0 && !shape->IsFilled() )
3189 shape->SetStroke( stroke );
3193 shape->Rotate( { 0, 0 }, parentFP->GetOrientation() );
3194 shape->Move( parentFP->GetPosition() );
3197 return shape.release();
3203 wxCHECK_MSG( CurTok() == T_image,
nullptr,
3204 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as a reference image." ) );
3207 std::unique_ptr<PCB_REFERENCE_IMAGE> bitmap = std::make_unique<PCB_REFERENCE_IMAGE>( aParent );
3209 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3211 if( token != T_LEFT )
3212 Expecting( T_LEFT );
3223 bitmap->SetPosition( pos );
3252 data.reserve( 1 << 19 );
3254 while( token != T_RIGHT )
3256 if( !IsSymbol( token ) )
3257 Expecting(
"base64 image data" );
3263 wxMemoryBuffer buffer = wxBase64Decode( data );
3276 bitmap->SetLocked(
locked );
3291 Expecting(
"at, layer, scale, data, locked or uuid" );
3295 return bitmap.release();
3301 wxCHECK_MSG( CurTok() == T_gr_text || CurTok() == T_fp_text,
nullptr,
3302 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as PCB_TEXT." ) );
3305 std::unique_ptr<PCB_TEXT>
text;
3307 T token = NextTok();
3312 text = std::unique_ptr<PCB_TEXT>( aBaseText );
3327 text = std::make_unique<PCB_TEXT>( parentFP );
3331 THROW_IO_ERROR( wxString::Format(
_(
"Cannot handle footprint text type %s" ),
3339 text = std::make_unique<PCB_TEXT>( aParent );
3343 if( token == T_locked )
3345 text->SetLocked(
true );
3349 if( !IsSymbol( token ) && (
int) token !=
DSN_NUMBER )
3350 Expecting(
"text value" );
3352 wxString value = FromUTF8();
3353 value.Replace( wxT(
"%V" ), wxT(
"${VALUE}" ) );
3354 value.Replace( wxT(
"%R" ), wxT(
"${REFERENCE}" ) );
3355 text->SetText( value );
3361 return text.release();
3368 bool hasAngle =
false;
3370 bool hasPos =
false;
3376 for( T token = NextTok(); token != T_RIGHT; token = NextTok() )
3378 if( token == T_LEFT )
3393 if( CurTok() == T_NUMBER )
3401 if( parentFP && CurTok() == T_unlocked )
3418 if( token == T_knockout )
3445 Expecting(
"layer, effects, locked, render_cache, uuid or tstamp" );
3461 Expecting(
"layer, effects, locked, render_cache or tstamp" );
3470 case T_render_cache:
3476 Expecting(
"layer, hide, effects, locked, render_cache or tstamp" );
3478 Expecting(
"layer, effects, locked, render_cache or tstamp" );
3508 wxCHECK_MSG( CurTok() == T_gr_text_box || CurTok() == T_fp_text_box,
nullptr,
3509 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as PCB_TEXTBOX." ) );
3511 std::unique_ptr<PCB_TEXTBOX> textbox = std::make_unique<PCB_TEXTBOX>( aParent );
3515 return textbox.release();
3521 wxCHECK_MSG( CurTok() == T_table_cell,
nullptr,
3522 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as a table cell." ) );
3524 std::unique_ptr<PCB_TABLECELL> cell = std::make_unique<PCB_TABLECELL>( aParent );
3528 return cell.release();
3539 bool foundMargins =
false;
3541 T token = NextTok();
3544 if( token == T_locked )
3550 if( !IsSymbol( token ) && (
int) token !=
DSN_NUMBER )
3551 Expecting(
"text value" );
3553 aTextBox->
SetText( FromUTF8() );
3555 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3557 if( token != T_LEFT )
3558 Expecting( T_LEFT );
3578 if( token != T_end )
3590 aTextBox->
SetShape( SHAPE_T::POLY );
3594 while( (token = NextTok() ) != T_RIGHT )
3610 strokeParser.SyncLineReaderWith( *
this );
3613 SyncLineReaderWith( strokeParser );
3628 foundMargins =
true;
3640 cell->SetColSpan(
parseInt(
"column span" ) );
3641 cell->SetRowSpan(
parseInt(
"row span" ) );
3645 Expecting(
"angle, width, layer, effects, render_cache, uuid or tstamp" );
3662 case T_render_cache:
3668 Expecting(
"locked, start, pts, angle, width, layer, effects, span, render_cache, uuid or tstamp" );
3670 Expecting(
"locked, start, pts, angle, width, layer, effects, render_cache, uuid or tstamp" );
3690 aTextBox->
Rotate( { 0, 0 }, parentFP->GetOrientation() );
3691 aTextBox->
Move( parentFP->GetPosition() );
3698 wxCHECK_MSG( CurTok() == T_table,
nullptr,
3699 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as a table." ) );
3704 std::unique_ptr<PCB_TABLE> table = std::make_unique<PCB_TABLE>( aParent, -1 );
3706 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3708 if( token != T_LEFT )
3709 Expecting( T_LEFT );
3715 case T_column_count:
3716 table->SetColCount(
parseInt(
"column count" ) );
3735 case T_column_widths:
3739 while( ( token = NextTok() ) != T_RIGHT )
3749 while( ( token = NextTok() ) != T_RIGHT )
3756 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3758 if( token != T_LEFT )
3759 Expecting( T_LEFT );
3763 if( token != T_table_cell )
3764 Expecting(
"table_cell" );
3772 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3774 if( token != T_LEFT )
3775 Expecting( T_LEFT );
3782 table->SetStrokeExternal(
parseBool() );
3794 strokeParser.SyncLineReaderWith( *
this );
3797 SyncLineReaderWith( strokeParser );
3799 table->SetBorderStroke( borderStroke );
3804 Expecting(
"external, header or stroke" );
3812 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3814 if( token != T_LEFT )
3815 Expecting( T_LEFT );
3834 strokeParser.SyncLineReaderWith( *
this );
3837 SyncLineReaderWith( strokeParser );
3839 table->SetSeparatorsStroke( separatorsStroke );
3844 Expecting(
"rows, cols, or stroke" );
3852 Expecting(
"columns, layer, col_widths, row_heights, border, separators, header or "
3858 table->SetOrientation( table->GetOrientation() + parentFP->GetOrientation() );
3860 return table.release();
3866 wxCHECK_MSG( CurTok() == T_dimension,
nullptr,
3867 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as DIMENSION." ) );
3871 std::unique_ptr<PCB_DIMENSION_BASE> dim;
3876 if( token == T_locked )
3883 if( token != T_LEFT )
3888 bool isLegacyDimension =
false;
3889 bool isStyleKnown =
false;
3892 if( token == T_width )
3894 isLegacyDimension =
true;
3895 dim = std::make_unique<PCB_DIM_ALIGNED>( aParent );
3901 if( token != T_type )
3902 Expecting( T_type );
3906 case T_aligned: dim = std::make_unique<PCB_DIM_ALIGNED>( aParent );
break;
3907 case T_orthogonal: dim = std::make_unique<PCB_DIM_ORTHOGONAL>( aParent );
break;
3908 case T_leader: dim = std::make_unique<PCB_DIM_LEADER>( aParent );
break;
3909 case T_center: dim = std::make_unique<PCB_DIM_CENTER>( aParent );
break;
3910 case T_radial: dim = std::make_unique<PCB_DIM_RADIAL>( aParent );
break;
3911 default: wxFAIL_MSG( wxT(
"Cannot parse unknown dimension type " )
3912 + GetTokenString( CurTok() ) );
3919 dim->SetArrowDirection( DIM_ARROW_DIRECTION::OUTWARD );
3922 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3924 if( token != T_LEFT )
3925 Expecting( T_LEFT );
3950 bool is_aligned = dim->GetKeepTextAligned();
3955 dim->SetTextPositionMode( DIM_TEXT_POSITION::MANUAL );
3956 dim->SetKeepTextAligned(
false );
3961 if( isLegacyDimension )
3963 EDA_UNITS units = EDA_UNITS::MILLIMETRES;
3966 dim->SetAutoUnits(
true );
3968 dim->SetUnits( units );
3973 dim->SetKeepTextAligned( is_aligned );
3974 dim->SetTextPositionMode( t_dim_pos );
3985 dim->SetStart( point );
3987 dim->SetEnd( point );
4007 case T_leader_length:
4023 int orientation =
parseInt(
"orthogonal dimension orientation" );
4029 orientation = std::clamp( orientation, 0, 1 );
4038 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
4046 NeedSYMBOLorNUMBER();
4047 dim->SetPrefix( FromUTF8() );
4052 NeedSYMBOLorNUMBER();
4053 dim->SetSuffix( FromUTF8() );
4059 int mode =
parseInt(
"dimension units mode" );
4060 mode = std::max( 0, std::min( 4, mode ) );
4066 case T_units_format:
4068 int format =
parseInt(
"dimension units format" );
4069 format = std::clamp( format, 0, 3 );
4080 case T_override_value:
4081 NeedSYMBOLorNUMBER();
4082 dim->SetOverrideTextEnabled(
true );
4083 dim->SetOverrideText( FromUTF8() );
4087 case T_suppress_zeroes:
4092 std::cerr <<
"Unknown format token: " << GetTokenString( token ) << std::endl;
4093 Expecting(
"prefix, suffix, units, units_format, precision, override_value, "
4094 "suppress_zeroes" );
4102 isStyleKnown =
true;
4105 dim->SetKeepTextAligned(
false );
4107 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
4115 dim->SetLineThickness(
parseBoardUnits(
"extension line thickness value" ) );
4119 case T_arrow_direction:
4123 if( token == T_inward )
4124 dim->ChangeArrowDirection( DIM_ARROW_DIRECTION::INWARD );
4125 else if( token == T_outward )
4126 dim->ChangeArrowDirection( DIM_ARROW_DIRECTION::OUTWARD );
4128 Expecting(
"inward or outward" );
4133 case T_arrow_length:
4139 case T_text_position_mode:
4141 int mode =
parseInt(
"text position mode" );
4142 mode = std::max( 0, std::min( 3, mode ) );
4148 case T_extension_height:
4151 wxCHECK_MSG( aligned,
nullptr, wxT(
"Invalid extension_height token" ) );
4157 case T_extension_offset:
4158 dim->SetExtensionOffset(
parseBoardUnits(
"extension offset value" ) );
4162 case T_keep_text_aligned:
4163 dim->SetKeepTextAligned(
true );
4169 wxT(
"Invalid text_frame token" ) );
4173 int textFrame =
parseInt(
"text frame mode" );
4174 textFrame = std::clamp( textFrame, 0, 3 );
4181 Expecting(
"thickness, arrow_length, arrow_direction, text_position_mode, "
4182 "extension_height, extension_offset" );
4195 if( token != T_pts )
4201 dim->SetStart( point );
4215 if( token != T_pts )
4221 dim->SetEnd( point );
4235 if( token == T_pts )
4257 if( token != T_pts )
4271 if( token != T_pts )
4285 if( token != T_pts )
4299 if( token != T_pts )
4313 dim->SetLocked( isLocked );
4318 Expecting(
"layer, tstamp, uuid, gr_text, feature1, feature2, crossbar, arrow1a, "
4319 "arrow1b, arrow2a, or arrow2b" );
4324 dim->SetLocked(
true );
4328 return dim.release();
4350 wxCHECK_MSG( CurTok() == T_module || CurTok() == T_footprint,
nullptr,
4351 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as FOOTPRINT." ) );
4359 std::unique_ptr<FOOTPRINT> footprint = std::make_unique<FOOTPRINT>(
m_board );
4361 footprint->SetInitialComments( aInitialComments );
4370 if( !IsSymbol( token ) && token != T_NUMBER )
4371 Expecting(
"symbol|number" );
4377 THROW_IO_ERROR( wxString::Format(
_(
"Invalid footprint ID in\nfile: %s\nline: %d\n"
4379 CurSource(), CurLineNumber(), CurOffset() ) );
4392 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
4394 if( token == T_LEFT )
4404 int this_version =
parseInt( FromUTF8().mb_str( wxConvUTF8 ) );
4408 footprint->SetFileFormatVersionAtLoad( this_version );
4419 case T_generator_version:
4466 footprint->SetPosition( pt );
4469 if( token == T_NUMBER )
4474 else if( token != T_RIGHT )
4476 Expecting( T_RIGHT );
4482 NeedSYMBOLorNUMBER();
4483 footprint->SetLibDescription( FromUTF8() );
4488 NeedSYMBOLorNUMBER();
4489 footprint->SetKeywords( FromUTF8() );
4498 wxString pName = FromUTF8();
4500 wxString pValue = FromUTF8();
4508 if( pName ==
"ki_keywords" || pName ==
"ki_locked" )
4516 if( pName ==
"ki_description" )
4524 if( pName ==
"Sheetfile" || pName ==
"Sheet file" )
4526 footprint->SetSheetfile( pValue );
4531 if( pName ==
"Sheetname" || pName ==
"Sheet name" )
4533 footprint->SetSheetname( pValue );
4541 if( pName ==
"ki_fp_filters" )
4543 footprint->SetFilters( pValue );
4561 if( footprint->HasFieldByName( pName ) )
4563 field = footprint->GetFieldByName( pName );
4568 field = footprint->AddField(
PCB_FIELD( footprint.get(), footprint->GetFieldCount(),
4590 NeedSYMBOLorNUMBER();
4591 footprint->SetPath(
KIID_PATH( FromUTF8() ) );
4597 footprint->SetSheetname( FromUTF8() );
4603 footprint->SetSheetfile( FromUTF8() );
4607 case T_autoplace_cost90:
4608 case T_autoplace_cost180:
4609 parseInt(
"legacy auto-place cost" );
4613 case T_private_layers:
4617 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
4622 privateLayers.
set( it->second );
4624 Expecting(
"layer name" );
4633 footprint->SetPrivateLayers( privateLayers );
4637 case T_net_tie_pad_groups:
4638 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
4639 footprint->AddNetTiePadGroup( CurStr() );
4643 case T_solder_mask_margin:
4644 footprint->SetLocalSolderMaskMargin(
parseBoardUnits(
"local solder mask margin value" ) );
4648 if( m_requiredVersion <= 20240201 && footprint->GetLocalSolderMaskMargin() == 0 )
4649 footprint->SetLocalSolderMaskMargin( {} );
4653 case T_solder_paste_margin:
4654 footprint->SetLocalSolderPasteMargin(
parseBoardUnits(
"local solder paste margin value" ) );
4658 if( m_requiredVersion <= 20240201 && footprint->GetLocalSolderPasteMargin() == 0 )
4659 footprint->SetLocalSolderPasteMargin( {} );
4663 case T_solder_paste_ratio:
4664 case T_solder_paste_margin_ratio:
4665 footprint->SetLocalSolderPasteMarginRatio(
parseDouble(
"local solder paste margin ratio value" ) );
4669 if( m_requiredVersion <= 20240201 && footprint->GetLocalSolderPasteMarginRatio() == 0 )
4670 footprint->SetLocalSolderPasteMarginRatio( {} );
4675 footprint->SetLocalClearance(
parseBoardUnits(
"local clearance value" ) );
4679 if( m_requiredVersion <= 20240201 && footprint->GetLocalClearance() == 0 )
4680 footprint->SetLocalClearance( {} );
4684 case T_zone_connect:
4689 case T_thermal_width:
4697 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
4705 case T_through_hole:
4717 case T_exclude_from_pos_files:
4721 case T_exclude_from_bom:
4725 case T_allow_missing_courtyard:
4733 case T_allow_soldermask_bridges:
4738 Expecting(
"through_hole, smd, virtual, board_only, exclude_from_pos_files, "
4739 "exclude_from_bom or allow_solder_mask_bridges" );
4753 switch( field->GetId() )
4757 const_cast<KIID&
>( footprint->Reference().m_Uuid ) =
text->m_Uuid;
4765 const_cast<KIID&
>( footprint->Value().m_Uuid ) =
text->m_Uuid;
4772 footprint->Add(
text, ADD_MODE::APPEND,
true );
4780 footprint->Add( textbox, ADD_MODE::APPEND,
true );
4787 footprint->Add( table, ADD_MODE::APPEND,
true );
4799 footprint->Add( shape, ADD_MODE::APPEND,
true );
4806 footprint->Add(
image, ADD_MODE::APPEND,
true );
4813 footprint->Add( dimension, ADD_MODE::APPEND,
true );
4820 footprint->Add(
pad, ADD_MODE::APPEND,
true );
4827 footprint->Add3DModel( model );
4835 footprint->Add( zone, ADD_MODE::APPEND,
true );
4843 case T_embedded_fonts:
4845 footprint->GetEmbeddedFiles()->SetAreFontsEmbedded(
parseBool() );
4850 case T_embedded_files:
4853 embeddedFilesParser.SyncLineReaderWith( *
this );
4857 embeddedFilesParser.
ParseEmbedded( footprint->GetEmbeddedFiles() );
4861 wxLogError( e.
What() );
4864 SyncLineReaderWith( embeddedFilesParser );
4868 case T_component_classes:
4870 std::unordered_set<wxString> componentClassNames;
4872 while( ( token = NextTok() ) != T_RIGHT )
4874 if( token != T_LEFT )
4875 Expecting( T_LEFT );
4877 if( ( token = NextTok() ) != T_class )
4878 Expecting( T_class );
4880 NeedSYMBOLorNUMBER();
4881 componentClassNames.insert(
From_UTF8( CurText() ) );
4889 componentClassNames );
4890 footprint->SetComponentClass( componentClass );
4897 Expecting(
"at, descr, locked, placed, tedit, tstamp, uuid, "
4898 "autoplace_cost90, autoplace_cost180, attr, clearance, "
4899 "embedded_files, fp_arc, fp_circle, fp_curve, fp_line, fp_poly, "
4900 "fp_rect, fp_text, pad, group, generator, model, path, solder_mask_margin, "
4901 "solder_paste_margin, solder_paste_margin_ratio, tags, thermal_gap, "
4902 "version, zone, zone_connect, or component_classes" );
4916 if( footprint->GetKeywords().StartsWith( wxT(
"net tie" ) ) )
4920 for(
PAD*
pad : footprint->Pads() )
4922 if( !padGroup.IsEmpty() )
4923 padGroup += wxS(
", " );
4925 padGroup +=
pad->GetNumber();
4928 if( !padGroup.IsEmpty() )
4929 footprint->AddNetTiePadGroup( padGroup );
4933 footprint->SetAttributes( attributes );
4935 footprint->SetFPID( fpid );
4937 return footprint.release();
4943 wxCHECK_MSG( CurTok() == T_pad,
nullptr,
4944 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as PAD." ) );
4948 bool foundNet =
false;
4950 std::unique_ptr<PAD>
pad = std::make_unique<PAD>( aParent );
4952 NeedSYMBOLorNUMBER();
4953 pad->SetNumber( FromUTF8() );
4955 T token = NextTok();
4960 pad->SetAttribute( PAD_ATTRIB::PTH );
4969 pad->SetAttribute( PAD_ATTRIB::SMD );
4977 pad->SetAttribute( PAD_ATTRIB::CONN );
4984 case T_np_thru_hole:
4985 pad->SetAttribute( PAD_ATTRIB::NPTH );
4989 Expecting(
"thru_hole, smd, connect, or np_thru_hole" );
5023 Expecting(
"circle, rectangle, roundrect, oval, trapezoid or custom" );
5026 std::optional<EDA_ANGLE> thermalBrAngleOverride;
5028 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
5030 if( token == T_locked )
5036 if( token != T_LEFT )
5037 Expecting( T_LEFT );
5053 pad->SetFPRelativePosition( pt );
5056 if( token == T_NUMBER )
5061 else if( token != T_RIGHT )
5063 Expecting(
") or angle value" );
5080 bool haveWidth =
false;
5083 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
5085 if( token == T_LEFT )
5090 case T_oval:
pad->SetDrillShape( PAD_DRILL_SHAPE::OBLONG );
break;
5099 drillSize.
y = drillSize.
x;
5118 Expecting(
"oval, size, or offset" );
5126 if(
pad->GetAttribute() != PAD_ATTRIB::SMD &&
pad->GetAttribute() != PAD_ATTRIB::CONN )
5127 pad->SetDrillSize( drillSize );
5137 pad->SetLayerSet( layerMask );
5146 wxLogError(
_(
"Invalid net ID in\nfile: %s\nline: %d offset: %d" ),
5147 CurSource(), CurLineNumber(), CurOffset() );
5150 NeedSYMBOLorNUMBER();
5155 wxString netName( FromUTF8() );
5165 wxLogError(
_(
"Net name doesn't match ID in\nfile: %s\nline: %d offset: %d" ),
5166 CurSource(), CurLineNumber(), CurOffset() );
5174 NeedSYMBOLorNUMBER();
5175 pad->SetPinFunction( FromUTF8() );
5180 NeedSYMBOLorNUMBER();
5181 pad->SetPinType( FromUTF8() );
5190 case T_solder_mask_margin:
5191 pad->SetLocalSolderMaskMargin(
parseBoardUnits(
"local solder mask margin value" ) );
5195 if( m_requiredVersion <= 20240201 && pad->GetLocalSolderMaskMargin() == 0 )
5196 pad->SetLocalSolderMaskMargin( {} );
5200 case T_solder_paste_margin:
5201 pad->SetLocalSolderPasteMargin(
parseBoardUnits(
"local solder paste margin value" ) );
5205 if( m_requiredVersion <= 20240201 && pad->GetLocalSolderPasteMargin() == 0 )
5206 pad->SetLocalSolderPasteMargin( {} );
5210 case T_solder_paste_margin_ratio:
5211 pad->SetLocalSolderPasteMarginRatio(
parseDouble(
"local solder paste margin ratio value" ) );
5215 if( m_requiredVersion <= 20240201 && pad->GetLocalSolderPasteMarginRatio() == 0 )
5216 pad->SetLocalSolderPasteMarginRatio( {} );
5225 if( m_requiredVersion <= 20240201 && pad->GetLocalClearance() == 0 )
5226 pad->SetLocalClearance( {} );
5234 case T_zone_connect:
5239 case T_thermal_width:
5240 case T_thermal_bridge_width:
5245 case T_thermal_bridge_angle:
5256 case T_roundrect_rratio:
5262 case T_chamfer_ratio:
5274 bool end_list =
false;
5294 case T_bottom_right:
5304 Expecting(
"chamfer_top_left chamfer_top_right chamfer_bottom_left or "
5305 "chamfer_bottom_right" );
5316 while( token != T_RIGHT )
5322 case T_pad_prop_bga:
pad->SetProperty( PAD_PROP::BGA );
break;
5323 case T_pad_prop_fiducial_glob:
pad->SetProperty( PAD_PROP::FIDUCIAL_GLBL );
break;
5324 case T_pad_prop_fiducial_loc:
pad->SetProperty( PAD_PROP::FIDUCIAL_LOCAL );
break;
5325 case T_pad_prop_testpoint:
pad->SetProperty( PAD_PROP::TESTPOINT );
break;
5326 case T_pad_prop_castellated:
pad->SetProperty( PAD_PROP::CASTELLATED );
break;
5327 case T_pad_prop_heatsink:
pad->SetProperty( PAD_PROP::HEATSINK );
break;
5328 case T_pad_prop_mechanical:
pad->SetProperty( PAD_PROP::MECHANICAL );
break;
5329 case T_none:
pad->SetProperty( PAD_PROP::NONE );
break;
5330 case T_RIGHT:
break;
5334 Expecting(
"pad_prop_bga pad_prop_fiducial_glob pad_prop_fiducial_loc"
5335 " pad_prop_heatsink or pad_prop_castellated" );
5352 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
5354 if( token == T_LEFT )
5385 Expecting(
"gr_line, gr_arc, gr_circle, gr_curve, gr_rect, gr_bbox or gr_poly" );
5392 case T_remove_unused_layers:
5395 pad->SetRemoveUnconnected( remove );
5399 case T_keep_end_layers:
5402 pad->SetKeepTopBottom( keep );
5406 case T_zone_layer_connections:
5413 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
5418 Expecting(
"copper layer name" );
5440 Expecting(
"at, locked, drill, layers, net, die_length, roundrect_rratio, "
5441 "solder_mask_margin, solder_paste_margin, solder_paste_margin_ratio, uuid, "
5442 "clearance, tstamp, primitives, remove_unused_layers, keep_end_layers, "
5443 "pinfunction, pintype, zone_connect, thermal_width, thermal_gap, padstack or "
5451 pad->SetNetCode( 0,
true );
5454 if( thermalBrAngleOverride )
5456 pad->SetThermalSpokeAngle( *thermalBrAngleOverride );
5479 if( !
pad->CanHaveNumber() )
5483 pad->SetNumber( wxEmptyString );
5487 if(
pad->GetSizeX() <= 0 ||
pad->GetSizeY() <= 0 )
5492 wxLogWarning(
_(
"Invalid zero-sized pad pinned to %s in\nfile: %s\nline: %d\noffset: %d" ),
5493 wxT(
"1µm" ), CurSource(), CurLineNumber(), CurOffset() );
5496 return pad.release();
5503 for( T token = NextTok(); token != T_RIGHT; token = NextTok() )
5505 if( token != T_LEFT )
5506 Expecting( T_LEFT );
5561 while( (token = NextTok() ) != T_RIGHT )
5576 for( T token = NextTok(); token != T_RIGHT; token = NextTok() )
5578 if( token != T_LEFT )
5579 Expecting( T_LEFT );
5590 case T_front_inner_back:
5599 Expecting(
"front_inner_back or custom" );
5610 if( curText ==
"Inner" )
5614 THROW_IO_ERROR( wxString::Format(
_(
"Invalid padstack layer in\nfile: %s\n"
5615 "line: %d\noffset: %d." ),
5616 CurSource(), CurLineNumber(), CurOffset() ) );
5629 error.Printf(
_(
"Invalid padstack layer '%s' in file '%s' at line %d, offset %d." ),
5630 curText, CurSource().GetData(), CurLineNumber(), CurOffset() );
5634 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
5636 if( token != T_LEFT )
5637 Expecting( T_LEFT );
5649 aPad->
SetShape( curLayer, PAD_SHAPE::CIRCLE );
5653 aPad->
SetShape( curLayer, PAD_SHAPE::RECTANGLE );
5657 aPad->
SetShape( curLayer, PAD_SHAPE::OVAL );
5661 aPad->
SetShape( curLayer, PAD_SHAPE::TRAPEZOID );
5667 aPad->
SetShape( curLayer, PAD_SHAPE::ROUNDRECT );
5671 aPad->
SetShape( curLayer, PAD_SHAPE::CUSTOM );
5675 Expecting(
"circle, rectangle, roundrect, oval, trapezoid or custom" );
5686 aPad->
SetSize( curLayer, sz );
5711 case T_roundrect_rratio:
5717 case T_chamfer_ratio:
5723 aPad->
SetShape( curLayer, PAD_SHAPE::CHAMFERED_RECT );
5732 bool end_list =
false;
5752 case T_bottom_right:
5762 Expecting(
"chamfer_top_left chamfer_top_right chamfer_bottom_left or "
5763 "chamfer_bottom_right" );
5768 aPad->
SetShape( curLayer, PAD_SHAPE::CHAMFERED_RECT );
5773 case T_thermal_bridge_width:
5784 case T_thermal_bridge_angle:
5790 case T_zone_connect:
5791 padstack.
ZoneConnection( curLayer ) = magic_enum::enum_cast<ZONE_CONNECTION>(
5792 parseInt(
"zone connection value" ) );
5808 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
5810 if( token != T_LEFT )
5811 Expecting( T_LEFT );
5849 while( ( token = NextTok() ) != T_RIGHT )
5862 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
5864 if( token == T_LEFT )
5895 Expecting(
"gr_line, gr_arc, gr_circle, gr_curve, gr_rect, gr_bbox or gr_poly" );
5912 Expecting(
"mode or layer" );
5923 while( ( token = NextTok() ) != T_RIGHT )
5928 KIID uuid( CurStr() );
5936 wxCHECK_RET( CurTok() == T_group,
5937 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as PCB_GROUP." ) );
5943 groupInfo.
parent = aParent;
5945 while( ( token = NextTok() ) != T_LEFT )
5947 if( token == T_STRING )
5948 groupInfo.
name = FromUTF8();
5949 else if( token == T_locked )
5952 Expecting(
"group name or locked" );
5955 for( ; token != T_RIGHT; token = NextTok() )
5957 if( token != T_LEFT )
5958 Expecting( T_LEFT );
5984 Expecting(
"uuid, locked, or members" );
5992 wxCHECK_RET( CurTok() == T_generated, wxT(
"Cannot parse " ) + GetTokenString( CurTok() )
5993 + wxT(
" as PCB_GENERATOR." ) );
6001 genInfo.
parent = aParent;
6008 if( token != T_uuid && token != T_id )
6009 Expecting( T_uuid );
6015 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
6017 if( token != T_LEFT )
6018 Expecting( T_LEFT );
6032 genInfo.
name = FromUTF8();
6038 genInfo.
locked = token == T_yes;
6051 wxString pName = FromUTF8();
6058 genInfo.
properties.emplace( pName, wxAny(
true ) );
6064 genInfo.
properties.emplace( pName, wxAny(
false ) );