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];
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 alg::delete_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" )
634 pad->shape = PAD_SHAPE::CIRCLE;
636 else if( pad_shape ==
"RECTANGLE" )
638 pad->shape = PAD_SHAPE::RECTANGLE;
640 else if( pad_shape ==
"ROUNDED_RECT" )
642 pad->shape = PAD_SHAPE::ROUNDRECT;
644 else if( pad_shape ==
"SQUARE" )
646 pad->shape = PAD_SHAPE::RECTANGLE;
649 else if( pad_shape ==
"OBLONG" || pad_shape ==
"OBLONG_X" || pad_shape ==
"OBLONG_Y" )
650 pad->shape = PAD_SHAPE::OVAL;
651 else if( pad_shape ==
"OCTAGON" )
653 pad->shape = PAD_SHAPE::RECTANGLE;
654 pad->is_octogon =
true;
656 else if( pad_shape ==
"SHAPE" )
658 pad->shape = PAD_SHAPE::CUSTOM;
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 );
2429 fp->
Add( txt, ADD_MODE::APPEND );
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 )
2485 fp->
Add( line, ADD_MODE::APPEND );
2494 circle->SetLayer( layer );
2503 circle->Mirror( fp_orig, FLIP_DIRECTION::TOP_BOTTOM );
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 =
2529 std::make_unique<PCB_SHAPE>( fp, SHAPE_T::ARC );
2538 sarc.
Mirror( fp_orig, FLIP_DIRECTION::TOP_BOTTOM );
2542 arc->SetLayer( layer );
2546 if( lsrc->
width == 0 )
2547 arc->SetStroke( defaultStroke );
2550 arc->Flip( arc->GetCenter(), FLIP_DIRECTION::TOP_BOTTOM );
2552 fp->
Add( arc.release(), ADD_MODE::APPEND );
2577 fp->
Add( rect, ADD_MODE::APPEND );
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 );
2599 fp->
Add( field, ADD_MODE::APPEND );
2603 fp->
Add( txt.release(), ADD_MODE::APPEND );
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;
2658 if(
pad.shape == PAD_SHAPE::CUSTOM )
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() );
2727 newpad->SetShape(
F_Cu, PAD_SHAPE::CIRCLE );
2733 poly_outline.
Move( -newpad->GetPosition() );
2738 FLIP_DIRECTION::TOP_BOTTOM );
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() );
2778 newpad->SetAttribute( PAD_ATTRIB::PTH );
2783 newpad->SetAttribute( PAD_ATTRIB::NPTH );
2787 if(
pad.drill_size_x ==
pad.drill_size_y )
2788 newpad->SetDrillShape( PAD_DRILL_SHAPE::CIRCLE );
2790 newpad->SetDrillShape( PAD_DRILL_SHAPE::OBLONG );
2792 newpad->SetDrillSize(
VECTOR2I(
pad.drill_size_x,
pad.drill_size_y ) );
2796 newpad->SetAttribute( PAD_ATTRIB::SMD );
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 )
2814 fp->
Add( newpad.release(), ADD_MODE::APPEND );
2818 wxLogError(
_(
"Invalid zero-sized pad ignored in\nfile: %s" ),
2830 aBoard->
Add( fp, ADD_MODE::APPEND );
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 );
2908 aBoard->
Add( new_via, ADD_MODE::APPEND );
2922 aBoard->
Add( newnet, ADD_MODE::APPEND );
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 );
2959 aBoard->
Add( trk, ADD_MODE::APPEND );
2970 if( net_it != netinfo.end() )
2971 trk->
SetNet( net_it->second );
2973 aBoard->
Add( trk, ADD_MODE::APPEND );
2979 for( std::unique_ptr<BOARD_ITEM>& new_item :
2982 aBoard->
Add( new_item.release(), ADD_MODE::APPEND );
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 );
3177 line->SetShape( SHAPE_T::SEGMENT );
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 )
3199 new_shape->SetShape( SHAPE_T::SEGMENT );
3209 new_shape->SetShape( SHAPE_T::ARC );
3218 new_shape->SetShape( SHAPE_T::CIRCLE );
3220 new_shape->SetRadius( src.
radius );
3227 new_shape->SetShape( SHAPE_T::RECTANGLE );
3231 new_shape->SetFilled( src.
fill );
3237 new_shape->SetShape( SHAPE_T::POLY );
3238 new_shape->SetPolyPoints( src.
m_pts );
3266 new_shape->SetShape( SHAPE_T::POLY );
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 ) )
3321 aBoard->
Add( new_item.release(), ADD_MODE::APPEND );
3338 new_poly->
SetShape( SHAPE_T::POLY );
3350 STROKE_PARAMS( ( *( aLine->segment.begin() ) )->width, LINE_STYLE::SOLID ) );
3357 aBoard->
Add( new_poly, ADD_MODE::APPEND );
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 = [&]()
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();
3499 aBoard->
Add( zone, ADD_MODE::APPEND );
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 ) )
3526 aBoard->
Add( new_item.release(), ADD_MODE::APPEND );
3544 if( geom.subclass ==
"PIN_NUMBER" )
3552 if( !geom.elements->empty() )
3555 if( ( *( geom.elements->begin() ) )->width == 0 )
3572 aBoard->
Add( new_poly, ADD_MODE::APPEND );
3576 for(
auto& seg : *geom.elements )
3578 for( std::unique_ptr<BOARD_ITEM>& new_item :
createBoardItems( *aBoard, layer, *seg ) )
3580 aBoard->
Add( new_item.release(), ADD_MODE::APPEND );
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! PADXOFF!PADYOFF!...
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()
return AllCuMask( MAX_CU_LAYERS );
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.
virtual bool KeepRefreshing(bool aWait=false)=0
Update the UI (if any).
virtual void SetCurrentProgress(double aProgress)=0
Set the progress value to aProgress (0..1).
const VECTOR2I & GetArcMid() const
void Mirror(const VECTOR2I &aRef, FLIP_DIRECTION aFlipDirection)
const VECTOR2I & GetP1() const
const VECTOR2I & GetP0() const
const VECTOR2I & GetCenter() const
const VECTOR2I GetCenter() const
void SetCenter(const VECTOR2I &aCenter)
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...
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
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 & CPoint(int aIndex) const
Return a reference to a given 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
static const wxChar traceFabmaster[]
Flag to enable FABMASTER plugin debugging output.
#define THROW_IO_ERROR(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:
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.
void delete_if(_Container &__c, _Function &&__f)
Deletes all values from __c for which __f returns true.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
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 radius
! GRAPHIC_DATA_7 ! width is GRAPHIC_DATA_8
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
int end_y
! GRAPHIC_DATA_4 ! width is GRAPHIC_DATA_5
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)
const SHAPE_LINE_CHAIN chain
SHAPE_CIRCLE circle(c.m_circle_center, c.m_circle_radius)
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