31#include <fmt/format.h>
35#include <wx/mstream.h>
36#include <wx/tokenzr.h>
73using namespace TSCHEMATIC_T;
78 unsigned aLineCount,
SCH_SHEET* aRootSheet,
80 SCHEMATIC_LEXER( aLineReader ),
99 unsigned progressDelta = std::max( 50u,
m_lineCount / 10 );
118 KIID id( FromUTF8() );
135 else if( token == T_no )
138 Expecting(
"yes or no" );
149 bool ret = aDefaultValue;
151 if( PrevTok() == T_LEFT )
156 if(
static_cast<int>( token ) ==
DSN_RIGHT )
157 return aDefaultValue;
161 else if( token == T_no )
164 Expecting(
"yes or no" );
171 return aDefaultValue;
189 bool versionChecked =
false;
200 versionChecked =
true;
203 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
205 if( token != T_LEFT )
231 case T_generator_version:
254 aSymbolLibMap[symbol->
GetName()] = symbol;
259 wxString warning = wxString::Format(
260 _(
"Error parsing symbol at line %d: %s\nSkipping symbol and continuing." ),
261 CurLineNumber(), e.
What() );
273 Expecting(
"symbol, generator, or generator_version" );
287 if( CurTok() == T_LEFT )
291 if( CurTok() == T_symbol )
296 const std::vector<wxString>* embeddedFonts =
303 textItem->ResolveFont( embeddedFonts );
309 wxString msg = wxString::Format(
_(
"Cannot parse %s as a symbol" ),
310 GetTokenString( CurTok() ) );
321 wxCHECK_MSG( CurTok() == T_symbol,
nullptr,
322 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as a symbol." ) );
329 std::unique_ptr<LIB_SYMBOL> symbol = std::make_unique<LIB_SYMBOL>( wxEmptyString );
331 symbol->SetUnitCount( 1,
true );
335 if( !IsSymbol( token ) )
336 THROW_PARSE_ERROR(
_(
"Invalid symbol name" ), CurSource(), CurLine(), CurLineNumber(), CurOffset() );
343 name.Replace( wxS(
"{slash}" ), wxT(
"/" ) );
350 if(
static_cast<int>(
name.size() ) > bad_pos )
352 wxString msg = wxString::Format(
_(
"Symbol %s contains invalid character '%c'" ),
361 CurLineNumber(), CurOffset() );
366 symbol->SetLibId(
id );
368 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
370 if( token != T_LEFT )
378 symbol->SetGlobalPower();
381 if( token == T_RIGHT )
384 if( token == T_local )
385 symbol->SetLocalPower();
386 else if( token != T_global )
387 Expecting(
"global or local" );
404 case T_exclude_from_sim:
405 symbol->SetExcludedFromSim(
parseBool() );
410 symbol->SetExcludedFromBOM( !
parseBool() );
415 symbol->SetExcludedFromBoard( !
parseBool() );
420 symbol->SetExcludedFromPosFiles( !
parseBool() );
424 case T_duplicate_pin_numbers_are_jumpers:
425 symbol->SetDuplicatePinNumbersAreJumpers(
parseBool() );
429 case T_jumper_pin_groups:
431 std::vector<std::set<wxString>>& groups = symbol->JumperPinGroups();
432 std::set<wxString>* currentGroup =
nullptr;
434 for( token = NextTok(); currentGroup || token != T_RIGHT; token = NextTok() )
436 switch(
static_cast<int>( token ) )
439 currentGroup = &groups.emplace_back();
443 currentGroup->insert( FromUTF8() );
447 currentGroup =
nullptr;
451 Expecting(
"list of pin names" );
466 if( !IsSymbol( token ) )
469 CurLineNumber(), CurOffset() );
477 name.Replace( wxS(
"{slash}" ), wxT(
"/" ) );
479 symbol->SetParentName(
name );
488 if( !IsSymbol( token ) )
491 CurLineNumber(), CurOffset() );
499 name.Replace( wxS(
"{slash}" ), wxT(
"/" ) );
503 error.Printf(
_(
"Invalid symbol unit name prefix %s" ),
name.c_str() );
504 THROW_PARSE_ERROR( error, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
509 wxStringTokenizer tokenizer(
name,
"_" );
511 if( tokenizer.CountTokens() != 2 )
513 error.Printf(
_(
"Invalid symbol unit name suffix %s" ),
name.c_str() );
514 THROW_PARSE_ERROR( error, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
517 if( !tokenizer.GetNextToken().ToLong( &tmp ) )
519 error.Printf(
_(
"Invalid symbol unit number %s" ),
name.c_str() );
520 THROW_PARSE_ERROR( error, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
523 m_unit =
static_cast<int>( tmp );
525 if( !tokenizer.GetNextToken().ToLong( &tmp ) )
527 error.Printf(
_(
"Invalid symbol body style number %s" ),
name.c_str() );
528 THROW_PARSE_ERROR( error, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
534 symbol->SetBodyStyleCount(
m_bodyStyle,
false,
false );
536 if(
m_unit > symbol->GetUnitCount() )
537 symbol->SetUnitCount(
m_unit,
false );
539 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
541 if( token != T_LEFT )
551 if( IsSymbol( token ) )
552 symbol->GetUnitDisplayNames()[
m_unit] = FromUTF8();
567 wxCHECK_MSG( item,
nullptr,
"Invalid draw item pointer." );
570 symbol->AddDrawItem( item,
false );
574 Expecting(
"arc, bezier, circle, pin, polyline, rectangle, or text" );
593 wxCHECK_MSG( item,
nullptr,
"Invalid draw item pointer." );
596 symbol->AddDrawItem( item,
false );
599 case T_embedded_fonts:
601 symbol->SetAreFontsEmbedded(
parseBool() );
606 case T_embedded_files:
609 embeddedFilesParser.SyncLineReaderWith( *
this );
613 embeddedFilesParser.
ParseEmbedded( symbol->GetEmbeddedFiles() );
620 SyncLineReaderWith( embeddedFilesParser );
625 Expecting(
"pin_names, pin_numbers, arc, bezier, circle, pin, polyline, "
626 "rectangle, or text" );
630 symbol->GetDrawItems().sort();
633 const std::vector<wxString>* embeddedFonts = symbol->GetEmbeddedFiles()->UpdateFontFiles();
635 symbol->RunOnChildren(
639 textItem->ResolveFont( embeddedFonts );
646 symbol->SetHasDeMorganBodyStyles( symbol->HasLegacyAlternateBodyStyle() );
648 return symbol.release();
664 default: Expecting(
"arc, bezier, circle, pin, polyline, rectangle, or text" );
678 constexpr double int_limit = std::numeric_limits<int>::max() * 0.7071;
680 return KiROUND( std::clamp( retval, -int_limit, int_limit ) );
688 constexpr double int_limit = std::numeric_limits<int>::max() * 0.7071;
690 return KiROUND( std::clamp( retval, -int_limit, int_limit ) );
697 strokeParser.SyncLineReaderWith( *
this );
700 SyncLineReaderWith( strokeParser );
706 wxCHECK_RET( CurTok() == T_fill,
"Cannot parse " + GetTokenString( CurTok() ) +
" as a fill." );
713 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
715 if( token != T_LEFT )
735 default: Expecting(
"none, outline, hatch, reverse_hatch, "
736 "cross_hatch, color or background" );
750 color.
a = std::clamp(
parseDouble(
"alpha" ), 0.0, 1.0 );
757 Expecting(
"type or color" );
764 bool aEnforceMinTextSize )
766 wxCHECK_RET( aText && ( CurTok() == T_effects || CurTok() == T_href ),
767 "Cannot parse " + GetTokenString( CurTok() ) +
" as an EDA_TEXT." );
784 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
786 if( token == T_LEFT )
792 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
794 if( token == T_LEFT )
834 color.
a = std::clamp(
parseDouble(
"alpha" ), 0.0, 1.0 );
845 Expecting(
"face, size, thickness, line_spacing, bold, or italic" );
852 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
861 case T_mirror:
break;
862 default: Expecting(
"left, right, top, bottom, or mirror" );
871 wxString hyperlink = FromUTF8();
876 CurSource(), CurLine(), CurLineNumber(), CurOffset() );
895 Expecting(
"font, justify, hide or href" );
903 if( CurTok() != aHeaderType )
906 GetTokenString( CurTok() ) ),
907 CurSource(), CurLine(), CurLineNumber(), CurOffset() );
914 if( tok == T_version )
928 wxCHECK_RET( CurTok() == T_body_styles,
929 "Cannot parse " + GetTokenString( CurTok() ) +
" as a body_styles token." );
931 std::vector<wxString> names;
933 for(
T token = NextTok(); token != T_RIGHT; token = NextTok() )
935 if( token == T_demorgan )
937 aSymbol->SetHasDeMorganBodyStyles(
true );
940 else if( !IsSymbol( token ) )
942 THROW_PARSE_ERROR(
_(
"Invalid property value" ), CurSource(), CurLine(), CurLineNumber(),
946 names.push_back( FromUTF8() );
950 aSymbol->SetBodyStyleNames( names );
956 wxCHECK_RET( CurTok() == T_pin_names,
957 "Cannot parse " + GetTokenString( CurTok() ) +
" as a pin_name token." );
967 for(
T token = NextTok(); token != T_RIGHT; token = NextTok() )
970 if( token == T_hide )
972 aSymbol->SetShowPinNames(
false );
976 if( token != T_LEFT )
991 aSymbol->SetShowPinNames( !
parseBool() );
996 Expecting(
"offset or hide" );
1004 wxCHECK_RET( CurTok() == T_pin_numbers,
1005 "Cannot parse " + GetTokenString( CurTok() ) +
" as a pin_number token." );
1014 for(
T token = NextTok(); token != T_RIGHT; token = NextTok() )
1017 if( token == T_hide )
1019 aSymbol->SetShowPinNumbers(
false );
1023 if( token != T_LEFT )
1025 Expecting( T_LEFT );
1033 aSymbol->SetShowPinNumbers( !
parseBool() );
1038 Expecting(
"hide" );
1047 wxCHECK_MSG( CurTok() == T_property,
nullptr,
1048 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as a property." ) );
1049 wxCHECK( aSymbol,
nullptr );
1054 bool isPrivate =
false;
1055 bool isVisible =
true;
1057 T token = NextTok();
1059 if( token == T_private )
1065 if( !IsSymbol( token ) )
1067 THROW_PARSE_ERROR(
_(
"Invalid property name" ), CurSource(), CurLine(), CurLineNumber(),
1073 if(
name.IsEmpty() )
1075 THROW_PARSE_ERROR(
_(
"Empty property name" ), CurSource(), CurLine(), CurLineNumber(),
1089 auto field = std::make_unique<SCH_FIELD>( aSymbol.get(), fieldId,
name );
1090 field->SetPrivate( isPrivate );
1091 field->SetVisible( isVisible );
1095 if( !IsSymbol( token ) )
1097 THROW_PARSE_ERROR(
_(
"Invalid property value" ), CurSource(), CurLine(), CurLineNumber(),
1104 value = wxEmptyString;
1108 field->SetText( value );
1110 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1112 if( token != T_LEFT )
1113 Expecting( T_LEFT );
1125 field->SetPosition(
parseXY(
true ) );
1143 field->SetNameShown( show );
1147 case T_do_not_autoplace:
1150 field->SetCanAutoplace( !doNotAutoplace );
1155 Expecting(
"id, at, hide, show_name, do_not_autoplace, or effects" );
1161 if( field->IsMandatory() )
1163 existingField = aSymbol->GetField( field->GetId() );
1165 *existingField = *field;
1166 return existingField;
1168 else if(
name ==
"ki_keywords" )
1171 aSymbol->SetKeyWords( value );
1175 else if(
name ==
"ki_description" )
1177 aSymbol->SetDescription( value );
1180 else if(
name ==
"ki_fp_filters" )
1183 wxArrayString filters;
1184 wxStringTokenizer tokenizer( value,
" \t\r\n", wxTOKEN_STRTOK );
1186 while( tokenizer.HasMoreTokens() )
1188 wxString curr_token =
UnescapeString( tokenizer.GetNextToken() );
1189 filters.Add( curr_token );
1192 aSymbol->SetFPFilters( filters );
1195 else if(
name ==
"ki_locked" )
1199 aSymbol->LockUnits(
true );
1205 existingField = aSymbol->GetField( field->GetCanonicalName() );
1213 wxString base_name = field->GetCanonicalName();
1216 for(
int ii = 1; ii < 10 && existingField; ii++ )
1218 wxString newname = base_name;
1219 newname <<
'_' << ii;
1221 existingField = aSymbol->GetField( newname );
1223 if( !existingField )
1224 field->SetName( newname );
1228 if( !existingField )
1230 aSymbol->AddDrawItem( field.get(),
false );
1231 return field.release();
1244 wxCHECK_MSG( CurTok() == T_arc,
nullptr,
1245 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as an arc." ) );
1251 bool hasMidPoint =
false;
1259 bool hasAngles =
false;
1268 if( token == T_private )
1270 arc->SetPrivate(
true );
1274 for( ; token != T_RIGHT; token = NextTok() )
1276 if( token != T_LEFT )
1277 Expecting( T_LEFT );
1300 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1302 if( token != T_LEFT )
1303 Expecting( T_LEFT );
1331 Expecting(
"at, length, or angles" );
1339 arc->SetStroke( stroke );
1345 arc->SetFillColor( fill.
m_Color );
1349 Expecting(
"start, mid, end, radius, stroke, or fill" );
1355 arc->SetArcGeometry( startPoint, midPoint, endPoint );
1366 EDA_ANGLE arc_start, arc_end, arc_angle;
1367 arc->CalcArcAngles( arc_start, arc_end );
1368 arc_angle = arc_end - arc_start;
1373 arc->SetStart( endPoint );
1374 arc->SetEnd( startPoint );
1377 arc->SetCenter( new_center );
1383 arc->SetCenter( new_center );
1387 else if( hasAngles )
1389 arc->SetCenter(
center );
1395 arc->SetStart( endPoint );
1396 arc->SetEnd( startPoint );
1400 EDA_ANGLE arc_start, arc_end, arc_angle;
1401 arc->CalcArcAngles( arc_start, arc_end );
1402 arc_angle = arc_end - arc_start;
1408 arc->SetStart( startPoint );
1409 arc->SetEnd( endPoint );
1417 arc->SetStart( startPoint );
1418 arc->SetEnd( endPoint );
1422 arc->SetCenter( new_center );
1428 wxFAIL_MSG(
"Setting arc without either midpoint or angles not implemented." );
1431 return arc.release();
1437 wxCHECK_MSG( CurTok() == T_bezier,
nullptr,
1438 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as a bezier." ) );
1446 bezier->SetUnit(
m_unit );
1451 if( token == T_private )
1453 bezier->SetPrivate(
true );
1457 for( ; token != T_RIGHT; token = NextTok() )
1459 if( token != T_LEFT )
1460 Expecting( T_LEFT );
1470 for( token = NextTok(); token != T_RIGHT; token = NextTok(), ++ii )
1472 if( token != T_LEFT )
1473 Expecting( T_LEFT );
1482 case 0: bezier->SetStart(
parseXY(
true ) );
break;
1483 case 1: bezier->SetBezierC1(
parseXY(
true ) );
break;
1484 case 2: bezier->SetBezierC2(
parseXY(
true ) );
break;
1485 case 3: bezier->SetEnd(
parseXY(
true ) );
break;
1486 default: Unexpected(
"control point" );
break;
1496 bezier->SetStroke( stroke );
1502 bezier->SetFillColor( fill.
m_Color );
1506 Expecting(
"pts, stroke, or fill" );
1510 bezier->RebuildBezierToSegmentsPointsList(
m_maxError );
1512 return bezier.release();
1518 wxCHECK_MSG( CurTok() == T_circle,
nullptr,
1519 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as a circle." ) );
1534 if( token == T_private )
1536 circle->SetPrivate(
true );
1540 for( ; token != T_RIGHT; token = NextTok() )
1542 if( token != T_LEFT )
1543 Expecting( T_LEFT );
1561 circle->SetStroke( stroke );
1571 Expecting(
"center, radius, stroke, or fill" );
1604 Expecting(
"input, output, bidirectional, tri_state, passive, unspecified, "
1605 "power_in, power_out, open_collector, open_emitter, free or "
1627 Expecting(
"line, inverted, clock, inverted_clock, input_low, clock_low, "
1628 "output_low, edge_clock_high, non_logic" );
1633 wxCHECK_MSG( CurTok() == T_pin,
nullptr,
1634 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as a pin token." ) );
1637 std::unique_ptr<SCH_PIN>
pin = std::make_unique<SCH_PIN>(
nullptr );
1644 pin->SetType( parseType( token ) );
1648 pin->SetShape( parseShape( token ) );
1650 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1653 if( token == T_hide )
1655 pin->SetVisible(
false );
1659 if( token != T_LEFT )
1660 Expecting( T_LEFT );
1669 switch(
parseInt(
"pin orientation" ) )
1675 default: Expecting(
"0, 90, 180, or 270" );
1694 if( !IsSymbol( token ) )
1701 pin->SetName( wxEmptyString );
1705 pin->SetName( FromUTF8() );
1709 if( token != T_RIGHT )
1713 if( token == T_effects )
1720 pin->SetNameTextSize(
text.GetTextHeight() );
1725 Expecting(
"effects" );
1734 if( !IsSymbol( token ) )
1737 CurLineNumber(), CurOffset() );
1741 pin->SetNumber( wxEmptyString );
1745 pin->SetNumber( FromUTF8() );
1749 if( token != T_RIGHT )
1753 if( token == T_effects )
1760 pin->SetNumberTextSize(
text.GetTextHeight() );
1765 Expecting(
"effects" );
1777 if( !IsSymbol( token ) )
1780 CurLineNumber(), CurOffset() );
1786 alt.
m_Type = parseType( token );
1789 alt.
m_Shape = parseShape( token );
1791 pin->GetAlternates()[ alt.
m_Name ] = alt;
1798 Expecting(
"at, name, number, hide, length, or alternate" );
1802 return pin.release();
1808 wxCHECK_MSG( CurTok() == T_polyline,
nullptr,
1809 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as a poly." ) );
1821 if( token == T_private )
1823 poly->SetPrivate(
true );
1827 for( ; token != T_RIGHT; token = NextTok() )
1829 if( token != T_LEFT )
1830 Expecting( T_LEFT );
1837 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1839 if( token != T_LEFT )
1840 Expecting( T_LEFT );
1847 poly->AddPoint(
parseXY(
true ) );
1856 poly->SetStroke( stroke );
1862 poly->SetFillColor( fill.
m_Color );
1866 Expecting(
"pts, stroke, or fill" );
1870 return poly.release();
1876 wxCHECK_MSG( CurTok() == T_rectangle,
nullptr,
1877 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as a rectangle." ) );
1884 rectangle->SetUnit(
m_unit );
1889 if( token == T_private )
1891 rectangle->SetPrivate(
true );
1895 for( ; token != T_RIGHT; token = NextTok() )
1897 if( token != T_LEFT )
1898 Expecting( T_LEFT );
1905 rectangle->SetPosition(
parseXY(
true ) );
1910 rectangle->SetEnd(
parseXY(
true ) );
1921 rectangle->SetStroke( stroke );
1927 rectangle->SetFillColor( fill.
m_Color );
1931 Expecting(
"start, end, stroke, or fill" );
1935 return rectangle.release();
1941 wxCHECK_MSG( CurTok() == T_text,
nullptr,
1942 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as a text token." ) );
1945 std::unique_ptr<SCH_TEXT>
text = std::make_unique<SCH_TEXT>();
1952 if( token == T_private )
1954 text->SetPrivate(
true );
1958 if( !IsSymbol( token ) )
1960 THROW_PARSE_ERROR(
_(
"Invalid text string" ), CurSource(), CurLine(), CurLineNumber(),
1964 text->SetText( FromUTF8() );
1966 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
1968 if( token != T_LEFT )
1969 Expecting( T_LEFT );
1987 Expecting(
"at or effects" );
1992 if( !
text->IsVisible() )
1995 return text.release();
2001 wxCHECK_MSG( CurTok() == T_text_box,
nullptr,
2002 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as a text box." ) );
2014 bool foundEnd =
false;
2015 bool foundSize =
false;
2016 bool foundMargins =
false;
2018 std::unique_ptr<SCH_TEXTBOX> textBox = std::make_unique<SCH_TEXTBOX>(
LAYER_DEVICE );
2020 textBox->SetUnit(
m_unit );
2024 if( token == T_private )
2026 textBox->SetPrivate(
true );
2030 if( !IsSymbol( token ) )
2032 THROW_PARSE_ERROR(
_(
"Invalid text string" ), CurSource(), CurLine(), CurLineNumber(),
2036 textBox->SetText( FromUTF8() );
2038 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2040 if( token != T_LEFT )
2041 Expecting( T_LEFT );
2072 textBox->SetStroke( stroke );
2078 textBox->SetFillColor( fill.
m_Color );
2083 textBox->SetMarginLeft(
left );
2084 textBox->SetMarginTop(
top );
2085 textBox->SetMarginRight(
right );
2086 textBox->SetMarginBottom( bottom );
2087 foundMargins =
true;
2096 Expecting(
"at, size, stroke, fill or effects" );
2100 textBox->SetPosition( pos );
2103 textBox->SetEnd(
end );
2104 else if( foundSize )
2105 textBox->SetEnd( pos + size );
2107 Expecting(
"size" );
2111 int margin = textBox->GetLegacyTextMargin();
2112 textBox->SetMarginLeft( margin );
2113 textBox->SetMarginTop( margin );
2114 textBox->SetMarginRight( margin );
2115 textBox->SetMarginBottom( margin );
2118 return textBox.release();
2124 wxCHECK_RET( ( CurTok() == T_page &&
m_requiredVersion <= 20200506 ) || CurTok() == T_paper,
2125 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as a PAGE_INFO." ) );
2131 wxString pageType = FromUTF8();
2133 if( !aPageInfo.
SetType( pageType ) )
2135 THROW_PARSE_ERROR(
_(
"Invalid page type" ), CurSource(), CurLine(), CurLineNumber(),
2162 if( token == T_portrait )
2167 else if( token != T_RIGHT )
2169 Expecting(
"portrait" );
2176 wxCHECK_RET( CurTok() == T_title_block,
2177 "Cannot parse " + GetTokenString( CurTok() ) +
" as a TITLE_BLOCK." );
2181 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2183 if( token != T_LEFT )
2184 Expecting( T_LEFT );
2192 aTitleBlock.
SetTitle( FromUTF8() );
2197 aTitleBlock.
SetDate( FromUTF8() );
2212 int commentNumber =
parseInt(
"comment" );
2214 switch( commentNumber )
2263 CurLine(), CurLineNumber(), CurOffset() );
2270 Expecting(
"title, date, rev, company, or comment" );
2280 wxCHECK_MSG( CurTok() == T_property,
nullptr,
2281 "Cannot parse " + GetTokenString( CurTok() ) +
" as a property token." );
2283 bool is_private =
false;
2285 T token = NextTok();
2287 if( token == T_private )
2293 if( !IsSymbol( token ) )
2295 THROW_PARSE_ERROR(
_(
"Invalid property name" ), CurSource(), CurLine(), CurLineNumber(),
2299 wxString
name = FromUTF8();
2301 if(
name.IsEmpty() )
2303 THROW_PARSE_ERROR(
_(
"Empty property name" ), CurSource(), CurLine(), CurLineNumber(),
2309 if( !IsSymbol( token ) )
2311 THROW_PARSE_ERROR(
_(
"Invalid property value" ), CurSource(), CurLine(), CurLineNumber(),
2319 value = wxEmptyString;
2351 if(
name.CmpNoCase( wxT(
"Sheet name" ) ) == 0 )
2353 else if(
name.CmpNoCase( wxT(
"Sheet file" ) ) == 0 )
2368 if(
name.CmpNoCase( wxT(
"Intersheet References" ) ) == 0 )
2372 std::unique_ptr<SCH_FIELD> field = std::make_unique<SCH_FIELD>( aParent, fieldId,
name );
2373 field->SetText( value );
2376 field->SetPrivate( is_private );
2378 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2380 if( token != T_LEFT )
2381 Expecting( T_LEFT );
2393 field->SetPosition(
parseXY() );
2411 field->SetNameShown( show );
2415 case T_do_not_autoplace:
2418 field->SetCanAutoplace( !doNotAutoplace );
2423 Expecting(
"id, at, hide, show_name, do_not_autoplace or effects" );
2427 return field.release();
2433 wxCHECK_MSG( aSheet !=
nullptr,
nullptr,
"" );
2434 wxCHECK_MSG( CurTok() == T_pin,
nullptr,
2435 "Cannot parse " + GetTokenString( CurTok() ) +
" as a sheet pin token." );
2437 T token = NextTok();
2439 if( !IsSymbol( token ) )
2441 THROW_PARSE_ERROR(
_(
"Invalid sheet pin name" ), CurSource(), CurLine(), CurLineNumber(),
2445 wxString
name = FromUTF8();
2447 if(
name.IsEmpty() )
2449 THROW_PARSE_ERROR(
_(
"Empty sheet pin name" ), CurSource(), CurLine(), CurLineNumber(),
2453 auto sheetPin = std::make_unique<SCH_SHEET_PIN>( aSheet,
VECTOR2I( 0, 0 ),
name );
2465 Expecting(
"input, output, bidirectional, tri_state, or passive" );
2468 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2470 if( token != T_LEFT )
2471 Expecting( T_LEFT );
2479 sheetPin->SetPosition(
parseXY() );
2481 double angle =
parseDouble(
"sheet pin angle (side)" );
2485 else if( angle == 90.0 )
2487 else if( angle == 180.0 )
2489 else if( angle == 270.0 )
2492 Expecting(
"0, 90, 180, or 270" );
2509 Expecting(
"at, uuid or effects" );
2513 return sheetPin.release();
2519 wxCHECK_RET( CurTok() == T_sheet_instances,
2520 "Cannot parse " + GetTokenString( CurTok() ) +
" as an instances token." );
2521 wxCHECK( aScreen, );
2525 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2527 if( token != T_LEFT )
2528 Expecting( T_LEFT );
2546 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2548 if( token != T_LEFT )
2549 Expecting( T_LEFT );
2553 std::vector<wxString> whitespaces = { wxT(
"\r" ), wxT(
"\n" ), wxT(
"\t" ),
2556 size_t numReplacements = 0;
2574 for(
const wxString& ch : whitespaces )
2575 numReplacements += instance.
m_PageNumber.Replace( ch, wxEmptyString );
2580 if( numReplacements > 0 )
2587 Expecting(
"path or page" );
2592 && ( instance.
m_Path.empty() ) )
2608 Expecting(
"path" );
2616 wxCHECK_RET( CurTok() == T_symbol_instances,
2617 "Cannot parse " + GetTokenString( CurTok() ) +
" as an instances token." );
2618 wxCHECK( aScreen, );
2623 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2625 if( token != T_LEFT )
2626 Expecting( T_LEFT );
2643 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2645 if( token != T_LEFT )
2646 Expecting( T_LEFT );
2667 instance.
m_Value = wxEmptyString;
2669 instance.
m_Value = FromUTF8();
2686 Expecting(
"path, unit, value or footprint" );
2695 Expecting(
"path" );
2704 wxCHECK( aSheet !=
nullptr, );
2708 wxCHECK( screen !=
nullptr, );
2711 m_maxError = schematic->Settings().m_MaxError;
2713 if( aIsCopyableOnly )
2716 bool fileHasUuid =
false;
2730 if( !aIsCopyableOnly )
2735 if( CurTok() != T_kicad_sch )
2736 Expecting(
"kicad_sch" );
2755 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2757 if( aIsCopyableOnly && token == T_EOF )
2760 if( token != T_LEFT )
2761 Expecting( T_LEFT );
2795 case T_generator_version:
2821 if( aIsCopyableOnly )
2822 Unexpected( T_paper );
2832 if( aIsCopyableOnly )
2833 Unexpected( T_page );
2837 NeedSYMBOLorNUMBER();
2838 NeedSYMBOLorNUMBER();
2845 if( aIsCopyableOnly )
2846 Unexpected( T_title_block );
2860 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
2862 if( token != T_LEFT )
2863 Expecting( T_LEFT );
2875 Expecting(
"symbol" );
2932 THROW_PARSE_ERROR(
_(
"Schematic polyline has too few points" ), CurSource(), CurLine(),
2933 CurLineNumber(), CurOffset() );
2982 case T_netclass_flag:
2987 case T_global_label:
2988 case T_hierarchical_label:
2989 case T_directive_label:
3001 case T_sheet_instances:
3005 case T_symbol_instances:
3010 if( aIsCopyableOnly )
3011 Unexpected( T_bus_alias );
3016 case T_embedded_fonts:
3022 CurLineNumber(), CurOffset() );
3029 case T_embedded_files:
3035 CurLineNumber(), CurOffset() );
3038 embeddedFilesParser.SyncLineReaderWith( *
this );
3049 SyncLineReaderWith( embeddedFilesParser );
3055 Expecting(
"bitmap, bus, bus_alias, bus_entry, class_label, embedded_files, global_label, "
3056 "hierarchical_label, junction, label, line, no_connect, page, paper, rule_area, "
3057 "sheet, symbol, symbol_instances, text, title_block" );
3078 CurLineNumber(), CurOffset() );
3082 std::vector<std::string> fontNames;
3083 Fontconfig()->ListFonts( fontNames, std::string(
Pgm().GetLanguageTag().utf8_str() ),
3093 wxCHECK_MSG( CurTok() == T_symbol,
nullptr,
3094 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as a symbol." ) );
3099 std::unique_ptr<SCH_SYMBOL> symbol = std::make_unique<SCH_SYMBOL>();
3101 std::set<int> fieldIDsRead;
3106 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3108 if( token != T_LEFT )
3109 Expecting( T_LEFT );
3121 if( !IsSymbol( token ) )
3124 CurLineNumber(), CurOffset() );
3127 libName = FromUTF8();
3131 libName.Replace(
"{slash}",
"/" );
3141 if( !IsSymbol( token ) && token != T_NUMBER )
3142 Expecting(
"symbol|number" );
3145 wxString
name = FromUTF8();
3149 name.Replace(
"{slash}",
"/" );
3155 if(
static_cast<int>(
name.size() ) > bad_pos )
3157 wxString msg = wxString::Format(
_(
"Symbol %s contains invalid character '%c'" ),
3165 CurLineNumber(), CurOffset() );
3168 symbol->SetLibId( libId );
3174 symbol->SetPosition(
parseXY() );
3176 switch(
static_cast<int>(
parseDouble(
"symbol orientation" ) ) )
3179 case 90: transform =
TRANSFORM( 0, 1, -1, 0 );
break;
3180 case 180: transform =
TRANSFORM( -1, 0, 0, -1 );
break;
3181 case 270: transform =
TRANSFORM( 0, -1, 1, 0 );
break;
3182 default: Expecting(
"0, 90, 180, or 270" );
3185 symbol->SetTransform( transform );
3194 else if( token == T_y )
3197 Expecting(
"x or y" );
3203 symbol->SetUnit(
parseInt(
"symbol unit" ) );
3209 symbol->SetBodyStyle(
parseInt(
"symbol body style" ) );
3213 case T_exclude_from_sim:
3214 symbol->SetExcludedFromSim(
parseBool() );
3219 symbol->SetExcludedFromBOM( !
parseBool() );
3224 symbol->SetExcludedFromBoard( !
parseBool() );
3228 case T_in_pos_files:
3229 symbol->SetExcludedFromPosFiles( !
parseBool() );
3238 case T_fields_autoplaced:
3250 case T_default_instance:
3254 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3256 if( token != T_LEFT )
3257 Expecting( T_LEFT );
3278 symbol->SetValueFieldText( wxEmptyString );
3280 symbol->SetValueFieldText( FromUTF8() );
3289 symbol->SetFootprintFieldText( wxEmptyString );
3291 symbol->SetFootprintFieldText( FromUTF8() );
3297 Expecting(
"reference, unit, value or footprint" );
3306 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3308 if( token != T_LEFT )
3309 Expecting( T_LEFT );
3313 if( token != T_project )
3314 Expecting(
"project" );
3318 wxString projectName = FromUTF8();
3320 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3322 if( token != T_LEFT )
3323 Expecting( T_LEFT );
3327 if( token != T_path )
3328 Expecting(
"path" );
3337 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3339 if( token != T_LEFT )
3340 Expecting( T_LEFT );
3361 symbol->SetValueFieldText( wxEmptyString );
3363 symbol->SetValueFieldText( FromUTF8() );
3372 symbol->SetFootprintFieldText( wxEmptyString );
3374 symbol->SetFootprintFieldText( FromUTF8() );
3385 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3387 if( token != T_LEFT )
3388 Expecting( T_LEFT );
3396 variant.
m_Name = FromUTF8();
3405 case T_exclude_from_sim:
3427 case T_in_pos_files:
3435 wxString fieldValue;
3437 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3439 if( token != T_LEFT )
3440 Expecting( T_LEFT );
3448 fieldName = FromUTF8();
3454 fieldValue = FromUTF8();
3459 Expecting(
"name or value" );
3463 variant.
m_Fields[fieldName] = fieldValue;
3468 Expecting(
"dnp, exclude_from_sim, field, in_bom, in_pos_files, name, or on_board" );
3478 Expecting(
"reference, unit, value, footprint, or variant" );
3482 symbol->AddHierarchicalReference( instance );
3498 symbol->SetExcludedFromSim( field->
GetText() == wxS(
"0" ) );
3506 symbol->SetExcludedFromSim( field->
GetText() == wxS(
"N" ) );
3514 existing = symbol->GetField( field->
GetId() );
3516 existing = symbol->GetField( field->
GetName() );
3521 symbol->AddField( *field );
3524 symbol->UpdatePrefix();
3537 number = FromUTF8();
3539 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3541 if( token != T_LEFT )
3542 Expecting( T_LEFT );
3566 Expecting(
"alternate or uuid" );
3570 symbol->GetRawPins().emplace_back( std::make_unique<SCH_PIN>( symbol.get(), number,
3576 Expecting(
"lib_id, lib_name, at, mirror, uuid, exclude_from_sim, on_board, in_bom, dnp, "
3577 "default_instance, property, pin, or instances" );
3581 if( !libName.IsEmpty() && ( symbol->GetLibId().Format().wx_str() != libName ) )
3582 symbol->SetSchSymbolLibraryName( libName );
3585 symbol->ClearFlags();
3587 return symbol.release();
3593 wxCHECK_MSG( CurTok() == T_image,
nullptr,
3594 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as an image." ) );
3597 std::unique_ptr<SCH_BITMAP> bitmap = std::make_unique<SCH_BITMAP>();
3600 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3602 if( token != T_LEFT )
3603 Expecting( T_LEFT );
3610 bitmap->SetPosition(
parseXY() );
3636 data.reserve( 1 << 17 );
3638 while( token != T_RIGHT )
3640 if( !IsSymbol( token ) )
3641 Expecting(
"base64 image data" );
3647 wxMemoryBuffer buffer = wxBase64Decode( data );
3656 Expecting(
"at, scale, uuid or data" );
3669 return bitmap.release();
3675 wxCHECK_MSG( CurTok() == T_sheet,
nullptr,
3676 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as a sheet." ) );
3682 std::vector<SCH_FIELD> fields;
3683 std::unique_ptr<SCH_SHEET> sheet = std::make_unique<SCH_SHEET>();
3684 std::set<int> fieldIDsRead;
3689 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3691 if( token != T_LEFT )
3692 Expecting( T_LEFT );
3699 sheet->SetPosition(
parseXY() );
3708 sheet->SetSize( size );
3713 case T_exclude_from_sim:
3714 sheet->SetExcludedFromSim(
parseBool() );
3719 sheet->SetExcludedFromBOM( !
parseBool() );
3724 sheet->SetExcludedFromBoard( !
parseBool() );
3733 case T_fields_autoplaced:
3741 sheet->SetBorderWidth( stroke.
GetWidth() );
3742 sheet->SetBorderColor( stroke.
GetColor() );
3747 sheet->SetBackgroundColor( fill.
m_Color );
3764 if( fields.empty() )
3770 fields.emplace_back( *field );
3781 std::vector<SCH_SHEET_INSTANCE> instances;
3783 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3785 if( token != T_LEFT )
3786 Expecting( T_LEFT );
3790 if( token != T_project )
3791 Expecting(
"project" );
3795 wxString projectName = FromUTF8();
3797 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3799 if( token != T_LEFT )
3800 Expecting( T_LEFT );
3804 if( token != T_path )
3805 Expecting(
"path" );
3814 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3816 if( token != T_LEFT )
3817 Expecting( T_LEFT );
3837 static std::vector<wxString> whitespaces =
3843 for( wxString ch : whitespaces )
3856 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3858 if( token != T_LEFT )
3859 Expecting( T_LEFT );
3867 variant.
m_Name = FromUTF8();
3876 case T_exclude_from_sim:
3898 case T_in_pos_files:
3906 wxString fieldValue;
3908 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3910 if( token != T_LEFT )
3911 Expecting( T_LEFT );
3919 fieldName = FromUTF8();
3925 fieldValue = FromUTF8();
3930 Expecting(
"name or value" );
3934 variant.
m_Fields[fieldName] = fieldValue;
3939 Expecting(
"dnp, exclude_from_sim, field, in_bom, in_pos_files, name, or on_board" );
3949 Expecting(
"page or variant" );
3953 instances.emplace_back( instance );
3957 sheet->setInstances( instances );
3962 Expecting(
"at, size, stroke, background, instances, uuid, property, or pin" );
3966 sheet->SetFields( fields );
3971 CurLineNumber(), CurOffset() );
3977 CurLineNumber(), CurOffset() );
3980 return sheet.release();
3986 wxCHECK_MSG( CurTok() == T_junction,
nullptr,
3987 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as a junction." ) );
3990 std::unique_ptr<SCH_JUNCTION> junction = std::make_unique<SCH_JUNCTION>();
3992 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
3994 if( token != T_LEFT )
3995 Expecting( T_LEFT );
4002 junction->SetPosition(
parseXY() );
4018 color.
a = std::clamp(
parseDouble(
"alpha" ), 0.0, 1.0 );
4020 junction->SetColor( color );
4032 Expecting(
"at, diameter, color or uuid" );
4036 return junction.release();
4042 wxCHECK_MSG( CurTok() == T_no_connect,
nullptr,
4043 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as a no connect." ) );
4046 std::unique_ptr<SCH_NO_CONNECT> no_connect = std::make_unique<SCH_NO_CONNECT>();
4048 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
4050 if( token != T_LEFT )
4051 Expecting( T_LEFT );
4058 no_connect->SetPosition(
parseXY() );
4069 Expecting(
"at or uuid" );
4073 return no_connect.release();
4079 wxCHECK_MSG( CurTok() == T_bus_entry,
nullptr,
4080 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as a bus entry." ) );
4084 std::unique_ptr<SCH_BUS_WIRE_ENTRY> busEntry = std::make_unique<SCH_BUS_WIRE_ENTRY>();
4086 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
4088 if( token != T_LEFT )
4089 Expecting( T_LEFT );
4096 busEntry->SetPosition(
parseXY() );
4106 busEntry->SetSize( size );
4113 busEntry->SetStroke( stroke );
4123 Expecting(
"at, size, uuid or stroke" );
4127 return busEntry.release();
4149 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
4151 if( token != T_LEFT )
4152 Expecting( T_LEFT );
4159 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
4161 if( token != T_LEFT )
4162 Expecting( T_LEFT );
4169 polyline->AddPoint(
parseXY() );
4182 polyline->SetStroke( stroke );
4188 polyline->SetFillColor( fill.
m_Color );
4199 Expecting(
"pts, uuid, stroke, or fill" );
4203 return polyline.release();
4222 wxCHECK_MSG(
false,
nullptr,
"Cannot parse " + GetTokenString( CurTok() ) +
" as a line." );
4225 std::unique_ptr<SCH_LINE> line = std::make_unique<SCH_LINE>(
VECTOR2I(), layer );
4227 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
4229 if( token != T_LEFT )
4230 Expecting( T_LEFT );
4243 line->SetStartPoint(
parseXY() );
4251 line->SetEndPoint(
parseXY() );
4258 line->SetStroke( stroke );
4268 Expecting(
"at, uuid or stroke" );
4272 return line.release();
4278 wxCHECK_MSG( CurTok() == T_arc,
nullptr,
4279 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as an arc." ) );
4287 std::unique_ptr<SCH_SHAPE> arc = std::make_unique<SCH_SHAPE>(
SHAPE_T::ARC );
4289 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
4291 if( token != T_LEFT )
4292 Expecting( T_LEFT );
4315 arc->SetStroke( stroke );
4321 arc->SetFillColor( fill.
m_Color );
4327 const_cast<KIID&
>( arc->m_Uuid ) =
KIID( FromUTF8() );
4332 Expecting(
"start, mid, end, stroke, fill or uuid" );
4336 arc->SetArcGeometry( startPoint, midPoint, endPoint );
4338 return arc.release();
4344 wxCHECK_MSG( CurTok() == T_circle,
nullptr,
4345 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as a circle." ) );
4354 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
4356 if( token != T_LEFT )
4357 Expecting( T_LEFT );
4375 circle->SetStroke( stroke );
4392 Expecting(
"center, radius, stroke, fill or uuid" );
4405 wxCHECK_MSG( CurTok() == T_rectangle,
nullptr,
4406 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as a rectangle." ) );
4411 std::unique_ptr<SCH_SHAPE> rectangle = std::make_unique<SCH_SHAPE>(
SHAPE_T::RECTANGLE );
4413 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
4415 if( token != T_LEFT )
4416 Expecting( T_LEFT );
4423 rectangle->SetPosition(
parseXY() );
4428 rectangle->SetEnd(
parseXY() );
4439 rectangle->SetStroke( stroke );
4445 rectangle->SetFillColor( fill.
m_Color );
4451 const_cast<KIID&
>( rectangle->m_Uuid ) =
KIID( FromUTF8() );
4456 Expecting(
"start, end, stroke, fill or uuid" );
4460 return rectangle.release();
4466 wxCHECK_MSG( CurTok() == T_rule_area,
nullptr,
4467 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as a rule area." ) );
4472 std::unique_ptr<SCH_RULE_AREA> ruleArea = std::make_unique<SCH_RULE_AREA>();
4474 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
4476 if( token != T_LEFT )
4477 Expecting( T_LEFT );
4491 ruleArea->SetPolyShape( sch_rule_poly );
4493 ruleArea->SetStroke( poly->GetStroke() );
4494 ruleArea->SetFillMode( poly->GetFillMode() );
4495 ruleArea->SetFillColor( poly->GetFillColor() );
4498 const_cast<KIID&
>( ruleArea->m_Uuid ) = poly->m_Uuid;
4502 case T_exclude_from_sim:
4503 ruleArea->SetExcludedFromSim(
parseBool() );
4508 ruleArea->SetExcludedFromBOM( !
parseBool() );
4513 ruleArea->SetExcludedFromBoard( !
parseBool() );
4523 Expecting(
"exclude_from_sim, on_board, in_bom, dnp, or polyline" );
4527 return ruleArea.release();
4533 wxCHECK_MSG( CurTok() == T_bezier,
nullptr,
4534 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as a bezier." ) );
4539 std::unique_ptr<SCH_SHAPE> bezier = std::make_unique<SCH_SHAPE>(
SHAPE_T::BEZIER );
4541 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
4543 if( token != T_LEFT )
4544 Expecting( T_LEFT );
4554 for( token = NextTok(); token != T_RIGHT; token = NextTok(), ++ii )
4556 if( token != T_LEFT )
4557 Expecting( T_LEFT );
4566 case 0: bezier->SetStart(
parseXY() );
break;
4567 case 1: bezier->SetBezierC1(
parseXY() );
break;
4568 case 2: bezier->SetBezierC2(
parseXY() );
break;
4569 case 3: bezier->SetEnd(
parseXY() );
break;
4570 default: Unexpected(
"control point" );
break;
4580 bezier->SetStroke( stroke );
4586 bezier->SetFillColor( fill.
m_Color );
4592 const_cast<KIID&
>( bezier->m_Uuid ) =
KIID( FromUTF8() );
4597 Expecting(
"pts, stroke, fill or uuid" );
4601 bezier->RebuildBezierToSegmentsPointsList(
m_maxError );
4603 return bezier.release();
4610 std::unique_ptr<SCH_TEXT>
text;
4614 case T_text:
text = std::make_unique<SCH_TEXT>();
break;
4615 case T_label:
text = std::make_unique<SCH_LABEL>();
break;
4616 case T_global_label:
text = std::make_unique<SCH_GLOBALLABEL>();
break;
4617 case T_hierarchical_label:
text = std::make_unique<SCH_HIERLABEL>();
break;
4618 case T_netclass_flag:
text = std::make_unique<SCH_DIRECTIVE_LABEL>();
break;
4619 case T_directive_label:
text = std::make_unique<SCH_DIRECTIVE_LABEL>();
break;
4621 wxCHECK_MSG(
false,
nullptr,
"Cannot parse " + GetTokenString( CurTok() ) +
" as text." );
4629 text->SetText( FromUTF8() );
4631 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
4633 if( token != T_LEFT )
4634 Expecting( T_LEFT );
4640 case T_exclude_from_sim:
4651 switch(
static_cast<int>( label->GetTextAngle().AsDegrees() ) )
4667 Unexpected( T_shape );
4685 Expecting(
"input, output, bidirectional, tri_state, passive, dot, round, diamond"
4696 Unexpected( T_length );
4705 case T_fields_autoplaced:
4715 text->SetVisible(
true );
4740 Unexpected( T_property );
4760 Expecting(
"at, shape, iref, uuid or effects" );
4766 if( label && label->
GetFields().empty() )
4769 return text.release();
4775 wxCHECK_MSG( CurTok() == T_text_box,
nullptr,
4776 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as a text box." ) );
4778 std::unique_ptr<SCH_TEXTBOX> textBox = std::make_unique<SCH_TEXTBOX>();
4782 return textBox.release();
4788 wxCHECK_MSG( CurTok() == T_table_cell,
nullptr,
4789 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as a table cell." ) );
4791 std::unique_ptr<SCH_TABLECELL> cell = std::make_unique<SCH_TABLECELL>();
4795 return cell.release();
4811 bool foundEnd =
false;
4812 bool foundSize =
false;
4813 bool foundMargins =
false;
4817 aTextBox->
SetText( FromUTF8() );
4819 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
4821 if( token != T_LEFT )
4822 Expecting( T_LEFT );
4828 case T_exclude_from_sim:
4859 cell->SetColSpan(
parseInt(
"column span" ) );
4860 cell->SetRowSpan(
parseInt(
"row span" ) );
4864 Expecting(
"at, size, stroke, fill, effects or uuid" );
4888 foundMargins =
true;
4904 Expecting(
"at, size, stroke, fill, effects, span or uuid" );
4906 Expecting(
"at, size, stroke, fill, effects or uuid" );
4914 else if( foundSize )
4915 aTextBox->
SetEnd( pos + size );
4917 Expecting(
"size" );
4932 wxCHECK_MSG( CurTok() == T_table,
nullptr,
4933 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as a table." ) );
4939 std::unique_ptr<SCH_TABLE>
table = std::make_unique<SCH_TABLE>( defaultLineWidth );
4941 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
4943 if( token != T_LEFT )
4944 Expecting( T_LEFT );
4950 case T_column_count:
4955 case T_column_widths:
4959 while( ( token = NextTok() ) != T_RIGHT )
4969 while( ( token = NextTok() ) != T_RIGHT )
4976 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
4978 if( token != T_LEFT )
4979 Expecting( T_LEFT );
4983 if( token != T_table_cell )
4984 Expecting(
"table_cell" );
4992 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
4994 if( token != T_LEFT )
4995 Expecting( T_LEFT );
5013 table->SetBorderStroke( borderStroke );
5017 Expecting(
"external, header or stroke" );
5025 for( token = NextTok(); token != T_RIGHT; token = NextTok() )
5027 if( token != T_LEFT )
5028 Expecting( T_LEFT );
5046 table->SetSeparatorsStroke( separatorsStroke );
5050 Expecting(
"rows, cols, or stroke" );
5064 Expecting(
"columns, col_widths, row_heights, border, separators, uuid, header or cells" );
5068 if( !
table->GetCell( 0, 0 ) )
5070 THROW_PARSE_ERROR(
_(
"Invalid table: no cells defined" ), CurSource(), CurLine(), CurLineNumber(),
5074 return table.release();
5080 wxCHECK_RET( CurTok() == T_bus_alias,
5081 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as a bus alias." ) );
5082 wxCHECK( aScreen, );
5085 std::shared_ptr<BUS_ALIAS> busAlias = std::make_shared<BUS_ALIAS>();
5096 busAlias->SetName( alias );
5101 if( token != T_members )
5102 Expecting(
"members" );
5106 while( token != T_RIGHT )
5108 if( !IsSymbol( token ) )
5109 Expecting(
"quoted string" );
5111 member = FromUTF8();
5116 busAlias->AddMember( member );
5131 while( ( token = NextTok() ) != T_RIGHT )
5136 KIID uuid( CurStr() );
5144 wxCHECK_RET( CurTok() == T_group,
5145 wxT(
"Cannot parse " ) + GetTokenString( CurTok() ) + wxT(
" as PCB_GROUP." ) );
5152 while( ( token = NextTok() ) != T_LEFT )
5154 if( token == T_STRING )
5155 groupInfo.
name = FromUTF8();
5157 Expecting(
"group name or locked" );
5160 for( ; token != T_RIGHT; token = NextTok() )
5162 if( token != T_LEFT )
5163 Expecting( T_LEFT );
5179 if( !IsSymbol( token ) && token != T_NUMBER )
5180 Expecting(
"symbol|number" );
5183 wxString
name = FromUTF8();
5187 name.Replace(
"{slash}",
"/" );
5193 if(
static_cast<int>(
name.size() ) > bad_pos )
5195 wxString msg = wxString::Format(
_(
"Group library link %s contains invalid character '%c'" ),
name,
5201 THROW_PARSE_ERROR(
_(
"Invalid library ID" ), CurSource(), CurLine(), CurLineNumber(), CurOffset() );
5215 Expecting(
"uuid, lib_id, members" );
5227 [&](
const KIID& aId )
5233 if( item->m_Uuid == aId )
5252 group->SetName( groupInfo.name );
5254 const_cast<KIID&
>(
group->m_Uuid ) = groupInfo.uuid;
5256 if( groupInfo.libId.IsValid() )
5257 group->SetDesignBlockLibId( groupInfo.libId );
5268 for(
const KIID& aUuid : groupInfo.memberUuids )
5270 if(
SCH_ITEM* gItem = getItem( aUuid ) )
5271 group->AddItem( gItem );
5286 T token = NextTok();
5288 if( token == T_EOF )
5290 else if( token == T_LEFT )
5292 else if( token == T_RIGHT )
constexpr EDA_IU_SCALE schIUScale
constexpr double ARC_LOW_DEF_MM
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
void SetContentModified(bool aModified=true)
static const COLOR4D UNSPECIFIED
For legacy support; used as a value to indicate color hasn't been set yet.
KICAD_T Type() const
Returns the type of object.
EDA_ITEM * GetParent() const
virtual void SetParent(EDA_ITEM *aParent)
FILL_T GetFillMode() const
SHAPE_POLY_SET & GetPolyShape()
void SetFillColor(const COLOR4D &aColor)
int GetPointCount() const
void SetEnd(const VECTOR2I &aEnd)
void SetFillMode(FILL_T aFill)
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
void SetTextColor(const COLOR4D &aColor)
void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true)
void SetUnresolvedFontName(const wxString &aFontName)
virtual const wxString & GetText() const
Return the string associated with the text object.
void SetTextPos(const VECTOR2I &aPoint)
void SetVertJustify(GR_TEXT_V_ALIGN_T aType)
void SetBoldFlag(bool aBold)
Set only the bold flag, without changing the font.
virtual void SetVisible(bool aVisible)
void SetLineSpacing(double aLineSpacing)
void SetTextThickness(int aWidth)
The TextThickness is that set by the user.
static bool ValidateHyperlink(const wxString &aURL)
Check if aURL is a valid hyperlink.
void SetItalicFlag(bool aItalic)
Set only the italic flag, without changing the font.
void SetHyperlink(wxString aLink)
virtual void SetText(const wxString &aText)
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
void ParseEmbedded(EMBEDDED_FILES *aFiles)
const std::vector< wxString > * UpdateFontFiles()
Helper function to get a list of fonts for fontconfig to add to the library.
const std::vector< wxString > * GetFontFiles() const
If we just need the cached version of the font files, we can use this function which is const and wil...
void SetAreFontsEmbedded(bool aEmbedFonts)
Simple container to manage fill parameters.
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString What() const
A composite of Problem() and Where()
A color representation with 4 components: red, green, blue, alpha.
A logical library item identifier and consists of various portions much like a URI.
int Parse(const UTF8 &aId, bool aFix=false)
Parse LIB_ID with the information from aId.
Define a library symbol object.
wxString GetName() const override
void RunOnChildren(const std::function< void(SCH_ITEM *)> &aFunction, RECURSE_MODE aMode) override
EMBEDDED_FILES * GetEmbeddedFiles() override
An abstract class from which implementation specific LINE_READERs may be derived to read single lines...
Describe the page size and margins of a paper page on which to eventually print or plot.
void SetPortrait(bool aIsPortrait)
Rotate the paper page 90 degrees.
bool SetType(PAGE_SIZE_TYPE aPageSize, bool aIsPortrait=false)
Set the name of the page type and also the sizes and margins commonly associated with that type name.
void SetWidthMM(double aWidthInMM)
void SetHeightMM(double aHeightInMM)
const PAGE_SIZE_TYPE & GetType() const
A progress reporter interface for use in multi-threaded environments.
A REFERENCE_IMAGE is a wrapper around a BITMAP_IMAGE that is displayed in an editor as a reference fo...
bool ReadImageFile(const wxString &aFullFilename)
Read and store an image file.
const BITMAP_BASE & GetImage() const
Get the underlying image.
double GetImageScale() const
void SetImageScale(double aScale)
Set the image "zoom" value.
Holds all the data relating to one schematic.
EMBEDDED_FILES * GetEmbeddedFiles() override
Object to handle a bitmap image that can be inserted in a schematic.
Class for a wire to bus entry.
void SetPinLength(int aLength)
virtual const wxString & GetText() const override
Return the string associated with the text object.
wxString GetCanonicalName() const
Get a non-language-specific name for a field which can be used for storage, variable look-up,...
wxString GetName(bool aUseDefaultName=true) const
Return the field name (not translated).
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this label.
A set of SCH_ITEMs (i.e., without duplicates).
SCH_ITEM * ParseSymbolDrawItem()
SCH_SHAPE * parseSymbolPolyLine()
SCH_TABLE * parseSchTable()
bool m_appending
Appending load status.
unsigned m_lastProgressLine
SCH_FIELD * parseSchField(SCH_ITEM *aParent)
SCH_SHAPE * parseSchCircle()
SCH_TEXT * parseSchText()
SCH_TABLECELL * parseSchTableCell()
void parseSchSymbolInstances(SCH_SCREEN *aScreen)
void parsePinNumbers(std::unique_ptr< LIB_SYMBOL > &aSymbol)
LIB_SYMBOL * parseLibSymbol(LIB_SYMBOL_MAP &aSymbolLibMap)
SCH_RULE_AREA * parseSchRuleArea()
SCH_ITEM * parseSymbolText()
PROGRESS_REPORTER * m_progressReporter
void parseFill(FILL_PARAMS &aFill)
SCH_TEXTBOX * parseSymbolTextBox()
void parseBusAlias(SCH_SCREEN *aScreen)
void parseTITLE_BLOCK(TITLE_BLOCK &aTitleBlock)
void parseGroupMembers(GROUP_INFO &aGroupInfo)
void parseStroke(STROKE_PARAMS &aStroke)
Parse stroke definition aStroke.
int m_unit
The current unit being parsed.
SCH_SHAPE * parseSymbolBezier()
void parseEDA_TEXT(EDA_TEXT *aText, bool aConvertOverbarSyntax, bool aEnforceMinTextSize=true)
SCH_TEXTBOX * parseSchTextBox()
void resolveGroups(SCH_SCREEN *aParent)
SCH_SHEET * m_rootSheet
The rootsheet for full project loads or null for importing a schematic.
SCH_SHAPE * parseSchArc()
SCH_SHAPE * parseSchPolyLine()
SCH_BITMAP * parseImage()
SCH_SHAPE * parseSymbolCircle()
wxString m_generatorVersion
void ParseLib(LIB_SYMBOL_MAP &aSymbolLibMap)
SCH_PIN * parseSymbolPin()
std::vector< GROUP_INFO > m_groupInfos
void parseHeader(TSCHEMATIC_T::T aHeaderType, int aFileVersion)
void parseBodyStyles(std::unique_ptr< LIB_SYMBOL > &aSymbol)
void parseMargins(int &aLeft, int &aTop, int &aRight, int &aBottom)
wxString m_symbolName
The current symbol name.
VECTOR2I parseXY(bool aInvertY=false)
SCH_SHAPE * parseSymbolRectangle()
void parsePinNames(std::unique_ptr< LIB_SYMBOL > &aSymbol)
SCH_SHAPE * parseSchBezier()
std::vector< wxString > m_parseWarnings
Non-fatal warnings collected during parsing.
SCH_JUNCTION * parseJunction()
void ParseSchematic(SCH_SHEET *aSheet, bool aIsCopyablyOnly=false, int aFileVersion=SEXPR_SCHEMATIC_FILE_VERSION)
Parse the internal LINE_READER object into aSheet.
SCH_SHEET_PIN * parseSchSheetPin(SCH_SHEET *aSheet)
int m_bodyStyle
The current body style being parsed.
SCH_NO_CONNECT * parseNoConnect()
SCH_SHAPE * parseSymbolArc()
SCH_BUS_WIRE_ENTRY * parseBusEntry()
SCH_SHAPE * parseSchRectangle()
SCH_FIELD * parseProperty(std::unique_ptr< LIB_SYMBOL > &aSymbol)
SCH_SYMBOL * parseSchematicSymbol()
void parseSchTextBoxContent(SCH_TEXTBOX *aTextBox)
bool parseMaybeAbsentBool(bool aDefaultValue)
Parses a boolean flag inside a list that existed before boolean normalization.
void parsePAGE_INFO(PAGE_INFO &aPageInfo)
int m_requiredVersion
Set to the symbol library file version required.
int m_maxError
Max deviation allowed when approximating bezier curves.
const LINE_READER * m_lineReader
LIB_SYMBOL * ParseSymbol(LIB_SYMBOL_MAP &aSymbolLibMap, int aFileVersion=SEXPR_SYMBOL_LIB_FILE_VERSION)
Parse internal LINE_READER object into symbols and return all found.
void skipToBlockEnd(int aDepth=1)
Skip tokens until we reach the end of the current S-expression block.
void parseSchSheetInstances(SCH_SHEET *aRootSheet, SCH_SCREEN *aScreen)
SCH_IO_KICAD_SEXPR_PARSER(LINE_READER *aLineReader=nullptr, PROGRESS_REPORTER *aProgressReporter=nullptr, unsigned aLineCount=0, SCH_SHEET *aRootSheet=nullptr, bool aIsAppending=false)
Base class for any item which can be embedded within the SCHEMATIC container class,...
void SetFieldsAutoplaced(AUTOPLACE_ALGO aAlgo)
void SetShape(LABEL_FLAG_SHAPE aShape)
std::vector< SCH_FIELD > & GetFields()
Segment description base class to describe items which have 2 end points (track, wire,...
void SetStartPoint(const VECTOR2I &aPosition)
virtual void SetStroke(const STROKE_PARAMS &aStroke) override
void SetEndPoint(const VECTOR2I &aPosition)
void SetFileFormatVersionAtLoad(int aVersion)
std::vector< SCH_SHEET_INSTANCE > m_sheetInstances
void SetTitleBlock(const TITLE_BLOCK &aTitleBlock)
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
void AddLibSymbol(LIB_SYMBOL *aLibSymbol)
Add aLibSymbol to the library symbol map.
void AddBusAlias(std::shared_ptr< BUS_ALIAS > aAlias)
Add a bus alias definition.
void SetPageSettings(const PAGE_INFO &aPageSettings)
EE_RTREE & Items()
Get the full RTree, usually for iterating.
const KIID & GetUuid() const
void UpdateLocalLibSymbolLinks()
Initialize the LIB_SYMBOL reference for each SCH_SYMBOL found in this schematic with the local projec...
void SetLegacySymbolInstanceData()
Update the symbol value and footprint instance data for legacy designs.
SCHEMATIC * Schematic() const
void FixupEmbeddedData()
After loading a file from disk, the library symbols do not yet contain the full data for their embedd...
int GetFileFormatVersionAtLoad() const
wxString GroupsSanityCheck(bool repair=false)
Consistency check of internal m_groups structure.
KIID m_uuid
A unique identifier for each schematic file.
std::vector< SCH_SYMBOL_INSTANCE > m_symbolInstances
The list of symbol instances loaded from the schematic file.
void SetPosition(const VECTOR2I &aPos) override
void SetStroke(const STROKE_PARAMS &aStroke) override
STROKE_PARAMS GetStroke() const override
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
void SetPageNumber(const wxString &aPageNumber)
Set the sheet instance user definable page number.
void push_back(SCH_SHEET *aSheet)
Forwarded method from std::vector.
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Variant information for a schematic sheet.
void InitializeAttributes(const SCH_SHEET &aSheet)
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
SCH_SCREEN * GetScreen() const
Variant information for a schematic symbol.
void InitializeAttributes(const SCH_SYMBOL &aSymbol)
void SetMarginBottom(int aBottom)
int GetLegacyTextMargin() const
void SetMarginLeft(int aLeft)
void SetMarginRight(int aRight)
void SetExcludedFromSim(bool aExclude, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
void SetMarginTop(int aTop)
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
Represent a set of closed polygons.
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
void ParseStroke(STROKE_PARAMS &aStroke)
Simple container to manage line stroke parameters.
void SetLineStyle(LINE_STYLE aLineStyle)
LINE_STYLE GetLineStyle() const
KIGFX::COLOR4D GetColor() const
Hold the information shown in the lower right corner of a plot, printout, or editing view.
void SetRevision(const wxString &aRevision)
void SetComment(int aIdx, const wxString &aComment)
void SetTitle(const wxString &aTitle)
void SetCompany(const wxString &aCompany)
void SetDate(const wxString &aDate)
Set the date field, and defaults to the current time and date.
std::map< wxString, wxString > m_Fields
bool m_ExcludedFromPosFiles
#define DEFAULT_LINE_WIDTH_MILS
The default wire width in mils. (can be changed in preference menu)
static constexpr EDA_ANGLE ANGLE_0
static constexpr EDA_ANGLE ANGLE_90
static constexpr EDA_ANGLE ANGLE_360
static constexpr EDA_ANGLE ANGLE_180
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
@ FILLED_WITH_BG_BODYCOLOR
@ FILLED_SHAPE
Fill with object color.
FONTCONFIG * Fontconfig()
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
#define THROW_PARSE_ERROR(aProblem, aSource, aInputLine, aLineNumber, aByteIndex)
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
#define MAX_PAGE_SIZE_EESCHEMA_MM
#define MIN_PAGE_SIZE_MM
Min and max page sizes for clamping, in mm.
PGM_BASE & Pgm()
The global program "get" accessor.
ELECTRICAL_PINTYPE
The symbol library pin object electrical types used in ERC tests.
@ PT_INPUT
usual pin input: must be connected
@ PT_NC
not connected (must be left open)
@ PT_TRISTATE
tri state bus pin
@ PT_NIC
not internally connected (may be connected to anything)
@ PT_BIDI
input or output (like port for a microprocessor)
@ PT_OPENEMITTER
pin type open emitter
@ PT_POWER_OUT
output of a regulator: intended to be connected to power input pins
@ PT_OPENCOLLECTOR
pin type open collector
@ PT_POWER_IN
power input (GND, VCC for ICs). Must be connected to a power output.
@ PT_UNSPECIFIED
unknown electrical properties: creates always a warning when connected
@ PT_PASSIVE
pin for passive symbols: must be connected, and can be connected to any pin.
@ PIN_UP
The pin extends upwards from the connection point: Probably on the bottom side of the symbol.
@ PIN_RIGHT
The pin extends rightwards from the connection point.
@ PIN_LEFT
The pin extends leftwards from the connection point: Probably on the right side of the symbol.
@ PIN_DOWN
The pin extends downwards from the connection: Probably on the top side of the symbol.
const SCH_FIELD * FindField(const std::vector< SCH_FIELD > &aFields, FIELD_T aFieldId)
#define SEXPR_SYMBOL_LIB_FILE_VERSION
This file contains the file format version information for the s-expression schematic and symbol libr...
#define SEXPR_SCHEMATIC_FILE_VERSION
Schematic file version.
Class to handle a set of SCH_ITEMs.
double parseDouble(LINE_READER &aReader, const char *aLine, const char **aOutput)
Parses an ASCII point string with possible leading whitespace into a double precision floating point ...
void fixupSchFillMode(SCH_SHAPE *aShape)
#define SIM_LEGACY_ENABLE_FIELD
#define SIM_LEGACY_ENABLE_FIELD_V7
wxString ConvertToNewOverbarNotation(const wxString &aOldStr)
Convert the old ~...~ overbar notation to the new ~{...} one.
wxString UnescapeString(const wxString &aSource)
A filename or source description, a problem input line, a line number, a byte offset,...
std::vector< KIID > memberUuids
ELECTRICAL_PINTYPE m_Type
A simple container for sheet instance information.
std::map< wxString, SCH_SHEET_VARIANT > m_Variants
A list of sheet variants.
A simple container for schematic symbol instance information.
std::map< wxString, SCH_SYMBOL_VARIANT > m_Variants
A list of symbol variants.
std::map< wxString, LIB_SYMBOL *, LibSymbolMapSort > LIB_SYMBOL_MAP
FIELD_T
The set of all field indices assuming an array like sequence that a SCH_COMPONENT or LIB_PART can hol...
@ USER
The field ID hasn't been set yet; field is invalid.
@ INTERSHEET_REFS
Global label cross-reference page numbers.
@ REFERENCE
Field Reference of part, i.e. "IC21".
@ VALUE
Field Value of part, i.e. "3.3K".
#define SHEET_MANDATORY_FIELDS
#define GLOBALLABEL_MANDATORY_FIELDS
wxString GetCanonicalFieldName(FIELD_T aFieldType)
KIBIS top(path, &reporter)
SHAPE_CIRCLE circle(c.m_circle_center, c.m_circle_radius)
static constexpr double IU_PER_MM
Mock up a conversion function.
const VECTOR2I CalcArcCenter(const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd)
Determine the center of an arc or circle given three points on its circumference.
VECTOR2< int32_t > VECTOR2I