357 lines
13 KiB
C++
357 lines
13 KiB
C++
/*
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
*
|
|
* Copyright (C) 2022 KiCad Developers, see AUTHORS.txt for contributors.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the
|
|
* Free Software Foundation, either version 3 of the License, or (at your
|
|
* option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <advanced_config.h>
|
|
#include <base_units.h>
|
|
#include <macros.h>
|
|
#include <schematic_lexer.h>
|
|
#include "sch_sexpr_plugin_common.h"
|
|
#include <string_utils.h>
|
|
|
|
|
|
using namespace TSCHEMATIC_T;
|
|
|
|
|
|
static const char* emptyString = "";
|
|
|
|
|
|
void formatFill( OUTPUTFORMATTER* aFormatter, int aNestLevel, FILL_T aFillMode,
|
|
const COLOR4D& aFillColor )
|
|
{
|
|
const char* fillType;
|
|
|
|
switch( aFillMode )
|
|
{
|
|
default:
|
|
case FILL_T::NO_FILL: fillType = "none"; break;
|
|
case FILL_T::FILLED_SHAPE: fillType = "outline"; break;
|
|
case FILL_T::FILLED_WITH_BG_BODYCOLOR: fillType = "background"; break;
|
|
case FILL_T::FILLED_WITH_COLOR: fillType = "color"; break;
|
|
}
|
|
|
|
if( aFillMode == FILL_T::FILLED_WITH_COLOR )
|
|
{
|
|
aFormatter->Print( aNestLevel, "(fill (type %s) (color %d %d %d %s))",
|
|
fillType,
|
|
KiROUND( aFillColor.r * 255.0 ),
|
|
KiROUND( aFillColor.g * 255.0 ),
|
|
KiROUND( aFillColor.b * 255.0 ),
|
|
FormatDouble2Str( aFillColor.a ).c_str() );
|
|
}
|
|
else
|
|
{
|
|
aFormatter->Print( aNestLevel, "(fill (type %s))",
|
|
fillType );
|
|
}
|
|
}
|
|
|
|
|
|
const char* getPinElectricalTypeToken( ELECTRICAL_PINTYPE aType )
|
|
{
|
|
switch( aType )
|
|
{
|
|
case ELECTRICAL_PINTYPE::PT_INPUT:
|
|
return SCHEMATIC_LEXER::TokenName( T_input );
|
|
|
|
case ELECTRICAL_PINTYPE::PT_OUTPUT:
|
|
return SCHEMATIC_LEXER::TokenName( T_output );
|
|
|
|
case ELECTRICAL_PINTYPE::PT_BIDI:
|
|
return SCHEMATIC_LEXER::TokenName( T_bidirectional );
|
|
|
|
case ELECTRICAL_PINTYPE::PT_TRISTATE:
|
|
return SCHEMATIC_LEXER::TokenName( T_tri_state );
|
|
|
|
case ELECTRICAL_PINTYPE::PT_PASSIVE:
|
|
return SCHEMATIC_LEXER::TokenName( T_passive );
|
|
|
|
case ELECTRICAL_PINTYPE::PT_NIC:
|
|
return SCHEMATIC_LEXER::TokenName( T_free );
|
|
|
|
case ELECTRICAL_PINTYPE::PT_UNSPECIFIED:
|
|
return SCHEMATIC_LEXER::TokenName( T_unspecified );
|
|
|
|
case ELECTRICAL_PINTYPE::PT_POWER_IN:
|
|
return SCHEMATIC_LEXER::TokenName( T_power_in );
|
|
|
|
case ELECTRICAL_PINTYPE::PT_POWER_OUT:
|
|
return SCHEMATIC_LEXER::TokenName( T_power_out );
|
|
|
|
case ELECTRICAL_PINTYPE::PT_OPENCOLLECTOR:
|
|
return SCHEMATIC_LEXER::TokenName( T_open_collector );
|
|
|
|
case ELECTRICAL_PINTYPE::PT_OPENEMITTER:
|
|
return SCHEMATIC_LEXER::TokenName( T_open_emitter );
|
|
|
|
case ELECTRICAL_PINTYPE::PT_NC:
|
|
return SCHEMATIC_LEXER::TokenName( T_no_connect );
|
|
|
|
default:
|
|
wxFAIL_MSG( "Missing symbol library pin connection type" );
|
|
}
|
|
|
|
return emptyString;
|
|
}
|
|
|
|
|
|
const char* getPinShapeToken( GRAPHIC_PINSHAPE aShape )
|
|
{
|
|
switch( aShape )
|
|
{
|
|
case GRAPHIC_PINSHAPE::LINE:
|
|
return SCHEMATIC_LEXER::TokenName( T_line );
|
|
|
|
case GRAPHIC_PINSHAPE::INVERTED:
|
|
return SCHEMATIC_LEXER::TokenName( T_inverted );
|
|
|
|
case GRAPHIC_PINSHAPE::CLOCK:
|
|
return SCHEMATIC_LEXER::TokenName( T_clock );
|
|
|
|
case GRAPHIC_PINSHAPE::INVERTED_CLOCK:
|
|
return SCHEMATIC_LEXER::TokenName( T_inverted_clock );
|
|
|
|
case GRAPHIC_PINSHAPE::INPUT_LOW:
|
|
return SCHEMATIC_LEXER::TokenName( T_input_low );
|
|
|
|
case GRAPHIC_PINSHAPE::CLOCK_LOW:
|
|
return SCHEMATIC_LEXER::TokenName( T_clock_low );
|
|
|
|
case GRAPHIC_PINSHAPE::OUTPUT_LOW:
|
|
return SCHEMATIC_LEXER::TokenName( T_output_low );
|
|
|
|
case GRAPHIC_PINSHAPE::FALLING_EDGE_CLOCK:
|
|
return SCHEMATIC_LEXER::TokenName( T_edge_clock_high );
|
|
|
|
case GRAPHIC_PINSHAPE::NONLOGIC:
|
|
return SCHEMATIC_LEXER::TokenName( T_non_logic );
|
|
|
|
default:
|
|
wxFAIL_MSG( "Missing symbol library pin shape type" );
|
|
}
|
|
|
|
return emptyString;
|
|
}
|
|
|
|
|
|
EDA_ANGLE getPinAngle( int aOrientation )
|
|
{
|
|
switch( aOrientation )
|
|
{
|
|
case PIN_RIGHT: return ANGLE_0;
|
|
case PIN_LEFT: return ANGLE_180;
|
|
case PIN_UP: return ANGLE_90;
|
|
case PIN_DOWN: return ANGLE_270;
|
|
default: wxFAIL_MSG( "Missing symbol library pin orientation type" ); return ANGLE_0;
|
|
}
|
|
}
|
|
|
|
|
|
const char* getSheetPinShapeToken( LABEL_FLAG_SHAPE aShape )
|
|
{
|
|
switch( aShape )
|
|
{
|
|
case LABEL_FLAG_SHAPE::L_INPUT: return SCHEMATIC_LEXER::TokenName( T_input );
|
|
case LABEL_FLAG_SHAPE::L_OUTPUT: return SCHEMATIC_LEXER::TokenName( T_output );
|
|
case LABEL_FLAG_SHAPE::L_BIDI: return SCHEMATIC_LEXER::TokenName( T_bidirectional );
|
|
case LABEL_FLAG_SHAPE::L_TRISTATE: return SCHEMATIC_LEXER::TokenName( T_tri_state );
|
|
case LABEL_FLAG_SHAPE::L_UNSPECIFIED: return SCHEMATIC_LEXER::TokenName( T_passive );
|
|
case LABEL_FLAG_SHAPE::F_DOT: return SCHEMATIC_LEXER::TokenName( T_dot );
|
|
case LABEL_FLAG_SHAPE::F_ROUND: return SCHEMATIC_LEXER::TokenName( T_round );
|
|
case LABEL_FLAG_SHAPE::F_DIAMOND: return SCHEMATIC_LEXER::TokenName( T_diamond );
|
|
case LABEL_FLAG_SHAPE::F_RECTANGLE: return SCHEMATIC_LEXER::TokenName( T_rectangle );
|
|
default: wxFAIL; return SCHEMATIC_LEXER::TokenName( T_passive );
|
|
}
|
|
}
|
|
|
|
|
|
EDA_ANGLE getSheetPinAngle( SHEET_SIDE aSide )
|
|
{
|
|
switch( aSide )
|
|
{
|
|
case SHEET_SIDE::UNDEFINED:
|
|
case SHEET_SIDE::LEFT: return ANGLE_180;
|
|
case SHEET_SIDE::RIGHT: return ANGLE_0;
|
|
case SHEET_SIDE::TOP: return ANGLE_90;
|
|
case SHEET_SIDE::BOTTOM: return ANGLE_270;
|
|
default: wxFAIL; return ANGLE_0;
|
|
}
|
|
}
|
|
|
|
|
|
const char* getTextTypeToken( KICAD_T aType )
|
|
{
|
|
switch( aType )
|
|
{
|
|
case SCH_TEXT_T: return SCHEMATIC_LEXER::TokenName( T_text );
|
|
case SCH_LABEL_T: return SCHEMATIC_LEXER::TokenName( T_label );
|
|
case SCH_GLOBAL_LABEL_T: return SCHEMATIC_LEXER::TokenName( T_global_label );
|
|
case SCH_HIER_LABEL_T: return SCHEMATIC_LEXER::TokenName( T_hierarchical_label );
|
|
case SCH_DIRECTIVE_LABEL_T: return SCHEMATIC_LEXER::TokenName( T_netclass_flag );
|
|
default: wxFAIL; return SCHEMATIC_LEXER::TokenName( T_text );
|
|
}
|
|
}
|
|
|
|
|
|
void formatArc( OUTPUTFORMATTER* aFormatter, int aNestLevel, EDA_SHAPE* aArc,
|
|
bool aIsPrivate, const STROKE_PARAMS& aStroke, FILL_T aFillMode,
|
|
const COLOR4D& aFillColor, const KIID& aUuid )
|
|
{
|
|
aFormatter->Print( aNestLevel, "(arc%s (start %s) (mid %s) (end %s)\n",
|
|
aIsPrivate ? " private" : "",
|
|
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, aArc->GetStart() ).c_str(),
|
|
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, aArc->GetArcMid() ).c_str(),
|
|
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, aArc->GetEnd() ).c_str() );
|
|
|
|
aStroke.Format( aFormatter, schIUScale, aNestLevel + 1 );
|
|
aFormatter->Print( 0, "\n" );
|
|
formatFill( aFormatter, aNestLevel + 1, aFillMode, aFillColor );
|
|
aFormatter->Print( 0, "\n" );
|
|
|
|
if( aUuid != niluuid )
|
|
aFormatter->Print( aNestLevel + 1, "(uuid %s)\n", TO_UTF8( aUuid.AsString() ) );
|
|
|
|
aFormatter->Print( aNestLevel, ")\n" );
|
|
}
|
|
|
|
|
|
void formatCircle( OUTPUTFORMATTER* aFormatter, int aNestLevel, EDA_SHAPE* aCircle,
|
|
bool aIsPrivate, const STROKE_PARAMS& aStroke, FILL_T aFillMode,
|
|
const COLOR4D& aFillColor, const KIID& aUuid )
|
|
{
|
|
aFormatter->Print( aNestLevel, "(circle%s (center %s %s) (radius %s)\n",
|
|
aIsPrivate ? " private" : "",
|
|
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, aCircle->GetStart().x ).c_str(),
|
|
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, aCircle->GetStart().y ).c_str(),
|
|
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, aCircle->GetRadius() ).c_str() );
|
|
|
|
aStroke.Format( aFormatter, schIUScale, aNestLevel + 1 );
|
|
aFormatter->Print( 0, "\n" );
|
|
formatFill( aFormatter, aNestLevel + 1, aFillMode, aFillColor );
|
|
aFormatter->Print( 0, "\n" );
|
|
|
|
if( aUuid != niluuid )
|
|
aFormatter->Print( aNestLevel + 1, "(uuid %s)\n", TO_UTF8( aUuid.AsString() ) );
|
|
|
|
aFormatter->Print( aNestLevel, ")\n" );
|
|
}
|
|
|
|
|
|
void formatRect( OUTPUTFORMATTER* aFormatter, int aNestLevel, EDA_SHAPE* aRect,
|
|
bool aIsPrivate, const STROKE_PARAMS& aStroke, FILL_T aFillMode,
|
|
const COLOR4D& aFillColor, const KIID& aUuid )
|
|
{
|
|
aFormatter->Print( aNestLevel, "(rectangle%s (start %s %s) (end %s %s)\n",
|
|
aIsPrivate ? " private" : "",
|
|
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, aRect->GetStart().x ).c_str(),
|
|
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, aRect->GetStart().y ).c_str(),
|
|
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, aRect->GetEnd().x ).c_str(),
|
|
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, aRect->GetEnd().y ).c_str() );
|
|
aStroke.Format( aFormatter, schIUScale, aNestLevel + 1 );
|
|
aFormatter->Print( 0, "\n" );
|
|
formatFill( aFormatter, aNestLevel + 1, aFillMode, aFillColor );
|
|
aFormatter->Print( 0, "\n" );
|
|
|
|
if( aUuid != niluuid )
|
|
aFormatter->Print( aNestLevel + 1, "(uuid %s)\n", TO_UTF8( aUuid.AsString() ) );
|
|
|
|
aFormatter->Print( aNestLevel, ")\n" );
|
|
}
|
|
|
|
|
|
void formatBezier( OUTPUTFORMATTER* aFormatter, int aNestLevel, EDA_SHAPE* aBezier,
|
|
bool aIsPrivate, const STROKE_PARAMS& aStroke, FILL_T aFillMode,
|
|
const COLOR4D& aFillColor, const KIID& aUuid )
|
|
{
|
|
aFormatter->Print( aNestLevel, "(bezier%s (pts ",
|
|
aIsPrivate ? " private" : "" );
|
|
|
|
for( const VECTOR2I& pt : { aBezier->GetStart(), aBezier->GetBezierC1(),
|
|
aBezier->GetBezierC2(), aBezier->GetEnd() } )
|
|
{
|
|
aFormatter->Print( 0, " (xy %s %s)",
|
|
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, pt.x ).c_str(),
|
|
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, pt.y ).c_str() );
|
|
}
|
|
|
|
aFormatter->Print( 0, ")\n" ); // Closes pts token on same line.
|
|
|
|
aStroke.Format( aFormatter, schIUScale, aNestLevel + 1 );
|
|
aFormatter->Print( 0, "\n" );
|
|
formatFill( aFormatter, aNestLevel + 1, aFillMode, aFillColor );
|
|
aFormatter->Print( 0, "\n" );
|
|
|
|
if( aUuid != niluuid )
|
|
aFormatter->Print( aNestLevel + 1, "(uuid %s)\n", TO_UTF8( aUuid.AsString() ) );
|
|
|
|
aFormatter->Print( aNestLevel, ")\n" );
|
|
}
|
|
|
|
|
|
void formatPoly( OUTPUTFORMATTER* aFormatter, int aNestLevel, EDA_SHAPE* aPolyLine,
|
|
bool aIsPrivate, const STROKE_PARAMS& aStroke, FILL_T aFillMode,
|
|
const COLOR4D& aFillColor, const KIID& aUuid )
|
|
{
|
|
int newLine = 0;
|
|
int lineCount = 1;
|
|
aFormatter->Print( aNestLevel, "(polyline%s\n",
|
|
aIsPrivate ? " private" : "" );
|
|
aFormatter->Print( aNestLevel + 1, "(pts" );
|
|
|
|
for( const VECTOR2I& pt : aPolyLine->GetPolyShape().Outline( 0 ).CPoints() )
|
|
{
|
|
if( newLine == 4 || !ADVANCED_CFG::GetCfg().m_CompactSave )
|
|
{
|
|
aFormatter->Print( 0, "\n" );
|
|
aFormatter->Print( aNestLevel + 2, "(xy %s %s)",
|
|
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, pt.x ).c_str(),
|
|
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, pt.y ).c_str() );
|
|
newLine = 0;
|
|
lineCount += 1;
|
|
}
|
|
else
|
|
{
|
|
aFormatter->Print( 0, " (xy %s %s)",
|
|
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, pt.x ).c_str(),
|
|
EDA_UNIT_UTILS::FormatInternalUnits( schIUScale, pt.y ).c_str() );
|
|
}
|
|
|
|
newLine += 1;
|
|
}
|
|
|
|
if( lineCount == 1 )
|
|
{
|
|
aFormatter->Print( 0, ")\n" ); // Closes pts token on same line.
|
|
}
|
|
else
|
|
{
|
|
aFormatter->Print( 0, "\n" );
|
|
aFormatter->Print( aNestLevel + 1, ")\n" ); // Closes pts token with multiple lines.
|
|
}
|
|
|
|
aStroke.Format( aFormatter, schIUScale, aNestLevel + 1 );
|
|
aFormatter->Print( 0, "\n" );
|
|
formatFill( aFormatter, aNestLevel + 1, aFillMode, aFillColor );
|
|
aFormatter->Print( 0, "\n" );
|
|
|
|
if( aUuid != niluuid )
|
|
aFormatter->Print( aNestLevel + 1, "(uuid %s)\n", TO_UTF8( aUuid.AsString() ) );
|
|
|
|
aFormatter->Print( aNestLevel, ")\n" );
|
|
}
|