You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

693 lines
22 KiB

10 months ago
10 months ago
10 months ago
10 months ago
3 years ago
10 months ago
10 months ago
10 months ago
10 months ago
3 years ago
  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. #include <eda_units.h>
  24. #include <fmt/core.h>
  25. #include <math/util.h> // for KiROUND
  26. #include <macros.h>
  27. #include <charconv>
  28. #include <wx/translation.h>
  29. static void removeTrailingZeros( wxString& aText )
  30. {
  31. int len = aText.length();
  32. int removeLast = 0;
  33. while( --len > 0 && aText[len] == '0' )
  34. removeLast++;
  35. if( len >= 0 && ( aText[len] == '.' || aText[len] == ',' ) )
  36. removeLast++;
  37. aText = aText.RemoveLast( removeLast );
  38. }
  39. bool EDA_UNIT_UTILS::IsImperialUnit( EDA_UNITS aUnit )
  40. {
  41. switch( aUnit )
  42. {
  43. case EDA_UNITS::INCH:
  44. case EDA_UNITS::MILS:
  45. return true;
  46. default:
  47. return false;
  48. }
  49. }
  50. bool EDA_UNIT_UTILS::IsMetricUnit( EDA_UNITS aUnit )
  51. {
  52. switch( aUnit )
  53. {
  54. case EDA_UNITS::UM:
  55. case EDA_UNITS::MM:
  56. case EDA_UNITS::CM:
  57. return true;
  58. default:
  59. return false;
  60. }
  61. }
  62. int EDA_UNIT_UTILS::Mm2mils( double aVal )
  63. {
  64. return KiROUND( aVal * 1000. / 25.4 );
  65. }
  66. int EDA_UNIT_UTILS::Mils2mm( double aVal )
  67. {
  68. return KiROUND( aVal * 25.4 / 1000. );
  69. }
  70. bool EDA_UNIT_UTILS::FetchUnitsFromString( const wxString& aTextValue, EDA_UNITS& aUnits )
  71. {
  72. wxString buf( aTextValue.Strip( wxString::both ) );
  73. unsigned brk_point = 0;
  74. while( brk_point < buf.Len() )
  75. {
  76. wxChar c = buf[brk_point];
  77. if( !( ( c >= '0' && c <= '9' ) || ( c == '.' ) || ( c == ',' ) || ( c == '-' )
  78. || ( c == '+' ) ) )
  79. break;
  80. ++brk_point;
  81. }
  82. // Check the unit designator (2 ch significant)
  83. wxString unit( buf.Mid( brk_point ).Strip( wxString::leading ).Left( 2 ).Lower() );
  84. //check for um, μm (µ is MICRO SIGN) and µm (µ is GREEK SMALL LETTER MU) for micrometre
  85. if( unit == wxT( "um" ) || unit == wxT( "\u00B5m" ) || unit == wxT( "\u03BCm" ) )
  86. aUnits = EDA_UNITS::UM;
  87. else if( unit == wxT( "mm" ) )
  88. aUnits = EDA_UNITS::MM;
  89. if( unit == wxT( "cm" ) )
  90. aUnits = EDA_UNITS::CM;
  91. else if( unit == wxT( "mi" ) || unit == wxT( "th" ) ) // "mils" or "thou"
  92. aUnits = EDA_UNITS::MILS;
  93. else if( unit == wxT( "in" ) || unit == wxT( "\"" ) )
  94. aUnits = EDA_UNITS::INCH;
  95. else if( unit == wxT( "de" ) || unit == wxT( "ra" ) ) // "deg" or "rad"
  96. aUnits = EDA_UNITS::DEGREES;
  97. else if( unit == wxT("fs" ) )
  98. aUnits = EDA_UNITS::FS;
  99. else if( unit == wxT( "ps" ) )
  100. {
  101. wxString timeUnit( buf.Mid( brk_point ).Strip( wxString::leading ).Left( 5 ).Lower() );
  102. if( timeUnit == wxT( "ps" ) )
  103. aUnits = EDA_UNITS::PS;
  104. else if( timeUnit == wxT( "ps/in" ) )
  105. aUnits = EDA_UNITS::PS_PER_INCH;
  106. else if( timeUnit == wxT( "ps/cm" ) )
  107. aUnits = EDA_UNITS::PS_PER_CM;
  108. else if( timeUnit == wxT( "ps/mm" ) )
  109. aUnits = EDA_UNITS::PS_PER_MM;
  110. else
  111. return false;
  112. }
  113. else
  114. return false;
  115. return true;
  116. }
  117. wxString EDA_UNIT_UTILS::GetText( EDA_UNITS aUnits, EDA_DATA_TYPE aType )
  118. {
  119. wxString label;
  120. switch( aUnits )
  121. {
  122. case EDA_UNITS::UM: label = wxT( " \u00B5m" ); break; //00B5 for µ
  123. case EDA_UNITS::MM: label = wxT( " mm" ); break;
  124. case EDA_UNITS::CM: label = wxT( " cm" ); break;
  125. case EDA_UNITS::DEGREES: label = wxT( "°" ); break;
  126. case EDA_UNITS::MILS: label = wxT( " mils" ); break;
  127. case EDA_UNITS::INCH: label = wxT( " in" ); break;
  128. case EDA_UNITS::PERCENT: label = wxT( "%" ); break;
  129. case EDA_UNITS::FS: label = wxT( " fs" ); break;
  130. case EDA_UNITS::PS: label = wxT( " ps" ); break;
  131. case EDA_UNITS::PS_PER_INCH: label = wxT( " ps/in" ); break;
  132. case EDA_UNITS::PS_PER_CM: label = wxT( " ps/cm"); break;
  133. case EDA_UNITS::PS_PER_MM: label = wxT( " ps/mm"); break;
  134. case EDA_UNITS::UNSCALED: break;
  135. default: UNIMPLEMENTED_FOR( wxS( "Unknown units" ) ); break;
  136. }
  137. switch( aType )
  138. {
  139. case EDA_DATA_TYPE::VOLUME: label += wxT( "³" ); break;
  140. case EDA_DATA_TYPE::AREA: label += wxT( "²" ); break;
  141. case EDA_DATA_TYPE::DISTANCE: break;
  142. case EDA_DATA_TYPE::TIME: break;
  143. case EDA_DATA_TYPE::LENGTH_DELAY: break;
  144. default: UNIMPLEMENTED_FOR( wxS( "Unknown measurement" ) ); break;
  145. }
  146. return label;
  147. }
  148. wxString EDA_UNIT_UTILS::GetLabel( EDA_UNITS aUnits, EDA_DATA_TYPE aType )
  149. {
  150. return GetText( aUnits, aType ).Trim( false );
  151. }
  152. std::string EDA_UNIT_UTILS::FormatAngle( const EDA_ANGLE& aAngle )
  153. {
  154. std::string temp = fmt::format( "{:.10g}", aAngle.AsDegrees() );
  155. return temp;
  156. }
  157. std::string EDA_UNIT_UTILS::FormatInternalUnits( const EDA_IU_SCALE& aIuScale, int aValue )
  158. {
  159. std::string buf;
  160. double engUnits = aValue;
  161. engUnits /= aIuScale.IU_PER_MM;
  162. if( engUnits != 0.0 && fabs( engUnits ) <= 0.0001 )
  163. {
  164. buf = fmt::format( "{:.10f}", engUnits );
  165. // remove trailing zeros
  166. while( !buf.empty() && buf[buf.size() - 1] == '0' )
  167. {
  168. buf.pop_back();
  169. }
  170. // if the value was really small
  171. // we may have just stripped all the zeros after the decimal
  172. if( buf[buf.size() - 1] == '.' )
  173. {
  174. buf.pop_back();
  175. }
  176. }
  177. else
  178. {
  179. buf = fmt::format( "{:.10g}", engUnits );
  180. }
  181. return buf;
  182. }
  183. std::string EDA_UNIT_UTILS::FormatInternalUnits( const EDA_IU_SCALE& aIuScale,
  184. const VECTOR2I& aPoint )
  185. {
  186. return FormatInternalUnits( aIuScale, aPoint.x ) + " "
  187. + FormatInternalUnits( aIuScale, aPoint.y );
  188. }
  189. #if 0 // No support for std::from_chars on MacOS yet
  190. bool EDA_UNIT_UTILS::ParseInternalUnits( const std::string& aInput, const EDA_IU_SCALE& aIuScale,
  191. int& aOut )
  192. {
  193. double value;
  194. if( std::from_chars( aInput.data(), aInput.data() + aInput.size(), value ).ec != std::errc() )
  195. return false;
  196. aOut = value * aIuScale.IU_PER_MM;
  197. return true;
  198. }
  199. bool EDA_UNIT_UTILS::ParseInternalUnits( const std::string& aInput, const EDA_IU_SCALE& aIuScale,
  200. VECTOR2I& aOut )
  201. {
  202. size_t pos = aInput.find( ' ' );
  203. if( pos == std::string::npos )
  204. return false;
  205. std::string first = aInput.substr( 0, pos );
  206. std::string second = aInput.substr( pos + 1 );
  207. VECTOR2I vec;
  208. if( !ParseInternalUnits( first, aIuScale, vec.x ) )
  209. return false;
  210. if( !ParseInternalUnits( second, aIuScale, vec.y ) )
  211. return false;
  212. aOut = vec;
  213. return true;
  214. }
  215. #endif
  216. #define IU_TO_MM( x, scale ) ( x / scale.IU_PER_MM )
  217. #define IU_TO_IN( x, scale ) ( x / scale.IU_PER_MILS / 1000 )
  218. #define IU_TO_MILS( x, scale ) ( x / scale.IU_PER_MILS )
  219. #define IU_TO_PS( x, scale ) ( x / scale.IU_PER_PS )
  220. #define IU_TO_PS_PER_MM( x, scale ) ( x / scale.IU_PER_PS_PER_MM )
  221. #define MM_TO_IU( x, scale ) ( x * scale.IU_PER_MM )
  222. #define IN_TO_IU( x, scale ) ( x * scale.IU_PER_MILS * 1000 )
  223. #define MILS_TO_IU( x, scale ) ( x * scale.IU_PER_MILS )
  224. #define PS_TO_IU( x, scale ) ( x * scale.IU_PER_PS )
  225. #define PS_PER_MM_TO_IU( x, scale ) ( x * scale.IU_PER_PS_PER_MM )
  226. double EDA_UNIT_UTILS::UI::ToUserUnit( const EDA_IU_SCALE& aIuScale, EDA_UNITS aUnit,
  227. double aValue )
  228. {
  229. switch( aUnit )
  230. {
  231. case EDA_UNITS::UM: return IU_TO_MM( aValue, aIuScale ) * 1000;
  232. case EDA_UNITS::MM: return IU_TO_MM( aValue, aIuScale );
  233. case EDA_UNITS::CM: return IU_TO_MM( aValue, aIuScale ) / 10;
  234. case EDA_UNITS::MILS: return IU_TO_MILS( aValue, aIuScale );
  235. case EDA_UNITS::INCH: return IU_TO_IN( aValue, aIuScale );
  236. case EDA_UNITS::DEGREES: return aValue;
  237. case EDA_UNITS::FS: return IU_TO_PS( aValue, aIuScale ) * 1000.0;
  238. case EDA_UNITS::PS: return IU_TO_PS( aValue, aIuScale );
  239. case EDA_UNITS::PS_PER_INCH: return IU_TO_PS_PER_MM( aValue, aIuScale ) * 25.4;
  240. case EDA_UNITS::PS_PER_CM: return IU_TO_PS_PER_MM( aValue, aIuScale ) * 10;
  241. case EDA_UNITS::PS_PER_MM: return IU_TO_PS_PER_MM( aValue, aIuScale );
  242. default: return aValue;
  243. }
  244. }
  245. wxString EDA_UNIT_UTILS::UI::StringFromValue( const EDA_IU_SCALE& aIuScale, EDA_UNITS aUnits,
  246. double aValue, bool aAddUnitsText,
  247. EDA_DATA_TYPE aType )
  248. {
  249. double value_to_print = aValue;
  250. bool is_eeschema = ( aIuScale.IU_PER_MM == SCH_IU_PER_MM );
  251. switch( aType )
  252. {
  253. case EDA_DATA_TYPE::VOLUME:
  254. value_to_print = ToUserUnit( aIuScale, aUnits, value_to_print );
  255. KI_FALLTHROUGH;
  256. case EDA_DATA_TYPE::AREA:
  257. value_to_print = ToUserUnit( aIuScale, aUnits, value_to_print );
  258. KI_FALLTHROUGH;
  259. case EDA_DATA_TYPE::DISTANCE:
  260. value_to_print = ToUserUnit( aIuScale, aUnits, value_to_print );
  261. break;
  262. case EDA_DATA_TYPE::UNITLESS:
  263. break;
  264. case EDA_DATA_TYPE::TIME:
  265. value_to_print = ToUserUnit( aIuScale, aUnits, value_to_print );
  266. break;
  267. case EDA_DATA_TYPE::LENGTH_DELAY:
  268. value_to_print = ToUserUnit( aIuScale, aUnits, value_to_print );
  269. break;
  270. }
  271. const wxChar* format = nullptr;
  272. switch( aUnits )
  273. {
  274. case EDA_UNITS::MILS: format = is_eeschema ? wxT( "%.3f" ) : wxT( "%.5f" ); break;
  275. case EDA_UNITS::INCH: format = is_eeschema ? wxT( "%.6f" ) : wxT( "%.8f" ); break;
  276. case EDA_UNITS::DEGREES: format = wxT( "%.4f" ); break;
  277. case EDA_UNITS::PS_PER_INCH: format = wxT( "%.4f" ); break;
  278. case EDA_UNITS::PS_PER_CM: format = wxT( "%.3f" ); break;
  279. case EDA_UNITS::PS_PER_MM: format = wxT( "%.3f" ); break;
  280. default: format = wxT( "%.10f" ); break;
  281. }
  282. wxString text;
  283. text.Printf( format, value_to_print );
  284. removeTrailingZeros( text );
  285. if( value_to_print != 0.0 && ( text == wxS( "0" ) || text == wxS( "-0" ) ) )
  286. {
  287. text.Printf( wxS( "%.10f" ), value_to_print );
  288. removeTrailingZeros( text );
  289. }
  290. if( aAddUnitsText )
  291. text << EDA_UNIT_UTILS::GetText( aUnits, aType );
  292. return text;
  293. }
  294. // A lower-precision (for readability) version of StringFromValue()
  295. wxString EDA_UNIT_UTILS::UI::MessageTextFromValue( const EDA_IU_SCALE& aIuScale, EDA_UNITS aUnits,
  296. int aValue,
  297. bool aAddUnitLabel,
  298. EDA_DATA_TYPE aType )
  299. {
  300. return MessageTextFromValue( aIuScale, aUnits, double( aValue ), aAddUnitLabel, aType );
  301. }
  302. // A lower-precision (for readability) version of StringFromValue()
  303. wxString EDA_UNIT_UTILS::UI::MessageTextFromValue( const EDA_IU_SCALE& aIuScale, EDA_UNITS aUnits,
  304. long long int aValue,
  305. bool aAddUnitLabel,
  306. EDA_DATA_TYPE aType )
  307. {
  308. return MessageTextFromValue( aIuScale, aUnits, double( aValue ), aAddUnitLabel, aType );
  309. }
  310. wxString EDA_UNIT_UTILS::UI::MessageTextFromValue( EDA_ANGLE aValue, bool aAddUnitLabel )
  311. {
  312. if( aAddUnitLabel )
  313. return wxString::Format( wxT( "%.1f°" ), aValue.AsDegrees() );
  314. else
  315. return wxString::Format( wxT( "%.1f" ), aValue.AsDegrees() );
  316. }
  317. // A lower-precision (for readability) version of StringFromValue()
  318. wxString EDA_UNIT_UTILS::UI::MessageTextFromValue( const EDA_IU_SCALE& aIuScale, EDA_UNITS aUnits,
  319. double aValue, bool aAddUnitsText,
  320. EDA_DATA_TYPE aType )
  321. {
  322. wxString text;
  323. const wxChar* format;
  324. double value = aValue;
  325. bool short_form = ( aIuScale.IU_PER_MM == SCH_IU_PER_MM )
  326. || ( aType == EDA_DATA_TYPE::VOLUME || aType == EDA_DATA_TYPE::AREA );
  327. switch( aType )
  328. {
  329. case EDA_DATA_TYPE::VOLUME:
  330. value = ToUserUnit( aIuScale, aUnits, value );
  331. // Fall through to continue computation
  332. KI_FALLTHROUGH;
  333. case EDA_DATA_TYPE::AREA:
  334. value = ToUserUnit( aIuScale, aUnits, value );
  335. // Fall through to continue computation
  336. KI_FALLTHROUGH;
  337. case EDA_DATA_TYPE::DISTANCE:
  338. value = ToUserUnit( aIuScale, aUnits, value );
  339. break;
  340. case EDA_DATA_TYPE::UNITLESS:
  341. break;
  342. case EDA_DATA_TYPE::TIME:
  343. value = ToUserUnit( aIuScale, aUnits, value );
  344. break;
  345. case EDA_DATA_TYPE::LENGTH_DELAY:
  346. value = ToUserUnit( aIuScale, aUnits, value );
  347. break;
  348. }
  349. switch( aUnits )
  350. {
  351. default:
  352. case EDA_UNITS::UM: format = short_form ? wxT( "%.0f" ) : wxT( "%.1f" ); break;
  353. case EDA_UNITS::MM: format = short_form ? wxT( "%.2f" ) : wxT( "%.4f" ); break;
  354. case EDA_UNITS::CM: format = short_form ? wxT( "%.3f" ) : wxT( "%.5f" ); break;
  355. case EDA_UNITS::MILS: format = short_form ? wxT( "%.0f" ) : wxT( "%.2f" ); break;
  356. case EDA_UNITS::INCH: format = short_form ? wxT( "%.3f" ) : wxT( "%.4f" ); break;
  357. case EDA_UNITS::DEGREES: format = wxT( "%.3f" ); break;
  358. case EDA_UNITS::UNSCALED: format = wxT( "%.0f" ); break;
  359. case EDA_UNITS::FS: format = wxT( "%.4f" ); break;
  360. case EDA_UNITS::PS: format = wxT( "%.2f" ); break;
  361. case EDA_UNITS::PS_PER_INCH: format = wxT( "%.2f" ); break;
  362. case EDA_UNITS::PS_PER_CM: format = wxT( "%.2f" ); break;
  363. case EDA_UNITS::PS_PER_MM: format = wxT( "%.2f" ); break;
  364. }
  365. text.Printf( format, value );
  366. if( aAddUnitsText )
  367. text += EDA_UNIT_UTILS::GetText( aUnits, aType );
  368. return text;
  369. }
  370. wxString EDA_UNIT_UTILS::UI::MessageTextFromMinOptMax( const EDA_IU_SCALE& aIuScale,
  371. EDA_UNITS aUnits,
  372. const MINOPTMAX<int>& aValue )
  373. {
  374. wxString msg;
  375. if( aValue.HasMin() && aValue.Min() > 0 )
  376. {
  377. msg += _( "min" ) + wxS( " " ) + MessageTextFromValue( aIuScale, aUnits, aValue.Min() );
  378. }
  379. if( aValue.HasOpt() )
  380. {
  381. if( !msg.IsEmpty() )
  382. msg += wxS( "; " );
  383. msg += _( "opt" ) + wxS( " " ) + MessageTextFromValue( aIuScale, aUnits, aValue.Opt() );
  384. }
  385. if( aValue.HasMax() )
  386. {
  387. if( !msg.IsEmpty() )
  388. msg += wxS( "; " );
  389. msg += _( "max" ) + wxS( " " ) + MessageTextFromValue( aIuScale, aUnits, aValue.Max() );
  390. }
  391. return msg;
  392. };
  393. double EDA_UNIT_UTILS::UI::FromUserUnit( const EDA_IU_SCALE& aIuScale, EDA_UNITS aUnits,
  394. double aValue )
  395. {
  396. switch( aUnits )
  397. {
  398. case EDA_UNITS::UM: return MM_TO_IU( aValue / 1000.0, aIuScale );
  399. case EDA_UNITS::MM: return MM_TO_IU( aValue, aIuScale );
  400. case EDA_UNITS::CM: return MM_TO_IU( aValue * 10, aIuScale );
  401. case EDA_UNITS::MILS: return MILS_TO_IU( aValue, aIuScale );
  402. case EDA_UNITS::INCH: return IN_TO_IU( aValue, aIuScale );
  403. case EDA_UNITS::FS: return PS_TO_IU( aValue / 1000.0, aIuScale );
  404. case EDA_UNITS::PS: return PS_TO_IU( aValue, aIuScale );
  405. case EDA_UNITS::PS_PER_INCH: return PS_PER_MM_TO_IU( aValue / 25.4, aIuScale );
  406. case EDA_UNITS::PS_PER_CM: return PS_PER_MM_TO_IU( aValue / 10, aIuScale );
  407. case EDA_UNITS::PS_PER_MM: return PS_PER_MM_TO_IU( aValue, aIuScale );
  408. default:
  409. case EDA_UNITS::DEGREES:
  410. case EDA_UNITS::UNSCALED:
  411. case EDA_UNITS::PERCENT: return aValue;
  412. }
  413. }
  414. double EDA_UNIT_UTILS::UI::DoubleValueFromString( const wxString& aTextValue )
  415. {
  416. double dtmp = 0;
  417. // Acquire the 'right' decimal point separator
  418. const struct lconv* lc = localeconv();
  419. wxChar decimal_point = lc->decimal_point[0];
  420. wxString buf( aTextValue.Strip( wxString::both ) );
  421. // Convert any entered decimal point separators to the 'right' one
  422. buf.Replace( wxT( "." ), wxString( decimal_point, 1 ) );
  423. buf.Replace( wxT( "," ), wxString( decimal_point, 1 ) );
  424. // Find the end of the numeric part
  425. unsigned brk_point = 0;
  426. while( brk_point < buf.Len() )
  427. {
  428. wxChar ch = buf[brk_point];
  429. if( !( ( ch >= '0' && ch <= '9' ) || ( ch == decimal_point ) || ( ch == '-' )
  430. || ( ch == '+' ) ) )
  431. {
  432. break;
  433. }
  434. ++brk_point;
  435. }
  436. // Extract the numeric part
  437. buf.Left( brk_point ).ToDouble( &dtmp );
  438. return dtmp;
  439. }
  440. double EDA_UNIT_UTILS::UI::DoubleValueFromString( const EDA_IU_SCALE& aIuScale, EDA_UNITS aUnits,
  441. const wxString& aTextValue, EDA_DATA_TYPE aType )
  442. {
  443. double dtmp = 0;
  444. // Acquire the 'right' decimal point separator
  445. const struct lconv* lc = localeconv();
  446. wxChar decimal_point = lc->decimal_point[0];
  447. wxString buf( aTextValue.Strip( wxString::both ) );
  448. // Convert any entered decimal point separators to the 'right' one
  449. buf.Replace( wxT( "." ), wxString( decimal_point, 1 ) );
  450. buf.Replace( wxT( "," ), wxString( decimal_point, 1 ) );
  451. // Find the end of the numeric part
  452. unsigned brk_point = 0;
  453. while( brk_point < buf.Len() )
  454. {
  455. wxChar ch = buf[brk_point];
  456. if( !( (ch >= '0' && ch <= '9') || (ch == decimal_point) || (ch == '-') || (ch == '+') ) )
  457. break;
  458. ++brk_point;
  459. }
  460. // Extract the numeric part
  461. buf.Left( brk_point ).ToDouble( &dtmp );
  462. // Check the optional unit designator (2 ch significant)
  463. wxString unit( buf.Mid( brk_point ).Strip( wxString::leading ).Left( 2 ).Lower() );
  464. if( aUnits == EDA_UNITS::UM
  465. || aUnits == EDA_UNITS::MM
  466. || aUnits == EDA_UNITS::CM
  467. || aUnits == EDA_UNITS::MILS
  468. || aUnits == EDA_UNITS::INCH )
  469. {
  470. //check for um, μm (µ is MICRO SIGN) and µm (µ is GREEK SMALL LETTER MU) for micrometre
  471. if( unit == wxT( "um" ) || unit == wxT( "\u00B5m" ) || unit == wxT( "\u03BCm" ) )
  472. {
  473. aUnits = EDA_UNITS::UM;
  474. }
  475. else if( unit == wxT( "mm" ) )
  476. {
  477. aUnits = EDA_UNITS::MM;
  478. }
  479. else if( unit == wxT( "cm" ) )
  480. {
  481. aUnits = EDA_UNITS::CM;
  482. }
  483. else if( unit == wxT( "mi" ) || unit == wxT( "th" ) )
  484. {
  485. aUnits = EDA_UNITS::MILS;
  486. }
  487. else if( unit == wxT( "in" ) || unit == wxT( "\"" ) )
  488. {
  489. aUnits = EDA_UNITS::INCH;
  490. }
  491. else if( unit == wxT( "oz" ) ) // 1 oz = 1.37 mils
  492. {
  493. aUnits = EDA_UNITS::MILS;
  494. dtmp *= 1.37;
  495. }
  496. }
  497. else if( aUnits == EDA_UNITS::DEGREES )
  498. {
  499. if( unit == wxT( "ra" ) ) // Radians
  500. dtmp *= 180.0f / M_PI;
  501. }
  502. else if( aUnits == EDA_UNITS::FS || aUnits == EDA_UNITS::PS || aUnits == EDA_UNITS::PS_PER_INCH
  503. || aUnits == EDA_UNITS::PS_PER_CM || aUnits == EDA_UNITS::PS_PER_MM )
  504. {
  505. wxString timeUnit( buf.Mid( brk_point ).Strip( wxString::leading ).Left( 5 ).Lower() );
  506. if( timeUnit == wxT( "fs" ) )
  507. aUnits = EDA_UNITS::FS;
  508. if( timeUnit == wxT( "ps" ) )
  509. aUnits = EDA_UNITS::PS;
  510. else if( timeUnit == wxT( "ps/in" ) )
  511. aUnits = EDA_UNITS::PS_PER_INCH;
  512. else if( timeUnit == wxT( "ps/cm" ) )
  513. aUnits = EDA_UNITS::PS_PER_CM;
  514. else if( timeUnit == wxT( "ps/mm" ) )
  515. aUnits = EDA_UNITS::PS_PER_MM;
  516. }
  517. switch( aType )
  518. {
  519. case EDA_DATA_TYPE::VOLUME:
  520. dtmp = FromUserUnit( aIuScale, aUnits, dtmp );
  521. KI_FALLTHROUGH;
  522. case EDA_DATA_TYPE::AREA:
  523. dtmp = FromUserUnit( aIuScale, aUnits, dtmp );
  524. KI_FALLTHROUGH;
  525. case EDA_DATA_TYPE::DISTANCE:
  526. dtmp = FromUserUnit( aIuScale, aUnits, dtmp );
  527. break;
  528. case EDA_DATA_TYPE::UNITLESS:
  529. break;
  530. case EDA_DATA_TYPE::TIME:
  531. dtmp = FromUserUnit( aIuScale, aUnits, dtmp );
  532. break;
  533. case EDA_DATA_TYPE::LENGTH_DELAY:
  534. dtmp = FromUserUnit( aIuScale, aUnits, dtmp );
  535. break;
  536. }
  537. return dtmp;
  538. }
  539. long long int EDA_UNIT_UTILS::UI::ValueFromString( const EDA_IU_SCALE& aIuScale, EDA_UNITS aUnits,
  540. const wxString& aTextValue, EDA_DATA_TYPE aType )
  541. {
  542. double value = DoubleValueFromString( aIuScale, aUnits, aTextValue, aType );
  543. return KiROUND<double, long long int>( value );
  544. }
  545. long long int EDA_UNIT_UTILS::UI::ValueFromString( const wxString& aTextValue )
  546. {
  547. double value = DoubleValueFromString( aTextValue );
  548. return KiROUND<double, long long int>( value );
  549. }