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-2020 KiCad Developers, see change_log.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 <math/util.h> // for KiROUND
40 #include <macros.h>
41 #include <title_block.h>
42 
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 // Helper function to print a float number without using scientific notation
57 // and no trailing 0
58 // So we cannot always just use the %g or the %f format to print a fp number
59 // this helper function uses the %f format when needed, or %g when %f is
60 // not well working and then removes trailing 0
61 
62 std::string Double2Str( double aValue )
63 {
64  char buf[50];
65  int len;
66 
67  if( aValue != 0.0 && fabs( aValue ) <= 0.0001 )
68  {
69  // For these small values, %f works fine,
70  // and %g gives an exponent
71  len = sprintf( buf, "%.16f", aValue );
72 
73  while( --len > 0 && buf[len] == '0' )
74  buf[len] = '\0';
75 
76  if( buf[len] == '.' )
77  buf[len] = '\0';
78  else
79  ++len;
80  }
81  else
82  {
83  // For these values, %g works fine, and sometimes %f
84  // gives a bad value (try aValue = 1.222222222222, with %.16f format!)
85  len = sprintf( buf, "%.16g", aValue );
86  }
87 
88  return std::string( buf, len );
89 }
90 
91 
92 double To_User_Unit( EDA_UNITS aUnit, double aValue, bool aUseMils )
93 {
94  switch( aUnit )
95  {
97  return IU_TO_MM( aValue );
98 
99  case EDA_UNITS::INCHES:
100  if( aUseMils )
101  return IU_TO_MILS( aValue );
102  else
103  return IU_TO_IN( aValue );
104 
105  case EDA_UNITS::DEGREES:
106  return aValue / 10.0f;
107 
108  default:
109  return aValue;
110  }
111 }
112 
113 /* Convert a value to a string using double notation.
114  * For readability, the mantissa has 0, 1, 3 or 4 digits, depending on units
115  * for unit = inch the mantissa has 3 digits (Eeschema) or 4 digits
116  * for unit = mil the mantissa has 0 digits (Eeschema) or 1 digits
117  * for unit = mm the mantissa has 3 digits (Eeschema) or 4 digits
118  * Should be used only to display info in status,
119  * but not in dialogs, because 4 digits only
120  * could truncate the actual value
121  */
122 
123 // A lower-precision (for readability) version of StringFromValue()
124 wxString MessageTextFromValue( EDA_UNITS aUnits, int aValue, bool aUseMils, EDA_DATA_TYPE aType )
125 {
126  return MessageTextFromValue( aUnits, double( aValue ), aUseMils );
127 }
128 
129 
130 // A lower-precision (for readability) version of StringFromValue()
131 wxString MessageTextFromValue( EDA_UNITS aUnits, long long int aValue,
132  bool aUseMils, EDA_DATA_TYPE aType )
133 {
134  return MessageTextFromValue( aUnits, double( aValue ), aUseMils );
135 }
136 
137 
138 // A lower-precision (for readability) version of StringFromValue()
139 wxString MessageTextFromValue( EDA_UNITS aUnits, double aValue, bool aUseMils, EDA_DATA_TYPE aType )
140 {
141  wxString text;
142  const wxChar* format;
143  double value = aValue;
144 
145  switch( aType )
146  {
148  value = To_User_Unit( aUnits, value, aUseMils );
149  // Fall through to continue computation
151 
152  case EDA_DATA_TYPE::AREA:
153  value = To_User_Unit( aUnits, value, aUseMils );
154  // Fall through to continue computation
156 
158  value = To_User_Unit( aUnits, value, aUseMils );
159  }
160 
161  if( aUnits == EDA_UNITS::INCHES )
162  {
163  if( aUseMils )
164  {
165 #if defined( EESCHEMA )
166  format = wxT( "%.0f" );
167 #else
168  format = wxT( "%.1f" );
169 #endif
170  }
171  else
172  {
173 #if defined( EESCHEMA )
174  format = wxT( "%.3f" );
175 #else
176  format = wxT( "%.4f" );
177 #endif
178  }
179  }
180  else
181  {
182 #if defined( EESCHEMA )
183  format = wxT( "%.4f" );
184 #else
185  format = wxT( "%.3f" );
186 #endif
187  }
188 
189  text.Printf( format, value );
190  text += " ";
191 
192  text += GetAbbreviatedUnitsLabel( aUnits, aUseMils, aType );
193 
194  return text;
195 }
196 
197 /* Remove trailing 0 from a string containing a converted float number.
198  * the trailing 0 are removed if the mantissa has more
199  * than aTrailingZeroAllowed digits and some trailing 0
200  */
201 void StripTrailingZeros( wxString& aStringValue, unsigned aTrailingZeroAllowed )
202 {
203  struct lconv * lc = localeconv();
204  char sep = lc->decimal_point[0];
205  unsigned sep_pos = aStringValue.Find( sep );
206 
207  if( sep_pos > 0 )
208  {
209  // We want to keep at least aTrailingZeroAllowed digits after the separator
210  unsigned min_len = sep_pos + aTrailingZeroAllowed + 1;
211 
212  while( aStringValue.Len() > min_len )
213  {
214  if( aStringValue.Last() == '0' )
215  aStringValue.RemoveLast();
216  else
217  break;
218  }
219  }
220 }
221 
222 
223 /* Convert a value to a string using double notation.
224  * For readability, the mantissa has 3 or more digits,
225  * the trailing 0 are removed if the mantissa has more than 3 digits
226  * and some trailing 0
227  * This function should be used to display values in dialogs because a value
228  * entered in mm (for instance 2.0 mm) could need up to 8 digits mantissa
229  * if displayed in inch to avoid truncation or rounding made just by the printf function.
230  * otherwise the actual value is rounded when read from dialog and converted
231  * in internal units, and therefore modified.
232  */
233 wxString StringFromValue( EDA_UNITS aUnits, double aValue, bool aAddUnitSymbol, bool aUseMils,
234  EDA_DATA_TYPE aType )
235 {
236  double value_to_print = aValue;
237 
238  switch( aType )
239  {
241  value_to_print = To_User_Unit( aUnits, value_to_print, aUseMils );
243 
244  case EDA_DATA_TYPE::AREA:
245  value_to_print = To_User_Unit( aUnits, value_to_print, aUseMils );
247 
249  value_to_print = To_User_Unit( aUnits, value_to_print, aUseMils );
250  }
251 
252 
253 #if defined( EESCHEMA )
254  wxString stringValue = wxString::Format( wxT( "%.3f" ), value_to_print );
255 
256  // Strip trailing zeros. However, keep at least 3 digits in mantissa
257  // For readability
258  StripTrailingZeros( stringValue, 3 );
259 
260 #else
261 
262  char buf[50];
263  int len;
264 
265  if( value_to_print != 0.0 && fabs( value_to_print ) <= 0.0001 )
266  {
267  len = sprintf( buf, "%.10f", value_to_print );
268 
269  while( --len > 0 && buf[len] == '0' )
270  buf[len] = '\0';
271 
272  if( buf[len]=='.' || buf[len]==',' )
273  buf[len] = '\0';
274  else
275  ++len;
276  }
277  else
278  {
279  if( aUnits == EDA_UNITS::INCHES && aUseMils )
280  len = sprintf( buf, "%.7g", value_to_print );
281  else
282  len = sprintf( buf, "%.10g", value_to_print );
283  }
284 
285  wxString stringValue( buf, wxConvUTF8 );
286 
287 #endif
288 
289  if( aAddUnitSymbol )
290  {
291  switch( aUnits )
292  {
293  case EDA_UNITS::INCHES:
294  if( aUseMils )
295  stringValue += wxT( " mils" );
296  else
297  stringValue += wxT( " in" );
298  break;
299 
301  stringValue += wxT( " mm" );
302  break;
303 
304  case EDA_UNITS::DEGREES:
305  stringValue += wxT( " deg" );
306  break;
307 
308  case EDA_UNITS::PERCENT:
309  stringValue += wxT( "%" );
310  break;
311 
312  case EDA_UNITS::UNSCALED:
313  break;
314  }
315  }
316 
317  return stringValue;
318 }
319 
320 
321 double From_User_Unit( EDA_UNITS aUnits, double aValue, bool aUseMils )
322 {
323  switch( aUnits )
324  {
326  return MM_TO_IU( aValue );
327 
328  case EDA_UNITS::INCHES:
329  if( aUseMils )
330  return MILS_TO_IU( aValue );
331  else
332  return IN_TO_IU( aValue );
333 
334  case EDA_UNITS::DEGREES:
335  // Convert to "decidegrees"
336  return aValue * 10;
337 
338  default:
339  case EDA_UNITS::UNSCALED:
340  case EDA_UNITS::PERCENT:
341  return aValue;
342  }
343 }
344 
345 
346 double DoubleValueFromString( EDA_UNITS aUnits, const wxString& aTextValue, bool aUseMils,
347  EDA_DATA_TYPE aType )
348 {
349  double dtmp = 0;
350 
351  // Acquire the 'right' decimal point separator
352  const struct lconv* lc = localeconv();
353 
354  wxChar decimal_point = lc->decimal_point[0];
355  wxString buf( aTextValue.Strip( wxString::both ) );
356 
357  // Convert the period in decimal point
358  buf.Replace( wxT( "." ), wxString( decimal_point, 1 ) );
359 
360  // Find the end of the numeric part
361  unsigned brk_point = 0;
362 
363  while( brk_point < buf.Len() )
364  {
365  wxChar ch = buf[brk_point];
366 
367  if( !( (ch >= '0' && ch <='9') || (ch == decimal_point) || (ch == '-') || (ch == '+') ) )
368  {
369  break;
370  }
371 
372  ++brk_point;
373  }
374 
375  // Extract the numeric part
376  buf.Left( brk_point );
377 
378  buf.ToDouble( &dtmp );
379 
380  // Check the optional unit designator (2 ch significant)
381  wxString unit( buf.Mid( brk_point ).Strip( wxString::leading ).Left( 2 ).Lower() );
382 
383  if( aUnits == EDA_UNITS::INCHES || aUnits == EDA_UNITS::MILLIMETRES )
384  {
385  if( unit == wxT( "in" ) || unit == wxT( "\"" ) )
386  {
387  aUnits = EDA_UNITS::INCHES;
388  aUseMils = false;
389  }
390  else if( unit == wxT( "mm" ) )
391  {
392  aUnits = EDA_UNITS::MILLIMETRES;
393  }
394  else if( unit == wxT( "mi" ) || unit == wxT( "th" ) ) // "mils" or "thou"
395  {
396  aUnits = EDA_UNITS::INCHES;
397  aUseMils = true;
398  }
399  else if( unit == "oz" ) // 1 oz = 1.37 mils
400  {
401  aUnits = EDA_UNITS::INCHES;
402  aUseMils = true;
403  dtmp *= 1.37;
404  }
405  }
406  else if( aUnits == EDA_UNITS::DEGREES )
407  {
408  if( unit == wxT( "ra" ) ) // Radians
409  {
410  dtmp *= 180.0f / M_PI;
411  }
412  }
413 
414  switch( aType )
415  {
417  dtmp = From_User_Unit( aUnits, dtmp, aUseMils );
419 
420  case EDA_DATA_TYPE::AREA:
421  dtmp = From_User_Unit( aUnits, dtmp, aUseMils );
423 
425  dtmp = From_User_Unit( aUnits, dtmp, aUseMils );
426  }
427 
428  return dtmp;
429 }
430 
431 
432 void FetchUnitsFromString( const wxString& aTextValue, EDA_UNITS& aUnits, bool& aUseMils )
433 {
434  wxString buf( aTextValue.Strip( wxString::both ) );
435  unsigned brk_point = 0;
436 
437  while( brk_point < buf.Len() )
438  {
439  wxChar c = buf[brk_point];
440 
441  if( !( (c >= '0' && c <='9') || (c == '.') || (c == ',') || (c == '-') || (c == '+') ) )
442  break;
443 
444  ++brk_point;
445  }
446 
447  // Check the unit designator (2 ch significant)
448  wxString unit( buf.Mid( brk_point ).Strip( wxString::leading ).Left( 2 ).Lower() );
449 
450  if( unit == wxT( "in" ) || unit == wxT( "\"" ) )
451  {
452  aUnits = EDA_UNITS::INCHES;
453  aUseMils = false;
454  }
455  else if( unit == wxT( "mm" ) )
456  {
457  aUnits = EDA_UNITS::MILLIMETRES;
458  }
459  else if( unit == wxT( "mi" ) || unit == wxT( "th" ) ) // "mils" or "thou"
460  {
461  aUnits = EDA_UNITS::INCHES;
462  aUseMils = true;
463  }
464  else if( unit == wxT( "de" ) || unit == wxT( "ra" ) ) // "deg" or "rad"
465  {
466  aUnits = EDA_UNITS::DEGREES;
467  }
468 }
469 
470 
471 long long int ValueFromString( EDA_UNITS aUnits, const wxString& aTextValue, bool aUseMils,
472  EDA_DATA_TYPE aType )
473 {
474  double value = DoubleValueFromString( aUnits, aTextValue, aUseMils, aType );
475  return KiROUND<double, long long int>( value );
476 }
477 
478 
484 wxString AngleToStringDegrees( double aAngle )
485 {
486  wxString text;
487 
488  text.Printf( wxT( "%.3f" ), aAngle/10.0 );
489  StripTrailingZeros( text, 1 );
490 
491  return text;
492 }
493 
494 
495 wxString GetAbbreviatedUnitsLabel( EDA_UNITS aUnit, bool aUseMils, EDA_DATA_TYPE aType )
496 {
497  switch( aUnit )
498  {
499  case EDA_UNITS::INCHES:
500  if( aUseMils )
501  {
502  switch( aType )
503  {
504  default:
505  wxASSERT( 0 );
508  return _( "mils" );
509  case EDA_DATA_TYPE::AREA:
510  return _( "sq. mils" );
512  return _( "cu. mils" );
513  }
514  }
515  else
516  {
517  switch( aType )
518  {
519  default:
520  wxASSERT( 0 );
523  return _( "in" );
524  case EDA_DATA_TYPE::AREA:
525  return _( "sq. in" );
527  return _( "cu. in" );
528  }
529  }
530 
532  switch( aType )
533  {
534  default:
535  wxASSERT( 0 );
538  return _( "mm" );
539  case EDA_DATA_TYPE::AREA:
540  return _( "sq. mm" );
542  return _( "cu. mm" );
543  }
544 
545  case EDA_UNITS::PERCENT:
546  return _( "%" );
547 
548  case EDA_UNITS::UNSCALED:
549  return wxEmptyString;
550 
551  case EDA_UNITS::DEGREES:
552  return _( "deg" );
553 
554  default:
555  return wxT( "??" );
556  }
557 }
558 
559 
560 std::string FormatInternalUnits( int aValue )
561 {
562  char buf[50];
563  double engUnits = aValue;
564  int len;
565 
566  engUnits /= IU_PER_MM;
567 
568  if( engUnits != 0.0 && fabs( engUnits ) <= 0.0001 )
569  {
570  len = snprintf( buf, sizeof(buf), "%.10f", engUnits );
571 
572  while( --len > 0 && buf[len] == '0' )
573  buf[len] = '\0';
574 
575  if( buf[len] == '.' )
576  buf[len] = '\0';
577  else
578  ++len;
579  }
580  else
581  {
582  len = snprintf( buf, sizeof(buf), "%.10g", engUnits );
583  }
584 
585  return std::string( buf, len );
586 }
587 
588 
589 std::string FormatAngle( double aAngle )
590 {
591  char temp[50];
592  int len;
593 
594  len = snprintf( temp, sizeof(temp), "%.10g", aAngle / 10.0 );
595 
596  return std::string( temp, len );
597 }
598 
599 
600 std::string FormatInternalUnits( const wxPoint& aPoint )
601 {
602  return FormatInternalUnits( aPoint.x ) + " " + FormatInternalUnits( aPoint.y );
603 }
604 
605 
606 std::string FormatInternalUnits( const VECTOR2I& aPoint )
607 {
608  return FormatInternalUnits( aPoint.x ) + " " + FormatInternalUnits( aPoint.y );
609 }
610 
611 
612 std::string FormatInternalUnits( const wxSize& aSize )
613 {
614  return FormatInternalUnits( aSize.GetWidth() ) + " " + FormatInternalUnits( aSize.GetHeight() );
615 }
616 
double To_User_Unit(EDA_UNITS aUnit, double aValue, bool aUseMils)
Function To_User_Unit convert aValue in internal units to the appropriate user units defined by aUnit...
Definition: base_units.cpp:92
EDA_UNITS
Definition: common.h:198
Implementation of conversion functions that require both schematic and board internal units.
EDA_DATA_TYPE
The type of unit.
Definition: common.h:191
static constexpr double IU_PER_MM
Mock up a conversion function.
double From_User_Unit(EDA_UNITS aUnits, double aValue, bool aUseMils)
Return in internal units the value "val" given in a real unit such as "in", "mm" or "deg".
Definition: base_units.cpp:321
VECTOR2 defines a general 2D-vector/point.
Definition: vector2d.h:61
double DoubleValueFromString(EDA_UNITS aUnits, const wxString &aTextValue, bool aUseMils, EDA_DATA_TYPE aType)
Function DoubleValueFromString converts aTextValue to a double.
Definition: base_units.cpp:346
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
Definition: macros.h:88
std::string Double2Str(double aValue)
Helper function Double2Str to print a float number without using scientific notation and no trailing ...
Definition: base_units.cpp:62
wxString GetAbbreviatedUnitsLabel(EDA_UNITS aUnit, bool aUseMils, EDA_DATA_TYPE aType)
Get the units string for a given units type.
Definition: base_units.cpp:495
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:589
void StripTrailingZeros(wxString &aStringValue, unsigned aTrailingZeroAllowed)
Function StripTrailingZeros Remove trailing 0 from a string containing a converted float number.
Definition: base_units.cpp:201
wxString AngleToStringDegrees(double aAngle)
Function AngleToStringDegrees is a helper to convert the double aAngle (in internal unit) to a string...
Definition: base_units.cpp:484
wxString MessageTextFromValue(EDA_UNITS aUnits, int aValue, bool aUseMils, EDA_DATA_TYPE aType)
Definition: base_units.cpp:124
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:201
#define _(s)
Definition: 3d_actions.cpp:33
void FetchUnitsFromString(const wxString &aTextValue, EDA_UNITS &aUnits, bool &aUseMils)
Function FetchUnitsFromString writes any unit info found in the string to aUnits and aUseMils.
Definition: base_units.cpp:432
The common library.
wxString StringFromValue(EDA_UNITS aUnits, double aValue, bool aAddUnitSymbol, bool aUseMils, EDA_DATA_TYPE aType)
Function StringFromValue returns the string from aValue according to units (inch, mm ....
Definition: base_units.cpp:233
std::string FormatInternalUnits(int aValue)
Function FormatInternalUnits converts aValue from internal units to a string appropriate for writing ...
Definition: base_units.cpp:560
long long int ValueFromString(EDA_UNITS aUnits, const wxString &aTextValue, bool aUseMils, EDA_DATA_TYPE aType)
Function ValueFromString converts aTextValue in aUnits to internal units used by the application.
Definition: base_units.cpp:471