59#include <wx/filename.h> 
   72    const unsigned PROGRESS_DELTA = 250;
 
 
   93    wxCHECK_MSG( !aStr.empty(), 0.0, 
"Empty string passed to readDouble" );
 
   95    std::istringstream istr( aStr );
 
   96    istr.imbue( std::locale::classic() );
 
 
  107    wxCHECK_MSG( !aStr.empty(), 0, 
"Empty string passed to readInt" );
 
  109    std::istringstream istr( aStr );
 
  110    istr.imbue( std::locale::classic() );
 
 
  120    std::ifstream ifs( aFile, std::ios::in | std::ios::binary );
 
  128    ifs.ignore( std::numeric_limits<std::streamsize>::max() );
 
  129    std::streamsize length = ifs.gcount();
 
  131    ifs.seekg( 0, std::ios_base::beg );
 
  133    std::string buffer( std::istreambuf_iterator<char>{ ifs }, {} );
 
  135    std::vector < std::string > row;
 
  139    row.reserve( length / 100 );
 
  145    for( 
auto& ch : buffer )
 
  151            if( cell.empty() || cell[0] == 
'"' )
 
  160                row.push_back( cell );
 
  172                row.push_back( cell );
 
  175            rows.push_back( row );
 
  184            cell += std::toupper( ch );
 
  189    if( !cell.empty() || !row.empty() )
 
  191        row.push_back( cell );
 
  193        rows.push_back( row );
 
 
  207        row = 
rows.at( aOffset );
 
  209    catch( std::out_of_range& )
 
  217    if( row[0].back() != 
'A' )
 
  220    std::string row1 = row[1];
 
  221    std::string row2 = row[2];
 
  226    std::erase_if( row1, []( 
char c ){ 
return c == 
'_'; } );
 
  227    std::erase_if( row2, []( 
char c ){ 
return c == 
'_'; } );
 
  232        std::erase_if( row3, []( 
char c ){ 
return c == 
'_'; } );
 
  235    if( row1 == 
"REFDES" && row2 == 
"COMPCLASS" )
 
  238    if( row1 == 
"NETNAME" && row2 == 
"REFDES" )
 
  241    if( row1 == 
"CLASS" && row2 == 
"SUBCLASS" && row3.empty() )
 
  244    if( row1 == 
"GRAPHICDATANAME" && row2 == 
"GRAPHICDATANUMBER" )
 
  247    if( row1 == 
"CLASS" && row2 == 
"SUBCLASS" && row3 == 
"GRAPHICDATANAME" )
 
  250    if( row1 == 
"SYMNAME" && row2 == 
"PINNAME" )
 
  253    if( row1 == 
"SYMNAME" && row2 == 
"SYMMIRROR" && row3 == 
"PINNAME" )
 
  256    if( row1 == 
"VIAX" && row2 == 
"VIAY" )
 
  259    if( row1 == 
"SUBCLASS" && row2 == 
"PADSHAPENAME" )
 
  262    if( row1 == 
"PADNAME" )
 
  265    if( row1 == 
"LAYERSORT" )
 
  268    wxLogError( 
_( 
"Unknown FABMASTER section %s:%s at row %zu." ),
 
 
  281    if( aRow >= 
rows.size() )
 
  284    if( 
rows[aRow].size() < 11 )
 
  286        wxLogError( 
_( 
"Invalid row size in J row %zu. Expecting 11 elements but found %zu." ),
 
  292    for( 
int i = 7; i < 10 && retval < 1.0; ++i )
 
  294        std::string units = 
rows[aRow][i];
 
  295        std::transform(units.begin(), units.end(),units.begin(), ::toupper);
 
  297        if( units == 
"MILS" )
 
  299        else if( units == 
"MILLIMETERS" )
 
  301        else if( units == 
"MICRONS" )
 
  303        else if( units == 
"INCHES" )
 
  309        wxLogError( 
_( 
"Could not find units value, defaulting to mils." ) );
 
 
  319    if( aRow >= 
rows.size() )
 
  322    std::vector<std::string> header = 
rows[aRow];
 
  324    for( 
size_t i = 0; i < header.size(); i++ )
 
  328        std::erase_if( header[i], []( 
const char c ) { 
return c == 
'_'; } );
 
  330        if( header[i] == aStr )
 
  334    THROW_IO_ERROR( wxString::Format( 
_( 
"Could not find column label %s." ), aStr.c_str() ) );
 
 
  341    const auto& kicad_layer = 
layers.find( aLayerName);
 
  343    if( kicad_layer == 
layers.end() )
 
  346        return static_cast<PCB_LAYER_ID>( kicad_layer->second.layerid );
 
 
  352    size_t rownum = aRow + 2;
 
  354    if( rownum >= 
rows.size() )
 
  372    for( ; rownum < 
rows.size() && 
rows[rownum].size() > 0 && 
rows[rownum][0] == 
"S"; ++rownum )
 
  376        if( row.size() != header.size() )
 
  378            wxLogError( 
_( 
"Invalid row size in row %zu. Expecting %zu elements but found %zu." ),
 
  385        auto& pad_name = row[pad_name_col];
 
  386        auto& pad_num = row[pad_num_col];
 
  387        auto& pad_layer = row[pad_lay_col];
 
  388        auto& pad_is_fixed = row[pad_fix_col];
 
  389        auto& pad_is_via = row[pad_via_col];
 
  390        auto& pad_shape = row[pad_shape_col];
 
  391        auto& pad_width = row[pad_width_col];
 
  392        auto& pad_height = row[pad_height_col];
 
  393        auto& pad_xoff = row[pad_xoff_col];
 
  394        auto& pad_yoff = row[pad_yoff_col];
 
  395        auto& pad_flash = row[pad_flash_col];
 
  396        auto& pad_shapename = row[pad_shape_name_col];
 
  399        if( pad_layer == 
"INTERNAL_PAD_DEF" || pad_layer == 
"internal_pad_def" )
 
  403        if( pad_layer[0] == 
'~' )
 
  412            layer.
name = pad_layer;
 
 
  430    size_t rownum = aRow + 2;
 
  432    if( rownum >= 
rows.size() )
 
  438    if( scale_factor <= 0.0 )
 
  454    for( ; rownum < 
rows.size() && 
rows[rownum].size() > 0 && 
rows[rownum][0] == 
"S"; ++rownum )
 
  459        if( row.size() != header.size() )
 
  461            wxLogError( 
_( 
"Invalid row size in row %zu. Expecting %zu elements but found %zu." ),
 
  468        auto& pad_name = row[pad_name_col];
 
  469        auto& pad_num = row[pad_num_col];
 
  470        auto& pad_layer = row[pad_lay_col];
 
  471        auto& pad_is_fixed = row[pad_fix_col];
 
  472        auto& pad_is_via = row[pad_via_col];
 
  473        auto& pad_shape = row[pad_shape_col];
 
  474        auto& pad_width = row[pad_width_col];
 
  475        auto& pad_height = row[pad_height_col];
 
  476        auto& pad_xoff = row[pad_xoff_col];
 
  477        auto& pad_yoff = row[pad_yoff_col];
 
  478        auto& pad_flash = row[pad_flash_col];
 
  479        auto& pad_shapename = row[pad_shape_name_col];
 
  482        if( pad_layer == 
"INTERNAL_PAD_DEF" || pad_layer == 
"internal_pad_def" )
 
  487        auto new_pad = 
pads.find( pad_name );
 
  489        if( new_pad != 
pads.end() )
 
  490            pad = &new_pad->second;
 
  495            pad->name = pad_name;
 
  499        if( pad_layer == 
"~DRILL" )
 
  513                wxLogError( 
_( 
"Expecting drill size value but found %s!%s!%s in row %zu." ),
 
  531            if( drill_x == drill_y )
 
  533                pad->drill_size_x = drill_hit;
 
  534                pad->drill_size_y = drill_hit;
 
  538                pad->drill_size_x = drill_x;
 
  539                pad->drill_size_y = drill_y;
 
  542            if( !pad_shapename.empty() && pad_shapename[0] == 
'P' )
 
  548        if( pad_shape.empty() )
 
  561            wxLogError( 
_( 
"Expecting pad size values but found %s : %s in row %zu." ),
 
  571        auto layer = 
layers.find( pad_layer );
 
  573        if( layer != 
layers.end() )
 
  575            if( layer->second.layerid == 
F_Cu )
 
  577            else if( layer->second.layerid == 
B_Cu )
 
  581        if( w > std::numeric_limits<int>::max() || h > std::numeric_limits<int>::max() )
 
  583            wxLogError( 
_( 
"Invalid pad size in row %zu." ), rownum );
 
  587        if( pad_layer == 
"~TSM" || pad_layer == 
"~BSM" )
 
  589            if( w > 0.0 && h > 0.0 )
 
  597        if( pad_layer == 
"~TSP" || pad_layer == 
"~BSP" )
 
  599            if( w > 0.0 && h > 0.0 )
 
  608        if( pad_layer[0] == 
'~' )
 
  618            wxLogError( 
_( 
"Expecting pad offset values but found %s:%s in row %zu." ),
 
  625        if( w > 0.0 && h > 0.0 && recnum == 1 )
 
  629            pad->via = ( std::toupper( pad_is_via[0] ) != 
'V' );
 
  631            if( pad_shape == 
"CIRCLE" )
 
  636            else if( pad_shape == 
"RECTANGLE" )
 
  640            else if( pad_shape == 
"ROUNDED_RECT" )
 
  644            else if( pad_shape == 
"SQUARE" )
 
  649            else if( pad_shape == 
"OBLONG" || pad_shape == 
"OBLONG_X" || pad_shape == 
"OBLONG_Y" )
 
  651            else if( pad_shape == 
"OCTAGON" )
 
  654                pad->is_octogon = 
true;
 
  656            else if( pad_shape == 
"SHAPE" )
 
  659                pad->custom_name = pad_shapename;
 
  663                wxLogError( 
_( 
"Unknown pad shape name '%s' on layer '%s' in row %zu." ),
 
  672    return rownum - aRow;
 
 
  678    size_t rownum = aRow + 2;
 
  680     if( rownum >= 
rows.size() )
 
  683     auto& header = 
rows[aRow];
 
  686     if( scale_factor <= 0.0 )
 
  692     if( layer_class_col < 0 || layer_subclass_col < 0 )
 
  695     for( ; rownum < 
rows.size() && 
rows[rownum].size() > 0 && 
rows[rownum][0] == 
"S"; ++rownum )
 
  699         if( row.size() != header.size() )
 
  701             wxLogError( 
_( 
"Invalid row size in row %zu. Expecting %zu elements but found %zu." ),
 
  711         layer.
name = row[layer_subclass_col];
 
  715         if( row[layer_class_col] == 
"ANTI ETCH" )
 
  720         else if( row[layer_class_col] == 
"ETCH" )
 
  726     return rownum - aRow;
 
 
  734    std::string max_layer_name;
 
  736    std::vector<std::pair<std::string, int>> extra_layers
 
  738        { 
"ASSEMBLY_TOP", 
F_Fab },
 
  739        { 
"ASSEMBLY_BOTTOM", 
B_Fab },
 
  740        { 
"PLACE_BOUND_TOP", 
F_CrtYd },
 
  741        { 
"PLACE_BOUND_BOTTOM", 
B_CrtYd },
 
  744    std::vector<FABMASTER_LAYER*> layer_order;
 
  746    int next_user_layer = 
User_1;
 
  755            layer_order.push_back( &layer );
 
  757        else if( ( layer.
name.find( 
"SILK" ) != std::string::npos
 
  758                   && layer.
name.find( 
"AUTOSILK" )
 
  759                              == std::string::npos ) 
 
  760                 || layer.
name.find( 
"DISPLAY" ) != std::string::npos )
 
  762            if( layer.
name.find( 
"B" ) != std::string::npos )
 
  767        else if( layer.
name.find( 
"MASK" ) != std::string::npos ||
 
  768                 layer.
name.find( 
"MSK" ) != std::string::npos )
 
  770            if( layer.
name.find( 
"B" ) != std::string::npos )
 
  775        else if( layer.
name.find( 
"PAST" ) != std::string::npos )
 
  777            if( layer.
name.find( 
"B" ) != std::string::npos )
 
  782        else if( layer.
name.find( 
"NCLEGEND" ) != std::string::npos )
 
  791            if( layer.
name.find( 
"AUTOSILK" ) == std::string::npos )
 
  793                if( next_user_layer <= 
User_9 )
 
  796                    layer.
layerid = next_user_layer;
 
  797                    next_user_layer += 2;
 
  805                    wxLogWarning( 
_( 
"No user layer to put layer %s" ), layer.
name );
 
  813    for( 
size_t layeri = 0; layeri < layer_order.size(); ++layeri )
 
  818        else if( layeri == layer_order.size() - 1 )
 
  821            layer->
layerid = layeri * 2 + 2;
 
  824    for( 
auto& new_pair : extra_layers )
 
  828        new_layer.
name = new_pair.first;
 
  829        new_layer.
layerid = new_pair.second;
 
  832        auto result = 
layers.emplace( new_pair.first, new_layer );
 
  836            result.first->second.layerid = new_pair.second;
 
  837            result.first->second.disable = 
false;
 
  841    for( 
const auto& [layer_name, fabmaster_layer] : 
layers )
 
  843        wxLogTrace( 
traceFabmaster, wxT( 
"Layer %s -> KiCad layer %d" ), layer_name,
 
  844                    fabmaster_layer.layerid );
 
 
  858    size_t rownum = aRow + 2;
 
  860    if( rownum >= 
rows.size() )
 
  863    auto& header = 
rows[aRow];
 
  866    if( scale_factor <= 0.0 )
 
  874    int layer_er_col        = 
getColFromName( aRow, 
"LAYERDIELECTRICCONSTANT" );
 
  875    int layer_rho_col       = 
getColFromName( aRow, 
"LAYERELECTRICALCONDUCTIVITY" );
 
  878    if( layer_sort_col < 0 || layer_subclass_col < 0 || layer_art_col < 0 || layer_use_col < 0
 
  879            || layer_cond_col < 0 || layer_er_col < 0 || layer_rho_col < 0 || layer_mat_col < 0 )
 
  882    for( ; rownum < 
rows.size() && 
rows[rownum].size() > 0 && 
rows[rownum][0] == 
"S"; ++rownum )
 
  886        if( row.size() != header.size() )
 
  888            wxLogError( 
_( 
"Invalid row size in row %zu. Expecting %zu elements but found %zu." ),
 
  895        auto& layer_sort = row[layer_sort_col];
 
  896        auto& layer_subclass = row[layer_subclass_col];
 
  897        auto& layer_art = row[layer_art_col];
 
  898        auto& layer_use = row[layer_use_col];
 
  899        auto& layer_cond = row[layer_cond_col];
 
  900        auto& layer_er = row[layer_er_col];
 
  901        auto& layer_rho = row[layer_rho_col];
 
  902        auto& layer_mat = row[layer_mat_col];
 
  904        if( layer_mat == 
"AIR" )
 
  909        if( layer_subclass.empty() )
 
  911            if( layer_cond != 
"NO" )
 
  912                layer.
name = 
"In.Cu" + layer_sort;
 
  914                layer.
name = 
"Dielectric" + layer_sort;
 
  917        layer.
positive = ( layer_art != 
"NEGATIVE" );
 
  922    return rownum - aRow;
 
 
  933    size_t rownum = aRow + 2;
 
  935    if( rownum >= 
rows.size() )
 
  938    auto& header = 
rows[aRow];
 
  941    if( scale_factor <= 0.0 )
 
  946    int pad_grdata_name_col  = 
getColFromName( aRow, 
"GRAPHICDATANAME" );
 
  947    int pad_grdata_num_col   = 
getColFromName( aRow, 
"GRAPHICDATANUMBER" );
 
  962    if( pad_subclass_col < 0 || pad_shape_name_col < 0 || pad_grdata1_col < 0 || pad_grdata2_col < 0
 
  963            || pad_grdata3_col < 0 || pad_grdata4_col < 0 || pad_grdata5_col < 0
 
  964            || pad_grdata6_col < 0 || pad_grdata7_col < 0 || pad_grdata8_col < 0
 
  965            || pad_grdata9_col < 0 || pad_stack_name_col < 0 || pad_refdes_col < 0
 
  966            || pad_pin_num_col < 0 )
 
  969    for( ; rownum < 
rows.size() && 
rows[rownum].size() > 0 && 
rows[rownum][0] == 
"S"; ++rownum )
 
  973        if( row.size() != header.size() )
 
  975            wxLogError( 
_( 
"Invalid row size in row %zu. Expecting %zu elements but found %zu." ),
 
  983        auto& pad_layer         = row[pad_subclass_col];
 
  984        auto pad_shape_name     = row[pad_shape_name_col];
 
  985        auto& pad_record_tag    = row[pad_record_tag_col];
 
 1000        auto& pad_stack_name     = row[pad_stack_name_col];
 
 1001        auto& pad_refdes         = row[pad_refdes_col];
 
 1002        auto& pad_pin_num        = row[pad_pin_num_col];
 
 1006        std::string prefix( 
"FIG_SHAPE " );
 
 1008        if( pad_shape_name.length() <= prefix.length()
 
 1009                || !std::equal( prefix.begin(), prefix.end(), pad_shape_name.begin() ) )
 
 1019        if( std::sscanf( pad_record_tag.c_str(), 
"%d %d", &
id, &seq ) != 2 )
 
 1021            wxLogError( 
_( 
"Invalid format for id string '%s' in custom pad row %zu." ),
 
 1022                        pad_record_tag.c_str(),
 
 1027        auto name = pad_shape_name.substr( prefix.length() );
 
 1028        name += 
"_" + pad_refdes + 
"_" + pad_pin_num;
 
 1031        auto& custom_pad = ret.first->second;
 
 1037            custom_pad.name = 
name;
 
 1038            custom_pad.padstack = pad_stack_name;
 
 1039            custom_pad.pinnum = pad_pin_num;
 
 1040            custom_pad.refdes = pad_refdes;
 
 1047        auto gr_item = std::unique_ptr<GRAPHIC_ITEM>( 
processGraphic( gr_data, scale_factor ) );
 
 1051            gr_item->layer = pad_layer;
 
 1052            gr_item->refdes = pad_refdes;
 
 1054            gr_item->subseq = 0;
 
 1059            auto retval = pad_it.first->second.insert( std::move(gr_item ) );
 
 1061            if( !retval.second )
 
 1063                wxLogError( 
_( 
"Could not insert graphical item %d into padstack '%s'." ),
 
 1065                            pad_stack_name.c_str() );
 
 1070            wxLogError( 
_( 
"Unrecognized pad shape primitive '%s' in row %zu." ),
 
 1076    return rownum - aRow;
 
 
 1126    angle = endangle - startangle;
 
 
 1161    std::unique_ptr<GRAPHIC_ARC> new_circle = std::make_unique<GRAPHIC_ARC>();
 
 1172    if( size.x != size.y )
 
 1174        wxLogError( 
_( 
"Circle with unequal x and y radii (x=%d, y=%d)" ), size.x, size.y );
 
 1180    new_circle->radius = size.x / 2;
 
 1186    new_circle->start_x = start.
x;
 
 1187    new_circle->start_y = start.
y;
 
 1189    new_circle->end_x = start.
x;
 
 1190    new_circle->end_y = start.
y;
 
 1192    new_circle->center_x = 
center.x;
 
 1193    new_circle->center_y = 
center.y;
 
 1195    new_circle->clockwise = 
true;
 
 1197    new_circle->result = 
SHAPE_ARC{ start, mid, start, 0 };
 
 1199    return new_circle.release();
 
 
 1219    new_rect->
width   = 0;
 
 
 1233    auto new_rect = std::make_unique<GRAPHIC_RECTANGLE>();
 
 1242    new_rect->start_x = center_x - size_x / 2;
 
 1243    new_rect->start_y = center_y + size_y / 2;
 
 1244    new_rect->end_x = center_x + size_x / 2;
 
 1245    new_rect->end_y = center_y - size_y / 2;
 
 1247    new_rect->width = 0;
 
 1249    return new_rect.release();
 
 
 1274    auto new_oblong = std::make_unique<GRAPHIC_OBLONG>();
 
 1286    return new_oblong.release();
 
 
 1314        wxLogDebug( 
"FABMASTER::processPolygon: Expected x and y to be the same, got x = %s and y = %s ",
 
 1318    auto new_poly = std::make_unique<GRAPHIC_POLYGON>();
 
 1323    bool      across_corners = 
true;
 
 1357        across_corners = 
false;
 
 1363        wxCHECK_MSG( 
false, 
nullptr,
 
 1364                     wxString::Format( 
"Unhandled polygon type: %s", aData.
graphic_dataname ) );
 
 1369    return new_poly.release();
 
 
 1380    auto new_cross = std::make_unique<GRAPHIC_CROSS>();
 
 1389    return new_cross.release();
 
 
 1413    if( toks.size() < 8 )
 
 1416            wxLogError( 
_( 
"Invalid token count. Expected 8 but found %zu." ), toks.size() );
 
 1418            new_text->
width  = 0;
 
 1419            new_text->
ital   = 
false;
 
 
 1493    size_t rownum = aRow + 2;
 
 1495    if( rownum >= 
rows.size() )
 
 1501    if( scale_factor <= 0.0 )
 
 1520    if( geo_name_col < 0 || geo_num_col < 0 || geo_grdata1_col < 0 || geo_grdata2_col < 0
 
 1521            || geo_grdata3_col < 0 || geo_grdata4_col < 0 || geo_grdata5_col < 0
 
 1522            || geo_grdata6_col < 0 || geo_grdata7_col < 0 || geo_grdata8_col < 0
 
 1523            || geo_grdata9_col < 0 || geo_subclass_col < 0 || geo_sym_name_col < 0
 
 1524            || geo_refdes_col < 0 )
 
 1527    for( ; rownum < 
rows.size() && 
rows[rownum].size() > 0 && 
rows[rownum][0] == 
"S"; ++rownum )
 
 1531        if( row.size() != header.size() )
 
 1533            wxLogError( 
_( 
"Invalid row size in row %zu. Expecting %zu elements but found %zu." ),
 
 1540        auto& geo_tag = row[geo_tag_col];
 
 1555        auto& geo_refdes = row[geo_refdes_col];
 
 1563        if( std::sscanf( geo_tag.c_str(), 
"%d %d %d", &
id, &seq, &subseq ) < 2 )
 
 1565            wxLogError( 
_( 
"Invalid format for record_tag string '%s' in row %zu." ),
 
 1571        auto gr_item = std::unique_ptr<GRAPHIC_ITEM>( 
processGraphic( gr_data, scale_factor ) );
 
 1575            wxLogDebug( wxT( 
"Unhandled graphic item '%s' in row %zu." ),
 
 1582        gr_item->layer = row[geo_subclass_col];
 
 1584        gr_item->subseq = subseq;
 
 1586        if( geo_refdes.empty() )
 
 1591                new_gr.
subclass = row[geo_subclass_col];
 
 1592                new_gr.
refdes   = row[geo_refdes_col];
 
 1593                new_gr.
name     = row[geo_sym_name_col];
 
 1595                new_gr.
elements = std::make_unique<graphic_element>();
 
 1600            graphic.
elements->emplace( std::move( gr_item ) );
 
 1605                    std::map<int, GEOM_GRAPHIC>{} );
 
 1606            auto map_it = sym_gr_it.first->second.emplace( 
id, 
GEOM_GRAPHIC{} );
 
 1607            auto& gr = map_it.first;
 
 1611                gr->second.subclass = row[geo_subclass_col];
 
 1612                gr->second.refdes   = row[geo_refdes_col];
 
 1613                gr->second.name     = row[geo_sym_name_col];
 
 1615                gr->second.elements = std::make_unique<graphic_element>();
 
 1618            auto result = gr->second.elements->emplace( std::move( gr_item ) );
 
 1622    return rownum - aRow;
 
 
 1631    size_t rownum = aRow + 2;
 
 1633    if( rownum >= 
rows.size() )
 
 1639    if( scale_factor <= 0.0 )
 
 1648    if( viax_col < 0 || viay_col < 0 || padstack_name_col < 0 || net_name_col < 0
 
 1649            || test_point_col < 0 )
 
 1652    for( ; rownum < 
rows.size() && 
rows[rownum].size() > 0 && 
rows[rownum][0] == 
"S"; ++rownum )
 
 1656        if( row.size() != header.size() )
 
 1658            wxLogError( 
_( 
"Invalid row size in row %zu. Expecting %zu elements but found %zu." ),
 
 1665        vias.emplace_back( std::make_unique<FM_VIA>() );
 
 1670        via->padstack = row[padstack_name_col];
 
 1671        via->net = row[net_name_col];
 
 1672        via->test_point = ( row[test_point_col] == 
"YES" );
 
 1675    return rownum - aRow;
 
 
 1686    size_t rownum = aRow + 2;
 
 1688    if( rownum >= 
rows.size() )
 
 1694    if( scale_factor <= 0.0 )
 
 1700    int grdata_num_col = 
getColFromName( aRow, 
"GRAPHICDATANUMBER" );
 
 1713    if( class_col < 0 || layer_col < 0 || grdata_name_col < 0 || grdata_num_col < 0
 
 1714            || tag_col < 0 || grdata1_col < 0 || grdata2_col < 0 || grdata3_col < 0
 
 1715            || grdata4_col < 0 || grdata5_col < 0 || grdata6_col < 0 || grdata7_col < 0
 
 1716            || grdata8_col < 0 || grdata9_col < 0 || netname_col < 0 )
 
 1719    for( ; rownum < 
rows.size() && 
rows[rownum].size() > 0 && 
rows[rownum][0] == 
"S"; ++rownum )
 
 1723        if( row.size() != header.size() )
 
 1725            wxLogError( 
_( 
"Invalid row size in row %zu.  Expecting %zu elements but found %zu." ),
 
 1745        const std::string& geo_tag = row[tag_col];
 
 1752        if( std::sscanf( geo_tag.c_str(), 
"%d %d %d", &
id, &seq, &subseq ) < 2 )
 
 1754            wxLogError( 
_( 
"Invalid format for record_tag string '%s' in row %zu." ),
 
 1760        auto gr_item = std::unique_ptr<GRAPHIC_ITEM>( 
processGraphic( gr_data, scale_factor ) );
 
 1764            wxLogTrace( 
traceFabmaster,  
_( 
"Unhandled graphic item '%s' in row %zu." ),
 
 1770        auto new_trace = std::make_unique<TRACE>();
 
 1772        new_trace->layer   = row[layer_col];
 
 1773        new_trace->netname = row[netname_col];
 
 1774        new_trace->lclass  = row[class_col];
 
 1776        gr_item->layer = row[layer_col];
 
 1778        gr_item->subseq = subseq;
 
 1781        if( new_trace->lclass == 
"REF DES" )
 
 1783            auto result = 
refdes.emplace( std::move( new_trace ) );
 
 1784            auto& ref   = *
result.first;
 
 1785            ref->segment.emplace( std::move( gr_item ) );
 
 1787        else if( new_trace->lclass == 
"DEVICE TYPE" || new_trace->lclass == 
"COMPONENT VALUE" 
 1788                 || new_trace->lclass == 
"TOLERANCE" )
 
 1801        else if( gr_item->width == 0 )
 
 1803            auto result = 
zones.emplace( std::move( new_trace ) );
 
 1804            auto& zone  = *
result.first;
 
 1805            auto gr_result = zone->segment.emplace( std::move( gr_item ) );
 
 1807            if( !gr_result.second )
 
 1809                wxLogError( 
_( 
"Duplicate item for ID %d and sequence %d in row %zu." ),
 
 1817            auto result = 
traces.emplace( std::move( new_trace ) );
 
 1818            auto& trace  = *
result.first;
 
 1819            auto gr_result = trace->segment.emplace( std::move( gr_item ) );
 
 1821            if( !gr_result.second )
 
 1823                wxLogError( 
_( 
"Duplicate item for ID %d and sequence %d in row %zu." ),
 
 1831    return rownum - aRow;
 
 
 1837    if( aSymType == 
"PACKAGE" )
 
 1839    else if( aSymType == 
"DRAFTING")
 
 1841    else if( aSymType == 
"MECHANICAL" )
 
 1843    else if( aSymType == 
"FORMAT" )
 
 
 1852    if( aCmpClass == 
"IO" )
 
 1854    else if( aCmpClass == 
"IC" )
 
 1856    else if( aCmpClass == 
"DISCRETE" )
 
 
 1869    size_t rownum = aRow + 2;
 
 1871    if( rownum >= 
rows.size() )
 
 1877    if( scale_factor <= 0.0 )
 
 1885    int compinscode_col = 
getColFromName( aRow, 
"COMPINSERTIONCODE" );
 
 1896    if( refdes_col < 0 || compclass_col < 0 || comppartnum_col < 0 || compheight_col < 0
 
 1897            || compdevlabelcol < 0 || compinscode_col < 0 || symtype_col < 0 || symname_col < 0
 
 1898            || symmirror_col < 0 || symrotate_col < 0 || symx_col < 0 || symy_col < 0
 
 1899            || compvalue_col < 0 || comptol_col < 0 || compvolt_col < 0 )
 
 1902    for( ; rownum < 
rows.size() && 
rows[rownum].size() > 0 && 
rows[rownum][0] == 
"S"; ++rownum )
 
 1906        if( row.size() != header.size() )
 
 1908            wxLogError( 
_( 
"Invalid row size in row %zu. Expecting %zu elements but found %zu." ),
 
 1915        const wxString& 
refdes = row[refdes_col];
 
 1917        if( row[symx_col].
empty() || row[symy_col].
empty() || row[symrotate_col].
empty() )
 
 1919            wxLogError( 
_( 
"Missing X, Y, or rotation data in row %zu for refdes %s. " 
 1920                           "This may be an unplaced component." ),
 
 1925        auto cmp = std::make_unique<COMPONENT>();
 
 1929        cmp->pn = row[comppartnum_col];
 
 1930        cmp->height = row[compheight_col];
 
 1931        cmp->dev_label = row[compdevlabelcol];
 
 1932        cmp->insert_code = row[compinscode_col];
 
 1934        cmp->name = row[symname_col];
 
 1935        cmp->mirror = ( row[symmirror_col] == 
"YES" );
 
 1936        cmp->rotate = 
readDouble( row[symrotate_col] );
 
 1939        cmp->value = row[compvalue_col];
 
 1940        cmp->tol = row[comptol_col];
 
 1941        cmp->voltage = row[compvolt_col];
 
 1947            auto retval = 
components.insert( std::make_pair( cmp->refdes, std::vector<std::unique_ptr<COMPONENT>>{} ) );
 
 1952        vec->second.push_back( std::move( cmp ) );
 
 1955    return rownum - aRow;
 
 
 1965    size_t rownum = aRow + 2;
 
 1967    if( rownum >= 
rows.size() )
 
 1973    if( scale_factor <= 0.0 )
 
 1987    if( symname_col < 0 ||symmirror_col < 0 || pinname_col < 0 || pinnum_col < 0 || pinx_col < 0
 
 1988            || piny_col < 0 || padstack_col < 0 || refdes_col < 0 || pinrot_col < 0
 
 1989            || testpoint_col < 0 )
 
 1992    for( ; rownum < 
rows.size() && 
rows[rownum].size() > 0 && 
rows[rownum][0] == 
"S"; ++rownum )
 
 1996        if( row.size() != header.size() )
 
 1998            wxLogError( 
_( 
"Invalid row size in row %zu. Expecting %zu elements but found %zu." ),
 
 2005        auto pin = std::make_unique<PIN>();
 
 2007        pin->name = row[symname_col];
 
 2008        pin->mirror = ( row[symmirror_col] == 
"YES" );
 
 2009        pin->pin_name = row[pinname_col];
 
 2010        pin->pin_number = row[pinnum_col];
 
 2013        pin->padstack = row[padstack_col];
 
 2014        pin->refdes = row[refdes_col];
 
 2017        auto map_it = 
pins.find( 
pin->refdes );
 
 2019        if( map_it == 
pins.end() )
 
 2021            auto retval = 
pins.insert( std::make_pair( 
pin->refdes, std::set<std::unique_ptr<PIN>,
 
 2023            map_it = retval.first;
 
 2026        map_it->second.insert( std::move( 
pin ) );
 
 2029    return rownum - aRow;
 
 
 2038    size_t rownum = aRow + 2;
 
 2040    if( rownum >= 
rows.size() )
 
 2046    if( scale_factor <= 0.0 )
 
 2056    if( netname_col < 0 || refdes_col < 0 || pinnum_col < 0 || pinname_col < 0 || pingnd_col < 0
 
 2060    for( ; rownum < 
rows.size() && 
rows[rownum].size() > 0 && 
rows[rownum][0] == 
"S"; ++rownum )
 
 2064        if( row.size() != header.size() )
 
 2066            wxLogError( 
_( 
"Invalid row size in row %zu. Expecting %zu elements but found %zu." ),
 
 2074        new_net.
name = row[netname_col];
 
 2075        new_net.
refdes = row[refdes_col];
 
 2076        new_net.
pin_num = row[pinnum_col];
 
 2077        new_net.
pin_name = row[pinname_col];
 
 2078        new_net.
pin_gnd = ( row[pingnd_col] == 
"YES" );
 
 2079        new_net.
pin_pwr = ( row[pinpwr_col] == 
"YES" );
 
 2082        netnames.insert( row[netname_col] );
 
 2085    return rownum - aRow;
 
 
 2092    for( 
size_t i = 0; i < 
rows.size(); )
 
 2106            i += std::max( retval, 1 );
 
 2114            i += std::max( retval, 1 );
 
 2122            i += std::max( retval, 1 );
 
 2130            i += std::max( retval, 1 );
 
 2138            i += std::max( retval, 1 );
 
 2146            i += std::max( retval, 1 );
 
 2154            i += std::max( retval, 1 );
 
 2162            i += std::max( retval, 1 );
 
 2170            i += std::max( retval, 1 );
 
 2178            i += std::max( retval, 1 );
 
 
 2195    for( 
auto& zone : 
zones )
 
 2205            if( zone->layer == 
"OUTLINE" || zone->layer == 
"DESIGN_OUTLINE" )
 
 2226    std::set<ZONE*> zones_to_delete;
 
 2228    for( 
auto zone : aBoard->
Zones() )
 
 2231        if( zone->GetNetCode() > 0 )
 
 2233            zones_to_delete.insert( zone );
 
 2237    for( 
auto zone1 : aBoard->
Zones() )
 
 2240        if( zone1->GetNetCode() > 0 )
 
 2245        std::vector<std::vector<ZONE*>> possible_deletions( overlaps.size() );
 
 2247        for( 
auto zone2 : aBoard->
Zones() )
 
 2249            if( zone2->GetNetCode() <= 0 )
 
 2254            if( zone1->GetLayer() != zone2->GetLayer() )
 
 2260            for( 
auto& pt1 : outline1.
CPoints() )
 
 2264                    overlaps[ zone2->GetNetCode() ]++;
 
 2267            for( 
auto& pt2 : outline2.
CPoints() )
 
 2272                    overlaps[ zone2->GetNetCode() ]++;
 
 2277        size_t max_net_id = 0;
 
 2279        for( 
size_t el = 1; el < overlaps.size(); ++el )
 
 2281            if( overlaps[el] > max_net )
 
 2283                max_net = overlaps[el];
 
 2289            zone1->SetNetCode( max_net_id );
 
 2292    for( 
auto zone : zones_to_delete )
 
 
 2312    if( aMirrorPoint.has_value() )
 
 
 2352        bool has_multiple = mod.second.size() > 1;
 
 2354        for( 
int i = 0; i < mod.second.size(); ++i )
 
 2356            auto& src = mod.second[i];
 
 2360            wxString mod_ref = src->name;
 
 2364                mod_ref.Append( wxString::Format( wxT( 
"_%d" ), i ) );
 
 2369            wxString key = !lib_ref.empty() ? lib_ref + wxT( 
":" ) + mod_ref : mod_ref;
 
 2372            fpID.
Parse( key, 
true );
 
 2381            wxString reference = src->refdes;
 
 2383            if( !std::isalpha( src->refdes[0] ) )
 
 2384                reference.Prepend( 
"UNK" );
 
 2397            for( 
auto& ref : 
refdes )
 
 2400                        static_cast<const GRAPHIC_TEXT&
>( **ref->segment.begin() );
 
 2402                if( lsrc.
text == src->refdes )
 
 2409                        wxLogTrace( 
traceFabmaster, wxS( 
"The layer %s is not mapped?" ),
 
 2410                                                         ref->layer.c_str() );
 
 2421                        flip_point = 
VECTOR2I( src->x, src->y );
 
 2426                    setupText( lsrc, layer, *txt, *aBoard, flip_point );
 
 2445            for( 
auto& gr_ref : gr_it->second )
 
 2447                auto& graphic = gr_ref.second;
 
 2449                for( 
auto& seg : *graphic.elements )
 
 2456                    STROKE_PARAMS defaultStroke( ds.GetLineThickness( layer ) );
 
 2458                    switch( seg->shape )
 
 2482                        if( lsrc->
width == 0 )
 
 2494                        circle->SetLayer( layer );
 
 2506                        if( lsrc.
width == 0 )
 
 2512                            if( lsrc.
layer == 
"DISPLAY_TOP" || lsrc.
layer == 
"DISPLAY_BOTTOM" )
 
 2513                                circle->SetFilled( 
true );
 
 2515                                circle->SetWidth( ds.GetLineThickness( 
circle->GetLayer() ) );
 
 2528                        std::unique_ptr<PCB_SHAPE> arc =
 
 2542                        arc->SetLayer( layer );
 
 2546                        if( lsrc->
width == 0 )
 
 2547                            arc->SetStroke( defaultStroke );
 
 2584                        std::unique_ptr<PCB_TEXT> txt = std::make_unique<PCB_TEXT>( fp );
 
 2589                            flip_point = 
VECTOR2I( src->x, src->y );
 
 2591                        setupText( lsrc, layer, *txt, *aBoard, flip_point );
 
 2614            auto pin_it = 
pins.find( src->refdes );
 
 2616            if( pin_it != 
pins.end() )
 
 2618                for( 
auto& 
pin : pin_it->second )
 
 2620                    auto pin_net_it = 
pin_nets.find( std::make_pair( 
pin->refdes,
 
 2621                                                                     pin->pin_number ) );
 
 2622                    auto padstack = 
pads.find( 
pin->padstack );
 
 2623                    std::string netname = 
"";
 
 2626                        netname = pin_net_it->second.name;
 
 2628                    auto net_it = netinfo.find( netname );
 
 2630                    std::unique_ptr<PAD> newpad = std::make_unique<PAD>( fp );
 
 2632                    if( net_it != netinfo.end() )
 
 2633                        newpad->SetNet( net_it->second );
 
 2635                        newpad->SetNetCode( 0 );
 
 2637                    newpad->SetX( 
pin->pin_x );
 
 2640                        newpad->SetY( 2 * src->y - 
pin->pin_y );
 
 2642                        newpad->SetY( 
pin->pin_y );
 
 2644                    newpad->SetNumber( 
pin->pin_number );
 
 2646                    if( padstack == 
pads.end() )
 
 2648                        wxLogError( 
_( 
"Unable to locate padstack %s in file %s\n" ),
 
 2654                        auto& 
pad = padstack->second;
 
 2662                            int pad_size = std::min( 
pad.width, 
pad.height );
 
 2665                                             VECTOR2I( pad_size / 2, pad_size / 2 ) );
 
 2667                            std::string custom_name = 
pad.custom_name + 
"_" + 
pin->refdes + 
"_" +
 
 2669                            auto custom_it = 
pad_shapes.find( custom_name );
 
 2675                                int last_subseq = 0;
 
 2682                                for( 
const auto& el : (*custom_it).second.elements )
 
 2689                                    if( 
getLayer( ( *( el.second.begin() ) )->layer ) != primary_layer )
 
 2692                                    for( 
const auto& seg : el.second )
 
 2694                                        if( seg->subseq > 0 || seg->subseq != last_subseq )
 
 2696                                            poly_outline.
Polygon(0).back().SetClosed( 
true );
 
 2704                                            if( poly_outline.
VertexCount( 0, hole_idx ) == 0 )
 
 2724                                    wxLogError( 
_( 
"Invalid custom pad '%s'. Replacing with " 
 2726                                                custom_name.c_str() );
 
 2733                                    poly_outline.
Move( -newpad->GetPosition() );
 
 2756                                    wxLogError( 
_( 
"Invalid custom pad '%s'. Replacing with " 
 2758                                                custom_name.c_str() );
 
 2764                                wxLogError( 
_( 
"Could not find custom pad '%s'." ),
 
 2765                                            custom_name.c_str() );
 
 2787                            if( 
pad.drill_size_x == 
pad.drill_size_y )
 
 2792                            newpad->SetDrillSize( 
VECTOR2I( 
pad.drill_size_x, 
pad.drill_size_y ) );
 
 2800                            else if( 
pad.bottom )
 
 2801                                newpad->SetLayerSet( 
PAD::SMDMask().FlipStandardLayers() );
 
 2806                        newpad->SetOrientation( 
EDA_ANGLE( -src->rotate + 
pin->rotation,
 
 2809                        newpad->SetOrientation( 
EDA_ANGLE( src->rotate - 
pin->rotation,
 
 2812                    if( newpad->GetSizeX() > 0 || newpad->GetSizeY() > 0 )
 
 2818                        wxLogError( 
_( 
"Invalid zero-sized pad ignored in\nfile: %s" ),
 
 
 2845    for( 
auto& layer : 
layers )
 
 2850            layer_set.
set( layer.second.layerid );
 
 2855    for( 
auto& layer : 
layers )
 
 2857        if( layer.second.conductive )
 
 2860                    layer.second.name );
 
 
 2877        auto net_it = netinfo.find( 
via->net );
 
 2878        auto padstack = 
pads.find( 
via->padstack );
 
 2884        if( net_it != netinfo.end() )
 
 2885            new_via->
SetNet( net_it->second );
 
 2887        if( padstack == 
pads.end() )
 
 2891            if( !ds.m_ViasDimensionsList.empty() )
 
 2894                new_via->
SetDrill( ds.m_ViasDimensionsList[0].m_Drill );
 
 2904            new_via->
SetDrill( padstack->second.drill_size_x );
 
 
 2932    auto net_it = netinfo.find( aLine->netname );
 
 2934    int  last_subseq = 0;
 
 2935    ZONE* new_zone = 
nullptr;
 
 2937    for( 
const auto& seg : aLine->segment )
 
 2943            switch( seg->shape )
 
 2956                if( net_it != netinfo.end() )
 
 2957                    trk->
SetNet( net_it->second );
 
 2970                if( net_it != netinfo.end() )
 
 2971                    trk->
SetNet( net_it->second );
 
 2979                for( std::unique_ptr<BOARD_ITEM>& new_item :
 
 2990            wxLogError( 
_( 
"Expecting etch data to be on copper layer. Row found on layer '%s'" ),
 
 2991                        seg->layer.c_str() );
 
 
 3002    int last_subseq = 0;
 
 3007    for( 
const auto& seg : aElement )
 
 3009        if( seg->subseq > 0 || seg->subseq != last_subseq )
 
 3016            if( poly_outline.
VertexCount( 0, hole_idx ) == 0 )
 
 3030    return poly_outline;
 
 
 3057    if( aLine.
segment.size() == 0 )
 
 3063    int                 first_subseq = -1;
 
 3064    bool                have_multiple_subseqs = 
false;
 
 3066    for( 
const std::unique_ptr<GRAPHIC_ITEM>& gr_item : aLine.
segment )
 
 3068        if( first == 
nullptr )
 
 3070            first = gr_item.get();
 
 3071            first_subseq = gr_item->subseq;
 
 3073        else if( gr_item->subseq == first_subseq )
 
 3075            last = gr_item.get();
 
 3079            have_multiple_subseqs = 
true;
 
 3085    wxCHECK( first, 
true );
 
 3103    switch( last->
shape )
 
 3123    if( 
end.has_value() && start == 
end )
 
 
 3131std::vector<std::unique_ptr<BOARD_ITEM>>
 
 3134    std::vector<std::unique_ptr<BOARD_ITEM>> new_items;
 
 3139    const auto setShapeParameters = [&]( 
PCB_SHAPE& aShape )
 
 3143        if( aShape.GetWidth() == 0 )
 
 3144            aShape.SetStroke( defaultStroke );
 
 3147    switch( aGraphic.
shape )
 
 3153        auto new_text = std::make_unique<PCB_TEXT>( &aBoard );
 
 3157            new_text->SetMirrored( 
true );
 
 3160        setupText( src, aLayer, *new_text, aBoard, std::nullopt );
 
 3162        new_items.emplace_back( std::move( new_text ) );
 
 3174        for( 
const SEG& seg : segs )
 
 3176            auto line = std::make_unique<PCB_SHAPE>( &aBoard );
 
 3178            line->SetStart( seg.A );
 
 3179            line->SetEnd( seg.B );
 
 3181            setShapeParameters( *line );
 
 3182            new_items.emplace_back( std::move( line ) );
 
 3189        auto new_shape = std::make_unique<PCB_SHAPE>( &aBoard );
 
 3191        setShapeParameters( *new_shape );
 
 3193        switch( aGraphic.
shape )
 
 3220            new_shape->SetRadius( src.
radius );
 
 3231            new_shape->SetFilled( src.
fill );
 
 3238            new_shape->SetPolyPoints( src.
m_pts );
 
 3267            new_shape->SetPolyShape( poly );
 
 3272            wxLogError( 
_( 
"Unhandled shape type %d in polygon on layer %s, seq %d %d" ),
 
 3277        new_items.emplace_back( std::move( new_shape ) );
 
 3281    for( std::unique_ptr<BOARD_ITEM>& new_item : new_items )
 
 3283        new_item->SetLayer( aLayer );
 
 3287    if( new_items.size() > 1 )
 
 3289        auto new_group = std::make_unique<PCB_GROUP>( &aBoard );
 
 3290        for( std::unique_ptr<BOARD_ITEM>& new_item : new_items )
 
 3292            new_group->AddItem( new_item.get() );
 
 3294        new_items.emplace_back( std::move( new_group ) );
 
 
 3303    if( aLine->segment.empty() )
 
 3317        for( 
const auto& seg : aLine->segment )
 
 3319            for( std::unique_ptr<BOARD_ITEM>& new_item : 
createBoardItems( *aBoard, layer, *seg ) )
 
 
 3366    if( aLine->segment.size() < 3 )
 
 3370    ZONE* zone = 
nullptr;
 
 3373    auto net_it = netinfo.find( aLine->netname );
 
 3375    auto new_layer = 
getLayer( aLine->layer );
 
 3380    zone = 
new ZONE( aBoard );
 
 3383    if( net_it != netinfo.end() )
 
 3384        zone->
SetNet( net_it->second );
 
 3386    if( aLine->layer == 
"ALL" )
 
 3398    if( aLine->lclass == 
"ROUTE KEEPOUT")
 
 3403    else if( aLine->lclass == 
"VIA KEEPOUT")
 
 3418    std::unique_ptr<SHAPE_LINE_CHAIN> pending_hole = 
nullptr;
 
 3421    const auto add_hole_if_valid = [&]()
 
 3425            pending_hole->SetClosed( 
true );
 
 3431                wxLogMessage( 
_( 
"Invalid hole with %d points in zone on layer %s with net %s" ),
 
 3436            pending_hole.reset();
 
 3440    int last_subseq = 0;
 
 3441    for( 
const auto& seg : aLine->segment )
 
 3443        if( seg->subseq > 0 && seg->subseq != last_subseq )
 
 3447            if( aLine->lclass == 
"BOUNDARY" )
 
 3450            add_hole_if_valid();
 
 3451            pending_hole = std::make_unique<SHAPE_LINE_CHAIN>();
 
 3452            active_chain = pending_hole.get();
 
 3453            last_subseq = seg->subseq;
 
 3464                active_chain->
Append( start );
 
 3473                    wxLogError( 
_( 
"Outline seems discontinuous: last point was %s, " 
 3474                                   "start point of next segment is %s" ),
 
 3489            wxLogError( 
_( 
"Invalid shape type %d in zone outline" ), seg->shape );
 
 3494    add_hole_if_valid();
 
 3503        delete( zone_outline );
 
 
 3515    if( aLine->lclass == 
"BOARD GEOMETRY" && aLine->layer != 
"DIMENSION" )
 
 3517    else if( aLine->lclass == 
"DRAWING FORMAT" )
 
 3522    for( 
auto& seg : aLine->segment )
 
 3524        for( std::unique_ptr<BOARD_ITEM>& new_item : 
createBoardItems( *aBoard, layer, *seg ) )
 
 
 3544        if( geom.subclass == 
"PIN_NUMBER" )
 
 3552        if( !geom.elements->empty() )
 
 3555            if( ( *( geom.elements->begin() ) )->width == 0 )
 
 3576        for( 
auto& seg : *geom.elements )
 
 3578            for( std::unique_ptr<BOARD_ITEM>& new_item : 
createBoardItems( *aBoard, layer, *seg ) )
 
 
 3592    std::vector<ZONE*> sortedZones;
 
 3593    std::copy( aBoard->
Zones().begin(), aBoard->
Zones().end(), std::back_inserter( sortedZones ) );
 
 3594    std::sort( sortedZones.begin(), sortedZones.end(),
 
 3595            [&]( 
const ZONE* a, 
const ZONE* b )
 
 3597                if( a->GetLayer() == b->GetLayer() )
 
 3598                    return a->GetBoundingBox().GetArea() > b->GetBoundingBox().GetArea();
 
 3600                return a->GetLayer() < b->GetLayer();
 
 3604    unsigned int priority = 0;
 
 3606    for( 
ZONE* zone : sortedZones )
 
 3609        if( zone->GetIsRuleArea() )
 
 3612        if( zone->GetLayer() != layer )
 
 3614            layer = zone->GetLayer();
 
 3618        zone->SetAssignedPriority( priority );
 
 
 3647    for( 
auto& track : 
traces )
 
 3651        if( track->lclass == 
"ETCH" )
 
 3653        else if( track->layer == 
"OUTLINE" || track->layer == 
"DIMENSION" )
 
 
constexpr EDA_IU_SCALE pcbIUScale
 
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
 
BASE_SET & set(size_t pos)
 
wxString GetNetname() const
 
void SetNet(NETINFO_ITEM *aNetInfo)
Set a NET_INFO object for the item.
 
Container for design settings for a BOARD object.
 
int GetLineThickness(PCB_LAYER_ID aLayer) const
Return the default graphic segment thickness from the layer class for the given layer.
 
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
 
wxString GetLayerName() const
Return the name of the PCB layer on which the item resides.
 
Information pertinent to a Pcbnew printed circuit board.
 
const NETINFO_LIST & GetNetInfo() const
 
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
 
void SetFileName(const wxString &aFileName)
 
LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
 
const ZONES & Zones() const
 
bool SetLayerName(PCB_LAYER_ID aLayer, const wxString &aLayerName)
Changes the name of the layer given by aLayer.
 
PCB_LAYER_ID FlipLayer(PCB_LAYER_ID aLayer) const
 
const wxString & GetFileName() const
 
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
 
void Remove(BOARD_ITEM *aBoardItem, REMOVE_MODE aMode=REMOVE_MODE::NORMAL) override
Removes an item from the container.
 
void SetEnabledLayers(const LSET &aLayerMask)
A proxy function that calls the correspondent function in m_BoardSettings.
 
constexpr bool Intersects(const BOX2< Vec > &aRect) const
 
EDA_ANGLE Normalized() const
 
void SetPolyShape(const SHAPE_POLY_SET &aShape)
 
virtual void SetFilled(bool aFlag)
 
void SetStart(const VECTOR2I &aStart)
 
void SetShape(SHAPE_T aShape)
 
void SetEnd(const VECTOR2I &aEnd)
 
void SetTextPos(const VECTOR2I &aPoint)
 
void SetMirrored(bool isMirrored)
 
void SetVertJustify(GR_TEXT_V_ALIGN_T aType)
 
void SetTextWidth(int aWidth)
 
virtual void SetVisible(bool aVisible)
 
void SetTextThickness(int aWidth)
The TextThickness is that set by the user.
 
void SetTextHeight(int aHeight)
 
void SetKeepUpright(bool aKeepUpright)
 
virtual void SetText(const wxString &aText)
 
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
 
void SetItalic(bool aItalic)
Set the text to be italic - this will also update the font if needed.
 
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
 
size_t processFootprints(size_t aRow)
A!REFDES!COMP_CLASS!COMP_PART_NUMBER!COMP_HEIGHT!COMP_DEVICE_LABEL!COMP_INSERTION_CODE!...
 
size_t processPins(size_t aRow)
A!SYM_NAME!SYM_MIRROR!PIN_NAME!PIN_NUMBER!PIN_X!PIN_Y!PAD_STACK_NAME!REFDES!PIN_ROTATION!
 
int readInt(const std::string &aStr) const
 
GRAPHIC_OBLONG * processOblong(const GRAPHIC_DATA &aData, double aScale)
 
size_t processGeometry(size_t aRow)
A!GRAPHIC_DATA_NAME!GRAPHIC_DATA_NUMBER!RECORD_TAG!GRAPHIC_DATA_1!GRAPHIC_DATA_2!GRAPHIC_DATA_3!
 
static std::vector< std::unique_ptr< BOARD_ITEM > > createBoardItems(BOARD &aBoard, PCB_LAYER_ID aLayer, FABMASTER::GRAPHIC_ITEM &aGraphic)
Convert one Fabmaster graphic item to one or more PCB items.
 
bool Read(const std::string &aFile)
 
bool loadNets(BOARD *aBoard)
 
std::map< std::string, std::map< int, GEOM_GRAPHIC > > comp_graphics
 
GRAPHIC_CROSS * processCross(const GRAPHIC_DATA &aData, double aScale)
 
unsigned m_lastProgressCount
 
SYMTYPE parseSymType(const std::string &aSymType)
 
GRAPHIC_TEXT * processText(const GRAPHIC_DATA &aData, double aScale)
 
bool loadLayers(BOARD *aBoard)
 
static void setupText(const FABMASTER::GRAPHIC_TEXT &aGraphicText, PCB_LAYER_ID aLayer, PCB_TEXT &aText, const BOARD &aBoard, const OPT_VECTOR2I &aMirrorPoint)
Set parameters for graphic text.
 
PCB_LAYER_ID getLayer(const std::string &aLayerName)
 
GRAPHIC_RECTANGLE * processSquare(const GRAPHIC_DATA &aData, double aScale)
 
static bool traceIsOpen(const FABMASTER::TRACE &aLine)
 
bool loadZones(BOARD *aBoard)
Loads sections of the database into the board.
 
GRAPHIC_RECTANGLE * processRectangle(const GRAPHIC_DATA &aData, double aScale)
 
std::vector< std::string > single_row
 
size_t processSimpleLayers(size_t aRow)
 
PROGRESS_REPORTER * m_progressReporter
optional; may be nullptr
 
bool loadFootprints(BOARD *aBoard)
 
GRAPHIC_ARC * processCircle(const GRAPHIC_DATA &aData, double aScale)
 
std::unordered_map< std::string, FM_PAD > pads
 
int getColFromName(size_t aRow, const std::string &aStr)
 
bool loadVias(BOARD *aBoard)
 
size_t processLayers(size_t aRow)
A!LAYER_SORT!LAYER_SUBCLASS!LAYER_ARTWORK!LAYER_USE!LAYER_CONDUCTOR!LAYER_DIELECTRIC_CONSTANT!
 
std::map< std::string, FABMASTER_LAYER > layers
 
COMPCLASS parseCompClass(const std::string &aCompClass)
 
bool loadEtch(BOARD *aBoard, const std::unique_ptr< TRACE > &aLine)
 
GRAPHIC_RECTANGLE * processFigRectangle(const GRAPHIC_DATA &aData, double aScale)
 
std::map< std::string, std::set< std::unique_ptr< PIN >, PIN::BY_NUM > > pins
 
std::set< std::unique_ptr< GRAPHIC_ITEM >, GRAPHIC_ITEM::SEQ_CMP > graphic_element
 
std::map< std::pair< std::string, std::string >, NETNAME > pin_nets
 
GRAPHIC_ITEM * processGraphic(const GRAPHIC_DATA &aData, double aScale)
Specialty functions for processing graphical data rows into the internal database.
 
std::deque< single_row > rows
 
GRAPHIC_POLYGON * processPolygon(const GRAPHIC_DATA &aData, double aScale)
 
bool loadOutline(BOARD *aBoard, const std::unique_ptr< TRACE > &aLine)
 
size_t processPadStacks(size_t aRow)
A!PADNAME!RECNUMBER!LAYER!FIXFLAG!VIAFLAG!PADSHAPE1!PADWIDTH!PADHGHT!
 
std::vector< GEOM_GRAPHIC > board_graphics
 
section_type detectType(size_t aOffset)
 
double readDouble(const std::string &aStr) const
Reads the double/integer value from a std string independent of the user locale.
 
bool loadZone(BOARD *aBoard, const std::unique_ptr< FABMASTER::TRACE > &aLine)
 
GRAPHIC_ARC * processArc(const GRAPHIC_DATA &aData, double aScale)
 
SHAPE_POLY_SET loadShapePolySet(const graphic_element &aLine)
 
bool loadGraphics(BOARD *aBoard)
 
std::unordered_map< std::string, FABMASTER_PAD_SHAPE > pad_shapes
 
bool LoadBoard(BOARD *aBoard, PROGRESS_REPORTER *aProgressReporter)
 
std::vector< std::unique_ptr< FM_VIA > > vias
 
std::set< std::unique_ptr< TRACE >, TRACE::BY_ID > traces
 
std::set< std::unique_ptr< TRACE >, TRACE::BY_ID > zones
 
std::map< std::string, std::vector< std::unique_ptr< COMPONENT > > > components
 
bool loadPolygon(BOARD *aBoard, const std::unique_ptr< FABMASTER::TRACE > &aLine)
 
std::set< std::unique_ptr< TRACE >, TRACE::BY_ID > refdes
 
@ GR_SHAPE_OBLONG
!< Actually 360° arcs (for both arcs where start==end and real circles)
 
@ GR_SHAPE_CROSS
!< X/Y oblongs
 
size_t processPadStackLayers(size_t aRow)
 
std::set< std::string > netnames
 
size_t processTraces(size_t aRow)
A!CLASS!SUBCLASS!GRAPHIC_DATA_NAME!GRAPHIC_DATA_NUMBER!RECORD_TAG!GRAPHIC_DATA_1!GRAPHIC_DATA_2!
 
size_t processNets(size_t aRow)
A!NET_NAME!REFDES!PIN_NUMBER!PIN_NAME!PIN_GROUND!PIN_POWER!
 
bool orderZones(BOARD *aBoard)
Sets zone priorities based on zone BB size.
 
double processScaleFactor(size_t aRow)
Processes data from text vectors into internal database for further ordering.
 
size_t processVias(size_t aRow)
A!VIA_X!VIA_Y!PAD_STACK_NAME!NET_NAME!TEST_POINT!
 
unsigned m_totalCount
for progress reporting
 
size_t processCustomPads(size_t aRow)
A!SUBCLASS!PAD_SHAPE_NAME!GRAPHIC_DATA_NAME!GRAPHIC_DATA_NUMBER!RECORD_TAG!GRAPHIC_DATA_1!
 
GRAPHIC_LINE * processLine(const GRAPHIC_DATA &aData, double aScale)
 
A logical library item identifier and consists of various portions much like a URI.
 
int Parse(const UTF8 &aId, bool aFix=false)
Parse LIB_ID with the information from aId.
 
LSET is a set of PCB_LAYER_IDs.
 
static const LSET & UserMask()
 
static const LSET & AllTechMask()
Return a mask holding all technical layers (no CU layer) on both side.
 
static LSET AllCuMask(int aCuLayerCount)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
 
Handle the data for a net.
 
unsigned GetNetCount() const
 
const NETNAMES_MAP & NetsByName() const
Return the name map, at least for python.
 
static constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
 
static LSET PTHMask()
layer set for a through hole pad
 
static LSET UnplatedHoleMask()
layer set for a mechanical unplated through hole pad
 
static LSET SMDMask()
layer set for a SMD pad on Front layer
 
int GetWidth() const override
 
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
 
void SetStroke(const STROKE_PARAMS &aStroke) override
 
void SetEnd(const VECTOR2I &aEnd)
 
void SetStart(const VECTOR2I &aStart)
 
virtual void SetWidth(int aWidth)
 
void SetDrillDefault()
Set the drill value for vias to the default value UNDEFINED_DRILL_DIAMETER.
 
void SetDrill(int aDrill)
Set the drill value for vias.
 
void SetPosition(const VECTOR2I &aPoint) override
 
void SetWidth(int aWidth) override
 
A progress reporter interface for use in multi-threaded environments.
 
const VECTOR2I & GetArcMid() const
 
void Mirror(const VECTOR2I &aRef, FLIP_DIRECTION aFlipDirection)
 
const VECTOR2I & GetP1() const
 
const VECTOR2I & GetP0() const
 
const VECTOR2I & GetCenter() const
 
bool PointOnEdge(const VECTOR2I &aP, int aAccuracy=0) const
Check if point aP lies on an edge or vertex of the line chain.
 
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
 
int PointCount() const
Return the number of points (vertices) in this line chain.
 
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
 
const VECTOR2I & CLastPoint() const
Return the last point in the line chain.
 
const std::vector< VECTOR2I > & CPoints() const
 
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
 
Represent a set of closed polygons.
 
void Rotate(const EDA_ANGLE &aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Rotate all vertices by a given angle.
 
int VertexCount(int aOutline=-1, int aHole=-1) const
Return the number of vertices in a given outline/hole.
 
void Fracture()
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
 
POLYGON & Polygon(int aIndex)
Return the aIndex-th subpolygon in the set.
 
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
 
int AddHole(const SHAPE_LINE_CHAIN &aHole, int aOutline=-1)
Adds a new hole to the given outline (default: last) and returns its index.
 
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
 
SHAPE_LINE_CHAIN & Hole(int aOutline, int aHole)
Return the reference to aHole-th hole in the aIndex-th outline.
 
int NewOutline()
Creates a new empty polygon in the set and returns its index.
 
void Mirror(const VECTOR2I &aRef, FLIP_DIRECTION aFlipDirection)
Mirror the line points about y or x (or both)
 
int OutlineCount() const
Return the number of outlines in the set.
 
void Move(const VECTOR2I &aVector) override
 
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
 
void TransformToPolygon(SHAPE_POLY_SET &aBuffer, int aError, ERROR_LOC aErrorLoc) const override
Fills a SHAPE_POLY_SET with a polygon representation of this shape.
 
Simple container to manage line stroke parameters.
 
const std::string Format() const
Return the vector formatted as a string.
 
Handle a list of polygons defining a copper zone.
 
void SetDoNotAllowPads(bool aEnable)
 
void SetLocalClearance(std::optional< int > aClearance)
 
virtual void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
 
void SetIsRuleArea(bool aEnable)
 
void SetDoNotAllowTracks(bool aEnable)
 
void SetLayerSet(const LSET &aLayerSet) override
 
void SetDoNotAllowVias(bool aEnable)
 
void SetDoNotAllowFootprints(bool aEnable)
 
void SetDoNotAllowZoneFills(bool aEnable)
 
void SetAssignedPriority(unsigned aPriority)
 
void SetPadConnection(ZONE_CONNECTION aPadConnection)
 
void SetOutline(SHAPE_POLY_SET *aOutline)
 
static bool empty(const wxTextEntryBase *aCtrl)
 
static constexpr EDA_ANGLE ANGLE_0
 
static constexpr EDA_ANGLE ANGLE_90
 
static constexpr EDA_ANGLE FULL_CIRCLE
 
static constexpr EDA_ANGLE ANGLE_360
 
static constexpr EDA_ANGLE ANGLE_180
 
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
 
static const wxChar traceFabmaster[]
Flag to enable FABMASTER plugin debugging output.
 
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
 
bool IsPcbLayer(int aLayer)
Test whether a layer is a valid layer for Pcbnew.
 
constexpr PCB_LAYER_ID PCBNEW_LAYER_ID_START
 
bool IsBackLayer(PCB_LAYER_ID aLayerId)
Layer classification: check if it's a back layer.
 
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
 
PCB_LAYER_ID
A quick note on layer IDs:
 
@ LEFT_RIGHT
Flip left to right (around the Y axis)
 
@ TOP_BOTTOM
Flip top to bottom (around the X axis)
 
bool AddHoleIfValid(SHAPE_POLY_SET &aOutline, SHAPE_LINE_CHAIN &&aHole)
Adds a hole to a polygon if it is valid (i.e.
 
std::vector< VECTOR2I > MakeRegularPolygonPoints(const VECTOR2I &aCenter, size_t aN, const VECTOR2I &aPt0)
Get the corners of a regular polygon from the centre, one point and the number of sides.
 
std::vector< SEG > MakeCrossSegments(const VECTOR2I &aCenter, const VECTOR2I &aSize, EDA_ANGLE aAngle)
Create the two segments for a cross.
 
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
 
@ NPTH
like PAD_PTH, but not plated mechanical use only, no connection allowed
 
@ SMD
Smd pad, appears on the solder paste layer (default)
 
@ PTH
Plated through hole pad.
 
Class to handle a set of BOARD_ITEMs.
 
std::optional< VECTOR2I > OPT_VECTOR2I
 
Utility functions for working with shapes.
 
bool ReplaceIllegalFileNameChars(std::string *aName, int aReplaceChar)
Checks aName for illegal file name characters.
 
static std::vector< std::string > split(const std::string &aStr, const std::string &aDelim)
Split the input string into a vector of output strings.
 
A!LAYER_SORT!LAYER_SUBCLASS!LAYER_ARTWORK!LAYER_USE!LAYER_CONDUCTOR!LAYER_DIELECTRIC_CONSTANT !...
 
bool disable
! if true, prevent the layer elements from being used
 
std::string name
! LAYER_SUBCLASS
 
int layerid
! pcbnew layer (assigned)
 
bool conductive
! LAYER_CONDUCTOR
 
bool positive
! LAYER_ARTWORK (either POSITIVE or NEGATIVE)
 
A!SUBCLASS!PAD_SHAPE_NAME!GRAPHIC_DATA_NAME!GRAPHIC_DATA_NUMBER!RECORD_TAG!GRAPHIC_DATA_1!
 
std::string name
! SYM_NAME
 
std::string refdes
! REFDES
 
std::string subclass
! SUBCLASS
 
std::unique_ptr< graphic_element > elements
 
int end_x
! GRAPHIC_DATA_3
 
SHAPE_ARC result
! KiCad-style arc representation
 
int center_x
! GRAPHIC_DATA_5
 
bool clockwise
! GRAPHIC_DATA_9
 
int center_y
! GRAPHIC_DATA_6
 
int end_y
! GRAPHIC_DATA_4
 
int size_y
! GRAPHIC_DATA_4
 
int size_x
! GRAPHIC_DATA_3
 
std::string graphic_data8
 
std::string graphic_data1
 
std::string graphic_dataname
 
std::string graphic_data6
 
std::string graphic_data7
 
std::string graphic_data2
 
std::string graphic_data3
 
std::string graphic_data10
 
std::string graphic_datanum
 
std::string graphic_data4
 
std::string graphic_data5
 
std::string graphic_data9
 
std::string layer
! SUBCLASS
 
int subseq
! RECORD_TAG[1]
 
int width
! Various sections depending on type
 
GRAPHIC_SHAPE shape
! Shape of the graphic_item
 
int start_y
! GRAPHIC_DATA_2
 
int start_x
! GRAPHIC_DATA_1
 
GRAPHIC_TYPE type
! Type of graphic item
 
int end_x
! GRAPHIC_DATA_3
 
bool oblong_x
! OBLONG_X (as opposed to OBLONG_Y)
 
int size_x
! GRAPHIC_DATA_3
 
int size_y
! GRAPHIC_DATA_4
 
std::vector< VECTOR2I > m_pts
 
bool fill
! GRAPHIC_DATA_5
 
int end_y
! GRAPHIC_DATA_4
 
int end_x
! GRAPHIC_DATA_3
 
double rotation
! GRAPHIC_DATA_3
 
std::string text
! GRAPHIC_DATA_7
 
int height
! GRAPHIC_DATA_6[2]
 
int thickness
! GRAPHIC_DATA_6[6]
 
GR_TEXT_H_ALIGN_T orient
! GRAPHIC_DATA_5
 
bool ital
! GRAPHIC_DATA_6[4] != 0.0
 
bool mirror
! GRAPHIC_DATA_4
 
std::string refdes
!< NET_NAME
 
std::string pin_num
!< REFDES
 
std::string pin_name
!< PIN_NUMBER
 
graphic_element segment
! GRAPHIC_DATA (can be either LINE or ARC)
 
@ USER
The field ID hasn't been set yet; field is invalid.
 
const SHAPE_LINE_CHAIN chain
 
SHAPE_CIRCLE circle(c.m_circle_center, c.m_circle_radius)
 
wxString result
Test unit parsing edge cases and error handling.
 
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
 
VECTOR2< int32_t > VECTOR2I
 
VECTOR2< double > VECTOR2D
 
@ FULL
pads are covered by copper