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 int Mm2mils( double x )
57 {
58  return KiROUND( x * 1000. / 25.4 );
59 }
60 
61 
62 int Mils2mm( double x )
63 {
64  return KiROUND( x * 25.4 / 1000. );
65 }
66 
67 
68 double To_User_Unit( EDA_UNITS aUnit, double aValue )
69 {
70  switch( aUnit )
71  {
73  return IU_TO_MM( aValue );
74 
75  case EDA_UNITS::MILS:
76  return IU_TO_MILS( aValue );
77 
78  case EDA_UNITS::INCHES:
79  return IU_TO_IN( aValue );
80 
81  case EDA_UNITS::DEGREES:
82  return aValue / 10.0f;
83 
84  default:
85  return aValue;
86  }
87 }
88 
89 
103 // A lower-precision (for readability) version of StringFromValue()
104 wxString MessageTextFromValue( EDA_UNITS aUnits, int aValue, bool aAddUnitLabel,
105  EDA_DATA_TYPE aType )
106 {
107  return MessageTextFromValue( aUnits, double( aValue ), aAddUnitLabel, aType );
108 }
109 
110 
111 // A lower-precision (for readability) version of StringFromValue()
112 wxString MessageTextFromValue( EDA_UNITS aUnits, long long int aValue, bool aAddUnitLabel,
113  EDA_DATA_TYPE aType )
114 {
115  return MessageTextFromValue( aUnits, double( aValue ), aAddUnitLabel, aType );
116 }
117 
118 
119 // A lower-precision (for readability) version of StringFromValue()
120 wxString MessageTextFromValue( EDA_UNITS aUnits, double aValue, bool aAddUnitLabel,
121  EDA_DATA_TYPE aType )
122 {
123  wxString text;
124  const wxChar* format;
125  double value = aValue;
126 
127  switch( aType )
128  {
130  value = To_User_Unit( aUnits, value );
131  // Fall through to continue computation
133 
134  case EDA_DATA_TYPE::AREA:
135  value = To_User_Unit( aUnits, value );
136  // Fall through to continue computation
138 
140  value = To_User_Unit( aUnits, value );
141  }
142 
143  switch( aUnits )
144  {
145  default:
147 #if defined( EESCHEMA )
148  format = wxT( "%.2f" );
149 #else
150  format = wxT( "%.4f" );
151 #endif
152  break;
153 
154  case EDA_UNITS::MILS:
155 #if defined( EESCHEMA )
156  format = wxT( "%.0f" );
157 #else
158  format = wxT( "%.2f" );
159 #endif
160  break;
161 
162  case EDA_UNITS::INCHES:
163 #if defined( EESCHEMA )
164  format = wxT( "%.3f" );
165 #else
166  format = wxT( "%.4f" );
167 #endif
168  break;
169 
170  case EDA_UNITS::DEGREES:
171  // 3 digits in mantissa should be good for rotation in degree
172  format = wxT( "%.3f" );
173  break;
174 
175  case EDA_UNITS::UNSCALED:
176  format = wxT( "%.0f" );
177  break;
178  }
179 
180  text.Printf( format, value );
181 
182  if( aAddUnitLabel )
183  {
184  text += " ";
185  text += GetAbbreviatedUnitsLabel( aUnits, aType );
186  }
187 
188  return text;
189 }
190 
191 
204 wxString StringFromValue( EDA_UNITS aUnits, double aValue, bool aAddUnitSymbol,
205  EDA_DATA_TYPE aType )
206 {
207  double value_to_print = aValue;
208 
209  switch( aType )
210  {
212  value_to_print = To_User_Unit( aUnits, value_to_print );
214 
215  case EDA_DATA_TYPE::AREA:
216  value_to_print = To_User_Unit( aUnits, value_to_print );
218 
220  value_to_print = To_User_Unit( aUnits, value_to_print );
221  }
222 
223 
224  char buf[50];
225  int len;
226 
227  if( value_to_print != 0.0 && fabs( value_to_print ) <= 0.0001 )
228  {
229  len = sprintf( buf, "%.10f", value_to_print );
230 
231  while( --len > 0 && buf[len] == '0' )
232  buf[len] = '\0';
233 
234  if( buf[len]=='.' || buf[len]==',' )
235  buf[len] = '\0';
236  else
237  ++len;
238  }
239  else
240  {
241  if( aUnits == EDA_UNITS::MILS )
242  len = sprintf( buf, "%.7g", value_to_print );
243  else
244  len = sprintf( buf, "%.10g", value_to_print );
245  }
246 
247  wxString stringValue( buf, wxConvUTF8 );
248 
249  if( aAddUnitSymbol )
250  {
251  switch( aUnits )
252  {
254  stringValue += wxT( " mm" );
255  break;
256 
257  case EDA_UNITS::DEGREES:
258  stringValue += wxT( " deg" );
259  break;
260 
261  case EDA_UNITS::MILS:
262  stringValue += wxT( " mils" );
263  break;
264 
265  case EDA_UNITS::INCHES:
266  stringValue += wxT( " in" );
267  break;
268 
269  case EDA_UNITS::PERCENT:
270  stringValue += wxT( "%" );
271  break;
272 
273  case EDA_UNITS::UNSCALED:
274  break;
275  }
276  }
277 
278  return stringValue;
279 }
280 
281 
282 double From_User_Unit( EDA_UNITS aUnits, double aValue )
283 {
284  switch( aUnits )
285  {
287  return MM_TO_IU( aValue );
288 
289  case EDA_UNITS::MILS:
290  return MILS_TO_IU( aValue );
291 
292  case EDA_UNITS::INCHES:
293  return IN_TO_IU( aValue );
294 
295  case EDA_UNITS::DEGREES:
296  // Convert to "decidegrees"
297  return aValue * 10;
298 
299  default:
300  case EDA_UNITS::UNSCALED:
301  case EDA_UNITS::PERCENT:
302  return aValue;
303  }
304 }
305 
306 
307 double DoubleValueFromString( EDA_UNITS aUnits, const wxString& aTextValue, EDA_DATA_TYPE aType )
308 {
309  double dtmp = 0;
310 
311  // Acquire the 'right' decimal point separator
312  const struct lconv* lc = localeconv();
313 
314  wxChar decimal_point = lc->decimal_point[0];
315  wxString buf( aTextValue.Strip( wxString::both ) );
316 
317  // Convert any entered decimal point separators to the 'right' one
318  buf.Replace( wxT( "." ), wxString( decimal_point, 1 ) );
319  buf.Replace( wxT( "," ), wxString( decimal_point, 1 ) );
320 
321  // Find the end of the numeric part
322  unsigned brk_point = 0;
323 
324  while( brk_point < buf.Len() )
325  {
326  wxChar ch = buf[brk_point];
327 
328  if( !( (ch >= '0' && ch <= '9') || (ch == decimal_point) || (ch == '-') || (ch == '+') ) )
329  break;
330 
331  ++brk_point;
332  }
333 
334  // Extract the numeric part
335  buf.Left( brk_point ).ToDouble( &dtmp );
336 
337  // Check the optional unit designator (2 ch significant)
338  wxString unit( buf.Mid( brk_point ).Strip( wxString::leading ).Left( 2 ).Lower() );
339 
340  if( aUnits == EDA_UNITS::MILLIMETRES || aUnits == EDA_UNITS::MILS
341  || aUnits == EDA_UNITS::INCHES )
342  {
343  if( unit == wxT( "mm" ) )
344  {
345  aUnits = EDA_UNITS::MILLIMETRES;
346  }
347  else if( unit == wxT( "mi" ) || unit == wxT( "th" ) )
348  {
349  aUnits = EDA_UNITS::MILS;
350  }
351  else if( unit == wxT( "in" ) || unit == wxT( "\"" ) )
352  {
353  aUnits = EDA_UNITS::INCHES;
354  }
355  else if( unit == "oz" ) // 1 oz = 1.37 mils
356  {
357  aUnits = EDA_UNITS::MILS;
358  dtmp *= 1.37;
359  }
360  }
361  else if( aUnits == EDA_UNITS::DEGREES )
362  {
363  if( unit == wxT( "ra" ) ) // Radians
364  {
365  dtmp *= 180.0f / M_PI;
366  }
367  }
368 
369  switch( aType )
370  {
372  dtmp = From_User_Unit( aUnits, dtmp );
374 
375  case EDA_DATA_TYPE::AREA:
376  dtmp = From_User_Unit( aUnits, dtmp );
378 
380  dtmp = From_User_Unit( aUnits, dtmp );
381  }
382 
383  return dtmp;
384 }
385 
386 
387 void FetchUnitsFromString( const wxString& aTextValue, EDA_UNITS& aUnits )
388 {
389  wxString buf( aTextValue.Strip( wxString::both ) );
390  unsigned brk_point = 0;
391 
392  while( brk_point < buf.Len() )
393  {
394  wxChar c = buf[brk_point];
395 
396  if( !( (c >= '0' && c <='9') || (c == '.') || (c == ',') || (c == '-') || (c == '+') ) )
397  break;
398 
399  ++brk_point;
400  }
401 
402  // Check the unit designator (2 ch significant)
403  wxString unit( buf.Mid( brk_point ).Strip( wxString::leading ).Left( 2 ).Lower() );
404 
405  if( unit == wxT( "mm" ) )
406  aUnits = EDA_UNITS::MILLIMETRES;
407  else if( unit == wxT( "mi" ) || unit == wxT( "th" ) ) // "mils" or "thou"
408  aUnits = EDA_UNITS::MILS;
409  else if( unit == wxT( "in" ) || unit == wxT( "\"" ) )
410  aUnits = EDA_UNITS::INCHES;
411  else if( unit == wxT( "de" ) || unit == wxT( "ra" ) ) // "deg" or "rad"
412  aUnits = EDA_UNITS::DEGREES;
413 }
414 
415 
416 long long int ValueFromString( EDA_UNITS aUnits, const wxString& aTextValue, EDA_DATA_TYPE aType )
417 {
418  double value = DoubleValueFromString( aUnits, aTextValue, aType );
419 
420  return KiROUND<double, long long int>( value );
421 }
422 
423 
425 {
426  switch( aUnit )
427  {
429  switch( aType )
430  {
431  default:
432  wxASSERT( 0 );
435  return _( "mm" );
436  case EDA_DATA_TYPE::AREA:
437  return _( "sq. mm" );
439  return _( "cu. mm" );
440  }
441 
442  case EDA_UNITS::MILS:
443  switch( aType )
444  {
445  default:
446  wxASSERT( 0 );
449  return _( "mils" );
450  case EDA_DATA_TYPE::AREA:
451  return _( "sq. mils" );
453  return _( "cu. mils" );
454  }
455 
456  case EDA_UNITS::INCHES:
457  switch( aType )
458  {
459  default:
460  wxASSERT( 0 );
463  return _( "in" );
464  case EDA_DATA_TYPE::AREA:
465  return _( "sq. in" );
467  return _( "cu. in" );
468  }
469 
470  case EDA_UNITS::PERCENT:
471  return _( "%" );
472 
473  case EDA_UNITS::UNSCALED:
474  return wxEmptyString;
475 
476  case EDA_UNITS::DEGREES:
477  return _( "deg" );
478 
479  default:
480  return wxT( "??" );
481  }
482 }
483 
484 
485 std::string FormatInternalUnits( int aValue )
486 {
487  char buf[50];
488  double engUnits = aValue;
489  int len;
490 
491  engUnits /= IU_PER_MM;
492 
493  if( engUnits != 0.0 && fabs( engUnits ) <= 0.0001 )
494  {
495  len = snprintf( buf, sizeof(buf), "%.10f", engUnits );
496 
497  // Make sure snprintf() didn't fail and the locale numeric separator is correct.
498  wxCHECK( len >= 0 && len < 50 && strchr( buf, ',' ) == nullptr, std::string( "" ) );
499 
500  while( --len > 0 && buf[len] == '0' )
501  buf[len] = '\0';
502 
503  if( buf[len] == '.' )
504  buf[len] = '\0';
505  else
506  ++len;
507  }
508  else
509  {
510  len = snprintf( buf, sizeof(buf), "%.10g", engUnits );
511 
512  // Make sure snprintf() didn't fail and the locale numeric separator is correct.
513  wxCHECK( len >= 0 && len < 50 && strchr( buf, ',' ) == nullptr , std::string( "" ) );
514  }
515 
516  return std::string( buf, len );
517 }
518 
519 
520 std::string FormatAngle( double aAngle )
521 {
522  char temp[50];
523  int len;
524 
525  len = snprintf( temp, sizeof(temp), "%.10g", aAngle / 10.0 );
526 
527  return std::string( temp, len );
528 }
529 
530 
531 std::string FormatInternalUnits( const wxPoint& aPoint )
532 {
533  return FormatInternalUnits( aPoint.x ) + " " + FormatInternalUnits( aPoint.y );
534 }
535 
536 
537 std::string FormatInternalUnits( const VECTOR2I& aPoint )
538 {
539  return FormatInternalUnits( aPoint.x ) + " " + FormatInternalUnits( aPoint.y );
540 }
541 
542 
543 std::string FormatInternalUnits( const wxSize& aSize )
544 {
545  return FormatInternalUnits( aSize.GetWidth() ) + " " + FormatInternalUnits( aSize.GetHeight() );
546 }
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:104
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:424
This file contains miscellaneous commonly used macros and functions.
int Mm2mils(double x)
Convert mm to mils.
Definition: base_units.cpp:56
std::string FormatAngle(double aAngle)
Function FormatAngle converts aAngle from board units to a string appropriate for writing to file.
Definition: base_units.cpp:520
void FetchUnitsFromString(const wxString &aTextValue, EDA_UNITS &aUnits)
Function FetchUnitsFromString writes any unit info found in the string to aUnits.
Definition: base_units.cpp:387
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:416
#define _(s)
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:68
int Mils2mm(double x)
Convert mils to mm.
Definition: base_units.cpp:62
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:73
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:204
double DoubleValueFromString(EDA_UNITS aUnits, const wxString &aTextValue, EDA_DATA_TYPE aType)
Function DoubleValueFromString converts aTextValue to a double.
Definition: base_units.cpp:307
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:282
std::string FormatInternalUnits(int aValue)
Function FormatInternalUnits converts aValue from internal units to a string appropriate for writing ...
Definition: base_units.cpp:485