KiCad PCB EDA Suite
pcb_parser.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) 2012 CERN
5  * Copyright (C) 2012-2020 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
30 #include <cerrno>
31 #include <common.h>
32 #include <confirm.h>
33 #include <macros.h>
34 #include <title_block.h>
35 #include <trigo.h>
36 
37 #include <class_board.h>
38 #include <class_dimension.h>
39 #include <class_drawsegment.h>
40 #include <class_edge_mod.h>
41 #include <class_pcb_target.h>
42 #include <class_module.h>
43 #include <netclass.h>
44 #include <class_pad.h>
45 #include <class_track.h>
46 #include <class_zone.h>
47 #include <kicad_plugin.h>
48 #include <pcb_plot_params_parser.h>
49 #include <pcb_plot_params.h>
50 #include <zones.h>
51 #include <pcb_parser.h>
52 #include <convert_basic_shapes_to_polygon.h> // for RECT_CHAMFER_POSITIONS definition
53 
54 using namespace PCB_KEYS_T;
55 
56 
58 {
59  m_showLegacyZoneWarning = true;
60  m_tooRecent = false;
61  m_requiredVersion = 0;
62  m_layerIndices.clear();
63  m_layerMasks.clear();
64 
65  // Add untranslated default (i.e. english) layernames.
66  // Some may be overridden later if parsing a board rather than a footprint.
67  // The english name will survive if parsing only a footprint.
68  for( LAYER_NUM layer = 0; layer < PCB_LAYER_ID_COUNT; ++layer )
69  {
70  std::string untranslated = TO_UTF8( wxString( LSET::Name( PCB_LAYER_ID( layer ) ) ) );
71 
72  m_layerIndices[ untranslated ] = PCB_LAYER_ID( layer );
73  m_layerMasks[ untranslated ] = LSET( PCB_LAYER_ID( layer ) );
74  }
75 
76  m_layerMasks[ "*.Cu" ] = LSET::AllCuMask();
77  m_layerMasks[ "*In.Cu" ] = LSET::InternalCuMask();
78  m_layerMasks[ "F&B.Cu" ] = LSET( 2, F_Cu, B_Cu );
79  m_layerMasks[ "*.Adhes" ] = LSET( 2, B_Adhes, F_Adhes );
80  m_layerMasks[ "*.Paste" ] = LSET( 2, B_Paste, F_Paste );
81  m_layerMasks[ "*.Mask" ] = LSET( 2, B_Mask, F_Mask );
82  m_layerMasks[ "*.SilkS" ] = LSET( 2, B_SilkS, F_SilkS );
83  m_layerMasks[ "*.Fab" ] = LSET( 2, B_Fab, F_Fab );
84  m_layerMasks[ "*.CrtYd" ] = LSET( 2, B_CrtYd, F_CrtYd );
85 
86  // This is for the first pretty & *.kicad_pcb formats, which had
87  // Inner1_Cu - Inner14_Cu with the numbering sequence
88  // reversed from the subsequent format's In1_Cu - In30_Cu numbering scheme.
89  // The newer format brought in an additional 16 Cu layers and flipped the cu stack but
90  // kept the gap between one of the outside layers and the last cu internal.
91 
92  for( int i=1; i<=14; ++i )
93  {
94  std::string key = StrPrintf( "Inner%d.Cu", i );
95 
96  m_layerMasks[ key ] = LSET( PCB_LAYER_ID( In15_Cu - i ) );
97  }
98 
99 #if defined(DEBUG) && 0
100  printf( "m_layerMasks:\n" );
101  for( LSET_MAP::const_iterator it = m_layerMasks.begin(); it != m_layerMasks.end(); ++it )
102  {
103  printf( " [%s] == 0x%s\n", it->first.c_str(), it->second.FmtHex().c_str() );
104  }
105 
106  printf( "m_layerIndices:\n" );
107  for( LAYER_ID_MAP::const_iterator it = m_layerIndices.begin(); it != m_layerIndices.end(); ++it )
108  {
109  printf( " [%s] == %d\n", it->first.c_str(), it->second );
110  }
111 #endif
112 
113 }
114 
115 
117 {
118  int curr_level = 0;
119  T token;
120 
121  while( ( token = NextTok() ) != T_EOF )
122  {
123  if( token == T_LEFT )
124  curr_level--;
125 
126  if( token == T_RIGHT )
127  {
128  curr_level++;
129 
130  if( curr_level > 0 )
131  return;
132  }
133  }
134 }
135 
136 
137 void PCB_PARSER::pushValueIntoMap( int aIndex, int aValue )
138 {
139  // Add aValue in netcode mapping (m_netCodes) at index aNetCode
140  // ensure there is room in m_netCodes for that, and add room if needed.
141 
142  if( (int)m_netCodes.size() <= aIndex )
143  m_netCodes.resize( aIndex+1 );
144 
145  m_netCodes[aIndex] = aValue;
146 }
147 
148 
150 {
151  char* tmp;
152 
153  errno = 0;
154 
155  double fval = strtod( CurText(), &tmp );
156 
157  if( errno )
158  {
159  wxString error;
160  error.Printf( _( "Invalid floating point number in\nfile: \"%s\"\nline: %d\noffset: %d" ),
161  GetChars( CurSource() ), CurLineNumber(), CurOffset() );
162 
163  THROW_IO_ERROR( error );
164  }
165 
166  if( CurText() == tmp )
167  {
168  wxString error;
169  error.Printf( _( "Missing floating point number in\nfile: \"%s\"\nline: %d\noffset: %d" ),
170  GetChars( CurSource() ), CurLineNumber(), CurOffset() );
171 
172  THROW_IO_ERROR( error );
173  }
174 
175  return fval;
176 }
177 
178 
180 {
181  T token = NextTok();
182 
183  if( token == T_yes )
184  return true;
185  else if( token == T_no )
186  return false;
187  else
188  Expecting( "yes or no" );
189 
190  return false;
191 }
192 
193 
195 {
196  if( NextTok() != T_version )
197  Expecting( GetTokenText( T_version ) );
198 
199  int pcb_version = parseInt( FromUTF8().mb_str( wxConvUTF8 ) );
200 
201  NeedRIGHT();
202 
203  return pcb_version;
204 }
205 
206 
208 {
209  int year, month, day;
210 
211  year = m_requiredVersion / 10000;
212  month = ( m_requiredVersion / 100 ) - ( year * 100 );
213  day = m_requiredVersion - ( year * 10000 ) - ( month * 100 );
214 
215  // wx throws an assertion, not a catchable exception, when the date is invalid.
216  // User input shouldn't give wx asserts, so check manually and throw a proper
217  // error instead
218  if( day <= 0 || month <= 0 || month > 12 ||
219  day > wxDateTime::GetNumberOfDays( (wxDateTime::Month)( month - 1 ), year ) )
220  {
221  wxString err;
222  err.Printf( _( "Cannot interpret date code %d" ), m_requiredVersion );
223  THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
224  }
225 
226  wxDateTime date( day, (wxDateTime::Month)( month - 1 ), year, 0, 0, 0, 0 );
227  return date.FormatDate();
228 }
229 
230 
232 {
233  if( CurTok() != T_LEFT )
234  NeedLEFT();
235 
236  wxPoint pt;
237  T token = NextTok();
238 
239  if( token != T_xy )
240  Expecting( T_xy );
241 
242  pt.x = parseBoardUnits( "X coordinate" );
243  pt.y = parseBoardUnits( "Y coordinate" );
244 
245  NeedRIGHT();
246 
247  return pt;
248 }
249 
250 
251 void PCB_PARSER::parseXY( int* aX, int* aY )
252 {
253  wxPoint pt = parseXY();
254 
255  if( aX )
256  *aX = pt.x;
257 
258  if( aY )
259  *aY = pt.y;
260 }
261 
262 
264 {
265  wxCHECK_RET( CurTok() == T_effects,
266  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as EDA_TEXT." ) );
267 
268  T token;
269 
270  // Prior to v5.0 text size was omitted from file format if equal to 60mils
271  // Now, it is always explicitly written to file
272  bool foundTextSize = false;
273 
274  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
275  {
276  if( token == T_LEFT )
277  token = NextTok();
278 
279  switch( token )
280  {
281  case T_font:
282  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
283  {
284  if( token == T_LEFT )
285  continue;
286 
287  switch( token )
288  {
289  case T_size:
290  {
291  wxSize sz;
292  sz.SetHeight( parseBoardUnits( "text height" ) );
293  sz.SetWidth( parseBoardUnits( "text width" ) );
294  aText->SetTextSize( sz );
295  NeedRIGHT();
296 
297  foundTextSize = true;
298  }
299  break;
300 
301  case T_thickness:
302  aText->SetThickness( parseBoardUnits( "text thickness" ) );
303  NeedRIGHT();
304  break;
305 
306  case T_bold:
307  aText->SetBold( true );
308  break;
309 
310  case T_italic:
311  aText->SetItalic( true );
312  break;
313 
314  default:
315  Expecting( "size, bold, or italic" );
316  }
317  }
318  break;
319 
320  case T_justify:
321  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
322  {
323  if( token == T_LEFT )
324  continue;
325 
326  switch( token )
327  {
328  case T_left:
330  break;
331 
332  case T_right:
334  break;
335 
336  case T_top:
338  break;
339 
340  case T_bottom:
342  break;
343 
344  case T_mirror:
345  aText->SetMirrored( true );
346  break;
347 
348  default:
349  Expecting( "left, right, top, bottom, or mirror" );
350  }
351 
352  }
353  break;
354 
355  case T_hide:
356  aText->SetVisible( false );
357  break;
358 
359  default:
360  Expecting( "font, justify, or hide" );
361  }
362  }
363 
364  // Text size was not specified in file, force legacy default units
365  // 60mils is 1.524mm
366  if( !foundTextSize )
367  {
368  const double defaultTextSize = 1.524 * IU_PER_MM;
369 
370  aText->SetTextSize( wxSize( defaultTextSize, defaultTextSize ) );
371  }
372 }
373 
374 
376 {
377  wxCHECK_MSG( CurTok() == T_model, NULL,
378  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as MODULE_3D_SETTINGS." ) );
379 
380  T token;
381 
383  NeedSYMBOLorNUMBER();
384  n3D->m_Filename = FromUTF8();
385 
386  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
387  {
388  if( token != T_LEFT )
389  Expecting( T_LEFT );
390 
391  token = NextTok();
392 
393  switch( token )
394  {
395  case T_at:
396  NeedLEFT();
397  token = NextTok();
398 
399  if( token != T_xyz )
400  Expecting( T_xyz );
401 
402  /* Note:
403  * Prior to KiCad v5, model offset was designated by "at",
404  * and the units were in inches.
405  * Now we use mm, but support reading of legacy files
406  */
407 
408  n3D->m_Offset.x = parseDouble( "x value" ) * 25.4f;
409  n3D->m_Offset.y = parseDouble( "y value" ) * 25.4f;
410  n3D->m_Offset.z = parseDouble( "z value" ) * 25.4f;
411  NeedRIGHT();
412  break;
413 
414  case T_offset:
415  NeedLEFT();
416  token = NextTok();
417 
418  if( token != T_xyz )
419  Expecting( T_xyz );
420 
421  /*
422  * 3D model offset is in mm
423  */
424  n3D->m_Offset.x = parseDouble( "x value" );
425  n3D->m_Offset.y = parseDouble( "y value" );
426  n3D->m_Offset.z = parseDouble( "z value" );
427  NeedRIGHT();
428  break;
429 
430  case T_scale:
431  NeedLEFT();
432  token = NextTok();
433 
434  if( token != T_xyz )
435  Expecting( T_xyz );
436 
437  n3D->m_Scale.x = parseDouble( "x value" );
438  n3D->m_Scale.y = parseDouble( "y value" );
439  n3D->m_Scale.z = parseDouble( "z value" );
440  NeedRIGHT();
441  break;
442 
443  case T_rotate:
444  NeedLEFT();
445  token = NextTok();
446 
447  if( token != T_xyz )
448  Expecting( T_xyz );
449 
450  n3D->m_Rotation.x = parseDouble( "x value" );
451  n3D->m_Rotation.y = parseDouble( "y value" );
452  n3D->m_Rotation.z = parseDouble( "z value" );
453  NeedRIGHT();
454  break;
455 
456  default:
457  Expecting( "at, offset, scale, or rotate" );
458  }
459 
460  NeedRIGHT();
461  }
462 
463  return n3D;
464 }
465 
466 
468 {
469  T token;
470  BOARD_ITEM* item;
471  LOCALE_IO toggle;
472 
473  // MODULEs can be prefixed with an initial block of single line comments and these
474  // are kept for Format() so they round trip in s-expression form. BOARDs might
475  // eventually do the same, but currently do not.
476  std::unique_ptr<wxArrayString> initial_comments( ReadCommentLines() );
477 
478  token = CurTok();
479 
480  if( token != T_LEFT )
481  Expecting( T_LEFT );
482 
483  switch( NextTok() )
484  {
485  case T_kicad_pcb:
486  if( m_board == NULL )
487  m_board = new BOARD();
488 
489  item = (BOARD_ITEM*) parseBOARD();
490  break;
491 
492  case T_module:
493  item = (BOARD_ITEM*) parseMODULE( initial_comments.release() );
494  break;
495 
496  default:
497  wxString err;
498  err.Printf( _( "Unknown token \"%s\"" ), GetChars( FromUTF8() ) );
499  THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
500  }
501 
502  return item;
503 }
504 
505 
507 {
508  try
509  {
510  return parseBOARD_unchecked();
511  }
512  catch( const PARSE_ERROR& parse_error )
513  {
514  if( m_tooRecent )
515  throw FUTURE_FORMAT_ERROR( parse_error, GetRequiredVersion() );
516  else
517  throw;
518  }
519 }
520 
521 
523 {
524  T token;
525 
526  parseHeader();
527 
528  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
529  {
530  if( token != T_LEFT )
531  Expecting( T_LEFT );
532 
533  token = NextTok();
534 
535  switch( token )
536  {
537  case T_general:
538  parseGeneralSection();
539  break;
540 
541  case T_page:
542  parsePAGE_INFO();
543  break;
544 
545  case T_title_block:
546  parseTITLE_BLOCK();
547  break;
548 
549  case T_layers:
550  parseLayers();
551  break;
552 
553  case T_setup:
554  parseSetup();
555  break;
556 
557  case T_net:
558  parseNETINFO_ITEM();
559  break;
560 
561  case T_net_class:
562  parseNETCLASS();
563  break;
564 
565  case T_gr_arc:
566  case T_gr_circle:
567  case T_gr_curve:
568  case T_gr_line:
569  case T_gr_poly:
570  m_board->Add( parseDRAWSEGMENT(), ADD_MODE::APPEND );
571  break;
572 
573  case T_gr_text:
574  m_board->Add( parseTEXTE_PCB(), ADD_MODE::APPEND );
575  break;
576 
577  case T_dimension:
578  m_board->Add( parseDIMENSION(), ADD_MODE::APPEND );
579  break;
580 
581  case T_module:
582  m_board->Add( parseMODULE(), ADD_MODE::APPEND );
583  break;
584 
585  case T_segment:
586  m_board->Add( parseTRACK(), ADD_MODE::INSERT );
587  break;
588 
589  case T_arc:
590  m_board->Add( parseARC(), ADD_MODE::INSERT );
591  break;
592 
593  case T_via:
594  m_board->Add( parseVIA(), ADD_MODE::INSERT );
595  break;
596 
597  case T_zone:
598  m_board->Add( parseZONE_CONTAINER( m_board ), ADD_MODE::APPEND );
599  break;
600 
601  case T_target:
602  m_board->Add( parsePCB_TARGET(), ADD_MODE::APPEND );
603  break;
604 
605  default:
606  wxString err;
607  err.Printf( _( "Unknown token \"%s\"" ), GetChars( FromUTF8() ) );
608  THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
609  }
610  }
611 
612  if( m_undefinedLayers.size() > 0 )
613  {
614  bool deleteItems;
615  std::vector<BOARD_ITEM*> deleteList;
616  wxString msg = wxString::Format( _( "Items found on undefined layers. Do you wish to\n"
617  "rescue them to the Cmts.User layer?" ) );
618  wxString details = wxString::Format( _( "Undefined layers:" ) );
619 
620  for( const wxString& undefinedLayer : m_undefinedLayers )
621  details += wxT( "\n " ) + undefinedLayer;
622 
623  wxRichMessageDialog dlg( nullptr, msg, _( "Warning" ),
624  wxYES_NO | wxCANCEL | wxCENTRE | wxICON_WARNING | wxSTAY_ON_TOP );
625  dlg.ShowDetailedText( details );
626  dlg.SetYesNoCancelLabels( _( "Rescue" ), _( "Delete" ), _( "Cancel" ) );
627 
628  switch( dlg.ShowModal() )
629  {
630  case wxID_YES: deleteItems = false; break;
631  case wxID_NO: deleteItems = true; break;
632  case wxID_CANCEL:
633  default: THROW_IO_ERROR( wxT( "CANCEL" ) );
634  }
635 
636  auto visitItem = [&]( BOARD_ITEM* item )
637  {
638  if( item->GetLayer() == Rescue )
639  {
640  if( deleteItems )
641  deleteList.push_back( item );
642  else
643  item->SetLayer( Cmts_User );
644  }
645  };
646 
647  for( auto segm : m_board->Tracks() )
648  {
649  if( segm->Type() == PCB_VIA_T )
650  {
651  VIA* via = (VIA*) segm;
652  PCB_LAYER_ID top_layer, bottom_layer;
653 
654  if( via->GetViaType() == VIATYPE::THROUGH )
655  continue;
656 
657  via->LayerPair( &top_layer, &bottom_layer );
658 
659  if( top_layer == Rescue || bottom_layer == Rescue )
660  {
661  if( deleteItems )
662  deleteList.push_back( via );
663  else
664  {
665  if( top_layer == Rescue )
666  top_layer = F_Cu;
667 
668  if( bottom_layer == Rescue )
669  bottom_layer = B_Cu;
670 
671  via->SetLayerPair( top_layer, bottom_layer );
672  }
673  }
674  }
675  else
676  visitItem( segm );
677  }
678 
679  for( BOARD_ITEM* zone : m_board->Zones() )
680  visitItem( zone );
681 
682  for( BOARD_ITEM* drawing : m_board->Drawings() )
683  visitItem( drawing );
684 
685  for( BOARD_ITEM* item : deleteList )
686  m_board->Delete( item );
687 
688  m_undefinedLayers.clear();
689  }
690 
691  return m_board;
692 }
693 
694 
696 {
697  wxCHECK_RET( CurTok() == T_kicad_pcb,
698  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a header." ) );
699 
700  NeedLEFT();
701 
702  T tok = NextTok();
703  if( tok == T_version )
704  {
705  m_requiredVersion = parseInt( FromUTF8().mb_str( wxConvUTF8 ) );
706  m_tooRecent = ( m_requiredVersion > SEXPR_BOARD_FILE_VERSION );
707  NeedRIGHT();
708 
709  // Skip the host name and host build version information.
710  NeedLEFT();
711  NeedSYMBOL();
712  NeedSYMBOL();
713  NeedSYMBOL();
714  NeedRIGHT();
715  }
716  else
717  {
718  m_requiredVersion = SEXPR_BOARD_FILE_VERSION;
719  m_tooRecent = ( m_requiredVersion > SEXPR_BOARD_FILE_VERSION );
720 
721  // Skip the host name and host build version information.
722  NeedSYMBOL();
723  NeedSYMBOL();
724  NeedRIGHT();
725  }
726 
727  m_board->SetFileFormatVersionAtLoad( m_requiredVersion );
728 }
729 
730 
732 {
733  wxCHECK_RET( CurTok() == T_general,
734  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) +
735  wxT( " as a general section." ) );
736 
737  T token;
738 
739  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
740  {
741  if( token != T_LEFT )
742  Expecting( T_LEFT );
743 
744  token = NextTok();
745 
746  switch( token )
747  {
748  case T_thickness:
749  m_board->GetDesignSettings().SetBoardThickness( parseBoardUnits( T_thickness ) );
750  NeedRIGHT();
751  break;
752 
753  case T_nets:
754  m_netCodes.resize( parseInt( "nets number" ) );
755  NeedRIGHT();
756  break;
757 
758  case T_no_connects:
759  // ignore
760  parseInt( "no connect count" );
761  NeedRIGHT();
762  break;
763 
764  default: // Skip everything but the board thickness.
765  //wxLogDebug( wxT( "Skipping general section token %s " ), GetChars( GetTokenString( token ) ) );
766 
767  while( ( token = NextTok() ) != T_RIGHT )
768  {
769  if( !IsSymbol( token ) && token != T_NUMBER )
770  Expecting( "symbol or number" );
771  }
772  }
773  }
774 }
775 
776 
778 {
779  wxCHECK_RET( CurTok() == T_page,
780  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a PAGE_INFO." ) );
781 
782  T token;
783  PAGE_INFO pageInfo;
784 
785  NeedSYMBOL();
786 
787  wxString pageType = FromUTF8();
788 
789  if( !pageInfo.SetType( pageType ) )
790  {
791  wxString err;
792  err.Printf( _( "Page type \"%s\" is not valid " ), GetChars( FromUTF8() ) );
793  THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
794  }
795 
796  if( pageType == PAGE_INFO::Custom )
797  {
798  double width = parseDouble( "width" ); // width in mm
799 
800  // Perform some controls to avoid crashes if the size is edited by hands
801  if( width < 100.0 )
802  width = 100.0;
803  else if( width > 1200.0 )
804  width = 1200.0;
805 
806  double height = parseDouble( "height" ); // height in mm
807 
808  if( height < 100.0 )
809  height = 100.0;
810  else if( height > 1200.0 )
811  height = 1200.0;
812 
813  pageInfo.SetWidthMils( Mm2mils( width ) );
814  pageInfo.SetHeightMils( Mm2mils( height ) );
815  }
816 
817  token = NextTok();
818 
819  if( token == T_portrait )
820  {
821  pageInfo.SetPortrait( true );
822  NeedRIGHT();
823  }
824  else if( token != T_RIGHT )
825  {
826  Expecting( "portrait|)" );
827  }
828 
829  m_board->SetPageSettings( pageInfo );
830 }
831 
832 
834 {
835  wxCHECK_RET( CurTok() == T_title_block,
836  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) +
837  wxT( " as TITLE_BLOCK." ) );
838 
839  T token;
840  TITLE_BLOCK titleBlock;
841 
842  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
843  {
844  if( token != T_LEFT )
845  Expecting( T_LEFT );
846 
847  token = NextTok();
848 
849  switch( token )
850  {
851  case T_title:
852  NextTok();
853  titleBlock.SetTitle( FromUTF8() );
854  break;
855 
856  case T_date:
857  NextTok();
858  titleBlock.SetDate( FromUTF8() );
859  break;
860 
861  case T_rev:
862  NextTok();
863  titleBlock.SetRevision( FromUTF8() );
864  break;
865 
866  case T_company:
867  NextTok();
868  titleBlock.SetCompany( FromUTF8() );
869  break;
870 
871  case T_comment:
872  {
873  int commentNumber = parseInt( "comment" );
874 
875  switch( commentNumber )
876  {
877  case 1:
878  NextTok();
879  titleBlock.SetComment( 0, FromUTF8() );
880  break;
881 
882  case 2:
883  NextTok();
884  titleBlock.SetComment( 1, FromUTF8() );
885  break;
886 
887  case 3:
888  NextTok();
889  titleBlock.SetComment( 2, FromUTF8() );
890  break;
891 
892  case 4:
893  NextTok();
894  titleBlock.SetComment( 3, FromUTF8() );
895  break;
896 
897  case 5:
898  NextTok();
899  titleBlock.SetComment( 4, FromUTF8() );
900  break;
901 
902  case 6:
903  NextTok();
904  titleBlock.SetComment( 5, FromUTF8() );
905  break;
906 
907  case 7:
908  NextTok();
909  titleBlock.SetComment( 6, FromUTF8() );
910  break;
911 
912  case 8:
913  NextTok();
914  titleBlock.SetComment( 7, FromUTF8() );
915  break;
916 
917  case 9:
918  NextTok();
919  titleBlock.SetComment( 8, FromUTF8() );
920  break;
921 
922  default:
923  wxString err;
924  err.Printf( wxT( "%d is not a valid title block comment number" ), commentNumber );
925  THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
926  }
927  }
928  break;
929 
930  default:
931  Expecting( "title, date, rev, company, or comment" );
932  }
933 
934  NeedRIGHT();
935  }
936 
937  m_board->SetTitleBlock( titleBlock );
938 }
939 
940 
942 {
943  T token;
944 
945  std::string name;
946  std::string type;
947  bool isVisible = true;
948 
949  aLayer->clear();
950 
951  if( CurTok() != T_LEFT )
952  Expecting( T_LEFT );
953 
954  // this layer_num is not used, we DO depend on LAYER_T however.
955  LAYER_NUM layer_num = parseInt( "layer index" );
956 
957  NeedSYMBOLorNUMBER();
958  name = CurText();
959 
960  NeedSYMBOL();
961  type = CurText();
962 
963  token = NextTok();
964 
965  if( token == T_hide )
966  {
967  isVisible = false;
968  NeedRIGHT();
969  }
970  else if( token != T_RIGHT )
971  {
972  Expecting( "hide or )" );
973  }
974 
975  aLayer->m_name = FROM_UTF8( name.c_str() );
976  aLayer->m_type = LAYER::ParseType( type.c_str() );
977  aLayer->m_number = layer_num;
978  aLayer->m_visible = isVisible;
979 }
980 
981 
983 {
984  T token;
985  wxString name;
986  int dielectric_idx = 1; // the index of dielectric layers
987  BOARD_STACKUP& stackup = m_board->GetDesignSettings().GetStackupDescriptor();
988 
989  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
990  {
991  if( CurTok() != T_LEFT )
992  Expecting( T_LEFT );
993 
994  token = NextTok();
995 
996  if( token != T_layer )
997  {
998  switch( token )
999  {
1000  case T_copper_finish:
1001  NeedSYMBOL();
1002  stackup.m_FinishType = FromUTF8();
1003  NeedRIGHT();
1004  break;
1005 
1006  case T_edge_plating:
1007  token = NextTok();
1008  stackup.m_EdgePlating = token == T_yes;
1009  NeedRIGHT();
1010  break;
1011 
1012  case T_dielectric_constraints:
1013  token = NextTok();
1014  stackup.m_HasDielectricConstrains = token == T_yes;
1015  NeedRIGHT();
1016  break;
1017 
1018  case T_edge_connector:
1019  token = NextTok();
1021 
1022  if( token == T_yes )
1024  else if( token == T_bevelled )
1026 
1027  NeedRIGHT();
1028  break;
1029 
1030  case T_castellated_pads:
1031  token = NextTok();
1032  stackup.m_CastellatedPads = token == T_yes;
1033  NeedRIGHT();
1034  break;
1035 
1036  default:
1037  // Currently, skip this item if not defined, because the stackup def
1038  // is a moving target
1039  //Expecting( "copper_finish, edge_plating, dielectric_constrains, edge_connector, castellated_pads" );
1040  skipCurrent();
1041  break;
1042  }
1043 
1044  continue;
1045  }
1046 
1047  NeedSYMBOL();
1048  name = FromUTF8();
1049 
1050  // init the layer id. For dielectric, layer id = UNDEFINED_LAYER
1051  PCB_LAYER_ID layerId = m_board->GetLayerID( name );
1052 
1053  // Init the type
1055 
1056  if( layerId == F_SilkS || layerId == B_SilkS )
1057  type = BS_ITEM_TYPE_SILKSCREEN;
1058  else if( layerId == F_Mask || layerId == B_Mask )
1059  type = BS_ITEM_TYPE_SOLDERMASK;
1060  else if( layerId == F_Paste || layerId == B_Paste )
1061  type = BS_ITEM_TYPE_SOLDERPASTE;
1062  else if( layerId == UNDEFINED_LAYER )
1063  type = BS_ITEM_TYPE_DIELECTRIC;
1064  else if( layerId >= F_Cu && layerId <= B_Cu )
1065  type = BS_ITEM_TYPE_COPPER;
1066 
1067  BOARD_STACKUP_ITEM* item = nullptr;
1068 
1069  if( type != BS_ITEM_TYPE_UNDEFINED )
1070  {
1071  item = new BOARD_STACKUP_ITEM( type );
1072  item->SetBrdLayerId( layerId );
1073 
1074  if( type == BS_ITEM_TYPE_DIELECTRIC )
1075  item->SetDielectricLayerId( dielectric_idx++ );
1076 
1077  stackup.Add( item );
1078  }
1079  else
1080  Expecting( "layer_name" );
1081 
1082  bool has_next_sublayer = true;
1083  int sublayer_idx = 0; // the index of dielectric sub layers
1084  // sublayer 0 is always existing (main sublayer)
1085 
1086  while( has_next_sublayer )
1087  {
1088  has_next_sublayer = false;
1089 
1090  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1091  {
1092  if( token == T_addsublayer )
1093  {
1094  has_next_sublayer = true;
1095  break;
1096  }
1097 
1098  if( token == T_LEFT )
1099  {
1100  token = NextTok();
1101 
1102  switch( token )
1103  {
1104  case T_type:
1105  NeedSYMBOL();
1106  item->SetTypeName( FromUTF8() );
1107  NeedRIGHT();
1108  break;
1109 
1110  case T_thickness:
1111  item->SetThickness( parseBoardUnits( T_thickness ), sublayer_idx );
1112  token = NextTok();
1113 
1114  if( token == T_LEFT )
1115  break;
1116 
1117  if( token == T_locked )
1118  {
1119  // Dielectric thickness can be locked (for impedance controled layers)
1120  if( type == BS_ITEM_TYPE_DIELECTRIC )
1121  item->SetThicknessLocked( true, sublayer_idx );
1122 
1123  NeedRIGHT();
1124  }
1125  break;
1126 
1127  case T_material:
1128  NeedSYMBOL();
1129  item->SetMaterial( FromUTF8(), sublayer_idx );
1130  NeedRIGHT();
1131  break;
1132 
1133  case T_epsilon_r:
1134  NextTok();
1135  item->SetEpsilonR( parseDouble(), sublayer_idx );
1136  NeedRIGHT();
1137  break;
1138 
1139  case T_loss_tangent:
1140  NextTok();
1141  item->SetLossTangent( parseDouble(), sublayer_idx );
1142  NeedRIGHT();
1143  break;
1144 
1145  case T_color:
1146  NeedSYMBOL();
1147  item->SetColor( FromUTF8() );
1148  NeedRIGHT();
1149  break;
1150 
1151  default:
1152  // Currently, skip this item if not defined, because the stackup def
1153  // is a moving target
1154  //Expecting( "type, thickness, material, epsilon_r, loss_tangent, color" );
1155  skipCurrent();
1156  }
1157  }
1158  }
1159 
1160  if( has_next_sublayer ) // Prepare reading the next sublayer description
1161  {
1162  sublayer_idx++;
1163  item->AddDielectricPrms( sublayer_idx );
1164  }
1165  }
1166  }
1167 
1168  if( token != T_RIGHT )
1169  {
1170  Expecting( ")" );
1171  }
1172 
1173  // Success:
1174  m_board->GetDesignSettings().m_HasStackup = true;
1175 }
1176 
1177 
1178 void PCB_PARSER::createOldLayerMapping( std::unordered_map< std::string, std::string >& aMap )
1179 {
1180  // N.B. This mapping only includes Italian, Polish and French as they were the only languages that
1181  // mapped the layer names as of cc2022b1ac739aa673d2a0b7a2047638aa7a47b3 (kicad-i18n) when the
1182  // bug was fixed in KiCad source.
1183 
1184  // Italian
1185  aMap["Adesivo.Retro"] = "B.Adhes";
1186  aMap["Adesivo.Fronte"] = "F.Adhes";
1187  aMap["Pasta.Retro"] = "B.Paste";
1188  aMap["Pasta.Fronte"] = "F.Paste";
1189  aMap["Serigrafia.Retro"] = "B.SilkS";
1190  aMap["Serigrafia.Fronte"] = "F.SilkS";
1191  aMap["Maschera.Retro"] = "B.Mask";
1192  aMap["Maschera.Fronte"] = "F.Mask";
1193  aMap["Grafica"] = "Dwgs.User";
1194  aMap["Commenti"] = "Cmts.User";
1195  aMap["Eco1"] = "Eco1.User";
1196  aMap["Eco2"] = "Eco2.User";
1197  aMap["Contorno.scheda"] = "Edge.Cuts";
1198 
1199  // Polish
1200  aMap["Kleju_Dolna"] = "B.Adhes";
1201  aMap["Kleju_Gorna"] = "F.Adhes";
1202  aMap["Pasty_Dolna"] = "B.Paste";
1203  aMap["Pasty_Gorna"] = "F.Paste";
1204  aMap["Opisowa_Dolna"] = "B.SilkS";
1205  aMap["Opisowa_Gorna"] = "F.SilkS";
1206  aMap["Maski_Dolna"] = "B.Mask";
1207  aMap["Maski_Gorna"] = "F.Mask";
1208  aMap["Rysunkowa"] = "Dwgs.User";
1209  aMap["Komentarzy"] = "Cmts.User";
1210  aMap["ECO1"] = "Eco1.User";
1211  aMap["ECO2"] = "Eco2.User";
1212  aMap["Krawedziowa"] = "Edge.Cuts";
1213 
1214  // French
1215  aMap["Dessous.Adhes"] = "B.Adhes";
1216  aMap["Dessus.Adhes"] = "F.Adhes";
1217  aMap["Dessous.Pate"] = "B.Paste";
1218  aMap["Dessus.Pate"] = "F.Paste";
1219  aMap["Dessous.SilkS"] = "B.SilkS";
1220  aMap["Dessus.SilkS"] = "F.SilkS";
1221  aMap["Dessous.Masque"] = "B.Mask";
1222  aMap["Dessus.Masque"] = "F.Mask";
1223  aMap["Dessin.User"] = "Dwgs.User";
1224  aMap["Contours.Ci"] = "Edge.Cuts";
1225 }
1226 
1227 
1229 {
1230  wxCHECK_RET( CurTok() == T_layers,
1231  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as layers." ) );
1232 
1233  T token;
1234  LSET visibleLayers;
1235  LSET enabledLayers;
1236  int copperLayerCount = 0;
1237  LAYER layer;
1238 
1239  std::unordered_map< std::string, std::string > v3_layer_names;
1240  std::vector<LAYER> cu;
1241 
1242  createOldLayerMapping( v3_layer_names );
1243 
1244  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1245  {
1246  parseLayer( &layer );
1247 
1248  if( layer.m_type == LT_UNDEFINED ) // it's a non-copper layer
1249  break;
1250 
1251  cu.push_back( layer ); // it's copper
1252  }
1253 
1254  // All Cu layers are parsed, but not the non-cu layers here.
1255 
1256  // The original *.kicad_pcb file format and the inverted
1257  // Cu stack format both have all the Cu layers first, so use this
1258  // trick to handle either. The layer number in the (layers ..)
1259  // s-expression element are ignored.
1260  if( cu.size() )
1261  {
1262  // Rework the layer numbers, which changed when the Cu stack
1263  // was flipped. So we instead use position in the list.
1264  cu[cu.size()-1].m_number = B_Cu;
1265 
1266  for( unsigned i=0; i < cu.size()-1; ++i )
1267  {
1268  cu[i].m_number = i;
1269  }
1270 
1271  for( std::vector<LAYER>::const_iterator it = cu.begin(); it<cu.end(); ++it )
1272  {
1273  enabledLayers.set( it->m_number );
1274 
1275  if( it->m_visible )
1276  visibleLayers.set( it->m_number );
1277 
1278  m_board->SetLayerDescr( PCB_LAYER_ID( it->m_number ), *it );
1279 
1280  UTF8 name = it->m_name;
1281 
1282  m_layerIndices[ name ] = PCB_LAYER_ID( it->m_number );
1283  m_layerMasks[ name ] = LSET( PCB_LAYER_ID( it->m_number ) );
1284  }
1285 
1286  copperLayerCount = cu.size();
1287  }
1288 
1289  // process non-copper layers
1290  while( token != T_RIGHT )
1291  {
1292  LAYER_ID_MAP::const_iterator it = m_layerIndices.find( UTF8( layer.m_name ) );
1293 
1294  if( it == m_layerIndices.end() )
1295  {
1296  auto new_layer_it = v3_layer_names.find( layer.m_name.ToStdString() );
1297 
1298  if( new_layer_it != v3_layer_names.end() )
1299  it = m_layerIndices.find( new_layer_it->second );
1300 
1301  if( it == m_layerIndices.end() )
1302  {
1303  wxString error = wxString::Format(
1304  _( "Layer \"%s\" in file \"%s\" at line %d, is not in fixed layer hash" ),
1305  GetChars( layer.m_name ),
1306  GetChars( CurSource() ),
1307  CurLineNumber(),
1308  CurOffset()
1309  );
1310 
1311  THROW_IO_ERROR( error );
1312  }
1313 
1314  // If we are here, then we have found a translated layer name. Put it in the maps so that
1315  // items on this layer get the appropriate layer ID number
1316  m_layerIndices[ UTF8( layer.m_name ) ] = it->second;
1317  m_layerMasks[ UTF8( layer.m_name ) ] = it->second;
1318  layer.m_name = it->first;
1319  }
1320 
1321  layer.m_number = it->second;
1322  enabledLayers.set( layer.m_number );
1323 
1324  if( layer.m_visible )
1325  visibleLayers.set( layer.m_number );
1326 
1327  m_board->SetLayerDescr( it->second, layer );
1328 
1329  token = NextTok();
1330 
1331  if( token != T_LEFT )
1332  break;
1333 
1334  parseLayer( &layer );
1335  }
1336 
1337  // We need at least 2 copper layers and there must be an even number of them.
1338  if( copperLayerCount < 2 || (copperLayerCount % 2) != 0 )
1339  {
1340  wxString err = wxString::Format(
1341  _( "%d is not a valid layer count" ), copperLayerCount );
1342 
1343  THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
1344  }
1345 
1346  m_board->SetCopperLayerCount( copperLayerCount );
1347  m_board->SetEnabledLayers( enabledLayers );
1348 
1349  // call SetEnabledLayers before SetVisibleLayers()
1350  m_board->SetVisibleLayers( visibleLayers );
1351 }
1352 
1353 
1354 template<class T, class M>
1355 T PCB_PARSER::lookUpLayer( const M& aMap )
1356 {
1357  // avoid constructing another std::string, use lexer's directly
1358  typename M::const_iterator it = aMap.find( curText );
1359 
1360  if( it == aMap.end() )
1361  {
1362 #if 0 && defined(DEBUG)
1363  // dump the whole darn table, there's something wrong with it.
1364  for( it = aMap.begin(); it != aMap.end(); ++it )
1365  {
1366  wxLogDebug( &aMap == (void*)&m_layerIndices ? wxT( "lm[%s] = %d" ) :
1367  wxT( "lm[%s] = %08X" ), it->first.c_str(), it->second );
1368  }
1369 #endif
1370 
1371  m_undefinedLayers.insert( curText );
1372  return Rescue;
1373  }
1374 
1375  return it->second;
1376 }
1377 
1378 
1380 {
1381  wxCHECK_MSG( CurTok() == T_layer, UNDEFINED_LAYER,
1382  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as layer." ) );
1383 
1384  NextTok();
1385 
1386  PCB_LAYER_ID layerIndex = lookUpLayer<PCB_LAYER_ID>( m_layerIndices );
1387 
1388  // Handle closing ) in object parser.
1389 
1390  return layerIndex;
1391 }
1392 
1393 
1395 {
1396  wxCHECK_MSG( CurTok() == T_layers, LSET(),
1397  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) +
1398  wxT( " as item layer mask." ) );
1399 
1400  LSET layerMask;
1401 
1402  for( T token = NextTok(); token != T_RIGHT; token = NextTok() )
1403  {
1404  LSET mask = lookUpLayer<LSET>( m_layerMasks );
1405  layerMask |= mask;
1406  }
1407 
1408  return layerMask;
1409 }
1410 
1411 
1413 {
1414  wxCHECK_RET( CurTok() == T_setup,
1415  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as setup." ) );
1416 
1417  T token;
1418  NETCLASSPTR defaultNetClass = m_board->GetDesignSettings().GetDefault();
1419  BOARD_DESIGN_SETTINGS& designSettings = m_board->GetDesignSettings();
1420  ZONE_SETTINGS zoneSettings = m_board->GetZoneSettings();
1421 
1422  // Missing soldermask min width value means that the user has set the value to 0 and
1423  // not the default value (0.25mm)
1424  designSettings.m_SolderMaskMinWidth = 0;
1425 
1426  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1427  {
1428  if( token != T_LEFT )
1429  Expecting( T_LEFT );
1430 
1431  token = NextTok();
1432 
1433  switch( token )
1434  {
1435  case T_stackup:
1436  parseBoardStackup();
1437  break;
1438 
1439  case T_last_trace_width: // not used now
1440  /* lastTraceWidth =*/ parseBoardUnits( T_last_trace_width );
1441  NeedRIGHT();
1442  break;
1443 
1444  case T_user_trace_width:
1445  designSettings.m_TrackWidthList.push_back( parseBoardUnits( T_user_trace_width ) );
1446  NeedRIGHT();
1447  break;
1448 
1449  case T_trace_clearance:
1450  defaultNetClass->SetClearance( parseBoardUnits( T_trace_clearance ) );
1451  NeedRIGHT();
1452  break;
1453 
1454  case T_zone_clearance:
1455  zoneSettings.m_ZoneClearance = parseBoardUnits( T_zone_clearance );
1456  NeedRIGHT();
1457  break;
1458 
1459  case T_zone_45_only:
1460  zoneSettings.m_Zone_45_Only = parseBool();
1461  NeedRIGHT();
1462  break;
1463 
1464  case T_trace_min:
1465  designSettings.m_TrackMinWidth = parseBoardUnits( T_trace_min );
1466  NeedRIGHT();
1467  break;
1468 
1469  case T_via_size:
1470  defaultNetClass->SetViaDiameter( parseBoardUnits( T_via_size ) );
1471  NeedRIGHT();
1472  break;
1473 
1474  case T_via_drill:
1475  defaultNetClass->SetViaDrill( parseBoardUnits( T_via_drill ) );
1476  NeedRIGHT();
1477  break;
1478 
1479  case T_via_min_size:
1480  designSettings.m_ViasMinSize = parseBoardUnits( T_via_min_size );
1481  NeedRIGHT();
1482  break;
1483 
1484  case T_via_min_drill:
1485  designSettings.m_ViasMinDrill = parseBoardUnits( T_via_min_drill );
1486  NeedRIGHT();
1487  break;
1488 
1489  case T_user_via:
1490  {
1491  int viaSize = parseBoardUnits( "user via size" );
1492  int viaDrill = parseBoardUnits( "user via drill" );
1493  designSettings.m_ViasDimensionsList.emplace_back( VIA_DIMENSION( viaSize, viaDrill ) );
1494  NeedRIGHT();
1495  }
1496  break;
1497 
1498  case T_uvia_size:
1499  defaultNetClass->SetuViaDiameter( parseBoardUnits( T_uvia_size ) );
1500  NeedRIGHT();
1501  break;
1502 
1503  case T_uvia_drill:
1504  defaultNetClass->SetuViaDrill( parseBoardUnits( T_uvia_drill ) );
1505  NeedRIGHT();
1506  break;
1507 
1508  case T_uvias_allowed:
1509  designSettings.m_MicroViasAllowed = parseBool();
1510  NeedRIGHT();
1511  break;
1512 
1513  case T_blind_buried_vias_allowed:
1514  designSettings.m_BlindBuriedViaAllowed = parseBool();
1515  NeedRIGHT();
1516  break;
1517 
1518  case T_uvia_min_size:
1519  designSettings.m_MicroViasMinSize = parseBoardUnits( T_uvia_min_size );
1520  NeedRIGHT();
1521  break;
1522 
1523  case T_uvia_min_drill:
1524  designSettings.m_MicroViasMinDrill = parseBoardUnits( T_uvia_min_drill );
1525  NeedRIGHT();
1526  break;
1527 
1528  case T_user_diff_pair:
1529  {
1530  int width = parseBoardUnits( "user diff-pair width" );
1531  int gap = parseBoardUnits( "user diff-pair gap" );
1532  int viaGap = parseBoardUnits( "user diff-pair via gap" );
1533  designSettings.m_DiffPairDimensionsList.emplace_back( DIFF_PAIR_DIMENSION( width, gap, viaGap ) );
1534  NeedRIGHT();
1535  }
1536  break;
1537 
1538  case T_segment_width: // note: legacy (pre-6.0) token
1539  designSettings.m_LineThickness[ LAYER_CLASS_COPPER ] = parseBoardUnits( T_segment_width );
1540  NeedRIGHT();
1541  break;
1542 
1543  case T_edge_width: // note: legacy (pre-6.0) token
1544  designSettings.m_LineThickness[ LAYER_CLASS_EDGES ] = parseBoardUnits( T_edge_width );
1545  NeedRIGHT();
1546  break;
1547 
1548  case T_mod_edge_width: // note: legacy (pre-6.0) token
1549  designSettings.m_LineThickness[ LAYER_CLASS_SILK ] = parseBoardUnits( T_mod_edge_width );
1550  NeedRIGHT();
1551  break;
1552 
1553  case T_pcb_text_width: // note: legacy (pre-6.0) token
1554  designSettings.m_TextThickness[ LAYER_CLASS_COPPER ] = parseBoardUnits( T_pcb_text_width );
1555  NeedRIGHT();
1556  break;
1557 
1558  case T_mod_text_width: // note: legacy (pre-6.0) token
1559  designSettings.m_TextThickness[ LAYER_CLASS_SILK ] = parseBoardUnits( T_mod_text_width );
1560  NeedRIGHT();
1561  break;
1562 
1563  case T_pcb_text_size: // note: legacy (pre-6.0) token
1564  designSettings.m_TextSize[ LAYER_CLASS_COPPER ].x = parseBoardUnits( "pcb text width" );
1565  designSettings.m_TextSize[ LAYER_CLASS_COPPER ].y = parseBoardUnits( "pcb text height" );
1566  NeedRIGHT();
1567  break;
1568 
1569  case T_mod_text_size: // note: legacy (pre-6.0) token
1570  designSettings.m_TextSize[ LAYER_CLASS_SILK ].x = parseBoardUnits( "module text width" );
1571  designSettings.m_TextSize[ LAYER_CLASS_SILK ].y = parseBoardUnits( "module text height" );
1572  NeedRIGHT();
1573  break;
1574 
1575  case T_defaults:
1576  parseDefaults( designSettings );
1577  break;
1578 
1579  case T_pad_size:
1580  {
1581  wxSize sz;
1582  sz.SetWidth( parseBoardUnits( "master pad width" ) );
1583  sz.SetHeight( parseBoardUnits( "master pad height" ) );
1584  designSettings.m_Pad_Master.SetSize( sz );
1585  NeedRIGHT();
1586  }
1587  break;
1588 
1589  case T_pad_drill:
1590  {
1591  int drillSize = parseBoardUnits( T_pad_drill );
1592  designSettings.m_Pad_Master.SetDrillSize( wxSize( drillSize, drillSize ) );
1593  NeedRIGHT();
1594  }
1595  break;
1596 
1597  case T_pad_to_mask_clearance:
1598  designSettings.m_SolderMaskMargin = parseBoardUnits( T_pad_to_mask_clearance );
1599  NeedRIGHT();
1600  break;
1601 
1602  case T_solder_mask_min_width:
1603  designSettings.m_SolderMaskMinWidth = parseBoardUnits( T_solder_mask_min_width );
1604  NeedRIGHT();
1605  break;
1606 
1607  case T_pad_to_paste_clearance:
1608  designSettings.m_SolderPasteMargin = parseBoardUnits( T_pad_to_paste_clearance );
1609  NeedRIGHT();
1610  break;
1611 
1612  case T_pad_to_paste_clearance_ratio:
1613  designSettings.m_SolderPasteMarginRatio = parseDouble( T_pad_to_paste_clearance_ratio );
1614  NeedRIGHT();
1615  break;
1616 
1617  case T_aux_axis_origin:
1618  {
1619  int x = parseBoardUnits( "auxiliary origin X" );
1620  int y = parseBoardUnits( "auxiliary origin Y" );
1621  // m_board->SetAuxOrigin( wxPoint( x, y ) ); gets overwritten via SetDesignSettings below
1622  designSettings.m_AuxOrigin = wxPoint( x, y );
1623  NeedRIGHT();
1624  }
1625  break;
1626 
1627  case T_grid_origin:
1628  {
1629  int x = parseBoardUnits( "grid origin X" );
1630  int y = parseBoardUnits( "grid origin Y" );
1631  // m_board->SetGridOrigin( wxPoint( x, y ) ); gets overwritten SetDesignSettings below
1632  designSettings.m_GridOrigin = wxPoint( x, y );
1633  NeedRIGHT();
1634  }
1635  break;
1636 
1637  case T_visible_elements:
1638  designSettings.SetVisibleElements( parseHex() | MIN_VISIBILITY_MASK );
1639  NeedRIGHT();
1640  break;
1641 
1642  case T_max_error:
1643  designSettings.m_MaxError = parseBoardUnits( T_max_error );
1644  NeedRIGHT();
1645  break;
1646 
1647  case T_filled_areas_thickness:
1648  designSettings.m_ZoneUseNoOutlineInFill = not parseBool();
1649  NeedRIGHT();
1650  break;
1651 
1652  case T_pcbplotparams:
1653  {
1654  PCB_PLOT_PARAMS plotParams;
1655  PCB_PLOT_PARAMS_PARSER parser( reader );
1656  // parser must share the same current line as our current PCB parser
1657  // synchronize it.
1658  parser.SyncLineReaderWith( *this );
1659 
1660  plotParams.Parse( &parser );
1661  SyncLineReaderWith( parser );
1662 
1663  m_board->SetPlotOptions( plotParams );
1664  }
1665  break;
1666 
1667  default:
1668  Unexpected( CurText() );
1669  }
1670  }
1671 
1672  //m_board->SetDesignSettings( designSettings );
1673  m_board->SetZoneSettings( zoneSettings );
1674 }
1675 
1676 
1678 {
1679  T token;
1680 
1681  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1682  {
1683  if( token != T_LEFT )
1684  Expecting( T_LEFT );
1685 
1686  token = NextTok();
1687 
1688  switch( token )
1689  {
1690  case T_edge_clearance:
1691  designSettings.m_CopperEdgeClearance = parseBoardUnits( T_edge_clearance );
1692  NeedRIGHT();
1693  break;
1694 
1695  case T_copper_line_width:
1696  designSettings.m_LineThickness[ LAYER_CLASS_COPPER ] = parseBoardUnits( token );
1697  NeedRIGHT();
1698  break;
1699 
1700  case T_copper_text_dims:
1701  parseDefaultTextDims( designSettings, LAYER_CLASS_COPPER );
1702  break;
1703 
1704  case T_courtyard_line_width:
1705  designSettings.m_LineThickness[ LAYER_CLASS_COURTYARD ] = parseBoardUnits( token );
1706  NeedRIGHT();
1707  break;
1708 
1709  case T_edge_cuts_line_width:
1710  designSettings.m_LineThickness[ LAYER_CLASS_EDGES ] = parseBoardUnits( token );
1711  NeedRIGHT();
1712  break;
1713 
1714  case T_silk_line_width:
1715  designSettings.m_LineThickness[ LAYER_CLASS_SILK ] = parseBoardUnits( token );
1716  NeedRIGHT();
1717  break;
1718 
1719  case T_silk_text_dims:
1720  parseDefaultTextDims( designSettings, LAYER_CLASS_SILK );
1721  break;
1722 
1723  case T_other_layers_line_width:
1724  designSettings.m_LineThickness[ LAYER_CLASS_OTHERS ] = parseBoardUnits( token );
1725  NeedRIGHT();
1726  break;
1727 
1728  case T_other_layers_text_dims:
1729  parseDefaultTextDims( designSettings, LAYER_CLASS_OTHERS );
1730  break;
1731 
1732  case T_dimension_units:
1733  designSettings.m_DimensionUnits = parseInt( "dimension units" );
1734  NeedRIGHT();
1735  break;
1736 
1737  case T_dimension_precision:
1738  designSettings.m_DimensionPrecision = parseInt( "dimension precision" );
1739  NeedRIGHT();
1740  break;
1741 
1742  default:
1743  Unexpected( CurText() );
1744  }
1745  }
1746 }
1747 
1748 
1750 {
1751  T token;
1752 
1753  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1754  {
1755  if( token == T_LEFT )
1756  token = NextTok();
1757 
1758  switch( token )
1759  {
1760  case T_size:
1761  aSettings.m_TextSize[ aLayer ].x = parseBoardUnits( "default text size X" );
1762  aSettings.m_TextSize[ aLayer ].y = parseBoardUnits( "default text size Y" );
1763  NeedRIGHT();
1764  break;
1765 
1766  case T_thickness:
1767  aSettings.m_TextThickness[ aLayer ] = parseBoardUnits( "default text width" );
1768  NeedRIGHT();
1769  break;
1770 
1771  case T_italic:
1772  aSettings.m_TextItalic[ aLayer ] = true;
1773  break;
1774 
1775  case T_keep_upright:
1776  aSettings.m_TextUpright[ aLayer ] = true;
1777  break;
1778 
1779  default:
1780  Expecting( "size, thickness, italic or keep_upright" );
1781  }
1782  }
1783 }
1784 
1785 
1787 {
1788  wxCHECK_RET( CurTok() == T_net,
1789  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as net." ) );
1790 
1791  int netCode = parseInt( "net number" );
1792 
1793  NeedSYMBOLorNUMBER();
1794  wxString name = FromUTF8();
1795 
1796  NeedRIGHT();
1797 
1798  // net 0 should be already in list, so store this net
1799  // if it is not the net 0, or if the net 0 does not exists.
1800  // (TODO: a better test.)
1801  if( netCode > NETINFO_LIST::UNCONNECTED || !m_board->FindNet( NETINFO_LIST::UNCONNECTED ) )
1802  {
1803  NETINFO_ITEM* net = new NETINFO_ITEM( m_board, name, netCode );
1804  m_board->Add( net );
1805 
1806  // Store the new code mapping
1807  pushValueIntoMap( netCode, net->GetNet() );
1808  }
1809 }
1810 
1811 
1813 {
1814  wxCHECK_RET( CurTok() == T_net_class,
1815  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as net class." ) );
1816 
1817  T token;
1818 
1819  NETCLASSPTR nc = std::make_shared<NETCLASS>( wxEmptyString );
1820 
1821  // Read netclass name (can be a name or just a number like track width)
1822  NeedSYMBOLorNUMBER();
1823  nc->SetName( FromUTF8() );
1824  NeedSYMBOL();
1825  nc->SetDescription( FromUTF8() );
1826 
1827  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1828  {
1829  if( token != T_LEFT )
1830  Expecting( T_LEFT );
1831 
1832  token = NextTok();
1833 
1834  switch( token )
1835  {
1836  case T_clearance:
1837  nc->SetClearance( parseBoardUnits( T_clearance ) );
1838  break;
1839 
1840  case T_trace_width:
1841  nc->SetTrackWidth( parseBoardUnits( T_trace_width ) );
1842  break;
1843 
1844  case T_via_dia:
1845  nc->SetViaDiameter( parseBoardUnits( T_via_dia ) );
1846  break;
1847 
1848  case T_via_drill:
1849  nc->SetViaDrill( parseBoardUnits( T_via_drill ) );
1850  break;
1851 
1852  case T_uvia_dia:
1853  nc->SetuViaDiameter( parseBoardUnits( T_uvia_dia ) );
1854  break;
1855 
1856  case T_uvia_drill:
1857  nc->SetuViaDrill( parseBoardUnits( T_uvia_drill ) );
1858  break;
1859 
1860  case T_diff_pair_width:
1861  nc->SetDiffPairWidth( parseBoardUnits( T_diff_pair_width ) );
1862  break;
1863 
1864  case T_diff_pair_gap:
1865  nc->SetDiffPairGap( parseBoardUnits( T_diff_pair_gap ) );
1866  break;
1867 
1868  case T_add_net:
1869  NeedSYMBOLorNUMBER();
1870  nc->Add( FromUTF8() );
1871  break;
1872 
1873  default:
1874  Expecting( "clearance, trace_width, via_dia, via_drill, uvia_dia, uvia_drill, diff_pair_width, diff_pair_gap or add_net" );
1875  }
1876 
1877  NeedRIGHT();
1878  }
1879 
1880  if( !m_board->GetDesignSettings().m_NetClasses.Add( nc ) )
1881  {
1882  // Must have been a name conflict, this is a bad board file.
1883  // User may have done a hand edit to the file.
1884 
1885  // unique_ptr will delete nc on this code path
1886 
1887  wxString error;
1888  error.Printf( _( "Duplicate NETCLASS name \"%s\" in file \"%s\" at line %d, offset %d" ),
1889  nc->GetName().GetData(), CurSource().GetData(), CurLineNumber(), CurOffset() );
1890  THROW_IO_ERROR( error );
1891  }
1892 }
1893 
1894 
1895 DRAWSEGMENT* PCB_PARSER::parseDRAWSEGMENT( bool aAllowCirclesZeroWidth )
1896 {
1897  wxCHECK_MSG( CurTok() == T_gr_arc || CurTok() == T_gr_circle || CurTok() == T_gr_curve ||
1898  CurTok() == T_gr_line || CurTok() == T_gr_poly, NULL,
1899  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as DRAWSEGMENT." ) );
1900 
1901  T token;
1902  wxPoint pt;
1903  std::unique_ptr< DRAWSEGMENT > segment( new DRAWSEGMENT( NULL ) );
1904 
1905  switch( CurTok() )
1906  {
1907  case T_gr_arc:
1908  segment->SetShape( S_ARC );
1909  NeedLEFT();
1910  token = NextTok();
1911 
1912  // the start keyword actually gives the arc center
1913  // Allows also T_center for future change
1914  if( token != T_start && token != T_center )
1915  Expecting( T_start );
1916 
1917  pt.x = parseBoardUnits( "X coordinate" );
1918  pt.y = parseBoardUnits( "Y coordinate" );
1919  segment->SetCenter( pt );
1920  NeedRIGHT();
1921  NeedLEFT();
1922  token = NextTok();
1923 
1924  if( token != T_end ) // the end keyword actually gives the starting point of the arc
1925  Expecting( T_end );
1926 
1927  pt.x = parseBoardUnits( "X coordinate" );
1928  pt.y = parseBoardUnits( "Y coordinate" );
1929  segment->SetArcStart( pt );
1930  NeedRIGHT();
1931  break;
1932 
1933  case T_gr_circle:
1934  segment->SetShape( S_CIRCLE );
1935  NeedLEFT();
1936  token = NextTok();
1937 
1938  if( token != T_center )
1939  Expecting( T_center );
1940 
1941  pt.x = parseBoardUnits( "X coordinate" );
1942  pt.y = parseBoardUnits( "Y coordinate" );
1943  segment->SetCenter( pt );
1944  NeedRIGHT();
1945  NeedLEFT();
1946 
1947  token = NextTok();
1948 
1949  if( token != T_end )
1950  Expecting( T_end );
1951 
1952  pt.x = parseBoardUnits( "X coordinate" );
1953  pt.y = parseBoardUnits( "Y coordinate" );
1954  segment->SetEnd( pt );
1955  NeedRIGHT();
1956  break;
1957 
1958  case T_gr_curve:
1959  segment->SetShape( S_CURVE );
1960  NeedLEFT();
1961  token = NextTok();
1962 
1963  if( token != T_pts )
1964  Expecting( T_pts );
1965 
1966  segment->SetStart( parseXY() );
1967  segment->SetBezControl1( parseXY() );
1968  segment->SetBezControl2( parseXY() );
1969  segment->SetEnd( parseXY() );
1970  NeedRIGHT();
1971  break;
1972 
1973  case T_gr_line:
1974  // Default DRAWSEGMENT type is S_SEGMENT.
1975  NeedLEFT();
1976  token = NextTok();
1977 
1978  if( token != T_start )
1979  Expecting( T_start );
1980 
1981  pt.x = parseBoardUnits( "X coordinate" );
1982  pt.y = parseBoardUnits( "Y coordinate" );
1983  segment->SetStart( pt );
1984  NeedRIGHT();
1985  NeedLEFT();
1986  token = NextTok();
1987 
1988  if( token != T_end )
1989  Expecting( T_end );
1990 
1991  pt.x = parseBoardUnits( "X coordinate" );
1992  pt.y = parseBoardUnits( "Y coordinate" );
1993  segment->SetEnd( pt );
1994  NeedRIGHT();
1995  break;
1996 
1997  case T_gr_poly:
1998  {
1999  segment->SetShape( S_POLYGON );
2000  segment->SetWidth( 0 ); // this is the default value. will be (perhaps) modified later
2001  NeedLEFT();
2002  token = NextTok();
2003 
2004  if( token != T_pts )
2005  Expecting( T_pts );
2006 
2007  std::vector< wxPoint > pts;
2008 
2009  while( (token = NextTok()) != T_RIGHT )
2010  pts.push_back( parseXY() );
2011 
2012  segment->SetPolyPoints( pts );
2013  }
2014  break;
2015 
2016  default:
2017  Expecting( "gr_arc, gr_circle, gr_curve, gr_line, or gr_poly" );
2018  }
2019 
2020  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2021  {
2022  if( token != T_LEFT )
2023  Expecting( T_LEFT );
2024 
2025  token = NextTok();
2026 
2027  switch( token )
2028  {
2029  case T_angle:
2030  segment->SetAngle( parseDouble( "segment angle" ) * 10.0 );
2031  break;
2032 
2033  case T_layer:
2034  segment->SetLayer( parseBoardItemLayer() );
2035  break;
2036 
2037  case T_width:
2038  segment->SetWidth( parseBoardUnits( T_width ) );
2039  break;
2040 
2041  case T_tstamp:
2042  NextTok();
2043  const_cast<KIID&>( segment->m_Uuid ) = KIID( CurStr() );
2044  break;
2045 
2046  case T_status:
2047  segment->SetStatus( static_cast<STATUS_FLAGS>( parseHex() ) );
2048  break;
2049 
2050  default:
2051  Expecting( "layer, width, tstamp, or status" );
2052  }
2053 
2054  NeedRIGHT();
2055  }
2056 
2057  // Only filled polygons may have a zero-line width
2058  // This is not permitted in KiCad but some external tools generate invalid
2059  // files.
2060  // However in custom pad shapes, zero-line width is allowed for filled circles
2061  if( segment->GetShape() != S_POLYGON && segment->GetWidth() == 0 &&
2062  !( segment->GetShape() == S_CIRCLE && aAllowCirclesZeroWidth ) )
2063  segment->SetWidth( Millimeter2iu( DEFAULT_LINE_WIDTH ) );
2064 
2065  return segment.release();
2066 }
2067 
2068 
2070 {
2071  wxCHECK_MSG( CurTok() == T_gr_text, NULL,
2072  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as TEXTE_PCB." ) );
2073 
2074  T token;
2075 
2076  std::unique_ptr<TEXTE_PCB> text( new TEXTE_PCB( m_board ) );
2077  NeedSYMBOLorNUMBER();
2078 
2079  text->SetText( FromUTF8() );
2080  NeedLEFT();
2081  token = NextTok();
2082 
2083  if( token != T_at )
2084  Expecting( T_at );
2085 
2086  wxPoint pt;
2087 
2088  pt.x = parseBoardUnits( "X coordinate" );
2089  pt.y = parseBoardUnits( "Y coordinate" );
2090  text->SetTextPos( pt );
2091 
2092  // If there is no orientation defined, then it is the default value of 0 degrees.
2093  token = NextTok();
2094 
2095  if( token == T_NUMBER )
2096  {
2097  text->SetTextAngle( parseDouble() * 10.0 );
2098  NeedRIGHT();
2099  }
2100  else if( token != T_RIGHT )
2101  {
2102  Unexpected( CurText() );
2103  }
2104 
2105  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2106  {
2107  if( token != T_LEFT )
2108  Expecting( T_LEFT );
2109 
2110  token = NextTok();
2111 
2112  switch( token )
2113  {
2114  case T_layer:
2115  text->SetLayer( parseBoardItemLayer() );
2116  NeedRIGHT();
2117  break;
2118 
2119  case T_tstamp:
2120  NextTok();
2121  const_cast<KIID&>( text->m_Uuid ) = KIID( CurStr() );
2122  NeedRIGHT();
2123  break;
2124 
2125  case T_effects:
2126  parseEDA_TEXT( (EDA_TEXT*) text.get() );
2127  break;
2128 
2129  default:
2130  Expecting( "layer, tstamp or effects" );
2131  }
2132  }
2133 
2134  return text.release();
2135 }
2136 
2137 
2139 {
2140  wxCHECK_MSG( CurTok() == T_dimension, NULL,
2141  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as DIMENSION." ) );
2142 
2143  T token;
2144 
2145  std::unique_ptr<DIMENSION> dimension( new DIMENSION( NULL ) );
2146 
2147  dimension->SetValue( parseBoardUnits( "dimension value" ) );
2148  NeedLEFT();
2149  token = NextTok();
2150 
2151  if( token != T_width )
2152  Expecting( T_width );
2153 
2154  dimension->SetWidth( parseBoardUnits( "dimension width value" ) );
2155  NeedRIGHT();
2156 
2157  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2158  {
2159  if( token != T_LEFT )
2160  Expecting( T_LEFT );
2161 
2162  token = NextTok();
2163 
2164  switch( token )
2165  {
2166  case T_layer:
2167  dimension->SetLayer( parseBoardItemLayer() );
2168  NeedRIGHT();
2169  break;
2170 
2171  case T_tstamp:
2172  NextTok();
2173  const_cast<KIID&>( dimension->m_Uuid ) = KIID( CurStr() );
2174  NeedRIGHT();
2175  break;
2176 
2177  case T_gr_text:
2178  {
2179  TEXTE_PCB* text = parseTEXTE_PCB();
2180  dimension->Text() = *text;
2181 
2182  // The text is part of the dimension and shares its uuid
2183  const_cast<KIID&>( dimension->Text().m_Uuid ) = dimension->m_Uuid;
2184 
2185  // Fetch other dimension properties out of the text item
2186  dimension->SetPosition( text->GetTextPos() );
2187 
2188  EDA_UNITS units = EDA_UNITS::INCHES;
2189  bool useMils = false;
2190  FetchUnitsFromString( text->GetText(), units, useMils );
2191  dimension->SetUnits( units, useMils );
2192 
2193  delete text;
2194  break;
2195  }
2196 
2197  case T_feature1:
2198  NeedLEFT();
2199  token = NextTok();
2200 
2201  if( token != T_pts )
2202  Expecting( T_pts );
2203 
2204  parseXY( &dimension->m_featureLineDO.x, &dimension->m_featureLineDO.y );
2205  parseXY( &dimension->m_featureLineDF.x, &dimension->m_featureLineDF.y );
2206  dimension->UpdateHeight();
2207  NeedRIGHT();
2208  NeedRIGHT();
2209  break;
2210 
2211  case T_feature2:
2212  NeedLEFT();
2213  token = NextTok();
2214 
2215  if( token != T_pts )
2216  Expecting( T_pts );
2217 
2218  parseXY( &dimension->m_featureLineGO.x, &dimension->m_featureLineGO.y );
2219  parseXY( &dimension->m_featureLineGF.x, &dimension->m_featureLineGF.y );
2220  dimension->UpdateHeight();
2221  NeedRIGHT();
2222  NeedRIGHT();
2223  break;
2224 
2225 
2226  case T_crossbar:
2227  NeedLEFT();
2228  token = NextTok();
2229 
2230  if( token != T_pts )
2231  Expecting( T_pts );
2232 
2233  parseXY( &dimension->m_crossBarO.x, &dimension->m_crossBarO.y );
2234  parseXY( &dimension->m_crossBarF.x, &dimension->m_crossBarF.y );
2235  dimension->UpdateHeight();
2236  NeedRIGHT();
2237  NeedRIGHT();
2238  break;
2239 
2240  case T_arrow1a:
2241  NeedLEFT();
2242  token = NextTok();
2243 
2244  if( token != T_pts )
2245  Expecting( T_pts );
2246 
2247  parseXY( &dimension->m_crossBarF.x, &dimension->m_crossBarF.y );
2248  parseXY( &dimension->m_arrowD1F.x, &dimension->m_arrowD1F.y );
2249  NeedRIGHT();
2250  NeedRIGHT();
2251  break;
2252 
2253  case T_arrow1b:
2254  NeedLEFT();
2255  token = NextTok();
2256 
2257  if( token != T_pts )
2258  Expecting( T_pts );
2259 
2260  parseXY( &dimension->m_crossBarF.x, &dimension->m_crossBarF.y );
2261  parseXY( &dimension->m_arrowD2F.x, &dimension->m_arrowD2F.y );
2262  NeedRIGHT();
2263  NeedRIGHT();
2264  break;
2265 
2266  case T_arrow2a:
2267  NeedLEFT();
2268  token = NextTok();
2269 
2270  if( token != T_pts )
2271  Expecting( T_pts );
2272 
2273  parseXY( &dimension->m_crossBarO.x, &dimension->m_crossBarO.y );
2274  parseXY( &dimension->m_arrowG1F.x, &dimension->m_arrowG1F.y );
2275  NeedRIGHT();
2276  NeedRIGHT();
2277  break;
2278 
2279  case T_arrow2b:
2280  NeedLEFT();
2281  token = NextTok();
2282 
2283  if( token != T_pts )
2284  Expecting( T_pts );
2285 
2286  parseXY( &dimension->m_crossBarO.x, &dimension->m_crossBarO.y );
2287  parseXY( &dimension->m_arrowG2F.x, &dimension->m_arrowG2F.y );
2288  NeedRIGHT();
2289  NeedRIGHT();
2290  break;
2291 
2292  default:
2293  Expecting( "layer, tstamp, gr_text, feature1, feature2 crossbar, arrow1a, "
2294  "arrow1b, arrow2a, or arrow2b" );
2295  }
2296  }
2297 
2298  return dimension.release();
2299 }
2300 
2301 
2302 MODULE* PCB_PARSER::parseMODULE( wxArrayString* aInitialComments )
2303 {
2304  try
2305  {
2306  return parseMODULE_unchecked( aInitialComments );
2307  }
2308  catch( const PARSE_ERROR& parse_error )
2309  {
2310  if( m_tooRecent )
2311  throw FUTURE_FORMAT_ERROR( parse_error, GetRequiredVersion() );
2312  else
2313  throw;
2314  }
2315 }
2316 
2317 
2318 MODULE* PCB_PARSER::parseMODULE_unchecked( wxArrayString* aInitialComments )
2319 {
2320  wxCHECK_MSG( CurTok() == T_module, NULL,
2321  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as MODULE." ) );
2322 
2323  wxString name;
2324  wxPoint pt;
2325  T token;
2326  LIB_ID fpid;
2327 
2328  std::unique_ptr<MODULE> module( new MODULE( m_board ) );
2329 
2330  module->SetInitialComments( aInitialComments );
2331 
2332  token = NextTok();
2333 
2334  if( !IsSymbol( token ) && token != T_NUMBER )
2335  Expecting( "symbol|number" );
2336 
2337  name = FromUTF8();
2338 
2339  if( !name.IsEmpty() && fpid.Parse( name, LIB_ID::ID_PCB, true ) >= 0 )
2340  {
2341  wxString error;
2342  error.Printf( _( "Invalid footprint ID in\nfile: \"%s\"\nline: %d\noffset: %d" ),
2343  GetChars( CurSource() ), CurLineNumber(), CurOffset() );
2344  THROW_IO_ERROR( error );
2345  }
2346 
2347  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2348  {
2349  if( token == T_LEFT )
2350  token = NextTok();
2351 
2352  switch( token )
2353  {
2354  case T_version:
2355  {
2356  // Theoretically a module nested in a PCB could declare its own version, though
2357  // as of writing this comment we don't do that. Just in case, take the greater
2358  // version.
2359  int this_version = parseInt( FromUTF8().mb_str( wxConvUTF8 ) );
2360  NeedRIGHT();
2361  m_requiredVersion = std::max( m_requiredVersion, this_version );
2362  m_tooRecent = ( m_requiredVersion > SEXPR_BOARD_FILE_VERSION );
2363  break;
2364  }
2365 
2366  case T_locked:
2367  module->SetLocked( true );
2368  break;
2369 
2370  case T_placed:
2371  module->SetIsPlaced( true );
2372  break;
2373 
2374  case T_layer:
2375  {
2376  // Footprints can be only on the front side or the back side.
2377  // but because we can find some stupid layer in file, ensure a
2378  // acceptable layer is set for the footprint
2379  PCB_LAYER_ID layer = parseBoardItemLayer();
2380  module->SetLayer( layer == B_Cu ? B_Cu : F_Cu );
2381  }
2382  NeedRIGHT();
2383  break;
2384 
2385  case T_tedit:
2386  module->SetLastEditTime( parseHex() );
2387  NeedRIGHT();
2388  break;
2389 
2390  case T_tstamp:
2391  NextTok();
2392  const_cast<KIID&>( module->m_Uuid ) = KIID( CurStr() );
2393  NeedRIGHT();
2394  break;
2395 
2396  case T_at:
2397  pt.x = parseBoardUnits( "X coordinate" );
2398  pt.y = parseBoardUnits( "Y coordinate" );
2399  module->SetPosition( pt );
2400  token = NextTok();
2401 
2402  if( token == T_NUMBER )
2403  {
2404  module->SetOrientation( parseDouble() * 10.0 );
2405  NeedRIGHT();
2406  }
2407  else if( token != T_RIGHT )
2408  {
2409  Expecting( T_RIGHT );
2410  }
2411 
2412  break;
2413 
2414  case T_descr:
2415  NeedSYMBOLorNUMBER(); // some symbols can be 0508, so a number is also a symbol here
2416  module->SetDescription( FromUTF8() );
2417  NeedRIGHT();
2418  break;
2419 
2420  case T_tags:
2421  NeedSYMBOLorNUMBER(); // some symbols can be 0508, so a number is also a symbol here
2422  module->SetKeywords( FromUTF8() );
2423  NeedRIGHT();
2424  break;
2425 
2426  case T_path:
2427  NeedSYMBOLorNUMBER(); // Paths can be numerical so a number is also a symbol here
2428  module->SetPath( KIID_PATH( FromUTF8() ) );
2429  NeedRIGHT();
2430  break;
2431 
2432  case T_autoplace_cost90:
2433  module->SetPlacementCost90( parseInt( "auto place cost at 90 degrees" ) );
2434  NeedRIGHT();
2435  break;
2436 
2437  case T_autoplace_cost180:
2438  module->SetPlacementCost180( parseInt( "auto place cost at 180 degrees" ) );
2439  NeedRIGHT();
2440  break;
2441 
2442  case T_solder_mask_margin:
2443  module->SetLocalSolderMaskMargin( parseBoardUnits( "local solder mask margin value" ) );
2444  NeedRIGHT();
2445  break;
2446 
2447  case T_solder_paste_margin:
2448  module->SetLocalSolderPasteMargin(
2449  parseBoardUnits( "local solder paste margin value" ) );
2450  NeedRIGHT();
2451  break;
2452 
2453  case T_solder_paste_ratio:
2454  module->SetLocalSolderPasteMarginRatio(
2455  parseDouble( "local solder paste margin ratio value" ) );
2456  NeedRIGHT();
2457  break;
2458 
2459  case T_clearance:
2460  module->SetLocalClearance( parseBoardUnits( "local clearance value" ) );
2461  NeedRIGHT();
2462  break;
2463 
2464  case T_zone_connect:
2465  module->SetZoneConnection( (ZONE_CONNECTION) parseInt( "zone connection value" ) );
2466  NeedRIGHT();
2467  break;
2468 
2469  case T_thermal_width:
2470  module->SetThermalWidth( parseBoardUnits( "thermal width value" ) );
2471  NeedRIGHT();
2472  break;
2473 
2474  case T_thermal_gap:
2475  module->SetThermalGap( parseBoardUnits( "thermal gap value" ) );
2476  NeedRIGHT();
2477  break;
2478 
2479  case T_attr:
2480  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2481  {
2482  switch( token )
2483  {
2484  case T_smd:
2485  module->SetAttributes( module->GetAttributes() | MOD_CMS );
2486  break;
2487 
2488  case T_virtual:
2489  module->SetAttributes( module->GetAttributes() | MOD_VIRTUAL );
2490  break;
2491 
2492  default:
2493  Expecting( "smd and/or virtual" );
2494  }
2495  }
2496  break;
2497 
2498  case T_fp_text:
2499  {
2500  TEXTE_MODULE* text = parseTEXTE_MODULE();
2501  text->SetParent( module.get() );
2502  double orientation = text->GetTextAngle();
2503  orientation -= module->GetOrientation();
2504  text->SetTextAngle( orientation );
2505  text->SetDrawCoord();
2506 
2507  switch( text->GetType() )
2508  {
2510  module->Reference() = *text;
2511  delete text;
2512  break;
2513 
2515  module->Value() = *text;
2516  delete text;
2517  break;
2518 
2519  default:
2520  module->Add( text );
2521  }
2522  }
2523  break;
2524 
2525  case T_fp_arc:
2526  {
2527  EDGE_MODULE* em = parseEDGE_MODULE();
2528 
2529  // Drop 0 and NaN angles as these can corrupt/crash the schematic
2530  if( std::isnormal( em->GetAngle() ) )
2531  {
2532  em->SetParent( module.get() );
2533  em->SetDrawCoord();
2534  module->Add( em );
2535  }
2536  else
2537  delete em;
2538  }
2539 
2540  break;
2541 
2542  case T_fp_circle:
2543  case T_fp_curve:
2544  case T_fp_line:
2545  case T_fp_poly:
2546  {
2547  EDGE_MODULE* em = parseEDGE_MODULE();
2548  em->SetParent( module.get() );
2549  em->SetDrawCoord();
2550  module->Add( em );
2551  }
2552 
2553  break;
2554 
2555  case T_pad:
2556  {
2557  D_PAD* pad = parseD_PAD( module.get() );
2558  pt = pad->GetPos0();
2559 
2560  RotatePoint( &pt, module->GetOrientation() );
2561  pad->SetPosition( pt + module->GetPosition() );
2562  module->Add( pad, ADD_MODE::APPEND );
2563  }
2564 
2565  break;
2566 
2567  case T_model:
2568  module->Add3DModel( parse3DModel() );
2569  break;
2570 
2571  case T_zone:
2572  {
2573  ZONE_CONTAINER* zone = parseZONE_CONTAINER( module.get() );
2574  module->Add( zone, ADD_MODE::APPEND );
2575  }
2576  break;
2577 
2578  default:
2579  Expecting(
2580  "locked, placed, tedit, tstamp, at, descr, tags, path, "
2581  "autoplace_cost90, autoplace_cost180, solder_mask_margin, "
2582  "solder_paste_margin, solder_paste_ratio, clearance, "
2583  "zone_connect, thermal_width, thermal_gap, attr, fp_text, "
2584  "fp_arc, fp_circle, fp_curve, fp_line, fp_poly, pad, "
2585  "zone, or model" );
2586  }
2587  }
2588 
2589  module->SetFPID( fpid );
2590  module->CalculateBoundingBox();
2591 
2592  return module.release();
2593 }
2594 
2595 
2597 {
2598  wxCHECK_MSG( CurTok() == T_fp_text, NULL,
2599  wxString::Format( wxT( "Cannot parse %s as TEXTE_MODULE at line %d, offset %d." ),
2600  GetChars( GetTokenString( CurTok() ) ),
2601  CurLineNumber(), CurOffset() ) );
2602 
2603  T token = NextTok();
2604 
2605  std::unique_ptr<TEXTE_MODULE> text( new TEXTE_MODULE( NULL ) );
2606 
2607  switch( token )
2608  {
2609  case T_reference:
2610  text->SetType( TEXTE_MODULE::TEXT_is_REFERENCE );
2611  break;
2612 
2613  case T_value:
2614  text->SetType( TEXTE_MODULE::TEXT_is_VALUE );
2615  break;
2616 
2617  case T_user:
2618  break; // Default type is user text.
2619 
2620  default:
2621  THROW_IO_ERROR( wxString::Format( _( "Cannot handle footprint text type %s" ),
2622  GetChars( FromUTF8() ) ) );
2623  }
2624 
2625  NeedSYMBOLorNUMBER();
2626 
2627  text->SetText( FromUTF8() );
2628  NeedLEFT();
2629  token = NextTok();
2630 
2631  if( token != T_at )
2632  Expecting( T_at );
2633 
2634  wxPoint pt;
2635 
2636  pt.x = parseBoardUnits( "X coordinate" );
2637  pt.y = parseBoardUnits( "Y coordinate" );
2638  text->SetPos0( pt );
2639 
2640  NextTok();
2641 
2642  if( CurTok() == T_NUMBER )
2643  {
2644  text->SetTextAngle( parseDouble() * 10.0 );
2645  NextTok();
2646  }
2647 
2648  if( CurTok() == T_unlocked )
2649  {
2650  text->SetKeepUpright( false );
2651  NextTok();
2652  }
2653 
2654  if( CurTok() != T_RIGHT )
2655  {
2656  Unexpected( CurText() );
2657  }
2658 
2659  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2660  {
2661  if( token == T_LEFT )
2662  token = NextTok();
2663 
2664  switch( token )
2665  {
2666  case T_layer:
2667  text->SetLayer( parseBoardItemLayer() );
2668  NeedRIGHT();
2669  break;
2670 
2671  case T_hide:
2672  text->SetVisible( false );
2673  break;
2674 
2675  case T_effects:
2676  parseEDA_TEXT( (EDA_TEXT*) text.get() );
2677  break;
2678 
2679  default:
2680  Expecting( "hide or effects" );
2681  }
2682  }
2683 
2684  return text.release();
2685 }
2686 
2687 
2689 {
2690  wxCHECK_MSG( CurTok() == T_fp_arc || CurTok() == T_fp_circle || CurTok() == T_fp_curve ||
2691  CurTok() == T_fp_line || CurTok() == T_fp_poly, NULL,
2692  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as EDGE_MODULE." ) );
2693 
2694  wxPoint pt;
2695  T token;
2696 
2697  std::unique_ptr< EDGE_MODULE > segment( new EDGE_MODULE( NULL ) );
2698 
2699  switch( CurTok() )
2700  {
2701  case T_fp_arc:
2702  segment->SetShape( S_ARC );
2703  NeedLEFT();
2704  token = NextTok();
2705 
2706  // the start keyword actually gives the arc center
2707  // Allows also T_center for future change
2708  if( token != T_start && token != T_center )
2709  Expecting( T_start );
2710 
2711  pt.x = parseBoardUnits( "X coordinate" );
2712  pt.y = parseBoardUnits( "Y coordinate" );
2713  segment->SetStart0( pt );
2714  NeedRIGHT();
2715  NeedLEFT();
2716  token = NextTok();
2717 
2718  if( token != T_end ) // end keyword actually gives the starting point of the arc
2719  Expecting( T_end );
2720 
2721  pt.x = parseBoardUnits( "X coordinate" );
2722  pt.y = parseBoardUnits( "Y coordinate" );
2723  segment->SetEnd0( pt );
2724  NeedRIGHT();
2725  NeedLEFT();
2726  token = NextTok();
2727 
2728  if( token != T_angle )
2729  Expecting( T_angle );
2730 
2731  segment->SetAngle( parseDouble( "segment angle" ) * 10.0 );
2732  NeedRIGHT();
2733  break;
2734 
2735  case T_fp_circle:
2736  segment->SetShape( S_CIRCLE );
2737  NeedLEFT();
2738  token = NextTok();
2739 
2740  if( token != T_center )
2741  Expecting( T_center );
2742 
2743  pt.x = parseBoardUnits( "X coordinate" );
2744  pt.y = parseBoardUnits( "Y coordinate" );
2745  segment->SetStart0( pt );
2746  NeedRIGHT();
2747  NeedLEFT();
2748  token = NextTok();
2749 
2750  if( token != T_end )
2751  Expecting( T_end );
2752 
2753  pt.x = parseBoardUnits( "X coordinate" );
2754  pt.y = parseBoardUnits( "Y coordinate" );
2755  segment->SetEnd0( pt );
2756  NeedRIGHT();
2757  break;
2758 
2759  case T_fp_curve:
2760  segment->SetShape( S_CURVE );
2761  NeedLEFT();
2762  token = NextTok();
2763 
2764  if( token != T_pts )
2765  Expecting( T_pts );
2766 
2767  segment->SetStart0( parseXY() );
2768  segment->SetBezier0_C1( parseXY() );
2769  segment->SetBezier0_C2( parseXY() );
2770  segment->SetEnd0( parseXY() );
2771  NeedRIGHT();
2772  break;
2773 
2774  case T_fp_line:
2775  // Default DRAWSEGMENT type is S_SEGMENT.
2776  NeedLEFT();
2777  token = NextTok();
2778 
2779  if( token != T_start )
2780  Expecting( T_start );
2781 
2782  pt.x = parseBoardUnits( "X coordinate" );
2783  pt.y = parseBoardUnits( "Y coordinate" );
2784  segment->SetStart0( pt );
2785 
2786  NeedRIGHT();
2787  NeedLEFT();
2788  token = NextTok();
2789 
2790  if( token != T_end )
2791  Expecting( T_end );
2792 
2793  pt.x = parseBoardUnits( "X coordinate" );
2794  pt.y = parseBoardUnits( "Y coordinate" );
2795  segment->SetEnd0( pt );
2796  NeedRIGHT();
2797  break;
2798 
2799  case T_fp_poly:
2800  {
2801  segment->SetShape( S_POLYGON );
2802  NeedLEFT();
2803  token = NextTok();
2804 
2805  if( token != T_pts )
2806  Expecting( T_pts );
2807 
2808  std::vector< wxPoint > pts;
2809 
2810  while( (token = NextTok()) != T_RIGHT )
2811  pts.push_back( parseXY() );
2812 
2813  segment->SetPolyPoints( pts );
2814  }
2815  break;
2816 
2817  default:
2818  Expecting( "fp_arc, fp_circle, fp_curve, fp_line, or fp_poly" );
2819  }
2820 
2821  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2822  {
2823  if( token != T_LEFT )
2824  Expecting( T_LEFT );
2825 
2826  token = NextTok();
2827 
2828  switch( token )
2829  {
2830  case T_layer:
2831  segment->SetLayer( parseBoardItemLayer() );
2832  break;
2833 
2834  case T_width:
2835  segment->SetWidth( parseBoardUnits( T_width ) );
2836  break;
2837 
2838  case T_tstamp:
2839  NextTok();
2840  const_cast<KIID&>( segment->m_Uuid ) = KIID( CurStr() );
2841  break;
2842 
2843  case T_status:
2844  segment->SetStatus( static_cast<STATUS_FLAGS>( parseHex() ) );
2845  break;
2846 
2847  default:
2848  Expecting( "layer or width" );
2849  }
2850 
2851  NeedRIGHT();
2852  }
2853 
2854  // Only filled polygons may have a zero-line width
2855  // This is not permitted in KiCad but some external tools generate invalid
2856  // files.
2857  if( segment->GetShape() != S_POLYGON && segment->GetWidth() == 0 )
2858  segment->SetWidth( Millimeter2iu( DEFAULT_LINE_WIDTH ) );
2859 
2860  return segment.release();
2861 }
2862 
2863 
2865 {
2866  wxCHECK_MSG( CurTok() == T_pad, NULL,
2867  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as D_PAD." ) );
2868 
2869  wxSize sz;
2870  wxPoint pt;
2871 
2872  std::unique_ptr< D_PAD > pad( new D_PAD( aParent ) );
2873 
2874  NeedSYMBOLorNUMBER();
2875  pad->SetName( FromUTF8() );
2876 
2877  T token = NextTok();
2878 
2879  switch( token )
2880  {
2881  case T_thru_hole:
2882  pad->SetAttribute( PAD_ATTRIB_STANDARD );
2883  break;
2884 
2885  case T_smd:
2886  pad->SetAttribute( PAD_ATTRIB_SMD );
2887 
2888  // Default D_PAD object is thru hole with drill.
2889  // SMD pads have no hole
2890  pad->SetDrillSize( wxSize( 0, 0 ) );
2891  break;
2892 
2893  case T_connect:
2894  pad->SetAttribute( PAD_ATTRIB_CONN );
2895 
2896  // Default D_PAD object is thru hole with drill.
2897  // CONN pads have no hole
2898  pad->SetDrillSize( wxSize( 0, 0 ) );
2899  break;
2900 
2901  case T_np_thru_hole:
2902  pad->SetAttribute( PAD_ATTRIB_HOLE_NOT_PLATED );
2903  break;
2904 
2905  default:
2906  Expecting( "thru_hole, smd, connect, or np_thru_hole" );
2907  }
2908 
2909  token = NextTok();
2910 
2911  switch( token )
2912  {
2913  case T_circle:
2914  pad->SetShape( PAD_SHAPE_CIRCLE );
2915  break;
2916 
2917  case T_rect:
2918  pad->SetShape( PAD_SHAPE_RECT );
2919  break;
2920 
2921  case T_oval:
2922  pad->SetShape( PAD_SHAPE_OVAL );
2923  break;
2924 
2925  case T_trapezoid:
2926  pad->SetShape( PAD_SHAPE_TRAPEZOID );
2927  break;
2928 
2929  case T_roundrect:
2930  // Note: the shape can be PAD_SHAPE_ROUNDRECT or PAD_SHAPE_CHAMFERED_RECT
2931  // (if champfer parameters are found later in pad descr.)
2932  pad->SetShape( PAD_SHAPE_ROUNDRECT );
2933  break;
2934 
2935  case T_custom:
2936  pad->SetShape( PAD_SHAPE_CUSTOM );
2937  break;
2938 
2939  default:
2940  Expecting( "circle, rectangle, roundrect, oval, trapezoid or custom" );
2941  }
2942 
2943  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2944  {
2945  if( token != T_LEFT )
2946  Expecting( T_LEFT );
2947 
2948  token = NextTok();
2949 
2950  switch( token )
2951  {
2952  case T_size:
2953  sz.SetWidth( parseBoardUnits( "width value" ) );
2954  sz.SetHeight( parseBoardUnits( "height value" ) );
2955  pad->SetSize( sz );
2956  NeedRIGHT();
2957  break;
2958 
2959  case T_at:
2960  pt.x = parseBoardUnits( "X coordinate" );
2961  pt.y = parseBoardUnits( "Y coordinate" );
2962  pad->SetPos0( pt );
2963  token = NextTok();
2964 
2965  if( token == T_NUMBER )
2966  {
2967  pad->SetOrientation( parseDouble() * 10.0 );
2968  NeedRIGHT();
2969  }
2970  else if( token != T_RIGHT )
2971  {
2972  Expecting( ") or angle value" );
2973  }
2974 
2975  break;
2976 
2977  case T_rect_delta:
2978  {
2979  wxSize delta;
2980  delta.SetWidth( parseBoardUnits( "rectangle delta width" ) );
2981  delta.SetHeight( parseBoardUnits( "rectangle delta height" ) );
2982  pad->SetDelta( delta );
2983  NeedRIGHT();
2984  }
2985  break;
2986 
2987  case T_drill:
2988  {
2989  bool haveWidth = false;
2990  wxSize drillSize = pad->GetDrillSize();
2991 
2992  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2993  {
2994  if( token == T_LEFT )
2995  token = NextTok();
2996 
2997  switch( token )
2998  {
2999  case T_oval:
3000  pad->SetDrillShape( PAD_DRILL_SHAPE_OBLONG );
3001  break;
3002 
3003  case T_NUMBER:
3004  {
3005  if( !haveWidth )
3006  {
3007  drillSize.SetWidth( parseBoardUnits() );
3008 
3009  // If height is not defined the width and height are the same.
3010  drillSize.SetHeight( drillSize.GetWidth() );
3011  haveWidth = true;
3012  }
3013  else
3014  {
3015  drillSize.SetHeight( parseBoardUnits() );
3016  }
3017 
3018  }
3019  break;
3020 
3021  case T_offset:
3022  pt.x = parseBoardUnits( "drill offset x" );
3023  pt.y = parseBoardUnits( "drill offset y" );
3024  pad->SetOffset( pt );
3025  NeedRIGHT();
3026  break;
3027 
3028  default:
3029  Expecting( "oval, size, or offset" );
3030  }
3031  }
3032 
3033  // This fixes a bug caused by setting the default D_PAD drill size to a value
3034  // other than 0 used to fix a bunch of debug assertions even though it is defined
3035  // as a through hole pad. Wouldn't a though hole pad with no drill be a surface
3036  // mount pad (or a conn pad which is a smd pad with no solder paste)?
3037  if( ( pad->GetAttribute() != PAD_ATTRIB_SMD ) && ( pad->GetAttribute() != PAD_ATTRIB_CONN ) )
3038  pad->SetDrillSize( drillSize );
3039  else
3040  pad->SetDrillSize( wxSize( 0, 0 ) );
3041 
3042  }
3043  break;
3044 
3045  case T_layers:
3046  {
3047  LSET layerMask = parseBoardItemLayersAsMask();
3048  pad->SetLayerSet( layerMask );
3049  }
3050  break;
3051 
3052  case T_net:
3053  if( ! pad->SetNetCode( getNetCode( parseInt( "net number" ) ), /* aNoAssert */ true ) )
3054  {
3055  wxLogError( wxString::Format( _( "Invalid net ID in\n"
3056  "file: '%s'\n"
3057  "line: %d\n"
3058  "offset: %d" ),
3059  CurSource(),
3060  CurLineNumber(),
3061  CurOffset() ) );
3062  }
3063 
3064  NeedSYMBOLorNUMBER();
3065 
3066  // Test validity of the netname in file for netcodes expected having a net name
3067  if( m_board && pad->GetNetCode() > 0 &&
3068  FromUTF8() != m_board->FindNet( pad->GetNetCode() )->GetNetname() )
3069  {
3070  pad->SetNetCode( NETINFO_LIST::ORPHANED, /* aNoAssert */ true );
3071  wxLogError( wxString::Format( _( "Net name doesn't match net ID in\n"
3072  "file: '%s'\n"
3073  "line: %d\n"
3074  "offset: %d" ),
3075  CurSource(),
3076  CurLineNumber(),
3077  CurOffset() ) );
3078  }
3079 
3080  NeedRIGHT();
3081  break;
3082 
3083  case T_pinfunction:
3084  NeedSYMBOLorNUMBER();
3085  pad->SetPinFunction( FromUTF8() );
3086  NeedRIGHT();
3087  break;
3088 
3089  case T_die_length:
3090  pad->SetPadToDieLength( parseBoardUnits( T_die_length ) );
3091  NeedRIGHT();
3092  break;
3093 
3094  case T_solder_mask_margin:
3095  pad->SetLocalSolderMaskMargin( parseBoardUnits( T_solder_mask_margin ) );
3096  NeedRIGHT();
3097  break;
3098 
3099  case T_solder_paste_margin:
3100  pad->SetLocalSolderPasteMargin( parseBoardUnits( T_solder_paste_margin ) );
3101  NeedRIGHT();
3102  break;
3103 
3104  case T_solder_paste_margin_ratio:
3105  pad->SetLocalSolderPasteMarginRatio(
3106  parseDouble( "pad local solder paste margin ratio value" ) );
3107  NeedRIGHT();
3108  break;
3109 
3110  case T_clearance:
3111  pad->SetLocalClearance( parseBoardUnits( "local clearance value" ) );
3112  NeedRIGHT();
3113  break;
3114 
3115  case T_zone_connect:
3116  pad->SetZoneConnection( (ZONE_CONNECTION) parseInt( "zone connection value" ) );
3117  NeedRIGHT();
3118  break;
3119 
3120  case T_thermal_width:
3121  pad->SetThermalWidth( parseBoardUnits( T_thermal_width ) );
3122  NeedRIGHT();
3123  break;
3124 
3125  case T_thermal_gap:
3126  pad->SetThermalGap( parseBoardUnits( T_thermal_gap ) );
3127  NeedRIGHT();
3128  break;
3129 
3130  case T_roundrect_rratio:
3131  pad->SetRoundRectRadiusRatio( parseDouble( "roundrect radius ratio" ) );
3132  NeedRIGHT();
3133  break;
3134 
3135  case T_chamfer_ratio:
3136  pad->SetChamferRectRatio( parseDouble( "chamfer ratio" ) );
3137 
3138  if( pad->GetChamferRectRatio() > 0 )
3139  pad->SetShape( PAD_SHAPE_CHAMFERED_RECT );
3140 
3141  NeedRIGHT();
3142  break;
3143 
3144  case T_chamfer:
3145  {
3146  int chamfers = 0;
3147  bool end_list = false;
3148 
3149  while( !end_list )
3150  {
3151  token = NextTok();
3152  switch( token )
3153  {
3154  case T_top_left:
3155  chamfers |= RECT_CHAMFER_TOP_LEFT;
3156  break;
3157 
3158  case T_top_right:
3159  chamfers |= RECT_CHAMFER_TOP_RIGHT;
3160  break;
3161 
3162  case T_bottom_left:
3163  chamfers |= RECT_CHAMFER_BOTTOM_LEFT;
3164  break;
3165 
3166  case T_bottom_right:
3167  chamfers |= RECT_CHAMFER_BOTTOM_RIGHT;
3168  break;
3169 
3170  case T_RIGHT:
3171  pad->SetChamferPositions( chamfers );
3172  end_list = true;
3173  break;
3174 
3175  default:
3176  Expecting( "chamfer_top_left chamfer_top_right chamfer_bottom_left or chamfer_bottom_right" );
3177  }
3178  }
3179 
3180  if( pad->GetChamferPositions() != RECT_NO_CHAMFER )
3181  pad->SetShape( PAD_SHAPE_CHAMFERED_RECT );
3182  }
3183  break;
3184 
3185  case T_property:
3186  {
3187  while( token != T_RIGHT )
3188  {
3189  token = NextTok();
3190 
3191  switch( token )
3192  {
3193  case T_pad_prop_bga:
3194  pad->SetProperty( PAD_PROP_BGA );
3195  break;
3196 
3197  case T_pad_prop_fiducial_glob:
3198  pad->SetProperty( PAD_PROP_FIDUCIAL_GLBL );
3199  break;
3200 
3201  case T_pad_prop_fiducial_loc:
3202  pad->SetProperty( PAD_PROP_FIDUCIAL_LOCAL );
3203  break;
3204 
3205  case T_pad_prop_testpoint:
3206  pad->SetProperty( PAD_PROP_TESTPOINT );
3207  break;
3208 
3209  case T_pad_prop_castellated:
3210  pad->SetProperty( PAD_PROP_CASTELLATED );
3211  break;
3212 
3213  case T_pad_prop_heatsink:
3214  pad->SetProperty( PAD_PROP_HEATSINK );
3215  break;
3216 
3217  case T_RIGHT:
3218  break;
3219 
3220  default:
3221 #if 0 // Currently: skip unknown property
3222  Expecting( "pad_prop_bga pad_prop_fiducial_glob pad_prop_fiducial_loc"
3223  " pad_prop_heatsink or pad_prop_castellated" );
3224 #endif
3225  break;
3226  }
3227  }
3228  }
3229  break;
3230 
3231  case T_options:
3232  parseD_PAD_option( pad.get() );
3233  break;
3234 
3235  case T_primitives:
3236  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3237  {
3238  if( token == T_LEFT )
3239  token = NextTok();
3240 
3241  // Currently, I am using parseDRAWSEGMENT() to read basic shapes parameters,
3242  // because they are the same as a DRAWSEGMENT.
3243  // However it could be better to write a specific parser, to avoid possible issues
3244  // if the DRAWSEGMENT parser is modified.
3245  DRAWSEGMENT* dummysegm = NULL;
3246 
3247  switch( token )
3248  {
3249  case T_gr_arc:
3250  dummysegm = parseDRAWSEGMENT();
3251  pad->AddPrimitiveArc( dummysegm->GetCenter(), dummysegm->GetArcStart(),
3252  dummysegm->GetAngle(), dummysegm->GetWidth(), false );
3253  break;
3254 
3255  case T_gr_line:
3256  dummysegm = parseDRAWSEGMENT();
3257  pad->AddPrimitiveSegment( dummysegm->GetStart(), dummysegm->GetEnd(),
3258  dummysegm->GetWidth(), false );
3259  break;
3260 
3261  case T_gr_circle:
3262  dummysegm = parseDRAWSEGMENT( true ); // Circles with 0 thickness are allowed
3263  // ( filled circles )
3264  pad->AddPrimitiveCircle( dummysegm->GetCenter(), dummysegm->GetRadius(),
3265  dummysegm->GetWidth(), false );
3266  break;
3267 
3268  case T_gr_poly:
3269  dummysegm = parseDRAWSEGMENT();
3270  pad->AddPrimitivePoly(
3271  dummysegm->BuildPolyPointsList(), dummysegm->GetWidth(), false );
3272  break;
3273 
3274  case T_gr_curve:
3275  dummysegm = parseDRAWSEGMENT();
3276  pad->AddPrimitiveCurve( dummysegm->GetStart(), dummysegm->GetEnd(),
3277  dummysegm->GetBezControl1(), dummysegm->GetBezControl2(),
3278  dummysegm->GetWidth(), false );
3279  break;
3280 
3281  default:
3282  Expecting( "gr_line, gr_arc, gr_circle, gr_curve or gr_poly" );
3283  break;
3284  }
3285 
3286  delete dummysegm;
3287  }
3288  break;
3289 
3290  case T_tstamp:
3291  NextTok();
3292  const_cast<KIID&>( pad->m_Uuid ) = KIID( CurStr() );
3293  NeedRIGHT();
3294  break;
3295 
3296  default:
3297  Expecting( "at, drill, layers, net, die_length, solder_mask_margin, roundrect_rratio,\n"
3298  "solder_paste_margin, solder_paste_margin_ratio, clearance, tstamp,\n"
3299  "zone_connect, fp_poly, primitives, thermal_width, or thermal_gap" );
3300  }
3301  }
3302 
3303  // Be sure the custom shape polygon is built:
3304  if( pad->GetShape() == PAD_SHAPE_CUSTOM )
3305  pad->MergePrimitivesAsPolygon();
3306 
3307  return pad.release();
3308 }
3309 
3310 
3312 {
3313  // Parse only the (option ...) inside a pad description
3314  for( T token = NextTok(); token != T_RIGHT; token = NextTok() )
3315  {
3316  if( token != T_LEFT )
3317  Expecting( T_LEFT );
3318 
3319  token = NextTok();
3320 
3321  switch( token )
3322  {
3323  case T_anchor:
3324  token = NextTok();
3325  // Custom shaped pads have a "anchor pad", which is the reference
3326  // for connection calculations.
3327  // Because this is an anchor, only the 2 very basic shapes are managed:
3328  // circle and rect. The default is circle
3329  switch( token )
3330  {
3331  case T_circle: // default
3332  break;
3333 
3334  case T_rect:
3336  break;
3337 
3338  default:
3339  // Currently, because pad options is a moving target
3340  // just skip unknown keywords
3341  break;
3342  }
3343  NeedRIGHT();
3344  break;
3345 
3346  case T_clearance:
3347  token = NextTok();
3348  // Custom shaped pads have a clearance area that is the pad shape
3349  // (like usual pads) or the convew hull of the pad shape.
3350  switch( token )
3351  {
3352  case T_outline:
3354  break;
3355 
3356  case T_convexhull:
3358  break;
3359 
3360  default:
3361  // Currently, because pad options is a moving target
3362  // just skip unknown keywords
3363  break;
3364  }
3365  NeedRIGHT();
3366  break;
3367 
3368  default:
3369  // Currently, because pad options is a moving target
3370  // just skip unknown keywords
3371  while( (token = NextTok() ) != T_RIGHT )
3372  {}
3373  break;
3374  }
3375  }
3376 
3377  return true;
3378 }
3379 
3380 
3382 {
3383  wxCHECK_MSG( CurTok() == T_arc, NULL,
3384  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as ARC." ) );
3385 
3386  wxPoint pt;
3387  T token;
3388 
3389  std::unique_ptr<ARC> arc( new ARC( m_board ) );
3390 
3391  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3392  {
3393  if( token != T_LEFT )
3394  Expecting( T_LEFT );
3395 
3396  token = NextTok();
3397 
3398  switch( token )
3399  {
3400  case T_start:
3401  pt.x = parseBoardUnits( "start x" );
3402  pt.y = parseBoardUnits( "start y" );
3403  arc->SetStart( pt );
3404  break;
3405 
3406  case T_mid:
3407  pt.x = parseBoardUnits( "mid x" );
3408  pt.y = parseBoardUnits( "mid y" );
3409  arc->SetMid( pt );
3410  break;
3411 
3412  case T_end:
3413  pt.x = parseBoardUnits( "end x" );
3414  pt.y = parseBoardUnits( "end y" );
3415  arc->SetEnd( pt );
3416  break;
3417 
3418  case T_width:
3419  arc->SetWidth( parseBoardUnits( "width" ) );
3420  break;
3421 
3422  case T_layer:
3423  arc->SetLayer( parseBoardItemLayer() );
3424  break;
3425 
3426  case T_net:
3427  if( !arc->SetNetCode( getNetCode( parseInt( "net number" ) ), /* aNoAssert */ true ) )
3429  _( "Invalid net ID in\nfile: \"%s\"\nline: %d\noffset: %d" ),
3430  GetChars( CurSource() ), CurLineNumber(), CurOffset() ) );
3431  break;
3432 
3433  case T_tstamp:
3434  NextTok();
3435  const_cast<KIID&>( arc->m_Uuid ) = KIID( CurStr() );
3436  break;
3437 
3438  case T_status:
3439  arc->SetStatus( static_cast<STATUS_FLAGS>( parseHex() ) );
3440  break;
3441 
3442  default:
3443  Expecting( "start, mid, end, width, layer, net, tstamp, or status" );
3444  }
3445 
3446  NeedRIGHT();
3447  }
3448 
3449  return arc.release();
3450 }
3451 
3452 
3454 {
3455  wxCHECK_MSG( CurTok() == T_segment, NULL,
3456  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as TRACK." ) );
3457 
3458  wxPoint pt;
3459  T token;
3460 
3461  std::unique_ptr< TRACK > track( new TRACK( m_board ) );
3462 
3463  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3464  {
3465  if( token != T_LEFT )
3466  Expecting( T_LEFT );
3467 
3468  token = NextTok();
3469 
3470  switch( token )
3471  {
3472  case T_start:
3473  pt.x = parseBoardUnits( "start x" );
3474  pt.y = parseBoardUnits( "start y" );
3475  track->SetStart( pt );
3476  break;
3477 
3478  case T_end:
3479  pt.x = parseBoardUnits( "end x" );
3480  pt.y = parseBoardUnits( "end y" );
3481  track->SetEnd( pt );
3482  break;
3483 
3484  case T_width:
3485  track->SetWidth( parseBoardUnits( "width" ) );
3486  break;
3487 
3488  case T_layer:
3489  track->SetLayer( parseBoardItemLayer() );
3490  break;
3491 
3492  case T_net:
3493  if( ! track->SetNetCode( getNetCode( parseInt( "net number" ) ), /* aNoAssert */ true ) )
3495  wxString::Format( _( "Invalid net ID in\nfile: \"%s\"\nline: %d\noffset: %d" ),
3496  GetChars( CurSource() ), CurLineNumber(), CurOffset() )
3497  );
3498  break;
3499 
3500  case T_tstamp:
3501  NextTok();
3502  const_cast<KIID&>( track->m_Uuid ) = KIID( CurStr() );
3503  break;
3504 
3505  case T_status:
3506  track->SetStatus( static_cast<STATUS_FLAGS>( parseHex() ) );
3507  break;
3508 
3509  default:
3510  Expecting( "start, end, width, layer, net, tstamp, or status" );
3511  }
3512 
3513  NeedRIGHT();
3514  }
3515 
3516  return track.release();
3517 }
3518 
3519 
3521 {
3522  wxCHECK_MSG( CurTok() == T_via, NULL,
3523  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as VIA." ) );
3524 
3525  wxPoint pt;
3526  T token;
3527 
3528  std::unique_ptr< VIA > via( new VIA( m_board ) );
3529 
3530  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3531  {
3532  if( token == T_LEFT )
3533  token = NextTok();
3534 
3535  switch( token )
3536  {
3537  case T_blind:
3538  via->SetViaType( VIATYPE::BLIND_BURIED );
3539  break;
3540 
3541  case T_micro:
3542  via->SetViaType( VIATYPE::MICROVIA );
3543  break;
3544 
3545  case T_at:
3546  pt.x = parseBoardUnits( "start x" );
3547  pt.y = parseBoardUnits( "start y" );
3548  via->SetStart( pt );
3549  via->SetEnd( pt );
3550  NeedRIGHT();
3551  break;
3552 
3553  case T_size:
3554  via->SetWidth( parseBoardUnits( "via width" ) );
3555  NeedRIGHT();
3556  break;
3557 
3558  case T_drill:
3559  via->SetDrill( parseBoardUnits( "drill diameter" ) );
3560  NeedRIGHT();
3561  break;
3562 
3563  case T_layers:
3564  {
3565  PCB_LAYER_ID layer1, layer2;
3566  NextTok();
3567  layer1 = lookUpLayer<PCB_LAYER_ID>( m_layerIndices );
3568  NextTok();
3569  layer2 = lookUpLayer<PCB_LAYER_ID>( m_layerIndices );
3570  via->SetLayerPair( layer1, layer2 );
3571  NeedRIGHT();
3572  }
3573  break;
3574 
3575  case T_net:
3576  if(! via->SetNetCode( getNetCode( parseInt( "net number" ) ), /* aNoAssert */ true))
3578  wxString::Format( _( "Invalid net ID in\nfile: \"%s\"\nline: %d\noffset: %d" ),
3579  GetChars( CurSource() ), CurLineNumber(), CurOffset() )
3580  );
3581  NeedRIGHT();
3582  break;
3583 
3584  case T_tstamp:
3585  NextTok();
3586  const_cast<KIID&>( via->m_Uuid ) = KIID( CurStr() );
3587  NeedRIGHT();
3588  break;
3589 
3590  case T_status:
3591  via->SetStatus( static_cast<STATUS_FLAGS>( parseHex() ) );
3592  NeedRIGHT();
3593  break;
3594 
3595  default:
3596  Expecting( "blind, micro, at, size, drill, layers, net, tstamp, or status" );
3597  }
3598  }
3599 
3600  return via.release();
3601 }
3602 
3603 
3605 {
3606  wxCHECK_MSG( CurTok() == T_zone, NULL,
3607  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) +
3608  wxT( " as ZONE_CONTAINER." ) );
3609 
3611 
3612  int hatchPitch = ZONE_CONTAINER::GetDefaultHatchPitch();
3613  wxPoint pt;
3614  T token;
3615  int tmp;
3616  wxString netnameFromfile; // the zone net name find in file
3617 
3618  // bigger scope since each filled_polygon is concatenated in here
3619  SHAPE_POLY_SET pts;
3620  bool inModule = false;
3621 
3622  if( dynamic_cast<MODULE*>( aParent ) ) // The zone belongs a footprint
3623  inModule = true;
3624 
3625  std::unique_ptr<ZONE_CONTAINER> zone( inModule ?
3626  new MODULE_ZONE_CONTAINER( aParent ) :
3627  new ZONE_CONTAINER( aParent ) );
3628 
3629  zone->SetPriority( 0 );
3630 
3631  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3632  {
3633  if( token == T_LEFT )
3634  token = NextTok();
3635 
3636  switch( token )
3637  {
3638  case T_net:
3639  // Init the net code only, not the netname, to be sure
3640  // the zone net name is the name read in file.
3641  // (When mismatch, the user will be prompted in DRC, to fix the actual name)
3642  tmp = getNetCode( parseInt( "net number" ) );
3643 
3644  if( tmp < 0 )
3645  tmp = 0;
3646 
3647  if( ! zone->SetNetCode( tmp, /* aNoAssert */ true ) )
3649  wxString::Format( _( "Invalid net ID in\nfile: \"%s\"\nline: %d\noffset: %d" ),
3650  GetChars( CurSource() ), CurLineNumber(), CurOffset() )
3651  );
3652 
3653  NeedRIGHT();
3654  break;
3655 
3656  case T_net_name:
3657  NeedSYMBOLorNUMBER();
3658  netnameFromfile = FromUTF8();
3659  NeedRIGHT();
3660  break;
3661 
3662  case T_layer: // keyword for zones that are on only one layer
3663  zone->SetLayer( parseBoardItemLayer() );
3664  NeedRIGHT();
3665  break;
3666 
3667  case T_layers: // keyword for zones that can live on a set of layer
3668  // currently: keepout zones
3669  zone->SetLayerSet( parseBoardItemLayersAsMask() );
3670  break;
3671 
3672  case T_tstamp:
3673  NextTok();
3674  const_cast<KIID&>( zone->m_Uuid ) = KIID( CurStr() );
3675  NeedRIGHT();
3676  break;
3677 
3678  case T_hatch:
3679  token = NextTok();
3680 
3681  if( token != T_none && token != T_edge && token != T_full )
3682  Expecting( "none, edge, or full" );
3683 
3684  switch( token )
3685  {
3686  default:
3687  case T_none:
3688  hatchStyle = ZONE_HATCH_STYLE::NO_HATCH;
3689  break;
3690  case T_edge:
3691  hatchStyle = ZONE_HATCH_STYLE::DIAGONAL_EDGE;
3692  break;
3693  case T_full:
3694  hatchStyle = ZONE_HATCH_STYLE::DIAGONAL_FULL;
3695  }
3696 
3697  hatchPitch = parseBoardUnits( "hatch pitch" );
3698  NeedRIGHT();
3699  break;
3700 
3701  case T_priority:
3702  zone->SetPriority( parseInt( "zone priority" ) );
3703  NeedRIGHT();
3704  break;
3705 
3706  case T_connect_pads:
3707  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3708  {
3709  if( token == T_LEFT )
3710  token = NextTok();
3711 
3712  switch( token )
3713  {
3714  case T_yes:
3715  zone->SetPadConnection( ZONE_CONNECTION::FULL );
3716  break;
3717 
3718  case T_no:
3719  zone->SetPadConnection( ZONE_CONNECTION::NONE );
3720  break;
3721 
3722  case T_thru_hole_only:
3723  zone->SetPadConnection( ZONE_CONNECTION::THT_THERMAL );
3724  break;
3725 
3726  case T_clearance:
3727  zone->SetZoneClearance( parseBoardUnits( "zone clearance" ) );
3728  NeedRIGHT();
3729  break;
3730 
3731  default:
3732  Expecting( "yes, no, or clearance" );
3733  }
3734  }
3735 
3736  break;
3737 
3738  case T_min_thickness:
3739  zone->SetMinThickness( parseBoardUnits( T_min_thickness ) );
3740  NeedRIGHT();
3741  break;
3742 
3743  case T_filled_areas_thickness:
3744  zone->SetFilledPolysUseThickness( parseBool() );
3745  NeedRIGHT();
3746  break;
3747 
3748  case T_fill:
3749  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3750  {
3751  if( token == T_LEFT )
3752  token = NextTok();
3753 
3754  switch( token )
3755  {
3756  case T_yes:
3757  zone->SetIsFilled( true );
3758  break;
3759 
3760  case T_mode:
3761  token = NextTok();
3762 
3763  if( token != T_segment && token != T_hatch && token != T_polygon )
3764  Expecting( "segment, hatch or polygon" );
3765 
3766  if( token == T_segment ) // deprecated
3767  {
3768  // SEGMENT fill mode no longer supported. Make sure user is OK with converting them.
3769  if( m_showLegacyZoneWarning )
3770  {
3771  KIDIALOG dlg( nullptr,
3772  _( "The legacy segment fill mode is no longer supported.\n"
3773  "Convert zones to polygon fills?"),
3774  _( "Legacy Zone Warning" ),
3775  wxYES_NO | wxICON_WARNING );
3776 
3777  dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
3778 
3779  if( dlg.ShowModal() == wxID_NO )
3780  THROW_IO_ERROR( wxT( "CANCEL" ) );
3781 
3782  m_showLegacyZoneWarning = false;
3783  }
3784 
3785  zone->SetFillMode( ZONE_FILL_MODE::POLYGONS );
3786  m_board->SetModified();
3787  }
3788  else if( token == T_hatch )
3789  zone->SetFillMode( ZONE_FILL_MODE::HATCH_PATTERN );
3790  else
3791  zone->SetFillMode( ZONE_FILL_MODE::POLYGONS );
3792  NeedRIGHT();
3793  break;
3794 
3795  case T_hatch_thickness:
3796  zone->SetHatchFillTypeThickness( parseBoardUnits( T_hatch_thickness ) );
3797  NeedRIGHT();
3798  break;
3799 
3800  case T_hatch_gap:
3801  zone->SetHatchFillTypeGap( parseBoardUnits( T_hatch_gap ) );
3802  NeedRIGHT();
3803  break;
3804 
3805  case T_hatch_orientation:
3806  zone->SetHatchFillTypeOrientation( parseDouble( T_hatch_orientation ) );
3807  NeedRIGHT();
3808  break;
3809 
3810  case T_hatch_smoothing_level:
3811  zone->SetHatchFillTypeSmoothingLevel( parseDouble( T_hatch_smoothing_level ) );
3812  NeedRIGHT();
3813  break;
3814 
3815  case T_hatch_smoothing_value:
3816  zone->SetHatchFillTypeSmoothingValue( parseDouble( T_hatch_smoothing_value ) );
3817  NeedRIGHT();
3818  break;
3819 
3820  case T_arc_segments:
3821  static_cast<void>( parseInt( "arc segment count" ) );
3822  NeedRIGHT();
3823  break;
3824 
3825  case T_thermal_gap:
3826  zone->SetThermalReliefGap( parseBoardUnits( T_thermal_gap ) );
3827  NeedRIGHT();
3828  break;
3829 
3830  case T_thermal_bridge_width:
3831  zone->SetThermalReliefCopperBridge( parseBoardUnits( T_thermal_bridge_width ) );
3832  NeedRIGHT();
3833  break;
3834 
3835  case T_smoothing:
3836  switch( NextTok() )
3837  {
3838  case T_none:
3839  zone->SetCornerSmoothingType( ZONE_SETTINGS::SMOOTHING_NONE );
3840  break;
3841 
3842  case T_chamfer:
3843  if( !zone->GetIsKeepout() ) // smoothing has meaning only for filled zones
3844  zone->SetCornerSmoothingType( ZONE_SETTINGS::SMOOTHING_CHAMFER );
3845  break;
3846 
3847  case T_fillet:
3848  if( !zone->GetIsKeepout() ) // smoothing has meaning only for filled zones
3849  zone->SetCornerSmoothingType( ZONE_SETTINGS::SMOOTHING_FILLET );
3850  break;
3851 
3852  default:
3853  Expecting( "none, chamfer, or fillet" );
3854  }
3855  NeedRIGHT();
3856  break;
3857 
3858  case T_radius:
3859  tmp = parseBoardUnits( "corner radius" );
3860  if( !zone->GetIsKeepout() ) // smoothing has meaning only for filled zones
3861  zone->SetCornerRadius( tmp );
3862  NeedRIGHT();
3863  break;
3864 
3865  default:
3866  Expecting( "mode, arc_segments, thermal_gap, thermal_bridge_width, "
3867  "hatch_thickness, hatch_gap, hatch_orientation, "
3868  "hatch_smoothing_level, hatch_smoothing_value, smoothing, or radius" );
3869  }
3870  }
3871  break;
3872 
3873  case T_keepout:
3874  zone->SetIsKeepout( true );
3875 
3876  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3877  {
3878  if( token == T_LEFT )
3879  token = NextTok();
3880 
3881  switch( token )
3882  {
3883  case T_tracks:
3884  token = NextTok();
3885 
3886  if( token != T_allowed && token != T_not_allowed )
3887  Expecting( "allowed or not_allowed" );
3888  zone->SetDoNotAllowTracks( token == T_not_allowed );
3889  break;
3890 
3891  case T_vias:
3892  token = NextTok();
3893 
3894  if( token != T_allowed && token != T_not_allowed )
3895  Expecting( "allowed or not_allowed" );
3896  zone->SetDoNotAllowVias( token == T_not_allowed );
3897  break;
3898 
3899  case T_copperpour:
3900  token = NextTok();
3901 
3902  if( token != T_allowed && token != T_not_allowed )
3903  Expecting( "allowed or not_allowed" );
3904  zone->SetDoNotAllowCopperPour( token == T_not_allowed );
3905  break;
3906 
3907  default:
3908  Expecting( "tracks, vias or copperpour" );
3909  }
3910 
3911  NeedRIGHT();
3912  }
3913 
3914  break;
3915 
3916  case T_polygon:
3917  {
3918  std::vector< wxPoint > corners;
3919 
3920  NeedLEFT();
3921  token = NextTok();
3922 
3923  if( token != T_pts )
3924  Expecting( T_pts );
3925 
3926  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3927  {
3928  corners.push_back( parseXY() );
3929  }
3930 
3931  NeedRIGHT();
3932 
3933  // Remark: The first polygon is the main outline.
3934  // Others are holes inside the main outline.
3935  zone->AddPolygon( corners );
3936  }
3937  break;
3938 
3939  case T_filled_polygon:
3940  {
3941  // "(filled_polygon (pts"
3942  NeedLEFT();
3943  token = NextTok();
3944 
3945  if( token != T_pts )
3946  Expecting( T_pts );
3947 
3948  pts.NewOutline();
3949 
3950  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3951  {
3952  pts.Append( parseXY() );
3953  }
3954 
3955  NeedRIGHT();
3956  }
3957  break;
3958 
3959  case T_fill_segments:
3960  {
3961  ZONE_SEGMENT_FILL segs;
3962 
3963  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3964  {
3965  if( token != T_LEFT )
3966  Expecting( T_LEFT );
3967 
3968  token = NextTok();
3969 
3970  if( token != T_pts )
3971  Expecting( T_pts );
3972 
3973  SEG segment( parseXY(), parseXY() );
3974  NeedRIGHT();
3975  segs.push_back( segment );
3976  }
3977 
3978  zone->SetFillSegments( segs );
3979  }
3980  break;
3981 
3982  default:
3983  Expecting( "net, layer/layers, tstamp, hatch, priority, connect_pads, min_thickness, "
3984  "fill, polygon, filled_polygon, or fill_segments" );
3985  }
3986  }
3987 
3988  if( zone->GetNumCorners() > 2 )
3989  {
3990  if( !zone->IsOnCopperLayer() )
3991  {
3992  //zone->SetFillMode( ZONE_FILL_MODE::POLYGONS );
3993  zone->SetNetCode( NETINFO_LIST::UNCONNECTED );
3994  }
3995 
3996  // Set hatch here, after outlines corners are read
3997  zone->SetHatch( hatchStyle, hatchPitch, true );
3998  }
3999 
4000  if( !pts.IsEmpty() )
4001  {
4002  zone->SetFilledPolysList( pts );
4003  zone->CalculateFilledArea();
4004  }
4005 
4006  // Ensure keepout and non copper zones do not have a net
4007  // (which have no sense for these zones)
4008  // the netcode 0 is used for these zones
4009  bool zone_has_net = zone->IsOnCopperLayer() && !zone->GetIsKeepout();
4010 
4011  if( !zone_has_net )
4012  zone->SetNetCode( NETINFO_LIST::UNCONNECTED );
4013 
4014  // Ensure the zone net name is valid, and matches the net code, for copper zones
4015  if( zone_has_net && ( zone->GetNet()->GetNetname() != netnameFromfile ) )
4016  {
4017  // Can happens which old boards, with nonexistent nets ...
4018  // or after being edited by hand
4019  // We try to fix the mismatch.
4020  NETINFO_ITEM* net = m_board->FindNet( netnameFromfile );
4021 
4022  if( net ) // An existing net has the same net name. use it for the zone
4023  zone->SetNetCode( net->GetNet() );
4024  else // Not existing net: add a new net to keep trace of the zone netname
4025  {
4026  int newnetcode = m_board->GetNetCount();
4027  net = new NETINFO_ITEM( m_board, netnameFromfile, newnetcode );
4028  m_board->Add( net );
4029 
4030  // Store the new code mapping
4031  pushValueIntoMap( newnetcode, net->GetNet() );
4032  // and update the zone netcode
4033  zone->SetNetCode( net->GetNet() );
4034 
4035  // FIXME: a call to any GUI item is not allowed in io plugins:
4036  // Change this code to generate a warning message outside this plugin
4037  // Prompt the user
4038  wxString msg;
4039  msg.Printf( _( "There is a zone that belongs to a not existing net\n"
4040  "\"%s\"\n"
4041  "you should verify and edit it (run DRC test)." ),
4042  GetChars( netnameFromfile ) );
4043  DisplayError( NULL, msg );
4044  }
4045  }
4046 
4047  // Clear flags used in zone edition:
4048  zone->SetNeedRefill( false );
4049 
4050  return zone.release();
4051 }
4052 
4053 
4055 {
4056  wxCHECK_MSG( CurTok() == T_target, NULL,
4057  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as PCB_TARGET." ) );
4058 
4059  wxPoint pt;
4060  T token;
4061 
4062  std::unique_ptr< PCB_TARGET > target( new PCB_TARGET( NULL ) );
4063 
4064  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
4065  {
4066  if( token == T_LEFT )
4067  token = NextTok();
4068 
4069  switch( token )
4070  {
4071  case T_x:
4072  target->SetShape( 1 );
4073  break;
4074 
4075  case T_plus:
4076  target->SetShape( 0 );
4077  break;
4078 
4079  case T_at:
4080  pt.x = parseBoardUnits( "target x position" );
4081  pt.y = parseBoardUnits( "target y position" );
4082  target->SetPosition( pt );
4083  NeedRIGHT();
4084  break;
4085 
4086  case T_size:
4087  target->SetSize( parseBoardUnits( "target size" ) );
4088  NeedRIGHT();
4089  break;
4090 
4091  case T_width:
4092  target->SetWidth( parseBoardUnits( "target thickness" ) );
4093  NeedRIGHT();
4094  break;
4095 
4096  case T_layer:
4097  target->SetLayer( parseBoardItemLayer() );
4098  NeedRIGHT();
4099  break;
4100 
4101  case T_tstamp:
4102  NextTok();
4103  const_cast<KIID&>( target->m_Uuid ) = KIID( CurStr() );
4104  NeedRIGHT();
4105  break;
4106 
4107  default:
4108  Expecting( "x, plus, at, size, width, layer or tstamp" );
4109  }
4110  }
4111 
4112  return target.release();
4113 }
void SetMirrored(bool isMirrored)
Definition: eda_text.h:172
void parseHeader()
Definition: pcb_parser.cpp:695
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Function AllCuMask returns a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:686
EDA_UNITS
Definition: common.h:184
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:239
int parseVersion()
Parse a format version tag like (version 20160417) return the version.
Definition: pcb_parser.cpp:194
UTF8 is an 8 bit string that is assuredly encoded in UTF8, and supplies special conversion support to...
Definition: utf8.h:73
int Mm2mils(double x)
Convert mm to mils.
Definition: base_units.h:52
int m_SolderMaskMargin
Solder mask margin.
ZONE_CONNECTION
How pads are covered by copper in zone.
Definition: zones.h:41
Struct VIA_DIMENSION is a small helper container to handle a stock of specific vias each with unique ...
ZONE_CONTAINER handles a list of polygons defining a copper zone.
Definition: class_zone.h:60
void LayerPair(PCB_LAYER_ID *top_layer, PCB_LAYER_ID *bottom_layer) const
Function LayerPair Return the 2 layers used by the via (the via actually uses all layers between thes...
std::vector< SEG > ZONE_SEGMENT_FILL
Definition: class_zone.h:47
void SetBrdLayerId(PCB_LAYER_ID aBrdLayerId)
void SetTypeName(const wxString &aName)
void DoNotShowCheckbox(wxString file, int line)
Shows the 'do not show again' checkbox
Definition: confirm.cpp:53
DRAWSEGMENT * parseDRAWSEGMENT(bool aAllowCirclesZeroWidth=false)
Read a DRAWSEGMENT description.
LSET parseBoardItemLayersAsMask()
Function parseBoardItemLayersAsMask parses the layers definition of a BOARD_ITEM object.
const wxPoint & GetPos0() const
Definition: class_pad.h:294
wxPoint m_GridOrigin
origin for grid offsets
int StrPrintf(std::string *aResult, const char *aFormat,...)
Function StrPrintf is like sprintf() but the output is appended to a std::string instead of to a char...
Definition: richio.cpp:74
static wxString FROM_UTF8(const char *cstring)
function FROM_UTF8 converts a UTF8 encoded C string to a wxString for all wxWidgets build modes.
Definition: macros.h:62
wxString m_name
The name of the layer, there should be no spaces in this name.
Definition: class_board.h:108
like PAD_STANDARD, but not plated mechanical use only, no connection allowed
Definition: pad_shapes.h:66
int m_SolderPasteMargin
Solder paste margin absolute value.
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: common.h:202
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
Definition: confirm.h:44
this class manage the layers needed to make a physical board they are solder mask,...
This file is part of the common library.
PCB_PLOT_PARAMS_PARSER is the parser class for PCB_PLOT_PARAMS.
BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class,...
std::vector< int > m_TrackWidthList
void SetRevision(const wxString &aRevision)
Definition: title_block.h:84
const wxPoint GetCenter() const override
Function GetCenter()
TRACK * parseTRACK()
wxString m_FinishType
The name of external copper finish.
VIA * parseVIA()
std::vector< DIFF_PAIR_DIMENSION > m_DiffPairDimensionsList
bool m_EdgePlating
True if the edge board is plated.
a fiducial (usually a smd) for the full board
Definition: pad_shapes.h:80
static uint32_t parseHex(LINE_READER &aReader, const char *aLine, const char **aOutput=NULL)
Parse an ASCII hex integer string with possible leading whitespace into a long integer and updates th...
LAYER_T m_type
The type of the layer.
Definition: class_board.h:109
void SetItalic(bool isItalic)
Definition: eda_text.h:163
polygon (not yet used for tracks, but could be in microwave apps)
bool IsEmpty() const
Returns true if the set is empty (no polygons at all)
BS_EDGE_CONNECTOR_CONSTRAINTS m_EdgeConnectorConstraints
If the board has edge connector cards, some constrains can be specifed in job file: BS_EDGE_CONNECTOR...
void parseBoardStackup()
Definition: pcb_parser.cpp:982
Smd pad, appears on the solder paste layer (default)
Definition: pad_shapes.h:62
wxPoint parseXY()
Function parseXY parses a coordinate pair (xy X Y) in board units (mm).
Definition: pcb_parser.cpp:231
void SetVisible(bool aVisible)
Definition: eda_text.h:169
void parseNETINFO_ITEM()
bool SetType(const wxString &aStandardPageDescriptionName, bool aIsPortrait=false)
Function SetType sets the name of the page type and also the sizes and margins commonly associated wi...
Definition: page_info.cpp:117
void createOldLayerMapping(std::unordered_map< std::string, std::string > &aMap)
Creates a mapping from the (short-lived) bug where layer names were translated TODO: Remove this once...
bool m_CastellatedPads
True if castellated pads exist.
Set for modules listed in the automatic insertion list (usually SMD footprints)
Definition: class_module.h:74
#define SEXPR_BOARD_FILE_VERSION
Current s-expression file format version. 2 was the last legacy format version.
double GetTextAngle() const
Definition: eda_text.h:158
#define DEFAULT_LINE_WIDTH
static double parseDouble(LINE_READER &aReader, const char *aLine, const char **aOutput=NULL)
Parses an ASCII point string with possible leading whitespace into a double precision floating point ...
BOARD * parseBOARD()
Definition: pcb_parser.cpp:506
Smd pad, used in BGA footprints.
Definition: pad_shapes.h:79
void SetPosition(const wxPoint &aPos) override
Definition: class_pad.h:240
void SetDate(const wxString &aDate)
Function SetDate sets the date field, and defaults to the current time and date.
Definition: title_block.h:74
bool parseD_PAD_option(D_PAD *aPad)
void parseEDA_TEXT(EDA_TEXT *aText)
Function parseEDA_TEXT parses the common settings for any object derived from EDA_TEXT.
Definition: pcb_parser.cpp:263
static const wxChar Custom[]
"User" defined page type
Definition: page_info.h:78
ARC * parseARC()
void SetDrillSize(const wxSize &aSize)
Definition: class_pad.h:305
void SetTextSize(const wxSize &aNewSize)
Definition: eda_text.h:222
DIMENSION * parseDIMENSION()
void parseTITLE_BLOCK()
Definition: pcb_parser.cpp:833
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:208
a pad used as heat sink, usually in SMD footprints
Definition: pad_shapes.h:83
const std::vector< wxPoint > BuildPolyPointsList() const
Build and return the list of corners in a std::vector<wxPoint> It must be used only to convert the SH...
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:51
const wxPoint & GetEnd() const
Function GetEnd returns the ending point of the graphic.
TITLE_BLOCK holds the information shown in the lower right corner of a plot, printout,...
Definition: title_block.h:40
Struct DIFF_PAIR_DIMENSION is a small helper container to handle a stock of specific differential pai...
static int GetDefaultHatchPitch()
Function GetDefaultHatchPitchMils.
void parseLayers()
Definitions for tracks, vias and zones.
VECTOR3D m_Offset
3D model offset (mm)
Definition: class_module.h:99
This file contains miscellaneous commonly used macros and functions.
a pad with a castellated through hole
Definition: pad_shapes.h:84
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition: eda_text.h:109
void parsePAGE_INFO()
Definition: pcb_parser.cpp:777
#define TO_UTF8(wxstring)
Macro TO_UTF8 converts a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: macros.h:48
wxSize m_TextSize[LAYER_CLASS_COUNT]
bool parseBool()
Definition: pcb_parser.cpp:179
DIMENSION class definition.
void skipCurrent()
Function skipCurrent Skip the current token level, i.e search for the RIGHT parenthesis which closes ...
Definition: pcb_parser.cpp:116
bool m_HasDielectricConstrains
True if some layers have impedance controlled tracks or have specific constrains for micro-wave appli...
Definition: common.h:65
void SetAnchorPadShape(PAD_SHAPE_T aShape)
Function SetAnchorPadShape Set the shape of the anchor pad for custm shped pads.
Definition: class_pad.h:274
PCB_LAYER_ID
A quick note on layer IDs:
wxString GetRequiredVersion()
Return a string representing the version of kicad required to open this file.
Definition: pcb_parser.cpp:207
int m_TextThickness[LAYER_CLASS_COUNT]
LSET is a set of PCB_LAYER_IDs.
pads are covered by copper
void SetComment(int aIdx, const wxString &aComment)
Definition: title_block.h:104
#define NULL
static const wxChar * Name(PCB_LAYER_ID aLayerId)
Function Name returns the fixed name association with aLayerId.
Definition: lset.cpp:78
#define MIN_VISIBILITY_MASK
void SetParent(EDA_ITEM *aParent)
Definition: base_struct.h:218
SHAPE_POLY_SET.
PAGE_INFO describes the page size and margins of a paper page on which to eventually print or plot.
Definition: page_info.h:54
void SetDielectricLayerId(int aLayerId)
void SetVertJustify(EDA_TEXT_VJUSTIFY_T aType)
Definition: eda_text.h:187
Arcs (with rounded ends)
void SetNetCode(int aNetCode)
Definition: netinfo.h:226
TEXT_TYPE GetType() const
MODULE * parseMODULE_unchecked(wxArrayString *aInitialComments=0)
Function parseMODULE_unchecked Parse a module, but do not replace PARSE_ERROR with FUTURE_FORMAT_ERRO...
bool m_TextItalic[LAYER_CLASS_COUNT]
PCB_TARGET * parsePCB_TARGET()
PCB_LAYER_ID parseBoardItemLayer()
Function parseBoardItemLayer parses the layer definition of a BOARD_ITEM object.
void SetCompany(const wxString &aCompany)
Definition: title_block.h:94
ZONE_CONTAINER * parseZONE_CONTAINER(BOARD_ITEM_CONTAINER *aParent)
static LSET InternalCuMask()
Function InternalCuMask() returns a complete set of internal copper layers, which is all Cu layers ex...
Definition: lset.cpp:646
bool m_visible
Definition: class_board.h:110
void SetSize(const wxSize &aSize)
Definition: class_pad.h:299
int m_ZoneClearance
Minimal clearance value.
Definition: zone_settings.h:74
TEXTE_PCB * parseTEXTE_PCB()
const wxPoint & GetArcStart() const
bool m_BlindBuriedViaAllowed
true to allow blind/buried vias
void SetLayerPair(PCB_LAYER_ID aTopLayer, PCB_LAYER_ID aBottomLayer)
Function SetLayerPair For a via m_Layer contains the top layer, the other layer is in m_BottomLayer.
void SetMaterial(const wxString &aName, int aDielectricSubLayer=0)
#define THROW_IO_ERROR(msg)
int GetRadius() const
Function GetRadius returns the radius of this item Has meaning only for arc and circle.
Bezier Curve.
#define THROW_PARSE_ERROR(aProblem, aSource, aInputLine, aLineNumber, aByteIndex)
static LAYER_T ParseType(const char *aType)
Function ParseType converts a string to a LAYER_T.
static int parseInt(LINE_READER &aReader, const char *aLine, const char **aOutput=NULL)
Parse an ASCII integer string with possible leading whitespace into an integer and updates the pointe...
BOARD_ITEM * Parse()
Definition: pcb_parser.cpp:467
void SetTitle(const wxString &aTitle)
Definition: title_block.h:60
PCB_PLOT_PARAMS handles plot parameters and options when plotting/printing a board.
void parseNETCLASS()
Like smd, does not appear on the solder paste layer (default) note also has a special attribute in Ge...
Definition: pad_shapes.h:63
int NewOutline()
Creates a new empty polygon in the set and returns its index
this class manage one layer needed to make a physical board it can be a solder mask,...
int m_LineThickness[LAYER_CLASS_COUNT]
void SetHeightMils(int aHeightInMils)
Definition: page_info.cpp:253
void SetEpsilonR(double aEpsilon, int aDielectricSubLayer=0)
void AddDielectricPrms(int aDielectricPrmsIdx)
true if this stackup item must be taken in account, false to ignore it.
int GetWidth() const
Pad object description.
Thermal relief only for THT pads.
void parseDefaults(BOARD_DESIGN_SETTINGS &aSettings)
void SetThickness(int aThickness, int aDielectricSubLayer=0)
static const int ORPHANED
Constant that forces initialization of a netinfo item to the NETINFO_ITEM ORPHANED (typically -1) whe...
Definition: netinfo.h:466
int LAYER_NUM
Type LAYER_NUM can be replaced with int and removed.
wxString m_Filename
The 3D shape filename in 3D library.
Definition: class_module.h:100
ZONE_SETTINGS handles zones parameters.
Definition: zone_settings.h:58
const KIID m_Uuid
Definition: base_struct.h:169
Definition: seg.h:39
BOARD * parseBOARD_unchecked()
Function parseBOARD_unchecked Parse a module, but do not replace PARSE_ERROR with FUTURE_FORMAT_ERROR...
Definition: pcb_parser.cpp:522
void clear()
Definition: class_board.h:89
void parseLayer(LAYER *aLayer)
Definition: pcb_parser.cpp:941
void SetThicknessLocked(bool aLocked, int aDielectricSubLayer=0)
double GetAngle() const
NETINFO_ITEM handles the data for a net.
Definition: netinfo.h:65
Struct PARSE_ERROR contains a filename or source description, a problem input line,...
Definition: ki_exception.h:123
void parseDefaultTextDims(BOARD_DESIGN_SETTINGS &aSettings, int aLayer)
static const wxChar * GetChars(const wxString &s)
Function GetChars returns a wxChar* to the actual wxChar* data within a wxString, and is helpful for ...
Definition: macros.h:101
a fiducial (usually a smd) local to the parent footprint
Definition: pad_shapes.h:81
EDGE_MODULE * parseEDGE_MODULE()
ZONE_HATCH_STYLE
Zone hatch styles.
Definition: zone_settings.h:45
Class to handle a graphic segment.
const char * name
Definition: DXF_plotter.cpp:60
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
VECTOR3D m_Rotation
3D model rotation (degrees)
Definition: class_module.h:98
int GetNet() const
Function GetNet.
Definition: netinfo.h:224
LAYER holds information pertinent to a layer of a BOARD.
Definition: class_board.h:82
BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:163
void SetHorizJustify(EDA_TEXT_HJUSTIFY_T aType)
Definition: eda_text.h:186
#define _(s)
Definition: 3d_actions.cpp:33
void FetchUnitsFromString(const wxString &aTextValue, EDA_UNITS &aUnits, bool &aUseMils)
Function FetchUnitsFromString writes any unit info found in the string to aUnits and aUseMils.
Definition: base_units.cpp:405
bool m_ZoneUseNoOutlineInFill
Option to handle filled polygons in zones: the "legacy" option is using thick outlines around filled ...
Virtual component: when created by copper shapes on board (Like edge card connectors,...
Definition: class_module.h:76
void parseGeneralSection()
Definition: pcb_parser.cpp:731
void init()
Function init clears and re-establishes m_layerMap with the default layer names.
Definition: pcb_parser.cpp:57
void SetWidthMils(int aWidthInMils)
Definition: page_info.cpp:239
void SetDrawCoord()
Set absolute coordinates.
D_PAD m_Pad_Master
A dummy pad to store all default parameters.
void SetDrawCoord()
Set draw coordinates (absolute values ) from relative coordinates.
void SetVisibleElements(int aMask)
Function SetVisibleElements changes the bit-mask of visible element categories.
VIATYPE GetViaType() const
Definition: class_track.h:416
BOARD_STACKUP_ITEM_TYPE
void pushValueIntoMap(int aIndex, int aValue)
function pushValueIntoMap Add aValue value in netcode mapping (m_netCodes) at index aIndex ensure the...
Definition: pcb_parser.cpp:137
const wxPoint & GetBezControl2() const
The common library.
MODULE_ZONE_CONTAINER is the same item as ZONE_CONTAINER, but with a specific type id ZONE_CONTAINER ...
Definition: class_zone.h:848
VECTOR3D m_Scale
3D model scaling factor (dimensionless)
Definition: class_module.h:97
Pads are not covered.
std::vector< VIA_DIMENSION > m_ViasDimensionsList
double parseDouble()
Function parseDouble parses the current token as an ASCII numeric string with possible leading whites...
Definition: pcb_parser.cpp:149
const char * GetTokenText(T aTok)
Function GetTokenText is in the DSN namespace and returns the C string representing a SPECCTRA_DB::ke...
Definition: specctra.cpp:69
int ShowModal() override
Definition: confirm.cpp:95
const wxPoint & GetTextPos() const
Definition: eda_text.h:232
PCB_TARGET class definition.
void SetCustomShapeInZoneOpt(CUST_PAD_SHAPE_IN_ZONE aOption)
Set the option for the custom pad shape to use as clearance area in copper zones.
Definition: class_pad.h:263
class VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:97
const wxPoint & GetBezControl1() const
const wxPoint & GetStart() const
Function GetStart returns the starting point of the graphic.
Pcbnew s-expression file format parser definition.
void SetTextAngle(double aAngle)
Struct FUTURE_FORMAT_ERROR variant of PARSE_ERROR indicating that a syntax or related error was likel...
Definition: ki_exception.h:172
Module description (excepted pads)
bool m_MicroViasAllowed
true to allow micro vias
TEXTE_MODULE * parseTEXTE_MODULE()
void SetColor(const wxString &aColorName)
Abstract interface for BOARD_ITEMs capable of storing other items inside.
int m_number
Definition: class_board.h:111
D_PAD * parseD_PAD(MODULE *aParent=NULL)
MODULE * parseMODULE(wxArrayString *aInitialComments=0)
Function parseMODULE.
void Add(BOARD_STACKUP_ITEM *aItem)
Add a new item in stackup layer.
double m_SolderPasteMarginRatio
Solder pask margin ratio value of pad size The final margin is the sum of these 2 values.
EDGE_MODULE class definition.
int Parse(const UTF8 &aId, LIB_ID_TYPE aType, bool aFix=false)
Parse LIB_ID with the information from aId.
Definition: lib_id.cpp:122
void Parse(PCB_PLOT_PARAMS_PARSER *aParser)
a test point pad
Definition: pad_shapes.h:82
void SetBold(bool aBold)
Definition: eda_text.h:166
void SetPortrait(bool aIsPortrait)
Function SetPortrait will rotate the paper page 90 degrees.
Definition: page_info.cpp:182
static const int UNCONNECTED
Constant that holds the "unconnected net" number (typically 0) all items "connected" to this net are ...
Definition: netinfo.h:462
void SetLossTangent(double aTg, int aDielectricSubLayer=0)
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition: eda_text.h:123
wxPoint m_AuxOrigin
origin for plot exports
DIMENSION.
bool m_TextUpright[LAYER_CLASS_COUNT]
void parseSetup()
T lookUpLayer(const M &aMap)
Function lookUpLayer parses the current token for the layer definition of a BOARD_ITEM object.
void SetThickness(int aNewThickness)
Set the pen width.
Definition: eda_text.h:143
int m_SolderMaskMinWidth
Solder mask min width.
BOARD_DESIGN_SETTINGS contains design settings for a BOARD object.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
MODULE_3D_SETTINGS * parse3DModel()
Definition: pcb_parser.cpp:375