2023-09-06 11:58:39 +00:00
|
|
|
/*
|
|
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2023 Alex Shvartzkop <dudesuchamazing@gmail.com>
|
|
|
|
* Copyright (C) 2023 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 2
|
|
|
|
* 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, you may find one here:
|
|
|
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
|
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
|
|
|
* or you may write to the Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "sch_easyedapro_parser.h"
|
2023-12-19 17:39:26 +00:00
|
|
|
#include <io/easyedapro/easyedapro_import_utils.h>
|
2023-09-06 11:58:39 +00:00
|
|
|
|
2023-10-30 08:34:42 +00:00
|
|
|
#include <core/map_helpers.h>
|
|
|
|
|
2023-12-19 17:39:26 +00:00
|
|
|
#include <sch_io/sch_io_mgr.h>
|
2023-09-06 11:58:39 +00:00
|
|
|
#include <schematic.h>
|
|
|
|
#include <sch_sheet.h>
|
|
|
|
#include <sch_sheet_pin.h>
|
|
|
|
#include <sch_line.h>
|
|
|
|
#include <sch_bitmap.h>
|
|
|
|
#include <lib_shape.h>
|
|
|
|
#include <lib_text.h>
|
|
|
|
#include <sch_no_connect.h>
|
|
|
|
#include <sch_label.h>
|
|
|
|
#include <sch_junction.h>
|
|
|
|
#include <sch_edit_frame.h>
|
|
|
|
#include <sch_shape.h>
|
|
|
|
#include <sch_bus_entry.h>
|
|
|
|
#include <string_utils.h>
|
|
|
|
#include <bezier_curves.h>
|
2023-09-26 00:40:15 +00:00
|
|
|
#include <wx/base64.h>
|
2023-09-06 11:58:39 +00:00
|
|
|
#include <wx/url.h>
|
|
|
|
#include <wx/mstream.h>
|
|
|
|
#include <gfx_import_utils.h>
|
|
|
|
#include <import_gfx/svg_import_plugin.h>
|
|
|
|
#include <import_gfx/graphics_importer_lib_symbol.h>
|
2023-10-30 08:34:42 +00:00
|
|
|
#include <import_gfx/graphics_importer_sch.h>
|
2023-09-06 11:58:39 +00:00
|
|
|
|
|
|
|
|
|
|
|
SCH_EASYEDAPRO_PARSER::SCH_EASYEDAPRO_PARSER( SCHEMATIC* aSchematic,
|
|
|
|
PROGRESS_REPORTER* aProgressReporter )
|
|
|
|
{
|
|
|
|
m_schematic = aSchematic;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
SCH_EASYEDAPRO_PARSER::~SCH_EASYEDAPRO_PARSER()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
double SCH_EASYEDAPRO_PARSER::Convert( wxString aValue )
|
|
|
|
{
|
|
|
|
double value = 0;
|
|
|
|
|
|
|
|
if( !aValue.ToCDouble( &value ) )
|
|
|
|
THROW_IO_ERROR( wxString::Format( _( "Failed to parse value: '%s'" ), aValue ) );
|
|
|
|
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
double SCH_EASYEDAPRO_PARSER::SizeToKi( wxString aValue )
|
|
|
|
{
|
|
|
|
return ScaleSize( Convert( aValue ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-11-25 13:05:45 +00:00
|
|
|
static LINE_STYLE ConvertStrokeStyle( int aStyle )
|
2023-09-06 11:58:39 +00:00
|
|
|
{
|
|
|
|
if( aStyle == 0 )
|
2023-11-25 13:05:45 +00:00
|
|
|
return LINE_STYLE::SOLID;
|
2023-09-06 11:58:39 +00:00
|
|
|
else if( aStyle == 1 )
|
2023-11-25 13:05:45 +00:00
|
|
|
return LINE_STYLE::DASH;
|
2023-09-06 11:58:39 +00:00
|
|
|
else if( aStyle == 2 )
|
2023-11-25 13:05:45 +00:00
|
|
|
return LINE_STYLE::DOT;
|
2023-09-06 11:58:39 +00:00
|
|
|
else if( aStyle == 3 )
|
2023-11-25 13:05:45 +00:00
|
|
|
return LINE_STYLE::DASHDOT;
|
2023-09-06 11:58:39 +00:00
|
|
|
|
2023-11-25 13:05:45 +00:00
|
|
|
return LINE_STYLE::DEFAULT;
|
2023-09-06 11:58:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void SCH_EASYEDAPRO_PARSER::ApplyFontStyle( const std::map<wxString, nlohmann::json>& fontStyles,
|
|
|
|
T& text, const wxString& styleStr )
|
|
|
|
{
|
|
|
|
auto it = fontStyles.find( styleStr );
|
|
|
|
|
|
|
|
if( it == fontStyles.end() )
|
|
|
|
return;
|
|
|
|
|
|
|
|
nlohmann::json style = it->second;
|
|
|
|
|
|
|
|
if( !style.is_array() )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if( style.size() < 12 )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if( style.at( 3 ).is_string() )
|
|
|
|
{
|
|
|
|
COLOR4D color( style.at( 3 ).get<wxString>() );
|
|
|
|
text->SetTextColor( color );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( style.at( 4 ).is_string() )
|
|
|
|
{
|
|
|
|
wxString fontname = ( style.at( 4 ) );
|
|
|
|
|
|
|
|
if( !fontname.IsSameAs( wxS( "default" ), false ) )
|
|
|
|
text->SetFont( KIFONT::FONT::GetFont( fontname ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( style.at( 5 ).is_number() )
|
|
|
|
{
|
|
|
|
double size = style.at( 5 ).get<double>() * 0.5;
|
|
|
|
text->SetTextSize( VECTOR2I( ScaleSize( size ), ScaleSize( size ) ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( style.at( 10 ).is_number() )
|
|
|
|
{
|
|
|
|
int valign = style.at( 10 );
|
|
|
|
|
|
|
|
if( !text->GetText().Contains( wxS( "\n" ) ) )
|
|
|
|
{
|
|
|
|
if( valign == 0 )
|
|
|
|
text->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
|
|
|
|
else if( valign == 1 )
|
|
|
|
text->SetVertJustify( GR_TEXT_V_ALIGN_CENTER );
|
|
|
|
else if( valign == 2 )
|
|
|
|
text->SetVertJustify( GR_TEXT_V_ALIGN_BOTTOM );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
text->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
|
|
|
|
// TODO: align by first line
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
text->SetVertJustify( GR_TEXT_V_ALIGN_BOTTOM );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( style.at( 11 ).is_number() )
|
|
|
|
{
|
|
|
|
int halign = style.at( 11 );
|
|
|
|
|
|
|
|
if( halign == 0 )
|
|
|
|
text->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
|
|
|
|
else if( halign == 1 )
|
|
|
|
text->SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
|
|
|
|
else if( halign == 2 )
|
|
|
|
text->SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
text->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void SCH_EASYEDAPRO_PARSER::ApplyLineStyle( const std::map<wxString, nlohmann::json>& lineStyles,
|
|
|
|
T& shape, const wxString& styleStr )
|
|
|
|
{
|
|
|
|
auto it = lineStyles.find( styleStr );
|
|
|
|
|
|
|
|
if( it == lineStyles.end() )
|
|
|
|
return;
|
|
|
|
|
|
|
|
nlohmann::json style = it->second;
|
|
|
|
|
|
|
|
if( !style.is_array() )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if( style.size() < 6 )
|
|
|
|
return;
|
|
|
|
|
|
|
|
STROKE_PARAMS stroke = shape->GetStroke();
|
|
|
|
|
|
|
|
if( style.at( 2 ).is_string() )
|
|
|
|
{
|
|
|
|
wxString colorStr = style.at( 2 ).get<wxString>();
|
|
|
|
|
|
|
|
if( !colorStr.empty() && colorStr.starts_with( wxS( "#" ) ) )
|
|
|
|
{
|
|
|
|
COLOR4D color( colorStr );
|
|
|
|
stroke.SetColor( color );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( style.at( 3 ).is_number() )
|
|
|
|
{
|
|
|
|
int dashStyle = style.at( 3 );
|
2023-11-25 13:05:45 +00:00
|
|
|
stroke.SetLineStyle( ConvertStrokeStyle( dashStyle ) );
|
2023-09-06 11:58:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if( style.at( 5 ).is_number() )
|
|
|
|
{
|
|
|
|
double thickness = style.at( 5 );
|
|
|
|
stroke.SetWidth( ScaleSize( thickness ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
shape->SetStroke( stroke );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-01-16 20:39:44 +00:00
|
|
|
wxString SCH_EASYEDAPRO_PARSER::ResolveFieldVariables(
|
|
|
|
const wxString aInput, const std::map<wxString, wxString>& aDeviceAttributes )
|
|
|
|
{
|
|
|
|
wxString inputText = aInput;
|
|
|
|
wxString resolvedText;
|
|
|
|
int variableCount = 0;
|
|
|
|
|
|
|
|
// Resolve variables
|
|
|
|
// ={Variable1}text{Variable2}
|
|
|
|
do
|
|
|
|
{
|
|
|
|
if( !inputText.StartsWith( wxS( "={" ) ) )
|
|
|
|
return inputText;
|
|
|
|
|
|
|
|
resolvedText.Clear();
|
|
|
|
variableCount = 0;
|
|
|
|
|
|
|
|
for( size_t i = 1; i < inputText.size(); )
|
|
|
|
{
|
|
|
|
wxUniChar c = inputText[i++];
|
|
|
|
|
|
|
|
if( c == '{' )
|
|
|
|
{
|
|
|
|
wxString varName;
|
|
|
|
bool endFound = false;
|
|
|
|
|
|
|
|
while( i < inputText.size() )
|
|
|
|
{
|
|
|
|
c = inputText[i++];
|
|
|
|
|
|
|
|
if( c == '}' )
|
|
|
|
{
|
|
|
|
endFound = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
varName << c;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( !endFound )
|
|
|
|
return inputText;
|
|
|
|
|
|
|
|
wxString varValue =
|
|
|
|
get_def( aDeviceAttributes, varName, wxString::Format( "{%s!}", varName ) );
|
|
|
|
|
|
|
|
resolvedText << varValue;
|
|
|
|
variableCount++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
resolvedText << c;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
inputText = resolvedText;
|
|
|
|
|
|
|
|
} while( variableCount > 0 );
|
|
|
|
|
|
|
|
return resolvedText;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-09-06 11:58:39 +00:00
|
|
|
template <typename T>
|
|
|
|
void SCH_EASYEDAPRO_PARSER::ApplyAttrToField( const std::map<wxString, nlohmann::json>& fontStyles,
|
|
|
|
T* field, const EASYEDAPRO::SCH_ATTR& aAttr,
|
2024-01-16 20:39:44 +00:00
|
|
|
bool aIsSym, bool aToSym,
|
|
|
|
const std::map<wxString, wxString>& aDeviceAttributes,
|
|
|
|
SCH_SYMBOL* aParent )
|
2023-09-06 11:58:39 +00:00
|
|
|
{
|
|
|
|
EDA_TEXT* text = static_cast<EDA_TEXT*>( field );
|
|
|
|
|
2024-01-16 20:39:44 +00:00
|
|
|
text->SetText( ResolveFieldVariables( aAttr.value, aDeviceAttributes ) );
|
2023-09-06 11:58:39 +00:00
|
|
|
text->SetVisible( aAttr.keyVisible || aAttr.valVisible );
|
|
|
|
|
|
|
|
field->SetNameShown( aAttr.keyVisible );
|
|
|
|
|
|
|
|
if( aAttr.position )
|
|
|
|
{
|
|
|
|
field->SetPosition( !aIsSym ? ScalePos( *aAttr.position )
|
|
|
|
: ScalePosSym( *aAttr.position ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
ApplyFontStyle( fontStyles, text, aAttr.fontStyle );
|
|
|
|
|
|
|
|
auto parent = aParent;
|
|
|
|
if( parent && parent->Type() == SCH_SYMBOL_T )
|
|
|
|
{
|
|
|
|
int orient = static_cast<SCH_SYMBOL*>( parent )->GetOrientation();
|
|
|
|
|
|
|
|
if( orient == SYM_ORIENT_180 )
|
|
|
|
{
|
|
|
|
text->SetVertJustify( static_cast<GR_TEXT_V_ALIGN_T>( -text->GetVertJustify() ) );
|
|
|
|
text->SetHorizJustify( static_cast<GR_TEXT_H_ALIGN_T>( -text->GetHorizJustify() ) );
|
|
|
|
}
|
|
|
|
else if( orient == SYM_MIRROR_X + SYM_ORIENT_0 )
|
|
|
|
{
|
|
|
|
text->SetVertJustify( static_cast<GR_TEXT_V_ALIGN_T>( -text->GetVertJustify() ) );
|
|
|
|
}
|
|
|
|
else if( orient == SYM_MIRROR_Y + SYM_ORIENT_0 )
|
|
|
|
{
|
|
|
|
text->SetHorizJustify( static_cast<GR_TEXT_H_ALIGN_T>( -text->GetHorizJustify() ) );
|
|
|
|
}
|
|
|
|
else if( orient == SYM_MIRROR_Y + SYM_ORIENT_180 )
|
|
|
|
{
|
|
|
|
text->SetHorizJustify( static_cast<GR_TEXT_H_ALIGN_T>( text->GetHorizJustify() ) );
|
|
|
|
}
|
|
|
|
else if( orient == SYM_ORIENT_90 )
|
|
|
|
{
|
|
|
|
text->SetTextAngle( ANGLE_VERTICAL );
|
|
|
|
text->SetVertJustify( static_cast<GR_TEXT_V_ALIGN_T>( -text->GetVertJustify() ) );
|
|
|
|
text->SetHorizJustify( static_cast<GR_TEXT_H_ALIGN_T>( -text->GetHorizJustify() ) );
|
|
|
|
}
|
|
|
|
if( orient == SYM_ORIENT_270 )
|
|
|
|
{
|
|
|
|
text->SetTextAngle( ANGLE_VERTICAL );
|
|
|
|
}
|
|
|
|
else if( orient == SYM_MIRROR_X + SYM_ORIENT_90 )
|
|
|
|
{
|
|
|
|
text->SetTextAngle( ANGLE_VERTICAL );
|
|
|
|
text->SetVertJustify( static_cast<GR_TEXT_V_ALIGN_T>( -text->GetVertJustify() ) );
|
|
|
|
text->SetHorizJustify( static_cast<GR_TEXT_H_ALIGN_T>( -text->GetHorizJustify() ) );
|
|
|
|
}
|
|
|
|
else if( orient == SYM_MIRROR_X + SYM_ORIENT_270 )
|
|
|
|
{
|
|
|
|
text->SetTextAngle( ANGLE_VERTICAL );
|
|
|
|
text->SetVertJustify( static_cast<GR_TEXT_V_ALIGN_T>( -text->GetVertJustify() ) );
|
|
|
|
}
|
|
|
|
else if( orient == SYM_MIRROR_Y + SYM_ORIENT_90 )
|
|
|
|
{
|
|
|
|
text->SetTextAngle( ANGLE_VERTICAL );
|
|
|
|
text->SetHorizJustify( static_cast<GR_TEXT_H_ALIGN_T>( -text->GetHorizJustify() ) );
|
|
|
|
}
|
|
|
|
else if( orient == SYM_MIRROR_Y + SYM_ORIENT_270 )
|
|
|
|
{
|
|
|
|
text->SetHorizJustify( static_cast<GR_TEXT_H_ALIGN_T>( text->GetHorizJustify() ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( aAttr.rotation == 90 )
|
|
|
|
{
|
|
|
|
if( text->GetTextAngle() == ANGLE_HORIZONTAL )
|
|
|
|
text->SetTextAngle( ANGLE_VERTICAL );
|
|
|
|
else
|
|
|
|
text->SetTextAngle( ANGLE_HORIZONTAL );
|
|
|
|
|
|
|
|
if( orient == SYM_ORIENT_90 )
|
|
|
|
{
|
|
|
|
text->SetVertJustify( static_cast<GR_TEXT_V_ALIGN_T>( -text->GetVertJustify() ) );
|
|
|
|
text->SetHorizJustify( static_cast<GR_TEXT_H_ALIGN_T>( -text->GetHorizJustify() ) );
|
|
|
|
}
|
|
|
|
if( orient == SYM_ORIENT_270 )
|
|
|
|
{
|
|
|
|
text->SetVertJustify( static_cast<GR_TEXT_V_ALIGN_T>( -text->GetVertJustify() ) );
|
|
|
|
text->SetHorizJustify( static_cast<GR_TEXT_H_ALIGN_T>( -text->GetHorizJustify() ) );
|
|
|
|
}
|
|
|
|
else if( orient == SYM_MIRROR_X + SYM_ORIENT_90 )
|
|
|
|
{
|
|
|
|
text->SetVertJustify( static_cast<GR_TEXT_V_ALIGN_T>( -text->GetVertJustify() ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
EASYEDAPRO::SYM_INFO SCH_EASYEDAPRO_PARSER::ParseSymbol( const std::vector<nlohmann::json>& aLines )
|
|
|
|
{
|
|
|
|
EASYEDAPRO::SYM_INFO symInfo;
|
|
|
|
|
|
|
|
std::unique_ptr<LIB_SYMBOL> ksymbolPtr = std::make_unique<LIB_SYMBOL>( wxEmptyString );
|
|
|
|
LIB_SYMBOL* ksymbol = ksymbolPtr.get();
|
|
|
|
|
|
|
|
std::map<wxString, nlohmann::json> lineStyles;
|
|
|
|
std::map<wxString, nlohmann::json> fontStyles;
|
|
|
|
std::map<wxString, int> partUnits;
|
|
|
|
|
|
|
|
std::map<int, std::map<wxString, EASYEDAPRO::SCH_ATTR>> unitAttributes;
|
|
|
|
std::map<int, std::map<wxString, std::vector<nlohmann::json>>> unitParentedLines;
|
|
|
|
|
|
|
|
int totalUnits = 0;
|
|
|
|
|
|
|
|
for( const nlohmann::json& line : aLines )
|
|
|
|
{
|
|
|
|
wxString type = line.at( 0 );
|
|
|
|
|
|
|
|
if( type == wxS( "LINESTYLE" ) )
|
|
|
|
lineStyles[line.at( 1 )] = line;
|
|
|
|
else if( type == wxS( "FONTSTYLE" ) )
|
|
|
|
fontStyles[line.at( 1 )] = line;
|
|
|
|
else if( type == wxS( "PART" ) )
|
|
|
|
partUnits[line.at( 1 )] = ++totalUnits;
|
|
|
|
}
|
|
|
|
|
|
|
|
symInfo.partUnits = partUnits;
|
|
|
|
ksymbol->SetUnitCount( totalUnits, false );
|
|
|
|
|
|
|
|
int currentUnit = 1;
|
|
|
|
|
|
|
|
for( const nlohmann::json& line : aLines )
|
|
|
|
{
|
|
|
|
wxString type = line.at( 0 );
|
|
|
|
|
|
|
|
if( type == wxS( "PART" ) )
|
|
|
|
{
|
|
|
|
currentUnit = partUnits.at( line.at( 1 ) );
|
|
|
|
}
|
|
|
|
else if( type == wxS( "RECT" ) )
|
|
|
|
{
|
|
|
|
VECTOR2D start( line.at( 2 ), line.at( 3 ) );
|
|
|
|
VECTOR2D end( line.at( 4 ), line.at( 5 ) );
|
|
|
|
wxString styleStr = line.at( 9 );
|
|
|
|
|
|
|
|
std::unique_ptr<LIB_SHAPE> rect =
|
|
|
|
std::make_unique<LIB_SHAPE>( ksymbol, SHAPE_T::RECTANGLE );
|
|
|
|
|
|
|
|
rect->SetStart( ScalePosSym( start ) );
|
|
|
|
rect->SetEnd( ScalePosSym( end ) );
|
|
|
|
|
|
|
|
rect->SetUnit( currentUnit );
|
|
|
|
ApplyLineStyle( lineStyles, rect, styleStr );
|
|
|
|
|
|
|
|
ksymbol->AddDrawItem( rect.release() );
|
|
|
|
}
|
|
|
|
else if( type == wxS( "CIRCLE" ) )
|
|
|
|
{
|
|
|
|
VECTOR2D center( line.at( 2 ), line.at( 3 ) );
|
|
|
|
double radius = line.at( 4 );
|
|
|
|
wxString styleStr = line.at( 5 );
|
|
|
|
|
|
|
|
std::unique_ptr<LIB_SHAPE> circle =
|
|
|
|
std::make_unique<LIB_SHAPE>( ksymbol, SHAPE_T::CIRCLE );
|
|
|
|
|
|
|
|
circle->SetCenter( ScalePosSym( center ) );
|
|
|
|
circle->SetEnd( circle->GetCenter() + VECTOR2I( ScaleSize( radius ), 0 ) );
|
|
|
|
|
|
|
|
circle->SetUnit( currentUnit );
|
|
|
|
ApplyLineStyle( lineStyles, circle, styleStr );
|
|
|
|
|
|
|
|
ksymbol->AddDrawItem( circle.release() );
|
|
|
|
}
|
|
|
|
else if( type == wxS( "ARC" ) )
|
|
|
|
{
|
|
|
|
VECTOR2D start( line.at( 2 ), line.at( 3 ) );
|
|
|
|
VECTOR2D mid( line.at( 4 ), line.at( 5 ) );
|
|
|
|
VECTOR2D end( line.at( 6 ), line.at( 7 ) );
|
|
|
|
wxString styleStr = line.at( 8 );
|
|
|
|
|
|
|
|
VECTOR2D kstart = ScalePosSym( start );
|
|
|
|
VECTOR2D kmid = ScalePosSym( mid );
|
|
|
|
VECTOR2D kend = ScalePosSym( end );
|
|
|
|
|
|
|
|
VECTOR2D kcenter = CalcArcCenter( kstart, kmid, kend );
|
|
|
|
|
|
|
|
std::unique_ptr<LIB_SHAPE> shape = std::make_unique<LIB_SHAPE>( ksymbol, SHAPE_T::ARC );
|
|
|
|
|
|
|
|
shape->SetStart( kstart );
|
|
|
|
shape->SetEnd( kend );
|
|
|
|
shape->SetCenter( kcenter );
|
|
|
|
|
|
|
|
if( SEG( start, end ).Side( mid ) != SEG( kstart, kend ).Side( shape->GetArcMid() ) )
|
|
|
|
{
|
|
|
|
shape->SetStart( kend );
|
|
|
|
shape->SetEnd( kstart );
|
|
|
|
}
|
|
|
|
|
|
|
|
shape->SetUnit( currentUnit );
|
|
|
|
ApplyLineStyle( lineStyles, shape, styleStr );
|
|
|
|
|
|
|
|
ksymbol->AddDrawItem( shape.release() );
|
|
|
|
}
|
|
|
|
else if( type == wxS( "POLY" ) )
|
|
|
|
{
|
|
|
|
std::vector<double> points = line.at( 2 );
|
|
|
|
wxString styleStr = line.at( 4 );
|
|
|
|
|
|
|
|
std::unique_ptr<LIB_SHAPE> shape =
|
|
|
|
std::make_unique<LIB_SHAPE>( ksymbol, SHAPE_T::POLY );
|
|
|
|
|
|
|
|
for( size_t i = 1; i < points.size(); i += 2 )
|
|
|
|
{
|
|
|
|
shape->AddPoint( ScalePosSym( VECTOR2D( points[i - 1], points[i] ) ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
shape->SetUnit( currentUnit );
|
|
|
|
ApplyLineStyle( lineStyles, shape, styleStr );
|
|
|
|
|
|
|
|
ksymbol->AddDrawItem( shape.release() );
|
|
|
|
}
|
|
|
|
else if( type == wxS( "TEXT" ) )
|
|
|
|
{
|
|
|
|
VECTOR2D pos( line.at( 2 ), line.at( 3 ) );
|
|
|
|
double angle = line.at( 4 );
|
|
|
|
wxString textStr = line.at( 5 );
|
|
|
|
wxString fontStyleStr = line.at( 6 );
|
|
|
|
|
|
|
|
std::unique_ptr<LIB_TEXT> text = std::make_unique<LIB_TEXT>( ksymbol );
|
|
|
|
|
|
|
|
text->SetPosition( ScalePosSym( pos ) );
|
|
|
|
text->SetText( UnescapeHTML( textStr ) );
|
|
|
|
|
|
|
|
text->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
|
|
|
|
text->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
|
|
|
|
|
|
|
|
text->SetTextAngleDegrees( angle );
|
|
|
|
|
|
|
|
text->SetUnit( currentUnit );
|
|
|
|
ApplyFontStyle( fontStyles, text, fontStyleStr );
|
|
|
|
|
|
|
|
ksymbol->AddDrawItem( text.release() );
|
|
|
|
}
|
|
|
|
else if( type == wxS( "OBJ" ) )
|
|
|
|
{
|
|
|
|
VECTOR2D start, size;
|
|
|
|
wxString mimeType, data;
|
2024-03-23 14:50:23 +00:00
|
|
|
//double angle = 0;
|
2023-09-06 11:58:39 +00:00
|
|
|
int upsideDown = 0;
|
|
|
|
|
|
|
|
if( line.at( 3 ).is_number() )
|
|
|
|
{
|
|
|
|
start = VECTOR2D( line.at( 3 ), line.at( 4 ) );
|
|
|
|
size = VECTOR2D( line.at( 5 ), line.at( 6 ) );
|
2024-03-23 14:50:23 +00:00
|
|
|
//angle = line.at( 7 );
|
2023-09-06 11:58:39 +00:00
|
|
|
upsideDown = line.at( 8 );
|
|
|
|
|
|
|
|
wxString imageUrl = line.at( 9 );
|
|
|
|
|
|
|
|
if( imageUrl.BeforeFirst( ':' ) == wxS( "data" ) )
|
|
|
|
{
|
|
|
|
wxArrayString paramsArr =
|
|
|
|
wxSplit( imageUrl.AfterFirst( ':' ).BeforeFirst( ',' ), ';', '\0' );
|
|
|
|
|
|
|
|
data = imageUrl.AfterFirst( ',' );
|
|
|
|
|
|
|
|
if( paramsArr.size() > 0 )
|
|
|
|
{
|
|
|
|
mimeType = paramsArr[0];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if( line.at( 3 ).is_string() )
|
|
|
|
{
|
|
|
|
mimeType = line.at( 3 ).get<wxString>().BeforeFirst( ';' );
|
|
|
|
|
|
|
|
start = VECTOR2D( line.at( 4 ), line.at( 5 ) );
|
|
|
|
size = VECTOR2D( line.at( 6 ), line.at( 7 ) );
|
2024-03-23 14:50:23 +00:00
|
|
|
//angle = line.at( 8 );
|
2023-09-06 11:58:39 +00:00
|
|
|
data = line.at( 9 ).get<wxString>();
|
|
|
|
}
|
|
|
|
|
|
|
|
if( mimeType.empty() || data.empty() )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
wxMemoryBuffer buf = wxBase64Decode( data );
|
|
|
|
|
|
|
|
if( mimeType == wxS( "image/svg+xml" ) )
|
|
|
|
{
|
|
|
|
VECTOR2D offset = ScalePosSym( start );
|
|
|
|
|
|
|
|
SVG_IMPORT_PLUGIN svgImportPlugin;
|
|
|
|
GRAPHICS_IMPORTER_LIB_SYMBOL libsymImporter( ksymbol, 0 );
|
|
|
|
|
|
|
|
svgImportPlugin.SetImporter( &libsymImporter );
|
|
|
|
svgImportPlugin.LoadFromMemory( buf );
|
|
|
|
|
|
|
|
VECTOR2D imSize( svgImportPlugin.GetImageWidth(),
|
|
|
|
svgImportPlugin.GetImageHeight() );
|
|
|
|
|
|
|
|
VECTOR2D pixelScale( schIUScale.IUTomm( ScaleSize( size.x ) ) / imSize.x,
|
|
|
|
schIUScale.IUTomm( -ScaleSize( size.y ) ) / imSize.y );
|
|
|
|
|
|
|
|
if( upsideDown )
|
|
|
|
pixelScale.y *= -1;
|
|
|
|
|
|
|
|
libsymImporter.SetScale( pixelScale );
|
|
|
|
|
|
|
|
VECTOR2D offsetMM( schIUScale.IUTomm( offset.x ), schIUScale.IUTomm( offset.y ) );
|
|
|
|
|
|
|
|
libsymImporter.SetImportOffsetMM( offsetMM );
|
|
|
|
|
|
|
|
svgImportPlugin.Import();
|
|
|
|
|
|
|
|
// TODO: rotation
|
|
|
|
for( std::unique_ptr<EDA_ITEM>& item : libsymImporter.GetItems() )
|
2024-04-06 13:14:44 +00:00
|
|
|
ksymbol->AddDrawItem( static_cast<SCH_ITEM*>( item.release() ) );
|
2023-09-06 11:58:39 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
wxMemoryInputStream memis( buf.GetData(), buf.GetDataLen() );
|
|
|
|
|
|
|
|
wxImage::SetDefaultLoadFlags( wxImage::GetDefaultLoadFlags()
|
|
|
|
& ~wxImage::Load_Verbose );
|
|
|
|
wxImage img;
|
|
|
|
if( img.LoadFile( memis, mimeType ) )
|
|
|
|
{
|
|
|
|
int dimMul = img.GetWidth() * img.GetHeight();
|
|
|
|
double maxPixels = 30000;
|
|
|
|
|
|
|
|
if( dimMul > maxPixels )
|
|
|
|
{
|
|
|
|
double scale = sqrt( maxPixels / dimMul );
|
|
|
|
img.Rescale( img.GetWidth() * scale, img.GetHeight() * scale );
|
|
|
|
}
|
|
|
|
|
|
|
|
VECTOR2D pixelScale( ScaleSize( size.x ) / img.GetWidth(),
|
|
|
|
-ScaleSize( size.y ) / img.GetHeight() );
|
|
|
|
|
|
|
|
// TODO: rotation
|
|
|
|
ConvertImageToLibShapes( ksymbol, 0, img, pixelScale, ScalePosSym( start ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if( type == wxS( "HEAD" ) )
|
|
|
|
{
|
|
|
|
symInfo.head = line;
|
|
|
|
}
|
|
|
|
else if( type == wxS( "PIN" ) )
|
|
|
|
{
|
|
|
|
wxString pinId = line.at( 1 );
|
|
|
|
unitParentedLines[currentUnit][pinId].push_back( line );
|
|
|
|
}
|
|
|
|
else if( type == wxS( "ATTR" ) )
|
|
|
|
{
|
|
|
|
wxString parentId = line.at( 2 );
|
|
|
|
|
|
|
|
if( parentId.empty() )
|
|
|
|
{
|
|
|
|
EASYEDAPRO::SCH_ATTR attr = line;
|
|
|
|
unitAttributes[currentUnit].emplace( attr.key, attr );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
unitParentedLines[currentUnit][parentId].push_back( line );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( symInfo.head.symbolType == EASYEDAPRO::SYMBOL_TYPE::POWER_PORT
|
|
|
|
|| symInfo.head.symbolType == EASYEDAPRO::SYMBOL_TYPE::NETPORT )
|
|
|
|
{
|
|
|
|
ksymbol->SetPower();
|
|
|
|
ksymbol->GetReferenceField().SetText( wxS( "#PWR" ) );
|
|
|
|
ksymbol->GetReferenceField().SetVisible( false );
|
|
|
|
ksymbol->SetKeyWords( wxS( "power-flag" ) );
|
|
|
|
ksymbol->SetShowPinNames( false );
|
|
|
|
ksymbol->SetShowPinNumbers( false );
|
|
|
|
|
|
|
|
if( auto globalNetAttr = get_opt( unitAttributes[1], wxS( "Global Net Name" ) ) )
|
|
|
|
{
|
|
|
|
ApplyAttrToField( fontStyles, &ksymbol->GetValueField(), *globalNetAttr, true, true );
|
|
|
|
|
|
|
|
wxString globalNetname = globalNetAttr->value;
|
|
|
|
|
|
|
|
if( !globalNetname.empty() )
|
|
|
|
{
|
|
|
|
ksymbol->SetDescription( wxString::Format(
|
2023-09-07 14:29:36 +00:00
|
|
|
_( "Power symbol creates a global label with name '%s'" ),
|
2023-09-06 11:58:39 +00:00
|
|
|
globalNetname ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
auto designatorAttr = get_opt( unitAttributes[1], wxS( "Designator" ) );
|
|
|
|
|
|
|
|
if( designatorAttr && !designatorAttr->value.empty() )
|
|
|
|
{
|
|
|
|
wxString symbolPrefix = designatorAttr->value;
|
|
|
|
|
|
|
|
if( !symbolPrefix.EndsWith( wxS( "?" ) ) )
|
|
|
|
symbolPrefix += wxS( "?" );
|
|
|
|
|
|
|
|
ksymbol->GetReferenceField().SetText( symbolPrefix );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for( auto& [unitId, parentedLines] : unitParentedLines )
|
|
|
|
{
|
|
|
|
for( auto& [pinId, lines] : parentedLines )
|
|
|
|
{
|
|
|
|
std::optional<EASYEDAPRO::SYM_PIN> epin;
|
|
|
|
std::map<wxString, EASYEDAPRO::SCH_ATTR> pinAttributes;
|
|
|
|
|
|
|
|
for( const nlohmann::json& line : lines )
|
|
|
|
{
|
|
|
|
wxString type = line.at( 0 );
|
|
|
|
|
|
|
|
if( type == wxS( "ATTR" ) )
|
|
|
|
{
|
|
|
|
EASYEDAPRO::SCH_ATTR attr = line;
|
|
|
|
pinAttributes.emplace( attr.key, attr );
|
|
|
|
}
|
|
|
|
else if( type == wxS( "PIN" ) )
|
|
|
|
{
|
|
|
|
epin = line;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( !epin )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
EASYEDAPRO::PIN_INFO pinInfo;
|
|
|
|
pinInfo.pin = *epin;
|
|
|
|
|
|
|
|
std::unique_ptr<LIB_PIN> pin = std::make_unique<LIB_PIN>( ksymbol );
|
|
|
|
|
|
|
|
pin->SetUnit( unitId );
|
|
|
|
|
|
|
|
pin->SetLength( ScaleSize( epin->length ) );
|
|
|
|
pin->SetPosition( ScalePosSym( epin->position ) );
|
|
|
|
|
|
|
|
PIN_ORIENTATION orient = PIN_ORIENTATION::PIN_RIGHT;
|
|
|
|
|
|
|
|
if( epin->rotation == 0 )
|
|
|
|
orient = PIN_ORIENTATION::PIN_RIGHT;
|
|
|
|
if( epin->rotation == 90 )
|
|
|
|
orient = PIN_ORIENTATION::PIN_UP;
|
|
|
|
if( epin->rotation == 180 )
|
|
|
|
orient = PIN_ORIENTATION::PIN_LEFT;
|
|
|
|
if( epin->rotation == 270 )
|
|
|
|
orient = PIN_ORIENTATION::PIN_DOWN;
|
|
|
|
|
|
|
|
pin->SetOrientation( orient );
|
|
|
|
|
|
|
|
if( symInfo.head.symbolType == EASYEDAPRO::SYMBOL_TYPE::POWER_PORT )
|
|
|
|
{
|
|
|
|
pin->SetName( ksymbol->GetName() );
|
|
|
|
//pin->SetVisible( false );
|
|
|
|
}
|
|
|
|
else if( auto pinNameAttr = get_opt( pinAttributes, "NAME" ) )
|
|
|
|
{
|
|
|
|
pin->SetName( pinNameAttr->value );
|
|
|
|
pinInfo.name = pinNameAttr->value;
|
|
|
|
|
|
|
|
if( !pinNameAttr->valVisible )
|
|
|
|
pin->SetNameTextSize( schIUScale.MilsToIU( 1 ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( auto pinNumAttr = get_opt( pinAttributes, "NUMBER" ) )
|
|
|
|
{
|
|
|
|
pin->SetNumber( pinNumAttr->value );
|
|
|
|
pinInfo.number = pinNumAttr->value;
|
|
|
|
|
|
|
|
if( !pinNumAttr->valVisible )
|
|
|
|
pin->SetNumberTextSize( schIUScale.MilsToIU( 1 ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( symInfo.head.symbolType == EASYEDAPRO::SYMBOL_TYPE::POWER_PORT )
|
|
|
|
{
|
|
|
|
pin->SetType( ELECTRICAL_PINTYPE::PT_POWER_IN );
|
|
|
|
}
|
|
|
|
else if( auto pinTypeAttr = get_opt( pinAttributes, "Pin Type" ) )
|
|
|
|
{
|
|
|
|
if( pinTypeAttr->value == wxS( "IN" ) )
|
|
|
|
pin->SetType( ELECTRICAL_PINTYPE::PT_INPUT );
|
|
|
|
if( pinTypeAttr->value == wxS( "OUT" ) )
|
|
|
|
pin->SetType( ELECTRICAL_PINTYPE::PT_OUTPUT );
|
|
|
|
if( pinTypeAttr->value == wxS( "BI" ) )
|
|
|
|
pin->SetType( ELECTRICAL_PINTYPE::PT_BIDI );
|
|
|
|
}
|
|
|
|
|
|
|
|
if( get_opt( pinAttributes, "NO_CONNECT" ) )
|
|
|
|
pin->SetType( ELECTRICAL_PINTYPE::PT_NC );
|
|
|
|
|
|
|
|
if( pin->GetNumberTextSize() * int( pin->GetNumber().size() ) > pin->GetLength() )
|
|
|
|
pin->SetNumberTextSize( pin->GetLength() / pin->GetNumber().size() );
|
|
|
|
|
|
|
|
symInfo.pins.push_back( pinInfo );
|
|
|
|
ksymbol->AddDrawItem( pin.release() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
symInfo.symbolAttr = get_opt( unitAttributes[1], "Symbol" ); // TODO: per-unit
|
|
|
|
|
|
|
|
/*BOX2I bbox = ksymbol->GetBodyBoundingBox( 0, 0, true, true );
|
|
|
|
bbox.Inflate( schIUScale.MilsToIU( 10 ) );*/
|
|
|
|
|
|
|
|
/*ksymbol->GetReferenceField().SetVertJustify( GR_TEXT_V_ALIGN_BOTTOM );
|
|
|
|
ksymbol->GetReferenceField().SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
|
|
|
|
ksymbol->GetReferenceField().SetPosition( VECTOR2I( bbox.GetCenter().x, -bbox.GetTop() ) );
|
|
|
|
|
|
|
|
ksymbol->GetValueField().SetVertJustify( GR_TEXT_V_ALIGN_TOP );
|
|
|
|
ksymbol->GetValueField().SetHorizJustify( GR_TEXT_H_ALIGN_CENTER );
|
|
|
|
ksymbol->GetValueField().SetPosition( VECTOR2I( bbox.GetCenter().x, -bbox.GetBottom() ) );*/
|
|
|
|
|
|
|
|
symInfo.libSymbol = std::move( ksymbolPtr );
|
|
|
|
|
|
|
|
return symInfo;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void SCH_EASYEDAPRO_PARSER::ParseSchematic( SCHEMATIC* aSchematic, SCH_SHEET* aRootSheet,
|
|
|
|
const nlohmann::json& aProject,
|
|
|
|
std::map<wxString, EASYEDAPRO::SYM_INFO>& aSymbolMap,
|
|
|
|
const std::map<wxString, EASYEDAPRO::BLOB>& aBlobMap,
|
|
|
|
const std::vector<nlohmann::json>& aLines,
|
|
|
|
const wxString& aLibName )
|
|
|
|
{
|
|
|
|
std::vector<std::unique_ptr<SCH_ITEM>> createdItems;
|
|
|
|
|
|
|
|
std::map<wxString, std::vector<nlohmann::json>> parentedLines;
|
|
|
|
std::map<wxString, std::vector<nlohmann::json>> ruleLines;
|
|
|
|
|
|
|
|
std::map<wxString, nlohmann::json> lineStyles;
|
|
|
|
std::map<wxString, nlohmann::json> fontStyles;
|
|
|
|
|
|
|
|
for( const nlohmann::json& line : aLines )
|
|
|
|
{
|
|
|
|
wxString type = line.at( 0 );
|
|
|
|
|
|
|
|
if( type == wxS( "LINESTYLE" ) )
|
|
|
|
lineStyles[line.at( 1 )] = line;
|
|
|
|
else if( type == wxS( "FONTSTYLE" ) )
|
|
|
|
fontStyles[line.at( 1 )] = line;
|
|
|
|
}
|
|
|
|
|
|
|
|
for( const nlohmann::json& line : aLines )
|
|
|
|
{
|
|
|
|
wxString type = line.at( 0 );
|
|
|
|
|
|
|
|
if( type == wxS( "RECT" ) )
|
|
|
|
{
|
|
|
|
VECTOR2D start( line.at( 2 ), line.at( 3 ) );
|
|
|
|
VECTOR2D end( line.at( 4 ), line.at( 5 ) );
|
|
|
|
wxString styleStr = line.at( 9 );
|
|
|
|
|
|
|
|
std::unique_ptr<SCH_SHAPE> rect = std::make_unique<SCH_SHAPE>( SHAPE_T::RECTANGLE );
|
|
|
|
|
|
|
|
rect->SetStart( ScalePos( start ) );
|
|
|
|
rect->SetEnd( ScalePos( end ) );
|
|
|
|
|
|
|
|
ApplyLineStyle( lineStyles, rect, styleStr );
|
|
|
|
|
|
|
|
createdItems.push_back( std::move( rect ) );
|
|
|
|
}
|
|
|
|
else if( type == wxS( "CIRCLE" ) )
|
|
|
|
{
|
|
|
|
VECTOR2D center( line.at( 2 ), line.at( 3 ) );
|
|
|
|
double radius = line.at( 4 );
|
|
|
|
wxString styleStr = line.at( 5 );
|
|
|
|
|
|
|
|
std::unique_ptr<SCH_SHAPE> circle = std::make_unique<SCH_SHAPE>( SHAPE_T::CIRCLE );
|
|
|
|
|
|
|
|
circle->SetCenter( ScalePos( center ) );
|
|
|
|
circle->SetEnd( circle->GetCenter() + VECTOR2I( ScaleSize( radius ), 0 ) );
|
|
|
|
|
|
|
|
ApplyLineStyle( lineStyles, circle, styleStr );
|
|
|
|
|
|
|
|
createdItems.push_back( std::move( circle ) );
|
|
|
|
}
|
|
|
|
else if( type == wxS( "POLY" ) )
|
|
|
|
{
|
|
|
|
std::vector<double> points = line.at( 2 );
|
|
|
|
wxString styleStr = line.at( 4 );
|
|
|
|
|
|
|
|
SHAPE_LINE_CHAIN chain;
|
|
|
|
|
|
|
|
for( size_t i = 1; i < points.size(); i += 2 )
|
|
|
|
chain.Append( ScalePos( VECTOR2D( points[i - 1], points[i] ) ) );
|
|
|
|
|
|
|
|
for( int segId = 0; segId < chain.SegmentCount(); segId++ )
|
|
|
|
{
|
|
|
|
const SEG& seg = chain.CSegment( segId );
|
|
|
|
|
|
|
|
std::unique_ptr<SCH_LINE> schLine =
|
|
|
|
std::make_unique<SCH_LINE>( seg.A, LAYER_NOTES );
|
|
|
|
schLine->SetEndPoint( seg.B );
|
|
|
|
|
|
|
|
ApplyLineStyle( lineStyles, schLine, styleStr );
|
|
|
|
|
|
|
|
createdItems.push_back( std::move( schLine ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if( type == wxS( "TEXT" ) )
|
|
|
|
{
|
|
|
|
VECTOR2D pos( line.at( 2 ), line.at( 3 ) );
|
|
|
|
double angle = line.at( 4 );
|
|
|
|
wxString textStr = line.at( 5 );
|
|
|
|
wxString fontStyleStr = line.at( 6 );
|
|
|
|
|
|
|
|
std::unique_ptr<SCH_TEXT> text =
|
|
|
|
std::make_unique<SCH_TEXT>( ScalePos( pos ), UnescapeHTML( textStr ) );
|
|
|
|
|
|
|
|
text->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
|
|
|
|
text->SetVertJustify( GR_TEXT_V_ALIGN_TOP );
|
|
|
|
|
|
|
|
text->SetTextAngleDegrees( angle );
|
|
|
|
|
|
|
|
ApplyFontStyle( fontStyles, text, fontStyleStr );
|
|
|
|
|
|
|
|
createdItems.push_back( std::move( text ) );
|
|
|
|
}
|
|
|
|
else if( type == wxS( "OBJ" ) )
|
|
|
|
{
|
|
|
|
VECTOR2D start, size;
|
|
|
|
wxString mimeType, base64Data;
|
|
|
|
double angle = 0;
|
2023-10-30 08:34:42 +00:00
|
|
|
int flipped = 0;
|
2023-09-06 11:58:39 +00:00
|
|
|
|
|
|
|
if( line.at( 3 ).is_number() )
|
|
|
|
{
|
|
|
|
start = VECTOR2D( line.at( 3 ), line.at( 4 ) );
|
|
|
|
size = VECTOR2D( line.at( 5 ), line.at( 6 ) );
|
|
|
|
angle = line.at( 7 );
|
2023-10-30 08:34:42 +00:00
|
|
|
flipped = line.at( 8 );
|
2023-09-06 11:58:39 +00:00
|
|
|
|
|
|
|
wxString imageUrl = line.at( 9 );
|
|
|
|
|
|
|
|
if( imageUrl.BeforeFirst( ':' ) == wxS( "data" ) )
|
|
|
|
{
|
|
|
|
wxArrayString paramsArr =
|
|
|
|
wxSplit( imageUrl.AfterFirst( ':' ).BeforeFirst( ',' ), ';', '\0' );
|
|
|
|
|
|
|
|
base64Data = imageUrl.AfterFirst( ',' );
|
|
|
|
|
|
|
|
if( paramsArr.size() > 0 )
|
|
|
|
mimeType = paramsArr[0];
|
|
|
|
}
|
|
|
|
else if( imageUrl.BeforeFirst( ':' ) == wxS( "blob" ) )
|
|
|
|
{
|
|
|
|
wxString objectId = imageUrl.AfterLast( ':' );
|
|
|
|
|
|
|
|
if( auto blob = get_opt( aBlobMap, objectId ) )
|
|
|
|
{
|
|
|
|
wxString blobUrl = blob->url;
|
|
|
|
|
|
|
|
if( blobUrl.BeforeFirst( ':' ) == wxS( "data" ) )
|
|
|
|
{
|
|
|
|
wxArrayString paramsArr = wxSplit(
|
|
|
|
blobUrl.AfterFirst( ':' ).BeforeFirst( ',' ), ';', '\0' );
|
|
|
|
|
|
|
|
base64Data = blobUrl.AfterFirst( ',' );
|
|
|
|
|
|
|
|
if( paramsArr.size() > 0 )
|
|
|
|
mimeType = paramsArr[0];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if( line.at( 3 ).is_string() )
|
|
|
|
{
|
|
|
|
mimeType = line.at( 3 ).get<wxString>().BeforeFirst( ';' );
|
|
|
|
|
|
|
|
start = VECTOR2D( line.at( 4 ), line.at( 5 ) );
|
|
|
|
size = VECTOR2D( line.at( 6 ), line.at( 7 ) );
|
|
|
|
angle = line.at( 8 );
|
|
|
|
base64Data = line.at( 9 ).get<wxString>();
|
|
|
|
}
|
|
|
|
|
2023-11-04 12:21:22 +00:00
|
|
|
VECTOR2D kstart = ScalePos( start );
|
|
|
|
VECTOR2D ksize = ScaleSize( size );
|
|
|
|
|
2023-09-06 11:58:39 +00:00
|
|
|
if( mimeType.empty() || base64Data.empty() )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
wxMemoryBuffer buf = wxBase64Decode( base64Data );
|
|
|
|
|
|
|
|
if( mimeType == wxS( "image/svg+xml" ) )
|
|
|
|
{
|
2023-10-30 08:34:42 +00:00
|
|
|
SVG_IMPORT_PLUGIN svgImportPlugin;
|
|
|
|
GRAPHICS_IMPORTER_SCH schImporter;
|
2023-09-06 11:58:39 +00:00
|
|
|
|
2023-10-30 08:34:42 +00:00
|
|
|
svgImportPlugin.SetImporter( &schImporter );
|
|
|
|
svgImportPlugin.LoadFromMemory( buf );
|
2023-09-06 11:58:39 +00:00
|
|
|
|
2023-10-30 08:34:42 +00:00
|
|
|
VECTOR2D imSize( svgImportPlugin.GetImageWidth(),
|
|
|
|
svgImportPlugin.GetImageHeight() );
|
|
|
|
|
|
|
|
VECTOR2D pixelScale( schIUScale.IUTomm( ScaleSize( size.x ) ) / imSize.x,
|
|
|
|
schIUScale.IUTomm( ScaleSize( size.y ) ) / imSize.y );
|
2023-09-06 11:58:39 +00:00
|
|
|
|
2023-10-30 08:34:42 +00:00
|
|
|
schImporter.SetScale( pixelScale );
|
2023-09-06 11:58:39 +00:00
|
|
|
|
2023-11-04 12:21:22 +00:00
|
|
|
VECTOR2D offsetMM( schIUScale.IUTomm( kstart.x ), schIUScale.IUTomm( kstart.y ) );
|
2023-09-06 11:58:39 +00:00
|
|
|
|
2023-10-30 08:34:42 +00:00
|
|
|
schImporter.SetImportOffsetMM( offsetMM );
|
2023-09-06 11:58:39 +00:00
|
|
|
|
2023-10-30 08:34:42 +00:00
|
|
|
svgImportPlugin.Import();
|
2023-09-06 11:58:39 +00:00
|
|
|
|
2023-10-30 08:34:42 +00:00
|
|
|
for( std::unique_ptr<EDA_ITEM>& item : schImporter.GetItems() )
|
|
|
|
{
|
|
|
|
SCH_ITEM* schItem = static_cast<SCH_ITEM*>( item.release() );
|
2023-09-06 11:58:39 +00:00
|
|
|
|
2023-10-30 08:34:42 +00:00
|
|
|
for( double i = angle; i > 0; i -= 90 )
|
|
|
|
{
|
|
|
|
if( schItem->Type() == SCH_LINE_T )
|
|
|
|
{
|
|
|
|
// Lines need special handling for some reason
|
|
|
|
schItem->SetFlags( STARTPOINT );
|
2024-04-04 22:51:22 +00:00
|
|
|
schItem->Rotate( kstart, false );
|
2023-10-30 08:34:42 +00:00
|
|
|
schItem->ClearFlags( STARTPOINT );
|
|
|
|
|
|
|
|
schItem->SetFlags( ENDPOINT );
|
2024-04-04 22:51:22 +00:00
|
|
|
schItem->Rotate( kstart, false );
|
2023-10-30 08:34:42 +00:00
|
|
|
schItem->ClearFlags( ENDPOINT );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-04-04 22:51:22 +00:00
|
|
|
schItem->Rotate( kstart, false );
|
2023-10-30 08:34:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-04 12:21:22 +00:00
|
|
|
if( flipped )
|
|
|
|
{
|
|
|
|
// Lines need special handling for some reason
|
|
|
|
if( schItem->Type() == SCH_LINE_T )
|
|
|
|
schItem->SetFlags( STARTPOINT | ENDPOINT );
|
|
|
|
|
|
|
|
schItem->MirrorHorizontally( kstart.x );
|
|
|
|
|
|
|
|
if( schItem->Type() == SCH_LINE_T )
|
|
|
|
schItem->ClearFlags( STARTPOINT | ENDPOINT );
|
|
|
|
}
|
|
|
|
|
2023-10-30 08:34:42 +00:00
|
|
|
createdItems.emplace_back( schItem );
|
|
|
|
}
|
2023-09-06 11:58:39 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std::unique_ptr<SCH_BITMAP> bitmap = std::make_unique<SCH_BITMAP>();
|
|
|
|
|
|
|
|
wxImage::SetDefaultLoadFlags( wxImage::GetDefaultLoadFlags()
|
|
|
|
& ~wxImage::Load_Verbose );
|
|
|
|
|
|
|
|
if( bitmap->ReadImageFile( buf ) )
|
|
|
|
{
|
|
|
|
VECTOR2D kcenter = kstart + ksize / 2;
|
|
|
|
|
|
|
|
double scaleFactor = ScaleSize( size.x ) / bitmap->GetSize().x;
|
|
|
|
bitmap->SetImageScale( scaleFactor );
|
|
|
|
bitmap->SetPosition( kcenter );
|
|
|
|
|
2023-10-30 08:34:42 +00:00
|
|
|
for( double i = angle; i > 0; i -= 90 )
|
2024-04-04 22:51:22 +00:00
|
|
|
bitmap->Rotate( kstart, false );
|
2023-10-30 08:34:42 +00:00
|
|
|
|
|
|
|
if( flipped )
|
|
|
|
bitmap->MirrorHorizontally( kstart.x );
|
|
|
|
|
2023-09-06 11:58:39 +00:00
|
|
|
createdItems.push_back( std::move( bitmap ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if( type == wxS( "WIRE" ) )
|
|
|
|
{
|
|
|
|
wxString wireId = line.at( 1 );
|
|
|
|
parentedLines[wireId].push_back( line );
|
|
|
|
}
|
|
|
|
else if( type == wxS( "COMPONENT" ) )
|
|
|
|
{
|
|
|
|
wxString compId = line.at( 1 );
|
|
|
|
parentedLines[compId].push_back( line );
|
|
|
|
}
|
|
|
|
else if( type == wxS( "ATTR" ) )
|
|
|
|
{
|
|
|
|
wxString compId = line.at( 2 );
|
|
|
|
parentedLines[compId].push_back( line );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for( auto& [parentId, lines] : parentedLines )
|
|
|
|
{
|
|
|
|
std::optional<EASYEDAPRO::SCH_COMPONENT> component;
|
|
|
|
std::optional<EASYEDAPRO::SCH_WIRE> wire;
|
|
|
|
std::map<wxString, EASYEDAPRO::SCH_ATTR> attributes;
|
|
|
|
|
|
|
|
for( const nlohmann::json& line : lines )
|
|
|
|
{
|
|
|
|
if( line.at( 0 ) == "COMPONENT" )
|
|
|
|
{
|
|
|
|
component = line;
|
|
|
|
}
|
|
|
|
else if( line.at( 0 ) == "WIRE" )
|
|
|
|
{
|
|
|
|
wire = line;
|
|
|
|
}
|
|
|
|
else if( line.at( 0 ) == "ATTR" )
|
|
|
|
{
|
|
|
|
EASYEDAPRO::SCH_ATTR attr = line;
|
|
|
|
attributes.emplace( attr.key, attr );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( component )
|
|
|
|
{
|
|
|
|
auto deviceAttr = get_opt( attributes, "Device" );
|
|
|
|
auto symbolAttr = get_opt( attributes, "Symbol" );
|
|
|
|
|
|
|
|
if( !deviceAttr )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
nlohmann::json compAttrs =
|
|
|
|
aProject.at( "devices" ).at( deviceAttr->value ).at( "attributes" );
|
|
|
|
|
|
|
|
wxString symbolId;
|
|
|
|
|
|
|
|
if( symbolAttr && !symbolAttr->value.IsEmpty() )
|
|
|
|
symbolId = symbolAttr->value;
|
|
|
|
else
|
|
|
|
symbolId = compAttrs.at( "Symbol" ).get<wxString>();
|
|
|
|
|
|
|
|
auto it = aSymbolMap.find( symbolId );
|
|
|
|
if( it == aSymbolMap.end() )
|
|
|
|
{
|
|
|
|
wxLogError( "Symbol of '%s' with uuid '%s' not found.", component->name, symbolId );
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
EASYEDAPRO::SYM_INFO& esymInfo = it->second;
|
|
|
|
LIB_SYMBOL newLibSymbol = *esymInfo.libSymbol.get();
|
|
|
|
|
|
|
|
wxString unitName = component->name;
|
|
|
|
|
2024-04-04 22:51:22 +00:00
|
|
|
LIB_ID libId = EASYEDAPRO::ToKiCadLibID( aLibName,
|
|
|
|
newLibSymbol.GetLibId().GetLibItemName() );
|
2023-09-06 11:58:39 +00:00
|
|
|
|
2024-04-04 22:51:22 +00:00
|
|
|
auto schSym = std::make_unique<SCH_SYMBOL>( newLibSymbol, libId,
|
|
|
|
&aSchematic->CurrentSheet(),
|
|
|
|
esymInfo.partUnits[unitName] );
|
2023-09-06 11:58:39 +00:00
|
|
|
|
|
|
|
schSym->SetFootprintFieldText( newLibSymbol.GetFootprintField().GetText() );
|
|
|
|
|
|
|
|
for( double i = component->rotation; i > 0; i -= 90 )
|
2024-04-04 22:51:22 +00:00
|
|
|
schSym->Rotate( VECTOR2I(), false );
|
2023-09-06 11:58:39 +00:00
|
|
|
|
|
|
|
if( component->mirror )
|
|
|
|
schSym->MirrorHorizontally( 0 );
|
|
|
|
|
|
|
|
schSym->SetPosition( ScalePos( component->position ) );
|
|
|
|
|
|
|
|
if( esymInfo.head.symbolType == EASYEDAPRO::SYMBOL_TYPE::POWER_PORT )
|
|
|
|
{
|
|
|
|
if( auto globalNetAttr = get_opt( attributes, "Global Net Name" ) )
|
|
|
|
{
|
|
|
|
ApplyAttrToField( fontStyles, schSym->GetField( VALUE_FIELD ), *globalNetAttr,
|
2024-01-16 20:39:44 +00:00
|
|
|
false, true, compAttrs, schSym.get() );
|
2023-09-06 11:58:39 +00:00
|
|
|
|
|
|
|
for( LIB_PIN* pin : schSym->GetAllLibPins() )
|
|
|
|
pin->SetName( globalNetAttr->value );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
schSym->GetField( VALUE_FIELD )
|
|
|
|
->SetText( newLibSymbol.GetValueField().GetText() );
|
|
|
|
}
|
|
|
|
|
|
|
|
schSym->SetRef( &aSchematic->CurrentSheet(), wxS( "#PWR?" ) );
|
|
|
|
schSym->GetField( REFERENCE_FIELD )->SetVisible( false );
|
|
|
|
}
|
|
|
|
else if( esymInfo.head.symbolType == EASYEDAPRO::SYMBOL_TYPE::NETPORT )
|
|
|
|
{
|
|
|
|
auto nameAttr = get_opt( attributes, "Name" );
|
|
|
|
|
|
|
|
if( nameAttr )
|
|
|
|
{
|
|
|
|
std::unique_ptr<SCH_GLOBALLABEL> label = std::make_unique<SCH_GLOBALLABEL>(
|
|
|
|
ScalePos( component->position ), nameAttr->value );
|
|
|
|
|
2023-09-07 17:00:04 +00:00
|
|
|
SPIN_STYLE spin = SPIN_STYLE::LEFT;
|
2023-09-06 11:58:39 +00:00
|
|
|
|
|
|
|
if( esymInfo.symbolAttr )
|
|
|
|
{
|
|
|
|
wxString symStr = esymInfo.symbolAttr->value;
|
|
|
|
|
|
|
|
if( symStr == wxS( "Netport-IN" ) )
|
2024-01-16 19:47:15 +00:00
|
|
|
{
|
|
|
|
spin = SPIN_STYLE::LEFT;
|
2023-09-06 11:58:39 +00:00
|
|
|
label->SetShape( LABEL_FLAG_SHAPE::L_INPUT );
|
2024-01-16 19:47:15 +00:00
|
|
|
}
|
2023-09-06 11:58:39 +00:00
|
|
|
if( symStr == wxS( "Netport-OUT" ) )
|
2024-01-16 19:47:15 +00:00
|
|
|
{
|
|
|
|
spin = SPIN_STYLE::RIGHT;
|
2023-09-06 11:58:39 +00:00
|
|
|
label->SetShape( LABEL_FLAG_SHAPE::L_OUTPUT );
|
2024-01-16 19:47:15 +00:00
|
|
|
}
|
2023-09-06 11:58:39 +00:00
|
|
|
if( symStr == wxS( "Netport-BI" ) )
|
2024-01-16 19:47:15 +00:00
|
|
|
{
|
|
|
|
spin = SPIN_STYLE::RIGHT;
|
2023-09-06 11:58:39 +00:00
|
|
|
label->SetShape( LABEL_FLAG_SHAPE::L_BIDI );
|
2024-01-16 19:47:15 +00:00
|
|
|
}
|
2023-09-06 11:58:39 +00:00
|
|
|
}
|
|
|
|
|
2024-01-16 19:47:15 +00:00
|
|
|
for( double i = component->rotation; i > 0; i -= 90 )
|
|
|
|
spin = spin.RotateCCW();
|
|
|
|
|
|
|
|
label->SetSpinStyle( spin );
|
|
|
|
|
2023-09-06 11:58:39 +00:00
|
|
|
nlohmann::json style = fontStyles[nameAttr->fontStyle];
|
|
|
|
|
|
|
|
if( !style.is_null() && style.at( 5 ).is_number() )
|
|
|
|
{
|
|
|
|
double size = style.at( 5 ).get<double>() * 0.5;
|
|
|
|
label->SetTextSize( VECTOR2I( ScaleSize( size ), ScaleSize( size ) ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
createdItems.push_back( std::move( label ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
auto nameAttr = get_opt( attributes, "Name" );
|
|
|
|
auto valueAttr = get_opt( attributes, "Value" );
|
|
|
|
|
|
|
|
std::optional<EASYEDAPRO::SCH_ATTR> targetValueAttr;
|
|
|
|
|
|
|
|
if( valueAttr && !valueAttr->value.empty() && valueAttr->valVisible )
|
|
|
|
targetValueAttr = valueAttr;
|
|
|
|
else if( nameAttr && !nameAttr->value.empty() && nameAttr->valVisible )
|
|
|
|
targetValueAttr = nameAttr;
|
|
|
|
else if( valueAttr && !valueAttr->value.empty() )
|
|
|
|
targetValueAttr = valueAttr;
|
|
|
|
else if( nameAttr && !nameAttr->value.empty() )
|
|
|
|
targetValueAttr = nameAttr;
|
|
|
|
|
|
|
|
if( targetValueAttr )
|
2024-01-16 20:39:44 +00:00
|
|
|
{
|
2023-09-06 11:58:39 +00:00
|
|
|
ApplyAttrToField( fontStyles, schSym->GetField( VALUE_FIELD ), *targetValueAttr,
|
2024-01-16 20:39:44 +00:00
|
|
|
false, true, compAttrs, schSym.get() );
|
|
|
|
}
|
2023-09-06 11:58:39 +00:00
|
|
|
|
|
|
|
if( auto descrAttr = get_opt( attributes, "Description" ) )
|
2024-01-16 20:39:44 +00:00
|
|
|
{
|
2023-09-06 11:58:39 +00:00
|
|
|
ApplyAttrToField( fontStyles, schSym->GetField( DESCRIPTION_FIELD ), *descrAttr,
|
2024-01-16 20:39:44 +00:00
|
|
|
false, true, compAttrs, schSym.get() );
|
|
|
|
}
|
2023-09-06 11:58:39 +00:00
|
|
|
|
|
|
|
if( auto designatorAttr = get_opt( attributes, "Designator" ) )
|
|
|
|
{
|
|
|
|
ApplyAttrToField( fontStyles, schSym->GetField( REFERENCE_FIELD ),
|
2024-01-16 20:39:44 +00:00
|
|
|
*designatorAttr, false, true, compAttrs, schSym.get() );
|
2023-09-06 11:58:39 +00:00
|
|
|
|
|
|
|
schSym->SetRef( &aSchematic->CurrentSheet(), designatorAttr->value );
|
|
|
|
}
|
|
|
|
|
|
|
|
for( auto& [attrKey, attr] : attributes )
|
|
|
|
{
|
|
|
|
if( attrKey == wxS( "Name" ) || attrKey == wxS( "Value" )
|
|
|
|
|| attrKey == wxS( "Global Net Name" ) || attrKey == wxS( "Designator" )
|
|
|
|
|| attrKey == wxS( "Description" ) || attrKey == wxS( "Device" )
|
|
|
|
|| attrKey == wxS( "Footprint" ) || attrKey == wxS( "Symbol" )
|
|
|
|
|| attrKey == wxS( "Unique ID" ) )
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( attr.value.IsEmpty() )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
SCH_FIELD* text =
|
|
|
|
new SCH_FIELD( schSym.get(), schSym->GetFieldCount(), attrKey );
|
|
|
|
|
|
|
|
text->SetPosition( schSym->GetPosition() );
|
|
|
|
|
2024-01-16 20:39:44 +00:00
|
|
|
ApplyAttrToField( fontStyles, text, attr, false, true, compAttrs,
|
|
|
|
schSym.get() );
|
|
|
|
|
2023-09-06 11:58:39 +00:00
|
|
|
schSym->AddField( *text );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for( const EASYEDAPRO::PIN_INFO& pinInfo : esymInfo.pins )
|
|
|
|
{
|
|
|
|
wxString pinKey = parentId + pinInfo.pin.id;
|
|
|
|
auto pinLines = get_opt( parentedLines, pinKey );
|
|
|
|
|
|
|
|
if( !pinLines )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for( const nlohmann::json& pinLine : *pinLines )
|
|
|
|
{
|
|
|
|
if( pinLine.at( 0 ) != "ATTR" )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
EASYEDAPRO::SCH_ATTR attr = pinLine;
|
|
|
|
|
|
|
|
if( attr.key != wxS( "NO_CONNECT" ) )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if( SCH_PIN* schPin = schSym->GetPin( pinInfo.number ) )
|
|
|
|
{
|
|
|
|
VECTOR2I pos = schSym->GetPinPhysicalPosition( schPin->GetLibPin() );
|
|
|
|
|
|
|
|
std::unique_ptr<SCH_NO_CONNECT> noConn =
|
|
|
|
std::make_unique<SCH_NO_CONNECT>( pos );
|
|
|
|
|
|
|
|
createdItems.push_back( std::move( noConn ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
createdItems.push_back( std::move( schSym ) );
|
|
|
|
}
|
|
|
|
else // Not component
|
|
|
|
{
|
|
|
|
std::vector<SHAPE_LINE_CHAIN> wireLines;
|
|
|
|
|
|
|
|
if( wire )
|
|
|
|
{
|
|
|
|
for( const std::vector<double>& ptArr : wire->geometry )
|
|
|
|
{
|
|
|
|
SHAPE_LINE_CHAIN chain;
|
|
|
|
|
|
|
|
for( size_t i = 1; i < ptArr.size(); i += 2 )
|
|
|
|
chain.Append( ScalePos( VECTOR2D( ptArr[i - 1], ptArr[i] ) ) );
|
|
|
|
|
|
|
|
if( chain.PointCount() < 2 )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
wireLines.push_back( chain );
|
|
|
|
|
|
|
|
for( int segId = 0; segId < chain.SegmentCount(); segId++ )
|
|
|
|
{
|
|
|
|
const SEG& seg = chain.CSegment( segId );
|
|
|
|
|
|
|
|
std::unique_ptr<SCH_LINE> schLine =
|
|
|
|
std::make_unique<SCH_LINE>( seg.A, LAYER_WIRE );
|
|
|
|
schLine->SetEndPoint( seg.B );
|
|
|
|
|
|
|
|
createdItems.push_back( std::move( schLine ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
auto netAttr = get_opt( attributes, "NET" );
|
|
|
|
|
|
|
|
if( netAttr )
|
|
|
|
{
|
|
|
|
if( !netAttr->valVisible )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
VECTOR2I kpos = ScalePos( *netAttr->position );
|
|
|
|
VECTOR2I nearestPos = kpos;
|
|
|
|
SEG::ecoord min_dist_sq = VECTOR2I::ECOORD_MAX;
|
|
|
|
|
|
|
|
for( const SHAPE_LINE_CHAIN& chain : wireLines )
|
|
|
|
{
|
|
|
|
VECTOR2I nearestPt = chain.NearestPoint( kpos, false );
|
|
|
|
SEG::ecoord dist_sq = ( nearestPt - kpos ).SquaredEuclideanNorm();
|
|
|
|
|
|
|
|
if( dist_sq < min_dist_sq )
|
|
|
|
{
|
|
|
|
min_dist_sq = dist_sq;
|
|
|
|
nearestPos = nearestPt;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::unique_ptr<SCH_LABEL> label = std::make_unique<SCH_LABEL>();
|
|
|
|
|
|
|
|
label->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
|
|
|
|
label->SetVertJustify( GR_TEXT_V_ALIGN_BOTTOM );
|
|
|
|
|
|
|
|
for( double i = netAttr->rotation; i > 0; i -= 90 )
|
|
|
|
label->Rotate90( true );
|
|
|
|
|
|
|
|
label->SetPosition( nearestPos );
|
|
|
|
label->SetText( netAttr->value );
|
|
|
|
|
|
|
|
ApplyFontStyle( fontStyles, label, netAttr->fontStyle );
|
|
|
|
|
|
|
|
createdItems.push_back( std::move( label ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Adjust page to content
|
|
|
|
BOX2I sheetBBox;
|
|
|
|
|
|
|
|
for( std::unique_ptr<SCH_ITEM>& ptr : createdItems )
|
|
|
|
{
|
|
|
|
if( ptr->Type() == SCH_SYMBOL_T )
|
|
|
|
sheetBBox.Merge( static_cast<SCH_SYMBOL*>( ptr.get() )->GetBodyAndPinsBoundingBox() );
|
|
|
|
else
|
|
|
|
sheetBBox.Merge( ptr->GetBoundingBox() );
|
|
|
|
}
|
|
|
|
|
|
|
|
SCH_SCREEN* screen = aRootSheet->GetScreen();
|
|
|
|
PAGE_INFO pageInfo = screen->GetPageSettings();
|
|
|
|
|
|
|
|
int alignGrid = schIUScale.MilsToIU( 50 );
|
|
|
|
|
|
|
|
VECTOR2D offset( -sheetBBox.GetLeft(), -sheetBBox.GetTop() );
|
|
|
|
offset.x = KiROUND( offset.x / alignGrid ) * alignGrid;
|
|
|
|
offset.y = KiROUND( offset.y / alignGrid ) * alignGrid;
|
|
|
|
|
|
|
|
pageInfo.SetWidthMils( schIUScale.IUToMils( sheetBBox.GetWidth() ) );
|
|
|
|
pageInfo.SetHeightMils( schIUScale.IUToMils( sheetBBox.GetHeight() ) );
|
|
|
|
|
|
|
|
screen->SetPageSettings( pageInfo );
|
|
|
|
|
|
|
|
for( std::unique_ptr<SCH_ITEM>& ptr : createdItems )
|
|
|
|
{
|
|
|
|
ptr->Move( offset );
|
|
|
|
screen->Append( ptr.release() );
|
|
|
|
}
|
|
|
|
}
|