KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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 The 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#include <charconv>
29#include <wx/translation.h>
30
31
32static void removeTrailingZeros( wxString& aText )
33{
34 int len = aText.length();
35 int removeLast = 0;
36
37 while( --len > 0 && aText[len] == '0' )
38 removeLast++;
39
40 if( len >= 0 && ( aText[len] == '.' || aText[len] == ',' ) )
41 removeLast++;
42
43 aText = aText.RemoveLast( removeLast );
44}
45
46
48{
49 switch( aUnit )
50 {
51 case EDA_UNITS::INCH:
52 case EDA_UNITS::MILS:
53 return true;
54
55 default:
56 return false;
57 }
58}
59
60
62{
63 switch( aUnit )
64 {
65 case EDA_UNITS::UM:
66 case EDA_UNITS::MM:
67 case EDA_UNITS::CM:
68 return true;
69
70 default:
71 return false;
72 }
73}
74
75
76int EDA_UNIT_UTILS::Mm2mils( double aVal )
77{
78 return KiROUND( aVal * 1000. / 25.4 );
79}
80
81
82int EDA_UNIT_UTILS::Mils2mm( double aVal )
83{
84 return KiROUND( aVal * 25.4 / 1000. );
85}
86
87
88bool EDA_UNIT_UTILS::FetchUnitsFromString( const wxString& aTextValue, EDA_UNITS& aUnits )
89{
90 wxString buf( aTextValue.Strip( wxString::both ) );
91 unsigned brk_point = 0;
92
93 while( brk_point < buf.Len() )
94 {
95 wxChar c = buf[brk_point];
96
97 if( !( ( c >= '0' && c <= '9' ) || ( c == '.' ) || ( c == ',' ) || ( c == '-' )
98 || ( c == '+' ) ) )
99 break;
100
101 ++brk_point;
102 }
103
104 // Check the unit designator (2 ch significant)
105 wxString unit( buf.Mid( brk_point ).Trim( false ).Left( 2 ).Lower() );
106
107 //check for um, μm (µ is MICRO SIGN) and µm (µ is GREEK SMALL LETTER MU) for micrometre
108 if( unit == wxT( "um" ) || unit == wxT( "\u00B5m" ) || unit == wxT( "\u03BCm" ) )
109 aUnits = EDA_UNITS::UM;
110 else if( unit == wxT( "mm" ) )
111 aUnits = EDA_UNITS::MM;
112 if( unit == wxT( "cm" ) )
113 aUnits = EDA_UNITS::CM;
114 else if( unit == wxT( "mi" ) || unit == wxT( "th" ) ) // "mils" or "thou"
115 aUnits = EDA_UNITS::MILS;
116 else if( unit == wxT( "in" ) || unit == wxT( "\"" ) )
117 aUnits = EDA_UNITS::INCH;
118 else if( unit == wxT( "de" ) || unit == wxT( "ra" ) ) // "deg" or "rad"
119 aUnits = EDA_UNITS::DEGREES;
120 else if( unit == wxT("fs" ) )
121 aUnits = EDA_UNITS::FS;
122 else if( unit == wxT( "ps" ) )
123 {
124 wxString timeUnit( buf.Mid( brk_point ).Trim( false ).Left( 5 ).Lower() );
125
126 if( timeUnit == wxT( "ps" ) )
127 aUnits = EDA_UNITS::PS;
128 else if( timeUnit == wxT( "ps/in" ) )
129 aUnits = EDA_UNITS::PS_PER_INCH;
130 else if( timeUnit == wxT( "ps/cm" ) )
131 aUnits = EDA_UNITS::PS_PER_CM;
132 else if( timeUnit == wxT( "ps/mm" ) )
133 aUnits = EDA_UNITS::PS_PER_MM;
134 else
135 return false;
136 }
137 else
138 return false;
139
140 return true;
141}
142
143
145{
146 wxString label;
147
148 switch( aUnits )
149 {
150 case EDA_UNITS::UM: label = wxT( " \u00B5m" ); break; //00B5 for µ
151 case EDA_UNITS::MM: label = wxT( " mm" ); break;
152 case EDA_UNITS::CM: label = wxT( " cm" ); break;
153 case EDA_UNITS::DEGREES: label = wxT( "°" ); break;
154 case EDA_UNITS::MILS: label = wxT( " mils" ); break;
155 case EDA_UNITS::INCH: label = wxT( " in" ); break;
156 case EDA_UNITS::PERCENT: label = wxT( "%" ); break;
157 case EDA_UNITS::FS: label = wxT( " fs" ); break;
158 case EDA_UNITS::PS: label = wxT( " ps" ); break;
159 case EDA_UNITS::PS_PER_INCH: label = wxT( " ps/in" ); break;
160 case EDA_UNITS::PS_PER_CM: label = wxT( " ps/cm"); break;
161 case EDA_UNITS::PS_PER_MM: label = wxT( " ps/mm"); break;
162 case EDA_UNITS::UNSCALED: break;
163 default: UNIMPLEMENTED_FOR( wxS( "Unknown units" ) ); break;
164 }
165
166 switch( aType )
167 {
168 case EDA_DATA_TYPE::VOLUME: label += wxT( "³" ); break;
169 case EDA_DATA_TYPE::AREA: label += wxT( "²" ); break;
170 case EDA_DATA_TYPE::DISTANCE: break;
171 case EDA_DATA_TYPE::TIME: break;
172 case EDA_DATA_TYPE::LENGTH_DELAY: break;
173 default: UNIMPLEMENTED_FOR( wxS( "Unknown measurement" ) ); break;
174 }
175
176 return label;
177}
178
179
181{
182 return GetText( aUnits, aType ).Trim( false );
183}
184
185
186std::string EDA_UNIT_UTILS::FormatAngle( const EDA_ANGLE& aAngle )
187{
188 std::string temp = fmt::format( "{:.10g}", aAngle.AsDegrees() );
189
190 return temp;
191}
192
193
194std::string EDA_UNIT_UTILS::FormatInternalUnits( const EDA_IU_SCALE& aIuScale, const int aValue,
195 const EDA_DATA_TYPE aDataType )
196{
197 std::string buf;
198 double engUnits = aValue;
199
200 engUnits /= GetScaleForInternalUnitType( aIuScale, aDataType );
201
202 if( engUnits != 0.0 && fabs( engUnits ) <= 0.0001 )
203 {
204 buf = fmt::format( "{:.10f}", engUnits );
205
206 // remove trailing zeros
207 while( !buf.empty() && buf[buf.size() - 1] == '0' )
208 {
209 buf.pop_back();
210 }
211
212 // if the value was really small
213 // we may have just stripped all the zeros after the decimal
214 if( buf[buf.size() - 1] == '.' )
215 {
216 buf.pop_back();
217 }
218 }
219 else
220 {
221 buf = fmt::format( "{:.10g}", engUnits );
222 }
223
224 return buf;
225}
226
227
229 const VECTOR2I& aPoint )
230{
231 return FormatInternalUnits( aIuScale, aPoint.x ) + " "
232 + FormatInternalUnits( aIuScale, aPoint.y );
233}
234
235
237{
238 switch( aDataType )
239 {
240 case EDA_DATA_TYPE::TIME: return aIuScale.IU_PER_PS;
241 case EDA_DATA_TYPE::LENGTH_DELAY: return aIuScale.IU_PER_PS_PER_MM;
242 case EDA_DATA_TYPE::UNITLESS: return 1.0;
243 default: return aIuScale.IU_PER_MM;
244 }
245}
246
247
248#if 0 // No support for std::from_chars on MacOS yet
249
250bool EDA_UNIT_UTILS::ParseInternalUnits( const std::string& aInput, const EDA_IU_SCALE& aIuScale,
251 int& aOut )
252{
253 double value;
254
255 if( std::from_chars( aInput.data(), aInput.data() + aInput.size(), value ).ec != std::errc() )
256 return false;
257
258 aOut = value * aIuScale.IU_PER_MM;
259 return true;
260}
261
262
263bool EDA_UNIT_UTILS::ParseInternalUnits( const std::string& aInput, const EDA_IU_SCALE& aIuScale,
264 VECTOR2I& aOut )
265{
266 size_t pos = aInput.find( ' ' );
267
268 if( pos == std::string::npos )
269 return false;
270
271 std::string first = aInput.substr( 0, pos );
272 std::string second = aInput.substr( pos + 1 );
273
274 VECTOR2I vec;
275
276 if( !ParseInternalUnits( first, aIuScale, vec.x ) )
277 return false;
278
279 if( !ParseInternalUnits( second, aIuScale, vec.y ) )
280 return false;
281
282 aOut = vec;
283
284 return true;
285}
286
287#endif
288
289
290#define IU_TO_MM( x, scale ) ( x / scale.IU_PER_MM )
291#define IU_TO_IN( x, scale ) ( x / scale.IU_PER_MILS / 1000 )
292#define IU_TO_MILS( x, scale ) ( x / scale.IU_PER_MILS )
293#define IU_TO_PS( x, scale ) ( x / scale.IU_PER_PS )
294#define IU_TO_PS_PER_MM( x, scale ) ( x / scale.IU_PER_PS_PER_MM )
295#define MM_TO_IU( x, scale ) ( x * scale.IU_PER_MM )
296#define IN_TO_IU( x, scale ) ( x * scale.IU_PER_MILS * 1000 )
297#define MILS_TO_IU( x, scale ) ( x * scale.IU_PER_MILS )
298#define PS_TO_IU( x, scale ) ( x * scale.IU_PER_PS )
299#define PS_PER_MM_TO_IU( x, scale ) ( x * scale.IU_PER_PS_PER_MM )
300
301
303 double aValue )
304{
305 switch( aUnit )
306 {
307 case EDA_UNITS::UM: return IU_TO_MM( aValue, aIuScale ) * 1000;
308 case EDA_UNITS::MM: return IU_TO_MM( aValue, aIuScale );
309 case EDA_UNITS::CM: return IU_TO_MM( aValue, aIuScale ) / 10;
310 case EDA_UNITS::MILS: return IU_TO_MILS( aValue, aIuScale );
311 case EDA_UNITS::INCH: return IU_TO_IN( aValue, aIuScale );
312 case EDA_UNITS::DEGREES: return aValue;
313 case EDA_UNITS::FS: return IU_TO_PS( aValue, aIuScale ) * 1000.0;
314 case EDA_UNITS::PS: return IU_TO_PS( aValue, aIuScale );
315 case EDA_UNITS::PS_PER_INCH: return IU_TO_PS_PER_MM( aValue, aIuScale ) * 25.4;
316 case EDA_UNITS::PS_PER_CM: return IU_TO_PS_PER_MM( aValue, aIuScale ) * 10;
317 case EDA_UNITS::PS_PER_MM: return IU_TO_PS_PER_MM( aValue, aIuScale );
318 default: return aValue;
319 }
320}
321
322
324 double aValue, bool aAddUnitsText,
325 EDA_DATA_TYPE aType )
326{
327 double value_to_print = aValue;
328 bool is_eeschema = ( aIuScale.IU_PER_MM == SCH_IU_PER_MM );
329
330 switch( aType )
331 {
333 value_to_print = ToUserUnit( aIuScale, aUnits, value_to_print );
335
337 value_to_print = ToUserUnit( aIuScale, aUnits, value_to_print );
339
341 value_to_print = ToUserUnit( aIuScale, aUnits, value_to_print );
342 break;
343
345 break;
346
348 value_to_print = ToUserUnit( aIuScale, aUnits, value_to_print );
349 break;
350
352 value_to_print = ToUserUnit( aIuScale, aUnits, value_to_print );
353 break;
354 }
355
356 const wxChar* format = nullptr;
357
358 switch( aUnits )
359 {
360 case EDA_UNITS::MILS: format = is_eeschema ? wxT( "%.3f" ) : wxT( "%.5f" ); break;
361 case EDA_UNITS::INCH: format = is_eeschema ? wxT( "%.6f" ) : wxT( "%.8f" ); break;
362 case EDA_UNITS::DEGREES: format = wxT( "%.4f" ); break;
363 case EDA_UNITS::PS_PER_INCH: format = wxT( "%.4f" ); break;
364 case EDA_UNITS::PS_PER_CM: format = wxT( "%.3f" ); break;
365 case EDA_UNITS::PS_PER_MM: format = wxT( "%.3f" ); break;
366 default: format = wxT( "%.10f" ); break;
367 }
368
369 wxString text;
370 text.Printf( format, value_to_print );
372
373 if( value_to_print != 0.0 && ( text == wxS( "0" ) || text == wxS( "-0" ) ) )
374 {
375 text.Printf( wxS( "%.10f" ), value_to_print );
377 }
378
379 if( aAddUnitsText )
380 text << EDA_UNIT_UTILS::GetText( aUnits, aType );
381
382 return text;
383}
384
385
386
387// A lower-precision (for readability) version of StringFromValue()
389 int aValue,
390 bool aAddUnitLabel,
391 EDA_DATA_TYPE aType )
392{
393 return MessageTextFromValue( aIuScale, aUnits, double( aValue ), aAddUnitLabel, aType );
394}
395
396
397// A lower-precision (for readability) version of StringFromValue()
399 long long int aValue,
400 bool aAddUnitLabel,
401 EDA_DATA_TYPE aType )
402{
403 return MessageTextFromValue( aIuScale, aUnits, double( aValue ), aAddUnitLabel, aType );
404}
405
406
407wxString EDA_UNIT_UTILS::UI::MessageTextFromValue( EDA_ANGLE aValue, bool aAddUnitLabel )
408{
409 if( aAddUnitLabel )
410 return wxString::Format( wxT( "%.1f°" ), aValue.AsDegrees() );
411 else
412 return wxString::Format( wxT( "%.1f" ), aValue.AsDegrees() );
413}
414
415
416// A lower-precision (for readability) version of StringFromValue()
418 double aValue, bool aAddUnitsText,
419 EDA_DATA_TYPE aType )
420{
421 wxString text;
422 const wxChar* format;
423 double value = aValue;
424 bool short_form = ( aIuScale.IU_PER_MM == SCH_IU_PER_MM )
425 || ( aType == EDA_DATA_TYPE::VOLUME || aType == EDA_DATA_TYPE::AREA );
426
427 switch( aType )
428 {
430 value = ToUserUnit( aIuScale, aUnits, value );
431 // Fall through to continue computation
433
435 value = ToUserUnit( aIuScale, aUnits, value );
436 // Fall through to continue computation
438
440 value = ToUserUnit( aIuScale, aUnits, value );
441 break;
442
444 break;
445
447 value = ToUserUnit( aIuScale, aUnits, value );
448 break;
449
451 value = ToUserUnit( aIuScale, aUnits, value );
452 break;
453 }
454
455 switch( aUnits )
456 {
457 default:
458 case EDA_UNITS::UM: format = short_form ? wxT( "%.0f" ) : wxT( "%.1f" ); break;
459 case EDA_UNITS::MM: format = short_form ? wxT( "%.3f" ) : wxT( "%.4f" ); break;
460 case EDA_UNITS::CM: format = short_form ? wxT( "%.3f" ) : wxT( "%.5f" ); break;
461 case EDA_UNITS::MILS: format = short_form ? wxT( "%.0f" ) : wxT( "%.2f" ); break;
462 case EDA_UNITS::INCH: format = short_form ? wxT( "%.3f" ) : wxT( "%.4f" ); break;
463 case EDA_UNITS::DEGREES: format = wxT( "%.3f" ); break;
464 case EDA_UNITS::UNSCALED: format = wxT( "%.0f" ); break;
465 case EDA_UNITS::FS: format = wxT( "%.4f" ); break;
466 case EDA_UNITS::PS: format = wxT( "%.2f" ); break;
467 case EDA_UNITS::PS_PER_INCH: format = wxT( "%.2f" ); break;
468 case EDA_UNITS::PS_PER_CM: format = wxT( "%.2f" ); break;
469 case EDA_UNITS::PS_PER_MM: format = wxT( "%.2f" ); break;
470 }
471
472 text.Printf( format, value );
473
474 // Check if the formatted value shows only zeros but the actual value is non-zero
475 // If so, use scientific notation instead
476 if( value != 0.0 )
477 {
478 bool showsOnlyZeros = true;
479
480 // Check if the text contains only zeros (allowing for decimal point, minus sign, etc.)
481 for( auto ch : text )
482 {
483 if( ch >= '1' && ch <= '9' )
484 {
485 showsOnlyZeros = false;
486 break;
487 }
488 }
489
490 if( showsOnlyZeros )
491 {
492 text.Printf( wxT( "%.3e" ), value );
493 }
494 }
495
496 // Trim to 2-1/2 digits after the decimal place for short-form mm
497 if( short_form && aUnits == EDA_UNITS::MM )
498 {
499 struct lconv* lc = localeconv();
500 int length = (int) text.Length();
501
502 if( length > 4 && text[length - 4] == *lc->decimal_point && text[length - 1] == '0' )
503 text = text.Left( length - 1 );
504 }
505
506 if( aAddUnitsText )
507 text += EDA_UNIT_UTILS::GetText( aUnits, aType );
508
509 return text;
510}
511
512
514 EDA_UNITS aUnits,
515 const MINOPTMAX<int>& aValue )
516{
517 wxString msg;
518
519 if( aValue.HasMin() && aValue.Min() > 0 )
520 {
521 msg += _( "min" ) + wxS( " " ) + MessageTextFromValue( aIuScale, aUnits, aValue.Min() );
522 }
523
524 if( aValue.HasOpt() )
525 {
526 if( !msg.IsEmpty() )
527 msg += wxS( "; " );
528
529 msg += _( "opt" ) + wxS( " " ) + MessageTextFromValue( aIuScale, aUnits, aValue.Opt() );
530 }
531
532 if( aValue.HasMax() )
533 {
534 if( !msg.IsEmpty() )
535 msg += wxS( "; " );
536
537 msg += _( "max" ) + wxS( " " ) + MessageTextFromValue( aIuScale, aUnits, aValue.Max() );
538 }
539
540 return msg;
541};
542
543
545 double aValue )
546{
547 switch( aUnits )
548 {
549 case EDA_UNITS::UM: return MM_TO_IU( aValue / 1000.0, aIuScale );
550 case EDA_UNITS::MM: return MM_TO_IU( aValue, aIuScale );
551 case EDA_UNITS::CM: return MM_TO_IU( aValue * 10, aIuScale );
552 case EDA_UNITS::MILS: return MILS_TO_IU( aValue, aIuScale );
553 case EDA_UNITS::INCH: return IN_TO_IU( aValue, aIuScale );
554 case EDA_UNITS::FS: return PS_TO_IU( aValue / 1000.0, aIuScale );
555 case EDA_UNITS::PS: return PS_TO_IU( aValue, aIuScale );
556 case EDA_UNITS::PS_PER_INCH: return PS_PER_MM_TO_IU( aValue / 25.4, aIuScale );
557 case EDA_UNITS::PS_PER_CM: return PS_PER_MM_TO_IU( aValue / 10, aIuScale );
558 case EDA_UNITS::PS_PER_MM: return PS_PER_MM_TO_IU( aValue, aIuScale );
559 default:
562 case EDA_UNITS::PERCENT: return aValue;
563 }
564}
565
566
567double EDA_UNIT_UTILS::UI::DoubleValueFromString( const wxString& aTextValue )
568{
569 double dtmp = 0;
570
571 // Acquire the 'right' decimal point separator
572 const struct lconv* lc = localeconv();
573
574 wxChar decimal_point = lc->decimal_point[0];
575 wxString buf( aTextValue.Strip( wxString::both ) );
576
577 // Convert any entered decimal point separators to the 'right' one
578 buf.Replace( wxT( "." ), wxString( decimal_point, 1 ) );
579 buf.Replace( wxT( "," ), wxString( decimal_point, 1 ) );
580
581 // Find the end of the numeric part
582 unsigned brk_point = 0;
583
584 while( brk_point < buf.Len() )
585 {
586 wxChar ch = buf[brk_point];
587
588 if( !( ( ch >= '0' && ch <= '9' ) || ( ch == decimal_point ) || ( ch == '-' )
589 || ( ch == '+' ) ) )
590 {
591 break;
592 }
593
594 ++brk_point;
595 }
596
597 // Extract the numeric part
598 buf.Left( brk_point ).ToDouble( &dtmp );
599
600 return dtmp;
601}
602
603
605 const wxString& aTextValue, EDA_DATA_TYPE aType )
606{
607 double dtmp = 0;
608
609 // Acquire the 'right' decimal point separator
610 const struct lconv* lc = localeconv();
611
612 wxChar decimal_point = lc->decimal_point[0];
613 wxString buf( aTextValue.Strip( wxString::both ) );
614
615 // Convert any entered decimal point separators to the 'right' one
616 buf.Replace( wxT( "." ), wxString( decimal_point, 1 ) );
617 buf.Replace( wxT( "," ), wxString( decimal_point, 1 ) );
618
619 // Find the end of the numeric part
620 unsigned brk_point = 0;
621
622 while( brk_point < buf.Len() )
623 {
624 wxChar ch = buf[brk_point];
625
626 if( !( (ch >= '0' && ch <= '9') || (ch == decimal_point) || (ch == '-') || (ch == '+') ) )
627 break;
628
629 ++brk_point;
630 }
631
632 // Extract the numeric part
633 buf.Left( brk_point ).ToDouble( &dtmp );
634
635 // Check the optional unit designator (2 ch significant)
636 wxString unit( buf.Mid( brk_point ).Trim( false ).Left( 2 ).Lower() );
637
638 if( aUnits == EDA_UNITS::UM
639 || aUnits == EDA_UNITS::MM
640 || aUnits == EDA_UNITS::CM
641 || aUnits == EDA_UNITS::MILS
642 || aUnits == EDA_UNITS::INCH )
643 {
644 //check for um, μm (µ is MICRO SIGN) and µm (µ is GREEK SMALL LETTER MU) for micrometre
645 if( unit == wxT( "um" ) || unit == wxT( "\u00B5m" ) || unit == wxT( "\u03BCm" ) )
646 {
647 aUnits = EDA_UNITS::UM;
648 }
649 else if( unit == wxT( "mm" ) )
650 {
651 aUnits = EDA_UNITS::MM;
652 }
653 else if( unit == wxT( "cm" ) )
654 {
655 aUnits = EDA_UNITS::CM;
656 }
657 else if( unit == wxT( "mi" ) || unit == wxT( "th" ) )
658 {
659 aUnits = EDA_UNITS::MILS;
660 }
661 else if( unit == wxT( "in" ) || unit == wxT( "\"" ) )
662 {
663 aUnits = EDA_UNITS::INCH;
664 }
665 else if( unit == wxT( "oz" ) ) // 1 oz = 1.37 mils
666 {
667 aUnits = EDA_UNITS::MILS;
668 dtmp *= 1.37;
669 }
670 }
671 else if( aUnits == EDA_UNITS::DEGREES )
672 {
673 if( unit == wxT( "ra" ) ) // Radians
674 dtmp *= 180.0f / M_PI;
675 }
676 else if( aUnits == EDA_UNITS::FS || aUnits == EDA_UNITS::PS || aUnits == EDA_UNITS::PS_PER_INCH
677 || aUnits == EDA_UNITS::PS_PER_CM || aUnits == EDA_UNITS::PS_PER_MM )
678
679 {
680 wxString timeUnit( buf.Mid( brk_point ).Trim( false ).Left( 5 ).Lower() );
681
682 if( timeUnit == wxT( "fs" ) )
683 aUnits = EDA_UNITS::FS;
684 if( timeUnit == wxT( "ps" ) )
685 aUnits = EDA_UNITS::PS;
686 else if( timeUnit == wxT( "ps/in" ) )
687 aUnits = EDA_UNITS::PS_PER_INCH;
688 else if( timeUnit == wxT( "ps/cm" ) )
689 aUnits = EDA_UNITS::PS_PER_CM;
690 else if( timeUnit == wxT( "ps/mm" ) )
691 aUnits = EDA_UNITS::PS_PER_MM;
692 }
693
694 switch( aType )
695 {
697 dtmp = FromUserUnit( aIuScale, aUnits, dtmp );
699
701 dtmp = FromUserUnit( aIuScale, aUnits, dtmp );
703
705 dtmp = FromUserUnit( aIuScale, aUnits, dtmp );
706 break;
707
709 break;
710
712 dtmp = FromUserUnit( aIuScale, aUnits, dtmp );
713 break;
714
716 dtmp = FromUserUnit( aIuScale, aUnits, dtmp );
717 break;
718 }
719
720 return dtmp;
721}
722
723
724bool EDA_UNIT_UTILS::UI::DoubleValueFromString( const EDA_IU_SCALE& aIuScale, const wxString& aTextValue,
725 double& aDoubleValue )
726{
727 double dtmp = 0;
728
729 // Acquire the 'right' decimal point separator
730 const struct lconv* lc = localeconv();
731
732 wxChar decimal_point = lc->decimal_point[0];
733 wxString buf( aTextValue.Strip( wxString::both ) );
734
735 // Convert any entered decimal point separators to the 'right' one
736 buf.Replace( wxT( "." ), wxString( decimal_point, 1 ) );
737 buf.Replace( wxT( "," ), wxString( decimal_point, 1 ) );
738
739 // Find the end of the numeric part
740 unsigned brk_point = 0;
741
742 while( brk_point < buf.Len() )
743 {
744 wxChar ch = buf[brk_point];
745
746 if( !( (ch >= '0' && ch <= '9') || (ch == decimal_point) || (ch == '-') || (ch == '+') ) )
747 break;
748
749 ++brk_point;
750 }
751
752 if( brk_point == 0 )
753 return false;
754
755 // Extract the numeric part
756 buf.Left( brk_point ).ToDouble( &dtmp );
757
758 // Check the unit designator
759 wxString unit( buf.Mid( brk_point ).Strip( wxString::both ).Lower() );
760 EDA_UNITS units = EDA_UNITS::MM; // Make gcc quiet
761
762 //check for um, μm (µ is MICRO SIGN) and µm (µ is GREEK SMALL LETTER MU) for micrometre
763 if( unit == wxT( "um" ) || unit == wxT( "\u00B5m" ) || unit == wxT( "\u03BCm" ) )
764 {
765 units = EDA_UNITS::UM;
766 }
767 else if( unit == wxT( "mm" ) )
768 {
769 units = EDA_UNITS::MM;
770 }
771 else if( unit == wxT( "cm" ) )
772 {
773 units = EDA_UNITS::CM;
774 }
775 else if( unit == wxT( "mil" ) || unit == wxT( "mils" ) || unit == wxT( "thou" ) )
776 {
777 units = EDA_UNITS::MILS;
778 }
779 else if( unit == wxT( "in" ) || unit == wxT( "\"" ) )
780 {
781 units = EDA_UNITS::INCH;
782 }
783 else if( unit == wxT( "oz" ) ) // 1 oz = 1.37 mils
784 {
785 units = EDA_UNITS::MILS;
786 dtmp *= 1.37;
787 }
788 else if( unit == wxT( "ra" ) ) // Radians
789 {
790 dtmp *= 180.0f / M_PI;
791 }
792 else if( unit == wxT( "fs" ) )
793 {
794 units = EDA_UNITS::FS;
795 }
796 else if( unit == wxT( "ps" ) )
797 {
798 units = EDA_UNITS::PS;
799 }
800 else if( unit == wxT( "ps/in" ) )
801 {
803 }
804 else if( unit == wxT( "ps/cm" ) )
805 {
806 units = EDA_UNITS::PS_PER_CM;
807 }
808 else if( unit == wxT( "ps/mm" ) )
809 {
810 units = EDA_UNITS::PS_PER_MM;
811 }
812 else
813 {
814 return false;
815 }
816
817 aDoubleValue = FromUserUnit( aIuScale, units, dtmp );
818 return true;
819}
820
821
822long long int EDA_UNIT_UTILS::UI::ValueFromString( const EDA_IU_SCALE& aIuScale, EDA_UNITS aUnits,
823 const wxString& aTextValue, EDA_DATA_TYPE aType )
824{
825 double value = DoubleValueFromString( aIuScale, aUnits, aTextValue, aType );
826
827 return KiROUND<double, long long int>( value );
828}
829
830
831long long int EDA_UNIT_UTILS::UI::ValueFromString( const wxString& aTextValue )
832{
833 double value = DoubleValueFromString( aTextValue );
834
835 return KiROUND<double, long long int>( value );
836}
constexpr double SCH_IU_PER_MM
Schematic internal units 1=100nm.
Definition base_units.h:72
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:990
double AsDegrees() const
Definition eda_angle.h:116
T Min() const
Definition minoptmax.h:33
bool HasMax() const
Definition minoptmax.h:38
bool HasMin() const
Definition minoptmax.h:37
T Max() const
Definition minoptmax.h:34
T Opt() const
Definition minoptmax.h:35
bool HasOpt() const
Definition minoptmax.h:39
#define _(s)
#define IU_TO_IN(x, scale)
#define IU_TO_PS_PER_MM(x, scale)
#define IN_TO_IU(x, scale)
#define IU_TO_MILS(x, scale)
#define IU_TO_PS(x, scale)
#define MM_TO_IU(x, scale)
#define PS_TO_IU(x, scale)
#define PS_PER_MM_TO_IU(x, scale)
#define IU_TO_MM(x, scale)
#define MILS_TO_IU(x, scale)
static void removeTrailingZeros(wxString &aText)
Definition eda_units.cpp:32
EDA_DATA_TYPE
The type of unit.
Definition eda_units.h:38
EDA_UNITS
Definition eda_units.h:48
@ PS_PER_INCH
Definition eda_units.h:59
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:96
KICOMMON_API 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.
KICOMMON_API double FromUserUnit(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnit, double aValue)
Return in internal units the value aValue given in a real unit such as "in", "mm",...
KICOMMON_API long long int ValueFromString(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits, const wxString &aTextValue, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Convert aTextValue in aUnits to internal units used by the application.
KICOMMON_API wxString StringFromValue(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits, double aValue, bool aAddUnitsText=false, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Return the string from aValue according to aUnits (inch, mm ...) for display.
KICOMMON_API wxString MessageTextFromMinOptMax(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits, const MINOPTMAX< int > &aValue)
KICOMMON_API double DoubleValueFromString(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits, const wxString &aTextValue, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Convert aTextValue to a double.
KICOMMON_API double ToUserUnit(const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnit, double aValue)
Convert aValue in internal units to the appropriate user units defined by aUnit.
KICOMMON_API wxString GetText(EDA_UNITS aUnits, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Get the units string for a given units type.
KICOMMON_API bool FetchUnitsFromString(const wxString &aTextValue, EDA_UNITS &aUnits)
Write any unit info found in the string to aUnits.
Definition eda_units.cpp:88
KICOMMON_API bool IsImperialUnit(EDA_UNITS aUnit)
Definition eda_units.cpp:47
KICOMMON_API bool IsMetricUnit(EDA_UNITS aUnit)
Definition eda_units.cpp:61
KICOMMON_API double GetScaleForInternalUnitType(const EDA_IU_SCALE &aIuScale, EDA_DATA_TYPE aDataType)
Returns the scaling parameter for the given units data type.
KICOMMON_API wxString GetLabel(EDA_UNITS aUnits, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Get the units string for a given units type.
KICOMMON_API int Mm2mils(double aVal)
Convert mm to mils.
Definition eda_units.cpp:76
KICOMMON_API std::string FormatAngle(const EDA_ANGLE &aAngle)
Convert aAngle from board units to a string appropriate for writing to file.
KICOMMON_API std::string FormatInternalUnits(const EDA_IU_SCALE &aIuScale, int aValue, EDA_DATA_TYPE aDataType=EDA_DATA_TYPE::DISTANCE)
Converts aValue from internal units to a string appropriate for writing to file.
KICOMMON_API int Mils2mm(double aVal)
Convert mils to mm.
Definition eda_units.cpp:82
const double IU_PER_PS
Internal time units are attoseconds.
Definition base_units.h:78
const double IU_PER_MM
Definition base_units.h:76
const double IU_PER_PS_PER_MM
Internal delay units are attoseconds/mm.
Definition base_units.h:79
#define M_PI
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695