KiCad PCB EDA Suite
eda_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) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
24#include <eda_units.h>
25#include <fmt/core.h>
26#include <math/util.h> // for KiROUND
27#include <macros.h>
28
30{
31 switch( aUnit )
32 {
34 case EDA_UNITS::MILS:
35 return true;
36
37 default:
38 return false;
39 }
40}
41
42
44{
45 switch( aUnit )
46 {
48 return true;
49
50 default:
51 return false;
52 }
53}
54
55
56int EDA_UNIT_UTILS::Mm2mils( double aVal )
57{
58 return KiROUND( aVal * 1000. / 25.4 );
59}
60
61
62int EDA_UNIT_UTILS::Mils2mm( double aVal )
63{
64 return KiROUND( aVal * 25.4 / 1000. );
65}
66
67
68void EDA_UNIT_UTILS::FetchUnitsFromString( const wxString& aTextValue, EDA_UNITS& aUnits )
69{
70 wxString buf( aTextValue.Strip( wxString::both ) );
71 unsigned brk_point = 0;
72
73 while( brk_point < buf.Len() )
74 {
75 wxChar c = buf[brk_point];
76
77 if( !( ( c >= '0' && c <= '9' ) || ( c == '.' ) || ( c == ',' ) || ( c == '-' )
78 || ( c == '+' ) ) )
79 break;
80
81 ++brk_point;
82 }
83
84 // Check the unit designator (2 ch significant)
85 wxString unit( buf.Mid( brk_point ).Strip( wxString::leading ).Left( 2 ).Lower() );
86
87 if( unit == wxT( "mm" ) )
89 else if( unit == wxT( "mi" ) || unit == wxT( "th" ) ) // "mils" or "thou"
90 aUnits = EDA_UNITS::MILS;
91 else if( unit == wxT( "in" ) || unit == wxT( "\"" ) )
92 aUnits = EDA_UNITS::INCHES;
93 else if( unit == wxT( "de" ) || unit == wxT( "ra" ) ) // "deg" or "rad"
94 aUnits = EDA_UNITS::DEGREES;
95}
96
97
99{
100 wxString label;
101
102 switch( aUnits )
103 {
104 case EDA_UNITS::MILLIMETRES: label = wxT( " mm" ); break;
105 case EDA_UNITS::DEGREES: label = wxT( "°" ); break;
106 case EDA_UNITS::MILS: label = wxT( " mils" ); break;
107 case EDA_UNITS::INCHES: label = wxT( " in" ); break;
108 case EDA_UNITS::PERCENT: label = wxT( "%" ); break;
109 case EDA_UNITS::UNSCALED: break;
110 default: UNIMPLEMENTED_FOR( "Unknown units" ); break;
111 }
112
113 switch( aType )
114 {
115 case EDA_DATA_TYPE::VOLUME: label += wxT( "³" ); break;
116 case EDA_DATA_TYPE::AREA: label += wxT( "²" ); break;
117 case EDA_DATA_TYPE::DISTANCE: break;
118 default: UNIMPLEMENTED_FOR( "Unknown measurement" ); break;
119 }
120
121 return label;
122}
123
124
126{
127 return GetText( aUnits, aType ).Trim( false );
128}
129
130
131std::string EDA_UNIT_UTILS::FormatAngle( const EDA_ANGLE& aAngle )
132{
133 std::string temp = fmt::format( "{:.10g}", aAngle.AsDegrees() );
134
135 return temp;
136}
137
138
139std::string EDA_UNIT_UTILS::FormatInternalUnits( const EDA_IU_SCALE& aIuScale, int aValue )
140{
141 std::string buf;
142 double engUnits = aValue;
143
144 engUnits /= aIuScale.IU_PER_MM;
145
146 if( engUnits != 0.0 && fabs( engUnits ) <= 0.0001 )
147 {
148 buf = fmt::format( "{:.10f}", engUnits );
149
150 // remove trailing zeros
151 while( !buf.empty() && buf[buf.size() - 1] == '0' )
152 {
153 buf.pop_back();
154 }
155 }
156 else
157 {
158 buf = fmt::format( "{:.10g}", engUnits );
159 }
160
161 return buf;
162}
163
164
166 const wxPoint& aPoint )
167{
168 return FormatInternalUnits( aIuScale, aPoint.x ) + " "
169 + FormatInternalUnits( aIuScale, aPoint.y );
170}
171
172
174 const VECTOR2I& aPoint )
175{
176 return FormatInternalUnits( aIuScale, aPoint.x ) + " "
177 + FormatInternalUnits( aIuScale, aPoint.y );
178}
179
180
181std::string EDA_UNIT_UTILS::FormatInternalUnits( const EDA_IU_SCALE& aIuScale, const wxSize& aSize )
182{
183 return FormatInternalUnits( aIuScale, aSize.GetWidth() ) + " "
184 + FormatInternalUnits( aIuScale, aSize.GetHeight() );
185}
186
187#define IU_TO_MM( x, scale ) ( x / scale.IU_PER_MM )
188#define IU_TO_IN( x, scale ) ( x / scale.IU_PER_MILS / 1000 )
189#define IU_TO_MILS( x, scale ) ( x / scale.IU_PER_MILS )
190#define MM_TO_IU( x, scale ) ( x * scale.IU_PER_MM )
191#define IN_TO_IU( x, scale ) ( x * scale.IU_PER_MILS * 1000 )
192#define MILS_TO_IU( x, scale ) ( x * scale.IU_PER_MILS )
193
195 double aValue )
196{
197 switch( aUnit )
198 {
200 return IU_TO_MM( aValue, aIuScale );
201
202 case EDA_UNITS::MILS:
203 return IU_TO_MILS( aValue, aIuScale );
204
206 return IU_TO_IN( aValue, aIuScale );
207
209 return aValue;
210
211 default:
212 return aValue;
213 }
214}
215
216
230 double aValue, bool aAddUnitsText,
231 EDA_DATA_TYPE aType )
232{
233 double value_to_print = aValue;
234
235 switch( aType )
236 {
238 value_to_print = ToUserUnit( aIuScale, aUnits, value_to_print );
240
242 value_to_print = ToUserUnit( aIuScale, aUnits, value_to_print );
244
246 value_to_print = ToUserUnit( aIuScale, aUnits, value_to_print );
247 }
248
249 char buf[50];
250
251 if( value_to_print != 0.0 && fabs( value_to_print ) <= 0.0001 )
252 {
253 int len = snprintf( buf, sizeof( buf ) - 1, "%.10f", value_to_print );
254
255 while( --len > 0 && buf[len] == '0' )
256 buf[len] = '\0';
257
258 if( len >= 0 && ( buf[len] == '.' || buf[len] == ',' ) )
259 buf[len] = '\0';
260 }
261 else
262 {
263 snprintf( buf, sizeof( buf ) - 1, "%.10g", value_to_print );
264 }
265
266 wxString stringValue( buf, wxConvUTF8 );
267
268 if( aAddUnitsText )
269 stringValue += EDA_UNIT_UTILS::GetText( aUnits, aType );
270
271 return stringValue;
272}
273
274
275
289// A lower-precision (for readability) version of StringFromValue()
291 int aValue,
292 bool aAddUnitLabel,
293 EDA_DATA_TYPE aType )
294{
295 return MessageTextFromValue( aIuScale, aUnits, double( aValue ), aAddUnitLabel, aType );
296}
297
298
299// A lower-precision (for readability) version of StringFromValue()
301 long long int aValue,
302 bool aAddUnitLabel,
303 EDA_DATA_TYPE aType )
304{
305 return MessageTextFromValue( aIuScale, aUnits, double( aValue ), aAddUnitLabel, aType );
306}
307
308
309wxString EDA_UNIT_UTILS::UI::MessageTextFromValue( EDA_ANGLE aValue, bool aAddUnitLabel )
310{
311 if( aAddUnitLabel )
312 return wxString::Format( wxT( "%.1f°" ), aValue.AsDegrees() );
313 else
314 return wxString::Format( wxT( "%.1f" ), aValue.AsDegrees() );
315}
316
317
318// A lower-precision (for readability) version of StringFromValue()
320 double aValue, bool aAddUnitsText,
321 EDA_DATA_TYPE aType )
322{
323 wxString text;
324 const wxChar* format;
325 double value = aValue;
326
327 switch( aType )
328 {
330 value = ToUserUnit( aIuScale, aUnits, value );
331 // Fall through to continue computation
333
335 value = ToUserUnit( aIuScale, aUnits, value );
336 // Fall through to continue computation
338
340 value = ToUserUnit( aIuScale, aUnits, value );
341 }
342
343 switch( aUnits )
344 {
345 default:
347#if defined( EESCHEMA )
348 format = wxT( "%.2f" );
349#else
350 format = wxT( "%.4f" );
351#endif
352 break;
353
354 case EDA_UNITS::MILS:
355#if defined( EESCHEMA )
356 format = wxT( "%.0f" );
357#else
358 format = wxT( "%.2f" );
359#endif
360 break;
361
363#if defined( EESCHEMA )
364 format = wxT( "%.3f" );
365#else
366 format = wxT( "%.4f" );
367#endif
368 break;
369
371 // 3 digits in mantissa should be good for rotation in degree
372 format = wxT( "%.3f" );
373 break;
374
376 format = wxT( "%.0f" );
377 break;
378 }
379
380 text.Printf( format, value );
381
382 if( aAddUnitsText )
383 text += EDA_UNIT_UTILS::GetText( aUnits, aType );
384
385 return text;
386}
387
388
390 double aValue )
391{
392 switch( aUnits )
393 {
395 return MM_TO_IU( aValue, aIuScale );
396
397 case EDA_UNITS::MILS:
398 return MILS_TO_IU( aValue, aIuScale );
399
401 return IN_TO_IU( aValue, aIuScale );
402
403 default:
407 return aValue;
408 }
409}
410
411
412double EDA_UNIT_UTILS::UI::DoubleValueFromString( const wxString& aTextValue )
413{
414 double dtmp = 0;
415
416 // Acquire the 'right' decimal point separator
417 const struct lconv* lc = localeconv();
418
419 wxChar decimal_point = lc->decimal_point[0];
420 wxString buf( aTextValue.Strip( wxString::both ) );
421
422 // Convert any entered decimal point separators to the 'right' one
423 buf.Replace( wxT( "." ), wxString( decimal_point, 1 ) );
424 buf.Replace( wxT( "," ), wxString( decimal_point, 1 ) );
425
426 // Find the end of the numeric part
427 unsigned brk_point = 0;
428
429 while( brk_point < buf.Len() )
430 {
431 wxChar ch = buf[brk_point];
432
433 if( !( ( ch >= '0' && ch <= '9' ) || ( ch == decimal_point ) || ( ch == '-' )
434 || ( ch == '+' ) ) )
435 {
436 break;
437 }
438
439 ++brk_point;
440 }
441
442 // Extract the numeric part
443 buf.Left( brk_point ).ToDouble( &dtmp );
444
445 return dtmp;
446}
447
448
450 const wxString& aTextValue, EDA_DATA_TYPE aType )
451{
452 double dtmp = 0;
453
454 // Acquire the 'right' decimal point separator
455 const struct lconv* lc = localeconv();
456
457 wxChar decimal_point = lc->decimal_point[0];
458 wxString buf( aTextValue.Strip( wxString::both ) );
459
460 // Convert any entered decimal point separators to the 'right' one
461 buf.Replace( wxT( "." ), wxString( decimal_point, 1 ) );
462 buf.Replace( wxT( "," ), wxString( decimal_point, 1 ) );
463
464 // Find the end of the numeric part
465 unsigned brk_point = 0;
466
467 while( brk_point < buf.Len() )
468 {
469 wxChar ch = buf[brk_point];
470
471 if( !( (ch >= '0' && ch <= '9') || (ch == decimal_point) || (ch == '-') || (ch == '+') ) )
472 break;
473
474 ++brk_point;
475 }
476
477 // Extract the numeric part
478 buf.Left( brk_point ).ToDouble( &dtmp );
479
480 // Check the optional unit designator (2 ch significant)
481 wxString unit( buf.Mid( brk_point ).Strip( wxString::leading ).Left( 2 ).Lower() );
482
483 if( aUnits == EDA_UNITS::MILLIMETRES
484 || aUnits == EDA_UNITS::MILS
485 || aUnits == EDA_UNITS::INCHES )
486 {
487 if( unit == wxT( "mm" ) )
488 {
489 aUnits = EDA_UNITS::MILLIMETRES;
490 }
491 else if( unit == wxT( "mi" ) || unit == wxT( "th" ) )
492 {
493 aUnits = EDA_UNITS::MILS;
494 }
495 else if( unit == wxT( "in" ) || unit == wxT( "\"" ) )
496 {
497 aUnits = EDA_UNITS::INCHES;
498 }
499 else if( unit == "oz" ) // 1 oz = 1.37 mils
500 {
501 aUnits = EDA_UNITS::MILS;
502 dtmp *= 1.37;
503 }
504 }
505 else if( aUnits == EDA_UNITS::DEGREES )
506 {
507 if( unit == wxT( "ra" ) ) // Radians
508 dtmp *= 180.0f / M_PI;
509 }
510
511 switch( aType )
512 {
514 dtmp = FromUserUnit( aIuScale, aUnits, dtmp );
516
518 dtmp = FromUserUnit( aIuScale, aUnits, dtmp );
520
522 dtmp = FromUserUnit( aIuScale, aUnits, dtmp );
523 }
524
525 return dtmp;
526}
527
528
529long long int EDA_UNIT_UTILS::UI::ValueFromString( const EDA_IU_SCALE& aIuScale, EDA_UNITS aUnits,
530 const wxString& aTextValue, EDA_DATA_TYPE aType )
531{
532 double value = DoubleValueFromString( aIuScale, aUnits, aTextValue, aType );
533
534 return KiROUND<double, long long int>( value );
535}
536
537
538long long int EDA_UNIT_UTILS::UI::ValueFromString( const wxString& aTextValue )
539{
540 double value = DoubleValueFromString( aTextValue );
541
542 return KiROUND<double, long long int>( value );
543}
double AsDegrees() const
Definition: eda_angle.h:149
#define IU_TO_IN(x, scale)
Definition: eda_units.cpp:188
#define IN_TO_IU(x, scale)
Definition: eda_units.cpp:191
#define IU_TO_MILS(x, scale)
Definition: eda_units.cpp:189
#define MM_TO_IU(x, scale)
Definition: eda_units.cpp:190
#define IU_TO_MM(x, scale)
Definition: eda_units.cpp:187
#define MILS_TO_IU(x, scale)
Definition: eda_units.cpp:192
EDA_DATA_TYPE
The type of unit.
Definition: eda_units.h:36
EDA_UNITS
Definition: eda_units.h:43
This file contains miscellaneous commonly used macros and functions.
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
Definition: macros.h:83
#define UNIMPLEMENTED_FOR(type)
Definition: macros.h:120
wxString MessageTextFromValue(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits, double aValue, bool aAddUnitsText=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
A helper to convert the double length aValue to a string in inches, millimeters, or unscaled units.
Definition: eda_units.cpp:319
double FromUserUnit(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnit, double aValue)
Return in internal units the value "val" given in a real unit such as "in", "mm" or "deg".
Definition: eda_units.cpp:389
long long int ValueFromString(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits, const wxString &aTextValue, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Function ValueFromString converts aTextValue in aUnits to internal units used by the application.
Definition: eda_units.cpp:529
wxString StringFromValue(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits, double aValue, bool aAddUnitsText=false, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Returns the string from aValue according to aUnits (inch, mm ...) for display.
Definition: eda_units.cpp:229
double DoubleValueFromString(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits, const wxString &aTextValue, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Function DoubleValueFromString converts aTextValue to a double.
Definition: eda_units.cpp:449
double ToUserUnit(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnit, double aValue)
Function To_User_Unit convert aValue in internal units to the appropriate user units defined by aUnit...
Definition: eda_units.cpp:194
wxString GetText(EDA_UNITS aUnits, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Get the units string for a given units type.
Definition: eda_units.cpp:98
bool IsImperialUnit(EDA_UNITS aUnit)
Definition: eda_units.cpp:29
bool IsMetricUnit(EDA_UNITS aUnit)
Definition: eda_units.cpp:43
wxString GetLabel(EDA_UNITS aUnits, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Get the units string for a given units type.
Definition: eda_units.cpp:125
int Mm2mils(double aVal)
Convert mm to mils.
Definition: eda_units.cpp:56
std::string FormatInternalUnits(const EDA_IU_SCALE &aIuScale, int aValue)
Converts aValue from internal units to a string appropriate for writing to file.
Definition: eda_units.cpp:139
std::string FormatAngle(const EDA_ANGLE &aAngle)
Converts aAngle from board units to a string appropriate for writing to file.
Definition: eda_units.cpp:131
int Mils2mm(double aVal)
Convert mils to mm.
Definition: eda_units.cpp:62
void FetchUnitsFromString(const wxString &aTextValue, EDA_UNITS &aUnits)
Writes any unit info found in the string to aUnits.
Definition: eda_units.cpp:68
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
const double IU_PER_MM
Definition: base_units.h:77
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:85