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