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