PageRenderTime 100ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 1ms

/PhysMeasure/PhysicalMeasure/PhysicalMeasure.2.Classes.cs

#
C# | 7916 lines | 6243 code | 1331 blank | 342 comment | 1447 complexity | 6d0760784ae4e865085f2ea494146e65 MD5 | raw file
  1. /* http://physicalmeasure.codeplex.com */
  2. /* http://en.wikipedia.org/wiki/International_System_of_Units */
  3. /* http://en.wikipedia.org/wiki/Physical_quantity */
  4. /* http://en.wikipedia.org/wiki/Physical_constant */
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Linq;
  8. using System.Diagnostics;
  9. using System.Globalization;
  10. using System.Runtime.Serialization;
  11. using static PhysicalMeasure.DimensionExponentsExtension;
  12. namespace PhysicalMeasure
  13. {
  14. #region Physical Measure Classes
  15. #region Physical Measure Exceptions
  16. [Serializable]
  17. public class PhysicalUnitFormatException : FormatException
  18. {
  19. public PhysicalUnitFormatException(String message, Exception innerException)
  20. : base(message, innerException)
  21. {
  22. }
  23. protected PhysicalUnitFormatException(SerializationInfo info, StreamingContext context)
  24. : base(info, context)
  25. {
  26. }
  27. public PhysicalUnitFormatException()
  28. : this("The string argument is not in a valid physical unit format.")
  29. {
  30. }
  31. public PhysicalUnitFormatException(String message)
  32. : base(message)
  33. {
  34. }
  35. }
  36. [Serializable]
  37. public class PhysicalUnitMathException : Exception
  38. {
  39. public PhysicalUnitMathException(String message, Exception innerException)
  40. : base(message, innerException)
  41. {
  42. }
  43. protected PhysicalUnitMathException(SerializationInfo info, StreamingContext context)
  44. : base(info, context)
  45. {
  46. }
  47. public PhysicalUnitMathException()
  48. : this("The result of the math operation on the Unit argument can't be represented by this implementation of PhysicalMeasure.")
  49. {
  50. }
  51. public PhysicalUnitMathException(String message)
  52. : base(message)
  53. {
  54. }
  55. }
  56. #endregion Physical Measure Exceptions
  57. #region Dimension Exponents Classes
  58. public class DimensionExponents : IEquatable<DimensionExponents>
  59. {
  60. private SByte[] exponents;
  61. public DimensionExponents(SByte[] exponents)
  62. {
  63. this.exponents = exponents;
  64. }
  65. public override int GetHashCode()
  66. {
  67. if (exponents == null)
  68. {
  69. return base.GetHashCode();
  70. }
  71. return exponents.GetHashCode();
  72. }
  73. public override Boolean Equals(Object obj)
  74. {
  75. if (obj == null)
  76. return false;
  77. DimensionExponents DimensionExponentsObj = obj as DimensionExponents;
  78. if (DimensionExponentsObj == null)
  79. return false;
  80. else
  81. return Equals(DimensionExponentsObj);
  82. }
  83. public Boolean Equals(DimensionExponents other)
  84. {
  85. if (other == null)
  86. return false;
  87. return Equals(this.exponents, other.exponents);
  88. }
  89. }
  90. public static class DimensionExponentsExtension
  91. {
  92. public static Boolean DimensionEquals(this SByte[] exponents1, SByte[] exponents2)
  93. {
  94. Debug.Assert(exponents1 != null, "Parameter must be specified");
  95. Debug.Assert(exponents2 != null, "Parameter must be specified");
  96. if (ReferenceEquals(exponents1, exponents2))
  97. {
  98. return true;
  99. }
  100. SByte MinNoOfBaseUnits = (SByte)Math.Min(exponents1.Length, exponents2.Length);
  101. SByte MaxNoOfBaseUnits = (SByte)Math.Max(exponents1.Length, exponents2.Length);
  102. Debug.Assert(MaxNoOfBaseUnits <= Physics.NoOfBaseQuanties + 1, "Too many base units:" + MaxNoOfBaseUnits.ToString() + ". No more than " + (Physics.NoOfBaseQuanties + 1) + " expected.");
  103. Boolean equal = true;
  104. SByte i = 0;
  105. do
  106. { // Compare exponents where defined in both arrays
  107. equal = exponents1[i] == exponents2[i];
  108. i++;
  109. }
  110. while (equal && i < MinNoOfBaseUnits);
  111. // Check tail of longest array to contain only zeros
  112. while (equal && i < MaxNoOfBaseUnits)
  113. {
  114. if (exponents1.Length > exponents2.Length)
  115. {
  116. equal = exponents1[i] == 0;
  117. }
  118. else
  119. {
  120. equal = exponents2[i] == 0;
  121. }
  122. i++;
  123. }
  124. return equal;
  125. }
  126. public static Boolean IsDimensionless(this SByte[] exponents)
  127. {
  128. Debug.Assert(exponents != null, "Parameter needed");
  129. SByte NoOfBaseUnits = (SByte)exponents.Length;
  130. Debug.Assert(NoOfBaseUnits <= Physics.NoOfBaseQuanties + 1, "Too many base units:" + NoOfBaseUnits.ToString() + ". No more than " + (Physics.NoOfBaseQuanties + 1) + " expected.");
  131. Boolean isDimensionless = true;
  132. SByte i = 0;
  133. do
  134. {
  135. isDimensionless = exponents[i] == 0;
  136. i++;
  137. }
  138. while (i < NoOfBaseUnits && isDimensionless);
  139. return isDimensionless;
  140. }
  141. public static SByte NoOfDimensions(this SByte[] exponents)
  142. {
  143. Debug.Assert(exponents != null, "Parameter needed");
  144. SByte NoOfBaseUnits = (SByte)exponents.Length;
  145. Debug.Assert(NoOfBaseUnits <= Physics.NoOfBaseQuanties + 1, "Too many base units:" + NoOfBaseUnits.ToString() + ". No more than " + (Physics.NoOfBaseQuanties + 1) + " expected.");
  146. SByte noOfDimensions = 0;
  147. SByte i = 0;
  148. do
  149. {
  150. if (exponents[i] != 0)
  151. {
  152. noOfDimensions++;
  153. }
  154. i++;
  155. }
  156. while (i < NoOfBaseUnits);
  157. return noOfDimensions;
  158. }
  159. public delegate SByte CombineExponentsFunc(SByte e1, SByte e2);
  160. public static SByte SByte_Mult(SByte e1, SByte e2) => (SByte)(e1 * e2);
  161. public static SByte SByte_Div(SByte e1, SByte e2) => (SByte)(e1 / e2);
  162. public static SByte SByte_Add(SByte e1, SByte e2) => (SByte)(e1 + e2);
  163. public static SByte SByte_Sub(SByte e1, SByte e2) => (SByte)(e1 - e2);
  164. public static SByte[] CombineExponentArrays(this SByte[] exponents1, SByte[] exponents2, CombineExponentsFunc cef)
  165. {
  166. Debug.Assert(exponents1 != null, "Parameter exponents1 needed");
  167. Debug.Assert(exponents2 != null, "Parameter exponents2 needed");
  168. SByte NoOfBaseUnits1 = (SByte)exponents1.Length;
  169. SByte NoOfBaseUnits2 = (SByte)exponents2.Length;
  170. SByte MaxNoOfBaseUnits = (SByte)Math.Max(NoOfBaseUnits1, NoOfBaseUnits2);
  171. SByte MinNoOfBaseUnits = (SByte)Math.Min(NoOfBaseUnits1, NoOfBaseUnits2);
  172. Debug.Assert(NoOfBaseUnits1 <= Physics.NoOfBaseQuanties + 1, "exponents1 has too many base units:" + NoOfBaseUnits1.ToString() + ". No more than " + (Physics.NoOfBaseQuanties + 1) + " expected.");
  173. Debug.Assert(NoOfBaseUnits2 <= Physics.NoOfBaseQuanties + 1, "exponents2 has too many base units:" + NoOfBaseUnits2.ToString() + ". No more than " + (Physics.NoOfBaseQuanties + 1) + " expected.");
  174. SByte[] NewExponents = new SByte[MaxNoOfBaseUnits];
  175. SByte i = 0;
  176. do
  177. {
  178. NewExponents[i] = cef(exponents1[i], exponents2[i]);
  179. i++;
  180. }
  181. while (i < MinNoOfBaseUnits);
  182. while (i < MaxNoOfBaseUnits)
  183. {
  184. if (NoOfBaseUnits1 > NoOfBaseUnits2)
  185. {
  186. NewExponents[i] = exponents1[i];
  187. }
  188. else
  189. {
  190. NewExponents[i] = cef(0, exponents2[i]);
  191. }
  192. i++;
  193. }
  194. return NewExponents;
  195. }
  196. public static SByte[] Multiply(this SByte[] exponents1, SByte[] exponents2)
  197. {
  198. SByte[] NewExponents = CombineExponentArrays(exponents1, exponents2, SByte_Add);
  199. return NewExponents;
  200. }
  201. public static SByte[] Divide(this SByte[] exponents1, SByte[] exponents2)
  202. {
  203. SByte[] NewExponents = CombineExponentArrays(exponents1, exponents2, SByte_Sub);
  204. return NewExponents;
  205. }
  206. public static SByte[] Power(this SByte[] exponents, SByte exponent)
  207. {
  208. Debug.Assert(exponents != null, "Parameter needed");
  209. Debug.Assert(exponent != 0, "Parameter needed");
  210. SByte NoOfBaseUnits = (SByte)exponents.Length;
  211. Debug.Assert(NoOfBaseUnits <= Physics.NoOfBaseQuanties + 1, "Too many base units:" + NoOfBaseUnits.ToString() + ". No more than " + (Physics.NoOfBaseQuanties + 1) + " expected.");
  212. SByte[] NewExponents = new SByte[NoOfBaseUnits];
  213. SByte i = 0;
  214. do
  215. {
  216. NewExponents[i] = (SByte)(exponents[i] * exponent);
  217. i++;
  218. }
  219. while (i < NoOfBaseUnits);
  220. return NewExponents;
  221. }
  222. public static SByte[] Root(this SByte[] exponents, SByte exponent)
  223. {
  224. Debug.Assert(exponents != null, "Parameter needed");
  225. Debug.Assert(exponent != 0, "Parameter needed");
  226. SByte NoOfBaseUnits = (SByte)exponents.Length;
  227. Debug.Assert(NoOfBaseUnits <= Physics.NoOfBaseQuanties + 1, "Too many base units:" + NoOfBaseUnits.ToString() + ". No more than " + (Physics.NoOfBaseQuanties + 1) + " expected.");
  228. SByte[] NewExponents = new SByte[NoOfBaseUnits];
  229. SByte i = 0;
  230. Boolean OK = true;
  231. do
  232. {
  233. int Remainder;
  234. int NewExponent = Math.DivRem(exponents[i], exponent, out Remainder);
  235. OK = Remainder == 0;
  236. NewExponents[i] = (SByte)NewExponent;
  237. i++;
  238. }
  239. while (i < NoOfBaseUnits && OK);
  240. if (!OK)
  241. {
  242. Debug.Assert(OK, "Verify to not happening");
  243. //if (ThrowExceptionOnUnitMathError) {
  244. throw new PhysicalUnitMathException("The result of the math operation on the Unit argument can't be represented by this implementation of PhysicalMeasure: (" + exponents.ToString() + ").Root(" + exponent.ToString() + ")");
  245. //}
  246. //NewExponents = null;
  247. }
  248. return NewExponents;
  249. }
  250. public static SByte[] AllExponents(this SByte[] Exponents, SByte length)
  251. {
  252. SByte[] resExponents;
  253. if (Exponents.Length < length)
  254. {
  255. resExponents = new SByte[length];
  256. foreach (int i in Enumerable.Range(0, length))
  257. {
  258. resExponents[i] = Exponents[i];
  259. }
  260. }
  261. else
  262. {
  263. Debug.Assert(Exponents.Length == length);
  264. resExponents = Exponents;
  265. }
  266. return resExponents;
  267. }
  268. public static String ArrayToString(this SByte[] exponents)
  269. {
  270. String str = "[";
  271. foreach (int i in Enumerable.Range(0, exponents.Length))
  272. {
  273. if (i > 0)
  274. {
  275. str = str + ", ";
  276. }
  277. str = str + exponents[i].ToString();
  278. }
  279. str = str + "]";
  280. return str;
  281. }
  282. }
  283. #endregion Dimension Exponents Classes
  284. public class NamedObject : INamed
  285. {
  286. private readonly String name;
  287. public String Name => name;
  288. public NamedObject(String someName)
  289. {
  290. this.name = someName;
  291. }
  292. public override String ToString() => Name;
  293. }
  294. #region Physical Unit prefix Classes
  295. public class UnitPrefixExponent : IUnitPrefixExponent
  296. {
  297. private SByte exponent;
  298. public SByte Exponent => exponent;
  299. public Double Value => Math.Pow(10, exponent);
  300. public UnitPrefixExponent(SByte somePrefixExponent)
  301. {
  302. this.exponent = somePrefixExponent;
  303. }
  304. #region IUnitPrefixExponentMath implementation
  305. public IUnitPrefixExponent Multiply(IUnitPrefixExponent prefix) => new UnitPrefixExponent((SByte)(this.exponent + prefix.Exponent));
  306. public IUnitPrefixExponent Divide(IUnitPrefixExponent prefix) => new UnitPrefixExponent((SByte)(this.exponent - prefix.Exponent));
  307. public IUnitPrefixExponent Power(SByte someExponent) => new UnitPrefixExponent((SByte)(this.exponent * someExponent));
  308. public IUnitPrefixExponent Root(SByte someExponent)
  309. {
  310. SByte result_exponent = (SByte)(this.exponent / someExponent);
  311. Debug.Assert(result_exponent * someExponent == this.exponent, " Root result exponent must be an integer");
  312. return new UnitPrefixExponent(result_exponent);
  313. }
  314. #endregion IUnitPrefixExponentMath implementation
  315. public override String ToString() => Exponent.ToString();
  316. }
  317. public class UnitPrefix : NamedObject, IUnitPrefix
  318. {
  319. private IUnitPrefixTable unitPrefixTable;
  320. private Char prefixChar;
  321. IUnitPrefixExponent prefixExponent;
  322. #region IUnitPrefix implementation
  323. public Char PrefixChar => prefixChar;
  324. public SByte Exponent => prefixExponent.Exponent;
  325. public Double Value => prefixExponent.Value;
  326. #endregion IUnitPrefix implementation
  327. public UnitPrefix(IUnitPrefixTable someUnitPrefixTable, String someName, Char somePrefixChar, IUnitPrefixExponent somePrefixExponent)
  328. : base(someName)
  329. {
  330. this.unitPrefixTable = someUnitPrefixTable;
  331. this.prefixChar = somePrefixChar;
  332. this.prefixExponent = somePrefixExponent;
  333. }
  334. public UnitPrefix(IUnitPrefixTable someUnitPrefixTable, String someName, Char somePrefixChar, SByte somePrefixExponent)
  335. : this(someUnitPrefixTable, someName, somePrefixChar, new UnitPrefixExponent(somePrefixExponent))
  336. {
  337. }
  338. public IUnitPrefix Multiply(IUnitPrefix prefix)
  339. {
  340. IUnitPrefix unitPrefix = null;
  341. IUnitPrefixExponent resultExponent = this.prefixExponent.Multiply(prefix);
  342. if (!unitPrefixTable.GetUnitPrefixFromExponent(resultExponent, out unitPrefix))
  343. {
  344. unitPrefix = new UnitPrefix(null, null, '\0', resultExponent);
  345. }
  346. return unitPrefix;
  347. }
  348. public IUnitPrefix Divide(IUnitPrefix prefix)
  349. {
  350. IUnitPrefix unitPrefix = null;
  351. IUnitPrefixExponent resultExponent = this.prefixExponent.Divide(prefix);
  352. if (!unitPrefixTable.GetUnitPrefixFromExponent(resultExponent, out unitPrefix))
  353. {
  354. unitPrefix = new UnitPrefix(null, null, '\0', resultExponent);
  355. }
  356. return unitPrefix;
  357. }
  358. #region IUnitPrefixExponentMath implementation
  359. public IUnitPrefixExponent Multiply(IUnitPrefixExponent prefix)
  360. {
  361. IUnitPrefix unitPrefix = null;
  362. IUnitPrefixExponent resultExponent = this.prefixExponent.Multiply(prefix);
  363. if (!unitPrefixTable.GetUnitPrefixFromExponent(resultExponent, out unitPrefix))
  364. {
  365. return resultExponent;
  366. }
  367. return unitPrefix;
  368. }
  369. public IUnitPrefixExponent Divide(IUnitPrefixExponent prefix)
  370. {
  371. IUnitPrefix unitPrefix = null;
  372. IUnitPrefixExponent resultExponent = this.prefixExponent.Divide(prefix);
  373. if (!unitPrefixTable.GetUnitPrefixFromExponent(resultExponent, out unitPrefix))
  374. {
  375. return resultExponent;
  376. }
  377. return unitPrefix;
  378. }
  379. public IUnitPrefixExponent Power(SByte someExponent)
  380. {
  381. IUnitPrefix unitPrefix = null;
  382. IUnitPrefixExponent resultExponent = this.prefixExponent.Power(someExponent);
  383. if (!unitPrefixTable.GetUnitPrefixFromExponent(resultExponent, out unitPrefix))
  384. {
  385. return resultExponent;
  386. }
  387. return unitPrefix;
  388. }
  389. public IUnitPrefixExponent Root(SByte someExponent)
  390. {
  391. IUnitPrefix unitPrefix = null;
  392. IUnitPrefixExponent resultExponent = this.prefixExponent.Root(someExponent);
  393. if (!unitPrefixTable.GetUnitPrefixFromExponent(resultExponent, out unitPrefix))
  394. {
  395. return resultExponent;
  396. }
  397. return unitPrefix;
  398. }
  399. public IPrefixedUnit Multiply(INamedSymbolUnit symbolUnit) => new PrefixedUnit(this, symbolUnit);
  400. #endregion IUnitPrefixExponentMath implementation
  401. public override String ToString() => PrefixChar.ToString();
  402. }
  403. public class UnitPrefixTable : IUnitPrefixTable
  404. {
  405. private readonly UnitPrefix[] unitPrefixes;
  406. public UnitPrefix[] UnitPrefixes => unitPrefixes;
  407. public UnitPrefixTable(UnitPrefix[] someUnitPrefix)
  408. {
  409. this.unitPrefixes = someUnitPrefix;
  410. }
  411. public Boolean GetUnitPrefixFromExponent(IUnitPrefixExponent someExponent, out IUnitPrefix unitPrefix)
  412. {
  413. Debug.Assert(someExponent.Exponent != 0);
  414. IUnitPrefix TempUnitPrefix;
  415. SByte ScaleFactorExponent;
  416. GetFloorUnitPrefixAndScaleFactorFromExponent(someExponent.Exponent, out TempUnitPrefix, out ScaleFactorExponent);
  417. if (ScaleFactorExponent == 0)
  418. {
  419. unitPrefix = TempUnitPrefix;
  420. return true;
  421. }
  422. else
  423. {
  424. unitPrefix = null;
  425. return false;
  426. }
  427. }
  428. public void GetFloorUnitPrefixAndScaleFactorFromExponent(SByte someExponent, out IUnitPrefix unitPrefix, out SByte ScaleFactorExponent)
  429. {
  430. Debug.Assert(someExponent != 0);
  431. int UnitPrefix = 11; // 10^1
  432. while (UnitPrefix - 1 >= 0 && UnitPrefixes[UnitPrefix - 1].Exponent <= someExponent)
  433. {
  434. UnitPrefix--;
  435. }
  436. while (UnitPrefix + 1 < UnitPrefixes.Length && UnitPrefixes[UnitPrefix + 1].Exponent >= someExponent)
  437. {
  438. UnitPrefix++;
  439. }
  440. unitPrefix = UnitPrefixes[UnitPrefix];
  441. ScaleFactorExponent = (SByte)(someExponent - unitPrefix.Exponent);
  442. }
  443. public Boolean GetPrefixCharFromExponent(IUnitPrefixExponent someExponent, out Char prefixChar)
  444. {
  445. prefixChar = '\0';
  446. foreach (UnitPrefix us in UnitPrefixes)
  447. {
  448. if (us.Exponent == someExponent.Exponent)
  449. {
  450. prefixChar = us.PrefixChar;
  451. return true;
  452. }
  453. }
  454. return false;
  455. }
  456. public Boolean GetUnitPrefixFromPrefixChar(Char somePrefixChar, out IUnitPrefix unitPrefix)
  457. {
  458. switch (somePrefixChar)
  459. {
  460. case '\x03BC':
  461. // 'μ' // '\0x03BC' (char)956
  462. // 'µ' // '\0x00B5' (char)181
  463. somePrefixChar = 'µ'; // 'µ' MICRO SIGN '\0x00B5' (char)181
  464. break;
  465. case 'k':
  466. somePrefixChar = 'K'; // Kilo
  467. break;
  468. case 'h':
  469. somePrefixChar = 'H'; // Hecto
  470. break;
  471. }
  472. foreach (UnitPrefix up in UnitPrefixes)
  473. {
  474. if (up.PrefixChar == somePrefixChar)
  475. {
  476. unitPrefix = up;
  477. return true;
  478. }
  479. }
  480. unitPrefix = null;
  481. return false;
  482. }
  483. public Boolean GetExponentFromPrefixChar(Char somePrefixChar, out IUnitPrefixExponent exponent)
  484. {
  485. switch (somePrefixChar)
  486. {
  487. case '\x03BC':
  488. // 'μ' // '\0x03BC' (Char)956
  489. // 'µ' // '\0x00B5' (Char)181
  490. somePrefixChar = 'µ'; // 'µ' MICRO SIGN '\0x00B5' (Char)181
  491. break;
  492. case 'k':
  493. somePrefixChar = 'K'; // Kilo
  494. break;
  495. case 'h':
  496. somePrefixChar = 'H'; // Hecto
  497. break;
  498. }
  499. foreach (UnitPrefix up in UnitPrefixes)
  500. {
  501. if (up.PrefixChar == somePrefixChar)
  502. {
  503. exponent = up;
  504. return true;
  505. }
  506. }
  507. exponent = null;
  508. return false;
  509. }
  510. public IUnitPrefix UnitPrefixFromPrefixChar(char somePrefixChar)
  511. {
  512. IUnitPrefix unitPrefix = null;
  513. GetUnitPrefixFromPrefixChar(somePrefixChar, out unitPrefix);
  514. return unitPrefix;
  515. }
  516. public IUnitPrefixExponent ExponentFromPrefixChar(char somePrefixChar)
  517. {
  518. IUnitPrefixExponent exponent = null;
  519. GetExponentFromPrefixChar(somePrefixChar, out exponent);
  520. return exponent;
  521. }
  522. public IUnitPrefix this[char somePrefixChar] => UnitPrefixFromPrefixChar(somePrefixChar);
  523. }
  524. #endregion Physical Unit prefix Classes
  525. #region Value Conversion Classes
  526. public abstract class ValueConversion : IValueConversion
  527. {
  528. // Specific/absolute quantity unit conversion (e.g. specific temperature)
  529. // Conversion value is specified. Must assume Specific conversion e.g. specific temperature.
  530. public Double Convert(Double value, Boolean backwards = false)
  531. {
  532. if (backwards)
  533. {
  534. return ConvertToPrimaryUnit(value);
  535. }
  536. else
  537. {
  538. return ConvertFromPrimaryUnit(value);
  539. }
  540. }
  541. public abstract Double ConvertFromPrimaryUnit(Double value);
  542. public abstract Double ConvertToPrimaryUnit(Double value);
  543. // No Conversion value is specified. Must assume relative conversion e.g. temperature interval.
  544. public Double Convert(Boolean backwards = false)
  545. {
  546. if (backwards)
  547. {
  548. return ConvertToPrimaryUnit();
  549. }
  550. else
  551. {
  552. return ConvertFromPrimaryUnit();
  553. }
  554. }
  555. public abstract Double ConvertFromPrimaryUnit();
  556. public abstract Double ConvertToPrimaryUnit();
  557. public abstract Double LinearOffset { get; }
  558. public abstract Double LinearScale { get; }
  559. }
  560. public class LinearValueConversion : ValueConversion
  561. {
  562. private Double offset;
  563. private Double scale;
  564. public Double Offset
  565. {
  566. get { return offset; }
  567. set { offset = value; }
  568. }
  569. public Double Scale
  570. {
  571. get { return scale; }
  572. set { scale = value; }
  573. }
  574. public override Double LinearOffset => offset;
  575. public override Double LinearScale => scale;
  576. public LinearValueConversion(Double someOffset, Double someScale)
  577. {
  578. this.Offset = someOffset;
  579. this.Scale = someScale;
  580. }
  581. // Specific/absolute quantity unit conversion (e.g. specific temperature)
  582. // Conversion value is specified. Must assume Specific conversion e.g. specific temperature.
  583. public override Double ConvertFromPrimaryUnit(Double value) => (value * this.Scale) + this.Offset;
  584. public override Double ConvertToPrimaryUnit(Double value)
  585. {
  586. Double convertedValue = (value - this.Offset) / this.Scale;
  587. return convertedValue;
  588. }
  589. // Unspecific/relative non-quantity unit conversion (e.g. temperature interval)
  590. // No Conversion value is specified. Must assume relative conversion e.g. temperature interval.
  591. public override Double ConvertFromPrimaryUnit() => 1.0d * this.Scale;
  592. public override Double ConvertToPrimaryUnit() => 1.0d / this.Scale;
  593. }
  594. public class ScaledValueConversion : LinearValueConversion
  595. {
  596. public ScaledValueConversion(Double someScale)
  597. : base(0, someScale)
  598. {
  599. Debug.Assert(someScale != 0, "Parameter needed");
  600. Debug.Assert(!Double.IsInfinity(someScale), "Finite scale value needed");
  601. if (someScale == 0)
  602. {
  603. throw new ArgumentException("0 is not a valid scale", nameof(someScale));
  604. }
  605. if (Double.IsInfinity(someScale))
  606. {
  607. throw new ArgumentException("Infinity is not a valid scale", nameof(someScale));
  608. }
  609. }
  610. }
  611. public class IdentityValueConversion : ScaledValueConversion
  612. {
  613. public IdentityValueConversion()
  614. : base(1)
  615. {
  616. }
  617. }
  618. public class CombinedValueConversion : ValueConversion
  619. {
  620. private IValueConversion firstValueConversion;
  621. private IValueConversion secondValueConversion;
  622. private Boolean firstValueConversionDirectionInverted;
  623. private Boolean secondValueConversionDirectionInverted;
  624. public override Double LinearOffset => firstValueConversion.LinearOffset + secondValueConversion.LinearOffset;
  625. public override Double LinearScale => firstValueConversion.LinearScale * secondValueConversion.LinearScale;
  626. public CombinedValueConversion(IValueConversion firstValueConversion, Boolean firstValueConversionDirectionInverted, IValueConversion secondValueConversion, Boolean secondValueConversionDirectionInverted)
  627. {
  628. this.firstValueConversion = firstValueConversion;
  629. this.firstValueConversionDirectionInverted = firstValueConversionDirectionInverted;
  630. this.secondValueConversion = secondValueConversion;
  631. this.secondValueConversionDirectionInverted = secondValueConversionDirectionInverted;
  632. }
  633. // Specific/absolute quantity unit conversion (e.g. specific temperature)
  634. // Conversion value is specified. Must assume Specific conversion e.g. specific temperature.
  635. public override Double ConvertFromPrimaryUnit(Double value) => this.secondValueConversion.Convert(this.firstValueConversion.Convert(value, this.firstValueConversionDirectionInverted), this.secondValueConversionDirectionInverted);
  636. public override Double ConvertToPrimaryUnit(Double value) => this.firstValueConversion.Convert(this.secondValueConversion.Convert(value, !this.secondValueConversionDirectionInverted), !this.firstValueConversionDirectionInverted);
  637. // Unspecific/relative non-quantity unit conversion (e.g. temperature interval)
  638. // No Conversion value is specified. Must assume relative conversion e.g. temperature interval.
  639. public override Double ConvertFromPrimaryUnit() => this.secondValueConversion.Convert(this.firstValueConversion.Convert(this.firstValueConversionDirectionInverted), this.secondValueConversionDirectionInverted);
  640. public override Double ConvertToPrimaryUnit() => this.firstValueConversion.Convert(this.secondValueConversion.Convert(!this.secondValueConversionDirectionInverted), !this.firstValueConversionDirectionInverted);
  641. }
  642. #endregion Value Conversion Classes
  643. #region Physical Unit Classes
  644. public class NamedSymbol : NamedObject, INamedSymbol
  645. {
  646. private String symbol;
  647. public String Symbol { get { return symbol; } set { symbol = value; } }
  648. public NamedSymbol(String someName, String someSymbol)
  649. : base(someName)
  650. {
  651. this.Symbol = someSymbol;
  652. }
  653. }
  654. public abstract class Unit : ISystemItem, IUnit /* <BaseUnit | DerivedUnit | ConvertibleUnit | CombinedUnit> */
  655. {
  656. protected Unit()
  657. {
  658. }
  659. public static IUnit MakePhysicalUnit(SByte[] exponents, Double ConversionFactor = 1, Double ConversionOffset = 0)
  660. {
  661. return MakePhysicalUnit(Physics.SI_Units, exponents, ConversionFactor, ConversionOffset);
  662. }
  663. public static Unit MakePhysicalUnit(IUnitSystem system, SByte[] exponents, Double ConversionFactor = 1, Double ConversionOffset = 0)
  664. {
  665. Unit res_unit = null;
  666. int nod = exponents.NoOfDimensions();
  667. if (nod == 0)
  668. {
  669. res_unit = Physics.dimensionless;
  670. }
  671. else
  672. {
  673. res_unit = system.UnitFromExponents(exponents);
  674. }
  675. if (ConversionFactor != 1 || ConversionOffset != 0)
  676. {
  677. if (ConversionOffset == 0)
  678. {
  679. res_unit = new ConvertibleUnit(null, res_unit, new ScaledValueConversion(ConversionFactor));
  680. }
  681. else
  682. {
  683. res_unit = new ConvertibleUnit(null, res_unit, new LinearValueConversion(ConversionOffset, ConversionFactor));
  684. }
  685. }
  686. Debug.Assert(res_unit != null, "res_unit must be found");
  687. return res_unit;
  688. }
  689. public PrefixedUnitExponentList AsPrefixedUnitExponentList()
  690. {
  691. IUnitSystem us = this.ExponentsSystem;
  692. PrefixedUnitExponentList res = new PrefixedUnitExponentList(this.Exponents.Select((exp, i) =>
  693. {
  694. if (exp != 0)
  695. {
  696. return new PrefixedUnitExponent(us.BaseUnits[i], exp);
  697. }
  698. else
  699. {
  700. return null;
  701. }
  702. }));
  703. return res;
  704. }
  705. #if DEBUG
  706. // [Conditional("DEBUG")]
  707. public void TestPropertiesPrint()
  708. {
  709. Boolean test = true;
  710. if (test)
  711. {
  712. string KindStr = this.Kind.ToString();
  713. string SimpleSystemStr = SimpleSystem?.ToString();
  714. string ExponentsSystemStr = ExponentsSystem?.ToString();
  715. string ExponentsStr = Exponents?.ArrayToString();
  716. string DimensionlessStr = Dimensionless?.ToPrintString();
  717. string IsDimensionlessStr = IsDimensionless.ToString();
  718. string ThisPrintStr = this.ToPrintString();
  719. string ThisStr = this.ToString();
  720. }
  721. }
  722. #endif // DEBUG
  723. public abstract IUnitSystem SimpleSystem { get; set; }
  724. public abstract IUnitSystem ExponentsSystem { get; }
  725. public abstract UnitKind Kind { get; }
  726. public abstract SByte[] Exponents { get; }
  727. public virtual Unit Dimensionless => Physics.dimensionless;
  728. public virtual Boolean IsDimensionless
  729. {
  730. get
  731. {
  732. SByte[] exponents = Exponents;
  733. if (Exponents == null)
  734. {
  735. Debug.Assert(Exponents != null, "Exponents must be found");
  736. return false; // Maybe combined unit with Assume
  737. }
  738. return Exponents.IsDimensionless();
  739. }
  740. }
  741. public override int GetHashCode() => this.ExponentsSystem.GetHashCode() + this.Exponents.GetHashCode();
  742. #region Unit Expression parser methods
  743. /**
  744. U = U "*" F | U F | U "/" F | F .
  745. F = SUX | "(" U ")" .
  746. SUX = U | S U | U X | S U X .
  747. U = F Uopt .
  748. //Uopt = "*" F Uopt | "/" F Uopt | UX | e .
  749. Uopt = "*" F Uopt | "/" F Uopt| U | e .
  750. F = SUX | "(" U ")" .
  751. SUX = SU Xopt .
  752. SU = Sopt u .
  753. Sopt = s | e .
  754. Xopt = x | e .
  755. * s : scale prefix char
  756. * u : unit symbol
  757. * x : exponent number
  758. **/
  759. #region IPhysicalUnit unit expression parser methods
  760. /// <summary>
  761. /// Parses the physical quantity from a string in form
  762. /// [prefix] [unitSymbol]
  763. /// </summary>
  764. public static Unit Parse(String unitString)
  765. {
  766. Unit pu = null;
  767. String resultLine = null;
  768. pu = ParseUnit(ref unitString, ref resultLine, throwExceptionOnInvalidInput: true);
  769. return pu;
  770. }
  771. public static Unit ParseUnit(ref String unitString, ref String resultLine, Boolean throwExceptionOnInvalidInput = true)
  772. {
  773. Unit pu = null;
  774. Char timeSeparator = ':';
  775. Char[] separators = { timeSeparator };
  776. Char fractionUnitSeparator = '\0';
  777. String fractionUnitSeparatorStr = null;
  778. int unitStrCount = 0;
  779. int unitStrStartCharIndex = 0;
  780. int nextUnitStrStartCharIndex = 0;
  781. Boolean validFractionalUnit = true;
  782. int lastUnitFieldRemainingLen = 0;
  783. Stack<Tuple<string, Unit>> FractionalUnits = new Stack<Tuple<string, Unit>>();
  784. while (validFractionalUnit && (unitStrStartCharIndex >= 0) && (unitStrStartCharIndex < unitString.Length))
  785. {
  786. int unitStrLen;
  787. int unitStrSeparatorCharIndex = unitString.IndexOfAny(separators, unitStrStartCharIndex);
  788. if (unitStrSeparatorCharIndex == -1)
  789. {
  790. unitStrLen = unitString.Length - unitStrStartCharIndex;
  791. nextUnitStrStartCharIndex = unitString.Length;
  792. }
  793. else
  794. {
  795. unitStrLen = unitStrSeparatorCharIndex - unitStrStartCharIndex;
  796. nextUnitStrStartCharIndex = unitStrSeparatorCharIndex + 1;
  797. }
  798. if (unitStrLen > 0)
  799. {
  800. unitStrCount++;
  801. string unitFieldString = unitString.Substring(unitStrStartCharIndex, unitStrLen).Trim();
  802. Unit tempPU = ParseUnit(null, ref unitFieldString);
  803. if (tempPU == null)
  804. {
  805. validFractionalUnit = false;
  806. resultLine = "'" + unitFieldString + "' is not a valid unit.";
  807. if (throwExceptionOnInvalidInput)
  808. {
  809. throw new PhysicalUnitFormatException("The string argument unitString is not in a valid physical unit format. " + resultLine);
  810. }
  811. }
  812. else
  813. {
  814. fractionUnitSeparatorStr = fractionUnitSeparator.ToString();
  815. FractionalUnits.Push(new Tuple<string, Unit>(fractionUnitSeparatorStr, tempPU));
  816. lastUnitFieldRemainingLen = unitFieldString.Length;
  817. if (lastUnitFieldRemainingLen != 0)
  818. { // Unparsed chars in (last?) field
  819. unitStrLen -= lastUnitFieldRemainingLen;
  820. }
  821. }
  822. }
  823. // Shift to next field
  824. if (unitStrSeparatorCharIndex >= 0)
  825. {
  826. fractionUnitSeparator = unitString[unitStrSeparatorCharIndex];
  827. }
  828. unitStrStartCharIndex = nextUnitStrStartCharIndex;
  829. }
  830. unitString = unitString.Substring(nextUnitStrStartCharIndex - lastUnitFieldRemainingLen);
  831. foreach (Tuple<string, Unit> tempFU in FractionalUnits)
  832. {
  833. Unit tempPU = tempFU.Item2;
  834. String tempFractionUnitSeparator = tempFU.Item1;
  835. if (pu == null)
  836. {
  837. pu = tempPU;
  838. fractionUnitSeparatorStr = tempFractionUnitSeparator;
  839. }
  840. else
  841. {
  842. if (new Quantity(tempPU).ConvertTo(pu) != null)
  843. {
  844. Debug.Assert(fractionUnitSeparatorStr != null, "Unit separator needed");
  845. pu = new MixedUnit(tempPU, fractionUnitSeparatorStr, pu);
  846. fractionUnitSeparatorStr = tempFractionUnitSeparator;
  847. }
  848. else
  849. {
  850. Debug.Assert(resultLine == null, "No resultLine expected");
  851. resultLine = tempPU.ToPrintString() + " is not a valid fractional unit for " + pu.ToPrintString() + ".";
  852. if (throwExceptionOnInvalidInput)
  853. {
  854. throw new PhysicalUnitFormatException("The string argument is not in a valid physical unit format. " + resultLine);
  855. }
  856. }
  857. }
  858. }
  859. return pu;
  860. }
  861. // Token kind enum values
  862. public enum TokenKind
  863. {
  864. None = 0,
  865. Unit = 1,
  866. Exponent = 2,
  867. Operator = 3
  868. }
  869. // Operator kind enum values
  870. // Precedence for a group of operators is same as first (lowest) enum in the group
  871. public enum OperatorKind
  872. {
  873. None = 0,
  874. // Precedence == 2
  875. Mult = 2,
  876. Div = 3,
  877. //Precedence == 4
  878. Pow = 4,
  879. Root = 5
  880. }
  881. private static OperatorKind OperatorPrecedence(OperatorKind operatoren)
  882. {
  883. OperatorKind precedence = (OperatorKind)((int)operatoren & 0XE);
  884. return precedence;
  885. }
  886. private class Token
  887. {
  888. public readonly TokenKind TokenKind;
  889. public readonly Unit PhysicalUnit;
  890. public readonly SByte Exponent;
  891. public readonly OperatorKind Operator;
  892. public Token(Unit physicalUni)
  893. {
  894. this.TokenKind = TokenKind.Unit;
  895. this.PhysicalUnit = physicalUni;
  896. }
  897. public Token(SByte exponent)
  898. {
  899. this.TokenKind = TokenKind.Exponent;
  900. this.Exponent = exponent;
  901. }
  902. public Token(OperatorKind Operator)
  903. {
  904. this.TokenKind = TokenKind.Operator;
  905. this.Operator = Operator;
  906. }
  907. }
  908. private class ExpressionTokenizer
  909. {
  910. private String inputString;
  911. private int pos = 0;
  912. private int afterLastOperandPos = 0;
  913. private int lastValidPos = 0;
  914. private Boolean inputRecognized = true;
  915. private IUnit dimensionless = Physics.dimensionless;
  916. private Boolean throwExceptionOnInvalidInput = false;
  917. private Stack<OperatorKind> operators = new Stack<OperatorKind>();
  918. private List<Token> tokens = new List<Token>();
  919. private TokenKind lastReadToken = TokenKind.None;
  920. public ExpressionTokenizer(String inputStr)
  921. {
  922. this.inputString = inputStr;
  923. }
  924. public ExpressionTokenizer(IUnit someDimensionless, String someInputStr)
  925. {
  926. this.dimensionless = someDimensionless;
  927. this.inputString = someInputStr;
  928. }
  929. public ExpressionTokenizer(IUnit someDimensionless, Boolean someThrowExceptionOnInvalidInput, String someInputStr)
  930. {
  931. this.dimensionless = someDimensionless;
  932. this.throwExceptionOnInvalidInput = someThrowExceptionOnInvalidInput;
  933. this.inputString = someInputStr;
  934. }
  935. public string GetRemainingInput() => inputString.Substring(pos);
  936. public string GetRemainingInputForLastValidPos() => inputString.Substring(lastValidPos);
  937. public void SetValidPos()
  938. {
  939. if (operators.Count <= 1 && tokens.Count == 0)
  940. {
  941. lastValidPos = afterLastOperandPos;
  942. }
  943. }
  944. private Boolean PushNewOperator(OperatorKind newOperator)
  945. {
  946. if (lastReadToken != TokenKind.Operator)
  947. {
  948. if (operators.Count > 0)
  949. {
  950. // Pop operators with precedence higher than new operator
  951. OperatorKind precedence = OperatorPrecedence(newOperator);
  952. while ((operators.Count > 0) && (operators.Peek() >= precedence))
  953. {
  954. tokens.Add(new Token(operators.Pop()));
  955. }
  956. }
  957. operators.Push(newOperator);
  958. lastReadToken = TokenKind.Operator;
  959. return true;
  960. }
  961. else
  962. {
  963. if (throwExceptionOnInvalidInput)
  964. {
  965. throw new PhysicalUnitFormatException("The string argument is not in a valid physical unit format. Invalid or missing unit at position " + pos.ToString());
  966. }
  967. return false;
  968. }
  969. }
  970. private void HandleNewOperator(OperatorKind newOperator)
  971. { // Push newOperator and shift Pos or mark as failed
  972. if (PushNewOperator(newOperator))
  973. {
  974. pos++;
  975. }
  976. else
  977. {
  978. inputRecognized = false;
  979. }
  980. }
  981. private Token RemoveFirstToken()
  982. { // return first operator from post fix operators
  983. Token token = tokens[0];
  984. tokens.RemoveAt(0);
  985. return token;
  986. }
  987. public Token GetToken()
  988. {
  989. Debug.Assert(inputString != null, "Source needed");
  990. if (tokens.Count > 0)
  991. { // return first operator from post fix operators
  992. return RemoveFirstToken();
  993. }
  994. int OperatorsCountForRecognizedTokens = operators.Count;
  995. while ((inputString.Length > pos) && inputRecognized)
  996. {
  997. Char c = inputString[pos];
  998. if (Char.IsWhiteSpace(c))
  999. {
  1000. // Ignore spaces, tabs, etc.
  1001. pos++;
  1002. }
  1003. else if (c == '*'
  1004. || c == '·') // center dot '\0x0B7' (char)183 U+00B7
  1005. {
  1006. HandleNewOperator(OperatorKind.Mult);
  1007. }
  1008. else if (c == '/')
  1009. {
  1010. HandleNewOperator(OperatorKind.Div);
  1011. }
  1012. else if (c == '^')
  1013. {
  1014. HandleNewOperator(OperatorKind.Pow);
  1015. }
  1016. else if (c == '-'
  1017. || c == '+'
  1018. || Char.IsDigit(c))
  1019. {
  1020. // An exponent
  1021. if ((lastReadToken != TokenKind.Unit) // Exponent can follow unit directly
  1022. && ((lastReadToken != TokenKind.Operator) // or follow Pow operator
  1023. || (operators.Peek() != OperatorKind.Pow)))
  1024. {
  1025. if (throwExceptionOnInvalidInput)
  1026. {
  1027. throw new PhysicalUnitFormatException("The string argument is not in a valid physical unit format. An exponent must follow a unit or Pow operator. Invalid exponent at '" + c + "' at position " + pos.ToString());
  1028. }
  1029. else
  1030. {
  1031. // return null;
  1032. inputRecognized = false;
  1033. }
  1034. }
  1035. else
  1036. {
  1037. //// Try to read an exponent from input
  1038. Int16 numLen = 1;
  1039. int maxLen = Math.Min(inputString.Length - pos, 1 + 3); // Max length of sign and digits to look for
  1040. while (numLen < maxLen && Char.IsDigit(inputString[pos + numLen]))
  1041. {
  1042. numLen++;
  1043. }
  1044. SByte exponent;
  1045. if (numLen > 0 && SByte.TryParse(inputString.Substring(pos, numLen), out exponent))
  1046. {
  1047. if ((lastReadToken == TokenKind.Operator)
  1048. && (operators.Peek() == OperatorKind.Pow))
  1049. {
  1050. // Exponent follow Pow operator;
  1051. // Remove Pow operator from operator stack since it is handled as implicit in parser.
  1052. operators.Pop();
  1053. }
  1054. pos += numLen;
  1055. afterLastOperandPos = pos;
  1056. lastReadToken = TokenKind.Exponent;
  1057. return new Token(exponent);
  1058. }
  1059. else
  1060. {
  1061. if (throwExceptionOnInvalidInput)
  1062. {
  1063. throw new PhysicalUnitFormatException("The string argument is not in a valid physical unit format. Invalid or missing exponent after '" + c + "' at position " + pos.ToString());
  1064. }
  1065. else
  1066. {
  1067. // return null;
  1068. inputRecognized = false;
  1069. }
  1070. }
  1071. }
  1072. }
  1073. else
  1074. {
  1075. if ((lastReadToken == TokenKind.Operator) // Unit follow Pow operator;
  1076. && (operators.Peek() == OperatorKind.Pow))
  1077. {
  1078. if (throwExceptionOnInvalidInput)
  1079. {
  1080. throw new PhysicalUnitFormatException("The string argument is not in a valid physical unit format. An unit must not follow an pow operator. Missing exponent at '" + c + "' at position " + pos.ToString());
  1081. }
  1082. else
  1083. {
  1084. inputRecognized = false;
  1085. }
  1086. }
  1087. else
  1088. {
  1089. // Try to read a unit from input
  1090. int maxLen = Math.Min(1 + 3, inputString.Length - pos); // Max length of scale and symbols to look for
  1091. String tempStr = inputString.Substring(pos, maxLen);
  1092. maxLen = tempStr.IndexOfAny(new Char[] { ' ', '*', '·', '/', '^', '+', '-', '(', ')' }); // '·' center dot '\0x0B7' (Char)183 U+00B7
  1093. if (maxLen < 0)
  1094. {
  1095. maxLen = tempStr.Length;
  1096. }
  1097. for (int unitLen = maxLen; unitLen > 0; unitLen--)
  1098. {
  1099. String unitStr = tempStr.Substring(0, unitLen);
  1100. Unit su = Physics.UnitSystems.ScaledUnitFromSymbol(unitStr);
  1101. if (su != null)
  1102. {
  1103. if (lastReadToken == TokenKind.Unit)
  1104. { // Assume implicit Mult operator
  1105. PushNewOperator(OperatorKind.Mult);
  1106. }
  1107. pos += unitLen;
  1108. afterLastOperandPos = pos;
  1109. lastReadToken = TokenKind.Unit;
  1110. return new Token(su);
  1111. }
  1112. }
  1113. if (throwExceptionOnInvalidInput)
  1114. {
  1115. throw new PhysicalUnitFormatException("The string argument is not in a valid physical unit format. Invalid unit '" + inputString.Substring(pos, maxLen) + "' at position " + pos.ToString());
  1116. }
  1117. else
  1118. {
  1119. inputRecognized = false;
  1120. }
  1121. }
  1122. }
  1123. if (tokens.Count > 0)
  1124. { // return first operator from post fix operators
  1125. return RemoveFirstToken();
  1126. }
  1127. };
  1128. if (!inputRecognized)
  1129. {
  1130. // Remove operators from stack which was pushed for not recognized input
  1131. while (operators.Count > OperatorsCountForRecognizedTokens)
  1132. {
  1133. operators.Pop();
  1134. }
  1135. }
  1136. //// Retrieve remaining operators from stack
  1137. while (operators.Count > 0)
  1138. {
  1139. tokens.Add(new Token(operators.Pop()));
  1140. }
  1141. if (tokens.Count > 0)
  1142. { // return first operator from post fix operators
  1143. return RemoveFirstToken();
  1144. }
  1145. return null;
  1146. }
  1147. }
  1148. public static Unit ParseUnit(IUnit dimensionless, ref String s)
  1149. {
  1150. if (dimensionless == null)
  1151. {
  1152. dimensionless = Physics.dimensionless;
  1153. }
  1154. ExpressionTokenizer tokenizer = new ExpressionTokenizer(dimensionless, /* throwExceptionOnInvalidInput = */ false, s);
  1155. Stack<Unit> operands = new Stack<Unit>();
  1156. Boolean inputTokenInvalid = false;
  1157. tokenizer.SetValidPos();
  1158. Token token = tokenizer.GetToken();
  1159. while (token != null && !inputTokenInvalid)
  1160. {
  1161. if (token.TokenKind == TokenKind.Unit)
  1162. {
  1163. // Stack unit operand
  1164. operands.Push(token.PhysicalUnit);
  1165. }
  1166. else if (token.TokenKind == TokenKind.Exponent)
  1167. {
  1168. Unit pu = operands.Pop();
  1169. // Combine pu and exponent to the new unit pu^exponent
  1170. operands.Push(pu.CombinePow(token.Exponent));
  1171. }
  1172. else if (token.TokenKind == TokenKind.Operator)
  1173. {
  1174. /****
  1175. * Pow operator is handled implicit
  1176. *
  1177. if (token.Operator == OperatorKind.Pow)
  1178. {
  1179. Debug.Assert(operands.Count >= 1, "The operands.Count must be 1 or more");
  1180. SByte exponentSecond = operands.Pop();
  1181. IUnit puFirst = operands.Pop();
  1182. // Combine pu and exponent to the new unit pu^exponent
  1183. operands.Push(puFirst.CombinePow(exponentSecond));
  1184. }
  1185. else
  1186. ****/
  1187. if (operands.Count >= 2)
  1188. {
  1189. Debug.Assert(operands.Count >= 2, "Two operands needed");
  1190. Unit puSecond = operands.Pop();
  1191. Unit puFirst = operands.Pop();
  1192. if (token.Operator == OperatorKind.Mult)
  1193. {
  1194. // Combine pu1 and pu2 to the new unit pu1*pu2
  1195. operands.Push(puFirst.CombineMultiply(puSecond));
  1196. }
  1197. else if (token.Operator == OperatorKind.Div)
  1198. {
  1199. // Combine pu1 and pu2 to the new unit pu1/pu2
  1200. operands.Push(puFirst.CombineDivide(puSecond));
  1201. }
  1202. }
  1203. else
  1204. { // Missing operand(s). Operator not valid part of (this) unit
  1205. inputTokenInvalid = true;
  1206. }
  1207. }
  1208. if (!inputTokenInvalid)
  1209. {
  1210. if (operands.Count == 1)
  1211. {
  1212. tokenizer.SetValidPos();
  1213. }
  1214. token = tokenizer.GetToken();
  1215. }
  1216. }
  1217. s = tokenizer.GetRemainingInputForLastValidPos(); // Remaining of input string
  1218. Debug.Assert(operands.Count <= 1, "Only one operand is allowed"); // 0 or 1
  1219. return (operands.Count > 0) ? operands.Last() : null;
  1220. }
  1221. #endregion IPhysicalUnit unit expression parser methods
  1222. #endregion Unit Expression parser methods
  1223. #region Unit print string methods
  1224. /// <summary>
  1225. /// String with PrefixedUnitExponent formatted symbol (without system name prefixed).
  1226. /// </summary>
  1227. public abstract String PureUnitString();
  1228. /// <summary>
  1229. /// String with PrefixedUnitExponent formatted symbol (without system name prefixed).
  1230. /// and prefixed with '(FactorValue)' if FactorValue is not 1
  1231. /// </summary>
  1232. public String UnitString()
  1233. {
  1234. String unitStr = PureUnitString();
  1235. if (FactorValue != 1)
  1236. {
  1237. unitStr = "(" + FactorValue + ") " + unitStr;
  1238. }
  1239. return unitStr;
  1240. }
  1241. /// <summary>
  1242. /// String with PrefixedUnitExponent formatted symbol (without system name prefixed).
  1243. /// without debug asserts.
  1244. /// </summary>
  1245. public virtual String UnitPrintString() => this.UnitString();
  1246. public virtual String CombinedUnitString(Boolean mayUseSlash = true, Boolean invertExponents = false)
  1247. {
  1248. Debug.Assert(invertExponents == false, "The invertExponents must be false");
  1249. return this.UnitString();
  1250. }
  1251. /// <summary>
  1252. /// String formatted by use of named derived unit symbols when possible(without system name prefixed).
  1253. /// without debug asserts.2
  1254. /// </summary>
  1255. public virtual String ReducedUnitString() => this.UnitString();
  1256. /// <summary>
  1257. /// IFormattable.ToString implementation.
  1258. /// Eventually with system name prefixed.
  1259. /// </summary>
  1260. public override String ToString()
  1261. {
  1262. String unitName = this.UnitString();
  1263. IUnitSystem system = this.ExponentsSystem; // this.SimpleSystem;
  1264. if ((!String.IsNullOrEmpty(unitName))
  1265. && (system != null)
  1266. && (system != Physics.CurrentUnitSystems.Default)
  1267. && (!system.IsIsolatedUnitSystem)
  1268. /*
  1269. && (!( Physics.SI_Units == Physics.Default_UnitSystem
  1270. && system.IsCombinedUnitSystem
  1271. && ((ICombinedUnitSystem)system).ContainsSubUnitSystem(Physics.Default_UnitSystem) ))
  1272. */
  1273. )
  1274. {
  1275. unitName = system.Name + "." + unitName;
  1276. }
  1277. return unitName;
  1278. }
  1279. /// <summary>
  1280. /// IUnit.ToPrintString implementation.
  1281. /// With system name prefixed if system specified.
  1282. /// </summary>
  1283. public virtual String ToPrintString()
  1284. {
  1285. String unitName = this.UnitPrintString();
  1286. if (String.IsNullOrEmpty(unitName))
  1287. {
  1288. unitName = "dimensionless";
  1289. }
  1290. else
  1291. {
  1292. IUnitSystem system = this.ExponentsSystem; // this.SimpleSystem;
  1293. if ((system != null)
  1294. && (system != Physics.CurrentUnitSystems.Default))
  1295. {
  1296. unitName = system.Name + "." + unitName;
  1297. }
  1298. }
  1299. return unitName;
  1300. }
  1301. public virtual string ValueString(double value) => value.ToString();
  1302. public virtual string ValueString(double value, String format, IFormatProvider formatProvider)
  1303. {
  1304. String valStr = null;
  1305. try
  1306. {
  1307. valStr = value.ToString(format, formatProvider);
  1308. }
  1309. catch
  1310. {
  1311. valStr = value.ToString() + " ?" + format + "?";
  1312. }
  1313. return valStr;
  1314. }
  1315. public virtual string ValueString(double value, String format)
  1316. {
  1317. String valStr = null;
  1318. try
  1319. {
  1320. valStr = value.ToString(format);
  1321. }
  1322. catch
  1323. {
  1324. valStr = value.ToString() + " ?" + format + "?";
  1325. }
  1326. return valStr;
  1327. }
  1328. public virtual string ValueAndUnitString(String valStr)
  1329. {
  1330. String unitStr = this.ToString();
  1331. if (String.IsNullOrEmpty(unitStr))
  1332. {
  1333. return valStr;
  1334. }
  1335. else
  1336. {
  1337. return valStr + " " + unitStr;
  1338. }
  1339. }
  1340. public virtual string ValueAndUnitString(double value)
  1341. {
  1342. String valStr = ValueString(value);
  1343. return ValueAndUnitString(valStr);
  1344. }
  1345. public virtual string ValueAndUnitString(double value, String format)
  1346. {
  1347. String valStr = ValueString(value, format);
  1348. return ValueAndUnitString(valStr);
  1349. }
  1350. public virtual string ValueAndUnitString(double value, String format, IFormatProvider formatProvider)
  1351. {
  1352. String valStr = ValueString(value, format, formatProvider);
  1353. return ValueAndUnitString(valStr);
  1354. }
  1355. public virtual Double FactorValue => 1;
  1356. public virtual Unit PureUnit => this;
  1357. public virtual Unit AsNamedUnit { get { return GetAsNamedUnit(); } }
  1358. public virtual Unit GetAsNamedUnit() => null;
  1359. #endregion Unit print string methods
  1360. #region Unit conversion methods
  1361. public abstract Boolean IsLinearConvertible();
  1362. //public static implicit operator Unit(INamedSymbolUnit namedSymbolUnit) => ((Unit)namedSymbolUnit);
  1363. // Unspecific/relative non-quantity unit conversion (e.g. temperature interval)
  1364. public Quantity this[Unit convertToUnit] => this.ConvertTo(convertToUnit);
  1365. public Quantity this[Quantity convertToUnit] => this.ConvertTo(convertToUnit.Unit).Multiply(convertToUnit.Value);
  1366. public virtual Quantity ConvertTo(Unit convertToUnit)
  1367. {
  1368. Debug.Assert(convertToUnit != null, "The convertToUnit must be specified");
  1369. // No Conversion value is specified. Must assume relative conversion e.g. temperature interval.
  1370. Quantity pq = null;
  1371. Quantity pq_systemUnit = this.ConvertToSystemUnit();
  1372. if (pq_systemUnit != null)
  1373. {
  1374. Quantity pq_toUnit = pq_systemUnit.Unit.SimpleSystem.ConvertTo(pq_systemUnit.Unit, convertToUnit);
  1375. if (pq_toUnit != null)
  1376. {
  1377. pq = pq_toUnit.Multiply(pq_systemUnit.Value);
  1378. }
  1379. }
  1380. return pq;
  1381. }
  1382. public virtual Quantity ConvertTo(IUnitSystem convertToUnitSystem)
  1383. {
  1384. Debug.Assert(convertToUnitSystem != null, "The convertToUnitSystem must be specified");
  1385. // No Conversion value is specified. Must assume relative conversion e.g. temperature interval.
  1386. Quantity pq = null;
  1387. Quantity pq_systemUnit = this.ConvertToSystemUnit();
  1388. if (pq_systemUnit != null)
  1389. {
  1390. pq = pq_systemUnit.Unit.SimpleSystem.ConvertTo(pq_systemUnit.Unit, convertToUnitSystem);
  1391. if (pq != null && pq_systemUnit.Value != 1)
  1392. {
  1393. pq = pq.Multiply(pq_systemUnit.Value);
  1394. }
  1395. }
  1396. return pq;
  1397. }
  1398. public abstract Quantity ConvertToSystemUnit();
  1399. // Specific/absolute quantity unit conversion (e.g. specific temperature)
  1400. public virtual Quantity ConvertTo(ref Double value, Unit convertToUnit)
  1401. {
  1402. Debug.Assert(convertToUnit != null, "The convertToUnit must be specified");
  1403. // Conversion value is specified. Must assume Specific conversion e.g. specific temperature.
  1404. Quantity pq = null;
  1405. Quantity pq_systemUnit = this.ConvertToSystemUnit(ref value);
  1406. if (pq_systemUnit != null)
  1407. {
  1408. pq = pq_systemUnit.Unit.SimpleSystem.ConvertTo(pq_systemUnit, convertToUnit);
  1409. }
  1410. //// Mark quantity as used now
  1411. value = 1;
  1412. return pq;
  1413. }
  1414. public virtual Quantity ConvertTo(ref Double value, IUnitSystem convertToUnitSystem)
  1415. {
  1416. Debug.Assert(convertToUnitSystem != null, "The convertToUnitSystem must be specified");
  1417. // Conversion value is specified. Must assume Specific conversion e.g. specific temperature.
  1418. Quantity pq = null;
  1419. Quantity pq_systemUnit = this.ConvertToSystemUnit(ref value);
  1420. if (pq_systemUnit != null)
  1421. {
  1422. pq = pq_systemUnit.Unit.SimpleSystem.ConvertTo(pq_systemUnit, convertToUnitSystem);
  1423. }
  1424. //// Mark quantity as used now
  1425. value = 1;
  1426. return pq;
  1427. }
  1428. // Conversion value is specified. Must assume Specific conversion e.g. specific temperature.
  1429. public abstract Quantity ConvertToSystemUnit(ref Double value);
  1430. public abstract Quantity ConvertToBaseUnit();
  1431. public abstract Quantity ConvertToBaseUnit(Double value);
  1432. public virtual Quantity ConvertToBaseUnit(Quantity physicalQuantity)
  1433. {
  1434. Quantity pq = physicalQuantity.ConvertTo(this);
  1435. Debug.Assert(pq != null, "The 'physicalQuantity' must be valid and convertible to this unit");
  1436. return this.ConvertToBaseUnit(pq.Value);
  1437. }
  1438. /// <summary>
  1439. ///
  1440. /// </summary>
  1441. public Quantity ConvertToBaseUnit(IUnitSystem convertToUnitSystem)
  1442. {
  1443. Quantity pq = this.ConvertTo(convertToUnitSystem);
  1444. if (pq != null)
  1445. {
  1446. pq = pq.ConvertToBaseUnit();
  1447. }
  1448. return pq;
  1449. }
  1450. /// <summary>
  1451. ///
  1452. public Quantity ConvertToBaseUnit(double quantity, IUnitSystem convertToUnitSystem)
  1453. {
  1454. Quantity pq = new Quantity(quantity, this).ConvertTo(convertToUnitSystem);
  1455. if (pq != null)
  1456. {
  1457. pq = pq.ConvertToBaseUnit();
  1458. }
  1459. return pq;
  1460. }
  1461. /// <summary>
  1462. ///
  1463. /// </summary>
  1464. public Quantity ConvertToBaseUnit(Quantity physicalQuantity, IUnitSystem convertToUnitSystem)
  1465. {
  1466. Quantity pq = physicalQuantity.ConvertTo(this);
  1467. if (pq != null)
  1468. {
  1469. pq = pq.ConvertTo(convertToUnitSystem);
  1470. if (pq != null)
  1471. {
  1472. pq = pq.ConvertToBaseUnit();
  1473. }
  1474. }
  1475. return pq;
  1476. }
  1477. public abstract Quantity ConvertToDerivedUnit();
  1478. public Boolean Equivalent(Unit other, out Double quotient)
  1479. {
  1480. /*
  1481. * This will not all ways be true
  1482. Debug.Assert(other != null, "The 'other' parameter must be specified");
  1483. */
  1484. if ((Object)other == null)
  1485. {
  1486. quotient = 0;
  1487. return false;
  1488. }
  1489. Quantity pq1;
  1490. Quantity pq2;
  1491. if (this.ExponentsSystem != other.ExponentsSystem)
  1492. { // Must be same unit system
  1493. if (this.ExponentsSystem == null || other.ExponentsSystem == null)
  1494. {
  1495. if (this.IsDimensionless && other.IsDimensionless)
  1496. {
  1497. // Any dimensionless can be converted to any systems dimensionless
  1498. quotient = other.FactorValue / this.FactorValue;
  1499. return true;
  1500. }
  1501. }
  1502. if (this.ExponentsSystem.IsCombinedUnitSystem || other.ExponentsSystem.IsCombinedUnitSystem)
  1503. {
  1504. if (this.ExponentsSystem.IsCombinedUnitSystem && other.ExponentsSystem.IsCombinedUnitSystem)
  1505. {
  1506. // Check for same sub systems
  1507. CombinedUnitSystem cus_this = (CombinedUnitSystem)this.ExponentsSystem;
  1508. CombinedUnitSystem cus_other = (CombinedUnitSystem)other.ExponentsSystem;
  1509. if (cus_this.Equals(cus_other))
  1510. {
  1511. Debug.Assert(false); // Missing check for scale factors and converted units
  1512. if (!this.Exponents.DimensionEquals(other.Exponents))
  1513. {
  1514. quotient = 0;
  1515. return false;
  1516. }
  1517. }
  1518. }
  1519. }
  1520. pq2 = other.ConvertTo(this.ExponentsSystem);
  1521. if (Object.ReferenceEquals(null, pq2))
  1522. {
  1523. quotient = 0;
  1524. return false;
  1525. }
  1526. pq1 = new Quantity(1, this);
  1527. return pq1.Equivalent(pq2, out quotient);
  1528. }
  1529. if (this.Kind == UnitKind.MixedUnit)
  1530. {
  1531. IMixedUnit this_imu = (IMixedUnit)this;
  1532. return this_imu.MainUnit.Equivalent(other, out quotient);
  1533. }
  1534. else if (other.Kind == UnitKind.MixedUnit)
  1535. {
  1536. IMixedUnit other_imu = (IMixedUnit)other;
  1537. return this.Equivalent(other_imu.MainUnit, out quotient);
  1538. }
  1539. else if (this.Kind == UnitKind.ConvertibleUnit)
  1540. {
  1541. IConvertibleUnit this_icu = (IConvertibleUnit)this;
  1542. if (!this_icu.IsLinearConvertible())
  1543. {
  1544. quotient = 0;
  1545. return false;
  1546. }
  1547. pq1 = this_icu.ConvertToPrimaryUnit();
  1548. pq2 = other.ConvertTo(this_icu.PrimaryUnit);
  1549. if (pq2 == null)
  1550. {
  1551. quotient = 0;
  1552. return false;
  1553. }
  1554. Boolean equals = pq1.Equivalent(pq2, out quotient);
  1555. return equals;
  1556. }
  1557. else if (other.Kind == UnitKind.ConvertibleUnit)
  1558. {
  1559. IConvertibleUnit other_icu = (IConvertibleUnit)other;
  1560. if (!other_icu.IsLinearConvertible())
  1561. {
  1562. quotient = 0;
  1563. return false;
  1564. }
  1565. pq2 = other_icu.ConvertToPrimaryUnit();
  1566. pq1 = this.ConvertTo(pq2.Unit);
  1567. if (pq1 == null)
  1568. {
  1569. quotient = 0;
  1570. return false;
  1571. }
  1572. Boolean equals = pq1.Equivalent(pq2, out quotient);
  1573. return equals;
  1574. }
  1575. else if (this.Kind == UnitKind.PrefixedUnit)
  1576. {
  1577. IPrefixedUnit this_pu = (IPrefixedUnit)this;
  1578. Double tempQuotient;
  1579. Boolean equivalent = this_pu.Unit.Equivalent(other, out tempQuotient);
  1580. if (equivalent)
  1581. {
  1582. quotient = this_pu.Prefix.Value * tempQuotient;
  1583. }
  1584. else
  1585. {
  1586. quotient = 0;
  1587. }
  1588. return equivalent;
  1589. }
  1590. else if (other.Kind == UnitKind.PrefixedUnit)
  1591. {
  1592. IPrefixedUnit other_pu = (IPrefixedUnit)other;
  1593. Double tempQuotient;
  1594. Boolean equivalent = this.Equivalent((Unit)other_pu.Unit, out tempQuotient);
  1595. if (equivalent)
  1596. {
  1597. quotient = tempQuotient / other_pu.Prefix.Value;
  1598. }
  1599. else
  1600. {
  1601. quotient = 0;
  1602. }
  1603. return equivalent;
  1604. }
  1605. else if (this.Kind == UnitKind.PrefixedUnitExponent)
  1606. {
  1607. IPrefixedUnitExponent this_pue = (IPrefixedUnitExponent)this;
  1608. Double tempQuotient;
  1609. Boolean equivalent = this_pue.Unit.Equivalent(other, out tempQuotient);
  1610. if (equivalent)
  1611. {
  1612. quotient = tempQuotient / this_pue.Prefix.Value;
  1613. }
  1614. else
  1615. {
  1616. quotient = 0;
  1617. }
  1618. return equivalent;
  1619. }
  1620. else if (other.Kind == UnitKind.PrefixedUnitExponent)
  1621. {
  1622. PrefixedUnitExponent other_pue = (PrefixedUnitExponent)other;
  1623. Double tempQuotient;
  1624. Boolean equivalent = this.Equivalent((Unit)other_pue.Unit, out tempQuotient);
  1625. if (equivalent)
  1626. {
  1627. quotient = tempQuotient / other_pue.Prefix.Value;
  1628. }
  1629. else
  1630. {
  1631. quotient = 0;
  1632. }
  1633. return equivalent;
  1634. }
  1635. else if (this.Kind == UnitKind.CombinedUnit)
  1636. {
  1637. ICombinedUnit this_icu = (ICombinedUnit)this;
  1638. if (!this_icu.IsLinearConvertible())
  1639. {
  1640. quotient = 0;
  1641. return false;
  1642. }
  1643. pq2 = other.ConvertToDerivedUnit();
  1644. IQuantity pq_this = this_icu.ConvertToDerivedUnit();
  1645. pq1 = pq_this.ConvertTo(pq2.Unit);
  1646. if (pq1 == null)
  1647. {
  1648. quotient = 0;
  1649. return false;
  1650. }
  1651. Boolean equals = pq1.Equivalent(pq2, out quotient);
  1652. return equals;
  1653. }
  1654. else if (other.Kind == UnitKind.CombinedUnit)
  1655. {
  1656. ICombinedUnit other_icu = (ICombinedUnit)other;
  1657. if (!other_icu.IsLinearConvertible())
  1658. {
  1659. quotient = 0;
  1660. return false;
  1661. }
  1662. pq1 = this.ConvertToDerivedUnit();
  1663. IQuantity pq_other = other_icu.ConvertToDerivedUnit();
  1664. pq2 = pq_other.ConvertTo(pq1.Unit);
  1665. if (pq2 == null)
  1666. {
  1667. quotient = 0;
  1668. return false;
  1669. }
  1670. Boolean equals = pq1.Equivalent(pq2, out quotient);
  1671. return equals;
  1672. }
  1673. Debug.Assert(this.Kind == UnitKind.BaseUnit || this.Kind == UnitKind.DerivedUnit);
  1674. Boolean equals2 = this.Exponents.DimensionEquals(other.Exponents);
  1675. if (!equals2)
  1676. {
  1677. quotient = 0;
  1678. return false;
  1679. }
  1680. quotient = other.FactorValue / this.FactorValue;
  1681. return true;
  1682. }
  1683. public Boolean Equivalent(Unit other)
  1684. {
  1685. Double quotient;
  1686. return Equivalent(other, out quotient);
  1687. }
  1688. public virtual Boolean Equals(Unit other)
  1689. {
  1690. /*
  1691. * This will not all ways be true
  1692. Debug.Assert(other != null, "The 'other' parameter must be specified");
  1693. */
  1694. if ((Object)other == null)
  1695. {
  1696. return false;
  1697. }
  1698. Double quotient;
  1699. Boolean equals = this.Equivalent(other, out quotient);
  1700. return equals && quotient == 1;
  1701. }
  1702. public override Boolean Equals(Object obj)
  1703. {
  1704. if (obj == null)
  1705. {
  1706. return base.Equals(obj);
  1707. }
  1708. Unit pu = obj as Unit;
  1709. if (pu != null)
  1710. {
  1711. return this.Equals(pu);
  1712. }
  1713. Debug.Assert(obj is Unit, "The 'obj' argument is not a IUnit object");
  1714. return false;
  1715. }
  1716. public static Boolean operator ==(Unit unit1, Unit unit2)
  1717. {
  1718. if ((Object)unit1 == null)
  1719. {
  1720. return (Object)unit2 == null;
  1721. }
  1722. Debug.Assert((Object)unit1 != null, "The 'unit1' parameter must be specified");
  1723. return unit1.Equals(unit2);
  1724. }
  1725. public static Boolean operator !=(Unit unit1, Unit unit2)
  1726. {
  1727. if ((Object)unit1 == null)
  1728. {
  1729. return (Object)unit2 != null;
  1730. }
  1731. Debug.Assert((Object)unit1 != null, "The 'unit1' parameter must be specified");
  1732. return !unit1.Equals(unit2);
  1733. }
  1734. #endregion Unit conversion methods
  1735. #region Unit static operator methods
  1736. protected delegate Double CombineQuantitiesFunc(Double q1, Double q2);
  1737. protected static Quantity CombineUnits(Unit u1, Unit u2, CombineExponentsFunc cef, CombineQuantitiesFunc cqf)
  1738. {
  1739. IUnitSystem us = u1.ExponentsSystem;
  1740. IQuantity u1_pq = u1.ConvertToBaseUnit(us);
  1741. IQuantity u2_pq = u2.ConvertToBaseUnit(us);
  1742. if (u1_pq == null || u2_pq == null)
  1743. {
  1744. // Found no conversion from u1_pq.Unit.System to u2_pq.Unit.System
  1745. return null;
  1746. }
  1747. SByte[] u1Exponents = u1_pq.Unit.Exponents;
  1748. SByte[] u2Exponents = u2_pq.Unit.Exponents;
  1749. SByte u1ExponentsLen = (SByte)u1_pq.Unit.Exponents.Length;
  1750. SByte u2ExponentsLen = (SByte)u2_pq.Unit.Exponents.Length;
  1751. int NoOfBaseUnits = Math.Max(u1ExponentsLen, u2ExponentsLen);
  1752. Debug.Assert(NoOfBaseUnits <= Physics.NoOfBaseQuanties, "The 'NoOfBaseUnits' must be <= Physics.NoOfBaseQuanties");
  1753. SByte[] combinedExponents = new SByte[NoOfBaseUnits];
  1754. for (int i = 0; i < NoOfBaseUnits; i++)
  1755. {
  1756. SByte u1Exponent = 0;
  1757. SByte u2Exponent = 0;
  1758. if (i < u1ExponentsLen)
  1759. {
  1760. u1Exponent = u1Exponents[i];
  1761. }
  1762. if (i < u2ExponentsLen)
  1763. {
  1764. u2Exponent = u2Exponents[i];
  1765. }
  1766. combinedExponents[i] = cef(u1Exponent, u2Exponent);
  1767. }
  1768. Debug.Assert(u1.ExponentsSystem != null, "The 'u1.ExponentsSystem' must be specified");
  1769. Unit pu = new DerivedUnit(u1.ExponentsSystem, combinedExponents);
  1770. return new Quantity(cqf(u1_pq.Value, u2_pq.Value), pu);
  1771. }
  1772. protected static Unit CombineUnitExponents(Unit u, SByte exponent, CombineExponentsFunc cef)
  1773. {
  1774. SByte[] exponents = u.Exponents;
  1775. int NoOfBaseUnits = exponents.Length;
  1776. Debug.Assert(NoOfBaseUnits <= Physics.NoOfBaseQuanties, "The 'NoOfBaseUnits' must be <= Physics.NoOfBaseQuanties");
  1777. SByte[] someExponents = new SByte[NoOfBaseUnits];
  1778. for (int i = 0; i < NoOfBaseUnits; i++)
  1779. {
  1780. someExponents[i] = cef(u.Exponents[i], exponent);
  1781. }
  1782. // Not valid during SI system initialization: Debug.Assert(u.System != null);
  1783. Unit pu = new DerivedUnit(u.ExponentsSystem, someExponents);
  1784. return pu;
  1785. }
  1786. protected static Unit AsUnitExponents(Unit u)
  1787. {
  1788. SByte[] exponents = u.Exponents;
  1789. int NoOfBaseUnits = exponents.Length;
  1790. Debug.Assert(NoOfBaseUnits <= Physics.NoOfBaseQuanties, "The 'NoOfBaseUnits' must be <= Physics.NoOfBaseQuanties");
  1791. // Not valid during SI system initialization: Debug.Assert(u.System != null);
  1792. Unit pu = new DerivedUnit(u.ExponentsSystem, exponents);
  1793. return pu;
  1794. }
  1795. public static Unit operator *(Unit u, IUnitPrefix up)
  1796. {
  1797. Debug.Assert(up != null, "The " + nameof(up) + " parameter must be specified");
  1798. // return up.Multiply(u);
  1799. return u.Multiply(up);
  1800. }
  1801. public static Unit operator *(IUnitPrefix up, Unit u)
  1802. {
  1803. Debug.Assert(up != null, "The " + nameof(up) + " parameter must be specified");
  1804. return u.Multiply(up);
  1805. }
  1806. public static Quantity operator *(Unit u, Double d) => new Quantity(d, u);
  1807. public static Quantity operator /(Unit u, Double d) => new Quantity(1 / d, u);
  1808. public static Quantity operator *(Double d, Unit u) => new Quantity(d, u);
  1809. public static Quantity operator /(Double d, Unit u) => new Quantity(d, 1 / u);
  1810. public static Unit operator *(Unit u1, Unit u2)
  1811. {
  1812. Debug.Assert(!Object.ReferenceEquals(null, u1), "The " + nameof(u1) + " parameter must be specified");
  1813. return u1.Multiply(u2);
  1814. }
  1815. public static Unit operator /(Unit u1, Unit u2)
  1816. {
  1817. Debug.Assert(!Object.ReferenceEquals(null, u1), "The " + nameof(u1) + " parameter must be specified");
  1818. return u1.Divide(u2);
  1819. }
  1820. public static Unit operator *(Unit u1, IUnit u2)
  1821. {
  1822. Debug.Assert(!Object.ReferenceEquals(null, u1), "The " + nameof(u1) + " parameter must be specified");
  1823. return u1.Multiply(u2);
  1824. }
  1825. public static Unit operator /(Unit u1, IUnit u2)
  1826. {
  1827. Debug.Assert(!Object.ReferenceEquals(null, u1), "The " + nameof(u1) + " parameter must be specified");
  1828. return u1.Divide(u2);
  1829. }
  1830. public static Unit operator *(IUnit u1, Unit u2)
  1831. {
  1832. Debug.Assert(!Object.ReferenceEquals(null, u1), "The " + nameof(u1) + " parameter must be specified");
  1833. return u1.Multiply(u2);
  1834. }
  1835. public static Unit operator /(IUnit u1, Unit u2)
  1836. {
  1837. Debug.Assert(!Object.ReferenceEquals(null, u1), "The " + nameof(u1) + " parameter must be specified");
  1838. return u1.Divide(u2);
  1839. }
  1840. public static Unit operator *(Unit u1, PrefixedUnitExponent pue2)
  1841. {
  1842. Debug.Assert(!Object.ReferenceEquals(null, u1), "The " + nameof(u1) + " parameter must be specified");
  1843. return u1.Multiply((IPrefixedUnitExponent)pue2);
  1844. }
  1845. public static Unit operator /(Unit u1, PrefixedUnitExponent pue2)
  1846. {
  1847. Debug.Assert(!Object.ReferenceEquals(null, u1), "The " + nameof(u1) + " parameter must be specified");
  1848. return u1.Divide((IPrefixedUnitExponent)pue2);
  1849. }
  1850. public static Unit operator *(Unit u1, IPrefixedUnitExponent pue2)
  1851. {
  1852. Debug.Assert(!Object.ReferenceEquals(null, u1), "The " + nameof(u1) + " parameter must be specified");
  1853. return u1.Multiply(pue2);
  1854. }
  1855. public static Unit operator /(Unit u1, IPrefixedUnitExponent pue2)
  1856. {
  1857. Debug.Assert(!Object.ReferenceEquals(null, u1), "The " + nameof(u1) + " parameter must be specified");
  1858. return u1.Divide(pue2);
  1859. }
  1860. public static Unit operator ^(Unit u, SByte exponent)
  1861. {
  1862. Debug.Assert(!Object.ReferenceEquals(null, u), "The " + nameof(u) + " parameter must be specified");
  1863. return u.Pow(exponent);
  1864. }
  1865. public static Unit operator %(Unit u, SByte exponent)
  1866. {
  1867. Debug.Assert(!Object.ReferenceEquals(null, u), "The "+ nameof(u) +" parameter must be specified");
  1868. return u.Rot(exponent);
  1869. }
  1870. /*
  1871. public static Quantity operator ^(Unit u, SByte exponent)
  1872. {
  1873. Debug.Assert(!Object.ReferenceEquals(null, u), "The " + nameof(u) + " parameter must be specified");
  1874. return new Quantity(u.Pow(exponent));
  1875. }
  1876. public static Quantity operator %(Unit u, SByte exponent)
  1877. {
  1878. Debug.Assert(!Object.ReferenceEquals(null, u), "The " + nameof(u) + " parameter must be specified");
  1879. return new Quantity(u.Rot(exponent));
  1880. }
  1881. */
  1882. #endregion Unit static operator methods
  1883. public virtual Quantity AsQuantity() => AsPhysicalQuantity(1);
  1884. public virtual Quantity AsPhysicalQuantity(double quantity) => new Quantity(quantity, this);
  1885. public virtual Unit Power(SByte exponent) => CombineUnitExponents(this, exponent, SByte_Mult);
  1886. public virtual Unit Root(SByte exponent) => CombineUnitExponents(this, exponent, SByte_Div);
  1887. #region Unit math methods
  1888. public virtual Unit Multiply(IUnitPrefixExponent prefix)
  1889. {
  1890. Debug.Assert(prefix != null, "The " + nameof(prefix) + " parameter must be specified");
  1891. return this.CombineMultiply(prefix);
  1892. }
  1893. public virtual Unit Divide(IUnitPrefixExponent prefix)
  1894. {
  1895. Debug.Assert(prefix != null, "The " + nameof(prefix) + " parameter must be specified");
  1896. return this.CombineDivide(prefix);
  1897. }
  1898. public virtual Unit Multiply(INamedSymbolUnit namedSymbolUnit)
  1899. {
  1900. Debug.Assert(namedSymbolUnit != null, "The " + nameof(namedSymbolUnit) + " parameter must be specified");
  1901. return this.CombineMultiply(namedSymbolUnit);
  1902. }
  1903. public virtual Unit Divide(INamedSymbolUnit namedSymbolUnit)
  1904. {
  1905. Debug.Assert(namedSymbolUnit != null, "The " + nameof(namedSymbolUnit) + " parameter must be specified");
  1906. return this.CombineDivide(namedSymbolUnit);
  1907. }
  1908. public virtual Unit Multiply(PrefixedUnit prefixedUnit)
  1909. {
  1910. Debug.Assert(prefixedUnit != null, "The " + nameof(prefixedUnit) + " parameter must be specified");
  1911. return this.CombineMultiply(prefixedUnit);
  1912. }
  1913. public virtual Unit Divide(PrefixedUnit prefixedUnit)
  1914. {
  1915. Debug.Assert(prefixedUnit != null, "The " + nameof(prefixedUnit) + " parameter must be specified");
  1916. return this.CombineDivide(prefixedUnit);
  1917. }
  1918. public virtual Unit Multiply(IPrefixedUnitExponent prefixedUnitExponent)
  1919. {
  1920. Debug.Assert(prefixedUnitExponent != null, "The " + nameof(prefixedUnitExponent) + " parameter must be specified");
  1921. return this.CombineMultiply(prefixedUnitExponent);
  1922. }
  1923. public virtual Unit Divide(IPrefixedUnitExponent prefixedUnitExponent)
  1924. {
  1925. Debug.Assert(prefixedUnitExponent != null, "The 'prefixedUnitExponent' parameter must be specified");
  1926. return this.CombineDivide(prefixedUnitExponent);
  1927. }
  1928. public virtual Unit Multiply(Unit physicalUnit)
  1929. {
  1930. Debug.Assert(physicalUnit != null, "The 'physicalUnit' parameter must be specified");
  1931. return this.CombineMultiply(physicalUnit);
  1932. }
  1933. public virtual Unit Divide(Unit physicalUnit)
  1934. {
  1935. Debug.Assert(physicalUnit != null, "The 'physicalUnit' parameter must be specified");
  1936. return this.CombineDivide(physicalUnit);
  1937. }
  1938. public virtual Unit Multiply(IUnit physicalUnit)
  1939. {
  1940. Debug.Assert(physicalUnit != null, "The 'physicalUnit' parameter must be specified");
  1941. return this.CombineMultiply(physicalUnit);
  1942. }
  1943. public virtual Unit Divide(IUnit physicalUnit)
  1944. {
  1945. Debug.Assert(physicalUnit != null, "The 'physicalUnit' parameter must be specified");
  1946. return this.CombineDivide(physicalUnit);
  1947. }
  1948. public virtual Quantity Multiply(Quantity physicalQuantity)
  1949. {
  1950. Debug.Assert(physicalQuantity != null, "The 'physicalQuantity' parameter must be specified");
  1951. Unit pu = this.Multiply(physicalQuantity.Unit);
  1952. return pu.Multiply(physicalQuantity.Value);
  1953. }
  1954. public virtual Quantity Divide(Quantity physicalQuantity)
  1955. {
  1956. Debug.Assert(physicalQuantity != null, "The 'physicalQuantity' parameter must be specified");
  1957. Unit pu = this.Divide(physicalQuantity.Unit);
  1958. return pu.Divide(physicalQuantity.Value);
  1959. }
  1960. public virtual Quantity Multiply(Double value) => new Quantity(value, this);
  1961. public virtual Quantity Divide(Double value) => new Quantity(1 / value, this);
  1962. public virtual Quantity Multiply(Double value, Quantity physicalQuantity)
  1963. {
  1964. Debug.Assert(physicalQuantity != null);
  1965. Unit pu = this.Multiply(physicalQuantity.Unit);
  1966. return pu.Multiply(value * physicalQuantity.Value);
  1967. }
  1968. public virtual Quantity Divide(Double value, Quantity physicalQuantity)
  1969. {
  1970. Debug.Assert(physicalQuantity != null, "The 'physicalQuantity' parameter must be specified");
  1971. Unit pu = this.Divide(physicalQuantity.Unit);
  1972. return pu.Multiply(value / physicalQuantity.Value);
  1973. }
  1974. public Unit Pow(SByte exponent) => this.Power(exponent);
  1975. public Unit Rot(SByte exponent) => this.Root(exponent);
  1976. #endregion Unit math methods
  1977. #region Unit Combine math methods
  1978. public virtual CombinedUnit CombineMultiply(Double value)
  1979. {
  1980. CombinedUnit uRes = new CombinedUnit(this);
  1981. uRes = uRes.CombineMultiply(value);
  1982. return uRes;
  1983. }
  1984. public virtual CombinedUnit CombineDivide(Double value)
  1985. {
  1986. CombinedUnit uRes = new CombinedUnit(this);
  1987. uRes = uRes.CombineDivide(value);
  1988. return uRes;
  1989. }
  1990. public virtual CombinedUnit CombineMultiply(IUnitPrefixExponent prefixExponent)
  1991. {
  1992. CombinedUnit uRes = new CombinedUnit(this);
  1993. uRes = uRes.CombineMultiply(prefixExponent);
  1994. return uRes;
  1995. }
  1996. public virtual CombinedUnit CombineDivide(IUnitPrefixExponent prefixExponent)
  1997. {
  1998. CombinedUnit uRes = new CombinedUnit(this);
  1999. uRes = uRes.CombineDivide(prefixExponent);
  2000. return uRes;
  2001. }
  2002. public virtual CombinedUnit CombineMultiply(BaseUnit physicalUnit)
  2003. {
  2004. CombinedUnit uRes = new CombinedUnit(this);
  2005. uRes = uRes.CombineMultiply(physicalUnit);
  2006. return uRes;
  2007. }
  2008. public virtual CombinedUnit CombineDivide(BaseUnit physicalUnit)
  2009. {
  2010. CombinedUnit uRes = new CombinedUnit(this);
  2011. uRes = uRes.CombineDivide(physicalUnit);
  2012. return uRes;
  2013. }
  2014. public virtual CombinedUnit CombineMultiply(NamedDerivedUnit physicalUnit)
  2015. {
  2016. CombinedUnit uRes = new CombinedUnit(this);
  2017. uRes = uRes.CombineMultiply(physicalUnit);
  2018. return uRes;
  2019. }
  2020. public virtual CombinedUnit CombineDivide(NamedDerivedUnit physicalUnit)
  2021. {
  2022. CombinedUnit uRes = new CombinedUnit(this);
  2023. uRes = uRes.CombineDivide(physicalUnit);
  2024. return uRes;
  2025. }
  2026. public virtual CombinedUnit CombineMultiply(ConvertibleUnit physicalUnit)
  2027. {
  2028. CombinedUnit uRes = new CombinedUnit(this);
  2029. uRes = uRes.CombineMultiply(physicalUnit);
  2030. return uRes;
  2031. }
  2032. public virtual CombinedUnit CombineDivide(ConvertibleUnit physicalUnit)
  2033. {
  2034. CombinedUnit uRes = new CombinedUnit(this);
  2035. uRes = uRes.CombineDivide(physicalUnit);
  2036. return uRes;
  2037. }
  2038. public virtual CombinedUnit CombineMultiply(INamedSymbolUnit physicalUnit)
  2039. {
  2040. CombinedUnit uRes = new CombinedUnit(this);
  2041. uRes = uRes.CombineMultiply(physicalUnit);
  2042. return uRes;
  2043. }
  2044. public virtual CombinedUnit CombineDivide(INamedSymbolUnit physicalUnit)
  2045. {
  2046. CombinedUnit uRes = new CombinedUnit(this);
  2047. uRes = uRes.CombineDivide(physicalUnit);
  2048. return uRes;
  2049. }
  2050. public virtual CombinedUnit CombineMultiply(Unit physicalUnit)
  2051. {
  2052. CombinedUnit uRes = new CombinedUnit(this);
  2053. uRes = uRes.CombineMultiply(physicalUnit);
  2054. return uRes;
  2055. }
  2056. public virtual CombinedUnit CombineDivide(Unit physicalUnit)
  2057. {
  2058. CombinedUnit uRes = new CombinedUnit(this);
  2059. uRes = uRes.CombineDivide(physicalUnit);
  2060. return uRes;
  2061. }
  2062. public virtual CombinedUnit CombineMultiply(IUnit physicalUnit)
  2063. {
  2064. CombinedUnit uRes = new CombinedUnit(this);
  2065. uRes = uRes.CombineMultiply(physicalUnit);
  2066. return uRes;
  2067. }
  2068. public virtual CombinedUnit CombineDivide(IUnit physicalUnit)
  2069. {
  2070. CombinedUnit uRes = new CombinedUnit(this);
  2071. uRes = uRes.CombineDivide(physicalUnit);
  2072. return uRes;
  2073. }
  2074. public virtual CombinedUnit CombinePow(SByte exponent)
  2075. {
  2076. CombinedUnit asCombinedUnit = new CombinedUnit(this);
  2077. CombinedUnit uRes = asCombinedUnit.CombinePow(exponent);
  2078. return uRes;
  2079. }
  2080. public virtual CombinedUnit CombineRot(SByte exponent)
  2081. {
  2082. CombinedUnit asCombinedUnit = new CombinedUnit(this);
  2083. CombinedUnit uRes = asCombinedUnit.CombineRot(exponent);
  2084. return uRes;
  2085. }
  2086. public virtual CombinedUnit CombineMultiply(PrefixedUnit prefixedUnit)
  2087. {
  2088. CombinedUnit uRes = new CombinedUnit(this);
  2089. uRes = uRes.CombineMultiply(prefixedUnit);
  2090. return uRes;
  2091. }
  2092. public virtual CombinedUnit CombineDivide(PrefixedUnit prefixedUnit)
  2093. {
  2094. CombinedUnit uRes = new CombinedUnit(this);
  2095. uRes = uRes.CombineDivide(prefixedUnit);
  2096. return uRes;
  2097. }
  2098. public virtual CombinedUnit CombineMultiply(PrefixedUnitExponent prefixedUnitExponent)
  2099. {
  2100. CombinedUnit uRes = new CombinedUnit(this);
  2101. uRes = uRes.CombineMultiply(prefixedUnitExponent);
  2102. return uRes;
  2103. }
  2104. public virtual CombinedUnit CombineDivide(PrefixedUnitExponent prefixedUnitExponent)
  2105. {
  2106. CombinedUnit uRes = new CombinedUnit(this);
  2107. uRes = uRes.CombineDivide(prefixedUnitExponent);
  2108. return uRes;
  2109. }
  2110. #endregion Unit Combine math methods
  2111. public static implicit operator Quantity(Unit physicalUnit) => new Quantity(physicalUnit);
  2112. }
  2113. public abstract class SystemUnit : Unit, ISystemUnit /* <BaseUnit | DerivedUnit | ConvertibleUnit> */
  2114. {
  2115. private IUnitSystem system;
  2116. public override IUnitSystem SimpleSystem { get { return system; } set { system = value; } }
  2117. public override IUnitSystem ExponentsSystem => system;
  2118. protected SystemUnit(IUnitSystem someSystem = null)
  2119. {
  2120. this.system = someSystem;
  2121. }
  2122. public override Quantity ConvertToSystemUnit(ref Double value) => new Quantity(value, (Unit)this);
  2123. public override Quantity ConvertToSystemUnit() => new Quantity(1, (Unit)this);
  2124. }
  2125. public class BaseUnit : SystemUnit, INamedSymbol, IBaseUnit //, IPrefixedUnit
  2126. {
  2127. private NamedSymbol namedSymbol;
  2128. public String Name => this.namedSymbol.Name;
  2129. public String Symbol => this.namedSymbol.Symbol;
  2130. private SByte baseunitnumber;
  2131. public SByte BaseUnitNumber => baseunitnumber;
  2132. public override UnitKind Kind => UnitKind.BaseUnit;
  2133. public override SByte[] Exponents
  2134. {
  2135. get
  2136. {
  2137. if (baseunitnumber < 0)
  2138. {
  2139. Debug.Assert(baseunitnumber >= 0);
  2140. }
  2141. int NoOfBaseUnits = baseunitnumber + 1;
  2142. if (SimpleSystem != null && SimpleSystem.BaseUnits != null)
  2143. {
  2144. NoOfBaseUnits = SimpleSystem.BaseUnits.Length;
  2145. }
  2146. SByte[] tempExponents = new SByte[NoOfBaseUnits];
  2147. tempExponents[baseunitnumber] = 1;
  2148. return tempExponents;
  2149. }
  2150. }
  2151. public BaseUnit(IUnitSystem someUnitSystem, SByte someBaseUnitNumber, NamedSymbol someNamedSymbol)
  2152. : base(someUnitSystem)
  2153. {
  2154. if (someBaseUnitNumber < 0)
  2155. {
  2156. Debug.Assert(someBaseUnitNumber >= 0);
  2157. }
  2158. this.baseunitnumber = someBaseUnitNumber;
  2159. this.namedSymbol = someNamedSymbol;
  2160. }
  2161. public BaseUnit(IUnitSystem someUnitSystem, SByte someBaseUnitNumber, String someName, String someSymbol)
  2162. : this(someUnitSystem, someBaseUnitNumber, new NamedSymbol(someName, someSymbol))
  2163. {
  2164. }
  2165. public BaseUnit(SByte someBaseUnitNumber, String someName, String someSymbol)
  2166. : this(null, someBaseUnitNumber, someName, someSymbol)
  2167. {
  2168. }
  2169. /// <summary>
  2170. /// String with PrefixedUnitExponent formatted symbol (without system name prefixed).
  2171. /// </summary>
  2172. public override String PureUnitString() => this.Symbol;
  2173. public override Unit GetAsNamedUnit() => this;
  2174. /// <summary>
  2175. ///
  2176. /// </summary>
  2177. public override Boolean IsLinearConvertible() => true;
  2178. public override Quantity ConvertToBaseUnit() => new Quantity((Unit)this);
  2179. public override Quantity ConvertToDerivedUnit() => new Quantity((Unit)this);
  2180. public override Quantity ConvertToBaseUnit(Double value) => new Quantity(value, (Unit)this);
  2181. public override Quantity ConvertToBaseUnit(Quantity physicalQuantity) => physicalQuantity.ConvertTo((Unit)this);
  2182. }
  2183. public class DerivedUnit : SystemUnit, IDerivedUnit
  2184. {
  2185. private readonly SByte[] exponents;
  2186. public override UnitKind Kind => UnitKind.DerivedUnit;
  2187. public override SByte[] Exponents => exponents;
  2188. public DerivedUnit(IUnitSystem someSystem, SByte[] someExponents = null)
  2189. : base(someSystem)
  2190. {
  2191. this.exponents = someExponents;
  2192. }
  2193. public DerivedUnit(SByte[] someExponents)
  2194. : this(Physics.SI_Units, someExponents)
  2195. {
  2196. }
  2197. /// <summary>
  2198. /// String with PrefixedUnitExponent formatted symbol (without system name prefixed).
  2199. /// </summary>
  2200. public override String PureUnitString()
  2201. {
  2202. Debug.Assert(this.Kind == UnitKind.DerivedUnit, "The 'this.Kind' must be UnitKind.DerivedUnit");
  2203. String ExponentsStr = "";
  2204. #if DEBUG // Error traces only included in debug build
  2205. Boolean UnitIsMissingSystem = false;
  2206. #endif
  2207. int index = 0;
  2208. foreach (SByte exponent in Exponents)
  2209. {
  2210. if (exponent != 0)
  2211. {
  2212. if (!String.IsNullOrEmpty(ExponentsStr))
  2213. {
  2214. ExponentsStr += '·'; // center dot '\0x0B7' (Char)183 U+00B7
  2215. }
  2216. IUnitSystem thisExponentsSystem = this.ExponentsSystem;
  2217. if (thisExponentsSystem != null)
  2218. {
  2219. ExponentsStr += thisExponentsSystem.BaseUnits[index].Symbol;
  2220. }
  2221. else
  2222. {
  2223. #if DEBUG // Error traces only included in debug build
  2224. UnitIsMissingSystem = true;
  2225. #endif
  2226. ExponentsStr += "<" + index.ToString() + ">";
  2227. }
  2228. if (exponent != 1)
  2229. {
  2230. ExponentsStr += exponent.ToString();
  2231. }
  2232. }
  2233. index++;
  2234. }
  2235. #if DEBUG // Error traces only included in debug build
  2236. if (UnitIsMissingSystem)
  2237. {
  2238. // Do some trace of error
  2239. Debug.WriteLine(global::System.Reflection.Assembly.GetExecutingAssembly().ToString() + " Unit " + this.Kind.ToString() + " { " + ExponentsStr + "} missing unit system.");
  2240. }
  2241. #endif
  2242. return ExponentsStr;
  2243. }
  2244. public override Boolean IsLinearConvertible() => true;
  2245. public override Quantity ConvertToBaseUnit() => new Quantity((Unit)this);
  2246. public override Quantity ConvertToBaseUnit(Double value) => new Quantity(value, (Unit)this);
  2247. public override Quantity ConvertToBaseUnit(Quantity physicalQuantity) => physicalQuantity.ConvertTo((Unit)this);
  2248. public override Quantity ConvertToDerivedUnit() => new Quantity((Unit)this);
  2249. public override Unit GetAsNamedUnit()
  2250. {
  2251. IUnitSystem unitSystem = SimpleSystem;
  2252. if (unitSystem != null && !unitSystem.IsCombinedUnitSystem)
  2253. {
  2254. Unit namedDerivatedUnit = (Unit)unitSystem.NamedDerivedUnitFromUnit(this);
  2255. if (namedDerivatedUnit != null)
  2256. {
  2257. return namedDerivatedUnit;
  2258. }
  2259. }
  2260. return this;
  2261. }
  2262. public override Unit Multiply(Unit physicalUnit)
  2263. {
  2264. Debug.Assert(physicalUnit != null, "The 'physicalUnit' parameter must be specified");
  2265. if (physicalUnit.Kind != UnitKind.CombinedUnit)
  2266. {
  2267. if (physicalUnit.SimpleSystem != this.SimpleSystem)
  2268. {
  2269. Quantity pq_pu = physicalUnit.ConvertTo(this.SimpleSystem);
  2270. if (pq_pu != null)
  2271. {
  2272. IQuantity pq = this.Multiply(pq_pu);
  2273. if (pq.Value.Equals(1.0))
  2274. {
  2275. return pq.Unit;
  2276. }
  2277. }
  2278. }
  2279. if (physicalUnit.SimpleSystem == this.SimpleSystem)
  2280. {
  2281. if (physicalUnit.Kind == UnitKind.BaseUnit)
  2282. {
  2283. IBaseUnit bu = physicalUnit as IBaseUnit;
  2284. return new DerivedUnit(this.SimpleSystem, this.Exponents.Multiply(bu.Exponents));
  2285. }
  2286. if (physicalUnit.Kind == UnitKind.DerivedUnit)
  2287. {
  2288. IDerivedUnit du = physicalUnit as IDerivedUnit;
  2289. return new DerivedUnit(this.SimpleSystem, this.Exponents.Multiply(du.Exponents));
  2290. }
  2291. }
  2292. }
  2293. return this.CombineMultiply(physicalUnit);
  2294. }
  2295. public override Unit Divide(Unit physicalUnit)
  2296. {
  2297. Debug.Assert(physicalUnit != null, "The 'physicalUnit' parameter must be specified");
  2298. if (physicalUnit.Kind != UnitKind.CombinedUnit)
  2299. {
  2300. if (physicalUnit.SimpleSystem != this.SimpleSystem)
  2301. {
  2302. Quantity pq_pu = physicalUnit.ConvertTo(this.SimpleSystem);
  2303. if (pq_pu != null)
  2304. {
  2305. Quantity pq = this.Divide(pq_pu);
  2306. if (pq.Value.Equals(1.0))
  2307. {
  2308. return pq.Unit;
  2309. }
  2310. }
  2311. }
  2312. if (physicalUnit.SimpleSystem == this.SimpleSystem)
  2313. {
  2314. if (physicalUnit.Kind == UnitKind.BaseUnit)
  2315. {
  2316. IBaseUnit bu = physicalUnit as IBaseUnit;
  2317. return new DerivedUnit(this.SimpleSystem, this.Exponents.Divide(bu.Exponents));
  2318. }
  2319. if (physicalUnit.Kind == UnitKind.DerivedUnit)
  2320. {
  2321. IDerivedUnit du = physicalUnit as IDerivedUnit;
  2322. return new DerivedUnit(this.SimpleSystem, this.Exponents.Divide(du.Exponents));
  2323. }
  2324. }
  2325. }
  2326. return this.CombineDivide(physicalUnit);
  2327. }
  2328. }
  2329. public class NamedDerivedUnit : DerivedUnit, INamedSymbol, INamedDerivedUnit // , IPrefixedUnit
  2330. {
  2331. private readonly NamedSymbol namedSymbol;
  2332. public String Name => this.namedSymbol.Name;
  2333. public String Symbol => this.namedSymbol.Symbol;
  2334. public NamedDerivedUnit(UnitSystem someSystem, NamedSymbol someNamedSymbol, SByte[] someExponents = null)
  2335. : base(someSystem, someExponents)
  2336. {
  2337. this.namedSymbol = someNamedSymbol;
  2338. }
  2339. public NamedDerivedUnit(UnitSystem someSystem, String someName, String someSymbol, SByte[] someExponents = null)
  2340. : this(someSystem, new NamedSymbol(someName, someSymbol), someExponents)
  2341. {
  2342. }
  2343. public NamedDerivedUnit(UnitSystem someSystem, String someName, String someSymbol, IDerivedUnit du)
  2344. : this(someSystem, new NamedSymbol(someName, someSymbol), du.Exponents)
  2345. {
  2346. Debug.Assert(du.SimpleSystem == someSystem);
  2347. }
  2348. public static Unit operator *(NamedDerivedUnit u, IUnitPrefix up)
  2349. {
  2350. Debug.Assert(up != null, "The " + nameof(up) + " parameter must be specified");
  2351. return new PrefixedUnit(up, u);
  2352. }
  2353. public static Unit operator *(IUnitPrefix up, NamedDerivedUnit u)
  2354. {
  2355. Debug.Assert(up != null, "The " + nameof(up) + " parameter must be specified");
  2356. return new PrefixedUnit(up, u);
  2357. }
  2358. /// <summary>
  2359. /// String PrefixedUnitExponent formatted symbol (without system name prefixed).
  2360. /// </summary>
  2361. public override String PureUnitString() => ReducedUnitString();
  2362. /// <summary>
  2363. /// String formatted by use of named derived unit symbols when possible(without system name prefixed).
  2364. /// without debug asserts.
  2365. /// </summary>
  2366. public override String ReducedUnitString()
  2367. {
  2368. Debug.Assert(this.Kind == UnitKind.DerivedUnit, "The 'this.Kind' must be UnitKind.DerivedUnit");
  2369. return Symbol;
  2370. }
  2371. /// <summary>
  2372. ///
  2373. /// </summary>
  2374. public override Quantity ConvertToBaseUnit() => this.ConvertToBaseUnit(1);
  2375. /// <summary>
  2376. ///
  2377. /// </summary>
  2378. public override Quantity ConvertToBaseUnit(double quantity)
  2379. {
  2380. IUnitSystem system = this.SimpleSystem;
  2381. Debug.Assert(system != null, "The 'System' must be valid for this unit");
  2382. return new Quantity(quantity, new DerivedUnit(system, this.Exponents));
  2383. }
  2384. /// <summary>
  2385. ///
  2386. /// </summary>
  2387. public override Quantity ConvertToBaseUnit(Quantity physicalQuantity)
  2388. {
  2389. Quantity pq = physicalQuantity.ConvertTo(this);
  2390. Debug.Assert(pq != null, "The 'physicalQuantity' must be valid and convertible to this unit");
  2391. return this.ConvertToBaseUnit(pq.Value);
  2392. }
  2393. public override Unit GetAsNamedUnit() => this;
  2394. }
  2395. public class ConvertibleUnit : SystemUnit, INamedSymbol, IConvertibleUnit
  2396. {
  2397. private readonly NamedSymbol namedSymbol;
  2398. public String Name => this.namedSymbol.Name;
  2399. public String Symbol => this.namedSymbol.Symbol;
  2400. private readonly Unit primaryunit;
  2401. private readonly IValueConversion conversion;
  2402. public Unit PrimaryUnit => primaryunit;
  2403. public IValueConversion Conversion => conversion;
  2404. public ConvertibleUnit(NamedSymbol someNamedSymbol, Unit somePrimaryUnit = null, ValueConversion someConversion = null)
  2405. : base(somePrimaryUnit != null ? somePrimaryUnit.SimpleSystem : null)
  2406. {
  2407. this.namedSymbol = someNamedSymbol;
  2408. primaryunit = somePrimaryUnit;
  2409. conversion = someConversion;
  2410. if (this.namedSymbol == null)
  2411. {
  2412. String name;
  2413. if (someConversion == null || someConversion.LinearOffset == 0)
  2414. {
  2415. name = this.ConvertToPrimaryUnit().ToPrintString();
  2416. }
  2417. else
  2418. {
  2419. name = this.primaryunit.ToPrintString();
  2420. if (someConversion.LinearScale != 1)
  2421. {
  2422. name = name + "/" + someConversion.LinearScale;
  2423. }
  2424. if (someConversion.LinearOffset >= 0)
  2425. {
  2426. name = name + " + " + someConversion.LinearOffset;
  2427. }
  2428. else
  2429. {
  2430. name = name + " - " + -someConversion.LinearOffset;
  2431. }
  2432. }
  2433. this.namedSymbol = new NamedSymbol(name, name);
  2434. }
  2435. Debug.Assert(this.namedSymbol != null, "The 'someNamedSymbol' must be valid and not null");
  2436. }
  2437. public ConvertibleUnit(String someName, String someSymbol, Unit somePrimaryUnit = null, ValueConversion someConversion = null)
  2438. : this(new NamedSymbol(someName, someSymbol), somePrimaryUnit, someConversion)
  2439. {
  2440. }
  2441. public override UnitKind Kind => UnitKind.ConvertibleUnit;
  2442. public override SByte[] Exponents => PrimaryUnit.Exponents;
  2443. public override IUnitSystem ExponentsSystem => PrimaryUnit.ExponentsSystem;
  2444. public override IUnitSystem SimpleSystem => PrimaryUnit.SimpleSystem;
  2445. /// <summary>
  2446. /// String with PrefixedUnitExponent formatted symbol (without system name prefixed).
  2447. /// </summary>
  2448. public override String PureUnitString() => ReducedUnitString();
  2449. /// <summary>
  2450. /// String with formatted by use of named derived unit symbols when possible(without system name prefixed).
  2451. /// without debug asserts.
  2452. /// </summary>
  2453. public override String ReducedUnitString()
  2454. {
  2455. Debug.Assert(this.Kind == UnitKind.ConvertibleUnit, "The 'this.Kind' must be valid and an UnitKind.ConvertibleUnit");
  2456. return this.namedSymbol.Symbol;
  2457. }
  2458. public override Unit GetAsNamedUnit() => this;
  2459. /// <summary>
  2460. ///
  2461. /// </summary>
  2462. public override Boolean IsLinearConvertible()
  2463. {
  2464. Debug.Assert(conversion != null, "The '_conversion' must be valid and not null");
  2465. return conversion.LinearOffset == 0;
  2466. }
  2467. public Quantity ConvertFromPrimaryUnit() => new Quantity(Conversion.ConvertFromPrimaryUnit(), (Unit)this);
  2468. public Quantity ConvertToPrimaryUnit() => new Quantity(Conversion.ConvertToPrimaryUnit(), PrimaryUnit);
  2469. public Quantity ConvertFromPrimaryUnit(Double value) => new Quantity(Conversion.ConvertFromPrimaryUnit(value), (Unit)this);
  2470. public Quantity ConvertToPrimaryUnit(Double value)
  2471. {
  2472. IValueConversion temp_conversion = Conversion;
  2473. Unit temp_primaryunit = PrimaryUnit;
  2474. Double convertedValue = temp_conversion.ConvertToPrimaryUnit(value);
  2475. return new Quantity(convertedValue, temp_primaryunit);
  2476. }
  2477. public override Quantity ConvertToSystemUnit(ref Double value)
  2478. {
  2479. Quantity pq = this.ConvertToPrimaryUnit(value);
  2480. pq = pq.ConvertToSystemUnit();
  2481. return pq;
  2482. }
  2483. public override Quantity ConvertToBaseUnit()
  2484. {
  2485. Quantity pq = this.ConvertToPrimaryUnit();
  2486. pq = pq.Unit.ConvertToBaseUnit().Multiply(pq.Value);
  2487. return pq;
  2488. }
  2489. public override Quantity ConvertToBaseUnit(double value) => PrimaryUnit.ConvertToBaseUnit(new Quantity(value, (Unit)this));
  2490. public override Quantity ConvertToBaseUnit(Quantity physicalQuantity)
  2491. {
  2492. Quantity pq = physicalQuantity.ConvertTo((Unit)this);
  2493. Debug.Assert(pq != null, "The 'physicalQuantity' must be valid and convertible to this unit");
  2494. return PrimaryUnit.ConvertToBaseUnit(pq);
  2495. }
  2496. public override Quantity ConvertToDerivedUnit() => this.ConvertToPrimaryUnit().ConvertToDerivedUnit();
  2497. public override Quantity ConvertTo(Unit convertToUnit)
  2498. {
  2499. if (convertToUnit == this)
  2500. {
  2501. return new Quantity(1, (Unit)this);
  2502. }
  2503. else
  2504. {
  2505. Quantity pq = this.ConvertToPrimaryUnit();
  2506. if (convertToUnit == PrimaryUnit)
  2507. {
  2508. return pq;
  2509. }
  2510. Quantity pq_toUnit = pq.Unit.ConvertTo(convertToUnit);
  2511. if (pq_toUnit != null)
  2512. {
  2513. return pq_toUnit.Multiply(pq.Value);
  2514. }
  2515. //// throw new ArgumentException("Physical unit is not convertible to a " + convertToUnit.ToString());
  2516. return null;
  2517. }
  2518. }
  2519. public override Unit Power(SByte exponent)
  2520. {
  2521. Quantity pq = this.ConvertToPrimaryUnit().ConvertToSystemUnit().Pow(exponent);
  2522. CombinedUnit cu = new CombinedUnit(pq.Value, pq.Unit);
  2523. return cu;
  2524. }
  2525. public override Unit Root(SByte exponent)
  2526. {
  2527. Quantity pq = this.ConvertToPrimaryUnit().ConvertToSystemUnit().Rot(exponent);
  2528. CombinedUnit cu = new CombinedUnit(pq.Value, pq.Unit);
  2529. return cu;
  2530. }
  2531. }
  2532. #region Combined Unit Classes
  2533. public class PrefixedUnit : Unit, IPrefixedUnit
  2534. {
  2535. private readonly IUnitPrefix prefix;
  2536. private readonly INamedSymbolUnit unit;
  2537. public IUnitPrefix Prefix => prefix;
  2538. public INamedSymbolUnit Unit => unit;
  2539. public override IUnitSystem SimpleSystem { get { return unit.SimpleSystem; } set { /* unit.SimpleSystem = value; */ } }
  2540. public override IUnitSystem ExponentsSystem => unit.ExponentsSystem;
  2541. public override UnitKind Kind => UnitKind.PrefixedUnit;
  2542. public override SByte[] Exponents => unit.Exponents;
  2543. /// <summary>
  2544. /// String with PrefixedUnitExponent formatted symbol (without system name prefixed).
  2545. /// </summary>
  2546. public override String PureUnitString() => Prefix.PrefixChar + Unit.Symbol;
  2547. public override Unit GetAsNamedUnit() => this;
  2548. public PrefixedUnit(IUnitPrefix somePrefix, INamedSymbolUnit someUnit)
  2549. {
  2550. this.prefix = somePrefix;
  2551. this.unit = someUnit;
  2552. }
  2553. public override Quantity AsPhysicalQuantity(Double value) => new Quantity(value, (Unit)this);
  2554. public override Boolean IsLinearConvertible() => unit.IsLinearConvertible();
  2555. public static implicit operator Quantity(PrefixedUnit prefixedUnit) => prefixedUnit.AsQuantity();
  2556. public override Quantity ConvertToSystemUnit()
  2557. {
  2558. Quantity pq = unit.ConvertToSystemUnit();
  2559. if (pq != null && prefix != null && prefix.Exponent != 0)
  2560. {
  2561. pq = pq.Multiply(prefix.Value);
  2562. }
  2563. return pq;
  2564. }
  2565. public override Quantity ConvertToSystemUnit(ref Double value)
  2566. {
  2567. // Conversion value is specified. Must assume Specific conversion e.g. specific temperature.
  2568. Quantity pq = unit.ConvertToSystemUnit(ref value);
  2569. if (pq != null && prefix != null && prefix.Exponent != 0)
  2570. {
  2571. pq = pq.Multiply(prefix.Value);
  2572. }
  2573. return pq;
  2574. }
  2575. public override Quantity ConvertToBaseUnit()
  2576. {
  2577. Quantity pq = unit.ConvertToBaseUnit();
  2578. if (pq != null && prefix != null && prefix.Exponent != 0)
  2579. {
  2580. pq = pq.Multiply(prefix.Value);
  2581. }
  2582. return pq;
  2583. }
  2584. public override Quantity ConvertToDerivedUnit()
  2585. {
  2586. Quantity pq = unit.ConvertToDerivedUnit();
  2587. if (pq != null && prefix != null && prefix.Exponent != 0)
  2588. {
  2589. pq = pq.Multiply(prefix.Value);
  2590. }
  2591. return pq;
  2592. }
  2593. public override Quantity ConvertToBaseUnit(Double value)
  2594. {
  2595. Quantity pq = this.ConvertToBaseUnit();
  2596. pq = pq.Multiply(value);
  2597. return pq;
  2598. }
  2599. public override String CombinedUnitString(Boolean mayUseSlash = true, Boolean invertExponents = false)
  2600. {
  2601. String combinedUnitString = Prefix.PrefixChar + Unit.Symbol;
  2602. return combinedUnitString;
  2603. }
  2604. }
  2605. public class PrefixedUnitExponent : Unit, IPrefixedUnitExponent
  2606. {
  2607. private readonly IPrefixedUnit prefixedUnit;
  2608. private readonly SByte exponent;
  2609. public SByte Exponent => exponent;
  2610. public PrefixedUnitExponent(INamedSymbolUnit someUnit)
  2611. : this(null, someUnit, 1)
  2612. {
  2613. }
  2614. public PrefixedUnitExponent(INamedSymbolUnit someUnit, SByte someExponent)
  2615. : this(null, someUnit, someExponent)
  2616. {
  2617. }
  2618. public PrefixedUnitExponent(IPrefixedUnitExponent prefixedUnitExponent)
  2619. : this(prefixedUnitExponent.Prefix, prefixedUnitExponent.Unit, prefixedUnitExponent.Exponent)
  2620. {
  2621. }
  2622. public PrefixedUnitExponent(IUnitPrefix somePrefix, INamedSymbolUnit someUnit, SByte someExponent)
  2623. : this(new PrefixedUnit(somePrefix, someUnit), someExponent)
  2624. {
  2625. }
  2626. public PrefixedUnitExponent(IPrefixedUnit somePrefixedUnit, SByte someExponent)
  2627. {
  2628. this.prefixedUnit = somePrefixedUnit;
  2629. this.exponent = someExponent;
  2630. Debug.Assert(someExponent != 0, "The 'exponent' must be valid and not zero");
  2631. }
  2632. public IUnitPrefix Prefix => prefixedUnit.Prefix;
  2633. public INamedSymbolUnit Unit => prefixedUnit.Unit;
  2634. public override UnitKind Kind => UnitKind.PrefixedUnitExponent;
  2635. public override IUnitSystem SimpleSystem { get { return prefixedUnit.SimpleSystem; } set { /* prefixedUnit.SimpleSystem = value; */ } }
  2636. public override IUnitSystem ExponentsSystem => prefixedUnit.ExponentsSystem;
  2637. public override SByte[] Exponents
  2638. {
  2639. get
  2640. {
  2641. SByte[] exponents = prefixedUnit.Exponents;
  2642. if (exponent != 1)
  2643. {
  2644. exponents = exponents.Power(exponent);
  2645. }
  2646. return exponents;
  2647. }
  2648. }
  2649. /// <summary>
  2650. /// String with PrefixedUnitExponent formatted symbol (without system name prefixed).
  2651. /// </summary>
  2652. public override String PureUnitString()
  2653. {
  2654. IUnit pu = prefixedUnit;
  2655. if (exponent != 1)
  2656. {
  2657. pu = pu.Pow(exponent);
  2658. }
  2659. String unitString = pu.PureUnitString();
  2660. return unitString;
  2661. }
  2662. public override Boolean IsLinearConvertible() => prefixedUnit.IsLinearConvertible();
  2663. public override Quantity ConvertToSystemUnit()
  2664. {
  2665. Quantity pq = prefixedUnit.ConvertToSystemUnit();
  2666. if (exponent != 1)
  2667. {
  2668. pq = pq.Pow(exponent);
  2669. }
  2670. return pq;
  2671. }
  2672. public override Quantity ConvertToSystemUnit(ref Double value)
  2673. {
  2674. // Conversion value is specified. Must assume Specific conversion e.g. specific temperature.
  2675. Quantity pq = prefixedUnit.ConvertToSystemUnit(ref value);
  2676. if (exponent != 1)
  2677. {
  2678. pq = pq.Pow(exponent);
  2679. }
  2680. return pq;
  2681. }
  2682. public override Quantity ConvertToBaseUnit()
  2683. {
  2684. Quantity pq = prefixedUnit.ConvertToBaseUnit();
  2685. if (exponent != 1)
  2686. {
  2687. pq = pq.Pow(exponent);
  2688. }
  2689. return pq;
  2690. }
  2691. public override Quantity ConvertToDerivedUnit()
  2692. {
  2693. Quantity pq = prefixedUnit.ConvertToDerivedUnit();
  2694. if (exponent != 1)
  2695. {
  2696. pq = pq.Pow(exponent);
  2697. }
  2698. return pq;
  2699. }
  2700. public override Quantity ConvertToBaseUnit(double quantity)
  2701. {
  2702. Quantity pq = prefixedUnit.ConvertToBaseUnit();
  2703. if (exponent != 1)
  2704. {
  2705. pq = pq.Pow(exponent);
  2706. }
  2707. pq = pq.Multiply(quantity);
  2708. return pq;
  2709. }
  2710. /// <summary>
  2711. /// IFormattable.ToString implementation.
  2712. /// </summary>
  2713. public override String ToString() => this.CombinedUnitString();
  2714. public override String CombinedUnitString(Boolean mayUseSlash = true, Boolean invertExponents = false)
  2715. {
  2716. String Str = "";
  2717. Debug.Assert(exponent != 0, "The '_Exponent' must be valid and not zero");
  2718. if (prefixedUnit.Unit != null)
  2719. {
  2720. string UnitStr = prefixedUnit.Unit.UnitString();
  2721. if (prefixedUnit.Prefix != null && prefixedUnit.Prefix.Exponent != 0)
  2722. {
  2723. Char PrefixChar = prefixedUnit.Prefix.PrefixChar;
  2724. UnitStr = PrefixChar + UnitStr;
  2725. }
  2726. SByte expo = Exponent;
  2727. if (invertExponents)
  2728. {
  2729. expo = (SByte)(-expo);
  2730. }
  2731. if ((UnitStr.Contains('·') || UnitStr.Contains('/') || UnitStr.Contains('^')) && (expo != 1))
  2732. {
  2733. Str = "(" + UnitStr + ")";
  2734. }
  2735. else
  2736. {
  2737. Str = UnitStr;
  2738. }
  2739. if (expo != 1)
  2740. {
  2741. Str += expo.ToString();
  2742. }
  2743. }
  2744. else
  2745. {
  2746. if (prefixedUnit.Prefix != null && prefixedUnit.Prefix.Exponent != 0)
  2747. {
  2748. SByte expo = Exponent;
  2749. if (invertExponents)
  2750. {
  2751. expo = (SByte)(-expo);
  2752. }
  2753. expo = (SByte)(prefixedUnit.Prefix.Exponent * expo);
  2754. Str = "10";
  2755. if (expo != 1)
  2756. {
  2757. Str += "^" + expo.ToString();
  2758. }
  2759. }
  2760. }
  2761. return Str;
  2762. }
  2763. public override Quantity AsQuantity()
  2764. {
  2765. Quantity pue_pq = prefixedUnit.AsQuantity();
  2766. if (exponent != 1)
  2767. {
  2768. pue_pq = pue_pq.Pow(exponent);
  2769. }
  2770. return pue_pq;
  2771. }
  2772. public PrefixedUnitExponent CombinePrefixAndExponents(SByte outerPUE_PrefixExponent, SByte outerPUE_Exponent, out SByte scaleExponent, out Double scaleFactor)
  2773. {
  2774. SByte combinedPrefixExponent = 0;
  2775. if (this.Exponent == 1 || outerPUE_PrefixExponent == 0)
  2776. {
  2777. //
  2778. scaleFactor = 1;
  2779. scaleExponent = 0;
  2780. combinedPrefixExponent = (SByte)(outerPUE_PrefixExponent + this.prefixedUnit.Prefix.Exponent);
  2781. }
  2782. else
  2783. {
  2784. int reminder;
  2785. combinedPrefixExponent = (SByte)Math.DivRem(outerPUE_PrefixExponent, this.Exponent, out reminder);
  2786. if (reminder != 0)
  2787. {
  2788. scaleFactor = Math.Pow(10, 1.0 * reminder);
  2789. scaleExponent = (SByte)reminder;
  2790. }
  2791. else
  2792. {
  2793. scaleFactor = 1;
  2794. scaleExponent = 0;
  2795. }
  2796. combinedPrefixExponent += this.prefixedUnit.Prefix.Exponent;
  2797. }
  2798. IUnitPrefix combinedUnitPrefix;
  2799. SByte combinedScaleFactorExponent;
  2800. Physics.UnitPrefixes.GetFloorUnitPrefixAndScaleFactorFromExponent(combinedPrefixExponent, out combinedUnitPrefix, out combinedScaleFactorExponent);
  2801. IUnitPrefixExponent pe = new UnitPrefixExponent((SByte)(combinedPrefixExponent + this.prefixedUnit.Prefix.Exponent));
  2802. IUnitPrefix up = null;
  2803. if (Physics.UnitPrefixes.GetUnitPrefixFromExponent(pe, out up))
  2804. {
  2805. PrefixedUnitExponent CombinedPUE = new PrefixedUnitExponent(up, this.prefixedUnit.Unit, (SByte)(this.Exponent * outerPUE_Exponent));
  2806. return CombinedPUE;
  2807. }
  2808. else
  2809. {
  2810. // TO DO: Handle to make result as IPrefixedUnitExponent
  2811. Debug.Assert(false);
  2812. return null;
  2813. }
  2814. }
  2815. public static implicit operator Quantity(PrefixedUnitExponent prefixedUnitExponent) => prefixedUnitExponent.AsQuantity();
  2816. }
  2817. public class PrefixedUnitExponentList : List<IPrefixedUnitExponent>, IPrefixedUnitExponentList
  2818. {
  2819. public PrefixedUnitExponentList()
  2820. {
  2821. }
  2822. public PrefixedUnitExponentList(IEnumerable<IPrefixedUnitExponent> elements)
  2823. : base(elements.Where(elm => elm != null))
  2824. {
  2825. }
  2826. /// <summary>
  2827. /// IFormattable.ToString implementation.
  2828. /// </summary>
  2829. public String CombinedUnitString(Boolean mayUseSlash = true, Boolean invertExponents = false)
  2830. {
  2831. String str = "";
  2832. foreach (IPrefixedUnitExponent ue in this)
  2833. {
  2834. Debug.Assert(ue.Exponent != 0, "ue.Exponent must be <> 0");
  2835. if (!String.IsNullOrEmpty(str))
  2836. {
  2837. str += '·'; // center dot '\0x0B7' (Char)183 U+00B7
  2838. }
  2839. str += ue.CombinedUnitString(mayUseSlash, invertExponents);
  2840. }
  2841. return str;
  2842. }
  2843. public IPrefixedUnitExponentList Power(SByte exponent)
  2844. {
  2845. PrefixedUnitExponentList result = new PrefixedUnitExponentList();
  2846. Double factorValue = 1.0;
  2847. foreach (IPrefixedUnitExponent pue in this)
  2848. {
  2849. SByte newPrefixExponent = 0;
  2850. SByte newExponent = (SByte)(pue.Exponent * exponent);
  2851. if (pue.Prefix != null && pue.Prefix.Exponent != 0)
  2852. {
  2853. newPrefixExponent = pue.Prefix.Exponent;
  2854. Debug.Assert((pue.Prefix.Exponent == 0) || (exponent == 1) || (exponent == -1), "Power: pue.Prefix.PrefixExponent must be 0. " + pue.CombinedUnitString() + "^" + exponent);
  2855. }
  2856. IUnitPrefix newUnitPrefix = null;
  2857. if (newPrefixExponent != 0)
  2858. {
  2859. SByte scaleFactorExponent;
  2860. Physics.UnitPrefixes.GetFloorUnitPrefixAndScaleFactorFromExponent(newPrefixExponent, out newUnitPrefix, out scaleFactorExponent);
  2861. if (scaleFactorExponent != 0)
  2862. {
  2863. factorValue *= Math.Pow(10, scaleFactorExponent * newExponent);
  2864. }
  2865. }
  2866. PrefixedUnitExponent result_pue = new PrefixedUnitExponent(newUnitPrefix, pue.Unit, newExponent);
  2867. result.Add(result_pue);
  2868. }
  2869. Debug.Assert(factorValue == 1.0);
  2870. return result;
  2871. }
  2872. public IPrefixedUnitExponentList Root(SByte someExponent)
  2873. {
  2874. PrefixedUnitExponentList result = new PrefixedUnitExponentList();
  2875. Double factorValue = 1.0;
  2876. foreach (IPrefixedUnitExponent pue in this)
  2877. {
  2878. SByte newPrefixExponent = 0;
  2879. int remainder;
  2880. int newExponent = Math.DivRem(pue.Exponent, someExponent, out remainder);
  2881. if (remainder != 0)
  2882. {
  2883. Debug.Assert(remainder == 0);
  2884. return null;
  2885. }
  2886. if (pue.Prefix != null && pue.Prefix.Exponent != 0)
  2887. {
  2888. newPrefixExponent = pue.Prefix.Exponent;
  2889. Debug.Assert((pue.Prefix.Exponent == 0) || (someExponent == 1) || (someExponent == -1), "Root: pue.Prefix.PrefixExponent must be 0. " + pue.CombinedUnitString() + "^(1/" + someExponent + ")");
  2890. }
  2891. IUnitPrefix newUnitPrefix = null;
  2892. if (newPrefixExponent != 0)
  2893. {
  2894. SByte scaleFactorExponent;
  2895. Physics.UnitPrefixes.GetFloorUnitPrefixAndScaleFactorFromExponent(newPrefixExponent, out newUnitPrefix, out scaleFactorExponent);
  2896. if (scaleFactorExponent != 0)
  2897. {
  2898. factorValue *= Math.Pow(10, scaleFactorExponent * newExponent);
  2899. }
  2900. }
  2901. PrefixedUnitExponent result_pue = new PrefixedUnitExponent(newUnitPrefix, pue.Unit, (SByte)newExponent);
  2902. result.Add(result_pue);
  2903. }
  2904. Debug.Assert(factorValue == 1.0);
  2905. return result;
  2906. }
  2907. }
  2908. public class CombinedUnit : Unit, ICombinedUnit
  2909. {
  2910. private Double scaleFactor = 1;
  2911. private IPrefixedUnitExponentList numerators;
  2912. private IPrefixedUnitExponentList denominators;
  2913. public IPrefixedUnitExponentList Numerators => numerators as IPrefixedUnitExponentList;
  2914. public IPrefixedUnitExponentList Denominators => denominators as IPrefixedUnitExponentList;
  2915. public CombinedUnit()
  2916. : this(new PrefixedUnitExponentList(), new PrefixedUnitExponentList())
  2917. {
  2918. }
  2919. public CombinedUnit(IPrefixedUnitExponentList someNumerators)
  2920. : this(someNumerators, new PrefixedUnitExponentList())
  2921. {
  2922. }
  2923. public CombinedUnit(IPrefixedUnitExponentList someNumerators, IPrefixedUnitExponentList someDenominators)
  2924. {
  2925. if ((someNumerators == null || someNumerators.Count == 0) && (someDenominators != null && someDenominators.Count > 0))
  2926. {
  2927. someNumerators = new PrefixedUnitExponentList(someDenominators.Select(pue => new PrefixedUnitExponent(pue.Prefix, pue.Unit, (SByte)(-pue.Exponent))));
  2928. someDenominators = null;
  2929. }
  2930. this.numerators = someNumerators != null ? someNumerators : new PrefixedUnitExponentList();
  2931. this.denominators = someDenominators != null ? someDenominators : new PrefixedUnitExponentList();
  2932. }
  2933. public CombinedUnit(Double someScaleFactor, IPrefixedUnitExponentList someNumerators, IPrefixedUnitExponentList someDenominators)
  2934. : this(someNumerators, someDenominators)
  2935. {
  2936. this.scaleFactor = someScaleFactor;
  2937. }
  2938. public CombinedUnit(ICombinedUnit combinedUnit)
  2939. : this(combinedUnit.FactorValue, combinedUnit.Numerators, combinedUnit.Denominators)
  2940. {
  2941. }
  2942. public CombinedUnit(IUnitPrefix prefix, CombinedUnit combinedUnit)
  2943. {
  2944. IUnitPrefix somePrefix = prefix;
  2945. Double someFactorValue = combinedUnit.FactorValue;
  2946. Boolean found = false;
  2947. PrefixedUnitExponentList someNumerators = new PrefixedUnitExponentList();
  2948. PrefixedUnitExponentList someDenominators = new PrefixedUnitExponentList();
  2949. foreach (IPrefixedUnitExponent pue in combinedUnit.Numerators)
  2950. {
  2951. Boolean added = false;
  2952. IUnitPrefix tempPrefix = null;
  2953. SByte ScaleFactorExponent = 0;
  2954. Double somePrefixExponentDiff = 0;
  2955. if (!found )
  2956. {
  2957. if (someFactorValue != 1)
  2958. {
  2959. // Try to combine specified prefix with combinedUnit valueFactor to a prefix
  2960. Double tempSomeFactorValue = Math.Pow(10, somePrefix.Exponent) * someFactorValue;
  2961. Double somePrefixExponentD = Math.Log10(tempSomeFactorValue);
  2962. SByte somePrefixExponent = (SByte)Math.Ceiling(somePrefixExponentD);
  2963. somePrefixExponentDiff = somePrefixExponentD - somePrefixExponent;
  2964. Physics.UnitPrefixes.GetFloorUnitPrefixAndScaleFactorFromExponent(somePrefixExponent, out tempPrefix, out ScaleFactorExponent);
  2965. }
  2966. else
  2967. {
  2968. // Just use specified prefix
  2969. tempPrefix = somePrefix;
  2970. }
  2971. }
  2972. if (!found && tempPrefix != null)
  2973. {
  2974. IPrefixedUnitExponent tempPue = new PrefixedUnitExponent(tempPrefix, pue.Unit, pue.Exponent);
  2975. someNumerators.Add(tempPue);
  2976. somePrefix = null;
  2977. if (ScaleFactorExponent != 0)
  2978. {
  2979. someFactorValue = Math.Pow(10, ScaleFactorExponent + somePrefixExponentDiff);
  2980. }
  2981. found = true;
  2982. added = true;
  2983. }
  2984. if (!added)
  2985. {
  2986. someNumerators.Add(pue);
  2987. }
  2988. }
  2989. foreach (IPrefixedUnitExponent pue in combinedUnit.Denominators)
  2990. {
  2991. someDenominators.Add(pue);
  2992. }
  2993. this.scaleFactor = someFactorValue;
  2994. this.numerators = someNumerators;
  2995. this.denominators = someDenominators;
  2996. }
  2997. public CombinedUnit(IPrefixedUnitExponent prefixedUnitExponent)
  2998. : this(new PrefixedUnitExponentList(), new PrefixedUnitExponentList())
  2999. {
  3000. this.numerators.Add(prefixedUnitExponent);
  3001. }
  3002. public CombinedUnit(IUnit physicalUnit)
  3003. {
  3004. ICombinedUnit cu = null;
  3005. INamedSymbolUnit nsu = physicalUnit as INamedSymbolUnit;
  3006. if (nsu != null)
  3007. {
  3008. cu = new CombinedUnit(nsu);
  3009. }
  3010. else
  3011. {
  3012. switch (physicalUnit.Kind)
  3013. {
  3014. case UnitKind.PrefixedUnit:
  3015. IPrefixedUnit pu = physicalUnit as IPrefixedUnit;
  3016. Debug.Assert(pu != null);
  3017. cu = new CombinedUnit(pu);
  3018. break;
  3019. case UnitKind.PrefixedUnitExponent:
  3020. IPrefixedUnitExponent pue = physicalUnit as IPrefixedUnitExponent;
  3021. Debug.Assert(pue != null);
  3022. cu = new CombinedUnit(pue);
  3023. break;
  3024. case UnitKind.DerivedUnit:
  3025. IDerivedUnit du = physicalUnit as IDerivedUnit;
  3026. Debug.Assert(du != null);
  3027. cu = new CombinedUnit(du);
  3028. break;
  3029. case UnitKind.MixedUnit:
  3030. IMixedUnit mu = physicalUnit as IMixedUnit;
  3031. Debug.Assert(mu != null);
  3032. cu = new CombinedUnit(mu.MainUnit);
  3033. break;
  3034. case UnitKind.CombinedUnit:
  3035. ICombinedUnit cu2 = physicalUnit as ICombinedUnit;
  3036. Debug.Assert(cu2 != null);
  3037. cu = new CombinedUnit(cu2);
  3038. break;
  3039. default:
  3040. Debug.Assert(false);
  3041. break;
  3042. }
  3043. }
  3044. if (cu != null)
  3045. {
  3046. this.scaleFactor = cu.FactorValue;
  3047. this.numerators = cu.Numerators;
  3048. this.denominators = cu.Denominators;
  3049. }
  3050. else
  3051. {
  3052. // TO DO: Convert physicalUnit to CombinedUnit
  3053. Debug.Assert(false);
  3054. }
  3055. }
  3056. public CombinedUnit(Double someScaleFactor, IUnit physicalUnit)
  3057. : this(physicalUnit)
  3058. {
  3059. this.scaleFactor *= someScaleFactor;
  3060. }
  3061. public CombinedUnit(INamedSymbolUnit namedSymbolUnit)
  3062. : this(new PrefixedUnitExponent(null, namedSymbolUnit, 1))
  3063. {
  3064. }
  3065. public CombinedUnit(IPrefixedUnit prefixedUnit)
  3066. : this(new PrefixedUnitExponent(prefixedUnit.Prefix, prefixedUnit.Unit, 1))
  3067. {
  3068. }
  3069. public CombinedUnit(IDerivedUnit derivedUnit)
  3070. {
  3071. IPrefixedUnitExponentList someNumerators = new PrefixedUnitExponentList();
  3072. IPrefixedUnitExponentList someDenominators = new PrefixedUnitExponentList();
  3073. IUnitSystem system = derivedUnit.ExponentsSystem;
  3074. int length = derivedUnit.Exponents.Length;
  3075. foreach (Byte i in Enumerable.Range(0, length))
  3076. {
  3077. SByte exp = derivedUnit.Exponents[i];
  3078. if (exp != 0)
  3079. {
  3080. if (exp > 0)
  3081. {
  3082. someNumerators.Add(new PrefixedUnitExponent(null, system.BaseUnits[i], exp));
  3083. }
  3084. else
  3085. {
  3086. someDenominators.Add(new PrefixedUnitExponent(null, system.BaseUnits[i], (sbyte)(-exp)));
  3087. }
  3088. }
  3089. }
  3090. this.scaleFactor = derivedUnit.FactorValue;
  3091. this.numerators = someNumerators;
  3092. this.denominators = someDenominators;
  3093. }
  3094. public override UnitKind Kind => UnitKind.CombinedUnit;
  3095. public override IUnitSystem SimpleSystem
  3096. {
  3097. get
  3098. {
  3099. IUnitSystem system = null; // No unit system
  3100. foreach (IPrefixedUnitExponent pue in Numerators.Union(Denominators))
  3101. {
  3102. if (pue.Unit == null)
  3103. {
  3104. // This could be at prefix only
  3105. // Just ignore this pue; it can't affect unit system info
  3106. // return null;
  3107. }
  3108. else
  3109. {
  3110. IUnitSystem subsystem = pue.Unit.SimpleSystem;
  3111. if (system == null)
  3112. {
  3113. system = subsystem;
  3114. }
  3115. else
  3116. {
  3117. if (system != subsystem)
  3118. {
  3119. // Multiple unit systems
  3120. return null;
  3121. }
  3122. }
  3123. }
  3124. }
  3125. return system; // The one and only system for all sub units
  3126. }
  3127. set { /* Just do nothing */ throw new NotImplementedException(); }
  3128. }
  3129. public override IUnitSystem ExponentsSystem
  3130. {
  3131. get
  3132. {
  3133. IUnitSystem system = null; // No unit system
  3134. List<IUnitSystem> subUnitSystems = null;
  3135. foreach (IPrefixedUnitExponent pue in Numerators.Union(Denominators))
  3136. {
  3137. if (pue.Unit != null)
  3138. {
  3139. if (system == null)
  3140. {
  3141. system = pue.Unit.ExponentsSystem;
  3142. }
  3143. else
  3144. {
  3145. IUnitSystem pue_system = pue.Unit.ExponentsSystem; // pue.Unit.SomeSimpleSystem;
  3146. if (system != pue_system
  3147. && ((!system.IsCombinedUnitSystem && !pue_system.IsCombinedUnitSystem)
  3148. || (system.IsCombinedUnitSystem
  3149. && !pue_system.IsCombinedUnitSystem
  3150. && !((CombinedUnitSystem)system).ContainsSubUnitSystem(pue_system))
  3151. /*
  3152. We must still include pue_system sub unit systems
  3153. || ( !system.IsCombinedUnitSystem
  3154. && pue_system.IsCombinedUnitSystem
  3155. && !((CombinedUnitSystem)pue_system).ContainsSubUnitSystem(system))
  3156. */
  3157. || (system.IsCombinedUnitSystem
  3158. && pue_system.IsCombinedUnitSystem
  3159. && !((CombinedUnitSystem)system).ContainsSubUnitSystems(((CombinedUnitSystem)pue_system).UnitSystemes))
  3160. )
  3161. )
  3162. {
  3163. // Multiple unit systems and some could be an isolated unit system
  3164. if (subUnitSystems == null)
  3165. { // First time we have found a second system. Add system as first system in list of systems
  3166. subUnitSystems = new List<IUnitSystem>();
  3167. if (!system.IsCombinedUnitSystem)
  3168. {
  3169. subUnitSystems.Add(system);
  3170. }
  3171. else
  3172. {
  3173. CombinedUnitSystem cus = (CombinedUnitSystem)system;
  3174. subUnitSystems.AddRange(cus.UnitSystemes);
  3175. }
  3176. }
  3177. { // Add pue_system to list of systems
  3178. if (!pue_system.IsCombinedUnitSystem)
  3179. {
  3180. subUnitSystems.Add(pue_system);
  3181. }
  3182. else
  3183. {
  3184. CombinedUnitSystem cus = (CombinedUnitSystem)pue_system;
  3185. subUnitSystems.AddRange(cus.UnitSystemes);
  3186. }
  3187. }
  3188. }
  3189. }
  3190. }
  3191. }
  3192. if (subUnitSystems != null)
  3193. {
  3194. if (subUnitSystems.Any(us => us.IsIsolatedUnitSystem))
  3195. { // Must combine the unit systems into one unit system
  3196. system = CombinedUnitSystem.GetCombinedUnitSystem(subUnitSystems.Distinct().ToArray());
  3197. }
  3198. else
  3199. {
  3200. IUnitSystem DefaultUnitSystem = Physics.CurrentUnitSystems.Default;
  3201. if (subUnitSystems.Contains(DefaultUnitSystem))
  3202. {
  3203. system = DefaultUnitSystem;
  3204. }
  3205. else
  3206. {
  3207. // system = SubUnitSystems.First(us => !us.IsIsolatedUnitSystem);
  3208. system = subUnitSystems.First();
  3209. }
  3210. }
  3211. }
  3212. if (system == null)
  3213. {
  3214. system = Physics.CurrentUnitSystems.Default;
  3215. }
  3216. Debug.Assert(system != null, "CombinedUnit.ExponentsSystem is null");
  3217. return system;
  3218. }
  3219. }
  3220. public IUnitSystem SomeSimpleSystem
  3221. {
  3222. get
  3223. {
  3224. foreach (IPrefixedUnitExponent pue in Numerators.Union(Denominators))
  3225. {
  3226. if (pue.Unit != null)
  3227. {
  3228. IUnit pu = pue.Unit;
  3229. IUnitSystem somesystem = pu.SimpleSystem;
  3230. if (somesystem != null)
  3231. {
  3232. return somesystem;
  3233. }
  3234. else if (pu.Kind == UnitKind.CombinedUnit)
  3235. {
  3236. ICombinedUnit cu = (ICombinedUnit)pu;
  3237. somesystem = cu.SomeSimpleSystem;
  3238. if (somesystem != null)
  3239. {
  3240. return somesystem;
  3241. }
  3242. }
  3243. }
  3244. }
  3245. return null;
  3246. }
  3247. }
  3248. public override SByte[] Exponents
  3249. {
  3250. get
  3251. {
  3252. SByte[] exponents = null;
  3253. int elementCount = Numerators.Count + Denominators.Count;
  3254. if (elementCount == 0)
  3255. { // No exponents at all; return array of zeros
  3256. exponents = new SByte[1];
  3257. exponents[0] = 0;
  3258. }
  3259. else
  3260. {
  3261. IUnitSystem anySystem = this.ExponentsSystem;
  3262. if (anySystem == null)
  3263. {
  3264. Debug.WriteLine("CombinedUnit.Exponents() missing ExponentsSystem");
  3265. Debug.Assert(anySystem != null, "CombinedUnit.Exponents() missing ExponentsSystem");
  3266. anySystem = this.SomeSimpleSystem;
  3267. if (anySystem == null)
  3268. {
  3269. Debug.WriteLine("CombinedUnit.Exponents() missing also SomeSystem");
  3270. Debug.Assert(anySystem != null, "CombinedUnit.Exponents() missing also SomeSystem");
  3271. anySystem = Physics.SI_Units;
  3272. }
  3273. }
  3274. if (anySystem != null)
  3275. {
  3276. IQuantity baseUnit_pq = null;
  3277. IUnit baseUnit_pu = null;
  3278. try
  3279. {
  3280. baseUnit_pq = this.ConvertToDerivedUnit();
  3281. if (baseUnit_pq != null)
  3282. {
  3283. baseUnit_pu = baseUnit_pq.Unit;
  3284. if (baseUnit_pu != null)
  3285. {
  3286. IUnitSystem system = this.ExponentsSystem;
  3287. Debug.Assert(system != null);
  3288. if (system.IsCombinedUnitSystem)
  3289. {
  3290. ICombinedUnitSystem cus = system as ICombinedUnitSystem;
  3291. exponents = cus.UnitExponents(this);
  3292. }
  3293. else
  3294. {
  3295. UnitKind uk = baseUnit_pu.Kind;
  3296. exponents = baseUnit_pu.Exponents;
  3297. }
  3298. }
  3299. }
  3300. Debug.Assert(exponents != null, "CombinedUnit.ConvertToDerivedUnit() are missing base unit and exponents");
  3301. }
  3302. catch (Exception e)
  3303. {
  3304. Debug.WriteLine("CombinedUnit.ConvertToBaseUnit() failed and unit are missing exponents: " + e.Message);
  3305. Debug.Assert(false, "CombinedUnit.ConvertToBaseUnit() failed and unit are missing exponents: " + e.Message);
  3306. }
  3307. }
  3308. else
  3309. {
  3310. Debug.WriteLine("CombinedUnit.ConvertToBaseUnit() missing exponents");
  3311. Debug.Assert(false, "CombinedUnit.ConvertToBaseUnit() missing exponents");
  3312. }
  3313. }
  3314. return exponents;
  3315. }
  3316. }
  3317. public CombinedUnit OnlySingleSystemUnits(IUnitSystem us)
  3318. {
  3319. PrefixedUnitExponentList tempNumerators = new PrefixedUnitExponentList();
  3320. PrefixedUnitExponentList tempDenominators = new PrefixedUnitExponentList();
  3321. foreach (IPrefixedUnitExponent pue in Numerators)
  3322. {
  3323. if (((pue.Unit != null) && (pue.Unit.SimpleSystem == us))
  3324. || ((pue.Unit == null) && (us == null)))
  3325. {
  3326. // pue has the specified system; Include in result
  3327. tempNumerators.Add(pue);
  3328. }
  3329. }
  3330. foreach (IPrefixedUnitExponent pue in Denominators)
  3331. {
  3332. if (((pue.Unit != null) && (pue.Unit.SimpleSystem == us))
  3333. || ((pue.Unit == null) && (us == null)))
  3334. {
  3335. // pue has the specified system; Include in result
  3336. tempDenominators.Add(pue);
  3337. }
  3338. }
  3339. CombinedUnit cu = new CombinedUnit(tempNumerators, tempDenominators);
  3340. return cu;
  3341. }
  3342. public override Double FactorValue => scaleFactor;
  3343. public override Unit PureUnit
  3344. {
  3345. get
  3346. {
  3347. Unit pureunit = this;
  3348. if (scaleFactor != 0)
  3349. {
  3350. pureunit = new CombinedUnit(Numerators, Denominators);
  3351. }
  3352. return pureunit;
  3353. }
  3354. }
  3355. public override Unit GetAsNamedUnit()
  3356. {
  3357. Quantity pq = this.ConvertToDerivedUnit();
  3358. Quantity pqNamedUnit = pq.AsNamedUnit;
  3359. Unit namedUnit = Quantity.GetAsNamedUnit(pqNamedUnit);
  3360. if (namedUnit != null)
  3361. {
  3362. // return namedUnit as INamedSymbolUnit or PrefixedUnit;
  3363. Debug.Assert(namedUnit is BaseUnit || namedUnit is NamedDerivedUnit || namedUnit is ConvertibleUnit || namedUnit is PrefixedUnit);
  3364. return namedUnit;
  3365. }
  3366. return this;
  3367. }
  3368. /// <summary>
  3369. ///
  3370. /// </summary>
  3371. public override Boolean IsLinearConvertible()
  3372. {
  3373. if (Numerators.Count == 1 && Denominators.Count == 0)
  3374. {
  3375. IPrefixedUnitExponent pue = Numerators[0];
  3376. if (pue.Exponent == 1)
  3377. {
  3378. IUnit unit = pue.Unit;
  3379. if (unit != null)
  3380. {
  3381. return unit.IsLinearConvertible();
  3382. }
  3383. }
  3384. }
  3385. return true;
  3386. }
  3387. // Relative conversion
  3388. public override Quantity ConvertToSystemUnit()
  3389. {
  3390. IUnitSystem system = this.SimpleSystem;
  3391. if (system == null)
  3392. {
  3393. system = this.SomeSimpleSystem;
  3394. if (system == null)
  3395. {
  3396. system = this.ExponentsSystem;
  3397. }
  3398. Debug.Assert(system != null);
  3399. Quantity pq = this.ConvertTo(system);
  3400. if (pq == null)
  3401. {
  3402. //Debug.Assert(pq == null || pq.Unit.SimpleSystem == system);
  3403. //Debug.Assert(pq != null);
  3404. }
  3405. return pq;
  3406. }
  3407. return new Quantity(1, (Unit)this);
  3408. }
  3409. // Absolute conversion
  3410. public override Quantity ConvertToSystemUnit(ref Double value)
  3411. {
  3412. IUnitSystem system = this.SimpleSystem;
  3413. if (system == null)
  3414. {
  3415. system = Physics.CurrentUnitSystems.Default;
  3416. }
  3417. Debug.Assert(system != null);
  3418. Quantity pq = this.ConvertTo(ref value, system);
  3419. Debug.Assert(pq == null || pq.Unit.SimpleSystem != null);
  3420. return pq;
  3421. }
  3422. public override Quantity ConvertToBaseUnit()
  3423. {
  3424. IUnitSystem system = this.SimpleSystem;
  3425. if (system == null)
  3426. {
  3427. system = this.ExponentsSystem;
  3428. Debug.Assert(system != null);
  3429. if (system.IsCombinedUnitSystem)
  3430. {
  3431. ICombinedUnitSystem cus = system as ICombinedUnitSystem;
  3432. return cus.ConvertToBaseUnit(this);
  3433. }
  3434. // This happens for combined unit with sub units of different but convertible systems Debug.Assert(false);
  3435. // Combined unit with sub units of different but convertible systems
  3436. Quantity pq = this.ConvertToSystemUnit();
  3437. if (pq != null)
  3438. {
  3439. pq = pq.ConvertToBaseUnit();
  3440. }
  3441. return pq;
  3442. }
  3443. Debug.Assert(system != null);
  3444. Double value = scaleFactor;
  3445. Unit unit = null;
  3446. foreach (IPrefixedUnitExponent pue in Numerators)
  3447. {
  3448. Quantity pq_baseunit = pue.ConvertToBaseUnit();
  3449. value *= pq_baseunit.Value;
  3450. Unit baseunit = pq_baseunit.Unit;
  3451. if (unit == null)
  3452. {
  3453. unit = baseunit;
  3454. }
  3455. else
  3456. {
  3457. unit = unit.Multiply(baseunit);
  3458. }
  3459. }
  3460. foreach (IPrefixedUnitExponent pue in Denominators)
  3461. {
  3462. Quantity pq_baseunit = pue.ConvertToBaseUnit();
  3463. value *= pq_baseunit.Value;
  3464. Unit baseunit = pq_baseunit.Unit;
  3465. if (unit == null)
  3466. {
  3467. unit = baseunit.CombinePow(-1);
  3468. }
  3469. else
  3470. {
  3471. unit = unit.Divide(baseunit);
  3472. }
  3473. }
  3474. return new Quantity(value, unit);
  3475. }
  3476. public override Quantity ConvertToBaseUnit(double quantity)
  3477. {
  3478. IUnitSystem system = this.SimpleSystem;
  3479. if (system == null)
  3480. {
  3481. Double ScaledQuantity = scaleFactor * quantity;
  3482. Quantity pq1 = this.ConvertToSystemUnit(ref ScaledQuantity).ConvertToBaseUnit();
  3483. Debug.Assert(ScaledQuantity == 1.0);
  3484. return pq1;
  3485. }
  3486. Debug.Assert(system != null);
  3487. Quantity pq = new Quantity(quantity);
  3488. foreach (IPrefixedUnitExponent pue in Numerators)
  3489. {
  3490. Quantity pue_pq = pue.ConvertToBaseUnit();
  3491. pq = pq.Multiply(pue_pq);
  3492. }
  3493. foreach (IPrefixedUnitExponent pue in Denominators)
  3494. {
  3495. Quantity pue_pq = pue.ConvertToBaseUnit();
  3496. pq = pq.Divide(pue_pq);
  3497. }
  3498. return pq;
  3499. }
  3500. public override Quantity ConvertToDerivedUnit()
  3501. {
  3502. IUnitSystem system = this.SimpleSystem;
  3503. if (system == null)
  3504. {
  3505. Double scaledQuantity = scaleFactor;
  3506. Quantity pq1 = this.ConvertToSystemUnit();
  3507. if (pq1 != null)
  3508. {
  3509. // Simple system DerivedUnit
  3510. // Debug.Assert(scaledQuantity == 1.0);
  3511. Debug.Assert(pq1.Unit.SimpleSystem != null);
  3512. }
  3513. else
  3514. {
  3515. // Combined system DerivedUnit
  3516. system = this.ExponentsSystem;
  3517. Debug.Assert(system != null && system.IsCombinedUnitSystem);
  3518. pq1 = this.ConvertToBaseUnit();
  3519. }
  3520. pq1 = pq1.ConvertToDerivedUnit();
  3521. return pq1;
  3522. }
  3523. Debug.Assert(system != null);
  3524. Quantity pq = new Quantity(scaleFactor, system.Dimensionless);
  3525. foreach (IPrefixedUnitExponent pue in Numerators)
  3526. {
  3527. Quantity pue_pq = pue.ConvertToDerivedUnit();
  3528. pq = pq.Multiply(pue_pq);
  3529. }
  3530. foreach (IPrefixedUnitExponent pue in Denominators)
  3531. {
  3532. Quantity pue_pq = pue.ConvertToDerivedUnit();
  3533. pq = pq.Divide(pue_pq);
  3534. }
  3535. return pq;
  3536. }
  3537. public override Quantity ConvertTo(Unit convertToUnit)
  3538. {
  3539. Debug.Assert(convertToUnit != null);
  3540. IUnitSystem system = this.SimpleSystem;
  3541. IUnitSystem convertToSystem = convertToUnit.SimpleSystem;
  3542. if (system == null || system != convertToSystem)
  3543. {
  3544. if (convertToSystem == null)
  3545. {
  3546. if (convertToUnit.Kind == UnitKind.CombinedUnit)
  3547. {
  3548. ICombinedUnit cu = convertToUnit as ICombinedUnit;
  3549. convertToSystem = cu.ExponentsSystem;
  3550. }
  3551. }
  3552. if (convertToSystem != null)
  3553. {
  3554. IQuantity this_as_ToSystemUnit = this.ConvertTo(convertToSystem);
  3555. if (this_as_ToSystemUnit != null)
  3556. {
  3557. if (this_as_ToSystemUnit.Unit != null
  3558. && this_as_ToSystemUnit.Unit.ExponentsSystem != convertToSystem
  3559. && (!convertToSystem.IsCombinedUnitSystem || !((ICombinedUnitSystem)convertToSystem).ContainsSubUnitSystem(this_as_ToSystemUnit.Unit.ExponentsSystem)))
  3560. {
  3561. Debug.Assert(this_as_ToSystemUnit.Unit == null || this_as_ToSystemUnit.Unit.ExponentsSystem == convertToSystem || (convertToSystem.IsCombinedUnitSystem && ((ICombinedUnitSystem)convertToSystem).ContainsSubUnitSystem(this_as_ToSystemUnit.Unit.ExponentsSystem)), "PRE this_as_ToSystemUnit.Unit.ExponentsSystem != convertToSystem");
  3562. }
  3563. Debug.Assert(this_as_ToSystemUnit.Unit == null || this_as_ToSystemUnit.Unit.ExponentsSystem == convertToSystem || (convertToSystem.IsCombinedUnitSystem && ((ICombinedUnitSystem)convertToSystem).ContainsSubUnitSystem(this_as_ToSystemUnit.Unit.ExponentsSystem)), "this_as_ToSystemUnit.Unit.ExponentsSystem != convertToSystem");
  3564. return this_as_ToSystemUnit.ConvertTo(convertToUnit);
  3565. }
  3566. return null;
  3567. }
  3568. Debug.Assert(false);
  3569. return null;
  3570. }
  3571. Debug.Assert(system != null && system == convertToSystem);
  3572. Quantity pq_tounit = null;
  3573. Quantity pq_baseunit = null;
  3574. if (convertToUnit.Kind == UnitKind.CombinedUnit)
  3575. {
  3576. CombinedUnit convertToUnit_cu = convertToUnit as CombinedUnit;
  3577. CombinedUnit relativeUnit_cu = this.CombineDivide(convertToUnit_cu);
  3578. Quantity pq = relativeUnit_cu.ConvertToDerivedUnit();
  3579. if (pq.IsDimensionless)
  3580. {
  3581. return new Quantity(pq.Value, convertToUnit);
  3582. }
  3583. return null;
  3584. }
  3585. else
  3586. {
  3587. pq_baseunit = this.ConvertToDerivedUnit();
  3588. Debug.Assert(pq_baseunit.Unit != this || pq_baseunit.Unit.Kind != this.Kind); // Some reduction must be performed; else infinite recursive calls can occur
  3589. pq_tounit = pq_baseunit.Unit.ConvertTo(convertToUnit);
  3590. }
  3591. if (pq_tounit != null)
  3592. {
  3593. // Valid conversion
  3594. return new Quantity(pq_baseunit.Value * pq_tounit.Value, pq_tounit.Unit);
  3595. }
  3596. // Invalid conversion
  3597. return null;
  3598. }
  3599. public override Quantity ConvertTo(IUnitSystem convertToUnitSystem)
  3600. {
  3601. Double value = this.FactorValue;
  3602. Unit unit = null;
  3603. Debug.Assert(convertToUnitSystem != null);
  3604. foreach (IPrefixedUnitExponent pue in Numerators)
  3605. {
  3606. IQuantity pue_pq = pue.ConvertTo(convertToUnitSystem);
  3607. if (pue_pq == null)
  3608. {
  3609. return null;
  3610. }
  3611. value *= pue_pq.Value;
  3612. if (unit == null)
  3613. {
  3614. unit = pue_pq.Unit;
  3615. }
  3616. else
  3617. {
  3618. var e = pue_pq.Unit.Exponents;
  3619. unit = unit.CombineMultiply(pue_pq.Unit);
  3620. }
  3621. }
  3622. foreach (IPrefixedUnitExponent pue in Denominators)
  3623. {
  3624. IQuantity pue_pq = pue.ConvertTo(convertToUnitSystem);
  3625. if (pue_pq == null)
  3626. {
  3627. return null;
  3628. }
  3629. value /= pue_pq.Value;
  3630. if (unit == null)
  3631. {
  3632. unit = pue_pq.Unit.CombinePow(-1);
  3633. }
  3634. else
  3635. {
  3636. unit = unit.CombineDivide(pue_pq.Unit);
  3637. }
  3638. }
  3639. if (unit == null)
  3640. { // dimension less unit
  3641. unit = convertToUnitSystem.Dimensionless;
  3642. }
  3643. return new Quantity(value, unit);
  3644. }
  3645. public override Quantity ConvertTo(ref Double value, IUnitSystem convertToUnitSystem)
  3646. {
  3647. Quantity pq = this.ConvertTo(convertToUnitSystem);
  3648. if (pq != null)
  3649. {
  3650. pq = pq.Multiply(value);
  3651. }
  3652. return pq;
  3653. }
  3654. public Quantity ConvertFrom(Quantity physicalQuantity)
  3655. {
  3656. Quantity pq_unit = physicalQuantity;
  3657. if (Numerators.Count == 1 && Denominators.Count == 0)
  3658. {
  3659. IPrefixedUnitExponent pue = Numerators[0];
  3660. Debug.Assert(pue.Exponent == 1);
  3661. pq_unit = pq_unit.ConvertTo((Unit)pue.Unit);
  3662. Debug.Assert(pq_unit != null);
  3663. if (pq_unit != null)
  3664. {
  3665. if (pue.Prefix.Exponent != 0)
  3666. {
  3667. pq_unit = pq_unit.Multiply(Math.Pow(10, -pue.Prefix.Exponent));
  3668. }
  3669. pq_unit = new Quantity(pq_unit.Value, (Unit)this);
  3670. }
  3671. }
  3672. else
  3673. {
  3674. // TODO: Not implemented yet
  3675. Debug.Assert(false);
  3676. }
  3677. return pq_unit;
  3678. }
  3679. #region IPhysicalUnitMath Members
  3680. public override Unit Dimensionless => new CombinedUnit();
  3681. public override Boolean IsDimensionless
  3682. {
  3683. get
  3684. {
  3685. if (Numerators.Count == 0 && Denominators.Count == 0)
  3686. {
  3687. return true;
  3688. }
  3689. return base.IsDimensionless;
  3690. }
  3691. }
  3692. private void MultiplyPUEL(IPrefixedUnitExponent prefixedUnitExponent, CombineExponentsFunc cef, IPrefixedUnitExponentList inPuel, ref IPrefixedUnitExponentList outPuel1,
  3693. ref Boolean primaryUnitFound, ref SByte prefixExponent, ref SByte prefixedUnitExponentScaleing,
  3694. ref SByte multExponent, ref Boolean changedExponentSign)
  3695. {
  3696. foreach (IPrefixedUnitExponent ue in inPuel)
  3697. {
  3698. if (!primaryUnitFound && prefixedUnitExponent.Unit.Equals(ue.Unit))
  3699. {
  3700. primaryUnitFound = true;
  3701. if (!prefixExponent.Equals(ue.Prefix.Exponent))
  3702. { // Convert prefixedUnitExponent to have same PrefixExponent as ue; Move difference in scaling to prefixedUnitExponentScaleing
  3703. prefixedUnitExponentScaleing = (SByte)((ue.Prefix.Exponent - prefixExponent) * multExponent);
  3704. prefixExponent = ue.Prefix.Exponent;
  3705. }
  3706. // Reduce the found CombinedUnit exponent with ue2´s exponent;
  3707. SByte newExponent = cef(ue.Exponent, multExponent);
  3708. if (newExponent > 0)
  3709. {
  3710. PrefixedUnitExponent temp_pue = new PrefixedUnitExponent(ue.Prefix, ue.Unit, newExponent);
  3711. outPuel1.Add(temp_pue);
  3712. // Done
  3713. }
  3714. else
  3715. { // Convert to opposite Numerator/Denominator
  3716. multExponent = cef(0, newExponent);
  3717. changedExponentSign = true;
  3718. }
  3719. }
  3720. else
  3721. {
  3722. outPuel1.Add(ue);
  3723. }
  3724. }
  3725. }
  3726. public override Unit Multiply(IPrefixedUnitExponent prefixedUnitExponent)
  3727. {
  3728. Debug.Assert(prefixedUnitExponent != null);
  3729. if (prefixedUnitExponent.Unit.Kind == UnitKind.CombinedUnit)
  3730. {
  3731. CombinedUnit cue = ((CombinedUnit)(prefixedUnitExponent.Unit));
  3732. if (prefixedUnitExponent.Prefix.Exponent != 0)
  3733. {
  3734. IPrefixedUnitExponent temp_pue = new PrefixedUnitExponent(prefixedUnitExponent.Prefix, null, 1);
  3735. cue = cue.CombineMultiply(temp_pue);
  3736. }
  3737. cue = cue.CombinePow(prefixedUnitExponent.Exponent);
  3738. CombinedUnit unit = this.CombineMultiply(cue);
  3739. return unit;
  3740. }
  3741. SByte multExponent = prefixedUnitExponent.Exponent;
  3742. SByte prefixExponent = prefixedUnitExponent.Prefix.Exponent;
  3743. SByte prefixedUnitExponentScaleing = 1;
  3744. IPrefixedUnitExponentList tempNumerators = new PrefixedUnitExponentList();
  3745. IPrefixedUnitExponentList tempDenominators = new PrefixedUnitExponentList();
  3746. Boolean primaryUnitFound = false;
  3747. Boolean changedExponentSign = false;
  3748. //// Check if pue2.Unit is already among our Numerators or Denominators
  3749. MultiplyPUEL(prefixedUnitExponent, SByte_Sub, Denominators, ref tempDenominators,
  3750. ref primaryUnitFound, ref prefixExponent, ref prefixedUnitExponentScaleing,
  3751. ref multExponent, ref changedExponentSign);
  3752. MultiplyPUEL(prefixedUnitExponent, SByte_Add, Numerators, ref tempNumerators,
  3753. ref primaryUnitFound, ref prefixExponent, ref prefixedUnitExponentScaleing,
  3754. ref multExponent, ref changedExponentSign);
  3755. if (!primaryUnitFound || changedExponentSign)
  3756. { // pue2.Unit is not among our Numerators or Denominators (or has changed from Numerators to Denominators)
  3757. if (multExponent > 0)
  3758. {
  3759. PrefixedUnitExponent temp_pue = new PrefixedUnitExponent(prefixedUnitExponent.Prefix, prefixedUnitExponent.Unit, multExponent);
  3760. tempNumerators.Add(temp_pue);
  3761. }
  3762. else if (multExponent < 0)
  3763. {
  3764. multExponent = (SByte)(-multExponent);
  3765. PrefixedUnitExponent temp_pue = new PrefixedUnitExponent(prefixedUnitExponent.Prefix, prefixedUnitExponent.Unit, multExponent);
  3766. tempDenominators.Add(temp_pue);
  3767. }
  3768. }
  3769. CombinedUnit cu = new CombinedUnit(tempNumerators, tempDenominators);
  3770. return cu;
  3771. }
  3772. public override Unit Divide(IPrefixedUnitExponent prefixedUnitExponent)
  3773. {
  3774. Debug.Assert(prefixedUnitExponent != null);
  3775. SByte newExponent = (SByte)(-prefixedUnitExponent.Exponent);
  3776. PrefixedUnitExponent temp_pue = new PrefixedUnitExponent(prefixedUnitExponent.Prefix, prefixedUnitExponent.Unit, newExponent);
  3777. return temp_pue;
  3778. }
  3779. public override Quantity Multiply(double quantity) => this * quantity;
  3780. public override Quantity Divide(double quantity) => this / quantity;
  3781. public override Unit Power(SByte exponent) => new CombinedUnit(Numerators.Power(exponent), Denominators.Power(exponent));
  3782. public override Unit Root(SByte exponent)
  3783. {
  3784. IPrefixedUnitExponentList tempNumerators;
  3785. IPrefixedUnitExponentList tempDenominators = null;
  3786. tempNumerators = Numerators.Root(exponent);
  3787. if (tempNumerators != null)
  3788. {
  3789. tempDenominators = Denominators.Root(exponent);
  3790. }
  3791. if ((tempNumerators != null) && (tempDenominators != null))
  3792. {
  3793. CombinedUnit cu = new CombinedUnit(tempNumerators, tempDenominators);
  3794. return cu;
  3795. }
  3796. else
  3797. {
  3798. SByte[] newExponents = this.Exponents;
  3799. if (newExponents != null)
  3800. {
  3801. newExponents = newExponents.Root(exponent);
  3802. Debug.Assert(this.ExponentsSystem != null);
  3803. DerivedUnit du = new DerivedUnit(this.ExponentsSystem, newExponents);
  3804. return du;
  3805. }
  3806. else
  3807. {
  3808. Debug.Assert(newExponents != null);
  3809. //if (throwExceptionOnUnitMathError) {
  3810. throw new PhysicalUnitMathException("The result of the math operation on the Unit argument can't be represented by this implementation of PhysicalMeasure: (" + this.ToPrintString() + ").Root(" + exponent.ToString() + ")");
  3811. //}
  3812. //return null;
  3813. }
  3814. }
  3815. }
  3816. #endregion IPhysicalUnitMath Members
  3817. #region Combine IPhysicalUnitMath Members
  3818. public override CombinedUnit CombineMultiply(double quantity)
  3819. {
  3820. Double factor = this.FactorValue * quantity;
  3821. CombinedUnit result = new CombinedUnit(factor, this.Numerators, this.Denominators);
  3822. return result;
  3823. }
  3824. public override CombinedUnit CombineDivide(double quantity)
  3825. {
  3826. Double factor = this.FactorValue / quantity;
  3827. CombinedUnit result = new CombinedUnit(factor, this.Numerators, this.Denominators);
  3828. return result;
  3829. }
  3830. public override CombinedUnit CombineMultiply(IUnitPrefixExponent prefixExponent) => this.CombineMultiply(prefixExponent.Value);
  3831. public override CombinedUnit CombineDivide(IUnitPrefixExponent prefixExponent) => this.CombineDivide(prefixExponent.Value);
  3832. private void CombineFactorPUEL(IPrefixedUnitExponent prefixedUnitExponent, CombineExponentsFunc cef, IPrefixedUnitExponentList inPuel, ref IPrefixedUnitExponentList outPuel1, ref IPrefixedUnitExponentList outPuel2,
  3833. ref Boolean primaryUnitFound, ref SByte pue_prefixExp, ref sbyte scalingPrefixExponent, ref SByte scalingExponent,
  3834. ref SByte multPrefixExponent, ref SByte multExponent, ref Boolean ChangedExponentSign)
  3835. {
  3836. foreach (IPrefixedUnitExponent ue in inPuel)
  3837. {
  3838. if (!primaryUnitFound && prefixedUnitExponent.Unit != null && ue.Unit != null && prefixedUnitExponent.Unit.Equals(ue.Unit))
  3839. {
  3840. primaryUnitFound = true;
  3841. // Reduce the found CombinedUnit exponent with ue2´s exponent;
  3842. SByte newExponent = (SByte)(cef(ue.Exponent, prefixedUnitExponent.Exponent));
  3843. SByte ue_prefixExp = 0; // 10^0 = 1
  3844. if (ue.Prefix != null)
  3845. {
  3846. ue_prefixExp = ue.Prefix.Exponent;
  3847. }
  3848. if (!pue_prefixExp.Equals(ue_prefixExp))
  3849. { // Convert prefixedUnitExponent to have same PrefixExponent as ue; Move difference in scaling to prefixedUnitExponentScaleing
  3850. scalingPrefixExponent = (SByte)(pue_prefixExp - ue_prefixExp);
  3851. scalingExponent = prefixedUnitExponent.Exponent;
  3852. }
  3853. if (newExponent > 0)
  3854. { // Still some exponent left for a denominator element
  3855. PrefixedUnitExponent temp_pue = new PrefixedUnitExponent(ue.Prefix, ue.Unit, newExponent);
  3856. outPuel1.Add(temp_pue);
  3857. // Done
  3858. }
  3859. else
  3860. if (newExponent< 0)
  3861. { // Convert to Numerator
  3862. multPrefixExponent = ue.Prefix.Exponent;
  3863. multExponent = (SByte)(-newExponent);
  3864. ChangedExponentSign = true;
  3865. }
  3866. }
  3867. else
  3868. {
  3869. if (ue.Exponent > 0)
  3870. {
  3871. outPuel1.Add(ue);
  3872. }
  3873. else
  3874. {
  3875. outPuel2.Add(new PrefixedUnitExponent(ue.Prefix, ue.Unit, (SByte)(-ue.Exponent)));
  3876. }
  3877. }
  3878. }
  3879. }
  3880. public override CombinedUnit CombineMultiply(PrefixedUnitExponent prefixedUnitExponent)
  3881. {
  3882. Debug.Assert(prefixedUnitExponent != null);
  3883. if (prefixedUnitExponent.Unit != null && prefixedUnitExponent.Unit.Kind == UnitKind.CombinedUnit)
  3884. {
  3885. CombinedUnit cue = ((CombinedUnit)(prefixedUnitExponent.Unit));
  3886. if (prefixedUnitExponent.Prefix.Exponent != 0)
  3887. {
  3888. IPrefixedUnitExponent temp_pue = new PrefixedUnitExponent(prefixedUnitExponent.Prefix, null, 1);
  3889. cue = cue.CombineMultiply(temp_pue);
  3890. }
  3891. cue = cue.CombinePow(prefixedUnitExponent.Exponent);
  3892. CombinedUnit unit = this.CombineMultiply(cue);
  3893. return unit;
  3894. }
  3895. SByte multPrefixExponent = 0; // 10^0 = 1
  3896. SByte multExponent = 1;
  3897. SByte scalingPrefixExponent = 0; // 10^0 = 1
  3898. SByte scalingExponent = 1;
  3899. SByte pue_prefixExp = 0; // 10^0 = 1
  3900. if (prefixedUnitExponent.Prefix != null)
  3901. {
  3902. pue_prefixExp = prefixedUnitExponent.Prefix.Exponent;
  3903. }
  3904. IPrefixedUnitExponentList tempNumerators = new PrefixedUnitExponentList();
  3905. IPrefixedUnitExponentList tempDenominators = new PrefixedUnitExponentList();
  3906. Boolean primaryUnitFound = false;
  3907. Boolean changedExponentSign = false;
  3908. CombineFactorPUEL(prefixedUnitExponent, SByte_Sub, Denominators, ref tempDenominators, ref tempNumerators,
  3909. ref primaryUnitFound, ref pue_prefixExp, ref scalingPrefixExponent, ref scalingExponent,
  3910. ref multPrefixExponent, ref multExponent, ref changedExponentSign);
  3911. CombineFactorPUEL(prefixedUnitExponent, SByte_Add, Numerators, ref tempNumerators, ref tempDenominators,
  3912. ref primaryUnitFound, ref pue_prefixExp, ref scalingPrefixExponent, ref scalingExponent,
  3913. ref multPrefixExponent, ref multExponent, ref changedExponentSign);
  3914. if (!primaryUnitFound || changedExponentSign)
  3915. {
  3916. if (!primaryUnitFound)
  3917. {
  3918. if (prefixedUnitExponent.Prefix != null)
  3919. {
  3920. multPrefixExponent = prefixedUnitExponent.Prefix.Exponent;
  3921. }
  3922. multExponent = prefixedUnitExponent.Exponent;
  3923. }
  3924. IUnitPrefix unitPrefix = null;
  3925. SByte restMultPrefixExponent = 0;
  3926. if (multPrefixExponent != 0)
  3927. {
  3928. Physics.UnitPrefixes.GetFloorUnitPrefixAndScaleFactorFromExponent(multPrefixExponent, out unitPrefix, out restMultPrefixExponent);
  3929. multPrefixExponent = restMultPrefixExponent;
  3930. }
  3931. if (multExponent > 0)
  3932. {
  3933. PrefixedUnitExponent temp_pue = new PrefixedUnitExponent(unitPrefix, prefixedUnitExponent.Unit, multExponent);
  3934. tempNumerators.Add(temp_pue);
  3935. }
  3936. else if (multExponent < 0)
  3937. {
  3938. PrefixedUnitExponent temp_pue = new PrefixedUnitExponent(unitPrefix, prefixedUnitExponent.Unit, (SByte)(-multExponent));
  3939. tempDenominators.Add(temp_pue);
  3940. }
  3941. }
  3942. Double resScaleFactor = scaleFactor;
  3943. if (scalingPrefixExponent != 0 && scalingExponent != 0)
  3944. { // Add scaling factor without unit
  3945. sbyte exp = (sbyte)(scalingPrefixExponent * scalingExponent);
  3946. resScaleFactor = scaleFactor * Math.Pow(10, exp);
  3947. }
  3948. CombinedUnit cu = new CombinedUnit(resScaleFactor, tempNumerators, tempDenominators);
  3949. return cu;
  3950. }
  3951. public override CombinedUnit CombineDivide(PrefixedUnitExponent prefixedUnitExponent)
  3952. {
  3953. Debug.Assert(prefixedUnitExponent != null);
  3954. SByte newExponent = (SByte)(-prefixedUnitExponent.Exponent);
  3955. IPrefixedUnitExponent temp_pue = new PrefixedUnitExponent(prefixedUnitExponent.Prefix, prefixedUnitExponent.Unit, newExponent);
  3956. return this.CombineMultiply(temp_pue);
  3957. }
  3958. public override CombinedUnit CombineMultiply(PrefixedUnit prefixedUnit)
  3959. {
  3960. CombinedUnit result = this.CombineMultiply((IPrefixedUnitExponent)new PrefixedUnitExponent(prefixedUnit.Prefix, prefixedUnit.Unit, 1));
  3961. return result;
  3962. }
  3963. public override CombinedUnit CombineDivide(PrefixedUnit prefixedUnit)
  3964. {
  3965. CombinedUnit result = this.CombineMultiply((IPrefixedUnitExponent)new PrefixedUnitExponent(prefixedUnit.Prefix, prefixedUnit.Unit, -1));
  3966. return result;
  3967. }
  3968. public override CombinedUnit CombineMultiply(BaseUnit physicalUnit) => this.CombineMultiply((IPrefixedUnitExponent)new PrefixedUnitExponent(null, physicalUnit, 1));
  3969. public override CombinedUnit CombineDivide(BaseUnit physicalUnit) => this.CombineMultiply((IPrefixedUnitExponent)new PrefixedUnitExponent(null, physicalUnit, -1));
  3970. public override CombinedUnit CombineMultiply(NamedDerivedUnit physicalUnit) => this.CombineMultiply((IPrefixedUnitExponent)new PrefixedUnitExponent(null, physicalUnit, 1));
  3971. public override CombinedUnit CombineDivide(NamedDerivedUnit physicalUnit) => this.CombineMultiply((IPrefixedUnitExponent)new PrefixedUnitExponent(null, physicalUnit, -1));
  3972. public override CombinedUnit CombineMultiply(ConvertibleUnit physicalUnit) => this.CombineMultiply((IPrefixedUnitExponent)new PrefixedUnitExponent(null, physicalUnit, 1));
  3973. public override CombinedUnit CombineDivide(ConvertibleUnit physicalUnit) => this.CombineMultiply((IPrefixedUnitExponent)new PrefixedUnitExponent(null, physicalUnit, -1));
  3974. public override CombinedUnit CombineMultiply(INamedSymbolUnit namedSymbolUnit)
  3975. {
  3976. CombinedUnit result = this.CombineMultiply((IPrefixedUnitExponent)new PrefixedUnitExponent(null, namedSymbolUnit, 1));
  3977. return result;
  3978. }
  3979. public override CombinedUnit CombineDivide(INamedSymbolUnit namedSymbolUnit)
  3980. {
  3981. CombinedUnit result = this.CombineMultiply((IPrefixedUnitExponent)new PrefixedUnitExponent(null, namedSymbolUnit, -1));
  3982. return result;
  3983. }
  3984. public override CombinedUnit CombineMultiply(Unit physicalUnit)
  3985. {
  3986. if (physicalUnit.Kind == UnitKind.CombinedUnit)
  3987. {
  3988. CombinedUnit cu = physicalUnit as CombinedUnit;
  3989. Debug.Assert(cu != null);
  3990. return this.CombineMultiply(cu);
  3991. }
  3992. if (physicalUnit.Kind == UnitKind.BaseUnit || physicalUnit.Kind == UnitKind.ConvertibleUnit)
  3993. {
  3994. INamedSymbolUnit nsu = physicalUnit as INamedSymbolUnit;
  3995. Debug.Assert(nsu != null);
  3996. return this.CombineMultiply(new PrefixedUnitExponent(null, nsu, 1));
  3997. }
  3998. if (physicalUnit.Kind == UnitKind.MixedUnit)
  3999. {
  4000. MixedUnit mu = physicalUnit as MixedUnit;
  4001. Debug.Assert(mu != null);
  4002. return this.CombineMultiply(mu.MainUnit);
  4003. }
  4004. if (physicalUnit.Kind == UnitKind.DerivedUnit)
  4005. {
  4006. DerivedUnit du = physicalUnit as DerivedUnit;
  4007. Debug.Assert(du != null);
  4008. return this.CombineMultiply(du);
  4009. }
  4010. if (physicalUnit.Kind == UnitKind.PrefixedUnit)
  4011. {
  4012. PrefixedUnit pu = physicalUnit as PrefixedUnit;
  4013. Debug.Assert(pu != null);
  4014. return this.CombineMultiply(pu);
  4015. }
  4016. if (physicalUnit.Kind == UnitKind.PrefixedUnitExponent)
  4017. {
  4018. PrefixedUnitExponent pue = physicalUnit as PrefixedUnitExponent;
  4019. Debug.Assert(pue != null);
  4020. return this.CombineMultiply(pue);
  4021. }
  4022. // PrefixedUnitExponent will not accept an IUnit: return this.CombinedUnitMultiply(new PrefixedUnitExponent(null, physicalUnit, 1));
  4023. // Will make recursive call without reduction: return this.CombinedUnitMultiply(physicalUnit);
  4024. //return this.CombinedUnitMultiply(new PrefixedUnitExponent(null, physicalUnit, 1));
  4025. // Just try to use as INamedSymbolUnit
  4026. INamedSymbolUnit nsu2 = physicalUnit as INamedSymbolUnit;
  4027. Debug.Assert(nsu2 != null);
  4028. return this.CombineMultiply(nsu2);
  4029. }
  4030. public override CombinedUnit CombineDivide(Unit physicalUnit)
  4031. {
  4032. if (physicalUnit.Kind == UnitKind.CombinedUnit)
  4033. {
  4034. CombinedUnit cu = physicalUnit as CombinedUnit;
  4035. Debug.Assert(cu != null);
  4036. return this.CombineDivide(cu);
  4037. }
  4038. if (physicalUnit.Kind == UnitKind.BaseUnit || physicalUnit.Kind == UnitKind.ConvertibleUnit
  4039. || (physicalUnit.Kind == UnitKind.DerivedUnit && physicalUnit as INamedSymbolUnit != null))
  4040. {
  4041. INamedSymbolUnit nsu = physicalUnit as INamedSymbolUnit;
  4042. Debug.Assert(nsu != null);
  4043. return this.CombineDivide((IPrefixedUnitExponent)new PrefixedUnitExponent(null, nsu, 1));
  4044. }
  4045. if (physicalUnit.Kind == UnitKind.MixedUnit)
  4046. {
  4047. IMixedUnit mu = physicalUnit as IMixedUnit;
  4048. Debug.Assert(mu != null);
  4049. return this.CombineDivide(mu.MainUnit);
  4050. }
  4051. if (physicalUnit.Kind == UnitKind.DerivedUnit)
  4052. {
  4053. DerivedUnit du = physicalUnit as DerivedUnit;
  4054. Debug.Assert(du != null);
  4055. return this.CombineDivide(du);
  4056. }
  4057. if (physicalUnit.Kind == UnitKind.PrefixedUnit)
  4058. {
  4059. IPrefixedUnit pu = physicalUnit as IPrefixedUnit;
  4060. Debug.Assert(pu != null);
  4061. return this.CombineDivide(pu);
  4062. }
  4063. if (physicalUnit.Kind == UnitKind.PrefixedUnitExponent)
  4064. {
  4065. PrefixedUnitExponent pue = physicalUnit as PrefixedUnitExponent;
  4066. Debug.Assert(pue != null);
  4067. return this.CombineDivide(pue);
  4068. }
  4069. // PrefixedUnitExponent will not accept an IUnit: return this.CombinedUnitDivide(new PrefixedUnitExponent(null, physicalUnit, 1));
  4070. // Will make recursive call without reduction: return this.CombinedUnitDivide(physicalUnit);
  4071. // return this.CombinedUnitDivide(new PrefixedUnitExponent(null, physicalUnit, 1));
  4072. // Just try to use as INamedSymbolUnit
  4073. INamedSymbolUnit nsu2 = physicalUnit as INamedSymbolUnit;
  4074. Debug.Assert(nsu2 != null);
  4075. return this.CombineDivide(nsu2);
  4076. }
  4077. public override CombinedUnit CombineMultiply(IUnit physicalUnit)
  4078. {
  4079. Unit pu = (Unit)physicalUnit;
  4080. Debug.Assert((pu != null) == (physicalUnit != null));
  4081. CombinedUnit result = this.CombineMultiply(pu);
  4082. return result;
  4083. }
  4084. public override CombinedUnit CombineDivide(IUnit physicalUnit)
  4085. {
  4086. Unit pu = (Unit)physicalUnit;
  4087. Debug.Assert((pu != null) == (physicalUnit != null));
  4088. CombinedUnit result = this.CombineDivide(pu);
  4089. return result;
  4090. }
  4091. public CombinedUnit CombineMultiply(IDerivedUnit derivedUnit)
  4092. {
  4093. CombinedUnit result = new CombinedUnit(this);
  4094. int baseUnitIndex = 0;
  4095. IUnitSystem sys = derivedUnit.ExponentsSystem;
  4096. foreach (SByte exp in derivedUnit.Exponents)
  4097. {
  4098. if (exp != 0)
  4099. {
  4100. result = result.CombineMultiply((IPrefixedUnitExponent)new PrefixedUnitExponent(null, sys.BaseUnits[baseUnitIndex], exp));
  4101. }
  4102. baseUnitIndex++;
  4103. }
  4104. return result;
  4105. }
  4106. public CombinedUnit CombineDivide(IDerivedUnit derivedUnit)
  4107. {
  4108. CombinedUnit result = new CombinedUnit(this);
  4109. int baseUnitIndex = 0;
  4110. IUnitSystem sys = derivedUnit.ExponentsSystem;
  4111. foreach (SByte exp in derivedUnit.Exponents)
  4112. {
  4113. if (exp != 0)
  4114. {
  4115. result = result.CombineDivide((IPrefixedUnitExponent)new PrefixedUnitExponent(null, sys.BaseUnits[baseUnitIndex], exp));
  4116. }
  4117. baseUnitIndex++;
  4118. }
  4119. return result;
  4120. }
  4121. protected void CombineExponentPUEL(SByte exponent, CombineExponentsFunc cef, IPrefixedUnitExponentList inPuel, ref IPrefixedUnitExponentList outPuel1, ref IPrefixedUnitExponentList outPuel2)
  4122. {
  4123. foreach (IPrefixedUnitExponent ue in inPuel)
  4124. {
  4125. SByte NewExponent = (SByte)(cef(ue.Exponent , exponent));
  4126. if (NewExponent > 0)
  4127. {
  4128. PrefixedUnitExponent temp_pue = new PrefixedUnitExponent(ue.Prefix, ue.Unit, NewExponent);
  4129. outPuel1.Add(temp_pue);
  4130. }
  4131. if (NewExponent< 0)
  4132. {
  4133. PrefixedUnitExponent temp_pue = new PrefixedUnitExponent(ue.Prefix, ue.Unit, (sbyte)(-NewExponent));
  4134. outPuel2.Add(temp_pue);
  4135. }
  4136. }
  4137. }
  4138. public override CombinedUnit CombinePow(SByte exponent)
  4139. {
  4140. if (exponent == 1)
  4141. {
  4142. return this;
  4143. }
  4144. else
  4145. {
  4146. IPrefixedUnitExponentList tempNumerators = new PrefixedUnitExponentList();
  4147. IPrefixedUnitExponentList tempDenominators = new PrefixedUnitExponentList();
  4148. CombineExponentPUEL(exponent, SByte_Mult, Numerators, ref tempNumerators, ref tempDenominators);
  4149. CombineExponentPUEL(exponent, SByte_Mult, Denominators, ref tempDenominators, ref tempNumerators);
  4150. CombinedUnit cu = new CombinedUnit(tempNumerators, tempDenominators);
  4151. return cu;
  4152. }
  4153. }
  4154. public override CombinedUnit CombineRot(SByte exponent)
  4155. {
  4156. if (exponent == 1)
  4157. {
  4158. return this;
  4159. }
  4160. else
  4161. {
  4162. IPrefixedUnitExponentList tempNumerators = new PrefixedUnitExponentList();
  4163. IPrefixedUnitExponentList tempDenominators = new PrefixedUnitExponentList();
  4164. CombineExponentPUEL(exponent, SByte_Div, Numerators, ref tempNumerators, ref tempDenominators);
  4165. CombineExponentPUEL(exponent, SByte_Div, Denominators, ref tempDenominators, ref tempNumerators);
  4166. CombinedUnit cu = new CombinedUnit(tempNumerators, tempDenominators);
  4167. return cu;
  4168. }
  4169. }
  4170. public CombinedUnit CombineMultiply(ICombinedUnit cu2)
  4171. {
  4172. if (this.IsDimensionless)
  4173. {
  4174. return cu2.CombineMultiply(this.FactorValue);
  4175. }
  4176. CombinedUnit cu1 = new CombinedUnit(this.FactorValue * cu2.FactorValue, this.Numerators, this.Denominators);
  4177. foreach (IPrefixedUnitExponent pue in cu2.Numerators)
  4178. {
  4179. cu1 = cu1.CombineMultiply(pue);
  4180. }
  4181. foreach (IPrefixedUnitExponent pue in cu2.Denominators)
  4182. {
  4183. cu1 = cu1.CombineDivide(pue);
  4184. }
  4185. return cu1;
  4186. }
  4187. public CombinedUnit CombineDivide(ICombinedUnit cu2)
  4188. {
  4189. CombinedUnit cu1 = new CombinedUnit(this.FactorValue / cu2.FactorValue, this.Numerators, this.Denominators);
  4190. foreach (IPrefixedUnitExponent pue in cu2.Numerators)
  4191. {
  4192. cu1 = cu1.CombineDivide(pue);
  4193. }
  4194. foreach (IPrefixedUnitExponent pue in cu2.Denominators)
  4195. {
  4196. cu1 = cu1.CombineMultiply(pue);
  4197. }
  4198. return cu1;
  4199. }
  4200. #endregion IPhysicalUnitMath Members
  4201. #region IEquatable<IPhysicalUnit> Members
  4202. public override Int32 GetHashCode() => numerators.GetHashCode() + denominators.GetHashCode();
  4203. public override Boolean Equals(object other)
  4204. {
  4205. if (other == null)
  4206. return false;
  4207. Unit otherIPU = other as Unit;
  4208. if (otherIPU == null)
  4209. return false;
  4210. return this.Equals(otherIPU);
  4211. }
  4212. #endregion IEquatable<IPhysicalUnit> Members
  4213. /// <summary>
  4214. /// String with PrefixedUnitExponent formatted symbol (without system name prefixed).
  4215. /// </summary>
  4216. public override String PureUnitString() => CombinedUnitString(mayUseSlash: true, invertExponents: false);
  4217. public override String CombinedUnitString(Boolean mayUseSlash = true, Boolean invertExponents = false)
  4218. {
  4219. String unitName = "";
  4220. Boolean nextLevelMayUseSlash = mayUseSlash && Denominators.Count == 0;
  4221. if (Numerators.Count > 0)
  4222. {
  4223. unitName = Numerators.CombinedUnitString(nextLevelMayUseSlash, invertExponents);
  4224. }
  4225. else
  4226. {
  4227. if (Denominators.Count > 0)
  4228. {
  4229. //UnitName = "1";
  4230. }
  4231. }
  4232. if (Denominators.Count > 0)
  4233. {
  4234. if (mayUseSlash && !String.IsNullOrWhiteSpace(unitName))
  4235. {
  4236. unitName += "/" + Denominators.CombinedUnitString(false, invertExponents);
  4237. }
  4238. else
  4239. {
  4240. if (!String.IsNullOrWhiteSpace(unitName))
  4241. {
  4242. // center dot '\0x0B7' (Char)183 U+00B7
  4243. unitName += '·' + Denominators.CombinedUnitString(false, !invertExponents);
  4244. }
  4245. else
  4246. {
  4247. unitName = Denominators.CombinedUnitString(false, !invertExponents);
  4248. }
  4249. }
  4250. }
  4251. return unitName;
  4252. }
  4253. public override String ToString() => UnitString();
  4254. }
  4255. #endregion Combined Unit Classes
  4256. #region Mixed Unit Classes
  4257. public class MixedUnit : Unit, IMixedUnit
  4258. {
  4259. protected readonly Unit mainUnit;
  4260. protected readonly Unit fractionalUnit;
  4261. protected readonly String separator;
  4262. protected readonly String fractionalValueFormat;
  4263. protected readonly Boolean inlineUnitFormat;
  4264. public Unit MainUnit
  4265. {
  4266. get
  4267. {
  4268. Debug.Assert(mainUnit != null);
  4269. return this.mainUnit;
  4270. }
  4271. }
  4272. public Unit FractionalUnit
  4273. {
  4274. get
  4275. {
  4276. Debug.Assert(mainUnit != null);
  4277. return this.fractionalUnit;
  4278. }
  4279. }
  4280. public String Separator
  4281. {
  4282. get
  4283. {
  4284. Debug.Assert(separator != null);
  4285. return this.separator;
  4286. }
  4287. }
  4288. public MixedUnit(Unit someMainUnit, String someSeparator, Unit someFractionalUnit, String someFractionalValueFormat, Boolean someInlineUnitFormat)
  4289. {
  4290. this.mainUnit = someMainUnit;
  4291. this.separator = someSeparator;
  4292. this.fractionalUnit = someFractionalUnit;
  4293. this.fractionalValueFormat = someFractionalValueFormat;
  4294. this.inlineUnitFormat = someInlineUnitFormat;
  4295. }
  4296. public MixedUnit(Unit someMainUnit, String someSeparator, Unit someFractionalUnit, String someFractionalValueFormat)
  4297. : this(someMainUnit, someSeparator, someFractionalUnit, someFractionalValueFormat, false)
  4298. {
  4299. }
  4300. public MixedUnit(Unit someMainUnit, String separator, Unit someFractionalUnit)
  4301. : this(someMainUnit, separator, someFractionalUnit, "00.################")
  4302. {
  4303. }
  4304. public MixedUnit(Unit someMainUnit, Unit someFractionalUnit)
  4305. : this(someMainUnit, ":", someFractionalUnit)
  4306. {
  4307. }
  4308. public override UnitKind Kind => UnitKind.MixedUnit;
  4309. public override IUnitSystem SimpleSystem
  4310. {
  4311. get
  4312. {
  4313. Debug.Assert(mainUnit != null);
  4314. return MainUnit.SimpleSystem;
  4315. }
  4316. set
  4317. {
  4318. Debug.Assert(mainUnit != null);
  4319. /* Just do nothing */
  4320. Debug.Assert(MainUnit.SimpleSystem == value);
  4321. }
  4322. }
  4323. public override IUnitSystem ExponentsSystem
  4324. {
  4325. get
  4326. {
  4327. Debug.Assert(mainUnit != null);
  4328. return MainUnit.ExponentsSystem;
  4329. }
  4330. }
  4331. public override SByte[] Exponents
  4332. {
  4333. get
  4334. {
  4335. Debug.Assert(mainUnit != null);
  4336. return MainUnit.Exponents;
  4337. }
  4338. }
  4339. /// <summary>
  4340. ///
  4341. /// </summary>
  4342. public override Boolean IsLinearConvertible()
  4343. {
  4344. Debug.Assert(mainUnit != null);
  4345. return mainUnit.IsLinearConvertible();
  4346. }
  4347. public override Quantity ConvertToSystemUnit(ref Double value)
  4348. {
  4349. Debug.Assert(mainUnit != null);
  4350. return MainUnit.ConvertToSystemUnit(ref value);
  4351. }
  4352. public override Quantity ConvertToSystemUnit()
  4353. {
  4354. Debug.Assert(mainUnit != null);
  4355. return MainUnit.ConvertToSystemUnit();
  4356. }
  4357. public override Quantity ConvertToBaseUnit() => this.ConvertToBaseUnit(1);
  4358. public override Quantity ConvertToDerivedUnit() => this.ConvertToBaseUnit();
  4359. public override Quantity ConvertToBaseUnit(Double value) => this.ConvertToSystemUnit(ref value).ConvertToBaseUnit();
  4360. public override string PureUnitString()
  4361. {
  4362. Debug.Assert(mainUnit != null);
  4363. string us = MainUnit.UnitString();
  4364. if (FractionalUnit != null)
  4365. {
  4366. us = us + this.Separator + FractionalUnit.UnitString();
  4367. }
  4368. return us;
  4369. }
  4370. public override string ValueString(Double value) => ValueString(value, null, null);
  4371. public override string ValueString(Double value, String format, IFormatProvider formatProvider)
  4372. {
  4373. Debug.Assert(mainUnit != null);
  4374. string valStr;
  4375. if (FractionalUnit == null)
  4376. {
  4377. valStr = MainUnit.ValueString(value, format, formatProvider);
  4378. }
  4379. Double integralValue = Math.Truncate(value);
  4380. Double fractionalValue = value - integralValue;
  4381. Quantity fracPQ = new Quantity(fractionalValue, this.MainUnit);
  4382. Quantity fracPQConv = fracPQ.ConvertTo(this.FractionalUnit);
  4383. if (fracPQConv != null)
  4384. {
  4385. valStr = MainUnit.ValueString(integralValue, format, formatProvider) + separator + FractionalUnit.ValueString(fracPQConv.Value, fractionalValueFormat, null);
  4386. }
  4387. else
  4388. {
  4389. valStr = MainUnit.ValueString(value, format, formatProvider);
  4390. }
  4391. return valStr;
  4392. }
  4393. public override string ValueAndUnitString(double value) => ValueAndUnitString(value, null, null);
  4394. public override string ValueAndUnitString(double value, String format, IFormatProvider formatProvider)
  4395. {
  4396. Debug.Assert(mainUnit != null);
  4397. string resultStr;
  4398. if (FractionalUnit == null)
  4399. {
  4400. resultStr = MainUnit.ValueAndUnitString(value, format, formatProvider);
  4401. return resultStr;
  4402. }
  4403. Double integralValue = Math.Truncate(value);
  4404. Double fractionalValue = value - integralValue;
  4405. Quantity fracPQ = new Quantity(fractionalValue, this.MainUnit);
  4406. Quantity fracPQConv = fracPQ.ConvertTo(this.FractionalUnit);
  4407. if (inlineUnitFormat)
  4408. {
  4409. if (fracPQConv != null)
  4410. {
  4411. resultStr = MainUnit.ValueAndUnitString(integralValue, format, formatProvider)
  4412. + separator
  4413. + FractionalUnit.ValueAndUnitString(fracPQConv.Value, fractionalValueFormat, null);
  4414. }
  4415. else
  4416. {
  4417. resultStr = MainUnit.ValueAndUnitString(value, format, formatProvider);
  4418. }
  4419. return resultStr;
  4420. }
  4421. String valStr;
  4422. if (fracPQConv != null)
  4423. {
  4424. valStr = MainUnit.ValueString(integralValue, format, formatProvider) + separator + FractionalUnit.ValueString(fracPQConv.Value, fractionalValueFormat, null);
  4425. }
  4426. else
  4427. {
  4428. valStr = MainUnit.ValueString(value, format, formatProvider);
  4429. }
  4430. String unitStr = this.ToString();
  4431. if (String.IsNullOrEmpty(unitStr))
  4432. {
  4433. resultStr = valStr;
  4434. }
  4435. else
  4436. {
  4437. resultStr = valStr + " " + unitStr;
  4438. }
  4439. return resultStr;
  4440. }
  4441. }
  4442. #endregion Mixed Unit Classes
  4443. #endregion Physical Unit Classes
  4444. #region Physical Unit System Classes
  4445. public abstract class AbstractUnitSystem : NamedObject, IUnitSystem
  4446. {
  4447. public abstract UnitPrefixTable UnitPrefixes { get; }
  4448. public abstract BaseUnit[] BaseUnits { get; /* */ set; /* */ }
  4449. public abstract NamedDerivedUnit[] NamedDerivedUnits { get; /* */ set; /* */ }
  4450. public abstract ConvertibleUnit[] ConvertibleUnits { get; /* */ set; /* */ }
  4451. public abstract Boolean IsIsolatedUnitSystem { get; }
  4452. public abstract Boolean IsCombinedUnitSystem { get; }
  4453. protected Unit dimensionless;
  4454. public virtual Unit Dimensionless
  4455. {
  4456. get
  4457. {
  4458. if (dimensionless == null)
  4459. {
  4460. dimensionless = new DerivedUnit(this, new SByte[] { 0 });
  4461. }
  4462. return dimensionless;
  4463. }
  4464. }
  4465. public AbstractUnitSystem(String someName)
  4466. : base(someName)
  4467. {
  4468. }
  4469. public override String ToString() => this.Name;
  4470. protected static INamedSymbolUnit UnitFromName(INamedSymbolUnit[] units, String unitname)
  4471. {
  4472. if (units != null)
  4473. {
  4474. foreach (INamedSymbolUnit u in units)
  4475. {
  4476. if (u.Name.Equals(unitname, StringComparison.OrdinalIgnoreCase))
  4477. {
  4478. return u;
  4479. }
  4480. }
  4481. }
  4482. return null;
  4483. }
  4484. protected static INamedSymbolUnit UnitFromSymbol(INamedSymbolUnit[] units, String unitsymbol)
  4485. {
  4486. if (units != null)
  4487. {
  4488. foreach (INamedSymbolUnit u in units)
  4489. {
  4490. // StringComparison must consider case))
  4491. if (u.Symbol.Equals(unitsymbol, StringComparison.Ordinal))
  4492. {
  4493. return u;
  4494. }
  4495. }
  4496. }
  4497. return null;
  4498. }
  4499. public INamedSymbolUnit UnitFromName(String unitName)
  4500. {
  4501. INamedSymbolUnit unit;
  4502. unit = UnitFromName(this.BaseUnits, unitName);
  4503. if (unit != null)
  4504. {
  4505. return unit;
  4506. }
  4507. unit = UnitFromName(this.NamedDerivedUnits, unitName);
  4508. if (unit != null)
  4509. {
  4510. return unit;
  4511. }
  4512. unit = UnitFromName(this.ConvertibleUnits, unitName);
  4513. if (unit != null)
  4514. {
  4515. return unit;
  4516. }
  4517. unit = UnitFromName(Physics.ExtraTimeUnits, unitName);
  4518. return unit;
  4519. }
  4520. public INamedSymbolUnit UnitFromSymbol(String unitSymbol)
  4521. {
  4522. INamedSymbolUnit unit;
  4523. unit = UnitFromSymbol(this.BaseUnits, unitSymbol);
  4524. if (unit != null)
  4525. {
  4526. return unit;
  4527. }
  4528. unit = UnitFromSymbol(this.NamedDerivedUnits, unitSymbol);
  4529. if (unit != null)
  4530. {
  4531. return unit;
  4532. }
  4533. unit = UnitFromSymbol(this.ConvertibleUnits, unitSymbol);
  4534. if (unit != null)
  4535. {
  4536. return unit;
  4537. }
  4538. unit = UnitFromSymbol(Physics.ExtraTimeUnits, unitSymbol);
  4539. return unit;
  4540. }
  4541. public Unit ScaledUnitFromSymbol(String scaledUnitSymbol)
  4542. {
  4543. INamedSymbolUnit symbolUnit = UnitFromSymbol(scaledUnitSymbol);
  4544. if (scaledUnitSymbol.Length > 1)
  4545. { // Check for prefixed unit
  4546. Char prefixchar = scaledUnitSymbol[0];
  4547. IUnitPrefix unitPrefix;
  4548. if (UnitPrefixes.GetUnitPrefixFromPrefixChar(prefixchar, out unitPrefix))
  4549. {
  4550. INamedSymbolUnit symbolUnit2 = UnitFromSymbol(scaledUnitSymbol.Substring(1));
  4551. if (symbolUnit2 != null)
  4552. { // Found both a prefix and an unit; Must be the right unit.
  4553. if (symbolUnit != null)
  4554. {
  4555. // symbolUnit = SI.Kg <-> symbolUnit2 = SI_prefix.K·SI.g Prefer (non-prefixed) symbolUnit, discharged symbolUnit2
  4556. // symbolUnit = SI.K (Kelvin) <-> symbolUnit2 = SI_prefix.K·... Prefer (prefixed) symbolUnit2, discharged symbolUnit
  4557. if (ReferenceEquals(symbolUnit, SI.Kg) && prefixchar == 'K' && ReferenceEquals(symbolUnit2, SI.g))
  4558. { // Prefer (non-prefixed) symbolUnit, discharged symbolUnit2
  4559. //Debug.Assert(symbolUnit == null); // For debug. Manually check if the discharged symbolUnit2 is a better choice than the returned symbolUnit.
  4560. return (Unit)symbolUnit;
  4561. }
  4562. // Prefer (prefixed) symbolUnit2, discharged symbolUnit
  4563. // Discharged symbolUnit even if set by non-prefixed unit (first call to UnitFromSymbol())
  4564. Debug.Assert(symbolUnit == null); // For debug. Manually check if the discharged symbolUnit could be a better choice than the returned symbolUnit2.
  4565. }
  4566. // Found both a prefix and an unit; Must be the right unit.
  4567. Debug.Assert(unitPrefix != null); // GetUnitPrefixFromPrefixChar must have returned a valid unitPrefix.
  4568. Unit pu = new PrefixedUnit(unitPrefix, symbolUnit2);
  4569. return pu;
  4570. }
  4571. }
  4572. }
  4573. return (Unit)symbolUnit;
  4574. }
  4575. public Unit UnitFromExponents(SByte[] exponents)
  4576. {
  4577. SByte noOfNonZeroExponents = 0;
  4578. SByte noOfNonOneExponents = 0;
  4579. SByte firstNonZeroExponent = -1;
  4580. SByte i = 0;
  4581. foreach (SByte exponent in exponents)
  4582. {
  4583. if (exponent != 0)
  4584. {
  4585. if (firstNonZeroExponent == -1)
  4586. {
  4587. firstNonZeroExponent = i;
  4588. }
  4589. noOfNonZeroExponents++;
  4590. if (exponent != 1)
  4591. {
  4592. noOfNonOneExponents++;
  4593. }
  4594. }
  4595. i++;
  4596. }
  4597. return UnitFromUnitInfo(exponents, noOfNonZeroExponents, noOfNonOneExponents, firstNonZeroExponent);
  4598. }
  4599. public Unit UnitFromUnitInfo(SByte[] exponents, SByte noOfNonZeroExponents, SByte noOfNonOneExponents, SByte firstNonZeroExponent)
  4600. {
  4601. Unit unit;
  4602. if ((noOfNonZeroExponents == 1) && (noOfNonOneExponents == 0))
  4603. {
  4604. // BaseUnit
  4605. unit = (Unit)BaseUnits[firstNonZeroExponent];
  4606. }
  4607. else
  4608. {
  4609. // Check if it is a NamedDerivedUnit
  4610. unit = null;
  4611. if (NamedDerivedUnits != null)
  4612. {
  4613. int namedderivedunitsindex = 0;
  4614. while ((namedderivedunitsindex < NamedDerivedUnits.Length)
  4615. && !NamedDerivedUnits[namedderivedunitsindex].Exponents.DimensionEquals(exponents))
  4616. {
  4617. namedderivedunitsindex++;
  4618. }
  4619. if (namedderivedunitsindex < NamedDerivedUnits.Length)
  4620. {
  4621. // NamedDerivedUnit
  4622. unit = (Unit)NamedDerivedUnits[namedderivedunitsindex];
  4623. }
  4624. }
  4625. if (unit == null)
  4626. {
  4627. // DerivedUnit
  4628. unit = new DerivedUnit(this, exponents);
  4629. }
  4630. }
  4631. return unit;
  4632. }
  4633. public INamedSymbolUnit NamedDerivedUnitFromUnit(IDerivedUnit derivedUnit)
  4634. {
  4635. SByte[] exponents = derivedUnit.Exponents;
  4636. int noOfDimensions = exponents.NoOfDimensions();
  4637. if (noOfDimensions > 1)
  4638. {
  4639. INamedSymbolUnit ns = NamedDerivedUnits.FirstOrNull(namedderivedunit => exponents.DimensionEquals(namedderivedunit.Exponents));
  4640. return ns;
  4641. }
  4642. return null;
  4643. }
  4644. public INamedSymbolUnit NamedDerivedUnitFromUnit(Unit derivedUnit)
  4645. {
  4646. Quantity pq = derivedUnit.ConvertToDerivedUnit();
  4647. if (!Quantity.IsPureUnit(pq))
  4648. {
  4649. Unit unit = Quantity.GetAsNamedUnit(pq);
  4650. return unit as INamedSymbolUnit;
  4651. }
  4652. if (Quantity.IsPureUnit(pq))
  4653. {
  4654. Unit derunit = Quantity.PureUnit(pq);
  4655. SByte[] exponents = derunit.Exponents;
  4656. int noOfDimensions = exponents.NoOfDimensions();
  4657. if (noOfDimensions > 1 && this.NamedDerivedUnits != null)
  4658. {
  4659. foreach (NamedDerivedUnit namedderivedunit in this.NamedDerivedUnits)
  4660. {
  4661. if (exponents.DimensionEquals(namedderivedunit.Exponents))
  4662. {
  4663. return namedderivedunit;
  4664. }
  4665. }
  4666. }
  4667. }
  4668. return null;
  4669. }
  4670. public INamedSymbolUnit this[String unitSymbol] => UnitFromSymbol(unitSymbol);
  4671. public Quantity ConvertTo(Unit convertFromUnit, Unit convertToUnit)
  4672. {
  4673. // Relative conversion is assumed
  4674. // Handle relative unit e.g. temperature interval ....
  4675. Debug.Assert(convertFromUnit != null);
  4676. Debug.Assert(convertToUnit != null);
  4677. if (convertFromUnit == null)
  4678. {
  4679. throw new ArgumentNullException(nameof(convertFromUnit));
  4680. }
  4681. if (convertToUnit == null)
  4682. {
  4683. throw new ArgumentNullException(nameof(convertToUnit));
  4684. }
  4685. Double quotient = 1; // 0 means not equivalent unit
  4686. Boolean isEquivalentUnit = convertFromUnit.Equivalent(convertToUnit, out quotient);
  4687. if (isEquivalentUnit)
  4688. {
  4689. return new Quantity(quotient, convertToUnit);
  4690. }
  4691. else
  4692. {
  4693. if (convertFromUnit.Kind == UnitKind.MixedUnit)
  4694. {
  4695. MixedUnit imu = (MixedUnit)convertFromUnit;
  4696. Quantity pq = ConvertTo(imu.MainUnit, convertToUnit);
  4697. return pq;
  4698. }
  4699. else if (convertToUnit.Kind == UnitKind.MixedUnit)
  4700. {
  4701. MixedUnit imu = (MixedUnit)convertToUnit;
  4702. Quantity pq = ConvertTo(convertFromUnit, imu.MainUnit);
  4703. Debug.Assert(pq != null);
  4704. return new Quantity(pq.Value, convertToUnit);
  4705. }
  4706. else if (convertFromUnit.Kind == UnitKind.ConvertibleUnit)
  4707. {
  4708. ConvertibleUnit icu = (ConvertibleUnit)convertFromUnit;
  4709. Quantity pq_prim = icu.ConvertToPrimaryUnit();
  4710. Quantity pq = pq_prim.Unit.ConvertTo(convertToUnit);
  4711. if (pq != null)
  4712. {
  4713. pq = pq.Multiply(pq_prim.Value);
  4714. }
  4715. return pq;
  4716. }
  4717. else if (convertToUnit.Kind == UnitKind.ConvertibleUnit)
  4718. {
  4719. ConvertibleUnit icu = (ConvertibleUnit)convertToUnit;
  4720. Quantity converted_fromunit = convertFromUnit.ConvertTo(icu.PrimaryUnit);
  4721. if (converted_fromunit != null)
  4722. {
  4723. converted_fromunit = icu.ConvertFromPrimaryUnit(converted_fromunit.Value);
  4724. }
  4725. return converted_fromunit;
  4726. }
  4727. else if (convertFromUnit.Kind == UnitKind.PrefixedUnit)
  4728. {
  4729. PrefixedUnit icu = (PrefixedUnit)convertFromUnit;
  4730. Quantity pq_derivedUnit = icu.ConvertToDerivedUnit();
  4731. Quantity pq = pq_derivedUnit.ConvertTo(convertToUnit);
  4732. return pq;
  4733. }
  4734. else if (convertToUnit.Kind == UnitKind.PrefixedUnit)
  4735. {
  4736. IPrefixedUnit icu = (PrefixedUnit)convertToUnit;
  4737. Quantity pq_unit = convertFromUnit.ConvertTo((Unit)icu.Unit);
  4738. if (pq_unit != null)
  4739. {
  4740. IQuantity pq = pq_unit.Divide(icu.Prefix.Value);
  4741. if (pq != null)
  4742. {
  4743. return new Quantity(pq.Value, convertToUnit);
  4744. }
  4745. }
  4746. return null;
  4747. }
  4748. else if (convertFromUnit.Kind == UnitKind.PrefixedUnitExponent)
  4749. {
  4750. PrefixedUnitExponent pue = (PrefixedUnitExponent)convertFromUnit;
  4751. Quantity pq_derivedUnit = pue.ConvertToDerivedUnit();
  4752. Quantity pq = pq_derivedUnit.ConvertTo(convertToUnit);
  4753. return pq;
  4754. }
  4755. else if (convertToUnit.Kind == UnitKind.PrefixedUnitExponent)
  4756. {
  4757. PrefixedUnitExponent pue = (PrefixedUnitExponent)convertToUnit;
  4758. Quantity pue_derivedUnit = pue.ConvertToDerivedUnit();
  4759. Quantity converted_fromunit = convertFromUnit.ConvertTo(pue_derivedUnit.Unit);
  4760. if (converted_fromunit != null)
  4761. {
  4762. return new Quantity(converted_fromunit.Value / pue_derivedUnit.Value, convertToUnit);
  4763. }
  4764. return null;
  4765. }
  4766. else if (convertFromUnit.Kind == UnitKind.CombinedUnit)
  4767. {
  4768. CombinedUnit icu = (CombinedUnit)convertFromUnit;
  4769. Quantity pq = icu.ConvertTo(convertToUnit);
  4770. return pq;
  4771. }
  4772. else if (convertToUnit.Kind == UnitKind.CombinedUnit)
  4773. {
  4774. CombinedUnit icu = (CombinedUnit)convertToUnit;
  4775. Quantity pqToUnit;
  4776. pqToUnit = icu.ConvertTo(convertFromUnit);
  4777. if (pqToUnit != null)
  4778. {
  4779. Unit pu = convertFromUnit.Divide(pqToUnit.Unit);
  4780. if (pu == null || pu.Exponents.IsDimensionless())
  4781. {
  4782. return new Quantity(1 / pqToUnit.Value, convertToUnit);
  4783. }
  4784. }
  4785. return null;
  4786. }
  4787. // From some simple system to some simple system
  4788. if ((convertFromUnit.SimpleSystem == this) && (convertToUnit.SimpleSystem == this))
  4789. { // Intra unit system conversion
  4790. Debug.Assert((convertFromUnit.Kind == UnitKind.BaseUnit) || (convertFromUnit.Kind == UnitKind.DerivedUnit));
  4791. Debug.Assert((convertToUnit.Kind == UnitKind.BaseUnit) || (convertToUnit.Kind == UnitKind.DerivedUnit));
  4792. if (!((convertFromUnit.Kind == UnitKind.BaseUnit) || (convertFromUnit.Kind == UnitKind.DerivedUnit)))
  4793. {
  4794. throw new ArgumentException("Must have a unit of BaseUnit or DerivedUnit", nameof(convertFromUnit));
  4795. }
  4796. if (!((convertToUnit.Kind == UnitKind.BaseUnit) || (convertToUnit.Kind == UnitKind.DerivedUnit)))
  4797. {
  4798. throw new ArgumentException("Must be a unit of BaseUnit or DerivedUnit", nameof(convertToUnit));
  4799. }
  4800. if (convertFromUnit.Exponents.DimensionEquals(convertToUnit.Exponents))
  4801. {
  4802. return new Quantity(1, convertToUnit);
  4803. }
  4804. }
  4805. else
  4806. { // Inter unit system conversion
  4807. UnitSystemConversion usc = Physics.UnitSystemConversions.GetUnitSystemConversion(convertFromUnit.SimpleSystem, convertToUnit.SimpleSystem);
  4808. if (usc != null)
  4809. {
  4810. return usc.ConvertTo(convertFromUnit, convertToUnit);
  4811. }
  4812. }
  4813. return null;
  4814. }
  4815. }
  4816. public virtual Quantity ConvertTo(Unit convertFromUnit, IUnitSystem convertToUnitSystem)
  4817. {
  4818. Debug.Assert(convertFromUnit != null);
  4819. Debug.Assert(convertToUnitSystem != null);
  4820. IUnitSystem convertFromUnitSystem = convertFromUnit.SimpleSystem;
  4821. if (convertFromUnitSystem == convertToUnitSystem
  4822. || (convertToUnitSystem.IsCombinedUnitSystem && ((CombinedUnitSystem)convertToUnitSystem).ContainsSubUnitSystem(convertFromUnitSystem)))
  4823. {
  4824. return new Quantity(1, convertFromUnit);
  4825. }
  4826. { // Inter unit system conversion
  4827. UnitSystemConversion usc = Physics.UnitSystemConversions.GetUnitSystemConversion(convertFromUnitSystem, convertToUnitSystem);
  4828. if (usc != null)
  4829. {
  4830. return usc.ConvertTo(convertFromUnit.ConvertToBaseUnit(), convertToUnitSystem);
  4831. }
  4832. if (convertFromUnitSystem.IsIsolatedUnitSystem || convertToUnitSystem.IsIsolatedUnitSystem)
  4833. {
  4834. // Unit system declared to be isolated (user defined) without conversion to other (physical) unit systems.
  4835. return null;
  4836. }
  4837. /* Missing unit system conversion from physicalquantity.Unit.System to ToUnitSystem */
  4838. /* TO DO Find intermediate systems with conversions between physicalquantity.Unit.System and convertToUnitSystem */
  4839. Debug.Assert(false, "Missing unit system conversion from " + convertFromUnitSystem.Name + " to " + convertToUnitSystem.Name);
  4840. return null;
  4841. }
  4842. }
  4843. public Quantity ConvertTo(Quantity physicalQuantity, Unit convertToUnit)
  4844. {
  4845. // return RelativeConvertTo(physicalQuantity, convertToUnit);
  4846. // We need to use specific conversion of unit, if either convertFromUnit or convertToUnit are a pure linear scaled unit.
  4847. Boolean physicalQuantityUnitRelativeconversion = physicalQuantity.Unit.IsLinearConvertible();
  4848. Boolean convertToUnitRelativeconversion = convertToUnit.IsLinearConvertible();
  4849. Boolean relativeconversion = physicalQuantityUnitRelativeconversion && convertToUnitRelativeconversion;
  4850. if (relativeconversion)
  4851. {
  4852. Quantity pq = this.ConvertTo(physicalQuantity.Unit, convertToUnit);
  4853. if (pq != null)
  4854. {
  4855. pq = pq.Multiply(physicalQuantity.Value);
  4856. }
  4857. return pq;
  4858. }
  4859. else
  4860. {
  4861. return SpecificConvertTo(physicalQuantity, convertToUnit);
  4862. }
  4863. }
  4864. public Quantity SpecificConvertTo(Quantity physicalQuantity, Unit convertToUnit)
  4865. {
  4866. Debug.Assert(physicalQuantity.Unit != null);
  4867. Debug.Assert(convertToUnit != null);
  4868. if (physicalQuantity.Unit == null)
  4869. {
  4870. throw new ArgumentException("Must have a unit", nameof(physicalQuantity));
  4871. }
  4872. if (convertToUnit == null)
  4873. {
  4874. throw new ArgumentNullException(nameof(convertToUnit));
  4875. }
  4876. if (physicalQuantity.Unit == convertToUnit)
  4877. {
  4878. return physicalQuantity;
  4879. }
  4880. if (physicalQuantity.Unit.SimpleSystem != null && physicalQuantity.Unit.SimpleSystem != this)
  4881. {
  4882. return physicalQuantity.Unit.SimpleSystem.SpecificConvertTo(physicalQuantity, convertToUnit);
  4883. }
  4884. else
  4885. {
  4886. IUnitSystem convertfromunitsystem = physicalQuantity.Unit.SimpleSystem;
  4887. IUnitSystem converttounitsystem = convertToUnit.SimpleSystem;
  4888. if (convertfromunitsystem == null)
  4889. {
  4890. string physicalQuantityUnitKind_debug_trace_str = physicalQuantity.Unit.Kind.ToString();
  4891. string physicalQuantity_debug_trace_str = physicalQuantity.ToPrintString();
  4892. Debug.Assert(physicalQuantity.Unit.Kind == UnitKind.CombinedUnit);
  4893. IUnitSystem tempconverttounitsystem = converttounitsystem;
  4894. if (tempconverttounitsystem == null && (physicalQuantity.Unit.Kind == UnitKind.CombinedUnit))
  4895. { // Find some system to convert into
  4896. ICombinedUnit icu = (ICombinedUnit)physicalQuantity.Unit;
  4897. Debug.Assert(icu != null);
  4898. tempconverttounitsystem = icu.SomeSimpleSystem;
  4899. }
  4900. if (tempconverttounitsystem != null)
  4901. {
  4902. physicalQuantity = physicalQuantity.ConvertTo(tempconverttounitsystem);
  4903. if (physicalQuantity != null)
  4904. {
  4905. convertfromunitsystem = physicalQuantity.Unit.SimpleSystem;
  4906. }
  4907. else
  4908. {
  4909. // ?? What TO DO here ??
  4910. Debug.Assert(false);
  4911. return null;
  4912. }
  4913. }
  4914. else
  4915. {
  4916. // ?? What TO DO here ??
  4917. Debug.Assert(false);
  4918. return null;
  4919. }
  4920. }
  4921. if (converttounitsystem == null)
  4922. {
  4923. Debug.Assert(convertToUnit.Kind == UnitKind.CombinedUnit);
  4924. ICombinedUnit icu = (ICombinedUnit)convertToUnit;
  4925. Debug.Assert(icu != null);
  4926. IUnitSystem tempconverttounitsystem;
  4927. tempconverttounitsystem = icu.SomeSimpleSystem;
  4928. Debug.Assert(tempconverttounitsystem != null);
  4929. // ?? What TO DO here ??
  4930. Debug.Assert(false);
  4931. }
  4932. if (converttounitsystem != null && convertfromunitsystem != converttounitsystem)
  4933. { // Inter unit system conversion
  4934. if (physicalQuantity.Unit.Kind == UnitKind.ConvertibleUnit)
  4935. {
  4936. ConvertibleUnit icu = (ConvertibleUnit)physicalQuantity.Unit;
  4937. Double d = physicalQuantity.Value;
  4938. physicalQuantity = icu.ConvertToSystemUnit(ref d);
  4939. }
  4940. Quantity pq = this.ConvertTo(physicalQuantity, converttounitsystem);
  4941. if (pq != null)
  4942. {
  4943. physicalQuantity = pq;
  4944. convertfromunitsystem = physicalQuantity.Unit.SimpleSystem;
  4945. }
  4946. else
  4947. {
  4948. return null;
  4949. }
  4950. }
  4951. if (convertfromunitsystem != null && convertfromunitsystem == converttounitsystem)
  4952. { // Intra unit system conversion
  4953. if (physicalQuantity.Unit.Kind == UnitKind.MixedUnit)
  4954. {
  4955. MixedUnit imu = (MixedUnit)physicalQuantity.Unit;
  4956. Quantity pq = new Quantity(physicalQuantity.Value, imu.MainUnit);
  4957. pq = pq.ConvertTo(convertToUnit);
  4958. return pq;
  4959. }
  4960. else if (physicalQuantity.Unit.Kind == UnitKind.CombinedUnit)
  4961. {
  4962. CombinedUnit icu = (CombinedUnit)physicalQuantity.Unit;
  4963. Double d = physicalQuantity.Value;
  4964. Quantity pq = icu.ConvertToSystemUnit(ref d);
  4965. Debug.Assert(pq != null);
  4966. pq = pq.ConvertTo(convertToUnit);
  4967. return pq;
  4968. }
  4969. else if (physicalQuantity.Unit.Kind == UnitKind.ConvertibleUnit)
  4970. {
  4971. ConvertibleUnit icu = (ConvertibleUnit)physicalQuantity.Unit;
  4972. Quantity prim_pq = icu.ConvertToPrimaryUnit(physicalQuantity.Value);
  4973. return ConvertTo(prim_pq, convertToUnit);
  4974. }
  4975. else if (convertToUnit.Kind == UnitKind.MixedUnit)
  4976. {
  4977. MixedUnit imu = (MixedUnit)convertToUnit;
  4978. Quantity pq = ConvertTo(physicalQuantity, imu.MainUnit);
  4979. if (pq != null)
  4980. {
  4981. pq = new Quantity(pq.Value, convertToUnit);
  4982. }
  4983. return pq;
  4984. }
  4985. else if (convertToUnit.Kind == UnitKind.CombinedUnit)
  4986. {
  4987. CombinedUnit icu = (CombinedUnit)convertToUnit;
  4988. Quantity pq = icu.ConvertFrom(physicalQuantity);
  4989. return pq;
  4990. }
  4991. else if (convertToUnit.Kind == UnitKind.ConvertibleUnit)
  4992. {
  4993. ConvertibleUnit icu = (ConvertibleUnit)convertToUnit;
  4994. Quantity pq = ConvertTo(physicalQuantity, icu.PrimaryUnit);
  4995. if (pq != null)
  4996. {
  4997. pq = icu.ConvertFromPrimaryUnit(pq.Value);
  4998. }
  4999. return pq;
  5000. }
  5001. Debug.Assert((physicalQuantity.Unit.Kind == UnitKind.BaseUnit) || (physicalQuantity.Unit.Kind == UnitKind.DerivedUnit));
  5002. Debug.Assert((convertToUnit.Kind == UnitKind.BaseUnit) || (convertToUnit.Kind == UnitKind.DerivedUnit));
  5003. if (!((physicalQuantity.Unit.Kind == UnitKind.BaseUnit) || (physicalQuantity.Unit.Kind == UnitKind.DerivedUnit)))
  5004. {
  5005. throw new ArgumentException("Must have a unit of BaseUnit or a DerivedUnit", nameof(physicalQuantity));
  5006. }
  5007. if (!((convertToUnit.Kind == UnitKind.BaseUnit) || (convertToUnit.Kind == UnitKind.DerivedUnit)))
  5008. {
  5009. throw new ArgumentException("Must be a unit of BaseUnit or a DerivedUnit", nameof(convertToUnit));
  5010. }
  5011. if (physicalQuantity.Unit.Exponents.DimensionEquals(convertToUnit.Exponents))
  5012. {
  5013. return new Quantity(physicalQuantity.Value, convertToUnit);
  5014. }
  5015. }
  5016. return null;
  5017. }
  5018. }
  5019. public Quantity ConvertTo(Quantity physicalQuantity, IUnitSystem convertToUnitSystem)
  5020. {
  5021. IUnitSystem convertFromUnitSystem = physicalQuantity.Unit.SimpleSystem;
  5022. if (convertFromUnitSystem == convertToUnitSystem)
  5023. {
  5024. return physicalQuantity;
  5025. }
  5026. if (convertFromUnitSystem.IsIsolatedUnitSystem || convertToUnitSystem.IsIsolatedUnitSystem)
  5027. {
  5028. // Unit system declared to be isolated (user defined) without conversion to other (physical) unit systems.
  5029. return null;
  5030. }
  5031. else
  5032. { // Inter unit system conversion
  5033. UnitSystemConversion usc = Physics.UnitSystemConversions.GetUnitSystemConversion(convertFromUnitSystem, convertToUnitSystem);
  5034. if (usc != null)
  5035. {
  5036. return usc.ConvertTo(physicalQuantity.ConvertToBaseUnit(), convertToUnitSystem);
  5037. }
  5038. /* Missing unit system conversion from physicalquantity.Unit.System to ToUnitSystem */
  5039. /* TO DO Find intermediate systems with conversions between physicalquantity.Unit.System and convertToUnitSystem */
  5040. Debug.Assert(false);
  5041. return null;
  5042. }
  5043. }
  5044. }
  5045. public class UnitSystem : AbstractUnitSystem
  5046. {
  5047. private /* readonly */ UnitPrefixTable unitPrefixes;
  5048. private /* readonly */ BaseUnit[] baseUnits;
  5049. private /* readonly */ NamedDerivedUnit[] namedDerivedUnits;
  5050. private /* readonly */ ConvertibleUnit[] convertibleUnits;
  5051. private /* readonly */ Boolean isIsolated;
  5052. public override UnitPrefixTable UnitPrefixes => unitPrefixes;
  5053. public override BaseUnit[] BaseUnits { get { return baseUnits; } /* */ set { baseUnits = (BaseUnit[])value; CheckBaseUnitSystem(); } /* */ }
  5054. public override NamedDerivedUnit[] NamedDerivedUnits { get { return namedDerivedUnits; } /* */ set { namedDerivedUnits = (NamedDerivedUnit[])value; CheckNamedDerivedUnitSystem(); } /* */ }
  5055. public override ConvertibleUnit[] ConvertibleUnits { get { return convertibleUnits; } /* */ set { convertibleUnits = (ConvertibleUnit[])value; CheckConvertibleUnitSystem(); } /* */ }
  5056. public override Boolean IsIsolatedUnitSystem => isIsolated;
  5057. public override Boolean IsCombinedUnitSystem => false;
  5058. public UnitSystem(String someName, Boolean someIsIsolated)
  5059. : base(someName)
  5060. {
  5061. this.isIsolated = someIsIsolated;
  5062. }
  5063. public UnitSystem(String someName)
  5064. : this(someName, true)
  5065. {
  5066. }
  5067. public UnitSystem(String someName, UnitPrefixTable someUnitPrefixes)
  5068. : this(someName, false)
  5069. {
  5070. this.unitPrefixes = someUnitPrefixes;
  5071. }
  5072. public UnitSystem(String someName, UnitPrefixTable someUnitPrefixes, BaseUnit[] someBaseUnits)
  5073. : this(someName, someUnitPrefixes)
  5074. {
  5075. this.baseUnits = someBaseUnits;
  5076. CheckBaseUnitSystem();
  5077. }
  5078. public UnitSystem(String someName, UnitPrefixTable someUnitPrefixes, BaseUnit[] someBaseUnits, NamedDerivedUnit[] someNamedDerivedUnits)
  5079. : this(someName, someUnitPrefixes, someBaseUnits)
  5080. {
  5081. this.namedDerivedUnits = someNamedDerivedUnits;
  5082. CheckNamedDerivedUnitSystem();
  5083. }
  5084. public UnitSystem(String someName, UnitPrefixTable someUnitPrefixes, BaseUnit[] someBaseUnits, NamedDerivedUnit[] someNamedDerivedUnits, ConvertibleUnit[] someConvertibleUnits)
  5085. : this(someName, someUnitPrefixes, someBaseUnits, someNamedDerivedUnits)
  5086. {
  5087. this.convertibleUnits = someConvertibleUnits;
  5088. CheckConvertibleUnitSystem();
  5089. }
  5090. public UnitSystem(String someName, UnitPrefixTable someUnitPrefixes, BaseUnit someBaseUnit, NamedDerivedUnit[] someNamedDerivedUnits, ConvertibleUnit[] someConvertibleUnits)
  5091. : this(someName, someUnitPrefixes, new BaseUnit[] { someBaseUnit }, someNamedDerivedUnits)
  5092. {
  5093. this.isIsolated = someBaseUnit.BaseUnitNumber == (SByte)MonetaryBaseQuantityKind.Currency;
  5094. this.convertibleUnits = someConvertibleUnits;
  5095. CheckConvertibleUnitSystem();
  5096. }
  5097. //public override INamedSymbolUnit this[String unitSymbol] => UnitFromSymbol(unitSymbol);
  5098. private void CheckBaseUnitSystem()
  5099. {
  5100. Debug.Assert(this.baseUnits != null);
  5101. foreach (BaseUnit aBaseUnit in this.baseUnits)
  5102. {
  5103. Debug.Assert(aBaseUnit.Kind == UnitKind.BaseUnit);
  5104. if (aBaseUnit.Kind != UnitKind.BaseUnit)
  5105. {
  5106. throw new ArgumentException("Must only contain units with Kind = UnitKind.BaseUnit", "BaseUnits");
  5107. }
  5108. if (aBaseUnit.SimpleSystem != this)
  5109. {
  5110. Debug.Assert(aBaseUnit.SimpleSystem == null);
  5111. aBaseUnit.SimpleSystem = this;
  5112. }
  5113. }
  5114. }
  5115. private void CheckNamedDerivedUnitSystem()
  5116. {
  5117. if (this.namedDerivedUnits != null)
  5118. {
  5119. foreach (NamedDerivedUnit namedderivedunit in this.namedDerivedUnits)
  5120. {
  5121. Debug.Assert(namedderivedunit.Kind == UnitKind.DerivedUnit);
  5122. if (namedderivedunit.Kind != UnitKind.DerivedUnit)
  5123. {
  5124. throw new ArgumentException("Must only contain units with Kind = UnitKind.DerivedUnit", "someNamedDerivedUnits");
  5125. }
  5126. if (namedderivedunit.SimpleSystem != this)
  5127. {
  5128. namedderivedunit.SimpleSystem = this;
  5129. }
  5130. }
  5131. }
  5132. }
  5133. private void CheckConvertibleUnitSystem()
  5134. {
  5135. if (this.convertibleUnits != null)
  5136. {
  5137. foreach (ConvertibleUnit convertibleunit in this.convertibleUnits)
  5138. {
  5139. Debug.Assert(convertibleunit.Kind == UnitKind.ConvertibleUnit);
  5140. if (convertibleunit.Kind != UnitKind.ConvertibleUnit)
  5141. {
  5142. throw new ArgumentException("Must only contain units with Kind = UnitKind.DerivedUnit", "someConvertibleUnits");
  5143. }
  5144. if (convertibleunit.SimpleSystem != this)
  5145. {
  5146. convertibleunit.SimpleSystem = this;
  5147. }
  5148. if (convertibleunit.PrimaryUnit.SimpleSystem == null)
  5149. {
  5150. (convertibleunit.PrimaryUnit as Unit).SimpleSystem = this;
  5151. }
  5152. }
  5153. }
  5154. }
  5155. }
  5156. public class CombinedUnitSystem : AbstractUnitSystem, ICombinedUnitSystem
  5157. {
  5158. private /* readonly */ IUnitSystem[] unitSystemes;
  5159. private /* readonly */ UnitPrefixTable unitprefixes;
  5160. private /* readonly */ BaseUnit[] baseunits;
  5161. private /* readonly */ NamedDerivedUnit[] namedderivedunits;
  5162. private /* readonly */ ConvertibleUnit[] convertibleunits;
  5163. public IUnitSystem[] UnitSystemes => unitSystemes;
  5164. public override UnitPrefixTable UnitPrefixes => unitprefixes;
  5165. public override BaseUnit[] BaseUnits { get { return baseunits; } /* */ set { throw new NotImplementedException(); } /* */ }
  5166. public override NamedDerivedUnit[] NamedDerivedUnits { get { return namedderivedunits; } /* */ set { throw new NotImplementedException(); } /* */ }
  5167. public override ConvertibleUnit[] ConvertibleUnits { get { return convertibleunits; } /* */ set { throw new NotImplementedException(); } /* */ }
  5168. public override Unit Dimensionless => UnitSystemes[0].Dimensionless;
  5169. public override Boolean IsIsolatedUnitSystem => UnitSystemes.All(us => us.IsIsolatedUnitSystem);
  5170. public override Boolean IsCombinedUnitSystem => true;
  5171. public Boolean ContainsSubUnitSystem(IUnitSystem unitsystem) => UnitSystemes.Contains(unitsystem);
  5172. public Boolean ContainsSubUnitSystems(IEnumerable<IUnitSystem> someUnitSystems) => UnitSystemes.Union(someUnitSystems).Count() == UnitSystemes.Count();
  5173. private static List<ICombinedUnitSystem> combinedUnitSystems = new List<ICombinedUnitSystem>();
  5174. public static ICombinedUnitSystem GetCombinedUnitSystem(IUnitSystem[] subUnitSystems)
  5175. {
  5176. Debug.Assert(!subUnitSystems.Any(us => us.IsCombinedUnitSystem));
  5177. IUnitSystem[] sortedSubUnitSystems = subUnitSystems.OrderByDescending(us => us.BaseUnits.Length).ToArray();
  5178. ICombinedUnitSystem cus = null;
  5179. if (combinedUnitSystems.Count() > 0)
  5180. {
  5181. IEnumerable<ICombinedUnitSystem> tempUnitSystems = combinedUnitSystems.Where(us => us.UnitSystemes.SequenceEqual(sortedSubUnitSystems));
  5182. if (tempUnitSystems.Count() >= 1)
  5183. {
  5184. Debug.Assert(tempUnitSystems.Count() == 1);
  5185. cus = tempUnitSystems.First();
  5186. }
  5187. }
  5188. if (cus == null)
  5189. {
  5190. lock (combinedUnitSystems)
  5191. {
  5192. IEnumerable<ICombinedUnitSystem> tempUnitSystems = combinedUnitSystems.Where(us => us.UnitSystemes.SequenceEqual(sortedSubUnitSystems));
  5193. if (tempUnitSystems.Count() >= 1)
  5194. {
  5195. cus = tempUnitSystems.First();
  5196. }
  5197. else
  5198. {
  5199. cus = new CombinedUnitSystem(null, sortedSubUnitSystems);
  5200. combinedUnitSystems.Add(cus);
  5201. }
  5202. }
  5203. }
  5204. return cus;
  5205. }
  5206. public CombinedUnitSystem(String someName, IUnitSystem us1, IUnitSystem us2)
  5207. : this(someName, new IUnitSystem[] { us1, us2 })
  5208. {
  5209. }
  5210. public CombinedUnitSystem(String someName, IUnitSystem[] someSubUnitSystems)
  5211. : base(someName != null ? someName : "<" + someSubUnitSystems.Aggregate("", ((str, us) => String.IsNullOrWhiteSpace(str) ? us.Name : str + ", " + us.Name)) + ">")
  5212. {
  5213. SetupCombinedUnitSystem(someSubUnitSystems.OrderByDescending(us => us.BaseUnits.Length).ToArray());
  5214. }
  5215. public void SetupCombinedUnitSystem(IUnitSystem[] subUnitSystems)
  5216. {
  5217. unitSystemes = subUnitSystems;
  5218. UnitPrefix[] tempUnitprefixes = null;
  5219. BaseUnit[] tempBaseUnits = null;
  5220. NamedDerivedUnit[] tempNamedDerivedUnits = null;
  5221. ConvertibleUnit[] tempConvertibleUnits = null;
  5222. foreach (IUnitSystem us in unitSystemes)
  5223. {
  5224. tempUnitprefixes = ArrayExtensions.Concat<UnitPrefix>(tempUnitprefixes, us.UnitPrefixes?.UnitPrefixes);
  5225. tempBaseUnits = ArrayExtensions.Concat<BaseUnit>(tempBaseUnits, us.BaseUnits);
  5226. tempNamedDerivedUnits = ArrayExtensions.Concat<NamedDerivedUnit>(tempNamedDerivedUnits, us.NamedDerivedUnits);
  5227. tempConvertibleUnits = ArrayExtensions.Concat<ConvertibleUnit>(tempConvertibleUnits, us.ConvertibleUnits);
  5228. }
  5229. unitprefixes = new UnitPrefixTable(tempUnitprefixes);
  5230. baseunits = tempBaseUnits;
  5231. namedderivedunits = tempNamedDerivedUnits;
  5232. convertibleunits = tempConvertibleUnits;
  5233. }
  5234. public SByte[] UnitExponents(CombinedUnit cu)
  5235. {
  5236. int noOfSubUnitSystems = UnitSystemes.Length;
  5237. SByte[] unitSystemExponentsLength = new sbyte[noOfSubUnitSystems];
  5238. SByte[] unitSystemExponentsOffsets = new sbyte[noOfSubUnitSystems];
  5239. SByte noOfDimensions = 0;
  5240. SByte index = 0;
  5241. foreach (IUnitSystem us in UnitSystemes)
  5242. {
  5243. unitSystemExponentsOffsets[index] = noOfDimensions;
  5244. unitSystemExponentsLength[index] = (sbyte)us.BaseUnits.Length;
  5245. noOfDimensions += unitSystemExponentsLength[index];
  5246. }
  5247. SByte[] resExponents = new sbyte[0];
  5248. // Split cu in to parts for each sub unit system in UnitSystemes
  5249. ICombinedUnit[] subUnitParts = new ICombinedUnit[noOfSubUnitSystems];
  5250. // Split into subUnitParts
  5251. for (int i = 0; i < noOfSubUnitSystems; i++)
  5252. {
  5253. subUnitParts[i] = cu.OnlySingleSystemUnits(UnitSystemes[i]);
  5254. SByte[] us_exponents = subUnitParts[i].Exponents;
  5255. if (us_exponents.Length < unitSystemExponentsLength[index])
  5256. {
  5257. us_exponents = us_exponents.AllExponents(unitSystemExponentsLength[index]);
  5258. }
  5259. resExponents = resExponents.Concat(us_exponents).ToArray();
  5260. }
  5261. return resExponents;
  5262. }
  5263. public Quantity ConvertToBaseUnit(CombinedUnit cu)
  5264. {
  5265. int noOfSubUnitSystems = UnitSystemes.Length;
  5266. SByte[] unitSystemExponentsLength = new sbyte[noOfSubUnitSystems];
  5267. SByte[] unitSystemExponentsOffsets = new sbyte[noOfSubUnitSystems];
  5268. SByte noOfDimensions = 0;
  5269. SByte index = 0;
  5270. foreach (IUnitSystem us in UnitSystemes)
  5271. {
  5272. unitSystemExponentsOffsets[index] = noOfDimensions;
  5273. unitSystemExponentsLength[index] = (sbyte)us.BaseUnits.Length;
  5274. noOfDimensions += unitSystemExponentsLength[index];
  5275. index++;
  5276. }
  5277. SByte[] resExponents = new sbyte[0];
  5278. // Split cu in to parts for each sub unit system in UnitSystemes
  5279. ICombinedUnit[] subUnitParts = new ICombinedUnit[noOfSubUnitSystems + 1];
  5280. // Split into subUnitParts
  5281. Double resValue = cu.FactorValue;
  5282. for (int i = 0; i < noOfSubUnitSystems; i++)
  5283. {
  5284. subUnitParts[i] = cu.OnlySingleSystemUnits(UnitSystemes[i]);
  5285. Quantity pq = subUnitParts[i].ConvertToBaseUnit(UnitSystemes[i]);
  5286. resValue *= pq.Value;
  5287. Debug.Assert(pq.Unit != null);
  5288. SByte[] us_exponents = pq.Unit.Exponents;
  5289. if (us_exponents.Length < unitSystemExponentsLength[i])
  5290. {
  5291. us_exponents = us_exponents.AllExponents(unitSystemExponentsLength[i]);
  5292. }
  5293. resExponents = resExponents.Concat(us_exponents).ToArray();
  5294. }
  5295. // Handle part of cu without (sub-)unit system
  5296. subUnitParts[noOfSubUnitSystems] = cu.OnlySingleSystemUnits(null); // no unit system
  5297. Quantity pq2 = subUnitParts[noOfSubUnitSystems].ConvertToBaseUnit();
  5298. resValue *= pq2.Value;
  5299. Unit derivatedUnit = new DerivedUnit(this, resExponents);
  5300. return new Quantity(resValue, derivatedUnit);
  5301. }
  5302. public override int GetHashCode()
  5303. {
  5304. if (unitSystemes == null)
  5305. {
  5306. return base.GetHashCode();
  5307. }
  5308. return unitSystemes.GetHashCode();
  5309. }
  5310. public override Boolean Equals(Object obj)
  5311. {
  5312. if (obj == null)
  5313. return false;
  5314. ICombinedUnitSystem ICombinedUnitSystemObj = obj as ICombinedUnitSystem;
  5315. if (ICombinedUnitSystemObj == null)
  5316. return false;
  5317. else
  5318. return Equals(ICombinedUnitSystemObj);
  5319. }
  5320. public Boolean Equals(ICombinedUnitSystem other) => Equals(this.UnitSystemes, other.UnitSystemes);
  5321. }
  5322. #endregion Physical Unit System Classes
  5323. #region Physical Unit System Conversion Classes
  5324. public class UnitSystemConversion
  5325. {
  5326. private readonly IUnitSystem baseUnitSystem;
  5327. private readonly IUnitSystem convertedUnitSystem;
  5328. public readonly ValueConversion[] BaseUnitConversions;
  5329. public IUnitSystem BaseUnitSystem => baseUnitSystem;
  5330. public IUnitSystem ConvertedUnitSystem => convertedUnitSystem;
  5331. public UnitSystemConversion(IUnitSystem someBaseUnitsystem, IUnitSystem someConvertedUnitsystem, ValueConversion[] someBaseUnitConversions)
  5332. {
  5333. this.baseUnitSystem = someBaseUnitsystem;
  5334. this.convertedUnitSystem = someConvertedUnitsystem;
  5335. this.BaseUnitConversions = someBaseUnitConversions;
  5336. }
  5337. public Quantity Convert(IUnit convertUnit, Boolean backwards = false)
  5338. {
  5339. Debug.Assert(convertUnit.Kind == UnitKind.BaseUnit || convertUnit.Kind == UnitKind.DerivedUnit);
  5340. SByte[] fromUnitExponents = convertUnit.Exponents;
  5341. Double convertproduct = 1;
  5342. SByte noOfNonZeroExponents = 0;
  5343. SByte noOfNonOneExponents = 0;
  5344. SByte firstNonZeroExponent = -1;
  5345. SByte i = 0;
  5346. foreach (SByte exponent in fromUnitExponents)
  5347. {
  5348. if (exponent != 0)
  5349. {
  5350. if (firstNonZeroExponent == -1)
  5351. {
  5352. firstNonZeroExponent = i;
  5353. }
  5354. noOfNonZeroExponents++;
  5355. if (exponent != 1)
  5356. {
  5357. noOfNonOneExponents++;
  5358. }
  5359. ValueConversion vc = BaseUnitConversions[i];
  5360. if (vc != null)
  5361. {
  5362. Double baseunitconvertedvalue = vc.Convert(1, backwards);
  5363. Double baseunitfactor = Math.Pow(baseunitconvertedvalue, exponent);
  5364. convertproduct = convertproduct * baseunitfactor;
  5365. }
  5366. else
  5367. {
  5368. /* throw new ArgumentException("object's physical unit is not convertible to a " + ConvertedUnitSystem.name + " unit. " + ConvertedUnitSystem.name + " does not "); */
  5369. return null;
  5370. }
  5371. }
  5372. i++;
  5373. }
  5374. Double value = convertproduct;
  5375. IUnitSystem unitsystem = (backwards ? BaseUnitSystem : ConvertedUnitSystem);
  5376. Unit unit = unitsystem.UnitFromUnitInfo(fromUnitExponents, noOfNonZeroExponents, noOfNonOneExponents, firstNonZeroExponent);
  5377. return new Quantity(value, unit);
  5378. }
  5379. public Quantity Convert(IQuantity physicalQuantity, Boolean backwards = false)
  5380. {
  5381. Debug.Assert(physicalQuantity != null);
  5382. IQuantity pq = Convert(physicalQuantity.Unit, backwards);
  5383. return new Quantity(physicalQuantity.Value * pq.Value, pq.Unit);
  5384. }
  5385. public Quantity ConvertFromBaseUnitSystem(IUnit convertUnit) => Convert(convertUnit, false);
  5386. public Quantity ConvertToBaseUnitSystem(IUnit convertUnit) => Convert(convertUnit, true);
  5387. public Quantity ConvertFromBaseUnitSystem(IQuantity physicalQuantity) => Convert(physicalQuantity, false);
  5388. public Quantity ConvertToBaseUnitSystem(IQuantity physicalQuantity) => Convert(physicalQuantity, true);
  5389. public Quantity ConvertTo(IUnit convertFromUnit, IUnitSystem convertToUnitSystem)
  5390. {
  5391. Debug.Assert(convertFromUnit != null);
  5392. if ((convertFromUnit.SimpleSystem == BaseUnitSystem) && (convertToUnitSystem == ConvertedUnitSystem))
  5393. {
  5394. return this.ConvertFromBaseUnitSystem(convertFromUnit);
  5395. }
  5396. else
  5397. if ((convertFromUnit.SimpleSystem == ConvertedUnitSystem) && (convertToUnitSystem == BaseUnitSystem))
  5398. {
  5399. return this.ConvertToBaseUnitSystem(convertFromUnit);
  5400. }
  5401. return null;
  5402. }
  5403. public Quantity ConvertTo(IQuantity physicalQuantity, IUnitSystem convertToUnitSystem)
  5404. {
  5405. Debug.Assert(physicalQuantity != null);
  5406. if ((physicalQuantity.Unit.SimpleSystem == BaseUnitSystem) && (convertToUnitSystem == ConvertedUnitSystem))
  5407. {
  5408. return this.ConvertFromBaseUnitSystem(physicalQuantity);
  5409. }
  5410. else
  5411. if ((physicalQuantity.Unit.SimpleSystem == ConvertedUnitSystem) && (convertToUnitSystem == BaseUnitSystem))
  5412. {
  5413. return this.ConvertToBaseUnitSystem(physicalQuantity);
  5414. }
  5415. return null;
  5416. }
  5417. public Quantity ConvertTo(Unit convertFromUnit, Unit convertToUnit)
  5418. {
  5419. Debug.Assert(convertToUnit != null);
  5420. Quantity pq = this.ConvertTo(convertFromUnit, convertToUnit.SimpleSystem);
  5421. if (pq != null)
  5422. {
  5423. pq = pq.ConvertTo(convertToUnit);
  5424. }
  5425. return pq;
  5426. }
  5427. public Quantity ConvertTo(Quantity physicalQuantity, Unit convertToUnit)
  5428. {
  5429. Debug.Assert(convertToUnit != null);
  5430. Quantity pq = this.ConvertTo(physicalQuantity, convertToUnit.SimpleSystem);
  5431. if (pq != null)
  5432. {
  5433. pq = pq.ConvertTo(convertToUnit);
  5434. }
  5435. return pq;
  5436. }
  5437. }
  5438. #endregion Physical Unit System Conversions
  5439. #region Physical Quantity Classes
  5440. public class Quantity : IQuantity
  5441. {
  5442. // The value holders
  5443. private readonly Double value;
  5444. private readonly Unit unit;
  5445. public Double Value => this.value;
  5446. public Unit Unit => this.unit;
  5447. public Unit Dimensionless => unit.Dimensionless;
  5448. public Boolean IsDimensionless => unit == null || unit.IsDimensionless;
  5449. public Quantity()
  5450. : this(0)
  5451. {
  5452. }
  5453. public Quantity(Double somevalue)
  5454. : this(somevalue, Physics.dimensionless)
  5455. {
  5456. }
  5457. public Quantity(Unit someunit)
  5458. : this(1, someunit)
  5459. {
  5460. }
  5461. public Quantity(Double somevalue, Unit someunit)
  5462. {
  5463. this.value = somevalue;
  5464. if (someunit != null)
  5465. {
  5466. this.unit = someunit;
  5467. }
  5468. else
  5469. {
  5470. this.unit = Physics.dimensionless;
  5471. }
  5472. }
  5473. public Quantity(Double somevalue, BaseUnit someunit)
  5474. {
  5475. this.value = somevalue;
  5476. if (someunit != null)
  5477. {
  5478. this.unit = someunit;
  5479. }
  5480. else
  5481. {
  5482. this.unit = Physics.dimensionless;
  5483. }
  5484. }
  5485. public Quantity(Double somevalue, DerivedUnit someunit)
  5486. {
  5487. this.value = somevalue;
  5488. if (someunit != null)
  5489. {
  5490. this.unit = someunit;
  5491. }
  5492. else
  5493. {
  5494. this.unit = Physics.dimensionless;
  5495. }
  5496. }
  5497. public Quantity(Double somevalue, NamedDerivedUnit someunit)
  5498. {
  5499. this.value = somevalue;
  5500. if (someunit != null)
  5501. {
  5502. this.unit = someunit;
  5503. }
  5504. else
  5505. {
  5506. this.unit = Physics.dimensionless;
  5507. }
  5508. }
  5509. public Quantity(Double somevalue, INamedSymbolUnit someunit)
  5510. {
  5511. this.value = somevalue;
  5512. if (someunit != null)
  5513. {
  5514. this.unit = (Unit)someunit;
  5515. }
  5516. else
  5517. {
  5518. this.unit = Physics.dimensionless;
  5519. }
  5520. }
  5521. public Quantity(Double somevalue, ConvertibleUnit someunit)
  5522. {
  5523. this.value = somevalue;
  5524. if (someunit != null)
  5525. {
  5526. this.unit = someunit;
  5527. }
  5528. else
  5529. {
  5530. this.unit = Physics.dimensionless;
  5531. }
  5532. }
  5533. public Quantity(Double somevalue, CombinedUnit someunit)
  5534. {
  5535. this.value = somevalue;
  5536. if (someunit != null)
  5537. {
  5538. this.unit = someunit;
  5539. }
  5540. else
  5541. {
  5542. this.unit = Physics.dimensionless;
  5543. }
  5544. }
  5545. public Quantity(Quantity somephysicalquantity)
  5546. {
  5547. if (somephysicalquantity != null)
  5548. {
  5549. this.value = somephysicalquantity.Value;
  5550. this.unit = somephysicalquantity.Unit;
  5551. }
  5552. else
  5553. {
  5554. this.value = 0;
  5555. this.unit = Physics.dimensionless;
  5556. }
  5557. }
  5558. public Quantity(Double somevalue, Quantity somephysicalquantity)
  5559. : this(somevalue * somephysicalquantity.Value, somephysicalquantity.Unit)
  5560. {
  5561. }
  5562. /// <summary>
  5563. /// IComparable.CompareTo implementation.
  5564. /// </summary>
  5565. public int CompareTo(object obj)
  5566. {
  5567. if (obj is Quantity)
  5568. {
  5569. Quantity temp = (Quantity)obj;
  5570. Quantity tempconverted = temp.ConvertTo(this.Unit);
  5571. if (tempconverted != null)
  5572. {
  5573. return value.EpsilonCompareTo(tempconverted.Value);
  5574. }
  5575. throw new ArgumentException("object's physical unit " + temp.Unit.ToPrintString() + " is not convertible to a " + this.Unit.ToPrintString());
  5576. }
  5577. throw new ArgumentException("object is not a IQuantity");
  5578. }
  5579. /// <summary>
  5580. /// IFormattable.ToString implementation.
  5581. /// </summary>
  5582. public String ToString(String format, IFormatProvider formatProvider)
  5583. {
  5584. Double unitValue = this.Unit.FactorValue;
  5585. Unit pureUnit = this.Unit.PureUnit;
  5586. return pureUnit.ValueAndUnitString(this.Value * unitValue, format, formatProvider);
  5587. }
  5588. public String ToString(String format)
  5589. {
  5590. Double unitValue = this.Unit.FactorValue;
  5591. Unit pureUnit = this.Unit.PureUnit;
  5592. return pureUnit.ValueAndUnitString(this.Value * unitValue, format);
  5593. }
  5594. public override String ToString()
  5595. {
  5596. Double unitValue = this.Unit.FactorValue;
  5597. Unit pureUnit = this.Unit.PureUnit;
  5598. return pureUnit.ValueAndUnitString(this.Value * unitValue);
  5599. }
  5600. public virtual String ToPrintString()
  5601. {
  5602. Double unitValue = this.Unit.FactorValue;
  5603. Unit pureUnit = this.Unit.PureUnit;
  5604. String valStr = pureUnit.ValueString(this.Value * unitValue);
  5605. String unitStr = pureUnit.ToString();
  5606. if (String.IsNullOrEmpty(unitStr))
  5607. {
  5608. return valStr;
  5609. }
  5610. else
  5611. {
  5612. return valStr + " " + unitStr;
  5613. }
  5614. }
  5615. /// <summary>
  5616. /// Parses the physical quantity from a string in form
  5617. /// // [whitespace] [number] [whitespace] [prefix] [unitsymbol] [whitespace]
  5618. /// [whitespace] [number] [whitespace] [unit] [whitespace]
  5619. /// </summary>
  5620. public static Boolean TryParse(String physicalQuantityStr, System.Globalization.NumberStyles styles, IFormatProvider provider, out Quantity result)
  5621. {
  5622. result = null;
  5623. String[] strings = physicalQuantityStr.Trim().Split(' ');
  5624. if (strings.GetLength(0) > 0)
  5625. {
  5626. // Parse numerical value
  5627. String numValueStr = strings[0];
  5628. Double numValue;
  5629. if (!Double.TryParse(numValueStr, styles, provider, out numValue))
  5630. {
  5631. if (!Double.TryParse(numValueStr, styles, null, out numValue)) // Try to use Default Format Provider
  5632. {
  5633. if (!Double.TryParse(numValueStr, styles, NumberFormatInfo.InvariantInfo, out numValue)) // Try to use invariant Format Provider
  5634. {
  5635. return false;
  5636. }
  5637. }
  5638. }
  5639. Unit unit = null;
  5640. if (strings.GetLength(0) > 1)
  5641. {
  5642. // Parse unit
  5643. String unitStr = strings[1];
  5644. unit = Unit.Parse(unitStr);
  5645. }
  5646. else
  5647. {
  5648. unit = Physics.dimensionless;
  5649. }
  5650. result = new Quantity(numValue, unit);
  5651. return true;
  5652. }
  5653. return false;
  5654. }
  5655. /// <summary>
  5656. /// Parses the physical quantity from a string in form
  5657. /// // [whitespace] [number] [whitespace] [prefix] [unitSymbol] [whitespace]
  5658. /// [whitespace] [number] [whitespace] [unit] [whitespace]
  5659. /// </summary>
  5660. public static Boolean TryParse(String physicalQuantityStr, System.Globalization.NumberStyles styles, out Quantity result) => TryParse(physicalQuantityStr, styles, null, out result);
  5661. public static Boolean TryParse(String physicalQuantityStr, out Quantity result) => TryParse(physicalQuantityStr, System.Globalization.NumberStyles.Float, null, out result);
  5662. public static Quantity Parse(String physicalQuantityStr, System.Globalization.NumberStyles styles = System.Globalization.NumberStyles.Float, IFormatProvider provider = null)
  5663. {
  5664. Quantity result;
  5665. if (!TryParse(physicalQuantityStr, styles, provider, out result))
  5666. {
  5667. throw new ArgumentException("Not a valid physical quantity format", nameof(physicalQuantityStr));
  5668. }
  5669. return result;
  5670. }
  5671. public Quantity Zero => new Quantity(0, this.Unit.Dimensionless);
  5672. public Quantity One => new Quantity(1, this.Unit.Dimensionless);
  5673. public override Int32 GetHashCode() => this.Value.GetHashCode() + this.Unit.GetHashCode();
  5674. public Quantity ConvertToSystemUnit()
  5675. {
  5676. if (this.Unit.SimpleSystem != null)
  5677. {
  5678. return this;
  5679. }
  5680. Double d = this.Value;
  5681. Quantity pq = this.Unit.ConvertToSystemUnit(ref d);
  5682. return pq;
  5683. }
  5684. public Quantity ConvertToBaseUnit()
  5685. {
  5686. Quantity pq = this.Unit.ConvertToBaseUnit(this.Value);
  5687. return pq;
  5688. }
  5689. public Quantity ConvertToDerivedUnit()
  5690. {
  5691. Quantity pq_baseunit = this.Unit.ConvertToBaseUnit(this.Value);
  5692. Quantity pq_derivedunit = pq_baseunit.Unit.ConvertToDerivedUnit().Multiply(pq_baseunit.Value);
  5693. return pq_derivedunit;
  5694. }
  5695. // Auto detecting if specific or relative unit conversion
  5696. public Quantity this[BaseUnit convertToUnit] => this.ConvertTo(convertToUnit);
  5697. public Quantity this[DerivedUnit convertToUnit] => this.ConvertTo(convertToUnit);
  5698. public Quantity this[NamedDerivedUnit convertToUnit] => this.ConvertTo(convertToUnit);
  5699. public Quantity this[ConvertibleUnit convertToUnit] => this.ConvertTo(convertToUnit);
  5700. public Quantity this[CombinedUnit convertToUnit] => this.ConvertTo(convertToUnit);
  5701. public Quantity this[MixedUnit convertToUnit] => this.ConvertTo(convertToUnit);
  5702. public Quantity this[Unit convertToUnit] => this.ConvertTo(convertToUnit);
  5703. public Quantity this[Quantity convertToUnit] => this.ConvertTo(convertToUnit);
  5704. public Quantity ConvertTo(Unit convertToUnit)
  5705. {
  5706. if (Object.ReferenceEquals(this.Unit, convertToUnit))
  5707. {
  5708. // Convert to its own unit; No conversion needed
  5709. return this;
  5710. }
  5711. if (this.Unit == null)
  5712. {
  5713. if (convertToUnit == null || (convertToUnit.IsDimensionless)) // || convertToUnit == 1)) // One ))
  5714. { // Any dimensionless can be converted to any systems dimensionless
  5715. Debug.Assert(convertToUnit != null);
  5716. Quantity quantity = new Quantity(this.Value * 1 / convertToUnit.FactorValue, convertToUnit);
  5717. return quantity;
  5718. }
  5719. else
  5720. { // No dimensionless can be converted to or from any non dimensionless.
  5721. return null;
  5722. }
  5723. }
  5724. Debug.Assert(this.Unit != null);
  5725. Debug.Assert(convertToUnit != null);
  5726. if (convertToUnit == null)
  5727. {
  5728. throw new ArgumentNullException(nameof(convertToUnit));
  5729. }
  5730. if (this.Unit.Kind != UnitKind.CombinedUnit && convertToUnit.Kind != UnitKind.CombinedUnit)
  5731. {
  5732. Boolean thisIsDimensionless = this.Unit.IsDimensionless;
  5733. Boolean toIsDimensionless = convertToUnit.IsDimensionless;
  5734. if (thisIsDimensionless != toIsDimensionless)
  5735. { // No dimensionless can be converted to or from any non-dimensionless.
  5736. return null;
  5737. }
  5738. if (thisIsDimensionless && toIsDimensionless)
  5739. {
  5740. // Any dimensionless can be converted to any systems dimensionless
  5741. Quantity quantity = new Quantity(this.Value * this.Unit.FactorValue / convertToUnit.FactorValue, convertToUnit);
  5742. return quantity;
  5743. }
  5744. }
  5745. else
  5746. if (this.Unit.Kind == UnitKind.CombinedUnit && convertToUnit.Kind == UnitKind.CombinedUnit)
  5747. {
  5748. }
  5749. else
  5750. {
  5751. }
  5752. IUnitSystem convertToUnitsystem = convertToUnit.SimpleSystem;
  5753. if (convertToUnitsystem == null)
  5754. {
  5755. convertToUnitsystem = convertToUnit.ExponentsSystem;
  5756. Debug.WriteLine("convertToUnitsystem assigned from convertToUnit.ExpresionsSystem");
  5757. }
  5758. Debug.Assert(convertToUnitsystem != null);
  5759. if (convertToUnitsystem == null)
  5760. {
  5761. convertToUnitsystem = this.Unit.SimpleSystem;
  5762. Debug.WriteLine("convertToUnitsystem assigned from this.Unit.System");
  5763. }
  5764. if (convertToUnitsystem == null)
  5765. {
  5766. Debug.WriteLine("convertToUnitsystem assigned from Physics.Default_UnitSystem");
  5767. convertToUnitsystem = Physics.CurrentUnitSystems.Default;
  5768. }
  5769. if (convertToUnitsystem != null)
  5770. {
  5771. // Let convertToUnitsystem do auto detecting of specific or relative unit conversion
  5772. Quantity quantity = convertToUnitsystem.ConvertTo(this, convertToUnit);
  5773. return quantity;
  5774. }
  5775. return null;
  5776. }
  5777. public Quantity ConvertTo(BaseUnit convertToUnit) => this.ConvertTo((Unit)convertToUnit);
  5778. public Quantity ConvertTo(DerivedUnit convertToUnit) => this.ConvertTo((Unit)convertToUnit);
  5779. public Quantity ConvertTo(ConvertibleUnit convertToUnit) => this.ConvertTo((Unit)convertToUnit);
  5780. public Quantity ConvertTo(CombinedUnit convertToUnit) => this.ConvertTo((Unit)convertToUnit);
  5781. public Quantity ConvertTo(MixedUnit convertToUnit) => this.ConvertTo((Unit)convertToUnit);
  5782. public Quantity ConvertTo(Quantity convertToUnit) => this.ConvertTo(convertToUnit.Unit);
  5783. public Quantity ConvertTo(IUnitSystem convertToUnitSystem)
  5784. {
  5785. IUnitSystem convertFromUnitsystem = this.Unit.SimpleSystem;
  5786. if (convertFromUnitsystem == convertToUnitSystem)
  5787. {
  5788. return this;
  5789. }
  5790. Debug.Assert(this.Unit != null);
  5791. Debug.Assert(convertToUnitSystem != null);
  5792. if (this.Unit == null)
  5793. {
  5794. throw new InvalidOperationException("Must have a unit to convert it");
  5795. }
  5796. if (convertToUnitSystem == null)
  5797. {
  5798. throw new ArgumentNullException(nameof(convertToUnitSystem));
  5799. }
  5800. if (convertFromUnitsystem != null)
  5801. {
  5802. // Let unit's unit system do auto detecting of specific or relative unit conversion
  5803. Quantity quantity = convertFromUnitsystem.ConvertTo(this, convertToUnitSystem);
  5804. return quantity;
  5805. }
  5806. return null;
  5807. }
  5808. // Unspecific/relative non-quantity unit conversion (e.g. temperature interval)1
  5809. public Quantity RelativeConvertTo(Unit convertToUnit)
  5810. {
  5811. IUnitSystem convertFromUnitsystem = this.Unit.SimpleSystem;
  5812. if (convertFromUnitsystem != null)
  5813. {
  5814. // Let unit's unit system do auto detecting of specific or relative unit conversion
  5815. Quantity quantity = convertFromUnitsystem.ConvertTo(this.Unit, convertToUnit).Multiply(this.Value);
  5816. return quantity;
  5817. }
  5818. return null;
  5819. }
  5820. public Quantity RelativeConvertTo(IUnitSystem convertToUnitSystem)
  5821. {
  5822. IUnitSystem convertFromUnitsystem = this.Unit.SimpleSystem;
  5823. if (convertFromUnitsystem != null)
  5824. {
  5825. // Let unit's unit system do auto detecting of specific or relative unit conversion
  5826. Quantity quantity = convertFromUnitsystem.ConvertTo(this.Unit, convertToUnitSystem).Multiply(this.Value);
  5827. return quantity;
  5828. }
  5829. return null;
  5830. }
  5831. // Specific/absolute quantity unit conversion (e.g. specific temperature)
  5832. public Quantity SpecificConvertTo(Unit convertToUnit)
  5833. {
  5834. IUnitSystem convertFromUnitsystem = this.Unit.SimpleSystem;
  5835. if (convertFromUnitsystem != null)
  5836. {
  5837. // Let unit's unit system do auto detecting of specific or relative unit conversion
  5838. Quantity quantity = convertFromUnitsystem.ConvertTo(this, convertToUnit);
  5839. return quantity;
  5840. }
  5841. return null;
  5842. }
  5843. public Quantity SpecificConvertTo(IUnitSystem convertToUnitSystem)
  5844. {
  5845. IUnitSystem convertFromUnitsystem = this.Unit.SimpleSystem;
  5846. if (convertFromUnitsystem != null)
  5847. {
  5848. // Let unit's unit system do auto detecting of specific or relative unit conversion
  5849. Quantity quantity = convertFromUnitsystem.ConvertTo(this, convertToUnitSystem);
  5850. return quantity;
  5851. }
  5852. return null;
  5853. }
  5854. public static Boolean IsPureUnit(Quantity physicalQuantity)
  5855. {
  5856. Debug.Assert(physicalQuantity != null);
  5857. return physicalQuantity.Value == 1;
  5858. }
  5859. public static Unit AsPureUnit(Quantity physicalQuantity)
  5860. {
  5861. Debug.Assert(physicalQuantity != null);
  5862. if (IsPureUnit(physicalQuantity))
  5863. {
  5864. return physicalQuantity.Unit;
  5865. }
  5866. Double prefixExponentD = Math.Log10(physicalQuantity.Value);
  5867. SByte prefixExponent = (SByte)Math.Floor(prefixExponentD);
  5868. if (prefixExponentD - prefixExponent == 0)
  5869. {
  5870. SByte newPrefixExponent = prefixExponent;
  5871. Unit newUnit = physicalQuantity.Unit;
  5872. if (physicalQuantity.Unit.Kind == UnitKind.PrefixedUnit)
  5873. {
  5874. IPrefixedUnit prefixUnit = physicalQuantity.Unit as PrefixedUnit;
  5875. newPrefixExponent = (SByte)(prefixExponent + prefixUnit.Prefix.Exponent);
  5876. newUnit = (Unit)prefixUnit.Unit;
  5877. }
  5878. INamedSymbolUnit namedSymbolUnit = newUnit as INamedSymbolUnit;
  5879. if (namedSymbolUnit != null)
  5880. {
  5881. if (newPrefixExponent == 0)
  5882. {
  5883. return (Unit)namedSymbolUnit;
  5884. }
  5885. IUnitPrefix unitPrefix;
  5886. if (physicalQuantity.Unit.SimpleSystem.UnitPrefixes.GetUnitPrefixFromExponent(new UnitPrefixExponent(newPrefixExponent), out unitPrefix))
  5887. {
  5888. return new PrefixedUnit(unitPrefix, namedSymbolUnit);
  5889. }
  5890. }
  5891. if (physicalQuantity.Unit.Kind == UnitKind.CombinedUnit)
  5892. {
  5893. CombinedUnit combinedUnit = (CombinedUnit)physicalQuantity.Unit;
  5894. IUnitPrefix unitPrefix;
  5895. if (physicalQuantity.Unit.SimpleSystem.UnitPrefixes.GetUnitPrefixFromExponent(new UnitPrefixExponent(prefixExponent), out unitPrefix))
  5896. {
  5897. return new CombinedUnit(unitPrefix, combinedUnit);
  5898. }
  5899. }
  5900. }
  5901. return null;
  5902. }
  5903. public static Unit GetAsNamedUnit(Quantity physicalQuantity)
  5904. {
  5905. Debug.Assert(physicalQuantity != null);
  5906. Double prefixExponentD = Math.Log10(physicalQuantity.Value);
  5907. SByte prefixExponent = (SByte)Math.Floor(prefixExponentD);
  5908. if (prefixExponentD - prefixExponent == 0)
  5909. {
  5910. SByte newPrefixExponent = prefixExponent;
  5911. Unit newUnit = physicalQuantity.Unit;
  5912. if (physicalQuantity.Unit.Kind == UnitKind.CombinedUnit)
  5913. {
  5914. CombinedUnit combinedUnit = (CombinedUnit)physicalQuantity.Unit;
  5915. Unit namedDerivatedUnit = (Unit)combinedUnit.SomeSimpleSystem.NamedDerivedUnitFromUnit(combinedUnit);
  5916. if (namedDerivatedUnit != null)
  5917. {
  5918. newUnit = namedDerivatedUnit;
  5919. }
  5920. }
  5921. if (physicalQuantity.Unit.Kind == UnitKind.DerivedUnit)
  5922. {
  5923. DerivedUnit derivedUnit = physicalQuantity.Unit as DerivedUnit;
  5924. Unit namedDerivatedUnit = (Unit)derivedUnit.SimpleSystem.NamedDerivedUnitFromUnit(derivedUnit);
  5925. newUnit = namedDerivatedUnit;
  5926. }
  5927. if (physicalQuantity.Unit.Kind == UnitKind.PrefixedUnit)
  5928. {
  5929. IPrefixedUnit prefixUnit = physicalQuantity.Unit as PrefixedUnit;
  5930. newPrefixExponent = (SByte)(prefixExponent + prefixUnit.Prefix.Exponent);
  5931. newUnit = (Unit)prefixUnit.Unit;
  5932. }
  5933. INamedSymbolUnit namedSymbolUnit = newUnit as INamedSymbolUnit;
  5934. if (namedSymbolUnit != null)
  5935. {
  5936. if (newPrefixExponent == 0)
  5937. {
  5938. return (Unit)namedSymbolUnit;
  5939. }
  5940. IUnitPrefix unitPrefix;
  5941. if (physicalQuantity.Unit.SimpleSystem.UnitPrefixes.GetUnitPrefixFromExponent(new UnitPrefixExponent(newPrefixExponent), out unitPrefix))
  5942. {
  5943. return new PrefixedUnit(unitPrefix, namedSymbolUnit);
  5944. }
  5945. }
  5946. }
  5947. return null;
  5948. }
  5949. public static Unit PureUnit(Quantity physicalQuantity)
  5950. {
  5951. Unit pureUnit = AsPureUnit(physicalQuantity);
  5952. if (pureUnit == null)
  5953. {
  5954. throw new ArgumentException("Physical quantity is not a pure unit; but has a value = " + physicalQuantity.Value.ToString());
  5955. }
  5956. return pureUnit;
  5957. }
  5958. public static PrefixedUnit AsPrefixedUnit(Quantity physicalQuantity)
  5959. {
  5960. Debug.Assert(physicalQuantity != null);
  5961. Unit unit = AsPureUnit(physicalQuantity);
  5962. if (unit == null)
  5963. {
  5964. return null;
  5965. }
  5966. PrefixedUnit prefixedUnit = unit as PrefixedUnit;
  5967. return prefixedUnit;
  5968. }
  5969. public Quantity AsNamedUnit
  5970. {
  5971. get
  5972. {
  5973. Unit namedUnit = Unit.AsNamedUnit;
  5974. if (namedUnit != null)
  5975. {
  5976. return new Quantity(this.Value, namedUnit);
  5977. }
  5978. return this;
  5979. }
  5980. }
  5981. public static Unit operator !(Quantity physicalQuantity) => PureUnit(physicalQuantity);
  5982. //public static implicit operator Unit(Quantity physicalQuantity) => PureUnit(physicalQuantity) as Unit;
  5983. public Boolean Equivalent(Quantity other, out Double quotient)
  5984. {
  5985. Debug.Assert(other != null);
  5986. Debug.Assert(this.Unit != null);
  5987. Debug.Assert(other.Unit != null);
  5988. if (Object.ReferenceEquals(null, other))
  5989. {
  5990. quotient = 0;
  5991. return false;
  5992. }
  5993. Quantity other2 = other.ConvertTo(this.Unit);
  5994. if (Object.ReferenceEquals(null, other2))
  5995. {
  5996. quotient = 0;
  5997. return false;
  5998. }
  5999. quotient = this.Value / other2.Value;
  6000. return true;
  6001. }
  6002. public Boolean Equivalent(Quantity other)
  6003. {
  6004. Double quotient;
  6005. return Equivalent(other, out quotient);
  6006. }
  6007. public Boolean Equals(Quantity other)
  6008. {
  6009. if (Object.ReferenceEquals(null, other))
  6010. {
  6011. return false;
  6012. }
  6013. Debug.Assert(other != null);
  6014. Debug.Assert(this.Unit != null);
  6015. // Debug.Assert(other.Unit != null);
  6016. Quantity other2 = other.ConvertTo(this.Unit);
  6017. if (Object.ReferenceEquals(null, other2))
  6018. {
  6019. return false;
  6020. }
  6021. return this.Value.EpsilonCompareTo(other2.Value) == 0;
  6022. }
  6023. public Boolean Equals(Unit other)
  6024. {
  6025. Quantity otherPhysicalQuantity = new Quantity(1, other);
  6026. return this.Equals(otherPhysicalQuantity);
  6027. }
  6028. public Boolean Equals(double other)
  6029. {
  6030. Quantity otherPhysicalQuantity = new Quantity(other);
  6031. return this.Equals(otherPhysicalQuantity);
  6032. }
  6033. public override Boolean Equals(Object obj)
  6034. {
  6035. if (obj == null)
  6036. {
  6037. return base.Equals(obj);
  6038. }
  6039. Quantity pq = obj as Quantity;
  6040. if (pq != null)
  6041. {
  6042. return Equals(pq);
  6043. }
  6044. Unit pu = obj as Unit;
  6045. if (pu != null)
  6046. {
  6047. return Equals(pu);
  6048. }
  6049. //throw new InvalidCastException("The 'obj' argument is not a IQuantity object or IUnit object.");
  6050. Debug.Assert(obj is Quantity || obj is Unit);
  6051. return false;
  6052. }
  6053. public static Boolean operator ==(Quantity pq1, Quantity pq2)
  6054. {
  6055. if ((Object)pq1 == null)
  6056. {
  6057. return (Object)pq2 == null;
  6058. }
  6059. Debug.Assert(!Object.ReferenceEquals(null, pq1));
  6060. return pq1.Equals(pq2);
  6061. }
  6062. public static Boolean operator ==(Quantity pq1, IQuantity pq2)
  6063. {
  6064. if ((Object)pq1 == null)
  6065. {
  6066. return (Object)pq2 == null;
  6067. }
  6068. Debug.Assert(!Object.ReferenceEquals(null, pq1));
  6069. return pq1.Equals(pq2);
  6070. }
  6071. public static Boolean operator !=(Quantity pq1, Quantity pq2)
  6072. {
  6073. if ((Object)pq1 == null)
  6074. {
  6075. return (Object)pq2 != null;
  6076. }
  6077. Debug.Assert(!Object.ReferenceEquals(null, pq1));
  6078. return !pq1.Equals(pq2);
  6079. }
  6080. public static Boolean operator !=(Quantity pq1, IQuantity pq2)
  6081. {
  6082. if ((Object)pq1 == null)
  6083. {
  6084. return (Object)pq2 != null;
  6085. }
  6086. Debug.Assert(!Object.ReferenceEquals(null, pq1));
  6087. return !pq1.Equals(pq2);
  6088. }
  6089. public static Boolean operator <(Quantity pq1, Quantity pq2)
  6090. {
  6091. Debug.Assert(!Object.ReferenceEquals(null, pq1));
  6092. return pq1.CompareTo(pq2) < 0;
  6093. }
  6094. public static Boolean operator <=(Quantity pq1, Quantity pq2)
  6095. {
  6096. Debug.Assert(!Object.ReferenceEquals(null, pq1));
  6097. return pq1.CompareTo(pq2) <= 0;
  6098. }
  6099. public static Boolean operator >(Quantity pq1, Quantity pq2)
  6100. {
  6101. Debug.Assert(!Object.ReferenceEquals(null, pq1));
  6102. return pq1.CompareTo(pq2) > 0;
  6103. }
  6104. public static Boolean operator >=(Quantity pq1, Quantity pq2)
  6105. {
  6106. Debug.Assert(!Object.ReferenceEquals(null, pq1));
  6107. return pq1.CompareTo(pq2) >= 0;
  6108. }
  6109. #region Physical Quantity static operator methods
  6110. protected delegate Double CombineValuesFunc(Double v1, Double v2);
  6111. protected delegate IUnit CombineUnitsFunc(IUnit u1, IUnit u2);
  6112. protected static Quantity CombineValues(IQuantity pq1, IQuantity pq2, CombineValuesFunc cvf)
  6113. {
  6114. if (pq1.Unit != pq2.Unit)
  6115. {
  6116. Quantity temp_pq2 = pq2.ConvertTo(pq1.Unit);
  6117. if (temp_pq2 == null)
  6118. {
  6119. throw new ArgumentException("object's physical unit " + pq2.Unit.ToPrintString() + " is not convertible to unit " + pq1.Unit.ToPrintString());
  6120. }
  6121. pq2 = temp_pq2;
  6122. }
  6123. return new Quantity(cvf(pq1.Value, pq2.Value), pq1.Unit);
  6124. }
  6125. protected static Quantity CombineUnitsAndValues(IQuantity pq1, IQuantity pq2, CombineValuesFunc cvf, CombineExponentsFunc cef)
  6126. {
  6127. Debug.Assert(pq1.Unit.Kind != UnitKind.CombinedUnit);
  6128. Debug.Assert(pq2.Unit.Kind != UnitKind.CombinedUnit);
  6129. if (pq1.Unit.Kind == UnitKind.CombinedUnit)
  6130. {
  6131. CombinedUnit pg1_unit = (CombinedUnit)pq1.Unit;
  6132. pq1 = pq1.ConvertToSystemUnit();
  6133. }
  6134. if (pq2.Unit.Kind == UnitKind.CombinedUnit)
  6135. {
  6136. CombinedUnit pg2_unit = (CombinedUnit)pq2.Unit;
  6137. pq2 = pq2.ConvertToSystemUnit();
  6138. }
  6139. while (pq1.Unit.Kind == UnitKind.ConvertibleUnit)
  6140. {
  6141. ConvertibleUnit pg1_unit = (ConvertibleUnit)pq1.Unit;
  6142. pq1 = pq1.ConvertTo(pg1_unit.PrimaryUnit);
  6143. }
  6144. while (pq2.Unit.Kind == UnitKind.ConvertibleUnit)
  6145. {
  6146. ConvertibleUnit pg2_unit = (ConvertibleUnit)pq2.Unit;
  6147. pq2 = pq2.ConvertTo(pg2_unit.PrimaryUnit);
  6148. }
  6149. IUnitSystem pq2UnitSystem = pq2.Unit.SimpleSystem;
  6150. IUnitSystem pq1UnitSystem = pq1.Unit.SimpleSystem;
  6151. if (pq2UnitSystem != pq1UnitSystem)
  6152. { // Must be same unit system
  6153. pq2 = pq2.ConvertTo(pq1UnitSystem);
  6154. Debug.Assert(pq2 != null);
  6155. }
  6156. SByte minNoOfBaseUnits = (SByte)Math.Min(pq1.Unit.Exponents.Length, pq2.Unit.Exponents.Length);
  6157. SByte maxNoOfBaseUnits = (SByte)Math.Max(pq1.Unit.Exponents.Length, pq2.Unit.Exponents.Length);
  6158. Debug.Assert(maxNoOfBaseUnits <= Physics.NoOfBaseQuanties);
  6159. SByte[] someexponents = new SByte[Physics.NoOfBaseQuanties];
  6160. for (int i = 0; i < minNoOfBaseUnits; i++)
  6161. {
  6162. someexponents[i] = cef(pq1.Unit.Exponents[i], pq2.Unit.Exponents[i]);
  6163. }
  6164. for (int i = minNoOfBaseUnits; i < maxNoOfBaseUnits; i++)
  6165. {
  6166. if (pq1.Unit.Exponents.Length > pq2.Unit.Exponents.Length)
  6167. {
  6168. someexponents[i] = cef(pq1.Unit.Exponents[i], 0);
  6169. }
  6170. else
  6171. {
  6172. someexponents[i] = cef(0, pq2.Unit.Exponents[i]);
  6173. }
  6174. }
  6175. Debug.Assert(pq1.Unit.ExponentsSystem != null);
  6176. Unit pu = new DerivedUnit(pq1.Unit.ExponentsSystem, someexponents);
  6177. return new Quantity(cvf(pq1.Value, pq2.Value), pu);
  6178. }
  6179. public static Quantity operator +(Quantity pq1, Quantity pq2) => new Quantity(pq1.Add(pq2));
  6180. public static Quantity operator -(Quantity pq1, Quantity pq2) => new Quantity(pq1.Subtract(pq2));
  6181. public static Quantity operator *(Quantity pq1, Quantity pq2)
  6182. {
  6183. Quantity pq = pq1.Unit.Multiply(pq1.Value, pq2);
  6184. return pq;
  6185. }
  6186. public static Quantity operator /(Quantity pq1, Quantity pq2)
  6187. {
  6188. Quantity pq = pq1.Unit.Divide(pq1.Value, pq2);
  6189. return pq;
  6190. }
  6191. public static Quantity operator *(Quantity pq, IUnitPrefix up) => new Quantity(pq.Value * up.Value, pq.Unit);
  6192. public static Quantity operator *(IUnitPrefix up, Quantity pq) => new Quantity(pq.Value * up.Value, pq.Unit);
  6193. public static Quantity operator *(Quantity pq, Double d) => new Quantity(pq.Value * d, pq.Unit);
  6194. public static Quantity operator /(Quantity pq, Double d) => new Quantity(pq.Value / d, pq.Unit);
  6195. public static Quantity operator *(Double d, Quantity pq) => new Quantity(pq.Multiply(d));
  6196. public static Quantity operator /(Double d, Quantity pq) => new Quantity(new Quantity(d).Divide(pq));
  6197. public static Quantity operator *(Quantity pq, NamedDerivedUnit pu) => new Quantity(pq.Value, pq.Unit.Multiply((INamedSymbolUnit)pu));
  6198. public static Quantity operator /(Quantity pq, NamedDerivedUnit pu) => new Quantity(pq.Value, pq.Unit.Divide((INamedSymbolUnit)pu));
  6199. public static Quantity operator *(Quantity pq, Unit pu) => new Quantity(pq.Value, pq.Unit.Multiply(pu));
  6200. public static Quantity operator /(Quantity pq, Unit pu) => new Quantity(pq.Value, pq.Unit.Divide(pu));
  6201. public static Quantity operator *(Unit pu, Quantity pq) => new Quantity(pq.Value, pu.Multiply(pq.Unit));
  6202. public static Quantity operator /(Unit pu, Quantity pq) => new Quantity(pq.Value, pu.Divide(pq.Unit));
  6203. public static Quantity operator ^(Quantity pq, SByte exponent) => pq.Power(exponent);
  6204. public static Quantity operator %(Quantity pq, SByte exponent) => pq.Root(exponent);
  6205. public static Quantity operator |(Quantity pq, SByte exponent) => pq.Root(exponent);
  6206. #endregion Physical Quantity static operator methods
  6207. public Quantity Power(SByte exponent)
  6208. {
  6209. Unit pu = this.Unit;
  6210. if (pu == null)
  6211. {
  6212. pu = Physics.CurrentUnitSystems.Default.Dimensionless;
  6213. }
  6214. Unit pu_pow = pu.Pow(exponent);
  6215. Double value = System.Math.Pow(this.Value, exponent);
  6216. return new Quantity(value, pu_pow);
  6217. }
  6218. public Quantity Root(SByte exponent)
  6219. {
  6220. Unit pu = this.Unit;
  6221. if (pu == null)
  6222. {
  6223. pu = Physics.CurrentUnitSystems.Default.Dimensionless;
  6224. }
  6225. Unit pu_rot = pu.Rot(exponent);
  6226. Double value = System.Math.Pow(this.Value, 1.0 / exponent);
  6227. return new Quantity(value, pu_rot);
  6228. }
  6229. #region Physical Quantity IPhysicalUnitMath implementation
  6230. public Quantity Add(Quantity physicalQuantity) => CombineValues(this, physicalQuantity, (Double v1, Double v2) => v1 + v2);
  6231. public Quantity Subtract(Quantity physicalQuantity) => CombineValues(this, physicalQuantity, (Double v1, Double v2) => v1 - v2);
  6232. public Quantity Abs() => new Quantity(Math.Abs(this.Value), this.Unit);
  6233. public Quantity Multiply(INamedSymbolUnit physicalUnit) => this.Multiply(new PrefixedUnitExponent(null, physicalUnit, 1));
  6234. public Quantity Divide(INamedSymbolUnit physicalUnit) => this.Divide(new PrefixedUnitExponent(null, physicalUnit, 1));
  6235. public Quantity Multiply(Unit physicalUnit) => this.Unit.Multiply(physicalUnit).Multiply(this.Value);
  6236. public Quantity Divide(Unit physicalUnit) => this.Unit.Divide(physicalUnit).Multiply(this.Value);
  6237. public Quantity Multiply(Quantity physicalQuantity) => this.Unit.Multiply(this.Value, physicalQuantity);
  6238. public Quantity Divide(Quantity physicalQuantity) => this.Unit.Divide(this.Value, physicalQuantity);
  6239. public Quantity Multiply(Double value) => new Quantity(this.Value * value, this.Unit);
  6240. public Quantity Divide(Double value) => new Quantity(this.Value / value, this.Unit);
  6241. public Quantity Pow(SByte exponent) => this.Power(exponent);
  6242. public Quantity Rot(SByte exponent) => this.Root(exponent);
  6243. public Quantity Multiply(PrefixedUnit prefixedUnit)
  6244. {
  6245. Unit pu = this.Unit.Multiply(prefixedUnit);
  6246. return new Quantity(this.Value, pu);
  6247. }
  6248. public Quantity Divide(PrefixedUnit prefixedUnit)
  6249. {
  6250. Unit pu = this.Unit.Divide(prefixedUnit);
  6251. return new Quantity(this.Value, pu);
  6252. }
  6253. public Quantity Multiply(PrefixedUnitExponent prefixedUnitExponent)
  6254. {
  6255. Unit pu = this.Unit.Multiply((IPrefixedUnitExponent)prefixedUnitExponent);
  6256. return new Quantity(Value, pu);
  6257. }
  6258. public Quantity Divide(PrefixedUnitExponent prefixedUnitExponent)
  6259. {
  6260. Unit pu = this.Unit.Divide((IPrefixedUnitExponent)prefixedUnitExponent);
  6261. return new Quantity(this.Value, pu);
  6262. }
  6263. public Quantity Multiply(IUnitPrefixExponent prefix)
  6264. {
  6265. Unit pu = this.Unit.Multiply(prefix);
  6266. return new Quantity(this.Value, pu);
  6267. }
  6268. public Quantity Divide(IUnitPrefixExponent prefix)
  6269. {
  6270. Unit pu = this.Unit.Divide(prefix);
  6271. return new Quantity(this.Value, pu);
  6272. }
  6273. public Quantity Multiply(Double value, Quantity physicalQuantity)
  6274. {
  6275. Quantity pq = this.Unit.Multiply(this.Value * value, physicalQuantity);
  6276. return pq;
  6277. }
  6278. public Quantity Divide(Double value, Quantity physicalQuantity)
  6279. {
  6280. Quantity pq = this.Unit.Divide(value, physicalQuantity).Multiply(this.Value);
  6281. return pq;
  6282. }
  6283. #endregion Physical Quantity IPhysicalUnitMath implementation
  6284. }
  6285. #endregion Physical Quantity Classes
  6286. public class UnitSystemStack
  6287. {
  6288. protected Stack<IUnitSystem> default_UnitSystem_Stack = new Stack<IUnitSystem>();
  6289. public IUnitSystem Default
  6290. {
  6291. get
  6292. {
  6293. if (default_UnitSystem_Stack == null || default_UnitSystem_Stack.Count <= 0)
  6294. {
  6295. return Physics.SI_Units;
  6296. }
  6297. else
  6298. {
  6299. return default_UnitSystem_Stack.Peek();
  6300. }
  6301. }
  6302. }
  6303. public Boolean Use(IUnitSystem newUnitSystem)
  6304. {
  6305. if (Default != newUnitSystem)
  6306. {
  6307. default_UnitSystem_Stack.Push(newUnitSystem);
  6308. return true;
  6309. }
  6310. return false;
  6311. }
  6312. public Boolean Unuse(IUnitSystem oldUnitSystem)
  6313. {
  6314. if (default_UnitSystem_Stack != null && default_UnitSystem_Stack.Count > 0 && default_UnitSystem_Stack.Peek() == oldUnitSystem)
  6315. {
  6316. default_UnitSystem_Stack.Pop();
  6317. return true;
  6318. }
  6319. return false;
  6320. }
  6321. public void Reset()
  6322. {
  6323. default_UnitSystem_Stack.Clear();
  6324. }
  6325. }
  6326. public class UnitLookup //(SingleUnitSystem[] unitSystems)
  6327. {
  6328. protected UnitSystem[] unitSystems;
  6329. public UnitLookup(UnitSystem[] someUnitSystems)
  6330. {
  6331. unitSystems = someUnitSystems;
  6332. }
  6333. public Unit UnitFromName(String namestr)
  6334. {
  6335. foreach (UnitSystem us in unitSystems)
  6336. {
  6337. INamedSymbolUnit unit = us.UnitFromName(namestr);
  6338. if (unit != null)
  6339. {
  6340. return (Unit)unit;
  6341. }
  6342. }
  6343. return null;
  6344. }
  6345. public Unit UnitFromSymbol(String symbolstr)
  6346. {
  6347. foreach (UnitSystem us in unitSystems)
  6348. {
  6349. INamedSymbolUnit unit = us.UnitFromSymbol(symbolstr);
  6350. if (unit != null)
  6351. {
  6352. return (Unit)unit;
  6353. }
  6354. }
  6355. return null;
  6356. }
  6357. public Unit ScaledUnitFromSymbol(String scaledsymbolstr)
  6358. {
  6359. foreach (UnitSystem us in unitSystems)
  6360. {
  6361. Unit scaledunit = us.ScaledUnitFromSymbol(scaledsymbolstr);
  6362. if (scaledunit != null)
  6363. {
  6364. return scaledunit;
  6365. }
  6366. }
  6367. return null;
  6368. }
  6369. public IUnitSystem UnitSystemFromName(String UnitSystemsymbolstr)
  6370. {
  6371. IUnitSystem result_us = unitSystems.FirstOrNull<IUnitSystem>(us => us.Name == UnitSystemsymbolstr);
  6372. return result_us;
  6373. }
  6374. }
  6375. public class UnitSystemConversionLookup
  6376. {
  6377. public IList<UnitSystemConversion> UnitSystemConversions;
  6378. public UnitSystemConversionLookup(IList<UnitSystemConversion> unitSystemConversions)
  6379. {
  6380. UnitSystemConversions = unitSystemConversions;
  6381. }
  6382. public UnitSystemConversion GetUnitSystemConversion(IUnitSystem unitsystem1, IUnitSystem unitsystem2)
  6383. {
  6384. UnitSystemConversion usc = GetDirectUnitSystemConversion(unitsystem1, unitsystem2);
  6385. if (usc != null)
  6386. {
  6387. return usc;
  6388. }
  6389. /* No direct unit system conversion from unitsystem1 to unitsystem2.
  6390. * Try to find an intermediate unit system with conversion to/from unitsystem1 and unitsystem2 */
  6391. return GetIntermediateUnitSystemConversion(unitsystem1, unitsystem2);
  6392. }
  6393. public UnitSystemConversion GetDirectUnitSystemConversion(IUnitSystem unitsystem1, IUnitSystem unitsystem2)
  6394. {
  6395. foreach (UnitSystemConversion usc in UnitSystemConversions)
  6396. {
  6397. if ((usc.BaseUnitSystem == unitsystem1 && usc.ConvertedUnitSystem == unitsystem2)
  6398. || (usc.BaseUnitSystem == unitsystem2 && usc.ConvertedUnitSystem == unitsystem1))
  6399. {
  6400. return usc;
  6401. }
  6402. }
  6403. return null;
  6404. }
  6405. public UnitSystemConversion GetIntermediateUnitSystemConversion(IUnitSystem unitsystem1, IUnitSystem unitsystem2)
  6406. {
  6407. /* No direct unit system conversion from unitsystem1 to unitsystem2.
  6408. * Try to find an intermediate unit system with conversion to/from unitsystem1 and unitsystem2 */
  6409. IList<IUnitSystem> oldUnitsystems1 = new List<IUnitSystem>() { }; // NoDiretConversionTounitsystems2
  6410. IList<IUnitSystem> newUnitSystemsConvertableToUnitsystems1 = new List<IUnitSystem>() { unitsystem1 };
  6411. IList<IUnitSystem> oldUnitsystems2 = new List<IUnitSystem>() { }; // NoDiretConversionTounitsystems1
  6412. IList<IUnitSystem> newUnitSystemsConvertableToUnitsystems2 = new List<IUnitSystem>() { unitsystem2 };
  6413. return GetIntermediateUnitSystemConversion(UnitSystemConversions, oldUnitsystems1, newUnitSystemsConvertableToUnitsystems1, oldUnitsystems2, newUnitSystemsConvertableToUnitsystems2);
  6414. }
  6415. public UnitSystemConversion GetIntermediateUnitSystemConversion(IList<UnitSystemConversion> unitSystemConversions,
  6416. IList<IUnitSystem> oldUnitsystems1, IList<IUnitSystem> newUnitSystemsConvertableToUnitsystems1,
  6417. IList<IUnitSystem> oldUnitsystems2, IList<IUnitSystem> newUnitSystemsConvertableToUnitsystems2)
  6418. {
  6419. IList<IUnitSystem> unitSystemsConvertableToUnitsystems1 = new List<IUnitSystem>();
  6420. IList<IUnitSystem> unitSystemsConvertableToUnitsystems2 = new List<IUnitSystem>();
  6421. IList<UnitSystemConversion> unitsystems1Conversions = new List<UnitSystemConversion>();
  6422. IList<UnitSystemConversion> unitsystems2Conversions = new List<UnitSystemConversion>();
  6423. foreach (UnitSystemConversion usc in UnitSystemConversions)
  6424. {
  6425. Boolean BUS_in_US1 = newUnitSystemsConvertableToUnitsystems1.Contains(usc.BaseUnitSystem);
  6426. Boolean CUS_in_US1 = newUnitSystemsConvertableToUnitsystems1.Contains(usc.ConvertedUnitSystem);
  6427. Boolean BUS_in_US2 = newUnitSystemsConvertableToUnitsystems2.Contains(usc.BaseUnitSystem);
  6428. Boolean CUS_in_US2 = newUnitSystemsConvertableToUnitsystems2.Contains(usc.ConvertedUnitSystem);
  6429. if (BUS_in_US1 || CUS_in_US1)
  6430. {
  6431. if (BUS_in_US2 || CUS_in_US2)
  6432. {
  6433. return usc;
  6434. }
  6435. Debug.Assert(!unitsystems1Conversions.Contains(usc));
  6436. unitsystems1Conversions.Add(usc);
  6437. if (!(BUS_in_US1 && CUS_in_US1))
  6438. {
  6439. if (BUS_in_US1)
  6440. {
  6441. unitSystemsConvertableToUnitsystems1.Add(usc.ConvertedUnitSystem);
  6442. }
  6443. else
  6444. {
  6445. unitSystemsConvertableToUnitsystems1.Add(usc.BaseUnitSystem);
  6446. }
  6447. }
  6448. }
  6449. else if (BUS_in_US2 || CUS_in_US2)
  6450. {
  6451. Debug.Assert(!unitsystems2Conversions.Contains(usc));
  6452. unitsystems2Conversions.Add(usc);
  6453. if (!(BUS_in_US2 && CUS_in_US2))
  6454. {
  6455. if (BUS_in_US2)
  6456. {
  6457. unitSystemsConvertableToUnitsystems2.Add(usc.ConvertedUnitSystem);
  6458. }
  6459. else
  6460. {
  6461. unitSystemsConvertableToUnitsystems2.Add(usc.BaseUnitSystem);
  6462. }
  6463. }
  6464. }
  6465. }
  6466. /* No direct unit system conversion from unitsystems1 to unitsystems2.
  6467. * Try to find an intermediate unit system with conversion to/from unitsystems1 and unitsystems2 */
  6468. if (unitSystemsConvertableToUnitsystems1.Count > 0 || unitSystemsConvertableToUnitsystems2.Count > 0)
  6469. {
  6470. IList<IUnitSystem> unitsystems1 = (IList<IUnitSystem>)oldUnitsystems1.Union(newUnitSystemsConvertableToUnitsystems1).ToList();
  6471. IList<IUnitSystem> unitsystems2 = (IList<IUnitSystem>)oldUnitsystems2.Union(newUnitSystemsConvertableToUnitsystems2).ToList();
  6472. UnitSystemConversion subIntermediereUnitSystemConversion = null;
  6473. IList<IUnitSystem> intersectUnitsystemsList = unitSystemsConvertableToUnitsystems1.Intersect(unitSystemsConvertableToUnitsystems2).ToList();
  6474. if (intersectUnitsystemsList.Count > 0)
  6475. {
  6476. IUnitSystem intersectUnitsystem = intersectUnitsystemsList[0];
  6477. subIntermediereUnitSystemConversion = GetIntermediateUnitSystemConversion(unitsystems1Conversions, new List<IUnitSystem>() { }, newUnitSystemsConvertableToUnitsystems1, new List<IUnitSystem>() { }, new List<IUnitSystem>() { intersectUnitsystem });
  6478. Debug.Assert(subIntermediereUnitSystemConversion != null);
  6479. }
  6480. else
  6481. {
  6482. IList<UnitSystemConversion> notIntermediereUnitSystemConversions = (IList<UnitSystemConversion>)unitSystemConversions.Except(unitsystems1Conversions.Union(unitsystems2Conversions)).ToList();
  6483. if (notIntermediereUnitSystemConversions.Count > 0)
  6484. {
  6485. subIntermediereUnitSystemConversion = GetIntermediateUnitSystemConversion(notIntermediereUnitSystemConversions, unitsystems1, unitSystemsConvertableToUnitsystems1, unitsystems2, unitSystemsConvertableToUnitsystems2);
  6486. }
  6487. }
  6488. if (subIntermediereUnitSystemConversion != null)
  6489. {
  6490. if (!unitsystems1.Contains(subIntermediereUnitSystemConversion.BaseUnitSystem)
  6491. && !unitsystems1.Contains(subIntermediereUnitSystemConversion.ConvertedUnitSystem))
  6492. {
  6493. // Combine system conversion from some unit system in unitsystems1 to one of subIntermediereUnitSystemConversion's systems
  6494. // Find the first and second UnitSystemConversions which will be combined into a two step conversion
  6495. IUnitSystem combinedUnitSystemConversionBaseUnitSystem;
  6496. IUnitSystem combinedUnitSystemConversionIntermedierUnitSystem;
  6497. IUnitSystem combinedUnitSystemConversionConvertedUnitSystem;
  6498. UnitSystemConversion secondUnitSystemConversion = subIntermediereUnitSystemConversion;
  6499. Boolean secondValueConversionDirectionInverted = !unitSystemsConvertableToUnitsystems1.Contains(subIntermediereUnitSystemConversion.BaseUnitSystem);
  6500. if (!secondValueConversionDirectionInverted)
  6501. {
  6502. combinedUnitSystemConversionIntermedierUnitSystem = subIntermediereUnitSystemConversion.BaseUnitSystem;
  6503. combinedUnitSystemConversionConvertedUnitSystem = subIntermediereUnitSystemConversion.ConvertedUnitSystem;
  6504. }
  6505. else
  6506. {
  6507. Debug.Assert(unitSystemsConvertableToUnitsystems1.Contains(subIntermediereUnitSystemConversion.ConvertedUnitSystem));
  6508. combinedUnitSystemConversionIntermedierUnitSystem = subIntermediereUnitSystemConversion.ConvertedUnitSystem;
  6509. combinedUnitSystemConversionConvertedUnitSystem = subIntermediereUnitSystemConversion.BaseUnitSystem;
  6510. }
  6511. UnitSystemConversion firstUnitSystemConversion = GetIntermediateUnitSystemConversion(unitsystems1Conversions, new List<IUnitSystem>() { }, unitsystems1, new List<IUnitSystem>() { }, new List<IUnitSystem>() { combinedUnitSystemConversionIntermedierUnitSystem });
  6512. Boolean firstValueConversionDirectionInverted = firstUnitSystemConversion.BaseUnitSystem == combinedUnitSystemConversionIntermedierUnitSystem;
  6513. if (!firstValueConversionDirectionInverted)
  6514. {
  6515. combinedUnitSystemConversionBaseUnitSystem = firstUnitSystemConversion.BaseUnitSystem;
  6516. }
  6517. else
  6518. {
  6519. combinedUnitSystemConversionBaseUnitSystem = firstUnitSystemConversion.ConvertedUnitSystem;
  6520. }
  6521. // Make the Combined unit system conversion
  6522. ValueConversion[] CombinedValueConversions = new ValueConversion[] { new CombinedValueConversion(firstUnitSystemConversion.BaseUnitConversions[0], firstValueConversionDirectionInverted, secondUnitSystemConversion.BaseUnitConversions[0], secondValueConversionDirectionInverted),
  6523. new CombinedValueConversion(firstUnitSystemConversion.BaseUnitConversions[1], firstValueConversionDirectionInverted, secondUnitSystemConversion.BaseUnitConversions[1], secondValueConversionDirectionInverted),
  6524. new CombinedValueConversion(firstUnitSystemConversion.BaseUnitConversions[2], firstValueConversionDirectionInverted, secondUnitSystemConversion.BaseUnitConversions[2], secondValueConversionDirectionInverted),
  6525. new CombinedValueConversion(firstUnitSystemConversion.BaseUnitConversions[3], firstValueConversionDirectionInverted, secondUnitSystemConversion.BaseUnitConversions[3], secondValueConversionDirectionInverted),
  6526. new CombinedValueConversion(firstUnitSystemConversion.BaseUnitConversions[4], firstValueConversionDirectionInverted, secondUnitSystemConversion.BaseUnitConversions[4], secondValueConversionDirectionInverted),
  6527. new CombinedValueConversion(firstUnitSystemConversion.BaseUnitConversions[5], firstValueConversionDirectionInverted, secondUnitSystemConversion.BaseUnitConversions[5], secondValueConversionDirectionInverted),
  6528. new CombinedValueConversion(firstUnitSystemConversion.BaseUnitConversions[6], firstValueConversionDirectionInverted, secondUnitSystemConversion.BaseUnitConversions[6], secondValueConversionDirectionInverted)
  6529. };
  6530. subIntermediereUnitSystemConversion = new UnitSystemConversion(combinedUnitSystemConversionBaseUnitSystem, combinedUnitSystemConversionConvertedUnitSystem, CombinedValueConversions);
  6531. }
  6532. if (!unitsystems2.Contains(subIntermediereUnitSystemConversion.BaseUnitSystem)
  6533. && !unitsystems2.Contains(subIntermediereUnitSystemConversion.ConvertedUnitSystem))
  6534. {
  6535. // Combine system conversion from one of subIntermediereUnitSystemConversion's systems to some unit system in unitsystems2
  6536. // Find Post UnitSystemConversion
  6537. IUnitSystem combinedUnitSystemConversionBaseUnitSystem;
  6538. IUnitSystem combinedUnitSystemConversionIntermedierUnitSystem;
  6539. IUnitSystem combinedUnitSystemConversionConvertedUnitSystem;
  6540. UnitSystemConversion firstUnitSystemConversion = subIntermediereUnitSystemConversion;
  6541. Boolean firstValueConversionDirectionInverted = !unitSystemsConvertableToUnitsystems2.Contains(subIntermediereUnitSystemConversion.ConvertedUnitSystem);
  6542. if (!firstValueConversionDirectionInverted)
  6543. {
  6544. combinedUnitSystemConversionBaseUnitSystem = subIntermediereUnitSystemConversion.BaseUnitSystem;
  6545. combinedUnitSystemConversionIntermedierUnitSystem = subIntermediereUnitSystemConversion.ConvertedUnitSystem;
  6546. }
  6547. else
  6548. {
  6549. Debug.Assert(unitSystemsConvertableToUnitsystems1.Contains(subIntermediereUnitSystemConversion.ConvertedUnitSystem) || unitsystems1.Contains(subIntermediereUnitSystemConversion.ConvertedUnitSystem));
  6550. combinedUnitSystemConversionBaseUnitSystem = subIntermediereUnitSystemConversion.ConvertedUnitSystem;
  6551. combinedUnitSystemConversionIntermedierUnitSystem = subIntermediereUnitSystemConversion.BaseUnitSystem;
  6552. }
  6553. UnitSystemConversion secondUnitSystemConversion = GetIntermediateUnitSystemConversion(unitsystems2Conversions, new List<IUnitSystem>() { }, new List<IUnitSystem>() { combinedUnitSystemConversionIntermedierUnitSystem }, new List<IUnitSystem>() { }, unitsystems2);
  6554. Boolean secondValueConversionDirectionInverted = secondUnitSystemConversion.ConvertedUnitSystem == combinedUnitSystemConversionIntermedierUnitSystem;
  6555. if (!secondValueConversionDirectionInverted)
  6556. {
  6557. combinedUnitSystemConversionConvertedUnitSystem = secondUnitSystemConversion.ConvertedUnitSystem;
  6558. }
  6559. else
  6560. {
  6561. combinedUnitSystemConversionConvertedUnitSystem = secondUnitSystemConversion.BaseUnitSystem;
  6562. }
  6563. // Make the Combined unit system conversion
  6564. ValueConversion[] combinedValueConversions = new ValueConversion[] { new CombinedValueConversion(firstUnitSystemConversion.BaseUnitConversions[0], firstValueConversionDirectionInverted, secondUnitSystemConversion.BaseUnitConversions[0], secondValueConversionDirectionInverted),
  6565. new CombinedValueConversion(firstUnitSystemConversion.BaseUnitConversions[1], firstValueConversionDirectionInverted, secondUnitSystemConversion.BaseUnitConversions[1], secondValueConversionDirectionInverted),
  6566. new CombinedValueConversion(firstUnitSystemConversion.BaseUnitConversions[2], firstValueConversionDirectionInverted, secondUnitSystemConversion.BaseUnitConversions[2], secondValueConversionDirectionInverted),
  6567. new CombinedValueConversion(firstUnitSystemConversion.BaseUnitConversions[3], firstValueConversionDirectionInverted, secondUnitSystemConversion.BaseUnitConversions[3], secondValueConversionDirectionInverted),
  6568. new CombinedValueConversion(firstUnitSystemConversion.BaseUnitConversions[4], firstValueConversionDirectionInverted, secondUnitSystemConversion.BaseUnitConversions[4], secondValueConversionDirectionInverted),
  6569. new CombinedValueConversion(firstUnitSystemConversion.BaseUnitConversions[5], firstValueConversionDirectionInverted, secondUnitSystemConversion.BaseUnitConversions[5], secondValueConversionDirectionInverted),
  6570. new CombinedValueConversion(firstUnitSystemConversion.BaseUnitConversions[6], firstValueConversionDirectionInverted, secondUnitSystemConversion.BaseUnitConversions[6], secondValueConversionDirectionInverted)
  6571. };
  6572. subIntermediereUnitSystemConversion = new UnitSystemConversion(combinedUnitSystemConversionBaseUnitSystem, combinedUnitSystemConversionConvertedUnitSystem, combinedValueConversions);
  6573. }
  6574. return subIntermediereUnitSystemConversion;
  6575. }
  6576. }
  6577. return null;
  6578. }
  6579. }
  6580. #endregion Physical Measure Classes
  6581. }