57#include <wx/filename.h>
62 const unsigned PROGRESS_DELTA = 250;
82 std::istringstream istr( aStr );
83 istr.imbue( std::locale::classic() );
93 std::istringstream istr( aStr );
94 istr.imbue( std::locale::classic() );
105 std::ifstream ifs( aFile, std::ios::in | std::ios::binary );
113 ifs.ignore( std::numeric_limits<std::streamsize>::max() );
114 std::streamsize length = ifs.gcount();
116 ifs.seekg( 0, std::ios_base::beg );
118 std::string buffer( std::istreambuf_iterator<char>{ ifs }, {} );
120 std::vector < std::string > row;
124 row.reserve( length / 100 );
130 for(
auto& ch : buffer )
136 if( cell.empty() || cell[0] ==
'"' )
145 row.push_back( cell );
157 row.push_back( cell );
160 rows.push_back( row );
169 cell += std::toupper( ch );
174 if( !cell.empty() || !row.empty() )
176 row.push_back( cell );
178 rows.push_back( row );
190 row =
rows.at( aOffset );
192 catch( std::out_of_range& )
200 if( row[0].back() !=
'A' )
203 std::string row1 = row[1];
204 std::string row2 = row[2];
217 if( row1 ==
"REFDES" && row2 ==
"COMPCLASS" )
220 if( row1 ==
"NETNAME" && row2 ==
"REFDES" )
223 if( row1 ==
"CLASS" && row2 ==
"SUBCLASS" && row3.empty() )
226 if( row1 ==
"GRAPHICDATANAME" && row2 ==
"GRAPHICDATANUMBER" )
229 if( row1 ==
"CLASS" && row2 ==
"SUBCLASS" && row3 ==
"GRAPHICDATANAME" )
232 if( row1 ==
"SYMNAME" && row2 ==
"PINNAME" )
235 if( row1 ==
"SYMNAME" && row2 ==
"SYMMIRROR" && row3 ==
"PINNAME" )
238 if( row1 ==
"VIAX" && row2 ==
"VIAY" )
241 if( row1 ==
"SUBCLASS" && row2 ==
"PADSHAPENAME" )
244 if( row1 ==
"PADNAME" )
247 if( row1 ==
"LAYERSORT" )
250 wxLogError(
_(
"Unknown FABMASTER section %s:%s at row %zu." ),
262 if( aRow >=
rows.size() )
265 if(
rows[aRow].size() < 11 )
267 wxLogError(
_(
"Invalid row size in J row %zu. Expecting 11 elements but found %zu." ),
273 for(
int i = 7; i < 10 && retval < 1.0; ++i )
275 std::string units =
rows[aRow][i];
276 std::transform(units.begin(), units.end(),units.begin(), ::toupper);
278 if( units ==
"MILS" )
280 else if( units ==
"MILLIMETERS" )
282 else if( units ==
"MICRONS" )
284 else if( units ==
"INCHES" )
290 wxLogError(
_(
"Could not find units value, defaulting to mils." ) );
299 if( aRow >=
rows.size() )
302 std::vector<std::string> header =
rows[aRow];
304 for(
size_t i = 0; i < header.size(); i++ )
308 alg::delete_if( header[i], [](
const char c ) {
return c ==
'_'; } );
310 if( header[i] == aStr )
321 const auto& kicad_layer =
layers.find( aLayerName);
323 if( kicad_layer ==
layers.end() )
326 return static_cast<PCB_LAYER_ID>( kicad_layer->second.layerid );
332 size_t rownum = aRow + 2;
334 if( rownum >=
rows.size() )
352 for( ; rownum <
rows.size() &&
rows[rownum].size() > 0 &&
rows[rownum][0] ==
"S"; ++rownum )
356 if( row.size() != header.size() )
358 wxLogError(
_(
"Invalid row size in row %zu. Expecting %zu elements but found %zu." ),
365 auto pad_name = row[pad_name_col];
366 auto pad_num = row[pad_num_col];
367 auto pad_layer = row[pad_lay_col];
368 auto pad_is_fixed = row[pad_fix_col];
369 auto pad_is_via = row[pad_via_col];
370 auto pad_shape = row[pad_shape_col];
371 auto pad_width = row[pad_width_col];
372 auto pad_height = row[pad_height_col];
373 auto pad_xoff = row[pad_xoff_col];
374 auto pad_yoff = row[pad_yoff_col];
375 auto pad_flash = row[pad_flash_col];
376 auto pad_shapename = row[pad_shape_name_col];
379 if( pad_layer ==
"INTERNAL_PAD_DEF" || pad_layer ==
"internal_pad_def" )
383 if( pad_layer[0] ==
'~' )
392 layer.
name = pad_layer;
410 size_t rownum = aRow + 2;
412 if( rownum >=
rows.size() )
418 if( scale_factor <= 0.0 )
434 for( ; rownum <
rows.size() &&
rows[rownum].size() > 0 &&
rows[rownum][0] ==
"S"; ++rownum )
439 if( row.size() != header.size() )
441 wxLogError(
_(
"Invalid row size in row %zu. Expecting %zu elements but found %zu." ),
448 auto pad_name = row[pad_name_col];
449 auto pad_num = row[pad_num_col];
450 auto pad_layer = row[pad_lay_col];
451 auto pad_is_fixed = row[pad_fix_col];
452 auto pad_is_via = row[pad_via_col];
453 auto pad_shape = row[pad_shape_col];
454 auto pad_width = row[pad_width_col];
455 auto pad_height = row[pad_height_col];
456 auto pad_xoff = row[pad_xoff_col];
457 auto pad_yoff = row[pad_yoff_col];
458 auto pad_flash = row[pad_flash_col];
459 auto pad_shapename = row[pad_shape_name_col];
462 if( pad_layer ==
"INTERNAL_PAD_DEF" || pad_layer ==
"internal_pad_def" )
467 auto new_pad =
pads.find( pad_name );
469 if( new_pad !=
pads.end() )
470 pad = &new_pad->second;
475 pad->name = pad_name;
479 if( pad_layer ==
"~DRILL" )
493 wxLogError(
_(
"Expecting drill size value but found %s!%s!%s in row %zu." ),
511 if( drill_x == drill_y )
513 pad->drill_size_x = drill_hit;
514 pad->drill_size_y = drill_hit;
518 pad->drill_size_x = drill_x;
519 pad->drill_size_y = drill_y;
522 if( !pad_shapename.empty() && pad_shapename[0] ==
'P' )
528 if( pad_shape.empty() )
541 wxLogError(
_(
"Expecting pad size values but found %s : %s in row %zu." ),
551 auto layer =
layers.find( pad_layer );
553 if( layer !=
layers.end() )
555 if( layer->second.layerid ==
F_Cu )
557 else if( layer->second.layerid ==
B_Cu )
561 if( w > std::numeric_limits<int>::max() || h > std::numeric_limits<int>::max() )
563 wxLogError(
_(
"Invalid pad size in row %zu." ), rownum );
567 if( pad_layer ==
"~TSM" || pad_layer ==
"~BSM" )
569 if( w > 0.0 && h > 0.0 )
577 if( pad_layer ==
"~TSP" || pad_layer ==
"~BSP" )
579 if( w > 0.0 && h > 0.0 )
588 if( pad_layer[0] ==
'~' )
598 wxLogError(
_(
"Expecting pad offset values but found %s:%s in row %zu." ),
605 if( w > 0.0 && h > 0.0 && recnum == 1 )
609 pad->via = ( std::toupper( pad_is_via[0] ) !=
'V' );
611 if( pad_shape ==
"CIRCLE" )
616 else if( pad_shape ==
"RECTANGLE" )
620 else if( pad_shape ==
"ROUNDED_RECT" )
624 else if( pad_shape ==
"SQUARE" )
629 else if( pad_shape ==
"OBLONG" || pad_shape ==
"OBLONG_X" || pad_shape ==
"OBLONG_Y" )
631 else if( pad_shape ==
"OCTAGON" )
634 pad->is_octogon =
true;
636 else if( pad_shape ==
"SHAPE" )
639 pad->custom_name = pad_shapename;
643 wxLogError(
_(
"Unknown pad shape name '%s' on layer '%s' in row %zu." ),
652 return rownum - aRow;
658 size_t rownum = aRow + 2;
660 if( rownum >=
rows.size() )
663 auto header =
rows[aRow];
666 if( scale_factor <= 0.0 )
672 if( layer_class_col < 0 || layer_subclass_col < 0 )
675 for( ; rownum <
rows.size() &&
rows[rownum].size() > 0 &&
rows[rownum][0] ==
"S"; ++rownum )
679 if( row.size() != header.size() )
681 wxLogError(
_(
"Invalid row size in row %zu. Expecting %zu elements but found %zu." ),
691 layer.
name = row[layer_subclass_col];
695 if( row[layer_class_col] ==
"ANTI ETCH" )
700 else if( row[layer_class_col] ==
"ETCH" )
706 return rownum - aRow;
714 std::string max_layer_name;
716 std::vector<std::pair<std::string, int>> extra_layers
718 {
"ASSEMBLY_TOP",
F_Fab },
719 {
"ASSEMBLY_BOTTOM",
B_Fab },
720 {
"PLACE_BOUND_TOP",
F_CrtYd },
721 {
"PLACE_BOUND_BOTTOM",
B_CrtYd },
724 std::vector<FABMASTER_LAYER*> layer_order;
733 layer_order.push_back( &layer );
735 else if( layer.
name.find(
"SILK" ) != std::string::npos &&
736 layer.
name.find(
"AUTOSILK" ) == std::string::npos )
738 if( layer.
name.find(
"B" ) != std::string::npos )
743 else if( layer.
name.find(
"MASK" ) != std::string::npos ||
744 layer.
name.find(
"MSK" ) != std::string::npos )
746 if( layer.
name.find(
"B" ) != std::string::npos )
751 else if( layer.
name.find(
"PAST" ) != std::string::npos )
753 if( layer.
name.find(
"B" ) != std::string::npos )
758 else if( layer.
name.find(
"NCLEGEND" ) != std::string::npos )
767 for(
auto layer : layer_order )
768 layer->layerid = layernum++;
772 layer_order.back()->layerid =
B_Cu;
774 for(
auto& new_pair : extra_layers )
778 new_layer.
name = new_pair.first;
779 new_layer.
layerid = new_pair.second;
782 auto result =
layers.emplace( new_pair.first, new_layer );
786 result.first->second.layerid = new_pair.second;
787 result.first->second.disable =
false;
802 size_t rownum = aRow + 2;
804 if( rownum >=
rows.size() )
807 auto header =
rows[aRow];
810 if( scale_factor <= 0.0 )
818 int layer_er_col =
getColFromName( aRow,
"LAYERDIELECTRICCONSTANT" );
819 int layer_rho_col =
getColFromName( aRow,
"LAYERELECTRICALCONDUCTIVITY" );
822 if( layer_sort_col < 0 || layer_subclass_col < 0 || layer_art_col < 0 || layer_use_col < 0
823 || layer_cond_col < 0 || layer_er_col < 0 || layer_rho_col < 0 || layer_mat_col < 0 )
826 for( ; rownum <
rows.size() &&
rows[rownum].size() > 0 &&
rows[rownum][0] ==
"S"; ++rownum )
830 if( row.size() != header.size() )
832 wxLogError(
_(
"Invalid row size in row %zu. Expecting %zu elements but found %zu." ),
839 auto layer_sort = row[layer_sort_col];
840 auto layer_subclass = row[layer_subclass_col];
841 auto layer_art = row[layer_art_col];
842 auto layer_use = row[layer_use_col];
843 auto layer_cond = row[layer_cond_col];
844 auto layer_er = row[layer_er_col];
845 auto layer_rho = row[layer_rho_col];
846 auto layer_mat = row[layer_mat_col];
848 if( layer_mat ==
"AIR" )
853 if( layer_subclass.empty() )
855 if( layer_cond !=
"NO" )
856 layer.
name =
"In.Cu" + layer_sort;
858 layer.
name =
"Dielectric" + layer_sort;
861 layer.
positive = ( layer_art !=
"NEGATIVE" );
866 return rownum - aRow;
877 size_t rownum = aRow + 2;
879 if( rownum >=
rows.size() )
882 auto header =
rows[aRow];
885 if( scale_factor <= 0.0 )
890 int pad_grdata_name_col =
getColFromName( aRow,
"GRAPHICDATANAME" );
891 int pad_grdata_num_col =
getColFromName( aRow,
"GRAPHICDATANUMBER" );
906 if( pad_subclass_col < 0 || pad_shape_name_col < 0 || pad_grdata1_col < 0 || pad_grdata2_col < 0
907 || pad_grdata3_col < 0 || pad_grdata4_col < 0 || pad_grdata5_col < 0
908 || pad_grdata6_col < 0 || pad_grdata7_col < 0 || pad_grdata8_col < 0
909 || pad_grdata9_col < 0 || pad_stack_name_col < 0 || pad_refdes_col < 0
910 || pad_pin_num_col < 0 )
913 for( ; rownum <
rows.size() &&
rows[rownum].size() > 0 &&
rows[rownum][0] ==
"S"; ++rownum )
917 if( row.size() != header.size() )
919 wxLogError(
_(
"Invalid row size in row %zu. Expecting %zu elements but found %zu." ),
927 auto pad_layer = row[pad_subclass_col];
928 auto pad_shape_name = row[pad_shape_name_col];
929 auto pad_record_tag = row[pad_record_tag_col];
944 auto pad_stack_name = row[pad_stack_name_col];
945 auto pad_refdes = row[pad_refdes_col];
946 auto pad_pin_num = row[pad_pin_num_col];
950 std::string prefix(
"FIG_SHAPE " );
952 if( pad_shape_name.length() <= prefix.length()
953 || !std::equal( prefix.begin(), prefix.end(), pad_shape_name.begin() ) )
963 if( std::sscanf( pad_record_tag.c_str(),
"%d %d", &
id, &seq ) != 2 )
965 wxLogError(
_(
"Invalid format for id string '%s' in custom pad row %zu." ),
966 pad_record_tag.c_str(),
971 auto name = pad_shape_name.substr( prefix.length() );
972 name +=
"_" + pad_refdes +
"_" + pad_pin_num;
975 auto& custom_pad = ret.first->second;
981 custom_pad.name =
name;
982 custom_pad.padstack = pad_stack_name;
983 custom_pad.pinnum = pad_pin_num;
984 custom_pad.refdes = pad_refdes;
991 auto gr_item = std::unique_ptr<GRAPHIC_ITEM>(
processGraphic( gr_data, scale_factor ) );
995 gr_item->layer = pad_layer;
996 gr_item->refdes = pad_refdes;
1002 auto retval = pad_it.first->second.insert( std::move(gr_item ) );
1004 if( !retval.second )
1006 wxLogError(
_(
"Could not insert graphical item %d into padstack '%s'." ),
1008 pad_stack_name.c_str() );
1013 wxLogError(
_(
"Unrecognized pad shape primitive '%s' in row %zu." ),
1019 return rownum - aRow;
1067 angle = endangle - startangle;
1097 new_rect->
width = 0;
1121 if( toks.size() < 8 )
1124 wxLogError(
_(
"Invalid token count. Expected 8 but found %zu." ), toks.size() );
1126 new_text->
width = 0;
1127 new_text->
ital =
false;
1187 size_t rownum = aRow + 2;
1189 if( rownum >=
rows.size() )
1195 if( scale_factor <= 0.0 )
1214 if( geo_name_col < 0 || geo_num_col < 0 || geo_grdata1_col < 0 || geo_grdata2_col < 0
1215 || geo_grdata3_col < 0 || geo_grdata4_col < 0 || geo_grdata5_col < 0
1216 || geo_grdata6_col < 0 || geo_grdata7_col < 0 || geo_grdata8_col < 0
1217 || geo_grdata9_col < 0 || geo_subclass_col < 0 || geo_sym_name_col < 0
1218 || geo_refdes_col < 0 )
1221 for( ; rownum <
rows.size() &&
rows[rownum].size() > 0 &&
rows[rownum][0] ==
"S"; ++rownum )
1225 if( row.size() != header.size() )
1227 wxLogError(
_(
"Invalid row size in row %zu. Expecting %zu elements but found %zu." ),
1234 auto geo_tag = row[geo_tag_col];
1249 auto geo_refdes = row[geo_refdes_col];
1257 if( std::sscanf( geo_tag.c_str(),
"%d %d %d", &
id, &seq, &subseq ) < 2 )
1259 wxLogError(
_(
"Invalid format for record_tag string '%s' in row %zu." ),
1265 auto gr_item = std::unique_ptr<GRAPHIC_ITEM>(
processGraphic( gr_data, scale_factor ) );
1269 wxLogDebug( wxT(
"Unhandled graphic item '%s' in row %zu." ),
1276 gr_item->layer = row[geo_subclass_col];
1278 gr_item->subseq = subseq;
1280 if( geo_refdes.empty() )
1285 new_gr.
subclass = row[geo_subclass_col];
1286 new_gr.
refdes = row[geo_refdes_col];
1287 new_gr.
name = row[geo_sym_name_col];
1289 new_gr.
elements = std::make_unique<graphic_element>();
1294 graphic.
elements->emplace( std::move( gr_item ) );
1299 std::map<int, GEOM_GRAPHIC>{} );
1300 auto map_it = sym_gr_it.first->second.emplace(
id,
GEOM_GRAPHIC{} );
1301 auto& gr = map_it.first;
1305 gr->second.subclass = row[geo_subclass_col];
1306 gr->second.refdes = row[geo_refdes_col];
1307 gr->second.name = row[geo_sym_name_col];
1309 gr->second.elements = std::make_unique<graphic_element>();
1312 auto result = gr->second.elements->emplace( std::move( gr_item ) );
1316 return rownum - aRow;
1325 size_t rownum = aRow + 2;
1327 if( rownum >=
rows.size() )
1333 if( scale_factor <= 0.0 )
1342 if( viax_col < 0 || viay_col < 0 || padstack_name_col < 0 || net_name_col < 0
1343 || test_point_col < 0 )
1346 for( ; rownum <
rows.size() &&
rows[rownum].size() > 0 &&
rows[rownum][0] ==
"S"; ++rownum )
1350 if( row.size() != header.size() )
1352 wxLogError(
_(
"Invalid row size in row %zu. Expecting %zu elements but found %zu." ),
1359 vias.emplace_back( std::make_unique<FM_VIA>() );
1364 via->padstack = row[padstack_name_col];
1365 via->net = row[net_name_col];
1366 via->test_point = ( row[test_point_col] ==
"YES" );
1369 return rownum - aRow;
1380 size_t rownum = aRow + 2;
1382 if( rownum >=
rows.size() )
1388 if( scale_factor <= 0.0 )
1394 int grdata_num_col =
getColFromName( aRow,
"GRAPHICDATANUMBER" );
1407 if( class_col < 0 || layer_col < 0 || grdata_name_col < 0 || grdata_num_col < 0
1408 || tag_col < 0 || grdata1_col < 0 || grdata2_col < 0 || grdata3_col < 0
1409 || grdata4_col < 0 || grdata5_col < 0 || grdata6_col < 0 || grdata7_col < 0
1410 || grdata8_col < 0 || grdata9_col < 0 || netname_col < 0 )
1413 for( ; rownum <
rows.size() &&
rows[rownum].size() > 0 &&
rows[rownum][0] ==
"S"; ++rownum )
1417 if( row.size() != header.size() )
1419 wxLogError(
_(
"Invalid row size in row %zu. Expecting %zu elements but found %zu." ),
1439 const std::string& geo_tag = row[tag_col];
1446 if( std::sscanf( geo_tag.c_str(),
"%d %d %d", &
id, &seq, &subseq ) < 2 )
1448 wxLogError(
_(
"Invalid format for record_tag string '%s' in row %zu." ),
1454 auto gr_item = std::unique_ptr<GRAPHIC_ITEM>(
processGraphic( gr_data, scale_factor ) );
1458 wxLogDebug(
_(
"Unhandled graphic item '%s' in row %zu." ),
1464 auto new_trace = std::make_unique<TRACE>();
1466 new_trace->layer = row[layer_col];
1467 new_trace->netname = row[netname_col];
1468 new_trace->lclass = row[class_col];
1470 gr_item->layer = row[layer_col];
1472 gr_item->subseq = subseq;
1475 if( new_trace->lclass ==
"REF DES" )
1477 auto result =
refdes.emplace( std::move( new_trace ) );
1478 auto& ref = *result.first;
1479 ref->segment.emplace( std::move( gr_item ) );
1481 else if( gr_item->width == 0 )
1483 auto result =
zones.emplace( std::move( new_trace ) );
1484 auto& zone = *result.first;
1485 auto gr_result = zone->segment.emplace( std::move( gr_item ) );
1487 if( !gr_result.second )
1489 wxLogError(
_(
"Duplicate item for ID %d and sequence %d in row %zu." ),
1498 auto result =
traces.emplace( std::move( new_trace ) );
1499 auto& trace = *result.first;
1500 auto gr_result = trace->segment.emplace( std::move( gr_item ) );
1502 if( !gr_result.second )
1504 wxLogError(
_(
"Duplicate item for ID %d and sequence %d in row %zu." ),
1512 return rownum - aRow;
1518 if( aSymType ==
"PACKAGE" )
1520 else if( aSymType ==
"DRAFTING")
1522 else if( aSymType ==
"MECHANICAL" )
1524 else if( aSymType ==
"FORMAT" )
1533 if( aCmpClass ==
"IO" )
1535 else if( aCmpClass ==
"IC" )
1537 else if( aCmpClass ==
"DISCRETE" )
1549 size_t rownum = aRow + 2;
1551 if( rownum >=
rows.size() )
1557 if( scale_factor <= 0.0 )
1565 int compinscode_col =
getColFromName( aRow,
"COMPINSERTIONCODE" );
1576 if( refdes_col < 0 || compclass_col < 0 || comppartnum_col < 0 || compheight_col < 0
1577 || compdevlabelcol < 0 || compinscode_col < 0 || symtype_col < 0 || symname_col < 0
1578 || symmirror_col < 0 || symrotate_col < 0 || symx_col < 0 || symy_col < 0
1579 || compvalue_col < 0 || comptol_col < 0 || compvolt_col < 0 )
1582 for( ; rownum <
rows.size() &&
rows[rownum].size() > 0 &&
rows[rownum][0] ==
"S"; ++rownum )
1586 if( row.size() != header.size() )
1588 wxLogError(
_(
"Invalid row size in row %zu. Expecting %zu elements but found %zu." ),
1595 auto cmp = std::make_unique<COMPONENT>();
1597 cmp->refdes = row[refdes_col];
1599 cmp->pn = row[comppartnum_col];
1600 cmp->height = row[compheight_col];
1601 cmp->dev_label = row[compdevlabelcol];
1602 cmp->insert_code = row[compinscode_col];
1604 cmp->name = row[symname_col];
1605 cmp->mirror = ( row[symmirror_col] ==
"YES" );
1606 cmp->rotate =
readDouble( row[symrotate_col] );
1609 cmp->value = row[compvalue_col];
1610 cmp->tol = row[comptol_col];
1611 cmp->voltage = row[compvolt_col];
1617 auto retval =
components.insert( std::make_pair( cmp->refdes, std::vector<std::unique_ptr<COMPONENT>>{} ) );
1622 vec->second.push_back( std::move( cmp ) );
1625 return rownum - aRow;
1634 size_t rownum = aRow + 2;
1636 if( rownum >=
rows.size() )
1642 if( scale_factor <= 0.0 )
1656 if( symname_col < 0 ||symmirror_col < 0 || pinname_col < 0 || pinnum_col < 0 || pinx_col < 0
1657 || piny_col < 0 || padstack_col < 0 || refdes_col < 0 || pinrot_col < 0
1658 || testpoint_col < 0 )
1661 for( ; rownum <
rows.size() &&
rows[rownum].size() > 0 &&
rows[rownum][0] ==
"S"; ++rownum )
1665 if( row.size() != header.size() )
1667 wxLogError(
_(
"Invalid row size in row %zu. Expecting %zu elements but found %zu." ),
1674 auto pin = std::make_unique<PIN>();
1676 pin->name = row[symname_col];
1677 pin->mirror = ( row[symmirror_col] ==
"YES" );
1678 pin->pin_name = row[pinname_col];
1679 pin->pin_number = row[pinnum_col];
1682 pin->padstack = row[padstack_col];
1683 pin->refdes = row[refdes_col];
1686 auto map_it =
pins.find(
pin->refdes );
1688 if( map_it ==
pins.end() )
1690 auto retval =
pins.insert( std::make_pair(
pin->refdes, std::set<std::unique_ptr<PIN>,
PIN::BY_NUM>{} ) );
1691 map_it = retval.first;
1694 map_it->second.insert( std::move(
pin ) );
1697 return rownum - aRow;
1706 size_t rownum = aRow + 2;
1708 if( rownum >=
rows.size() )
1714 if( scale_factor <= 0.0 )
1724 if( netname_col < 0 || refdes_col < 0 || pinnum_col < 0 || pinname_col < 0 || pingnd_col < 0
1728 for( ; rownum <
rows.size() &&
rows[rownum].size() > 0 &&
rows[rownum][0] ==
"S"; ++rownum )
1732 if( row.size() != header.size() )
1734 wxLogError(
_(
"Invalid row size in row %zu. Expecting %zu elements but found %zu." ),
1742 new_net.
name = row[netname_col];
1743 new_net.
refdes = row[refdes_col];
1744 new_net.
pin_num = row[pinnum_col];
1745 new_net.
pin_name = row[pinname_col];
1746 new_net.
pin_gnd = ( row[pingnd_col] ==
"YES" );
1747 new_net.
pin_pwr = ( row[pinpwr_col] ==
"YES" );
1750 netnames.insert( row[netname_col] );
1753 return rownum - aRow;
1760 for(
size_t i = 0; i <
rows.size(); )
1774 i += std::max( retval, 1 );
1782 i += std::max( retval, 1 );
1790 i += std::max( retval, 1 );
1798 i += std::max( retval, 1 );
1806 i += std::max( retval, 1 );
1814 i += std::max( retval, 1 );
1822 i += std::max( retval, 1 );
1830 i += std::max( retval, 1 );
1838 i += std::max( retval, 1 );
1846 i += std::max( retval, 1 );
1863 for(
auto& zone :
zones )
1873 if( zone->layer ==
"OUTLINE" || zone->layer ==
"DESIGN_OUTLINE" )
1894 std::set<ZONE*> zones_to_delete;
1896 for(
auto zone : aBoard->
Zones() )
1899 if( zone->GetNetCode() > 0 )
1901 zones_to_delete.insert( zone );
1905 for(
auto zone1 : aBoard->
Zones() )
1908 if( zone1->GetNetCode() > 0 )
1913 std::vector<std::vector<ZONE*>> possible_deletions( overlaps.size() );
1915 for(
auto zone2 : aBoard->
Zones() )
1917 if( zone2->GetNetCode() <= 0 )
1922 if( zone1->GetLayer() != zone2->GetLayer() )
1928 for(
auto& pt1 : outline1.
CPoints() )
1932 overlaps[ zone2->GetNetCode() ]++;
1935 for(
auto& pt2 : outline2.
CPoints() )
1940 overlaps[ zone2->GetNetCode() ]++;
1945 size_t max_net_id = 0;
1947 for(
size_t el = 1; el < overlaps.size(); ++el )
1949 if( overlaps[el] > max_net )
1951 max_net = overlaps[el];
1957 zone1->SetNetCode( max_net_id );
1960 for(
auto zone : zones_to_delete )
1979 bool has_multiple = mod.second.size() > 1;
1981 for(
int i = 0; i < mod.second.size(); ++i )
1983 auto& src = mod.second[i];
1987 wxString mod_ref = src->name;
1996 wxString key = !lib_ref.empty() ? lib_ref + wxT(
":" ) + mod_ref : mod_ref;
1999 fpID.
Parse( key,
true );
2007 wxString reference = src->refdes;
2009 if( !std::isalpha( src->refdes[0] ) )
2010 reference.Prepend(
"UNK" );
2018 for(
auto& ref :
refdes )
2021 static_cast<const GRAPHIC_TEXT*
>( ( *( ref->segment.begin() ) ).get() );
2023 if( lsrc->
text == src->refdes )
2030 wxLogDebug(
"The layer %s is not mapped?\n", ref->layer.c_str() );
2075 for(
auto& gr_ref : gr_it->second )
2077 auto& graphic = gr_ref.second;
2079 for(
auto& seg : *graphic.elements )
2086 STROKE_PARAMS defaultStroke( ds.GetLineThickness( layer ) );
2088 switch( seg->shape )
2113 if( lsrc->
width == 0 )
2131 if( lsrc->
width == 0 )
2153 if( lsrc->
width == 0 )
2228 auto pin_it =
pins.find( src->refdes );
2230 if( pin_it !=
pins.end() )
2232 for(
auto&
pin : pin_it->second )
2234 auto pin_net_it =
pin_nets.find( std::make_pair(
pin->refdes,
pin->pin_number ) );
2235 auto padstack =
pads.find(
pin->padstack );
2236 std::string netname =
"";
2239 netname = pin_net_it->second.name;
2241 auto net_it = netinfo.find( netname );
2243 std::unique_ptr<PAD> newpad = std::make_unique<PAD>( fp );
2245 if( net_it != netinfo.end() )
2246 newpad->SetNet( net_it->second );
2248 newpad->SetNetCode( 0 );
2250 newpad->SetX(
pin->pin_x );
2253 newpad->SetY( 2 * src->y -
pin->pin_y );
2255 newpad->SetY(
pin->pin_y );
2257 newpad->SetNumber(
pin->pin_number );
2259 if( padstack ==
pads.end() )
2261 wxLogError(
_(
"Unable to locate padstack %s in file %s\n" ),
2267 auto&
pad = padstack->second;
2269 newpad->SetShape(
pad.shape );
2275 int pad_size = std::min(
pad.width,
pad.height );
2277 newpad->SetSize(
VECTOR2I( pad_size / 2, pad_size / 2 ) );
2279 std::string custom_name =
pad.custom_name +
"_" +
pin->refdes +
"_" +
pin->pin_number;
2280 auto custom_it =
pad_shapes.find( custom_name );
2286 int last_subseq = 0;
2293 for(
const auto& el : (*custom_it).second.elements )
2299 if(
getLayer( ( *( el.second.begin() ) )->layer ) != primary_layer )
2302 for(
const auto& seg : el.second )
2304 if( seg->subseq > 0 || seg->subseq != last_subseq )
2306 poly_outline.
Polygon(0).back().SetClosed(
true );
2314 if( poly_outline.
VertexCount( 0, hole_idx ) == 0 )
2332 wxLogError(
_(
"Invalid custom pad '%s'. Replacing with "
2334 custom_name.c_str() );
2339 poly_outline.
Fracture( SHAPE_POLY_SET::POLYGON_MODE::PM_FAST );
2341 poly_outline.
Move( -newpad->GetPosition() );
2353 newpad->AddPrimitivePoly( poly_outline, 0,
true );
2357 newpad->MergePrimitivesAsPolygon( &mergedPolygon );
2361 wxLogError(
_(
"Invalid custom pad '%s'. Replacing with "
2363 custom_name.c_str() );
2369 wxLogError(
_(
"Could not find custom pad '%s'." ),
2370 custom_name.c_str() );
2389 if(
pad.drill_size_x ==
pad.drill_size_y )
2394 newpad->SetDrillSize(
VECTOR2I(
pad.drill_size_x,
pad.drill_size_y ) );
2402 else if(
pad.bottom )
2407 newpad->SetLocalCoord();
2414 if( newpad->GetSizeX() > 0 || newpad->GetSizeY() > 0 )
2420 wxLogError(
_(
"Invalid zero-sized pad ignored in\nfile: %s" ),
2447 for(
auto& layer :
layers )
2452 layer_set.set( layer.second.layerid );
2457 for(
auto& layer :
layers )
2459 if( layer.second.conductive )
2462 layer.second.name );
2479 auto net_it = netinfo.find(
via->net );
2480 auto padstack =
pads.find(
via->padstack );
2486 if( net_it != netinfo.end() )
2487 new_via->
SetNet( net_it->second );
2489 if( padstack ==
pads.end() )
2493 if( !ds.m_ViasDimensionsList.empty() )
2495 new_via->
SetWidth( ds.m_ViasDimensionsList[0].m_Diameter );
2496 new_via->
SetDrill( ds.m_ViasDimensionsList[0].m_Drill );
2501 new_via->
SetWidth( ds.m_ViasMinSize );
2506 new_via->
SetDrill( padstack->second.drill_size_x );
2507 new_via->
SetWidth( padstack->second.width );
2534 auto net_it = netinfo.find( aLine->netname );
2536 int last_subseq = 0;
2537 ZONE* new_zone =
nullptr;
2539 for(
const auto& seg : aLine->segment )
2556 if( net_it != netinfo.end() )
2557 trk->
SetNet( net_it->second );
2569 if( net_it != netinfo.end() )
2570 trk->
SetNet( net_it->second );
2577 wxLogError(
_(
"Expecting etch data to be on copper layer. Row found on layer '%s'" ),
2578 seg->layer.c_str() );
2589 int last_subseq = 0;
2594 for(
const auto& seg : aElement )
2596 if( seg->subseq > 0 || seg->subseq != last_subseq )
2603 if( poly_outline.
VertexCount( 0, hole_idx ) == 0 )
2617 poly_outline.
Fracture( SHAPE_POLY_SET::POLYGON_MODE::PM_FAST );
2618 return poly_outline;
2624 if( aLine->segment.size() < 3 )
2629 auto new_layer =
getLayer( aLine->layer );
2670 if( aLine->segment.size() < 3 )
2673 int last_subseq = 0;
2676 ZONE* zone =
nullptr;
2679 auto net_it = netinfo.find( aLine->netname );
2681 auto new_layer =
getLayer( aLine->layer );
2686 zone =
new ZONE( aBoard );
2689 if( net_it != netinfo.end() )
2690 zone->
SetNet( net_it->second );
2692 if( aLine->layer ==
"ALL" )
2704 if( aLine->lclass ==
"ROUTE KEEPOUT")
2709 else if( aLine->lclass ==
"VIA KEEPOUT")
2725 for(
const auto& seg : aLine->segment )
2727 if( seg->subseq > 0 && seg->subseq != last_subseq )
2730 if( aLine->lclass ==
"BOUNDARY" )
2734 last_subseq = seg->subseq;
2735 last_subseq = seg->subseq;
2742 if( zone_outline->
VertexCount( 0, hole_idx ) == 0 )
2761 delete( zone_outline );
2773 if( aLine->lclass ==
"BOARD GEOMETRY" )
2775 else if( aLine->lclass ==
"DRAWING FORMAT" )
2782 for(
auto& seg : aLine->segment )
2784 switch( seg->shape )
2814 if( lsrc->
width == 0 )
2887 if( geom.subclass ==
"PIN_NUMBER" )
2895 if( !geom.elements->empty() )
2898 if( ( *( geom.elements->begin() ) )->width == 0 )
2917 for(
auto& seg : *geom.elements )
2919 switch( seg->shape )
3007 std::sort( aBoard->
Zones().begin(), aBoard->
Zones().end(),
3008 [&](
const ZONE* a,
const ZONE* b )
3010 if( a->GetLayer() == b->GetLayer() )
3011 return a->GetBoundingBox().GetArea() > b->GetBoundingBox().GetArea();
3013 return a->GetLayer() < b->GetLayer();
3017 unsigned int priority = 0;
3022 if( zone->GetIsRuleArea() )
3025 if( zone->GetLayer() != layer )
3027 layer = zone->GetLayer();
3031 zone->SetAssignedPriority( priority );
3060 for(
auto& track :
traces )
3064 if( track->lclass ==
"ETCH" )
3066 else if( track->layer ==
"OUTLINE" )
constexpr EDA_IU_SCALE pcbIUScale
void SetNet(NETINFO_ITEM *aNetInfo)
Set a NET_INFO object for the item.
int GetLineThickness(PCB_LAYER_ID aLayer) const
Return the default graphic segment thickness from the layer class for the given layer.
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically 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)
void SetEnabledLayers(LSET aLayerMask)
A proxy function that calls the correspondent function in m_BoardSettings.
bool SetLayerName(PCB_LAYER_ID aLayer, const wxString &aLayerName)
Changes the name of the layer given by aLayer.
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.
bool Intersects(const BOX2< Vec > &aRect) const
void SetCenter(const VECTOR2I &aCenter)
void SetFilled(bool aFlag)
void SetPolyShape(const SHAPE_POLY_SET &aShape)
void SetStart(const VECTOR2I &aStart)
void SetShape(SHAPE_T aShape)
void SetEnd(const VECTOR2I &aEnd)
void SetArcGeometry(const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd)
Set the three controlling points for an arc.
void SetWidth(int aWidth)
void SetTextPos(const VECTOR2I &aPoint)
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)
virtual void SetText(const wxString &aText)
void SetItalic(bool aItalic)
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
size_t processGeometry(size_t aRow)
A!GRAPHIC_DATA_NAME!GRAPHIC_DATA_NUMBER!RECORD_TAG!GRAPHIC_DATA_1!GRAPHIC_DATA_2!GRAPHIC_DATA_3!...
bool Read(const std::string &aFile)
bool loadNets(BOARD *aBoard)
std::map< std::string, std::map< int, GEOM_GRAPHIC > > comp_graphics
unsigned m_lastProgressCount
SYMTYPE parseSymType(const std::string &aSymType)
GRAPHIC_TEXT * processText(const GRAPHIC_DATA &aData, double aScale)
bool loadLayers(BOARD *aBoard)
PCB_LAYER_ID getLayer(const std::string &aLayerName)
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)
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)
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
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_CIRCLE
! Not actually in Fabmaster but we use for 360° arcs
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)
void Flip(const VECTOR2I &aCentre, bool aFlipLeftRight) override
Flip entity relative to aCentre.
virtual void SetLocalCoord()
Set relative coordinates from draw coordinates.
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 LSET AllTechMask()
Return a mask holding all technical layers (no CU layer) on both side.
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Handle the data for a net.
unsigned GetNetCount() const
const NETNAMES_MAP & NetsByName() const
Return the name map, at least for python.
static 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
VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
void SetStroke(const STROKE_PARAMS &aStroke) override
void SetWidth(int aWidth)
void SetEnd(const VECTOR2I &aEnd)
void SetStart(const VECTOR2I &aStart)
void SetDrillDefault()
Function SetDrillDefault sets the drill value for vias to the default value UNDEFINED_DRILL_DIAMETER.
void SetDrill(int aDrill)
Function SetDrill sets the drill value for vias.
void SetPosition(const VECTOR2I &aPoint) 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
const VECTOR2I & GetP1() const
const VECTOR2I & GetP0() 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 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.
void Fracture(POLYGON_MODE aFastMode)
Convert a single outline slitted ("fractured") polygon into a set ouf outlines with holes.
int VertexCount(int aOutline=-1, int aHole=-1) const
Return the number of points in the shape poly set.
POLYGON & Polygon(int aIndex)
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Add a new vertex to the contour indexed by aOutline and aHole (defaults to the outline of the last po...
int AddHole(const SHAPE_LINE_CHAIN &aHole, int aOutline=-1)
Return the area of this poly set.
void Mirror(bool aX=true, bool aY=false, const VECTOR2I &aRef={ 0, 0 })
Mirror the line points about y or x (or both)
SHAPE_LINE_CHAIN & Outline(int aIndex)
SHAPE_LINE_CHAIN & Hole(int aOutline, int aHole)
Return the aIndex-th subpolygon in the set.
int NewOutline()
Creates a new hole in a given outline.
int OutlineCount() const
Return the number of vertices in a given outline/hole.
void Move(const VECTOR2I &aVector) override
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
Simple container to manage line stroke parameters.
Handle a list of polygons defining a copper zone.
void SetDoNotAllowPads(bool aEnable)
void SetDoNotAllowCopperPour(bool aEnable)
virtual void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
void SetIsRuleArea(bool aEnable)
void SetDoNotAllowTracks(bool aEnable)
void SetDoNotAllowVias(bool aEnable)
void SetLocalClearance(int aClearance)
void SetLayerSet(LSET aLayerSet) override
void SetDoNotAllowFootprints(bool aEnable)
void SetAssignedPriority(unsigned aPriority)
void SetPadConnection(ZONE_CONNECTION aPadConnection)
void SetOutline(SHAPE_POLY_SET *aOutline)
static constexpr EDA_ANGLE & ANGLE_360
static constexpr EDA_ANGLE & ANGLE_0
#define THROW_IO_ERROR(msg)
bool IsPcbLayer(int aLayer)
Test whether a layer is a valid layer for Pcbnew.
bool IsCopperLayer(int aLayerId)
Tests whether a layer is a copper layer.
PCB_LAYER_ID
A quick note on layer IDs:
LSET FlipLayerMask(LSET aMask, int aCopperLayersCount)
Calculate the mask layer when flipping a footprint.
PCB_LAYER_ID FlipLayer(PCB_LAYER_ID aLayerId, int aCopperLayersCount)
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
void delete_if(_Container &__c, _Function &&__f)
Deletes all values from __c for which __f returns true.
@ NPTH
like PAD_PTH, but not plated
@ SMD
Smd pad, appears on the solder paste layer (default)
@ PTH
Plated through hole pad.
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
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
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
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 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
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
@ FULL
pads are covered by copper