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