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, int aValue )
195{
196 std::string buf;
197 double engUnits = aValue;
198
199 engUnits /= aIuScale.IU_PER_MM;
200
201 if( engUnits != 0.0 && fabs( engUnits ) <= 0.0001 )
202 {
203 buf = fmt::format( "{:.10f}", engUnits );
204
205 // remove trailing zeros
206 while( !buf.empty() && buf[buf.size() - 1] == '0' )
207 {
208 buf.pop_back();
209 }
210
211 // if the value was really small
212 // we may have just stripped all the zeros after the decimal
213 if( buf[buf.size() - 1] == '.' )
214 {
215 buf.pop_back();
216 }
217 }
218 else
219 {
220 buf = fmt::format( "{:.10g}", engUnits );
221 }
222
223 return buf;
224}
225
226
228 const VECTOR2I& aPoint )
229{
230 return FormatInternalUnits( aIuScale, aPoint.x ) + " "
231 + FormatInternalUnits( aIuScale, aPoint.y );
232}
233
234
235#if 0 // No support for std::from_chars on MacOS yet
236
237bool EDA_UNIT_UTILS::ParseInternalUnits( const std::string& aInput, const EDA_IU_SCALE& aIuScale,
238 int& aOut )
239{
240 double value;
241
242 if( std::from_chars( aInput.data(), aInput.data() + aInput.size(), value ).ec != std::errc() )
243 return false;
244
245 aOut = value * aIuScale.IU_PER_MM;
246 return true;
247}
248
249
250bool EDA_UNIT_UTILS::ParseInternalUnits( const std::string& aInput, const EDA_IU_SCALE& aIuScale,
251 VECTOR2I& aOut )
252{
253 size_t pos = aInput.find( ' ' );
254
255 if( pos == std::string::npos )
256 return false;
257
258 std::string first = aInput.substr( 0, pos );
259 std::string second = aInput.substr( pos + 1 );
260
261 VECTOR2I vec;
262
263 if( !ParseInternalUnits( first, aIuScale, vec.x ) )
264 return false;
265
266 if( !ParseInternalUnits( second, aIuScale, vec.y ) )
267 return false;
268
269 aOut = vec;
270
271 return true;
272}
273
274#endif
275
276
277#define IU_TO_MM( x, scale ) ( x / scale.IU_PER_MM )
278#define IU_TO_IN( x, scale ) ( x / scale.IU_PER_MILS / 1000 )
279#define IU_TO_MILS( x, scale ) ( x / scale.IU_PER_MILS )
280#define IU_TO_PS( x, scale ) ( x / scale.IU_PER_PS )
281#define IU_TO_PS_PER_MM( x, scale ) ( x / scale.IU_PER_PS_PER_MM )
282#define MM_TO_IU( x, scale ) ( x * scale.IU_PER_MM )
283#define IN_TO_IU( x, scale ) ( x * scale.IU_PER_MILS * 1000 )
284#define MILS_TO_IU( x, scale ) ( x * scale.IU_PER_MILS )
285#define PS_TO_IU( x, scale ) ( x * scale.IU_PER_PS )
286#define PS_PER_MM_TO_IU( x, scale ) ( x * scale.IU_PER_PS_PER_MM )
287
288
290 double aValue )
291{
292 switch( aUnit )
293 {
294 case EDA_UNITS::UM: return IU_TO_MM( aValue, aIuScale ) * 1000;
295 case EDA_UNITS::MM: return IU_TO_MM( aValue, aIuScale );
296 case EDA_UNITS::CM: return IU_TO_MM( aValue, aIuScale ) / 10;
297 case EDA_UNITS::MILS: return IU_TO_MILS( aValue, aIuScale );
298 case EDA_UNITS::INCH: return IU_TO_IN( aValue, aIuScale );
299 case EDA_UNITS::DEGREES: return aValue;
300 case EDA_UNITS::FS: return IU_TO_PS( aValue, aIuScale ) * 1000.0;
301 case EDA_UNITS::PS: return IU_TO_PS( aValue, aIuScale );
302 case EDA_UNITS::PS_PER_INCH: return IU_TO_PS_PER_MM( aValue, aIuScale ) * 25.4;
303 case EDA_UNITS::PS_PER_CM: return IU_TO_PS_PER_MM( aValue, aIuScale ) * 10;
304 case EDA_UNITS::PS_PER_MM: return IU_TO_PS_PER_MM( aValue, aIuScale );
305 default: return aValue;
306 }
307}
308
309
311 double aValue, bool aAddUnitsText,
312 EDA_DATA_TYPE aType )
313{
314 double value_to_print = aValue;
315 bool is_eeschema = ( aIuScale.IU_PER_MM == SCH_IU_PER_MM );
316
317 switch( aType )
318 {
320 value_to_print = ToUserUnit( aIuScale, aUnits, value_to_print );
322
324 value_to_print = ToUserUnit( aIuScale, aUnits, value_to_print );
326
328 value_to_print = ToUserUnit( aIuScale, aUnits, value_to_print );
329 break;
330
332 break;
333
335 value_to_print = ToUserUnit( aIuScale, aUnits, value_to_print );
336 break;
337
339 value_to_print = ToUserUnit( aIuScale, aUnits, value_to_print );
340 break;
341 }
342
343 const wxChar* format = nullptr;
344
345 switch( aUnits )
346 {
347 case EDA_UNITS::MILS: format = is_eeschema ? wxT( "%.3f" ) : wxT( "%.5f" ); break;
348 case EDA_UNITS::INCH: format = is_eeschema ? wxT( "%.6f" ) : wxT( "%.8f" ); break;
349 case EDA_UNITS::DEGREES: format = wxT( "%.4f" ); break;
350 case EDA_UNITS::PS_PER_INCH: format = wxT( "%.4f" ); break;
351 case EDA_UNITS::PS_PER_CM: format = wxT( "%.3f" ); break;
352 case EDA_UNITS::PS_PER_MM: format = wxT( "%.3f" ); break;
353 default: format = wxT( "%.10f" ); break;
354 }
355
356 wxString text;
357 text.Printf( format, value_to_print );
359
360 if( value_to_print != 0.0 && ( text == wxS( "0" ) || text == wxS( "-0" ) ) )
361 {
362 text.Printf( wxS( "%.10f" ), value_to_print );
364 }
365
366 if( aAddUnitsText )
367 text << EDA_UNIT_UTILS::GetText( aUnits, aType );
368
369 return text;
370}
371
372
373
374// A lower-precision (for readability) version of StringFromValue()
376 int aValue,
377 bool aAddUnitLabel,
378 EDA_DATA_TYPE aType )
379{
380 return MessageTextFromValue( aIuScale, aUnits, double( aValue ), aAddUnitLabel, aType );
381}
382
383
384// A lower-precision (for readability) version of StringFromValue()
386 long long int aValue,
387 bool aAddUnitLabel,
388 EDA_DATA_TYPE aType )
389{
390 return MessageTextFromValue( aIuScale, aUnits, double( aValue ), aAddUnitLabel, aType );
391}
392
393
394wxString EDA_UNIT_UTILS::UI::MessageTextFromValue( EDA_ANGLE aValue, bool aAddUnitLabel )
395{
396 if( aAddUnitLabel )
397 return wxString::Format( wxT( "%.1f°" ), aValue.AsDegrees() );
398 else
399 return wxString::Format( wxT( "%.1f" ), aValue.AsDegrees() );
400}
401
402
403// A lower-precision (for readability) version of StringFromValue()
405 double aValue, bool aAddUnitsText,
406 EDA_DATA_TYPE aType )
407{
408 wxString text;
409 const wxChar* format;
410 double value = aValue;
411 bool short_form = ( aIuScale.IU_PER_MM == SCH_IU_PER_MM )
412 || ( aType == EDA_DATA_TYPE::VOLUME || aType == EDA_DATA_TYPE::AREA );
413
414 switch( aType )
415 {
417 value = ToUserUnit( aIuScale, aUnits, value );
418 // Fall through to continue computation
420
422 value = ToUserUnit( aIuScale, aUnits, value );
423 // Fall through to continue computation
425
427 value = ToUserUnit( aIuScale, aUnits, value );
428 break;
429
431 break;
432
434 value = ToUserUnit( aIuScale, aUnits, value );
435 break;
436
438 value = ToUserUnit( aIuScale, aUnits, value );
439 break;
440 }
441
442 switch( aUnits )
443 {
444 default:
445 case EDA_UNITS::UM: format = short_form ? wxT( "%.0f" ) : wxT( "%.1f" ); break;
446 case EDA_UNITS::MM: format = short_form ? wxT( "%.3f" ) : wxT( "%.4f" ); break;
447 case EDA_UNITS::CM: format = short_form ? wxT( "%.3f" ) : wxT( "%.5f" ); break;
448 case EDA_UNITS::MILS: format = short_form ? wxT( "%.0f" ) : wxT( "%.2f" ); break;
449 case EDA_UNITS::INCH: format = short_form ? wxT( "%.3f" ) : wxT( "%.4f" ); break;
450 case EDA_UNITS::DEGREES: format = wxT( "%.3f" ); break;
451 case EDA_UNITS::UNSCALED: format = wxT( "%.0f" ); break;
452 case EDA_UNITS::FS: format = wxT( "%.4f" ); break;
453 case EDA_UNITS::PS: format = wxT( "%.2f" ); break;
454 case EDA_UNITS::PS_PER_INCH: format = wxT( "%.2f" ); break;
455 case EDA_UNITS::PS_PER_CM: format = wxT( "%.2f" ); break;
456 case EDA_UNITS::PS_PER_MM: format = wxT( "%.2f" ); break;
457 }
458
459 text.Printf( format, value );
460
461 // Check if the formatted value shows only zeros but the actual value is non-zero
462 // If so, use scientific notation instead
463 if( value != 0.0 )
464 {
465 bool showsOnlyZeros = true;
466
467 // Check if the text contains only zeros (allowing for decimal point, minus sign, etc.)
468 for( auto ch : text )
469 {
470 if( ch >= '1' && ch <= '9' )
471 {
472 showsOnlyZeros = false;
473 break;
474 }
475 }
476
477 if( showsOnlyZeros )
478 {
479 text.Printf( wxT( "%.3e" ), value );
480 }
481 }
482
483 // Trim to 2-1/2 digits after the decimal place for short-form mm
484 if( short_form && aUnits == EDA_UNITS::MM )
485 {
486 struct lconv* lc = localeconv();
487 int length = (int) text.Length();
488
489 if( length > 4 && text[length - 4] == *lc->decimal_point && text[length - 1] == '0' )
490 text = text.Left( length - 1 );
491 }
492
493 if( aAddUnitsText )
494 text += EDA_UNIT_UTILS::GetText( aUnits, aType );
495
496 return text;
497}
498
499
501 EDA_UNITS aUnits,
502 const MINOPTMAX<int>& aValue )
503{
504 wxString msg;
505
506 if( aValue.HasMin() && aValue.Min() > 0 )
507 {
508 msg += _( "min" ) + wxS( " " ) + MessageTextFromValue( aIuScale, aUnits, aValue.Min() );
509 }
510
511 if( aValue.HasOpt() )
512 {
513 if( !msg.IsEmpty() )
514 msg += wxS( "; " );
515
516 msg += _( "opt" ) + wxS( " " ) + MessageTextFromValue( aIuScale, aUnits, aValue.Opt() );
517 }
518
519 if( aValue.HasMax() )
520 {
521 if( !msg.IsEmpty() )
522 msg += wxS( "; " );
523
524 msg += _( "max" ) + wxS( " " ) + MessageTextFromValue( aIuScale, aUnits, aValue.Max() );
525 }
526
527 return msg;
528};
529
530
532 double aValue )
533{
534 switch( aUnits )
535 {
536 case EDA_UNITS::UM: return MM_TO_IU( aValue / 1000.0, aIuScale );
537 case EDA_UNITS::MM: return MM_TO_IU( aValue, aIuScale );
538 case EDA_UNITS::CM: return MM_TO_IU( aValue * 10, aIuScale );
539 case EDA_UNITS::MILS: return MILS_TO_IU( aValue, aIuScale );
540 case EDA_UNITS::INCH: return IN_TO_IU( aValue, aIuScale );
541 case EDA_UNITS::FS: return PS_TO_IU( aValue / 1000.0, aIuScale );
542 case EDA_UNITS::PS: return PS_TO_IU( aValue, aIuScale );
543 case EDA_UNITS::PS_PER_INCH: return PS_PER_MM_TO_IU( aValue / 25.4, aIuScale );
544 case EDA_UNITS::PS_PER_CM: return PS_PER_MM_TO_IU( aValue / 10, aIuScale );
545 case EDA_UNITS::PS_PER_MM: return PS_PER_MM_TO_IU( aValue, aIuScale );
546 default:
549 case EDA_UNITS::PERCENT: return aValue;
550 }
551}
552
553
554double EDA_UNIT_UTILS::UI::DoubleValueFromString( const wxString& aTextValue )
555{
556 double dtmp = 0;
557
558 // Acquire the 'right' decimal point separator
559 const struct lconv* lc = localeconv();
560
561 wxChar decimal_point = lc->decimal_point[0];
562 wxString buf( aTextValue.Strip( wxString::both ) );
563
564 // Convert any entered decimal point separators to the 'right' one
565 buf.Replace( wxT( "." ), wxString( decimal_point, 1 ) );
566 buf.Replace( wxT( "," ), wxString( decimal_point, 1 ) );
567
568 // Find the end of the numeric part
569 unsigned brk_point = 0;
570
571 while( brk_point < buf.Len() )
572 {
573 wxChar ch = buf[brk_point];
574
575 if( !( ( ch >= '0' && ch <= '9' ) || ( ch == decimal_point ) || ( ch == '-' )
576 || ( ch == '+' ) ) )
577 {
578 break;
579 }
580
581 ++brk_point;
582 }
583
584 // Extract the numeric part
585 buf.Left( brk_point ).ToDouble( &dtmp );
586
587 return dtmp;
588}
589
590
592 const wxString& aTextValue, EDA_DATA_TYPE aType )
593{
594 double dtmp = 0;
595
596 // Acquire the 'right' decimal point separator
597 const struct lconv* lc = localeconv();
598
599 wxChar decimal_point = lc->decimal_point[0];
600 wxString buf( aTextValue.Strip( wxString::both ) );
601
602 // Convert any entered decimal point separators to the 'right' one
603 buf.Replace( wxT( "." ), wxString( decimal_point, 1 ) );
604 buf.Replace( wxT( "," ), wxString( decimal_point, 1 ) );
605
606 // Find the end of the numeric part
607 unsigned brk_point = 0;
608
609 while( brk_point < buf.Len() )
610 {
611 wxChar ch = buf[brk_point];
612
613 if( !( (ch >= '0' && ch <= '9') || (ch == decimal_point) || (ch == '-') || (ch == '+') ) )
614 break;
615
616 ++brk_point;
617 }
618
619 // Extract the numeric part
620 buf.Left( brk_point ).ToDouble( &dtmp );
621
622 // Check the optional unit designator (2 ch significant)
623 wxString unit( buf.Mid( brk_point ).Trim( false ).Left( 2 ).Lower() );
624
625 if( aUnits == EDA_UNITS::UM
626 || aUnits == EDA_UNITS::MM
627 || aUnits == EDA_UNITS::CM
628 || aUnits == EDA_UNITS::MILS
629 || aUnits == EDA_UNITS::INCH )
630 {
631 //check for um, μm (µ is MICRO SIGN) and µm (µ is GREEK SMALL LETTER MU) for micrometre
632 if( unit == wxT( "um" ) || unit == wxT( "\u00B5m" ) || unit == wxT( "\u03BCm" ) )
633 {
634 aUnits = EDA_UNITS::UM;
635 }
636 else if( unit == wxT( "mm" ) )
637 {
638 aUnits = EDA_UNITS::MM;
639 }
640 else if( unit == wxT( "cm" ) )
641 {
642 aUnits = EDA_UNITS::CM;
643 }
644 else if( unit == wxT( "mi" ) || unit == wxT( "th" ) )
645 {
646 aUnits = EDA_UNITS::MILS;
647 }
648 else if( unit == wxT( "in" ) || unit == wxT( "\"" ) )
649 {
650 aUnits = EDA_UNITS::INCH;
651 }
652 else if( unit == wxT( "oz" ) ) // 1 oz = 1.37 mils
653 {
654 aUnits = EDA_UNITS::MILS;
655 dtmp *= 1.37;
656 }
657 }
658 else if( aUnits == EDA_UNITS::DEGREES )
659 {
660 if( unit == wxT( "ra" ) ) // Radians
661 dtmp *= 180.0f / M_PI;
662 }
663 else if( aUnits == EDA_UNITS::FS || aUnits == EDA_UNITS::PS || aUnits == EDA_UNITS::PS_PER_INCH
664 || aUnits == EDA_UNITS::PS_PER_CM || aUnits == EDA_UNITS::PS_PER_MM )
665
666 {
667 wxString timeUnit( buf.Mid( brk_point ).Trim( false ).Left( 5 ).Lower() );
668
669 if( timeUnit == wxT( "fs" ) )
670 aUnits = EDA_UNITS::FS;
671 if( timeUnit == wxT( "ps" ) )
672 aUnits = EDA_UNITS::PS;
673 else if( timeUnit == wxT( "ps/in" ) )
674 aUnits = EDA_UNITS::PS_PER_INCH;
675 else if( timeUnit == wxT( "ps/cm" ) )
676 aUnits = EDA_UNITS::PS_PER_CM;
677 else if( timeUnit == wxT( "ps/mm" ) )
678 aUnits = EDA_UNITS::PS_PER_MM;
679 }
680
681 switch( aType )
682 {
684 dtmp = FromUserUnit( aIuScale, aUnits, dtmp );
686
688 dtmp = FromUserUnit( aIuScale, aUnits, dtmp );
690
692 dtmp = FromUserUnit( aIuScale, aUnits, dtmp );
693 break;
694
696 break;
697
699 dtmp = FromUserUnit( aIuScale, aUnits, dtmp );
700 break;
701
703 dtmp = FromUserUnit( aIuScale, aUnits, dtmp );
704 break;
705 }
706
707 return dtmp;
708}
709
710
711bool EDA_UNIT_UTILS::UI::DoubleValueFromString( const EDA_IU_SCALE& aIuScale, const wxString& aTextValue,
712 double& aDoubleValue )
713{
714 double dtmp = 0;
715
716 // Acquire the 'right' decimal point separator
717 const struct lconv* lc = localeconv();
718
719 wxChar decimal_point = lc->decimal_point[0];
720 wxString buf( aTextValue.Strip( wxString::both ) );
721
722 // Convert any entered decimal point separators to the 'right' one
723 buf.Replace( wxT( "." ), wxString( decimal_point, 1 ) );
724 buf.Replace( wxT( "," ), wxString( decimal_point, 1 ) );
725
726 // Find the end of the numeric part
727 unsigned brk_point = 0;
728
729 while( brk_point < buf.Len() )
730 {
731 wxChar ch = buf[brk_point];
732
733 if( !( (ch >= '0' && ch <= '9') || (ch == decimal_point) || (ch == '-') || (ch == '+') ) )
734 break;
735
736 ++brk_point;
737 }
738
739 if( brk_point == 0 )
740 return false;
741
742 // Extract the numeric part
743 buf.Left( brk_point ).ToDouble( &dtmp );
744
745 // Check the unit designator
746 wxString unit( buf.Mid( brk_point ).Strip( wxString::both ).Lower() );
747 EDA_UNITS units = EDA_UNITS::MM; // Make gcc quiet
748
749 //check for um, μm (µ is MICRO SIGN) and µm (µ is GREEK SMALL LETTER MU) for micrometre
750 if( unit == wxT( "um" ) || unit == wxT( "\u00B5m" ) || unit == wxT( "\u03BCm" ) )
751 {
752 units = EDA_UNITS::UM;
753 }
754 else if( unit == wxT( "mm" ) )
755 {
756 units = EDA_UNITS::MM;
757 }
758 else if( unit == wxT( "cm" ) )
759 {
760 units = EDA_UNITS::CM;
761 }
762 else if( unit == wxT( "mil" ) || unit == wxT( "mils" ) || unit == wxT( "thou" ) )
763 {
764 units = EDA_UNITS::MILS;
765 }
766 else if( unit == wxT( "in" ) || unit == wxT( "\"" ) )
767 {
768 units = EDA_UNITS::INCH;
769 }
770 else if( unit == wxT( "oz" ) ) // 1 oz = 1.37 mils
771 {
772 units = EDA_UNITS::MILS;
773 dtmp *= 1.37;
774 }
775 else if( unit == wxT( "ra" ) ) // Radians
776 {
777 dtmp *= 180.0f / M_PI;
778 }
779 else if( unit == wxT( "fs" ) )
780 {
781 units = EDA_UNITS::FS;
782 }
783 else if( unit == wxT( "ps" ) )
784 {
785 units = EDA_UNITS::PS;
786 }
787 else if( unit == wxT( "ps/in" ) )
788 {
790 }
791 else if( unit == wxT( "ps/cm" ) )
792 {
793 units = EDA_UNITS::PS_PER_CM;
794 }
795 else if( unit == wxT( "ps/mm" ) )
796 {
797 units = EDA_UNITS::PS_PER_MM;
798 }
799 else
800 {
801 return false;
802 }
803
804 aDoubleValue = FromUserUnit( aIuScale, units, dtmp );
805 return true;
806}
807
808
809long long int EDA_UNIT_UTILS::UI::ValueFromString( const EDA_IU_SCALE& aIuScale, EDA_UNITS aUnits,
810 const wxString& aTextValue, EDA_DATA_TYPE aType )
811{
812 double value = DoubleValueFromString( aIuScale, aUnits, aTextValue, aType );
813
814 return KiROUND<double, long long int>( value );
815}
816
817
818long long int EDA_UNIT_UTILS::UI::ValueFromString( const wxString& aTextValue )
819{
820 double value = DoubleValueFromString( aTextValue );
821
822 return KiROUND<double, long long int>( value );
823}
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 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 FormatInternalUnits(const EDA_IU_SCALE &aIuScale, int aValue)
Converts aValue from internal units to a string appropriate for writing to file.
KICOMMON_API std::string FormatAngle(const EDA_ANGLE &aAngle)
Convert aAngle from board 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_MM
Definition base_units.h:76
#define M_PI
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695