KiCad PCB EDA Suite
pcad2kicad_common.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2007, 2008 Lubo Racko <developer@lura.sk>
5  * Copyright (C) 2008, 2012 Alexander Lunev <al.lunev@yahoo.com>
6  * Copyright (C) 2012-2021 KiCad Developers, see AUTHORS.txt for contributors.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, you may find one here:
20  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21  * or you may search the http://www.gnu.org website for the version 2 license,
22  * or you may write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25 
30 #include <pcad/pcad2kicad_common.h>
31 
32 #include <common.h>
33 #include <convert_to_biu.h>
34 #include <math/util.h> // for KiROUND
35 #include <trigo.h>
36 #include <xnode.h>
37 
38 #include <wx/regex.h>
39 
40 namespace PCAD2KICAD {
41 
42 // PCAD stroke font average ratio of width to size
43 const double TEXT_WIDTH_TO_SIZE_AVERAGE = 0.5;
44 
45 // PCAD proportions of stroke font
46 const double STROKE_HEIGHT_TO_SIZE = 0.656;
47 const double STROKE_WIDTH_TO_SIZE = 0.69;
48 
49 // TrueType font
50 const double TRUETYPE_HEIGHT_TO_SIZE = 0.585;
51 const double TRUETYPE_WIDTH_TO_SIZE = 0.585;
52 const double TRUETYPE_THICK_PER_HEIGHT = 0.073;
53 const double TRUETYPE_BOLD_THICK_MUL = 1.6;
54 const long TRUETYPE_BOLD_MIN_WEIGHT = 700;
55 
56 
57 wxString GetWord( wxString* aStr )
58 {
59  wxString result = wxEmptyString;
60 
61  *aStr = aStr->Trim( false );
62 
63  if( aStr->Len() == 0 )
64  return result;
65 
66  if( (*aStr)[0] == wxT( '"' ) )
67  {
68  result += (*aStr)[0];
69  *aStr = aStr->Mid( 1 ); // remove Frot apostrofe
70 
71  while( aStr->Len() > 0 && (*aStr)[0] != wxT( '"' ) )
72  {
73  result += (*aStr)[0];
74  *aStr = aStr->Mid( 1 );
75  }
76 
77  if( aStr->Len() > 0 && (*aStr)[0] == wxT( '"' ) )
78  {
79  result += (*aStr)[0];
80  *aStr = aStr->Mid( 1 ); // remove ending apostrophe
81  }
82  }
83  else
84  {
85  while( aStr->Len() > 0
86  && !( (*aStr)[0] == wxT( ' ' )
87  || (*aStr)[0] == wxT( '(' )
88  || (*aStr)[0] == wxT( ')' ) ) )
89  {
90  result += (*aStr)[0];
91  *aStr = aStr->Mid( 1 );
92  }
93  }
94 
95  result.Trim( true );
96  result.Trim( false );
97 
98  return result;
99 }
100 
101 
103 {
104  XNODE* result, * lNode;
105 
106  result = nullptr;
107  lNode = FindNode( aNode, wxT( "attachedPattern" ) );
108 
109  if( lNode )
110  result = FindNode( lNode, wxT( "padPinMap" ) );
111 
112  return result;
113 }
114 
115 
116 double StrToDoublePrecisionUnits( const wxString& aStr, char aAxe,
117  const wxString& aActualConversion )
118 {
119  wxString ls;
120  double i;
121  char u;
122 
123  ls = aStr;
124  ls.Trim( true );
125  ls.Trim( false );
126 
127  if( ls.Len() > 0 )
128  {
129  u = ls[ls.Len() - 1];
130 
131  while( ls.Len() > 0
132  && !( ls[ls.Len() - 1] == wxT( '.' )
133  || ls[ls.Len() - 1] == wxT( ',' )
134  || (ls[ls.Len() - 1] >= wxT( '0' ) && ls[ls.Len() - 1] <= wxT( '9' ) ) ) )
135  {
136  ls = ls.Left( ls.Len() - 1 );
137  }
138 
139  while( ls.Len() > 0
140  && !( ls[0] == wxT( '-' )
141  || ls[0] == wxT( '+' )
142  || ls[0] == wxT( '.' )
143  || ls[0] == wxT( ',' )
144  || (ls[0] >= wxT( '0' ) && ls[0] <= wxT( '9' ) ) ) )
145  {
146  ls = ls.Mid( 1 );
147  }
148 
149  if( u == wxT( 'm' ) )
150  {
151  ls.ToCDouble( &i );
152 
153 #ifdef PCAD2KICAD_SCALE_SCH_TO_INCH_GRID
154  if( aActualConversion == wxT( "SCH" )
155  || aActualConversion == wxT( "SCHLIB" ) )
156  i = i * (0.0254 / 0.025);
157 #endif
158 
159  i = Millimeter2iu( i );
160  }
161  else
162  {
163  ls.ToCDouble( &i );
164  i = Mils2iu( i );
165  }
166  }
167  else
168  {
169  i = 0.0;
170  }
171 
172  if( ( aActualConversion == wxT( "PCB" ) || aActualConversion == wxT( "SCH" ) )
173  && aAxe == wxT( 'Y' ) )
174  return -i;
175  else
176  return i; // Y axe is mirrored compared to P-Cad
177 }
178 
179 
180 int StrToIntUnits( const wxString& aStr, char aAxe, const wxString& aActualConversion )
181 {
182  return KiROUND( StrToDoublePrecisionUnits( aStr, aAxe, aActualConversion ) );
183 }
184 
185 
186 wxString GetAndCutWordWithMeasureUnits( wxString* aStr, const wxString& aDefaultMeasurementUnit )
187 {
188  wxString result;
189 
190  aStr->Trim( false );
191  result = wxEmptyString;
192 
193  // value
194  while( aStr->Len() > 0 && (*aStr)[0] != wxT( ' ' ) )
195  {
196  result += (*aStr)[0];
197  *aStr = aStr->Mid( 1 );
198  }
199 
200  aStr->Trim( false );
201 
202  // if there is also measurement unit
203  while( aStr->Len() > 0
204  && ( ( (*aStr)[0] >= wxT( 'a' ) && (*aStr)[0] <= wxT( 'z' ) )
205  || ( (*aStr)[0] >= wxT( 'A' ) && (*aStr)[0] <= wxT( 'Z' ) ) ) )
206  {
207  result += (*aStr)[0];
208  *aStr = aStr->Mid( 1 );
209  }
210 
211  // and if not, add default....
212  if( result.Len() > 0
213  && ( result[result.Len() - 1] == wxT( '.' )
214  || result[result.Len() - 1] == wxT( ',' )
215  || (result[result.Len() - 1] >= wxT( '0' )
216  && result[result.Len() - 1] <= wxT( '9' ) ) ) )
217  {
218  result += aDefaultMeasurementUnit;
219  }
220 
221  return result;
222 }
223 
224 
225 int StrToInt1Units( const wxString& aStr )
226 {
227  double num, precision = 10;
228 
229  aStr.ToCDouble( &num );
230  return KiROUND( num * precision );
231 }
232 
233 
234 wxString ValidateName( wxString aName )
235 {
236  aName.Replace( wxT( " " ), wxT( "_" ) );
237 
238  return aName;
239 }
240 
241 
242 wxString ValidateReference( wxString aRef )
243 {
244  wxRegEx reRef;
245  reRef.Compile( wxT( "^[[:digit:]][[:digit:]]*$" ) );
246 
247  if( reRef.Matches( aRef ) )
248  aRef.Prepend( wxT( '.' ) );
249 
250  return aRef;
251 }
252 
253 
254 void SetWidth( wxString aStr, const wxString& aDefaultMeasurementUnit, int* aWidth,
255  const wxString& aActualConversion )
256 {
257  *aWidth = StrToIntUnits( GetAndCutWordWithMeasureUnits( &aStr, aDefaultMeasurementUnit ),
258  wxT( ' ' ), aActualConversion );
259 }
260 
261 
262 void SetHeight( wxString aStr, const wxString& aDefaultMeasurementUnit, int* aHeight,
263  const wxString& aActualConversion )
264 {
265  *aHeight = StrToIntUnits( GetAndCutWordWithMeasureUnits( &aStr, aDefaultMeasurementUnit ),
266  wxT( ' ' ), aActualConversion );
267 }
268 
269 
270 void SetPosition( wxString aStr, const wxString& aDefaultMeasurementUnit, int* aX, int* aY,
271  const wxString& aActualConversion )
272 {
273  *aX = StrToIntUnits( GetAndCutWordWithMeasureUnits( &aStr, aDefaultMeasurementUnit ),
274  wxT( 'X' ), aActualConversion );
275  *aY = StrToIntUnits( GetAndCutWordWithMeasureUnits( &aStr, aDefaultMeasurementUnit ),
276  wxT( 'Y' ), aActualConversion );
277 }
278 
279 
280 void SetDoublePrecisionPosition( wxString aStr, const wxString& aDefaultMeasurementUnit, double* aX,
281  double* aY, const wxString& aActualConversion )
282 {
284  GetAndCutWordWithMeasureUnits( &aStr, aDefaultMeasurementUnit ), wxT( 'X' ),
285  aActualConversion );
287  GetAndCutWordWithMeasureUnits( &aStr, aDefaultMeasurementUnit ), wxT( 'Y' ),
288  aActualConversion );
289 }
290 
291 
292 TTEXT_JUSTIFY GetJustifyIdentificator( const wxString& aJustify )
293 {
294  TTEXT_JUSTIFY id;
295 
296  if( aJustify == wxT( "LowerCenter" ) )
297  id = LowerCenter;
298  else if( aJustify == wxT( "LowerRight" ) )
299  id = LowerRight;
300  else if( aJustify == wxT( "UpperLeft" ) )
301  id = UpperLeft;
302  else if( aJustify == wxT( "UpperCenter" ) )
303  id = UpperCenter;
304  else if( aJustify == wxT( "UpperRight" ) )
305  id = UpperRight;
306  else if( aJustify == wxT( "Left" ) )
307  id = Left;
308  else if( aJustify == wxT( "Center" ) )
309  id = Center;
310  else if( aJustify == wxT( "Right" ) )
311  id = Right;
312  else
313  id = LowerLeft;
314 
315  return id;
316 }
317 
318 
319 void SetTextParameters( XNODE* aNode, TTEXTVALUE* aTextValue,
320  const wxString& aDefaultMeasurementUnit, const wxString& aActualConversion )
321 {
322  XNODE* tNode;
323  wxString str;
324 
325  tNode = FindNode( aNode, wxT( "pt" ) );
326 
327  if( tNode )
328  SetPosition( tNode->GetNodeContent(), aDefaultMeasurementUnit, &aTextValue->textPositionX,
329  &aTextValue->textPositionY, aActualConversion );
330 
331  tNode = FindNode( aNode, wxT( "rotation" ) );
332 
333  if( tNode )
334  {
335  str = tNode->GetNodeContent();
336  str.Trim( false );
337  aTextValue->textRotation = StrToInt1Units( str );
338  }
339  else
340  {
341  aTextValue->textRotation = 0;
342  }
343 
344  str = FindNodeGetContent( aNode, wxT( "isVisible" ) );
345 
346  if( str == wxT( "True" ) )
347  aTextValue->textIsVisible = 1;
348  else
349  aTextValue->textIsVisible = 0;
350 
351  str = FindNodeGetContent( aNode, wxT( "justify" ) );
352  aTextValue->justify = GetJustifyIdentificator( str );
353 
354  str = FindNodeGetContent( aNode, wxT( "isFlipped" ) );
355 
356  if( str == wxT( "True" ) )
357  aTextValue->mirror = 1;
358  else
359  aTextValue->mirror = 0;
360 
361  tNode = FindNode( aNode, wxT( "textStyleRef" ) );
362 
363  if( tNode )
364  SetFontProperty( tNode, aTextValue, aDefaultMeasurementUnit, aActualConversion );
365 }
366 
367 
368 void SetFontProperty( XNODE* aNode, TTEXTVALUE* aTextValue, const wxString& aDefaultMeasurementUnit,
369  const wxString& aActualConversion )
370 {
371  wxString n, propValue;
372 
373  aNode->GetAttribute( wxT( "Name" ), &n );
374 
375  while( aNode->GetName() != wxT( "www.lura.sk" ) )
376  aNode = aNode->GetParent();
377 
378  aNode = FindNode( aNode, wxT( "library" ) );
379 
380  if( aNode )
381  aNode = FindNode( aNode, wxT( "textStyleDef" ) );
382 
383  while( aNode )
384  {
385  aNode->GetAttribute( wxT( "Name" ), &propValue );
386  propValue.Trim( false );
387  propValue.Trim( true );
388 
389  if( propValue == n )
390  break;
391 
392  aNode = aNode->GetNext();
393  }
394 
395  if( aNode )
396  {
397  wxString fontType;
398 
399  propValue = FindNodeGetContent( aNode, wxT( "textStyleDisplayTType" ) );
400  aTextValue->isTrueType = ( propValue == wxT( "True" ) );
401 
402  aNode = FindNode( aNode, wxT( "font" ) );
403  fontType = FindNodeGetContent( aNode, wxT( "fontType" ) );
404 
405  if( ( aTextValue->isTrueType && ( fontType != wxT( "TrueType" ) ) ) ||
406  ( !aTextValue->isTrueType && ( fontType != wxT( "Stroke" ) ) ) )
407  aNode = aNode->GetNext();
408 
409  if( aNode )
410  {
411  if( aTextValue->isTrueType )
412  {
413  propValue = FindNodeGetContent( aNode, wxT( "fontItalic" ) );
414  aTextValue->isItalic = ( propValue == wxT( "True" ) );
415 
416  propValue = FindNodeGetContent( aNode, wxT( "fontWeight" ) );
417 
418  if( propValue != wxEmptyString )
419  {
420  long fontWeight;
421 
422  propValue.ToLong( &fontWeight );
423  aTextValue->isBold = ( fontWeight >= TRUETYPE_BOLD_MIN_WEIGHT );
424  }
425  }
426 
427  XNODE* lNode;
428 
429  lNode = FindNode( aNode, wxT( "fontHeight" ) );
430 
431  if( lNode )
432  SetHeight( lNode->GetNodeContent(), aDefaultMeasurementUnit,
433  &aTextValue->textHeight, aActualConversion );
434 
435  if( aTextValue->isTrueType )
436  {
437  aTextValue->textstrokeWidth = TRUETYPE_THICK_PER_HEIGHT * aTextValue->textHeight;
438 
439  if( aTextValue->isBold )
441  }
442  else
443  {
444  lNode = FindNode( aNode, wxT( "strokeWidth" ) );
445 
446  if( lNode )
447  SetWidth( lNode->GetNodeContent(), aDefaultMeasurementUnit,
448  &aTextValue->textstrokeWidth, aActualConversion );
449  }
450  }
451  }
452 }
453 
454 
455 void SetTextJustify( EDA_TEXT* aText, TTEXT_JUSTIFY aJustify )
456 {
457  switch( aJustify )
458  {
459  case LowerLeft:
462  break;
463  case LowerCenter:
466  break;
467  case LowerRight:
470  break;
471  case UpperLeft:
474  break;
475  case UpperCenter:
478  break;
479  case UpperRight:
482  break;
483  case Left:
486  break;
487  case Center:
490  break;
491  case Right:
494  break;
495  }
496 }
497 
498 
500 {
501  return KiROUND( (double) aText->text.Len() *
502  (double) aText->textHeight * TEXT_WIDTH_TO_SIZE_AVERAGE );
503 }
504 
505 
507 {
508  int cm = aValue->mirror ? -1 : 1;
509  int cl = KiROUND( (double) CalculateTextLengthSize( aValue ) / 2.0 );
510  int ch = KiROUND( (double) aValue->textHeight / 2.0 );
511  int posX = 0;
512  int posY = 0;
513 
514  if( aValue->justify == LowerLeft || aValue->justify == Left || aValue->justify == UpperLeft )
515  posX += cl * cm;
516  else if( aValue->justify == LowerRight || aValue->justify == Right ||
517  aValue->justify == UpperRight )
518  posX -= cl * cm;
519 
520  if( aValue->justify == LowerLeft || aValue->justify == LowerCenter ||
521  aValue->justify == LowerRight )
522  posY -= ch;
523  else if( aValue->justify == UpperLeft || aValue->justify == UpperCenter ||
524  aValue->justify == UpperRight )
525  posY += ch;
526 
527  RotatePoint( &posX, &posY, aValue->textRotation );
528 
529  aValue->correctedPositionX = aValue->textPositionX + posX;
530  aValue->correctedPositionY = aValue->textPositionY + posY;
531 }
532 
533 
534 void SetTextSizeFromStrokeFontHeight( EDA_TEXT* aText, int aTextHeight )
535 {
536  aText->SetTextSize( wxSize( KiROUND( aTextHeight * STROKE_WIDTH_TO_SIZE ),
537  KiROUND( aTextHeight * STROKE_HEIGHT_TO_SIZE ) ) );
538 }
539 
540 
541 void SetTextSizeFromTrueTypeFontHeight( EDA_TEXT* aText, int aTextHeight )
542 {
543  aText->SetTextSize( wxSize( KiROUND( aTextHeight * TRUETYPE_WIDTH_TO_SIZE ),
544  KiROUND( aTextHeight * TRUETYPE_HEIGHT_TO_SIZE ) ) );
545 }
546 
547 
548 XNODE* FindNode( XNODE* aChild, const wxString& aTag )
549 {
550  aChild = aChild->GetChildren();
551 
552  while( aChild )
553  {
554  if( aChild->GetName() == aTag )
555  return aChild;
556 
557  aChild = aChild->GetNext();
558  }
559 
560  return nullptr;
561 }
562 
563 
564 wxString FindNodeGetContent( XNODE* aChild, const wxString& aTag )
565 {
566  wxString str = wxEmptyString;
567 
568  aChild = FindNode( aChild, aTag );
569 
570  if( aChild )
571  {
572  str = aChild->GetNodeContent();
573  str.Trim( false );
574  str.Trim( true );
575  }
576 
577  return str;
578 }
579 
580 
581 void InitTTextValue( TTEXTVALUE* aTextValue )
582 {
583  aTextValue->text = wxEmptyString;
584  aTextValue->textPositionX = 0;
585  aTextValue->textPositionY = 0;
586  aTextValue->textRotation = 0;
587  aTextValue->textHeight = 0;
588  aTextValue->textstrokeWidth = 0;
589  aTextValue->textIsVisible = 0;
590  aTextValue->mirror = 0;
591  aTextValue->textUnit = 0;
592  aTextValue->correctedPositionX = 0;
593  aTextValue->correctedPositionY = 0;
594  aTextValue->justify = LowerLeft;
595  aTextValue->isBold = false;
596  aTextValue->isItalic = false;
597  aTextValue->isTrueType = false;
598 }
599 
600 } // namespace PCAD2KICAD
const long TRUETYPE_BOLD_MIN_WEIGHT
wxString GetWord(wxString *aStr)
void SetFontProperty(XNODE *aNode, TTEXTVALUE *aTextValue, const wxString &aDefaultMeasurementUnit, const wxString &aActualConversion)
void SetPosition(wxString aStr, const wxString &aDefaultMeasurementUnit, int *aX, int *aY, const wxString &aActualConversion)
double StrToDoublePrecisionUnits(const wxString &aStr, char aAxe, const wxString &aActualConversion)
const double TRUETYPE_BOLD_THICK_MUL
const double TEXT_WIDTH_TO_SIZE_AVERAGE
const double TRUETYPE_THICK_PER_HEIGHT
wxString GetAndCutWordWithMeasureUnits(wxString *aStr, const wxString &aDefaultMeasurementUnit)
void SetWidth(wxString aStr, const wxString &aDefaultMeasurementUnit, int *aWidth, const wxString &aActualConversion)
void SetHeight(wxString aStr, const wxString &aDefaultMeasurementUnit, int *aHeight, const wxString &aActualConversion)
void SetTextSize(const wxSize &aNewSize)
Definition: eda_text.h:237
const double TRUETYPE_WIDTH_TO_SIZE
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:228
void SetTextSizeFromTrueTypeFontHeight(EDA_TEXT *aText, int aTextHeight)
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition: eda_text.h:119
wxString ValidateName(wxString aName)
int CalculateTextLengthSize(TTEXTVALUE *aText)
XNODE * GetChildren() const
Definition: xnode.h:62
const double STROKE_WIDTH_TO_SIZE
XNODE * GetParent() const
Definition: xnode.h:72
wxString FindNodeGetContent(XNODE *aChild, const wxString &aTag)
void SetVertJustify(EDA_TEXT_VJUSTIFY_T aType)
Definition: eda_text.h:202
void SetTextParameters(XNODE *aNode, TTEXTVALUE *aTextValue, const wxString &aDefaultMeasurementUnit, const wxString &aActualConversion)
wxString ValidateReference(wxString aRef)
const double STROKE_HEIGHT_TO_SIZE
void SetDoublePrecisionPosition(wxString aStr, const wxString &aDefaultMeasurementUnit, double *aX, double *aY, const wxString &aActualConversion)
int StrToIntUnits(const wxString &aStr, char aAxe, const wxString &aActualConversion)
Hold an XML or S-expression element.
Definition: xnode.h:43
void SetTextJustify(EDA_TEXT *aText, TTEXT_JUSTIFY aJustify)
const double TRUETYPE_HEIGHT_TO_SIZE
XNODE * GetNext() const
Definition: xnode.h:67
void SetHorizJustify(EDA_TEXT_HJUSTIFY_T aType)
Definition: eda_text.h:201
void CorrectTextPosition(TTEXTVALUE *aValue)
TTEXT_JUSTIFY GetJustifyIdentificator(const wxString &aJustify)
XNODE * FindNode(XNODE *aChild, const wxString &aTag)
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:73
void InitTTextValue(TTEXTVALUE *aTextValue)
The common library.
void SetTextSizeFromStrokeFontHeight(EDA_TEXT *aText, int aTextHeight)
XNODE * FindPinMap(XNODE *aNode)
static constexpr int Millimeter2iu(double mm)
int StrToInt1Units(const wxString &aStr)