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-2017 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 <errno.h>
31 #include <common.h>
32 #include <confirm.h>
33 #include <macros.h>
34 #include <trigo.h>
35 #include <class_title_block.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_mire.h>
42 #include <class_module.h>
43 #include <class_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 
53 using namespace PCB_KEYS_T;
54 
55 
57 {
58  m_tooRecent = false;
59  m_requiredVersion = 0;
60  m_layerIndices.clear();
61  m_layerMasks.clear();
62 
63  // Add untranslated default (i.e. english) layernames.
64  // Some may be overridden later if parsing a board rather than a footprint.
65  // The english name will survive if parsing only a footprint.
66  for( LAYER_NUM layer = 0; layer < PCB_LAYER_ID_COUNT; ++layer )
67  {
68  std::string untranslated = TO_UTF8( wxString( LSET::Name( PCB_LAYER_ID( layer ) ) ) );
69 
70  m_layerIndices[ untranslated ] = PCB_LAYER_ID( layer );
71  m_layerMasks[ untranslated ] = LSET( PCB_LAYER_ID( layer ) );
72  }
73 
74  m_layerMasks[ "*.Cu" ] = LSET::AllCuMask();
75  m_layerMasks[ "F&B.Cu" ] = LSET( 2, F_Cu, B_Cu );
76  m_layerMasks[ "*.Adhes" ] = LSET( 2, B_Adhes, F_Adhes );
77  m_layerMasks[ "*.Paste" ] = LSET( 2, B_Paste, F_Paste );
78  m_layerMasks[ "*.Mask" ] = LSET( 2, B_Mask, F_Mask );
79  m_layerMasks[ "*.SilkS" ] = LSET( 2, B_SilkS, F_SilkS );
80  m_layerMasks[ "*.Fab" ] = LSET( 2, B_Fab, F_Fab );
81  m_layerMasks[ "*.CrtYd" ] = LSET( 2, B_CrtYd, F_CrtYd );
82 
83  // This is for the first pretty & *.kicad_pcb formats, which had
84  // Inner1_Cu - Inner14_Cu with the numbering sequence
85  // reversed from the subsequent format's In1_Cu - In30_Cu numbering scheme.
86  // The newer format brought in an additional 16 Cu layers and flipped the cu stack but
87  // kept the gap between one of the outside layers and the last cu internal.
88 
89  for( int i=1; i<=14; ++i )
90  {
91  std::string key = StrPrintf( "Inner%d.Cu", i );
92 
93  m_layerMasks[ key ] = LSET( PCB_LAYER_ID( In15_Cu - i ) );
94  }
95 
96 #if defined(DEBUG) && 0
97  printf( "m_layerMasks:\n" );
98  for( LSET_MAP::const_iterator it = m_layerMasks.begin(); it != m_layerMasks.end(); ++it )
99  {
100  printf( " [%s] == 0x%s\n", it->first.c_str(), it->second.FmtHex().c_str() );
101  }
102 
103  printf( "m_layerIndices:\n" );
104  for( LAYER_ID_MAP::const_iterator it = m_layerIndices.begin(); it != m_layerIndices.end(); ++it )
105  {
106  printf( " [%s] == %d\n", it->first.c_str(), it->second );
107  }
108 #endif
109 
110 }
111 
112 
113 void PCB_PARSER::pushValueIntoMap( int aIndex, int aValue )
114 {
115  // Add aValue in netcode mapping (m_netCodes) at index aNetCode
116  // ensure there is room in m_netCodes for that, and add room if needed.
117 
118  if( (int)m_netCodes.size() <= aIndex )
119  m_netCodes.resize( aIndex+1 );
120 
121  m_netCodes[aIndex] = aValue;
122 }
123 
125 {
126  char* tmp;
127 
128  errno = 0;
129 
130  double fval = strtod( CurText(), &tmp );
131 
132  if( errno )
133  {
134  wxString error;
135  error.Printf( _( "invalid floating point number in\nfile: <%s>\nline: %d\noffset: %d" ),
136  GetChars( CurSource() ), CurLineNumber(), CurOffset() );
137 
138  THROW_IO_ERROR( error );
139  }
140 
141  if( CurText() == tmp )
142  {
143  wxString error;
144  error.Printf( _( "missing floating point number in\nfile: <%s>\nline: %d\noffset: %d" ),
145  GetChars( CurSource() ), CurLineNumber(), CurOffset() );
146 
147  THROW_IO_ERROR( error );
148  }
149 
150  return fval;
151 }
152 
153 
155 {
156  T token = NextTok();
157 
158  if( token == T_yes )
159  return true;
160  else if( token == T_no )
161  return false;
162  else
163  Expecting( "yes or no" );
164 
165  return false;
166 }
167 
168 
170 {
171  if( NextTok() != T_version )
172  Expecting( GetTokenText( T_version ) );
173 
174  int pcb_version = parseInt( FromUTF8().mb_str( wxConvUTF8 ) );
175 
176  NeedRIGHT();
177 
178  return pcb_version;
179 }
180 
181 
183 {
184  int year, month, day;
185 
186  year = m_requiredVersion / 10000;
187  month = ( m_requiredVersion / 100 ) - ( year * 100 );
188  day = m_requiredVersion - ( year * 10000 ) - ( month * 100 );
189 
190  // wx throws an assertion, not a catchable exception, when the date is invalid.
191  // User input shouldn't give wx asserts, so check manually and throw a proper
192  // error instead
193  if( day <= 0 || month <= 0 || month > 12 ||
194  day > wxDateTime::GetNumberOfDays( (wxDateTime::Month)( month - 1 ), year ) )
195  {
196  wxString err;
197  err.Printf( _( "cannot interpret date code %d" ), m_requiredVersion );
198  THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
199  }
200 
201  wxDateTime date( day, (wxDateTime::Month)( month - 1 ), year, 0, 0, 0, 0 );
202  return date.FormatDate();
203 }
204 
205 
207 {
208  if( CurTok() != T_LEFT )
209  NeedLEFT();
210 
211  wxPoint pt;
212  T token = NextTok();
213 
214  if( token != T_xy )
215  Expecting( T_xy );
216 
217  pt.x = parseBoardUnits( "X coordinate" );
218  pt.y = parseBoardUnits( "Y coordinate" );
219 
220  NeedRIGHT();
221 
222  return pt;
223 }
224 
225 
226 void PCB_PARSER::parseXY( int* aX, int* aY )
227 {
228  wxPoint pt = parseXY();
229 
230  if( aX )
231  *aX = pt.x;
232 
233  if( aY )
234  *aY = pt.y;
235 }
236 
237 
239 {
240  wxCHECK_RET( CurTok() == T_effects,
241  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as EDA_TEXT." ) );
242 
243  T token;
244 
245  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
246  {
247  if( token == T_LEFT )
248  token = NextTok();
249 
250  switch( token )
251  {
252  case T_font:
253  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
254  {
255  if( token == T_LEFT )
256  continue;
257 
258  switch( token )
259  {
260  case T_size:
261  {
262  wxSize sz;
263  sz.SetHeight( parseBoardUnits( "text height" ) );
264  sz.SetWidth( parseBoardUnits( "text width" ) );
265  aText->SetTextSize( sz );
266  NeedRIGHT();
267  }
268  break;
269 
270  case T_thickness:
271  aText->SetThickness( parseBoardUnits( "text thickness" ) );
272  NeedRIGHT();
273  break;
274 
275  case T_bold:
276  aText->SetBold( true );
277  break;
278 
279  case T_italic:
280  aText->SetItalic( true );
281  break;
282 
283  default:
284  Expecting( "size, bold, or italic" );
285  }
286  }
287  break;
288 
289  case T_justify:
290  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
291  {
292  if( token == T_LEFT )
293  continue;
294 
295  switch( token )
296  {
297  case T_left:
299  break;
300 
301  case T_right:
303  break;
304 
305  case T_top:
307  break;
308 
309  case T_bottom:
311  break;
312 
313  case T_mirror:
314  aText->SetMirrored( true );
315  break;
316 
317  default:
318  Expecting( "left, right, top, bottom, or mirror" );
319  }
320 
321  }
322  break;
323 
324  case T_hide:
325  aText->SetVisible( false );
326  break;
327 
328  default:
329  Expecting( "font, justify, or hide" );
330  }
331  }
332 }
333 
334 
336 {
337  wxCHECK_MSG( CurTok() == T_model, NULL,
338  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as S3D_INFO." ) );
339 
340  T token;
341 
342  S3D_INFO* n3D = new S3D_INFO;
343  NeedSYMBOLorNUMBER();
344  n3D->m_Filename = FromUTF8();
345 
346  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
347  {
348  if( token != T_LEFT )
349  Expecting( T_LEFT );
350 
351  token = NextTok();
352 
353  switch( token )
354  {
355  case T_at:
356  NeedLEFT();
357  token = NextTok();
358 
359  if( token != T_xyz )
360  Expecting( T_xyz );
361 
362  n3D->m_Offset.x = parseDouble( "x value" );
363  n3D->m_Offset.y = parseDouble( "y value" );
364  n3D->m_Offset.z = parseDouble( "z value" );
365  NeedRIGHT();
366  break;
367 
368  case T_scale:
369  NeedLEFT();
370  token = NextTok();
371 
372  if( token != T_xyz )
373  Expecting( T_xyz );
374 
375  n3D->m_Scale.x = parseDouble( "x value" );
376  n3D->m_Scale.y = parseDouble( "y value" );
377  n3D->m_Scale.z = parseDouble( "z value" );
378  NeedRIGHT();
379  break;
380 
381  case T_rotate:
382  NeedLEFT();
383  token = NextTok();
384 
385  if( token != T_xyz )
386  Expecting( T_xyz );
387 
388  n3D->m_Rotation.x = parseDouble( "x value" );
389  n3D->m_Rotation.y = parseDouble( "y value" );
390  n3D->m_Rotation.z = parseDouble( "z value" );
391  NeedRIGHT();
392  break;
393 
394  default:
395  Expecting( "at, scale, or rotate" );
396  }
397 
398  NeedRIGHT();
399  }
400 
401  return n3D;
402 }
403 
404 
406 {
407  T token;
408  BOARD_ITEM* item;
409  LOCALE_IO toggle;
410 
411  // MODULEs can be prefixed with an initial block of single line comments and these
412  // are kept for Format() so they round trip in s-expression form. BOARDs might
413  // eventually do the same, but currently do not.
414  std::unique_ptr<wxArrayString> initial_comments( ReadCommentLines() );
415 
416  token = CurTok();
417 
418  if( token != T_LEFT )
419  Expecting( T_LEFT );
420 
421  switch( NextTok() )
422  {
423  case T_kicad_pcb:
424  if( m_board == NULL )
425  m_board = new BOARD();
426 
427  item = (BOARD_ITEM*) parseBOARD();
428  break;
429 
430  case T_module:
431  item = (BOARD_ITEM*) parseMODULE( initial_comments.release() );
432  break;
433 
434  default:
435  wxString err;
436  err.Printf( _( "unknown token \"%s\"" ), GetChars( FromUTF8() ) );
437  THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
438  }
439 
440  return item;
441 }
442 
443 
445 {
446  try
447  {
448  return parseBOARD_unchecked();
449  }
450  catch( const PARSE_ERROR& parse_error )
451  {
452  if( m_tooRecent )
453  throw FUTURE_FORMAT_ERROR( parse_error, GetRequiredVersion() );
454  else
455  throw;
456  }
457 }
458 
459 
461 {
462  T token;
463 
464  parseHeader();
465 
466  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
467  {
468  if( token != T_LEFT )
469  Expecting( T_LEFT );
470 
471  token = NextTok();
472 
473  switch( token )
474  {
475  case T_general:
476  parseGeneralSection();
477  break;
478 
479  case T_page:
480  parsePAGE_INFO();
481  break;
482 
483  case T_title_block:
484  parseTITLE_BLOCK();
485  break;
486 
487  case T_layers:
488  parseLayers();
489  break;
490 
491  case T_setup:
492  parseSetup();
493  break;
494 
495  case T_net:
496  parseNETINFO_ITEM();
497  break;
498 
499  case T_net_class:
500  parseNETCLASS();
501  break;
502 
503  case T_gr_arc:
504  case T_gr_circle:
505  case T_gr_curve:
506  case T_gr_line:
507  case T_gr_poly:
508  m_board->Add( parseDRAWSEGMENT(), ADD_APPEND );
509  break;
510 
511  case T_gr_text:
512  m_board->Add( parseTEXTE_PCB(), ADD_APPEND );
513  break;
514 
515  case T_dimension:
516  m_board->Add( parseDIMENSION(), ADD_APPEND );
517  break;
518 
519  case T_module:
520  m_board->Add( parseMODULE(), ADD_APPEND );
521  break;
522 
523  case T_segment:
524  m_board->Add( parseTRACK(), ADD_APPEND );
525  break;
526 
527  case T_via:
528  m_board->Add( parseVIA(), ADD_APPEND );
529  break;
530 
531  case T_zone:
532  m_board->Add( parseZONE_CONTAINER(), ADD_APPEND );
533  break;
534 
535  case T_target:
536  m_board->Add( parsePCB_TARGET(), ADD_APPEND );
537  break;
538 
539  default:
540  wxString err;
541  err.Printf( _( "unknown token \"%s\"" ), GetChars( FromUTF8() ) );
542  THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
543  }
544  }
545 
546  return m_board;
547 }
548 
549 
551 {
552  wxCHECK_RET( CurTok() == T_kicad_pcb,
553  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a header." ) );
554 
555  NeedLEFT();
556 
557  T tok = NextTok();
558  if( tok == T_version )
559  {
560  m_requiredVersion = parseInt( FromUTF8().mb_str( wxConvUTF8 ) );
561  m_tooRecent = ( m_requiredVersion > SEXPR_BOARD_FILE_VERSION );
562  NeedRIGHT();
563 
564  // Skip the host name and host build version information.
565  NeedLEFT();
566  NeedSYMBOL();
567  NeedSYMBOL();
568  NeedSYMBOL();
569  NeedRIGHT();
570  }
571  else
572  {
573  m_requiredVersion = SEXPR_BOARD_FILE_VERSION;
574  m_tooRecent = ( m_requiredVersion > SEXPR_BOARD_FILE_VERSION );
575 
576  // Skip the host name and host build version information.
577  NeedSYMBOL();
578  NeedSYMBOL();
579  NeedRIGHT();
580  }
581 
582  m_board->SetFileFormatVersionAtLoad( m_requiredVersion );
583 }
584 
585 
587 {
588  wxCHECK_RET( CurTok() == T_general,
589  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) +
590  wxT( " as a general section." ) );
591 
592  T token;
593 
594  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
595  {
596  if( token != T_LEFT )
597  Expecting( T_LEFT );
598 
599  token = NextTok();
600 
601  switch( token )
602  {
603  case T_thickness:
604  m_board->GetDesignSettings().SetBoardThickness( parseBoardUnits( T_thickness ) );
605  NeedRIGHT();
606  break;
607 
608  case T_nets:
609  m_netCodes.resize( parseInt( "nets number" ) );
610  NeedRIGHT();
611  break;
612 
613  case T_no_connects:
614  // ignore
615  parseInt( "no connect count" );
616  NeedRIGHT();
617  break;
618 
619  default: // Skip everything but the board thickness.
620  //wxLogDebug( wxT( "Skipping general section token %s " ), GetChars( GetTokenString( token ) ) );
621 
622  while( ( token = NextTok() ) != T_RIGHT )
623  {
624  if( !IsSymbol( token ) && token != T_NUMBER )
625  Expecting( "symbol or number" );
626  }
627  }
628  }
629 }
630 
631 
633 {
634  wxCHECK_RET( CurTok() == T_page,
635  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as a PAGE_INFO." ) );
636 
637  T token;
638  PAGE_INFO pageInfo;
639 
640  NeedSYMBOL();
641 
642  wxString pageType = FromUTF8();
643 
644  if( !pageInfo.SetType( pageType ) )
645  {
646  wxString err;
647  err.Printf( _( "page type \"%s\" is not valid " ), GetChars( FromUTF8() ) );
648  THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
649  }
650 
651  if( pageType == PAGE_INFO::Custom )
652  {
653  double width = parseDouble( "width" ); // width in mm
654 
655  // Perform some controls to avoid crashes if the size is edited by hands
656  if( width < 100.0 )
657  width = 100.0;
658  else if( width > 1200.0 )
659  width = 1200.0;
660 
661  double height = parseDouble( "height" ); // height in mm
662 
663  if( height < 100.0 )
664  height = 100.0;
665  else if( height > 1200.0 )
666  height = 1200.0;
667 
668  pageInfo.SetWidthMils( Mm2mils( width ) );
669  pageInfo.SetHeightMils( Mm2mils( height ) );
670  }
671 
672  token = NextTok();
673 
674  if( token == T_portrait )
675  {
676  pageInfo.SetPortrait( true );
677  NeedRIGHT();
678  }
679  else if( token != T_RIGHT )
680  {
681  Expecting( "portrait|)" );
682  }
683 
684  m_board->SetPageSettings( pageInfo );
685 }
686 
687 
689 {
690  wxCHECK_RET( CurTok() == T_title_block,
691  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) +
692  wxT( " as TITLE_BLOCK." ) );
693 
694  T token;
695  TITLE_BLOCK titleBlock;
696 
697  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
698  {
699  if( token != T_LEFT )
700  Expecting( T_LEFT );
701 
702  token = NextTok();
703 
704  switch( token )
705  {
706  case T_title:
707  NextTok();
708  titleBlock.SetTitle( FromUTF8() );
709  break;
710 
711  case T_date:
712  NextTok();
713  titleBlock.SetDate( FromUTF8() );
714  break;
715 
716  case T_rev:
717  NextTok();
718  titleBlock.SetRevision( FromUTF8() );
719  break;
720 
721  case T_company:
722  NextTok();
723  titleBlock.SetCompany( FromUTF8() );
724  break;
725 
726  case T_comment:
727  {
728  int commentNumber = parseInt( "comment" );
729 
730  switch( commentNumber )
731  {
732  case 1:
733  NextTok();
734  titleBlock.SetComment1( FromUTF8() );
735  break;
736 
737  case 2:
738  NextTok();
739  titleBlock.SetComment2( FromUTF8() );
740  break;
741 
742  case 3:
743  NextTok();
744  titleBlock.SetComment3( FromUTF8() );
745  break;
746 
747  case 4:
748  NextTok();
749  titleBlock.SetComment4( FromUTF8() );
750  break;
751 
752  default:
753  wxString err;
754  err.Printf( wxT( "%d is not a valid title block comment number" ), commentNumber );
755  THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
756  }
757  }
758  break;
759 
760  default:
761  Expecting( "title, date, rev, company, or comment" );
762  }
763 
764  NeedRIGHT();
765  }
766 
767  m_board->SetTitleBlock( titleBlock );
768 }
769 
770 
772 {
773  T token;
774 
775  std::string name;
776  std::string type;
777  bool isVisible = true;
778 
779  aLayer->clear();
780 
781  if( CurTok() != T_LEFT )
782  Expecting( T_LEFT );
783 
784  // this layer_num is not used, we DO depend on LAYER_T however.
785  LAYER_NUM layer_num = parseInt( "layer index" );
786 
787  NeedSYMBOLorNUMBER();
788  name = CurText();
789 
790  NeedSYMBOL();
791  type = CurText();
792 
793  token = NextTok();
794 
795  if( token == T_hide )
796  {
797  isVisible = false;
798  NeedRIGHT();
799  }
800  else if( token != T_RIGHT )
801  {
802  Expecting( "hide or )" );
803  }
804 
805  aLayer->m_name = FROM_UTF8( name.c_str() );
806  aLayer->m_type = LAYER::ParseType( type.c_str() );
807  aLayer->m_number = layer_num;
808  aLayer->m_visible = isVisible;
809 }
810 
811 
812 
814 {
815  wxCHECK_RET( CurTok() == T_layers,
816  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as layers." ) );
817 
818  T token;
819  LSET visibleLayers;
820  LSET enabledLayers;
821  int copperLayerCount = 0;
822  LAYER layer;
823 
824  std::vector<LAYER> cu;
825 
826  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
827  {
828  parseLayer( &layer );
829 
830  if( layer.m_type == LT_UNDEFINED ) // it's a non-copper layer
831  break;
832 
833  cu.push_back( layer ); // it's copper
834  }
835 
836  // All Cu layers are parsed, but not the non-cu layers here.
837 
838  // The original *.kicad_pcb file format and the inverted
839  // Cu stack format both have all the Cu layers first, so use this
840  // trick to handle either. The layer number in the (layers ..)
841  // s-expression element are ignored.
842  if( cu.size() )
843  {
844  // Rework the layer numbers, which changed when the Cu stack
845  // was flipped. So we instead use position in the list.
846  cu[cu.size()-1].m_number = B_Cu;
847 
848  for( unsigned i=0; i < cu.size()-1; ++i )
849  {
850  cu[i].m_number = i;
851  }
852 
853  for( std::vector<LAYER>::const_iterator it = cu.begin(); it<cu.end(); ++it )
854  {
855  enabledLayers.set( it->m_number );
856 
857  if( it->m_visible )
858  visibleLayers.set( it->m_number );
859 
860  m_board->SetLayerDescr( PCB_LAYER_ID( it->m_number ), *it );
861 
862  UTF8 name = it->m_name;
863 
864  m_layerIndices[ name ] = PCB_LAYER_ID( it->m_number );
865  m_layerMasks[ name ] = LSET( PCB_LAYER_ID( it->m_number ) );
866  }
867 
868  copperLayerCount = cu.size();
869  }
870 
871  // process non-copper layers
872  while( token != T_RIGHT )
873  {
874  LAYER_ID_MAP::const_iterator it = m_layerIndices.find( UTF8( layer.m_name ) );
875 
876  if( it == m_layerIndices.end() )
877  {
878  wxString error = wxString::Format(
879  _( "Layer '%s' in file '%s' at line %d, is not in fixed layer hash" ),
880  GetChars( layer.m_name ),
881  GetChars( CurSource() ),
882  CurLineNumber(),
883  CurOffset()
884  );
885 
886  THROW_IO_ERROR( error );
887  }
888 
889  layer.m_number = it->second;
890 
891  enabledLayers.set( layer.m_number );
892 
893  if( layer.m_visible )
894  visibleLayers.set( layer.m_number );
895 
896  // DBG( printf( "aux m_visible:%s\n", layer.m_visible ? "true" : "false" );)
897 
898  m_board->SetLayerDescr( it->second, layer );
899 
900  token = NextTok();
901 
902  if( token != T_LEFT )
903  break;
904 
905  parseLayer( &layer );
906  }
907 
908  // We need at least 2 copper layers and there must be an even number of them.
909  if( copperLayerCount < 2 || (copperLayerCount % 2) != 0 )
910  {
911  wxString err = wxString::Format(
912  _( "%d is not a valid layer count" ), copperLayerCount );
913 
914  THROW_PARSE_ERROR( err, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
915  }
916 
917  m_board->SetCopperLayerCount( copperLayerCount );
918  m_board->SetEnabledLayers( enabledLayers );
919 
920  // call SetEnabledLayers before SetVisibleLayers()
921  m_board->SetVisibleLayers( visibleLayers );
922 }
923 
924 
925 template<class T, class M>
926 T PCB_PARSER::lookUpLayer( const M& aMap )
927 {
928  // avoid constructing another std::string, use lexer's directly
929  typename M::const_iterator it = aMap.find( curText );
930 
931  if( it == aMap.end() )
932  {
933 #if 0 && defined(DEBUG)
934  // dump the whole darn table, there's something wrong with it.
935  for( it = aMap.begin(); it != aMap.end(); ++it )
936  {
937  wxLogDebug( &aMap == (void*)&m_layerIndices ? wxT( "lm[%s] = %d" ) :
938  wxT( "lm[%s] = %08X" ), it->first.c_str(), it->second );
939  }
940 #endif
941 
942  wxString error = wxString::Format( _(
943  "Layer '%s' in file\n"
944  "'%s'\n"
945  "at line %d, position %d\n"
946  "was not defined in the layers section"
947  ),
948  GetChars( FROM_UTF8( CurText() ) ),
949  GetChars( CurSource() ),
950  CurLineNumber(), CurOffset() );
951 
952  THROW_IO_ERROR( error );
953  }
954 
955  return it->second;
956 }
957 
958 
960 {
961  wxCHECK_MSG( CurTok() == T_layer, UNDEFINED_LAYER,
962  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as layer." ) );
963 
964  NextTok();
965 
966  PCB_LAYER_ID layerIndex = lookUpLayer<PCB_LAYER_ID>( m_layerIndices );
967 
968  // Handle closing ) in object parser.
969 
970  return layerIndex;
971 }
972 
973 
975 {
976  wxCHECK_MSG( CurTok() == T_layers, LSET(),
977  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) +
978  wxT( " as item layer mask." ) );
979 
980  LSET layerMask;
981 
982  for( T token = NextTok(); token != T_RIGHT; token = NextTok() )
983  {
984  LSET mask = lookUpLayer<LSET>( m_layerMasks );
985  layerMask |= mask;
986  }
987 
988  return layerMask;
989 }
990 
991 
993 {
994  wxCHECK_RET( CurTok() == T_setup,
995  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as setup." ) );
996 
997  T token;
998  NETCLASSPTR defaultNetClass = m_board->GetDesignSettings().GetDefault();
999  // TODO Orson: is it really necessary to first operate on a copy and then apply it?
1000  // would not it be better to use reference here and apply all the changes instantly?
1001  BOARD_DESIGN_SETTINGS designSettings = m_board->GetDesignSettings();
1002  ZONE_SETTINGS zoneSettings = m_board->GetZoneSettings();
1003 
1004  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1005  {
1006  if( token != T_LEFT )
1007  Expecting( T_LEFT );
1008 
1009  token = NextTok();
1010 
1011  switch( token )
1012  {
1013  case T_last_trace_width: // not used now
1014  /* lastTraceWidth =*/ parseBoardUnits( T_last_trace_width );
1015  NeedRIGHT();
1016  break;
1017 
1018  case T_user_trace_width:
1019  designSettings.m_TrackWidthList.push_back( parseBoardUnits( T_user_trace_width ) );
1020  NeedRIGHT();
1021  break;
1022 
1023  case T_trace_clearance:
1024  defaultNetClass->SetClearance( parseBoardUnits( T_trace_clearance ) );
1025  NeedRIGHT();
1026  break;
1027 
1028  case T_zone_clearance:
1029  zoneSettings.m_ZoneClearance = parseBoardUnits( T_zone_clearance );
1030  NeedRIGHT();
1031  break;
1032 
1033  case T_zone_45_only:
1034  zoneSettings.m_Zone_45_Only = parseBool();
1035  NeedRIGHT();
1036  break;
1037 
1038  case T_trace_min:
1039  designSettings.m_TrackMinWidth = parseBoardUnits( T_trace_min );
1040  NeedRIGHT();
1041  break;
1042 
1043  case T_segment_width:
1044  designSettings.m_DrawSegmentWidth = parseBoardUnits( T_segment_width );
1045  NeedRIGHT();
1046  break;
1047 
1048  case T_edge_width:
1049  designSettings.m_EdgeSegmentWidth = parseBoardUnits( T_edge_width );
1050  NeedRIGHT();
1051  break;
1052 
1053  case T_via_size:
1054  defaultNetClass->SetViaDiameter( parseBoardUnits( T_via_size ) );
1055  NeedRIGHT();
1056  break;
1057 
1058  case T_via_drill:
1059  defaultNetClass->SetViaDrill( parseBoardUnits( T_via_drill ) );
1060  NeedRIGHT();
1061  break;
1062 
1063  case T_via_min_size:
1064  designSettings.m_ViasMinSize = parseBoardUnits( T_via_min_size );
1065  NeedRIGHT();
1066  break;
1067 
1068  case T_via_min_drill:
1069  designSettings.m_ViasMinDrill = parseBoardUnits( T_via_min_drill );
1070  NeedRIGHT();
1071  break;
1072 
1073  case T_user_via:
1074  {
1075  int viaSize = parseBoardUnits( "user via size" );
1076  int viaDrill = parseBoardUnits( "user via drill" );
1077  designSettings.m_ViasDimensionsList.push_back( VIA_DIMENSION( viaSize, viaDrill ) );
1078  NeedRIGHT();
1079  }
1080  break;
1081 
1082  case T_uvia_size:
1083  defaultNetClass->SetuViaDiameter( parseBoardUnits( T_uvia_size ) );
1084  NeedRIGHT();
1085  break;
1086 
1087  case T_uvia_drill:
1088  defaultNetClass->SetuViaDrill( parseBoardUnits( T_uvia_drill ) );
1089  NeedRIGHT();
1090  break;
1091 
1092  case T_uvias_allowed:
1093  designSettings.m_MicroViasAllowed = parseBool();
1094  NeedRIGHT();
1095  break;
1096 
1098  designSettings.m_BlindBuriedViaAllowed = parseBool();
1099  NeedRIGHT();
1100  break;
1101 
1102  case T_uvia_min_size:
1103  designSettings.m_MicroViasMinSize = parseBoardUnits( T_uvia_min_size );
1104  NeedRIGHT();
1105  break;
1106 
1107  case T_uvia_min_drill:
1108  designSettings.m_MicroViasMinDrill = parseBoardUnits( T_uvia_min_drill );
1109  NeedRIGHT();
1110  break;
1111 
1112  case T_pcb_text_width:
1113  designSettings.m_PcbTextWidth = parseBoardUnits( T_pcb_text_width );
1114  NeedRIGHT();
1115  break;
1116 
1117  case T_pcb_text_size:
1118  designSettings.m_PcbTextSize.x = parseBoardUnits( "pcb text width" );
1119  designSettings.m_PcbTextSize.y = parseBoardUnits( "pcb text height" );
1120  NeedRIGHT();
1121  break;
1122 
1123  case T_mod_edge_width:
1124  designSettings.m_ModuleSegmentWidth = parseBoardUnits( T_mod_edge_width );
1125  NeedRIGHT();
1126  break;
1127 
1128  case T_mod_text_size:
1129  designSettings.m_ModuleTextSize.x = parseBoardUnits( "module text width" );
1130  designSettings.m_ModuleTextSize.y = parseBoardUnits( "module text height" );
1131  NeedRIGHT();
1132  break;
1133 
1134  case T_mod_text_width:
1135  designSettings.m_ModuleTextWidth = parseBoardUnits( T_mod_text_width );
1136  NeedRIGHT();
1137  break;
1138 
1139  case T_pad_size:
1140  {
1141  wxSize sz;
1142  sz.SetWidth( parseBoardUnits( "master pad width" ) );
1143  sz.SetHeight( parseBoardUnits( "master pad height" ) );
1144  designSettings.m_Pad_Master.SetSize( sz );
1145  NeedRIGHT();
1146  }
1147  break;
1148 
1149  case T_pad_drill:
1150  {
1151  int drillSize = parseBoardUnits( T_pad_drill );
1152  designSettings.m_Pad_Master.SetDrillSize( wxSize( drillSize, drillSize ) );
1153  NeedRIGHT();
1154  }
1155  break;
1156 
1158  designSettings.m_SolderMaskMargin = parseBoardUnits( T_pad_to_mask_clearance );
1159  NeedRIGHT();
1160  break;
1161 
1163  designSettings.m_SolderMaskMinWidth = parseBoardUnits( T_solder_mask_min_width );
1164  NeedRIGHT();
1165  break;
1166 
1168  designSettings.m_SolderPasteMargin = parseBoardUnits( T_pad_to_paste_clearance );
1169  NeedRIGHT();
1170  break;
1171 
1174  NeedRIGHT();
1175  break;
1176 
1177  case T_aux_axis_origin:
1178  {
1179  int x = parseBoardUnits( "auxiliary origin X" );
1180  int y = parseBoardUnits( "auxiliary origin Y" );
1181  // m_board->SetAuxOrigin( wxPoint( x, y ) ); gets overwritten via SetDesignSettings below
1182  designSettings.m_AuxOrigin = wxPoint( x, y );
1183  NeedRIGHT();
1184  }
1185  break;
1186 
1187  case T_grid_origin:
1188  {
1189  int x = parseBoardUnits( "grid origin X" );
1190  int y = parseBoardUnits( "grid origin Y" );
1191  // m_board->SetGridOrigin( wxPoint( x, y ) ); gets overwritten SetDesignSettings below
1192  designSettings.m_GridOrigin = wxPoint( x, y );
1193  NeedRIGHT();
1194  }
1195  break;
1196 
1197  case T_visible_elements:
1198  designSettings.SetVisibleElements( parseHex() | MIN_VISIBILITY_MASK );
1199  NeedRIGHT();
1200  break;
1201 
1202  case T_pcbplotparams:
1203  {
1204  PCB_PLOT_PARAMS plotParams;
1205  PCB_PLOT_PARAMS_PARSER parser( reader );
1206  // parser must share the same current line as our current PCB parser
1207  // synchronize it.
1208  parser.SyncLineReaderWith( *this );
1209 
1210  plotParams.Parse( &parser );
1211  SyncLineReaderWith( parser );
1212 
1213  m_board->SetPlotOptions( plotParams );
1214  }
1215  break;
1216 
1217  default:
1218  Unexpected( CurText() );
1219  }
1220  }
1221 
1222  m_board->SetDesignSettings( designSettings );
1223  m_board->SetZoneSettings( zoneSettings );
1224 }
1225 
1226 
1228 {
1229  wxCHECK_RET( CurTok() == T_net,
1230  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as net." ) );
1231 
1232  int netCode = parseInt( "net number" );
1233 
1234  NeedSYMBOLorNUMBER();
1235  wxString name = FromUTF8();
1236 
1237  NeedRIGHT();
1238 
1239  // net 0 should be already in list, so store this net
1240  // if it is not the net 0, or if the net 0 does not exists.
1241  // (TODO: a better test.)
1242  if( netCode > NETINFO_LIST::UNCONNECTED || !m_board->FindNet( NETINFO_LIST::UNCONNECTED ) )
1243  {
1244  NETINFO_ITEM* net = new NETINFO_ITEM( m_board, name, netCode );
1245  m_board->Add( net );
1246 
1247  // Store the new code mapping
1248  pushValueIntoMap( netCode, net->GetNet() );
1249  }
1250 }
1251 
1252 
1254 {
1255  wxCHECK_RET( CurTok() == T_net_class,
1256  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as net class." ) );
1257 
1258  T token;
1259 
1260  NETCLASSPTR nc = std::make_shared<NETCLASS>( wxEmptyString );
1261 
1262  // Read netclass name (can be a name or just a number like track width)
1263  NeedSYMBOLorNUMBER();
1264  nc->SetName( FromUTF8() );
1265  NeedSYMBOL();
1266  nc->SetDescription( FromUTF8() );
1267 
1268  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1269  {
1270  if( token != T_LEFT )
1271  Expecting( T_LEFT );
1272 
1273  token = NextTok();
1274 
1275  switch( token )
1276  {
1277  case T_clearance:
1278  nc->SetClearance( parseBoardUnits( T_clearance ) );
1279  break;
1280 
1281  case T_trace_width:
1282  nc->SetTrackWidth( parseBoardUnits( T_trace_width ) );
1283  break;
1284 
1285  case T_via_dia:
1286  nc->SetViaDiameter( parseBoardUnits( T_via_dia ) );
1287  break;
1288 
1289  case T_via_drill:
1290  nc->SetViaDrill( parseBoardUnits( T_via_drill ) );
1291  break;
1292 
1293  case T_uvia_dia:
1294  nc->SetuViaDiameter( parseBoardUnits( T_uvia_dia ) );
1295  break;
1296 
1297  case T_uvia_drill:
1298  nc->SetuViaDrill( parseBoardUnits( T_uvia_drill ) );
1299  break;
1300 
1301  case T_diff_pair_width:
1302  nc->SetDiffPairWidth( parseBoardUnits( T_diff_pair_width ) );
1303  break;
1304 
1305  case T_diff_pair_gap:
1306  nc->SetDiffPairGap( parseBoardUnits( T_diff_pair_gap ) );
1307  break;
1308 
1309  case T_add_net:
1310  NeedSYMBOLorNUMBER();
1311  nc->Add( FromUTF8() );
1312  break;
1313 
1314  default:
1315  Expecting( "clearance, trace_width, via_dia, via_drill, uvia_dia, uvia_drill, diff_pair_width, diff_pair_gap or add_net" );
1316  }
1317 
1318  NeedRIGHT();
1319  }
1320 
1321  if( !m_board->GetDesignSettings().m_NetClasses.Add( nc ) )
1322  {
1323  // Must have been a name conflict, this is a bad board file.
1324  // User may have done a hand edit to the file.
1325 
1326  // unique_ptr will delete nc on this code path
1327 
1328  wxString error;
1329  error.Printf( _( "duplicate NETCLASS name '%s' in file <%s> at line %d, offset %d" ),
1330  nc->GetName().GetData(), CurSource().GetData(), CurLineNumber(), CurOffset() );
1331  THROW_IO_ERROR( error );
1332  }
1333 }
1334 
1335 
1337 {
1338  wxCHECK_MSG( CurTok() == T_gr_arc || CurTok() == T_gr_circle || CurTok() == T_gr_curve ||
1339  CurTok() == T_gr_line || CurTok() == T_gr_poly, NULL,
1340  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as DRAWSEGMENT." ) );
1341 
1342  T token;
1343  wxPoint pt;
1344  std::unique_ptr< DRAWSEGMENT > segment( new DRAWSEGMENT( NULL ) );
1345 
1346  switch( CurTok() )
1347  {
1348  case T_gr_arc:
1349  segment->SetShape( S_ARC );
1350  NeedLEFT();
1351  token = NextTok();
1352 
1353  // the start keyword actually gives the arc center
1354  // Allows also T_center for future change
1355  if( token != T_start && token != T_center )
1356  Expecting( T_start );
1357 
1358  pt.x = parseBoardUnits( "X coordinate" );
1359  pt.y = parseBoardUnits( "Y coordinate" );
1360  segment->SetCenter( pt );
1361  NeedRIGHT();
1362  NeedLEFT();
1363  token = NextTok();
1364 
1365  if( token != T_end ) // the end keyword actually gives the starting point of the arc
1366  Expecting( T_end );
1367 
1368  pt.x = parseBoardUnits( "X coordinate" );
1369  pt.y = parseBoardUnits( "Y coordinate" );
1370  segment->SetArcStart( pt );
1371  NeedRIGHT();
1372  break;
1373 
1374  case T_gr_circle:
1375  segment->SetShape( S_CIRCLE );
1376  NeedLEFT();
1377  token = NextTok();
1378 
1379  if( token != T_center )
1380  Expecting( T_center );
1381 
1382  pt.x = parseBoardUnits( "X coordinate" );
1383  pt.y = parseBoardUnits( "Y coordinate" );
1384  segment->SetCenter( pt );
1385  NeedRIGHT();
1386  NeedLEFT();
1387 
1388  token = NextTok();
1389 
1390  if( token != T_end )
1391  Expecting( T_end );
1392 
1393  pt.x = parseBoardUnits( "X coordinate" );
1394  pt.y = parseBoardUnits( "Y coordinate" );
1395  segment->SetEnd( pt );
1396  NeedRIGHT();
1397  break;
1398 
1399  case T_gr_curve:
1400  segment->SetShape( S_CURVE );
1401  NeedLEFT();
1402  token = NextTok();
1403 
1404  if( token != T_pts )
1405  Expecting( T_pts );
1406 
1407  segment->SetStart( parseXY() );
1408  segment->SetBezControl1( parseXY() );
1409  segment->SetBezControl2( parseXY() );
1410  segment->SetEnd( parseXY() );
1411  NeedRIGHT();
1412  break;
1413 
1414  case T_gr_line:
1415  // Default DRAWSEGMENT type is S_SEGMENT.
1416  NeedLEFT();
1417  token = NextTok();
1418 
1419  if( token != T_start )
1420  Expecting( T_start );
1421 
1422  pt.x = parseBoardUnits( "X coordinate" );
1423  pt.y = parseBoardUnits( "Y coordinate" );
1424  segment->SetStart( pt );
1425  NeedRIGHT();
1426  NeedLEFT();
1427  token = NextTok();
1428 
1429  if( token != T_end )
1430  Expecting( T_end );
1431 
1432  pt.x = parseBoardUnits( "X coordinate" );
1433  pt.y = parseBoardUnits( "Y coordinate" );
1434  segment->SetEnd( pt );
1435  NeedRIGHT();
1436  break;
1437 
1438  case T_gr_poly:
1439  {
1440  segment->SetShape( S_POLYGON );
1441  NeedLEFT();
1442  token = NextTok();
1443 
1444  if( token != T_pts )
1445  Expecting( T_pts );
1446 
1447  std::vector< wxPoint > pts;
1448 
1449  while( (token = NextTok()) != T_RIGHT )
1450  pts.push_back( parseXY() );
1451 
1452  segment->SetPolyPoints( pts );
1453  }
1454  break;
1455 
1456  default:
1457  Expecting( "gr_arc, gr_circle, gr_curve, gr_line, or gr_poly" );
1458  }
1459 
1460  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1461  {
1462  if( token != T_LEFT )
1463  Expecting( T_LEFT );
1464 
1465  token = NextTok();
1466 
1467  switch( token )
1468  {
1469  case T_angle:
1470  segment->SetAngle( parseDouble( "segment angle" ) * 10.0 );
1471  break;
1472 
1473  case T_layer:
1474  segment->SetLayer( parseBoardItemLayer() );
1475  break;
1476 
1477  case T_width:
1478  segment->SetWidth( parseBoardUnits( T_width ) );
1479  break;
1480 
1481  case T_tstamp:
1482  segment->SetTimeStamp( parseHex() );
1483  break;
1484 
1485  case T_status:
1486  segment->SetStatus( static_cast<STATUS_FLAGS>( parseHex() ) );
1487  break;
1488 
1489  default:
1490  Expecting( "layer, width, tstamp, or status" );
1491  }
1492 
1493  NeedRIGHT();
1494  }
1495 
1496  return segment.release();
1497 }
1498 
1499 
1501 {
1502  wxCHECK_MSG( CurTok() == T_gr_text, NULL,
1503  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as TEXTE_PCB." ) );
1504 
1505  T token;
1506 
1507  std::unique_ptr<TEXTE_PCB> text( new TEXTE_PCB( m_board ) );
1508  NeedSYMBOLorNUMBER();
1509 
1510  text->SetText( FromUTF8() );
1511  NeedLEFT();
1512  token = NextTok();
1513 
1514  if( token != T_at )
1515  Expecting( T_at );
1516 
1517  wxPoint pt;
1518 
1519  pt.x = parseBoardUnits( "X coordinate" );
1520  pt.y = parseBoardUnits( "Y coordinate" );
1521  text->SetTextPos( pt );
1522 
1523  // If there is no orientation defined, then it is the default value of 0 degrees.
1524  token = NextTok();
1525 
1526  if( token == T_NUMBER )
1527  {
1528  text->SetTextAngle( parseDouble() * 10.0 );
1529  NeedRIGHT();
1530  }
1531  else if( token != T_RIGHT )
1532  {
1533  Unexpected( CurText() );
1534  }
1535 
1536  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1537  {
1538  if( token != T_LEFT )
1539  Expecting( T_LEFT );
1540 
1541  token = NextTok();
1542 
1543  switch( token )
1544  {
1545  case T_layer:
1546  text->SetLayer( parseBoardItemLayer() );
1547  NeedRIGHT();
1548  break;
1549 
1550  case T_tstamp:
1551  text->SetTimeStamp( parseHex() );
1552  NeedRIGHT();
1553  break;
1554 
1555  case T_effects:
1556  parseEDA_TEXT( (EDA_TEXT*) text.get() );
1557  break;
1558 
1559  default:
1560  Expecting( "layer, tstamp or effects" );
1561  }
1562  }
1563 
1564  return text.release();
1565 }
1566 
1567 
1569 {
1570  wxCHECK_MSG( CurTok() == T_dimension, NULL,
1571  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as DIMENSION." ) );
1572 
1573  T token;
1574 
1575  std::unique_ptr<DIMENSION> dimension( new DIMENSION( NULL ) );
1576 
1577  dimension->SetValue( parseBoardUnits( "dimension value" ) );
1578  NeedLEFT();
1579  token = NextTok();
1580 
1581  if( token != T_width )
1582  Expecting( T_width );
1583 
1584  dimension->SetWidth( parseBoardUnits( "dimension width value" ) );
1585  NeedRIGHT();
1586 
1587  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1588  {
1589  if( token != T_LEFT )
1590  Expecting( T_LEFT );
1591 
1592  token = NextTok();
1593 
1594  switch( token )
1595  {
1596  case T_layer:
1597  dimension->SetLayer( parseBoardItemLayer() );
1598  NeedRIGHT();
1599  break;
1600 
1601  case T_tstamp:
1602  dimension->SetTimeStamp( parseHex() );
1603  NeedRIGHT();
1604  break;
1605 
1606  case T_gr_text:
1607  {
1608  TEXTE_PCB* text = parseTEXTE_PCB();
1609  dimension->Text() = *text;
1610  dimension->SetPosition( text->GetTextPos() );
1611  delete text;
1612  break;
1613  }
1614 
1615  case T_feature1:
1616  NeedLEFT();
1617  token = NextTok();
1618 
1619  if( token != T_pts )
1620  Expecting( T_pts );
1621 
1622  parseXY( &dimension->m_featureLineDO.x, &dimension->m_featureLineDO.y );
1623  parseXY( &dimension->m_featureLineDF.x, &dimension->m_featureLineDF.y );
1624  dimension->UpdateHeight();
1625  NeedRIGHT();
1626  NeedRIGHT();
1627  break;
1628 
1629  case T_feature2:
1630  NeedLEFT();
1631  token = NextTok();
1632 
1633  if( token != T_pts )
1634  Expecting( T_pts );
1635 
1636  parseXY( &dimension->m_featureLineGO.x, &dimension->m_featureLineGO.y );
1637  parseXY( &dimension->m_featureLineGF.x, &dimension->m_featureLineGF.y );
1638  dimension->UpdateHeight();
1639  NeedRIGHT();
1640  NeedRIGHT();
1641  break;
1642 
1643 
1644  case T_crossbar:
1645  NeedLEFT();
1646  token = NextTok();
1647 
1648  if( token != T_pts )
1649  Expecting( T_pts );
1650 
1651  parseXY( &dimension->m_crossBarO.x, &dimension->m_crossBarO.y );
1652  parseXY( &dimension->m_crossBarF.x, &dimension->m_crossBarF.y );
1653  dimension->UpdateHeight();
1654  NeedRIGHT();
1655  NeedRIGHT();
1656  break;
1657 
1658  case T_arrow1a:
1659  NeedLEFT();
1660  token = NextTok();
1661 
1662  if( token != T_pts )
1663  Expecting( T_pts );
1664 
1665  parseXY( &dimension->m_crossBarF.x, &dimension->m_crossBarF.y );
1666  parseXY( &dimension->m_arrowD1F.x, &dimension->m_arrowD1F.y );
1667  NeedRIGHT();
1668  NeedRIGHT();
1669  break;
1670 
1671  case T_arrow1b:
1672  NeedLEFT();
1673  token = NextTok();
1674 
1675  if( token != T_pts )
1676  Expecting( T_pts );
1677 
1678  parseXY( &dimension->m_crossBarF.x, &dimension->m_crossBarF.y );
1679  parseXY( &dimension->m_arrowD2F.x, &dimension->m_arrowD2F.y );
1680  NeedRIGHT();
1681  NeedRIGHT();
1682  break;
1683 
1684  case T_arrow2a:
1685  NeedLEFT();
1686  token = NextTok();
1687 
1688  if( token != T_pts )
1689  Expecting( T_pts );
1690 
1691  parseXY( &dimension->m_crossBarO.x, &dimension->m_crossBarO.y );
1692  parseXY( &dimension->m_arrowG1F.x, &dimension->m_arrowG1F.y );
1693  NeedRIGHT();
1694  NeedRIGHT();
1695  break;
1696 
1697  case T_arrow2b:
1698  NeedLEFT();
1699  token = NextTok();
1700 
1701  if( token != T_pts )
1702  Expecting( T_pts );
1703 
1704  parseXY( &dimension->m_crossBarO.x, &dimension->m_crossBarO.y );
1705  parseXY( &dimension->m_arrowG2F.x, &dimension->m_arrowG2F.y );
1706  NeedRIGHT();
1707  NeedRIGHT();
1708  break;
1709 
1710  default:
1711  Expecting( "layer, tstamp, gr_text, feature1, feature2 crossbar, arrow1a, "
1712  "arrow1b, arrow2a, or arrow2b" );
1713  }
1714  }
1715 
1716  return dimension.release();
1717 }
1718 
1719 
1720 MODULE* PCB_PARSER::parseMODULE( wxArrayString* aInitialComments )
1721 {
1722  try
1723  {
1724  return parseMODULE_unchecked( aInitialComments );
1725  }
1726  catch( const PARSE_ERROR& parse_error )
1727  {
1728  if( m_tooRecent )
1729  throw FUTURE_FORMAT_ERROR( parse_error, GetRequiredVersion() );
1730  else
1731  throw;
1732  }
1733 }
1734 
1735 
1736 MODULE* PCB_PARSER::parseMODULE_unchecked( wxArrayString* aInitialComments )
1737 {
1738  wxCHECK_MSG( CurTok() == T_module, NULL,
1739  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as MODULE." ) );
1740 
1741  wxString name;
1742  wxPoint pt;
1743  T token;
1744  LIB_ID fpid;
1745 
1746  std::unique_ptr<MODULE> module( new MODULE( m_board ) );
1747 
1748  module->SetInitialComments( aInitialComments );
1749 
1750  token = NextTok();
1751 
1752  if( !IsSymbol( token ) && token != T_NUMBER )
1753  Expecting( "symbol|number" );
1754 
1755  name = FromUTF8();
1756 
1757  if( !name.IsEmpty() && fpid.Parse( TO_UTF8( FromUTF8() ) ) >= 0 )
1758  {
1759  wxString error;
1760  error.Printf( _( "invalid footprint ID in\nfile: <%s>\nline: %d\noffset: %d" ),
1761  GetChars( CurSource() ), CurLineNumber(), CurOffset() );
1762  THROW_IO_ERROR( error );
1763  }
1764 
1765  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1766  {
1767  if( token == T_LEFT )
1768  token = NextTok();
1769 
1770  switch( token )
1771  {
1772  case T_version:
1773  {
1774  // Theoretically a module nested in a PCB could declare its own version, though
1775  // as of writing this comment we don't do that. Just in case, take the greater
1776  // version.
1777  int this_version = parseInt( FromUTF8().mb_str( wxConvUTF8 ) );
1778  NeedRIGHT();
1779  m_requiredVersion = std::max( m_requiredVersion, this_version );
1780  m_tooRecent = ( m_requiredVersion > SEXPR_BOARD_FILE_VERSION );
1781  break;
1782  }
1783 
1784  case T_locked:
1785  module->SetLocked( true );
1786  break;
1787 
1788  case T_placed:
1789  module->SetIsPlaced( true );
1790  break;
1791 
1792  case T_layer:
1793  {
1794  // Footprints can be only on the front side or the back side.
1795  // but because we can find some stupid layer in file, ensure a
1796  // acceptable layer is set for the footprint
1797  PCB_LAYER_ID layer = parseBoardItemLayer();
1798  module->SetLayer( layer == B_Cu ? B_Cu : F_Cu );
1799  }
1800  NeedRIGHT();
1801  break;
1802 
1803  case T_tedit:
1804  module->SetLastEditTime( parseHex() );
1805  NeedRIGHT();
1806  break;
1807 
1808  case T_tstamp:
1809  module->SetTimeStamp( parseHex() );
1810  NeedRIGHT();
1811  break;
1812 
1813  case T_at:
1814  pt.x = parseBoardUnits( "X coordinate" );
1815  pt.y = parseBoardUnits( "Y coordinate" );
1816  module->SetPosition( pt );
1817  token = NextTok();
1818 
1819  if( token == T_NUMBER )
1820  {
1821  module->SetOrientation( parseDouble() * 10.0 );
1822  NeedRIGHT();
1823  }
1824  else if( token != T_RIGHT )
1825  {
1826  Expecting( T_RIGHT );
1827  }
1828 
1829  break;
1830 
1831  case T_descr:
1832  NeedSYMBOLorNUMBER(); // some symbols can be 0508, so a number is also a symbol here
1833  module->SetDescription( FromUTF8() );
1834  NeedRIGHT();
1835  break;
1836 
1837  case T_tags:
1838  NeedSYMBOLorNUMBER(); // some symbols can be 0508, so a number is also a symbol here
1839  module->SetKeywords( FromUTF8() );
1840  NeedRIGHT();
1841  break;
1842 
1843  case T_path:
1844  NeedSYMBOLorNUMBER(); // Paths can be numerical so a number is also a symbol here
1845  module->SetPath( FromUTF8() );
1846  NeedRIGHT();
1847  break;
1848 
1849  case T_autoplace_cost90:
1850  module->SetPlacementCost90( parseInt( "auto place cost at 90 degrees" ) );
1851  NeedRIGHT();
1852  break;
1853 
1854  case T_autoplace_cost180:
1855  module->SetPlacementCost180( parseInt( "auto place cost at 180 degrees" ) );
1856  NeedRIGHT();
1857  break;
1858 
1859  case T_solder_mask_margin:
1860  module->SetLocalSolderMaskMargin( parseBoardUnits( "local solder mask margin value" ) );
1861  NeedRIGHT();
1862  break;
1863 
1864  case T_solder_paste_margin:
1865  module->SetLocalSolderPasteMargin(
1866  parseBoardUnits( "local solder paste margin value" ) );
1867  NeedRIGHT();
1868  break;
1869 
1870  case T_solder_paste_ratio:
1871  module->SetLocalSolderPasteMarginRatio(
1872  parseDouble( "local solder paste margin ratio value" ) );
1873  NeedRIGHT();
1874  break;
1875 
1876  case T_clearance:
1877  module->SetLocalClearance( parseBoardUnits( "local clearance value" ) );
1878  NeedRIGHT();
1879  break;
1880 
1881  case T_zone_connect:
1882  module->SetZoneConnection( (ZoneConnection) parseInt( "zone connection value" ) );
1883  NeedRIGHT();
1884  break;
1885 
1886  case T_thermal_width:
1887  module->SetThermalWidth( parseBoardUnits( "thermal width value" ) );
1888  NeedRIGHT();
1889  break;
1890 
1891  case T_thermal_gap:
1892  module->SetThermalGap( parseBoardUnits( "thermal gap value" ) );
1893  NeedRIGHT();
1894  break;
1895 
1896  case T_attr:
1897  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1898  {
1899  switch( token )
1900  {
1901  case T_smd:
1902  module->SetAttributes( module->GetAttributes() | MOD_CMS );
1903  break;
1904 
1905  case T_virtual:
1906  module->SetAttributes( module->GetAttributes() | MOD_VIRTUAL );
1907  break;
1908 
1909  default:
1910  Expecting( "smd and/or virtual" );
1911  }
1912  }
1913 
1914  break;
1915 
1916  case T_fp_text:
1917  {
1918  TEXTE_MODULE* text = parseTEXTE_MODULE();
1919  text->SetParent( module.get() );
1920  double orientation = text->GetTextAngle();
1921  orientation -= module->GetOrientation();
1922  text->SetTextAngle( orientation );
1923  text->SetDrawCoord();
1924 
1925  switch( text->GetType() )
1926  {
1928  module->Reference() = *text;
1929  delete text;
1930  break;
1931 
1933  module->Value() = *text;
1934  delete text;
1935  break;
1936 
1937  default:
1938  module->GraphicalItemsList().PushBack( text );
1939  }
1940  }
1941  break;
1942 
1943  case T_fp_arc:
1944  case T_fp_circle:
1945  case T_fp_curve:
1946  case T_fp_line:
1947  case T_fp_poly:
1948  {
1949  EDGE_MODULE* em = parseEDGE_MODULE();
1950  em->SetParent( module.get() );
1951  em->SetDrawCoord();
1952  module->GraphicalItemsList().PushBack( em );
1953  }
1954  break;
1955 
1956  case T_pad:
1957  {
1958  D_PAD* pad = parseD_PAD( module.get() );
1959  pt = pad->GetPos0();
1960 
1961  RotatePoint( &pt, module->GetOrientation() );
1962  pad->SetPosition( pt + module->GetPosition() );
1963  module->Add( pad, ADD_APPEND );
1964  }
1965  break;
1966 
1967  case T_model:
1968  module->Add3DModel( parse3DModel() );
1969  break;
1970 
1971  default:
1972  Expecting( "locked, placed, tedit, tstamp, at, descr, tags, path, "
1973  "autoplace_cost90, autoplace_cost180, solder_mask_margin, "
1974  "solder_paste_margin, solder_paste_ratio, clearance, "
1975  "zone_connect, thermal_width, thermal_gap, attr, fp_text, "
1976  "fp_arc, fp_circle, fp_curve, fp_line, fp_poly, pad, or model" );
1977  }
1978  }
1979 
1980  module->SetFPID( fpid );
1981  module->CalculateBoundingBox();
1982 
1983  return module.release();
1984 }
1985 
1986 
1988 {
1989  wxCHECK_MSG( CurTok() == T_fp_text, NULL,
1990  wxString::Format( wxT( "Cannot parse %s as TEXTE_MODULE at line %d, offset %d." ),
1991  GetChars( GetTokenString( CurTok() ) ),
1992  CurLineNumber(), CurOffset() ) );
1993 
1994  T token = NextTok();
1995 
1996  std::unique_ptr<TEXTE_MODULE> text( new TEXTE_MODULE( NULL ) );
1997 
1998  switch( token )
1999  {
2000  case T_reference:
2001  text->SetType( TEXTE_MODULE::TEXT_is_REFERENCE );
2002  break;
2003 
2004  case T_value:
2005  text->SetType( TEXTE_MODULE::TEXT_is_VALUE );
2006  break;
2007 
2008  case T_user:
2009  break; // Default type is user text.
2010 
2011  default:
2012  THROW_IO_ERROR( wxString::Format( _( "cannot handle footprint text type %s" ),
2013  GetChars( FromUTF8() ) ) );
2014  }
2015 
2016  NeedSYMBOLorNUMBER();
2017 
2018  text->SetText( FromUTF8() );
2019  NeedLEFT();
2020  token = NextTok();
2021 
2022  if( token != T_at )
2023  Expecting( T_at );
2024 
2025  wxPoint pt;
2026 
2027  pt.x = parseBoardUnits( "X coordinate" );
2028  pt.y = parseBoardUnits( "Y coordinate" );
2029  text->SetPos0( pt );
2030  token = NextTok();
2031 
2032  // If there is no orientation defined, then it is the default value of 0 degrees.
2033  if( token == T_NUMBER )
2034  {
2035  text->SetTextAngle( parseDouble() * 10.0 );
2036  NeedRIGHT();
2037  }
2038  else if( token != T_RIGHT )
2039  {
2040  Unexpected( CurText() );
2041  }
2042 
2043  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2044  {
2045  if( token == T_LEFT )
2046  token = NextTok();
2047 
2048  switch( token )
2049  {
2050  case T_layer:
2051  text->SetLayer( parseBoardItemLayer() );
2052  NeedRIGHT();
2053  break;
2054 
2055  case T_hide:
2056  text->SetVisible( false );
2057  break;
2058 
2059  case T_effects:
2060  parseEDA_TEXT( (EDA_TEXT*) text.get() );
2061  break;
2062 
2063  default:
2064  Expecting( "hide or effects" );
2065  }
2066  }
2067 
2068  return text.release();
2069 }
2070 
2071 
2073 {
2074  wxCHECK_MSG( CurTok() == T_fp_arc || CurTok() == T_fp_circle || CurTok() == T_fp_curve ||
2075  CurTok() == T_fp_line || CurTok() == T_fp_poly, NULL,
2076  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as EDGE_MODULE." ) );
2077 
2078  wxPoint pt;
2079  T token;
2080 
2081  std::unique_ptr< EDGE_MODULE > segment( new EDGE_MODULE( NULL ) );
2082 
2083  switch( CurTok() )
2084  {
2085  case T_fp_arc:
2086  segment->SetShape( S_ARC );
2087  NeedLEFT();
2088  token = NextTok();
2089 
2090  // the start keyword actually gives the arc center
2091  // Allows also T_center for future change
2092  if( token != T_start && token != T_center )
2093  Expecting( T_start );
2094 
2095  pt.x = parseBoardUnits( "X coordinate" );
2096  pt.y = parseBoardUnits( "Y coordinate" );
2097  segment->SetStart0( pt );
2098  NeedRIGHT();
2099  NeedLEFT();
2100  token = NextTok();
2101 
2102  if( token != T_end ) // end keyword actually gives the starting point of the arc
2103  Expecting( T_end );
2104 
2105  pt.x = parseBoardUnits( "X coordinate" );
2106  pt.y = parseBoardUnits( "Y coordinate" );
2107  segment->SetEnd0( pt );
2108  NeedRIGHT();
2109  NeedLEFT();
2110  token = NextTok();
2111 
2112  if( token != T_angle )
2113  Expecting( T_angle );
2114 
2115  segment->SetAngle( parseDouble( "segment angle" ) * 10.0 );
2116  NeedRIGHT();
2117  break;
2118 
2119  case T_fp_circle:
2120  segment->SetShape( S_CIRCLE );
2121  NeedLEFT();
2122  token = NextTok();
2123 
2124  if( token != T_center )
2125  Expecting( T_center );
2126 
2127  pt.x = parseBoardUnits( "X coordinate" );
2128  pt.y = parseBoardUnits( "Y coordinate" );
2129  segment->SetStart0( pt );
2130  NeedRIGHT();
2131  NeedLEFT();
2132  token = NextTok();
2133 
2134  if( token != T_end )
2135  Expecting( T_end );
2136 
2137  pt.x = parseBoardUnits( "X coordinate" );
2138  pt.y = parseBoardUnits( "Y coordinate" );
2139  segment->SetEnd0( pt );
2140  NeedRIGHT();
2141  break;
2142 
2143  case T_fp_curve:
2144  segment->SetShape( S_CURVE );
2145  NeedLEFT();
2146  token = NextTok();
2147 
2148  if( token != T_pts )
2149  Expecting( T_pts );
2150 
2151  segment->SetStart0( parseXY() );
2152  segment->SetBezControl1( parseXY() );
2153  segment->SetBezControl2( parseXY() );
2154  segment->SetEnd0( parseXY() );
2155  NeedRIGHT();
2156  break;
2157 
2158  case T_fp_line:
2159  // Default DRAWSEGMENT type is S_SEGMENT.
2160  NeedLEFT();
2161  token = NextTok();
2162 
2163  if( token != T_start )
2164  Expecting( T_start );
2165 
2166  pt.x = parseBoardUnits( "X coordinate" );
2167  pt.y = parseBoardUnits( "Y coordinate" );
2168  segment->SetStart0( pt );
2169 
2170  NeedRIGHT();
2171  NeedLEFT();
2172  token = NextTok();
2173 
2174  if( token != T_end )
2175  Expecting( T_end );
2176 
2177  pt.x = parseBoardUnits( "X coordinate" );
2178  pt.y = parseBoardUnits( "Y coordinate" );
2179  segment->SetEnd0( pt );
2180  NeedRIGHT();
2181  break;
2182 
2183  case T_fp_poly:
2184  {
2185  segment->SetShape( S_POLYGON );
2186  NeedLEFT();
2187  token = NextTok();
2188 
2189  if( token != T_pts )
2190  Expecting( T_pts );
2191 
2192  std::vector< wxPoint > pts;
2193 
2194  while( (token = NextTok()) != T_RIGHT )
2195  pts.push_back( parseXY() );
2196 
2197  segment->SetPolyPoints( pts );
2198  }
2199  break;
2200 
2201  default:
2202  Expecting( "fp_arc, fp_circle, fp_curve, fp_line, or fp_poly" );
2203  }
2204 
2205  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2206  {
2207  if( token != T_LEFT )
2208  Expecting( T_LEFT );
2209 
2210  token = NextTok();
2211 
2212  switch( token )
2213  {
2214  case T_layer:
2215  segment->SetLayer( parseBoardItemLayer() );
2216  break;
2217 
2218  case T_width:
2219  segment->SetWidth( parseBoardUnits( T_width ) );
2220  break;
2221 
2222  case T_tstamp:
2223  segment->SetTimeStamp( parseHex() );
2224  break;
2225 
2226  case T_status:
2227  segment->SetStatus( static_cast<STATUS_FLAGS>( parseHex() ) );
2228  break;
2229 
2230  default:
2231  Expecting( "layer or width" );
2232  }
2233 
2234  NeedRIGHT();
2235  }
2236 
2237  return segment.release();
2238 }
2239 
2240 
2242 {
2243  wxCHECK_MSG( CurTok() == T_pad, NULL,
2244  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as D_PAD." ) );
2245 
2246  wxSize sz;
2247  wxPoint pt;
2248 
2249  std::unique_ptr< D_PAD > pad( new D_PAD( aParent ) );
2250 
2251  NeedSYMBOLorNUMBER();
2252  pad->SetPadName( FromUTF8() );
2253 
2254  T token = NextTok();
2255 
2256  switch( token )
2257  {
2258  case T_thru_hole:
2259  pad->SetAttribute( PAD_ATTRIB_STANDARD );
2260  break;
2261 
2262  case T_smd:
2263  pad->SetAttribute( PAD_ATTRIB_SMD );
2264 
2265  // Default D_PAD object is thru hole with drill.
2266  // SMD pads have no hole
2267  pad->SetDrillSize( wxSize( 0, 0 ) );
2268  break;
2269 
2270  case T_connect:
2271  pad->SetAttribute( PAD_ATTRIB_CONN );
2272 
2273  // Default D_PAD object is thru hole with drill.
2274  // CONN pads have no hole
2275  pad->SetDrillSize( wxSize( 0, 0 ) );
2276  break;
2277 
2278  case T_np_thru_hole:
2279  pad->SetAttribute( PAD_ATTRIB_HOLE_NOT_PLATED );
2280  break;
2281 
2282  default:
2283  Expecting( "thru_hole, smd, connect, or np_thru_hole" );
2284  }
2285 
2286  token = NextTok();
2287 
2288  switch( token )
2289  {
2290  case T_circle:
2291  pad->SetShape( PAD_SHAPE_CIRCLE );
2292  break;
2293 
2294  case T_rect:
2295  pad->SetShape( PAD_SHAPE_RECT );
2296  break;
2297 
2298  case T_oval:
2299  pad->SetShape( PAD_SHAPE_OVAL );
2300  break;
2301 
2302  case T_trapezoid:
2303  pad->SetShape( PAD_SHAPE_TRAPEZOID );
2304  break;
2305 
2306  case T_roundrect:
2307  pad->SetShape( PAD_SHAPE_ROUNDRECT );
2308  break;
2309 
2310  default:
2311  Expecting( "circle, rectangle, roundrect, oval, trapezoid or custom" );
2312  }
2313 
2314  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2315  {
2316  if( token != T_LEFT )
2317  Expecting( T_LEFT );
2318 
2319  token = NextTok();
2320 
2321  switch( token )
2322  {
2323  case T_size:
2324  sz.SetWidth( parseBoardUnits( "width value" ) );
2325  sz.SetHeight( parseBoardUnits( "height value" ) );
2326  pad->SetSize( sz );
2327  NeedRIGHT();
2328  break;
2329 
2330  case T_at:
2331  pt.x = parseBoardUnits( "X coordinate" );
2332  pt.y = parseBoardUnits( "Y coordinate" );
2333  pad->SetPos0( pt );
2334  token = NextTok();
2335 
2336  if( token == T_NUMBER )
2337  {
2338  pad->SetOrientation( parseDouble() * 10.0 );
2339  NeedRIGHT();
2340  }
2341  else if( token != T_RIGHT )
2342  {
2343  Expecting( ") or angle value" );
2344  }
2345 
2346  break;
2347 
2348  case T_rect_delta:
2349  {
2350  wxSize delta;
2351  delta.SetWidth( parseBoardUnits( "rectangle delta width" ) );
2352  delta.SetHeight( parseBoardUnits( "rectangle delta height" ) );
2353  pad->SetDelta( delta );
2354  NeedRIGHT();
2355  }
2356  break;
2357 
2358  case T_drill:
2359  {
2360  bool haveWidth = false;
2361  wxSize drillSize = pad->GetDrillSize();
2362 
2363  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2364  {
2365  if( token == T_LEFT )
2366  token = NextTok();
2367 
2368  switch( token )
2369  {
2370  case T_oval:
2371  pad->SetDrillShape( PAD_DRILL_SHAPE_OBLONG );
2372  break;
2373 
2374  case T_NUMBER:
2375  {
2376  if( !haveWidth )
2377  {
2378  drillSize.SetWidth( parseBoardUnits() );
2379 
2380  // If height is not defined the width and height are the same.
2381  drillSize.SetHeight( drillSize.GetWidth() );
2382  haveWidth = true;
2383  }
2384  else
2385  {
2386  drillSize.SetHeight( parseBoardUnits() );
2387  }
2388 
2389  }
2390  break;
2391 
2392  case T_offset:
2393  pt.x = parseBoardUnits( "drill offset x" );
2394  pt.y = parseBoardUnits( "drill offset y" );
2395  pad->SetOffset( pt );
2396  NeedRIGHT();
2397  break;
2398 
2399  default:
2400  Expecting( "oval, size, or offset" );
2401  }
2402  }
2403 
2404  // This fixes a bug caused by setting the default D_PAD drill size to a value
2405  // other than 0 used to fix a bunch of debug assertions even though it is defined
2406  // as a through hole pad. Wouldn't a though hole pad with no drill be a surface
2407  // mount pad (or a conn pad which is a smd pad with no solder paste)?
2408  if( ( pad->GetAttribute() != PAD_ATTRIB_SMD ) && ( pad->GetAttribute() != PAD_ATTRIB_CONN ) )
2409  pad->SetDrillSize( drillSize );
2410  else
2411  pad->SetDrillSize( wxSize( 0, 0 ) );
2412 
2413  }
2414  break;
2415 
2416  case T_layers:
2417  {
2418  LSET layerMask = parseBoardItemLayersAsMask();
2419  pad->SetLayerSet( layerMask );
2420  }
2421  break;
2422 
2423  case T_net:
2424  if( ! pad->SetNetCode( getNetCode( parseInt( "net number" ) ), /* aNoAssert */ true ) )
2426  wxString::Format( _( "invalid net ID in\nfile: <%s>\nline: %d\noffset: %d" ),
2427  GetChars( CurSource() ), CurLineNumber(), CurOffset() )
2428  );
2429  NeedSYMBOLorNUMBER();
2430  if( m_board && FromUTF8() != m_board->FindNet( pad->GetNetCode() )->GetNetname() )
2432  wxString::Format( _( "invalid net ID in\nfile: <%s>\nline: %d\noffset: %d" ),
2433  GetChars( CurSource() ), CurLineNumber(), CurOffset() )
2434  );
2435  NeedRIGHT();
2436  break;
2437 
2438  case T_die_length:
2439  pad->SetPadToDieLength( parseBoardUnits( T_die_length ) );
2440  NeedRIGHT();
2441  break;
2442 
2443  case T_solder_mask_margin:
2444  pad->SetLocalSolderMaskMargin( parseBoardUnits( T_solder_mask_margin ) );
2445  NeedRIGHT();
2446  break;
2447 
2448  case T_solder_paste_margin:
2449  pad->SetLocalSolderPasteMargin( parseBoardUnits( T_solder_paste_margin ) );
2450  NeedRIGHT();
2451  break;
2452 
2454  pad->SetLocalSolderPasteMarginRatio(
2455  parseDouble( "pad local solder paste margin ratio value" ) );
2456  NeedRIGHT();
2457  break;
2458 
2459  case T_clearance:
2460  pad->SetLocalClearance( parseBoardUnits( "local clearance value" ) );
2461  NeedRIGHT();
2462  break;
2463 
2464  case T_zone_connect:
2465  pad->SetZoneConnection( (ZoneConnection) parseInt( "zone connection value" ) );
2466  NeedRIGHT();
2467  break;
2468 
2469  case T_thermal_width:
2470  pad->SetThermalWidth( parseBoardUnits( T_thermal_width ) );
2471  NeedRIGHT();
2472  break;
2473 
2474  case T_thermal_gap:
2475  pad->SetThermalGap( parseBoardUnits( T_thermal_gap ) );
2476  NeedRIGHT();
2477  break;
2478 
2479  case T_roundrect_rratio:
2480  pad->SetRoundRectRadiusRatio( parseDouble( "roundrect radius ratio" ) );
2481  NeedRIGHT();
2482  break;
2483 
2484  default:
2485  Expecting( "at, drill, layers, net, die_length, solder_mask_margin, roundrect_rratio,"
2486  "solder_paste_margin, solder_paste_margin_ratio, clearance, "
2487  "zone_connect, fp_poly, basic_shapes, thermal_width, or thermal_gap" );
2488  }
2489  }
2490 
2491  return pad.release();
2492 }
2493 
2494 
2496 {
2497  wxCHECK_MSG( CurTok() == T_segment, NULL,
2498  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as TRACK." ) );
2499 
2500  wxPoint pt;
2501  T token;
2502 
2503  std::unique_ptr< TRACK > track( new TRACK( m_board ) );
2504 
2505  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2506  {
2507  if( token != T_LEFT )
2508  Expecting( T_LEFT );
2509 
2510  token = NextTok();
2511 
2512  switch( token )
2513  {
2514  case T_start:
2515  pt.x = parseBoardUnits( "start x" );
2516  pt.y = parseBoardUnits( "start y" );
2517  track->SetStart( pt );
2518  break;
2519 
2520  case T_end:
2521  pt.x = parseBoardUnits( "end x" );
2522  pt.y = parseBoardUnits( "end y" );
2523  track->SetEnd( pt );
2524  break;
2525 
2526  case T_width:
2527  track->SetWidth( parseBoardUnits( "width" ) );
2528  break;
2529 
2530  case T_layer:
2531  track->SetLayer( parseBoardItemLayer() );
2532  break;
2533 
2534  case T_net:
2535  if( ! track->SetNetCode( getNetCode( parseInt( "net number" ) ), /* aNoAssert */ true ) )
2537  wxString::Format( _( "invalid net ID in\nfile: <%s>\nline: %d\noffset: %d" ),
2538  GetChars( CurSource() ), CurLineNumber(), CurOffset() )
2539  );
2540  break;
2541 
2542  case T_tstamp:
2543  track->SetTimeStamp( parseHex() );
2544  break;
2545 
2546  case T_status:
2547  track->SetStatus( static_cast<STATUS_FLAGS>( parseHex() ) );
2548  break;
2549 
2550  default:
2551  Expecting( "start, end, width, layer, net, tstamp, or status" );
2552  }
2553 
2554  NeedRIGHT();
2555  }
2556 
2557  return track.release();
2558 }
2559 
2560 
2562 {
2563  wxCHECK_MSG( CurTok() == T_via, NULL,
2564  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as VIA." ) );
2565 
2566  wxPoint pt;
2567  T token;
2568 
2569  std::unique_ptr< VIA > via( new VIA( m_board ) );
2570 
2571  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2572  {
2573  if( token == T_LEFT )
2574  token = NextTok();
2575 
2576  switch( token )
2577  {
2578  case T_blind:
2579  via->SetViaType( VIA_BLIND_BURIED );
2580  break;
2581 
2582  case T_micro:
2583  via->SetViaType( VIA_MICROVIA );
2584  break;
2585 
2586  case T_at:
2587  pt.x = parseBoardUnits( "start x" );
2588  pt.y = parseBoardUnits( "start y" );
2589  via->SetStart( pt );
2590  via->SetEnd( pt );
2591  NeedRIGHT();
2592  break;
2593 
2594  case T_size:
2595  via->SetWidth( parseBoardUnits( "via width" ) );
2596  NeedRIGHT();
2597  break;
2598 
2599  case T_drill:
2600  via->SetDrill( parseBoardUnits( "drill diameter" ) );
2601  NeedRIGHT();
2602  break;
2603 
2604  case T_layers:
2605  {
2606  PCB_LAYER_ID layer1, layer2;
2607  NextTok();
2608  layer1 = lookUpLayer<PCB_LAYER_ID>( m_layerIndices );
2609  NextTok();
2610  layer2 = lookUpLayer<PCB_LAYER_ID>( m_layerIndices );
2611  via->SetLayerPair( layer1, layer2 );
2612  NeedRIGHT();
2613  }
2614  break;
2615 
2616  case T_net:
2617  if(! via->SetNetCode( getNetCode( parseInt( "net number" ) ), /* aNoAssert */ true))
2619  wxString::Format( _( "invalid net ID in\nfile: <%s>\nline: %d\noffset: %d" ),
2620  GetChars( CurSource() ), CurLineNumber(), CurOffset() )
2621  );
2622  NeedRIGHT();
2623  break;
2624 
2625  case T_tstamp:
2626  via->SetTimeStamp( parseHex() );
2627  NeedRIGHT();
2628  break;
2629 
2630  case T_status:
2631  via->SetStatus( static_cast<STATUS_FLAGS>( parseHex() ) );
2632  NeedRIGHT();
2633  break;
2634 
2635  default:
2636  Expecting( "blind, micro, at, size, drill, layers, net, tstamp, or status" );
2637  }
2638  }
2639 
2640  return via.release();
2641 }
2642 
2643 
2645 {
2646  wxCHECK_MSG( CurTok() == T_zone, NULL,
2647  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) +
2648  wxT( " as ZONE_CONTAINER." ) );
2649 
2651 
2652  int hatchPitch = ZONE_CONTAINER::GetDefaultHatchPitch();
2653  wxPoint pt;
2654  T token;
2655  int tmp;
2656  wxString netnameFromfile; // the zone net name find in file
2657 
2658  // bigger scope since each filled_polygon is concatenated in here
2659  SHAPE_POLY_SET pts;
2660 
2661  std::unique_ptr< ZONE_CONTAINER > zone( new ZONE_CONTAINER( m_board ) );
2662 
2663  zone->SetPriority( 0 );
2664 
2665  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2666  {
2667  if( token == T_LEFT )
2668  token = NextTok();
2669 
2670  switch( token )
2671  {
2672  case T_net:
2673  // Init the net code only, not the netname, to be sure
2674  // the zone net name is the name read in file.
2675  // (When mismatch, the user will be prompted in DRC, to fix the actual name)
2676  tmp = getNetCode( parseInt( "net number" ) );
2677 
2678  if( tmp < 0 )
2679  tmp = 0;
2680 
2681  if( ! zone->SetNetCode( tmp, /* aNoAssert */ true ) )
2683  wxString::Format( _( "invalid net ID in\nfile: <%s>\nline: %d\noffset: %d" ),
2684  GetChars( CurSource() ), CurLineNumber(), CurOffset() )
2685  );
2686 
2687  NeedRIGHT();
2688  break;
2689 
2690  case T_net_name:
2691  NeedSYMBOLorNUMBER();
2692  netnameFromfile = FromUTF8();
2693  NeedRIGHT();
2694  break;
2695 
2696  case T_layer:
2697  zone->SetLayer( parseBoardItemLayer() );
2698  NeedRIGHT();
2699  break;
2700 
2701  case T_tstamp:
2702  zone->SetTimeStamp( parseHex() );
2703  NeedRIGHT();
2704  break;
2705 
2706  case T_hatch:
2707  token = NextTok();
2708 
2709  if( token != T_none && token != T_edge && token != T_full )
2710  Expecting( "none, edge, or full" );
2711 
2712  switch( token )
2713  {
2714  default:
2715  case T_none: hatchStyle = ZONE_CONTAINER::NO_HATCH; break;
2716  case T_edge: hatchStyle = ZONE_CONTAINER::DIAGONAL_EDGE; break;
2717  case T_full: hatchStyle = ZONE_CONTAINER::DIAGONAL_FULL;
2718  }
2719 
2720  hatchPitch = parseBoardUnits( "hatch pitch" );
2721  NeedRIGHT();
2722  break;
2723 
2724  case T_priority:
2725  zone->SetPriority( parseInt( "zone priority" ) );
2726  NeedRIGHT();
2727  break;
2728 
2729  case T_connect_pads:
2730  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2731  {
2732  if( token == T_LEFT )
2733  token = NextTok();
2734 
2735  switch( token )
2736  {
2737  case T_yes:
2738  zone->SetPadConnection( PAD_ZONE_CONN_FULL );
2739  break;
2740 
2741  case T_no:
2742  zone->SetPadConnection( PAD_ZONE_CONN_NONE );
2743  break;
2744 
2745  case T_thru_hole_only:
2746  zone->SetPadConnection( PAD_ZONE_CONN_THT_THERMAL );
2747  break;
2748 
2749  case T_clearance:
2750  zone->SetZoneClearance( parseBoardUnits( "zone clearance" ) );
2751  NeedRIGHT();
2752  break;
2753 
2754  default:
2755  Expecting( "yes, no, or clearance" );
2756  }
2757  }
2758 
2759  break;
2760 
2761  case T_min_thickness:
2762  zone->SetMinThickness( parseBoardUnits( T_min_thickness ) );
2763  NeedRIGHT();
2764  break;
2765 
2766  case T_fill:
2767  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2768  {
2769  if( token == T_LEFT )
2770  token = NextTok();
2771 
2772  switch( token )
2773  {
2774  case T_yes:
2775  zone->SetIsFilled( true );
2776  break;
2777 
2778  case T_mode:
2779  token = NextTok();
2780 
2781  if( token != T_segment && token != T_polygon )
2782  Expecting( "segment or polygon" );
2783 
2784  // @todo Create an enum for fill modes.
2785  zone->SetFillMode( token == T_polygon ? 0 : 1 );
2786  NeedRIGHT();
2787  break;
2788 
2789  case T_arc_segments:
2790  zone->SetArcSegmentCount( parseInt( "arc segment count" ) );
2791  NeedRIGHT();
2792  break;
2793 
2794  case T_thermal_gap:
2795  zone->SetThermalReliefGap( parseBoardUnits( T_thermal_gap ) );
2796  NeedRIGHT();
2797  break;
2798 
2800  zone->SetThermalReliefCopperBridge( parseBoardUnits( T_thermal_bridge_width ) );
2801  NeedRIGHT();
2802  break;
2803 
2804  case T_smoothing:
2805  switch( NextTok() )
2806  {
2807  case T_none:
2808  zone->SetCornerSmoothingType( ZONE_SETTINGS::SMOOTHING_NONE );
2809  break;
2810 
2811  case T_chamfer:
2812  if( !zone->GetIsKeepout() ) // smoothing has meaning only for filled zones
2813  zone->SetCornerSmoothingType( ZONE_SETTINGS::SMOOTHING_CHAMFER );
2814  break;
2815 
2816  case T_fillet:
2817  if( !zone->GetIsKeepout() ) // smoothing has meaning only for filled zones
2818  zone->SetCornerSmoothingType( ZONE_SETTINGS::SMOOTHING_FILLET );
2819  break;
2820 
2821  default:
2822  Expecting( "none, chamfer, or fillet" );
2823  }
2824  NeedRIGHT();
2825  break;
2826 
2827  case T_radius:
2828  tmp = parseBoardUnits( "corner radius" );
2829  if( !zone->GetIsKeepout() ) // smoothing has meaning only for filled zones
2830  zone->SetCornerRadius( tmp );
2831  NeedRIGHT();
2832  break;
2833 
2834  default:
2835  Expecting( "mode, arc_segments, thermal_gap, thermal_bridge_width, "
2836  "smoothing, or radius" );
2837  }
2838  }
2839  break;
2840 
2841  case T_keepout:
2842  zone->SetIsKeepout( true );
2843 
2844  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2845  {
2846  if( token == T_LEFT )
2847  token = NextTok();
2848 
2849  switch( token )
2850  {
2851  case T_tracks:
2852  token = NextTok();
2853 
2854  if( token != T_allowed && token != T_not_allowed )
2855  Expecting( "allowed or not_allowed" );
2856  zone->SetDoNotAllowTracks( token == T_not_allowed );
2857  break;
2858 
2859  case T_vias:
2860  token = NextTok();
2861 
2862  if( token != T_allowed && token != T_not_allowed )
2863  Expecting( "allowed or not_allowed" );
2864  zone->SetDoNotAllowVias( token == T_not_allowed );
2865  break;
2866 
2867  case T_copperpour:
2868  token = NextTok();
2869 
2870  if( token != T_allowed && token != T_not_allowed )
2871  Expecting( "allowed or not_allowed" );
2872  zone->SetDoNotAllowCopperPour( token == T_not_allowed );
2873  break;
2874 
2875  default:
2876  Expecting( "tracks, vias or copperpour" );
2877  }
2878 
2879  NeedRIGHT();
2880  }
2881 
2882  break;
2883 
2884  case T_polygon:
2885  {
2886  std::vector< wxPoint > corners;
2887 
2888  NeedLEFT();
2889  token = NextTok();
2890 
2891  if( token != T_pts )
2892  Expecting( T_pts );
2893 
2894  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2895  {
2896  corners.push_back( parseXY() );
2897  }
2898 
2899  NeedRIGHT();
2900 
2901  // Remark: The first polygon is the main outline.
2902  // Others are holes inside the main outline.
2903  zone->AddPolygon( corners );
2904  }
2905  break;
2906 
2907  case T_filled_polygon:
2908  {
2909  // "(filled_polygon (pts"
2910  NeedLEFT();
2911  token = NextTok();
2912 
2913  if( token != T_pts )
2914  Expecting( T_pts );
2915 
2916  pts.NewOutline();
2917 
2918  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2919  {
2920  pts.Append( parseXY() );
2921  }
2922 
2923  NeedRIGHT();
2924  }
2925  break;
2926 
2927  case T_fill_segments:
2928  {
2929  std::vector< SEGMENT > segs;
2930 
2931  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2932  {
2933  if( token != T_LEFT )
2934  Expecting( T_LEFT );
2935 
2936  token = NextTok();
2937 
2938  if( token != T_pts )
2939  Expecting( T_pts );
2940 
2941  SEGMENT segment( parseXY(), parseXY() );
2942  NeedRIGHT();
2943  segs.push_back( segment );
2944  }
2945 
2946  zone->AddFillSegments( segs );
2947  }
2948  break;
2949 
2950  default:
2951  Expecting( "net, layer, tstamp, hatch, priority, connect_pads, min_thickness, "
2952  "fill, polygon, filled_polygon, or fill_segments" );
2953  }
2954  }
2955 
2956  if( zone->GetNumCorners() > 2 )
2957  {
2958  if( !zone->IsOnCopperLayer() )
2959  {
2960  zone->SetFillMode( 0 );
2961  zone->SetNetCode( NETINFO_LIST::UNCONNECTED );
2962  }
2963 
2964  // Set hatch here, after outlines corners are read
2965  zone->SetHatch( hatchStyle, hatchPitch, true );
2966  }
2967 
2968  if( !pts.IsEmpty() )
2969  zone->AddFilledPolysList( pts );
2970 
2971  // Ensure keepout and non copper zones do not have a net
2972  // (which have no sense for these zones)
2973  // the netcode 0 is used for these zones
2974  bool zone_has_net = zone->IsOnCopperLayer() && !zone->GetIsKeepout();
2975 
2976  if( !zone_has_net )
2977  zone->SetNetCode( NETINFO_LIST::UNCONNECTED );
2978 
2979  // Ensure the zone net name is valid, and matches the net code, for copper zones
2980  if( zone_has_net && ( zone->GetNet()->GetNetname() != netnameFromfile ) )
2981  {
2982  // Can happens which old boards, with nonexistent nets ...
2983  // or after being edited by hand
2984  // We try to fix the mismatch.
2985  NETINFO_ITEM* net = m_board->FindNet( netnameFromfile );
2986 
2987  if( net ) // An existing net has the same net name. use it for the zone
2988  zone->SetNetCode( net->GetNet() );
2989  else // Not existing net: add a new net to keep trace of the zone netname
2990  {
2991  int newnetcode = m_board->GetNetCount();
2992  net = new NETINFO_ITEM( m_board, netnameFromfile, newnetcode );
2993  m_board->Add( net );
2994 
2995  // Store the new code mapping
2996  pushValueIntoMap( newnetcode, net->GetNet() );
2997  // and update the zone netcode
2998  zone->SetNetCode( net->GetNet() );
2999 
3000  // Prompt the user
3001  wxString msg;
3002  msg.Printf( _( "There is a zone that belongs to a not existing net\n"
3003  "\"%s\"\n"
3004  "you should verify and edit it (run DRC test)." ),
3005  GetChars( netnameFromfile ) );
3006  DisplayError( NULL, msg );
3007  }
3008  }
3009 
3010  return zone.release();
3011 }
3012 
3013 
3015 {
3016  wxCHECK_MSG( CurTok() == T_target, NULL,
3017  wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as PCB_TARGET." ) );
3018 
3019  wxPoint pt;
3020  T token;
3021 
3022  std::unique_ptr< PCB_TARGET > target( new PCB_TARGET( NULL ) );
3023 
3024  for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3025  {
3026  if( token == T_LEFT )
3027  token = NextTok();
3028 
3029  switch( token )
3030  {
3031  case T_x:
3032  target->SetShape( 1 );
3033  break;
3034 
3035  case T_plus:
3036  target->SetShape( 0 );
3037  break;
3038 
3039  case T_at:
3040  pt.x = parseBoardUnits( "target x position" );
3041  pt.y = parseBoardUnits( "target y position" );
3042  target->SetPosition( pt );
3043  NeedRIGHT();
3044  break;
3045 
3046  case T_size:
3047  target->SetSize( parseBoardUnits( "target size" ) );
3048  NeedRIGHT();
3049  break;
3050 
3051  case T_width:
3052  target->SetWidth( parseBoardUnits( "target thickness" ) );
3053  NeedRIGHT();
3054  break;
3055 
3056  case T_layer:
3057  target->SetLayer( parseBoardItemLayer() );
3058  NeedRIGHT();
3059  break;
3060 
3061  case T_tstamp:
3062  target->SetTimeStamp( parseHex() );
3063  NeedRIGHT();
3064  break;
3065 
3066  default:
3067  Expecting( "x, plus, at, size, width, layer or tstamp" );
3068  }
3069  }
3070 
3071  return target.release();
3072 }
void SetMirrored(bool isMirrored)
Definition: eda_text.h:178
void SetComment1(const wxString &aComment)
void parseHeader()
Definition: pcb_parser.cpp:550
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:639
int parseVersion()
Parse a format version tag like (version 20160417) return the version.
Definition: pcb_parser.cpp:169
Class UTF8 is an 8 bit std::string that is assuredly encoded in UTF8, and supplies special conversion...
Definition: utf8.h:53
int Mm2mils(double x)
Convert mm to mils.
Definition: base_units.h:41
int m_SolderMaskMargin
Solder mask margin.
Struct VIA_DIMENSION is a small helper container to handle a stock of specific vias each with unique ...
Class ZONE_CONTAINER handles a list of polygons defining a copper zone.
Definition: class_zone.h:78
LSET parseBoardItemLayersAsMask()
Function parseBoardItemLayersAsMask parses the layers definition of a BOARD_ITEM object.
Definition: pcb_parser.cpp:974
PCB_TARGET class definition.
double x
Definition: sg_base.h:70
wxPoint m_GridOrigin
origin for grid offsets
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:53
const wxPoint & GetTextPos() const
Definition: eda_text.h:224
wxString m_name
The name of the layer, there should be no spaces in this name.
Definition: class_board.h:111
like PAD_STANDARD, but not plated mechanical use only, no connection allowed
Definition: pad_shapes.h:63
int m_SolderPasteMargin
Solder paste margin absolute value.
Class LOCALE_IO is a class that can be instantiated within a scope in which you are expecting excepti...
Definition: common.h:166
This file is part of the common library.
Class PCB_PLOT_PARAMS_PARSER is the parser class for PCB_PLOT_PARAMS.
int m_ModuleTextWidth
Default footprint texts thickness.
Class BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class...
std::vector< int > m_TrackWidthList
Track width list.
S3D_INFO * parse3DModel()
Definition: pcb_parser.cpp:335
void SetRevision(const wxString &aRevision)
int m_ModuleSegmentWidth
Default width for all graphic lines.
TEXT_TYPE GetType() const
TRACK * parseTRACK()
VIA * parseVIA()
int m_PcbTextWidth
current Pcb (not module) Text width
Class BOARD to handle a board.
LAYER_T m_type
The type of the layer.
Definition: class_board.h:113
void SetItalic(bool isItalic)
Definition: eda_text.h:169
ZoneConnection
How pads are covered by copper in zone.
Definition: zones.h:55
polygon (not yet used for tracks, but could be in microwave apps)
Smd pad, appears on the solder paste layer (default)
Definition: pad_shapes.h:59
wxPoint parseXY()
Function parseXY parses a coordinate pair (xy X Y) in board units (mm).
Definition: pcb_parser.cpp:206
void SetVisible(bool aVisible)
Definition: eda_text.h:175
void parseNETINFO_ITEM()
Set for modules listed in the automatic insertion list (usually SMD footprints)
Definition: class_module.h:77
#define SEXPR_BOARD_FILE_VERSION
Current s-expression file format version. 2 was the last legacy format version.
BOARD * parseBOARD()
Definition: pcb_parser.cpp:444
void SetPosition(const wxPoint &aPos) override
Definition: class_pad.h:169
void SetDate(const wxString &aDate)
Function SetDate sets the date field, and defaults to the current time and date.
Classes to handle copper zones.
const wxPoint & GetPos0() const
Definition: class_pad.h:176
int Parse(const UTF8 &aId)
Function Parse.
Definition: lib_id.cpp:122
void parseEDA_TEXT(EDA_TEXT *aText)
Function parseEDA_TEXT parses the common settings for any object derived from EDA_TEXT.
Definition: pcb_parser.cpp:238
static const wxChar Custom[]
"User" defined page type
void SetDrillSize(const wxSize &aSize)
Definition: class_pad.h:187
void SetTextSize(const wxSize &aNewSize)
Definition: eda_text.h:214
DIMENSION * parseDIMENSION()
void parseTITLE_BLOCK()
Definition: pcb_parser.cpp:688
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:317
double y
Definition: sg_base.h:71
SGPOINT m_Offset
an offset (unit = inch) for the 3D shape
Definition: 3d_info.h:44
Class LIB_ID.
Definition: lib_id.h:56
wxSize m_ModuleTextSize
Default footprint texts size.
#define cu(a)
Definition: auxiliary.h:88
Class TITLE_BLOCK holds the information shown in the lower right corner of a plot, printout, or editing view.
static const int delta[8][2]
Definition: solve.cpp:112
static int GetDefaultHatchPitch()
Function GetDefaultHatchPitchMils.
void parseLayers()
Definition: pcb_parser.cpp:813
double GetTextAngle() const
Definition: eda_text.h:164
Functions relatives to tracks, vias and segments used to fill zones.
void SetComment4(const wxString &aComment)
This file contains miscellaneous commonly used macros and functions.
Pads are not covered.
Definition: zones.h:57
Class EDA_TEXT is a mix-in class (via multiple inheritance) that handles texts such as labels...
Definition: eda_text.h:114
void parsePAGE_INFO()
Definition: pcb_parser.cpp:632
int StrPrintf(std::string *result, const char *format,...)
Function StrPrintf is like sprintf() but the output is appended to a std::string instead of to a char...
Definition: richio.cpp:75
static double parseDouble(FILE_LINE_READER &aReader, const char *aLine, const char **aOutput=NULL)
Function parseDouble.
#define TO_UTF8(wxstring)
Macro TO_UTF8 converts a wxString to a UTF8 encoded C string for all wxWidgets build modes...
Definition: macros.h:47
bool parseBool()
Definition: pcb_parser.cpp:154
DIMENSION class definition.
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:182
Class LSET is a set of PCB_LAYER_IDs.
#define THROW_PARSE_ERROR(aProblem, aSource, aInputLine, aLineNumber, aByteIndex)
Definition: ki_exception.h:133
static const wxChar * Name(PCB_LAYER_ID aLayerId)
Function Name returns the fixed name association with aLayerId.
Definition: lset.cpp:73
#define MIN_VISIBILITY_MASK
void SetParent(EDA_ITEM *aParent)
Definition: base_struct.h:213
Class SHAPE_POLY_SET.
wxSize m_PcbTextSize
current Pcb (not module) Text size
C++ does not put enum values in separate namespaces unless the enum itself is in a separate namespace...
Definition: pcb_lexer.h:23
Class PAGE_INFO describes the page size and margins of a paper page on which to eventually print or p...
int m_TrackMinWidth
track min value for width ((min copper size value
void SetVertJustify(EDA_TEXT_VJUSTIFY_T aType)
Definition: eda_text.h:194
Arcs (with rounded ends)
int m_ViasMinSize
vias (not micro vias) min diameter
void SetNetCode(int aNetCode)
MODULE * parseMODULE_unchecked(wxArrayString *aInitialComments=0)
Function parseMODULE_unchecked Parse a module, but do not replace PARSE_ERROR with FUTURE_FORMAT_ERRO...
DRAWSEGMENT * parseDRAWSEGMENT()
int m_DrawSegmentWidth
current graphic line width (not EDGE layer)
PCB_TARGET * parsePCB_TARGET()
int m_ViasMinDrill
vias (not micro vias) min drill diameter
PCB_LAYER_ID parseBoardItemLayer()
Function parseBoardItemLayer parses the layer definition of a BOARD_ITEM object.
Definition: pcb_parser.cpp:959
void SetCompany(const wxString &aCompany)
bool m_visible
Definition: class_board.h:115
void SetSize(const wxSize &aSize)
Definition: class_pad.h:181
static unsigned long parseHex(FILE_LINE_READER &aReader, const char *aLine, const char **aOutput=NULL)
Function parseHex.
int m_ZoneClearance
Clearance value.
TEXTE_PCB * parseTEXTE_PCB()
bool m_BlindBuriedViaAllowed
true to allow blind/buried vias
bool SetType(const wxString &aStandardPageDescriptionName, bool IsPortrait=false)
Function SetType sets the name of the page type and also the sizes and margins commonly associated wi...
#define THROW_IO_ERROR(x)
Definition: utf8.cpp:60
HATCH_STYLE
Zone hatch styles.
Definition: class_zone.h:85
Bezier Curve.
int GetNet() const
Function GetNet.
static LAYER_T ParseType(const char *aType)
Function ParseType converts a string to a LAYER_T.
BOARD_ITEM * Parse()
Definition: pcb_parser.cpp:405
void SetTitle(const wxString &aTitle)
int m_MicroViasMinSize
micro vias (not vias) min diameter
Class 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:60
int NewOutline()
Creates a new empty polygon in the set and returns its index
void SetPortrait(bool isPortrait)
Function SetPortrait will rotate the paper page 90 degrees.
void SetHeightMils(int aHeightInMils)
Thermal relief only for THT pads.
Definition: zones.h:60
Pad object description.
int LAYER_NUM
Type LAYER_NUM can be replaced with int and removed.
Class ZONE_SETTINGS handles zones parameters.
BOARD * parseBOARD_unchecked()
Function parseBOARD_unchecked Parse a module, but do not replace PARSE_ERROR with FUTURE_FORMAT_ERROR...
Definition: pcb_parser.cpp:460
ZONE_CONTAINER * parseZONE_CONTAINER()
void clear()
Definition: class_board.h:92
void parseLayer(LAYER *aLayer)
Definition: pcb_parser.cpp:771
virtual void SetPosition(const wxPoint &aPos) override
Class NETINFO_ITEM handles the data for a net.
Definition: class_netinfo.h:69
void SetComment2(const wxString &aComment)
Struct PARSE_ERROR contains a filename or source description, a problem input line, a line number, a byte offset, and an error message which contains the the caller's report and his call site information: CPP source file, function, and line number.
Definition: ki_exception.h:94
T
enum T contains all this lexer's tokens.
Definition: pcb_lexer.h:26
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:92
bool SyncLineReaderWith(DSNLEXER &aLexer)
Useable only for DSN lexers which share the same LINE_READER Synchronizes the pointers handling the d...
Definition: dsnlexer.cpp:169
EDGE_MODULE * parseEDGE_MODULE()
Class to handle a graphic segment.
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
#define max(a, b)
Definition: auxiliary.h:86
Class LAYER holds information pertinent to a layer of a BOARD.
Definition: class_board.h:85
Class BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:169
void SetHorizJustify(EDA_TEXT_HJUSTIFY_T aType)
Definition: eda_text.h:193
Virtual component: when created by copper shapes on board (Like edge card connectors, mounting hole...)
Definition: class_module.h:79
void parseGeneralSection()
Definition: pcb_parser.cpp:586
SGPOINT m_Rotation
an X,Y,Z rotation (unit = degrees) for the 3D shape
Definition: 3d_info.h:43
void init()
Function init clears and re-establishes m_layerMap with the default layer names.
Definition: pcb_parser.cpp:56
void SetWidthMils(int aWidthInMils)
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.
double z
Definition: sg_base.h:72
Usual pad.
Definition: pad_shapes.h:58
void SetVisibleElements(int aMask)
Function SetVisibleElements changes the bit-mask of visible element categories.
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:113
The common library.
std::vector< VIA_DIMENSION > m_ViasDimensionsList
Vias size and drill list.
double parseDouble()
Function parseDouble parses the current token as an ASCII numeric string with possible leading whites...
Definition: pcb_parser.cpp:124
const char * name
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
Struct SEGMENT is a simple container used when filling areas with segments.
Definition: class_zone.h:57
Pcbnew s-expression file format parser definition.
void SetTextAngle(double aAngle)
SGPOINT m_Scale
scaling factors for the 3D footprint shape
Definition: 3d_info.h:42
Struct FUTURE_FORMAT_ERROR variant of PARSE_ERROR indicating that a syntax or related error was likel...
Definition: ki_exception.h:143
Module description (excepted pads)
void SetComment3(const wxString &aComment)
bool IsEmpty() const
Returns true if the set is empty (no polygons at all)
bool m_MicroViasAllowed
true to allow micro vias
TEXTE_MODULE * parseTEXTE_MODULE()
int m_number
Definition: class_board.h:117
D_PAD * parseD_PAD(MODULE *aParent=NULL)
MODULE * parseMODULE(wxArrayString *aInitialComments=0)
Function parseMODULE.
int m_MicroViasMinDrill
micro vias (not vias) min drill diameter
int m_EdgeSegmentWidth
current graphic line width (EDGE layer only)
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.
void Parse(PCB_PLOT_PARAMS_PARSER *aParser)
void SetBold(bool aBold)
Definition: eda_text.h:172
void DisplayError(wxWindow *parent, const wxString &text, int displaytime)
Function DisplayError displays an error or warning message box with aMessage.
Definition: confirm.cpp:69
static const int UNCONNECTED
Constant that holds the "unconnected net" number (typically 0) all items "connected" to this net are ...
wxPoint m_AuxOrigin
origin for plot exports
Class DIMENSION.
static long parseInt(const wxString &aValue, double aScalar)
Definition: gpcb_plugin.cpp:73
void parseSetup()
Definition: pcb_parser.cpp:992
T lookUpLayer(const M &aMap)
Function lookUpLayer parses the current token for the layer definition of a BOARD_ITEM object...
Definition: pcb_parser.cpp:926
void SetThickness(int aNewThickness)
Function SetThickness sets pen width.
Definition: eda_text.h:148
int m_SolderMaskMinWidth
Solder mask min width.
pads are covered by copper
Definition: zones.h:59
Class BOARD_DESIGN_SETTINGS contains design settings for a BOARD object.
wxString m_Filename
The 3D shape filename in 3D library.
Definition: 3d_info.h:45
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) ...