57#include <wx/filename.h>
64 const unsigned PROGRESS_DELTA = 250;
85 wxCHECK_MSG( !aStr.empty(), 0.0,
"Empty string passed to readDouble" );
87 std::istringstream istr( aStr );
88 istr.imbue( std::locale::classic() );
99 wxCHECK_MSG( !aStr.empty(), 0,
"Empty string passed to readInt" );
101 std::istringstream istr( aStr );
102 istr.imbue( std::locale::classic() );
112 std::ifstream ifs( aFile, std::ios::in | std::ios::binary );
120 ifs.ignore( std::numeric_limits<std::streamsize>::max() );
121 std::streamsize length = ifs.gcount();
123 ifs.seekg( 0, std::ios_base::beg );
125 std::string buffer( std::istreambuf_iterator<char>{ ifs }, {} );
127 std::vector < std::string > row;
131 row.reserve( length / 100 );
137 for(
auto& ch : buffer )
143 if( cell.empty() || cell[0] ==
'"' )
152 row.push_back( cell );
164 row.push_back( cell );
167 rows.push_back( row );
176 cell += std::toupper( ch );
181 if( !cell.empty() || !row.empty() )
183 row.push_back( cell );
185 rows.push_back( row );
199 row =
rows.at( aOffset );
201 catch( std::out_of_range& )
209 if( row[0].back() !=
'A' )
212 std::string row1 = row[1];
213 std::string row2 = row[2];
218 std::erase_if( row1, [](
char c ){
return c ==
'_'; } );
219 std::erase_if( row2, [](
char c ){
return c ==
'_'; } );
224 std::erase_if( row3, [](
char c ){
return c ==
'_'; } );
227 if( row1 ==
"REFDES" && row2 ==
"COMPCLASS" )
230 if( row1 ==
"NETNAME" && row2 ==
"REFDES" )
233 if( row1 ==
"CLASS" && row2 ==
"SUBCLASS" && row3.empty() )
236 if( row1 ==
"GRAPHICDATANAME" && row2 ==
"GRAPHICDATANUMBER" )
239 if( row1 ==
"CLASS" && row2 ==
"SUBCLASS" && row3 ==
"GRAPHICDATANAME" )
242 if( row1 ==
"SYMNAME" && row2 ==
"PINNAME" )
245 if( row1 ==
"SYMNAME" && row2 ==
"SYMMIRROR" && row3 ==
"PINNAME" )
248 if( row1 ==
"VIAX" && row2 ==
"VIAY" )
251 if( row1 ==
"SUBCLASS" && row2 ==
"PADSHAPENAME" )
254 if( row1 ==
"PADNAME" )
257 if( row1 ==
"LAYERSORT" )
260 reportError(
_(
"Unknown FABMASTER section %s:%s at row %zu." ),
273 if( aRow >=
rows.size() )
276 if(
rows[aRow].size() < 11 )
278 reportError(
_(
"Invalid row size in J row %zu. Expecting 11 elements but found %zu." ),
284 for(
int i = 7; i < 10 && retval < 1.0; ++i )
286 std::string units =
rows[aRow][i];
287 std::transform(units.begin(), units.end(),units.begin(), ::toupper);
289 if( units ==
"MILS" )
291 else if( units ==
"MILLIMETERS" )
293 else if( units ==
"MICRONS" )
295 else if( units ==
"INCHES" )
301 reportError(
_(
"Could not find units value, defaulting to mils." ) );
311 if( aRow >=
rows.size() )
314 std::vector<std::string> header =
rows[aRow];
316 for(
size_t i = 0; i < header.size(); i++ )
320 std::erase_if( header[i], [](
const char c ) {
return c ==
'_'; } );
322 if( header[i] == aStr )
333 const auto& kicad_layer =
layers.find( aLayerName);
335 if( kicad_layer ==
layers.end() )
338 return static_cast<PCB_LAYER_ID>( kicad_layer->second.layerid );
344 size_t rownum = aRow + 2;
346 if( rownum >=
rows.size() )
354 for( ; rownum <
rows.size() &&
rows[rownum].size() > 0 &&
rows[rownum][0] ==
"S"; ++rownum )
358 if( row.size() != header.size() )
360 reportError(
_(
"Invalid row size in row %zu. Expecting %zu elements but found %zu." ),
367 auto& pad_num = row[pad_num_col];
368 auto& pad_layer = row[pad_lay_col];
371 if( pad_layer ==
"INTERNAL_PAD_DEF" || pad_layer ==
"internal_pad_def" )
375 if( pad_layer[0] ==
'~' )
384 layer.
name = pad_layer;
402 size_t rownum = aRow + 2;
404 if( rownum >=
rows.size() )
410 if( scale_factor <= 0.0 )
424 for( ; rownum <
rows.size() &&
rows[rownum].size() > 0 &&
rows[rownum][0] ==
"S"; ++rownum )
429 if( row.size() != header.size() )
431 reportError(
_(
"Invalid row size in row %zu. Expecting %zu elements but found %zu." ),
438 auto& pad_name = row[pad_name_col];
439 auto& pad_num = row[pad_num_col];
440 auto& pad_layer = row[pad_lay_col];
441 auto& pad_is_via = row[pad_via_col];
442 auto& pad_shape = row[pad_shape_col];
443 auto& pad_width = row[pad_width_col];
444 auto& pad_height = row[pad_height_col];
445 auto& pad_xoff = row[pad_xoff_col];
446 auto& pad_yoff = row[pad_yoff_col];
447 auto& pad_shapename = row[pad_shape_name_col];
450 if( pad_layer ==
"INTERNAL_PAD_DEF" || pad_layer ==
"internal_pad_def" )
455 auto new_pad =
pads.find( pad_name );
457 if( new_pad !=
pads.end() )
458 pad = &new_pad->second;
463 pad->name = pad_name;
467 if( pad_layer ==
"~DRILL" )
481 reportError(
_(
"Expecting drill size value but found %s!%s!%s in row %zu." ),
499 if( drill_x == drill_y )
501 pad->drill_size_x = drill_hit;
502 pad->drill_size_y = drill_hit;
506 pad->drill_size_x = drill_x;
507 pad->drill_size_y = drill_y;
510 if( !pad_shapename.empty() && pad_shapename[0] ==
'P' )
516 if( pad_shape.empty() )
529 reportError(
_(
"Expecting pad size values but found %s : %s in row %zu." ),
536 auto layer =
layers.find( pad_layer );
538 if( w > 0.0 && layer !=
layers.end() && layer->second.conductive )
539 pad->copper_layers.insert( pad_layer );
544 if( layer !=
layers.end() )
546 if( layer->second.layerid ==
F_Cu )
548 else if( layer->second.layerid ==
B_Cu )
552 if( w > std::numeric_limits<int>::max() || h > std::numeric_limits<int>::max() )
554 reportError(
_(
"Invalid pad size in row %zu." ), rownum );
558 if( pad_layer ==
"~TSM" || pad_layer ==
"~BSM" )
560 if( w > 0.0 && h > 0.0 )
568 if( pad_layer ==
"~TSP" || pad_layer ==
"~BSP" )
570 if( w > 0.0 && h > 0.0 )
579 if( pad_layer[0] ==
'~' )
582 int layer_x_offset = 0;
583 int layer_y_offset = 0;
592 reportError(
_(
"Expecting pad offset values but found %s:%s in row %zu." ),
601 pad->x_offset = layer_x_offset;
602 pad->y_offset = layer_y_offset;
605 if( w > 0.0 && h > 0.0 )
610 layer_data.
x_offset = layer_x_offset;
611 layer_data.
y_offset = layer_y_offset;
613 if( pad_shape ==
"CIRCLE" )
618 else if( pad_shape ==
"RECTANGLE" )
622 else if( pad_shape ==
"ROUNDED_RECT" )
626 else if( pad_shape ==
"SQUARE" )
631 else if( pad_shape ==
"OBLONG" || pad_shape ==
"OBLONG_X"
632 || pad_shape ==
"OBLONG_Y" )
636 else if( pad_shape ==
"OCTAGON" )
641 else if( pad_shape ==
"SHAPE" )
648 reportError(
_(
"Unknown pad shape name '%s' on layer '%s' in row %zu." ),
655 pad->layer_shapes[pad_layer] = layer_data;
663 pad->via = pad_is_via.empty()
664 || std::toupper(
static_cast<unsigned char>( pad_is_via[0] ) ) !=
'V';
667 pad->custom_name = pad_shapename;
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 reportError(
_(
"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;
732 std::vector<std::pair<std::string, int>> extra_layers
734 {
"ASSEMBLY_TOP",
F_Fab },
735 {
"ASSEMBLY_BOTTOM",
B_Fab },
736 {
"PLACE_BOUND_TOP",
F_CrtYd },
737 {
"PLACE_BOUND_BOTTOM",
B_CrtYd },
740 std::vector<FABMASTER_LAYER*> layer_order;
742 int next_user_layer =
User_1;
751 layer_order.push_back( &layer );
753 else if( ( layer.
name.find(
"SILK" ) != std::string::npos
754 && layer.
name.find(
"AUTOSILK" )
755 == std::string::npos )
756 || layer.
name.find(
"DISPLAY" ) != std::string::npos )
758 if( layer.
name.find(
"B" ) != std::string::npos )
763 else if( layer.
name.find(
"MASK" ) != std::string::npos ||
764 layer.
name.find(
"MSK" ) != std::string::npos )
766 if( layer.
name.find(
"B" ) != std::string::npos )
771 else if( layer.
name.find(
"PAST" ) != std::string::npos )
773 if( layer.
name.find(
"B" ) != std::string::npos )
778 else if( layer.
name.find(
"NCLEGEND" ) != std::string::npos )
787 if( layer.
name.find(
"AUTOSILK" ) == std::string::npos )
789 if( next_user_layer <=
User_9 )
792 layer.
layerid = next_user_layer;
793 next_user_layer += 2;
809 for(
size_t layeri = 0; layeri < layer_order.size(); ++layeri )
814 else if( layeri == layer_order.size() - 1 )
817 layer->
layerid = layeri * 2 + 2;
820 for(
auto& new_pair : extra_layers )
824 new_layer.
name = new_pair.first;
825 new_layer.
layerid = new_pair.second;
828 auto result =
layers.emplace( new_pair.first, new_layer );
832 result.first->second.layerid = new_pair.second;
833 result.first->second.disable =
false;
837 for(
const auto& [layer_name, fabmaster_layer] :
layers )
839 wxLogTrace(
traceFabmaster, wxT(
"Layer %s -> KiCad layer %d" ), layer_name,
840 fabmaster_layer.layerid );
854 size_t rownum = aRow + 2;
856 if( rownum >=
rows.size() )
859 auto& header =
rows[aRow];
862 if( scale_factor <= 0.0 )
870 int layer_er_col =
getColFromName( aRow,
"LAYERDIELECTRICCONSTANT" );
871 int layer_rho_col =
getColFromName( aRow,
"LAYERELECTRICALCONDUCTIVITY" );
874 if( layer_sort_col < 0 || layer_subclass_col < 0 || layer_art_col < 0 || layer_use_col < 0
875 || layer_cond_col < 0 || layer_er_col < 0 || layer_rho_col < 0 || layer_mat_col < 0 )
878 for( ; rownum <
rows.size() &&
rows[rownum].size() > 0 &&
rows[rownum][0] ==
"S"; ++rownum )
882 if( row.size() != header.size() )
884 reportError(
_(
"Invalid row size in row %zu. Expecting %zu elements but found %zu." ),
891 auto& layer_sort = row[layer_sort_col];
892 auto& layer_subclass = row[layer_subclass_col];
893 auto& layer_art = row[layer_art_col];
894 auto& layer_cond = row[layer_cond_col];
895 auto& layer_mat = row[layer_mat_col];
897 if( layer_mat ==
"AIR" )
902 if( layer_subclass.empty() )
904 if( layer_cond !=
"NO" )
905 layer.
name =
"In.Cu" + layer_sort;
907 layer.
name =
"Dielectric" + layer_sort;
910 layer.
positive = ( layer_art !=
"NEGATIVE" );
915 return rownum - aRow;
926 size_t rownum = aRow + 2;
928 if( rownum >=
rows.size() )
931 auto& header =
rows[aRow];
934 if( scale_factor <= 0.0 )
939 int pad_grdata_name_col =
getColFromName( aRow,
"GRAPHICDATANAME" );
940 int pad_grdata_num_col =
getColFromName( aRow,
"GRAPHICDATANUMBER" );
955 if( pad_subclass_col < 0 || pad_shape_name_col < 0 || pad_grdata1_col < 0 || pad_grdata2_col < 0
956 || pad_grdata3_col < 0 || pad_grdata4_col < 0 || pad_grdata5_col < 0
957 || pad_grdata6_col < 0 || pad_grdata7_col < 0 || pad_grdata8_col < 0
958 || pad_grdata9_col < 0 || pad_stack_name_col < 0 || pad_refdes_col < 0
959 || pad_pin_num_col < 0 )
962 for( ; rownum <
rows.size() &&
rows[rownum].size() > 0 &&
rows[rownum][0] ==
"S"; ++rownum )
966 if( row.size() != header.size() )
968 reportError(
_(
"Invalid row size in row %zu. Expecting %zu elements but found %zu." ),
976 auto& pad_layer = row[pad_subclass_col];
977 auto pad_shape_name = row[pad_shape_name_col];
978 auto& pad_record_tag = row[pad_record_tag_col];
993 auto& pad_stack_name = row[pad_stack_name_col];
994 auto& pad_refdes = row[pad_refdes_col];
995 auto& pad_pin_num = row[pad_pin_num_col];
999 std::string prefix(
"FIG_SHAPE " );
1001 if( pad_shape_name.length() <= prefix.length()
1002 || !std::equal( prefix.begin(), prefix.end(), pad_shape_name.begin() ) )
1012 if( std::sscanf( pad_record_tag.c_str(),
"%d %d", &
id, &seq ) != 2 )
1014 reportError(
_(
"Invalid format for id string '%s' in custom pad row %zu." ),
1015 pad_record_tag.c_str(),
1020 auto name = pad_shape_name.substr( prefix.length() );
1021 name +=
"_" + pad_refdes +
"_" + pad_pin_num;
1024 auto& custom_pad = ret.first->second;
1030 custom_pad.name =
name;
1031 custom_pad.padstack = pad_stack_name;
1032 custom_pad.pinnum = pad_pin_num;
1033 custom_pad.refdes = pad_refdes;
1040 auto gr_item = std::unique_ptr<GRAPHIC_ITEM>(
processGraphic( gr_data, scale_factor ) );
1044 gr_item->layer = pad_layer;
1045 gr_item->refdes = pad_refdes;
1047 gr_item->subseq = 0;
1052 auto retval = pad_it.first->second.insert( std::move(gr_item ) );
1054 if( !retval.second )
1056 reportError(
_(
"Could not insert graphical item %d into padstack '%s'." ),
1058 pad_stack_name.c_str() );
1063 reportError(
_(
"Unrecognized pad shape primitive '%s' in row %zu." ),
1069 return rownum - aRow;
1119 angle = endangle - startangle;
1154 std::unique_ptr<GRAPHIC_ARC> new_circle = std::make_unique<GRAPHIC_ARC>();
1165 if( size.
x != size.
y )
1167 reportError(
_(
"Circle with unequal x and y radii (x=%d, y=%d)" ), size.
x, size.
y );
1173 new_circle->radius = size.
x / 2;
1179 new_circle->start_x = start.
x;
1180 new_circle->start_y = start.
y;
1182 new_circle->end_x = start.
x;
1183 new_circle->end_y = start.
y;
1185 new_circle->center_x =
center.x;
1186 new_circle->center_y =
center.y;
1188 new_circle->clockwise =
true;
1190 new_circle->result =
SHAPE_ARC{ start, mid, start, 0 };
1192 return new_circle.release();
1212 new_rect->
width = 0;
1226 auto new_rect = std::make_unique<GRAPHIC_RECTANGLE>();
1235 new_rect->start_x = center_x - size_x / 2;
1236 new_rect->start_y = center_y + size_y / 2;
1237 new_rect->end_x = center_x + size_x / 2;
1238 new_rect->end_y = center_y - size_y / 2;
1240 new_rect->width = 0;
1242 return new_rect.release();
1267 auto new_oblong = std::make_unique<GRAPHIC_OBLONG>();
1279 return new_oblong.release();
1309 auto new_poly = std::make_unique<GRAPHIC_POLYGON>();
1314 bool across_corners =
true;
1348 across_corners =
false;
1354 wxCHECK_MSG(
false,
nullptr,
1355 wxString::Format(
"Unhandled polygon type: %s", aData.
graphic_dataname ) );
1360 return new_poly.release();
1371 auto new_cross = std::make_unique<GRAPHIC_CROSS>();
1380 return new_cross.release();
1404 if( toks.size() < 8 )
1407 reportError(
_(
"Invalid token count. Expected 8 but found %zu." ), toks.size() );
1409 new_text->
width = 0;
1410 new_text->
ital =
false;
1484 size_t rownum = aRow + 2;
1486 if( rownum >=
rows.size() )
1492 if( scale_factor <= 0.0 )
1511 if( geo_name_col < 0 || geo_num_col < 0 || geo_grdata1_col < 0 || geo_grdata2_col < 0
1512 || geo_grdata3_col < 0 || geo_grdata4_col < 0 || geo_grdata5_col < 0
1513 || geo_grdata6_col < 0 || geo_grdata7_col < 0 || geo_grdata8_col < 0
1514 || geo_grdata9_col < 0 || geo_subclass_col < 0 || geo_sym_name_col < 0
1515 || geo_refdes_col < 0 )
1518 for( ; rownum <
rows.size() &&
rows[rownum].size() > 0 &&
rows[rownum][0] ==
"S"; ++rownum )
1522 if( row.size() != header.size() )
1524 reportError(
_(
"Invalid row size in row %zu. Expecting %zu elements but found %zu." ),
1531 auto& geo_tag = row[geo_tag_col];
1546 auto& geo_refdes = row[geo_refdes_col];
1554 if( std::sscanf( geo_tag.c_str(),
"%d %d %d", &
id, &seq, &subseq ) < 2 )
1556 reportError(
_(
"Invalid format for record_tag string '%s' in row %zu." ),
1562 auto gr_item = std::unique_ptr<GRAPHIC_ITEM>(
processGraphic( gr_data, scale_factor ) );
1567 gr_item->layer = row[geo_subclass_col];
1569 gr_item->subseq = subseq;
1571 if( geo_refdes.empty() )
1576 new_gr.
subclass = row[geo_subclass_col];
1577 new_gr.
refdes = row[geo_refdes_col];
1578 new_gr.
name = row[geo_sym_name_col];
1580 new_gr.
elements = std::make_unique<graphic_element>();
1585 graphic.
elements->emplace( std::move( gr_item ) );
1590 std::map<int, GEOM_GRAPHIC>{} );
1591 auto map_it = sym_gr_it.first->second.emplace(
id,
GEOM_GRAPHIC{} );
1592 auto& gr = map_it.first;
1596 gr->second.subclass = row[geo_subclass_col];
1597 gr->second.refdes = row[geo_refdes_col];
1598 gr->second.name = row[geo_sym_name_col];
1600 gr->second.elements = std::make_unique<graphic_element>();
1603 gr->second.elements->emplace( std::move( gr_item ) );
1607 return rownum - aRow;
1616 size_t rownum = aRow + 2;
1618 if( rownum >=
rows.size() )
1624 if( scale_factor <= 0.0 )
1633 if( viax_col < 0 || viay_col < 0 || padstack_name_col < 0 || net_name_col < 0
1634 || test_point_col < 0 )
1637 for( ; rownum <
rows.size() &&
rows[rownum].size() > 0 &&
rows[rownum][0] ==
"S"; ++rownum )
1641 if( row.size() != header.size() )
1643 reportError(
_(
"Invalid row size in row %zu. Expecting %zu elements but found %zu." ),
1650 vias.emplace_back( std::make_unique<FM_VIA>() );
1655 via->padstack = row[padstack_name_col];
1656 via->net = row[net_name_col];
1657 via->test_point = ( row[test_point_col] ==
"YES" );
1660 return rownum - aRow;
1671 size_t rownum = aRow + 2;
1673 if( rownum >=
rows.size() )
1679 if( scale_factor <= 0.0 )
1685 int grdata_num_col =
getColFromName( aRow,
"GRAPHICDATANUMBER" );
1698 if( class_col < 0 || layer_col < 0 || grdata_name_col < 0 || grdata_num_col < 0
1699 || tag_col < 0 || grdata1_col < 0 || grdata2_col < 0 || grdata3_col < 0
1700 || grdata4_col < 0 || grdata5_col < 0 || grdata6_col < 0 || grdata7_col < 0
1701 || grdata8_col < 0 || grdata9_col < 0 || netname_col < 0 )
1704 for( ; rownum <
rows.size() &&
rows[rownum].size() > 0 &&
rows[rownum][0] ==
"S"; ++rownum )
1708 if( row.size() != header.size() )
1710 reportError(
_(
"Invalid row size in row %zu. Expecting %zu elements but found %zu." ),
1730 const std::string& geo_tag = row[tag_col];
1737 if( std::sscanf( geo_tag.c_str(),
"%d %d %d", &
id, &seq, &subseq ) < 2 )
1739 reportError(
_(
"Invalid format for record_tag string '%s' in row %zu." ),
1745 auto gr_item = std::unique_ptr<GRAPHIC_ITEM>(
processGraphic( gr_data, scale_factor ) );
1749 wxLogTrace(
traceFabmaster, wxT(
"Unhandled graphic item '%s' in row %zu." ),
1755 auto new_trace = std::make_unique<TRACE>();
1757 new_trace->layer = row[layer_col];
1758 new_trace->netname = row[netname_col];
1759 new_trace->lclass = row[class_col];
1761 gr_item->layer = row[layer_col];
1763 gr_item->subseq = subseq;
1766 if( new_trace->lclass ==
"REF DES" )
1768 auto result =
refdes.emplace( std::move( new_trace ) );
1769 auto& ref = *
result.first;
1770 ref->segment.emplace( std::move( gr_item ) );
1772 else if( new_trace->lclass ==
"DEVICE TYPE" || new_trace->lclass ==
"COMPONENT VALUE"
1773 || new_trace->lclass ==
"TOLERANCE" )
1786 else if( gr_item->width == 0 )
1788 auto result =
zones.emplace( std::move( new_trace ) );
1789 auto& zone = *
result.first;
1790 auto gr_result = zone->segment.emplace( std::move( gr_item ) );
1792 if( !gr_result.second )
1794 reportError(
_(
"Duplicate item for ID %d and sequence %d in row %zu." ),
1802 auto result =
traces.emplace( std::move( new_trace ) );
1803 auto& trace = *
result.first;
1804 auto gr_result = trace->segment.emplace( std::move( gr_item ) );
1806 if( !gr_result.second )
1808 reportError(
_(
"Duplicate item for ID %d and sequence %d in row %zu." ),
1816 return rownum - aRow;
1822 if( aSymType ==
"PACKAGE" )
1824 else if( aSymType ==
"DRAFTING")
1826 else if( aSymType ==
"MECHANICAL" )
1828 else if( aSymType ==
"FORMAT" )
1837 if( aCmpClass ==
"IO" )
1839 else if( aCmpClass ==
"IC" )
1841 else if( aCmpClass ==
"DISCRETE" )
1854 size_t rownum = aRow + 2;
1856 if( rownum >=
rows.size() )
1862 if( scale_factor <= 0.0 )
1870 int compinscode_col =
getColFromName( aRow,
"COMPINSERTIONCODE" );
1881 if( refdes_col < 0 || compclass_col < 0 || comppartnum_col < 0 || compheight_col < 0
1882 || compdevlabelcol < 0 || compinscode_col < 0 || symtype_col < 0 || symname_col < 0
1883 || symmirror_col < 0 || symrotate_col < 0 || symx_col < 0 || symy_col < 0
1884 || compvalue_col < 0 || comptol_col < 0 || compvolt_col < 0 )
1887 for( ; rownum <
rows.size() &&
rows[rownum].size() > 0 &&
rows[rownum][0] ==
"S"; ++rownum )
1891 if( row.size() != header.size() )
1893 reportError(
_(
"Invalid row size in row %zu. Expecting %zu elements but found %zu." ),
1900 const wxString& comp_refdes = row[refdes_col];
1902 if( row[symx_col].
empty() || row[symy_col].
empty() || row[symrotate_col].
empty() )
1904 reportError(
_(
"Missing X, Y, or rotation data in row %zu for refdes %s. "
1905 "This may be an unplaced component." ),
1906 rownum, comp_refdes );
1910 auto cmp = std::make_unique<COMPONENT>();
1912 cmp->refdes = comp_refdes;
1914 cmp->pn = row[comppartnum_col];
1915 cmp->height = row[compheight_col];
1916 cmp->dev_label = row[compdevlabelcol];
1917 cmp->insert_code = row[compinscode_col];
1919 cmp->name = row[symname_col];
1920 cmp->mirror = ( row[symmirror_col] ==
"YES" );
1921 cmp->rotate =
readDouble( row[symrotate_col] );
1924 cmp->value = row[compvalue_col];
1925 cmp->tol = row[comptol_col];
1926 cmp->voltage = row[compvolt_col];
1932 auto retval =
components.insert( std::make_pair( cmp->refdes, std::vector<std::unique_ptr<COMPONENT>>{} ) );
1937 vec->second.push_back( std::move( cmp ) );
1940 return rownum - aRow;
1950 size_t rownum = aRow + 2;
1952 if( rownum >=
rows.size() )
1958 if( scale_factor <= 0.0 )
1972 if( symname_col < 0 ||symmirror_col < 0 || pinname_col < 0 || pinnum_col < 0 || pinx_col < 0
1973 || piny_col < 0 || padstack_col < 0 || refdes_col < 0 || pinrot_col < 0
1974 || testpoint_col < 0 )
1977 for( ; rownum <
rows.size() &&
rows[rownum].size() > 0 &&
rows[rownum][0] ==
"S"; ++rownum )
1981 if( row.size() != header.size() )
1983 reportError(
_(
"Invalid row size in row %zu. Expecting %zu elements but found %zu." ),
1990 auto pin = std::make_unique<PIN>();
1992 pin->name = row[symname_col];
1993 pin->mirror = ( row[symmirror_col] ==
"YES" );
1994 pin->pin_name = row[pinname_col];
1995 pin->pin_number = row[pinnum_col];
1998 pin->padstack = row[padstack_col];
1999 pin->refdes = row[refdes_col];
2005 std::string pin_key =
pin->refdes.empty() ?
pin->name :
pin->refdes;
2007 auto map_it =
pins.find( pin_key );
2009 if( map_it ==
pins.end() )
2011 auto retval =
pins.insert( std::make_pair( pin_key, std::set<std::unique_ptr<PIN>,
2013 map_it = retval.first;
2016 map_it->second.insert( std::move(
pin ) );
2019 return rownum - aRow;
2028 size_t rownum = aRow + 2;
2030 if( rownum >=
rows.size() )
2036 if( scale_factor <= 0.0 )
2046 if( netname_col < 0 || refdes_col < 0 || pinnum_col < 0 || pinname_col < 0 || pingnd_col < 0
2050 for( ; rownum <
rows.size() &&
rows[rownum].size() > 0 &&
rows[rownum][0] ==
"S"; ++rownum )
2054 if( row.size() != header.size() )
2056 reportError(
_(
"Invalid row size in row %zu. Expecting %zu elements but found %zu." ),
2064 new_net.
name = row[netname_col];
2065 new_net.
refdes = row[refdes_col];
2066 new_net.
pin_num = row[pinnum_col];
2067 new_net.
pin_name = row[pinname_col];
2068 new_net.
pin_gnd = ( row[pingnd_col] ==
"YES" );
2069 new_net.
pin_pwr = ( row[pinpwr_col] ==
"YES" );
2072 netnames.insert( row[netname_col] );
2075 return rownum - aRow;
2082 for(
size_t i = 0; i <
rows.size(); )
2096 i += std::max( retval, 1 );
2104 i += std::max( retval, 1 );
2112 i += std::max( retval, 1 );
2120 i += std::max( retval, 1 );
2128 i += std::max( retval, 1 );
2136 i += std::max( retval, 1 );
2144 i += std::max( retval, 1 );
2152 i += std::max( retval, 1 );
2160 i += std::max( retval, 1 );
2168 i += std::max( retval, 1 );
2189 return aClass ==
"ROUTE KEEPOUT" || aClass ==
"VIA KEEPOUT" || aClass ==
"PACKAGE KEEPOUT"
2190 || aClass ==
"ROUTE KEEPIN" || aClass ==
"PACKAGE KEEPIN"
2191 || aClass ==
"CONSTRAINT REGION";
2197 for(
auto& zone :
zones )
2202 || zone->layer ==
"ALL" )
2208 if( zone->layer ==
"OUTLINE" || zone->layer ==
"DESIGN_OUTLINE" )
2229 std::set<ZONE*> zones_to_delete;
2230 std::set<ZONE*> matched_fills;
2232 for(
auto zone : aBoard->
Zones() )
2234 if( zone->GetNetCode() > 0 )
2235 zones_to_delete.insert( zone );
2238 for(
auto zone1 : aBoard->
Zones() )
2240 if( zone1->GetNetCode() > 0 )
2244 if( zone1->GetIsRuleArea() )
2249 std::map<int, std::vector<ZONE*>> net_to_fills;
2251 for(
auto zone2 : aBoard->
Zones() )
2253 if( zone2->GetNetCode() <= 0 )
2258 if( zone1->GetLayer() != zone2->GetLayer() )
2264 size_t match_count = 0;
2266 for(
auto& pt1 : outline1.
CPoints() )
2272 for(
auto& pt2 : outline2.
CPoints() )
2278 if( match_count > 0 )
2280 overlaps[zone2->GetNetCode()] += match_count;
2281 net_to_fills[zone2->GetNetCode()].push_back( zone2 );
2286 size_t max_net_id = 0;
2288 for(
size_t el = 1; el < overlaps.size(); ++el )
2290 if( overlaps[el] > max_net )
2292 max_net = overlaps[el];
2299 zone1->SetNetCode( max_net_id );
2301 for(
ZONE* fill : net_to_fills[max_net_id] )
2302 matched_fills.insert( fill );
2306 for(
auto zone : zones_to_delete )
2308 if( matched_fills.find( zone ) != matched_fills.end() )
2329 if( aMirrorPoint.has_value() )
2362 for(
const auto& [pinKey, pinSet] :
pins )
2364 if( pinSet.empty() )
2370 const auto& firstPin = *pinSet.begin();
2372 int minX = firstPin->pin_x;
2373 int maxX = firstPin->pin_x;
2374 int minY = firstPin->pin_y;
2375 int maxY = firstPin->pin_y;
2377 for(
const auto&
pin : pinSet )
2379 minX = std::min( minX,
pin->pin_x );
2380 maxX = std::max( maxX,
pin->pin_x );
2381 minY = std::min( minY,
pin->pin_y );
2382 maxY = std::max( maxY,
pin->pin_y );
2385 auto cmp = std::make_unique<COMPONENT>();
2386 cmp->refdes = pinKey;
2387 cmp->name = firstPin->name;
2388 cmp->mirror = firstPin->mirror;
2390 cmp->x = ( minX + maxX ) / 2;
2391 cmp->y = ( minY + maxY ) / 2;
2395 std::vector<std::unique_ptr<COMPONENT>> compVec;
2396 compVec.push_back( std::move( cmp ) );
2397 components.insert( std::make_pair( pinKey, std::move( compVec ) ) );
2411 bool has_multiple = mod.second.size() > 1;
2413 for(
int i = 0; i < (int) mod.second.size(); ++i )
2415 auto& src = mod.second[i];
2419 wxString mod_ref = src->name;
2423 mod_ref.Append( wxString::Format( wxT(
"_%d" ), i ) );
2428 wxString key = !lib_ref.empty() ? lib_ref + wxT(
":" ) + mod_ref : mod_ref;
2431 fpID.
Parse( key,
true );
2440 wxString reference = src->refdes;
2442 if( !std::isalpha( src->refdes[0] ) )
2443 reference.Prepend(
"UNK" );
2456 for(
auto& ref :
refdes )
2459 static_cast<const GRAPHIC_TEXT&
>( **ref->segment.begin() );
2461 if( lsrc.
text == src->refdes )
2468 wxLogTrace(
traceFabmaster, wxS(
"The layer %s is not mapped?" ),
2469 ref->layer.c_str() );
2480 flip_point =
VECTOR2I( src->x, src->y );
2485 setupText( lsrc, layer, *txt, *aBoard, flip_point );
2500 for(
auto& gr_ref : gr_it->second )
2502 auto& graphic = gr_ref.second;
2504 for(
auto& seg : *graphic.elements )
2511 STROKE_PARAMS defaultStroke( ds.GetLineThickness( layer ) );
2513 switch( seg->shape )
2536 if( lsrc->
width == 0 )
2549 circle->SetLayer( layer );
2561 if( lsrc.
width == 0 )
2567 if( lsrc.
layer ==
"DISPLAY_TOP" || lsrc.
layer ==
"DISPLAY_BOTTOM" )
2568 circle->SetFilled(
true );
2570 circle->SetWidth( ds.GetLineThickness(
circle->GetLayer() ) );
2584 std::unique_ptr<PCB_SHAPE> arc =
2598 arc->SetLayer( layer );
2602 if( lsrc->
width == 0 )
2603 arc->SetStroke( defaultStroke );
2642 std::unique_ptr<PCB_TEXT> txt = std::make_unique<PCB_TEXT>( fp );
2647 flip_point =
VECTOR2I( src->x, src->y );
2649 setupText( lsrc, layer, *txt, *aBoard, flip_point );
2674 auto pin_it =
pins.find( src->refdes );
2677 if( pin_it ==
pins.end() )
2678 pin_it =
pins.find( src->name );
2680 if( pin_it !=
pins.end() )
2682 for(
auto&
pin : pin_it->second )
2684 auto pin_net_it =
pin_nets.find( std::make_pair(
pin->refdes,
2685 pin->pin_number ) );
2686 auto padstack =
pads.find(
pin->padstack );
2687 std::string netname =
"";
2690 netname = pin_net_it->second.name;
2692 auto net_it = netinfo.find( netname );
2694 std::unique_ptr<PAD> newpad = std::make_unique<PAD>( fp );
2696 if( net_it != netinfo.end() )
2697 newpad->SetNet( net_it->second );
2699 newpad->SetNetCode( 0 );
2701 newpad->SetX(
pin->pin_x );
2704 newpad->SetY( 2 * src->y -
pin->pin_y );
2706 newpad->SetY(
pin->pin_y );
2708 newpad->SetNumber(
pin->pin_number );
2710 if( padstack ==
pads.end() )
2712 reportError(
_(
"Unable to locate padstack %s in file %s\n" ),
2718 auto&
pad = padstack->second;
2726 for(
const auto& [layer_name, layer_data] :
pad.layer_shapes )
2728 auto layer_it =
layers.find( layer_name );
2730 if( layer_it ==
layers.end() || !layer_it->second.conductive )
2736 if( kicad_layer ==
F_Cu )
2737 front_layer = &layer_data;
2738 else if( kicad_layer ==
B_Cu )
2739 back_layer = &layer_data;
2741 inner_layer = &layer_data;
2746 return aA.
shape != aB.shape
2747 || aA.
width != aB.width
2748 || aA.
height != aB.height
2755 std::vector<const FM_PAD_LAYER*> copper_defs;
2757 for(
const FM_PAD_LAYER* def : { front_layer, inner_layer, back_layer } )
2760 copper_defs.push_back( def );
2763 bool needs_padstack =
false;
2765 for(
size_t ii = 1; ii < copper_defs.size(); ++ii )
2767 if( layersDiffer( *copper_defs[0], *copper_defs[ii] ) )
2769 needs_padstack =
true;
2774 if( needs_padstack )
2780 newpad->SetShape( aLayer, aLayerData.shape );
2784 newpad->SetSize( aLayer,
2785 VECTOR2I( aLayerData.width, aLayerData.width ) );
2789 newpad->SetSize( aLayer,
2790 VECTOR2I( aLayerData.width, aLayerData.height ) );
2793 newpad->SetOffset( aLayer,
2794 VECTOR2I( aLayerData.x_offset, aLayerData.y_offset ) );
2797 if( needs_padstack )
2800 applyLayerShape(
F_Cu, *front_layer );
2803 applyLayerShape(
B_Cu, *back_layer );
2807 else if( front_layer )
2813 "geometry; custom primitives not supported "
2814 "in padstack mode." ),
2824 int pad_size = std::min(
pad.width,
pad.height );
2827 VECTOR2I( pad_size / 2, pad_size / 2 ) );
2829 std::string custom_name =
pad.custom_name +
"_" +
pin->refdes +
"_" +
2831 auto custom_it =
pad_shapes.find( custom_name );
2837 int last_subseq = 0;
2844 for(
const auto& el : (*custom_it).second.elements )
2850 if(
getLayer( ( *( el.second.begin() ) )->layer ) != primary_layer )
2853 for(
const auto& seg : el.second )
2855 if( seg->subseq > 0 || seg->subseq != last_subseq )
2857 poly_outline.
Polygon(0).back().SetClosed(
true );
2865 if( poly_outline.
VertexCount( 0, hole_idx ) == 0 )
2885 reportError(
_(
"Invalid custom pad '%s'. Replacing with "
2887 custom_name.c_str() );
2894 poly_outline.
Move( -newpad->GetPosition() );
2917 reportError(
_(
"Invalid custom pad '%s'. Replacing with "
2919 custom_name.c_str() );
2926 custom_name.c_str() );
2936 if( !needs_padstack && (
pad.x_offset ||
pad.y_offset ) )
2955 if(
pad.drill_size_x ==
pad.drill_size_y )
2960 newpad->SetDrillSize(
VECTOR2I(
pad.drill_size_x,
pad.drill_size_y ) );
2968 else if(
pad.bottom )
2969 newpad->SetLayerSet(
PAD::SMDMask().FlipStandardLayers() );
2974 newpad->SetOrientation(
EDA_ANGLE( -src->rotate +
pin->rotation,
2977 newpad->SetOrientation(
EDA_ANGLE( src->rotate -
pin->rotation,
2980 if( newpad->GetSizeX() > 0 || newpad->GetSizeY() > 0 )
2986 reportError(
_(
"Invalid zero-sized pad ignored in\nfile: %s" ),
3013 for(
auto& layer :
layers )
3018 layer_set.
set( layer.second.layerid );
3023 for(
auto& layer :
layers )
3025 if( layer.second.conductive )
3028 layer.second.name );
3042 std::vector<const FABMASTER_LAYER*> conductiveLayers;
3044 for(
const auto& layer :
layers )
3046 if( layer.second.conductive )
3047 conductiveLayers.push_back( &layer.second );
3056 auto net_it = netinfo.find(
via->net );
3057 auto padstack =
pads.find(
via->padstack );
3063 if( net_it != netinfo.end() )
3064 new_via->
SetNet( net_it->second );
3066 if( padstack ==
pads.end() )
3070 if( !ds.m_ViasDimensionsList.empty() )
3073 new_via->
SetDrill( ds.m_ViasDimensionsList[0].m_Drill );
3083 new_via->
SetDrill( padstack->second.drill_size_x );
3086 const std::set<std::string>& viaLayers = padstack->second.copper_layers;
3088 if( viaLayers.size() >= 2 )
3096 if( viaLayers.count( layer->name ) )
3105 if( topLayer && botLayer && topLayer != botLayer )
3111 bool isThrough = ( topLayerId ==
F_Cu && botLayerId ==
B_Cu );
3117 if( topLayerId ==
F_Cu || botLayerId ==
B_Cu )
3152 auto net_it = netinfo.find( aLine->netname );
3154 for(
const auto& seg : aLine->segment )
3160 switch( seg->shape )
3173 if( net_it != netinfo.end() )
3174 trk->
SetNet( net_it->second );
3188 if( net_it != netinfo.end() )
3189 trk->
SetNet( net_it->second );
3197 for( std::unique_ptr<BOARD_ITEM>& new_item :
createBoardItems( *aBoard, layer, *seg ) )
3205 reportError(
_(
"Expecting etch data to be on copper layer. Row found on layer '%s'" ),
3206 seg->layer.c_str() );
3217 int last_subseq = 0;
3222 for(
const auto& seg : aElement )
3224 if( seg->subseq > 0 || seg->subseq != last_subseq )
3231 if( poly_outline.
VertexCount( 0, hole_idx ) == 0 )
3245 return poly_outline;
3272 if( aLine.
segment.size() == 0 )
3278 int first_subseq = -1;
3279 bool have_multiple_subseqs =
false;
3281 for(
const std::unique_ptr<GRAPHIC_ITEM>& gr_item : aLine.
segment )
3283 if( first ==
nullptr )
3285 first = gr_item.get();
3286 first_subseq = gr_item->subseq;
3288 else if( gr_item->subseq == first_subseq )
3290 last = gr_item.get();
3294 have_multiple_subseqs =
true;
3300 wxCHECK( first,
true );
3318 switch( last->
shape )
3340 if(
end.has_value() && start ==
end )
3348std::vector<std::unique_ptr<BOARD_ITEM>>
3351 std::vector<std::unique_ptr<BOARD_ITEM>> new_items;
3356 const auto setShapeParameters = [&](
PCB_SHAPE& aShape )
3360 if( aShape.GetWidth() == 0 )
3361 aShape.SetStroke( defaultStroke );
3364 switch( aGraphic.
shape )
3370 auto new_text = std::make_unique<PCB_TEXT>( &aBoard );
3374 new_text->SetMirrored(
true );
3377 setupText( src, aLayer, *new_text, aBoard, std::nullopt );
3379 new_items.emplace_back( std::move( new_text ) );
3392 for(
const SEG& seg : segs )
3394 auto line = std::make_unique<PCB_SHAPE>( &aBoard );
3396 line->SetStart( seg.A );
3397 line->SetEnd( seg.B );
3399 setShapeParameters( *line );
3400 new_items.emplace_back( std::move( line ) );
3408 auto new_shape = std::make_unique<PCB_SHAPE>( &aBoard );
3410 setShapeParameters( *new_shape );
3412 switch( aGraphic.
shape )
3441 new_shape->SetRadius( src.
radius );
3453 new_shape->SetFilled( src.
fill );
3461 new_shape->SetPolyPoints( src.
m_pts );
3491 new_shape->SetPolyShape( poly );
3499 wxT(
"Unhandled shape type %d in polygon on layer %s, seq %d %d" ),
3503 new_items.emplace_back( std::move( new_shape ) );
3507 for( std::unique_ptr<BOARD_ITEM>& new_item : new_items )
3509 new_item->SetLayer( aLayer );
3513 if( new_items.size() > 1 )
3515 auto new_group = std::make_unique<PCB_GROUP>( &aBoard );
3516 for( std::unique_ptr<BOARD_ITEM>& new_item : new_items )
3518 new_group->AddItem( new_item.get() );
3520 new_items.emplace_back( std::move( new_group ) );
3529 if( aLine->segment.empty() )
3543 for(
const auto& seg : aLine->segment )
3545 for( std::unique_ptr<BOARD_ITEM>& new_item :
createBoardItems( *aBoard, layer, *seg ) )
3592 if( aLine->segment.size() < 3 )
3596 ZONE* zone =
nullptr;
3599 auto net_it = netinfo.find( aLine->netname );
3601 auto new_layer =
getLayer( aLine->layer );
3606 zone =
new ZONE( aBoard );
3609 if( net_it != netinfo.end() )
3610 zone->
SetNet( net_it->second );
3612 if( aLine->layer ==
"ALL" )
3614 else if( aLine->layer ==
"OUTER_LAYERS" )
3616 else if( aLine->layer ==
"INNER_PLANE_LAYERS" || aLine->layer ==
"INNER_SIGNAL_LAYERS" )
3628 if( aLine->lclass ==
"ROUTE KEEPOUT" )
3637 else if( aLine->lclass ==
"VIA KEEPOUT" )
3642 else if( aLine->lclass ==
"PACKAGE KEEPOUT" )
3647 else if( aLine->lclass ==
"ROUTE KEEPIN" || aLine->lclass ==
"PACKAGE KEEPIN"
3648 || aLine->lclass ==
"CONSTRAINT REGION" )
3653 zone->
SetZoneName( wxString::FromUTF8( aLine->lclass.c_str() ) );
3665 std::unique_ptr<SHAPE_LINE_CHAIN> pending_hole =
nullptr;
3668 const auto add_hole_if_valid = [&]()
3672 pending_hole->SetClosed(
true );
3678 reportInfo(
_(
"Invalid hole with %d points in zone on layer %s with net %s" ),
3683 pending_hole.reset();
3687 int last_subseq = 0;
3688 for(
const auto& seg : aLine->segment )
3690 if( seg->subseq > 0 && seg->subseq != last_subseq )
3694 if( aLine->lclass ==
"BOUNDARY" )
3697 add_hole_if_valid();
3698 pending_hole = std::make_unique<SHAPE_LINE_CHAIN>();
3699 active_chain = pending_hole.get();
3700 last_subseq = seg->subseq;
3711 active_chain->
Append( start );
3720 reportError(
_(
"Outline seems discontinuous: last point was %s, "
3721 "start point of next segment is %s" ),
3736 reportError(
_(
"Invalid shape type %d in zone outline" ), seg->shape );
3741 add_hole_if_valid();
3750 delete( zone_outline );
3762 if( aLine->lclass ==
"BOARD GEOMETRY" && aLine->layer !=
"DIMENSION" )
3764 else if( aLine->lclass ==
"DRAWING FORMAT" )
3769 for(
auto& seg : aLine->segment )
3771 for( std::unique_ptr<BOARD_ITEM>& new_item :
createBoardItems( *aBoard, layer, *seg ) )
3791 if( geom.subclass ==
"PIN_NUMBER" )
3799 if( !geom.elements->empty() )
3802 if( ( *( geom.elements->begin() ) )->width == 0 )
3823 for(
auto& seg : *geom.elements )
3825 for( std::unique_ptr<BOARD_ITEM>& new_item :
createBoardItems( *aBoard, layer, *seg ) )
3866 for(
auto& track :
traces )
3870 if( track->lclass ==
"ETCH" )
3872 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
virtual void SetNet(NETINFO_ITEM *aNetInfo)
Set a NET_INFO object for the item.
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
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
virtual void SetFilled(bool aFlag)
virtual void SetTextPos(const VECTOR2I &aPoint)
void SetMirrored(bool isMirrored)
void SetVertJustify(GR_TEXT_V_ALIGN_T aType)
virtual void SetTextWidth(int aWidth)
virtual void SetVisible(bool aVisible)
virtual void SetTextHeight(int aHeight)
void SetKeepUpright(bool aKeepUpright)
virtual void SetText(const wxString &aText)
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!
void reportError(const wxString &aMsg) const
Report a malformed-input issue the user can act on.
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
void reportInfo(const wxString &aFormat, Args &&... aArgs) const
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)
void createComponentsFromOrphanPins()
Creates synthetic COMPONENT entries from pins that have no matching component.
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)
void reportWarning(const wxString &aFormat, Args &&... aArgs) const
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 & ExternalCuMask()
Return a mask holding the Front and Bottom layers.
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.
static const LSET & InternalCuMask()
Return a complete set of internal copper layers which is all Cu layers except F_Cu and B_Cu.
Handle the data for a net.
unsigned GetNetCount() const
const NETNAMES_MAP & NetsByName() const
Return the name map, at least for python.
@ FRONT_INNER_BACK
Up to three shapes can be defined (F_Cu, inner copper layers, B_Cu)
static constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
static constexpr PCB_LAYER_ID INNER_LAYERS
! The layer identifier to use for "inner layers" on top/inner/bottom padstacks
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 SetShape(SHAPE_T aShape) override
void SetEnd(const VECTOR2I &aEnd) override
void SetPolyShape(const SHAPE_POLY_SET &aShape) override
void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
void SetStart(const VECTOR2I &aStart) override
void SetStroke(const STROKE_PARAMS &aStroke) override
void SetTextThickness(int aWidth) override
The TextThickness is that set by the user.
void SetTextAngle(const EDA_ANGLE &aAngle) 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)
void SetPosition(const VECTOR2I &aPoint) override
void SetLayerPair(PCB_LAYER_ID aTopLayer, PCB_LAYER_ID aBottomLayer)
For a via m_layer contains the top layer, the other layer is in m_bottomLayer/.
void SetViaType(VIATYPE aViaType)
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.
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
void Fracture(bool aSimplify=true)
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
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 SetNet(NETINFO_ITEM *aNetInfo) override
Override that drops aNetInfo when this zone is in copper-thieving fill mode.
void SetDoNotAllowFootprints(bool aEnable)
void SetDoNotAllowZoneFills(bool aEnable)
void SetAssignedPriority(unsigned aPriority)
void SetPadConnection(ZONE_CONNECTION aPadConnection)
void SetZoneName(const wxString &aName)
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.
const wxChar *const traceFabmaster
static bool isRuleAreaClass(const std::string &aClass)
Allegro area "shapes" that carry no net and must not become copper fills.
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
#define THROW_IO_ERRORF(msg,...)
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)
std::map< wxString, NETINFO_ITEM * > NETNAMES_MAP
@ 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!
Per-layer pad geometry within a pad stack.
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.
wxLogTrace helper definitions.
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
bool AutoAssignZonePriorities(BOARD *aBoard, PROGRESS_REPORTER *aReporter)
Automatically assign zone priorities based on connectivity analysis of overlapping regions.
@ FULL
pads are covered by copper