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