KiCad PCB EDA Suite
import_fabmaster.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2020 BeagleBoard Foundation
5  * Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
6  * Author: Seth Hillbrand <hillbrand@kipro-pcb.com>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 3
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, you may find one here:
20  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21  * or you may search the http://www.gnu.org website for the version 2 license,
22  * or you may write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25 
26 #include "import_fabmaster.h"
27 
28 #include <algorithm>
29 #include <array>
30 #include <iostream>
31 #include <fstream>
32 #include <map>
33 #include <memory>
34 #include <string>
35 #include <sstream>
36 #include <vector>
37 #include <utility>
38 
39 #include <wx/log.h>
40 
41 #include <board.h>
42 #include <board_item.h>
43 #include <convert_to_biu.h>
44 #include <fp_shape.h>
45 #include <pad_shapes.h>
46 #include <pcb_shape.h>
47 #include <pcb_text.h>
48 #include <track.h>
49 #include <common.h>
50 #include <geometry/shape_arc.h>
51 #include <kicad_string.h>
52 #include <convert_to_biu.h>
53 #include <math/util.h>
54 #include <wx/filename.h>
55 
56 
57 double FABMASTER::readDouble( const std::string aStr ) const
58 {
59  std::istringstream istr( aStr );
60  istr.imbue( std::locale::classic() );
61 
62  double doubleValue;
63  istr >> doubleValue;
64  return doubleValue;
65 }
66 
67 
68 int FABMASTER::readInt( const std::string aStr ) const
69 {
70  std::istringstream istr( aStr );
71  istr.imbue( std::locale::classic() );
72 
73  int intValue;
74  istr >> intValue;
75  return intValue;
76 }
77 
78 
79 bool FABMASTER::Read( const std::string& aFile )
80 {
81 
82  std::ifstream ifs( aFile, std::ios::in | std::ios::binary );
83 
84  if( !ifs.is_open() )
85  return false;
86 
87  m_filename = aFile;
88 
89  // Read/ignore all bytes in the file to find the size and then go back to the beginning
90  ifs.ignore( std::numeric_limits<std::streamsize>::max() );
91  std::streamsize length = ifs.gcount();
92  ifs.clear();
93  ifs.seekg( 0, std::ios_base::beg );
94 
95  std::string buffer( std::istreambuf_iterator<char>{ ifs }, {} );
96 
97  std::vector < std::string > row;
98 
99  // Reserve an estimate of the number of rows to prevent continual re-allocation
100  // crashing (Looking at you MSVC)
101  row.reserve( length / 100 );
102  std::string cell;
103  cell.reserve( 100 );
104 
105  bool quoted = false;
106 
107  for( auto ch : buffer )
108  {
109  switch( ch )
110  {
111  case '"':
112 
113  if( cell.empty() || cell[0] == '"' )
114  quoted = !quoted;
115 
116  cell += ch;
117  break;
118 
119  case '!':
120  if( !quoted )
121  {
122  row.push_back( cell );
123  cell.clear();
124  }
125  else
126  cell += ch;
127 
128  break;
129 
130  case '\n':
131 
133  if( !cell.empty() )
134  row.push_back( cell );
135 
136  cell.clear();
137  rows.push_back( row );
138  row.clear();
139  quoted = false;
140  break;
141 
142  case '\r':
143  break;
144 
145  default:
146  cell += std::toupper( ch );
147  }
148  }
149 
150  // Handle last line without linebreak
151  if( !cell.empty() || !row.empty() )
152  {
153  row.push_back( cell );
154  cell.clear();
155  rows.push_back( row );
156  row.clear();
157  }
158 
159  return true;
160 }
161 
163 {
164  single_row row;
165  try
166  {
167  row = rows.at( aOffset );
168  }
169  catch( std::out_of_range& )
170  {
171  return UNKNOWN_EXTRACT;
172  }
173 
174  if( row.size() < 3 )
175  return UNKNOWN_EXTRACT;
176 
177  if( row[0].back() != 'A' )
178  return UNKNOWN_EXTRACT;
179 
180  std::string row1 = row[1];
181  std::string row2 = row[2];
182  std::string row3{};
183 
185  row1.erase( std::remove_if( row1.begin(), row1.end(), []( char c ){ return c == '_'; } ),
186  row1.end() );
187  row2.erase( std::remove_if( row2.begin(), row2.end(), []( char c ){ return c == '_'; } ),
188  row2.end() );
189 
190  if( row.size() > 3 )
191  {
192  row3 = row[3];
193  row3.erase( std::remove_if( row3.begin(), row3.end(), []( char c ){ return c == '_'; } ),
194  row3.end() );
195  }
196 
197  if( row1 == "REFDES" && row2 == "COMPCLASS" )
198  return EXTRACT_REFDES;
199 
200  if( row1 == "NETNAME" && row2 == "REFDES" )
201  return EXTRACT_NETS;
202 
203  if( row1 == "CLASS" && row2 == "SUBCLASS" && row3.empty() )
204  return EXTRACT_BASIC_LAYERS;
205 
206  if( row1 == "GRAPHICDATANAME" && row2 == "GRAPHICDATANUMBER" )
207  return EXTRACT_GRAPHICS;
208 
209  if( row1 == "CLASS" && row2 == "SUBCLASS" && row3 == "GRAPHICDATANAME" )
210  return EXTRACT_TRACES;
211 
212  if( row1 == "SYMNAME" && row2 == "PINNAME" )
213  return FABMASTER_EXTRACT_PINS;
214 
215  if( row1 == "SYMNAME" && row2 == "SYMMIRROR" && row3 == "PINNAME" )
216  return EXTRACT_PINS;
217 
218  if( row1 == "VIAX" && row2 == "VIAY" )
219  return EXTRACT_VIAS;
220 
221  if( row1 == "SUBCLASS" && row2 == "PADSHAPENAME" )
222  return EXTRACT_PAD_SHAPES;
223 
224  if( row1 == "PADNAME" )
225  return EXTRACT_PADSTACKS;
226 
227  if( row1 == "LAYERSORT" )
228  return EXTRACT_FULL_LAYERS;
229 
230  wxLogError
231  (
232  wxString::Format( _( "Unknown FABMASTER section %s:%s at row %zu." ), row1.c_str(),
233  row2.c_str(), aOffset ) );
234  return UNKNOWN_EXTRACT;
235 
236 }
237 
238 double FABMASTER::processScaleFactor( size_t aRow )
239 {
240  double retval = 0.0;
241 
242  if( aRow >= rows.size() )
243  return -1.0;
244 
245  if( rows[aRow].size() < 11 )
246  {
247  wxLogError( wxString::Format( _( "Invalid row size in J row %zu. "
248  "Expecting 11 elements but found %zu" ), aRow, rows[aRow].size() ) );
249  return -1.0;
250  }
251 
252  for( int i = 7; i < 10 && retval < 1.0; ++i )
253  {
254  auto units = rows[aRow][i];
255  std::transform(units.begin(), units.end(),units.begin(), ::toupper);
256 
257  if( units == "MILS" )
258  retval = IU_PER_MILS;
259  else if( units == "MILLIMETERS" )
260  retval = IU_PER_MM;
261  else if( units == "MICRONS" )
262  retval = IU_PER_MM * 10.0;
263  else if( units == "INCHES" )
264  retval = IU_PER_MILS * 1000.0;
265  }
266 
267  if( retval < 1.0 )
268  {
269  wxLogError( _( "Could not find units value, defaulting to Mils" ) );
270  retval = IU_PER_MILS;
271  }
272 
273  return retval;
274 }
275 
276 int FABMASTER::getColFromName( size_t aRow, const std::string& aStr )
277 {
278  if( aRow >= rows.size() )
279  return -1;
280 
281  auto header = rows[aRow];
282 
283  for( size_t i = 0; i < header.size(); i++ )
284  {
287  header[i].erase( std::remove_if( header[i].begin(), header[i].end(),
288  []( const char c ){ return c == '_'; } ), header[i].end() );
289 
290  if( header[i] == aStr )
291  return i;
292  }
293 
294  THROW_IO_ERROR( wxString::Format( _( "Could not find column label %s" ), aStr.c_str() ) );
295  return -1;
296 }
297 
298 
299 PCB_LAYER_ID FABMASTER::getLayer( const std::string& aLayerName )
300 {
301  const auto& kicad_layer = layers.find( aLayerName);
302 
303  if( kicad_layer == layers.end() )
304  return UNDEFINED_LAYER;
305  else
306  return static_cast<PCB_LAYER_ID>( kicad_layer->second.layerid );
307 }
308 
309 
310 size_t FABMASTER::processPadStackLayers( size_t aRow )
311 {
312  size_t rownum = aRow + 2;
313 
314  if( rownum >= rows.size() )
315  return -1;
316 
317  const auto header = rows[aRow];
318 
319  int pad_name_col = getColFromName( aRow, "PADNAME" );
320  int pad_num_col = getColFromName( aRow, "RECNUMBER" );
321  int pad_lay_col = getColFromName( aRow, "LAYER" );
322  int pad_fix_col = getColFromName( aRow, "FIXFLAG" );
323  int pad_via_col = getColFromName( aRow, "VIAFLAG" );
324  int pad_shape_col = getColFromName( aRow, "PADSHAPE1" );
325  int pad_width_col = getColFromName( aRow, "PADWIDTH" );
326  int pad_height_col = getColFromName( aRow, "PADHGHT" );
327  int pad_xoff_col = getColFromName( aRow, "PADXOFF" );
328  int pad_yoff_col = getColFromName( aRow, "PADYOFF" );
329  int pad_flash_col = getColFromName( aRow, "PADFLASH" );
330  int pad_shape_name_col = getColFromName( aRow, "PADSHAPENAME" );
331 
332  for( ; rownum < rows.size() && rows[rownum].size() > 0 && rows[rownum][0] == "S"; ++rownum )
333  {
334  auto row = rows[rownum];
335 
336  if( row.size() != header.size() )
337  {
338  wxLogError( wxString::Format( _( "Invalid row size in row %zu. "
339  "Expecting %zu elements but found %zu" ), rownum, header.size(), row.size() ) );
340  continue;
341  }
342 
343  auto pad_name = row[pad_name_col];
344  auto pad_num = row[pad_num_col];
345  auto pad_layer = row[pad_lay_col];
346  auto pad_is_fixed = row[pad_fix_col];
347  auto pad_is_via = row[pad_via_col];
348  auto pad_shape = row[pad_shape_col];
349  auto pad_width = row[pad_width_col];
350  auto pad_height = row[pad_height_col];
351  auto pad_xoff = row[pad_xoff_col];
352  auto pad_yoff = row[pad_yoff_col];
353  auto pad_flash = row[pad_flash_col];
354  auto pad_shapename = row[pad_shape_name_col];
355 
356  // This layer setting seems to be unused
357  if( pad_layer == "INTERNAL_PAD_DEF" || pad_layer == "internal_pad_def" )
358  continue;
359 
360  // Skip the technical layers
361  if( pad_layer[0] == '~' )
362  break;
363 
364  auto result = layers.emplace( pad_layer, FABMASTER_LAYER{} );
365  FABMASTER_LAYER& layer = result.first->second;
366 
368  if( layer.id == 0 )
369  {
370  layer.name = pad_layer;
371  layer.id = readInt( pad_num );
372  layer.conductive = true;
373  }
374  }
375 
376  return 0;
377 }
378 
379 
386 size_t FABMASTER::processPadStacks( size_t aRow )
387 {
388  size_t rownum = aRow + 2;
389 
390  if( rownum >= rows.size() )
391  return -1;
392 
393  const auto header = rows[aRow];
394  double scale_factor = processScaleFactor( aRow + 1 );
395 
396  if( scale_factor <= 0.0 )
397  return -1;
398 
399  int pad_name_col = getColFromName( aRow, "PADNAME" );
400  int pad_num_col = getColFromName( aRow, "RECNUMBER" );
401  int pad_lay_col = getColFromName( aRow, "LAYER" );
402  int pad_fix_col = getColFromName( aRow, "FIXFLAG" );
403  int pad_via_col = getColFromName( aRow, "VIAFLAG" );
404  int pad_shape_col = getColFromName( aRow, "PADSHAPE1" );
405  int pad_width_col = getColFromName( aRow, "PADWIDTH" );
406  int pad_height_col = getColFromName( aRow, "PADHGHT" );
407  int pad_xoff_col = getColFromName( aRow, "PADXOFF" );
408  int pad_yoff_col = getColFromName( aRow, "PADYOFF" );
409  int pad_flash_col = getColFromName( aRow, "PADFLASH" );
410  int pad_shape_name_col = getColFromName( aRow, "PADSHAPENAME" );
411 
412  for( ; rownum < rows.size() && rows[rownum].size() > 0 && rows[rownum][0] == "S"; ++rownum )
413  {
414  auto row = rows[rownum];
415  FM_PAD* pad;
416 
417  if( row.size() != header.size() )
418  {
419  wxLogError( wxString::Format( _( "Invalid row size in row %zu. "
420  "Expecting %zu elements but found %zu" ), rownum, header.size(), row.size() ) );
421  continue;
422  }
423 
424  auto pad_name = row[pad_name_col];
425  auto pad_num = row[pad_num_col];
426  auto pad_layer = row[pad_lay_col];
427  auto pad_is_fixed = row[pad_fix_col];
428  auto pad_is_via = row[pad_via_col];
429  auto pad_shape = row[pad_shape_col];
430  auto pad_width = row[pad_width_col];
431  auto pad_height = row[pad_height_col];
432  auto pad_xoff = row[pad_xoff_col];
433  auto pad_yoff = row[pad_yoff_col];
434  auto pad_flash = row[pad_flash_col];
435  auto pad_shapename = row[pad_shape_name_col];
436 
437  // This layer setting seems to be unused
438  if( pad_layer == "INTERNAL_PAD_DEF" || pad_layer == "internal_pad_def" )
439  continue;
440 
441  int recnum = KiROUND( readDouble( pad_num ) );
442 
443  auto new_pad = pads.find( pad_name );
444 
445  if( new_pad != pads.end() )
446  pad = &new_pad->second;
447  else
448  {
449  pads[pad_name] = FM_PAD();
450  pad = &pads[pad_name];
451  pad->name = pad_name;
452  }
453 
455  if( pad_layer == "~DRILL" )
456  {
457  int drill_hit;
458  int drill_x;
459  int drill_y;
460 
461  try
462  {
463  drill_hit = KiROUND( std::fabs( readDouble( pad_shape ) * scale_factor ) );
464  drill_x = KiROUND( std::fabs( readDouble( pad_width ) * scale_factor ) );
465  drill_y = KiROUND( std::fabs( readDouble( pad_height ) * scale_factor ) );
466  }
467  catch( ... )
468  {
469  wxLogError( wxString::Format( _( "Expecting drill size value "
470  "but found %s!%s!%s at line %zu" ),
471  pad_shape.c_str(), pad_width.c_str(), pad_height.c_str(), rownum ) );
472  continue;
473  }
474 
475  if( drill_hit == 0 )
476  {
477  pad->drill = false;
478  continue;
479  }
480 
481  pad->drill = true;
482 
485  if( drill_x == drill_y )
486  {
487  pad->drill_size_x = drill_hit;
488  pad->drill_size_y = drill_hit;
489  }
490  else
491  {
492  pad->drill_size_x = drill_x;
493  pad->drill_size_y = drill_y;
494  }
495 
496  if( !pad_shapename.empty() && pad_shapename[0] == 'P' )
497  pad->plated = true;
498 
499  continue;
500  }
501 
502  if( pad_shape.empty() )
503  continue;
504 
505  double w;
506  double h;
507 
508  try
509  {
510  w = readDouble( pad_width ) * scale_factor;
511  h = readDouble( pad_height ) * scale_factor;
512  }
513  catch( ... )
514  {
515  wxLogError( wxString::Format( _( "Expecting pad size values "
516  "but found %s : %s at line %zu" ), pad_width.c_str(), pad_height.c_str(), rownum ) );
517  continue;
518  }
519 
520  if( w <= 0.0 )
521  continue;
522 
523  auto layer = layers.find( pad_layer );
524 
525  if( layer != layers.end() )
526  {
527  if( layer->second.layerid == F_Cu )
528  pad->top = true;
529  else if( layer->second.layerid == B_Cu )
530  pad->bottom = true;
531  }
532 
533  if( w > std::numeric_limits<int>::max() || h > std::numeric_limits<int>::max() )
534  {
535  wxLogError( wxString::Format( _( "Invalid pad size on line %zu" ), rownum ) );
536  continue;
537  }
538 
539  if( pad_layer == "~TSM" || pad_layer == "~BSM" )
540  {
541  if( w > 0.0 && h > 0.0 )
542  {
543  pad->mask_width = KiROUND( w );
544  pad->mask_height = KiROUND( h );
545  }
546  continue;
547  }
548 
549  if( pad_layer == "~TSP" || pad_layer == "~BSP" )
550  {
551  if( w > 0.0 && h > 0.0 )
552  {
553  pad->paste_width = KiROUND( w );
554  pad->paste_height = KiROUND( h );
555  }
556  continue;
557  }
558 
560  if( pad_layer[0] == '~' )
561  continue;
562 
563  try
564  {
565  pad->x_offset = KiROUND( readDouble( pad_xoff ) * scale_factor );
566  pad->y_offset = -KiROUND( readDouble( pad_yoff ) * scale_factor );
567  }
568  catch( ... )
569  {
570  wxLogError( wxString::Format( _( "Expecting pad offset values "
571  "but found %s : %s at line %zu" ), pad_xoff.c_str(), pad_yoff.c_str(), rownum ) );
572  continue;
573  }
574 
575  if( w > 0.0 && h > 0.0 && recnum == 1 )
576  {
577  pad->width = KiROUND( w );
578  pad->height = KiROUND( h );
579  pad->via = ( std::toupper( pad_is_via[0] ) != 'V' );
580 
581  if( pad_shape == "CIRCLE" )
582  {
583  pad->height = pad->width;
584  pad->shape = PAD_SHAPE_CIRCLE;
585  }
586  else if( pad_shape == "RECTANGLE" )
587  {
588  pad->shape = PAD_SHAPE_RECT;
589  }
590  else if( pad_shape == "ROUNDED_RECT" )
591  {
592  pad->shape = PAD_SHAPE_ROUNDRECT;
593  }
594  else if( pad_shape == "SQUARE" )
595  {
596  pad->shape = PAD_SHAPE_RECT;
597  pad->height = pad->width;
598  }
599  else if( pad_shape == "OBLONG" || pad_shape == "OBLONG_X" || pad_shape == "OBLONG_Y" )
600  pad->shape = PAD_SHAPE_OVAL;
601  else if( pad_shape == "OCTAGON" )
602  {
603  pad->shape = PAD_SHAPE_RECT;
604  pad->is_octogon = true;
605  }
606  else if( pad_shape == "SHAPE" )
607  {
608  pad->shape = PAD_SHAPE_CUSTOM;
609  pad->custom_name = pad_shapename;
610  }
611  else
612  {
613  wxLogError( wxString::Format( _( "Unknown pad shape name '%s' on layer '%s' at line %zu" ),
614  pad_shape.c_str(), pad_layer.c_str(), rownum ) );
615  continue;
616  }
617  }
618  }
619 
620  return rownum - aRow;
621 }
622 
623 
624 size_t FABMASTER::processSimpleLayers( size_t aRow )
625 {
626  size_t rownum = aRow + 2;
627 
628  if( rownum >= rows.size() )
629  return -1;
630 
631  auto header = rows[aRow];
632  double scale_factor = processScaleFactor( aRow + 1 );
633 
634  if( scale_factor <= 0.0 )
635  return -1;
636 
637  int layer_class_col = getColFromName( aRow, "CLASS" );
638  int layer_subclass_col = getColFromName( aRow, "SUBCLASS" );
639 
640  if( layer_class_col < 0 || layer_subclass_col < 0 )
641  return -1;
642 
643  for( ; rownum < rows.size() && rows[rownum].size() > 0 && rows[rownum][0] == "S"; ++rownum )
644  {
645  auto row = rows[rownum];
646 
647  if( row.size() != header.size() )
648  {
649  wxLogError( wxString::Format( _( "Invalid row size in row %zu. "
650  "Expecting %zu elements but found %zu" ), rownum, header.size(), row.size() ) );
651  continue;
652  }
653 
654  auto result = layers.emplace( row[layer_subclass_col], FABMASTER_LAYER{} );
655  FABMASTER_LAYER& layer = result.first->second;
656 
657  layer.name = row[layer_subclass_col];
658  layer.positive = true;
659  layer.conductive = false;
660 
661  if( row[layer_class_col] == "ANTI ETCH" )
662  {
663  layer.positive = false;
664  layer.conductive = true;
665  }
666  else if( row[layer_class_col] == "ETCH" )
667  {
668  layer.conductive = true;
669  }
670  }
671 
672  return rownum - aRow;
673 }
674 
675 
677 {
678  bool has_l1 = false;
679  int max_layer = 0;
680  std::string max_layer_name;
681 
682  std::vector<std::pair<std::string, int>> extra_layers
683  {
684  { "ASSEMBLY_TOP", F_Fab },
685  { "ASSEMBLY_BOTTOM", B_Fab },
686  { "PLACE_BOUND_TOP", F_CrtYd },
687  { "PLACE_BOUND_BOTTOM", B_CrtYd },
688  };
689 
690  std::vector<FABMASTER_LAYER*> layer_order;
691 
692  for( auto& el : layers )
693  {
694  FABMASTER_LAYER& layer = el.second;
695  layer.layerid = UNSELECTED_LAYER;
696 
697  if( layer.conductive )
698  {
699  layer_order.push_back( &layer );
700  }
701  else if( layer.name.find( "SILK" ) != std::string::npos &&
702  layer.name.find( "AUTOSILK" ) == std::string::npos ) // Skip the autosilk layer
703  {
704  if( layer.name.find( "B" ) != std::string::npos )
705  layer.layerid = B_SilkS;
706  else
707  layer.layerid = F_SilkS;
708  }
709  else if( layer.name.find( "MASK" ) != std::string::npos ||
710  layer.name.find( "MSK" ) != std::string::npos )
711  {
712  if( layer.name.find( "B" ) != std::string::npos )
713  layer.layerid = B_Mask;
714  else
715  layer.layerid = F_Mask;
716  }
717  else if( layer.name.find( "PAST" ) != std::string::npos )
718  {
719  if( layer.name.find( "B" ) != std::string::npos )
720  layer.layerid = B_Paste;
721  else
722  layer.layerid = F_Paste;
723  }
724  else if( layer.name.find( "NCLEGEND" ) != std::string::npos )
725  layer.layerid = Dwgs_User;
726  else
727  layer.disable = true;
728  }
729 
730  std::sort( layer_order.begin(), layer_order.end(), FABMASTER_LAYER::BY_ID() );
731  int layernum = 0;
732 
733  for( auto layer : layer_order )
734  layer->layerid = layernum++;
735 
738  layer_order.back()->layerid = B_Cu;
739 
740  for( auto& new_pair : extra_layers )
741  {
742  FABMASTER_LAYER new_layer;
743 
744  new_layer.name = new_pair.first;
745  new_layer.layerid = new_pair.second;
746  new_layer.conductive = false;
747 
748  auto result = layers.emplace( new_pair.first, new_layer );
749 
750  if( !result.second )
751  {
752  result.first->second.layerid = new_pair.second;
753  result.first->second.disable = false;
754  }
755  }
756 
757  return true;
758 }
759 
760 
766 size_t FABMASTER::processLayers( size_t aRow )
767 {
768  size_t rownum = aRow + 2;
769 
770  if( rownum >= rows.size() )
771  return -1;
772 
773  auto header = rows[aRow];
774  double scale_factor = processScaleFactor( aRow + 1 );
775 
776  if( scale_factor <= 0.0 )
777  return -1;
778 
779  int layer_sort_col = getColFromName( aRow, "LAYERSORT" );
780  int layer_subclass_col = getColFromName( aRow, "LAYERSUBCLASS" );
781  int layer_art_col = getColFromName( aRow, "LAYERARTWORK" );
782  int layer_use_col = getColFromName( aRow, "LAYERUSE" );
783  int layer_cond_col = getColFromName( aRow, "LAYERCONDUCTOR" );
784  int layer_er_col = getColFromName( aRow, "LAYERDIELECTRICCONSTANT" );
785  int layer_rho_col = getColFromName( aRow, "LAYERELECTRICALCONDUCTIVITY" );
786  int layer_mat_col = getColFromName( aRow, "LAYERMATERIAL" );
787 
788  if( layer_sort_col < 0 || layer_subclass_col < 0 || layer_art_col < 0 || layer_use_col < 0
789  || layer_cond_col < 0 || layer_er_col < 0 || layer_rho_col < 0 || layer_mat_col < 0 )
790  return -1;
791 
792  for( ; rownum < rows.size() && rows[rownum].size() > 0 && rows[rownum][0] == "S"; ++rownum )
793  {
794  auto row = rows[rownum];
795 
796  if( row.size() != header.size() )
797  {
798  wxLogError( wxString::Format( _( "Invalid row size in row %zu. "
799  "Expecting %zu elements but found %zu" ), rownum, header.size(), row.size() ) );
800  continue;
801  }
802 
803  auto layer_sort = row[layer_sort_col];
804  auto layer_subclass = row[layer_subclass_col];
805  auto layer_art = row[layer_art_col];
806  auto layer_use = row[layer_use_col];
807  auto layer_cond = row[layer_cond_col];
808  auto layer_er = row[layer_er_col];
809  auto layer_rho = row[layer_rho_col];
810  auto layer_mat = row[layer_mat_col];
811 
812  if( layer_mat == "AIR" )
813  continue;
814 
815  FABMASTER_LAYER layer;
816 
817  if( layer_subclass.empty() )
818  {
819  if( layer_cond != "NO" )
820  layer.name = "In.Cu" + layer_sort;
821  else
822  layer.name = "Dielectric" + layer_sort;
823  }
824 
825  layer.positive = ( layer_art != "NEGATIVE" );
826 
827  layers.emplace( layer.name, layer );
828  }
829 
830  return rownum - aRow;
831 }
832 
833 
839 size_t FABMASTER::processCustomPads( size_t aRow )
840 {
841  size_t rownum = aRow + 2;
842 
843  if( rownum >= rows.size() )
844  return -1;
845 
846  auto header = rows[aRow];
847  double scale_factor = processScaleFactor( aRow + 1 );
848 
849  if( scale_factor <= 0.0 )
850  return -1;
851 
852  int pad_subclass_col = getColFromName( aRow, "SUBCLASS" );
853  int pad_shape_name_col = getColFromName( aRow, "PADSHAPENAME" );
854  int pad_grdata_name_col = getColFromName( aRow, "GRAPHICDATANAME" );
855  int pad_grdata_num_col = getColFromName( aRow, "GRAPHICDATANUMBER" );
856  int pad_record_tag_col = getColFromName( aRow, "RECORDTAG" );
857  int pad_grdata1_col = getColFromName( aRow, "GRAPHICDATA1" );
858  int pad_grdata2_col = getColFromName( aRow, "GRAPHICDATA2" );
859  int pad_grdata3_col = getColFromName( aRow, "GRAPHICDATA3" );
860  int pad_grdata4_col = getColFromName( aRow, "GRAPHICDATA4" );
861  int pad_grdata5_col = getColFromName( aRow, "GRAPHICDATA5" );
862  int pad_grdata6_col = getColFromName( aRow, "GRAPHICDATA6" );
863  int pad_grdata7_col = getColFromName( aRow, "GRAPHICDATA7" );
864  int pad_grdata8_col = getColFromName( aRow, "GRAPHICDATA8" );
865  int pad_grdata9_col = getColFromName( aRow, "GRAPHICDATA9" );
866  int pad_stack_name_col = getColFromName( aRow, "PADSTACKNAME" );
867  int pad_refdes_col = getColFromName( aRow, "REFDES" );
868  int pad_pin_num_col = getColFromName( aRow, "PINNUMBER" );
869 
870  if( pad_subclass_col < 0 || pad_shape_name_col < 0 || pad_grdata1_col < 0 || pad_grdata2_col < 0
871  || pad_grdata3_col < 0 || pad_grdata4_col < 0 || pad_grdata5_col < 0
872  || pad_grdata6_col < 0 || pad_grdata7_col < 0 || pad_grdata8_col < 0
873  || pad_grdata9_col < 0 || pad_stack_name_col < 0 || pad_refdes_col < 0
874  || pad_pin_num_col < 0 )
875  return -1;
876 
877  for( ; rownum < rows.size() && rows[rownum].size() > 0 && rows[rownum][0] == "S"; ++rownum )
878  {
879  auto row = rows[rownum];
880 
881  if( row.size() != header.size() )
882  {
883  wxLogError( wxString::Format( _( "Invalid row size in row %zu. "
884  "Expecting %zu elements but found %zu" ), rownum, header.size(), row.size() ) );
885 
886  continue;
887  }
888 
889  auto pad_layer = row[pad_subclass_col];
890  auto pad_shape_name = row[pad_shape_name_col];
891  auto pad_record_tag = row[pad_record_tag_col];
892 
893  GRAPHIC_DATA gr_data;
894  gr_data.graphic_dataname = row[pad_grdata_name_col];
895  gr_data.graphic_datanum = row[pad_grdata_num_col];
896  gr_data.graphic_data1 = row[pad_grdata1_col];
897  gr_data.graphic_data2 = row[pad_grdata2_col];
898  gr_data.graphic_data3 = row[pad_grdata3_col];
899  gr_data.graphic_data4 = row[pad_grdata4_col];
900  gr_data.graphic_data5 = row[pad_grdata5_col];
901  gr_data.graphic_data6 = row[pad_grdata6_col];
902  gr_data.graphic_data7 = row[pad_grdata7_col];
903  gr_data.graphic_data8 = row[pad_grdata8_col];
904  gr_data.graphic_data9 = row[pad_grdata9_col];
905 
906  auto pad_stack_name = row[pad_stack_name_col];
907  auto pad_refdes = row[pad_refdes_col];
908  auto pad_pin_num = row[pad_pin_num_col];
909 
910  // N.B. We get the FIGSHAPE records as "FIG_SHAPE name". We only want "name"
911  // and we don't process other pad shape records
912  std::string prefix( "FIG_SHAPE " );
913 
914  if( pad_shape_name.length() <= prefix.length()
915  || !std::equal( prefix.begin(), prefix.end(), pad_shape_name.begin() ) )
916  {
917  continue;
918  }
919 
920  // Custom pads are a series of records with the same record ID but incrementing
921  // Sequence numbers.
922  int id = -1;
923  int seq = -1;
924 
925  if( std::sscanf( pad_record_tag.c_str(), "%d %d", &id, &seq ) != 2 )
926  {
927  wxLogError( wxString::Format( _( "Invalid format for id string \"%s\" "
928  "in custom pad row %zu" ),
929  pad_record_tag.c_str(), rownum ) );
930  continue;
931  }
932 
933  auto name = pad_shape_name.substr( prefix.length() );
934  name += "_" + pad_refdes + "_" + pad_pin_num;
935  auto ret = pad_shapes.emplace( name, PAD_SHAPE{} );
936 
937  auto& custom_pad = ret.first->second;
938 
939  // If we were able to insert the pad name, then we need to initialize the
940  // record
941  if( ret.second )
942  {
943  custom_pad.name = name;
944  custom_pad.padstack = pad_stack_name;
945  custom_pad.pinnum = pad_pin_num;
946  custom_pad.refdes = pad_refdes;
947  }
948 
949  // At this point we extract the individual graphical elements for processing the complex pad. The
950  // coordinates are in board origin format, so we'll need to fix the offset later when we assign them
951  // to the modules.
952 
953  auto gr_item = std::unique_ptr<GRAPHIC_ITEM>( processGraphic( gr_data, scale_factor ) );
954 
955  if( gr_item )
956  {
957  gr_item->layer = pad_layer;
958  gr_item->refdes = pad_refdes;
959  gr_item->seq = seq;
960  gr_item->subseq = 0;
961 
963  auto pad_it = custom_pad.elements.emplace( id, graphic_element{} );
964  auto retval = pad_it.first->second.insert( std::move(gr_item ) );
965 
966  if( !retval.second )
967  {
968  wxLogError( wxString::Format( _( "Could not insert graphical item %d into padstack \"%s\"" ),
969  seq, pad_stack_name.c_str() ) );
970  }
971  }
972  else
973  {
974  wxLogError( wxString::Format( _( "Unrecognized pad shape primitive \"%s\" in line %zu." ),
975  gr_data.graphic_dataname, rownum ) );
976  }
977  }
978 
979  return rownum - aRow;
980 }
981 
982 
984 {
985  GRAPHIC_LINE* new_line = new GRAPHIC_LINE ;
986 
987  new_line->shape = GR_SHAPE_LINE;
988  new_line->start_x = KiROUND( readDouble( aData.graphic_data1.c_str() ) * aScale );
989  new_line->start_y = -KiROUND( readDouble( aData.graphic_data2.c_str() ) * aScale );
990  new_line->end_x = KiROUND( readDouble( aData.graphic_data3.c_str() ) * aScale );
991  new_line->end_y = -KiROUND( readDouble( aData.graphic_data4.c_str() ) * aScale );
992  new_line->width = KiROUND( readDouble( aData.graphic_data5.c_str() ) * aScale );
993 
994  return new_line;
995 }
996 
998 {
999  GRAPHIC_ARC* new_arc = new GRAPHIC_ARC ;
1000 
1001  new_arc->shape = GR_SHAPE_ARC;
1002  new_arc->start_x = KiROUND( readDouble( aData.graphic_data1.c_str() ) * aScale );
1003  new_arc->start_y = -KiROUND( readDouble( aData.graphic_data2.c_str() ) * aScale );
1004  new_arc->end_x = KiROUND( readDouble( aData.graphic_data3.c_str() ) * aScale );
1005  new_arc->end_y = -KiROUND( readDouble( aData.graphic_data4.c_str() ) * aScale );
1006  new_arc->center_x = KiROUND( readDouble( aData.graphic_data5.c_str() ) * aScale );
1007  new_arc->center_y = -KiROUND( readDouble( aData.graphic_data6.c_str() ) * aScale );
1008  new_arc->radius = KiROUND( readDouble( aData.graphic_data7.c_str() ) * aScale );
1009  new_arc->width = KiROUND( readDouble( aData.graphic_data8.c_str() ) * aScale );
1010 
1011  new_arc->clockwise = ( aData.graphic_data9 != "COUNTERCLOCKWISE" );
1012 
1013  double startangle = NormalizeAnglePos( RAD2DECIDEG(
1014  atan2( new_arc->start_y - new_arc->center_y,
1015  new_arc->start_x - new_arc->center_x ) ) );
1016  double endangle = NormalizeAnglePos( RAD2DECIDEG(
1017  atan2( new_arc->end_y - new_arc->center_y,
1018  new_arc->end_x - new_arc->center_x ) ) );
1019  double angle;
1020 
1021  VECTOR2I center( new_arc->center_x, new_arc->center_y );
1022  VECTOR2I start( new_arc->start_x, new_arc->start_y );
1023  VECTOR2I mid( new_arc->start_x, new_arc->start_y );
1024  VECTOR2I end( new_arc->end_x, new_arc->end_y );
1025 
1026  angle = endangle - startangle;
1027 
1028  if( new_arc->clockwise && angle < 0.0 )
1029  angle += 3600.0;
1030  if( !new_arc->clockwise && angle > 0.0 )
1031  angle -= 3600.0;
1032 
1033  if( start == end )
1034  angle = -3600.0;
1035 
1036  RotatePoint( mid, center, -angle / 2.0 );
1037 
1038  new_arc->result = SHAPE_ARC( start, mid, end, 0 );
1039 
1040  return new_arc;
1041 }
1042 
1044 {
1045  GRAPHIC_RECTANGLE* new_rect = new GRAPHIC_RECTANGLE;
1046 
1047  new_rect->shape = GR_SHAPE_RECTANGLE;
1048  new_rect->start_x = KiROUND( readDouble( aData.graphic_data1.c_str() ) * aScale );
1049  new_rect->start_y = -KiROUND( readDouble( aData.graphic_data2.c_str() ) * aScale );
1050  new_rect->end_x = KiROUND( readDouble( aData.graphic_data3.c_str() ) * aScale );
1051  new_rect->end_y = -KiROUND( readDouble( aData.graphic_data4.c_str() ) * aScale );
1052  new_rect->fill = aData.graphic_data5 == "1";
1053  new_rect->width = 0;
1054 
1055  return new_rect;
1056 }
1057 
1059 {
1060  GRAPHIC_TEXT* new_text = new GRAPHIC_TEXT;
1061 
1062  new_text->shape = GR_SHAPE_TEXT;
1063  new_text->start_x = KiROUND( readDouble( aData.graphic_data1.c_str() ) * aScale );
1064  new_text->start_y = -KiROUND( readDouble( aData.graphic_data2.c_str() ) * aScale );
1065  new_text->rotation = KiROUND( readDouble( aData.graphic_data3.c_str() ) );
1066  new_text->mirror = ( aData.graphic_data4 == "YES" );
1067 
1068  if( aData.graphic_data5 == "RIGHT" )
1069  new_text->orient = GR_TEXT_HJUSTIFY_RIGHT;
1070  else if( aData.graphic_data5 == "CENTER" )
1071  new_text->orient = GR_TEXT_HJUSTIFY_CENTER;
1072  else
1073  new_text->orient = GR_TEXT_HJUSTIFY_LEFT;
1074 
1075  std::vector<std::string> toks = split( aData.graphic_data6, " \t" );
1076 
1077  if( toks.size() < 8 )
1078  {
1079  // We log the error here but continue in the case of too few tokens
1080  wxLogError( wxString::Format( _( "Invalid token count."
1081  " Expected 8 but found %zu" ), toks.size() ) );
1082  new_text->height = 0;
1083  new_text->width = 0;
1084  new_text->ital = false;
1085  new_text->thickness = 0;
1086  }
1087  else
1088  {
1089  // 0 = size
1090  // 1 = font
1091  new_text->height = KiROUND( readDouble( toks[2].c_str() ) * aScale );
1092  new_text->width = KiROUND( readDouble( toks[3].c_str() ) * aScale );
1093  new_text->ital = readDouble( toks[4].c_str() ) != 0.0;
1094  // 5 = character spacing
1095  // 6 = line spacing
1096  new_text->thickness = KiROUND( readDouble( toks[7].c_str() ) * aScale );
1097  }
1098 
1099  new_text->text = aData.graphic_data7;
1100  return new_text;
1101 }
1102 
1103 
1105 {
1106  GRAPHIC_ITEM* retval = nullptr;
1107 
1108  if( aData.graphic_dataname == "LINE" )
1109  retval = processLine( aData, aScale );
1110  else if( aData.graphic_dataname == "ARC" )
1111  retval = processArc( aData, aScale );
1112  else if( aData.graphic_dataname == "RECTANGLE" )
1113  retval = processRectangle( aData, aScale );
1114  else if( aData.graphic_dataname == "TEXT" )
1115  retval = processText( aData, aScale );
1116 
1117  if( retval && !aData.graphic_data10.empty() )
1118  {
1119  if( aData.graphic_data10 == "CONNECT" )
1120  retval->type = GR_TYPE_CONNECT;
1121  else if( aData.graphic_data10 == "NOTCONNECT" )
1122  retval->type = GR_TYPE_NOTCONNECT;
1123  else if( aData.graphic_data10 == "SHAPE" )
1124  retval->type = GR_TYPE_NOTCONNECT;
1125  else if( aData.graphic_data10 == "VOID" )
1126  retval->type = GR_TYPE_NOTCONNECT;
1127  else if( aData.graphic_data10 == "POLYGON" )
1128  retval->type = GR_TYPE_NOTCONNECT;
1129  else
1130  retval->type = GR_TYPE_NONE;
1131  }
1132 
1133  return retval;
1134 }
1135 
1136 
1142 size_t FABMASTER::processGeometry( size_t aRow )
1143 {
1144  size_t rownum = aRow + 2;
1145 
1146  if( rownum >= rows.size() )
1147  return -1;
1148 
1149  const auto header = rows[aRow];
1150  double scale_factor = processScaleFactor( aRow + 1 );
1151 
1152  if( scale_factor <= 0.0 )
1153  return -1;
1154 
1155  int geo_name_col = getColFromName( aRow, "GRAPHICDATANAME" );
1156  int geo_num_col = getColFromName( aRow, "GRAPHICDATANUMBER" );
1157  int geo_tag_col = getColFromName( aRow, "RECORDTAG" );
1158  int geo_grdata1_col = getColFromName( aRow, "GRAPHICDATA1" );
1159  int geo_grdata2_col = getColFromName( aRow, "GRAPHICDATA2" );
1160  int geo_grdata3_col = getColFromName( aRow, "GRAPHICDATA3" );
1161  int geo_grdata4_col = getColFromName( aRow, "GRAPHICDATA4" );
1162  int geo_grdata5_col = getColFromName( aRow, "GRAPHICDATA5" );
1163  int geo_grdata6_col = getColFromName( aRow, "GRAPHICDATA6" );
1164  int geo_grdata7_col = getColFromName( aRow, "GRAPHICDATA7" );
1165  int geo_grdata8_col = getColFromName( aRow, "GRAPHICDATA8" );
1166  int geo_grdata9_col = getColFromName( aRow, "GRAPHICDATA9" );
1167  int geo_subclass_col = getColFromName( aRow, "SUBCLASS" );
1168  int geo_sym_name_col = getColFromName( aRow, "SYMNAME" );
1169  int geo_refdes_col = getColFromName( aRow, "REFDES" );
1170 
1171  if( geo_name_col < 0 || geo_num_col < 0 || geo_grdata1_col < 0 || geo_grdata2_col < 0
1172  || geo_grdata3_col < 0 || geo_grdata4_col < 0 || geo_grdata5_col < 0
1173  || geo_grdata6_col < 0 || geo_grdata7_col < 0 || geo_grdata8_col < 0
1174  || geo_grdata9_col < 0 || geo_subclass_col < 0 || geo_sym_name_col < 0
1175  || geo_refdes_col < 0 )
1176  return -1;
1177 
1178  for( ; rownum < rows.size() && rows[rownum].size() > 0 && rows[rownum][0] == "S"; ++rownum )
1179  {
1180  auto row = rows[rownum];
1181 
1182  if( row.size() != header.size() )
1183  {
1184  wxLogError( wxString::Format( _( "Invalid row size in row %zu. "
1185  "Expecting %zu elements but found %zu" ), rownum, header.size(), row.size() ) );
1186  continue;
1187  }
1188 
1189  auto geo_tag = row[geo_tag_col];
1190 
1191  GRAPHIC_DATA gr_data;
1192  gr_data.graphic_dataname = row[geo_name_col];
1193  gr_data.graphic_datanum = row[geo_num_col];
1194  gr_data.graphic_data1 = row[geo_grdata1_col];
1195  gr_data.graphic_data2 = row[geo_grdata2_col];
1196  gr_data.graphic_data3 = row[geo_grdata3_col];
1197  gr_data.graphic_data4 = row[geo_grdata4_col];
1198  gr_data.graphic_data5 = row[geo_grdata5_col];
1199  gr_data.graphic_data6 = row[geo_grdata6_col];
1200  gr_data.graphic_data7 = row[geo_grdata7_col];
1201  gr_data.graphic_data8 = row[geo_grdata8_col];
1202  gr_data.graphic_data9 = row[geo_grdata9_col];
1203 
1204  auto geo_refdes = row[geo_refdes_col];
1205 
1206  // Grouped graphics are a series of records with the same record ID but incrementing
1207  // Sequence numbers.
1208  int id = -1;
1209  int seq = -1;
1210  int subseq = 0;
1211 
1212  if( std::sscanf( geo_tag.c_str(), "%d %d %d", &id, &seq, &subseq ) < 2 )
1213  {
1214  wxLogError( wxString::Format( _( "Invalid format for record_tag string \"%s\" "
1215  "in Geometric definition row %zu" ),
1216  geo_tag.c_str(), rownum ) );
1217  continue;
1218  }
1219 
1220  auto gr_item = std::unique_ptr<GRAPHIC_ITEM>( processGraphic( gr_data, scale_factor ) );
1221 
1222  if( !gr_item )
1223  {
1224  wxLogDebug( wxString::Format( _( "Unhandled graphic item '%s' "
1225  "in Geometric definition row %zu" ),
1226  gr_data.graphic_dataname.c_str(), geo_tag.c_str(), rownum ) );
1227  continue;
1228  }
1229 
1230  gr_item->layer = row[geo_subclass_col];
1231  gr_item->seq = seq;
1232  gr_item->subseq = subseq;
1233 
1234  if( geo_refdes.empty() )
1235  {
1236  if( board_graphics.empty() || board_graphics.back().id != id )
1237  {
1238  GEOM_GRAPHIC new_gr;
1239  new_gr.subclass = row[geo_subclass_col];
1240  new_gr.refdes = row[geo_refdes_col];
1241  new_gr.name = row[geo_sym_name_col];
1242  new_gr.id = id;
1243  new_gr.elements = std::make_unique<graphic_element>();
1244  board_graphics.push_back( std::move( new_gr ) );
1245  }
1246 
1247  GEOM_GRAPHIC& graphic = board_graphics.back();
1248  graphic.elements->emplace( std::move( gr_item ) );
1249  }
1250  else
1251  {
1252  auto sym_gr_it = comp_graphics.emplace( geo_refdes,
1253  std::map<int, GEOM_GRAPHIC>{} );
1254  auto map_it = sym_gr_it.first->second.emplace( id, GEOM_GRAPHIC{} );
1255  auto& gr = map_it.first;
1256 
1257  if( map_it.second )
1258  {
1259  gr->second.subclass = row[geo_subclass_col];
1260  gr->second.refdes = row[geo_refdes_col];
1261  gr->second.name = row[geo_sym_name_col];
1262  gr->second.id = id;
1263  gr->second.elements = std::make_unique<graphic_element>();
1264  }
1265 
1266  auto result = gr->second.elements->emplace( std::move( gr_item ) );
1267  }
1268  }
1269 
1270  return rownum - aRow;
1271 }
1272 
1273 
1277 size_t FABMASTER::processVias( size_t aRow )
1278 {
1279  size_t rownum = aRow + 2;
1280 
1281  if( rownum >= rows.size() )
1282  return -1;
1283 
1284  const auto header = rows[aRow];
1285  double scale_factor = processScaleFactor( aRow + 1 );
1286 
1287  if( scale_factor <= 0.0 )
1288  return -1;
1289 
1290  int viax_col = getColFromName( aRow, "VIAX" );
1291  int viay_col = getColFromName( aRow, "VIAY" );
1292  int padstack_name_col = getColFromName( aRow, "PADSTACKNAME" );
1293  int net_name_col = getColFromName( aRow, "NETNAME" );
1294  int test_point_col = getColFromName( aRow, "TESTPOINT" );
1295 
1296  if( viax_col < 0 || viay_col < 0 || padstack_name_col < 0 || net_name_col < 0
1297  || test_point_col < 0 )
1298  return -1;
1299 
1300  for( ; rownum < rows.size() && rows[rownum].size() > 0 && rows[rownum][0] == "S"; ++rownum )
1301  {
1302  auto row = rows[rownum];
1303 
1304  if( row.size() != header.size() )
1305  {
1306  wxLogError( wxString::Format( _( "Invalid row size in row %zu. "
1307  "Expecting %zu elements but found %zu" ), rownum, header.size(), row.size() ) );
1308  continue;
1309  }
1310 
1311  vias.emplace_back( std::make_unique<FM_VIA>() );
1312  auto& via = vias.back();
1313 
1314  via->x = KiROUND( readDouble( row[viax_col] ) * scale_factor );
1315  via->y = -KiROUND( readDouble( row[viay_col] ) * scale_factor );
1316  via->padstack = row[padstack_name_col];
1317  via->net = row[net_name_col];
1318  via->test_point = ( row[test_point_col] == "YES" );
1319  }
1320 
1321  return rownum - aRow;
1322 }
1323 
1324 
1330 size_t FABMASTER::processTraces( size_t aRow )
1331 {
1332  size_t rownum = aRow + 2;
1333 
1334  if( rownum >= rows.size() )
1335  return -1;
1336 
1337  const auto header = rows[aRow];
1338  double scale_factor = processScaleFactor( aRow + 1 );
1339 
1340  if( scale_factor <= 0.0 )
1341  return -1;
1342 
1343  int class_col = getColFromName( aRow, "CLASS" );
1344  int layer_col = getColFromName( aRow, "SUBCLASS" );
1345  int grdata_name_col = getColFromName( aRow, "GRAPHICDATANAME" );
1346  int grdata_num_col = getColFromName( aRow, "GRAPHICDATANUMBER" );
1347  int tag_col = getColFromName( aRow, "RECORDTAG" );
1348  int grdata1_col = getColFromName( aRow, "GRAPHICDATA1" );
1349  int grdata2_col = getColFromName( aRow, "GRAPHICDATA2" );
1350  int grdata3_col = getColFromName( aRow, "GRAPHICDATA3" );
1351  int grdata4_col = getColFromName( aRow, "GRAPHICDATA4" );
1352  int grdata5_col = getColFromName( aRow, "GRAPHICDATA5" );
1353  int grdata6_col = getColFromName( aRow, "GRAPHICDATA6" );
1354  int grdata7_col = getColFromName( aRow, "GRAPHICDATA7" );
1355  int grdata8_col = getColFromName( aRow, "GRAPHICDATA8" );
1356  int grdata9_col = getColFromName( aRow, "GRAPHICDATA9" );
1357  int netname_col = getColFromName( aRow, "NETNAME" );
1358 
1359  if( class_col < 0 || layer_col < 0 || grdata_name_col < 0 || grdata_num_col < 0
1360  || tag_col < 0 || grdata1_col < 0 || grdata2_col < 0 || grdata3_col < 0
1361  || grdata4_col < 0 || grdata5_col < 0 || grdata6_col < 0 || grdata7_col < 0
1362  || grdata8_col < 0 || grdata9_col < 0 || netname_col < 0 )
1363  return -1;
1364 
1365  for( ; rownum < rows.size() && rows[rownum].size() > 0 && rows[rownum][0] == "S"; ++rownum )
1366  {
1367  auto row = rows[rownum];
1368 
1369  if( row.size() != header.size() )
1370  {
1371  wxLogError( wxString::Format( _( "Invalid row size in row %zu. "
1372  "Expecting %zu elements but found %zu" ), rownum, header.size(), row.size() ) );
1373  continue;
1374  }
1375 
1376  GRAPHIC_DATA gr_data;
1377  gr_data.graphic_dataname = row[grdata_name_col];
1378  gr_data.graphic_datanum = row[grdata_num_col];
1379  gr_data.graphic_data1 = row[grdata1_col];
1380  gr_data.graphic_data2 = row[grdata2_col];
1381  gr_data.graphic_data3 = row[grdata3_col];
1382  gr_data.graphic_data4 = row[grdata4_col];
1383  gr_data.graphic_data5 = row[grdata5_col];
1384  gr_data.graphic_data6 = row[grdata6_col];
1385  gr_data.graphic_data7 = row[grdata7_col];
1386  gr_data.graphic_data8 = row[grdata8_col];
1387  gr_data.graphic_data9 = row[grdata9_col];
1388 
1389  auto geo_tag = row[tag_col];
1390  // Grouped graphics are a series of records with the same record ID but incrementing
1391  // Sequence numbers.
1392  int id = -1;
1393  int seq = -1;
1394  int subseq = 0;
1395 
1396  if( std::sscanf( geo_tag.c_str(), "%d %d %d", &id, &seq, &subseq ) < 2 )
1397  {
1398  wxLogError( wxString::Format( _( "Invalid format for record_tag string \"%s\" "
1399  "in Traces definition row %zu" ),
1400  geo_tag.c_str(), rownum ) );
1401  continue;
1402  }
1403 
1404  auto gr_item = std::unique_ptr<GRAPHIC_ITEM>( processGraphic( gr_data, scale_factor ) );
1405 
1406  if( !gr_item )
1407  {
1408  wxLogDebug( wxString::Format( _( "Unhandled graphic item '%s' "
1409  "in Traces definition row %zu" ),
1410  gr_data.graphic_dataname.c_str(), rownum ) );
1411  continue;
1412  }
1413 
1414  auto new_trace = std::make_unique<TRACE>();
1415  new_trace->id = id;
1416  new_trace->layer = row[layer_col];
1417  new_trace->netname = row[netname_col];
1418  new_trace->lclass = row[class_col];
1419 
1420  gr_item->layer = row[layer_col];
1421  gr_item->seq = seq;
1422  gr_item->subseq = subseq;
1423 
1424  // Collect the reference designator positions for the footprints later
1425  if( new_trace->lclass == "REF DES" )
1426  {
1427  auto result = refdes.emplace( std::move( new_trace ) );
1428  auto& ref = *result.first;
1429  ref->segment.emplace( std::move( gr_item ) );
1430  }
1431  else if( gr_item->width == 0 )
1432  {
1433  auto result = zones.emplace( std::move( new_trace ) );
1434  auto& zone = *result.first;
1435  auto gr_result = zone->segment.emplace( std::move( gr_item ) );
1436 
1437  if( !gr_result.second )
1438  {
1439  wxLogError( wxString::Format( _( "Duplicate item for ID %d and sequence %d "
1440  "in Traces definition row %zu \n" ), id, seq, rownum ) );
1441  }
1442 
1443  }
1444  else
1445  {
1446  auto result = traces.emplace( std::move( new_trace ) );
1447  auto& trace = *result.first;
1448  auto gr_result = trace->segment.emplace( std::move( gr_item ) );
1449 
1450  if( !gr_result.second )
1451  {
1452  wxLogError( wxString::Format( _( "Duplicate item for ID %d and sequence %d "
1453  "in Traces definition row %zu \n" ), id, seq, rownum ) );
1454  }
1455  }
1456  }
1457 
1458  return rownum - aRow;
1459 }
1460 
1461 
1462 FABMASTER::SYMTYPE FABMASTER::parseSymType( const std::string& aSymType )
1463 {
1464  if( aSymType == "PACKAGE" )
1465  return SYMTYPE_PACKAGE;
1466  else if( aSymType == "DRAFTING")
1467  return SYMTYPE_DRAFTING;
1468  else if( aSymType == "MECHANICAL" )
1469  return SYMTYPE_MECH;
1470  else if( aSymType == "FORMAT" )
1471  return SYMTYPE_FORMAT;
1472 
1473  return SYMTYPE_NONE;
1474 }
1475 
1476 
1477 FABMASTER::COMPCLASS FABMASTER::parseCompClass( const std::string& aCmpClass )
1478 {
1479  if( aCmpClass == "IO" )
1480  return COMPCLASS_IO;
1481  else if( aCmpClass == "IC" )
1482  return COMPCLASS_IC;
1483  else if( aCmpClass == "DISCRETE" )
1484  return COMPCLASS_DISCRETE;
1485 
1486  return COMPCLASS_NONE;
1487 }
1488 
1493 size_t FABMASTER::processFootprints( size_t aRow )
1494 {
1495  size_t rownum = aRow + 2;
1496 
1497  if( rownum >= rows.size() )
1498  return -1;
1499 
1500  const auto header = rows[aRow];
1501  double scale_factor = processScaleFactor( aRow + 1 );
1502 
1503  if( scale_factor <= 0.0 )
1504  return -1;
1505 
1506  int refdes_col = getColFromName( aRow, "REFDES" );
1507  int compclass_col = getColFromName( aRow, "COMPCLASS" );
1508  int comppartnum_col = getColFromName( aRow, "COMPPARTNUMBER" );
1509  int compheight_col = getColFromName( aRow, "COMPHEIGHT" );
1510  int compdevlabelcol = getColFromName( aRow, "COMPDEVICELABEL" );
1511  int compinscode_col = getColFromName( aRow, "COMPINSERTIONCODE" );
1512  int symtype_col = getColFromName( aRow, "SYMTYPE" );
1513  int symname_col = getColFromName( aRow, "SYMNAME" );
1514  int symmirror_col = getColFromName( aRow, "SYMMIRROR" );
1515  int symrotate_col = getColFromName( aRow, "SYMROTATE" );
1516  int symx_col = getColFromName( aRow, "SYMX" );
1517  int symy_col = getColFromName( aRow, "SYMY" );
1518  int compvalue_col = getColFromName( aRow, "COMPVALUE" );
1519  int comptol_col = getColFromName( aRow, "COMPTOL" );
1520  int compvolt_col = getColFromName( aRow, "COMPVOLTAGE" );
1521 
1522  if( refdes_col < 0 || compclass_col < 0 || comppartnum_col < 0 || compheight_col < 0
1523  || compdevlabelcol < 0 || compinscode_col < 0 || symtype_col < 0 || symname_col < 0
1524  || symmirror_col < 0 || symrotate_col < 0 || symx_col < 0 || symy_col < 0
1525  || compvalue_col < 0 || comptol_col < 0 || compvolt_col < 0 )
1526  return -1;
1527 
1528  for( ; rownum < rows.size() && rows[rownum].size() > 0 && rows[rownum][0] == "S"; ++rownum )
1529  {
1530  auto row = rows[rownum];
1531 
1532  if( row.size() != header.size() )
1533  {
1534  wxLogError( wxString::Format( _( "Invalid row size in row %zu. "
1535  "Expecting %zu elements but found %zu" ), rownum, header.size(), row.size() ) );
1536  continue;
1537  }
1538 
1539  auto cmp = std::make_unique<COMPONENT>();
1540 
1541  cmp->refdes = row[refdes_col];
1542  cmp->cclass = parseCompClass( row[compclass_col] );
1543  cmp->pn = row[comppartnum_col];
1544  cmp->height = row[compheight_col];
1545  cmp->dev_label = row[compdevlabelcol];
1546  cmp->insert_code = row[compinscode_col];
1547  cmp->type = parseSymType( row[symtype_col] );
1548  cmp->name = row[symname_col];
1549  cmp->mirror = ( row[symmirror_col] == "YES" );
1550  cmp->rotate = readDouble( row[symrotate_col] );
1551  cmp->x = KiROUND( readDouble( row[symx_col] ) * scale_factor );
1552  cmp->y = -KiROUND( readDouble( row[symy_col] ) * scale_factor );
1553  cmp->value = row[compvalue_col];
1554  cmp->tol = row[comptol_col];
1555  cmp->voltage = row[compvolt_col];
1556 
1557  auto vec = components.find( cmp->refdes );
1558 
1559  if( vec == components.end() )
1560  {
1561  auto retval = components.insert( std::make_pair( cmp->refdes, std::vector<std::unique_ptr<COMPONENT>>{} ) );
1562 
1563  vec = retval.first;
1564  }
1565 
1566  vec->second.push_back( std::move( cmp ) );
1567  }
1568 
1569  return rownum - aRow;
1570 }
1571 
1572 
1576 size_t FABMASTER::processPins( size_t aRow )
1577 {
1578  size_t rownum = aRow + 2;
1579 
1580  if( rownum >= rows.size() )
1581  return -1;
1582 
1583  const auto header = rows[aRow];
1584  double scale_factor = processScaleFactor( aRow + 1 );
1585 
1586  if( scale_factor <= 0.0 )
1587  return -1;
1588 
1589  int symname_col = getColFromName( aRow, "SYMNAME" );
1590  int symmirror_col = getColFromName( aRow, "SYMMIRROR" );
1591  int pinname_col = getColFromName( aRow, "PINNAME" );
1592  int pinnum_col = getColFromName( aRow, "PINNUMBER" );
1593  int pinx_col = getColFromName( aRow, "PINX" );
1594  int piny_col = getColFromName( aRow, "PINY" );
1595  int padstack_col = getColFromName( aRow, "PADSTACKNAME" );
1596  int refdes_col = getColFromName( aRow, "REFDES" );
1597  int pinrot_col = getColFromName( aRow, "PINROTATION" );
1598  int testpoint_col = getColFromName( aRow, "TESTPOINT" );
1599 
1600  if( symname_col < 0 ||symmirror_col < 0 || pinname_col < 0 || pinnum_col < 0 || pinx_col < 0
1601  || piny_col < 0 || padstack_col < 0 || refdes_col < 0 || pinrot_col < 0
1602  || testpoint_col < 0 )
1603  return -1;
1604 
1605  for( ; rownum < rows.size() && rows[rownum].size() > 0 && rows[rownum][0] == "S"; ++rownum )
1606  {
1607  auto row = rows[rownum];
1608 
1609  if( row.size() != header.size() )
1610  {
1611  wxLogError( wxString::Format( _( "Invalid row size in row %zu. "
1612  "Expecting %zu elements but found %zu" ), rownum, header.size(), row.size() ) );
1613  continue;
1614  }
1615 
1616  auto pin = std::make_unique<PIN>();
1617 
1618  pin->name = row[symname_col];
1619  pin->mirror = ( row[symmirror_col] == "YES" );
1620  pin->pin_name = row[pinname_col];
1621  pin->pin_number = row[pinnum_col];
1622  pin->pin_x = KiROUND( readDouble( row[pinx_col] ) * scale_factor );
1623  pin->pin_y = -KiROUND( readDouble( row[piny_col] ) * scale_factor );
1624  pin->padstack = row[padstack_col];
1625  pin->refdes = row[refdes_col];
1626  pin->rotation = readDouble( row[pinrot_col] );
1627 
1628  auto map_it = pins.find( pin->refdes );
1629 
1630  if( map_it == pins.end() )
1631  {
1632  auto retval = pins.insert( std::make_pair( pin->refdes, std::set<std::unique_ptr<PIN>, PIN::BY_NUM>{} ) );
1633  map_it = retval.first;
1634  }
1635 
1636  map_it->second.insert( std::move( pin ) );
1637  }
1638 
1639  return rownum - aRow;
1640 }
1641 
1642 
1646 size_t FABMASTER::processNets( size_t aRow )
1647 {
1648  size_t rownum = aRow + 2;
1649 
1650  if( rownum >= rows.size() )
1651  return -1;
1652 
1653  const auto header = rows[aRow];
1654  double scale_factor = processScaleFactor( aRow + 1 );
1655 
1656  if( scale_factor <= 0.0 )
1657  return -1;
1658 
1659  int netname_col = getColFromName( aRow, "NETNAME" );
1660  int refdes_col = getColFromName( aRow, "REFDES" );
1661  int pinnum_col = getColFromName( aRow, "PINNUMBER" );
1662  int pinname_col = getColFromName( aRow, "PINNAME" );
1663  int pingnd_col = getColFromName( aRow, "PINGROUND" );
1664  int pinpwr_col = getColFromName( aRow, "PINPOWER" );
1665 
1666  if( netname_col < 0 || refdes_col < 0 || pinnum_col < 0 || pinname_col < 0 || pingnd_col < 0
1667  || pinpwr_col < 0 )
1668  return -1;
1669 
1670  for( ; rownum < rows.size() && rows[rownum].size() > 0 && rows[rownum][0] == "S"; ++rownum )
1671  {
1672  auto row = rows[rownum];
1673 
1674  if( row.size() != header.size() )
1675  {
1676  wxLogError( wxString::Format( _( "Invalid row size in row %zu. "
1677  "Expecting %zu elements but found %zu" ), rownum, header.size(), row.size() ) );
1678  continue;
1679  }
1680 
1681  NETNAME new_net;
1682  new_net.name = row[netname_col];
1683  new_net.refdes = row[refdes_col];
1684  new_net.pin_num = row[pinnum_col];
1685  new_net.pin_name = row[pinname_col];
1686  new_net.pin_gnd = ( row[pingnd_col] == "YES" );
1687  new_net.pin_pwr = ( row[pinpwr_col] == "YES" );
1688 
1689  pin_nets.emplace( std::make_pair( new_net.refdes, new_net.pin_num ), new_net );
1690  netnames.insert( row[netname_col] );
1691  }
1692 
1693  return rownum - aRow;
1694 }
1695 
1696 
1698 {
1699 
1700  for( size_t i = 0; i < rows.size(); )
1701  {
1702  auto type = detectType( i );
1703 
1704  switch( type )
1705  {
1706  case EXTRACT_PADSTACKS:
1707  {
1710  processPadStackLayers( i );
1711  assignLayers();
1712  int retval = processPadStacks( i );
1713 
1714  i += std::max( retval, 1 );
1715  break;
1716  }
1717 
1718  case EXTRACT_FULL_LAYERS:
1719  {
1720  int retval = processLayers( i );
1721 
1722  i += std::max( retval, 1 );
1723  break;
1724  }
1725 
1726  case EXTRACT_BASIC_LAYERS:
1727  {
1728  int retval = processSimpleLayers( i );
1729 
1730  i += std::max( retval, 1 );
1731  break;
1732  }
1733 
1734  case EXTRACT_VIAS:
1735  {
1736  int retval = processVias( i );
1737 
1738  i += std::max( retval, 1 );
1739  break;
1740  }
1741 
1742  case EXTRACT_TRACES:
1743  {
1744  int retval = processTraces( i );
1745 
1746  i += std::max( retval, 1 );
1747  break;
1748  }
1749 
1750  case EXTRACT_REFDES:
1751  {
1752  int retval = processFootprints( i );
1753 
1754  i += std::max( retval, 1 );
1755  break;
1756  }
1757 
1758  case EXTRACT_NETS:
1759  {
1760  int retval = processNets( i );
1761 
1762  i += std::max( retval, 1 );
1763  break;
1764  }
1765 
1766  case EXTRACT_GRAPHICS:
1767  {
1768  int retval = processGeometry( i );
1769 
1770  i += std::max( retval, 1 );
1771  break;
1772  }
1773 
1774  case EXTRACT_PINS:
1775  {
1776  int retval = processPins( i );
1777 
1778  i += std::max( retval, 1 );
1779  break;
1780  }
1781 
1782  case EXTRACT_PAD_SHAPES:
1783  {
1784  int retval = processCustomPads( i );
1785 
1786  i += std::max( retval, 1 );
1787  break;
1788  }
1789 
1790  default:
1791  ++i;
1792  break;
1793  }
1794 
1795  }
1796 
1797  return true;
1798 }
1799 
1800 
1802 {
1803 
1804  for( auto& zone : zones )
1805  {
1806  if( IsCopperLayer( getLayer( zone->layer ) ) || zone->layer == "ALL" )
1807  loadZone( aBoard, zone );
1808  else
1809  {
1810  if( zone->layer == "OUTLINE" || zone->layer == "DESIGN_OUTLINE" )
1811  {
1812  loadOutline( aBoard, zone );
1813  }
1814  else
1815  {
1816  loadPolygon( aBoard, zone );
1817  }
1818  }
1819  }
1820 
1831  std::set<ZONE*> zones_to_delete;
1832 
1833  for( auto zone : aBoard->Zones() )
1834  {
1836  if( zone->GetNetCode() > 0 )
1837  {
1838  zones_to_delete.insert( zone );
1839  }
1840  }
1841 
1842  for( auto zone1 : aBoard->Zones() )
1843  {
1845  if( zone1->GetNetCode() > 0 )
1846  continue;
1847 
1848  SHAPE_LINE_CHAIN& outline1 = zone1->Outline()->Outline( 0 );
1849  std::vector<size_t> overlaps( aBoard->GetNetInfo().GetNetCount() + 1, 0 );
1850  std::vector<std::vector<ZONE*>> possible_deletions( overlaps.size() );
1851 
1852  for( auto zone2 : aBoard->Zones() )
1853  {
1854  if( zone2->GetNetCode() <= 0 )
1855  continue;
1856 
1857  SHAPE_LINE_CHAIN& outline2 = zone2->Outline()->Outline( 0 );
1858 
1859  if( zone1->GetLayer() != zone2->GetLayer() )
1860  continue;
1861 
1862  if( !outline1.BBox().Intersects( outline2.BBox() ) )
1863  continue;
1864 
1865  for( auto& pt1 : outline1.CPoints() )
1866  {
1868  if( outline2.PointOnEdge( pt1, 1 ) )
1869  overlaps[ zone2->GetNetCode() ]++;
1870  }
1871 
1872  for( auto& pt2 : outline2.CPoints() )
1873  {
1876  if( outline1.PointOnEdge( pt2, 1 ) )
1877  overlaps[ zone2->GetNetCode() ]++;
1878  }
1879  }
1880 
1881  size_t max_net = 0;
1882  size_t max_net_id = 0;
1883 
1884  for( size_t el = 1; el < overlaps.size(); ++el )
1885  {
1886  if( overlaps[el] > max_net )
1887  {
1888  max_net = overlaps[el];
1889  max_net_id = el;
1890  }
1891  }
1892 
1893  if( max_net > 0 )
1894  zone1->SetNetCode( max_net_id );
1895  }
1896 
1897  for( auto zone : zones_to_delete )
1898  {
1899  aBoard->Remove( zone );
1900  free(zone);
1901  }
1902 
1903  return true;
1904 }
1905 
1906 
1908 {
1909  const NETNAMES_MAP& netinfo = aBoard->GetNetInfo().NetsByName();
1910  const auto& ds = aBoard->GetDesignSettings();
1911 
1912  for( auto& mod : components )
1913  {
1914  bool has_multiple = mod.second.size() > 1;
1915 
1916  for( int i = 0; i < mod.second.size(); ++i )
1917  {
1918  auto& src = mod.second[i];
1919 
1920  FOOTPRINT* fp = new FOOTPRINT( aBoard );
1921 
1922  wxString mod_ref = src->name;
1923  wxString lib_ref = m_filename.GetName();
1924 
1925  if( has_multiple )
1926  mod_ref.Append( wxString::Format( "_%d", i ) );
1927 
1928  ReplaceIllegalFileNameChars( lib_ref, '_' );
1929  ReplaceIllegalFileNameChars( mod_ref, '_' );
1930 
1931  wxString key = !lib_ref.empty() ? lib_ref + ":" + mod_ref : mod_ref;
1932 
1933  LIB_ID fpID;
1934  fpID.Parse( key, true );
1935  fp->SetFPID( fpID );
1936 
1937  fp->SetPosition( wxPoint( src->x, src->y ) );
1938  fp->SetOrientationDegrees( -src->rotate );
1939 
1940  // KiCad netlisting requires parts to have non-digit + digit annotation.
1941  // If the reference begins with a number, we prepend 'UNK' (unknown) for the source designator
1942  wxString reference = src->refdes;
1943 
1944  if( !std::isalpha( src->refdes[0] ) )
1945  reference.Prepend( "UNK" );
1946 
1947  fp->SetReference( reference );
1948 
1949  fp->SetValue( src->value );
1950  fp->Value().SetLayer( F_Fab );
1951  fp->Value().SetVisible( false );
1952 
1953  for( auto& ref : refdes )
1954  {
1955  const GRAPHIC_TEXT *lsrc =
1956  static_cast<const GRAPHIC_TEXT*>( ( *( ref->segment.begin() ) ).get() );
1957 
1958  if( lsrc->text == src->refdes )
1959  {
1960  FP_TEXT* txt = nullptr;
1961  PCB_LAYER_ID layer = getLayer( ref->layer );
1962 
1963  if( !IsPcbLayer( layer ) )
1964  {
1965  printf("The layer %s is not mapped?\n", ref->layer.c_str() );
1966  continue;
1967  }
1968 
1969  if( layer == F_SilkS || layer == B_SilkS )
1970  txt = &( fp->Reference() );
1971  else
1972  txt = new FP_TEXT( fp );
1973 
1974  if( src->mirror )
1975  {
1976  txt->SetLayer( FlipLayer( layer ) );
1977  txt->SetTextPos( wxPoint( lsrc->start_x, 2 * src->y - ( lsrc->start_y - lsrc->height / 2 ) ) );
1978  }
1979  else
1980  {
1981  txt->SetLayer( layer );
1982  txt->SetTextPos( wxPoint( lsrc->start_x, lsrc->start_y - lsrc->height / 2 ) );
1983  }
1984 
1985  txt->SetText( lsrc->text );
1986  txt->SetItalic( lsrc->ital );
1987  txt->SetTextThickness( lsrc->thickness );
1988  txt->SetTextHeight( lsrc->height );
1989  txt->SetTextWidth( lsrc->width );
1990  txt->SetHorizJustify( lsrc->orient );
1991  txt->SetLocalCoord();
1992 
1993  if( txt != &fp->Reference() )
1994  fp->Add( txt, ADD_MODE::APPEND );
1995  }
1996  }
1997 
2000  fp->SetLayer( F_Cu );
2001 
2002  auto gr_it = comp_graphics.find( src->refdes );
2003 
2004  if( gr_it == comp_graphics.end() )
2005  {
2006  continue;
2007  //TODO: Error
2008  }
2009 
2010  for( auto& gr_ref : gr_it->second )
2011  {
2012  auto& graphic = gr_ref.second;
2013 
2014  for( auto& seg : *graphic.elements )
2015  {
2016  PCB_LAYER_ID layer = Dwgs_User;
2017 
2018  if( IsPcbLayer( getLayer( seg->layer ) ) )
2019  layer = getLayer( seg->layer );
2020 
2021  switch( seg->shape )
2022  {
2023 
2024  case GR_SHAPE_LINE:
2025  {
2026  const GRAPHIC_LINE* lsrc = static_cast<const GRAPHIC_LINE*>( seg.get() );
2027 
2028  FP_SHAPE* line = new FP_SHAPE( fp, S_SEGMENT );
2029 
2030  if( src->mirror )
2031  {
2032  line->SetLayer( FlipLayer( layer ) );
2033  line->SetStart( wxPoint( lsrc->start_x, 2 * src->y - lsrc->start_y ) );
2034  line->SetEnd( wxPoint( lsrc->end_x, 2 * src->y - lsrc->end_y ) );
2035  }
2036  else
2037  {
2038  line->SetLayer( layer );
2039  line->SetStart( wxPoint( lsrc->start_x, lsrc->start_y ) );
2040  line->SetEnd( wxPoint( lsrc->end_x, lsrc->end_y ) );
2041  }
2042 
2043  line->SetWidth( lsrc->width );
2044  line->SetLocalCoord();
2045 
2046  if( lsrc->width == 0 )
2047  line->SetWidth( ds.GetLineThickness( line->GetLayer() ) );
2048 
2049  fp->Add( line, ADD_MODE::APPEND );
2050  break;
2051  }
2052  case GR_SHAPE_ARC:
2053  {
2054  const GRAPHIC_ARC* lsrc = static_cast<const GRAPHIC_ARC*>( seg.get() );
2055 
2056  FP_SHAPE* arc = new FP_SHAPE( fp, S_ARC );
2057 
2058  if( src->mirror )
2059  {
2060  arc->SetLayer( FlipLayer( layer ) );
2061  arc->SetCenter( wxPoint( lsrc->center_x, 2 * src->y - lsrc->center_y ) );
2062  arc->SetArcStart( wxPoint( lsrc->end_x, 2 * src->y - lsrc->end_y ) );
2063  arc->SetAngle( lsrc->result.GetCentralAngle() * 10.0 );
2064  }
2065  else
2066  {
2067  arc->SetLayer( layer );
2068  arc->SetCenter( wxPoint( lsrc->center_x, lsrc->center_y ) );
2069  arc->SetArcStart( wxPoint( lsrc->end_x, lsrc->end_y ) );
2070  arc->SetAngle( -lsrc->result.GetCentralAngle() * 10.0 );
2071  }
2072 
2073  arc->SetWidth( lsrc->width );
2074  arc->SetLocalCoord();
2075 
2076  if( lsrc->width == 0 )
2077  arc->SetWidth( ds.GetLineThickness( arc->GetLayer() ) );
2078 
2079  fp->Add( arc, ADD_MODE::APPEND );
2080  break;
2081  }
2082  case GR_SHAPE_RECTANGLE:
2083  {
2084  const GRAPHIC_RECTANGLE *lsrc =
2085  static_cast<const GRAPHIC_RECTANGLE*>( seg.get() );
2086 
2087  FP_SHAPE* rect = new FP_SHAPE( fp, S_RECT );
2088 
2089  if( src->mirror )
2090  {
2091  rect->SetLayer( FlipLayer( layer ) );
2092  rect->SetStart( wxPoint( lsrc->start_x, 2 * src->y - lsrc->start_y ) );
2093  rect->SetEnd( wxPoint( lsrc->end_x, 2 * src->y - lsrc->end_y ) );
2094  }
2095  else
2096  {
2097  rect->SetLayer( layer );
2098  rect->SetStart( wxPoint( lsrc->start_x, lsrc->start_y ) );
2099  rect->SetEnd( wxPoint( lsrc->end_x, lsrc->end_y ) );
2100  }
2101 
2102  rect->SetWidth( ds.GetLineThickness( rect->GetLayer() ) );
2103  rect->SetLocalCoord();
2104 
2105  fp->Add( rect, ADD_MODE::APPEND );
2106  break;
2107  }
2108  case GR_SHAPE_TEXT:
2109  {
2110  const GRAPHIC_TEXT *lsrc =
2111  static_cast<const GRAPHIC_TEXT*>( seg.get() );
2112 
2113  FP_TEXT* txt = new FP_TEXT( fp );
2114 
2115  if( src->mirror )
2116  {
2117  txt->SetLayer( FlipLayer( layer ) );
2118  txt->SetTextPos( wxPoint( lsrc->start_x, 2 * src->y - ( lsrc->start_y - lsrc->height / 2 ) ) );
2119  }
2120  else
2121  {
2122  txt->SetLayer( layer );
2123  txt->SetTextPos( wxPoint( lsrc->start_x, lsrc->start_y - lsrc->height / 2 ) );
2124  }
2125 
2126  txt->SetText( lsrc->text );
2127  txt->SetItalic( lsrc->ital );
2128  txt->SetTextThickness( lsrc->thickness );
2129  txt->SetTextHeight( lsrc->height );
2130  txt->SetTextWidth( lsrc->width );
2131  txt->SetHorizJustify( lsrc->orient );
2132  txt->SetLocalCoord();
2133 
2134  // FABMASTER doesn't have visibility flags but layers that are not silk should be hidden
2135  // by default to prevent clutter.
2136  if( txt->GetLayer() != F_SilkS && txt->GetLayer() != B_SilkS )
2137  txt->SetVisible( false );
2138 
2139  fp->Add( txt, ADD_MODE::APPEND );
2140  break;
2141  }
2142  default:
2143  continue;
2144  }
2145  }
2146  }
2147 
2148  auto pin_it = pins.find( src->refdes );
2149 
2150  if( pin_it != pins.end() )
2151  {
2152  for( auto& pin : pin_it->second )
2153  {
2154  auto pin_net_it = pin_nets.find( std::make_pair( pin->refdes, pin->pin_number ) );
2155  auto padstack = pads.find( pin->padstack );
2156  std::string netname = "";
2157 
2158  if( pin_net_it != pin_nets.end() )
2159  netname = pin_net_it->second.name;
2160 
2161  auto net_it = netinfo.find( netname );
2162 
2163  PAD* newpad = new PAD( fp );
2164 
2165  if( net_it != netinfo.end() )
2166  newpad->SetNet( net_it->second );
2167  else
2168  newpad->SetNetCode( 0 );
2169 
2170  newpad->SetX( pin->pin_x );
2171 
2172  if( src->mirror )
2173  newpad->SetY( 2 * src->y - pin->pin_y );
2174  else
2175  newpad->SetY( pin->pin_y );
2176 
2177  newpad->SetName( pin->pin_number );
2178 
2179  if( padstack == pads.end() )
2180  {
2182  free( newpad );
2183  continue;
2184  }
2185  else
2186  {
2187  auto& pad = padstack->second;
2188 
2189  newpad->SetShape( pad.shape );
2190 
2191  if( pad.shape == PAD_SHAPE_CUSTOM )
2192  {
2193  // Choose the smaller dimension to ensure the base pad
2194  // is fully hidden by the custom pad
2195  int pad_size = std::min( pad.width, pad.height );
2196 
2197  newpad->SetSize( wxSize( pad_size / 2, pad_size / 2 ) );
2198 
2199  std::string custom_name = pad.custom_name + "_" + pin->refdes + "_" + pin->pin_number;
2200  auto custom_it = pad_shapes.find( custom_name );
2201 
2202  if( custom_it != pad_shapes.end() )
2203  {
2204 
2205  SHAPE_POLY_SET poly_outline;
2206  int last_subseq = 0;
2207  int hole_idx = -1;
2208 
2209  poly_outline.NewOutline();
2210 
2211  // Custom pad shapes have a group of elements
2212  // that are a list of graphical polygons
2213  for( const auto& el : (*custom_it).second.elements )
2214  {
2215  // For now, we are only processing the custom pad for the top layer
2216  // TODO: Use full padstacks when implementing in KiCad
2217  PCB_LAYER_ID primary_layer = src->mirror ? B_Cu : F_Cu;
2218 
2219  if( getLayer( ( *( el.second.begin() ) )->layer ) != primary_layer )
2220  continue;
2221 
2222  for( const auto& seg : el.second )
2223  {
2224  if( seg->subseq > 0 || seg->subseq != last_subseq )
2225  {
2226  poly_outline.Polygon(0).back().SetClosed( true );
2227  hole_idx = poly_outline.AddHole( SHAPE_LINE_CHAIN{} );
2228  }
2229 
2230  if( seg->shape == GR_SHAPE_LINE )
2231  {
2232  const GRAPHIC_LINE* src = static_cast<const GRAPHIC_LINE*>( seg.get() );
2233 
2234  if( poly_outline.VertexCount( 0, hole_idx ) == 0 )
2235  poly_outline.Append( src->start_x, src->start_y, 0, hole_idx );
2236 
2237  poly_outline.Append( src->end_x, src->end_y, 0, hole_idx );
2238  }
2239  else if( seg->shape == GR_SHAPE_ARC )
2240  {
2241  const GRAPHIC_ARC* src = static_cast<const GRAPHIC_ARC*>( seg.get() );
2242  SHAPE_LINE_CHAIN& chain = poly_outline.Hole( 0, hole_idx );
2243 
2244  chain.Append( src->result );
2245  }
2246  }
2247  }
2248 
2249  if( poly_outline.OutlineCount() < 1
2250  || poly_outline.Outline( 0 ).PointCount() < 3 )
2251  {
2252  wxLogError( wxString::Format(
2253  _( "Invalid custom pad named '%s'. Replacing with circular pad." ),
2254  custom_name.c_str() ) );
2255  newpad->SetShape( PAD_SHAPE_CIRCLE );
2256  }
2257  else
2258  {
2259  poly_outline.Fracture( SHAPE_POLY_SET::POLYGON_MODE::PM_FAST );
2260 
2261  poly_outline.Move( -newpad->GetPosition() );
2262 
2263  if( src->mirror )
2264  {
2265  poly_outline.Mirror( false, true, VECTOR2I( 0, ( pin->pin_y - src->y ) ) );
2266  poly_outline.Rotate( ( -src->rotate + pin->rotation ) * M_PI / 180.0 );
2267  }
2268  else
2269  {
2270  poly_outline.Rotate( ( src->rotate - pin->rotation ) * M_PI / 180.0 );
2271  }
2272 
2273  newpad->AddPrimitivePoly( poly_outline, 0, true );
2274  }
2275 
2276  SHAPE_POLY_SET mergedPolygon;
2277  newpad->MergePrimitivesAsPolygon( &mergedPolygon, UNDEFINED_LAYER );
2278 
2279  if( mergedPolygon.OutlineCount() > 1 )
2280  {
2281  wxLogError( wxString::Format(
2282  _( "Invalid custom pad named '%s'. Replacing with circular pad." ),
2283  custom_name.c_str() ) );
2284  newpad->SetShape( PAD_SHAPE_CIRCLE );
2285  }
2286  }
2287  else
2288  {
2289  wxLogError( wxString::Format( _( "Could not find custom pad named %s" ),
2290  custom_name.c_str() ) );
2291  }
2292  }
2293  else
2294  newpad->SetSize( wxSize( pad.width, pad.height ) );
2295 
2296  if( pad.drill )
2297  {
2298  if( pad.plated )
2299  {
2301  newpad->SetLayerSet( PAD::PTHMask() );
2302  }
2303  else
2304  {
2306  newpad->SetLayerSet( PAD::UnplatedHoleMask() );
2307  }
2308 
2309  if( pad.drill_size_x == pad.drill_size_y )
2311  else
2313 
2314  newpad->SetDrillSize( wxSize( pad.drill_size_x, pad.drill_size_y ) );
2315  }
2316  else
2317  {
2319 
2320  if( pad.top )
2321  newpad->SetLayerSet( PAD::SMDMask() );
2322  else if( pad.bottom )
2323  newpad->SetLayerSet( FlipLayerMask( PAD::SMDMask() ) );
2324  }
2325  }
2326 
2327  newpad->SetLocalCoord();
2328 
2329  if( src->mirror )
2330  newpad->SetOrientation( ( -src->rotate + pin->rotation ) * 10.0 );
2331  else
2332  newpad->SetOrientation( ( src->rotate - pin->rotation ) * 10.0 );
2333 
2334  fp->Add( newpad, ADD_MODE::APPEND );
2335  }
2336  }
2337 
2338  if( src->mirror )
2339  {
2340  fp->SetOrientationDegrees( 180.0 - src->rotate );
2341  fp->Flip( fp->GetPosition(), true );
2342  }
2343 
2344  aBoard->Add( fp, ADD_MODE::APPEND );
2345  }
2346  }
2347 
2348  return true;
2349 }
2350 
2351 
2353 {
2354  LSET layer_set;
2355 
2357  layer_set |= LSET::AllTechMask() | LSET::UserMask();
2358 
2359  for( auto& layer : layers )
2360  {
2361  if( layer.second.layerid >= PCBNEW_LAYER_ID_START )
2362  layer_set.set( layer.second.layerid );
2363  }
2364 
2365  aBoard->SetEnabledLayers( layer_set );
2366 
2367  for( auto& layer : layers )
2368  {
2369  if( layer.second.conductive )
2370  {
2371  aBoard->SetLayerName( static_cast<PCB_LAYER_ID>( layer.second.layerid ),
2372  layer.second.name );
2373  }
2374  }
2375 
2376  return true;
2377 }
2378 
2379 
2381 {
2382  const NETNAMES_MAP& netinfo = aBoard->GetNetInfo().NetsByName();
2383  const auto& ds = aBoard->GetDesignSettings();
2384 
2385  for( auto& via : vias )
2386  {
2387  auto net_it = netinfo.find( via->net );
2388  auto padstack = pads.find( via->padstack );
2389 
2390  VIA* new_via = new VIA( aBoard );
2391 
2392  new_via->SetPosition( wxPoint( via->x, via->y ) );
2393 
2394  if( net_it != netinfo.end() )
2395  new_via->SetNet( net_it->second );
2396 
2397  if( padstack == pads.end() )
2398  {
2399  new_via->SetDrillDefault();
2400 
2401  if( !ds.m_ViasDimensionsList.empty() )
2402  {
2403  new_via->SetWidth( ds.m_ViasDimensionsList[0].m_Diameter );
2404  new_via->SetDrill( ds.m_ViasDimensionsList[0].m_Drill );
2405  }
2406  else
2407  {
2408  new_via->SetDrillDefault();
2409  new_via->SetWidth( ds.m_ViasMinSize );
2410  }
2411  }
2412  else
2413  {
2414  new_via->SetDrill( padstack->second.drill_size_x );
2415  new_via->SetWidth( padstack->second.width );
2416  }
2417 
2418  aBoard->Add( new_via, ADD_MODE::APPEND );
2419  }
2420 
2421  return true;
2422 }
2423 
2424 
2426 {
2427  for( auto& net : netnames )
2428  {
2429  NETINFO_ITEM *newnet = new NETINFO_ITEM( aBoard, net );
2430  aBoard->Add( newnet, ADD_MODE::APPEND );
2431  }
2432 
2433  return true;
2434 }
2435 
2436 
2437 bool FABMASTER::loadEtch( BOARD* aBoard, const std::unique_ptr<FABMASTER::TRACE>& aLine)
2438 {
2439  const NETNAMES_MAP& netinfo = aBoard->GetNetInfo().NetsByName();
2440  auto net_it = netinfo.find( aLine->netname );
2441 
2442  int last_subseq = 0;
2443  ZONE* new_zone = nullptr;
2444 
2445  for( const auto& seg : aLine->segment )
2446  {
2447  PCB_LAYER_ID layer = getLayer( seg->layer );
2448 
2449  if( IsCopperLayer( layer ) )
2450  {
2451  if( seg->shape == GR_SHAPE_LINE )
2452  {
2453  const GRAPHIC_LINE* src = static_cast<const GRAPHIC_LINE*>( seg.get() );
2454 
2455  TRACK* trk = new TRACK( aBoard );
2456 
2457  trk->SetLayer( layer );
2458  trk->SetStart( wxPoint( src->start_x, src->start_y ) );
2459  trk->SetEnd( wxPoint( src->end_x, src->end_y ) );
2460  trk->SetWidth( src->width );
2461 
2462  if( net_it != netinfo.end() )
2463  trk->SetNet( net_it->second );
2464 
2465  aBoard->Add( trk, ADD_MODE::APPEND );
2466  }
2467  else if( seg->shape == GR_SHAPE_ARC )
2468  {
2469  const GRAPHIC_ARC* src = static_cast<const GRAPHIC_ARC*>( seg.get() );
2470 
2471  ARC* trk = new ARC( aBoard, &src->result );
2472  trk->SetLayer( layer );
2473  trk->SetWidth( src->width );
2474 
2475  if( net_it != netinfo.end() )
2476  trk->SetNet( net_it->second );
2477 
2478  aBoard->Add( trk, ADD_MODE::APPEND );
2479  }
2480  }
2481  else
2482  {
2483  wxLogError( wxString::Format( _( "Expecting etch data to be on copper layer. "
2484  "Row found on layer '%s'" ), seg->layer.c_str() ) );
2485  }
2486  }
2487 
2488  return true;
2489 }
2490 
2491 
2493 {
2494  SHAPE_POLY_SET poly_outline;
2495  int last_subseq = 0;
2496  int hole_idx = -1;
2497 
2498  poly_outline.NewOutline();
2499 
2500  for( const auto& seg : aElement )
2501  {
2502  if( seg->subseq > 0 || seg->subseq != last_subseq )
2503  hole_idx = poly_outline.AddHole( SHAPE_LINE_CHAIN{} );
2504 
2505  if( seg->shape == GR_SHAPE_LINE )
2506  {
2507  const GRAPHIC_LINE* src = static_cast<const GRAPHIC_LINE*>( seg.get() );
2508 
2509  if( poly_outline.VertexCount( 0, hole_idx ) == 0 )
2510  poly_outline.Append( src->start_x, src->start_y, 0, hole_idx );
2511 
2512  poly_outline.Append( src->end_x, src->end_y, 0, hole_idx );
2513  }
2514  else if( seg->shape == GR_SHAPE_ARC )
2515  {
2516  const GRAPHIC_ARC* src = static_cast<const GRAPHIC_ARC*>( seg.get() );
2517  SHAPE_LINE_CHAIN& chain = poly_outline.Hole( 0, hole_idx );
2518 
2519  chain.Append( src->result );
2520  }
2521  }
2522 
2523  poly_outline.Fracture( SHAPE_POLY_SET::POLYGON_MODE::PM_FAST );
2524  return poly_outline;
2525 }
2526 
2527 
2528 bool FABMASTER::loadPolygon( BOARD* aBoard, const std::unique_ptr<FABMASTER::TRACE>& aLine)
2529 {
2530  if( aLine->segment.size() < 3 )
2531  return false;
2532 
2533  PCB_LAYER_ID layer = Cmts_User;
2534 
2535  auto new_layer = getLayer( aLine->layer );
2536 
2537  if( IsPcbLayer( new_layer ) )
2538  layer = new_layer;
2539 
2540  SHAPE_POLY_SET poly_outline = loadShapePolySet( aLine->segment );
2541 
2542  if( poly_outline.OutlineCount() < 1 || poly_outline.COutline( 0 ).PointCount() < 3 )
2543  return false;
2544 
2545  PCB_SHAPE* new_poly = new PCB_SHAPE( aBoard );
2546 
2547  new_poly->SetShape( S_POLYGON );
2548  new_poly->SetLayer( layer );
2549 
2550  // Polygons on the silk layer are filled but other layers are not/fill doesn't make sense
2551  if( layer == F_SilkS || layer == B_SilkS )
2552  {
2553  new_poly->SetFilled( true );
2554  new_poly->SetWidth( 0 );
2555  }
2556  else
2557  {
2558  new_poly->SetWidth( ( *( aLine->segment.begin() ) )->width );
2559 
2560  if( new_poly->GetWidth() == 0 )
2561  new_poly->SetWidth( aBoard->GetDesignSettings().GetLineThickness( layer ) );
2562  }
2563 
2564  new_poly->SetPolyShape( poly_outline );
2565  aBoard->Add( new_poly, ADD_MODE::APPEND );
2566 
2567  return true;
2568 
2569 }
2570 
2571 
2572 bool FABMASTER::loadZone( BOARD* aBoard, const std::unique_ptr<FABMASTER::TRACE>& aLine)
2573 {
2574  if( aLine->segment.size() < 3 )
2575  return false;
2576 
2577  int last_subseq = 0;
2578  int hole_idx = -1;
2579  SHAPE_POLY_SET* zone_outline = nullptr;
2580  ZONE* zone = nullptr;
2581 
2582  const NETNAMES_MAP& netinfo = aBoard->GetNetInfo().NetsByName();
2583  auto net_it = netinfo.find( aLine->netname );
2584  PCB_LAYER_ID layer = Cmts_User;
2585  auto new_layer = getLayer( aLine->layer );
2586 
2587  if( IsPcbLayer( new_layer ) )
2588  layer = new_layer;
2589 
2590  zone = new ZONE( aBoard );
2591  zone_outline = new SHAPE_POLY_SET;
2592 
2593  if( net_it != netinfo.end() )
2594  zone->SetNet( net_it->second );
2595 
2596  if( aLine->layer == "ALL" )
2597  zone->SetLayerSet( aBoard->GetLayerSet() & LSET::AllCuMask() );
2598  else
2599  zone->SetLayer( layer );
2600 
2601  zone->SetIsRuleArea( false );
2602  zone->SetDoNotAllowTracks( false );
2603  zone->SetDoNotAllowVias( false );
2604  zone->SetDoNotAllowPads( false );
2605  zone->SetDoNotAllowFootprints( false );
2606  zone->SetDoNotAllowCopperPour( false );
2607 
2608  if( aLine->lclass == "ROUTE KEEPOUT")
2609  {
2610  zone->SetIsRuleArea( true );
2611  zone->SetDoNotAllowTracks( true );
2612  }
2613  else if( aLine->lclass == "VIA KEEPOUT")
2614  {
2615  zone->SetIsRuleArea( true );
2616  zone->SetDoNotAllowVias( true );
2617  }
2618 
2619  zone->SetPriority( 50 );
2620  zone->SetLocalClearance( 0 );
2622 
2623  zone_outline->NewOutline();
2624 
2625 
2626  for( const auto& seg : aLine->segment )
2627  {
2628  if( seg->subseq > 0 && seg->subseq != last_subseq )
2629  {
2631  if( aLine->lclass == "BOUNDARY" )
2632  break;
2633 
2634  hole_idx = zone_outline->AddHole( SHAPE_LINE_CHAIN{} );
2635  last_subseq = seg->subseq;
2636  last_subseq = seg->subseq;
2637  }
2638 
2639  if( seg->shape == GR_SHAPE_LINE )
2640  {
2641  const GRAPHIC_LINE* src = static_cast<const GRAPHIC_LINE*>( seg.get() );
2642 
2643  if( zone_outline->VertexCount( 0, hole_idx ) == 0 )
2644  zone_outline->Append( src->start_x, src->start_y, 0, hole_idx );
2645 
2646  zone_outline->Append( src->end_x, src->end_y, 0, hole_idx );
2647  }
2648  else if( seg->shape == GR_SHAPE_ARC )
2649  {
2650  const GRAPHIC_ARC* src = static_cast<const GRAPHIC_ARC*>( seg.get() );
2651  zone_outline->Hole( 0, hole_idx ).Append( src->result );
2652  }
2653  }
2654 
2655  if( zone_outline->Outline( 0 ).PointCount() >= 3 )
2656  {
2657  zone->SetOutline( zone_outline );
2658  aBoard->Add( zone, ADD_MODE::APPEND );
2659  }
2660  else
2661  {
2662  delete( zone_outline );
2663  delete( zone );
2664  }
2665 
2666  return true;
2667 }
2668 
2669 
2670 bool FABMASTER::loadOutline( BOARD* aBoard, const std::unique_ptr<FABMASTER::TRACE>& aLine)
2671 {
2672  PCB_LAYER_ID layer;
2673 
2674  if( aLine->lclass == "BOARD GEOMETRY" )
2675  layer = Edge_Cuts;
2676  else if( aLine->lclass == "DRAWING FORMAT" )
2677  layer = Dwgs_User;
2678  else
2679  layer = Cmts_User;
2680 
2681  for( auto& seg : aLine->segment )
2682  {
2683  switch( seg->shape )
2684  {
2685 
2686  case GR_SHAPE_LINE:
2687  {
2688  const GRAPHIC_LINE* src = static_cast<const GRAPHIC_LINE*>( seg.get() );
2689 
2690  PCB_SHAPE* line = new PCB_SHAPE( aBoard );
2691  line->SetShape( S_SEGMENT );
2692  line->SetLayer( layer );
2693  line->SetStart( wxPoint( src->start_x, src->start_y ) );
2694  line->SetEnd( wxPoint( src->end_x, src->end_y ) );
2695  line->SetWidth( src->width );
2696 
2697  if( line->GetWidth() == 0 )
2698  line->SetWidth( aBoard->GetDesignSettings().GetLineThickness( layer ) );
2699 
2700  aBoard->Add( line, ADD_MODE::APPEND );
2701  break;
2702  }
2703  case GR_SHAPE_ARC:
2704  {
2705  const GRAPHIC_ARC* src = static_cast<const GRAPHIC_ARC*>( seg.get() );
2706 
2707  PCB_SHAPE* arc = new PCB_SHAPE( aBoard );
2708  arc->SetShape( S_ARC );
2709  arc->SetLayer( layer );
2710  arc->SetCenter( wxPoint( src->center_x, src->center_y ) );
2711  arc->SetArcStart( wxPoint( src->start_x, src->start_y ) );
2712  arc->SetAngle( src->result.GetCentralAngle() * 10.0 );
2713  arc->SetWidth( src->width );
2714 
2715  if( arc->GetWidth() == 0 )
2716  arc->SetWidth( aBoard->GetDesignSettings().GetLineThickness( layer ) );
2717 
2718  aBoard->Add( arc, ADD_MODE::APPEND );
2719  break;
2720  }
2721  case GR_SHAPE_RECTANGLE:
2722  {
2723  const GRAPHIC_RECTANGLE *src =
2724  static_cast<const GRAPHIC_RECTANGLE*>( seg.get() );
2725 
2726  PCB_SHAPE* rect = new PCB_SHAPE( aBoard );
2727  rect->SetShape( S_RECT );
2728  rect->SetLayer( layer );
2729  rect->SetStart( wxPoint( src->start_x, src->start_y ) );
2730  rect->SetEnd( wxPoint( src->end_x, src->end_y ) );
2731  rect->SetWidth( aBoard->GetDesignSettings().GetLineThickness( layer ) );
2732 
2733  aBoard->Add( rect, ADD_MODE::APPEND );
2734  break;
2735  }
2736  case GR_SHAPE_TEXT:
2737  {
2738  const GRAPHIC_TEXT *src =
2739  static_cast<const GRAPHIC_TEXT*>( seg.get() );
2740 
2741  PCB_TEXT* txt = new PCB_TEXT( aBoard );
2742  txt->SetLayer( layer );
2743  txt->SetTextPos( wxPoint( src->start_x, src->start_y - src->height / 2 ) );
2744  txt->SetText( src->text );
2745  txt->SetItalic( src->ital );
2746  txt->SetTextThickness( src->thickness );
2747  txt->SetTextHeight( src->height );
2748  txt->SetTextWidth( src->width );
2749  txt->SetHorizJustify( src->orient );
2750 
2751  aBoard->Add( txt, ADD_MODE::APPEND );
2752  break;
2753  }
2754  default:
2755  return false;
2756  }
2757  }
2758 
2759  return true;
2760 }
2761 
2762 
2764 {
2765 
2766  for( auto& geom : board_graphics )
2767  {
2768  PCB_LAYER_ID layer;
2769 
2770  // The pin numbers are not useful for us outside of the footprints
2771  if( geom.subclass == "PIN_NUMBER" )
2772  continue;
2773 
2774  layer = getLayer( geom.subclass );
2775 
2776  if( !IsPcbLayer( layer ) )
2777  layer = Cmts_User;
2778 
2779  if( !geom.elements->empty() )
2780  {
2782  if( ( *( geom.elements->begin() ) )->width == 0 )
2783  {
2784  SHAPE_POLY_SET poly_outline = loadShapePolySet( *( geom.elements ) );
2785 
2786  if( poly_outline.OutlineCount() < 1 || poly_outline.COutline( 0 ).PointCount() < 3 )
2787  continue;
2788 
2789  PCB_SHAPE* new_poly = new PCB_SHAPE( aBoard );
2790 
2791  new_poly->SetShape( S_POLYGON );
2792  new_poly->SetLayer( layer );
2793  new_poly->SetPolyShape( poly_outline );
2794  new_poly->SetWidth( 0 );
2795 
2796  if( layer == F_SilkS || layer == B_SilkS )
2797  new_poly->SetFilled( true );
2798 
2799  aBoard->Add( new_poly, ADD_MODE::APPEND );
2800  }
2801  }
2802 
2803  for( auto& seg : *geom.elements )
2804  {
2805  switch( seg->shape )
2806  {
2807 
2808  case GR_SHAPE_LINE:
2809  {
2810  const GRAPHIC_LINE* src = static_cast<const GRAPHIC_LINE*>( seg.get() );
2811 
2812  PCB_SHAPE* line = new PCB_SHAPE( aBoard );
2813  line->SetShape( S_SEGMENT );
2814  line->SetLayer( layer );
2815  line->SetStart( wxPoint( src->start_x, src->start_y ) );
2816  line->SetEnd( wxPoint( src->end_x, src->end_y ) );
2817  line->SetWidth( src->width );
2818 
2819  aBoard->Add( line, ADD_MODE::APPEND );
2820  break;
2821  }
2822  case GR_SHAPE_ARC:
2823  {
2824  const GRAPHIC_ARC* src = static_cast<const GRAPHIC_ARC*>( seg.get() );
2825 
2826  PCB_SHAPE* arc = new PCB_SHAPE( aBoard );
2827  arc->SetShape( S_ARC );
2828  arc->SetLayer( layer );
2829  arc->SetCenter( wxPoint( src->center_x, src->center_y ) );
2830  arc->SetArcStart( wxPoint( src->start_x, src->start_y ) );
2831  arc->SetAngle( src->result.GetCentralAngle() * 10.0 );
2832  arc->SetWidth( src->width );
2833 
2834  aBoard->Add( arc, ADD_MODE::APPEND );
2835  break;
2836  }
2837  case GR_SHAPE_RECTANGLE:
2838  {
2839  const GRAPHIC_RECTANGLE *src =
2840  static_cast<const GRAPHIC_RECTANGLE*>( seg.get() );
2841 
2842  PCB_SHAPE* rect = new PCB_SHAPE( aBoard );
2843  rect->SetShape( S_RECT );
2844  rect->SetLayer( layer );
2845  rect->SetStart( wxPoint( src->start_x, src->start_y ) );
2846  rect->SetEnd( wxPoint( src->end_x, src->end_y ) );
2847  rect->SetWidth( 0 );
2848  aBoard->Add( rect, ADD_MODE::APPEND );
2849  break;
2850  }
2851  case GR_SHAPE_TEXT:
2852  {
2853  const GRAPHIC_TEXT *src =
2854  static_cast<const GRAPHIC_TEXT*>( seg.get() );
2855 
2856  PCB_TEXT* txt = new PCB_TEXT( aBoard );
2857  txt->SetLayer( layer );
2858  txt->SetTextPos( wxPoint( src->start_x, src->start_y - src->height / 2 ) );
2859  txt->SetText( src->text );
2860  txt->SetItalic( src->ital );
2861  txt->SetTextThickness( src->thickness );
2862  txt->SetTextHeight( src->height );
2863  txt->SetTextWidth( src->width );
2864  txt->SetHorizJustify( src->orient );
2865  aBoard->Add( txt, ADD_MODE::APPEND );
2866  break;
2867  }
2868  default:
2869  return false;
2870  }
2871  }
2872  }
2873 
2874  return true;
2875 
2876 }
2877 
2878 
2880 {
2881  std::vector<ZONE*> zones = aBoard->Zones();
2882 
2883  std::sort( zones.begin(), zones.end(),
2884  [&]( const ZONE* a, const ZONE* b ) {
2885  if( a->GetLayer() == b->GetLayer() )
2886  return a->GetBoundingBox().GetArea() > b->GetBoundingBox().GetArea();
2887 
2888  return a->GetLayer() < b->GetLayer();
2889  } );
2890 
2891  PCB_LAYER_ID layer = UNDEFINED_LAYER;
2892  unsigned int priority = 0;
2893 
2894  for( ZONE* zone : zones )
2895  {
2896  if( zone->GetLayer() != layer )
2897  {
2898  layer = zone->GetLayer();
2899  priority = 0;
2900  }
2901 
2902  zone->SetPriority( priority );
2903  priority += 10;
2904  }
2905 
2906  return true;
2907 }
2908 
2909 
2911 {
2912  aBoard->SetFileName( m_filename.GetFullPath() );
2913 
2914  loadNets( aBoard );
2915  loadLayers( aBoard );
2916  loadVias( aBoard );
2917  loadFootprints( aBoard );
2918  loadZones( aBoard );
2919  loadGraphics( aBoard );
2920 
2921  for( auto& track : traces )
2922  {
2923  if( track->lclass == "ETCH" )
2924  {
2925  loadEtch( aBoard, track);
2926  }
2927  else if( track->layer == "OUTLINE" )
2928  {
2929  loadOutline( aBoard, track );
2930  }
2931  }
2932 
2933  orderZones( aBoard );
2934 
2935  return true;
2936 }
void SetReference(const wxString &aReference)
Definition: footprint.h:432
SHAPE_ARC result
! KiCad-style arc representation
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:750
size_t processSimpleLayers(size_t aRow)
bool Read(const std::string &aFile)
std::vector< std::string > single_row
Definition: track.h:343
LSET FlipLayerMask(LSET aMask, int aCopperLayersCount)
Calculate the mask layer when flipping a footprint.
Definition: lset.cpp:567
int OutlineCount() const
Return the number of vertices in a given outline/hole.
std::map< std::string, std::map< int, GEOM_GRAPHIC > > comp_graphics
ZONES & Zones()
Definition: board.h:309
void SetDoNotAllowTracks(bool aEnable)
Definition: zone.h:765
void SetPosition(const wxPoint &aPoint) override
Definition: track.h:412
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:194
std::string name
! LAYER_SUBCLASS
static constexpr double IU_PER_MM
Mock up a conversion function.
std::map< std::string, std::vector< std::unique_ptr< COMPONENT > > > components
void SetFilled(bool aFlag)
Definition: pcb_shape.h:94
bool ital
! GRAPHIC_DATA_6[4] != 0.0
void SetLayerSet(LSET aLayerSet) override
Definition: zone.cpp:243
bool loadGraphics(BOARD *aBoard)
int readInt(const std::string aStr) const
void SetItalic(bool isItalic)
Definition: eda_text.h:186
PCB_LAYER_ID FlipLayer(PCB_LAYER_ID aLayerId, int aCopperLayersCount)
Definition: lset.cpp:521
int GetWidth() const
Definition: pcb_shape.h:118
GRAPHIC_LINE * processLine(const GRAPHIC_DATA &aData, double aScale)
int VertexCount(int aOutline=-1, int aHole=-1) const
Returns the number of holes in a given outline.
Smd pad, appears on the solder paste layer (default)
Definition: pad_shapes.h:81
void SetTextPos(const wxPoint &aPoint)
Definition: eda_text.h:253
polygon (not yet used for tracks, but could be in microwave apps)
Definition: board_item.h:54
void SetVisible(bool aVisible)
Definition: eda_text.h:192
PCB_LAYER_ID getLayer(const std::string &aLayerName)
int thickness
! GRAPHIC_DATA_6[6]
std::unique_ptr< graphic_element > elements
void SetName(const wxString &aName)
Set the pad name (sometimes called pad number, although it can be an array reference like AA12).
Definition: pad.h:132
int end_x
! GRAPHIC_DATA_3
bool SetNetCode(int aNetCode, bool aNoAssert)
Set net using a net code.
double RAD2DECIDEG(double rad)
Definition: trigo.h:236
SHAPE_LINE_CHAIN & Hole(int aOutline, int aHole)
Return the aIndex-th subpolygon in the set.
std::string subclass
! SUBCLASS
std::unordered_map< std::string, PAD_SHAPE > pad_shapes
usual segment : line with rounded ends
Definition: board_item.h:50
int start_y
! GRAPHIC_DATA_2
bool ReplaceIllegalFileNameChars(std::string *aName, int aReplaceChar)
Checks aName for illegal file name characters.
Definition: string.cpp:746
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.h:591
bool loadEtch(BOARD *aBoard, const std::unique_ptr< TRACE > &aLine)
const NETINFO_LIST & GetNetInfo() const
Definition: board.h:752
bool PointOnEdge(const VECTOR2I &aP, int aAccuracy=0) const
Check if point aP lies on an edge or vertex of the line chain.
Arcs (with rounded ends)
Definition: board_item.h:52
bool loadZone(BOARD *aBoard, const std::unique_ptr< FABMASTER::TRACE > &aLine)
void SetOrientationDegrees(double aOrientation)
Definition: footprint.h:185
std::map< std::string, FABMASTER_LAYER > layers
void Rotate(double aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Rotate all vertices by a given angle.
void SetSize(const wxSize &aSize)
Definition: pad.h:231
std::string refdes
! REFDES
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:228
std::vector< std::unique_ptr< FM_VIA > > vias
like PAD_PTH, but not plated mechanical use only, no connection allowed
Definition: pad_shapes.h:85
segment with non rounded ends
Definition: board_item.h:51
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:51
static LSET AllTechMask()
Return a mask holding all technical layers (no CU layer) on both side.
Definition: lset.cpp:820
VECTOR2< int > VECTOR2I
Definition: vector2d.h:623
int center_x
! GRAPHIC_DATA_5
bool loadNets(BOARD *aBoard)
int PointCount() const
Function PointCount()
void SetPriority(unsigned aPriority)
Function SetPriority.
Definition: zone.h:118
A!LAYER_SORT!LAYER_SUBCLASS!LAYER_ARTWORK!LAYER_USE!LAYER_CONDUCTOR!LAYER_DIELECTRIC_CONSTANT !...
A!SUBCLASS!PAD_SHAPE_NAME!GRAPHIC_DATA_NAME!GRAPHIC_DATA_NUMBER!RECORD_TAG!GRAPHIC_DATA_1!...
std::set< std::unique_ptr< TRACE >, TRACE::BY_ID > traces
bool LoadBoard(BOARD *aBoard)
void Mirror(bool aX=true, bool aY=false, const VECTOR2I &aRef={ 0, 0 })
Mirror the line points about y or x (or both)
void Append(int aX, int aY, bool aAllowDuplication=false)
Function Append()
void SetWidth(int aWidth)
Definition: track.h:109
FP_TEXT & Value()
read/write accessors:
Definition: footprint.h:459
const NETNAMES_MAP & NetsByName() const
Return the name map, at least for python.
Definition: netinfo.h:358
void SetIsRuleArea(bool aEnable)
Definition: zone.h:762
size_t processFootprints(size_t aRow)
A!REFDES!COMP_CLASS!COMP_PART_NUMBER!COMP_HEIGHT!COMP_DEVICE_LABEL!COMP_INSERTION_CODE!...
FP_TEXT & Reference()
Definition: footprint.h:460
int GetLineThickness(PCB_LAYER_ID aLayer) const
Return the default graphic segment thickness from the layer class for the given layer.
bool Intersects(const BOX2< Vec > &aRect) const
Function Intersects.
Definition: box2.h:236
int end_y
! GRAPHIC_DATA_4 ! width is GRAPHIC_DATA_5
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT) override
Adds an item to the container.
Definition: board.cpp:563
section_type detectType(size_t aOffset)
std::vector< GEOM_GRAPHIC > board_graphics
GRAPHIC_ITEM * processGraphic(const GRAPHIC_DATA &aData, double aScale)
Specialty functions for processing graphical data rows into the internal database.
PCB_LAYER_ID
A quick note on layer IDs:
bool loadFootprints(BOARD *aBoard)
LSET is a set of PCB_LAYER_IDs.
pads are covered by copper
bool loadVias(BOARD *aBoard)
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:121
const EDA_RECT GetBoundingBox() const override
Function GetBoundingBox (virtual)
Definition: zone.cpp:319
int height
! GRAPHIC_DATA_6[2]
std::map< std::pair< std::string, std::string >, NETNAME > pin_nets
size_t processGeometry(size_t aRow)
A!GRAPHIC_DATA_NAME!GRAPHIC_DATA_NUMBER!RECORD_TAG!GRAPHIC_DATA_1!GRAPHIC_DATA_2!GRAPHIC_DATA_3!...
void Move(const VECTOR2I &aVector) override
void SetShape(PCB_SHAPE_TYPE_T aShape)
Definition: pcb_shape.h:129
const std::vector< VECTOR2I > & CPoints() const
void SetLocalCoord()
< Set relative coordinates.
Definition: pcbnew/pad.cpp:545
void SetDoNotAllowPads(bool aEnable)
Definition: zone.h:766
Represent a set of closed polygons.
SHAPE_LINE_CHAIN & Outline(int aIndex)
virtual PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition: zone.cpp:215
double rotation
! GRAPHIC_DATA_3
void SetOutline(SHAPE_POLY_SET *aOutline)
Definition: zone.h:326
std::set< std::unique_ptr< GRAPHIC_ITEM >, GRAPHIC_ITEM::SEQ_CMP > graphic_element
void SetDrillSize(const wxSize &aSize)
Definition: pad.h:241
void Flip(const wxPoint &aCentre, bool aFlipLeftRight) override
Flip this object, i.e.
Definition: footprint.cpp:1366
size_t processVias(size_t aRow)
A!VIA_X!VIA_Y!PAD_STACK_NAME!NET_NAME!TEST_POINT!
bool SetLayerName(PCB_LAYER_ID aLayer, const wxString &aLayerName)
Changes the name of the layer given by aLayer.
Definition: board.cpp:358
double readDouble(const std::string aStr) const
Reads the double/integer value from a std string independent of the user locale.
static LSET PTHMask()
layer set for a through hole pad
Definition: pcbnew/pad.cpp:147
size_t processPadStacks(size_t aRow)
A!PADNAME!RECNUMBER!LAYER!FIXFLAG!VIAFLAG!PADSHAPE1!PADWIDTH!PADHGHT! PADXOFF!PADYOFF!...
int center_y
! GRAPHIC_DATA_6
GRAPHIC_RECTANGLE * processRectangle(const GRAPHIC_DATA &aData, double aScale)
void SetDoNotAllowVias(bool aEnable)
Definition: zone.h:764
std::string refdes
!< NET_NAME
std::string pin_num
!< REFDES
GRAPHIC_TYPE type
! Type of graphic item
std::set< std::unique_ptr< TRACE >, TRACE::BY_ID > zones
ZONE handles a list of polygons defining a copper zone.
Definition: zone.h:57
SHAPE_POLY_SET loadShapePolySet(const graphic_element &aLine)
void SetFileName(const wxString &aFileName)
Definition: board.h:296
double GetArea() const
Return the area of the rectangle.
Definition: eda_rect.cpp:481
void SetValue(const wxString &aValue)
Definition: footprint.h:453
int getColFromName(size_t aRow, const std::string &aStr)
void SetShape(PAD_SHAPE_T aShape)
Set the new shape of this pad.
Definition: pad.h:160
int NewOutline()
Creates a new hole in a given outline.
int radius
! GRAPHIC_DATA_7 ! width is GRAPHIC_DATA_8
void Fracture(POLYGON_MODE aFastMode)
Convert a single outline slitted ("fractured") polygon into a set ouf outlines with holes.
int AddHole(const SHAPE_LINE_CHAIN &aHole, int aOutline=-1)
Return the area of this poly set.
void SetDrillShape(PAD_DRILL_SHAPE_T aShape)
Definition: pad.h:345
std::string text
! GRAPHIC_DATA_7
void SetDrillDefault()
Function SetDrillDefault sets the drill value for vias to the default value UNDEFINED_DRILL_DIAMETER.
Definition: track.h:495
std::map< std::string, std::set< std::unique_ptr< PIN >, PIN::BY_NUM > > pins
std::set< std::string > netnames
int id
! RECORD_TAG[0]
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
void SetTextWidth(int aWidth)
Definition: eda_text.h:247
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!...
void SetFPID(const LIB_ID &aFPID)
Definition: footprint.h:191
std::unordered_map< std::string, FM_PAD > pads
size_t processCustomPads(size_t aRow)
A!SUBCLASS!PAD_SHAPE_NAME!GRAPHIC_DATA_NAME!GRAPHIC_DATA_NUMBER!RECORD_TAG!GRAPHIC_DATA_1!...
GRAPHIC_ARC * processArc(const GRAPHIC_DATA &aData, double aScale)
Handle the data for a net.
Definition: netinfo.h:64
int Parse(const UTF8 &aId, bool aFix=false)
Parse LIB_ID with the information from aId.
Definition: lib_id.cpp:122
void SetPadConnection(ZONE_CONNECTION aPadConnection)
Definition: zone.h:245
void SetLayerSet(LSET aLayers) override
Definition: pad.h:359
void SetNet(NETINFO_ITEM *aNetInfo)
Set a NET_INFO object for the item.
int layerid
! pcbnew layer (assigned)
wxFileName m_filename
int start_x
! GRAPHIC_DATA_1
EDA_TEXT_HJUSTIFY_T orient
! GRAPHIC_DATA_5
bool conductive
! LAYER_CONDUCTOR
const char * name
Definition: DXF_plotter.cpp:59
wxPoint GetPosition() const override
Definition: pad.h:177
void MergePrimitivesAsPolygon(SHAPE_POLY_SET *aMergedPolygon, PCB_LAYER_ID aLayer) const
Merge all basic shapes to a SHAPE_POLY_SET.
Definition: track.h:262
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:190
void SetHorizJustify(EDA_TEXT_HJUSTIFY_T aType)
Definition: eda_text.h:208
void SetDoNotAllowCopperPour(bool aEnable)
Definition: zone.h:763
#define _(s)
Definition: 3d_actions.cpp:33
SHAPE_LINE_CHAIN.
int end_y
! GRAPHIC_DATA_4
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
T NormalizeAnglePos(T Angle)
Normalize angle to be in the 0.0 .
Definition: trigo.h:279
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
void AddPrimitivePoly(const SHAPE_POLY_SET &aPoly, int aThickness, bool aFilled)
Has meaning only for custom shape pads.
bool disable
! if true, prevent the layer elements from being used
void SetY(int y)
Definition: pad.h:222
Plated through hole pad.
Definition: pad_shapes.h:80
double GetCentralAngle() const
Definition: shape_arc.cpp:369
void SetDrill(int aDrill)
Function SetDrill sets the drill value for vias.
Definition: track.h:474
void SetTextHeight(int aHeight)
Definition: eda_text.h:250
void SetWidth(int aWidth)
Definition: pcb_shape.h:117
void SetLocalCoord()
Definition: fp_text.cpp:218
#define IU_PER_MILS
Definition: plotter.cpp:137
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:68
size_t processNets(size_t aRow)
A!NET_NAME!REFDES!PIN_NUMBER!PIN_NAME!PIN_GROUND!PIN_POWER!
void Remove(BOARD_ITEM *aBoardItem, REMOVE_MODE aMode=REMOVE_MODE::NORMAL) override
Removes an item from the container.
Definition: board.cpp:665
The common library.
size_t processLayers(size_t aRow)
A!LAYER_SORT!LAYER_SUBCLASS!LAYER_ARTWORK!LAYER_USE!LAYER_CONDUCTOR!LAYER_DIELECTRIC_CONSTANT!...
wxPoint GetPosition() const override
Definition: footprint.h:182
unsigned GetNetCount() const
Definition: netinfo.h:339
bool IsCopperLayer(LAYER_NUM aLayerId)
Tests whether a layer is a copper layer.
COMPCLASS parseCompClass(const std::string &aCompClass)
bool loadPolygon(BOARD *aBoard, const std::unique_ptr< FABMASTER::TRACE > &aLine)
virtual void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
Definition: zone.cpp:235
void SetTextThickness(int aWidth)
The TextThickness is that set by the user.
Definition: eda_text.h:166
void SetPolyShape(const SHAPE_POLY_SET &aShape)
Definition: pcb_shape.h:276
bool orderZones(BOARD *aBoard)
Sets zone priorities based on zone BB size.
static LSET UnplatedHoleMask()
layer set for a mechanical unplated through hole pad
Definition: pcbnew/pad.cpp:168
void SetLocalClearance(int aClearance)
Definition: zone.h:161
int width
! Various sections depending on type
bool IsPcbLayer(LAYER_NUM aLayer)
Test whether a layer is a valid layer for Pcbnew.
size_t processTraces(size_t aRow)
A!CLASS!SUBCLASS!GRAPHIC_DATA_NAME!GRAPHIC_DATA_NUMBER!RECORD_TAG!GRAPHIC_DATA_1!GRAPHIC_DATA_2!...
POLYGON & Polygon(int aIndex)
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT) override
Removes an item from the container.
Definition: footprint.cpp:467
std::string pin_name
!< PIN_NUMBER
Definition: pad.h:60
static LSET UserMask()
Definition: lset.cpp:834
void SetPosition(const wxPoint &aPos) override
Definition: footprint.cpp:1437
std::string name
! SYM_NAME
bool pin_gnd
!< PIN_NAME
int end_x
! GRAPHIC_DATA_3
SYMTYPE parseSymType(const std::string &aSymType)
bool mirror
! GRAPHIC_DATA_4
GRAPHIC_SHAPE shape
! Shape of the graphic_item
static LSET SMDMask()
layer set for a SMD pad on Front layer
Definition: pcbnew/pad.cpp:154
bool clockwise
! GRAPHIC_DATA_9
bool loadZones(BOARD *aBoard)
Loads sections of the database into the board.
bool positive
! LAYER_ARTWORK (either POSITIVE or NEGATIVE)
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38
void SetEnabledLayers(LSET aLayerMask)
A proxy function that calls the correspondent function in m_BoardSettings Changes the bit-mask of ena...
Definition: board.cpp:467
bool loadLayers(BOARD *aBoard)
Definition: track.h:83
void SetOrientation(double aAngle)
Set the rotation angle of the pad.
Definition: pcbnew/pad.cpp:579
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition: board_item.h:178
std::set< std::unique_ptr< TRACE >, TRACE::BY_ID > refdes
static std::vector< std::string > split(const std::string &aStr, const std::string &aDelim)
Splits the input string into a vector of output strings.
Definition: kicad_string.h:273
bool loadOutline(BOARD *aBoard, const std::unique_ptr< TRACE > &aLine)
double processScaleFactor(size_t aRow)
Processes data from text vectors into internal database for further ordering.
void SetDoNotAllowFootprints(bool aEnable)
Definition: zone.h:767
size_t processPadStackLayers(size_t aRow)
bool pin_pwr
!< PIN_GND
void SetX(int x)
Definition: pad.h:223
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...
GRAPHIC_TEXT * processText(const GRAPHIC_DATA &aData, double aScale)
std::deque< single_row > rows
void SetAttribute(PAD_ATTR_T aAttribute)
Definition: pcbnew/pad.cpp:560