601 lines
16 KiB
C++
601 lines
16 KiB
C++
/*
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
*
|
|
* Copyright (C) 2007, 2008 Lubo Racko <developer@lura.sk>
|
|
* Copyright (C) 2008, 2012 Alexander Lunev <al.lunev@yahoo.com>
|
|
* Copyright (C) 2012-2021 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
|
|
*/
|
|
|
|
/**
|
|
* @file pcad2kicad_common.cpp
|
|
*/
|
|
|
|
#include <pcad/pcad2kicad_common.h>
|
|
|
|
#include <common.h>
|
|
#include <convert_to_biu.h>
|
|
#include <math/util.h> // for KiROUND
|
|
#include <trigo.h>
|
|
#include <xnode.h>
|
|
|
|
#include <wx/regex.h>
|
|
|
|
namespace PCAD2KICAD {
|
|
|
|
// PCAD stroke font average ratio of width to size
|
|
const double TEXT_WIDTH_TO_SIZE_AVERAGE = 0.5;
|
|
|
|
// PCAD proportions of stroke font
|
|
const double STROKE_HEIGHT_TO_SIZE = 0.656;
|
|
const double STROKE_WIDTH_TO_SIZE = 0.69;
|
|
|
|
// TrueType font
|
|
const double TRUETYPE_HEIGHT_TO_SIZE = 0.585;
|
|
const double TRUETYPE_WIDTH_TO_SIZE = 0.585;
|
|
const double TRUETYPE_THICK_PER_HEIGHT = 0.073;
|
|
const double TRUETYPE_BOLD_THICK_MUL = 1.6;
|
|
const long TRUETYPE_BOLD_MIN_WEIGHT = 700;
|
|
|
|
|
|
wxString GetWord( wxString* aStr )
|
|
{
|
|
wxString result = wxEmptyString;
|
|
|
|
*aStr = aStr->Trim( false );
|
|
|
|
if( aStr->Len() == 0 )
|
|
return result;
|
|
|
|
if( (*aStr)[0] == wxT( '"' ) )
|
|
{
|
|
result += (*aStr)[0];
|
|
*aStr = aStr->Mid( 1 ); // remove Frot apostrofe
|
|
|
|
while( aStr->Len() > 0 && (*aStr)[0] != wxT( '"' ) )
|
|
{
|
|
result += (*aStr)[0];
|
|
*aStr = aStr->Mid( 1 );
|
|
}
|
|
|
|
if( aStr->Len() > 0 && (*aStr)[0] == wxT( '"' ) )
|
|
{
|
|
result += (*aStr)[0];
|
|
*aStr = aStr->Mid( 1 ); // remove ending apostrophe
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while( aStr->Len() > 0
|
|
&& !( (*aStr)[0] == wxT( ' ' )
|
|
|| (*aStr)[0] == wxT( '(' )
|
|
|| (*aStr)[0] == wxT( ')' ) ) )
|
|
{
|
|
result += (*aStr)[0];
|
|
*aStr = aStr->Mid( 1 );
|
|
}
|
|
}
|
|
|
|
result.Trim( true );
|
|
result.Trim( false );
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
XNODE* FindPinMap( XNODE* aNode )
|
|
{
|
|
XNODE* result, * lNode;
|
|
|
|
result = nullptr;
|
|
lNode = FindNode( aNode, wxT( "attachedPattern" ) );
|
|
|
|
if( lNode )
|
|
result = FindNode( lNode, wxT( "padPinMap" ) );
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
double StrToDoublePrecisionUnits( const wxString& aStr, char aAxe,
|
|
const wxString& aActualConversion )
|
|
{
|
|
wxString ls;
|
|
double i;
|
|
char u;
|
|
|
|
ls = aStr;
|
|
ls.Trim( true );
|
|
ls.Trim( false );
|
|
|
|
if( ls.Len() > 0 )
|
|
{
|
|
u = ls[ls.Len() - 1];
|
|
|
|
while( ls.Len() > 0
|
|
&& !( ls[ls.Len() - 1] == wxT( '.' )
|
|
|| ls[ls.Len() - 1] == wxT( ',' )
|
|
|| (ls[ls.Len() - 1] >= wxT( '0' ) && ls[ls.Len() - 1] <= wxT( '9' ) ) ) )
|
|
{
|
|
ls = ls.Left( ls.Len() - 1 );
|
|
}
|
|
|
|
while( ls.Len() > 0
|
|
&& !( ls[0] == wxT( '-' )
|
|
|| ls[0] == wxT( '+' )
|
|
|| ls[0] == wxT( '.' )
|
|
|| ls[0] == wxT( ',' )
|
|
|| (ls[0] >= wxT( '0' ) && ls[0] <= wxT( '9' ) ) ) )
|
|
{
|
|
ls = ls.Mid( 1 );
|
|
}
|
|
|
|
if( u == wxT( 'm' ) )
|
|
{
|
|
ls.ToCDouble( &i );
|
|
|
|
#ifdef PCAD2KICAD_SCALE_SCH_TO_INCH_GRID
|
|
if( aActualConversion == wxT( "SCH" )
|
|
|| aActualConversion == wxT( "SCHLIB" ) )
|
|
i = i * (0.0254 / 0.025);
|
|
#endif
|
|
|
|
i = Millimeter2iu( i );
|
|
}
|
|
else
|
|
{
|
|
ls.ToCDouble( &i );
|
|
i = Mils2iu( i );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
i = 0.0;
|
|
}
|
|
|
|
if( ( aActualConversion == wxT( "PCB" ) || aActualConversion == wxT( "SCH" ) )
|
|
&& aAxe == wxT( 'Y' ) )
|
|
return -i;
|
|
else
|
|
return i; // Y axe is mirrored compared to P-Cad
|
|
}
|
|
|
|
|
|
int StrToIntUnits( const wxString& aStr, char aAxe, const wxString& aActualConversion )
|
|
{
|
|
return KiROUND( StrToDoublePrecisionUnits( aStr, aAxe, aActualConversion ) );
|
|
}
|
|
|
|
|
|
wxString GetAndCutWordWithMeasureUnits( wxString* aStr, const wxString& aDefaultMeasurementUnit )
|
|
{
|
|
wxString result;
|
|
|
|
aStr->Trim( false );
|
|
result = wxEmptyString;
|
|
|
|
// value
|
|
while( aStr->Len() > 0 && (*aStr)[0] != wxT( ' ' ) )
|
|
{
|
|
result += (*aStr)[0];
|
|
*aStr = aStr->Mid( 1 );
|
|
}
|
|
|
|
aStr->Trim( false );
|
|
|
|
// if there is also measurement unit
|
|
while( aStr->Len() > 0
|
|
&& ( ( (*aStr)[0] >= wxT( 'a' ) && (*aStr)[0] <= wxT( 'z' ) )
|
|
|| ( (*aStr)[0] >= wxT( 'A' ) && (*aStr)[0] <= wxT( 'Z' ) ) ) )
|
|
{
|
|
result += (*aStr)[0];
|
|
*aStr = aStr->Mid( 1 );
|
|
}
|
|
|
|
// and if not, add default....
|
|
if( result.Len() > 0
|
|
&& ( result[result.Len() - 1] == wxT( '.' )
|
|
|| result[result.Len() - 1] == wxT( ',' )
|
|
|| (result[result.Len() - 1] >= wxT( '0' )
|
|
&& result[result.Len() - 1] <= wxT( '9' ) ) ) )
|
|
{
|
|
result += aDefaultMeasurementUnit;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
int StrToInt1Units( const wxString& aStr )
|
|
{
|
|
double num, precision = 10;
|
|
|
|
aStr.ToCDouble( &num );
|
|
return KiROUND( num * precision );
|
|
}
|
|
|
|
|
|
wxString ValidateName( wxString aName )
|
|
{
|
|
aName.Replace( wxT( " " ), wxT( "_" ) );
|
|
|
|
return aName;
|
|
}
|
|
|
|
|
|
wxString ValidateReference( wxString aRef )
|
|
{
|
|
wxRegEx reRef;
|
|
reRef.Compile( wxT( "^[[:digit:]][[:digit:]]*$" ) );
|
|
|
|
if( reRef.Matches( aRef ) )
|
|
aRef.Prepend( wxT( '.' ) );
|
|
|
|
return aRef;
|
|
}
|
|
|
|
|
|
void SetWidth( wxString aStr, const wxString& aDefaultMeasurementUnit, int* aWidth,
|
|
const wxString& aActualConversion )
|
|
{
|
|
*aWidth = StrToIntUnits( GetAndCutWordWithMeasureUnits( &aStr, aDefaultMeasurementUnit ),
|
|
wxT( ' ' ), aActualConversion );
|
|
}
|
|
|
|
|
|
void SetHeight( wxString aStr, const wxString& aDefaultMeasurementUnit, int* aHeight,
|
|
const wxString& aActualConversion )
|
|
{
|
|
*aHeight = StrToIntUnits( GetAndCutWordWithMeasureUnits( &aStr, aDefaultMeasurementUnit ),
|
|
wxT( ' ' ), aActualConversion );
|
|
}
|
|
|
|
|
|
void SetPosition( wxString aStr, const wxString& aDefaultMeasurementUnit, int* aX, int* aY,
|
|
const wxString& aActualConversion )
|
|
{
|
|
*aX = StrToIntUnits( GetAndCutWordWithMeasureUnits( &aStr, aDefaultMeasurementUnit ),
|
|
wxT( 'X' ), aActualConversion );
|
|
*aY = StrToIntUnits( GetAndCutWordWithMeasureUnits( &aStr, aDefaultMeasurementUnit ),
|
|
wxT( 'Y' ), aActualConversion );
|
|
}
|
|
|
|
|
|
void SetDoublePrecisionPosition( wxString aStr, const wxString& aDefaultMeasurementUnit, double* aX,
|
|
double* aY, const wxString& aActualConversion )
|
|
{
|
|
*aX = StrToDoublePrecisionUnits(
|
|
GetAndCutWordWithMeasureUnits( &aStr, aDefaultMeasurementUnit ), wxT( 'X' ),
|
|
aActualConversion );
|
|
*aY = StrToDoublePrecisionUnits(
|
|
GetAndCutWordWithMeasureUnits( &aStr, aDefaultMeasurementUnit ), wxT( 'Y' ),
|
|
aActualConversion );
|
|
}
|
|
|
|
|
|
TTEXT_JUSTIFY GetJustifyIdentificator( const wxString& aJustify )
|
|
{
|
|
TTEXT_JUSTIFY id;
|
|
|
|
if( aJustify == wxT( "LowerCenter" ) )
|
|
id = LowerCenter;
|
|
else if( aJustify == wxT( "LowerRight" ) )
|
|
id = LowerRight;
|
|
else if( aJustify == wxT( "UpperLeft" ) )
|
|
id = UpperLeft;
|
|
else if( aJustify == wxT( "UpperCenter" ) )
|
|
id = UpperCenter;
|
|
else if( aJustify == wxT( "UpperRight" ) )
|
|
id = UpperRight;
|
|
else if( aJustify == wxT( "Left" ) )
|
|
id = Left;
|
|
else if( aJustify == wxT( "Center" ) )
|
|
id = Center;
|
|
else if( aJustify == wxT( "Right" ) )
|
|
id = Right;
|
|
else
|
|
id = LowerLeft;
|
|
|
|
return id;
|
|
}
|
|
|
|
|
|
void SetTextParameters( XNODE* aNode, TTEXTVALUE* aTextValue,
|
|
const wxString& aDefaultMeasurementUnit, const wxString& aActualConversion )
|
|
{
|
|
XNODE* tNode;
|
|
wxString str;
|
|
|
|
tNode = FindNode( aNode, wxT( "pt" ) );
|
|
|
|
if( tNode )
|
|
SetPosition( tNode->GetNodeContent(), aDefaultMeasurementUnit, &aTextValue->textPositionX,
|
|
&aTextValue->textPositionY, aActualConversion );
|
|
|
|
tNode = FindNode( aNode, wxT( "rotation" ) );
|
|
|
|
if( tNode )
|
|
{
|
|
str = tNode->GetNodeContent();
|
|
str.Trim( false );
|
|
aTextValue->textRotation = StrToInt1Units( str );
|
|
}
|
|
else
|
|
{
|
|
aTextValue->textRotation = 0;
|
|
}
|
|
|
|
str = FindNodeGetContent( aNode, wxT( "isVisible" ) );
|
|
|
|
if( str == wxT( "True" ) )
|
|
aTextValue->textIsVisible = 1;
|
|
else
|
|
aTextValue->textIsVisible = 0;
|
|
|
|
str = FindNodeGetContent( aNode, wxT( "justify" ) );
|
|
aTextValue->justify = GetJustifyIdentificator( str );
|
|
|
|
str = FindNodeGetContent( aNode, wxT( "isFlipped" ) );
|
|
|
|
if( str == wxT( "True" ) )
|
|
aTextValue->mirror = 1;
|
|
else
|
|
aTextValue->mirror = 0;
|
|
|
|
tNode = FindNode( aNode, wxT( "textStyleRef" ) );
|
|
|
|
if( tNode )
|
|
SetFontProperty( tNode, aTextValue, aDefaultMeasurementUnit, aActualConversion );
|
|
}
|
|
|
|
|
|
void SetFontProperty( XNODE* aNode, TTEXTVALUE* aTextValue, const wxString& aDefaultMeasurementUnit,
|
|
const wxString& aActualConversion )
|
|
{
|
|
wxString n, propValue;
|
|
|
|
aNode->GetAttribute( wxT( "Name" ), &n );
|
|
|
|
while( aNode->GetName() != wxT( "www.lura.sk" ) )
|
|
aNode = aNode->GetParent();
|
|
|
|
aNode = FindNode( aNode, wxT( "library" ) );
|
|
|
|
if( aNode )
|
|
aNode = FindNode( aNode, wxT( "textStyleDef" ) );
|
|
|
|
while( aNode )
|
|
{
|
|
aNode->GetAttribute( wxT( "Name" ), &propValue );
|
|
propValue.Trim( false );
|
|
propValue.Trim( true );
|
|
|
|
if( propValue == n )
|
|
break;
|
|
|
|
aNode = aNode->GetNext();
|
|
}
|
|
|
|
if( aNode )
|
|
{
|
|
wxString fontType;
|
|
|
|
propValue = FindNodeGetContent( aNode, wxT( "textStyleDisplayTType" ) );
|
|
aTextValue->isTrueType = ( propValue == wxT( "True" ) );
|
|
|
|
aNode = FindNode( aNode, wxT( "font" ) );
|
|
fontType = FindNodeGetContent( aNode, wxT( "fontType" ) );
|
|
|
|
if( ( aTextValue->isTrueType && ( fontType != wxT( "TrueType" ) ) ) ||
|
|
( !aTextValue->isTrueType && ( fontType != wxT( "Stroke" ) ) ) )
|
|
aNode = aNode->GetNext();
|
|
|
|
if( aNode )
|
|
{
|
|
if( aTextValue->isTrueType )
|
|
{
|
|
propValue = FindNodeGetContent( aNode, wxT( "fontItalic" ) );
|
|
aTextValue->isItalic = ( propValue == wxT( "True" ) );
|
|
|
|
propValue = FindNodeGetContent( aNode, wxT( "fontWeight" ) );
|
|
|
|
if( propValue != wxEmptyString )
|
|
{
|
|
long fontWeight;
|
|
|
|
propValue.ToLong( &fontWeight );
|
|
aTextValue->isBold = ( fontWeight >= TRUETYPE_BOLD_MIN_WEIGHT );
|
|
}
|
|
}
|
|
|
|
XNODE* lNode;
|
|
|
|
lNode = FindNode( aNode, wxT( "fontHeight" ) );
|
|
|
|
if( lNode )
|
|
SetHeight( lNode->GetNodeContent(), aDefaultMeasurementUnit,
|
|
&aTextValue->textHeight, aActualConversion );
|
|
|
|
if( aTextValue->isTrueType )
|
|
{
|
|
aTextValue->textstrokeWidth = TRUETYPE_THICK_PER_HEIGHT * aTextValue->textHeight;
|
|
|
|
if( aTextValue->isBold )
|
|
aTextValue->textstrokeWidth *= TRUETYPE_BOLD_THICK_MUL;
|
|
}
|
|
else
|
|
{
|
|
lNode = FindNode( aNode, wxT( "strokeWidth" ) );
|
|
|
|
if( lNode )
|
|
SetWidth( lNode->GetNodeContent(), aDefaultMeasurementUnit,
|
|
&aTextValue->textstrokeWidth, aActualConversion );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void SetTextJustify( EDA_TEXT* aText, TTEXT_JUSTIFY aJustify )
|
|
{
|
|
switch( aJustify )
|
|
{
|
|
case LowerLeft:
|
|
aText->SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM );
|
|
aText->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
|
|
break;
|
|
case LowerCenter:
|
|
aText->SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM );
|
|
aText->SetHorizJustify( GR_TEXT_HJUSTIFY_CENTER );
|
|
break;
|
|
case LowerRight:
|
|
aText->SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM );
|
|
aText->SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
|
|
break;
|
|
case UpperLeft:
|
|
aText->SetVertJustify( GR_TEXT_VJUSTIFY_TOP );
|
|
aText->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
|
|
break;
|
|
case UpperCenter:
|
|
aText->SetVertJustify( GR_TEXT_VJUSTIFY_TOP );
|
|
aText->SetHorizJustify( GR_TEXT_HJUSTIFY_CENTER );
|
|
break;
|
|
case UpperRight:
|
|
aText->SetVertJustify( GR_TEXT_VJUSTIFY_TOP );
|
|
aText->SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
|
|
break;
|
|
case Left:
|
|
aText->SetVertJustify( GR_TEXT_VJUSTIFY_CENTER );
|
|
aText->SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
|
|
break;
|
|
case Center:
|
|
aText->SetVertJustify( GR_TEXT_VJUSTIFY_CENTER );
|
|
aText->SetHorizJustify( GR_TEXT_HJUSTIFY_CENTER );
|
|
break;
|
|
case Right:
|
|
aText->SetVertJustify( GR_TEXT_VJUSTIFY_CENTER );
|
|
aText->SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
int CalculateTextLengthSize( TTEXTVALUE* aText )
|
|
{
|
|
return KiROUND( (double) aText->text.Len() *
|
|
(double) aText->textHeight * TEXT_WIDTH_TO_SIZE_AVERAGE );
|
|
}
|
|
|
|
|
|
void CorrectTextPosition( TTEXTVALUE* aValue )
|
|
{
|
|
int cm = aValue->mirror ? -1 : 1;
|
|
int cl = KiROUND( (double) CalculateTextLengthSize( aValue ) / 2.0 );
|
|
int ch = KiROUND( (double) aValue->textHeight / 2.0 );
|
|
int posX = 0;
|
|
int posY = 0;
|
|
|
|
if( aValue->justify == LowerLeft || aValue->justify == Left || aValue->justify == UpperLeft )
|
|
posX += cl * cm;
|
|
else if( aValue->justify == LowerRight || aValue->justify == Right ||
|
|
aValue->justify == UpperRight )
|
|
posX -= cl * cm;
|
|
|
|
if( aValue->justify == LowerLeft || aValue->justify == LowerCenter ||
|
|
aValue->justify == LowerRight )
|
|
posY -= ch;
|
|
else if( aValue->justify == UpperLeft || aValue->justify == UpperCenter ||
|
|
aValue->justify == UpperRight )
|
|
posY += ch;
|
|
|
|
RotatePoint( &posX, &posY, aValue->textRotation );
|
|
|
|
aValue->correctedPositionX = aValue->textPositionX + posX;
|
|
aValue->correctedPositionY = aValue->textPositionY + posY;
|
|
}
|
|
|
|
|
|
void SetTextSizeFromStrokeFontHeight( EDA_TEXT* aText, int aTextHeight )
|
|
{
|
|
aText->SetTextSize( wxSize( KiROUND( aTextHeight * STROKE_WIDTH_TO_SIZE ),
|
|
KiROUND( aTextHeight * STROKE_HEIGHT_TO_SIZE ) ) );
|
|
}
|
|
|
|
|
|
void SetTextSizeFromTrueTypeFontHeight( EDA_TEXT* aText, int aTextHeight )
|
|
{
|
|
aText->SetTextSize( wxSize( KiROUND( aTextHeight * TRUETYPE_WIDTH_TO_SIZE ),
|
|
KiROUND( aTextHeight * TRUETYPE_HEIGHT_TO_SIZE ) ) );
|
|
}
|
|
|
|
|
|
XNODE* FindNode( XNODE* aChild, const wxString& aTag )
|
|
{
|
|
aChild = aChild->GetChildren();
|
|
|
|
while( aChild )
|
|
{
|
|
if( aChild->GetName() == aTag )
|
|
return aChild;
|
|
|
|
aChild = aChild->GetNext();
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
|
|
wxString FindNodeGetContent( XNODE* aChild, const wxString& aTag )
|
|
{
|
|
wxString str = wxEmptyString;
|
|
|
|
aChild = FindNode( aChild, aTag );
|
|
|
|
if( aChild )
|
|
{
|
|
str = aChild->GetNodeContent();
|
|
str.Trim( false );
|
|
str.Trim( true );
|
|
}
|
|
|
|
return str;
|
|
}
|
|
|
|
|
|
void InitTTextValue( TTEXTVALUE* aTextValue )
|
|
{
|
|
aTextValue->text = wxEmptyString;
|
|
aTextValue->textPositionX = 0;
|
|
aTextValue->textPositionY = 0;
|
|
aTextValue->textRotation = 0;
|
|
aTextValue->textHeight = 0;
|
|
aTextValue->textstrokeWidth = 0;
|
|
aTextValue->textIsVisible = 0;
|
|
aTextValue->mirror = 0;
|
|
aTextValue->textUnit = 0;
|
|
aTextValue->correctedPositionX = 0;
|
|
aTextValue->correctedPositionY = 0;
|
|
aTextValue->justify = LowerLeft;
|
|
aTextValue->isBold = false;
|
|
aTextValue->isItalic = false;
|
|
aTextValue->isTrueType = false;
|
|
}
|
|
|
|
} // namespace PCAD2KICAD
|