/* * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2007, 2008 Lubo Racko * Copyright (C) 2008, 2012 Alexander Lunev * 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 #include #include #include // for KiROUND #include #include #include 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( const wxString& aName ) { wxString retv = aName; retv.Replace( wxT( " " ), wxT( "_" ) ); return retv; } wxString ValidateReference( const wxString& aRef ) { wxRegEx reRef; reRef.Compile( wxT( "^[[:digit:]][[:digit:]]*$" ) ); wxString retv = aRef; if( reRef.Matches( retv ) ) retv.Prepend( wxT( '.' ) ); return retv; } void SetWidth( const wxString& aStr, const wxString& aDefaultMeasurementUnit, int* aWidth, const wxString& aActualConversion ) { wxString tmp = aStr; *aWidth = StrToIntUnits( GetAndCutWordWithMeasureUnits( &tmp, aDefaultMeasurementUnit ), wxT( ' ' ), aActualConversion ); } void SetHeight( const wxString& aStr, const wxString& aDefaultMeasurementUnit, int* aHeight, const wxString& aActualConversion ) { wxString tmp = aStr; *aHeight = StrToIntUnits( GetAndCutWordWithMeasureUnits( &tmp, aDefaultMeasurementUnit ), wxT( ' ' ), aActualConversion ); } void SetPosition( const wxString& aStr, const wxString& aDefaultMeasurementUnit, int* aX, int* aY, const wxString& aActualConversion ) { wxString tmp = aStr; *aX = StrToIntUnits( GetAndCutWordWithMeasureUnits( &tmp, aDefaultMeasurementUnit ), wxT( 'X' ), aActualConversion ); *aY = StrToIntUnits( GetAndCutWordWithMeasureUnits( &tmp, aDefaultMeasurementUnit ), wxT( 'Y' ), aActualConversion ); } void SetDoublePrecisionPosition( const wxString& aStr, const wxString& aDefaultMeasurementUnit, double* aX, double* aY, const wxString& aActualConversion ) { wxString tmp = aStr; *aX = StrToDoublePrecisionUnits( GetAndCutWordWithMeasureUnits( &tmp, aDefaultMeasurementUnit ), wxT( 'X' ), aActualConversion ); *aY = StrToDoublePrecisionUnits( GetAndCutWordWithMeasureUnits( &tmp, 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