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