KiCad PCB EDA Suite
base_units.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) 2012 CERN
5  * Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
6  *
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 
37 #include <base_units.h>
38 #include <common.h>
39 #include <kicad_string.h>
40 #include <math/util.h> // for KiROUND
41 #include <macros.h>
42 #include <title_block.h>
43 
44 #if defined( PCBNEW ) || defined( CVPCB ) || defined( EESCHEMA ) || defined( GERBVIEW ) || defined( PL_EDITOR )
45 #define IU_TO_MM( x ) ( x / IU_PER_MM )
46 #define IU_TO_IN( x ) ( x / IU_PER_MILS / 1000 )
47 #define IU_TO_MILS( x ) ( x / IU_PER_MILS )
48 #define MM_TO_IU( x ) ( x * IU_PER_MM )
49 #define IN_TO_IU( x ) ( x * IU_PER_MILS * 1000 )
50 #define MILS_TO_IU( x ) ( x * IU_PER_MILS )
51 #else
52 #error "Cannot resolve internal units due to no definition of EESCHEMA, CVPCB or PCBNEW."
53 #endif
54 
55 
56 double To_User_Unit( EDA_UNITS aUnit, double aValue )
57 {
58  switch( aUnit )
59  {
61  return IU_TO_MM( aValue );
62 
63  case EDA_UNITS::MILS:
64  return IU_TO_MILS( aValue );
65 
66  case EDA_UNITS::INCHES:
67  return IU_TO_IN( aValue );
68 
69  case EDA_UNITS::DEGREES:
70  return aValue / 10.0f;
71 
72  default:
73  return aValue;
74  }
75 }
76 
89 // A lower-precision (for readability) version of StringFromValue()
90 wxString MessageTextFromValue( EDA_UNITS aUnits, int aValue, bool aAddUnitLabel,
91  EDA_DATA_TYPE aType )
92 {
93  return MessageTextFromValue( aUnits, double( aValue ), aAddUnitLabel, aType );
94 }
95 
96 
97 // A lower-precision (for readability) version of StringFromValue()
98 wxString MessageTextFromValue( EDA_UNITS aUnits, long long int aValue, bool aAddUnitLabel,
99  EDA_DATA_TYPE aType )
100 {
101  return MessageTextFromValue( aUnits, double( aValue ), aAddUnitLabel, aType );
102 }
103 
104 
105 // A lower-precision (for readability) version of StringFromValue()
106 wxString MessageTextFromValue( EDA_UNITS aUnits, double aValue, bool aAddUnitLabel,
107  EDA_DATA_TYPE aType )
108 {
109  wxString text;
110  const wxChar* format;
111  double value = aValue;
112 
113  switch( aType )
114  {
116  value = To_User_Unit( aUnits, value );
117  // Fall through to continue computation
119 
120  case EDA_DATA_TYPE::AREA:
121  value = To_User_Unit( aUnits, value );
122  // Fall through to continue computation
124 
126  value = To_User_Unit( aUnits, value );
127  }
128 
129  switch( aUnits )
130  {
131  default:
133 #if defined( EESCHEMA )
134  format = wxT( "%.2f" );
135 #else
136  format = wxT( "%.4f" );
137 #endif
138  break;
139 
140  case EDA_UNITS::MILS:
141 #if defined( EESCHEMA )
142  format = wxT( "%.0f" );
143 #else
144  format = wxT( "%.2f" );
145 #endif
146  break;
147 
148  case EDA_UNITS::INCHES:
149 #if defined( EESCHEMA )
150  format = wxT( "%.3f" );
151 #else
152  format = wxT( "%.4f" );
153 #endif
154  break;
155 
156  case EDA_UNITS::DEGREES:
157  // 3 digits in mantissa should be good for rotation in degree
158  format = wxT( "%.3f" );
159  break;
160 
161  case EDA_UNITS::UNSCALED:
162  format = wxT( "%.0f" );
163  break;
164  }
165 
166  text.Printf( format, value );
167 
168  if( aAddUnitLabel )
169  {
170  text += " ";
171  text += GetAbbreviatedUnitsLabel( aUnits, aType );
172  }
173 
174  return text;
175 }
176 
177 
190 wxString StringFromValue( EDA_UNITS aUnits, double aValue, bool aAddUnitSymbol,
191  EDA_DATA_TYPE aType )
192 {
193  double value_to_print = aValue;
194 
195  switch( aType )
196  {
198  value_to_print = To_User_Unit( aUnits, value_to_print );
200 
201  case EDA_DATA_TYPE::AREA:
202  value_to_print = To_User_Unit( aUnits, value_to_print );
204 
206  value_to_print = To_User_Unit( aUnits, value_to_print );
207  }
208 
209 
210  char buf[50];
211  int len;
212 
213  if( value_to_print != 0.0 && fabs( value_to_print ) <= 0.0001 )
214  {
215  len = sprintf( buf, "%.10f", value_to_print );
216 
217  while( --len > 0 && buf[len] == '0' )
218  buf[len] = '\0';
219 
220  if( buf[len]=='.' || buf[len]==',' )
221  buf[len] = '\0';
222  else
223  ++len;
224  }
225  else
226  {
227  if( aUnits == EDA_UNITS::MILS )
228  len = sprintf( buf, "%.7g", value_to_print );
229  else
230  len = sprintf( buf, "%.10g", value_to_print );
231  }
232 
233  wxString stringValue( buf, wxConvUTF8 );
234 
235  if( aAddUnitSymbol )
236  {
237  switch( aUnits )
238  {
240  stringValue += wxT( " mm" );
241  break;
242 
243  case EDA_UNITS::DEGREES:
244  stringValue += wxT( " deg" );
245  break;
246 
247  case EDA_UNITS::MILS:
248  stringValue += wxT( " mils" );
249  break;
250 
251  case EDA_UNITS::INCHES:
252  stringValue += wxT( " in" );
253  break;
254 
255  case EDA_UNITS::PERCENT:
256  stringValue += wxT( "%" );
257  break;
258 
259  case EDA_UNITS::UNSCALED:
260  break;
261  }
262  }
263 
264  return stringValue;
265 }
266 
267 
268 double From_User_Unit( EDA_UNITS aUnits, double aValue )
269 {
270  switch( aUnits )
271  {
273  return MM_TO_IU( aValue );
274 
275  case EDA_UNITS::MILS:
276  return MILS_TO_IU( aValue );
277 
278  case EDA_UNITS::INCHES:
279  return IN_TO_IU( aValue );
280 
281  case EDA_UNITS::DEGREES:
282  // Convert to "decidegrees"
283  return aValue * 10;
284 
285  default:
286  case EDA_UNITS::UNSCALED:
287  case EDA_UNITS::PERCENT:
288  return aValue;
289  }
290 }
291 
292 
293 double DoubleValueFromString( EDA_UNITS aUnits, const wxString& aTextValue, EDA_DATA_TYPE aType )
294 {
295  double dtmp = 0;
296 
297  // Acquire the 'right' decimal point separator
298  const struct lconv* lc = localeconv();
299 
300  wxChar decimal_point = lc->decimal_point[0];
301  wxString buf( aTextValue.Strip( wxString::both ) );
302 
303  // Convert any entered decimal point separators to the 'right' one
304  buf.Replace( wxT( "." ), wxString( decimal_point, 1 ) );
305  buf.Replace( wxT( "," ), wxString( decimal_point, 1 ) );
306 
307  // Find the end of the numeric part
308  unsigned brk_point = 0;
309 
310  while( brk_point < buf.Len() )
311  {
312  wxChar ch = buf[brk_point];
313 
314  if( !( (ch >= '0' && ch <= '9') || (ch == decimal_point) || (ch == '-') || (ch == '+') ) )
315  break;
316 
317  ++brk_point;
318  }
319 
320  // Extract the numeric part
321  buf.Left( brk_point ).ToDouble( &dtmp );
322 
323  // Check the optional unit designator (2 ch significant)
324  wxString unit( buf.Mid( brk_point ).Strip( wxString::leading ).Left( 2 ).Lower() );
325 
326  if( aUnits == EDA_UNITS::MILLIMETRES || aUnits == EDA_UNITS::MILS
327  || aUnits == EDA_UNITS::INCHES )
328  {
329  if( unit == wxT( "mm" ) )
330  {
331  aUnits = EDA_UNITS::MILLIMETRES;
332  }
333  else if( unit == wxT( "mi" ) || unit == wxT( "th" ) )
334  {
335  aUnits = EDA_UNITS::MILS;
336  }
337  else if( unit == wxT( "in" ) || unit == wxT( "\"" ) )
338  {
339  aUnits = EDA_UNITS::INCHES;
340  }
341  else if( unit == "oz" ) // 1 oz = 1.37 mils
342  {
343  aUnits = EDA_UNITS::MILS;
344  dtmp *= 1.37;
345  }
346  }
347  else if( aUnits == EDA_UNITS::DEGREES )
348  {
349  if( unit == wxT( "ra" ) ) // Radians
350  {
351  dtmp *= 180.0f / M_PI;
352  }
353  }
354 
355  switch( aType )
356  {
358  dtmp = From_User_Unit( aUnits, dtmp );
360 
361  case EDA_DATA_TYPE::AREA:
362  dtmp = From_User_Unit( aUnits, dtmp );
364 
366  dtmp = From_User_Unit( aUnits, dtmp );
367  }
368 
369  return dtmp;
370 }
371 
372 
373 void FetchUnitsFromString( const wxString& aTextValue, EDA_UNITS& aUnits )
374 {
375  wxString buf( aTextValue.Strip( wxString::both ) );
376  unsigned brk_point = 0;
377 
378  while( brk_point < buf.Len() )
379  {
380  wxChar c = buf[brk_point];
381 
382  if( !( (c >= '0' && c <='9') || (c == '.') || (c == ',') || (c == '-') || (c == '+') ) )
383  break;
384 
385  ++brk_point;
386  }
387 
388  // Check the unit designator (2 ch significant)
389  wxString unit( buf.Mid( brk_point ).Strip( wxString::leading ).Left( 2 ).Lower() );
390 
391  if( unit == wxT( "mm" ) )
392  aUnits = EDA_UNITS::MILLIMETRES;
393  else if( unit == wxT( "mi" ) || unit == wxT( "th" ) ) // "mils" or "thou"
394  aUnits = EDA_UNITS::MILS;
395  else if( unit == wxT( "in" ) || unit == wxT( "\"" ) )
396  aUnits = EDA_UNITS::INCHES;
397  else if( unit == wxT( "de" ) || unit == wxT( "ra" ) ) // "deg" or "rad"
398  aUnits = EDA_UNITS::DEGREES;
399 }
400 
401 
402 long long int ValueFromString( EDA_UNITS aUnits, const wxString& aTextValue, EDA_DATA_TYPE aType )
403 {
404  double value = DoubleValueFromString( aUnits, aTextValue, aType );
405 
406  return KiROUND<double, long long int>( value );
407 }
408 
409 
411 {
412  switch( aUnit )
413  {
415  switch( aType )
416  {
417  default:
418  wxASSERT( 0 );
421  return _( "mm" );
422  case EDA_DATA_TYPE::AREA:
423  return _( "sq. mm" );
425  return _( "cu. mm" );
426  }
427 
428  case EDA_UNITS::MILS:
429  switch( aType )
430  {
431  default:
432  wxASSERT( 0 );
435  return _( "mils" );
436  case EDA_DATA_TYPE::AREA:
437  return _( "sq. mils" );
439  return _( "cu. mils" );
440  }
441 
442  case EDA_UNITS::INCHES:
443  switch( aType )
444  {
445  default:
446  wxASSERT( 0 );
449  return _( "in" );
450  case EDA_DATA_TYPE::AREA:
451  return _( "sq. in" );
453  return _( "cu. in" );
454  }
455 
456  case EDA_UNITS::PERCENT:
457  return _( "%" );
458 
459  case EDA_UNITS::UNSCALED:
460  return wxEmptyString;
461 
462  case EDA_UNITS::DEGREES:
463  return _( "deg" );
464 
465  default:
466  return wxT( "??" );
467  }
468 }
469 
470 
471 std::string FormatInternalUnits( int aValue )
472 {
473  char buf[50];
474  double engUnits = aValue;
475  int len;
476 
477  engUnits /= IU_PER_MM;
478 
479  if( engUnits != 0.0 && fabs( engUnits ) <= 0.0001 )
480  {
481  len = snprintf( buf, sizeof(buf), "%.10f", engUnits );
482 
483  // Make sure snprintf() didn't fail and the locale numeric separator is correct.
484  wxCHECK( len >= 0 && len < 50 && strchr( buf, ',' ) == NULL, std::string( "" ) );
485 
486  while( --len > 0 && buf[len] == '0' )
487  buf[len] = '\0';
488 
489  if( buf[len] == '.' )
490  buf[len] = '\0';
491  else
492  ++len;
493  }
494  else
495  {
496  len = snprintf( buf, sizeof(buf), "%.10g", engUnits );
497 
498  // Make sure snprintf() didn't fail and the locale numeric separator is correct.
499  wxCHECK( len >= 0 && len < 50 && strchr( buf, ',' ) == NULL , std::string( "" ) );
500  }
501 
502  return std::string( buf, len );
503 }
504 
505 
506 std::string FormatAngle( double aAngle )
507 {
508  char temp[50];
509  int len;
510 
511  len = snprintf( temp, sizeof(temp), "%.10g", aAngle / 10.0 );
512 
513  return std::string( temp, len );
514 }
515 
516 
517 std::string FormatInternalUnits( const wxPoint& aPoint )
518 {
519  return FormatInternalUnits( aPoint.x ) + " " + FormatInternalUnits( aPoint.y );
520 }
521 
522 
523 std::string FormatInternalUnits( const VECTOR2I& aPoint )
524 {
525  return FormatInternalUnits( aPoint.x ) + " " + FormatInternalUnits( aPoint.y );
526 }
527 
528 
529 std::string FormatInternalUnits( const wxSize& aSize )
530 {
531  return FormatInternalUnits( aSize.GetWidth() ) + " " + FormatInternalUnits( aSize.GetHeight() );
532 }
wxString MessageTextFromValue(EDA_UNITS aUnits, int aValue, bool aAddUnitLabel, EDA_DATA_TYPE aType)
Convert a value to a string using double notation.
Definition: base_units.cpp:90
Implementation of conversion functions that require both schematic and board internal units.
static constexpr double IU_PER_MM
Mock up a conversion function.
EDA_DATA_TYPE
The type of unit.
Definition: eda_units.h:31
Define a general 2D-vector/point.
Definition: vector2d.h:61
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
Definition: macros.h:83
wxString GetAbbreviatedUnitsLabel(EDA_UNITS aUnit, EDA_DATA_TYPE aType)
Get the units string for a given units type.
Definition: base_units.cpp:410
This file contains miscellaneous commonly used macros and functions.
std::string FormatAngle(double aAngle)
Function FormatAngle converts aAngle from board units to a string appropriate for writing to file.
Definition: base_units.cpp:506
void FetchUnitsFromString(const wxString &aTextValue, EDA_UNITS &aUnits)
Function FetchUnitsFromString writes any unit info found in the string to aUnits.
Definition: base_units.cpp:373
#define NULL
long long int ValueFromString(EDA_UNITS aUnits, const wxString &aTextValue, EDA_DATA_TYPE aType)
Function ValueFromString converts aTextValue in aUnits to internal units used by the application.
Definition: base_units.cpp:402
EDA_UNITS
Definition: eda_units.h:38
double To_User_Unit(EDA_UNITS aUnit, double aValue)
Function To_User_Unit convert aValue in internal units to the appropriate user units defined by aUnit...
Definition: base_units.cpp:56
#define _(s)
Definition: 3d_actions.cpp:33
The common library.
wxString StringFromValue(EDA_UNITS aUnits, double aValue, bool aAddUnitSymbol, EDA_DATA_TYPE aType)
Convert a value to a string using double notation.
Definition: base_units.cpp:190
double DoubleValueFromString(EDA_UNITS aUnits, const wxString &aTextValue, EDA_DATA_TYPE aType)
Function DoubleValueFromString converts aTextValue to a double.
Definition: base_units.cpp:293
double From_User_Unit(EDA_UNITS aUnits, double aValue)
Return in internal units the value "val" given in a real unit such as "in", "mm" or "deg".
Definition: base_units.cpp:268
std::string FormatInternalUnits(int aValue)
Function FormatInternalUnits converts aValue from internal units to a string appropriate for writing ...
Definition: base_units.cpp:471